aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd Schouten <ed@FreeBSD.org>2009-06-02 17:58:47 +0000
committerEd Schouten <ed@FreeBSD.org>2009-06-02 17:58:47 +0000
commitec2b103c267a06a66e926f62cd96767b280f5cf5 (patch)
treece7d964cbb5e39695b71481698f10cb099c23d4a
downloadsrc-ec2b103c267a06a66e926f62cd96767b280f5cf5.tar.gz
src-ec2b103c267a06a66e926f62cd96767b280f5cf5.zip
Import Clang, at r72732.vendor/clang/clang-r72732
Notes
Notes: svn path=/vendor/clang/dist/; revision=193326 svn path=/vendor/clang/clang-r72732/; revision=193327; tag=vendor/clang/clang-r72732
-rw-r--r--CMakeLists.txt56
-rw-r--r--INPUTS/Cocoa_h.m2
-rw-r--r--INPUTS/c99-intconst-1.c639
-rw-r--r--INPUTS/carbon_h.c4
-rw-r--r--INPUTS/iostream.cc5
-rw-r--r--INPUTS/macro_pounder_fn.c17
-rw-r--r--INPUTS/macro_pounder_obj.c16
-rw-r--r--INPUTS/stpcpy-test.c47
-rw-r--r--LICENSE.TXT63
-rw-r--r--Makefile32
-rw-r--r--ModuleInfo.txt5
-rw-r--r--NOTES.txt86
-rw-r--r--README.txt178
-rw-r--r--TODO.txt68
-rw-r--r--clang.xcodeproj/project.pbxproj1836
-rw-r--r--docs/AnalyzerRegions.html258
-rw-r--r--docs/BlockImplementation.txt647
-rw-r--r--docs/BlockLanguageSpec.txt165
-rw-r--r--docs/DriverArchitecture.pngbin0 -> 72966 bytes
-rw-r--r--docs/DriverInternals.html517
-rw-r--r--docs/InternalsManual.html1676
-rw-r--r--docs/LanguageExtensions.html327
-rw-r--r--docs/Makefile97
-rw-r--r--docs/PCHInternals.html71
-rw-r--r--docs/PTHInternals.html177
-rw-r--r--docs/UsersManual.html688
-rw-r--r--docs/doxygen.cfg1230
-rw-r--r--docs/doxygen.cfg.in1230
-rw-r--r--docs/doxygen.css378
-rw-r--r--docs/doxygen.footer10
-rw-r--r--docs/doxygen.header9
-rw-r--r--docs/doxygen.intro15
-rw-r--r--docs/index.html4
-rw-r--r--docs/tools/Makefile112
-rw-r--r--docs/tools/clang.pod514
-rw-r--r--docs/tools/manpage.css256
-rw-r--r--include/CMakeLists.txt1
-rw-r--r--include/Makefile4
-rw-r--r--include/clang/AST/APValue.h253
-rw-r--r--include/clang/AST/AST.h28
-rw-r--r--include/clang/AST/ASTConsumer.h81
-rw-r--r--include/clang/AST/ASTContext.h857
-rw-r--r--include/clang/AST/ASTDiagnostic.h27
-rw-r--r--include/clang/AST/Attr.h506
-rw-r--r--include/clang/AST/Builtins.def389
-rw-r--r--include/clang/AST/Builtins.h137
-rw-r--r--include/clang/AST/CFG.h405
-rw-r--r--include/clang/AST/Decl.h1409
-rw-r--r--include/clang/AST/DeclBase.h900
-rw-r--r--include/clang/AST/DeclCXX.h1073
-rw-r--r--include/clang/AST/DeclContextInternals.h220
-rw-r--r--include/clang/AST/DeclGroup.h152
-rw-r--r--include/clang/AST/DeclNodes.def161
-rw-r--r--include/clang/AST/DeclObjC.h1224
-rw-r--r--include/clang/AST/DeclTemplate.h859
-rw-r--r--include/clang/AST/DeclVisitor.h54
-rw-r--r--include/clang/AST/DeclarationName.h357
-rw-r--r--include/clang/AST/Expr.h2500
-rw-r--r--include/clang/AST/ExprCXX.h1234
-rw-r--r--include/clang/AST/ExprObjC.h494
-rw-r--r--include/clang/AST/ExternalASTSource.h184
-rw-r--r--include/clang/AST/NestedNameSpecifier.h183
-rw-r--r--include/clang/AST/PPCBuiltins.def24
-rw-r--r--include/clang/AST/ParentMap.h50
-rw-r--r--include/clang/AST/PrettyPrinter.h86
-rw-r--r--include/clang/AST/RecordLayout.h103
-rw-r--r--include/clang/AST/Stmt.h1223
-rw-r--r--include/clang/AST/StmtCXX.h100
-rw-r--r--include/clang/AST/StmtGraphTraits.h83
-rw-r--r--include/clang/AST/StmtIterator.h145
-rw-r--r--include/clang/AST/StmtNodes.def156
-rw-r--r--include/clang/AST/StmtObjC.h307
-rw-r--r--include/clang/AST/StmtVisitor.h176
-rw-r--r--include/clang/AST/TargetBuiltins.h38
-rw-r--r--include/clang/AST/TemplateName.h258
-rw-r--r--include/clang/AST/Type.h1977
-rw-r--r--include/clang/AST/TypeNodes.def85
-rw-r--r--include/clang/AST/TypeOrdering.h63
-rw-r--r--include/clang/AST/X86Builtins.def427
-rw-r--r--include/clang/Analysis/Analyses/LiveVariables.h119
-rw-r--r--include/clang/Analysis/Analyses/UninitializedValues.h74
-rw-r--r--include/clang/Analysis/AnalysisDiagnostic.h27
-rw-r--r--include/clang/Analysis/FlowSensitive/DataflowSolver.h291
-rw-r--r--include/clang/Analysis/FlowSensitive/DataflowValues.h172
-rw-r--r--include/clang/Analysis/LocalCheckers.h54
-rw-r--r--include/clang/Analysis/PathDiagnostic.h487
-rw-r--r--include/clang/Analysis/PathSensitive/BasicValueFactory.h163
-rw-r--r--include/clang/Analysis/PathSensitive/BugReporter.h466
-rw-r--r--include/clang/Analysis/PathSensitive/ConstraintManager.h67
-rw-r--r--include/clang/Analysis/PathSensitive/Environment.h151
-rw-r--r--include/clang/Analysis/PathSensitive/ExplodedGraph.h582
-rw-r--r--include/clang/Analysis/PathSensitive/GRAuditor.h39
-rw-r--r--include/clang/Analysis/PathSensitive/GRBlockCounter.h50
-rw-r--r--include/clang/Analysis/PathSensitive/GRCoreEngine.h668
-rw-r--r--include/clang/Analysis/PathSensitive/GRExprEngine.h738
-rw-r--r--include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h101
-rw-r--r--include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h40
-rw-r--r--include/clang/Analysis/PathSensitive/GRState.h820
-rw-r--r--include/clang/Analysis/PathSensitive/GRStateTrait.h148
-rw-r--r--include/clang/Analysis/PathSensitive/GRTransferFuncs.h123
-rw-r--r--include/clang/Analysis/PathSensitive/GRWorkList.h76
-rw-r--r--include/clang/Analysis/PathSensitive/MemRegion.h665
-rw-r--r--include/clang/Analysis/PathSensitive/SVals.h447
-rw-r--r--include/clang/Analysis/PathSensitive/Store.h204
-rw-r--r--include/clang/Analysis/PathSensitive/SymbolManager.h329
-rw-r--r--include/clang/Analysis/PathSensitive/ValueManager.h103
-rw-r--r--include/clang/Analysis/ProgramPoint.h351
-rw-r--r--include/clang/Analysis/Support/BlkExprDeclBitVector.h307
-rw-r--r--include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h91
-rw-r--r--include/clang/Analysis/Visitors/CFGRecStmtVisitor.h35
-rw-r--r--include/clang/Analysis/Visitors/CFGStmtVisitor.h156
-rw-r--r--include/clang/Analysis/Visitors/CFGVarDeclVisitor.h64
-rw-r--r--include/clang/Basic/CMakeLists.txt20
-rw-r--r--include/clang/Basic/ConvertUTF.h159
-rw-r--r--include/clang/Basic/Diagnostic.h697
-rw-r--r--include/clang/Basic/Diagnostic.td73
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td29
-rw-r--r--include/clang/Basic/DiagnosticAnalysisKinds.td15
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td58
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td64
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td136
-rw-r--r--include/clang/Basic/DiagnosticGroups.td133
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td277
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td280
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td1822
-rw-r--r--include/clang/Basic/FileManager.h178
-rw-r--r--include/clang/Basic/IdentifierTable.h561
-rw-r--r--include/clang/Basic/LangOptions.h157
-rw-r--r--include/clang/Basic/Makefile22
-rw-r--r--include/clang/Basic/OnDiskHashTable.h362
-rw-r--r--include/clang/Basic/OperatorKinds.def106
-rw-r--r--include/clang/Basic/OperatorKinds.h32
-rw-r--r--include/clang/Basic/PrettyStackTrace.h37
-rw-r--r--include/clang/Basic/SourceLocation.h305
-rw-r--r--include/clang/Basic/SourceManager.h714
-rw-r--r--include/clang/Basic/SourceManagerInternals.h130
-rw-r--r--include/clang/Basic/TargetInfo.h391
-rw-r--r--include/clang/Basic/TemplateKinds.h39
-rw-r--r--include/clang/Basic/TokenKinds.def413
-rw-r--r--include/clang/Basic/TokenKinds.h64
-rw-r--r--include/clang/Basic/TypeTraits.h40
-rw-r--r--include/clang/Basic/Version.h35
-rw-r--r--include/clang/CMakeLists.txt1
-rw-r--r--include/clang/CodeGen/ModuleBuilder.h40
-rw-r--r--include/clang/Driver/Action.h209
-rw-r--r--include/clang/Driver/Arg.h230
-rw-r--r--include/clang/Driver/ArgList.h245
-rw-r--r--include/clang/Driver/Compilation.h127
-rw-r--r--include/clang/Driver/Driver.h271
-rw-r--r--include/clang/Driver/DriverDiagnostic.h27
-rw-r--r--include/clang/Driver/HostInfo.h84
-rw-r--r--include/clang/Driver/Job.h138
-rw-r--r--include/clang/Driver/Option.h308
-rw-r--r--include/clang/Driver/Options.def624
-rw-r--r--include/clang/Driver/Options.h90
-rw-r--r--include/clang/Driver/Phases.h32
-rw-r--r--include/clang/Driver/Tool.h69
-rw-r--r--include/clang/Driver/ToolChain.h105
-rw-r--r--include/clang/Driver/Types.def78
-rw-r--r--include/clang/Driver/Types.h85
-rw-r--r--include/clang/Driver/Util.h30
-rw-r--r--include/clang/Frontend/ASTConsumers.h107
-rw-r--r--include/clang/Frontend/Analyses.def77
-rw-r--r--include/clang/Frontend/AnalysisConsumer.h78
-rw-r--r--include/clang/Frontend/CompileOptions.h62
-rw-r--r--include/clang/Frontend/DocumentXML.h128
-rw-r--r--include/clang/Frontend/FixItRewriter.h95
-rw-r--r--include/clang/Frontend/FrontendDiagnostic.h27
-rw-r--r--include/clang/Frontend/InitHeaderSearch.h74
-rw-r--r--include/clang/Frontend/InitPreprocessor.h70
-rw-r--r--include/clang/Frontend/ManagerRegistry.h53
-rw-r--r--include/clang/Frontend/PCHBitCodes.h660
-rw-r--r--include/clang/Frontend/PCHReader.h567
-rw-r--r--include/clang/Frontend/PCHWriter.h278
-rw-r--r--include/clang/Frontend/PathDiagnosticClients.h34
-rw-r--r--include/clang/Frontend/TextDiagnosticBuffer.h48
-rw-r--r--include/clang/Frontend/TextDiagnosticPrinter.h85
-rw-r--r--include/clang/Frontend/Utils.h79
-rw-r--r--include/clang/Lex/DirectoryLookup.h133
-rw-r--r--include/clang/Lex/HeaderMap.h67
-rw-r--r--include/clang/Lex/HeaderSearch.h237
-rw-r--r--include/clang/Lex/LexDiagnostic.h27
-rw-r--r--include/clang/Lex/Lexer.h376
-rw-r--r--include/clang/Lex/LiteralSupport.h176
-rw-r--r--include/clang/Lex/MacroInfo.h218
-rw-r--r--include/clang/Lex/MultipleIncludeOpt.h130
-rw-r--r--include/clang/Lex/PPCallbacks.h122
-rw-r--r--include/clang/Lex/PTHLexer.h104
-rw-r--r--include/clang/Lex/PTHManager.h141
-rw-r--r--include/clang/Lex/Pragma.h90
-rw-r--r--include/clang/Lex/Preprocessor.h801
-rw-r--r--include/clang/Lex/PreprocessorLexer.h161
-rw-r--r--include/clang/Lex/ScratchBuffer.h45
-rw-r--r--include/clang/Lex/Token.h312
-rw-r--r--include/clang/Lex/TokenConcatenation.h73
-rw-r--r--include/clang/Lex/TokenLexer.h154
-rw-r--r--include/clang/Makefile4
-rw-r--r--include/clang/Parse/AccessSpecifier.h30
-rw-r--r--include/clang/Parse/Action.h1839
-rw-r--r--include/clang/Parse/AttributeList.h173
-rw-r--r--include/clang/Parse/DeclSpec.h1086
-rw-r--r--include/clang/Parse/Designator.h239
-rw-r--r--include/clang/Parse/Ownership.h830
-rw-r--r--include/clang/Parse/ParseDiagnostic.h27
-rw-r--r--include/clang/Parse/Parser.h1208
-rw-r--r--include/clang/Parse/Scope.h310
-rw-r--r--include/clang/Rewrite/DeltaTree.h48
-rw-r--r--include/clang/Rewrite/HTMLRewrite.h82
-rw-r--r--include/clang/Rewrite/RewriteRope.h230
-rw-r--r--include/clang/Rewrite/Rewriter.h238
-rw-r--r--include/clang/Rewrite/TokenRewriter.h79
-rw-r--r--include/clang/Sema/ExternalSemaSource.h56
-rw-r--r--include/clang/Sema/ParseAST.h37
-rw-r--r--include/clang/Sema/SemaConsumer.h45
-rw-r--r--include/clang/Sema/SemaDiagnostic.h27
-rw-r--r--lib/AST/APValue.cpp108
-rw-r--r--lib/AST/ASTConsumer.cpp19
-rw-r--r--lib/AST/ASTContext.cpp3332
-rw-r--r--lib/AST/Builtins.cpp290
-rw-r--r--lib/AST/CFG.cpp1913
-rw-r--r--lib/AST/CMakeLists.txt32
-rw-r--r--lib/AST/Decl.cpp630
-rw-r--r--lib/AST/DeclBase.cpp756
-rw-r--r--lib/AST/DeclCXX.cpp462
-rw-r--r--lib/AST/DeclGroup.cpp37
-rw-r--r--lib/AST/DeclObjC.cpp693
-rw-r--r--lib/AST/DeclPrinter.cpp722
-rw-r--r--lib/AST/DeclTemplate.cpp324
-rw-r--r--lib/AST/DeclarationName.cpp355
-rw-r--r--lib/AST/Expr.cpp2059
-rw-r--r--lib/AST/ExprCXX.cpp424
-rw-r--r--lib/AST/ExprConstant.cpp1723
-rw-r--r--lib/AST/InheritViz.cpp168
-rw-r--r--lib/AST/Makefile22
-rw-r--r--lib/AST/NestedNameSpecifier.cpp160
-rw-r--r--lib/AST/ParentMap.cpp94
-rw-r--r--lib/AST/Stmt.cpp587
-rw-r--r--lib/AST/StmtDumper.cpp542
-rw-r--r--lib/AST/StmtIterator.cpp155
-rw-r--r--lib/AST/StmtPrinter.cpp1239
-rw-r--r--lib/AST/StmtViz.cpp61
-rw-r--r--lib/AST/TemplateName.cpp65
-rw-r--r--lib/AST/Type.cpp1658
-rw-r--r--lib/Analysis/BasicConstraintManager.cpp342
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.cpp492
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.h47
-rw-r--r--lib/Analysis/BasicStore.cpp637
-rw-r--r--lib/Analysis/BasicValueFactory.cpp264
-rw-r--r--lib/Analysis/BugReporter.cpp1697
-rw-r--r--lib/Analysis/CFRefCount.cpp3635
-rw-r--r--lib/Analysis/CMakeLists.txt36
-rw-r--r--lib/Analysis/CheckDeadStores.cpp259
-rw-r--r--lib/Analysis/CheckNSError.cpp231
-rw-r--r--lib/Analysis/CheckObjCDealloc.cpp257
-rw-r--r--lib/Analysis/CheckObjCInstMethSignature.cpp120
-rw-r--r--lib/Analysis/CheckObjCUnusedIVars.cpp111
-rw-r--r--lib/Analysis/Environment.cpp167
-rw-r--r--lib/Analysis/ExplodedGraph.cpp241
-rw-r--r--lib/Analysis/GRBlockCounter.cpp54
-rw-r--r--lib/Analysis/GRCoreEngine.cpp576
-rw-r--r--lib/Analysis/GRExprEngine.cpp3426
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.cpp961
-rw-r--r--lib/Analysis/GRSimpleVals.cpp416
-rw-r--r--lib/Analysis/GRSimpleVals.h86
-rw-r--r--lib/Analysis/GRState.cpp318
-rw-r--r--lib/Analysis/GRTransferFuncs.cpp28
-rw-r--r--lib/Analysis/LiveVariables.cpp359
-rw-r--r--lib/Analysis/Makefile22
-rw-r--r--lib/Analysis/MemRegion.cpp494
-rw-r--r--lib/Analysis/PathDiagnostic.cpp242
-rw-r--r--lib/Analysis/RangeConstraintManager.cpp363
-rw-r--r--lib/Analysis/RegionStore.cpp1304
-rw-r--r--lib/Analysis/SVals.cpp513
-rw-r--r--lib/Analysis/SimpleConstraintManager.cpp263
-rw-r--r--lib/Analysis/SimpleConstraintManager.h84
-rw-r--r--lib/Analysis/Store.cpp110
-rw-r--r--lib/Analysis/SymbolManager.cpp203
-rw-r--r--lib/Analysis/UninitializedValues.cpp312
-rw-r--r--lib/Basic/CMakeLists.txt24
-rw-r--r--lib/Basic/ConvertUTF.c547
-rw-r--r--lib/Basic/Diagnostic.cpp788
-rw-r--r--lib/Basic/FileManager.cpp302
-rw-r--r--lib/Basic/IdentifierTable.cpp388
-rw-r--r--lib/Basic/Makefile22
-rw-r--r--lib/Basic/SourceLocation.cpp125
-rw-r--r--lib/Basic/SourceManager.cpp943
-rw-r--r--lib/Basic/TargetInfo.cpp295
-rw-r--r--lib/Basic/Targets.cpp1500
-rw-r--r--lib/Basic/TokenKinds.cpp90
-rw-r--r--lib/CMakeLists.txt11
-rw-r--r--lib/CodeGen/ABIInfo.h133
-rw-r--r--lib/CodeGen/CGBlocks.cpp1037
-rw-r--r--lib/CodeGen/CGBlocks.h223
-rw-r--r--lib/CodeGen/CGBuilder.h26
-rw-r--r--lib/CodeGen/CGBuiltin.cpp1037
-rw-r--r--lib/CodeGen/CGCXX.cpp454
-rw-r--r--lib/CodeGen/CGCXX.h36
-rw-r--r--lib/CodeGen/CGCall.cpp2196
-rw-r--r--lib/CodeGen/CGCall.h104
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp987
-rw-r--r--lib/CodeGen/CGDebugInfo.h126
-rw-r--r--lib/CodeGen/CGDecl.cpp489
-rw-r--r--lib/CodeGen/CGExpr.cpp1324
-rw-r--r--lib/CodeGen/CGExprAgg.cpp554
-rw-r--r--lib/CodeGen/CGExprComplex.cpp663
-rw-r--r--lib/CodeGen/CGExprConstant.cpp588
-rw-r--r--lib/CodeGen/CGExprScalar.cpp1575
-rw-r--r--lib/CodeGen/CGObjC.cpp644
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp1582
-rw-r--r--lib/CodeGen/CGObjCMac.cpp5780
-rw-r--r--lib/CodeGen/CGObjCRuntime.h206
-rw-r--r--lib/CodeGen/CGStmt.cpp1022
-rw-r--r--lib/CodeGen/CGValue.h323
-rw-r--r--lib/CodeGen/CMakeLists.txt24
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp714
-rw-r--r--lib/CodeGen/CodeGenFunction.h900
-rw-r--r--lib/CodeGen/CodeGenModule.cpp1543
-rw-r--r--lib/CodeGen/CodeGenModule.h467
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp614
-rw-r--r--lib/CodeGen/CodeGenTypes.h212
-rw-r--r--lib/CodeGen/Makefile23
-rw-r--r--lib/CodeGen/Mangle.cpp772
-rw-r--r--lib/CodeGen/Mangle.h44
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp100
-rw-r--r--lib/CodeGen/README.txt65
-rw-r--r--lib/Driver/Action.cpp79
-rw-r--r--lib/Driver/Arg.cpp192
-rw-r--r--lib/Driver/ArgList.cpp232
-rw-r--r--lib/Driver/CMakeLists.txt19
-rw-r--r--lib/Driver/Compilation.cpp174
-rw-r--r--lib/Driver/Driver.cpp1254
-rw-r--r--lib/Driver/HostInfo.cpp408
-rw-r--r--lib/Driver/InputInfo.h101
-rw-r--r--lib/Driver/Job.cpp31
-rw-r--r--lib/Driver/Makefile28
-rw-r--r--lib/Driver/OptTable.cpp265
-rw-r--r--lib/Driver/Option.cpp250
-rw-r--r--lib/Driver/Phases.cpp27
-rw-r--r--lib/Driver/Tool.cpp19
-rw-r--r--lib/Driver/ToolChain.cpp35
-rw-r--r--lib/Driver/ToolChains.cpp475
-rw-r--r--lib/Driver/ToolChains.h134
-rw-r--r--lib/Driver/Tools.cpp2033
-rw-r--r--lib/Driver/Tools.h316
-rw-r--r--lib/Driver/Types.cpp205
-rw-r--r--lib/Frontend/ASTConsumers.cpp451
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp659
-rw-r--r--lib/Frontend/Backend.cpp415
-rw-r--r--lib/Frontend/CMakeLists.txt35
-rw-r--r--lib/Frontend/CacheTokens.cpp658
-rw-r--r--lib/Frontend/DependencyFile.cpp169
-rw-r--r--lib/Frontend/DiagChecker.cpp302
-rw-r--r--lib/Frontend/DocumentXML.cpp579
-rw-r--r--lib/Frontend/FixItRewriter.cpp199
-rw-r--r--lib/Frontend/GeneratePCH.cpp78
-rw-r--r--lib/Frontend/HTMLDiagnostics.cpp602
-rw-r--r--lib/Frontend/HTMLPrint.cpp92
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp327
-rw-r--r--lib/Frontend/InitPreprocessor.cpp495
-rw-r--r--lib/Frontend/Makefile18
-rw-r--r--lib/Frontend/ManagerRegistry.cpp20
-rw-r--r--lib/Frontend/PCHReader.cpp2260
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp712
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp1136
-rw-r--r--lib/Frontend/PCHWriter.cpp1966
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp532
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp829
-rw-r--r--lib/Frontend/PlistDiagnostics.cpp389
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp831
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp470
-rw-r--r--lib/Frontend/RewriteBlocks.cpp1162
-rw-r--r--lib/Frontend/RewriteMacros.cpp215
-rw-r--r--lib/Frontend/RewriteObjC.cpp4693
-rw-r--r--lib/Frontend/RewriteTest.cpp39
-rw-r--r--lib/Frontend/StmtXML.cpp409
-rw-r--r--lib/Frontend/TextDiagnosticBuffer.cpp39
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp710
-rw-r--r--lib/Frontend/Warnings.cpp106
-rw-r--r--lib/Headers/CMakeLists.txt25
-rw-r--r--lib/Headers/Makefile40
-rw-r--r--lib/Headers/emmintrin.h1329
-rw-r--r--lib/Headers/float.h71
-rw-r--r--lib/Headers/iso646.h43
-rw-r--r--lib/Headers/limits.h114
-rw-r--r--lib/Headers/mm_malloc.h59
-rw-r--r--lib/Headers/mmintrin.h449
-rw-r--r--lib/Headers/pmmintrin.h121
-rw-r--r--lib/Headers/stdarg.h47
-rw-r--r--lib/Headers/stdbool.h38
-rw-r--r--lib/Headers/stddef.h43
-rw-r--r--lib/Headers/stdint.h232
-rw-r--r--lib/Headers/tgmath.h1358
-rw-r--r--lib/Headers/tmmintrin.h218
-rw-r--r--lib/Headers/xmmintrin.h888
-rw-r--r--lib/Lex/CMakeLists.txt26
-rw-r--r--lib/Lex/HeaderMap.cpp245
-rw-r--r--lib/Lex/HeaderSearch.cpp446
-rw-r--r--lib/Lex/Lexer.cpp1809
-rw-r--r--lib/Lex/LiteralSupport.cpp929
-rw-r--r--lib/Lex/MacroArgs.cpp240
-rw-r--r--lib/Lex/MacroArgs.h109
-rw-r--r--lib/Lex/MacroInfo.cpp75
-rw-r--r--lib/Lex/Makefile28
-rw-r--r--lib/Lex/PPCaching.cpp113
-rw-r--r--lib/Lex/PPDirectives.cpp1665
-rw-r--r--lib/Lex/PPExpressions.cpp717
-rw-r--r--lib/Lex/PPLexerChange.cpp345
-rw-r--r--lib/Lex/PPMacroExpansion.cpp605
-rw-r--r--lib/Lex/PTHLexer.cpp701
-rw-r--r--lib/Lex/Pragma.cpp699
-rw-r--r--lib/Lex/Preprocessor.cpp478
-rw-r--r--lib/Lex/PreprocessorLexer.cpp45
-rw-r--r--lib/Lex/ScratchBuffer.cpp73
-rw-r--r--lib/Lex/TokenConcatenation.cpp219
-rw-r--r--lib/Lex/TokenLexer.cpp542
-rwxr-xr-xlib/Makefile15
-rw-r--r--lib/Parse/AttributeList.cpp145
-rw-r--r--lib/Parse/CMakeLists.txt21
-rw-r--r--lib/Parse/DeclSpec.cpp395
-rw-r--r--lib/Parse/ExtensionRAIIObject.h40
-rw-r--r--lib/Parse/Makefile22
-rw-r--r--lib/Parse/MinimalAction.cpp225
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp271
-rw-r--r--lib/Parse/ParseDecl.cpp2707
-rw-r--r--lib/Parse/ParseDeclCXX.cpp1292
-rw-r--r--lib/Parse/ParseExpr.cpp1514
-rw-r--r--lib/Parse/ParseExprCXX.cpp1166
-rw-r--r--lib/Parse/ParseInit.cpp308
-rw-r--r--lib/Parse/ParseObjc.cpp1708
-rw-r--r--lib/Parse/ParsePragma.cpp182
-rw-r--r--lib/Parse/ParsePragma.h44
-rw-r--r--lib/Parse/ParseStmt.cpp1435
-rw-r--r--lib/Parse/ParseTemplate.cpp812
-rw-r--r--lib/Parse/ParseTentative.cpp920
-rw-r--r--lib/Parse/Parser.cpp996
-rw-r--r--lib/Rewrite/CMakeLists.txt9
-rw-r--r--lib/Rewrite/DeltaTree.cpp485
-rw-r--r--lib/Rewrite/HTMLRewrite.cpp574
-rw-r--r--lib/Rewrite/Makefile22
-rw-r--r--lib/Rewrite/RewriteRope.cpp807
-rw-r--r--lib/Rewrite/Rewriter.cpp228
-rw-r--r--lib/Rewrite/TokenRewriter.cpp98
-rw-r--r--lib/Sema/CMakeLists.txt33
-rw-r--r--lib/Sema/CXXFieldCollector.h76
-rw-r--r--lib/Sema/IdentifierResolver.cpp293
-rw-r--r--lib/Sema/IdentifierResolver.h214
-rw-r--r--lib/Sema/JumpDiagnostics.cpp327
-rw-r--r--lib/Sema/Makefile23
-rw-r--r--lib/Sema/ParseAST.cpp85
-rw-r--r--lib/Sema/Sema.cpp333
-rw-r--r--lib/Sema/Sema.h2814
-rw-r--r--lib/Sema/SemaAccess.cpp124
-rw-r--r--lib/Sema/SemaAttr.cpp211
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp312
-rw-r--r--lib/Sema/SemaChecking.cpp1449
-rw-r--r--lib/Sema/SemaDecl.cpp4415
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1803
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2823
-rw-r--r--lib/Sema/SemaDeclObjC.cpp2166
-rw-r--r--lib/Sema/SemaExpr.cpp5395
-rw-r--r--lib/Sema/SemaExprCXX.cpp1603
-rw-r--r--lib/Sema/SemaExprObjC.cpp860
-rw-r--r--lib/Sema/SemaInherit.cpp344
-rw-r--r--lib/Sema/SemaInherit.h248
-rw-r--r--lib/Sema/SemaInit.cpp1784
-rw-r--r--lib/Sema/SemaLookup.cpp1626
-rw-r--r--lib/Sema/SemaNamedCast.cpp932
-rw-r--r--lib/Sema/SemaOverload.cpp4485
-rw-r--r--lib/Sema/SemaOverload.h263
-rw-r--r--lib/Sema/SemaStmt.cpp1266
-rw-r--r--lib/Sema/SemaTemplate.cpp2651
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp1034
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp767
-rw-r--r--lib/Sema/SemaTemplateInstantiateExpr.cpp1278
-rw-r--r--lib/Sema/SemaTemplateInstantiateStmt.cpp443
-rw-r--r--lib/Sema/SemaType.cpp1301
-rw-r--r--test/Analysis/CFDateGC.m87
-rw-r--r--test/Analysis/CFNumber.c31
-rw-r--r--test/Analysis/CFRetainRelease_NSAssertionHandler.m67
-rw-r--r--test/Analysis/CGColorSpace.c21
-rw-r--r--test/Analysis/CheckNSError.m59
-rw-r--r--test/Analysis/MissingDealloc.m117
-rw-r--r--test/Analysis/NSPanel.m90
-rw-r--r--test/Analysis/NSString.m335
-rw-r--r--test/Analysis/NSWindow.m89
-rw-r--r--test/Analysis/NoReturn.m82
-rw-r--r--test/Analysis/ObjCProperties.m25
-rw-r--r--test/Analysis/ObjCRetSigs.m25
-rw-r--r--test/Analysis/PR2599.m64
-rw-r--r--test/Analysis/PR2978.m61
-rw-r--r--test/Analysis/PR3991.m67
-rw-r--r--test/Analysis/array-struct.c150
-rw-r--r--test/Analysis/basicstore_wine_crash.c11
-rw-r--r--test/Analysis/casts.c16
-rw-r--r--test/Analysis/casts.m22
-rw-r--r--test/Analysis/cfref_PR2519.c48
-rw-r--r--test/Analysis/cfref_rdar6080742.c58
-rw-r--r--test/Analysis/complex.c21
-rw-r--r--test/Analysis/conditional-op-missing-lhs.c26
-rw-r--r--test/Analysis/dead-stores.c175
-rw-r--r--test/Analysis/dead-stores.m36
-rw-r--r--test/Analysis/delegates.m114
-rw-r--r--test/Analysis/exercise-ps.c25
-rw-r--r--test/Analysis/fields.c10
-rw-r--r--test/Analysis/func.c17
-rw-r--r--test/Analysis/misc-ps-64.m49
-rw-r--r--test/Analysis/misc-ps-basic-store.m21
-rw-r--r--test/Analysis/misc-ps-eager-assume.m79
-rw-r--r--test/Analysis/misc-ps-ranges.m23
-rw-r--r--test/Analysis/misc-ps-region-store.m70
-rw-r--r--test/Analysis/misc-ps.m287
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m67
-rw-r--r--test/Analysis/no-exit-cfg.c19
-rw-r--r--test/Analysis/no-outofbounds-basicstore.c7
-rw-r--r--test/Analysis/null-deref-ps-region.c14
-rw-r--r--test/Analysis/null-deref-ps.c265
-rw-r--r--test/Analysis/outofbound.c7
-rw-r--r--test/Analysis/override-werror.c15
-rw-r--r--test/Analysis/pr4209.m70
-rw-r--r--test/Analysis/pr_2542_rdar_6793404.m68
-rw-r--r--test/Analysis/pr_4164.c41
-rw-r--r--test/Analysis/ptr-arith.c34
-rw-r--r--test/Analysis/rdar-6442306-1.m31
-rw-r--r--test/Analysis/rdar-6539791.c47
-rw-r--r--test/Analysis/rdar-6540084.m36
-rw-r--r--test/Analysis/rdar-6541136-region.c19
-rw-r--r--test/Analysis/rdar-6541136.c20
-rw-r--r--test/Analysis/rdar-6562655.m63
-rw-r--r--test/Analysis/rdar-6582778-basic-store.c22
-rw-r--r--test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m25
-rw-r--r--test/Analysis/refcnt_naming.m62
-rw-r--r--test/Analysis/region-1.m90
-rw-r--r--test/Analysis/region-only-test.c13
-rw-r--r--test/Analysis/retain-release-basic-store.m102
-rw-r--r--test/Analysis/retain-release-gc-only.m161
-rw-r--r--test/Analysis/retain-release-region-store.m118
-rw-r--r--test/Analysis/retain-release.m708
-rw-r--r--test/Analysis/stack-addr-ps.c44
-rw-r--r--test/Analysis/uninit-msg-expr.m58
-rw-r--r--test/Analysis/uninit-ps-rdar6145427.m37
-rw-r--r--test/Analysis/uninit-vals-ps-region.c17
-rw-r--r--test/Analysis/uninit-vals-ps.c85
-rw-r--r--test/Analysis/uninit-vals.c53
-rw-r--r--test/Analysis/uninit-vals.m25
-rw-r--r--test/Analysis/unused-ivars.m10
-rw-r--r--test/Analysis/xfail-no-outofbounds.c7
-rw-r--r--test/Analysis/xfail_regionstore_wine_crash.c12
-rw-r--r--test/CodeGen/2007-11-29-ArraySizeFromInitializer.c4
-rw-r--r--test/CodeGen/2008-02-07-bitfield-bug.c11
-rw-r--r--test/CodeGen/2008-02-08-bitfield-bug.c9
-rw-r--r--test/CodeGen/2008-02-26-inline-asm-bug.c6
-rw-r--r--test/CodeGen/2008-07-17-no-emit-on-error.c10
-rw-r--r--test/CodeGen/2008-07-21-mixed-var-fn-decl.c5
-rw-r--r--test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c11
-rw-r--r--test/CodeGen/2008-07-22-packed-bitfield-access.c10
-rw-r--r--test/CodeGen/2008-07-29-override-alias-decl.c12
-rw-r--r--test/CodeGen/2008-07-30-implicit-initialization.c28
-rw-r--r--test/CodeGen/2008-07-30-redef-of-bitcasted-decl.c28
-rw-r--r--test/CodeGen/2008-07-31-asm-labels.c33
-rw-r--r--test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c25
-rw-r--r--test/CodeGen/2008-08-04-void-pointer-arithmetic.c6
-rw-r--r--test/CodeGen/2008-08-19-cast-of-typedef.c10
-rw-r--r--test/CodeGen/2008-08-25-incompatible-cond-expr.m10
-rw-r--r--test/CodeGen/2008-09-22-bad-switch-type.c34
-rw-r--r--test/CodeGen/2008-12-02-logical-or-fold.c4
-rw-r--r--test/CodeGen/2009-01-21-invalid-debug-info.m16
-rw-r--r--test/CodeGen/2009-03-22-increment-bitfield.c7
-rw-r--r--test/CodeGen/2009-04-23-dbg.c20
-rw-r--r--test/CodeGen/2009-05-22-callingconv.c25
-rw-r--r--test/CodeGen/2009-05-28-const-typedef.c17
-rw-r--r--test/CodeGen/2009-06-01-addrofknr.c21
-rw-r--r--test/CodeGen/OpaqueStruct.c12
-rw-r--r--test/CodeGen/PR2001-bitfield-reload.c17
-rw-r--r--test/CodeGen/PR2413-void-address-cast-error.c6
-rw-r--r--test/CodeGen/PR2643-null-store-to-bitfield.c10
-rw-r--r--test/CodeGen/PR2743-reference-missing-static.c16
-rw-r--r--test/CodeGen/PR3130-cond-constant.c3
-rw-r--r--test/CodeGen/PR3589-freestanding-libcalls.c9
-rw-r--r--test/CodeGen/PR3613-static-decl.c16
-rw-r--r--test/CodeGen/PR3709-int-to-pointer-sign.c5
-rw-r--r--test/CodeGen/PR3869-indirect-goto-long.c4
-rw-r--r--test/CodeGen/address-space-cast.c4
-rw-r--r--test/CodeGen/address-space.c20
-rw-r--r--test/CodeGen/alias.c32
-rw-r--r--test/CodeGen/align-local.c8
-rw-r--r--test/CodeGen/alignof.c12
-rw-r--r--test/CodeGen/array.c14
-rw-r--r--test/CodeGen/asm-2.c10
-rw-r--r--test/CodeGen/asm.c103
-rw-r--r--test/CodeGen/atomic.c53
-rw-r--r--test/CodeGen/attr-cleanup.c8
-rw-r--r--test/CodeGen/attr-nodebug.c12
-rw-r--r--test/CodeGen/attr-noinline.c9
-rw-r--r--test/CodeGen/attr-used.c14
-rw-r--r--test/CodeGen/attributes.c59
-rw-r--r--test/CodeGen/bitfield-assign.c44
-rw-r--r--test/CodeGen/bitfield-init.c14
-rw-r--r--test/CodeGen/bitfield-promote.c19
-rw-r--r--test/CodeGen/bitfield.c74
-rw-r--r--test/CodeGen/blocks-1.c78
-rw-r--r--test/CodeGen/blocks-2.c13
-rw-r--r--test/CodeGen/blocks-seq.c18
-rw-r--r--test/CodeGen/blocks.c30
-rw-r--r--test/CodeGen/bool-bitfield.c54
-rw-r--r--test/CodeGen/bool-convert.c10
-rw-r--r--test/CodeGen/bool-init.c4
-rw-r--r--test/CodeGen/boolassign.c6
-rw-r--r--test/CodeGen/builtin-count-zeros.c4
-rw-r--r--test/CodeGen/builtin-memfns.c15
-rw-r--r--test/CodeGen/builtin-nanf.c15
-rw-r--r--test/CodeGen/builtin-rename.c8
-rw-r--r--test/CodeGen/builtin-stackaddress.c9
-rw-r--r--test/CodeGen/builtin-unwind-init.c4
-rw-r--r--test/CodeGen/builtinmemcpy.c3
-rw-r--r--test/CodeGen/builtins-ffs_parity_popcount.c15
-rw-r--r--test/CodeGen/builtins-powi.c29
-rw-r--r--test/CodeGen/builtins-x86.c522
-rw-r--r--test/CodeGen/builtins.c124
-rw-r--r--test/CodeGen/builtinshufflevector.c5
-rw-r--r--test/CodeGen/c-strings.c36
-rw-r--r--test/CodeGen/cast-to-union.c13
-rw-r--r--test/CodeGen/cast.c6
-rw-r--r--test/CodeGen/cfstring.c13
-rw-r--r--test/CodeGen/cfstring2.c13
-rw-r--r--test/CodeGen/cleanup-stack.c25
-rw-r--r--test/CodeGen/complex.c61
-rw-r--r--test/CodeGen/compound-literal.c12
-rw-r--r--test/CodeGen/compound-type.c7
-rw-r--r--test/CodeGen/compound.c25
-rw-r--r--test/CodeGen/conditional-gnu-ext.c12
-rw-r--r--test/CodeGen/conditional.c44
-rw-r--r--test/CodeGen/const-init.c104
-rw-r--r--test/CodeGen/const-label-addr.c4
-rw-r--r--test/CodeGen/constant-comparison.c12
-rw-r--r--test/CodeGen/constructor-attribute.c38
-rw-r--r--test/CodeGen/cxx-condition.cpp9
-rw-r--r--test/CodeGen/cxx-default-arg.cpp25
-rw-r--r--test/CodeGen/cxx-value-init.cpp11
-rw-r--r--test/CodeGen/darwin-string-literals.c10
-rw-r--r--test/CodeGen/debug-info.c37
-rw-r--r--test/CodeGen/designated-initializers.c21
-rw-r--r--test/CodeGen/dllimport-dllexport.c7
-rw-r--r--test/CodeGen/dostmt.c70
-rw-r--r--test/CodeGen/emit-all-decls.c8
-rw-r--r--test/CodeGen/empty-union-init.c13
-rw-r--r--test/CodeGen/enum.c18
-rw-r--r--test/CodeGen/exprs.c118
-rw-r--r--test/CodeGen/ext-vector-shuffle.c15
-rw-r--r--test/CodeGen/ext-vector.c129
-rw-r--r--test/CodeGen/extern-block-var.c6
-rw-r--r--test/CodeGen/flexible-array-init.c8
-rw-r--r--test/CodeGen/func-decl-cleanup.c12
-rw-r--r--test/CodeGen/func-return-member.c23
-rw-r--r--test/CodeGen/function-attributes.c69
-rw-r--r--test/CodeGen/function-decay.m10
-rw-r--r--test/CodeGen/functions.c35
-rw-r--r--test/CodeGen/global-decls.c22
-rw-r--r--test/CodeGen/global-init.c7
-rw-r--r--test/CodeGen/global-with-initialiser.c25
-rw-r--r--test/CodeGen/globalinit.c51
-rw-r--r--test/CodeGen/illegal-UTF8.m8
-rw-r--r--test/CodeGen/incomplete-function-type.c10
-rw-r--r--test/CodeGen/indirect-goto.c20
-rw-r--r--test/CodeGen/init-with-member-expr.c21
-rw-r--r--test/CodeGen/init.c31
-rw-r--r--test/CodeGen/inline.c86
-rw-r--r--test/CodeGen/int-to-pointer.c6
-rw-r--r--test/CodeGen/kr-func-promote.c5
-rw-r--r--test/CodeGen/kr-style-block.c10
-rw-r--r--test/CodeGen/libcalls.c22
-rw-r--r--test/CodeGen/lineno-dbginfo.c5
-rw-r--r--test/CodeGen/linkage-redecl.c11
-rw-r--r--test/CodeGen/long-double-x86.c4
-rw-r--r--test/CodeGen/mandel.c67
-rw-r--r--test/CodeGen/mangle.c54
-rw-r--r--test/CodeGen/merge-attrs.c13
-rw-r--r--test/CodeGen/merge-statics.c13
-rw-r--r--test/CodeGen/mmintrin-test.c26
-rw-r--r--test/CodeGen/no-common.c6
-rw-r--r--test/CodeGen/offsetof.c12
-rw-r--r--test/CodeGen/opaque-pointer.c13
-rw-r--r--test/CodeGen/overloadable.c26
-rw-r--r--test/CodeGen/parameter-passing.c57
-rw-r--r--test/CodeGen/pascal-string.c8
-rw-r--r--test/CodeGen/pointer-arithmetic.c22
-rw-r--r--test/CodeGen/pointer-cmp-type.c3
-rw-r--r--test/CodeGen/pointer-to-int.c13
-rw-r--r--test/CodeGen/private-extern.c10
-rw-r--r--test/CodeGen/rdr-6098585-default-after-caserange.c18
-rw-r--r--test/CodeGen/rdr-6098585-default-fallthrough-to-caserange.c20
-rw-r--r--test/CodeGen/rdr-6098585-empty-case-range.c23
-rw-r--r--test/CodeGen/rdr-6098585-fallthrough-to-empty-range.c15
-rw-r--r--test/CodeGen/rdr-6098585-unsigned-caserange.c12
-rw-r--r--test/CodeGen/rdr-6732143-dangling-block-reference.m10
-rw-r--r--test/CodeGen/regparm.c19
-rw-r--r--test/CodeGen/shared-string-literals.c9
-rw-r--r--test/CodeGen/sizeof-vla.c13
-rw-r--r--test/CodeGen/statements.c13
-rw-r--r--test/CodeGen/static-forward-decl-fun.c6
-rw-r--r--test/CodeGen/static-forward-decl.c5
-rw-r--r--test/CodeGen/static-local-union.c4
-rw-r--r--test/CodeGen/static-order.c19
-rw-r--r--test/CodeGen/staticinit.c31
-rw-r--r--test/CodeGen/stdcall-fastcall.c17
-rw-r--r--test/CodeGen/string-init.c10
-rw-r--r--test/CodeGen/string-literal.c7
-rw-r--r--test/CodeGen/struct-comma.c4
-rw-r--r--test/CodeGen/struct-copy.c7
-rw-r--r--test/CodeGen/struct-init.c12
-rw-r--r--test/CodeGen/struct-passing.c21
-rw-r--r--test/CodeGen/struct-x86-darwin.c25
-rw-r--r--test/CodeGen/struct.c192
-rw-r--r--test/CodeGen/switch.c87
-rw-r--r--test/CodeGen/tentative-decls.c39
-rw-r--r--test/CodeGen/thread-specifier.c10
-rw-r--r--test/CodeGen/trapv.c10
-rw-r--r--test/CodeGen/typedef-func.c16
-rw-r--r--test/CodeGen/typedef.c8
-rw-r--r--test/CodeGen/types.c34
-rw-r--r--test/CodeGen/uint128_t.c18
-rw-r--r--test/CodeGen/union-init.c31
-rw-r--r--test/CodeGen/union.c41
-rw-r--r--test/CodeGen/unwind-attr.c5
-rw-r--r--test/CodeGen/var-align.c4
-rw-r--r--test/CodeGen/variable-array.c19
-rw-r--r--test/CodeGen/vector.c13
-rw-r--r--test/CodeGen/visibility.c41
-rw-r--r--test/CodeGen/vla.c37
-rw-r--r--test/CodeGen/volatile-1.c143
-rw-r--r--test/CodeGen/volatile.c94
-rw-r--r--test/CodeGen/weak-global.c3
-rw-r--r--test/CodeGen/weak-incomplete.c5
-rw-r--r--test/CodeGen/whilestmt.c62
-rw-r--r--test/CodeGen/writable-strings.c8
-rw-r--r--test/CodeGen/x86.c23
-rw-r--r--test/CodeGen/x86_32-arguments.c157
-rw-r--r--test/CodeGen/x86_64-arguments.c85
-rw-r--r--test/CodeGenCXX/__null.cpp9
-rw-r--r--test/CodeGenCXX/const-init.cpp11
-rw-r--r--test/CodeGenCXX/explicit-instantiation.cpp11
-rw-r--r--test/CodeGenCXX/expr.cpp5
-rw-r--r--test/CodeGenCXX/extern-c.cpp13
-rw-r--r--test/CodeGenCXX/mangle.cpp87
-rw-r--r--test/CodeGenCXX/member-functions.cpp63
-rw-r--r--test/CodeGenCXX/new.cpp56
-rw-r--r--test/CodeGenCXX/reference-field.cpp6
-rw-r--r--test/CodeGenCXX/references.cpp89
-rw-r--r--test/CodeGenObjC/2008-10-23-invalid-icmp.m7
-rw-r--r--test/CodeGenObjC/attr-strong.c9
-rw-r--r--test/CodeGenObjC/bitfield-1.m81
-rw-r--r--test/CodeGenObjC/bitfield-ivar-metadata.m15
-rw-r--r--test/CodeGenObjC/bitfield-ivar-offsets.m26
-rw-r--r--test/CodeGenObjC/blocks-1.m33
-rw-r--r--test/CodeGenObjC/blocks-2.m11
-rw-r--r--test/CodeGenObjC/blocks.m36
-rw-r--r--test/CodeGenObjC/category-super-class-meth.m19
-rw-r--r--test/CodeGenObjC/class-getter-dotsyntax.m21
-rw-r--r--test/CodeGenObjC/class-obj-hidden-visibility.m6
-rw-r--r--test/CodeGenObjC/class-type.m36
-rw-r--r--test/CodeGenObjC/compatibility-alias.m8
-rw-r--r--test/CodeGenObjC/constant-strings.m4
-rw-r--r--test/CodeGenObjC/continuation-class.m35
-rw-r--r--test/CodeGenObjC/debug-info.m18
-rw-r--r--test/CodeGenObjC/dot-syntax-1.m264
-rw-r--r--test/CodeGenObjC/dot-syntax.m98
-rw-r--r--test/CodeGenObjC/encode-test-1.m36
-rw-r--r--test/CodeGenObjC/encode-test-2.m29
-rw-r--r--test/CodeGenObjC/encode-test-3.m21
-rw-r--r--test/CodeGenObjC/encode-test-4.m5
-rw-r--r--test/CodeGenObjC/encode-test-5.m16
-rw-r--r--test/CodeGenObjC/encode-test.m94
-rw-r--r--test/CodeGenObjC/forward-class-impl-metadata.m41
-rw-r--r--test/CodeGenObjC/hidden-synthesized-ivar.m13
-rw-r--r--test/CodeGenObjC/hidden.m19
-rw-r--r--test/CodeGenObjC/image-info.m2
-rw-r--r--test/CodeGenObjC/implicit-objc_msgSend.m7
-rw-r--r--test/CodeGenObjC/implicit-property.m16
-rw-r--r--test/CodeGenObjC/interface-layout-64.m124
-rw-r--r--test/CodeGenObjC/interface.m34
-rw-r--r--test/CodeGenObjC/ivar-layout-64.m89
-rw-r--r--test/CodeGenObjC/ivars.m14
-rw-r--r--test/CodeGenObjC/link-errors.m39
-rw-r--r--test/CodeGenObjC/message-arrays.m15
-rw-r--r--test/CodeGenObjC/messages-2.m139
-rw-r--r--test/CodeGenObjC/messages.m27
-rw-r--r--test/CodeGenObjC/metadata-symbols-32.m88
-rw-r--r--test/CodeGenObjC/metadata-symbols-64.m130
-rw-r--r--test/CodeGenObjC/metadata_symbols.m61
-rw-r--r--test/CodeGenObjC/newproperty-nested-synthesis-1.m78
-rw-r--r--test/CodeGenObjC/no-category-class.m8
-rw-r--r--test/CodeGenObjC/non-lazy-classes.m33
-rw-r--r--test/CodeGenObjC/objc-align.m47
-rw-r--r--test/CodeGenObjC/objc2-assign-global.m8
-rw-r--r--test/CodeGenObjC/objc2-no-strong-cast.m22
-rw-r--r--test/CodeGenObjC/objc2-no-write-barrier.m18
-rw-r--r--test/CodeGenObjC/objc2-property-encode.m13
-rw-r--r--test/CodeGenObjC/objc2-protocol-enc.m43
-rw-r--r--test/CodeGenObjC/objc2-retain-codegen.m12
-rw-r--r--test/CodeGenObjC/objc2-strong-cast-1.m23
-rw-r--r--test/CodeGenObjC/objc2-strong-cast-2.m27
-rw-r--r--test/CodeGenObjC/objc2-strong-cast.m17
-rw-r--r--test/CodeGenObjC/objc2-weak-compare.m24
-rw-r--r--test/CodeGenObjC/objc2-weak-ivar.m10
-rw-r--r--test/CodeGenObjC/overloadable.m10
-rw-r--r--test/CodeGenObjC/predefined-expr-in-method.m17
-rw-r--r--test/CodeGenObjC/property-aggr-type.m50
-rw-r--r--test/CodeGenObjC/property-agrr-getter.m17
-rw-r--r--test/CodeGenObjC/property-getter-dot-syntax.m11
-rw-r--r--test/CodeGenObjC/property-incr-decr-1.m29
-rw-r--r--test/CodeGenObjC/property-setter-attr.m10
-rw-r--r--test/CodeGenObjC/property.m52
-rw-r--r--test/CodeGenObjC/protocol-definition-hidden-visibility.m19
-rw-r--r--test/CodeGenObjC/protocol-property-synth.m33
-rw-r--r--test/CodeGenObjC/protocols-lazy.m48
-rw-r--r--test/CodeGenObjC/runtime-fns.m33
-rw-r--r--test/CodeGenObjC/super-classmethod-category.m13
-rw-r--r--test/CodeGenObjC/super-dotsyntax-property.m41
-rw-r--r--test/CodeGenObjC/synchronized.m41
-rw-r--r--test/CodeGenObjC/synthesize_ivar-cont-class.m18
-rw-r--r--test/CodeGenObjC/synthesize_ivar.m27
-rw-r--r--test/CodeGenObjC/try.m9
-rw-r--r--test/CodeGenObjC/unname-bf-metadata.m14
-rw-r--r--test/Coverage/ast-printing.c6
-rw-r--r--test/Coverage/ast-printing.cpp6
-rw-r--r--test/Coverage/ast-printing.m5
-rw-r--r--test/Coverage/c-language-features.inc181
-rw-r--r--test/Coverage/codegen-gnu.m3
-rw-r--r--test/Coverage/codegen-next.m4
-rw-r--r--test/Coverage/codegen.c7
-rw-r--r--test/Coverage/cxx-language-features.inc21
-rw-r--r--test/Coverage/html-diagnostics.c15
-rw-r--r--test/Coverage/html-print.c3
-rw-r--r--test/Coverage/objc-language-features.inc81
-rw-r--r--test/Coverage/parse-callbacks.c4
-rw-r--r--test/Coverage/parse-callbacks.m4
-rw-r--r--test/Coverage/targets.c18
-rw-r--r--test/Coverage/verbose.c1
-rw-r--r--test/Driver/Xarch.c10
-rw-r--r--test/Driver/analyze.c9
-rw-r--r--test/Driver/bindings.c56
-rw-r--r--test/Driver/ccc-add-args.c3
-rw-r--r--test/Driver/clang-translation.c16
-rw-r--r--test/Driver/clang_cpp.c4
-rw-r--r--test/Driver/clang_f_opts.c10
-rw-r--r--test/Driver/darwin-cc.c6
-rw-r--r--test/Driver/darwin-ld.c44
-rw-r--r--test/Driver/darwin-version.c6
-rw-r--r--test/Driver/dragonfly.c6
-rw-r--r--test/Driver/emit-llvm.c3
-rw-r--r--test/Driver/flags.c9
-rw-r--r--test/Driver/freebsd.c7
-rw-r--r--test/Driver/hello.c14
-rw-r--r--test/Driver/immediate-options.c5
-rw-r--r--test/Driver/lto.c25
-rw-r--r--test/Driver/parsing.c24
-rw-r--r--test/Driver/phases.c79
-rw-r--r--test/Driver/preprocessor.c6
-rw-r--r--test/Driver/pth.c8
-rw-r--r--test/Driver/qa_override.c6
-rw-r--r--test/Driver/std.c8
-rw-r--r--test/Driver/unknown-gcc-arch.c8
-rw-r--r--test/Driver/x86_features.c3
-rw-r--r--test/FixIt/fixit-at.c5
-rw-r--r--test/FixIt/fixit-c90.c11
-rw-r--r--test/FixIt/fixit-errors-1.c13
-rw-r--r--test/FixIt/fixit-errors.c10
-rw-r--r--test/FixIt/fixit-objc.m8
-rw-r--r--test/FixIt/fixit.c29
-rw-r--r--test/FixIt/fixit.cpp29
-rw-r--r--test/Frontend/darwin-version.c23
-rw-r--r--test/Frontend/dependency-gen.c7
-rw-r--r--test/Frontend/mmacosx-version-min-test.c1
-rw-r--r--test/Frontend/rewrite-macros.c18
-rw-r--r--test/Frontend/stdin.c3
-rw-r--r--test/Lexer/11-27-2007-FloatLiterals.c7
-rw-r--r--test/Lexer/badstring_in_if0.c8
-rw-r--r--test/Lexer/block_cmt_end.c38
-rw-r--r--test/Lexer/c90.c13
-rw-r--r--test/Lexer/comment-escape.c6
-rw-r--r--test/Lexer/constants.c35
-rw-r--r--test/Lexer/counter.c16
-rw-r--r--test/Lexer/cxx0x_keyword.cpp2
-rw-r--r--test/Lexer/cxx0x_keyword_as_cxx98.cpp2
-rw-r--r--test/Lexer/digraph.c15
-rw-r--r--test/Lexer/dollar-idents.c7
-rw-r--r--test/Lexer/escape_newline.c7
-rw-r--r--test/Lexer/multiple-include.c27
-rw-r--r--test/Lexer/numeric-literal-trash.c13
-rw-r--r--test/Lexer/pragma-mark.c11
-rw-r--r--test/Lexer/rdr-6096838-2.c5
-rw-r--r--test/Lexer/rdr-6096838.c6
-rw-r--r--test/Lexer/token-concat.c4
-rw-r--r--test/Lexer/unknown-char.c2
-rw-r--r--test/Makefile47
-rw-r--r--test/Misc/caret-diags-macros.c26
-rw-r--r--test/Misc/caret-diags-scratch-buffer.c12
-rw-r--r--test/Misc/diag-checker.c5
-rw-r--r--test/Misc/diag-mapping.c30
-rw-r--r--test/Misc/diag-mapping2.c19
-rw-r--r--test/Misc/emit-html-insert.c4
-rw-r--r--test/Misc/emit-html.c18
-rw-r--r--test/Misc/message-length.c35
-rw-r--r--test/Misc/predefines.c5
-rw-r--r--test/PCH/asm.c11
-rw-r--r--test/PCH/asm.h14
-rw-r--r--test/PCH/attrs.c8
-rw-r--r--test/PCH/attrs.h7
-rw-r--r--test/PCH/blocks.c12
-rw-r--r--test/PCH/blocks.h14
-rw-r--r--test/PCH/builtins.c10
-rw-r--r--test/PCH/builtins.h2
-rw-r--r--test/PCH/enum.c15
-rw-r--r--test/PCH/enum.h16
-rw-r--r--test/PCH/exprs.c89
-rw-r--r--test/PCH/exprs.h86
-rw-r--r--test/PCH/ext_vector.c10
-rw-r--r--test/PCH/ext_vector.h4
-rw-r--r--test/PCH/external-defs.c19
-rw-r--r--test/PCH/external-defs.h13
-rw-r--r--test/PCH/functions.c20
-rw-r--r--test/PCH/functions.h6
-rw-r--r--test/PCH/fuzzy-pch.c19
-rw-r--r--test/PCH/fuzzy-pch.h2
-rw-r--r--test/PCH/line-directive.c25
-rw-r--r--test/PCH/line-directive.h2
-rw-r--r--test/PCH/method_pool.h37
-rw-r--r--test/PCH/method_pool.m21
-rw-r--r--test/PCH/multiple_decls.c17
-rw-r--r--test/PCH/multiple_decls.h7
-rw-r--r--test/PCH/nonvisible-external-defs.c10
-rw-r--r--test/PCH/nonvisible-external-defs.h11
-rw-r--r--test/PCH/objc_exprs.h18
-rw-r--r--test/PCH/objc_exprs.m28
-rw-r--r--test/PCH/objc_import.h7
-rw-r--r--test/PCH/objc_import.m15
-rw-r--r--test/PCH/objc_methods.h11
-rw-r--r--test/PCH/objc_methods.m16
-rw-r--r--test/PCH/objc_property.h12
-rw-r--r--test/PCH/objc_property.m11
-rw-r--r--test/PCH/preprocess.c5
-rw-r--r--test/PCH/preprocess.h7
-rw-r--r--test/PCH/stmts.c14
-rw-r--r--test/PCH/stmts.h96
-rw-r--r--test/PCH/struct.c28
-rw-r--r--test/PCH/struct.h29
-rw-r--r--test/PCH/tentative-defs.c9
-rw-r--r--test/PCH/tentative-defs.h9
-rw-r--r--test/PCH/types.c72
-rw-r--r--test/PCH/types.h44
-rw-r--r--test/PCH/va_arg.c12
-rw-r--r--test/PCH/va_arg.h8
-rw-r--r--test/PCH/variables.c23
-rw-r--r--test/PCH/variables.h26
-rwxr-xr-xtest/Parser/2008-10-31-parse-noop-failure.c4
-rw-r--r--test/Parser/CompoundStmtScope.c8
-rw-r--r--test/Parser/MicrosoftExtensions.c30
-rw-r--r--test/Parser/argument_qualified.c5
-rw-r--r--test/Parser/argument_redef.c6
-rw-r--r--test/Parser/argument_scope.c6
-rw-r--r--test/Parser/asm.c15
-rw-r--r--test/Parser/attributes.c53
-rw-r--r--test/Parser/bad-control.c9
-rw-r--r--test/Parser/block-block-storageclass.c19
-rw-r--r--test/Parser/block-pointer-decl.c26
-rw-r--r--test/Parser/builtin_classify_type.c21
-rw-r--r--test/Parser/builtin_types_compatible.c43
-rw-r--r--test/Parser/c-namespace.c6
-rw-r--r--test/Parser/char-literal-printing.c31
-rw-r--r--test/Parser/check-objc2-syntax-1.m10
-rw-r--r--test/Parser/check-syntax-1.m4
-rw-r--r--test/Parser/check_cast.c12
-rw-r--r--test/Parser/compound_literal.c5
-rw-r--r--test/Parser/control-scope.c8
-rw-r--r--test/Parser/cxx-ambig-paren-expr.cpp26
-rw-r--r--test/Parser/cxx-bool.cpp4
-rw-r--r--test/Parser/cxx-casting.cpp36
-rw-r--r--test/Parser/cxx-class.cpp38
-rw-r--r--test/Parser/cxx-condition.cpp11
-rw-r--r--test/Parser/cxx-decl.cpp3
-rw-r--r--test/Parser/cxx-exception-spec.cpp17
-rw-r--r--test/Parser/cxx-friend.cpp17
-rw-r--r--test/Parser/cxx-namespace-alias.cpp8
-rw-r--r--test/Parser/cxx-reference.cpp21
-rw-r--r--test/Parser/cxx-template-decl.cpp82
-rw-r--r--test/Parser/cxx-throw.cpp15
-rw-r--r--test/Parser/cxx-try.cpp41
-rw-r--r--test/Parser/cxx-typeid.cpp13
-rw-r--r--test/Parser/cxx-typeof.cpp7
-rw-r--r--test/Parser/cxx-using-directive.cpp41
-rw-r--r--test/Parser/cxx-variadic-func.cpp5
-rw-r--r--test/Parser/cxx0x-rvalue-reference.cpp9
-rw-r--r--test/Parser/declarators.c66
-rw-r--r--test/Parser/designator.c17
-rw-r--r--test/Parser/encode.m8
-rw-r--r--test/Parser/enhanced-proto-1.m17
-rw-r--r--test/Parser/expressions.c50
-rw-r--r--test/Parser/expressions.m6
-rw-r--r--test/Parser/extension.c20
-rw-r--r--test/Parser/function-decls.c10
-rw-r--r--test/Parser/goto-ident.c6
-rw-r--r--test/Parser/if-scope-c90.c8
-rw-r--r--test/Parser/if-scope-c99.c8
-rw-r--r--test/Parser/implicit-casts.c20
-rw-r--r--test/Parser/method-prototype-1.m43
-rw-r--r--test/Parser/namelookup-bug-1.c7
-rw-r--r--test/Parser/namelookup-bug-2.c14
-rw-r--r--test/Parser/objc-alias-printing.m18
-rw-r--r--test/Parser/objc-category-neg-1.m8
-rw-r--r--test/Parser/objc-forcollection-1.m43
-rw-r--r--test/Parser/objc-forcollection-neg-2.m38
-rw-r--r--test/Parser/objc-forcollection-neg.m37
-rw-r--r--test/Parser/objc-foreach-syntax.m26
-rw-r--r--test/Parser/objc-init.m41
-rw-r--r--test/Parser/objc-interfaces.m8
-rw-r--r--test/Parser/objc-messaging-1.m19
-rw-r--r--test/Parser/objc-messaging-neg-1.m7
-rw-r--r--test/Parser/objc-missing-impl.m2
-rw-r--r--test/Parser/objc-property-syntax.m12
-rw-r--r--test/Parser/objc-quirks.m10
-rw-r--r--test/Parser/objc-try-catch-1.m68
-rw-r--r--test/Parser/objc-type-printing.m19
-rw-r--r--test/Parser/parmvardecl_conversion.c4
-rw-r--r--test/Parser/pointer-arithmetic.c9
-rw-r--r--test/Parser/pointer_promotion.c18
-rw-r--r--test/Parser/pragma-pack.c32
-rw-r--r--test/Parser/prefix-attributes.m8
-rw-r--r--test/Parser/promote_types_in_proto.c9
-rw-r--r--test/Parser/recovery.c75
-rw-r--r--test/Parser/selector-1.m14
-rw-r--r--test/Parser/statements.c56
-rw-r--r--test/Parser/struct-recursion.c11
-rw-r--r--test/Parser/traditional_arg_scope.c7
-rw-r--r--test/Parser/typeof.c19
-rw-r--r--test/Parser/types.c14
-rw-r--r--test/Preprocessor/_Pragma-dependency.c7
-rw-r--r--test/Preprocessor/_Pragma-location.c4
-rw-r--r--test/Preprocessor/_Pragma-physloc.c6
-rw-r--r--test/Preprocessor/_Pragma-syshdr2.c5
-rw-r--r--test/Preprocessor/_Pragma.c10
-rw-r--r--test/Preprocessor/assembler-with-cpp.c77
-rw-r--r--test/Preprocessor/builtin_line.c13
-rw-r--r--test/Preprocessor/c90.c10
-rw-r--r--test/Preprocessor/c99-6_10_3_3_p4.c6
-rw-r--r--test/Preprocessor/c99-6_10_3_4_p5.c29
-rw-r--r--test/Preprocessor/c99-6_10_3_4_p6.c24
-rw-r--r--test/Preprocessor/c99-6_10_3_4_p7.c9
-rw-r--r--test/Preprocessor/c99-6_10_3_4_p9.c16
-rw-r--r--test/Preprocessor/clang_headers.c3
-rw-r--r--test/Preprocessor/comment_save.c7
-rw-r--r--test/Preprocessor/comment_save_if.c6
-rw-r--r--test/Preprocessor/comment_save_macro.c8
-rw-r--r--test/Preprocessor/cxx_and.cpp17
-rw-r--r--test/Preprocessor/cxx_bitand.cpp16
-rw-r--r--test/Preprocessor/cxx_bitor.cpp18
-rw-r--r--test/Preprocessor/cxx_compl.cpp16
-rw-r--r--test/Preprocessor/cxx_not.cpp15
-rw-r--r--test/Preprocessor/cxx_not_eq.cpp16
-rw-r--r--test/Preprocessor/cxx_oper_keyword.cpp7
-rw-r--r--test/Preprocessor/cxx_oper_spelling.cpp11
-rw-r--r--test/Preprocessor/cxx_or.cpp17
-rw-r--r--test/Preprocessor/cxx_true.cpp13
-rw-r--r--test/Preprocessor/cxx_xor.cpp18
-rw-r--r--test/Preprocessor/dependencies-and-pp.c5
-rw-r--r--test/Preprocessor/disabled-cond-diags.c10
-rw-r--r--test/Preprocessor/dump-macros-spacing.c13
-rw-r--r--test/Preprocessor/dump-options.c3
-rw-r--r--test/Preprocessor/dump_macros.c31
-rw-r--r--test/Preprocessor/dumptokens_phyloc.c5
-rw-r--r--test/Preprocessor/expr_comma.c10
-rw-r--r--test/Preprocessor/expr_invalid_tok.c15
-rw-r--r--test/Preprocessor/expr_liveness.c52
-rw-r--r--test/Preprocessor/expr_multichar.c5
-rw-r--r--test/Preprocessor/expr_usual_conversions.c13
-rw-r--r--test/Preprocessor/extension-warning.c18
-rw-r--r--test/Preprocessor/file_to_include.h3
-rw-r--r--test/Preprocessor/function_macro_file.c5
-rw-r--r--test/Preprocessor/function_macro_file.h3
-rw-r--r--test/Preprocessor/hash_line.c8
-rw-r--r--test/Preprocessor/hash_space.c6
-rw-r--r--test/Preprocessor/header_lookup1.c2
-rw-r--r--test/Preprocessor/if_warning.c21
-rw-r--r--test/Preprocessor/ifdef-recover.c15
-rw-r--r--test/Preprocessor/import_self.c7
-rw-r--r--test/Preprocessor/include-directive1.c14
-rw-r--r--test/Preprocessor/include-directive2.c17
-rw-r--r--test/Preprocessor/include-directive3.c3
-rw-r--r--test/Preprocessor/include-macros.c4
-rw-r--r--test/Preprocessor/include-pth.c3
-rw-r--r--test/Preprocessor/indent_macro.c6
-rw-r--r--test/Preprocessor/line-directive.c92
-rw-r--r--test/Preprocessor/macro-multiline.c8
-rw-r--r--test/Preprocessor/macro_arg_keyword.c6
-rw-r--r--test/Preprocessor/macro_disable.c13
-rw-r--r--test/Preprocessor/macro_disable2.c8
-rw-r--r--test/Preprocessor/macro_disable3.c8
-rw-r--r--test/Preprocessor/macro_disable4.c6
-rw-r--r--test/Preprocessor/macro_expand.c19
-rw-r--r--test/Preprocessor/macro_expandloc.c6
-rw-r--r--test/Preprocessor/macro_expandloc2.c6
-rw-r--r--test/Preprocessor/macro_fn.c46
-rw-r--r--test/Preprocessor/macro_fn_comma_swallow.c21
-rw-r--r--test/Preprocessor/macro_fn_disable_expand.c11
-rw-r--r--test/Preprocessor/macro_fn_lparen_scan.c27
-rw-r--r--test/Preprocessor/macro_fn_lparen_scan2.c7
-rw-r--r--test/Preprocessor/macro_fn_placemarker.c5
-rw-r--r--test/Preprocessor/macro_fn_preexpand.c12
-rw-r--r--test/Preprocessor/macro_fn_varargs_iso.c11
-rw-r--r--test/Preprocessor/macro_fn_varargs_named.c10
-rw-r--r--test/Preprocessor/macro_misc.c23
-rw-r--r--test/Preprocessor/macro_not_define.c9
-rw-r--r--test/Preprocessor/macro_paste_bad.c35
-rw-r--r--test/Preprocessor/macro_paste_bcpl_comment.c5
-rw-r--r--test/Preprocessor/macro_paste_c_block_comment.c7
-rw-r--r--test/Preprocessor/macro_paste_commaext.c13
-rw-r--r--test/Preprocessor/macro_paste_empty.c13
-rw-r--r--test/Preprocessor/macro_paste_hard.c17
-rw-r--r--test/Preprocessor/macro_paste_hashhash.c7
-rw-r--r--test/Preprocessor/macro_paste_mscomment.c20
-rw-r--r--test/Preprocessor/macro_paste_none.c6
-rw-r--r--test/Preprocessor/macro_paste_simple.c5
-rw-r--r--test/Preprocessor/macro_paste_spacing.c7
-rw-r--r--test/Preprocessor/macro_paste_spacing2.c6
-rw-r--r--test/Preprocessor/macro_rescan.c9
-rw-r--r--test/Preprocessor/macro_rescan2.c15
-rw-r--r--test/Preprocessor/macro_rescan_varargs.c10
-rw-r--r--test/Preprocessor/macro_rparen_scan.c8
-rw-r--r--test/Preprocessor/macro_rparen_scan2.c8
-rw-r--r--test/Preprocessor/macro_space.c5
-rw-r--r--test/Preprocessor/mi_opt.c11
-rw-r--r--test/Preprocessor/mi_opt.h4
-rw-r--r--test/Preprocessor/objc-pp.m4
-rw-r--r--test/Preprocessor/optimize.c29
-rw-r--r--test/Preprocessor/output_paste_avoid.c23
-rw-r--r--test/Preprocessor/overflow.c25
-rw-r--r--test/Preprocessor/pic.c10
-rw-r--r--test/Preprocessor/pr2086.c11
-rw-r--r--test/Preprocessor/pr2086.h6
-rw-r--r--test/Preprocessor/pragma_microsoft.c20
-rw-r--r--test/Preprocessor/pragma_poison.c20
-rw-r--r--test/Preprocessor/pragma_unknown.c28
-rw-r--r--test/Preprocessor/print_line_track.c17
-rw-r--r--test/Preprocessor/skipping_unclean.c9
-rw-r--r--test/Preprocessor/stringize_misc.c26
-rw-r--r--test/Preprocessor/stringize_space.c4
-rw-r--r--test/Preprocessor/stringize_space2.c6
-rw-r--r--test/Preprocessor/undef-error.c5
-rw-r--r--test/Preprocessor/unterminated.c5
-rw-r--r--test/Preprocessor/x86_target_features.c35
-rw-r--r--test/Rewriter/block-test.c38
-rw-r--r--test/Rewriter/crash.m25
-rw-r--r--test/Rewriter/finally.m27
-rw-r--r--test/Rewriter/id-test-3.m14
-rw-r--r--test/Rewriter/ivar-encoding-1.m15
-rw-r--r--test/Rewriter/ivar-encoding-2.m12
-rw-r--r--test/Rewriter/metadata-test-1.m12
-rw-r--r--test/Rewriter/metadata-test-2.m15
-rw-r--r--test/Rewriter/method-encoding-1.m18
-rw-r--r--test/Rewriter/objc-encoding-bug-1.m19
-rw-r--r--test/Rewriter/objc-ivar-receiver-1.m24
-rw-r--r--test/Rewriter/objc-string-concat-1.m14
-rw-r--r--test/Rewriter/objc-super-test.m18
-rw-r--r--test/Rewriter/objc-synchronized-1.m20
-rw-r--r--test/Rewriter/properties.m54
-rw-r--r--test/Rewriter/protocol-rewrite-1.m48
-rw-r--r--test/Rewriter/rewrite-api-bug.m11
-rw-r--r--test/Rewriter/rewrite-foreach-1.m37
-rw-r--r--test/Rewriter/rewrite-foreach-2.m34
-rw-r--r--test/Rewriter/rewrite-foreach-3.m29
-rw-r--r--test/Rewriter/rewrite-foreach-4.m32
-rw-r--r--test/Rewriter/rewrite-foreach-5.m47
-rw-r--r--test/Rewriter/rewrite-foreach-6.m13
-rw-r--r--test/Rewriter/rewrite-nest.m27
-rw-r--r--test/Rewriter/rewrite-protocol-type-1.m24
-rw-r--r--test/Rewriter/rewrite-try-catch.m27
-rw-r--r--test/Rewriter/static-type-protocol-1.m27
-rw-r--r--test/Rewriter/undecl-objc-h.m29
-rw-r--r--test/Rewriter/undeclared-method-1.m9
-rw-r--r--test/Rewriter/undef-field-reference-1.m15
-rw-r--r--test/Rewriter/va-method.m17
-rw-r--r--test/Sema/128bitint.c6
-rw-r--r--test/Sema/PR2727.c8
-rw-r--r--test/Sema/PR2728.c9
-rw-r--r--test/Sema/PR2919-builtin-types-compat-strips-crv.c7
-rw-r--r--test/Sema/PR2923.c12
-rw-r--r--test/Sema/PR2963-enum-constant.c17
-rw-r--r--test/Sema/address-constant.c10
-rw-r--r--test/Sema/address_spaces.c32
-rw-r--r--test/Sema/align-x86.c14
-rw-r--r--test/Sema/annotate.c7
-rw-r--r--test/Sema/anonymous-struct-union.c98
-rw-r--r--test/Sema/arg-duplicate.c14
-rw-r--r--test/Sema/arg-scope-c99.c2
-rw-r--r--test/Sema/arg-scope.c5
-rw-r--r--test/Sema/array-constraint.c52
-rw-r--r--test/Sema/array-declared-as-incorrect-type.c16
-rw-r--r--test/Sema/array-init.c265
-rw-r--r--test/Sema/asm.c78
-rw-r--r--test/Sema/assign-null.c10
-rw-r--r--test/Sema/assign.c15
-rw-r--r--test/Sema/ast-print.c8
-rw-r--r--test/Sema/attr-aligned.c21
-rw-r--r--test/Sema/attr-cleanup.c40
-rw-r--r--test/Sema/attr-deprecated.c45
-rw-r--r--test/Sema/attr-mode.c22
-rw-r--r--test/Sema/attr-nodebug.c8
-rw-r--r--test/Sema/attr-noinline.c8
-rw-r--r--test/Sema/attr-noreturn.c27
-rw-r--r--test/Sema/attr-regparm.c7
-rw-r--r--test/Sema/attr-unused.c12
-rw-r--r--test/Sema/attr-used.c20
-rw-r--r--test/Sema/attr-warn_unused_result.c19
-rw-r--r--test/Sema/attr-weak.c13
-rw-r--r--test/Sema/bitfield-layout.c32
-rw-r--r--test/Sema/bitfield.c36
-rw-r--r--test/Sema/block-args.c29
-rw-r--r--test/Sema/block-as-object.m20
-rw-r--r--test/Sema/block-byref-args.c18
-rw-r--r--test/Sema/block-call.c55
-rw-r--r--test/Sema/block-explicit-return-type.c81
-rw-r--r--test/Sema/block-labels.c17
-rw-r--r--test/Sema/block-literal.c124
-rw-r--r--test/Sema/block-misc.c187
-rw-r--r--test/Sema/block-printf-attribute-1.c15
-rw-r--r--test/Sema/block-return.c104
-rw-r--r--test/Sema/block-sentinel-attribute.c25
-rw-r--r--test/Sema/block-storageclass.c18
-rw-r--r--test/Sema/builtin-object-size.c28
-rw-r--r--test/Sema/builtin-prefetch.c13
-rw-r--r--test/Sema/builtin-stackaddress.c16
-rw-r--r--test/Sema/builtins.c52
-rw-r--r--test/Sema/c89-2.c7
-rw-r--r--test/Sema/c89.c82
-rw-r--r--test/Sema/callingconv.c10
-rw-r--r--test/Sema/carbon-pth.c7
-rw-r--r--test/Sema/carbon.c5
-rw-r--r--test/Sema/cast-to-union.c19
-rw-r--r--test/Sema/cast.c14
-rw-r--r--test/Sema/check-increment.c10
-rw-r--r--test/Sema/compare.c17
-rw-r--r--test/Sema/complex-int.c52
-rw-r--r--test/Sema/complex-promotion.c15
-rw-r--r--test/Sema/compound-literal.c33
-rw-r--r--test/Sema/conditional-expr.c51
-rw-r--r--test/Sema/conditional.c15
-rw-r--r--test/Sema/const-eval.c67
-rw-r--r--test/Sema/const-ptr-int-ptr-cast.c5
-rw-r--r--test/Sema/constant-builtins-2.c50
-rw-r--r--test/Sema/constant-builtins.c24
-rw-r--r--test/Sema/constructor-attribute.c15
-rw-r--r--test/Sema/darwin-align-cast.c23
-rw-r--r--test/Sema/decl-invalid.c29
-rw-r--r--test/Sema/decl-type-merging.c16
-rw-r--r--test/Sema/declspec.c23
-rw-r--r--test/Sema/default.c8
-rw-r--r--test/Sema/default1.c2
-rw-r--r--test/Sema/deref.c44
-rw-r--r--test/Sema/designated-initializers.c234
-rw-r--r--test/Sema/dllimport-dllexport.c18
-rw-r--r--test/Sema/enum.c86
-rw-r--r--test/Sema/expr-address-of.c109
-rw-r--r--test/Sema/expr-comma-c89.c18
-rw-r--r--test/Sema/expr-comma.c18
-rw-r--r--test/Sema/exprs.c108
-rw-r--r--test/Sema/ext_vector_components.c37
-rw-r--r--test/Sema/flexible-array-init.c58
-rw-r--r--test/Sema/floating-point-compare.c25
-rw-r--r--test/Sema/for.c7
-rw-r--r--test/Sema/format-attribute.c34
-rw-r--r--test/Sema/format-string-percentm.c6
-rw-r--r--test/Sema/format-strings.c132
-rw-r--r--test/Sema/function-pointer-sentinel-attribute.c23
-rw-r--r--test/Sema/function-ptr.c11
-rw-r--r--test/Sema/function-redecl.c127
-rw-r--r--test/Sema/function-sentinel-attr.c30
-rw-r--r--test/Sema/function.c89
-rw-r--r--test/Sema/gnu89.c3
-rw-r--r--test/Sema/heinous-extensions-off.c10
-rw-r--r--test/Sema/heinous-extensions-on.c10
-rw-r--r--test/Sema/i-c-e.c66
-rw-r--r--test/Sema/if-empty-body.c16
-rw-r--r--test/Sema/illegal-types.c7
-rw-r--r--test/Sema/implicit-builtin-decl.c53
-rw-r--r--test/Sema/implicit-builtin-freestanding.c4
-rw-r--r--test/Sema/implicit-builtin-redecl.c14
-rw-r--r--test/Sema/implicit-cast.c8
-rw-r--r--test/Sema/implicit-decl.c17
-rw-r--r--test/Sema/implicit-def.c8
-rw-r--r--test/Sema/implicit-int.c31
-rw-r--r--test/Sema/incompatible-sign.c5
-rw-r--r--test/Sema/incomplete-call.c13
-rw-r--r--test/Sema/incomplete-decl.c30
-rw-r--r--test/Sema/indirect-goto.c8
-rw-r--r--test/Sema/init-struct-qualified.c12
-rw-r--r--test/Sema/init.c128
-rw-r--r--test/Sema/inline.c6
-rw-r--r--test/Sema/int-arith-convert.c12
-rw-r--r--test/Sema/invalid-decl.c22
-rw-r--r--test/Sema/invalid-init-diag.c4
-rw-r--r--test/Sema/invalid-struct-init.c29
-rw-r--r--test/Sema/knr-def-call.c18
-rw-r--r--test/Sema/knr-variadic-def.c29
-rw-r--r--test/Sema/member-reference.c20
-rw-r--r--test/Sema/merge-decls.c39
-rw-r--r--test/Sema/ms-fuzzy-asm.c9
-rw-r--r--test/Sema/nested-redef.c22
-rw-r--r--test/Sema/nonnull.c32
-rw-r--r--test/Sema/offsetof.c50
-rw-r--r--test/Sema/overloadable-complex.c50
-rw-r--r--test/Sema/overloadable.c53
-rw-r--r--test/Sema/pointer-addition.c19
-rw-r--r--test/Sema/pointer-subtract-compat.c11
-rw-r--r--test/Sema/pragma-pack-2.c93
-rw-r--r--test/Sema/pragma-pack-3.c34
-rw-r--r--test/Sema/pragma-pack.c27
-rw-r--r--test/Sema/pragma-unused.c38
-rw-r--r--test/Sema/predef.c19
-rw-r--r--test/Sema/predefined-function.c38
-rw-r--r--test/Sema/private-extern.c88
-rw-r--r--test/Sema/rdar6248119.m27
-rw-r--r--test/Sema/rdr6094103-unordered-compare-promote.c6
-rw-r--r--test/Sema/recover-goto.c4
-rw-r--r--test/Sema/redefinition.c10
-rw-r--r--test/Sema/return-silent.c9
-rw-r--r--test/Sema/return.c12
-rw-r--r--test/Sema/scope-check.c196
-rw-r--r--test/Sema/self-comparison.c33
-rw-r--r--test/Sema/sentinel-attribute.c15
-rw-r--r--test/Sema/shift.c6
-rw-r--r--test/Sema/statements.c29
-rw-r--r--test/Sema/static-init.c23
-rw-r--r--test/Sema/stdcall-fastcall.c10
-rw-r--r--test/Sema/struct-cast.c14
-rw-r--r--test/Sema/struct-compat.c17
-rw-r--r--test/Sema/struct-decl.c43
-rw-r--r--test/Sema/struct-packed-align.c111
-rw-r--r--test/Sema/surpress-deprecated.c7
-rw-r--r--test/Sema/switch.c70
-rw-r--r--test/Sema/tentative-decls.c65
-rw-r--r--test/Sema/text-diag.c4
-rw-r--r--test/Sema/thread-specifier.c21
-rw-r--r--test/Sema/transparent-union-pointer.c14
-rw-r--r--test/Sema/transparent-union.c40
-rw-r--r--test/Sema/type-spec-struct-union.c65
-rw-r--r--test/Sema/typecheck-binop.c27
-rw-r--r--test/Sema/typedef-prototype.c8
-rw-r--r--test/Sema/typedef-redef.c11
-rw-r--r--test/Sema/typedef-retain.c38
-rw-r--r--test/Sema/typedef-variable-type.c3
-rw-r--r--test/Sema/types.c39
-rw-r--r--test/Sema/ucn-cstring.c17
-rw-r--r--test/Sema/unnamed-bitfield-init.c6
-rw-r--r--test/Sema/unused-expr.c46
-rw-r--r--test/Sema/usual-float.c12
-rw-r--r--test/Sema/va_arg_x86_32.c6
-rw-r--r--test/Sema/va_arg_x86_64.c16
-rw-r--r--test/Sema/var-redecl.c61
-rw-r--r--test/Sema/varargs-x86-64.c8
-rw-r--r--test/Sema/varargs.c63
-rw-r--r--test/Sema/variadic-block.c41
-rw-r--r--test/Sema/vector-assign.c45
-rw-r--r--test/Sema/vector-cast.c38
-rw-r--r--test/Sema/vector-init.c23
-rw-r--r--test/Sema/vla.c56
-rw-r--r--test/Sema/void_arg.c26
-rw-r--r--test/Sema/warn-freestanding-complex.c4
-rw-r--r--test/Sema/warn-missing-prototypes.c37
-rw-r--r--test/Sema/wchar.c12
-rw-r--r--test/SemaCXX/__null.cpp14
-rw-r--r--test/SemaCXX/abstract.cpp128
-rw-r--r--test/SemaCXX/access-base-class.cpp82
-rw-r--r--test/SemaCXX/access.cpp23
-rw-r--r--test/SemaCXX/addr-of-overloaded-function.cpp29
-rw-r--r--test/SemaCXX/address-of.cpp35
-rw-r--r--test/SemaCXX/aggregate-initialization.cpp28
-rw-r--r--test/SemaCXX/anonymous-union.cpp113
-rw-r--r--test/SemaCXX/attr-unavailable.cpp20
-rw-r--r--test/SemaCXX/basic_lookup_argdep.cpp60
-rw-r--r--test/SemaCXX/blocks.cpp11
-rw-r--r--test/SemaCXX/bool.cpp18
-rw-r--r--test/SemaCXX/carbon.cpp5
-rw-r--r--test/SemaCXX/class-names.cpp52
-rw-r--r--test/SemaCXX/class.cpp112
-rw-r--r--test/SemaCXX/complex-overload.cpp50
-rw-r--r--test/SemaCXX/composite-pointer-type.cpp27
-rw-r--r--test/SemaCXX/condition.cpp35
-rw-r--r--test/SemaCXX/conditional-expr.cpp181
-rw-r--r--test/SemaCXX/const-cast.cpp63
-rw-r--r--test/SemaCXX/constant-expression.cpp83
-rw-r--r--test/SemaCXX/constructor-initializer.cpp56
-rw-r--r--test/SemaCXX/constructor-recovery.cpp10
-rw-r--r--test/SemaCXX/constructor.cpp60
-rw-r--r--test/SemaCXX/conversion-function.cpp66
-rw-r--r--test/SemaCXX/convert-to-bool.cpp67
-rw-r--r--test/SemaCXX/converting-constructor.cpp40
-rw-r--r--test/SemaCXX/copy-assignment.cpp99
-rw-r--r--test/SemaCXX/copy-initialization.cpp23
-rw-r--r--test/SemaCXX/dcl_ambig_res.cpp66
-rw-r--r--test/SemaCXX/dcl_init_aggr.cpp122
-rw-r--r--test/SemaCXX/decl-expr-ambiguity.cpp43
-rw-r--r--test/SemaCXX/default1.cpp31
-rw-r--r--test/SemaCXX/default2.cpp123
-rw-r--r--test/SemaCXX/deleted-function.cpp36
-rw-r--r--test/SemaCXX/dependent-types.cpp10
-rw-r--r--test/SemaCXX/derived-to-base-ambig.cpp33
-rw-r--r--test/SemaCXX/destructor.cpp56
-rw-r--r--test/SemaCXX/direct-initializer.cpp36
-rw-r--r--test/SemaCXX/do-while-scope.cpp8
-rw-r--r--test/SemaCXX/dynamic-cast.cpp74
-rw-r--r--test/SemaCXX/elaborated-type-specifier.cpp47
-rw-r--r--test/SemaCXX/enum.cpp38
-rw-r--r--test/SemaCXX/exception-spec.cpp35
-rw-r--r--test/SemaCXX/exceptions.cpp99
-rw-r--r--test/SemaCXX/expressions.cpp9
-rw-r--r--test/SemaCXX/fntype-decl.cpp20
-rw-r--r--test/SemaCXX/friend.cpp6
-rw-r--r--test/SemaCXX/function-redecl.cpp26
-rw-r--r--test/SemaCXX/function-type-qual.cpp23
-rw-r--r--test/SemaCXX/functional-cast.cpp27
-rw-r--r--test/SemaCXX/i-c-e-cxx.cpp6
-rw-r--r--test/SemaCXX/implicit-int.cpp5
-rw-r--r--test/SemaCXX/inherit.cpp32
-rw-r--r--test/SemaCXX/inline.cpp5
-rw-r--r--test/SemaCXX/linkage-spec.cpp27
-rw-r--r--test/SemaCXX/member-expr-static.cpp21
-rw-r--r--test/SemaCXX/member-expr.cpp33
-rw-r--r--test/SemaCXX/member-location.cpp5
-rw-r--r--test/SemaCXX/member-name-lookup.cpp148
-rw-r--r--test/SemaCXX/member-pointer-size.cpp15
-rw-r--r--test/SemaCXX/member-pointer.cpp129
-rw-r--r--test/SemaCXX/ms-exception-spec.cpp3
-rw-r--r--test/SemaCXX/namespace-alias.cpp64
-rw-r--r--test/SemaCXX/namespace.cpp69
-rw-r--r--test/SemaCXX/nested-name-spec.cpp173
-rw-r--r--test/SemaCXX/new-delete.cpp97
-rw-r--r--test/SemaCXX/no-implicit-builtin-decls.cpp7
-rw-r--r--test/SemaCXX/nullptr.cpp67
-rw-r--r--test/SemaCXX/offsetof.cpp15
-rw-r--r--test/SemaCXX/overload-call-copycon.cpp48
-rw-r--r--test/SemaCXX/overload-call.cpp280
-rw-r--r--test/SemaCXX/overload-decl.cpp31
-rw-r--r--test/SemaCXX/overload-member-call.cpp56
-rw-r--r--test/SemaCXX/overloaded-builtin-operators.cpp122
-rw-r--r--test/SemaCXX/overloaded-operator-decl.cpp39
-rw-r--r--test/SemaCXX/overloaded-operator.cpp211
-rw-r--r--test/SemaCXX/qualification-conversion.cpp23
-rw-r--r--test/SemaCXX/qualified-id-lookup.cpp111
-rw-r--r--test/SemaCXX/qualified-names-diag.cpp33
-rw-r--r--test/SemaCXX/qualified-names-print.cpp15
-rw-r--r--test/SemaCXX/references.cpp89
-rw-r--r--test/SemaCXX/reinterpret-cast.cpp90
-rw-r--r--test/SemaCXX/reinterpret-fn-obj-pedantic.cpp9
-rw-r--r--test/SemaCXX/return-stack-addr.cpp112
-rw-r--r--test/SemaCXX/rval-references.cpp91
-rw-r--r--test/SemaCXX/statements.cpp5
-rw-r--r--test/SemaCXX/static-assert.cpp30
-rw-r--r--test/SemaCXX/static-cast.cpp129
-rw-r--r--test/SemaCXX/static-initializers.cpp12
-rw-r--r--test/SemaCXX/struct-class-redecl.cpp8
-rw-r--r--test/SemaCXX/template-specialization.cpp4
-rw-r--r--test/SemaCXX/this.cpp6
-rw-r--r--test/SemaCXX/trivial-constructor.cpp38
-rw-r--r--test/SemaCXX/trivial-destructor.cpp38
-rw-r--r--test/SemaCXX/type-convert-construct.cpp17
-rw-r--r--test/SemaCXX/type-definition-in-specifier.cpp25
-rw-r--r--test/SemaCXX/type-dependent-exprs.cpp24
-rw-r--r--test/SemaCXX/type-traits.cpp111
-rw-r--r--test/SemaCXX/typedef-redecl.cpp31
-rw-r--r--test/SemaCXX/typeid.cpp16
-rw-r--r--test/SemaCXX/types_compatible_p.cpp5
-rw-r--r--test/SemaCXX/unused.cpp15
-rw-r--r--test/SemaCXX/user-defined-conversions.cpp69
-rw-r--r--test/SemaCXX/using-directive.cpp108
-rw-r--r--test/SemaCXX/vararg-non-pod.cpp56
-rw-r--r--test/SemaCXX/virtual-override.cpp106
-rw-r--r--test/SemaCXX/virtuals.cpp38
-rw-r--r--test/SemaCXX/warn-for-var-in-else.cpp30
-rw-r--r--test/SemaCXX/wchar_t.cpp9
-rw-r--r--test/SemaObjC/ContClassPropertyLookup.m18
-rw-r--r--test/SemaObjC/DoubleMethod.m19
-rw-r--r--test/SemaObjC/access-property-getter.m35
-rw-r--r--test/SemaObjC/alias-test-1.m31
-rw-r--r--test/SemaObjC/alias-test-2.m17
-rw-r--r--test/SemaObjC/argument-checking.m25
-rw-r--r--test/SemaObjC/at-defs.m29
-rw-r--r--test/SemaObjC/attr-cleanup.m10
-rw-r--r--test/SemaObjC/attr-deprecated.m99
-rw-r--r--test/SemaObjC/attr-objc-exception.m16
-rw-r--r--test/SemaObjC/attr-objc-gc.m8
-rw-r--r--test/SemaObjC/bad-receiver-1.m19
-rw-r--r--test/SemaObjC/block-attr.m9
-rw-r--r--test/SemaObjC/block-ivar.m19
-rw-r--r--test/SemaObjC/blocks.m46
-rw-r--r--test/SemaObjC/call-super-2.m98
-rw-r--r--test/SemaObjC/catch-stmt.m13
-rw-r--r--test/SemaObjC/category-1.m56
-rw-r--r--test/SemaObjC/category-method-lookup-2.m22
-rw-r--r--test/SemaObjC/category-method-lookup.m31
-rw-r--r--test/SemaObjC/check-dup-decl-methods-1.m38
-rw-r--r--test/SemaObjC/check-dup-objc-decls-1.m39
-rw-r--r--test/SemaObjC/class-bitfield.m37
-rw-r--r--test/SemaObjC/class-conforming-protocol-1.m21
-rw-r--r--test/SemaObjC/class-conforming-protocol-2.m22
-rw-r--r--test/SemaObjC/class-def-test-1.m33
-rw-r--r--test/SemaObjC/class-extension-dup-methods.m15
-rw-r--r--test/SemaObjC/class-impl-1.m40
-rw-r--r--test/SemaObjC/class-method-lookup.m46
-rw-r--r--test/SemaObjC/class-method-self.m26
-rw-r--r--test/SemaObjC/class-property-access.m12
-rw-r--r--test/SemaObjC/class-proto-1.m36
-rw-r--r--test/SemaObjC/cocoa-pth.m7
-rw-r--r--test/SemaObjC/cocoa.m5
-rw-r--r--test/SemaObjC/compare-qualified-id.m33
-rw-r--r--test/SemaObjC/compatible-protocol-qualified-types.m75
-rw-r--r--test/SemaObjC/comptypes-1.m91
-rw-r--r--test/SemaObjC/comptypes-2.m37
-rw-r--r--test/SemaObjC/comptypes-3.m64
-rw-r--r--test/SemaObjC/comptypes-4.m25
-rw-r--r--test/SemaObjC/comptypes-5.m44
-rw-r--r--test/SemaObjC/comptypes-6.m16
-rw-r--r--test/SemaObjC/comptypes-7.m70
-rw-r--r--test/SemaObjC/comptypes-8.m12
-rw-r--r--test/SemaObjC/comptypes-9.m86
-rw-r--r--test/SemaObjC/comptypes-a.m32
-rw-r--r--test/SemaObjC/comptypes-legal.m37
-rw-r--r--test/SemaObjC/conditional-expr-2.m29
-rw-r--r--test/SemaObjC/conditional-expr-3.m67
-rw-r--r--test/SemaObjC/conditional-expr-4.m78
-rw-r--r--test/SemaObjC/conditional-expr.m44
-rw-r--r--test/SemaObjC/conflicting-ivar-test-1.m86
-rw-r--r--test/SemaObjC/continuation-class-err.m15
-rw-r--r--test/SemaObjC/duplicate-ivar-check.m22
-rw-r--r--test/SemaObjC/enhanced-proto-2.m21
-rw-r--r--test/SemaObjC/error-property-gc-attr.m27
-rw-r--r--test/SemaObjC/exprs.m21
-rw-r--r--test/SemaObjC/foreach.m18
-rw-r--r--test/SemaObjC/format-arg-attribute.m28
-rw-r--r--test/SemaObjC/format-strings-objc.m43
-rw-r--r--test/SemaObjC/forward-class-1.m47
-rw-r--r--test/SemaObjC/forward-class-receiver.m13
-rw-r--r--test/SemaObjC/gcc-cast-ext.m24
-rw-r--r--test/SemaObjC/id.m20
-rw-r--r--test/SemaObjC/id_builtin.m10
-rw-r--r--test/SemaObjC/ignore-weakimport-method.m7
-rw-r--r--test/SemaObjC/incompatible-protocol-qualified-types.m40
-rw-r--r--test/SemaObjC/inst-method-lookup-in-root.m27
-rw-r--r--test/SemaObjC/interface-1.m38
-rw-r--r--test/SemaObjC/interface-layout-2.m16
-rw-r--r--test/SemaObjC/interface-layout.m27
-rw-r--r--test/SemaObjC/interface-scope-2.m126
-rw-r--r--test/SemaObjC/interface-scope.m12
-rw-r--r--test/SemaObjC/interface-tu-variable.m26
-rw-r--r--test/SemaObjC/invalid-code.m7
-rw-r--r--test/SemaObjC/invalid-objc-decls-1.m34
-rw-r--r--test/SemaObjC/invalid-receiver.m9
-rw-r--r--test/SemaObjC/invalid-typename.m12
-rw-r--r--test/SemaObjC/ivar-access-package.m45
-rw-r--r--test/SemaObjC/ivar-access-tests.m122
-rw-r--r--test/SemaObjC/ivar-lookup.m18
-rw-r--r--test/SemaObjC/ivar-ref-misuse.m41
-rw-r--r--test/SemaObjC/ivar-sem-check-1.m19
-rw-r--r--test/SemaObjC/ivar-sem-check-2.m23
-rw-r--r--test/SemaObjC/legacy-implementation-1.m11
-rw-r--r--test/SemaObjC/message.m100
-rw-r--r--test/SemaObjC/method-arg-decay.m95
-rw-r--r--test/SemaObjC/method-attributes.m32
-rw-r--r--test/SemaObjC/method-bad-param.m30
-rw-r--r--test/SemaObjC/method-conflict.m53
-rw-r--r--test/SemaObjC/method-def-1.m40
-rw-r--r--test/SemaObjC/method-def-2.m19
-rw-r--r--test/SemaObjC/method-encoding-2.m12
-rw-r--r--test/SemaObjC/method-lookup-2.m62
-rw-r--r--test/SemaObjC/method-lookup-3.m52
-rw-r--r--test/SemaObjC/method-lookup-4.m62
-rw-r--r--test/SemaObjC/method-lookup.m34
-rw-r--r--test/SemaObjC/method-no-context.m4
-rw-r--r--test/SemaObjC/method-not-defined.m13
-rw-r--r--test/SemaObjC/method-sentinel-attr.m37
-rw-r--r--test/SemaObjC/method-typecheck-1.m37
-rw-r--r--test/SemaObjC/method-typecheck-2.m25
-rw-r--r--test/SemaObjC/method-undef-category-warn-1.m32
-rw-r--r--test/SemaObjC/method-undef-extension-warn-1.m25
-rw-r--r--test/SemaObjC/method-undefined-warn-1.m42
-rw-r--r--test/SemaObjC/missing-method-context.m4
-rw-r--r--test/SemaObjC/newproperty-class-method-1.m60
-rw-r--r--test/SemaObjC/no-gc-weak-test.m28
-rw-r--r--test/SemaObjC/no-warn-synth-protocol-meth.m17
-rw-r--r--test/SemaObjC/no-warn-unimpl-method.m42
-rw-r--r--test/SemaObjC/nsobject-attribute-1.m48
-rw-r--r--test/SemaObjC/nsobject-attribute.m36
-rw-r--r--test/SemaObjC/objc-string-constant.m39
-rw-r--r--test/SemaObjC/objc2-merge-gc-attribue-decl.m12
-rw-r--r--test/SemaObjC/objc2-warn-weak-decl.m10
-rw-r--r--test/SemaObjC/property-10.m22
-rw-r--r--test/SemaObjC/property-11.m35
-rw-r--r--test/SemaObjC/property-12.m32
-rw-r--r--test/SemaObjC/property-13.m77
-rw-r--r--test/SemaObjC/property-2.m63
-rw-r--r--test/SemaObjC/property-3.m14
-rw-r--r--test/SemaObjC/property-4.m29
-rw-r--r--test/SemaObjC/property-5.m34
-rw-r--r--test/SemaObjC/property-6.m69
-rw-r--r--test/SemaObjC/property-7.m34
-rw-r--r--test/SemaObjC/property-8.m74
-rw-r--r--test/SemaObjC/property-9-impl-method.m94
-rw-r--r--test/SemaObjC/property-9.m86
-rw-r--r--test/SemaObjC/property-category-1.m52
-rw-r--r--test/SemaObjC/property-category-2.m19
-rw-r--r--test/SemaObjC/property-category-3.m31
-rw-r--r--test/SemaObjC/property-error-readonly-assign.m21
-rw-r--r--test/SemaObjC/property-impl-misuse.m16
-rw-r--r--test/SemaObjC/property-inherited.m44
-rw-r--r--test/SemaObjC/property-ivar-mismatch.m14
-rw-r--r--test/SemaObjC/property-method-lookup-impl.m26
-rw-r--r--test/SemaObjC/property-missing.m22
-rw-r--r--test/SemaObjC/property-nonfragile-abi.m21
-rw-r--r--test/SemaObjC/property-noprotocol-warning.m36
-rw-r--r--test/SemaObjC/property-redundant-decl-accessor.m18
-rw-r--r--test/SemaObjC/property-typecheck-1.m101
-rw-r--r--test/SemaObjC/property-user-setter.m90
-rw-r--r--test/SemaObjC/property-weak.m5
-rw-r--r--test/SemaObjC/property.m55
-rw-r--r--test/SemaObjC/props-on-prots.m65
-rw-r--r--test/SemaObjC/protocol-archane.m35
-rw-r--r--test/SemaObjC/protocol-attribute.m49
-rw-r--r--test/SemaObjC/protocol-expr-1.m15
-rw-r--r--test/SemaObjC/protocol-expr-neg-1.m19
-rw-r--r--test/SemaObjC/protocol-id-test-1.m16
-rw-r--r--test/SemaObjC/protocol-id-test-2.m12
-rw-r--r--test/SemaObjC/protocol-id-test-3.m94
-rw-r--r--test/SemaObjC/protocol-implementation-inherited.m56
-rw-r--r--test/SemaObjC/protocol-lookup-2.m33
-rw-r--r--test/SemaObjC/protocol-lookup.m50
-rw-r--r--test/SemaObjC/protocol-qualified-class-unsupported.m40
-rw-r--r--test/SemaObjC/protocol-typecheck.m25
-rw-r--r--test/SemaObjC/protocols.m63
-rw-r--r--test/SemaObjC/rdr-6211479-array-property.m9
-rw-r--r--test/SemaObjC/scope-check.m103
-rw-r--r--test/SemaObjC/selector-1.m22
-rw-r--r--test/SemaObjC/selector-error.m20
-rw-r--r--test/SemaObjC/selector-overload.m47
-rw-r--r--test/SemaObjC/sizeof-interface.m79
-rw-r--r--test/SemaObjC/static-ivar-ref-1.m17
-rw-r--r--test/SemaObjC/stmts.m14
-rw-r--r--test/SemaObjC/string.m15
-rw-r--r--test/SemaObjC/super-cat-prot.m48
-rw-r--r--test/SemaObjC/super-property-message-expr.m21
-rw-r--r--test/SemaObjC/super-property-notation.m30
-rw-r--r--test/SemaObjC/super.m40
-rw-r--r--test/SemaObjC/synchronized.m23
-rw-r--r--test/SemaObjC/synthesize-setter-contclass.m24
-rw-r--r--test/SemaObjC/synthesized-ivar.m13
-rw-r--r--test/SemaObjC/try-catch.m47
-rw-r--r--test/SemaObjC/typedef-class.m78
-rw-r--r--test/SemaObjC/ucn-objc-string.m13
-rw-r--r--test/SemaObjC/undef-class-messagin-error.m13
-rw-r--r--test/SemaObjC/undef-protocol-methods-1.m42
-rw-r--r--test/SemaObjC/undef-superclass-1.m26
-rw-r--r--test/SemaObjC/undefined-protocol-type-1.m9
-rw-r--r--test/SemaObjC/unused.m18
-rw-r--r--test/SemaObjC/va-method-1.m17
-rw-r--r--test/SemaObjC/warn-selector-selection.m14
-rw-r--r--test/SemaObjC/warn-weak-field.m24
-rw-r--r--test/SemaObjC/weak-attr-ivar.m73
-rw-r--r--test/SemaObjC/writable-property-in-superclass.m17
-rw-r--r--test/SemaObjCXX/blocks.mm46
-rw-r--r--test/SemaObjCXX/cocoa.mm4
-rw-r--r--test/SemaObjCXX/linkage-spec.mm4
-rw-r--r--test/SemaObjCXX/objc-decls-inside-namespace.mm27
-rw-r--r--test/SemaObjCXX/overload.mm94
-rw-r--r--test/SemaObjCXX/protocol-lookup.mm50
-rw-r--r--test/SemaObjCXX/reserved-keyword-selectors.mm35
-rw-r--r--test/SemaObjCXX/vararg-non-pod.mm32
-rw-r--r--test/SemaObjCXX/void_to_obj.mm11
-rw-r--r--test/SemaTemplate/class-template-decl.cpp49
-rw-r--r--test/SemaTemplate/class-template-id-2.cpp24
-rw-r--r--test/SemaTemplate/class-template-id.cpp38
-rw-r--r--test/SemaTemplate/class-template-spec.cpp80
-rw-r--r--test/SemaTemplate/current-instantiation.cpp71
-rw-r--r--test/SemaTemplate/default-arguments.cpp12
-rw-r--r--test/SemaTemplate/dependent-type-identity.cpp72
-rw-r--r--test/SemaTemplate/enum-argument.cpp7
-rw-r--r--test/SemaTemplate/example-dynarray.cpp150
-rw-r--r--test/SemaTemplate/fibonacci.cpp66
-rw-r--r--test/SemaTemplate/fun-template-def.cpp43
-rw-r--r--test/SemaTemplate/injected-class-name.cpp40
-rw-r--r--test/SemaTemplate/instantiate-array.cpp28
-rw-r--r--test/SemaTemplate/instantiate-c99.cpp81
-rw-r--r--test/SemaTemplate/instantiate-call.cpp50
-rw-r--r--test/SemaTemplate/instantiate-cast.cpp109
-rw-r--r--test/SemaTemplate/instantiate-clang.cpp35
-rw-r--r--test/SemaTemplate/instantiate-complete.cpp47
-rw-r--r--test/SemaTemplate/instantiate-declref.cpp71
-rw-r--r--test/SemaTemplate/instantiate-enum.cpp11
-rw-r--r--test/SemaTemplate/instantiate-expr-1.cpp71
-rw-r--r--test/SemaTemplate/instantiate-expr-2.cpp132
-rw-r--r--test/SemaTemplate/instantiate-expr-3.cpp115
-rw-r--r--test/SemaTemplate/instantiate-expr-4.cpp289
-rw-r--r--test/SemaTemplate/instantiate-expr-basic.cpp17
-rw-r--r--test/SemaTemplate/instantiate-field.cpp28
-rw-r--r--test/SemaTemplate/instantiate-function-1.cpp211
-rw-r--r--test/SemaTemplate/instantiate-function-1.mm14
-rw-r--r--test/SemaTemplate/instantiate-function-2.cpp12
-rw-r--r--test/SemaTemplate/instantiate-member-class.cpp38
-rw-r--r--test/SemaTemplate/instantiate-method.cpp74
-rw-r--r--test/SemaTemplate/instantiate-static-var.cpp18
-rw-r--r--test/SemaTemplate/instantiate-subscript.cpp26
-rw-r--r--test/SemaTemplate/instantiate-template-template-parm.cpp21
-rw-r--r--test/SemaTemplate/instantiate-try-catch.cpp14
-rw-r--r--test/SemaTemplate/instantiate-type.cpp17
-rw-r--r--test/SemaTemplate/instantiate-typedef.cpp16
-rw-r--r--test/SemaTemplate/instantiation-backtrace.cpp32
-rw-r--r--test/SemaTemplate/instantiation-default-1.cpp102
-rw-r--r--test/SemaTemplate/instantiation-default-2.cpp18
-rw-r--r--test/SemaTemplate/instantiation-default-3.cpp21
-rw-r--r--test/SemaTemplate/instantiation-depth.cpp9
-rw-r--r--test/SemaTemplate/metafun-apply.cpp43
-rw-r--r--test/SemaTemplate/nested-name-spec-template.cpp61
-rw-r--r--test/SemaTemplate/nested-template.cpp16
-rw-r--r--test/SemaTemplate/qualified-names-diag.cpp16
-rw-r--r--test/SemaTemplate/right-angle-brackets-0x.cpp22
-rw-r--r--test/SemaTemplate/right-angle-brackets-98.cpp12
-rw-r--r--test/SemaTemplate/temp.cpp5
-rw-r--r--test/SemaTemplate/temp_arg.cpp12
-rw-r--r--test/SemaTemplate/temp_arg_nontype.cpp124
-rw-r--r--test/SemaTemplate/temp_arg_template.cpp38
-rw-r--r--test/SemaTemplate/temp_arg_type.cpp24
-rw-r--r--test/SemaTemplate/temp_class_spec.cpp20
-rw-r--r--test/SemaTemplate/temp_explicit.cpp111
-rw-r--r--test/SemaTemplate/temp_explicit_cxx0x.cpp24
-rw-r--r--test/SemaTemplate/temp_param.cpp90
-rw-r--r--test/SemaTemplate/typename-specifier-2.cpp30
-rw-r--r--test/SemaTemplate/typename-specifier.cpp74
-rwxr-xr-xtest/TestRunner.sh134
-rw-r--r--tools/CMakeLists.txt2
-rw-r--r--tools/Makefile13
-rw-r--r--tools/clang-cc/CMakeLists.txt26
-rw-r--r--tools/clang-cc/Makefile32
-rw-r--r--tools/clang-cc/clang-cc.cpp2293
-rw-r--r--tools/driver/CMakeLists.txt12
-rw-r--r--tools/driver/Makefile23
-rw-r--r--tools/driver/driver.cpp228
-rw-r--r--tools/scan-view/Reporter.py248
-rw-r--r--tools/scan-view/Resources/FileRadar.scptbin0 -> 18418 bytes
-rw-r--r--tools/scan-view/Resources/GetRadarVersion.scpt0
-rw-r--r--tools/scan-view/Resources/bugcatcher.icobin0 -> 318 bytes
-rw-r--r--tools/scan-view/ScanView.py770
-rwxr-xr-xtools/scan-view/scan-view131
-rw-r--r--tools/scan-view/startfile.py203
-rwxr-xr-xutils/ABITest/ABITestGen.py638
-rw-r--r--utils/ABITest/Enumeration.py276
-rw-r--r--utils/ABITest/Makefile.test.common170
-rw-r--r--utils/ABITest/TypeGen.py381
-rwxr-xr-xutils/ABITest/build-and-summarize-all.sh15
-rwxr-xr-xutils/ABITest/build-and-summarize.sh14
-rwxr-xr-xutils/ABITest/build.sh12
-rw-r--r--utils/ABITest/layout/Makefile68
-rw-r--r--utils/ABITest/return-types-32/Makefile7
-rw-r--r--utils/ABITest/return-types-64/Makefile7
-rw-r--r--utils/ABITest/single-args-32/Makefile7
-rw-r--r--utils/ABITest/single-args-64/Makefile13
-rwxr-xr-xutils/ABITest/summarize.sh15
-rwxr-xr-xutils/CaptureCmd73
-rwxr-xr-xutils/CmpDriver194
-rwxr-xr-xutils/FindSpecRefs910
-rwxr-xr-xutils/SummarizeErrors117
-rw-r--r--utils/builtin-defines.c85
-rwxr-xr-xutils/ccc-analyzer617
-rwxr-xr-xutils/pch-test.pl61
-rwxr-xr-xutils/scan-build1278
-rw-r--r--utils/scanview.css62
-rw-r--r--utils/sorttable.js493
-rw-r--r--utils/test/Makefile.multi21
-rwxr-xr-xutils/test/MultiTestRunner.py331
-rw-r--r--utils/test/ProgressBar.py227
-rwxr-xr-xutils/test/TestRunner.py210
-rwxr-xr-xutils/token-delta.py251
-rwxr-xr-xutils/ubiviz74
-rw-r--r--win32/clangAST/clangAST.vcproj347
-rw-r--r--win32/clangAnalysis/clangAnalysis.vcproj351
-rw-r--r--win32/clangBasic/clangBasic.vcproj236
-rw-r--r--win32/clangCodeGen/clangCodeGen.vcproj271
-rw-r--r--win32/clangDriver/clangDriver.vcproj270
-rw-r--r--win32/clangLex/clangLex.vcproj283
-rw-r--r--win32/clangLibDriver/clangLibDriver.vcproj205
-rw-r--r--win32/clangParse/clangParse.vcproj248
-rw-r--r--win32/clangRewrite/clangRewrite.vcproj191
-rw-r--r--win32/clangSema/clangSema.vcproj263
-rw-r--r--www/CheckerNotes.html9
-rw-r--r--www/OpenProjects.html112
-rw-r--r--www/StaticAnalysis.html156
-rw-r--r--www/StaticAnalysisUsage.html274
-rw-r--r--www/carbon-compile.pngbin0 -> 23702 bytes
-rw-r--r--www/clang_video-05-25-2007.html27
-rw-r--r--www/clang_video-07-25-2007.html30
-rw-r--r--www/comparison.html195
-rw-r--r--www/content.css25
-rw-r--r--www/cxx_status.html2320
-rw-r--r--www/demo/DemoInfo.html83
-rw-r--r--www/demo/cathead.pngbin0 -> 21602 bytes
-rw-r--r--www/demo/index.cgi461
-rw-r--r--www/demo/syntax.css4
-rw-r--r--www/demo/what is this directory.txt15
-rw-r--r--www/diagnostics.html279
-rw-r--r--www/distclang_status.html30
-rw-r--r--www/feature-compile1.pngbin0 -> 91247 bytes
-rw-r--r--www/feature-compile2.pngbin0 -> 140963 bytes
-rw-r--r--www/feature-memory1.pngbin0 -> 92680 bytes
-rw-r--r--www/features.html423
-rw-r--r--www/get_involved.html61
-rw-r--r--www/get_started.html228
-rw-r--r--www/hacking.html101
-rw-r--r--www/index.html117
-rw-r--r--www/latest_checker.html.incl1
-rw-r--r--www/menu.css39
-rw-r--r--www/menu.html.incl43
-rw-r--r--www/performance-2008-10-31.html134
-rw-r--r--www/performance.html112
-rw-r--r--www/timing-data/2008-10-31/176.gcc-01.txt135
-rw-r--r--www/timing-data/2008-10-31/176.gcc-02.txt135
-rw-r--r--www/timing-data/2008-10-31/176.gcc.pngbin0 -> 20395 bytes
-rw-r--r--www/timing-data/2008-10-31/sketch-01.txt187
-rw-r--r--www/timing-data/2008-10-31/sketch-02.txt187
-rw-r--r--www/timing-data/2008-10-31/sketch.pngbin0 -> 23482 bytes
-rw-r--r--www/timing-data/2009-03-02/176.gcc.pdfbin0 -> 34547 bytes
-rw-r--r--www/timing-data/2009-03-02/176.gcc.pngbin0 -> 77003 bytes
-rw-r--r--www/timing-data/2009-03-02/176.gcc.txt1120
-rw-r--r--www/timing-data/2009-03-02/sketch.pdfbin0 -> 36086 bytes
-rw-r--r--www/timing-data/2009-03-02/sketch.pngbin0 -> 78278 bytes
-rw-r--r--www/timing-data/2009-03-02/sketch.txt2368
1829 files changed, 297910 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 000000000000..8ca44b844574
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,56 @@
+macro(add_clang_library name)
+ set(srcs ${ARGN})
+ if(MSVC_IDE OR XCODE)
+ file( GLOB_RECURSE headers *.h)
+ set(srcs ${srcs} ${headers})
+ string( REGEX MATCHALL "/[^/]+" split_path ${CMAKE_CURRENT_SOURCE_DIR})
+ list( GET split_path -1 dir)
+ file( GLOB_RECURSE headers ../../include/clang${dir}/*.h)
+ set(srcs ${srcs} ${headers})
+ endif(MSVC_IDE OR XCODE)
+ add_library( ${name} ${srcs} )
+ if( LLVM_COMMON_DEPENDS )
+ add_dependencies( ${name} ${LLVM_COMMON_DEPENDS} )
+ endif( LLVM_COMMON_DEPENDS )
+ add_dependencies(${name} ClangDiagnosticCommon)
+ if(MSVC)
+ get_target_property(cflag ${name} COMPILE_FLAGS)
+ if(NOT cflag)
+ set(cflag "")
+ endif(NOT cflag)
+ set(cflag "${cflag} /Za")
+ set_target_properties(${name} PROPERTIES COMPILE_FLAGS ${cflag})
+ endif(MSVC)
+ install(TARGETS ${name}
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib)
+endmacro(add_clang_library)
+
+macro(add_clang_executable name)
+ set(srcs ${ARGN})
+ if(MSVC_IDE)
+ file( GLOB_RECURSE headers *.h)
+ set(srcs ${srcs} ${headers})
+ endif(MSVC_IDE)
+ add_llvm_executable( ${name} ${srcs} )
+ install(TARGETS ${name}
+ RUNTIME DESTINATION bin)
+endmacro(add_clang_executable)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/include
+ ${CMAKE_CURRENT_BINARY_DIR}/include
+ )
+
+install(DIRECTORY include
+ DESTINATION .
+ PATTERN ".svn" EXCLUDE
+ )
+
+add_definitions( -D_GNU_SOURCE )
+
+add_subdirectory(include)
+add_subdirectory(lib)
+add_subdirectory(tools)
+
+# TODO: docs.
diff --git a/INPUTS/Cocoa_h.m b/INPUTS/Cocoa_h.m
new file mode 100644
index 000000000000..e6ba59924d6d
--- /dev/null
+++ b/INPUTS/Cocoa_h.m
@@ -0,0 +1,2 @@
+
+#import <Cocoa/Cocoa.h>
diff --git a/INPUTS/c99-intconst-1.c b/INPUTS/c99-intconst-1.c
new file mode 100644
index 000000000000..629b0bcac205
--- /dev/null
+++ b/INPUTS/c99-intconst-1.c
@@ -0,0 +1,639 @@
+/* Test for integer constant types. */
+
+/* Origin: Joseph Myers <jsm28@cam.ac.uk>. */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+#include <limits.h>
+
+/* Assertion that constant C is of type T. */
+#define ASSERT_CONST_TYPE(C, T) \
+ do { \
+ typedef T type; \
+ typedef type **typepp; \
+ typedef __typeof__((C)) ctype; \
+ typedef ctype **ctypepp; \
+ typepp x = 0; \
+ ctypepp y = 0; \
+ x = y; \
+ y = x; \
+ } while (0)
+
+/* (T *) if E is zero, (void *) otherwise. */
+#define type_if_not(T, E) __typeof__(0 ? (T *)0 : (void *)(E))
+
+/* (T *) if E is nonzero, (void *) otherwise. */
+#define type_if(T, E) type_if_not(T, !(E))
+
+/* Combine pointer types, all but one (void *). */
+#define type_comb2(T1, T2) __typeof__(0 ? (T1)0 : (T2)0)
+#define type_comb3(T1, T2, T3) type_comb2(T1, type_comb2(T2, T3))
+#define type_comb4(T1, T2, T3, T4) \
+ type_comb2(T1, type_comb2(T2, type_comb2(T3, T4)))
+#define type_comb6(T1, T2, T3, T4, T5, T6) \
+ type_comb2(T1, \
+ type_comb2(T2, \
+ type_comb2(T3, \
+ type_comb2(T4, \
+ type_comb2(T5, T6)))))
+
+/* (T1 *) if E1, otherwise (T2 *) if E2. */
+#define first_of2p(T1, E1, T2, E2) type_comb2(type_if(T1, (E1)), \
+ type_if(T2, (!(E1) && (E2))))
+/* (T1 *) if E1, otherwise (T2 *) if E2, otherwise (T3 *) if E3. */
+#define first_of3p(T1, E1, T2, E2, T3, E3) \
+ type_comb3(type_if(T1, (E1)), \
+ type_if(T2, (!(E1) && (E2))), \
+ type_if(T3, (!(E1) && !(E2) && (E3))))
+/* (T1 *) if E1, otherwise (T2 *) if E2, otherwise (T3 *) if E3, otherwise
+ (T4 *) if E4. */
+#define first_of4p(T1, E1, T2, E2, T3, E3, T4, E4) \
+ type_comb4(type_if(T1, (E1)), \
+ type_if(T2, (!(E1) && (E2))), \
+ type_if(T3, (!(E1) && !(E2) && (E3))), \
+ type_if(T4, (!(E1) && !(E2) && !(E3) && (E4))))
+/* (T1 *) if E1, otherwise (T2 *) if E2, otherwise (T3 *) if E3, otherwise
+ (T4 *) if E4, otherwise (T5 *) if E5, otherwise (T6 *) if E6. */
+#define first_of6p(T1, E1, T2, E2, T3, E3, T4, E4, T5, E5, T6, E6) \
+ type_comb6(type_if(T1, (E1)), \
+ type_if(T2, (!(E1) && (E2))), \
+ type_if(T3, (!(E1) && !(E2) && (E3))), \
+ type_if(T4, (!(E1) && !(E2) && !(E3) && (E4))), \
+ type_if(T5, (!(E1) && !(E2) && !(E3) && !(E4) && (E5))), \
+ type_if(T6, (!(E1) && !(E2) && !(E3) \
+ && !(E4) && !(E5) && (E6))))
+
+/* Likewise, but return the original type rather than a pointer type. */
+#define first_of2(T1, E1, T2, E2) \
+ __typeof__(*((first_of2p(T1, (E1), T2, (E2)))0))
+#define first_of3(T1, E1, T2, E2, T3, E3) \
+ __typeof__(*((first_of3p(T1, (E1), T2, (E2), T3, (E3)))0))
+#define first_of4(T1, E1, T2, E2, T3, E3, T4, E4) \
+ __typeof__(*((first_of4p(T1, (E1), T2, (E2), T3, (E3), T4, (E4)))0))
+#define first_of6(T1, E1, T2, E2, T3, E3, T4, E4, T5, E5, T6, E6) \
+ __typeof__(*((first_of6p(T1, (E1), T2, (E2), T3, (E3), \
+ T4, (E4), T5, (E5), T6, (E6)))0))
+
+/* Types of constants according to the C99 rules. */
+#define C99_UNSUF_DEC_TYPE(C) \
+ first_of3(int, (C) <= INT_MAX, \
+ long int, (C) <= LONG_MAX, \
+ long long int, (C) <= LLONG_MAX)
+#define C99_UNSUF_OCTHEX_TYPE(C) \
+ first_of6(int, (C) <= INT_MAX, \
+ unsigned int, (C) <= UINT_MAX, \
+ long int, (C) <= LONG_MAX, \
+ unsigned long int, (C) <= ULONG_MAX, \
+ long long int, (C) <= LLONG_MAX, \
+ unsigned long long int, (C) <= ULLONG_MAX)
+#define C99_SUFu_TYPE(C) \
+ first_of3(unsigned int, (C) <= UINT_MAX, \
+ unsigned long int, (C) <= ULONG_MAX, \
+ unsigned long long int, (C) <= ULLONG_MAX)
+#define C99_SUFl_DEC_TYPE(C) \
+ first_of2(long int, (C) <= LONG_MAX, \
+ long long int, (C) <= LLONG_MAX)
+#define C99_SUFl_OCTHEX_TYPE(C) \
+ first_of4(long int, (C) <= LONG_MAX, \
+ unsigned long int, (C) <= ULONG_MAX, \
+ long long int, (C) <= LLONG_MAX, \
+ unsigned long long int, (C) <= ULLONG_MAX)
+#define C99_SUFul_TYPE(C) \
+ first_of2(unsigned long int, (C) <= ULONG_MAX, \
+ unsigned long long int, (C) <= ULLONG_MAX)
+#define C99_SUFll_OCTHEX_TYPE(C) \
+ first_of2(long long int, (C) <= LLONG_MAX, \
+ unsigned long long int, (C) <= ULLONG_MAX)
+
+/* Checks that constants have correct type. */
+#define CHECK_UNSUF_DEC_TYPE(C) ASSERT_CONST_TYPE((C), C99_UNSUF_DEC_TYPE((C)))
+#define CHECK_UNSUF_OCTHEX_TYPE(C) \
+ ASSERT_CONST_TYPE((C), C99_UNSUF_OCTHEX_TYPE((C)))
+#define CHECK_SUFu_TYPE(C) ASSERT_CONST_TYPE((C), C99_SUFu_TYPE((C)))
+#define CHECK_SUFl_DEC_TYPE(C) ASSERT_CONST_TYPE((C), C99_SUFl_DEC_TYPE((C)))
+#define CHECK_SUFl_OCTHEX_TYPE(C) \
+ ASSERT_CONST_TYPE((C), C99_SUFl_OCTHEX_TYPE((C)))
+#define CHECK_SUFul_TYPE(C) ASSERT_CONST_TYPE((C), C99_SUFul_TYPE((C)))
+#define CHECK_SUFll_DEC_TYPE(C) ASSERT_CONST_TYPE((C), long long int)
+#define CHECK_SUFll_OCTHEX_TYPE(C) \
+ ASSERT_CONST_TYPE((C), C99_SUFll_OCTHEX_TYPE((C)))
+#define CHECK_SUFull_TYPE(C) ASSERT_CONST_TYPE((C), unsigned long long int)
+
+/* Check a decimal value, with all suffixes. */
+#define CHECK_DEC_CONST(C) \
+ CHECK_UNSUF_DEC_TYPE(C); \
+ CHECK_SUFu_TYPE(C##u); \
+ CHECK_SUFu_TYPE(C##U); \
+ CHECK_SUFl_DEC_TYPE(C##l); \
+ CHECK_SUFl_DEC_TYPE(C##L); \
+ CHECK_SUFul_TYPE(C##ul); \
+ CHECK_SUFul_TYPE(C##uL); \
+ CHECK_SUFul_TYPE(C##Ul); \
+ CHECK_SUFul_TYPE(C##UL); \
+ CHECK_SUFll_DEC_TYPE(C##ll); \
+ CHECK_SUFll_DEC_TYPE(C##LL); \
+ CHECK_SUFull_TYPE(C##ull); \
+ CHECK_SUFull_TYPE(C##uLL); \
+ CHECK_SUFull_TYPE(C##Ull); \
+ CHECK_SUFull_TYPE(C##ULL);
+
+/* Check an octal or hexadecimal value, with all suffixes. */
+#define CHECK_OCTHEX_CONST(C) \
+ CHECK_UNSUF_OCTHEX_TYPE(C); \
+ CHECK_SUFu_TYPE(C##u); \
+ CHECK_SUFu_TYPE(C##U); \
+ CHECK_SUFl_OCTHEX_TYPE(C##l); \
+ CHECK_SUFl_OCTHEX_TYPE(C##L); \
+ CHECK_SUFul_TYPE(C##ul); \
+ CHECK_SUFul_TYPE(C##uL); \
+ CHECK_SUFul_TYPE(C##Ul); \
+ CHECK_SUFul_TYPE(C##UL); \
+ CHECK_SUFll_OCTHEX_TYPE(C##ll); \
+ CHECK_SUFll_OCTHEX_TYPE(C##LL); \
+ CHECK_SUFull_TYPE(C##ull); \
+ CHECK_SUFull_TYPE(C##uLL); \
+ CHECK_SUFull_TYPE(C##Ull); \
+ CHECK_SUFull_TYPE(C##ULL);
+
+#define CHECK_OCT_CONST(C) CHECK_OCTHEX_CONST(C)
+#define CHECK_HEX_CONST(C) \
+ CHECK_OCTHEX_CONST(0x##C); \
+ CHECK_OCTHEX_CONST(0X##C);
+
+/* True iff "long long" is at least B bits. This presumes that (B-2)/3 is at
+ most 63. */
+#define LLONG_AT_LEAST(B) \
+ (LLONG_MAX >> ((B)-2)/3 >> ((B)-2)/3 \
+ >> ((B)-2 - ((B)-2)/3 - ((B)-2)/3))
+
+#define LLONG_HAS_BITS(B) (LLONG_AT_LEAST((B)) && !LLONG_AT_LEAST((B) + 1))
+
+void
+foo (void)
+{
+ /* Decimal. */
+ /* Check all 2^n and 2^n - 1 up to 2^71 - 1. */
+ CHECK_DEC_CONST(1);
+ CHECK_DEC_CONST(2);
+ CHECK_DEC_CONST(3);
+ CHECK_DEC_CONST(4);
+ CHECK_DEC_CONST(7);
+ CHECK_DEC_CONST(8);
+ CHECK_DEC_CONST(15);
+ CHECK_DEC_CONST(16);
+ CHECK_DEC_CONST(31);
+ CHECK_DEC_CONST(32);
+ CHECK_DEC_CONST(63);
+ CHECK_DEC_CONST(64);
+ CHECK_DEC_CONST(127);
+ CHECK_DEC_CONST(128);
+ CHECK_DEC_CONST(255);
+ CHECK_DEC_CONST(256);
+ CHECK_DEC_CONST(511);
+ CHECK_DEC_CONST(512);
+ CHECK_DEC_CONST(1023);
+ CHECK_DEC_CONST(1024);
+ CHECK_DEC_CONST(2047);
+ CHECK_DEC_CONST(2048);
+ CHECK_DEC_CONST(4095);
+ CHECK_DEC_CONST(4096);
+ CHECK_DEC_CONST(8191);
+ CHECK_DEC_CONST(8192);
+ CHECK_DEC_CONST(16383);
+ CHECK_DEC_CONST(16384);
+ CHECK_DEC_CONST(32767);
+ CHECK_DEC_CONST(32768);
+ CHECK_DEC_CONST(65535);
+ CHECK_DEC_CONST(65536);
+ CHECK_DEC_CONST(131071);
+ CHECK_DEC_CONST(131072);
+ CHECK_DEC_CONST(262143);
+ CHECK_DEC_CONST(262144);
+ CHECK_DEC_CONST(524287);
+ CHECK_DEC_CONST(524288);
+ CHECK_DEC_CONST(1048575);
+ CHECK_DEC_CONST(1048576);
+ CHECK_DEC_CONST(2097151);
+ CHECK_DEC_CONST(2097152);
+ CHECK_DEC_CONST(4194303);
+ CHECK_DEC_CONST(4194304);
+ CHECK_DEC_CONST(8388607);
+ CHECK_DEC_CONST(8388608);
+ CHECK_DEC_CONST(16777215);
+ CHECK_DEC_CONST(16777216);
+ CHECK_DEC_CONST(33554431);
+ CHECK_DEC_CONST(33554432);
+ CHECK_DEC_CONST(67108863);
+ CHECK_DEC_CONST(67108864);
+ CHECK_DEC_CONST(134217727);
+ CHECK_DEC_CONST(134217728);
+ CHECK_DEC_CONST(268435455);
+ CHECK_DEC_CONST(268435456);
+ CHECK_DEC_CONST(536870911);
+ CHECK_DEC_CONST(536870912);
+ CHECK_DEC_CONST(1073741823);
+ CHECK_DEC_CONST(1073741824);
+ CHECK_DEC_CONST(2147483647);
+ CHECK_DEC_CONST(2147483648);
+ CHECK_DEC_CONST(4294967295);
+ CHECK_DEC_CONST(4294967296);
+ CHECK_DEC_CONST(8589934591);
+ CHECK_DEC_CONST(8589934592);
+ CHECK_DEC_CONST(17179869183);
+ CHECK_DEC_CONST(17179869184);
+ CHECK_DEC_CONST(34359738367);
+ CHECK_DEC_CONST(34359738368);
+ CHECK_DEC_CONST(68719476735);
+ CHECK_DEC_CONST(68719476736);
+ CHECK_DEC_CONST(137438953471);
+ CHECK_DEC_CONST(137438953472);
+ CHECK_DEC_CONST(274877906943);
+ CHECK_DEC_CONST(274877906944);
+ CHECK_DEC_CONST(549755813887);
+ CHECK_DEC_CONST(549755813888);
+ CHECK_DEC_CONST(1099511627775);
+ CHECK_DEC_CONST(1099511627776);
+ CHECK_DEC_CONST(2199023255551);
+ CHECK_DEC_CONST(2199023255552);
+ CHECK_DEC_CONST(4398046511103);
+ CHECK_DEC_CONST(4398046511104);
+ CHECK_DEC_CONST(8796093022207);
+ CHECK_DEC_CONST(8796093022208);
+ CHECK_DEC_CONST(17592186044415);
+ CHECK_DEC_CONST(17592186044416);
+ CHECK_DEC_CONST(35184372088831);
+ CHECK_DEC_CONST(35184372088832);
+ CHECK_DEC_CONST(70368744177663);
+ CHECK_DEC_CONST(70368744177664);
+ CHECK_DEC_CONST(140737488355327);
+ CHECK_DEC_CONST(140737488355328);
+ CHECK_DEC_CONST(281474976710655);
+ CHECK_DEC_CONST(281474976710656);
+ CHECK_DEC_CONST(562949953421311);
+ CHECK_DEC_CONST(562949953421312);
+ CHECK_DEC_CONST(1125899906842623);
+ CHECK_DEC_CONST(1125899906842624);
+ CHECK_DEC_CONST(2251799813685247);
+ CHECK_DEC_CONST(2251799813685248);
+ CHECK_DEC_CONST(4503599627370495);
+ CHECK_DEC_CONST(4503599627370496);
+ CHECK_DEC_CONST(9007199254740991);
+ CHECK_DEC_CONST(9007199254740992);
+ CHECK_DEC_CONST(18014398509481983);
+ CHECK_DEC_CONST(18014398509481984);
+ CHECK_DEC_CONST(36028797018963967);
+ CHECK_DEC_CONST(36028797018963968);
+ CHECK_DEC_CONST(72057594037927935);
+ CHECK_DEC_CONST(72057594037927936);
+ CHECK_DEC_CONST(144115188075855871);
+ CHECK_DEC_CONST(144115188075855872);
+ CHECK_DEC_CONST(288230376151711743);
+ CHECK_DEC_CONST(288230376151711744);
+ CHECK_DEC_CONST(576460752303423487);
+ CHECK_DEC_CONST(576460752303423488);
+ CHECK_DEC_CONST(1152921504606846975);
+ CHECK_DEC_CONST(1152921504606846976);
+ CHECK_DEC_CONST(2305843009213693951);
+ CHECK_DEC_CONST(2305843009213693952);
+ CHECK_DEC_CONST(4611686018427387903);
+ CHECK_DEC_CONST(4611686018427387904);
+ CHECK_DEC_CONST(9223372036854775807);
+#if LLONG_AT_LEAST(65)
+ CHECK_DEC_CONST(9223372036854775808);
+ CHECK_DEC_CONST(18446744073709551615);
+#endif
+#if LLONG_AT_LEAST(66)
+ CHECK_DEC_CONST(18446744073709551616);
+ CHECK_DEC_CONST(36893488147419103231);
+#endif
+#if LLONG_AT_LEAST(67)
+ CHECK_DEC_CONST(36893488147419103232);
+ CHECK_DEC_CONST(73786976294838206463);
+#endif
+#if LLONG_AT_LEAST(68)
+ CHECK_DEC_CONST(73786976294838206464);
+ CHECK_DEC_CONST(147573952589676412927);
+#endif
+#if LLONG_AT_LEAST(69)
+ CHECK_DEC_CONST(147573952589676412928);
+ CHECK_DEC_CONST(295147905179352825855);
+#endif
+#if LLONG_AT_LEAST(70)
+ CHECK_DEC_CONST(295147905179352825856);
+ CHECK_DEC_CONST(590295810358705651711);
+#endif
+#if LLONG_AT_LEAST(71)
+ CHECK_DEC_CONST(590295810358705651712);
+ CHECK_DEC_CONST(1180591620717411303423);
+#endif
+#if LLONG_AT_LEAST(72)
+ CHECK_DEC_CONST(1180591620717411303424);
+ CHECK_DEC_CONST(2361183241434822606847);
+#endif
+ /* Octal and hexadecimal. */
+ /* Check all 2^n and 2^n - 1 up to 2^72 - 1. */
+ CHECK_OCT_CONST(0);
+ CHECK_HEX_CONST(0);
+ CHECK_OCT_CONST(01);
+ CHECK_HEX_CONST(1);
+ CHECK_OCT_CONST(02);
+ CHECK_HEX_CONST(2);
+ CHECK_OCT_CONST(03);
+ CHECK_HEX_CONST(3);
+ CHECK_OCT_CONST(04);
+ CHECK_HEX_CONST(4);
+ CHECK_OCT_CONST(07);
+ CHECK_HEX_CONST(7);
+ CHECK_OCT_CONST(010);
+ CHECK_HEX_CONST(8);
+ CHECK_OCT_CONST(017);
+ CHECK_HEX_CONST(f);
+ CHECK_OCT_CONST(020);
+ CHECK_HEX_CONST(10);
+ CHECK_OCT_CONST(037);
+ CHECK_HEX_CONST(1f);
+ CHECK_OCT_CONST(040);
+ CHECK_HEX_CONST(20);
+ CHECK_OCT_CONST(077);
+ CHECK_HEX_CONST(3f);
+ CHECK_OCT_CONST(0100);
+ CHECK_HEX_CONST(40);
+ CHECK_OCT_CONST(0177);
+ CHECK_HEX_CONST(7f);
+ CHECK_OCT_CONST(0200);
+ CHECK_HEX_CONST(80);
+ CHECK_OCT_CONST(0377);
+ CHECK_HEX_CONST(ff);
+ CHECK_OCT_CONST(0400);
+ CHECK_HEX_CONST(100);
+ CHECK_OCT_CONST(0777);
+ CHECK_HEX_CONST(1ff);
+ CHECK_OCT_CONST(01000);
+ CHECK_HEX_CONST(200);
+ CHECK_OCT_CONST(01777);
+ CHECK_HEX_CONST(3ff);
+ CHECK_OCT_CONST(02000);
+ CHECK_HEX_CONST(400);
+ CHECK_OCT_CONST(03777);
+ CHECK_HEX_CONST(7ff);
+ CHECK_OCT_CONST(04000);
+ CHECK_HEX_CONST(800);
+ CHECK_OCT_CONST(07777);
+ CHECK_HEX_CONST(fff);
+ CHECK_OCT_CONST(010000);
+ CHECK_HEX_CONST(1000);
+ CHECK_OCT_CONST(017777);
+ CHECK_HEX_CONST(1fff);
+ CHECK_OCT_CONST(020000);
+ CHECK_HEX_CONST(2000);
+ CHECK_OCT_CONST(037777);
+ CHECK_HEX_CONST(3fff);
+ CHECK_OCT_CONST(040000);
+ CHECK_HEX_CONST(4000);
+ CHECK_OCT_CONST(077777);
+ CHECK_HEX_CONST(7fff);
+ CHECK_OCT_CONST(0100000);
+ CHECK_HEX_CONST(8000);
+ CHECK_OCT_CONST(0177777);
+ CHECK_HEX_CONST(ffff);
+ CHECK_OCT_CONST(0200000);
+ CHECK_HEX_CONST(10000);
+ CHECK_OCT_CONST(0377777);
+ CHECK_HEX_CONST(1ffff);
+ CHECK_OCT_CONST(0400000);
+ CHECK_HEX_CONST(20000);
+ CHECK_OCT_CONST(0777777);
+ CHECK_HEX_CONST(3ffff);
+ CHECK_OCT_CONST(01000000);
+ CHECK_HEX_CONST(40000);
+ CHECK_OCT_CONST(01777777);
+ CHECK_HEX_CONST(7ffff);
+ CHECK_OCT_CONST(02000000);
+ CHECK_HEX_CONST(80000);
+ CHECK_OCT_CONST(03777777);
+ CHECK_HEX_CONST(fffff);
+ CHECK_OCT_CONST(04000000);
+ CHECK_HEX_CONST(100000);
+ CHECK_OCT_CONST(07777777);
+ CHECK_HEX_CONST(1fffff);
+ CHECK_OCT_CONST(010000000);
+ CHECK_HEX_CONST(200000);
+ CHECK_OCT_CONST(017777777);
+ CHECK_HEX_CONST(3fffff);
+ CHECK_OCT_CONST(020000000);
+ CHECK_HEX_CONST(400000);
+ CHECK_OCT_CONST(037777777);
+ CHECK_HEX_CONST(7fffff);
+ CHECK_OCT_CONST(040000000);
+ CHECK_HEX_CONST(800000);
+ CHECK_OCT_CONST(077777777);
+ CHECK_HEX_CONST(ffffff);
+ CHECK_OCT_CONST(0100000000);
+ CHECK_HEX_CONST(1000000);
+ CHECK_OCT_CONST(0177777777);
+ CHECK_HEX_CONST(1ffffff);
+ CHECK_OCT_CONST(0200000000);
+ CHECK_HEX_CONST(2000000);
+ CHECK_OCT_CONST(0377777777);
+ CHECK_HEX_CONST(3ffffff);
+ CHECK_OCT_CONST(0400000000);
+ CHECK_HEX_CONST(4000000);
+ CHECK_OCT_CONST(0777777777);
+ CHECK_HEX_CONST(7ffffff);
+ CHECK_OCT_CONST(01000000000);
+ CHECK_HEX_CONST(8000000);
+ CHECK_OCT_CONST(01777777777);
+ CHECK_HEX_CONST(fffffff);
+ CHECK_OCT_CONST(02000000000);
+ CHECK_HEX_CONST(10000000);
+ CHECK_OCT_CONST(03777777777);
+ CHECK_HEX_CONST(1fffffff);
+ CHECK_OCT_CONST(04000000000);
+ CHECK_HEX_CONST(20000000);
+ CHECK_OCT_CONST(07777777777);
+ CHECK_HEX_CONST(3fffffff);
+ CHECK_OCT_CONST(010000000000);
+ CHECK_HEX_CONST(40000000);
+ CHECK_OCT_CONST(017777777777);
+ CHECK_HEX_CONST(7fffffff);
+ CHECK_OCT_CONST(020000000000);
+ CHECK_HEX_CONST(80000000);
+ CHECK_OCT_CONST(037777777777);
+ CHECK_HEX_CONST(ffffffff);
+ CHECK_OCT_CONST(040000000000);
+ CHECK_HEX_CONST(100000000);
+ CHECK_OCT_CONST(077777777777);
+ CHECK_HEX_CONST(1ffffffff);
+ CHECK_OCT_CONST(0100000000000);
+ CHECK_HEX_CONST(200000000);
+ CHECK_OCT_CONST(0177777777777);
+ CHECK_HEX_CONST(3ffffffff);
+ CHECK_OCT_CONST(0200000000000);
+ CHECK_HEX_CONST(400000000);
+ CHECK_OCT_CONST(0377777777777);
+ CHECK_HEX_CONST(7ffffffff);
+ CHECK_OCT_CONST(0400000000000);
+ CHECK_HEX_CONST(800000000);
+ CHECK_OCT_CONST(0777777777777);
+ CHECK_HEX_CONST(fffffffff);
+ CHECK_OCT_CONST(01000000000000);
+ CHECK_HEX_CONST(1000000000);
+ CHECK_OCT_CONST(01777777777777);
+ CHECK_HEX_CONST(1fffffffff);
+ CHECK_OCT_CONST(02000000000000);
+ CHECK_HEX_CONST(2000000000);
+ CHECK_OCT_CONST(03777777777777);
+ CHECK_HEX_CONST(3fffffffff);
+ CHECK_OCT_CONST(04000000000000);
+ CHECK_HEX_CONST(4000000000);
+ CHECK_OCT_CONST(07777777777777);
+ CHECK_HEX_CONST(7fffffffff);
+ CHECK_OCT_CONST(010000000000000);
+ CHECK_HEX_CONST(8000000000);
+ CHECK_OCT_CONST(017777777777777);
+ CHECK_HEX_CONST(ffffffffff);
+ CHECK_OCT_CONST(020000000000000);
+ CHECK_HEX_CONST(10000000000);
+ CHECK_OCT_CONST(037777777777777);
+ CHECK_HEX_CONST(1ffffffffff);
+ CHECK_OCT_CONST(040000000000000);
+ CHECK_HEX_CONST(20000000000);
+ CHECK_OCT_CONST(077777777777777);
+ CHECK_HEX_CONST(3ffffffffff);
+ CHECK_OCT_CONST(0100000000000000);
+ CHECK_HEX_CONST(40000000000);
+ CHECK_OCT_CONST(0177777777777777);
+ CHECK_HEX_CONST(7ffffffffff);
+ CHECK_OCT_CONST(0200000000000000);
+ CHECK_HEX_CONST(80000000000);
+ CHECK_OCT_CONST(0377777777777777);
+ CHECK_HEX_CONST(fffffffffff);
+ CHECK_OCT_CONST(0400000000000000);
+ CHECK_HEX_CONST(100000000000);
+ CHECK_OCT_CONST(0777777777777777);
+ CHECK_HEX_CONST(1fffffffffff);
+ CHECK_OCT_CONST(01000000000000000);
+ CHECK_HEX_CONST(200000000000);
+ CHECK_OCT_CONST(01777777777777777);
+ CHECK_HEX_CONST(3fffffffffff);
+ CHECK_OCT_CONST(02000000000000000);
+ CHECK_HEX_CONST(400000000000);
+ CHECK_OCT_CONST(03777777777777777);
+ CHECK_HEX_CONST(7fffffffffff);
+ CHECK_OCT_CONST(04000000000000000);
+ CHECK_HEX_CONST(800000000000);
+ CHECK_OCT_CONST(07777777777777777);
+ CHECK_HEX_CONST(ffffffffffff);
+ CHECK_OCT_CONST(010000000000000000);
+ CHECK_HEX_CONST(1000000000000);
+ CHECK_OCT_CONST(017777777777777777);
+ CHECK_HEX_CONST(1ffffffffffff);
+ CHECK_OCT_CONST(020000000000000000);
+ CHECK_HEX_CONST(2000000000000);
+ CHECK_OCT_CONST(037777777777777777);
+ CHECK_HEX_CONST(3ffffffffffff);
+ CHECK_OCT_CONST(040000000000000000);
+ CHECK_HEX_CONST(4000000000000);
+ CHECK_OCT_CONST(077777777777777777);
+ CHECK_HEX_CONST(7ffffffffffff);
+ CHECK_OCT_CONST(0100000000000000000);
+ CHECK_HEX_CONST(8000000000000);
+ CHECK_OCT_CONST(0177777777777777777);
+ CHECK_HEX_CONST(fffffffffffff);
+ CHECK_OCT_CONST(0200000000000000000);
+ CHECK_HEX_CONST(10000000000000);
+ CHECK_OCT_CONST(0377777777777777777);
+ CHECK_HEX_CONST(1fffffffffffff);
+ CHECK_OCT_CONST(0400000000000000000);
+ CHECK_HEX_CONST(20000000000000);
+ CHECK_OCT_CONST(0777777777777777777);
+ CHECK_HEX_CONST(3fffffffffffff);
+ CHECK_OCT_CONST(01000000000000000000);
+ CHECK_HEX_CONST(40000000000000);
+ CHECK_OCT_CONST(01777777777777777777);
+ CHECK_HEX_CONST(7fffffffffffff);
+ CHECK_OCT_CONST(02000000000000000000);
+ CHECK_HEX_CONST(80000000000000);
+ CHECK_OCT_CONST(03777777777777777777);
+ CHECK_HEX_CONST(ffffffffffffff);
+ CHECK_OCT_CONST(04000000000000000000);
+ CHECK_HEX_CONST(100000000000000);
+ CHECK_OCT_CONST(07777777777777777777);
+ CHECK_HEX_CONST(1ffffffffffffff);
+ CHECK_OCT_CONST(010000000000000000000);
+ CHECK_HEX_CONST(200000000000000);
+ CHECK_OCT_CONST(017777777777777777777);
+ CHECK_HEX_CONST(3ffffffffffffff);
+ CHECK_OCT_CONST(020000000000000000000);
+ CHECK_HEX_CONST(400000000000000);
+ CHECK_OCT_CONST(037777777777777777777);
+ CHECK_HEX_CONST(7ffffffffffffff);
+ CHECK_OCT_CONST(040000000000000000000);
+ CHECK_HEX_CONST(800000000000000);
+ CHECK_OCT_CONST(077777777777777777777);
+ CHECK_HEX_CONST(fffffffffffffff);
+ CHECK_OCT_CONST(0100000000000000000000);
+ CHECK_HEX_CONST(1000000000000000);
+ CHECK_OCT_CONST(0177777777777777777777);
+ CHECK_HEX_CONST(1fffffffffffffff);
+ CHECK_OCT_CONST(0200000000000000000000);
+ CHECK_HEX_CONST(2000000000000000);
+ CHECK_OCT_CONST(0377777777777777777777);
+ CHECK_HEX_CONST(3fffffffffffffff);
+ CHECK_OCT_CONST(0400000000000000000000);
+ CHECK_HEX_CONST(4000000000000000);
+ CHECK_OCT_CONST(0777777777777777777777);
+ CHECK_HEX_CONST(7fffffffffffffff);
+ CHECK_OCT_CONST(01000000000000000000000);
+ CHECK_HEX_CONST(8000000000000000);
+ CHECK_OCT_CONST(01777777777777777777777);
+ CHECK_HEX_CONST(ffffffffffffffff);
+#if LLONG_AT_LEAST(65)
+ CHECK_OCT_CONST(02000000000000000000000);
+ CHECK_HEX_CONST(10000000000000000);
+ CHECK_OCT_CONST(03777777777777777777777);
+ CHECK_HEX_CONST(1ffffffffffffffff);
+#endif
+#if LLONG_AT_LEAST(66)
+ CHECK_OCT_CONST(04000000000000000000000);
+ CHECK_HEX_CONST(20000000000000000);
+ CHECK_OCT_CONST(07777777777777777777777);
+ CHECK_HEX_CONST(3ffffffffffffffff);
+#endif
+#if LLONG_AT_LEAST(67)
+ CHECK_OCT_CONST(010000000000000000000000);
+ CHECK_HEX_CONST(40000000000000000);
+ CHECK_OCT_CONST(017777777777777777777777);
+ CHECK_HEX_CONST(7ffffffffffffffff);
+#endif
+#if LLONG_AT_LEAST(68)
+ CHECK_OCT_CONST(020000000000000000000000);
+ CHECK_HEX_CONST(80000000000000000);
+ CHECK_OCT_CONST(037777777777777777777777);
+ CHECK_HEX_CONST(fffffffffffffffff);
+#endif
+#if LLONG_AT_LEAST(69)
+ CHECK_OCT_CONST(040000000000000000000000);
+ CHECK_HEX_CONST(100000000000000000);
+ CHECK_OCT_CONST(077777777777777777777777);
+ CHECK_HEX_CONST(1fffffffffffffffff);
+#endif
+#if LLONG_AT_LEAST(70)
+ CHECK_OCT_CONST(0100000000000000000000000);
+ CHECK_HEX_CONST(200000000000000000);
+ CHECK_OCT_CONST(0177777777777777777777777);
+ CHECK_HEX_CONST(3fffffffffffffffff);
+#endif
+#if LLONG_AT_LEAST(71)
+ CHECK_OCT_CONST(0200000000000000000000000);
+ CHECK_HEX_CONST(400000000000000000);
+ CHECK_OCT_CONST(0377777777777777777777777);
+ CHECK_HEX_CONST(7fffffffffffffffff);
+#endif
+#if LLONG_AT_LEAST(72)
+ CHECK_OCT_CONST(0400000000000000000000000);
+ CHECK_HEX_CONST(800000000000000000);
+ CHECK_OCT_CONST(0777777777777777777777777);
+ CHECK_HEX_CONST(ffffffffffffffffff);
+#endif
+}
diff --git a/INPUTS/carbon_h.c b/INPUTS/carbon_h.c
new file mode 100644
index 000000000000..599f123a36c6
--- /dev/null
+++ b/INPUTS/carbon_h.c
@@ -0,0 +1,4 @@
+
+#include <Carbon/Carbon.h>
+
+//#import<vecLib/vecLib.h>
diff --git a/INPUTS/iostream.cc b/INPUTS/iostream.cc
new file mode 100644
index 000000000000..eb12fc9aaf4e
--- /dev/null
+++ b/INPUTS/iostream.cc
@@ -0,0 +1,5 @@
+// clang -I/usr/include/c++/4.0.0 -I/usr/include/c++/4.0.0/powerpc-apple-darwin8 -I/usr/include/c++/4.0.0/backward INPUTS/iostream.cc -Eonly
+
+#include <iostream>
+
+#include <stdint.h>
diff --git a/INPUTS/macro_pounder_fn.c b/INPUTS/macro_pounder_fn.c
new file mode 100644
index 000000000000..73f40a1d6db8
--- /dev/null
+++ b/INPUTS/macro_pounder_fn.c
@@ -0,0 +1,17 @@
+
+// This pounds on macro expansion for performance reasons. This is currently
+// heavily constrained by darwin's malloc.
+
+// Function-like macros.
+#define A0(A, B) A B
+#define A1(A, B) A0(A,B) A0(A,B) A0(A,B) A0(A,B) A0(A,B) A0(A,B)
+#define A2(A, B) A1(A,B) A1(A,B) A1(A,B) A1(A,B) A1(A,B) A1(A,B)
+#define A3(A, B) A2(A,B) A2(A,B) A2(A,B) A2(A,B) A2(A,B) A2(A,B)
+#define A4(A, B) A3(A,B) A3(A,B) A3(A,B) A3(A,B) A3(A,B) A3(A,B)
+#define A5(A, B) A4(A,B) A4(A,B) A4(A,B) A4(A,B) A4(A,B) A4(A,B)
+#define A6(A, B) A5(A,B) A5(A,B) A5(A,B) A5(A,B) A5(A,B) A5(A,B)
+#define A7(A, B) A6(A,B) A6(A,B) A6(A,B) A6(A,B) A6(A,B) A6(A,B)
+#define A8(A, B) A7(A,B) A7(A,B) A7(A,B) A7(A,B) A7(A,B) A7(A,B)
+
+A8(a, b)
+
diff --git a/INPUTS/macro_pounder_obj.c b/INPUTS/macro_pounder_obj.c
new file mode 100644
index 000000000000..d2465f34edb7
--- /dev/null
+++ b/INPUTS/macro_pounder_obj.c
@@ -0,0 +1,16 @@
+
+// This pounds on macro expansion for performance reasons. This is currently
+// heavily constrained by darwin's malloc.
+
+// Object-like expansions
+#define A0 a b
+#define A1 A0 A0 A0 A0 A0 A0
+#define A2 A1 A1 A1 A1 A1 A1
+#define A3 A2 A2 A2 A2 A2 A2
+#define A4 A3 A3 A3 A3 A3 A3
+#define A5 A4 A4 A4 A4 A4 A4
+#define A6 A5 A5 A5 A5 A5 A5
+#define A7 A6 A6 A6 A6 A6 A6
+#define A8 A7 A7 A7 A7 A7 A7
+
+A8
diff --git a/INPUTS/stpcpy-test.c b/INPUTS/stpcpy-test.c
new file mode 100644
index 000000000000..b96a8066e63c
--- /dev/null
+++ b/INPUTS/stpcpy-test.c
@@ -0,0 +1,47 @@
+#define __extension__
+
+#define __stpcpy(dest, src) (__extension__ (__builtin_constant_p (src) ? (__string2_1bptr_p (src) && strlen (src) + 1 <= 8 ? __stpcpy_small (dest, __stpcpy_args (src), strlen (src) + 1) : ((char *) __mempcpy (dest, src, strlen (src) + 1) - 1)) : __stpcpy (dest, src)))
+#define stpcpy(dest, src) __stpcpy (dest, src)
+#define __stpcpy_args(src) __extension__ __STRING2_SMALL_GET16 (src, 0), __extension__ __STRING2_SMALL_GET16 (src, 4), __extension__ __STRING2_SMALL_GET32 (src, 0), __extension__ __STRING2_SMALL_GET32 (src, 4)
+
+#define __mempcpy(dest, src, n) (__extension__ (__builtin_constant_p (src) && __builtin_constant_p (n) && __string2_1bptr_p (src) && n <= 8 ? __mempcpy_small (dest, __mempcpy_args (src), n) : __mempcpy (dest, src, n)))
+#define mempcpy(dest, src, n) __mempcpy (dest, src, n)
+#define __mempcpy_args(src) ((char *) (src))[0], ((char *) (src))[2], ((char *) (src))[4], ((char *) (src))[6], __extension__ __STRING2_SMALL_GET16 (src, 0), __extension__ __STRING2_SMALL_GET16 (src, 4), __extension__ __STRING2_SMALL_GET32 (src, 0), __extension__ __STRING2_SMALL_GET32 (src, 4)
+
+#define __STRING2_SMALL_GET16(src, idx) (((__const unsigned char *) (__const char *) (src))[idx + 1] << 8 | ((__const unsigned char *) (__const char *) (src))[idx])
+
+#define __STRING2_SMALL_GET32(src, idx) (((((__const unsigned char *) (__const char *) (src))[idx + 3] << 8 | ((__const unsigned char *) (__const char *) (src))[idx + 2]) << 8 | ((__const unsigned char *) (__const char *) (src))[idx + 1]) << 8 | ((__const unsigned char *) (__const char *) (src))[idx])
+
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
+stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
diff --git a/LICENSE.TXT b/LICENSE.TXT
new file mode 100644
index 000000000000..21cb5c7ac589
--- /dev/null
+++ b/LICENSE.TXT
@@ -0,0 +1,63 @@
+==============================================================================
+LLVM Release License
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2007 University of Illinois at Urbana-Champaign.
+All rights reserved.
+
+Developed by:
+
+ LLVM Team
+
+ University of Illinois at Urbana-Champaign
+
+ http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+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:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimers in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLVM Team, University of Illinois at
+ Urbana-Champaign, nor the names of its contributors may be used to
+ endorse or promote products derived from this Software without specific
+ prior written permission.
+
+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
+CONTRIBUTORS 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 WITH THE
+SOFTWARE.
+
+==============================================================================
+The LLVM software contains code written by third parties. Such software will
+have its own individual LICENSE.TXT file in the directory in which it appears.
+This file will describe the copyrights, license, and restrictions which apply
+to that code.
+
+The disclaimer of warranty in the University of Illinois Open Source License
+applies to all code in the LLVM Distribution, and nothing in any of the
+other licenses gives permission to use the names of the LLVM Team or the
+University of Illinois to endorse or promote products derived from this
+Software.
+
+The following pieces of software have additional or alternate copyrights,
+licenses, and/or restrictions:
+
+Program Directory
+------- ---------
+<none yet>
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000000..00e38d26de46
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,32 @@
+LEVEL = ../..
+DIRS := include lib tools docs
+
+include $(LEVEL)/Makefile.common
+
+ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
+test::
+ $(Verb) if [ ! -f test/Makefile ]; then \
+ $(MKDIR) test; \
+ $(CP) $(PROJ_SRC_DIR)/test/Makefile test/Makefile; \
+ fi
+endif
+
+test::
+ @ $(MAKE) -C test
+
+report::
+ @ $(MAKE) -C test report
+
+clean::
+ @ $(MAKE) -C test clean
+
+tags::
+ $(Verb) etags `find . -type f -name \*.h | grep -v /lib/Headers | grep -v /test/` `find . -type f -name \*.cpp | grep -v /lib/Headers | grep -v /test/`
+
+cscope.files:
+ find tools lib include -name '*.cpp' \
+ -or -name '*.def' \
+ -or -name '*.td' \
+ -or -name '*.h' > cscope.files
+
+.PHONY: test report clean cscope.files
diff --git a/ModuleInfo.txt b/ModuleInfo.txt
new file mode 100644
index 000000000000..4368ef067aea
--- /dev/null
+++ b/ModuleInfo.txt
@@ -0,0 +1,5 @@
+# This file provides information for llvm-top
+DepModule: llvm
+ConfigCmd:
+ConfigTest:
+BuildCmd:
diff --git a/NOTES.txt b/NOTES.txt
new file mode 100644
index 000000000000..3b5ad16e3e10
--- /dev/null
+++ b/NOTES.txt
@@ -0,0 +1,86 @@
+//===---------------------------------------------------------------------===//
+// Random Notes
+//===---------------------------------------------------------------------===//
+
+C90/C99/C++ Comparisons:
+http://david.tribble.com/text/cdiffs.htm
+
+//===---------------------------------------------------------------------===//
+
+To time GCC preprocessing speed without output, use:
+ "time gcc -MM file"
+This is similar to -Eonly.
+
+//===---------------------------------------------------------------------===//
+
+Creating and using a PTH file for performance measurement (use a release-asserts
+build).
+
+$ clang -x objective-c-header INPUTS/Cocoa_h.m -o /tmp/tokencache
+$ clang -token-cache /tmp/tokencache INPUTS/Cocoa_h.m
+
+//===---------------------------------------------------------------------===//
+
+ C++ Template Instantiation benchmark:
+ http://users.rcn.com/abrahams/instantiation_speed/index.html
+
+//===---------------------------------------------------------------------===//
+
+TODO: File Manager Speedup:
+
+ We currently do a lot of stat'ing for files that don't exist, particularly
+ when lots of -I paths exist (e.g. see the <iostream> example, check for
+ failures in stat in FileManager::getFile). It would be far better to make
+ the following changes:
+ 1. FileEntry contains a sys::Path instead of a std::string for Name.
+ 2. sys::Path contains timestamp and size, lazily computed. Eliminate from
+ FileEntry.
+ 3. File UIDs are created on request, not when files are opened.
+ These changes make it possible to efficiently have FileEntry objects for
+ files that exist on the file system, but have not been used yet.
+
+ Once this is done:
+ 1. DirectoryEntry gets a boolean value "has read entries". When false, not
+ all entries in the directory are in the file mgr, when true, they are.
+ 2. Instead of stat'ing the file in FileManager::getFile, check to see if
+ the dir has been read. If so, fail immediately, if not, read the dir,
+ then retry.
+ 3. Reading the dir uses the getdirentries syscall, creating an FileEntry
+ for all files found.
+
+//===---------------------------------------------------------------------===//
+// Specifying targets: -triple and -arch
+===---------------------------------------------------------------------===//
+
+The clang supports "-triple" and "-arch" options. At most one -triple and one
+-arch option may be specified. Both are optional.
+
+The "selection of target" behavior is defined as follows:
+
+(1) If the user does not specify -triple, we default to the host triple.
+(2) If the user specifies a -arch, that overrides the arch in the host or
+ specified triple.
+
+//===---------------------------------------------------------------------===//
+
+
+verifyInputConstraint and verifyOutputConstraint should not return bool.
+
+Instead we should return something like:
+
+enum VerifyConstraintResult {
+ Valid,
+
+ // Output only
+ OutputOperandConstraintLacksEqualsCharacter,
+ MatchingConstraintNotValidInOutputOperand,
+
+ // Input only
+ InputOperandConstraintContainsEqualsCharacter,
+ MatchingConstraintReferencesInvalidOperandNumber,
+
+ // Both
+ PercentConstraintUsedWithLastOperand
+};
+
+//===---------------------------------------------------------------------===//
diff --git a/README.txt b/README.txt
new file mode 100644
index 000000000000..611dc9d2c01c
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,178 @@
+//===----------------------------------------------------------------------===//
+// C Language Family Front-end
+//===----------------------------------------------------------------------===//
+ Chris Lattner
+
+I. Introduction:
+
+ clang: noun
+ 1. A loud, resonant, metallic sound.
+ 2. The strident call of a crane or goose.
+ 3. C-language family front-end toolkit.
+
+ The world needs better compiler tools, tools which are built as libraries. This
+ design point allows reuse of the tools in new and novel ways. However, building
+ the tools as libraries isn't enough: they must have clean APIs, be as
+ decoupled from each other as possible, and be easy to modify/extend. This
+ requires clean layering, decent design, and avoiding tying the libraries to a
+ specific use. Oh yeah, did I mention that we want the resultant libraries to
+ be as fast as possible? :)
+
+ This front-end is built as a component of the LLVM toolkit that can be used
+ with the LLVM backend or independently of it. In this spirit, the API has been
+ carefully designed as the following components:
+
+ libsupport - Basic support library, reused from LLVM.
+
+ libsystem - System abstraction library, reused from LLVM.
+
+ libbasic - Diagnostics, SourceLocations, SourceBuffer abstraction,
+ file system caching for input source files. This depends on
+ libsupport and libsystem.
+
+ libast - Provides classes to represent the C AST, the C type system,
+ builtin functions, and various helpers for analyzing and
+ manipulating the AST (visitors, pretty printers, etc). This
+ library depends on libbasic.
+
+
+ liblex - C/C++/ObjC lexing and preprocessing, identifier hash table,
+ pragma handling, tokens, and macros. This depends on libbasic.
+
+ libparse - C (for now) parsing and local semantic analysis. This library
+ invokes coarse-grained 'Actions' provided by the client to do
+ stuff (e.g. libsema builds ASTs). This depends on liblex.
+
+ libsema - Provides a set of parser actions to build a standardized AST
+ for programs. AST's are 'streamed' out a top-level declaration
+ at a time, allowing clients to use decl-at-a-time processing,
+ build up entire translation units, or even build 'whole
+ program' ASTs depending on how they use the APIs. This depends
+ on libast and libparse.
+
+ librewrite - Fast, scalable rewriting of source code. This operates on
+ the raw syntactic text of source code, allowing a client
+ to insert and delete text in very large source files using
+ the same source location information embedded in ASTs. This
+ is intended to be a low-level API that is useful for
+ higher-level clients and libraries such as code refactoring.
+
+ libanalysis - Source-level dataflow analysis useful for performing analyses
+ such as computing live variables. It also includes a
+ path-sensitive "graph-reachability" engine for writing
+ analyses that reason about different possible paths of
+ execution through source code. This is currently being
+ employed to write a set of checks for finding bugs in software.
+
+ libcodegen - Lower the AST to LLVM IR for optimization & codegen. Depends
+ on libast.
+
+ clang - An example driver, client of the libraries at various levels.
+ This depends on all these libraries, and on LLVM VMCore.
+
+ This front-end has been intentionally built as a DAG of libraries, making it
+ easy to reuse individual parts or replace pieces if desired. For example, to
+ build a preprocessor, you take the Basic and Lexer libraries. If you want an
+ indexer, you take those plus the Parser library and provide some actions for
+ indexing. If you want a refactoring, static analysis, or source-to-source
+ compiler tool, it makes sense to take those plus the AST building and semantic
+ analyzer library. Finally, if you want to use this with the LLVM backend,
+ you'd take these components plus the AST to LLVM lowering code.
+
+ In the future I hope this toolkit will grow to include new and interesting
+ components, including a C++ front-end, ObjC support, and a whole lot of other
+ things.
+
+ Finally, it should be pointed out that the goal here is to build something that
+ is high-quality and industrial-strength: all the obnoxious features of the C
+ family must be correctly supported (trigraphs, preprocessor arcana, K&R-style
+ prototypes, GCC/MS extensions, etc). It cannot be used if it is not 'real'.
+
+
+II. Usage of clang driver:
+
+ * Basic Command-Line Options:
+ - Help: clang --help
+ - Standard GCC options accepted: -E, -I*, -i*, -pedantic, -std=c90, etc.
+ - To make diagnostics more gcc-like: -fno-caret-diagnostics -fno-show-column
+ - Enable metric printing: -stats
+
+ * -fsyntax-only is currently the default mode.
+
+ * -E mode works the same way as GCC.
+
+ * -Eonly mode does all preprocessing, but does not print the output,
+ useful for timing the preprocessor.
+
+ * -fsyntax-only is currently partially implemented, lacking some
+ semantic analysis (some errors and warnings are not produced).
+
+ * -parse-noop parses code without building an AST. This is useful
+ for timing the cost of the parser without including AST building
+ time.
+
+ * -parse-ast builds ASTs, but doesn't print them. This is most
+ useful for timing AST building vs -parse-noop.
+
+ * -parse-ast-print pretty prints most expression and statements nodes.
+
+ * -parse-ast-check checks that diagnostic messages that are expected
+ are reported and that those which are reported are expected.
+
+ * -dump-cfg builds ASTs and then CFGs. CFGs are then pretty-printed.
+
+ * -view-cfg builds ASTs and then CFGs. CFGs are then visualized by
+ invoking Graphviz.
+
+ For more information on getting Graphviz to work with clang/LLVM,
+ see: http://llvm.org/docs/ProgrammersManual.html#ViewGraph
+
+
+III. Current advantages over GCC:
+
+ * Column numbers are fully tracked (no 256 col limit, no GCC-style pruning).
+ * All diagnostics have column numbers, includes 'caret diagnostics', and they
+ highlight regions of interesting code (e.g. the LHS and RHS of a binop).
+ * Full diagnostic customization by client (can format diagnostics however they
+ like, e.g. in an IDE or refactoring tool) through DiagnosticClient interface.
+ * Built as a framework, can be reused by multiple tools.
+ * All languages supported linked into same library (no cc1,cc1obj, ...).
+ * mmap's code in read-only, does not dirty the pages like GCC (mem footprint).
+ * LLVM License, can be linked into non-GPL projects.
+ * Full diagnostic control, per diagnostic. Diagnostics are identified by ID.
+ * Significantly faster than GCC at semantic analysis, parsing, preprocessing
+ and lexing.
+ * Defers exposing platform-specific stuff to as late as possible, tracks use of
+ platform-specific features (e.g. #ifdef PPC) to allow 'portable bytecodes'.
+ * The lexer doesn't rely on the "lexer hack": it has no notion of scope and
+ does not categorize identifiers as types or variables -- this is up to the
+ parser to decide.
+
+Potential Future Features:
+
+ * Fine grained diag control within the source (#pragma enable/disable warning).
+ * Better token tracking within macros? (Token came from this line, which is
+ a macro argument instantiated here, recursively instantiated here).
+ * Fast #import with a module system.
+ * Dependency tracking: change to header file doesn't recompile every function
+ that texually depends on it: recompile only those functions that need it.
+ This is aka 'incremental parsing'.
+
+
+IV. Missing Functionality / Improvements
+
+Lexer:
+ * Source character mapping. GCC supports ASCII and UTF-8.
+ See GCC options: -ftarget-charset and -ftarget-wide-charset.
+ * Universal character support. Experimental in GCC, enabled with
+ -fextended-identifiers.
+ * -fpreprocessed mode.
+
+Preprocessor:
+ * #assert/#unassert
+ * MSExtension: "L#param" stringizes to a wide string literal.
+ * Add support for -M*
+
+Traditional Preprocessor:
+ * Currently, we have none. :)
+
diff --git a/TODO.txt b/TODO.txt
new file mode 100644
index 000000000000..522dcd37b365
--- /dev/null
+++ b/TODO.txt
@@ -0,0 +1,68 @@
+//===---------------------------------------------------------------------===//
+// 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)
+ - Change "foo.bar" to "foo->bar" when "foo" is a pointer.
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj
new file mode 100644
index 000000000000..c0ccb2e79733
--- /dev/null
+++ b/clang.xcodeproj/project.pbxproj
@@ -0,0 +1,1836 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 03F50AC60D416EAA00B9CF60 /* Targets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 03F50AC50D416EAA00B9CF60 /* Targets.cpp */; };
+ 1A2193CE0F45EEB700C0713D /* Mangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2193CC0F45EEB700C0713D /* Mangle.cpp */; };
+ 1A2A54B50FD1DD1C00F4CE45 /* AnalysisConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */; };
+ 1A2A54B60FD1DD1C00F4CE45 /* ASTConsumers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */; };
+ 1A2A54B70FD1DD1C00F4CE45 /* Backend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */; };
+ 1A2A54B80FD1DD1C00F4CE45 /* CacheTokens.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */; };
+ 1A2A54B90FD1DD1C00F4CE45 /* DependencyFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A80FD1DD1C00F4CE45 /* DependencyFile.cpp */; };
+ 1A2A54BA0FD1DD1C00F4CE45 /* DiagChecker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A90FD1DD1C00F4CE45 /* DiagChecker.cpp */; };
+ 1A2A54BB0FD1DD1C00F4CE45 /* DocumentXML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54AA0FD1DD1C00F4CE45 /* DocumentXML.cpp */; };
+ 1A2A54BC0FD1DD1C00F4CE45 /* GeneratePCH.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54AB0FD1DD1C00F4CE45 /* GeneratePCH.cpp */; };
+ 1A2A54BD0FD1DD1C00F4CE45 /* HTMLPrint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54AC0FD1DD1C00F4CE45 /* HTMLPrint.cpp */; };
+ 1A2A54BE0FD1DD1C00F4CE45 /* PrintParserCallbacks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54AD0FD1DD1C00F4CE45 /* PrintParserCallbacks.cpp */; };
+ 1A2A54BF0FD1DD1C00F4CE45 /* PrintPreprocessedOutput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54AE0FD1DD1C00F4CE45 /* PrintPreprocessedOutput.cpp */; };
+ 1A2A54C00FD1DD1C00F4CE45 /* RewriteBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54AF0FD1DD1C00F4CE45 /* RewriteBlocks.cpp */; };
+ 1A2A54C10FD1DD1C00F4CE45 /* RewriteMacros.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54B00FD1DD1C00F4CE45 /* RewriteMacros.cpp */; };
+ 1A2A54C20FD1DD1C00F4CE45 /* RewriteObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54B10FD1DD1C00F4CE45 /* RewriteObjC.cpp */; };
+ 1A2A54C30FD1DD1C00F4CE45 /* RewriteTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54B20FD1DD1C00F4CE45 /* RewriteTest.cpp */; };
+ 1A2A54C40FD1DD1C00F4CE45 /* StmtXML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54B30FD1DD1C00F4CE45 /* StmtXML.cpp */; };
+ 1A2A54C50FD1DD1C00F4CE45 /* Warnings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54B40FD1DD1C00F4CE45 /* Warnings.cpp */; };
+ 1A30A9E90B93A4C800201A91 /* ExprCXX.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A30A9E80B93A4C800201A91 /* ExprCXX.h */; };
+ 1A32C17F0E1C87AD00A6B483 /* ExprConstant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */; };
+ 1A376A2D0D4AED9B002A1C52 /* CGExprConstant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */; };
+ 1A410F850FBCE51100351440 /* SemaTemplateInstantiateExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A410F840FBCE51100351440 /* SemaTemplateInstantiateExpr.cpp */; };
+ 1A471AB50F437BC500753CE8 /* CGBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */; };
+ 1A5119C40FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A5119C30FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp */; };
+ 1A5D5E580E5E81010023C059 /* CGCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A5D5E570E5E81010023C059 /* CGCXX.cpp */; };
+ 1A701B640F7C8FE400FEC4D1 /* SemaAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */; };
+ 1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A7342470C7B57D500122F56 /* CGObjC.cpp */; };
+ 1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */; };
+ 1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; };
+ 1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */; };
+ 1ADF47AF0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */; };
+ 1AFEF4070F8A6B2300476F2B /* clang-cc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFEF4050F8A6B2300476F2B /* clang-cc.cpp */; };
+ 3507E4C20E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */; };
+ 352246E70F5C6BE000D0D279 /* HTMLDiagnostics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */; };
+ 352246E80F5C6BE000D0D279 /* InitHeaderSearch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E20F5C6BE000D0D279 /* InitHeaderSearch.cpp */; };
+ 352246E90F5C6BE000D0D279 /* ManagerRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E30F5C6BE000D0D279 /* ManagerRegistry.cpp */; };
+ 352246EA0F5C6BE000D0D279 /* PlistDiagnostics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E40F5C6BE000D0D279 /* PlistDiagnostics.cpp */; };
+ 352246EB0F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E50F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp */; };
+ 352246EC0F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E60F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp */; };
+ 35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */; };
+ 352712510DAFE54700C76352 /* IdentifierResolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352712500DAFE54700C76352 /* IdentifierResolver.cpp */; };
+ 3534A01D0E129849002709B2 /* ParseCXXInlineMethods.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3534A01C0E129849002709B2 /* ParseCXXInlineMethods.cpp */; };
+ 3536456B0E23EBF7009C6509 /* Environment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3536456A0E23EBF7009C6509 /* Environment.cpp */; };
+ 3537AA0E0ECD08A4008F7CDC /* PreprocessorLexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3537AA0D0ECD08A4008F7CDC /* PreprocessorLexer.cpp */; };
+ 3538FDB80ED24A4E005EC283 /* DeclarationName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3538FDB70ED24A4E005EC283 /* DeclarationName.cpp */; };
+ 353959D50EE5F88A00E82461 /* ParseTemplate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 353959D40EE5F88A00E82461 /* ParseTemplate.cpp */; };
+ 35475B200E79973F0000BFE4 /* CGCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35475B1F0E79973F0000BFE4 /* CGCall.cpp */; };
+ 355106860E9A8507006A4E44 /* MemRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 355106850E9A8507006A4E44 /* MemRegion.cpp */; };
+ 3551068C0E9A8546006A4E44 /* ParsePragma.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3551068A0E9A8546006A4E44 /* ParsePragma.cpp */; };
+ 3551068D0E9A8546006A4E44 /* ParseTentative.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3551068B0E9A8546006A4E44 /* ParseTentative.cpp */; };
+ 3552E7550E520D80003A8CA5 /* PPCaching.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3552E7540E520D80003A8CA5 /* PPCaching.cpp */; };
+ 3552E7590E520DD7003A8CA5 /* CGObjCMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3552E7580E520DD7003A8CA5 /* CGObjCMac.cpp */; };
+ 35544B880F5C7FD700D92AA9 /* RangeConstraintManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35544B850F5C7FD700D92AA9 /* RangeConstraintManager.cpp */; };
+ 35544B890F5C7FD700D92AA9 /* SimpleConstraintManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35544B860F5C7FD700D92AA9 /* SimpleConstraintManager.cpp */; };
+ 35544B8C0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */; };
+ 3557D1A90EB136B100C59739 /* InheritViz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3557D1A80EB136B100C59739 /* InheritViz.cpp */; };
+ 3557D1F00EB13BB700C59739 /* SemaInherit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3557D1EF0EB13BB700C59739 /* SemaInherit.cpp */; };
+ 35585DC00EAFBC4500D0A97A /* SemaOverload.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */; };
+ 3558F76D0E267C8300A5B0DF /* BasicStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3558F76C0E267C8300A5B0DF /* BasicStore.cpp */; };
+ 356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */; };
+ 35707EFE0CD0F5CC000B2204 /* SourceLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35707EFD0CD0F5CC000B2204 /* SourceLocation.cpp */; };
+ 357EA27D0F2526F300439B60 /* SemaLookup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 357EA27C0F2526F300439B60 /* SemaLookup.cpp */; };
+ 35847BE50CC7DBAF00C40FFF /* StmtIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35847BE40CC7DBAF00C40FFF /* StmtIterator.cpp */; };
+ 35862B0D0E3628CB0009F542 /* CheckDeadStores.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35862B0C0E3628CB0009F542 /* CheckDeadStores.cpp */; };
+ 35862B120E3629850009F542 /* GRExprEngineInternalChecks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35862B110E3629850009F542 /* GRExprEngineInternalChecks.cpp */; };
+ 358CFBB80E65AB04002A8E19 /* BasicConstraintManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 358CFBB70E65AB04002A8E19 /* BasicConstraintManager.cpp */; };
+ 358D230B0E8BEB9D0003DDCC /* DeclGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 358D230A0E8BEB9D0003DDCC /* DeclGroup.cpp */; };
+ 358F51520E529AA4007F2102 /* GRState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 358F51510E529AA4007F2102 /* GRState.cpp */; };
+ 3591853F0EFB1088000039AF /* SemaTemplate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3591853E0EFB1088000039AF /* SemaTemplate.cpp */; };
+ 3593790A0DA48ABA0043B19C /* BugReporter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 359379090DA48ABA0043B19C /* BugReporter.cpp */; };
+ 3595AFB80E1C8D62004CDF09 /* CheckObjCDealloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3595AFB70E1C8D62004CDF09 /* CheckObjCDealloc.cpp */; };
+ 3599299B0DE2425300A8A33E /* SemaInit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3599299A0DE2425300A8A33E /* SemaInit.cpp */; };
+ 35A057E20EAE2D950069249F /* RegionStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35A057E00EAE2D950069249F /* RegionStore.cpp */; };
+ 35A057E30EAE2D950069249F /* SVals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35A057E10EAE2D950069249F /* SVals.cpp */; };
+ 35A3E7020DD3874400757F74 /* CGDebugInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35A3E7000DD3874400757F74 /* CGDebugInfo.cpp */; };
+ 35A8FCF90D9B4B2A001C2F97 /* PathDiagnostic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35A8FCF80D9B4B29001C2F97 /* PathDiagnostic.cpp */; };
+ 35BAC1E80E82C5B7003FB76F /* CheckNSError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35BAC1E70E82C5B7003FB76F /* CheckNSError.cpp */; };
+ 35BB2D7F0D19954000944DB5 /* ASTConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35BB2D7E0D19954000944DB5 /* ASTConsumer.cpp */; };
+ 35CFFE000CA1CBCB00E6F2BE /* StmtViz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35CFFDFF0CA1CBCB00E6F2BE /* StmtViz.cpp */; };
+ 35D55B270D81D8C60092E734 /* BasicValueFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35D55B240D81D8C60092E734 /* BasicValueFactory.cpp */; };
+ 35D55B280D81D8C60092E734 /* CFRefCount.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35D55B250D81D8C60092E734 /* CFRefCount.cpp */; };
+ 35E194690ECB82FB00F21733 /* SemaCXXScopeSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35E194670ECB82FB00F21733 /* SemaCXXScopeSpec.cpp */; };
+ 35E1946A0ECB82FB00F21733 /* SemaNamedCast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35E194680ECB82FB00F21733 /* SemaNamedCast.cpp */; };
+ 35E1946D0ECB83C100F21733 /* PTHLexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35E1946C0ECB83C100F21733 /* PTHLexer.cpp */; };
+ 35EE48B10E0C4CCA00715C54 /* DeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35EE48AF0E0C4CCA00715C54 /* DeclCXX.cpp */; };
+ 35EE48B20E0C4CCA00715C54 /* ParentMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35EE48B00E0C4CCA00715C54 /* ParentMap.cpp */; };
+ 35EF67700DAD1D2C00B19414 /* SemaDeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35EF676F0DAD1D2C00B19414 /* SemaDeclCXX.cpp */; };
+ 35EFEFB60DB67ED60020783D /* GRTransferFuncs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35EFEFB50DB67ED60020783D /* GRTransferFuncs.cpp */; };
+ 35F2A01E0E36AFF100D17527 /* CheckObjCUnusedIVars.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35F2A01D0E36AFF100D17527 /* CheckObjCUnusedIVars.cpp */; };
+ 35F8D0D60D9B82CD00D91C5E /* BasicObjCFoundationChecks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35F8D0D50D9B82CD00D91C5E /* BasicObjCFoundationChecks.cpp */; };
+ 35FE6BCF0DF6EE1F00739712 /* DeclBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35FE6BCE0DF6EE1F00739712 /* DeclBase.cpp */; };
+ 72D16C1F0D9975C400E6DA4A /* HTMLRewrite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 72D16C1E0D9975C400E6DA4A /* HTMLRewrite.cpp */; };
+ 84AF36A10CB17A3B00C820A5 /* DeclObjC.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84AF36A00CB17A3B00C820A5 /* DeclObjC.h */; };
+ 84D9A8880C1A57E100AC7ABC /* AttributeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */; };
+ 84D9A88C0C1A581300AC7ABC /* AttributeList.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84D9A88B0C1A581300AC7ABC /* AttributeList.h */; };
+ 906BF4B00F83BA2E001071FA /* ConvertUTF.c in Sources */ = {isa = PBXBuildFile; fileRef = 906BF4AF0F83BA2E001071FA /* ConvertUTF.c */; };
+ DE01DA490B12ADA300AC22CE /* PPCallbacks.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE01DA480B12ADA300AC22CE /* PPCallbacks.h */; };
+ DE06756C0C051CFE00EBBFD8 /* ParseExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */; };
+ DE06B73E0A8307640050E87E /* LangOptions.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE06B73D0A8307640050E87E /* LangOptions.h */; };
+ DE06BECB0A854E4B0050E87E /* Scope.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE06BECA0A854E4B0050E87E /* Scope.h */; };
+ DE06D4310A8BB52D0050E87E /* Parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE06D42F0A8BB52D0050E87E /* Parser.cpp */; };
+ DE06E8140A8FF9330050E87E /* Action.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE06E8130A8FF9330050E87E /* Action.h */; };
+ DE0FCA630A95859D00248FD5 /* Expr.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE0FCA620A95859D00248FD5 /* Expr.h */; };
+ DE0FCB340A9C21F100248FD5 /* Expr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE0FCB330A9C21F100248FD5 /* Expr.cpp */; };
+ DE1733000B068B700080B521 /* ASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE1732FF0B068B700080B521 /* ASTContext.cpp */; };
+ DE17336E0B068DC20080B521 /* DeclSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE17336D0B068DC20080B521 /* DeclSpec.cpp */; };
+ DE1733700B068DC60080B521 /* DeclSpec.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE17336F0B068DC60080B521 /* DeclSpec.h */; };
+ DE1F22030A7D852A00FBF588 /* Parser.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE1F22020A7D852A00FBF588 /* Parser.h */; };
+ DE224FF80C7AA98800D370A5 /* CGExprComplex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE224FF70C7AA98800D370A5 /* CGExprComplex.cpp */; };
+ DE2252700C7E82D000D370A5 /* CGExprScalar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE22526F0C7E82D000D370A5 /* CGExprScalar.cpp */; };
+ DE2255FC0C8004E600D370A5 /* ParseDeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE2255FB0C8004E600D370A5 /* ParseDeclCXX.cpp */; };
+ DE22BCF20E14197E0094DC60 /* SemaDeclAttr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE22BCF10E14197E0094DC60 /* SemaDeclAttr.cpp */; };
+ DE344AB80AE5DF6D00DBC861 /* HeaderSearch.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE344AB70AE5DF6D00DBC861 /* HeaderSearch.h */; };
+ DE344B540AE5E46C00DBC861 /* HeaderSearch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE344B530AE5E46C00DBC861 /* HeaderSearch.cpp */; };
+ DE3450D70AEB543100DBC861 /* DirectoryLookup.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3450D60AEB543100DBC861 /* DirectoryLookup.h */; };
+ DE3452410AEF1A2D00DBC861 /* Stmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3452400AEF1A2D00DBC861 /* Stmt.cpp */; };
+ DE3452810AEF1B1800DBC861 /* Stmt.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3452800AEF1B1800DBC861 /* Stmt.h */; };
+ DE345C1A0AFC658B00DBC861 /* StmtVisitor.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE345C190AFC658B00DBC861 /* StmtVisitor.h */; };
+ DE345F220AFD347900DBC861 /* StmtNodes.def in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE345F210AFD347900DBC861 /* StmtNodes.def */; };
+ DE3460000AFDCC1900DBC861 /* ParseObjc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE345FFF0AFDCC1900DBC861 /* ParseObjc.cpp */; };
+ DE3460050AFDCC6500DBC861 /* ParseInit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3460040AFDCC6500DBC861 /* ParseInit.cpp */; };
+ DE34600B0AFDCCBF00DBC861 /* ParseStmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE34600A0AFDCCBF00DBC861 /* ParseStmt.cpp */; };
+ DE34600F0AFDCCCE00DBC861 /* ParseDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE34600E0AFDCCCE00DBC861 /* ParseDecl.cpp */; };
+ DE3460130AFDCCDA00DBC861 /* ParseExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3460120AFDCCDA00DBC861 /* ParseExpr.cpp */; };
+ DE3461270AFE68BE00DBC861 /* MinimalAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3461260AFE68BE00DBC861 /* MinimalAction.cpp */; };
+ DE34621D0AFEB19B00DBC861 /* StmtPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */; };
+ DE3464220B03040900DBC861 /* Type.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3464210B03040900DBC861 /* Type.h */; };
+ DE38CD500D794D0100A273B6 /* CGObjCGNU.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */; };
+ DE38CF270D8C9E6C00A273B6 /* DeclObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE38CF260D8C9E6C00A273B6 /* DeclObjC.cpp */; };
+ DE3986F00CB8D4B300223765 /* IdentifierTable.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3986EF0CB8D4B300223765 /* IdentifierTable.h */; };
+ DE3986F40CB8D50C00223765 /* IdentifierTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3986F30CB8D50C00223765 /* IdentifierTable.cpp */; };
+ DE4121350D7F1C1C0080F80A /* SymbolManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE4121270D7F1C1C0080F80A /* SymbolManager.cpp */; };
+ DE4121360D7F1C1C0080F80A /* ExplodedGraph.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE4121280D7F1C1C0080F80A /* ExplodedGraph.cpp */; };
+ DE4121370D7F1C1C0080F80A /* UninitializedValues.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE4121290D7F1C1C0080F80A /* UninitializedValues.cpp */; };
+ DE4121380D7F1C1C0080F80A /* GRCoreEngine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE41212A0D7F1C1C0080F80A /* GRCoreEngine.cpp */; };
+ DE41213C0D7F1C1C0080F80A /* GRSimpleVals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE41212F0D7F1C1C0080F80A /* GRSimpleVals.cpp */; };
+ DE41213D0D7F1C1C0080F80A /* GRBlockCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE4121300D7F1C1C0080F80A /* GRBlockCounter.cpp */; };
+ DE41213E0D7F1C1C0080F80A /* GRExprEngine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE4121310D7F1C1C0080F80A /* GRExprEngine.cpp */; };
+ DE4264FC0C113592005A861D /* CGDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE4264FB0C113592005A861D /* CGDecl.cpp */; };
+ DE46BF280AE0A82D00CC047C /* TargetInfo.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE46BF270AE0A82D00CC047C /* TargetInfo.h */; };
+ DE4772FA0C10EAE5002239E8 /* CGStmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE4772F90C10EAE5002239E8 /* CGStmt.cpp */; };
+ DE4772FC0C10EAEC002239E8 /* CGExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE4772FB0C10EAEC002239E8 /* CGExpr.cpp */; };
+ DE47999C0D2EBE1A00706D2D /* SemaExprObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE47999B0D2EBE1A00706D2D /* SemaExprObjC.cpp */; };
+ DE4DC7A30EA1C33E00069E5A /* TokenRewriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE4DC7A20EA1C33E00069E5A /* TokenRewriter.cpp */; };
+ DE67E70B0C020EC500F66BC5 /* SemaType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E70A0C020EC500F66BC5 /* SemaType.cpp */; };
+ DE67E70D0C020ECA00F66BC5 /* SemaStmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */; };
+ DE67E70F0C020ECF00F66BC5 /* SemaExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */; };
+ DE67E7110C020ED400F66BC5 /* SemaExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */; };
+ DE67E7130C020ED900F66BC5 /* SemaDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E7120C020ED900F66BC5 /* SemaDecl.cpp */; };
+ DE67E7150C020EDF00F66BC5 /* Sema.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE67E7140C020EDF00F66BC5 /* Sema.h */; };
+ DE67E7170C020EE400F66BC5 /* Sema.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E7160C020EE400F66BC5 /* Sema.cpp */; };
+ DE67E71A0C020F4F00F66BC5 /* ParseAST.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E7190C020F4F00F66BC5 /* ParseAST.cpp */; };
+ DE67E7280C02109800F66BC5 /* ParseAST.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE67E7270C02109800F66BC5 /* ParseAST.h */; };
+ DE6951C70C4D1F5D00A5826B /* RecordLayout.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE6951C60C4D1F5D00A5826B /* RecordLayout.h */; };
+ DE6954640C5121BD00A5826B /* Token.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE6954630C5121BD00A5826B /* Token.h */; };
+ DE704B260D0FBEBE009C7762 /* SemaDeclObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */; };
+ DE704DD20D1668A4009C7762 /* HeaderMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE704DD10D1668A4009C7762 /* HeaderMap.cpp */; };
+ DE75ED290B044DC90020CF81 /* ASTContext.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE75ED280B044DC90020CF81 /* ASTContext.h */; };
+ DE75EDF10B06880E0020CF81 /* Type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE75EDF00B06880E0020CF81 /* Type.cpp */; };
+ DE85CD810D8380B10070E26E /* TokenLexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE85CD800D8380B10070E26E /* TokenLexer.cpp */; };
+ DE85CDA30D8383B20070E26E /* MacroArgs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE85CDA20D8383B20070E26E /* MacroArgs.cpp */; };
+ DE85CDAC0D838C120070E26E /* PPMacroExpansion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE85CDAB0D838C120070E26E /* PPMacroExpansion.cpp */; };
+ DE85CDB00D838C390070E26E /* PPDirectives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE85CDAF0D838C390070E26E /* PPDirectives.cpp */; };
+ DE85CDB60D839BAE0070E26E /* PPLexerChange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE85CDB50D839BAE0070E26E /* PPLexerChange.cpp */; };
+ DE8823CB0ED0046600CBC30A /* APValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE8823CA0ED0046600CBC30A /* APValue.cpp */; };
+ DE928B130C05659200231DA4 /* ModuleBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE928B120C05659200231DA4 /* ModuleBuilder.cpp */; };
+ DE928B200C0565B000231DA4 /* ModuleBuilder.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE928B1F0C0565B000231DA4 /* ModuleBuilder.h */; };
+ DE928B7D0C0A615100231DA4 /* CodeGenModule.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE928B7C0C0A615100231DA4 /* CodeGenModule.h */; };
+ DE928B7F0C0A615600231DA4 /* CodeGenModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE928B7E0C0A615600231DA4 /* CodeGenModule.cpp */; };
+ DE928B810C0A615B00231DA4 /* CodeGenFunction.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE928B800C0A615B00231DA4 /* CodeGenFunction.h */; };
+ DE928B830C0A616000231DA4 /* CodeGenFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */; };
+ DEAEE98B0A5A2B970045101B /* MultipleIncludeOpt.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEAEE98A0A5A2B970045101B /* MultipleIncludeOpt.h */; };
+ DEAEED4B0A5AF89A0045101B /* NOTES.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEAEED4A0A5AF89A0045101B /* NOTES.txt */; };
+ DEB076CF0F3A222200F5A2BE /* DeclTemplate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */; };
+ DEB077990F44F97800F5A2BE /* TokenConcatenation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */; };
+ DEB07AC80F4A427E00F5A2BE /* SemaAttr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */; };
+ DEC63B1A0C7B940200DBF169 /* CFG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEC63B190C7B940200DBF169 /* CFG.cpp */; };
+ DEC63B1C0C7B940600DBF169 /* CFG.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEC63B1B0C7B940600DBF169 /* CFG.h */; };
+ DEC8D9910A9433CD00353FCA /* Decl.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEC8D9900A9433CD00353FCA /* Decl.h */; };
+ DEC8D9A40A94346E00353FCA /* AST.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEC8D9A30A94346E00353FCA /* AST.h */; };
+ DECAB0D00DB3C84200E13CCB /* RewriteRope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DECAB0CF0DB3C84200E13CCB /* RewriteRope.cpp */; };
+ DECB6D650F9AE26600F5FBC7 /* JumpDiagnostics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DECB6D640F9AE26600F5FBC7 /* JumpDiagnostics.cpp */; };
+ DECB6F070F9D93A800F5FBC7 /* InitPreprocessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DECB6F060F9D93A800F5FBC7 /* InitPreprocessor.cpp */; };
+ DECB77130FA5752300F5FBC7 /* PCHReaderStmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DECB77120FA5752300F5FBC7 /* PCHReaderStmt.cpp */; };
+ DECB77790FA579B000F5FBC7 /* PCHReaderDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DECB77780FA579B000F5FBC7 /* PCHReaderDecl.cpp */; };
+ DECB77F70FA5850200F5FBC7 /* PCHWriterDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DECB77F60FA5850200F5FBC7 /* PCHWriterDecl.cpp */; };
+ DECB78170FA5882F00F5FBC7 /* PCHWriterStmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DECB78160FA5882F00F5FBC7 /* PCHWriterStmt.cpp */; };
+ DED626C90AE0C065001E80A4 /* TargetInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED626C80AE0C065001E80A4 /* TargetInfo.cpp */; };
+ DED62ABB0AE2EDF1001E80A4 /* Decl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */; };
+ DED676D10B6C786700AAD4A3 /* Builtins.def in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED676D00B6C786700AAD4A3 /* Builtins.def */; };
+ DED676FA0B6C797B00AAD4A3 /* Builtins.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED676F90B6C797B00AAD4A3 /* Builtins.h */; };
+ DED677C90B6C854100AAD4A3 /* Builtins.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED677C80B6C854100AAD4A3 /* Builtins.cpp */; };
+ DED7D7410A524295003AD0FB /* Diagnostic.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7310A524295003AD0FB /* Diagnostic.h */; };
+ DED7D7430A524295003AD0FB /* FileManager.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7330A524295003AD0FB /* FileManager.h */; };
+ DED7D7450A524295003AD0FB /* SourceLocation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7350A524295003AD0FB /* SourceLocation.h */; };
+ DED7D7460A524295003AD0FB /* SourceManager.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7360A524295003AD0FB /* SourceManager.h */; };
+ DED7D7470A524295003AD0FB /* TokenKinds.def in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7370A524295003AD0FB /* TokenKinds.def */; };
+ DED7D7480A524295003AD0FB /* TokenKinds.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7380A524295003AD0FB /* TokenKinds.h */; };
+ DED7D74A0A524295003AD0FB /* Lexer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D73B0A524295003AD0FB /* Lexer.h */; };
+ DED7D74D0A524295003AD0FB /* MacroInfo.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D73E0A524295003AD0FB /* MacroInfo.h */; };
+ DED7D74E0A524295003AD0FB /* Pragma.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D73F0A524295003AD0FB /* Pragma.h */; };
+ DED7D74F0A524295003AD0FB /* Preprocessor.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7400A524295003AD0FB /* Preprocessor.h */; };
+ DED7D77A0A5242C7003AD0FB /* Diagnostic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D75D0A5242C7003AD0FB /* Diagnostic.cpp */; };
+ DED7D77B0A5242C7003AD0FB /* FileManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D75E0A5242C7003AD0FB /* FileManager.cpp */; };
+ DED7D7890A5242C7003AD0FB /* SourceManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D76D0A5242C7003AD0FB /* SourceManager.cpp */; };
+ DED7D78A0A5242C7003AD0FB /* TokenKinds.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D76E0A5242C7003AD0FB /* TokenKinds.cpp */; };
+ DED7D7C30A5242E6003AD0FB /* Lexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D79E0A5242E6003AD0FB /* Lexer.cpp */; };
+ DED7D7C50A5242E6003AD0FB /* MacroInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D7A00A5242E6003AD0FB /* MacroInfo.cpp */; };
+ DED7D7C70A5242E6003AD0FB /* PPExpressions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D7A20A5242E6003AD0FB /* PPExpressions.cpp */; };
+ DED7D7C80A5242E6003AD0FB /* Pragma.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D7A30A5242E6003AD0FB /* Pragma.cpp */; };
+ DED7D7C90A5242E6003AD0FB /* Preprocessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D7A40A5242E6003AD0FB /* Preprocessor.cpp */; };
+ DED7D7D80A524302003AD0FB /* README.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7D70A524302003AD0FB /* README.txt */; };
+ DED7D9180A52518C003AD0FB /* ScratchBuffer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D9170A52518C003AD0FB /* ScratchBuffer.h */; };
+ DED7D9E50A5257F6003AD0FB /* ScratchBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */; };
+ DEDFE5CF0F7206E40035BD10 /* NestedNameSpecifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE5CE0F7206E40035BD10 /* NestedNameSpecifier.cpp */; };
+ DEDFE6460F7B3B4E0035BD10 /* driver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6450F7B3B4E0035BD10 /* driver.cpp */; };
+ DEDFE65A0F7B3B830035BD10 /* Types.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6480F7B3B830035BD10 /* Types.cpp */; };
+ DEDFE65B0F7B3B830035BD10 /* Tools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE64A0F7B3B830035BD10 /* Tools.cpp */; };
+ DEDFE65C0F7B3B830035BD10 /* Compilation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE64C0F7B3B830035BD10 /* Compilation.cpp */; };
+ DEDFE65D0F7B3B830035BD10 /* ArgList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE64D0F7B3B830035BD10 /* ArgList.cpp */; };
+ DEDFE65E0F7B3B830035BD10 /* Arg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE64E0F7B3B830035BD10 /* Arg.cpp */; };
+ DEDFE65F0F7B3B830035BD10 /* Action.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE64F0F7B3B830035BD10 /* Action.cpp */; };
+ DEDFE6600F7B3B830035BD10 /* Phases.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6500F7B3B830035BD10 /* Phases.cpp */; };
+ DEDFE6610F7B3B830035BD10 /* OptTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6510F7B3B830035BD10 /* OptTable.cpp */; };
+ DEDFE6620F7B3B830035BD10 /* Option.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6520F7B3B830035BD10 /* Option.cpp */; };
+ DEDFE6630F7B3B830035BD10 /* Job.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6530F7B3B830035BD10 /* Job.cpp */; };
+ DEDFE6640F7B3B830035BD10 /* ToolChains.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6550F7B3B830035BD10 /* ToolChains.cpp */; };
+ DEDFE6650F7B3B830035BD10 /* ToolChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6560F7B3B830035BD10 /* ToolChain.cpp */; };
+ DEDFE6660F7B3B830035BD10 /* Tool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6570F7B3B830035BD10 /* Tool.cpp */; };
+ DEDFE6670F7B3B830035BD10 /* HostInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6580F7B3B830035BD10 /* HostInfo.cpp */; };
+ DEDFE6680F7B3B830035BD10 /* Driver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6590F7B3B830035BD10 /* Driver.cpp */; };
+ DEDFF8880F848CF80035BD10 /* TemplateName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFF8870F848CF80035BD10 /* TemplateName.cpp */; };
+ DEEBBD440C19C5D200A9FE82 /* TODO.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEEBBD430C19C5D200A9FE82 /* TODO.txt */; };
+ DEEBC3BA0C2363B800A9FE82 /* CodeGenTypes.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEEBC3B90C2363B800A9FE82 /* CodeGenTypes.h */; };
+ DEEBC3BC0C2363BC00A9FE82 /* CodeGenTypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEEBC3BB0C2363BC00A9FE82 /* CodeGenTypes.cpp */; };
+ DEF165710F8FB34D0098507F /* PCHWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF165700F8FB34D0098507F /* PCHWriter.cpp */; };
+ DEF165750F8FB3510098507F /* PCHReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF165740F8FB3510098507F /* PCHReader.cpp */; };
+ DEF168400F9548DC0098507F /* FixItRewriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF1683F0F9548DC0098507F /* FixItRewriter.cpp */; };
+ DEF2E95F0C5FBD74000C4259 /* InternalsManual.html in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEF2E95E0C5FBD74000C4259 /* InternalsManual.html */; };
+ DEF2EDA70C6A4252000C4259 /* StmtDumper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */; };
+ DEF2EFF30C6CDD74000C4259 /* CGExprAgg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF2EFF20C6CDD74000C4259 /* CGExprAgg.cpp */; };
+ DEF2F0100C6CFED5000C4259 /* SemaChecking.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */; };
+ DEF7D9F70C9C8B1A0001F598 /* Rewriter.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEF7D9F60C9C8B1A0001F598 /* Rewriter.h */; };
+ DEF7D9F90C9C8B1D0001F598 /* Rewriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF7D9F80C9C8B1D0001F598 /* Rewriter.cpp */; };
+ DEFFECA70DB1546600B4E7C3 /* DeltaTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEFFECA60DB1546600B4E7C3 /* DeltaTree.cpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 8DD76F690486A84900D96B5E /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ DED7D7410A524295003AD0FB /* Diagnostic.h in CopyFiles */,
+ DED7D7430A524295003AD0FB /* FileManager.h in CopyFiles */,
+ DED7D7450A524295003AD0FB /* SourceLocation.h in CopyFiles */,
+ DED7D7460A524295003AD0FB /* SourceManager.h in CopyFiles */,
+ DED7D7470A524295003AD0FB /* TokenKinds.def in CopyFiles */,
+ DED7D7480A524295003AD0FB /* TokenKinds.h in CopyFiles */,
+ DED7D74A0A524295003AD0FB /* Lexer.h in CopyFiles */,
+ DED7D74D0A524295003AD0FB /* MacroInfo.h in CopyFiles */,
+ DED7D74E0A524295003AD0FB /* Pragma.h in CopyFiles */,
+ DED7D74F0A524295003AD0FB /* Preprocessor.h in CopyFiles */,
+ DED7D7D80A524302003AD0FB /* README.txt in CopyFiles */,
+ DED7D9180A52518C003AD0FB /* ScratchBuffer.h in CopyFiles */,
+ DEAEE98B0A5A2B970045101B /* MultipleIncludeOpt.h in CopyFiles */,
+ DEAEED4B0A5AF89A0045101B /* NOTES.txt in CopyFiles */,
+ DE1F22030A7D852A00FBF588 /* Parser.h in CopyFiles */,
+ DE06B73E0A8307640050E87E /* LangOptions.h in CopyFiles */,
+ DE06BECB0A854E4B0050E87E /* Scope.h in CopyFiles */,
+ DE06E8140A8FF9330050E87E /* Action.h in CopyFiles */,
+ DEC8D9910A9433CD00353FCA /* Decl.h in CopyFiles */,
+ DEC8D9A40A94346E00353FCA /* AST.h in CopyFiles */,
+ DE0FCA630A95859D00248FD5 /* Expr.h in CopyFiles */,
+ DE46BF280AE0A82D00CC047C /* TargetInfo.h in CopyFiles */,
+ DE344AB80AE5DF6D00DBC861 /* HeaderSearch.h in CopyFiles */,
+ DE3450D70AEB543100DBC861 /* DirectoryLookup.h in CopyFiles */,
+ DE3452810AEF1B1800DBC861 /* Stmt.h in CopyFiles */,
+ DE345C1A0AFC658B00DBC861 /* StmtVisitor.h in CopyFiles */,
+ DE345F220AFD347900DBC861 /* StmtNodes.def in CopyFiles */,
+ DE3464220B03040900DBC861 /* Type.h in CopyFiles */,
+ DE75ED290B044DC90020CF81 /* ASTContext.h in CopyFiles */,
+ DE1733700B068DC60080B521 /* DeclSpec.h in CopyFiles */,
+ DE01DA490B12ADA300AC22CE /* PPCallbacks.h in CopyFiles */,
+ DED676D10B6C786700AAD4A3 /* Builtins.def in CopyFiles */,
+ DED676FA0B6C797B00AAD4A3 /* Builtins.h in CopyFiles */,
+ 1A30A9E90B93A4C800201A91 /* ExprCXX.h in CopyFiles */,
+ 1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */,
+ DE67E7150C020EDF00F66BC5 /* Sema.h in CopyFiles */,
+ DE67E7280C02109800F66BC5 /* ParseAST.h in CopyFiles */,
+ DE928B200C0565B000231DA4 /* ModuleBuilder.h in CopyFiles */,
+ DE928B7D0C0A615100231DA4 /* CodeGenModule.h in CopyFiles */,
+ DE928B810C0A615B00231DA4 /* CodeGenFunction.h in CopyFiles */,
+ DEEBBD440C19C5D200A9FE82 /* TODO.txt in CopyFiles */,
+ 84D9A88C0C1A581300AC7ABC /* AttributeList.h in CopyFiles */,
+ DEEBC3BA0C2363B800A9FE82 /* CodeGenTypes.h in CopyFiles */,
+ DE6951C70C4D1F5D00A5826B /* RecordLayout.h in CopyFiles */,
+ DE6954640C5121BD00A5826B /* Token.h in CopyFiles */,
+ DEF2E95F0C5FBD74000C4259 /* InternalsManual.html in CopyFiles */,
+ DEC63B1C0C7B940600DBF169 /* CFG.h in CopyFiles */,
+ DEF7D9F70C9C8B1A0001F598 /* Rewriter.h in CopyFiles */,
+ 84AF36A10CB17A3B00C820A5 /* DeclObjC.h in CopyFiles */,
+ DE3986F00CB8D4B300223765 /* IdentifierTable.h in CopyFiles */,
+ );
+ 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; };
+ 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; };
+ 1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AnalysisConsumer.cpp; path = lib/Frontend/AnalysisConsumer.cpp; sourceTree = "<group>"; };
+ 1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumers.cpp; path = lib/Frontend/ASTConsumers.cpp; sourceTree = "<group>"; };
+ 1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Backend.cpp; path = lib/Frontend/Backend.cpp; sourceTree = "<group>"; };
+ 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>"; };
+ 1A2A54AB0FD1DD1C00F4CE45 /* GeneratePCH.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GeneratePCH.cpp; path = lib/Frontend/GeneratePCH.cpp; sourceTree = "<group>"; };
+ 1A2A54AC0FD1DD1C00F4CE45 /* HTMLPrint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLPrint.cpp; path = lib/Frontend/HTMLPrint.cpp; sourceTree = "<group>"; };
+ 1A2A54AD0FD1DD1C00F4CE45 /* PrintParserCallbacks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PrintParserCallbacks.cpp; path = lib/Frontend/PrintParserCallbacks.cpp; sourceTree = "<group>"; };
+ 1A2A54AE0FD1DD1C00F4CE45 /* PrintPreprocessedOutput.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PrintPreprocessedOutput.cpp; path = lib/Frontend/PrintPreprocessedOutput.cpp; sourceTree = "<group>"; };
+ 1A2A54AF0FD1DD1C00F4CE45 /* RewriteBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteBlocks.cpp; path = lib/Frontend/RewriteBlocks.cpp; sourceTree = "<group>"; };
+ 1A2A54B00FD1DD1C00F4CE45 /* RewriteMacros.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteMacros.cpp; path = lib/Frontend/RewriteMacros.cpp; sourceTree = "<group>"; };
+ 1A2A54B10FD1DD1C00F4CE45 /* RewriteObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteObjC.cpp; path = lib/Frontend/RewriteObjC.cpp; sourceTree = "<group>"; };
+ 1A2A54B20FD1DD1C00F4CE45 /* RewriteTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteTest.cpp; path = lib/Frontend/RewriteTest.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; };
+ 1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ExprConstant.cpp; path = lib/AST/ExprConstant.cpp; 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; };
+ 1A410F840FBCE51100351440 /* SemaTemplateInstantiateExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateExpr.cpp; path = lib/Sema/SemaTemplateInstantiateExpr.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 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; };
+ 1A5119C30FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateStmt.cpp; path = lib/Sema/SemaTemplateInstantiateStmt.cpp; sourceTree = "<group>"; };
+ 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; };
+ 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; lastKnownFileType = sourcecode.c.h; name = CGCXX.h; path = lib/CodeGen/CGCXX.h; sourceTree = "<group>"; };
+ 1A68BC110D0CADDD001A28C8 /* PPCBuiltins.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = PPCBuiltins.def; path = clang/AST/PPCBuiltins.def; sourceTree = "<group>"; tabWidth = 2; };
+ 1A68BC120D0CADDD001A28C8 /* TargetBuiltins.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TargetBuiltins.h; path = clang/AST/TargetBuiltins.h; sourceTree = "<group>"; tabWidth = 2; };
+ 1A68BC130D0CADDD001A28C8 /* X86Builtins.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = X86Builtins.def; path = clang/AST/X86Builtins.def; 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; };
+ 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>"; };
+ 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; };
+ 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; };
+ 1AFEF4050F8A6B2300476F2B /* clang-cc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = "clang-cc.cpp"; path = "tools/clang-cc/clang-cc.cpp"; sourceTree = "<group>"; tabWidth = 2; };
+ 3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckObjCInstMethSignature.cpp; path = lib/Analysis/CheckObjCInstMethSignature.cpp; sourceTree = "<group>"; };
+ 352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLDiagnostics.cpp; path = lib/Frontend/HTMLDiagnostics.cpp; sourceTree = "<group>"; };
+ 352246E20F5C6BE000D0D279 /* InitHeaderSearch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InitHeaderSearch.cpp; path = lib/Frontend/InitHeaderSearch.cpp; sourceTree = "<group>"; };
+ 352246E30F5C6BE000D0D279 /* ManagerRegistry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ManagerRegistry.cpp; path = lib/Frontend/ManagerRegistry.cpp; sourceTree = "<group>"; };
+ 352246E40F5C6BE000D0D279 /* PlistDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlistDiagnostics.cpp; path = lib/Frontend/PlistDiagnostics.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>"; };
+ 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ExprCXX.cpp; path = lib/AST/ExprCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 3527124F0DAFE54700C76352 /* IdentifierResolver.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = IdentifierResolver.h; path = lib/Sema/IdentifierResolver.h; sourceTree = "<group>"; tabWidth = 2; };
+ 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; };
+ 3536456A0E23EBF7009C6509 /* Environment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Environment.cpp; path = lib/Analysis/Environment.cpp; sourceTree = "<group>"; };
+ 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; };
+ 3538FDB70ED24A4E005EC283 /* DeclarationName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclarationName.cpp; path = lib/AST/DeclarationName.cpp; sourceTree = "<group>"; };
+ 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; };
+ 355106850E9A8507006A4E44 /* MemRegion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MemRegion.cpp; path = lib/Analysis/MemRegion.cpp; sourceTree = "<group>"; };
+ 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; };
+ 3551068E0E9A855F006A4E44 /* AccessSpecifier.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = AccessSpecifier.h; path = clang/Parse/AccessSpecifier.h; 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>"; };
+ 35544B850F5C7FD700D92AA9 /* RangeConstraintManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RangeConstraintManager.cpp; path = lib/Analysis/RangeConstraintManager.cpp; sourceTree = "<group>"; };
+ 35544B860F5C7FD700D92AA9 /* SimpleConstraintManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SimpleConstraintManager.cpp; path = lib/Analysis/SimpleConstraintManager.cpp; sourceTree = "<group>"; };
+ 35544B870F5C7FD700D92AA9 /* SimpleConstraintManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SimpleConstraintManager.h; path = lib/Analysis/SimpleConstraintManager.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; };
+ 3557D1A80EB136B100C59739 /* InheritViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = InheritViz.cpp; path = lib/AST/InheritViz.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 3557D1EF0EB13BB700C59739 /* SemaInherit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaInherit.cpp; path = lib/Sema/SemaInherit.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 35585DBD0EAFBC4500D0A97A /* CXXFieldCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CXXFieldCollector.h; path = lib/Sema/CXXFieldCollector.h; 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; };
+ 35585DBF0EAFBC4500D0A97A /* SemaOverload.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SemaOverload.h; path = lib/Sema/SemaOverload.h; sourceTree = "<group>"; tabWidth = 2; };
+ 3558F76C0E267C8300A5B0DF /* BasicStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BasicStore.cpp; path = lib/Analysis/BasicStore.cpp; sourceTree = "<group>"; };
+ 3558F76F0E267C9A00A5B0DF /* Store.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Store.h; path = clang/Analysis/PathSensitive/Store.h; sourceTree = "<group>"; };
+ 355CF6820C90A8B600A08AA3 /* LocalCheckers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LocalCheckers.h; path = clang/Analysis/LocalCheckers.h; sourceTree = "<group>"; };
+ 356B89760D9BFDC100CBEBE9 /* BasicObjCFoundationChecks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BasicObjCFoundationChecks.h; path = lib/Analysis/BasicObjCFoundationChecks.h; sourceTree = "<group>"; };
+ 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LiveVariables.cpp; path = lib/Analysis/LiveVariables.cpp; 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; };
+ 35847BE40CC7DBAF00C40FFF /* StmtIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtIterator.cpp; path = lib/AST/StmtIterator.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 35862B0C0E3628CB0009F542 /* CheckDeadStores.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckDeadStores.cpp; path = lib/Analysis/CheckDeadStores.cpp; sourceTree = "<group>"; };
+ 35862B110E3629850009F542 /* GRExprEngineInternalChecks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRExprEngineInternalChecks.cpp; path = lib/Analysis/GRExprEngineInternalChecks.cpp; sourceTree = "<group>"; };
+ 358CFBB70E65AB04002A8E19 /* BasicConstraintManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BasicConstraintManager.cpp; path = lib/Analysis/BasicConstraintManager.cpp; sourceTree = "<group>"; };
+ 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; };
+ 358D230A0E8BEB9D0003DDCC /* DeclGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclGroup.cpp; path = lib/AST/DeclGroup.cpp; 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>"; };
+ 358F51510E529AA4007F2102 /* GRState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRState.cpp; path = lib/Analysis/GRState.cpp; 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>"; };
+ 359379090DA48ABA0043B19C /* BugReporter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BugReporter.cpp; path = lib/Analysis/BugReporter.cpp; sourceTree = "<group>"; };
+ 3595AFB70E1C8D62004CDF09 /* CheckObjCDealloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckObjCDealloc.cpp; path = lib/Analysis/CheckObjCDealloc.cpp; 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>"; };
+ 35A057E00EAE2D950069249F /* RegionStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegionStore.cpp; path = lib/Analysis/RegionStore.cpp; sourceTree = "<group>"; };
+ 35A057E10EAE2D950069249F /* SVals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SVals.cpp; path = lib/Analysis/SVals.cpp; 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; lastKnownFileType = sourcecode.c.h; name = ProgramPoint.h; path = clang/Analysis/ProgramPoint.h; sourceTree = "<group>"; };
+ 35A8FCF70D9B4ADD001C2F97 /* PathDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PathDiagnostic.h; path = clang/Analysis/PathDiagnostic.h; sourceTree = "<group>"; };
+ 35A8FCF80D9B4B29001C2F97 /* PathDiagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PathDiagnostic.cpp; path = lib/Analysis/PathDiagnostic.cpp; sourceTree = "<group>"; };
+ 35B820740ECB811A0020BEC0 /* PreprocessorLexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreprocessorLexer.h; sourceTree = "<group>"; };
+ 35BAC1E70E82C5B7003FB76F /* CheckNSError.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckNSError.cpp; path = lib/Analysis/CheckNSError.cpp; sourceTree = "<group>"; };
+ 35BB2D7E0D19954000944DB5 /* ASTConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumer.cpp; path = lib/AST/ASTConsumer.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 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; };
+ 35CFFDFF0CA1CBCB00E6F2BE /* StmtViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtViz.cpp; path = lib/AST/StmtViz.cpp; 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>"; };
+ 35D55B240D81D8C60092E734 /* BasicValueFactory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BasicValueFactory.cpp; path = lib/Analysis/BasicValueFactory.cpp; sourceTree = "<group>"; };
+ 35D55B250D81D8C60092E734 /* CFRefCount.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CFRefCount.cpp; path = lib/Analysis/CFRefCount.cpp; 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 /* SemaNamedCast.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaNamedCast.cpp; path = lib/Sema/SemaNamedCast.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; };
+ 35EE48AF0E0C4CCA00715C54 /* DeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclCXX.cpp; path = lib/AST/DeclCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 35EE48B00E0C4CCA00715C54 /* ParentMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParentMap.cpp; path = lib/AST/ParentMap.cpp; 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; };
+ 35EFEFB50DB67ED60020783D /* GRTransferFuncs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRTransferFuncs.cpp; path = lib/Analysis/GRTransferFuncs.cpp; sourceTree = "<group>"; };
+ 35F1ACE60E66166C001F4532 /* ConstraintManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConstraintManager.h; path = clang/Analysis/PathSensitive/ConstraintManager.h; sourceTree = "<group>"; };
+ 35F2A01D0E36AFF100D17527 /* CheckObjCUnusedIVars.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckObjCUnusedIVars.cpp; path = lib/Analysis/CheckObjCUnusedIVars.cpp; 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>"; };
+ 35F8D0D50D9B82CD00D91C5E /* BasicObjCFoundationChecks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BasicObjCFoundationChecks.cpp; path = lib/Analysis/BasicObjCFoundationChecks.cpp; 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>"; };
+ 35FE6BCE0DF6EE1F00739712 /* DeclBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclBase.cpp; path = lib/AST/DeclBase.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 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; };
+ 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = lib/Parse/AttributeList.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 84D9A88B0C1A581300AC7ABC /* AttributeList.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = AttributeList.h; path = clang/Parse/AttributeList.h; sourceTree = "<group>"; tabWidth = 2; };
+ 8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = clang; sourceTree = BUILT_PRODUCTS_DIR; };
+ 9063F2210F9E8BDF002F7251 /* ExternalSemaSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExternalSemaSource.h; path = clang/Sema/ExternalSemaSource.h; sourceTree = "<group>"; };
+ 9063F2220F9E8BDF002F7251 /* SemaConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaConsumer.h; path = clang/Sema/SemaConsumer.h; sourceTree = "<group>"; };
+ 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>"; };
+ 90FB99DE0F98FB1D008F9415 /* DeclContextInternals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclContextInternals.h; path = clang/AST/DeclContextInternals.h; sourceTree = "<group>"; };
+ 90FB99DF0F98FB1D008F9415 /* DeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclVisitor.h; path = clang/AST/DeclVisitor.h; sourceTree = "<group>"; };
+ 90FB99E00F98FB1D008F9415 /* ExternalASTSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExternalASTSource.h; path = clang/AST/ExternalASTSource.h; 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; };
+ DE06BECA0A854E4B0050E87E /* Scope.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Scope.h; path = clang/Parse/Scope.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; };
+ DE06E8130A8FF9330050E87E /* Action.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Action.h; path = clang/Parse/Action.h; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
+ 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; };
+ DE0FCB330A9C21F100248FD5 /* Expr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Expr.cpp; path = lib/AST/Expr.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ DE1263C20EF2341900F56D2B /* Ownership.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Ownership.h; path = clang/Parse/Ownership.h; sourceTree = "<group>"; tabWidth = 2; };
+ DE1732FF0B068B700080B521 /* ASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ASTContext.cpp; path = lib/AST/ASTContext.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ DE17336D0B068DC20080B521 /* DeclSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclSpec.cpp; path = lib/Parse/DeclSpec.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ DE17336F0B068DC60080B521 /* DeclSpec.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclSpec.h; path = clang/Parse/DeclSpec.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>"; };
+ DE3452400AEF1A2D00DBC861 /* Stmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Stmt.cpp; path = lib/AST/Stmt.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 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; };
+ DE345F210AFD347900DBC861 /* StmtNodes.def */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = text; name = StmtNodes.def; path = clang/AST/StmtNodes.def; 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; };
+ DE3461260AFE68BE00DBC861 /* MinimalAction.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = MinimalAction.cpp; path = lib/Parse/MinimalAction.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtPrinter.cpp; path = lib/AST/StmtPrinter.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; };
+ 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; };
+ DE38CF260D8C9E6C00A273B6 /* DeclObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclObjC.cpp; path = lib/AST/DeclObjC.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; };
+ DE3B90DE0EAC5EF200D01046 /* ExtensionRAIIObject.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExtensionRAIIObject.h; path = lib/Parse/ExtensionRAIIObject.h; sourceTree = "<group>"; tabWidth = 2; };
+ DE3B921C0EB1A81400D01046 /* SemaInherit.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SemaInherit.h; path = lib/Sema/SemaInherit.h; sourceTree = "<group>"; tabWidth = 2; };
+ DE3B92230EB5152000D01046 /* Designator.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Designator.h; path = clang/Parse/Designator.h; 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>"; };
+ DE4121270D7F1C1C0080F80A /* SymbolManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SymbolManager.cpp; path = lib/Analysis/SymbolManager.cpp; sourceTree = "<group>"; };
+ DE4121280D7F1C1C0080F80A /* ExplodedGraph.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExplodedGraph.cpp; path = lib/Analysis/ExplodedGraph.cpp; sourceTree = "<group>"; };
+ DE4121290D7F1C1C0080F80A /* UninitializedValues.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UninitializedValues.cpp; path = lib/Analysis/UninitializedValues.cpp; sourceTree = "<group>"; };
+ DE41212A0D7F1C1C0080F80A /* GRCoreEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRCoreEngine.cpp; path = lib/Analysis/GRCoreEngine.cpp; sourceTree = "<group>"; };
+ DE41212C0D7F1C1C0080F80A /* GRSimpleVals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRSimpleVals.h; path = lib/Analysis/GRSimpleVals.h; sourceTree = "<group>"; };
+ DE41212F0D7F1C1C0080F80A /* GRSimpleVals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRSimpleVals.cpp; path = lib/Analysis/GRSimpleVals.cpp; sourceTree = "<group>"; };
+ DE4121300D7F1C1C0080F80A /* GRBlockCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRBlockCounter.cpp; path = lib/Analysis/GRBlockCounter.cpp; sourceTree = "<group>"; };
+ DE4121310D7F1C1C0080F80A /* GRExprEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRExprEngine.cpp; path = lib/Analysis/GRExprEngine.cpp; 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; };
+ DE67E70A0C020EC500F66BC5 /* SemaType.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaType.cpp; path = lib/Sema/SemaType.cpp; 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; };
+ DE67E7140C020EDF00F66BC5 /* Sema.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Sema.h; path = lib/Sema/Sema.h; sourceTree = "<group>"; tabWidth = 2; };
+ 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; };
+ DE67E7190C020F4F00F66BC5 /* ParseAST.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseAST.cpp; path = lib/Sema/ParseAST.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ DE67E7270C02109800F66BC5 /* ParseAST.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ParseAST.h; path = clang/Sema/ParseAST.h; sourceTree = "<group>"; };
+ 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; };
+ DE75EDF00B06880E0020CF81 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Type.cpp; path = lib/AST/Type.cpp; 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; };
+ DE8823CA0ED0046600CBC30A /* APValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = APValue.cpp; path = lib/AST/APValue.cpp; sourceTree = "<group>"; };
+ 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; };
+ DEA09A890F3175D9000C2258 /* SemaDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaDiagnostic.h; path = clang/Sema/SemaDiagnostic.h; sourceTree = "<group>"; };
+ 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; };
+ DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclTemplate.cpp; path = lib/AST/DeclTemplate.cpp; sourceTree = "<group>"; };
+ 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>"; };
+ DEC63B190C7B940200DBF169 /* CFG.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CFG.cpp; path = lib/AST/CFG.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ DEC63B1B0C7B940600DBF169 /* CFG.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CFG.h; path = clang/AST/CFG.h; sourceTree = "<group>"; tabWidth = 2; };
+ 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; lastKnownFileType = sourcecode.cpp.cpp; name = JumpDiagnostics.cpp; path = lib/Sema/JumpDiagnostics.cpp; sourceTree = "<group>"; };
+ DECB6F030F9D939A00F5FBC7 /* InitPreprocessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InitPreprocessor.h; path = clang/Frontend/InitPreprocessor.h; sourceTree = "<group>"; };
+ 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; lastKnownFileType = sourcecode.c.h; name = StmtObjC.h; path = clang/AST/StmtObjC.h; sourceTree = "<group>"; };
+ DECB73550FA3EE5A00F5FBC7 /* StmtCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StmtCXX.h; path = clang/AST/StmtCXX.h; sourceTree = "<group>"; };
+ DECB77120FA5752300F5FBC7 /* PCHReaderStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PCHReaderStmt.cpp; path = lib/Frontend/PCHReaderStmt.cpp; sourceTree = "<group>"; };
+ DECB77780FA579B000F5FBC7 /* PCHReaderDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PCHReaderDecl.cpp; path = lib/Frontend/PCHReaderDecl.cpp; sourceTree = "<group>"; };
+ DECB77F60FA5850200F5FBC7 /* PCHWriterDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PCHWriterDecl.cpp; path = lib/Frontend/PCHWriterDecl.cpp; sourceTree = "<group>"; };
+ DECB78160FA5882F00F5FBC7 /* PCHWriterStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PCHWriterStmt.cpp; path = lib/Frontend/PCHWriterStmt.cpp; sourceTree = "<group>"; };
+ DECB78540FA58F5500F5FBC7 /* AccessSpecifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AccessSpecifier.h; path = clang/Parse/AccessSpecifier.h; sourceTree = "<group>"; };
+ DED626C80AE0C065001E80A4 /* TargetInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TargetInfo.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Decl.cpp; path = lib/AST/Decl.cpp; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
+ DED676D00B6C786700AAD4A3 /* Builtins.def */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = text; name = Builtins.def; path = clang/AST/Builtins.def; sourceTree = "<group>"; tabWidth = 2; };
+ DED676F90B6C797B00AAD4A3 /* Builtins.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Builtins.h; path = clang/AST/Builtins.h; sourceTree = "<group>"; tabWidth = 2; };
+ DED677C80B6C854100AAD4A3 /* Builtins.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Builtins.cpp; path = lib/AST/Builtins.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>"; };
+ DEDFE5270F63A9230035BD10 /* DeclNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = DeclNodes.def; path = clang/AST/DeclNodes.def; sourceTree = "<group>"; tabWidth = 2; };
+ DEDFE5CB0F7206CC0035BD10 /* NestedNameSpecifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NestedNameSpecifier.h; path = clang/AST/NestedNameSpecifier.h; sourceTree = "<group>"; };
+ DEDFE5CE0F7206E40035BD10 /* NestedNameSpecifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NestedNameSpecifier.cpp; path = lib/AST/NestedNameSpecifier.cpp; sourceTree = "<group>"; };
+ 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; lastKnownFileType = sourcecode.cpp.cpp; name = Types.cpp; path = lib/Driver/Types.cpp; sourceTree = "<group>"; };
+ DEDFE6490F7B3B830035BD10 /* Tools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Tools.h; path = lib/Driver/Tools.h; sourceTree = "<group>"; };
+ DEDFE64A0F7B3B830035BD10 /* Tools.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Tools.cpp; path = lib/Driver/Tools.cpp; sourceTree = "<group>"; };
+ DEDFE64B0F7B3B830035BD10 /* ToolChains.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ToolChains.h; path = lib/Driver/ToolChains.h; sourceTree = "<group>"; };
+ DEDFE64C0F7B3B830035BD10 /* Compilation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Compilation.cpp; path = lib/Driver/Compilation.cpp; sourceTree = "<group>"; };
+ DEDFE64D0F7B3B830035BD10 /* ArgList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ArgList.cpp; path = lib/Driver/ArgList.cpp; sourceTree = "<group>"; };
+ DEDFE64E0F7B3B830035BD10 /* Arg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Arg.cpp; path = lib/Driver/Arg.cpp; sourceTree = "<group>"; };
+ DEDFE64F0F7B3B830035BD10 /* Action.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Action.cpp; path = lib/Driver/Action.cpp; sourceTree = "<group>"; };
+ DEDFE6500F7B3B830035BD10 /* Phases.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Phases.cpp; path = lib/Driver/Phases.cpp; sourceTree = "<group>"; };
+ DEDFE6510F7B3B830035BD10 /* OptTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OptTable.cpp; path = lib/Driver/OptTable.cpp; sourceTree = "<group>"; };
+ DEDFE6520F7B3B830035BD10 /* Option.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Option.cpp; path = lib/Driver/Option.cpp; sourceTree = "<group>"; };
+ DEDFE6530F7B3B830035BD10 /* Job.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Job.cpp; path = lib/Driver/Job.cpp; sourceTree = "<group>"; };
+ DEDFE6540F7B3B830035BD10 /* InputInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InputInfo.h; path = lib/Driver/InputInfo.h; sourceTree = "<group>"; };
+ DEDFE6550F7B3B830035BD10 /* ToolChains.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ToolChains.cpp; path = lib/Driver/ToolChains.cpp; sourceTree = "<group>"; };
+ DEDFE6560F7B3B830035BD10 /* ToolChain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ToolChain.cpp; path = lib/Driver/ToolChain.cpp; sourceTree = "<group>"; };
+ DEDFE6570F7B3B830035BD10 /* Tool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Tool.cpp; path = lib/Driver/Tool.cpp; sourceTree = "<group>"; };
+ DEDFE6580F7B3B830035BD10 /* HostInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HostInfo.cpp; path = lib/Driver/HostInfo.cpp; sourceTree = "<group>"; };
+ DEDFE6590F7B3B830035BD10 /* Driver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Driver.cpp; path = lib/Driver/Driver.cpp; sourceTree = "<group>"; };
+ DEDFF87F0F848CE30035BD10 /* TemplateName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemplateName.h; path = clang/AST/TemplateName.h; sourceTree = "<group>"; };
+ DEDFF8870F848CF80035BD10 /* TemplateName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TemplateName.cpp; path = lib/AST/TemplateName.cpp; sourceTree = "<group>"; };
+ 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; };
+ DEF1615E0F65C81C0098507F /* InitHeaderSearch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InitHeaderSearch.h; path = clang/Frontend/InitHeaderSearch.h; sourceTree = "<group>"; };
+ DEF1615F0F65C81C0098507F /* ManagerRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ManagerRegistry.h; path = clang/Frontend/ManagerRegistry.h; sourceTree = "<group>"; };
+ DEF161600F65C81C0098507F /* TextDiagnosticBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TextDiagnosticBuffer.h; path = clang/Frontend/TextDiagnosticBuffer.h; sourceTree = "<group>"; };
+ DEF161610F65C81C0098507F /* PathDiagnosticClients.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PathDiagnosticClients.h; path = clang/Frontend/PathDiagnosticClients.h; sourceTree = "<group>"; };
+ DEF161620F65C81C0098507F /* CompileOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CompileOptions.h; path = clang/Frontend/CompileOptions.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>"; };
+ DEF165180F8D46980098507F /* Options.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Options.def; path = clang/Driver/Options.def; 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>"; };
+ DEF165700F8FB34D0098507F /* PCHWriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PCHWriter.cpp; path = lib/Frontend/PCHWriter.cpp; sourceTree = "<group>"; };
+ DEF165740F8FB3510098507F /* PCHReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PCHReader.cpp; path = lib/Frontend/PCHReader.cpp; sourceTree = "<group>"; };
+ DEF165780F8FB3690098507F /* PCHWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PCHWriter.h; path = clang/Frontend/PCHWriter.h; sourceTree = "<group>"; };
+ DEF1657B0F8FB36E0098507F /* PCHReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PCHReader.h; path = clang/Frontend/PCHReader.h; sourceTree = "<group>"; };
+ DEF1657E0F8FB3730098507F /* PCHBitCodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PCHBitCodes.h; path = clang/Frontend/PCHBitCodes.h; sourceTree = "<group>"; };
+ DEF1683F0F9548DC0098507F /* FixItRewriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FixItRewriter.cpp; path = lib/Frontend/FixItRewriter.cpp; sourceTree = "<group>"; };
+ DEF168620F9549250098507F /* FixItRewriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FixItRewriter.h; path = clang/Frontend/FixItRewriter.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; lastKnownFileType = sourcecode.c.h; name = AnalysisDiagnostic.h; path = clang/Analysis/AnalysisDiagnostic.h; sourceTree = "<group>"; };
+ DEF16BE40FA13A5B0098507F /* TypeNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = TypeNodes.def; path = clang/AST/TypeNodes.def; sourceTree = "<group>"; };
+ DEF16BE50FA13A650098507F /* TypeOrdering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeOrdering.h; path = clang/AST/TypeOrdering.h; sourceTree = "<group>"; };
+ DEF2E95E0C5FBD74000C4259 /* InternalsManual.html */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.html; name = InternalsManual.html; path = docs/InternalsManual.html; sourceTree = "<group>"; };
+ DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtDumper.cpp; path = lib/AST/StmtDumper.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 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>"; };
+/* 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 = (
+ DED7D7500A5242C7003AD0FB /* Basic */,
+ DED7D78C0A5242E6003AD0FB /* Lex */,
+ DE1F22600A7D8C9B00FBF588 /* Parse */,
+ DEC8D9920A9433F400353FCA /* AST */,
+ DE67E7070C020EAB00F66BC5 /* Sema */,
+ DE927FCC0C0557CD00231DA4 /* CodeGen */,
+ 356EF9B30C8F7DCA006650F5 /* Analysis */,
+ DEF7D9F50C9C8B0C0001F598 /* Rewrite */,
+ 352246E00F5C6BC000D0D279 /* Frontend */,
+ DEDFE6470F7B3B560035BD10 /* Driver */,
+ );
+ name = Libraries;
+ sourceTree = "<group>";
+ };
+ 1AB674ADFE9D54B511CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8DD76F6C0486A84900D96B5E /* clang */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 3507E4C30E27FE3800FB7B57 /* Checks */ = {
+ isa = PBXGroup;
+ children = (
+ 35BAC1E70E82C5B7003FB76F /* CheckNSError.cpp */,
+ 356B89760D9BFDC100CBEBE9 /* BasicObjCFoundationChecks.h */,
+ 35F8D0D50D9B82CD00D91C5E /* BasicObjCFoundationChecks.cpp */,
+ 35862B0C0E3628CB0009F542 /* CheckDeadStores.cpp */,
+ 3595AFB70E1C8D62004CDF09 /* CheckObjCDealloc.cpp */,
+ 3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */,
+ 35F2A01D0E36AFF100D17527 /* CheckObjCUnusedIVars.cpp */,
+ DE4121290D7F1C1C0080F80A /* UninitializedValues.cpp */,
+ );
+ name = Checks;
+ sourceTree = "<group>";
+ };
+ 3507E4C60E27FE5500FB7B57 /* Core */ = {
+ isa = PBXGroup;
+ children = (
+ 35A057E10EAE2D950069249F /* SVals.cpp */,
+ 355106850E9A8507006A4E44 /* MemRegion.cpp */,
+ 35D55B240D81D8C60092E734 /* BasicValueFactory.cpp */,
+ 3536456A0E23EBF7009C6509 /* Environment.cpp */,
+ DE4121280D7F1C1C0080F80A /* ExplodedGraph.cpp */,
+ DE4121300D7F1C1C0080F80A /* GRBlockCounter.cpp */,
+ DE41212A0D7F1C1C0080F80A /* GRCoreEngine.cpp */,
+ DE4121310D7F1C1C0080F80A /* GRExprEngine.cpp */,
+ 35862B110E3629850009F542 /* GRExprEngineInternalChecks.cpp */,
+ 358F51510E529AA4007F2102 /* GRState.cpp */,
+ 35EFEFB50DB67ED60020783D /* GRTransferFuncs.cpp */,
+ DE4121270D7F1C1C0080F80A /* SymbolManager.cpp */,
+ );
+ name = Core;
+ sourceTree = "<group>";
+ };
+ 3507E4C90E27FE9000FB7B57 /* Bug Reporting */ = {
+ isa = PBXGroup;
+ children = (
+ 35A8FCF80D9B4B29001C2F97 /* PathDiagnostic.cpp */,
+ 359379090DA48ABA0043B19C /* BugReporter.cpp */,
+ );
+ name = "Bug Reporting";
+ sourceTree = "<group>";
+ };
+ 3507E4CC0E27FEB900FB7B57 /* Flow-Sensitive Analyses */ = {
+ isa = PBXGroup;
+ children = (
+ 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */,
+ );
+ name = "Flow-Sensitive Analyses";
+ sourceTree = "<group>";
+ };
+ 352246E00F5C6BC000D0D279 /* Frontend */ = {
+ isa = PBXGroup;
+ children = (
+ 1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */,
+ 1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */,
+ 1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */,
+ 1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */,
+ 1A2A54A80FD1DD1C00F4CE45 /* DependencyFile.cpp */,
+ 1A2A54A90FD1DD1C00F4CE45 /* DiagChecker.cpp */,
+ 1A2A54AA0FD1DD1C00F4CE45 /* DocumentXML.cpp */,
+ DEF1683F0F9548DC0098507F /* FixItRewriter.cpp */,
+ 1A2A54AB0FD1DD1C00F4CE45 /* GeneratePCH.cpp */,
+ 352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */,
+ 1A2A54AC0FD1DD1C00F4CE45 /* HTMLPrint.cpp */,
+ 352246E20F5C6BE000D0D279 /* InitHeaderSearch.cpp */,
+ DECB6F060F9D93A800F5FBC7 /* InitPreprocessor.cpp */,
+ 352246E30F5C6BE000D0D279 /* ManagerRegistry.cpp */,
+ DEF165740F8FB3510098507F /* PCHReader.cpp */,
+ DECB77780FA579B000F5FBC7 /* PCHReaderDecl.cpp */,
+ DECB77120FA5752300F5FBC7 /* PCHReaderStmt.cpp */,
+ DEF165700F8FB34D0098507F /* PCHWriter.cpp */,
+ DECB77F60FA5850200F5FBC7 /* PCHWriterDecl.cpp */,
+ DECB78160FA5882F00F5FBC7 /* PCHWriterStmt.cpp */,
+ 352246E40F5C6BE000D0D279 /* PlistDiagnostics.cpp */,
+ 1A2A54AD0FD1DD1C00F4CE45 /* PrintParserCallbacks.cpp */,
+ 1A2A54AE0FD1DD1C00F4CE45 /* PrintPreprocessedOutput.cpp */,
+ 352246E50F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp */,
+ 352246E60F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp */,
+ 1A2A54AF0FD1DD1C00F4CE45 /* RewriteBlocks.cpp */,
+ 1A2A54B00FD1DD1C00F4CE45 /* RewriteMacros.cpp */,
+ 1A2A54B10FD1DD1C00F4CE45 /* RewriteObjC.cpp */,
+ 1A2A54B20FD1DD1C00F4CE45 /* RewriteTest.cpp */,
+ 1A2A54B30FD1DD1C00F4CE45 /* StmtXML.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>";
+ };
+ 35544B820F5C7F6600D92AA9 /* StoreManagers */ = {
+ isa = PBXGroup;
+ children = (
+ 35A057E00EAE2D950069249F /* RegionStore.cpp */,
+ 3558F76C0E267C8300A5B0DF /* BasicStore.cpp */,
+ );
+ name = StoreManagers;
+ sourceTree = "<group>";
+ };
+ 35544B830F5C7F8900D92AA9 /* ConstraintManagers */ = {
+ isa = PBXGroup;
+ children = (
+ 35544B870F5C7FD700D92AA9 /* SimpleConstraintManager.h */,
+ 35544B860F5C7FD700D92AA9 /* SimpleConstraintManager.cpp */,
+ 358CFBB70E65AB04002A8E19 /* BasicConstraintManager.cpp */,
+ 35544B850F5C7FD700D92AA9 /* RangeConstraintManager.cpp */,
+ );
+ name = ConstraintManagers;
+ sourceTree = "<group>";
+ };
+ 35544B840F5C7F9D00D92AA9 /* Path-Sensitive */ = {
+ isa = PBXGroup;
+ children = (
+ 3507E4C60E27FE5500FB7B57 /* Core */,
+ 35544B820F5C7F6600D92AA9 /* StoreManagers */,
+ 35862B130E3629BC0009F542 /* Transfer Function Analyses */,
+ 35544B830F5C7F8900D92AA9 /* ConstraintManagers */,
+ );
+ name = "Path-Sensitive";
+ sourceTree = "<group>";
+ };
+ 356EF9AF0C8F7DA4006650F5 /* Analysis */ = {
+ isa = PBXGroup;
+ children = (
+ DEF1692C0F9645BF0098507F /* AnalysisDiagnostic.h */,
+ 35A8FCF60D9B4ADD001C2F97 /* ProgramPoint.h */,
+ 35A8FCF70D9B4ADD001C2F97 /* PathDiagnostic.h */,
+ 355CF6820C90A8B600A08AA3 /* LocalCheckers.h */,
+ 35F9B1540D1C6AFC00DDFDAE /* Analyses */,
+ 35D1DDCF0CA9C6BE0096E967 /* FlowSensitive */,
+ DE4121130D7F1B980080F80A /* PathSensitive */,
+ 35F9B1520D1C6ACB00DDFDAE /* Support */,
+ 352C19DB0CA321AC0045DB98 /* Visitors */,
+ );
+ name = Analysis;
+ sourceTree = "<group>";
+ };
+ 356EF9B30C8F7DCA006650F5 /* Analysis */ = {
+ isa = PBXGroup;
+ children = (
+ 35544B840F5C7F9D00D92AA9 /* Path-Sensitive */,
+ 3507E4CC0E27FEB900FB7B57 /* Flow-Sensitive Analyses */,
+ 3507E4C30E27FE3800FB7B57 /* Checks */,
+ 3507E4C90E27FE9000FB7B57 /* Bug Reporting */,
+ );
+ name = Analysis;
+ sourceTree = "<group>";
+ };
+ 35862B130E3629BC0009F542 /* Transfer Function Analyses */ = {
+ isa = PBXGroup;
+ children = (
+ 35D55B250D81D8C60092E734 /* CFRefCount.cpp */,
+ DE41212F0D7F1C1C0080F80A /* GRSimpleVals.cpp */,
+ DE41212C0D7F1C1C0080F80A /* GRSimpleVals.h */,
+ );
+ name = "Transfer Function Analyses";
+ 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>";
+ };
+ 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 = (
+ 3551068E0E9A855F006A4E44 /* AccessSpecifier.h */,
+ 84D9A88B0C1A581300AC7ABC /* AttributeList.h */,
+ DE06E8130A8FF9330050E87E /* Action.h */,
+ DE17336F0B068DC60080B521 /* DeclSpec.h */,
+ DE3B92230EB5152000D01046 /* Designator.h */,
+ DE1263C20EF2341900F56D2B /* Ownership.h */,
+ DEA09A860F3175CA000C2258 /* ParseDiagnostic.h */,
+ DE1F22020A7D852A00FBF588 /* Parser.h */,
+ DE06BECA0A854E4B0050E87E /* Scope.h */,
+ );
+ name = Parse;
+ sourceTree = "<group>";
+ };
+ DE1F22600A7D8C9B00FBF588 /* Parse */ = {
+ isa = PBXGroup;
+ children = (
+ 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */,
+ DE17336D0B068DC20080B521 /* DeclSpec.cpp */,
+ DE3B90DE0EAC5EF200D01046 /* ExtensionRAIIObject.h */,
+ DE3461260AFE68BE00DBC861 /* MinimalAction.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 */,
+ );
+ 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 = (
+ 35585DBD0EAFBC4500D0A97A /* CXXFieldCollector.h */,
+ 3527124F0DAFE54700C76352 /* IdentifierResolver.h */,
+ 352712500DAFE54700C76352 /* IdentifierResolver.cpp */,
+ DECB6D640F9AE26600F5FBC7 /* JumpDiagnostics.cpp */,
+ DE67E7190C020F4F00F66BC5 /* ParseAST.cpp */,
+ DE67E7140C020EDF00F66BC5 /* Sema.h */,
+ DE67E7160C020EE400F66BC5 /* Sema.cpp */,
+ 1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */,
+ DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */,
+ DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */,
+ 35E194670ECB82FB00F21733 /* SemaCXXScopeSpec.cpp */,
+ DE67E7120C020ED900F66BC5 /* SemaDecl.cpp */,
+ DE22BCF10E14197E0094DC60 /* SemaDeclAttr.cpp */,
+ 35EF676F0DAD1D2C00B19414 /* SemaDeclCXX.cpp */,
+ DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */,
+ DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */,
+ DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */,
+ DE47999B0D2EBE1A00706D2D /* SemaExprObjC.cpp */,
+ 3557D1EF0EB13BB700C59739 /* SemaInherit.cpp */,
+ DE3B921C0EB1A81400D01046 /* SemaInherit.h */,
+ 3599299A0DE2425300A8A33E /* SemaInit.cpp */,
+ 357EA27C0F2526F300439B60 /* SemaLookup.cpp */,
+ 35E194680ECB82FB00F21733 /* SemaNamedCast.cpp */,
+ 35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */,
+ 35585DBF0EAFBC4500D0A97A /* SemaOverload.h */,
+ DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */,
+ 3591853E0EFB1088000039AF /* SemaTemplate.cpp */,
+ 35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */,
+ 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */,
+ 1A410F840FBCE51100351440 /* SemaTemplateInstantiateExpr.cpp */,
+ 1A5119C30FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp */,
+ DE67E70A0C020EC500F66BC5 /* SemaType.cpp */,
+ );
+ name = Sema;
+ sourceTree = "<group>";
+ };
+ DE67E7260C02108300F66BC5 /* Sema */ = {
+ isa = PBXGroup;
+ children = (
+ 9063F2210F9E8BDF002F7251 /* ExternalSemaSource.h */,
+ 9063F2220F9E8BDF002F7251 /* SemaConsumer.h */,
+ DE67E7270C02109800F66BC5 /* ParseAST.h */,
+ DEA09A890F3175D9000C2258 /* SemaDiagnostic.h */,
+ );
+ name = Sema;
+ sourceTree = "<group>";
+ };
+ DE927FCC0C0557CD00231DA4 /* CodeGen */ = {
+ isa = PBXGroup;
+ children = (
+ 1A2193CB0F45EEB700C0713D /* ABIInfo.h */,
+ 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */,
+ 1A649E1D0F9599D9005B965E /* CGBlocks.h */,
+ DE8822350EC80C0A00CBC30A /* CGBuilder.h */,
+ 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */,
+ 35475B1F0E79973F0000BFE4 /* CGCall.cpp */,
+ 35475B220E7997680000BFE4 /* CGCall.h */,
+ 1A5D5E570E5E81010023C059 /* CGCXX.cpp */,
+ 1A649E1E0F9599DA005B965E /* CGCXX.h */,
+ 35A3E7000DD3874400757F74 /* CGDebugInfo.cpp */,
+ 35A3E7010DD3874400757F74 /* CGDebugInfo.h */,
+ DE4264FB0C113592005A861D /* CGDecl.cpp */,
+ DE4772FB0C10EAEC002239E8 /* CGExpr.cpp */,
+ DEF2EFF20C6CDD74000C4259 /* CGExprAgg.cpp */,
+ DE224FF70C7AA98800D370A5 /* CGExprComplex.cpp */,
+ 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */,
+ DE22526F0C7E82D000D370A5 /* CGExprScalar.cpp */,
+ 1A7342470C7B57D500122F56 /* CGObjC.cpp */,
+ DE38CD4E0D794CF900A273B6 /* CGObjCRuntime.h */,
+ DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */,
+ 3552E7580E520DD7003A8CA5 /* CGObjCMac.cpp */,
+ DE4772F90C10EAE5002239E8 /* CGStmt.cpp */,
+ 35475B230E7997680000BFE4 /* CGValue.h */,
+ DE928B800C0A615B00231DA4 /* CodeGenFunction.h */,
+ DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */,
+ DE928B7C0C0A615100231DA4 /* CodeGenModule.h */,
+ DE928B7E0C0A615600231DA4 /* CodeGenModule.cpp */,
+ DEEBC3BB0C2363BC00A9FE82 /* CodeGenTypes.cpp */,
+ DEEBC3B90C2363B800A9FE82 /* CodeGenTypes.h */,
+ 1A2193CC0F45EEB700C0713D /* Mangle.cpp */,
+ 1A2193CD0F45EEB700C0713D /* Mangle.h */,
+ DE928B120C05659200231DA4 /* ModuleBuilder.cpp */,
+ );
+ name = CodeGen;
+ sourceTree = "<group>";
+ };
+ DE928B140C05659A00231DA4 /* CodeGen */ = {
+ isa = PBXGroup;
+ children = (
+ DE928B1F0C0565B000231DA4 /* ModuleBuilder.h */,
+ );
+ name = CodeGen;
+ sourceTree = "<group>";
+ };
+ DEC8D98B0A9433BC00353FCA /* AST */ = {
+ isa = PBXGroup;
+ children = (
+ DECB78540FA58F5500F5FBC7 /* AccessSpecifier.h */,
+ DE613EF30E0E148D00B05B79 /* APValue.h */,
+ DEC8D9A30A94346E00353FCA /* AST.h */,
+ 35BFBD2B0C9EDE1E006CB644 /* ASTConsumer.h */,
+ DE75ED280B044DC90020CF81 /* ASTContext.h */,
+ DEA09A6E0F31756F000C2258 /* ASTDiagnostic.h */,
+ 1A72BEAC0D641E9400B085E9 /* Attr.h */,
+ DED676D00B6C786700AAD4A3 /* Builtins.def */,
+ DED676F90B6C797B00AAD4A3 /* Builtins.h */,
+ 90FB99DE0F98FB1D008F9415 /* DeclContextInternals.h */,
+ 90FB99DF0F98FB1D008F9415 /* DeclVisitor.h */,
+ 90FB99E00F98FB1D008F9415 /* ExternalASTSource.h */,
+ 1A68BC110D0CADDD001A28C8 /* PPCBuiltins.def */,
+ 1A68BC130D0CADDD001A28C8 /* X86Builtins.def */,
+ DEC63B1B0C7B940600DBF169 /* CFG.h */,
+ DEC8D9900A9433CD00353FCA /* Decl.h */,
+ 3538FDB60ED24A2C005EC283 /* DeclarationName.h */,
+ 035611470DA6A45C00D2EF2A /* DeclBase.h */,
+ 84AF36A00CB17A3B00C820A5 /* DeclObjC.h */,
+ 35EE48AD0E0C4CB200715C54 /* DeclCXX.h */,
+ 358D23090E8BEB850003DDCC /* DeclGroup.h */,
+ DEDFE5270F63A9230035BD10 /* DeclNodes.def */,
+ DEB076C90F3A221200F5A2BE /* DeclTemplate.h */,
+ DE0FCA620A95859D00248FD5 /* Expr.h */,
+ 1A30A9E80B93A4C800201A91 /* ExprCXX.h */,
+ 35CEA05A0DF9E82700A41296 /* ExprObjC.h */,
+ DEDFE5CB0F7206CC0035BD10 /* NestedNameSpecifier.h */,
+ 35EE48AE0E0C4CB200715C54 /* ParentMap.h */,
+ 3547129D0C88881300B3E1D5 /* PrettyPrinter.h */,
+ DE6951C60C4D1F5D00A5826B /* RecordLayout.h */,
+ DE3452800AEF1B1800DBC861 /* Stmt.h */,
+ DECB73550FA3EE5A00F5FBC7 /* StmtCXX.h */,
+ DE345F210AFD347900DBC861 /* StmtNodes.def */,
+ DECB734E0FA3ED8400F5FBC7 /* StmtObjC.h */,
+ DE345C190AFC658B00DBC861 /* StmtVisitor.h */,
+ 35847BE30CC7DB9000C40FFF /* StmtIterator.h */,
+ 35CFFE010CA1CBDD00E6F2BE /* StmtGraphTraits.h */,
+ 1A68BC120D0CADDD001A28C8 /* TargetBuiltins.h */,
+ DEDFF87F0F848CE30035BD10 /* TemplateName.h */,
+ DEF16BE40FA13A5B0098507F /* TypeNodes.def */,
+ DEF16BE50FA13A650098507F /* TypeOrdering.h */,
+ DE3464210B03040900DBC861 /* Type.h */,
+ );
+ name = AST;
+ sourceTree = "<group>";
+ };
+ DEC8D9920A9433F400353FCA /* AST */ = {
+ isa = PBXGroup;
+ children = (
+ DE8823CA0ED0046600CBC30A /* APValue.cpp */,
+ 35BB2D7E0D19954000944DB5 /* ASTConsumer.cpp */,
+ DE1732FF0B068B700080B521 /* ASTContext.cpp */,
+ DED677C80B6C854100AAD4A3 /* Builtins.cpp */,
+ DEC63B190C7B940200DBF169 /* CFG.cpp */,
+ 35FE6BCE0DF6EE1F00739712 /* DeclBase.cpp */,
+ DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */,
+ 3538FDB70ED24A4E005EC283 /* DeclarationName.cpp */,
+ 35EE48AF0E0C4CCA00715C54 /* DeclCXX.cpp */,
+ 358D230A0E8BEB9D0003DDCC /* DeclGroup.cpp */,
+ DE38CF260D8C9E6C00A273B6 /* DeclObjC.cpp */,
+ DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */,
+ DE0FCB330A9C21F100248FD5 /* Expr.cpp */,
+ 1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */,
+ 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */,
+ 3557D1A80EB136B100C59739 /* InheritViz.cpp */,
+ DEDFE5CE0F7206E40035BD10 /* NestedNameSpecifier.cpp */,
+ 35EE48B00E0C4CCA00715C54 /* ParentMap.cpp */,
+ DE3452400AEF1A2D00DBC861 /* Stmt.cpp */,
+ DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */,
+ DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */,
+ 35847BE40CC7DBAF00C40FFF /* StmtIterator.cpp */,
+ 35CFFDFF0CA1CBCB00E6F2BE /* StmtViz.cpp */,
+ DEDFF8870F848CF80035BD10 /* TemplateName.cpp */,
+ DE75EDF00B06880E0020CF81 /* Type.cpp */,
+ );
+ name = AST;
+ sourceTree = "<group>";
+ };
+ DED7D72E0A524295003AD0FB /* include */ = {
+ isa = PBXGroup;
+ children = (
+ DED7D7300A524295003AD0FB /* Basic */,
+ DED7D7390A524295003AD0FB /* Lex */,
+ DE1F21F20A7D84E800FBF588 /* Parse */,
+ DEC8D98B0A9433BC00353FCA /* AST */,
+ DE67E7260C02108300F66BC5 /* Sema */,
+ DE928B140C05659A00231DA4 /* CodeGen */,
+ 356EF9AF0C8F7DA4006650F5 /* Analysis */,
+ DEF7D9F40C9C8B020001F598 /* Rewrite */,
+ DEF1615D0F65C7FC0098507F /* Frontend */,
+ DEF165020F8D46810098507F /* Driver */,
+ );
+ path = include;
+ sourceTree = "<group>";
+ };
+ DED7D7300A524295003AD0FB /* Basic */ = {
+ isa = PBXGroup;
+ children = (
+ 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 */,
+ DEAABDF70F5F477C0098928A /* PrettyStackTrace.h */,
+ DED7D7350A524295003AD0FB /* SourceLocation.h */,
+ DED7D7360A524295003AD0FB /* SourceManager.h */,
+ 9063F2290F9E911F002F7251 /* SourceManagerInternals.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 = (
+ 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 = (
+ 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 = (
+ 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 = (
+ DEDFE6200F7B3AE90035BD10 /* clang-cc */,
+ DEDFE6210F7B3AF10035BD10 /* clang */,
+ );
+ name = Tools;
+ sourceTree = "<group>";
+ };
+ DEDFE6200F7B3AE90035BD10 /* clang-cc */ = {
+ isa = PBXGroup;
+ children = (
+ 1AFEF4050F8A6B2300476F2B /* clang-cc.cpp */,
+ );
+ name = "clang-cc";
+ sourceTree = "<group>";
+ };
+ DEDFE6210F7B3AF10035BD10 /* clang */ = {
+ isa = PBXGroup;
+ children = (
+ 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 = (
+ DEF161620F65C81C0098507F /* CompileOptions.h */,
+ DEF168620F9549250098507F /* FixItRewriter.h */,
+ DEF169220F9645960098507F /* FrontendDiagnostic.h */,
+ DEF1615E0F65C81C0098507F /* InitHeaderSearch.h */,
+ DECB6F030F9D939A00F5FBC7 /* InitPreprocessor.h */,
+ DEF1615F0F65C81C0098507F /* ManagerRegistry.h */,
+ DEF1657E0F8FB3730098507F /* PCHBitCodes.h */,
+ DEF1657B0F8FB36E0098507F /* PCHReader.h */,
+ DEF165780F8FB3690098507F /* PCHWriter.h */,
+ DEF161610F65C81C0098507F /* PathDiagnosticClients.h */,
+ DEF161600F65C81C0098507F /* TextDiagnosticBuffer.h */,
+ DEF161630F65C81C0098507F /* TextDiagnosticPrinter.h */,
+ );
+ name = Frontend;
+ sourceTree = "<group>";
+ };
+ DEF165020F8D46810098507F /* Driver */ = {
+ isa = PBXGroup;
+ children = (
+ DEF165160F8D46980098507F /* Action.h */,
+ DEF1651D0F8D46980098507F /* ArgList.h */,
+ DEF1651E0F8D46980098507F /* Arg.h */,
+ DEF165170F8D46980098507F /* Compilation.h */,
+ DEF165240F8D46980098507F /* DriverDiagnostic.h */,
+ DEF165200F8D46980098507F /* Driver.h */,
+ DEF1651F0F8D46980098507F /* HostInfo.h */,
+ DEF165210F8D46980098507F /* Job.h */,
+ DEF165180F8D46980098507F /* Options.def */,
+ DEF165190F8D46980098507F /* Option.h */,
+ DEF1651C0F8D46980098507F /* Options.h */,
+ 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 = (
+ 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 */,
+ DE4DC7A20EA1C33E00069E5A /* TokenRewriter.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";
+ hasScannedForEncodings = 1;
+ mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8DD76F620486A84900D96B5E /* clang */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 8DD76F640486A84900D96B5E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DED7D77A0A5242C7003AD0FB /* Diagnostic.cpp in Sources */,
+ DED7D77B0A5242C7003AD0FB /* FileManager.cpp in Sources */,
+ DED7D7890A5242C7003AD0FB /* SourceManager.cpp in Sources */,
+ DED7D78A0A5242C7003AD0FB /* TokenKinds.cpp in Sources */,
+ DED7D7C30A5242E6003AD0FB /* Lexer.cpp in Sources */,
+ DED7D7C50A5242E6003AD0FB /* MacroInfo.cpp in Sources */,
+ DED7D7C70A5242E6003AD0FB /* PPExpressions.cpp in Sources */,
+ DED7D7C80A5242E6003AD0FB /* Pragma.cpp in Sources */,
+ DED7D7C90A5242E6003AD0FB /* Preprocessor.cpp in Sources */,
+ DED7D9E50A5257F6003AD0FB /* ScratchBuffer.cpp in Sources */,
+ DE06D4310A8BB52D0050E87E /* Parser.cpp in Sources */,
+ DE0FCB340A9C21F100248FD5 /* Expr.cpp in Sources */,
+ DED626C90AE0C065001E80A4 /* TargetInfo.cpp in Sources */,
+ DED62ABB0AE2EDF1001E80A4 /* Decl.cpp in Sources */,
+ DE344B540AE5E46C00DBC861 /* HeaderSearch.cpp in Sources */,
+ DE3452410AEF1A2D00DBC861 /* Stmt.cpp in Sources */,
+ DE3460000AFDCC1900DBC861 /* ParseObjc.cpp in Sources */,
+ DE3460050AFDCC6500DBC861 /* ParseInit.cpp in Sources */,
+ DE34600B0AFDCCBF00DBC861 /* ParseStmt.cpp in Sources */,
+ DE34600F0AFDCCCE00DBC861 /* ParseDecl.cpp in Sources */,
+ DE3460130AFDCCDA00DBC861 /* ParseExpr.cpp in Sources */,
+ DE3461270AFE68BE00DBC861 /* MinimalAction.cpp in Sources */,
+ DE34621D0AFEB19B00DBC861 /* StmtPrinter.cpp in Sources */,
+ DE75EDF10B06880E0020CF81 /* Type.cpp in Sources */,
+ DE1733000B068B700080B521 /* ASTContext.cpp in Sources */,
+ DE17336E0B068DC20080B521 /* DeclSpec.cpp in Sources */,
+ DED677C90B6C854100AAD4A3 /* Builtins.cpp in Sources */,
+ 1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */,
+ DE67E70B0C020EC500F66BC5 /* SemaType.cpp in Sources */,
+ DE67E70D0C020ECA00F66BC5 /* SemaStmt.cpp in Sources */,
+ DE67E70F0C020ECF00F66BC5 /* SemaExprCXX.cpp in Sources */,
+ DE67E7110C020ED400F66BC5 /* SemaExpr.cpp in Sources */,
+ DE67E7130C020ED900F66BC5 /* SemaDecl.cpp in Sources */,
+ DE67E7170C020EE400F66BC5 /* Sema.cpp in Sources */,
+ DE67E71A0C020F4F00F66BC5 /* ParseAST.cpp in Sources */,
+ DE06756C0C051CFE00EBBFD8 /* ParseExprCXX.cpp in Sources */,
+ DE928B130C05659200231DA4 /* ModuleBuilder.cpp in Sources */,
+ DE928B7F0C0A615600231DA4 /* CodeGenModule.cpp in Sources */,
+ DE928B830C0A616000231DA4 /* CodeGenFunction.cpp in Sources */,
+ DE4772FA0C10EAE5002239E8 /* CGStmt.cpp in Sources */,
+ DE4772FC0C10EAEC002239E8 /* CGExpr.cpp in Sources */,
+ DE4264FC0C113592005A861D /* CGDecl.cpp in Sources */,
+ 84D9A8880C1A57E100AC7ABC /* AttributeList.cpp in Sources */,
+ DEEBC3BC0C2363BC00A9FE82 /* CodeGenTypes.cpp in Sources */,
+ DEF2EDA70C6A4252000C4259 /* StmtDumper.cpp in Sources */,
+ DEF2EFF30C6CDD74000C4259 /* CGExprAgg.cpp in Sources */,
+ DEF2F0100C6CFED5000C4259 /* SemaChecking.cpp in Sources */,
+ 1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */,
+ DE224FF80C7AA98800D370A5 /* CGExprComplex.cpp in Sources */,
+ 1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */,
+ DEC63B1A0C7B940200DBF169 /* CFG.cpp in Sources */,
+ DE2252700C7E82D000D370A5 /* CGExprScalar.cpp in Sources */,
+ 35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */,
+ DE2255FC0C8004E600D370A5 /* ParseDeclCXX.cpp in Sources */,
+ 356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */,
+ DEF7D9F90C9C8B1D0001F598 /* Rewriter.cpp in Sources */,
+ 35CFFE000CA1CBCB00E6F2BE /* StmtViz.cpp in Sources */,
+ DE3986F40CB8D50C00223765 /* IdentifierTable.cpp in Sources */,
+ 35847BE50CC7DBAF00C40FFF /* StmtIterator.cpp in Sources */,
+ 35707EFE0CD0F5CC000B2204 /* SourceLocation.cpp in Sources */,
+ DE704B260D0FBEBE009C7762 /* SemaDeclObjC.cpp in Sources */,
+ DE704DD20D1668A4009C7762 /* HeaderMap.cpp in Sources */,
+ 35BB2D7F0D19954000944DB5 /* ASTConsumer.cpp in Sources */,
+ DE47999C0D2EBE1A00706D2D /* SemaExprObjC.cpp in Sources */,
+ 03F50AC60D416EAA00B9CF60 /* Targets.cpp in Sources */,
+ 1A376A2D0D4AED9B002A1C52 /* CGExprConstant.cpp in Sources */,
+ DE38CD500D794D0100A273B6 /* CGObjCGNU.cpp in Sources */,
+ DE4121350D7F1C1C0080F80A /* SymbolManager.cpp in Sources */,
+ DE4121360D7F1C1C0080F80A /* ExplodedGraph.cpp in Sources */,
+ DE4121370D7F1C1C0080F80A /* UninitializedValues.cpp in Sources */,
+ DE4121380D7F1C1C0080F80A /* GRCoreEngine.cpp in Sources */,
+ DE41213C0D7F1C1C0080F80A /* GRSimpleVals.cpp in Sources */,
+ DE41213D0D7F1C1C0080F80A /* GRBlockCounter.cpp in Sources */,
+ DE41213E0D7F1C1C0080F80A /* GRExprEngine.cpp in Sources */,
+ 35D55B270D81D8C60092E734 /* BasicValueFactory.cpp in Sources */,
+ 35D55B280D81D8C60092E734 /* CFRefCount.cpp in Sources */,
+ DE85CD810D8380B10070E26E /* TokenLexer.cpp in Sources */,
+ DE85CDA30D8383B20070E26E /* MacroArgs.cpp in Sources */,
+ DE85CDAC0D838C120070E26E /* PPMacroExpansion.cpp in Sources */,
+ DE85CDB00D838C390070E26E /* PPDirectives.cpp in Sources */,
+ DE85CDB60D839BAE0070E26E /* PPLexerChange.cpp in Sources */,
+ DE38CF270D8C9E6C00A273B6 /* DeclObjC.cpp in Sources */,
+ 72D16C1F0D9975C400E6DA4A /* HTMLRewrite.cpp in Sources */,
+ 35A8FCF90D9B4B2A001C2F97 /* PathDiagnostic.cpp in Sources */,
+ 35F8D0D60D9B82CD00D91C5E /* BasicObjCFoundationChecks.cpp in Sources */,
+ 3593790A0DA48ABA0043B19C /* BugReporter.cpp in Sources */,
+ 35EF67700DAD1D2C00B19414 /* SemaDeclCXX.cpp in Sources */,
+ 352712510DAFE54700C76352 /* IdentifierResolver.cpp in Sources */,
+ DEFFECA70DB1546600B4E7C3 /* DeltaTree.cpp in Sources */,
+ DECAB0D00DB3C84200E13CCB /* RewriteRope.cpp in Sources */,
+ 35EFEFB60DB67ED60020783D /* GRTransferFuncs.cpp in Sources */,
+ 35A3E7020DD3874400757F74 /* CGDebugInfo.cpp in Sources */,
+ 3599299B0DE2425300A8A33E /* SemaInit.cpp in Sources */,
+ 35FE6BCF0DF6EE1F00739712 /* DeclBase.cpp in Sources */,
+ 35EE48B10E0C4CCA00715C54 /* DeclCXX.cpp in Sources */,
+ 35EE48B20E0C4CCA00715C54 /* ParentMap.cpp in Sources */,
+ 3534A01D0E129849002709B2 /* ParseCXXInlineMethods.cpp in Sources */,
+ DE22BCF20E14197E0094DC60 /* SemaDeclAttr.cpp in Sources */,
+ 1A32C17F0E1C87AD00A6B483 /* ExprConstant.cpp in Sources */,
+ 3595AFB80E1C8D62004CDF09 /* CheckObjCDealloc.cpp in Sources */,
+ 3536456B0E23EBF7009C6509 /* Environment.cpp in Sources */,
+ 3558F76D0E267C8300A5B0DF /* BasicStore.cpp in Sources */,
+ 3507E4C20E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp in Sources */,
+ 35862B0D0E3628CB0009F542 /* CheckDeadStores.cpp in Sources */,
+ 35862B120E3629850009F542 /* GRExprEngineInternalChecks.cpp in Sources */,
+ 35F2A01E0E36AFF100D17527 /* CheckObjCUnusedIVars.cpp in Sources */,
+ 3552E7550E520D80003A8CA5 /* PPCaching.cpp in Sources */,
+ 3552E7590E520DD7003A8CA5 /* CGObjCMac.cpp in Sources */,
+ 358F51520E529AA4007F2102 /* GRState.cpp in Sources */,
+ 1A5D5E580E5E81010023C059 /* CGCXX.cpp in Sources */,
+ 358CFBB80E65AB04002A8E19 /* BasicConstraintManager.cpp in Sources */,
+ 35475B200E79973F0000BFE4 /* CGCall.cpp in Sources */,
+ 35BAC1E80E82C5B7003FB76F /* CheckNSError.cpp in Sources */,
+ 358D230B0E8BEB9D0003DDCC /* DeclGroup.cpp in Sources */,
+ 355106860E9A8507006A4E44 /* MemRegion.cpp in Sources */,
+ 3551068C0E9A8546006A4E44 /* ParsePragma.cpp in Sources */,
+ 3551068D0E9A8546006A4E44 /* ParseTentative.cpp in Sources */,
+ DE4DC7A30EA1C33E00069E5A /* TokenRewriter.cpp in Sources */,
+ 35A057E20EAE2D950069249F /* RegionStore.cpp in Sources */,
+ 35A057E30EAE2D950069249F /* SVals.cpp in Sources */,
+ 35585DC00EAFBC4500D0A97A /* SemaOverload.cpp in Sources */,
+ 3557D1A90EB136B100C59739 /* InheritViz.cpp in Sources */,
+ 3557D1F00EB13BB700C59739 /* SemaInherit.cpp in Sources */,
+ 35E194690ECB82FB00F21733 /* SemaCXXScopeSpec.cpp in Sources */,
+ 35E1946A0ECB82FB00F21733 /* SemaNamedCast.cpp in Sources */,
+ 35E1946D0ECB83C100F21733 /* PTHLexer.cpp in Sources */,
+ 3537AA0E0ECD08A4008F7CDC /* PreprocessorLexer.cpp in Sources */,
+ DE8823CB0ED0046600CBC30A /* APValue.cpp in Sources */,
+ 3538FDB80ED24A4E005EC283 /* DeclarationName.cpp in Sources */,
+ 353959D50EE5F88A00E82461 /* ParseTemplate.cpp in Sources */,
+ 3591853F0EFB1088000039AF /* SemaTemplate.cpp in Sources */,
+ 357EA27D0F2526F300439B60 /* SemaLookup.cpp in Sources */,
+ DEB076CF0F3A222200F5A2BE /* DeclTemplate.cpp in Sources */,
+ 1A471AB50F437BC500753CE8 /* CGBlocks.cpp in Sources */,
+ DEB077990F44F97800F5A2BE /* TokenConcatenation.cpp in Sources */,
+ 1A2193CE0F45EEB700C0713D /* Mangle.cpp in Sources */,
+ DEB07AC80F4A427E00F5A2BE /* SemaAttr.cpp in Sources */,
+ 352246E70F5C6BE000D0D279 /* HTMLDiagnostics.cpp in Sources */,
+ 352246E80F5C6BE000D0D279 /* InitHeaderSearch.cpp in Sources */,
+ 352246E90F5C6BE000D0D279 /* ManagerRegistry.cpp in Sources */,
+ 352246EA0F5C6BE000D0D279 /* PlistDiagnostics.cpp in Sources */,
+ 352246EB0F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp in Sources */,
+ 352246EC0F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp in Sources */,
+ 35544B880F5C7FD700D92AA9 /* RangeConstraintManager.cpp in Sources */,
+ 35544B890F5C7FD700D92AA9 /* SimpleConstraintManager.cpp in Sources */,
+ 35544B8C0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp in Sources */,
+ DEDFE5CF0F7206E40035BD10 /* NestedNameSpecifier.cpp in Sources */,
+ 1ADF47AF0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp in Sources */,
+ DEDFE6460F7B3B4E0035BD10 /* driver.cpp in Sources */,
+ DEDFE65A0F7B3B830035BD10 /* Types.cpp in Sources */,
+ DEDFE65B0F7B3B830035BD10 /* Tools.cpp in Sources */,
+ DEDFE65C0F7B3B830035BD10 /* Compilation.cpp in Sources */,
+ DEDFE65D0F7B3B830035BD10 /* ArgList.cpp in Sources */,
+ DEDFE65E0F7B3B830035BD10 /* Arg.cpp in Sources */,
+ DEDFE65F0F7B3B830035BD10 /* Action.cpp in Sources */,
+ DEDFE6600F7B3B830035BD10 /* Phases.cpp in Sources */,
+ DEDFE6610F7B3B830035BD10 /* OptTable.cpp in Sources */,
+ DEDFE6620F7B3B830035BD10 /* Option.cpp in Sources */,
+ DEDFE6630F7B3B830035BD10 /* Job.cpp in Sources */,
+ DEDFE6640F7B3B830035BD10 /* ToolChains.cpp in Sources */,
+ DEDFE6650F7B3B830035BD10 /* ToolChain.cpp in Sources */,
+ DEDFE6660F7B3B830035BD10 /* Tool.cpp in Sources */,
+ DEDFE6670F7B3B830035BD10 /* HostInfo.cpp in Sources */,
+ DEDFE6680F7B3B830035BD10 /* Driver.cpp in Sources */,
+ 1A701B640F7C8FE400FEC4D1 /* SemaAccess.cpp in Sources */,
+ 906BF4B00F83BA2E001071FA /* ConvertUTF.c in Sources */,
+ DEDFF8880F848CF80035BD10 /* TemplateName.cpp in Sources */,
+ 1AFEF4070F8A6B2300476F2B /* clang-cc.cpp in Sources */,
+ DEF165710F8FB34D0098507F /* PCHWriter.cpp in Sources */,
+ DEF165750F8FB3510098507F /* PCHReader.cpp in Sources */,
+ DEF168400F9548DC0098507F /* FixItRewriter.cpp in Sources */,
+ DECB6D650F9AE26600F5FBC7 /* JumpDiagnostics.cpp in Sources */,
+ DECB6F070F9D93A800F5FBC7 /* InitPreprocessor.cpp in Sources */,
+ DECB77130FA5752300F5FBC7 /* PCHReaderStmt.cpp in Sources */,
+ DECB77790FA579B000F5FBC7 /* PCHReaderDecl.cpp in Sources */,
+ DECB77F70FA5850200F5FBC7 /* PCHWriterDecl.cpp in Sources */,
+ DECB78170FA5882F00F5FBC7 /* PCHWriterStmt.cpp in Sources */,
+ 1A410F850FBCE51100351440 /* SemaTemplateInstantiateExpr.cpp in Sources */,
+ 1A5119C40FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp in Sources */,
+ 1A2A54B50FD1DD1C00F4CE45 /* AnalysisConsumer.cpp in Sources */,
+ 1A2A54B60FD1DD1C00F4CE45 /* ASTConsumers.cpp in Sources */,
+ 1A2A54B70FD1DD1C00F4CE45 /* Backend.cpp in Sources */,
+ 1A2A54B80FD1DD1C00F4CE45 /* CacheTokens.cpp in Sources */,
+ 1A2A54B90FD1DD1C00F4CE45 /* DependencyFile.cpp in Sources */,
+ 1A2A54BA0FD1DD1C00F4CE45 /* DiagChecker.cpp in Sources */,
+ 1A2A54BB0FD1DD1C00F4CE45 /* DocumentXML.cpp in Sources */,
+ 1A2A54BC0FD1DD1C00F4CE45 /* GeneratePCH.cpp in Sources */,
+ 1A2A54BD0FD1DD1C00F4CE45 /* HTMLPrint.cpp in Sources */,
+ 1A2A54BE0FD1DD1C00F4CE45 /* PrintParserCallbacks.cpp in Sources */,
+ 1A2A54BF0FD1DD1C00F4CE45 /* PrintPreprocessedOutput.cpp in Sources */,
+ 1A2A54C00FD1DD1C00F4CE45 /* RewriteBlocks.cpp in Sources */,
+ 1A2A54C10FD1DD1C00F4CE45 /* RewriteMacros.cpp in Sources */,
+ 1A2A54C20FD1DD1C00F4CE45 /* RewriteObjC.cpp in Sources */,
+ 1A2A54C30FD1DD1C00F4CE45 /* RewriteTest.cpp in Sources */,
+ 1A2A54C40FD1DD1C00F4CE45 /* StmtXML.cpp in Sources */,
+ 1A2A54C50FD1DD1C00F4CE45 /* Warnings.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/AnalyzerRegions.html b/docs/AnalyzerRegions.html
new file mode 100644
index 000000000000..35708d57c970
--- /dev/null
+++ b/docs/AnalyzerRegions.html
@@ -0,0 +1,258 @@
+<html>
+<head>
+<title>Static Analyzer Design Document: Memory Regions</title>
+</head>
+<body>
+
+<h1>Static Analyzer Design Document: Memory Regions</h1>
+
+<h3>Authors</h3>
+
+<p>Ted Kremenek, <tt>kremenek at apple</tt><br>
+Zhongxing Xu, <tt>xuzhongzhing at gmail</tt></p>
+
+<h2 id="intro">Introduction</h2>
+
+<p>The path-sensitive analysis engine in libAnalysis employs an extensible API
+for abstractly modeling the memory of an analyzed program. This API employs the
+concept of "memory regions" to abstractly model chunks of program memory such as
+program variables and dynamically allocated memory such as those returned from
+'malloc' and 'alloca'. Regions are hierarchical, with subregions modeling
+subtyping relationships, field and array offsets into larger chunks of memory,
+and so on.</p>
+
+<p>The region API consists of two components:</p>
+
+<ul> <li>A taxonomy and representation of regions themselves within the analyzer
+engine. The primary definitions and interfaces are described in <tt><a
+href="http://clang.llvm.org/doxygen/MemRegion_8h-source.html">MemRegion.h</a></tt>.
+At the root of the region hierarchy is the class <tt>MemRegion</tt> with
+specific subclasses refining the region concept for variables, heap allocated
+memory, and so forth.</li> <li>The modeling of binding of values to regions. For
+example, modeling the value stored to a local variable <tt>x</tt> consists of
+recording the binding between the region for <tt>x</tt> (which represents the
+raw memory associated with <tt>x</tt>) and the value stored to <tt>x</tt>. This
+binding relationship is captured with the notion of &quot;symbolic
+stores.&quot;</li> </ul>
+
+<p>Symbolic stores, which can be thought of as representing the relation
+<tt>regions -> values</tt>, are implemented by subclasses of the
+<tt>StoreManager</tt> class (<tt><a
+href="http://clang.llvm.org/doxygen/Store_8h-source.html">Store.h</a></tt>). A
+particular StoreManager implementation has complete flexibility concerning the
+following:
+
+<ul>
+<li><em>How</em> to model the binding between regions and values</li>
+<li><em>What</em> bindings are recorded
+</ul>
+
+<p>Together, both points allow different StoreManagers to tradeoff between
+different levels of analysis precision and scalability concerning the reasoning
+of program memory. Meanwhile, the core path-sensitive engine makes no
+assumptions about either points, and queries a StoreManager about the bindings
+to a memory region through a generic interface that all StoreManagers share. If
+a particular StoreManager cannot reason about the potential bindings of a given
+memory region (e.g., '<tt>BasicStoreManager</tt>' does not reason about fields
+of structures) then the StoreManager can simply return 'unknown' (represented by
+'<tt>UnknownVal</tt>') for a particular region-binding. This separation of
+concerns not only isolates the core analysis engine from the details of
+reasoning about program memory but also facilities the option of a client of the
+path-sensitive engine to easily swap in different StoreManager implementations
+that internally reason about program memory in very different ways.</pp>
+
+<p>The rest of this document is divided into two parts. We first discuss region
+taxonomy and the semantics of regions. We then discuss the StoreManager
+interface, and details of how the currently available StoreManager classes
+implement region bindings.</p>
+
+<h2 id="regions">Memory Regions and Region Taxonomy</h2>
+
+<h3>Pointers</h3>
+
+<p>Before talking about the memory regions, we would talk about the pointers
+since memory regions are essentially used to represent pointer values.</p>
+
+<p>The pointer is a type of values. Pointer values have two semantic aspects.
+One is its physical value, which is an address or location. The other is the
+type of the memory object residing in the address.</p>
+
+<p>Memory regions are designed to abstract these two properties of the pointer.
+The physical value of a pointer is represented by MemRegion pointers. The rvalue
+type of the region corresponds to the type of the pointee object.</p>
+
+<p>One complication is that we could have different view regions on the same
+memory chunk. They represent the same memory location, but have different
+abstract location, i.e., MemRegion pointers. Thus we need to canonicalize the
+abstract locations to get a unique abstract location for one physical
+location.</p>
+
+<p>Furthermore, these different view regions may or may not represent memory
+objects of different types. Some different types are semantically the same,
+for example, 'struct s' and 'my_type' are the same type.</p>
+
+<pre>
+struct s;
+typedef struct s my_type;
+</pre>
+
+<p>But <tt>char</tt> and <tt>int</tt> are not the same type in the code below:</p>
+
+<pre>
+void *p;
+int *q = (int*) p;
+char *r = (char*) p;
+</pre
+
+<p>Thus we need to canonicalize the MemRegion which is used in binding and
+retrieving.</p>
+
+<h3>Regions</h3>
+<p>Region is the entity used to model pointer values. A Region has the following
+properties:</p>
+
+<ul>
+<li>Kind</li>
+
+<li>ObjectType: the type of the object residing on the region.</li>
+
+<li>LocationType: the type of the pointer value that the region corresponds to.
+ Usually this is the pointer to the ObjectType. But sometimes we want to cache
+ this type explicitly, for example, for a CodeTextRegion.</li>
+
+<li>StartLocation</li>
+
+<li>EndLocation</li>
+</ul>
+
+<h3>Symbolic Regions</h3>
+
+<p>A symbolic region is a map of the concept of symbolic values into the domain
+of regions. It is the way that we represent symbolic pointers. Whenever a
+symbolic pointer value is needed, a symbolic region is created to represent
+it.</p>
+
+<p>A symbolic region has no type. It wraps a SymbolData. But sometimes we have
+type information associated with a symbolic region. For this case, a
+TypedViewRegion is created to layer the type information on top of the symbolic
+region. The reason we do not carry type information with the symbolic region is
+that the symbolic regions can have no type. To be consistent, we don't let them
+to carry type information.</p>
+
+<p>Like a symbolic pointer, a symbolic region may be NULL, has unknown extent,
+and represents a generic chunk of memory.</p>
+
+<p><em><b>NOTE</b>: We plan not to use loc::SymbolVal in RegionStore and remove it
+ gradually.</em></p>
+
+<p>Symbolic regions get their rvalue types through the following ways:</p>
+
+<ul>
+<li>Through the parameter or global variable that points to it, e.g.:
+<pre>
+void f(struct s* p) {
+ ...
+}
+</pre>
+
+<p>The symbolic region pointed to by <tt>p</tt> has type <tt>struct
+s</tt>.</p></li>
+
+<li>Through explicit or implicit casts, e.g.:
+<pre>
+void f(void* p) {
+ struct s* q = (struct s*) p;
+ ...
+}
+</pre>
+</li>
+</ul>
+
+<p>We attach the type information to the symbolic region lazily. For the first
+case above, we create the <tt>TypedViewRegion</tt> only when the pointer is
+actually used to access the pointee memory object, that is when the element or
+field region is created. For the cast case, the <tt>TypedViewRegion</tt> is
+created when visiting the <tt>CastExpr</tt>.</p>
+
+<p>The reason for doing lazy typing is that symbolic regions are sometimes only
+used to do location comparison.</p>
+
+<h3>Pointer Casts</h3>
+
+<p>Pointer casts allow people to impose different 'views' onto a chunk of
+memory.</p>
+
+<p>Usually we have two kinds of casts. One kind of casts cast down with in the
+type hierarchy. It imposes more specific views onto more generic memory regions.
+The other kind of casts cast up with in the type hierarchy. It strips away more
+specific views on top of the more generic memory regions.</p>
+
+<p>We simulate the down casts by layering another <tt>TypedViewRegion</tt> on
+top of the original region. We simulate the up casts by striping away the top
+<tt>TypedViewRegion</tt>. Down casts is usually simple. For up casts, if the
+there is no <tt>TypedViewRegion</tt> to be stripped, we return the original
+region. If the underlying region is of the different type than the cast-to type,
+we flag an error state.</p>
+
+<p>For toll-free bridging casts, we return the original region.</p>
+
+<p>We can set up a partial order for pointer types, with the most general type
+<tt>void*</tt> at the top. The partial order forms a tree with <tt>void*</tt> as
+its root node.</p>
+
+<p>Every <tt>MemRegion</tt> has a root position in the type tree. For example,
+the pointee region of <tt>void *p</tt> has its root position at the root node of
+the tree. <tt>VarRegion</tt> of <tt>int x</tt> has its root position at the 'int
+type' node.</p>
+
+<p><tt>TypedViewRegion</tt> is used to move the region down or up in the tree.
+Moving down in the tree adds a <tt>TypedViewRegion</tt>. Moving up in the tree
+removes a <Tt>TypedViewRegion</tt>.</p>
+
+<p>Do we want to allow moving up beyond the root position? This happens
+when:</p> <pre> int x; void *p = &amp;x; </pre>
+
+<p>The region of <tt>x</tt> has its root position at 'int*' node. the cast to
+void* moves that region up to the 'void*' node. I propose to not allow such
+casts, and assign the region of <tt>x</tt> for <tt>p</tt>.</p>
+
+<p>Another non-ideal case is that people might cast to a non-generic pointer
+from another non-generic pointer instead of first casting it back to the generic
+pointer. Direct handling of this case would result in multiple layers of
+TypedViewRegions. This enforces an incorrect semantic view to the region,
+because we can only have one typed view on a region at a time. To avoid this
+inconsistency, before casting the region, we strip the TypedViewRegion, then do
+the cast. In summary, we only allow one layer of TypedViewRegion.</p>
+
+<h3>Region Bindings</h3>
+
+<p>The following region kinds are boundable: VarRegion, CompoundLiteralRegion,
+StringRegion, ElementRegion, FieldRegion, and ObjCIvarRegion.</p>
+
+<p>When binding regions, we perform canonicalization on element regions and field
+regions. This is because we can have different views on the same region, some
+of which are essentially the same view with different sugar type names.</p>
+
+<p>To canonicalize a region, we get the canonical types for all TypedViewRegions
+along the way up to the root region, and make new TypedViewRegions with those
+canonical types.</p>
+
+<p>For Objective-C and C++, perhaps another canonicalization rule should be
+added: for FieldRegion, the least derived class that has the field is used as
+the type of the super region of the FieldRegion.</p>
+
+<p>All bindings and retrievings are done on the canonicalized regions.</p>
+
+<p>Canonicalization is transparent outside the region store manager, and more
+specifically, unaware outside the Bind() and Retrieve() method. We don't need to
+consider region canonicalization when doing pointer cast.</p>
+
+<h3>Constraint Manager</h3>
+
+<p>The constraint manager reasons about the abstract location of memory objects.
+We can have different views on a region, but none of these views changes the
+location of that object. Thus we should get the same abstract location for those
+regions.</p>
+
+</body>
+</html>
diff --git a/docs/BlockImplementation.txt b/docs/BlockImplementation.txt
new file mode 100644
index 000000000000..b2ad40576b5e
--- /dev/null
+++ b/docs/BlockImplementation.txt
@@ -0,0 +1,647 @@
+Block Implementation Specification
+
+Copyright 2008-2009 Apple, Inc.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+0. History
+
+2008/7/14 - created
+2008/8/21 - revised, C++
+2008/9/24 - add NULL isa field to __block storage
+2008/10/1 - revise block layout to use a static descriptor structure
+2008/10/6 - revise block layout to use an unsigned long int flags
+2008/10/28 - specify use of _Block_object_assign/dispose for all "Object" types in helper functions
+2008/10/30 - revise new layout to have invoke function in same place
+2008/10/30 - add __weak support
+
+This document describes the Apple ABI implementation specification of Blocks.
+
+1. High Level
+
+A Block consists of a structure of the following form:
+
+struct Block_literal_1 {
+ void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
+ int flags;
+ int reserved;
+ void (*invoke)(void *, ...);
+ struct Block_descriptor_1 {
+ unsigned long int reserved; // NULL
+ unsigned long int size; // sizeof(struct Block_literal_1)
+ // optional helper functions
+ void (*copy_helper)(void *dst, void *src);
+ void (*dispose_helper)(void *src);
+ } *descriptor;
+ // imported variables
+};
+
+The following flags bits are used by the compiler:
+
+enum {
+ BLOCK_HAS_COPY_DISPOSE = (1 << 25),
+ BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
+ BLOCK_IS_GLOBAL = (1 << 28),
+ BLOCK_HAS_DESCRIPTOR = (1 << 29), // interim until complete world build is accomplished
+};
+
+Block literals may occur within functions where the structure is created in stack local memory. They may also appear as initialization expressions for Block variables of global or static local variables.
+
+When a Block literal expression is evaluated the stack based structure is initialized as follows:
+
+1) static descriptor structure is declared and initialized as follows:
+1a) the invoke function pointer is set to a function that takes the Block structure as its first argument and the rest of the arguments (if any) to the Block and executes the Block compound statement.
+1b) the size field is set to the size of the following Block literal structure.
+1c) the copy_helper and dispose_helper function pointers are set to respective helper functions if they are required by the Block literal
+2) a stack (or global) Block literal data structure is created and initialized as follows:
+2a) the isa field is set to the address of the external _NSConcreteStackBlock, which is a block of uninitialized memory supplied in libSystem, or _NSConcreteGlobalBlock if this is a static or file level block literal.
+2) The flags field is set to zero unless there are variables imported into the block that need helper functions for program level Block_copy() and Block_release() operations, in which case the (1<<25) flags bit is set.
+
+As an example, the Block literal expression
+ ^ { printf("hello world\n"); }
+would cause to be created on a 32-bit system:
+
+struct __block_literal_1 {
+ void *isa;
+ int flags;
+ int reserved;
+ void (*invoke)(struct __block_literal_1 *);
+ struct __block_descriptor_1 *descriptor;
+};
+
+void __block_invoke_1(struct __block_literal_1 *_block) {
+ printf("hello world\n");
+}
+
+static struct __block_descriptor_1 {
+ unsigned long int reserved;
+ unsigned long int Block_size;
+} __block_descriptor_1 = { 0, sizeof(struct __block_literal_1), __block_invoke_1 };
+
+and where the block literal appeared
+
+ struct __block_literal_1 _block_literal = {
+ &_NSConcreteStackBlock,
+ (1<<29), <uninitialized>,
+ __block_invoke_1,
+ &__block_descriptor_1
+ };
+
+Blocks import other Block references, const copies of other variables, and variables marked __block. In Objective-C variables may additionally be objects.
+
+When a Block literal expression used as the initial value of a global or static local variable it is initialized as follows:
+ struct __block_literal_1 __block_literal_1 = {
+ &_NSConcreteGlobalBlock,
+ (1<<28)|(1<<29), <uninitialized>,
+ __block_invoke_1,
+ &__block_descriptor_1
+ };
+that is, a different address is provided as the first value and a particular (1<<28) bit is set in the flags field, and otherwise it is the same as for stack based Block literals. This is an optimization that can be used for any Block literal that imports no const or __block storage variables.
+
+
+2. Imported Variables
+
+Variables of "auto" storage class are imported as const copies. Variables of "__block" storage class are imported as a pointer to an enclosing data structure. Global variables are simply referenced and not considered as imported.
+
+2.1 Imported const copy variables
+
+Automatic storage variables not marked with __block are imported as const copies.
+
+The simplest example is that of importing a variable of type int.
+
+ int x = 10;
+ void (^vv)(void) = ^{ printf("x is %d\n", x); }
+ x = 11;
+ vv();
+
+would be compiled
+
+struct __block_literal_2 {
+ void *isa;
+ int flags;
+ int reserved;
+ void (*invoke)(struct __block_literal_2 *);
+ struct __block_descriptor_2 *descriptor;
+ const int x;
+};
+
+void __block_invoke_2(struct __block_literal_2 *_block) {
+ printf("x is %d\n", _block->x);
+}
+
+static struct __block_descriptor_2 {
+ unsigned long int reserved;
+ unsigned long int Block_size;
+} __block_descriptor_2 = { 0, sizeof(struct __block_literal_2) };
+
+and
+
+ struct __block_literal_2 __block_literal_2 = {
+ &_NSConcreteStackBlock,
+ (1<<29), <uninitialized>,
+ __block_invoke_2,
+ &__block_descriptor_2,
+ x
+ };
+
+In summary, scalars, structures, unions, and function pointers are generally imported as const copies with no need for helper functions.
+
+2.2 Imported const copy of Block reference
+
+The first case where copy and dispose helper functions are required is for the case of when a block itself is imported. In this case both a copy_helper function and a dispose_helper function are needed. The copy_helper function is passed both the existing stack based pointer and the pointer to the new heap version and should call back into the runtime to actually do the copy operation on the imported fields within the block. The runtime functions are all described in Section 5.0 Runtime Helper Functions.
+
+An example:
+
+ void (^existingBlock)(void) = ...;
+ void (^vv)(void) = ^{ existingBlock(); }
+ vv();
+
+struct __block_literal_3 {
+ ...; // existing block
+};
+
+struct __block_literal_4 {
+ void *isa;
+ int flags;
+ int reserved;
+ void (*invoke)(struct __block_literal_4 *);
+ struct __block_literal_3 *const existingBlock;
+};
+
+void __block_invoke_4(struct __block_literal_2 *_block) {
+ __block->existingBlock->invoke(__block->existingBlock);
+}
+
+void __block_copy_4(struct __block_literal_4 *dst, struct __block_literal_4 *src) {
+ //_Block_copy_assign(&dst->existingBlock, src->existingBlock, 0);
+ _Block_object_assign(&dst->existingBlock, src->existingBlock, BLOCK_FIELD_IS_BLOCK);
+}
+
+void __block_dispose_4(struct __block_literal_4 *src) {
+ // was _Block_destroy
+ _Block_object_dispose(src->existingBlock, BLOCK_FIELD_IS_BLOCK);
+}
+
+static struct __block_descriptor_4 {
+ unsigned long int reserved;
+ unsigned long int Block_size;
+ void (*copy_helper)(struct __block_literal_4 *dst, struct __block_literal_4 *src);
+ void (*dispose_helper)(struct __block_literal_4 *);
+} __block_descriptor_4 = {
+ 0,
+ sizeof(struct __block_literal_4),
+ __block_copy_4,
+ __block_dispose_4,
+};
+
+and where it is used
+
+ struct __block_literal_4 _block_literal = {
+ &_NSConcreteStackBlock,
+ (1<<25)|(1<<29), <uninitialized>
+ __block_invoke_4,
+ & __block_descriptor_4
+ existingBlock,
+ };
+
+2.2.1 Importing __attribute__((NSObject)) variables.
+
+GCC introduces __attribute__((NSObject)) on structure pointers to mean "this is an object". This is useful because many low level data structures are declared as opaque structure pointers, e.g. CFStringRef, CFArrayRef, etc. When used from C, however, these are still really objects and are the second case where that requires copy and dispose helper functions to be generated. The copy helper functions generated by the compiler should use the _Block_object_assign runtime helper function and in the dispose helper the _Block_object_dispose runtime helper function should be called.
+
+For example, block xyzzy in the following
+
+ struct Opaque *__attribute__((NSObject)) objectPointer = ...;
+ ...
+ void (^xyzzy)(void) = ^{ CFPrint(objectPointer); };
+
+would have helper functions
+
+void __block_copy_xyzzy(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
+ _Block_object_assign(&dst->objectPointer, src-> objectPointer, BLOCK_FIELD_IS_OBJECT);
+}
+
+void __block_dispose_xyzzy(struct __block_literal_5 *src) {
+ _Block_object_dispose(src->objectPointer, BLOCK_FIELD_IS_OBJECT);
+}
+
+generated.
+
+
+2.3 Imported __block marked variables.
+
+2.3.1 Layout of __block marked variables
+
+The compiler must embed variables that are marked __block in a specialized structure of the form:
+
+struct _block_byref_xxxx {
+ void *isa;
+ struct Block_byref *forwarding;
+ int flags; //refcount;
+ int size;
+ typeof(marked_variable) marked_variable;
+};
+
+Variables of certain types require helper functions for when Block_copy() and Block_release() are performed upon a referencing Block. At the "C" level only variables that are of type Block or ones that have __attribute__((NSObject)) marked require helper functions. In Objective-C objects require helper functions and in C++ stack based objects require helper functions. Variables that require helper functions use the form:
+
+struct _block_byref_xxxx {
+ void *isa;
+ struct _block_byref_xxxx *forwarding;
+ int flags; //refcount;
+ int size;
+ // helper functions called via Block_copy() and Block_release()
+ void (*byref_keep)(void *dst, void *src);
+ void (*byref_dispose)(void *);
+ typeof(marked_variable) marked_variable;
+};
+
+The structure is initialized such that
+ a) the forwarding pointer is set to the beginning of its enclosing structure,
+ b) the size field is initialized to the total size of the enclosing structure,
+ c) the flags field is set to either 0 if no helper functions are needed or (1<<25) if they are,
+ d) the helper functions are initialized (if present)
+ e) the variable itself is set to its initial value.
+ f) the isa field is set to NULL
+
+2.3.2 Access to __block variables from within its lexical scope.
+
+In order to "move" the variable to the heap upon a copy_helper operation the compiler must rewrite access to such a variable to be indirect through the structures forwarding pointer. For example:
+
+ int __block i = 10;
+ i = 11;
+
+would be rewritten to be:
+
+ struct _block_byref_i {
+ void *isa;
+ struct _block_byref_i *forwarding;
+ int flags; //refcount;
+ int size;
+ int captured_i;
+ } i = { NULL, &i, 0, sizeof(struct _block_byref_i), 11;
+
+ i.forwarding->captured_i = 11;
+
+In the case of a Block reference variable being marked __block the helper code generated must use the _Block_object_assign and _Block_object_dispose routines supplied by the runtime to make the copies. For example:
+
+ __block void (voidBlock)(void) = blockA;
+ voidBlock = blockB;
+
+would translate into
+
+struct _block_byref_voidBlock {
+ void *isa;
+ struct _block_byref_voidBlock *forwarding;
+ int flags; //refcount;
+ int size;
+ void (*byref_keep)(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src);
+ void (*byref_dispose)(struct _block_byref_voidBlock *);
+ void (^captured_voidBlock)(void);
+};
+
+void _block_byref_keep_helper(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
+ //_Block_copy_assign(&dst->captured_voidBlock, src->captured_voidBlock, 0);
+ _Block_object_assign(&dst->captured_voidBlock, src->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
+}
+
+void _block_byref_dispose_helper(struct _block_byref_voidBlock *param) {
+ //_Block_destroy(param->captured_voidBlock, 0);
+ _Block_object_dispose(param->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER)}
+
+and
+ struct _block_byref_voidBlock voidBlock = {( .forwarding=&voidBlock, .flags=(1<<25), .size=sizeof(struct _block_byref_voidBlock *),
+ .byref_keep=_block_byref_keep_helper, .byref_dispose=_block_byref_dispose_helper,
+ .captured_voidBlock=blockA };
+
+ voidBlock.forwarding->captured_voidBlock = blockB;
+
+
+2.3.3 Importing __block variables into Blocks
+
+A Block that uses a __block variable in its compound statement body must import the variable and emit copy_helper and dispose_helper helper functions that, in turn, call back into the runtime to actually copy or release the byref data block using the functions _Block_object_assign and _Block_object_dispose.
+
+For example:
+
+ int __block i = 2;
+ functioncall(^{ i = 10; });
+
+would translate to
+
+struct _block_byref_i {
+ void *isa; // set to NULL
+ struct _block_byref_voidBlock *forwarding;
+ int flags; //refcount;
+ int size;
+ void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
+ void (*byref_dispose)(struct _block_byref_i *);
+ int captured_i;
+};
+
+
+struct __block_literal_5 {
+ void *isa;
+ int flags;
+ int reserved;
+ void (*invoke)(struct __block_literal_5 *);
+ struct __block_descriptor_5 *descriptor;
+ struct _block_byref_i *i_holder;
+};
+
+void __block_invoke_5(struct __block_literal_5 *_block) {
+ _block->forwarding->captured_i = 10;
+}
+
+void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
+ //_Block_byref_assign_copy(&dst->captured_i, src->captured_i);
+ _Block_object_assign(&dst->captured_i, src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
+}
+
+void __block_dispose_5(struct __block_literal_5 *src) {
+ //_Block_byref_release(src->captured_i);
+ _Block_object_dispose(src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
+}
+
+static struct __block_descriptor_5 {
+ unsigned long int reserved;
+ unsigned long int Block_size;
+ void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
+ void (*dispose_helper)(struct __block_literal_5 *);
+} __block_descriptor_5 = { 0, sizeof(struct __block_literal_5) __block_copy_5, __block_dispose_5 };
+
+and
+
+ struct _block_byref_i i = {( .forwarding=&i, .flags=0, .size=sizeof(struct _block_byref_i) )};
+ struct __block_literal_5 _block_literal = {
+ &_NSConcreteStackBlock,
+ (1<<25)|(1<<29), <uninitialized>,
+ __block_invoke_5,
+ &__block_descriptor_5,
+ 2,
+ };
+
+2.3.4 Importing __attribute__((NSObject)) __block variables
+
+A __block variable that is also marked __attribute__((NSObject)) should have byref_keep and byref_dispose helper functions that use _Block_object_assign and _Block_object_dispose.
+
+2.3.5 __block escapes
+
+Because Blocks referencing __block variables may have Block_copy() performed upon them the underlying storage for the variables may move to the heap. In Objective-C Garbage Collection Only compilation environments the heap used is the garbage collected one and no further action is required. Otherwise the compiler must issue a call to potentially release any heap storage for __block variables at all escapes or terminations of their scope.
+
+
+2.3.6 Nesting
+
+Blocks may contain Block literal expressions. Any variables used within inner blocks are imported into all enclosing Block scopes even if the variables are not used. This includes const imports as well as __block variables.
+
+3. Objective C Extensions to Blocks
+
+3.1 Importing Objects
+
+Objects should be treated as __attribute__((NSObject)) variables; all copy_helper, dispose_helper, byref_keep, and byref_dispose helper functions should use _Block_object_assign and _Block_object_dispose. There should be no code generated that uses -retain or -release methods.
+
+
+3.2 Blocks as Objects
+
+The compiler will treat Blocks as objects when synthesizing property setters and getters, will characterize them as objects when generating garbage collection strong and weak layout information in the same manner as objects, and will issue strong and weak write-barrier assignments in the same manner as objects.
+
+3.3 __weak __block Support
+
+Objective-C (and Objective-C++) support the __weak attribute on __block variables. Under normal circumstances the compiler uses the Objective-C runtime helper support functions objc_assign_weak and objc_read_weak. Both should continue to be used for all reads and writes of __weak __block variables:
+ objc_read_weak(&block->byref_i->forwarding->i)
+
+The __weak variable is stored in a _block_byref_xxxx structure and the Block has copy and dispose helpers for this structure that call:
+ _Block_object_assign(&dest->_block_byref_i, src-> _block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF);
+and
+ _Block_object_dispose(src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF);
+
+
+In turn, the block_byref copy support helpers distinguish between whether the __block variable is a Block or not and should either call:
+ _Block_object_assign(&dest->_block_byref_i, src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_OBJECT | BLOCK_BYREF_CALLER);
+for something declared as an object or
+ _Block_object_assign(&dest->_block_byref_i, src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
+for something declared as a Block.
+
+A full example follows:
+
+
+ __block __weak id obj = <initialization expression>;
+ functioncall(^{ [obj somemessage]; });
+
+would translate to
+
+struct _block_byref_obj {
+ void *isa; // uninitialized
+ struct _block_byref_obj *forwarding;
+ int flags; //refcount;
+ int size;
+ void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
+ void (*byref_dispose)(struct _block_byref_i *);
+ int captured_obj;
+};
+
+void _block_byref_obj_keep(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
+ //_Block_copy_assign(&dst->captured_obj, src->captured_obj, 0);
+ _Block_object_assign(&dst->captured_obj, src->captured_obj, BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
+}
+
+void _block_byref_obj_dispose(struct _block_byref_voidBlock *param) {
+ //_Block_destroy(param->captured_obj, 0);
+ _Block_object_dispose(param->captured_obj, BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
+};
+
+for the block byref part and
+
+struct __block_literal_5 {
+ void *isa;
+ int flags;
+ int reserved;
+ void (*invoke)(struct __block_literal_5 *);
+ struct __block_descriptor_5 *descriptor;
+ struct _block_byref_obj *byref_obj;
+};
+
+void __block_invoke_5(struct __block_literal_5 *_block) {
+ [objc_read_weak(&_block->byref_obj->forwarding->captured_obj) somemessage];
+}
+
+void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
+ //_Block_byref_assign_copy(&dst->byref_obj, src->byref_obj);
+ _Block_object_assign(&dst->byref_obj, src->byref_obj, BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
+}
+
+void __block_dispose_5(struct __block_literal_5 *src) {
+ //_Block_byref_release(src->byref_obj);
+ _Block_object_dispose(src->byref_obj, BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
+}
+
+static struct __block_descriptor_5 {
+ unsigned long int reserved;
+ unsigned long int Block_size;
+ void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
+ void (*dispose_helper)(struct __block_literal_5 *);
+} __block_descriptor_5 = { 0, sizeof(struct __block_literal_5), __block_copy_5, __block_dispose_5 };
+
+and within the compound statement:
+
+ struct _block_byref_obj obj = {( .forwarding=&obj, .flags=(1<<25), .size=sizeof(struct _block_byref_obj),
+ .byref_keep=_block_byref_obj_keep, .byref_dispose=_block_byref_obj_dispose,
+ .captured_obj = <initialization expression> )};
+
+ struct __block_literal_5 _block_literal = {
+ &_NSConcreteStackBlock,
+ (1<<25)|(1<<29), <uninitialized>,
+ __block_invoke_5,
+ &__block_descriptor_5,
+ &obj, // a reference to the on-stack structure containing "captured_obj"
+ };
+
+
+ functioncall(_block_literal->invoke(&_block_literal));
+
+
+4.0 C++ Support
+
+Within a block stack based C++ objects are copied as const copies using the const copy constructor. It is an error if a stack based C++ object is used within a block if it does not have a const copy constructor. In addition both copy and destroy helper routines must be synthesized for the block to support the Block_copy() operation, and the flags work marked with the (1<<26) bit in addition to the (1<<25) bit. The copy helper should call the constructor using appropriate offsets of the variable within the supplied stack based block source and heap based destination for all const constructed copies, and similarly should call the destructor in the destroy routine.
+
+As an example, suppose a C++ class FOO existed with a const copy constructor. Within a code block a stack version of a FOO object is declared and used within a Block literal expression:
+
+{
+ FOO foo;
+ void (^block)(void) = ^{ printf("%d\n", foo.value()); };
+}
+
+The compiler would synthesize
+
+struct __block_literal_10 {
+ void *isa;
+ int flags;
+ int reserved;
+ void (*invoke)(struct __block_literal_10 *);
+ struct __block_descriptor_10 *descriptor;
+ const FOO foo;
+};
+
+void __block_invoke_10(struct __block_literal_10 *_block) {
+ printf("%d\n", _block->foo.value());
+}
+
+void __block_literal_10(struct __block_literal_10 *dst, struct __block_literal_10 *src) {
+ comp_ctor(&dst->foo, &src->foo);
+}
+
+void __block_dispose_10(struct __block_literal_10 *src) {
+ comp_dtor(&src->foo);
+}
+
+static struct __block_descriptor_10 {
+ unsigned long int reserved;
+ unsigned long int Block_size;
+ void (*copy_helper)(struct __block_literal_10 *dst, struct __block_literal_10 *src);
+ void (*dispose_helper)(struct __block_literal_10 *);
+} __block_descriptor_10 = { 0, sizeof(struct __block_literal_10), __block_copy_10, __block_dispose_10 };
+
+and the code would be:
+{
+ FOO foo;
+ comp_ctor(&foo); // default constructor
+ struct __block_literal_10 _block_literal = {
+ &_NSConcreteStackBlock,
+ (1<<25)|(1<<26)|(1<<29), <uninitialized>,
+ __block_invoke_10,
+ &__block_descriptor_10,
+ };
+ comp_ctor(&_block_literal->foo, &foo); // const copy into stack version
+ struct __block_literal_10 &block = &_block_literal; // assign literal to block variable
+ block->invoke(block); // invoke block
+ comp_dtor(&_block_literal->foo); // destroy stack version of const block copy
+ comp_dtor(&foo); // destroy original version
+}
+
+
+C++ objects stored in __block storage start out on the stack in a block_byref data structure as do other variables. Such objects (if not const objects) must support a regular copy constructor. The block_byref data structure will have copy and destroy helper routines synthesized by the compiler. The copy helper will have code created to perform the copy constructor based on the initial stack block_byref data structure, and will also set the (1<<26) bit in addition to the (1<<25) bit. The destroy helper will have code to do the destructor on the object stored within the supplied block_byref heap data structure.
+
+To support member variable and function access the compiler will synthesize a const pointer to a block version of the this pointer.
+
+5.0 Runtime Helper Functions
+
+The runtime helper functions are described in /usr/local/include/Block_private.h. To summarize their use, a block requires copy/dispose helpers if it imports any block variables, __block storage variables, __attribute__((NSObject)) variables, or C++ const copied objects with constructor/destructors. The (1<<26) bit is set and functions are generated.
+
+The block copy helper function should, for each of the variables of the type mentioned above, call
+ _Block_object_assign(&dst->target, src->target, BLOCK_FIELD_<appropo>);
+in the copy helper and
+ _Block_object_dispose(->target, BLOCK_FIELD_<appropo>);
+in the dispose helper where
+ <appropo> is
+
+enum {
+ BLOCK_FIELD_IS_OBJECT = 3, // id, NSObject, __attribute__((NSObject)), block, ...
+ BLOCK_FIELD_IS_BLOCK = 7, // a block variable
+ BLOCK_FIELD_IS_BYREF = 8, // the on stack structure holding the __block variable
+
+ BLOCK_FIELD_IS_WEAK = 16, // declared __weak
+
+ BLOCK_BYREF_CALLER = 128, // called from byref copy/dispose helpers
+};
+
+and of course the CTORs/DTORs for const copied C++ objects.
+
+The block_byref data structure similarly requires copy/dispose helpers for block variables, __attribute__((NSObject)) variables, or C++ const copied objects with constructor/destructors, and again the (1<<26) bit is set and functions are generated in the same manner.
+
+Under ObjC we allow __weak as an attribute on __block variables, and this causes the addition of BLOCK_FIELD_IS_WEAK orred onto the BLOCK_FIELD_IS_BYREF flag when copying the block_byref structure in the block copy helper, and onto the BLOCK_FIELD_<appropo> field within the block_byref copy/dispose helper calls.
+
+The prototypes, and summary, of the helper functions are
+
+/* Certain field types require runtime assistance when being copied to the heap. The following function is used
+ to copy fields of types: blocks, pointers to byref structures, and objects (including __attribute__((NSObject)) pointers.
+ BLOCK_FIELD_IS_WEAK is orthogonal to the other choices which are mutually exclusive.
+ Only in a Block copy helper will one see BLOCK_FIELD_IS_BYREF.
+ */
+void _Block_object_assign(void *destAddr, const void *object, const int flags);
+
+/* Similarly a compiler generated dispose helper needs to call back for each field of the byref data structure.
+ (Currently the implementation only packs one field into the byref structure but in principle there could be more).
+ The same flags used in the copy helper should be used for each call generated to this function:
+ */
+void _Block_object_dispose(const void *object, const int flags);
+
+The following functions have been used and will continue to be supported until new compiler support is complete.
+
+// Obsolete functions.
+// Copy helper callback for copying a block imported into a Block
+// Called by copy_helper helper functions synthesized by the compiler.
+// The address in the destination block of an imported Block is provided as the first argument
+// and the value of the existing imported Block is the second.
+// Use: _Block_object_assign(dest, src, BLOCK_FIELD_IS_BLOCK {| BLOCK_FIELD_IS_WEAK});
+void _Block_copy_assign(struct Block_basic **dest, const struct Block_basic *src, const int flags);
+
+// Destroy helper callback for releasing Blocks imported into a Block
+// Called by dispose_helper helper functions synthesized by the compiler.
+// The value of the imported Block variable is passed back.
+// Use: _Block_object_dispose(src, BLOCK_FIELD_IS_BLOCK {| BLOCK_FIELD_IS_WEAK});
+void _Block_destroy(const struct Block_basic *src, const int flags);
+
+// Byref data block copy helper callback
+// Called by block copy helpers when copying __block structures
+// Use: _Block_object_assign(dest, src, BLOCK_FIELD_IS_BYREF {| BLOCK_FIELD_IS_WEAK});
+void _Block_byref_assign_copy(struct Block_byref **destp, struct Block_byref *src);
+
+// Byref data block release helper callback
+// Called by block release helpers when releasing a Block
+// Called at escape points in scope where __block variables live (under non-GC-only conditions)
+// Use: _Block_object_dispose(src, BLOCK_FIELD_IS_BYREF {| BLOCK_FIELD_IS_WEAK});
+void §(struct Block_byref *shared_struct);
+
+
diff --git a/docs/BlockLanguageSpec.txt b/docs/BlockLanguageSpec.txt
new file mode 100644
index 000000000000..a612fd28892b
--- /dev/null
+++ b/docs/BlockLanguageSpec.txt
@@ -0,0 +1,165 @@
+Language Specification for Blocks
+
+2008/2/25 — created
+2008/7/28 — revised, __block syntax
+2008/8/13 — revised, Block globals
+2008/8/21 — revised, C++ elaboration
+2008/11/1 — revised, __weak support
+2009/1/12 — revised, explicit return types
+2009/2/10 — revised, __block objects need retain
+
+Copyright 2008-2009 Apple, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+The Block Type
+
+A new derived type is introduced to C and, by extension, Objective-C, C++, and Objective-C++. Like function types, the Block type is a pair consisting of a result value type and a list of parameter types very similar to a function type. Blocks are intended to be used much like functions with the key distinction being that in addition to executable code they also contain various variable bindings to automatic (stack) or managed (heap) memory.
+
+The abstract declarator int (^)(char, float) describes a reference to a Block that, when invoked, takes two parameters, the first of type char and the second of type float, and returns a value of type int. The Block referenced is of opaque data that may reside in automatic (stack) memory, global memory, or heap memory.
+
+
+Block Variable Declarations
+
+A variable with Block type is declared using function pointer style notation substituting ^ for *. The following are valid Block variable declarations:
+ void (^blockReturningVoidWithVoidArgument)(void);
+ int (^blockReturningIntWithIntAndCharArguments)(int, char);
+ void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);
+
+Variadic ... arguments are supported. [variadic.c] A Block that takes no arguments must specify void in the argument list [voidarg.c]. An empty parameter list does not represent, as K&R provide, an unspecified argument list. Note: both gcc and clang support K&R style as a convenience.
+
+A Block reference may be cast to a pointer of arbitrary type and vice versa. [cast.c] A Block reference may not be dereferenced via the pointer dereference operator *, and thus a Block's size may not be computed at compile time. [sizeof.c]
+
+
+Block Literal Expressions
+
+A Block literal expression produces a reference to a Block. It is introduced by the use of the ^ token as a unary operator.
+ Block_literal_expression ::= ^ block_decl compound_statement_body
+ block_decl ::=
+ block_decl ::= parameter_list
+ block_decl ::= type_expression
+
+...where type expression is extended to allow ^ as a Block reference (pointer) where * is allowed as a function reference (pointer).
+
+The following Block literal:
+ ^ void (void) { printf("hello world\n"); }
+
+...produces a reference to a Block with no arguments with no return value.
+
+The return type is optional and is inferred from the return statements. If the return statements return a value, they all must return a value of the same type. If there is no value returned the inferred type of the Block is void; otherwise it is the type of the return statement value.
+
+If the return type is omitted and the argument list is ( void ), the ( void ) argument list may also be omitted.
+
+So:
+ ^ ( void ) { printf("hello world\n"); }
+
+...and:
+ ^ { printf("hello world\n"); }
+
+...are exactly equivalent constructs for the same expression.
+
+The type_expression extends C expression parsing to accommodate Block reference declarations as it accommodates function pointer declarations.
+
+Given:
+ typedef int (*pointerToFunctionThatReturnsIntWithCharArg)(char);
+ pointerToFunctionThatReturnsIntWithCharArg functionPointer;
+
+ ^ pointerToFunctionThatReturnsIntWithCharArg (float x) { return functionPointer; }
+
+...and:
+ ^ int ((*)(float x))(char) { return functionPointer; }
+
+...are equivalent expressions, as is:
+
+ ^(float x) { return functionPointer; }
+
+[returnfunctionptr.c]
+
+The compound statement body establishes a new lexical scope within that of its parent. Variables used within the scope of the compound statement are bound to the Block in the normal manner with the exception of those in automatic (stack) storage. Thus one may access functions and global variables as one would expect, as well as static local variables. [testme]
+
+Local automatic (stack) variables referenced within the compound statement of a Block are imported and captured by the Block as const copies. The capture (binding) is performed at the time of the Block literal expression evaluation.
+
+The lifetime of variables declared in a Block is that of a function; each activation frame contains a new copy of variables declared within the local scope of the Block. Such variable declarations should be allowed anywhere [testme] rather than only when C99 parsing is requested, including for statements. [testme]
+
+Block literal expressions may occur within Block literal expressions (nest) and all variables captured by any nested blocks are implicitly also captured in the scopes of their enclosing Blocks.
+
+A Block literal expression may be used as the initialization value for Block variables at global or local static scope.
+
+
+The Invoke Operator
+
+Blocks are invoked using function call syntax with a list of expression parameters of types corresponding to the declaration and returning a result type also according to the declaration. Given:
+ int (^x)(char);
+ void (^z)(void);
+ int (^(*y))(char) = &x;
+
+...the following are all legal Block invocations:
+ x('a');
+ (*y)('a');
+ (true ? x : *y)('a')
+
+
+The Copy and Release Operations
+
+The compiler and runtime provide copy and release operations for Block references that create and, in matched use, release allocated storage for referenced Blocks.
+
+The copy operation Block_copy() is styled as a function that takes an arbitrary Block reference and returns a Block reference of the same type. The release operation, Block_release(), is styled as a function that takes an arbitrary Block reference and, if dynamically matched to a Block copy operation, allows recovery of the referenced allocated memory.
+
+
+The __block Storage Qualifier
+
+In addition to the new Block type we also introduce a new storage qualifier, __block, for local variables. [testme: a __block declaration within a block literal] The __block storage qualifier is mutually exclusive to the existing local storage qualifiers auto, register, and static.[testme] Variables qualified by __block act as if they were in allocated storage and this storage is automatically recovered after last use of said variable. An implementation may choose an optimization where the storage is initially automatic and only "moved" to allocated (heap) storage upon a Block_copy of a referencing Block. Such variables may be mutated as normal variables are.
+
+In the case where a __block variable is a Block one must assume that the __block variable resides in allocated storage and as such is assumed to reference a Block that is also in allocated storage (that it is the result of a Block_copy operation). Despite this there is no provision to do a Block_copy or a Block_release if an implementation provides initial automatic storage for Blocks. This is due to the inherent race condition of potentially several threads trying to update the shared variable and the need for synchronization around disposing of older values and copying new ones. Such synchronization is beyond the scope of this language specification.
+
+
+Control Flow
+
+The compound statement of a Block is treated much like a function body with respect to control flow in that goto, break, and continue do not escape the Block. Exceptions are treated "normally" in that when thrown they pop stack frames until a catch clause is found.
+
+
+Objective-C Extensions
+
+Objective-C extends the definition of a Block reference type to be that also of id. A variable or expression of Block type may be messaged or used as a parameter wherever an id may be. The converse is also true. Block references may thus appear as properties and are subject to the assign, retain, and copy attribute logic that is reserved for objects.
+
+All Blocks are constructed to be Objective-C objects regardless of whether the Objective-C runtime is operational in the program or not. Blocks using automatic (stack) memory are objects and may be messaged, although they may not be assigned into __weak locations if garbage collection is enabled.
+
+Within a Block literal expression within a method definition references to instance variables are also imported into the lexical scope of the compound statement. These variables are implicitly qualified as references from self, and so self is imported as a const copy. The net effect is that instance variables can be mutated.
+
+The Block_copy operator retains all objects held in variables of automatic storage referenced within the Block expression (or form strong references if running under garbage collection). Object variables of __block storage type are assumed to hold normal pointers with no provision for retain and release messages.
+
+Foundation defines (and supplies) -copy and -release methods for Blocks.
+
+In the Objective-C and Objective-C++ languages, we allow the __weak specifier for __block variables of object type. If garbage collection is not enabled, this qualifier causes these variables to be kept without retain messages being sent. This knowingly leads to dangling pointers if the Block (or a copy) outlives the lifetime of this object.
+
+In garbage collected environments, the __weak variable is set to nil when the object it references is collected, as long as the __block variable resides in the heap (either by default or via Block_copy()). The initial Apple implementation does in fact start __block variables on the stack and migrate them to the heap only as a result of a Block_copy() operation.
+
+It is a runtime error to attempt to assign a reference to a stack-based Block into any storage marked __weak, including __weak __block variables.
+
+
+C++ Extensions
+
+Block literal expressions within functions are extended to allow const use of C++ objects, pointers, or references held in automatic storage.
+
+For example, given class Foo with member function fighter(void):
+ Foo foo;
+ Foo &fooRef = foo;
+ Foo *fooPtr = &foo;
+
+...a Block that used foo would import the variables as const variations:
+ const Foo block_foo = foo; // const copy constructor
+ const Foo &block_fooRef = fooRef;
+ const Foo *block_fooPtr = fooPtr;
+
+Stack-local objects are copied into a Block via a copy const constructor. If no such constructor exists, it is considered an error to reference such objects from within the Block compound statements. A destructor is run as control leaves the compound statement that contains the Block literal expression.
+
+If a Block originates on the stack, a const copy constructor of the stack-based Block const copy is performed when a Block_copy operation is called; when the last Block_release (or subsequently GC) occurs, a destructor is run on the heap copy.
+
+Variables declared as residing in __block storage may be initially allocated in the heap or may first appear on the stack and be copied to the heap as a result of a Block_copy() operation. When copied from the stack, a normal copy constructor is used to initialize the heap-based version from the original stack version. The destructor for a const copied object is run at the normal end of scope. The destructor for any initial stack based version is also called at normal end of scope.
+
+Within a member function, access to member functions and variables is done via an implicit const copy of a this pointer.
+
+Member variables that are Blocks may not be overloaded by the types of their arguments.
+
diff --git a/docs/DriverArchitecture.png b/docs/DriverArchitecture.png
new file mode 100644
index 000000000000..056a70a98fba
--- /dev/null
+++ b/docs/DriverArchitecture.png
Binary files differ
diff --git a/docs/DriverInternals.html b/docs/DriverInternals.html
new file mode 100644
index 000000000000..a99d72cd4eb2
--- /dev/null
+++ b/docs/DriverInternals.html
@@ -0,0 +1,517 @@
+<html>
+ <head>
+ <title>Clang Driver Manual</title>
+ <link type="text/css" rel="stylesheet" href="../menu.css" />
+ <link type="text/css" rel="stylesheet" href="../content.css" />
+ <style type="text/css">
+ td {
+ vertical-align: top;
+ }
+ </style>
+ </head>
+ <body>
+
+ <!--#include virtual="../menu.html.incl"-->
+
+ <div id="content">
+
+ <h1>Driver Design &amp; Internals</h1>
+
+ <ul>
+ <li><a href="#intro">Introduction</a></li>
+ <li><a href="#features">Features and Goals</a></li>
+ <ul>
+ <li><a href="#gcccompat">GCC Compatibility</a></li>
+ <li><a href="#components">Flexible</a></li>
+ <li><a href="#performance">Low Overhead</a></li>
+ <li><a href="#simple">Simple</a></li>
+ </ul>
+ <li><a href="#design">Design</a></li>
+ <ul>
+ <li><a href="#int_intro">Internals Introduction</a></li>
+ <li><a href="#int_overview">Design Overview</a></li>
+ <li><a href="#int_notes">Additional Notes</a></li>
+ <ul>
+ <li><a href="#int_compilation">The Compilation Object</a></li>
+ <li><a href="#int_unified_parsing">Unified Parsing &amp; Pipelining</a></li>
+ <li><a href="#int_toolchain_translation">ToolChain Argument Translation</a></li>
+ <li><a href="#int_unused_warnings">Unused Argument Warnings</a></li>
+ </ul>
+ <li><a href="#int_gcc_concepts">Relation to GCC Driver Concepts</a></li>
+ </ul>
+ </ul>
+
+
+ <!-- ======================================================================= -->
+ <h2 id="intro">Introduction</h2>
+ <!-- ======================================================================= -->
+
+ <p>This document describes the Clang driver. The purpose of this
+ document is to describe both the motivation and design goals
+ for the driver, as well as details of the internal
+ implementation.</p>
+
+ <!-- ======================================================================= -->
+ <h2 id="features">Features and Goals</h2>
+ <!-- ======================================================================= -->
+
+ <p>The Clang driver is intended to be a production quality
+ compiler driver providing access to the Clang compiler and
+ tools, with a command line interface which is compatible with
+ the gcc driver.</p>
+
+ <p>Although the driver is part of and driven by the Clang
+ project, it is logically a separate tool which shares many of
+ the same goals as Clang:</p>
+
+ <p><b>Features</b>:</p>
+ <ul>
+ <li><a href="#gcccompat">GCC Compatibility</a></li>
+ <li><a href="#components">Flexible</a></li>
+ <li><a href="#performance">Low Overhead</a></li>
+ <li><a href="#simple">Simple</a></li>
+ </ul>
+
+ <!--=======================================================================-->
+ <h3 id="gcccompat">GCC Compatibility</h3>
+ <!--=======================================================================-->
+
+ <p>The number one goal of the driver is to ease the adoption of
+ Clang by allowing users to drop Clang into a build system
+ which was designed to call GCC. Although this makes the driver
+ much more complicated than might otherwise be necessary, we
+ decided that being very compatible with the gcc command line
+ interface was worth it in order to allow users to quickly test
+ clang on their projects.</p>
+
+ <!--=======================================================================-->
+ <h3 id="components">Flexible</h3>
+ <!--=======================================================================-->
+
+ <p>The driver was designed to be flexible and easily accomodate
+ new uses as we grow the clang and LLVM infrastructure. As one
+ example, the driver can easily support the introduction of
+ tools which have an integrated assembler; something we hope to
+ add to LLVM in the future.</p>
+
+ <p>Similarly, most of the driver functionality is kept in a
+ library which can be used to build other tools which want to
+ implement or accept a gcc like interface. </p>
+
+ <!--=======================================================================-->
+ <h3 id="performance">Low Overhead</h3>
+ <!--=======================================================================-->
+
+ <p>The driver should have as little overhead as possible. In
+ practice, we found that the gcc driver by itself incurred a
+ small but meaningful overhead when compiling many small
+ files. The driver doesn't do much work compared to a
+ compilation, but we have tried to keep it as efficient as
+ possible by following a few simple principles:</p>
+ <ul>
+ <li>Avoid memory allocation and string copying when
+ possible.</li>
+
+ <li>Don't parse arguments more than once.</li>
+
+ <li>Provide a few simple interfaces for efficiently searching
+ arguments.</li>
+ </ul>
+
+ <!--=======================================================================-->
+ <h3 id="simple">Simple</h3>
+ <!--=======================================================================-->
+
+ <p>Finally, the driver was designed to be "as simple as
+ possible", given the other goals. Notably, trying to be
+ completely compatible with the gcc driver adds a significant
+ amount of complexity. However, the design of the driver
+ attempts to mitigate this complexity by dividing the process
+ into a number of independent stages instead of a single
+ monolithic task.</p>
+
+ <!-- ======================================================================= -->
+ <h2 id="design">Internal Design and Implementation</h2>
+ <!-- ======================================================================= -->
+
+ <ul>
+ <li><a href="#int_intro">Internals Introduction</a></li>
+ <li><a href="#int_overview">Design Overview</a></li>
+ <li><a href="#int_notes">Additional Notes</a></li>
+ <li><a href="#int_gcc_concepts">Relation to GCC Driver Concepts</a></li>
+ </ul>
+
+ <!--=======================================================================-->
+ <h3><a name="int_intro">Internals Introduction</a></h3>
+ <!--=======================================================================-->
+
+ <p>In order to satisfy the stated goals, the driver was designed
+ to completely subsume the functionality of the gcc executable;
+ that is, the driver should not need to delegate to gcc to
+ perform subtasks. On Darwin, this implies that the Clang
+ driver also subsumes the gcc driver-driver, which is used to
+ implement support for building universal images (binaries and
+ object files). This also implies that the driver should be
+ able to call the language specific compilers (e.g. cc1)
+ directly, which means that it must have enough information to
+ forward command line arguments to child processes
+ correctly.</p>
+
+ <!--=======================================================================-->
+ <h3><a name="int_overview">Design Overview</a></h3>
+ <!--=======================================================================-->
+
+ <p>The diagram below shows the significant components of the
+ driver architecture and how they relate to one another. The
+ orange components represent concrete data structures built by
+ the driver, the green components indicate conceptually
+ distinct stages which manipulate these data structures, and
+ the blue components are important helper classes. </p>
+
+ <center>
+ <a href="DriverArchitecture.png" alt="Driver Architecture Diagram">
+ <img width=400 src="DriverArchitecture.png">
+ </a>
+ </center>
+
+ <!--=======================================================================-->
+ <h3><a name="int_stages">Driver Stages</a></h3>
+ <!--=======================================================================-->
+
+ <p>The driver functionality is conceptually divided into five stages:</p>
+
+ <ol>
+ <li>
+ <b>Parse: Option Parsing</b>
+
+ <p>The command line argument strings are decomposed into
+ arguments (<tt>Arg</tt> instances). The driver expects to
+ understand all available options, although there is some
+ facility for just passing certain classes of options
+ through (like <tt>-Wl,</tt>).</p>
+
+ <p>Each argument corresponds to exactly one
+ abstract <tt>Option</tt> definition, which describes how
+ the option is parsed along with some additional
+ metadata. The Arg instances themselves are lightweight and
+ merely contain enough information for clients to determine
+ which option they correspond to and their values (if they
+ have additional parameters).</p>
+
+ <p>For example, a command line like "-Ifoo -I foo" would
+ parse to two Arg instances (a JoinedArg and a SeparateArg
+ instance), but each would refer to the same Option.</p>
+
+ <p>Options are lazily created in order to avoid populating
+ all Option classes when the driver is loaded. Most of the
+ driver code only needs to deal with options by their
+ unique ID (e.g., <tt>options::OPT_I</tt>),</p>
+
+ <p>Arg instances themselves do not generally store the
+ values of parameters. In many cases, this would
+ simply result in creating unnecessary string
+ copies. Instead, Arg instances are always embedded inside
+ an ArgList structure, which contains the original vector
+ of argument strings. Each Arg itself only needs to contain
+ an index into this vector instead of storing its values
+ directly.</p>
+
+ <p>The clang driver can dump the results of this
+ stage using the <tt>-ccc-print-options</tt> flag (which
+ must preceed any actual command line arguments). For
+ example:</p>
+ <pre>
+ $ <b>clang -ccc-print-options -Xarch_i386 -fomit-frame-pointer -Wa,-fast -Ifoo -I foo t.c</b>
+ Option 0 - Name: "-Xarch_", Values: {"i386", "-fomit-frame-pointer"}
+ Option 1 - Name: "-Wa,", Values: {"-fast"}
+ Option 2 - Name: "-I", Values: {"foo"}
+ Option 3 - Name: "-I", Values: {"foo"}
+ Option 4 - Name: "&lt;input&gt;", Values: {"t.c"}
+ </pre>
+
+ <p>After this stage is complete the command line should be
+ broken down into well defined option objects with their
+ appropriate parameters. Subsequent stages should rarely,
+ if ever, need to do any string processing.</p>
+ </li>
+
+ <li>
+ <b>Pipeline: Compilation Job Construction</b>
+
+ <p>Once the arguments are parsed, the tree of subprocess
+ jobs needed for the desired compilation sequence are
+ constructed. This involves determing the input files and
+ their types, what work is to be done on them (preprocess,
+ compile, assemble, link, etc.), and constructing a list of
+ Action instances for each task. The result is a list of
+ one or more top-level actions, each of which generally
+ corresponds to a single output (for example, an object or
+ linked executable).</p>
+
+ <p>The majority of Actions correspond to actual tasks,
+ however there are two special Actions. The first is
+ InputAction, which simply serves to adapt an input
+ argument for use as an input to other Actions. The second
+ is BindArchAction, which conceptually alters the
+ architecture to be used for all of its input Actions.</p>
+
+ <p>The clang driver can dump the results of this
+ stage using the <tt>-ccc-print-phases</tt> flag. For
+ example:</p>
+ <pre>
+ $ <b>clang -ccc-print-phases -x c t.c -x assembler t.s</b>
+ 0: input, "t.c", c
+ 1: preprocessor, {0}, cpp-output
+ 2: compiler, {1}, assembler
+ 3: assembler, {2}, object
+ 4: input, "t.s", assembler
+ 5: assembler, {4}, object
+ 6: linker, {3, 5}, image
+ </pre>
+ <p>Here the driver is constructing seven distinct actions,
+ four to compile the "t.c" input into an object file, two to
+ assemble the "t.s" input, and one to link them together.</p>
+
+ <p>A rather different compilation pipeline is shown here; in
+ this example there are two top level actions to compile
+ the input files into two separate object files, where each
+ object file is built using <tt>lipo</tt> to merge results
+ built for two separate architectures.</p>
+ <pre>
+ $ <b>clang -ccc-print-phases -c -arch i386 -arch x86_64 t0.c t1.c</b>
+ 0: input, "t0.c", c
+ 1: preprocessor, {0}, cpp-output
+ 2: compiler, {1}, assembler
+ 3: assembler, {2}, object
+ 4: bind-arch, "i386", {3}, object
+ 5: bind-arch, "x86_64", {3}, object
+ 6: lipo, {4, 5}, object
+ 7: input, "t1.c", c
+ 8: preprocessor, {7}, cpp-output
+ 9: compiler, {8}, assembler
+ 10: assembler, {9}, object
+ 11: bind-arch, "i386", {10}, object
+ 12: bind-arch, "x86_64", {10}, object
+ 13: lipo, {11, 12}, object
+ </pre>
+
+ <p>After this stage is complete the compilation process is
+ divided into a simple set of actions which need to be
+ performed to produce intermediate or final outputs (in
+ some cases, like <tt>-fsyntax-only</tt>, there is no
+ "real" final output). Phases are well known compilation
+ steps, such as "preprocess", "compile", "assemble",
+ "link", etc.</p>
+ </li>
+
+ <li>
+ <b>Bind: Tool &amp; Filename Selection</b>
+
+ <p>This stage (in conjunction with the Translate stage)
+ turns the tree of Actions into a list of actual subprocess
+ to run. Conceptually, the driver performs a top down
+ matching to assign Action(s) to Tools. The ToolChain is
+ responsible for selecting the tool to perform a particular
+ action; once seleected the driver interacts with the tool
+ to see if it can match additional actions (for example, by
+ having an integrated preprocessor).
+
+ <p>Once Tools have been selected for all actions, the driver
+ determines how the tools should be connected (for example,
+ using an inprocess module, pipes, temporary files, or user
+ provided filenames). If an output file is required, the
+ driver also computes the appropriate file name (the suffix
+ and file location depend on the input types and options
+ such as <tt>-save-temps</tt>).
+
+ <p>The driver interacts with a ToolChain to perform the Tool
+ bindings. Each ToolChain contains information about all
+ the tools needed for compilation for a particular
+ architecture, platform, and operating system. A single
+ driver invocation may query multiple ToolChains during one
+ compilation in order to interact with tools for separate
+ architectures.</p>
+
+ <p>The results of this stage are not computed directly, but
+ the driver can print the results via
+ the <tt>-ccc-print-bindings</tt> option. For example:</p>
+ <pre>
+ $ <b>clang -ccc-print-bindings -arch i386 -arch ppc t0.c</b>
+ # "i386-apple-darwin9" - "clang", inputs: ["t0.c"], output: "/tmp/cc-Sn4RKF.s"
+ # "i386-apple-darwin9" - "darwin::Assemble", inputs: ["/tmp/cc-Sn4RKF.s"], output: "/tmp/cc-gvSnbS.o"
+ # "i386-apple-darwin9" - "darwin::Link", inputs: ["/tmp/cc-gvSnbS.o"], output: "/tmp/cc-jgHQxi.out"
+ # "ppc-apple-darwin9" - "gcc::Compile", inputs: ["t0.c"], output: "/tmp/cc-Q0bTox.s"
+ # "ppc-apple-darwin9" - "gcc::Assemble", inputs: ["/tmp/cc-Q0bTox.s"], output: "/tmp/cc-WCdicw.o"
+ # "ppc-apple-darwin9" - "gcc::Link", inputs: ["/tmp/cc-WCdicw.o"], output: "/tmp/cc-HHBEBh.out"
+ # "i386-apple-darwin9" - "darwin::Lipo", inputs: ["/tmp/cc-jgHQxi.out", "/tmp/cc-HHBEBh.out"], output: "a.out"
+ </pre>
+
+ <p>This shows the tool chain, tool, inputs and outputs which
+ have been bound for this compilation sequence. Here clang
+ is being used to compile t0.c on the i386 architecture and
+ darwin specific versions of the tools are being used to
+ assemble and link the result, but generic gcc versions of
+ the tools are being used on PowerPC.</p>
+ </li>
+
+ <li>
+ <b>Translate: Tool Specific Argument Translation</b>
+
+ <p>Once a Tool has been selected to perform a particular
+ Action, the Tool must construct concrete Jobs which will be
+ executed during compilation. The main work is in translating
+ from the gcc style command line options to whatever options
+ the subprocess expects.</p>
+
+ <p>Some tools, such as the assembler, only interact with a
+ handful of arguments and just determine the path of the
+ executable to call and pass on their input and output
+ arguments. Others, like the compiler or the linker, may
+ translate a large number of arguments in addition.</p>
+
+ <p>The ArgList class provides a number of simple helper
+ methods to assist with translating arguments; for example,
+ to pass on only the last of arguments corresponding to some
+ option, or all arguments for an option.</p>
+
+ <p>The result of this stage is a list of Jobs (executable
+ paths and argument strings) to execute.</p>
+ </li>
+
+ <li>
+ <b>Execute</b>
+ <p>Finally, the compilation pipeline is executed. This is
+ mostly straightforward, although there is some interaction
+ with options
+ like <tt>-pipe</tt>, <tt>-pass-exit-codes</tt>
+ and <tt>-time</tt>.</p>
+ </li>
+
+ </ol>
+
+ <!--=======================================================================-->
+ <h3><a name="int_notes">Additional Notes</a></h3>
+ <!--=======================================================================-->
+
+ <h4 id="int_compilation">The Compilation Object</h4>
+
+ <p>The driver constructs a Compilation object for each set of
+ command line arguments. The Driver itself is intended to be
+ invariant during construct of a Compilation; an IDE should be
+ able to construct a single long lived driver instance to use
+ for an entire build, for example.</p>
+
+ <p>The Compilation object holds information that is particular
+ to each compilation sequence. For example, the list of used
+ temporary files (which must be removed once compilation is
+ finished) and result files (which should be removed if
+ compilation files).</p>
+
+ <h4 id="int_unified_parsing">Unified Parsing &amp; Pipelining</h4>
+
+ <p>Parsing and pipeling both occur without reference to a
+ Compilation instance. This is by design; the driver expects that
+ both of these phases are platform neutral, with a few very well
+ defined exceptions such as whether the platform uses a driver
+ driver.</p>
+
+ <h4 id="int_toolchain_translation">ToolChain Argument Translation</h4>
+
+ <p>In order to match gcc very closely, the clang driver
+ currently allows tool chains to perform their own translation of
+ the argument list (into a new ArgList data structure). Although
+ this allows the clang driver to match gcc easily, it also makes
+ the driver operation much harder to understand (since the Tools
+ stop seeing some arguments the user provided, and see new ones
+ instead).</p>
+
+ <p>For example, on Darwin <tt>-gfull</tt> gets translated into
+ two separate arguments, <tt>-g</tt>
+ and <tt>-fno-eliminate-unused-debug-symbols</tt>. Trying to
+ write Tool logic to do something with <tt>-gfull</tt> will not
+ work, because at Tools run after the arguments have been
+ translated.</p>
+
+ <p>A long term goal is to remove this tool chain specific
+ translation, and instead force each tool to change its own logic
+ to do the right thing on the untranslated original arguments.</p>
+
+ <h4 id="int_unused_warnings">Unused Argument Warnings</h4>
+ <p>The driver operates by parsing all arguments but giving Tools
+ the opportunity to choose which arguments to pass on. One
+ downside of this infrastructure is that if the user misspells
+ some option, or is confused about which options to use, some
+ command line arguments the user really cared about may go
+ unused. This problem is particularly important when using
+ clang as a compiler, since the clang compiler does not support
+ anywhere near all the options that gcc does, and we want to make
+ sure users know which ones are being used.</p>
+
+ <p>To support this, the driver maintains a bit associated with
+ each argument of whether it has been used (at all) during the
+ compilation. This bit usually doesn't need to be set by hand,
+ as the key ArgList accessors will set it automatically.</p>
+
+ <p>When a compilation is successful (there are no errors), the
+ driver checks the bit and emits an "unused argument" warning for
+ any arguments which were never accessed. This is conservative
+ (the argument may not have been used to do what the user wanted)
+ but still catches the most obvious cases.</p>
+
+ <!--=======================================================================-->
+ <h3><a name="int_gcc_concepts">Relation to GCC Driver Concepts</a></h3>
+ <!--=======================================================================-->
+
+ <p>For those familiar with the gcc driver, this section provides
+ a brief overview of how things from the gcc driver map to the
+ clang driver.</p>
+
+ <ul>
+ <li>
+ <b>Driver Driver</b>
+ <p>The driver driver is fully integrated into the clang
+ driver. The driver simply constructs additional Actions to
+ bind the architecture during the <i>Pipeline</i>
+ phase. The tool chain specific argument translation is
+ responsible for handling <tt>-Xarch_</tt>.</p>
+
+ <p>The one caveat is that this approach
+ requires <tt>-Xarch_</tt> not be used to alter the
+ compilation itself (for example, one cannot
+ provide <tt>-S</tt> as an <tt>-Xarch_</tt> argument). The
+ driver attempts to reject such invocations, and overall
+ there isn't a good reason to abuse <tt>-Xarch_</tt> to
+ that end in practice.</p>
+
+ <p>The upside is that the clang driver is more efficient and
+ does little extra work to support universal builds. It also
+ provides better error reporting and UI consistency.</p>
+ </li>
+
+ <li>
+ <b>Specs</b>
+ <p>The clang driver has no direct correspondant for
+ "specs". The majority of the functionality that is
+ embedded in specs is in the Tool specific argument
+ translation routines. The parts of specs which control the
+ compilation pipeline are generally part of
+ the <ii>Pipeline</ii> stage.</p>
+ </li>
+
+ <li>
+ <b>Toolchains</b>
+ <p>The gcc driver has no direct understanding of tool
+ chains. Each gcc binary roughly corresponds to the
+ information which is embedded inside a single
+ ToolChain.</p>
+
+ <p>The clang driver is intended to be portable and support
+ complex compilation environments. All platform and tool
+ chain specific code should be protected behind either
+ abstract or well defined interfaces (such as whether the
+ platform supports use as a driver driver).</p>
+ </li>
+ </ul>
+ </div>
+ </body>
+</html>
diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html
new file mode 100644
index 000000000000..a4d5a057ebaa
--- /dev/null
+++ b/docs/InternalsManual.html
@@ -0,0 +1,1676 @@
+<html>
+<head>
+<title>"Clang" CFE Internals Manual</title>
+<link type="text/css" rel="stylesheet" href="../menu.css" />
+<link type="text/css" rel="stylesheet" href="../content.css" />
+<style type="text/css">
+td {
+ vertical-align: top;
+}
+</style>
+</head>
+<body>
+
+<!--#include virtual="../menu.html.incl"-->
+
+<div id="content">
+
+<h1>"Clang" CFE Internals Manual</h1>
+
+<ul>
+<li><a href="#intro">Introduction</a></li>
+<li><a href="#libsystem">LLVM System and Support Libraries</a></li>
+<li><a href="#libbasic">The Clang 'Basic' Library</a>
+ <ul>
+ <li><a href="#Diagnostics">The Diagnostics Subsystem</a></li>
+ <li><a href="#SourceLocation">The SourceLocation and SourceManager
+ classes</a></li>
+ </ul>
+</li>
+<li><a href="#libdriver">The Driver Library</a>
+ <ul>
+ </ul>
+</li>
+<li><a href="#pch">Precompiled Headers</a>
+<li><a href="#libfrontend">The Frontend Library</a>
+ <ul>
+ </ul>
+</li>
+<li><a href="#liblex">The Lexer and Preprocessor Library</a>
+ <ul>
+ <li><a href="#Token">The Token class</a></li>
+ <li><a href="#Lexer">The Lexer class</a></li>
+ <li><a href="#AnnotationToken">Annotation Tokens</a></li>
+ <li><a href="#TokenLexer">The TokenLexer class</a></li>
+ <li><a href="#MultipleIncludeOpt">The MultipleIncludeOpt class</a></li>
+ </ul>
+</li>
+<li><a href="#libparse">The Parser Library</a>
+ <ul>
+ </ul>
+</li>
+<li><a href="#libast">The AST Library</a>
+ <ul>
+ <li><a href="#Type">The Type class and its subclasses</a></li>
+ <li><a href="#QualType">The QualType class</a></li>
+ <li><a href="#DeclarationName">Declaration names</a></li>
+ <li><a href="#DeclContext">Declaration contexts</a>
+ <ul>
+ <li><a href="#Redeclarations">Redeclarations and Overloads</a></li>
+ <li><a href="#LexicalAndSemanticContexts">Lexical and Semantic
+ Contexts</a></li>
+ <li><a href="#TransparentContexts">Transparent Declaration Contexts</a></li>
+ <li><a href="#MultiDeclContext">Multiply-Defined Declaration Contexts</a></li>
+ </ul>
+ </li>
+ <li><a href="#CFG">The CFG class</a></li>
+ <li><a href="#Constants">Constant Folding in the Clang AST</a></li>
+ </ul>
+</li>
+</ul>
+
+
+<!-- ======================================================================= -->
+<h2 id="intro">Introduction</h2>
+<!-- ======================================================================= -->
+
+<p>This document describes some of the more important APIs and internal design
+decisions made in the Clang C front-end. The purpose of this document is to
+both capture some of this high level information and also describe some of the
+design decisions behind it. This is meant for people interested in hacking on
+Clang, not for end-users. The description below is categorized by
+libraries, and does not describe any of the clients of the libraries.</p>
+
+<!-- ======================================================================= -->
+<h2 id="libsystem">LLVM System and Support Libraries</h2>
+<!-- ======================================================================= -->
+
+<p>The LLVM libsystem library provides the basic Clang system abstraction layer,
+which is used for file system access. The LLVM libsupport library provides many
+underlying libraries and <a
+href="http://llvm.org/docs/ProgrammersManual.html">data-structures</a>,
+ including command line option
+processing and various containers.</p>
+
+<!-- ======================================================================= -->
+<h2 id="libbasic">The Clang 'Basic' Library</h2>
+<!-- ======================================================================= -->
+
+<p>This library certainly needs a better name. The 'basic' library contains a
+number of low-level utilities for tracking and manipulating source buffers,
+locations within the source buffers, diagnostics, tokens, target abstraction,
+and information about the subset of the language being compiled for.</p>
+
+<p>Part of this infrastructure is specific to C (such as the TargetInfo class),
+other parts could be reused for other non-C-based languages (SourceLocation,
+SourceManager, Diagnostics, FileManager). When and if there is future demand
+we can figure out if it makes sense to introduce a new library, move the general
+classes somewhere else, or introduce some other solution.</p>
+
+<p>We describe the roles of these classes in order of their dependencies.</p>
+
+
+<!-- ======================================================================= -->
+<h3 id="Diagnostics">The Diagnostics Subsystem</h3>
+<!-- ======================================================================= -->
+
+<p>The Clang Diagnostics subsystem is an important part of how the compiler
+communicates with the human. Diagnostics are the warnings and errors produced
+when the code is incorrect or dubious. In Clang, each diagnostic produced has
+(at the minimum) a unique ID, a <a href="#SourceLocation">SourceLocation</a> to
+"put the caret", an English translation associated with it, and a severity (e.g.
+<tt>WARNING</tt> or <tt>ERROR</tt>). They can also optionally include a number
+of arguments to the dianostic (which fill in "%0"'s in the string) as well as a
+number of source ranges that related to the diagnostic.</p>
+
+<p>In this section, we'll be giving examples produced by the Clang command line
+driver, but diagnostics can be <a href="#DiagnosticClient">rendered in many
+different ways</a> depending on how the DiagnosticClient interface is
+implemented. A representative example of a diagonstic is:</p>
+
+<pre>
+t.c:38:15: error: invalid operands to binary expression ('int *' and '_Complex float')
+ <font color="darkgreen">P = (P-42) + Gamma*4;</font>
+ <font color="blue">~~~~~~ ^ ~~~~~~~</font>
+</pre>
+
+<p>In this example, you can see the English translation, the severity (error),
+you can see the source location (the caret ("^") and file/line/column info),
+the source ranges "~~~~", arguments to the diagnostic ("int*" and "_Complex
+float"). You'll have to believe me that there is a unique ID backing the
+diagnostic :).</p>
+
+<p>Getting all of this to happen has several steps and involves many moving
+pieces, this section describes them and talks about best practices when adding
+a new diagnostic.</p>
+
+<!-- ============================ -->
+<h4>The DiagnosticKinds.def file</h4>
+<!-- ============================ -->
+
+<p>Diagnostics are created by adding an entry to the <tt><a
+href="http://llvm.org/svn/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def"
+>DiagnosticKinds.def</a></tt> file. This file encodes the unique ID of the
+diagnostic (as an enum, the first argument), the severity of the diagnostic
+(second argument) and the English translation + format string.</p>
+
+<p>There is little sanity with the naming of the unique ID's right now. Some
+start with err_, warn_, ext_ to encode the severity into the name. Since the
+enum is referenced in the C++ code that produces the diagnostic, it is somewhat
+useful for it to be reasonably short.</p>
+
+<p>The severity of the diagnostic comes from the set {<tt>NOTE</tt>,
+<tt>WARNING</tt>, <tt>EXTENSION</tt>, <tt>EXTWARN</tt>, <tt>ERROR</tt>}. The
+<tt>ERROR</tt> severity is used for diagnostics indicating the program is never
+acceptable under any circumstances. When an error is emitted, the AST for the
+input code may not be fully built. The <tt>EXTENSION</tt> and <tt>EXTWARN</tt>
+severities are used for extensions to the language that Clang accepts. This
+means that Clang fully understands and can represent them in the AST, but we
+produce diagnostics to tell the user their code is non-portable. The difference
+is that the former are ignored by default, and the later warn by default. The
+<tt>WARNING</tt> severity is used for constructs that are valid in the currently
+selected source language but that are dubious in some way. The <tt>NOTE</tt>
+level is used to staple more information onto previous diagnostics.</p>
+
+<p>These <em>severities</em> are mapped into a smaller set (the
+Diagnostic::Level enum, {<tt>Ignored</tt>, <tt>Note</tt>, <tt>Warning</tt>,
+<tt>Error</tt>, <tt>Fatal</tt> }) of output <em>levels</em> by the diagnostics
+subsystem based on various configuration options. Clang internally supports a
+fully fine grained mapping mechanism that allows you to map almost any
+diagnostic to the output level that you want. The only diagnostics that cannot
+be mapped are <tt>NOTE</tt>s, which always follow the severity of the previously
+emitted diagnostic and <tt>ERROR</tt>s, which can only be mapped to
+<tt>Fatal</tt> (it is not possible to turn an error into a warning,
+for example).</p>
+
+<p>Diagnostic mappings are used in many ways. For example, if the user
+specifies <tt>-pedantic</tt>, <tt>EXTENSION</tt> maps to <tt>Warning</tt>, if
+they specify <tt>-pedantic-errors</tt>, it turns into <tt>Error</tt>. This is
+used to implement options like <tt>-Wunused_macros</tt>, <tt>-Wundef</tt> etc.
+</p>
+
+<p>
+Mapping to <tt>Fatal</tt> should only be used for diagnostics that are
+considered so severe that error recovery won't be able to recover sensibly from
+them (thus spewing a ton of bogus errors). One example of this class of error
+are failure to #include a file.
+</p>
+
+<!-- ================= -->
+<h4>The Format String</h4>
+<!-- ================= -->
+
+<p>The format string for the diagnostic is very simple, but it has some power.
+It takes the form of a string in English with markers that indicate where and
+how arguments to the diagnostic are inserted and formatted. For example, here
+are some simple format strings:</p>
+
+<pre>
+ "binary integer literals are an extension"
+ "format string contains '\\0' within the string body"
+ "more '<b>%%</b>' conversions than data arguments"
+ "invalid operands to binary expression (<b>%0</b> and <b>%1</b>)"
+ "overloaded '<b>%0</b>' must be a <b>%select{unary|binary|unary or binary}2</b> operator"
+ " (has <b>%1</b> parameter<b>%s1</b>)"
+</pre>
+
+<p>These examples show some important points of format strings. You can use any
+ plain ASCII character in the diagnostic string except "%" without a problem,
+ but these are C strings, so you have to use and be aware of all the C escape
+ sequences (as in the second example). If you want to produce a "%" in the
+ output, use the "%%" escape sequence, like the third diagnostic. Finally,
+ Clang uses the "%...[digit]" sequences to specify where and how arguments to
+ the diagnostic are formatted.</p>
+
+<p>Arguments to the diagnostic are numbered according to how they are specified
+ by the C++ code that <a href="#producingdiag">produces them</a>, and are
+ referenced by <tt>%0</tt> .. <tt>%9</tt>. If you have more than 10 arguments
+ to your diagnostic, you are doing something wrong :). Unlike printf, there
+ is no requirement that arguments to the diagnostic end up in the output in
+ the same order as they are specified, you could have a format string with
+ <tt>"%1 %0"</tt> that swaps them, for example. The text in between the
+ percent and digit are formatting instructions. If there are no instructions,
+ the argument is just turned into a string and substituted in.</p>
+
+<p>Here are some "best practices" for writing the English format string:</p>
+
+<ul>
+<li>Keep the string short. It should ideally fit in the 80 column limit of the
+ <tt>DiagnosticKinds.def</tt> file. This avoids the diagnostic wrapping when
+ printed, and forces you to think about the important point you are conveying
+ with the diagnostic.</li>
+<li>Take advantage of location information. The user will be able to see the
+ line and location of the caret, so you don't need to tell them that the
+ problem is with the 4th argument to the function: just point to it.</li>
+<li>Do not capitalize the diagnostic string, and do not end it with a
+ period.</li>
+<li>If you need to quote something in the diagnostic string, use single
+ quotes.</li>
+</ul>
+
+<p>Diagnostics should never take random English strings as arguments: you
+shouldn't use <tt>"you have a problem with %0"</tt> and pass in things like
+<tt>"your argument"</tt> or <tt>"your return value"</tt> as arguments. Doing
+this prevents <a href="translation">translating</a> the Clang diagnostics to
+other languages (because they'll get random English words in their otherwise
+localized diagnostic). The exceptions to this are C/C++ language keywords
+(e.g. auto, const, mutable, etc) and C/C++ operators (<tt>/=</tt>). Note
+that things like "pointer" and "reference" are not keywords. On the other
+hand, you <em>can</em> include anything that comes from the user's source code,
+including variable names, types, labels, etc. The 'select' format can be
+used to achieve this sort of thing in a localizable way, see below.</p>
+
+<!-- ==================================== -->
+<h4>Formatting a Diagnostic Argument</a></h4>
+<!-- ==================================== -->
+
+<p>Arguments to diagnostics are fully typed internally, and come from a couple
+different classes: integers, types, names, and random strings. Depending on
+the class of the argument, it can be optionally formatted in different ways.
+This gives the DiagnosticClient information about what the argument means
+without requiring it to use a specific presentation (consider this MVC for
+Clang :).</p>
+
+<p>Here are the different diagnostic argument formats currently supported by
+Clang:</p>
+
+<table>
+<tr><td colspan="2"><b>"s" format</b></td></tr>
+<tr><td>Example:</td><td><tt>"requires %1 parameter%s1"</tt></td></tr>
+<tr><td>Class:</td><td>Integers</td></tr>
+<tr><td>Description:</td><td>This is a simple formatter for integers that is
+ useful when producing English diagnostics. When the integer is 1, it prints
+ as nothing. When the integer is not 1, it prints as "s". This allows some
+ simple grammatical forms to be to be handled correctly, and eliminates the
+ need to use gross things like <tt>"requires %1 parameter(s)"</tt>.</td></tr>
+
+<tr><td colspan="2"><b>"select" format</b></td></tr>
+<tr><td>Example:</td><td><tt>"must be a %select{unary|binary|unary or binary}2
+ operator"</tt></td></tr>
+<tr><td>Class:</td><td>Integers</td></tr>
+<tr><td>Description:</td><td>This format specifier is used to merge multiple
+ related diagnostics together into one common one, without requiring the
+ difference to be specified as an English string argument. Instead of
+ specifying the string, the diagnostic gets an integer argument and the
+ format string selects the numbered option. In this case, the "%2" value
+ must be an integer in the range [0..2]. If it is 0, it prints 'unary', if
+ it is 1 it prints 'binary' if it is 2, it prints 'unary or binary'. This
+ allows other language translations to substitute reasonable words (or entire
+ phrases) based on the semantics of the diagnostic instead of having to do
+ things textually.</td></tr>
+
+<tr><td colspan="2"><b>"plural" format</b></td></tr>
+<tr><td>Example:</td><td><tt>"you have %1 %plural{1:mouse|:mice}1 connected to
+ your computer"</tt></td></tr>
+<tr><td>Class:</td><td>Integers</td></tr>
+<tr><td>Description:</td><td><p>This is a formatter for complex plural forms.
+ It is designed to handle even the requirements of languages with very
+ complex plural forms, as many Baltic languages have. The argument consists
+ of a series of expression/form pairs, separated by ':', where the first form
+ whose expression evaluates to true is the result of the modifier.</p>
+ <p>An expression can be empty, in which case it is always true. See the
+ example at the top. Otherwise, it is a series of one or more numeric
+ conditions, separated by ','. If any condition matches, the expression
+ matches. Each numeric condition can take one of three forms.</p>
+ <ul>
+ <li>number: A simple decimal number matches if the argument is the same
+ as the number. Example: <tt>"%plural{1:mouse|:mice}4"</tt></li>
+ <li>range: A range in square brackets matches if the argument is within
+ the range. Then range is inclusive on both ends. Example:
+ <tt>"%plural{0:none|1:one|[2,5]:some|:many}2"</tt></li>
+ <li>modulo: A modulo operator is followed by a number, and
+ equals sign and either a number or a range. The tests are the
+ same as for plain
+ numbers and ranges, but the argument is taken modulo the number first.
+ Example: <tt>"%plural{%100=0:even hundred|%100=[1,50]:lower half|:everything
+ else}1"</tt></li>
+ </ul>
+ <p>The parser is very unforgiving. A syntax error, even whitespace, will
+ abort, as will a failure to match the argument against any
+ expression.</p></td></tr>
+
+<tr><td colspan="2"><b>"objcclass" format</b></td></tr>
+<tr><td>Example:</td><td><tt>"method %objcclass0 not found"</tt></td></tr>
+<tr><td>Class:</td><td>DeclarationName</td></tr>
+<tr><td>Description:</td><td><p>This is a simple formatter that indicates the
+ DeclarationName corresponds to an Objective-C class method selector. As
+ such, it prints the selector with a leading '+'.</p></td></tr>
+
+<tr><td colspan="2"><b>"objcinstance" format</b></td></tr>
+<tr><td>Example:</td><td><tt>"method %objcinstance0 not found"</tt></td></tr>
+<tr><td>Class:</td><td>DeclarationName</td></tr>
+<tr><td>Description:</td><td><p>This is a simple formatter that indicates the
+ DeclarationName corresponds to an Objective-C instance method selector. As
+ such, it prints the selector with a leading '-'.</p></td></tr>
+
+<tr><td colspan="2"><b>"q" format</b></td></tr>
+<tr><td>Example:</td><td><tt>"candidate found by name lookup is %q0"</tt></td></tr>
+<tr><td>Class:</td><td>NamedDecl*</td></tr>
+<tr><td>Description</td><td><p>This formatter indicates that the fully-qualified name of the declaration should be printed, e.g., "std::vector" rather than "vector".</p></td></tr>
+
+</table>
+
+<p>It is really easy to add format specifiers to the Clang diagnostics system,
+but they should be discussed before they are added. If you are creating a lot
+of repetitive diagnostics and/or have an idea for a useful formatter, please
+bring it up on the cfe-dev mailing list.</p>
+
+<!-- ===================================================== -->
+<h4><a name="#producingdiag">Producing the Diagnostic</a></h4>
+<!-- ===================================================== -->
+
+<p>Now that you've created the diagnostic in the DiagnosticKinds.def file, you
+need to write the code that detects the condition in question and emits the
+new diagnostic. Various components of Clang (e.g. the preprocessor, Sema,
+etc) provide a helper function named "Diag". It creates a diagnostic and
+accepts the arguments, ranges, and other information that goes along with
+it.</p>
+
+<p>For example, the binary expression error comes from code like this:</p>
+
+<pre>
+ if (various things that are bad)
+ Diag(Loc, diag::err_typecheck_invalid_operands)
+ &lt;&lt; lex-&gt;getType() &lt;&lt; rex-&gt;getType()
+ &lt;&lt; lex-&gt;getSourceRange() &lt;&lt; rex-&gt;getSourceRange();
+</pre>
+
+<p>This shows that use of the Diag method: they take a location (a <a
+href="#SourceLocation">SourceLocation</a> object) and a diagnostic enum value
+(which matches the name from DiagnosticKinds.def). If the diagnostic takes
+arguments, they are specified with the &lt;&lt; operator: the first argument
+becomes %0, the second becomes %1, etc. The diagnostic interface allows you to
+specify arguments of many different types, including <tt>int</tt> and
+<tt>unsigned</tt> for integer arguments, <tt>const char*</tt> and
+<tt>std::string</tt> for string arguments, <tt>DeclarationName</tt> and
+<tt>const IdentifierInfo*</tt> for names, <tt>QualType</tt> for types, etc.
+SourceRanges are also specified with the &lt;&lt; operator, but do not have a
+specific ordering requirement.</p>
+
+<p>As you can see, adding and producing a diagnostic is pretty straightforward.
+The hard part is deciding exactly what you need to say to help the user, picking
+a suitable wording, and providing the information needed to format it correctly.
+The good news is that the call site that issues a diagnostic should be
+completely independent of how the diagnostic is formatted and in what language
+it is rendered.
+</p>
+
+<!-- ==================================================== -->
+<h4 id="code-modification-hints">Code Modification Hints</h4>
+<!-- ==================================================== -->
+
+<p>In some cases, the front end emits diagnostics when it is clear
+that some small change to the source code would fix the problem. For
+example, a missing semicolon at the end of a statement or a use of
+deprecated syntax that is easily rewritten into a more modern form.
+Clang tries very hard to emit the diagnostic and recover gracefully
+in these and other cases.</p>
+
+<p>However, for these cases where the fix is obvious, the diagnostic
+can be annotated with a code
+modification "hint" that describes how to change the code referenced
+by the diagnostic to fix the problem. For example, it might add the
+missing semicolon at the end of the statement or rewrite the use of a
+deprecated construct into something more palatable. Here is one such
+example C++ front end, where we warn about the right-shift operator
+changing meaning from C++98 to C++0x:</p>
+
+<pre>
+test.cpp:3:7: warning: use of right-shift operator ('&gt;&gt;') in template argument will require parentheses in C++0x
+A&lt;100 &gt;&gt; 2&gt; *a;
+ ^
+ ( )
+</pre>
+
+<p>Here, the code modification hint is suggesting that parentheses be
+added, and showing exactly where those parentheses would be inserted
+into the source code. The code modification hints themselves describe
+what changes to make to the source code in an abstract manner, which
+the text diagnostic printer renders as a line of "insertions" below
+the caret line. <a href="#DiagnosticClient">Other diagnostic
+clients</a> might choose to render the code differently (e.g., as
+markup inline) or even give the user the ability to automatically fix
+the problem.</p>
+
+<p>All code modification hints are described by the
+<code>CodeModificationHint</code> class, instances of which should be
+attached to the diagnostic using the &lt;&lt; operator in the same way
+that highlighted source ranges and arguments are passed to the
+diagnostic. Code modification hints can be created with one of three
+constructors:</p>
+
+<dl>
+ <dt><code>CodeModificationHint::CreateInsertion(Loc, Code)</code></dt>
+ <dd>Specifies that the given <code>Code</code> (a string) should be inserted
+ before the source location <code>Loc</code>.</dd>
+
+ <dt><code>CodeModificationHint::CreateRemoval(Range)</code></dt>
+ <dd>Specifies that the code in the given source <code>Range</code>
+ should be removed.</dd>
+
+ <dt><code>CodeModificationHint::CreateReplacement(Range, Code)</code></dt>
+ <dd>Specifies that the code in the given source <code>Range</code>
+ should be removed, and replaced with the given <code>Code</code> string.</dd>
+</dl>
+
+<!-- ============================================================= -->
+<h4><a name="DiagnosticClient">The DiagnosticClient Interface</a></h4>
+<!-- ============================================================= -->
+
+<p>Once code generates a diagnostic with all of the arguments and the rest of
+the relevant information, Clang needs to know what to do with it. As previously
+mentioned, the diagnostic machinery goes through some filtering to map a
+severity onto a diagnostic level, then (assuming the diagnostic is not mapped to
+"<tt>Ignore</tt>") it invokes an object that implements the DiagnosticClient
+interface with the information.</p>
+
+<p>It is possible to implement this interface in many different ways. For
+example, the normal Clang DiagnosticClient (named 'TextDiagnosticPrinter') turns
+the arguments into strings (according to the various formatting rules), prints
+out the file/line/column information and the string, then prints out the line of
+code, the source ranges, and the caret. However, this behavior isn't required.
+</p>
+
+<p>Another implementation of the DiagnosticClient interface is the
+'TextDiagnosticBuffer' class, which is used when Clang is in -verify mode.
+Instead of formatting and printing out the diagnostics, this implementation just
+captures and remembers the diagnostics as they fly by. Then -verify compares
+the list of produced diagnostics to the list of expected ones. If they disagree,
+it prints out its own output.
+</p>
+
+<p>There are many other possible implementations of this interface, and this is
+why we prefer diagnostics to pass down rich structured information in arguments.
+For example, an HTML output might want declaration names be linkified to where
+they come from in the source. Another example is that a GUI might let you click
+on typedefs to expand them. This application would want to pass significantly
+more information about types through to the GUI than a simple flat string. The
+interface allows this to happen.</p>
+
+<!-- ====================================================== -->
+<h4><a name="translation">Adding Translations to Clang</a></h4>
+<!-- ====================================================== -->
+
+<p>Not possible yet! Diagnostic strings should be written in UTF-8, the client
+can translate to the relevant code page if needed. Each translation completely
+replaces the format string for the diagnostic.</p>
+
+
+<!-- ======================================================================= -->
+<h3 id="SourceLocation">The SourceLocation and SourceManager classes</h3>
+<!-- ======================================================================= -->
+
+<p>Strangely enough, the SourceLocation class represents a location within the
+source code of the program. Important design points include:</p>
+
+<ol>
+<li>sizeof(SourceLocation) must be extremely small, as these are embedded into
+ many AST nodes and are passed around often. Currently it is 32 bits.</li>
+<li>SourceLocation must be a simple value object that can be efficiently
+ copied.</li>
+<li>We should be able to represent a source location for any byte of any input
+ file. This includes in the middle of tokens, in whitespace, in trigraphs,
+ etc.</li>
+<li>A SourceLocation must encode the current #include stack that was active when
+ the location was processed. For example, if the location corresponds to a
+ token, it should contain the set of #includes active when the token was
+ lexed. This allows us to print the #include stack for a diagnostic.</li>
+<li>SourceLocation must be able to describe macro expansions, capturing both
+ the ultimate instantiation point and the source of the original character
+ data.</li>
+</ol>
+
+<p>In practice, the SourceLocation works together with the SourceManager class
+to encode two pieces of information about a location: it's spelling location
+and it's instantiation location. For most tokens, these will be the same. However,
+for a macro expansion (or tokens that came from a _Pragma directive) these will
+describe the location of the characters corresponding to the token and the
+location where the token was used (i.e. the macro instantiation point or the
+location of the _Pragma itself).</p>
+
+<p>For efficiency, we only track one level of macro instantiations: if a token was
+produced by multiple instantiations, we only track the source and ultimate
+destination. Though we could track the intermediate instantiation points, this
+would require extra bookkeeping and no known client would benefit substantially
+from this.</p>
+
+<p>The Clang front-end inherently depends on the location of a token being
+tracked correctly. If it is ever incorrect, the front-end may get confused and
+die. The reason for this is that the notion of the 'spelling' of a Token in
+Clang depends on being able to find the original input characters for the token.
+This concept maps directly to the "spelling location" for the token.</p>
+
+<!-- ======================================================================= -->
+<h2 id="libdriver">The Driver Library</h2>
+<!-- ======================================================================= -->
+
+<p>The clang Driver and library are documented <a
+href="DriverInternals.html">here<a>.<p>
+
+<!-- ======================================================================= -->
+<h2 id="pch">Precompiled Headers</h2>
+<!-- ======================================================================= -->
+
+<p>Clang supports two implementations of precompiled headers. The
+ default implementation, precompiled headers (<a
+ href="PCHInternals.html">PCH</a>) uses a serialized representation
+ of Clang's internal data structures, encoded with the <a
+ href="http://llvm.org/docs/BitCodeFormat.html">LLVM bitstream
+ format</a>. Pretokenized headers (<a
+ href="PTHInternals.html">PTH</a>), on the other hand, contain a
+ serialized representation of the tokens encountered when
+ preprocessing a header (and anything that header includes).</p>
+
+
+<!-- ======================================================================= -->
+<h2 id="libfrontend">The Frontend Library</h2>
+<!-- ======================================================================= -->
+
+<p>The Frontend library contains functionality useful for building
+tools on top of the clang libraries, for example several methods for
+outputting diagnostics.</p>
+
+<!-- ======================================================================= -->
+<h2 id="liblex">The Lexer and Preprocessor Library</h2>
+<!-- ======================================================================= -->
+
+<p>The Lexer library contains several tightly-connected classes that are involved
+with the nasty process of lexing and preprocessing C source code. The main
+interface to this library for outside clients is the large <a
+href="#Preprocessor">Preprocessor</a> class.
+It contains the various pieces of state that are required to coherently read
+tokens out of a translation unit.</p>
+
+<p>The core interface to the Preprocessor object (once it is set up) is the
+Preprocessor::Lex method, which returns the next <a href="#Token">Token</a> from
+the preprocessor stream. There are two types of token providers that the
+preprocessor is capable of reading from: a buffer lexer (provided by the <a
+href="#Lexer">Lexer</a> class) and a buffered token stream (provided by the <a
+href="#TokenLexer">TokenLexer</a> class).
+
+
+<!-- ======================================================================= -->
+<h3 id="Token">The Token class</h3>
+<!-- ======================================================================= -->
+
+<p>The Token class is used to represent a single lexed token. Tokens are
+intended to be used by the lexer/preprocess and parser libraries, but are not
+intended to live beyond them (for example, they should not live in the ASTs).<p>
+
+<p>Tokens most often live on the stack (or some other location that is efficient
+to access) as the parser is running, but occasionally do get buffered up. For
+example, macro definitions are stored as a series of tokens, and the C++
+front-end periodically needs to buffer tokens up for tentative parsing and
+various pieces of look-ahead. As such, the size of a Token matter. On a 32-bit
+system, sizeof(Token) is currently 16 bytes.</p>
+
+<p>Tokens occur in two forms: "<a href="#AnnotationToken">Annotation
+Tokens</a>" and normal tokens. Normal tokens are those returned by the lexer,
+annotation tokens represent semantic information and are produced by the parser,
+replacing normal tokens in the token stream. Normal tokens contain the
+following information:</p>
+
+<ul>
+<li><b>A SourceLocation</b> - This indicates the location of the start of the
+token.</li>
+
+<li><b>A length</b> - This stores the length of the token as stored in the
+SourceBuffer. For tokens that include them, this length includes trigraphs and
+escaped newlines which are ignored by later phases of the compiler. By pointing
+into the original source buffer, it is always possible to get the original
+spelling of a token completely accurately.</li>
+
+<li><b>IdentifierInfo</b> - If a token takes the form of an identifier, and if
+identifier lookup was enabled when the token was lexed (e.g. the lexer was not
+reading in 'raw' mode) this contains a pointer to the unique hash value for the
+identifier. Because the lookup happens before keyword identification, this
+field is set even for language keywords like 'for'.</li>
+
+<li><b>TokenKind</b> - This indicates the kind of token as classified by the
+lexer. This includes things like <tt>tok::starequal</tt> (for the "*="
+operator), <tt>tok::ampamp</tt> for the "&amp;&amp;" token, and keyword values
+(e.g. <tt>tok::kw_for</tt>) for identifiers that correspond to keywords. Note
+that some tokens can be spelled multiple ways. For example, C++ supports
+"operator keywords", where things like "and" are treated exactly like the
+"&amp;&amp;" operator. In these cases, the kind value is set to
+<tt>tok::ampamp</tt>, which is good for the parser, which doesn't have to
+consider both forms. For something that cares about which form is used (e.g.
+the preprocessor 'stringize' operator) the spelling indicates the original
+form.</li>
+
+<li><b>Flags</b> - There are currently four flags tracked by the
+lexer/preprocessor system on a per-token basis:
+
+ <ol>
+ <li><b>StartOfLine</b> - This was the first token that occurred on its input
+ source line.</li>
+ <li><b>LeadingSpace</b> - There was a space character either immediately
+ before the token or transitively before the token as it was expanded
+ through a macro. The definition of this flag is very closely defined by
+ the stringizing requirements of the preprocessor.</li>
+ <li><b>DisableExpand</b> - This flag is used internally to the preprocessor to
+ represent identifier tokens which have macro expansion disabled. This
+ prevents them from being considered as candidates for macro expansion ever
+ in the future.</li>
+ <li><b>NeedsCleaning</b> - This flag is set if the original spelling for the
+ token includes a trigraph or escaped newline. Since this is uncommon,
+ many pieces of code can fast-path on tokens that did not need cleaning.
+ </p>
+ </ol>
+</li>
+</ul>
+
+<p>One interesting (and somewhat unusual) aspect of normal tokens is that they
+don't contain any semantic information about the lexed value. For example, if
+the token was a pp-number token, we do not represent the value of the number
+that was lexed (this is left for later pieces of code to decide). Additionally,
+the lexer library has no notion of typedef names vs variable names: both are
+returned as identifiers, and the parser is left to decide whether a specific
+identifier is a typedef or a variable (tracking this requires scope information
+among other things). The parser can do this translation by replacing tokens
+returned by the preprocessor with "Annotation Tokens".</p>
+
+<!-- ======================================================================= -->
+<h3 id="AnnotationToken">Annotation Tokens</h3>
+<!-- ======================================================================= -->
+
+<p>Annotation Tokens are tokens that are synthesized by the parser and injected
+into the preprocessor's token stream (replacing existing tokens) to record
+semantic information found by the parser. For example, if "foo" is found to be
+a typedef, the "foo" <tt>tok::identifier</tt> token is replaced with an
+<tt>tok::annot_typename</tt>. This is useful for a couple of reasons: 1) this
+makes it easy to handle qualified type names (e.g. "foo::bar::baz&lt;42&gt;::t")
+in C++ as a single "token" in the parser. 2) if the parser backtracks, the
+reparse does not need to redo semantic analysis to determine whether a token
+sequence is a variable, type, template, etc.</p>
+
+<p>Annotation Tokens are created by the parser and reinjected into the parser's
+token stream (when backtracking is enabled). Because they can only exist in
+tokens that the preprocessor-proper is done with, it doesn't need to keep around
+flags like "start of line" that the preprocessor uses to do its job.
+Additionally, an annotation token may "cover" a sequence of preprocessor tokens
+(e.g. <tt>a::b::c</tt> is five preprocessor tokens). As such, the valid fields
+of an annotation token are different than the fields for a normal token (but
+they are multiplexed into the normal Token fields):</p>
+
+<ul>
+<li><b>SourceLocation "Location"</b> - The SourceLocation for the annotation
+token indicates the first token replaced by the annotation token. In the example
+above, it would be the location of the "a" identifier.</li>
+
+<li><b>SourceLocation "AnnotationEndLoc"</b> - This holds the location of the
+last token replaced with the annotation token. In the example above, it would
+be the location of the "c" identifier.</li>
+
+<li><b>void* "AnnotationValue"</b> - This contains an opaque object that the
+parser gets from Sema through an Actions module, it is passed around and Sema
+intepretes it, based on the type of annotation token.</li>
+
+<li><b>TokenKind "Kind"</b> - This indicates the kind of Annotation token this
+is. See below for the different valid kinds.</li>
+</ul>
+
+<p>Annotation tokens currently come in three kinds:</p>
+
+<ol>
+<li><b>tok::annot_typename</b>: This annotation token represents a
+resolved typename token that is potentially qualified. The AnnotationValue
+field contains a pointer returned by Action::getTypeName(). In the case of the
+Sema actions module, this is a <tt>Decl*</tt> for the type.</li>
+
+<li><b>tok::annot_cxxscope</b>: This annotation token represents a C++ scope
+specifier, such as "A::B::". This corresponds to the grammar productions "::"
+and ":: [opt] nested-name-specifier". The AnnotationValue pointer is returned
+by the Action::ActOnCXXGlobalScopeSpecifier and
+Action::ActOnCXXNestedNameSpecifier callbacks. In the case of Sema, this is a
+<tt>DeclContext*</tt>.</li>
+
+<li><b>tok::annot_template_id</b>: This annotation token represents a
+C++ template-id such as "foo&lt;int, 4&gt;", where "foo" is the name
+of a template. The AnnotationValue pointer is a pointer to a malloc'd
+TemplateIdAnnotation object. Depending on the context, a parsed template-id that names a type might become a typename annotation token (if all we care about is the named type, e.g., because it occurs in a type specifier) or might remain a template-id token (if we want to retain more source location information or produce a new type, e.g., in a declaration of a class template specialization). template-id annotation tokens that refer to a type can be "upgraded" to typename annotation tokens by the parser.</li>
+
+</ol>
+
+<p>As mentioned above, annotation tokens are not returned by the preprocessor,
+they are formed on demand by the parser. This means that the parser has to be
+aware of cases where an annotation could occur and form it where appropriate.
+This is somewhat similar to how the parser handles Translation Phase 6 of C99:
+String Concatenation (see C99 5.1.1.2). In the case of string concatenation,
+the preprocessor just returns distinct tok::string_literal and
+tok::wide_string_literal tokens and the parser eats a sequence of them wherever
+the grammar indicates that a string literal can occur.</p>
+
+<p>In order to do this, whenever the parser expects a tok::identifier or
+tok::coloncolon, it should call the TryAnnotateTypeOrScopeToken or
+TryAnnotateCXXScopeToken methods to form the annotation token. These methods
+will maximally form the specified annotation tokens and replace the current
+token with them, if applicable. If the current tokens is not valid for an
+annotation token, it will remain an identifier or :: token.</p>
+
+
+
+<!-- ======================================================================= -->
+<h3 id="Lexer">The Lexer class</h3>
+<!-- ======================================================================= -->
+
+<p>The Lexer class provides the mechanics of lexing tokens out of a source
+buffer and deciding what they mean. The Lexer is complicated by the fact that
+it operates on raw buffers that have not had spelling eliminated (this is a
+necessity to get decent performance), but this is countered with careful coding
+as well as standard performance techniques (for example, the comment handling
+code is vectorized on X86 and PowerPC hosts).</p>
+
+<p>The lexer has a couple of interesting modal features:</p>
+
+<ul>
+<li>The lexer can operate in 'raw' mode. This mode has several features that
+ make it possible to quickly lex the file (e.g. it stops identifier lookup,
+ doesn't specially handle preprocessor tokens, handles EOF differently, etc).
+ This mode is used for lexing within an "<tt>#if 0</tt>" block, for
+ example.</li>
+<li>The lexer can capture and return comments as tokens. This is required to
+ support the -C preprocessor mode, which passes comments through, and is
+ used by the diagnostic checker to identifier expect-error annotations.</li>
+<li>The lexer can be in ParsingFilename mode, which happens when preprocessing
+ after reading a #include directive. This mode changes the parsing of '&lt;'
+ to return an "angled string" instead of a bunch of tokens for each thing
+ within the filename.</li>
+<li>When parsing a preprocessor directive (after "<tt>#</tt>") the
+ ParsingPreprocessorDirective mode is entered. This changes the parser to
+ return EOM at a newline.</li>
+<li>The Lexer uses a LangOptions object to know whether trigraphs are enabled,
+ whether C++ or ObjC keywords are recognized, etc.</li>
+</ul>
+
+<p>In addition to these modes, the lexer keeps track of a couple of other
+ features that are local to a lexed buffer, which change as the buffer is
+ lexed:</p>
+
+<ul>
+<li>The Lexer uses BufferPtr to keep track of the current character being
+ lexed.</li>
+<li>The Lexer uses IsAtStartOfLine to keep track of whether the next lexed token
+ will start with its "start of line" bit set.</li>
+<li>The Lexer keeps track of the current #if directives that are active (which
+ can be nested).</li>
+<li>The Lexer keeps track of an <a href="#MultipleIncludeOpt">
+ MultipleIncludeOpt</a> object, which is used to
+ detect whether the buffer uses the standard "<tt>#ifndef XX</tt> /
+ <tt>#define XX</tt>" idiom to prevent multiple inclusion. If a buffer does,
+ subsequent includes can be ignored if the XX macro is defined.</li>
+</ul>
+
+<!-- ======================================================================= -->
+<h3 id="TokenLexer">The TokenLexer class</h3>
+<!-- ======================================================================= -->
+
+<p>The TokenLexer class is a token provider that returns tokens from a list
+of tokens that came from somewhere else. It typically used for two things: 1)
+returning tokens from a macro definition as it is being expanded 2) returning
+tokens from an arbitrary buffer of tokens. The later use is used by _Pragma and
+will most likely be used to handle unbounded look-ahead for the C++ parser.</p>
+
+<!-- ======================================================================= -->
+<h3 id="MultipleIncludeOpt">The MultipleIncludeOpt class</h3>
+<!-- ======================================================================= -->
+
+<p>The MultipleIncludeOpt class implements a really simple little state machine
+that is used to detect the standard "<tt>#ifndef XX</tt> / <tt>#define XX</tt>"
+idiom that people typically use to prevent multiple inclusion of headers. If a
+buffer uses this idiom and is subsequently #include'd, the preprocessor can
+simply check to see whether the guarding condition is defined or not. If so,
+the preprocessor can completely ignore the include of the header.</p>
+
+
+
+<!-- ======================================================================= -->
+<h2 id="libparse">The Parser Library</h2>
+<!-- ======================================================================= -->
+
+<!-- ======================================================================= -->
+<h2 id="libast">The AST Library</h2>
+<!-- ======================================================================= -->
+
+<!-- ======================================================================= -->
+<h3 id="Type">The Type class and its subclasses</h3>
+<!-- ======================================================================= -->
+
+<p>The Type class (and its subclasses) are an important part of the AST. Types
+are accessed through the ASTContext class, which implicitly creates and uniques
+them as they are needed. Types have a couple of non-obvious features: 1) they
+do not capture type qualifiers like const or volatile (See
+<a href="#QualType">QualType</a>), and 2) they implicitly capture typedef
+information. Once created, types are immutable (unlike decls).</p>
+
+<p>Typedefs in C make semantic analysis a bit more complex than it would
+be without them. The issue is that we want to capture typedef information
+and represent it in the AST perfectly, but the semantics of operations need to
+"see through" typedefs. For example, consider this code:</p>
+
+<code>
+void func() {<br>
+&nbsp;&nbsp;typedef int foo;<br>
+&nbsp;&nbsp;foo X, *Y;<br>
+&nbsp;&nbsp;typedef foo* bar;<br>
+&nbsp;&nbsp;bar Z;<br>
+&nbsp;&nbsp;*X; <i>// error</i><br>
+&nbsp;&nbsp;**Y; <i>// error</i><br>
+&nbsp;&nbsp;**Z; <i>// error</i><br>
+}<br>
+</code>
+
+<p>The code above is illegal, and thus we expect there to be diagnostics emitted
+on the annotated lines. In this example, we expect to get:</p>
+
+<pre>
+<b>test.c:6:1: error: indirection requires pointer operand ('foo' invalid)</b>
+*X; // error
+<font color="blue">^~</font>
+<b>test.c:7:1: error: indirection requires pointer operand ('foo' invalid)</b>
+**Y; // error
+<font color="blue">^~~</font>
+<b>test.c:8:1: error: indirection requires pointer operand ('foo' invalid)</b>
+**Z; // error
+<font color="blue">^~~</font>
+</pre>
+
+<p>While this example is somewhat silly, it illustrates the point: we want to
+retain typedef information where possible, so that we can emit errors about
+"<tt>std::string</tt>" instead of "<tt>std::basic_string&lt;char, std:...</tt>".
+Doing this requires properly keeping typedef information (for example, the type
+of "X" is "foo", not "int"), and requires properly propagating it through the
+various operators (for example, the type of *Y is "foo", not "int"). In order
+to retain this information, the type of these expressions is an instance of the
+TypedefType class, which indicates that the type of these expressions is a
+typedef for foo.
+</p>
+
+<p>Representing types like this is great for diagnostics, because the
+user-specified type is always immediately available. There are two problems
+with this: first, various semantic checks need to make judgements about the
+<em>actual structure</em> of a type, ignoring typdefs. Second, we need an
+efficient way to query whether two types are structurally identical to each
+other, ignoring typedefs. The solution to both of these problems is the idea of
+canonical types.</p>
+
+<!-- =============== -->
+<h4>Canonical Types</h4>
+<!-- =============== -->
+
+<p>Every instance of the Type class contains a canonical type pointer. For
+simple types with no typedefs involved (e.g. "<tt>int</tt>", "<tt>int*</tt>",
+"<tt>int**</tt>"), the type just points to itself. For types that have a
+typedef somewhere in their structure (e.g. "<tt>foo</tt>", "<tt>foo*</tt>",
+"<tt>foo**</tt>", "<tt>bar</tt>"), the canonical type pointer points to their
+structurally equivalent type without any typedefs (e.g. "<tt>int</tt>",
+"<tt>int*</tt>", "<tt>int**</tt>", and "<tt>int*</tt>" respectively).</p>
+
+<p>This design provides a constant time operation (dereferencing the canonical
+type pointer) that gives us access to the structure of types. For example,
+we can trivially tell that "bar" and "foo*" are the same type by dereferencing
+their canonical type pointers and doing a pointer comparison (they both point
+to the single "<tt>int*</tt>" type).</p>
+
+<p>Canonical types and typedef types bring up some complexities that must be
+carefully managed. Specifically, the "isa/cast/dyncast" operators generally
+shouldn't be used in code that is inspecting the AST. For example, when type
+checking the indirection operator (unary '*' on a pointer), the type checker
+must verify that the operand has a pointer type. It would not be correct to
+check that with "<tt>isa&lt;PointerType&gt;(SubExpr-&gt;getType())</tt>",
+because this predicate would fail if the subexpression had a typedef type.</p>
+
+<p>The solution to this problem are a set of helper methods on Type, used to
+check their properties. In this case, it would be correct to use
+"<tt>SubExpr-&gt;getType()-&gt;isPointerType()</tt>" to do the check. This
+predicate will return true if the <em>canonical type is a pointer</em>, which is
+true any time the type is structurally a pointer type. The only hard part here
+is remembering not to use the <tt>isa/cast/dyncast</tt> operations.</p>
+
+<p>The second problem we face is how to get access to the pointer type once we
+know it exists. To continue the example, the result type of the indirection
+operator is the pointee type of the subexpression. In order to determine the
+type, we need to get the instance of PointerType that best captures the typedef
+information in the program. If the type of the expression is literally a
+PointerType, we can return that, otherwise we have to dig through the
+typedefs to find the pointer type. For example, if the subexpression had type
+"<tt>foo*</tt>", we could return that type as the result. If the subexpression
+had type "<tt>bar</tt>", we want to return "<tt>foo*</tt>" (note that we do
+<em>not</em> want "<tt>int*</tt>"). In order to provide all of this, Type has
+a getAsPointerType() method that checks whether the type is structurally a
+PointerType and, if so, returns the best one. If not, it returns a null
+pointer.</p>
+
+<p>This structure is somewhat mystical, but after meditating on it, it will
+make sense to you :).</p>
+
+<!-- ======================================================================= -->
+<h3 id="QualType">The QualType class</h3>
+<!-- ======================================================================= -->
+
+<p>The QualType class is designed as a trivial value class that is small,
+passed by-value and is efficient to query. The idea of QualType is that it
+stores the type qualifiers (const, volatile, restrict) separately from the types
+themselves: QualType is conceptually a pair of "Type*" and bits for the type
+qualifiers.</p>
+
+<p>By storing the type qualifiers as bits in the conceptual pair, it is
+extremely efficient to get the set of qualifiers on a QualType (just return the
+field of the pair), add a type qualifier (which is a trivial constant-time
+operation that sets a bit), and remove one or more type qualifiers (just return
+a QualType with the bitfield set to empty).</p>
+
+<p>Further, because the bits are stored outside of the type itself, we do not
+need to create duplicates of types with different sets of qualifiers (i.e. there
+is only a single heap allocated "int" type: "const int" and "volatile const int"
+both point to the same heap allocated "int" type). This reduces the heap size
+used to represent bits and also means we do not have to consider qualifiers when
+uniquing types (<a href="#Type">Type</a> does not even contain qualifiers).</p>
+
+<p>In practice, on hosts where it is safe, the 3 type qualifiers are stored in
+the low bit of the pointer to the Type object. This means that QualType is
+exactly the same size as a pointer, and this works fine on any system where
+malloc'd objects are at least 8 byte aligned.</p>
+
+<!-- ======================================================================= -->
+<h3 id="DeclarationName">Declaration names</h3>
+<!-- ======================================================================= -->
+
+<p>The <tt>DeclarationName</tt> class represents the name of a
+ declaration in Clang. Declarations in the C family of languages can
+ take several different forms. Most declarations are named by
+ simple identifiers, e.g., "<code>f</code>" and "<code>x</code>" in
+ the function declaration <code>f(int x)</code>. In C++, declaration
+ names can also name class constructors ("<code>Class</code>"
+ in <code>struct Class { Class(); }</code>), class destructors
+ ("<code>~Class</code>"), overloaded operator names ("operator+"),
+ and conversion functions ("<code>operator void const *</code>"). In
+ Objective-C, declaration names can refer to the names of Objective-C
+ methods, which involve the method name and the parameters,
+ collectively called a <i>selector</i>, e.g.,
+ "<code>setWidth:height:</code>". Since all of these kinds of
+ entities - variables, functions, Objective-C methods, C++
+ constructors, destructors, and operators - are represented as
+ subclasses of Clang's common <code>NamedDecl</code>
+ class, <code>DeclarationName</code> is designed to efficiently
+ represent any kind of name.</p>
+
+<p>Given
+ a <code>DeclarationName</code> <code>N</code>, <code>N.getNameKind()</code>
+ will produce a value that describes what kind of name <code>N</code>
+ stores. There are 8 options (all of the names are inside
+ the <code>DeclarationName</code> class)</p>
+<dl>
+ <dt>Identifier</dt>
+ <dd>The name is a simple
+ identifier. Use <code>N.getAsIdentifierInfo()</code> to retrieve the
+ corresponding <code>IdentifierInfo*</code> pointing to the actual
+ identifier. Note that C++ overloaded operators (e.g.,
+ "<code>operator+</code>") are represented as special kinds of
+ identifiers. Use <code>IdentifierInfo</code>'s <code>getOverloadedOperatorID</code>
+ function to determine whether an identifier is an overloaded
+ operator name.</dd>
+
+ <dt>ObjCZeroArgSelector, ObjCOneArgSelector,
+ ObjCMultiArgSelector</dt>
+ <dd>The name is an Objective-C selector, which can be retrieved as a
+ <code>Selector</code> instance
+ via <code>N.getObjCSelector()</code>. The three possible name
+ kinds for Objective-C reflect an optimization within
+ the <code>DeclarationName</code> class: both zero- and
+ one-argument selectors are stored as a
+ masked <code>IdentifierInfo</code> pointer, and therefore require
+ very little space, since zero- and one-argument selectors are far
+ more common than multi-argument selectors (which use a different
+ structure).</dd>
+
+ <dt>CXXConstructorName</dt>
+ <dd>The name is a C++ constructor
+ name. Use <code>N.getCXXNameType()</code> to retrieve
+ the <a href="#QualType">type</a> that this constructor is meant to
+ construct. The type is always the canonical type, since all
+ constructors for a given type have the same name.</dd>
+
+ <dt>CXXDestructorName</dt>
+ <dd>The name is a C++ destructor
+ name. Use <code>N.getCXXNameType()</code> to retrieve
+ the <a href="#QualType">type</a> whose destructor is being
+ named. This type is always a canonical type.</dd>
+
+ <dt>CXXConversionFunctionName</dt>
+ <dd>The name is a C++ conversion function. Conversion functions are
+ named according to the type they convert to, e.g., "<code>operator void
+ const *</code>". Use <code>N.getCXXNameType()</code> to retrieve
+ the type that this conversion function converts to. This type is
+ always a canonical type.</dd>
+
+ <dt>CXXOperatorName</dt>
+ <dd>The name is a C++ overloaded operator name. Overloaded operators
+ are named according to their spelling, e.g.,
+ "<code>operator+</code>" or "<code>operator new
+ []</code>". Use <code>N.getCXXOverloadedOperator()</code> to
+ retrieve the overloaded operator (a value of
+ type <code>OverloadedOperatorKind</code>).</dd>
+</dl>
+
+<p><code>DeclarationName</code>s are cheap to create, copy, and
+ compare. They require only a single pointer's worth of storage in
+ the common cases (identifiers, zero-
+ and one-argument Objective-C selectors) and use dense, uniqued
+ storage for the other kinds of
+ names. Two <code>DeclarationName</code>s can be compared for
+ equality (<code>==</code>, <code>!=</code>) using a simple bitwise
+ comparison, can be ordered
+ with <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>,
+ and <code>&gt;=</code> (which provide a lexicographical ordering for
+ normal identifiers but an unspecified ordering for other kinds of
+ names), and can be placed into LLVM <code>DenseMap</code>s
+ and <code>DenseSet</code>s.</p>
+
+<p><code>DeclarationName</code> instances can be created in different
+ ways depending on what kind of name the instance will store. Normal
+ identifiers (<code>IdentifierInfo</code> pointers) and Objective-C selectors
+ (<code>Selector</code>) can be implicitly converted
+ to <code>DeclarationName</code>s. Names for C++ constructors,
+ destructors, conversion functions, and overloaded operators can be retrieved from
+ the <code>DeclarationNameTable</code>, an instance of which is
+ available as <code>ASTContext::DeclarationNames</code>. The member
+ functions <code>getCXXConstructorName</code>, <code>getCXXDestructorName</code>,
+ <code>getCXXConversionFunctionName</code>, and <code>getCXXOperatorName</code>, respectively,
+ return <code>DeclarationName</code> instances for the four kinds of
+ C++ special function names.</p>
+
+<!-- ======================================================================= -->
+<h3 id="DeclContext">Declaration contexts</h3>
+<!-- ======================================================================= -->
+<p>Every declaration in a program exists within some <i>declaration
+ context</i>, such as a translation unit, namespace, class, or
+ function. Declaration contexts in Clang are represented by
+ the <code>DeclContext</code> class, from which the various
+ declaration-context AST nodes
+ (<code>TranslationUnitDecl</code>, <code>NamespaceDecl</code>, <code>RecordDecl</code>, <code>FunctionDecl</code>,
+ etc.) will derive. The <code>DeclContext</code> class provides
+ several facilities common to each declaration context:</p>
+<dl>
+ <dt>Source-centric vs. Semantics-centric View of Declarations</dt>
+ <dd><code>DeclContext</code> provides two views of the declarations
+ stored within a declaration context. The source-centric view
+ accurately represents the program source code as written, including
+ multiple declarations of entities where present (see the
+ section <a href="#Redeclarations">Redeclarations and
+ Overloads</a>), while the semantics-centric view represents the
+ program semantics. The two views are kept synchronized by semantic
+ analysis while the ASTs are being constructed.</dd>
+
+ <dt>Storage of declarations within that context</dt>
+ <dd>Every declaration context can contain some number of
+ declarations. For example, a C++ class (represented
+ by <code>RecordDecl</code>) contains various member functions,
+ fields, nested types, and so on. All of these declarations will be
+ stored within the <code>DeclContext</code>, and one can iterate
+ over the declarations via
+ [<code>DeclContext::decls_begin()</code>,
+ <code>DeclContext::decls_end()</code>). This mechanism provides
+ the source-centric view of declarations in the context.</dd>
+
+ <dt>Lookup of declarations within that context</dt>
+ <dd>The <code>DeclContext</code> structure provides efficient name
+ lookup for names within that declaration context. For example,
+ if <code>N</code> is a namespace we can look for the
+ name <code>N::f</code>
+ using <code>DeclContext::lookup</code>. The lookup itself is
+ based on a lazily-constructed array (for declaration contexts
+ with a small number of declarations) or hash table (for
+ declaration contexts with more declarations). The lookup
+ operation provides the semantics-centric view of the declarations
+ in the context.</dd>
+
+ <dt>Ownership of declarations</dt>
+ <dd>The <code>DeclContext</code> owns all of the declarations that
+ were declared within its declaration context, and is responsible
+ for the management of their memory as well as their
+ (de-)serialization.</dd>
+</dl>
+
+<p>All declarations are stored within a declaration context, and one
+ can query
+ information about the context in which each declaration lives. One
+ can retrieve the <code>DeclContext</code> that contains a
+ particular <code>Decl</code>
+ using <code>Decl::getDeclContext</code>. However, see the
+ section <a href="#LexicalAndSemanticContexts">Lexical and Semantic
+ Contexts</a> for more information about how to interpret this
+ context information.</p>
+
+<h4 id="Redeclarations">Redeclarations and Overloads</h4>
+<p>Within a translation unit, it is common for an entity to be
+declared several times. For example, we might declare a function "f"
+ and then later re-declare it as part of an inlined definition:</p>
+
+<pre>
+void f(int x, int y, int z = 1);
+
+inline void f(int x, int y, int z) { /* ... */ }
+</pre>
+
+<p>The representation of "f" differs in the source-centric and
+ semantics-centric views of a declaration context. In the
+ source-centric view, all redeclarations will be present, in the
+ order they occurred in the source code, making
+ this view suitable for clients that wish to see the structure of
+ the source code. In the semantics-centric view, only the most recent "f"
+ will be found by the lookup, since it effectively replaces the first
+ declaration of "f".</p>
+
+<p>In the semantics-centric view, overloading of functions is
+ represented explicitly. For example, given two declarations of a
+ function "g" that are overloaded, e.g.,</p>
+<pre>
+void g();
+void g(int);
+</pre>
+<p>the <code>DeclContext::lookup</code> operation will return
+ an <code>OverloadedFunctionDecl</code> that contains both
+ declarations of "g". Clients that perform semantic analysis on a
+ program that is not concerned with the actual source code will
+ primarily use this semantics-centric view.</p>
+
+<h4 id="LexicalAndSemanticContexts">Lexical and Semantic Contexts</h4>
+<p>Each declaration has two potentially different
+ declaration contexts: a <i>lexical</i> context, which corresponds to
+ the source-centric view of the declaration context, and
+ a <i>semantic</i> context, which corresponds to the
+ semantics-centric view. The lexical context is accessible
+ via <code>Decl::getLexicalDeclContext</code> while the
+ semantic context is accessible
+ via <code>Decl::getDeclContext</code>, both of which return
+ <code>DeclContext</code> pointers. For most declarations, the two
+ contexts are identical. For example:</p>
+
+<pre>
+class X {
+public:
+ void f(int x);
+};
+</pre>
+
+<p>Here, the semantic and lexical contexts of <code>X::f</code> are
+ the <code>DeclContext</code> associated with the
+ class <code>X</code> (itself stored as a <code>RecordDecl</code> AST
+ node). However, we can now define <code>X::f</code> out-of-line:</p>
+
+<pre>
+void X::f(int x = 17) { /* ... */ }
+</pre>
+
+<p>This definition of has different lexical and semantic
+ contexts. The lexical context corresponds to the declaration
+ context in which the actual declaration occurred in the source
+ code, e.g., the translation unit containing <code>X</code>. Thus,
+ this declaration of <code>X::f</code> can be found by traversing
+ the declarations provided by
+ [<code>decls_begin()</code>, <code>decls_end()</code>) in the
+ translation unit.</p>
+
+<p>The semantic context of <code>X::f</code> corresponds to the
+ class <code>X</code>, since this member function is (semantically) a
+ member of <code>X</code>. Lookup of the name <code>f</code> into
+ the <code>DeclContext</code> associated with <code>X</code> will
+ then return the definition of <code>X::f</code> (including
+ information about the default argument).</p>
+
+<h4 id="TransparentContexts">Transparent Declaration Contexts</h4>
+<p>In C and C++, there are several contexts in which names that are
+ logically declared inside another declaration will actually "leak"
+ out into the enclosing scope from the perspective of name
+ lookup. The most obvious instance of this behavior is in
+ enumeration types, e.g.,</p>
+<pre>
+enum Color {
+ Red,
+ Green,
+ Blue
+};
+</pre>
+
+<p>Here, <code>Color</code> is an enumeration, which is a declaration
+ context that contains the
+ enumerators <code>Red</code>, <code>Green</code>,
+ and <code>Blue</code>. Thus, traversing the list of declarations
+ contained in the enumeration <code>Color</code> will
+ yield <code>Red</code>, <code>Green</code>,
+ and <code>Blue</code>. However, outside of the scope
+ of <code>Color</code> one can name the enumerator <code>Red</code>
+ without qualifying the name, e.g.,</p>
+
+<pre>
+Color c = Red;
+</pre>
+
+<p>There are other entities in C++ that provide similar behavior. For
+ example, linkage specifications that use curly braces:</p>
+
+<pre>
+extern "C" {
+ void f(int);
+ void g(int);
+}
+// f and g are visible here
+</pre>
+
+<p>For source-level accuracy, we treat the linkage specification and
+ enumeration type as a
+ declaration context in which its enclosed declarations ("Red",
+ "Green", and "Blue"; "f" and "g")
+ are declared. However, these declarations are visible outside of the
+ scope of the declaration context.</p>
+
+<p>These language features (and several others, described below) have
+ roughly the same set of
+ requirements: declarations are declared within a particular lexical
+ context, but the declarations are also found via name lookup in
+ scopes enclosing the declaration itself. This feature is implemented
+ via <i>transparent</i> declaration contexts
+ (see <code>DeclContext::isTransparentContext()</code>), whose
+ declarations are visible in the nearest enclosing non-transparent
+ declaration context. This means that the lexical context of the
+ declaration (e.g., an enumerator) will be the
+ transparent <code>DeclContext</code> itself, as will the semantic
+ context, but the declaration will be visible in every outer context
+ up to and including the first non-transparent declaration context (since
+ transparent declaration contexts can be nested).</p>
+
+<p>The transparent <code>DeclContexts</code> are:</p>
+<ul>
+ <li>Enumerations (but not C++0x "scoped enumerations"):
+ <pre>
+enum Color {
+ Red,
+ Green,
+ Blue
+};
+// Red, Green, and Blue are in scope
+ </pre></li>
+ <li>C++ linkage specifications:
+ <pre>
+extern "C" {
+ void f(int);
+ void g(int);
+}
+// f and g are in scope
+ </pre></li>
+ <li>Anonymous unions and structs:
+ <pre>
+struct LookupTable {
+ bool IsVector;
+ union {
+ std::vector&lt;Item&gt; *Vector;
+ std::set&lt;Item&gt; *Set;
+ };
+};
+
+LookupTable LT;
+LT.Vector = 0; // Okay: finds Vector inside the unnamed union
+ </pre>
+ </li>
+ <li>C++0x inline namespaces:
+<pre>
+namespace mylib {
+ inline namespace debug {
+ class X;
+ }
+}
+mylib::X *xp; // okay: mylib::X refers to mylib::debug::X
+</pre>
+</li>
+</ul>
+
+
+<h4 id="MultiDeclContext">Multiply-Defined Declaration Contexts</h4>
+<p>C++ namespaces have the interesting--and, so far, unique--property that
+the namespace can be defined multiple times, and the declarations
+provided by each namespace definition are effectively merged (from
+the semantic point of view). For example, the following two code
+snippets are semantically indistinguishable:</p>
+<pre>
+// Snippet #1:
+namespace N {
+ void f();
+}
+namespace N {
+ void f(int);
+}
+
+// Snippet #2:
+namespace N {
+ void f();
+ void f(int);
+}
+</pre>
+
+<p>In Clang's representation, the source-centric view of declaration
+ contexts will actually have two separate <code>NamespaceDecl</code>
+ nodes in Snippet #1, each of which is a declaration context that
+ contains a single declaration of "f". However, the semantics-centric
+ view provided by name lookup into the namespace <code>N</code> for
+ "f" will return an <code>OverloadedFunctionDecl</code> that contains
+ both declarations of "f".</p>
+
+<p><code>DeclContext</code> manages multiply-defined declaration
+ contexts internally. The
+ function <code>DeclContext::getPrimaryContext</code> retrieves the
+ "primary" context for a given <code>DeclContext</code> instance,
+ which is the <code>DeclContext</code> responsible for maintaining
+ the lookup table used for the semantics-centric view. Given the
+ primary context, one can follow the chain
+ of <code>DeclContext</code> nodes that define additional
+ declarations via <code>DeclContext::getNextContext</code>. Note that
+ these functions are used internally within the lookup and insertion
+ methods of the <code>DeclContext</code>, so the vast majority of
+ clients can ignore them.</p>
+
+<!-- ======================================================================= -->
+<h3 id="CFG">The <tt>CFG</tt> class</h3>
+<!-- ======================================================================= -->
+
+<p>The <tt>CFG</tt> class is designed to represent a source-level
+control-flow graph for a single statement (<tt>Stmt*</tt>). Typically
+instances of <tt>CFG</tt> are constructed for function bodies (usually
+an instance of <tt>CompoundStmt</tt>), but can also be instantiated to
+represent the control-flow of any class that subclasses <tt>Stmt</tt>,
+which includes simple expressions. Control-flow graphs are especially
+useful for performing
+<a href="http://en.wikipedia.org/wiki/Data_flow_analysis#Sensitivities">flow-
+or path-sensitive</a> program analyses on a given function.</p>
+
+<!-- ============ -->
+<h4>Basic Blocks</h4>
+<!-- ============ -->
+
+<p>Concretely, an instance of <tt>CFG</tt> is a collection of basic
+blocks. Each basic block is an instance of <tt>CFGBlock</tt>, which
+simply contains an ordered sequence of <tt>Stmt*</tt> (each referring
+to statements in the AST). The ordering of statements within a block
+indicates unconditional flow of control from one statement to the
+next. <a href="#ConditionalControlFlow">Conditional control-flow</a>
+is represented using edges between basic blocks. The statements
+within a given <tt>CFGBlock</tt> can be traversed using
+the <tt>CFGBlock::*iterator</tt> interface.</p>
+
+<p>
+A <tt>CFG</tt> object owns the instances of <tt>CFGBlock</tt> within
+the control-flow graph it represents. Each <tt>CFGBlock</tt> within a
+CFG is also uniquely numbered (accessible
+via <tt>CFGBlock::getBlockID()</tt>). Currently the number is
+based on the ordering the blocks were created, but no assumptions
+should be made on how <tt>CFGBlock</tt>s are numbered other than their
+numbers are unique and that they are numbered from 0..N-1 (where N is
+the number of basic blocks in the CFG).</p>
+
+<!-- ===================== -->
+<h4>Entry and Exit Blocks</h4>
+<!-- ===================== -->
+
+Each instance of <tt>CFG</tt> contains two special blocks:
+an <i>entry</i> block (accessible via <tt>CFG::getEntry()</tt>), which
+has no incoming edges, and an <i>exit</i> block (accessible
+via <tt>CFG::getExit()</tt>), which has no outgoing edges. Neither
+block contains any statements, and they serve the role of providing a
+clear entrance and exit for a body of code such as a function body.
+The presence of these empty blocks greatly simplifies the
+implementation of many analyses built on top of CFGs.
+
+<!-- ===================================================== -->
+<h4 id ="ConditionalControlFlow">Conditional Control-Flow</h4>
+<!-- ===================================================== -->
+
+<p>Conditional control-flow (such as those induced by if-statements
+and loops) is represented as edges between <tt>CFGBlock</tt>s.
+Because different C language constructs can induce control-flow,
+each <tt>CFGBlock</tt> also records an extra <tt>Stmt*</tt> that
+represents the <i>terminator</i> of the block. A terminator is simply
+the statement that caused the control-flow, and is used to identify
+the nature of the conditional control-flow between blocks. For
+example, in the case of an if-statement, the terminator refers to
+the <tt>IfStmt</tt> object in the AST that represented the given
+branch.</p>
+
+<p>To illustrate, consider the following code example:</p>
+
+<code>
+int foo(int x) {<br>
+&nbsp;&nbsp;x = x + 1;<br>
+<br>
+&nbsp;&nbsp;if (x > 2) x++;<br>
+&nbsp;&nbsp;else {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;x += 2;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;x *= 2;<br>
+&nbsp;&nbsp;}<br>
+<br>
+&nbsp;&nbsp;return x;<br>
+}
+</code>
+
+<p>After invoking the parser+semantic analyzer on this code fragment,
+the AST of the body of <tt>foo</tt> is referenced by a
+single <tt>Stmt*</tt>. We can then construct an instance
+of <tt>CFG</tt> representing the control-flow graph of this function
+body by single call to a static class method:</p>
+
+<code>
+&nbsp;&nbsp;Stmt* FooBody = ...<br>
+&nbsp;&nbsp;CFG* FooCFG = <b>CFG::buildCFG</b>(FooBody);
+</code>
+
+<p>It is the responsibility of the caller of <tt>CFG::buildCFG</tt>
+to <tt>delete</tt> the returned <tt>CFG*</tt> when the CFG is no
+longer needed.</p>
+
+<p>Along with providing an interface to iterate over
+its <tt>CFGBlock</tt>s, the <tt>CFG</tt> class also provides methods
+that are useful for debugging and visualizing CFGs. For example, the
+method
+<tt>CFG::dump()</tt> dumps a pretty-printed version of the CFG to
+standard error. This is especially useful when one is using a
+debugger such as gdb. For example, here is the output
+of <tt>FooCFG->dump()</tt>:</p>
+
+<code>
+&nbsp;[ B5 (ENTRY) ]<br>
+&nbsp;&nbsp;&nbsp;&nbsp;Predecessors (0):<br>
+&nbsp;&nbsp;&nbsp;&nbsp;Successors (1): B4<br>
+<br>
+&nbsp;[ B4 ]<br>
+&nbsp;&nbsp;&nbsp;&nbsp;1: x = x + 1<br>
+&nbsp;&nbsp;&nbsp;&nbsp;2: (x > 2)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<b>T: if [B4.2]</b><br>
+&nbsp;&nbsp;&nbsp;&nbsp;Predecessors (1): B5<br>
+&nbsp;&nbsp;&nbsp;&nbsp;Successors (2): B3 B2<br>
+<br>
+&nbsp;[ B3 ]<br>
+&nbsp;&nbsp;&nbsp;&nbsp;1: x++<br>
+&nbsp;&nbsp;&nbsp;&nbsp;Predecessors (1): B4<br>
+&nbsp;&nbsp;&nbsp;&nbsp;Successors (1): B1<br>
+<br>
+&nbsp;[ B2 ]<br>
+&nbsp;&nbsp;&nbsp;&nbsp;1: x += 2<br>
+&nbsp;&nbsp;&nbsp;&nbsp;2: x *= 2<br>
+&nbsp;&nbsp;&nbsp;&nbsp;Predecessors (1): B4<br>
+&nbsp;&nbsp;&nbsp;&nbsp;Successors (1): B1<br>
+<br>
+&nbsp;[ B1 ]<br>
+&nbsp;&nbsp;&nbsp;&nbsp;1: return x;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;Predecessors (2): B2 B3<br>
+&nbsp;&nbsp;&nbsp;&nbsp;Successors (1): B0<br>
+<br>
+&nbsp;[ B0 (EXIT) ]<br>
+&nbsp;&nbsp;&nbsp;&nbsp;Predecessors (1): B1<br>
+&nbsp;&nbsp;&nbsp;&nbsp;Successors (0):
+</code>
+
+<p>For each block, the pretty-printed output displays for each block
+the number of <i>predecessor</i> blocks (blocks that have outgoing
+control-flow to the given block) and <i>successor</i> blocks (blocks
+that have control-flow that have incoming control-flow from the given
+block). We can also clearly see the special entry and exit blocks at
+the beginning and end of the pretty-printed output. For the entry
+block (block B5), the number of predecessor blocks is 0, while for the
+exit block (block B0) the number of successor blocks is 0.</p>
+
+<p>The most interesting block here is B4, whose outgoing control-flow
+represents the branching caused by the sole if-statement
+in <tt>foo</tt>. Of particular interest is the second statement in
+the block, <b><tt>(x > 2)</tt></b>, and the terminator, printed
+as <b><tt>if [B4.2]</tt></b>. The second statement represents the
+evaluation of the condition of the if-statement, which occurs before
+the actual branching of control-flow. Within the <tt>CFGBlock</tt>
+for B4, the <tt>Stmt*</tt> for the second statement refers to the
+actual expression in the AST for <b><tt>(x > 2)</tt></b>. Thus
+pointers to subclasses of <tt>Expr</tt> can appear in the list of
+statements in a block, and not just subclasses of <tt>Stmt</tt> that
+refer to proper C statements.</p>
+
+<p>The terminator of block B4 is a pointer to the <tt>IfStmt</tt>
+object in the AST. The pretty-printer outputs <b><tt>if
+[B4.2]</tt></b> because the condition expression of the if-statement
+has an actual place in the basic block, and thus the terminator is
+essentially
+<i>referring</i> to the expression that is the second statement of
+block B4 (i.e., B4.2). In this manner, conditions for control-flow
+(which also includes conditions for loops and switch statements) are
+hoisted into the actual basic block.</p>
+
+<!-- ===================== -->
+<!-- <h4>Implicit Control-Flow</h4> -->
+<!-- ===================== -->
+
+<!--
+<p>A key design principle of the <tt>CFG</tt> class was to not require
+any transformations to the AST in order to represent control-flow.
+Thus the <tt>CFG</tt> does not perform any "lowering" of the
+statements in an AST: loops are not transformed into guarded gotos,
+short-circuit operations are not converted to a set of if-statements,
+and so on.</p>
+-->
+
+
+<!-- ======================================================================= -->
+<h3 id="Constants">Constant Folding in the Clang AST</h3>
+<!-- ======================================================================= -->
+
+<p>There are several places where constants and constant folding matter a lot to
+the Clang front-end. First, in general, we prefer the AST to retain the source
+code as close to how the user wrote it as possible. This means that if they
+wrote "5+4", we want to keep the addition and two constants in the AST, we don't
+want to fold to "9". This means that constant folding in various ways turns
+into a tree walk that needs to handle the various cases.</p>
+
+<p>However, there are places in both C and C++ that require constants to be
+folded. For example, the C standard defines what an "integer constant
+expression" (i-c-e) is with very precise and specific requirements. The
+language then requires i-c-e's in a lot of places (for example, the size of a
+bitfield, the value for a case statement, etc). For these, we have to be able
+to constant fold the constants, to do semantic checks (e.g. verify bitfield size
+is non-negative and that case statements aren't duplicated). We aim for Clang
+to be very pedantic about this, diagnosing cases when the code does not use an
+i-c-e where one is required, but accepting the code unless running with
+<tt>-pedantic-errors</tt>.</p>
+
+<p>Things get a little bit more tricky when it comes to compatibility with
+real-world source code. Specifically, GCC has historically accepted a huge
+superset of expressions as i-c-e's, and a lot of real world code depends on this
+unfortuate accident of history (including, e.g., the glibc system headers). GCC
+accepts anything its "fold" optimizer is capable of reducing to an integer
+constant, which means that the definition of what it accepts changes as its
+optimizer does. One example is that GCC accepts things like "case X-X:" even
+when X is a variable, because it can fold this to 0.</p>
+
+<p>Another issue are how constants interact with the extensions we support, such
+as __builtin_constant_p, __builtin_inf, __extension__ and many others. C99
+obviously does not specify the semantics of any of these extensions, and the
+definition of i-c-e does not include them. However, these extensions are often
+used in real code, and we have to have a way to reason about them.</p>
+
+<p>Finally, this is not just a problem for semantic analysis. The code
+generator and other clients have to be able to fold constants (e.g. to
+initialize global variables) and has to handle a superset of what C99 allows.
+Further, these clients can benefit from extended information. For example, we
+know that "foo()||1" always evaluates to true, but we can't replace the
+expression with true because it has side effects.</p>
+
+<!-- ======================= -->
+<h4>Implementation Approach</h4>
+<!-- ======================= -->
+
+<p>After trying several different approaches, we've finally converged on a
+design (Note, at the time of this writing, not all of this has been implemented,
+consider this a design goal!). Our basic approach is to define a single
+recursive method evaluation method (<tt>Expr::Evaluate</tt>), which is
+implemented in <tt>AST/ExprConstant.cpp</tt>. Given an expression with 'scalar'
+type (integer, fp, complex, or pointer) this method returns the following
+information:</p>
+
+<ul>
+<li>Whether the expression is an integer constant expression, a general
+ constant that was folded but has no side effects, a general constant that
+ was folded but that does have side effects, or an uncomputable/unfoldable
+ value.
+</li>
+<li>If the expression was computable in any way, this method returns the APValue
+ for the result of the expression.</li>
+<li>If the expression is not evaluatable at all, this method returns
+ information on one of the problems with the expression. This includes a
+ SourceLocation for where the problem is, and a diagnostic ID that explains
+ the problem. The diagnostic should be have ERROR type.</li>
+<li>If the expression is not an integer constant expression, this method returns
+ information on one of the problems with the expression. This includes a
+ SourceLocation for where the problem is, and a diagnostic ID that explains
+ the problem. The diagnostic should be have EXTENSION type.</li>
+</ul>
+
+<p>This information gives various clients the flexibility that they want, and we
+will eventually have some helper methods for various extensions. For example,
+Sema should have a <tt>Sema::VerifyIntegerConstantExpression</tt> method, which
+calls Evaluate on the expression. If the expression is not foldable, the error
+is emitted, and it would return true. If the expression is not an i-c-e, the
+EXTENSION diagnostic is emitted. Finally it would return false to indicate that
+the AST is ok.</p>
+
+<p>Other clients can use the information in other ways, for example, codegen can
+just use expressions that are foldable in any way.</p>
+
+<!-- ========== -->
+<h4>Extensions</h4>
+<!-- ========== -->
+
+<p>This section describes how some of the various extensions Clang supports
+interacts with constant evaluation:</p>
+
+<ul>
+<li><b><tt>__extension__</tt></b>: The expression form of this extension causes
+ any evaluatable subexpression to be accepted as an integer constant
+ expression.</li>
+<li><b><tt>__builtin_constant_p</tt></b>: This returns true (as a integer
+ constant expression) if the operand is any evaluatable constant. As a
+ special case, if <tt>__builtin_constant_p</tt> is the (potentially
+ parenthesized) condition of a conditional operator expression ("?:"), only
+ the true side of the conditional operator is considered, and it is evaluated
+ with full constant folding.</li>
+<li><b><tt>__builtin_choose_expr</tt></b>: The condition is required to be an
+ integer constant expression, but we accept any constant as an "extension of
+ an extension". This only evaluates one operand depending on which way the
+ condition evaluates.</li>
+<li><b><tt>__builtin_classify_type</tt></b>: This always returns an integer
+ constant expression.</li>
+<li><b><tt>__builtin_inf,nan,..</tt></b>: These are treated just like a
+ floating-point literal.</li>
+<li><b><tt>__builtin_abs,copysign,..</tt></b>: These are constant folded as
+ general constant expressions.</li>
+</ul>
+
+
+
+
+</div>
+</body>
+</html>
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
new file mode 100644
index 000000000000..c486562b1009
--- /dev/null
+++ b/docs/LanguageExtensions.html
@@ -0,0 +1,327 @@
+<html>
+<head>
+<title>Clang Language Extensions</title>
+<link type="text/css" rel="stylesheet" href="../menu.css" />
+<link type="text/css" rel="stylesheet" href="../content.css" />
+<style type="text/css">
+td {
+ vertical-align: top;
+}
+</style>
+</head>
+<body>
+
+<!--#include virtual="../menu.html.incl"-->
+
+<div id="content">
+
+<h1>Clang Language Extensions</h1>
+
+<ul>
+<li><a href="#intro">Introduction</a></li>
+<li><a href="#builtinmacros">Builtin Macros</a></li>
+<li><a href="#vectors">Vectors and Extended Vectors</a></li>
+<li><a href="#blocks">Blocks</a></li>
+<li><a href="#overloading-in-c">Function Overloading in C</a></li>
+<li><a href="#builtins">Builtin Functions</a>
+ <ul>
+ <li><a href="#__builtin_shufflevector">__builtin_shufflevector</a></li>
+ </ul>
+</li>
+<li><a href="#targetspecific">Target-Specific Extensions</a>
+ <ul>
+ <li><a href="#x86-specific">X86/X86-64 Language Extensions</a></li>
+ </ul>
+</li>
+<li><a href="#analyzerspecific">Static Analysis-Specific Extensions</a>
+ <ul>
+ <li><a href="#analyzerattributes">Analyzer Attributes</a></li>
+ </ul>
+</li>
+</ul>
+
+<!-- ======================================================================= -->
+<h2 id="intro">Introduction</h2>
+<!-- ======================================================================= -->
+
+<p>This document describes the language extensions provided by Clang. In
+addition to the langauge extensions listed here, Clang aims to support a broad
+range of GCC extensions. Please see the <a
+href="http://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html">GCC manual</a> for
+more information on these extensions.</p>
+
+<!-- ======================================================================= -->
+<h2 id="builtinmacros">Builtin Macros</h2>
+<!-- ======================================================================= -->
+
+<p>__BASE_FILE__, __INCLUDE_LEVEL__, __TIMESTAMP__, __COUNTER__</p>
+
+<!-- ======================================================================= -->
+<h2 id="vectors">Vectors and Extended Vectors</h2>
+<!-- ======================================================================= -->
+
+<p>Supports the GCC vector extensions, plus some stuff like V[1]. ext_vector
+with V.xyzw syntax and other tidbits. See also <a
+href="#__builtin_shufflevector">__builtin_shufflevector</a>.</p>
+
+<!-- ======================================================================= -->
+<h2 id="blocks">Blocks</h2>
+<!-- ======================================================================= -->
+
+<p>The syntax and high level language feature description is in <a
+href="BlockLanguageSpec.txt">BlockLanguageSpec.txt</a>. Implementation and ABI
+details for the clang implementation are in <a
+href="BlockImplementation.txt">BlockImplementation.txt</a>.</p>
+
+<!-- ======================================================================= -->
+<h2 id="overloading-in-c">Function Overloading in C</h2>
+<!-- ======================================================================= -->
+
+<p>Clang provides support for C++ function overloading in C. Function
+overloading in C is introduced using the <tt>overloadable</tt> attribute. For
+example, one might provide several overloaded versions of a <tt>tgsin</tt>
+function that invokes the appropriate standard function computing the sine of a
+value with <tt>float</tt>, <tt>double</tt>, or <tt>long double</tt>
+precision:</p>
+
+<blockquote>
+<pre>
+#include &lt;math.h&gt;
+float <b>__attribute__((overloadable))</b> tgsin(float x) { return sinf(x); }
+double <b>__attribute__((overloadable))</b> tgsin(double x) { return sin(x); }
+long double <b>__attribute__((overloadable))</b> tgsin(long double x) { return sinl(x); }
+</pre>
+</blockquote>
+
+<p>Given these declarations, one can call <tt>tgsin</tt> with a
+<tt>float</tt> value to receive a <tt>float</tt> result, with a
+<tt>double</tt> to receive a <tt>double</tt> result, etc. Function
+overloading in C follows the rules of C++ function overloading to pick
+the best overload given the call arguments, with a few C-specific
+semantics:</p>
+<ul>
+ <li>Conversion from <tt>float</tt> or <tt>double</tt> to <tt>long
+ double</tt> is ranked as a floating-point promotion (per C99) rather
+ than as a floating-point conversion (as in C++).</li>
+
+ <li>A conversion from a pointer of type <tt>T*</tt> to a pointer of type
+ <tt>U*</tt> is considered a pointer conversion (with conversion
+ rank) if <tt>T</tt> and <tt>U</tt> are compatible types.</li>
+
+ <li>A conversion from type <tt>T</tt> to a value of type <tt>U</tt>
+ is permitted if <tt>T</tt> and <tt>U</tt> are compatible types. This
+ conversion is given "conversion" rank.</li>
+</ul>
+
+<p>The declaration of <tt>overloadable</tt> functions is restricted to
+function declarations and definitions. Most importantly, if any
+function with a given name is given the <tt>overloadable</tt>
+attribute, then all function declarations and definitions with that
+name (and in that scope) must have the <tt>overloadable</tt>
+attribute. This rule even applies to redeclarations of functions whose original
+declaration had the <tt>overloadable</tt> attribute, e.g.,</p>
+
+<blockquote>
+<pre>
+int f(int) __attribute__((overloadable));
+float f(float); <i>// error: declaration of "f" must have the "overloadable" attribute</i>
+
+int g(int) __attribute__((overloadable));
+int g(int) { } <i>// error: redeclaration of "g" must also have the "overloadable" attribute</i>
+</pre>
+</blockquote>
+
+<p>Functions marked <tt>overloadable</tt> must have
+prototypes. Therefore, the following code is ill-formed:</p>
+
+<blockquote>
+<pre>
+int h() __attribute__((overloadable)); <i>// error: h does not have a prototype</i>
+</pre>
+</blockquote>
+
+<p>However, <tt>overloadable</tt> functions are allowed to use a
+ellipsis even if there are no named parameters (as is permitted in C++). This feature is particularly useful when combined with the <tt>unavailable</tt> attribute:</p>
+
+<blockquote>
+<pre>
+void honeypot(...) __attribute__((overloadable, unavailable)); <i>// calling me is an error</i>
+</pre>
+</blockquote>
+
+<p>Functions declared with the <tt>overloadable</tt> attribute have
+their names mangled according to the same rules as C++ function
+names. For example, the three <tt>tgsin</tt> functions in our
+motivating example get the mangled names <tt>_Z5tgsinf</tt>,
+<tt>_Z5tgsind</tt>, and <tt>Z5tgsine</tt>, respectively. There are two
+caveats to this use of name mangling:</p>
+
+<ul>
+
+ <li>Future versions of Clang may change the name mangling of
+ functions overloaded in C, so you should not depend on an specific
+ mangling. To be completely safe, we strongly urge the use of
+ <tt>static inline</tt> with <tt>overloadable</tt> functions.</li>
+
+ <li>The <tt>overloadable</tt> attribute has almost no meaning when
+ used in C++, because names will already be mangled and functions are
+ already overloadable. However, when an <tt>overloadable</tt>
+ function occurs within an <tt>extern "C"</tt> linkage specification,
+ it's name <i>will</i> be mangled in the same way as it would in
+ C.</li>
+</ul>
+
+<!-- ======================================================================= -->
+<h2 id="builtins">Builtin Functions</h2>
+<!-- ======================================================================= -->
+
+<p>Clang supports a number of builtin library functions with the same syntax as
+GCC, including things like <tt>__builtin_nan</tt>,
+<tt>__builtin_constant_p</tt>, <tt>__builtin_choose_expr</tt>,
+<tt>__builtin_types_compatible_p</tt>, <tt>__sync_fetch_and_add</tt>, etc. In
+addition to the GCC builtins, Clang supports a number of builtins that GCC does
+not, which are listed here.</p>
+
+<p>Please note that Clang does not and will not support all of the GCC builtins
+for vector operations. Instead of using builtins, you should use the functions
+defined in target-specific header files like <tt>&lt;xmmintrin.h&gt;</tt>, which
+define portable wrappers for these. Many of the Clang versions of these
+functions are implemented directly in terms of <a href="#vectors">extended
+vector support</a> instead of builtins, in order to reduce the number of
+builtins that we need to implement.</p>
+
+<!-- ======================================================================= -->
+<h3 id="__builtin_shufflevector">__builtin_shufflevector</h3>
+<!-- ======================================================================= -->
+
+<p><tt>__builtin_shufflevector</tt> is used to expression generic vector
+permutation/shuffle/swizzle operations. This builtin is also very important for
+the implementation of various target-specific header files like
+<tt>&lt;xmmintrin.h&gt;</tt>.
+</p>
+
+<p><b>Syntax:</b></p>
+
+<pre>
+__builtin_shufflevector(vec1, vec2, index1, index2, ...)
+</pre>
+
+<p><b>Examples:</b></p>
+
+<pre>
+ // Identity operation - return 4-element vector V1.
+ __builtin_shufflevector(V1, V1, 0, 1, 2, 3)
+
+ // "Splat" element 0 of V1 into a 4-element result.
+ __builtin_shufflevector(V1, V1, 0, 0, 0, 0)
+
+ // Reverse 4-element vector V1.
+ __builtin_shufflevector(V1, V1, 3, 2, 1, 0)
+
+ // Concatenate every other element of 4-element vectors V1 and V2.
+ __builtin_shufflevector(V1, V2, 0, 2, 4, 6)
+
+ // Concatenate every other element of 8-element vectors V1 and V2.
+ __builtin_shufflevector(V1, V2, 0, 2, 4, 6, 8, 10, 12, 14)
+</pre>
+
+<p><b>Description:</b></p>
+
+<p>The first two arguments to __builtin_shufflevector are vectors that have the
+same element type. The remaining arguments are a list of integers that specify
+the elements indices of the first two vectors that should be extracted and
+returned in a new vector. These element indices are numbered sequentially
+starting with the first vector, continuing into the second vector. Thus, if
+vec1 is a 4-element vector, index 5 would refer to the second element of vec2.
+</p>
+
+<p>The result of __builtin_shufflevector is a vector
+with the same element type as vec1/vec2 but that has an element count equal to
+the number of indices specified.
+</p>
+
+<!-- ======================================================================= -->
+<h2 id="targetspecific">Target-Specific Extensions</h2>
+<!-- ======================================================================= -->
+
+<p>Clang supports some language features conditionally on some targets.</p>
+
+<!-- ======================================================================= -->
+<h3 id="x86-specific">X86/X86-64 Language Extensions</h3>
+<!-- ======================================================================= -->
+
+<p>The X86 backend has these language extensions:</p>
+
+<!-- ======================================================================= -->
+<h4 id="x86-gs-segment">Memory references off the GS segment</h4>
+<!-- ======================================================================= -->
+
+<p>Annotating a pointer with address space #256 causes it to be code generated
+relative to the X86 GS segment register, and address space #257 causes it to be
+relative to the X86 FS segment. Note that this is a very very low-level
+feature that should only be used if you know what you're doing (for example in
+an OS kernel).</p>
+
+<p>Here is an example:</p>
+
+<pre>
+#define GS_RELATIVE __attribute__((address_space(256)))
+int foo(int GS_RELATIVE *P) {
+ return *P;
+}
+</pre>
+
+<p>Which compiles to (on X86-32):</p>
+
+<pre>
+_foo:
+ movl 4(%esp), %eax
+ movl %gs:(%eax), %eax
+ ret
+</pre>
+
+<!-- ======================================================================= -->
+<h2 id="analyzerspecific">Static Analysis-Specific Extensions</h2>
+<!-- ======================================================================= -->
+
+<p>Clang supports additional attributes that are useful for documenting program
+invariants and rules for static analysis tools. The extensions documented here
+are used by the <a
+href="http://clang.llvm.org/StaticAnalysis.html">path-sensitive static analyzer
+engine</a> that is part of Clang's Analysis library.</p>
+
+<!-- ======================================================================= -->
+<h3 id="analyzerattributes">Analyzer Attributes</h3>
+<!-- ======================================================================= -->
+
+<h4 id="attr_analyzer_noreturn"><tt>analyzer_noreturn</tt></h4>
+
+<p>Clang's static analysis engine understands the standard <tt>noreturn</tt>
+attribute. This attribute, which is typically affixed to a function prototype,
+indicates that a call to a given function never returns. Function prototypes for
+common functions like <tt>exit</tt> are typically annotated with this attribute,
+as well as a variety of common assertion handlers. Users can educate the static
+analyzer about their own custom assertion handles (thus cutting down on false
+positives due to false paths) by marking their own &quot;panic&quot; functions
+with this attribute.</p>
+
+<p>While useful, <tt>noreturn</tt> is not applicable in all cases. Sometimes
+there are special functions that for all intensive purposes should be considered
+panic functions (i.e., they are only called when an internal program error
+occurs) but may actually return so that the program can fail gracefully. The
+<tt>analyzer_noreturn</tt> attribute allows one to annotate such functions as
+being interpreted as &quot;no return&quot; functions by the analyzer (thus
+pruning bogus paths) but will not affect compilation (as in the case of
+<tt>noreturn</tt>).</p>
+
+<p><b>Usage</b>: The <tt>analyzer_noreturn</tt> attribute can be placed in the
+same places where the <tt>noreturn</tt> attribute can be placed. It is commonly
+placed at the end of function prototypes:</p>
+
+<pre>
+ void foo() <b>__attribute__((analyzer_noreturn))</b>;
+</p>
+
+</div>
+</body>
+</html>
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 000000000000..9b706c7f36d2
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,97 @@
+##===- docs/Makefile ---------------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL := ../../..
+DIRS := tools
+
+ifdef BUILD_FOR_WEBSITE
+PROJ_OBJ_DIR = .
+DOXYGEN = doxygen
+
+$(PROJ_OBJ_DIR)/doxygen.cfg: doxygen.cfg.in
+ cat $< | sed \
+ -e 's/@abs_top_srcdir@/../g' \
+ -e 's/@DOT@/dot/g' \
+ -e 's/@PACKAGE_VERSION@/mainline/' \
+ -e 's/@abs_top_builddir@/../g' > $@
+endif
+
+include $(LEVEL)/Makefile.common
+
+HTML := $(wildcard $(PROJ_SRC_DIR)/*.html) \
+ $(wildcard $(PROJ_SRC_DIR)/*.css)
+#IMAGES := $(wildcard $(PROJ_SRC_DIR)/img/*.*)
+DOXYFILES := doxygen.cfg.in doxygen.css doxygen.footer doxygen.header \
+ doxygen.intro
+EXTRA_DIST := $(HTML) $(DOXYFILES) llvm.css CommandGuide img
+
+.PHONY: install-html install-doxygen doxygen generated
+
+install_targets :=
+ifndef ONLY_MAN_DOCS
+install_targets += install-html
+endif
+ifeq ($(ENABLE_DOXYGEN),1)
+install_targets += install-doxygen
+endif
+install-local:: $(install_targets)
+
+# Live documentation is generated for the web site using this target:
+# 'make generated BUILD_FOR_WEBSITE=1'
+generated:: doxygen
+
+install-html: $(PROJ_OBJ_DIR)/html.tar.gz
+ $(Echo) Installing HTML documentation
+ $(Verb) $(MKDIR) $(PROJ_docsdir)/html
+ $(Verb) $(MKDIR) $(PROJ_docsdir)/html/img
+ $(Verb) $(DataInstall) $(HTML) $(PROJ_docsdir)/html
+# $(Verb) $(DataInstall) $(IMAGES) $(PROJ_docsdir)/html/img
+ $(Verb) $(DataInstall) $(PROJ_OBJ_DIR)/html.tar.gz $(PROJ_docsdir)
+
+$(PROJ_OBJ_DIR)/html.tar.gz: $(HTML)
+ $(Echo) Packaging HTML documentation
+ $(Verb) $(RM) -rf $@ $(PROJ_OBJ_DIR)/html.tar
+ $(Verb) cd $(PROJ_SRC_DIR) && \
+ $(TAR) cf $(PROJ_OBJ_DIR)/html.tar *.html
+ $(Verb) $(GZIP) $(PROJ_OBJ_DIR)/html.tar
+
+install-doxygen: doxygen
+ $(Echo) Installing doxygen documentation
+ $(Verb) $(MKDIR) $(PROJ_docsdir)/html/doxygen
+ $(Verb) $(DataInstall) $(PROJ_OBJ_DIR)/doxygen.tar.gz $(PROJ_docsdir)
+ $(Verb) cd $(PROJ_OBJ_DIR)/doxygen && \
+ $(FIND) . -type f -exec \
+ $(DataInstall) {} $(PROJ_docsdir)/html/doxygen \;
+
+doxygen: regendoc $(PROJ_OBJ_DIR)/doxygen.tar.gz
+
+regendoc:
+ $(Echo) Building doxygen documentation
+ $(Verb) if test -e $(PROJ_OBJ_DIR)/doxygen ; then \
+ $(RM) -rf $(PROJ_OBJ_DIR)/doxygen ; \
+ fi
+ $(Verb) $(DOXYGEN) $(PROJ_OBJ_DIR)/doxygen.cfg
+
+$(PROJ_OBJ_DIR)/doxygen.tar.gz: $(DOXYFILES) $(PROJ_OBJ_DIR)/doxygen.cfg
+ $(Echo) Packaging doxygen documentation
+ $(Verb) $(RM) -rf $@ $(PROJ_OBJ_DIR)/doxygen.tar
+ $(Verb) $(TAR) cf $(PROJ_OBJ_DIR)/doxygen.tar doxygen
+ $(Verb) $(GZIP) $(PROJ_OBJ_DIR)/doxygen.tar
+ $(Verb) $(CP) $(PROJ_OBJ_DIR)/doxygen.tar.gz $(PROJ_OBJ_DIR)/doxygen/html/
+
+userloc: $(LLVM_SRC_ROOT)/docs/userloc.html
+
+$(LLVM_SRC_ROOT)/docs/userloc.html:
+ $(Echo) Making User LOC Table
+ $(Verb) cd $(LLVM_SRC_ROOT) ; ./utils/userloc.pl -details -recurse \
+ -html lib include tools runtime utils examples autoconf test > docs/userloc.html
+
+uninstall-local::
+ $(Echo) Uninstalling Documentation
+ $(Verb) $(RM) -rf $(PROJ_docsdir)
diff --git a/docs/PCHInternals.html b/docs/PCHInternals.html
new file mode 100644
index 000000000000..d90c446e9f29
--- /dev/null
+++ b/docs/PCHInternals.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html> <head>
+<title>Precompiled Headers (PCH)</title>
+</head>
+
+<body>
+
+<!--#include virtual="../menu.html.incl"-->
+
+<div id="content">
+
+<h1>Precompiled Headers</h1>
+
+ <p>This document describes the design and implementation of Clang's
+ precompiled headers (PCH). If you are interested in the end-user
+ view, please see the <a
+ href="UsersManual.html#precompiledheaders">User's Manual</a>.</p>
+
+<h2>Using precompiled headers with <tt>clang-cc</tt></h2>
+
+<p>The low-level Clang compiler, <tt>clang-cc</tt>, supports two command
+line options for generating and using PCH files.<p>
+
+<p>To generate PCH files using <tt>clang-cc</tt>, use the option
+<b><tt>-emit-pch</tt></b>:
+
+<pre> $ clang-cc test.h -emit-pch -o test.h.pch </pre>
+
+<p>This option is transparently used by <tt>clang</tt> when generating
+PCH files. The resulting PCH file contains the serialized form of the
+compiler's internal representation after it has completed parsing and
+semantic analysis. The PCH file can then be used as a prefix header
+with the <b><tt>-include-pch</tt></b> option:</p>
+
+<pre>
+ $ clang-cc -include-pch test.h.pch test.c -o test.s
+</pre>
+
+<h2>PCH Design Philosophy</h2>
+
+<p>Precompiled headers are meant to improve overall compile times for
+ projects, so the design of precompiled headers is entirely driven by
+ performance concerns. The use case for precompiled headers is
+ relatively simple: when there is a common set of headers that is
+ included in nearly every source file in the project, we
+ <i>precompile</i> that bundle of headers into a single precompiled
+ header (PCH file). Then, when compiling the source files in the
+ project, we load the PCH file first (as a prefix header), which acts
+ as a stand-in for that bundle of headers.</p>
+
+<p>A precompiled header implementation improves performance when:</p>
+<ul>
+ <li>Loading the PCH file is significantly faster than re-parsing the
+ bundle of headers stored within the PCH file. Thus, a precompiled
+ header design attempts to minimize the cost of reading the PCH
+ file. Ideally, this cost should not vary with the size of the
+ precompiled header file.</li>
+
+ <li>The cost of generating the PCH file initially is not so large
+ that it counters the per-source-file performance improvement due to
+ eliminating the need to parse the bundled headers in the first
+ place. This is particularly important on multi-core systems, because
+ PCH file generation serializes the build when all compilations
+ require the PCH file to be up-to-date.</li>
+</ul>
+
+<p>More to be written...</p>
+</div>
+
+</body>
+</html>
diff --git a/docs/PTHInternals.html b/docs/PTHInternals.html
new file mode 100644
index 000000000000..832d3b0a9788
--- /dev/null
+++ b/docs/PTHInternals.html
@@ -0,0 +1,177 @@
+<html>
+ <head>
+ <title>Pretokenized Headers (PTH)</title>
+ <link type="text/css" rel="stylesheet" href="../menu.css" />
+ <link type="text/css" rel="stylesheet" href="../content.css" />
+ <style type="text/css">
+ td {
+ vertical-align: top;
+ }
+ </style>
+</head>
+<body>
+
+<!--#include virtual="../menu.html.incl"-->
+
+<div id="content">
+
+<h1>Pretokenized Headers (PTH)</h1>
+
+<p>This document first describes the low-level
+interface for using PTH and then briefly elaborates on its design and
+implementation. If you are interested in the end-user view, please see the
+<a href="UsersManual.html#precompiledheaders">User's Manual</a>.</p>
+
+
+<h2>Using Pretokenized Headers with <tt>clang-cc</tt> (Low-level Interface)</h2>
+
+<p>The low-level Clang compiler tool, <tt>clang-cc</tt>, supports three command
+line options for generating and using PTH files.<p>
+
+<p>To generate PTH files using <tt>clang-cc</tt>, use the option
+<b><tt>-emit-pth</tt></b>:
+
+<pre> $ clang-cc test.h -emit-pth -o test.h.pth </pre>
+
+<p>This option is transparently used by <tt>clang</tt> when generating PTH
+files. Similarly, PTH files can be used as prefix headers using the
+<b><tt>-include-pth</tt></b> option:</p>
+
+<pre>
+ $ clang-cc -include-pth test.h.pth test.c -o test.s
+</pre>
+
+<p>Alternatively, Clang's PTH files can be used as a raw &quot;token-cache&quot;
+(or &quot;content&quot; cache) of the source included by the original header
+file. This means that the contents of the PTH file are searched as substitutes
+for <em>any</em> source files that are used by <tt>clang-cc</tt> to process a
+source file. This is done by specifying the <b><tt>-token-cache</tt></b>
+option:</p>
+
+<pre>
+ $ cat test.h
+ #include &lt;stdio.h&gt;
+ $ clang-cc -emit-pth test.h -o test.h.pth
+ $ cat test.c
+ #include "test.h"
+ $ clang-cc test.c -o test -token-cache test.h.pth
+</pre>
+
+<p>In this example the contents of <tt>stdio.h</tt> (and the files it includes)
+will be retrieved from <tt>test.h.pth</tt>, as the PTH file is being used in
+this case as a raw cache of the contents of <tt>test.h</tt>. This is a low-level
+interface used to both implement the high-level PTH interface as well as to
+provide alternative means to use PTH-style caching.</p>
+
+<h2>PTH Design and Implementation</h2>
+
+<p>Unlike GCC's precompiled headers, which cache the full ASTs and preprocessor
+state of a header file, Clang's pretokenized header files mainly cache the raw
+lexer <em>tokens</em> that are needed to segment the stream of characters in a
+source file into keywords, identifiers, and operators. Consequently, PTH serves
+to mainly directly speed up the lexing and preprocessing of a source file, while
+parsing and type-checking must be completely redone every time a PTH file is
+used.</p>
+
+<h3>Basic Design Tradeoffs</h3>
+
+<p>In the long term there are plans to provide an alternate PCH implementation
+for Clang that also caches the work for parsing and type checking the contents
+of header files. The current implementation of PCH in Clang as pretokenized
+header files was motivated by the following factors:<p>
+
+<ul>
+
+<li><p><b>Language independence</b>: PTH files work with any language that
+Clang's lexer can handle, including C, Objective-C, and (in the early stages)
+C++. This means development on language features at the parsing level or above
+(which is basically almost all interesting pieces) does not require PTH to be
+modified.</p></li>
+
+<li><b>Simple design</b>: Relatively speaking, PTH has a simple design and
+implementation, making it easy to test. Further, because the machinery for PTH
+resides at the lower-levels of the Clang library stack it is fairly
+straightforward to profile and optimize.</li>
+</ul>
+
+<p>Further, compared to GCC's PCH implementation (which is the dominate
+precompiled header file implementation that Clang can be directly compared
+against) the PTH design in Clang yields several attractive features:</p>
+
+<ul>
+
+<li><p><b>Architecture independence</b>: In contrast to GCC's PCH files (and
+those of several other compilers), Clang's PTH files are architecture
+independent, requiring only a single PTH file when building an program for
+multiple architectures.</p>
+
+<p>For example, on Mac OS X one may wish to
+compile a &quot;universal binary&quot; that runs on PowerPC, 32-bit Intel
+(i386), and 64-bit Intel architectures. In contrast, GCC requires a PCH file for
+each architecture, as the definitions of types in the AST are
+architecture-specific. Since a Clang PTH file essentially represents a lexical
+cache of header files, a single PTH file can be safely used when compiling for
+multiple architectures. This can also reduce compile times because only a single
+PTH file needs to be generated during a build instead of several.</p></li>
+
+<li><p><b>Reduced memory pressure</b>: Similar to GCC,
+Clang reads PTH files via the use of memory mapping (i.e., <tt>mmap</tt>).
+Clang, however, memory maps PTH files as read-only, meaning that multiple
+invocations of <tt>clang-cc</tt> can share the same pages in memory from a
+memory-mapped PTH file. In comparison, GCC also memory maps its PCH files but
+also modifies those pages in memory, incurring the copy-on-write costs. The
+read-only nature of PTH can greatly reduce memory pressure for builds involving
+multiple cores, thus improving overall scalability.</p></li>
+
+<li><p><b>Fast generation</b>: PTH files can be generated in a small fraction
+of the time needed to generate GCC's PCH files. Since PTH/PCH generation is a
+serial operation that typically blocks progress during a build, faster
+generation time leads to improved processor utilization with parallel builds on
+multicore machines.</p></li>
+
+</ul>
+
+<p>Despite these strengths, PTH's simple design suffers some algorithmic
+handicaps compared to other PCH strategies such as those used by GCC. While PTH
+can greatly speed up the processing time of a header file, the amount of work
+required to process a header file is still roughly linear in the size of the
+header file. In contrast, the amount of work done by GCC to process a
+precompiled header is (theoretically) constant (the ASTs for the header are
+literally memory mapped into the compiler). This means that only the pieces of
+the header file that are referenced by the source file including the header are
+the only ones the compiler needs to process during actual compilation. While
+GCC's particular implementation of PCH mitigates some of these algorithmic
+strengths via the use of copy-on-write pages, the approach itself can
+fundamentally dominate at an algorithmic level, especially when one considers
+header files of arbitrary size.</p>
+
+<p>There are plans to potentially implement an complementary PCH implementation
+for Clang based on the lazy deserialization of ASTs. This approach would
+theoretically have the same constant-time algorithmic advantages just mentioned
+but would also retain some of the strengths of PTH such as reduced memory
+pressure (ideal for multi-core builds).</p>
+
+<h3>Internal PTH Optimizations</h3>
+
+<p>While the main optimization employed by PTH is to reduce lexing time of
+header files by caching pre-lexed tokens, PTH also employs several other
+optimizations to speed up the processing of header files:</p>
+
+<ul>
+
+<li><p><em><tt>stat</tt> caching</em>: PTH files cache information obtained via
+calls to <tt>stat</tt> that <tt>clang-cc</tt> uses to resolve which files are
+included by <tt>#include</tt> directives. This greatly reduces the overhead
+involved in context-switching to the kernel to resolve included files.</p></li>
+
+<li><p><em>Fasting skipping of <tt>#ifdef</tt>...<tt>#endif</tt> chains</em>:
+PTH files record the basic structure of nested preprocessor blocks. When the
+condition of the preprocessor block is false, all of its tokens are immediately
+skipped instead of requiring them to be handled by Clang's
+preprocessor.</p></li>
+
+</ul>
+
+</div>
+</body>
+</html>
diff --git a/docs/UsersManual.html b/docs/UsersManual.html
new file mode 100644
index 000000000000..3f48c4abe6f9
--- /dev/null
+++ b/docs/UsersManual.html
@@ -0,0 +1,688 @@
+<html>
+<head>
+<title>Clang Compiler User's Manual</title>
+<link type="text/css" rel="stylesheet" href="../menu.css" />
+<link type="text/css" rel="stylesheet" href="../content.css" />
+<style type="text/css">
+td {
+ vertical-align: top;
+}
+</style>
+</head>
+<body>
+
+<!--#include virtual="../menu.html.incl"-->
+
+<div id="content">
+
+<h1>Clang Compiler User's Manual</h1>
+
+<ul>
+<li><a href="#intro">Introduction</a>
+ <ul>
+ <li><a href="#terminology">Terminology</a></li>
+ <li><a href="#basicusage">Basic Usage</a></li>
+ </ul>
+</li>
+<li><a href="#commandline">Command Line Options</a>
+ <ul>
+ <li><a href="#cl_diagnostics">Options to Control Error and Warning
+ Messages</a></li>
+ </ul>
+</li>
+<li><a href="#general_features">Language and Target-Independent Features</a>
+ <ul>
+ <li><a href="#diagnostics">Controlling Errors and Warnings</a></li>
+ <li><a href="#precompiledheaders">Precompiled Headers</a></li>
+ </ul>
+</li>
+<li><a href="#c">C Language Features</a>
+ <ul>
+ <li><a href="#c_ext">Extensions supported by clang</a></li>
+ <li><a href="#c_modes">Differences between various standard modes</a></li>
+ <li><a href="#c_unimpl_gcc">GCC extensions not implemented yet</a></li>
+ <li><a href="#c_unsupp_gcc">Intentionally unsupported GCC extensions</a></li>
+ <li><a href="#c_ms">Microsoft extensions</a></li>
+ </ul>
+</li>
+<li><a href="#objc">Objective-C Language Features</a>
+ <ul>
+ <li><a href="#objc_incompatibilities">Intentional Incompatibilities with
+ GCC</a></li>
+ </ul>
+</li>
+<li><a href="#cxx">C++ Language Features</a>
+ <ul>
+ <li>...</li>
+ </ul>
+</li>
+<li><a href="#objcxx">Objective C++ Language Features</a>
+ <ul>
+ <li>...</li>
+ </ul>
+</li>
+<li><a href="#target_features">Target-Specific Features and Limitations</a>
+ <ul>
+ <li><a href="#target_arch">CPU Architectures Features and Limitations</a>
+ <ul>
+ <li><a href="#target_arch_x86">X86</a></li>
+ <li>PPC</li>
+ <li>ARM</li>
+ </ul>
+ </li>
+ <li><a href="#target_os">Operating System Features and Limitations</a>
+ <ul>
+ <li><a href="#target_os_darwin">Darwin (Mac OS/X)</a></li>
+ <li>Linux, etc.</li>
+ </ul>
+
+ </li>
+ </ul>
+</li>
+</ul>
+
+
+<!-- ======================================================================= -->
+<h2 id="intro">Introduction</h2>
+<!-- ======================================================================= -->
+
+<p>The Clang Compiler is an open-source compiler for the C family of programming
+languages, aiming to be the best in class implementation of these languages.
+Clang builds on the LLVM optimizer and code generator, allowing it to provide
+high-quality optimization and code generation support for many targets. For
+more general information, please see the <a href="http://clang.llvm.org">Clang
+Web Site</a> or the <a href="http://llvm.org">LLVM Web Site</a>.</p>
+
+<p>This document describes important notes about using Clang as a compiler for
+an end-user, documenting the supported features, command line options, etc. If
+you are interested in using Clang to build a tool that processes code, please
+see <a href="InternalsManual.html">the Clang Internals Manual</a>. If you are
+interested in the <a href="http://clang.llvm.org/StaticAnalysis.html">Clang
+Static Analyzer</a>, please see its web page.</p>
+
+<p>Clang is designed to support the C family of programming languages, which
+includes <a href="#c">C</a>, <a href="#objc">Objective-C</a>, <a
+href="#cxx">C++</a>, and <a href="#objcxx">Objective-C++</a> as well as many
+dialects of those. For language-specific information, please see the
+corresponding language specific section:</p>
+
+<ul>
+<li><a href="#c">C Language</a>: K&amp;R C, ANSI C89, ISO C90, ISO C94
+ (C89+AMD1), ISO C99 (+TC1, TC2, TC3). </li>
+<li><a href="#objc">Objective-C Language</a>: ObjC 1, ObjC 2, ObjC 2.1, plus
+ variants depending on base language.</li>
+<li><a href="#cxx">C++ Language Features</a></li>
+<li><a href="#objcxx">Objective C++ Language</a></li>
+</ul>
+
+<p>In addition to these base languages and their dialects, Clang supports a
+broad variety of language extensions, which are documented in the corresponding
+language section. These extensions are provided to be compatible with the GCC,
+Microsoft, and other popular compilers as well as to improve functionality
+through Clang-specific features. The Clang driver and language features are
+intentionally designed to be as compatible with the GNU GCC compiler as
+reasonably possible, easing migration from GCC to Clang. In most cases, code
+"just works".</p>
+
+<p>In addition to language specific features, Clang has a variety of features
+that depend on what CPU architecture or operating system is being compiled for.
+Please see the <a href="target_features">Target-Specific Features and
+Limitations</a> section for more details.</p>
+
+<p>The rest of the introduction introduces some basic <a
+href="#terminology">compiler terminology</a> that is used throughout this manual
+and contains a basic <a href="#basicusage">introduction to using Clang</a>
+as a command line compiler.</p>
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="terminology">Terminology</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<p>Front end, parser, backend, preprocessor, undefined behavior, diagnostic,
+ optimizer</p>
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="basicusage">Basic Usage</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<p>Intro to how to use a C compiler for newbies.</p>
+<p>
+compile + link
+
+compile then link
+
+debug info
+
+enabling optimizations
+
+picking a language to use, defaults to C99 by default. Autosenses based on
+extension.
+
+using a makefile
+</p>
+
+
+<!-- ======================================================================= -->
+<h2 id="commandline">Command Line Options</h2>
+<!-- ======================================================================= -->
+
+<p>
+This section is generally an index into other sections. It does not go into
+depth on the ones that are covered by other sections. However, the first part
+introduces the language selection and other high level options like -c, -g, etc.
+</p>
+
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="cl_diagnostics">Options to Control Error and Warning Messages</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<p><b>-Werror</b>: Turn warnings into errors.</p>
+<p><b>-Werror=foo</b>: Turn warning "foo" into an error.</p>
+<p><b>-Wno-error=foo</b>: Turn warning "foo" into an warning even if -Werror is
+ specified.</p>
+<p><b>-Wfoo</b>: Enable warning foo</p>
+<p><b>-Wno-foo</b>: Disable warning foo</p>
+<p><b>-w</b>: Disable all warnings.</p>
+<p><b>-pedantic</b>: Warn on language extensions.</p>
+<p><b>-pedantic-errors</b>: Error on language extensions.</p>
+<p><b>-Wsystem-headers</b>: Enable warnings from system headers.</p>
+
+<!-- ================================================= -->
+<h4 id="cl_diag_formatting">Formatting of Diagnostics</h4>
+<!-- ================================================= -->
+
+<p>Clang aims to produce beautiful diagnostics by default, particularly for new
+users that first come to Clang. However, different people have different
+preferences, and sometimes Clang is driven by another program that wants to
+parse simple and consistent output, not a person. For these cases, Clang
+provides a wide range of options to control the exact output format of the
+diagnostics that it generates.</p>
+
+<dl>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<dt id="opt_fshow-column"><b>-f[no-]show-column</b>: Print column number in
+diagnostic.</dt>
+<dd>This option, which defaults to on, controls whether or not Clang prints the
+column number of a diagnostic. For example, when this is enabled, Clang will
+print something like:</p>
+
+<pre>
+ test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+ #endif bad
+ ^
+ //
+</pre>
+
+<p>When this is disabled, Clang will print "test.c:28: warning..." with no
+column number.</p>
+</dd>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<dt id="opt_fshow-source-location"><b>-f[no-]show-source-location</b>: Print
+source file/line/column information in diagnostic.</dt>
+<dd>This option, which defaults to on, controls whether or not Clang prints the
+filename, line number and column number of a diagnostic. For example,
+when this is enabled, Clang will print something like:</p>
+
+<pre>
+ test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+ #endif bad
+ ^
+ //
+</pre>
+
+<p>When this is disabled, Clang will not print the "test.c:28:8: " part.</p>
+</dd>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<dt id="opt_fcaret-diagnostics"><b>-f[no-]caret-diagnostics</b>: Print source
+line and ranges from source code in diagnostic.</dt>
+<dd>This option, which defaults to on, controls whether or not Clang prints the
+source line, source ranges, and caret when emitting a diagnostic. For example,
+when this is enabled, Clang will print something like:</p>
+
+<pre>
+ test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+ #endif bad
+ ^
+ //
+</pre>
+
+<p>When this is disabled, Clang will just print:</p>
+
+<pre>
+ test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+</pre>
+
+</dd>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<dt id="opt_fdiagnostics-show-option"><b>-f[no-]diagnostics-show-option</b>:
+Enable <tt>[-Woption]</tt> information in diagnostic line.</dt>
+<dd>This option, which defaults to on,
+controls whether or not Clang prints the associated <A
+href="#cl_diag_warning_groups">warning group</a> option name when outputting
+a warning diagnostic. For example, in this output:</p>
+
+<pre>
+ test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+ #endif bad
+ ^
+ //
+</pre>
+
+<p>Passing <b>-fno-diagnostics-show-option</b> will prevent Clang from printing
+the [<a href="#opt_Wextra-tokens">-Wextra-tokens</a>] information in the
+diagnostic. This information tells you the flag needed to enable or disable the
+diagnostic, either from the command line or through <a
+href="#pragma_GCC_diagnostic">#pragma GCC diagnostic</a>.</dd>
+
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<dt id="opt_fdiagnostics-fixit-info"><b>-f[no-]diagnostics-fixit-info</b>:
+Enable "FixIt" information in the diagnostics output.</dt>
+<dd>This option, which defaults to on, controls whether or not Clang prints the
+information on how to fix a specific diagnostic underneath it when it knows.
+For example, in this output:</p>
+
+<pre>
+ test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+ #endif bad
+ ^
+ //
+</pre>
+
+<p>Passing <b>-fno-diagnostics-fixit-info</b> will prevent Clang from printing
+the "//" line at the end of the message. This information is useful for users
+who may not understand what is wrong, but can be confusing for machine
+parsing.</p>
+</dd>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<dt id="opt_fdiagnostics-print-source-range-info">
+<b>-f[no-]diagnostics-print-source-range-info</b>:
+Print machine parsable information about source ranges.</dt>
+<dd>This option, which defaults to off, controls whether or not Clang prints
+information about source ranges in a machine parsable format after the
+file/line/column number information. The information is a simple sequence of
+brace enclosed ranges, where each range lists the start and end line/column
+locations. For example, in this output:</p>
+
+<pre>
+exprs.c:47:15:{47:8-47:14}{47:17-47:24}: error: invalid operands to binary expression ('int *' and '_Complex float')
+ P = (P-42) + Gamma*4;
+ ~~~~~~ ^ ~~~~~~~
+</pre>
+
+<p>The {}'s are generated by -fdiagnostics-print-source-range-info.</p>
+</dd>
+
+
+</dl>
+
+
+
+
+<!-- ===================================================== -->
+<h4 id="cl_diag_warning_groups">Individual Warning Groups</h4>
+<!-- ===================================================== -->
+
+<p>TODO: Generate this from tblgen. Define one anchor per warning group.</p>
+
+
+<dl>
+
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<dt id="opt_Wextra-tokens"><b>-Wextra-tokens</b>: Warn about excess tokens at
+ the end of a preprocessor directive.</dt>
+<dd>This option, which defaults to on, enables warnings about extra tokens at
+the end of preprocessor directives. For example:</p>
+
+<pre>
+ test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+ #endif bad
+ ^
+</pre>
+
+<p>These extra tokens are not strictly conforming, and are usually best handled
+by commenting them out.</p>
+
+<p>This option is also enabled by <a href="">-Wfoo</a>, <a href="">-Wbar</a>,
+ and <a href="">-Wbaz</a>.</p>
+</dd>
+
+</dl>
+
+<!-- ======================================================================= -->
+<h2 id="general_features">Language and Target-Independent Features</h2>
+<!-- ======================================================================= -->
+
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="diagnostics">Controlling Errors and Warnings</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<p>Clang provides a number of ways to control which code constructs cause it to
+emit errors and warning messages, and how they are displayed to the console.</p>
+
+<h4>Controlling How Clang Displays Diagnostics</h4>
+
+<p>When Clang emits a diagnostic, it includes rich information in the output,
+and gives you fine-grain control over which information is printed. Clang has
+the ability to print this information, and these are the options that control
+it:</p>
+
+<p>
+<ol>
+<li>A file/line/column indicator that shows exactly where the diagnostic occurs
+ in your code [<a href="#opt_fshow-column">-fshow-column</a>, <a
+ href="#opt_fshow-source-location">-fshow-source-location</a>].</li>
+<li>A categorization of the diagnostic as a note, warning, error, or fatal
+ error.</li>
+<li>A text string that describes what the problem is.</li>
+<li>An option that indicates how to control the diagnostic (for diagnostics that
+ support it) [<a
+ href="#opt_fdiagnostics-show-option">-fdiagnostics-show-option</a>].</li>
+<li>The line of source code that the issue occurs on, along with a caret and
+ ranges that indicate the important locations [<a
+ href="opt_fcaret-diagnostics">-fcaret-diagnostics</a>].</li>
+<li>"FixIt" information, which is a concise explanation of how to fix the
+ problem (when Clang is certain it knows) [<a
+ href="opt_fdiagnostics-fixit-info">-fdiagnostics-fixit-info</a>].</li>
+<li>A machine-parsable representation of the ranges involved (off by
+ default) [<a
+ href="opt_fdiagnostics-print-source-range-info">-fdiagnostics-print-source-range-info</a>].</li>
+</ol></p>
+
+<p>For more information please see <a href="#cl_diag_formatting">Formatting of
+Diagnostics</a>.</p>
+
+<h4>Controlling Which Diagnostics Clang Generates</h4>
+
+<p>mappings: ignore, note, warning, error, fatal</p>
+
+<p>
+The two major classes are control from the command line and control via pragmas
+in your code.</p>
+
+
+<p>-W flags, -pedantic, etc</p>
+
+<p>pragma GCC diagnostic</p>
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="precompiledheaders">Precompiled Headers</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<p><a href="http://en.wikipedia.org/wiki/Precompiled_header">Precompiled
+headers</a> are a general approach employed by many compilers to reduce
+compilation time. The underlying motivation of the approach is that it is
+common for the same (and often large) header files to be included by
+multiple source files. Consequently, compile times can often be greatly improved
+by caching some of the (redundant) work done by a compiler to process headers.
+Precompiled header files, which represent one of many ways to implement
+this optimization, are literally files that represent an on-disk cache that
+contains the vital information necessary to reduce some of the work
+needed to process a corresponding header file. While details of precompiled
+headers vary between compilers, precompiled headers have been shown to be a
+highly effective at speeding up program compilation on systems with very large
+system headers (e.g., Mac OS/X).</p>
+
+<p>Clang supports an implementation of precompiled headers known as
+<em>pre-tokenized headers</em> (PTH). Clang's pre-tokenized headers support most
+of same interfaces as GCC's pre-compiled headers (as well as others) but are
+completely different in their implementation. If you are interested in how
+PTH is implemented, please see the <a href="PTHInternals.html">PTH Internals
+ document</a>.</p>
+
+<h4>Generating a PTH File</h4>
+
+<p>To generate a PTH file using Clang, one invokes Clang with
+the <b><tt>-x <i>&lt;language&gt;</i>-header</tt></b> option. This mirrors the
+interface in GCC for generating PCH files:</p>
+
+<pre>
+ $ gcc -x c-header test.h -o test.h.gch
+ $ clang -x c-header test.h -o test.h.pth
+</pre>
+
+<h4>Using a PTH File</h4>
+
+<p>A PTH file can then be used as a prefix header when a
+<b><tt>-include</tt></b> option is passed to <tt>clang</tt>:</p>
+
+<pre>
+ $ clang -include test.h test.c -o test
+</pre>
+
+<p>The <tt>clang</tt> driver will first check if a PTH file for <tt>test.h</tt>
+is available; if so, the contents of <tt>test.h</tt> (and the files it includes)
+will be processed from the PTH file. Otherwise, Clang falls back to
+directly processing the content of <tt>test.h</tt>. This mirrors the behavior of
+GCC.</p>
+
+<p><b>NOTE:</b> Clang does <em>not</em> automatically use PTH files
+for headers that are directly included within a source file. For example:</p>
+
+<pre>
+ $ clang -x c-header test.h -o test.h.pth
+ $ cat test.c
+ #include "test.h"
+ $ clang test.c -o test
+</pre>
+
+<p>In this example, <tt>clang</tt> will not automatically use the PTH file for
+<tt>test.h</tt> since <tt>test.h</tt> was included directly in the source file
+and not specified on the command line using <tt>-include</tt>.</p>
+
+
+<!-- ======================================================================= -->
+<h2 id="c">C Language Features</h2>
+<!-- ======================================================================= -->
+
+<p>The support for standard C in clang is feature-complete except for the C99
+floating-point pragmas.</p>
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="c_ext">Extensions supported by clang</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<p>See <a href="LanguageExtensions.html">clang language extensions</a>.</p>
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="c_modes">Differences between various standard modes</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<p>clang supports the -std option, which changes what language mode clang uses.
+The supported modes for C are c89, gnu89, c94, c99, gnu99 and various aliases
+for those modes. If no -std option is specified, clang defaults to gnu99 mode.
+</p>
+
+<p>Differences between all c* and gnu* modes:</p>
+<ul>
+<li>c* modes define "__STRICT_ANSI__".</li>
+<li>Target-specific defines not prefixed by underscores, like "linux", are
+defined in gnu* modes.</li>
+<li>Trigraphs default to being off in gnu* modes; they can be enabled by the
+-trigraphs option.</li>
+<li>The parser recognizes "asm" and "typeof" as keywords in gnu* modes; the
+variants "__asm__" and "__typeof__" are recognized in all modes.</li>
+<li>The Apple "blocks" extension is recognized by default in gnu* modes
+on some platforms; it can be enabled in any mode with the "-fblocks"
+option.</li>
+<li>Some warnings are different.</li>
+</ul>
+
+<p>Differences between *89 and *99 modes:</p>
+<ul>
+<li>The *99 modes default to implementing "inline" as specified in C99, while
+the *89 modes implement the GNU version. This can be overridden for individual
+functions with the __gnu_inline__ attribute.</li>
+<li>Digraphs are not recognized in c89 mode.</li>
+<li>The scope of names defined inside a "for", "if", "switch", "while", or "do"
+statement is different. (example: "if ((struct x {int x;}*)0) {}".)</li>
+<li>__STDC_VERSION__ is not defined in *89 modes.</li>
+<li>"inline" is not recognized as a keyword in c89 mode.</li>
+<li>"restrict" is not recognized as a keyword in *89 modes.</li>
+<li>Commas are allowed in integer constant expressions in *99 modes.</li>
+<li>Arrays which are not lvalues are not implicitly promoted to pointers in
+*89 modes.</li>
+<li>Some warnings are different.</li>
+</ul>
+
+<p>c94 mode is identical to c89 mode except that digraphs are enabled in
+c94 mode (FIXME: And __STDC_VERSION__ should be defined!).</p>
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="c_unimpl_gcc">GCC extensions not implemented yet</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<p>clang tries to be compatible with gcc as much as possible, but some gcc
+extensions are not implemented yet:</p>
+
+<ul>
+<li>clang does not support __label__
+(<a href="http://llvm.org/bugs/show_bug.cgi?id=3429">bug 3429</a>). This is
+a relatively small feature, so it is likely to be implemented relatively
+soon.</li>
+
+<li>clang does not support attributes on function pointers
+(<a href="http://llvm.org/bugs/show_bug.cgi?id=2461">bug 2461</a>). This is
+a relatively important feature, so it is likely to be implemented relatively
+soon.</li>
+
+<li>clang does not support #pragma weak
+(<a href="http://llvm.org/bugs/show_bug.cgi?id=3679">bug 3679</a>). Due to
+the uses described in the bug, this is likely to be implemented at some
+point, at least partially.</li>
+
+<li>clang does not support #pragma align
+(<a href="http://llvm.org/bugs/show_bug.cgi?id=3811">bug 3811</a>). This is a
+relatively small feature, so it is likely to be implemented relatively
+soon.</li>
+
+<li>clang does not support code generation for local variables pinned to
+registers (<a href="http://llvm.org/bugs/show_bug.cgi?id=3933">bug 3933</a>).
+This is a relatively small feature, so it is likely to be implemented
+relatively soon.</li>
+
+<li>clang does not support decimal floating point types (_Decimal32 and
+friends) or fixed-point types (_Fract and friends); nobody has expressed
+interest in these features yet, so it's hard to say when they will be
+implemented.</li>
+
+<li>clang does not support nested functions; this is a complex feature which
+is infrequently used, so it is unlikely to be implemented anytime soon.</li>
+
+<li>clang does not support __builtin_apply and friends; this extension requires
+complex code generator support that does not currently exist in LLVM, and there
+is very little demand, so it is unlikely to be implemented anytime soon.</li>
+
+<li>clang does not support global register variables, this is unlikely
+to be implemented soon.</li>
+
+<li>clang does not support static initialization of flexible array
+members. This appears to be a rarely used extension, but could be
+implemented pending user demand.</li>
+
+</ul>
+
+<p>This is not a complete list; if you find an unsupported extension
+missing from this list, please send an e-mail to cfe-dev. This list
+currently excludes C++; see <a href="#cxx">C++ Language Features</a>.
+Also, this list does not include bugs in mostly-implemented features; please
+see the <a href="http://llvm.org/bugs/buglist.cgi?quicksearch=product%3Aclang+component%3A-New%2BBugs%2CAST%2CBasic%2CDriver%2CHeaders%2CLLVM%2BCodeGen%2Cparser%2Cpreprocessor%2CSemantic%2BAnalyzer">
+bug tracker</a> for known existing bugs (FIXME: Is there a section for
+bug-reporting guidelines somewhere?).</p>
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="c_unsupp_gcc">Intentionally unsupported GCC extensions</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<p>clang does not support the gcc extension that allows variable-length arrays
+in structures. This is for a few of reasons: one, it is tricky
+to implement, two, the extension is completely undocumented, and three, the
+extension appears to be very rarely used.</p>
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="c_ms">Microsoft extensions</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<p>clang has some experimental support for extensions from
+Microsoft Visual C++; to enable it, use the -fms-extensions command-line
+option. Eventually, this will be the default for Windows targets.
+These extensions are not anywhere near complete, so please do not
+file bugs; patches are welcome, though.</p>
+
+<li>clang does not support the Microsoft extension where anonymous
+record members can be declared using user defined typedefs.</li>
+
+<li>clang supports the Microsoft "#pragma pack" feature for
+controlling record layout. GCC also contains support for this feature,
+however where MSVC and GCC are incompatible clang follows the MSVC
+definition.</li>
+
+<!-- ======================================================================= -->
+<h2 id="objc">Objective-C Language Features</h2>
+<!-- ======================================================================= -->
+
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="objc_incompatibilities">Intentional Incompatibilities with GCC</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<p>No cast of super, no lvalue casts.</p>
+
+
+
+<!-- ======================================================================= -->
+<h2 id="cxx">C++ Language Features</h2>
+<!-- ======================================================================= -->
+
+<p>At this point, Clang C++ is not generally useful. However, Clang C++ support
+is under active development and is progressing rapidly. Please see the <a
+href="http://clang.llvm.org/cxx_status.html">C++ Status</a> page for details or
+ask on the mailing list about how you can help.</p>
+
+<p>Note that the clang driver will refuse to even try to use clang to compile
+C++ code unless you pass the <tt>-ccc-clang-cxx</tt> option to the driver. If
+you really want to play with Clang's C++ support, please pass that flag. </p>
+
+<!-- ======================================================================= -->
+<h2 id="objcxx">Objective C++ Language Features</h2>
+<!-- ======================================================================= -->
+
+<p>At this point, Clang C++ support is not generally useful (and therefore,
+neither is Objective-C++). Please see the <a href="#cxx">C++ section</a> for
+more information.</p>
+
+<!-- ======================================================================= -->
+<h2 id="target_features">Target-Specific Features and Limitations</h2>
+<!-- ======================================================================= -->
+
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="target_arch">CPU Architectures Features and Limitations</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<!-- ======================== -->
+<h4 id="target_arch_x86">X86</h4>
+<!-- ======================== -->
+
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="target_os">Operating System Features and Limitations</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<!-- ======================================= -->
+<h4 id="target_os_darwin">Darwin (Mac OS/X)</h4>
+<!-- ======================================= -->
+
+<p>No __thread support, 64-bit ObjC support requires SL tools.</p>
+
+</div>
+</body>
+</html>
diff --git a/docs/doxygen.cfg b/docs/doxygen.cfg
new file mode 100644
index 000000000000..40180b2415df
--- /dev/null
+++ b/docs/doxygen.cfg
@@ -0,0 +1,1230 @@
+# Doxyfile 1.4.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = clang
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = mainline
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = ../docs/doxygen
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH = ../..
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+#SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 2
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is YES.
+
+SHOW_DIRECTORIES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the progam writes to standard output
+# is used as the file version. See the manual for examples.
+
+#FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = NO
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+#WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT =
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = ../include \
+ ../lib \
+ ../docs/doxygen.intro
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH = ../examples
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = YES
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH = ../docs/img
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+#USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 4
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX = llvm::
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER = ../docs/doxygen.header
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER = ../docs/doxygen.footer
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET = ../docs/doxygen.css
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT =
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = letter
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT =
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT =
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION =
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH = ../include
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = YES
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+#GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+#DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH = dot
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+#DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+#DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/docs/doxygen.cfg.in b/docs/doxygen.cfg.in
new file mode 100644
index 000000000000..c1130fba4eee
--- /dev/null
+++ b/docs/doxygen.cfg.in
@@ -0,0 +1,1230 @@
+# Doxyfile 1.4.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = clang
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = @PACKAGE_VERSION@
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = @abs_top_builddir@/docs/doxygen
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH = ../..
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+#SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 2
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is YES.
+
+SHOW_DIRECTORIES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the progam writes to standard output
+# is used as the file version. See the manual for examples.
+
+#FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = NO
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+#WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT =
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = @abs_top_srcdir@/include \
+ @abs_top_srcdir@/lib \
+ @abs_top_srcdir@/docs/doxygen.intro
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH = @abs_top_srcdir@/examples
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = YES
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH = @abs_top_srcdir@/docs/img
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+#USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 4
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX = clang::
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER = @abs_top_srcdir@/docs/doxygen.header
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER = @abs_top_srcdir@/docs/doxygen.footer
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET = @abs_top_srcdir@/docs/doxygen.css
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT =
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = letter
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT =
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT =
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION =
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH = ../include
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = YES
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+#GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+#DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH = @DOT@
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+#DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+#DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/docs/doxygen.css b/docs/doxygen.css
new file mode 100644
index 000000000000..f105e202761f
--- /dev/null
+++ b/docs/doxygen.css
@@ -0,0 +1,378 @@
+BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
+ font-family: Verdana,Geneva,Arial,Helvetica,sans-serif;
+}
+BODY,TD {
+ font-size: 90%;
+}
+H1 {
+ text-align: center;
+ font-size: 140%;
+ font-weight: bold;
+}
+H2 {
+ font-size: 120%;
+ font-style: italic;
+}
+H3 {
+ font-size: 100%;
+}
+CAPTION { font-weight: bold }
+DIV.qindex {
+ width: 100%;
+ background-color: #eeeeff;
+ border: 1px solid #b0b0b0;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+ line-height: 140%;
+}
+DIV.nav {
+ width: 100%;
+ background-color: #eeeeff;
+ border: 1px solid #b0b0b0;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+ line-height: 140%;
+}
+DIV.navtab {
+ background-color: #eeeeff;
+ border: 1px solid #b0b0b0;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+TD.navtab {
+ font-size: 70%;
+}
+A.qindex {
+ text-decoration: none;
+ font-weight: bold;
+ color: #1A419D;
+}
+A.qindex:visited {
+ text-decoration: none;
+ font-weight: bold;
+ color: #1A419D
+}
+A.qindex:hover {
+ text-decoration: none;
+ background-color: #ddddff;
+}
+A.qindexHL {
+ text-decoration: none;
+ font-weight: bold;
+ background-color: #6666cc;
+ color: #ffffff;
+ border: 1px double #9295C2;
+}
+A.qindexHL:hover {
+ text-decoration: none;
+ background-color: #6666cc;
+ color: #ffffff;
+}
+A.qindexHL:visited {
+ text-decoration: none; background-color: #6666cc; color: #ffffff }
+A.el { text-decoration: none; font-weight: bold }
+A.elRef { font-weight: bold }
+A.code:link { text-decoration: none; font-weight: normal; color: #0000FF}
+A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF}
+A.codeRef:link { font-weight: normal; color: #0000FF}
+A.codeRef:visited { font-weight: normal; color: #0000FF}
+A:hover { text-decoration: none; background-color: #f2f2ff }
+DL.el { margin-left: -1cm }
+.fragment {
+ font-family: Fixed, monospace;
+ font-size: 95%;
+}
+PRE.fragment {
+ border: 1px solid #CCCCCC;
+ background-color: #f5f5f5;
+ margin-top: 4px;
+ margin-bottom: 4px;
+ margin-left: 2px;
+ margin-right: 8px;
+ padding-left: 6px;
+ padding-right: 6px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+}
+DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px }
+TD.md { background-color: #F4F4FB; font-weight: bold; }
+TD.mdPrefix {
+ background-color: #F4F4FB;
+ color: #606060;
+ font-size: 80%;
+}
+TD.mdname1 { background-color: #F4F4FB; font-weight: bold; color: #602020; }
+TD.mdname { background-color: #F4F4FB; font-weight: bold; color: #602020; width: 600px; }
+DIV.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ margin-bottom: 6px;
+ font-weight: bold;
+}
+DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% }
+BODY {
+ background: white;
+ color: black;
+ margin-right: 20px;
+ margin-left: 20px;
+}
+TD.indexkey {
+ background-color: #eeeeff;
+ font-weight: bold;
+ padding-right : 10px;
+ padding-top : 2px;
+ padding-left : 10px;
+ padding-bottom : 2px;
+ margin-left : 0px;
+ margin-right : 0px;
+ margin-top : 2px;
+ margin-bottom : 2px;
+ border: 1px solid #CCCCCC;
+}
+TD.indexvalue {
+ background-color: #eeeeff;
+ font-style: italic;
+ padding-right : 10px;
+ padding-top : 2px;
+ padding-left : 10px;
+ padding-bottom : 2px;
+ margin-left : 0px;
+ margin-right : 0px;
+ margin-top : 2px;
+ margin-bottom : 2px;
+ border: 1px solid #CCCCCC;
+}
+TR.memlist {
+ background-color: #f0f0f0;
+}
+P.formulaDsp { text-align: center; }
+IMG.formulaDsp { }
+IMG.formulaInl { vertical-align: middle; }
+SPAN.keyword { color: #008000 }
+SPAN.keywordtype { color: #604020 }
+SPAN.keywordflow { color: #e08000 }
+SPAN.comment { color: #800000 }
+SPAN.preprocessor { color: #806020 }
+SPAN.stringliteral { color: #002080 }
+SPAN.charliteral { color: #008080 }
+.mdTable {
+ border: 1px solid #868686;
+ background-color: #F4F4FB;
+}
+.mdRow {
+ padding: 8px 10px;
+}
+.mdescLeft {
+ padding: 0px 8px 4px 8px;
+ font-size: 80%;
+ font-style: italic;
+ background-color: #FAFAFA;
+ border-top: 1px none #E0E0E0;
+ border-right: 1px none #E0E0E0;
+ border-bottom: 1px none #E0E0E0;
+ border-left: 1px none #E0E0E0;
+ margin: 0px;
+}
+.mdescRight {
+ padding: 0px 8px 4px 8px;
+ font-size: 80%;
+ font-style: italic;
+ background-color: #FAFAFA;
+ border-top: 1px none #E0E0E0;
+ border-right: 1px none #E0E0E0;
+ border-bottom: 1px none #E0E0E0;
+ border-left: 1px none #E0E0E0;
+ margin: 0px;
+}
+.memItemLeft {
+ padding: 1px 0px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: solid;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memItemRight {
+ padding: 1px 8px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: solid;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memTemplItemLeft {
+ padding: 1px 0px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: none;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memTemplItemRight {
+ padding: 1px 8px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: none;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memTemplParams {
+ padding: 1px 0px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: solid;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ color: #606060;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.search { color: #003399;
+ font-weight: bold;
+}
+FORM.search {
+ margin-bottom: 0px;
+ margin-top: 0px;
+}
+INPUT.search { font-size: 75%;
+ color: #000080;
+ font-weight: normal;
+ background-color: #eeeeff;
+}
+TD.tiny { font-size: 75%;
+}
+a {
+ color: #252E78;
+}
+a:visited {
+ color: #3D2185;
+}
+.dirtab { padding: 4px;
+ border-collapse: collapse;
+ border: 1px solid #b0b0b0;
+}
+TH.dirtab { background: #eeeeff;
+ font-weight: bold;
+}
+HR { height: 1px;
+ border: none;
+ border-top: 1px solid black;
+}
+
+/*
+ * LLVM Modifications.
+ * Note: Everything above here is generated with "doxygen -w htlm" command. See
+ * "doxygen --help" for details. What follows are CSS overrides for LLVM
+ * specific formatting. We want to keep the above so it can be replaced with
+ * subsequent doxygen upgrades.
+ */
+
+.footer {
+ font-size: 80%;
+ font-weight: bold;
+ text-align: center;
+ vertical-align: middle;
+}
+.title {
+ font-size: 25pt;
+ color: black; background: url("http://llvm.org/img/lines.gif");
+ font-weight: bold;
+ border-width: 1px;
+ border-style: solid none solid none;
+ text-align: center;
+ vertical-align: middle;
+ padding-left: 8pt;
+ padding-top: 1px;
+ padding-bottom: 2px
+}
+A:link {
+ cursor: pointer;
+ text-decoration: none;
+ font-weight: bolder;
+}
+A:visited {
+ cursor: pointer;
+ text-decoration: underline;
+ font-weight: bolder;
+}
+A:hover {
+ cursor: pointer;
+ text-decoration: underline;
+ font-weight: bolder;
+}
+A:active {
+ cursor: pointer;
+ text-decoration: underline;
+ font-weight: bolder;
+ font-style: italic;
+}
+H1 {
+ text-align: center;
+ font-size: 140%;
+ font-weight: bold;
+}
+H2 {
+ font-size: 120%;
+ font-style: italic;
+}
+H3 {
+ font-size: 100%;
+}
+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 }
diff --git a/docs/doxygen.footer b/docs/doxygen.footer
new file mode 100644
index 000000000000..524e9a2bb8b9
--- /dev/null
+++ b/docs/doxygen.footer
@@ -0,0 +1,10 @@
+<hr>
+<p class="footer">
+Generated on $datetime by <a href="http://www.doxygen.org">Doxygen
+$doxygenversion</a>.</p>
+
+<p class="footer">
+See the <a href="http://clang.llvm.org">Main Clang Web Page</a> for more
+information.</p>
+</body>
+</html>
diff --git a/docs/doxygen.header b/docs/doxygen.header
new file mode 100644
index 000000000000..bea51371ed27
--- /dev/null
+++ b/docs/doxygen.header
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html><head>
+<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"/>
+<meta name="keywords" content="clang,LLVM,Low Level Virtual Machine,C,C++,doxygen,API,frontend,documentation"/>
+<meta name="description" content="C++ source code API documentation for clang."/>
+<title>clang: $title</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css"/>
+</head><body>
+<p class="title">clang API Documentation</p>
diff --git a/docs/doxygen.intro b/docs/doxygen.intro
new file mode 100644
index 000000000000..accab72bd085
--- /dev/null
+++ b/docs/doxygen.intro
@@ -0,0 +1,15 @@
+/// @mainpage clang
+///
+/// @section main_intro Introduction
+/// Welcome to the clang project.
+///
+/// This documentation describes the @b internal software that makes
+/// up clang, not the @b external use of clang. There are no instructions
+/// here on how to use clang, only the APIs that make up the software. For
+/// usage instructions, please see the programmer's guide or reference
+/// manual.
+///
+/// @section main_caveat Caveat
+/// This documentation is generated directly from the source code with doxygen.
+/// Since clang is constantly under active development, what you're about to
+/// read is out of date!
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 000000000000..d741b68a4160
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,4 @@
+<title>'clang' C frontend documentation</title>
+
+None yet, sorry :(
+
diff --git a/docs/tools/Makefile b/docs/tools/Makefile
new file mode 100644
index 000000000000..90eb7768f531
--- /dev/null
+++ b/docs/tools/Makefile
@@ -0,0 +1,112 @@
+##===- docs/tools/Makefile ---------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+ifdef BUILD_FOR_WEBSITE
+
+# FIXME: This was copied from the CommandGuide makefile. Figure out
+# how to get this stuff on the website.
+
+# This special case is for keeping the CommandGuide on the LLVM web site
+# up to date automatically as the documents are checked in. It must build
+# the POD files to HTML only and keep them in the src directories. It must also
+# build in an unconfigured tree, hence the ifdef. To use this, run
+# make -s BUILD_FOR_WEBSITE=1 inside the cvs commit script.
+SRC_DOC_DIR=
+DST_HTML_DIR=html/
+DST_MAN_DIR=man/man1/
+DST_PS_DIR=ps/
+
+# If we are in BUILD_FOR_WEBSITE mode, default to the all target.
+all:: html man ps
+
+clean:
+ rm -f pod2htm*.*~~ $(HTML) $(MAN) $(PS)
+
+# To create other directories, as needed, and timestamp their creation
+%/.dir:
+ -mkdir $* > /dev/null
+ date > $@
+
+else
+
+# Otherwise, if not in BUILD_FOR_WEBSITE mode, use the project info.
+LEVEL := ../../../..
+include $(LEVEL)/Makefile.common
+
+SRC_DOC_DIR=$(PROJ_SRC_DIR)/
+DST_HTML_DIR=$(PROJ_OBJ_DIR)/
+DST_MAN_DIR=$(PROJ_OBJ_DIR)/
+DST_PS_DIR=$(PROJ_OBJ_DIR)/
+
+endif
+
+
+POD := $(wildcard $(SRC_DOC_DIR)*.pod)
+HTML := $(patsubst $(SRC_DOC_DIR)%.pod, $(DST_HTML_DIR)%.html, $(POD))
+MAN := $(patsubst $(SRC_DOC_DIR)%.pod, $(DST_MAN_DIR)%.1, $(POD))
+PS := $(patsubst $(SRC_DOC_DIR)%.pod, $(DST_PS_DIR)%.ps, $(POD))
+
+ifdef ONLY_MAN_DOCS
+INSTALL_TARGETS := install-man
+else
+INSTALL_TARGETS := install-html install-man install-ps
+endif
+
+.SUFFIXES:
+.SUFFIXES: .html .pod .1 .ps
+
+$(DST_HTML_DIR)%.html: %.pod $(DST_HTML_DIR)/.dir
+ pod2html --css=manpage.css --htmlroot=. \
+ --podpath=. --infile=$< --outfile=$@ --title=$*
+
+$(DST_MAN_DIR)%.1: %.pod $(DST_MAN_DIR)/.dir
+ pod2man --release "clang 1.0" --center="Clang Tools Documentation" $< $@
+
+$(DST_PS_DIR)%.ps: $(DST_MAN_DIR)%.1 $(DST_PS_DIR)/.dir
+ groff -Tps -man $< > $@
+
+
+html: $(HTML)
+man: $(MAN)
+ps: $(PS)
+
+EXTRA_DIST := $(POD)
+
+clean-local::
+ $(Verb) $(RM) -f pod2htm*.*~~ $(HTML) $(MAN) $(PS)
+
+HTML_DIR := $(PROJ_docsdir)/html/clang
+MAN_DIR := $(PROJ_mandir)/man1
+PS_DIR := $(PROJ_docsdir)/ps
+
+install-html:: $(HTML)
+ $(Echo) Installing HTML Clang Tools Documentation
+ $(Verb) $(MKDIR) $(HTML_DIR)
+ $(Verb) $(DataInstall) $(HTML) $(HTML_DIR)
+ $(Verb) $(DataInstall) $(PROJ_SRC_DIR)/manpage.css $(HTML_DIR)
+
+install-man:: $(MAN)
+ $(Echo) Installing MAN Clang Tools Documentation
+ $(Verb) $(MKDIR) $(MAN_DIR)
+ $(Verb) $(DataInstall) $(MAN) $(MAN_DIR)
+
+install-ps:: $(PS)
+ $(Echo) Installing PS Clang Tools Documentation
+ $(Verb) $(MKDIR) $(PS_DIR)
+ $(Verb) $(DataInstall) $(PS) $(PS_DIR)
+
+install-local:: $(INSTALL_TARGETS)
+
+uninstall-local::
+ $(Echo) Uninstalling Clang Tools Documentation
+ $(Verb) $(RM) -rf $(HTML_DIR) $(MAN_DIR) $(PS_DIR)
+
+printvars::
+ $(Echo) "POD : " '$(POD)'
+ $(Echo) "HTML : " '$(HTML)'
diff --git a/docs/tools/clang.pod b/docs/tools/clang.pod
new file mode 100644
index 000000000000..c520f93997e5
--- /dev/null
+++ b/docs/tools/clang.pod
@@ -0,0 +1,514 @@
+=pod
+
+=head1 NAME
+
+clang - the Clang C and Objective-C compiler
+
+=head1 SYNOPSIS
+
+B<clang> [B<-c>|B<-S>|B<-E>] B<-std=>I<standard> B<-g>
+ [B<-O0>|B<-O1>|B<-O2>|B<-Os>|B<-O3>|B<-O4>]
+ B<-W>I<warnings...> B<-pedantic>
+ B<-I>I<dir...> B<-L>I<dir...>
+ B<-D>I<macro[=defn]>
+ B<-f>I<feature-option...>
+ B<-m>I<machine-option...>
+ B<-o> I<output-file>
+ I<input-filenames>
+
+=head1 DESCRIPTION
+
+B<clang> is a C and Objective-C compiler which encompasses preprocessing,
+parsing, optimization, code generation, assembly, and linking. Depending on
+which high-level mode setting is passed, Clang will stop before doing a full
+link. While Clang is highly integrated, it is important to understand the
+stages of compilation, to understand how to invoke it. These stages are:
+
+=over
+
+=item B<Driver>
+
+The B<clang> executable is actually a small driver which controls the overall
+execution of other tools such as the compiler, assembler and linker. Typically
+you do not need to interact with the driver, but you transparently use it to run
+the other tools.
+
+=item B<Preprocessing>
+
+This stage handles tokenization of the input source file, macro expansion,
+#include expansion and handling of other preprocessor directives. The output of
+this stage is typically called a ".i" (for C) or ".mi" (for Objective-C) file.
+
+=item B<Parsing and Semantic Analysis>
+
+This stage parses the input file, translating preprocessor tokens into a parse
+tree. Once in the form of a parser tree, it applies semantic analysis to compute
+types for expressions as well and determine whether the code is well formed. This
+stage is responsible for generating most of the compiler warnings as well as
+parse errors. The output of this stage is an "Abstract Syntax Tree" (AST).
+
+=item B<Code Generation and Optimization>
+
+This stage translates an AST into low-level intermediate code (known as "LLVM
+IR") and ultimately to machine code (depending on the optimization level). This
+phase is responsible for optimizing the generated code and handling
+target-specfic code generation. The output of this stage is typically called a
+".s" file or "assembly" file.
+
+=item B<Assembler>
+
+This stage runs the target assembler to translate the output of the compiler
+into a target object file. The output of this stage is typically called a ".o"
+file or "object" file.
+
+=item B<Linker>
+
+This stage runs the target linker to merge multiple object files into an
+executable or dynamic library. The output of this stage is typically called an
+"a.out", ".dylib" or ".so" file.
+
+=back
+
+The Clang compiler supports a large number of options to control each of these
+stages. In addition to compilation of code, Clang also supports other tools:
+
+B<Clang Static Analyzer>
+
+The Clang Static Analyzer is a tool that scans source code to try to find bugs
+though code analysis. This tool uses many parts of Clang and is built into the
+same driver.
+
+
+=head1 OPTIONS
+
+=head2 Stage Selection Options
+
+=over
+
+=item B<-E>
+
+Run the preprocessor stage.
+
+=item B<-fsyntax-only>
+
+Run the preprocessor, parser and type checking stages.
+
+=item B<-S>
+
+Run the previous stages as well as LLVM generation and optimization stages and
+target-specific code generation, producing an assembly file.
+
+=item B<-c>
+
+Run all of the above, plus the assembler, generating a target ".o" object file.
+
+=item B<no stage selection option>
+
+If no stage selection option is specified, all stages above are run, and the
+linker is run to combine the results into an executable or shared library.
+
+=item B<--analyze>
+
+Run the Clang Static Analyzer.
+
+=back
+
+
+
+=head2 Language Selection and Mode Options
+
+=over
+
+=item B<-x> I<language>
+
+Treat subsequent input files as having type I<language>.
+
+=item B<-std>=I<language>
+
+Specify the language standard to compile for.
+
+=item B<-ansi>
+
+Same as B<-std=c89>.
+
+=item B<-ObjC++>
+
+Treat source input files as Objective-C++ inputs.
+
+=item B<-ObjC>
+
+Treat source input files as Objective-C inputs.
+
+=item B<-trigraphs>
+
+Enable trigraphs.
+
+=item B<-ffreestanding>
+
+Indicate that the file should be compiled for a freestanding, not a hosted,
+environment.
+
+=item B<-fno-builtin>
+
+Disable special handling and optimizations of builtin functions like strlen and
+malloc.
+
+=item B<-fmath-errno>
+
+Indicate that math functions should be treated as updating errno.
+
+=item B<-fpascal-strings>
+
+Enable support for Pascal-style strings with "\pfoo".
+
+=item B<-fms-extensions>
+
+Enable support for Microsoft extensions.
+
+=item B<-fwritable-strings>
+
+Make all string literals default to writable. This disables uniquing of
+strings and other optimizations.
+
+=item B<-flax-vector-conversions>
+
+Allow loose type checking rules for implicit vector conversions.
+
+=item B<-fblocks>
+
+Enable the "Blocks" language feature.
+
+
+=item B<-fobjc-gc-only>
+
+Indicate that Objective-C code should be compiled in GC-only mode, which only
+works when Objective-C Garbage Collection is enabled.
+
+=item B<-fobjc-gc>
+
+Indicate that Objective-C code should be compiled in hybrid-GC mode, which works
+with both GC and non-GC mode.
+
+=back
+
+
+
+=head2 Target Selection Options
+
+Clang fully supports cross compilation as an inherent part of its design.
+Depending on how your version of Clang is configured, it may have support for
+a number of cross compilers, or may only support a native target.
+
+=over
+
+=item B<-arch> I<architecture>
+
+Specify the architecture to build for.
+
+=item B<-mmacosx-version-min>=I<version>
+
+When building for Mac OS/X, specify the minimum version supported by your
+application.
+
+=item B<-miphoneos-version-min>
+
+When building for iPhone OS, specify the minimum version supported by your
+application.
+
+
+=item B<-march>=I<cpu>
+
+Specify that Clang should generate code for a specific processor family member
+and later. For example, if you specify -march=i486, the compiler is allowed to
+generate instructions that are valid on i486 and later processors, but which
+may not exist on earlier ones.
+
+=back
+
+
+=head2 Code Generation Options
+
+=over
+
+=item B<-O0> B<-O1> B<-O2> B<-Os> B<-O3> B<-O4>
+
+Specify which optimization level to use. B<-O0> means "no optimization": this
+level compiles the fastest and generates the most debuggable code. B<-O2> is a
+moderate level of optimization which enables most optimizations. B<-Os> is like
+B<-O2> with extra optimizations to reduce code size. B<-O3> is like B<-O2>,
+except that it enables optimizations that take longer to perform or that may
+generate larger code (in an attempt to make the program run faster). On
+supported platforms, B<-O4> enables link-time optimization; object files are
+stored in the LLVM bitcode file format and whole program optimization is done at
+link time. B<-O1> is somewhere between B<-O0> and B<-O2>.
+
+=item B<-g>
+
+Generate debug information. Note that Clang debug information works best at
+B<-O0>. At higher optimization levels, only line number information is
+currently available.
+
+=item B<-fexceptions>
+
+Enable generation of unwind information, this allows exceptions to be thrown
+through Clang compiled stack frames. This is on by default in x86-64.
+
+=item B<-ftrapv>
+
+Generate code to catch integer overflow errors. Signed integer overflow is
+undefined in C, with this flag, extra code is generated to detect this and abort
+when it happens.
+
+
+=item B<-fvisibility>
+
+This flag sets the default visibility level.
+
+=item B<-fcommon>
+
+This flag specifies that variables without initializers get common linkage. It
+can be disabled with B<-fno-common>.
+
+=item B<-flto> B<-emit-llvm>
+
+Generate output files in LLVM formats, suitable for link time optimization. When
+used with B<-S> this generates LLVM intermediate language assembly files,
+otherwise this generates LLVM bitcode format object files (which may be passed
+to the linker depending on the stage selection options).
+
+=cut
+
+##=item B<-fnext-runtime> B<-fobjc-nonfragile-abi> B<-fgnu-runtime>
+##These options specify which Objective-C runtime the code generator should
+##target. FIXME: we don't want people poking these generally.
+
+=pod
+
+=back
+
+
+=head2 Driver Options
+
+=over
+
+=item B<-###>
+
+Print the commands to run for this compilation.
+
+=item B<--help>
+
+Display available options.
+
+=item B<-Qunused-arguments>
+
+Don't emit warning for unused driver arguments.
+
+=item B<-Wa,>I<args>
+
+Pass the comma separated arguments in I<args> to the assembler.
+
+=item B<-Wl,>I<args>
+
+Pass the comma separated arguments in I<args> to the linker.
+
+=item B<-Wp,>I<args>
+
+Pass the comma separated arguments in I<args> to the preprocessor.
+
+=item B<-Xanalyzer> I<arg>
+
+Pass I<arg> to the static analyzer.
+
+=item B<-Xassembler> I<arg>
+
+Pass I<arg> to the assembler.
+
+=item B<-Xclang> I<arg>
+
+Pass I<arg> to the clang compiler.
+
+=item B<-Xlinker> I<arg>
+
+Pass I<arg> to the linker.
+
+=item B<-Xpreprocessor> I<arg>
+
+Pass I<arg> to the preprocessor.
+
+=item B<-o> I<file>
+
+Write output to I<file>.
+
+=item B<-print-file-name>=I<file>
+
+Print the full library path of I<file>.
+
+=item B<-print-libgcc-file-name>
+
+Print the library path for "libgcc.a".
+
+=item B<-print-prog-name>=I<name>
+
+Print the full program path of I<name>.
+
+=item B<-print-search-dirs>
+
+Print the paths used for finding libraries and programs.
+
+=item B<-save-temps>
+
+Save intermediate compilation results.
+
+=item B<-time>
+
+Time individual commands.
+
+=item B<-ftime-report>
+
+Print timing summary of each stage of compilation.
+
+=item B<-v>
+
+Show commands to run and use verbose output.
+
+=back
+
+
+=head2 Diagnostics Options
+
+=over
+
+=item
+B<-fshow-column>
+B<-fshow-source-location>
+B<-fcaret-diagnostics>
+B<-fdiagnostics-fixit-info>
+B<-fdiagnostics-print-source-range-info>
+B<-fprint-source-range-info>
+B<-fdiagnostics-show-option>
+B<-fmessage-length>
+
+These options control how Clang prints out information about diagnostics (errors
+and warnings). Please see the Clang User's Manual for more information.
+
+=back
+
+
+=head2 Preprocessor Options
+
+=over
+
+=item B<-D>I<macroname=value>
+
+Adds an implicit #define into the predefines buffer which is read before the
+source file is preprocessed.
+
+=item B<-U>I<macroname>
+
+Adds an implicit #undef into the predefines buffer which is read before the
+source file is preprocessed.
+
+=item B<-include> I<filename>
+
+Adds an implicit #include into the predefines buffer which is read before the
+source file is preprocessed.
+
+=item B<-I>I<directory>
+
+Add the specified directory to the search path for include files.
+
+=item B<-F>I<directory>
+
+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.
+
+=cut
+
+## TODO, but do we really want people using this stuff?
+=item B<-idirafter>I<directory>
+=item B<-iquote>I<directory>
+=item B<-isystem>I<directory>
+=item B<-iprefix>I<directory>
+=item B<-iwithprefix>I<directory>
+=item B<-iwithprefixbefore>I<directory>
+=item B<-isysroot>
+=pod
+
+
+=back
+
+
+
+=cut
+
+### TODO someday.
+=head2 Warning Control Options
+=over
+=back
+=head2 Code Generation and Optimization Options
+=over
+=back
+=head2 Assembler Options
+=over
+=back
+=head2 Linker Options
+=over
+=back
+=head2 Static Analyzer Options
+=over
+=back
+
+=pod
+
+
+=head1 ENVIRONMENT
+
+=over
+
+=item B<TMPDIR>, B<TEMP>, B<TMP>
+
+These environment variables are checked, in order, for the location to
+write temporary files used during the compilation process.
+
+=item B<CPATH>
+
+If this environment variable is present, it is treated as a delimited
+list of paths to be added to the default system include path list. The
+delimiter is the platform dependent delimitor, as used in the I<PATH>
+environment variable.
+
+Empty components in the environment variable are ignored.
+
+=item B<C_INCLUDE_PATH>, B<OBJC_INCLUDE_PATH>, B<CPLUS_INCLUDE_PATH>,
+B<OBJCPLUS_INCLUDE_PATH>
+
+These environment variables specify additional paths, as for CPATH,
+which are only used when processing the appropriate language.
+
+=item B<MACOSX_DEPLOYMENT_TARGET>
+
+If -mmacosx-version-min is unspecified, the default deployment target
+is read from this environment variable. This option only affects darwin
+targets.
+
+=back
+
+=head1 BUGS
+
+Clang currently does not have C++ support, and this manual page is incomplete.
+To report bugs, please visit L<http://llvm.org/bugs/>. Most bug reports should
+include preprocessed source files (use the B<-E> option) and the full output of
+the compiler, along with information to reproduce.
+
+=head1 SEE ALSO
+
+ as(1), ld(1)
+
+=head1 AUTHOR
+
+Maintained by the Clang / LLVM Team (L<http://clang.llvm.org>).
+
+=cut
diff --git a/docs/tools/manpage.css b/docs/tools/manpage.css
new file mode 100644
index 000000000000..c922564dc3c3
--- /dev/null
+++ b/docs/tools/manpage.css
@@ -0,0 +1,256 @@
+/* Based on http://www.perldoc.com/css/perldoc.css */
+
+@import url("../llvm.css");
+
+body { font-family: Arial,Helvetica; }
+
+blockquote { margin: 10pt; }
+
+h1, a { color: #336699; }
+
+
+/*** Top menu style ****/
+.mmenuon {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #ff6600; font-size: 10pt;
+}
+.mmenuoff {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #ffffff; font-size: 10pt;
+}
+.cpyright {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #ffffff; font-size: xx-small;
+}
+.cpyrightText {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #ffffff; font-size: xx-small;
+}
+.sections {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #336699; font-size: 11pt;
+}
+.dsections {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #336699; font-size: 12pt;
+}
+.slink {
+ font-family: Arial,Helvetica; font-weight: normal; text-decoration: none;
+ color: #000000; font-size: 9pt;
+}
+
+.slink2 { font-family: Arial,Helvetica; text-decoration: none; color: #336699; }
+
+.maintitle {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #336699; font-size: 18pt;
+}
+.dblArrow {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #336699; font-size: small;
+}
+.menuSec {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #336699; font-size: small;
+}
+
+.newstext {
+ font-family: Arial,Helvetica; font-size: small;
+}
+
+.linkmenu {
+ font-family: Arial,Helvetica; color: #000000; font-weight: bold;
+ text-decoration: none;
+}
+
+P {
+ font-family: Arial,Helvetica;
+}
+
+PRE {
+ font-size: 10pt;
+}
+.quote {
+ font-family: Times; text-decoration: none;
+ color: #000000; font-size: 9pt; font-style: italic;
+}
+.smstd { font-family: Arial,Helvetica; color: #000000; font-size: x-small; }
+.std { font-family: Arial,Helvetica; color: #000000; }
+.meerkatTitle {
+ font-family: sans-serif; font-size: x-small; color: black; }
+
+.meerkatDescription { font-family: sans-serif; font-size: 10pt; color: black }
+.meerkatCategory {
+ font-family: sans-serif; font-size: 9pt; font-weight: bold; font-style: italic;
+ color: brown; }
+.meerkatChannel {
+ font-family: sans-serif; font-size: 9pt; font-style: italic; color: brown; }
+.meerkatDate { font-family: sans-serif; font-size: xx-small; color: #336699; }
+
+.tocTitle {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #333333; font-size: 10pt;
+}
+
+.toc-item {
+ font-family: Arial,Helvetica; font-weight: bold;
+ color: #336699; font-size: 10pt; text-decoration: underline;
+}
+
+.perlVersion {
+ font-family: Arial,Helvetica; font-weight: bold;
+ color: #336699; font-size: 10pt; text-decoration: none;
+}
+
+.podTitle {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #000000;
+}
+
+.docTitle {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #000000; font-size: 10pt;
+}
+.dotDot {
+ font-family: Arial,Helvetica; font-weight: bold;
+ color: #000000; font-size: 9pt;
+}
+
+.docSec {
+ font-family: Arial,Helvetica; font-weight: normal;
+ color: #333333; font-size: 9pt;
+}
+.docVersion {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #336699; font-size: 10pt;
+}
+
+.docSecs-on {
+ font-family: Arial,Helvetica; font-weight: normal; text-decoration: none;
+ color: #ff0000; font-size: 10pt;
+}
+.docSecs-off {
+ font-family: Arial,Helvetica; font-weight: normal; text-decoration: none;
+ color: #333333; font-size: 10pt;
+}
+
+h2 {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #336699; font-size: medium;
+}
+h1 {
+ font-family: Verdana,Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #336699; font-size: large;
+}
+
+DL {
+ font-family: Arial,Helvetica; font-weight: normal; text-decoration: none;
+ color: #333333; font-size: 10pt;
+}
+
+UL > LI > A {
+ font-family: Arial,Helvetica; font-weight: bold;
+ color: #336699; font-size: 10pt;
+}
+
+.moduleInfo {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #333333; font-size: 11pt;
+}
+
+.moduleInfoSec {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #336699; font-size: 10pt;
+}
+
+.moduleInfoVal {
+ font-family: Arial,Helvetica; font-weight: normal; text-decoration: underline;
+ color: #000000; font-size: 10pt;
+}
+
+.cpanNavTitle {
+ font-family: Arial,Helvetica; font-weight: bold;
+ color: #ffffff; font-size: 10pt;
+}
+.cpanNavLetter {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #333333; font-size: 9pt;
+}
+.cpanCat {
+ font-family: Arial,Helvetica; font-weight: bold; text-decoration: none;
+ color: #336699; font-size: 9pt;
+}
+
+.bttndrkblue-bkgd-top {
+ background-color: #225688;
+ background-image: url(/global/mvc_objects/images/bttndrkblue_bgtop.gif);
+}
+.bttndrkblue-bkgd-left {
+ background-color: #225688;
+ background-image: url(/global/mvc_objects/images/bttndrkblue_bgleft.gif);
+}
+.bttndrkblue-bkgd {
+ padding-top: 0px;
+ padding-bottom: 0px;
+ margin-bottom: 0px;
+ margin-top: 0px;
+ background-repeat: no-repeat;
+ background-color: #225688;
+ background-image: url(/global/mvc_objects/images/bttndrkblue_bgmiddle.gif);
+ vertical-align: top;
+}
+.bttndrkblue-bkgd-right {
+ background-color: #225688;
+ background-image: url(/global/mvc_objects/images/bttndrkblue_bgright.gif);
+}
+.bttndrkblue-bkgd-bottom {
+ background-color: #225688;
+ background-image: url(/global/mvc_objects/images/bttndrkblue_bgbottom.gif);
+}
+.bttndrkblue-text a {
+ color: #ffffff;
+ text-decoration: none;
+}
+a.bttndrkblue-text:hover {
+ color: #ffDD3C;
+ text-decoration: none;
+}
+.bg-ltblue {
+ background-color: #f0f5fa;
+}
+
+.border-left-b {
+ background: #f0f5fa url(/i/corner-leftline.gif) repeat-y;
+}
+
+.border-right-b {
+ background: #f0f5fa url(/i/corner-rightline.gif) repeat-y;
+}
+
+.border-top-b {
+ background: #f0f5fa url(/i/corner-topline.gif) repeat-x;
+}
+
+.border-bottom-b {
+ background: #f0f5fa url(/i/corner-botline.gif) repeat-x;
+}
+
+.border-right-w {
+ background: #ffffff url(/i/corner-rightline.gif) repeat-y;
+}
+
+.border-top-w {
+ background: #ffffff url(/i/corner-topline.gif) repeat-x;
+}
+
+.border-bottom-w {
+ background: #ffffff url(/i/corner-botline.gif) repeat-x;
+}
+
+.bg-white {
+ background-color: #ffffff;
+}
+
+.border-left-w {
+ background: #ffffff url(/i/corner-leftline.gif) repeat-y;
+}
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
new file mode 100644
index 000000000000..253a09b1012f
--- /dev/null
+++ b/include/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(clang)
diff --git a/include/Makefile b/include/Makefile
new file mode 100644
index 000000000000..47daabc7fa69
--- /dev/null
+++ b/include/Makefile
@@ -0,0 +1,4 @@
+LEVEL = ../../..
+DIRS := clang
+
+include $(LEVEL)/Makefile.common
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h
new file mode 100644
index 000000000000..5d5abfe011d4
--- /dev/null
+++ b/include/clang/AST/APValue.h
@@ -0,0 +1,253 @@
+//===--- APValue.h - Union class for APFloat/APSInt/Complex -----*- 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 APValue class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_APVALUE_H
+#define LLVM_CLANG_AST_APVALUE_H
+
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/APFloat.h"
+
+namespace clang {
+ class Expr;
+
+/// APValue - This class implements a discriminated union of [uninitialized]
+/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset].
+class APValue {
+ typedef llvm::APSInt APSInt;
+ typedef llvm::APFloat APFloat;
+public:
+ enum ValueKind {
+ Uninitialized,
+ Int,
+ Float,
+ ComplexInt,
+ ComplexFloat,
+ LValue,
+ Vector
+ };
+private:
+ ValueKind Kind;
+
+ struct ComplexAPSInt {
+ APSInt Real, Imag;
+ ComplexAPSInt() : Real(1), Imag(1) {}
+ };
+ struct ComplexAPFloat {
+ APFloat Real, Imag;
+ ComplexAPFloat() : Real(0.0), Imag(0.0) {}
+ };
+
+ struct LV {
+ Expr* Base;
+ uint64_t Offset;
+ };
+ struct Vec {
+ APValue *Elts;
+ unsigned NumElts;
+ Vec() : Elts(0), NumElts(0) {}
+ ~Vec() { delete[] Elts; }
+ };
+
+ enum {
+ MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ?
+ sizeof(ComplexAPSInt) : sizeof(ComplexAPFloat))
+ };
+
+ /// Data - space for the largest member in units of void*. This is an effort
+ /// to ensure that the APSInt/APFloat values have proper alignment.
+ void *Data[(MaxSize+sizeof(void*)-1)/sizeof(void*)];
+
+public:
+ APValue() : Kind(Uninitialized) {}
+ explicit APValue(const APSInt &I) : Kind(Uninitialized) {
+ MakeInt(); setInt(I);
+ }
+ explicit APValue(const APFloat &F) : Kind(Uninitialized) {
+ MakeFloat(); setFloat(F);
+ }
+ explicit APValue(const APValue *E, unsigned N) : Kind(Uninitialized) {
+ MakeVector(); setVector(E, N);
+ }
+ APValue(const APSInt &R, const APSInt &I) : Kind(Uninitialized) {
+ MakeComplexInt(); setComplexInt(R, I);
+ }
+ APValue(const APFloat &R, const APFloat &I) : Kind(Uninitialized) {
+ MakeComplexFloat(); setComplexFloat(R, I);
+ }
+ APValue(const APValue &RHS) : Kind(Uninitialized) {
+ *this = RHS;
+ }
+ APValue(Expr* B, uint64_t O) : Kind(Uninitialized) {
+ MakeLValue(); setLValue(B, O);
+ }
+ ~APValue() {
+ MakeUninit();
+ }
+
+ ValueKind getKind() const { return Kind; }
+ bool isUninit() const { return Kind == Uninitialized; }
+ bool isInt() const { return Kind == Int; }
+ bool isFloat() const { return Kind == Float; }
+ bool isComplexInt() const { return Kind == ComplexInt; }
+ bool isComplexFloat() const { return Kind == ComplexFloat; }
+ bool isLValue() const { return Kind == LValue; }
+ bool isVector() const { return Kind == Vector; }
+
+ void print(llvm::raw_ostream &OS) const;
+ void dump() const;
+
+ APSInt &getInt() {
+ assert(isInt() && "Invalid accessor");
+ return *(APSInt*)(void*)Data;
+ }
+ const APSInt &getInt() const {
+ return const_cast<APValue*>(this)->getInt();
+ }
+
+ APFloat &getFloat() {
+ assert(isFloat() && "Invalid accessor");
+ return *(APFloat*)(void*)Data;
+ }
+ const APFloat &getFloat() const {
+ return const_cast<APValue*>(this)->getFloat();
+ }
+
+ APValue &getVectorElt(unsigned i) const {
+ assert(isVector() && "Invalid accessor");
+ return ((Vec*)(void*)Data)->Elts[i];
+ }
+ unsigned getVectorLength() const {
+ assert(isVector() && "Invalid accessor");
+ return ((Vec*)(void *)Data)->NumElts;
+ }
+
+ APSInt &getComplexIntReal() {
+ assert(isComplexInt() && "Invalid accessor");
+ return ((ComplexAPSInt*)(void*)Data)->Real;
+ }
+ const APSInt &getComplexIntReal() const {
+ return const_cast<APValue*>(this)->getComplexIntReal();
+ }
+
+ APSInt &getComplexIntImag() {
+ assert(isComplexInt() && "Invalid accessor");
+ return ((ComplexAPSInt*)(void*)Data)->Imag;
+ }
+ const APSInt &getComplexIntImag() const {
+ return const_cast<APValue*>(this)->getComplexIntImag();
+ }
+
+ APFloat &getComplexFloatReal() {
+ assert(isComplexFloat() && "Invalid accessor");
+ return ((ComplexAPFloat*)(void*)Data)->Real;
+ }
+ const APFloat &getComplexFloatReal() const {
+ return const_cast<APValue*>(this)->getComplexFloatReal();
+ }
+
+ APFloat &getComplexFloatImag() {
+ assert(isComplexFloat() && "Invalid accessor");
+ return ((ComplexAPFloat*)(void*)Data)->Imag;
+ }
+ const APFloat &getComplexFloatImag() const {
+ return const_cast<APValue*>(this)->getComplexFloatImag();
+ }
+
+ Expr* getLValueBase() const {
+ assert(isLValue() && "Invalid accessor");
+ return ((const LV*)(const void*)Data)->Base;
+ }
+ uint64_t getLValueOffset() const {
+ assert(isLValue() && "Invalid accessor");
+ return ((const LV*)(const void*)Data)->Offset;
+ }
+
+ void setInt(const APSInt &I) {
+ assert(isInt() && "Invalid accessor");
+ *(APSInt*)(void*)Data = I;
+ }
+ void setFloat(const APFloat &F) {
+ assert(isFloat() && "Invalid accessor");
+ *(APFloat*)(void*)Data = F;
+ }
+ void setVector(const APValue *E, unsigned N) {
+ assert(isVector() && "Invalid accessor");
+ ((Vec*)(void*)Data)->Elts = new APValue[N];
+ ((Vec*)(void*)Data)->NumElts = N;
+ for (unsigned i = 0; i != N; ++i)
+ ((Vec*)(void*)Data)->Elts[i] = E[i];
+ }
+ void setComplexInt(const APSInt &R, const APSInt &I) {
+ assert(R.getBitWidth() == I.getBitWidth() &&
+ "Invalid complex int (type mismatch).");
+ assert(isComplexInt() && "Invalid accessor");
+ ((ComplexAPSInt*)(void*)Data)->Real = R;
+ ((ComplexAPSInt*)(void*)Data)->Imag = I;
+ }
+ void setComplexFloat(const APFloat &R, const APFloat &I) {
+ assert(&R.getSemantics() == &I.getSemantics() &&
+ "Invalid complex float (type mismatch).");
+ assert(isComplexFloat() && "Invalid accessor");
+ ((ComplexAPFloat*)(void*)Data)->Real = R;
+ ((ComplexAPFloat*)(void*)Data)->Imag = I;
+ }
+ void setLValue(Expr *B, uint64_t O) {
+ assert(isLValue() && "Invalid accessor");
+ ((LV*)(void*)Data)->Base = B;
+ ((LV*)(void*)Data)->Offset = O;
+ }
+
+ const APValue &operator=(const APValue &RHS);
+
+private:
+ void MakeUninit();
+ void MakeInt() {
+ assert(isUninit() && "Bad state change");
+ new ((void*)Data) APSInt(1);
+ Kind = Int;
+ }
+ void MakeFloat() {
+ assert(isUninit() && "Bad state change");
+ new ((APFloat*)(void*)Data) APFloat(0.0);
+ Kind = Float;
+ }
+ void MakeVector() {
+ assert(isUninit() && "Bad state change");
+ new ((Vec*)(void*)Data) Vec();
+ Kind = Vector;
+ }
+ void MakeComplexInt() {
+ assert(isUninit() && "Bad state change");
+ new ((ComplexAPSInt*)(void*)Data) ComplexAPSInt();
+ Kind = ComplexInt;
+ }
+ void MakeComplexFloat() {
+ assert(isUninit() && "Bad state change");
+ new ((ComplexAPFloat*)(void*)Data) ComplexAPFloat();
+ Kind = ComplexFloat;
+ }
+ void MakeLValue() {
+ assert(isUninit() && "Bad state change");
+ new ((LV*)(void*)Data) LV();
+ Kind = LValue;
+ }
+};
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const APValue &V) {
+ V.print(OS);
+ return OS;
+}
+
+} // end namespace clang.
+
+#endif
diff --git a/include/clang/AST/AST.h b/include/clang/AST/AST.h
new file mode 100644
index 000000000000..164c5fbbb6e2
--- /dev/null
+++ b/include/clang/AST/AST.h
@@ -0,0 +1,28 @@
+//===--- AST.h - "Umbrella" header for AST library --------------*- 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 to the AST classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_AST_H
+#define LLVM_CLANG_AST_AST_H
+
+// This header exports all AST interfaces.
+#include "clang/AST/ASTContext.h"
+#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/ExprObjC.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/StmtVisitor.h"
+
+#endif
diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h
new file mode 100644
index 000000000000..6dc7e13d8f70
--- /dev/null
+++ b/include/clang/AST/ASTConsumer.h
@@ -0,0 +1,81 @@
+//===--- ASTConsumer.h - Abstract interface for reading ASTs ----*- 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 ASTConsumer class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_ASTCONSUMER_H
+#define LLVM_CLANG_AST_ASTCONSUMER_H
+
+namespace clang {
+ class ASTContext;
+ class DeclGroupRef;
+ class TagDecl;
+ class HandleTagDeclDefinition;
+ class SemaConsumer; // layering violation required for safe SemaConsumer
+ class VarDecl;
+
+/// ASTConsumer - This is an abstract interface that should be implemented by
+/// clients that read ASTs. This abstraction layer allows the client to be
+/// independent of the AST producer (e.g. parser vs AST dump file reader, etc).
+class ASTConsumer {
+ /// \brief Whether this AST consumer also requires information about
+ /// semantic analysis.
+ bool SemaConsumer;
+
+ friend class SemaConsumer;
+
+public:
+ ASTConsumer() : SemaConsumer(false) { }
+
+ virtual ~ASTConsumer() {}
+
+ /// Initialize - This is called to initialize the consumer, providing the
+ /// ASTContext and the Action.
+ virtual void Initialize(ASTContext &Context) {}
+
+ /// HandleTopLevelDecl - Handle the specified top-level declaration. This is
+ /// called by the parser to process every top-level Decl*. Note that D can
+ /// be the head of a chain of Decls (e.g. for `int a, b` the chain will have
+ /// two elements). Use Decl::getNextDeclarator() to walk the chain.
+ virtual void HandleTopLevelDecl(DeclGroupRef D);
+
+ /// HandleTranslationUnit - This method is called when the ASTs for entire
+ /// translation unit have been parsed.
+ virtual void HandleTranslationUnit(ASTContext &Ctx) {}
+
+ /// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
+ /// (e.g. struct, union, enum, class) is completed. This allows the client to
+ /// hack on the type, which can occur at any point in the file (because these
+ /// can be defined in declspecs).
+ virtual void HandleTagDeclDefinition(TagDecl *D) {}
+
+ /// \brief Callback invoked at the end of a translation unit to
+ /// notify the consumer that the given tentative definition should
+ /// be completed.
+ ///
+ /// The variable declaration itself will be a tentative
+ /// definition. If it had an incomplete array type, its type will
+ /// have already been changed to an array of size 1. However, the
+ /// declaration remains a tentative definition and has not been
+ /// modified by the introduction of an implicit zero initializer.
+ virtual void CompleteTentativeDefinition(VarDecl *D) {}
+
+ /// PrintStats - If desired, print any statistics.
+ virtual void PrintStats() {
+ }
+
+ // Support isa/cast/dyn_cast
+ static bool classof(const ASTConsumer *) { return true; }
+};
+
+} // end namespace clang.
+
+#endif
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
new file mode 100644
index 000000000000..e99e9f2b18f3
--- /dev/null
+++ b/include/clang/AST/ASTContext.h
@@ -0,0 +1,857 @@
+//===--- ASTContext.h - Context to hold long-lived AST nodes ----*- 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 ASTContext interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_ASTCONTEXT_H
+#define LLVM_CLANG_AST_ASTCONTEXT_H
+
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Builtins.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/TemplateName.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/Allocator.h"
+#include <vector>
+
+namespace llvm {
+ struct fltSemantics;
+}
+
+namespace clang {
+ class FileManager;
+ class ASTRecordLayout;
+ class Expr;
+ class ExternalASTSource;
+ class IdentifierTable;
+ class SelectorTable;
+ class SourceManager;
+ class TargetInfo;
+ // Decls
+ class Decl;
+ class ObjCPropertyDecl;
+ class RecordDecl;
+ class TagDecl;
+ class TranslationUnitDecl;
+ class TypeDecl;
+ class TypedefDecl;
+ class TemplateTypeParmDecl;
+ class FieldDecl;
+ class ObjCIvarRefExpr;
+ class ObjCIvarDecl;
+
+/// ASTContext - This class holds long-lived AST nodes (such as types and
+/// decls) that can be referred to throughout the semantic analysis of a file.
+class ASTContext {
+ std::vector<Type*> Types;
+ llvm::FoldingSet<ExtQualType> ExtQualTypes;
+ llvm::FoldingSet<ComplexType> ComplexTypes;
+ llvm::FoldingSet<PointerType> PointerTypes;
+ llvm::FoldingSet<BlockPointerType> BlockPointerTypes;
+ llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes;
+ llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes;
+ llvm::FoldingSet<MemberPointerType> MemberPointerTypes;
+ llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes;
+ llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes;
+ std::vector<VariableArrayType*> VariableArrayTypes;
+ std::vector<DependentSizedArrayType*> DependentSizedArrayTypes;
+ llvm::FoldingSet<VectorType> VectorTypes;
+ llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes;
+ llvm::FoldingSet<FunctionProtoType> FunctionProtoTypes;
+ llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
+ llvm::FoldingSet<TemplateSpecializationType> TemplateSpecializationTypes;
+ llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes;
+ llvm::FoldingSet<TypenameType> TypenameTypes;
+ llvm::FoldingSet<ObjCQualifiedInterfaceType> ObjCQualifiedInterfaceTypes;
+ llvm::FoldingSet<ObjCQualifiedIdType> ObjCQualifiedIdTypes;
+
+ llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
+ llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
+
+ /// \brief The set of nested name specifiers.
+ ///
+ /// This set is managed by the NestedNameSpecifier class.
+ llvm::FoldingSet<NestedNameSpecifier> NestedNameSpecifiers;
+ NestedNameSpecifier *GlobalNestedNameSpecifier;
+ friend class NestedNameSpecifier;
+
+ /// ASTRecordLayouts - A cache mapping from RecordDecls to ASTRecordLayouts.
+ /// This is lazily created. This is intentionally not serialized.
+ llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*> ASTRecordLayouts;
+ llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*> ObjCLayouts;
+
+ llvm::DenseMap<unsigned, FixedWidthIntType*> SignedFixedWidthIntTypes;
+ llvm::DenseMap<unsigned, FixedWidthIntType*> UnsignedFixedWidthIntTypes;
+
+ /// 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 ObjCIdType;
+ const RecordType *IdStructType;
+
+ /// ObjCSelType - another pseudo built-in typedef type (set by Sema).
+ QualType ObjCSelType;
+ const RecordType *SelStructType;
+
+ /// 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 ObjCClassType;
+ const RecordType *ClassStructType;
+
+ QualType ObjCConstantStringType;
+ RecordDecl *CFConstantStringTypeDecl;
+
+ RecordDecl *ObjCFastEnumerationStateTypeDecl;
+
+ TranslationUnitDecl *TUDecl;
+
+ /// SourceMgr - The associated SourceManager object.
+ SourceManager &SourceMgr;
+
+ /// LangOpts - The language options used to create the AST associated with
+ /// this ASTContext object.
+ LangOptions LangOpts;
+
+ /// MallocAlloc/BumpAlloc - The allocator objects used to create AST objects.
+ bool FreeMemory;
+ llvm::MallocAllocator MallocAlloc;
+ llvm::BumpPtrAllocator BumpAlloc;
+public:
+ TargetInfo &Target;
+ IdentifierTable &Idents;
+ SelectorTable &Selectors;
+ DeclarationNameTable DeclarationNames;
+ llvm::OwningPtr<ExternalASTSource> ExternalSource;
+ clang::PrintingPolicy PrintingPolicy;
+
+ SourceManager& getSourceManager() { return SourceMgr; }
+ const SourceManager& getSourceManager() const { return SourceMgr; }
+ void *Allocate(unsigned Size, unsigned Align = 8) {
+ return FreeMemory ? MallocAlloc.Allocate(Size, Align) :
+ BumpAlloc.Allocate(Size, Align);
+ }
+ void Deallocate(void *Ptr) {
+ if (FreeMemory)
+ MallocAlloc.Deallocate(Ptr);
+ }
+ const LangOptions& getLangOptions() const { return LangOpts; }
+
+ FullSourceLoc getFullLoc(SourceLocation Loc) const {
+ return FullSourceLoc(Loc,SourceMgr);
+ }
+
+ TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
+
+ Builtin::Context BuiltinInfo;
+
+ // Builtin Types.
+ QualType VoidTy;
+ QualType BoolTy;
+ QualType CharTy;
+ QualType WCharTy; // [C++ 3.9.1p5], integer type in C99.
+ QualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy, Int128Ty;
+ QualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy;
+ QualType UnsignedLongLongTy, UnsignedInt128Ty;
+ QualType FloatTy, DoubleTy, LongDoubleTy;
+ QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
+ QualType VoidPtrTy, NullPtrTy;
+ QualType OverloadTy;
+ QualType DependentTy;
+
+ ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t,
+ IdentifierTable &idents, SelectorTable &sels,
+ bool FreeMemory = true, unsigned size_reserve=0,
+ bool InitializeBuiltins = true);
+
+ ~ASTContext();
+
+ /// \brief Initialize builtins.
+ ///
+ /// Typically, this routine will be called automatically by the
+ /// constructor. However, in certain cases (e.g., when there is a
+ /// PCH file to be loaded), the constructor does not perform
+ /// initialization for builtins. This routine can be called to
+ /// perform the initialization.
+ void InitializeBuiltins(IdentifierTable &idents);
+
+ /// \brief Attach an external AST source to the AST context.
+ ///
+ /// The external AST source provides the ability to load parts of
+ /// the abstract syntax tree as needed from some external storage,
+ /// e.g., a precompiled header.
+ void setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source);
+
+ /// \brief Retrieve a pointer to the external AST source associated
+ /// with this AST context, if any.
+ ExternalASTSource *getExternalSource() const { return ExternalSource.get(); }
+
+ void PrintStats() const;
+ const std::vector<Type*>& getTypes() const { return Types; }
+
+ //===--------------------------------------------------------------------===//
+ // Type Constructors
+ //===--------------------------------------------------------------------===//
+
+ /// getAddSpaceQualType - Return the uniqued reference to the type for an
+ /// address space qualified type with the specified type and address space.
+ /// The resulting type has a union of the qualifiers from T and the address
+ /// space. If T already has an address space specifier, it is silently
+ /// replaced.
+ QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace);
+
+ /// getObjCGCQualType - Returns the uniqued reference to the type for an
+ /// objc gc qualified type. The retulting type has a union of the qualifiers
+ /// from T and the gc attribute.
+ QualType getObjCGCQualType(QualType T, QualType::GCAttrTypes gcAttr);
+
+ /// getComplexType - Return the uniqued reference to the type for a complex
+ /// number with the specified element type.
+ QualType getComplexType(QualType T);
+
+ /// getPointerType - Return the uniqued reference to the type for a pointer to
+ /// the specified type.
+ QualType getPointerType(QualType T);
+
+ /// getBlockPointerType - Return the uniqued reference to the type for a block
+ /// of the specified type.
+ QualType getBlockPointerType(QualType T);
+
+ /// getLValueReferenceType - Return the uniqued reference to the type for an
+ /// lvalue reference to the specified type.
+ QualType getLValueReferenceType(QualType T);
+
+ /// getRValueReferenceType - Return the uniqued reference to the type for an
+ /// rvalue reference to the specified type.
+ QualType getRValueReferenceType(QualType T);
+
+ /// getMemberPointerType - Return the uniqued reference to the type for a
+ /// member pointer to the specified type in the specified class. The class
+ /// is a Type because it could be a dependent name.
+ QualType getMemberPointerType(QualType T, const Type *Cls);
+
+ /// getVariableArrayType - Returns a non-unique reference to the type for a
+ /// variable array of the specified element type.
+ QualType getVariableArrayType(QualType EltTy, Expr *NumElts,
+ ArrayType::ArraySizeModifier ASM,
+ unsigned EltTypeQuals);
+
+ /// getDependentSizedArrayType - Returns a non-unique reference to
+ /// the type for a dependently-sized array of the specified element
+ /// type. FIXME: We will need these to be uniqued, or at least
+ /// comparable, at some point.
+ QualType getDependentSizedArrayType(QualType EltTy, Expr *NumElts,
+ ArrayType::ArraySizeModifier ASM,
+ unsigned EltTypeQuals);
+
+ /// getIncompleteArrayType - Returns a unique reference to the type for a
+ /// incomplete array of the specified element type.
+ QualType getIncompleteArrayType(QualType EltTy,
+ ArrayType::ArraySizeModifier ASM,
+ unsigned EltTypeQuals);
+
+ /// getConstantArrayType - Return the unique reference to the type for a
+ /// constant array of the specified element type.
+ QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize,
+ ArrayType::ArraySizeModifier ASM,
+ unsigned EltTypeQuals);
+
+ /// getVectorType - Return the unique reference to a vector type of
+ /// the specified element type and size. VectorType must be a built-in type.
+ QualType getVectorType(QualType VectorType, unsigned NumElts);
+
+ /// getExtVectorType - Return the unique reference to an extended vector type
+ /// of the specified element type and size. VectorType must be a built-in
+ /// type.
+ QualType getExtVectorType(QualType VectorType, unsigned NumElts);
+
+ /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
+ ///
+ QualType getFunctionNoProtoType(QualType ResultTy);
+
+ /// getFunctionType - Return a normal function type with a typed argument
+ /// list. isVariadic indicates whether the argument list includes '...'.
+ QualType getFunctionType(QualType ResultTy, const QualType *ArgArray,
+ unsigned NumArgs, bool isVariadic,
+ unsigned TypeQuals, bool hasExceptionSpec = false,
+ bool hasAnyExceptionSpec = false,
+ unsigned NumExs = 0, const QualType *ExArray = 0);
+
+ /// getTypeDeclType - Return the unique reference to the type for
+ /// the specified type declaration.
+ QualType getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl=0);
+
+ /// getTypedefType - Return the unique reference to the type for the
+ /// specified typename decl.
+ QualType getTypedefType(TypedefDecl *Decl);
+ QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl);
+
+ QualType getTemplateTypeParmType(unsigned Depth, unsigned Index,
+ IdentifierInfo *Name = 0);
+
+ QualType getTemplateSpecializationType(TemplateName T,
+ const TemplateArgument *Args,
+ unsigned NumArgs,
+ QualType Canon = QualType());
+
+ QualType getQualifiedNameType(NestedNameSpecifier *NNS,
+ QualType NamedType);
+ QualType getTypenameType(NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name,
+ QualType Canon = QualType());
+ QualType getTypenameType(NestedNameSpecifier *NNS,
+ const TemplateSpecializationType *TemplateId,
+ QualType Canon = QualType());
+
+ /// getObjCQualifiedInterfaceType - Return a
+ /// ObjCQualifiedInterfaceType type for the given interface decl and
+ /// the conforming protocol list.
+ QualType getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl,
+ ObjCProtocolDecl **ProtocolList,
+ unsigned NumProtocols);
+
+ /// getObjCQualifiedIdType - Return an ObjCQualifiedIdType for a
+ /// given 'id' and conforming protocol list.
+ QualType getObjCQualifiedIdType(ObjCProtocolDecl **ProtocolList,
+ unsigned NumProtocols);
+
+
+ /// getTypeOfType - GCC extension.
+ QualType getTypeOfExprType(Expr *e);
+ QualType getTypeOfType(QualType t);
+
+ /// getTagDeclType - Return the unique reference to the type for the
+ /// specified TagDecl (struct/union/class/enum) decl.
+ QualType getTagDeclType(TagDecl *Decl);
+
+ /// getSizeType - Return the unique type for "size_t" (C99 7.17), defined
+ /// in <stddef.h>. The sizeof operator requires this (C99 6.5.3.4p4).
+ QualType getSizeType() const;
+
+ /// getWCharType - In C++, this returns the unique wchar_t type. In C99, this
+ /// returns a type compatible with the type defined in <stddef.h> as defined
+ /// by the target.
+ QualType getWCharType() const { return WCharTy; }
+
+ /// getSignedWCharType - Return the type of "signed wchar_t".
+ /// Used when in C++, as a GCC extension.
+ QualType getSignedWCharType() const;
+
+ /// getUnsignedWCharType - Return the type of "unsigned wchar_t".
+ /// Used when in C++, as a GCC extension.
+ QualType getUnsignedWCharType() const;
+
+ /// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?)
+ /// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
+ QualType getPointerDiffType() const;
+
+ // getCFConstantStringType - Return the C structure type used to represent
+ // constant CFStrings.
+ QualType getCFConstantStringType();
+
+ /// Get the structure type used to representation CFStrings, or NULL
+ /// if it hasn't yet been built.
+ QualType getRawCFConstantStringType() {
+ if (CFConstantStringTypeDecl)
+ return getTagDeclType(CFConstantStringTypeDecl);
+ return QualType();
+ }
+ void setCFConstantStringType(QualType T);
+
+ // This setter/getter represents the ObjC type for an NSConstantString.
+ void setObjCConstantStringInterface(ObjCInterfaceDecl *Decl);
+ QualType getObjCConstantStringInterface() const {
+ return ObjCConstantStringType;
+ }
+
+ //// This gets the struct used to keep track of fast enumerations.
+ QualType getObjCFastEnumerationStateType();
+
+ /// Get the ObjCFastEnumerationState type, or NULL if it hasn't yet
+ /// been built.
+ QualType getRawObjCFastEnumerationStateType() {
+ if (ObjCFastEnumerationStateTypeDecl)
+ return getTagDeclType(ObjCFastEnumerationStateTypeDecl);
+ return QualType();
+ }
+
+ void setObjCFastEnumerationStateType(QualType T);
+
+ /// getObjCEncodingForType - Emit the ObjC type encoding for the
+ /// given type into \arg S. If \arg NameFields is specified then
+ /// record field names are also encoded.
+ void getObjCEncodingForType(QualType t, std::string &S,
+ const FieldDecl *Field=0);
+
+ void getLegacyIntegralTypeEncoding(QualType &t) const;
+
+ // Put the string version of type qualifiers into S.
+ void getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
+ std::string &S) const;
+
+ /// getObjCEncodingForMethodDecl - Return the encoded type for this method
+ /// declaration.
+ void getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S);
+
+ /// getObjCEncodingForPropertyDecl - Return the encoded type for
+ /// this method declaration. If non-NULL, Container must be either
+ /// an ObjCCategoryImplDecl or ObjCImplementationDecl; it should
+ /// only be NULL when getting encodings for protocol properties.
+ void getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
+ const Decl *Container,
+ std::string &S);
+
+ /// getObjCEncodingTypeSize returns size of type for objective-c encoding
+ /// purpose.
+ int getObjCEncodingTypeSize(QualType t);
+
+ /// 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 ObjCIdType; }
+ void setObjCIdType(QualType T);
+
+ void setObjCSelType(QualType T);
+ QualType getObjCSelType() const { return ObjCSelType; }
+
+ void setObjCProtoType(QualType QT);
+ QualType getObjCProtoType() const { return ObjCProtoType; }
+
+ /// 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 ObjCClassType; }
+ void setObjCClassType(QualType T);
+
+ void setBuiltinVaListType(QualType T);
+ QualType getBuiltinVaListType() const { return BuiltinVaListType; }
+
+ QualType getFixedWidthIntType(unsigned Width, bool Signed);
+
+ TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS,
+ bool TemplateKeyword,
+ TemplateDecl *Template);
+
+ TemplateName getDependentTemplateName(NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name);
+
+private:
+ QualType getFromTargetType(unsigned Type) const;
+
+ //===--------------------------------------------------------------------===//
+ // Type Predicates.
+ //===--------------------------------------------------------------------===//
+
+public:
+ /// isObjCObjectPointerType - Returns true if type is an Objective-C pointer
+ /// to an object type. This includes "id" and "Class" (two 'special' pointers
+ /// to struct), Interface* (pointer to ObjCInterfaceType) and id<P> (qualified
+ /// ID type).
+ bool isObjCObjectPointerType(QualType Ty) const;
+
+ /// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's
+ /// garbage collection attribute.
+ ///
+ QualType::GCAttrTypes getObjCGCAttrKind(const QualType &Ty) const;
+
+ /// isObjCNSObjectType - Return true if this is an NSObject object with
+ /// its NSObject attribute set.
+ bool isObjCNSObjectType(QualType Ty) const;
+
+ //===--------------------------------------------------------------------===//
+ // Type Sizing and Analysis
+ //===--------------------------------------------------------------------===//
+
+ /// getFloatTypeSemantics - Return the APFloat 'semantics' for the specified
+ /// scalar floating point type.
+ const llvm::fltSemantics &getFloatTypeSemantics(QualType T) const;
+
+ /// getTypeInfo - Get the size and alignment of the specified complete type in
+ /// bits.
+ std::pair<uint64_t, unsigned> getTypeInfo(const Type *T);
+ std::pair<uint64_t, unsigned> getTypeInfo(QualType T) {
+ return getTypeInfo(T.getTypePtr());
+ }
+
+ /// getTypeSize - Return the size of the specified type, in bits. This method
+ /// does not work on incomplete types.
+ uint64_t getTypeSize(QualType T) {
+ return getTypeInfo(T).first;
+ }
+ uint64_t getTypeSize(const Type *T) {
+ return getTypeInfo(T).first;
+ }
+
+ /// getTypeAlign - Return the ABI-specified alignment of a type, in bits.
+ /// This method does not work on incomplete types.
+ unsigned getTypeAlign(QualType T) {
+ return getTypeInfo(T).second;
+ }
+ unsigned getTypeAlign(const Type *T) {
+ return getTypeInfo(T).second;
+ }
+
+ /// getPreferredTypeAlign - Return the "preferred" alignment of the specified
+ /// type for the current target in bits. This can be different than the ABI
+ /// alignment in cases where it is beneficial for performance to overalign
+ /// a data type.
+ unsigned getPreferredTypeAlign(const Type *T);
+
+ /// getDeclAlignInBytes - Return the alignment of the specified decl
+ /// that should be returned by __alignof(). Note that bitfields do
+ /// not have a valid alignment, so this method will assert on them.
+ unsigned getDeclAlignInBytes(const Decl *D);
+
+ /// 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 &getASTRecordLayout(const RecordDecl *D);
+
+ /// getASTObjCInterfaceLayout - Get or compute information about the
+ /// layout of the specified Objective-C interface.
+ const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D);
+
+ /// getASTObjCImplementationLayout - Get or compute information about
+ /// the layout of the specified Objective-C implementation. This may
+ /// differ from the interface if synthesized ivars are present.
+ const ASTRecordLayout &
+ getASTObjCImplementationLayout(const ObjCImplementationDecl *D);
+
+ void CollectObjCIvars(const ObjCInterfaceDecl *OI,
+ llvm::SmallVectorImpl<FieldDecl*> &Fields);
+
+ void CollectSynthesizedIvars(const ObjCInterfaceDecl *OI,
+ llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
+ void CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD,
+ llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
+
+ //===--------------------------------------------------------------------===//
+ // Type Operators
+ //===--------------------------------------------------------------------===//
+
+ /// getCanonicalType - Return the canonical (structural) type corresponding to
+ /// the specified potentially non-canonical type. The non-canonical version
+ /// of a type may have many "decorated" versions of types. Decorators can
+ /// include typedefs, 'typeof' operators, etc. The returned type is guaranteed
+ /// to be free of any of these, allowing two canonical types to be compared
+ /// for exact equality with a simple pointer comparison.
+ QualType getCanonicalType(QualType T);
+ const Type *getCanonicalType(const Type *T) {
+ return T->getCanonicalTypeInternal().getTypePtr();
+ }
+
+ /// \brief Determine whether the given types are equivalent.
+ bool hasSameType(QualType T1, QualType T2) {
+ return getCanonicalType(T1) == getCanonicalType(T2);
+ }
+
+ /// \brief Determine whether the given types are equivalent after
+ /// cvr-qualifiers have been removed.
+ bool hasSameUnqualifiedType(QualType T1, QualType T2) {
+ T1 = getCanonicalType(T1);
+ T2 = getCanonicalType(T2);
+ return T1.getUnqualifiedType() == T2.getUnqualifiedType();
+ }
+
+ /// \brief Retrieves the "canonical" declaration of the given declaration.
+ Decl *getCanonicalDecl(Decl *D);
+
+ /// \brief Retrieves the "canonical" declaration of the given tag
+ /// declaration.
+ ///
+ /// The canonical declaration for the given tag declaration is
+ /// either the definition of the tag (if it is a complete type) or
+ /// the first declaration of that tag.
+ TagDecl *getCanonicalDecl(TagDecl *Tag) {
+ return cast<TagDecl>(getCanonicalDecl((Decl *)Tag));
+ }
+
+ /// \brief Retrieves the "canonical" declaration of
+
+ /// \brief Retrieves the "canonical" nested name specifier for a
+ /// given nested name specifier.
+ ///
+ /// The canonical nested name specifier is a nested name specifier
+ /// that uniquely identifies a type or namespace within the type
+ /// system. For example, given:
+ ///
+ /// \code
+ /// namespace N {
+ /// struct S {
+ /// template<typename T> struct X { typename T* type; };
+ /// };
+ /// }
+ ///
+ /// template<typename T> struct Y {
+ /// typename N::S::X<T>::type member;
+ /// };
+ /// \endcode
+ ///
+ /// Here, the nested-name-specifier for N::S::X<T>:: will be
+ /// S::X<template-param-0-0>, since 'S' and 'X' are uniquely defined
+ /// by declarations in the type system and the canonical type for
+ /// the template type parameter 'T' is template-param-0-0.
+ NestedNameSpecifier *
+ getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS);
+
+ /// \brief Retrieves the "canonical" template name that refers to a
+ /// given template.
+ ///
+ /// The canonical template name is the simplest expression that can
+ /// be used to refer to a given template. For most templates, this
+ /// expression is just the template declaration itself. For example,
+ /// the template std::vector can be referred to via a variety of
+ /// names---std::vector, ::std::vector, vector (if vector is in
+ /// scope), etc.---but all of these names map down to the same
+ /// TemplateDecl, which is used to form the canonical template name.
+ ///
+ /// Dependent template names are more interesting. Here, the
+ /// template name could be something like T::template apply or
+ /// std::allocator<T>::template rebind, where the nested name
+ /// specifier itself is dependent. In this case, the canonical
+ /// template name uses the shortest form of the dependent
+ /// nested-name-specifier, which itself contains all canonical
+ /// types, values, and templates.
+ TemplateName getCanonicalTemplateName(TemplateName Name);
+
+ /// Type Query functions. If the type is an instance of the specified class,
+ /// return the Type pointer for the underlying maximally pretty type. This
+ /// is a member of ASTContext because this may need to do some amount of
+ /// canonicalization, e.g. to move type qualifiers into the element type.
+ const ArrayType *getAsArrayType(QualType T);
+ const ConstantArrayType *getAsConstantArrayType(QualType T) {
+ return dyn_cast_or_null<ConstantArrayType>(getAsArrayType(T));
+ }
+ const VariableArrayType *getAsVariableArrayType(QualType T) {
+ return dyn_cast_or_null<VariableArrayType>(getAsArrayType(T));
+ }
+ const IncompleteArrayType *getAsIncompleteArrayType(QualType T) {
+ return dyn_cast_or_null<IncompleteArrayType>(getAsArrayType(T));
+ }
+
+ /// getBaseElementType - Returns the innermost element type of a variable
+ /// length array type. For example, will return "int" for int[m][n]
+ QualType getBaseElementType(const VariableArrayType *VAT);
+
+ /// getArrayDecayedType - Return the properly qualified result of decaying the
+ /// specified array type to a pointer. This operation is non-trivial when
+ /// handling typedefs etc. The canonical type of "T" must be an array type,
+ /// this returns a pointer to a properly qualified element of the array.
+ ///
+ /// See C99 6.7.5.3p7 and C99 6.3.2.1p3.
+ QualType getArrayDecayedType(QualType T);
+
+ /// getIntegerTypeOrder - Returns the highest ranked integer type:
+ /// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If
+ /// LHS < RHS, return -1.
+ int getIntegerTypeOrder(QualType LHS, QualType RHS);
+
+ /// getFloatingTypeOrder - Compare the rank of the two specified floating
+ /// point types, ignoring the domain of the type (i.e. 'double' ==
+ /// '_Complex double'). If LHS > RHS, return 1. If LHS == RHS, return 0. If
+ /// LHS < RHS, return -1.
+ int getFloatingTypeOrder(QualType LHS, QualType RHS);
+
+ /// getFloatingTypeOfSizeWithinDomain - Returns a real floating
+ /// point or a complex type (based on typeDomain/typeSize).
+ /// 'typeDomain' is a real floating point or complex type.
+ /// 'typeSize' is a real floating point or complex type.
+ QualType getFloatingTypeOfSizeWithinDomain(QualType typeSize,
+ QualType typeDomain) const;
+
+private:
+ // Helper for integer ordering
+ unsigned getIntegerRank(Type* T);
+
+public:
+
+ //===--------------------------------------------------------------------===//
+ // Type Compatibility Predicates
+ //===--------------------------------------------------------------------===//
+
+ /// Compatibility predicates used to check assignment expressions.
+ bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1
+ bool typesAreBlockCompatible(QualType lhs, QualType rhs);
+
+ bool isObjCIdType(QualType T) const {
+ return T == ObjCIdType;
+ }
+ bool isObjCIdStructType(QualType T) const {
+ if (!IdStructType) // ObjC isn't enabled
+ return false;
+ return T->getAsStructureType() == IdStructType;
+ }
+ bool isObjCClassType(QualType T) const {
+ return T == ObjCClassType;
+ }
+ bool isObjCClassStructType(QualType T) const {
+ if (!ClassStructType) // ObjC isn't enabled
+ return false;
+ return T->getAsStructureType() == ClassStructType;
+ }
+ bool isObjCSelType(QualType T) const {
+ assert(SelStructType && "isObjCSelType used before 'SEL' type is built");
+ return T->getAsStructureType() == SelStructType;
+ }
+
+ // Check the safety of assignment from LHS to RHS
+ bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
+ const ObjCInterfaceType *RHS);
+ bool areComparableObjCPointerTypes(QualType LHS, QualType RHS);
+
+ // Functions for calculating composite types
+ QualType mergeTypes(QualType, QualType);
+ QualType mergeFunctionTypes(QualType, QualType);
+
+ //===--------------------------------------------------------------------===//
+ // Integer Predicates
+ //===--------------------------------------------------------------------===//
+
+ // The width of an integer, as defined in C99 6.2.6.2. This is the number
+ // of bits in an integer type excluding any padding bits.
+ unsigned getIntWidth(QualType T);
+
+ // Per C99 6.2.5p6, for every signed integer type, there is a corresponding
+ // unsigned integer type. This method takes a signed type, and returns the
+ // corresponding unsigned integer type.
+ QualType getCorrespondingUnsignedType(QualType T);
+
+ //===--------------------------------------------------------------------===//
+ // Type Iterators.
+ //===--------------------------------------------------------------------===//
+
+ typedef std::vector<Type*>::iterator type_iterator;
+ typedef std::vector<Type*>::const_iterator const_type_iterator;
+
+ type_iterator types_begin() { return Types.begin(); }
+ type_iterator types_end() { return Types.end(); }
+ const_type_iterator types_begin() const { return Types.begin(); }
+ const_type_iterator types_end() const { return Types.end(); }
+
+ //===--------------------------------------------------------------------===//
+ // Integer Values
+ //===--------------------------------------------------------------------===//
+
+ /// MakeIntValue - Make an APSInt of the appropriate width and
+ /// signedness for the given \arg Value and integer \arg Type.
+ llvm::APSInt MakeIntValue(uint64_t Value, QualType Type) {
+ llvm::APSInt Res(getIntWidth(Type), !Type->isSignedIntegerType());
+ Res = Value;
+ return Res;
+ }
+
+private:
+ ASTContext(const ASTContext&); // DO NOT IMPLEMENT
+ void operator=(const ASTContext&); // DO NOT IMPLEMENT
+
+ void InitBuiltinTypes();
+ void InitBuiltinType(QualType &R, BuiltinType::Kind K);
+
+ // Return the ObjC type encoding for a given type.
+ void getObjCEncodingForTypeImpl(QualType t, std::string &S,
+ bool ExpandPointedToStructures,
+ bool ExpandStructures,
+ const FieldDecl *Field,
+ bool OutermostType = false,
+ bool EncodingProperty = false);
+
+ const ASTRecordLayout &getObjCLayout(const ObjCInterfaceDecl *D,
+ const ObjCImplementationDecl *Impl);
+};
+
+} // end namespace clang
+
+// operator new and delete aren't allowed inside namespaces.
+// The throw specifications are mandated by the standard.
+/// @brief Placement new for using the ASTContext's allocator.
+///
+/// This placement form of operator new uses the ASTContext's allocator for
+/// obtaining memory. It is a non-throwing new, which means that it returns
+/// null on error. (If that is what the allocator does. The current does, so if
+/// this ever changes, this operator will have to be changed, too.)
+/// Usage looks like this (assuming there's an ASTContext 'Context' in scope):
+/// @code
+/// // Default alignment (16)
+/// IntegerLiteral *Ex = new (Context) IntegerLiteral(arguments);
+/// // Specific alignment
+/// IntegerLiteral *Ex2 = new (Context, 8) IntegerLiteral(arguments);
+/// @endcode
+/// Please note that you cannot use delete on the pointer; it must be
+/// deallocated using an explicit destructor call followed by
+/// @c Context.Deallocate(Ptr).
+///
+/// @param Bytes The number of bytes to allocate. Calculated by the compiler.
+/// @param C The ASTContext that provides the allocator.
+/// @param Alignment The alignment of the allocated memory (if the underlying
+/// allocator supports it).
+/// @return The allocated memory. Could be NULL.
+inline void *operator new(size_t Bytes, clang::ASTContext &C,
+ size_t Alignment) throw () {
+ return C.Allocate(Bytes, Alignment);
+}
+/// @brief Placement delete companion to the new above.
+///
+/// This operator is just a companion to the new above. There is no way of
+/// invoking it directly; see the new operator for more details. This operator
+/// is called implicitly by the compiler if a placement new expression using
+/// the ASTContext throws in the object constructor.
+inline void operator delete(void *Ptr, clang::ASTContext &C, size_t)
+ throw () {
+ C.Deallocate(Ptr);
+}
+
+/// This placement form of operator new[] uses the ASTContext's allocator for
+/// obtaining memory. It is a non-throwing new[], which means that it returns
+/// null on error.
+/// Usage looks like this (assuming there's an ASTContext 'Context' in scope):
+/// @code
+/// // Default alignment (16)
+/// char *data = new (Context) char[10];
+/// // Specific alignment
+/// char *data = new (Context, 8) char[10];
+/// @endcode
+/// Please note that you cannot use delete on the pointer; it must be
+/// deallocated using an explicit destructor call followed by
+/// @c Context.Deallocate(Ptr).
+///
+/// @param Bytes The number of bytes to allocate. Calculated by the compiler.
+/// @param C The ASTContext that provides the allocator.
+/// @param Alignment The alignment of the allocated memory (if the underlying
+/// allocator supports it).
+/// @return The allocated memory. Could be NULL.
+inline void *operator new[](size_t Bytes, clang::ASTContext& C,
+ size_t Alignment = 16) throw () {
+ return C.Allocate(Bytes, Alignment);
+}
+
+/// @brief Placement delete[] companion to the new[] above.
+///
+/// This operator is just a companion to the new[] above. There is no way of
+/// invoking it directly; see the new[] operator for more details. This operator
+/// is called implicitly by the compiler if a placement new[] expression using
+/// the ASTContext throws in the object constructor.
+inline void operator delete[](void *Ptr, clang::ASTContext &C) throw () {
+ C.Deallocate(Ptr);
+}
+
+#endif
diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h
new file mode 100644
index 000000000000..244ca9e10f3a
--- /dev/null
+++ b/include/clang/AST/ASTDiagnostic.h
@@ -0,0 +1,27 @@
+//===--- DiagnosticAST.h - Diagnostics for the AST library ------*- 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_DIAGNOSTICAST_H
+#define LLVM_CLANG_DIAGNOSTICAST_H
+
+#include "clang/Basic/Diagnostic.h"
+
+namespace clang {
+ namespace diag {
+ enum {
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM,
+#define ASTSTART
+#include "clang/Basic/DiagnosticASTKinds.inc"
+#undef DIAG
+ NUM_BUILTIN_AST_DIAGNOSTICS
+ };
+ } // end namespace diag
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
new file mode 100644
index 000000000000..0427f0003a3a
--- /dev/null
+++ b/include/clang/AST/Attr.h
@@ -0,0 +1,506 @@
+//===--- Attr.h - Classes for representing 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 the Attr interface and subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_ATTR_H
+#define LLVM_CLANG_AST_ATTR_H
+
+#include <cassert>
+#include <cstring>
+#include <string>
+#include <algorithm>
+
+namespace clang {
+ class ASTContext;
+}
+
+
+// Defined in ASTContext.cpp
+void *operator new(size_t Bytes, clang::ASTContext &C,
+ size_t Alignment = 16) throw ();
+
+namespace clang {
+
+/// Attr - This represents one attribute.
+class Attr {
+public:
+ enum Kind {
+ Alias,
+ Aligned,
+ AlwaysInline,
+ AnalyzerNoReturn, // Clang-specific.
+ Annotate,
+ AsmLabel, // Represent GCC asm label extension.
+ Blocks,
+ Cleanup,
+ Const,
+ Constructor,
+ DLLExport,
+ DLLImport,
+ Deprecated,
+ Destructor,
+ FastCall,
+ Format,
+ FormatArg,
+ GNUInline,
+ IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict with
+ NoReturn,
+ NoThrow,
+ Nodebug,
+ Noinline,
+ NonNull,
+ ObjCException,
+ ObjCNSObject,
+ CFReturnsRetained, // Clang/Checker-specific.
+ NSReturnsRetained, // Clang/Checker-specific.
+ Overloadable, // Clang-specific
+ Packed,
+ Pure,
+ Regparm,
+ Section,
+ Sentinel,
+ StdCall,
+ TransparentUnion,
+ Unavailable,
+ Unused,
+ Used,
+ Visibility,
+ WarnUnusedResult,
+ Weak,
+ WeakImport
+ };
+
+private:
+ Attr *Next;
+ Kind AttrKind;
+ bool Inherited : 1;
+
+protected:
+ void* operator new(size_t bytes) throw() {
+ assert(0 && "Attrs cannot be allocated with regular 'new'.");
+ return 0;
+ }
+ void operator delete(void* data) throw() {
+ assert(0 && "Attrs cannot be released with regular 'delete'.");
+ }
+
+protected:
+ Attr(Kind AK) : Next(0), AttrKind(AK), Inherited(false) {}
+ virtual ~Attr() {
+ assert(Next == 0 && "Destroy didn't work");
+ }
+public:
+
+ void Destroy(ASTContext &C);
+
+ /// \brief Whether this attribute should be merged to new
+ /// declarations.
+ virtual bool isMerged() const { return true; }
+
+ Kind getKind() const { return AttrKind; }
+
+ Attr *getNext() { return Next; }
+ const Attr *getNext() const { return Next; }
+ void setNext(Attr *next) { Next = next; }
+
+ bool isInherited() const { return Inherited; }
+ void setInherited(bool value) { Inherited = value; }
+
+ void addAttr(Attr *attr) {
+ assert((attr != 0) && "addAttr(): attr is null");
+
+ // FIXME: This doesn't preserve the order in any way.
+ attr->Next = Next;
+ Next = attr;
+ }
+
+ // Clone this attribute.
+ virtual Attr* clone(ASTContext &C) const = 0;
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *) { return true; }
+};
+
+#define DEF_SIMPLE_ATTR(ATTR) \
+class ATTR##Attr : public Attr { \
+public: \
+ ATTR##Attr() : Attr(ATTR) {} \
+ virtual Attr *clone(ASTContext &C) const { return ::new (C) ATTR##Attr; }\
+ static bool classof(const Attr *A) { return A->getKind() == ATTR; } \
+ static bool classof(const ATTR##Attr *A) { return true; } \
+}
+
+class PackedAttr : public Attr {
+ unsigned Alignment;
+
+public:
+ PackedAttr(unsigned alignment) : Attr(Packed), Alignment(alignment) {}
+
+ /// getAlignment - The specified alignment in bits.
+ unsigned getAlignment() const { return Alignment; }
+
+ virtual Attr* clone(ASTContext &C) const {
+ return ::new (C) PackedAttr(Alignment);
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) {
+ return A->getKind() == Packed;
+ }
+ static bool classof(const PackedAttr *A) { return true; }
+};
+
+class AlignedAttr : public Attr {
+ unsigned Alignment;
+public:
+ AlignedAttr(unsigned alignment) : Attr(Aligned), Alignment(alignment) {}
+
+ /// getAlignment - The specified alignment in bits.
+ unsigned getAlignment() const { return Alignment; }
+
+ virtual Attr* clone(ASTContext &C) const { return ::new (C) AlignedAttr(Alignment); }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) {
+ return A->getKind() == Aligned;
+ }
+ static bool classof(const AlignedAttr *A) { return true; }
+};
+
+class AnnotateAttr : public Attr {
+ std::string Annotation;
+public:
+ AnnotateAttr(const std::string &ann) : Attr(Annotate), Annotation(ann) {}
+
+ const std::string& getAnnotation() const { return Annotation; }
+
+ virtual Attr* clone(ASTContext &C) const { return ::new (C) AnnotateAttr(Annotation); }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) {
+ return A->getKind() == Annotate;
+ }
+ static bool classof(const AnnotateAttr *A) { return true; }
+};
+
+class AsmLabelAttr : public Attr {
+ std::string Label;
+public:
+ AsmLabelAttr(const std::string &L) : Attr(AsmLabel), Label(L) {}
+
+ const std::string& getLabel() const { return Label; }
+
+ virtual Attr* clone(ASTContext &C) const { return ::new (C) AsmLabelAttr(Label); }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) {
+ return A->getKind() == AsmLabel;
+ }
+ static bool classof(const AsmLabelAttr *A) { return true; }
+};
+
+DEF_SIMPLE_ATTR(AlwaysInline);
+
+class AliasAttr : public Attr {
+ std::string Aliasee;
+public:
+ AliasAttr(const std::string &aliasee) : Attr(Alias), Aliasee(aliasee) {}
+
+ const std::string& getAliasee() const { return Aliasee; }
+
+ virtual Attr *clone(ASTContext &C) const { return ::new (C) AliasAttr(Aliasee); }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) { return A->getKind() == Alias; }
+ static bool classof(const AliasAttr *A) { return true; }
+};
+
+class ConstructorAttr : public Attr {
+ int priority;
+public:
+ ConstructorAttr(int p) : Attr(Constructor), priority(p) {}
+
+ int getPriority() const { return priority; }
+
+ virtual Attr *clone(ASTContext &C) const { return ::new (C) ConstructorAttr(priority); }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) { return A->getKind() == Constructor; }
+ static bool classof(const ConstructorAttr *A) { return true; }
+};
+
+class DestructorAttr : public Attr {
+ int priority;
+public:
+ DestructorAttr(int p) : Attr(Destructor), priority(p) {}
+
+ int getPriority() const { return priority; }
+
+ virtual Attr *clone(ASTContext &C) const { return ::new (C) DestructorAttr(priority); }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) { return A->getKind() == Destructor; }
+ static bool classof(const DestructorAttr *A) { return true; }
+};
+
+class GNUInlineAttr : public Attr {
+public:
+ GNUInlineAttr() : Attr(GNUInline) {}
+
+ virtual Attr *clone(ASTContext &C) const { return ::new (C) GNUInlineAttr; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) {
+ return A->getKind() == GNUInline;
+ }
+ static bool classof(const GNUInlineAttr *A) { return true; }
+};
+
+class IBOutletAttr : public Attr {
+public:
+ IBOutletAttr() : Attr(IBOutletKind) {}
+
+ virtual Attr *clone(ASTContext &C) const { return ::new (C) IBOutletAttr; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) {
+ return A->getKind() == IBOutletKind;
+ }
+ static bool classof(const IBOutletAttr *A) { return true; }
+};
+
+DEF_SIMPLE_ATTR(NoReturn);
+DEF_SIMPLE_ATTR(AnalyzerNoReturn);
+DEF_SIMPLE_ATTR(Deprecated);
+
+class SectionAttr : public Attr {
+ std::string Name;
+public:
+ SectionAttr(const std::string &N) : Attr(Section), Name(N) {}
+
+ const std::string& getName() const { return Name; }
+
+ virtual Attr *clone(ASTContext &C) const { return ::new (C) SectionAttr(Name); }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) {
+ return A->getKind() == Section;
+ }
+ static bool classof(const SectionAttr *A) { return true; }
+};
+
+DEF_SIMPLE_ATTR(Unavailable);
+DEF_SIMPLE_ATTR(Unused);
+DEF_SIMPLE_ATTR(Used);
+DEF_SIMPLE_ATTR(Weak);
+DEF_SIMPLE_ATTR(WeakImport);
+DEF_SIMPLE_ATTR(NoThrow);
+DEF_SIMPLE_ATTR(Const);
+DEF_SIMPLE_ATTR(Pure);
+
+class NonNullAttr : public Attr {
+ unsigned* ArgNums;
+ unsigned Size;
+public:
+ NonNullAttr(unsigned* arg_nums = 0, unsigned size = 0) : Attr(NonNull),
+ ArgNums(0), Size(0) {
+
+ if (size == 0) return;
+ assert(arg_nums);
+ ArgNums = new unsigned[size];
+ Size = size;
+ memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size);
+ }
+
+ virtual ~NonNullAttr() {
+ delete [] ArgNums;
+ }
+
+ typedef const unsigned *iterator;
+ iterator begin() const { return ArgNums; }
+ iterator end() const { return ArgNums + Size; }
+ unsigned size() const { return Size; }
+
+ bool isNonNull(unsigned arg) const {
+ return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true;
+ }
+
+ virtual Attr *clone(ASTContext &C) const { return ::new (C) NonNullAttr(ArgNums, Size); }
+
+ static bool classof(const Attr *A) { return A->getKind() == NonNull; }
+ static bool classof(const NonNullAttr *A) { return true; }
+};
+
+class FormatAttr : public Attr {
+ std::string Type;
+ int formatIdx, firstArg;
+public:
+ FormatAttr(const std::string &type, int idx, int first) : Attr(Format),
+ Type(type), formatIdx(idx), firstArg(first) {}
+
+ const std::string& getType() const { return Type; }
+ void setType(const std::string &type) { Type = type; }
+ int getFormatIdx() const { return formatIdx; }
+ int getFirstArg() const { return firstArg; }
+
+ virtual Attr *clone(ASTContext &C) const {
+ return ::new (C) FormatAttr(Type, formatIdx, firstArg);
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) { return A->getKind() == Format; }
+ static bool classof(const FormatAttr *A) { return true; }
+};
+
+class FormatArgAttr : public Attr {
+ int formatIdx;
+public:
+ FormatArgAttr(int idx) : Attr(FormatArg), formatIdx(idx) {}
+ int getFormatIdx() const { return formatIdx; }
+
+ virtual Attr *clone(ASTContext &C) const {
+ return ::new (C) FormatArgAttr(formatIdx);
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) { return A->getKind() == FormatArg; }
+ static bool classof(const FormatArgAttr *A) { return true; }
+};
+
+class SentinelAttr : public Attr {
+ int sentinel, NullPos;
+public:
+ SentinelAttr(int sentinel_val, int nullPos) : Attr(Sentinel),
+ sentinel(sentinel_val), NullPos(nullPos) {}
+ int getSentinel() const { return sentinel; }
+ int getNullPos() const { return NullPos; }
+
+ virtual Attr *clone(ASTContext &C) const {
+ return ::new (C) SentinelAttr(sentinel, NullPos);
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) { return A->getKind() == Sentinel; }
+ static bool classof(const SentinelAttr *A) { return true; }
+};
+
+class VisibilityAttr : public Attr {
+public:
+ /// @brief An enumeration for the kinds of visibility of symbols.
+ enum VisibilityTypes {
+ DefaultVisibility = 0,
+ HiddenVisibility,
+ ProtectedVisibility
+ };
+private:
+ VisibilityTypes VisibilityType;
+public:
+ VisibilityAttr(VisibilityTypes v) : Attr(Visibility),
+ VisibilityType(v) {}
+
+ VisibilityTypes getVisibility() const { return VisibilityType; }
+
+ virtual Attr *clone(ASTContext &C) const { return ::new (C) VisibilityAttr(VisibilityType); }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) { return A->getKind() == Visibility; }
+ static bool classof(const VisibilityAttr *A) { return true; }
+};
+
+DEF_SIMPLE_ATTR(DLLImport);
+DEF_SIMPLE_ATTR(DLLExport);
+DEF_SIMPLE_ATTR(FastCall);
+DEF_SIMPLE_ATTR(StdCall);
+DEF_SIMPLE_ATTR(TransparentUnion);
+DEF_SIMPLE_ATTR(ObjCNSObject);
+DEF_SIMPLE_ATTR(ObjCException);
+
+class OverloadableAttr : public Attr {
+public:
+ OverloadableAttr() : Attr(Overloadable) { }
+
+ virtual bool isMerged() const { return false; }
+
+ virtual Attr *clone(ASTContext &C) const {
+ return ::new (C) OverloadableAttr;
+ }
+
+ static bool classof(const Attr *A) { return A->getKind() == Overloadable; }
+ static bool classof(const OverloadableAttr *) { return true; }
+};
+
+class BlocksAttr : public Attr {
+public:
+ enum BlocksAttrTypes {
+ ByRef = 0
+ };
+private:
+ BlocksAttrTypes BlocksAttrType;
+public:
+ BlocksAttr(BlocksAttrTypes t) : Attr(Blocks), BlocksAttrType(t) {}
+
+ BlocksAttrTypes getType() const { return BlocksAttrType; }
+
+ virtual Attr *clone(ASTContext &C) const { return ::new (C) BlocksAttr(BlocksAttrType); }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) { return A->getKind() == Blocks; }
+ static bool classof(const BlocksAttr *A) { return true; }
+};
+
+class FunctionDecl;
+
+class CleanupAttr : public Attr {
+ FunctionDecl *FD;
+
+public:
+ CleanupAttr(FunctionDecl *fd) : Attr(Cleanup), FD(fd) {}
+
+ const FunctionDecl *getFunctionDecl() const { return FD; }
+
+ virtual Attr *clone(ASTContext &C) const { return ::new (C) CleanupAttr(FD); }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) { return A->getKind() == Cleanup; }
+ static bool classof(const CleanupAttr *A) { return true; }
+};
+
+DEF_SIMPLE_ATTR(Nodebug);
+DEF_SIMPLE_ATTR(WarnUnusedResult);
+DEF_SIMPLE_ATTR(Noinline);
+
+class RegparmAttr : public Attr {
+ unsigned NumParams;
+
+public:
+ RegparmAttr(unsigned np) : Attr(Regparm), NumParams(np) {}
+
+ unsigned getNumParams() const { return NumParams; }
+
+ virtual Attr *clone(ASTContext &C) const {
+ return ::new (C) RegparmAttr(NumParams);
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) { return A->getKind() == Regparm; }
+ static bool classof(const RegparmAttr *A) { return true; }
+};
+
+// Checker-specific attributes.
+DEF_SIMPLE_ATTR(CFReturnsRetained);
+DEF_SIMPLE_ATTR(NSReturnsRetained);
+
+#undef DEF_SIMPLE_ATTR
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/Builtins.def b/include/clang/AST/Builtins.def
new file mode 100644
index 000000000000..671c4bd6cd4a
--- /dev/null
+++ b/include/clang/AST/Builtins.def
@@ -0,0 +1,389 @@
+//===--- Builtins.def - Builtin function info 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 standard builtin function database. Users of this file
+// must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+// FIXME: this needs to be the full list supported by GCC. Right now, I'm just
+// adding stuff on demand.
+//
+// FIXME: This should really be a .td file, but that requires modifying tblgen.
+// Perhaps tblgen should have plugins.
+
+// The first value provided to the macro specifies the function name of the
+// builtin, and results in a clang::builtin::BIXX enum value for XX.
+
+// The second value provided to the macro specifies the type of the function
+// (result value, then each argument) as follows:
+// v -> void
+// b -> boolean
+// c -> char
+// s -> short
+// i -> int
+// f -> float
+// d -> double
+// z -> size_t
+// F -> constant CFString
+// a -> __builtin_va_list
+// A -> "reference" to __builtin_va_list
+// V -> Vector, following num elements and a base type.
+// P -> FILE
+// . -> "...". This may only occur at the end of the function list.
+//
+// Types maybe prefixed with the following modifiers:
+// L -> long (e.g. Li for 'long int')
+// LL -> long long
+// LLL -> __int128_t (e.g. LLLi)
+// S -> signed
+// U -> unsigned
+//
+// Types may be postfixed with the following modifiers:
+// * -> pointer
+// & -> reference
+// C -> const
+
+// The third value provided to the macro specifies information about attributes
+// of the function. These must be kept in sync with the predicates in the
+// Builtin::Context class. Currently we have:
+// n -> nothrow
+// c -> const
+// F -> this is a libc/libm function with a '__builtin_' prefix added.
+// f -> this is a libc/libm function without the '__builtin_' prefix. It can
+// be followed by ':headername:' to state which header this function
+// comes from.
+// p:N: -> this is a printf-like function whose Nth argument is the format
+// string.
+// P:N: -> similar to the p:N: attribute, but the function is like vprintf
+// in that it accepts its arguments as a va_list rather than
+// through an ellipsis
+// e -> const, but only when -fmath-errno=0
+// FIXME: gcc has nonnull
+
+#if defined(BUILTIN) && !defined(LIBBUILTIN)
+# define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) BUILTIN(ID, TYPE, ATTRS)
+#endif
+
+// Standard libc/libm functions:
+BUILTIN(__builtin_huge_val, "d", "nc")
+BUILTIN(__builtin_huge_valf, "f", "nc")
+BUILTIN(__builtin_huge_vall, "Ld", "nc")
+BUILTIN(__builtin_inf , "d" , "nc")
+BUILTIN(__builtin_inff , "f" , "nc")
+BUILTIN(__builtin_infl , "Ld" , "nc")
+BUILTIN(__builtin_nan, "dcC*" , "ncF")
+BUILTIN(__builtin_nanf, "fcC*" , "ncF")
+BUILTIN(__builtin_nanl, "LdcC*", "ncF")
+BUILTIN(__builtin_nans, "dcC*" , "ncF")
+BUILTIN(__builtin_nansf, "fcC*" , "ncF")
+BUILTIN(__builtin_nansl, "LdcC*", "ncF")
+BUILTIN(__builtin_abs , "ii" , "ncF")
+BUILTIN(__builtin_fabs , "dd" , "ncF")
+BUILTIN(__builtin_fabsf, "ff" , "ncF")
+BUILTIN(__builtin_fabsl, "LdLd", "ncF")
+BUILTIN(__builtin_copysign, "ddd", "ncF")
+BUILTIN(__builtin_copysignf, "fff", "ncF")
+BUILTIN(__builtin_copysignl, "LdLdLd", "ncF")
+BUILTIN(__builtin_powi , "ddi" , "nc")
+BUILTIN(__builtin_powif, "ffi" , "nc")
+BUILTIN(__builtin_powil, "LdLdi", "nc")
+
+// FP Comparisons.
+BUILTIN(__builtin_isgreater , "i.", "nc")
+BUILTIN(__builtin_isgreaterequal, "i.", "nc")
+BUILTIN(__builtin_isless , "i.", "nc")
+BUILTIN(__builtin_islessequal , "i.", "nc")
+BUILTIN(__builtin_islessgreater , "i.", "nc")
+BUILTIN(__builtin_isunordered , "i.", "nc")
+
+// Builtins for arithmetic.
+BUILTIN(__builtin_clz , "iUi" , "nc")
+BUILTIN(__builtin_clzl , "iULi" , "nc")
+BUILTIN(__builtin_clzll, "iULLi", "nc")
+// TODO: int clzimax(uintmax_t)
+BUILTIN(__builtin_ctz , "iUi" , "nc")
+BUILTIN(__builtin_ctzl , "iULi" , "nc")
+BUILTIN(__builtin_ctzll, "iULLi", "nc")
+// TODO: int ctzimax(uintmax_t)
+BUILTIN(__builtin_ffs , "iUi" , "nc")
+BUILTIN(__builtin_ffsl , "iULi" , "nc")
+BUILTIN(__builtin_ffsll, "iULLi", "nc")
+BUILTIN(__builtin_parity , "iUi" , "nc")
+BUILTIN(__builtin_parityl , "iULi" , "nc")
+BUILTIN(__builtin_parityll, "iULLi", "nc")
+BUILTIN(__builtin_popcount , "iUi" , "nc")
+BUILTIN(__builtin_popcountl , "iULi" , "nc")
+BUILTIN(__builtin_popcountll, "iULLi", "nc")
+
+// FIXME: These type signatures are not correct for targets with int != 32-bits
+// or with ULL != 64-bits.
+BUILTIN(__builtin_bswap32, "UiUi", "nc")
+BUILTIN(__builtin_bswap64, "ULLiULLi", "nc")
+
+// Random GCC builtins
+BUILTIN(__builtin_constant_p, "Us.", "nc")
+BUILTIN(__builtin_classify_type, "i.", "nc")
+BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc")
+BUILTIN(__builtin_va_start, "vA.", "n")
+BUILTIN(__builtin_va_end, "vA", "n")
+BUILTIN(__builtin_va_copy, "vAA", "n")
+BUILTIN(__builtin_stdarg_start, "vA.", "n")
+BUILTIN(__builtin_bcmp, "iv*v*z", "n")
+BUILTIN(__builtin_bcopy, "vv*v*z", "n")
+BUILTIN(__builtin_bzero, "vv*z", "n")
+BUILTIN(__builtin_memcmp, "ivC*vC*z", "nF")
+BUILTIN(__builtin_memcpy, "v*v*vC*z", "nF")
+BUILTIN(__builtin_memmove, "v*v*vC*z", "nF")
+BUILTIN(__builtin_mempcpy, "v*v*vC*z", "nF")
+BUILTIN(__builtin_memset, "v*v*iz", "nF")
+BUILTIN(__builtin_stpcpy, "c*c*cC*", "nF")
+BUILTIN(__builtin_stpncpy, "c*c*cC*z", "nF")
+BUILTIN(__builtin_strcasecmp, "icC*cC*", "nF")
+BUILTIN(__builtin_strcat, "c*c*cC*", "nF")
+BUILTIN(__builtin_strchr, "c*cC*i", "nF")
+BUILTIN(__builtin_strcmp, "icC*cC*", "nF")
+BUILTIN(__builtin_strcpy, "c*c*cC*", "nF")
+BUILTIN(__builtin_strcspn, "zcC*cC*", "nF")
+BUILTIN(__builtin_strdup, "c*cC*", "nF")
+BUILTIN(__builtin_strlen, "zcC*", "nF")
+BUILTIN(__builtin_strncasecmp, "icC*cC*z", "nF")
+BUILTIN(__builtin_strncat, "c*c*cC*z", "nF")
+BUILTIN(__builtin_strncmp, "icC*cC*z", "nF")
+BUILTIN(__builtin_strncpy, "c*c*cC*z", "nF")
+BUILTIN(__builtin_strndup, "c*cC*z", "nF")
+BUILTIN(__builtin_strpbrk, "c*cC*cC*", "nF")
+BUILTIN(__builtin_strrchr, "c*cC*i", "nF")
+BUILTIN(__builtin_strspn, "zcC*cC*", "nF")
+BUILTIN(__builtin_strstr, "c*cC*cC*", "nF")
+BUILTIN(__builtin_return_address, "v*Ui", "n")
+BUILTIN(__builtin_extract_return_addr, "v*v*", "n")
+BUILTIN(__builtin_frame_address, "v*Ui", "n")
+BUILTIN(__builtin_flt_rounds, "i", "nc")
+BUILTIN(__builtin_setjmp, "iv**", "")
+BUILTIN(__builtin_longjmp, "vv**i", "")
+BUILTIN(__builtin_unwind_init, "v", "")
+
+// GCC Object size checking builtins
+BUILTIN(__builtin_object_size, "zv*i", "n")
+BUILTIN(__builtin___memcpy_chk, "v*v*vC*zz", "nF")
+BUILTIN(__builtin___memmove_chk, "v*v*vC*zz", "nF")
+BUILTIN(__builtin___mempcpy_chk, "v*v*vC*zz", "nF")
+BUILTIN(__builtin___memset_chk, "v*v*izz", "nF")
+BUILTIN(__builtin___stpcpy_chk, "c*c*cC*z", "nF")
+BUILTIN(__builtin___strcat_chk, "c*c*cC*z", "nF")
+BUILTIN(__builtin___strcpy_chk, "c*c*cC*z", "nF")
+BUILTIN(__builtin___strncat_chk, "c*c*cC*zz", "nF")
+BUILTIN(__builtin___strncpy_chk, "c*c*cC*zz", "nF")
+BUILTIN(__builtin___snprintf_chk, "ic*zizcC*.", "Fp:4:")
+BUILTIN(__builtin___sprintf_chk, "ic*izcC*.", "Fp:3:")
+BUILTIN(__builtin___vsnprintf_chk, "ic*zizcC*a", "FP:4:")
+BUILTIN(__builtin___vsprintf_chk, "ic*izcC*a", "FP:3:")
+BUILTIN(__builtin___fprintf_chk, "iP*icC*.", "Fp:2:")
+BUILTIN(__builtin___printf_chk, "iicC*.", "Fp:1:")
+BUILTIN(__builtin___vfprintf_chk, "iP*icC*a", "FP:2:")
+BUILTIN(__builtin___vprintf_chk, "iicC*a", "FP:1:")
+
+BUILTIN(__builtin_expect, "iii" , "nc")
+BUILTIN(__builtin_prefetch, "vvC*.", "nc")
+BUILTIN(__builtin_trap, "v", "n")
+
+BUILTIN(__builtin_shufflevector, "v." , "nc")
+
+BUILTIN(__builtin_alloca, "v*z" , "n")
+
+// "Overloaded" Atomic operator builtins. These are overloaded to support data
+// types of i8, i16, i32, i64, and i128. The front-end sees calls to the
+// non-suffixed version of these (which has a bogus type) and transforms them to
+// the right overloaded version in Sema (plus casts).
+
+// FIXME: These assume that char -> i8, short -> i16, int -> i32,
+// long long -> i64.
+
+BUILTIN(__sync_fetch_and_add, "v.", "")
+BUILTIN(__sync_fetch_and_add_1, "cc*c.", "n")
+BUILTIN(__sync_fetch_and_add_2, "ss*s.", "n")
+BUILTIN(__sync_fetch_and_add_4, "ii*i.", "n")
+BUILTIN(__sync_fetch_and_add_8, "LLiLLi*LLi.", "n")
+BUILTIN(__sync_fetch_and_add_16, "LLLiLLLi*LLLi.", "n")
+
+BUILTIN(__sync_fetch_and_sub, "v.", "")
+BUILTIN(__sync_fetch_and_sub_1, "cc*c.", "n")
+BUILTIN(__sync_fetch_and_sub_2, "ss*s.", "n")
+BUILTIN(__sync_fetch_and_sub_4, "ii*i.", "n")
+BUILTIN(__sync_fetch_and_sub_8, "LLiLLi*LLi.", "n")
+BUILTIN(__sync_fetch_and_sub_16, "LLLiLLLi*LLLi.", "n")
+
+BUILTIN(__sync_fetch_and_or, "v.", "")
+BUILTIN(__sync_fetch_and_or_1, "cc*c.", "n")
+BUILTIN(__sync_fetch_and_or_2, "ss*s.", "n")
+BUILTIN(__sync_fetch_and_or_4, "ii*i.", "n")
+BUILTIN(__sync_fetch_and_or_8, "LLiLLi*LLi.", "n")
+BUILTIN(__sync_fetch_and_or_16, "LLLiLLLi*LLLi.", "n")
+
+BUILTIN(__sync_fetch_and_and, "v.", "")
+BUILTIN(__sync_fetch_and_and_1, "cc*c.", "n")
+BUILTIN(__sync_fetch_and_and_2, "ss*s.", "n")
+BUILTIN(__sync_fetch_and_and_4, "ii*i.", "n")
+BUILTIN(__sync_fetch_and_and_8, "LLiLLi*LLi.", "n")
+BUILTIN(__sync_fetch_and_and_16, "LLLiLLLi*LLLi.", "n")
+
+BUILTIN(__sync_fetch_and_xor, "v.", "")
+BUILTIN(__sync_fetch_and_xor_1, "cc*c.", "n")
+BUILTIN(__sync_fetch_and_xor_2, "ss*s.", "n")
+BUILTIN(__sync_fetch_and_xor_4, "ii*i.", "n")
+BUILTIN(__sync_fetch_and_xor_8, "LLiLLi*LLi.", "n")
+BUILTIN(__sync_fetch_and_xor_16, "LLLiLLLi*LLLi.", "n")
+
+BUILTIN(__sync_fetch_and_nand, "v.", "")
+BUILTIN(__sync_fetch_and_nand_1, "cc*c.", "n")
+BUILTIN(__sync_fetch_and_nand_2, "ss*s.", "n")
+BUILTIN(__sync_fetch_and_nand_4, "ii*i.", "n")
+BUILTIN(__sync_fetch_and_nand_8, "LLiLLi*LLi.", "n")
+BUILTIN(__sync_fetch_and_nand_16, "LLLiLLLi*LLLi.", "n")
+
+
+BUILTIN(__sync_add_and_fetch, "v.", "")
+BUILTIN(__sync_add_and_fetch_1, "cc*c.", "n")
+BUILTIN(__sync_add_and_fetch_2, "ss*s.", "n")
+BUILTIN(__sync_add_and_fetch_4, "ii*i.", "n")
+BUILTIN(__sync_add_and_fetch_8, "LLiLLi*LLi.", "n")
+BUILTIN(__sync_add_and_fetch_16, "LLLiLLLi*LLLi.", "n")
+
+BUILTIN(__sync_sub_and_fetch, "v.", "")
+BUILTIN(__sync_sub_and_fetch_1, "cc*c.", "n")
+BUILTIN(__sync_sub_and_fetch_2, "ss*s.", "n")
+BUILTIN(__sync_sub_and_fetch_4, "ii*i.", "n")
+BUILTIN(__sync_sub_and_fetch_8, "LLiLLi*LLi.", "n")
+BUILTIN(__sync_sub_and_fetch_16, "LLLiLLLi*LLLi.", "n")
+
+BUILTIN(__sync_or_and_fetch, "v.", "")
+BUILTIN(__sync_or_and_fetch_1, "cc*c.", "n")
+BUILTIN(__sync_or_and_fetch_2, "ss*s.", "n")
+BUILTIN(__sync_or_and_fetch_4, "ii*i.", "n")
+BUILTIN(__sync_or_and_fetch_8, "LLiLLi*LLi.", "n")
+BUILTIN(__sync_or_and_fetch_16, "LLLiLLLi*LLLi.", "n")
+
+BUILTIN(__sync_and_and_fetch, "v.", "")
+BUILTIN(__sync_and_and_fetch_1, "cc*c.", "n")
+BUILTIN(__sync_and_and_fetch_2, "ss*s.", "n")
+BUILTIN(__sync_and_and_fetch_4, "ii*i.", "n")
+BUILTIN(__sync_and_and_fetch_8, "LLiLLi*LLi.", "n")
+BUILTIN(__sync_and_and_fetch_16, "LLLiLLLi*LLLi.", "n")
+
+BUILTIN(__sync_xor_and_fetch, "v.", "")
+BUILTIN(__sync_xor_and_fetch_1, "cc*c.", "n")
+BUILTIN(__sync_xor_and_fetch_2, "ss*s.", "n")
+BUILTIN(__sync_xor_and_fetch_4, "ii*i.", "n")
+BUILTIN(__sync_xor_and_fetch_8, "LLiLLi*LLi.", "n")
+BUILTIN(__sync_xor_and_fetch_16, "LLLiLLLi*LLLi.", "n")
+
+BUILTIN(__sync_nand_and_fetch, "v.", "")
+BUILTIN(__sync_nand_and_fetch_1, "cc*c.", "n")
+BUILTIN(__sync_nand_and_fetch_2, "ss*s.", "n")
+BUILTIN(__sync_nand_and_fetch_4, "ii*i.", "n")
+BUILTIN(__sync_nand_and_fetch_8, "LLiLLi*LLi.", "n")
+BUILTIN(__sync_nand_and_fetch_16, "LLLiLLLi*LLLi.", "n")
+
+
+BUILTIN(__sync_bool_compare_and_swap, "v.", "")
+BUILTIN(__sync_bool_compare_and_swap_1, "bc*cc.", "n")
+BUILTIN(__sync_bool_compare_and_swap_2, "bs*ss.", "n")
+BUILTIN(__sync_bool_compare_and_swap_4, "bi*ii.", "n")
+BUILTIN(__sync_bool_compare_and_swap_8, "bLLi*LLi.", "n")
+BUILTIN(__sync_bool_compare_and_swap_16, "bLLLi*LLLiLLLi.", "n")
+
+BUILTIN(__sync_val_compare_and_swap, "v.", "")
+BUILTIN(__sync_val_compare_and_swap_1, "cc*cc.", "n")
+BUILTIN(__sync_val_compare_and_swap_2, "ss*ss.", "n")
+BUILTIN(__sync_val_compare_and_swap_4, "ii*ii.", "n")
+BUILTIN(__sync_val_compare_and_swap_8, "LLiLLi*LLi.", "n")
+BUILTIN(__sync_val_compare_and_swap_16, "LLLiLLLi*LLLiLLLi.", "n")
+
+BUILTIN(__sync_lock_test_and_set, "v.", "")
+BUILTIN(__sync_lock_test_and_set_1, "cc*c.", "n")
+BUILTIN(__sync_lock_test_and_set_2, "ss*s.", "n")
+BUILTIN(__sync_lock_test_and_set_4, "ii*i.", "n")
+BUILTIN(__sync_lock_test_and_set_8, "LLiLLi*LLi.", "n")
+BUILTIN(__sync_lock_test_and_set_16, "LLLiLLLi*LLLi.", "n")
+
+BUILTIN(__sync_lock_release, "v.", "")
+BUILTIN(__sync_lock_release_1, "vc*.", "n")
+BUILTIN(__sync_lock_release_2, "vs*.", "n")
+BUILTIN(__sync_lock_release_4, "vi*.", "n")
+BUILTIN(__sync_lock_release_8, "vLLi*.", "n")
+BUILTIN(__sync_lock_release_16, "vLLLi*.", "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, "ii*i", "n")
+BUILTIN(__sync_fetch_and_max, "ii*i", "n")
+BUILTIN(__sync_fetch_and_umin, "UiUi*Ui", "n")
+BUILTIN(__sync_fetch_and_umax, "UiUi*Ui", "n")
+
+// Builtin library functions
+LIBBUILTIN(alloca, "v*z", "f", "stdlib.h")
+LIBBUILTIN(calloc, "v*zz", "f", "stdlib.h")
+LIBBUILTIN(malloc, "v*z", "f", "stdlib.h")
+LIBBUILTIN(realloc, "v*v*z", "f", "stdlib.h")
+LIBBUILTIN(memcpy, "v*v*vC*z", "f", "string.h")
+LIBBUILTIN(memmove, "v*v*vC*z", "f", "string.h")
+LIBBUILTIN(memset, "v*v*iz", "f", "string.h")
+LIBBUILTIN(strcat, "c*c*cC*", "f", "string.h")
+LIBBUILTIN(strchr, "c*cC*i", "f", "string.h")
+LIBBUILTIN(strcpy, "c*c*cC*", "f", "string.h")
+LIBBUILTIN(strcspn, "zcC*cC*", "f", "string.h")
+LIBBUILTIN(strlen, "zcC*", "f", "string.h")
+LIBBUILTIN(strncat, "c*c*cC*z", "f", "string.h")
+LIBBUILTIN(strncpy, "c*c*cC*z", "f", "string.h")
+LIBBUILTIN(strpbrk, "c*cC*cC*", "f", "string.h")
+LIBBUILTIN(strrchr, "c*cC*i", "f", "string.h")
+LIBBUILTIN(strspn, "zcC*cC*", "f", "string.h")
+LIBBUILTIN(strstr, "c*cC*cC*", "f", "string.h")
+LIBBUILTIN(printf, "icC*.", "fp:0:", "stdio.h")
+LIBBUILTIN(fprintf, "iP*cC*.", "fp:1:", "stdio.h")
+LIBBUILTIN(snprintf, "ic*zcC*.", "fp:2:", "stdio.h")
+LIBBUILTIN(sprintf, "ic*cC*.", "fp:1:", "stdio.h")
+LIBBUILTIN(vprintf, "icC*a", "fP:0:", "stdio.h")
+LIBBUILTIN(vfprintf, "iP*cC*a", "fP:1:", "stdio.h")
+LIBBUILTIN(vsnprintf, "ic*zcC*a", "fP:2:", "stdio.h")
+LIBBUILTIN(vsprintf, "ic*cC*a", "fP:1:", "stdio.h")
+
+// FIXME: This type isn't very correct, it should be
+// id objc_msgSend(id, SEL)
+// but we need new type letters for that.
+LIBBUILTIN(objc_msgSend, "v*.", "f", "objc/message.h")
+
+// FIXME: asprintf and vasprintf aren't C99 functions. Should they be
+// target-specific builtins, perhaps?
+
+// Builtin math library functions
+LIBBUILTIN(pow, "ddd", "fe", "math.h")
+LIBBUILTIN(powl, "LdLdLd", "fe", "math.h")
+LIBBUILTIN(powf, "fff", "fe", "math.h")
+
+LIBBUILTIN(sqrt, "dd", "fe", "math.h")
+LIBBUILTIN(sqrtl, "LdLd", "fe", "math.h")
+LIBBUILTIN(sqrtf, "ff", "fe", "math.h")
+
+LIBBUILTIN(sin, "dd", "fe", "math.h")
+LIBBUILTIN(sinl, "LdLd", "fe", "math.h")
+LIBBUILTIN(sinf, "ff", "fe", "math.h")
+
+LIBBUILTIN(cos, "dd", "fe", "math.h")
+LIBBUILTIN(cosl, "LdLd", "fe", "math.h")
+LIBBUILTIN(cosf, "ff", "fe", "math.h")
+
+#undef BUILTIN
+#undef LIBBUILTIN
diff --git a/include/clang/AST/Builtins.h b/include/clang/AST/Builtins.h
new file mode 100644
index 000000000000..b16d3bf34139
--- /dev/null
+++ b/include/clang/AST/Builtins.h
@@ -0,0 +1,137 @@
+//===--- Builtins.h - Builtin function header -------------------*- 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 enum values for all the target-independent builtin
+// functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_BUILTINS_H
+#define LLVM_CLANG_AST_BUILTINS_H
+
+#include <cstring>
+#include <string>
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+ class TargetInfo;
+ class IdentifierTable;
+ class ASTContext;
+ class QualType;
+
+namespace Builtin {
+enum ID {
+ NotBuiltin = 0, // This is not a builtin function.
+#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
+#include "clang/AST/Builtins.def"
+ FirstTSBuiltin
+};
+
+struct Info {
+ const char *Name, *Type, *Attributes, *HeaderName;
+ bool Suppressed;
+
+ bool operator==(const Info &RHS) const {
+ return !strcmp(Name, RHS.Name) &&
+ !strcmp(Type, RHS.Type) &&
+ !strcmp(Attributes, RHS.Attributes);
+ }
+ bool operator!=(const Info &RHS) const { return !(*this == RHS); }
+};
+
+/// Builtin::Context - This holds information about target-independent and
+/// target-specific builtins, allowing easy queries by clients.
+class Context {
+ const Info *TSRecords;
+ unsigned NumTSRecords;
+public:
+ Context() : TSRecords(0), NumTSRecords(0) {}
+
+ /// \brief Load all of the target builtins. This should be called
+ /// prior to initializing the builtin identifiers.
+ void InitializeTargetBuiltins(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, bool NoBuiltins = false);
+
+ /// \brief Popular the vector with the names of all of the builtins.
+ void GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names,
+ bool NoBuiltins);
+
+ /// Builtin::GetName - Return the identifier name for the specified builtin,
+ /// e.g. "__builtin_abs".
+ const char *GetName(unsigned ID) const {
+ return GetRecord(ID).Name;
+ }
+
+ /// isConst - Return true if this function has no side effects and doesn't
+ /// read memory.
+ bool isConst(unsigned ID) const {
+ return strchr(GetRecord(ID).Attributes, 'c') != 0;
+ }
+
+ /// isNoThrow - Return true if we know this builtin never throws an exception.
+ bool isNoThrow(unsigned ID) const {
+ return strchr(GetRecord(ID).Attributes, 'n') != 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 {
+ return strchr(GetRecord(ID).Attributes, 'F') != 0;
+ }
+
+ /// \brief Determines whether this builtin is a predefined libc/libm
+ /// function, such as "malloc", where we know the signature a
+ /// priori.
+ bool isPredefinedLibFunction(unsigned ID) const {
+ return strchr(GetRecord(ID).Attributes, 'f') != 0;
+ }
+
+ /// \brief If this is a library function that comes from a specific
+ /// header, retrieve that header name.
+ const char *getHeaderName(unsigned ID) const {
+ return GetRecord(ID).HeaderName;
+ }
+
+ /// \brief Determine whether this builtin is like printf in its
+ /// formatting rules and, if so, set the index to the format string
+ /// argument and whether this function as a va_list argument.
+ bool isPrintfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg);
+
+ /// hasVAListUse - Return true of the specified builtin uses __builtin_va_list
+ /// as an operand or return type.
+ bool hasVAListUse(unsigned ID) const {
+ return strpbrk(GetRecord(ID).Type, "Aa") != 0;
+ }
+
+ /// isConstWithoutErrno - Return true if this function has no side
+ /// effects and doesn't read memory, except for possibly errno. Such
+ /// functions can be const when the MathErrno lang option is
+ /// disabled.
+ bool isConstWithoutErrno(unsigned ID) const {
+ return strchr(GetRecord(ID).Attributes, 'e') != 0;
+ }
+
+ /// GetBuiltinType - Return the type for the specified builtin.
+ enum GetBuiltinTypeError {
+ GE_None, //< No error
+ GE_Missing_FILE //< Missing the FILE type from <stdio.h>
+ };
+ QualType GetBuiltinType(unsigned ID, ASTContext &Context,
+ GetBuiltinTypeError &Error) const;
+private:
+ const Info &GetRecord(unsigned ID) const;
+};
+
+}
+} // end namespace clang
+#endif
diff --git a/include/clang/AST/CFG.h b/include/clang/AST/CFG.h
new file mode 100644
index 000000000000..7a9ee01d4f62
--- /dev/null
+++ b/include/clang/AST/CFG.h
@@ -0,0 +1,405 @@
+//===--- CFG.h - Classes for representing and building 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 defines the CFG and CFGBuilder classes for representing and
+// building Control-Flow Graphs (CFGs) from ASTs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CFG_H
+#define LLVM_CLANG_CFG_H
+
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/raw_ostream.h"
+#include <list>
+#include <vector>
+#include <cassert>
+
+namespace clang {
+ class Stmt;
+ class Expr;
+ class CFG;
+ class PrinterHelper;
+ class BlockEdge;
+
+/// CFGBlock - Represents a single basic block in a source-level CFG.
+/// It consists of:
+///
+/// (1) A set of statements/expressions (which may contain subexpressions).
+/// (2) A "terminator" statement (not in the set of statements).
+/// (3) A list of successors and predecessors.
+///
+/// Terminator: The terminator represents the type of control-flow that occurs
+/// at the end of the basic block. The terminator is a Stmt* referring to an
+/// AST node that has control-flow: if-statements, breaks, loops, etc.
+/// If the control-flow is conditional, the condition expression will appear
+/// within the set of statements in the block (usually the last statement).
+///
+/// Predecessors: the order in the set of predecessors is arbitrary.
+///
+/// Successors: the order in the set of successors is NOT arbitrary. We
+/// currently have the following orderings based on the terminator:
+///
+/// Terminator Successor Ordering
+/// -----------------------------------------------------
+/// if Then Block; Else Block
+/// ? operator LHS expression; RHS expression
+/// &&, || expression that uses result of && or ||, RHS
+///
+class CFGBlock {
+ typedef std::vector<Stmt*> StatementListTy;
+ /// Stmts - The set of statements in the basic block.
+ StatementListTy Stmts;
+
+ /// Label - An (optional) label that prefixes the executable
+ /// statements in the block. When this variable is non-NULL, it is
+ /// either an instance of LabelStmt or SwitchCase.
+ Stmt *Label;
+
+ /// Terminator - The terminator for a basic block that
+ /// indicates the type of control-flow that occurs between a block
+ /// and its successors.
+ Stmt *Terminator;
+
+ /// LoopTarget - Some blocks are used to represent the "loop edge" to
+ /// the start of a loop from within the loop body. This Stmt* will be
+ /// refer to the loop statement for such blocks (and be null otherwise).
+ const Stmt *LoopTarget;
+
+ /// BlockID - A numerical ID assigned to a CFGBlock during construction
+ /// of the CFG.
+ unsigned BlockID;
+
+ /// Predecessors/Successors - Keep track of the predecessor / successor
+ /// CFG blocks.
+ typedef std::vector<CFGBlock*> AdjacentBlocks;
+ AdjacentBlocks Preds;
+ AdjacentBlocks Succs;
+
+public:
+ explicit CFGBlock(unsigned blockid) : Label(NULL), Terminator(NULL),
+ LoopTarget(NULL), BlockID(blockid) {}
+ ~CFGBlock() {};
+
+ // Statement iterators
+ typedef StatementListTy::iterator iterator;
+ typedef StatementListTy::const_iterator const_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+
+ Stmt* front() const { return Stmts.front(); }
+ Stmt* back() const { return Stmts.back(); }
+
+ iterator begin() { return Stmts.begin(); }
+ iterator end() { return Stmts.end(); }
+ const_iterator begin() const { return Stmts.begin(); }
+ const_iterator end() const { return Stmts.end(); }
+
+ reverse_iterator rbegin() { return Stmts.rbegin(); }
+ reverse_iterator rend() { return Stmts.rend(); }
+ const_reverse_iterator rbegin() const { return Stmts.rbegin(); }
+ const_reverse_iterator rend() const { return Stmts.rend(); }
+
+ unsigned size() const { return Stmts.size(); }
+ bool empty() const { return Stmts.empty(); }
+
+ Stmt* operator[](size_t i) const { assert (i < size()); return Stmts[i]; }
+
+ // CFG iterators
+ typedef AdjacentBlocks::iterator pred_iterator;
+ typedef AdjacentBlocks::const_iterator const_pred_iterator;
+ typedef AdjacentBlocks::reverse_iterator pred_reverse_iterator;
+ typedef AdjacentBlocks::const_reverse_iterator const_pred_reverse_iterator;
+
+ typedef AdjacentBlocks::iterator succ_iterator;
+ typedef AdjacentBlocks::const_iterator const_succ_iterator;
+ typedef AdjacentBlocks::reverse_iterator succ_reverse_iterator;
+ typedef AdjacentBlocks::const_reverse_iterator const_succ_reverse_iterator;
+
+ pred_iterator pred_begin() { return Preds.begin(); }
+ pred_iterator pred_end() { return Preds.end(); }
+ const_pred_iterator pred_begin() const { return Preds.begin(); }
+ const_pred_iterator pred_end() const { return Preds.end(); }
+
+ pred_reverse_iterator pred_rbegin() { return Preds.rbegin(); }
+ pred_reverse_iterator pred_rend() { return Preds.rend(); }
+ const_pred_reverse_iterator pred_rbegin() const { return Preds.rbegin(); }
+ const_pred_reverse_iterator pred_rend() const { return Preds.rend(); }
+
+ succ_iterator succ_begin() { return Succs.begin(); }
+ succ_iterator succ_end() { return Succs.end(); }
+ const_succ_iterator succ_begin() const { return Succs.begin(); }
+ const_succ_iterator succ_end() const { return Succs.end(); }
+
+ succ_reverse_iterator succ_rbegin() { return Succs.rbegin(); }
+ succ_reverse_iterator succ_rend() { return Succs.rend(); }
+ const_succ_reverse_iterator succ_rbegin() const { return Succs.rbegin(); }
+ const_succ_reverse_iterator succ_rend() const { return Succs.rend(); }
+
+ unsigned succ_size() const { return Succs.size(); }
+ bool succ_empty() const { return Succs.empty(); }
+
+ unsigned pred_size() const { return Preds.size(); }
+ bool pred_empty() const { return Preds.empty(); }
+
+ // Manipulation of block contents
+
+ void appendStmt(Stmt* Statement) { Stmts.push_back(Statement); }
+ void setTerminator(Stmt* Statement) { Terminator = Statement; }
+ void setLabel(Stmt* Statement) { Label = Statement; }
+ void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; }
+
+ Stmt* getTerminator() { return Terminator; }
+ const Stmt* getTerminator() const { return Terminator; }
+
+ Stmt* getTerminatorCondition();
+
+ const Stmt* getTerminatorCondition() const {
+ return const_cast<CFGBlock*>(this)->getTerminatorCondition();
+ }
+
+ const Stmt *getLoopTarget() const { return LoopTarget; }
+
+ bool hasBinaryBranchTerminator() const;
+
+ Stmt* getLabel() { return Label; }
+ const Stmt* getLabel() const { return Label; }
+
+ void reverseStmts();
+
+ void addSuccessor(CFGBlock* Block) {
+ Block->Preds.push_back(this);
+ Succs.push_back(Block);
+ }
+
+ unsigned getBlockID() const { return BlockID; }
+
+ void dump(const CFG* cfg) const;
+ void print(llvm::raw_ostream& OS, const CFG* cfg) const;
+ void printTerminator(llvm::raw_ostream& OS) const;
+};
+
+
+/// CFG - Represents a source-level, intra-procedural CFG that represents the
+/// control-flow of a Stmt. The Stmt can represent an entire function body,
+/// or a single expression. A CFG will always contain one empty block that
+/// represents the Exit point of the CFG. A CFG will also contain a designated
+/// Entry block. The CFG solely represents control-flow; it consists of
+/// CFGBlocks which are simply containers of Stmt*'s in the AST the CFG
+/// was constructed from.
+class CFG {
+public:
+ //===--------------------------------------------------------------------===//
+ // CFG Construction & Manipulation.
+ //===--------------------------------------------------------------------===//
+
+ /// buildCFG - Builds a CFG from an AST. The responsibility to free the
+ /// constructed CFG belongs to the caller.
+ static CFG* buildCFG(Stmt* AST);
+
+ /// createBlock - Create a new block in the CFG. The CFG owns the block;
+ /// the caller should not directly free it.
+ CFGBlock* createBlock();
+
+ /// setEntry - Set the entry block of the CFG. This is typically used
+ /// only during CFG construction. Most CFG clients expect that the
+ /// entry block has no predecessors and contains no statements.
+ void setEntry(CFGBlock *B) { Entry = B; }
+
+ /// setExit - Set the exit block of the CFG. This is typically used
+ /// only during CFG construction. Most CFG clients expect that the
+ /// exit block has no successors and contains no statements.
+ void setIndirectGotoBlock(CFGBlock* B) { IndirectGotoBlock = B; }
+
+ //===--------------------------------------------------------------------===//
+ // Block Iterators
+ //===--------------------------------------------------------------------===//
+
+ typedef std::list<CFGBlock> CFGBlockListTy;
+
+ typedef CFGBlockListTy::iterator iterator;
+ typedef CFGBlockListTy::const_iterator const_iterator;
+ 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(); }
+
+ iterator begin() { return Blocks.begin(); }
+ iterator end() { return Blocks.end(); }
+ const_iterator begin() const { return Blocks.begin(); }
+ const_iterator end() const { return Blocks.end(); }
+
+ reverse_iterator rbegin() { return Blocks.rbegin(); }
+ reverse_iterator rend() { return Blocks.rend(); }
+ 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* getIndirectGotoBlock() { return IndirectGotoBlock; }
+ const CFGBlock* getIndirectGotoBlock() const { return IndirectGotoBlock; }
+
+ //===--------------------------------------------------------------------===//
+ // Member templates useful for various batch operations over CFGs.
+ //===--------------------------------------------------------------------===//
+
+ template <typename CALLBACK>
+ void VisitBlockStmts(CALLBACK& O) const {
+ for (const_iterator I=begin(), E=end(); I != E; ++I)
+ for (CFGBlock::const_iterator BI=I->begin(), BE=I->end(); BI != BE; ++BI)
+ O(*BI);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // CFG Introspection.
+ //===--------------------------------------------------------------------===//
+
+ struct BlkExprNumTy {
+ const signed Idx;
+ explicit BlkExprNumTy(signed idx) : Idx(idx) {}
+ explicit BlkExprNumTy() : Idx(-1) {}
+ operator bool() const { return Idx >= 0; }
+ operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; }
+ };
+
+ bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); }
+ BlkExprNumTy getBlkExprNum(const Stmt* S);
+ unsigned getNumBlkExprs();
+
+ unsigned getNumBlockIDs() const { return NumBlockIDs; }
+
+ //===--------------------------------------------------------------------===//
+ // CFG Debugging: Pretty-Printing and Visualization.
+ //===--------------------------------------------------------------------===//
+
+ void viewCFG() const;
+ void print(llvm::raw_ostream& OS) const;
+ void dump() const;
+
+ //===--------------------------------------------------------------------===//
+ // Internal: constructors and data.
+ //===--------------------------------------------------------------------===//
+
+ CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0),
+ BlkExprMap(NULL) {};
+
+ ~CFG();
+
+ llvm::BumpPtrAllocator& getAllocator() {
+ return Alloc;
+ }
+
+private:
+ CFGBlock* Entry;
+ CFGBlock* Exit;
+ CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch
+ // for indirect gotos
+ CFGBlockListTy Blocks;
+ unsigned NumBlockIDs;
+
+ // BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h.
+ // It represents a map from Expr* to integers to record the set of
+ // block-level expressions and their "statement number" in the CFG.
+ void* BlkExprMap;
+
+ /// Alloc - An internal allocator.
+ llvm::BumpPtrAllocator Alloc;
+};
+} // end namespace clang
+
+//===----------------------------------------------------------------------===//
+// GraphTraits specializations for CFG basic block graphs (source-level CFGs)
+//===----------------------------------------------------------------------===//
+
+namespace llvm {
+
+// Traits for: CFGBlock
+
+template <> struct GraphTraits<clang::CFGBlock* > {
+ typedef clang::CFGBlock NodeType;
+ typedef clang::CFGBlock::succ_iterator ChildIteratorType;
+
+ static NodeType* getEntryNode(clang::CFGBlock* BB)
+ { return BB; }
+
+ static inline ChildIteratorType child_begin(NodeType* N)
+ { return N->succ_begin(); }
+
+ static inline ChildIteratorType child_end(NodeType* N)
+ { return N->succ_end(); }
+};
+
+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)
+ { return BB; }
+
+ static inline ChildIteratorType child_begin(NodeType* N)
+ { return N->succ_begin(); }
+
+ static inline ChildIteratorType child_end(NodeType* N)
+ { return N->succ_end(); }
+};
+
+template <> struct GraphTraits<Inverse<const clang::CFGBlock*> > {
+ typedef const clang::CFGBlock NodeType;
+ typedef clang::CFGBlock::const_pred_iterator ChildIteratorType;
+
+ static NodeType *getEntryNode(Inverse<const clang::CFGBlock*> G)
+ { return G.Graph; }
+
+ static inline ChildIteratorType child_begin(NodeType* N)
+ { return N->pred_begin(); }
+
+ static inline ChildIteratorType child_end(NodeType* N)
+ { return N->pred_end(); }
+};
+
+// Traits for: CFG
+
+template <> struct GraphTraits<clang::CFG* >
+ : public GraphTraits<clang::CFGBlock* > {
+
+ typedef clang::CFG::iterator nodes_iterator;
+
+ static NodeType *getEntryNode(clang::CFG* F) { return &F->getEntry(); }
+ static nodes_iterator nodes_begin(clang::CFG* F) { return F->begin(); }
+ static nodes_iterator nodes_end(clang::CFG* F) { return F->end(); }
+};
+
+template <> struct GraphTraits< const clang::CFG* >
+ : public GraphTraits< const clang::CFGBlock* > {
+
+ typedef clang::CFG::const_iterator nodes_iterator;
+
+ static NodeType *getEntryNode( const clang::CFG* F) { return &F->getEntry(); }
+ static nodes_iterator nodes_begin( const clang::CFG* F) { return F->begin(); }
+ static nodes_iterator nodes_end( const clang::CFG* F) { return F->end(); }
+};
+
+template <> struct GraphTraits<Inverse<const clang::CFG*> >
+ : public GraphTraits<Inverse<const clang::CFGBlock*> > {
+
+ typedef clang::CFG::const_iterator nodes_iterator;
+
+ static NodeType *getEntryNode(const clang::CFG* F) { return &F->getExit(); }
+ static nodes_iterator nodes_begin(const clang::CFG* F) { return F->begin();}
+ static nodes_iterator nodes_end(const clang::CFG* F) { return F->end(); }
+};
+
+} // end llvm namespace
+
+#endif
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
new file mode 100644
index 000000000000..e134aed73d77
--- /dev/null
+++ b/include/clang/AST/Decl.h
@@ -0,0 +1,1409 @@
+//===--- Decl.h - Classes for representing 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 Decl subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_DECL_H
+#define LLVM_CLANG_AST_DECL_H
+
+#include "clang/AST/APValue.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/ExternalASTSource.h"
+
+namespace clang {
+class Expr;
+class FunctionTemplateDecl;
+class Stmt;
+class CompoundStmt;
+class StringLiteral;
+
+/// TranslationUnitDecl - The top declaration context.
+class TranslationUnitDecl : public Decl, public DeclContext {
+ TranslationUnitDecl()
+ : Decl(TranslationUnit, 0, SourceLocation()),
+ DeclContext(TranslationUnit) {}
+public:
+ static TranslationUnitDecl *Create(ASTContext &C);
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return D->getKind() == TranslationUnit; }
+ static bool classof(const TranslationUnitDecl *D) { return true; }
+ static DeclContext *castToDeclContext(const TranslationUnitDecl *D) {
+ return static_cast<DeclContext *>(const_cast<TranslationUnitDecl*>(D));
+ }
+ static TranslationUnitDecl *castFromDeclContext(const DeclContext *DC) {
+ return static_cast<TranslationUnitDecl *>(const_cast<DeclContext*>(DC));
+ }
+};
+
+/// NamedDecl - This represents a decl with a name. Many decls have names such
+/// as ObjCMethodDecl, but not @class, etc.
+class NamedDecl : public Decl {
+ /// Name - The name of this declaration, which is typically a normal
+ /// identifier but may also be a special kind of name (C++
+ /// constructor, Objective-C selector, etc.)
+ DeclarationName Name;
+
+protected:
+ NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N)
+ : Decl(DK, DC, L), Name(N) { }
+
+public:
+ /// getIdentifier - Get the identifier that names this declaration,
+ /// if there is one. This will return NULL if this declaration has
+ /// no name (e.g., for an unnamed class) or if the name is a special
+ /// name (C++ constructor, Objective-C selector, etc.).
+ IdentifierInfo *getIdentifier() const { return Name.getAsIdentifierInfo(); }
+
+ /// getNameAsCString - Get the name of identifier for this declaration as a
+ /// C string (const char*). This requires that the declaration have a name
+ /// and that it be a simple identifier.
+ const char *getNameAsCString() const {
+ assert(getIdentifier() && "Name is not a simple identifier");
+ return getIdentifier()->getName();
+ }
+
+ /// getDeclName - Get the actual, stored name of the declaration,
+ /// which may be a special name.
+ DeclarationName getDeclName() const { return Name; }
+
+ /// \brief Set the name of this declaration.
+ void setDeclName(DeclarationName N) { Name = N; }
+
+ /// getNameAsString - Get a human-readable name for the declaration, even if
+ /// it is one of the special kinds of names (C++ constructor, Objective-C
+ /// selector, etc). Creating this name requires expensive string
+ /// manipulation, so it should be called only when performance doesn't matter.
+ /// For simple declarations, getNameAsCString() should suffice.
+ std::string getNameAsString() const { return Name.getAsString(); }
+
+ /// getQualifiedNameAsString - Returns human-readable qualified name for
+ /// declaration, like A::B::i, for i being member of namespace A::B.
+ /// If declaration is not member of context which can be named (record,
+ /// namespace), it will return same result as getNameAsString().
+ /// Creating this name is expensive, so it should be called only when
+ /// performance doesn't matter.
+ std::string getQualifiedNameAsString() const;
+
+ /// declarationReplaces - Determine whether this declaration, if
+ /// known to be well-formed within its context, will replace the
+ /// declaration OldD if introduced into scope. A declaration will
+ /// replace another declaration if, for example, it is a
+ /// redeclaration of the same variable or function, but not if it is
+ /// a declaration of a different kind (function vs. class) or an
+ /// overloaded function.
+ bool declarationReplaces(NamedDecl *OldD) const;
+
+ /// \brief Determine whether this declaration has linkage.
+ bool hasLinkage() const;
+
+ static bool classof(const Decl *D) {
+ return D->getKind() >= NamedFirst && D->getKind() <= NamedLast;
+ }
+ static bool classof(const NamedDecl *D) { return true; }
+};
+
+/// NamespaceDecl - Represent a C++ namespace.
+class NamespaceDecl : public NamedDecl, public DeclContext {
+ SourceLocation LBracLoc, RBracLoc;
+
+ // For extended namespace definitions:
+ //
+ // namespace A { int x; }
+ // namespace A { int y; }
+ //
+ // there will be one NamespaceDecl for each declaration.
+ // NextNamespace points to the next extended declaration.
+ // OrigNamespace points to the original namespace declaration.
+ // OrigNamespace of the first namespace decl points to itself.
+ NamespaceDecl *OrigNamespace, *NextNamespace;
+
+ NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
+ : NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace) {
+ OrigNamespace = this;
+ NextNamespace = 0;
+ }
+public:
+ static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id);
+
+ virtual void Destroy(ASTContext& C);
+
+ NamespaceDecl *getNextNamespace() { return NextNamespace; }
+ const NamespaceDecl *getNextNamespace() const { return NextNamespace; }
+ void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; }
+
+ NamespaceDecl *getOriginalNamespace() const {
+ return OrigNamespace;
+ }
+ void setOriginalNamespace(NamespaceDecl *ND) { OrigNamespace = ND; }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(LBracLoc, RBracLoc);
+ }
+
+ SourceLocation getLBracLoc() const { return LBracLoc; }
+ SourceLocation getRBracLoc() const { return RBracLoc; }
+ void setLBracLoc(SourceLocation LBrace) { LBracLoc = LBrace; }
+ void setRBracLoc(SourceLocation RBrace) { RBracLoc = RBrace; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return D->getKind() == Namespace; }
+ static bool classof(const NamespaceDecl *D) { return true; }
+ static DeclContext *castToDeclContext(const NamespaceDecl *D) {
+ return static_cast<DeclContext *>(const_cast<NamespaceDecl*>(D));
+ }
+ static NamespaceDecl *castFromDeclContext(const DeclContext *DC) {
+ return static_cast<NamespaceDecl *>(const_cast<DeclContext*>(DC));
+ }
+};
+
+/// ValueDecl - Represent the declaration of a variable (in which case it is
+/// an lvalue) a function (in which case it is a function designator) or
+/// an enum constant.
+class ValueDecl : public NamedDecl {
+ QualType DeclType;
+
+protected:
+ ValueDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ DeclarationName N, QualType T)
+ : NamedDecl(DK, DC, L, N), DeclType(T) {}
+public:
+ QualType getType() const { return DeclType; }
+ void setType(QualType newType) { DeclType = newType; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() >= ValueFirst && D->getKind() <= ValueLast;
+ }
+ static bool classof(const ValueDecl *D) { return true; }
+};
+
+/// \brief Structure used to store a statement, the constant value to
+/// which it was evaluated (if any), and whether or not the statement
+/// is an integral constant expression (if known).
+struct EvaluatedStmt {
+ EvaluatedStmt() : WasEvaluated(false), CheckedICE(false), IsICE(false) { }
+
+ /// \brief Whether this statement was already evaluated.
+ bool WasEvaluated : 1;
+
+ /// \brief Whether we already checked whether this statement was an
+ /// integral constant expression.
+ bool CheckedICE : 1;
+
+ /// \brief Whether this statement is an integral constant
+ /// expression. Only valid if CheckedICE is true.
+ bool IsICE : 1;
+
+ Stmt *Value;
+ APValue Evaluated;
+};
+
+/// VarDecl - An instance of this class is created to represent a variable
+/// declaration or definition.
+class VarDecl : public ValueDecl {
+public:
+ enum StorageClass {
+ None, Auto, Register, Extern, Static, PrivateExtern
+ };
+
+ /// getStorageClassSpecifierString - Return the string used to
+ /// specify the storage class \arg SC.
+ ///
+ /// It is illegal to call this function with SC == None.
+ static const char *getStorageClassSpecifierString(StorageClass SC);
+
+private:
+ mutable llvm::PointerUnion<Stmt *, EvaluatedStmt *> Init;
+ // FIXME: This can be packed into the bitfields in Decl.
+ unsigned SClass : 3;
+ bool ThreadSpecified : 1;
+ bool HasCXXDirectInit : 1;
+
+ /// DeclaredInCondition - Whether this variable was declared in a
+ /// condition, e.g., if (int x = foo()) { ... }.
+ bool DeclaredInCondition : 1;
+
+ /// \brief The previous declaration of this variable.
+ VarDecl *PreviousDeclaration;
+
+ // Move to DeclGroup when it is implemented.
+ SourceLocation TypeSpecStartLoc;
+ friend class StmtIteratorBase;
+protected:
+ VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
+ QualType T, StorageClass SC, SourceLocation TSSL = SourceLocation())
+ : ValueDecl(DK, DC, L, Id, T), Init(),
+ ThreadSpecified(false), HasCXXDirectInit(false),
+ DeclaredInCondition(false), PreviousDeclaration(0),
+ TypeSpecStartLoc(TSSL) {
+ SClass = SC;
+ }
+public:
+ static VarDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ QualType T, StorageClass S,
+ SourceLocation TypeSpecStartLoc = SourceLocation());
+
+ virtual ~VarDecl();
+ virtual void Destroy(ASTContext& C);
+
+ StorageClass getStorageClass() const { return (StorageClass)SClass; }
+ void setStorageClass(StorageClass SC) { SClass = SC; }
+
+ SourceLocation getTypeSpecStartLoc() const { return TypeSpecStartLoc; }
+ void setTypeSpecStartLoc(SourceLocation SL) {
+ TypeSpecStartLoc = SL;
+ }
+
+ const Expr *getInit() const {
+ if (Init.isNull())
+ return 0;
+
+ const Stmt *S = Init.dyn_cast<Stmt *>();
+ if (!S)
+ S = Init.get<EvaluatedStmt *>()->Value;
+
+ return (const Expr*) S;
+ }
+ Expr *getInit() {
+ if (Init.isNull())
+ return 0;
+
+ Stmt *S = Init.dyn_cast<Stmt *>();
+ if (!S)
+ S = Init.get<EvaluatedStmt *>()->Value;
+
+ return (Expr*) S;
+ }
+
+ /// \brief Retrieve the address of the initializer expression.
+ Stmt **getInitAddress() {
+ if (Init.is<Stmt *>())
+ return reinterpret_cast<Stmt **>(&Init); // FIXME: ugly hack
+ return &Init.get<EvaluatedStmt *>()->Value;
+ }
+
+ void setInit(ASTContext &C, Expr *I);
+
+ /// \brief Note that constant evaluation has computed the given
+ /// value for this variable's initializer.
+ void setEvaluatedValue(ASTContext &C, const APValue &Value) const {
+ EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
+ if (!Eval) {
+ Stmt *S = Init.get<Stmt *>();
+ Eval = new (C) EvaluatedStmt;
+ Eval->Value = S;
+ Init = Eval;
+ }
+
+ Eval->WasEvaluated = true;
+ Eval->Evaluated = Value;
+ }
+
+ /// \brief Return the already-evaluated value of this variable's
+ /// initializer, or NULL if the value is not yet known.
+ APValue *getEvaluatedValue() const {
+ if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
+ if (Eval->WasEvaluated)
+ return &Eval->Evaluated;
+
+ return 0;
+ }
+
+ /// \brief Determines whether it is already known whether the
+ /// initializer is an integral constant expression or not.
+ bool isInitKnownICE() const {
+ if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
+ return Eval->CheckedICE;
+
+ return false;
+ }
+
+ /// \brief Determines whether the initializer is an integral
+ /// constant expression.
+ ///
+ /// \pre isInitKnownICE()
+ bool isInitICE() const {
+ assert(isInitKnownICE() &&
+ "Check whether we already know that the initializer is an ICE");
+ return Init.get<EvaluatedStmt *>()->IsICE;
+ }
+
+ /// \brief Note that we now know whether the initializer is an
+ /// integral constant expression.
+ void setInitKnownICE(ASTContext &C, bool IsICE) const {
+ EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
+ if (!Eval) {
+ Stmt *S = Init.get<Stmt *>();
+ Eval = new (C) EvaluatedStmt;
+ Eval->Value = S;
+ Init = Eval;
+ }
+
+ Eval->CheckedICE = true;
+ Eval->IsICE = IsICE;
+ }
+
+ /// \brief Retrieve the definition of this variable, which may come
+ /// from a previous declaration. Def will be set to the VarDecl that
+ /// contains the initializer, and the result will be that
+ /// initializer.
+ const Expr *getDefinition(const VarDecl *&Def) const;
+
+ void setThreadSpecified(bool T) { ThreadSpecified = T; }
+ bool isThreadSpecified() const {
+ return ThreadSpecified;
+ }
+
+ void setCXXDirectInitializer(bool T) { HasCXXDirectInit = T; }
+
+ /// hasCXXDirectInitializer - If true, the initializer was a direct
+ /// initializer, e.g: "int x(1);". The Init expression will be the expression
+ /// inside the parens or a "ClassType(a,b,c)" class constructor expression for
+ /// class types. Clients can distinguish between "int x(1);" and "int x=1;"
+ /// by checking hasCXXDirectInitializer.
+ ///
+ bool hasCXXDirectInitializer() const {
+ return HasCXXDirectInit;
+ }
+
+ /// isDeclaredInCondition - Whether this variable was declared as
+ /// part of a condition in an if/switch/while statement, e.g.,
+ /// @code
+ /// if (int x = foo()) { ... }
+ /// @endcode
+ bool isDeclaredInCondition() const {
+ return DeclaredInCondition;
+ }
+ void setDeclaredInCondition(bool InCondition) {
+ DeclaredInCondition = InCondition;
+ }
+
+ /// getPreviousDeclaration - Return the previous declaration of this
+ /// variable.
+ const VarDecl *getPreviousDeclaration() const { return PreviousDeclaration; }
+
+ void setPreviousDeclaration(VarDecl *PrevDecl) {
+ PreviousDeclaration = PrevDecl;
+ }
+
+ /// hasLocalStorage - Returns true if a variable with function scope
+ /// is a non-static local variable.
+ bool hasLocalStorage() const {
+ if (getStorageClass() == None)
+ return !isFileVarDecl();
+
+ // Return true for: Auto, Register.
+ // Return false for: Extern, Static, PrivateExtern.
+
+ return getStorageClass() <= Register;
+ }
+
+ /// hasExternStorage - Returns true if a variable has extern or
+ /// __private_extern__ storage.
+ bool hasExternalStorage() const {
+ return getStorageClass() == Extern || getStorageClass() == PrivateExtern;
+ }
+
+ /// hasGlobalStorage - Returns true for all variables that do not
+ /// have local storage. This includs all global variables as well
+ /// as static variables declared within a function.
+ bool hasGlobalStorage() const { return !hasLocalStorage(); }
+
+ /// isBlockVarDecl - Returns true for local variable declarations. Note that
+ /// this includes static variables inside of functions.
+ ///
+ /// void foo() { int x; static int y; extern int z; }
+ ///
+ bool isBlockVarDecl() const {
+ if (getKind() != Decl::Var)
+ return false;
+ if (const DeclContext *DC = getDeclContext())
+ return DC->getLookupContext()->isFunctionOrMethod();
+ return false;
+ }
+
+ /// \brief Determines whether this is a static data member.
+ ///
+ /// This will only be true in C++, and applies to, e.g., the
+ /// variable 'x' in:
+ /// \code
+ /// struct S {
+ /// static int x;
+ /// };
+ /// \endcode
+ bool isStaticDataMember() const {
+ return getDeclContext()->isRecord();
+ }
+
+ /// isFileVarDecl - Returns true for file scoped variable declaration.
+ bool isFileVarDecl() const {
+ if (getKind() != Decl::Var)
+ return false;
+ if (const DeclContext *Ctx = getDeclContext()) {
+ Ctx = Ctx->getLookupContext();
+ if (isa<TranslationUnitDecl>(Ctx) || isa<NamespaceDecl>(Ctx) )
+ return true;
+ }
+ return false;
+ }
+
+ /// \brief Determine whether this is a tentative definition of a
+ /// variable in C.
+ bool isTentativeDefinition(ASTContext &Context) const;
+
+ /// \brief Determines whether this variable is a variable with
+ /// external, C linkage.
+ bool isExternC(ASTContext &Context) const;
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() >= VarFirst && D->getKind() <= VarLast;
+ }
+ static bool classof(const VarDecl *D) { return true; }
+};
+
+class ImplicitParamDecl : public VarDecl {
+protected:
+ ImplicitParamDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType Tw)
+ : VarDecl(DK, DC, L, Id, Tw, VarDecl::None) {}
+public:
+ static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ QualType T);
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const ImplicitParamDecl *D) { return true; }
+ static bool classof(const Decl *D) { return D->getKind() == ImplicitParam; }
+};
+
+/// ParmVarDecl - Represent a parameter to a function.
+class ParmVarDecl : public VarDecl {
+ // NOTE: VC++ treats enums as signed, avoid using the ObjCDeclQualifier enum
+ /// FIXME: Also can be paced into the bitfields in Decl.
+ /// in, inout, etc.
+ unsigned objcDeclQualifier : 6;
+
+ /// Default argument, if any. [C++ Only]
+ Expr *DefaultArg;
+protected:
+ ParmVarDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType T, StorageClass S,
+ Expr *DefArg)
+ : VarDecl(DK, DC, L, Id, T, S),
+ objcDeclQualifier(OBJC_TQ_None), DefaultArg(DefArg) {}
+
+public:
+ static ParmVarDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,IdentifierInfo *Id,
+ QualType T, StorageClass S, Expr *DefArg);
+
+ ObjCDeclQualifier getObjCDeclQualifier() const {
+ return ObjCDeclQualifier(objcDeclQualifier);
+ }
+ void setObjCDeclQualifier(ObjCDeclQualifier QTVal) {
+ objcDeclQualifier = QTVal;
+ }
+
+ const Expr *getDefaultArg() const { return DefaultArg; }
+ Expr *getDefaultArg() { return DefaultArg; }
+ void setDefaultArg(Expr *defarg) { DefaultArg = defarg; }
+
+ /// hasUnparsedDefaultArg - Determines whether this parameter has a
+ /// default argument that has not yet been parsed. This will occur
+ /// during the processing of a C++ class whose member functions have
+ /// default arguments, e.g.,
+ /// @code
+ /// class X {
+ /// public:
+ /// void f(int x = 17); // x has an unparsed default argument now
+ /// }; // x has a regular default argument now
+ /// @endcode
+ bool hasUnparsedDefaultArg() const {
+ return DefaultArg == reinterpret_cast<Expr *>(-1);
+ }
+
+ /// setUnparsedDefaultArg - Specify that this parameter has an
+ /// unparsed default argument. The argument will be replaced with a
+ /// real default argument via setDefaultArg when the class
+ /// definition enclosing the function declaration that owns this
+ /// default argument is completed.
+ void setUnparsedDefaultArg() { DefaultArg = reinterpret_cast<Expr *>(-1); }
+
+ QualType getOriginalType() const;
+
+ /// setOwningFunction - Sets the function declaration that owns this
+ /// ParmVarDecl. Since ParmVarDecls are often created before the
+ /// FunctionDecls that own them, this routine is required to update
+ /// the DeclContext appropriately.
+ void setOwningFunction(DeclContext *FD) { setDeclContext(FD); }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return (D->getKind() == ParmVar ||
+ D->getKind() == OriginalParmVar);
+ }
+ static bool classof(const ParmVarDecl *D) { return true; }
+};
+
+/// OriginalParmVarDecl - Represent a parameter to a function, when
+/// the type of the parameter has been promoted. This node represents the
+/// parameter to the function with its original type.
+///
+class OriginalParmVarDecl : public ParmVarDecl {
+ friend class ParmVarDecl;
+protected:
+ QualType OriginalType;
+private:
+ OriginalParmVarDecl(DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType T,
+ QualType OT, StorageClass S,
+ Expr *DefArg)
+ : ParmVarDecl(OriginalParmVar, DC, L, Id, T, S, DefArg), OriginalType(OT) {}
+public:
+ static OriginalParmVarDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,IdentifierInfo *Id,
+ QualType T, QualType OT,
+ StorageClass S, Expr *DefArg);
+
+ void setOriginalType(QualType T) { OriginalType = T; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return D->getKind() == OriginalParmVar; }
+ static bool classof(const OriginalParmVarDecl *D) { return true; }
+};
+
+/// FunctionDecl - An instance of this class is created to represent a
+/// function declaration or definition.
+///
+/// Since a given function can be declared several times in a program,
+/// there may be several FunctionDecls that correspond to that
+/// function. Only one of those FunctionDecls will be found when
+/// traversing the list of declarations in the context of the
+/// FunctionDecl (e.g., the translation unit); this FunctionDecl
+/// contains all of the information known about the function. Other,
+/// previous declarations of the function are available via the
+/// getPreviousDeclaration() chain.
+class FunctionDecl : public ValueDecl, public DeclContext {
+public:
+ enum StorageClass {
+ None, Extern, Static, PrivateExtern
+ };
+private:
+ /// ParamInfo - new[]'d array of pointers to VarDecls for the formal
+ /// parameters of this function. This is null if a prototype or if there are
+ /// no formals. TODO: we could allocate this space immediately after the
+ /// FunctionDecl object to save an allocation like FunctionType does.
+ ParmVarDecl **ParamInfo;
+
+ LazyDeclStmtPtr Body;
+
+ /// PreviousDeclaration - A link to the previous declaration of this
+ /// same function, NULL if this is the first declaration. For
+ /// example, in the following code, the PreviousDeclaration can be
+ /// traversed several times to see all three declarations of the
+ /// function "f", the last of which is also a definition.
+ ///
+ /// int f(int x, int y = 1);
+ /// int f(int x = 0, int y);
+ /// int f(int x, int y) { return x + y; }
+ FunctionDecl *PreviousDeclaration;
+
+ // FIXME: This can be packed into the bitfields in Decl.
+ // NOTE: VC++ treats enums as signed, avoid using the StorageClass enum
+ unsigned SClass : 2;
+ bool IsInline : 1;
+ bool C99InlineDefinition : 1;
+ bool IsVirtualAsWritten : 1;
+ bool IsPure : 1;
+ bool HasInheritedPrototype : 1;
+ bool HasWrittenPrototype : 1;
+ bool IsDeleted : 1;
+
+ // Move to DeclGroup when it is implemented.
+ SourceLocation TypeSpecStartLoc;
+
+ /// \brief The template or declaration that this declaration
+ /// describes or was instantiated from, respectively.
+ ///
+ /// For non-templates, this value will be NULL. For function
+ /// declarations that describe a function template, this will be a
+ /// pointer to a FunctionTemplateDecl. For member functions
+ /// of class template specializations, this will be the
+ /// FunctionDecl from which the member function was instantiated.
+ llvm::PointerUnion<FunctionTemplateDecl*, FunctionDecl*>
+ TemplateOrInstantiation;
+
+protected:
+ FunctionDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ DeclarationName N, QualType T,
+ StorageClass S, bool isInline,
+ SourceLocation TSSL = SourceLocation())
+ : ValueDecl(DK, DC, L, N, T),
+ DeclContext(DK),
+ ParamInfo(0), Body(), PreviousDeclaration(0),
+ SClass(S), IsInline(isInline), C99InlineDefinition(false),
+ IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false),
+ HasWrittenPrototype(true), IsDeleted(false), TypeSpecStartLoc(TSSL),
+ TemplateOrInstantiation() {}
+
+ virtual ~FunctionDecl() {}
+ virtual void Destroy(ASTContext& C);
+
+public:
+ static FunctionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ DeclarationName N, QualType T,
+ StorageClass S = None, bool isInline = false,
+ bool hasWrittenPrototype = true,
+ SourceLocation TSStartLoc = SourceLocation());
+
+ SourceLocation getTypeSpecStartLoc() const { return TypeSpecStartLoc; }
+ void setTypeSpecStartLoc(SourceLocation TS) { TypeSpecStartLoc = TS; }
+
+ /// getBody - Retrieve the body (definition) of the function. The
+ /// function body might be in any of the (re-)declarations of this
+ /// function. The variant that accepts a FunctionDecl pointer will
+ /// set that function declaration to the actual declaration
+ /// containing the body (if there is one).
+ Stmt *getBody(ASTContext &Context, const FunctionDecl *&Definition) const;
+
+ virtual Stmt *getBody(ASTContext &Context) const {
+ const FunctionDecl* Definition;
+ return getBody(Context, Definition);
+ }
+
+ /// \brief If the function has a body that is immediately available,
+ /// return it.
+ Stmt *getBodyIfAvailable() const;
+
+ /// isThisDeclarationADefinition - Returns whether this specific
+ /// declaration of the function is also a definition. This does not
+ /// determine whether the function has been defined (e.g., in a
+ /// previous definition); for that information, use getBody.
+ /// FIXME: Should return true if function is deleted or defaulted. However,
+ /// CodeGenModule.cpp uses it, and I don't know if this would break it.
+ bool isThisDeclarationADefinition() const { return Body; }
+
+ void setBody(Stmt *B) { Body = B; }
+ void setLazyBody(uint64_t Offset) { Body = Offset; }
+
+ /// Whether this function is marked as virtual explicitly.
+ bool isVirtualAsWritten() const { return IsVirtualAsWritten; }
+ void setVirtualAsWritten(bool V) { IsVirtualAsWritten = V; }
+
+ /// Whether this virtual function is pure, i.e. makes the containing class
+ /// abstract.
+ bool isPure() const { return IsPure; }
+ void setPure(bool P = true) { IsPure = P; }
+
+ /// \brief Whether this function has a prototype, either because one
+ /// was explicitly written or because it was "inherited" by merging
+ /// a declaration without a prototype with a declaration that has a
+ /// prototype.
+ bool hasPrototype() const {
+ return HasWrittenPrototype || HasInheritedPrototype;
+ }
+
+ bool hasWrittenPrototype() const { return HasWrittenPrototype; }
+ void setHasWrittenPrototype(bool P) { HasWrittenPrototype = P; }
+
+ /// \brief Whether this function inherited its prototype from a
+ /// previous declaration.
+ bool hasInheritedPrototype() const { return HasInheritedPrototype; }
+ void setHasInheritedPrototype(bool P = true) { HasInheritedPrototype = P; }
+
+ /// \brief Whether this function has been deleted.
+ ///
+ /// A function that is "deleted" (via the C++0x "= delete" syntax)
+ /// acts like a normal function, except that it cannot actually be
+ /// called or have its address taken. Deleted functions are
+ /// typically used in C++ overload resolution to attract arguments
+ /// whose type or lvalue/rvalue-ness would permit the use of a
+ /// different overload that would behave incorrectly. For example,
+ /// one might use deleted functions to ban implicit conversion from
+ /// a floating-point number to an Integer type:
+ ///
+ /// @code
+ /// struct Integer {
+ /// Integer(long); // construct from a long
+ /// Integer(double) = delete; // no construction from float or double
+ /// Integer(long double) = delete; // no construction from long double
+ /// };
+ /// @endcode
+ bool isDeleted() const { return IsDeleted; }
+ void setDeleted(bool D = true) { IsDeleted = D; }
+
+ /// \brief Determines whether this is a function "main", which is
+ /// the entry point into an executable program.
+ bool isMain() const;
+
+ /// \brief Determines whether this function is a function with
+ /// external, C linkage.
+ bool isExternC(ASTContext &Context) const;
+
+ /// \brief Determines whether this is a global function.
+ bool isGlobal() const;
+
+ /// getPreviousDeclaration - Return the previous declaration of this
+ /// function.
+ const FunctionDecl *getPreviousDeclaration() const {
+ return PreviousDeclaration;
+ }
+
+ void setPreviousDeclaration(FunctionDecl * PrevDecl) {
+ PreviousDeclaration = PrevDecl;
+ }
+
+ unsigned getBuiltinID(ASTContext &Context) const;
+
+ unsigned getNumParmVarDeclsFromType() const;
+
+ // Iterator access to formal parameters.
+ unsigned param_size() const { return getNumParams(); }
+ typedef ParmVarDecl **param_iterator;
+ typedef ParmVarDecl * const *param_const_iterator;
+
+ param_iterator param_begin() { return ParamInfo; }
+ param_iterator param_end() { return ParamInfo+param_size(); }
+
+ param_const_iterator param_begin() const { return ParamInfo; }
+ param_const_iterator param_end() const { return ParamInfo+param_size(); }
+
+ /// getNumParams - Return the number of parameters this function must have
+ /// based on its functiontype. This is the length of the PararmInfo array
+ /// after it has been created.
+ unsigned getNumParams() const;
+
+ const ParmVarDecl *getParamDecl(unsigned i) const {
+ assert(i < getNumParams() && "Illegal param #");
+ return ParamInfo[i];
+ }
+ ParmVarDecl *getParamDecl(unsigned i) {
+ assert(i < getNumParams() && "Illegal param #");
+ return ParamInfo[i];
+ }
+ void setParams(ASTContext& C, ParmVarDecl **NewParamInfo, unsigned NumParams);
+
+ /// getMinRequiredArguments - Returns the minimum number of arguments
+ /// needed to call this function. This may be fewer than the number of
+ /// function parameters, if some of the parameters have default
+ /// arguments (in C++).
+ unsigned getMinRequiredArguments() const;
+
+ QualType getResultType() const {
+ return getType()->getAsFunctionType()->getResultType();
+ }
+ StorageClass getStorageClass() const { return StorageClass(SClass); }
+ void setStorageClass(StorageClass SC) { SClass = SC; }
+
+ bool isInline() const { return IsInline; }
+ void setInline(bool I) { IsInline = I; }
+
+ /// \brief Whether this function is an "inline definition" as
+ /// defined by C99.
+ bool isC99InlineDefinition() const { return C99InlineDefinition; }
+ void setC99InlineDefinition(bool I) { C99InlineDefinition = I; }
+
+ /// \brief Determines whether this function has a gnu_inline
+ /// attribute that affects its semantics.
+ ///
+ /// The gnu_inline attribute only introduces GNU inline semantics
+ /// when all of the inline declarations of the function are marked
+ /// gnu_inline.
+ bool hasActiveGNUInlineAttribute() const;
+
+ /// \brief Determines whether this function is a GNU "extern
+ /// inline", which is roughly the opposite of a C99 "extern inline"
+ /// function.
+ bool isExternGNUInline() const;
+
+ /// isOverloadedOperator - Whether this function declaration
+ /// represents an C++ overloaded operator, e.g., "operator+".
+ bool isOverloadedOperator() const {
+ return getOverloadedOperator() != OO_None;
+ };
+
+ OverloadedOperatorKind getOverloadedOperator() const;
+
+ /// \brief If this function is an instantiation of a member function
+ /// of a class template specialization, retrieves the function from
+ /// which it was instantiated.
+ ///
+ /// This routine will return non-NULL for (non-templated) member
+ /// functions of class templates and for instantiations of function
+ /// templates. For example, given:
+ ///
+ /// \code
+ /// template<typename T>
+ /// struct X {
+ /// void f(T);
+ /// };
+ /// \endcode
+ ///
+ /// The declaration for X<int>::f is a (non-templated) FunctionDecl
+ /// whose parent is the class template specialization X<int>. For
+ /// this declaration, getInstantiatedFromFunction() will return
+ /// the FunctionDecl X<T>::A. When a complete definition of
+ /// X<int>::A is required, it will be instantiated from the
+ /// declaration returned by getInstantiatedFromMemberFunction().
+ FunctionDecl *getInstantiatedFromMemberFunction() const {
+ return TemplateOrInstantiation.dyn_cast<FunctionDecl*>();
+ }
+
+ /// \brief Specify that this record is an instantiation of the
+ /// member function RD.
+ void setInstantiationOfMemberFunction(FunctionDecl *RD) {
+ TemplateOrInstantiation = RD;
+ }
+
+ /// \brief Retrieves the function template that is described by this
+ /// function declaration.
+ ///
+ /// Every function template is represented as a FunctionTemplateDecl
+ /// and a FunctionDecl (or something derived from FunctionDecl). The
+ /// former contains template properties (such as the template
+ /// parameter lists) while the latter contains the actual
+ /// description of the template's
+ /// contents. FunctionTemplateDecl::getTemplatedDecl() retrieves the
+ /// FunctionDecl that describes the function template,
+ /// getDescribedFunctionTemplate() retrieves the
+ /// FunctionTemplateDecl from a FunctionDecl.
+ FunctionTemplateDecl *getDescribedFunctionTemplate() const {
+ return TemplateOrInstantiation.dyn_cast<FunctionTemplateDecl*>();
+ }
+
+ void setDescribedFunctionTemplate(FunctionTemplateDecl *Template) {
+ TemplateOrInstantiation = Template;
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast;
+ }
+ static bool classof(const FunctionDecl *D) { return true; }
+ static DeclContext *castToDeclContext(const FunctionDecl *D) {
+ return static_cast<DeclContext *>(const_cast<FunctionDecl*>(D));
+ }
+ static FunctionDecl *castFromDeclContext(const DeclContext *DC) {
+ return static_cast<FunctionDecl *>(const_cast<DeclContext*>(DC));
+ }
+};
+
+
+/// FieldDecl - An instance of this class is created by Sema::ActOnField to
+/// represent a member of a struct/union/class.
+class FieldDecl : public ValueDecl {
+ // FIXME: This can be packed into the bitfields in Decl.
+ bool Mutable : 1;
+ Expr *BitWidth;
+protected:
+ FieldDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType T, Expr *BW, bool Mutable)
+ : ValueDecl(DK, DC, L, Id, T), Mutable(Mutable), BitWidth(BW)
+ { }
+
+public:
+ static FieldDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType T, Expr *BW,
+ bool Mutable);
+
+ /// isMutable - Determines whether this field is mutable (C++ only).
+ bool isMutable() const { return Mutable; }
+
+ /// \brief Set whether this field is mutable (C++ only).
+ void setMutable(bool M) { Mutable = M; }
+
+ /// isBitfield - Determines whether this field is a bitfield.
+ bool isBitField() const { return BitWidth != NULL; }
+
+ /// @brief Determines whether this is an unnamed bitfield.
+ bool isUnnamedBitfield() const { return BitWidth != NULL && !getDeclName(); }
+
+ /// isAnonymousStructOrUnion - Determines whether this field is a
+ /// representative for an anonymous struct or union. Such fields are
+ /// unnamed and are implicitly generated by the implementation to
+ /// store the data for the anonymous union or struct.
+ bool isAnonymousStructOrUnion() const;
+
+ Expr *getBitWidth() const { return BitWidth; }
+ void setBitWidth(Expr *BW) { BitWidth = BW; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() >= FieldFirst && D->getKind() <= FieldLast;
+ }
+ static bool classof(const FieldDecl *D) { return true; }
+};
+
+/// EnumConstantDecl - An instance of this object exists for each enum constant
+/// that is defined. For example, in "enum X {a,b}", each of a/b are
+/// EnumConstantDecl's, X is an instance of EnumDecl, and the type of a/b is a
+/// TagType for the X EnumDecl.
+class EnumConstantDecl : public ValueDecl {
+ Stmt *Init; // an integer constant expression
+ llvm::APSInt Val; // The value.
+protected:
+ EnumConstantDecl(DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType T, Expr *E,
+ const llvm::APSInt &V)
+ : ValueDecl(EnumConstant, DC, L, Id, T), Init((Stmt*)E), Val(V) {}
+
+ virtual ~EnumConstantDecl() {}
+public:
+
+ static EnumConstantDecl *Create(ASTContext &C, EnumDecl *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ QualType T, Expr *E,
+ const llvm::APSInt &V);
+
+ virtual void Destroy(ASTContext& C);
+
+ const Expr *getInitExpr() const { return (const Expr*) Init; }
+ Expr *getInitExpr() { return (Expr*) Init; }
+ const llvm::APSInt &getInitVal() const { return Val; }
+
+ void setInitExpr(Expr *E) { Init = (Stmt*) E; }
+ void setInitVal(const llvm::APSInt &V) { Val = V; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return D->getKind() == EnumConstant; }
+ static bool classof(const EnumConstantDecl *D) { return true; }
+
+ friend class StmtIteratorBase;
+};
+
+
+/// TypeDecl - Represents a declaration of a type.
+///
+class TypeDecl : public NamedDecl {
+ /// TypeForDecl - This indicates the Type object that represents
+ /// this TypeDecl. It is a cache maintained by
+ /// ASTContext::getTypedefType, ASTContext::getTagDeclType, and
+ /// ASTContext::getTemplateTypeParmType, and TemplateTypeParmDecl.
+ mutable Type *TypeForDecl;
+ friend class ASTContext;
+ friend class DeclContext;
+ friend class TagDecl;
+ friend class TemplateTypeParmDecl;
+ friend class ClassTemplateSpecializationDecl;
+ friend class TagType;
+
+protected:
+ TypeDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id)
+ : NamedDecl(DK, DC, L, Id), TypeForDecl(0) {}
+
+public:
+ // Low-level accessor
+ Type *getTypeForDecl() const { return TypeForDecl; }
+ void setTypeForDecl(Type *TD) { TypeForDecl = TD; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() >= TypeFirst && D->getKind() <= TypeLast;
+ }
+ static bool classof(const TypeDecl *D) { return true; }
+};
+
+
+class TypedefDecl : public TypeDecl {
+ /// UnderlyingType - This is the type the typedef is set to.
+ QualType UnderlyingType;
+ TypedefDecl(DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType T)
+ : TypeDecl(Typedef, DC, L, Id), UnderlyingType(T) {}
+
+ virtual ~TypedefDecl() {}
+public:
+
+ static TypedefDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,IdentifierInfo *Id,
+ QualType T);
+
+ QualType getUnderlyingType() const { return UnderlyingType; }
+ void setUnderlyingType(QualType newType) { UnderlyingType = newType; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return D->getKind() == Typedef; }
+ static bool classof(const TypedefDecl *D) { return true; }
+};
+
+class TypedefDecl;
+
+/// TagDecl - Represents the declaration of a struct/union/class/enum.
+class TagDecl : public TypeDecl, public DeclContext {
+public:
+ enum TagKind {
+ TK_struct,
+ TK_union,
+ TK_class,
+ TK_enum
+ };
+
+private:
+ // FIXME: This can be packed into the bitfields in Decl.
+ /// 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;
+
+ /// TypedefForAnonDecl - If a TagDecl is anonymous and part of a typedef,
+ /// this points to the TypedefDecl. Used for mangling.
+ TypedefDecl *TypedefForAnonDecl;
+
+protected:
+ TagDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id)
+ : TypeDecl(DK, DC, L, Id), DeclContext(DK), TypedefForAnonDecl(0) {
+ assert((DK != Enum || TK == TK_enum) &&"EnumDecl not matched with TK_enum");
+ TagDeclKind = TK;
+ IsDefinition = false;
+ }
+public:
+
+ /// isDefinition - Return true if this decl has its body specified.
+ bool isDefinition() const {
+ return IsDefinition;
+ }
+
+ /// \brief Whether this declaration declares a type that is
+ /// dependent, i.e., a type that somehow depends on template
+ /// parameters.
+ bool isDependentType() const { return isDependentContext(); }
+
+ /// @brief Starts the definition of this tag declaration.
+ ///
+ /// This method should be invoked at the beginning of the definition
+ /// of this tag declaration. It will set the tag type into a state
+ /// where it is in the process of being defined.
+ void startDefinition();
+
+ /// @brief Completes the definition of this tag declaration.
+ void completeDefinition();
+
+ /// 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(ASTContext& C) const;
+
+ const char *getKindName() const {
+ switch (getTagKind()) {
+ default: assert(0 && "Unknown TagKind!");
+ case TK_struct: return "struct";
+ case TK_union: return "union";
+ case TK_class: return "class";
+ case TK_enum: return "enum";
+ }
+ }
+
+ TagKind getTagKind() const {
+ return TagKind(TagDeclKind);
+ }
+
+ void setTagKind(TagKind TK) { TagDeclKind = TK; }
+
+ bool isStruct() const { return getTagKind() == TK_struct; }
+ bool isClass() const { return getTagKind() == TK_class; }
+ bool isUnion() const { return getTagKind() == TK_union; }
+ bool isEnum() const { return getTagKind() == TK_enum; }
+
+ TypedefDecl *getTypedefForAnonDecl() const { return TypedefForAnonDecl; }
+ void setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefForAnonDecl = TDD; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() >= TagFirst && D->getKind() <= TagLast;
+ }
+ static bool classof(const TagDecl *D) { return true; }
+
+ static DeclContext *castToDeclContext(const TagDecl *D) {
+ return static_cast<DeclContext *>(const_cast<TagDecl*>(D));
+ }
+ static TagDecl *castFromDeclContext(const DeclContext *DC) {
+ return static_cast<TagDecl *>(const_cast<DeclContext*>(DC));
+ }
+
+ void setDefinition(bool V) { IsDefinition = V; }
+};
+
+/// EnumDecl - Represents an enum. As an extension, we allow forward-declared
+/// enums.
+class EnumDecl : public TagDecl {
+ /// IntegerType - This represent the integer type that the enum corresponds
+ /// to for code generation purposes. Note that the enumerator constants may
+ /// have a different type than this does.
+ QualType IntegerType;
+
+ /// \brief If the enumeration was instantiated from an enumeration
+ /// within a class or function template, this pointer refers to the
+ /// enumeration declared within the template.
+ EnumDecl *InstantiatedFrom;
+
+ EnumDecl(DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id)
+ : TagDecl(Enum, TK_enum, DC, L, Id), InstantiatedFrom(0) {
+ IntegerType = QualType();
+ }
+public:
+ static EnumDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ EnumDecl *PrevDecl);
+
+ virtual void Destroy(ASTContext& C);
+
+ /// completeDefinition - When created, the EnumDecl corresponds to a
+ /// forward-declared enum. This method is used to mark the
+ /// declaration as being defined; it's enumerators have already been
+ /// added (via DeclContext::addDecl). NewType is the new underlying
+ /// type of the enumeration type.
+ void completeDefinition(ASTContext &C, QualType NewType);
+
+ // enumerator_iterator - Iterates through the enumerators of this
+ // enumeration.
+ typedef specific_decl_iterator<EnumConstantDecl> enumerator_iterator;
+
+ enumerator_iterator enumerator_begin(ASTContext &Context) const {
+ return enumerator_iterator(this->decls_begin(Context));
+ }
+
+ enumerator_iterator enumerator_end(ASTContext &Context) const {
+ return enumerator_iterator(this->decls_end(Context));
+ }
+
+ /// getIntegerType - Return the integer type this enum decl corresponds to.
+ /// This returns a null qualtype for an enum forward definition.
+ QualType getIntegerType() const { return IntegerType; }
+
+ /// \brief Set the underlying integer type.
+ void setIntegerType(QualType T) { IntegerType = T; }
+
+ /// \brief Returns the enumeration (declared within the template)
+ /// from which this enumeration type was instantiated, or NULL if
+ /// this enumeration was not instantiated from any template.
+ EnumDecl *getInstantiatedFromMemberEnum() const {
+ return InstantiatedFrom;
+ }
+
+ void setInstantiationOfMemberEnum(EnumDecl *IF) { InstantiatedFrom = IF; }
+
+ static bool classof(const Decl *D) { return D->getKind() == Enum; }
+ static bool classof(const EnumDecl *D) { return true; }
+};
+
+
+/// RecordDecl - Represents a struct/union/class. For example:
+/// struct X; // Forward declaration, no "body".
+/// union Y { int A, B; }; // Has body with members A and B (FieldDecls).
+/// This decl will be marked invalid if *any* members are invalid.
+///
+class RecordDecl : public TagDecl {
+ // FIXME: This can be packed into the bitfields in Decl.
+ /// HasFlexibleArrayMember - This is true if this struct ends with a flexible
+ /// array member (e.g. int X[]) or if this union contains a struct that does.
+ /// If so, this cannot be contained in arrays or other structs as a member.
+ bool HasFlexibleArrayMember : 1;
+
+ /// AnonymousStructOrUnion - Whether this is the type of an
+ /// anonymous struct or union.
+ bool AnonymousStructOrUnion : 1;
+
+protected:
+ RecordDecl(Kind DK, TagKind TK, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id);
+ virtual ~RecordDecl();
+
+public:
+ static RecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ RecordDecl* PrevDecl = 0);
+
+ virtual void Destroy(ASTContext& C);
+
+ bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
+ void setHasFlexibleArrayMember(bool V) { HasFlexibleArrayMember = V; }
+
+ /// isAnonymousStructOrUnion - Whether this is an anonymous struct
+ /// or union. To be an anonymous struct or union, it must have been
+ /// declared without a name and there must be no objects of this
+ /// type declared, e.g.,
+ /// @code
+ /// union { int i; float f; };
+ /// @endcode
+ /// is an anonymous union but neither of the following are:
+ /// @code
+ /// union X { int i; float f; };
+ /// union { int i; float f; } obj;
+ /// @endcode
+ bool isAnonymousStructOrUnion() const { return AnonymousStructOrUnion; }
+ void setAnonymousStructOrUnion(bool Anon) {
+ AnonymousStructOrUnion = Anon;
+ }
+
+ /// \brief Determines whether this declaration represents the
+ /// injected class name.
+ ///
+ /// The injected class name in C++ is the name of the class that
+ /// appears inside the class itself. For example:
+ ///
+ /// \code
+ /// struct C {
+ /// // C is implicitly declared here as a synonym for the class name.
+ /// };
+ ///
+ /// C::C c; // same as "C c;"
+ /// \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(ASTContext& C) const {
+ return cast_or_null<RecordDecl>(TagDecl::getDefinition(C));
+ }
+
+ // Iterator access to field members. The field iterator only visits
+ // the non-static data members of this class, ignoring any static
+ // data members, functions, constructors, destructors, etc.
+ typedef specific_decl_iterator<FieldDecl> field_iterator;
+
+ field_iterator field_begin(ASTContext &Context) const {
+ return field_iterator(decls_begin(Context));
+ }
+ field_iterator field_end(ASTContext &Context) const {
+ return field_iterator(decls_end(Context));
+ }
+
+ // field_empty - Whether there are any fields (non-static data
+ // members) in this record.
+ bool field_empty(ASTContext &Context) const {
+ return field_begin(Context) == field_end(Context);
+ }
+
+ /// completeDefinition - Notes that the definition of this type is
+ /// now complete.
+ void completeDefinition(ASTContext& C);
+
+ static bool classof(const Decl *D) {
+ return D->getKind() >= RecordFirst && D->getKind() <= RecordLast;
+ }
+ static bool classof(const RecordDecl *D) { return true; }
+};
+
+class FileScopeAsmDecl : public Decl {
+ StringLiteral *AsmString;
+ FileScopeAsmDecl(DeclContext *DC, SourceLocation L, StringLiteral *asmstring)
+ : Decl(FileScopeAsm, DC, L), AsmString(asmstring) {}
+public:
+ static FileScopeAsmDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, StringLiteral *Str);
+
+ const StringLiteral *getAsmString() const { return AsmString; }
+ StringLiteral *getAsmString() { return AsmString; }
+ void setAsmString(StringLiteral *Asm) { AsmString = Asm; }
+
+ static bool classof(const Decl *D) {
+ return D->getKind() == FileScopeAsm;
+ }
+ static bool classof(const FileScopeAsmDecl *D) { return true; }
+};
+
+/// BlockDecl - This represents a block literal declaration, which is like an
+/// unnamed FunctionDecl. For example:
+/// ^{ statement-body } or ^(int arg1, float arg2){ statement-body }
+///
+class BlockDecl : public Decl, public DeclContext {
+ // FIXME: This can be packed into the bitfields in Decl.
+ bool isVariadic : 1;
+ /// ParamInfo - new[]'d array of pointers to ParmVarDecls for the formal
+ /// parameters of this function. This is null if a prototype or if there are
+ /// no formals.
+ ParmVarDecl **ParamInfo;
+ unsigned NumParams;
+
+ Stmt *Body;
+
+protected:
+ BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
+ : Decl(Block, DC, CaretLoc), DeclContext(Block),
+ isVariadic(false), ParamInfo(0), NumParams(0), Body(0) {}
+
+ virtual ~BlockDecl();
+ virtual void Destroy(ASTContext& C);
+
+public:
+ static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L);
+
+ SourceLocation getCaretLocation() const { return getLocation(); }
+
+ bool IsVariadic() const { return isVariadic; }
+ void setIsVariadic(bool value) { isVariadic = value; }
+
+ CompoundStmt *getBody() const { return (CompoundStmt*) Body; }
+ Stmt *getBody(ASTContext &C) const { return (Stmt*) Body; }
+ void setBody(CompoundStmt *B) { Body = (Stmt*) B; }
+
+ // Iterator access to formal parameters.
+ unsigned param_size() const { return getNumParams(); }
+ typedef ParmVarDecl **param_iterator;
+ typedef ParmVarDecl * const *param_const_iterator;
+
+ bool param_empty() const { return NumParams == 0; }
+ param_iterator param_begin() { return ParamInfo; }
+ param_iterator param_end() { return ParamInfo+param_size(); }
+
+ param_const_iterator param_begin() const { return ParamInfo; }
+ param_const_iterator param_end() const { return ParamInfo+param_size(); }
+
+ unsigned getNumParams() const;
+ const ParmVarDecl *getParamDecl(unsigned i) const {
+ assert(i < getNumParams() && "Illegal param #");
+ return ParamInfo[i];
+ }
+ ParmVarDecl *getParamDecl(unsigned i) {
+ assert(i < getNumParams() && "Illegal param #");
+ return ParamInfo[i];
+ }
+ void setParams(ASTContext& C, ParmVarDecl **NewParamInfo, unsigned NumParams);
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return D->getKind() == Block; }
+ static bool classof(const BlockDecl *D) { return true; }
+ static DeclContext *castToDeclContext(const BlockDecl *D) {
+ return static_cast<DeclContext *>(const_cast<BlockDecl*>(D));
+ }
+ static BlockDecl *castFromDeclContext(const DeclContext *DC) {
+ return static_cast<BlockDecl *>(const_cast<DeclContext*>(DC));
+ }
+};
+
+/// 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);
+ return DB;
+}
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
new file mode 100644
index 000000000000..c061b857063a
--- /dev/null
+++ b/include/clang/AST/DeclBase.h
@@ -0,0 +1,900 @@
+//===-- DeclBase.h - Base Classes for representing 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 Decl and DeclContext interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_DECLBASE_H
+#define LLVM_CLANG_AST_DECLBASE_H
+
+#include "clang/AST/Attr.h"
+#include "clang/AST/Type.h"
+// FIXME: Layering violation
+#include "clang/Parse/AccessSpecifier.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/ADT/PointerUnion.h"
+
+namespace clang {
+class DeclContext;
+class TranslationUnitDecl;
+class NamespaceDecl;
+class UsingDirectiveDecl;
+class NamedDecl;
+class FunctionDecl;
+class CXXRecordDecl;
+class EnumDecl;
+class ObjCMethodDecl;
+class ObjCContainerDecl;
+class ObjCInterfaceDecl;
+class ObjCCategoryDecl;
+class ObjCProtocolDecl;
+class ObjCImplementationDecl;
+class ObjCCategoryImplDecl;
+class LinkageSpecDecl;
+class BlockDecl;
+class DeclarationName;
+class CompoundStmt;
+}
+
+namespace llvm {
+// DeclContext* is only 4-byte aligned on 32-bit systems.
+template<>
+ class PointerLikeTypeTraits<clang::DeclContext*> {
+ typedef clang::DeclContext* PT;
+public:
+ static inline void *getAsVoidPointer(PT P) { return P; }
+ static inline PT getFromVoidPointer(void *P) {
+ return static_cast<PT>(P);
+ }
+ enum { NumLowBitsAvailable = 2 };
+};
+}
+
+namespace clang {
+
+/// Decl - This represents one declaration (or definition), e.g. a variable,
+/// typedef, function, struct, etc.
+///
+class Decl {
+public:
+ /// \brief Lists the kind of concrete classes of Decl.
+ enum Kind {
+#define DECL(Derived, Base) Derived,
+#define DECL_RANGE(CommonBase, Start, End) \
+ CommonBase##First = Start, CommonBase##Last = End,
+#define LAST_DECL_RANGE(CommonBase, Start, End) \
+ CommonBase##First = Start, CommonBase##Last = End
+#include "clang/AST/DeclNodes.def"
+ };
+
+ /// IdentifierNamespace - According to C99 6.2.3, there are four
+ /// namespaces, labels, tags, members and ordinary
+ /// identifiers. These are meant as bitmasks, so that searches in
+ /// C++ can look into the "tag" namespace during ordinary lookup. We
+ /// use additional namespaces for Objective-C entities.
+ enum IdentifierNamespace {
+ IDNS_Label = 0x1,
+ IDNS_Tag = 0x2,
+ IDNS_Member = 0x4,
+ IDNS_Ordinary = 0x8,
+ IDNS_ObjCProtocol = 0x10,
+ IDNS_ObjCImplementation = 0x20,
+ IDNS_ObjCCategoryImpl = 0x40
+ };
+
+ /// ObjCDeclQualifier - Qualifier used on types in method declarations
+ /// for remote messaging. They are meant for the arguments though and
+ /// applied to the Decls (ObjCMethodDecl and ParmVarDecl).
+ enum ObjCDeclQualifier {
+ OBJC_TQ_None = 0x0,
+ OBJC_TQ_In = 0x1,
+ OBJC_TQ_Inout = 0x2,
+ OBJC_TQ_Out = 0x4,
+ OBJC_TQ_Bycopy = 0x8,
+ OBJC_TQ_Byref = 0x10,
+ OBJC_TQ_Oneway = 0x20
+ };
+
+private:
+ /// NextDeclInContext - The next declaration within the same lexical
+ /// DeclContext. These pointers form the linked list that is
+ /// traversed via DeclContext's decls_begin()/decls_end().
+ Decl *NextDeclInContext;
+
+ friend class DeclContext;
+
+ struct MultipleDC {
+ DeclContext *SemanticDC;
+ DeclContext *LexicalDC;
+ };
+
+
+ /// DeclCtx - Holds either a DeclContext* or a MultipleDC*.
+ /// For declarations that don't contain C++ scope specifiers, it contains
+ /// the DeclContext where the Decl was declared.
+ /// For declarations with C++ scope specifiers, it contains a MultipleDC*
+ /// with the context where it semantically belongs (SemanticDC) and the
+ /// context where it was lexically declared (LexicalDC).
+ /// e.g.:
+ ///
+ /// namespace A {
+ /// void f(); // SemanticDC == LexicalDC == 'namespace A'
+ /// }
+ /// void A::f(); // SemanticDC == namespace 'A'
+ /// // LexicalDC == global namespace
+ llvm::PointerUnion<DeclContext*, MultipleDC*> DeclCtx;
+
+ inline bool isInSemaDC() const { return DeclCtx.is<DeclContext*>(); }
+ inline bool isOutOfSemaDC() const { return DeclCtx.is<MultipleDC*>(); }
+ inline MultipleDC *getMultipleDC() const {
+ return DeclCtx.get<MultipleDC*>();
+ }
+ inline DeclContext *getSemanticDC() const {
+ return DeclCtx.get<DeclContext*>();
+ }
+
+ /// Loc - The location that this decl.
+ SourceLocation Loc;
+
+ /// DeclKind - This indicates which class this is.
+ Kind DeclKind : 8;
+
+ /// InvalidDecl - This indicates a semantic error occurred.
+ unsigned int InvalidDecl : 1;
+
+ /// HasAttrs - This indicates whether the decl has attributes or not.
+ unsigned int HasAttrs : 1;
+
+ /// Implicit - Whether this declaration was implicitly generated by
+ /// the implementation rather than explicitly written by the user.
+ bool Implicit : 1;
+
+ /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
+ unsigned IdentifierNamespace : 8;
+
+#ifndef NDEBUG
+ void CheckAccessDeclContext() const;
+#else
+ void CheckAccessDeclContext() const { }
+#endif
+
+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;
+
+ Decl(Kind DK, DeclContext *DC, SourceLocation L)
+ : NextDeclInContext(0), DeclCtx(DC),
+ Loc(L), DeclKind(DK), InvalidDecl(0),
+ HasAttrs(false), Implicit(false),
+ IdentifierNamespace(getIdentifierNamespaceForKind(DK)), Access(AS_none) {
+ if (Decl::CollectingStats()) addDeclKind(DK);
+ }
+
+ virtual ~Decl();
+
+public:
+ SourceLocation getLocation() const { return Loc; }
+ void setLocation(SourceLocation L) { Loc = L; }
+
+ Kind getKind() const { return DeclKind; }
+ const char *getDeclKindName() const;
+
+ Decl *getNextDeclInContext() { return NextDeclInContext; }
+ const Decl *getNextDeclInContext() const { return NextDeclInContext; }
+
+ DeclContext *getDeclContext() {
+ if (isInSemaDC())
+ return getSemanticDC();
+ return getMultipleDC()->SemanticDC;
+ }
+ const DeclContext *getDeclContext() const {
+ return const_cast<Decl*>(this)->getDeclContext();
+ }
+
+ void setAccess(AccessSpecifier AS) {
+ Access = AS;
+ CheckAccessDeclContext();
+ }
+
+ AccessSpecifier getAccess() const {
+ CheckAccessDeclContext();
+ return AccessSpecifier(Access);
+ }
+
+ bool hasAttrs() const { return HasAttrs; }
+ void addAttr(Attr *attr);
+ const Attr *getAttrs() const {
+ if (!HasAttrs) return 0; // common case, no attributes.
+ return getAttrsImpl(); // Uncommon case, out of line hash lookup.
+ }
+ void swapAttrs(Decl *D);
+ void invalidateAttrs();
+
+ template<typename T> const T *getAttr() const {
+ for (const Attr *attr = getAttrs(); attr; attr = attr->getNext())
+ if (const T *V = dyn_cast<T>(attr))
+ return V;
+ return 0;
+ }
+
+ template<typename T> bool hasAttr() const {
+ return getAttr<T>() != 0;
+ }
+
+ /// setInvalidDecl - Indicates the Decl had a semantic error. This
+ /// allows for graceful error recovery.
+ void setInvalidDecl(bool Invalid = true) { InvalidDecl = Invalid; }
+ bool isInvalidDecl() const { return (bool) InvalidDecl; }
+
+ /// isImplicit - Indicates whether the declaration was implicitly
+ /// generated by the implementation. If false, this declaration
+ /// was written explicitly in the source code.
+ bool isImplicit() const { return Implicit; }
+ void setImplicit(bool I = true) { Implicit = I; }
+
+ unsigned getIdentifierNamespace() const {
+ return IdentifierNamespace;
+ }
+ bool isInIdentifierNamespace(unsigned NS) const {
+ return getIdentifierNamespace() & NS;
+ }
+ static unsigned getIdentifierNamespaceForKind(Kind DK);
+
+
+ /// getLexicalDeclContext - The declaration context where this Decl was
+ /// lexically declared (LexicalDC). May be different from
+ /// getDeclContext() (SemanticDC).
+ /// e.g.:
+ ///
+ /// namespace A {
+ /// void f(); // SemanticDC == LexicalDC == 'namespace A'
+ /// }
+ /// void A::f(); // SemanticDC == namespace 'A'
+ /// // LexicalDC == global namespace
+ DeclContext *getLexicalDeclContext() {
+ if (isInSemaDC())
+ return getSemanticDC();
+ return getMultipleDC()->LexicalDC;
+ }
+ const DeclContext *getLexicalDeclContext() const {
+ return const_cast<Decl*>(this)->getLexicalDeclContext();
+ }
+
+ /// setDeclContext - Set both the semantic and lexical DeclContext
+ /// to DC.
+ void setDeclContext(DeclContext *DC);
+
+ void setLexicalDeclContext(DeclContext *DC);
+
+ // isDefinedOutsideFunctionOrMethod - This predicate returns true if this
+ // 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;
+
+ /// getBody - If this Decl represents a declaration for a body of code,
+ /// such as a function or method definition, this method returns the
+ /// top-level Stmt* of that body. Otherwise this method returns null.
+ virtual Stmt* getBody(ASTContext &Context) const { return 0; }
+
+ /// getCompoundBody - Returns getBody(), dyn_casted to a CompoundStmt.
+ CompoundStmt* getCompoundBody(ASTContext &Context) const;
+
+ /// getBodyRBrace - Gets the right brace of the body, if a body exists.
+ /// This works whether the body is a CompoundStmt or a CXXTryStmt.
+ SourceLocation getBodyRBrace(ASTContext &Context) const;
+
+ // global temp stats (until we have a per-module visitor)
+ static void addDeclKind(Kind k);
+ static bool CollectingStats(bool Enable = false);
+ static void PrintStats();
+
+ /// isTemplateParameter - Determines whether this declartion is a
+ /// template parameter.
+ bool isTemplateParameter() const;
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *) { return true; }
+ static DeclContext *castToDeclContext(const Decl *);
+ static Decl *castFromDeclContext(const DeclContext *);
+
+ /// Destroy - Call destructors and release memory.
+ virtual void Destroy(ASTContext& C);
+
+ void print(llvm::raw_ostream &Out, ASTContext &Context,
+ unsigned Indentation = 0);
+ void print(llvm::raw_ostream &Out, ASTContext &Context,
+ const PrintingPolicy &Policy, unsigned Indentation = 0);
+ static void printGroup(Decl** Begin, unsigned NumDecls,
+ llvm::raw_ostream &Out, ASTContext &Context,
+ const PrintingPolicy &Policy,
+ unsigned Indentation = 0);
+ void dump(ASTContext &Context);
+
+private:
+ const Attr *getAttrsImpl() const;
+
+};
+
+/// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when
+/// doing something to a specific decl.
+class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry {
+ Decl *TheDecl;
+ SourceLocation Loc;
+ SourceManager &SM;
+ const char *Message;
+public:
+ PrettyStackTraceDecl(Decl *theDecl, SourceLocation L,
+ SourceManager &sm, const char *Msg)
+ : TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {}
+
+ virtual void print(llvm::raw_ostream &OS) const;
+};
+
+
+/// DeclContext - This is used only as base class of specific decl types that
+/// can act as declaration contexts. These decls are (only the top classes
+/// that directly derive from DeclContext are mentioned, not their subclasses):
+///
+/// TranslationUnitDecl
+/// NamespaceDecl
+/// FunctionDecl
+/// TagDecl
+/// ObjCMethodDecl
+/// ObjCContainerDecl
+/// ObjCCategoryImplDecl
+/// ObjCImplementationDecl
+/// LinkageSpecDecl
+/// BlockDecl
+///
+class DeclContext {
+ /// DeclKind - This indicates which class this is.
+ Decl::Kind DeclKind : 8;
+
+ /// \brief Whether this declaration context also has some external
+ /// storage that contains additional declarations that are lexically
+ /// part of this context.
+ mutable bool ExternalLexicalStorage : 1;
+
+ /// \brief Whether this declaration context also has some external
+ /// storage that contains additional declarations that are visible
+ /// in this context.
+ mutable bool ExternalVisibleStorage : 1;
+
+ /// \brief Pointer to the data structure used to lookup declarations
+ /// within this context, which is a DenseMap<DeclarationName,
+ /// StoredDeclsList>.
+ mutable void* LookupPtr;
+
+ /// FirstDecl - The first declaration stored within this declaration
+ /// context.
+ mutable Decl *FirstDecl;
+
+ /// LastDecl - The last declaration stored within this declaration
+ /// context. FIXME: We could probably cache this value somewhere
+ /// outside of the DeclContext, to reduce the size of DeclContext by
+ /// another pointer.
+ mutable Decl *LastDecl;
+
+protected:
+ DeclContext(Decl::Kind K)
+ : DeclKind(K), ExternalLexicalStorage(false),
+ ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0),
+ LastDecl(0) { }
+
+ void DestroyDecls(ASTContext &C);
+
+public:
+ ~DeclContext();
+
+ Decl::Kind getDeclKind() const {
+ return DeclKind;
+ }
+ const char *getDeclKindName() const;
+
+ /// getParent - Returns the containing DeclContext.
+ DeclContext *getParent() {
+ return cast<Decl>(this)->getDeclContext();
+ }
+ const DeclContext *getParent() const {
+ return const_cast<DeclContext*>(this)->getParent();
+ }
+
+ /// getLexicalParent - Returns the containing lexical DeclContext. May be
+ /// different from getParent, e.g.:
+ ///
+ /// namespace A {
+ /// struct S;
+ /// }
+ /// struct A::S {}; // getParent() == namespace 'A'
+ /// // getLexicalParent() == translation unit
+ ///
+ DeclContext *getLexicalParent() {
+ return cast<Decl>(this)->getLexicalDeclContext();
+ }
+ const DeclContext *getLexicalParent() const {
+ return const_cast<DeclContext*>(this)->getLexicalParent();
+ }
+
+ bool isFunctionOrMethod() const {
+ switch (DeclKind) {
+ case Decl::Block:
+ case Decl::ObjCMethod:
+ return true;
+ default:
+ return DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast;
+ }
+ }
+
+ bool isFileContext() const {
+ return DeclKind == Decl::TranslationUnit || DeclKind == Decl::Namespace;
+ }
+
+ bool isTranslationUnit() const {
+ return DeclKind == Decl::TranslationUnit;
+ }
+
+ bool isRecord() const {
+ return DeclKind >= Decl::RecordFirst && DeclKind <= Decl::RecordLast;
+ }
+
+ bool isNamespace() const {
+ return DeclKind == Decl::Namespace;
+ }
+
+ /// \brief Determines whether this context is dependent on a
+ /// template parameter.
+ bool isDependentContext() const;
+
+ /// isTransparentContext - Determines whether this context is a
+ /// "transparent" context, meaning that the members declared in this
+ /// context are semantically declared in the nearest enclosing
+ /// non-transparent (opaque) context but are lexically declared in
+ /// this context. For example, consider the enumerators of an
+ /// enumeration type:
+ /// @code
+ /// enum E {
+ /// Val1
+ /// };
+ /// @endcode
+ /// Here, E is a transparent context, so its enumerator (Val1) will
+ /// appear (semantically) that it is in the same context of E.
+ /// Examples of transparent contexts include: enumerations (except for
+ /// C++0x scoped enums), C++ linkage specifications, and C++0x
+ /// inline namespaces.
+ bool isTransparentContext() const;
+
+ bool Encloses(DeclContext *DC) const {
+ for (; DC; DC = DC->getParent())
+ if (DC == this)
+ return true;
+ return false;
+ }
+
+ /// getPrimaryContext - There may be many different
+ /// declarations of the same entity (including forward declarations
+ /// of classes, multiple definitions of namespaces, etc.), each with
+ /// a different set of declarations. This routine returns the
+ /// "primary" DeclContext structure, which will contain the
+ /// information needed to perform name lookup into this context.
+ DeclContext *getPrimaryContext();
+
+ /// getLookupContext - Retrieve the innermost non-transparent
+ /// context of this context, which corresponds to the innermost
+ /// location from which name lookup can find the entities in this
+ /// context.
+ DeclContext *getLookupContext();
+ const DeclContext *getLookupContext() const {
+ return const_cast<DeclContext *>(this)->getLookupContext();
+ }
+
+ /// \brief Retrieve the nearest enclosing namespace context.
+ DeclContext *getEnclosingNamespaceContext();
+ const DeclContext *getEnclosingNamespaceContext() const {
+ return const_cast<DeclContext *>(this)->getEnclosingNamespaceContext();
+ }
+
+ /// getNextContext - If this is a DeclContext that may have other
+ /// DeclContexts that are semantically connected but syntactically
+ /// different, such as C++ namespaces, this routine retrieves the
+ /// next DeclContext in the link. Iteration through the chain of
+ /// DeclContexts should begin at the primary DeclContext and
+ /// continue until this function returns NULL. For example, given:
+ /// @code
+ /// namespace N {
+ /// int x;
+ /// }
+ /// namespace N {
+ /// int y;
+ /// }
+ /// @endcode
+ /// The first occurrence of namespace N will be the primary
+ /// DeclContext. Its getNextContext will return the second
+ /// occurrence of namespace N.
+ DeclContext *getNextContext();
+
+ /// decl_iterator - Iterates through the declarations stored
+ /// within this context.
+ class decl_iterator {
+ /// Current - The current declaration.
+ Decl *Current;
+
+ public:
+ typedef Decl* value_type;
+ typedef Decl* reference;
+ typedef Decl* pointer;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef std::ptrdiff_t difference_type;
+
+ decl_iterator() : Current(0) { }
+ explicit decl_iterator(Decl *C) : Current(C) { }
+
+ reference operator*() const { return Current; }
+ pointer operator->() const { return Current; }
+
+ decl_iterator& operator++() {
+ Current = Current->getNextDeclInContext();
+ return *this;
+ }
+
+ decl_iterator operator++(int) {
+ decl_iterator tmp(*this);
+ ++(*this);
+ return tmp;
+ }
+
+ friend bool operator==(decl_iterator x, decl_iterator y) {
+ return x.Current == y.Current;
+ }
+ friend bool operator!=(decl_iterator x, decl_iterator y) {
+ return x.Current != y.Current;
+ }
+ };
+
+ /// decls_begin/decls_end - Iterate over the declarations stored in
+ /// this context.
+ decl_iterator decls_begin(ASTContext &Context) const;
+ decl_iterator decls_end(ASTContext &Context) const;
+ bool decls_empty(ASTContext &Context) const;
+
+ /// specific_decl_iterator - Iterates over a subrange of
+ /// declarations stored in a DeclContext, providing only those that
+ /// are of type SpecificDecl (or a class derived from it). This
+ /// iterator is used, for example, to provide iteration over just
+ /// the fields within a RecordDecl (with SpecificDecl = FieldDecl).
+ template<typename SpecificDecl>
+ class specific_decl_iterator {
+ /// Current - The current, underlying declaration iterator, which
+ /// will either be NULL or will point to a declaration of
+ /// type SpecificDecl.
+ DeclContext::decl_iterator Current;
+
+ /// SkipToNextDecl - Advances the current position up to the next
+ /// declaration of type SpecificDecl that also meets the criteria
+ /// required by Acceptable.
+ void SkipToNextDecl() {
+ while (*Current && !isa<SpecificDecl>(*Current))
+ ++Current;
+ }
+
+ public:
+ typedef SpecificDecl* value_type;
+ typedef SpecificDecl* reference;
+ typedef SpecificDecl* pointer;
+ typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type
+ difference_type;
+ typedef std::forward_iterator_tag iterator_category;
+
+ specific_decl_iterator() : Current() { }
+
+ /// specific_decl_iterator - Construct a new iterator over a
+ /// subset of the declarations the range [C,
+ /// end-of-declarations). If A is non-NULL, it is a pointer to a
+ /// member function of SpecificDecl that should return true for
+ /// all of the SpecificDecl instances that will be in the subset
+ /// of iterators. For example, if you want Objective-C instance
+ /// methods, SpecificDecl will be ObjCMethodDecl and A will be
+ /// &ObjCMethodDecl::isInstanceMethod.
+ explicit specific_decl_iterator(DeclContext::decl_iterator C) : Current(C) {
+ SkipToNextDecl();
+ }
+
+ reference operator*() const { return cast<SpecificDecl>(*Current); }
+ pointer operator->() const { return cast<SpecificDecl>(*Current); }
+
+ specific_decl_iterator& operator++() {
+ ++Current;
+ SkipToNextDecl();
+ return *this;
+ }
+
+ specific_decl_iterator operator++(int) {
+ specific_decl_iterator tmp(*this);
+ ++(*this);
+ return tmp;
+ }
+
+ friend bool
+ operator==(const specific_decl_iterator& x, const specific_decl_iterator& y) {
+ return x.Current == y.Current;
+ }
+
+ friend bool
+ operator!=(const specific_decl_iterator& x, const specific_decl_iterator& y) {
+ return x.Current != y.Current;
+ }
+ };
+
+ /// \brief Iterates over a filtered subrange of declarations stored
+ /// in a DeclContext.
+ ///
+ /// This iterator visits only those declarations that are of type
+ /// SpecificDecl (or a class derived from it) and that meet some
+ /// additional run-time criteria. This iterator is used, for
+ /// example, to provide access to the instance methods within an
+ /// Objective-C interface (with SpecificDecl = ObjCMethodDecl and
+ /// Acceptable = ObjCMethodDecl::isInstanceMethod).
+ template<typename SpecificDecl, bool (SpecificDecl::*Acceptable)() const>
+ class filtered_decl_iterator {
+ /// Current - The current, underlying declaration iterator, which
+ /// will either be NULL or will point to a declaration of
+ /// type SpecificDecl.
+ DeclContext::decl_iterator Current;
+
+ /// SkipToNextDecl - Advances the current position up to the next
+ /// declaration of type SpecificDecl that also meets the criteria
+ /// required by Acceptable.
+ void SkipToNextDecl() {
+ while (*Current &&
+ (!isa<SpecificDecl>(*Current) ||
+ (Acceptable && !(cast<SpecificDecl>(*Current)->*Acceptable)())))
+ ++Current;
+ }
+
+ public:
+ typedef SpecificDecl* value_type;
+ typedef SpecificDecl* reference;
+ typedef SpecificDecl* pointer;
+ typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type
+ difference_type;
+ typedef std::forward_iterator_tag iterator_category;
+
+ filtered_decl_iterator() : Current() { }
+
+ /// specific_decl_iterator - Construct a new iterator over a
+ /// subset of the declarations the range [C,
+ /// end-of-declarations). If A is non-NULL, it is a pointer to a
+ /// member function of SpecificDecl that should return true for
+ /// all of the SpecificDecl instances that will be in the subset
+ /// of iterators. For example, if you want Objective-C instance
+ /// methods, SpecificDecl will be ObjCMethodDecl and A will be
+ /// &ObjCMethodDecl::isInstanceMethod.
+ explicit filtered_decl_iterator(DeclContext::decl_iterator C) : Current(C) {
+ SkipToNextDecl();
+ }
+
+ reference operator*() const { return cast<SpecificDecl>(*Current); }
+ pointer operator->() const { return cast<SpecificDecl>(*Current); }
+
+ filtered_decl_iterator& operator++() {
+ ++Current;
+ SkipToNextDecl();
+ return *this;
+ }
+
+ filtered_decl_iterator operator++(int) {
+ filtered_decl_iterator tmp(*this);
+ ++(*this);
+ return tmp;
+ }
+
+ friend bool
+ operator==(const filtered_decl_iterator& x, const filtered_decl_iterator& y) {
+ return x.Current == y.Current;
+ }
+
+ friend bool
+ operator!=(const filtered_decl_iterator& x, const filtered_decl_iterator& y) {
+ return x.Current != y.Current;
+ }
+ };
+
+ /// @brief Add the declaration D into this context.
+ ///
+ /// This routine should be invoked when the declaration D has first
+ /// been declared, to place D into the context where it was
+ /// (lexically) defined. Every declaration must be added to one
+ /// (and only one!) context, where it can be visited via
+ /// [decls_begin(), decls_end()). Once a declaration has been added
+ /// to its lexical context, the corresponding DeclContext owns the
+ /// declaration.
+ ///
+ /// If D is also a NamedDecl, it will be made visible within its
+ /// semantic context via makeDeclVisibleInContext.
+ void addDecl(ASTContext &Context, Decl *D);
+
+ /// lookup_iterator - An iterator that provides access to the results
+ /// of looking up a name within this context.
+ typedef NamedDecl **lookup_iterator;
+
+ /// lookup_const_iterator - An iterator that provides non-mutable
+ /// access to the results of lookup up a name within this context.
+ typedef NamedDecl * const * lookup_const_iterator;
+
+ typedef std::pair<lookup_iterator, lookup_iterator> lookup_result;
+ typedef std::pair<lookup_const_iterator, lookup_const_iterator>
+ lookup_const_result;
+
+ /// lookup - Find the declarations (if any) with the given Name in
+ /// this context. Returns a range of iterators that contains all of
+ /// the declarations with this name, with object, function, member,
+ /// and enumerator names preceding any tag name. Note that this
+ /// routine will not look into parent contexts.
+ lookup_result lookup(ASTContext &Context, DeclarationName Name);
+ lookup_const_result lookup(ASTContext &Context, DeclarationName Name) const;
+
+ /// @brief Makes a declaration visible within this context.
+ ///
+ /// This routine makes the declaration D visible to name lookup
+ /// within this context and, if this is a transparent context,
+ /// within its parent contexts up to the first enclosing
+ /// non-transparent context. Making a declaration visible within a
+ /// context does not transfer ownership of a declaration, and a
+ /// declaration can be visible in many contexts that aren't its
+ /// lexical context.
+ ///
+ /// If D is a redeclaration of an existing declaration that is
+ /// visible from this context, as determined by
+ /// NamedDecl::declarationReplaces, the previous declaration will be
+ /// replaced with D.
+ void makeDeclVisibleInContext(ASTContext &Context, NamedDecl *D);
+
+ /// udir_iterator - Iterates through the using-directives stored
+ /// within this context.
+ typedef UsingDirectiveDecl * const * udir_iterator;
+
+ typedef std::pair<udir_iterator, udir_iterator> udir_iterator_range;
+
+ udir_iterator_range getUsingDirectives(ASTContext &Context) const;
+
+ udir_iterator using_directives_begin(ASTContext &Context) const {
+ return getUsingDirectives(Context).first;
+ }
+
+ udir_iterator using_directives_end(ASTContext &Context) const {
+ return getUsingDirectives(Context).second;
+ }
+
+ // Low-level accessors
+
+ /// \brief Retrieve the internal representation of the lookup structure.
+ void* getLookupPtr() const { return LookupPtr; }
+
+ /// \brief Whether this DeclContext has external storage containing
+ /// additional declarations that are lexically in this context.
+ bool hasExternalLexicalStorage() const { return ExternalLexicalStorage; }
+
+ /// \brief State whether this DeclContext has external storage for
+ /// declarations lexically in this context.
+ void setHasExternalLexicalStorage(bool ES = true) {
+ ExternalLexicalStorage = ES;
+ }
+
+ /// \brief Whether this DeclContext has external storage containing
+ /// additional declarations that are visible in this context.
+ bool hasExternalVisibleStorage() const { return ExternalVisibleStorage; }
+
+ /// \brief State whether this DeclContext has external storage for
+ /// declarations visible in this context.
+ void setHasExternalVisibleStorage(bool ES = true) {
+ ExternalVisibleStorage = ES;
+ }
+
+ static bool classof(const Decl *D);
+ static bool classof(const DeclContext *D) { return true; }
+#define DECL_CONTEXT(Name) \
+ static bool classof(const Name##Decl *D) { return true; }
+#include "clang/AST/DeclNodes.def"
+
+private:
+ void LoadLexicalDeclsFromExternalStorage(ASTContext &Context) const;
+ void LoadVisibleDeclsFromExternalStorage(ASTContext &Context) const;
+
+ void buildLookup(ASTContext &Context, DeclContext *DCtx);
+ void makeDeclVisibleInContextImpl(ASTContext &Context, NamedDecl *D);
+};
+
+inline bool Decl::isTemplateParameter() const {
+ return getKind() == TemplateTypeParm || getKind() == NonTypeTemplateParm;
+}
+
+inline bool Decl::isDefinedOutsideFunctionOrMethod() const {
+ if (getDeclContext())
+ return !getDeclContext()->getLookupContext()->isFunctionOrMethod();
+ return true;
+}
+
+} // end clang.
+
+namespace llvm {
+
+/// Implement a isa_impl_wrap specialization to check whether a DeclContext is
+/// a specific Decl.
+template<class ToTy>
+struct isa_impl_wrap<ToTy,
+ const ::clang::DeclContext,const ::clang::DeclContext> {
+ static bool doit(const ::clang::DeclContext &Val) {
+ return ToTy::classof(::clang::Decl::castFromDeclContext(&Val));
+ }
+};
+template<class ToTy>
+struct isa_impl_wrap<ToTy, ::clang::DeclContext, ::clang::DeclContext>
+ : public isa_impl_wrap<ToTy,
+ const ::clang::DeclContext,const ::clang::DeclContext> {};
+
+/// Implement cast_convert_val for Decl -> DeclContext conversions.
+template<class FromTy>
+struct cast_convert_val< ::clang::DeclContext, FromTy, FromTy> {
+ static ::clang::DeclContext &doit(const FromTy &Val) {
+ return *FromTy::castToDeclContext(&Val);
+ }
+};
+
+template<class FromTy>
+struct cast_convert_val< ::clang::DeclContext, FromTy*, FromTy*> {
+ static ::clang::DeclContext *doit(const FromTy *Val) {
+ return FromTy::castToDeclContext(Val);
+ }
+};
+
+template<class FromTy>
+struct cast_convert_val< const ::clang::DeclContext, FromTy, FromTy> {
+ static const ::clang::DeclContext &doit(const FromTy &Val) {
+ return *FromTy::castToDeclContext(&Val);
+ }
+};
+
+template<class FromTy>
+struct cast_convert_val< const ::clang::DeclContext, FromTy*, FromTy*> {
+ static const ::clang::DeclContext *doit(const FromTy *Val) {
+ return FromTy::castToDeclContext(Val);
+ }
+};
+
+/// Implement cast_convert_val for DeclContext -> Decl conversions.
+template<class ToTy>
+struct cast_convert_val<ToTy,
+ const ::clang::DeclContext,const ::clang::DeclContext> {
+ static ToTy &doit(const ::clang::DeclContext &Val) {
+ return *reinterpret_cast<ToTy*>(ToTy::castFromDeclContext(&Val));
+ }
+};
+template<class ToTy>
+struct cast_convert_val<ToTy, ::clang::DeclContext, ::clang::DeclContext>
+ : public cast_convert_val<ToTy,
+ const ::clang::DeclContext,const ::clang::DeclContext> {};
+
+template<class ToTy>
+struct cast_convert_val<ToTy,
+ const ::clang::DeclContext*, const ::clang::DeclContext*> {
+ static ToTy *doit(const ::clang::DeclContext *Val) {
+ return reinterpret_cast<ToTy*>(ToTy::castFromDeclContext(Val));
+ }
+};
+template<class ToTy>
+struct cast_convert_val<ToTy, ::clang::DeclContext*, ::clang::DeclContext*>
+ : public cast_convert_val<ToTy,
+ const ::clang::DeclContext*,const ::clang::DeclContext*> {};
+
+} // end namespace llvm
+
+#endif
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
new file mode 100644
index 000000000000..4a74a2c2cbc4
--- /dev/null
+++ b/include/clang/AST/DeclCXX.h
@@ -0,0 +1,1073 @@
+//===-- DeclCXX.h - Classes for representing C++ 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 C++ Decl subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_DECLCXX_H
+#define LLVM_CLANG_AST_DECLCXX_H
+
+#include "clang/AST/Decl.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+
+class ClassTemplateDecl;
+class CXXRecordDecl;
+class CXXConstructorDecl;
+class CXXDestructorDecl;
+class CXXConversionDecl;
+class CXXMethodDecl;
+class ClassTemplateSpecializationDecl;
+
+/// OverloadedFunctionDecl - An instance of this class represents a
+/// set of overloaded functions. All of the functions have the same
+/// name and occur within the same scope.
+///
+/// An OverloadedFunctionDecl has no ownership over the FunctionDecl
+/// nodes it contains. Rather, the FunctionDecls are owned by the
+/// enclosing scope (which also owns the OverloadedFunctionDecl
+/// node). OverloadedFunctionDecl is used primarily to store a set of
+/// overloaded functions for name lookup.
+class OverloadedFunctionDecl : public NamedDecl {
+protected:
+ OverloadedFunctionDecl(DeclContext *DC, DeclarationName N)
+ : NamedDecl(OverloadedFunction, DC, SourceLocation(), N) { }
+
+ /// Functions - the set of overloaded functions contained in this
+ /// overload set.
+ llvm::SmallVector<FunctionDecl *, 4> Functions;
+
+ // FIXME: This should go away when we stop using
+ // OverloadedFunctionDecl to store conversions in CXXRecordDecl.
+ friend class CXXRecordDecl;
+
+public:
+ typedef llvm::SmallVector<FunctionDecl *, 4>::iterator function_iterator;
+ typedef llvm::SmallVector<FunctionDecl *, 4>::const_iterator
+ function_const_iterator;
+
+ static OverloadedFunctionDecl *Create(ASTContext &C, DeclContext *DC,
+ DeclarationName N);
+
+ /// addOverload - Add an overloaded function FD to this set of
+ /// overloaded functions.
+ void addOverload(FunctionDecl *FD) {
+ assert((FD->getDeclName() == getDeclName() ||
+ isa<CXXConversionDecl>(FD) || isa<CXXConstructorDecl>(FD)) &&
+ "Overloaded functions must have the same name");
+ Functions.push_back(FD);
+
+ // An overloaded function declaration always has the location of
+ // the most-recently-added function declaration.
+ if (FD->getLocation().isValid())
+ this->setLocation(FD->getLocation());
+ }
+
+ function_iterator function_begin() { return Functions.begin(); }
+ function_iterator function_end() { return Functions.end(); }
+ function_const_iterator function_begin() const { return Functions.begin(); }
+ function_const_iterator function_end() const { return Functions.end(); }
+
+ /// getNumFunctions - the number of overloaded functions stored in
+ /// this set.
+ unsigned getNumFunctions() const { return Functions.size(); }
+
+ /// getFunction - retrieve the ith function in the overload set.
+ const FunctionDecl *getFunction(unsigned i) const {
+ assert(i < getNumFunctions() && "Illegal function #");
+ return Functions[i];
+ }
+ FunctionDecl *getFunction(unsigned i) {
+ assert(i < getNumFunctions() && "Illegal function #");
+ return Functions[i];
+ }
+
+ // getDeclContext - Get the context of these overloaded functions.
+ DeclContext *getDeclContext() {
+ assert(getNumFunctions() > 0 && "Context of an empty overload set");
+ return getFunction(0)->getDeclContext();
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() == OverloadedFunction;
+ }
+ static bool classof(const OverloadedFunctionDecl *D) { return true; }
+};
+
+/// CXXBaseSpecifier - A base class of a C++ class.
+///
+/// Each CXXBaseSpecifier represents a single, direct base class (or
+/// struct) of a C++ class (or struct). It specifies the type of that
+/// base class, whether it is a virtual or non-virtual base, and what
+/// level of access (public, protected, private) is used for the
+/// derivation. For example:
+///
+/// @code
+/// class A { };
+/// class B { };
+/// class C : public virtual A, protected B { };
+/// @endcode
+///
+/// In this code, C will have two CXXBaseSpecifiers, one for "public
+/// virtual A" and the other for "protected B".
+class CXXBaseSpecifier {
+ /// Range - The source code range that covers the full base
+ /// specifier, including the "virtual" (if present) and access
+ /// specifier (if present).
+ SourceRange Range;
+
+ /// Virtual - Whether this is a virtual base class or not.
+ bool Virtual : 1;
+
+ /// BaseOfClass - Whether this is the base of a class (true) or of a
+ /// struct (false). This determines the mapping from the access
+ /// specifier as written in the source code to the access specifier
+ /// used for semantic analysis.
+ bool BaseOfClass : 1;
+
+ /// Access - Access specifier as written in the source code (which
+ /// may be AS_none). The actual type of data stored here is an
+ /// AccessSpecifier, but we use "unsigned" here to work around a
+ /// VC++ bug.
+ unsigned Access : 2;
+
+ /// BaseType - The type of the base class. This will be a class or
+ /// struct (or a typedef of such).
+ QualType BaseType;
+
+public:
+ CXXBaseSpecifier() { }
+
+ CXXBaseSpecifier(SourceRange R, bool V, bool BC, AccessSpecifier A, QualType T)
+ : Range(R), Virtual(V), BaseOfClass(BC), Access(A), BaseType(T) { }
+
+ /// getSourceRange - Retrieves the source range that contains the
+ /// entire base specifier.
+ SourceRange getSourceRange() const { return Range; }
+
+ /// isVirtual - Determines whether the base class is a virtual base
+ /// class (or not).
+ bool isVirtual() const { return Virtual; }
+
+ /// getAccessSpecifier - Returns the access specifier for this base
+ /// specifier. This is the actual base specifier as used for
+ /// semantic analysis, so the result can never be AS_none. To
+ /// retrieve the access specifier as written in the source code, use
+ /// getAccessSpecifierAsWritten().
+ AccessSpecifier getAccessSpecifier() const {
+ if ((AccessSpecifier)Access == AS_none)
+ return BaseOfClass? AS_private : AS_public;
+ else
+ return (AccessSpecifier)Access;
+ }
+
+ /// getAccessSpecifierAsWritten - Retrieves the access specifier as
+ /// written in the source code (which may mean that no access
+ /// specifier was explicitly written). Use getAccessSpecifier() to
+ /// retrieve the access specifier for use in semantic analysis.
+ AccessSpecifier getAccessSpecifierAsWritten() const {
+ return (AccessSpecifier)Access;
+ }
+
+ /// getType - Retrieves the type of the base class. This type will
+ /// always be an unqualified class type.
+ QualType getType() const { return BaseType; }
+};
+
+/// CXXRecordDecl - Represents a C++ struct/union/class.
+/// FIXME: This class will disappear once we've properly taught RecordDecl
+/// to deal with C++-specific things.
+class CXXRecordDecl : public RecordDecl {
+ /// UserDeclaredConstructor - True when this class has a
+ /// user-declared constructor.
+ bool UserDeclaredConstructor : 1;
+
+ /// UserDeclaredCopyConstructor - True when this class has a
+ /// user-declared copy constructor.
+ bool UserDeclaredCopyConstructor : 1;
+
+ /// UserDeclaredCopyAssignment - True when this class has a
+ /// user-declared copy assignment operator.
+ bool UserDeclaredCopyAssignment : 1;
+
+ /// UserDeclaredDestructor - True when this class has a
+ /// user-declared destructor.
+ bool UserDeclaredDestructor : 1;
+
+ /// Aggregate - True when this class is an aggregate.
+ bool Aggregate : 1;
+
+ /// PlainOldData - True when this class is a POD-type.
+ bool PlainOldData : 1;
+
+ /// Polymorphic - True when this class is polymorphic, i.e. has at least one
+ /// virtual member or derives from a polymorphic class.
+ bool Polymorphic : 1;
+
+ /// Abstract - True when this class is abstract, i.e. has at least one
+ /// pure virtual function, (that can come from a base class).
+ bool Abstract : 1;
+
+ /// HasTrivialConstructor - True when this class has a trivial constructor
+ bool HasTrivialConstructor : 1;
+
+ /// HasTrivialDestructor - True when this class has a trivial destructor
+ bool HasTrivialDestructor : 1;
+
+ /// Bases - Base classes of this class.
+ /// FIXME: This is wasted space for a union.
+ CXXBaseSpecifier *Bases;
+
+ /// NumBases - The number of base class specifiers in Bases.
+ unsigned NumBases;
+
+ /// Conversions - Overload set containing the conversion functions
+ /// of this C++ class (but not its inherited conversion
+ /// functions). Each of the entries in this overload set is a
+ /// CXXConversionDecl.
+ OverloadedFunctionDecl Conversions;
+
+ /// \brief The template or declaration that this declaration
+ /// describes or was instantiated from, respectively.
+ ///
+ /// For non-templates, this value will be NULL. For record
+ /// declarations that describe a class template, this will be a
+ /// pointer to a ClassTemplateDecl. For member
+ /// classes of class template specializations, this will be the
+ /// RecordDecl from which the member class was instantiated.
+ llvm::PointerUnion<ClassTemplateDecl*, CXXRecordDecl*>
+ TemplateOrInstantiation;
+
+protected:
+ CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id);
+
+ ~CXXRecordDecl();
+
+public:
+ /// base_class_iterator - Iterator that traverses the base classes
+ /// of a clas.
+ typedef CXXBaseSpecifier* base_class_iterator;
+
+ /// base_class_const_iterator - Iterator that traverses the base
+ /// classes of a clas.
+ typedef const CXXBaseSpecifier* base_class_const_iterator;
+
+ static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ CXXRecordDecl* PrevDecl=0,
+ bool DelayTypeCreation = false);
+
+ /// setBases - Sets the base classes of this struct or class.
+ void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases);
+
+ /// getNumBases - Retrieves the number of base classes of this
+ /// class.
+ unsigned getNumBases() const { return NumBases; }
+
+ base_class_iterator bases_begin() { return Bases; }
+ base_class_const_iterator bases_begin() const { return Bases; }
+ base_class_iterator bases_end() { return Bases + NumBases; }
+ base_class_const_iterator bases_end() const { return Bases + NumBases; }
+
+ /// hasConstCopyConstructor - Determines whether this class has a
+ /// copy constructor that accepts a const-qualified argument.
+ bool hasConstCopyConstructor(ASTContext &Context) const;
+
+ /// hasConstCopyAssignment - Determines whether this class has a
+ /// copy assignment operator that accepts a const-qualified argument.
+ bool hasConstCopyAssignment(ASTContext &Context) const;
+
+ /// addedConstructor - Notify the class that another constructor has
+ /// been added. This routine helps maintain information about the
+ /// class based on which constructors have been added.
+ void addedConstructor(ASTContext &Context, CXXConstructorDecl *ConDecl);
+
+ /// hasUserDeclaredConstructor - Whether this class has any
+ /// user-declared constructors. When true, a default constructor
+ /// will not be implicitly declared.
+ bool hasUserDeclaredConstructor() const { return UserDeclaredConstructor; }
+
+ /// hasUserDeclaredCopyConstructor - Whether this class has a
+ /// user-declared copy constructor. When false, a copy constructor
+ /// will be implicitly declared.
+ bool hasUserDeclaredCopyConstructor() const {
+ return UserDeclaredCopyConstructor;
+ }
+
+ /// addedAssignmentOperator - Notify the class that another assignment
+ /// operator has been added. This routine helps maintain information about the
+ /// class based on which operators have been added.
+ void addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl);
+
+ /// hasUserDeclaredCopyAssignment - Whether this class has a
+ /// user-declared copy assignment operator. When false, a copy
+ /// assigment operator will be implicitly declared.
+ bool hasUserDeclaredCopyAssignment() const {
+ return UserDeclaredCopyAssignment;
+ }
+
+ /// hasUserDeclaredDestructor - Whether this class has a
+ /// user-declared destructor. When false, a destructor will be
+ /// implicitly declared.
+ bool hasUserDeclaredDestructor() const { return UserDeclaredDestructor; }
+
+ /// setUserDeclaredDestructor - Set whether this class has a
+ /// user-declared destructor. If not set by the time the class is
+ /// fully defined, a destructor will be implicitly declared.
+ void setUserDeclaredDestructor(bool UCD) {
+ UserDeclaredDestructor = UCD;
+ }
+
+ /// getConversions - Retrieve the overload set containing all of the
+ /// conversion functions in this class.
+ OverloadedFunctionDecl *getConversionFunctions() {
+ return &Conversions;
+ }
+ const OverloadedFunctionDecl *getConversionFunctions() const {
+ return &Conversions;
+ }
+
+ /// addConversionFunction - Add a new conversion function to the
+ /// list of conversion functions.
+ void addConversionFunction(ASTContext &Context, CXXConversionDecl *ConvDecl);
+
+ /// isAggregate - Whether this class is an aggregate (C++
+ /// [dcl.init.aggr]), which is a class with no user-declared
+ /// constructors, no private or protected non-static data members,
+ /// no base classes, and no virtual functions (C++ [dcl.init.aggr]p1).
+ bool isAggregate() const { return Aggregate; }
+
+ /// setAggregate - Set whether this class is an aggregate (C++
+ /// [dcl.init.aggr]).
+ void setAggregate(bool Agg) { Aggregate = Agg; }
+
+ /// isPOD - Whether this class is a POD-type (C++ [class]p4), which is a class
+ /// that is an aggregate that has no non-static non-POD data members, no
+ /// reference data members, no user-defined copy assignment operator and no
+ /// user-defined destructor.
+ bool isPOD() const { return PlainOldData; }
+
+ /// setPOD - Set whether this class is a POD-type (C++ [class]p4).
+ void setPOD(bool POD) { PlainOldData = POD; }
+
+ /// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]),
+ /// which means that the class contains or inherits a virtual function.
+ bool isPolymorphic() const { return Polymorphic; }
+
+ /// setPolymorphic - Set whether this class is polymorphic (C++
+ /// [class.virtual]).
+ void setPolymorphic(bool Poly) { Polymorphic = Poly; }
+
+ /// isAbstract - Whether this class is abstract (C++ [class.abstract]),
+ /// which means that the class contains or inherits a pure virtual function.
+ bool isAbstract() const { return Abstract; }
+
+ /// setAbstract - Set whether this class is abstract (C++ [class.abstract])
+ void setAbstract(bool Abs) { Abstract = Abs; }
+
+ // hasTrivialConstructor - Whether this class has a trivial constructor
+ // (C++ [class.ctor]p5)
+ bool hasTrivialConstructor() const { return HasTrivialConstructor; }
+
+ // setHasTrivialConstructor - Set whether this class has a trivial constructor
+ // (C++ [class.ctor]p5)
+ void setHasTrivialConstructor(bool TC) { HasTrivialConstructor = TC; }
+
+ // hasTrivialDestructor - Whether this class has a trivial destructor
+ // (C++ [class.dtor]p3)
+ bool hasTrivialDestructor() const { return HasTrivialDestructor; }
+
+ // setHasTrivialDestructor - Set whether this class has a trivial destructor
+ // (C++ [class.dtor]p3)
+ void setHasTrivialDestructor(bool TC) { HasTrivialDestructor = TC; }
+
+ /// \brief If this record is an instantiation of a member class,
+ /// retrieves the member class from which it was instantiated.
+ ///
+ /// This routine will return non-NULL for (non-templated) member
+ /// classes of class templates. For example, given:
+ ///
+ /// \code
+ /// template<typename T>
+ /// struct X {
+ /// struct A { };
+ /// };
+ /// \endcode
+ ///
+ /// The declaration for X<int>::A is a (non-templated) CXXRecordDecl
+ /// whose parent is the class template specialization X<int>. For
+ /// this declaration, getInstantiatedFromMemberClass() will return
+ /// the CXXRecordDecl X<T>::A. When a complete definition of
+ /// X<int>::A is required, it will be instantiated from the
+ /// declaration returned by getInstantiatedFromMemberClass().
+ CXXRecordDecl *getInstantiatedFromMemberClass() const {
+ return TemplateOrInstantiation.dyn_cast<CXXRecordDecl*>();
+ }
+
+ /// \brief Specify that this record is an instantiation of the
+ /// member class RD.
+ void setInstantiationOfMemberClass(CXXRecordDecl *RD) {
+ TemplateOrInstantiation = RD;
+ }
+
+ /// \brief Retrieves the class template that is described by this
+ /// class declaration.
+ ///
+ /// Every class template is represented as a ClassTemplateDecl and a
+ /// CXXRecordDecl. The former contains template properties (such as
+ /// the template parameter lists) while the latter contains the
+ /// actual description of the template's
+ /// contents. ClassTemplateDecl::getTemplatedDecl() retrieves the
+ /// CXXRecordDecl that from a ClassTemplateDecl, while
+ /// getDescribedClassTemplate() retrieves the ClassTemplateDecl from
+ /// a CXXRecordDecl.
+ ClassTemplateDecl *getDescribedClassTemplate() const {
+ return TemplateOrInstantiation.dyn_cast<ClassTemplateDecl*>();
+ }
+
+ void setDescribedClassTemplate(ClassTemplateDecl *Template) {
+ TemplateOrInstantiation = Template;
+ }
+
+ /// getDestructor - Returns the destructor decl for this class.
+ const CXXDestructorDecl *getDestructor(ASTContext &Context);
+
+ /// viewInheritance - Renders and displays an inheritance diagram
+ /// for this C++ class and all of its base classes (transitively) using
+ /// GraphViz.
+ void viewInheritance(ASTContext& Context) const;
+
+ static bool classof(const Decl *D) {
+ return D->getKind() == CXXRecord ||
+ D->getKind() == ClassTemplateSpecialization ||
+ D->getKind() == ClassTemplatePartialSpecialization;
+ }
+ static bool classof(const CXXRecordDecl *D) { return true; }
+ static bool classof(const ClassTemplateSpecializationDecl *D) {
+ return true;
+ }
+};
+
+/// CXXMethodDecl - Represents a static or instance method of a
+/// struct/union/class.
+class CXXMethodDecl : public FunctionDecl {
+protected:
+ CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation L,
+ DeclarationName N, QualType T,
+ bool isStatic, bool isInline)
+ : FunctionDecl(DK, RD, L, N, T, (isStatic ? Static : None),
+ isInline) {}
+
+public:
+ static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation L, DeclarationName N,
+ QualType T, bool isStatic = false,
+ bool isInline = false);
+
+ bool isStatic() const { return getStorageClass() == Static; }
+ bool isInstance() const { return !isStatic(); }
+
+ bool isOutOfLineDefinition() const {
+ return getLexicalDeclContext() != getDeclContext();
+ }
+
+ bool isVirtual() const {
+ return isVirtualAsWritten() ||
+ (begin_overridden_methods() != end_overridden_methods());
+ }
+
+ ///
+ void addOverriddenMethod(const CXXMethodDecl *MD);
+
+ typedef const CXXMethodDecl ** method_iterator;
+
+ method_iterator begin_overridden_methods() const;
+ method_iterator end_overridden_methods() const;
+
+ /// getParent - Returns the parent of this method declaration, which
+ /// is the class in which this method is defined.
+ const CXXRecordDecl *getParent() const {
+ return cast<CXXRecordDecl>(FunctionDecl::getParent());
+ }
+
+ /// getParent - Returns the parent of this method declaration, which
+ /// is the class in which this method is defined.
+ CXXRecordDecl *getParent() {
+ return const_cast<CXXRecordDecl *>(
+ cast<CXXRecordDecl>(FunctionDecl::getParent()));
+ }
+
+ /// getThisType - Returns the type of 'this' pointer.
+ /// Should only be called for instance methods.
+ QualType getThisType(ASTContext &C) const;
+
+ unsigned getTypeQualifiers() const {
+ return getType()->getAsFunctionProtoType()->getTypeQuals();
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() >= CXXMethod && D->getKind() <= CXXConversion;
+ }
+ static bool classof(const CXXMethodDecl *D) { return true; }
+};
+
+/// CXXBaseOrMemberInitializer - Represents a C++ base or member
+/// initializer, which is part of a constructor initializer that
+/// initializes one non-static member variable or one base class. For
+/// example, in the following, both 'A(a)' and 'f(3.14159)' are member
+/// initializers:
+///
+/// @code
+/// class A { };
+/// class B : public A {
+/// float f;
+/// public:
+/// B(A& a) : A(a), f(3.14159) { }
+/// };
+class CXXBaseOrMemberInitializer {
+ /// BaseOrMember - This points to the entity being initialized,
+ /// which is either a base class (a Type) or a non-static data
+ /// member. When the low bit is 1, it's a base
+ /// class; when the low bit is 0, it's a member.
+ uintptr_t BaseOrMember;
+
+ /// Args - The arguments used to initialize the base or member.
+ Expr **Args;
+ unsigned NumArgs;
+
+public:
+ /// CXXBaseOrMemberInitializer - Creates a new base-class initializer.
+ explicit
+ CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs);
+
+ /// CXXBaseOrMemberInitializer - Creates a new member initializer.
+ explicit
+ CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs);
+
+ /// ~CXXBaseOrMemberInitializer - Destroy the base or member initializer.
+ ~CXXBaseOrMemberInitializer();
+
+ /// arg_iterator - Iterates through the member initialization
+ /// arguments.
+ typedef Expr **arg_iterator;
+
+ /// arg_const_iterator - Iterates through the member initialization
+ /// arguments.
+ typedef Expr * const * arg_const_iterator;
+
+ /// isBaseInitializer - Returns true when this initializer is
+ /// initializing a base class.
+ bool isBaseInitializer() const { return (BaseOrMember & 0x1) != 0; }
+
+ /// isMemberInitializer - Returns true when this initializer is
+ /// initializing a non-static data member.
+ bool isMemberInitializer() const { return (BaseOrMember & 0x1) == 0; }
+
+ /// getBaseClass - If this is a base class initializer, returns the
+ /// type used to specify the initializer. The resulting type will be
+ /// a class type or a typedef of a class type. If this is not a base
+ /// class initializer, returns NULL.
+ Type *getBaseClass() {
+ if (isBaseInitializer())
+ return reinterpret_cast<Type*>(BaseOrMember & ~0x01);
+ else
+ return 0;
+ }
+
+ /// getBaseClass - If this is a base class initializer, returns the
+ /// type used to specify the initializer. The resulting type will be
+ /// a class type or a typedef of a class type. If this is not a base
+ /// class initializer, returns NULL.
+ const Type *getBaseClass() const {
+ if (isBaseInitializer())
+ return reinterpret_cast<const Type*>(BaseOrMember & ~0x01);
+ else
+ return 0;
+ }
+
+ /// getMember - If this is a member initializer, returns the
+ /// declaration of the non-static data member being
+ /// initialized. Otherwise, returns NULL.
+ FieldDecl *getMember() {
+ if (isMemberInitializer())
+ return reinterpret_cast<FieldDecl *>(BaseOrMember);
+ else
+ return 0;
+ }
+
+ /// begin() - Retrieve an iterator to the first initializer argument.
+ arg_iterator begin() { return Args; }
+ /// begin() - Retrieve an iterator to the first initializer argument.
+ arg_const_iterator begin() const { return Args; }
+
+ /// end() - Retrieve an iterator past the last initializer argument.
+ arg_iterator end() { return Args + NumArgs; }
+ /// end() - Retrieve an iterator past the last initializer argument.
+ arg_const_iterator end() const { return Args + NumArgs; }
+
+ /// getNumArgs - Determine the number of arguments used to
+ /// initialize the member or base.
+ unsigned getNumArgs() const { return NumArgs; }
+};
+
+/// CXXConstructorDecl - Represents a C++ constructor within a
+/// class. For example:
+///
+/// @code
+/// class X {
+/// public:
+/// explicit X(int); // represented by a CXXConstructorDecl.
+/// };
+/// @endcode
+class CXXConstructorDecl : public CXXMethodDecl {
+ /// Explicit - Whether this constructor is explicit.
+ bool Explicit : 1;
+
+ /// ImplicitlyDefined - Whether this constructor was implicitly
+ /// defined by the compiler. When false, the constructor was defined
+ /// by the user. In C++03, this flag will have the same value as
+ /// Implicit. In C++0x, however, a constructor that is
+ /// explicitly defaulted (i.e., defined with " = default") will have
+ /// @c !Implicit && ImplicitlyDefined.
+ bool ImplicitlyDefined : 1;
+
+ /// FIXME: Add support for base and member initializers.
+
+ CXXConstructorDecl(CXXRecordDecl *RD, SourceLocation L,
+ DeclarationName N, QualType T,
+ bool isExplicit, bool isInline, bool isImplicitlyDeclared)
+ : CXXMethodDecl(CXXConstructor, RD, L, N, T, false, isInline),
+ Explicit(isExplicit), ImplicitlyDefined(false) {
+ setImplicit(isImplicitlyDeclared);
+ }
+
+public:
+ static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation L, DeclarationName N,
+ QualType T, bool isExplicit,
+ bool isInline, bool isImplicitlyDeclared);
+
+ /// isExplicit - Whether this constructor was marked "explicit" or not.
+ bool isExplicit() const { return Explicit; }
+
+ /// isImplicitlyDefined - Whether this constructor was implicitly
+ /// defined. If false, then this constructor was defined by the
+ /// user. This operation can only be invoked if the constructor has
+ /// already been defined.
+ bool isImplicitlyDefined(ASTContext &C) const {
+ assert(isThisDeclarationADefinition() &&
+ "Can only get the implicit-definition flag once the constructor has been defined");
+ return ImplicitlyDefined;
+ }
+
+ /// setImplicitlyDefined - Set whether this constructor was
+ /// implicitly defined or not.
+ void setImplicitlyDefined(bool ID) {
+ assert(isThisDeclarationADefinition() &&
+ "Can only set the implicit-definition flag once the constructor has been defined");
+ ImplicitlyDefined = ID;
+ }
+
+ /// isDefaultConstructor - Whether this constructor is a default
+ /// constructor (C++ [class.ctor]p5), which can be used to
+ /// default-initialize a class of this type.
+ bool isDefaultConstructor() const;
+
+ /// isCopyConstructor - Whether this constructor is a copy
+ /// constructor (C++ [class.copy]p2, which can be used to copy the
+ /// class. @p TypeQuals will be set to the qualifiers on the
+ /// argument type. For example, @p TypeQuals would be set to @c
+ /// QualType::Const for the following copy constructor:
+ ///
+ /// @code
+ /// class X {
+ /// public:
+ /// X(const X&);
+ /// };
+ /// @endcode
+ bool isCopyConstructor(ASTContext &Context, unsigned &TypeQuals) const;
+
+ /// isCopyConstructor - Whether this constructor is a copy
+ /// constructor (C++ [class.copy]p2, which can be used to copy the
+ /// class.
+ bool isCopyConstructor(ASTContext &Context) const {
+ unsigned TypeQuals = 0;
+ return isCopyConstructor(Context, TypeQuals);
+ }
+
+ /// isConvertingConstructor - Whether this constructor is a
+ /// converting constructor (C++ [class.conv.ctor]), which can be
+ /// used for user-defined conversions.
+ bool isConvertingConstructor() const;
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() == CXXConstructor;
+ }
+ static bool classof(const CXXConstructorDecl *D) { return true; }
+};
+
+/// CXXDestructorDecl - Represents a C++ destructor within a
+/// class. For example:
+///
+/// @code
+/// class X {
+/// public:
+/// ~X(); // represented by a CXXDestructorDecl.
+/// };
+/// @endcode
+class CXXDestructorDecl : public CXXMethodDecl {
+ /// ImplicitlyDefined - Whether this destructor was implicitly
+ /// defined by the compiler. When false, the destructor was defined
+ /// by the user. In C++03, this flag will have the same value as
+ /// Implicit. In C++0x, however, a destructor that is
+ /// explicitly defaulted (i.e., defined with " = default") will have
+ /// @c !Implicit && ImplicitlyDefined.
+ bool ImplicitlyDefined : 1;
+
+ CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation L,
+ DeclarationName N, QualType T,
+ bool isInline, bool isImplicitlyDeclared)
+ : CXXMethodDecl(CXXDestructor, RD, L, N, T, false, isInline),
+ ImplicitlyDefined(false) {
+ setImplicit(isImplicitlyDeclared);
+ }
+
+public:
+ static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation L, DeclarationName N,
+ QualType T, bool isInline,
+ bool isImplicitlyDeclared);
+
+ /// isImplicitlyDefined - Whether this destructor was implicitly
+ /// defined. If false, then this destructor was defined by the
+ /// user. This operation can only be invoked if the destructor has
+ /// already been defined.
+ bool isImplicitlyDefined() const {
+ assert(isThisDeclarationADefinition() &&
+ "Can only get the implicit-definition flag once the destructor has been defined");
+ return ImplicitlyDefined;
+ }
+
+ /// setImplicitlyDefined - Set whether this destructor was
+ /// implicitly defined or not.
+ void setImplicitlyDefined(bool ID) {
+ assert(isThisDeclarationADefinition() &&
+ "Can only set the implicit-definition flag once the destructor has been defined");
+ ImplicitlyDefined = ID;
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() == CXXDestructor;
+ }
+ static bool classof(const CXXDestructorDecl *D) { return true; }
+};
+
+/// CXXConversionDecl - Represents a C++ conversion function within a
+/// class. For example:
+///
+/// @code
+/// class X {
+/// public:
+/// operator bool();
+/// };
+/// @endcode
+class CXXConversionDecl : public CXXMethodDecl {
+ /// Explicit - Whether this conversion function is marked
+ /// "explicit", meaning that it can only be applied when the user
+ /// explicitly wrote a cast. This is a C++0x feature.
+ bool Explicit : 1;
+
+ CXXConversionDecl(CXXRecordDecl *RD, SourceLocation L,
+ DeclarationName N, QualType T,
+ bool isInline, bool isExplicit)
+ : CXXMethodDecl(CXXConversion, RD, L, N, T, false, isInline),
+ Explicit(isExplicit) { }
+
+public:
+ static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation L, DeclarationName N,
+ QualType T, bool isInline,
+ bool isExplicit);
+
+ /// isExplicit - Whether this is an explicit conversion operator
+ /// (C++0x only). Explicit conversion operators are only considered
+ /// when the user has explicitly written a cast.
+ bool isExplicit() const { return Explicit; }
+
+ /// getConversionType - Returns the type that this conversion
+ /// function is converting to.
+ QualType getConversionType() const {
+ return getType()->getAsFunctionType()->getResultType();
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() == CXXConversion;
+ }
+ static bool classof(const CXXConversionDecl *D) { return true; }
+};
+
+/// LinkageSpecDecl - This represents a linkage specification. For example:
+/// extern "C" void foo();
+///
+class LinkageSpecDecl : public Decl, public DeclContext {
+public:
+ /// LanguageIDs - Used to represent the language in a linkage
+ /// specification. The values are part of the serialization abi for
+ /// ASTs and cannot be changed without altering that abi. To help
+ /// ensure a stable abi for this, we choose the DW_LANG_ encodings
+ /// from the dwarf standard.
+ enum LanguageIDs { lang_c = /* DW_LANG_C */ 0x0002,
+ lang_cxx = /* DW_LANG_C_plus_plus */ 0x0004 };
+private:
+ /// Language - The language for this linkage specification.
+ LanguageIDs Language;
+
+ /// HadBraces - Whether this linkage specification had curly braces or not.
+ bool HadBraces : 1;
+
+ LinkageSpecDecl(DeclContext *DC, SourceLocation L, LanguageIDs lang,
+ bool Braces)
+ : Decl(LinkageSpec, DC, L),
+ DeclContext(LinkageSpec), Language(lang), HadBraces(Braces) { }
+
+public:
+ static LinkageSpecDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, LanguageIDs Lang,
+ bool Braces);
+
+ LanguageIDs getLanguage() const { return Language; }
+
+ /// hasBraces - Determines whether this linkage specification had
+ /// braces in its syntactic form.
+ bool hasBraces() const { return HadBraces; }
+
+ static bool classof(const Decl *D) {
+ return D->getKind() == LinkageSpec;
+ }
+ static bool classof(const LinkageSpecDecl *D) { return true; }
+ static DeclContext *castToDeclContext(const LinkageSpecDecl *D) {
+ return static_cast<DeclContext *>(const_cast<LinkageSpecDecl*>(D));
+ }
+ static LinkageSpecDecl *castFromDeclContext(const DeclContext *DC) {
+ return static_cast<LinkageSpecDecl *>(const_cast<DeclContext*>(DC));
+ }
+};
+
+/// UsingDirectiveDecl - Represents C++ using-directive. For example:
+///
+/// using namespace std;
+///
+// NB: UsingDirectiveDecl should be Decl not NamedDecl, but we provide
+// artificial name, for all using-directives in order to store
+// them in DeclContext effectively.
+class UsingDirectiveDecl : public NamedDecl {
+
+ /// SourceLocation - Location of 'namespace' token.
+ SourceLocation NamespaceLoc;
+
+ /// \brief The source range that covers the nested-name-specifier
+ /// preceding the namespace name.
+ SourceRange QualifierRange;
+
+ /// \brief The nested-name-specifier that precedes the namespace
+ /// name, if any.
+ NestedNameSpecifier *Qualifier;
+
+ /// IdentLoc - Location of nominated namespace-name identifier.
+ // FIXME: We don't store location of scope specifier.
+ SourceLocation IdentLoc;
+
+ /// NominatedNamespace - Namespace nominated by using-directive.
+ NamespaceDecl *NominatedNamespace;
+
+ /// Enclosing context containing both using-directive and nomintated
+ /// namespace.
+ DeclContext *CommonAncestor;
+
+ /// getUsingDirectiveName - Returns special DeclarationName used by
+ /// using-directives. This is only used by DeclContext for storing
+ /// UsingDirectiveDecls in its lookup structure.
+ static DeclarationName getName() {
+ return DeclarationName::getUsingDirectiveName();
+ }
+
+ UsingDirectiveDecl(DeclContext *DC, SourceLocation L,
+ SourceLocation NamespcLoc,
+ SourceRange QualifierRange,
+ NestedNameSpecifier *Qualifier,
+ SourceLocation IdentLoc,
+ NamespaceDecl *Nominated,
+ DeclContext *CommonAncestor)
+ : NamedDecl(Decl::UsingDirective, DC, L, getName()),
+ NamespaceLoc(NamespcLoc), QualifierRange(QualifierRange),
+ Qualifier(Qualifier), IdentLoc(IdentLoc),
+ NominatedNamespace(Nominated? Nominated->getOriginalNamespace() : 0),
+ CommonAncestor(CommonAncestor) {
+ }
+
+public:
+ /// \brief Retrieve the source range of the nested-name-specifier
+ /// that qualifiers the namespace name.
+ SourceRange getQualifierRange() const { return QualifierRange; }
+
+ /// \brief Retrieve the nested-name-specifier that qualifies the
+ /// name of the namespace.
+ NestedNameSpecifier *getQualifier() const { return Qualifier; }
+
+ /// getNominatedNamespace - Returns namespace nominated by using-directive.
+ NamespaceDecl *getNominatedNamespace() { return NominatedNamespace; }
+
+ const NamespaceDecl *getNominatedNamespace() const {
+ return const_cast<UsingDirectiveDecl*>(this)->getNominatedNamespace();
+ }
+
+ /// getCommonAncestor - returns common ancestor context of using-directive,
+ /// and nominated by it namespace.
+ DeclContext *getCommonAncestor() { return CommonAncestor; }
+ const DeclContext *getCommonAncestor() const { return CommonAncestor; }
+
+ /// getNamespaceKeyLocation - Returns location of namespace keyword.
+ SourceLocation getNamespaceKeyLocation() const { return NamespaceLoc; }
+
+ /// getIdentLocation - Returns location of identifier.
+ SourceLocation getIdentLocation() const { return IdentLoc; }
+
+ static UsingDirectiveDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ SourceLocation NamespaceLoc,
+ SourceRange QualifierRange,
+ NestedNameSpecifier *Qualifier,
+ SourceLocation IdentLoc,
+ NamespaceDecl *Nominated,
+ DeclContext *CommonAncestor);
+
+ static bool classof(const Decl *D) {
+ return D->getKind() == Decl::UsingDirective;
+ }
+ static bool classof(const UsingDirectiveDecl *D) { return true; }
+
+ // Friend for getUsingDirectiveName.
+ friend class DeclContext;
+};
+
+/// NamespaceAliasDecl - Represents a C++ namespace alias. For example:
+///
+/// @code
+/// namespace Foo = Bar;
+/// @endcode
+class NamespaceAliasDecl : public NamedDecl {
+ SourceLocation AliasLoc;
+
+ /// \brief The source range that covers the nested-name-specifier
+ /// preceding the namespace name.
+ SourceRange QualifierRange;
+
+ /// \brief The nested-name-specifier that precedes the namespace
+ /// name, if any.
+ NestedNameSpecifier *Qualifier;
+
+ /// IdentLoc - Location of namespace identifier.
+ SourceLocation IdentLoc;
+
+ /// Namespace - The Decl that this alias points to. Can either be a
+ /// NamespaceDecl or a NamespaceAliasDecl.
+ NamedDecl *Namespace;
+
+ NamespaceAliasDecl(DeclContext *DC, SourceLocation L,
+ SourceLocation AliasLoc, IdentifierInfo *Alias,
+ SourceRange QualifierRange,
+ NestedNameSpecifier *Qualifier,
+ SourceLocation IdentLoc, NamedDecl *Namespace)
+ : NamedDecl(Decl::NamespaceAlias, DC, L, Alias), AliasLoc(AliasLoc),
+ QualifierRange(QualifierRange), Qualifier(Qualifier),
+ IdentLoc(IdentLoc), Namespace(Namespace) { }
+
+public:
+ /// \brief Retrieve the source range of the nested-name-specifier
+ /// that qualifiers the namespace name.
+ SourceRange getQualifierRange() const { return QualifierRange; }
+
+ /// \brief Retrieve the nested-name-specifier that qualifies the
+ /// name of the namespace.
+ NestedNameSpecifier *getQualifier() const { return Qualifier; }
+
+ NamespaceDecl *getNamespace() {
+ if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(Namespace))
+ return AD->getNamespace();
+
+ return cast<NamespaceDecl>(Namespace);
+ }
+
+ const NamespaceDecl *getNamespace() const {
+ return const_cast<NamespaceAliasDecl*>(this)->getNamespace();
+ }
+
+ /// \brief Retrieve the namespace that this alias refers to, which
+ /// may either be a NamespaceDecl or a NamespaceAliasDecl.
+ NamedDecl *getAliasedNamespace() const { return Namespace; }
+
+ static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, SourceLocation AliasLoc,
+ IdentifierInfo *Alias,
+ SourceRange QualifierRange,
+ NestedNameSpecifier *Qualifier,
+ SourceLocation IdentLoc,
+ NamedDecl *Namespace);
+
+ static bool classof(const Decl *D) {
+ return D->getKind() == Decl::NamespaceAlias;
+ }
+ static bool classof(const NamespaceAliasDecl *D) { return true; }
+};
+
+/// StaticAssertDecl - Represents a C++0x static_assert declaration.
+class StaticAssertDecl : public Decl {
+ Expr *AssertExpr;
+ StringLiteral *Message;
+
+ StaticAssertDecl(DeclContext *DC, SourceLocation L,
+ Expr *assertexpr, StringLiteral *message)
+ : Decl(StaticAssert, DC, L), AssertExpr(assertexpr), Message(message) { }
+
+public:
+ static StaticAssertDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, Expr *AssertExpr,
+ StringLiteral *Message);
+
+ Expr *getAssertExpr() { return AssertExpr; }
+ const Expr *getAssertExpr() const { return AssertExpr; }
+
+ StringLiteral *getMessage() { return Message; }
+ const StringLiteral *getMessage() const { return Message; }
+
+ virtual ~StaticAssertDecl();
+ virtual void Destroy(ASTContext& C);
+
+ static bool classof(const Decl *D) {
+ return D->getKind() == Decl::StaticAssert;
+ }
+ static bool classof(StaticAssertDecl *D) { return true; }
+};
+
+/// Insertion operator for diagnostics. This allows sending AccessSpecifier's
+/// into a diagnostic with <<.
+const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ AccessSpecifier AS);
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h
new file mode 100644
index 000000000000..6c1231c0a73d
--- /dev/null
+++ b/include/clang/AST/DeclContextInternals.h
@@ -0,0 +1,220 @@
+//===-- DeclContextInternals.h - DeclContext Representation -----*- 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 data structures used in the implementation
+// of DeclContext.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
+#define LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
+
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclarationName.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/SmallVector.h"
+#include <algorithm>
+
+namespace clang {
+
+/// StoredDeclsList - This is an array of decls optimized a common case of only
+/// containing one entry.
+struct StoredDeclsList {
+ /// The kind of data encoded in this list.
+ enum DataKind {
+ /// \brief The data is a NamedDecl*.
+ DK_Decl = 0,
+ /// \brief The data is a declaration ID (an unsigned value),
+ /// shifted left by 2 bits.
+ DK_DeclID = 1,
+ /// \brief The data is a pointer to a vector (of type VectorTy)
+ /// that contains declarations.
+ DK_Decl_Vector = 2,
+ /// \brief The data is a pointer to a vector (of type VectorTy)
+ /// that contains declaration ID.
+ DK_ID_Vector = 3
+ };
+
+ /// VectorTy - When in vector form, this is what the Data pointer points to.
+ typedef llvm::SmallVector<uintptr_t, 4> VectorTy;
+
+ /// \brief The stored data, which will be either a declaration ID, a
+ /// pointer to a NamedDecl, or a pointer to a vector.
+ uintptr_t Data;
+
+public:
+ StoredDeclsList() : Data(0) {}
+
+ StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) {
+ if (VectorTy *RHSVec = RHS.getAsVector()) {
+ VectorTy *New = new VectorTy(*RHSVec);
+ Data = reinterpret_cast<uintptr_t>(New) | (Data & 0x03);
+ }
+ }
+
+ ~StoredDeclsList() {
+ // If this is a vector-form, free the vector.
+ if (VectorTy *Vector = getAsVector())
+ delete Vector;
+ }
+
+ StoredDeclsList &operator=(const StoredDeclsList &RHS) {
+ if (VectorTy *Vector = getAsVector())
+ delete Vector;
+ Data = RHS.Data;
+ if (VectorTy *RHSVec = RHS.getAsVector()) {
+ VectorTy *New = new VectorTy(*RHSVec);
+ Data = reinterpret_cast<uintptr_t>(New) | (Data & 0x03);
+ }
+ return *this;
+ }
+
+ bool isNull() const { return (Data & ~0x03) == 0; }
+
+ NamedDecl *getAsDecl() const {
+ if ((Data & 0x03) != DK_Decl)
+ return 0;
+
+ return reinterpret_cast<NamedDecl *>(Data & ~0x03);
+ }
+
+ VectorTy *getAsVector() const {
+ if ((Data & 0x03) != DK_ID_Vector && (Data & 0x03) != DK_Decl_Vector)
+ return 0;
+
+ return reinterpret_cast<VectorTy *>(Data & ~0x03);
+ }
+
+ void setOnlyValue(NamedDecl *ND) {
+ assert(!getAsVector() && "Not inline");
+ Data = reinterpret_cast<uintptr_t>(ND);
+ }
+
+ void setFromDeclIDs(const llvm::SmallVectorImpl<unsigned> &Vec) {
+ if (Vec.size() > 1) {
+ VectorTy *Vector = getAsVector();
+ if (!Vector) {
+ Vector = new VectorTy;
+ Data = reinterpret_cast<uintptr_t>(Vector) | DK_ID_Vector;
+ }
+
+ Vector->resize(Vec.size());
+ std::copy(Vec.begin(), Vec.end(), Vector->begin());
+ return;
+ }
+
+ if (VectorTy *Vector = getAsVector())
+ delete Vector;
+
+ if (Vec.empty())
+ Data = 0;
+ else
+ Data = (Vec[0] << 2) | DK_DeclID;
+ }
+
+ /// \brief Force the stored declarations list to contain actual
+ /// declarations.
+ ///
+ /// This routine will resolve any declaration IDs for declarations
+ /// that may not yet have been loaded from external storage.
+ void materializeDecls(ASTContext &Context);
+
+ bool hasDeclarationIDs() const {
+ DataKind DK = (DataKind)(Data & 0x03);
+ return DK == DK_DeclID || DK == DK_ID_Vector;
+ }
+
+ /// getLookupResult - Return an array of all the decls that this list
+ /// represents.
+ DeclContext::lookup_result getLookupResult(ASTContext &Context) {
+ if (isNull())
+ return DeclContext::lookup_result(0, 0);
+
+ if (hasDeclarationIDs())
+ materializeDecls(Context);
+
+ // If we have a single NamedDecl, return it.
+ if (getAsDecl()) {
+ assert(!isNull() && "Empty list isn't allowed");
+
+ // Data is a raw pointer to a NamedDecl*, return it.
+ void *Ptr = &Data;
+ return DeclContext::lookup_result((NamedDecl**)Ptr, (NamedDecl**)Ptr+1);
+ }
+
+ assert(getAsVector() && "Must have a vector at this point");
+ VectorTy &Vector = *getAsVector();
+
+ // Otherwise, we have a range result.
+ return DeclContext::lookup_result((NamedDecl **)&Vector[0],
+ (NamedDecl **)&Vector[0]+Vector.size());
+ }
+
+ /// HandleRedeclaration - If this is a redeclaration of an existing decl,
+ /// replace the old one with D and return true. Otherwise return false.
+ bool HandleRedeclaration(ASTContext &Context, NamedDecl *D) {
+ if (hasDeclarationIDs())
+ materializeDecls(Context);
+
+ // Most decls only have one entry in their list, special case it.
+ if (NamedDecl *OldD = getAsDecl()) {
+ if (!D->declarationReplaces(OldD))
+ return false;
+ setOnlyValue(D);
+ return true;
+ }
+
+ // Determine if this declaration is actually a redeclaration.
+ VectorTy &Vec = *getAsVector();
+ for (VectorTy::iterator OD = Vec.begin(), ODEnd = Vec.end();
+ OD != ODEnd; ++OD) {
+ NamedDecl *OldD = reinterpret_cast<NamedDecl *>(*OD);
+ if (D->declarationReplaces(OldD)) {
+ *OD = reinterpret_cast<uintptr_t>(D);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /// AddSubsequentDecl - This is called on the second and later decl when it is
+ /// not a redeclaration to merge it into the appropriate place in our list.
+ ///
+ void AddSubsequentDecl(NamedDecl *D) {
+ assert(!hasDeclarationIDs() && "Must materialize before adding decls");
+
+ // If this is the second decl added to the list, convert this to vector
+ // form.
+ if (NamedDecl *OldD = getAsDecl()) {
+ VectorTy *VT = new VectorTy();
+ VT->push_back(reinterpret_cast<uintptr_t>(OldD));
+ Data = reinterpret_cast<uintptr_t>(VT) | DK_Decl_Vector;
+ }
+
+ VectorTy &Vec = *getAsVector();
+ if (isa<UsingDirectiveDecl>(D) ||
+ D->getIdentifierNamespace() == Decl::IDNS_Tag)
+ Vec.push_back(reinterpret_cast<uintptr_t>(D));
+ else if (reinterpret_cast<NamedDecl *>(Vec.back())
+ ->getIdentifierNamespace() == Decl::IDNS_Tag) {
+ uintptr_t TagD = Vec.back();
+ Vec.back() = reinterpret_cast<uintptr_t>(D);
+ Vec.push_back(TagD);
+ } else
+ Vec.push_back(reinterpret_cast<uintptr_t>(D));
+ }
+};
+
+typedef llvm::DenseMap<DeclarationName, StoredDeclsList> StoredDeclsMap;
+
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/DeclGroup.h b/include/clang/AST/DeclGroup.h
new file mode 100644
index 000000000000..15a8adef8e57
--- /dev/null
+++ b/include/clang/AST/DeclGroup.h
@@ -0,0 +1,152 @@
+//===--- DeclGroup.h - Classes for representing groups of Decls -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the DeclGroup, DeclGroupRef, and OwningDeclGroup classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_DECLGROUP_H
+#define LLVM_CLANG_AST_DECLGROUP_H
+
+#include "llvm/Support/DataTypes.h"
+#include <cassert>
+
+namespace clang {
+
+class ASTContext;
+class Decl;
+class DeclGroup;
+class DeclGroupIterator;
+
+class DeclGroup {
+ // FIXME: Include a TypeSpecifier object.
+ unsigned NumDecls;
+
+private:
+ DeclGroup() : NumDecls(0) {}
+ DeclGroup(unsigned numdecls, Decl** decls);
+
+public:
+ static DeclGroup *Create(ASTContext &C, Decl **Decls, unsigned NumDecls);
+ void Destroy(ASTContext& C);
+
+ unsigned size() const { return NumDecls; }
+
+ Decl*& operator[](unsigned i) {
+ assert (i < NumDecls && "Out-of-bounds access.");
+ return *((Decl**) (this+1));
+ }
+
+ Decl* const& operator[](unsigned i) const {
+ assert (i < NumDecls && "Out-of-bounds access.");
+ return *((Decl* const*) (this+1));
+ }
+};
+
+class DeclGroupRef {
+ // Note this is not a PointerIntPair because we need the address of the
+ // non-group case to be valid as a Decl** for iteration.
+ enum Kind { SingleDeclKind=0x0, DeclGroupKind=0x1, Mask=0x1 };
+ Decl* D;
+
+ Kind getKind() const {
+ return (Kind) (reinterpret_cast<uintptr_t>(D) & Mask);
+ }
+
+public:
+ DeclGroupRef() : D(0) {}
+
+ explicit DeclGroupRef(Decl* d) : D(d) {}
+ explicit DeclGroupRef(DeclGroup* dg)
+ : D((Decl*) (reinterpret_cast<uintptr_t>(dg) | DeclGroupKind)) {}
+
+ static DeclGroupRef Create(ASTContext &C, Decl **Decls, unsigned NumDecls) {
+ if (NumDecls == 0)
+ return DeclGroupRef();
+ if (NumDecls == 1)
+ return DeclGroupRef(Decls[0]);
+ return DeclGroupRef(DeclGroup::Create(C, Decls, NumDecls));
+ }
+
+ typedef Decl** iterator;
+ typedef Decl* const * const_iterator;
+
+ bool isNull() const { return D == 0; }
+ bool isSingleDecl() const { return getKind() == SingleDeclKind; }
+ bool isDeclGroup() const { return getKind() == DeclGroupKind; }
+
+ Decl *getSingleDecl() {
+ assert(isSingleDecl() && "Isn't a declgroup");
+ return D;
+ }
+ const Decl *getSingleDecl() const {
+ return const_cast<DeclGroupRef*>(this)->getSingleDecl();
+ }
+
+ DeclGroup &getDeclGroup() {
+ assert(isDeclGroup() && "Isn't a declgroup");
+ return *((DeclGroup*)(reinterpret_cast<uintptr_t>(D) & ~Mask));
+ }
+ const DeclGroup &getDeclGroup() const {
+ return const_cast<DeclGroupRef*>(this)->getDeclGroup();
+ }
+
+ iterator begin() {
+ if (isSingleDecl())
+ return D ? &D : 0;
+ return &getDeclGroup()[0];
+ }
+
+ iterator end() {
+ if (isSingleDecl())
+ return D ? &D+1 : 0;
+ DeclGroup &G = getDeclGroup();
+ return &G[0] + G.size();
+ }
+
+ const_iterator begin() const {
+ if (isSingleDecl())
+ return D ? &D : 0;
+ return &getDeclGroup()[0];
+ }
+
+ const_iterator end() const {
+ if (isSingleDecl())
+ return D ? &D+1 : 0;
+ const DeclGroup &G = getDeclGroup();
+ return &G[0] + G.size();
+ }
+
+ void *getAsOpaquePtr() const { return D; }
+ static DeclGroupRef getFromOpaquePtr(void *Ptr) {
+ DeclGroupRef X;
+ X.D = static_cast<Decl*>(Ptr);
+ return X;
+ }
+};
+
+} // end clang namespace
+
+namespace llvm {
+ // DeclGroupRef is "like a pointer", implement PointerLikeTypeTraits.
+ template <typename T>
+ class PointerLikeTypeTraits;
+ template <>
+ class PointerLikeTypeTraits<clang::DeclGroupRef> {
+ public:
+ static inline void *getAsVoidPointer(clang::DeclGroupRef P) {
+ return P.getAsOpaquePtr();
+ }
+ static inline clang::DeclGroupRef getFromVoidPointer(void *P) {
+ return clang::DeclGroupRef::getFromOpaquePtr(P);
+ }
+ enum { NumLowBitsAvailable = 0 };
+ };
+}
+#endif
diff --git a/include/clang/AST/DeclNodes.def b/include/clang/AST/DeclNodes.def
new file mode 100644
index 000000000000..d1b921a4cb65
--- /dev/null
+++ b/include/clang/AST/DeclNodes.def
@@ -0,0 +1,161 @@
+//===-- DeclNodes.def - Metadata about Decl AST nodes -----------*- 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 declaration nodes within the AST. The
+// description of the declaration nodes uses six macros:
+//
+// DECL(Derived, Base) describes a normal declaration type Derived
+// and specifies its base class. Note that Derived should not have
+// the Decl suffix on it, while Base should.
+//
+// LAST_DECL(Derived, Base) is like DECL, but is used for the last
+// declaration in the list.
+//
+// ABSTRACT_DECL(Derived, Base) describes an abstract class that is
+// used to specify a classification of declarations. For example,
+// TagDecl is an abstract class used to describe the various kinds of
+// "tag" declarations (unions, structs, classes, enums).
+//
+// DECL_CONTEXT(Decl) specifies that Decl is a kind of declaration
+// that is also a DeclContext.
+//
+// LAST_DECL_CONTEXT(Decl) is like DECL_CONTEXT, but is used for the
+// last declaration context.
+//
+// DECL_RANGE(CommonBase, Start, End) specifies a range of
+// declaration values that have a common (potentially indirect) base
+// class.
+//
+// LAST_DECL_RANGE(CommonBase, Start, End) is like DECL_RANGE, but is
+// used for the last declaration range.
+//
+// Note that, due to the use of ranges, the order of the these
+// declarations is significant. A declaration should be listed under
+// its base class.
+// ===----------------------------------------------------------------------===//
+
+#ifndef DECL
+# define DECL(Derived, Base)
+#endif
+
+#ifndef LAST_DECL
+# define LAST_DECL(Derived, Base) DECL(Derived, Base)
+#endif
+
+#ifndef ABSTRACT_DECL
+# define ABSTRACT_DECL(Derived, Base)
+#endif
+
+#ifndef DECL_CONTEXT
+# define DECL_CONTEXT(Decl)
+#endif
+
+#ifndef DECL_CONTEXT_BASE
+# define DECL_CONTEXT_BASE(Decl) DECL_CONTEXT(Decl)
+#endif
+
+#ifndef LAST_DECL_CONTEXT
+# define LAST_DECL_CONTEXT(Decl) DECL_CONTEXT(Decl)
+#endif
+
+#ifndef DECL_RANGE
+# define DECL_RANGE(CommonBase, Start, End)
+#endif
+
+#ifndef LAST_DECL_RANGE
+# define LAST_DECL_RANGE(CommonBase, Start, End) \
+ DECL_RANGE(CommonBase, Start, End)
+#endif
+
+DECL(TranslationUnit, Decl)
+ABSTRACT_DECL(Named, Decl)
+ DECL(OverloadedFunction, NamedDecl)
+ DECL(Namespace, NamedDecl)
+ DECL(UsingDirective, NamedDecl)
+ DECL(NamespaceAlias, NamedDecl)
+ ABSTRACT_DECL(Type, NamedDecl)
+ DECL(Typedef, TypeDecl)
+ ABSTRACT_DECL(Tag, TypeDecl)
+ DECL(Enum, TagDecl)
+ DECL(Record, TagDecl)
+ DECL(CXXRecord, RecordDecl)
+ DECL(ClassTemplateSpecialization, CXXRecordDecl)
+ DECL(ClassTemplatePartialSpecialization,
+ ClassTemplateSpecializationDecl)
+ DECL(TemplateTypeParm, TypeDecl)
+ ABSTRACT_DECL(Value, NamedDecl)
+ DECL(EnumConstant, ValueDecl)
+ DECL(Function, ValueDecl)
+ DECL(CXXMethod, FunctionDecl)
+ DECL(CXXConstructor, CXXMethodDecl)
+ DECL(CXXDestructor, CXXMethodDecl)
+ DECL(CXXConversion, CXXMethodDecl)
+ DECL(Field, ValueDecl)
+ DECL(ObjCIvar, FieldDecl)
+ DECL(ObjCAtDefsField, FieldDecl)
+ DECL(Var, ValueDecl)
+ DECL(ImplicitParam, VarDecl)
+ DECL(ParmVar, VarDecl)
+ DECL(OriginalParmVar, ParmVarDecl)
+ DECL(NonTypeTemplateParm, VarDecl)
+ DECL(Template, NamedDecl)
+ DECL(FunctionTemplate, TemplateDecl)
+ DECL(ClassTemplate, TemplateDecl)
+ DECL(TemplateTemplateParm, TemplateDecl)
+ DECL(ObjCMethod, NamedDecl)
+ DECL(ObjCContainer, NamedDecl)
+ DECL(ObjCCategory, ObjCContainerDecl)
+ DECL(ObjCProtocol, ObjCContainerDecl)
+ DECL(ObjCInterface, ObjCContainerDecl)
+ DECL(ObjCProperty, NamedDecl)
+ DECL(ObjCCompatibleAlias, NamedDecl)
+ ABSTRACT_DECL(ObjCImpl, NamedDecl)
+ DECL(ObjCCategoryImpl, ObjCImplDecl)
+ DECL(ObjCImplementation, ObjCImplDecl)
+DECL(LinkageSpec, Decl)
+DECL(ObjCPropertyImpl, Decl)
+DECL(ObjCForwardProtocol, Decl)
+DECL(ObjCClass, Decl)
+DECL(FileScopeAsm, Decl)
+DECL(StaticAssert, Decl)
+LAST_DECL(Block, Decl)
+
+// Declaration contexts. DECL_CONTEXT_BASE indicates that it has subclasses.
+DECL_CONTEXT(TranslationUnit)
+DECL_CONTEXT(Namespace)
+DECL_CONTEXT(LinkageSpec)
+DECL_CONTEXT(ObjCMethod)
+DECL_CONTEXT(ObjCCategoryImpl)
+DECL_CONTEXT(ObjCImplementation)
+DECL_CONTEXT_BASE(Tag)
+DECL_CONTEXT_BASE(Function)
+DECL_CONTEXT_BASE(ObjCContainer)
+LAST_DECL_CONTEXT(Block)
+
+// Declaration ranges
+DECL_RANGE(Named, OverloadedFunction, ObjCImplementation)
+DECL_RANGE(ObjCContainer, ObjCContainer, ObjCInterface)
+DECL_RANGE(Field, Field, ObjCAtDefsField)
+DECL_RANGE(Type, Typedef, TemplateTypeParm)
+DECL_RANGE(Tag, Enum, ClassTemplatePartialSpecialization)
+DECL_RANGE(Record, Record, ClassTemplatePartialSpecialization)
+DECL_RANGE(Value, EnumConstant, NonTypeTemplateParm)
+DECL_RANGE(Function, Function, CXXConversion)
+DECL_RANGE(Template, Template, TemplateTemplateParm)
+DECL_RANGE(ObjCImpl, ObjCCategoryImpl, ObjCImplementation)
+LAST_DECL_RANGE(Var, Var, NonTypeTemplateParm)
+
+#undef LAST_DECL_RANGE
+#undef DECL_RANGE
+#undef LAST_DECL_CONTEXT
+#undef DECL_CONTEXT_BASE
+#undef DECL_CONTEXT
+#undef ABSTRACT_DECL
+#undef LAST_DECL
+#undef DECL
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
new file mode 100644
index 000000000000..6e89a7ae7bc9
--- /dev/null
+++ b/include/clang/AST/DeclObjC.h
@@ -0,0 +1,1224 @@
+//===--- DeclObjC.h - Classes for representing 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 DeclObjC interface and subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_DECLOBJC_H
+#define LLVM_CLANG_AST_DECLOBJC_H
+
+#include "clang/AST/Decl.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace clang {
+class Expr;
+class Stmt;
+class FunctionDecl;
+class AttributeList;
+class RecordDecl;
+class ObjCIvarDecl;
+class ObjCMethodDecl;
+class ObjCProtocolDecl;
+class ObjCCategoryDecl;
+class ObjCPropertyDecl;
+class ObjCPropertyImplDecl;
+
+class ObjCListBase {
+ void operator=(const ObjCListBase &); // DO NOT IMPLEMENT
+ ObjCListBase(const ObjCListBase&); // DO NOT IMPLEMENT
+protected:
+ /// List is an array of pointers to objects that are not owned by this object.
+ void **List;
+ unsigned NumElts;
+
+public:
+ ObjCListBase() : List(0), NumElts(0) {}
+ ~ObjCListBase() {
+ assert(List == 0 && "Destroy should have been called before dtor");
+ }
+
+ void Destroy(ASTContext &Ctx);
+
+ unsigned size() const { return NumElts; }
+ bool empty() const { return NumElts == 0; }
+
+protected:
+ void set(void *const* InList, unsigned Elts, ASTContext &Ctx);
+};
+
+
+/// ObjCList - This is a simple template class used to hold various lists of
+/// decls etc, which is heavily used by the ObjC front-end. This only use case
+/// this supports is setting the list all at once and then reading elements out
+/// of it.
+template <typename T>
+class ObjCList : public ObjCListBase {
+public:
+ void set(T* const* InList, unsigned Elts, ASTContext &Ctx) {
+ ObjCListBase::set(reinterpret_cast<void*const*>(InList), Elts, Ctx);
+ }
+
+ typedef T* const * iterator;
+ iterator begin() const { return (iterator)List; }
+ iterator end() const { return (iterator)List+NumElts; }
+
+ T* operator[](unsigned Idx) const {
+ assert(Idx < NumElts && "Invalid access");
+ return (T*)List[Idx];
+ }
+};
+
+
+
+/// ObjCMethodDecl - Represents an instance or class method declaration.
+/// ObjC methods can be declared within 4 contexts: class interfaces,
+/// categories, protocols, and class implementations. While C++ member
+/// functions leverage C syntax, Objective-C method syntax is modeled after
+/// Smalltalk (using colons to specify argument types/expressions).
+/// Here are some brief examples:
+///
+/// Setter/getter instance methods:
+/// - (void)setMenu:(NSMenu *)menu;
+/// - (NSMenu *)menu;
+///
+/// Instance method that takes 2 NSView arguments:
+/// - (void)replaceSubview:(NSView *)oldView with:(NSView *)newView;
+///
+/// Getter class method:
+/// + (NSMenu *)defaultMenu;
+///
+/// A selector represents a unique name for a method. The selector names for
+/// the above methods are setMenu:, menu, replaceSubview:with:, and defaultMenu.
+///
+class ObjCMethodDecl : public NamedDecl, public DeclContext {
+public:
+ enum ImplementationControl { None, Required, Optional };
+private:
+ /// Bitfields must be first fields in this class so they pack with those
+ /// declared in class Decl.
+ /// instance (true) or class (false) method.
+ bool IsInstance : 1;
+ bool IsVariadic : 1;
+
+ // Synthesized declaration method for a property setter/getter
+ bool IsSynthesized : 1;
+
+ // NOTE: VC++ treats enums as signed, avoid using ImplementationControl enum
+ /// @required/@optional
+ unsigned DeclImplementation : 2;
+
+ // NOTE: VC++ treats enums as signed, avoid using the ObjCDeclQualifier enum
+ /// in, inout, etc.
+ unsigned objcDeclQualifier : 6;
+
+ // Type of this method.
+ QualType MethodDeclType;
+ /// ParamInfo - List of pointers to VarDecls for the formal parameters of this
+ /// Method.
+ ObjCList<ParmVarDecl> ParamInfo;
+
+ /// List of attributes for this method declaration.
+ SourceLocation EndLoc; // the location of the ';' or '{'.
+
+ // The following are only used for method definitions, null otherwise.
+ // FIXME: space savings opportunity, consider a sub-class.
+ Stmt *Body;
+
+ /// SelfDecl - Decl for the implicit self parameter. This is lazily
+ /// constructed by createImplicitParams.
+ ImplicitParamDecl *SelfDecl;
+ /// CmdDecl - Decl for the implicit _cmd parameter. This is lazily
+ /// constructed by createImplicitParams.
+ ImplicitParamDecl *CmdDecl;
+
+ ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc,
+ Selector SelInfo, QualType T,
+ DeclContext *contextDecl,
+ bool isInstance = true,
+ bool isVariadic = false,
+ bool isSynthesized = false,
+ ImplementationControl impControl = None)
+ : NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
+ DeclContext(ObjCMethod),
+ IsInstance(isInstance), IsVariadic(isVariadic),
+ IsSynthesized(isSynthesized),
+ DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None),
+ MethodDeclType(T),
+ EndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {}
+
+ virtual ~ObjCMethodDecl() {}
+
+public:
+
+ /// Destroy - Call destructors and release memory.
+ virtual void Destroy(ASTContext& C);
+
+ static ObjCMethodDecl *Create(ASTContext &C,
+ SourceLocation beginLoc,
+ SourceLocation endLoc, Selector SelInfo,
+ QualType T, DeclContext *contextDecl,
+ bool isInstance = true,
+ bool isVariadic = false,
+ bool isSynthesized = false,
+ ImplementationControl impControl = None);
+
+ ObjCDeclQualifier getObjCDeclQualifier() const {
+ return ObjCDeclQualifier(objcDeclQualifier);
+ }
+ void setObjCDeclQualifier(ObjCDeclQualifier QV) { objcDeclQualifier = QV; }
+
+ // Location information, modeled after the Stmt API.
+ SourceLocation getLocStart() const { return getLocation(); }
+ SourceLocation getLocEnd() const { return EndLoc; }
+ void setEndLoc(SourceLocation Loc) { EndLoc = Loc; }
+ SourceRange getSourceRange() const {
+ return SourceRange(getLocation(), EndLoc);
+ }
+
+ ObjCInterfaceDecl *getClassInterface();
+ const ObjCInterfaceDecl *getClassInterface() const {
+ return const_cast<ObjCMethodDecl*>(this)->getClassInterface();
+ }
+
+ Selector getSelector() const { return getDeclName().getObjCSelector(); }
+ unsigned getSynthesizedMethodSize() const;
+ QualType getResultType() const { return MethodDeclType; }
+ void setResultType(QualType T) { MethodDeclType = T; }
+
+ // 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(); }
+
+ void setMethodParams(ASTContext &C, ParmVarDecl *const *List, unsigned Num) {
+ ParamInfo.set(List, Num, C);
+ }
+
+ // 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;
+
+ arg_type_iterator arg_type_begin() const {
+ return llvm::map_iterator(param_begin(), deref_fun(&ParmVarDecl::getType));
+ }
+ arg_type_iterator arg_type_end() const {
+ return llvm::map_iterator(param_end(), deref_fun(&ParmVarDecl::getType));
+ }
+
+ /// createImplicitParams - Used to lazily create the self and cmd
+ /// implict parameters. This must be called prior to using getSelfDecl()
+ /// or getCmdDecl(). The call is ignored if the implicit paramters
+ /// have already been created.
+ void createImplicitParams(ASTContext &Context, const ObjCInterfaceDecl *ID);
+
+ ImplicitParamDecl * getSelfDecl() const { return SelfDecl; }
+ void setSelfDecl(ImplicitParamDecl *SD) { SelfDecl = SD; }
+ ImplicitParamDecl * getCmdDecl() const { return CmdDecl; }
+ void setCmdDecl(ImplicitParamDecl *CD) { CmdDecl = CD; }
+
+ bool isInstanceMethod() const { return IsInstance; }
+ void setInstanceMethod(bool isInst) { IsInstance = isInst; }
+ bool isVariadic() const { return IsVariadic; }
+ void setVariadic(bool isVar) { IsVariadic = isVar; }
+
+ bool isClassMethod() const { return !IsInstance; }
+
+ bool isSynthesized() const { return IsSynthesized; }
+ void setSynthesized(bool isSynth) { IsSynthesized = isSynth; }
+
+ // Related to protocols declared in @protocol
+ void setDeclImplementation(ImplementationControl ic) {
+ DeclImplementation = ic;
+ }
+ ImplementationControl getImplementationControl() const {
+ return ImplementationControl(DeclImplementation);
+ }
+
+ virtual Stmt *getBody(ASTContext &C) const {
+ return (Stmt*) Body;
+ }
+ CompoundStmt *getBody() { return (CompoundStmt*)Body; }
+ void setBody(Stmt *B) { Body = B; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return D->getKind() == ObjCMethod; }
+ static bool classof(const ObjCMethodDecl *D) { return true; }
+ static DeclContext *castToDeclContext(const ObjCMethodDecl *D) {
+ return static_cast<DeclContext *>(const_cast<ObjCMethodDecl*>(D));
+ }
+ static ObjCMethodDecl *castFromDeclContext(const DeclContext *DC) {
+ return static_cast<ObjCMethodDecl *>(const_cast<DeclContext*>(DC));
+ }
+};
+
+/// ObjCMethodList - a linked list of methods with different signatures.
+struct ObjCMethodList {
+ ObjCMethodDecl *Method;
+ ObjCMethodList *Next;
+
+ ObjCMethodList() {
+ Method = 0;
+ Next = 0;
+ }
+ ObjCMethodList(ObjCMethodDecl *M, ObjCMethodList *C) {
+ Method = M;
+ Next = C;
+ }
+};
+
+/// ObjCContainerDecl - Represents a container for method declarations.
+/// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl, and
+/// ObjCProtocolDecl.
+/// FIXME: Use for ObjC implementation decls.
+///
+class ObjCContainerDecl : public NamedDecl, public DeclContext {
+ SourceLocation AtEndLoc; // marks the end of the method container.
+public:
+
+ ObjCContainerDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id)
+ : NamedDecl(DK, DC, L, Id), DeclContext(DK) {}
+
+ virtual ~ObjCContainerDecl() {}
+
+ // Iterator access to properties.
+ typedef specific_decl_iterator<ObjCPropertyDecl> prop_iterator;
+ prop_iterator prop_begin(ASTContext &Context) const {
+ return prop_iterator(decls_begin(Context));
+ }
+ prop_iterator prop_end(ASTContext &Context) const {
+ return prop_iterator(decls_end(Context));
+ }
+
+ // Iterator access to instance/class methods.
+ typedef specific_decl_iterator<ObjCMethodDecl> method_iterator;
+ method_iterator meth_begin(ASTContext &Context) const {
+ return method_iterator(decls_begin(Context));
+ }
+ method_iterator meth_end(ASTContext &Context) const {
+ return method_iterator(decls_end(Context));
+ }
+
+ typedef filtered_decl_iterator<ObjCMethodDecl,
+ &ObjCMethodDecl::isInstanceMethod>
+ instmeth_iterator;
+ instmeth_iterator instmeth_begin(ASTContext &Context) const {
+ return instmeth_iterator(decls_begin(Context));
+ }
+ instmeth_iterator instmeth_end(ASTContext &Context) const {
+ return instmeth_iterator(decls_end(Context));
+ }
+
+ typedef filtered_decl_iterator<ObjCMethodDecl,
+ &ObjCMethodDecl::isClassMethod>
+ classmeth_iterator;
+ classmeth_iterator classmeth_begin(ASTContext &Context) const {
+ return classmeth_iterator(decls_begin(Context));
+ }
+ classmeth_iterator classmeth_end(ASTContext &Context) const {
+ return classmeth_iterator(decls_end(Context));
+ }
+
+ // Get the local instance/class method declared in this interface.
+ ObjCMethodDecl *getInstanceMethod(ASTContext &Context, Selector Sel) const;
+ ObjCMethodDecl *getClassMethod(ASTContext &Context, Selector Sel) const;
+
+ ObjCMethodDecl *
+ getMethod(ASTContext &Context, Selector Sel, bool isInstance) const {
+ return isInstance ? getInstanceMethod(Context, Sel)
+ : getClassMethod(Context, Sel);
+ }
+
+ ObjCPropertyDecl *FindPropertyDeclaration(ASTContext &Context,
+ IdentifierInfo *PropertyId) const;
+
+ // Marks the end of the container.
+ SourceLocation getAtEndLoc() const { return AtEndLoc; }
+ void setAtEndLoc(SourceLocation L) { AtEndLoc = L; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() >= ObjCContainerFirst &&
+ D->getKind() <= ObjCContainerLast;
+ }
+ static bool classof(const ObjCContainerDecl *D) { return true; }
+
+ static DeclContext *castToDeclContext(const ObjCContainerDecl *D) {
+ return static_cast<DeclContext *>(const_cast<ObjCContainerDecl*>(D));
+ }
+ static ObjCContainerDecl *castFromDeclContext(const DeclContext *DC) {
+ return static_cast<ObjCContainerDecl *>(const_cast<DeclContext*>(DC));
+ }
+};
+
+/// ObjCInterfaceDecl - Represents an ObjC class declaration. For example:
+///
+/// // MostPrimitive declares no super class (not particularly useful).
+/// @interface MostPrimitive
+/// // no instance variables or methods.
+/// @end
+///
+/// // NSResponder inherits from NSObject & implements NSCoding (a protocol).
+/// @interface NSResponder : NSObject <NSCoding>
+/// { // instance variables are represented by ObjCIvarDecl.
+/// id nextResponder; // nextResponder instance variable.
+/// }
+/// - (NSResponder *)nextResponder; // return a pointer to NSResponder.
+/// - (void)mouseMoved:(NSEvent *)theEvent; // return void, takes a pointer
+/// @end // to an NSEvent.
+///
+/// Unlike C/C++, forward class declarations are accomplished with @class.
+/// Unlike C/C++, @class allows for a list of classes to be forward declared.
+/// Unlike C++, ObjC is a single-rooted class model. In Cocoa, classes
+/// typically inherit from NSObject (an exception is NSProxy).
+///
+class ObjCInterfaceDecl : public ObjCContainerDecl {
+ /// TypeForDecl - This indicates the Type object that represents this
+ /// TypeDecl. It is a cache maintained by ASTContext::getObjCInterfaceType
+ mutable Type *TypeForDecl;
+ friend class ASTContext;
+
+ /// Class's super class.
+ ObjCInterfaceDecl *SuperClass;
+
+ /// Protocols referenced in interface header declaration
+ ObjCList<ObjCProtocolDecl> ReferencedProtocols;
+
+ /// Instance variables in the interface.
+ ObjCList<ObjCIvarDecl> IVars;
+
+ /// List of categories defined for this class.
+ /// FIXME: Why is this a linked list??
+ ObjCCategoryDecl *CategoryList;
+
+ bool ForwardDecl:1; // declared with @class.
+ bool InternalInterface:1; // true - no @interface for @implementation
+
+ SourceLocation ClassLoc; // location of the class identifier.
+ SourceLocation SuperClassLoc; // location of the super class identifier.
+ SourceLocation EndLoc; // marks the '>', '}', or identifier.
+
+ ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
+ SourceLocation CLoc, bool FD, bool isInternal);
+
+ virtual ~ObjCInterfaceDecl() {}
+
+public:
+
+ /// Destroy - Call destructors and release memory.
+ virtual void Destroy(ASTContext& C);
+
+ static ObjCInterfaceDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation atLoc,
+ IdentifierInfo *Id,
+ SourceLocation ClassLoc = SourceLocation(),
+ bool ForwardDecl = false,
+ bool isInternal = false);
+ const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const {
+ return ReferencedProtocols;
+ }
+
+ ObjCCategoryDecl *FindCategoryDeclaration(IdentifierInfo *CategoryId) const;
+
+ typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator;
+ protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();}
+ protocol_iterator protocol_end() const { return ReferencedProtocols.end(); }
+ unsigned protocol_size() const { return ReferencedProtocols.size(); }
+
+ typedef ObjCList<ObjCIvarDecl>::iterator ivar_iterator;
+ ivar_iterator ivar_begin() const { return IVars.begin(); }
+ ivar_iterator ivar_end() const { return IVars.end(); }
+ unsigned ivar_size() const { return IVars.size(); }
+ bool ivar_empty() const { return IVars.empty(); }
+
+ /// setProtocolList - Set the list of protocols that this interface
+ /// implements.
+ void setProtocolList(ObjCProtocolDecl *const* List, unsigned Num,
+ ASTContext &C) {
+ ReferencedProtocols.set(List, Num, C);
+ }
+
+ void setIVarList(ObjCIvarDecl * const *List, unsigned Num, ASTContext &C) {
+ IVars.set(List, Num, C);
+ }
+
+ bool isForwardDecl() const { return ForwardDecl; }
+ void setForwardDecl(bool val) { ForwardDecl = val; }
+
+ ObjCInterfaceDecl *getSuperClass() const { return SuperClass; }
+ void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; }
+
+ ObjCCategoryDecl* getCategoryList() const { return CategoryList; }
+ void setCategoryList(ObjCCategoryDecl *category) {
+ CategoryList = category;
+ }
+
+ /// isSuperClassOf - Return true if this class is the specified class or is a
+ /// super class of the specified interface class.
+ bool isSuperClassOf(const ObjCInterfaceDecl *I) const {
+ // If RHS is derived from LHS it is OK; else it is not OK.
+ while (I != NULL) {
+ if (this == I)
+ return true;
+ I = I->getSuperClass();
+ }
+ return false;
+ }
+
+ ObjCIvarDecl *lookupInstanceVariable(ASTContext &Context,
+ IdentifierInfo *IVarName,
+ ObjCInterfaceDecl *&ClassDeclared);
+ ObjCIvarDecl *lookupInstanceVariable(ASTContext &Context,
+ IdentifierInfo *IVarName) {
+ ObjCInterfaceDecl *ClassDeclared;
+ return lookupInstanceVariable(Context, IVarName, ClassDeclared);
+ }
+
+ // Lookup a method. First, we search locally. If a method isn't
+ // found, we search referenced protocols and class categories.
+ ObjCMethodDecl *lookupInstanceMethod(ASTContext &Context, Selector Sel);
+ ObjCMethodDecl *lookupClassMethod(ASTContext &Context, Selector Sel);
+ ObjCInterfaceDecl *lookupInheritedClass(const IdentifierInfo *ICName);
+
+ // Location information, modeled after the Stmt API.
+ SourceLocation getLocStart() const { return getLocation(); } // '@'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; }
+
+ /// isImplicitInterfaceDecl - check that this is an implicitly declared
+ /// ObjCInterfaceDecl node. This is for legacy objective-c @implementation
+ /// declaration without an @interface declaration.
+ bool isImplicitInterfaceDecl() const { return InternalInterface; }
+ void setImplicitInterfaceDecl(bool val) { InternalInterface = val; }
+
+ // Low-level accessor
+ Type *getTypeForDecl() const { return TypeForDecl; }
+ void setTypeForDecl(Type *TD) const { TypeForDecl = TD; }
+
+ static bool classof(const Decl *D) { return D->getKind() == ObjCInterface; }
+ static bool classof(const ObjCInterfaceDecl *D) { return true; }
+};
+
+/// ObjCIvarDecl - Represents an ObjC instance variable. In general, ObjC
+/// instance variables are identical to C. The only exception is Objective-C
+/// supports C++ style access control. For example:
+///
+/// @interface IvarExample : NSObject
+/// {
+/// id defaultToProtected;
+/// @public:
+/// id canBePublic; // same as C++.
+/// @protected:
+/// id canBeProtected; // same as C++.
+/// @package:
+/// id canBePackage; // framework visibility (not available in C++).
+/// }
+///
+class ObjCIvarDecl : public FieldDecl {
+public:
+ enum AccessControl {
+ None, Private, Protected, Public, Package
+ };
+
+private:
+ ObjCIvarDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
+ QualType T, AccessControl ac, Expr *BW)
+ : FieldDecl(ObjCIvar, DC, L, Id, T, BW, /*Mutable=*/false),
+ DeclAccess(ac) {}
+
+public:
+ static ObjCIvarDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType T,
+ AccessControl ac, Expr *BW = NULL);
+
+ void setAccessControl(AccessControl ac) { DeclAccess = ac; }
+
+ AccessControl getAccessControl() const { return AccessControl(DeclAccess); }
+
+ AccessControl getCanonicalAccessControl() const {
+ return DeclAccess == None ? Protected : AccessControl(DeclAccess);
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return D->getKind() == ObjCIvar; }
+ static bool classof(const ObjCIvarDecl *D) { return true; }
+private:
+ // NOTE: VC++ treats enums as signed, avoid using the AccessControl enum
+ unsigned DeclAccess : 3;
+};
+
+
+/// ObjCAtDefsFieldDecl - Represents a field declaration created by an
+/// @defs(...).
+class ObjCAtDefsFieldDecl : public FieldDecl {
+private:
+ ObjCAtDefsFieldDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
+ QualType T, Expr *BW)
+ : FieldDecl(ObjCAtDefsField, DC, L, Id, T, BW, /*Mutable=*/false) {}
+
+public:
+ static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ IdentifierInfo *Id, QualType T,
+ Expr *BW);
+
+ virtual void Destroy(ASTContext& C);
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return D->getKind() == ObjCAtDefsField; }
+ static bool classof(const ObjCAtDefsFieldDecl *D) { return true; }
+};
+
+/// ObjCProtocolDecl - Represents a protocol declaration. ObjC protocols
+/// declare a pure abstract type (i.e no instance variables are permitted).
+/// Protocols orginally drew inspiration from C++ pure virtual functions (a C++
+/// feature with nice semantics and lousy syntax:-). Here is an example:
+///
+/// @protocol NSDraggingInfo <refproto1, refproto2>
+/// - (NSWindow *)draggingDestinationWindow;
+/// - (NSImage *)draggedImage;
+/// @end
+///
+/// This says that NSDraggingInfo requires two methods and requires everything
+/// that the two "referenced protocols" 'refproto1' and 'refproto2' require as
+/// well.
+///
+/// @interface ImplementsNSDraggingInfo : NSObject <NSDraggingInfo>
+/// @end
+///
+/// ObjC protocols inspired Java interfaces. Unlike Java, ObjC classes and
+/// protocols are in distinct namespaces. For example, Cocoa defines both
+/// an NSObject protocol and class (which isn't allowed in Java). As a result,
+/// protocols are referenced using angle brackets as follows:
+///
+/// id <NSDraggingInfo> anyObjectThatImplementsNSDraggingInfo;
+///
+class ObjCProtocolDecl : public ObjCContainerDecl {
+ /// Referenced protocols
+ ObjCList<ObjCProtocolDecl> ReferencedProtocols;
+
+ bool isForwardProtoDecl; // declared with @protocol.
+
+ SourceLocation EndLoc; // marks the '>' or identifier.
+
+ ObjCProtocolDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
+ : ObjCContainerDecl(ObjCProtocol, DC, L, Id),
+ isForwardProtoDecl(true) {
+ }
+
+ virtual ~ObjCProtocolDecl() {}
+
+public:
+ static ObjCProtocolDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id);
+
+ /// Destroy - Call destructors and release memory.
+ virtual void Destroy(ASTContext& C);
+
+ const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const {
+ return ReferencedProtocols;
+ }
+ typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator;
+ protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();}
+ protocol_iterator protocol_end() const { return ReferencedProtocols.end(); }
+ unsigned protocol_size() const { return ReferencedProtocols.size(); }
+
+ /// setProtocolList - Set the list of protocols that this interface
+ /// implements.
+ void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num,
+ ASTContext &C) {
+ ReferencedProtocols.set(List, Num, C);
+ }
+
+ ObjCProtocolDecl *lookupProtocolNamed(IdentifierInfo *PName);
+
+ // Lookup a method. First, we search locally. If a method isn't
+ // found, we search referenced protocols and class categories.
+ ObjCMethodDecl *lookupInstanceMethod(ASTContext &Context, Selector Sel);
+ ObjCMethodDecl *lookupClassMethod(ASTContext &Context, Selector Sel);
+
+ bool isForwardDecl() const { return isForwardProtoDecl; }
+ void setForwardDecl(bool val) { isForwardProtoDecl = val; }
+
+ // Location information, modeled after the Stmt API.
+ SourceLocation getLocStart() const { return getLocation(); } // '@'protocol
+ SourceLocation getLocEnd() const { return EndLoc; }
+ void setLocEnd(SourceLocation LE) { EndLoc = LE; };
+
+ static bool classof(const Decl *D) { return D->getKind() == ObjCProtocol; }
+ static bool classof(const ObjCProtocolDecl *D) { return true; }
+};
+
+/// ObjCClassDecl - Specifies a list of forward class declarations. For example:
+///
+/// @class NSCursor, NSImage, NSPasteboard, NSWindow;
+///
+class ObjCClassDecl : public Decl {
+ ObjCList<ObjCInterfaceDecl> ForwardDecls;
+
+ ObjCClassDecl(DeclContext *DC, SourceLocation L,
+ ObjCInterfaceDecl *const *Elts, unsigned nElts, ASTContext &C);
+ virtual ~ObjCClassDecl() {}
+public:
+
+ /// Destroy - Call destructors and release memory.
+ virtual void Destroy(ASTContext& C);
+
+ static ObjCClassDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ ObjCInterfaceDecl *const *Elts = 0,
+ unsigned nElts = 0);
+
+ typedef ObjCList<ObjCInterfaceDecl>::iterator iterator;
+ iterator begin() const { return ForwardDecls.begin(); }
+ iterator end() const { return ForwardDecls.end(); }
+ unsigned size() const { return ForwardDecls.size(); }
+
+ /// setClassList - Set the list of forward classes.
+ void setClassList(ASTContext &C, ObjCInterfaceDecl*const*List, unsigned Num) {
+ ForwardDecls.set(List, Num, C);
+ }
+
+ static bool classof(const Decl *D) { return D->getKind() == ObjCClass; }
+ static bool classof(const ObjCClassDecl *D) { return true; }
+};
+
+/// ObjCForwardProtocolDecl - Specifies a list of forward protocol declarations.
+/// For example:
+///
+/// @protocol NSTextInput, NSChangeSpelling, NSDraggingInfo;
+///
+class ObjCForwardProtocolDecl : public Decl {
+ ObjCList<ObjCProtocolDecl> ReferencedProtocols;
+
+ ObjCForwardProtocolDecl(DeclContext *DC, SourceLocation L,
+ ObjCProtocolDecl *const *Elts, unsigned nElts,
+ ASTContext &C);
+ virtual ~ObjCForwardProtocolDecl() {}
+
+public:
+ static ObjCForwardProtocolDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ ObjCProtocolDecl *const *Elts = 0,
+ unsigned Num = 0);
+
+ /// Destroy - Call destructors and release memory.
+ virtual void Destroy(ASTContext& C);
+
+ typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator;
+ protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();}
+ protocol_iterator protocol_end() const { return ReferencedProtocols.end(); }
+ unsigned protocol_size() const { return ReferencedProtocols.size(); }
+
+ /// setProtocolList - Set the list of forward protocols.
+ void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num,
+ ASTContext &C) {
+ ReferencedProtocols.set(List, Num, C);
+ }
+ static bool classof(const Decl *D) {
+ return D->getKind() == ObjCForwardProtocol;
+ }
+ static bool classof(const ObjCForwardProtocolDecl *D) { return true; }
+};
+
+/// ObjCCategoryDecl - Represents a category declaration. A category allows
+/// you to add methods to an existing class (without subclassing or modifying
+/// the original class interface or implementation:-). Categories don't allow
+/// you to add instance data. The following example adds "myMethod" to all
+/// NSView's within a process:
+///
+/// @interface NSView (MyViewMethods)
+/// - myMethod;
+/// @end
+///
+/// Cateogries also allow you to split the implementation of a class across
+/// several files (a feature more naturally supported in C++).
+///
+/// Categories were originally inspired by dynamic languages such as Common
+/// Lisp and Smalltalk. More traditional class-based languages (C++, Java)
+/// don't support this level of dynamism, which is both powerful and dangerous.
+///
+class ObjCCategoryDecl : public ObjCContainerDecl {
+ /// Interface belonging to this category
+ ObjCInterfaceDecl *ClassInterface;
+
+ /// referenced protocols in this category.
+ ObjCList<ObjCProtocolDecl> ReferencedProtocols;
+
+ /// Next category belonging to this class.
+ /// FIXME: this should not be a singly-linked list. Move storage elsewhere.
+ ObjCCategoryDecl *NextClassCategory;
+
+ SourceLocation EndLoc; // marks the '>' or identifier.
+
+ ObjCCategoryDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
+ : ObjCContainerDecl(ObjCCategory, DC, L, Id),
+ ClassInterface(0), NextClassCategory(0){
+ }
+public:
+
+ static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id);
+
+ ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
+ const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; }
+ void setClassInterface(ObjCInterfaceDecl *IDecl) { ClassInterface = IDecl; }
+
+ /// setProtocolList - Set the list of protocols that this interface
+ /// implements.
+ void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num,
+ ASTContext &C) {
+ ReferencedProtocols.set(List, Num, C);
+ }
+
+ const ObjCList<ObjCProtocolDecl> &getReferencedProtocols() const {
+ return ReferencedProtocols;
+ }
+
+ typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator;
+ protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();}
+ protocol_iterator protocol_end() const { return ReferencedProtocols.end(); }
+ unsigned protocol_size() const { return ReferencedProtocols.size(); }
+
+ ObjCCategoryDecl *getNextClassCategory() const { return NextClassCategory; }
+ void setNextClassCategory(ObjCCategoryDecl *Cat) {
+ NextClassCategory = Cat;
+ }
+ void insertNextClassCategory() {
+ NextClassCategory = ClassInterface->getCategoryList();
+ ClassInterface->setCategoryList(this);
+ }
+ // Location information, modeled after the Stmt API.
+ SourceLocation getLocStart() const { return getLocation(); } // '@'interface
+ SourceLocation getLocEnd() const { return EndLoc; }
+ void setLocEnd(SourceLocation LE) { EndLoc = LE; };
+
+ static bool classof(const Decl *D) { return D->getKind() == ObjCCategory; }
+ static bool classof(const ObjCCategoryDecl *D) { return true; }
+};
+
+class ObjCImplDecl : public NamedDecl, public DeclContext {
+ /// Class interface for this category implementation
+ ObjCInterfaceDecl *ClassInterface;
+
+ SourceLocation EndLoc;
+
+protected:
+ ObjCImplDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ ObjCInterfaceDecl *classInterface)
+ : NamedDecl(DK, DC, L,
+ classInterface? classInterface->getDeclName()
+ : DeclarationName()),
+ DeclContext(DK), ClassInterface(classInterface) {}
+
+public:
+ virtual ~ObjCImplDecl() {}
+
+ const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; }
+ ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
+ void setClassInterface(ObjCInterfaceDecl *IFace) { ClassInterface = IFace; }
+
+ void addInstanceMethod(ASTContext &Context, ObjCMethodDecl *method) {
+ // FIXME: Context should be set correctly before we get here.
+ method->setLexicalDeclContext(this);
+ addDecl(Context, method);
+ }
+ void addClassMethod(ASTContext &Context, ObjCMethodDecl *method) {
+ // FIXME: Context should be set correctly before we get here.
+ method->setLexicalDeclContext(this);
+ addDecl(Context, method);
+ }
+
+ // Get the local instance/class method declared in this interface.
+ ObjCMethodDecl *getInstanceMethod(ASTContext &Context, Selector Sel) const;
+ ObjCMethodDecl *getClassMethod(ASTContext &Context, Selector Sel) const;
+ ObjCMethodDecl *getMethod(ASTContext &Context, Selector Sel,
+ bool isInstance) const {
+ return isInstance ? getInstanceMethod(Context, Sel)
+ : getClassMethod(Context, Sel);
+ }
+
+ void addPropertyImplementation(ASTContext &Context,
+ ObjCPropertyImplDecl *property);
+
+ ObjCPropertyImplDecl *FindPropertyImplDecl(ASTContext &Context,
+ IdentifierInfo *propertyId) const;
+ ObjCPropertyImplDecl *FindPropertyImplIvarDecl(ASTContext &Context,
+ IdentifierInfo *ivarId) const;
+
+ // Iterator access to properties.
+ typedef specific_decl_iterator<ObjCPropertyImplDecl> propimpl_iterator;
+ propimpl_iterator propimpl_begin(ASTContext &Context) const {
+ return propimpl_iterator(decls_begin(Context));
+ }
+ propimpl_iterator propimpl_end(ASTContext &Context) const {
+ return propimpl_iterator(decls_end(Context));
+ }
+
+ typedef filtered_decl_iterator<ObjCMethodDecl,
+ &ObjCMethodDecl::isInstanceMethod>
+ instmeth_iterator;
+ instmeth_iterator instmeth_begin(ASTContext &Context) const {
+ return instmeth_iterator(decls_begin(Context));
+ }
+ instmeth_iterator instmeth_end(ASTContext &Context) const {
+ return instmeth_iterator(decls_end(Context));
+ }
+
+ typedef filtered_decl_iterator<ObjCMethodDecl,
+ &ObjCMethodDecl::isClassMethod>
+ classmeth_iterator;
+ classmeth_iterator classmeth_begin(ASTContext &Context) const {
+ return classmeth_iterator(decls_begin(Context));
+ }
+ classmeth_iterator classmeth_end(ASTContext &Context) const {
+ return classmeth_iterator(decls_end(Context));
+ }
+
+ // Location information, modeled after the Stmt API.
+ SourceLocation getLocStart() const { return getLocation(); }
+ SourceLocation getLocEnd() const { return EndLoc; }
+ void setLocEnd(SourceLocation LE) { EndLoc = LE; };
+};
+
+/// ObjCCategoryImplDecl - An object of this class encapsulates a category
+/// @implementation declaration. If a category class has declaration of a
+/// property, its implementation must be specified in the category's
+/// @implementation declaration. Example:
+/// @interface I @end
+/// @interface I(CATEGORY)
+/// @property int p1, d1;
+/// @end
+/// @implementation I(CATEGORY)
+/// @dynamic p1,d1;
+/// @end
+///
+/// ObjCCategoryImplDecl
+class ObjCCategoryImplDecl : public ObjCImplDecl {
+ // Category name
+ IdentifierInfo *Id;
+
+ ObjCCategoryImplDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
+ ObjCInterfaceDecl *classInterface)
+ : ObjCImplDecl(ObjCCategoryImpl, DC, L, classInterface), Id(Id) {}
+public:
+ static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ ObjCInterfaceDecl *classInterface);
+
+ /// getIdentifier - Get the identifier that names the class
+ /// interface associated with this implementation.
+ IdentifierInfo *getIdentifier() const {
+ return Id;
+ }
+ void setIdentifier(IdentifierInfo *II) { Id = II; }
+
+ /// getNameAsCString - Get the name of identifier for the class
+ /// interface associated with this implementation as a C string
+ /// (const char*).
+ const char *getNameAsCString() const {
+ return Id ? Id->getName() : "";
+ }
+
+ /// @brief Get the name of the class associated with this interface.
+ std::string getNameAsString() const {
+ return Id ? Id->getName() : "";
+ }
+
+ static bool classof(const Decl *D) { return D->getKind() == ObjCCategoryImpl;}
+ static bool classof(const ObjCCategoryImplDecl *D) { return true; }
+ static DeclContext *castToDeclContext(const ObjCCategoryImplDecl *D) {
+ return static_cast<DeclContext *>(const_cast<ObjCCategoryImplDecl*>(D));
+ }
+ static ObjCCategoryImplDecl *castFromDeclContext(const DeclContext *DC) {
+ return static_cast<ObjCCategoryImplDecl *>(const_cast<DeclContext*>(DC));
+ }
+};
+
+/// ObjCImplementationDecl - Represents a class definition - this is where
+/// method definitions are specified. For example:
+///
+/// @code
+/// @implementation MyClass
+/// - (void)myMethod { /* do something */ }
+/// @end
+/// @endcode
+///
+/// Typically, instance variables are specified in the class interface,
+/// *not* in the implementation. Nevertheless (for legacy reasons), we
+/// allow instance variables to be specified in the implementation. When
+/// specified, they need to be *identical* to the interface.
+///
+class ObjCImplementationDecl : public ObjCImplDecl {
+ /// Implementation Class's super class.
+ ObjCInterfaceDecl *SuperClass;
+
+ ObjCImplementationDecl(DeclContext *DC, SourceLocation L,
+ ObjCInterfaceDecl *classInterface,
+ ObjCInterfaceDecl *superDecl)
+ : ObjCImplDecl(ObjCImplementation, DC, L, classInterface),
+ SuperClass(superDecl){}
+public:
+ static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ ObjCInterfaceDecl *classInterface,
+ ObjCInterfaceDecl *superDecl);
+
+ /// getIdentifier - Get the identifier that names the class
+ /// interface associated with this implementation.
+ IdentifierInfo *getIdentifier() const {
+ return getClassInterface()->getIdentifier();
+ }
+
+ /// getNameAsCString - Get the name of identifier for the class
+ /// interface associated with this implementation as a C string
+ /// (const char*).
+ const char *getNameAsCString() const {
+ assert(getIdentifier() && "Name is not a simple identifier");
+ return getIdentifier()->getName();
+ }
+
+ /// @brief Get the name of the class associated with this interface.
+ std::string getNameAsString() const {
+ return getClassInterface()->getNameAsString();
+ }
+
+ const ObjCInterfaceDecl *getSuperClass() const { return SuperClass; }
+ ObjCInterfaceDecl *getSuperClass() { return SuperClass; }
+
+ void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; }
+
+ typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator;
+ ivar_iterator ivar_begin(ASTContext &Context) const {
+ return ivar_iterator(decls_begin(Context));
+ }
+ ivar_iterator ivar_end(ASTContext &Context) const {
+ return ivar_iterator(decls_end(Context));
+ }
+ unsigned ivar_size(ASTContext &Context) const {
+ return std::distance(ivar_begin(Context), ivar_end(Context));
+ }
+ bool ivar_empty(ASTContext &Context) const {
+ return ivar_begin(Context) == ivar_end(Context);
+ }
+
+ static bool classof(const Decl *D) {
+ return D->getKind() == ObjCImplementation;
+ }
+ static bool classof(const ObjCImplementationDecl *D) { return true; }
+ static DeclContext *castToDeclContext(const ObjCImplementationDecl *D) {
+ return static_cast<DeclContext *>(const_cast<ObjCImplementationDecl*>(D));
+ }
+ static ObjCImplementationDecl *castFromDeclContext(const DeclContext *DC) {
+ return static_cast<ObjCImplementationDecl *>(const_cast<DeclContext*>(DC));
+ }
+};
+
+/// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is
+/// declared as @compatibility_alias alias class.
+class ObjCCompatibleAliasDecl : public NamedDecl {
+ /// Class that this is an alias of.
+ ObjCInterfaceDecl *AliasedClass;
+
+ ObjCCompatibleAliasDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
+ ObjCInterfaceDecl* aliasedClass)
+ : NamedDecl(ObjCCompatibleAlias, DC, L, Id), AliasedClass(aliasedClass) {}
+public:
+ static ObjCCompatibleAliasDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ ObjCInterfaceDecl* aliasedClass);
+
+ const ObjCInterfaceDecl *getClassInterface() const { return AliasedClass; }
+ ObjCInterfaceDecl *getClassInterface() { return AliasedClass; }
+ void setClassInterface(ObjCInterfaceDecl *D) { AliasedClass = D; }
+
+ static bool classof(const Decl *D) {
+ return D->getKind() == ObjCCompatibleAlias;
+ }
+ static bool classof(const ObjCCompatibleAliasDecl *D) { return true; }
+
+};
+
+/// ObjCPropertyDecl - Represents one property declaration in an interface.
+/// For example:
+/// @property (assign, readwrite) int MyProperty;
+///
+class ObjCPropertyDecl : public NamedDecl {
+public:
+ enum PropertyAttributeKind {
+ OBJC_PR_noattr = 0x00,
+ OBJC_PR_readonly = 0x01,
+ OBJC_PR_getter = 0x02,
+ OBJC_PR_assign = 0x04,
+ OBJC_PR_readwrite = 0x08,
+ OBJC_PR_retain = 0x10,
+ OBJC_PR_copy = 0x20,
+ OBJC_PR_nonatomic = 0x40,
+ OBJC_PR_setter = 0x80
+ };
+
+ enum SetterKind { Assign, Retain, Copy };
+ enum PropertyControl { None, Required, Optional };
+private:
+ QualType DeclType;
+ unsigned PropertyAttributes : 8;
+
+ // @required/@optional
+ unsigned PropertyImplementation : 2;
+
+ Selector GetterName; // getter name of NULL if no getter
+ Selector SetterName; // setter name of NULL if no setter
+
+ ObjCMethodDecl *GetterMethodDecl; // Declaration of getter instance method
+ ObjCMethodDecl *SetterMethodDecl; // Declaration of setter instance method
+ ObjCIvarDecl *PropertyIvarDecl; // Synthesize ivar for this property
+
+ ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
+ QualType T)
+ : NamedDecl(ObjCProperty, DC, L, Id), DeclType(T),
+ PropertyAttributes(OBJC_PR_noattr), PropertyImplementation(None),
+ GetterName(Selector()),
+ SetterName(Selector()),
+ GetterMethodDecl(0), SetterMethodDecl(0) , PropertyIvarDecl(0) {}
+public:
+ static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ IdentifierInfo *Id, QualType T,
+ PropertyControl propControl = None);
+ QualType getType() const { return DeclType; }
+ void setType(QualType T) { DeclType = T; }
+
+ PropertyAttributeKind getPropertyAttributes() const {
+ return PropertyAttributeKind(PropertyAttributes);
+ }
+ void setPropertyAttributes(PropertyAttributeKind PRVal) {
+ PropertyAttributes |= PRVal;
+ }
+
+ void makeitReadWriteAttribute(void) {
+ PropertyAttributes &= ~OBJC_PR_readonly;
+ PropertyAttributes |= OBJC_PR_readwrite;
+ }
+
+ // Helper methods for accessing attributes.
+
+ /// isReadOnly - Return true iff the property has a setter.
+ bool isReadOnly() const {
+ return (PropertyAttributes & OBJC_PR_readonly);
+ }
+
+ /// 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)
+ return Retain;
+ if (PropertyAttributes & OBJC_PR_copy)
+ return Copy;
+ return Assign;
+ }
+
+ Selector getGetterName() const { return GetterName; }
+ void setGetterName(Selector Sel) { GetterName = Sel; }
+
+ Selector getSetterName() const { return SetterName; }
+ void setSetterName(Selector Sel) { SetterName = Sel; }
+
+ ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; }
+ void setGetterMethodDecl(ObjCMethodDecl *gDecl) { GetterMethodDecl = gDecl; }
+
+ ObjCMethodDecl *getSetterMethodDecl() const { return SetterMethodDecl; }
+ void setSetterMethodDecl(ObjCMethodDecl *gDecl) { SetterMethodDecl = gDecl; }
+
+ // Related to @optional/@required declared in @protocol
+ void setPropertyImplementation(PropertyControl pc) {
+ PropertyImplementation = pc;
+ }
+ PropertyControl getPropertyImplementation() const {
+ return PropertyControl(PropertyImplementation);
+ }
+
+ void setPropertyIvarDecl(ObjCIvarDecl *Ivar) {
+ PropertyIvarDecl = Ivar;
+ }
+ ObjCIvarDecl *getPropertyIvarDecl() const {
+ return PropertyIvarDecl;
+ }
+
+ static bool classof(const Decl *D) {
+ return D->getKind() == ObjCProperty;
+ }
+ static bool classof(const ObjCPropertyDecl *D) { return true; }
+};
+
+/// ObjCPropertyImplDecl - Represents implementation declaration of a property
+/// in a class or category implementation block. For example:
+/// @synthesize prop1 = ivar1;
+///
+class ObjCPropertyImplDecl : public Decl {
+public:
+ enum Kind {
+ Synthesize,
+ Dynamic
+ };
+private:
+ SourceLocation AtLoc; // location of @synthesize or @dynamic
+ /// Property declaration being implemented
+ ObjCPropertyDecl *PropertyDecl;
+
+ /// Null for @dynamic. Required for @synthesize.
+ ObjCIvarDecl *PropertyIvarDecl;
+
+ ObjCPropertyImplDecl(DeclContext *DC, SourceLocation atLoc, SourceLocation L,
+ ObjCPropertyDecl *property,
+ Kind PK,
+ ObjCIvarDecl *ivarDecl)
+ : Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc),
+ PropertyDecl(property), PropertyIvarDecl(ivarDecl) {
+ assert (PK == Dynamic || PropertyIvarDecl);
+ }
+
+public:
+ static ObjCPropertyImplDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation atLoc, SourceLocation L,
+ ObjCPropertyDecl *property,
+ Kind PK,
+ ObjCIvarDecl *ivarDecl);
+
+ SourceLocation getLocStart() const { return AtLoc; }
+ void setAtLoc(SourceLocation Loc) { AtLoc = Loc; }
+
+ ObjCPropertyDecl *getPropertyDecl() const {
+ return PropertyDecl;
+ }
+ void setPropertyDecl(ObjCPropertyDecl *Prop) { PropertyDecl = Prop; }
+
+ Kind getPropertyImplementation() const {
+ return PropertyIvarDecl ? Synthesize : Dynamic;
+ }
+
+ ObjCIvarDecl *getPropertyIvarDecl() const {
+ return PropertyIvarDecl;
+ }
+ void setPropertyIvarDecl(ObjCIvarDecl *Ivar) { PropertyIvarDecl = Ivar; }
+
+ static bool classof(const Decl *D) {
+ return D->getKind() == ObjCPropertyImpl;
+ }
+ static bool classof(const ObjCPropertyImplDecl *D) { return true; }
+};
+
+} // end namespace clang
+#endif
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
new file mode 100644
index 000000000000..226af3411d55
--- /dev/null
+++ b/include/clang/AST/DeclTemplate.h
@@ -0,0 +1,859 @@
+//===-- DeclTemplate.h - Classes for representing C++ templates -*- 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 C++ template declaration subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_DECLTEMPLATE_H
+#define LLVM_CLANG_AST_DECLTEMPLATE_H
+
+#include "clang/AST/DeclCXX.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/FoldingSet.h"
+
+namespace clang {
+
+class TemplateParameterList;
+class TemplateDecl;
+class FunctionTemplateDecl;
+class ClassTemplateDecl;
+class ClassTemplatePartialSpecializationDecl;
+class TemplateTypeParmDecl;
+class NonTypeTemplateParmDecl;
+class TemplateTemplateParmDecl;
+
+/// TemplateParameterList - Stores a list of template parameters for a
+/// TemplateDecl and its derived classes.
+class TemplateParameterList {
+ /// The location of the 'template' keyword.
+ SourceLocation TemplateLoc;
+
+ /// The locations of the '<' and '>' angle brackets.
+ SourceLocation LAngleLoc, RAngleLoc;
+
+ /// The number of template parameters in this template
+ /// parameter list.
+ unsigned NumParams;
+
+ TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
+ Decl **Params, unsigned NumParams,
+ SourceLocation RAngleLoc);
+
+public:
+ static TemplateParameterList *Create(ASTContext &C,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ Decl **Params,
+ unsigned NumParams,
+ SourceLocation RAngleLoc);
+
+ /// iterator - Iterates through the template parameters in this list.
+ typedef Decl** iterator;
+
+ /// const_iterator - Iterates through the template parameters in this list.
+ typedef Decl* const* const_iterator;
+
+ iterator begin() { return reinterpret_cast<Decl **>(this + 1); }
+ const_iterator begin() const {
+ return reinterpret_cast<Decl * const *>(this + 1);
+ }
+ iterator end() { return begin() + NumParams; }
+ const_iterator end() const { return begin() + NumParams; }
+
+ unsigned size() const { return NumParams; }
+
+ const Decl* getParam(unsigned Idx) const {
+ assert(Idx < size() && "Template parameter index out-of-range");
+ return begin()[Idx];
+ }
+
+ /// \btief Returns the minimum number of arguments needed to form a
+ /// template specialization. This may be fewer than the number of
+ /// template parameters, if some of the parameters have default
+ /// arguments.
+ unsigned getMinRequiredArguments() const;
+
+ SourceLocation getTemplateLoc() const { return TemplateLoc; }
+ SourceLocation getLAngleLoc() const { return LAngleLoc; }
+ SourceLocation getRAngleLoc() const { return RAngleLoc; }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(TemplateLoc, RAngleLoc);
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// Kinds of Templates
+//===----------------------------------------------------------------------===//
+
+/// TemplateDecl - The base class of all kinds of template declarations (e.g.,
+/// class, function, etc.). The TemplateDecl class stores the list of template
+/// parameters and a reference to the templated scoped declaration: the
+/// underlying AST node.
+class TemplateDecl : public NamedDecl {
+protected:
+ // This is probably never used.
+ TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ DeclarationName Name)
+ : NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(0)
+ { }
+
+ // Construct a template decl with the given name and parameters.
+ // Used when there is not templated element (tt-params, alias?).
+ TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ DeclarationName Name, TemplateParameterList *Params)
+ : NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(Params)
+ { }
+
+ // Construct a template decl with name, parameters, and templated element.
+ TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ DeclarationName Name, TemplateParameterList *Params,
+ NamedDecl *Decl)
+ : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl),
+ TemplateParams(Params) { }
+public:
+ ~TemplateDecl();
+
+ /// Get the list of template parameters
+ TemplateParameterList *getTemplateParameters() const {
+ return TemplateParams;
+ }
+
+ /// Get the underlying, templated declaration.
+ NamedDecl *getTemplatedDecl() const { return TemplatedDecl; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() >= TemplateFirst && D->getKind() <= TemplateLast;
+ }
+ static bool classof(const TemplateDecl *D) { return true; }
+ static bool classof(const FunctionTemplateDecl *D) { return true; }
+ static bool classof(const ClassTemplateDecl *D) { return true; }
+ static bool classof(const TemplateTemplateParmDecl *D) { return true; }
+
+protected:
+ NamedDecl *TemplatedDecl;
+ TemplateParameterList* TemplateParams;
+};
+
+/// Declaration of a template function.
+class FunctionTemplateDecl : public TemplateDecl {
+protected:
+ FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params, NamedDecl *Decl)
+ : TemplateDecl(FunctionTemplate, DC, L, Name, Params, Decl) { }
+public:
+ /// Get the underling function declaration of the template.
+ FunctionDecl *getTemplatedDecl() const {
+ return static_cast<FunctionDecl*>(TemplatedDecl);
+ }
+
+ /// Create a template function node.
+ static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ DeclarationName Name,
+ TemplateParameterList *Params,
+ NamedDecl *Decl);
+
+ // Implement isa/cast/dyncast support
+ static bool classof(const Decl *D)
+ { return D->getKind() == FunctionTemplate; }
+ static bool classof(const FunctionTemplateDecl *D)
+ { return true; }
+};
+
+//===----------------------------------------------------------------------===//
+// Kinds of Template Parameters
+//===----------------------------------------------------------------------===//
+
+/// The TemplateParmPosition class defines the position of a template parameter
+/// within a template parameter list. Because template parameter can be listed
+/// sequentially for out-of-line template members, each template parameter is
+/// given a Depth - the nesting of template parameter scopes - and a Position -
+/// the occurrence within the parameter list.
+/// This class is inheritedly privately by different kinds of template
+/// parameters and is not part of the Decl hierarchy. Just a facility.
+class TemplateParmPosition
+{
+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"); */ }
+
+ TemplateParmPosition(unsigned D, unsigned P)
+ : Depth(D), Position(P)
+ { }
+
+ // FIXME: These probably don't need to be ints. int:5 for depth, int:8 for
+ // position? Maybe?
+ unsigned Depth;
+ unsigned Position;
+
+public:
+ /// Get the nesting depth of the template parameter.
+ unsigned getDepth() const { return Depth; }
+
+ /// Get the position of the template parameter within its parameter list.
+ unsigned getPosition() const { return Position; }
+};
+
+/// TemplateTypeParmDecl - Declaration of a template type parameter,
+/// e.g., "T" in
+/// @code
+/// template<typename T> class vector;
+/// @endcode
+class TemplateTypeParmDecl : public TypeDecl {
+ /// \brief Whether this template type parameter was declaration with
+ /// the 'typename' keyword. If false, it was declared with the
+ /// 'class' keyword.
+ bool Typename : 1;
+
+ /// \brief Whether this template type parameter inherited its
+ /// default argument.
+ bool InheritedDefault : 1;
+
+ /// \brief The location of the default argument, if any.
+ SourceLocation DefaultArgumentLoc;
+
+ /// \brief The default template argument, if any.
+ QualType DefaultArgument;
+
+ TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
+ bool Typename, QualType Type)
+ : TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename),
+ InheritedDefault(false), DefaultArgument() {
+ TypeForDecl = Type.getTypePtr();
+ }
+
+public:
+ static TemplateTypeParmDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, unsigned D, unsigned P,
+ IdentifierInfo *Id, bool Typename);
+
+ /// \brief Whether this template type parameter was declared with
+ /// the 'typename' keyword. If not, it was declared with the 'class'
+ /// keyword.
+ bool wasDeclaredWithTypename() const { return Typename; }
+
+ /// \brief Determine whether this template parameter has a default
+ /// argument.
+ bool hasDefaultArgument() const { return !DefaultArgument.isNull(); }
+
+ /// \brief Retrieve the default argument, if any.
+ QualType getDefaultArgument() const { return DefaultArgument; }
+
+ /// \brief Retrieve the location of the default argument, if any.
+ SourceLocation getDefaultArgumentLoc() const { return DefaultArgumentLoc; }
+
+ /// \brief Determines whether the default argument was inherited
+ /// from a previous declaration of this template.
+ bool defaultArgumentWasInherited() const { return InheritedDefault; }
+
+ /// \brief Set the default argument for this template parameter, and
+ /// whether that default argument was inherited from another
+ /// declaration.
+ void setDefaultArgument(QualType DefArg, SourceLocation DefArgLoc,
+ bool Inherited) {
+ DefaultArgument = DefArg;
+ DefaultArgumentLoc = DefArgLoc;
+ InheritedDefault = Inherited;
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() == TemplateTypeParm;
+ }
+ static bool classof(const TemplateTypeParmDecl *D) { return true; }
+};
+
+/// NonTypeTemplateParmDecl - Declares a non-type template parameter,
+/// e.g., "Size" in
+/// @code
+/// template<int Size> class array { };
+/// @endcode
+class NonTypeTemplateParmDecl
+ : public VarDecl, protected TemplateParmPosition {
+ /// \brief The default template argument, if any.
+ Expr *DefaultArgument;
+
+ NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
+ unsigned P, IdentifierInfo *Id, QualType T,
+ SourceLocation TSSL = SourceLocation())
+ : VarDecl(NonTypeTemplateParm, DC, L, Id, T, VarDecl::None, TSSL),
+ TemplateParmPosition(D, P), DefaultArgument(0)
+ { }
+
+public:
+ static NonTypeTemplateParmDecl *
+ Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
+ unsigned P, IdentifierInfo *Id, QualType T,
+ SourceLocation TypeSpecStartLoc = SourceLocation());
+
+ using TemplateParmPosition::getDepth;
+ using TemplateParmPosition::getPosition;
+
+ /// \brief Determine whether this template parameter has a default
+ /// argument.
+ bool hasDefaultArgument() const { return DefaultArgument; }
+
+ /// \brief Retrieve the default argument, if any.
+ Expr *getDefaultArgument() const { return DefaultArgument; }
+
+ /// \brief Retrieve the location of the default argument, if any.
+ SourceLocation getDefaultArgumentLoc() const;
+
+ /// \brief Set the default argument for this template parameter.
+ void setDefaultArgument(Expr *DefArg) {
+ DefaultArgument = DefArg;
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() == NonTypeTemplateParm;
+ }
+ static bool classof(const NonTypeTemplateParmDecl *D) { return true; }
+};
+
+/// TemplateTemplateParmDecl - Declares a template template parameter,
+/// e.g., "T" in
+/// @code
+/// template <template <typename> class T> class container { };
+/// @endcode
+/// A template template parameter is a TemplateDecl because it defines the
+/// name of a template and the template parameters allowable for substitution.
+class TemplateTemplateParmDecl
+ : public TemplateDecl, protected TemplateParmPosition {
+
+ /// \brief The default template argument, if any.
+ Expr *DefaultArgument;
+
+ TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
+ unsigned D, unsigned P,
+ IdentifierInfo *Id, TemplateParameterList *Params)
+ : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
+ TemplateParmPosition(D, P), DefaultArgument(0)
+ { }
+
+public:
+ static TemplateTemplateParmDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, unsigned D,
+ unsigned P, IdentifierInfo *Id,
+ TemplateParameterList *Params);
+
+ using TemplateParmPosition::getDepth;
+ using TemplateParmPosition::getPosition;
+
+ /// \brief Determine whether this template parameter has a default
+ /// argument.
+ bool hasDefaultArgument() const { return DefaultArgument; }
+
+ /// \brief Retrieve the default argument, if any.
+ Expr *getDefaultArgument() const { return DefaultArgument; }
+
+ /// \brief Retrieve the location of the default argument, if any.
+ SourceLocation getDefaultArgumentLoc() const;
+
+ /// \brief Set the default argument for this template parameter.
+ void setDefaultArgument(Expr *DefArg) {
+ DefaultArgument = DefArg;
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() == TemplateTemplateParm;
+ }
+ static bool classof(const TemplateTemplateParmDecl *D) { return true; }
+};
+
+/// \brief Represents a template argument within a class template
+/// specialization.
+class TemplateArgument {
+ union {
+ uintptr_t TypeOrValue;
+ struct {
+ char Value[sizeof(llvm::APSInt)];
+ void *Type;
+ } Integer;
+ };
+
+ /// \brief Location of the beginning of this template argument.
+ SourceLocation StartLoc;
+
+public:
+ /// \brief The type of template argument we're storing.
+ enum ArgKind {
+ /// The template argument is a type. It's value is stored in the
+ /// TypeOrValue field.
+ Type = 0,
+ /// The template argument is a declaration
+ Declaration = 1,
+ /// The template argument is an integral value stored in an llvm::APSInt.
+ Integral = 2,
+ /// The template argument is a value- or type-dependent expression
+ /// stored in an Expr*.
+ Expression = 3
+ } Kind;
+
+ /// \brief Construct an empty, invalid template argument.
+ TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Type) { }
+
+ /// \brief Construct a template type argument.
+ TemplateArgument(SourceLocation Loc, QualType T) : Kind(Type) {
+ TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+ StartLoc = Loc;
+ }
+
+ /// \brief Construct a template argument that refers to a
+ /// declaration, which is either an external declaration or a
+ /// template declaration.
+ TemplateArgument(SourceLocation Loc, Decl *D) : Kind(Declaration) {
+ // FIXME: Need to be sure we have the "canonical" declaration!
+ TypeOrValue = reinterpret_cast<uintptr_t>(D);
+ StartLoc = Loc;
+ }
+
+ /// \brief Construct an integral constant template argument.
+ TemplateArgument(SourceLocation Loc, const llvm::APSInt &Value,
+ QualType Type)
+ : Kind(Integral) {
+ new (Integer.Value) llvm::APSInt(Value);
+ Integer.Type = Type.getAsOpaquePtr();
+ StartLoc = Loc;
+ }
+
+ /// \brief Construct a template argument that is an expression.
+ ///
+ /// This form of template argument only occurs in template argument
+ /// lists used for dependent types and for expression; it will not
+ /// occur in a non-dependent, canonical template argument list.
+ TemplateArgument(Expr *E);
+
+ /// \brief Copy constructor for a template argument.
+ TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
+ if (Kind == Integral) {
+ new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
+ Integer.Type = Other.Integer.Type;
+ }
+ else
+ TypeOrValue = Other.TypeOrValue;
+ StartLoc = Other.StartLoc;
+ }
+
+ TemplateArgument& operator=(const TemplateArgument& Other) {
+ // FIXME: Does not provide the strong guarantee for exception
+ // safety.
+ using llvm::APSInt;
+
+ if (Kind == Other.Kind && Kind == Integral) {
+ // Copy integral values.
+ *this->getAsIntegral() = *Other.getAsIntegral();
+ Integer.Type = Other.Integer.Type;
+ } else {
+ // Destroy the current integral value, if that's what we're holding.
+ if (Kind == Integral)
+ getAsIntegral()->~APSInt();
+
+ Kind = Other.Kind;
+
+ if (Other.Kind == Integral) {
+ new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
+ Integer.Type = Other.Integer.Type;
+ } else
+ TypeOrValue = Other.TypeOrValue;
+ }
+ StartLoc = Other.StartLoc;
+
+ return *this;
+ }
+
+ ~TemplateArgument() {
+ using llvm::APSInt;
+
+ if (Kind == Integral)
+ getAsIntegral()->~APSInt();
+ }
+
+ /// \brief Return the kind of stored template argument.
+ ArgKind getKind() const { return Kind; }
+
+ /// \brief Retrieve the template argument as a type.
+ QualType getAsType() const {
+ if (Kind != Type)
+ return QualType();
+
+ return QualType::getFromOpaquePtr(
+ reinterpret_cast<void*>(TypeOrValue));
+ }
+
+ /// \brief Retrieve the template argument as a declaration.
+ Decl *getAsDecl() const {
+ if (Kind != Declaration)
+ return 0;
+ return reinterpret_cast<Decl *>(TypeOrValue);
+ }
+
+ /// \brief Retrieve the template argument as an integral value.
+ llvm::APSInt *getAsIntegral() {
+ if (Kind != Integral)
+ return 0;
+ return reinterpret_cast<llvm::APSInt*>(&Integer.Value[0]);
+ }
+
+ const llvm::APSInt *getAsIntegral() const {
+ return const_cast<TemplateArgument*>(this)->getAsIntegral();
+ }
+
+ /// \brief Retrieve the type of the integral value.
+ QualType getIntegralType() const {
+ if (Kind != Integral)
+ return QualType();
+
+ return QualType::getFromOpaquePtr(Integer.Type);
+ }
+
+ /// \brief Retrieve the template argument as an expression.
+ Expr *getAsExpr() const {
+ if (Kind != Expression)
+ return 0;
+
+ return reinterpret_cast<Expr *>(TypeOrValue);
+ }
+
+ /// \brief Retrieve the location where the template argument starts.
+ SourceLocation getLocation() const { return StartLoc; }
+
+ /// \brief Used to insert TemplateArguments into FoldingSets.
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(Kind);
+ switch (Kind) {
+ case Type:
+ getAsType().Profile(ID);
+ break;
+
+ case Declaration:
+ ID.AddPointer(getAsDecl()); // FIXME: Must be canonical!
+ break;
+
+ case Integral:
+ getAsIntegral()->Profile(ID);
+ getIntegralType().Profile(ID);
+ break;
+
+ case Expression:
+ // FIXME: We need a canonical representation of expressions.
+ ID.AddPointer(getAsExpr());
+ break;
+ }
+ }
+};
+
+/// \brief A template argument list.
+///
+/// FIXME: In the future, this class will be extended to support
+/// variadic templates and member templates, which will make some of
+/// the function names below make more sense.
+class TemplateArgumentList {
+ /// \brief The template argument list.
+ ///
+ /// The integer value will be non-zero to indicate that this
+ /// template argument list does not own the pointer.
+ llvm::PointerIntPair<TemplateArgument *, 1> Arguments;
+
+ /// \brief The number of template arguments in this template
+ /// argument list.
+ unsigned NumArguments;
+
+
+public:
+ TemplateArgumentList(ASTContext &Context,
+ TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ bool CopyArgs);
+
+ ~TemplateArgumentList();
+
+ /// \brief Retrieve the template argument at a given index.
+ const TemplateArgument &get(unsigned Idx) const {
+ assert(Idx < NumArguments && "Invalid template argument index");
+ return getFlatArgumentList()[Idx];
+ }
+
+ /// \brief Retrieve the template argument at a given index.
+ TemplateArgument &get(unsigned Idx) {
+ assert(Idx < NumArguments && "Invalid template argument index");
+ return getFlatArgumentList()[Idx];
+ }
+
+ /// \brief Retrieve the template argument at a given index.
+ TemplateArgument &operator[](unsigned Idx) { return get(Idx); }
+ const TemplateArgument &operator[](unsigned Idx) const { return get(Idx); }
+
+ /// \brief Retrieve the number of template arguments in this
+ /// template argument list.
+ unsigned size() const { return NumArguments; }
+
+ /// \brief Retrieve the number of template arguments in the
+ /// flattened template argument list.
+ unsigned flat_size() const { return NumArguments; }
+
+ /// \brief Retrieve the flattened template argument list.
+ TemplateArgument *getFlatArgumentList() {
+ return Arguments.getPointer();
+ }
+ const TemplateArgument *getFlatArgumentList() const {
+ return Arguments.getPointer();
+ }
+};
+
+// \brief Describes the kind of template specialization that a
+// particular template specialization declaration represents.
+enum TemplateSpecializationKind {
+ /// This template specialization was formed from a template-id but
+ /// has not yet been declared, defined, or instantiated.
+ TSK_Undeclared = 0,
+ /// This template specialization was declared or defined by an
+ /// explicit specialization (C++ [temp.expl.spec]) or partial
+ /// specialization (C++ [temp.class.spec]).
+ TSK_ExplicitSpecialization,
+ /// This template specialization was implicitly instantiated from a
+ /// template. (C++ [temp.inst]).
+ TSK_ImplicitInstantiation,
+ /// This template specialization was instantiated from a template
+ /// due to an explicit instantiation request (C++ [temp.explicit]).
+ TSK_ExplicitInstantiation
+};
+
+/// \brief Represents a class template specialization, which refers to
+/// a class template with a given set of template arguments.
+///
+/// Class template specializations represent both explicit
+/// specialization of class templates, as in the example below, and
+/// implicit instantiations of class templates.
+///
+/// \code
+/// template<typename T> class array;
+///
+/// template<>
+/// class array<bool> { }; // class template specialization array<bool>
+/// \endcode
+class ClassTemplateSpecializationDecl
+ : public CXXRecordDecl, public llvm::FoldingSetNode {
+ /// \brief The template that this specialization specializes
+ ClassTemplateDecl *SpecializedTemplate;
+
+ /// \brief The template arguments used to describe this specialization.
+ TemplateArgumentList TemplateArgs;
+
+ /// \brief The kind of specialization this declaration refers to.
+ /// Really a value of type TemplateSpecializationKind.
+ unsigned SpecializationKind : 2;
+
+protected:
+ ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
+ DeclContext *DC, SourceLocation L,
+ ClassTemplateDecl *SpecializedTemplate,
+ TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+
+public:
+ static ClassTemplateSpecializationDecl *
+ Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
+ ClassTemplateDecl *SpecializedTemplate,
+ TemplateArgument *TemplateArgs, unsigned NumTemplateArgs,
+ ClassTemplateSpecializationDecl *PrevDecl);
+
+ /// \brief Retrieve the template that this specialization specializes.
+ ClassTemplateDecl *getSpecializedTemplate() const {
+ return SpecializedTemplate;
+ }
+
+ const TemplateArgumentList &getTemplateArgs() const {
+ return TemplateArgs;
+ }
+
+ /// \brief Determine the kind of specialization that this
+ /// declaration represents.
+ TemplateSpecializationKind getSpecializationKind() const {
+ return static_cast<TemplateSpecializationKind>(SpecializationKind);
+ }
+
+ void setSpecializationKind(TemplateSpecializationKind TSK) {
+ SpecializationKind = TSK;
+ }
+
+ /// \brief Sets the type of this specialization as it was written by
+ /// the user. This will be a class template specialization type.
+ void setTypeAsWritten(QualType T) {
+ TypeForDecl = T.getTypePtr();
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Profile(ID, TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size());
+ }
+
+ static void
+ Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg)
+ TemplateArgs[Arg].Profile(ID);
+ }
+
+ static bool classof(const Decl *D) {
+ return D->getKind() == ClassTemplateSpecialization ||
+ D->getKind() == ClassTemplatePartialSpecialization;
+ }
+
+ static bool classof(const ClassTemplateSpecializationDecl *) {
+ return true;
+ }
+
+ static bool classof(const ClassTemplatePartialSpecializationDecl *) {
+ return true;
+ }
+};
+
+class ClassTemplatePartialSpecializationDecl
+ : public ClassTemplateSpecializationDecl
+{
+ /// \brief The list of template parameters
+ TemplateParameterList* TemplateParams;
+
+ ClassTemplatePartialSpecializationDecl(ASTContext &Context,
+ DeclContext *DC, SourceLocation L,
+ TemplateParameterList *Params,
+ ClassTemplateDecl *SpecializedTemplate,
+ TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs)
+ : ClassTemplateSpecializationDecl(Context, ClassTemplatePartialSpecialization,
+ DC, L, SpecializedTemplate, TemplateArgs,
+ NumTemplateArgs),
+ TemplateParams(Params) { }
+
+public:
+ static ClassTemplatePartialSpecializationDecl *
+ Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
+ TemplateParameterList *Params,
+ ClassTemplateDecl *SpecializedTemplate,
+ TemplateArgument *TemplateArgs, unsigned NumTemplateArgs,
+ ClassTemplatePartialSpecializationDecl *PrevDecl);
+
+ /// Get the list of template parameters
+ TemplateParameterList *getTemplateParameters() const {
+ return TemplateParams;
+ }
+
+ // FIXME: Add Profile support!
+
+ static bool classof(const Decl *D) {
+ return D->getKind() == ClassTemplatePartialSpecialization;
+ }
+
+ static bool classof(const ClassTemplatePartialSpecializationDecl *) {
+ return true;
+ }
+};
+
+/// Declaration of a class template.
+class ClassTemplateDecl : public TemplateDecl {
+protected:
+ /// \brief Data that is common to all of the declarations of a given
+ /// class template.
+ struct Common {
+ /// \brief The class template specializations for this class
+ /// template, including explicit specializations and instantiations.
+ llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations;
+
+ /// \brief The class template partial specializations for this class
+ /// template.
+ llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>
+ PartialSpecializations;
+
+ /// \brief The injected-class-name type for this class template.
+ QualType InjectedClassNameType;
+ };
+
+ /// \brief Previous declaration of this class template.
+ ClassTemplateDecl *PreviousDeclaration;
+
+ /// \brief Pointer to the data that is common to all of the
+ /// declarations of this class template.
+ ///
+ /// The first declaration of a class template (e.g., the declaration
+ /// with no "previous declaration") owns this pointer.
+ Common *CommonPtr;
+
+ ClassTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params, NamedDecl *Decl,
+ ClassTemplateDecl *PrevDecl, Common *CommonPtr)
+ : TemplateDecl(ClassTemplate, DC, L, Name, Params, Decl),
+ PreviousDeclaration(PrevDecl), CommonPtr(CommonPtr) { }
+
+ ~ClassTemplateDecl();
+
+public:
+ /// Get the underlying class declarations of the template.
+ CXXRecordDecl *getTemplatedDecl() const {
+ return static_cast<CXXRecordDecl *>(TemplatedDecl);
+ }
+
+ /// \brief Retrieve the previous declaration of this template.
+ ClassTemplateDecl *getPreviousDeclaration() const {
+ return PreviousDeclaration;
+ }
+
+ /// Create a class template node.
+ static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ DeclarationName Name,
+ TemplateParameterList *Params,
+ NamedDecl *Decl,
+ ClassTemplateDecl *PrevDecl);
+
+ /// \brief Retrieve the set of specializations of this class template.
+ llvm::FoldingSet<ClassTemplateSpecializationDecl> &getSpecializations() {
+ return CommonPtr->Specializations;
+ }
+
+ /// \brief Retrieve the set of partial specializations of this class
+ /// template.
+ llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &
+ getPartialSpecializations() {
+ return CommonPtr->PartialSpecializations;
+ }
+
+ /// \brief Retrieve the type of the injected-class-name for this
+ /// class template.
+ ///
+ /// The injected-class-name for a class template \c X is \c
+ /// X<template-args>, where \c template-args is formed from the
+ /// template arguments that correspond to the template parameters of
+ /// \c X. For example:
+ ///
+ /// \code
+ /// template<typename T, int N>
+ /// struct array {
+ /// typedef array this_type; // "array" is equivalent to "array<T, N>"
+ /// };
+ /// \endcode
+ QualType getInjectedClassNameType(ASTContext &Context);
+
+ // Implement isa/cast/dyncast support
+ static bool classof(const Decl *D)
+ { return D->getKind() == ClassTemplate; }
+ static bool classof(const ClassTemplateDecl *D)
+ { return true; }
+
+ virtual void Destroy(ASTContext& C);
+};
+
+} /* end of namespace clang */
+
+#endif
diff --git a/include/clang/AST/DeclVisitor.h b/include/clang/AST/DeclVisitor.h
new file mode 100644
index 000000000000..9423c319c3e3
--- /dev/null
+++ b/include/clang/AST/DeclVisitor.h
@@ -0,0 +1,54 @@
+//===--- DeclVisitor.h - Visitor for Decl subclasses ------------*- 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 DeclVisitor interface.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_DECLVISITOR_H
+#define LLVM_CLANG_AST_DECLVISITOR_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+
+namespace clang {
+
+#define DISPATCH(NAME, CLASS) \
+ return static_cast<ImplClass*>(this)-> Visit##NAME(static_cast<CLASS*>(D))
+
+/// \brief A simple visitor class that helps create declaration visitors.
+template<typename ImplClass, typename RetTy=void>
+class DeclVisitor {
+public:
+ RetTy Visit(Decl *D) {
+ switch (D->getKind()) {
+ default: assert(false && "Decl that isn't part of DeclNodes.def!");
+#define DECL(Derived, Base) \
+ case Decl::Derived: DISPATCH(Derived##Decl, Derived##Decl);
+#define ABSTRACT_DECL(Derived, Base)
+#include "clang/AST/DeclNodes.def"
+ }
+ }
+
+ // If the implementation chooses not to implement a certain visit
+ // method, fall back to the parent.
+#define DECL(Derived, Base) \
+ RetTy Visit##Derived##Decl(Derived##Decl *D) { DISPATCH(Base, Base); }
+#define ABSTRACT_DECL(Derived, Base) DECL(Derived, Base)
+#include "clang/AST/DeclNodes.def"
+
+ RetTy VisitDecl(Decl *D) { return RetTy(); }
+};
+
+#undef DISPATCH
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_DECLVISITOR_H
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
new file mode 100644
index 000000000000..db140999b045
--- /dev/null
+++ b/include/clang/AST/DeclarationName.h
@@ -0,0 +1,357 @@
+//===-- DeclarationName.h - Representation of declaration names -*- 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 the DeclarationName and DeclarationNameTable classes.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_DECLARATIONNAME_H
+#define LLVM_CLANG_AST_DECLARATIONNAME_H
+
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/AST/Type.h"
+
+namespace llvm {
+ template <typename T> struct DenseMapInfo;
+}
+
+namespace clang {
+ class CXXSpecialName;
+ class CXXOperatorIdName;
+ class DeclarationNameExtra;
+ class IdentifierInfo;
+ class MultiKeywordSelector;
+ class UsingDirectiveDecl;
+
+/// DeclarationName - The name of a declaration. In the common case,
+/// this just stores an IdentifierInfo pointer to a normal
+/// name. However, it also provides encodings for Objective-C
+/// selectors (optimizing zero- and one-argument selectors, which make
+/// up 78% percent of all selectors in Cocoa.h) and special C++ names
+/// for constructors, destructors, and conversion functions.
+class DeclarationName {
+public:
+ /// NameKind - The kind of name this object contains.
+ enum NameKind {
+ Identifier,
+ ObjCZeroArgSelector,
+ ObjCOneArgSelector,
+ ObjCMultiArgSelector,
+ CXXConstructorName,
+ CXXDestructorName,
+ CXXConversionFunctionName,
+ CXXOperatorName,
+ CXXUsingDirective
+ };
+
+private:
+ /// StoredNameKind - The kind of name that is actually stored in the
+ /// upper bits of the Ptr field. This is only used internally.
+ enum StoredNameKind {
+ StoredIdentifier = 0,
+ StoredObjCZeroArgSelector,
+ StoredObjCOneArgSelector,
+ StoredDeclarationNameExtra,
+ PtrMask = 0x03
+ };
+
+ /// Ptr - The lowest two bits are used to express what kind of name
+ /// we're actually storing, using the values of NameKind. Depending
+ /// on the kind of name this is, the upper bits of Ptr may have one
+ /// of several different meanings:
+ ///
+ /// StoredIdentifier - The name is a normal identifier, and Ptr is
+ /// a normal IdentifierInfo pointer.
+ ///
+ /// StoredObjCZeroArgSelector - The name is an Objective-C
+ /// selector with zero arguments, and Ptr is an IdentifierInfo
+ /// pointer pointing to the selector name.
+ ///
+ /// StoredObjCOneArgSelector - The name is an Objective-C selector
+ /// with one argument, and Ptr is an IdentifierInfo pointer
+ /// pointing to the selector name.
+ ///
+ /// StoredDeclarationNameExtra - Ptr is actually a pointer to a
+ /// DeclarationNameExtra structure, whose first value will tell us
+ /// whether this is an Objective-C selector, C++ operator-id name,
+ /// or special C++ name.
+ uintptr_t Ptr;
+
+ /// getStoredNameKind - Return the kind of object that is stored in
+ /// Ptr.
+ StoredNameKind getStoredNameKind() const {
+ return static_cast<StoredNameKind>(Ptr & PtrMask);
+ }
+
+ /// getExtra - Get the "extra" information associated with this
+ /// multi-argument selector or C++ special name.
+ DeclarationNameExtra *getExtra() const {
+ assert(getStoredNameKind() == StoredDeclarationNameExtra &&
+ "Declaration name does not store an Extra structure");
+ return reinterpret_cast<DeclarationNameExtra *>(Ptr & ~PtrMask);
+ }
+
+ /// getAsCXXSpecialName - If the stored pointer is actually a
+ /// CXXSpecialName, returns a pointer to it. Otherwise, returns
+ /// a NULL pointer.
+ CXXSpecialName *getAsCXXSpecialName() const {
+ if (getNameKind() >= CXXConstructorName &&
+ getNameKind() <= CXXConversionFunctionName)
+ return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask);
+ return 0;
+ }
+
+ /// getAsCXXOperatorIdName
+ CXXOperatorIdName *getAsCXXOperatorIdName() const {
+ if (getNameKind() == CXXOperatorName)
+ return reinterpret_cast<CXXOperatorIdName *>(Ptr & ~PtrMask);
+ return 0;
+ }
+
+ // Construct a declaration name from the name of a C++ constructor,
+ // destructor, or conversion function.
+ DeclarationName(CXXSpecialName *Name)
+ : Ptr(reinterpret_cast<uintptr_t>(Name)) {
+ assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXSpecialName");
+ Ptr |= StoredDeclarationNameExtra;
+ }
+
+ // Construct a declaration name from the name of a C++ overloaded
+ // operator.
+ DeclarationName(CXXOperatorIdName *Name)
+ : Ptr(reinterpret_cast<uintptr_t>(Name)) {
+ assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId");
+ Ptr |= StoredDeclarationNameExtra;
+ }
+
+ /// Construct a declaration name from a raw pointer.
+ DeclarationName(uintptr_t Ptr) : Ptr(Ptr) { }
+
+ friend class DeclarationNameTable;
+ friend class NamedDecl;
+
+ /// getFETokenInfoAsVoid - Retrieves the front end-specified pointer
+ /// for this name as a void pointer.
+ void *getFETokenInfoAsVoid() const;
+
+public:
+ /// DeclarationName - Used to create an empty selector.
+ DeclarationName() : Ptr(0) { }
+
+ // Construct a declaration name from an IdentifierInfo *.
+ DeclarationName(const IdentifierInfo *II)
+ : Ptr(reinterpret_cast<uintptr_t>(II)) {
+ assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo");
+ }
+
+ // Construct a declaration name from an Objective-C selector.
+ DeclarationName(Selector Sel);
+
+ /// getUsingDirectiveName - Return name for all using-directives.
+ static DeclarationName getUsingDirectiveName();
+
+ // operator bool() - Evaluates true when this declaration name is
+ // non-empty.
+ operator bool() const {
+ return ((Ptr & PtrMask) != 0) ||
+ (reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask));
+ }
+
+ /// Predicate functions for querying what type of name this is.
+ bool isIdentifier() const { return getStoredNameKind() == StoredIdentifier; }
+ bool isObjCZeroArgSelector() const {
+ return getStoredNameKind() == StoredObjCZeroArgSelector;
+ }
+ bool isObjCOneArgSelector() const {
+ return getStoredNameKind() == StoredObjCOneArgSelector;
+ }
+
+ /// getNameKind - Determine what kind of name this is.
+ NameKind getNameKind() const;
+
+
+ /// getName - Retrieve the human-readable string for this name.
+ std::string getAsString() const;
+
+ /// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in
+ /// this declaration name, or NULL if this declaration name isn't a
+ /// simple identifier.
+ IdentifierInfo *getAsIdentifierInfo() const {
+ if (isIdentifier())
+ return reinterpret_cast<IdentifierInfo *>(Ptr);
+ return 0;
+ }
+
+ /// getAsOpaqueInteger - Get the representation of this declaration
+ /// name as an opaque integer.
+ uintptr_t getAsOpaqueInteger() const { return Ptr; }
+
+ /// getAsOpaquePtr - Get the representation of this declaration name as
+ /// an opaque pointer.
+ void *getAsOpaquePtr() const { return reinterpret_cast<void*>(Ptr); }
+
+ static DeclarationName getFromOpaqueInteger(uintptr_t P) {
+ DeclarationName N;
+ N.Ptr = P;
+ return N;
+ }
+
+ /// getCXXNameType - If this name is one of the C++ names (of a
+ /// constructor, destructor, or conversion function), return the
+ /// type associated with that name.
+ QualType getCXXNameType() const;
+
+ /// getCXXOverloadedOperator - If this name is the name of an
+ /// overloadable operator in C++ (e.g., @c operator+), retrieve the
+ /// kind of overloaded operator.
+ OverloadedOperatorKind getCXXOverloadedOperator() const;
+
+ /// getObjCSelector - Get the Objective-C selector stored in this
+ /// declaration name.
+ Selector getObjCSelector() const;
+
+ /// getFETokenInfo/setFETokenInfo - The language front-end is
+ /// allowed to associate arbitrary metadata with some kinds of
+ /// declaration names, including normal identifiers and C++
+ /// constructors, destructors, and conversion functions.
+ template<typename T>
+ T *getFETokenInfo() const { return static_cast<T*>(getFETokenInfoAsVoid()); }
+
+ void setFETokenInfo(void *T);
+
+ /// operator== - Determine whether the specified names are identical..
+ friend bool operator==(DeclarationName LHS, DeclarationName RHS) {
+ return LHS.Ptr == RHS.Ptr;
+ }
+
+ /// operator!= - Determine whether the specified names are different.
+ friend bool operator!=(DeclarationName LHS, DeclarationName RHS) {
+ return LHS.Ptr != RHS.Ptr;
+ }
+
+ static DeclarationName getEmptyMarker() {
+ return DeclarationName(uintptr_t(-1));
+ }
+
+ static DeclarationName getTombstoneMarker() {
+ return DeclarationName(uintptr_t(-2));
+ }
+};
+
+/// Ordering on two declaration names. If both names are identifiers,
+/// this provides a lexicographical ordering.
+bool operator<(DeclarationName LHS, DeclarationName RHS);
+
+/// Ordering on two declaration names. If both names are identifiers,
+/// this provides a lexicographical ordering.
+inline bool operator>(DeclarationName LHS, DeclarationName RHS) {
+ return RHS < LHS;
+}
+
+/// Ordering on two declaration names. If both names are identifiers,
+/// this provides a lexicographical ordering.
+inline bool operator<=(DeclarationName LHS, DeclarationName RHS) {
+ return !(RHS < LHS);
+}
+
+/// Ordering on two declaration names. If both names are identifiers,
+/// this provides a lexicographical ordering.
+inline bool operator>=(DeclarationName LHS, DeclarationName RHS) {
+ return !(LHS < RHS);
+}
+
+/// DeclarationNameTable - Used to store and retrieve DeclarationName
+/// instances for the various kinds of declaration names, e.g., normal
+/// identifiers, C++ constructor names, etc. This class contains
+/// uniqued versions of each of the C++ special names, which can be
+/// retrieved using its member functions (e.g.,
+/// getCXXConstructorName).
+class DeclarationNameTable {
+ void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
+ CXXOperatorIdName *CXXOperatorNames; // Operator names
+
+ DeclarationNameTable(const DeclarationNameTable&); // NONCOPYABLE
+ DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE
+
+public:
+ DeclarationNameTable();
+ ~DeclarationNameTable();
+
+ /// getIdentifier - Create a declaration name that is a simple
+ /// identifier.
+ DeclarationName getIdentifier(IdentifierInfo *ID) {
+ return DeclarationName(ID);
+ }
+
+ /// getCXXConstructorName - Returns the name of a C++ constructor
+ /// for the given Type.
+ DeclarationName getCXXConstructorName(QualType Ty) {
+ return getCXXSpecialName(DeclarationName::CXXConstructorName, Ty);
+ }
+
+ /// getCXXDestructorName - Returns the name of a C++ destructor
+ /// for the given Type.
+ DeclarationName getCXXDestructorName(QualType Ty) {
+ return getCXXSpecialName(DeclarationName::CXXDestructorName, Ty);
+ }
+
+ /// getCXXConversionFunctionName - Returns the name of a C++
+ /// conversion function for the given Type.
+ DeclarationName getCXXConversionFunctionName(QualType Ty) {
+ return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty);
+ }
+
+ /// getCXXSpecialName - Returns a declaration name for special kind
+ /// of C++ name, e.g., for a constructor, destructor, or conversion
+ /// function.
+ DeclarationName getCXXSpecialName(DeclarationName::NameKind Kind,
+ QualType Ty);
+
+ /// getCXXOperatorName - Get the name of the overloadable C++
+ /// operator corresponding to Op.
+ DeclarationName getCXXOperatorName(OverloadedOperatorKind Op);
+};
+
+/// Insertion operator for diagnostics. This allows sending DeclarationName's
+/// into a diagnostic with <<.
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ DeclarationName N) {
+ DB.AddTaggedVal(N.getAsOpaqueInteger(),
+ Diagnostic::ak_declarationname);
+ return DB;
+}
+
+
+} // end namespace clang
+
+namespace llvm {
+/// Define DenseMapInfo so that DeclarationNames can be used as keys
+/// in DenseMap and DenseSets.
+template<>
+struct DenseMapInfo<clang::DeclarationName> {
+ static inline clang::DeclarationName getEmptyKey() {
+ return clang::DeclarationName::getEmptyMarker();
+ }
+
+ static inline clang::DeclarationName getTombstoneKey() {
+ return clang::DeclarationName::getTombstoneMarker();
+ }
+
+ static unsigned getHashValue(clang::DeclarationName);
+
+ static inline bool
+ isEqual(clang::DeclarationName LHS, clang::DeclarationName RHS) {
+ return LHS == RHS;
+ }
+
+ static inline bool isPod() { return true; }
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
new file mode 100644
index 000000000000..98de5f9d382e
--- /dev/null
+++ b/include/clang/AST/Expr.h
@@ -0,0 +1,2500 @@
+//===--- Expr.h - Classes for representing 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 the Expr interface and subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_EXPR_H
+#define LLVM_CLANG_AST_EXPR_H
+
+#include "clang/AST/APValue.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/SmallVector.h"
+#include <vector>
+
+namespace clang {
+ class ASTContext;
+ class APValue;
+ class Decl;
+ class IdentifierInfo;
+ class ParmVarDecl;
+ class NamedDecl;
+ class ValueDecl;
+ class BlockDecl;
+ class CXXOperatorCallExpr;
+ class CXXMemberCallExpr;
+
+/// Expr - This represents one expression. Note that Expr's are subclasses of
+/// Stmt. This allows an expression to be transparently used any place a Stmt
+/// is required.
+///
+class Expr : public Stmt {
+ QualType TR;
+
+protected:
+ /// TypeDependent - Whether this expression is type-dependent
+ /// (C++ [temp.dep.expr]).
+ bool TypeDependent : 1;
+
+ /// ValueDependent - Whether this expression is value-dependent
+ /// (C++ [temp.dep.constexpr]).
+ bool ValueDependent : 1;
+
+ // FIXME: Eventually, this constructor should go away and we should
+ // require every subclass to provide type/value-dependence
+ // information.
+ Expr(StmtClass SC, QualType T)
+ : Stmt(SC), TypeDependent(false), ValueDependent(false) {
+ setType(T);
+ }
+
+ Expr(StmtClass SC, QualType T, bool TD, bool VD)
+ : Stmt(SC), TypeDependent(TD), ValueDependent(VD) {
+ setType(T);
+ }
+
+ /// \brief Construct an empty expression.
+ explicit Expr(StmtClass SC, EmptyShell) : Stmt(SC) { }
+
+public:
+ QualType getType() const { return TR; }
+ void setType(QualType t) {
+ // In C++, the type of an expression is always adjusted so that it
+ // will not have reference type an expression will never have
+ // reference type (C++ [expr]p6). Use
+ // QualType::getNonReferenceType() to retrieve the non-reference
+ // type. Additionally, inspect Expr::isLvalue to determine whether
+ // an expression that is adjusted in this manner should be
+ // considered an lvalue.
+ assert((TR.isNull() || !TR->isReferenceType()) &&
+ "Expressions can't have reference type");
+
+ TR = t;
+ }
+
+ /// isValueDependent - Determines whether this expression is
+ /// value-dependent (C++ [temp.dep.constexpr]). For example, the
+ /// array bound of "Chars" in the following example is
+ /// value-dependent.
+ /// @code
+ /// template<int Size, char (&Chars)[Size]> struct meta_string;
+ /// @endcode
+ bool isValueDependent() const { return ValueDependent; }
+
+ /// \brief Set whether this expression is value-dependent or not.
+ void setValueDependent(bool VD) { ValueDependent = VD; }
+
+ /// isTypeDependent - Determines whether this expression is
+ /// type-dependent (C++ [temp.dep.expr]), which means that its type
+ /// could change from one template instantiation to the next. For
+ /// example, the expressions "x" and "x + y" are type-dependent in
+ /// the following code, but "y" is not type-dependent:
+ /// @code
+ /// template<typename T>
+ /// void add(T x, int y) {
+ /// x + y;
+ /// }
+ /// @endcode
+ bool isTypeDependent() const { return TypeDependent; }
+
+ /// \brief Set whether this expression is type-dependent or not.
+ void setTypeDependent(bool TD) { TypeDependent = TD; }
+
+ /// SourceLocation tokens are not useful in isolation - they are low level
+ /// value objects created/interpreted by SourceManager. We assume AST
+ /// clients will have a pointer to the respective SourceManager.
+ virtual SourceRange getSourceRange() const = 0;
+
+ /// getExprLoc - Return the preferred location for the arrow when diagnosing
+ /// a problem with a generic expression.
+ virtual SourceLocation getExprLoc() const { return getLocStart(); }
+
+ /// isUnusedResultAWarning - Return true if this immediate expression should
+ /// be warned about if the result is unused. If so, fill in Loc and Ranges
+ /// with location to warn on and the source range[s] to report with the
+ /// warning.
+ bool isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
+ SourceRange &R2) const;
+
+ /// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or
+ /// incomplete type other than void. Nonarray expressions that can be lvalues:
+ /// - name, where name must be a variable
+ /// - e[i]
+ /// - (e), where e must be an lvalue
+ /// - e.name, where e must be an lvalue
+ /// - e->name
+ /// - *e, the type of e cannot be a function type
+ /// - string-constant
+ /// - reference type [C++ [expr]]
+ /// - b ? x : y, where x and y are lvalues of suitable types [C++]
+ ///
+ enum isLvalueResult {
+ LV_Valid,
+ LV_NotObjectType,
+ LV_IncompleteVoidType,
+ LV_DuplicateVectorComponents,
+ LV_InvalidExpression,
+ LV_MemberFunction
+ };
+ isLvalueResult isLvalue(ASTContext &Ctx) const;
+
+ // Same as above, but excluding checks for non-object and void types in C
+ isLvalueResult isLvalueInternal(ASTContext &Ctx) const;
+
+ /// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type,
+ /// does not have an incomplete type, does not have a const-qualified type,
+ /// and if it is a structure or union, does not have any member (including,
+ /// recursively, any member or element of all contained aggregates or unions)
+ /// with a const-qualified type.
+ ///
+ /// \param Loc [in] [out] - A source location which *may* be filled
+ /// in with the location of the expression making this a
+ /// non-modifiable lvalue, if specified.
+ enum isModifiableLvalueResult {
+ MLV_Valid,
+ MLV_NotObjectType,
+ MLV_IncompleteVoidType,
+ MLV_DuplicateVectorComponents,
+ MLV_InvalidExpression,
+ MLV_LValueCast, // Specialized form of MLV_InvalidExpression.
+ MLV_IncompleteType,
+ MLV_ConstQualified,
+ MLV_ArrayType,
+ MLV_NotBlockQualified,
+ MLV_ReadonlyProperty,
+ MLV_NoSetterProperty,
+ MLV_MemberFunction
+ };
+ isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx,
+ SourceLocation *Loc = 0) const;
+
+ /// \brief If this expression refers to a bit-field, retrieve the
+ /// declaration of that bit-field.
+ FieldDecl *getBitField();
+
+ const FieldDecl *getBitField() const {
+ return const_cast<Expr*>(this)->getBitField();
+ }
+
+ /// isIntegerConstantExpr - Return true if this expression is a valid integer
+ /// constant expression, and, if so, return its value in Result. If not a
+ /// valid i-c-e, return false and fill in Loc (if specified) with the location
+ /// of the invalid expression.
+ bool isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
+ SourceLocation *Loc = 0,
+ bool isEvaluated = true) const;
+ bool isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc = 0) const {
+ llvm::APSInt X;
+ return isIntegerConstantExpr(X, Ctx, Loc);
+ }
+ /// isConstantInitializer - Returns true if this expression is a constant
+ /// initializer, which can be emitted at compile-time.
+ bool isConstantInitializer(ASTContext &Ctx) const;
+
+ /// EvalResult is a struct with detailed info about an evaluated expression.
+ struct EvalResult {
+ /// Val - This is the value the expression can be folded to.
+ APValue Val;
+
+ /// HasSideEffects - Whether the evaluated expression has side effects.
+ /// For example, (f() && 0) can be folded, but it still has side effects.
+ bool HasSideEffects;
+
+ /// Diag - If the expression is unfoldable, then Diag contains a note
+ /// diagnostic indicating why it's not foldable. DiagLoc indicates a caret
+ /// position for the error, and DiagExpr is the expression that caused
+ /// the error.
+ /// If the expression is foldable, but not an integer constant expression,
+ /// Diag contains a note diagnostic that describes why it isn't an integer
+ /// constant expression. If the expression *is* an integer constant
+ /// expression, then Diag will be zero.
+ unsigned Diag;
+ const Expr *DiagExpr;
+ SourceLocation DiagLoc;
+
+ EvalResult() : HasSideEffects(false), Diag(0), DiagExpr(0) {}
+ };
+
+ /// Evaluate - Return true if this is a constant which we can fold using
+ /// any crazy technique (that has nothing to do with language standards) that
+ /// we want to. If this function returns true, it returns the folded constant
+ /// in Result.
+ bool Evaluate(EvalResult &Result, ASTContext &Ctx) const;
+
+ /// isEvaluatable - Call Evaluate to see if this expression can be constant
+ /// folded, but discard the result.
+ bool isEvaluatable(ASTContext &Ctx) const;
+
+ /// EvaluateAsInt - Call Evaluate and return the folded integer. This
+ /// must be called on an expression that constant folds to an integer.
+ llvm::APSInt EvaluateAsInt(ASTContext &Ctx) const;
+
+ /// EvaluateAsLValue - Evaluate an expression to see if it's a valid LValue.
+ bool EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const;
+
+ /// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an
+ /// integer constant expression with the value zero, or if this is one that is
+ /// cast to void*.
+ bool isNullPointerConstant(ASTContext &Ctx) const;
+
+ /// hasGlobalStorage - Return true if this expression has static storage
+ /// duration. This means that the address of this expression is a link-time
+ /// constant.
+ bool hasGlobalStorage() const;
+
+ /// isOBJCGCCandidate - Return true if this expression may be used in a read/
+ /// write barrier.
+ bool isOBJCGCCandidate(ASTContext &Ctx) const;
+
+ /// IgnoreParens - Ignore parentheses. If this Expr is a ParenExpr, return
+ /// its subexpression. If that subexpression is also a ParenExpr,
+ /// then this method recursively returns its subexpression, and so forth.
+ /// Otherwise, the method returns the current Expr.
+ Expr* IgnoreParens();
+
+ /// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr
+ /// or CastExprs, returning their operand.
+ Expr *IgnoreParenCasts();
+
+ /// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the
+ /// value (including ptr->int casts of the same size). Strip off any
+ /// ParenExpr or CastExprs, returning their operand.
+ Expr *IgnoreParenNoopCasts(ASTContext &Ctx);
+
+ const Expr* IgnoreParens() const {
+ return const_cast<Expr*>(this)->IgnoreParens();
+ }
+ const Expr *IgnoreParenCasts() const {
+ return const_cast<Expr*>(this)->IgnoreParenCasts();
+ }
+ const Expr *IgnoreParenNoopCasts(ASTContext &Ctx) const {
+ return const_cast<Expr*>(this)->IgnoreParenNoopCasts(Ctx);
+ }
+
+ static bool hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs);
+ static bool hasAnyValueDependentArguments(Expr** Exprs, unsigned NumExprs);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() >= firstExprConstant &&
+ T->getStmtClass() <= lastExprConstant;
+ }
+ static bool classof(const Expr *) { return true; }
+};
+
+
+//===----------------------------------------------------------------------===//
+// Primary Expressions.
+//===----------------------------------------------------------------------===//
+
+/// DeclRefExpr - [C99 6.5.1p2] - A reference to a declared variable, function,
+/// enum, etc.
+class DeclRefExpr : public Expr {
+ NamedDecl *D;
+ SourceLocation Loc;
+
+protected:
+ // FIXME: Eventually, this constructor will go away and all subclasses
+ // will have to provide the type- and value-dependent flags.
+ DeclRefExpr(StmtClass SC, NamedDecl *d, QualType t, SourceLocation l) :
+ Expr(SC, t), D(d), Loc(l) {}
+
+ DeclRefExpr(StmtClass SC, NamedDecl *d, QualType t, SourceLocation l, bool TD,
+ bool VD) :
+ Expr(SC, t, TD, VD), D(d), Loc(l) {}
+
+public:
+ // FIXME: Eventually, this constructor will go away and all clients
+ // will have to provide the type- and value-dependent flags.
+ DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l) :
+ Expr(DeclRefExprClass, t), D(d), Loc(l) {}
+
+ DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, bool VD) :
+ Expr(DeclRefExprClass, t, TD, VD), D(d), Loc(l) {}
+
+ /// \brief Construct an empty declaration reference expression.
+ explicit DeclRefExpr(EmptyShell Empty)
+ : Expr(DeclRefExprClass, Empty) { }
+
+ NamedDecl *getDecl() { return D; }
+ const NamedDecl *getDecl() const { return D; }
+ void setDecl(NamedDecl *NewD) { D = NewD; }
+
+ SourceLocation getLocation() const { return Loc; }
+ void setLocation(SourceLocation L) { Loc = L; }
+ virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == DeclRefExprClass ||
+ T->getStmtClass() == CXXConditionDeclExprClass ||
+ T->getStmtClass() == QualifiedDeclRefExprClass;
+ }
+ static bool classof(const DeclRefExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// PredefinedExpr - [C99 6.4.2.2] - A predefined identifier such as __func__.
+class PredefinedExpr : public Expr {
+public:
+ enum IdentType {
+ Func,
+ Function,
+ PrettyFunction
+ };
+
+private:
+ SourceLocation Loc;
+ IdentType Type;
+public:
+ PredefinedExpr(SourceLocation l, QualType type, IdentType IT)
+ : Expr(PredefinedExprClass, type), Loc(l), Type(IT) {}
+
+ /// \brief Construct an empty predefined expression.
+ explicit PredefinedExpr(EmptyShell Empty)
+ : Expr(PredefinedExprClass, Empty) { }
+
+ PredefinedExpr* Clone(ASTContext &C) const;
+
+ IdentType getIdentType() const { return Type; }
+ void setIdentType(IdentType IT) { Type = IT; }
+
+ SourceLocation getLocation() const { return Loc; }
+ void setLocation(SourceLocation L) { Loc = L; }
+
+ // FIXME: The logic for computing the value of a predefined expr should go
+ // into a method here that takes the inner-most code decl (a block, function
+ // or objc method) that the expr lives in. This would allow sema and codegen
+ // to be consistent for things like sizeof(__func__) etc.
+
+ virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == PredefinedExprClass;
+ }
+ static bool classof(const PredefinedExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+class IntegerLiteral : public Expr {
+ llvm::APInt Value;
+ SourceLocation Loc;
+public:
+ // type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy,
+ // or UnsignedLongLongTy
+ IntegerLiteral(const llvm::APInt &V, QualType type, SourceLocation l)
+ : Expr(IntegerLiteralClass, type), Value(V), Loc(l) {
+ assert(type->isIntegerType() && "Illegal type in IntegerLiteral");
+ }
+
+ /// \brief Construct an empty integer literal.
+ explicit IntegerLiteral(EmptyShell Empty)
+ : Expr(IntegerLiteralClass, Empty) { }
+
+ IntegerLiteral* Clone(ASTContext &C) const;
+
+ const llvm::APInt &getValue() const { return Value; }
+ virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+
+ /// \brief Retrieve the location of the literal.
+ SourceLocation getLocation() const { return Loc; }
+
+ void setValue(const llvm::APInt &Val) { Value = Val; }
+ void setLocation(SourceLocation Location) { Loc = Location; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == IntegerLiteralClass;
+ }
+ static bool classof(const IntegerLiteral *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+class CharacterLiteral : public Expr {
+ unsigned Value;
+ SourceLocation Loc;
+ bool IsWide;
+public:
+ // type should be IntTy
+ CharacterLiteral(unsigned value, bool iswide, QualType type, SourceLocation l)
+ : Expr(CharacterLiteralClass, type), Value(value), Loc(l), IsWide(iswide) {
+ }
+
+ /// \brief Construct an empty character literal.
+ CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { }
+
+ CharacterLiteral* Clone(ASTContext &C) const;
+
+ SourceLocation getLoc() const { return Loc; }
+ bool isWide() const { return IsWide; }
+
+ virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+
+ unsigned getValue() const { return Value; }
+
+ void setLocation(SourceLocation Location) { Loc = Location; }
+ void setWide(bool W) { IsWide = W; }
+ void setValue(unsigned Val) { Value = Val; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CharacterLiteralClass;
+ }
+ static bool classof(const CharacterLiteral *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+class FloatingLiteral : public Expr {
+ llvm::APFloat Value;
+ bool IsExact : 1;
+ SourceLocation Loc;
+public:
+ FloatingLiteral(const llvm::APFloat &V, bool* isexact,
+ QualType Type, SourceLocation L)
+ : Expr(FloatingLiteralClass, Type), Value(V), IsExact(*isexact), Loc(L) {}
+
+ /// \brief Construct an empty floating-point literal.
+ explicit FloatingLiteral(EmptyShell Empty)
+ : Expr(FloatingLiteralClass, Empty), Value(0.0) { }
+
+ FloatingLiteral* Clone(ASTContext &C) const;
+
+ const llvm::APFloat &getValue() const { return Value; }
+ void setValue(const llvm::APFloat &Val) { Value = Val; }
+
+ bool isExact() const { return IsExact; }
+ void setExact(bool E) { IsExact = E; }
+
+ /// getValueAsApproximateDouble - This returns the value as an inaccurate
+ /// double. Note that this may cause loss of precision, but is useful for
+ /// debugging dumps, etc.
+ double getValueAsApproximateDouble() const;
+
+ SourceLocation getLocation() const { return Loc; }
+ void setLocation(SourceLocation L) { Loc = L; }
+
+ // FIXME: The logic for computing the value of a predefined expr should go
+ // into a method here that takes the inner-most code decl (a block, function
+ // or objc method) that the expr lives in. This would allow sema and codegen
+ // to be consistent for things like sizeof(__func__) etc.
+
+ virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == FloatingLiteralClass;
+ }
+ static bool classof(const FloatingLiteral *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ImaginaryLiteral - We support imaginary integer and floating point literals,
+/// like "1.0i". We represent these as a wrapper around FloatingLiteral and
+/// IntegerLiteral classes. Instances of this class always have a Complex type
+/// whose element type matches the subexpression.
+///
+class ImaginaryLiteral : public Expr {
+ Stmt *Val;
+public:
+ ImaginaryLiteral(Expr *val, QualType Ty)
+ : Expr(ImaginaryLiteralClass, Ty), Val(val) {}
+
+ /// \brief Build an empty imaginary literal.
+ explicit ImaginaryLiteral(EmptyShell Empty)
+ : Expr(ImaginaryLiteralClass, Empty) { }
+
+ const Expr *getSubExpr() const { return cast<Expr>(Val); }
+ Expr *getSubExpr() { return cast<Expr>(Val); }
+ void setSubExpr(Expr *E) { Val = E; }
+
+ ImaginaryLiteral* Clone(ASTContext &C) const;
+
+ virtual SourceRange getSourceRange() const { return Val->getSourceRange(); }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ImaginaryLiteralClass;
+ }
+ static bool classof(const ImaginaryLiteral *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// StringLiteral - This represents a string literal expression, e.g. "foo"
+/// or L"bar" (wide strings). The actual string is returned by getStrData()
+/// is NOT null-terminated, and the length of the string is determined by
+/// calling getByteLength(). The C type for a string is always a
+/// ConstantArrayType. In C++, the char type is const qualified, in C it is
+/// not.
+///
+/// Note that strings in C can be formed by concatenation of multiple string
+/// literal pptokens in translation phase #6. This keeps track of the locations
+/// of each of these pieces.
+///
+/// Strings in C can also be truncated and extended by assigning into arrays,
+/// e.g. with constructs like:
+/// char X[2] = "foobar";
+/// In this case, getByteLength() will return 6, but the string literal will
+/// have type "char[2]".
+class StringLiteral : public Expr {
+ const char *StrData;
+ unsigned ByteLength;
+ bool IsWide;
+ unsigned NumConcatenated;
+ SourceLocation TokLocs[1];
+
+ StringLiteral(QualType Ty) : Expr(StringLiteralClass, Ty) {}
+public:
+ /// This is the "fully general" constructor that allows representation of
+ /// strings formed from multiple concatenated tokens.
+ static StringLiteral *Create(ASTContext &C, const char *StrData,
+ unsigned ByteLength, bool Wide, QualType Ty,
+ const SourceLocation *Loc, unsigned NumStrs);
+
+ /// Simple constructor for string literals made from one token.
+ static StringLiteral *Create(ASTContext &C, const char *StrData,
+ unsigned ByteLength,
+ bool Wide, QualType Ty, SourceLocation Loc) {
+ return Create(C, StrData, ByteLength, Wide, Ty, &Loc, 1);
+ }
+
+ /// \brief Construct an empty string literal.
+ static StringLiteral *CreateEmpty(ASTContext &C, unsigned NumStrs);
+
+ StringLiteral* Clone(ASTContext &C) const;
+ void Destroy(ASTContext &C);
+
+ const char *getStrData() const { return StrData; }
+ unsigned getByteLength() const { return ByteLength; }
+
+ /// \brief Sets the string data to the given string data.
+ void setStrData(ASTContext &C, const char *Str, unsigned Len);
+
+ bool isWide() const { return IsWide; }
+ void setWide(bool W) { IsWide = W; }
+
+ bool containsNonAsciiOrNull() const {
+ for (unsigned i = 0; i < getByteLength(); ++i)
+ if (!isascii(getStrData()[i]) || !getStrData()[i])
+ return true;
+ return false;
+ }
+ /// getNumConcatenated - Get the number of string literal tokens that were
+ /// concatenated in translation phase #6 to form this string literal.
+ unsigned getNumConcatenated() const { return NumConcatenated; }
+
+ SourceLocation getStrTokenLoc(unsigned TokNum) const {
+ assert(TokNum < NumConcatenated && "Invalid tok number");
+ return TokLocs[TokNum];
+ }
+ void setStrTokenLoc(unsigned TokNum, SourceLocation L) {
+ assert(TokNum < NumConcatenated && "Invalid tok number");
+ TokLocs[TokNum] = L;
+ }
+
+ typedef const SourceLocation *tokloc_iterator;
+ tokloc_iterator tokloc_begin() const { return TokLocs; }
+ tokloc_iterator tokloc_end() const { return TokLocs+NumConcatenated; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(TokLocs[0], TokLocs[NumConcatenated-1]);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == StringLiteralClass;
+ }
+ static bool classof(const StringLiteral *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ParenExpr - This represents a parethesized expression, e.g. "(1)". This
+/// AST node is only formed if full location information is requested.
+class ParenExpr : public Expr {
+ SourceLocation L, R;
+ Stmt *Val;
+public:
+ ParenExpr(SourceLocation l, SourceLocation r, Expr *val)
+ : Expr(ParenExprClass, val->getType(),
+ val->isTypeDependent(), val->isValueDependent()),
+ L(l), R(r), Val(val) {}
+
+ /// \brief Construct an empty parenthesized expression.
+ explicit ParenExpr(EmptyShell Empty)
+ : Expr(ParenExprClass, Empty) { }
+
+ const Expr *getSubExpr() const { return cast<Expr>(Val); }
+ Expr *getSubExpr() { return cast<Expr>(Val); }
+ void setSubExpr(Expr *E) { Val = E; }
+
+ virtual SourceRange getSourceRange() const { return SourceRange(L, R); }
+
+ /// \brief Get the location of the left parentheses '('.
+ SourceLocation getLParen() const { return L; }
+ void setLParen(SourceLocation Loc) { L = Loc; }
+
+ /// \brief Get the location of the right parentheses ')'.
+ SourceLocation getRParen() const { return R; }
+ void setRParen(SourceLocation Loc) { R = Loc; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ParenExprClass;
+ }
+ static bool classof(const ParenExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+
+/// UnaryOperator - This represents the unary-expression's (except sizeof and
+/// alignof), the postinc/postdec operators from postfix-expression, and various
+/// extensions.
+///
+/// Notes on various nodes:
+///
+/// Real/Imag - These return the real/imag part of a complex operand. If
+/// applied to a non-complex value, the former returns its operand and the
+/// later returns zero in the type of the operand.
+///
+/// __builtin_offsetof(type, a.b[10]) is represented as a unary operator whose
+/// subexpression is a compound literal with the various MemberExpr and
+/// ArraySubscriptExpr's applied to it.
+///
+class UnaryOperator : public Expr {
+public:
+ // Note that additions to this should also update the StmtVisitor class.
+ enum Opcode {
+ PostInc, PostDec, // [C99 6.5.2.4] Postfix increment and decrement operators
+ PreInc, PreDec, // [C99 6.5.3.1] Prefix increment and decrement operators.
+ AddrOf, Deref, // [C99 6.5.3.2] Address and indirection operators.
+ Plus, Minus, // [C99 6.5.3.3] Unary arithmetic operators.
+ Not, LNot, // [C99 6.5.3.3] Unary arithmetic operators.
+ Real, Imag, // "__real expr"/"__imag expr" Extension.
+ Extension, // __extension__ marker.
+ OffsetOf // __builtin_offsetof
+ };
+private:
+ Stmt *Val;
+ Opcode Opc;
+ SourceLocation Loc;
+public:
+
+ UnaryOperator(Expr *input, Opcode opc, QualType type, SourceLocation l)
+ : Expr(UnaryOperatorClass, type,
+ input->isTypeDependent() && opc != OffsetOf,
+ input->isValueDependent()),
+ Val(input), Opc(opc), Loc(l) {}
+
+ /// \brief Build an empty unary operator.
+ explicit UnaryOperator(EmptyShell Empty)
+ : Expr(UnaryOperatorClass, Empty), Opc(AddrOf) { }
+
+ Opcode getOpcode() const { return Opc; }
+ void setOpcode(Opcode O) { Opc = O; }
+
+ Expr *getSubExpr() const { return cast<Expr>(Val); }
+ void setSubExpr(Expr *E) { Val = E; }
+
+ /// getOperatorLoc - Return the location of the operator.
+ SourceLocation getOperatorLoc() const { return Loc; }
+ void setOperatorLoc(SourceLocation L) { Loc = L; }
+
+ /// isPostfix - Return true if this is a postfix operation, like x++.
+ static bool isPostfix(Opcode Op) {
+ return Op == PostInc || Op == PostDec;
+ }
+
+ /// isPostfix - Return true if this is a prefix operation, like --x.
+ static bool isPrefix(Opcode Op) {
+ return Op == PreInc || Op == PreDec;
+ }
+
+ bool isPrefix() const { return isPrefix(Opc); }
+ bool isPostfix() const { return isPostfix(Opc); }
+ bool isIncrementOp() const {return Opc==PreInc || Opc==PostInc; }
+ bool isIncrementDecrementOp() const { return Opc>=PostInc && Opc<=PreDec; }
+ bool isOffsetOfOp() const { return Opc == OffsetOf; }
+ static bool isArithmeticOp(Opcode Op) { return Op >= Plus && Op <= LNot; }
+
+ /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
+ /// corresponds to, e.g. "sizeof" or "[pre]++"
+ static const char *getOpcodeStr(Opcode Op);
+
+ /// \brief Retrieve the unary opcode that corresponds to the given
+ /// overloaded operator.
+ static Opcode getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix);
+
+ /// \brief Retrieve the overloaded operator kind that corresponds to
+ /// the given unary opcode.
+ static OverloadedOperatorKind getOverloadedOperator(Opcode Opc);
+
+ virtual SourceRange getSourceRange() const {
+ if (isPostfix())
+ return SourceRange(Val->getLocStart(), Loc);
+ else
+ return SourceRange(Loc, Val->getLocEnd());
+ }
+ virtual SourceLocation getExprLoc() const { return Loc; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == UnaryOperatorClass;
+ }
+ static bool classof(const UnaryOperator *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// SizeOfAlignOfExpr - [C99 6.5.3.4] - This is for sizeof/alignof, both of
+/// types and expressions.
+class SizeOfAlignOfExpr : public Expr {
+ bool isSizeof : 1; // true if sizeof, false if alignof.
+ bool isType : 1; // true if operand is a type, false if an expression
+ union {
+ void *Ty;
+ Stmt *Ex;
+ } Argument;
+ SourceLocation OpLoc, RParenLoc;
+public:
+ SizeOfAlignOfExpr(bool issizeof, QualType T,
+ QualType resultType, SourceLocation op,
+ SourceLocation rp) :
+ Expr(SizeOfAlignOfExprClass, resultType,
+ false, // Never type-dependent (C++ [temp.dep.expr]p3).
+ // Value-dependent if the argument is type-dependent.
+ T->isDependentType()),
+ isSizeof(issizeof), isType(true), OpLoc(op), RParenLoc(rp) {
+ Argument.Ty = T.getAsOpaquePtr();
+ }
+
+ SizeOfAlignOfExpr(bool issizeof, Expr *E,
+ QualType resultType, SourceLocation op,
+ SourceLocation rp) :
+ Expr(SizeOfAlignOfExprClass, resultType,
+ false, // Never type-dependent (C++ [temp.dep.expr]p3).
+ // Value-dependent if the argument is type-dependent.
+ E->isTypeDependent()),
+ isSizeof(issizeof), isType(false), OpLoc(op), RParenLoc(rp) {
+ Argument.Ex = E;
+ }
+
+ /// \brief Construct an empty sizeof/alignof expression.
+ explicit SizeOfAlignOfExpr(EmptyShell Empty)
+ : Expr(SizeOfAlignOfExprClass, Empty) { }
+
+ virtual void Destroy(ASTContext& C);
+
+ bool isSizeOf() const { return isSizeof; }
+ void setSizeof(bool S) { isSizeof = S; }
+
+ bool isArgumentType() const { return isType; }
+ QualType getArgumentType() const {
+ assert(isArgumentType() && "calling getArgumentType() when arg is expr");
+ return QualType::getFromOpaquePtr(Argument.Ty);
+ }
+ Expr *getArgumentExpr() {
+ assert(!isArgumentType() && "calling getArgumentExpr() when arg is type");
+ return static_cast<Expr*>(Argument.Ex);
+ }
+ const Expr *getArgumentExpr() const {
+ return const_cast<SizeOfAlignOfExpr*>(this)->getArgumentExpr();
+ }
+
+ void setArgument(Expr *E) { Argument.Ex = E; isType = false; }
+ void setArgument(QualType T) {
+ Argument.Ty = T.getAsOpaquePtr();
+ isType = true;
+ }
+
+ /// Gets the argument type, or the type of the argument expression, whichever
+ /// is appropriate.
+ QualType getTypeOfArgument() const {
+ return isArgumentType() ? getArgumentType() : getArgumentExpr()->getType();
+ }
+
+ SourceLocation getOperatorLoc() const { return OpLoc; }
+ void setOperatorLoc(SourceLocation L) { OpLoc = L; }
+
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(OpLoc, RParenLoc);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == SizeOfAlignOfExprClass;
+ }
+ static bool classof(const SizeOfAlignOfExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+//===----------------------------------------------------------------------===//
+// Postfix Operators.
+//===----------------------------------------------------------------------===//
+
+/// ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
+class ArraySubscriptExpr : public Expr {
+ enum { LHS, RHS, END_EXPR=2 };
+ Stmt* SubExprs[END_EXPR];
+ SourceLocation RBracketLoc;
+public:
+ ArraySubscriptExpr(Expr *lhs, Expr *rhs, QualType t,
+ SourceLocation rbracketloc)
+ : Expr(ArraySubscriptExprClass, t,
+ lhs->isTypeDependent() || rhs->isTypeDependent(),
+ lhs->isValueDependent() || rhs->isValueDependent()),
+ RBracketLoc(rbracketloc) {
+ SubExprs[LHS] = lhs;
+ SubExprs[RHS] = rhs;
+ }
+
+ /// \brief Create an empty array subscript expression.
+ explicit ArraySubscriptExpr(EmptyShell Shell)
+ : Expr(ArraySubscriptExprClass, Shell) { }
+
+ /// An array access can be written A[4] or 4[A] (both are equivalent).
+ /// - getBase() and getIdx() always present the normalized view: A[4].
+ /// In this case getBase() returns "A" and getIdx() returns "4".
+ /// - getLHS() and getRHS() present the syntactic view. e.g. for
+ /// 4[A] getLHS() returns "4".
+ /// Note: Because vector element access is also written A[4] we must
+ /// predicate the format conversion in getBase and getIdx only on the
+ /// the type of the RHS, as it is possible for the LHS to be a vector of
+ /// integer type
+ Expr *getLHS() { return cast<Expr>(SubExprs[LHS]); }
+ const Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); }
+ void setLHS(Expr *E) { SubExprs[LHS] = E; }
+
+ Expr *getRHS() { return cast<Expr>(SubExprs[RHS]); }
+ const Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); }
+ void setRHS(Expr *E) { SubExprs[RHS] = E; }
+
+ Expr *getBase() {
+ return cast<Expr>(getRHS()->getType()->isIntegerType() ? getLHS():getRHS());
+ }
+
+ const Expr *getBase() const {
+ return cast<Expr>(getRHS()->getType()->isIntegerType() ? getLHS():getRHS());
+ }
+
+ Expr *getIdx() {
+ return cast<Expr>(getRHS()->getType()->isIntegerType() ? getRHS():getLHS());
+ }
+
+ const Expr *getIdx() const {
+ return cast<Expr>(getRHS()->getType()->isIntegerType() ? getRHS():getLHS());
+ }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(getLHS()->getLocStart(), RBracketLoc);
+ }
+
+ SourceLocation getRBracketLoc() const { return RBracketLoc; }
+ void setRBracketLoc(SourceLocation L) { RBracketLoc = L; }
+
+ virtual SourceLocation getExprLoc() const { return getBase()->getExprLoc(); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ArraySubscriptExprClass;
+ }
+ static bool classof(const ArraySubscriptExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+
+/// CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
+/// CallExpr itself represents a normal function call, e.g., "f(x, 2)",
+/// while its subclasses may represent alternative syntax that (semantically)
+/// results in a function call. For example, CXXOperatorCallExpr is
+/// a subclass for overloaded operator calls that use operator syntax, e.g.,
+/// "str1 + str2" to resolve to a function call.
+class CallExpr : public Expr {
+ enum { FN=0, ARGS_START=1 };
+ Stmt **SubExprs;
+ unsigned NumArgs;
+ SourceLocation RParenLoc;
+
+protected:
+ // This version of the constructor is for derived classes.
+ CallExpr(ASTContext& C, StmtClass SC, Expr *fn, Expr **args, unsigned numargs,
+ QualType t, SourceLocation rparenloc);
+
+public:
+ CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, QualType t,
+ SourceLocation rparenloc);
+
+ /// \brief Build an empty call expression.
+ CallExpr(ASTContext &C, EmptyShell Empty);
+
+ ~CallExpr() {}
+
+ void Destroy(ASTContext& C);
+
+ const Expr *getCallee() const { return cast<Expr>(SubExprs[FN]); }
+ Expr *getCallee() { return cast<Expr>(SubExprs[FN]); }
+ void setCallee(Expr *F) { SubExprs[FN] = F; }
+
+ /// getNumArgs - Return the number of actual arguments to this call.
+ ///
+ unsigned getNumArgs() const { return NumArgs; }
+
+ /// getArg - Return the specified argument.
+ Expr *getArg(unsigned Arg) {
+ assert(Arg < NumArgs && "Arg access out of range!");
+ return cast<Expr>(SubExprs[Arg+ARGS_START]);
+ }
+ const Expr *getArg(unsigned Arg) const {
+ assert(Arg < NumArgs && "Arg access out of range!");
+ return cast<Expr>(SubExprs[Arg+ARGS_START]);
+ }
+
+ /// setArg - Set the specified argument.
+ void setArg(unsigned Arg, Expr *ArgExpr) {
+ assert(Arg < NumArgs && "Arg access out of range!");
+ SubExprs[Arg+ARGS_START] = ArgExpr;
+ }
+
+ /// setNumArgs - This changes the number of arguments present in this call.
+ /// Any orphaned expressions are deleted by this, and any new operands are set
+ /// to null.
+ void setNumArgs(ASTContext& C, unsigned NumArgs);
+
+ typedef ExprIterator arg_iterator;
+ typedef ConstExprIterator const_arg_iterator;
+
+ arg_iterator arg_begin() { return SubExprs+ARGS_START; }
+ arg_iterator arg_end() { return SubExprs+ARGS_START+getNumArgs(); }
+ const_arg_iterator arg_begin() const { return SubExprs+ARGS_START; }
+ const_arg_iterator arg_end() const { return SubExprs+ARGS_START+getNumArgs();}
+
+ /// getNumCommas - Return the number of commas that must have been present in
+ /// this function call.
+ unsigned getNumCommas() const { return NumArgs ? NumArgs - 1 : 0; }
+
+ /// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If
+ /// not, return 0.
+ unsigned isBuiltinCall(ASTContext &Context) const;
+
+ /// getCallReturnType - Get the return type of the call expr. This is not
+ /// always the type of the expr itself, if the return type is a reference
+ /// type.
+ QualType getCallReturnType() const;
+
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(getCallee()->getLocStart(), RParenLoc);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CallExprClass ||
+ T->getStmtClass() == CXXOperatorCallExprClass ||
+ T->getStmtClass() == CXXMemberCallExprClass;
+ }
+ static bool classof(const CallExpr *) { return true; }
+ static bool classof(const CXXOperatorCallExpr *) { return true; }
+ static bool classof(const CXXMemberCallExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F.
+///
+class MemberExpr : public Expr {
+ /// Base - the expression for the base pointer or structure references. In
+ /// X.F, this is "X".
+ Stmt *Base;
+
+ /// MemberDecl - This is the decl being referenced by the field/member name.
+ /// In X.F, this is the decl referenced by F.
+ NamedDecl *MemberDecl;
+
+ /// MemberLoc - This is the location of the member name.
+ SourceLocation MemberLoc;
+
+ /// IsArrow - True if this is "X->F", false if this is "X.F".
+ bool IsArrow;
+public:
+ MemberExpr(Expr *base, bool isarrow, NamedDecl *memberdecl, SourceLocation l,
+ QualType ty)
+ : Expr(MemberExprClass, ty,
+ base->isTypeDependent(), base->isValueDependent()),
+ Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow) {}
+
+ /// \brief Build an empty member reference expression.
+ explicit MemberExpr(EmptyShell Empty) : Expr(MemberExprClass, Empty) { }
+
+ void setBase(Expr *E) { Base = E; }
+ Expr *getBase() const { return cast<Expr>(Base); }
+
+ /// \brief Retrieve the member declaration to which this expression refers.
+ ///
+ /// The returned declaration will either be a FieldDecl or (in C++)
+ /// a CXXMethodDecl.
+ NamedDecl *getMemberDecl() const { return MemberDecl; }
+ void setMemberDecl(NamedDecl *D) { MemberDecl = D; }
+
+ bool isArrow() const { return IsArrow; }
+ void setArrow(bool A) { IsArrow = A; }
+
+ /// getMemberLoc - Return the location of the "member", in X->F, it is the
+ /// location of 'F'.
+ SourceLocation getMemberLoc() const { return MemberLoc; }
+ void setMemberLoc(SourceLocation L) { MemberLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ // If we have an implicit base (like a C++ implicit this),
+ // make sure not to return its location
+ SourceLocation BaseLoc = getBase()->getLocStart();
+ if (BaseLoc.isInvalid())
+ return SourceRange(MemberLoc, MemberLoc);
+ return SourceRange(BaseLoc, MemberLoc);
+ }
+
+ virtual SourceLocation getExprLoc() const { return MemberLoc; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == MemberExprClass;
+ }
+ static bool classof(const MemberExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// CompoundLiteralExpr - [C99 6.5.2.5]
+///
+class CompoundLiteralExpr : public Expr {
+ /// LParenLoc - If non-null, this is the location of the left paren in a
+ /// compound literal like "(int){4}". This can be null if this is a
+ /// synthesized compound expression.
+ SourceLocation LParenLoc;
+ Stmt *Init;
+ bool FileScope;
+public:
+ CompoundLiteralExpr(SourceLocation lparenloc, QualType ty, Expr *init,
+ bool fileScope)
+ : Expr(CompoundLiteralExprClass, ty), LParenLoc(lparenloc), Init(init),
+ FileScope(fileScope) {}
+
+ /// \brief Construct an empty compound literal.
+ explicit CompoundLiteralExpr(EmptyShell Empty)
+ : Expr(CompoundLiteralExprClass, Empty) { }
+
+ const Expr *getInitializer() const { return cast<Expr>(Init); }
+ Expr *getInitializer() { return cast<Expr>(Init); }
+ void setInitializer(Expr *E) { Init = E; }
+
+ bool isFileScope() const { return FileScope; }
+ void setFileScope(bool FS) { FileScope = FS; }
+
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+ void setLParenLoc(SourceLocation L) { LParenLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ // FIXME: Init should never be null.
+ if (!Init)
+ return SourceRange();
+ if (LParenLoc.isInvalid())
+ return Init->getSourceRange();
+ return SourceRange(LParenLoc, Init->getLocEnd());
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CompoundLiteralExprClass;
+ }
+ static bool classof(const CompoundLiteralExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// CastExpr - Base class for type casts, including both implicit
+/// casts (ImplicitCastExpr) and explicit casts that have some
+/// representation in the source code (ExplicitCastExpr's derived
+/// classes).
+class CastExpr : public Expr {
+ Stmt *Op;
+protected:
+ CastExpr(StmtClass SC, QualType ty, Expr *op) :
+ Expr(SC, ty,
+ // Cast expressions are type-dependent if the type is
+ // dependent (C++ [temp.dep.expr]p3).
+ ty->isDependentType(),
+ // Cast expressions are value-dependent if the type is
+ // dependent or if the subexpression is value-dependent.
+ ty->isDependentType() || (op && op->isValueDependent())),
+ Op(op) {}
+
+ /// \brief Construct an empty cast.
+ CastExpr(StmtClass SC, EmptyShell Empty)
+ : Expr(SC, Empty) { }
+
+public:
+ Expr *getSubExpr() { return cast<Expr>(Op); }
+ const Expr *getSubExpr() const { return cast<Expr>(Op); }
+ void setSubExpr(Expr *E) { Op = E; }
+
+ static bool classof(const Stmt *T) {
+ StmtClass SC = T->getStmtClass();
+ if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass)
+ return true;
+
+ if (SC >= ImplicitCastExprClass && SC <= CStyleCastExprClass)
+ return true;
+
+ return false;
+ }
+ static bool classof(const CastExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ImplicitCastExpr - Allows us to explicitly represent implicit type
+/// conversions, which have no direct representation in the original
+/// source code. For example: converting T[]->T*, void f()->void
+/// (*f)(), float->double, short->int, etc.
+///
+/// In C, implicit casts always produce rvalues. However, in C++, an
+/// implicit cast whose result is being bound to a reference will be
+/// an lvalue. For example:
+///
+/// @code
+/// class Base { };
+/// class Derived : public Base { };
+/// void f(Derived d) {
+/// Base& b = d; // initializer is an ImplicitCastExpr to an lvalue of type Base
+/// }
+/// @endcode
+class ImplicitCastExpr : public CastExpr {
+ /// LvalueCast - Whether this cast produces an lvalue.
+ bool LvalueCast;
+
+public:
+ ImplicitCastExpr(QualType ty, Expr *op, bool Lvalue) :
+ CastExpr(ImplicitCastExprClass, ty, op), LvalueCast(Lvalue) { }
+
+ /// \brief Construct an empty implicit cast.
+ explicit ImplicitCastExpr(EmptyShell Shell)
+ : CastExpr(ImplicitCastExprClass, Shell) { }
+
+
+ virtual SourceRange getSourceRange() const {
+ return getSubExpr()->getSourceRange();
+ }
+
+ /// isLvalueCast - Whether this cast produces an lvalue.
+ bool isLvalueCast() const { return LvalueCast; }
+
+ /// setLvalueCast - Set whether this cast produces an lvalue.
+ void setLvalueCast(bool Lvalue) { LvalueCast = Lvalue; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ImplicitCastExprClass;
+ }
+ static bool classof(const ImplicitCastExpr *) { return true; }
+};
+
+/// ExplicitCastExpr - An explicit cast written in the source
+/// code.
+///
+/// This class is effectively an abstract class, because it provides
+/// the basic representation of an explicitly-written cast without
+/// specifying which kind of cast (C cast, functional cast, static
+/// cast, etc.) was written; specific derived classes represent the
+/// particular style of cast and its location information.
+///
+/// Unlike implicit casts, explicit cast nodes have two different
+/// types: the type that was written into the source code, and the
+/// actual type of the expression as determined by semantic
+/// analysis. These types may differ slightly. For example, in C++ one
+/// can cast to a reference type, which indicates that the resulting
+/// expression will be an lvalue. The reference type, however, will
+/// not be used as the type of the expression.
+class ExplicitCastExpr : public CastExpr {
+ /// TypeAsWritten - The type that this expression is casting to, as
+ /// written in the source code.
+ QualType TypeAsWritten;
+
+protected:
+ ExplicitCastExpr(StmtClass SC, QualType exprTy, Expr *op, QualType writtenTy)
+ : CastExpr(SC, exprTy, op), TypeAsWritten(writtenTy) {}
+
+ /// \brief Construct an empty explicit cast.
+ ExplicitCastExpr(StmtClass SC, EmptyShell Shell)
+ : CastExpr(SC, Shell) { }
+
+public:
+ /// getTypeAsWritten - Returns the type that this expression is
+ /// casting to, as written in the source code.
+ QualType getTypeAsWritten() const { return TypeAsWritten; }
+ void setTypeAsWritten(QualType T) { TypeAsWritten = T; }
+
+ static bool classof(const Stmt *T) {
+ StmtClass SC = T->getStmtClass();
+ if (SC >= ExplicitCastExprClass && SC <= CStyleCastExprClass)
+ return true;
+ if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass)
+ return true;
+
+ return false;
+ }
+ static bool classof(const ExplicitCastExpr *) { return true; }
+};
+
+/// CStyleCastExpr - 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: @c (int)f.
+class CStyleCastExpr : public ExplicitCastExpr {
+ SourceLocation LPLoc; // the location of the left paren
+ SourceLocation RPLoc; // the location of the right paren
+public:
+ CStyleCastExpr(QualType exprTy, Expr *op, QualType writtenTy,
+ SourceLocation l, SourceLocation r) :
+ ExplicitCastExpr(CStyleCastExprClass, exprTy, op, writtenTy),
+ LPLoc(l), RPLoc(r) {}
+
+ /// \brief Construct an empty C-style explicit cast.
+ explicit CStyleCastExpr(EmptyShell Shell)
+ : ExplicitCastExpr(CStyleCastExprClass, Shell) { }
+
+ SourceLocation getLParenLoc() const { return LPLoc; }
+ void setLParenLoc(SourceLocation L) { LPLoc = L; }
+
+ SourceLocation getRParenLoc() const { return RPLoc; }
+ void setRParenLoc(SourceLocation L) { RPLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(LPLoc, getSubExpr()->getSourceRange().getEnd());
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CStyleCastExprClass;
+ }
+ static bool classof(const CStyleCastExpr *) { return true; }
+};
+
+/// \brief A builtin binary operation expression such as "x + y" or "x <= y".
+///
+/// This expression node kind describes a builtin binary operation,
+/// such as "x + y" for integer values "x" and "y". The operands will
+/// already have been converted to appropriate types (e.g., by
+/// performing promotions or conversions).
+///
+/// In C++, where operators may be overloaded, a different kind of
+/// expression node (CXXOperatorCallExpr) is used to express the
+/// invocation of an overloaded operator with operator syntax. Within
+/// a C++ template, whether BinaryOperator or CXXOperatorCallExpr is
+/// used to store an expression "x + y" depends on the subexpressions
+/// for x and y. If neither x or y is type-dependent, and the "+"
+/// operator resolves to a built-in operation, BinaryOperator will be
+/// used to express the computation (x and y may still be
+/// value-dependent). If either x or y is type-dependent, or if the
+/// "+" resolves to an overloaded operator, CXXOperatorCallExpr will
+/// be used to express the computation.
+class BinaryOperator : public Expr {
+public:
+ enum Opcode {
+ // Operators listed in order of precedence.
+ // Note that additions to this should also update the StmtVisitor class.
+ PtrMemD, PtrMemI, // [C++ 5.5] Pointer-to-member operators.
+ Mul, Div, Rem, // [C99 6.5.5] Multiplicative operators.
+ Add, Sub, // [C99 6.5.6] Additive operators.
+ Shl, Shr, // [C99 6.5.7] Bitwise shift operators.
+ LT, GT, LE, GE, // [C99 6.5.8] Relational operators.
+ EQ, NE, // [C99 6.5.9] Equality operators.
+ And, // [C99 6.5.10] Bitwise AND operator.
+ Xor, // [C99 6.5.11] Bitwise XOR operator.
+ Or, // [C99 6.5.12] Bitwise OR operator.
+ LAnd, // [C99 6.5.13] Logical AND operator.
+ LOr, // [C99 6.5.14] Logical OR operator.
+ Assign, MulAssign,// [C99 6.5.16] Assignment operators.
+ DivAssign, RemAssign,
+ AddAssign, SubAssign,
+ ShlAssign, ShrAssign,
+ AndAssign, XorAssign,
+ OrAssign,
+ Comma // [C99 6.5.17] Comma operator.
+ };
+private:
+ enum { LHS, RHS, END_EXPR };
+ Stmt* SubExprs[END_EXPR];
+ Opcode Opc;
+ SourceLocation OpLoc;
+public:
+
+ BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
+ SourceLocation opLoc)
+ : Expr(BinaryOperatorClass, ResTy,
+ lhs->isTypeDependent() || rhs->isTypeDependent(),
+ lhs->isValueDependent() || rhs->isValueDependent()),
+ Opc(opc), OpLoc(opLoc) {
+ SubExprs[LHS] = lhs;
+ SubExprs[RHS] = rhs;
+ assert(!isCompoundAssignmentOp() &&
+ "Use ArithAssignBinaryOperator for compound assignments");
+ }
+
+ /// \brief Construct an empty binary operator.
+ explicit BinaryOperator(EmptyShell Empty)
+ : Expr(BinaryOperatorClass, Empty), Opc(Comma) { }
+
+ SourceLocation getOperatorLoc() const { return OpLoc; }
+ void setOperatorLoc(SourceLocation L) { OpLoc = L; }
+
+ Opcode getOpcode() const { return Opc; }
+ void setOpcode(Opcode O) { Opc = O; }
+
+ Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); }
+ void setLHS(Expr *E) { SubExprs[LHS] = E; }
+ Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); }
+ void setRHS(Expr *E) { SubExprs[RHS] = E; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(getLHS()->getLocStart(), getRHS()->getLocEnd());
+ }
+
+ /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
+ /// corresponds to, e.g. "<<=".
+ static const char *getOpcodeStr(Opcode Op);
+
+ /// \brief Retrieve the binary opcode that corresponds to the given
+ /// overloaded operator.
+ static Opcode getOverloadedOpcode(OverloadedOperatorKind OO);
+
+ /// \brief Retrieve the overloaded operator kind that corresponds to
+ /// the given binary opcode.
+ static OverloadedOperatorKind getOverloadedOperator(Opcode Opc);
+
+ /// predicates to categorize the respective opcodes.
+ bool isMultiplicativeOp() const { return Opc >= Mul && Opc <= Rem; }
+ bool isAdditiveOp() const { return Opc == Add || Opc == Sub; }
+ bool isShiftOp() const { return Opc == Shl || Opc == Shr; }
+ bool isBitwiseOp() const { return Opc >= And && Opc <= Or; }
+
+ static bool isRelationalOp(Opcode Opc) { return Opc >= LT && Opc <= GE; }
+ bool isRelationalOp() const { return isRelationalOp(Opc); }
+
+ static bool isEqualityOp(Opcode Opc) { return Opc == EQ || Opc == NE; }
+ bool isEqualityOp() const { return isEqualityOp(Opc); }
+
+ static bool isLogicalOp(Opcode Opc) { return Opc == LAnd || Opc == LOr; }
+ bool isLogicalOp() const { return isLogicalOp(Opc); }
+
+ bool isAssignmentOp() const { return Opc >= Assign && Opc <= OrAssign; }
+ bool isCompoundAssignmentOp() const { return Opc > Assign && Opc <= OrAssign;}
+ bool isShiftAssignOp() const { return Opc == ShlAssign || Opc == ShrAssign; }
+
+ static bool classof(const Stmt *S) {
+ return S->getStmtClass() == BinaryOperatorClass ||
+ S->getStmtClass() == CompoundAssignOperatorClass;
+ }
+ static bool classof(const BinaryOperator *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+
+protected:
+ BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
+ SourceLocation oploc, bool dead)
+ : Expr(CompoundAssignOperatorClass, ResTy), Opc(opc), OpLoc(oploc) {
+ SubExprs[LHS] = lhs;
+ SubExprs[RHS] = rhs;
+ }
+
+ BinaryOperator(StmtClass SC, EmptyShell Empty)
+ : Expr(SC, Empty), Opc(MulAssign) { }
+};
+
+/// 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
+/// implicit conversion back to the result type done, then the assignment takes
+/// place. This captures the intermediate type which the computation is done
+/// in.
+class CompoundAssignOperator : public BinaryOperator {
+ QualType ComputationLHSType;
+ QualType ComputationResultType;
+public:
+ CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc,
+ QualType ResType, QualType CompLHSType,
+ QualType CompResultType,
+ SourceLocation OpLoc)
+ : BinaryOperator(lhs, rhs, opc, ResType, OpLoc, true),
+ ComputationLHSType(CompLHSType),
+ ComputationResultType(CompResultType) {
+ assert(isCompoundAssignmentOp() &&
+ "Only should be used for compound assignments");
+ }
+
+ /// \brief Build an empty compound assignment operator expression.
+ explicit CompoundAssignOperator(EmptyShell Empty)
+ : BinaryOperator(CompoundAssignOperatorClass, Empty) { }
+
+ // The two computation types are the type the LHS is converted
+ // to for the computation and the type of the result; the two are
+ // distinct in a few cases (specifically, int+=ptr and ptr-=ptr).
+ QualType getComputationLHSType() const { return ComputationLHSType; }
+ void setComputationLHSType(QualType T) { ComputationLHSType = T; }
+
+ QualType getComputationResultType() const { return ComputationResultType; }
+ void setComputationResultType(QualType T) { ComputationResultType = T; }
+
+ static bool classof(const CompoundAssignOperator *) { return true; }
+ static bool classof(const Stmt *S) {
+ return S->getStmtClass() == CompoundAssignOperatorClass;
+ }
+};
+
+/// ConditionalOperator - The ?: operator. Note that LHS may be null when the
+/// GNU "missing LHS" extension is in use.
+///
+class ConditionalOperator : public Expr {
+ enum { COND, LHS, RHS, END_EXPR };
+ Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides.
+public:
+ ConditionalOperator(Expr *cond, Expr *lhs, Expr *rhs, QualType t)
+ : Expr(ConditionalOperatorClass, t,
+ // FIXME: the type of the conditional operator doesn't
+ // depend on the type of the conditional, but the standard
+ // seems to imply that it could. File a bug!
+ ((lhs && lhs->isTypeDependent()) || (rhs && rhs->isTypeDependent())),
+ (cond->isValueDependent() ||
+ (lhs && lhs->isValueDependent()) ||
+ (rhs && rhs->isValueDependent()))) {
+ SubExprs[COND] = cond;
+ SubExprs[LHS] = lhs;
+ SubExprs[RHS] = rhs;
+ }
+
+ /// \brief Build an empty conditional operator.
+ explicit ConditionalOperator(EmptyShell Empty)
+ : Expr(ConditionalOperatorClass, Empty) { }
+
+ // getCond - Return the expression representing the condition for
+ // the ?: operator.
+ Expr *getCond() const { return cast<Expr>(SubExprs[COND]); }
+ void setCond(Expr *E) { SubExprs[COND] = E; }
+
+ // getTrueExpr - Return the subexpression representing the value of the ?:
+ // expression if the condition evaluates to true. In most cases this value
+ // will be the same as getLHS() except a GCC extension allows the left
+ // subexpression to be omitted, and instead of the condition be returned.
+ // e.g: x ?: y is shorthand for x ? x : y, except that the expression "x"
+ // is only evaluated once.
+ Expr *getTrueExpr() const {
+ return cast<Expr>(SubExprs[LHS] ? SubExprs[LHS] : SubExprs[COND]);
+ }
+
+ // getTrueExpr - Return the subexpression representing the value of the ?:
+ // expression if the condition evaluates to false. This is the same as getRHS.
+ Expr *getFalseExpr() const { return cast<Expr>(SubExprs[RHS]); }
+
+ Expr *getLHS() const { return cast_or_null<Expr>(SubExprs[LHS]); }
+ void setLHS(Expr *E) { SubExprs[LHS] = E; }
+
+ Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); }
+ void setRHS(Expr *E) { SubExprs[RHS] = E; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(getCond()->getLocStart(), getRHS()->getLocEnd());
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ConditionalOperatorClass;
+ }
+ static bool classof(const ConditionalOperator *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// AddrLabelExpr - The GNU address of label extension, representing &&label.
+class AddrLabelExpr : public Expr {
+ SourceLocation AmpAmpLoc, LabelLoc;
+ LabelStmt *Label;
+public:
+ AddrLabelExpr(SourceLocation AALoc, SourceLocation LLoc, LabelStmt *L,
+ QualType t)
+ : Expr(AddrLabelExprClass, t), AmpAmpLoc(AALoc), LabelLoc(LLoc), Label(L) {}
+
+ /// \brief Build an empty address of a label expression.
+ explicit AddrLabelExpr(EmptyShell Empty)
+ : Expr(AddrLabelExprClass, Empty) { }
+
+ SourceLocation getAmpAmpLoc() const { return AmpAmpLoc; }
+ void setAmpAmpLoc(SourceLocation L) { AmpAmpLoc = L; }
+ SourceLocation getLabelLoc() const { return LabelLoc; }
+ void setLabelLoc(SourceLocation L) { LabelLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(AmpAmpLoc, LabelLoc);
+ }
+
+ LabelStmt *getLabel() const { return Label; }
+ void setLabel(LabelStmt *S) { Label = S; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == AddrLabelExprClass;
+ }
+ static bool classof(const AddrLabelExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}).
+/// The StmtExpr contains a single CompoundStmt node, which it evaluates and
+/// takes the value of the last subexpression.
+class StmtExpr : public Expr {
+ Stmt *SubStmt;
+ SourceLocation LParenLoc, RParenLoc;
+public:
+ StmtExpr(CompoundStmt *substmt, QualType T,
+ SourceLocation lp, SourceLocation rp) :
+ Expr(StmtExprClass, T), SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) { }
+
+ /// \brief Build an empty statement expression.
+ explicit StmtExpr(EmptyShell Empty) : Expr(StmtExprClass, Empty) { }
+
+ CompoundStmt *getSubStmt() { return cast<CompoundStmt>(SubStmt); }
+ const CompoundStmt *getSubStmt() const { return cast<CompoundStmt>(SubStmt); }
+ void setSubStmt(CompoundStmt *S) { SubStmt = S; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(LParenLoc, RParenLoc);
+ }
+
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+ void setLParenLoc(SourceLocation L) { LParenLoc = L; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == StmtExprClass;
+ }
+ static bool classof(const StmtExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// TypesCompatibleExpr - GNU builtin-in function __builtin_types_compatible_p.
+/// This AST node represents a function that returns 1 if two *types* (not
+/// expressions) are compatible. The result of this built-in function can be
+/// used in integer constant expressions.
+class TypesCompatibleExpr : public Expr {
+ QualType Type1;
+ QualType Type2;
+ SourceLocation BuiltinLoc, RParenLoc;
+public:
+ TypesCompatibleExpr(QualType ReturnType, SourceLocation BLoc,
+ QualType t1, QualType t2, SourceLocation RP) :
+ Expr(TypesCompatibleExprClass, ReturnType), Type1(t1), Type2(t2),
+ BuiltinLoc(BLoc), RParenLoc(RP) {}
+
+ /// \brief Build an empty __builtin_type_compatible_p expression.
+ explicit TypesCompatibleExpr(EmptyShell Empty)
+ : Expr(TypesCompatibleExprClass, Empty) { }
+
+ QualType getArgType1() const { return Type1; }
+ void setArgType1(QualType T) { Type1 = T; }
+ QualType getArgType2() const { return Type2; }
+ void setArgType2(QualType T) { Type2 = T; }
+
+ SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
+ void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; }
+
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(BuiltinLoc, RParenLoc);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == TypesCompatibleExprClass;
+ }
+ static bool classof(const TypesCompatibleExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ShuffleVectorExpr - clang-specific builtin-in function
+/// __builtin_shufflevector.
+/// This AST node represents a operator that does a constant
+/// shuffle, similar to LLVM's shufflevector instruction. It takes
+/// two vectors and a variable number of constant indices,
+/// and returns the appropriately shuffled vector.
+class ShuffleVectorExpr : public Expr {
+ SourceLocation BuiltinLoc, RParenLoc;
+
+ // SubExprs - the list of values passed to the __builtin_shufflevector
+ // function. The first two are vectors, and the rest are constant
+ // indices. The number of values in this list is always
+ // 2+the number of indices in the vector type.
+ Stmt **SubExprs;
+ unsigned NumExprs;
+
+public:
+ ShuffleVectorExpr(Expr **args, unsigned nexpr,
+ QualType Type, SourceLocation BLoc,
+ SourceLocation RP) :
+ Expr(ShuffleVectorExprClass, Type), BuiltinLoc(BLoc),
+ RParenLoc(RP), NumExprs(nexpr) {
+
+ SubExprs = new Stmt*[nexpr];
+ for (unsigned i = 0; i < nexpr; i++)
+ SubExprs[i] = args[i];
+ }
+
+ /// \brief Build an empty vector-shuffle expression.
+ explicit ShuffleVectorExpr(EmptyShell Empty)
+ : Expr(ShuffleVectorExprClass, Empty), SubExprs(0) { }
+
+ SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
+ void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; }
+
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(BuiltinLoc, RParenLoc);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ShuffleVectorExprClass;
+ }
+ static bool classof(const ShuffleVectorExpr *) { return true; }
+
+ ~ShuffleVectorExpr() {
+ delete [] SubExprs;
+ }
+
+ /// getNumSubExprs - Return the size of the SubExprs array. This includes the
+ /// constant expression, the actual arguments passed in, and the function
+ /// pointers.
+ unsigned getNumSubExprs() const { return NumExprs; }
+
+ /// getExpr - Return the Expr at the specified index.
+ Expr *getExpr(unsigned Index) {
+ assert((Index < NumExprs) && "Arg access out of range!");
+ return cast<Expr>(SubExprs[Index]);
+ }
+ const Expr *getExpr(unsigned Index) const {
+ assert((Index < NumExprs) && "Arg access out of range!");
+ return cast<Expr>(SubExprs[Index]);
+ }
+
+ void setExprs(Expr ** Exprs, unsigned NumExprs);
+
+ unsigned getShuffleMaskIdx(ASTContext &Ctx, unsigned N) {
+ assert((N < NumExprs - 2) && "Shuffle idx out of range!");
+ return getExpr(N+2)->EvaluateAsInt(Ctx).getZExtValue();
+ }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ChooseExpr - GNU builtin-in function __builtin_choose_expr.
+/// This AST node is similar to the conditional operator (?:) in C, with
+/// the following exceptions:
+/// - the test expression must be a integer constant expression.
+/// - the expression returned acts like the chosen subexpression in every
+/// visible way: the type is the same as that of the chosen subexpression,
+/// and all predicates (whether it's an l-value, whether it's an integer
+/// constant expression, etc.) return the same result as for the chosen
+/// sub-expression.
+class ChooseExpr : public Expr {
+ enum { COND, LHS, RHS, END_EXPR };
+ Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides.
+ SourceLocation BuiltinLoc, RParenLoc;
+public:
+ ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs, QualType t,
+ SourceLocation RP)
+ : Expr(ChooseExprClass, t),
+ BuiltinLoc(BLoc), RParenLoc(RP) {
+ SubExprs[COND] = cond;
+ SubExprs[LHS] = lhs;
+ SubExprs[RHS] = rhs;
+ }
+
+ /// \brief Build an empty __builtin_choose_expr.
+ explicit ChooseExpr(EmptyShell Empty) : Expr(ChooseExprClass, Empty) { }
+
+ /// isConditionTrue - Return whether the condition is true (i.e. not
+ /// equal to zero).
+ bool isConditionTrue(ASTContext &C) const;
+
+ /// getChosenSubExpr - Return the subexpression chosen according to the
+ /// condition.
+ Expr *getChosenSubExpr(ASTContext &C) const {
+ return isConditionTrue(C) ? getLHS() : getRHS();
+ }
+
+ Expr *getCond() const { return cast<Expr>(SubExprs[COND]); }
+ void setCond(Expr *E) { SubExprs[COND] = E; }
+ Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); }
+ void setLHS(Expr *E) { SubExprs[LHS] = E; }
+ Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); }
+ void setRHS(Expr *E) { SubExprs[RHS] = E; }
+
+ SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
+ void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; }
+
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(BuiltinLoc, RParenLoc);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ChooseExprClass;
+ }
+ static bool classof(const ChooseExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// GNUNullExpr - 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).
+class GNUNullExpr : public Expr {
+ /// TokenLoc - The location of the __null keyword.
+ SourceLocation TokenLoc;
+
+public:
+ GNUNullExpr(QualType Ty, SourceLocation Loc)
+ : Expr(GNUNullExprClass, Ty), TokenLoc(Loc) { }
+
+ /// \brief Build an empty GNU __null expression.
+ explicit GNUNullExpr(EmptyShell Empty) : Expr(GNUNullExprClass, Empty) { }
+
+ GNUNullExpr* Clone(ASTContext &C) const;
+
+ /// getTokenLocation - The location of the __null token.
+ SourceLocation getTokenLocation() const { return TokenLoc; }
+ void setTokenLocation(SourceLocation L) { TokenLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(TokenLoc);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == GNUNullExprClass;
+ }
+ static bool classof(const GNUNullExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// VAArgExpr, used for the builtin function __builtin_va_start.
+class VAArgExpr : public Expr {
+ Stmt *Val;
+ SourceLocation BuiltinLoc, RParenLoc;
+public:
+ VAArgExpr(SourceLocation BLoc, Expr* e, QualType t, SourceLocation RPLoc)
+ : Expr(VAArgExprClass, t),
+ Val(e),
+ BuiltinLoc(BLoc),
+ RParenLoc(RPLoc) { }
+
+ /// \brief Create an empty __builtin_va_start expression.
+ explicit VAArgExpr(EmptyShell Empty) : Expr(VAArgExprClass, Empty) { }
+
+ const Expr *getSubExpr() const { return cast<Expr>(Val); }
+ Expr *getSubExpr() { return cast<Expr>(Val); }
+ void setSubExpr(Expr *E) { Val = E; }
+
+ SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
+ void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; }
+
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(BuiltinLoc, RParenLoc);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == VAArgExprClass;
+ }
+ static bool classof(const VAArgExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// @brief Describes an C or C++ initializer list.
+///
+/// InitListExpr describes an initializer list, which can be used to
+/// initialize objects of different types, including
+/// struct/class/union types, arrays, and vectors. For example:
+///
+/// @code
+/// struct foo x = { 1, { 2, 3 } };
+/// @endcode
+///
+/// Prior to semantic analysis, an initializer list will represent the
+/// initializer list as written by the user, but will have the
+/// placeholder type "void". This initializer list is called the
+/// syntactic form of the initializer, and may contain C99 designated
+/// initializers (represented as DesignatedInitExprs), initializations
+/// of subobject members without explicit braces, and so on. Clients
+/// interested in the original syntax of the initializer list should
+/// use the syntactic form of the initializer list.
+///
+/// After semantic analysis, the initializer list will represent the
+/// semantic form of the initializer, where the initializations of all
+/// subobjects are made explicit with nested InitListExpr nodes and
+/// C99 designators have been eliminated by placing the designated
+/// initializations into the subobject they initialize. Additionally,
+/// any "holes" in the initialization, where no initializer has been
+/// specified for a particular subobject, will be replaced with
+/// implicitly-generated ImplicitValueInitExpr expressions that
+/// value-initialize the subobjects. Note, however, that the
+/// initializer lists may still have fewer initializers than there are
+/// elements to initialize within the object.
+///
+/// Given the semantic form of the initializer list, one can retrieve
+/// the original syntactic form of that initializer list (if it
+/// exists) using getSyntacticForm(). Since many initializer lists
+/// have the same syntactic and semantic forms, getSyntacticForm() may
+/// return NULL, indicating that the current initializer list also
+/// serves as its syntactic form.
+class InitListExpr : public Expr {
+ std::vector<Stmt *> InitExprs;
+ SourceLocation LBraceLoc, RBraceLoc;
+
+ /// Contains the initializer list that describes the syntactic form
+ /// written in the source code.
+ InitListExpr *SyntacticForm;
+
+ /// If this initializer list initializes a union, specifies which
+ /// field within the union will be initialized.
+ FieldDecl *UnionFieldInit;
+
+ /// Whether this initializer list originally had a GNU array-range
+ /// designator in it. This is a temporary marker used by CodeGen.
+ bool HadArrayRangeDesignator;
+
+public:
+ InitListExpr(SourceLocation lbraceloc, Expr **initexprs, unsigned numinits,
+ SourceLocation rbraceloc);
+
+ /// \brief Build an empty initializer list.
+ explicit InitListExpr(EmptyShell Empty) : Expr(InitListExprClass, Empty) { }
+
+ unsigned getNumInits() const { return InitExprs.size(); }
+
+ const Expr* getInit(unsigned Init) const {
+ assert(Init < getNumInits() && "Initializer access out of range!");
+ return cast_or_null<Expr>(InitExprs[Init]);
+ }
+
+ Expr* getInit(unsigned Init) {
+ assert(Init < getNumInits() && "Initializer access out of range!");
+ return cast_or_null<Expr>(InitExprs[Init]);
+ }
+
+ void setInit(unsigned Init, Expr *expr) {
+ assert(Init < getNumInits() && "Initializer access out of range!");
+ InitExprs[Init] = expr;
+ }
+
+ /// \brief Reserve space for some number of initializers.
+ void reserveInits(unsigned NumInits);
+
+ /// @brief Specify the number of initializers
+ ///
+ /// If there are more than @p NumInits initializers, the remaining
+ /// initializers will be destroyed. If there are fewer than @p
+ /// NumInits initializers, NULL expressions will be added for the
+ /// unknown initializers.
+ void resizeInits(ASTContext &Context, unsigned NumInits);
+
+ /// @brief Updates the initializer at index @p Init with the new
+ /// expression @p expr, and returns the old expression at that
+ /// location.
+ ///
+ /// When @p Init is out of range for this initializer list, the
+ /// initializer list will be extended with NULL expressions to
+ /// accomodate the new entry.
+ Expr *updateInit(unsigned Init, Expr *expr);
+
+ /// \brief If this initializes a union, specifies which field in the
+ /// union to initialize.
+ ///
+ /// Typically, this field is the first named field within the
+ /// union. However, a designated initializer can specify the
+ /// initialization of a different field within the union.
+ FieldDecl *getInitializedFieldInUnion() { return UnionFieldInit; }
+ void setInitializedFieldInUnion(FieldDecl *FD) { UnionFieldInit = FD; }
+
+ // Explicit InitListExpr's originate from source code (and have valid source
+ // locations). Implicit InitListExpr's are created by the semantic analyzer.
+ bool isExplicit() {
+ return LBraceLoc.isValid() && RBraceLoc.isValid();
+ }
+
+ SourceLocation getLBraceLoc() const { return LBraceLoc; }
+ void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; }
+ SourceLocation getRBraceLoc() const { return RBraceLoc; }
+ void setRBraceLoc(SourceLocation Loc) { RBraceLoc = Loc; }
+
+ /// @brief Retrieve the initializer list that describes the
+ /// syntactic form of the initializer.
+ ///
+ ///
+ InitListExpr *getSyntacticForm() const { return SyntacticForm; }
+ void setSyntacticForm(InitListExpr *Init) { SyntacticForm = Init; }
+
+ bool hadArrayRangeDesignator() const { return HadArrayRangeDesignator; }
+ void sawArrayRangeDesignator(bool ARD = true) {
+ HadArrayRangeDesignator = ARD;
+ }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(LBraceLoc, RBraceLoc);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == InitListExprClass;
+ }
+ static bool classof(const InitListExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+
+ typedef std::vector<Stmt *>::iterator iterator;
+ typedef std::vector<Stmt *>::reverse_iterator reverse_iterator;
+
+ iterator begin() { return InitExprs.begin(); }
+ iterator end() { return InitExprs.end(); }
+ reverse_iterator rbegin() { return InitExprs.rbegin(); }
+ reverse_iterator rend() { return InitExprs.rend(); }
+};
+
+/// @brief Represents a C99 designated initializer expression.
+///
+/// A designated initializer expression (C99 6.7.8) contains one or
+/// more designators (which can be field designators, array
+/// designators, or GNU array-range designators) followed by an
+/// expression that initializes the field or element(s) that the
+/// designators refer to. For example, given:
+///
+/// @code
+/// struct point {
+/// double x;
+/// double y;
+/// };
+/// struct point ptarray[10] = { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 };
+/// @endcode
+///
+/// The InitListExpr contains three DesignatedInitExprs, the first of
+/// which covers @c [2].y=1.0. This DesignatedInitExpr will have two
+/// designators, one array designator for @c [2] followed by one field
+/// designator for @c .y. The initalization expression will be 1.0.
+class DesignatedInitExpr : public Expr {
+public:
+ /// \brief Forward declaration of the Designator class.
+ class Designator;
+
+private:
+ /// The location of the '=' or ':' prior to the actual initializer
+ /// expression.
+ SourceLocation EqualOrColonLoc;
+
+ /// Whether this designated initializer used the GNU deprecated
+ /// syntax rather than the C99 '=' syntax.
+ bool GNUSyntax : 1;
+
+ /// The number of designators in this initializer expression.
+ unsigned NumDesignators : 15;
+
+ /// \brief The designators in this designated initialization
+ /// expression.
+ Designator *Designators;
+
+ /// The number of subexpressions of this initializer expression,
+ /// which contains both the initializer and any additional
+ /// expressions used by array and array-range designators.
+ unsigned NumSubExprs : 16;
+
+
+ DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
+ const Designator *Designators,
+ SourceLocation EqualOrColonLoc, bool GNUSyntax,
+ Expr **IndexExprs, unsigned NumIndexExprs,
+ Expr *Init);
+
+ explicit DesignatedInitExpr(unsigned NumSubExprs)
+ : Expr(DesignatedInitExprClass, EmptyShell()),
+ NumDesignators(0), Designators(0), NumSubExprs(NumSubExprs) { }
+
+public:
+ /// A field designator, e.g., ".x".
+ struct FieldDesignator {
+ /// Refers to the field that is being initialized. The low bit
+ /// of this field determines whether this is actually a pointer
+ /// to an IdentifierInfo (if 1) or a FieldDecl (if 0). When
+ /// initially constructed, a field designator will store an
+ /// IdentifierInfo*. After semantic analysis has resolved that
+ /// name, the field designator will instead store a FieldDecl*.
+ uintptr_t NameOrField;
+
+ /// The location of the '.' in the designated initializer.
+ unsigned DotLoc;
+
+ /// The location of the field name in the designated initializer.
+ unsigned FieldLoc;
+ };
+
+ /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]".
+ struct ArrayOrRangeDesignator {
+ /// Location of the first index expression within the designated
+ /// initializer expression's list of subexpressions.
+ unsigned Index;
+ /// The location of the '[' starting the array range designator.
+ unsigned LBracketLoc;
+ /// The location of the ellipsis separating the start and end
+ /// indices. Only valid for GNU array-range designators.
+ unsigned EllipsisLoc;
+ /// The location of the ']' terminating the array range designator.
+ unsigned RBracketLoc;
+ };
+
+ /// @brief Represents a single C99 designator.
+ ///
+ /// @todo This class is infuriatingly similar to clang::Designator,
+ /// but minor differences (storing indices vs. storing pointers)
+ /// keep us from reusing it. Try harder, later, to rectify these
+ /// differences.
+ class Designator {
+ /// @brief The kind of designator this describes.
+ enum {
+ FieldDesignator,
+ ArrayDesignator,
+ ArrayRangeDesignator
+ } Kind;
+
+ union {
+ /// A field designator, e.g., ".x".
+ struct FieldDesignator Field;
+ /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]".
+ struct ArrayOrRangeDesignator ArrayOrRange;
+ };
+ friend class DesignatedInitExpr;
+
+ public:
+ Designator() {}
+
+ /// @brief Initializes a field designator.
+ Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc,
+ SourceLocation FieldLoc)
+ : Kind(FieldDesignator) {
+ Field.NameOrField = reinterpret_cast<uintptr_t>(FieldName) | 0x01;
+ Field.DotLoc = DotLoc.getRawEncoding();
+ Field.FieldLoc = FieldLoc.getRawEncoding();
+ }
+
+ /// @brief Initializes an array designator.
+ Designator(unsigned Index, SourceLocation LBracketLoc,
+ SourceLocation RBracketLoc)
+ : Kind(ArrayDesignator) {
+ ArrayOrRange.Index = Index;
+ ArrayOrRange.LBracketLoc = LBracketLoc.getRawEncoding();
+ ArrayOrRange.EllipsisLoc = SourceLocation().getRawEncoding();
+ ArrayOrRange.RBracketLoc = RBracketLoc.getRawEncoding();
+ }
+
+ /// @brief Initializes a GNU array-range designator.
+ Designator(unsigned Index, SourceLocation LBracketLoc,
+ SourceLocation EllipsisLoc, SourceLocation RBracketLoc)
+ : Kind(ArrayRangeDesignator) {
+ ArrayOrRange.Index = Index;
+ ArrayOrRange.LBracketLoc = LBracketLoc.getRawEncoding();
+ ArrayOrRange.EllipsisLoc = EllipsisLoc.getRawEncoding();
+ ArrayOrRange.RBracketLoc = RBracketLoc.getRawEncoding();
+ }
+
+ bool isFieldDesignator() const { return Kind == FieldDesignator; }
+ bool isArrayDesignator() const { return Kind == ArrayDesignator; }
+ bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; }
+
+ IdentifierInfo * getFieldName();
+
+ FieldDecl *getField() {
+ assert(Kind == FieldDesignator && "Only valid on a field designator");
+ if (Field.NameOrField & 0x01)
+ return 0;
+ else
+ return reinterpret_cast<FieldDecl *>(Field.NameOrField);
+ }
+
+ void setField(FieldDecl *FD) {
+ assert(Kind == FieldDesignator && "Only valid on a field designator");
+ Field.NameOrField = reinterpret_cast<uintptr_t>(FD);
+ }
+
+ SourceLocation getDotLoc() const {
+ assert(Kind == FieldDesignator && "Only valid on a field designator");
+ return SourceLocation::getFromRawEncoding(Field.DotLoc);
+ }
+
+ SourceLocation getFieldLoc() const {
+ assert(Kind == FieldDesignator && "Only valid on a field designator");
+ return SourceLocation::getFromRawEncoding(Field.FieldLoc);
+ }
+
+ SourceLocation getLBracketLoc() const {
+ assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) &&
+ "Only valid on an array or array-range designator");
+ return SourceLocation::getFromRawEncoding(ArrayOrRange.LBracketLoc);
+ }
+
+ SourceLocation getRBracketLoc() const {
+ assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) &&
+ "Only valid on an array or array-range designator");
+ return SourceLocation::getFromRawEncoding(ArrayOrRange.RBracketLoc);
+ }
+
+ SourceLocation getEllipsisLoc() const {
+ assert(Kind == ArrayRangeDesignator &&
+ "Only valid on an array-range designator");
+ return SourceLocation::getFromRawEncoding(ArrayOrRange.EllipsisLoc);
+ }
+
+ unsigned getFirstExprIndex() const {
+ assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) &&
+ "Only valid on an array or array-range designator");
+ return ArrayOrRange.Index;
+ }
+
+ SourceLocation getStartLocation() const {
+ if (Kind == FieldDesignator)
+ return getDotLoc().isInvalid()? getFieldLoc() : getDotLoc();
+ else
+ return getLBracketLoc();
+ }
+ };
+
+ static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators,
+ unsigned NumDesignators,
+ Expr **IndexExprs, unsigned NumIndexExprs,
+ SourceLocation EqualOrColonLoc,
+ bool GNUSyntax, Expr *Init);
+
+ static DesignatedInitExpr *CreateEmpty(ASTContext &C, unsigned NumIndexExprs);
+
+ /// @brief Returns the number of designators in this initializer.
+ unsigned size() const { return NumDesignators; }
+
+ // Iterator access to the designators.
+ typedef Designator* designators_iterator;
+ designators_iterator designators_begin() { return Designators; }
+ designators_iterator designators_end() {
+ return Designators + NumDesignators;
+ }
+
+ Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; }
+
+ void setDesignators(const Designator *Desigs, unsigned NumDesigs);
+
+ Expr *getArrayIndex(const Designator& D);
+ Expr *getArrayRangeStart(const Designator& D);
+ Expr *getArrayRangeEnd(const Designator& D);
+
+ /// @brief Retrieve the location of the '=' that precedes the
+ /// initializer value itself, if present.
+ SourceLocation getEqualOrColonLoc() const { return EqualOrColonLoc; }
+ void setEqualOrColonLoc(SourceLocation L) { EqualOrColonLoc = L; }
+
+ /// @brief Determines whether this designated initializer used the
+ /// deprecated GNU syntax for designated initializers.
+ bool usesGNUSyntax() const { return GNUSyntax; }
+ void setGNUSyntax(bool GNU) { GNUSyntax = GNU; }
+
+ /// @brief Retrieve the initializer value.
+ Expr *getInit() const {
+ return cast<Expr>(*const_cast<DesignatedInitExpr*>(this)->child_begin());
+ }
+
+ void setInit(Expr *init) {
+ *child_begin() = init;
+ }
+
+ /// \brief Retrieve the total number of subexpressions in this
+ /// designated initializer expression, including the actual
+ /// initialized value and any expressions that occur within array
+ /// and array-range designators.
+ unsigned getNumSubExprs() const { return NumSubExprs; }
+
+ Expr *getSubExpr(unsigned Idx) {
+ assert(Idx < NumSubExprs && "Subscript out of range");
+ char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ Ptr += sizeof(DesignatedInitExpr);
+ return reinterpret_cast<Expr**>(reinterpret_cast<void**>(Ptr))[Idx];
+ }
+
+ void setSubExpr(unsigned Idx, Expr *E) {
+ assert(Idx < NumSubExprs && "Subscript out of range");
+ char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ Ptr += sizeof(DesignatedInitExpr);
+ reinterpret_cast<Expr**>(reinterpret_cast<void**>(Ptr))[Idx] = E;
+ }
+
+ /// \brief Replaces the designator at index @p Idx with the series
+ /// of designators in [First, Last).
+ void ExpandDesignator(unsigned Idx, const Designator *First,
+ const Designator *Last);
+
+ virtual SourceRange getSourceRange() const;
+
+ virtual void Destroy(ASTContext &C);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == DesignatedInitExprClass;
+ }
+ static bool classof(const DesignatedInitExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// \brief Represents an implicitly-generated value initialization of
+/// an object of a given type.
+///
+/// Implicit value initializations occur within semantic initializer
+/// list expressions (InitListExpr) as placeholders for subobject
+/// initializations not explicitly specified by the user.
+///
+/// \see InitListExpr
+class ImplicitValueInitExpr : public Expr {
+public:
+ explicit ImplicitValueInitExpr(QualType ty)
+ : Expr(ImplicitValueInitExprClass, ty) { }
+
+ /// \brief Construct an empty implicit value initialization.
+ explicit ImplicitValueInitExpr(EmptyShell Empty)
+ : Expr(ImplicitValueInitExprClass, Empty) { }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ImplicitValueInitExprClass;
+ }
+ static bool classof(const ImplicitValueInitExpr *) { return true; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange();
+ }
+
+ ImplicitValueInitExpr *Clone(ASTContext &C) const;
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+//===----------------------------------------------------------------------===//
+// Clang Extensions
+//===----------------------------------------------------------------------===//
+
+
+/// ExtVectorElementExpr - This represents access to specific elements of a
+/// vector, and may occur on the left hand side or right hand side. For example
+/// the following is legal: "V.xy = V.zw" if V is a 4 element extended vector.
+///
+/// Note that the base may have either vector or pointer to vector type, just
+/// like a struct field reference.
+///
+class ExtVectorElementExpr : public Expr {
+ Stmt *Base;
+ IdentifierInfo *Accessor;
+ SourceLocation AccessorLoc;
+public:
+ ExtVectorElementExpr(QualType ty, Expr *base, IdentifierInfo &accessor,
+ SourceLocation loc)
+ : Expr(ExtVectorElementExprClass, ty),
+ Base(base), Accessor(&accessor), AccessorLoc(loc) {}
+
+ /// \brief Build an empty vector element expression.
+ explicit ExtVectorElementExpr(EmptyShell Empty)
+ : Expr(ExtVectorElementExprClass, Empty) { }
+
+ const Expr *getBase() const { return cast<Expr>(Base); }
+ Expr *getBase() { return cast<Expr>(Base); }
+ void setBase(Expr *E) { Base = E; }
+
+ IdentifierInfo &getAccessor() const { return *Accessor; }
+ void setAccessor(IdentifierInfo *II) { Accessor = II; }
+
+ SourceLocation getAccessorLoc() const { return AccessorLoc; }
+ void setAccessorLoc(SourceLocation L) { AccessorLoc = L; }
+
+ /// getNumElements - Get the number of components being selected.
+ unsigned getNumElements() const;
+
+ /// containsDuplicateElements - Return true if any element access is
+ /// repeated.
+ bool containsDuplicateElements() const;
+
+ /// getEncodedElementAccess - Encode the elements accessed into an llvm
+ /// aggregate Constant of ConstantInt(s).
+ void getEncodedElementAccess(llvm::SmallVectorImpl<unsigned> &Elts) const;
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(getBase()->getLocStart(), AccessorLoc);
+ }
+
+ /// isArrow - Return true if the base expression is a pointer to vector,
+ /// return false if the base expression is a vector.
+ bool isArrow() const;
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ExtVectorElementExprClass;
+ }
+ static bool classof(const ExtVectorElementExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+
+/// BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
+/// ^{ statement-body } or ^(int arg1, float arg2){ statement-body }
+class BlockExpr : public Expr {
+protected:
+ BlockDecl *TheBlock;
+ bool HasBlockDeclRefExprs;
+public:
+ BlockExpr(BlockDecl *BD, QualType ty, bool hasBlockDeclRefExprs)
+ : Expr(BlockExprClass, ty),
+ TheBlock(BD), HasBlockDeclRefExprs(hasBlockDeclRefExprs) {}
+
+ /// \brief Build an empty block expression.
+ explicit BlockExpr(EmptyShell Empty) : Expr(BlockExprClass, Empty) { }
+
+ const BlockDecl *getBlockDecl() const { return TheBlock; }
+ BlockDecl *getBlockDecl() { return TheBlock; }
+ void setBlockDecl(BlockDecl *BD) { TheBlock = BD; }
+
+ // Convenience functions for probing the underlying BlockDecl.
+ SourceLocation getCaretLocation() const;
+ const Stmt *getBody() const;
+ Stmt *getBody();
+
+ const Stmt *getBody(ASTContext &C) const { return getBody(); }
+ Stmt *getBody(ASTContext &C) { return getBody(); }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(getCaretLocation(), getBody()->getLocEnd());
+ }
+
+ /// getFunctionType - Return the underlying function type for this block.
+ const FunctionType *getFunctionType() const;
+
+ /// hasBlockDeclRefExprs - Return true iff the block has BlockDeclRefExpr
+ /// inside of the block that reference values outside the block.
+ bool hasBlockDeclRefExprs() const { return HasBlockDeclRefExprs; }
+ void setHasBlockDeclRefExprs(bool BDRE) { HasBlockDeclRefExprs = BDRE; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == BlockExprClass;
+ }
+ static bool classof(const BlockExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// BlockDeclRefExpr - A reference to a declared variable, function,
+/// enum, etc.
+class BlockDeclRefExpr : public Expr {
+ ValueDecl *D;
+ SourceLocation Loc;
+ bool IsByRef;
+public:
+ BlockDeclRefExpr(ValueDecl *d, QualType t, SourceLocation l, bool ByRef) :
+ Expr(BlockDeclRefExprClass, t), D(d), Loc(l), IsByRef(ByRef) {}
+
+ // \brief Build an empty reference to a declared variable in a
+ // block.
+ explicit BlockDeclRefExpr(EmptyShell Empty)
+ : Expr(BlockDeclRefExprClass, Empty) { }
+
+ ValueDecl *getDecl() { return D; }
+ const ValueDecl *getDecl() const { return D; }
+ void setDecl(ValueDecl *VD) { D = VD; }
+
+ SourceLocation getLocation() const { return Loc; }
+ void setLocation(SourceLocation L) { Loc = L; }
+
+ virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+
+ bool isByRef() const { return IsByRef; }
+ void setByRef(bool BR) { IsByRef = BR; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == BlockDeclRefExprClass;
+ }
+ static bool classof(const BlockDeclRefExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
new file mode 100644
index 000000000000..53386231a03f
--- /dev/null
+++ b/include/clang/AST/ExprCXX.h
@@ -0,0 +1,1234 @@
+//===--- ExprCXX.h - Classes for representing 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 the Expr interface and subclasses for C++ expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_EXPRCXX_H
+#define LLVM_CLANG_AST_EXPRCXX_H
+
+#include "clang/Basic/TypeTraits.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Decl.h"
+
+namespace clang {
+
+ class CXXConstructorDecl;
+ class CXXDestructorDecl;
+ class CXXTemporary;
+
+//===--------------------------------------------------------------------===//
+// C++ Expressions.
+//===--------------------------------------------------------------------===//
+
+/// \brief A call to an overloaded operator written using operator
+/// syntax.
+///
+/// Represents a call to an overloaded operator written using operator
+/// syntax, e.g., "x + y" or "*p". While semantically equivalent to a
+/// normal call, this AST node provides better information about the
+/// syntactic representation of the call.
+///
+/// In a C++ template, this expression node kind will be used whenever
+/// any of the arguments are type-dependent. In this case, the
+/// function itself will be a (possibly empty) set of functions and
+/// function templates that were found by name lookup at template
+/// definition time.
+class CXXOperatorCallExpr : public CallExpr {
+ /// \brief The overloaded operator.
+ OverloadedOperatorKind Operator;
+
+public:
+ CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
+ Expr **args, unsigned numargs, QualType t,
+ SourceLocation operatorloc)
+ : CallExpr(C, CXXOperatorCallExprClass, fn, args, numargs, t, operatorloc),
+ Operator(Op) {}
+
+ /// getOperator - Returns the kind of overloaded operator that this
+ /// expression refers to.
+ OverloadedOperatorKind getOperator() const { return Operator; }
+
+ /// getOperatorLoc - Returns the location of the operator symbol in
+ /// the expression. When @c getOperator()==OO_Call, this is the
+ /// location of the right parentheses; when @c
+ /// getOperator()==OO_Subscript, this is the location of the right
+ /// bracket.
+ SourceLocation getOperatorLoc() const { return getRParenLoc(); }
+
+ virtual SourceRange getSourceRange() const;
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXOperatorCallExprClass;
+ }
+ static bool classof(const CXXOperatorCallExpr *) { return true; }
+};
+
+/// CXXMemberCallExpr - Represents a call to a member function that
+/// may be written either with member call syntax (e.g., "obj.func()"
+/// or "objptr->func()") or with normal function-call syntax
+/// ("func()") within a member function that ends up calling a member
+/// function. The callee in either case is a MemberExpr that contains
+/// both the object argument and the member function, while the
+/// arguments are the arguments within the parentheses (not including
+/// the object argument).
+class CXXMemberCallExpr : public CallExpr {
+public:
+ CXXMemberCallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs,
+ QualType t, SourceLocation rparenloc)
+ : CallExpr(C, CXXMemberCallExprClass, fn, args, numargs, t, rparenloc) {}
+
+ /// getImplicitObjectArgument - Retrieves the implicit object
+ /// argument for the member call. For example, in "x.f(5)", this
+ /// operation would return "x".
+ Expr *getImplicitObjectArgument();
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXMemberCallExprClass;
+ }
+ static bool classof(const CXXMemberCallExpr *) { return true; }
+};
+
+/// CXXNamedCastExpr - Abstract class common to all of the C++ "named"
+/// casts, @c static_cast, @c dynamic_cast, @c reinterpret_cast, or @c
+/// const_cast.
+///
+/// This abstract class is inherited by all of the classes
+/// representing "named" casts, e.g., CXXStaticCastExpr,
+/// CXXDynamicCastExpr, CXXReinterpretCastExpr, and CXXConstCastExpr.
+class CXXNamedCastExpr : public ExplicitCastExpr {
+private:
+ SourceLocation Loc; // the location of the casting op
+
+protected:
+ CXXNamedCastExpr(StmtClass SC, QualType ty, Expr *op, QualType writtenTy,
+ SourceLocation l)
+ : ExplicitCastExpr(SC, ty, op, writtenTy), Loc(l) {}
+
+public:
+ const char *getCastName() const;
+
+ /// \brief Retrieve the location of the cast operator keyword, e.g.,
+ /// "static_cast".
+ SourceLocation getOperatorLoc() const { return Loc; }
+ void setOperatorLoc(SourceLocation L) { Loc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(Loc, getSubExpr()->getSourceRange().getEnd());
+ }
+ static bool classof(const Stmt *T) {
+ switch (T->getStmtClass()) {
+ case CXXNamedCastExprClass:
+ case CXXStaticCastExprClass:
+ case CXXDynamicCastExprClass:
+ case CXXReinterpretCastExprClass:
+ case CXXConstCastExprClass:
+ return true;
+ default:
+ return false;
+ }
+ }
+ static bool classof(const CXXNamedCastExpr *) { return true; }
+};
+
+/// CXXStaticCastExpr - A C++ @c static_cast expression (C++ [expr.static.cast]).
+///
+/// This expression node represents a C++ static cast, e.g.,
+/// @c static_cast<int>(1.0).
+class CXXStaticCastExpr : public CXXNamedCastExpr {
+public:
+ CXXStaticCastExpr(QualType ty, Expr *op, QualType writtenTy, SourceLocation l)
+ : CXXNamedCastExpr(CXXStaticCastExprClass, ty, op, writtenTy, l) {}
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXStaticCastExprClass;
+ }
+ static bool classof(const CXXStaticCastExpr *) { return true; }
+};
+
+/// CXXDynamicCastExpr - A C++ @c dynamic_cast expression
+/// (C++ [expr.dynamic.cast]), which may perform a run-time check to
+/// determine how to perform the type cast.
+///
+/// This expression node represents a dynamic cast, e.g.,
+/// @c dynamic_cast<Derived*>(BasePtr).
+class CXXDynamicCastExpr : public CXXNamedCastExpr {
+public:
+ CXXDynamicCastExpr(QualType ty, Expr *op, QualType writtenTy, SourceLocation l)
+ : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, op, writtenTy, l) {}
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXDynamicCastExprClass;
+ }
+ static bool classof(const CXXDynamicCastExpr *) { return true; }
+};
+
+/// CXXReinterpretCastExpr - A C++ @c reinterpret_cast expression (C++
+/// [expr.reinterpret.cast]), which provides a differently-typed view
+/// of a value but performs no actual work at run time.
+///
+/// This expression node represents a reinterpret cast, e.g.,
+/// @c reinterpret_cast<int>(VoidPtr).
+class CXXReinterpretCastExpr : public CXXNamedCastExpr {
+public:
+ CXXReinterpretCastExpr(QualType ty, Expr *op, QualType writtenTy,
+ SourceLocation l)
+ : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, op, writtenTy, l) {}
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXReinterpretCastExprClass;
+ }
+ static bool classof(const CXXReinterpretCastExpr *) { return true; }
+};
+
+/// CXXConstCastExpr - A C++ @c const_cast expression (C++ [expr.const.cast]),
+/// which can remove type qualifiers but does not change the underlying value.
+///
+/// This expression node represents a const cast, e.g.,
+/// @c const_cast<char*>(PtrToConstChar).
+class CXXConstCastExpr : public CXXNamedCastExpr {
+public:
+ CXXConstCastExpr(QualType ty, Expr *op, QualType writtenTy,
+ SourceLocation l)
+ : CXXNamedCastExpr(CXXConstCastExprClass, ty, op, writtenTy, l) {}
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXConstCastExprClass;
+ }
+ static bool classof(const CXXConstCastExpr *) { return true; }
+};
+
+/// CXXBoolLiteralExpr - [C++ 2.13.5] C++ Boolean Literal.
+///
+class CXXBoolLiteralExpr : public Expr {
+ bool Value;
+ SourceLocation Loc;
+public:
+ CXXBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) :
+ Expr(CXXBoolLiteralExprClass, Ty), Value(val), Loc(l) {}
+
+ CXXBoolLiteralExpr* Clone(ASTContext &C) const;
+
+ bool getValue() const { return Value; }
+
+ virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXBoolLiteralExprClass;
+ }
+ static bool classof(const CXXBoolLiteralExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// CXXNullPtrLiteralExpr - [C++0x 2.14.7] C++ Pointer Literal
+class CXXNullPtrLiteralExpr : public Expr {
+ SourceLocation Loc;
+public:
+ CXXNullPtrLiteralExpr(QualType Ty, SourceLocation l) :
+ Expr(CXXNullPtrLiteralExprClass, Ty), Loc(l) {}
+
+ CXXNullPtrLiteralExpr* Clone(ASTContext &C) const;
+
+ virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXNullPtrLiteralExprClass;
+ }
+ static bool classof(const CXXNullPtrLiteralExpr *) { return true; }
+
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// CXXTypeidExpr - A C++ @c typeid expression (C++ [expr.typeid]), which gets
+/// the type_info that corresponds to the supplied type, or the (possibly
+/// dynamic) type of the supplied expression.
+///
+/// This represents code like @c typeid(int) or @c typeid(*objPtr)
+class CXXTypeidExpr : public Expr {
+private:
+ bool isTypeOp : 1;
+ union {
+ void *Ty;
+ Stmt *Ex;
+ } Operand;
+ SourceRange Range;
+
+public:
+ CXXTypeidExpr(bool isTypeOp, void *op, QualType Ty, const SourceRange r) :
+ Expr(CXXTypeidExprClass, Ty,
+ // typeid is never type-dependent (C++ [temp.dep.expr]p4)
+ false,
+ // typeid is value-dependent if the type or expression are dependent
+ (isTypeOp ? QualType::getFromOpaquePtr(op)->isDependentType()
+ : static_cast<Expr*>(op)->isValueDependent())),
+ isTypeOp(isTypeOp), Range(r) {
+ if (isTypeOp)
+ Operand.Ty = op;
+ else
+ // op was an Expr*, so cast it back to that to be safe
+ Operand.Ex = static_cast<Expr*>(op);
+ }
+
+ bool isTypeOperand() const { return isTypeOp; }
+ QualType getTypeOperand() const {
+ assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)");
+ return QualType::getFromOpaquePtr(Operand.Ty);
+ }
+ Expr* getExprOperand() const {
+ assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)");
+ return static_cast<Expr*>(Operand.Ex);
+ }
+
+ virtual SourceRange getSourceRange() const {
+ return Range;
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXTypeidExprClass;
+ }
+ static bool classof(const CXXTypeidExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// CXXThisExpr - Represents the "this" expression in C++, which is a
+/// pointer to the object on which the current member function is
+/// executing (C++ [expr.prim]p3). Example:
+///
+/// @code
+/// class Foo {
+/// public:
+/// void bar();
+/// void test() { this->bar(); }
+/// };
+/// @endcode
+class CXXThisExpr : public Expr {
+ SourceLocation Loc;
+
+public:
+ CXXThisExpr(SourceLocation L, QualType Type)
+ : Expr(CXXThisExprClass, Type,
+ // 'this' is type-dependent if the class type of the enclosing
+ // member function is dependent (C++ [temp.dep.expr]p2)
+ Type->isDependentType(), Type->isDependentType()),
+ Loc(L) { }
+
+ virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXThisExprClass;
+ }
+ static bool classof(const CXXThisExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// CXXThrowExpr - [C++ 15] C++ Throw Expression. This handles
+/// 'throw' and 'throw' assignment-expression. When
+/// assignment-expression isn't present, Op will be null.
+///
+class CXXThrowExpr : public Expr {
+ Stmt *Op;
+ SourceLocation ThrowLoc;
+public:
+ // Ty is the void type which is used as the result type of the
+ // exepression. The l is the location of the throw keyword. expr
+ // can by null, if the optional expression to throw isn't present.
+ CXXThrowExpr(Expr *expr, QualType Ty, SourceLocation l) :
+ Expr(CXXThrowExprClass, Ty, false, false), Op(expr), ThrowLoc(l) {}
+ const Expr *getSubExpr() const { return cast_or_null<Expr>(Op); }
+ Expr *getSubExpr() { return cast_or_null<Expr>(Op); }
+ void setSubExpr(Expr *E) { Op = E; }
+
+ SourceLocation getThrowLoc() const { return ThrowLoc; }
+ void setThrowLoc(SourceLocation L) { ThrowLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ if (getSubExpr() == 0)
+ return SourceRange(ThrowLoc, ThrowLoc);
+ return SourceRange(ThrowLoc, getSubExpr()->getSourceRange().getEnd());
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXThrowExprClass;
+ }
+ static bool classof(const CXXThrowExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// CXXDefaultArgExpr - C++ [dcl.fct.default]. This wraps up a
+/// function call argument that was created from the corresponding
+/// parameter's default argument, when the call did not explicitly
+/// supply arguments for all of the parameters.
+class CXXDefaultArgExpr : public Expr {
+ ParmVarDecl *Param;
+public:
+ // Param is the parameter whose default argument is used by this
+ // expression.
+ explicit CXXDefaultArgExpr(ParmVarDecl *param)
+ : Expr(CXXDefaultArgExprClass,
+ param->hasUnparsedDefaultArg()? param->getType().getNonReferenceType()
+ : param->getDefaultArg()->getType()),
+ Param(param) { }
+
+ // Retrieve the parameter that the argument was created from.
+ const ParmVarDecl *getParam() const { return Param; }
+ ParmVarDecl *getParam() { return Param; }
+
+ // Retrieve the actual argument to the function call.
+ const Expr *getExpr() const { return Param->getDefaultArg(); }
+ Expr *getExpr() { return Param->getDefaultArg(); }
+
+ virtual SourceRange getSourceRange() const {
+ // Default argument expressions have no representation in the
+ // source, so they have an empty source range.
+ return SourceRange();
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXDefaultArgExprClass;
+ }
+ static bool classof(const CXXDefaultArgExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// CXXTemporary - Represents a C++ temporary.
+class CXXTemporary {
+ /// Destructor - The destructor that needs to be called.
+ const CXXDestructorDecl *Destructor;
+
+ CXXTemporary(const CXXDestructorDecl *destructor)
+ : Destructor(destructor) { }
+ ~CXXTemporary() { }
+
+public:
+ static CXXTemporary *Create(ASTContext &C,
+ const CXXDestructorDecl *Destructor);
+ void Destroy(ASTContext &C);
+
+ const CXXDestructorDecl *getDestructor() const { return Destructor; }
+};
+
+/// CXXBindTemporaryExpr - Represents binding an expression to a temporary,
+/// so its destructor can be called later.
+class CXXBindTemporaryExpr : public Expr {
+ CXXTemporary *Temp;
+
+ Stmt *SubExpr;
+
+ CXXBindTemporaryExpr(CXXTemporary *temp, Expr* subexpr)
+ : Expr(CXXBindTemporaryExprClass,
+ subexpr->getType()), Temp(temp), SubExpr(subexpr) { }
+ ~CXXBindTemporaryExpr() { }
+
+public:
+ static CXXBindTemporaryExpr *Create(ASTContext &C, CXXTemporary *Temp,
+ Expr* SubExpr);
+ void Destroy(ASTContext &C);
+
+ CXXTemporary *getTemporary() { return Temp; }
+ const CXXTemporary *getTemporary() const { return Temp; }
+
+ const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
+ Expr *getSubExpr() { return cast<Expr>(SubExpr); }
+ void setSubExpr(Expr *E) { SubExpr = E; }
+
+ virtual SourceRange getSourceRange() const { return SourceRange(); }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXBindTemporaryExprClass;
+ }
+ static bool classof(const CXXBindTemporaryExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// CXXConstructExpr - Represents a call to a C++ constructor.
+class CXXConstructExpr : public Expr {
+ CXXConstructorDecl *Constructor;
+
+ bool Elidable;
+
+ Stmt **Args;
+ unsigned NumArgs;
+
+
+protected:
+ CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
+ CXXConstructorDecl *d, bool elidable,
+ Expr **args, unsigned numargs);
+ ~CXXConstructExpr() { }
+
+public:
+ static CXXConstructExpr *Create(ASTContext &C, QualType T,
+ CXXConstructorDecl *D, bool Elidable,
+ Expr **Args, unsigned NumArgs);
+
+ void Destroy(ASTContext &C);
+
+ CXXConstructorDecl* getConstructor() const { return Constructor; }
+
+ /// \brief Whether this construction is elidable.
+ bool isElidable() const { return Elidable; }
+
+ typedef ExprIterator arg_iterator;
+ typedef ConstExprIterator const_arg_iterator;
+
+ arg_iterator arg_begin() { return Args; }
+ arg_iterator arg_end() { return Args + NumArgs; }
+ const_arg_iterator arg_begin() const { return Args; }
+ const_arg_iterator arg_end() const { return Args + NumArgs; }
+
+ unsigned getNumArgs() const { return NumArgs; }
+
+ virtual SourceRange getSourceRange() const { return SourceRange(); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXConstructExprClass ||
+ T->getStmtClass() == CXXTemporaryObjectExprClass;
+ }
+ static bool classof(const CXXConstructExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// CXXFunctionalCastExpr - Represents an explicit C++ type conversion
+/// that uses "functional" notion (C++ [expr.type.conv]). Example: @c
+/// x = int(0.5);
+class CXXFunctionalCastExpr : public ExplicitCastExpr {
+ SourceLocation TyBeginLoc;
+ SourceLocation RParenLoc;
+public:
+ CXXFunctionalCastExpr(QualType ty, QualType writtenTy,
+ SourceLocation tyBeginLoc, Expr *castExpr,
+ SourceLocation rParenLoc) :
+ ExplicitCastExpr(CXXFunctionalCastExprClass, ty, castExpr, writtenTy),
+ TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {}
+
+ SourceLocation getTypeBeginLoc() const { return TyBeginLoc; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(TyBeginLoc, RParenLoc);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXFunctionalCastExprClass;
+ }
+ static bool classof(const CXXFunctionalCastExpr *) { return true; }
+};
+
+/// @brief Represents a C++ functional cast expression that builds a
+/// temporary object.
+///
+/// This expression type represents a C++ "functional" cast
+/// (C++[expr.type.conv]) with N != 1 arguments that invokes a
+/// constructor to build a temporary object. If N == 0 but no
+/// constructor will be called (because the functional cast is
+/// performing a value-initialized an object whose class type has no
+/// user-declared constructors), CXXZeroInitValueExpr will represent
+/// the functional cast. Finally, with N == 1 arguments the functional
+/// cast expression will be represented by CXXFunctionalCastExpr.
+/// Example:
+/// @code
+/// struct X { X(int, float); }
+///
+/// X create_X() {
+/// return X(1, 3.14f); // creates a CXXTemporaryObjectExpr
+/// };
+/// @endcode
+class CXXTemporaryObjectExpr : public CXXConstructExpr {
+ SourceLocation TyBeginLoc;
+ SourceLocation RParenLoc;
+
+public:
+ CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons,
+ QualType writtenTy, SourceLocation tyBeginLoc,
+ Expr **Args,unsigned NumArgs,
+ SourceLocation rParenLoc);
+
+ ~CXXTemporaryObjectExpr() { }
+
+ SourceLocation getTypeBeginLoc() const { return TyBeginLoc; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(TyBeginLoc, RParenLoc);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXTemporaryObjectExprClass;
+ }
+ static bool classof(const CXXTemporaryObjectExpr *) { return true; }
+};
+
+/// CXXZeroInitValueExpr - [C++ 5.2.3p2]
+/// Expression "T()" which creates a value-initialized rvalue of type
+/// T, which is either a non-class type or a class type without any
+/// user-defined constructors.
+///
+class CXXZeroInitValueExpr : public Expr {
+ SourceLocation TyBeginLoc;
+ SourceLocation RParenLoc;
+
+public:
+ CXXZeroInitValueExpr(QualType ty, SourceLocation tyBeginLoc,
+ SourceLocation rParenLoc ) :
+ Expr(CXXZeroInitValueExprClass, ty, false, false),
+ TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {}
+
+ SourceLocation getTypeBeginLoc() const { return TyBeginLoc; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+
+ /// @brief Whether this initialization expression was
+ /// implicitly-generated.
+ bool isImplicit() const {
+ return TyBeginLoc.isInvalid() && RParenLoc.isInvalid();
+ }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(TyBeginLoc, RParenLoc);
+ }
+
+ CXXZeroInitValueExpr* Clone(ASTContext &C) const;
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXZeroInitValueExprClass;
+ }
+ static bool classof(const CXXZeroInitValueExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// CXXConditionDeclExpr - Condition declaration of a if/switch/while/for
+/// statement, e.g: "if (int x = f()) {...}".
+/// The main difference with DeclRefExpr is that CXXConditionDeclExpr owns the
+/// decl that it references.
+///
+class CXXConditionDeclExpr : public DeclRefExpr {
+public:
+ CXXConditionDeclExpr(SourceLocation startLoc,
+ SourceLocation eqLoc, VarDecl *var)
+ : DeclRefExpr(CXXConditionDeclExprClass, var,
+ var->getType().getNonReferenceType(), startLoc,
+ var->getType()->isDependentType(),
+ /*FIXME:integral constant?*/
+ var->getType()->isDependentType()) {}
+
+ virtual void Destroy(ASTContext& Ctx);
+
+ SourceLocation getStartLoc() const { return getLocation(); }
+
+ VarDecl *getVarDecl() { return cast<VarDecl>(getDecl()); }
+ const VarDecl *getVarDecl() const { return cast<VarDecl>(getDecl()); }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(getStartLoc(), getVarDecl()->getInit()->getLocEnd());
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXConditionDeclExprClass;
+ }
+ static bool classof(const CXXConditionDeclExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// CXXNewExpr - A new expression for memory allocation and constructor calls,
+/// e.g: "new CXXNewExpr(foo)".
+class CXXNewExpr : public Expr {
+ // Was the usage ::new, i.e. is the global new to be used?
+ bool GlobalNew : 1;
+ // Was the form (type-id) used? Otherwise, it was new-type-id.
+ bool ParenTypeId : 1;
+ // Is there an initializer? If not, built-ins are uninitialized, else they're
+ // value-initialized.
+ bool Initializer : 1;
+ // Do we allocate an array? If so, the first SubExpr is the size expression.
+ bool Array : 1;
+ // The number of placement new arguments.
+ unsigned NumPlacementArgs : 14;
+ // The number of constructor arguments. This may be 1 even for non-class
+ // types; use the pseudo copy constructor.
+ unsigned NumConstructorArgs : 14;
+ // Contains an optional array size expression, any number of optional
+ // placement arguments, and any number of optional constructor arguments,
+ // in that order.
+ Stmt **SubExprs;
+ // Points to the allocation function used.
+ FunctionDecl *OperatorNew;
+ // Points to the deallocation function used in case of error. May be null.
+ FunctionDecl *OperatorDelete;
+ // Points to the constructor used. Cannot be null if AllocType is a record;
+ // it would still point at the default constructor (even an implicit one).
+ // Must be null for all other types.
+ CXXConstructorDecl *Constructor;
+
+ SourceLocation StartLoc;
+ SourceLocation EndLoc;
+
+public:
+ CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs,
+ unsigned numPlaceArgs, bool ParenTypeId, Expr *arraySize,
+ CXXConstructorDecl *constructor, bool initializer,
+ Expr **constructorArgs, unsigned numConsArgs,
+ FunctionDecl *operatorDelete, QualType ty,
+ SourceLocation startLoc, SourceLocation endLoc);
+ ~CXXNewExpr() {
+ delete[] SubExprs;
+ }
+
+ QualType getAllocatedType() const {
+ assert(getType()->isPointerType());
+ return getType()->getAsPointerType()->getPointeeType();
+ }
+
+ FunctionDecl *getOperatorNew() const { return OperatorNew; }
+ FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
+ CXXConstructorDecl *getConstructor() const { return Constructor; }
+
+ bool isArray() const { return Array; }
+ Expr *getArraySize() {
+ return Array ? cast<Expr>(SubExprs[0]) : 0;
+ }
+ const Expr *getArraySize() const {
+ return Array ? cast<Expr>(SubExprs[0]) : 0;
+ }
+
+ unsigned getNumPlacementArgs() const { return NumPlacementArgs; }
+ Expr *getPlacementArg(unsigned i) {
+ assert(i < NumPlacementArgs && "Index out of range");
+ return cast<Expr>(SubExprs[Array + i]);
+ }
+ const Expr *getPlacementArg(unsigned i) const {
+ assert(i < NumPlacementArgs && "Index out of range");
+ return cast<Expr>(SubExprs[Array + i]);
+ }
+
+ bool isGlobalNew() const { return GlobalNew; }
+ bool isParenTypeId() const { return ParenTypeId; }
+ bool hasInitializer() const { return Initializer; }
+
+ unsigned getNumConstructorArgs() const { return NumConstructorArgs; }
+ Expr *getConstructorArg(unsigned i) {
+ assert(i < NumConstructorArgs && "Index out of range");
+ return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]);
+ }
+ const Expr *getConstructorArg(unsigned i) const {
+ assert(i < NumConstructorArgs && "Index out of range");
+ return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]);
+ }
+
+ typedef ExprIterator arg_iterator;
+ typedef ConstExprIterator const_arg_iterator;
+
+ arg_iterator placement_arg_begin() {
+ return SubExprs + Array;
+ }
+ arg_iterator placement_arg_end() {
+ return SubExprs + Array + getNumPlacementArgs();
+ }
+ const_arg_iterator placement_arg_begin() const {
+ return SubExprs + Array;
+ }
+ const_arg_iterator placement_arg_end() const {
+ return SubExprs + Array + getNumPlacementArgs();
+ }
+
+ arg_iterator constructor_arg_begin() {
+ return SubExprs + Array + getNumPlacementArgs();
+ }
+ arg_iterator constructor_arg_end() {
+ return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
+ }
+ const_arg_iterator constructor_arg_begin() const {
+ return SubExprs + Array + getNumPlacementArgs();
+ }
+ const_arg_iterator constructor_arg_end() const {
+ return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
+ }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(StartLoc, EndLoc);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXNewExprClass;
+ }
+ static bool classof(const CXXNewExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// CXXDeleteExpr - A delete expression for memory deallocation and destructor
+/// calls, e.g. "delete[] pArray".
+class CXXDeleteExpr : public Expr {
+ // Is this a forced global delete, i.e. "::delete"?
+ bool GlobalDelete : 1;
+ // Is this the array form of delete, i.e. "delete[]"?
+ bool ArrayForm : 1;
+ // Points to the operator delete overload that is used. Could be a member.
+ FunctionDecl *OperatorDelete;
+ // The pointer expression to be deleted.
+ Stmt *Argument;
+ // Location of the expression.
+ SourceLocation Loc;
+public:
+ CXXDeleteExpr(QualType ty, bool globalDelete, bool arrayForm,
+ FunctionDecl *operatorDelete, Expr *arg, SourceLocation loc)
+ : Expr(CXXDeleteExprClass, ty, false, false), GlobalDelete(globalDelete),
+ ArrayForm(arrayForm), OperatorDelete(operatorDelete), Argument(arg),
+ Loc(loc) { }
+
+ bool isGlobalDelete() const { return GlobalDelete; }
+ bool isArrayForm() const { return ArrayForm; }
+
+ FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
+
+ Expr *getArgument() { return cast<Expr>(Argument); }
+ const Expr *getArgument() const { return cast<Expr>(Argument); }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(Loc, Argument->getLocEnd());
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXDeleteExprClass;
+ }
+ static bool classof(const CXXDeleteExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// \brief Represents the name of a function that has not been
+/// resolved to any declaration.
+///
+/// Unresolved function names occur when a function name is
+/// encountered prior to an open parentheses ('(') in a C++ function
+/// call, and the function name itself did not resolve to a
+/// declaration. These function names can only be resolved when they
+/// form the postfix-expression of a function call, so that
+/// argument-dependent lookup finds declarations corresponding to
+/// these functions.
+
+/// @code
+/// template<typename T> void f(T x) {
+/// g(x); // g is an unresolved function name (that is also a dependent name)
+/// }
+/// @endcode
+class UnresolvedFunctionNameExpr : public Expr {
+ /// The name that was present in the source
+ DeclarationName Name;
+
+ /// The location of this name in the source code
+ SourceLocation Loc;
+
+public:
+ UnresolvedFunctionNameExpr(DeclarationName N, QualType T, SourceLocation L)
+ : Expr(UnresolvedFunctionNameExprClass, T, false, false), Name(N), Loc(L) { }
+
+ /// \brief Retrieves the name that occurred in the source code.
+ DeclarationName getName() const { return Name; }
+
+ /// getLocation - Retrieves the location in the source code where
+ /// the name occurred.
+ SourceLocation getLocation() const { return Loc; }
+
+ virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+
+ UnresolvedFunctionNameExpr* Clone(ASTContext &C) const;
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == UnresolvedFunctionNameExprClass;
+ }
+ static bool classof(const UnresolvedFunctionNameExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// UnaryTypeTraitExpr - A GCC or MS unary type trait, as used in the
+/// implementation of TR1/C++0x type trait templates.
+/// Example:
+/// __is_pod(int) == true
+/// __is_enum(std::string) == false
+class UnaryTypeTraitExpr : public Expr {
+ /// UTT - The trait.
+ UnaryTypeTrait UTT;
+
+ /// Loc - The location of the type trait keyword.
+ SourceLocation Loc;
+
+ /// RParen - The location of the closing paren.
+ SourceLocation RParen;
+
+ /// QueriedType - The type we're testing.
+ QualType QueriedType;
+
+public:
+ UnaryTypeTraitExpr(SourceLocation loc, UnaryTypeTrait utt, QualType queried,
+ SourceLocation rparen, QualType ty)
+ : Expr(UnaryTypeTraitExprClass, ty, false, queried->isDependentType()),
+ UTT(utt), Loc(loc), RParen(rparen), QueriedType(queried) { }
+
+ virtual SourceRange getSourceRange() const { return SourceRange(Loc, RParen);}
+
+ UnaryTypeTrait getTrait() const { return UTT; }
+
+ QualType getQueriedType() const { return QueriedType; }
+
+ bool EvaluateTrait() const;
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == UnaryTypeTraitExprClass;
+ }
+ static bool classof(const UnaryTypeTraitExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// QualifiedDeclRefExpr - A reference to a declared variable,
+/// function, enum, etc., that includes a qualification, e.g.,
+/// "N::foo".
+class QualifiedDeclRefExpr : public DeclRefExpr {
+ /// QualifierRange - The source range that covers the
+ /// nested-name-specifier.
+ SourceRange QualifierRange;
+
+ /// \brief The nested-name-specifier that qualifies this declaration
+ /// name.
+ NestedNameSpecifier *NNS;
+
+public:
+ QualifiedDeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD,
+ bool VD, SourceRange R, NestedNameSpecifier *NNS)
+ : DeclRefExpr(QualifiedDeclRefExprClass, d, t, l, TD, VD),
+ QualifierRange(R), NNS(NNS) { }
+
+ /// \brief Retrieve the source range of the nested-name-specifier.
+ SourceRange getQualifierRange() const { return QualifierRange; }
+
+ /// \brief Retrieve the nested-name-specifier that qualifies this
+ /// declaration.
+ NestedNameSpecifier *getQualifier() const { return NNS; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(QualifierRange.getBegin(), getLocation());
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == QualifiedDeclRefExprClass;
+ }
+ static bool classof(const QualifiedDeclRefExpr *) { return true; }
+};
+
+/// \brief A qualified reference to a name whose declaration cannot
+/// yet be resolved.
+///
+/// UnresolvedDeclRefExpr is similar to QualifiedDeclRefExpr in that
+/// it expresses a qualified reference to a declaration such as
+/// X<T>::value. The difference, however, is that an
+/// UnresolvedDeclRefExpr node is used only within C++ templates when
+/// the qualification (e.g., X<T>::) refers to a dependent type. In
+/// this case, X<T>::value cannot resolve to a declaration because the
+/// declaration will differ from on instantiation of X<T> to the
+/// next. Therefore, UnresolvedDeclRefExpr keeps track of the
+/// qualifier (X<T>::) and the name of the entity being referenced
+/// ("value"). Such expressions will instantiate to
+/// QualifiedDeclRefExprs.
+class UnresolvedDeclRefExpr : public Expr {
+ /// The name of the entity we will be referencing.
+ DeclarationName Name;
+
+ /// Location of the name of the declaration we're referencing.
+ SourceLocation Loc;
+
+ /// QualifierRange - The source range that covers the
+ /// nested-name-specifier.
+ SourceRange QualifierRange;
+
+ /// \brief The nested-name-specifier that qualifies this unresolved
+ /// declaration name.
+ NestedNameSpecifier *NNS;
+
+public:
+ UnresolvedDeclRefExpr(DeclarationName N, QualType T, SourceLocation L,
+ SourceRange R, NestedNameSpecifier *NNS)
+ : Expr(UnresolvedDeclRefExprClass, T, true, true),
+ Name(N), Loc(L), QualifierRange(R), NNS(NNS) { }
+
+ /// \brief Retrieve the name that this expression refers to.
+ DeclarationName getDeclName() const { return Name; }
+
+ /// \brief Retrieve the location of the name within the expression.
+ SourceLocation getLocation() const { return Loc; }
+
+ /// \brief Retrieve the source range of the nested-name-specifier.
+ SourceRange getQualifierRange() const { return QualifierRange; }
+
+ /// \brief Retrieve the nested-name-specifier that qualifies this
+ /// declaration.
+ NestedNameSpecifier *getQualifier() const { return NNS; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(QualifierRange.getBegin(), getLocation());
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == UnresolvedDeclRefExprClass;
+ }
+ static bool classof(const UnresolvedDeclRefExpr *) { return true; }
+
+ virtual StmtIterator child_begin();
+ virtual StmtIterator child_end();
+};
+
+class CXXExprWithTemporaries : public Expr {
+ Stmt *SubExpr;
+
+ CXXTemporary **Temps;
+ unsigned NumTemps;
+
+ CXXExprWithTemporaries(Expr *subexpr, CXXTemporary **temps,
+ unsigned numtemps);
+ ~CXXExprWithTemporaries();
+
+public:
+ static CXXExprWithTemporaries *Create(ASTContext &C, Expr *SubExpr,
+ CXXTemporary **Temps,
+ unsigned NumTemps);
+ void Destroy(ASTContext &C);
+
+ unsigned getNumTemporaries() const { return NumTemps; }
+ CXXTemporary *getTemporary(unsigned i) {
+ assert(i < NumTemps && "Index out of range");
+ return Temps[i];
+ }
+ const CXXTemporary *getTemporary(unsigned i) const {
+ assert(i < NumTemps && "Index out of range");
+ return Temps[i];
+ }
+
+ void removeLastTemporary() { NumTemps--; }
+
+ Expr *getSubExpr() { return cast<Expr>(SubExpr); }
+ const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
+ void setSubExpr(Expr *E) { SubExpr = E; }
+
+ virtual SourceRange getSourceRange() const { return SourceRange(); }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXExprWithTemporariesClass;
+ }
+ static bool classof(const CXXExprWithTemporaries *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// \brief Describes an explicit type conversion that uses functional
+/// notion but could not be resolved because one or more arguments are
+/// type-dependent.
+///
+/// The explicit type conversions expressed by
+/// CXXUnresolvedConstructExpr have the form \c T(a1, a2, ..., aN),
+/// where \c T is some type and \c a1, a2, ..., aN are values, and
+/// either \C T is a dependent type or one or more of the \c a's is
+/// type-dependent. For example, this would occur in a template such
+/// as:
+///
+/// \code
+/// template<typename T, typename A1>
+/// inline T make_a(const A1& a1) {
+/// return T(a1);
+/// }
+/// \endcode
+///
+/// When the returned expression is instantiated, it may resolve to a
+/// constructor call, conversion function call, or some kind of type
+/// conversion.
+class CXXUnresolvedConstructExpr : public Expr {
+ /// \brief The starting location of the type
+ SourceLocation TyBeginLoc;
+
+ /// \brief The type being constructed.
+ QualType Type;
+
+ /// \brief The location of the left parentheses ('(').
+ SourceLocation LParenLoc;
+
+ /// \brief The location of the right parentheses (')').
+ SourceLocation RParenLoc;
+
+ /// \brief The number of arguments used to construct the type.
+ unsigned NumArgs;
+
+ CXXUnresolvedConstructExpr(SourceLocation TyBegin,
+ QualType T,
+ SourceLocation LParenLoc,
+ Expr **Args,
+ unsigned NumArgs,
+ SourceLocation RParenLoc);
+
+public:
+ static CXXUnresolvedConstructExpr *Create(ASTContext &C,
+ SourceLocation TyBegin,
+ QualType T,
+ SourceLocation LParenLoc,
+ Expr **Args,
+ unsigned NumArgs,
+ SourceLocation RParenLoc);
+
+ /// \brief Retrieve the source location where the type begins.
+ SourceLocation getTypeBeginLoc() const { return TyBeginLoc; }
+ void setTypeBeginLoc(SourceLocation L) { TyBeginLoc = L; }
+
+ /// \brief Retrieve the type that is being constructed, as specified
+ /// in the source code.
+ QualType getTypeAsWritten() const { return Type; }
+ void setTypeAsWritten(QualType T) { Type = T; }
+
+ /// \brief Retrieve the location of the left parentheses ('(') that
+ /// precedes the argument list.
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+ void setLParenLoc(SourceLocation L) { LParenLoc = L; }
+
+ /// \brief Retrieve the location of the right parentheses (')') that
+ /// follows the argument list.
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ /// \brief Retrieve the number of arguments.
+ unsigned arg_size() const { return NumArgs; }
+
+ typedef Expr** arg_iterator;
+ arg_iterator arg_begin() { return reinterpret_cast<Expr**>(this + 1); }
+ arg_iterator arg_end() { return arg_begin() + NumArgs; }
+
+ Expr *getArg(unsigned I) {
+ assert(I < NumArgs && "Argument index out-of-range");
+ return *(arg_begin() + I);
+ }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(TyBeginLoc, RParenLoc);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXUnresolvedConstructExprClass;
+ }
+ static bool classof(const CXXUnresolvedConstructExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// \brief
+class CXXUnresolvedMemberExpr : public Expr {
+ /// \brief The expression for the base pointer or class reference,
+ /// e.g., the \c x in x.f.
+ Stmt *Base;
+
+ /// \brief Whether this member expression used the '->' operator or
+ /// the '.' operator.
+ bool IsArrow;
+
+ /// \brief The location of the '->' or '.' operator.
+ SourceLocation OperatorLoc;
+
+ /// \brief The member to which this member expression refers, which
+ /// can be name, overloaded operator, or destructor.
+ /// FIXME: could also be a template-id, and we might have a
+ /// nested-name-specifier as well.
+ DeclarationName Member;
+
+ /// \brief The location of the member name.
+ SourceLocation MemberLoc;
+
+public:
+ CXXUnresolvedMemberExpr(ASTContext &C,
+ Expr *Base, bool IsArrow,
+ SourceLocation OperatorLoc,
+ DeclarationName Member,
+ SourceLocation MemberLoc)
+ : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true),
+ Base(Base), IsArrow(IsArrow), OperatorLoc(OperatorLoc),
+ Member(Member), MemberLoc(MemberLoc) { }
+
+ /// \brief Retrieve the base object of this member expressions,
+ /// e.g., the \c x in \c x.m.
+ Expr *getBase() { return cast<Expr>(Base); }
+ void setBase(Expr *E) { Base = E; }
+
+ /// \brief Determine whether this member expression used the '->'
+ /// operator; otherwise, it used the '.' operator.
+ bool isArrow() const { return IsArrow; }
+ void setArrow(bool A) { IsArrow = A; }
+
+ /// \brief Retrieve the location of the '->' or '.' operator.
+ SourceLocation getOperatorLoc() const { return OperatorLoc; }
+ void setOperatorLoc(SourceLocation L) { OperatorLoc = L; }
+
+ /// \brief Retrieve the name of the member that this expression
+ /// refers to.
+ DeclarationName getMember() const { return Member; }
+ void setMember(DeclarationName N) { Member = N; }
+
+ // \brief Retrieve the location of the name of the member that this
+ // expression refers to.
+ SourceLocation getMemberLoc() const { return MemberLoc; }
+ void setMemberLoc(SourceLocation L) { MemberLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(Base->getSourceRange().getBegin(),
+ MemberLoc);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXUnresolvedMemberExprClass;
+ }
+ static bool classof(const CXXUnresolvedMemberExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h
new file mode 100644
index 000000000000..51b99610cd9d
--- /dev/null
+++ b/include/clang/AST/ExprObjC.h
@@ -0,0 +1,494 @@
+//===--- ExprObjC.h - Classes for representing ObjC 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 the ExprObjC interface and subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_EXPROBJC_H
+#define LLVM_CLANG_AST_EXPROBJC_H
+
+#include "clang/AST/Expr.h"
+#include "clang/Basic/IdentifierTable.h"
+
+namespace clang {
+ class IdentifierInfo;
+ class ASTContext;
+ class ObjCMethodDecl;
+ class ObjCPropertyDecl;
+
+/// ObjCStringLiteral, used for Objective-C string literals
+/// i.e. @"foo".
+class ObjCStringLiteral : public Expr {
+ Stmt *String;
+ SourceLocation AtLoc;
+public:
+ ObjCStringLiteral(StringLiteral *SL, QualType T, SourceLocation L)
+ : Expr(ObjCStringLiteralClass, T), String(SL), AtLoc(L) {}
+ explicit ObjCStringLiteral(EmptyShell Empty)
+ : Expr(ObjCStringLiteralClass, Empty) {}
+
+ StringLiteral *getString() { return cast<StringLiteral>(String); }
+ const StringLiteral *getString() const { return cast<StringLiteral>(String); }
+ void setString(StringLiteral *S) { String = S; }
+
+ SourceLocation getAtLoc() const { return AtLoc; }
+ void setAtLoc(SourceLocation L) { AtLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(AtLoc, String->getLocEnd());
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCStringLiteralClass;
+ }
+ static bool classof(const ObjCStringLiteral *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ObjCEncodeExpr, used for @encode in Objective-C. @encode has the same type
+/// and behavior as StringLiteral except that the string initializer is obtained
+/// from ASTContext with the encoding type as an argument.
+class ObjCEncodeExpr : public Expr {
+ QualType EncType;
+ SourceLocation AtLoc, RParenLoc;
+public:
+ ObjCEncodeExpr(QualType T, QualType ET,
+ SourceLocation at, SourceLocation rp)
+ : Expr(ObjCEncodeExprClass, T), EncType(ET), AtLoc(at), RParenLoc(rp) {}
+
+ explicit ObjCEncodeExpr(EmptyShell Empty) : Expr(ObjCEncodeExprClass, Empty){}
+
+
+ SourceLocation getAtLoc() const { return AtLoc; }
+ void setAtLoc(SourceLocation L) { AtLoc = L; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ QualType getEncodedType() const { return EncType; }
+ void setEncodedType(QualType T) { EncType = T; }
+
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(AtLoc, RParenLoc);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCEncodeExprClass;
+ }
+ static bool classof(const ObjCEncodeExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ObjCSelectorExpr used for @selector in Objective-C.
+class ObjCSelectorExpr : public Expr {
+ Selector SelName;
+ SourceLocation AtLoc, RParenLoc;
+public:
+ ObjCSelectorExpr(QualType T, Selector selInfo,
+ SourceLocation at, SourceLocation rp)
+ : Expr(ObjCSelectorExprClass, T), SelName(selInfo), AtLoc(at), RParenLoc(rp){}
+ explicit ObjCSelectorExpr(EmptyShell Empty)
+ : Expr(ObjCSelectorExprClass, Empty) {}
+
+ Selector getSelector() const { return SelName; }
+ void setSelector(Selector S) { SelName = S; }
+
+ SourceLocation getAtLoc() const { return AtLoc; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setAtLoc(SourceLocation L) { AtLoc = L; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(AtLoc, RParenLoc);
+ }
+
+ /// getNumArgs - Return the number of actual arguments to this call.
+ unsigned getNumArgs() const { return SelName.getNumArgs(); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCSelectorExprClass;
+ }
+ static bool classof(const ObjCSelectorExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ObjCProtocolExpr used for protocol expression in Objective-C. This is used
+/// as: @protocol(foo), as in:
+/// obj conformsToProtocol:@protocol(foo)]
+/// The return type is "Protocol*".
+class ObjCProtocolExpr : public Expr {
+ ObjCProtocolDecl *Protocol;
+ SourceLocation AtLoc, RParenLoc;
+public:
+ ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol,
+ SourceLocation at, SourceLocation rp)
+ : Expr(ObjCProtocolExprClass, T), Protocol(protocol),
+ AtLoc(at), RParenLoc(rp) {}
+ explicit ObjCProtocolExpr(EmptyShell Empty)
+ : Expr(ObjCProtocolExprClass, Empty) {}
+
+ ObjCProtocolDecl *getProtocol() const { return Protocol; }
+ void setProtocol(ObjCProtocolDecl *P) { Protocol = P; }
+
+ SourceLocation getAtLoc() const { return AtLoc; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setAtLoc(SourceLocation L) { AtLoc = L; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(AtLoc, RParenLoc);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCProtocolExprClass;
+ }
+ static bool classof(const ObjCProtocolExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ObjCIvarRefExpr - A reference to an ObjC instance variable.
+class ObjCIvarRefExpr : public Expr {
+ class ObjCIvarDecl *D;
+ SourceLocation Loc;
+ Stmt *Base;
+ bool IsArrow:1; // True if this is "X->F", false if this is "X.F".
+ bool IsFreeIvar:1; // True if ivar reference has no base (self assumed).
+
+public:
+ ObjCIvarRefExpr(ObjCIvarDecl *d,
+ QualType t, SourceLocation l, Expr *base=0,
+ bool arrow = false, bool freeIvar = false) :
+ Expr(ObjCIvarRefExprClass, t), D(d),
+ Loc(l), Base(base), IsArrow(arrow),
+ IsFreeIvar(freeIvar) {}
+
+ explicit ObjCIvarRefExpr(EmptyShell Empty)
+ : Expr(ObjCIvarRefExprClass, Empty) {}
+
+ ObjCIvarDecl *getDecl() { return D; }
+ const ObjCIvarDecl *getDecl() const { return D; }
+ void setDecl(ObjCIvarDecl *d) { D = d; }
+
+ const Expr *getBase() const { return cast<Expr>(Base); }
+ Expr *getBase() { return cast<Expr>(Base); }
+ void setBase(Expr * base) { Base = base; }
+
+ bool isArrow() const { return IsArrow; }
+ bool isFreeIvar() const { return IsFreeIvar; }
+ void setIsArrow(bool A) { IsArrow = A; }
+ void setIsFreeIvar(bool A) { IsFreeIvar = A; }
+
+ SourceLocation getLocation() const { return Loc; }
+ void setLocation(SourceLocation L) { Loc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return isFreeIvar() ? SourceRange(Loc)
+ : SourceRange(getBase()->getLocStart(), Loc);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCIvarRefExprClass;
+ }
+ static bool classof(const ObjCIvarRefExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC
+/// property.
+///
+class ObjCPropertyRefExpr : public Expr {
+private:
+ ObjCPropertyDecl *AsProperty;
+ SourceLocation IdLoc;
+ Stmt *Base;
+public:
+ ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
+ SourceLocation l, Expr *base)
+ : Expr(ObjCPropertyRefExprClass, t), AsProperty(PD), IdLoc(l), Base(base) {
+ }
+
+ explicit ObjCPropertyRefExpr(EmptyShell Empty)
+ : Expr(ObjCPropertyRefExprClass, Empty) {}
+
+ ObjCPropertyDecl *getProperty() const { return AsProperty; }
+ void setProperty(ObjCPropertyDecl *D) { AsProperty = D; }
+
+ const Expr *getBase() const { return cast<Expr>(Base); }
+ Expr *getBase() { return cast<Expr>(Base); }
+ void setBase(Expr *base) { Base = base; }
+
+ SourceLocation getLocation() const { return IdLoc; }
+ void setLocation(SourceLocation L) { IdLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(getBase()->getLocStart(), IdLoc);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCPropertyRefExprClass;
+ }
+ static bool classof(const ObjCPropertyRefExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ObjCKVCRefExpr - A dot-syntax expression to access "implicit" properties
+/// (i.e. methods following the property naming convention). KVC stands for
+/// Key Value Encoding, a generic concept for accessing or setting a 'Key'
+/// value for an object.
+///
+class ObjCKVCRefExpr : public Expr {
+ ObjCMethodDecl *Setter;
+ ObjCMethodDecl *Getter;
+ SourceLocation Loc;
+ // FIXME: Swizzle these into a single pointer.
+ Stmt *Base;
+ ObjCInterfaceDecl *ClassProp;
+ SourceLocation ClassLoc;
+
+public:
+ ObjCKVCRefExpr(ObjCMethodDecl *getter,
+ QualType t,
+ ObjCMethodDecl *setter,
+ SourceLocation l, Expr *base)
+ : Expr(ObjCKVCRefExprClass, t), Setter(setter),
+ Getter(getter), Loc(l), Base(base), ClassProp(0),
+ ClassLoc(SourceLocation()) {
+ }
+ ObjCKVCRefExpr(ObjCMethodDecl *getter,
+ QualType t,
+ ObjCMethodDecl *setter,
+ SourceLocation l, ObjCInterfaceDecl *C, SourceLocation CL)
+ : Expr(ObjCKVCRefExprClass, t), Setter(setter),
+ Getter(getter), Loc(l), Base(0), ClassProp(C), ClassLoc(CL) {
+ }
+ explicit ObjCKVCRefExpr(EmptyShell Empty) : Expr(ObjCKVCRefExprClass, Empty){}
+
+ ObjCMethodDecl *getGetterMethod() const { return Getter; }
+ ObjCMethodDecl *getSetterMethod() const { return Setter; }
+ ObjCInterfaceDecl *getClassProp() const { return ClassProp; }
+ void setGetterMethod(ObjCMethodDecl *D) { Getter = D; }
+ void setSetterMethod(ObjCMethodDecl *D) { Setter = D; }
+ void setClassProp(ObjCInterfaceDecl *D) { ClassProp = D; }
+
+ virtual SourceRange getSourceRange() const {
+ if (Base)
+ return SourceRange(getBase()->getLocStart(), Loc);
+ return SourceRange(ClassLoc, Loc);
+ }
+ const Expr *getBase() const { return cast_or_null<Expr>(Base); }
+ Expr *getBase() { return cast_or_null<Expr>(Base); }
+ void setBase(Expr *base) { Base = base; }
+
+ SourceLocation getLocation() const { return Loc; }
+ void setLocation(SourceLocation L) { Loc = L; }
+ SourceLocation getClassLoc() const { return ClassLoc; }
+ void setClassLoc(SourceLocation L) { ClassLoc = L; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCKVCRefExprClass;
+ }
+ static bool classof(const ObjCKVCRefExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+class ObjCMessageExpr : public Expr {
+ // SubExprs - The receiver and arguments of the message expression.
+ Stmt **SubExprs;
+
+ // NumArgs - The number of arguments (not including the receiver) to the
+ // message expression.
+ unsigned NumArgs;
+
+ // A unigue name for this message.
+ Selector SelName;
+
+ // A method prototype for this message (optional).
+ // FIXME: Since method decls contain the selector, and most messages have a
+ // prototype, consider devising a scheme for unifying SelName/MethodProto.
+ ObjCMethodDecl *MethodProto;
+
+ SourceLocation LBracloc, RBracloc;
+
+ // Constants for indexing into SubExprs.
+ enum { RECEIVER=0, ARGS_START=1 };
+
+ // Bit-swizzling flags.
+ enum { IsInstMeth=0, IsClsMethDeclUnknown, IsClsMethDeclKnown, Flags=0x3 };
+ unsigned getFlag() const { return (uintptr_t) SubExprs[RECEIVER] & Flags; }
+
+public:
+ /// This constructor is used to represent class messages where the
+ /// ObjCInterfaceDecl* of the receiver is not known.
+ ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo,
+ QualType retType, ObjCMethodDecl *methDecl,
+ SourceLocation LBrac, SourceLocation RBrac,
+ Expr **ArgExprs, unsigned NumArgs);
+
+ /// This constructor is used to represent class messages where the
+ /// ObjCInterfaceDecl* of the receiver is known.
+ // FIXME: clsName should be typed to ObjCInterfaceType
+ ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo,
+ QualType retType, ObjCMethodDecl *methDecl,
+ SourceLocation LBrac, SourceLocation RBrac,
+ Expr **ArgExprs, unsigned NumArgs);
+
+ // constructor for instance messages.
+ ObjCMessageExpr(Expr *receiver, Selector selInfo,
+ QualType retType, ObjCMethodDecl *methDecl,
+ SourceLocation LBrac, SourceLocation RBrac,
+ Expr **ArgExprs, unsigned NumArgs);
+
+ explicit ObjCMessageExpr(EmptyShell Empty)
+ : Expr(ObjCMessageExprClass, Empty), SubExprs(0), NumArgs(0) {}
+
+ ~ObjCMessageExpr() {
+ delete [] SubExprs;
+ }
+
+ /// getReceiver - Returns the receiver of the message expression.
+ /// This can be NULL if the message is for class methods. For
+ /// class methods, use getClassName.
+ /// FIXME: need to handle/detect 'super' usage within a class method.
+ Expr *getReceiver() {
+ uintptr_t x = (uintptr_t) SubExprs[RECEIVER];
+ return (x & Flags) == IsInstMeth ? (Expr*) x : 0;
+ }
+ const Expr *getReceiver() const {
+ return const_cast<ObjCMessageExpr*>(this)->getReceiver();
+ }
+ // FIXME: need setters for different receiver types.
+ void setReceiver(Expr *rec) { SubExprs[RECEIVER] = rec; }
+ Selector getSelector() const { return SelName; }
+ void setSelector(Selector S) { SelName = S; }
+
+ const ObjCMethodDecl *getMethodDecl() const { return MethodProto; }
+ ObjCMethodDecl *getMethodDecl() { return MethodProto; }
+ void setMethodDecl(ObjCMethodDecl *MD) { MethodProto = MD; }
+
+ typedef std::pair<ObjCInterfaceDecl*, IdentifierInfo*> ClassInfo;
+
+ /// getClassInfo - For class methods, this returns both the ObjCInterfaceDecl*
+ /// and IdentifierInfo* of the invoked class. Both can be NULL if this
+ /// is an instance message, and the ObjCInterfaceDecl* can be NULL if none
+ /// was available when this ObjCMessageExpr object was constructed.
+ ClassInfo getClassInfo() const;
+ void setClassInfo(const ClassInfo &C);
+
+ /// getClassName - For class methods, this returns the invoked class,
+ /// and returns NULL otherwise. For instance methods, use getReceiver.
+ IdentifierInfo *getClassName() const {
+ return getClassInfo().second;
+ }
+
+ /// getNumArgs - Return the number of actual arguments to this call.
+ unsigned getNumArgs() const { return NumArgs; }
+ void setNumArgs(unsigned nArgs) {
+ NumArgs = nArgs;
+ // FIXME: should always allocate SubExprs via the ASTContext's
+ // allocator.
+ if (!SubExprs)
+ SubExprs = new Stmt* [NumArgs + 1];
+ }
+
+ /// getArg - Return the specified argument.
+ Expr *getArg(unsigned Arg) {
+ assert(Arg < NumArgs && "Arg access out of range!");
+ return cast<Expr>(SubExprs[Arg+ARGS_START]);
+ }
+ const Expr *getArg(unsigned Arg) const {
+ assert(Arg < NumArgs && "Arg access out of range!");
+ return cast<Expr>(SubExprs[Arg+ARGS_START]);
+ }
+ /// setArg - Set the specified argument.
+ void setArg(unsigned Arg, Expr *ArgExpr) {
+ assert(Arg < NumArgs && "Arg access out of range!");
+ SubExprs[Arg+ARGS_START] = ArgExpr;
+ }
+
+ SourceLocation getLeftLoc() const { return LBracloc; }
+ SourceLocation getRightLoc() const { return RBracloc; }
+
+ void setLeftLoc(SourceLocation L) { LBracloc = L; }
+ void setRightLoc(SourceLocation L) { RBracloc = L; }
+
+ void setSourceRange(SourceRange R) {
+ LBracloc = R.getBegin();
+ RBracloc = R.getEnd();
+ }
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(LBracloc, RBracloc);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCMessageExprClass;
+ }
+ static bool classof(const ObjCMessageExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+
+ typedef ExprIterator arg_iterator;
+ typedef ConstExprIterator const_arg_iterator;
+
+ arg_iterator arg_begin() { return &SubExprs[ARGS_START]; }
+ arg_iterator arg_end() { return &SubExprs[ARGS_START] + NumArgs; }
+ const_arg_iterator arg_begin() const { return &SubExprs[ARGS_START]; }
+ const_arg_iterator arg_end() const { return &SubExprs[ARGS_START] + NumArgs; }
+};
+
+/// ObjCSuperExpr - Represents the "super" expression in Objective-C,
+/// which refers to the object on which the current method is executing.
+class ObjCSuperExpr : public Expr {
+ SourceLocation Loc;
+public:
+ ObjCSuperExpr(SourceLocation L, QualType Type)
+ : Expr(ObjCSuperExprClass, Type), Loc(L) { }
+ explicit ObjCSuperExpr(EmptyShell Empty) : Expr(ObjCSuperExprClass, Empty) {}
+
+ SourceLocation getLoc() const { return Loc; }
+ void setLoc(SourceLocation L) { Loc = L; }
+
+ virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCSuperExprClass;
+ }
+ static bool classof(const ObjCSuperExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h
new file mode 100644
index 000000000000..4219bd507a90
--- /dev/null
+++ b/include/clang/AST/ExternalASTSource.h
@@ -0,0 +1,184 @@
+//===--- ExternalASTSource.h - Abstract External AST 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 ExternalASTSource interface, which enables
+// construction of AST nodes from some external source.x
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
+#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
+
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/SmallVector.h"
+#include <cassert>
+namespace clang {
+
+class ASTConsumer;
+class Decl;
+class DeclContext;
+class ExternalSemaSource; // layering violation required for downcasting
+class Stmt;
+
+/// \brief The deserialized representation of a set of declarations
+/// with the same name that are visible in a given context.
+struct VisibleDeclaration {
+ /// \brief The name of the declarations.
+ DeclarationName Name;
+
+ /// \brief The ID numbers of all of the declarations with this name.
+ ///
+ /// These declarations have not necessarily been de-serialized.
+ llvm::SmallVector<unsigned, 4> Declarations;
+};
+
+/// \brief Abstract interface for external sources of AST nodes.
+///
+/// External AST sources provide AST nodes constructed from some
+/// external source, such as a precompiled header. External AST
+/// sources can resolve types and declarations from abstract IDs into
+/// actual type and declaration nodes, and read parts of declaration
+/// contexts.
+class ExternalASTSource {
+ /// \brief Whether this AST source also provides information for
+ /// semantic analysis.
+ bool SemaSource;
+
+ friend class ExternalSemaSource;
+
+public:
+ ExternalASTSource() : SemaSource(false) { }
+
+ virtual ~ExternalASTSource();
+
+ /// \brief Resolve a type ID into a type, potentially building a new
+ /// type.
+ virtual QualType GetType(uint32_t ID) = 0;
+
+ /// \brief Resolve a declaration ID into a declaration, potentially
+ /// building a new declaration.
+ virtual Decl *GetDecl(uint32_t ID) = 0;
+
+ /// \brief Resolve the offset of a statement in the decl stream into a
+ /// statement.
+ ///
+ /// This operation will read a new statement from the external
+ /// source each time it is called, and is meant to be used via a
+ /// LazyOffsetPtr.
+ virtual Stmt *GetDeclStmt(uint64_t Offset) = 0;
+
+ /// \brief Read all of the declarations lexically stored in a
+ /// declaration context.
+ ///
+ /// \param DC The declaration context whose declarations will be
+ /// read.
+ ///
+ /// \param Decls Vector that will contain the declarations loaded
+ /// from the external source. The caller is responsible for merging
+ /// these declarations with any declarations already stored in the
+ /// declaration context.
+ ///
+ /// \returns true if there was an error while reading the
+ /// declarations for this declaration context.
+ virtual bool ReadDeclsLexicallyInContext(DeclContext *DC,
+ llvm::SmallVectorImpl<uint32_t> &Decls) = 0;
+
+ /// \brief Read all of the declarations visible from a declaration
+ /// context.
+ ///
+ /// \param DC The declaration context whose visible declarations
+ /// will be read.
+ ///
+ /// \param Decls A vector of visible declaration structures,
+ /// providing the mapping from each name visible in the declaration
+ /// context to the declaration IDs of declarations with that name.
+ ///
+ /// \returns true if there was an error while reading the
+ /// declarations for this declaration context.
+ virtual bool ReadDeclsVisibleInContext(DeclContext *DC,
+ llvm::SmallVectorImpl<VisibleDeclaration> & Decls) = 0;
+
+ /// \brief Function that will be invoked when we begin parsing a new
+ /// translation unit involving this external AST source.
+ virtual void StartTranslationUnit(ASTConsumer *Consumer) { }
+
+ /// \brief Print any statistics that have been gathered regarding
+ /// the external AST source.
+ virtual void PrintStats();
+};
+
+/// \brief A lazy pointer to an AST node (of base type T) that resides
+/// within an external AST source.
+///
+/// The AST node is identified within the external AST source by a
+/// 63-bit offset, and can be retrieved via an operation on the
+/// external AST source itself.
+template<typename T, T* (ExternalASTSource::*Get)(uint64_t Offset)>
+struct LazyOffsetPtr {
+ /// \brief Either a pointer to an AST node or the offset within the
+ /// external AST source where the AST node can be found.
+ ///
+ /// If the low bit is clear, a pointer to the AST node. If the low
+ /// bit is set, the upper 63 bits are the offset.
+ mutable uint64_t Ptr;
+
+public:
+ LazyOffsetPtr() : Ptr(0) { }
+
+ explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) { }
+ explicit LazyOffsetPtr(uint64_t Offset) : Ptr((Offset << 1) | 0x01) {
+ assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits");
+ if (Offset == 0)
+ Ptr = 0;
+ }
+
+ LazyOffsetPtr &operator=(T *Ptr) {
+ this->Ptr = reinterpret_cast<uint64_t>(Ptr);
+ return *this;
+ }
+
+ LazyOffsetPtr &operator=(uint64_t Offset) {
+ assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits");
+ if (Offset == 0)
+ Ptr = 0;
+ else
+ Ptr = (Offset << 1) | 0x01;
+
+ return *this;
+ }
+
+ /// \brief Whether this pointer is non-NULL.
+ ///
+ /// This operation does not require the AST node to be deserialized.
+ operator bool() const { return Ptr != 0; }
+
+ /// \brief Whether this pointer is currently stored as an offset.
+ bool isOffset() const { return Ptr & 0x01; }
+
+ /// \brief Retrieve the pointer to the AST node that this lazy pointer
+ ///
+ /// \param Source the external AST source.
+ ///
+ /// \returns a pointer to the AST node.
+ T* get(ExternalASTSource *Source) const {
+ if (isOffset()) {
+ assert(Source &&
+ "Cannot deserialize a lazy pointer without an AST source");
+ Ptr = reinterpret_cast<uint64_t>((Source->*Get)(Ptr >> 1));
+ }
+ return reinterpret_cast<T*>(Ptr);
+ }
+};
+
+/// \brief A lazy pointer to a statement.
+typedef LazyOffsetPtr<Stmt, &ExternalASTSource::GetDeclStmt> LazyDeclStmtPtr;
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h
new file mode 100644
index 000000000000..4eea1031f063
--- /dev/null
+++ b/include/clang/AST/NestedNameSpecifier.h
@@ -0,0 +1,183 @@
+//===--- NestedNameSpecifier.h - C++ nested name specifiers -----*- 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 NestedNameSpecifier class, which represents
+// a C++ nested-name-specifier.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
+#define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
+
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/PointerIntPair.h"
+
+namespace llvm {
+ class raw_ostream;
+}
+
+namespace clang {
+
+class ASTContext;
+class NamespaceDecl;
+class IdentifierInfo;
+class PrintingPolicy;
+class Type;
+
+/// \brief Represents a C++ nested name specifier, such as
+/// "::std::vector<int>::".
+///
+/// C++ nested name specifiers are the prefixes to qualified
+/// namespaces. For example, "foo::" in "foo::x" is a nested name
+/// specifier. Nested name specifiers are made up of a sequence of
+/// specifiers, each of which can be a namespace, type, identifier
+/// (for dependent names), or the global specifier ('::', must be the
+/// first specifier).
+class NestedNameSpecifier : public llvm::FoldingSetNode {
+ /// \brief The nested name specifier that precedes this nested name
+ /// specifier.
+ ///
+ /// The pointer is the nested-name-specifier that precedes this
+ /// one. The integer stores one of the first four values of type
+ /// SpecifierKind.
+ llvm::PointerIntPair<NestedNameSpecifier *, 2> Prefix;
+
+ /// \brief The last component in the nested name specifier, which
+ /// can be an identifier, a declaration, or a type.
+ ///
+ /// When the pointer is NULL, this specifier represents the global
+ /// specifier '::'. Otherwise, the pointer is one of
+ /// IdentifierInfo*, Namespace*, or Type*, depending on the kind of
+ /// specifier as encoded within the prefix.
+ void* Specifier;
+
+public:
+ /// \brief The kind of specifier that completes this nested name
+ /// specifier.
+ enum SpecifierKind {
+ /// \brief An identifier, stored as an IdentifierInfo*.
+ Identifier = 0,
+ /// \brief A namespace, stored as a Namespace*.
+ Namespace = 1,
+ /// \brief A type, stored as a Type*.
+ TypeSpec = 2,
+ /// \brief A type that was preceded by the 'template' keyword,
+ /// stored as a Type*.
+ TypeSpecWithTemplate = 3,
+ /// \brief The global specifier '::'. There is no stored value.
+ Global = 4
+ };
+
+private:
+ /// \brief Builds the global specifier.
+ NestedNameSpecifier() : Prefix(0, 0), Specifier(0) { }
+
+ /// \brief Copy constructor used internally to clone nested name
+ /// specifiers.
+ NestedNameSpecifier(const NestedNameSpecifier &Other)
+ : llvm::FoldingSetNode(Other), Prefix(Other.Prefix),
+ Specifier(Other.Specifier) {
+ }
+
+ NestedNameSpecifier &operator=(const NestedNameSpecifier &); // do not implement
+
+ /// \brief Either find or insert the given nested name specifier
+ /// mockup in the given context.
+ static NestedNameSpecifier *FindOrInsert(ASTContext &Context,
+ const NestedNameSpecifier &Mockup);
+
+public:
+ /// \brief Builds a specifier combining a prefix and an identifier.
+ ///
+ /// The prefix must be dependent, since nested name specifiers
+ /// referencing an identifier are only permitted when the identifier
+ /// cannot be resolved.
+ static NestedNameSpecifier *Create(ASTContext &Context,
+ NestedNameSpecifier *Prefix,
+ IdentifierInfo *II);
+
+ /// \brief Builds a nested name specifier that names a namespace.
+ static NestedNameSpecifier *Create(ASTContext &Context,
+ NestedNameSpecifier *Prefix,
+ NamespaceDecl *NS);
+
+ /// \brief Builds a nested name specifier that names a type.
+ static NestedNameSpecifier *Create(ASTContext &Context,
+ NestedNameSpecifier *Prefix,
+ bool Template, Type *T);
+
+ /// \brief Returns the nested name specifier representing the global
+ /// scope.
+ static NestedNameSpecifier *GlobalSpecifier(ASTContext &Context);
+
+ /// \brief Return the prefix of this nested name specifier.
+ ///
+ /// The prefix contains all of the parts of the nested name
+ /// specifier that preced this current specifier. For example, for a
+ /// nested name specifier that represents "foo::bar::", the current
+ /// specifier will contain "bar::" and the prefix will contain
+ /// "foo::".
+ NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); }
+
+ /// \brief Determine what kind of nested name specifier is stored.
+ SpecifierKind getKind() const {
+ if (Specifier == 0)
+ return Global;
+ return (SpecifierKind)Prefix.getInt();
+ }
+
+ /// \brief Retrieve the identifier stored in this nested name
+ /// specifier.
+ IdentifierInfo *getAsIdentifier() const {
+ if (Prefix.getInt() == Identifier)
+ return (IdentifierInfo *)Specifier;
+
+ return 0;
+ }
+
+ /// \brief Retrieve the namespace stored in this nested name
+ /// specifier.
+ NamespaceDecl *getAsNamespace() const {
+ if (Prefix.getInt() == Namespace)
+ return (NamespaceDecl *)Specifier;
+
+ return 0;
+ }
+
+ /// \brief Retrieve the type stored in this nested name specifier.
+ Type *getAsType() const {
+ if (Prefix.getInt() == TypeSpec ||
+ Prefix.getInt() == TypeSpecWithTemplate)
+ return (Type *)Specifier;
+
+ return 0;
+ }
+
+ /// \brief Whether this nested name specifier refers to a dependent
+ /// type or not.
+ bool isDependent() const;
+
+ /// \brief Print this nested name specifier to the given output
+ /// stream.
+ void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(Prefix.getOpaqueValue());
+ ID.AddPointer(Specifier);
+ }
+
+ void Destroy(ASTContext &Context);
+
+ /// \brief Dump the nested name specifier to standard output to aid
+ /// in debugging.
+ void dump();
+};
+
+}
+
+#endif
diff --git a/include/clang/AST/PPCBuiltins.def b/include/clang/AST/PPCBuiltins.def
new file mode 100644
index 000000000000..b8c791286e55
--- /dev/null
+++ b/include/clang/AST/PPCBuiltins.def
@@ -0,0 +1,24 @@
+//===--- PPCBuiltins.def - PowerPC Builtin function database ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the PowerPC-specific builtin function database. Users of
+// this file must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+// FIXME: this needs to be the full list supported by GCC. Right now, I'm just
+// adding stuff on demand.
+
+// The format of this database matches clang/AST/Builtins.def.
+
+// This is just a placeholder, the types and attributes are wrong.
+BUILTIN(__builtin_altivec_abs_v4sf , "ii" , "nc")
+// FIXME: Obviously incomplete.
+
+#undef BUILTIN
diff --git a/include/clang/AST/ParentMap.h b/include/clang/AST/ParentMap.h
new file mode 100644
index 000000000000..c669991ccc08
--- /dev/null
+++ b/include/clang/AST/ParentMap.h
@@ -0,0 +1,50 @@
+//===--- ParentMap.h - Mappings from Stmts to their Parents -----*- 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 ParentMap class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PARENTMAP_H
+#define LLVM_CLANG_PARENTMAP_H
+
+namespace clang {
+class Stmt;
+class Expr;
+
+class ParentMap {
+ void* Impl;
+public:
+ ParentMap(Stmt* ASTRoot);
+ ~ParentMap();
+
+ Stmt *getParent(Stmt*) const;
+ Stmt *getParentIgnoreParens(Stmt *) const;
+
+ const Stmt *getParent(const Stmt* S) const {
+ return getParent(const_cast<Stmt*>(S));
+ }
+
+ const Stmt *getParentIgnoreParens(const Stmt *S) const {
+ return getParentIgnoreParens(const_cast<Stmt*>(S));
+ }
+
+ bool hasParent(Stmt* S) const {
+ return getParent(S) != 0;
+ }
+
+ bool isConsumedExpr(Expr *E) const;
+
+ bool isConsumedExpr(const Expr *E) const {
+ return isConsumedExpr(const_cast<Expr*>(E));
+ }
+};
+
+} // end clang namespace
+#endif
diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h
new file mode 100644
index 000000000000..385602b1fb9c
--- /dev/null
+++ b/include/clang/AST/PrettyPrinter.h
@@ -0,0 +1,86 @@
+//===--- PrettyPrinter.h - Classes for aiding with AST printing -*- 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 PrinterHelper interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_PRETTY_PRINTER_H
+#define LLVM_CLANG_AST_PRETTY_PRINTER_H
+
+namespace llvm {
+ class raw_ostream;
+}
+
+namespace clang {
+
+class Stmt;
+class TagDecl;
+
+class PrinterHelper {
+public:
+ virtual ~PrinterHelper();
+ virtual bool handledStmt(Stmt* E, llvm::raw_ostream& OS) = 0;
+};
+
+/// \brief Describes how types, statements, expressions, and
+/// declarations should be printed.
+struct PrintingPolicy {
+ /// \brief Create a default printing policy for C.
+ PrintingPolicy()
+ : Indentation(2), CPlusPlus(false), SuppressSpecifiers(false),
+ SuppressTag(false), SuppressTagKind(false), Dump(false) { }
+
+ /// \brief The number of spaces to use to indent each line.
+ unsigned Indentation : 8;
+
+ /// \brief Whether we're printing C++ code (otherwise, we're
+ /// printing C code).
+ bool CPlusPlus : 1;
+
+ /// \brief Whether we should suppress printing of the actual specifiers for
+ /// the given type or declaration.
+ ///
+ /// This flag is only used when we are printing declarators beyond
+ /// the first declarator within a declaration group. For example, given:
+ ///
+ /// \code
+ /// const int *x, *y;
+ /// \endcode
+ ///
+ /// SuppressSpecifiers will be false when printing the
+ /// declaration for "x", so that we will print "int *x"; it will be
+ /// \c true when we print "y", so that we suppress printing the
+ /// "const int" type specifier and instead only print the "*y".
+ bool SuppressSpecifiers : 1;
+
+ /// \brief Whether type printing should skip printing the actual tag type.
+ ///
+ /// This is used when the caller needs to print a tag definition in front
+ /// of the type, as in constructs like the following:
+ ///
+ /// \code
+ /// typedef struct { int x, y; } Point;
+ /// \endcode
+ bool SuppressTag : 1;
+
+ /// \brief If we are printing a tag type, suppresses printing of the
+ /// kind of tag, e.g., "struct", "union", "enum".
+ bool SuppressTagKind : 1;
+
+ /// \brief True when we are "dumping" rather than "pretty-printing",
+ /// where dumping involves printing the internal details of the AST
+ /// and pretty-printing involves printing something similar to
+ /// source code.
+ bool Dump : 1;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h
new file mode 100644
index 000000000000..ab184563da23
--- /dev/null
+++ b/include/clang/AST/RecordLayout.h
@@ -0,0 +1,103 @@
+//===--- RecordLayout.h - Layout information for a struct/union -*- 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 RecordLayout interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_LAYOUTINFO_H
+#define LLVM_CLANG_AST_LAYOUTINFO_H
+
+#include "llvm/Support/DataTypes.h"
+
+namespace clang {
+ class ASTContext;
+ class RecordDecl;
+
+/// ASTRecordLayout -
+/// This class contains layout information for one RecordDecl,
+/// which is a struct/union/class. The decl represented must be a definition,
+/// not a forward declaration.
+/// This class is also used to contain layout information for one
+/// ObjCInterfaceDecl. FIXME - Find appropriate name.
+/// These objects are managed by ASTContext.
+class ASTRecordLayout {
+ uint64_t Size; // Size of record in bits.
+ uint64_t NextOffset; // Next available offset
+ uint64_t *FieldOffsets;
+ unsigned Alignment; // Alignment of record in bits.
+ unsigned FieldCount; // Number of fields
+ friend class ASTContext;
+
+ ASTRecordLayout(uint64_t S = 0, unsigned A = 8)
+ : Size(S), NextOffset(S), Alignment(A), FieldCount(0) {}
+ ~ASTRecordLayout() {
+ delete [] FieldOffsets;
+ }
+
+ /// Initialize record layout. N is the number of fields in this record.
+ void InitializeLayout(unsigned N) {
+ FieldCount = N;
+ FieldOffsets = new uint64_t[N];
+ }
+
+ /// Finalize record layout. Adjust record size based on the alignment.
+ void FinalizeLayout(bool ForceNonEmpty = false) {
+ // In C++, records cannot be of size 0.
+ if (ForceNonEmpty && Size == 0)
+ Size = 8;
+ // Finally, round the size of the record up to the alignment of the
+ // record itself.
+ Size = (Size + (Alignment-1)) & ~(Alignment-1);
+ }
+
+ void SetFieldOffset(unsigned FieldNo, uint64_t Offset) {
+ assert (FieldNo < FieldCount && "Invalid Field No");
+ FieldOffsets[FieldNo] = Offset;
+ }
+
+ void SetAlignment(unsigned A) { Alignment = A; }
+
+ /// LayoutField - Field layout. StructPacking is the specified
+ /// packing alignment (maximum alignment) in bits to use for the
+ /// structure, or 0 if no packing alignment is specified.
+ void LayoutField(const FieldDecl *FD, unsigned FieldNo,
+ bool IsUnion, unsigned StructPacking,
+ ASTContext &Context);
+
+ ASTRecordLayout(const ASTRecordLayout&); // DO NOT IMPLEMENT
+ void operator=(const ASTRecordLayout&); // DO NOT IMPLEMENT
+public:
+
+ /// getAlignment - Get the record alignment in bits.
+ unsigned getAlignment() const { return Alignment; }
+
+ /// getSize - Get the record size in bits.
+ uint64_t getSize() const { return Size; }
+
+ /// getFieldCount - Get the number of fields in the layout.
+ unsigned getFieldCount() const { return FieldCount; }
+
+ /// getFieldOffset - Get the offset of the given field index, in
+ /// bits.
+ uint64_t getFieldOffset(unsigned FieldNo) const {
+ assert (FieldNo < FieldCount && "Invalid Field No");
+ return FieldOffsets[FieldNo];
+ }
+
+ /// getNextOffset - Get the next available (unused) offset in the
+ /// structure, in bits.
+ uint64_t getNextOffset() const {
+ return NextOffset;
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
new file mode 100644
index 000000000000..3656333d7423
--- /dev/null
+++ b/include/clang/AST/Stmt.h
@@ -0,0 +1,1223 @@
+//===--- Stmt.h - Classes for representing statements -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Stmt interface and subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#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/SourceLocation.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/StmtIterator.h"
+#include "clang/AST/DeclGroup.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/iterator.h"
+#include "clang/AST/ASTContext.h"
+#include <string>
+using llvm::dyn_cast_or_null;
+
+namespace clang {
+ class ASTContext;
+ class Expr;
+ class Decl;
+ class ParmVarDecl;
+ class QualType;
+ class IdentifierInfo;
+ class SourceManager;
+ class StringLiteral;
+ class SwitchStmt;
+
+ //===----------------------------------------------------------------------===//
+ // ExprIterator - Iterators for iterating over Stmt* arrays that contain
+ // only Expr*. This is needed because AST nodes use Stmt* arrays to store
+ // references to children (to be compatible with StmtIterator).
+ //===----------------------------------------------------------------------===//
+
+ class Stmt;
+ class Expr;
+
+ class ExprIterator {
+ Stmt** I;
+ public:
+ ExprIterator(Stmt** i) : I(i) {}
+ ExprIterator() : I(0) {}
+ ExprIterator& operator++() { ++I; return *this; }
+ ExprIterator operator-(size_t i) { return I-i; }
+ ExprIterator operator+(size_t i) { return I+i; }
+ Expr* operator[](size_t idx);
+ // FIXME: Verify that this will correctly return a signed distance.
+ signed operator-(const ExprIterator& R) const { return I - R.I; }
+ Expr* operator*() const;
+ Expr* operator->() const;
+ bool operator==(const ExprIterator& R) const { return I == R.I; }
+ bool operator!=(const ExprIterator& R) const { return I != R.I; }
+ bool operator>(const ExprIterator& R) const { return I > R.I; }
+ bool operator>=(const ExprIterator& R) const { return I >= R.I; }
+ };
+
+ class ConstExprIterator {
+ Stmt* const * I;
+ public:
+ ConstExprIterator(Stmt* const* i) : I(i) {}
+ ConstExprIterator() : I(0) {}
+ ConstExprIterator& operator++() { ++I; return *this; }
+ ConstExprIterator operator+(size_t i) { return I+i; }
+ ConstExprIterator operator-(size_t i) { return I-i; }
+ const Expr * operator[](size_t idx) const;
+ signed operator-(const ConstExprIterator& R) const { return I - R.I; }
+ const Expr * operator*() const;
+ const Expr * operator->() const;
+ bool operator==(const ConstExprIterator& R) const { return I == R.I; }
+ bool operator!=(const ConstExprIterator& R) const { return I != R.I; }
+ bool operator>(const ConstExprIterator& R) const { return I > R.I; }
+ bool operator>=(const ConstExprIterator& R) const { return I >= R.I; }
+ };
+
+//===----------------------------------------------------------------------===//
+// AST classes for statements.
+//===----------------------------------------------------------------------===//
+
+/// Stmt - This represents one statement.
+///
+class Stmt {
+public:
+ enum StmtClass {
+ NoStmtClass = 0,
+#define STMT(CLASS, PARENT) CLASS##Class,
+#define FIRST_STMT(CLASS) firstStmtConstant = CLASS##Class,
+#define LAST_STMT(CLASS) lastStmtConstant = CLASS##Class,
+#define FIRST_EXPR(CLASS) firstExprConstant = CLASS##Class,
+#define LAST_EXPR(CLASS) lastExprConstant = CLASS##Class
+#include "clang/AST/StmtNodes.def"
+};
+private:
+ const StmtClass sClass;
+
+ // 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;
+ }
+ void operator delete(void* data) throw() {
+ assert(0 && "Stmts cannot be released with regular 'delete'.");
+ }
+
+public:
+ // Only allow allocation of Stmts using the allocator in ASTContext
+ // or by doing a placement new.
+ void* operator new(size_t bytes, ASTContext& C,
+ unsigned alignment = 16) throw() {
+ return ::operator new(bytes, C, alignment);
+ }
+
+ void* operator new(size_t bytes, ASTContext* C,
+ unsigned alignment = 16) throw() {
+ return ::operator new(bytes, *C, alignment);
+ }
+
+ void* operator new(size_t bytes, void* mem) throw() {
+ return mem;
+ }
+
+ void operator delete(void*, ASTContext&, unsigned) throw() { }
+ void operator delete(void*, ASTContext*, unsigned) throw() { }
+ void operator delete(void*, std::size_t) throw() { }
+ void operator delete(void*, void*) throw() { }
+
+public:
+ /// \brief A placeholder type used to construct an empty shell of a
+ /// type, that will be filled in later (e.g., by some
+ /// de-serialization).
+ struct EmptyShell { };
+
+protected:
+ /// DestroyChildren - Invoked by destructors of subclasses of Stmt to
+ /// recursively release child AST nodes.
+ void DestroyChildren(ASTContext& Ctx);
+
+ /// \brief Construct an empty statement.
+ explicit Stmt(StmtClass SC, EmptyShell) : sClass(SC) {
+ if (Stmt::CollectingStats()) Stmt::addStmtClass(SC);
+ }
+
+public:
+ Stmt(StmtClass SC) : sClass(SC) {
+ if (Stmt::CollectingStats()) Stmt::addStmtClass(SC);
+ }
+ virtual ~Stmt() {}
+
+ virtual void Destroy(ASTContext &Ctx);
+
+ StmtClass getStmtClass() const { return sClass; }
+ const char *getStmtClassName() const;
+
+ /// SourceLocation tokens are not useful in isolation - they are low level
+ /// value objects created/interpreted by SourceManager. We assume AST
+ /// clients will have a pointer to the respective SourceManager.
+ virtual SourceRange getSourceRange() const = 0;
+ SourceLocation getLocStart() const { return getSourceRange().getBegin(); }
+ SourceLocation getLocEnd() const { return getSourceRange().getEnd(); }
+
+ // global temp stats (until we have a per-module visitor)
+ static void addStmtClass(const StmtClass s);
+ static bool CollectingStats(bool enable=false);
+ static void PrintStats();
+
+ /// dump - This does a local dump of the specified AST fragment. It dumps the
+ /// specified node and a few nodes underneath it, but not the whole subtree.
+ /// This is useful in a debugger.
+ void dump() const;
+ void dump(SourceManager &SM) const;
+
+ /// dumpAll - This does a dump of the specified AST fragment and all subtrees.
+ void dumpAll() const;
+ void dumpAll(SourceManager &SM) const;
+
+ /// 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 = 0,
+ const PrintingPolicy &Policy = PrintingPolicy(),
+ unsigned Indentation = 0) const {
+ printPretty(OS, *(ASTContext*)0, Helper, Policy, Indentation);
+ }
+ void printPretty(llvm::raw_ostream &OS, ASTContext& Context,
+ PrinterHelper *Helper = 0,
+ const PrintingPolicy &Policy = PrintingPolicy(),
+ unsigned Indentation = 0) const;
+
+ /// viewAST - Visualize an AST rooted at this Stmt* using GraphViz. Only
+ /// works on systems with GraphViz (Mac OS X) or dot+gv installed.
+ void viewAST() const;
+
+ // Implement isa<T> support.
+ static bool classof(const Stmt *) { return true; }
+
+ /// hasImplicitControlFlow - Some statements (e.g. short circuited operations)
+ /// contain implicit control-flow in the order their subexpressions
+ /// are evaluated. This predicate returns true if this statement has
+ /// such implicit control-flow. Such statements are also specially handled
+ /// within CFGs.
+ bool hasImplicitControlFlow() const;
+
+ /// Child Iterators: All subclasses must implement child_begin and child_end
+ /// to permit easy iteration over the substatements/subexpessions of an
+ /// AST node. This permits easy iteration over all nodes in the AST.
+ typedef StmtIterator child_iterator;
+ typedef ConstStmtIterator const_child_iterator;
+
+ virtual child_iterator child_begin() = 0;
+ virtual child_iterator child_end() = 0;
+
+ const_child_iterator child_begin() const {
+ return const_child_iterator(const_cast<Stmt*>(this)->child_begin());
+ }
+
+ const_child_iterator child_end() const {
+ return const_child_iterator(const_cast<Stmt*>(this)->child_end());
+ }
+};
+
+/// DeclStmt - Adaptor class for mixing declarations with statements and
+/// expressions. For example, CompoundStmt mixes statements, expressions
+/// and declarations (variables, types). Another example is ForStmt, where
+/// the first statement can be an expression or a declaration.
+///
+class DeclStmt : public Stmt {
+ DeclGroupRef DG;
+ SourceLocation StartLoc, EndLoc;
+public:
+ DeclStmt(DeclGroupRef dg, SourceLocation startLoc,
+ SourceLocation endLoc) : Stmt(DeclStmtClass), DG(dg),
+ StartLoc(startLoc), EndLoc(endLoc) {}
+
+ /// \brief Build an empty declaration statement.
+ explicit DeclStmt(EmptyShell Empty) : Stmt(DeclStmtClass, Empty) { }
+
+ virtual void Destroy(ASTContext& Ctx);
+
+ /// isSingleDecl - This method returns true if this DeclStmt refers
+ /// to a single Decl.
+ bool isSingleDecl() const {
+ return DG.isSingleDecl();
+ }
+
+ const Decl *getSingleDecl() const { return DG.getSingleDecl(); }
+ Decl *getSingleDecl() { return DG.getSingleDecl(); }
+
+ const DeclGroupRef getDeclGroup() const { return DG; }
+ DeclGroupRef getDeclGroup() { return DG; }
+ void setDeclGroup(DeclGroupRef DGR) { DG = DGR; }
+
+ SourceLocation getStartLoc() const { return StartLoc; }
+ void setStartLoc(SourceLocation L) { StartLoc = L; }
+ SourceLocation getEndLoc() const { return EndLoc; }
+ void setEndLoc(SourceLocation L) { EndLoc = L; }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(StartLoc, EndLoc);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == DeclStmtClass;
+ }
+ static bool classof(const DeclStmt *) { return true; }
+
+ // Iterators over subexpressions.
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+
+ typedef DeclGroupRef::iterator decl_iterator;
+ typedef DeclGroupRef::const_iterator const_decl_iterator;
+
+ decl_iterator decl_begin() { return DG.begin(); }
+ decl_iterator decl_end() { return DG.end(); }
+ const_decl_iterator decl_begin() const { return DG.begin(); }
+ const_decl_iterator decl_end() const { return DG.end(); }
+};
+
+/// NullStmt - This is the null statement ";": C99 6.8.3p3.
+///
+class NullStmt : public Stmt {
+ SourceLocation SemiLoc;
+public:
+ NullStmt(SourceLocation L) : Stmt(NullStmtClass), SemiLoc(L) {}
+
+ /// \brief Build an empty null statement.
+ explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty) { }
+
+ NullStmt* Clone(ASTContext &C) const;
+
+ SourceLocation getSemiLoc() const { return SemiLoc; }
+ void setSemiLoc(SourceLocation L) { SemiLoc = L; }
+
+ virtual SourceRange getSourceRange() const { return SourceRange(SemiLoc); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == NullStmtClass;
+ }
+ static bool classof(const NullStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// CompoundStmt - This represents a group of statements like { stmt stmt }.
+///
+class CompoundStmt : public Stmt {
+ Stmt** Body;
+ unsigned NumStmts;
+ SourceLocation LBracLoc, RBracLoc;
+public:
+ CompoundStmt(ASTContext& C, Stmt **StmtStart, unsigned numStmts,
+ SourceLocation LB, SourceLocation RB)
+ : Stmt(CompoundStmtClass), NumStmts(numStmts), LBracLoc(LB), RBracLoc(RB) {
+ if (NumStmts == 0) {
+ Body = 0;
+ return;
+ }
+
+ Body = new (C) Stmt*[NumStmts];
+ memcpy(Body, StmtStart, numStmts * sizeof(*Body));
+ }
+
+ // \brief Build an empty compound statement.
+ explicit CompoundStmt(EmptyShell Empty)
+ : Stmt(CompoundStmtClass, Empty), Body(0), NumStmts(0) { }
+
+ void setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts);
+
+ bool body_empty() const { return NumStmts == 0; }
+ unsigned size() const { return NumStmts; }
+
+ typedef Stmt** body_iterator;
+ body_iterator body_begin() { return Body; }
+ body_iterator body_end() { return Body + NumStmts; }
+ Stmt *body_back() { return NumStmts ? Body[NumStmts-1] : 0; }
+
+ typedef Stmt* const * const_body_iterator;
+ const_body_iterator body_begin() const { return Body; }
+ const_body_iterator body_end() const { return Body + NumStmts; }
+ const Stmt *body_back() const { return NumStmts ? Body[NumStmts-1] : 0; }
+
+ typedef std::reverse_iterator<body_iterator> reverse_body_iterator;
+ reverse_body_iterator body_rbegin() {
+ return reverse_body_iterator(body_end());
+ }
+ reverse_body_iterator body_rend() {
+ return reverse_body_iterator(body_begin());
+ }
+
+ typedef std::reverse_iterator<const_body_iterator>
+ const_reverse_body_iterator;
+
+ const_reverse_body_iterator body_rbegin() const {
+ return const_reverse_body_iterator(body_end());
+ }
+
+ const_reverse_body_iterator body_rend() const {
+ return const_reverse_body_iterator(body_begin());
+ }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(LBracLoc, RBracLoc);
+ }
+
+ SourceLocation getLBracLoc() const { return LBracLoc; }
+ void setLBracLoc(SourceLocation L) { LBracLoc = L; }
+ SourceLocation getRBracLoc() const { return RBracLoc; }
+ void setRBracLoc(SourceLocation L) { RBracLoc = L; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CompoundStmtClass;
+ }
+ static bool classof(const CompoundStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+// SwitchCase is the base class for CaseStmt and DefaultStmt,
+class SwitchCase : public Stmt {
+protected:
+ // A pointer to the following CaseStmt or DefaultStmt class,
+ // used by SwitchStmt.
+ SwitchCase *NextSwitchCase;
+
+ SwitchCase(StmtClass SC) : Stmt(SC), NextSwitchCase(0) {}
+
+public:
+ const SwitchCase *getNextSwitchCase() const { return NextSwitchCase; }
+
+ SwitchCase *getNextSwitchCase() { return NextSwitchCase; }
+
+ void setNextSwitchCase(SwitchCase *SC) { NextSwitchCase = SC; }
+
+ Stmt *getSubStmt() { return v_getSubStmt(); }
+
+ virtual SourceRange getSourceRange() const { return SourceRange(); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CaseStmtClass ||
+ T->getStmtClass() == DefaultStmtClass;
+ }
+ static bool classof(const SwitchCase *) { return true; }
+protected:
+ virtual Stmt* v_getSubStmt() = 0;
+};
+
+class CaseStmt : public SwitchCase {
+ enum { SUBSTMT, LHS, RHS, END_EXPR };
+ Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for
+ // GNU "case 1 ... 4" extension
+ SourceLocation CaseLoc;
+ SourceLocation EllipsisLoc;
+ SourceLocation ColonLoc;
+
+ virtual Stmt* v_getSubStmt() { return getSubStmt(); }
+public:
+ CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc,
+ SourceLocation ellipsisLoc, SourceLocation colonLoc)
+ : SwitchCase(CaseStmtClass) {
+ SubExprs[SUBSTMT] = 0;
+ SubExprs[LHS] = reinterpret_cast<Stmt*>(lhs);
+ SubExprs[RHS] = reinterpret_cast<Stmt*>(rhs);
+ CaseLoc = caseLoc;
+ EllipsisLoc = ellipsisLoc;
+ ColonLoc = colonLoc;
+ }
+
+ /// \brief Build an empty switch case statement.
+ explicit CaseStmt(EmptyShell Empty) : SwitchCase(CaseStmtClass) { }
+
+ SourceLocation getCaseLoc() const { return CaseLoc; }
+ void setCaseLoc(SourceLocation L) { CaseLoc = L; }
+ SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
+ void setEllipsisLoc(SourceLocation L) { EllipsisLoc = L; }
+ SourceLocation getColonLoc() const { return ColonLoc; }
+ void setColonLoc(SourceLocation L) { ColonLoc = L; }
+
+ Expr *getLHS() { return reinterpret_cast<Expr*>(SubExprs[LHS]); }
+ Expr *getRHS() { return reinterpret_cast<Expr*>(SubExprs[RHS]); }
+ Stmt *getSubStmt() { return SubExprs[SUBSTMT]; }
+
+ const Expr *getLHS() const {
+ return reinterpret_cast<const Expr*>(SubExprs[LHS]);
+ }
+ const Expr *getRHS() const {
+ return reinterpret_cast<const Expr*>(SubExprs[RHS]);
+ }
+ const Stmt *getSubStmt() const { return SubExprs[SUBSTMT]; }
+
+ void setSubStmt(Stmt *S) { SubExprs[SUBSTMT] = S; }
+ void setLHS(Expr *Val) { SubExprs[LHS] = reinterpret_cast<Stmt*>(Val); }
+ void setRHS(Expr *Val) { SubExprs[RHS] = reinterpret_cast<Stmt*>(Val); }
+
+
+ virtual SourceRange getSourceRange() const {
+ // Handle deeply nested case statements with iteration instead of recursion.
+ const CaseStmt *CS = this;
+ while (const CaseStmt *CS2 = dyn_cast<CaseStmt>(CS->getSubStmt()))
+ CS = CS2;
+
+ return SourceRange(CaseLoc, CS->getSubStmt()->getLocEnd());
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CaseStmtClass;
+ }
+ static bool classof(const CaseStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+class DefaultStmt : public SwitchCase {
+ Stmt* SubStmt;
+ SourceLocation DefaultLoc;
+ SourceLocation ColonLoc;
+ virtual Stmt* v_getSubStmt() { return getSubStmt(); }
+public:
+ DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) :
+ SwitchCase(DefaultStmtClass), SubStmt(substmt), DefaultLoc(DL),
+ ColonLoc(CL) {}
+
+ /// \brief Build an empty default statement.
+ explicit DefaultStmt(EmptyShell) : SwitchCase(DefaultStmtClass) { }
+
+ Stmt *getSubStmt() { return SubStmt; }
+ const Stmt *getSubStmt() const { return SubStmt; }
+ void setSubStmt(Stmt *S) { SubStmt = S; }
+
+ SourceLocation getDefaultLoc() const { return DefaultLoc; }
+ void setDefaultLoc(SourceLocation L) { DefaultLoc = L; }
+ SourceLocation getColonLoc() const { return ColonLoc; }
+ void setColonLoc(SourceLocation L) { ColonLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(DefaultLoc, SubStmt->getLocEnd());
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == DefaultStmtClass;
+ }
+ static bool classof(const DefaultStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+class LabelStmt : public Stmt {
+ IdentifierInfo *Label;
+ Stmt *SubStmt;
+ SourceLocation IdentLoc;
+public:
+ LabelStmt(SourceLocation IL, IdentifierInfo *label, Stmt *substmt)
+ : Stmt(LabelStmtClass), Label(label),
+ SubStmt(substmt), IdentLoc(IL) {}
+
+ // \brief Build an empty label statement.
+ explicit LabelStmt(EmptyShell Empty) : Stmt(LabelStmtClass, Empty) { }
+
+ SourceLocation getIdentLoc() const { return IdentLoc; }
+ IdentifierInfo *getID() const { return Label; }
+ void setID(IdentifierInfo *II) { Label = II; }
+ const char *getName() const;
+ Stmt *getSubStmt() { return SubStmt; }
+ const Stmt *getSubStmt() const { return SubStmt; }
+ void setIdentLoc(SourceLocation L) { IdentLoc = L; }
+ void setSubStmt(Stmt *SS) { SubStmt = SS; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(IdentLoc, SubStmt->getLocEnd());
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == LabelStmtClass;
+ }
+ static bool classof(const LabelStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+
+/// IfStmt - This represents an if/then/else.
+///
+class IfStmt : public Stmt {
+ enum { COND, THEN, ELSE, END_EXPR };
+ Stmt* SubExprs[END_EXPR];
+ SourceLocation IfLoc;
+ SourceLocation ElseLoc;
+public:
+ IfStmt(SourceLocation IL, Expr *cond, Stmt *then,
+ SourceLocation EL = SourceLocation(), Stmt *elsev = 0)
+ : Stmt(IfStmtClass) {
+ SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
+ SubExprs[THEN] = then;
+ SubExprs[ELSE] = elsev;
+ IfLoc = IL;
+ ElseLoc = EL;
+ }
+
+ /// \brief Build an empty if/then/else statement
+ explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { }
+
+ const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
+ void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
+ const Stmt *getThen() const { return SubExprs[THEN]; }
+ void setThen(Stmt *S) { SubExprs[THEN] = S; }
+ const Stmt *getElse() const { return SubExprs[ELSE]; }
+ void setElse(Stmt *S) { SubExprs[ELSE] = S; }
+
+ Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
+ Stmt *getThen() { return SubExprs[THEN]; }
+ Stmt *getElse() { return SubExprs[ELSE]; }
+
+ SourceLocation getIfLoc() const { return IfLoc; }
+ void setIfLoc(SourceLocation L) { IfLoc = L; }
+ SourceLocation getElseLoc() const { return ElseLoc; }
+ void setElseLoc(SourceLocation L) { ElseLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ if (SubExprs[ELSE])
+ return SourceRange(IfLoc, SubExprs[ELSE]->getLocEnd());
+ else
+ return SourceRange(IfLoc, SubExprs[THEN]->getLocEnd());
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == IfStmtClass;
+ }
+ static bool classof(const IfStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// SwitchStmt - This represents a 'switch' stmt.
+///
+class SwitchStmt : public Stmt {
+ enum { COND, BODY, END_EXPR };
+ Stmt* SubExprs[END_EXPR];
+ // This points to a linked list of case and default statements.
+ SwitchCase *FirstCase;
+ SourceLocation SwitchLoc;
+public:
+ SwitchStmt(Expr *cond) : Stmt(SwitchStmtClass), FirstCase(0) {
+ SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
+ SubExprs[BODY] = NULL;
+ }
+
+ /// \brief Build a empty switch statement.
+ explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { }
+
+ const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
+ const Stmt *getBody() const { return SubExprs[BODY]; }
+ const SwitchCase *getSwitchCaseList() const { return FirstCase; }
+
+ Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]);}
+ void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
+ Stmt *getBody() { return SubExprs[BODY]; }
+ void setBody(Stmt *S) { SubExprs[BODY] = S; }
+ SwitchCase *getSwitchCaseList() { return FirstCase; }
+ void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; }
+
+ SourceLocation getSwitchLoc() const { return SwitchLoc; }
+ void setSwitchLoc(SourceLocation L) { SwitchLoc = L; }
+
+ void setBody(Stmt *S, SourceLocation SL) {
+ SubExprs[BODY] = S;
+ SwitchLoc = SL;
+ }
+ void addSwitchCase(SwitchCase *SC) {
+ assert(!SC->getNextSwitchCase() && "case/default already added to a switch");
+ SC->setNextSwitchCase(FirstCase);
+ FirstCase = SC;
+ }
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(SwitchLoc, SubExprs[BODY]->getLocEnd());
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == SwitchStmtClass;
+ }
+ static bool classof(const SwitchStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+
+/// WhileStmt - This represents a 'while' stmt.
+///
+class WhileStmt : public Stmt {
+ enum { COND, BODY, END_EXPR };
+ Stmt* SubExprs[END_EXPR];
+ SourceLocation WhileLoc;
+public:
+ WhileStmt(Expr *cond, Stmt *body, SourceLocation WL) : Stmt(WhileStmtClass) {
+ SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
+ SubExprs[BODY] = body;
+ WhileLoc = WL;
+ }
+
+ /// \brief Build an empty while statement.
+ explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) { }
+
+ Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
+ const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
+ void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); }
+ Stmt *getBody() { return SubExprs[BODY]; }
+ const Stmt *getBody() const { return SubExprs[BODY]; }
+ void setBody(Stmt *S) { SubExprs[BODY] = S; }
+
+ SourceLocation getWhileLoc() const { return WhileLoc; }
+ void setWhileLoc(SourceLocation L) { WhileLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(WhileLoc, SubExprs[BODY]->getLocEnd());
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == WhileStmtClass;
+ }
+ static bool classof(const WhileStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// DoStmt - This represents a 'do/while' stmt.
+///
+class DoStmt : public Stmt {
+ enum { COND, BODY, END_EXPR };
+ Stmt* SubExprs[END_EXPR];
+ SourceLocation DoLoc;
+ SourceLocation WhileLoc;
+
+public:
+ DoStmt(Stmt *body, Expr *cond, SourceLocation DL, SourceLocation WL)
+ : Stmt(DoStmtClass), DoLoc(DL), WhileLoc(WL) {
+ SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
+ SubExprs[BODY] = body;
+ DoLoc = DL;
+ WhileLoc = WL;
+ }
+
+ /// \brief Build an empty do-while statement.
+ explicit DoStmt(EmptyShell Empty) : Stmt(DoStmtClass, Empty) { }
+
+ Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
+ const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
+ void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); }
+ Stmt *getBody() { return SubExprs[BODY]; }
+ const Stmt *getBody() const { return SubExprs[BODY]; }
+ void setBody(Stmt *S) { SubExprs[BODY] = S; }
+
+ SourceLocation getDoLoc() const { return DoLoc; }
+ void setDoLoc(SourceLocation L) { DoLoc = L; }
+ SourceLocation getWhileLoc() const { return WhileLoc; }
+ void setWhileLoc(SourceLocation L) { WhileLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(DoLoc, SubExprs[BODY]->getLocEnd());
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == DoStmtClass;
+ }
+ static bool classof(const DoStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+
+/// ForStmt - This represents a 'for (init;cond;inc)' stmt. Note that any of
+/// the init/cond/inc parts of the ForStmt will be null if they were not
+/// specified in the source.
+///
+class ForStmt : public Stmt {
+ enum { INIT, COND, INC, BODY, END_EXPR };
+ Stmt* SubExprs[END_EXPR]; // SubExprs[INIT] is an expression or declstmt.
+ SourceLocation ForLoc;
+ SourceLocation LParenLoc, RParenLoc;
+
+public:
+ ForStmt(Stmt *Init, Expr *Cond, Expr *Inc, Stmt *Body, SourceLocation FL,
+ SourceLocation LP, SourceLocation RP)
+ : Stmt(ForStmtClass) {
+ SubExprs[INIT] = Init;
+ SubExprs[COND] = reinterpret_cast<Stmt*>(Cond);
+ SubExprs[INC] = reinterpret_cast<Stmt*>(Inc);
+ SubExprs[BODY] = Body;
+ ForLoc = FL;
+ LParenLoc = LP;
+ RParenLoc = RP;
+ }
+
+ /// \brief Build an empty for statement.
+ explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { }
+
+ Stmt *getInit() { return SubExprs[INIT]; }
+ Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
+ Expr *getInc() { return reinterpret_cast<Expr*>(SubExprs[INC]); }
+ Stmt *getBody() { return SubExprs[BODY]; }
+
+ const Stmt *getInit() const { return SubExprs[INIT]; }
+ const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
+ const Expr *getInc() const { return reinterpret_cast<Expr*>(SubExprs[INC]); }
+ const Stmt *getBody() const { return SubExprs[BODY]; }
+
+ void setInit(Stmt *S) { SubExprs[INIT] = S; }
+ void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); }
+ void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); }
+ void setBody(Stmt *S) { SubExprs[BODY] = S; }
+
+ SourceLocation getForLoc() const { return ForLoc; }
+ void setForLoc(SourceLocation L) { ForLoc = L; }
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+ void setLParenLoc(SourceLocation L) { LParenLoc = L; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ForStmtClass;
+ }
+ static bool classof(const ForStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// GotoStmt - This represents a direct goto.
+///
+class GotoStmt : public Stmt {
+ LabelStmt *Label;
+ SourceLocation GotoLoc;
+ SourceLocation LabelLoc;
+public:
+ GotoStmt(LabelStmt *label, SourceLocation GL, SourceLocation LL)
+ : Stmt(GotoStmtClass), Label(label), GotoLoc(GL), LabelLoc(LL) {}
+
+ /// \brief Build an empty goto statement.
+ explicit GotoStmt(EmptyShell Empty) : Stmt(GotoStmtClass, Empty) { }
+
+ LabelStmt *getLabel() const { return Label; }
+ void setLabel(LabelStmt *S) { Label = S; }
+
+ SourceLocation getGotoLoc() const { return GotoLoc; }
+ void setGotoLoc(SourceLocation L) { GotoLoc = L; }
+ SourceLocation getLabelLoc() const { return LabelLoc; }
+ void setLabelLoc(SourceLocation L) { LabelLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(GotoLoc, LabelLoc);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == GotoStmtClass;
+ }
+ static bool classof(const GotoStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// IndirectGotoStmt - This represents an indirect goto.
+///
+class IndirectGotoStmt : public Stmt {
+ SourceLocation GotoLoc;
+ SourceLocation StarLoc;
+ Stmt *Target;
+public:
+ IndirectGotoStmt(SourceLocation gotoLoc, SourceLocation starLoc,
+ Expr *target)
+ : Stmt(IndirectGotoStmtClass), GotoLoc(gotoLoc), StarLoc(starLoc),
+ Target((Stmt*)target) {}
+
+ /// \brief Build an empty indirect goto statement.
+ explicit IndirectGotoStmt(EmptyShell Empty)
+ : Stmt(IndirectGotoStmtClass, Empty) { }
+
+ void setGotoLoc(SourceLocation L) { GotoLoc = L; }
+ SourceLocation getGotoLoc() const { return GotoLoc; }
+ void setStarLoc(SourceLocation L) { StarLoc = L; }
+ SourceLocation getStarLoc() const { return StarLoc; }
+
+ Expr *getTarget();
+ const Expr *getTarget() const;
+ void setTarget(Expr *E) { Target = reinterpret_cast<Stmt*>(E); }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(GotoLoc, Target->getLocEnd());
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == IndirectGotoStmtClass;
+ }
+ static bool classof(const IndirectGotoStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+
+/// ContinueStmt - This represents a continue.
+///
+class ContinueStmt : public Stmt {
+ SourceLocation ContinueLoc;
+public:
+ ContinueStmt(SourceLocation CL) : Stmt(ContinueStmtClass), ContinueLoc(CL) {}
+
+ /// \brief Build an empty continue statement.
+ explicit ContinueStmt(EmptyShell Empty) : Stmt(ContinueStmtClass, Empty) { }
+
+ SourceLocation getContinueLoc() const { return ContinueLoc; }
+ void setContinueLoc(SourceLocation L) { ContinueLoc = L; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(ContinueLoc);
+ }
+
+ ContinueStmt* Clone(ASTContext &C) const;
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ContinueStmtClass;
+ }
+ static bool classof(const ContinueStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// BreakStmt - This represents a break.
+///
+class BreakStmt : public Stmt {
+ SourceLocation BreakLoc;
+public:
+ BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass), BreakLoc(BL) {}
+
+ /// \brief Build an empty break statement.
+ explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) { }
+
+ SourceLocation getBreakLoc() const { return BreakLoc; }
+ void setBreakLoc(SourceLocation L) { BreakLoc = L; }
+
+ virtual SourceRange getSourceRange() const { return SourceRange(BreakLoc); }
+
+ BreakStmt* Clone(ASTContext &C) const;
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == BreakStmtClass;
+ }
+ static bool classof(const BreakStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+
+/// ReturnStmt - This represents a return, optionally of an expression:
+/// return;
+/// return 4;
+///
+/// Note that GCC allows return with no argument in a function declared to
+/// return a value, and it allows returning a value in functions declared to
+/// return void. We explicitly model this in the AST, which means you can't
+/// depend on the return type of the function and the presence of an argument.
+///
+class ReturnStmt : public Stmt {
+ Stmt *RetExpr;
+ SourceLocation RetLoc;
+public:
+ ReturnStmt(SourceLocation RL, Expr *E = 0) : Stmt(ReturnStmtClass),
+ RetExpr((Stmt*) E), RetLoc(RL) {}
+
+ /// \brief Build an empty return expression.
+ explicit ReturnStmt(EmptyShell Empty) : Stmt(ReturnStmtClass, Empty) { }
+
+ const Expr *getRetValue() const;
+ Expr *getRetValue();
+ void setRetValue(Expr *E) { RetExpr = reinterpret_cast<Stmt*>(E); }
+
+ SourceLocation getReturnLoc() const { return RetLoc; }
+ void setReturnLoc(SourceLocation L) { RetLoc = L; }
+
+ virtual SourceRange getSourceRange() const;
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ReturnStmtClass;
+ }
+ static bool classof(const ReturnStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// AsmStmt - This represents a GNU inline-assembly statement extension.
+///
+class AsmStmt : public Stmt {
+ SourceLocation AsmLoc, RParenLoc;
+ StringLiteral *AsmStr;
+
+ bool IsSimple;
+ bool IsVolatile;
+
+ unsigned NumOutputs;
+ unsigned NumInputs;
+
+ llvm::SmallVector<std::string, 4> Names;
+ llvm::SmallVector<StringLiteral*, 4> Constraints;
+ llvm::SmallVector<Stmt*, 4> Exprs;
+
+ llvm::SmallVector<StringLiteral*, 4> Clobbers;
+public:
+ AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile,
+ unsigned numoutputs, unsigned numinputs,
+ std::string *names, StringLiteral **constraints,
+ Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
+ StringLiteral **clobbers, SourceLocation rparenloc);
+
+ /// \brief Build an empty inline-assembly statement.
+ explicit AsmStmt(EmptyShell Empty) : Stmt(AsmStmtClass, Empty) { }
+
+ SourceLocation getAsmLoc() const { return AsmLoc; }
+ void setAsmLoc(SourceLocation L) { AsmLoc = L; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ bool isVolatile() const { return IsVolatile; }
+ void setVolatile(bool V) { IsVolatile = V; }
+ bool isSimple() const { return IsSimple; }
+ void setSimple(bool V) { IsSimple = false; }
+
+ //===--- Asm String Analysis ---===//
+
+ const StringLiteral *getAsmString() const { return AsmStr; }
+ StringLiteral *getAsmString() { return AsmStr; }
+ void setAsmString(StringLiteral *E) { AsmStr = E; }
+
+ /// AsmStringPiece - this is part of a decomposed asm string specification
+ /// (for use with the AnalyzeAsmString function below). An asm string is
+ /// considered to be a concatenation of these parts.
+ class AsmStringPiece {
+ public:
+ enum Kind {
+ String, // String in .ll asm string form, "$" -> "$$" and "%%" -> "%".
+ Operand // Operand reference, with optional modifier %c4.
+ };
+ private:
+ Kind MyKind;
+ std::string Str;
+ unsigned OperandNo;
+ public:
+ AsmStringPiece(const std::string &S) : MyKind(String), Str(S) {}
+ AsmStringPiece(unsigned OpNo, char Modifier)
+ : MyKind(Operand), Str(), OperandNo(OpNo) {
+ Str += Modifier;
+ }
+
+ bool isString() const { return MyKind == String; }
+ bool isOperand() const { return MyKind == Operand; }
+
+ const std::string &getString() const {
+ assert(isString());
+ return Str;
+ }
+
+ unsigned getOperandNo() const {
+ assert(isOperand());
+ return OperandNo;
+ }
+
+ /// getModifier - Get the modifier for this operand, if present. This
+ /// returns '\0' if there was no modifier.
+ char getModifier() const {
+ assert(isOperand());
+ return Str[0];
+ }
+ };
+
+ /// 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. 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,
+ ASTContext &C, unsigned &DiagOffs) const;
+
+
+ //===--- Output operands ---===//
+
+ unsigned getNumOutputs() const { return NumOutputs; }
+
+ const std::string &getOutputName(unsigned i) const {
+ return Names[i];
+ }
+
+ /// getOutputConstraint - Return the constraint string for the specified
+ /// output operand. All output constraints are known to be non-empty (either
+ /// '=' or '+').
+ std::string getOutputConstraint(unsigned i) const;
+
+ const StringLiteral *getOutputConstraintLiteral(unsigned i) const {
+ return Constraints[i];
+ }
+ StringLiteral *getOutputConstraintLiteral(unsigned i) {
+ return Constraints[i];
+ }
+
+
+ Expr *getOutputExpr(unsigned i);
+
+ const Expr *getOutputExpr(unsigned i) const {
+ return const_cast<AsmStmt*>(this)->getOutputExpr(i);
+ }
+
+ /// isOutputPlusConstraint - Return true if the specified output constraint
+ /// is a "+" constraint (which is both an input and an output) or false if it
+ /// is an "=" constraint (just an output).
+ bool isOutputPlusConstraint(unsigned i) const {
+ return getOutputConstraint(i)[0] == '+';
+ }
+
+ /// getNumPlusOperands - Return the number of output operands that have a "+"
+ /// constraint.
+ unsigned getNumPlusOperands() const;
+
+ //===--- Input operands ---===//
+
+ unsigned getNumInputs() const { return NumInputs; }
+
+ const std::string &getInputName(unsigned i) const {
+ return Names[i + NumOutputs];
+ }
+
+ /// getInputConstraint - Return the specified input constraint. Unlike output
+ /// constraints, these can be empty.
+ std::string getInputConstraint(unsigned i) const;
+
+ const StringLiteral *getInputConstraintLiteral(unsigned i) const {
+ return Constraints[i + NumOutputs];
+ }
+ StringLiteral *getInputConstraintLiteral(unsigned i) {
+ return Constraints[i + NumOutputs];
+ }
+
+
+ Expr *getInputExpr(unsigned i);
+
+ const Expr *getInputExpr(unsigned i) const {
+ return const_cast<AsmStmt*>(this)->getInputExpr(i);
+ }
+
+ void setOutputsAndInputs(unsigned NumOutputs,
+ unsigned NumInputs,
+ const std::string *Names,
+ StringLiteral **Constraints,
+ Stmt **Exprs);
+
+ //===--- Other ---===//
+
+ /// 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(const std::string &SymbolicName) const;
+
+
+
+ unsigned getNumClobbers() const { return Clobbers.size(); }
+ StringLiteral *getClobber(unsigned i) { return Clobbers[i]; }
+ const StringLiteral *getClobber(unsigned i) const { return Clobbers[i]; }
+ void setClobbers(StringLiteral **Clobbers, unsigned NumClobbers);
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(AsmLoc, RParenLoc);
+ }
+
+ static bool classof(const Stmt *T) {return T->getStmtClass() == AsmStmtClass;}
+ static bool classof(const AsmStmt *) { return true; }
+
+ // Input expr iterators.
+
+ typedef ExprIterator inputs_iterator;
+ typedef ConstExprIterator const_inputs_iterator;
+
+ inputs_iterator begin_inputs() {
+ return Exprs.data() + NumOutputs;
+ }
+
+ inputs_iterator end_inputs() {
+ return Exprs.data() + NumOutputs + NumInputs;
+ }
+
+ const_inputs_iterator begin_inputs() const {
+ return Exprs.data() + NumOutputs;
+ }
+
+ const_inputs_iterator end_inputs() const {
+ return Exprs.data() + NumOutputs + NumInputs;
+ }
+
+ // Output expr iterators.
+
+ typedef ExprIterator outputs_iterator;
+ typedef ConstExprIterator const_outputs_iterator;
+
+ outputs_iterator begin_outputs() {
+ return Exprs.data();
+ }
+ outputs_iterator end_outputs() {
+ return Exprs.data() + NumOutputs;
+ }
+
+ const_outputs_iterator begin_outputs() const {
+ return Exprs.data();
+ }
+ const_outputs_iterator end_outputs() const {
+ return Exprs.data() + NumOutputs;
+ }
+
+ // Input name iterator.
+
+ const std::string *begin_output_names() const {
+ return &Names[0];
+ }
+
+ const std::string *end_output_names() const {
+ return &Names[0] + NumOutputs;
+ }
+
+ // Child iterators
+
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h
new file mode 100644
index 000000000000..2338f1457a84
--- /dev/null
+++ b/include/clang/AST/StmtCXX.h
@@ -0,0 +1,100 @@
+//===--- StmtCXX.h - Classes for representing C++ statements ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the C++ statement AST node classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_STMTCXX_H
+#define LLVM_CLANG_AST_STMTCXX_H
+
+#include "clang/AST/Stmt.h"
+
+namespace clang {
+
+class VarDecl;
+
+/// CXXCatchStmt - This represents a C++ catch block.
+///
+class CXXCatchStmt : public Stmt {
+ SourceLocation CatchLoc;
+ /// The exception-declaration of the type.
+ VarDecl *ExceptionDecl;
+ /// The handler block.
+ Stmt *HandlerBlock;
+
+public:
+ CXXCatchStmt(SourceLocation catchLoc, VarDecl *exDecl, Stmt *handlerBlock)
+ : Stmt(CXXCatchStmtClass), CatchLoc(catchLoc), ExceptionDecl(exDecl),
+ HandlerBlock(handlerBlock) {}
+
+ virtual void Destroy(ASTContext& Ctx);
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(CatchLoc, HandlerBlock->getLocEnd());
+ }
+
+ SourceLocation getCatchLoc() const { return CatchLoc; }
+ VarDecl *getExceptionDecl() { return ExceptionDecl; }
+ QualType getCaughtType();
+ Stmt *getHandlerBlock() { return HandlerBlock; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXCatchStmtClass;
+ }
+ static bool classof(const CXXCatchStmt *) { return true; }
+
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// CXXTryStmt - A C++ try block, including all handlers.
+///
+class CXXTryStmt : public Stmt {
+ SourceLocation TryLoc;
+ // First place is the guarded CompoundStatement. Subsequent are the handlers.
+ // More than three handlers should be rare.
+ llvm::SmallVector<Stmt*, 4> Stmts;
+
+public:
+ CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
+ Stmt **handlers, unsigned numHandlers);
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(TryLoc, Stmts.back()->getLocEnd());
+ }
+
+ SourceLocation getTryLoc() const { return TryLoc; }
+
+ CompoundStmt *getTryBlock() { return llvm::cast<CompoundStmt>(Stmts[0]); }
+ const CompoundStmt *getTryBlock() const {
+ return llvm::cast<CompoundStmt>(Stmts[0]);
+ }
+
+ unsigned getNumHandlers() const { return Stmts.size() - 1; }
+ CXXCatchStmt *getHandler(unsigned i) {
+ return llvm::cast<CXXCatchStmt>(Stmts[i + 1]);
+ }
+ const CXXCatchStmt *getHandler(unsigned i) const {
+ return llvm::cast<CXXCatchStmt>(Stmts[i + 1]);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXTryStmtClass;
+ }
+ static bool classof(const CXXTryStmt *) { return true; }
+
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/StmtGraphTraits.h b/include/clang/AST/StmtGraphTraits.h
new file mode 100644
index 000000000000..1bfac6a9587e
--- /dev/null
+++ b/include/clang/AST/StmtGraphTraits.h
@@ -0,0 +1,83 @@
+//===--- StmtGraphTraits.h - Graph Traits for the class Stmt ----*- 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 a template specialization of llvm::GraphTraits to
+// treat ASTs (Stmt*) as graphs
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_STMT_GRAPHTRAITS_H
+#define LLVM_CLANG_AST_STMT_GRAPHTRAITS_H
+
+#include "clang/AST/Stmt.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/DepthFirstIterator.h"
+
+namespace llvm {
+
+//template <typename T> struct GraphTraits;
+
+
+template <> struct GraphTraits<clang::Stmt*> {
+ typedef clang::Stmt NodeType;
+ typedef clang::Stmt::child_iterator ChildIteratorType;
+ typedef llvm::df_iterator<clang::Stmt*> nodes_iterator;
+
+ static NodeType* getEntryNode(clang::Stmt* S) { return S; }
+
+ static inline ChildIteratorType child_begin(NodeType* N) {
+ if (N) return N->child_begin();
+ else return ChildIteratorType();
+ }
+
+ static inline ChildIteratorType child_end(NodeType* N) {
+ if (N) return N->child_end();
+ else return ChildIteratorType();
+ }
+
+ static nodes_iterator nodes_begin(clang::Stmt* S) {
+ return df_begin(S);
+ }
+
+ static nodes_iterator nodes_end(clang::Stmt* S) {
+ return df_end(S);
+ }
+};
+
+
+template <> struct GraphTraits<const clang::Stmt*> {
+ typedef const clang::Stmt NodeType;
+ typedef clang::Stmt::const_child_iterator ChildIteratorType;
+ typedef llvm::df_iterator<const clang::Stmt*> nodes_iterator;
+
+ static NodeType* getEntryNode(const clang::Stmt* S) { return S; }
+
+ static inline ChildIteratorType child_begin(NodeType* N) {
+ if (N) return N->child_begin();
+ else return ChildIteratorType();
+ }
+
+ static inline ChildIteratorType child_end(NodeType* N) {
+ if (N) return N->child_end();
+ else return ChildIteratorType();
+ }
+
+ static nodes_iterator nodes_begin(const clang::Stmt* S) {
+ return df_begin(S);
+ }
+
+ static nodes_iterator nodes_end(const clang::Stmt* S) {
+ return df_end(S);
+ }
+};
+
+
+} // end namespace llvm
+
+#endif
diff --git a/include/clang/AST/StmtIterator.h b/include/clang/AST/StmtIterator.h
new file mode 100644
index 000000000000..35bd5ada0256
--- /dev/null
+++ b/include/clang/AST/StmtIterator.h
@@ -0,0 +1,145 @@
+//===--- StmtIterator.h - Iterators for Statements ------------------------===//
+//
+// 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 StmtIterator and ConstStmtIterator classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_STMT_ITR_H
+#define LLVM_CLANG_AST_STMT_ITR_H
+
+#include "llvm/ADT/iterator.h"
+#include "llvm/Support/DataTypes.h"
+#include <cassert>
+
+namespace clang {
+
+class Stmt;
+class Decl;
+class VariableArrayType;
+
+class StmtIteratorBase {
+protected:
+ enum { DeclMode = 0x1, SizeOfTypeVAMode = 0x2, DeclGroupMode = 0x3,
+ Flags = 0x3 };
+
+ union { Stmt** stmt; Decl* decl; Decl** DGI; };
+ uintptr_t RawVAPtr;
+ Decl** DGE;
+
+ bool inDecl() const {
+ return (RawVAPtr & Flags) == DeclMode;
+ }
+
+ bool inDeclGroup() const {
+ return (RawVAPtr & Flags) == DeclGroupMode;
+ }
+
+ bool inSizeOfTypeVA() const {
+ return (RawVAPtr & Flags) == SizeOfTypeVAMode;
+ }
+
+ bool inStmt() const {
+ return (RawVAPtr & Flags) == 0;
+ }
+
+ VariableArrayType* getVAPtr() const {
+ return reinterpret_cast<VariableArrayType*>(RawVAPtr & ~Flags);
+ }
+
+ void setVAPtr(VariableArrayType* P) {
+ assert (inDecl() || inDeclGroup() || inSizeOfTypeVA());
+ RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags);
+ }
+
+ void NextDecl(bool ImmediateAdvance = true);
+ bool HandleDecl(Decl* D);
+ void NextVA();
+
+ Stmt*& GetDeclExpr() const;
+
+ StmtIteratorBase(Stmt** s) : stmt(s), RawVAPtr(0) {}
+ StmtIteratorBase(Decl* d);
+ StmtIteratorBase(VariableArrayType* t);
+ StmtIteratorBase(Decl** dgi, Decl** dge);
+ StmtIteratorBase() : stmt(NULL), RawVAPtr(0) {}
+};
+
+
+template <typename DERIVED, typename REFERENCE>
+class StmtIteratorImpl : public StmtIteratorBase,
+ public std::iterator<std::forward_iterator_tag,
+ REFERENCE, ptrdiff_t,
+ REFERENCE, REFERENCE> {
+protected:
+ StmtIteratorImpl(const StmtIteratorBase& RHS) : StmtIteratorBase(RHS) {}
+public:
+ StmtIteratorImpl() {}
+ StmtIteratorImpl(Stmt** s) : StmtIteratorBase(s) {}
+ StmtIteratorImpl(Decl** dgi, Decl** dge) : StmtIteratorBase(dgi, dge) {}
+ StmtIteratorImpl(Decl* d) : StmtIteratorBase(d) {}
+ StmtIteratorImpl(VariableArrayType* t) : StmtIteratorBase(t) {}
+
+ DERIVED& operator++() {
+ if (inDecl() || inDeclGroup()) {
+ if (getVAPtr()) NextVA();
+ else NextDecl();
+ }
+ else if (inSizeOfTypeVA())
+ NextVA();
+ else
+ ++stmt;
+
+ return static_cast<DERIVED&>(*this);
+ }
+
+ DERIVED operator++(int) {
+ DERIVED tmp = static_cast<DERIVED&>(*this);
+ operator++();
+ return tmp;
+ }
+
+ bool operator==(const DERIVED& RHS) const {
+ return stmt == RHS.stmt && RawVAPtr == RHS.RawVAPtr;
+ }
+
+ bool operator!=(const DERIVED& RHS) const {
+ return stmt != RHS.stmt || RawVAPtr != RHS.RawVAPtr;
+ }
+
+ REFERENCE operator*() const {
+ return (REFERENCE) (inStmt() ? *stmt : GetDeclExpr());
+ }
+
+ REFERENCE operator->() const { return operator*(); }
+};
+
+struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
+ explicit StmtIterator() : StmtIteratorImpl<StmtIterator,Stmt*&>() {}
+
+ StmtIterator(Stmt** S) : StmtIteratorImpl<StmtIterator,Stmt*&>(S) {}
+ StmtIterator(Decl** dgi, Decl** dge)
+ : StmtIteratorImpl<StmtIterator,Stmt*&>(dgi, dge) {}
+
+ StmtIterator(VariableArrayType* t):StmtIteratorImpl<StmtIterator,Stmt*&>(t) {}
+ StmtIterator(Decl* D) : StmtIteratorImpl<StmtIterator,Stmt*&>(D) {}
+};
+
+struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
+ const Stmt*> {
+ explicit ConstStmtIterator() :
+ StmtIteratorImpl<ConstStmtIterator,const Stmt*>() {}
+
+ ConstStmtIterator(const StmtIterator& RHS) :
+ StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {}
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def
new file mode 100644
index 000000000000..ab6524663d63
--- /dev/null
+++ b/include/clang/AST/StmtNodes.def
@@ -0,0 +1,156 @@
+//===-- StmtNodes.def - Metadata about Stmt AST nodes -----------*- 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 AST Node info database.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FIRST_STMT
+#define FIRST_STMT(CLASS)
+#define LAST_STMT(CLASS)
+#endif
+
+#ifndef FIRST_EXPR
+#define FIRST_EXPR(CLASS)
+#define LAST_EXPR(CLASS)
+#endif
+
+#ifndef EXPR
+# define EXPR(Type, Base) STMT(Type, Base)
+#endif
+
+// Normal Statements.
+STMT(NullStmt , Stmt)
+FIRST_STMT(NullStmt)
+STMT(CompoundStmt , Stmt)
+STMT(CaseStmt , SwitchCase)
+STMT(DefaultStmt , SwitchCase)
+STMT(LabelStmt , Stmt)
+STMT(IfStmt , Stmt)
+STMT(SwitchStmt , Stmt)
+STMT(WhileStmt , Stmt)
+STMT(DoStmt , Stmt)
+STMT(ForStmt , Stmt)
+STMT(GotoStmt , Stmt)
+STMT(IndirectGotoStmt, Stmt)
+STMT(ContinueStmt , Stmt)
+STMT(BreakStmt , Stmt)
+STMT(ReturnStmt , Stmt)
+STMT(DeclStmt , Stmt)
+STMT(SwitchCase , Stmt)
+
+// GNU Stmt Extensions
+STMT(AsmStmt , Stmt)
+
+// Obj-C statements
+STMT(ObjCAtTryStmt , Stmt)
+STMT(ObjCAtCatchStmt , Stmt)
+STMT(ObjCAtFinallyStmt , Stmt)
+STMT(ObjCAtThrowStmt , Stmt)
+STMT(ObjCAtSynchronizedStmt , Stmt)
+// Obj-C2 statements
+STMT(ObjCForCollectionStmt, Stmt)
+
+// C++ statements
+STMT(CXXCatchStmt, Stmt)
+STMT(CXXTryStmt , Stmt)
+
+LAST_STMT(CXXTryStmt)
+
+// Expressions.
+EXPR(Expr , Stmt)
+FIRST_EXPR(Expr)
+EXPR(PredefinedExpr , Expr)
+EXPR(DeclRefExpr , Expr)
+EXPR(IntegerLiteral , Expr)
+EXPR(FloatingLiteral , Expr)
+EXPR(ImaginaryLiteral , Expr)
+EXPR(StringLiteral , Expr)
+EXPR(CharacterLiteral , Expr)
+EXPR(ParenExpr , Expr)
+EXPR(UnaryOperator , Expr)
+EXPR(SizeOfAlignOfExpr , Expr)
+EXPR(ArraySubscriptExpr , Expr)
+EXPR(CallExpr , Expr)
+EXPR(MemberExpr , Expr)
+EXPR(CastExpr , Expr)
+EXPR(BinaryOperator , Expr)
+EXPR(CompoundAssignOperator, BinaryOperator)
+EXPR(ConditionalOperator , Expr)
+EXPR(ImplicitCastExpr , CastExpr)
+EXPR(ExplicitCastExpr , CastExpr)
+EXPR(CStyleCastExpr , ExplicitCastExpr)
+EXPR(CompoundLiteralExpr , Expr)
+EXPR(ExtVectorElementExpr , Expr)
+EXPR(InitListExpr , Expr)
+EXPR(DesignatedInitExpr , Expr)
+EXPR(ImplicitValueInitExpr , Expr)
+EXPR(VAArgExpr , Expr)
+
+// GNU Extensions.
+EXPR(AddrLabelExpr , Expr)
+EXPR(StmtExpr , Expr)
+EXPR(TypesCompatibleExpr , Expr)
+EXPR(ChooseExpr , Expr)
+EXPR(GNUNullExpr , Expr)
+
+// C++ Expressions.
+EXPR(CXXOperatorCallExpr , CallExpr)
+EXPR(CXXMemberCallExpr , CallExpr)
+EXPR(CXXNamedCastExpr , ExplicitCastExpr)
+EXPR(CXXStaticCastExpr , CXXNamedCastExpr)
+EXPR(CXXDynamicCastExpr , CXXNamedCastExpr)
+EXPR(CXXReinterpretCastExpr , CXXNamedCastExpr)
+EXPR(CXXConstCastExpr , CXXNamedCastExpr)
+EXPR(CXXFunctionalCastExpr , ExplicitCastExpr)
+EXPR(CXXTypeidExpr , Expr)
+EXPR(CXXBoolLiteralExpr , Expr)
+EXPR(CXXNullPtrLiteralExpr , Expr)
+EXPR(CXXThisExpr , Expr)
+EXPR(CXXThrowExpr , Expr)
+EXPR(CXXDefaultArgExpr , Expr)
+EXPR(CXXZeroInitValueExpr , Expr)
+EXPR(CXXConditionDeclExpr , DeclRefExpr)
+EXPR(CXXNewExpr , Expr)
+EXPR(CXXDeleteExpr , Expr)
+EXPR(UnresolvedFunctionNameExpr , Expr)
+EXPR(UnaryTypeTraitExpr , Expr)
+EXPR(QualifiedDeclRefExpr , DeclRefExpr)
+EXPR(UnresolvedDeclRefExpr , Expr)
+EXPR(CXXConstructExpr , Expr)
+EXPR(CXXBindTemporaryExpr , Expr)
+EXPR(CXXExprWithTemporaries , Expr)
+EXPR(CXXTemporaryObjectExpr , CXXConstructExpr)
+EXPR(CXXUnresolvedConstructExpr, Expr)
+EXPR(CXXUnresolvedMemberExpr, Expr)
+
+// Obj-C Expressions.
+EXPR(ObjCStringLiteral , Expr)
+EXPR(ObjCEncodeExpr , Expr)
+EXPR(ObjCMessageExpr , Expr)
+EXPR(ObjCSelectorExpr , Expr)
+EXPR(ObjCProtocolExpr , Expr)
+EXPR(ObjCIvarRefExpr , Expr)
+EXPR(ObjCPropertyRefExpr , Expr)
+EXPR(ObjCKVCRefExpr , Expr)
+EXPR(ObjCSuperExpr , Expr)
+
+// Clang Extensions.
+EXPR(ShuffleVectorExpr , Expr)
+EXPR(BlockExpr , Expr)
+EXPR(BlockDeclRefExpr , Expr)
+
+LAST_EXPR(BlockDeclRefExpr)
+
+#undef STMT
+#undef EXPR
+#undef FIRST_STMT
+#undef LAST_STMT
+#undef FIRST_EXPR
+#undef LAST_EXPR
diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h
new file mode 100644
index 000000000000..8ae707174403
--- /dev/null
+++ b/include/clang/AST/StmtObjC.h
@@ -0,0 +1,307 @@
+//===--- StmtObjC.h - Classes for representing ObjC statements --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Objective-C statement AST node classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_STMTOBJC_H
+#define LLVM_CLANG_AST_STMTOBJC_H
+
+#include "clang/AST/Stmt.h"
+
+namespace clang {
+
+/// ObjCForCollectionStmt - This represents Objective-c's collection statement;
+/// represented as 'for (element 'in' collection-expression)' stmt.
+///
+class ObjCForCollectionStmt : public Stmt {
+ enum { ELEM, COLLECTION, BODY, END_EXPR };
+ Stmt* SubExprs[END_EXPR]; // SubExprs[ELEM] is an expression or declstmt.
+ SourceLocation ForLoc;
+ SourceLocation RParenLoc;
+public:
+ ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, Stmt *Body,
+ SourceLocation FCL, SourceLocation RPL);
+ explicit ObjCForCollectionStmt(EmptyShell Empty) :
+ Stmt(ObjCForCollectionStmtClass, Empty) { }
+
+ Stmt *getElement() { return SubExprs[ELEM]; }
+ Expr *getCollection() {
+ return reinterpret_cast<Expr*>(SubExprs[COLLECTION]);
+ }
+ Stmt *getBody() { return SubExprs[BODY]; }
+
+ const Stmt *getElement() const { return SubExprs[ELEM]; }
+ const Expr *getCollection() const {
+ return reinterpret_cast<Expr*>(SubExprs[COLLECTION]);
+ }
+ const Stmt *getBody() const { return SubExprs[BODY]; }
+
+ void setElement(Stmt *S) { SubExprs[ELEM] = S; }
+ void setCollection(Expr *E) {
+ SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(E);
+ }
+ void setBody(Stmt *S) { SubExprs[BODY] = S; }
+
+ SourceLocation getForLoc() const { return ForLoc; }
+ void setForLoc(SourceLocation Loc) { ForLoc = Loc; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCForCollectionStmtClass;
+ }
+ static bool classof(const ObjCForCollectionStmt *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ObjCAtCatchStmt - This represents objective-c's @catch statement.
+class ObjCAtCatchStmt : public Stmt {
+private:
+ enum { BODY, NEXT_CATCH, END_EXPR };
+ ParmVarDecl *ExceptionDecl;
+ Stmt *SubExprs[END_EXPR];
+ SourceLocation AtCatchLoc, RParenLoc;
+
+public:
+ ObjCAtCatchStmt(SourceLocation atCatchLoc, SourceLocation rparenloc,
+ ParmVarDecl *catchVarDecl,
+ Stmt *atCatchStmt, Stmt *atCatchList);
+
+ explicit ObjCAtCatchStmt(EmptyShell Empty) :
+ Stmt(ObjCAtCatchStmtClass, Empty) { }
+
+ const Stmt *getCatchBody() const { return SubExprs[BODY]; }
+ Stmt *getCatchBody() { return SubExprs[BODY]; }
+ void setCatchBody(Stmt *S) { SubExprs[BODY] = S; }
+
+ const ObjCAtCatchStmt *getNextCatchStmt() const {
+ return static_cast<const ObjCAtCatchStmt*>(SubExprs[NEXT_CATCH]);
+ }
+ ObjCAtCatchStmt *getNextCatchStmt() {
+ return static_cast<ObjCAtCatchStmt*>(SubExprs[NEXT_CATCH]);
+ }
+ void setNextCatchStmt(Stmt *S) { SubExprs[NEXT_CATCH] = S; }
+
+ const ParmVarDecl *getCatchParamDecl() const {
+ return ExceptionDecl;
+ }
+ ParmVarDecl *getCatchParamDecl() {
+ return ExceptionDecl;
+ }
+ void setCatchParamDecl(ParmVarDecl *D) { ExceptionDecl = D; }
+
+ SourceLocation getAtCatchLoc() const { return AtCatchLoc; }
+ void setAtCatchLoc(SourceLocation Loc) { AtCatchLoc = Loc; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(AtCatchLoc, SubExprs[BODY]->getLocEnd());
+ }
+
+ bool hasEllipsis() const { return getCatchParamDecl() == 0; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCAtCatchStmtClass;
+ }
+ static bool classof(const ObjCAtCatchStmt *) { return true; }
+
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ObjCAtFinallyStmt - This represent objective-c's @finally Statement
+class ObjCAtFinallyStmt : public Stmt {
+ Stmt *AtFinallyStmt;
+ SourceLocation AtFinallyLoc;
+public:
+ ObjCAtFinallyStmt(SourceLocation atFinallyLoc, Stmt *atFinallyStmt)
+ : Stmt(ObjCAtFinallyStmtClass),
+ AtFinallyStmt(atFinallyStmt), AtFinallyLoc(atFinallyLoc) {}
+
+ explicit ObjCAtFinallyStmt(EmptyShell Empty) :
+ Stmt(ObjCAtFinallyStmtClass, Empty) { }
+
+ const Stmt *getFinallyBody() const { return AtFinallyStmt; }
+ Stmt *getFinallyBody() { return AtFinallyStmt; }
+ void setFinallyBody(Stmt *S) { AtFinallyStmt = S; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(AtFinallyLoc, AtFinallyStmt->getLocEnd());
+ }
+
+ SourceLocation getAtFinallyLoc() const { return AtFinallyLoc; }
+ void setAtFinallyLoc(SourceLocation Loc) { AtFinallyLoc = Loc; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCAtFinallyStmtClass;
+ }
+ static bool classof(const ObjCAtFinallyStmt *) { return true; }
+
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ObjCAtTryStmt - This represent objective-c's over-all
+/// @try ... @catch ... @finally statement.
+class ObjCAtTryStmt : public Stmt {
+private:
+ enum { TRY, CATCH, FINALLY, END_EXPR };
+ Stmt* SubStmts[END_EXPR];
+
+ SourceLocation AtTryLoc;
+public:
+ ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
+ Stmt *atCatchStmt,
+ Stmt *atFinallyStmt)
+ : Stmt(ObjCAtTryStmtClass) {
+ SubStmts[TRY] = atTryStmt;
+ SubStmts[CATCH] = atCatchStmt;
+ SubStmts[FINALLY] = atFinallyStmt;
+ AtTryLoc = atTryLoc;
+ }
+ explicit ObjCAtTryStmt(EmptyShell Empty) :
+ Stmt(ObjCAtTryStmtClass, Empty) { }
+
+ SourceLocation getAtTryLoc() const { return AtTryLoc; }
+ void setAtTryLoc(SourceLocation Loc) { AtTryLoc = Loc; }
+
+ const Stmt *getTryBody() const { return SubStmts[TRY]; }
+ Stmt *getTryBody() { return SubStmts[TRY]; }
+ void setTryBody(Stmt *S) { SubStmts[TRY] = S; }
+
+ const ObjCAtCatchStmt *getCatchStmts() const {
+ return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]);
+ }
+ ObjCAtCatchStmt *getCatchStmts() {
+ return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]);
+ }
+ void setCatchStmts(Stmt *S) { SubStmts[CATCH] = S; }
+
+ const ObjCAtFinallyStmt *getFinallyStmt() const {
+ return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]);
+ }
+ ObjCAtFinallyStmt *getFinallyStmt() {
+ return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]);
+ }
+ void setFinallyStmt(Stmt *S) { SubStmts[FINALLY] = S; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(AtTryLoc, SubStmts[TRY]->getLocEnd());
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCAtTryStmtClass;
+ }
+ static bool classof(const ObjCAtTryStmt *) { return true; }
+
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ObjCAtSynchronizedStmt - This is for objective-c's @synchronized statement.
+/// Example: @synchronized (sem) {
+/// do-something;
+/// }
+///
+class ObjCAtSynchronizedStmt : public Stmt {
+private:
+ enum { SYNC_EXPR, SYNC_BODY, END_EXPR };
+ Stmt* SubStmts[END_EXPR];
+ SourceLocation AtSynchronizedLoc;
+
+public:
+ ObjCAtSynchronizedStmt(SourceLocation atSynchronizedLoc, Stmt *synchExpr,
+ Stmt *synchBody)
+ : Stmt(ObjCAtSynchronizedStmtClass) {
+ SubStmts[SYNC_EXPR] = synchExpr;
+ SubStmts[SYNC_BODY] = synchBody;
+ AtSynchronizedLoc = atSynchronizedLoc;
+ }
+ explicit ObjCAtSynchronizedStmt(EmptyShell Empty) :
+ Stmt(ObjCAtSynchronizedStmtClass, Empty) { }
+
+ SourceLocation getAtSynchronizedLoc() const { return AtSynchronizedLoc; }
+ void setAtSynchronizedLoc(SourceLocation Loc) { AtSynchronizedLoc = Loc; }
+
+ const CompoundStmt *getSynchBody() const {
+ return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]);
+ }
+ CompoundStmt *getSynchBody() {
+ return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]);
+ }
+ void setSynchBody(Stmt *S) { SubStmts[SYNC_BODY] = S; }
+
+ const Expr *getSynchExpr() const {
+ return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]);
+ }
+ Expr *getSynchExpr() {
+ return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]);
+ }
+ void setSynchExpr(Stmt *S) { SubStmts[SYNC_EXPR] = S; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(AtSynchronizedLoc, getSynchBody()->getLocEnd());
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCAtSynchronizedStmtClass;
+ }
+ static bool classof(const ObjCAtSynchronizedStmt *) { return true; }
+
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+/// ObjCAtThrowStmt - This represents objective-c's @throw statement.
+class ObjCAtThrowStmt : public Stmt {
+ Stmt *Throw;
+ SourceLocation AtThrowLoc;
+public:
+ ObjCAtThrowStmt(SourceLocation atThrowLoc, Stmt *throwExpr)
+ : Stmt(ObjCAtThrowStmtClass), Throw(throwExpr) {
+ AtThrowLoc = atThrowLoc;
+ }
+ explicit ObjCAtThrowStmt(EmptyShell Empty) :
+ Stmt(ObjCAtThrowStmtClass, Empty) { }
+
+ const Expr *getThrowExpr() const { return reinterpret_cast<Expr*>(Throw); }
+ Expr *getThrowExpr() { return reinterpret_cast<Expr*>(Throw); }
+ void setThrowExpr(Stmt *S) { Throw = S; }
+
+ SourceLocation getThrowLoc() { return AtThrowLoc; }
+ void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; }
+
+ virtual SourceRange getSourceRange() const {
+ if (Throw)
+ return SourceRange(AtThrowLoc, Throw->getLocEnd());
+ else
+ return SourceRange(AtThrowLoc);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCAtThrowStmtClass;
+ }
+ static bool classof(const ObjCAtThrowStmt *) { return true; }
+
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h
new file mode 100644
index 000000000000..4f4066ab8602
--- /dev/null
+++ b/include/clang/AST/StmtVisitor.h
@@ -0,0 +1,176 @@
+//===--- StmtVisitor.h - Visitor for Stmt subclasses ------------*- 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 StmtVisitor interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_STMTVISITOR_H
+#define LLVM_CLANG_AST_STMTVISITOR_H
+
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
+
+namespace clang {
+
+#define DISPATCH(NAME, CLASS) \
+ return static_cast<ImplClass*>(this)->Visit ## NAME(static_cast<CLASS*>(S))
+
+/// StmtVisitor - This class implements a simple visitor for Stmt subclasses.
+/// Since Expr derives from Stmt, this also includes support for visiting Exprs.
+template<typename ImplClass, typename RetTy=void>
+class StmtVisitor {
+public:
+ RetTy Visit(Stmt *S) {
+
+ // If we have a binary expr, dispatch to the subcode of the binop. A smart
+ // optimizer (e.g. LLVM) will fold this comparison into the switch stmt
+ // below.
+ if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
+ switch (BinOp->getOpcode()) {
+ default: assert(0 && "Unknown binary operator!");
+ case BinaryOperator::PtrMemD: DISPATCH(BinPtrMemD, BinaryOperator);
+ case BinaryOperator::PtrMemI: DISPATCH(BinPtrMemI, BinaryOperator);
+ case BinaryOperator::Mul: DISPATCH(BinMul, BinaryOperator);
+ case BinaryOperator::Div: DISPATCH(BinDiv, BinaryOperator);
+ case BinaryOperator::Rem: DISPATCH(BinRem, BinaryOperator);
+ case BinaryOperator::Add: DISPATCH(BinAdd, BinaryOperator);
+ case BinaryOperator::Sub: DISPATCH(BinSub, BinaryOperator);
+ case BinaryOperator::Shl: DISPATCH(BinShl, BinaryOperator);
+ case BinaryOperator::Shr: DISPATCH(BinShr, BinaryOperator);
+
+ case BinaryOperator::LT: DISPATCH(BinLT, BinaryOperator);
+ case BinaryOperator::GT: DISPATCH(BinGT, BinaryOperator);
+ case BinaryOperator::LE: DISPATCH(BinLE, BinaryOperator);
+ case BinaryOperator::GE: DISPATCH(BinGE, BinaryOperator);
+ case BinaryOperator::EQ: DISPATCH(BinEQ, BinaryOperator);
+ case BinaryOperator::NE: DISPATCH(BinNE, BinaryOperator);
+
+ case BinaryOperator::And: DISPATCH(BinAnd, BinaryOperator);
+ case BinaryOperator::Xor: DISPATCH(BinXor, BinaryOperator);
+ case BinaryOperator::Or : DISPATCH(BinOr, BinaryOperator);
+ case BinaryOperator::LAnd: DISPATCH(BinLAnd, BinaryOperator);
+ case BinaryOperator::LOr : DISPATCH(BinLOr, BinaryOperator);
+ case BinaryOperator::Assign: DISPATCH(BinAssign, BinaryOperator);
+ case BinaryOperator::MulAssign:
+ DISPATCH(BinMulAssign, CompoundAssignOperator);
+ case BinaryOperator::DivAssign:
+ DISPATCH(BinDivAssign, CompoundAssignOperator);
+ case BinaryOperator::RemAssign:
+ DISPATCH(BinRemAssign, CompoundAssignOperator);
+ case BinaryOperator::AddAssign:
+ DISPATCH(BinAddAssign, CompoundAssignOperator);
+ case BinaryOperator::SubAssign:
+ DISPATCH(BinSubAssign, CompoundAssignOperator);
+ case BinaryOperator::ShlAssign:
+ DISPATCH(BinShlAssign, CompoundAssignOperator);
+ case BinaryOperator::ShrAssign:
+ DISPATCH(BinShrAssign, CompoundAssignOperator);
+ case BinaryOperator::AndAssign:
+ DISPATCH(BinAndAssign, CompoundAssignOperator);
+ case BinaryOperator::OrAssign:
+ DISPATCH(BinOrAssign, CompoundAssignOperator);
+ case BinaryOperator::XorAssign:
+ DISPATCH(BinXorAssign, CompoundAssignOperator);
+ case BinaryOperator::Comma: DISPATCH(BinComma, BinaryOperator);
+ }
+ } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
+ switch (UnOp->getOpcode()) {
+ default: assert(0 && "Unknown unary operator!");
+ case UnaryOperator::PostInc: DISPATCH(UnaryPostInc, UnaryOperator);
+ case UnaryOperator::PostDec: DISPATCH(UnaryPostDec, UnaryOperator);
+ case UnaryOperator::PreInc: DISPATCH(UnaryPreInc, UnaryOperator);
+ case UnaryOperator::PreDec: DISPATCH(UnaryPreDec, UnaryOperator);
+ case UnaryOperator::AddrOf: DISPATCH(UnaryAddrOf, UnaryOperator);
+ case UnaryOperator::Deref: DISPATCH(UnaryDeref, UnaryOperator);
+ case UnaryOperator::Plus: DISPATCH(UnaryPlus, UnaryOperator);
+ case UnaryOperator::Minus: DISPATCH(UnaryMinus, UnaryOperator);
+ case UnaryOperator::Not: DISPATCH(UnaryNot, UnaryOperator);
+ case UnaryOperator::LNot: DISPATCH(UnaryLNot, UnaryOperator);
+ case UnaryOperator::Real: DISPATCH(UnaryReal, UnaryOperator);
+ case UnaryOperator::Imag: DISPATCH(UnaryImag, UnaryOperator);
+ case UnaryOperator::Extension: DISPATCH(UnaryExtension, UnaryOperator);
+ case UnaryOperator::OffsetOf: DISPATCH(UnaryOffsetOf, UnaryOperator);
+ }
+ }
+
+ // Top switch stmt: dispatch to VisitFooStmt for each FooStmt.
+ switch (S->getStmtClass()) {
+ default: assert(0 && "Unknown stmt kind!");
+#define STMT(CLASS, PARENT) \
+ case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS);
+#include "clang/AST/StmtNodes.def"
+ }
+ }
+
+ // If the implementation chooses not to implement a certain visit method, fall
+ // back on VisitExpr or whatever else is the superclass.
+#define STMT(CLASS, PARENT) \
+ RetTy Visit ## CLASS(CLASS *S) { DISPATCH(PARENT, PARENT); }
+#include "clang/AST/StmtNodes.def"
+
+ // If the implementation doesn't implement binary operator methods, fall back
+ // on VisitBinaryOperator.
+#define BINOP_FALLBACK(NAME) \
+ RetTy VisitBin ## NAME(BinaryOperator *S) { \
+ DISPATCH(BinaryOperator, BinaryOperator); \
+ }
+ BINOP_FALLBACK(PtrMemD) BINOP_FALLBACK(PtrMemI)
+ BINOP_FALLBACK(Mul) BINOP_FALLBACK(Div) BINOP_FALLBACK(Rem)
+ BINOP_FALLBACK(Add) BINOP_FALLBACK(Sub) BINOP_FALLBACK(Shl)
+ BINOP_FALLBACK(Shr)
+
+ BINOP_FALLBACK(LT) BINOP_FALLBACK(GT) BINOP_FALLBACK(LE)
+ BINOP_FALLBACK(GE) BINOP_FALLBACK(EQ) BINOP_FALLBACK(NE)
+ BINOP_FALLBACK(And) BINOP_FALLBACK(Xor) BINOP_FALLBACK(Or)
+ BINOP_FALLBACK(LAnd) BINOP_FALLBACK(LOr)
+
+ BINOP_FALLBACK(Assign)
+ BINOP_FALLBACK(Comma)
+#undef BINOP_FALLBACK
+
+ // If the implementation doesn't implement compound assignment operator
+ // methods, fall back on VisitCompoundAssignOperator.
+#define CAO_FALLBACK(NAME) \
+ RetTy VisitBin ## NAME(CompoundAssignOperator *S) { \
+ DISPATCH(CompoundAssignOperator, CompoundAssignOperator); \
+ }
+ CAO_FALLBACK(MulAssign) CAO_FALLBACK(DivAssign) CAO_FALLBACK(RemAssign)
+ CAO_FALLBACK(AddAssign) CAO_FALLBACK(SubAssign) CAO_FALLBACK(ShlAssign)
+ CAO_FALLBACK(ShrAssign) CAO_FALLBACK(AndAssign) CAO_FALLBACK(OrAssign)
+ CAO_FALLBACK(XorAssign)
+#undef CAO_FALLBACK
+
+ // If the implementation doesn't implement unary operator methods, fall back
+ // on VisitUnaryOperator.
+#define UNARYOP_FALLBACK(NAME) \
+ RetTy VisitUnary ## NAME(UnaryOperator *S) { \
+ DISPATCH(UnaryOperator, UnaryOperator); \
+ }
+ UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec)
+ UNARYOP_FALLBACK(PreInc) UNARYOP_FALLBACK(PreDec)
+ UNARYOP_FALLBACK(AddrOf) UNARYOP_FALLBACK(Deref)
+
+ UNARYOP_FALLBACK(Plus) UNARYOP_FALLBACK(Minus)
+ UNARYOP_FALLBACK(Not) UNARYOP_FALLBACK(LNot)
+ UNARYOP_FALLBACK(Real) UNARYOP_FALLBACK(Imag)
+ UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(OffsetOf)
+#undef UNARYOP_FALLBACK
+
+ // Base case, ignore it. :)
+ RetTy VisitStmt(Stmt *Node) { return RetTy(); }
+};
+
+#undef DISPATCH
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/TargetBuiltins.h b/include/clang/AST/TargetBuiltins.h
new file mode 100644
index 000000000000..d425a9b8ecad
--- /dev/null
+++ b/include/clang/AST/TargetBuiltins.h
@@ -0,0 +1,38 @@
+//===--- TargetBuiltins.h - Target specific builtin IDs -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_TARGET_BUILTINS_H
+#define LLVM_CLANG_AST_TARGET_BUILTINS_H
+
+#include "clang/AST/Builtins.h"
+#undef PPC
+
+namespace clang {
+ /// X86 builtins
+ namespace X86 {
+ enum {
+ LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1,
+#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
+#include "X86Builtins.def"
+ LastTSBuiltin
+ };
+ }
+
+ /// PPC builtins
+ namespace PPC {
+ enum {
+ LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1,
+#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
+#include "PPCBuiltins.def"
+ LastTSBuiltin
+ };
+ }
+} // end namespace clang.
+
+#endif
diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h
new file mode 100644
index 000000000000..511934c1dbf5
--- /dev/null
+++ b/include/clang/AST/TemplateName.h
@@ -0,0 +1,258 @@
+//===--- TemplateName.h - C++ Template Name Representation-------*- 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 TemplateName interface and subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_TEMPLATENAME_H
+#define LLVM_CLANG_AST_TEMPLATENAME_H
+
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/PointerUnion.h"
+
+namespace llvm {
+ class raw_ostream;
+}
+
+namespace clang {
+
+class DependentTemplateName;
+class IdentifierInfo;
+class NestedNameSpecifier;
+class PrintingPolicy;
+class QualifiedTemplateName;
+class TemplateDecl;
+
+/// \brief Represents a C++ template name within the type system.
+///
+/// A C++ template name refers to a template within the C++ type
+/// system. In most cases, a template name is simply a reference to a
+/// class template, e.g.
+///
+/// \code
+/// template<typename T> class X { };
+///
+/// X<int> xi;
+/// \endcode
+///
+/// Here, the 'X' in \c X<int> is a template name that refers to the
+/// declaration of the class template X, above. Template names can
+/// also refer to function templates, C++0x template aliases, etc.
+///
+/// Some template names are dependent. For example, consider:
+///
+/// \code
+/// template<typename MetaFun, typename T1, typename T2> struct apply2 {
+/// typedef typename MetaFun::template apply<T1, T2>::type type;
+/// };
+/// \endcode
+///
+/// Here, "apply" is treated as a template name within the typename
+/// specifier in the typedef. "apply" is a nested template, and can
+/// only be understood in the context of
+class TemplateName {
+ typedef llvm::PointerUnion3<TemplateDecl *, QualifiedTemplateName *,
+ DependentTemplateName *> StorageType;
+
+ StorageType Storage;
+
+ explicit TemplateName(void *Ptr) {
+ Storage = StorageType::getFromOpaqueValue(Ptr);
+ }
+
+public:
+ TemplateName() : Storage() { }
+ explicit TemplateName(TemplateDecl *Template) : Storage(Template) { }
+ explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { }
+ explicit TemplateName(DependentTemplateName *Dep) : Storage(Dep) { }
+
+ /// \brief Retrieve the the underlying template declaration that
+ /// this template name refers to, if known.
+ ///
+ /// \returns The template declaration that this template name refers
+ /// to, if any. If the template name does not refer to a specific
+ /// declaration because it is a dependent name, returns NULL.
+ TemplateDecl *getAsTemplateDecl() const;
+
+ /// \brief Retrieve the underlying qualified template name
+ /// structure, if any.
+ QualifiedTemplateName *getAsQualifiedTemplateName() const {
+ return Storage.dyn_cast<QualifiedTemplateName *>();
+ }
+
+ /// \brief Retrieve the underlying dependent template name
+ /// structure, if any.
+ DependentTemplateName *getAsDependentTemplateName() const {
+ return Storage.dyn_cast<DependentTemplateName *>();
+ }
+
+ /// \brief Determines whether this is a dependent template name.
+ bool isDependent() const;
+
+ /// \brief Print the template name.
+ ///
+ /// \param OS the output stream to which the template name will be
+ /// printed.
+ ///
+ /// \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,
+ bool SuppressNNS = false) const;
+
+ /// \brief Debugging aid that dumps the template name to standard
+ /// error.
+ void dump() const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ ID.AddPointer(Storage.getOpaqueValue());
+ }
+
+ /// \brief Retrieve the template name as a void pointer.
+ void *getAsVoidPointer() const { return Storage.getOpaqueValue(); }
+
+ /// \brief Build a template name from a void pointer.
+ static TemplateName getFromVoidPointer(void *Ptr) {
+ return TemplateName(Ptr);
+ }
+};
+
+/// \brief Represents a template name that was expressed as a
+/// qualified name.
+///
+/// This kind of template name refers to a template name that was
+/// preceded by a nested name specifier, e.g., \c std::vector. Here,
+/// the nested name specifier is "std::" and the template name is the
+/// declaration for "vector". The QualifiedTemplateName class is only
+/// used to provide "sugar" for template names that were expressed
+/// with a qualified name, and has no semantic meaning. In this
+/// manner, it is to TemplateName what QualifiedNameType is to Type,
+/// providing extra syntactic sugar for downstream clients.
+class QualifiedTemplateName : public llvm::FoldingSetNode {
+ /// \brief The nested name specifier that qualifies the template name.
+ ///
+ /// The bit is used to indicate whether the "template" keyword was
+ /// present before the template name itself. Note that the
+ /// "template" keyword is always redundant in this case (otherwise,
+ /// the template name would be a dependent name and we would express
+ /// this name with DependentTemplateName).
+ llvm::PointerIntPair<NestedNameSpecifier *, 1> Qualifier;
+
+ /// \brief The template declaration that this qualified name refers
+ /// to.
+ TemplateDecl *Template;
+
+ friend class ASTContext;
+
+ QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword,
+ TemplateDecl *Template)
+ : Qualifier(NNS, TemplateKeyword? 1 : 0), Template(Template) { }
+
+public:
+ /// \brief Return the nested name specifier that qualifies this name.
+ NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); }
+
+ /// \brief Whether the template name was prefixed by the "template"
+ /// keyword.
+ bool hasTemplateKeyword() const { return Qualifier.getInt(); }
+
+ /// \brief The template declaration to which this qualified name
+ /// refers.
+ TemplateDecl *getTemplateDecl() const { return Template; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getQualifier(), hasTemplateKeyword(), getTemplateDecl());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
+ bool TemplateKeyword, TemplateDecl *Template) {
+ ID.AddPointer(NNS);
+ ID.AddBoolean(TemplateKeyword);
+ ID.AddPointer(Template);
+ }
+};
+
+/// \brief Represents a dependent template name that cannot be
+/// resolved prior to template instantiation.
+///
+/// This kind of template name refers to a dependent template name,
+/// including its nested name specifier. For example,
+/// DependentTemplateName can refer to "MetaFun::template apply",
+/// where "MetaFun::" is the nested name specifier and "apply" is the
+/// template name referenced. The "template" keyword is implied.
+class DependentTemplateName : public llvm::FoldingSetNode {
+ /// \brief The nested name specifier that qualifies the template
+ /// name.
+ NestedNameSpecifier *Qualifier;
+
+ /// \brief The dependent template name.
+ const IdentifierInfo *Name;
+
+ /// \brief The canonical template name to which this dependent
+ /// template name refers.
+ ///
+ /// The canonical template name for a dependent template name is
+ /// another dependent template name whose nested name specifier is
+ /// canonical.
+ TemplateName CanonicalTemplateName;
+
+ friend class ASTContext;
+
+ DependentTemplateName(NestedNameSpecifier *Qualifier,
+ const IdentifierInfo *Name)
+ : Qualifier(Qualifier), Name(Name), CanonicalTemplateName(this) { }
+
+ DependentTemplateName(NestedNameSpecifier *Qualifier,
+ const IdentifierInfo *Name,
+ TemplateName Canon)
+ : Qualifier(Qualifier), Name(Name), CanonicalTemplateName(Canon) { }
+
+public:
+ /// \brief Return the nested name specifier that qualifies this name.
+ NestedNameSpecifier *getQualifier() const { return Qualifier; }
+
+ /// \brief Return the name to which this dependent template name
+ /// refers.
+ const IdentifierInfo *getName() const { return Name; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getQualifier(), getName());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name) {
+ ID.AddPointer(NNS);
+ ID.AddPointer(Name);
+ }
+};
+
+} // end namespace clang.
+
+namespace llvm {
+
+/// \brief The clang::TemplateName class is effectively a pointer.
+template<>
+class PointerLikeTypeTraits<clang::TemplateName> {
+public:
+ static inline void *getAsVoidPointer(clang::TemplateName TN) {
+ return TN.getAsVoidPointer();
+ }
+
+ static inline clang::TemplateName getFromVoidPointer(void *Ptr) {
+ return clang::TemplateName::getFromVoidPointer(Ptr);
+ }
+
+ // No bits are available!
+ enum { NumLowBitsAvailable = 0 };
+};
+
+} // end namespace llvm.
+
+#endif
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
new file mode 100644
index 000000000000..1b012385c9f2
--- /dev/null
+++ b/include/clang/AST/Type.h
@@ -0,0 +1,1977 @@
+//===--- Type.h - C Language Family Type Representation ---------*- 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 Type interface and subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_TYPE_H
+#define LLVM_CLANG_AST_TYPE_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/TemplateName.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/PointerUnion.h"
+
+using llvm::isa;
+using llvm::cast;
+using llvm::cast_or_null;
+using llvm::dyn_cast;
+using llvm::dyn_cast_or_null;
+namespace clang { class Type; }
+
+namespace llvm {
+ template <typename T>
+ class PointerLikeTypeTraits;
+ template<>
+ class PointerLikeTypeTraits< ::clang::Type*> {
+ public:
+ static inline void *getAsVoidPointer(::clang::Type *P) { return P; }
+ static inline ::clang::Type *getFromVoidPointer(void *P) {
+ return static_cast< ::clang::Type*>(P);
+ }
+ enum { NumLowBitsAvailable = 3 };
+ };
+}
+
+namespace clang {
+ class ASTContext;
+ class TypedefDecl;
+ class TemplateDecl;
+ class TemplateTypeParmDecl;
+ class NonTypeTemplateParmDecl;
+ class TemplateTemplateParmDecl;
+ class TagDecl;
+ class RecordDecl;
+ class CXXRecordDecl;
+ class EnumDecl;
+ class FieldDecl;
+ class ObjCInterfaceDecl;
+ class ObjCProtocolDecl;
+ class ObjCMethodDecl;
+ class Expr;
+ class Stmt;
+ class SourceLocation;
+ class StmtIteratorBase;
+ class TemplateArgument;
+ class QualifiedNameType;
+ class PrintingPolicy;
+
+ // Provide forward declarations for all of the *Type classes
+#define TYPE(Class, Base) class Class##Type;
+#include "clang/AST/TypeNodes.def"
+
+/// QualType - For efficiency, we don't store CVR-qualified types as nodes on
+/// their own: instead each reference to a type stores the qualifiers. This
+/// greatly reduces the number of nodes we need to allocate for types (for
+/// example we only need one for 'int', 'const int', 'volatile int',
+/// 'const volatile int', etc).
+///
+/// As an added efficiency bonus, instead of making this a pair, we just store
+/// the three bits we care about in the low bits of the pointer. To handle the
+/// packing/unpacking, we make QualType be a simple wrapper class that acts like
+/// a smart pointer.
+class QualType {
+ llvm::PointerIntPair<Type*, 3> Value;
+public:
+ enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ.
+ Const = 0x1,
+ Restrict = 0x2,
+ Volatile = 0x4,
+ CVRFlags = Const|Restrict|Volatile
+ };
+
+ enum GCAttrTypes {
+ GCNone = 0,
+ Weak,
+ Strong
+ };
+
+ QualType() {}
+
+ QualType(const Type *Ptr, unsigned Quals)
+ : Value(const_cast<Type*>(Ptr), Quals) {}
+
+ unsigned getCVRQualifiers() const { return Value.getInt(); }
+ void setCVRQualifiers(unsigned Quals) { Value.setInt(Quals); }
+ Type *getTypePtr() const { return Value.getPointer(); }
+
+ void *getAsOpaquePtr() const { return Value.getOpaqueValue(); }
+ static QualType getFromOpaquePtr(void *Ptr) {
+ QualType T;
+ T.Value.setFromOpaqueValue(Ptr);
+ return T;
+ }
+
+ Type &operator*() const {
+ return *getTypePtr();
+ }
+
+ Type *operator->() const {
+ return getTypePtr();
+ }
+
+ /// isNull - Return true if this QualType doesn't point to a type yet.
+ bool isNull() const {
+ return getTypePtr() == 0;
+ }
+
+ bool isConstQualified() const {
+ return (getCVRQualifiers() & Const) ? true : false;
+ }
+ bool isVolatileQualified() const {
+ return (getCVRQualifiers() & Volatile) ? true : false;
+ }
+ bool isRestrictQualified() const {
+ return (getCVRQualifiers() & Restrict) ? true : false;
+ }
+
+ bool isConstant(ASTContext& Ctx) const;
+
+ /// addConst/addVolatile/addRestrict - add the specified type qual to this
+ /// QualType.
+ void addConst() { Value.setInt(Value.getInt() | Const); }
+ void addVolatile() { Value.setInt(Value.getInt() | Volatile); }
+ void addRestrict() { Value.setInt(Value.getInt() | Restrict); }
+
+ void removeConst() { Value.setInt(Value.getInt() & ~Const); }
+ void removeVolatile() { Value.setInt(Value.getInt() & ~Volatile); }
+ void removeRestrict() { Value.setInt(Value.getInt() & ~Restrict); }
+
+ QualType getQualifiedType(unsigned TQs) const {
+ return QualType(getTypePtr(), TQs);
+ }
+ QualType getWithAdditionalQualifiers(unsigned TQs) const {
+ return QualType(getTypePtr(), TQs|getCVRQualifiers());
+ }
+
+ QualType withConst() const { return getWithAdditionalQualifiers(Const); }
+ QualType withVolatile() const { return getWithAdditionalQualifiers(Volatile);}
+ QualType withRestrict() const { return getWithAdditionalQualifiers(Restrict);}
+
+ QualType getUnqualifiedType() const;
+ bool isMoreQualifiedThan(QualType Other) const;
+ bool isAtLeastAsQualifiedAs(QualType Other) const;
+ QualType getNonReferenceType() const;
+
+ /// getDesugaredType - Return the specified type with any "sugar" removed from
+ /// the type. This takes off typedefs, typeof's etc. If the outer level of
+ /// the type is already concrete, it returns it unmodified. This is similar
+ /// to getting the canonical type, but it doesn't remove *all* typedefs. For
+ /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is
+ /// concrete.
+ QualType getDesugaredType(bool ForDisplay = false) const;
+
+ /// operator==/!= - Indicate whether the specified types and qualifiers are
+ /// identical.
+ bool operator==(const QualType &RHS) const {
+ return Value == RHS.Value;
+ }
+ bool operator!=(const QualType &RHS) const {
+ return Value != RHS.Value;
+ }
+ std::string getAsString() const;
+
+ std::string getAsString(const PrintingPolicy &Policy) const {
+ std::string S;
+ getAsStringInternal(S, Policy);
+ return S;
+ }
+ void getAsStringInternal(std::string &Str, const PrintingPolicy &Policy) const;
+
+ void dump(const char *s) const;
+ void dump() const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(getAsOpaquePtr());
+ }
+
+public:
+
+ /// getAddressSpace - Return the address space of this type.
+ inline unsigned getAddressSpace() const;
+
+ /// GCAttrTypesAttr - Returns gc attribute of this type.
+ inline QualType::GCAttrTypes getObjCGCAttr() const;
+
+ /// isObjCGCWeak true when Type is objc's weak.
+ bool isObjCGCWeak() const {
+ return getObjCGCAttr() == Weak;
+ }
+
+ /// isObjCGCStrong true when Type is objc's strong.
+ bool isObjCGCStrong() const {
+ return getObjCGCAttr() == Strong;
+ }
+};
+
+} // end clang.
+
+namespace llvm {
+/// Implement simplify_type for QualType, so that we can dyn_cast from QualType
+/// to a specific Type class.
+template<> struct simplify_type<const ::clang::QualType> {
+ typedef ::clang::Type* SimpleType;
+ static SimpleType getSimplifiedValue(const ::clang::QualType &Val) {
+ return Val.getTypePtr();
+ }
+};
+template<> struct simplify_type< ::clang::QualType>
+ : public simplify_type<const ::clang::QualType> {};
+
+// Teach SmallPtrSet that QualType is "basically a pointer".
+template<>
+class PointerLikeTypeTraits<clang::QualType> {
+public:
+ static inline void *getAsVoidPointer(clang::QualType P) {
+ return P.getAsOpaquePtr();
+ }
+ static inline clang::QualType getFromVoidPointer(void *P) {
+ return clang::QualType::getFromOpaquePtr(P);
+ }
+ // CVR qualifiers go in low bits.
+ enum { NumLowBitsAvailable = 0 };
+};
+} // end namespace llvm
+
+namespace clang {
+
+/// Type - This is the base class of the type hierarchy. A central concept
+/// with types is that each type always has a canonical type. A canonical type
+/// is the type with any typedef names stripped out of it or the types it
+/// references. For example, consider:
+///
+/// typedef int foo;
+/// typedef foo* bar;
+/// 'int *' 'foo *' 'bar'
+///
+/// There will be a Type object created for 'int'. Since int is canonical, its
+/// canonicaltype pointer points to itself. There is also a Type for 'foo' (a
+/// TypedefType). Its CanonicalType pointer points to the 'int' Type. Next
+/// there is a PointerType that represents 'int*', which, like 'int', is
+/// canonical. Finally, there is a PointerType type for 'foo*' whose canonical
+/// type is 'int*', and there is a TypedefType for 'bar', whose canonical type
+/// is also 'int*'.
+///
+/// Non-canonical types are useful for emitting diagnostics, without losing
+/// information about typedefs being used. Canonical types are useful for type
+/// comparisons (they allow by-pointer equality tests) and useful for reasoning
+/// about whether something has a particular form (e.g. is a function type),
+/// because they implicitly, recursively, strip all typedefs out of a type.
+///
+/// Types, once created, are immutable.
+///
+class Type {
+public:
+ enum TypeClass {
+#define TYPE(Class, Base) Class,
+#define ABSTRACT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+ TagFirst = Record, TagLast = Enum
+ };
+
+private:
+ QualType CanonicalType;
+
+ /// Dependent - Whether this type is a dependent type (C++ [temp.dep.type]).
+ bool Dependent : 1;
+
+ /// TypeClass bitfield - Enum that specifies what subclass this belongs to.
+ /// Note that this should stay at the end of the ivars for Type so that
+ /// subclasses can pack their bitfields into the same word.
+ unsigned TC : 5;
+
+ Type(const Type&); // DO NOT IMPLEMENT.
+ void operator=(const Type&); // DO NOT IMPLEMENT.
+protected:
+ // silence VC++ warning C4355: 'this' : used in base member initializer list
+ Type *this_() { return this; }
+ Type(TypeClass tc, QualType Canonical, bool dependent)
+ : CanonicalType(Canonical.isNull() ? QualType(this_(), 0) : Canonical),
+ Dependent(dependent), TC(tc) {}
+ virtual ~Type() {}
+ virtual void Destroy(ASTContext& C);
+ friend class ASTContext;
+
+public:
+ TypeClass getTypeClass() const { return static_cast<TypeClass>(TC); }
+
+ bool isCanonical() const { return CanonicalType.getTypePtr() == this; }
+
+ /// Types are partitioned into 3 broad categories (C99 6.2.5p1):
+ /// object types, function types, and incomplete types.
+
+ /// \brief Determines whether the type describes an object in memory.
+ ///
+ /// Note that this definition of object type corresponds to the C++
+ /// definition of object type, which includes incomplete types, as
+ /// opposed to the C definition (which does not include incomplete
+ /// types).
+ bool isObjectType() const;
+
+ /// isIncompleteType - Return true if this is an incomplete type.
+ /// A type that can describe objects, but which lacks information needed to
+ /// determine its size (e.g. void, or a fwd declared struct). Clients of this
+ /// routine will need to determine if the size is actually required.
+ bool isIncompleteType() const;
+
+ /// isIncompleteOrObjectType - Return true if this is an incomplete or object
+ /// type, in other words, not a function type.
+ bool isIncompleteOrObjectType() const {
+ return !isFunctionType();
+ }
+
+ /// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10).
+ bool isPODType() const;
+
+ /// isVariablyModifiedType (C99 6.7.5.2p2) - Return true for variable array
+ /// types that have a non-constant expression. This does not include "[]".
+ bool isVariablyModifiedType() const;
+
+ /// Helper methods to distinguish type categories. All type predicates
+ /// operate on the canonical type, ignoring typedefs and qualifiers.
+
+ /// isSpecificBuiltinType - Test for a particular builtin type.
+ bool isSpecificBuiltinType(unsigned K) const;
+
+ /// isIntegerType() does *not* include complex integers (a GCC extension).
+ /// isComplexIntegerType() can be used to test for complex integers.
+ bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum)
+ bool isEnumeralType() const;
+ bool isBooleanType() const;
+ bool isCharType() const;
+ bool isWideCharType() const;
+ bool isIntegralType() const;
+
+ /// Floating point categories.
+ bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double)
+ /// isComplexType() does *not* include complex integers (a GCC extension).
+ /// isComplexIntegerType() can be used to test for complex integers.
+ 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 isRealType() const; // C99 6.2.5p17 (real floating + integer)
+ bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating)
+ bool isVoidType() const; // C99 6.2.5p19
+ bool isDerivedType() const; // C99 6.2.5p20
+ bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers)
+ bool isAggregateType() const;
+
+ // Type Predicates: Check to see if this type is structurally the specified
+ // type, ignoring typedefs and qualifiers.
+ bool isFunctionType() const;
+ bool isFunctionNoProtoType() const { return getAsFunctionNoProtoType() != 0; }
+ bool isFunctionProtoType() const { return getAsFunctionProtoType() != 0; }
+ bool isPointerType() const;
+ bool isBlockPointerType() const;
+ bool isReferenceType() const;
+ bool isLValueReferenceType() const;
+ bool isRValueReferenceType() const;
+ bool isFunctionPointerType() const;
+ bool isMemberPointerType() const;
+ bool isMemberFunctionPointerType() const;
+ bool isArrayType() const;
+ bool isConstantArrayType() const;
+ bool isIncompleteArrayType() const;
+ bool isVariableArrayType() const;
+ bool isDependentSizedArrayType() const;
+ bool isRecordType() const;
+ bool isClassType() const;
+ bool isStructureType() const;
+ bool isUnionType() const;
+ bool isComplexIntegerType() const; // GCC _Complex integer type.
+ bool isVectorType() const; // GCC vector type.
+ bool isExtVectorType() const; // Extended vector type.
+ bool isObjCInterfaceType() const; // NSString or NSString<foo>
+ bool isObjCQualifiedInterfaceType() const; // NSString<foo>
+ bool isObjCQualifiedIdType() const; // id<foo>
+ bool isTemplateTypeParmType() const; // C++ template type parameter
+ bool isNullPtrType() const; // C++0x nullptr_t
+
+ /// isDependentType - Whether this type is a dependent type, meaning
+ /// that its definition somehow depends on a template parameter
+ /// (C++ [temp.dep.type]).
+ bool isDependentType() const { return Dependent; }
+ bool isOverloadableType() const;
+
+ /// hasPointerRepresentation - Whether this type is represented
+ /// natively as a pointer; this includes pointers, references, block
+ /// pointers, and Objective-C interface, qualified id, and qualified
+ /// interface types, as well as nullptr_t.
+ bool hasPointerRepresentation() const;
+
+ /// hasObjCPointerRepresentation - Whether this type can represent
+ /// an objective pointer type for the purpose of GC'ability
+ bool hasObjCPointerRepresentation() const;
+
+ // Type Checking Functions: Check to see if this type is structurally the
+ // specified type, ignoring typedefs and qualifiers, and return a pointer to
+ // the best type we can.
+ const BuiltinType *getAsBuiltinType() const;
+ const FunctionType *getAsFunctionType() const;
+ const FunctionNoProtoType *getAsFunctionNoProtoType() const;
+ const FunctionProtoType *getAsFunctionProtoType() const;
+ const PointerType *getAsPointerType() const;
+ const BlockPointerType *getAsBlockPointerType() const;
+ const ReferenceType *getAsReferenceType() const;
+ const LValueReferenceType *getAsLValueReferenceType() const;
+ const RValueReferenceType *getAsRValueReferenceType() const;
+ const MemberPointerType *getAsMemberPointerType() const;
+ const TagType *getAsTagType() const;
+ const RecordType *getAsRecordType() const;
+ const RecordType *getAsStructureType() const;
+ /// NOTE: getAs*ArrayType are methods on ASTContext.
+ const TypedefType *getAsTypedefType() const;
+ const RecordType *getAsUnionType() const;
+ const EnumType *getAsEnumType() const;
+ const VectorType *getAsVectorType() const; // GCC vector type.
+ const ComplexType *getAsComplexType() const;
+ const ComplexType *getAsComplexIntegerType() const; // GCC complex int type.
+ const ExtVectorType *getAsExtVectorType() const; // Extended vector type.
+ const ObjCInterfaceType *getAsObjCInterfaceType() const;
+ const ObjCQualifiedInterfaceType *getAsObjCQualifiedInterfaceType() const;
+ const ObjCQualifiedIdType *getAsObjCQualifiedIdType() const;
+ const TemplateTypeParmType *getAsTemplateTypeParmType() const;
+
+ const TemplateSpecializationType *
+ getAsTemplateSpecializationType() const;
+
+ /// getAsPointerToObjCInterfaceType - If this is a pointer to an ObjC
+ /// interface, return the interface type, otherwise return null.
+ const ObjCInterfaceType *getAsPointerToObjCInterfaceType() const;
+
+ /// getArrayElementTypeNoTypeQual - If this is an array type, return the
+ /// element type of the array, potentially with type qualifiers missing.
+ /// This method should never be used when type qualifiers are meaningful.
+ const Type *getArrayElementTypeNoTypeQual() const;
+
+ /// getDesugaredType - Return the specified type with any "sugar" removed from
+ /// the type. This takes off typedefs, typeof's etc. If the outer level of
+ /// the type is already concrete, it returns it unmodified. This is similar
+ /// to getting the canonical type, but it doesn't remove *all* typedefs. For
+ /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is
+ /// concrete.
+ QualType getDesugaredType(bool ForDisplay = false) const;
+
+ /// More type predicates useful for type checking/promotion
+ bool isPromotableIntegerType() const; // C99 6.3.1.1p2
+
+ /// isSignedIntegerType - Return true if this is an integer type that is
+ /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..],
+ /// an enum decl which has a signed representation, or a vector of signed
+ /// integer element type.
+ bool isSignedIntegerType() const;
+
+ /// isUnsignedIntegerType - Return true if this is an integer type that is
+ /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], an enum
+ /// decl which has an unsigned representation, or a vector of unsigned integer
+ /// element type.
+ bool isUnsignedIntegerType() const;
+
+ /// isConstantSizeType - Return true if this is not a variable sized type,
+ /// according to the rules of C99 6.7.5p3. It is not legal to call this on
+ /// incomplete types.
+ bool isConstantSizeType() const;
+
+ /// isSpecifierType - Returns true if this type can be represented by some
+ /// set of type specifiers.
+ bool isSpecifierType() const;
+
+ QualType getCanonicalTypeInternal() const { return CanonicalType; }
+ void dump() const;
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const = 0;
+ static bool classof(const Type *) { return true; }
+};
+
+/// ExtQualType - TR18037 (C embedded extensions) 6.2.5p26
+/// This supports all kinds of type attributes; including,
+/// address space qualified types, objective-c's __weak and
+/// __strong attributes.
+///
+class ExtQualType : public Type, public llvm::FoldingSetNode {
+ /// BaseType - This is the underlying type that this qualifies. All CVR
+ /// qualifiers are stored on the QualType that references this type, so we
+ /// can't have any here.
+ Type *BaseType;
+
+ /// Address Space ID - The address space ID this type is qualified with.
+ unsigned AddressSpace;
+ /// GC __weak/__strong attributes
+ QualType::GCAttrTypes GCAttrType;
+
+ ExtQualType(Type *Base, QualType CanonicalPtr, unsigned AddrSpace,
+ QualType::GCAttrTypes gcAttr) :
+ Type(ExtQual, CanonicalPtr, Base->isDependentType()), BaseType(Base),
+ AddressSpace(AddrSpace), GCAttrType(gcAttr) {
+ assert(!isa<ExtQualType>(BaseType) &&
+ "Cannot have ExtQualType of ExtQualType");
+ }
+ friend class ASTContext; // ASTContext creates these.
+public:
+ Type *getBaseType() const { return BaseType; }
+ QualType::GCAttrTypes getObjCGCAttr() const { return GCAttrType; }
+ unsigned getAddressSpace() const { return AddressSpace; }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getBaseType(), AddressSpace, GCAttrType);
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, Type *Base,
+ unsigned AddrSpace, QualType::GCAttrTypes gcAttr) {
+ ID.AddPointer(Base);
+ ID.AddInteger(AddrSpace);
+ ID.AddInteger(gcAttr);
+ }
+
+ static bool classof(const Type *T) { return T->getTypeClass() == ExtQual; }
+ static bool classof(const ExtQualType *) { return true; }
+};
+
+
+/// BuiltinType - This class is used for builtin types like 'int'. Builtin
+/// types are always canonical and have a literal name field.
+class BuiltinType : public Type {
+public:
+ enum Kind {
+ Void,
+
+ Bool, // This is bool and/or _Bool.
+ Char_U, // This is 'char' for targets where char is unsigned.
+ UChar, // This is explicitly qualified unsigned char.
+ UShort,
+ UInt,
+ ULong,
+ ULongLong,
+ UInt128, // __uint128_t
+
+ Char_S, // This is 'char' for targets where char is signed.
+ SChar, // This is explicitly qualified signed char.
+ WChar, // This is 'wchar_t' for C++.
+ Short,
+ Int,
+ Long,
+ LongLong,
+ Int128, // __int128_t
+
+ Float, Double, LongDouble,
+
+ NullPtr, // This is the type of C++0x 'nullptr'.
+
+ Overload, // This represents the type of an overloaded function declaration.
+ Dependent // This represents the type of a type-dependent expression.
+ };
+private:
+ Kind TypeKind;
+public:
+ BuiltinType(Kind K)
+ : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent)),
+ TypeKind(K) {}
+
+ Kind getKind() const { return TypeKind; }
+ const char *getName(bool CPlusPlus) const;
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
+ static bool classof(const BuiltinType *) { return true; }
+};
+
+/// FixedWidthIntType - Used for arbitrary width types that we either don't
+/// want to or can't map to named integer types. These always have a lower
+/// integer rank than builtin types of the same width.
+class FixedWidthIntType : public Type {
+private:
+ unsigned Width;
+ bool Signed;
+public:
+ FixedWidthIntType(unsigned W, bool S) : Type(FixedWidthInt, QualType(), false),
+ Width(W), Signed(S) {}
+
+ unsigned getWidth() const { return Width; }
+ bool isSigned() const { return Signed; }
+ const char *getName() const;
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) { return T->getTypeClass() == FixedWidthInt; }
+ static bool classof(const FixedWidthIntType *) { return true; }
+};
+
+/// ComplexType - C99 6.2.5p11 - Complex values. This supports the C99 complex
+/// types (_Complex float etc) as well as the GCC integer complex extensions.
+///
+class ComplexType : public Type, public llvm::FoldingSetNode {
+ QualType ElementType;
+ ComplexType(QualType Element, QualType CanonicalPtr) :
+ Type(Complex, CanonicalPtr, Element->isDependentType()),
+ ElementType(Element) {
+ }
+ friend class ASTContext; // ASTContext creates these.
+public:
+ QualType getElementType() const { return ElementType; }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getElementType());
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Element) {
+ ID.AddPointer(Element.getAsOpaquePtr());
+ }
+
+ static bool classof(const Type *T) { return T->getTypeClass() == Complex; }
+ static bool classof(const ComplexType *) { return true; }
+};
+
+/// PointerType - C99 6.7.5.1 - Pointer Declarators.
+///
+class PointerType : public Type, public llvm::FoldingSetNode {
+ QualType PointeeType;
+
+ PointerType(QualType Pointee, QualType CanonicalPtr) :
+ Type(Pointer, CanonicalPtr, Pointee->isDependentType()), PointeeType(Pointee) {
+ }
+ friend class ASTContext; // ASTContext creates these.
+public:
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ QualType getPointeeType() const { return PointeeType; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getPointeeType());
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) {
+ ID.AddPointer(Pointee.getAsOpaquePtr());
+ }
+
+ static bool classof(const Type *T) { return T->getTypeClass() == Pointer; }
+ static bool classof(const PointerType *) { return true; }
+};
+
+/// BlockPointerType - pointer to a block type.
+/// This type is to represent types syntactically represented as
+/// "void (^)(int)", etc. Pointee is required to always be a function type.
+///
+class BlockPointerType : public Type, public llvm::FoldingSetNode {
+ QualType PointeeType; // Block is some kind of pointer type
+ BlockPointerType(QualType Pointee, QualType CanonicalCls) :
+ Type(BlockPointer, CanonicalCls, Pointee->isDependentType()),
+ PointeeType(Pointee) {
+ }
+ friend class ASTContext; // ASTContext creates these.
+public:
+
+ // Get the pointee type. Pointee is required to always be a function type.
+ QualType getPointeeType() const { return PointeeType; }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getPointeeType());
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) {
+ ID.AddPointer(Pointee.getAsOpaquePtr());
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == BlockPointer;
+ }
+ static bool classof(const BlockPointerType *) { return true; }
+};
+
+/// ReferenceType - Base for LValueReferenceType and RValueReferenceType
+///
+class ReferenceType : public Type, public llvm::FoldingSetNode {
+ QualType PointeeType;
+
+protected:
+ ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef) :
+ Type(tc, CanonicalRef, Referencee->isDependentType()),
+ PointeeType(Referencee) {
+ }
+public:
+ QualType getPointeeType() const { return PointeeType; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getPointeeType());
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Referencee) {
+ ID.AddPointer(Referencee.getAsOpaquePtr());
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == LValueReference ||
+ T->getTypeClass() == RValueReference;
+ }
+ static bool classof(const ReferenceType *) { return true; }
+};
+
+/// LValueReferenceType - C++ [dcl.ref] - Lvalue reference
+///
+class LValueReferenceType : public ReferenceType {
+ LValueReferenceType(QualType Referencee, QualType CanonicalRef) :
+ ReferenceType(LValueReference, Referencee, CanonicalRef) {
+ }
+ friend class ASTContext; // ASTContext creates these
+public:
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == LValueReference;
+ }
+ static bool classof(const LValueReferenceType *) { return true; }
+};
+
+/// RValueReferenceType - C++0x [dcl.ref] - Rvalue reference
+///
+class RValueReferenceType : public ReferenceType {
+ RValueReferenceType(QualType Referencee, QualType CanonicalRef) :
+ ReferenceType(RValueReference, Referencee, CanonicalRef) {
+ }
+ friend class ASTContext; // ASTContext creates these
+public:
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == RValueReference;
+ }
+ static bool classof(const RValueReferenceType *) { return true; }
+};
+
+/// MemberPointerType - C++ 8.3.3 - Pointers to members
+///
+class MemberPointerType : public Type, public llvm::FoldingSetNode {
+ QualType PointeeType;
+ /// The class of which the pointee is a member. Must ultimately be a
+ /// RecordType, but could be a typedef or a template parameter too.
+ const Type *Class;
+
+ MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) :
+ Type(MemberPointer, CanonicalPtr,
+ Cls->isDependentType() || Pointee->isDependentType()),
+ PointeeType(Pointee), Class(Cls) {
+ }
+ friend class ASTContext; // ASTContext creates these.
+public:
+
+ QualType getPointeeType() const { return PointeeType; }
+
+ const Type *getClass() const { return Class; }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getPointeeType(), getClass());
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee,
+ const Type *Class) {
+ ID.AddPointer(Pointee.getAsOpaquePtr());
+ ID.AddPointer(Class);
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == MemberPointer;
+ }
+ static bool classof(const MemberPointerType *) { return true; }
+};
+
+/// ArrayType - C99 6.7.5.2 - Array Declarators.
+///
+class ArrayType : public Type, public llvm::FoldingSetNode {
+public:
+ /// ArraySizeModifier - Capture whether this is a normal array (e.g. int X[4])
+ /// an array with a static size (e.g. int X[static 4]), or an array
+ /// with a star size (e.g. int X[*]).
+ /// 'static' is only allowed on function parameters.
+ enum ArraySizeModifier {
+ Normal, Static, Star
+ };
+private:
+ /// ElementType - The element type of the array.
+ QualType ElementType;
+
+ // NOTE: VC++ treats enums as signed, avoid using the ArraySizeModifier enum
+ /// NOTE: These fields are packed into the bitfields space in the Type class.
+ unsigned SizeModifier : 2;
+
+ /// IndexTypeQuals - Capture qualifiers in declarations like:
+ /// 'int X[static restrict 4]'. For function parameters only.
+ unsigned IndexTypeQuals : 3;
+
+protected:
+ // C++ [temp.dep.type]p1:
+ // A type is dependent if it is...
+ // - an array type constructed from any dependent type or whose
+ // size is specified by a constant expression that is
+ // value-dependent,
+ ArrayType(TypeClass tc, QualType et, QualType can,
+ ArraySizeModifier sm, unsigned tq)
+ : Type(tc, can, et->isDependentType() || tc == DependentSizedArray),
+ ElementType(et), SizeModifier(sm), IndexTypeQuals(tq) {}
+
+ friend class ASTContext; // ASTContext creates these.
+public:
+ QualType getElementType() const { return ElementType; }
+ ArraySizeModifier getSizeModifier() const {
+ return ArraySizeModifier(SizeModifier);
+ }
+ unsigned getIndexTypeQualifier() const { return IndexTypeQuals; }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ConstantArray ||
+ T->getTypeClass() == VariableArray ||
+ T->getTypeClass() == IncompleteArray ||
+ T->getTypeClass() == DependentSizedArray;
+ }
+ static bool classof(const ArrayType *) { return true; }
+};
+
+/// ConstantArrayType - This class represents C arrays with a specified constant
+/// size. For example 'int A[100]' has ConstantArrayType where the element type
+/// is 'int' and the size is 100.
+class ConstantArrayType : public ArrayType {
+ llvm::APInt Size; // Allows us to unique the type.
+
+ ConstantArrayType(QualType et, QualType can, const llvm::APInt &size,
+ ArraySizeModifier sm, unsigned tq)
+ : ArrayType(ConstantArray, et, can, sm, tq), Size(size) {}
+ friend class ASTContext; // ASTContext creates these.
+public:
+ const llvm::APInt &getSize() const { return Size; }
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getElementType(), getSize(),
+ getSizeModifier(), getIndexTypeQualifier());
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType ET,
+ const llvm::APInt &ArraySize, ArraySizeModifier SizeMod,
+ unsigned TypeQuals) {
+ ID.AddPointer(ET.getAsOpaquePtr());
+ ID.AddInteger(ArraySize.getZExtValue());
+ ID.AddInteger(SizeMod);
+ ID.AddInteger(TypeQuals);
+ }
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ConstantArray;
+ }
+ static bool classof(const ConstantArrayType *) { return true; }
+};
+
+/// IncompleteArrayType - This class represents C arrays with an unspecified
+/// size. For example 'int A[]' has an IncompleteArrayType where the element
+/// type is 'int' and the size is unspecified.
+class IncompleteArrayType : public ArrayType {
+ IncompleteArrayType(QualType et, QualType can,
+ ArraySizeModifier sm, unsigned tq)
+ : ArrayType(IncompleteArray, et, can, sm, tq) {}
+ friend class ASTContext; // ASTContext creates these.
+public:
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == IncompleteArray;
+ }
+ static bool classof(const IncompleteArrayType *) { return true; }
+
+ friend class StmtIteratorBase;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getElementType(), getSizeModifier(), getIndexTypeQualifier());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType ET,
+ ArraySizeModifier SizeMod, unsigned TypeQuals) {
+ ID.AddPointer(ET.getAsOpaquePtr());
+ ID.AddInteger(SizeMod);
+ ID.AddInteger(TypeQuals);
+ }
+};
+
+/// VariableArrayType - This class represents C arrays with a specified size
+/// which is not an integer-constant-expression. For example, 'int s[x+foo()]'.
+/// Since the size expression is an arbitrary expression, we store it as such.
+///
+/// Note: VariableArrayType's aren't uniqued (since the expressions aren't) and
+/// should not be: two lexically equivalent variable array types could mean
+/// different things, for example, these variables do not have the same type
+/// dynamically:
+///
+/// void foo(int x) {
+/// int Y[x];
+/// ++x;
+/// int Z[x];
+/// }
+///
+class VariableArrayType : public ArrayType {
+ /// SizeExpr - An assignment expression. VLA's are only permitted within
+ /// a function block.
+ Stmt *SizeExpr;
+
+ VariableArrayType(QualType et, QualType can, Expr *e,
+ ArraySizeModifier sm, unsigned tq)
+ : ArrayType(VariableArray, et, can, sm, tq), SizeExpr((Stmt*) e) {}
+ friend class ASTContext; // ASTContext creates these.
+ virtual void Destroy(ASTContext& C);
+
+public:
+ Expr *getSizeExpr() const {
+ // We use C-style casts instead of cast<> here because we do not wish
+ // to have a dependency of Type.h on Stmt.h/Expr.h.
+ return (Expr*) SizeExpr;
+ }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == VariableArray;
+ }
+ static bool classof(const VariableArrayType *) { return true; }
+
+ friend class StmtIteratorBase;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ assert(0 && "Cannnot unique VariableArrayTypes.");
+ }
+};
+
+/// DependentSizedArrayType - This type represents an array type in
+/// C++ whose size is a value-dependent expression. For example:
+/// @code
+/// template<typename T, int Size>
+/// class array {
+/// T data[Size];
+/// };
+/// @endcode
+/// For these types, we won't actually know what the array bound is
+/// until template instantiation occurs, at which point this will
+/// become either a ConstantArrayType or a VariableArrayType.
+class DependentSizedArrayType : public ArrayType {
+ /// SizeExpr - An assignment expression that will instantiate to the
+ /// size of the array.
+ Stmt *SizeExpr;
+
+ DependentSizedArrayType(QualType et, QualType can, Expr *e,
+ ArraySizeModifier sm, unsigned tq)
+ : ArrayType(DependentSizedArray, et, can, sm, tq), SizeExpr((Stmt*) e) {}
+ friend class ASTContext; // ASTContext creates these.
+ virtual void Destroy(ASTContext& C);
+
+public:
+ Expr *getSizeExpr() const {
+ // We use C-style casts instead of cast<> here because we do not wish
+ // to have a dependency of Type.h on Stmt.h/Expr.h.
+ return (Expr*) SizeExpr;
+ }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == DependentSizedArray;
+ }
+ static bool classof(const DependentSizedArrayType *) { return true; }
+
+ friend class StmtIteratorBase;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ assert(0 && "Cannnot unique DependentSizedArrayTypes.");
+ }
+};
+
+/// VectorType - GCC generic vector type. This type is created using
+/// __attribute__((vector_size(n)), where "n" specifies the vector size in
+/// bytes. Since the constructor takes the number of vector elements, the
+/// client is responsible for converting the size into the number of elements.
+class VectorType : public Type, public llvm::FoldingSetNode {
+protected:
+ /// ElementType - The element type of the vector.
+ QualType ElementType;
+
+ /// NumElements - The number of elements in the vector.
+ unsigned NumElements;
+
+ VectorType(QualType vecType, unsigned nElements, QualType canonType) :
+ Type(Vector, canonType, vecType->isDependentType()),
+ ElementType(vecType), NumElements(nElements) {}
+ VectorType(TypeClass tc, QualType vecType, unsigned nElements,
+ QualType canonType)
+ : Type(tc, canonType, vecType->isDependentType()), ElementType(vecType),
+ NumElements(nElements) {}
+ friend class ASTContext; // ASTContext creates these.
+public:
+
+ QualType getElementType() const { return ElementType; }
+ unsigned getNumElements() const { return NumElements; }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getElementType(), getNumElements(), getTypeClass());
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType,
+ unsigned NumElements, TypeClass TypeClass) {
+ ID.AddPointer(ElementType.getAsOpaquePtr());
+ ID.AddInteger(NumElements);
+ ID.AddInteger(TypeClass);
+ }
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector;
+ }
+ static bool classof(const VectorType *) { return true; }
+};
+
+/// ExtVectorType - Extended vector type. This type is created using
+/// __attribute__((ext_vector_type(n)), where "n" is the number of elements.
+/// Unlike vector_size, ext_vector_type is only allowed on typedef's. This
+/// class enables syntactic extensions, like Vector Components for accessing
+/// points, colors, and textures (modeled after OpenGL Shading Language).
+class ExtVectorType : public VectorType {
+ ExtVectorType(QualType vecType, unsigned nElements, QualType canonType) :
+ VectorType(ExtVector, vecType, nElements, canonType) {}
+ friend class ASTContext; // ASTContext creates these.
+public:
+ static int getPointAccessorIdx(char c) {
+ switch (c) {
+ default: return -1;
+ case 'x': return 0;
+ case 'y': return 1;
+ case 'z': return 2;
+ case 'w': return 3;
+ }
+ }
+ static int getNumericAccessorIdx(char c) {
+ switch (c) {
+ default: return -1;
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ case 'a': return 10;
+ case 'b': return 11;
+ case 'c': return 12;
+ case 'd': return 13;
+ case 'e': return 14;
+ case 'f': return 15;
+ }
+ }
+
+ static int getAccessorIdx(char c) {
+ if (int idx = getPointAccessorIdx(c)+1) return idx-1;
+ return getNumericAccessorIdx(c);
+ }
+
+ bool isAccessorWithinNumElements(char c) const {
+ if (int idx = getAccessorIdx(c)+1)
+ return unsigned(idx-1) < NumElements;
+ return false;
+ }
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ExtVector;
+ }
+ static bool classof(const ExtVectorType *) { return true; }
+};
+
+/// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base
+/// class of FunctionNoProtoType and FunctionProtoType.
+///
+class FunctionType : public Type {
+ /// SubClassData - This field is owned by the subclass, put here to pack
+ /// tightly with the ivars in Type.
+ bool SubClassData : 1;
+
+ /// TypeQuals - Used only by FunctionProtoType, put here to pack with the
+ /// other bitfields.
+ /// The qualifiers are part of FunctionProtoType because...
+ ///
+ /// C++ 8.3.5p4: The return type, the parameter type list and the
+ /// cv-qualifier-seq, [...], are part of the function type.
+ ///
+ unsigned TypeQuals : 3;
+
+ // The type returned by the function.
+ QualType ResultType;
+protected:
+ FunctionType(TypeClass tc, QualType res, bool SubclassInfo,
+ unsigned typeQuals, QualType Canonical, bool Dependent)
+ : Type(tc, Canonical, Dependent),
+ SubClassData(SubclassInfo), TypeQuals(typeQuals), ResultType(res) {}
+ bool getSubClassData() const { return SubClassData; }
+ unsigned getTypeQuals() const { return TypeQuals; }
+public:
+
+ QualType getResultType() const { return ResultType; }
+
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == FunctionNoProto ||
+ T->getTypeClass() == FunctionProto;
+ }
+ static bool classof(const FunctionType *) { return true; }
+};
+
+/// FunctionNoProtoType - Represents a K&R-style 'int foo()' function, which has
+/// no information available about its arguments.
+class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
+ FunctionNoProtoType(QualType Result, QualType Canonical)
+ : FunctionType(FunctionNoProto, Result, false, 0, Canonical,
+ /*Dependent=*/false) {}
+ friend class ASTContext; // ASTContext creates these.
+public:
+ // No additional state past what FunctionType provides.
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getResultType());
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType) {
+ ID.AddPointer(ResultType.getAsOpaquePtr());
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == FunctionNoProto;
+ }
+ static bool classof(const FunctionNoProtoType *) { return true; }
+};
+
+/// FunctionProtoType - Represents a prototype with argument type info, e.g.
+/// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no
+/// arguments, not as having a single void argument. Such a type can have an
+/// exception specification, but this specification is not part of the canonical
+/// type.
+class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
+ /// hasAnyDependentType - Determine whether there are any dependent
+ /// types within the arguments passed in.
+ static bool hasAnyDependentType(const QualType *ArgArray, unsigned numArgs) {
+ for (unsigned Idx = 0; Idx < numArgs; ++Idx)
+ if (ArgArray[Idx]->isDependentType())
+ return true;
+
+ return false;
+ }
+
+ FunctionProtoType(QualType Result, const QualType *ArgArray, unsigned numArgs,
+ bool isVariadic, unsigned typeQuals, bool hasExs,
+ bool hasAnyExs, const QualType *ExArray,
+ unsigned numExs, QualType Canonical)
+ : FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical,
+ (Result->isDependentType() ||
+ hasAnyDependentType(ArgArray, numArgs))),
+ NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs),
+ AnyExceptionSpec(hasAnyExs) {
+ // Fill in the trailing argument array.
+ QualType *ArgInfo = reinterpret_cast<QualType*>(this+1);
+ for (unsigned i = 0; i != numArgs; ++i)
+ ArgInfo[i] = ArgArray[i];
+ // Fill in the exception array.
+ QualType *Ex = ArgInfo + numArgs;
+ for (unsigned i = 0; i != numExs; ++i)
+ Ex[i] = ExArray[i];
+ }
+
+ /// NumArgs - The number of arguments this function has, not counting '...'.
+ unsigned NumArgs : 20;
+
+ /// NumExceptions - The number of types in the exception spec, if any.
+ unsigned NumExceptions : 10;
+
+ /// HasExceptionSpec - Whether this function has an exception spec at all.
+ bool HasExceptionSpec : 1;
+
+ /// AnyExceptionSpec - Whether this function has a throw(...) spec.
+ bool AnyExceptionSpec : 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.
+
+ friend class ASTContext; // ASTContext creates these.
+
+public:
+ unsigned getNumArgs() const { return NumArgs; }
+ QualType getArgType(unsigned i) const {
+ assert(i < NumArgs && "Invalid argument number!");
+ return arg_type_begin()[i];
+ }
+
+ bool hasExceptionSpec() const { return HasExceptionSpec; }
+ bool hasAnyExceptionSpec() const { return AnyExceptionSpec; }
+ unsigned getNumExceptions() const { return NumExceptions; }
+ QualType getExceptionType(unsigned i) const {
+ assert(i < NumExceptions && "Invalid exception number!");
+ return exception_begin()[i];
+ }
+ bool hasEmptyExceptionSpec() const {
+ return hasExceptionSpec() && !hasAnyExceptionSpec() &&
+ getNumExceptions() == 0;
+ }
+
+ bool isVariadic() const { return getSubClassData(); }
+ unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); }
+
+ typedef const QualType *arg_type_iterator;
+ arg_type_iterator arg_type_begin() const {
+ return reinterpret_cast<const QualType *>(this+1);
+ }
+ arg_type_iterator arg_type_end() const { return arg_type_begin()+NumArgs; }
+
+ typedef const QualType *exception_iterator;
+ exception_iterator exception_begin() const {
+ // exceptions begin where arguments end
+ return arg_type_end();
+ }
+ exception_iterator exception_end() const {
+ return exception_begin() + NumExceptions;
+ }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == FunctionProto;
+ }
+ static bool classof(const FunctionProtoType *) { return true; }
+
+ void Profile(llvm::FoldingSetNodeID &ID);
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,
+ arg_type_iterator ArgTys, unsigned NumArgs,
+ bool isVariadic, unsigned TypeQuals,
+ bool hasExceptionSpec, bool anyExceptionSpec,
+ unsigned NumExceptions, exception_iterator Exs);
+};
+
+
+class TypedefType : public Type {
+ TypedefDecl *Decl;
+protected:
+ TypedefType(TypeClass tc, TypedefDecl *D, QualType can)
+ : Type(tc, can, can->isDependentType()), Decl(D) {
+ assert(!isa<TypedefType>(can) && "Invalid canonical type");
+ }
+ friend class ASTContext; // ASTContext creates these.
+public:
+
+ TypedefDecl *getDecl() const { return Decl; }
+
+ /// LookThroughTypedefs - Return the ultimate type this typedef corresponds to
+ /// potentially looking through *all* consecutive typedefs. This returns the
+ /// sum of the type qualifiers, so if you have:
+ /// typedef const int A;
+ /// typedef volatile A B;
+ /// looking through the typedefs for B will give you "const volatile A".
+ QualType LookThroughTypedefs() const;
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) { return T->getTypeClass() == Typedef; }
+ static bool classof(const TypedefType *) { return true; }
+};
+
+/// TypeOfExprType (GCC extension).
+class TypeOfExprType : public Type {
+ Expr *TOExpr;
+ TypeOfExprType(Expr *E, QualType can);
+ friend class ASTContext; // ASTContext creates these.
+public:
+ Expr *getUnderlyingExpr() const { return TOExpr; }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; }
+ static bool classof(const TypeOfExprType *) { return true; }
+};
+
+/// TypeOfType (GCC extension).
+class TypeOfType : public Type {
+ QualType TOType;
+ TypeOfType(QualType T, QualType can)
+ : Type(TypeOf, can, T->isDependentType()), TOType(T) {
+ assert(!isa<TypedefType>(can) && "Invalid canonical type");
+ }
+ friend class ASTContext; // ASTContext creates these.
+public:
+ QualType getUnderlyingType() const { return TOType; }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; }
+ static bool classof(const TypeOfType *) { return true; }
+};
+
+class TagType : public Type {
+ /// Stores the TagDecl associated with this type. The decl will
+ /// point to the TagDecl that actually defines the entity (or is a
+ /// definition in progress), if there is such a definition. The
+ /// single-bit value will be non-zero when this tag is in the
+ /// process of being defined.
+ mutable llvm::PointerIntPair<TagDecl *, 1> decl;
+ friend class ASTContext;
+ friend class TagDecl;
+
+protected:
+ TagType(TypeClass TC, TagDecl *D, QualType can);
+
+public:
+ TagDecl *getDecl() const { return decl.getPointer(); }
+
+ /// @brief Determines whether this type is in the process of being
+ /// defined.
+ bool isBeingDefined() const { return decl.getInt(); }
+ void setBeingDefined(bool Def) { decl.setInt(Def? 1 : 0); }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast;
+ }
+ static bool classof(const TagType *) { return true; }
+ static bool classof(const RecordType *) { return true; }
+ static bool classof(const EnumType *) { return true; }
+};
+
+/// RecordType - This is a helper class that allows the use of isa/cast/dyncast
+/// to detect TagType objects of structs/unions/classes.
+class RecordType : public TagType {
+protected:
+ explicit RecordType(RecordDecl *D)
+ : TagType(Record, reinterpret_cast<TagDecl*>(D), QualType()) { }
+ explicit RecordType(TypeClass TC, RecordDecl *D)
+ : TagType(TC, reinterpret_cast<TagDecl*>(D), QualType()) { }
+ friend class ASTContext; // ASTContext creates these.
+public:
+
+ RecordDecl *getDecl() const {
+ return reinterpret_cast<RecordDecl*>(TagType::getDecl());
+ }
+
+ // FIXME: This predicate is a helper to QualType/Type. It needs to
+ // recursively check all fields for const-ness. If any field is declared
+ // const, it needs to return false.
+ bool hasConstFields() const { return false; }
+
+ // FIXME: RecordType needs to check when it is created that all fields are in
+ // the same address space, and return that.
+ unsigned getAddressSpace() const { return 0; }
+
+ static bool classof(const TagType *T);
+ static bool classof(const Type *T) {
+ return isa<TagType>(T) && classof(cast<TagType>(T));
+ }
+ static bool classof(const RecordType *) { return true; }
+};
+
+/// EnumType - This is a helper class that allows the use of isa/cast/dyncast
+/// to detect TagType objects of enums.
+class EnumType : public TagType {
+ explicit EnumType(EnumDecl *D)
+ : TagType(Enum, reinterpret_cast<TagDecl*>(D), QualType()) { }
+ friend class ASTContext; // ASTContext creates these.
+public:
+
+ EnumDecl *getDecl() const {
+ return reinterpret_cast<EnumDecl*>(TagType::getDecl());
+ }
+
+ static bool classof(const TagType *T);
+ static bool classof(const Type *T) {
+ return isa<TagType>(T) && classof(cast<TagType>(T));
+ }
+ static bool classof(const EnumType *) { return true; }
+};
+
+class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
+ unsigned Depth : 16;
+ unsigned Index : 16;
+ IdentifierInfo *Name;
+
+ TemplateTypeParmType(unsigned D, unsigned I, IdentifierInfo *N,
+ QualType Canon)
+ : Type(TemplateTypeParm, Canon, /*Dependent=*/true),
+ Depth(D), Index(I), Name(N) { }
+
+ TemplateTypeParmType(unsigned D, unsigned I)
+ : Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true),
+ Depth(D), Index(I), Name(0) { }
+
+ friend class ASTContext; // ASTContext creates these
+
+public:
+ unsigned getDepth() const { return Depth; }
+ unsigned getIndex() const { return Index; }
+ IdentifierInfo *getName() const { return Name; }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, Depth, Index, Name);
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth,
+ unsigned Index, IdentifierInfo *Name) {
+ ID.AddInteger(Depth);
+ ID.AddInteger(Index);
+ ID.AddPointer(Name);
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == TemplateTypeParm;
+ }
+ static bool classof(const TemplateTypeParmType *T) { return true; }
+};
+
+/// \brief Represents the type of a template specialization as written
+/// in the source code.
+///
+/// Template specialization types represent the syntactic form of a
+/// template-id that refers to a type, e.g., @c vector<int>. Some
+/// template specialization types are syntactic sugar, whose canonical
+/// type will point to some other type node that represents the
+/// instantiation or class template specialization. For example, a
+/// class template specialization type of @c vector<int> will refer to
+/// a tag type for the instantiation
+/// @c std::vector<int, std::allocator<int>>.
+///
+/// Other template specialization types, for which the template name
+/// is dependent, may be canonical types. These types are always
+/// dependent.
+class TemplateSpecializationType
+ : public Type, public llvm::FoldingSetNode {
+
+ /// \brief The name of the template being specialized.
+ TemplateName Template;
+
+ /// \brief - The number of template arguments named in this class
+ /// template specialization.
+ unsigned NumArgs;
+
+ TemplateSpecializationType(TemplateName T,
+ const TemplateArgument *Args,
+ unsigned NumArgs, QualType Canon);
+
+ virtual void Destroy(ASTContext& C);
+
+ friend class ASTContext; // ASTContext creates these
+
+public:
+ /// \brief Determine whether any of the given template arguments are
+ /// dependent.
+ static bool anyDependentTemplateArguments(const TemplateArgument *Args,
+ unsigned NumArgs);
+
+ /// \brief Print a template argument list, including the '<' and '>'
+ /// enclosing the template arguments.
+ static std::string PrintTemplateArgumentList(const TemplateArgument *Args,
+ unsigned NumArgs,
+ const PrintingPolicy &Policy);
+
+ typedef const TemplateArgument * iterator;
+
+ iterator begin() const { return getArgs(); }
+ iterator end() const;
+
+ /// \brief Retrieve the name of the template that we are specializing.
+ TemplateName getTemplateName() const { return Template; }
+
+ /// \brief Retrieve the template arguments.
+ const TemplateArgument *getArgs() const {
+ return reinterpret_cast<const TemplateArgument *>(this + 1);
+ }
+
+ /// \brief Retrieve the number of template arguments.
+ unsigned getNumArgs() const { return NumArgs; }
+
+ /// \brief Retrieve a specific template argument as a type.
+ /// \precondition @c isArgType(Arg)
+ const TemplateArgument &getArg(unsigned Idx) const;
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, Template, getArgs(), NumArgs);
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T,
+ const TemplateArgument *Args, unsigned NumArgs);
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == TemplateSpecialization;
+ }
+ static bool classof(const TemplateSpecializationType *T) { return true; }
+};
+
+/// \brief Represents a type that was referred to via a qualified
+/// name, e.g., N::M::type.
+///
+/// This type is used to keep track of a type name as written in the
+/// source code, including any nested-name-specifiers. The type itself
+/// is always "sugar", used to express what was written in the source
+/// code but containing no additional semantic information.
+class QualifiedNameType : public Type, public llvm::FoldingSetNode {
+ /// \brief The nested name specifier containing the qualifier.
+ NestedNameSpecifier *NNS;
+
+ /// \brief The type that this qualified name refers to.
+ QualType NamedType;
+
+ QualifiedNameType(NestedNameSpecifier *NNS, QualType NamedType,
+ QualType CanonType)
+ : Type(QualifiedName, CanonType, NamedType->isDependentType()),
+ NNS(NNS), NamedType(NamedType) { }
+
+ friend class ASTContext; // ASTContext creates these
+
+public:
+ /// \brief Retrieve the qualification on this type.
+ NestedNameSpecifier *getQualifier() const { return NNS; }
+
+ /// \brief Retrieve the type named by the qualified-id.
+ QualType getNamedType() const { return NamedType; }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, NNS, NamedType);
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
+ QualType NamedType) {
+ ID.AddPointer(NNS);
+ NamedType.Profile(ID);
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == QualifiedName;
+ }
+ static bool classof(const QualifiedNameType *T) { return true; }
+};
+
+/// \brief Represents a 'typename' specifier that names a type within
+/// a dependent type, e.g., "typename T::type".
+///
+/// TypenameType has a very similar structure to QualifiedNameType,
+/// which also involves a nested-name-specifier following by a type,
+/// and (FIXME!) both can even be prefixed by the 'typename'
+/// keyword. However, the two types serve very different roles:
+/// QualifiedNameType is a non-semantic type that serves only as sugar
+/// to show how a particular type was written in the source
+/// code. TypenameType, on the other hand, only occurs when the
+/// nested-name-specifier is dependent, such that we cannot resolve
+/// the actual type until after instantiation.
+class TypenameType : public Type, public llvm::FoldingSetNode {
+ /// \brief The nested name specifier containing the qualifier.
+ NestedNameSpecifier *NNS;
+
+ typedef llvm::PointerUnion<const IdentifierInfo *,
+ const TemplateSpecializationType *> NameType;
+
+ /// \brief The type that this typename specifier refers to.
+ NameType Name;
+
+ TypenameType(NestedNameSpecifier *NNS, const IdentifierInfo *Name,
+ QualType CanonType)
+ : Type(Typename, CanonType, true), NNS(NNS), Name(Name) {
+ assert(NNS->isDependent() &&
+ "TypenameType requires a dependent nested-name-specifier");
+ }
+
+ TypenameType(NestedNameSpecifier *NNS, const TemplateSpecializationType *Ty,
+ QualType CanonType)
+ : Type(Typename, CanonType, true), NNS(NNS), Name(Ty) {
+ assert(NNS->isDependent() &&
+ "TypenameType requires a dependent nested-name-specifier");
+ }
+
+ friend class ASTContext; // ASTContext creates these
+
+public:
+ /// \brief Retrieve the qualification on this type.
+ NestedNameSpecifier *getQualifier() const { return NNS; }
+
+ /// \brief Retrieve the type named by the typename specifier as an
+ /// identifier.
+ ///
+ /// This routine will return a non-NULL identifier pointer when the
+ /// form of the original typename was terminated by an identifier,
+ /// e.g., "typename T::type".
+ const IdentifierInfo *getIdentifier() const {
+ return Name.dyn_cast<const IdentifierInfo *>();
+ }
+
+ /// \brief Retrieve the type named by the typename specifier as a
+ /// type specialization.
+ const TemplateSpecializationType *getTemplateId() const {
+ return Name.dyn_cast<const TemplateSpecializationType *>();
+ }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, NNS, Name);
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
+ NameType Name) {
+ ID.AddPointer(NNS);
+ ID.AddPointer(Name.getOpaqueValue());
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == Typename;
+ }
+ static bool classof(const TypenameType *T) { return true; }
+};
+
+/// ObjCInterfaceType - Interfaces are the core concept in Objective-C for
+/// object oriented design. They basically correspond to C++ classes. There
+/// are two kinds of interface types, normal interfaces like "NSString" and
+/// qualified interfaces, which are qualified with a protocol list like
+/// "NSString<NSCopyable, NSAmazing>". Qualified interface types are instances
+/// of ObjCQualifiedInterfaceType, which is a subclass of ObjCInterfaceType.
+class ObjCInterfaceType : public Type {
+ ObjCInterfaceDecl *Decl;
+protected:
+ ObjCInterfaceType(TypeClass tc, ObjCInterfaceDecl *D) :
+ Type(tc, QualType(), /*Dependent=*/false), Decl(D) { }
+ friend class ASTContext; // ASTContext creates these.
+public:
+
+ ObjCInterfaceDecl *getDecl() const { return Decl; }
+
+ /// qual_iterator and friends: this provides access to the (potentially empty)
+ /// list of protocols qualifying this interface. If this is an instance of
+ /// ObjCQualifiedInterfaceType it returns the list, otherwise it returns an
+ /// empty list if there are no qualifying protocols.
+ typedef llvm::SmallVector<ObjCProtocolDecl*, 8>::const_iterator qual_iterator;
+ inline qual_iterator qual_begin() const;
+ inline qual_iterator qual_end() const;
+ bool qual_empty() const { return getTypeClass() != ObjCQualifiedInterface; }
+
+ /// getNumProtocols - Return the number of qualifying protocols in this
+ /// interface type, or 0 if there are none.
+ inline unsigned getNumProtocols() const;
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ObjCInterface ||
+ T->getTypeClass() == ObjCQualifiedInterface;
+ }
+ static bool classof(const ObjCInterfaceType *) { return true; }
+};
+
+/// ObjCQualifiedInterfaceType - This class represents interface types
+/// conforming to a list of protocols, such as INTF<Proto1, Proto2, Proto1>.
+///
+/// Duplicate protocols are removed and protocol list is canonicalized to be in
+/// alphabetical order.
+class ObjCQualifiedInterfaceType : public ObjCInterfaceType,
+ public llvm::FoldingSetNode {
+
+ // List of protocols for this protocol conforming object type
+ // List is sorted on protocol name. No protocol is enterred more than once.
+ llvm::SmallVector<ObjCProtocolDecl*, 4> Protocols;
+
+ ObjCQualifiedInterfaceType(ObjCInterfaceDecl *D,
+ ObjCProtocolDecl **Protos, unsigned NumP) :
+ ObjCInterfaceType(ObjCQualifiedInterface, D),
+ Protocols(Protos, Protos+NumP) { }
+ friend class ASTContext; // ASTContext creates these.
+public:
+
+ unsigned getNumProtocols() const {
+ return Protocols.size();
+ }
+
+ qual_iterator qual_begin() const { return Protocols.begin(); }
+ qual_iterator qual_end() const { return Protocols.end(); }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID);
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ const ObjCInterfaceDecl *Decl,
+ ObjCProtocolDecl **protocols, unsigned NumProtocols);
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ObjCQualifiedInterface;
+ }
+ static bool classof(const ObjCQualifiedInterfaceType *) { return true; }
+};
+
+inline ObjCInterfaceType::qual_iterator ObjCInterfaceType::qual_begin() const {
+ if (const ObjCQualifiedInterfaceType *QIT =
+ dyn_cast<ObjCQualifiedInterfaceType>(this))
+ return QIT->qual_begin();
+ return 0;
+}
+inline ObjCInterfaceType::qual_iterator ObjCInterfaceType::qual_end() const {
+ if (const ObjCQualifiedInterfaceType *QIT =
+ dyn_cast<ObjCQualifiedInterfaceType>(this))
+ return QIT->qual_end();
+ return 0;
+}
+
+/// getNumProtocols - Return the number of qualifying protocols in this
+/// interface type, or 0 if there are none.
+inline unsigned ObjCInterfaceType::getNumProtocols() const {
+ if (const ObjCQualifiedInterfaceType *QIT =
+ dyn_cast<ObjCQualifiedInterfaceType>(this))
+ return QIT->getNumProtocols();
+ return 0;
+}
+
+/// ObjCQualifiedIdType - to represent id<protocol-list>.
+///
+/// Duplicate protocols are removed and protocol list is canonicalized to be in
+/// alphabetical order.
+class ObjCQualifiedIdType : public Type,
+ public llvm::FoldingSetNode {
+ // List of protocols for this protocol conforming 'id' type
+ // List is sorted on protocol name. No protocol is enterred more than once.
+ llvm::SmallVector<ObjCProtocolDecl*, 8> Protocols;
+
+ ObjCQualifiedIdType(ObjCProtocolDecl **Protos, unsigned NumP)
+ : Type(ObjCQualifiedId, QualType()/*these are always canonical*/,
+ /*Dependent=*/false),
+ Protocols(Protos, Protos+NumP) { }
+ friend class ASTContext; // ASTContext creates these.
+public:
+
+ unsigned getNumProtocols() const {
+ return Protocols.size();
+ }
+
+ typedef llvm::SmallVector<ObjCProtocolDecl*, 8>::const_iterator qual_iterator;
+ qual_iterator qual_begin() const { return Protocols.begin(); }
+ qual_iterator qual_end() const { return Protocols.end(); }
+
+ virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID);
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ ObjCProtocolDecl **protocols, unsigned NumProtocols);
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ObjCQualifiedId;
+ }
+ static bool classof(const ObjCQualifiedIdType *) { return true; }
+
+};
+
+// Inline function definitions.
+
+/// getUnqualifiedType - Return the type without any qualifiers.
+inline QualType QualType::getUnqualifiedType() const {
+ Type *TP = getTypePtr();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(TP))
+ TP = EXTQT->getBaseType();
+ return QualType(TP, 0);
+}
+
+/// getAddressSpace - Return the address space of this type.
+inline unsigned QualType::getAddressSpace() const {
+ QualType CT = getTypePtr()->getCanonicalTypeInternal();
+ if (const ArrayType *AT = dyn_cast<ArrayType>(CT))
+ return AT->getElementType().getAddressSpace();
+ if (const RecordType *RT = dyn_cast<RecordType>(CT))
+ return RT->getAddressSpace();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CT))
+ return EXTQT->getAddressSpace();
+ return 0;
+}
+
+/// getObjCGCAttr - Return the gc attribute of this type.
+inline QualType::GCAttrTypes QualType::getObjCGCAttr() const {
+ QualType CT = getTypePtr()->getCanonicalTypeInternal();
+ if (const ArrayType *AT = dyn_cast<ArrayType>(CT))
+ return AT->getElementType().getObjCGCAttr();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CT))
+ return EXTQT->getObjCGCAttr();
+ if (const PointerType *PT = CT->getAsPointerType())
+ return PT->getPointeeType().getObjCGCAttr();
+ return GCNone;
+}
+
+/// isMoreQualifiedThan - Determine whether this type is more
+/// qualified than the Other type. For example, "const volatile int"
+/// is more qualified than "const int", "volatile int", and
+/// "int". However, it is not more qualified than "const volatile
+/// int".
+inline bool QualType::isMoreQualifiedThan(QualType Other) const {
+ unsigned MyQuals = this->getCVRQualifiers();
+ unsigned OtherQuals = Other.getCVRQualifiers();
+ if (getAddressSpace() != Other.getAddressSpace())
+ return false;
+ return MyQuals != OtherQuals && (MyQuals | OtherQuals) == MyQuals;
+}
+
+/// isAtLeastAsQualifiedAs - Determine whether this type is at last
+/// as qualified as the Other type. For example, "const volatile
+/// int" is at least as qualified as "const int", "volatile int",
+/// "int", and "const volatile int".
+inline bool QualType::isAtLeastAsQualifiedAs(QualType Other) const {
+ unsigned MyQuals = this->getCVRQualifiers();
+ unsigned OtherQuals = Other.getCVRQualifiers();
+ if (getAddressSpace() != Other.getAddressSpace())
+ return false;
+ return (MyQuals | OtherQuals) == MyQuals;
+}
+
+/// getNonReferenceType - If Type is a reference type (e.g., const
+/// int&), returns the type that the reference refers to ("const
+/// int"). Otherwise, returns the type itself. This routine is used
+/// throughout Sema to implement C++ 5p6:
+///
+/// If an expression initially has the type "reference to T" (8.3.2,
+/// 8.5.3), the type is adjusted to "T" prior to any further
+/// analysis, the expression designates the object or function
+/// denoted by the reference, and the expression is an lvalue.
+inline QualType QualType::getNonReferenceType() const {
+ if (const ReferenceType *RefType = (*this)->getAsReferenceType())
+ return RefType->getPointeeType();
+ else
+ return *this;
+}
+
+inline const TypedefType* Type::getAsTypedefType() const {
+ return dyn_cast<TypedefType>(this);
+}
+inline const ObjCInterfaceType *Type::getAsPointerToObjCInterfaceType() const {
+ if (const PointerType *PT = getAsPointerType())
+ return PT->getPointeeType()->getAsObjCInterfaceType();
+ return 0;
+}
+
+// NOTE: All of these methods use "getUnqualifiedType" to strip off address
+// space qualifiers if present.
+inline bool Type::isFunctionType() const {
+ return isa<FunctionType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isPointerType() const {
+ return isa<PointerType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isBlockPointerType() const {
+ return isa<BlockPointerType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isReferenceType() const {
+ return isa<ReferenceType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isLValueReferenceType() const {
+ return isa<LValueReferenceType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isRValueReferenceType() const {
+ return isa<RValueReferenceType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isFunctionPointerType() const {
+ if (const PointerType* T = getAsPointerType())
+ return T->getPointeeType()->isFunctionType();
+ else
+ return false;
+}
+inline bool Type::isMemberPointerType() const {
+ return isa<MemberPointerType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isMemberFunctionPointerType() const {
+ if (const MemberPointerType* T = getAsMemberPointerType())
+ return T->getPointeeType()->isFunctionType();
+ else
+ return false;
+}
+inline bool Type::isArrayType() const {
+ return isa<ArrayType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isConstantArrayType() const {
+ return isa<ConstantArrayType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isIncompleteArrayType() const {
+ return isa<IncompleteArrayType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isVariableArrayType() const {
+ return isa<VariableArrayType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isDependentSizedArrayType() const {
+ return isa<DependentSizedArrayType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isRecordType() const {
+ return isa<RecordType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isAnyComplexType() const {
+ return isa<ComplexType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isVectorType() const {
+ return isa<VectorType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isExtVectorType() const {
+ return isa<ExtVectorType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isObjCInterfaceType() const {
+ return isa<ObjCInterfaceType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isObjCQualifiedInterfaceType() const {
+ return isa<ObjCQualifiedInterfaceType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isObjCQualifiedIdType() const {
+ return isa<ObjCQualifiedIdType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isTemplateTypeParmType() const {
+ return isa<TemplateTypeParmType>(CanonicalType.getUnqualifiedType());
+}
+
+inline bool Type::isSpecificBuiltinType(unsigned K) const {
+ if (const BuiltinType *BT = getAsBuiltinType())
+ if (BT->getKind() == (BuiltinType::Kind) K)
+ return true;
+ return false;
+}
+
+/// \brief Determines whether this is a type for which one can define
+/// an overloaded operator.
+inline bool Type::isOverloadableType() const {
+ return isDependentType() || isRecordType() || isEnumeralType();
+}
+
+inline bool Type::hasPointerRepresentation() const {
+ return (isPointerType() || isReferenceType() || isBlockPointerType() ||
+ isObjCInterfaceType() || isObjCQualifiedIdType() ||
+ isObjCQualifiedInterfaceType() || isNullPtrType());
+}
+
+inline bool Type::hasObjCPointerRepresentation() const {
+ return (isObjCInterfaceType() || isObjCQualifiedIdType() ||
+ isObjCQualifiedInterfaceType());
+}
+
+/// Insertion operator for diagnostics. This allows sending QualType's into a
+/// diagnostic with <<.
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ QualType T) {
+ DB.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
+ Diagnostic::ak_qualtype);
+ return DB;
+}
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
new file mode 100644
index 000000000000..76cbed311d79
--- /dev/null
+++ b/include/clang/AST/TypeNodes.def
@@ -0,0 +1,85 @@
+//===-- TypeNodes.def - Metadata about Type AST nodes -----------*- 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 AST type info database. Each type node is
+// enumerated by providing its name (e.g., "Builtin" or "Enum") and
+// base class (e.g., "Type" or "TagType"). Depending on where in the
+// abstract syntax tree the type will show up, the enumeration uses
+// one of four different macros:
+//
+// TYPE(Class, Base) - A type that can show up anywhere in the AST,
+// and might be dependent, canonical, or non-canonical. All clients
+// will need to understand these types.
+//
+// ABSTRACT_TYPE(Class, Base) - An abstract class that shows up in
+// the type hierarchy but has no concrete instances.
+//
+// NON_CANONICAL_TYPE(Class, Base) - A type that can show up
+// anywhere in the AST but will never be a part of a canonical
+// type. Clients that only need to deal with canonical types
+// (ignoring, e.g., typedefs and other type alises used for
+// pretty-printing) can ignore these types.
+//
+// DEPENDENT_TYPE(Class, Base) - A type that will only show up
+// within a C++ template that has not been instantiated, e.g., a
+// type that is always dependent. Clients that do not need to deal
+// with uninstantiated C++ templates can ignore these types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ABSTRACT_TYPE
+# define ABSTRACT_TYPE(Class, Base) TYPE(Class, Base)
+#endif
+
+#ifndef NON_CANONICAL_TYPE
+# define NON_CANONICAL_TYPE(Class, Base) TYPE(Class, Base)
+#endif
+
+#ifndef DEPENDENT_TYPE
+# define DEPENDENT_TYPE(Class, Base) TYPE(Class, Base)
+#endif
+
+TYPE(ExtQual, Type)
+TYPE(Builtin, Type)
+TYPE(FixedWidthInt, Type)
+TYPE(Complex, Type)
+TYPE(Pointer, Type)
+TYPE(BlockPointer, Type)
+ABSTRACT_TYPE(Reference, Type)
+TYPE(LValueReference, ReferenceType)
+TYPE(RValueReference, ReferenceType)
+TYPE(MemberPointer, Type)
+ABSTRACT_TYPE(Array, Type)
+TYPE(ConstantArray, ArrayType)
+TYPE(IncompleteArray, ArrayType)
+TYPE(VariableArray, ArrayType)
+DEPENDENT_TYPE(DependentSizedArray, ArrayType)
+TYPE(Vector, Type)
+TYPE(ExtVector, VectorType)
+ABSTRACT_TYPE(Function, Type)
+TYPE(FunctionProto, FunctionType)
+TYPE(FunctionNoProto, FunctionType)
+NON_CANONICAL_TYPE(Typedef, Type)
+NON_CANONICAL_TYPE(TypeOfExpr, Type)
+NON_CANONICAL_TYPE(TypeOf, Type)
+ABSTRACT_TYPE(Tag, Type)
+TYPE(Record, TagType)
+TYPE(Enum, TagType)
+DEPENDENT_TYPE(TemplateTypeParm, Type)
+TYPE(TemplateSpecialization, Type)
+NON_CANONICAL_TYPE(QualifiedName, Type)
+DEPENDENT_TYPE(Typename, Type)
+TYPE(ObjCInterface, Type)
+TYPE(ObjCQualifiedInterface, ObjCInterfaceType)
+TYPE(ObjCQualifiedId, Type)
+
+#undef DEPENDENT_TYPE
+#undef NON_CANONICAL_TYPE
+#undef ABSTRACT_TYPE
+#undef TYPE
diff --git a/include/clang/AST/TypeOrdering.h b/include/clang/AST/TypeOrdering.h
new file mode 100644
index 000000000000..4f60273d6809
--- /dev/null
+++ b/include/clang/AST/TypeOrdering.h
@@ -0,0 +1,63 @@
+//===-------------- TypeOrdering.h - Total ordering for types -------------===//
+//
+// 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 function objects and specializations that
+// allow QualType values to be sorted, used in std::maps, std::sets,
+// llvm::DenseMaps, and llvm::DenseSets.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TYPE_ORDERING_H
+#define LLVM_CLANG_TYPE_ORDERING_H
+
+#include "clang/AST/Type.h"
+#include <functional>
+
+namespace clang {
+
+/// QualTypeOrdering - Function object that provides a total ordering
+/// on QualType values.
+struct QualTypeOrdering : std::binary_function<QualType, QualType, bool> {
+ bool operator()(QualType T1, QualType T2) const {
+ return std::less<void*>()(T1.getAsOpaquePtr(), T2.getAsOpaquePtr());
+ }
+};
+
+}
+
+namespace llvm {
+ template<class> struct DenseMapInfo;
+
+ template<> struct DenseMapInfo<clang::QualType> {
+ static inline clang::QualType getEmptyKey() { return clang::QualType(); }
+
+ static inline clang::QualType getTombstoneKey() {
+ using clang::QualType;
+ return QualType::getFromOpaquePtr(reinterpret_cast<clang::Type *>(-1));
+ }
+
+ static unsigned getHashValue(clang::QualType Val) {
+ return (unsigned)((uintptr_t)Val.getAsOpaquePtr()) ^
+ ((unsigned)((uintptr_t)Val.getAsOpaquePtr() >> 9));
+ }
+
+ static bool isEqual(clang::QualType LHS, clang::QualType RHS) {
+ return LHS == RHS;
+ }
+
+ static bool isPod() {
+ // QualType isn't *technically* a POD type. However, we can get
+ // away with calling it a POD type since its copy constructor,
+ // copy assignment operator, and destructor are all trivial.
+ return true;
+ }
+ };
+}
+
+#endif
diff --git a/include/clang/AST/X86Builtins.def b/include/clang/AST/X86Builtins.def
new file mode 100644
index 000000000000..710efa8cee4b
--- /dev/null
+++ b/include/clang/AST/X86Builtins.def
@@ -0,0 +1,427 @@
+//===--- X86Builtins.def - X86 Builtin function database --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the X86-specific builtin function database. Users of
+// this file must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+// FIXME: this needs to be the full list supported by GCC. Right now, I'm just
+// adding stuff on demand.
+
+// The format of this database matches clang/AST/Builtins.def.
+
+// FIXME: In GCC, these builtins are defined depending on whether support for
+// MMX/SSE/etc is turned on. We should do this too.
+
+// FIXME: Ideally we would be able to pull this information from what
+// LLVM already knows about X86 builtins. We need to match the LLVM
+// definition anyway, since code generation will lower to the
+// intrinsic if one exists.
+
+BUILTIN(__builtin_ia32_emms , "v", "")
+
+// FIXME: Are these nothrow/const?
+
+// SSE intrinsics.
+BUILTIN(__builtin_ia32_comieq, "iV4fV4f", "")
+BUILTIN(__builtin_ia32_comilt, "iV4fV4f", "")
+BUILTIN(__builtin_ia32_comile, "iV4fV4f", "")
+BUILTIN(__builtin_ia32_comigt, "iV4fV4f", "")
+BUILTIN(__builtin_ia32_comige, "iV4fV4f", "")
+BUILTIN(__builtin_ia32_comineq, "iV4fV4f", "")
+BUILTIN(__builtin_ia32_ucomieq, "iV4fV4f", "")
+BUILTIN(__builtin_ia32_ucomilt, "iV4fV4f", "")
+BUILTIN(__builtin_ia32_ucomile, "iV4fV4f", "")
+BUILTIN(__builtin_ia32_ucomigt, "iV4fV4f", "")
+BUILTIN(__builtin_ia32_ucomige, "iV4fV4f", "")
+BUILTIN(__builtin_ia32_ucomineq, "iV4fV4f", "")
+BUILTIN(__builtin_ia32_comisdeq, "iV2dV2d", "")
+BUILTIN(__builtin_ia32_comisdlt, "iV2dV2d", "")
+BUILTIN(__builtin_ia32_comisdle, "iV2dV2d", "")
+BUILTIN(__builtin_ia32_comisdgt, "iV2dV2d", "")
+BUILTIN(__builtin_ia32_comisdge, "iV2dV2d", "")
+BUILTIN(__builtin_ia32_comisdneq, "iV2dV2d", "")
+BUILTIN(__builtin_ia32_ucomisdeq, "iV2dV2d", "")
+BUILTIN(__builtin_ia32_ucomisdlt, "iV2dV2d", "")
+BUILTIN(__builtin_ia32_ucomisdle, "iV2dV2d", "")
+BUILTIN(__builtin_ia32_ucomisdgt, "iV2dV2d", "")
+BUILTIN(__builtin_ia32_ucomisdge, "iV2dV2d", "")
+BUILTIN(__builtin_ia32_ucomisdneq, "iV2dV2d", "")
+BUILTIN(__builtin_ia32_addps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_subps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_mulps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_divps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_addss, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_subss, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_mulss, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_divss, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_cmpps, "V4fV4fV4fc", "")
+BUILTIN(__builtin_ia32_cmpss, "V4fV4fV4fc", "")
+BUILTIN(__builtin_ia32_minps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_maxps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_minss, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_maxss, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_andps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_andnps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_orps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_xorps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_movss, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_movhlps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_movlhps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_unpckhps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_unpcklps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_paddb, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_paddw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_paddd, "V2iV2iV2i", "")
+BUILTIN(__builtin_ia32_paddq, "V1LLiV1LLiV1LLi", "")
+BUILTIN(__builtin_ia32_psubb, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_psubw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_psubd, "V2iV2iV2i", "")
+BUILTIN(__builtin_ia32_psubq, "V1LLiV1LLiV1LLi", "")
+BUILTIN(__builtin_ia32_paddsb, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_paddsw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_psubsb, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_psubsw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_paddusb, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_paddusw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_psubusb, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_psubusw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_pmullw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_pmulhw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_pmulhuw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_pand, "V1LLiV1LLiV1LLi", "")
+BUILTIN(__builtin_ia32_pandn, "V1LLiV1LLiV1LLi", "")
+BUILTIN(__builtin_ia32_por, "V1LLiV1LLiV1LLi", "")
+BUILTIN(__builtin_ia32_pxor, "V1LLiV1LLiV1LLi", "")
+BUILTIN(__builtin_ia32_pavgb, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_pavgw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_pcmpeqb, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_pcmpeqw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_pcmpeqd, "V2iV2iV2i", "")
+BUILTIN(__builtin_ia32_pcmpgtb, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_pcmpgtw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_pcmpgtd, "V2iV2iV2i", "")
+BUILTIN(__builtin_ia32_pmaxub, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_pmaxsw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_pminub, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_pminsw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_punpckhbw, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_punpckhwd, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_punpckhdq, "V2iV2iV2i", "")
+BUILTIN(__builtin_ia32_punpcklbw, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_punpcklwd, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_punpckldq, "V2iV2iV2i", "")
+BUILTIN(__builtin_ia32_addpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_subpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_mulpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_divpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_addsd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_subsd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_mulsd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_divsd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_cmppd, "V2dV2dV2dc", "")
+BUILTIN(__builtin_ia32_cmpsd, "V2dV2dV2dc", "")
+BUILTIN(__builtin_ia32_minpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_maxpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_minsd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_maxsd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_andpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_andnpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_orpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_xorpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_movsd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_unpckhpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_unpcklpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_paddb128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_paddw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_paddd128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_paddq128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_psubb128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_psubw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_psubd128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_psubq128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_paddsb128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_paddsw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_psubsb128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_psubsw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_paddusb128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_paddusw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_psubusb128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_psubusw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_pmullw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_pmulhw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_pand128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_pandn128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_por128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_pxor128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_pavgb128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_pavgw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_pcmpeqb128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_pcmpeqw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_pcmpeqd128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_pcmpgtb128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_pcmpgtw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_pcmpgtd128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_pmaxub128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_pmaxsw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_pminub128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_pminsw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_punpckhbw128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_punpckhwd128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_punpckhdq128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_punpckhqdq128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_punpcklbw128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_punpcklwd128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_punpckldq128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_punpcklqdq128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_packsswb128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_packssdw128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_packuswb128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_pmulhuw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_addsubps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_addsubpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_haddps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_haddpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_hsubps, "V4fV4fV4f", "")
+BUILTIN(__builtin_ia32_hsubpd, "V2dV2dV2d", "")
+BUILTIN(__builtin_ia32_phaddw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_phaddw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_phaddd128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_phaddd, "V2iV2iV2i", "")
+BUILTIN(__builtin_ia32_phaddsw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_phaddsw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_phsubw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_phsubw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_phsubd128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_phsubd, "V2iV2iV2i", "")
+BUILTIN(__builtin_ia32_phsubsw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_phsubsw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_pmaddubsw128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_pmaddubsw, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_pmulhrsw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_pmulhrsw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_pshufb128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_pshufb, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_psignb128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_psignb, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_psignw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_psignw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_psignd128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_psignd, "V2iV2iV2i", "")
+BUILTIN(__builtin_ia32_pabsb128, "V16cV16c", "")
+BUILTIN(__builtin_ia32_pabsb, "V8cV8c", "")
+BUILTIN(__builtin_ia32_pabsw128, "V8sV8s", "")
+BUILTIN(__builtin_ia32_pabsw, "V4sV4s", "")
+BUILTIN(__builtin_ia32_pabsd128, "V4iV4i", "")
+BUILTIN(__builtin_ia32_pabsd, "V2iV2i", "")
+BUILTIN(__builtin_ia32_psllw, "V4sV4sV1LLi", "")
+BUILTIN(__builtin_ia32_pslld, "V2iV2iV1LLi", "")
+BUILTIN(__builtin_ia32_psllq, "V1LLiV1LLiV1LLi", "")
+BUILTIN(__builtin_ia32_psrlw, "V4sV4sV1LLi", "")
+BUILTIN(__builtin_ia32_psrld, "V2iV2iV1LLi", "")
+BUILTIN(__builtin_ia32_psrlq, "V1LLiV1LLiV1LLi", "")
+BUILTIN(__builtin_ia32_psraw, "V4sV4sV1LLi", "")
+BUILTIN(__builtin_ia32_psrad, "V2iV2iV1LLi", "")
+BUILTIN(__builtin_ia32_pshufw, "V4sV4si", "")
+BUILTIN(__builtin_ia32_pmaddwd, "V2iV4sV4s", "")
+BUILTIN(__builtin_ia32_packsswb, "V8cV4sV4s", "")
+BUILTIN(__builtin_ia32_packssdw, "V4sV2iV2i", "")
+BUILTIN(__builtin_ia32_packuswb, "V8cV4sV4s", "")
+BUILTIN(__builtin_ia32_ldmxcsr, "vUi", "")
+BUILTIN(__builtin_ia32_stmxcsr, "Ui", "")
+BUILTIN(__builtin_ia32_cvtpi2ps, "V4fV4fV2i", "")
+BUILTIN(__builtin_ia32_cvtps2pi, "V2iV4f", "")
+BUILTIN(__builtin_ia32_cvtsi2ss, "V4fV4fi", "")
+BUILTIN(__builtin_ia32_cvtsi642ss, "V4fV4fLLi", "")
+BUILTIN(__builtin_ia32_cvtss2si, "iV4f", "")
+BUILTIN(__builtin_ia32_cvtss2si64, "LLiV4f", "")
+BUILTIN(__builtin_ia32_cvttps2pi, "V2iV4f", "")
+BUILTIN(__builtin_ia32_cvttss2si, "iV4f", "")
+BUILTIN(__builtin_ia32_cvttss2si64, "LLiV4f", "")
+BUILTIN(__builtin_ia32_maskmovq, "vV8cV8cc*", "")
+BUILTIN(__builtin_ia32_loadups, "V4ffC*", "")
+BUILTIN(__builtin_ia32_storeups, "vf*V4f", "")
+BUILTIN(__builtin_ia32_loadhps, "V4fV4fV2i*", "")
+BUILTIN(__builtin_ia32_loadlps, "V4fV4fV2i*", "")
+BUILTIN(__builtin_ia32_storehps, "vV2i*V4f", "")
+BUILTIN(__builtin_ia32_storelps, "vV2i*V4f", "")
+BUILTIN(__builtin_ia32_movmskps, "iV4f", "")
+BUILTIN(__builtin_ia32_pmovmskb, "iV8c", "")
+BUILTIN(__builtin_ia32_movntps, "vf*V4f", "")
+BUILTIN(__builtin_ia32_movntq, "vV1LLi*V1LLi", "")
+BUILTIN(__builtin_ia32_sfence, "v", "")
+BUILTIN(__builtin_ia32_psadbw, "V4sV8cV8c", "")
+BUILTIN(__builtin_ia32_rcpps, "V4fV4f", "")
+BUILTIN(__builtin_ia32_rcpss, "V4fV4f", "")
+BUILTIN(__builtin_ia32_rsqrtps, "V4fV4f", "")
+BUILTIN(__builtin_ia32_rsqrtss, "V4fV4f", "")
+BUILTIN(__builtin_ia32_sqrtps, "V4fV4f", "")
+BUILTIN(__builtin_ia32_sqrtss, "V4fV4f", "")
+BUILTIN(__builtin_ia32_shufps, "V4fV4fV4fi", "")
+BUILTIN(__builtin_ia32_femms, "v", "")
+BUILTIN(__builtin_ia32_pavgusb, "V8cV8cV8c", "")
+BUILTIN(__builtin_ia32_pf2id, "V2iV2f", "")
+BUILTIN(__builtin_ia32_pfacc, "V2fV2fV2f", "")
+BUILTIN(__builtin_ia32_pfadd, "V2fV2fV2f", "")
+BUILTIN(__builtin_ia32_pfcmpeq, "V2iV2fV2f", "")
+BUILTIN(__builtin_ia32_pfcmpge, "V2iV2fV2f", "")
+BUILTIN(__builtin_ia32_pfcmpgt, "V2iV2fV2f", "")
+BUILTIN(__builtin_ia32_pfmax, "V2fV2fV2f", "")
+BUILTIN(__builtin_ia32_pfmin, "V2fV2fV2f", "")
+BUILTIN(__builtin_ia32_pfmul, "V2fV2fV2f", "")
+BUILTIN(__builtin_ia32_pfrcp, "V2fV2f", "")
+BUILTIN(__builtin_ia32_pfrcpit1, "V2fV2fV2f", "")
+BUILTIN(__builtin_ia32_pfrcpit2, "V2fV2fV2f", "")
+BUILTIN(__builtin_ia32_pfrsqrt, "V2fV2f", "")
+BUILTIN(__builtin_ia32_pfrsqit1, "V2fV2fV2f", "")
+BUILTIN(__builtin_ia32_pfsub, "V2fV2fV2f", "")
+BUILTIN(__builtin_ia32_pfsubr, "V2fV2fV2f", "")
+BUILTIN(__builtin_ia32_pi2fd, "V2fV2i", "")
+BUILTIN(__builtin_ia32_pmulhrw, "V4sV4sV4s", "")
+BUILTIN(__builtin_ia32_pf2iw, "V2iV2f", "")
+BUILTIN(__builtin_ia32_pfnacc, "V2fV2fV2f", "")
+BUILTIN(__builtin_ia32_pfpnacc, "V2fV2fV2f", "")
+BUILTIN(__builtin_ia32_pi2fw, "V2fV2i", "")
+BUILTIN(__builtin_ia32_pswapdsf, "V2fV2f", "")
+BUILTIN(__builtin_ia32_pswapdsi, "V2iV2i", "")
+BUILTIN(__builtin_ia32_maskmovdqu, "vV16cV16cc*", "")
+BUILTIN(__builtin_ia32_loadupd, "V2ddC*", "")
+BUILTIN(__builtin_ia32_storeupd, "vd*V2d", "")
+BUILTIN(__builtin_ia32_loadhpd, "V2dV2ddC*", "")
+BUILTIN(__builtin_ia32_loadlpd, "V2dV2ddC*", "")
+BUILTIN(__builtin_ia32_movmskpd, "iV2d", "")
+BUILTIN(__builtin_ia32_pmovmskb128, "iV16c", "")
+BUILTIN(__builtin_ia32_movnti, "vi*i", "")
+BUILTIN(__builtin_ia32_movntpd, "vd*V2d", "")
+BUILTIN(__builtin_ia32_movntdq, "vV2LLi*V2LLi", "")
+BUILTIN(__builtin_ia32_pshufd, "V4iV4ii", "")
+BUILTIN(__builtin_ia32_pshuflw, "V8sV8si", "")
+BUILTIN(__builtin_ia32_pshufhw, "V8sV8si", "")
+BUILTIN(__builtin_ia32_psadbw128, "V2LLiV16cV16c", "")
+BUILTIN(__builtin_ia32_sqrtpd, "V2dV2d", "")
+BUILTIN(__builtin_ia32_sqrtsd, "V2dV2d", "")
+BUILTIN(__builtin_ia32_shufpd, "V2dV2dV2di", "")
+BUILTIN(__builtin_ia32_cvtdq2pd, "V2dV4i", "")
+BUILTIN(__builtin_ia32_cvtdq2ps, "V4fV4i", "")
+BUILTIN(__builtin_ia32_cvtpd2dq, "V2LLiV2d", "")
+BUILTIN(__builtin_ia32_cvtpd2pi, "V2iV2d", "")
+BUILTIN(__builtin_ia32_cvtpd2ps, "V4fV2d", "")
+BUILTIN(__builtin_ia32_cvttpd2dq, "V4iV2d", "")
+BUILTIN(__builtin_ia32_cvttpd2pi, "V2iV2d", "")
+BUILTIN(__builtin_ia32_cvtpi2pd, "V2dV2i", "")
+BUILTIN(__builtin_ia32_cvtsd2si, "iV2d", "")
+BUILTIN(__builtin_ia32_cvttsd2si, "iV2d", "")
+BUILTIN(__builtin_ia32_cvtsd2si64, "LLiV2d", "")
+BUILTIN(__builtin_ia32_cvttsd2si64, "LLiV2d", "")
+BUILTIN(__builtin_ia32_cvtps2dq, "V4iV4f", "")
+BUILTIN(__builtin_ia32_cvtps2pd, "V2dV4f", "")
+BUILTIN(__builtin_ia32_cvttps2dq, "V4iV4f", "")
+BUILTIN(__builtin_ia32_cvtsi2sd, "V2dV2di", "")
+BUILTIN(__builtin_ia32_cvtsi642sd, "V2dV2dLLi", "")
+BUILTIN(__builtin_ia32_cvtsd2ss, "V4fV4fV2d", "")
+BUILTIN(__builtin_ia32_cvtss2sd, "V2dV2dV4f", "")
+BUILTIN(__builtin_ia32_clflush, "vvC*", "")
+BUILTIN(__builtin_ia32_lfence, "v", "")
+BUILTIN(__builtin_ia32_mfence, "v", "")
+BUILTIN(__builtin_ia32_loaddqu, "V16ccC*", "")
+BUILTIN(__builtin_ia32_storedqu, "vc*V16c", "")
+BUILTIN(__builtin_ia32_psllwi, "V4sV4si", "")
+BUILTIN(__builtin_ia32_pslldi, "V2iV2ii", "")
+BUILTIN(__builtin_ia32_psllqi, "V1LLiV1LLii", "")
+BUILTIN(__builtin_ia32_psrawi, "V4sV4si", "")
+BUILTIN(__builtin_ia32_psradi, "V2iV2ii", "")
+BUILTIN(__builtin_ia32_psrlwi, "V4sV4si", "")
+BUILTIN(__builtin_ia32_psrldi, "V2iV2ii", "")
+BUILTIN(__builtin_ia32_psrlqi, "V1LLiV1LLii", "")
+BUILTIN(__builtin_ia32_pmuludq, "V1LLiV2iV2i", "")
+BUILTIN(__builtin_ia32_pmuludq128, "V2LLiV4iV4i", "")
+BUILTIN(__builtin_ia32_psraw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_psrad128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_psrlw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_psrld128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_pslldqi128, "V2LLiV2LLii", "")
+BUILTIN(__builtin_ia32_psrldqi128, "V2LLiV2LLii", "")
+BUILTIN(__builtin_ia32_psrlq128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_psllw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_pslld128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_psllq128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_psllwi128, "V8sV8si", "")
+BUILTIN(__builtin_ia32_pslldi128, "V4iV4ii", "")
+BUILTIN(__builtin_ia32_psllqi128, "V2LLiV2LLii", "")
+BUILTIN(__builtin_ia32_psrlwi128, "V8sV8si", "")
+BUILTIN(__builtin_ia32_psrldi128, "V4iV4ii", "")
+BUILTIN(__builtin_ia32_psrlqi128, "V2LLiV2LLii", "")
+BUILTIN(__builtin_ia32_psrawi128, "V8sV8si", "")
+BUILTIN(__builtin_ia32_psradi128, "V4iV4ii", "")
+BUILTIN(__builtin_ia32_pmaddwd128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "")
+BUILTIN(__builtin_ia32_mwait, "vUiUi", "")
+BUILTIN(__builtin_ia32_movshdup, "V4fV4f", "")
+BUILTIN(__builtin_ia32_movsldup, "V4fV4f", "")
+BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "")
+BUILTIN(__builtin_ia32_palignr128, "V2LLiV2LLiV2LLii", "")
+BUILTIN(__builtin_ia32_palignr, "V1LLiV1LLiV1LLis", "")
+BUILTIN(__builtin_ia32_vec_init_v2si, "V2iii", "")
+BUILTIN(__builtin_ia32_vec_init_v4hi, "V4sssss", "")
+BUILTIN(__builtin_ia32_vec_init_v8qi, "V8ccccccccc", "")
+BUILTIN(__builtin_ia32_vec_ext_v2df, "dV2di", "")
+BUILTIN(__builtin_ia32_vec_ext_v2di, "LLiV2LLii", "")
+BUILTIN(__builtin_ia32_vec_ext_v4sf, "fV4fi", "")
+BUILTIN(__builtin_ia32_vec_ext_v4si, "iV4ii", "")
+BUILTIN(__builtin_ia32_vec_ext_v8hi, "UsV8si", "")
+BUILTIN(__builtin_ia32_vec_ext_v4hi, "sV4si", "")
+BUILTIN(__builtin_ia32_vec_ext_v2si, "iV2ii", "")
+BUILTIN(__builtin_ia32_vec_set_v8hi, "V8sV8ssi", "")
+BUILTIN(__builtin_ia32_vec_set_v4hi, "V4sV4ssi", "")
+BUILTIN(__builtin_ia32_vec_set_v16qi, "V16cV16cii", "")
+BUILTIN(__builtin_ia32_vec_set_v4si, "V4iV4iii", "")
+BUILTIN(__builtin_ia32_vec_set_v2di, "V2LLiV2LLiLLii", "")
+BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fi", "")
+
+BUILTIN(__builtin_ia32_loadlv4si, "V4iV2i*", "")
+BUILTIN(__builtin_ia32_storelv4si, "vV2i*V2LLi", "")
+
+BUILTIN(__builtin_ia32_pblendvb128, "V16cV16cV16cV16c", "")
+BUILTIN(__builtin_ia32_pblendw128, "V8sV8sV8si", "")
+BUILTIN(__builtin_ia32_blendpd, "V2dV2dV2di", "")
+BUILTIN(__builtin_ia32_blendps, "V4fV4fV4fi", "")
+BUILTIN(__builtin_ia32_blendvpd, "V2dV2dV2dV2d", "")
+BUILTIN(__builtin_ia32_blendvps, "V4fV4fV4fV4f", "")
+
+BUILTIN(__builtin_ia32_packusdw128, "V8sV4iV4i", "")
+BUILTIN(__builtin_ia32_pmaxsb128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_pmaxsd128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_pmaxud128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_pmaxuw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_pminsb128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_pminsd128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_pminud128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_pminuw128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_pmovsxbd128, "V4iV16c", "")
+BUILTIN(__builtin_ia32_pmovsxbq128, "V2LLiV16c", "")
+BUILTIN(__builtin_ia32_pmovsxbw128, "V8sV16c", "")
+BUILTIN(__builtin_ia32_pmovsxdq128, "V2LLiV4i", "")
+BUILTIN(__builtin_ia32_pmovsxwd128, "V4iV8s", "")
+BUILTIN(__builtin_ia32_pmovsxwq128, "V2LLiV8s", "")
+BUILTIN(__builtin_ia32_pmovzxbd128, "V4iV16c", "")
+BUILTIN(__builtin_ia32_pmovzxbq128, "V2LLiV16c", "")
+BUILTIN(__builtin_ia32_pmovzxbw128, "V8sV16c", "")
+BUILTIN(__builtin_ia32_pmovzxdq128, "V2LLiV4i", "")
+BUILTIN(__builtin_ia32_pmovzxwd128, "V4iV8s", "")
+BUILTIN(__builtin_ia32_pmovzxwq128, "V2LLiV8s", "")
+BUILTIN(__builtin_ia32_pmuldq128, "V2LLiV4iV4i", "")
+BUILTIN(__builtin_ia32_pmulld128, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_roundps, "V4fV4fi", "")
+BUILTIN(__builtin_ia32_roundss, "V4fV4fi", "")
+BUILTIN(__builtin_ia32_roundsd, "V2dV2di", "")
+BUILTIN(__builtin_ia32_roundpd, "V2dV2di", "")
+
+
+#undef BUILTIN
diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h
new file mode 100644
index 000000000000..b41cd684e951
--- /dev/null
+++ b/include/clang/Analysis/Analyses/LiveVariables.h
@@ -0,0 +1,119 @@
+//===- LiveVariables.h - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIVEVARIABLES_H
+#define LLVM_CLANG_LIVEVARIABLES_H
+
+#include "clang/AST/Decl.h"
+#include "clang/Analysis/Support/BlkExprDeclBitVector.h"
+#include "clang/Analysis/FlowSensitive/DataflowValues.h"
+
+namespace clang {
+
+class Stmt;
+class DeclRefExpr;
+class SourceManager;
+
+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;
+
+ AnalysisDataTy() : Observer(NULL) {}
+ };
+
+ //===-----------------------------------------------------===//
+ // ObserverTy - Observer for uninitialized values queries.
+ //===-----------------------------------------------------===//
+
+ struct ObserverTy {
+ virtual ~ObserverTy() {}
+
+ /// ObserveStmt - A callback invoked right before invoking the
+ /// liveness transfer function on the given statement.
+ virtual void ObserveStmt(Stmt* S, 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(ASTContext& Ctx, CFG& cfg);
+
+ /// IsLive - Return true if a variable is live at beginning 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
+ /// 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
+ /// 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, SourceManager& M) const;
+
+ /// dumpBlockLiveness - Print to stderr the liveness information
+ /// associated with each basic block.
+ void dumpBlockLiveness(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);
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h
new file mode 100644
index 000000000000..7a9da03e4bd2
--- /dev/null
+++ b/include/clang/Analysis/Analyses/UninitializedValues.h
@@ -0,0 +1,74 @@
+//===- UninitializedValues.h - unintialized values analysis ----*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides the interface for the Unintialized Values analysis,
+// a flow-sensitive analysis that detects when variable values are unintialized.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_UNITVALS_H
+#define LLVM_CLANG_UNITVALS_H
+
+#include "clang/Analysis/Support/BlkExprDeclBitVector.h"
+#include "clang/Analysis/FlowSensitive/DataflowValues.h"
+
+namespace clang {
+
+ class BlockVarDecl;
+ class Expr;
+ class DeclRefExpr;
+ class VarDecl;
+
+/// UninitializedValues_ValueTypes - Utility class to wrap type declarations
+/// for dataflow values and dataflow analysis state for the
+/// Unitialized Values analysis.
+class UninitializedValues_ValueTypes {
+public:
+
+ struct ObserverTy;
+
+ struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy {
+ AnalysisDataTy() : Observer(NULL), FullUninitTaint(true) {}
+ virtual ~AnalysisDataTy() {};
+
+ ObserverTy* Observer;
+ bool FullUninitTaint;
+ };
+
+ typedef StmtDeclBitVector_Types::ValTy ValTy;
+
+ //===--------------------------------------------------------------------===//
+ // ObserverTy - Observer for querying DeclRefExprs that use an uninitalized
+ // value.
+ //===--------------------------------------------------------------------===//
+
+ struct ObserverTy {
+ virtual ~ObserverTy();
+ virtual void ObserveDeclRefExpr(ValTy& Val, AnalysisDataTy& AD,
+ DeclRefExpr* DR, VarDecl* VD) = 0;
+ };
+};
+
+/// UninitializedValues - Objects of this class encapsulate dataflow analysis
+/// information regarding what variable declarations in a function are
+/// potentially unintialized.
+class UninitializedValues :
+ public DataflowValues<UninitializedValues_ValueTypes> {
+public:
+ typedef UninitializedValues_ValueTypes::ObserverTy ObserverTy;
+
+ UninitializedValues(CFG &cfg) { getAnalysisData().setCFG(cfg); }
+
+ /// IntializeValues - Create initial dataflow values and meta data for
+ /// a given CFG. This is intended to be called by the dataflow solver.
+ void InitializeValues(const CFG& cfg);
+};
+
+} // end namespace clang
+#endif
diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h
new file mode 100644
index 000000000000..e82dc9ed9f3f
--- /dev/null
+++ b/include/clang/Analysis/AnalysisDiagnostic.h
@@ -0,0 +1,27 @@
+//===--- DiagnosticAnalysis.h - Diagnostics for libanalysis -----*- 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_DIAGNOSTICANALYSIS_H
+#define LLVM_CLANG_DIAGNOSTICANALYSIS_H
+
+#include "clang/Basic/Diagnostic.h"
+
+namespace clang {
+ namespace diag {
+ enum {
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM,
+#define ANALYSISSTART
+#include "clang/Basic/DiagnosticAnalysisKinds.inc"
+#undef DIAG
+ NUM_BUILTIN_ANALYSIS_DIAGNOSTICS
+ };
+ } // end namespace diag
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
new file mode 100644
index 000000000000..38612593368b
--- /dev/null
+++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
@@ -0,0 +1,291 @@
+//===--- DataflowSolver.h - Skeleton Dataflow Analysis Code -----*- 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 skeleton code for implementing dataflow analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
+#define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
+
+#include "clang/AST/CFG.h"
+#include "clang/Analysis/ProgramPoint.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "functional" // STL
+
+namespace clang {
+
+//===----------------------------------------------------------------------===//
+/// DataflowWorkListTy - Data structure representing the worklist used for
+/// dataflow algorithms.
+//===----------------------------------------------------------------------===//
+
+class DataflowWorkListTy {
+ typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet;
+ BlockSet wlist;
+public:
+ /// enqueue - Add a block to the worklist. Blocks already on the
+ /// worklist are not added a second time.
+ void enqueue(const CFGBlock* B) { wlist.insert(B); }
+
+ /// dequeue - Remove a block from the worklist.
+ const CFGBlock* dequeue() {
+ assert (!wlist.empty());
+ const CFGBlock* B = *wlist.begin();
+ wlist.erase(B);
+ return B;
+ }
+
+ /// isEmpty - Return true if the worklist is empty.
+ bool isEmpty() const { return wlist.empty(); }
+};
+
+//===----------------------------------------------------------------------===//
+// BlockItrTraits - Traits classes that allow transparent iteration
+// over successors/predecessors of a block depending on the direction
+// of our dataflow analysis.
+//===----------------------------------------------------------------------===//
+
+namespace dataflow {
+template<typename Tag> struct ItrTraits {};
+
+template <> struct ItrTraits<forward_analysis_tag> {
+ typedef CFGBlock::const_pred_iterator PrevBItr;
+ 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 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 BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) {
+ return BlockEdge(Prev, B);
+ }
+
+ static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
+ return BlockEdge(B, Next);
+ }
+};
+
+template <> struct ItrTraits<backward_analysis_tag> {
+ typedef CFGBlock::const_succ_iterator PrevBItr;
+ 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 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 BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) {
+ return BlockEdge(B, Prev);
+ }
+
+ static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
+ return BlockEdge(Next, B);
+ }
+};
+} // end namespace dataflow
+
+//===----------------------------------------------------------------------===//
+/// DataflowSolverTy - Generic dataflow solver.
+//===----------------------------------------------------------------------===//
+
+template <typename _DFValuesTy, // Usually a subclass of DataflowValues
+ typename _TransferFuncsTy,
+ typename _MergeOperatorTy,
+ typename _Equal = std::equal_to<typename _DFValuesTy::ValTy> >
+class DataflowSolver {
+
+ //===----------------------------------------------------===//
+ // Type declarations.
+ //===----------------------------------------------------===//
+
+public:
+ typedef _DFValuesTy DFValuesTy;
+ typedef _TransferFuncsTy TransferFuncsTy;
+ typedef _MergeOperatorTy MergeOperatorTy;
+
+ typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag;
+ typedef typename _DFValuesTy::ValTy ValTy;
+ typedef typename _DFValuesTy::EdgeDataMapTy EdgeDataMapTy;
+ typedef typename _DFValuesTy::BlockDataMapTy BlockDataMapTy;
+
+ typedef dataflow::ItrTraits<AnalysisDirTag> ItrTraits;
+ typedef typename ItrTraits::NextBItr NextBItr;
+ typedef typename ItrTraits::PrevBItr PrevBItr;
+ typedef typename ItrTraits::StmtItr StmtItr;
+
+ //===----------------------------------------------------===//
+ // External interface: constructing and running the solver.
+ //===----------------------------------------------------===//
+
+public:
+ DataflowSolver(DFValuesTy& d) : D(d), TF(d.getAnalysisData()) {}
+ ~DataflowSolver() {}
+
+ /// runOnCFG - Computes dataflow values for all blocks in a CFG.
+ void runOnCFG(CFG& cfg, bool recordStmtValues = false) {
+ // Set initial dataflow values and boundary conditions.
+ D.InitializeValues(cfg);
+ // Solve the dataflow equations. This will populate D.EdgeDataMap
+ // with dataflow values.
+ SolveDataflowEquations(cfg, recordStmtValues);
+ }
+
+ /// runOnBlock - Computes dataflow values for a given block. This
+ /// should usually be invoked only after previously computing
+ /// 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) {
+ BlockDataMapTy& M = D.getBlockDataMap();
+ typename BlockDataMapTy::iterator I = M.find(B);
+
+ if (I != M.end()) {
+ TF.getVal().copyValues(I->second);
+ ProcessBlock(B, recordStmtValues, AnalysisDirTag());
+ }
+ }
+
+ void runOnBlock(const CFGBlock& B, bool recordStmtValues) {
+ runOnBlock(&B, recordStmtValues);
+ }
+ void runOnBlock(CFG::iterator& I, bool recordStmtValues) {
+ runOnBlock(*I, recordStmtValues);
+ }
+ void runOnBlock(CFG::const_iterator& I, bool recordStmtValues) {
+ runOnBlock(*I, recordStmtValues);
+ }
+
+ void runOnAllBlocks(const CFG& cfg, bool recordStmtValues = false) {
+ for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
+ runOnBlock(I, recordStmtValues);
+ }
+
+ //===----------------------------------------------------===//
+ // Internal solver logic.
+ //===----------------------------------------------------===//
+
+private:
+
+ /// SolveDataflowEquations - Perform the actual worklist algorithm
+ /// to compute dataflow values.
+ void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) {
+ // Enqueue all blocks to ensure the dataflow values are computed
+ // for every block. Not all blocks are guaranteed to reach the exit block.
+ for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
+ WorkList.enqueue(&*I);
+
+ while (!WorkList.isEmpty()) {
+ const CFGBlock* B = WorkList.dequeue();
+ ProcessMerge(cfg,B);
+ ProcessBlock(B, recordStmtValues, AnalysisDirTag());
+ UpdateEdges(cfg,B,TF.getVal());
+ }
+ }
+
+ void ProcessMerge(CFG& cfg, const CFGBlock* B) {
+ ValTy& V = TF.getVal();
+ TF.SetTopValue(V);
+
+ // Merge dataflow values from all predecessors of this block.
+ MergeOperatorTy Merge;
+
+ EdgeDataMapTy& M = D.getEdgeDataMap();
+ bool firstMerge = true;
+
+ for (PrevBItr I=ItrTraits::PrevBegin(B),E=ItrTraits::PrevEnd(B); I!=E; ++I){
+
+ typename EdgeDataMapTy::iterator EI =
+ M.find(ItrTraits::PrevEdge(B, *I));
+
+ if (EI != M.end()) {
+ if (firstMerge) {
+ firstMerge = false;
+ V.copyValues(EI->second);
+ }
+ else Merge(V,EI->second);
+ }
+ }
+
+ // Set the data for the block.
+ D.getBlockDataMap()[B].copyValues(V);
+ }
+
+ /// ProcessBlock - Process the transfer functions for a given block.
+ void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
+ dataflow::forward_analysis_tag) {
+
+ for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I)
+ ProcessStmt(*I, recordStmtValues, AnalysisDirTag());
+
+ TF.VisitTerminator(const_cast<CFGBlock*>(B));
+ }
+
+ void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
+ dataflow::backward_analysis_tag) {
+
+ TF.VisitTerminator(const_cast<CFGBlock*>(B));
+
+ for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I)
+ ProcessStmt(*I, recordStmtValues, AnalysisDirTag());
+ }
+
+ 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){
+ TF.BlockStmt_Visit(const_cast<Stmt*>(S));
+ if (record) D.getStmtDataMap()[S] = TF.getVal();
+ }
+
+ /// UpdateEdges - After processing the transfer functions for a
+ /// 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) {
+ for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I)
+ UpdateEdgeValue(ItrTraits::NextEdge(B, *I),V,*I);
+ }
+
+ /// UpdateEdgeValue - Update the value associated with a given edge.
+ void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock* TargetBlock) {
+ EdgeDataMapTy& M = D.getEdgeDataMap();
+ typename EdgeDataMapTy::iterator I = M.find(E);
+
+ if (I == M.end()) { // First computed value for this edge?
+ M[E].copyValues(V);
+ WorkList.enqueue(TargetBlock);
+ }
+ else if (!_Equal()(V,I->second)) {
+ I->second.copyValues(V);
+ WorkList.enqueue(TargetBlock);
+ }
+ }
+
+private:
+ DFValuesTy& D;
+ DataflowWorkListTy WorkList;
+ TransferFuncsTy TF;
+};
+
+} // end namespace clang
+#endif
diff --git a/include/clang/Analysis/FlowSensitive/DataflowValues.h b/include/clang/Analysis/FlowSensitive/DataflowValues.h
new file mode 100644
index 000000000000..d6427a5cab47
--- /dev/null
+++ b/include/clang/Analysis/FlowSensitive/DataflowValues.h
@@ -0,0 +1,172 @@
+//===--- DataflowValues.h - Data structure for dataflow 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 defines a skeleton data structure for encapsulating the dataflow
+// values for a CFG. Typically this is subclassed to provide methods for
+// computing these values from a CFG.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_VALUES
+#define LLVM_CLANG_ANALYSES_DATAFLOW_VALUES
+
+#include "clang/AST/CFG.h"
+#include "clang/Analysis/ProgramPoint.h"
+#include "llvm/ADT/DenseMap.h"
+
+//===----------------------------------------------------------------------===//
+/// Dataflow Directional Tag Classes. These are used for tag dispatching
+/// within the dataflow solver/transfer functions to determine what direction
+/// a dataflow analysis flows.
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+namespace dataflow {
+ struct forward_analysis_tag {};
+ struct backward_analysis_tag {};
+} // end namespace dataflow
+
+//===----------------------------------------------------------------------===//
+/// DataflowValues. Container class to store dataflow values for a CFG.
+//===----------------------------------------------------------------------===//
+
+template <typename ValueTypes,
+ typename _AnalysisDirTag = dataflow::forward_analysis_tag >
+class DataflowValues {
+
+ //===--------------------------------------------------------------------===//
+ // Type declarations.
+ //===--------------------------------------------------------------------===//
+
+public:
+ typedef typename ValueTypes::ValTy ValTy;
+ typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy;
+ typedef _AnalysisDirTag AnalysisDirTag;
+ typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy;
+ typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy;
+ typedef llvm::DenseMap<const Stmt*, ValTy> StmtDataMapTy;
+
+ //===--------------------------------------------------------------------===//
+ // Predicates.
+ //===--------------------------------------------------------------------===//
+
+public:
+ /// isForwardAnalysis - Returns true if the dataflow values are computed
+ /// from a forward analysis.
+ bool isForwardAnalysis() { return isForwardAnalysis(AnalysisDirTag()); }
+
+ /// isBackwardAnalysis - Returns true if the dataflow values are computed
+ /// from a backward analysis.
+ bool isBackwardAnalysis() { return !isForwardAnalysis(); }
+
+private:
+ bool isForwardAnalysis(dataflow::forward_analysis_tag) { return true; }
+ bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; }
+
+ //===--------------------------------------------------------------------===//
+ // Initialization and accessors methods.
+ //===--------------------------------------------------------------------===//
+
+public:
+ DataflowValues() : StmtDataMap(NULL) {}
+ ~DataflowValues() { delete StmtDataMap; }
+
+ /// InitializeValues - Invoked by the solver to initialize state needed for
+ /// dataflow analysis. This method is usually specialized by subclasses.
+ void InitializeValues(const CFG& cfg) {};
+
+
+ /// getEdgeData - Retrieves the dataflow values associated with a
+ /// CFG edge.
+ 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 {
+ return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E);
+ }
+
+ /// getBlockData - Retrieves the dataflow values associated with a
+ /// 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) {
+ 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 {
+ return const_cast<DataflowValues*>(this)->getBlockData(B);
+ }
+
+ /// getStmtData - Retrieves the dataflow values associated with a
+ /// specified Stmt. If the dataflow analysis is a forward analysis,
+ /// this data corresponds to the point immediately before a Stmt.
+ /// 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) {
+ 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 {
+ return const_cast<DataflowValues*>(this)->getStmtData(S);
+ }
+
+ /// getEdgeDataMap - Retrieves the internal map between CFG edges and
+ /// dataflow values. Usually used by a dataflow solver to compute
+ /// values for blocks.
+ EdgeDataMapTy& getEdgeDataMap() { return EdgeDataMap; }
+ const EdgeDataMapTy& getEdgeDataMap() const { return EdgeDataMap; }
+
+ /// getBlockDataMap - Retrieves the internal map between CFGBlocks and
+ /// dataflow values. If the dataflow analysis operates in the forward
+ /// direction, the values correspond to the dataflow values at the start
+ /// of the block. Otherwise, for a backward analysis, the values correpsond
+ /// to the dataflow values at the end of the block.
+ BlockDataMapTy& getBlockDataMap() { return BlockDataMap; }
+ const BlockDataMapTy& getBlockDataMap() const { return BlockDataMap; }
+
+ /// getStmtDataMap - Retrieves the internal map between Stmts and
+ /// dataflow values.
+ StmtDataMapTy& getStmtDataMap() {
+ if (!StmtDataMap) StmtDataMap = new StmtDataMapTy();
+ return *StmtDataMap;
+ }
+
+ const StmtDataMapTy& getStmtDataMap() const {
+ return const_cast<DataflowValues*>(this)->getStmtDataMap();
+ }
+
+ /// getAnalysisData - Retrieves the meta data associated with a
+ /// dataflow analysis for analyzing a particular CFG.
+ /// This is typically consumed by transfer function code (via the solver).
+ /// This can also be used by subclasses to interpret the dataflow values.
+ AnalysisDataTy& getAnalysisData() { return AnalysisData; }
+ const AnalysisDataTy& getAnalysisData() const { return AnalysisData; }
+
+ //===--------------------------------------------------------------------===//
+ // Internal data.
+ //===--------------------------------------------------------------------===//
+
+protected:
+ EdgeDataMapTy EdgeDataMap;
+ BlockDataMapTy BlockDataMap;
+ StmtDataMapTy* StmtDataMap;
+ AnalysisDataTy AnalysisData;
+};
+
+} // end namespace clang
+#endif
diff --git a/include/clang/Analysis/LocalCheckers.h b/include/clang/Analysis/LocalCheckers.h
new file mode 100644
index 000000000000..23610f9a2d97
--- /dev/null
+++ b/include/clang/Analysis/LocalCheckers.h
@@ -0,0 +1,54 @@
+//==- LocalCheckers.h - Intra-Procedural+Flow-Sensitive 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 the interface to call a set of intra-procedural (local)
+// checkers that use flow/path-sensitive analyses to find bugs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_LOCALCHECKERS_H
+#define LLVM_CLANG_ANALYSIS_LOCALCHECKERS_H
+
+namespace clang {
+
+class CFG;
+class Decl;
+class Diagnostic;
+class ASTContext;
+class PathDiagnosticClient;
+class GRTransferFuncs;
+class BugType;
+class LangOptions;
+class ParentMap;
+class LiveVariables;
+class BugReporter;
+class ObjCImplementationDecl;
+class LangOptions;
+class GRExprEngine;
+
+void CheckDeadStores(LiveVariables& L, BugReporter& BR);
+
+void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags,
+ bool FullUninitTaint=false);
+
+GRTransferFuncs* MakeGRSimpleValsTF();
+GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
+ const LangOptions& lopts);
+
+void CheckObjCDealloc(ObjCImplementationDecl* D, const LangOptions& L,
+ BugReporter& BR);
+
+void CheckObjCInstMethSignature(ObjCImplementationDecl* ID, BugReporter& BR);
+void CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR);
+
+void RegisterAppleChecks(GRExprEngine& Eng);
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Analysis/PathDiagnostic.h b/include/clang/Analysis/PathDiagnostic.h
new file mode 100644
index 000000000000..994b35e5efda
--- /dev/null
+++ b/include/clang/Analysis/PathDiagnostic.h
@@ -0,0 +1,487 @@
+//===--- PathDiagnostic.h - Path-Specific Diagnostic Handling ---*- 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 PathDiagnostic-related interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H
+#define LLVM_CLANG_PATH_DIAGNOSTIC_H
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/OwningPtr.h"
+
+#include <vector>
+#include <deque>
+#include <string>
+#include <algorithm>
+
+namespace clang {
+
+//===----------------------------------------------------------------------===//
+// High-level interface for handlers of path-sensitive diagnostics.
+//===----------------------------------------------------------------------===//
+
+class PathDiagnostic;
+class Stmt;
+class Decl;
+class Preprocessor;
+
+class PathDiagnosticClient : public DiagnosticClient {
+public:
+ PathDiagnosticClient() {}
+ virtual ~PathDiagnosticClient() {}
+
+ virtual void SetPreprocessor(Preprocessor *PP) {}
+
+ virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info);
+
+ virtual void HandlePathDiagnostic(const PathDiagnostic* D) = 0;
+
+ 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; }
+};
+
+//===----------------------------------------------------------------------===//
+// Path-sensitive diagnostics.
+//===----------------------------------------------------------------------===//
+
+class PathDiagnosticRange : public SourceRange {
+public:
+ const bool isPoint;
+
+ PathDiagnosticRange(const SourceRange &R, bool isP = false)
+ : SourceRange(R), isPoint(isP) {}
+};
+
+class PathDiagnosticLocation {
+private:
+ enum Kind { RangeK, SingleLocK, StmtK, DeclK } K;
+ SourceRange R;
+ const Stmt *S;
+ const Decl *D;
+ const SourceManager *SM;
+public:
+ PathDiagnosticLocation()
+ : K(SingleLocK), S(0), D(0), SM(0) {}
+
+ PathDiagnosticLocation(FullSourceLoc L)
+ : K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()) {}
+
+ PathDiagnosticLocation(const Stmt *s, const SourceManager &sm)
+ : K(StmtK), S(s), D(0), SM(&sm) {}
+
+ PathDiagnosticLocation(SourceRange r, const SourceManager &sm)
+ : K(RangeK), R(r), S(0), D(0), SM(&sm) {}
+
+ PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
+ : K(DeclK), S(0), D(d), SM(&sm) {}
+
+ bool operator==(const PathDiagnosticLocation &X) const {
+ return K == X.K && R == X.R && S == X.S && D == X.D;
+ }
+
+ 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;
+ }
+
+ bool isValid() const {
+ return SM != 0;
+ }
+
+ const SourceManager& getSourceManager() const { assert(isValid());return *SM;}
+
+ FullSourceLoc asLocation() const;
+ PathDiagnosticRange asRange() const;
+ const Stmt *asStmt() const { assert(isValid()); return S; }
+ const Decl *asDecl() const { assert(isValid()); return D; }
+
+ bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
+
+ void invalidate() {
+ *this = PathDiagnosticLocation();
+ }
+
+ void flatten();
+
+ const SourceManager& getManager() const { assert(isValid()); return *SM; }
+};
+
+class PathDiagnosticLocationPair {
+private:
+ PathDiagnosticLocation Start, End;
+public:
+ PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
+ const PathDiagnosticLocation &end)
+ : Start(start), End(end) {}
+
+ const PathDiagnosticLocation &getStart() const { return Start; }
+ const PathDiagnosticLocation &getEnd() const { return End; }
+
+ void flatten() {
+ Start.flatten();
+ End.flatten();
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// Path "pieces" for path-sensitive diagnostics.
+//===----------------------------------------------------------------------===//
+
+class PathDiagnosticPiece {
+public:
+ enum Kind { ControlFlow, Event, Macro };
+ enum DisplayHint { Above, Below };
+
+private:
+ const std::string str;
+ std::vector<CodeModificationHint> CodeModificationHints;
+ const Kind kind;
+ const DisplayHint Hint;
+ std::vector<SourceRange> ranges;
+
+ // Do not implement:
+ PathDiagnosticPiece();
+ PathDiagnosticPiece(const PathDiagnosticPiece &P);
+ PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P);
+
+protected:
+ PathDiagnosticPiece(const std::string& s, Kind k, DisplayHint hint = Below);
+
+ PathDiagnosticPiece(const char* s, Kind k, DisplayHint hint = Below);
+
+ PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
+
+public:
+ virtual ~PathDiagnosticPiece();
+
+ const std::string& getString() const { return str; }
+
+ /// getDisplayHint - Return a hint indicating where the diagnostic should
+ /// be displayed by the PathDiagnosticClient.
+ DisplayHint getDisplayHint() const { return Hint; }
+
+ virtual PathDiagnosticLocation getLocation() const = 0;
+ virtual void flattenLocations() = 0;
+
+ Kind getKind() const { return kind; }
+
+ void addRange(SourceRange R) { ranges.push_back(R); }
+
+ void addRange(SourceLocation B, SourceLocation E) {
+ ranges.push_back(SourceRange(B,E));
+ }
+
+ void addCodeModificationHint(const CodeModificationHint& Hint) {
+ CodeModificationHints.push_back(Hint);
+ }
+
+ typedef const SourceRange* range_iterator;
+
+ range_iterator ranges_begin() const {
+ return ranges.empty() ? NULL : &ranges[0];
+ }
+
+ range_iterator ranges_end() const {
+ return ranges_begin() + ranges.size();
+ }
+
+ typedef const CodeModificationHint *code_modifications_iterator;
+
+ code_modifications_iterator code_modifications_begin() const {
+ return CodeModificationHints.empty()? 0 : &CodeModificationHints[0];
+ }
+
+ code_modifications_iterator code_modifications_end() const {
+ return CodeModificationHints.empty()? 0
+ : &CodeModificationHints[0] + CodeModificationHints.size();
+ }
+
+ static inline bool classof(const PathDiagnosticPiece* P) {
+ return true;
+ }
+};
+
+class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
+private:
+ PathDiagnosticLocation Pos;
+public:
+ PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
+ const std::string& s,
+ PathDiagnosticPiece::Kind k,
+ bool addPosRange = true)
+ : PathDiagnosticPiece(s, k), Pos(pos) {
+ assert(Pos.asLocation().isValid() &&
+ "PathDiagnosticSpotPiece's must have a valid location.");
+ if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
+ }
+
+ PathDiagnosticLocation getLocation() const { return Pos; }
+ virtual void flattenLocations() { Pos.flatten(); }
+};
+
+class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
+
+public:
+ PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
+ const std::string& s, bool addPosRange = true)
+ : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
+
+ PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, const char* s,
+ bool addPosRange = true)
+ : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
+
+ ~PathDiagnosticEventPiece();
+
+ static inline bool classof(const PathDiagnosticPiece* P) {
+ return P->getKind() == Event;
+ }
+};
+
+class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
+ std::vector<PathDiagnosticLocationPair> LPairs;
+public:
+ PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
+ const PathDiagnosticLocation &endPos,
+ const std::string& s)
+ : PathDiagnosticPiece(s, ControlFlow) {
+ LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
+ }
+
+ PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
+ const PathDiagnosticLocation &endPos,
+ const char* s)
+ : PathDiagnosticPiece(s, ControlFlow) {
+ LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
+ }
+
+ PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
+ const PathDiagnosticLocation &endPos)
+ : PathDiagnosticPiece(ControlFlow) {
+ LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
+ }
+
+ ~PathDiagnosticControlFlowPiece();
+
+ PathDiagnosticLocation getStartLocation() const {
+ assert(!LPairs.empty() &&
+ "PathDiagnosticControlFlowPiece needs at least one location.");
+ return LPairs[0].getStart();
+ }
+
+ PathDiagnosticLocation getEndLocation() const {
+ assert(!LPairs.empty() &&
+ "PathDiagnosticControlFlowPiece needs at least one location.");
+ return LPairs[0].getEnd();
+ }
+
+ void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
+
+ virtual PathDiagnosticLocation getLocation() const {
+ return getStartLocation();
+ }
+
+ typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
+ iterator begin() { return LPairs.begin(); }
+ iterator end() { return LPairs.end(); }
+
+ virtual void flattenLocations() {
+ for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
+ }
+
+ typedef std::vector<PathDiagnosticLocationPair>::const_iterator
+ const_iterator;
+ const_iterator begin() const { return LPairs.begin(); }
+ const_iterator end() const { return LPairs.end(); }
+
+ static inline bool classof(const PathDiagnosticPiece* P) {
+ return P->getKind() == ControlFlow;
+ }
+};
+
+class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
+ std::vector<PathDiagnosticPiece*> SubPieces;
+public:
+ PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
+ : PathDiagnosticSpotPiece(pos, "", Macro) {}
+
+ ~PathDiagnosticMacroPiece();
+
+ bool containsEvent() const;
+
+ void push_back(PathDiagnosticPiece* P) { SubPieces.push_back(P); }
+
+ typedef std::vector<PathDiagnosticPiece*>::iterator iterator;
+ iterator begin() { return SubPieces.begin(); }
+ iterator end() { return SubPieces.end(); }
+
+ virtual void flattenLocations() {
+ PathDiagnosticSpotPiece::flattenLocations();
+ for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->flattenLocations();
+ }
+
+ typedef std::vector<PathDiagnosticPiece*>::const_iterator const_iterator;
+ const_iterator begin() const { return SubPieces.begin(); }
+ const_iterator end() const { return SubPieces.end(); }
+
+ static inline bool classof(const PathDiagnosticPiece* P) {
+ return P->getKind() == Macro;
+ }
+};
+
+/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
+/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
+/// each which represent the pieces of the path.
+class PathDiagnostic {
+ std::deque<PathDiagnosticPiece*> path;
+ unsigned Size;
+ std::string BugType;
+ std::string Desc;
+ std::string Category;
+ std::deque<std::string> OtherDesc;
+
+public:
+ PathDiagnostic();
+
+ PathDiagnostic(const char* bugtype, const char* desc, const char* category);
+
+ PathDiagnostic(const std::string& bugtype, const std::string& desc,
+ const std::string& category);
+
+ ~PathDiagnostic();
+
+ const std::string& getDescription() const { return Desc; }
+ const std::string& getBugType() const { return BugType; }
+ const std::string& 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(const std::string& s) { OtherDesc.push_back(s); }
+ void addMeta(const char* 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) {
+ path.push_front(piece);
+ ++Size;
+ }
+
+ void push_back(PathDiagnosticPiece* piece) {
+ path.push_back(piece);
+ ++Size;
+ }
+
+ PathDiagnosticPiece* back() {
+ return path.back();
+ }
+
+ const PathDiagnosticPiece* back() const {
+ return path.back();
+ }
+
+ unsigned size() const { return Size; }
+ bool empty() const { return Size == 0; }
+
+ void resetPath(bool deletePieces = true);
+
+ class iterator {
+ public:
+ typedef std::deque<PathDiagnosticPiece*>::iterator ImplTy;
+
+ typedef PathDiagnosticPiece value_type;
+ typedef value_type& reference;
+ typedef value_type* pointer;
+ typedef ptrdiff_t difference_type;
+ typedef std::bidirectional_iterator_tag iterator_category;
+
+ private:
+ ImplTy I;
+
+ 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; }
+
+ PathDiagnosticPiece& operator*() const { return **I; }
+ PathDiagnosticPiece* operator->() const { return *I; }
+
+ iterator& operator++() { ++I; return *this; }
+ iterator& operator--() { --I; return *this; }
+ };
+
+ class const_iterator {
+ public:
+ typedef std::deque<PathDiagnosticPiece*>::const_iterator ImplTy;
+
+ typedef const PathDiagnosticPiece value_type;
+ typedef value_type& reference;
+ typedef value_type* pointer;
+ typedef ptrdiff_t difference_type;
+ typedef std::bidirectional_iterator_tag iterator_category;
+
+ private:
+ ImplTy I;
+
+ 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; }
+
+ reference operator*() const { return **I; }
+ pointer operator->() const { return *I; }
+
+ const_iterator& operator++() { ++I; return *this; }
+ const_iterator& operator--() { --I; return *this; }
+ };
+
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ // forward iterator creation methods.
+
+ iterator begin() { return path.begin(); }
+ iterator end() { return path.end(); }
+
+ const_iterator begin() const { return path.begin(); }
+ const_iterator end() const { return path.end(); }
+
+ // reverse iterator creation methods.
+ reverse_iterator rbegin() { return reverse_iterator(end()); }
+ const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
+ reverse_iterator rend() { return reverse_iterator(begin()); }
+ const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
+
+ void flattenLocations() {
+ for (iterator I = begin(), E = end(); I != E; ++I) I->flattenLocations();
+ }
+};
+
+
+} //end clang namespace
+#endif
diff --git a/include/clang/Analysis/PathSensitive/BasicValueFactory.h b/include/clang/Analysis/PathSensitive/BasicValueFactory.h
new file mode 100644
index 000000000000..b694e9b29940
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/BasicValueFactory.h
@@ -0,0 +1,163 @@
+//=== BasicValueFactory.h - Basic values for Path Sens 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 BasicValueFactory, a class that manages the lifetime
+// of APSInt objects and symbolic constraints used by GRExprEngine
+// and related classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
+#define LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
+
+#include "clang/Analysis/PathSensitive/SymbolManager.h"
+#include "clang/Analysis/PathSensitive/SVals.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/ImmutableList.h"
+
+namespace clang {
+
+class CompoundValData : public llvm::FoldingSetNode {
+ QualType T;
+ llvm::ImmutableList<SVal> L;
+
+public:
+ CompoundValData(QualType t, llvm::ImmutableList<SVal> l)
+ : T(t), L(l) {}
+
+ typedef llvm::ImmutableList<SVal>::iterator iterator;
+ iterator begin() const { return L.begin(); }
+ iterator end() const { return L.end(); }
+
+ static void Profile(llvm::FoldingSetNodeID& ID, QualType T,
+ llvm::ImmutableList<SVal> L);
+
+ void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, T, L); }
+};
+
+class BasicValueFactory {
+ typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
+ APSIntSetTy;
+
+ ASTContext& Ctx;
+ llvm::BumpPtrAllocator& BPAlloc;
+
+ APSIntSetTy APSIntSet;
+ void* PersistentSVals;
+ void* PersistentSValPairs;
+
+ llvm::ImmutableList<SVal>::Factory SValListFactory;
+ llvm::FoldingSet<CompoundValData> CompoundValDataSet;
+
+public:
+ BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc)
+ : Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0),
+ SValListFactory(Alloc) {}
+
+ ~BasicValueFactory();
+
+ ASTContext& getContext() const { return Ctx; }
+
+ const llvm::APSInt& getValue(const llvm::APSInt& X);
+ const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned);
+ const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
+ const llvm::APSInt& getValue(uint64_t X, QualType T);
+
+ /// Convert - Create a new persistent APSInt with the same value as 'From'
+ /// but with the bitwidth and signedness of 'To'.
+ const llvm::APSInt& Convert(const llvm::APSInt& To,
+ const llvm::APSInt& From) {
+
+ if (To.isUnsigned() == From.isUnsigned() &&
+ To.getBitWidth() == From.getBitWidth())
+ return From;
+
+ return getValue(From.getSExtValue(),
+ To.getBitWidth(),
+ To.isUnsigned());
+ }
+
+ const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) {
+ QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy;
+ return getValue(X, T);
+ }
+
+ inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) {
+ return getValue(llvm::APSInt::getMaxValue(v.getBitWidth(), v.isUnsigned()));
+ }
+
+ inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) {
+ return getValue(llvm::APSInt::getMinValue(v.getBitWidth(), v.isUnsigned()));
+ }
+
+ inline const llvm::APSInt& getMaxValue(QualType T) {
+ assert(T->isIntegerType() || Loc::IsLocType(T));
+ bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T);
+ return getValue(llvm::APSInt::getMaxValue(Ctx.getTypeSize(T), isUnsigned));
+ }
+
+ inline const llvm::APSInt& getMinValue(QualType T) {
+ assert(T->isIntegerType() || Loc::IsLocType(T));
+ bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T);
+ return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned));
+ }
+
+ inline const llvm::APSInt& Add1(const llvm::APSInt& V) {
+ llvm::APSInt X = V;
+ ++X;
+ return getValue(X);
+ }
+
+ inline const llvm::APSInt& Sub1(const llvm::APSInt& V) {
+ llvm::APSInt X = V;
+ --X;
+ return getValue(X);
+ }
+
+ inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) {
+ return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
+ }
+
+ inline const llvm::APSInt& getTruthValue(bool b, QualType T) {
+ return getValue(b ? 1 : 0, Ctx.getTypeSize(T), false);
+ }
+
+ inline const llvm::APSInt& getTruthValue(bool b) {
+ return getTruthValue(b, Ctx.IntTy);
+ }
+
+ const CompoundValData* getCompoundValData(QualType T,
+ llvm::ImmutableList<SVal> Vals);
+
+ llvm::ImmutableList<SVal> getEmptySValList() {
+ return SValListFactory.GetEmptyList();
+ }
+
+ llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) {
+ return SValListFactory.Add(X, L);
+ }
+
+ const llvm::APSInt* EvaluateAPSInt(BinaryOperator::Opcode Op,
+ const llvm::APSInt& V1,
+ const llvm::APSInt& V2);
+
+ const std::pair<SVal, uintptr_t>&
+ getPersistentSValWithData(const SVal& V, uintptr_t Data);
+
+ const std::pair<SVal, SVal>&
+ getPersistentSValPair(const SVal& V1, const SVal& V2);
+
+ const SVal* getPersistentSVal(SVal X);
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h
new file mode 100644
index 000000000000..90fd9d8ebf45
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/BugReporter.h
@@ -0,0 +1,466 @@
+//===--- BugReporter.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 defines BugReporter, a utility class for generating
+// PathDiagnostics for analyses based on GRState.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_BUGREPORTER
+#define LLVM_CLANG_ANALYSIS_BUGREPORTER
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/ImmutableSet.h"
+#include <list>
+
+namespace clang {
+
+class PathDiagnostic;
+class PathDiagnosticPiece;
+class PathDiagnosticClient;
+class ASTContext;
+class Diagnostic;
+class BugReporter;
+class BugReporterContext;
+class GRExprEngine;
+class GRState;
+class Stmt;
+class BugType;
+class ParentMap;
+
+//===----------------------------------------------------------------------===//
+// Interface for individual bug reports.
+//===----------------------------------------------------------------------===//
+
+class BugReporterVisitor {
+public:
+ virtual ~BugReporterVisitor();
+ virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N,
+ const ExplodedNode<GRState>* PrevN,
+ BugReporterContext& BRC) = 0;
+
+ virtual bool isOwnedByReporterContext() { return true; }
+};
+
+// FIXME: Combine this with RangedBugReport and remove RangedBugReport.
+class BugReport : public BugReporterVisitor {
+protected:
+ BugType& BT;
+ std::string ShortDescription;
+ std::string Description;
+ const ExplodedNode<GRState> *EndNode;
+ SourceRange R;
+
+protected:
+ friend class BugReporter;
+ friend class BugReportEquivClass;
+
+ virtual void Profile(llvm::FoldingSetNodeID& hash) const {
+ hash.AddInteger(getLocation().getRawEncoding());
+ }
+
+public:
+ class NodeResolver {
+ public:
+ virtual ~NodeResolver() {}
+ virtual const ExplodedNode<GRState>*
+ getOriginalNode(const ExplodedNode<GRState>* N) = 0;
+ };
+
+ BugReport(BugType& bt, const char* desc, const ExplodedNode<GRState> *n)
+ : BT(bt), Description(desc), EndNode(n) {}
+
+ BugReport(BugType& bt, const char* shortDesc, const char* desc,
+ const ExplodedNode<GRState> *n)
+ : BT(bt), ShortDescription(shortDesc), Description(desc), EndNode(n) {}
+
+ virtual ~BugReport();
+
+ virtual bool isOwnedByReporterContext() { return false; }
+
+ const BugType& getBugType() const { return BT; }
+ BugType& getBugType() { return BT; }
+
+ // FIXME: Perhaps this should be moved into a subclass?
+ const ExplodedNode<GRState>* getEndNode() const { return EndNode; }
+
+ // 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.
+ Stmt* getStmt(BugReporter& BR) const;
+
+ const std::string& getDescription() const { return Description; }
+
+ const std::string& 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);
+ }
+
+ // FIXME: Perhaps move this into a subclass.
+ virtual PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N);
+
+ /// getLocation - 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 occured.
+ /// This location is used by clients rendering diagnostics.
+ virtual SourceLocation getLocation() const;
+
+ /// getRanges - Returns the source ranges associated with this bug.
+ virtual void getRanges(BugReporter& BR,const SourceRange*& beg,
+ const SourceRange*& end);
+
+ virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N,
+ const ExplodedNode<GRState>* PrevN,
+ BugReporterContext& BR);
+
+ virtual void registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N) {}
+};
+
+//===----------------------------------------------------------------------===//
+// BugTypes (collections of related reports).
+//===----------------------------------------------------------------------===//
+
+class BugReportEquivClass : public llvm::FoldingSetNode {
+ // List of *owned* BugReport objects.
+ std::list<BugReport*> Reports;
+
+ friend class BugReporter;
+ void AddReport(BugReport* R) { Reports.push_back(R); }
+public:
+ BugReportEquivClass(BugReport* R) { Reports.push_back(R); }
+ ~BugReportEquivClass();
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ assert(!Reports.empty());
+ (*Reports.begin())->Profile(ID);
+ }
+
+ class iterator {
+ 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; }
+ BugReport* operator*() const { return *impl; }
+ BugReport* operator->() const { return *impl; }
+ };
+
+ class const_iterator {
+ 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 BugReport* operator*() const { return *impl; }
+ const BugReport* operator->() const { return *impl; }
+ };
+
+ iterator begin() { return iterator(Reports.begin()); }
+ iterator end() { return iterator(Reports.end()); }
+
+ const_iterator begin() const { return const_iterator(Reports.begin()); }
+ const_iterator end() const { return const_iterator(Reports.end()); }
+};
+
+class BugType {
+private:
+ const std::string Name;
+ const std::string Category;
+ llvm::FoldingSet<BugReportEquivClass> EQClasses;
+ friend class BugReporter;
+public:
+ BugType(const char *name, const char* cat) : Name(name), Category(cat) {}
+ virtual ~BugType();
+
+ // FIXME: Should these be made strings as well?
+ const std::string& getName() const { return Name; }
+ const std::string& getCategory() const { return Category; }
+
+ virtual void FlushReports(BugReporter& BR);
+ void AddReport(BugReport* BR);
+
+ typedef llvm::FoldingSet<BugReportEquivClass>::iterator iterator;
+ iterator begin() { return EQClasses.begin(); }
+ iterator end() { return EQClasses.end(); }
+
+ typedef llvm::FoldingSet<BugReportEquivClass>::const_iterator const_iterator;
+ const_iterator begin() const { return EQClasses.begin(); }
+ const_iterator end() const { return EQClasses.end(); }
+};
+
+//===----------------------------------------------------------------------===//
+// Specialized subclasses of BugReport.
+//===----------------------------------------------------------------------===//
+
+// FIXME: Collapse this with the default BugReport class.
+class RangedBugReport : public BugReport {
+ std::vector<SourceRange> Ranges;
+public:
+ RangedBugReport(BugType& D, const char* description, ExplodedNode<GRState> *n)
+ : BugReport(D, description, n) {}
+
+ RangedBugReport(BugType& D, const char *shortDescription,
+ const char *description, ExplodedNode<GRState> *n)
+ : BugReport(D, shortDescription, description, n) {}
+
+ ~RangedBugReport();
+
+ // FIXME: Move this out of line.
+ void addRange(SourceRange R) { Ranges.push_back(R); }
+
+ // FIXME: Move this out of line.
+ void getRanges(BugReporter& BR,const SourceRange*& beg,
+ const SourceRange*& end) {
+
+ if (Ranges.empty()) {
+ beg = NULL;
+ end = NULL;
+ }
+ else {
+ beg = &Ranges[0];
+ end = beg + Ranges.size();
+ }
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// BugReporter and friends.
+//===----------------------------------------------------------------------===//
+
+class BugReporterData {
+public:
+ virtual ~BugReporterData();
+ virtual Diagnostic& getDiagnostic() = 0;
+ virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
+ virtual ASTContext& getContext() = 0;
+ virtual SourceManager& getSourceManager() = 0;
+ virtual CFG* getCFG() = 0;
+ virtual ParentMap& getParentMap() = 0;
+ virtual LiveVariables* getLiveVariables() = 0;
+};
+
+class BugReporter {
+public:
+ enum Kind { BaseBRKind, GRBugReporterKind };
+
+private:
+ typedef llvm::ImmutableSet<BugType*> BugTypesTy;
+ BugTypesTy::Factory F;
+ BugTypesTy BugTypes;
+
+ const Kind kind;
+ BugReporterData& D;
+
+ void FlushReport(BugReportEquivClass& EQ);
+
+protected:
+ BugReporter(BugReporterData& d, Kind k) : BugTypes(F.GetEmptySet()), kind(k), D(d) {}
+
+public:
+ BugReporter(BugReporterData& d) : BugTypes(F.GetEmptySet()), kind(BaseBRKind), D(d) {}
+ virtual ~BugReporter();
+
+ void FlushReports();
+
+ Kind getKind() const { return kind; }
+
+ Diagnostic& getDiagnostic() {
+ return D.getDiagnostic();
+ }
+
+ PathDiagnosticClient* getPathDiagnosticClient() {
+ return D.getPathDiagnosticClient();
+ }
+
+ typedef BugTypesTy::iterator iterator;
+ iterator begin() { return BugTypes.begin(); }
+ iterator end() { return BugTypes.end(); }
+
+ ASTContext& getContext() { return D.getContext(); }
+
+ SourceManager& getSourceManager() { return D.getSourceManager(); }
+
+ CFG* getCFG() { return D.getCFG(); }
+
+ ParentMap& getParentMap() { return D.getParentMap(); }
+
+ LiveVariables* getLiveVariables() { return D.getLiveVariables(); }
+
+ virtual void GeneratePathDiagnostic(PathDiagnostic& PD,
+ BugReportEquivClass& EQ) {}
+
+ void Register(BugType *BT);
+
+ void EmitReport(BugReport *R);
+
+ void EmitBasicReport(const char* BugName, const char* BugStr,
+ SourceLocation Loc,
+ SourceRange* RangeBeg, unsigned NumRanges);
+
+ void EmitBasicReport(const char* BugName, const char* BugCategory,
+ const char* BugStr, SourceLocation Loc,
+ SourceRange* RangeBeg, unsigned NumRanges);
+
+
+ void EmitBasicReport(const char* BugName, const char* BugStr,
+ SourceLocation Loc) {
+ EmitBasicReport(BugName, BugStr, Loc, 0, 0);
+ }
+
+ void EmitBasicReport(const char* BugName, const char* BugCategory,
+ const char* BugStr, SourceLocation Loc) {
+ EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
+ }
+
+ void EmitBasicReport(const char* BugName, const char* BugStr,
+ SourceLocation Loc, SourceRange R) {
+ EmitBasicReport(BugName, BugStr, Loc, &R, 1);
+ }
+
+ void EmitBasicReport(const char* BugName, const char* Category,
+ const char* BugStr, SourceLocation Loc, SourceRange R) {
+ EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
+ }
+
+ static bool classof(const BugReporter* R) { return true; }
+};
+
+// FIXME: Get rid of GRBugReporter. It's the wrong abstraction.
+class GRBugReporter : public BugReporter {
+ GRExprEngine& Eng;
+ llvm::SmallSet<SymbolRef, 10> NotableSymbols;
+public:
+ GRBugReporter(BugReporterData& d, GRExprEngine& eng)
+ : BugReporter(d, GRBugReporterKind), Eng(eng) {}
+
+ virtual ~GRBugReporter();
+
+ /// getEngine - Return the analysis engine used to analyze a given
+ /// function or method.
+ GRExprEngine& getEngine() { return Eng; }
+
+ /// getGraph - Get the exploded graph created by the analysis engine
+ /// for the analyzed method or function.
+ ExplodedGraph<GRState>& getGraph();
+
+ /// getStateManager - Return the state manager used by the analysis
+ /// engine.
+ GRStateManager& getStateManager();
+
+ virtual void GeneratePathDiagnostic(PathDiagnostic& PD,
+ BugReportEquivClass& R);
+
+ void addNotableSymbol(SymbolRef Sym) {
+ NotableSymbols.insert(Sym);
+ }
+
+ bool isNotable(SymbolRef Sym) const {
+ return (bool) NotableSymbols.count(Sym);
+ }
+
+ /// classof - Used by isa<>, cast<>, and dyn_cast<>.
+ static bool classof(const BugReporter* R) {
+ return R->getKind() == GRBugReporterKind;
+ }
+};
+
+class BugReporterContext {
+ GRBugReporter &BR;
+ std::vector<BugReporterVisitor*> Callbacks;
+public:
+ BugReporterContext(GRBugReporter& br) : BR(br) {}
+ virtual ~BugReporterContext();
+
+ void addVisitor(BugReporterVisitor* visitor) {
+ if (visitor) Callbacks.push_back(visitor);
+ }
+
+ typedef std::vector<BugReporterVisitor*>::iterator visitor_iterator;
+ visitor_iterator visitor_begin() { return Callbacks.begin(); }
+ visitor_iterator visitor_end() { return Callbacks.end(); }
+
+ GRBugReporter& getBugReporter() { return BR; }
+
+ ExplodedGraph<GRState>& getGraph() { return BR.getGraph(); }
+
+ void addNotableSymbol(SymbolRef Sym) {
+ // FIXME: For now forward to GRBugReporter.
+ BR.addNotableSymbol(Sym);
+ }
+
+ bool isNotable(SymbolRef Sym) const {
+ // FIXME: For now forward to GRBugReporter.
+ return BR.isNotable(Sym);
+ }
+
+ GRStateManager& getStateManager() {
+ return BR.getStateManager();
+ }
+
+ ValueManager& getValueManager() {
+ return getStateManager().getValueManager();
+ }
+
+ ASTContext& getASTContext() {
+ return BR.getContext();
+ }
+
+ SourceManager& getSourceManager() {
+ return BR.getSourceManager();
+ }
+
+ const Decl& getCodeDecl() {
+ return getStateManager().getCodeDecl();
+ }
+
+ const CFG& getCFG() {
+ return *BR.getCFG();
+ }
+
+ virtual BugReport::NodeResolver& getNodeResolver() = 0;
+};
+
+class DiagBugReport : public RangedBugReport {
+ std::list<std::string> Strs;
+ FullSourceLoc L;
+public:
+ DiagBugReport(BugType& D, const char* 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(const std::string& 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(); }
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/ConstraintManager.h b/include/clang/Analysis/PathSensitive/ConstraintManager.h
new file mode 100644
index 000000000000..c8e5e85c8a1a
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/ConstraintManager.h
@@ -0,0 +1,67 @@
+//== ConstraintManager.h - Constraints on symbolic values.-------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defined the interface to manage constraints on symbolic values.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H
+#define LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H
+
+// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place.
+#include "clang/Analysis/PathSensitive/Store.h"
+
+namespace llvm {
+class APSInt;
+}
+
+namespace clang {
+
+class GRState;
+class GRStateManager;
+class SVal;
+
+class ConstraintManager {
+public:
+ virtual ~ConstraintManager();
+ virtual const GRState* Assume(const GRState* St, SVal Cond,
+ bool Assumption, bool& isFeasible) = 0;
+
+ virtual const GRState* AssumeInBound(const GRState* St, SVal Idx,
+ SVal UpperBound, bool Assumption,
+ bool& isFeasible) = 0;
+
+ virtual const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym)
+ const = 0;
+
+ virtual bool isEqual(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V) const = 0;
+
+ virtual const GRState* RemoveDeadBindings(const GRState* St,
+ SymbolReaper& SymReaper) = 0;
+
+ virtual void print(const GRState* St, std::ostream& Out,
+ const char* nl, const char *sep) = 0;
+
+ virtual void EndPath(const GRState* St) {}
+
+ /// canReasonAbout - Not all ConstraintManagers can accurately reason about
+ /// all SVal values. This method returns true if the ConstraintManager can
+ /// reasonably handle a given SVal value. This is typically queried by
+ /// GRExprEngine to determine if the value should be replaced with a
+ /// conjured symbolic value in order to recover some precision.
+ virtual bool canReasonAbout(SVal X) const = 0;
+};
+
+ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr);
+ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr);
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/Environment.h b/include/clang/Analysis/PathSensitive/Environment.h
new file mode 100644
index 000000000000..fde8b167f3c7
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/Environment.h
@@ -0,0 +1,151 @@
+//== Environment.h - Map from Stmt* to Locations/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 Environment and EnvironmentManager classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ENVIRONMENT_H
+#define LLVM_CLANG_ANALYSIS_ENVIRONMENT_H
+
+// For using typedefs in StoreManager. Should find a better place for these
+// typedefs.
+#include "clang/Analysis/PathSensitive/Store.h"
+
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "clang/Analysis/PathSensitive/SVals.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/ADT/FoldingSet.h"
+
+namespace clang {
+
+class EnvironmentManager;
+class BasicValueFactory;
+class LiveVariables;
+
+class Environment : public llvm::FoldingSetNode {
+private:
+
+ friend class EnvironmentManager;
+
+ // Type definitions.
+ typedef llvm::ImmutableMap<Stmt*,SVal> BindingsTy;
+
+ // Data.
+ BindingsTy SubExprBindings;
+ BindingsTy BlkExprBindings;
+
+ Environment(BindingsTy seb, BindingsTy beb)
+ : SubExprBindings(seb), BlkExprBindings(beb) {}
+
+public:
+
+ typedef BindingsTy::iterator seb_iterator;
+ seb_iterator seb_begin() const { return SubExprBindings.begin(); }
+ seb_iterator seb_end() const { return SubExprBindings.end(); }
+
+ typedef BindingsTy::iterator beb_iterator;
+ beb_iterator beb_begin() const { return BlkExprBindings.begin(); }
+ beb_iterator beb_end() const { return BlkExprBindings.end(); }
+
+ SVal LookupSubExpr(Stmt* E) const {
+ const SVal* X = SubExprBindings.lookup(cast<Expr>(E));
+ return X ? *X : UnknownVal();
+ }
+
+ SVal LookupBlkExpr(Stmt* E) const {
+ const SVal* X = BlkExprBindings.lookup(E);
+ return X ? *X : UnknownVal();
+ }
+
+ SVal LookupExpr(Stmt* E) const {
+ const SVal* X = SubExprBindings.lookup(E);
+ if (X) return *X;
+ X = BlkExprBindings.lookup(E);
+ return X ? *X : UnknownVal();
+ }
+
+ SVal GetSVal(Stmt* Ex, BasicValueFactory& BasicVals) const;
+ SVal GetBlkExprSVal(Stmt* Ex, BasicValueFactory& BasicVals) const;
+
+ /// Profile - Profile the contents of an Environment object for use
+ /// in a FoldingSet.
+ static void Profile(llvm::FoldingSetNodeID& ID, const Environment* E) {
+ E->SubExprBindings.Profile(ID);
+ E->BlkExprBindings.Profile(ID);
+ }
+
+ /// Profile - Used to profile the contents of this object for inclusion
+ /// in a FoldingSet.
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ Profile(ID, this);
+ }
+
+ bool operator==(const Environment& RHS) const {
+ return SubExprBindings == RHS.SubExprBindings &&
+ BlkExprBindings == RHS.BlkExprBindings;
+ }
+};
+
+class EnvironmentManager {
+private:
+ typedef Environment::BindingsTy::Factory FactoryTy;
+ FactoryTy F;
+
+public:
+
+ EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {}
+ ~EnvironmentManager() {}
+
+ /// RemoveBlkExpr - Return a new environment object with the same bindings as
+ /// the provided environment except with any bindings for the provided Stmt*
+ /// removed. This method only removes bindings for block-level expressions.
+ /// Using this method on a non-block level expression will return the
+ /// same environment object.
+ Environment RemoveBlkExpr(const Environment& Env, Stmt* E) {
+ return Environment(Env.SubExprBindings, F.Remove(Env.BlkExprBindings, E));
+ }
+
+ Environment RemoveSubExpr(const Environment& Env, Stmt* E) {
+ return Environment(F.Remove(Env.SubExprBindings, E), Env.BlkExprBindings);
+ }
+
+ Environment AddBlkExpr(const Environment& Env, Stmt* E, SVal V) {
+ return Environment(Env.SubExprBindings, F.Add(Env.BlkExprBindings, E, V));
+ }
+
+ Environment AddSubExpr(const Environment& Env, Stmt* E, SVal V) {
+ return Environment(F.Add(Env.SubExprBindings, E, V), Env.BlkExprBindings);
+ }
+
+ /// RemoveSubExprBindings - Return a new environment object with
+ /// the same bindings as the provided environment except with all the
+ /// subexpression bindings removed.
+ Environment RemoveSubExprBindings(const Environment& Env) {
+ return Environment(F.GetEmptyMap(), Env.BlkExprBindings);
+ }
+
+ Environment getInitialEnvironment() {
+ return Environment(F.GetEmptyMap(), F.GetEmptyMap());
+ }
+
+ Environment BindExpr(const Environment& Env, Stmt* E, SVal V,
+ bool isBlkExpr, bool Invalidate);
+
+ Environment
+ RemoveDeadBindings(Environment Env, Stmt* Loc, SymbolReaper& SymReaper,
+ GRStateManager& StateMgr, const GRState *state,
+ llvm::SmallVectorImpl<const MemRegion*>& DRoots);
+
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Analysis/PathSensitive/ExplodedGraph.h
new file mode 100644
index 000000000000..8494d935650d
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/ExplodedGraph.h
@@ -0,0 +1,582 @@
+//=-- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -*- 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 template classes ExplodedNode and ExplodedGraph,
+// which represent a path-sensitive, intra-procedural "exploded graph."
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH
+#define LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH
+
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/AST/Decl.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/Support/Casting.h"
+
+namespace clang {
+
+class GRCoreEngineImpl;
+class ExplodedNodeImpl;
+class CFG;
+class ASTContext;
+
+class GRStmtNodeBuilderImpl;
+class GRBranchNodeBuilderImpl;
+class GRIndirectGotoNodeBuilderImpl;
+class GRSwitchNodeBuilderImpl;
+class GREndPathNodebuilderImpl;
+
+//===----------------------------------------------------------------------===//
+// ExplodedGraph "implementation" classes. These classes are not typed to
+// contain a specific kind of state. Typed-specialized versions are defined
+// on top of these classes.
+//===----------------------------------------------------------------------===//
+
+class ExplodedNodeImpl : public llvm::FoldingSetNode {
+protected:
+ friend class ExplodedGraphImpl;
+ friend class GRCoreEngineImpl;
+ friend class GRStmtNodeBuilderImpl;
+ friend class GRBranchNodeBuilderImpl;
+ friend class GRIndirectGotoNodeBuilderImpl;
+ friend class GRSwitchNodeBuilderImpl;
+ friend class GREndPathNodeBuilderImpl;
+
+ class NodeGroup {
+ enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 };
+ uintptr_t P;
+
+ unsigned getKind() const {
+ return P & 0x1;
+ }
+
+ void* getPtr() const {
+ assert (!getFlag());
+ return reinterpret_cast<void*>(P & ~Mask);
+ }
+
+ ExplodedNodeImpl* getNode() const {
+ return reinterpret_cast<ExplodedNodeImpl*>(getPtr());
+ }
+
+ public:
+ NodeGroup() : P(0) {}
+
+ ~NodeGroup();
+
+ ExplodedNodeImpl** begin() const;
+
+ ExplodedNodeImpl** end() const;
+
+ unsigned size() const;
+
+ bool empty() const { return size() == 0; }
+
+ void addNode(ExplodedNodeImpl* N);
+
+ void setFlag() {
+ assert (P == 0);
+ P = AuxFlag;
+ }
+
+ bool getFlag() const {
+ return P & AuxFlag ? true : false;
+ }
+ };
+
+ /// Location - The program location (within a function body) associated
+ /// with this node.
+ const ProgramPoint Location;
+
+ /// State - The state associated with this node.
+ const void* State;
+
+ /// Preds - The predecessors of this node.
+ NodeGroup Preds;
+
+ /// Succs - The successors of this node.
+ NodeGroup Succs;
+
+ /// Construct a ExplodedNodeImpl with the provided location and state.
+ explicit ExplodedNodeImpl(const ProgramPoint& loc, const void* state)
+ : Location(loc), State(state) {}
+
+ /// addPredeccessor - Adds a predecessor to the current node, and
+ /// in tandem add this node as a successor of the other node.
+ void addPredecessor(ExplodedNodeImpl* V);
+
+public:
+
+ /// getLocation - Returns the edge associated with the given node.
+ ProgramPoint getLocation() const { return Location; }
+
+ template <typename T>
+ const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); }
+
+ unsigned succ_size() const { return Succs.size(); }
+ unsigned pred_size() const { return Preds.size(); }
+ bool succ_empty() const { return Succs.empty(); }
+ bool pred_empty() const { return Preds.empty(); }
+
+ bool isSink() const { return Succs.getFlag(); }
+ void markAsSink() { Succs.setFlag(); }
+
+ // For debugging.
+
+public:
+
+ class Auditor {
+ public:
+ virtual ~Auditor();
+ virtual void AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst) = 0;
+ };
+
+ static void SetAuditor(Auditor* A);
+};
+
+
+template <typename StateTy>
+struct GRTrait {
+ static inline void Profile(llvm::FoldingSetNodeID& ID, const StateTy* St) {
+ St->Profile(ID);
+ }
+};
+
+
+template <typename StateTy>
+class ExplodedNode : public ExplodedNodeImpl {
+public:
+ /// Construct a ExplodedNodeImpl with the given node ID, program edge,
+ /// and state.
+ explicit ExplodedNode(const ProgramPoint& loc, const StateTy* St)
+ : ExplodedNodeImpl(loc, St) {}
+
+ /// getState - Returns the state associated with the node.
+ inline const StateTy* getState() const {
+ return static_cast<const StateTy*>(State);
+ }
+
+ // Profiling (for FoldingSet).
+
+ static inline void Profile(llvm::FoldingSetNodeID& ID,
+ const ProgramPoint& Loc,
+ const StateTy* state) {
+ ID.Add(Loc);
+ GRTrait<StateTy>::Profile(ID, state);
+ }
+
+ inline void Profile(llvm::FoldingSetNodeID& ID) const {
+ Profile(ID, getLocation(), getState());
+ }
+
+ void addPredecessor(ExplodedNode* V) {
+ ExplodedNodeImpl::addPredecessor(V);
+ }
+
+ ExplodedNode* getFirstPred() {
+ return pred_empty() ? NULL : *(pred_begin());
+ }
+
+ const ExplodedNode* getFirstPred() const {
+ return const_cast<ExplodedNode*>(this)->getFirstPred();
+ }
+
+ // Iterators over successor and predecessor vertices.
+ typedef ExplodedNode** succ_iterator;
+ typedef const ExplodedNode* const * const_succ_iterator;
+ typedef ExplodedNode** pred_iterator;
+ typedef const ExplodedNode* const * const_pred_iterator;
+
+ pred_iterator pred_begin() { return (ExplodedNode**) Preds.begin(); }
+ pred_iterator pred_end() { return (ExplodedNode**) Preds.end(); }
+
+ const_pred_iterator pred_begin() const {
+ return const_cast<ExplodedNode*>(this)->pred_begin();
+ }
+ const_pred_iterator pred_end() const {
+ return const_cast<ExplodedNode*>(this)->pred_end();
+ }
+
+ succ_iterator succ_begin() { return (ExplodedNode**) Succs.begin(); }
+ succ_iterator succ_end() { return (ExplodedNode**) Succs.end(); }
+
+ const_succ_iterator succ_begin() const {
+ return const_cast<ExplodedNode*>(this)->succ_begin();
+ }
+ const_succ_iterator succ_end() const {
+ return const_cast<ExplodedNode*>(this)->succ_end();
+ }
+};
+
+class InterExplodedGraphMapImpl;
+
+class ExplodedGraphImpl {
+protected:
+ friend class GRCoreEngineImpl;
+ friend class GRStmtNodeBuilderImpl;
+ friend class GRBranchNodeBuilderImpl;
+ friend class GRIndirectGotoNodeBuilderImpl;
+ friend class GRSwitchNodeBuilderImpl;
+ friend class GREndPathNodeBuilderImpl;
+
+ // Type definitions.
+ typedef llvm::SmallVector<ExplodedNodeImpl*,2> RootsTy;
+ typedef llvm::SmallVector<ExplodedNodeImpl*,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
+ /// SimulGraph. Moreover, these subgraphs can often merge when paths from
+ /// different roots reach the same state at the same program location.
+ RootsTy Roots;
+
+ /// EndNodes - The nodes in the simulation graph which have been
+ /// specially marked as the endpoint of an abstract simulation path.
+ EndNodesTy EndNodes;
+
+ /// Allocator - BumpPtrAllocator to create nodes.
+ llvm::BumpPtrAllocator Allocator;
+
+ /// cfg - The CFG associated with this analysis graph.
+ CFG& cfg;
+
+ /// CodeDecl - The declaration containing the code being analyzed. This
+ /// can be a FunctionDecl or and ObjCMethodDecl.
+ Decl& CodeDecl;
+
+ /// Ctx - The ASTContext used to "interpret" CodeDecl.
+ ASTContext& Ctx;
+
+ /// NumNodes - The number of nodes in the graph.
+ unsigned NumNodes;
+
+ /// getNodeImpl - Retrieve the node associated with a (Location,State)
+ /// pair, where 'State' is represented as an opaque void*. This method
+ /// is intended to be used only by GRCoreEngineImpl.
+ virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L,
+ const void* State,
+ bool* IsNew) = 0;
+
+ virtual ExplodedGraphImpl* MakeEmptyGraph() const = 0;
+
+ /// addRoot - Add an untyped node to the set of roots.
+ ExplodedNodeImpl* addRoot(ExplodedNodeImpl* V) {
+ Roots.push_back(V);
+ return V;
+ }
+
+ /// addEndOfPath - Add an untyped node to the set of EOP nodes.
+ ExplodedNodeImpl* addEndOfPath(ExplodedNodeImpl* V) {
+ EndNodes.push_back(V);
+ return V;
+ }
+
+ // ctor.
+ ExplodedGraphImpl(CFG& c, Decl& cd, ASTContext& ctx)
+ : cfg(c), CodeDecl(cd), Ctx(ctx), NumNodes(0) {}
+
+public:
+ virtual ~ExplodedGraphImpl() {}
+
+ unsigned num_roots() const { return Roots.size(); }
+ unsigned num_eops() const { return EndNodes.size(); }
+
+ bool empty() const { return NumNodes == 0; }
+ unsigned size() const { return NumNodes; }
+
+ llvm::BumpPtrAllocator& getAllocator() { return Allocator; }
+ CFG& getCFG() { return cfg; }
+ ASTContext& getContext() { return Ctx; }
+
+ Decl& getCodeDecl() { return CodeDecl; }
+ const Decl& getCodeDecl() const { return CodeDecl; }
+
+ const FunctionDecl* getFunctionDecl() const {
+ return llvm::dyn_cast<FunctionDecl>(&CodeDecl);
+ }
+
+ typedef llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> NodeMap;
+
+ ExplodedGraphImpl* Trim(const ExplodedNodeImpl* const * NBeg,
+ const ExplodedNodeImpl* const * NEnd,
+ InterExplodedGraphMapImpl *M,
+ llvm::DenseMap<const void*, const void*> *InverseMap)
+ const;
+};
+
+class InterExplodedGraphMapImpl {
+ llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> M;
+ friend class ExplodedGraphImpl;
+ void add(const ExplodedNodeImpl* From, ExplodedNodeImpl* To);
+
+protected:
+ ExplodedNodeImpl* getMappedImplNode(const ExplodedNodeImpl* N) const;
+
+ InterExplodedGraphMapImpl();
+public:
+ virtual ~InterExplodedGraphMapImpl() {}
+};
+
+//===----------------------------------------------------------------------===//
+// Type-specialized ExplodedGraph classes.
+//===----------------------------------------------------------------------===//
+
+template <typename STATE>
+class InterExplodedGraphMap : public InterExplodedGraphMapImpl {
+public:
+ InterExplodedGraphMap() {};
+ ~InterExplodedGraphMap() {};
+
+ ExplodedNode<STATE>* getMappedNode(const ExplodedNode<STATE>* N) const {
+ return static_cast<ExplodedNode<STATE>*>(getMappedImplNode(N));
+ }
+};
+
+template <typename STATE>
+class ExplodedGraph : public ExplodedGraphImpl {
+public:
+ typedef STATE StateTy;
+ typedef ExplodedNode<StateTy> NodeTy;
+ typedef llvm::FoldingSet<NodeTy> AllNodesTy;
+
+protected:
+ /// Nodes - The nodes in the graph.
+ AllNodesTy Nodes;
+
+protected:
+ virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L,
+ const void* State,
+ bool* IsNew) {
+
+ return getNode(L, static_cast<const StateTy*>(State), IsNew);
+ }
+
+ virtual ExplodedGraphImpl* MakeEmptyGraph() const {
+ return new ExplodedGraph(cfg, CodeDecl, Ctx);
+ }
+
+public:
+ ExplodedGraph(CFG& c, Decl& cd, ASTContext& ctx)
+ : ExplodedGraphImpl(c, cd, ctx) {}
+
+ /// getNode - Retrieve the node associated with a (Location,State) pair,
+ /// where the 'Location' is a ProgramPoint in the CFG. If no node for
+ /// this pair exists, it is created. IsNew is set to true if
+ /// the node was freshly created.
+ NodeTy* getNode(const ProgramPoint& L, const StateTy* State,
+ bool* IsNew = NULL) {
+
+ // Profile 'State' to determine if we already have an existing node.
+ llvm::FoldingSetNodeID profile;
+ void* InsertPos = 0;
+
+ NodeTy::Profile(profile, L, State);
+ NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos);
+
+ if (!V) {
+ // Allocate a new node.
+ V = (NodeTy*) Allocator.Allocate<NodeTy>();
+ new (V) NodeTy(L, State);
+
+ // Insert the node into the node set and return it.
+ Nodes.InsertNode(V, InsertPos);
+
+ ++NumNodes;
+
+ if (IsNew) *IsNew = true;
+ }
+ else
+ if (IsNew) *IsNew = false;
+
+ return V;
+ }
+
+ // Iterators.
+ typedef NodeTy** roots_iterator;
+ typedef const NodeTy** const_roots_iterator;
+ typedef NodeTy** eop_iterator;
+ typedef const NodeTy** const_eop_iterator;
+ typedef typename AllNodesTy::iterator node_iterator;
+ typedef typename AllNodesTy::const_iterator const_node_iterator;
+
+ node_iterator nodes_begin() {
+ return Nodes.begin();
+ }
+
+ node_iterator nodes_end() {
+ return Nodes.end();
+ }
+
+ const_node_iterator nodes_begin() const {
+ return Nodes.begin();
+ }
+
+ const_node_iterator nodes_end() const {
+ return Nodes.end();
+ }
+
+ roots_iterator roots_begin() {
+ return reinterpret_cast<roots_iterator>(Roots.begin());
+ }
+
+ roots_iterator roots_end() {
+ return reinterpret_cast<roots_iterator>(Roots.end());
+ }
+
+ const_roots_iterator roots_begin() const {
+ return const_cast<ExplodedGraph>(this)->roots_begin();
+ }
+
+ const_roots_iterator roots_end() const {
+ return const_cast<ExplodedGraph>(this)->roots_end();
+ }
+
+ eop_iterator eop_begin() {
+ return reinterpret_cast<eop_iterator>(EndNodes.begin());
+ }
+
+ eop_iterator eop_end() {
+ return reinterpret_cast<eop_iterator>(EndNodes.end());
+ }
+
+ const_eop_iterator eop_begin() const {
+ return const_cast<ExplodedGraph>(this)->eop_begin();
+ }
+
+ const_eop_iterator eop_end() const {
+ return const_cast<ExplodedGraph>(this)->eop_end();
+ }
+
+ std::pair<ExplodedGraph*, InterExplodedGraphMap<STATE>*>
+ Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd,
+ llvm::DenseMap<const void*, const void*> *InverseMap = 0) const {
+
+ if (NBeg == NEnd)
+ return std::make_pair((ExplodedGraph*) 0,
+ (InterExplodedGraphMap<STATE>*) 0);
+
+ assert (NBeg < NEnd);
+
+ const ExplodedNodeImpl* const* NBegImpl =
+ (const ExplodedNodeImpl* const*) NBeg;
+ const ExplodedNodeImpl* const* NEndImpl =
+ (const ExplodedNodeImpl* const*) NEnd;
+
+ llvm::OwningPtr<InterExplodedGraphMap<STATE> >
+ M(new InterExplodedGraphMap<STATE>());
+
+ ExplodedGraphImpl* G = ExplodedGraphImpl::Trim(NBegImpl, NEndImpl, M.get(),
+ InverseMap);
+
+ return std::make_pair(static_cast<ExplodedGraph*>(G), M.take());
+ }
+};
+
+template <typename StateTy>
+class ExplodedNodeSet {
+
+ typedef ExplodedNode<StateTy> NodeTy;
+ typedef llvm::SmallPtrSet<NodeTy*,5> ImplTy;
+ ImplTy Impl;
+
+public:
+ ExplodedNodeSet(NodeTy* N) {
+ assert (N && !static_cast<ExplodedNodeImpl*>(N)->isSink());
+ Impl.insert(N);
+ }
+
+ ExplodedNodeSet() {}
+
+ inline void Add(NodeTy* N) {
+ if (N && !static_cast<ExplodedNodeImpl*>(N)->isSink()) Impl.insert(N);
+ }
+
+ typedef typename ImplTy::iterator iterator;
+ typedef typename ImplTy::const_iterator const_iterator;
+
+ inline unsigned size() const { return Impl.size(); }
+ inline bool empty() const { return Impl.empty(); }
+
+ inline void clear() { Impl.clear(); }
+
+ inline iterator begin() { return Impl.begin(); }
+ inline iterator end() { return Impl.end(); }
+
+ inline const_iterator begin() const { return Impl.begin(); }
+ inline const_iterator end() const { return Impl.end(); }
+};
+
+} // end clang namespace
+
+// GraphTraits
+
+namespace llvm {
+ template<typename StateTy>
+ struct GraphTraits<clang::ExplodedNode<StateTy>*> {
+ typedef clang::ExplodedNode<StateTy> NodeType;
+ typedef typename NodeType::succ_iterator ChildIteratorType;
+ typedef llvm::df_iterator<NodeType*> nodes_iterator;
+
+ static inline NodeType* getEntryNode(NodeType* N) {
+ return N;
+ }
+
+ static inline ChildIteratorType child_begin(NodeType* N) {
+ return N->succ_begin();
+ }
+
+ static inline ChildIteratorType child_end(NodeType* N) {
+ return N->succ_end();
+ }
+
+ static inline nodes_iterator nodes_begin(NodeType* N) {
+ return df_begin(N);
+ }
+
+ static inline nodes_iterator nodes_end(NodeType* N) {
+ return df_end(N);
+ }
+ };
+
+ template<typename StateTy>
+ struct GraphTraits<const clang::ExplodedNode<StateTy>*> {
+ typedef const clang::ExplodedNode<StateTy> NodeType;
+ typedef typename NodeType::succ_iterator ChildIteratorType;
+ typedef llvm::df_iterator<NodeType*> nodes_iterator;
+
+ static inline NodeType* getEntryNode(NodeType* N) {
+ return N;
+ }
+
+ static inline ChildIteratorType child_begin(NodeType* N) {
+ return N->succ_begin();
+ }
+
+ static inline ChildIteratorType child_end(NodeType* N) {
+ return N->succ_end();
+ }
+
+ static inline nodes_iterator nodes_begin(NodeType* N) {
+ return df_begin(N);
+ }
+
+ static inline nodes_iterator nodes_end(NodeType* N) {
+ return df_end(N);
+ }
+ };
+
+} // end llvm namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/GRAuditor.h b/include/clang/Analysis/PathSensitive/GRAuditor.h
new file mode 100644
index 000000000000..eca591d4af0e
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/GRAuditor.h
@@ -0,0 +1,39 @@
+//==- GRAuditor.h - Observers of the creation of ExplodedNodes------*- 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 GRAuditor and its primary subclasses, an interface
+// to audit the creation of ExplodedNodes. This interface can be used
+// to implement simple checkers that do not mutate analysis state but
+// instead operate by perfoming simple logical checks at key monitoring
+// locations (e.g., function calls).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRAUDITOR
+#define LLVM_CLANG_ANALYSIS_GRAUDITOR
+
+#include "clang/AST/Expr.h"
+#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
+
+namespace clang {
+
+template <typename STATE>
+class GRAuditor {
+public:
+ typedef ExplodedNode<STATE> NodeTy;
+ typedef typename STATE::ManagerTy ManagerTy;
+
+ virtual ~GRAuditor() {}
+ virtual bool Audit(NodeTy* N, ManagerTy& M) = 0;
+};
+
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/GRBlockCounter.h b/include/clang/Analysis/PathSensitive/GRBlockCounter.h
new file mode 100644
index 000000000000..b4fd2704b81a
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/GRBlockCounter.h
@@ -0,0 +1,50 @@
+//==- GRBlockCounter.h - ADT for counting block visits -------------*- 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 GRBlockCounter, an abstract data type used to count
+// the number of times a given block has been visited along a path
+// analyzed by GRCoreEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER
+#define LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER
+
+namespace llvm {
+ class BumpPtrAllocator;
+}
+
+namespace clang {
+
+class GRBlockCounter {
+ void* Data;
+
+ GRBlockCounter(void* D) : Data(D) {}
+
+public:
+ GRBlockCounter() : Data(0) {}
+
+ unsigned getNumVisited(unsigned BlockID) const;
+
+ class Factory {
+ void* F;
+ public:
+ Factory(llvm::BumpPtrAllocator& Alloc);
+ ~Factory();
+
+ GRBlockCounter GetEmptyCounter();
+ GRBlockCounter IncrementCount(GRBlockCounter BC, unsigned BlockID);
+ };
+
+ friend class Factory;
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/include/clang/Analysis/PathSensitive/GRCoreEngine.h
new file mode 100644
index 000000000000..0fbdbde55bd5
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/GRCoreEngine.h
@@ -0,0 +1,668 @@
+//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine ------------------*- 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 a generic engine for intraprocedural, path-sensitive,
+// dataflow analysis via graph reachability.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRENGINE
+#define LLVM_CLANG_ANALYSIS_GRENGINE
+
+#include "clang/AST/Expr.h"
+#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
+#include "clang/Analysis/PathSensitive/GRWorkList.h"
+#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
+#include "clang/Analysis/PathSensitive/GRAuditor.h"
+#include "llvm/ADT/OwningPtr.h"
+
+namespace clang {
+
+class GRStmtNodeBuilderImpl;
+class GRBranchNodeBuilderImpl;
+class GRIndirectGotoNodeBuilderImpl;
+class GRSwitchNodeBuilderImpl;
+class GREndPathNodeBuilderImpl;
+class GRWorkList;
+
+//===----------------------------------------------------------------------===//
+/// GRCoreEngineImpl - Implements the core logic of the graph-reachability
+/// analysis. It traverses the CFG and generates the ExplodedGraph.
+/// Program "states" are treated as opaque void pointers.
+/// The template class GRCoreEngine (which subclasses GRCoreEngineImpl)
+/// provides the matching component to the engine that knows the actual types
+/// for states. Note that this engine only dispatches to transfer functions
+/// at the statement and block-level. The analyses themselves must implement
+/// any transfer function logic and the sub-expression level (if any).
+class GRCoreEngineImpl {
+protected:
+ friend class GRStmtNodeBuilderImpl;
+ friend class GRBranchNodeBuilderImpl;
+ friend class GRIndirectGotoNodeBuilderImpl;
+ friend class GRSwitchNodeBuilderImpl;
+ friend class GREndPathNodeBuilderImpl;
+
+ /// G - The simulation graph. Each node is a (location,state) pair.
+ llvm::OwningPtr<ExplodedGraphImpl> G;
+
+ /// WList - A set of queued nodes that need to be processed by the
+ /// worklist algorithm. It is up to the implementation of WList to decide
+ /// the order that nodes are processed.
+ GRWorkList* WList;
+
+ /// BCounterFactory - A factory object for created GRBlockCounter objects.
+ /// These are used to record for key nodes in the ExplodedGraph the
+ /// number of times different CFGBlocks have been visited along a path.
+ GRBlockCounter::Factory BCounterFactory;
+
+ void GenerateNode(const ProgramPoint& Loc, const void* State,
+ ExplodedNodeImpl* Pred);
+
+ /// getInitialState - Gets the void* representing the initial 'state'
+ /// of the analysis. This is simply a wrapper (implemented
+ /// in GRCoreEngine) that performs type erasure on the initial
+ /// state returned by the checker object.
+ virtual const void* getInitialState() = 0;
+
+ void HandleBlockEdge(const BlockEdge& E, ExplodedNodeImpl* Pred);
+ void HandleBlockEntrance(const BlockEntrance& E, ExplodedNodeImpl* Pred);
+ void HandleBlockExit(CFGBlock* B, ExplodedNodeImpl* Pred);
+ void HandlePostStmt(const PostStmt& S, CFGBlock* B,
+ unsigned StmtIdx, ExplodedNodeImpl *Pred);
+
+ void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B,
+ ExplodedNodeImpl* Pred);
+
+ virtual void ProcessEndPath(GREndPathNodeBuilderImpl& Builder) = 0;
+
+ virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
+ GRBlockCounter BC) = 0;
+
+ virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& Builder) = 0;
+
+ virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
+ GRBranchNodeBuilderImpl& Builder) = 0;
+
+ virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0;
+
+ virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& Builder) = 0;
+
+private:
+ GRCoreEngineImpl(const GRCoreEngineImpl&); // Do not implement.
+ GRCoreEngineImpl& operator=(const GRCoreEngineImpl&);
+
+protected:
+ GRCoreEngineImpl(ExplodedGraphImpl* g, GRWorkList* wl)
+ : G(g), WList(wl), BCounterFactory(g->getAllocator()) {}
+
+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(unsigned Steps);
+
+ virtual ~GRCoreEngineImpl();
+
+ CFG& getCFG() { return G->getCFG(); }
+};
+
+class GRStmtNodeBuilderImpl {
+ GRCoreEngineImpl& Eng;
+ CFGBlock& B;
+ const unsigned Idx;
+ ExplodedNodeImpl* Pred;
+ ExplodedNodeImpl* LastNode;
+
+ typedef llvm::SmallPtrSet<ExplodedNodeImpl*,5> DeferredTy;
+ DeferredTy Deferred;
+
+ void GenerateAutoTransition(ExplodedNodeImpl* N);
+
+public:
+ GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx,
+ ExplodedNodeImpl* N, GRCoreEngineImpl* e);
+
+ ~GRStmtNodeBuilderImpl();
+
+ ExplodedNodeImpl* getBasePredecessor() const { return Pred; }
+
+ ExplodedNodeImpl* getLastNode() const {
+ return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL;
+ }
+
+ GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
+
+ unsigned getCurrentBlockCount() const {
+ return getBlockCounter().getNumVisited(B.getBlockID());
+ }
+
+ ExplodedNodeImpl*
+ generateNodeImpl(PostStmt PP, const void* State, ExplodedNodeImpl* Pred);
+
+ ExplodedNodeImpl*
+ generateNodeImpl(Stmt* S, const void* State, ExplodedNodeImpl* Pred,
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
+ const void *tag = 0);
+
+ ExplodedNodeImpl*
+ generateNodeImpl(Stmt* S, const void* State,
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
+ const void *tag = 0) {
+ ExplodedNodeImpl* N = getLastNode();
+ assert (N && "Predecessor of new node is infeasible.");
+ return generateNodeImpl(S, State, N, K, tag);
+ }
+
+ ExplodedNodeImpl*
+ generateNodeImpl(Stmt* S, const void* State, const void *tag = 0) {
+ ExplodedNodeImpl* N = getLastNode();
+ assert (N && "Predecessor of new node is infeasible.");
+ return generateNodeImpl(S, State, N, ProgramPoint::PostStmtKind, tag);
+ }
+
+ /// getStmt - Return the current block-level expression associated with
+ /// this builder.
+ Stmt* getStmt() const { return B[Idx]; }
+
+ /// getBlock - Return the CFGBlock associated with the block-level expression
+ /// of this builder.
+ CFGBlock* getBlock() const { return &B; }
+};
+
+
+template<typename STATE>
+class GRStmtNodeBuilder {
+public:
+ typedef STATE StateTy;
+ typedef typename StateTy::ManagerTy StateManagerTy;
+ typedef ExplodedNode<StateTy> NodeTy;
+
+private:
+ GRStmtNodeBuilderImpl& NB;
+ StateManagerTy& Mgr;
+ const StateTy* CleanedState;
+ GRAuditor<StateTy>* Auditor;
+
+public:
+ GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb, StateManagerTy& mgr) :
+ NB(nb), Mgr(mgr), Auditor(0), PurgingDeadSymbols(false),
+ BuildSinks(false), HasGeneratedNode(false),
+ PointKind(ProgramPoint::PostStmtKind), Tag(0) {
+
+ CleanedState = getLastNode()->getState();
+ }
+
+ void setAuditor(GRAuditor<StateTy>* A) {
+ Auditor = A;
+ }
+
+ NodeTy* getLastNode() const {
+ return static_cast<NodeTy*>(NB.getLastNode());
+ }
+
+ NodeTy* generateNode(PostStmt PP, const StateTy* St, NodeTy* Pred) {
+ HasGeneratedNode = true;
+ return static_cast<NodeTy*>(NB.generateNodeImpl(PP, St, Pred));
+ }
+
+ NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred,
+ ProgramPoint::Kind K) {
+ HasGeneratedNode = true;
+ if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
+ return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, K, Tag));
+ }
+
+ NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred) {
+ return generateNode(S, St, Pred, PointKind);
+ }
+
+ NodeTy* generateNode(Stmt* S, const StateTy* St, ProgramPoint::Kind K) {
+ HasGeneratedNode = true;
+ if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
+ return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, K, Tag));
+ }
+
+ NodeTy* generateNode(Stmt* S, const StateTy* St) {
+ return generateNode(S, St, PointKind);
+ }
+
+
+ GRBlockCounter getBlockCounter() const {
+ return NB.getBlockCounter();
+ }
+
+ unsigned getCurrentBlockCount() const {
+ return NB.getCurrentBlockCount();
+ }
+
+ const StateTy* GetState(NodeTy* Pred) const {
+ if ((ExplodedNodeImpl*) Pred == NB.getBasePredecessor())
+ return CleanedState;
+ else
+ return Pred->getState();
+ }
+
+ void SetCleanedState(const StateTy* St) {
+ CleanedState = St;
+ }
+
+ NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
+ NodeTy* Pred, const StateTy* St) {
+ return MakeNode(Dst, S, Pred, St, PointKind);
+ }
+
+ NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
+ NodeTy* Pred, const StateTy* St, ProgramPoint::Kind K) {
+
+ const StateTy* PredState = GetState(Pred);
+
+ // If the state hasn't changed, don't generate a new node.
+ if (!BuildSinks && St == PredState && Auditor == 0) {
+ Dst.Add(Pred);
+ return NULL;
+ }
+
+ NodeTy* N = generateNode(S, St, Pred, K);
+
+ if (N) {
+ if (BuildSinks)
+ N->markAsSink();
+ else {
+ if (Auditor && Auditor->Audit(N, Mgr))
+ N->markAsSink();
+
+ Dst.Add(N);
+ }
+ }
+
+ return N;
+ }
+
+ NodeTy* MakeSinkNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
+ NodeTy* Pred, const StateTy* St) {
+ bool Tmp = BuildSinks;
+ BuildSinks = true;
+ NodeTy* N = MakeNode(Dst, S, Pred, St);
+ BuildSinks = Tmp;
+ return N;
+ }
+
+ bool PurgingDeadSymbols;
+ bool BuildSinks;
+ bool HasGeneratedNode;
+ ProgramPoint::Kind PointKind;
+ const void *Tag;
+};
+
+class GRBranchNodeBuilderImpl {
+ GRCoreEngineImpl& Eng;
+ CFGBlock* Src;
+ CFGBlock* DstT;
+ CFGBlock* DstF;
+ ExplodedNodeImpl* Pred;
+
+ typedef llvm::SmallVector<ExplodedNodeImpl*,3> DeferredTy;
+ DeferredTy Deferred;
+
+ bool GeneratedTrue;
+ bool GeneratedFalse;
+
+public:
+ GRBranchNodeBuilderImpl(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF,
+ ExplodedNodeImpl* pred, GRCoreEngineImpl* e)
+ : Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred),
+ GeneratedTrue(false), GeneratedFalse(false) {}
+
+ ~GRBranchNodeBuilderImpl();
+
+ ExplodedNodeImpl* getPredecessor() const { return Pred; }
+ const ExplodedGraphImpl& getGraph() const { return *Eng.G; }
+ GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
+
+ ExplodedNodeImpl* generateNodeImpl(const void* State, bool branch);
+
+ CFGBlock* getTargetBlock(bool branch) const {
+ return branch ? DstT : DstF;
+ }
+
+ void markInfeasible(bool branch) {
+ if (branch) GeneratedTrue = true;
+ else GeneratedFalse = true;
+ }
+};
+
+template<typename STATE>
+class GRBranchNodeBuilder {
+ typedef STATE StateTy;
+ typedef ExplodedGraph<StateTy> GraphTy;
+ typedef typename GraphTy::NodeTy NodeTy;
+
+ GRBranchNodeBuilderImpl& NB;
+
+public:
+ GRBranchNodeBuilder(GRBranchNodeBuilderImpl& nb) : NB(nb) {}
+
+ const GraphTy& getGraph() const {
+ return static_cast<const GraphTy&>(NB.getGraph());
+ }
+
+ NodeTy* getPredecessor() const {
+ return static_cast<NodeTy*>(NB.getPredecessor());
+ }
+
+ const StateTy* getState() const {
+ return getPredecessor()->getState();
+ }
+
+ NodeTy* generateNode(const StateTy* St, bool branch) {
+ return static_cast<NodeTy*>(NB.generateNodeImpl(St, branch));
+ }
+
+ GRBlockCounter getBlockCounter() const {
+ return NB.getBlockCounter();
+ }
+
+ CFGBlock* getTargetBlock(bool branch) const {
+ return NB.getTargetBlock(branch);
+ }
+
+ void markInfeasible(bool branch) {
+ NB.markInfeasible(branch);
+ }
+};
+
+class GRIndirectGotoNodeBuilderImpl {
+ GRCoreEngineImpl& Eng;
+ CFGBlock* Src;
+ CFGBlock& DispatchBlock;
+ Expr* E;
+ ExplodedNodeImpl* Pred;
+public:
+ GRIndirectGotoNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
+ Expr* e, CFGBlock* dispatch,
+ GRCoreEngineImpl* eng)
+ : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
+
+
+ class Iterator {
+ CFGBlock::succ_iterator I;
+
+ friend class GRIndirectGotoNodeBuilderImpl;
+ Iterator(CFGBlock::succ_iterator i) : I(i) {}
+ public:
+
+ Iterator& operator++() { ++I; return *this; }
+ bool operator!=(const Iterator& X) const { return I != X.I; }
+
+ LabelStmt* getLabel() const {
+ return llvm::cast<LabelStmt>((*I)->getLabel());
+ }
+
+ CFGBlock* getBlock() const {
+ return *I;
+ }
+ };
+
+ Iterator begin() { return Iterator(DispatchBlock.succ_begin()); }
+ Iterator end() { return Iterator(DispatchBlock.succ_end()); }
+
+ ExplodedNodeImpl* generateNodeImpl(const Iterator& I, const void* State,
+ bool isSink);
+
+ Expr* getTarget() const { return E; }
+ const void* getState() const { return Pred->State; }
+};
+
+template<typename STATE>
+class GRIndirectGotoNodeBuilder {
+ typedef STATE StateTy;
+ typedef ExplodedGraph<StateTy> GraphTy;
+ typedef typename GraphTy::NodeTy NodeTy;
+
+ GRIndirectGotoNodeBuilderImpl& NB;
+
+public:
+ GRIndirectGotoNodeBuilder(GRIndirectGotoNodeBuilderImpl& nb) : NB(nb) {}
+
+ typedef GRIndirectGotoNodeBuilderImpl::Iterator iterator;
+
+ iterator begin() { return NB.begin(); }
+ iterator end() { return NB.end(); }
+
+ Expr* getTarget() const { return NB.getTarget(); }
+
+ NodeTy* generateNode(const iterator& I, const StateTy* St, bool isSink=false){
+ return static_cast<NodeTy*>(NB.generateNodeImpl(I, St, isSink));
+ }
+
+ const StateTy* getState() const {
+ return static_cast<const StateTy*>(NB.getState());
+ }
+};
+
+class GRSwitchNodeBuilderImpl {
+ GRCoreEngineImpl& Eng;
+ CFGBlock* Src;
+ Expr* Condition;
+ ExplodedNodeImpl* Pred;
+public:
+ GRSwitchNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
+ Expr* condition, GRCoreEngineImpl* eng)
+ : Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
+
+ class Iterator {
+ CFGBlock::succ_reverse_iterator I;
+
+ friend class GRSwitchNodeBuilderImpl;
+ Iterator(CFGBlock::succ_reverse_iterator i) : I(i) {}
+ public:
+
+ Iterator& operator++() { ++I; return *this; }
+ bool operator!=(const Iterator& X) const { return I != X.I; }
+
+ CaseStmt* getCase() const {
+ return llvm::cast<CaseStmt>((*I)->getLabel());
+ }
+
+ CFGBlock* getBlock() const {
+ return *I;
+ }
+ };
+
+ Iterator begin() { return Iterator(Src->succ_rbegin()+1); }
+ Iterator end() { return Iterator(Src->succ_rend()); }
+
+ ExplodedNodeImpl* generateCaseStmtNodeImpl(const Iterator& I,
+ const void* State);
+
+ ExplodedNodeImpl* generateDefaultCaseNodeImpl(const void* State,
+ bool isSink);
+
+ Expr* getCondition() const { return Condition; }
+ const void* getState() const { return Pred->State; }
+};
+
+template<typename STATE>
+class GRSwitchNodeBuilder {
+ typedef STATE StateTy;
+ typedef ExplodedGraph<StateTy> GraphTy;
+ typedef typename GraphTy::NodeTy NodeTy;
+
+ GRSwitchNodeBuilderImpl& NB;
+
+public:
+ GRSwitchNodeBuilder(GRSwitchNodeBuilderImpl& nb) : NB(nb) {}
+
+ typedef GRSwitchNodeBuilderImpl::Iterator iterator;
+
+ iterator begin() { return NB.begin(); }
+ iterator end() { return NB.end(); }
+
+ Expr* getCondition() const { return NB.getCondition(); }
+
+ NodeTy* generateCaseStmtNode(const iterator& I, const StateTy* St) {
+ return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, St));
+ }
+
+ NodeTy* generateDefaultCaseNode(const StateTy* St, bool isSink = false) {
+ return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(St, isSink));
+ }
+
+ const StateTy* getState() const {
+ return static_cast<const StateTy*>(NB.getState());
+ }
+};
+
+
+class GREndPathNodeBuilderImpl {
+ GRCoreEngineImpl& Eng;
+ CFGBlock& B;
+ ExplodedNodeImpl* Pred;
+ bool HasGeneratedNode;
+
+public:
+ GREndPathNodeBuilderImpl(CFGBlock* b, ExplodedNodeImpl* N,
+ GRCoreEngineImpl* e)
+ : Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {}
+
+ ~GREndPathNodeBuilderImpl();
+
+ ExplodedNodeImpl* getPredecessor() const { return Pred; }
+
+ GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
+
+ unsigned getCurrentBlockCount() const {
+ return getBlockCounter().getNumVisited(B.getBlockID());
+ }
+
+ ExplodedNodeImpl* generateNodeImpl(const void* State,
+ const void *tag = 0,
+ ExplodedNodeImpl *P = 0);
+
+ CFGBlock* getBlock() const { return &B; }
+};
+
+
+template<typename STATE>
+class GREndPathNodeBuilder {
+ typedef STATE StateTy;
+ typedef ExplodedNode<StateTy> NodeTy;
+
+ GREndPathNodeBuilderImpl& NB;
+
+public:
+ GREndPathNodeBuilder(GREndPathNodeBuilderImpl& nb) : NB(nb) {}
+
+ NodeTy* getPredecessor() const {
+ return static_cast<NodeTy*>(NB.getPredecessor());
+ }
+
+ GRBlockCounter getBlockCounter() const {
+ return NB.getBlockCounter();
+ }
+
+ unsigned getCurrentBlockCount() const {
+ return NB.getCurrentBlockCount();
+ }
+
+ const StateTy* getState() const {
+ return getPredecessor()->getState();
+ }
+
+ NodeTy* MakeNode(const StateTy* St, const void *tag = 0) {
+ return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag));
+ }
+
+ NodeTy *generateNode(const StateTy *St, NodeTy *Pred, const void *tag = 0) {
+ return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag, Pred));
+ }
+};
+
+
+template<typename SUBENGINE>
+class GRCoreEngine : public GRCoreEngineImpl {
+public:
+ typedef SUBENGINE SubEngineTy;
+ typedef typename SubEngineTy::StateTy StateTy;
+ typedef typename StateTy::ManagerTy StateManagerTy;
+ typedef ExplodedGraph<StateTy> GraphTy;
+ typedef typename GraphTy::NodeTy NodeTy;
+
+protected:
+ SubEngineTy& SubEngine;
+
+ virtual const void* getInitialState() {
+ return SubEngine.getInitialState();
+ }
+
+ virtual void ProcessEndPath(GREndPathNodeBuilderImpl& BuilderImpl) {
+ GREndPathNodeBuilder<StateTy> Builder(BuilderImpl);
+ SubEngine.ProcessEndPath(Builder);
+ }
+
+ virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& BuilderImpl) {
+ GRStmtNodeBuilder<StateTy> Builder(BuilderImpl,SubEngine.getStateManager());
+ SubEngine.ProcessStmt(S, Builder);
+ }
+
+ virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
+ GRBlockCounter BC) {
+ return SubEngine.ProcessBlockEntrance(Blk,
+ static_cast<const StateTy*>(State),
+ BC);
+ }
+
+ virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
+ GRBranchNodeBuilderImpl& BuilderImpl) {
+ GRBranchNodeBuilder<StateTy> Builder(BuilderImpl);
+ SubEngine.ProcessBranch(Condition, Terminator, Builder);
+ }
+
+ virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& BuilderImpl) {
+ GRIndirectGotoNodeBuilder<StateTy> Builder(BuilderImpl);
+ SubEngine.ProcessIndirectGoto(Builder);
+ }
+
+ virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& BuilderImpl) {
+ GRSwitchNodeBuilder<StateTy> Builder(BuilderImpl);
+ SubEngine.ProcessSwitch(Builder);
+ }
+
+public:
+ /// Construct a GRCoreEngine object to analyze the provided CFG using
+ /// a DFS exploration of the exploded graph.
+ GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, SubEngineTy& subengine)
+ : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx),
+ GRWorkList::MakeBFS()),
+ SubEngine(subengine) {}
+
+ /// Construct a GRCoreEngine object to analyze the provided CFG and to
+ /// use the provided worklist object to execute the worklist algorithm.
+ /// The GRCoreEngine object assumes ownership of 'wlist'.
+ GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, GRWorkList* wlist,
+ SubEngineTy& subengine)
+ : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), wlist),
+ SubEngine(subengine) {}
+
+ virtual ~GRCoreEngine() {}
+
+ /// getGraph - Returns the exploded graph.
+ GraphTy& getGraph() {
+ return *static_cast<GraphTy*>(G.get());
+ }
+
+ /// takeGraph - Returns the exploded graph. Ownership of the graph is
+ /// transfered to the caller.
+ GraphTy* takeGraph() {
+ return static_cast<GraphTy*>(G.take());
+ }
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h
new file mode 100644
index 000000000000..2068b1beaa13
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h
@@ -0,0 +1,738 @@
+//===-- GRExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- 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 a meta-engine for path-sensitive dataflow analysis that
+// is built on GRCoreEngine, but provides the boilerplate to execute transfer
+// functions and build the ExplodedGraph at the expression level.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE
+#define LLVM_CLANG_ANALYSIS_GREXPRENGINE
+
+#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
+#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/ExprObjC.h"
+
+namespace clang {
+
+ class PathDiagnosticClient;
+ class Diagnostic;
+ class ObjCForCollectionStmt;
+
+class GRExprEngine {
+public:
+ typedef GRState StateTy;
+ typedef ExplodedGraph<StateTy> GraphTy;
+ typedef GraphTy::NodeTy NodeTy;
+
+ // Builders.
+ typedef GRStmtNodeBuilder<StateTy> StmtNodeBuilder;
+ typedef GRBranchNodeBuilder<StateTy> BranchNodeBuilder;
+ typedef GRIndirectGotoNodeBuilder<StateTy> IndirectGotoNodeBuilder;
+ typedef GRSwitchNodeBuilder<StateTy> SwitchNodeBuilder;
+ typedef GREndPathNodeBuilder<StateTy> EndPathNodeBuilder;
+ typedef ExplodedNodeSet<StateTy> NodeSet;
+
+protected:
+ GRCoreEngine<GRExprEngine> CoreEngine;
+
+ /// G - the simulation graph.
+ GraphTy& G;
+
+ /// Liveness - live-variables information the ValueDecl* and block-level
+ /// Expr* in the CFG. Used to prune out dead state.
+ LiveVariables& Liveness;
+
+ /// Builder - The current GRStmtNodeBuilder which is used when building the
+ /// nodes for a given statement.
+ StmtNodeBuilder* Builder;
+
+ /// StateMgr - Object that manages the data for all created states.
+ GRStateManager StateMgr;
+
+ /// SymMgr - Object that manages the symbol information.
+ SymbolManager& SymMgr;
+
+ /// ValMgr - Object that manages/creates SVals.
+ ValueManager &ValMgr;
+
+ /// EntryNode - The immediate predecessor node.
+ NodeTy* EntryNode;
+
+ /// CleanedState - The state for EntryNode "cleaned" of all dead
+ /// variables and symbols (as determined by a liveness analysis).
+ const GRState* CleanedState;
+
+ /// CurrentStmt - The current block-level statement.
+ Stmt* CurrentStmt;
+
+ // Obj-C Class Identifiers.
+ IdentifierInfo* NSExceptionII;
+
+ // Obj-C Selectors.
+ Selector* NSExceptionInstanceRaiseSelectors;
+ Selector RaiseSel;
+
+ llvm::OwningPtr<GRSimpleAPICheck> BatchAuditor;
+
+ /// PurgeDead - Remove dead bindings before processing a statement.
+ bool PurgeDead;
+
+ /// BR - 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 GRExprEngine is destroyed.
+ GRBugReporter BR;
+
+ /// EargerlyAssume - A flag indicating how the engine should handle
+ // expressions such as: 'x = (y != 0)'. When this flag is true then
+ // the subexpression 'y != 0' will be eagerly assumed to be true or false,
+ // thus evaluating it to the integers 0 or 1 respectively. The upside
+ // is that this can increase analysis precision until we have a better way
+ // to lazily evaluate such logic. The downside is that it eagerly
+ // bifurcates paths.
+ const bool EagerlyAssume;
+
+public:
+ typedef llvm::SmallPtrSet<NodeTy*,2> ErrorNodes;
+ typedef llvm::DenseMap<NodeTy*, Expr*> UndefArgsTy;
+
+ /// NilReceiverStructRetExplicit - Nodes in the ExplodedGraph that resulted
+ /// from [x ...] with 'x' definitely being nil and the result was a 'struct'
+ // (an undefined value).
+ ErrorNodes NilReceiverStructRetExplicit;
+
+ /// NilReceiverStructRetImplicit - Nodes in the ExplodedGraph that resulted
+ /// from [x ...] with 'x' possibly being nil and the result was a 'struct'
+ // (an undefined value).
+ ErrorNodes NilReceiverStructRetImplicit;
+
+ /// NilReceiverLargerThanVoidPtrRetExplicit - Nodes in the ExplodedGraph that
+ /// resulted from [x ...] with 'x' definitely being nil and the result's size
+ // was larger than sizeof(void *) (an undefined value).
+ ErrorNodes NilReceiverLargerThanVoidPtrRetExplicit;
+
+ /// NilReceiverLargerThanVoidPtrRetImplicit - Nodes in the ExplodedGraph that
+ /// resulted from [x ...] with 'x' possibly being nil and the result's size
+ // was larger than sizeof(void *) (an undefined value).
+ ErrorNodes NilReceiverLargerThanVoidPtrRetImplicit;
+
+ /// RetsStackAddr - Nodes in the ExplodedGraph that result from returning
+ /// the address of a stack variable.
+ ErrorNodes RetsStackAddr;
+
+ /// RetsUndef - Nodes in the ExplodedGraph that result from returning
+ /// an undefined value.
+ ErrorNodes RetsUndef;
+
+ /// UndefBranches - Nodes in the ExplodedGraph that result from
+ /// taking a branch based on an undefined value.
+ ErrorNodes UndefBranches;
+
+ /// UndefStores - Sinks in the ExplodedGraph that result from
+ /// making a store to an undefined lvalue.
+ ErrorNodes UndefStores;
+
+ /// NoReturnCalls - Sinks in the ExplodedGraph that result from
+ // calling a function with the attribute "noreturn".
+ ErrorNodes NoReturnCalls;
+
+ /// ImplicitNullDeref - Nodes in the ExplodedGraph that result from
+ /// taking a dereference on a symbolic pointer that MAY be NULL.
+ ErrorNodes ImplicitNullDeref;
+
+ /// ExplicitNullDeref - Nodes in the ExplodedGraph that result from
+ /// taking a dereference on a symbolic pointer that MUST be NULL.
+ ErrorNodes ExplicitNullDeref;
+
+ /// UnitDeref - Nodes in the ExplodedGraph that result from
+ /// taking a dereference on an undefined value.
+ ErrorNodes UndefDeref;
+
+ /// ImplicitBadDivides - Nodes in the ExplodedGraph that result from
+ /// evaluating a divide or modulo operation where the denominator
+ /// MAY be zero.
+ ErrorNodes ImplicitBadDivides;
+
+ /// ExplicitBadDivides - Nodes in the ExplodedGraph that result from
+ /// evaluating a divide or modulo operation where the denominator
+ /// MUST be zero or undefined.
+ ErrorNodes ExplicitBadDivides;
+
+ /// ImplicitBadSizedVLA - Nodes in the ExplodedGraph that result from
+ /// constructing a zero-sized VLA where the size may be zero.
+ ErrorNodes ImplicitBadSizedVLA;
+
+ /// ExplicitBadSizedVLA - Nodes in the ExplodedGraph that result from
+ /// constructing a zero-sized VLA where the size must be zero.
+ ErrorNodes ExplicitBadSizedVLA;
+
+ /// UndefResults - Nodes in the ExplodedGraph where the operands are defined
+ /// by the result is not. Excludes divide-by-zero errors.
+ ErrorNodes UndefResults;
+
+ /// BadCalls - Nodes in the ExplodedGraph resulting from calls to function
+ /// pointers that are NULL (or other constants) or Undefined.
+ ErrorNodes BadCalls;
+
+ /// UndefReceiver - Nodes in the ExplodedGraph resulting from message
+ /// ObjC message expressions where the receiver is undefined (uninitialized).
+ ErrorNodes UndefReceivers;
+
+ /// UndefArg - Nodes in the ExplodedGraph resulting from calls to functions
+ /// where a pass-by-value argument has an undefined value.
+ UndefArgsTy UndefArgs;
+
+ /// MsgExprUndefArgs - Nodes in the ExplodedGraph resulting from
+ /// message expressions where a pass-by-value argument has an undefined
+ /// value.
+ UndefArgsTy MsgExprUndefArgs;
+
+ /// OutOfBoundMemAccesses - Nodes in the ExplodedGraph resulting from
+ /// out-of-bound memory accesses where the index MAY be out-of-bound.
+ ErrorNodes ImplicitOOBMemAccesses;
+
+ /// OutOfBoundMemAccesses - Nodes in the ExplodedGraph resulting from
+ /// out-of-bound memory accesses where the index MUST be out-of-bound.
+ ErrorNodes ExplicitOOBMemAccesses;
+
+public:
+ GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx, LiveVariables& L,
+ BugReporterData& BRD,
+ bool purgeDead, bool eagerlyAssume = true,
+ StoreManagerCreator SMC = CreateBasicStoreManager,
+ ConstraintManagerCreator CMC = CreateBasicConstraintManager);
+
+ ~GRExprEngine();
+
+ void ExecuteWorkList(unsigned Steps = 150000) {
+ CoreEngine.ExecuteWorkList(Steps);
+ }
+
+ /// getContext - Return the ASTContext associated with this analysis.
+ ASTContext& getContext() const { return G.getContext(); }
+
+ /// getCFG - Returns the CFG associated with this analysis.
+ CFG& getCFG() { return G.getCFG(); }
+
+ GRTransferFuncs& getTF() { return *StateMgr.TF; }
+
+ BugReporter& getBugReporter() { return BR; }
+
+ /// setTransferFunctions
+ void setTransferFunctions(GRTransferFuncs* tf);
+
+ void setTransferFunctions(GRTransferFuncs& tf) {
+ setTransferFunctions(&tf);
+ }
+
+ /// ViewGraph - Visualize the ExplodedGraph created by executing the
+ /// simulation.
+ void ViewGraph(bool trim = false);
+
+ void ViewGraph(NodeTy** Beg, NodeTy** End);
+
+ /// getLiveness - Returned computed live-variables information for the
+ /// analyzed function.
+ const LiveVariables& getLiveness() const { return Liveness; }
+ LiveVariables& getLiveness() { return Liveness; }
+
+ /// getInitialState - Return the initial state used for the root vertex
+ /// in the ExplodedGraph.
+ const GRState* getInitialState();
+
+ GraphTy& getGraph() { return G; }
+ const GraphTy& getGraph() const { return G; }
+
+ void RegisterInternalChecks();
+
+ bool isRetStackAddr(const NodeTy* N) const {
+ return N->isSink() && RetsStackAddr.count(const_cast<NodeTy*>(N)) != 0;
+ }
+
+ bool isUndefControlFlow(const NodeTy* N) const {
+ return N->isSink() && UndefBranches.count(const_cast<NodeTy*>(N)) != 0;
+ }
+
+ bool isUndefStore(const NodeTy* N) const {
+ return N->isSink() && UndefStores.count(const_cast<NodeTy*>(N)) != 0;
+ }
+
+ bool isImplicitNullDeref(const NodeTy* N) const {
+ return N->isSink() && ImplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0;
+ }
+
+ bool isExplicitNullDeref(const NodeTy* N) const {
+ return N->isSink() && ExplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0;
+ }
+
+ bool isUndefDeref(const NodeTy* N) const {
+ return N->isSink() && UndefDeref.count(const_cast<NodeTy*>(N)) != 0;
+ }
+
+ bool isImplicitBadDivide(const NodeTy* N) const {
+ return N->isSink() && ImplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0;
+ }
+
+ bool isExplicitBadDivide(const NodeTy* N) const {
+ return N->isSink() && ExplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0;
+ }
+
+ bool isNoReturnCall(const NodeTy* N) const {
+ return N->isSink() && NoReturnCalls.count(const_cast<NodeTy*>(N)) != 0;
+ }
+
+ bool isUndefResult(const NodeTy* N) const {
+ return N->isSink() && UndefResults.count(const_cast<NodeTy*>(N)) != 0;
+ }
+
+ bool isBadCall(const NodeTy* N) const {
+ return N->isSink() && BadCalls.count(const_cast<NodeTy*>(N)) != 0;
+ }
+
+ bool isUndefArg(const NodeTy* N) const {
+ return N->isSink() &&
+ (UndefArgs.find(const_cast<NodeTy*>(N)) != UndefArgs.end() ||
+ MsgExprUndefArgs.find(const_cast<NodeTy*>(N)) != MsgExprUndefArgs.end());
+ }
+
+ bool isUndefReceiver(const NodeTy* N) const {
+ return N->isSink() && UndefReceivers.count(const_cast<NodeTy*>(N)) != 0;
+ }
+
+ typedef ErrorNodes::iterator ret_stackaddr_iterator;
+ ret_stackaddr_iterator ret_stackaddr_begin() { return RetsStackAddr.begin(); }
+ ret_stackaddr_iterator ret_stackaddr_end() { return RetsStackAddr.end(); }
+
+ typedef ErrorNodes::iterator ret_undef_iterator;
+ ret_undef_iterator ret_undef_begin() { return RetsUndef.begin(); }
+ ret_undef_iterator ret_undef_end() { return RetsUndef.end(); }
+
+ typedef ErrorNodes::iterator undef_branch_iterator;
+ undef_branch_iterator undef_branches_begin() { return UndefBranches.begin(); }
+ undef_branch_iterator undef_branches_end() { return UndefBranches.end(); }
+
+ typedef ErrorNodes::iterator null_deref_iterator;
+ null_deref_iterator null_derefs_begin() { return ExplicitNullDeref.begin(); }
+ null_deref_iterator null_derefs_end() { return ExplicitNullDeref.end(); }
+
+ null_deref_iterator implicit_null_derefs_begin() {
+ return ImplicitNullDeref.begin();
+ }
+ null_deref_iterator implicit_null_derefs_end() {
+ return ImplicitNullDeref.end();
+ }
+
+ typedef ErrorNodes::iterator nil_receiver_struct_ret_iterator;
+
+ nil_receiver_struct_ret_iterator nil_receiver_struct_ret_begin() {
+ return NilReceiverStructRetExplicit.begin();
+ }
+
+ nil_receiver_struct_ret_iterator nil_receiver_struct_ret_end() {
+ return NilReceiverStructRetExplicit.end();
+ }
+
+ typedef ErrorNodes::iterator nil_receiver_larger_than_voidptr_ret_iterator;
+
+ nil_receiver_larger_than_voidptr_ret_iterator
+ nil_receiver_larger_than_voidptr_ret_begin() {
+ return NilReceiverLargerThanVoidPtrRetExplicit.begin();
+ }
+
+ nil_receiver_larger_than_voidptr_ret_iterator
+ nil_receiver_larger_than_voidptr_ret_end() {
+ return NilReceiverLargerThanVoidPtrRetExplicit.end();
+ }
+
+ typedef ErrorNodes::iterator undef_deref_iterator;
+ undef_deref_iterator undef_derefs_begin() { return UndefDeref.begin(); }
+ undef_deref_iterator undef_derefs_end() { return UndefDeref.end(); }
+
+ typedef ErrorNodes::iterator bad_divide_iterator;
+
+ bad_divide_iterator explicit_bad_divides_begin() {
+ return ExplicitBadDivides.begin();
+ }
+
+ bad_divide_iterator explicit_bad_divides_end() {
+ return ExplicitBadDivides.end();
+ }
+
+ bad_divide_iterator implicit_bad_divides_begin() {
+ return ImplicitBadDivides.begin();
+ }
+
+ bad_divide_iterator implicit_bad_divides_end() {
+ return ImplicitBadDivides.end();
+ }
+
+ typedef ErrorNodes::iterator undef_result_iterator;
+ undef_result_iterator undef_results_begin() { return UndefResults.begin(); }
+ undef_result_iterator undef_results_end() { return UndefResults.end(); }
+
+ typedef ErrorNodes::iterator bad_calls_iterator;
+ bad_calls_iterator bad_calls_begin() { return BadCalls.begin(); }
+ bad_calls_iterator bad_calls_end() { return BadCalls.end(); }
+
+ typedef UndefArgsTy::iterator undef_arg_iterator;
+ undef_arg_iterator undef_arg_begin() { return UndefArgs.begin(); }
+ undef_arg_iterator undef_arg_end() { return UndefArgs.end(); }
+
+ undef_arg_iterator msg_expr_undef_arg_begin() {
+ return MsgExprUndefArgs.begin();
+ }
+ undef_arg_iterator msg_expr_undef_arg_end() {
+ return MsgExprUndefArgs.end();
+ }
+
+ typedef ErrorNodes::iterator undef_receivers_iterator;
+
+ undef_receivers_iterator undef_receivers_begin() {
+ return UndefReceivers.begin();
+ }
+
+ undef_receivers_iterator undef_receivers_end() {
+ return UndefReceivers.end();
+ }
+
+ typedef ErrorNodes::iterator oob_memacc_iterator;
+ oob_memacc_iterator implicit_oob_memacc_begin() {
+ return ImplicitOOBMemAccesses.begin();
+ }
+ oob_memacc_iterator implicit_oob_memacc_end() {
+ return ImplicitOOBMemAccesses.end();
+ }
+ oob_memacc_iterator explicit_oob_memacc_begin() {
+ return ExplicitOOBMemAccesses.begin();
+ }
+ oob_memacc_iterator explicit_oob_memacc_end() {
+ return ExplicitOOBMemAccesses.end();
+ }
+
+ void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C);
+ void AddCheck(GRSimpleAPICheck* A);
+
+ /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor
+ /// nodes by processing the 'effects' of a block-level statement.
+ void ProcessStmt(Stmt* S, StmtNodeBuilder& builder);
+
+ /// ProcessBlockEntrance - Called by GRCoreEngine when start processing
+ /// a CFGBlock. This method returns true if the analysis should continue
+ /// exploring the given path, and false otherwise.
+ bool ProcessBlockEntrance(CFGBlock* B, const GRState* St,
+ GRBlockCounter BC);
+
+ /// ProcessBranch - Called by GRCoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a branch condition.
+ void ProcessBranch(Stmt* Condition, Stmt* Term, BranchNodeBuilder& builder);
+
+ /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a computed goto jump.
+ void ProcessIndirectGoto(IndirectGotoNodeBuilder& builder);
+
+ /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a switch statement.
+ void ProcessSwitch(SwitchNodeBuilder& builder);
+
+ /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
+ /// nodes when the control reaches the end of a function.
+ void ProcessEndPath(EndPathNodeBuilder& builder) {
+ getTF().EvalEndPath(*this, builder);
+ StateMgr.EndPath(builder.getState());
+ }
+
+ GRStateManager& getStateManager() { return StateMgr; }
+ const GRStateManager& getStateManager() const { return StateMgr; }
+
+ StoreManager& getStoreManager() { return StateMgr.getStoreManager(); }
+
+ ConstraintManager& getConstraintManager() {
+ return StateMgr.getConstraintManager();
+ }
+
+ // FIXME: Remove when we migrate over to just using ValueManager.
+ BasicValueFactory& getBasicVals() {
+ return StateMgr.getBasicVals();
+ }
+ const BasicValueFactory& getBasicVals() const {
+ return StateMgr.getBasicVals();
+ }
+
+ ValueManager &getValueManager() { return ValMgr; }
+ const ValueManager &getValueManager() const { return ValMgr; }
+
+ // FIXME: Remove when we migrate over to just using ValueManager.
+ SymbolManager& getSymbolManager() { return SymMgr; }
+ const SymbolManager& getSymbolManager() const { return SymMgr; }
+
+protected:
+
+ const GRState* GetState(NodeTy* N) {
+ return N == EntryNode ? CleanedState : N->getState();
+ }
+
+public:
+
+ const GRState* BindExpr(const GRState* St, Expr* Ex, SVal V) {
+ return StateMgr.BindExpr(St, Ex, V);
+ }
+
+ const GRState* BindExpr(const GRState* St, const Expr* Ex, SVal V) {
+ return BindExpr(St, const_cast<Expr*>(Ex), V);
+ }
+
+protected:
+
+ const GRState* BindBlkExpr(const GRState* St, Expr* Ex, SVal V) {
+ return StateMgr.BindExpr(St, Ex, V, true, false);
+ }
+
+ const GRState* BindLoc(const GRState* St, Loc LV, SVal V) {
+ return StateMgr.BindLoc(St, LV, V);
+ }
+
+ SVal GetSVal(const GRState* St, Stmt* Ex) {
+ return StateMgr.GetSVal(St, Ex);
+ }
+
+ SVal GetSVal(const GRState* St, const Stmt* Ex) {
+ return GetSVal(St, const_cast<Stmt*>(Ex));
+ }
+
+ SVal GetBlkExprSVal(const GRState* St, Stmt* Ex) {
+ return StateMgr.GetBlkExprSVal(St, Ex);
+ }
+
+ SVal GetSVal(const GRState* St, Loc LV, QualType T = QualType()) {
+ return StateMgr.GetSVal(St, LV, T);
+ }
+
+ inline NonLoc MakeConstantVal(uint64_t X, Expr* Ex) {
+ return NonLoc::MakeVal(getBasicVals(), X, Ex->getType());
+ }
+
+ /// Assume - Create new state by assuming that a given expression
+ /// is true or false.
+ const GRState* Assume(const GRState* St, SVal Cond, bool Assumption,
+ bool& isFeasible) {
+ return StateMgr.Assume(St, Cond, Assumption, isFeasible);
+ }
+
+ const GRState* Assume(const GRState* St, Loc Cond, bool Assumption,
+ bool& isFeasible) {
+ return StateMgr.Assume(St, Cond, Assumption, isFeasible);
+ }
+
+ const GRState* AssumeInBound(const GRState* St, SVal Idx, SVal UpperBound,
+ bool Assumption, bool& isFeasible) {
+ return StateMgr.AssumeInBound(St, Idx, UpperBound, Assumption, isFeasible);
+ }
+
+public:
+ NodeTy* MakeNode(NodeSet& Dst, Stmt* S, NodeTy* Pred, const GRState* St,
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
+ const void *tag = 0);
+protected:
+
+ /// Visit - Transfer function logic for all statements. Dispatches to
+ /// other functions that handle specific kinds of statements.
+ void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst);
+
+ /// VisitLValue - Evaluate the lvalue of the expression. For example, if Ex is
+ /// a DeclRefExpr, it evaluates to the MemRegionVal which represents its
+ /// storage location. Note that not all kinds of expressions has lvalue.
+ void VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst);
+
+ /// VisitArraySubscriptExpr - Transfer function for array accesses.
+ void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, NodeTy* Pred,
+ NodeSet& Dst, bool asLValue);
+
+ /// VisitAsmStmt - Transfer function logic for inline asm.
+ void VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst);
+
+ void VisitAsmStmtHelperOutputs(AsmStmt* A,
+ AsmStmt::outputs_iterator I,
+ AsmStmt::outputs_iterator E,
+ NodeTy* Pred, NodeSet& Dst);
+
+ void VisitAsmStmtHelperInputs(AsmStmt* A,
+ AsmStmt::inputs_iterator I,
+ AsmStmt::inputs_iterator E,
+ NodeTy* Pred, NodeSet& Dst);
+
+ /// VisitBinaryOperator - Transfer function logic for binary operators.
+ void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
+
+
+ /// VisitCall - Transfer function for function calls.
+ void VisitCall(CallExpr* CE, NodeTy* Pred,
+ CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
+ NodeSet& Dst);
+ void VisitCallRec(CallExpr* CE, NodeTy* Pred,
+ CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
+ NodeSet& Dst, const FunctionProtoType *,
+ unsigned ParamIdx = 0);
+
+ /// VisitCast - Transfer function logic for all casts (implicit and explicit).
+ void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst);
+
+ /// VisitCastPointerToInteger - Transfer function (called by VisitCast) that
+ /// handles pointer to integer casts and array to integer casts.
+ void VisitCastPointerToInteger(SVal V, const GRState* state, QualType PtrTy,
+ Expr* CastE, NodeTy* Pred, NodeSet& Dst);
+
+ /// VisitCompoundLiteralExpr - Transfer function logic for compound literals.
+ void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, NodeTy* Pred,
+ NodeSet& Dst, bool asLValue);
+
+ /// VisitDeclRefExpr - Transfer function logic for DeclRefExprs.
+ void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
+ bool asLValue);
+
+ /// VisitDeclStmt - Transfer function logic for DeclStmts.
+ void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst);
+
+ /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
+ void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst);
+
+ void VisitInitListExpr(InitListExpr* E, NodeTy* Pred, NodeSet& Dst);
+
+ /// VisitLogicalExpr - Transfer function logic for '&&', '||'
+ void VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
+
+ /// VisitMemberExpr - Transfer function for member expressions.
+ void VisitMemberExpr(MemberExpr* M, NodeTy* Pred, NodeSet& Dst,bool asLValue);
+
+ /// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs.
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
+ bool asLValue);
+
+ /// VisitObjCForCollectionStmt - Transfer function logic for
+ /// ObjCForCollectionStmt.
+ void VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, NodeTy* Pred,
+ NodeSet& Dst);
+
+ void VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, NodeTy* Pred,
+ NodeSet& Dst, SVal ElementV);
+
+ /// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
+ void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst);
+
+ void VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
+ ObjCMessageExpr::arg_iterator I,
+ ObjCMessageExpr::arg_iterator E,
+ NodeTy* Pred, NodeSet& Dst);
+
+ void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, NodeTy* Pred,
+ NodeSet& Dst);
+
+ /// VisitReturnStmt - Transfer function logic for return statements.
+ void VisitReturnStmt(ReturnStmt* R, NodeTy* Pred, NodeSet& Dst);
+
+ /// VisitSizeOfAlignOfExpr - Transfer function for sizeof.
+ void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, NodeTy* Pred,
+ NodeSet& Dst);
+
+ /// VisitUnaryOperator - Transfer function logic for unary operators.
+ void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst,
+ bool asLValue);
+
+ const GRState* CheckDivideZero(Expr* Ex, const GRState* St, NodeTy* Pred,
+ SVal Denom);
+
+ /// 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(NodeSet& Dst, NodeSet& Src, Expr *Ex);
+
+ SVal EvalCast(SVal X, QualType CastT) {
+ if (X.isUnknownOrUndef())
+ return X;
+
+ if (isa<Loc>(X))
+ return getTF().EvalCast(*this, cast<Loc>(X), CastT);
+ else
+ return getTF().EvalCast(*this, cast<NonLoc>(X), CastT);
+ }
+
+ SVal EvalMinus(UnaryOperator* U, SVal X) {
+ return X.isValid() ? getTF().EvalMinus(*this, U, cast<NonLoc>(X)) : X;
+ }
+
+ SVal EvalComplement(SVal X) {
+ return X.isValid() ? getTF().EvalComplement(*this, cast<NonLoc>(X)) : X;
+ }
+
+public:
+
+ SVal EvalBinOp(BinaryOperator::Opcode Op, NonLoc L, NonLoc R, QualType T) {
+ return R.isValid() ? getTF().DetermEvalBinOpNN(*this, Op, L, R, T)
+ : R;
+ }
+
+ SVal EvalBinOp(BinaryOperator::Opcode Op, NonLoc L, SVal R, QualType T) {
+ return R.isValid() ? getTF().DetermEvalBinOpNN(*this, Op, L,
+ cast<NonLoc>(R), T) : R;
+ }
+
+ void EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex,
+ BinaryOperator::Opcode Op, NonLoc L, NonLoc R,
+ ExplodedNode<GRState>* Pred, QualType T);
+
+ void EvalBinOp(GRStateSet& OStates, const GRState* St, Expr* Ex,
+ BinaryOperator::Opcode Op, NonLoc L, NonLoc R, QualType T);
+
+ SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op, SVal L,SVal R,
+ QualType T);
+
+protected:
+
+ void EvalCall(NodeSet& Dst, CallExpr* CE, SVal L, NodeTy* Pred);
+
+ void EvalObjCMessageExpr(NodeSet& Dst, ObjCMessageExpr* ME, NodeTy* Pred) {
+ assert (Builder && "GRStmtNodeBuilder must be defined.");
+ getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred);
+ }
+
+ void EvalReturn(NodeSet& Dst, ReturnStmt* s, NodeTy* Pred);
+
+ const GRState* MarkBranch(const GRState* St, 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(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
+ const GRState* St, SVal location, SVal Val);
+
+public:
+ void EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
+ const GRState* St, SVal location, const void *tag = 0);
+
+ NodeTy* EvalLocation(Stmt* Ex, NodeTy* Pred,
+ const GRState* St, SVal location,
+ const void *tag = 0);
+
+
+ void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, const GRState* St,
+ SVal TargetLV, SVal Val, const void *tag = 0);
+
+ void EvalStore(NodeSet& Dst, Expr* E, Expr* StoreE, NodeTy* Pred,
+ const GRState* St, SVal TargetLV, SVal Val,
+ const void *tag = 0);
+
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h b/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h
new file mode 100644
index 000000000000..6c23745de23a
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h
@@ -0,0 +1,101 @@
+//===-- GRExprEngineBuilders.h - "Builder" classes for GRExprEngine -*- 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 smart builder "references" which are used to marshal
+// builders between GRExprEngine objects and their related components.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS
+#define LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+
+namespace clang {
+
+
+// SaveAndRestore - A utility class that uses RAII to save and restore
+// the value of a variable.
+template<typename T>
+struct SaveAndRestore {
+ SaveAndRestore(T& x) : X(x), old_value(x) {}
+ ~SaveAndRestore() { X = old_value; }
+ T get() { return old_value; }
+private:
+ T& X;
+ T old_value;
+};
+
+// SaveOr - Similar to SaveAndRestore. Operates only on bools; the old
+// value of a variable is saved, and during the dstor the old value is
+// or'ed with the new value.
+struct SaveOr {
+ SaveOr(bool& x) : X(x), old_value(x) { x = false; }
+ ~SaveOr() { X |= old_value; }
+private:
+ bool& X;
+ const bool old_value;
+};
+
+class GRStmtNodeBuilderRef {
+ GRExprEngine::NodeSet &Dst;
+ GRExprEngine::StmtNodeBuilder &B;
+ GRExprEngine& Eng;
+ GRExprEngine::NodeTy* Pred;
+ const GRState* state;
+ const Stmt* stmt;
+ const unsigned OldSize;
+ const bool AutoCreateNode;
+ SaveAndRestore<bool> OldSink;
+ SaveAndRestore<const void*> OldTag;
+ SaveOr OldHasGen;
+
+private:
+ friend class GRExprEngine;
+
+ GRStmtNodeBuilderRef(); // do not implement
+ void operator=(const GRStmtNodeBuilderRef&); // do not implement
+
+ GRStmtNodeBuilderRef(GRExprEngine::NodeSet &dst,
+ GRExprEngine::StmtNodeBuilder &builder,
+ GRExprEngine& eng,
+ GRExprEngine::NodeTy* pred,
+ const GRState *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), OldTag(B.Tag), OldHasGen(B.HasGeneratedNode) {}
+
+public:
+
+ ~GRStmtNodeBuilderRef() {
+ // Handle the case where no nodes where generated. Auto-generate that
+ // contains the updated state if we aren't generating sinks.
+ if (!B.BuildSinks && Dst.size() == OldSize && !B.HasGeneratedNode) {
+ if (AutoCreateNode)
+ B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
+ else
+ Dst.Add(Pred);
+ }
+ }
+
+ GRStateRef getState() {
+ return GRStateRef(state, Eng.getStateManager());
+ }
+
+ GRStateManager& getStateManager() {
+ return Eng.getStateManager();
+ }
+
+ GRExprEngine::NodeTy* MakeNode(const GRState* state) {
+ return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
+ }
+};
+
+} // end clang namespace
+#endif
diff --git a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h
new file mode 100644
index 000000000000..e54b31dfe883
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h
@@ -0,0 +1,40 @@
+// GRCheckAPI.h - Simple API checks based on GRAuditor ------------*- 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 for building simple, path-sensitive checks
+// that are stateless and only emit warnings at errors that occur at
+// CallExpr or ObjCMessageExpr.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRAPICHECKS
+#define LLVM_CLANG_ANALYSIS_GRAPICHECKS
+
+#include "clang/Analysis/PathSensitive/GRAuditor.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+
+namespace clang {
+
+class Diagnostic;
+class BugReporter;
+class ASTContext;
+class GRExprEngine;
+class PathDiagnosticClient;
+template <typename T> class ExplodedGraph;
+
+
+class GRSimpleAPICheck : public GRAuditor<GRState> {
+public:
+ GRSimpleAPICheck() {}
+ virtual ~GRSimpleAPICheck() {}
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Analysis/PathSensitive/GRState.h
new file mode 100644
index 000000000000..d61feea4819e
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/GRState.h
@@ -0,0 +1,820 @@
+//== GRState*h - Path-Sens. "State" for tracking valuues -----*- 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 SymbolRef, ExprBindKey, and GRState*
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_VALUESTATE_H
+#define LLVM_CLANG_ANALYSIS_VALUESTATE_H
+
+// FIXME: Reduce the number of includes.
+
+#include "clang/Analysis/PathSensitive/Environment.h"
+#include "clang/Analysis/PathSensitive/Store.h"
+#include "clang/Analysis/PathSensitive/ConstraintManager.h"
+#include "clang/Analysis/PathSensitive/ValueManager.h"
+#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Streams.h"
+
+#include <functional>
+
+namespace clang {
+
+class GRStateManager;
+class GRTransferFuncs;
+
+typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&);
+typedef StoreManager* (*StoreManagerCreator)(GRStateManager&);
+
+//===----------------------------------------------------------------------===//
+// GRStateTrait - Traits used by the Generic Data Map of a GRState.
+//===----------------------------------------------------------------------===//
+
+template <typename T> struct GRStatePartialTrait;
+
+template <typename T> struct GRStateTrait {
+ 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) {
+ return P ? (data_type) *P : (data_type) 0;
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// GRState- An ImmutableMap type Stmt*/Decl*/Symbols to SVals.
+//===----------------------------------------------------------------------===//
+
+/// GRState - This class encapsulates the actual data values for
+/// for a "state" in our symbolic value tracking. It 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 {
+public:
+ // Typedefs.
+ typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy;
+ typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
+
+ typedef GRStateManager ManagerTy;
+
+private:
+ void operator=(const GRState& R) const;
+
+ friend class GRStateManager;
+
+ Environment Env;
+ Store St;
+
+ // FIXME: Make these private.
+public:
+ GenericDataMap GDM;
+
+public:
+
+ /// This ctor is used when creating the first GRState object.
+ GRState(const Environment& env, Store st, GenericDataMap gdm)
+ : Env(env),
+ St(st),
+ GDM(gdm) {}
+
+ /// Copy ctor - We must explicitly define this or else the "Next" ptr
+ /// in FoldingSetNode will also get copied.
+ GRState(const GRState& RHS)
+ : llvm::FoldingSetNode(),
+ Env(RHS.Env),
+ St(RHS.St),
+ GDM(RHS.GDM) {}
+
+ /// getEnvironment - Return the environment associated with this state.
+ /// The environment is the mapping from expressions to values.
+ const Environment& getEnvironment() const { return Env; }
+
+ /// getStore - Return the store associated with this state. The store
+ /// is a mapping from locations to values.
+ Store getStore() const { return St; }
+
+ /// getGDM - Return the generic data map associated with this state.
+ GenericDataMap getGDM() const { return GDM; }
+
+ /// Profile - Profile the contents of a GRState object for use
+ /// in a FoldingSet.
+ static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) {
+ V->Env.Profile(ID);
+ ID.AddPointer(V->St);
+ V->GDM.Profile(ID);
+ }
+
+ /// Profile - Used to profile the contents of this object for inclusion
+ /// in a FoldingSet.
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ Profile(ID, this);
+ }
+
+ SVal LookupExpr(Expr* E) const {
+ return Env.LookupExpr(E);
+ }
+
+ // Iterators.
+ typedef Environment::seb_iterator seb_iterator;
+ seb_iterator seb_begin() const { return Env.seb_begin(); }
+ seb_iterator seb_end() const { return Env.beb_end(); }
+
+ typedef Environment::beb_iterator beb_iterator;
+ beb_iterator beb_begin() const { return Env.beb_begin(); }
+ beb_iterator beb_end() const { return Env.beb_end(); }
+
+ // Trait based GDM dispatch.
+ void* const* FindGDM(void* K) const;
+
+ template <typename T>
+ typename GRStateTrait<T>::data_type
+ get() const {
+ return GRStateTrait<T>::MakeData(FindGDM(GRStateTrait<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);
+ }
+
+ 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);
+ }
+
+ // State pretty-printing.
+ class Printer {
+ public:
+ virtual ~Printer() {}
+ virtual void Print(std::ostream& Out, const GRState* state,
+ const char* nl, const char* sep) = 0;
+ };
+
+ void print(std::ostream& Out, StoreManager& StoreMgr,
+ ConstraintManager& ConstraintMgr,
+ Printer **Beg = 0, Printer **End = 0,
+ const char* nl = "\n", const char *sep = "") const;
+
+ // Tags used for the Generic Data Map.
+ struct NullDerefTag {
+ static int TagInt;
+ typedef const SVal* data_type;
+ };
+};
+
+template<> struct GRTrait<GRState*> {
+ static inline void* toPtr(GRState* St) { return (void*) St; }
+ static inline GRState* toState(void* P) { return (GRState*) P; }
+ static inline void Profile(llvm::FoldingSetNodeID& profile, GRState* St) {
+ // At this point states have already been uniqued. Just
+ // add the pointer.
+ profile.AddPointer(St);
+ }
+};
+
+
+class GRStateSet {
+ typedef llvm::SmallPtrSet<const GRState*,5> ImplTy;
+ ImplTy Impl;
+public:
+ GRStateSet() {}
+
+ inline void Add(const GRState* St) {
+ Impl.insert(St);
+ }
+
+ typedef ImplTy::const_iterator iterator;
+
+ inline unsigned size() const { return Impl.size(); }
+ inline bool empty() const { return Impl.empty(); }
+
+ inline iterator begin() const { return Impl.begin(); }
+ inline iterator end() const { return Impl.end(); }
+
+ class AutoPopulate {
+ GRStateSet& S;
+ unsigned StartSize;
+ const GRState* St;
+ public:
+ AutoPopulate(GRStateSet& s, const GRState* st)
+ : S(s), StartSize(S.size()), St(st) {}
+
+ ~AutoPopulate() {
+ if (StartSize == S.size())
+ S.Add(St);
+ }
+ };
+};
+
+//===----------------------------------------------------------------------===//
+// GRStateManager - Factory object for GRStates.
+//===----------------------------------------------------------------------===//
+
+class GRStateRef;
+
+class GRStateManager {
+ friend class GRExprEngine;
+ friend class GRStateRef;
+
+private:
+ EnvironmentManager EnvMgr;
+ llvm::OwningPtr<StoreManager> StoreMgr;
+ llvm::OwningPtr<ConstraintManager> ConstraintMgr;
+ GRState::IntSetTy::Factory ISetFactory;
+
+ GRState::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;
+
+ /// ValueMgr - Object that manages the data for all created SVals.
+ ValueManager ValueMgr;
+
+ /// Alloc - A BumpPtrAllocator to allocate states.
+ llvm::BumpPtrAllocator& Alloc;
+
+ /// CurrentStmt - The block-level statement currently being visited. This
+ /// is set by GRExprEngine.
+ Stmt* CurrentStmt;
+
+ /// cfg - The CFG for the analyzed function/method.
+ CFG& cfg;
+
+ /// codedecl - The Decl representing the function/method being analyzed.
+ const Decl& codedecl;
+
+ /// TF - Object that represents a bundle of transfer functions
+ /// for manipulating and creating SVals.
+ GRTransferFuncs* TF;
+
+ /// Liveness - live-variables information of the ValueDecl* and block-level
+ /// Expr* in the CFG. Used to get initial store and prune out dead state.
+ LiveVariables& Liveness;
+
+private:
+
+ Environment RemoveBlkExpr(const Environment& Env, Expr* E) {
+ return EnvMgr.RemoveBlkExpr(Env, E);
+ }
+
+ // FIXME: Remove when we do lazy initializaton of variable bindings.
+// const GRState* BindVar(const GRState* St, VarDecl* D, SVal V) {
+// return SetSVal(St, getLoc(D), V);
+// }
+
+public:
+
+ GRStateManager(ASTContext& Ctx,
+ StoreManagerCreator CreateStoreManager,
+ ConstraintManagerCreator CreateConstraintManager,
+ llvm::BumpPtrAllocator& alloc, CFG& c,
+ const Decl& cd, LiveVariables& L)
+ : EnvMgr(alloc),
+ ISetFactory(alloc),
+ GDMFactory(alloc),
+ ValueMgr(alloc, Ctx),
+ Alloc(alloc),
+ cfg(c),
+ codedecl(cd),
+ Liveness(L) {
+ StoreMgr.reset((*CreateStoreManager)(*this));
+ ConstraintMgr.reset((*CreateConstraintManager)(*this));
+ }
+
+ ~GRStateManager();
+
+ const GRState* getInitialState();
+
+ ASTContext &getContext() { return ValueMgr.getContext(); }
+ const ASTContext &getContext() const { return ValueMgr.getContext(); }
+
+ const Decl &getCodeDecl() { return codedecl; }
+ GRTransferFuncs& getTransferFuncs() { return *TF; }
+
+ BasicValueFactory &getBasicVals() {
+ return ValueMgr.getBasicValueFactory();
+ }
+ const BasicValueFactory& getBasicVals() const {
+ return ValueMgr.getBasicValueFactory();
+ }
+
+ SymbolManager &getSymbolManager() {
+ return ValueMgr.getSymbolManager();
+ }
+ const SymbolManager &getSymbolManager() const {
+ return ValueMgr.getSymbolManager();
+ }
+
+ ValueManager &getValueManager() { return ValueMgr; }
+ const ValueManager &getValueManager() const { return ValueMgr; }
+
+ LiveVariables& getLiveVariables() { return Liveness; }
+ llvm::BumpPtrAllocator& getAllocator() { return Alloc; }
+
+ MemRegionManager& getRegionManager() {
+ return ValueMgr.getRegionManager();
+ }
+ const MemRegionManager& getRegionManager() const {
+ return ValueMgr.getRegionManager();
+ }
+
+ StoreManager& getStoreManager() { return *StoreMgr; }
+ ConstraintManager& getConstraintManager() { return *ConstraintMgr; }
+
+ const GRState* BindDecl(const GRState* St, const VarDecl* VD, SVal IVal) {
+ // Store manager should return a persistent state.
+ return StoreMgr->BindDecl(St, VD, IVal);
+ }
+
+ const GRState* BindDeclWithNoInit(const GRState* St, const VarDecl* VD) {
+ // Store manager should return a persistent state.
+ return StoreMgr->BindDeclWithNoInit(St, VD);
+ }
+
+ /// BindCompoundLiteral - Return the state that has the bindings currently
+ /// in 'state' plus the bindings for the CompoundLiteral. 'R' is the region
+ /// for the compound literal and 'BegInit' and 'EndInit' represent an
+ /// array of initializer values.
+ const GRState* BindCompoundLiteral(const GRState* St,
+ const CompoundLiteralExpr* CL, SVal V) {
+ return StoreMgr->BindCompoundLiteral(St, CL, V);
+ }
+
+ const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc,
+ SymbolReaper& SymReaper);
+
+ const GRState* RemoveSubExprBindings(const GRState* St) {
+ GRState NewSt = *St;
+ NewSt.Env = EnvMgr.RemoveSubExprBindings(NewSt.Env);
+ return getPersistentState(NewSt);
+ }
+
+
+ // Utility methods for getting regions.
+
+ VarRegion* getRegion(const VarDecl* D) {
+ return getRegionManager().getVarRegion(D);
+ }
+
+ const MemRegion* getSelfRegion(const GRState* state) {
+ return StoreMgr->getSelfRegion(state->getStore());
+ }
+
+ // Get the lvalue for a variable reference.
+ SVal GetLValue(const GRState* St, const VarDecl* D) {
+ return StoreMgr->getLValueVar(St, D);
+ }
+
+ // Get the lvalue for a StringLiteral.
+ SVal GetLValue(const GRState* St, const StringLiteral* E) {
+ return StoreMgr->getLValueString(St, E);
+ }
+
+ SVal GetLValue(const GRState* St, const CompoundLiteralExpr* CL) {
+ return StoreMgr->getLValueCompoundLiteral(St, CL);
+ }
+
+ // Get the lvalue for an ivar reference.
+ SVal GetLValue(const GRState* St, const ObjCIvarDecl* D, SVal Base) {
+ return StoreMgr->getLValueIvar(St, D, Base);
+ }
+
+ // Get the lvalue for a field reference.
+ SVal GetLValue(const GRState* St, SVal Base, const FieldDecl* D) {
+ return StoreMgr->getLValueField(St, Base, D);
+ }
+
+ // Get the lvalue for an array index.
+ SVal GetLValue(const GRState* St, QualType ElementType, SVal Base, SVal Idx) {
+ return StoreMgr->getLValueElement(St, ElementType, Base, Idx);
+ }
+
+ // Methods that query & manipulate the Environment.
+
+ SVal GetSVal(const GRState* St, Stmt* Ex) {
+ return St->getEnvironment().GetSVal(Ex, getBasicVals());
+ }
+
+ SVal GetSValAsScalarOrLoc(const GRState* state, const Stmt *S) {
+ if (const Expr *Ex = dyn_cast<Expr>(S)) {
+ QualType T = Ex->getType();
+ if (Loc::IsLocType(T) || T->isIntegerType())
+ return GetSVal(state, S);
+ }
+
+ return UnknownVal();
+ }
+
+
+ SVal GetSVal(const GRState* St, const Stmt* Ex) {
+ return St->getEnvironment().GetSVal(const_cast<Stmt*>(Ex), getBasicVals());
+ }
+
+ SVal GetBlkExprSVal(const GRState* St, Stmt* Ex) {
+ return St->getEnvironment().GetBlkExprSVal(Ex, getBasicVals());
+ }
+
+
+
+ const GRState* BindExpr(const GRState* St, Stmt* Ex, SVal V,
+ bool isBlkExpr, bool Invalidate) {
+
+ const Environment& OldEnv = St->getEnvironment();
+ Environment NewEnv = EnvMgr.BindExpr(OldEnv, Ex, V, isBlkExpr, Invalidate);
+
+ if (NewEnv == OldEnv)
+ return St;
+
+ GRState NewSt = *St;
+ NewSt.Env = NewEnv;
+ return getPersistentState(NewSt);
+ }
+
+ const GRState* BindExpr(const GRState* St, Stmt* Ex, SVal V,
+ bool Invalidate = true) {
+
+ bool isBlkExpr = false;
+
+ if (Ex == CurrentStmt) {
+ // FIXME: Should this just be an assertion? When would we want to set
+ // the value of a block-level expression if it wasn't CurrentStmt?
+ isBlkExpr = cfg.isBlkExpr(Ex);
+
+ if (!isBlkExpr)
+ return St;
+ }
+
+ return BindExpr(St, Ex, V, isBlkExpr, Invalidate);
+ }
+
+ SVal ArrayToPointer(Loc Array) {
+ return StoreMgr->ArrayToPointer(Array);
+ }
+
+ // Methods that manipulate the GDM.
+ const GRState* addGDM(const GRState* St, void* Key, void* Data);
+
+ // Methods that query or create regions.
+ bool hasStackStorage(const MemRegion* R) {
+ return getRegionManager().hasStackStorage(R);
+ }
+
+ // Methods that query & manipulate the Store.
+
+ void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) {
+ StoreMgr->iterBindings(state->getStore(), F);
+ }
+
+
+ SVal GetSVal(const GRState* state, Loc LV, QualType T = QualType()) {
+ return StoreMgr->Retrieve(state, LV, T);
+ }
+
+ SVal GetSVal(const GRState* state, const MemRegion* R) {
+ return StoreMgr->Retrieve(state, loc::MemRegionVal(R));
+ }
+
+ SVal GetSValAsScalarOrLoc(const GRState* state, const MemRegion *R) {
+ // 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(getContext()))
+ return UnknownVal();
+
+ if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+ QualType T = TR->getValueType(getContext());
+ if (Loc::IsLocType(T) || T->isIntegerType())
+ return GetSVal(state, R);
+ }
+
+ return UnknownVal();
+ }
+
+ const GRState* BindLoc(const GRState* St, Loc LV, SVal V) {
+ return StoreMgr->Bind(St, LV, V);
+ }
+
+ void Unbind(GRState& St, Loc LV) {
+ St.St = StoreMgr->Remove(St.St, LV);
+ }
+
+ const GRState* Unbind(const GRState* St, Loc LV);
+
+ const GRState* getPersistentState(GRState& Impl);
+
+ // MakeStateWithStore - get a persistent state with the new store.
+ const GRState* MakeStateWithStore(const GRState* St, Store store);
+
+ bool isEqual(const GRState* state, Expr* Ex, const llvm::APSInt& V);
+ bool isEqual(const GRState* state, Expr* Ex, uint64_t);
+
+
+ //==---------------------------------------------------------------------==//
+ // 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
+ // 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.
+ // Clients are responsible for ensuring that data values referred to by a
+ // the data pointer are immutable (and thus are essentially purely functional
+ // data).
+ //
+ // The templated methods below use the GRStateTrait<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));
+ }
+
+ 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) {
+
+ return addGDM(st, GRStateTrait<T>::GDMIndex(),
+ GRStateTrait<T>::MakeVoidPtr(GRStateTrait<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)));
+ }
+
+ template <typename T>
+ const GRState* remove(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>::Remove(st->get<T>(), K, C)));
+ }
+
+
+ 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);
+
+ return GRStateTrait<T>::MakeContext(p);
+ }
+
+ //==---------------------------------------------------------------------==//
+ // Constraints on values.
+ //==---------------------------------------------------------------------==//
+ //
+ // Each GRState records constraints on symbolic values. These constraints
+ // are managed using the ConstraintManager associated with a GRStateManager.
+ // 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 GRExprEngine/GRState.
+ //
+ // 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.
+ //
+ // (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" are two values:
+ //
+ // (a) "isFeasible" is set to true or false to indicate whether or not
+ // the assumption is feasible.
+ //
+ // (b) A new GRState object with the added constraints.
+ //
+ // FIXME: (a) should probably disappear since it is redundant with (b).
+ // (i.e., (b) could just be set to NULL).
+ //
+
+ const GRState* Assume(const GRState* St, SVal Cond, bool Assumption,
+ bool& isFeasible) {
+ const GRState *state =
+ ConstraintMgr->Assume(St, Cond, Assumption, isFeasible);
+ assert(!isFeasible || state);
+ return isFeasible ? state : NULL;
+ }
+
+ const GRState* AssumeInBound(const GRState* St, SVal Idx, SVal UpperBound,
+ bool Assumption, bool& isFeasible) {
+ const GRState *state =
+ ConstraintMgr->AssumeInBound(St, Idx, UpperBound, Assumption,
+ isFeasible);
+ assert(!isFeasible || state);
+ return isFeasible ? state : NULL;
+ }
+
+ const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) {
+ return ConstraintMgr->getSymVal(St, sym);
+ }
+
+ void EndPath(const GRState* St) {
+ ConstraintMgr->EndPath(St);
+ }
+
+ bool scanReachableSymbols(SVal val, const GRState* state,
+ SymbolVisitor& visitor);
+};
+
+//===----------------------------------------------------------------------===//
+// GRStateRef - A "fat" reference to GRState that also bundles GRStateManager.
+//===----------------------------------------------------------------------===//
+
+class GRStateRef {
+ const GRState* St;
+ GRStateManager* Mgr;
+public:
+ GRStateRef(const GRState* st, GRStateManager& mgr) : St(st), Mgr(&mgr) {}
+
+ const GRState* getState() const { return St; }
+ operator const GRState*() const { return St; }
+ GRStateManager& getManager() const { return *Mgr; }
+
+ SVal GetSVal(Expr* Ex) {
+ return Mgr->GetSVal(St, Ex);
+ }
+
+ SVal GetBlkExprSVal(Expr* Ex) {
+ return Mgr->GetBlkExprSVal(St, Ex);
+ }
+
+ SVal GetSValAsScalarOrLoc(const Expr *Ex) {
+ return Mgr->GetSValAsScalarOrLoc(St, Ex);
+ }
+
+ SVal GetSVal(Loc LV, QualType T = QualType()) {
+ return Mgr->GetSVal(St, LV, T);
+ }
+
+ SVal GetSVal(const MemRegion* R) {
+ return Mgr->GetSVal(St, R);
+ }
+
+ SVal GetSValAsScalarOrLoc(const MemRegion *R) {
+ return Mgr->GetSValAsScalarOrLoc(St, R);
+ }
+
+ GRStateRef BindExpr(Stmt* Ex, SVal V, bool isBlkExpr, bool Invalidate) {
+ return GRStateRef(Mgr->BindExpr(St, Ex, V, isBlkExpr, Invalidate), *Mgr);
+ }
+
+ GRStateRef BindExpr(Stmt* Ex, SVal V, bool Invalidate = true) {
+ return GRStateRef(Mgr->BindExpr(St, Ex, V, Invalidate), *Mgr);
+ }
+
+ GRStateRef BindDecl(const VarDecl* VD, SVal InitVal) {
+ return GRStateRef(Mgr->BindDecl(St, VD, InitVal), *Mgr);
+ }
+
+ GRStateRef BindLoc(Loc LV, SVal V) {
+ return GRStateRef(Mgr->BindLoc(St, LV, V), *Mgr);
+ }
+
+ GRStateRef BindLoc(SVal LV, SVal V) {
+ if (!isa<Loc>(LV)) return *this;
+ return BindLoc(cast<Loc>(LV), V);
+ }
+
+ GRStateRef Unbind(Loc LV) {
+ return GRStateRef(Mgr->Unbind(St, LV), *Mgr);
+ }
+
+ // Trait based GDM dispatch.
+ template<typename T>
+ typename GRStateTrait<T>::data_type get() const {
+ return St->get<T>();
+ }
+
+ template<typename T>
+ typename GRStateTrait<T>::lookup_type
+ get(typename GRStateTrait<T>::key_type key) const {
+ return St->get<T>(key);
+ }
+
+ template<typename T>
+ GRStateRef set(typename GRStateTrait<T>::data_type D) {
+ return GRStateRef(Mgr->set<T>(St, D), *Mgr);
+ }
+
+ template <typename T>
+ typename GRStateTrait<T>::context_type get_context() {
+ return Mgr->get_context<T>();
+ }
+
+ template<typename T>
+ GRStateRef set(typename GRStateTrait<T>::key_type K,
+ typename GRStateTrait<T>::value_type E,
+ typename GRStateTrait<T>::context_type C) {
+ return GRStateRef(Mgr->set<T>(St, K, E, C), *Mgr);
+ }
+
+ template<typename T>
+ GRStateRef set(typename GRStateTrait<T>::key_type K,
+ typename GRStateTrait<T>::value_type E) {
+ return GRStateRef(Mgr->set<T>(St, K, E, get_context<T>()), *Mgr);
+ }
+
+ template<typename T>
+ GRStateRef add(typename GRStateTrait<T>::key_type K) {
+ return GRStateRef(Mgr->add<T>(St, K, get_context<T>()), *Mgr);
+ }
+
+ template<typename T>
+ GRStateRef remove(typename GRStateTrait<T>::key_type K,
+ typename GRStateTrait<T>::context_type C) {
+ return GRStateRef(Mgr->remove<T>(St, K, C), *Mgr);
+ }
+
+ template<typename T>
+ GRStateRef remove(typename GRStateTrait<T>::key_type K) {
+ return GRStateRef(Mgr->remove<T>(St, K, get_context<T>()), *Mgr);
+ }
+
+ template<typename T>
+ bool contains(typename GRStateTrait<T>::key_type key) const {
+ return St->contains<T>(key);
+ }
+
+ // Lvalue methods.
+ SVal GetLValue(const VarDecl* VD) {
+ return Mgr->GetLValue(St, VD);
+ }
+
+ GRStateRef Assume(SVal Cond, bool Assumption, bool& isFeasible) {
+ return GRStateRef(Mgr->Assume(St, Cond, Assumption, isFeasible), *Mgr);
+ }
+
+ template <typename CB>
+ CB scanReachableSymbols(SVal val) {
+ CB cb(*this);
+ Mgr->scanReachableSymbols(val, St, cb);
+ return cb;
+ }
+
+ SymbolManager& getSymbolManager() { return Mgr->getSymbolManager(); }
+ BasicValueFactory& getBasicVals() { return Mgr->getBasicVals(); }
+
+ // Pretty-printing.
+ void print(std::ostream& Out, const char* nl = "\n",
+ const char *sep = "") const;
+
+ void printStdErr() const;
+
+ void printDOT(std::ostream& Out) const;
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/GRStateTrait.h b/include/clang/Analysis/PathSensitive/GRStateTrait.h
new file mode 100644
index 000000000000..ce43cda31e9e
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/GRStateTrait.h
@@ -0,0 +1,148 @@
+//==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- 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 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.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H
+#define LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H
+
+namespace llvm {
+ class BumpPtrAllocator;
+ template <typename K, typename D, typename I> class ImmutableMap;
+ template <typename K, typename I> class ImmutableSet;
+ template <typename T> class ImmutableList;
+ template <typename T> class ImmutableListImpl;
+}
+
+namespace clang {
+ template <typename T> struct GRStatePartialTrait;
+
+ // Partial-specialization for ImmutableMap.
+
+ template <typename Key, typename Data, typename Info>
+ struct GRStatePartialTrait< 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) {
+ return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
+ }
+ static inline void* MakeVoidPtr(data_type B) {
+ return B.getRoot();
+ }
+ static lookup_type Lookup(data_type B, key_type K) {
+ return B.lookup(K);
+ }
+ static data_type Set(data_type B, key_type K, value_type E,context_type F){
+ return F.Add(B, K, E);
+ }
+
+ static data_type Remove(data_type B, key_type K, context_type F) {
+ return F.Remove(B, K);
+ }
+
+ static inline context_type MakeContext(void* p) {
+ return *((typename data_type::Factory*) p);
+ }
+
+ static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
+ return new typename data_type::Factory(Alloc);
+ }
+
+ static void DeleteContext(void* Ctx) {
+ delete (typename data_type::Factory*) Ctx;
+ }
+ };
+
+
+ // Partial-specialization for ImmutableSet.
+
+ template <typename Key, typename Info>
+ struct GRStatePartialTrait< 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) {
+ return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
+ }
+
+ static inline void* MakeVoidPtr(data_type B) {
+ return B.getRoot();
+ }
+
+ static data_type Add(data_type B, key_type K, context_type F) {
+ return F.Add(B, K);
+ }
+
+ static data_type Remove(data_type B, key_type K, context_type F) {
+ return F.Remove(B, K);
+ }
+
+ static bool Contains(data_type B, key_type K) {
+ return B.contains(K);
+ }
+
+ static inline context_type MakeContext(void* p) {
+ return *((typename data_type::Factory*) p);
+ }
+
+ static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
+ return new typename data_type::Factory(Alloc);
+ }
+
+ static void DeleteContext(void* Ctx) {
+ delete (typename data_type::Factory*) Ctx;
+ }
+ };
+
+ // Partial-specialization for ImmutableList.
+
+ template <typename T>
+ struct GRStatePartialTrait< llvm::ImmutableList<T> > {
+ typedef llvm::ImmutableList<T> data_type;
+ typedef T key_type;
+ typedef typename data_type::Factory& context_type;
+
+ static data_type Add(data_type L, key_type K, context_type F) {
+ return F.Add(K, L);
+ }
+
+ 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) {
+ return (void*) D.getInternalPointer();
+ }
+
+ static inline context_type MakeContext(void* p) {
+ return *((typename data_type::Factory*) p);
+ }
+
+ static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
+ return new typename data_type::Factory(Alloc);
+ }
+
+ static void DeleteContext(void* Ctx) {
+ delete (typename data_type::Factory*) Ctx;
+ }
+ };
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h
new file mode 100644
index 000000000000..0f353d07004f
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h
@@ -0,0 +1,123 @@
+//== GRTransferFuncs.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 GRTransferFuncs, which provides a base-class that
+// defines an interface for transfer functions used by GRExprEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRTF
+#define LLVM_CLANG_ANALYSIS_GRTF
+
+#include "clang/Analysis/PathSensitive/SVals.h"
+#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include <vector>
+
+namespace clang {
+
+ class GRExprEngine;
+ class BugReporter;
+ class ObjCMessageExpr;
+ class GRStmtNodeBuilderRef;
+
+class GRTransferFuncs {
+ friend class GRExprEngine;
+protected:
+ virtual SVal DetermEvalBinOpNN(GRExprEngine& Eng,
+ BinaryOperator::Opcode Op,
+ NonLoc L, NonLoc R, QualType T) {
+ return UnknownVal();
+ }
+
+public:
+ GRTransferFuncs() {}
+ virtual ~GRTransferFuncs() {}
+
+ virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {}
+ virtual void RegisterChecks(BugReporter& BR) {}
+
+ // Casts.
+
+ virtual SVal EvalCast(GRExprEngine& Engine, NonLoc V, QualType CastT) =0;
+ virtual SVal EvalCast(GRExprEngine& Engine, Loc V, QualType CastT) = 0;
+
+ // Unary Operators.
+
+ virtual SVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLoc X) = 0;
+
+ virtual SVal EvalComplement(GRExprEngine& Engine, NonLoc X) = 0;
+
+ // Binary Operators.
+ // FIXME: We're moving back towards using GREXprEngine directly. No need
+ // for OStates
+ virtual void EvalBinOpNN(GRStateSet& OStates, GRExprEngine& Eng,
+ const GRState* St, Expr* Ex,
+ BinaryOperator::Opcode Op, NonLoc L, NonLoc R,
+ QualType T);
+
+ virtual SVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
+ Loc L, Loc R) = 0;
+
+ // Pointer arithmetic.
+
+ virtual SVal EvalBinOp(GRExprEngine& Engine, const GRState *state,
+ BinaryOperator::Opcode Op, Loc L, NonLoc R) = 0;
+
+ // Calls.
+
+ virtual void EvalCall(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder<GRState>& Builder,
+ CallExpr* CE, SVal L,
+ ExplodedNode<GRState>* Pred) {}
+
+ virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder<GRState>& Builder,
+ ObjCMessageExpr* ME,
+ ExplodedNode<GRState>* Pred) {}
+
+ // Stores.
+
+ virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) {}
+
+ // End-of-path and dead symbol notification.
+
+ virtual void EvalEndPath(GRExprEngine& Engine,
+ GREndPathNodeBuilder<GRState>& Builder) {}
+
+
+ virtual void EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder<GRState>& Builder,
+ ExplodedNode<GRState>* Pred,
+ Stmt* S, const GRState* state,
+ SymbolReaper& SymReaper) {}
+
+ // Return statements.
+ virtual void EvalReturn(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder<GRState>& Builder,
+ ReturnStmt* S,
+ ExplodedNode<GRState>* Pred) {}
+
+ // Assumptions.
+
+ virtual const GRState* EvalAssume(GRStateManager& VMgr,
+ const GRState* St,
+ SVal Cond, bool Assumption,
+ bool& isFeasible) {
+ return St;
+ }
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/GRWorkList.h b/include/clang/Analysis/PathSensitive/GRWorkList.h
new file mode 100644
index 000000000000..c76532294c1f
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/GRWorkList.h
@@ -0,0 +1,76 @@
+//==- GRWorkList.h - Worklist class used by GRCoreEngine -----------*- 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 GRWorkList, a pure virtual class that represents an opaque
+// worklist used by GRCoreEngine to explore the reachability state space.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRWORKLIST
+#define LLVM_CLANG_ANALYSIS_GRWORKLIST
+
+#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
+
+namespace clang {
+
+class ExplodedNodeImpl;
+
+class GRWorkListUnit {
+ ExplodedNodeImpl* Node;
+ GRBlockCounter Counter;
+ CFGBlock* Block;
+ unsigned BlockIdx;
+
+public:
+ GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C,
+ CFGBlock* B, unsigned idx)
+ : Node(N),
+ Counter(C),
+ Block(B),
+ BlockIdx(idx) {}
+
+ explicit GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C)
+ : Node(N),
+ Counter(C),
+ Block(NULL),
+ BlockIdx(0) {}
+
+ ExplodedNodeImpl* getNode() const { return Node; }
+ GRBlockCounter getBlockCounter() const { return Counter; }
+ CFGBlock* getBlock() const { return Block; }
+ unsigned getIndex() const { return BlockIdx; }
+};
+
+class GRWorkList {
+ GRBlockCounter CurrentCounter;
+public:
+ virtual ~GRWorkList();
+ virtual bool hasWork() const = 0;
+
+ virtual void Enqueue(const GRWorkListUnit& U) = 0;
+
+ void Enqueue(ExplodedNodeImpl* N, CFGBlock& B, unsigned idx) {
+ Enqueue(GRWorkListUnit(N, CurrentCounter, &B, idx));
+ }
+
+ void Enqueue(ExplodedNodeImpl* N) {
+ Enqueue(GRWorkListUnit(N, CurrentCounter));
+ }
+
+ virtual GRWorkListUnit Dequeue() = 0;
+
+ void setBlockCounter(GRBlockCounter C) { CurrentCounter = C; }
+ GRBlockCounter getBlockCounter() const { return CurrentCounter; }
+
+ static GRWorkList *MakeDFS();
+ static GRWorkList *MakeBFS();
+ static GRWorkList *MakeBFSBlockDFSContents();
+};
+} // end clang namespace
+#endif
diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h
new file mode 100644
index 000000000000..0e8da2aee318
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/MemRegion.h
@@ -0,0 +1,665 @@
+//== MemRegion.h - Abstract memory regions for static 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 MemRegion and its subclasses. MemRegion defines a
+// partially-typed abstraction of memory useful for path-sensitive dataflow
+// analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_MEMREGION_H
+#define LLVM_CLANG_ANALYSIS_MEMREGION_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Analysis/PathSensitive/SymbolManager.h"
+#include "clang/Analysis/PathSensitive/SVals.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/Support/Allocator.h"
+#include <string>
+
+namespace llvm { class raw_ostream; }
+
+namespace clang {
+
+class MemRegionManager;
+
+
+/// MemRegion - The root abstract class for all memory regions.
+class MemRegion : public llvm::FoldingSetNode {
+public:
+ enum Kind { MemSpaceRegionKind,
+ SymbolicRegionKind,
+ AllocaRegionKind,
+ // Typed regions.
+ BEG_TYPED_REGIONS,
+ CodeTextRegionKind,
+ CompoundLiteralRegionKind,
+ StringRegionKind, ElementRegionKind,
+ TypedViewRegionKind,
+ // Decl Regions.
+ BEG_DECL_REGIONS,
+ VarRegionKind, FieldRegionKind,
+ ObjCIvarRegionKind, ObjCObjectRegionKind,
+ END_DECL_REGIONS,
+ END_TYPED_REGIONS };
+private:
+ const Kind kind;
+
+protected:
+ MemRegion(Kind k) : kind(k) {}
+ virtual ~MemRegion();
+
+public:
+ // virtual MemExtent getExtent(MemRegionManager& mrm) const = 0;
+ virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0;
+
+ std::string getString() const;
+
+ virtual void print(llvm::raw_ostream& os) const;
+
+ Kind getKind() const { return kind; }
+
+ template<typename RegionTy> const RegionTy* getAs() const;
+
+ virtual bool isBoundable(ASTContext&) const { return true; }
+
+ static bool classof(const MemRegion*) { return true; }
+};
+
+/// MemSpaceRegion - A memory region that represents and "memory space";
+/// for example, the set of global variables, the stack frame, etc.
+class MemSpaceRegion : public MemRegion {
+ friend class MemRegionManager;
+ MemSpaceRegion() : MemRegion(MemSpaceRegionKind) {}
+
+public:
+ //RegionExtent getExtent() const { return UndefinedExtent(); }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+ bool isBoundable(ASTContext &) const { return false; }
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == MemSpaceRegionKind;
+ }
+};
+
+/// SubRegion - A region that subsets another larger region. Most regions
+/// are subclasses of SubRegion.
+class SubRegion : public MemRegion {
+protected:
+ const MemRegion* superRegion;
+ SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {}
+
+public:
+ const MemRegion* getSuperRegion() const {
+ return superRegion;
+ }
+
+ bool isSubRegionOf(const MemRegion* R) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() > MemSpaceRegionKind;
+ }
+};
+
+/// AllocaRegion - A region that represents an untyped blob of bytes created
+/// by a call to 'alloca'.
+class AllocaRegion : public SubRegion {
+ friend class MemRegionManager;
+protected:
+ unsigned Cnt; // Block counter. Used to distinguish different pieces of
+ // memory allocated by alloca at the same call site.
+ const Expr* Ex;
+
+ AllocaRegion(const Expr* ex, unsigned cnt, const MemRegion* superRegion)
+ : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {}
+
+public:
+
+ const Expr* getExpr() const { return Ex; }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex,
+ unsigned Cnt);
+
+ void print(llvm::raw_ostream& os) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == AllocaRegionKind;
+ }
+};
+
+/// TypedRegion - An abstract class representing regions that are typed.
+class TypedRegion : public SubRegion {
+protected:
+ TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {}
+
+public:
+ virtual QualType getValueType(ASTContext &C) const = 0;
+
+ virtual QualType getLocationType(ASTContext& C) const {
+ // FIXME: We can possibly optimize this later to cache this value.
+ return C.getPointerType(getValueType(C));
+ }
+
+ QualType getDesugaredValueType(ASTContext& C) const {
+ QualType T = getValueType(C);
+ return T.getTypePtr() ? T->getDesugaredType() : T;
+ }
+
+ QualType getDesugaredLocationType(ASTContext& C) const {
+ return getLocationType(C)->getDesugaredType();
+ }
+
+ bool isBoundable(ASTContext &C) const {
+ return !getValueType(C).isNull();
+ }
+
+ static bool classof(const MemRegion* R) {
+ unsigned k = R->getKind();
+ return k > BEG_TYPED_REGIONS && k < END_TYPED_REGIONS;
+ }
+};
+
+/// CodeTextRegion - A region that represents code texts of a function. It wraps
+/// two kinds of code texts: real function and symbolic function. Real function
+/// is a function declared in the program. Symbolic function is a function
+/// pointer that we don't know which function it points to.
+class CodeTextRegion : public TypedRegion {
+public:
+ enum CodeKind { Declared, Symbolic };
+
+private:
+ // The function pointer kind that this CodeTextRegion represents.
+ CodeKind codekind;
+
+ // Data may be a SymbolRef or FunctionDecl*.
+ const void* Data;
+
+ // Cached function pointer type.
+ QualType LocationType;
+
+public:
+
+ CodeTextRegion(const FunctionDecl* fd, QualType t, const MemRegion* sreg)
+ : TypedRegion(sreg, CodeTextRegionKind),
+ codekind(Declared),
+ Data(fd),
+ LocationType(t) {}
+
+ CodeTextRegion(SymbolRef sym, QualType t, const MemRegion* sreg)
+ : TypedRegion(sreg, CodeTextRegionKind),
+ codekind(Symbolic),
+ Data(sym),
+ LocationType(t) {}
+
+ QualType getValueType(ASTContext &C) const {
+ // Do not get the object type of a CodeTextRegion.
+ assert(0);
+ return QualType();
+ }
+
+ QualType getLocationType(ASTContext &C) const {
+ return LocationType;
+ }
+
+ bool isDeclared() const { return codekind == Declared; }
+ bool isSymbolic() const { return codekind == Symbolic; }
+
+ const FunctionDecl* getDecl() const {
+ assert(codekind == Declared);
+ return static_cast<const FunctionDecl*>(Data);
+ }
+
+ SymbolRef getSymbol() const {
+ assert(codekind == Symbolic);
+ return const_cast<SymbolRef>(static_cast<const SymbolRef>(Data));
+ }
+
+ bool isBoundable(ASTContext&) const { return false; }
+
+ virtual void print(llvm::raw_ostream& os) const;
+
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const void* data, QualType t);
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == CodeTextRegionKind;
+ }
+};
+
+/// SymbolicRegion - A special, "non-concrete" region. Unlike other region
+/// clases, SymbolicRegion represents a region that serves as an alias for
+/// either a real region, a NULL pointer, etc. It essentially is used to
+/// map the concept of symbolic values into the domain of regions. Symbolic
+/// regions do not need to be typed.
+class SymbolicRegion : public SubRegion {
+protected:
+ const SymbolRef sym;
+
+public:
+ SymbolicRegion(const SymbolRef s, const MemRegion* sreg)
+ : SubRegion(sreg, SymbolicRegionKind), sym(s) {}
+
+ SymbolRef getSymbol() const {
+ return sym;
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym);
+
+ void print(llvm::raw_ostream& os) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == SymbolicRegionKind;
+ }
+};
+
+/// StringRegion - Region associated with a StringLiteral.
+class StringRegion : public TypedRegion {
+ friend class MemRegionManager;
+ const StringLiteral* Str;
+protected:
+
+ StringRegion(const StringLiteral* str, MemRegion* sreg)
+ : TypedRegion(sreg, StringRegionKind), Str(str) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const StringLiteral* Str,
+ const MemRegion* superRegion);
+
+public:
+
+ const StringLiteral* getStringLiteral() const { return Str; }
+
+ QualType getValueType(ASTContext& C) const {
+ return Str->getType();
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ProfileRegion(ID, Str, superRegion);
+ }
+
+ void print(llvm::raw_ostream& os) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == StringRegionKind;
+ }
+};
+
+class TypedViewRegion : public TypedRegion {
+ friend class MemRegionManager;
+ QualType LValueType;
+
+ TypedViewRegion(QualType lvalueType, const MemRegion* sreg)
+ : TypedRegion(sreg, TypedViewRegionKind), LValueType(lvalueType) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType T,
+ const MemRegion* superRegion);
+
+public:
+
+ void print(llvm::raw_ostream& os) const;
+
+ QualType getLocationType(ASTContext&) const {
+ return LValueType;
+ }
+
+ QualType getValueType(ASTContext&) const {
+ const PointerType* PTy = LValueType->getAsPointerType();
+ assert(PTy);
+ return PTy->getPointeeType();
+ }
+
+ bool isBoundable(ASTContext &C) const {
+ return isa<PointerType>(LValueType);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ProfileRegion(ID, LValueType, superRegion);
+ }
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == TypedViewRegionKind;
+ }
+
+ const MemRegion *removeViews() const;
+};
+
+
+/// 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 {
+private:
+ friend class MemRegionManager;
+ const CompoundLiteralExpr* CL;
+
+ CompoundLiteralRegion(const CompoundLiteralExpr* cl, const MemRegion* sReg)
+ : TypedRegion(sReg, CompoundLiteralRegionKind), CL(cl) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const CompoundLiteralExpr* CL,
+ const MemRegion* superRegion);
+public:
+ QualType getValueType(ASTContext& C) const {
+ return C.getCanonicalType(CL->getType());
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+ void print(llvm::raw_ostream& os) const;
+
+ const CompoundLiteralExpr* getLiteralExpr() const { return CL; }
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == CompoundLiteralRegionKind;
+ }
+};
+
+class DeclRegion : public TypedRegion {
+protected:
+ const Decl* D;
+
+ DeclRegion(const Decl* d, const MemRegion* sReg, Kind k)
+ : TypedRegion(sReg, k), D(d) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
+ const MemRegion* superRegion, Kind k);
+
+public:
+ const Decl* getDecl() const { return D; }
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+ static bool classof(const MemRegion* R) {
+ unsigned k = R->getKind();
+ return k > BEG_DECL_REGIONS && k < END_DECL_REGIONS;
+ }
+};
+
+class VarRegion : public DeclRegion {
+ friend class MemRegionManager;
+
+ VarRegion(const VarDecl* vd, const MemRegion* sReg)
+ : DeclRegion(vd, sReg, VarRegionKind) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, VarDecl* VD,
+ const MemRegion* superRegion) {
+ DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
+ }
+
+public:
+ const VarDecl* getDecl() const { return cast<VarDecl>(D); }
+
+ QualType getValueType(ASTContext& C) const {
+ // FIXME: We can cache this if needed.
+ return C.getCanonicalType(getDecl()->getType());
+ }
+
+ void print(llvm::raw_ostream& os) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == VarRegionKind;
+ }
+};
+
+class FieldRegion : public DeclRegion {
+ friend class MemRegionManager;
+
+ FieldRegion(const FieldDecl* fd, const MemRegion* sReg)
+ : DeclRegion(fd, sReg, FieldRegionKind) {}
+
+public:
+
+ void print(llvm::raw_ostream& os) const;
+
+ const FieldDecl* getDecl() const { return cast<FieldDecl>(D); }
+
+ QualType getValueType(ASTContext& C) const {
+ // FIXME: We can cache this if needed.
+ return C.getCanonicalType(getDecl()->getType());
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, FieldDecl* FD,
+ const MemRegion* superRegion) {
+ DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
+ }
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == FieldRegionKind;
+ }
+};
+
+class ObjCObjectRegion : public DeclRegion {
+
+ friend class MemRegionManager;
+
+ ObjCObjectRegion(const ObjCInterfaceDecl* ivd, const MemRegion* sReg)
+ : DeclRegion(ivd, sReg, ObjCObjectRegionKind) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, ObjCInterfaceDecl* ivd,
+ const MemRegion* superRegion) {
+ DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCObjectRegionKind);
+ }
+
+public:
+ const ObjCInterfaceDecl* getInterface() const {
+ return cast<ObjCInterfaceDecl>(D);
+ }
+
+ QualType getValueType(ASTContext& C) const {
+ return C.getObjCInterfaceType(getInterface());
+ }
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == ObjCObjectRegionKind;
+ }
+};
+
+class ObjCIvarRegion : public DeclRegion {
+
+ friend class MemRegionManager;
+
+ ObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* sReg)
+ : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, ObjCIvarDecl* ivd,
+ const MemRegion* superRegion) {
+ DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind);
+ }
+
+public:
+ const ObjCIvarDecl* getDecl() const { return cast<ObjCIvarDecl>(D); }
+ QualType getValueType(ASTContext&) const { return getDecl()->getType(); }
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == ObjCIvarRegionKind;
+ }
+};
+
+class ElementRegion : public TypedRegion {
+ friend class MemRegionManager;
+
+ QualType ElementType;
+ SVal Index;
+
+ ElementRegion(QualType elementType, SVal Idx, const MemRegion* sReg)
+ : TypedRegion(sReg, ElementRegionKind),
+ ElementType(elementType), Index(Idx) {
+ assert((!isa<nonloc::ConcreteInt>(&Idx) ||
+ cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) &&
+ "The index must be signed");
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType,
+ SVal Idx, const MemRegion* superRegion);
+
+public:
+
+ SVal getIndex() const { return Index; }
+
+ QualType getValueType(ASTContext&) const {
+ return ElementType;
+ }
+
+ QualType getElementType() const {
+ return ElementType;
+ }
+
+ void print(llvm::raw_ostream& os) const;
+
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == ElementRegionKind;
+ }
+};
+
+template<typename RegionTy>
+const RegionTy* MemRegion::getAs() const {
+ const MemRegion *R = this;
+
+ do {
+ if (const RegionTy* RT = dyn_cast<RegionTy>(R))
+ return RT;
+
+ if (const TypedViewRegion *TR = dyn_cast<TypedViewRegion>(R)) {
+ R = TR->getSuperRegion();
+ continue;
+ }
+
+ break;
+ }
+ while (R);
+
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// MemRegionManager - Factory object for creating regions.
+//===----------------------------------------------------------------------===//
+
+class MemRegionManager {
+ llvm::BumpPtrAllocator& A;
+ llvm::FoldingSet<MemRegion> Regions;
+
+ MemSpaceRegion* globals;
+ MemSpaceRegion* stack;
+ MemSpaceRegion* heap;
+ MemSpaceRegion* unknown;
+ MemSpaceRegion* code;
+
+public:
+ MemRegionManager(llvm::BumpPtrAllocator& a)
+ : A(a), globals(0), stack(0), heap(0), unknown(0), code(0) {}
+
+ ~MemRegionManager() {}
+
+ /// getStackRegion - Retrieve the memory region associated with the
+ /// current stack frame.
+ MemSpaceRegion* getStackRegion();
+
+ /// getGlobalsRegion - Retrieve the memory region associated with
+ /// all global variables.
+ MemSpaceRegion* getGlobalsRegion();
+
+ /// getHeapRegion - Retrieve the memory region associated with the
+ /// generic "heap".
+ MemSpaceRegion* getHeapRegion();
+
+ /// getUnknownRegion - Retrieve the memory region associated with unknown
+ /// memory space.
+ MemSpaceRegion* getUnknownRegion();
+
+ MemSpaceRegion* getCodeRegion();
+
+ bool isGlobalsRegion(const MemRegion* R) {
+ assert(R);
+ return R == globals;
+ }
+
+ /// onStack - check if the region is allocated on the stack.
+ bool onStack(const MemRegion* R);
+
+ /// onHeap - check if the region is allocated on the heap, usually by malloc.
+ bool onHeap(const MemRegion* R);
+
+ /// getAllocaRegion - Retrieve a region associated with a call to alloca().
+ AllocaRegion* getAllocaRegion(const Expr* Ex, unsigned Cnt);
+
+ /// getCompoundLiteralRegion - Retrieve the region associated with a
+ /// given CompoundLiteral.
+ CompoundLiteralRegion*
+ getCompoundLiteralRegion(const CompoundLiteralExpr* CL);
+
+ /// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
+ SymbolicRegion* getSymbolicRegion(SymbolRef sym);
+
+ StringRegion* getStringRegion(const StringLiteral* Str);
+
+ /// getVarRegion - Retrieve or create the memory region associated with
+ /// a specified VarDecl.
+ VarRegion* getVarRegion(const VarDecl* vd);
+
+ /// getElementRegion - Retrieve the memory region associated with the
+ /// associated element type, index, and super region.
+ ElementRegion* getElementRegion(QualType elementType, SVal Idx,
+ const MemRegion* superRegion);
+
+ /// getFieldRegion - Retrieve or create the memory region associated with
+ /// a specified FieldDecl. 'superRegion' corresponds to the containing
+ /// memory region (which typically represents the memory representing
+ /// a structure or class).
+ FieldRegion* getFieldRegion(const FieldDecl* fd,
+ const MemRegion* superRegion);
+
+ /// getObjCObjectRegion - Retrieve or create the memory region associated with
+ /// the instance of a specified Objective-C class.
+ ObjCObjectRegion* getObjCObjectRegion(const ObjCInterfaceDecl* ID,
+ const MemRegion* superRegion);
+
+ /// getObjCIvarRegion - Retrieve or create the memory region associated with
+ /// a specified Objective-c instance variable. 'superRegion' corresponds
+ /// to the containing region (which typically represents the Objective-C
+ /// object).
+ ObjCIvarRegion* getObjCIvarRegion(const ObjCIvarDecl* ivd,
+ const MemRegion* superRegion);
+
+ TypedViewRegion* getTypedViewRegion(QualType LValueType,
+ const MemRegion* superRegion);
+
+ CodeTextRegion* getCodeTextRegion(SymbolRef sym, QualType t);
+ CodeTextRegion* getCodeTextRegion(const FunctionDecl* fd, QualType t);
+
+ bool hasStackStorage(const MemRegion* R);
+
+private:
+ MemSpaceRegion* LazyAllocate(MemSpaceRegion*& region);
+};
+} // end clang namespace
+
+namespace llvm {
+static inline raw_ostream& operator<<(raw_ostream& O,
+ const clang::MemRegion* R) {
+ R->print(O);
+ return O;
+}
+} // end llvm namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/SVals.h b/include/clang/Analysis/PathSensitive/SVals.h
new file mode 100644
index 000000000000..ee6d4dcf1f37
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/SVals.h
@@ -0,0 +1,447 @@
+//== SVals.h - Abstract Values for Static 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 SVal, Loc, and NonLoc, classes that represent
+// abstract r-values for use with path-sensitive value tracking.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_RVALUE_H
+#define LLVM_CLANG_ANALYSIS_RVALUE_H
+
+#include "clang/Analysis/PathSensitive/SymbolManager.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/ADT/ImmutableList.h"
+
+//==------------------------------------------------------------------------==//
+// Base SVal types.
+//==------------------------------------------------------------------------==//
+
+namespace clang {
+
+class CompoundValData;
+class BasicValueFactory;
+class MemRegion;
+class MemRegionManager;
+class GRStateManager;
+
+class SVal {
+public:
+ enum BaseKind { UndefinedKind, UnknownKind, LocKind, NonLocKind };
+ enum { BaseBits = 2, BaseMask = 0x3 };
+
+protected:
+ void* Data;
+ unsigned Kind;
+
+protected:
+ SVal(const void* d, bool isLoc, unsigned ValKind)
+ : Data(const_cast<void*>(d)),
+ Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {}
+
+ explicit SVal(BaseKind k, void* D = NULL)
+ : Data(D), Kind(k) {}
+
+public:
+ SVal() : Data(0), Kind(0) {}
+ ~SVal() {};
+
+ /// BufferTy - A temporary buffer to hold a set of SVals.
+ typedef llvm::SmallVector<SVal,5> BufferTy;
+
+ inline unsigned getRawKind() const { return Kind; }
+ inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
+ inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; }
+
+ inline void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddInteger((unsigned) getRawKind());
+ ID.AddPointer(reinterpret_cast<void*>(Data));
+ }
+
+ inline bool operator==(const SVal& R) const {
+ return getRawKind() == R.getRawKind() && Data == R.Data;
+ }
+
+ inline bool operator!=(const SVal& R) const {
+ return !(*this == R);
+ }
+
+ inline bool isUnknown() const {
+ return getRawKind() == UnknownKind;
+ }
+
+ inline bool isUndef() const {
+ return getRawKind() == UndefinedKind;
+ }
+
+ inline bool isUnknownOrUndef() const {
+ return getRawKind() <= UnknownKind;
+ }
+
+ inline bool isValid() const {
+ return getRawKind() > UnknownKind;
+ }
+
+ bool isZeroConstant() const;
+
+ /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true;
+ bool hasConjuredSymbol() const;
+
+ /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a
+ /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl.
+ /// Otherwise return 0.
+ const FunctionDecl* getAsFunctionDecl() const;
+
+ /// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
+ /// wraps a symbol, return that SymbolRef. Otherwise return a SymbolData*
+ SymbolRef getAsLocSymbol() const;
+
+ /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
+ /// Otherwise return a SymbolRef where 'isValid()' returns false.
+ SymbolRef getAsSymbol() const;
+
+ /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
+ /// return that expression. Otherwise return NULL.
+ const SymExpr *getAsSymbolicExpression() const;
+
+ void print(std::ostream& OS) const;
+ void print(llvm::raw_ostream& OS) const;
+ void printStdErr() const;
+
+ // Iterators.
+ class symbol_iterator {
+ llvm::SmallVector<const SymExpr*, 5> itr;
+ void expand();
+ public:
+ symbol_iterator() {}
+ symbol_iterator(const SymExpr* SE);
+
+ symbol_iterator& operator++();
+ SymbolRef operator*();
+
+ bool operator==(const symbol_iterator& X) const;
+ bool operator!=(const symbol_iterator& X) const;
+ };
+
+ symbol_iterator symbol_begin() const {
+ const SymExpr *SE = getAsSymbolicExpression();
+ if (SE)
+ return symbol_iterator(SE);
+ else
+ return symbol_iterator();
+ }
+
+ symbol_iterator symbol_end() const { return symbol_iterator(); }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SVal*) { return true; }
+};
+
+class UnknownVal : public SVal {
+public:
+ UnknownVal() : SVal(UnknownKind) {}
+
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == UnknownKind;
+ }
+};
+
+class UndefinedVal : public SVal {
+public:
+ UndefinedVal() : SVal(UndefinedKind) {}
+ UndefinedVal(void* D) : SVal(UndefinedKind, D) {}
+
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == UndefinedKind;
+ }
+
+ void* getData() const { return Data; }
+};
+
+class NonLoc : public SVal {
+protected:
+ NonLoc(unsigned SubKind, const void* d) : SVal(d, false, SubKind) {}
+
+public:
+ void print(llvm::raw_ostream& Out) const;
+
+ // Utility methods to create NonLocs.
+
+ static NonLoc MakeIntVal(BasicValueFactory& BasicVals, uint64_t X,
+ bool isUnsigned);
+
+ static NonLoc MakeVal(BasicValueFactory& BasicVals, uint64_t X,
+ unsigned BitWidth, bool isUnsigned);
+
+ static NonLoc MakeVal(BasicValueFactory& BasicVals, uint64_t X, QualType T);
+
+ static NonLoc MakeVal(BasicValueFactory& BasicVals, IntegerLiteral* I);
+
+ static NonLoc MakeVal(BasicValueFactory& BasicVals, const llvm::APInt& I,
+ bool isUnsigned);
+
+ static NonLoc MakeVal(BasicValueFactory& BasicVals, const llvm::APSInt& I);
+
+ static NonLoc MakeIntTruthVal(BasicValueFactory& BasicVals, bool b);
+
+ static NonLoc MakeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals,
+ BasicValueFactory& BasicVals);
+
+ // Implement isa<T> support.
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == NonLocKind;
+ }
+};
+
+class Loc : public SVal {
+protected:
+ Loc(unsigned SubKind, const void* D)
+ : SVal(const_cast<void*>(D), true, SubKind) {}
+
+public:
+ void print(llvm::raw_ostream& Out) const;
+
+ Loc(const Loc& X) : SVal(X.Data, true, X.getSubKind()) {}
+ Loc& operator=(const Loc& X) { memcpy(this, &X, sizeof(Loc)); return *this; }
+
+ static Loc MakeVal(const MemRegion* R);
+
+ static Loc MakeVal(AddrLabelExpr* E);
+
+ static Loc MakeNull(BasicValueFactory &BasicVals);
+
+ // Implement isa<T> support.
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == LocKind;
+ }
+
+ static inline bool IsLocType(QualType T) {
+ return T->isPointerType() || T->isObjCQualifiedIdType()
+ || T->isBlockPointerType();
+ }
+};
+
+//==------------------------------------------------------------------------==//
+// Subclasses of NonLoc.
+//==------------------------------------------------------------------------==//
+
+namespace nonloc {
+
+enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind,
+ LocAsIntegerKind, CompoundValKind };
+
+class SymbolVal : public NonLoc {
+public:
+ SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {}
+
+ SymbolRef getSymbol() const {
+ return (const SymbolData*) Data;
+ }
+
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == NonLocKind &&
+ V->getSubKind() == SymbolValKind;
+ }
+
+ static inline bool classof(const NonLoc* V) {
+ return V->getSubKind() == SymbolValKind;
+ }
+};
+
+class SymExprVal : public NonLoc {
+public:
+ SymExprVal(const SymExpr *SE)
+ : NonLoc(SymExprValKind, reinterpret_cast<const void*>(SE)) {}
+
+ const SymExpr *getSymbolicExpression() const {
+ return reinterpret_cast<SymExpr*>(Data);
+ }
+
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == NonLocKind &&
+ V->getSubKind() == SymExprValKind;
+ }
+
+ static inline bool classof(const NonLoc* V) {
+ return V->getSubKind() == SymExprValKind;
+ }
+};
+
+class ConcreteInt : public NonLoc {
+public:
+ ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {}
+
+ const llvm::APSInt& getValue() const {
+ return *static_cast<llvm::APSInt*>(Data);
+ }
+
+ // Transfer functions for binary/unary operations on ConcreteInts.
+ SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
+ const ConcreteInt& R) const;
+
+ ConcreteInt EvalComplement(BasicValueFactory& BasicVals) const;
+
+ ConcreteInt EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U) const;
+
+ // Implement isa<T> support.
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == NonLocKind &&
+ V->getSubKind() == ConcreteIntKind;
+ }
+
+ static inline bool classof(const NonLoc* V) {
+ return V->getSubKind() == ConcreteIntKind;
+ }
+};
+
+class LocAsInteger : public NonLoc {
+ LocAsInteger(const std::pair<SVal, uintptr_t>& data) :
+ NonLoc(LocAsIntegerKind, &data) {
+ assert (isa<Loc>(data.first));
+ }
+
+public:
+
+ Loc getLoc() const {
+ return cast<Loc>(((std::pair<SVal, uintptr_t>*) Data)->first);
+ }
+
+ const Loc& getPersistentLoc() const {
+ const SVal& V = ((std::pair<SVal, uintptr_t>*) Data)->first;
+ return cast<Loc>(V);
+ }
+
+ unsigned getNumBits() const {
+ return ((std::pair<SVal, unsigned>*) Data)->second;
+ }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == NonLocKind &&
+ V->getSubKind() == LocAsIntegerKind;
+ }
+
+ static inline bool classof(const NonLoc* V) {
+ return V->getSubKind() == LocAsIntegerKind;
+ }
+
+ static LocAsInteger Make(BasicValueFactory& Vals, Loc V, unsigned Bits);
+};
+
+class CompoundVal : public NonLoc {
+ friend class NonLoc;
+
+ CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {}
+
+public:
+ const CompoundValData* getValue() const {
+ return static_cast<CompoundValData*>(Data);
+ }
+
+ typedef llvm::ImmutableList<SVal>::iterator iterator;
+ iterator begin() const;
+ iterator end() const;
+
+ static bool classof(const SVal* V) {
+ return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind;
+ }
+
+ static bool classof(const NonLoc* V) {
+ return V->getSubKind() == CompoundValKind;
+ }
+};
+
+} // end namespace clang::nonloc
+
+//==------------------------------------------------------------------------==//
+// Subclasses of Loc.
+//==------------------------------------------------------------------------==//
+
+namespace loc {
+
+enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind };
+
+class GotoLabel : public Loc {
+public:
+ GotoLabel(LabelStmt* Label) : Loc(GotoLabelKind, Label) {}
+
+ LabelStmt* getLabel() const {
+ return static_cast<LabelStmt*>(Data);
+ }
+
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == LocKind &&
+ V->getSubKind() == GotoLabelKind;
+ }
+
+ static inline bool classof(const Loc* V) {
+ return V->getSubKind() == GotoLabelKind;
+ }
+};
+
+
+class MemRegionVal : public Loc {
+public:
+ MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {}
+
+ const MemRegion* getRegion() const {
+ return static_cast<MemRegion*>(Data);
+ }
+
+ template <typename REGION>
+ const REGION* getRegionAs() const {
+ return llvm::dyn_cast<REGION>(getRegion());
+ }
+
+ inline bool operator==(const MemRegionVal& R) const {
+ return getRegion() == R.getRegion();
+ }
+
+ inline bool operator!=(const MemRegionVal& R) const {
+ return getRegion() != R.getRegion();
+ }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == LocKind &&
+ V->getSubKind() == MemRegionKind;
+ }
+
+ static inline bool classof(const Loc* V) {
+ return V->getSubKind() == MemRegionKind;
+ }
+};
+
+class ConcreteInt : public Loc {
+public:
+ ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {}
+
+ const llvm::APSInt& getValue() const {
+ return *static_cast<llvm::APSInt*>(Data);
+ }
+
+ // Transfer functions for binary/unary operations on ConcreteInts.
+ SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
+ const ConcreteInt& R) const;
+
+ // Implement isa<T> support.
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == LocKind &&
+ V->getSubKind() == ConcreteIntKind;
+ }
+
+ static inline bool classof(const Loc* V) {
+ return V->getSubKind() == ConcreteIntKind;
+ }
+};
+
+} // end clang::loc namespace
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h
new file mode 100644
index 000000000000..1f081f4eb0d0
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/Store.h
@@ -0,0 +1,204 @@
+//== Store.h - Interface for maps 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 types Store and StoreManager.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_STORE_H
+#define LLVM_CLANG_ANALYSIS_STORE_H
+
+#include "clang/Analysis/PathSensitive/SVals.h"
+#include "clang/Analysis/PathSensitive/MemRegion.h"
+#include "clang/Analysis/PathSensitive/ValueManager.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include <iosfwd>
+
+namespace clang {
+
+typedef const void* Store;
+
+class GRState;
+class GRStateManager;
+class Stmt;
+class Expr;
+class ObjCIvarDecl;
+class SubRegionMap;
+
+class StoreManager {
+protected:
+ ValueManager &ValMgr;
+ GRStateManager &StateMgr;
+
+ /// MRMgr - Manages region objects associated with this StoreManager.
+ MemRegionManager &MRMgr;
+
+ StoreManager(GRStateManager &stateMgr);
+
+protected:
+ virtual const GRState* AddRegionView(const GRState* St,
+ const MemRegion* View,
+ const MemRegion* Base) {
+ return St;
+ }
+
+public:
+ virtual ~StoreManager() {}
+
+ /// Return the value bound to specified location in a given state.
+ /// \param[in] state The analysis state.
+ /// \param[in] loc The symbolic memory location.
+ /// \param[in] T An optional type that provides a hint indicating the
+ /// expected type of the returned value. This is used if the value is
+ /// lazily computed.
+ /// \return The value bound to the location \c loc.
+ virtual SVal Retrieve(const GRState* state, Loc loc,
+ QualType T = QualType()) = 0;
+
+ /// Return a state with the specified value bound to the given location.
+ /// \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
+ /// \c state with the addition of having the value specified by \c val bound
+ /// to the location given for \c loc.
+ virtual const GRState* Bind(const GRState* state, Loc loc, SVal val) = 0;
+
+ virtual Store Remove(Store St, Loc L) = 0;
+
+ /// BindCompoundLiteral - Return the store that has the bindings currently
+ /// in 'store' plus the bindings for the CompoundLiteral. 'R' is the region
+ /// for the compound literal and 'BegInit' and 'EndInit' represent an
+ /// array of initializer values.
+ virtual const GRState* BindCompoundLiteral(const GRState* St,
+ const CompoundLiteralExpr* CL,
+ SVal V) = 0;
+
+ /// getInitialStore - Returns the initial "empty" store representing the
+ /// value bindings upon entry to an analyzed function.
+ virtual Store getInitialStore() = 0;
+
+ /// getRegionManager - Returns the internal RegionManager object that is
+ /// used to query and manipulate MemRegion objects.
+ MemRegionManager& getRegionManager() { return MRMgr; }
+
+ /// getSubRegionMap - Returns an opaque map object that clients can query
+ /// to get the subregions of a given MemRegion object. It is the
+ // caller's responsibility to 'delete' the returned map.
+ virtual SubRegionMap* getSubRegionMap(const GRState *state) = 0;
+
+ virtual SVal getLValueVar(const GRState* St, const VarDecl* VD) = 0;
+
+ virtual SVal getLValueString(const GRState* St, const StringLiteral* S) = 0;
+
+ virtual SVal getLValueCompoundLiteral(const GRState* St,
+ const CompoundLiteralExpr* CL) = 0;
+
+ virtual SVal getLValueIvar(const GRState* St, const ObjCIvarDecl* D,
+ SVal Base) = 0;
+
+ virtual SVal getLValueField(const GRState* St, SVal Base,
+ const FieldDecl* D) = 0;
+
+ virtual SVal getLValueElement(const GRState* St, QualType elementType,
+ SVal Base, SVal Offset) = 0;
+
+ virtual SVal getSizeInElements(const GRState* St, const MemRegion* R) {
+ return UnknownVal();
+ }
+
+ /// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit
+ /// conversions between arrays and pointers.
+ virtual SVal ArrayToPointer(Loc Array) = 0;
+
+
+ class CastResult {
+ const GRState* State;
+ const MemRegion* R;
+ public:
+ const GRState* getState() const { return State; }
+ const MemRegion* getRegion() const { return R; }
+ CastResult(const GRState* s, const MemRegion* r = 0) : State(s), R(r) {}
+ };
+
+ /// CastRegion - Used by GRExprEngine::VisitCast to handle casts from
+ /// a MemRegion* to a specific location type. 'R' is the region being
+ /// casted and 'CastToTy' the result type of the cast.
+ virtual CastResult CastRegion(const GRState* state, const MemRegion* R,
+ QualType CastToTy);
+
+ /// EvalBinOp - Perform pointer arithmetic.
+ virtual SVal EvalBinOp(const GRState *state,
+ BinaryOperator::Opcode Op, Loc L, NonLoc R) {
+ return UnknownVal();
+ }
+
+ /// getSelfRegion - Returns the region for the 'self' (Objective-C) or
+ /// 'this' object (C++). When used when analyzing a normal function this
+ /// method returns NULL.
+ virtual const MemRegion* getSelfRegion(Store store) = 0;
+
+ virtual Store
+ RemoveDeadBindings(const GRState* state, Stmt* Loc, SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0;
+
+ virtual const GRState* BindDecl(const GRState* St, const VarDecl* VD,
+ SVal InitVal) = 0;
+
+ virtual const GRState* BindDeclWithNoInit(const GRState* St,
+ const VarDecl* VD) = 0;
+
+ virtual const GRState* setExtent(const GRState* St,
+ const MemRegion* R, SVal Extent) {
+ return St;
+ }
+
+ virtual const GRState* setDefaultValue(const GRState* St,
+ const MemRegion* R, SVal V) {
+ return St;
+ }
+
+ virtual void print(Store store, std::ostream& Out,
+ const char* nl, const char *sep) = 0;
+
+ class BindingsHandler {
+ public:
+ virtual ~BindingsHandler();
+ virtual bool HandleBinding(StoreManager& SMgr, Store store,
+ const MemRegion* R, SVal val) = 0;
+ };
+
+ /// iterBindings - Iterate over the bindings in the Store.
+ virtual void iterBindings(Store store, BindingsHandler& f) = 0;
+};
+
+/// SubRegionMap - An abstract interface that represents a queryable map
+/// between MemRegion objects and their subregions.
+class SubRegionMap {
+public:
+ virtual ~SubRegionMap() {}
+
+ class Visitor {
+ public:
+ virtual ~Visitor() {};
+ virtual bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) = 0;
+ };
+
+ virtual bool iterSubRegions(const MemRegion* R, Visitor& V) const = 0;
+};
+
+StoreManager* CreateBasicStoreManager(GRStateManager& StMgr);
+StoreManager* CreateRegionStoreManager(GRStateManager& StMgr);
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/SymbolManager.h b/include/clang/Analysis/PathSensitive/SymbolManager.h
new file mode 100644
index 000000000000..d424526d4eb0
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/SymbolManager.h
@@ -0,0 +1,329 @@
+//== SymbolManager.h - Management of Symbolic Values ------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SymbolManager, a class that manages symbolic values
+// created for use by GRExprEngine and related classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_SYMMGR_H
+#define LLVM_CLANG_ANALYSIS_SYMMGR_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/ImmutableSet.h"
+
+namespace llvm {
+ class raw_ostream;
+}
+
+namespace clang {
+ class MemRegion;
+ class ASTContext;
+ class BasicValueFactory;
+}
+
+namespace clang {
+
+class SymExpr : public llvm::FoldingSetNode {
+public:
+ enum Kind { BEGIN_SYMBOLS, RegionValueKind, ConjuredKind, END_SYMBOLS,
+ SymIntKind, SymSymKind };
+private:
+ Kind K;
+
+protected:
+ SymExpr(Kind k) : K(k) {}
+
+public:
+ virtual ~SymExpr() {}
+
+ Kind getKind() const { return K; }
+
+ virtual QualType getType(ASTContext&) const = 0;
+ virtual void Profile(llvm::FoldingSetNodeID& profile) = 0;
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr*) { return true; }
+};
+
+typedef unsigned SymbolID;
+
+class SymbolData : public SymExpr {
+private:
+ const SymbolID Sym;
+
+protected:
+ SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {}
+
+public:
+ virtual ~SymbolData() {}
+
+ SymbolID getSymbolID() const { return Sym; }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr* SE) {
+ Kind k = SE->getKind();
+ return k > BEGIN_SYMBOLS && k < END_SYMBOLS;
+ }
+};
+
+typedef const SymbolData* SymbolRef;
+
+class SymbolRegionValue : public SymbolData {
+ const MemRegion *R;
+public:
+ SymbolRegionValue(SymbolID sym, const MemRegion *r)
+ : SymbolData(RegionValueKind, sym), R(r) {}
+
+ const MemRegion* getRegion() const { return R; }
+
+ static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion* R) {
+ profile.AddInteger((unsigned) RegionValueKind);
+ profile.AddPointer(R);
+ }
+
+ virtual void Profile(llvm::FoldingSetNodeID& profile) {
+ Profile(profile, R);
+ }
+
+ QualType getType(ASTContext&) const;
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr* SE) {
+ return SE->getKind() == RegionValueKind;
+ }
+};
+
+class SymbolConjured : public SymbolData {
+ const Stmt* S;
+ QualType T;
+ unsigned Count;
+ const void* SymbolTag;
+
+public:
+ 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; }
+ unsigned getCount() const { return Count; }
+ const void* getTag() const { return SymbolTag; }
+
+ QualType getType(ASTContext&) const;
+
+ 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);
+ profile.AddInteger(Count);
+ profile.AddPointer(SymbolTag);
+ }
+
+ virtual void Profile(llvm::FoldingSetNodeID& profile) {
+ Profile(profile, S, T, Count, SymbolTag);
+ }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr* SE) {
+ return SE->getKind() == ConjuredKind;
+ }
+};
+
+// SymIntExpr - Represents symbolic expression like 'x' + 3.
+class SymIntExpr : public SymExpr {
+ const SymExpr *LHS;
+ BinaryOperator::Opcode Op;
+ const llvm::APSInt& RHS;
+ QualType T;
+
+public:
+ SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const llvm::APSInt& rhs, QualType t)
+ : SymExpr(SymIntKind), LHS(lhs), Op(op), RHS(rhs), T(t) {}
+
+ // FIXME: We probably need to make this out-of-line to avoid redundant
+ // generation of virtual functions.
+ QualType getType(ASTContext& C) const { return T; }
+
+ BinaryOperator::Opcode getOpcode() const { return Op; }
+
+ const SymExpr *getLHS() const { return LHS; }
+ const llvm::APSInt &getRHS() const { return RHS; }
+
+ static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
+ BinaryOperator::Opcode op, const llvm::APSInt& rhs,
+ QualType t) {
+ ID.AddInteger((unsigned) SymIntKind);
+ ID.AddPointer(lhs);
+ ID.AddInteger(op);
+ ID.AddPointer(&rhs);
+ ID.Add(t);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) {
+ Profile(ID, LHS, Op, RHS, T);
+ }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr* SE) {
+ return SE->getKind() == SymIntKind;
+ }
+};
+
+// SymSymExpr - Represents symbolic expression like 'x' + 'y'.
+class SymSymExpr : public SymExpr {
+ const SymExpr *LHS;
+ BinaryOperator::Opcode Op;
+ const SymExpr *RHS;
+ QualType T;
+
+public:
+ SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs,
+ QualType t)
+ : SymExpr(SymSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {}
+
+ const SymExpr *getLHS() const { return LHS; }
+ const SymExpr *getRHS() const { return RHS; }
+
+ // FIXME: We probably need to make this out-of-line to avoid redundant
+ // generation of virtual functions.
+ QualType getType(ASTContext& C) const { return T; }
+
+ static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
+ BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) {
+ ID.AddInteger((unsigned) SymSymKind);
+ ID.AddPointer(lhs);
+ ID.AddInteger(op);
+ ID.AddPointer(rhs);
+ ID.Add(t);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) {
+ Profile(ID, LHS, Op, RHS, T);
+ }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr* SE) {
+ return SE->getKind() == SymSymKind;
+ }
+};
+
+class SymbolManager {
+ typedef llvm::FoldingSet<SymExpr> DataSetTy;
+ DataSetTy DataSet;
+ unsigned SymbolCounter;
+ llvm::BumpPtrAllocator& BPAlloc;
+ BasicValueFactory &BV;
+ ASTContext& Ctx;
+
+public:
+ SymbolManager(ASTContext& ctx, BasicValueFactory &bv,
+ llvm::BumpPtrAllocator& bpalloc)
+ : 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 MemRegion* R);
+ const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T,
+ 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 SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const llvm::APSInt& rhs, QualType t);
+
+ const SymIntExpr *getSymIntExpr(const SymExpr &lhs, BinaryOperator::Opcode op,
+ const llvm::APSInt& rhs, QualType t) {
+ return getSymIntExpr(&lhs, op, rhs, t);
+ }
+
+ const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const SymExpr *rhs, QualType t);
+
+ QualType getType(const SymExpr *SE) const {
+ return SE->getType(Ctx);
+ }
+
+ ASTContext &getContext() { return Ctx; }
+ BasicValueFactory &getBasicVals() { return BV; }
+};
+
+class SymbolReaper {
+ typedef llvm::ImmutableSet<SymbolRef> SetTy;
+ typedef SetTy::Factory FactoryTy;
+
+ FactoryTy F;
+ SetTy TheLiving;
+ SetTy TheDead;
+ LiveVariables& Liveness;
+ SymbolManager& SymMgr;
+
+public:
+ SymbolReaper(LiveVariables& liveness, SymbolManager& symmgr)
+ : TheLiving(F.GetEmptySet()), TheDead(F.GetEmptySet()),
+ Liveness(liveness), SymMgr(symmgr) {}
+
+ bool isLive(SymbolRef sym);
+
+ bool isLive(const Stmt* Loc, const Stmt* ExprVal) const {
+ return Liveness.isLive(Loc, ExprVal);
+ }
+
+ bool isLive(const Stmt* Loc, const VarDecl* VD) const {
+ return Liveness.isLive(Loc, VD);
+ }
+
+ void markLive(SymbolRef sym);
+ bool maybeDead(SymbolRef sym);
+
+ typedef SetTy::iterator dead_iterator;
+ dead_iterator dead_begin() const { return TheDead.begin(); }
+ dead_iterator dead_end() const { return TheDead.end(); }
+
+ bool hasDeadSymbols() const {
+ return !TheDead.isEmpty();
+ }
+};
+
+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.
+ virtual bool VisitSymbol(SymbolRef sym) = 0;
+ virtual ~SymbolVisitor();
+};
+
+} // end clang namespace
+
+namespace llvm {
+ llvm::raw_ostream& operator<<(llvm::raw_ostream& Out,
+ const clang::SymExpr *SE);
+}
+namespace std {
+ std::ostream& operator<<(std::ostream& Out,
+ const clang::SymExpr *SE);
+}
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/ValueManager.h b/include/clang/Analysis/PathSensitive/ValueManager.h
new file mode 100644
index 000000000000..89af975de7af
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/ValueManager.h
@@ -0,0 +1,103 @@
+//== ValueManager.h - Aggregate manager of symbols and SVals ----*- 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 ValueManager, a class that manages symbolic values
+// and SVals created for use by GRExprEngine and related classes. It
+// wraps SymbolManager, MemRegionManager, and BasicValueFactory.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H
+#define LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H
+
+#include "clang/Analysis/PathSensitive/MemRegion.h"
+#include "clang/Analysis/PathSensitive/SVals.h"
+#include "clang/Analysis/PathSensitive/BasicValueFactory.h"
+#include "clang/Analysis/PathSensitive/SymbolManager.h"
+
+namespace llvm { class BumpPtrAllocator; }
+
+namespace clang {
+class ValueManager {
+
+ ASTContext &Context;
+ BasicValueFactory BasicVals;
+
+ /// SymMgr - Object that manages the symbol information.
+ SymbolManager SymMgr;
+
+
+ MemRegionManager MemMgr;
+
+public:
+ ValueManager(llvm::BumpPtrAllocator &alloc, ASTContext &context)
+ : Context(context), BasicVals(Context, alloc),
+ SymMgr(Context, BasicVals, alloc),
+ MemMgr(alloc) {}
+
+ // Accessors to submanagers.
+
+ ASTContext &getContext() { return Context; }
+ const ASTContext &getContext() const { return Context; }
+
+ BasicValueFactory &getBasicValueFactory() { return BasicVals; }
+ const BasicValueFactory &getBasicValueFactory() const { return BasicVals; }
+
+ SymbolManager &getSymbolManager() { return SymMgr; }
+ const SymbolManager &getSymbolManager() const { return SymMgr; }
+
+ MemRegionManager &getRegionManager() { return MemMgr; }
+ const MemRegionManager &getRegionManager() const { return MemMgr; }
+
+ // Forwarding methods to SymbolManager.
+
+ const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T,
+ unsigned VisitCount,
+ const void* SymbolTag = 0) {
+ return SymMgr.getConjuredSymbol(E, T, VisitCount, SymbolTag);
+ }
+
+ const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount,
+ const void* SymbolTag = 0) {
+ return SymMgr.getConjuredSymbol(E, VisitCount, SymbolTag);
+ }
+
+ // Aggregation methods that use multiple submanagers.
+
+ Loc makeRegionVal(SymbolRef Sym) {
+ return Loc::MakeVal(MemMgr.getSymbolicRegion(Sym));
+ }
+
+ /// makeZeroVal - Construct an SVal representing '0' for the specified type.
+ SVal makeZeroVal(QualType T);
+ /// makeZeroArrayIndex - Construct an SVal representing '0' index for array
+ /// elements.
+ SVal makeZeroArrayIndex();
+
+ /// GetRegionValueSymbolVal - make a unique symbol for value of R.
+ SVal getRegionValueSymbolVal(const MemRegion* R);
+
+ SVal getConjuredSymbolVal(const Expr *E, unsigned Count);
+ SVal getConjuredSymbolVal(const Expr* E, QualType T, unsigned Count);
+
+ SVal getFunctionPointer(const FunctionDecl* FD);
+
+ NonLoc makeNonLoc(SymbolRef sym);
+
+ NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const llvm::APSInt& rhs, QualType T);
+
+ NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const SymExpr *rhs, QualType T);
+
+ NonLoc makeTruthVal(bool b, QualType T);
+};
+} // end clang namespace
+#endif
+
diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h
new file mode 100644
index 000000000000..d2b536ca1cb2
--- /dev/null
+++ b/include/clang/Analysis/ProgramPoint.h
@@ -0,0 +1,351 @@
+//==- ProgramPoint.h - 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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT
+#define LLVM_CLANG_ANALYSIS_PROGRAM_POINT
+
+#include "clang/AST/CFG.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/Casting.h"
+#include <cassert>
+#include <utility>
+
+namespace clang {
+
+class ProgramPoint {
+public:
+ enum Kind { BlockEdgeKind = 0x0,
+ BlockEntranceKind = 0x1,
+ BlockExitKind = 0x2,
+ // Keep the following four together and in this order.
+ PostStmtKind = 0x3,
+ PostLocationChecksSucceedKind = 0x4,
+ PostOutOfBoundsCheckFailedKind = 0x5,
+ PostNullCheckFailedKind = 0x6,
+ PostUndefLocationCheckFailedKind = 0x7,
+ PostLoadKind = 0x8,
+ PostStoreKind = 0x9,
+ PostPurgeDeadSymbolsKind = 0x10,
+ PostStmtCustomKind = 0x11,
+ PostLValueKind = 0x12,
+ MinPostStmtKind = PostStmtKind,
+ MaxPostStmtKind = PostLValueKind };
+
+private:
+ enum { TwoPointers = 0x1, Custom = 0x2, Mask = 0x3 };
+
+ std::pair<uintptr_t,uintptr_t> Data;
+ const void *Tag;
+
+protected:
+ ProgramPoint(const void* P, Kind k, const void *tag = 0)
+ : Data(reinterpret_cast<uintptr_t>(P),
+ (uintptr_t) k), Tag(tag) {}
+
+ ProgramPoint(const void* P1, const void* P2, const void *tag = 0)
+ : Data(reinterpret_cast<uintptr_t>(P1) | TwoPointers,
+ reinterpret_cast<uintptr_t>(P2)), Tag(tag) {}
+
+ ProgramPoint(const void* P1, const void* P2, bool, const void *tag = 0)
+ : Data(reinterpret_cast<uintptr_t>(P1) | Custom,
+ reinterpret_cast<uintptr_t>(P2)), Tag(tag) {}
+
+protected:
+ void* getData1NoMask() const {
+ Kind k = getKind(); k = k;
+ assert(k == BlockEntranceKind || k == BlockExitKind);
+ return reinterpret_cast<void*>(Data.first);
+ }
+
+ void* getData1() const {
+ Kind k = getKind(); k = k;
+ assert(k == BlockEdgeKind ||(k >= MinPostStmtKind && k <= MaxPostStmtKind));
+ return reinterpret_cast<void*>(Data.first & ~Mask);
+ }
+
+ void* getData2() const {
+ Kind k = getKind(); k = k;
+ assert(k == BlockEdgeKind || k == PostStmtCustomKind);
+ return reinterpret_cast<void*>(Data.second);
+ }
+
+ const void *getTag() const { return Tag; }
+
+public:
+ Kind getKind() const {
+ switch (Data.first & Mask) {
+ case TwoPointers: return BlockEdgeKind;
+ case Custom: return PostStmtCustomKind;
+ default: return (Kind) Data.second;
+ }
+ }
+
+ // For use with DenseMap. This hash is probably slow.
+ unsigned getHashValue() const {
+ llvm::FoldingSetNodeID ID;
+ ID.AddPointer(reinterpret_cast<void*>(Data.first));
+ ID.AddPointer(reinterpret_cast<void*>(Data.second));
+ ID.AddPointer(Tag);
+ return ID.ComputeHash();
+ }
+
+ static bool classof(const ProgramPoint*) { return true; }
+
+ bool operator==(const ProgramPoint & RHS) const {
+ return Data == RHS.Data && Tag == RHS.Tag;
+ }
+
+ bool operator!=(const ProgramPoint& RHS) const {
+ return Data != RHS.Data || Tag != RHS.Tag;
+ }
+
+ bool operator<(const ProgramPoint& RHS) const {
+ return Data < RHS.Data && Tag < RHS.Tag;
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddPointer(reinterpret_cast<void*>(Data.first));
+ if (getKind() != PostStmtCustomKind)
+ ID.AddPointer(reinterpret_cast<void*>(Data.second));
+ else {
+ const std::pair<const void*, const void*> *P =
+ reinterpret_cast<std::pair<const void*, const void*>*>(Data.second);
+ ID.AddPointer(P->first);
+ ID.AddPointer(P->second);
+ }
+ ID.AddPointer(Tag);
+ }
+};
+
+class BlockEntrance : public ProgramPoint {
+public:
+ BlockEntrance(const CFGBlock* B, const void *tag = 0)
+ : ProgramPoint(B, BlockEntranceKind, tag) {}
+
+ CFGBlock* getBlock() const {
+ return reinterpret_cast<CFGBlock*>(getData1NoMask());
+ }
+
+ Stmt* getFirstStmt() const {
+ CFGBlock* B = getBlock();
+ return B->empty() ? NULL : B->front();
+ }
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == BlockEntranceKind;
+ }
+};
+
+class BlockExit : public ProgramPoint {
+public:
+ BlockExit(const CFGBlock* B) : ProgramPoint(B, BlockExitKind) {}
+
+ CFGBlock* getBlock() const {
+ return reinterpret_cast<CFGBlock*>(getData1NoMask());
+ }
+
+ Stmt* getLastStmt() const {
+ CFGBlock* B = getBlock();
+ return B->empty() ? NULL : B->back();
+ }
+
+ Stmt* getTerminator() const {
+ return getBlock()->getTerminator();
+ }
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == BlockExitKind;
+ }
+};
+
+class PostStmt : public ProgramPoint {
+protected:
+ PostStmt(const Stmt* S, Kind k,const void *tag = 0)
+ : ProgramPoint(S, k, tag) {}
+
+ PostStmt(const Stmt* S, const void* data, bool, const void *tag =0)
+ : ProgramPoint(S, data, true, tag) {}
+
+public:
+ PostStmt(const Stmt* S, const void *tag = 0)
+ : ProgramPoint(S, PostStmtKind, tag) {}
+
+ Stmt* getStmt() const { return (Stmt*) getData1(); }
+
+ template<typename T>
+ T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); }
+
+ static bool classof(const ProgramPoint* Location) {
+ unsigned k = Location->getKind();
+ return k >= MinPostStmtKind && k <= MaxPostStmtKind;
+ }
+};
+
+class PostLocationChecksSucceed : public PostStmt {
+public:
+ PostLocationChecksSucceed(const Stmt* S, const void *tag = 0)
+ : PostStmt(S, PostLocationChecksSucceedKind, tag) {}
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == PostLocationChecksSucceedKind;
+ }
+};
+
+class PostStmtCustom : public PostStmt {
+public:
+ PostStmtCustom(const Stmt* S,
+ const std::pair<const void*, const void*>* TaggedData)
+ : PostStmt(S, TaggedData, true) {
+ assert(getKind() == PostStmtCustomKind);
+ }
+
+ const std::pair<const void*, const void*>& getTaggedPair() const {
+ return *reinterpret_cast<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;
+ }
+};
+
+class PostOutOfBoundsCheckFailed : public PostStmt {
+public:
+ PostOutOfBoundsCheckFailed(const Stmt* S, const void *tag = 0)
+ : PostStmt(S, PostOutOfBoundsCheckFailedKind, tag) {}
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == PostOutOfBoundsCheckFailedKind;
+ }
+};
+
+class PostUndefLocationCheckFailed : public PostStmt {
+public:
+ PostUndefLocationCheckFailed(const Stmt* S, const void *tag = 0)
+ : PostStmt(S, PostUndefLocationCheckFailedKind, tag) {}
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == PostUndefLocationCheckFailedKind;
+ }
+};
+
+class PostNullCheckFailed : public PostStmt {
+public:
+ PostNullCheckFailed(const Stmt* S, const void *tag = 0)
+ : PostStmt(S, PostNullCheckFailedKind, tag) {}
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == PostNullCheckFailedKind;
+ }
+};
+
+class PostLoad : public PostStmt {
+public:
+ PostLoad(const Stmt* S, const void *tag = 0)
+ : PostStmt(S, PostLoadKind, tag) {}
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == PostLoadKind;
+ }
+};
+
+class PostStore : public PostStmt {
+public:
+ PostStore(const Stmt* S, const void *tag = 0)
+ : PostStmt(S, PostStoreKind, tag) {}
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == PostStoreKind;
+ }
+};
+
+class PostLValue : public PostStmt {
+public:
+ PostLValue(const Stmt* S, const void *tag = 0)
+ : PostStmt(S, PostLValueKind, tag) {}
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == PostLValueKind;
+ }
+};
+
+class PostPurgeDeadSymbols : public PostStmt {
+public:
+ PostPurgeDeadSymbols(const Stmt* S, const void *tag = 0)
+ : PostStmt(S, PostPurgeDeadSymbolsKind, tag) {}
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == PostPurgeDeadSymbolsKind;
+ }
+};
+
+class BlockEdge : public ProgramPoint {
+public:
+ BlockEdge(const CFGBlock* B1, const CFGBlock* B2)
+ : ProgramPoint(B1, B2) {}
+
+ CFGBlock* getSrc() const {
+ return static_cast<CFGBlock*>(getData1());
+ }
+
+ CFGBlock* getDst() const {
+ return static_cast<CFGBlock*>(getData2());
+ }
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == BlockEdgeKind;
+ }
+};
+
+
+} // end namespace clang
+
+
+namespace llvm { // Traits specialization for DenseMap
+
+template <> struct DenseMapInfo<clang::ProgramPoint> {
+
+static inline clang::ProgramPoint getEmptyKey() {
+ uintptr_t x =
+ reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7;
+ return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x));
+}
+
+static inline clang::ProgramPoint getTombstoneKey() {
+ uintptr_t x =
+ reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7;
+ return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x));
+}
+
+static unsigned getHashValue(const clang::ProgramPoint& Loc) {
+ return Loc.getHashValue();
+}
+
+static bool isEqual(const clang::ProgramPoint& L,
+ const clang::ProgramPoint& R) {
+ return L == R;
+}
+
+static bool isPod() {
+ return true;
+}
+};
+} // end namespace llvm
+
+#endif
diff --git a/include/clang/Analysis/Support/BlkExprDeclBitVector.h b/include/clang/Analysis/Support/BlkExprDeclBitVector.h
new file mode 100644
index 000000000000..a592be815419
--- /dev/null
+++ b/include/clang/Analysis/Support/BlkExprDeclBitVector.h
@@ -0,0 +1,307 @@
+// BlkExprDeclBitVector.h - Dataflow types for Bitvector Analysis --*- C++ --*--
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides definition of dataflow types used by analyses such
+// as LiveVariables and UninitializedValues. The underlying dataflow values
+// are implemented as bitvectors, but the definitions in this file include
+// the necessary boilerplate to use with our dataflow framework.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STMTDECLBVDVAL_H
+#define LLVM_CLANG_STMTDECLBVDVAL_H
+
+#include "clang/AST/CFG.h"
+#include "clang/AST/Decl.h" // for Decl* -> NamedDecl* conversion
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+
+ class Stmt;
+ class ASTContext;
+
+struct DeclBitVector_Types {
+
+ class Idx {
+ unsigned I;
+ public:
+ explicit Idx(unsigned i) : I(i) {}
+ Idx() : I(~0U) {}
+
+ bool isValid() const {
+ return I != ~0U;
+ }
+ operator unsigned() const {
+ assert (isValid());
+ return I;
+ }
+ };
+
+ //===--------------------------------------------------------------------===//
+ // AnalysisDataTy - Whole-function meta data.
+ //===--------------------------------------------------------------------===//
+
+ class AnalysisDataTy {
+ public:
+ typedef llvm::DenseMap<const NamedDecl*, unsigned > DMapTy;
+ typedef DMapTy::const_iterator decl_iterator;
+
+ protected:
+ DMapTy DMap;
+ unsigned NDecls;
+
+ public:
+
+ AnalysisDataTy() : NDecls(0) {}
+ virtual ~AnalysisDataTy() {}
+
+ bool isTracked(const NamedDecl* SD) { return DMap.find(SD) != DMap.end(); }
+
+ Idx getIdx(const NamedDecl* SD) const {
+ DMapTy::const_iterator I = DMap.find(SD);
+ return I == DMap.end() ? Idx() : Idx(I->second);
+ }
+
+ unsigned getNumDecls() const { return NDecls; }
+
+ void Register(const NamedDecl* SD) {
+ if (!isTracked(SD)) DMap[SD] = NDecls++;
+ }
+
+ decl_iterator begin_decl() const { return DMap.begin(); }
+ decl_iterator end_decl() const { return DMap.end(); }
+ };
+
+ //===--------------------------------------------------------------------===//
+ // ValTy - Dataflow value.
+ //===--------------------------------------------------------------------===//
+
+ class ValTy {
+ llvm::BitVector DeclBV;
+ public:
+
+ void resetDeclValues(AnalysisDataTy& AD) {
+ DeclBV.resize(AD.getNumDecls());
+ DeclBV.reset();
+ }
+
+ void setDeclValues(AnalysisDataTy& AD) {
+ DeclBV.resize(AD.getNumDecls());
+ DeclBV.set();
+ }
+
+ void resetValues(AnalysisDataTy& AD) {
+ resetDeclValues(AD);
+ }
+
+ bool operator==(const ValTy& RHS) const {
+ assert (sizesEqual(RHS));
+ return DeclBV == RHS.DeclBV;
+ }
+
+ void copyValues(const ValTy& RHS) { DeclBV = RHS.DeclBV; }
+
+ llvm::BitVector::reference getBit(unsigned i) {
+ return DeclBV[i];
+ }
+
+ bool getBit(unsigned i) const {
+ return DeclBV[i];
+ }
+
+ llvm::BitVector::reference
+ operator()(const NamedDecl* ND, const AnalysisDataTy& AD) {
+ return getBit(AD.getIdx(ND));
+ }
+
+ bool operator()(const NamedDecl* ND, const AnalysisDataTy& AD) const {
+ return getBit(AD.getIdx(ND));
+ }
+
+ llvm::BitVector::reference getDeclBit(unsigned i) { return DeclBV[i]; }
+ const llvm::BitVector::reference getDeclBit(unsigned i) const {
+ return const_cast<llvm::BitVector&>(DeclBV)[i];
+ }
+
+ ValTy& operator|=(const ValTy& RHS) {
+ assert (sizesEqual(RHS));
+ DeclBV |= RHS.DeclBV;
+ return *this;
+ }
+
+ ValTy& operator&=(const ValTy& RHS) {
+ assert (sizesEqual(RHS));
+ DeclBV &= RHS.DeclBV;
+ return *this;
+ }
+
+ ValTy& OrDeclBits(const ValTy& RHS) {
+ return operator|=(RHS);
+ }
+
+ ValTy& AndDeclBits(const ValTy& RHS) {
+ return operator&=(RHS);
+ }
+
+ bool sizesEqual(const ValTy& RHS) const {
+ return DeclBV.size() == RHS.DeclBV.size();
+ }
+ };
+
+ //===--------------------------------------------------------------------===//
+ // Some useful merge operations.
+ //===--------------------------------------------------------------------===//
+
+ struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } };
+ struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } };
+};
+
+
+struct StmtDeclBitVector_Types {
+
+ //===--------------------------------------------------------------------===//
+ // AnalysisDataTy - Whole-function meta data.
+ //===--------------------------------------------------------------------===//
+
+ class AnalysisDataTy : public DeclBitVector_Types::AnalysisDataTy {
+ ASTContext* ctx;
+ CFG* cfg;
+ public:
+ AnalysisDataTy() : ctx(0), cfg(0) {}
+ virtual ~AnalysisDataTy() {}
+
+ void setContext(ASTContext& c) { ctx = &c; }
+ ASTContext& getContext() {
+ assert(ctx && "ASTContext should not be NULL.");
+ return *ctx;
+ }
+
+ void setCFG(CFG& c) { cfg = &c; }
+ CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; }
+
+ bool isTracked(const Stmt* S) { return cfg->isBlkExpr(S); }
+ using DeclBitVector_Types::AnalysisDataTy::isTracked;
+
+ unsigned getIdx(const Stmt* S) const {
+ CFG::BlkExprNumTy I = cfg->getBlkExprNum(S);
+ assert(I && "Stmtession not tracked for bitvector.");
+ return I;
+ }
+ using DeclBitVector_Types::AnalysisDataTy::getIdx;
+
+ unsigned getNumBlkExprs() const { return cfg->getNumBlkExprs(); }
+ };
+
+ //===--------------------------------------------------------------------===//
+ // ValTy - Dataflow value.
+ //===--------------------------------------------------------------------===//
+
+ class ValTy : public DeclBitVector_Types::ValTy {
+ llvm::BitVector BlkExprBV;
+ typedef DeclBitVector_Types::ValTy ParentTy;
+
+ static inline ParentTy& ParentRef(ValTy& X) {
+ return static_cast<ParentTy&>(X);
+ }
+
+ static inline const ParentTy& ParentRef(const ValTy& X) {
+ return static_cast<const ParentTy&>(X);
+ }
+
+ public:
+
+ void resetBlkExprValues(AnalysisDataTy& AD) {
+ BlkExprBV.resize(AD.getNumBlkExprs());
+ BlkExprBV.reset();
+ }
+
+ void setBlkExprValues(AnalysisDataTy& AD) {
+ BlkExprBV.resize(AD.getNumBlkExprs());
+ BlkExprBV.set();
+ }
+
+ void resetValues(AnalysisDataTy& AD) {
+ resetDeclValues(AD);
+ resetBlkExprValues(AD);
+ }
+
+ void setValues(AnalysisDataTy& AD) {
+ setDeclValues(AD);
+ setBlkExprValues(AD);
+ }
+
+ bool operator==(const ValTy& RHS) const {
+ return ParentRef(*this) == ParentRef(RHS)
+ && BlkExprBV == RHS.BlkExprBV;
+ }
+
+ void copyValues(const ValTy& RHS) {
+ ParentRef(*this).copyValues(ParentRef(RHS));
+ BlkExprBV = RHS.BlkExprBV;
+ }
+
+ llvm::BitVector::reference
+ operator()(const Stmt* S, const AnalysisDataTy& AD) {
+ return BlkExprBV[AD.getIdx(S)];
+ }
+ const llvm::BitVector::reference
+ operator()(const Stmt* S, const AnalysisDataTy& AD) const {
+ return const_cast<ValTy&>(*this)(S,AD);
+ }
+
+ using DeclBitVector_Types::ValTy::operator();
+
+
+ llvm::BitVector::reference getStmtBit(unsigned i) { return BlkExprBV[i]; }
+ const llvm::BitVector::reference getStmtBit(unsigned i) const {
+ return const_cast<llvm::BitVector&>(BlkExprBV)[i];
+ }
+
+ ValTy& OrBlkExprBits(const ValTy& RHS) {
+ BlkExprBV |= RHS.BlkExprBV;
+ return *this;
+ }
+
+ ValTy& AndBlkExprBits(const ValTy& RHS) {
+ BlkExprBV &= RHS.BlkExprBV;
+ return *this;
+ }
+
+ ValTy& operator|=(const ValTy& RHS) {
+ assert (sizesEqual(RHS));
+ ParentRef(*this) |= ParentRef(RHS);
+ BlkExprBV |= RHS.BlkExprBV;
+ return *this;
+ }
+
+ ValTy& operator&=(const ValTy& RHS) {
+ assert (sizesEqual(RHS));
+ ParentRef(*this) &= ParentRef(RHS);
+ BlkExprBV &= RHS.BlkExprBV;
+ return *this;
+ }
+
+ bool sizesEqual(const ValTy& RHS) const {
+ return ParentRef(*this).sizesEqual(ParentRef(RHS))
+ && BlkExprBV.size() == RHS.BlkExprBV.size();
+ }
+ };
+
+ //===--------------------------------------------------------------------===//
+ // Some useful merge operations.
+ //===--------------------------------------------------------------------===//
+
+ struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } };
+ struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } };
+
+};
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
new file mode 100644
index 000000000000..ee79c517030f
--- /dev/null
+++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
@@ -0,0 +1,91 @@
+//= CFGRecStmtDeclVisitor - Recursive visitor of CFG stmts/decls -*- C++ --*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the template class CFGRecStmtDeclVisitor, which extends
+// CFGRecStmtVisitor by implementing (typed) visitation of decls.
+//
+// FIXME: This may not be fully complete. We currently explore only subtypes
+// of ScopedDecl.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H
+#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H
+
+#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+
+#define DISPATCH_CASE(CASE,CLASS) \
+case Decl::CASE: \
+static_cast<ImplClass*>(this)->Visit##CLASS(static_cast<CLASS*>(D));\
+break;
+
+#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS(CLASS* D) {}
+#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS(CLASS* D)\
+ { static_cast<ImplClass*>(this)->VisitVarDecl(D); }
+
+
+namespace clang {
+template <typename ImplClass>
+class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> {
+public:
+
+ void VisitDeclRefExpr(DeclRefExpr* DR) {
+ static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl());
+ }
+
+ void VisitDeclStmt(DeclStmt* DS) {
+ for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
+ DI != DE; ++DI) {
+ Decl* D = *DI;
+ static_cast<ImplClass*>(this)->VisitDecl(D);
+ // Visit the initializer.
+ if (VarDecl* VD = dyn_cast<VarDecl>(D))
+ if (Expr* I = VD->getInit())
+ static_cast<ImplClass*>(this)->Visit(I);
+ }
+ }
+
+ void VisitDecl(Decl* D) {
+ switch (D->getKind()) {
+ DISPATCH_CASE(Function,FunctionDecl)
+ DISPATCH_CASE(Var,VarDecl)
+ DISPATCH_CASE(ParmVar,ParmVarDecl) // FIXME: (same)
+ DISPATCH_CASE(OriginalParmVar,OriginalParmVarDecl) // FIXME: (same)
+ DISPATCH_CASE(ImplicitParam,ImplicitParamDecl)
+ DISPATCH_CASE(EnumConstant,EnumConstantDecl)
+ DISPATCH_CASE(Typedef,TypedefDecl)
+ DISPATCH_CASE(Record,RecordDecl) // FIXME: Refine. VisitStructDecl?
+ DISPATCH_CASE(Enum,EnumDecl)
+ default:
+ assert(false && "Subtype of ScopedDecl not handled.");
+ }
+ }
+
+ DEFAULT_DISPATCH(VarDecl)
+ DEFAULT_DISPATCH(FunctionDecl)
+ DEFAULT_DISPATCH_VARDECL(OriginalParmVarDecl)
+ DEFAULT_DISPATCH_VARDECL(ParmVarDecl)
+ DEFAULT_DISPATCH(ImplicitParamDecl)
+ DEFAULT_DISPATCH(EnumConstantDecl)
+ DEFAULT_DISPATCH(TypedefDecl)
+ DEFAULT_DISPATCH(RecordDecl)
+ DEFAULT_DISPATCH(EnumDecl)
+ DEFAULT_DISPATCH(ObjCInterfaceDecl)
+ DEFAULT_DISPATCH(ObjCClassDecl)
+ DEFAULT_DISPATCH(ObjCMethodDecl)
+ DEFAULT_DISPATCH(ObjCProtocolDecl)
+ DEFAULT_DISPATCH(ObjCCategoryDecl)
+};
+
+} // end namespace clang
+
+#undef DISPATCH_CASE
+#undef DEFAULT_DISPATCH
+#endif
diff --git a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h
new file mode 100644
index 000000000000..4d3201962250
--- /dev/null
+++ b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h
@@ -0,0 +1,35 @@
+//==- CFGRecStmtVisitor - Recursive visitor of CFG statements ---*- C++ --*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the template class CFGRecStmtVisitor, which extends
+// CFGStmtVisitor by implementing a default recursive visit of all statements.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H
+#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H
+
+#include "clang/Analysis/Visitors/CFGStmtVisitor.h"
+
+namespace clang {
+template <typename ImplClass>
+class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> {
+public:
+
+ void VisitStmt(Stmt* S) {
+ static_cast< ImplClass* >(this)->VisitChildren(S);
+ }
+
+ // Defining operator() allows the visitor to be used as a C++ style functor.
+ void operator()(Stmt* S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);}
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h
new file mode 100644
index 000000000000..f42bbde8f148
--- /dev/null
+++ b/include/clang/Analysis/Visitors/CFGStmtVisitor.h
@@ -0,0 +1,156 @@
+//===--- CFGStmtVisitor.h - Visitor for Stmts in a CFG ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the CFGStmtVisitor interface, which extends
+// StmtVisitor. This interface is useful for visiting statements in a CFG
+// where some statements have implicit control-flow and thus should
+// be treated specially.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H
+#define LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H
+
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/CFG.h"
+
+namespace clang {
+
+#define DISPATCH_CASE(CLASS) \
+case Stmt::CLASS ## Class: return \
+static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S));
+
+#define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\
+{ return\
+ static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(\
+ cast<Expr>(S)); }
+
+template <typename ImplClass, typename RetTy=void>
+class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
+ Stmt* CurrentBlkStmt;
+
+ struct NullifyStmt {
+ Stmt*& S;
+
+ NullifyStmt(Stmt*& s) : S(s) {}
+ ~NullifyStmt() { S = NULL; }
+ };
+
+public:
+ CFGStmtVisitor() : CurrentBlkStmt(NULL) {}
+
+ Stmt* getCurrentBlkStmt() const { return CurrentBlkStmt; }
+
+ RetTy Visit(Stmt* S) {
+ if (S == CurrentBlkStmt ||
+ !static_cast<ImplClass*>(this)->getCFG().isBlkExpr(S))
+ return StmtVisitor<ImplClass,RetTy>::Visit(S);
+ else
+ return RetTy();
+ }
+
+ /// BlockVisit_XXX - Visitor methods for visiting the "root" statements in
+ /// CFGBlocks. Root statements are the statements that appear explicitly in
+ /// the list of statements in a CFGBlock. For substatements, or when there
+ /// is no implementation provided for a BlockStmt_XXX method, we default
+ /// to using StmtVisitor's Visit method.
+ RetTy BlockStmt_Visit(Stmt* S) {
+ CurrentBlkStmt = S;
+ NullifyStmt cleanup(CurrentBlkStmt);
+
+ switch (S->getStmtClass()) {
+
+ DISPATCH_CASE(StmtExpr)
+ DISPATCH_CASE(ConditionalOperator)
+ DISPATCH_CASE(ObjCForCollectionStmt)
+
+ case Stmt::BinaryOperatorClass: {
+ BinaryOperator* B = cast<BinaryOperator>(S);
+ if (B->isLogicalOp())
+ return static_cast<ImplClass*>(this)->BlockStmt_VisitLogicalOp(B);
+ else if (B->getOpcode() == BinaryOperator::Comma)
+ return static_cast<ImplClass*>(this)->BlockStmt_VisitComma(B);
+ // Fall through.
+ }
+
+ default:
+ if (isa<Expr>(S))
+ return
+ static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(cast<Expr>(S));
+ else
+ return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
+ }
+ }
+
+ DEFAULT_BLOCKSTMT_VISIT(StmtExpr)
+ DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator)
+
+ RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
+ return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
+ }
+
+ RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr* E) {
+ return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E);
+ }
+
+ RetTy BlockStmt_VisitExpr(Expr* E) {
+ return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(E);
+ }
+
+ RetTy BlockStmt_VisitStmt(Stmt* S) {
+ return static_cast<ImplClass*>(this)->Visit(S);
+ }
+
+ RetTy BlockStmt_VisitLogicalOp(BinaryOperator* B) {
+ return
+ static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B);
+ }
+
+ RetTy BlockStmt_VisitComma(BinaryOperator* B) {
+ return
+ static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Utility methods. Not called by default (but subclasses may use them).
+ //===--------------------------------------------------------------------===//
+
+ /// VisitChildren: Call "Visit" on each child of S.
+ void VisitChildren(Stmt* S) {
+
+ switch (S->getStmtClass()) {
+ default:
+ break;
+
+ case Stmt::StmtExprClass: {
+ CompoundStmt* CS = cast<StmtExpr>(S)->getSubStmt();
+ if (CS->body_empty()) return;
+ static_cast<ImplClass*>(this)->Visit(CS->body_back());
+ return;
+ }
+
+ case Stmt::BinaryOperatorClass: {
+ BinaryOperator* B = cast<BinaryOperator>(S);
+ if (B->getOpcode() != BinaryOperator::Comma) break;
+ static_cast<ImplClass*>(this)->Visit(B->getRHS());
+ return;
+ }
+ }
+
+ for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I)
+ if (*I) static_cast<ImplClass*>(this)->Visit(*I);
+ }
+};
+
+#undef DEFAULT_BLOCKSTMT_VISIT
+#undef DISPATCH_CASE
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h b/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h
new file mode 100644
index 000000000000..25101235ddd2
--- /dev/null
+++ b/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h
@@ -0,0 +1,64 @@
+//==- CFGVarDeclVisitor - Generic visitor of VarDecls in a CFG --*- C++ --*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the template class CFGVarDeclVisitor, which provides
+// a generic way to visit all the VarDecl's in a CFG.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CFG_VARDECL_VISITOR_H
+#define LLVM_CLANG_ANALYSIS_CFG_VARDECL_VISITOR_H
+
+#include "clang/Analysis/Visitors/CFGStmtVisitor.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/CFG.h"
+
+namespace clang {
+
+template <typename ImplClass>
+class CFGVarDeclVisitor : public CFGStmtVisitor<ImplClass> {
+ const CFG& cfg;
+public:
+ CFGVarDeclVisitor(const CFG& c) : cfg(c) {}
+
+ void VisitStmt(Stmt* S) {
+ static_cast<ImplClass*>(this)->VisitChildren(S);
+ }
+
+ void VisitDeclRefExpr(DeclRefExpr* DR) {
+ static_cast<ImplClass*>(this)->VisitDeclChain(DR->getDecl());
+ }
+
+ void VisitDeclStmt(DeclStmt* DS) {
+ static_cast<ImplClass*>(this)->VisitDeclChain(DS->getDecl());
+ }
+
+ void VisitDeclChain(ScopedDecl* D) {
+ for (; D != NULL ; D = D->getNextDeclarator())
+ static_cast<ImplClass*>(this)->VisitScopedDecl(D);
+ }
+
+ void VisitScopedDecl(ScopedDecl* D) {
+ if (VarDecl* V = dyn_cast<VarDecl>(D))
+ static_cast<ImplClass*>(this)->VisitVarDecl(V);
+ }
+
+ void VisitVarDecl(VarDecl* D) {}
+
+ void VisitAllDecls() {
+ for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI)
+ for (CFGBlock::const_iterator SI=BI->begin(),SE = BI->end();SI != SE;++SI)
+ static_cast<ImplClass*>(this)->BlockStmt_Visit(const_cast<Stmt*>(*SI));
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/CMakeLists.txt b/include/clang/Basic/CMakeLists.txt
new file mode 100644
index 000000000000..9e643bb3c2c1
--- /dev/null
+++ b/include/clang/Basic/CMakeLists.txt
@@ -0,0 +1,20 @@
+macro(clang_diag_gen component)
+ tablegen(Diagnostic${component}Kinds.inc
+ -gen-clang-diags-defs -clang-component=${component})
+ add_custom_target(ClangDiagnostic${component}
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Diagnostic${component}Kinds.inc)
+endmacro(clang_diag_gen)
+
+set(LLVM_TARGET_DEFINITIONS Diagnostic.td)
+clang_diag_gen(Analysis)
+clang_diag_gen(AST)
+clang_diag_gen(Common)
+clang_diag_gen(Driver)
+clang_diag_gen(Frontend)
+clang_diag_gen(Lex)
+clang_diag_gen(Parse)
+clang_diag_gen(Sema)
+tablegen(DiagnosticGroups.inc
+ -gen-clang-diag-groups)
+add_custom_target(ClangDiagnosticGroups
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/DiagnosticGroups.inc)
diff --git a/include/clang/Basic/ConvertUTF.h b/include/clang/Basic/ConvertUTF.h
new file mode 100644
index 000000000000..73e2fcd12fee
--- /dev/null
+++ b/include/clang/Basic/ConvertUTF.h
@@ -0,0 +1,159 @@
+/*===--- ConvertUTF.h - Universal Character Names conversions ---------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ *
+ *==------------------------------------------------------------------------==*/
+/*
+ * Copyright 2001-2004 Unicode, Inc.
+ *
+ * Disclaimer
+ *
+ * This source code is provided as is by Unicode, Inc. No claims are
+ * made as to fitness for any particular purpose. No warranties of any
+ * kind are expressed or implied. The recipient agrees to determine
+ * applicability of information provided. If this file has been
+ * purchased on magnetic or optical media from Unicode, Inc., the
+ * sole remedy for any claim will be exchange of defective media
+ * within 90 days of receipt.
+ *
+ * Limitations on Rights to Redistribute This Code
+ *
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+
+/* ---------------------------------------------------------------------
+
+ Conversions between UTF32, UTF-16, and UTF-8. Header file.
+
+ Several funtions are included here, forming a complete set of
+ conversions between the three formats. UTF-7 is not included
+ here, but is handled in a separate source file.
+
+ Each of these routines takes pointers to input buffers and output
+ buffers. The input buffers are const.
+
+ Each routine converts the text between *sourceStart and sourceEnd,
+ putting the result into the buffer between *targetStart and
+ targetEnd. Note: the end pointers are *after* the last item: e.g.
+ *(sourceEnd - 1) is the last item.
+
+ The return result indicates whether the conversion was successful,
+ and if not, whether the problem was in the source or target buffers.
+ (Only the first encountered problem is indicated.)
+
+ After the conversion, *sourceStart and *targetStart are both
+ updated to point to the end of last text successfully converted in
+ the respective buffers.
+
+ Input parameters:
+ sourceStart - pointer to a pointer to the source buffer.
+ The contents of this are modified on return so that
+ it points at the next thing to be converted.
+ targetStart - similarly, pointer to pointer to the target buffer.
+ sourceEnd, targetEnd - respectively pointers to the ends of the
+ two buffers, for overflow checking only.
+
+ These conversion functions take a ConversionFlags argument. When this
+ flag is set to strict, both irregular sequences and isolated surrogates
+ will cause an error. When the flag is set to lenient, both irregular
+ sequences and isolated surrogates are converted.
+
+ Whether the flag is strict or lenient, all illegal sequences will cause
+ an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
+ or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
+ must check for illegal sequences.
+
+ When the flag is set to lenient, characters over 0x10FFFF are converted
+ to the replacement character; otherwise (when the flag is set to strict)
+ they constitute an error.
+
+ Output parameters:
+ The value "sourceIllegal" is returned from some routines if the input
+ sequence is malformed. When "sourceIllegal" is returned, the source
+ value will point to the illegal value that caused the problem. E.g.,
+ in UTF-8 when a sequence is malformed, it points to the start of the
+ malformed sequence.
+
+ Author: Mark E. Davis, 1994.
+ Rev History: Rick McGowan, fixes & updates May 2001.
+ Fixes & updates, Sept 2001.
+
+------------------------------------------------------------------------ */
+
+/* ---------------------------------------------------------------------
+ The following 4 definitions are compiler-specific.
+ The C standard does not guarantee that wchar_t has at least
+ 16 bits, so wchar_t is no less portable than unsigned short!
+ All should be unsigned values to avoid sign extension during
+ bit mask & shift operations.
+------------------------------------------------------------------------ */
+
+typedef unsigned long UTF32; /* at least 32 bits */
+typedef unsigned short UTF16; /* at least 16 bits */
+typedef unsigned char UTF8; /* typically 8 bits */
+typedef unsigned char Boolean; /* 0 or 1 */
+
+/* Some fundamental constants */
+#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
+#define UNI_MAX_BMP (UTF32)0x0000FFFF
+#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
+#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
+#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
+
+typedef enum {
+ conversionOK, /* conversion successful */
+ sourceExhausted, /* partial character in source, but hit end */
+ targetExhausted, /* insuff. room in target for conversion */
+ sourceIllegal /* source sequence is illegal/malformed */
+} ConversionResult;
+
+typedef enum {
+ strictConversion = 0,
+ lenientConversion
+} ConversionFlags;
+
+/* This is for C++ and does no harm in C */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ConversionResult ConvertUTF8toUTF16 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
+
+#ifdef CLANG_NEEDS_THESE_ONE_DAY
+ConversionResult ConvertUTF16toUTF8 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF8toUTF32 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF32toUTF8 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF16toUTF32 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF32toUTF16 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
+#endif
+
+Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* --------------------------------------------------------------------- */
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
new file mode 100644
index 000000000000..22e7fb3f85ea
--- /dev/null
+++ b/include/clang/Basic/Diagnostic.h
@@ -0,0 +1,697 @@
+//===--- Diagnostic.h - C Language Family Diagnostic Handling ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Diagnostic-related interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_DIAGNOSTIC_H
+#define LLVM_CLANG_DIAGNOSTIC_H
+
+#include "clang/Basic/SourceLocation.h"
+#include <string>
+#include <cassert>
+
+namespace llvm {
+ template <typename T> class SmallVectorImpl;
+}
+
+namespace clang {
+ class DiagnosticClient;
+ class SourceRange;
+ class DiagnosticBuilder;
+ class IdentifierInfo;
+ class LangOptions;
+
+ // Import the diagnostic enums themselves.
+ namespace diag {
+ // Start position for diagnostics.
+ enum {
+ DIAG_START_DRIVER = 300,
+ DIAG_START_FRONTEND = DIAG_START_DRIVER + 100,
+ DIAG_START_LEX = DIAG_START_FRONTEND + 100,
+ DIAG_START_PARSE = DIAG_START_LEX + 300,
+ DIAG_START_AST = DIAG_START_PARSE + 300,
+ DIAG_START_SEMA = DIAG_START_AST + 100,
+ DIAG_START_ANALYSIS = DIAG_START_SEMA + 1000,
+ DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100
+ };
+
+ class CustomDiagInfo;
+
+ /// diag::kind - All of the diagnostics that can be emitted by the frontend.
+ typedef unsigned kind;
+
+ // Get typedefs for common diagnostics.
+ enum {
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM,
+#include "clang/Basic/DiagnosticCommonKinds.inc"
+ NUM_BUILTIN_COMMON_DIAGNOSTICS
+#undef DIAG
+ };
+
+ /// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
+ /// to either MAP_IGNORE (nothing), MAP_WARNING (emit a warning), MAP_ERROR
+ /// (emit as an error). It allows clients to map errors to
+ /// MAP_ERROR/MAP_DEFAULT or MAP_FATAL (stop emitting diagnostics after this
+ /// one).
+ enum Mapping {
+ // NOTE: 0 means "uncomputed".
+ 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
+ };
+ }
+
+/// \brief Annotates a diagnostic with some code that should be
+/// inserted, removed, or replaced to fix the problem.
+///
+/// This kind of hint should be used when we are certain that the
+/// introduction, removal, or modification of a particular (small!)
+/// amount of code will correct a compilation error. The compiler
+/// should also provide full recovery from such errors, such that
+/// suppressing the diagnostic output can still result in successful
+/// compilation.
+class CodeModificationHint {
+public:
+ /// \brief Tokens that should be removed to correct the error.
+ SourceRange RemoveRange;
+
+ /// \brief The location at which we should insert code to correct
+ /// the error.
+ SourceLocation InsertionLoc;
+
+ /// \brief The actual code to insert at the insertion location, as a
+ /// string.
+ std::string CodeToInsert;
+
+ /// \brief Empty code modification hint, indicating that no code
+ /// modification is known.
+ CodeModificationHint() : RemoveRange(), InsertionLoc() { }
+
+ /// \brief Create a code modification hint that inserts the given
+ /// code string at a specific location.
+ static CodeModificationHint CreateInsertion(SourceLocation InsertionLoc,
+ const std::string &Code) {
+ CodeModificationHint Hint;
+ Hint.InsertionLoc = InsertionLoc;
+ Hint.CodeToInsert = Code;
+ return Hint;
+ }
+
+ /// \brief Create a code modification hint that removes the given
+ /// source range.
+ static CodeModificationHint CreateRemoval(SourceRange RemoveRange) {
+ CodeModificationHint Hint;
+ Hint.RemoveRange = RemoveRange;
+ return Hint;
+ }
+
+ /// \brief Create a code modification hint that replaces the given
+ /// source range with the given code string.
+ static CodeModificationHint CreateReplacement(SourceRange RemoveRange,
+ const std::string &Code) {
+ CodeModificationHint Hint;
+ Hint.RemoveRange = RemoveRange;
+ Hint.InsertionLoc = RemoveRange.getBegin();
+ Hint.CodeToInsert = Code;
+ return Hint;
+ }
+};
+
+/// Diagnostic - 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.
+class Diagnostic {
+public:
+ /// Level - The level of the diagnostic, after it has been through mapping.
+ enum Level {
+ Ignored, Note, Warning, Error, Fatal
+ };
+
+ /// ExtensionHandling - How do we handle otherwise-unmapped extension? This
+ /// is controlled by -pedantic and -pedantic-errors.
+ enum ExtensionHandling {
+ Ext_Ignore, Ext_Warn, Ext_Error
+ };
+
+ enum ArgumentKind {
+ ak_std_string, // std::string
+ ak_c_string, // const char *
+ ak_sint, // int
+ ak_uint, // unsigned
+ ak_identifierinfo, // IdentifierInfo
+ ak_qualtype, // QualType
+ ak_declarationname, // DeclarationName
+ ak_nameddecl // NamedDecl *
+ };
+
+private:
+ unsigned char AllExtensionsSilenced; // Used by __extension__
+ bool IgnoreAllWarnings; // Ignore all warnings: -w
+ bool WarningsAsErrors; // Treat warnings like errors:
+ bool SuppressSystemWarnings; // Suppress warnings in system headers.
+ ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors?
+ DiagnosticClient *Client;
+
+ /// DiagMappings - Mapping information for diagnostics. Mapping info is
+ /// packed into four bits per diagnostic. The low three bits are the mapping
+ /// (an instance of diag::Mapping), or zero if unset. The high bit is set
+ /// when the mapping was established as a user mapping. If the high bit is
+ /// clear, then the low bits are set to the default value, and should be
+ /// mapped with -pedantic, -Werror, etc.
+ mutable unsigned char DiagMappings[diag::DIAG_UPPER_LIMIT/2];
+
+ /// ErrorOccurred / FatalErrorOccurred - This is set to true when an error or
+ /// fatal error is emitted, and is sticky.
+ bool ErrorOccurred;
+ bool FatalErrorOccurred;
+
+ /// LastDiagLevel - This is the level of the last diagnostic emitted. This is
+ /// used to emit continuation diagnostics with the same level as the
+ /// diagnostic that they follow.
+ Diagnostic::Level LastDiagLevel;
+
+ unsigned NumDiagnostics; // Number of diagnostics reported
+ unsigned NumErrors; // Number of diagnostics that are errors
+
+ /// CustomDiagInfo - Information for uniquing and looking up custom diags.
+ diag::CustomDiagInfo *CustomDiagInfo;
+
+ /// ArgToStringFn - A function pointer that converts an opaque diagnostic
+ /// argument to a strings. This takes the modifiers and argument that was
+ /// present in the diagnostic.
+ /// This is a hack to avoid a layering violation between libbasic and libsema.
+ typedef void (*ArgToStringFnTy)(ArgumentKind Kind, intptr_t Val,
+ const char *Modifier, unsigned ModifierLen,
+ const char *Argument, unsigned ArgumentLen,
+ llvm::SmallVectorImpl<char> &Output,
+ void *Cookie);
+ void *ArgToStringCookie;
+ ArgToStringFnTy ArgToStringFn;
+public:
+ explicit Diagnostic(DiagnosticClient *client = 0);
+ ~Diagnostic();
+
+ //===--------------------------------------------------------------------===//
+ // Diagnostic characterization methods, used by a client to customize how
+ //
+
+ DiagnosticClient *getClient() { return Client; };
+ const DiagnosticClient *getClient() const { return Client; };
+
+ void setClient(DiagnosticClient* client) { Client = client; }
+
+ /// setIgnoreAllWarnings - When set to true, any unmapped warnings are
+ /// ignored. If this and WarningsAsErrors are both set, then this one wins.
+ void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }
+ bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; }
+
+ /// setWarningsAsErrors - When set to true, any warnings reported are issued
+ /// as errors.
+ void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; }
+ bool getWarningsAsErrors() const { return WarningsAsErrors; }
+
+ /// setSuppressSystemWarnings - When set to true mask warnings that
+ /// come from system headers.
+ void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; }
+ bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; }
+
+ /// setExtensionHandlingBehavior - This controls whether otherwise-unmapped
+ /// extension diagnostics are mapped onto ignore/warning/error. This
+ /// corresponds to the GCC -pedantic and -pedantic-errors option.
+ void setExtensionHandlingBehavior(ExtensionHandling H) {
+ ExtBehavior = H;
+ }
+
+ /// AllExtensionsSilenced - This is a counter bumped when an __extension__
+ /// block is encountered. When non-zero, all extension diagnostics are
+ /// entirely silenced, no matter how they are mapped.
+ void IncrementAllExtensionsSilenced() { ++AllExtensionsSilenced; }
+ void DecrementAllExtensionsSilenced() { --AllExtensionsSilenced; }
+
+ /// setDiagnosticMapping - This allows the client to specify that certain
+ /// warnings are ignored. Notes can never be mapped, errors can only be
+ /// mapped to fatal, and WARNINGs and EXTENSIONs can be mapped arbitrarily.
+ void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map) {
+ assert(Diag < diag::DIAG_UPPER_LIMIT &&
+ "Can only map builtin diagnostics");
+ assert((isBuiltinWarningOrExtension(Diag) || Map == diag::MAP_FATAL) &&
+ "Cannot map errors!");
+ setDiagnosticMappingInternal(Diag, Map, true);
+ }
+
+ /// 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(const char *Group, diag::Mapping Map);
+
+ bool hasErrorOccurred() const { return ErrorOccurred; }
+ bool hasFatalErrorOccurred() const { return FatalErrorOccurred; }
+
+ unsigned getNumErrors() const { return NumErrors; }
+ unsigned getNumDiagnostics() const { return NumDiagnostics; }
+
+ /// 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, const char *Message);
+
+
+ /// ConvertArgToString - This method converts a diagnostic argument (as an
+ /// intptr_t) into the string that represents it.
+ void ConvertArgToString(ArgumentKind Kind, intptr_t Val,
+ const char *Modifier, unsigned ModLen,
+ const char *Argument, unsigned ArgLen,
+ llvm::SmallVectorImpl<char> &Output) const {
+ ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen, Output,
+ ArgToStringCookie);
+ }
+
+ void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) {
+ ArgToStringFn = Fn;
+ ArgToStringCookie = Cookie;
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Diagnostic classification and reporting interfaces.
+ //
+
+ /// getDescription - Given a diagnostic ID, return a description of the
+ /// issue.
+ const char *getDescription(unsigned DiagID) const;
+
+ /// isNoteWarningOrExtension - 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 Determine whether the given built-in diagnostic ID is a
+ /// Note.
+ static bool isBuiltinNote(unsigned DiagID);
+
+ /// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
+ /// ID is for an extension of some sort.
+ ///
+ static bool isBuiltinExtensionDiag(unsigned DiagID);
+
+ /// 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 const char *getWarningOptionForDiag(unsigned DiagID);
+
+ /// getDiagnosticLevel - Based on the way the client configured the Diagnostic
+ /// object, classify the specified diagnostic ID into a Level, consumable by
+ /// the DiagnosticClient.
+ Level getDiagnosticLevel(unsigned DiagID) const;
+
+ /// Report - Issue the message to the client. @c DiagID is a member of the
+ /// @c diag::kind enum. This actually returns aninstance of DiagnosticBuilder
+ /// which emits the diagnostics (through @c ProcessDiag) when it is destroyed.
+ /// @c Pos represents the source location associated with the diagnostic,
+ /// which can be an invalid location if no position information is available.
+ inline DiagnosticBuilder Report(FullSourceLoc Pos, unsigned DiagID);
+
+ /// \brief Clear out the current diagnostic.
+ void Clear() { CurDiagID = ~0U; }
+
+private:
+ /// 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.
+ unsigned getDiagnosticMappingInfo(diag::kind Diag) const {
+ return (diag::Mapping)((DiagMappings[Diag/2] >> (Diag & 1)*4) & 15);
+ }
+
+ void setDiagnosticMappingInternal(unsigned DiagId, unsigned Map,
+ bool isUser) const {
+ if (isUser) Map |= 8; // Set the high bit for user mappings.
+ unsigned char &Slot = DiagMappings[DiagId/2];
+ unsigned Shift = (DiagId & 1)*4;
+ Slot &= ~(15 << Shift);
+ Slot |= Map << Shift;
+ }
+
+ /// getDiagnosticLevel - This is an internal implementation helper used when
+ /// DiagClass is already known.
+ Level getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const;
+
+ // 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
+ // diagnostic "in flight" at a time, but this seems to be a reasonable
+ // tradeoff to keep these objects small. Assertions verify that only one
+ // diagnostic is in flight at a time.
+ friend class DiagnosticBuilder;
+ friend class DiagnosticInfo;
+
+ /// CurDiagLoc - This is the location of the current diagnostic that is in
+ /// flight.
+ FullSourceLoc CurDiagLoc;
+
+ /// CurDiagID - This is the ID of the current diagnostic that is in flight.
+ /// This is set to ~0U when there is no diagnostic in flight.
+ unsigned CurDiagID;
+
+ enum {
+ /// MaxArguments - The maximum number of arguments we can hold. We 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
+ };
+
+ /// NumDiagArgs - This contains the number of entries in Arguments.
+ signed char NumDiagArgs;
+ /// NumRanges - This is the number of ranges in the DiagRanges array.
+ unsigned char NumDiagRanges;
+ /// \brief The number of code modifications hints in the
+ /// CodeModificationHints array.
+ unsigned char NumCodeModificationHints;
+
+ /// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum
+ /// values, with one for each argument. This specifies whether the argument
+ /// is in DiagArgumentsStr or in DiagArguments.
+ unsigned char DiagArgumentsKind[MaxArguments];
+
+ /// DiagArgumentsStr - This holds the values of each string argument for the
+ /// current diagnostic. This value is only used when the corresponding
+ /// ArgumentKind is ak_std_string.
+ std::string DiagArgumentsStr[MaxArguments];
+
+ /// DiagArgumentsVal - The values for the various substitution positions. This
+ /// is used when the argument is not an std::string. The specific value is
+ /// mangled into an intptr_t and the intepretation depends on exactly what
+ /// sort of argument kind it is.
+ intptr_t DiagArgumentsVal[MaxArguments];
+
+ /// DiagRanges - The list of ranges added to this diagnostic. It currently
+ /// only support 10 ranges, could easily be extended if needed.
+ const SourceRange *DiagRanges[10];
+
+ enum { MaxCodeModificationHints = 3 };
+
+ /// CodeModificationHints - If valid, provides a hint with some code
+ /// to insert, remove, or modify at a particular position.
+ CodeModificationHint CodeModificationHints[MaxCodeModificationHints];
+
+ /// ProcessDiag - This is the method used to report a diagnostic that is
+ /// finally fully formed.
+ void ProcessDiag();
+};
+
+//===----------------------------------------------------------------------===//
+// DiagnosticBuilder
+//===----------------------------------------------------------------------===//
+
+/// 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
+/// destroyed, the diagnostic is issued.
+///
+/// Note that many of these will be created as temporary objects (many call
+/// sites), so we want them to be small and we never want their address taken.
+/// This ensures that compilers with somewhat reasonable optimizers will promote
+/// the common fields to registers, eliminating increments of the NumArgs field,
+/// for example.
+class DiagnosticBuilder {
+ mutable Diagnostic *DiagObj;
+ mutable unsigned NumArgs, NumRanges, NumCodeModificationHints;
+
+ void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT
+ friend class Diagnostic;
+ explicit DiagnosticBuilder(Diagnostic *diagObj)
+ : DiagObj(diagObj), NumArgs(0), NumRanges(0),
+ NumCodeModificationHints(0) {}
+
+public:
+ /// Copy constructor. When copied, this "takes" the diagnostic info from the
+ /// input and neuters it.
+ DiagnosticBuilder(const DiagnosticBuilder &D) {
+ DiagObj = D.DiagObj;
+ D.DiagObj = 0;
+ NumArgs = D.NumArgs;
+ NumRanges = D.NumRanges;
+ NumCodeModificationHints = D.NumCodeModificationHints;
+ }
+
+ /// \brief Force the diagnostic builder to emit the diagnostic now.
+ ///
+ /// Once this function has been called, the DiagnosticBuilder object
+ /// should not be used again before it is destroyed.
+ void Emit() {
+ // If DiagObj is null, then its soul was stolen by the copy ctor
+ // or the user called Emit().
+ if (DiagObj == 0) return;
+
+ // When emitting diagnostics, we set the final argument count into
+ // the Diagnostic object.
+ DiagObj->NumDiagArgs = NumArgs;
+ DiagObj->NumDiagRanges = NumRanges;
+ DiagObj->NumCodeModificationHints = NumCodeModificationHints;
+
+ // Process the diagnostic, sending the accumulated information to the
+ // DiagnosticClient.
+ DiagObj->ProcessDiag();
+
+ // Clear out the current diagnostic object.
+ DiagObj->Clear();
+
+ // This diagnostic is dead.
+ DiagObj = 0;
+ }
+
+ /// Destructor - The dtor emits the diagnostic if it hasn't already
+ /// been emitted.
+ ~DiagnosticBuilder() { Emit(); }
+
+ /// Operator bool: conversion of DiagnosticBuilder to bool always returns
+ /// true. This allows is to be used in boolean error contexts like:
+ /// return Diag(...);
+ operator bool() const { return true; }
+
+ void AddString(const std::string &S) const {
+ assert(NumArgs < Diagnostic::MaxArguments &&
+ "Too many arguments to diagnostic!");
+ DiagObj->DiagArgumentsKind[NumArgs] = Diagnostic::ak_std_string;
+ DiagObj->DiagArgumentsStr[NumArgs++] = S;
+ }
+
+ void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const {
+ assert(NumArgs < Diagnostic::MaxArguments &&
+ "Too many arguments to diagnostic!");
+ DiagObj->DiagArgumentsKind[NumArgs] = Kind;
+ DiagObj->DiagArgumentsVal[NumArgs++] = V;
+ }
+
+ void AddSourceRange(const SourceRange &R) const {
+ assert(NumRanges <
+ sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) &&
+ "Too many arguments to diagnostic!");
+ DiagObj->DiagRanges[NumRanges++] = &R;
+ }
+
+ void AddCodeModificationHint(const CodeModificationHint &Hint) const {
+ assert(NumCodeModificationHints < Diagnostic::MaxCodeModificationHints &&
+ "Too many code modification hints!");
+ DiagObj->CodeModificationHints[NumCodeModificationHints++] = Hint;
+ }
+};
+
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const std::string &S) {
+ DB.AddString(S);
+ return DB;
+}
+
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const char *Str) {
+ DB.AddTaggedVal(reinterpret_cast<intptr_t>(Str),
+ Diagnostic::ak_c_string);
+ return DB;
+}
+
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, int I) {
+ DB.AddTaggedVal(I, Diagnostic::ak_sint);
+ return DB;
+}
+
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,bool I) {
+ DB.AddTaggedVal(I, Diagnostic::ak_sint);
+ return DB;
+}
+
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ unsigned I) {
+ DB.AddTaggedVal(I, Diagnostic::ak_uint);
+ return DB;
+}
+
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const IdentifierInfo *II) {
+ DB.AddTaggedVal(reinterpret_cast<intptr_t>(II),
+ Diagnostic::ak_identifierinfo);
+ return DB;
+}
+
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const SourceRange &R) {
+ DB.AddSourceRange(R);
+ return DB;
+}
+
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const CodeModificationHint &Hint) {
+ DB.AddCodeModificationHint(Hint);
+ return 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(FullSourceLoc Loc, unsigned DiagID){
+ assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!");
+ CurDiagLoc = Loc;
+ CurDiagID = DiagID;
+ return DiagnosticBuilder(this);
+}
+
+//===----------------------------------------------------------------------===//
+// DiagnosticInfo
+//===----------------------------------------------------------------------===//
+
+/// 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;
+public:
+ explicit DiagnosticInfo(const Diagnostic *DO) : DiagObj(DO) {}
+
+ const Diagnostic *getDiags() const { return DiagObj; }
+ unsigned getID() const { return DiagObj->CurDiagID; }
+ const FullSourceLoc &getLocation() const { return DiagObj->CurDiagLoc; }
+
+ unsigned getNumArgs() const { return DiagObj->NumDiagArgs; }
+
+ /// 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 {
+ assert(Idx < getNumArgs() && "Argument index out of range!");
+ return (Diagnostic::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 &&
+ "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 &&
+ "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 &&
+ "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 &&
+ "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 &&
+ "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 &&
+ "invalid argument accessor!");
+ return DiagObj->DiagArgumentsVal[Idx];
+ }
+
+
+ /// getNumRanges - Return the number of source ranges associated with this
+ /// diagnostic.
+ unsigned getNumRanges() const {
+ return DiagObj->NumDiagRanges;
+ }
+
+ const SourceRange &getRange(unsigned Idx) const {
+ assert(Idx < DiagObj->NumDiagRanges && "Invalid diagnostic range index!");
+ return *DiagObj->DiagRanges[Idx];
+ }
+
+ unsigned getNumCodeModificationHints() const {
+ return DiagObj->NumCodeModificationHints;
+ }
+
+ const CodeModificationHint &getCodeModificationHint(unsigned Idx) const {
+ return DiagObj->CodeModificationHints[Idx];
+ }
+
+ const CodeModificationHint *getCodeModificationHints() const {
+ return DiagObj->NumCodeModificationHints?
+ &DiagObj->CodeModificationHints[0] : 0;
+ }
+
+ /// 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;
+};
+
+/// DiagnosticClient - This is an abstract interface implemented by clients of
+/// the front-end, which formats and prints fully processed diagnostics.
+class DiagnosticClient {
+public:
+ virtual ~DiagnosticClient();
+
+ /// setLangOptions - This is set by clients of diagnostics when they know the
+ /// language parameters of the diagnostics that may be sent through. Note
+ /// that this can change over time if a DiagClient has multiple languages sent
+ /// through it. It may also be set to null (e.g. when processing command line
+ /// options).
+ virtual void setLangOptions(const LangOptions *LO) {}
+
+ /// 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.
+ 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) = 0;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/Diagnostic.td b/include/clang/Basic/Diagnostic.td
new file mode 100644
index 000000000000..67d8eaafc9ec
--- /dev/null
+++ b/include/clang/Basic/Diagnostic.td
@@ -0,0 +1,73 @@
+//===--- Diagnostic.td - C Language Family Diagnostic Handling ------------===//
+//
+// 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 TableGen core definitions for the diagnostics
+// and diagnostic control.
+//
+//===----------------------------------------------------------------------===//
+
+// Define the diagnostic mappings.
+class DiagMapping;
+def MAP_IGNORE : DiagMapping;
+def MAP_WARNING : DiagMapping;
+def MAP_ERROR : DiagMapping;
+def MAP_FATAL : DiagMapping;
+
+// Define the diagnostic classes.
+class DiagClass;
+def CLASS_NOTE : DiagClass;
+def CLASS_WARNING : DiagClass;
+def CLASS_EXTENSION : DiagClass;
+def CLASS_ERROR : DiagClass;
+
+// Diagnostic Groups.
+class DiagGroup<string Name, list<DiagGroup> subgroups = []> {
+ string GroupName = Name;
+ list<DiagGroup> SubGroups = subgroups;
+}
+class InGroup<DiagGroup G> { DiagGroup Group = G; }
+//class IsGroup<string Name> { DiagGroup Group = DiagGroup<Name>; }
+
+
+// This defines the diagnostic groups that have references to them.
+include "DiagnosticGroups.td"
+
+
+// All diagnostics emitted by the compiler are an indirect subclass of this.
+class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> {
+ /// Component is specified by the file with a big let directive.
+ string Component = ?;
+ string Text = text;
+ DiagClass Class = DC;
+ DiagMapping DefaultMapping = defaultmapping;
+ DiagGroup Group;
+}
+
+class Error<string str> : Diagnostic<str, CLASS_ERROR, MAP_ERROR>;
+class Warning<string str> : Diagnostic<str, CLASS_WARNING, MAP_WARNING>;
+class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_IGNORE>;
+class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_WARNING>;
+class Note<string str> : Diagnostic<str, CLASS_NOTE, MAP_FATAL/*ignored*/>;
+
+
+class DefaultIgnore { DiagMapping DefaultMapping = MAP_IGNORE; }
+class DefaultWarn { DiagMapping DefaultMapping = MAP_WARNING; }
+class DefaultError { DiagMapping DefaultMapping = MAP_ERROR; }
+class DefaultFatal { DiagMapping DefaultMapping = MAP_FATAL; }
+
+// Definitions for Diagnostics.
+include "DiagnosticASTKinds.td"
+include "DiagnosticAnalysisKinds.td"
+include "DiagnosticCommonKinds.td"
+include "DiagnosticDriverKinds.td"
+include "DiagnosticFrontendKinds.td"
+include "DiagnosticLexKinds.td"
+include "DiagnosticParseKinds.td"
+include "DiagnosticSemaKinds.td"
+
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
new file mode 100644
index 000000000000..f075aaaf422f
--- /dev/null
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -0,0 +1,29 @@
+//==--- DiagnosticASTKinds.td - libast diagnostics ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+let Component = "AST" in {
+
+//def note_comma_in_ice : Note<
+// "C does not permit evaluated commas in an integer constant expression">;
+def note_expr_divide_by_zero : Note<"division by zero">;
+
+// inline asm related.
+def err_asm_invalid_escape : Error<
+ "invalid %% escape in inline assembly string">;
+def err_asm_unknown_symbolic_operand_name : Error<
+ "unknown symbolic operand name in inline assembly string">;
+
+def err_asm_unterminated_symbolic_operand_name : Error<
+ "unterminated symbolic operand name in inline assembly string">;
+def err_asm_empty_symbolic_operand_name : Error<
+ "empty symbolic operand name in inline assembly string">;
+def err_asm_invalid_operand_number : Error<
+ "invalid operand number in inline asm string">;
+
+}
diff --git a/include/clang/Basic/DiagnosticAnalysisKinds.td b/include/clang/Basic/DiagnosticAnalysisKinds.td
new file mode 100644
index 000000000000..46dc0e60a7eb
--- /dev/null
+++ b/include/clang/Basic/DiagnosticAnalysisKinds.td
@@ -0,0 +1,15 @@
+//==--- DiagnosticAnalysisKinds.td - libanalysis diagnostics --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+let Component = "Analysis" in {
+
+// CHECK: use of uninitialized values
+def warn_uninit_val : Warning<"use of uninitialized variable">;
+
+}
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
new file mode 100644
index 000000000000..e059d5e60520
--- /dev/null
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -0,0 +1,58 @@
+//==--- DiagnosticCommonKinds.td - common diagnostics ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Common Helpers
+//===----------------------------------------------------------------------===//
+
+let Component = "Common" in {
+
+def note_previous_definition : Note<"previous definition is here">;
+def note_previous_declaration : Note<"previous declaration is here">;
+def note_previous_implicit_declaration : Note<
+ "previous implicit declaration is here">;
+def note_previous_use : Note<"previous use is here">;
+def note_duplicate_case_prev : Note<"previous case defined here">;
+def note_forward_declaration : Note<"forward declaration of %0">;
+def note_type_being_defined : Note<
+ "definition of %0 is not complete until the closing '}'">;
+/// note_matching - this is used as a continuation of a previous diagnostic,
+/// e.g. to specify the '(' when we expected a ')'.
+def note_matching : Note<"to match this '%0'">;
+
+def note_using_decl : Note<"using">;
+def note_also_found_decl : Note<"also found">;
+
+// Parse && Lex
+def err_expected_colon : Error<"expected ':'">;
+
+// Parse && Sema
+def err_no_declarators : Error<"declaration does not declare anything">;
+def err_param_redefinition : Error<"redefinition of parameter %0">;
+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">;
+
+// Sema && Lex
+def ext_longlong : Extension<
+ "'long long' is an extension when C99 mode is not enabled">;
+def warn_integer_too_large : Warning<
+ "integer constant is too large for its type">;
+def warn_integer_too_large_for_signed : Warning<
+ "integer constant is so large that it is unsigned">;
+
+// Sema && AST
+def note_invalid_subexpr_in_ice : Note<
+ "subexpression not valid in an integer constant expression">;
+
+// clang-cc
+def err_pp_I_dash_not_supported : Error<
+ "-I- not supported, please use -iquote instead">;
+
+}
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
new file mode 100644
index 000000000000..327db00e0b28
--- /dev/null
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -0,0 +1,64 @@
+//==--- DiagnosticDriverKinds.td - libdriver diagnostics ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+let Component = "Driver" in {
+
+def err_drv_no_such_file : Error<"no such file or directory: '%0'">;
+def err_drv_unsupported_opt : Error<"unsupported option '%0'">;
+def err_drv_unknown_stdin_type : Error<
+ "-E or -x required when input is from standard input">;
+def err_drv_unknown_language : Error<"language not recognized: '%0'">;
+def err_drv_invalid_opt_with_multiple_archs : Error<
+ "option '%0' cannot be used with multiple -arch options">;
+def err_drv_invalid_output_with_multiple_archs : Error<
+ "cannot use '%0' output with multiple -arch options">;
+def err_drv_no_input_files : Error<"no input files">;
+def err_drv_use_of_Z_option : Error<
+ "unsupported use of internal gcc -Z option '%0'">;
+def err_drv_output_argument_with_multiple_files : Error<
+ "cannot specify -o when generating multiple output files">;
+def err_drv_unable_to_make_temp : Error<
+ "unable to make temporary file: %0">;
+def err_drv_unable_to_remove_file : Error<
+ "unable to remove file: %0">;
+def err_drv_command_failure : Error<
+ "unable to execute command: %0">;
+def err_drv_invalid_darwin_version : Error<
+ "invalid Darwin version number: %0">;
+def err_drv_missing_argument : Error<
+ "argument to '%0' is missing (expected %1 %plural{1:value|:values}1)">;
+def err_drv_invalid_Xarch_argument : Error<
+ "invalid Xarch argument: '%0'">;
+def err_drv_argument_only_allowed_with : Error<
+ "invalid argument '%0' only allowed with '%1'">;
+def err_drv_argument_not_allowed_with : Error<
+ "invalid argument '%0' not allowed with '%1'">;
+def err_drv_invalid_version_number : Error<
+ "invalid version number in '%0'">;
+def err_drv_no_linker_llvm_support : Error<
+ "'%0': unable to pass LLVM bit-code files to linker">;
+def err_drv_clang_unsupported : Error<
+ "the clang compiler does not support '%0'">;
+
+def warn_drv_input_file_unused : Warning<
+ "%0: '%1' input unused when '%2' is present">;
+def warn_drv_unused_argument : Warning<
+ "argument unused during compilation: '%0'">;
+def warn_drv_pipe_ignored_with_save_temps : Warning<
+ "-pipe ignored because -save-temps specified">;
+def warn_drv_not_using_clang_cpp : Warning<
+ "not using the clang prepreprocessor due to user override">;
+def warn_drv_not_using_clang_cxx : Warning<
+ "not using the clang compiler for C++ inputs">;
+def warn_drv_not_using_clang_arch : Warning<
+ "not using the clang compiler for the '%0' architecture">;
+def warn_drv_clang_unsupported : Warning<
+ "the clang compiler does not support '%0'">;
+
+}
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
new file mode 100644
index 000000000000..1bc296babd3b
--- /dev/null
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -0,0 +1,136 @@
+//==--- DiagnosticFrontendKinds.td - frontend diagnostics -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+let Component = "Frontend" in {
+
+def err_fe_unknown_triple : Error<
+ "unknown target triple '%0', please use -triple or -arch">;
+def err_fe_error_reading : Error<"error reading '%0'">;
+def err_fe_error_reading_stdin : Error<"error reading stdin">;
+
+def note_fixit_applied : Note<"FIX-IT applied suggested code changes">;
+def note_fixit_in_macro : Note<
+ "FIX-IT unable to apply suggested code changes in a macro">;
+def note_fixit_failed : Note<
+ "FIX-IT unable to apply suggested code changes">;
+def note_fixit_unfixed_error : Note<"FIX-IT detected an error it cannot fix">;
+def warn_fixit_no_changes : Note<
+ "FIX-IT detected errors it could not fix; no output will be generated">;
+
+// PCH reader
+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_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_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_microsoft_extensions : Error<
+ "Microsoft extensions were %select{disabled|enabled}0 in PCH file but are "
+ "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_exceptions : Error<
+ "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_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_overflow_checking : Error<
+ "signed integer overflow checking was %select{disabled|enabled}0 in PCH "
+ "file but is currently %select{disabled|enabled}1">;
+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_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 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<
+ "PCH file uses a newer PCH format that cannot be read">;
+def warn_cmdline_conflicting_macro_def : Error<
+ "definition of the macro '%0' conflicts with the definition used to "
+ "build the precompiled header">;
+def note_pch_macro_defined_as : Note<
+ "definition of macro '%0' in the precompiled header">;
+def warn_cmdline_missing_macro_defs : Warning<
+ "macro definitions used to build the precompiled header are missing">;
+def note_using_macro_def_from_pch : Note<
+ "using this macro definition from precompiled header">;
+def warn_macro_name_used_in_pch : Error<
+ "definition of macro %0 conflicts with an identifier used in the "
+ "precompiled header">;
+def warn_pch_compiler_options_mismatch : Error<
+ "compiler options used when building the precompiled header differ from "
+ "the options used when using the precompiled header">;
+def 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 err_not_a_pch_file : Error<
+ "'%0' does not appear to be a precompiled header file">, DefaultFatal;
+}
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
new file mode 100644
index 000000000000..700826fa658f
--- /dev/null
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -0,0 +1,133 @@
+//==--- DiagnosticGroups.td - Diagnostic Group Definitions ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+def ImplicitFunctionDeclare : DiagGroup<"implicit-function-declaration">;
+def ImplicitInt : DiagGroup<"implicit-int">;
+
+// Aggregation warning settings.
+def Implicit : DiagGroup<"implicit", [
+ ImplicitFunctionDeclare,
+ ImplicitInt
+]>;
+
+
+
+// Empty DiagGroups: these are recognized by clang but ignored.
+def : DiagGroup<"aggregate-return">;
+def : DiagGroup<"bad-function-cast">;
+def : DiagGroup<"cast-align">;
+def : DiagGroup<"cast-qual">;
+def : DiagGroup<"char-align">;
+def : DiagGroup<"char-subscripts">;
+def Comment : DiagGroup<"comment">;
+def : DiagGroup<"conversion">;
+def : DiagGroup<"declaration-after-statement">;
+def : DiagGroup<"disabled-optimization">;
+def : DiagGroup<"discard-qual">;
+def ExtraTokens : DiagGroup<"extra-tokens">;
+
+def FormatExtraArgs : DiagGroup<"format-extra-args">;
+def FormatZeroLength : DiagGroup<"format-zero-length">;
+
+def FourByteMultiChar : DiagGroup<"four-char-constants">;
+def : DiagGroup<"init-self">;
+def : DiagGroup<"inline">;
+def : DiagGroup<"int-to-pointer-cast">;
+def : DiagGroup<"missing-braces">;
+def : DiagGroup<"missing-declarations">;
+def : DiagGroup<"missing-format-attribute">;
+def : DiagGroup<"missing-noreturn">;
+def MultiChar : DiagGroup<"multichar">;
+def : DiagGroup<"nested-externs">;
+def : DiagGroup<"newline-eof">;
+def : DiagGroup<"long-long">;
+def MismatchedTags : DiagGroup<"mismatched-tags">;
+def : DiagGroup<"missing-field-initializers">;
+def NonNull : DiagGroup<"nonnull">;
+def : DiagGroup<"nonportable-cfstrings">;
+def : DiagGroup<"old-style-definition">;
+def : DiagGroup<"packed">;
+def Parentheses : DiagGroup<"parentheses">;
+def : DiagGroup<"pointer-arith">;
+def : DiagGroup<"pointer-to-int-cast">;
+def : DiagGroup<"redundant-decls">;
+def ReturnType : DiagGroup<"return-type">;
+def : DiagGroup<"sequence-point">;
+def : DiagGroup<"shadow">;
+def : DiagGroup<"shorten-64-to-32">;
+def : DiagGroup<"sign-compare">;
+
+// Just silence warnings about common forms of -Wstrict-aliasing for now.
+def : DiagGroup<"strict-aliasing=0">;
+def : DiagGroup<"strict-aliasing=1">;
+def : DiagGroup<"strict-aliasing=2">;
+def : DiagGroup<"strict-aliasing">;
+
+// Just silence warnings about common forms of -Wstrict-aliasing for now.
+def : DiagGroup<"strict-overflow=0">;
+def : DiagGroup<"strict-overflow=1">;
+def : DiagGroup<"strict-overflow=2">;
+def : DiagGroup<"strict-overflow">;
+
+def InvalidOffsetof : DiagGroup<"invalid-offsetof">;
+def : DiagGroup<"strict-prototypes">;
+def : DiagGroup<"strict-selector-match">;
+def Switch : DiagGroup<"switch">;
+def Trigraphs : DiagGroup<"trigraphs">;
+
+def : DiagGroup<"type-limits">;
+def Uninitialized : DiagGroup<"uninitialized">;
+def UnknownPragmas : DiagGroup<"unknown-pragmas">;
+def : DiagGroup<"unused-function">;
+def : DiagGroup<"unused-label">;
+def : DiagGroup<"unused-parameter">;
+def UnusedValue : DiagGroup<"unused-value">;
+def UnusedVariable : DiagGroup<"unused-variable">;
+def : DiagGroup<"variadic-macros">;
+def VectorConversions : DiagGroup<"vector-conversions">; // clang specific
+def VolatileRegisterVar : DiagGroup<"volatile-register-var">;
+def : DiagGroup<"write-strings">;
+
+// Aggregation warning settings.
+
+
+// Format settings.
+def Format : DiagGroup<"format", [FormatExtraArgs, FormatZeroLength, NonNull]>;
+def FormatSecurity : DiagGroup<"format-security", [Format]>;
+def FormatNonLiteral : DiagGroup<"format-nonliteral", [FormatSecurity]>;
+def FormatY2K : DiagGroup<"format-y2k", [Format]>;
+def Format2 : DiagGroup<"format=2",
+ [FormatNonLiteral, FormatSecurity, FormatY2K]>;
+
+
+def Extra : DiagGroup<"extra">;
+
+def Most : DiagGroup<"most", [
+ Comment,
+ Format,
+ Implicit,
+ MismatchedTags,
+ MultiChar,
+ Switch,
+ Trigraphs,
+ Uninitialized,
+ UnknownPragmas,
+ UnusedValue,
+ UnusedVariable,
+ VectorConversions,
+ VolatileRegisterVar
+ ]>;
+
+// -Wall is -Wmost -Wparentheses
+def : DiagGroup<"all", [Most, Parentheses]>;
+
+// Aliases.
+def : DiagGroup<"", [Extra]>; // -W = -Wextra
+def : DiagGroup<"endif-labels", [ExtraTokens]>; // endif-labels = endif-tokens
+
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
new file mode 100644
index 000000000000..3d1f9320cd41
--- /dev/null
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -0,0 +1,277 @@
+//==--- DiagnosticLexKinds.td - liblex diagnostics ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Lexer Diagnostics
+//===----------------------------------------------------------------------===//
+
+let Component = "Lex" in {
+
+def null_in_string : Warning<"null character(s) preserved in string literal">;
+def null_in_char : Warning<"null character(s) preserved in character literal">;
+def null_in_file : Warning<"null character ignored">;
+def warn_nested_block_comment : Warning<"'/*' within block comment">,
+ InGroup<Comment>;
+def escaped_newline_block_comment_end : Warning<
+ "escaped newline between */ characters at block comment end">,
+ InGroup<Comment>;
+def backslash_newline_space : Warning<
+ "backslash and newline separated by space">;
+
+// Trigraphs.
+def trigraph_ignored : Warning<"trigraph ignored">, InGroup<Trigraphs>;
+def trigraph_ignored_block_comment : Warning<
+ "ignored trigraph would end block comment">, InGroup<Trigraphs>;
+def trigraph_ends_block_comment : Warning<"trigraph ends block comment">,
+ InGroup<Trigraphs>;
+def trigraph_converted : Warning<"trigraph converted to '%0' character">,
+ InGroup<Trigraphs>;
+
+def ext_multi_line_bcpl_comment : Extension<"multi-line // comment">,
+ InGroup<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_dollar_in_identifier : Extension<"'$' in identifier">;
+def charize_microsoft_ext : Extension<"@# is a microsoft extension">;
+
+def ext_token_used : Extension<"extension used">;
+
+def err_unterminated_string : Error<"missing terminating '\"' character">;
+def err_unterminated_char : Error<"missing terminating ' character">;
+def err_empty_character : Error<"empty character constant">;
+def err_unterminated_block_comment : Error<"unterminated /* comment">;
+def err_invalid_character_to_charify : Error<
+ "invalid argument to convert to character">;
+def ext_multichar_character_literal : ExtWarn<
+ "multi-character character constant">, InGroup<MultiChar>;
+def ext_four_char_character_literal : Extension<
+ "multi-character character constant">, InGroup<FourByteMultiChar>;
+
+
+// Literal
+def ext_nonstandard_escape : Extension<
+ "use of non-standard escape character '\\%0'">;
+def ext_unknown_escape : ExtWarn<"unknown escape sequence '\\%0'">;
+def err_hex_escape_no_digits : Error<"\\x used with no following hex digits">;
+def err_ucn_escape_no_digits : Error<"\\u used with no following hex digits">;
+def err_ucn_escape_invalid : Error<"invalid universal character">;
+def err_ucn_escape_incomplete : Error<"incomplete universal character name">;
+def err_ucn_escape_too_big : Error<"universal character name is too long">;
+def err_invalid_decimal_digit : Error<"invalid digit '%0' in decimal constant">;
+def err_invalid_binary_digit : Error<"invalid digit '%0' in binary constant">;
+def err_invalid_octal_digit : Error<"invalid digit '%0' in octal constant">;
+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_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_invalid : Extension<
+ "hexadecimal floating constants are a C99 feature">;
+def ext_binary_literal : Extension<
+ "binary integer literals are an extension">;
+def err_pascal_string_too_long : Error<"Pascal string is too long">;
+def warn_octal_escape_too_large : ExtWarn<"octal escape sequence out of range">;
+def warn_hex_escape_too_large : ExtWarn<"hex escape sequence out of range">;
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Diagnostics
+//===----------------------------------------------------------------------===//
+def pp_hash_warning : Warning<"#warning%0">, InGroup<DiagGroup<"#warnings">>;
+def pp_include_next_in_primary : Warning<
+ "#include_next in primary source file">;
+def pp_include_macros_out_of_predefines : Error<
+ "the #__include_macros directive is only for internal use by -imacros">;
+def pp_include_next_absolute_path : Warning<"#include_next with absolute path">;
+def ext_c99_whitespace_required_after_macro_name : ExtWarn<
+ "ISO C99 requires whitespace after the macro name">;
+def ext_missing_whitespace_after_macro_name : ExtWarn<
+ "whitespace required after macro name">;
+def warn_missing_whitespace_after_macro_name : Warning<
+ "whitespace recommended after macro name">;
+
+def pp_pragma_once_in_main_file : Warning<"#pragma once in main file">;
+def pp_pragma_sysheader_in_main_file : Warning<
+ "#pragma system_header ignored in main file">;
+def pp_poisoning_existing_macro : Warning<"poisoning existing macro">;
+def pp_out_of_date_dependency : Warning<
+ "current file is older than dependency %0">;
+def pp_undef_builtin_macro : Warning<"undefining builtin macro">;
+def pp_redef_builtin_macro : Warning<"redefining builtin macro">;
+def pp_macro_not_used : Warning<"macro is not used">, DefaultIgnore,
+ InGroup<DiagGroup<"unused-macros">>;
+def warn_pp_undef_identifier : Warning<
+ "%0 is not defined, evaluates to 0">,
+ InGroup<DiagGroup<"undef">>, DefaultIgnore;
+
+def pp_invalid_string_literal : Warning<
+ "invalid string literal, ignoring final '\\'">;
+def warn_pp_expr_overflow : Warning<
+ "integer overflow in preprocessor expression">;
+def warn_pp_convert_lhs_to_positive : Warning<
+ "left side of operator converted from negative value to unsigned: %0">;
+def warn_pp_convert_rhs_to_positive : Warning<
+ "right side of operator converted from negative value to unsigned: %0">;
+
+def ext_pp_import_directive : Extension<"#import is a language extension">;
+def ext_pp_ident_directive : Extension<"#ident is a language extension">;
+def ext_pp_include_next_directive : Extension<
+ "#include_next is a language extension">;
+def ext_pp_warning_directive : Extension<"#warning is a language extension">;
+
+def ext_pp_extra_tokens_at_eol : ExtWarn<
+ "extra tokens at end of #%0 directive">, InGroup<ExtraTokens>;
+
+def ext_pp_comma_expr : Extension<"comma operator in operand of #if">;
+def ext_pp_bad_vaargs_use : Extension<
+ "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro">;
+def ext_pp_macro_redef : ExtWarn<"%0 macro redefined">;
+def ext_variadic_macro : Extension<"variadic macros were introduced in C99">;
+def ext_named_variadic_macro : Extension<
+ "named variadic macros are a GNU extension">;
+def ext_embedded_directive : Extension<
+ "embedding a directive within macro arguments is not portable">;
+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 ext_pp_base_file : Extension<"__BASE_FILE__ is a language extension">;
+def ext_pp_include_level : Extension<
+ "__INCLUDE_LEVEL__ is a language extension">;
+def ext_pp_timestamp : Extension<"__TIMESTAMP__ is a language extension">;
+def ext_pp_counter : Extension<
+ "__COUNTER__ is a language extension">;
+
+def err_pp_invalid_directive : Error<"invalid preprocessing directive">;
+def err_pp_hash_error : Error<"#error%0">;
+def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal;
+def err_pp_empty_filename : Error<"empty filename">;
+def err_pp_include_too_deep : Error<"#include nested too deeply">;
+def err_pp_expects_filename : Error<"expected \"FILENAME\" or <FILENAME>">;
+def err_pp_macro_not_identifier : Error<"macro names must be identifiers">;
+def err_pp_missing_macro_name : Error<"macro name missing">;
+def err_pp_missing_rparen_in_macro_def : Error<
+ "missing ')' in macro parameter list">;
+def err_pp_invalid_tok_in_arg_list : Error<
+ "invalid token in macro parameter list">;
+def err_pp_expected_ident_in_arg_list : Error<
+ "expected identifier in macro parameter list">;
+def err_pp_expected_comma_in_arg_list : Error<
+ "expected comma in macro parameter list">;
+def err_pp_duplicate_name_in_arg_list : Error<
+ "duplicate macro parameter name %0">;
+def err_pp_stringize_not_parameter : Error<
+ "'#' is not followed by a macro parameter">;
+def err_pp_malformed_ident : Error<"invalid #ident directive">;
+def err_pp_unterminated_conditional : Error<
+ "unterminated conditional directive">;
+def pp_err_else_after_else : Error<"#else after #else">;
+def pp_err_elif_after_else : Error<"#elif after #else">;
+def pp_err_else_without_if : Error<"#else without #if">;
+def pp_err_elif_without_if : Error<"#elif without #if">;
+def err_pp_endif_without_if : Error<"#endif without #if">;
+def err_pp_expected_value_in_expr : Error<"expected value in expression">;
+def err_pp_missing_val_before_operator : Error<"missing value before operator">;
+def err_pp_expected_rparen : Error<"expected ')' in preprocessor expression">;
+def err_pp_expected_eol : Error<
+ "expected end of line in preprocessor expression">;
+def err_pp_defined_requires_identifier : Error<
+ "operator 'defined' requires an identifier">;
+def err_pp_missing_rparen : Error<"missing ')' after 'defined'">;
+def err_pp_colon_without_question : Error<"':' without preceding '?'">;
+def err_pp_division_by_zero : Error<
+ "division by zero in preprocessor expression">;
+def err_pp_remainder_by_zero : Error<
+ "remainder by zero in preprocessor expression">;
+def err_pp_expr_bad_token_binop : Error<
+ "token is not a valid binary operator in a preprocessor subexpression">;
+def err_pp_expr_bad_token_start_expr : Error<
+ "invalid token at start of a preprocessor expression">;
+def err_pp_invalid_poison : Error<"can only poison identifier tokens">;
+def err_pp_used_poisoned_id : Error<"attempt to use a poisoned identifier">;
+def err__Pragma_malformed : Error<
+ "_Pragma takes a parenthesized string literal">;
+def err_pragma_comment_malformed : Error<
+ "pragma comment requires parenthesized identifier and optional string">;
+def warn_pragma_ignored : Warning<"unknown pragma ignored">,
+ InGroup<UnknownPragmas>, DefaultIgnore;
+def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
+ InGroup<UnknownPragmas>;
+def ext_stdc_pragma_syntax :
+ ExtWarn<"expected 'ON' or 'OFF' or 'DEFAULT' in pragma">,
+ InGroup<UnknownPragmas>;
+def ext_stdc_pragma_syntax_eom :
+ ExtWarn<"expected end of macro in STDC pragma">,
+ InGroup<UnknownPragmas>;
+def warn_stdc_fenv_access_not_supported :
+ Warning<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">,
+ InGroup<UnknownPragmas>;
+def warn_pragma_diagnostic_invalid :
+ ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', or"
+ " 'fatal'">,
+ InGroup<UnknownPragmas>;
+def warn_pragma_diagnostic_invalid_option :
+ ExtWarn<"pragma diagnostic expected option name (e.g. \"-Wundef\")">,
+ InGroup<UnknownPragmas>;
+def warn_pragma_diagnostic_invalid_token :
+ ExtWarn<"unexpected token in pragma diagnostic">,
+ InGroup<UnknownPragmas>;
+def warn_pragma_diagnostic_unknown_warning :
+ ExtWarn<"unknown warning group '%0', ignored">,
+ InGroup<UnknownPragmas>;
+
+def err_pragma_comment_unknown_kind : Error<"unknown kind of pragma comment">;
+def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">;
+def err_paste_at_start : Error<
+ "'##' cannot appear at start of macro expansion">;
+def err_paste_at_end : Error<"'##' cannot appear at end of macro expansion">;
+def ext_paste_comma : Extension<
+ "Use of comma pasting extension is non-portable">;
+def err_unterm_macro_invoc : Error<
+ "unterminated function-like macro invocation">;
+def err_too_many_args_in_macro_invoc : Error<
+ "too many arguments provided to function-like macro invocation">;
+def err_too_few_args_in_macro_invoc : Error<
+ "too few arguments provided to function-like macro invocation">;
+def err_pp_bad_paste : Error<
+ "pasting formed '%0', an invalid preprocessing token">;
+def err_pp_operator_used_as_macro_name : Error<
+ "C++ operator '%0' cannot be used as a macro name">;
+def err_pp_illegal_floating_literal : Error<
+ "floating point literal in preprocessor expression">;
+def err_pp_line_requires_integer : Error<
+ "#line directive requires a positive integer argument">;
+def err_pp_line_invalid_filename : Error<
+ "invalid filename for #line directive">;
+def warn_pp_line_decimal : Warning<
+ "#line directive interprets number as decimal, not octal">;
+def err_pp_line_digit_sequence : Error<
+ "#line directive requires a simple digit sequence">;
+def err_pp_linemarker_requires_integer : Error<
+ "line marker directive requires a positive integer argument">;
+def err_pp_linemarker_invalid_filename : Error<
+ "invalid filename for line marker directive">;
+def err_pp_linemarker_invalid_flag : Error<
+ "invalid flag line marker directive">;
+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">;
+
+}
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
new file mode 100644
index 000000000000..2912344e06f8
--- /dev/null
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -0,0 +1,280 @@
+//==--- DiagnosticParseKinds.td - libparse diagnostics --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Parser Diagnostics
+//===----------------------------------------------------------------------===//
+
+let Component = "Parse" in {
+
+def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">;
+
+def ext_empty_source_file : Extension<"ISO C forbids an empty source file">;
+def ext_top_level_semi : Extension<
+ "extra ';' outside of a function">;
+def ext_extra_struct_semi : Extension<
+ "extra ';' inside a struct or union">;
+
+def ext_duplicate_declspec : Extension<"duplicate '%0' declaration specifier">;
+def ext_plain_complex : ExtWarn<
+ "plain '_Complex' requires a type specifier; assuming '_Complex double'">;
+def ext_integer_complex : Extension<
+ "complex integer types are an extension">;
+def ext_thread_before : Extension<"'__thread' before 'static'">;
+
+def ext_empty_struct_union_enum : Extension<"use of empty %0 extension">;
+
+def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">;
+def err_invalid_short_spec : Error<"'short %0' is invalid">;
+def err_invalid_long_spec : Error<"'long %0' is invalid">;
+def err_invalid_longlong_spec : Error<"'long long %0' is invalid">;
+def err_invalid_complex_spec : Error<"'_Complex %0' is invalid">;
+
+def ext_ident_list_in_param : Extension<
+ "type-less parameter names in function declaration">;
+def ext_c99_variable_decl_in_for_loop : Extension<
+ "variable declaration in for loop is a C99-specific feature">;
+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 feature">;
+
+def ext_gnu_indirect_goto : Extension<
+ "use of GNU indirect-goto extension">;
+def ext_gnu_address_of_label : Extension<
+ "use of GNU address-of-label extension">;
+def ext_gnu_statement_expr : Extension<
+ "use of GNU statement expression extension">;
+def ext_gnu_conditional_expr : Extension<
+ "use of GNU ?: expression extension, eliding middle term">;
+def ext_gnu_empty_initializer : Extension<
+ "use of GNU empty initializer extension">;
+def ext_gnu_array_range : Extension<"use of GNU array range extension">;
+def ext_gnu_missing_equal_designator : ExtWarn<
+ "use of GNU 'missing =' extension in designator">;
+def err_expected_equal_designator : Error<"expected '=' or another designator">;
+def ext_gnu_old_style_field_designator : ExtWarn<
+ "use of GNU old-style field designator extension">;
+def ext_gnu_case_range : Extension<"use of GNU case range extension">;
+
+// Generic errors.
+def err_parse_error : Error<"parse error">;
+def err_expected_expression : Error<"expected expression">;
+def err_expected_type : Error<"expected a type">;
+def err_expected_external_declaration : Error<"expected external declaration">;
+def err_expected_ident : Error<"expected identifier">;
+def err_expected_ident_lparen : Error<"expected identifier or '('">;
+def err_expected_ident_lbrace : Error<"expected identifier or '{'">;
+def err_expected_lbrace : Error<"expected '{'">;
+def err_expected_lparen : Error<"expected '('">;
+def err_expected_rparen : Error<"expected ')'">;
+def err_expected_rsquare : Error<"expected ']'">;
+def err_expected_rbrace : Error<"expected '}'">;
+def err_expected_greater : Error<"expected '>'">;
+def err_expected_semi_declation : Error<
+ "expected ';' at end of declaration">;
+def err_expected_semi_decl_list : Error<
+ "expected ';' at end of declaration list">;
+def ext_expected_semi_decl_list : Extension<
+ "expected ';' at end of declaration list">;
+def err_expected_member_name_or_semi : Error<
+ "expected member name or ';' after declaration specifiers">;
+def err_function_declared_typedef : Error<
+ "function definition declared 'typedef'">;
+def err_expected_fn_body : Error<
+ "expected function body after function declarator">;
+def err_expected_method_body : Error<"expected method body">;
+def err_invalid_token_after_toplevel_declarator : Error<
+ "invalid token after top level declarator">;
+def err_expected_statement : Error<"expected statement">;
+def err_expected_lparen_after : Error<"expected '(' after '%0'">;
+def err_expected_lparen_after_id : Error<"expected '(' after %0">;
+def err_expected_less_after : Error<"expected '<' after '%0'">;
+def err_expected_comma : Error<"expected ','">;
+def err_expected_lbrace_in_compound_literal : Error<
+ "expected '{' in compound literal">;
+def err_expected_while : Error<"expected 'while' in do/while loop">;
+def err_expected_semi_after : Error<"expected ';' after %0">;
+def err_expected_semi_after_expr : Error<"expected ';' after expression">;
+def err_expected_semi_after_method_proto : Error<
+ "expected ';' after method prototype">;
+def err_expected_semi_after_static_assert : Error<
+ "expected ';' after static_assert">;
+def err_expected_semi_for : Error<"expected ';' in 'for' statement specifier">;
+def err_expected_colon_after : Error<"expected ':' after %0">;
+def err_label_end_of_compound_statement : Error<
+ "label at end of compound statement: expected statement">;
+def err_expected_string_literal : Error<"expected string literal">;
+def err_expected_asm_operand : Error<
+ "expected string literal or '[' for asm operand">;
+def err_expected_selector_for_method : Error<
+ "expected selector for Objective-C method">;
+
+def err_unexpected_at : Error<"unexpected '@' in program">;
+
+def err_invalid_reference_qualifier_application : Error<
+ "'%0' qualifier may not be applied to a reference">;
+def err_illegal_decl_reference_to_reference : Error<
+ "%0 declared as a reference to a reference">;
+def err_rvalue_reference : Error<
+ "rvalue references are only allowed in C++0x">;
+def err_argument_required_after_attribute : Error<
+ "argument required after attribute">;
+def err_missing_param : Error<"expected parameter declarator">;
+def err_unexpected_typedef_ident : Error<
+ "unexpected type name %0: expected identifier">;
+def err_expected_class_name : Error<"expected class name">;
+def err_unspecified_vla_size_with_static : Error<
+ "'static' may not be used with an unspecified variable length array size">;
+
+// Declarations.
+def err_typename_requires_specqual : Error<
+ "type name requires a specifier or qualifier">;
+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_invalid_decl_spec_combination : Error<
+ "cannot combine with previous '%0' declaration specifier">;
+def err_unknown_typename : Error<
+ "unknown type name %0">;
+def err_use_of_tag_name_without_tag : Error<
+ "use of tagged type %0 without '%1' tag">;
+
+
+/// Objective-C parser diagnostics
+def err_objc_no_attributes_on_category : Error<
+ "attributes may not be specified on a category">;
+def err_objc_missing_end : Error<"missing @end">;
+def warn_objc_protocol_qualifier_missing_id : Warning<
+ "protocol qualifiers without 'id' is archaic">;
+
+def err_objc_illegal_visibility_spec : Error<
+ "illegal visibility specification">;
+def err_objc_illegal_interface_qual : Error<"illegal interface qualifier">;
+def err_objc_expected_equal : Error<
+ "setter/getter expects '=' followed by name">;
+def err_objc_property_requires_field_name : Error<
+ "property requires fields to be named">;
+def err_objc_property_bitfield : Error<"property name cannot be a bitfield">;
+def err_objc_expected_property_attr : Error<"unknown property attribute %0">;
+def err_objc_propertoes_require_objc2 : Error<
+ "properties are an Objective-C 2 feature">;
+def err_objc_unexpected_attr : Error<
+ "prefix attribute must be followed by an interface or protocol">;
+def err_objc_directive_only_in_protocol : Error<
+ "directive may only be specified in protocols only">;
+def err_missing_catch_finally : Error<
+ "@try statement without a @catch and @finally clause">;
+def err_objc_concat_string : Error<"unexpected token after Objective-C string">;
+def err_missing_sel_definition : Error<"cannot find definition of 'SEL'">;
+def err_missing_id_definition : Error<"cannot find definition of 'id'">;
+def err_missing_proto_definition : Error<
+ "cannot find definition of 'Protocol'">;
+def err_missing_class_definition : Error<"cannot find definition of 'Class'">;
+def warn_expected_implementation : Warning<
+ "@end must appear in an @implementation context">;
+def error_property_ivar_decl : Error<
+ "property synthesize requires specification of an ivar">;
+
+def err_expected_field_designator : Error<
+ "expected a field designator, such as '.field = 4'">;
+
+def err_declaration_does_not_declare_param : Error<
+ "declaration does not declare a parameter">;
+def err_no_matching_param : Error<"parameter named %0 is missing">;
+
+/// C++ parser diagnostics
+def err_expected_unqualified_id : Error<"expected unqualified-id">;
+def err_func_def_no_params : Error<
+ "function definition does not declare parameters">;
+def err_expected_lparen_after_type : Error<
+ "expected '(' for function-style cast or type construction">;
+def err_expected_equal_after_declarator : Error<
+ "expected '=' after declarator">;
+def warn_parens_disambiguated_as_function_decl : Warning<
+ "parentheses were disambiguated as a function declarator">;
+def err_expected_member_or_base_name : Error<
+ "expected class member or base class name">;
+def ext_ellipsis_exception_spec : Extension<
+ "exception specification of '...' is a Microsoft extension">;
+def err_expected_catch : Error<"expected catch">;
+def err_expected_lbrace_or_comma : Error<"expected '{' or ','">;
+
+// C++ derived classes
+def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
+
+// C++ operator overloading
+def err_operator_missing_type_specifier : Error<
+ "missing type specifier after 'operator'">;
+
+// Classes.
+def err_anon_type_definition : Error<
+ "declaration of anonymous %0 must be a definition">;
+
+
+/// C++ Templates
+def err_expected_template : Error<"expected template">;
+def err_expected_comma_greater : Error<
+ "expected ',' or '>' in template-parameter-list">;
+def err_expected_type_id_after : Error<"expected type-id after '%0'">;
+def err_expected_class_before : Error<"expected 'class' before '%0'">;
+def err_template_spec_syntax_non_template : Error<
+ "identifier followed by '<' indicates a class template specialization but "
+ "%0 %select{does not refer to a template|refers to a function "
+ "template|<unused>|refers to a template template parameter}1">;
+def err_id_after_template_in_nested_name_spec : Error<
+ "expected template name after 'template' keyword in nested name specifier">;
+def err_id_after_template_in_typename_spec : Error<
+ "expected template name after 'template' keyword in typename specifier">;
+def err_less_after_template_name_in_nested_name_spec : Error<
+ "expected '<' after 'template %0' in nested name specifier">;
+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">;
+def err_multiple_template_declarators : Error<
+ "%select{|a template declaration|an explicit template specialization|"
+ "an explicit template instantiation}0 can "
+ "only %select{|declare|declare|instantiate}0 a single entity">;
+def err_explicit_instantiation_with_definition : Error<
+ "explicit template instantiation cannot have a definition; if this "
+ "definition is meant to be an explicit specialization, add '<>' after the "
+ "'template' keyword">;
+
+def err_expected_qualified_after_typename : Error<
+ "expected a qualified name after 'typename'">;
+def err_typename_refers_to_non_type_template : Error<
+ "typename specifier refers to a non-template">;
+def err_expected_type_name_after_typename : Error<
+ "expected an identifier or template-id after '::'">;
+
+// Language specific pragmas
+// - Generic warnings
+def warn_pragma_expected_lparen : Warning<
+ "missing '(' after '#pragma %0' - ignoring">;
+def warn_pragma_expected_rparen : Warning<
+ "missing ')' after '#pragma %0' - ignoring">;
+def warn_pragma_expected_identifier : Warning<
+ "expected identifier in '#pragma %0' - ignored">;
+// - #pragma pack
+def warn_pragma_pack_invalid_action : Warning<
+ "unknown action for '#pragma pack' - ignored">;
+def warn_pragma_pack_invalid_constant : Warning<
+ "invalid constant for '#pragma pack', expected %0 - ignored">;
+def warn_pragma_pack_malformed : Warning<
+ "expected integer or identifier in '#pragma pack' - ignored">;
+// - #pragma unused
+def warn_pragma_unused_expected_var : Warning<
+ "expected '#pragma unused' argument to be a variable name">;
+def warn_pragma_unused_expected_punc : Warning<
+ "expected ')' or ',' in '#pragma unused'">;
+
+} // end of Parser diagnostics
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
new file mode 100644
index 000000000000..672e473678dd
--- /dev/null
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -0,0 +1,1822 @@
+//==--- DiagnosticSemaKinds.td - libsema diagnostics ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Semantic Analysis
+//===----------------------------------------------------------------------===//
+
+let Component = "Sema" in {
+
+// Constant expressions
+def err_expr_not_ice : Error<
+ "expression is not an integer constant expression">;
+def ext_expr_not_ice : Extension<
+ "expression is not integer constant expression "
+ "(but is allowed as an extension)">;
+
+def ext_null_pointer_expr_not_ice : Extension<
+ "null pointer expression is not an integer constant expression "
+ "(but is allowed as an extension)">;
+
+
+
+// Semantic analysis of string and character constant literals.
+def ext_predef_outside_function : Warning<
+ "predefined identifier is only valid inside function">;
+
+// C99 Designated Initializers
+def err_array_designator_negative : Error<
+ "array designator value '%0' is negative">;
+def err_array_designator_empty_range : Error<
+ "array designator range [%0, %1] is empty">;
+def err_array_designator_non_array : Error<
+ "array designator cannot initialize non-array type %0">;
+def err_array_designator_too_large : Error<
+ "array designator index (%0) exceeds array bounds (%1)">;
+def err_field_designator_non_aggr : Error<
+ "field designator cannot initialize a "
+ "%select{non-struct, non-union|non-class}0 type %1">;
+def err_field_designator_unknown : Error<
+ "field designator %0 does not refer to any field in type %1">;
+def err_field_designator_nonfield : Error<
+ "field designator %0 does not refer to a non-static data member">;
+def note_field_designator_found : Note<"field designator refers here">;
+def err_designator_for_scalar_init : Error<
+ "designator in initializer for scalar type %0">;
+def warn_subobject_initializer_overrides : Warning<
+ "subobject initialization overrides initialization of other fields "
+ "within its enclosing subobject">;
+def warn_initializer_overrides : Warning<
+ "initializer overrides prior initialization of this subobject">;
+def note_previous_initializer : Note<
+ "previous initialization %select{|with side effects }0is here"
+ "%select{| (side effects may not occur at run time)}0">;
+def err_designator_into_flexible_array_member : Error<
+ "designator into flexible array member subobject">;
+def note_flexible_array_member : Note<
+ "initialized flexible array member %0 is here">;
+def ext_flexible_array_init : Extension<
+ "flexible array initialization is a GNU extension">;
+
+// Declarations.
+def ext_vla : Extension<
+ "variable length arrays are a C99 feature, accepted as an 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">;
+def err_parameter_name_omitted : Error<"parameter name omitted">;
+def warn_decl_in_param_list : Warning<
+ "declaration of %0 will not be visible outside of this function">;
+
+def warn_implicit_function_decl : Warning<
+ "implicit declaration of function %0">,
+ InGroup<ImplicitFunctionDeclare>, DefaultIgnore;
+def ext_implicit_function_decl : Extension<
+ "implicit declaration of function %0 is invalid in C99">,
+ InGroup<ImplicitFunctionDeclare>;
+
+def err_ellipsis_first_arg : Error<
+ "ISO C requires a named argument before '...'">;
+def err_declarator_need_ident : Error<"declarator requires an identifier">;
+def err_bad_language : Error<"unknown linkage language">;
+def warn_use_out_of_scope_declaration : Warning<
+ "use of out-of-scope declaration of %0">;
+def err_inline_non_function : Error<
+ "'inline' can only appear on functions">;
+
+def err_invalid_thread : Error<
+ "'__thread' is only allowed on variable declarations">;
+def err_thread_non_global : Error<
+ "'__thread' variables must have global storage">;
+def err_thread_unsupported : Error<
+ "thread-local storage is unsupported for the current target">;
+
+/// Built-in functions.
+def ext_implicit_lib_function_decl : ExtWarn<
+ "implicitly declaring C library function '%0' with type %1">;
+def note_please_include_header : Note<
+ "please include the header <%0> or explicitly provide a "
+ "declaration for '%1'">;
+def note_previous_builtin_declaration : Note<"%0 is a builtin with type %1">;
+def err_implicit_decl_requires_stdio : Error<
+ "implicit declaration of '%0' requires inclusion of the header <stdio.h>">;
+def warn_redecl_library_builtin : Warning<
+ "incompatible redeclaration of library function %0">;
+def err_builtin_definition : Error<"definition of builtin function %0">;
+def err_types_compatible_p_in_cplusplus : Error<
+ "__builtin_types_compatible_p is not valid in C++">;
+
+/// parser diagnostics
+def ext_typedef_without_a_name : ExtWarn<"typedef requires a name">;
+def err_statically_allocated_object : Error<
+ "interface type cannot be statically allocated">;
+def err_object_cannot_be_passed_returned_by_value : Error<
+ "interface type %1 cannot be %select{returned|passed}0 by value">;
+def warn_enum_value_overflow : Warning<"overflow in enumeration value">;
+def warn_pragma_pack_invalid_alignment : Warning<
+ "expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">;
+// Follow the MSVC implementation.
+def warn_pragma_pack_show : Warning<"value of #pragma pack(show) == %0">;
+// FIXME: Dehardcode.
+def warn_pragma_pack_pop_identifer_and_alignment : Warning<
+ "specifying both a name and alignment to 'pop' is undefined">;
+def warn_pragma_pack_pop_failed : Warning<"#pragma pack(pop, ...) failed: %0">;
+
+def warn_pragma_unused_expected_localvar : Warning<
+ "only local variables can be arguments to '#pragma unused'">;
+
+/// Objective-C parser diagnostics
+def err_duplicate_class_def : Error<
+ "duplicate interface definition for class %0">;
+def err_undef_superclass : Error<
+ "cannot find interface declaration for %0, superclass of %1">;
+def warn_previous_alias_decl : Warning<"previously declared alias is ignored">;
+def err_conflicting_aliasing_type : Error<"conflicting types for alias %0">;
+def warn_undef_interface : Warning<"cannot find interface declaration for %0">;
+def warn_duplicate_protocol_def : Warning<"duplicate protocol definition of %0 is ignored">;
+def err_protocol_has_circular_dependency : Error<
+ "protocol has circular dependency">;
+def err_undeclared_protocol : Error<"cannot find protocol declaration for %0">;
+def warn_undef_protocolref : Warning<"cannot find protocol definition for %0">;
+def warn_readonly_property : Warning<
+ "attribute 'readonly' of property %0 restricts attribute "
+ "'readwrite' of property inherited from %1">;
+
+def warn_property_attribute : Warning<
+ "property %0 '%1' attribute does not match the property inherited from %2">;
+def warn_property_types_are_incompatible : Warning<
+ "property type %0 is incompatible with type %1 inherited from %2">;
+def err_undef_interface : Error<"cannot find interface declaration for %0">;
+def warn_dup_category_def : Warning<
+ "duplicate definition of category %1 on interface %0">;
+def err_conflicting_super_class : Error<"conflicting super class name %0">;
+def err_dup_implementation_class : Error<"reimplementation of class %0">;
+def err_conflicting_ivar_type : Error<
+ "instance variable %0 has conflicting type: %1 vs %2">;
+def err_conflicting_ivar_bitwidth : Error<
+ "instance variable %0 has conflicting bitfield width">;
+def err_conflicting_ivar_name : Error<
+ "conflicting instance variable names: %0 vs %1">;
+def err_inconsistant_ivar_count : Error<
+ "inconsistent number of instance variables specified">;
+def warn_incomplete_impl : Warning<"incomplete implementation">;
+def warn_undef_method_impl : Warning<"method definition for %0 not found">;
+
+def warn_conflicting_ret_types : Warning<
+ "conflicting return type in implementation of %0: %1 vs %2">;
+
+def warn_conflicting_param_types : Warning<
+ "conflicting parameter types in implementation of %0: %1 vs %2">;
+
+def warn_multiple_method_decl : Warning<"multiple methods named %0 found">;
+def warn_accessor_property_type_mismatch : Warning<
+ "type of property %0 does not match type of accessor %1">;
+def note_declared_at : Note<"declared at">;
+def err_setter_type_void : Error<"type of setter must be void">;
+def err_duplicate_method_decl : Error<"duplicate declaration of method %0">;
+def err_objc_var_decl_inclass :
+ Error<"cannot declare variable inside @interface or @protocol">;
+def error_missing_method_context : Error<
+ "missing context for method declaration">;
+def err_objc_property_attr_mutually_exclusive : Error<
+ "property attributes '%0' and '%1' are mutually exclusive">;
+def err_objc_property_requires_object : Error<
+ "property with '%0' attribute must be of object type">;
+def warn_objc_property_no_assignment_attribute : Warning<
+ "no 'assign', 'retain', or 'copy' attribute is specified - "
+ "'assign' is assumed">;
+def warn_objc_property_default_assign_on_object : Warning<
+ "default property attribute 'assign' not appropriate for non-gc object">;
+def warn_property_attr_mismatch : Warning<
+ "property attribute in continuation class does not match the primary class">;
+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 err_use_continuation_class : Error<
+ "attribute of property in continuation class of %0 can only be 'readwrite'">;
+def err_continuation_class : Error<"continuation class has no primary class">;
+def err_property_type : Error<"property cannot have array or function type %0">;
+def error_missing_property_context : Error<
+ "missing context for property implementation declaration">;
+def error_bad_property_decl : Error<
+ "property implementation must have its declaration in interface %0">;
+def error_synthesize_category_decl : Error<
+ "@synthesize not allowed in a category's implementation">;
+def error_missing_property_interface : Error<
+ "property implementation in a category with no category declaration">;
+def error_bad_category_property_decl : Error<
+ "property implementation must have its declaration in the category %0">;
+def error_bad_property_context : Error<
+ "property implementation must be in a class or category implementation">;
+def error_missing_property_ivar_decl : Error<
+ "synthesized property %0 must either be named the same as a compatible"
+ " ivar or must explicitly name an ivar">;
+
+def error_synthesized_ivar_yet_not_supported : Error<
+ "instance variable synthesis not yet supported"
+ " (need to declare %0 explicitly)">;
+
+def error_property_ivar_type : Error<
+ "type of property %0 does not match type of ivar %1">;
+def error_ivar_in_superclass_use : Error<
+ "property %0 attempting to use ivar %1 declared in super class %2">;
+def error_weak_property : Error<
+ "existing ivar %1 for __weak property %0 must be __weak">;
+def error_strong_property : Error<
+ "existing ivar %1 for a __strong property %0 must be garbage collectable">;
+def error_dynamic_property_ivar_decl : Error<
+ "dynamic property can not have ivar specification">;
+def error_duplicate_ivar_use : Error<
+ "synthesized properties %0 and %1 both claim ivar %2">;
+def error_property_implemented : Error<"property %0 is already implemented">;
+def warn_objc_property_attr_mutually_exclusive : Warning<
+ "property attributes '%0' and '%1' are mutually exclusive">,
+ InGroup<DiagGroup<"readonly-setter-attrs">>, DefaultIgnore;
+
+// C++ declarations
+def err_static_assert_expression_is_not_constant : Error<
+ "static_assert expression is not an integral constant expression">;
+def err_static_assert_failed : Error<"static_assert failed \"%0\"">;
+
+def err_friend_decl_outside_class : Error<
+ "'friend' used outside of class">;
+
+def err_abstract_type_in_decl : Error<
+ "%select{return|parameter|variable|field}1 type %0 is an abstract class">;
+def err_allocation_of_abstract_type : Error<
+ "allocation of an object of abstract type %0">;
+
+def err_type_defined_in_type_specifier : Error<
+ "%0 can not be defined in a type specifier">;
+def err_type_defined_in_result_type : Error<
+ "%0 can not be defined in the result type of a function">;
+def err_type_defined_in_param_type : Error<
+ "%0 can not be defined in a parameter type">;
+
+def note_pure_virtual_function : Note<
+ "pure virtual function %0">;
+
+def err_deleted_non_function : Error<
+ "only functions can have deleted definitions">;
+def err_deleted_decl_not_first : Error<
+ "deleted definition must be first declaration">;
+
+// C++ exception specifications
+def err_exception_spec_in_typedef : Error<
+ "exception specifications are not allowed in typedefs">;
+def err_distant_exception_spec : Error<
+ "exception specifications are not allowed beyond a single level "
+ "of indirection">;
+def err_incomplete_in_exception_spec : Error<
+ "%select{|pointer to |reference to }1incomplete type %0 is not allowed "
+ "in exception specification">;
+
+// C++ access checking
+def err_class_redeclared_with_different_access : Error<
+ "%0 redeclared with '%1' access">;
+def note_previous_access_declaration : Note<
+ "previously declared '%1' here">;
+
+// C++ name lookup
+def err_incomplete_nested_name_spec : Error<
+ "incomplete type %0 named in nested name specifier">;
+
+// C++ class members
+def err_storageclass_invalid_for_member : Error<
+ "storage class specified for a member declaration">;
+def err_mutable_function : Error<"'mutable' cannot be applied to functions">;
+def err_mutable_reference : Error<"'mutable' cannot be applied to references">;
+def err_mutable_const : Error<"'mutable' and 'const' cannot be mixed">;
+def err_mutable_nonmember : Error<
+ "'mutable' can only be applied to member variables">;
+def err_virtual_non_function : Error<
+ "'virtual' can only appear on non-static member functions">;
+def err_explicit_non_function : Error<
+ "'explicit' can only appear on non-static member functions">;
+def err_virtual_out_of_class : Error<
+ "'virtual' can only be specified inside the class definition">;
+def err_static_not_bitfield : Error<"static member %0 cannot be a bit-field">;
+def err_static_out_of_line : Error<
+ "'static' can only be specified inside the class definition">;
+def err_typedef_not_bitfield : Error<"typedef member %0 cannot be a bit-field">;
+def err_not_integral_type_bitfield : Error<
+ "bit-field %0 has non-integral type %1">;
+def err_not_integral_type_anon_bitfield : Error<
+ "anonymous bit-field has non-integral type %0">;
+def err_member_initialization : Error<
+ "%0 can only be initialized if it is a static const integral data member">;
+def err_member_function_initialization : Error<
+ "initializer on function does not look like a pure-specifier">;
+def err_non_virtual_pure : Error<
+ "%0 is not virtual and cannot be declared pure">;
+def err_implicit_object_parameter_init : Error<
+ "cannot initialize object parameter of type %0 with an expression "
+ "of type %1">;
+
+def err_different_return_type_for_overriding_virtual_function : Error<
+ "virtual function %0 has a different return type (%1) than the "
+ "function it overrides (which has return type %2)">;
+def note_overridden_virtual_function : Note<
+ "overridden virtual function is here">;
+
+def err_covariant_return_inaccessible_base : Error<
+ "return type of virtual function %2 is not covariant with the return type "
+ "of the function it overrides "
+ "(conversion from %0 to inaccessible base class %1)">;
+def err_covariant_return_ambiguous_derived_to_base_conv : Error<
+ "return type of virtual function %3 is not covariant with the return type of "
+ "the function it overrides (ambiguous conversion from derived class "
+ "%0 to base class %1:%2)">;
+def err_covariant_return_not_derived : Error<
+ "return type of virtual function %0 is not covariant with the return type of "
+ "the function it overrides (%1 is not derived from %2)">;
+def err_covariant_return_type_different_qualifications : Error<
+ "return type of virtual function %0 is not covariant with the return type of "
+ "the function it overrides (%1 has different qualifiers than %2)">;
+def err_covariant_return_type_class_type_more_qualified : Error<
+ "return type of virtual function %0 is not covariant with the return type of "
+ "the function it overrides (class type %1 is more qualified than class "
+ "type %2">;
+// C++ constructors
+def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">;
+def err_invalid_qualified_constructor : Error<
+ "'%0' qualifier is not allowed on a constructor">;
+def err_constructor_return_type : Error<
+ "constructor cannot have a return type">;
+def err_constructor_redeclared : Error<"constructor cannot be redeclared">;
+def err_constructor_byvalue_arg : Error<
+ "copy constructor must pass its first argument by reference">;
+
+// C++ destructors
+def err_destructor_not_member : Error<
+ "destructor must be a non-static member function">;
+def err_destructor_cannot_be : Error<"destructor cannot be declared '%0'">;
+def err_invalid_qualified_destructor : Error<
+ "'%0' qualifier is not allowed on a destructor">;
+def err_destructor_return_type : Error<"destructor cannot have a return type">;
+def err_destructor_redeclared : Error<"destructor cannot be redeclared">;
+def err_destructor_with_params : Error<"destructor cannot have any parameters">;
+def err_destructor_variadic : Error<"destructor cannot be variadic">;
+def err_destructor_typedef_name : Error<
+ "destructor cannot be declared using a typedef %0 of the class name">;
+
+// C++ initialization
+def err_lvalue_to_rvalue_ref : Error<"rvalue reference cannot bind to lvalue">;
+// FIXME: passing in an English string as %1!
+def err_not_reference_to_const_init : Error<
+ "non-const lvalue reference to type %0 cannot be initialized "
+ "with a %1 of type %2">;
+// FIXME: passing in an English string as %1!
+def err_reference_init_drops_quals : Error<
+ "initialization of reference to type %0 with a %1 of type %2 drops "
+ "qualifiers">;
+def err_reference_var_requires_init : Error<
+ "declaration of reference variable %0 requires an initializer">;
+def err_const_var_requires_init : Error<
+ "declaration of const variable '%0' requires an initializer">;
+def err_init_non_aggr_init_list : Error<
+ "initialization of non-aggregate type %0 with an initializer list">;
+def err_init_reference_member_uninitialized : Error<
+ "reference member of type %0 uninitialized">;
+def note_uninit_reference_member : Note<
+ "uninitialized reference member is here">;
+
+// Objective-C++
+def err_objc_decls_may_only_appear_in_global_scope : Error<
+ "Objective-C declarations may only appear in global scope">;
+def err_nsobject_attribute : Error<
+ "__attribute ((NSObject)) is for pointer types only">;
+
+// Attributes
+def err_attribute_can_be_applied_only_to_symbol_declaration : Error<
+ "%0 attribute can be applied only to symbol declaration">;
+def err_attributes_are_not_compatible : Error<
+ "%0 and %1 attributes are not compatible">;
+def err_attribute_wrong_number_arguments : Error<
+ "attribute requires %0 argument(s)">;
+def err_attribute_missing_parameter_name : Error<
+ "attribute requires unquoted parameter">;
+def err_attribute_invalid_vector_type : Error<"invalid vector type %0">;
+def err_attribute_argument_not_int : Error<
+ "'%0' attribute requires integer constant">;
+def err_attribute_argument_n_not_int : Error<
+ "'%0' attribute requires parameter %1 to be an integer constant">;
+def err_attribute_argument_n_not_string : Error<
+ "'%0' attribute requires parameter %1 to be a string">;
+def err_attribute_argument_out_of_bounds : Error<
+ "'%0' attribute parameter %1 is out of bounds">;
+def err_attribute_requires_objc_interface : Error<
+ "attribute may only be applied to an Objective-C interface">;
+def err_nonnull_pointers_only : Error<
+ "nonnull attribute only applies to pointer arguments">;
+def err_format_strftime_third_parameter : Error<
+ "strftime format attribute requires 3rd parameter to be 0">;
+def err_format_attribute_requires_variadic : Error<
+ "format attribute requires variadic function">;
+def err_format_attribute_not : Error<"format argument not %0">;
+def err_format_attribute_result_not : Error<"function does not return %0">;
+def err_attribute_invalid_size : Error<
+ "vector size not an integral multiple of component size">;
+def err_attribute_zero_size : Error<"zero vector size">;
+def err_typecheck_vector_not_convertable : Error<
+ "can't convert between vector values of different size (%0 and %1)">;
+def err_typecheck_ext_vector_not_typedef : Error<
+ "ext_vector_type only applies to types, not variables">;
+def err_unsupported_vector_size : Error<
+ "unsupported type %0 for vector_size attribute, please use on typedef">;
+def err_ext_vector_component_exceeds_length : Error<
+ "vector component access exceeds type %0">;
+def err_ext_vector_component_requires_even : Error<
+ "vector component access invalid for odd-sized type %0">;
+def err_ext_vector_component_name_illegal : Error<
+ "illegal vector component name '%0'">;
+def err_attribute_address_space_not_int : Error<
+ "address space attribute requires an integer constant">;
+def err_attribute_address_multiple_qualifiers : Error<
+ "multiple address spaces specified for type">;
+def err_implicit_pointer_address_space_cast : Error<
+ "illegal implicit cast between two pointers with different address spaces">;
+def err_as_qualified_auto_decl : Error<
+ "automatic variable qualified with an address space">;
+def err_attribute_annotate_no_string : Error<
+ "argument to annotate attribute was not a string literal">;
+def err_attribute_aligned_not_power_of_two : Error<
+ "requested alignment is not a power of 2">;
+def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
+ "'%0' redeclared without %1 attribute: previous %1 ignored">;
+def warn_attribute_ignored : Warning<"%0 attribute ignored">;
+def warn_attribute_weak_on_field : Warning<
+ "__weak attribute cannot be specified on a field declaration">;
+def warn_attribute_weak_on_local : Warning<
+ "__weak attribute cannot be specified on an automatic variable">;
+def warn_attribute_weak_import_invalid_on_definition : Warning<
+ "'weak_import' attribute cannot be specified on a definition">;
+def warn_attribute_wrong_decl_type : Warning<
+ "%0 attribute only applies to %select{function|union|"
+ "variable and function|function or method|parameter|parameter or Objective-C method |"
+ "function, method or block}1 types">;
+def warn_gnu_inline_attribute_requires_inline : Warning<
+ "'gnu_inline' attribute requires function to be marked 'inline',"
+ " attribute ignored">;
+
+def warn_attribute_ignored_for_field_of_type : Warning<
+ "%0 attribute ignored for field of type %1">;
+def warn_transparent_union_attribute_field_size_align : Warning<
+ "%select{alignment|size}0 of field %1 (%2 bits) does not match the "
+ "%select{alignment|size}0 of the first field in transparent union; "
+ "transparent_union attribute ignored">;
+def note_transparent_union_first_field_size_align : Note<
+ "%select{alignment|size}0 of first field is %1 bits">;
+def warn_transparent_union_attribute_not_definition : Warning<
+ "transparent_union attribute can only be applied to a union definition; "
+ "attribute ignored">;
+def warn_transparent_union_attribute_floating : Warning<
+ "first field of a transparent union cannot have floating point or vector "
+ "type; transparent_union attribute ignored">;
+def warn_transparent_union_attribute_zero_fields : Warning<
+ "transparent union definition must contain at least one field; "
+ "transparent_union attribute ignored">;
+def warn_attribute_type_not_supported : Warning<
+ "'%0' attribute argument not supported: %1">;
+def warn_attribute_unknown_visibility : Warning<"unknown visibility '%1'">;
+def err_unknown_machine_mode : Error<"unknown machine mode %0">;
+def err_unsupported_machine_mode : Error<"unsupported machine mode %0">;
+def err_mode_not_primitive : Error<
+ "mode attribute only supported for integer and floating-point types">;
+def err_mode_wrong_type : Error<
+ "type of machine mode does not match type of base type">;
+def err_attr_wrong_decl : Error<
+ "'%0' attribute invalid on this declaration, requires typedef or value">;
+def warn_attribute_nonnull_no_pointers : Warning<
+ "'nonnull' attribute applied to function with no pointer arguments">;
+def warn_transparent_union_nonpointer : Warning<
+ "'transparent_union' attribute support incomplete; only supported for "
+ "pointer unions">;
+
+def warn_attribute_sentinel_named_arguments : Warning<
+ "'sentinel' attribute requires named arguments">;
+def warn_attribute_sentinel_not_variadic : Warning<
+ "'sentinel' attribute only supported for variadic %select{functions|blocks}0">;
+def err_attribute_sentinel_less_than_zero : Error<
+ "'sentinel' parameter 1 less than zero">;
+def err_attribute_sentinel_not_zero_or_one : Error<
+ "'sentinel' parameter 2 not 0 or 1">;
+def err_attribute_cleanup_arg_not_found : Error<
+ "'cleanup' argument %0 not found">;
+def err_attribute_cleanup_arg_not_function : Error<
+ "'cleanup' argument %0 is not a function">;
+def err_attribute_cleanup_func_must_take_one_arg : Error<
+ "'cleanup' function %0 must take 1 parameter">;
+def err_attribute_cleanup_func_arg_incompatible_type : Error<
+ "'cleanup' function %0 parameter has type %1 which is incompatible with "
+ "type %2">;
+def err_attribute_regparm_wrong_platform : Error<
+ "'regparm' is not valid on this platform">;
+def err_attribute_regparm_invalid_number : Error<
+ "'regparm' parameter must be between 0 and %0 inclusive">;
+
+
+// Clang-Specific Attributes
+def err_attribute_iboutlet : Error<
+ "'iboutlet' attribute can only be applied to instance variables or "
+ "properties">;
+def err_attribute_overloadable_not_function : Error<
+ "'overloadable' attribute can only be applied to a function">;
+def err_attribute_overloadable_missing : Error<
+ "%select{overloaded function|redeclaration of}0 %1 must have the "
+ "'overloadable' attribute">;
+def note_attribute_overloadable_prev_overload : Note<
+ "previous overload of function is here">;
+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 functions or methods that "
+ "return a pointer or Objective-C object">;
+
+// Function Parameter Semantic Analysis.
+def err_param_with_void_type : Error<"argument may not have 'void' type">;
+def err_void_only_param : Error<
+ "'void' must be the first and only parameter if specified">;
+def err_void_param_qualified : Error<
+ "'void' as parameter must not have type qualifiers">;
+def err_ident_list_in_fn_declaration : Error<
+ "a parameter list without types is only allowed in a function definition">;
+def ext_param_not_declared : Extension<
+ "parameter %0 was not declared, defaulting to type 'int'">;
+def err_param_typedef_of_void : Error<
+ "empty parameter list defined with a typedef of 'void' not allowed in C++">;
+def err_param_default_argument : Error<
+ "C does not support default arguments">;
+def err_param_default_argument_redefinition : Error<
+ "redefinition of default argument">;
+def err_param_default_argument_missing : Error<
+ "missing default argument on parameter">;
+def err_param_default_argument_missing_name : Error<
+ "missing default argument on parameter %0">;
+def err_param_default_argument_references_param : Error<
+ "default argument references parameter %0">;
+def err_param_default_argument_references_local : Error<
+ "default argument references local variable %0 of enclosing function">;
+def err_param_default_argument_references_this : Error<
+ "default argument references 'this'">;
+def err_param_default_argument_nonfunc : Error<
+ "default arguments can only be specified for parameters in a function "
+ "declaration">;
+
+def ext_param_promoted_not_compatible_with_prototype : ExtWarn<
+ "promoted type %0 of K&R function parameter is not compatible with the "
+ "parameter type %1 declared in a previous prototype">;
+
+
+// C++ Overloading Semantic Analysis.
+def err_ovl_diff_return_type : Error<
+ "functions that differ only in their return type cannot be overloaded">;
+def err_ovl_static_nonstatic_member : Error<
+ "static and non-static member functions with the same parameter types "
+ "cannot be overloaded">;
+
+def err_ovl_no_viable_function_in_call : Error<
+ "no matching function for call to %0">;
+def err_ovl_no_viable_member_function_in_call : Error<
+ "no matching member function for call to %0">;
+def err_ovl_ambiguous_call : Error<
+ "call to %0 is ambiguous">;
+def err_ovl_deleted_call : Error<
+ "call to %select{unavailable|deleted}0 function %1">;
+def err_ovl_ambiguous_member_call : Error<
+ "call to member function %0 is ambiguous">;
+def err_ovl_deleted_member_call : Error<
+ "call to %select{unavailable|deleted}0 member function %1">;
+def err_ovl_candidate : Note<"candidate function">;
+def err_ovl_candidate_deleted : Note<
+ "candidate function has been explicitly %select{made unavailable|deleted}0">;
+def err_ovl_builtin_candidate : Note<"built-in candidate function %0">;
+def err_ovl_no_viable_function_in_init : Error<
+ "no matching constructor for initialization of %0">;
+def err_ovl_ambiguous_init : Error<"call to constructor of %0 is ambiguous">;
+def err_ovl_deleted_init : Error<
+ "call to %select{unavailable|deleted}0 constructor of %1">;
+def err_ovl_ambiguous_oper : Error<
+ "use of overloaded operator '%0' is ambiguous">;
+def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">;
+def err_ovl_deleted_oper : Error<
+ "overload resolution selected %select{unavailable|deleted}0 operator '%1'">;
+
+def err_ovl_no_viable_object_call : Error<
+ "no matching function for call to object of type %0">;
+def err_ovl_ambiguous_object_call : Error<
+ "call to object of type %0 is ambiguous">;
+def err_ovl_deleted_object_call : Error<
+ "call to %select{unavailable|deleted}0 function call operator in type %1">;
+def err_ovl_surrogate_cand : Note<"conversion candidate of type %0">;
+def err_member_call_without_object : Error<
+ "call to non-static member function without an object argument">;
+
+// C++ Template Declarations
+def err_template_param_shadow : Error<
+ "declaration of %0 shadows template parameter">;
+def note_template_param_here : Note<"template parameter is declared here">;
+def note_template_export_unsupported : Note<
+ "exported templates are unsupported">;
+def err_template_outside_namespace_or_class_scope : Error<
+ "templates can only be declared in namespace or class scope">;
+def err_template_linkage : Error<"templates must have C++ linkage">;
+def err_template_unnamed_class : Error<
+ "cannot declare a class template with no name">;
+def err_template_param_list_different_arity : Error<
+ "%select{too few|too many}0 template parameters in template "
+ "%select{|template parameter }1redeclaration">;
+def note_template_param_list_different_arity : Note<
+ "%select{too few|too many}0 template parameters in template template "
+ "argument">;
+def note_template_prev_declaration : Note<
+ "previous template %select{declaration|template parameter}0 is here">;
+def err_template_param_different_kind : Error<
+ "template parameter has a different kind in template "
+ "%select{|template parameter }0redeclaration">;
+def note_template_param_different_kind : Note<
+ "template parameter has a different kind in template argument">;
+def err_template_nontype_parm_different_type : Error<
+ "template non-type parameter has a different type %0 in template "
+ "%select{|template parameter }1redeclaration">;
+
+def note_template_nontype_parm_different_type : Note<
+ "template non-type parameter has a different type %0 in template argument">;
+def note_template_nontype_parm_prev_declaration : Note<
+ "previous non-type template parameter with type %0 is here">;
+def err_template_nontype_parm_bad_type : Error<
+ "a non-type template parameter cannot have type %0">;
+def err_template_param_default_arg_redefinition : Error<
+ "template parameter redefines default argument">;
+def note_template_param_prev_default_arg : Note<
+ "previous default template argument defined here">;
+def err_template_param_default_arg_missing : Error<
+ "template parameter missing a default argument">;
+
+// C++ Template Argument Lists
+def err_template_arg_list_different_arity : Error<
+ "%select{too few|too many}0 template arguments for "
+ "%select{class template|function template|template template parameter"
+ "|template}1 %2">;
+def note_template_decl_here : Note<"template is declared here">;
+def note_member_of_template_here : Note<"member is declared here">;
+def err_template_arg_must_be_type : Error<
+ "template argument for template type parameter must be a type">;
+def err_template_arg_must_be_expr : Error<
+ "template argument for non-type template parameter must be an expression">;
+def err_template_arg_nontype_ambig : Error<
+ "template argument for non-type template parameter is treated as type %0">;
+def err_template_arg_must_be_template : Error<
+ "template argument for template template parameter must be a template">;
+def err_template_arg_local_type : Error<"template argument uses local type %0">;
+def err_template_arg_unnamed_type : Error<
+ "template argument uses unnamed type">;
+def note_template_unnamed_type_here : Note<
+ "unnamed type used in template argument was declared here">;
+def err_template_arg_not_class_template : Error<
+ "template argument does not refer to a class template">;
+def note_template_arg_refers_here_func : Note<
+ "template argument refers to function template %0, here">;
+def err_template_arg_template_params_mismatch : Error<
+ "template template argument has different template parameters than its "
+ "corresponding template template parameter">;
+def err_template_arg_not_integral_or_enumeral : Error<
+ "non-type template argument of type %0 must have an integral or enumeration"
+ " type">;
+def err_template_arg_not_ice : Error<
+ "non-type template argument of type %0 is not an integral constant "
+ "expression">;
+def err_template_arg_not_convertible : Error<
+ "non-type template argument of type %0 cannot be converted to a value "
+ "of type %1">;
+def err_template_arg_negative : Error<
+ "non-type template argument provides negative value '%0' for unsigned "
+ "template parameter of type %1">;
+def err_template_arg_too_large : Error<
+ "non-type template argument value '%0' is too large for template "
+ "parameter of type %1">;
+def err_template_arg_no_ref_bind : Error<
+ "non-type template parameter of reference type %0 cannot bind to template "
+ "argument of type %1">;
+def err_template_arg_ref_bind_ignores_quals : Error<
+ "reference binding of non-type template parameter of type %0 to template "
+ "argument of type %1 ignores qualifiers">;
+def err_template_arg_not_object_or_func_form : Error<
+ "non-type template argument does not directly refer to an object or "
+ "function">;
+def err_template_arg_field : Error<
+ "non-type template argument refers to non-static data member %0">;
+def err_template_arg_method : Error<
+ "non-type template argument refers to non-static member function %0">;
+def err_template_arg_function_not_extern : Error<
+ "non-template argument refers to function %0 with internal linkage">;
+def err_template_arg_object_not_extern : Error<
+ "non-template argument refers to object %0 that does not have external "
+ "linkage">;
+def note_template_arg_internal_object : Note<
+ "non-template argument refers to %select{function|object}0 here">;
+def note_template_arg_refers_here : Note<"non-template argument refers here">;
+def err_template_arg_not_object_or_func : Error<
+ "non-type template argument does not refer to an object or function">;
+def err_template_arg_not_pointer_to_member_form : Error<
+ "non-type template argument is not a pointer to member constant">;
+def err_template_arg_extra_parens : Error<
+ "non-type template argument cannot be surrounded by parentheses">;
+
+// C++ class template specialization
+def err_template_spec_needs_header : Error<
+ "template specialization requires 'template<>'">;
+def err_template_spec_extra_headers : Error<
+ "template specialization must have a single 'template<>' header">;
+def unsup_template_partial_spec_ordering : Error<
+ "partial ordering of class template partial specializations is not yet "
+ "supported">;
+def err_template_spec_decl_out_of_scope_global : Error<
+ "class template specialization of %0 must occur in the global scope">;
+def err_template_spec_decl_out_of_scope : Error<
+ "class template specialization of %0 not in namespace %1">;
+def err_template_spec_decl_function_scope : Error<
+ "%select{class template specialization|explicit instantiation}0 of %1 "
+ "in function scope">;
+def err_template_spec_redecl_out_of_scope : Error<
+ "%select{class template specialization|explicit instantiation}0 of %1 "
+ "not in a namespace enclosing %2">;
+def err_template_spec_redecl_global_scope : Error<
+ "%select{class template specialization|explicit instantiation}0 of %1 must "
+ "occur at global scope">;
+
+// C++ Template Instantiation
+def err_template_recursion_depth_exceeded : Error<
+ "recursive template instantiation exceeded maximum depth of %0">,DefaultFatal;
+def note_template_recursion_depth : Note<
+ "use -ftemplate-depth-N to increase recursive template instantiation depth">;
+
+def err_template_instantiate_undefined : Error<
+ "%select{implicit|explicit}0 instantiation of undefined template %1">;
+def err_implicit_instantiate_member_undefined : Error<
+ "implicit instantiation of undefined member %0">;
+def note_template_class_instantiation_here : Note<
+ "in instantiation of template class %0 requested here">;
+def note_template_member_class_here : Note<
+ "in instantiation of member class %0 requested here">;
+def note_template_member_function_here : Note<
+ "in instantiation of member function %q0 requested here">;
+def note_default_arg_instantiation_here : Note<
+ "in instantiation of default argument for '%0' required here">;
+def err_field_instantiates_to_function : Error<
+ "data member instantiated with function type %0">;
+def err_nested_name_spec_non_tag : Error<
+ "type %0 cannot be used prior to '::' because it has no members">;
+
+// C++ Explicit Instantiation
+def err_explicit_instantiation_duplicate : Error<
+ "duplicate explicit instantiation of %0">;
+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)">;
+def note_previous_template_specialization : Note<
+ "previous template specialization is here">;
+def err_explicit_instantiation_enum : Error<
+ "explicit instantiation of enumeration type %0">;
+def err_explicit_instantiation_nontemplate_type : Error<
+ "explicit instantiation of non-templated type %0">;
+def note_nontemplate_decl_here : Note<
+ "non-templated declaration is here">;
+def err_explicit_instantiation_out_of_scope : Error<
+ "explicit instantiation of %0 not in a namespace enclosing %1">;
+
+// C++ typename-specifiers
+def err_typename_nested_not_found : Error<"no type named %0 in %1">;
+def err_typename_nested_not_found_global : Error<
+ "no type named %0 in the global namespace">;
+def err_typename_nested_not_type : Error<
+ "typename specifier refers to non-type member %0">;
+def note_typename_refers_here : Note<
+ "referenced member %0 is declared here">;
+
+def err_template_kw_refers_to_non_template : Error<
+ "%0 following the 'template' keyword does not refer to a template">;
+def err_template_kw_refers_to_function_template : Error<
+ "%0 following the 'template' keyword refers to a function template">;
+
+def err_unexpected_typedef : Error<
+ "unexpected type name %0: expected expression">;
+def err_unexpected_namespace : Error<
+ "unexpected namespace name %0: expected expression">;
+def err_undeclared_var_use : Error<"use of undeclared identifier %0">;
+def err_undeclared_use : Error<"use of undeclared '%0'">;
+def warn_deprecated : Warning<"%0 is deprecated">,
+ InGroup<DiagGroup<"deprecated-declarations">>;
+def warn_unavailable : Warning<"%0 is unavailable">;
+def note_unavailable_here : Note<
+ "function has been explicitly marked %select{unavailable|deleted}0 here">;
+def warn_not_enough_argument : Warning<
+ "not enough variable arguments in %0 declaration to fit a sentinel">;
+def warn_missing_sentinel : Warning <
+ "missing sentinel in %select{function call|method dispatch|block call}0">;
+def note_sentinel_here : Note<
+ "%select{function|method|block}0 has been explicitly marked sentinel here">;
+def warn_missing_prototype : Warning<
+ "no previous prototype for function %0">,
+ InGroup<DiagGroup<"missing-prototypes">>, DefaultIgnore;
+def err_redefinition : Error<"redefinition of %0">;
+
+def warn_redefinition_of_typedef : Warning<
+ "redefinition of typedef %0 is invalid in C">,
+ InGroup<DiagGroup<"typedef-redefinition"> >, DefaultError;
+
+def err_static_non_static : Error<
+ "static declaration of %0 follows non-static declaration">;
+def err_non_static_static : Error<
+ "non-static declaration of %0 follows static declaration">;
+def err_non_thread_thread : Error<
+ "non-thread-local declaration of %0 follows thread-local declaration">;
+def err_thread_non_thread : Error<
+ "thread-local declaration of %0 follows non-thread-local declaration">;
+def err_redefinition_different_type : Error<
+ "redefinition of %0 with a different type">;
+def err_redefinition_different_kind : Error<
+ "redefinition of %0 as different kind of symbol">;
+def err_redefinition_different_typedef : Error<
+ "typedef redefinition with different types (%0 vs %1)">;
+def err_tag_definition_of_typedef : Error<
+ "definition of type %0 conflicts with typedef of the same name">;
+def err_conflicting_types : Error<"conflicting types for %0">;
+def err_nested_redefinition : Error<"nested redefinition of %0">;
+def err_use_with_wrong_tag : Error<
+ "use of %0 with tag type that does not match previous declaration">;
+def warn_struct_class_tag_mismatch : Warning<
+ "%select{struct|class}0 %select{|template}1 %2 was previously declared "
+ "as a %select{class|struct}0 %select{|template}1">,
+ InGroup<MismatchedTags>, DefaultIgnore;
+def ext_forward_ref_enum : Extension<
+ "ISO C forbids forward references to 'enum' types">;
+def err_forward_ref_enum : Error<
+ "ISO C++ forbids forward references to 'enum' types">;
+def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">;
+def err_duplicate_member : Error<"duplicate member %0">;
+def ext_enum_value_not_int : Extension<
+ "ISO C restricts enumerator values to range of 'int' (%0 is too large)">;
+def warn_enum_too_large : Warning<
+ "enumeration values exceed range of largest integer">;
+def warn_illegal_constant_array_size : Extension<
+ "size of static array must be an integer constant expression">;
+def err_vla_decl_in_file_scope : Error<
+ "variable length array declaration not allowed at file scope">;
+def err_vla_decl_has_static_storage : Error<
+ "variable length array declaration can not have 'static' storage duration">;
+def err_vla_decl_has_extern_linkage : Error<
+ "variable length array declaration can not have 'extern' linkage">;
+def err_vm_decl_in_file_scope : Error<
+ "variably modified type declaration not allowed at file scope">;
+def err_vm_decl_has_extern_linkage : Error<
+ "variably modified type declaration can not have 'extern' linkage">;
+def err_typecheck_field_variable_size : Error<
+ "fields must have a constant size: 'variable length array in structure' "
+ "extension will never be supported">;
+def err_vm_func_decl : Error<
+ "function declaration cannot have variably modified type">;
+
+def err_typecheck_negative_array_size : Error<"array size is negative">;
+def warn_typecheck_function_qualifiers : Warning<
+ "qualifier on function type %0 has unspecified behavior">;
+def err_typecheck_invalid_restrict_not_pointer : Error<
+ "restrict requires a pointer or reference (%0 is invalid)">;
+def err_typecheck_invalid_restrict_invalid_pointee : Error<
+ "pointer to function type %0 may not be 'restrict' qualified">;
+def ext_typecheck_zero_array_size : Extension<
+ "zero size arrays are an extension">;
+def err_at_least_one_initializer_needed_to_size_array : Error<
+ "at least one initializer value required to size array">;
+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_block_extern_cant_init : Error<
+ "'extern' variable cannot have an initializer">;
+def warn_extern_init : Warning<"'extern' variable has an initializer">;
+def err_variable_object_no_init : Error<
+ "variable-sized object may not be initialized">;
+def err_array_init_list_required : Error<
+ "initialization with '{...}' expected for array">;
+def err_excess_initializers : Error<
+ "excess elements in %select{array|vector|scalar|union|struct}0 initializer">;
+def warn_excess_initializers : Warning<
+ "excess elements in %select{array|vector|scalar|union|struct}0 initializer">;
+def err_excess_initializers_in_char_array_initializer : Error<
+ "excess elements in char array initializer">;
+def warn_excess_initializers_in_char_array_initializer : Warning<
+ "excess elements in char array initializer">;
+def warn_initializer_string_for_char_array_too_long : Warning<
+ "initializer-string for char array is too long">;
+def warn_braces_around_scalar_init : Warning<
+ "braces around scalar initializer">;
+def err_many_braces_around_scalar_init : Error<
+ "too many braces around scalar initializer">;
+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_implicit_empty_initializer : Error<
+ "initializer for aggregate with no elements requires explicit braces">;
+def err_bitfield_has_negative_width : Error<
+ "bit-field %0 has negative width (%1)">;
+def err_anon_bitfield_has_negative_width : Error<
+ "anonymous bit-field has negative width (%0)">;
+def err_bitfield_has_zero_width : Error<"bit-field %0 has zero width">;
+def err_bitfield_width_exceeds_type_size : Error<
+ "size of bit-field %0 exceeds size of its type (%1 bits)">;
+def err_anon_bitfield_width_exceeds_type_size : Error<
+ "size of anonymous bitfield exceeds size of its type (%0 bits)">;
+
+def err_redefinition_of_label : Error<"redefinition of label '%0'">;
+def err_undeclared_label_use : Error<"use of undeclared label '%0'">;
+
+def err_goto_into_protected_scope : Error<"illegal goto into protected scope">;
+def err_switch_into_protected_scope : Error<
+ "illegal switch case into protected scope">;
+def err_indirect_goto_in_protected_scope : Error<
+ "illegal indirect goto in protected scope, unknown effect on scopes">;
+def err_addr_of_label_in_protected_scope : Error<
+ "address taken of label in protected scope, jump to it would have "
+ "unknown effect on scope">;
+def note_protected_by_vla_typedef : Note<
+ "jump bypasses initialization of VLA typedef">;
+def note_protected_by_vla : Note<
+ "jump bypasses initialization of variable length array">;
+def note_protected_by_cleanup : Note<
+ "jump bypasses initialization of declaration with __attribute__((cleanup))">;
+def note_protected_by_objc_try : Note<
+ "jump bypasses initialization of @try block">;
+def note_protected_by_objc_catch : Note<
+ "jump bypasses initialization of @catch block">;
+def note_protected_by_objc_finally : Note<
+ "jump bypasses initialization of @finally block">;
+def note_protected_by_objc_synchronized : Note<
+ "jump bypasses initialization of @synchronized block">;
+def note_protected_by_cxx_try : Note<
+ "jump bypasses initialization of try block">;
+def note_protected_by_cxx_catch : Note<
+ "jump bypasses initialization of catch block">;
+
+def err_func_returning_array_function : Error<
+ "function cannot return array or function type %0">;
+def err_field_declared_as_function : Error<"field %0 declared as a function">;
+def err_field_incomplete : Error<"field has incomplete type %0">;
+def ext_variable_sized_type_in_struct : ExtWarn<
+ "field %0 with variable sized type %1 not at the end of a struct or class is"
+ " a GNU extension">;
+
+def err_flexible_array_empty_struct : Error<
+ "flexible array %0 not allowed in otherwise empty struct">;
+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_needs_braces : Error<
+ "flexible array requires brace-enclosed initializer">;
+def err_illegal_decl_array_of_functions : Error<
+ "'%0' declared as array of functions">;
+def err_illegal_decl_array_incomplete_type : Error<
+ "array has incomplete element type %0">;
+def err_illegal_decl_array_of_references : Error<
+ "'%0' declared as array of references">;
+def err_array_star_outside_prototype : Error<
+ "star modifier used outside of function prototype">;
+def err_illegal_decl_pointer_to_reference : Error<
+ "'%0' declared as a pointer to a reference">;
+def err_illegal_decl_mempointer_to_void : Error<
+ "'%0' declared as a member pointer to void">;
+def err_illegal_decl_mempointer_in_nonclass : Error<
+ "'%0' does not point into a class">;
+def err_reference_to_void : Error<"cannot form a reference to 'void'">;
+def err_qualified_block_pointer_type : Error<
+ "qualifier specification on block pointer type not allowed">;
+def err_nonfunction_block_type : Error<
+ "block pointer to non-function type is invalid">;
+def err_return_block_has_expr : Error<"void block should not return a value">;
+def err_block_return_missing_expr : Error<
+ "non-void block should return a value">;
+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">;
+
+// Expressions.
+def ext_sizeof_function_type : Extension<
+ "invalid application of 'sizeof' to a function type">;
+def ext_sizeof_void_type : Extension<
+ "invalid application of '%0' to a void type">;
+// FIXME: merge with %select
+def err_sizeof_incomplete_type : Error<
+ "invalid application of 'sizeof' to an incomplete type %0">;
+def err_alignof_incomplete_type : Error<
+ "invalid application of '__alignof' to an incomplete type %0">;
+def err_sizeof_alignof_bitfield : Error<
+ "invalid application of '%select{sizeof|__alignof}0' to bitfield">;
+def err_offsetof_record_type : Error<
+ "offsetof requires struct, union, or class type, %0 invalid">;
+def err_offsetof_array_type : Error<"offsetof requires array type, %0 invalid">;
+def ext_offsetof_extended_field_designator : Extension<
+ "using extended field designator is an extension">;
+def warn_offsetof_non_pod_type : Warning<"offset of on non-POD type %0">,
+ InGroup<InvalidOffsetof>;
+
+def warn_floatingpoint_eq : Warning<
+ "comparing floating point with == or != is unsafe">,
+ InGroup<DiagGroup<"float-equal">>, DefaultIgnore;
+
+def err_sizeof_nonfragile_interface : Error<
+ "invalid application of '%select{alignof|sizeof}1' to interface %0 in "
+ "non-fragile ABI">;
+def err_atdef_nonfragile_interface : Error<
+ "invalid application of @defs in non-fragile ABI">;
+def err_subscript_nonfragile_interface : Error<
+ "subscript requires size of interface %0, which is not constant in "
+ "non-fragile ABI">;
+
+def err_arithmetic_nonfragile_interface : Error<
+ "arithmetic on pointer to interface %0, which is not a constant size in "
+ "non-fragile ABI">;
+
+
+def ext_subscript_non_lvalue : Extension<
+ "ISO C90 does not allow subscripting non-lvalue array">;
+def err_typecheck_subscript_value : Error<
+ "subscripted value is not an array, pointer, or vector">;
+def err_typecheck_subscript_not_integer : Error<
+ "array subscript is not an integer">;
+def err_subscript_function_type : Error<
+ "subscript of pointer to function type %0">;
+def err_subscript_incomplete_type : Error<
+ "subscript of pointer to incomplete type %0">;
+def err_typecheck_member_reference_struct_union : Error<
+ "member reference base type %0 is not a structure or union">;
+def err_typecheck_member_reference_ivar : Error<
+ "%0 does not have a member named %1">;
+def err_typecheck_member_reference_arrow : Error<
+ "member reference type %0 is not a pointer">;
+def err_typecheck_member_reference_type : Error<
+ "cannot refer to type member %0 with '%select{.|->}1'">;
+def err_typecheck_member_reference_unknown : Error<
+ "cannot refer to member %0 with '%select{.|->}1'">;
+def note_member_reference_needs_call : Note<
+ "perhaps you meant to call this function with '()'?">;
+
+def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">;
+def err_typecheck_no_member : Error<"no member named %0">;
+def err_member_redeclared : Error<"class member cannot be redeclared">;
+def err_member_def_does_not_match : Error<
+ "out-of-line definition does not match any declaration in %0">;
+def err_nonstatic_member_out_of_line : Error<
+ "non-static data member defined out-of-line">;
+def err_qualified_typedef_declarator : Error<
+ "typedef declarator cannot be qualified">;
+def err_qualified_param_declarator : Error<
+ "parameter declarator cannot be qualified">;
+def err_out_of_line_declaration : Error<
+ "out-of-line declaration of a member must be a definition">;
+def note_member_def_close_match : Note<"member declaration nearly matches">;
+def err_typecheck_ivar_variable_size : Error<
+ "instance variables must have a constant size">;
+// FIXME: Improve with %select
+def err_typecheck_illegal_increment_decrement : Error<
+ "cannot modify value of type %0">;
+def err_typecheck_arithmetic_incomplete_type : Error<
+ "arithmetic on pointer to incomplete type %0">;
+def err_typecheck_pointer_arith_function_type : Error<
+ "arithmetic on pointer to function type %0">;
+def err_typecheck_pointer_arith_void_type : Error<
+ "arithmetic on pointer to void type">;
+def err_typecheck_decl_incomplete_type : Error<
+ "variable has incomplete type %0">;
+def err_tentative_def_incomplete_type : Error<
+ "tentative definition has type %0 that is never completed">;
+def err_tentative_def_incomplete_type_arr : Error<
+ "tentative definition has array of type %0 that is never completed">;
+def warn_tentative_incomplete_array : Warning<
+ "tentative array definition assumed to have one element">;
+
+def err_realimag_invalid_type : Error<"invalid type %0 to %1 operator">;
+def err_typecheck_sclass_fscope : Error<
+ "illegal storage class on file-scoped variable">;
+def err_unsupported_global_register : Error<
+ "global register variables are not supported">;
+def 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 ext_typecheck_addrof_void : Extension<
+ "ISO C forbids taking the address of an expression of type 'void'">;
+def err_typecheck_invalid_lvalue_addrof : Error<
+ "address expression must be an lvalue or a function designator">;
+def err_typecheck_unary_expr : Error<
+ "invalid argument type %0 to unary expression">;
+def err_typecheck_indirection_requires_pointer : Error<
+ "indirection requires pointer operand (%0 invalid)">;
+def err_typecheck_invalid_operands : Error<
+ "invalid operands to binary expression (%0 and %1)">;
+def err_typecheck_sub_ptr_object : Error<
+ "subtraction of pointer %0 requires pointee to be a complete object type">;
+def err_typecheck_sub_ptr_compatible : Error<
+ "%0 and %1 are not pointers to compatible types">;
+def ext_typecheck_comparison_of_pointer_integer : Warning<
+ "comparison between pointer and integer (%0 and %1)">;
+def ext_typecheck_comparison_of_distinct_pointers : Warning<
+ "comparison of distinct pointer types (%0 and %1)">;
+def ext_typecheck_cond_incompatible_operands : Warning<
+ "incompatible operand types (%0 and %1)">;
+def err_typecheck_comparison_of_distinct_pointers : Error<
+ "comparison of distinct pointer types (%0 and %1)">;
+def err_typecheck_vector_comparison : Error<
+ "comparison of vector types (%0 and %1) not supported yet">;
+def err_typecheck_assign_const : Error<"read-only variable is not assignable">;
+def err_stmtexpr_file_scope : Error<
+ "statement expression not allowed at file scope">;
+
+def err_invalid_this_use : Error<
+ "invalid use of 'this' outside of a nonstatic member function">;
+def err_invalid_member_use_in_static_method : Error<
+ "invalid use of member %0 in static member function">;
+def err_invalid_qualified_function_type : Error<
+ "type qualifier is not allowed on this function">;
+def err_invalid_qualified_typedef_function_type_use : Error<
+ "a qualified function type cannot be used to declare a nonmember function "
+ "or a static member function">;
+
+def err_invalid_non_static_member_use : Error<
+ "invalid use of nonstatic data member %0">;
+def err_invalid_incomplete_type_use : Error<
+ "invalid use of incomplete type %0">;
+def err_builtin_func_cast_more_than_one_arg : Error<
+ "function-style cast to a builtin type can only take one argument">;
+def err_builtin_direct_init_more_than_one_arg : Error<
+ "initializer of a builtin type can only take one argument">;
+def err_value_init_for_array_type : Error<
+ "array types cannot be value-initialized">;
+def warn_printf_nonliteral_noargs : Warning<
+ "format string is not a string literal (potentially insecure)">,
+ InGroup<FormatSecurity>;
+def warn_printf_nonliteral : Warning<
+ "format string is not a string literal">,
+ InGroup<FormatNonLiteral>, DefaultIgnore;
+
+def err_unexpected_interface : Error<
+ "unexpected interface name %0: expected expression">;
+def err_property_not_found : Error<
+ "property %0 not found on object of type %1">;
+def ext_gnu_void_ptr : Extension<
+ "use of GNU void* extension">;
+def ext_gnu_ptr_func_arith : Extension<
+ "arithmetic on pointer to function type %0 is a GNU extension">;
+def error_readonly_property_assignment : Error<
+ "assigning to property with 'readonly' attribute not allowed">;
+def ext_integer_increment_complex : Extension<
+ "ISO C does not support '++'/'--' on complex integer type %0">;
+def ext_integer_complement_complex : Extension<
+ "ISO C does not support '~' for complex conjugation of %0">;
+def error_nosetter_property_assignment : Error<
+ "setter method is needed to assign to object using property" " assignment syntax">;
+
+def ext_freestanding_complex : Extension<
+ "complex numbers are an extension in a freestanding C99 implementation">;
+
+
+// Obj-c expressions
+def warn_root_inst_method_not_found : Warning<
+ "instance method %0 is being used on 'Class' which is not in the root class">;
+def warn_class_method_not_found : Warning<
+ "method %objcclass0 not found (return type defaults to 'id')">;
+def warn_inst_method_not_found : Warning<
+ "method %objcinstance0 not found (return type defaults to 'id')">;
+def error_no_super_class_message : Error<
+ "no @interface declaration found in class messaging of %0">;
+def error_no_super_class : Error<
+ "no super class declared in @interface for %0">;
+def err_invalid_receiver_to_message : Error<
+ "invalid receiver to message expression">;
+def warn_bad_receiver_type : Warning<
+ "receiver type %0 is not 'id' or interface pointer, consider "
+ "casting it to 'id'">;
+def err_bad_receiver_type : Error<"bad receiver type %0">;
+def error_objc_throw_expects_object : Error<
+ "@throw requires an Objective-C object type (%0 invalid)">;
+def error_objc_synchronized_expects_object : Error<
+ "@synchronized requires an Objective-C object type (%0 invalid)">;
+def error_rethrow_used_outside_catch : Error<
+ "@throw (rethrow) used outside of a @catch block">;
+def err_attribute_multiple_objc_gc : Error<
+ "multiple garbage collection attributes specified for type">;
+def err_catch_param_not_objc_type : Error<
+ "@catch parameter is not a pointer to an interface type">;
+def err_illegal_qualifiers_on_catch_parm : Error<
+ "illegal qualifiers on @catch parameter">;
+def err_illegal_super_cast : Error<
+ "cannot cast 'super' (it isn't an expression)">;
+def warn_setter_getter_impl_required : Warning<
+ "property %0 requires method %1 to be defined - "
+ "use @synthesize, @dynamic or provide a method implementation">;
+def note_property_impl_required : Note<
+ "implementation is here">;
+
+
+// C++ casts
+def err_bad_cxx_cast_generic : Error<"%0 from %2 to %1 is not allowed">;
+def err_bad_cxx_cast_rvalue : Error<"%0 from rvalue to reference type %1">;
+def err_bad_cxx_cast_const_away : Error<
+ "%0 from %2 to %1 casts away constness">;
+def err_bad_const_cast_dest : Error<
+ "const_cast to %0, which is not a reference, pointer-to-object, "
+ "or pointer-to-data-member">;
+
+def err_bad_reinterpret_cast_same_type : Error<
+ "source and destination type of reinterpret_cast are not distinct">;
+def ext_reinterpret_cast_fn_obj : Extension<
+ "reinterpret_cast between pointer-to-function and pointer-to-object is "
+ "an extension">;
+
+def err_bad_reinterpret_cast_small_int : Error<
+ "cast from pointer to smaller type %0 loses information">;
+def err_bad_dynamic_cast_not_ref_or_ptr : Error<
+ "%0 is not a reference or pointer">;
+def err_bad_dynamic_cast_not_class : Error<"%0 is not a class">;
+def err_bad_dynamic_cast_incomplete : Error<"%0 is an incomplete type">;
+def err_bad_dynamic_cast_not_ptr : Error<"%0 is not a pointer">;
+def err_bad_dynamic_cast_not_polymorphic : Error<"%0 is not polymorphic">;
+// FIXME: Display the path somehow better.
+def err_ambiguous_base_to_derived_cast : Error<
+ "ambiguous static_cast from base %0 to derived %1:%2">;
+def err_static_downcast_via_virtual : Error<
+ "cannot cast %0 to %1 via virtual base %2">;
+def err_bad_lvalue_to_rvalue_cast : Error<
+ "cannot cast from lvalue of type %0 to rvalue reference to %1; types are "
+ "not compatible">;
+
+// Other C++ expressions
+def err_need_header_before_typeid : Error<
+ "you need to include <typeinfo> before using the 'typeid' operator">;
+def err_static_illegal_in_new : Error<
+ "the 'static' modifier for the array size is not legal in new expressions">;
+def err_array_new_needs_size : Error<
+ "array size must be specified in new expressions">;
+def err_bad_new_type : Error<
+ "cannot allocate %select{function|reference}1 type %0 with new">;
+def err_new_incomplete_type : Error<
+ "allocation of incomplete type %0">;
+def err_new_array_nonconst : Error<
+ "only the first dimension of an allocated array may be non-const">;
+def err_array_size_not_integral : Error<
+ "array size expression must have integral or enumerated type, not %0">;
+def err_new_uninitialized_const : Error<
+ "must provide an initializer if the allocated object is 'const'">;
+def err_delete_operand : Error<"cannot delete expression of type %0">;
+def warn_delete_incomplete : Warning<
+ "deleting pointer to incomplete type %0 may cause undefined behaviour">;
+def err_decrement_bool : Error<"cannot decrement expression of type bool">;
+def warn_increment_bool : Warning<
+ "incrementing expression of type bool is deprecated">;
+def err_catch_incomplete_ptr : Error<
+ "cannot catch pointer to incomplete type %0">;
+def err_catch_incomplete_ref : Error<
+ "cannot catch reference to incomplete type %0">;
+def err_catch_incomplete : Error<"cannot catch incomplete type %0">;
+def err_catch_rvalue_ref : Error<"cannot catch exceptions by rvalue reference">;
+def err_qualified_catch_declarator : Error<
+ "exception declarator cannot be qualified">;
+def err_early_catch_all : Error<"catch-all handler must come last">;
+def err_bad_memptr_rhs : Error<
+ "right hand operand to %0 has non pointer-to-member type %1">;
+def err_bad_memptr_lhs : Error<
+ "left hand operand to %0 must be a %select{|pointer to }1class "
+ "compatible with the right hand operand, but is %2">;
+
+def err_conditional_void_nonvoid : Error<
+ "%select{left|right}1 operand to ? is void, but %select{right|left}1 operand "
+ "is of type %0">;
+def err_conditional_ambiguous : Error<
+ "conditional expression is ambiguous; %0 can be converted to %1 "
+ "and vice versa">;
+def err_conditional_ambiguous_ovl : Error<
+ "conditional expression is ambiguous; %0 and %1 can be converted to several "
+ "common types">;
+
+def err_throw_incomplete : Error<
+ "cannot throw object of incomplete type %0">;
+def err_throw_incomplete_ptr : Error<
+ "cannot throw pointer to object of incomplete type %0">;
+def err_return_in_constructor_handler : Error<
+ "return in the catch of a function try block of a constructor is illegal">;
+
+def err_invalid_use_of_function_type : Error<
+ "a function type is not allowed here">;
+def err_invalid_use_of_array_type : Error<"an array type is not allowed here">;
+def err_type_defined_in_condition : Error<
+ "types may not be defined in conditions">;
+def err_typecheck_bool_condition : Error<
+ "value of type %0 is not contextually convertible to 'bool'">;
+def err_expected_class_or_namespace : Error<"expected a class or namespace">;
+def err_invalid_declarator_scope : Error<
+ "definition or redeclaration of %0 not in a namespace enclosing %1">;
+def err_invalid_declarator_global_scope : Error<
+ "definition or redeclaration of %0 cannot name the global scope">;
+def err_invalid_declarator_in_function : Error<
+ "definition or redeclaration of %0 not allowed inside a function">;
+def err_not_tag_in_scope : Error<
+ "%0 does not name a tag member in the specified scope">;
+
+def warn_value_always_zero : Warning<"%0 is always zero in this context">;
+def warn_value_always_false : Warning<"%0 is always false in this context">;
+
+// assignment related diagnostics (also for argument passing, returning, etc).
+// FIXME: %2 is an english string here.
+def err_typecheck_convert_incompatible : Error<
+ "incompatible type %2 %1, expected %0">;
+def err_cannot_initialize_decl_noname : Error<
+ "cannot initialize a value of type %0 with an %select{rvalue|lvalue}1 "
+ "of type %2">;
+def err_cannot_initialize_decl : Error<
+ "cannot initialize %0 with an %select{rvalue|lvalue}1 of type %2">;
+def warn_incompatible_qualified_id : Warning<
+ "incompatible type %2 %1, expected %0">;
+def warn_incompatible_qualified_id_operands : Warning<
+ "invalid operands to binary expression (%0 and %1)">;
+def ext_typecheck_convert_pointer_int : ExtWarn<
+ "incompatible pointer to integer conversion %2 %1, expected %0">;
+def ext_typecheck_convert_int_pointer : ExtWarn<
+ "incompatible integer to pointer conversion %2 %1, expected %0">;
+def ext_typecheck_convert_pointer_void_func : Extension<
+ "%2 %1 converts between void* and function pointer, expected %0">;
+def ext_typecheck_convert_incompatible_pointer_sign : ExtWarn<
+ "pointer types point to integer types with different sign %2 %1, expected %0">,
+ InGroup<DiagGroup<"pointer-sign">>;
+def ext_typecheck_convert_incompatible_pointer : ExtWarn<
+ "incompatible pointer types %2 %1, expected %0">;
+def ext_typecheck_convert_discards_qualifiers : ExtWarn<
+ "%2 %1 discards qualifiers, expected %0">;
+def warn_incompatible_vectors : Warning<
+ "incompatible vector types %2 %1, expected %0">,
+ InGroup<VectorConversions>, DefaultIgnore;
+def err_int_to_block_pointer : Error<
+ "invalid conversion %2 integer %1, expected block pointer %0">;
+def err_typecheck_comparison_of_distinct_blocks : Error<
+ "comparison of distinct block types (%0 and %1)">;
+def err_typecheck_convert_incompatible_block_pointer : Error<
+ "incompatible block pointer types %2 %1, expected %0">;
+
+def err_typecheck_array_not_modifiable_lvalue : Error<
+ "array type %0 is not assignable">;
+def err_typecheck_non_object_not_modifiable_lvalue : Error<
+ "non-object type %0 is not assignable">;
+def err_typecheck_expression_not_modifiable_lvalue : Error<
+ "expression is not assignable">;
+def err_typecheck_incomplete_type_not_modifiable_lvalue : Error<
+ "incomplete type %0 is not assignable">;
+def err_typecheck_lvalue_casts_not_supported : Error<
+ "assignment to cast is illegal, lvalue casts are not supported">;
+
+def err_typecheck_duplicate_vector_components_not_mlvalue : Error<
+ "vector is not assignable (contains duplicate components)">;
+def err_block_decl_ref_not_modifiable_lvalue : Error<
+ "variable is not assignable (missing __block type specifier)">;
+def err_typecheck_call_not_function : Error<
+ "called object type %0 is not a function or function pointer">;
+def err_call_incomplete_return : Error<
+ "return type of called function (%0) is incomplete">;
+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">;
+def err_typecheck_call_too_many_args : Error<
+ "too many arguments to %select{function|block|method}0 call">;
+def warn_call_wrong_number_of_arguments : Warning<
+ "too %select{few|many}0 arguments in call to %1">;
+def err_atomic_builtin_must_be_pointer : Error<
+ "first argument to atomic builtin must be a pointer (%0 invalid)">;
+def err_atomic_builtin_must_be_pointer_intptr : Error<
+ "first argument to atomic builtin must be a pointer to integer or pointer"
+ " (%0 invalid)">;
+def err_atomic_builtin_pointer_size : Error<
+ "first argument to atomic builtin must be a pointer to 1,2,4,8 or 16 byte "
+ "type (%0 invalid)">;
+
+
+def err_deleted_function_use : Error<"attempt to use a deleted function">;
+
+def err_cannot_pass_objc_interface_to_vararg : Error<
+ "cannot pass object with interface type %0 by-value through variadic "
+ "%select{function|block|method}1">;
+
+def warn_cannot_pass_non_pod_arg_to_vararg : Warning<
+ "cannot pass object of non-POD type %0 through variadic "
+ "%select{function|block|method}1; call will abort at runtime">;
+
+def err_typecheck_closure_too_many_args : Error<
+ "too many arguments to closure call">;
+def err_typecheck_call_invalid_ordered_compare : Error<
+ "ordered compare requires two args of floating point type (%0 and %1)">;
+def err_typecheck_cond_expect_scalar : Error<
+ "used type %0 where arithmetic or pointer type is required">;
+def ext_typecheck_cond_one_void : Extension<
+ "C99 forbids conditional expressions with only one void side">;
+def ext_typecheck_cast_nonscalar : Extension<
+ "C99 forbids casting nonscalar type %0 to the same type">;
+def ext_typecheck_cast_to_union : Extension<"C99 forbids casts to union type">;
+def err_typecheck_cast_to_union_no_type : Error<
+ "cast to union type from type %0 not present in union">;
+def err_cast_pointer_from_non_pointer_int : Error<
+ "operand of type %0 cannot be cast to a pointer type">;
+def err_cast_pointer_to_non_pointer_int : Error<
+ "pointer cannot be cast to type %0">;
+def err_typecheck_expect_scalar_operand : Error<
+ "operand of type %0 where arithmetic or pointer type is required">;
+def err_typecheck_cond_incompatible_operands : Error<
+ "incompatible operand types (%0 and %1)">;
+def err_cast_selector_expr : Error<
+ "cannot type cast @selector expression">;
+def warn_typecheck_cond_incompatible_pointers : Warning<
+ "pointer type mismatch (%0 and %1)">;
+def warn_typecheck_cond_pointer_integer_mismatch : Warning<
+ "pointer/integer type mismatch in conditional expression (%0 and %1)">;
+def err_typecheck_choose_expr_requires_constant : Error<
+ "'__builtin_choose_expr' requires a constant expression">;
+def ext_typecheck_expression_not_constant_but_accepted : Extension<
+ "expression is not a constant, but is accepted as one by GNU extensions">;
+def warn_unused_expr : Warning<"expression result unused">,
+ InGroup<UnusedValue>;
+
+// inline asm.
+def err_asm_wide_character : Error<"wide string is invalid in 'asm'">;
+def err_asm_invalid_lvalue_in_output : Error<"invalid lvalue in asm output">;
+def err_asm_invalid_output_constraint : Error<
+ "invalid output constraint '%0' in asm">;
+def err_asm_invalid_lvalue_in_input : Error<
+ "invalid lvalue in asm input for constraint '%0'">;
+def err_asm_invalid_input_constraint : Error<
+ "invalid input constraint '%0' in asm">;
+def err_asm_invalid_type_in_input : Error<
+ "invalid type %0 in asm input for constraint '%1'">;
+def err_asm_tying_incompatible_types : Error<
+ "unsupported inline asm: input with type %0 matching output with type %1">;
+def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">;
+def err_invalid_asm_cast_lvalue : Error<
+ "invalid use of a cast in a inline asm context requiring an l-value: "
+ "remove the cast or build with -fheinous-gnu-extensions">;
+
+def warn_invalid_asm_cast_lvalue : Warning<
+ "invalid use of a cast in a inline asm context requiring an l-value: "
+ "accepted due to -fheinous-gnu-extensions, but clang may remove support "
+ "for this in the future">;
+
+
+
+def err_invalid_conversion_between_vectors : Error<
+ "invalid conversion between vector type %0 and %1 of different size">;
+def err_invalid_conversion_between_vector_and_integer : Error<
+ "invalid conversion between vector type %0 and integer type %1 "
+ "of different size">;
+
+def err_invalid_conversion_between_vector_and_scalar : Error<
+ "invalid conversion between vector type %0 and scalar type %1">;
+def err_overload_expr_requires_non_zero_constant : Error<
+ "overload requires a non-zero constant expression as first argument">;
+def err_overload_incorrect_fntype : Error<
+ "argument is not a function, or has wrong number of parameters">;
+
+// FIXME: PASSING TYPES AS STRING.
+def err_overload_no_match : Error<
+ "no matching overload found for arguments of type '%0'">;
+def err_overload_multiple_match : Error<
+ "more than one matching function found in __builtin_overload">;
+
+// C++ member initializers.
+def err_only_constructors_take_base_inits : Error<
+ "only constructors take base initializers">;
+
+def err_mem_init_not_member_or_class : Error<
+ "member initializer %0 does not name a non-static data member or base "
+ "class">;
+
+def err_base_init_does_not_name_class : Error<
+ "constructor initializer %0 does not name a class">;
+def err_base_init_direct_and_virtual : Error<
+ "base class initializer %0 names both a direct base class and an "
+ "inherited virtual base class">;
+
+def err_in_class_initializer_non_integral_type : Error<
+ "in-class initializer has non-integral, non-enumeration type %0">;
+def err_in_class_initializer_non_constant : Error<
+ "in-class initializer is not an integral constant expression">;
+
+// C++ anonymous unions and GNU anonymous structs/unions
+def ext_anonymous_union : Extension<
+ "anonymous unions are a GNU extension in C">;
+def ext_anonymous_struct : Extension<
+ "anonymous structs are a GNU extension">;
+def err_anonymous_union_not_static : Error<
+ "anonymous unions at namespace or global scope must be declared 'static'">;
+def err_anonymous_union_with_storage_spec : Error<
+ "anonymous union at class scope must not have a storage specifier">;
+def err_anonymous_struct_not_member : Error<
+ "anonymous %select{structs|structs and classes}0 must be "
+ "%select{struct or union|class}0 members">;
+def err_anonymous_union_member_redecl : Error<
+ "member of anonymous union redeclares %0">;
+def err_anonymous_struct_member_redecl : Error<
+ "member of anonymous struct redeclares %0">;
+def err_anonymous_record_with_type : Error<
+ "types cannot be declared in an anonymous %select{struct|union}0">;
+def err_anonymous_record_with_function : Error<
+ "functions cannot be declared in an anonymous %select{struct|union}0">;
+def err_anonymous_record_with_static : Error<
+ "static members cannot be declared in an anonymous %select{struct|union}0">;
+def err_anonymous_record_bad_member : Error<
+ "anonymous %select{struct|union}0 can only contain non-static data members">;
+def err_anonymous_record_nonpublic_member : Error<
+ "anonymous %select{struct|union}0 cannot contain a "
+ "%select{private|protected}1 data member">;
+
+// C++ derived classes
+def err_base_clause_on_union : Error<"unions cannot have base classes">;
+def err_base_must_be_class : Error<"base specifier must name a class">;
+def err_union_as_base_class : Error<"unions cannot be base classes">;
+def err_incomplete_base_class : Error<"base class has incomplete type">;
+def err_duplicate_base_class : Error<
+ "base class %0 specified more than once as a direct base class">;
+// FIXME: better way to display derivation? Pass entire thing into diagclient?
+def err_ambiguous_derived_to_base_conv : Error<
+ "ambiguous conversion from derived class %0 to base class %1:%2">;
+def err_ambiguous_memptr_conv : Error<
+ "ambiguous conversion from pointer to member of %select{base|derived}0 "
+ "class %1 to pointer to member of %select{derived|base}0 class %2:%3">;
+
+def err_memptr_conv_via_virtual : Error<
+ "conversion from pointer to member of class %0 to pointer to member "
+ "of class %1 via virtual base %2 is not allowed">;
+
+// C++ access control
+def err_conv_to_inaccessible_base : Error<
+ "conversion from %0 to inaccessible base class %1">;
+def note_inheritance_specifier_here : Note<
+ "'%0' inheritance specifier here">;
+def note_inheritance_implicitly_private_here : Note<
+ "inheritance is implicitly 'private'">;
+
+// C++ member name lookup
+def err_ambiguous_member_multiple_subobjects : Error<
+ "non-static member %0 found in multiple base-class subobjects of type %1:%2">;
+def err_ambiguous_member_multiple_subobject_types : Error<
+ "member %0 found in multiple base classes of different types">;
+def note_ambiguous_member_found : Note<"member found by ambiguous name lookup">;
+def err_ambiguous_reference : Error<"reference to %0 is ambiguous">;
+def note_ambiguous_candidate : Note<"candidate found by name lookup is %q0">;
+
+// C++ operator overloading
+def err_operator_overload_needs_class_or_enum : Error<
+ "overloaded %0 must have at least one parameter of class "
+ "or enumeration type">;
+
+def err_operator_overload_variadic : Error<"overloaded %0 cannot be variadic">;
+def err_operator_overload_static : Error<
+ "overloaded %0 cannot be a static member function">;
+def err_operator_overload_default_arg : Error<
+ "parameter of overloaded %0 cannot have a default argument">;
+def err_operator_overload_must_be : Error<
+ "overloaded %0 must be a %select{unary|binary|unary or binary}2 operator "
+ "(has %1 parameter%s1)">;
+
+def err_operator_overload_must_be_member : Error<
+ "overloaded %0 must be a non-static member function">;
+def err_operator_overload_post_incdec_must_be_int : Error<
+ "parameter of overloaded post-%select{increment|decrement}1 operator must "
+ "have type 'int' (not %0)">;
+
+
+// C++ conversion functions
+def err_conv_function_not_member : Error<
+ "conversion function must be a non-static member function">;
+def err_conv_function_return_type : Error<
+ "conversion function cannot have a return type">;
+def err_conv_function_with_params : Error<
+ "conversion function cannot have any parameters">;
+def err_conv_function_variadic : Error<
+ "conversion function cannot be variadic">;
+def err_conv_function_to_array : Error<
+ "conversion function cannot convert to an array type">;
+def err_conv_function_to_function : Error<
+ "conversion function cannot convert to a function type">;
+def err_conv_function_redeclared : Error<
+ "conversion function cannot be redeclared">;
+def warn_conv_to_self_not_used : Warning<
+ "conversion function converting %0 to itself will never be used">;
+def warn_conv_to_base_not_used : Warning<
+ "conversion function converting %0 to its base class %1 will never be used">;
+def warn_conv_to_void_not_used : Warning<
+ "conversion function converting %0 to %1 will never be used">;
+
+def warn_not_compound_assign : Warning<
+ "use of unary operator that may be intended as compound assignment (%0=)">;
+
+// C++0x explicit conversion operators
+def warn_explicit_conversion_functions : Warning<
+ "explicit conversion functions are a C++0x extension">;
+
+def warn_printf_write_back : Warning<
+ "use of '%%n' in format string discouraged (potentially insecure)">,
+ InGroup<FormatSecurity>;
+def warn_printf_insufficient_data_args : Warning<
+ "more '%%' conversions than data arguments">, InGroup<Format>;
+def warn_printf_too_many_data_args : Warning<
+ "more data arguments than '%%' conversions">, InGroup<FormatExtraArgs>;
+def warn_printf_invalid_conversion : Warning<
+ "invalid conversion '%0'">, InGroup<Format>;
+def warn_printf_missing_format_string : Warning<
+ "format string missing">, InGroup<Format>;
+def warn_null_arg : Warning<
+ "null passed to a callee which requires a non-null argument">,
+ InGroup<NonNull>;
+def warn_printf_empty_format_string : Warning<
+ "format string is empty">, InGroup<FormatZeroLength>;
+def warn_printf_format_string_is_wide_literal : Warning<
+ "format string should not be a wide string">, InGroup<Format>;
+def warn_printf_format_string_contains_null_char : Warning<
+ "format string contains '\\0' within the string body">, InGroup<Format>;
+def warn_printf_asterisk_width_missing_arg : Warning<
+ "'*' specified field width is missing a matching 'int' argument">;
+def warn_printf_asterisk_precision_missing_arg : Warning<
+ "'.*' specified field precision is missing a matching 'int' argument">;
+def warn_printf_asterisk_width_wrong_type : Warning<
+ "field width should have type 'int', but argument has type %0">,
+ InGroup<Format>;
+def warn_printf_asterisk_precision_wrong_type : Warning<
+ "field precision should have type 'int', but argument has type %0">,
+ InGroup<Format>;
+
+// CHECK: returning address/reference of stack memory
+def warn_ret_stack_addr : Warning<
+ "address of stack memory associated with local variable %0 returned">;
+def warn_ret_stack_ref : Warning<
+ "reference to stack memory associated with local variable %0 returned">;
+
+
+// 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.
+def warn_selfcomparison : Warning<
+ "self-comparison always results in a constant value">;
+def warn_stringcompare : Warning<
+ "result of comparison against %select{a string literal|@encode}0 is "
+ "unspecified (use strcmp instead)">;
+
+
+
+// Blocks
+def err_blocks_disable : Error<"blocks support disabled - compile with -fblocks"
+ " or pick a deployment target that supports them">;
+def err_expected_block_lbrace : Error<"expected '{' in block literal">;
+def err_goto_in_block : Error<
+ "goto not allowed in block literal">;
+def err_return_in_block_expression : Error<
+ "return not allowed in block expression literal">;
+def err_block_returns_array : Error<
+ "block declared as returning an array">;
+
+def err_ret_local_block : Error<
+ "returning block that lives on the local stack">;
+
+// CFString checking
+def err_cfstring_literal_not_string_constant : Error<
+ "CFString literal is not a string constant">;
+def warn_cfstring_literal_contains_nul_character : Warning<
+ "CFString literal contains NUL character">;
+
+// Statements.
+def err_continue_not_in_loop : Error<
+ "'continue' statement not in loop statement">;
+def err_break_not_in_loop_or_switch : Error<
+ "'break' statement not in loop or switch statement">;
+def err_default_not_in_switch : Error<
+ "'default' statement not in switch statement">;
+def err_case_not_in_switch : Error<"'case' statement not in switch statement">;
+def warn_case_value_overflow : Warning<
+ "overflow converting case value to switch condition type (%0 to %1)">;
+def err_duplicate_case : Error<"duplicate case value '%0'">;
+def warn_case_empty_range : Warning<"empty case range specified">;
+def err_typecheck_statement_requires_scalar : Error<
+ "statement requires expression of scalar type (%0 invalid)">;
+def err_typecheck_statement_requires_integer : Error<
+ "statement requires expression of integer type (%0 invalid)">;
+def err_multiple_default_labels_defined : Error<
+ "multiple default labels in one switch">;
+def warn_empty_if_body : Warning<
+ "if statement has empty body">;
+def err_va_start_used_in_non_variadic_function : Error<
+ "'va_start' used in function with fixed args">;
+def warn_second_parameter_of_va_start_not_last_named_argument : Warning<
+ "second parameter of 'va_start' not last named argument">;
+def err_first_argument_to_va_arg_not_of_type_va_list : Error<
+ "first argument to 'va_arg' is of type %0 and not 'va_list'">;
+
+def warn_return_missing_expr : Warning<
+ "non-void %select{function|method}1 %0 should return a value">,
+ InGroup<ReturnType>;
+def ext_return_missing_expr : ExtWarn<
+ "non-void %select{function|method}1 %0 should return a value">,
+ InGroup<ReturnType>;
+def ext_return_has_expr : ExtWarn<
+ "void %select{function|method}1 %0 should not return a value">,
+ InGroup<ReturnType>;
+def ext_return_has_void_expr : Extension<
+ "void %select{function|method}1 %0 should not return void expression">;
+def warn_noreturn_function_has_return_expr : Warning<
+ "function %0 declared 'noreturn' should not return">, DefaultError,
+ InGroup<DiagGroup<"invalid-noreturn">>;
+def err_noreturn_block_has_return_expr : Error<
+ "block declared 'noreturn' should not return">;
+def err_block_on_nonlocal : Error<
+ "__block attribute not allowed, only allowed on local variables">;
+def err_block_on_vm : Error<
+ "__block attribute not allowed on declaration with a variably modified type">;
+
+def err_shufflevector_non_vector : Error<
+ "first two arguments to __builtin_shufflevector must be vectors">;
+def err_shufflevector_incompatible_vector : Error<
+ "first two arguments to __builtin_shufflevector must have the same type">;
+def err_shufflevector_nonconstant_argument : Error<
+ "index for __builtin_shufflevector must be a constant integer">;
+def err_shufflevector_argument_too_large : Error<
+ "index for __builtin_shufflevector must be less than the total number "
+ "of vector elements">;
+
+
+def err_stack_const_level : Error<
+ "level argument for a stack address builtin must be constant">;
+
+def err_prefetch_invalid_argument : Error<
+ "argument to __builtin_prefetch must be a constant integer">;
+def err_argument_invalid_range : Error<
+ "argument should be a value from %0 to %1">;
+
+def err_object_size_invalid_argument : Error<
+ "argument to __builtin_object_size must be a constant integer">;
+
+def err_builtin_longjmp_invalid_val : Error<
+ "argument to __builtin_longjmp must be a constant 1">;
+
+def ext_mixed_decls_code : Extension<
+ "ISO C90 forbids mixing declarations and code">;
+def err_non_variable_decl_in_for : Error<
+ "declaration of non-local variable in 'for' loop">;
+def err_toomany_element_decls : Error<
+ "only one element declaration is allowed">;
+def err_selector_element_not_lvalue : Error<
+ "selector element is not a valid lvalue">;
+def err_selector_element_type : Error<
+ "selector element type %0 is not a valid object">;
+def err_collection_expr_type : Error<
+ "collection expression type %0 is not a valid object">;
+
+// Type
+def ext_invalid_sign_spec : Extension<"'%0' cannot be signed or unsigned">;
+def warn_receiver_forward_class : Warning<
+ "receiver %0 is a forward class and corresponding @interface may not exist">;
+def note_method_sent_forward_class : Note<"method %0 is used for the forward class">;
+def warn_missing_declspec : Warning<
+ "declaration specifier missing, defaulting to 'int'">;
+def warn_missing_type_specifier : Warning<
+ "type specifier missing, defaults to 'int'">,
+ InGroup<ImplicitInt>;
+def err_decimal_unsupported : Error<
+ "GNU decimal type extension not supported">;
+def err_missing_type_specifier : Error<
+ "C++ requires a type specifier for all declarations">;
+def err_missing_param_declspec : Error<
+ "parameter requires a declaration specifier">;
+def err_objc_array_of_interfaces : Error<
+ "array of interface %0 is invalid (probably should be an array of pointers)">;
+def ext_c99_array_usage : Extension<
+ "use of C99-specific array features, accepted as an extension">;
+def err_invalid_protocol_qualifiers : Error<
+ "invalid protocol qualifiers on non-ObjC type">;
+def err_qualified_class_unsupported : Error<
+ "protocol qualified 'Class' is unsupported">;
+def warn_ivar_use_hidden : Warning<
+ "local declaration of %0 hides instance variable">;
+def error_ivar_use_in_class_method : Error<
+ "instance variable %0 accessed in class method">;
+def error_private_ivar_access : Error<"instance variable %0 is private">;
+def error_protected_ivar_access : Error<"instance variable %0 is protected">;
+def warn_maynot_respond : Warning<"%0 may not respond to %1">;
+def warn_attribute_method_def : Warning<
+ "method attribute can only be specified on method declarations">;
+
+
+}
diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h
new file mode 100644
index 000000000000..d6a0cf34d9fa
--- /dev/null
+++ b/include/clang/Basic/FileManager.h
@@ -0,0 +1,178 @@
+//===--- FileManager.h - File System Probing and Caching --------*- 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 FileManager interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FILEMANAGER_H
+#define LLVM_CLANG_FILEMANAGER_H
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Config/config.h" // for mode_t
+#include <map>
+#include <set>
+#include <string>
+// FIXME: Enhance libsystem to support inode and other fields in stat.
+#include <sys/types.h>
+#include <sys/stat.h>
+
+namespace clang {
+class FileManager;
+
+/// DirectoryEntry - Cached information about one directory on the disk.
+///
+class DirectoryEntry {
+ const char *Name; // Name of the directory.
+ friend class FileManager;
+public:
+ DirectoryEntry() : Name(0) {}
+ const char *getName() const { return Name; }
+};
+
+/// FileEntry - Cached information about one file on the disk.
+///
+class FileEntry {
+ const char *Name; // Name of the file.
+ off_t Size; // File size in bytes.
+ time_t ModTime; // Modification time of file.
+ const DirectoryEntry *Dir; // Directory file lives in.
+ unsigned UID; // A unique (small) ID for the file.
+ dev_t Device; // ID for the device containing the file.
+ ino_t Inode; // Inode number for the file.
+ mode_t FileMode; // The file mode as returned by 'stat'.
+ friend class FileManager;
+public:
+ FileEntry(dev_t device, ino_t inode, mode_t m)
+ : Name(0), Device(device), Inode(inode), FileMode(m) {}
+ // Add a default constructor for use with llvm::StringMap
+ FileEntry() : Name(0), Device(0), Inode(0), FileMode(0) {}
+
+ const char *getName() const { return Name; }
+ off_t getSize() const { return Size; }
+ unsigned getUID() const { return UID; }
+ ino_t getInode() const { return Inode; }
+ dev_t getDevice() const { return Device; }
+ time_t getModificationTime() const { return ModTime; }
+ mode_t getFileMode() const { return FileMode; }
+
+ /// getDir - Return the directory the file lives in.
+ ///
+ const DirectoryEntry *getDir() const { return Dir; }
+
+ bool operator<(const FileEntry& RHS) const {
+ return Device < RHS.Device || (Device == RHS.Device && Inode < RHS.Inode);
+ }
+};
+
+// FIXME: This is a lightweight shim that is used by FileManager to cache
+// 'stat' system calls. We will use it with PTH to identify if caching
+// stat calls in PTH files is a performance win.
+class StatSysCallCache {
+public:
+ virtual ~StatSysCallCache() {}
+ virtual int stat(const char *path, struct stat *buf) = 0;
+};
+
+/// \brief A stat listener that can be used by FileManager to keep
+/// track of the results of stat() calls that occur throughout the
+/// execution of the front end.
+class MemorizeStatCalls : public StatSysCallCache {
+public:
+ /// \brief The result of a stat() call.
+ ///
+ /// The first member is the result of calling stat(). If stat()
+ /// found something, the second member is a copy of the stat
+ /// structure.
+ typedef std::pair<int, struct stat> StatResult;
+
+ /// \brief The set of stat() calls that have been
+ llvm::StringMap<StatResult, llvm::BumpPtrAllocator> StatCalls;
+
+ typedef llvm::StringMap<StatResult, llvm::BumpPtrAllocator>::const_iterator
+ iterator;
+
+ iterator begin() const { return StatCalls.begin(); }
+ iterator end() const { return StatCalls.end(); }
+
+ virtual int stat(const char *path, struct stat *buf);
+};
+
+/// FileManager - Implements support for file system lookup, file system
+/// caching, and directory search management. This also handles more advanced
+/// properties, such as uniquing files based on "inode", so that a file with two
+/// names (e.g. symlinked) will be treated as a single file.
+///
+class FileManager {
+
+ class UniqueDirContainer;
+ class UniqueFileContainer;
+
+ /// UniqueDirs/UniqueFiles - Cache for existing directories/files.
+ ///
+ UniqueDirContainer &UniqueDirs;
+ UniqueFileContainer &UniqueFiles;
+
+ /// DirEntries/FileEntries - This is a cache of directory/file entries we have
+ /// looked up. The actual Entry is owned by UniqueFiles/UniqueDirs above.
+ ///
+ llvm::StringMap<DirectoryEntry*, llvm::BumpPtrAllocator> DirEntries;
+ llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> FileEntries;
+
+ /// NextFileUID - Each FileEntry we create is assigned a unique ID #.
+ ///
+ unsigned NextFileUID;
+
+ // Statistics.
+ unsigned NumDirLookups, NumFileLookups;
+ unsigned NumDirCacheMisses, NumFileCacheMisses;
+
+ // Caching.
+ llvm::OwningPtr<StatSysCallCache> StatCache;
+
+ int stat_cached(const char* path, struct stat* buf) {
+ return StatCache.get() ? StatCache->stat(path, buf) : stat(path, buf);
+ }
+
+public:
+ FileManager();
+ ~FileManager();
+
+ /// setStatCache - Installs the provided StatSysCallCache object within
+ /// the FileManager. Ownership of this object is transferred to the
+ /// FileManager.
+ void setStatCache(StatSysCallCache *statCache) {
+ StatCache.reset(statCache);
+ }
+
+ /// getDirectory - Lookup, cache, and verify the specified directory. This
+ /// returns null if the directory doesn't exist.
+ ///
+ const DirectoryEntry *getDirectory(const std::string &Filename) {
+ return getDirectory(&Filename[0], &Filename[0] + Filename.size());
+ }
+ const DirectoryEntry *getDirectory(const char *FileStart,const char *FileEnd);
+
+ /// getFile - Lookup, cache, and verify the specified file. This returns null
+ /// if the file doesn't exist.
+ ///
+ const FileEntry *getFile(const std::string &Filename) {
+ return getFile(&Filename[0], &Filename[0] + Filename.size());
+ }
+ const FileEntry *getFile(const char *FilenameStart,
+ const char *FilenameEnd);
+
+ void PrintStats() const;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
new file mode 100644
index 000000000000..57cd31163144
--- /dev/null
+++ b/include/clang/Basic/IdentifierTable.h
@@ -0,0 +1,561 @@
+//===--- IdentifierTable.h - Hash table for identifier lookup ---*- 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 IdentifierInfo, IdentifierTable, and Selector
+// interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_IDENTIFIERTABLE_H
+#define LLVM_CLANG_BASIC_IDENTIFIERTABLE_H
+
+#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/TokenKinds.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
+#include <string>
+#include <cassert>
+
+namespace llvm {
+ template <typename T> struct DenseMapInfo;
+}
+
+namespace clang {
+ class LangOptions;
+ class IdentifierInfo;
+ class IdentifierTable;
+ class SourceLocation;
+ class MultiKeywordSelector; // private class used by Selector
+ class DeclarationName; // AST class that stores declaration names
+
+ /// IdentifierLocPair - A simple pair of identifier info and location.
+ typedef std::pair<IdentifierInfo*, SourceLocation> IdentifierLocPair;
+
+
+/// IdentifierInfo - One of these records is kept for each identifier that
+/// is lexed. This contains information about whether the token was #define'd,
+/// is a language keyword, or if it is a front-end token of some sort (e.g. a
+/// variable or function name). The preprocessor keeps this information in a
+/// 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.
+ // 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 :10;
+ bool HasMacro : 1; // True if there is a #define for this.
+ bool IsExtension : 1; // True if identifier is a lang extension.
+ bool IsPoisoned : 1; // True if identifier is poisoned.
+ bool IsCPPOperatorKeyword : 1; // True if ident is a C++ operator keyword.
+ bool NeedsHandleIdentifier : 1; // See "RecomputeNeedsHandleIdentifier".
+ // 9 bits left in 32-bit word.
+ void *FETokenInfo; // Managed by the language front-end.
+ llvm::StringMapEntry<IdentifierInfo*> *Entry;
+
+ IdentifierInfo(const IdentifierInfo&); // NONCOPYABLE.
+ void operator=(const IdentifierInfo&); // NONASSIGNABLE.
+
+ friend class IdentifierTable;
+
+public:
+ IdentifierInfo();
+
+
+ /// isStr - Return true if this is the identifier for the specified string.
+ /// This is intended to be used for string literals only: II->isStr("foo").
+ template <std::size_t StrLen>
+ bool isStr(const char (&Str)[StrLen]) const {
+ return getLength() == StrLen-1 && !memcmp(getName(), Str, StrLen-1);
+ }
+
+ /// getName - Return the actual string for this identifier. The returned
+ /// string is properly null terminated.
+ ///
+ const char *getName() const {
+ if (Entry) return Entry->getKeyData();
+ // FIXME: This is gross. It would be best not to embed specific details
+ // of the PTH file format here.
+ // The 'this' pointer really points to a
+ // std::pair<IdentifierInfo, const char*>, where internal pointer
+ // points to the external string data.
+ return ((std::pair<IdentifierInfo, const char*>*) this)->second;
+ }
+
+ /// getLength - Efficiently return the length of this identifier info.
+ ///
+ unsigned getLength() const {
+ if (Entry) return Entry->getKeyLength();
+ // FIXME: This is gross. It would be best not to embed specific details
+ // of the PTH file format here.
+ // The 'this' pointer really points to a
+ // std::pair<IdentifierInfo, const char*>, where internal pointer
+ // points to the external string data.
+ const char* p = ((std::pair<IdentifierInfo, const char*>*) this)->second-2;
+ return (((unsigned) p[0])
+ | (((unsigned) p[1]) << 8)) - 1;
+ }
+
+ /// hasMacroDefinition - Return true if this identifier is #defined to some
+ /// other value.
+ bool hasMacroDefinition() const {
+ return HasMacro;
+ }
+ void setHasMacroDefinition(bool Val) {
+ if (HasMacro == Val) return;
+
+ HasMacro = Val;
+ if (Val)
+ NeedsHandleIdentifier = 1;
+ else
+ RecomputeNeedsHandleIdentifier();
+ }
+
+ /// get/setTokenID - If this is a source-language token (e.g. 'for'), this API
+ /// can be used to cause the lexer to map identifiers to source-language
+ /// tokens.
+ tok::TokenKind getTokenID() const { return (tok::TokenKind)TokenID; }
+ void setTokenID(tok::TokenKind ID) { TokenID = ID; }
+
+ /// getPPKeywordID - Return the preprocessor keyword ID for this identifier.
+ /// For example, "define" will return tok::pp_define.
+ tok::PPKeywordKind getPPKeywordID() const;
+
+ /// getObjCKeywordID - Return the Objective-C keyword ID for the this
+ /// identifier. For example, 'class' will return tok::objc_class if ObjC is
+ /// enabled.
+ tok::ObjCKeywordKind getObjCKeywordID() const {
+ if (ObjCOrBuiltinID < tok::NUM_OBJC_KEYWORDS)
+ return tok::ObjCKeywordKind(ObjCOrBuiltinID);
+ else
+ return tok::objc_not_keyword;
+ }
+ void setObjCKeywordID(tok::ObjCKeywordKind ID) { ObjCOrBuiltinID = ID; }
+
+ /// getBuiltinID - Return a value indicating whether this is a builtin
+ /// function. 0 is not-built-in. 1 is builtin-for-some-nonprimary-target.
+ /// 2+ are specific builtin functions.
+ unsigned getBuiltinID() const {
+ if (ObjCOrBuiltinID >= tok::NUM_OBJC_KEYWORDS)
+ return ObjCOrBuiltinID - tok::NUM_OBJC_KEYWORDS;
+ else
+ return 0;
+ }
+ void setBuiltinID(unsigned ID) {
+ ObjCOrBuiltinID = ID + tok::NUM_OBJC_KEYWORDS;
+ assert(ObjCOrBuiltinID - unsigned(tok::NUM_OBJC_KEYWORDS) == ID
+ && "ID too large for field!");
+ }
+
+ unsigned getObjCOrBuiltinID() const { return ObjCOrBuiltinID; }
+ void setObjCOrBuiltinID(unsigned ID) { ObjCOrBuiltinID = ID; }
+
+ /// get/setExtension - Initialize information about whether or not this
+ /// language token is an extension. This controls extension warnings, and is
+ /// only valid if a custom token ID is set.
+ bool isExtensionToken() const { return IsExtension; }
+ void setIsExtensionToken(bool Val) {
+ IsExtension = 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) {
+ IsPoisoned = Value;
+ if (Value)
+ NeedsHandleIdentifier = 1;
+ else
+ RecomputeNeedsHandleIdentifier();
+ }
+
+ /// isPoisoned - Return true if this token has been poisoned.
+ bool isPoisoned() const { return IsPoisoned; }
+
+ /// isCPlusPlusOperatorKeyword/setIsCPlusPlusOperatorKeyword controls whether
+ /// this identifier is a C++ alternate representation of an operator.
+ void setIsCPlusPlusOperatorKeyword(bool Val = true) {
+ IsCPPOperatorKeyword = Val;
+ if (Val)
+ NeedsHandleIdentifier = 1;
+ else
+ RecomputeNeedsHandleIdentifier();
+ }
+ bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; }
+
+ /// getFETokenInfo/setFETokenInfo - The language front-end is allowed to
+ /// associate arbitrary metadata with this token.
+ template<typename T>
+ T *getFETokenInfo() const { return static_cast<T*>(FETokenInfo); }
+ void setFETokenInfo(void *T) { FETokenInfo = T; }
+
+ /// isHandleIdentifierCase - Return true if the Preprocessor::HandleIdentifier
+ /// must be called on a token of this identifier. If this returns false, we
+ /// know that HandleIdentifier will not affect the token.
+ bool isHandleIdentifierCase() const { return NeedsHandleIdentifier; }
+
+private:
+ /// RecomputeNeedsHandleIdentifier - The Preprocessor::HandleIdentifier does
+ /// several special (but rare) things to identifiers of various sorts. For
+ /// example, it changes the "for" keyword token from tok::identifier to
+ /// tok::for.
+ ///
+ /// This method is very tied to the definition of HandleIdentifier. Any
+ /// change to it should be reflected here.
+ void RecomputeNeedsHandleIdentifier() {
+ NeedsHandleIdentifier =
+ (isPoisoned() | hasMacroDefinition() | isCPlusPlusOperatorKeyword() |
+ isExtensionToken());
+ }
+};
+
+/// IdentifierInfoLookup - An abstract class used by IdentifierTable that
+/// provides an interface for performing lookups from strings
+/// (const char *) to IdentiferInfo objects.
+class IdentifierInfoLookup {
+public:
+ virtual ~IdentifierInfoLookup();
+
+ /// get - Return the identifier token info for the specified named identifier.
+ /// Unlike the version in IdentifierTable, this returns a pointer instead
+ /// of a reference. If the pointer is NULL then the IdentifierInfo cannot
+ /// be found.
+ virtual IdentifierInfo* get(const char *NameStart, const char *NameEnd) = 0;
+};
+
+/// \brief An abstract class used to resolve numerical identifier
+/// references (meaningful only to some external source) into
+/// IdentifierInfo pointers.
+class ExternalIdentifierLookup {
+public:
+ virtual ~ExternalIdentifierLookup();
+
+ /// \brief Return the identifier associated with the given ID number.
+ ///
+ /// The ID 0 is associated with the NULL identifier.
+ virtual IdentifierInfo *GetIdentifier(unsigned ID) = 0;
+};
+
+/// IdentifierTable - This table implements an efficient mapping from strings to
+/// IdentifierInfo nodes. It has no other purpose, but this is an
+/// extremely performance-critical piece of the code, as each occurrance of
+/// every identifier goes through here when lexed.
+class IdentifierTable {
+ // Shark shows that using MallocAllocator is *much* slower than using this
+ // BumpPtrAllocator!
+ typedef llvm::StringMap<IdentifierInfo*, llvm::BumpPtrAllocator> HashTableTy;
+ HashTableTy HashTable;
+
+ IdentifierInfoLookup* ExternalLookup;
+
+public:
+ /// IdentifierTable ctor - Create the identifier table, populating it with
+ /// info about the language keywords for the language specified by LangOpts.
+ IdentifierTable(const LangOptions &LangOpts,
+ IdentifierInfoLookup* externalLookup = 0);
+
+ /// \brief Set the external identifier lookup mechanism.
+ void setExternalIdentifierLookup(IdentifierInfoLookup *IILookup) {
+ ExternalLookup = IILookup;
+ }
+
+ llvm::BumpPtrAllocator& getAllocator() {
+ return HashTable.getAllocator();
+ }
+
+ /// get - Return the identifier token info for the specified named identifier.
+ ///
+ IdentifierInfo &get(const char *NameStart, const char *NameEnd) {
+ llvm::StringMapEntry<IdentifierInfo*> &Entry =
+ HashTable.GetOrCreateValue(NameStart, NameEnd);
+
+ IdentifierInfo *II = Entry.getValue();
+ if (II) return *II;
+
+ // No entry; if we have an external lookup, look there first.
+ if (ExternalLookup) {
+ II = ExternalLookup->get(NameStart, NameEnd);
+ if (II) {
+ // Cache in the StringMap for subsequent lookups.
+ Entry.setValue(II);
+ return *II;
+ }
+ }
+
+ // Lookups failed, make a new IdentifierInfo.
+ void *Mem = getAllocator().Allocate<IdentifierInfo>();
+ II = new (Mem) IdentifierInfo();
+ Entry.setValue(II);
+
+ // Make sure getName() knows how to find the IdentifierInfo
+ // contents.
+ II->Entry = &Entry;
+
+ return *II;
+ }
+
+ /// \brief Creates a new IdentifierInfo from the given string.
+ ///
+ /// This is a lower-level version of get() that requires that this
+ /// identifier not be known previously and that does not consult an
+ /// external source for identifiers. In particular, external
+ /// identifier sources can use this routine to build IdentifierInfo
+ /// nodes and then introduce additional information about those
+ /// identifiers.
+ IdentifierInfo &CreateIdentifierInfo(const char *NameStart,
+ const char *NameEnd) {
+ llvm::StringMapEntry<IdentifierInfo*> &Entry =
+ HashTable.GetOrCreateValue(NameStart, NameEnd);
+
+ IdentifierInfo *II = Entry.getValue();
+ assert(!II && "IdentifierInfo already exists");
+
+ // Lookups failed, make a new IdentifierInfo.
+ void *Mem = getAllocator().Allocate<IdentifierInfo>();
+ II = new (Mem) IdentifierInfo();
+ Entry.setValue(II);
+
+ // Make sure getName() knows how to find the IdentifierInfo
+ // contents.
+ II->Entry = &Entry;
+
+ return *II;
+ }
+
+ IdentifierInfo &get(const char *Name) {
+ return get(Name, Name+strlen(Name));
+ }
+ IdentifierInfo &get(const std::string &Name) {
+ // Don't use c_str() here: no need to be null terminated.
+ const char *NameBytes = Name.data();
+ return get(NameBytes, NameBytes+Name.size());
+ }
+
+ typedef HashTableTy::const_iterator iterator;
+ typedef HashTableTy::const_iterator const_iterator;
+
+ iterator begin() const { return HashTable.begin(); }
+ iterator end() const { return HashTable.end(); }
+ unsigned size() const { return HashTable.size(); }
+
+ /// PrintStats - Print some statistics to stderr that indicate how well the
+ /// hashing is doing.
+ void PrintStats() const;
+
+ void AddKeywords(const LangOptions &LangOpts);
+};
+
+/// Selector - This smart pointer class efficiently represents Objective-C
+/// method names. This class will either point to an IdentifierInfo or a
+/// MultiKeywordSelector (which is private). This enables us to optimize
+/// 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;
+
+ enum IdentifierInfoFlag {
+ // MultiKeywordSelector = 0.
+ ZeroArg = 0x1,
+ OneArg = 0x2,
+ ArgFlags = ZeroArg|OneArg
+ };
+ uintptr_t InfoPtr; // a pointer to the MultiKeywordSelector or IdentifierInfo.
+
+ Selector(IdentifierInfo *II, unsigned nArgs) {
+ InfoPtr = reinterpret_cast<uintptr_t>(II);
+ assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo");
+ assert(nArgs < 2 && "nArgs not equal to 0/1");
+ InfoPtr |= nArgs+1;
+ }
+ Selector(MultiKeywordSelector *SI) {
+ InfoPtr = reinterpret_cast<uintptr_t>(SI);
+ assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo");
+ }
+
+ IdentifierInfo *getAsIdentifierInfo() const {
+ if (getIdentifierInfoFlag())
+ return reinterpret_cast<IdentifierInfo *>(InfoPtr & ~ArgFlags);
+ return 0;
+ }
+ unsigned getIdentifierInfoFlag() const {
+ return InfoPtr & ArgFlags;
+ }
+
+public:
+ friend class SelectorTable; // only the SelectorTable can create these
+ friend class DeclarationName; // and the AST's DeclarationName.
+
+ /// The default ctor should only be used when creating data structures that
+ /// will contain selectors.
+ Selector() : InfoPtr(0) {}
+ Selector(uintptr_t V) : InfoPtr(V) {}
+
+ /// operator==/!= - Indicate whether the specified selectors are identical.
+ bool operator==(Selector RHS) const {
+ return InfoPtr == RHS.InfoPtr;
+ }
+ bool operator!=(Selector RHS) const {
+ return InfoPtr != RHS.InfoPtr;
+ }
+ void *getAsOpaquePtr() const {
+ return reinterpret_cast<void*>(InfoPtr);
+ }
+
+ /// \brief Determine whether this is the empty selector.
+ bool isNull() const { return InfoPtr == 0; }
+
+ // Predicates to identify the selector type.
+ bool isKeywordSelector() const {
+ return getIdentifierInfoFlag() != ZeroArg;
+ }
+ bool isUnarySelector() const {
+ return getIdentifierInfoFlag() == ZeroArg;
+ }
+ unsigned getNumArgs() const;
+ IdentifierInfo *getIdentifierInfoForSlot(unsigned argIndex) const;
+
+ /// getAsString - Derive the full selector name (e.g. "foo:bar:") and return
+ /// it as an std::string.
+ std::string getAsString() const;
+
+ static Selector getEmptyMarker() {
+ return Selector(uintptr_t(-1));
+ }
+ static Selector getTombstoneMarker() {
+ return Selector(uintptr_t(-2));
+ }
+};
+
+/// SelectorTable - This table allows us to fully hide how we implement
+/// multi-keyword caching.
+class SelectorTable {
+ void *Impl; // Actually a SelectorTableImpl
+ SelectorTable(const SelectorTable&); // DISABLED: DO NOT IMPLEMENT
+ void operator=(const SelectorTable&); // DISABLED: DO NOT IMPLEMENT
+public:
+ SelectorTable();
+ ~SelectorTable();
+
+ /// getSelector - This can create any sort of selector. NumArgs indicates
+ /// whether this is a no argument selector "foo", a single argument selector
+ /// "foo:" or multi-argument "foo:bar:".
+ Selector getSelector(unsigned NumArgs, IdentifierInfo **IIV);
+
+ Selector getUnarySelector(IdentifierInfo *ID) {
+ return Selector(ID, 1);
+ }
+ Selector getNullarySelector(IdentifierInfo *ID) {
+ return Selector(ID, 0);
+ }
+
+ /// constructSetterName - Return the setter name for the given
+ /// identifier, i.e. "set" + Name where the initial character of Name
+ /// has been capitalized.
+ static Selector constructSetterName(IdentifierTable &Idents,
+ SelectorTable &SelTable,
+ const IdentifierInfo *Name) {
+ llvm::SmallString<100> SelectorName;
+ SelectorName = "set";
+ SelectorName.append(Name->getName(), Name->getName()+Name->getLength());
+ SelectorName[3] = toupper(SelectorName[3]);
+ IdentifierInfo *SetterName =
+ &Idents.get(SelectorName.data(),
+ SelectorName.data() + SelectorName.size());
+ return SelTable.getUnarySelector(SetterName);
+ }
+};
+
+/// DeclarationNameExtra - Common base of the MultiKeywordSelector,
+/// CXXSpecialName, and CXXOperatorIdName classes, all of which are
+/// private classes that describe different kinds of names.
+class DeclarationNameExtra {
+public:
+ /// ExtraKind - The kind of "extra" information stored in the
+ /// DeclarationName. See @c ExtraKindOrNumArgs for an explanation of
+ /// how these enumerator values are used.
+ enum ExtraKind {
+ CXXConstructor = 0,
+ CXXDestructor,
+ CXXConversionFunction,
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ CXXOperator##Name,
+#include "clang/Basic/OperatorKinds.def"
+ CXXUsingDirective,
+ NUM_EXTRA_KINDS
+ };
+
+ /// ExtraKindOrNumArgs - Either the kind of C++ special name or
+ /// operator-id (if the value is one of the CXX* enumerators of
+ /// ExtraKind), in which case the DeclarationNameExtra is also a
+ /// CXXSpecialName (for CXXConstructor, CXXDestructor, or
+ /// CXXConversionFunction) or CXXOperatorIdName, it may be also
+ /// name common to C++ using-directives (CXXUsingDirective), otherwise
+ /// it is NUM_EXTRA_KINDS+NumArgs, where NumArgs is the number of
+ /// arguments in the Objective-C selector, in which case the
+ /// DeclarationNameExtra is also a MultiKeywordSelector.
+ unsigned ExtraKindOrNumArgs;
+};
+
+} // end namespace clang
+
+namespace llvm {
+/// Define DenseMapInfo so that Selectors can be used as keys in DenseMap and
+/// DenseSets.
+template <>
+struct DenseMapInfo<clang::Selector> {
+ static inline clang::Selector getEmptyKey() {
+ return clang::Selector::getEmptyMarker();
+ }
+ static inline clang::Selector getTombstoneKey() {
+ return clang::Selector::getTombstoneMarker();
+ }
+
+ static unsigned getHashValue(clang::Selector S);
+
+ static bool isEqual(clang::Selector LHS, clang::Selector RHS) {
+ return LHS == RHS;
+ }
+
+ static bool isPod() { return true; }
+};
+
+// Provide PointerLikeTypeTraits for IdentifierInfo pointers, which
+// are not guaranteed to be 8-byte aligned.
+template<>
+class PointerLikeTypeTraits<clang::IdentifierInfo*> {
+public:
+ static inline void *getAsVoidPointer(clang::IdentifierInfo* P) {
+ return P;
+ }
+ static inline clang::IdentifierInfo *getFromVoidPointer(void *P) {
+ return static_cast<clang::IdentifierInfo*>(P);
+ }
+ enum { NumLowBitsAvailable = 1 };
+};
+
+template<>
+class PointerLikeTypeTraits<const clang::IdentifierInfo*> {
+public:
+ static inline const void *getAsVoidPointer(const clang::IdentifierInfo* P) {
+ return P;
+ }
+ static inline const clang::IdentifierInfo *getFromVoidPointer(const void *P) {
+ return static_cast<const clang::IdentifierInfo*>(P);
+ }
+ enum { NumLowBitsAvailable = 1 };
+};
+
+} // end namespace llvm
+#endif
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
new file mode 100644
index 000000000000..92370cdd9efc
--- /dev/null
+++ b/include/clang/Basic/LangOptions.h
@@ -0,0 +1,157 @@
+//===--- LangOptions.h - 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 interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LANGOPTIONS_H
+#define LLVM_CLANG_LANGOPTIONS_H
+
+namespace clang {
+
+/// LangOptions - This class keeps track of the various options that can be
+/// 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 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 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 Microsoft : 1; // Microsoft 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 ObjCSenderDispatch: 1; // Objective-C 2 three-dimensional dispatch
+ // enabled.
+ unsigned ObjCNonFragileABI : 1; // Objective-C modern abi enabled
+
+ unsigned PascalStrings : 1; // Allow Pascal strings
+ unsigned WritableStrings : 1; // Allow writable strings
+ unsigned LaxVectorConversions : 1;
+ unsigned Exceptions : 1; // Support exception handling.
+
+ 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 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 OverflowChecking : 1; // Extension to call a handler function when
+ // signed integer arithmetic overflows.
+
+ 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 ObjCGCBitmapPrint : 1; // Enable printing of gc's bitmap layout
+ // for __weak/__strong ivars.
+
+ unsigned AccessControl : 1; // Whether C++ access control should
+ // be enabled.
+private:
+ unsigned GC : 2; // Objective-C Garbage Collection modes. We declare
+ // this enum as unsigned because MSVC insists on making enums
+ // signed. Set/Query this value using accessors.
+ unsigned SymbolVisibility : 3; // Symbol's visibility.
+
+ /// The user provided name for the "main file", if non-null. This is
+ /// useful in situations where the input file name does not match
+ /// the original input file, for example with -save-temps.
+ const char *MainFileName;
+
+public:
+ unsigned InstantiationDepth; // Maximum template instantiation depth.
+
+ enum GCMode { NonGC, GCOnly, HybridGC };
+ enum VisibilityMode {
+ Default,
+ Protected,
+ Hidden
+ };
+
+ LangOptions() {
+ Trigraphs = BCPLComment = DollarIdents = AsmPreprocessor = 0;
+ GNUMode = ImplicitInt = Digraphs = 0;
+ HexFloats = 0;
+ GC = ObjC1 = ObjC2 = ObjCNonFragileABI = 0;
+ C99 = Microsoft = CPlusPlus = CPlusPlus0x = 0;
+ CXXOperatorNames = PascalStrings = WritableStrings = 0;
+ Exceptions = NeXTRuntime = Freestanding = NoBuiltin = 0;
+ LaxVectorConversions = 1;
+ HeinousExtensions = 0;
+
+ SymbolVisibility = (unsigned) Default;
+
+ // FIXME: The default should be 1.
+ ThreadsafeStatics = 0;
+ Blocks = 0;
+ EmitAllDecls = 0;
+ MathErrno = 1;
+
+ // FIXME: The default should be 1.
+ AccessControl = 0;
+
+ OverflowChecking = 0;
+ ObjCGCBitmapPrint = 0;
+ ObjCSenderDispatch = 0;
+
+ InstantiationDepth = 99;
+
+ Optimize = 0;
+ OptimizeSize = 0;
+
+ Static = 0;
+ PICLevel = 0;
+
+ GNUInline = 0;
+ NoInline = 0;
+
+ MainFileName = 0;
+ }
+
+ GCMode getGCMode() const { return (GCMode) GC; }
+ void setGCMode(GCMode m) { GC = (unsigned) m; }
+
+ const char *getMainFileName() const { return MainFileName; }
+ void setMainFileName(const char *Name) { MainFileName = Name; }
+
+ VisibilityMode getVisibilityMode() const {
+ return (VisibilityMode) SymbolVisibility;
+ }
+ void setVisibilityMode(VisibilityMode v) { SymbolVisibility = (unsigned) v; }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/Makefile b/include/clang/Basic/Makefile
new file mode 100644
index 000000000000..b08d61457b75
--- /dev/null
+++ b/include/clang/Basic/Makefile
@@ -0,0 +1,22 @@
+LEVEL = ../../../../..
+BUILT_SOURCES = DiagnosticAnalysisKinds.inc DiagnosticASTKinds.inc \
+ DiagnosticCommonKinds.inc DiagnosticDriverKinds.inc \
+ DiagnosticFrontendKinds.inc DiagnosticLexKinds.inc \
+ DiagnosticParseKinds.inc DiagnosticSemaKinds.inc \
+ DiagnosticGroups.inc
+
+TABLEGEN_INC_FILES_COMMON = 1
+
+include $(LEVEL)/Makefile.common
+
+$(ObjDir)/Diagnostic%Kinds.inc.tmp : Diagnostic.td DiagnosticGroups.td Diagnostic%Kinds.td $(TBLGEN)
+ $(Echo) "Building Clang $(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) diagnostic tables with tblgen"
+ $(Verb) -$(MKDIR) $(@D)
+ $(Verb) $(TableGen) -gen-clang-diags-defs -clang-component=$(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) -o $(call SYSPATH, $@) $<
+
+$(ObjDir)/DiagnosticGroups.inc.tmp : Diagnostic.td $(wildcard Diagnostic*.td) $(TBLGEN)
+ $(Echo) "Building Clang diagnostic groups with tblgen"
+ $(Verb) -$(MKDIR) $(@D)
+ $(Verb) $(TableGen) -gen-clang-diag-groups -o $(call SYSPATH, $@) $<
+
+
diff --git a/include/clang/Basic/OnDiskHashTable.h b/include/clang/Basic/OnDiskHashTable.h
new file mode 100644
index 000000000000..f54d67042c47
--- /dev/null
+++ b/include/clang/Basic/OnDiskHashTable.h
@@ -0,0 +1,362 @@
+//===--- OnDiskHashTable.h - On-Disk Hash Table Implementation --*- 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 facilities for reading and writing on-disk hash
+// tables.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_ON_DISK_HASH_TABLE_H
+#define LLVM_CLANG_BASIC_ON_DISK_HASH_TABLE_H
+
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Host.h"
+#include <cassert>
+#include <cstdlib>
+
+namespace clang {
+
+// Bernstein hash function:
+// This is basically copy-and-paste from StringMap. This likely won't
+// stay here, which is why I didn't both to expose this function from
+// String Map.
+inline unsigned BernsteinHash(const char* x) {
+ unsigned int R = 0;
+ for ( ; *x != '\0' ; ++x) R = R * 33 + *x;
+ return R + (R >> 5);
+}
+
+inline unsigned BernsteinHash(const char* x, unsigned n) {
+ unsigned int R = 0;
+ for (unsigned i = 0 ; i < n ; ++i, ++x) R = R * 33 + *x;
+ return R + (R >> 5);
+}
+
+inline unsigned BernsteinHashPartial(const char* x, unsigned n, unsigned R) {
+ for (unsigned i = 0 ; i < n ; ++i, ++x) R = R * 33 + *x;
+ return R + (R >> 5);
+}
+
+namespace io {
+
+typedef uint32_t Offset;
+
+inline void Emit8(llvm::raw_ostream& Out, uint32_t V) {
+ Out << (unsigned char)(V);
+}
+
+inline void Emit16(llvm::raw_ostream& Out, uint32_t V) {
+ Out << (unsigned char)(V);
+ Out << (unsigned char)(V >> 8);
+ assert((V >> 16) == 0);
+}
+
+inline void Emit32(llvm::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) {
+ Out << (unsigned char)(V);
+ Out << (unsigned char)(V >> 8);
+ Out << (unsigned char)(V >> 16);
+ Out << (unsigned char)(V >> 24);
+ Out << (unsigned char)(V >> 32);
+ Out << (unsigned char)(V >> 40);
+ Out << (unsigned char)(V >> 48);
+ Out << (unsigned char)(V >> 56);
+}
+
+inline void Pad(llvm::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)
+ Emit8(Out, 0);
+}
+
+inline uint16_t ReadUnalignedLE16(const unsigned char *&Data) {
+ uint16_t V = ((uint16_t)Data[0]) |
+ ((uint16_t)Data[1] << 8);
+ Data += 2;
+ return V;
+}
+
+inline uint32_t ReadUnalignedLE32(const unsigned char *&Data) {
+ uint32_t V = ((uint32_t)Data[0]) |
+ ((uint32_t)Data[1] << 8) |
+ ((uint32_t)Data[2] << 16) |
+ ((uint32_t)Data[3] << 24);
+ Data += 4;
+ return V;
+}
+
+inline uint64_t ReadUnalignedLE64(const unsigned char *&Data) {
+ uint64_t V = ((uint64_t)Data[0]) |
+ ((uint64_t)Data[1] << 8) |
+ ((uint64_t)Data[2] << 16) |
+ ((uint64_t)Data[3] << 24) |
+ ((uint64_t)Data[4] << 32) |
+ ((uint64_t)Data[5] << 40) |
+ ((uint64_t)Data[6] << 48) |
+ ((uint64_t)Data[7] << 56);
+ Data += 8;
+ return V;
+}
+
+inline uint32_t ReadLE32(const unsigned char *&Data) {
+ // Hosts that directly support little-endian 32-bit loads can just
+ // use them. Big-endian hosts need a bswap.
+ uint32_t V = *((uint32_t*)Data);
+ if (llvm::sys::isBigEndianHost())
+ V = llvm::ByteSwap_32(V);
+ Data += 4;
+ return V;
+}
+
+} // end namespace io
+
+template<typename Info>
+class OnDiskChainedHashTableGenerator {
+ unsigned NumBuckets;
+ unsigned NumEntries;
+ llvm::BumpPtrAllocator BA;
+
+ class Item {
+ public:
+ typename Info::key_type key;
+ typename Info::data_type data;
+ Item *next;
+ const uint32_t hash;
+
+ Item(typename Info::key_type_ref k, typename Info::data_type_ref d)
+ : key(k), data(d), next(0), hash(Info::ComputeHash(k)) {}
+ };
+
+ class Bucket {
+ public:
+ io::Offset off;
+ Item* head;
+ unsigned length;
+
+ Bucket() {}
+ };
+
+ Bucket* Buckets;
+
+private:
+ void insert(Bucket* b, size_t size, Item* E) {
+ unsigned idx = E->hash & (size - 1);
+ Bucket& B = b[idx];
+ E->next = B.head;
+ ++B.length;
+ B.head = E;
+ }
+
+ void resize(size_t newsize) {
+ Bucket* newBuckets = (Bucket*) std::calloc(newsize, sizeof(Bucket));
+ // Populate newBuckets with the old entries.
+ for (unsigned i = 0; i < NumBuckets; ++i)
+ for (Item* E = Buckets[i].head; E ; ) {
+ Item* N = E->next;
+ E->next = 0;
+ insert(newBuckets, newsize, E);
+ E = N;
+ }
+
+ free(Buckets);
+ NumBuckets = newsize;
+ Buckets = newBuckets;
+ }
+
+public:
+
+ void insert(typename Info::key_type_ref key,
+ typename Info::data_type_ref data) {
+
+ ++NumEntries;
+ if (4*NumEntries >= 3*NumBuckets) resize(NumBuckets*2);
+ insert(Buckets, NumBuckets, new (BA.Allocate<Item>()) Item(key, data));
+ }
+
+ io::Offset Emit(llvm::raw_ostream &out) {
+ Info InfoObj;
+ return Emit(out, InfoObj);
+ }
+
+ io::Offset Emit(llvm::raw_ostream &out, Info &InfoObj) {
+ using namespace clang::io;
+
+ // Emit the payload of the table.
+ for (unsigned i = 0; i < NumBuckets; ++i) {
+ Bucket& B = Buckets[i];
+ if (!B.head) continue;
+
+ // Store the offset for the data of this bucket.
+ B.off = out.tell();
+ assert(B.off && "Cannot write a bucket at offset 0. Please add padding.");
+
+ // Write out the number of items in the bucket.
+ Emit16(out, B.length);
+
+ // Write out the entries in the bucket.
+ for (Item *I = B.head; I ; I = I->next) {
+ Emit32(out, I->hash);
+ const std::pair<unsigned, unsigned>& Len =
+ InfoObj.EmitKeyDataLength(out, I->key, I->data);
+ InfoObj.EmitKey(out, I->key, Len.first);
+ InfoObj.EmitData(out, I->key, I->data, Len.second);
+ }
+ }
+
+ // Emit the hashtable itself.
+ Pad(out, 4);
+ io::Offset TableOff = out.tell();
+ Emit32(out, NumBuckets);
+ Emit32(out, NumEntries);
+ for (unsigned i = 0; i < NumBuckets; ++i) Emit32(out, Buckets[i].off);
+
+ return TableOff;
+ }
+
+ OnDiskChainedHashTableGenerator() {
+ NumEntries = 0;
+ NumBuckets = 64;
+ // Note that we do not need to run the constructors of the individual
+ // Bucket objects since 'calloc' returns bytes that are all 0.
+ Buckets = (Bucket*) std::calloc(NumBuckets, sizeof(Bucket));
+ }
+
+ ~OnDiskChainedHashTableGenerator() {
+ std::free(Buckets);
+ }
+};
+
+template<typename Info>
+class OnDiskChainedHashTable {
+ const unsigned NumBuckets;
+ const unsigned NumEntries;
+ const unsigned char* const Buckets;
+ const unsigned char* const Base;
+ Info InfoObj;
+
+public:
+ typedef typename Info::internal_key_type internal_key_type;
+ typedef typename Info::external_key_type external_key_type;
+ typedef typename Info::data_type data_type;
+
+ OnDiskChainedHashTable(unsigned numBuckets, unsigned numEntries,
+ const unsigned char* buckets,
+ const unsigned char* base,
+ const Info &InfoObj = Info())
+ : NumBuckets(numBuckets), NumEntries(numEntries),
+ Buckets(buckets), Base(base), InfoObj(InfoObj) {
+ assert((reinterpret_cast<uintptr_t>(buckets) & 0x3) == 0 &&
+ "'buckets' must have a 4-byte alignment");
+ }
+
+ unsigned getNumBuckets() const { return NumBuckets; }
+ unsigned getNumEntries() const { return NumEntries; }
+ const unsigned char* getBase() const { return Base; }
+ const unsigned char* getBuckets() const { return Buckets; }
+
+ bool isEmpty() const { return NumEntries == 0; }
+
+ class iterator {
+ internal_key_type key;
+ const unsigned char* const data;
+ const unsigned len;
+ Info *InfoObj;
+ public:
+ iterator() : data(0), len(0) {}
+ iterator(const internal_key_type k, const unsigned char* d, unsigned l,
+ Info *InfoObj)
+ : key(k), data(d), len(l), InfoObj(InfoObj) {}
+
+ data_type operator*() const { return InfoObj->ReadData(key, data, len); }
+ bool operator==(const iterator& X) const { return X.data == data; }
+ bool operator!=(const iterator& X) const { return X.data != data; }
+ };
+
+ iterator find(const external_key_type& eKey, Info *InfoPtr = 0) {
+ if (!InfoPtr)
+ InfoPtr = &InfoObj;
+
+ using namespace io;
+ const internal_key_type& iKey = Info::GetInternalKey(eKey);
+ unsigned key_hash = Info::ComputeHash(iKey);
+
+ // Each bucket is just a 32-bit offset into the hash table file.
+ unsigned idx = key_hash & (NumBuckets - 1);
+ const unsigned char* Bucket = Buckets + sizeof(uint32_t)*idx;
+
+ unsigned offset = ReadLE32(Bucket);
+ if (offset == 0) return iterator(); // Empty bucket.
+ const unsigned char* Items = Base + offset;
+
+ // 'Items' starts with a 16-bit unsigned integer representing the
+ // number of items in this bucket.
+ unsigned len = ReadUnalignedLE16(Items);
+
+ for (unsigned i = 0; i < len; ++i) {
+ // Read the hash.
+ uint32_t item_hash = ReadUnalignedLE32(Items);
+
+ // Determine the length of the key and the data.
+ const std::pair<unsigned, unsigned>& L = Info::ReadKeyDataLength(Items);
+ unsigned item_len = L.first + L.second;
+
+ // Compare the hashes. If they are not the same, skip the entry entirely.
+ if (item_hash != key_hash) {
+ Items += item_len;
+ continue;
+ }
+
+ // Read the key.
+ const internal_key_type& X =
+ InfoPtr->ReadKey((const unsigned char* const) Items, L.first);
+
+ // If the key doesn't match just skip reading the value.
+ if (!Info::EqualKey(X, iKey)) {
+ Items += item_len;
+ continue;
+ }
+
+ // The key matches!
+ return iterator(X, Items + L.first, L.second, InfoPtr);
+ }
+
+ return iterator();
+ }
+
+ iterator end() const { return iterator(); }
+
+
+ static OnDiskChainedHashTable* Create(const unsigned char* buckets,
+ const unsigned char* const base,
+ const Info &InfoObj = Info()) {
+ using namespace io;
+ assert(buckets > base);
+ assert((reinterpret_cast<uintptr_t>(buckets) & 0x3) == 0 &&
+ "buckets should be 4-byte aligned.");
+
+ unsigned numBuckets = ReadLE32(buckets);
+ unsigned numEntries = ReadLE32(buckets);
+ return new OnDiskChainedHashTable<Info>(numBuckets, numEntries, buckets,
+ base, InfoObj);
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/OperatorKinds.def b/include/clang/Basic/OperatorKinds.def
new file mode 100644
index 000000000000..d011e9d39ff8
--- /dev/null
+++ b/include/clang/Basic/OperatorKinds.def
@@ -0,0 +1,106 @@
+//===--- OperatorKinds.def - C++ Overloaded Operator 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 OverloadedOperator database, which includes
+// all of the overloadable C++ operators.
+//
+//===----------------------------------------------------------------------===//
+//
+/// @file OperatorKinds.def
+///
+/// In this file, each of the overloadable C++ operators is enumerated
+/// with either the OVERLOADED_OPERATOR or OVERLOADED_OPERATOR_MULTI
+/// macro, each of which can be specified by the code including this
+/// file. OVERLOADED_OPERATOR is used for single-token operators
+/// (e.g., "+"), and has six arguments:
+///
+/// Name: The name of the token. OO_Name will be the name of the
+/// corresponding enumerator in OverloadedOperatorKind in
+/// OperatorKinds.h.
+///
+/// Spelling: A string that provides a canonical spelling for the
+/// operator, e.g., "operator+".
+///
+/// Token: The name of the token that specifies the operator, e.g.,
+/// "plus" for operator+ or "greatergreaterequal" for
+/// "operator>>=". With a "kw_" prefix, the token name can be used as
+/// an enumerator into the TokenKind enumeration.
+///
+/// Unary: True if the operator can be declared as a unary operator.
+///
+/// Binary: True if the operator can be declared as a binary
+/// operator. Note that some operators (e.g., "operator+" and
+/// "operator*") can be both unary and binary.
+///
+/// MemberOnly: True if this operator can only be declared as a
+/// non-static member function. False if the operator can be both a
+/// non-member function and a non-static member function.
+///
+/// OVERLOADED_OPERATOR_MULTI is used to enumerate the multi-token
+/// overloaded operator names, e.g., "operator delete []". The macro
+/// has all of the parameters of OVERLOADED_OPERATOR except Token,
+/// which is omitted.
+
+#ifndef OVERLOADED_OPERATOR
+# define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly)
+#endif
+
+#ifndef OVERLOADED_OPERATOR_MULTI
+# define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) \
+ OVERLOADED_OPERATOR(Name,Spelling,unknown,Unary,Binary,MemberOnly)
+#endif
+
+OVERLOADED_OPERATOR_MULTI(New , "new" , true , true , false)
+OVERLOADED_OPERATOR_MULTI(Delete , "delete" , true , true , false)
+OVERLOADED_OPERATOR_MULTI(Array_New , "new[]" , true , true , false)
+OVERLOADED_OPERATOR_MULTI(Array_Delete , "delete[]" , true , true , false)
+OVERLOADED_OPERATOR(Plus , "+" , plus , true , true , false)
+OVERLOADED_OPERATOR(Minus , "-" , minus , true , true , false)
+OVERLOADED_OPERATOR(Star , "*" , star , true , true , false)
+OVERLOADED_OPERATOR(Slash , "/" , slash , false, true , false)
+OVERLOADED_OPERATOR(Percent , "%" , percent , false, true , false)
+OVERLOADED_OPERATOR(Caret , "^" , caret , false, true , false)
+OVERLOADED_OPERATOR(Amp , "&" , amp , true , true , false)
+OVERLOADED_OPERATOR(Pipe , "|" , pipe , false, true , false)
+OVERLOADED_OPERATOR(Tilde , "~" , tilde , true , false, false)
+OVERLOADED_OPERATOR(Exclaim , "!" , exclaim , true , false, false)
+OVERLOADED_OPERATOR(Equal , "=" , equal , false, true , true)
+OVERLOADED_OPERATOR(Less , "<" , less , false, true , false)
+OVERLOADED_OPERATOR(Greater , ">" , greater , false, true , false)
+OVERLOADED_OPERATOR(PlusEqual , "+=" , plusequal , false, true , false)
+OVERLOADED_OPERATOR(MinusEqual , "-=" , minusequal , false, true , false)
+OVERLOADED_OPERATOR(StarEqual , "*=" , starequal , false, true , false)
+OVERLOADED_OPERATOR(SlashEqual , "/=" , slashequal , false, true , false)
+OVERLOADED_OPERATOR(PercentEqual , "%=" , percentequal , false, true , false)
+OVERLOADED_OPERATOR(CaretEqual , "^=" , caretequal , false, true , false)
+OVERLOADED_OPERATOR(AmpEqual , "&=" , ampequal , false, true , false)
+OVERLOADED_OPERATOR(PipeEqual , "|=" , pipeequal , false, true , false)
+OVERLOADED_OPERATOR(LessLess , "<<" , lessless , false, true , false)
+OVERLOADED_OPERATOR(GreaterGreater , ">>" , greatergreater , false, true , false)
+OVERLOADED_OPERATOR(LessLessEqual , "<<=" , lesslessequal , false, true , false)
+OVERLOADED_OPERATOR(GreaterGreaterEqual , ">>=" , greatergreaterequal, false, true , false)
+OVERLOADED_OPERATOR(EqualEqual , "==" , equalequal , false, true , false)
+OVERLOADED_OPERATOR(ExclaimEqual , "!=" , exclaimequal , false, true , false)
+OVERLOADED_OPERATOR(LessEqual , "<=" , lessequal , false, true , false)
+OVERLOADED_OPERATOR(GreaterEqual , ">=" , greaterequal , false, true , false)
+OVERLOADED_OPERATOR(AmpAmp , "&&" , ampamp , false, true , false)
+OVERLOADED_OPERATOR(PipePipe , "||" , pipepipe , false, true , false)
+OVERLOADED_OPERATOR(PlusPlus , "++" , plusplus , true , true , false)
+OVERLOADED_OPERATOR(MinusMinus , "--" , minusminus , true , true , false)
+OVERLOADED_OPERATOR(Comma , "," , comma , false, true , false)
+OVERLOADED_OPERATOR(ArrowStar , "->*" , arrowstar , false, true , false)
+OVERLOADED_OPERATOR(Arrow , "->" , arrow , true , false, true)
+OVERLOADED_OPERATOR_MULTI(Call , "()" , true , true , true)
+OVERLOADED_OPERATOR_MULTI(Subscript , "[]" , false, true , true)
+// ?: can *not* be overloaded, but we need the overload
+// resolution machinery for it.
+OVERLOADED_OPERATOR_MULTI(Conditional , "?" , false, true , false)
+
+#undef OVERLOADED_OPERATOR_MULTI
+#undef OVERLOADED_OPERATOR
diff --git a/include/clang/Basic/OperatorKinds.h b/include/clang/Basic/OperatorKinds.h
new file mode 100644
index 000000000000..790b75ba3af3
--- /dev/null
+++ b/include/clang/Basic/OperatorKinds.h
@@ -0,0 +1,32 @@
+//===--- OperatorKinds.h - C++ Overloaded Operators -------------*- 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 C++ overloaded operators.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_OPERATOR_KINDS_H
+#define LLVM_CLANG_BASIC_OPERATOR_KINDS_H
+
+namespace clang {
+
+/// OverloadedOperatorKind - Enumeration specifying the different kinds of
+/// C++ overloaded operators.
+enum OverloadedOperatorKind {
+ OO_None, //< Not an overloaded operator
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ OO_##Name,
+#include "clang/Basic/OperatorKinds.def"
+ NUM_OVERLOADED_OPERATORS
+};
+
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/PrettyStackTrace.h b/include/clang/Basic/PrettyStackTrace.h
new file mode 100644
index 000000000000..5a5d55192b69
--- /dev/null
+++ b/include/clang/Basic/PrettyStackTrace.h
@@ -0,0 +1,37 @@
+//===- clang/Basic/PrettyStackTrace.h - Pretty Crash Handling --*- 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 PrettyStackTraceEntry class, which is used to make
+// crashes give more contextual information about what the program was doing
+// when it crashed.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_BASIC_PRETTYSTACKTRACE_H
+#define CLANG_BASIC_PRETTYSTACKTRACE_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/Support/PrettyStackTrace.h"
+
+namespace clang {
+
+ /// PrettyStackTraceLoc - If a crash happens while one of these objects are
+ /// live, the message is printed out along with the specified source location.
+ class PrettyStackTraceLoc : public llvm::PrettyStackTraceEntry {
+ SourceManager &SM;
+ SourceLocation Loc;
+ const char *Message;
+ public:
+ PrettyStackTraceLoc(SourceManager &sm, SourceLocation L, const char *Msg)
+ : SM(sm), Loc(L), Message(Msg) {}
+ virtual void print(llvm::raw_ostream &OS) const;
+ };
+}
+
+#endif
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
new file mode 100644
index 000000000000..2405c2fe7db7
--- /dev/null
+++ b/include/clang/Basic/SourceLocation.h
@@ -0,0 +1,305 @@
+//===--- SourceLocation.h - Compact identifier for Source Files -*- 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 SourceLocation class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SOURCELOCATION_H
+#define LLVM_CLANG_SOURCELOCATION_H
+
+#include <utility>
+#include <cassert>
+
+namespace llvm {
+ class MemoryBuffer;
+ class raw_ostream;
+ template <typename T> struct DenseMapInfo;
+}
+
+namespace clang {
+
+class SourceManager;
+class FileEntry;
+
+/// FileID - This is an opaque identifier used by SourceManager which refers to
+/// a source file (MemoryBuffer) along with its #include path and #line data.
+///
+class FileID {
+ /// ID - Opaque identifier, 0 is "invalid".
+ unsigned ID;
+public:
+ FileID() : ID(0) {}
+
+ bool isInvalid() const { return ID == 0; }
+
+ bool operator==(const FileID &RHS) const { return ID == RHS.ID; }
+ bool operator<(const FileID &RHS) const { return ID < RHS.ID; }
+ bool operator<=(const FileID &RHS) const { return ID <= RHS.ID; }
+ bool operator!=(const FileID &RHS) const { return !(*this == RHS); }
+ 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; }
+
+private:
+ friend class SourceManager;
+ static FileID get(unsigned V) {
+ FileID F;
+ F.ID = V;
+ return F;
+ }
+ unsigned 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.
+class SourceLocation {
+ unsigned ID;
+ friend class SourceManager;
+ enum {
+ MacroIDBit = 1U << 31
+ };
+public:
+
+ SourceLocation() : ID(0) {} // 0 is an invalid FileID.
+
+ 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).
+ ///
+ 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.
+ unsigned getOffset() const {
+ return ID & ~MacroIDBit;
+ }
+
+ static SourceLocation getFileLoc(unsigned ID) {
+ assert((ID & MacroIDBit) == 0 && "Ran out of source locations!");
+ SourceLocation L;
+ L.ID = ID;
+ return L;
+ }
+
+ static SourceLocation getMacroLoc(unsigned ID) {
+ assert((ID & MacroIDBit) == 0 && "Ran out of source locations!");
+ SourceLocation L;
+ L.ID = MacroIDBit | ID;
+ return L;
+ }
+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");
+ SourceLocation L;
+ L.ID = ID+Offset;
+ return L;
+ }
+
+ /// getRawEncoding - When a SourceLocation itself cannot be used, this returns
+ /// an (opaque) 32-bit integer encoding for it. This should only be passed
+ /// to SourceLocation::getFromRawEncoding, it should not be inspected
+ /// directly.
+ unsigned getRawEncoding() const { return ID; }
+
+
+ /// getFromRawEncoding - Turn a raw encoding of a SourceLocation object into
+ /// a real SourceLocation.
+ static SourceLocation getFromRawEncoding(unsigned Encoding) {
+ SourceLocation X;
+ X.ID = Encoding;
+ return X;
+ }
+
+ void print(llvm::raw_ostream &OS, const SourceManager &SM) const;
+ void dump(const SourceManager &SM) const;
+};
+
+inline bool operator==(const SourceLocation &LHS, const SourceLocation &RHS) {
+ return LHS.getRawEncoding() == RHS.getRawEncoding();
+}
+
+inline bool operator!=(const SourceLocation &LHS, const SourceLocation &RHS) {
+ return !(LHS == RHS);
+}
+
+inline bool operator<(const SourceLocation &LHS, const SourceLocation &RHS) {
+ return LHS.getRawEncoding() < RHS.getRawEncoding();
+}
+
+/// SourceRange - a trival tuple used to represent a source range.
+class SourceRange {
+ SourceLocation B;
+ SourceLocation E;
+public:
+ SourceRange(): B(SourceLocation()), E(SourceLocation()) {}
+ SourceRange(SourceLocation loc) : B(loc), E(loc) {}
+ SourceRange(SourceLocation begin, SourceLocation end) : B(begin), E(end) {}
+
+ SourceLocation getBegin() const { return B; }
+ SourceLocation getEnd() const { return E; }
+
+ void setBegin(SourceLocation b) { B = b; }
+ void setEnd(SourceLocation e) { E = e; }
+
+ bool isValid() const { return B.isValid() && E.isValid(); }
+
+ bool operator==(const SourceRange &X) const {
+ return B == X.B && E == X.E;
+ }
+
+ bool operator!=(const SourceRange &X) const {
+ return B != X.B || E != X.E;
+ }
+};
+
+/// FullSourceLoc - A SourceLocation and its associated SourceManager. Useful
+/// for argument passing to functions that expect both objects.
+class FullSourceLoc : public SourceLocation {
+ SourceManager* SrcMgr;
+public:
+ /// Creates a FullSourceLoc where isValid() returns false.
+ explicit FullSourceLoc() : SrcMgr((SourceManager*) 0) {}
+
+ explicit FullSourceLoc(SourceLocation Loc, SourceManager &SM)
+ : SourceLocation(Loc), SrcMgr(&SM) {}
+
+ SourceManager &getManager() {
+ assert(SrcMgr && "SourceManager is NULL.");
+ return *SrcMgr;
+ }
+
+ const SourceManager &getManager() const {
+ assert(SrcMgr && "SourceManager is NULL.");
+ return *SrcMgr;
+ }
+
+ FileID getFileID() const;
+
+ FullSourceLoc getInstantiationLoc() const;
+ FullSourceLoc getSpellingLoc() const;
+
+ unsigned getInstantiationLineNumber() const;
+ unsigned getInstantiationColumnNumber() const;
+
+ unsigned getSpellingLineNumber() const;
+ unsigned getSpellingColumnNumber() const;
+
+ const char *getCharacterData() const;
+
+ const llvm::MemoryBuffer* getBuffer() const;
+
+ /// getBufferData - Return a pointer to the start and end of the source buffer
+ /// data for the specified FileID.
+ std::pair<const char*, const char*> getBufferData() const;
+
+ /// getDecomposedLoc - Decompose the specified location into a raw FileID +
+ /// Offset pair. The first element is the FileID, the second is the
+ /// offset from the start of the buffer of the location.
+ std::pair<FileID, unsigned> getDecomposedLoc() const;
+
+ bool isInSystemHeader() const;
+
+ /// Prints information about this FullSourceLoc to stderr. Useful for
+ /// debugging.
+ void dump() const { SourceLocation::dump(*SrcMgr); }
+
+ friend inline bool
+ operator==(const FullSourceLoc &LHS, const FullSourceLoc &RHS) {
+ return LHS.getRawEncoding() == RHS.getRawEncoding() &&
+ LHS.SrcMgr == RHS.SrcMgr;
+ }
+
+ friend inline bool
+ operator!=(const FullSourceLoc &LHS, const FullSourceLoc &RHS) {
+ return !(LHS == RHS);
+ }
+
+};
+
+/// 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.
+///
+/// You can get a PresumedLoc from a SourceLocation with SourceManager.
+class PresumedLoc {
+ const char *Filename;
+ unsigned Line, Col;
+ SourceLocation IncludeLoc;
+public:
+ PresumedLoc() : Filename(0) {}
+ PresumedLoc(const char *FN, unsigned Ln, unsigned Co, SourceLocation IL)
+ : Filename(FN), Line(Ln), Col(Co), IncludeLoc(IL) {
+ }
+
+ /// isInvalid - Return true if this object is invalid or uninitialized. This
+ /// occurs when created with invalid source locations or when walking off
+ /// the top of a #include stack.
+ bool isInvalid() const { return Filename == 0; }
+ bool isValid() const { return Filename != 0; }
+
+ /// getFilename - Return the presumed filename of this location. This can be
+ /// affected by #line etc.
+ const char *getFilename() const { return Filename; }
+
+ /// getLine - Return the presumed line number of this location. This can be
+ /// affected by #line etc.
+ unsigned getLine() const { return Line; }
+
+ /// getColumn - Return the presumed column number of this location. This can
+ /// not be affected by #line, but is packaged here for convenience.
+ unsigned getColumn() const { return Col; }
+
+ /// getIncludeLoc - Return the presumed include location of this location.
+ /// This can be affected by GNU linemarker directives.
+ SourceLocation getIncludeLoc() const { return IncludeLoc; }
+};
+
+
+} // end namespace clang
+
+namespace llvm {
+ /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and
+ /// DenseSets.
+ template <>
+ struct DenseMapInfo<clang::FileID> {
+ static inline clang::FileID getEmptyKey() {
+ return clang::FileID();
+ }
+ static inline clang::FileID getTombstoneKey() {
+ return clang::FileID::getSentinel();
+ }
+
+ static unsigned getHashValue(clang::FileID S) {
+ return S.getHashValue();
+ }
+
+ static bool isEqual(clang::FileID LHS, clang::FileID RHS) {
+ return LHS == RHS;
+ }
+
+ static bool isPod() { return true; }
+ };
+
+} // end namespace llvm
+
+#endif
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
new file mode 100644
index 000000000000..43369829387d
--- /dev/null
+++ b/include/clang/Basic/SourceManager.h
@@ -0,0 +1,714 @@
+//===--- SourceManager.h - Track and cache source files ---------*- 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 SourceManager interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SOURCEMANAGER_H
+#define LLVM_CLANG_SOURCEMANAGER_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/ADT/DenseMap.h"
+#include <vector>
+#include <cassert>
+
+namespace llvm {
+class MemoryBuffer;
+}
+
+namespace clang {
+
+class SourceManager;
+class FileManager;
+class FileEntry;
+class IdentifierTokenInfo;
+class LineTableInfo;
+
+/// SrcMgr - Public enums and private classes that are part of the
+/// SourceManager implementation.
+///
+namespace SrcMgr {
+ /// CharacteristicKind - This is used to represent whether a file or directory
+ /// 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.
+ ///
+ enum CharacteristicKind {
+ C_User, C_System, C_ExternCSystem
+ };
+
+ /// ContentCache - Once instance of this struct is kept for every file
+ /// loaded or used. This object owns the MemoryBuffer object.
+ class ContentCache {
+ /// Buffer - The actual buffer containing the characters from the input
+ /// file. This is owned by the ContentCache object.
+ mutable const llvm::MemoryBuffer *Buffer;
+
+ public:
+ /// Reference to the file entry. This reference does not own
+ /// the FileEntry object. It is possible for this to be NULL if
+ /// the ContentCache encapsulates an imaginary text buffer.
+ const FileEntry *Entry;
+
+ /// SourceLineCache - A bump pointer allocated array of offsets for each
+ /// source line. This is lazily computed. This is owned by the
+ /// SourceManager BumpPointerAllocator object.
+ unsigned *SourceLineCache;
+
+ /// NumLines - The number of lines in this ContentCache. This is only valid
+ /// if SourceLineCache is non-null.
+ unsigned NumLines;
+
+ /// getBuffer - Returns the memory buffer for the associated content.
+ const llvm::MemoryBuffer *getBuffer() const;
+
+ /// getSize - Returns the size of the content encapsulated by this
+ /// ContentCache. This can be the size of the source file or the size of an
+ /// arbitrary scratch buffer. If the ContentCache encapsulates a source
+ /// file this size is retrieved from the file's FileEntry.
+ 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.
+ unsigned getSizeBytesMapped() const;
+
+ void setBuffer(const llvm::MemoryBuffer *B) {
+ assert(!Buffer && "MemoryBuffer already set.");
+ Buffer = B;
+ }
+
+ ContentCache(const FileEntry *Ent = 0)
+ : Buffer(0), Entry(Ent), SourceLineCache(0), NumLines(0) {}
+
+ ~ContentCache();
+
+ /// The copy ctor does not allow copies where source object has either
+ /// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory
+ /// is not transfered, so this is a logical error.
+ ContentCache(const ContentCache &RHS) : Buffer(0), SourceLineCache(0) {
+ Entry = RHS.Entry;
+
+ assert (RHS.Buffer == 0 && RHS.SourceLineCache == 0
+ && "Passed ContentCache object cannot own a buffer.");
+
+ NumLines = RHS.NumLines;
+ }
+
+ private:
+ // Disable assignments.
+ ContentCache &operator=(const ContentCache& RHS);
+ };
+
+ /// FileInfo - Information about a FileID, basically just the logical file
+ /// 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.
+ ///
+ /// FileInfos contain a "ContentCache *", with the contents of the file.
+ ///
+ class FileInfo {
+ /// IncludeLoc - The location of the #include that brought in this file.
+ /// This is an invalid SLOC for the main file (top of the #include chain).
+ unsigned IncludeLoc; // Really a SourceLocation
+
+ /// 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;
+ public:
+ /// get - Return a FileInfo object.
+ static FileInfo get(SourceLocation IL, const ContentCache *Con,
+ CharacteristicKind FileCharacter) {
+ FileInfo X;
+ X.IncludeLoc = IL.getRawEncoding();
+ X.Data = (uintptr_t)Con;
+ assert((X.Data & 7) == 0 &&"ContentCache pointer insufficiently aligned");
+ assert((unsigned)FileCharacter < 4 && "invalid file character");
+ X.Data |= (unsigned)FileCharacter;
+ return X;
+ }
+
+ SourceLocation getIncludeLoc() const {
+ return SourceLocation::getFromRawEncoding(IncludeLoc);
+ }
+ const ContentCache* getContentCache() const {
+ return reinterpret_cast<const ContentCache*>(Data & ~7UL);
+ }
+
+ /// getCharacteristic - Return whether this is a system header or not.
+ CharacteristicKind getFileCharacteristic() const {
+ return (CharacteristicKind)(Data & 3);
+ }
+
+ /// hasLineDirectives - Return true if this FileID has #line directives in
+ /// it.
+ bool hasLineDirectives() const { return (Data & 4) != 0; }
+
+ /// setHasLineDirectives - Set the flag that indicates that this FileID has
+ /// line table entries associated with it.
+ void setHasLineDirectives() {
+ Data |= 4;
+ }
+ };
+
+ /// 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.
+
+ /// 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 ')'.
+ unsigned InstantiationLocStart, InstantiationLocEnd;
+ public:
+ SourceLocation getSpellingLoc() const {
+ return SourceLocation::getFromRawEncoding(SpellingLoc);
+ }
+ SourceLocation getInstantiationLocStart() const {
+ return SourceLocation::getFromRawEncoding(InstantiationLocStart);
+ }
+ SourceLocation getInstantiationLocEnd() const {
+ return SourceLocation::getFromRawEncoding(InstantiationLocEnd);
+ }
+
+ std::pair<SourceLocation,SourceLocation> getInstantiationLocRange() const {
+ return std::make_pair(getInstantiationLocStart(),
+ getInstantiationLocEnd());
+ }
+
+ /// get - Return a InstantiationInfo for an expansion. IL specifies
+ /// the instantiation location (where the macro is expanded), and SL
+ /// specifies the spelling location (where the characters from the token
+ /// come from). IL and PL can both refer to normal File SLocs or
+ /// instantiation locations.
+ static InstantiationInfo get(SourceLocation ILStart, SourceLocation ILEnd,
+ SourceLocation SL) {
+ InstantiationInfo X;
+ X.SpellingLoc = SL.getRawEncoding();
+ X.InstantiationLocStart = ILStart.getRawEncoding();
+ X.InstantiationLocEnd = ILEnd.getRawEncoding();
+ return X;
+ }
+ };
+
+ /// SLocEntry - This is a discriminated union of FileInfo and
+ /// InstantiationInfo. 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.
+ union {
+ FileInfo File;
+ InstantiationInfo Instantiation;
+ };
+ public:
+ unsigned getOffset() const { return Offset >> 1; }
+
+ bool isInstantiation() const { return Offset & 1; }
+ bool isFile() const { return !isInstantiation(); }
+
+ const FileInfo &getFile() const {
+ assert(isFile() && "Not a file SLocEntry!");
+ return File;
+ }
+
+ const InstantiationInfo &getInstantiation() const {
+ assert(isInstantiation() && "Not an instantiation SLocEntry!");
+ return Instantiation;
+ }
+
+ static SLocEntry get(unsigned Offset, const FileInfo &FI) {
+ SLocEntry E;
+ E.Offset = Offset << 1;
+ E.File = FI;
+ return E;
+ }
+
+ static SLocEntry get(unsigned Offset, const InstantiationInfo &II) {
+ SLocEntry E;
+ E.Offset = (Offset << 1) | 1;
+ E.Instantiation = II;
+ return E;
+ }
+ };
+} // end SrcMgr namespace.
+
+/// \brief External source of source location entries.
+class ExternalSLocEntrySource {
+public:
+ virtual ~ExternalSLocEntrySource();
+
+ /// \brief Read the source location entry with index ID.
+ virtual void ReadSLocEntry(unsigned ID) = 0;
+};
+
+/// SourceManager - This file 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.
+class SourceManager {
+ mutable llvm::BumpPtrAllocator ContentCacheAlloc;
+
+ /// FileInfos - Memoized information about all of the files tracked by this
+ /// SourceManager. This set allows us to merge ContentCache entries based
+ /// on their FileEntry*. All ContentCache objects will thus have unique,
+ /// non-null, FileEntry pointers.
+ llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> FileInfos;
+
+ /// MemBufferInfos - Information about various memory buffers that we have
+ /// read in. All FileEntry* within the stored ContentCache objects are NULL,
+ /// 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 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.
+ std::vector<bool> SLocEntryLoaded;
+
+ /// \brief An external source for source location entries.
+ ExternalSLocEntrySource *ExternalSLocEntries;
+
+ /// LastFileIDLookup - This is a one-entry cache to speed up getFileID.
+ /// LastFileIDLookup records the last FileID looked up or created, because it
+ /// is very common to look up many tokens from the same file.
+ mutable FileID LastFileIDLookup;
+
+ /// LineTable - This holds information for #line directives. It is referenced
+ /// by indices from SLocEntryTable.
+ LineTableInfo *LineTable;
+
+ /// LastLineNo - These ivars serve as a cache used in the getLineNumber
+ /// method which is used to speedup getLineNumber calls to nearby locations.
+ mutable FileID LastLineNoFileIDQuery;
+ mutable SrcMgr::ContentCache *LastLineNoContentCache;
+ mutable unsigned LastLineNoFilePos;
+ mutable unsigned LastLineNoResult;
+
+ /// MainFileID - The file ID for the main source file of the translation unit.
+ FileID MainFileID;
+
+ // Statistics for -print-stats.
+ mutable unsigned NumLinearScans, NumBinaryProbes;
+
+ // SourceManager doesn't support copy construction.
+ explicit SourceManager(const SourceManager&);
+ void operator=(const SourceManager&);
+public:
+ SourceManager()
+ : ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
+ NumBinaryProbes(0) {
+ clearIDTables();
+ }
+ ~SourceManager();
+
+ void clearIDTables();
+
+ //===--------------------------------------------------------------------===//
+ // MainFileID creation and querying methods.
+ //===--------------------------------------------------------------------===//
+
+ /// getMainFileID - Returns the FileID of the main source file.
+ FileID getMainFileID() const { return MainFileID; }
+
+ /// createMainFileID - Create the FileID for the main source file.
+ FileID createMainFileID(const FileEntry *SourceFile,
+ SourceLocation IncludePos) {
+ assert(MainFileID.isInvalid() && "MainFileID already set!");
+ MainFileID = createFileID(SourceFile, IncludePos, SrcMgr::C_User);
+ return MainFileID;
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Methods to create new FileID's and instantiations.
+ //===--------------------------------------------------------------------===//
+
+ /// createFileID - Create a new FileID that represents the specified file
+ /// being #included from the specified IncludePosition. This returns 0 on
+ /// error and translates NULL into standard input.
+ /// PreallocateID should be non-zero to specify which a 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) {
+ const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile);
+ if (IR == 0) return FileID(); // Error opening file?
+ return createFileID(IR, IncludePos, FileCharacter, PreallocatedID, Offset);
+ }
+
+ /// 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) {
+ return createFileID(createMemBufferContentCache(Buffer), SourceLocation(),
+ SrcMgr::C_User, PreallocatedID, Offset);
+ }
+
+ /// 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;
+ }
+
+ /// createInstantiationLoc - Return a new SourceLocation that encodes the fact
+ /// that a token at Loc should actually be referenced from InstantiationLoc.
+ /// TokLength is the length of the token being instantiated.
+ SourceLocation createInstantiationLoc(SourceLocation Loc,
+ SourceLocation InstantiationLocStart,
+ SourceLocation InstantiationLocEnd,
+ unsigned TokLength,
+ unsigned PreallocatedID = 0,
+ unsigned Offset = 0);
+
+ //===--------------------------------------------------------------------===//
+ // FileID manipulation methods.
+ //===--------------------------------------------------------------------===//
+
+ /// getBuffer - Return the buffer for the specified FileID.
+ ///
+ const llvm::MemoryBuffer *getBuffer(FileID FID) const {
+ return getSLocEntry(FID).getFile().getContentCache()->getBuffer();
+ }
+
+ /// getFileEntryForID - Returns the FileEntry record for the provided FileID.
+ const FileEntry *getFileEntryForID(FileID FID) const {
+ return getSLocEntry(FID).getFile().getContentCache()->Entry;
+ }
+
+ /// getBufferData - Return a pointer to the start and end of the source buffer
+ /// data for the specified FileID.
+ std::pair<const char*, const char*> getBufferData(FileID FID) const;
+
+
+ //===--------------------------------------------------------------------===//
+ // SourceLocation manipulation methods.
+ //===--------------------------------------------------------------------===//
+
+ /// getFileID - 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.
+ ///
+ FileID getFileID(SourceLocation SpellingLoc) const {
+ unsigned SLocOffset = SpellingLoc.getOffset();
+
+ // If our one-entry cache covers this offset, just return it.
+ if (isOffsetInFileID(LastFileIDLookup, SLocOffset))
+ return LastFileIDLookup;
+
+ return getFileIDSlow(SLocOffset);
+ }
+
+ /// 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");
+ assert(getSLocEntry(FID).isFile() && "FileID is not a file");
+ unsigned FileOffset = getSLocEntry(FID).getOffset();
+ return SourceLocation::getFileLoc(FileOffset);
+ }
+
+ /// getInstantiationLoc - Given a SourceLocation object, return the
+ /// instantiation location referenced by the ID.
+ SourceLocation getInstantiationLoc(SourceLocation Loc) const {
+ // Handle the non-mapped case inline, defer to out of line code to handle
+ // instantiations.
+ if (Loc.isFileID()) return Loc;
+ return getInstantiationLocSlowCase(Loc);
+ }
+
+ /// getImmediateInstantiationRange - Loc is required to be an instantiation
+ /// location. Return the start/end of the instantiation information.
+ std::pair<SourceLocation,SourceLocation>
+ getImmediateInstantiationRange(SourceLocation Loc) const;
+
+ /// getInstantiationRange - Given a SourceLocation object, return the
+ /// range of tokens covered by the instantiation in the ultimate file.
+ std::pair<SourceLocation,SourceLocation>
+ getInstantiationRange(SourceLocation Loc) const;
+
+
+ /// getSpellingLoc - Given a SourceLocation object, return the spelling
+ /// location referenced by the ID. This is the place where the characters
+ /// 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.
+ if (Loc.isFileID()) return Loc;
+ return getSpellingLocSlowCase(Loc);
+ }
+
+ /// getImmediateSpellingLoc - Given a SourceLocation object, return the
+ /// spelling location referenced by the ID. This is the first level down
+ /// towards the place where the characters that make up the lexed token can be
+ /// found. This should not generally be used by clients.
+ SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const;
+
+ /// getDecomposedLoc - Decompose the specified location into a raw FileID +
+ /// Offset pair. The first element is the FileID, the second is the
+ /// offset from the start of the buffer of the location.
+ std::pair<FileID, unsigned> getDecomposedLoc(SourceLocation Loc) const {
+ FileID FID = getFileID(Loc);
+ 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.
+ std::pair<FileID, unsigned>
+ getDecomposedInstantiationLoc(SourceLocation Loc) const {
+ FileID FID = getFileID(Loc);
+ const SrcMgr::SLocEntry *E = &getSLocEntry(FID);
+
+ unsigned Offset = Loc.getOffset()-E->getOffset();
+ if (Loc.isFileID())
+ return std::make_pair(FID, Offset);
+
+ return getDecomposedInstantiationLocSlowCase(E, Offset);
+ }
+
+ /// getDecomposedSpellingLoc - Decompose the specified location into a raw
+ /// FileID + Offset pair. If the location is an instantiation record, walk
+ /// through it until we find its spelling record.
+ std::pair<FileID, unsigned>
+ getDecomposedSpellingLoc(SourceLocation Loc) const {
+ FileID FID = getFileID(Loc);
+ const SrcMgr::SLocEntry *E = &getSLocEntry(FID);
+
+ unsigned Offset = Loc.getOffset()-E->getOffset();
+ if (Loc.isFileID())
+ return std::make_pair(FID, Offset);
+ return getDecomposedSpellingLocSlowCase(E, Offset);
+ }
+
+ /// getFileOffset - This method returns the offset from the start
+ /// of the file that the specified SourceLocation represents. This is not very
+ /// meaningful for a macro ID.
+ unsigned getFileOffset(SourceLocation SpellingLoc) const {
+ return getDecomposedLoc(SpellingLoc).second;
+ }
+
+
+ //===--------------------------------------------------------------------===//
+ // Queries about the code at a SourceLocation.
+ //===--------------------------------------------------------------------===//
+
+ /// getCharacterData - Return a pointer to the start of the specified location
+ /// in the appropriate spelling MemoryBuffer.
+ const char *getCharacterData(SourceLocation SL) const;
+
+ /// 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
+ /// before calling this method.
+ unsigned getColumnNumber(FileID FID, unsigned FilePos) const;
+ unsigned getSpellingColumnNumber(SourceLocation Loc) const;
+ unsigned getInstantiationColumnNumber(SourceLocation Loc) const;
+
+
+ /// getLineNumber - Given a SourceLocation, return the spelling line number
+ /// for the position indicated. This requires building and caching a table of
+ /// line offsets for the MemoryBuffer, so this is not cheap: use only when
+ /// about to emit a diagnostic.
+ unsigned getLineNumber(FileID FID, unsigned FilePos) const;
+
+ unsigned getInstantiationLineNumber(SourceLocation Loc) const;
+ unsigned getSpellingLineNumber(SourceLocation Loc) const;
+
+ /// Return the filename or buffer identifier of the buffer the location is in.
+ /// Note that this name does not respect #line directives. Use getPresumedLoc
+ /// for normal clients.
+ const char *getBufferName(SourceLocation Loc) const;
+
+ /// getFileCharacteristic - return the file characteristic of the specified
+ /// source location, indicating whether this is a normal file, a system
+ /// header, or an "implicit extern C" system header.
+ ///
+ /// This state can be modified with flags on GNU linemarker directives like:
+ /// # 4 "foo.h" 3
+ /// which changes all source locations in the current file after that to be
+ /// considered to be from a system header.
+ SrcMgr::CharacteristicKind getFileCharacteristic(SourceLocation Loc) const;
+
+ /// getPresumedLoc - This method returns the "presumed" location of a
+ /// SourceLocation specifies. A "presumed location" can be modified by #line
+ /// 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.
+ PresumedLoc getPresumedLoc(SourceLocation Loc) const;
+
+ /// isFromSameFile - Returns true if both SourceLocations correspond to
+ /// the same file.
+ bool isFromSameFile(SourceLocation Loc1, SourceLocation Loc2) const {
+ return getFileID(Loc1) == getFileID(Loc2);
+ }
+
+ /// isFromMainFile - Returns true if the file of provided SourceLocation is
+ /// the main file.
+ bool isFromMainFile(SourceLocation Loc) const {
+ return getFileID(Loc) == getMainFileID();
+ }
+
+ /// isInSystemHeader - Returns if a SourceLocation is in a system header.
+ bool isInSystemHeader(SourceLocation Loc) const {
+ return getFileCharacteristic(Loc) != SrcMgr::C_User;
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Line Table Manipulation Routines
+ //===--------------------------------------------------------------------===//
+
+ /// getLineTableFilenameID - Return the uniqued ID for the specified filename.
+ ///
+ unsigned getLineTableFilenameID(const char *Ptr, unsigned Len);
+
+ /// 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
+ /// unspecified.
+ void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID);
+ void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID,
+ bool IsFileEntry, bool IsFileExit,
+ bool IsSystemHeader, bool IsExternCHeader);
+
+ /// \brief Determine if the source manager has a line table.
+ bool hasLineTable() const { return LineTable != 0; }
+
+ /// \brief Retrieve the stored line table.
+ LineTableInfo &getLineTable();
+
+ //===--------------------------------------------------------------------===//
+ // Other miscellaneous methods.
+ //===--------------------------------------------------------------------===//
+
+ // Iterators over FileInfos.
+ typedef llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>
+ ::const_iterator fileinfo_iterator;
+ fileinfo_iterator fileinfo_begin() const { return FileInfos.begin(); }
+ fileinfo_iterator fileinfo_end() const { return FileInfos.end(); }
+
+ /// PrintStats - Print statistics to stderr.
+ ///
+ void PrintStats() const;
+
+ // Iteration over the source location entry table.
+ typedef std::vector<SrcMgr::SLocEntry>::const_iterator sloc_entry_iterator;
+
+ sloc_entry_iterator sloc_entry_begin() const {
+ return SLocEntryTable.begin();
+ }
+
+ sloc_entry_iterator sloc_entry_end() const {
+ return SLocEntryTable.end();
+ }
+
+ unsigned sloc_entry_size() const { return SLocEntryTable.size(); }
+
+ const SrcMgr::SLocEntry &getSLocEntry(FileID FID) const {
+ assert(FID.ID < SLocEntryTable.size() && "Invalid id");
+ if (ExternalSLocEntries &&
+ FID.ID < SLocEntryLoaded.size() &&
+ !SLocEntryLoaded[FID.ID])
+ ExternalSLocEntries->ReadSLocEntry(FID.ID);
+ return SLocEntryTable[FID.ID];
+ }
+
+ unsigned getNextOffset() const { return NextOffset; }
+
+ /// \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 Clear out any preallocated source location entries that
+ /// haven't already been loaded.
+ void ClearPreallocatedSLocEntries();
+
+private:
+ /// isOffsetInFileID - Return true if the specified FileID contains the
+ /// specified SourceLocation offset. This is a very hot method.
+ inline bool isOffsetInFileID(FileID FID, unsigned SLocOffset) const {
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID);
+ // 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;
+
+ return SLocOffset < getSLocEntry(FileID::get(FID.ID+1)).getOffset();
+ }
+
+ /// createFileID - Create a new fileID for the specified ContentCache and
+ /// include position. This works regardless of whether the ContentCache
+ /// corresponds to a file or some other input source.
+ FileID createFileID(const SrcMgr::ContentCache* File,
+ SourceLocation IncludePos,
+ SrcMgr::CharacteristicKind DirCharacter,
+ unsigned PreallocatedID = 0,
+ unsigned Offset = 0);
+
+ const SrcMgr::ContentCache *
+ getOrCreateContentCache(const FileEntry *SourceFile);
+
+ /// createMemBufferContentCache - Create a new ContentCache for the specified
+ /// memory buffer.
+ const SrcMgr::ContentCache*
+ createMemBufferContentCache(const llvm::MemoryBuffer *Buf);
+
+ FileID getFileIDSlow(unsigned SLocOffset) const;
+
+ SourceLocation getInstantiationLocSlowCase(SourceLocation Loc) const;
+ SourceLocation getSpellingLocSlowCase(SourceLocation Loc) const;
+
+ std::pair<FileID, unsigned>
+ getDecomposedInstantiationLocSlowCase(const SrcMgr::SLocEntry *E,
+ unsigned Offset) const;
+ std::pair<FileID, unsigned>
+ getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E,
+ unsigned Offset) const;
+};
+
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/SourceManagerInternals.h b/include/clang/Basic/SourceManagerInternals.h
new file mode 100644
index 000000000000..0bcb68e4601d
--- /dev/null
+++ b/include/clang/Basic/SourceManagerInternals.h
@@ -0,0 +1,130 @@
+//===--- SourceManagerInternals.h - SourceManager 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 defines the implementation details of the SourceManager
+// class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SOURCEMANAGER_INTERNALS_H
+#define LLVM_CLANG_SOURCEMANAGER_INTERNALS_H
+
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/StringMap.h"
+#include <map>
+
+namespace clang {
+
+//===----------------------------------------------------------------------===//
+// Line Table Implementation
+//===----------------------------------------------------------------------===//
+
+struct LineEntry {
+ /// FileOffset - The offset in this file that the line entry occurs at.
+ unsigned FileOffset;
+
+ /// LineNo - The presumed line number of this line entry: #line 4.
+ unsigned LineNo;
+
+ /// FilenameID - The ID of the filename identified by this line entry:
+ /// #line 4 "foo.c". This is -1 if not specified.
+ int FilenameID;
+
+ /// Flags - Set the 0 if no flags, 1 if a system header,
+ SrcMgr::CharacteristicKind FileKind;
+
+ /// IncludeOffset - This is the offset of the virtual include stack location,
+ /// which is manipulated by GNU linemarker directives. If this is 0 then
+ /// there is no virtual #includer.
+ unsigned IncludeOffset;
+
+ static LineEntry get(unsigned Offs, unsigned Line, int Filename,
+ SrcMgr::CharacteristicKind FileKind,
+ unsigned IncludeOffset) {
+ LineEntry E;
+ E.FileOffset = Offs;
+ E.LineNo = Line;
+ E.FilenameID = Filename;
+ E.FileKind = FileKind;
+ E.IncludeOffset = IncludeOffset;
+ return E;
+ }
+};
+
+// needed for FindNearestLineEntry (upper_bound of LineEntry)
+inline bool operator<(const LineEntry &lhs, const LineEntry &rhs) {
+ // FIXME: should check the other field?
+ return lhs.FileOffset < rhs.FileOffset;
+}
+
+inline bool operator<(const LineEntry &E, unsigned Offset) {
+ return E.FileOffset < Offset;
+}
+
+inline bool operator<(unsigned Offset, const LineEntry &E) {
+ return Offset < E.FileOffset;
+}
+
+/// LineTableInfo - This class is used to hold and unique data used to
+/// represent #line information.
+class LineTableInfo {
+ /// FilenameIDs - This map is used to assign unique IDs to filenames in
+ /// #line directives. This allows us to unique the filenames that
+ /// frequently reoccur and reference them with indices. FilenameIDs holds
+ /// the mapping from string -> ID, and FilenamesByID holds the mapping of ID
+ /// to string.
+ llvm::StringMap<unsigned, llvm::BumpPtrAllocator> FilenameIDs;
+ std::vector<llvm::StringMapEntry<unsigned>*> FilenamesByID;
+
+ /// 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;
+public:
+ LineTableInfo() {
+ }
+
+ void clear() {
+ FilenameIDs.clear();
+ FilenamesByID.clear();
+ LineEntries.clear();
+ }
+
+ ~LineTableInfo() {}
+
+ unsigned getLineTableFilenameID(const char *Ptr, unsigned Len);
+ 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,
+ unsigned LineNo, int FilenameID);
+ void AddLineNote(unsigned 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);
+
+ // Low-level access
+ typedef std::map<unsigned, 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);
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
new file mode 100644
index 000000000000..f577d6b32287
--- /dev/null
+++ b/include/clang/Basic/TargetInfo.h
@@ -0,0 +1,391 @@
+//===--- TargetInfo.h - Expose information about the target -----*- 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 TargetInfo interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_TARGETINFO_H
+#define LLVM_CLANG_BASIC_TARGETINFO_H
+
+// FIXME: Daniel isn't smart enough to use a prototype for this.
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/DataTypes.h"
+#include <cassert>
+#include <vector>
+#include <string>
+
+namespace llvm { struct fltSemantics; }
+
+namespace clang {
+
+class Diagnostic;
+class SourceManager;
+class LangOptions;
+
+namespace Builtin { struct Info; }
+
+/// TargetInfo - This class exposes information about the current target.
+///
+class TargetInfo {
+ std::string Triple;
+protected:
+ // Target values set by the ctor of the actual target implementation. Default
+ // values are specified by the TargetInfo constructor.
+ bool CharIsSigned;
+ bool TLSSupported;
+ unsigned char PointerWidth, PointerAlign;
+ unsigned char WCharWidth, WCharAlign;
+ unsigned char IntWidth, IntAlign;
+ unsigned char FloatWidth, FloatAlign;
+ unsigned char DoubleWidth, DoubleAlign;
+ unsigned char LongDoubleWidth, LongDoubleAlign;
+ unsigned char LongWidth, LongAlign;
+ unsigned char LongLongWidth, LongLongAlign;
+ unsigned char IntMaxTWidth;
+ const char *DescriptionString;
+ const char *UserLabelPrefix;
+ const llvm::fltSemantics *FloatFormat, *DoubleFormat, *LongDoubleFormat;
+ unsigned char RegParmMax, SSERegParmMax;
+
+ // TargetInfo Constructor. Default initializes all fields.
+ TargetInfo(const std::string &T);
+
+public:
+ /// CreateTargetInfo - Return the target info object for the specified target
+ /// triple.
+ static TargetInfo* CreateTargetInfo(const std::string &Triple);
+
+ virtual ~TargetInfo();
+
+ ///===---- Target Data Type Query Methods -------------------------------===//
+ enum IntType {
+ NoInt = 0,
+ SignedShort,
+ UnsignedShort,
+ SignedInt,
+ UnsignedInt,
+ SignedLong,
+ UnsignedLong,
+ SignedLongLong,
+ UnsignedLongLong
+ };
+protected:
+ IntType SizeType, IntMaxType, UIntMaxType, PtrDiffType, IntPtrType, WCharType;
+public:
+ IntType getSizeType() const { return SizeType; }
+ IntType getIntMaxType() const { return IntMaxType; }
+ IntType getUIntMaxType() const { return UIntMaxType; }
+ IntType getPtrDiffType(unsigned AddrSpace) const {
+ return AddrSpace == 0 ? PtrDiffType : getPtrDiffTypeV(AddrSpace);
+ }
+ IntType getIntPtrType() const { return IntPtrType; }
+ IntType getWCharType() const { return WCharType; }
+
+ /// isCharSigned - Return true if 'char' is 'signed char' or false if it is
+ /// treated as 'unsigned char'. This is implementation defined according to
+ /// C99 6.2.5p15. In our implementation, this is target-specific.
+ bool isCharSigned() const { return CharIsSigned; }
+
+ /// getPointerWidth - Return the width of pointers on this target, for the
+ /// specified address space.
+ uint64_t getPointerWidth(unsigned AddrSpace) const {
+ return AddrSpace == 0 ? PointerWidth : getPointerWidthV(AddrSpace);
+ }
+ uint64_t getPointerAlign(unsigned AddrSpace) const {
+ return AddrSpace == 0 ? PointerAlign : getPointerAlignV(AddrSpace);
+ }
+
+ /// getBoolWidth/Align - Return the size of '_Bool' and C++ 'bool' for this
+ /// target, in bits.
+ unsigned getBoolWidth(bool isWide = false) const { return 8; } // FIXME
+ unsigned getBoolAlign(bool isWide = false) const { return 8; } // FIXME
+
+ unsigned getCharWidth(bool isWide = false) const {
+ return isWide ? getWCharWidth() : 8; // FIXME
+ }
+ unsigned getCharAlign(bool isWide = false) const {
+ return isWide ? getWCharAlign() : 8; // FIXME
+ }
+
+ /// getShortWidth/Align - Return the size of 'signed short' and
+ /// 'unsigned short' for this target, in bits.
+ unsigned getShortWidth() const { return 16; } // FIXME
+ unsigned getShortAlign() const { return 16; } // FIXME
+
+ /// getIntWidth/Align - Return the size of 'signed int' and 'unsigned int' for
+ /// this target, in bits.
+ unsigned getIntWidth() const { return IntWidth; }
+ unsigned getIntAlign() const { return IntAlign; }
+
+ /// getLongWidth/Align - Return the size of 'signed long' and 'unsigned long'
+ /// for this target, in bits.
+ unsigned getLongWidth() const { return LongWidth; }
+ unsigned getLongAlign() const { return LongAlign; }
+
+ /// getLongLongWidth/Align - Return the size of 'signed long long' and
+ /// 'unsigned long long' for this target, in bits.
+ unsigned getLongLongWidth() const { return LongLongWidth; }
+ unsigned getLongLongAlign() const { return LongLongAlign; }
+
+ /// getWcharWidth/Align - Return the size of 'wchar_t' for this target, in
+ /// bits.
+ unsigned getWCharWidth() const { return WCharWidth; }
+ unsigned getWCharAlign() const { return WCharAlign; }
+
+ /// getFloatWidth/Align/Format - Return the size/align/format of 'float'.
+ unsigned getFloatWidth() const { return FloatWidth; }
+ unsigned getFloatAlign() const { return FloatAlign; }
+ const llvm::fltSemantics &getFloatFormat() const { return *FloatFormat; }
+
+ /// getDoubleWidth/Align/Format - Return the size/align/format of 'double'.
+ unsigned getDoubleWidth() const { return DoubleWidth; }
+ unsigned getDoubleAlign() const { return DoubleAlign; }
+ const llvm::fltSemantics &getDoubleFormat() const { return *DoubleFormat; }
+
+ /// getLongDoubleWidth/Align/Format - Return the size/align/format of 'long
+ /// double'.
+ unsigned getLongDoubleWidth() const { return LongDoubleWidth; }
+ unsigned getLongDoubleAlign() const { return LongDoubleAlign; }
+ const llvm::fltSemantics &getLongDoubleFormat() const {
+ return *LongDoubleFormat;
+ }
+
+ /// getIntMaxTWidth - Return the size of intmax_t and uintmax_t for this
+ /// target, in bits.
+ unsigned getIntMaxTWidth() const {
+ return IntMaxTWidth;
+ }
+
+ /// getUserLabelPrefix - This returns the default value of the
+ /// __USER_LABEL_PREFIX__ macro, which is the prefix given to user symbols by
+ /// default. On most platforms this is "_", but it is "" on some, and "." on
+ /// others.
+ const char *getUserLabelPrefix() const {
+ return UserLabelPrefix;
+ }
+
+ /// getTypeName - Return the user string for the specified integer type enum.
+ /// For example, SignedShort -> "short".
+ static const char *getTypeName(IntType T);
+
+ ///===---- Other target property query methods --------------------------===//
+
+ /// getTargetDefines - Appends the target-specific #define values for this
+ /// target set to the specified buffer.
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &DefineBuffer) const = 0;
+
+ /// getTargetBuiltins - Return information about target-specific builtins for
+ /// the current primary target, and info about which builtins are non-portable
+ /// across the current set of primary and secondary targets.
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const = 0;
+
+ /// getVAListDeclaration - Return the declaration to use for
+ /// __builtin_va_list, which is target-specific.
+ virtual const char *getVAListDeclaration() const = 0;
+
+ /// 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(const char *Name) const;
+
+ // getNormalizedGCCRegisterName - Returns the "normalized" GCC register name.
+ // For example, on x86 it will return "ax" when "eax" is passed in.
+ const char *getNormalizedGCCRegisterName(const char *Name) const;
+
+ struct ConstraintInfo {
+ enum {
+ CI_None = 0x00,
+ CI_AllowsMemory = 0x01,
+ CI_AllowsRegister = 0x02,
+ CI_ReadWrite = 0x04, // "+r" output constraint (read and write).
+ CI_HasMatchingInput = 0x08 // This output operand has a matching input.
+ };
+ unsigned Flags;
+ int TiedOperand;
+
+ std::string ConstraintStr; // constraint: "=rm"
+ std::string Name; // Operand name: [foo] with no []'s.
+ public:
+ ConstraintInfo(const char *str, unsigned strlen, const std::string &name)
+ : Flags(0), TiedOperand(-1), ConstraintStr(str, str+strlen), Name(name) {}
+ explicit ConstraintInfo(const std::string &Str, const std::string &name)
+ : Flags(0), TiedOperand(-1), ConstraintStr(Str), Name(name) {}
+
+ const std::string &getConstraintStr() const { return ConstraintStr; }
+ const std::string &getName() const { return Name; }
+ bool isReadWrite() const { return (Flags & CI_ReadWrite) != 0; }
+ bool allowsRegister() const { return (Flags & CI_AllowsRegister) != 0; }
+ bool allowsMemory() const { return (Flags & CI_AllowsMemory) != 0; }
+
+ /// hasMatchingInput - Return true if this output operand has a matching
+ /// (tied) input operand.
+ bool hasMatchingInput() const { return (Flags & CI_HasMatchingInput) != 0; }
+
+ /// hasTiedOperand() - Return true if this input operand is a matching
+ /// constraint that ties it to an output operand. If this returns true,
+ /// then getTiedOperand will indicate which output operand this is tied to.
+ bool hasTiedOperand() const { return TiedOperand != -1; }
+ unsigned getTiedOperand() const {
+ assert(hasTiedOperand() && "Has no tied operand!");
+ return (unsigned)TiedOperand;
+ }
+
+ void setIsReadWrite() { Flags |= CI_ReadWrite; }
+ void setAllowsMemory() { Flags |= CI_AllowsMemory; }
+ void setAllowsRegister() { Flags |= CI_AllowsRegister; }
+ void setHasMatchingInput() { Flags |= CI_HasMatchingInput; }
+
+ /// setTiedOperand - Indicate that this is an input operand that is tied to
+ /// the specified output operand. Copy over the various constraint
+ /// information from the output.
+ void setTiedOperand(unsigned N, ConstraintInfo &Output) {
+ Output.setHasMatchingInput();
+ Flags = Output.Flags;
+ TiedOperand = N;
+ // Don't copy Name or constraint string.
+ }
+ };
+
+ // validateOutputConstraint, validateInputConstraint - Checks that
+ // a constraint is valid and provides information about it.
+ // FIXME: These should return a real error instead of just true/false.
+ bool validateOutputConstraint(ConstraintInfo &Info) const;
+ bool validateInputConstraint(ConstraintInfo *OutputConstraints,
+ unsigned NumOutputs,
+ ConstraintInfo &info) const;
+ bool resolveSymbolicName(const char *&Name,
+ ConstraintInfo *OutputConstraints,
+ unsigned NumOutputs, unsigned &Index) const;
+
+ virtual std::string convertConstraint(const char Constraint) const {
+ return std::string(1, Constraint);
+ }
+
+ // Returns a string of target-specific clobbers, in LLVM format.
+ virtual const char *getClobbers() const = 0;
+
+
+ /// getTargetPrefix - Return the target prefix used for identifying
+ /// llvm intrinsics.
+ virtual const char *getTargetPrefix() const = 0;
+
+ /// getTargetTriple - Return the target triple of the primary target.
+ const char *getTargetTriple() const {
+ return Triple.c_str();
+ }
+
+ const char *getTargetDescription() const {
+ return DescriptionString;
+ }
+
+ struct GCCRegAlias {
+ const char * const Aliases[5];
+ const char * const Register;
+ };
+
+ virtual bool useGlobalsForAutomaticVariables() const { return false; }
+
+ /// getStringSymbolPrefix - Get the default symbol prefix to
+ /// use for string literals.
+ virtual const char *getStringSymbolPrefix(bool IsConstant) const {
+ return ".str";
+ }
+
+ /// getCFStringSymbolPrefix - Get the default symbol prefix
+ /// to use for CFString literals.
+ virtual const char *getCFStringSymbolPrefix() const {
+ return "";
+ }
+
+ /// getUnicodeStringSymbolPrefix - Get the default symbol prefix to
+ /// use for string literals.
+ virtual const char *getUnicodeStringSymbolPrefix() const {
+ return ".str";
+ }
+
+ /// getUnicodeStringSection - Return the section to use for unicode
+ /// string literals, or 0 if no special section is used.
+ virtual const char *getUnicodeStringSection() const {
+ return 0;
+ }
+
+ /// getCFStringSection - Return the section to use for CFString
+ /// literals, or 0 if no special section is used.
+ virtual const char *getCFStringSection() const {
+ return "__DATA,__cfstring";
+ }
+
+ /// getCFStringDataSection - Return the section to use for the
+ /// constant string data associated with a CFString literal, or 0 if
+ /// no special section is used.
+ virtual const char *getCFStringDataSection() const {
+ return "__TEXT,__cstring,cstring_literals";
+ }
+
+ /// getDefaultLangOptions - Allow the target to specify default settings for
+ /// various language options. These may be overridden by command line
+ /// options.
+ virtual void getDefaultLangOptions(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 {
+ }
+
+ /// setFeatureEnabled - Enable or disable a specific target feature,
+ /// the feature name must be valid.
+ ///
+ /// \return - False on error (invalid feature name).
+ virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
+ const std::string &Name,
+ bool Enabled) const {
+ return false;
+ }
+
+ /// HandleTargetOptions - Perform initialization based on the user
+ /// configured set of features.
+ virtual void HandleTargetFeatures(const llvm::StringMap<bool> &Features) {
+ }
+
+ // getRegParmMax - Returns maximal number of args passed in registers.
+ unsigned getRegParmMax() const {
+ return RegParmMax;
+ }
+
+ // isTLSSupported - Whether the target supports thread-local storage
+ unsigned isTLSSupported() const {
+ return TLSSupported;
+ }
+
+protected:
+ virtual uint64_t getPointerWidthV(unsigned AddrSpace) const {
+ return PointerWidth;
+ }
+ virtual uint64_t getPointerAlignV(unsigned AddrSpace) const {
+ return PointerAlign;
+ }
+ virtual enum IntType getPtrDiffTypeV(unsigned AddrSpace) const {
+ return PtrDiffType;
+ }
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const = 0;
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const = 0;
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const= 0;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/TemplateKinds.h b/include/clang/Basic/TemplateKinds.h
new file mode 100644
index 000000000000..c6ea05bb1396
--- /dev/null
+++ b/include/clang/Basic/TemplateKinds.h
@@ -0,0 +1,39 @@
+//===--- TemplateKinds.h - Enum values for C++ Template Kinds ---*- 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 TemplateNameKind enum.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TEMPLATEKINDS_H
+#define LLVM_CLANG_TEMPLATEKINDS_H
+
+namespace clang {
+
+/// \brief Specifies the kind of template name that an identifier refers to.
+enum TemplateNameKind {
+ /// The name does not refer to a template.
+ TNK_Non_template = 0,
+ /// The name refers to a function template or a set of overloaded
+ /// functions that includes at least one function template.
+ TNK_Function_template,
+ /// The name refers to a template whose specialization produces a
+ /// type. The template itself could be a class template, template
+ /// template parameter, or C++0x template alias.
+ TNK_Type_template,
+ /// The name refers to a dependent template name. Whether the
+ /// template name is assumed to refer to a type template or a
+ /// function template depends on the context in which the template
+ /// name occurs.
+ TNK_Dependent_template_name
+};
+
+}
+#endif
+
+
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
new file mode 100644
index 000000000000..9b65288f68e1
--- /dev/null
+++ b/include/clang/Basic/TokenKinds.def
@@ -0,0 +1,413 @@
+//===--- TokenKinds.def - C Family Token Kind 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 TokenKind database. This includes normal tokens like
+// tok::ampamp (corresponding to the && token) as well as keywords for various
+// languages. Users of this file must optionally #define the TOK, KEYWORD,
+// ALIAS, or PPKEYWORD macros to make use of this file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TOK
+#define TOK(X)
+#endif
+#ifndef KEYWORD
+#define KEYWORD(X,Y) TOK(kw_ ## X)
+#endif
+#ifndef ALIAS
+#define ALIAS(X,Y,Z)
+#endif
+#ifndef PPKEYWORD
+#define PPKEYWORD(X)
+#endif
+#ifndef CXX_KEYWORD_OPERATOR
+#define CXX_KEYWORD_OPERATOR(X,Y)
+#endif
+#ifndef OBJC1_AT_KEYWORD
+#define OBJC1_AT_KEYWORD(X)
+#endif
+#ifndef OBJC2_AT_KEYWORD
+#define OBJC2_AT_KEYWORD(X)
+#endif
+#ifndef ANNOTATION
+#define ANNOTATION(X) TOK(annot_ ## X)
+#endif
+
+//===----------------------------------------------------------------------===//
+// Preprocessor keywords.
+//===----------------------------------------------------------------------===//
+
+// These have meaning after a '#' at the start of a line. These define enums in
+// the tok::pp_* namespace. Note that IdentifierInfo::getPPKeywordID must be
+// manually updated if something is added here.
+PPKEYWORD(not_keyword)
+
+// C99 6.10.1 - Conditional Inclusion.
+PPKEYWORD(if)
+PPKEYWORD(ifdef)
+PPKEYWORD(ifndef)
+PPKEYWORD(elif)
+PPKEYWORD(else)
+PPKEYWORD(endif)
+PPKEYWORD(defined)
+
+// C99 6.10.2 - Source File Inclusion.
+PPKEYWORD(include)
+PPKEYWORD(__include_macros)
+
+// C99 6.10.3 - Macro Replacement.
+PPKEYWORD(define)
+PPKEYWORD(undef)
+
+// C99 6.10.4 - Line Control.
+PPKEYWORD(line)
+
+// C99 6.10.5 - Error Directive.
+PPKEYWORD(error)
+
+// C99 6.10.6 - Pragma Directive.
+PPKEYWORD(pragma)
+
+// GNU Extensions.
+PPKEYWORD(import)
+PPKEYWORD(include_next)
+PPKEYWORD(warning)
+PPKEYWORD(ident)
+PPKEYWORD(sccs)
+PPKEYWORD(assert)
+PPKEYWORD(unassert)
+
+//===----------------------------------------------------------------------===//
+// Language keywords.
+//===----------------------------------------------------------------------===//
+
+// These define members of the tok::* namespace.
+
+TOK(unknown) // Not a token.
+TOK(eof) // End of file.
+TOK(eom) // End of macro (end of line inside a macro).
+
+// C99 6.4.9: Comments.
+TOK(comment) // Comment (only in -E -C[C] mode)
+
+// C99 6.4.2: Identifiers.
+TOK(identifier) // abcde123
+
+// C99 6.4.4.1: Integer Constants
+// C99 6.4.4.2: Floating Constants
+TOK(numeric_constant) // 0x123
+
+// C99 6.4.4: Character Constants
+TOK(char_constant) // 'a' L'b'
+
+// C99 6.4.5: String Literals.
+TOK(string_literal) // "foo"
+TOK(wide_string_literal) // L"foo"
+TOK(angle_string_literal)// <foo>
+
+// C99 6.4.6: Punctuators.
+TOK(l_square) // [
+TOK(r_square) // ]
+TOK(l_paren) // (
+TOK(r_paren) // )
+TOK(l_brace) // {
+TOK(r_brace) // }
+TOK(period) // .
+TOK(ellipsis) // ...
+TOK(amp) // &
+TOK(ampamp) // &&
+TOK(ampequal) // &=
+TOK(star) // *
+TOK(starequal) // *=
+TOK(plus) // +
+TOK(plusplus) // ++
+TOK(plusequal) // +=
+TOK(minus) // -
+TOK(arrow) // ->
+TOK(minusminus) // --
+TOK(minusequal) // -=
+TOK(tilde) // ~
+TOK(exclaim) // !
+TOK(exclaimequal) // !=
+TOK(slash) // /
+TOK(slashequal) // /=
+TOK(percent) // %
+TOK(percentequal) // %=
+TOK(less) // <
+TOK(lessless) // <<
+TOK(lessequal) // <=
+TOK(lesslessequal) // <<=
+TOK(greater) // >
+TOK(greatergreater) // >>
+TOK(greaterequal) // >=
+TOK(greatergreaterequal) // >>=
+TOK(caret) // ^
+TOK(caretequal) // ^=
+TOK(pipe) // |
+TOK(pipepipe) // ||
+TOK(pipeequal) // |=
+TOK(question) // ?
+TOK(colon) // :
+TOK(semi) // ;
+TOK(equal) // =
+TOK(equalequal) // ==
+TOK(comma) // ,
+TOK(hash) // #
+TOK(hashhash) // ##
+TOK(hashat) // #@
+
+// C++ Support
+TOK(periodstar) // .*
+TOK(arrowstar) // ->*
+TOK(coloncolon) // ::
+
+// Objective C support.
+TOK(at) // @
+
+
+// C99 6.4.1: Keywords. These turn into kw_* tokens.
+// Flags allowed:
+// KEYALL - This is a keyword in all variants of C and C++, or it
+// is a keyword in the implementation namespace that should
+// always be treated as a keyword
+// KEYC99 - This is a keyword introduced to C in C99
+// KEYCXX - This is a C++ keyword, or a C++-specific keyword in the
+// implementation namespace
+// KEYCXX0X - This is a C++ keyword introduced to C++ in C++0x
+// KEYGNU - This is a keyword if GNU extensions are enabled
+// KEYMS - This is a keyword if Microsoft extensions are enabled
+//
+KEYWORD(auto , KEYALL)
+KEYWORD(break , KEYALL)
+KEYWORD(case , KEYALL)
+KEYWORD(char , KEYALL)
+KEYWORD(const , KEYALL)
+KEYWORD(continue , KEYALL)
+KEYWORD(default , KEYALL)
+KEYWORD(do , KEYALL)
+KEYWORD(double , KEYALL)
+KEYWORD(else , KEYALL)
+KEYWORD(enum , KEYALL)
+KEYWORD(extern , KEYALL)
+KEYWORD(float , KEYALL)
+KEYWORD(for , KEYALL)
+KEYWORD(goto , KEYALL)
+KEYWORD(if , KEYALL)
+KEYWORD(inline , KEYC99|KEYCXX|KEYGNU)
+KEYWORD(int , KEYALL)
+KEYWORD(long , KEYALL)
+KEYWORD(register , KEYALL)
+KEYWORD(restrict , KEYC99)
+KEYWORD(return , KEYALL)
+KEYWORD(short , KEYALL)
+KEYWORD(signed , KEYALL)
+KEYWORD(sizeof , KEYALL)
+KEYWORD(static , KEYALL)
+KEYWORD(struct , KEYALL)
+KEYWORD(switch , KEYALL)
+KEYWORD(typedef , KEYALL)
+KEYWORD(union , KEYALL)
+KEYWORD(unsigned , KEYALL)
+KEYWORD(void , KEYALL)
+KEYWORD(volatile , KEYALL)
+KEYWORD(while , KEYALL)
+KEYWORD(_Bool , KEYALL)
+KEYWORD(_Complex , KEYALL)
+KEYWORD(_Imaginary , KEYALL)
+KEYWORD(__func__ , KEYALL)
+
+// C++ 2.11p1: Keywords.
+KEYWORD(asm , KEYCXX|KEYGNU)
+KEYWORD(bool , KEYCXX)
+KEYWORD(catch , KEYCXX)
+KEYWORD(class , KEYCXX)
+KEYWORD(const_cast , KEYCXX)
+KEYWORD(delete , KEYCXX)
+KEYWORD(dynamic_cast , KEYCXX)
+KEYWORD(explicit , KEYCXX)
+KEYWORD(export , KEYCXX)
+KEYWORD(false , KEYCXX)
+KEYWORD(friend , KEYCXX)
+KEYWORD(mutable , KEYCXX)
+KEYWORD(namespace , KEYCXX)
+KEYWORD(new , KEYCXX)
+KEYWORD(operator , KEYCXX)
+KEYWORD(private , KEYCXX)
+KEYWORD(protected , KEYCXX)
+KEYWORD(public , KEYCXX)
+KEYWORD(reinterpret_cast , KEYCXX)
+KEYWORD(static_cast , KEYCXX)
+KEYWORD(template , KEYCXX)
+KEYWORD(this , KEYCXX)
+KEYWORD(throw , KEYCXX)
+KEYWORD(true , KEYCXX)
+KEYWORD(try , KEYCXX)
+KEYWORD(typename , KEYCXX)
+KEYWORD(typeid , KEYCXX)
+KEYWORD(using , KEYCXX)
+KEYWORD(virtual , KEYCXX)
+KEYWORD(wchar_t , KEYCXX)
+
+// C++ 2.5p2: Alternative Representations.
+CXX_KEYWORD_OPERATOR(and , ampamp)
+CXX_KEYWORD_OPERATOR(and_eq , ampequal)
+CXX_KEYWORD_OPERATOR(bitand , amp)
+CXX_KEYWORD_OPERATOR(bitor , pipe)
+CXX_KEYWORD_OPERATOR(compl , tilde)
+CXX_KEYWORD_OPERATOR(not , exclaim)
+CXX_KEYWORD_OPERATOR(not_eq , exclaimequal)
+CXX_KEYWORD_OPERATOR(or , pipepipe)
+CXX_KEYWORD_OPERATOR(or_eq , pipeequal)
+CXX_KEYWORD_OPERATOR(xor , caret)
+CXX_KEYWORD_OPERATOR(xor_eq , caretequal)
+
+// C++0x keywords
+KEYWORD(alignof , KEYCXX0X)
+KEYWORD(axiom , KEYCXX0X)
+KEYWORD(char16_t , KEYCXX0X)
+KEYWORD(char32_t , KEYCXX0X)
+KEYWORD(concept , KEYCXX0X)
+KEYWORD(concept_map , KEYCXX0X)
+KEYWORD(constexpr , KEYCXX0X)
+KEYWORD(decltype , KEYCXX0X)
+KEYWORD(late_check , KEYCXX0X)
+KEYWORD(nullptr , KEYCXX0X)
+KEYWORD(requires , KEYCXX0X)
+KEYWORD(static_assert , KEYCXX0X)
+KEYWORD(thread_local , KEYCXX0X)
+
+// GNU Extensions (in impl-reserved namespace)
+KEYWORD(_Decimal32 , KEYALL)
+KEYWORD(_Decimal64 , KEYALL)
+KEYWORD(_Decimal128 , KEYALL)
+KEYWORD(__null , KEYCXX)
+KEYWORD(__alignof , KEYALL)
+KEYWORD(__attribute , KEYALL)
+KEYWORD(__builtin_choose_expr , KEYALL)
+KEYWORD(__builtin_offsetof , KEYALL)
+KEYWORD(__builtin_types_compatible_p, KEYALL)
+KEYWORD(__builtin_va_arg , KEYALL)
+KEYWORD(__extension__ , KEYALL)
+KEYWORD(__imag , KEYALL)
+KEYWORD(__label__ , KEYALL)
+KEYWORD(__real , KEYALL)
+KEYWORD(__thread , KEYALL)
+KEYWORD(__FUNCTION__ , KEYALL)
+KEYWORD(__PRETTY_FUNCTION__ , KEYALL)
+
+// GNU Extensions (outside impl-reserved namespace)
+KEYWORD(typeof , KEYGNU)
+
+// GNU and MS Type Traits
+KEYWORD(__has_nothrow_assign , KEYCXX)
+KEYWORD(__has_nothrow_copy , KEYCXX)
+KEYWORD(__has_nothrow_constructor , KEYCXX)
+KEYWORD(__has_trivial_assign , KEYCXX)
+KEYWORD(__has_trivial_copy , KEYCXX)
+KEYWORD(__has_trivial_constructor , KEYCXX)
+KEYWORD(__has_trivial_destructor , KEYCXX)
+KEYWORD(__has_virtual_destructor , KEYCXX)
+KEYWORD(__is_abstract , KEYCXX)
+KEYWORD(__is_base_of , KEYCXX)
+KEYWORD(__is_class , KEYCXX)
+KEYWORD(__is_empty , KEYCXX)
+KEYWORD(__is_enum , KEYCXX)
+KEYWORD(__is_pod , KEYCXX)
+KEYWORD(__is_polymorphic , KEYCXX)
+KEYWORD(__is_union , KEYCXX)
+// FIXME: Add MS's traits, too.
+
+// Apple Extension.
+KEYWORD(__private_extern__ , KEYALL)
+
+// Microsoft Extension.
+KEYWORD(__declspec , KEYALL)
+KEYWORD(__cdecl , KEYALL)
+KEYWORD(__stdcall , KEYALL)
+KEYWORD(__fastcall , KEYALL)
+KEYWORD(__ptr64 , KEYALL)
+KEYWORD(__w64 , KEYALL)
+KEYWORD(__forceinline , KEYALL)
+
+// Alternate spelling for various tokens. There are GCC extensions in all
+// languages, but should not be disabled in strict conformance mode.
+ALIAS("__attribute__", __attribute, KEYALL)
+ALIAS("__const" , const , KEYALL)
+ALIAS("__const__" , const , KEYALL)
+ALIAS("__alignof__" , __alignof , KEYALL)
+ALIAS("_asm" , asm , KEYMS)
+ALIAS("__asm" , asm , KEYALL)
+ALIAS("__asm__" , asm , KEYALL)
+ALIAS("__complex" , _Complex , KEYALL)
+ALIAS("__complex__" , _Complex , KEYALL)
+ALIAS("__imag__" , __imag , KEYALL)
+ALIAS("__inline" , inline , KEYALL)
+ALIAS("__inline__" , inline , KEYALL)
+ALIAS("__real__" , __real , KEYALL)
+ALIAS("__restrict" , restrict , KEYALL)
+ALIAS("__restrict__" , restrict , KEYALL)
+ALIAS("__signed" , signed , KEYALL)
+ALIAS("__signed__" , signed , KEYALL)
+ALIAS("__typeof" , typeof , KEYALL)
+ALIAS("__typeof__" , typeof , KEYALL)
+ALIAS("__volatile" , volatile , KEYALL)
+ALIAS("__volatile__" , volatile , KEYALL)
+
+
+//===----------------------------------------------------------------------===//
+// Objective-C @-preceeded keywords.
+//===----------------------------------------------------------------------===//
+
+// These have meaning after an '@' in Objective-C mode. These define enums in
+// the tok::objc_* namespace.
+
+OBJC1_AT_KEYWORD(not_keyword)
+OBJC1_AT_KEYWORD(class)
+OBJC1_AT_KEYWORD(compatibility_alias)
+OBJC1_AT_KEYWORD(defs)
+OBJC1_AT_KEYWORD(encode)
+OBJC1_AT_KEYWORD(end)
+OBJC1_AT_KEYWORD(implementation)
+OBJC1_AT_KEYWORD(interface)
+OBJC1_AT_KEYWORD(private)
+OBJC1_AT_KEYWORD(protected)
+OBJC1_AT_KEYWORD(protocol)
+OBJC1_AT_KEYWORD(public)
+OBJC1_AT_KEYWORD(selector)
+OBJC1_AT_KEYWORD(throw)
+OBJC1_AT_KEYWORD(try)
+OBJC1_AT_KEYWORD(catch)
+OBJC1_AT_KEYWORD(finally)
+OBJC1_AT_KEYWORD(synchronized)
+
+OBJC2_AT_KEYWORD(property)
+OBJC2_AT_KEYWORD(package)
+OBJC2_AT_KEYWORD(required)
+OBJC2_AT_KEYWORD(optional)
+OBJC2_AT_KEYWORD(synthesize)
+OBJC2_AT_KEYWORD(dynamic)
+
+// TODO: What to do about context-sensitive keywords like:
+// bycopy/byref/in/inout/oneway/out?
+
+ANNOTATION(cxxscope) // annotation for a C++ scope spec, e.g. "::foo::bar::"
+ANNOTATION(typename) // annotation for a C typedef name, a C++ (possibly
+ // qualified) typename, e.g. "foo::MyClass", or
+ // template-id that names a type ("std::vector<int>")
+ANNOTATION(template_id) // annotation for a C++ template-id that names a
+ // function template specialization (not a type),
+ // e.g., "std::swap<int>"
+#undef ANNOTATION
+#undef OBJC2_AT_KEYWORD
+#undef OBJC1_AT_KEYWORD
+#undef CXX_KEYWORD_OPERATOR
+#undef PPKEYWORD
+#undef ALIAS
+#undef KEYWORD
+#undef TOK
diff --git a/include/clang/Basic/TokenKinds.h b/include/clang/Basic/TokenKinds.h
new file mode 100644
index 000000000000..62a9e428bf21
--- /dev/null
+++ b/include/clang/Basic/TokenKinds.h
@@ -0,0 +1,64 @@
+//===--- TokenKinds.h - Enum values for C Token Kinds -----------*- 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 TokenKind enum and support functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOKENKINDS_H
+#define LLVM_CLANG_TOKENKINDS_H
+
+namespace clang {
+
+namespace tok {
+
+/// TokenKind - This provides a simple uniform namespace for tokens from all C
+/// languages.
+enum TokenKind {
+#define TOK(X) X,
+#include "clang/Basic/TokenKinds.def"
+ NUM_TOKENS
+};
+
+/// PPKeywordKind - This provides a namespace for preprocessor keywords which
+/// start with a '#' at the beginning of the line.
+enum PPKeywordKind {
+#define PPKEYWORD(X) pp_##X,
+#include "clang/Basic/TokenKinds.def"
+ NUM_PP_KEYWORDS
+};
+
+/// ObjCKeywordKind - This provides a namespace for Objective-C keywords which
+/// start with an '@'.
+enum ObjCKeywordKind {
+#define OBJC1_AT_KEYWORD(X) objc_##X,
+#define OBJC2_AT_KEYWORD(X) objc_##X,
+#include "clang/Basic/TokenKinds.def"
+ NUM_OBJC_KEYWORDS
+};
+
+/// \brief Determines the name of a token as used within the front end.
+///
+/// The name of a token will be an internal name (such as "l_square")
+/// and should not be used as part of diagnostic messages.
+const char *getTokenName(enum TokenKind Kind);
+
+/// \brief Determines the spelling of simple punctuation tokens like
+/// '!' or '%', and returns NULL for literal and annotation tokens.
+///
+/// This routine only retrieves the "simple" spelling of the token,
+/// and will not produce any alternative spellings (e.g., a
+/// digraph). For the actual spelling of a given Token, use
+/// Preprocessor::getSpelling().
+const char *getTokenSimpleSpelling(enum TokenKind Kind);
+
+} // end namespace tok
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h
new file mode 100644
index 000000000000..2a2eacc4caac
--- /dev/null
+++ b/include/clang/Basic/TypeTraits.h
@@ -0,0 +1,40 @@
+//===--- TypeTraits.h - C++ Type Traits Support Enumerations ----*- 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 enumerations for the type traits support.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TYPETRAITS_H
+#define LLVM_CLANG_TYPETRAITS_H
+
+namespace clang {
+
+ /// UnaryTypeTrait - Names for the unary type traits.
+ enum UnaryTypeTrait {
+ UTT_HasNothrowAssign,
+ UTT_HasNothrowCopy,
+ UTT_HasNothrowConstructor,
+ UTT_HasTrivialAssign,
+ UTT_HasTrivialCopy,
+ UTT_HasTrivialConstructor,
+ UTT_HasTrivialDestructor,
+ UTT_HasVirtualDestructor,
+ UTT_IsAbstract,
+ UTT_IsClass,
+ UTT_IsEmpty,
+ UTT_IsEnum,
+ UTT_IsPOD,
+ UTT_IsPolymorphic,
+ UTT_IsUnion
+ };
+
+}
+
+#endif
diff --git a/include/clang/Basic/Version.h b/include/clang/Basic/Version.h
new file mode 100644
index 000000000000..f0e1aa7db233
--- /dev/null
+++ b/include/clang/Basic/Version.h
@@ -0,0 +1,35 @@
+//===- Version.h - Clang Version Number -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines version macros for Clang.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_VERSION_H
+#define LLVM_CLANG_BASIC_VERSION_H
+
+/// \brief Clang major version
+#define CLANG_VERSION_MAJOR 1
+
+/// \brief Clang minor version
+#define CLANG_VERSION_MINOR 0
+
+/// \brief Helper macro for CLANG_VERSION_STRING.
+#define CLANG_MAKE_VERSION_STRING2(X) #X
+
+/// \brief Helper macro for CLANG_VERSION_STRING.
+#define CLANG_MAKE_VERSION_STRING(X,Y) CLANG_MAKE_VERSION_STRING2(X.Y)
+
+/// \brief A string that describes the Clang version number, e.g.,
+/// "1.0".
+#define CLANG_VERSION_STRING \
+ CLANG_MAKE_VERSION_STRING(CLANG_VERSION_MAJOR,CLANG_VERSION_MINOR)
+
+
+#endif // LLVM_CLANG_BASIC_VERSION_H
diff --git a/include/clang/CMakeLists.txt b/include/clang/CMakeLists.txt
new file mode 100644
index 000000000000..39e3698a1655
--- /dev/null
+++ b/include/clang/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(Basic)
diff --git a/include/clang/CodeGen/ModuleBuilder.h b/include/clang/CodeGen/ModuleBuilder.h
new file mode 100644
index 000000000000..5812da1b562e
--- /dev/null
+++ b/include/clang/CodeGen/ModuleBuilder.h
@@ -0,0 +1,40 @@
+//===--- CodeGen/ModuleBuilder.h - Build LLVM from ASTs ---------*- 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 ModuleBuilder interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGEN_MODULEBUILDER_H
+#define LLVM_CLANG_CODEGEN_MODULEBUILDER_H
+
+#include "clang/AST/ASTConsumer.h"
+#include <string>
+
+namespace llvm {
+ class Module;
+}
+
+namespace clang {
+ class Diagnostic;
+ class LangOptions;
+ class CompileOptions;
+
+ class CodeGenerator : public ASTConsumer {
+ public:
+ virtual llvm::Module* GetModule() = 0;
+ virtual llvm::Module* ReleaseModule() = 0;
+ };
+
+ CodeGenerator *CreateLLVMCodeGen(Diagnostic &Diags,
+ const std::string &ModuleName,
+ const CompileOptions &CO);
+}
+
+#endif
diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h
new file mode 100644
index 000000000000..b9bf671db2bd
--- /dev/null
+++ b/include/clang/Driver/Action.h
@@ -0,0 +1,209 @@
+//===--- Action.h - Abstract compilation steps ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_DRIVER_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;
+
+namespace clang {
+namespace driver {
+ class Arg;
+
+/// Action - Represent an abstract compilation step to perform.
+///
+/// An action represents an edge in the compilation graph; typically
+/// it is a job to transform an input using some tool.
+///
+/// The current driver is hard wired to expect actions which produce a
+/// single primary output, at least in terms of controlling the
+/// compilation. Actions can produce auxiliary files, but can only
+/// produce a single output to feed into subsequent actions.
+class Action {
+public:
+ typedef ActionList::size_type size_type;
+ typedef ActionList::iterator iterator;
+ typedef ActionList::const_iterator const_iterator;
+
+ enum ActionClass {
+ InputClass = 0,
+ BindArchClass,
+ PreprocessJobClass,
+ PrecompileJobClass,
+ AnalyzeJobClass,
+ CompileJobClass,
+ AssembleJobClass,
+ LinkJobClass,
+ LipoJobClass,
+
+ JobClassFirst=PreprocessJobClass,
+ JobClassLast=LipoJobClass
+ };
+
+ static const char *getClassName(ActionClass AC);
+
+private:
+ ActionClass Kind;
+
+ /// The output type of this action.
+ types::ID Type;
+
+ ActionList Inputs;
+
+protected:
+ Action(ActionClass _Kind, types::ID _Type) : Kind(_Kind), Type(_Type) {}
+ Action(ActionClass _Kind, Action *Input, types::ID _Type)
+ : Kind(_Kind), Type(_Type), Inputs(&Input, &Input + 1) {}
+ Action(ActionClass _Kind, const ActionList &_Inputs, types::ID _Type)
+ : Kind(_Kind), Type(_Type), Inputs(_Inputs) {}
+public:
+ virtual ~Action();
+
+ ActionClass getKind() const { return Kind; }
+ types::ID getType() const { return Type; }
+
+ ActionList &getInputs() { return Inputs; }
+ const ActionList &getInputs() const { return Inputs; }
+
+ size_type size() const { return Inputs.size(); }
+
+ iterator begin() { return Inputs.begin(); }
+ iterator end() { return Inputs.end(); }
+ const_iterator begin() const { return Inputs.begin(); }
+ const_iterator end() const { return Inputs.end(); }
+
+ static bool classof(const Action *) { return true; }
+};
+
+class InputAction : public Action {
+ const Arg &Input;
+public:
+ InputAction(const Arg &_Input, types::ID _Type);
+
+ const Arg &getInputArg() const { return Input; }
+
+ static bool classof(const Action *A) {
+ return A->getKind() == InputClass;
+ }
+ static bool classof(const InputAction *) { return true; }
+};
+
+class BindArchAction : public Action {
+ /// The architecture to bind, or 0 if the default architecture
+ /// should be bound.
+ const char *ArchName;
+
+public:
+ BindArchAction(Action *Input, const char *_ArchName);
+
+ const char *getArchName() const { return ArchName; }
+
+ static bool classof(const Action *A) {
+ return A->getKind() == BindArchClass;
+ }
+ static bool classof(const BindArchAction *) { return true; }
+};
+
+class JobAction : public Action {
+protected:
+ JobAction(ActionClass Kind, Action *Input, types::ID Type);
+ JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type);
+
+public:
+ static bool classof(const Action *A) {
+ return (A->getKind() >= JobClassFirst &&
+ A->getKind() <= JobClassLast);
+ }
+ static bool classof(const JobAction *) { return true; }
+};
+
+class PreprocessJobAction : public JobAction {
+public:
+ PreprocessJobAction(Action *Input, types::ID OutputType);
+
+ static bool classof(const Action *A) {
+ return A->getKind() == PreprocessJobClass;
+ }
+ static bool classof(const PreprocessJobAction *) { return true; }
+};
+
+class PrecompileJobAction : public JobAction {
+public:
+ PrecompileJobAction(Action *Input, types::ID OutputType);
+
+ static bool classof(const Action *A) {
+ return A->getKind() == PrecompileJobClass;
+ }
+ static bool classof(const PrecompileJobAction *) { return true; }
+};
+
+class AnalyzeJobAction : public JobAction {
+public:
+ AnalyzeJobAction(Action *Input, types::ID OutputType);
+
+ static bool classof(const Action *A) {
+ return A->getKind() == AnalyzeJobClass;
+ }
+ static bool classof(const AnalyzeJobAction *) { return true; }
+};
+
+class CompileJobAction : public JobAction {
+public:
+ CompileJobAction(Action *Input, types::ID OutputType);
+
+ static bool classof(const Action *A) {
+ return A->getKind() == CompileJobClass;
+ }
+ static bool classof(const CompileJobAction *) { return true; }
+};
+
+class AssembleJobAction : public JobAction {
+public:
+ AssembleJobAction(Action *Input, types::ID OutputType);
+
+ static bool classof(const Action *A) {
+ return A->getKind() == AssembleJobClass;
+ }
+ static bool classof(const AssembleJobAction *) { return true; }
+};
+
+class LinkJobAction : public JobAction {
+public:
+ LinkJobAction(ActionList &Inputs, types::ID Type);
+
+ static bool classof(const Action *A) {
+ return A->getKind() == LinkJobClass;
+ }
+ static bool classof(const LinkJobAction *) { return true; }
+};
+
+class LipoJobAction : public JobAction {
+public:
+ LipoJobAction(ActionList &Inputs, types::ID Type);
+
+ static bool classof(const Action *A) {
+ return A->getKind() == LipoJobClass;
+ }
+ static bool classof(const LipoJobAction *) { return true; }
+};
+
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Driver/Arg.h b/include/clang/Driver/Arg.h
new file mode 100644
index 000000000000..6bed2b8cbdef
--- /dev/null
+++ b/include/clang/Driver/Arg.h
@@ -0,0 +1,230 @@
+//===--- Arg.h - Parsed Argument Classes ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_DRIVER_ARG_H_
+#define CLANG_DRIVER_ARG_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 "Util.h"
+#include <vector>
+#include <string>
+
+namespace clang {
+namespace driver {
+ class ArgList;
+ class Option;
+
+ /// Arg - A concrete instance of a particular driver option.
+ ///
+ /// The Arg class encodes just enough information to be able to
+ /// derive the argument values efficiently. In addition, Arg
+ /// instances have an intrusive double linked list which is used by
+ /// ArgList to provide efficient iteration over all instances of a
+ /// particular option.
+ class Arg {
+ public:
+ enum ArgClass {
+ FlagClass = 0,
+ PositionalClass,
+ JoinedClass,
+ SeparateClass,
+ CommaJoinedClass,
+ JoinedAndSeparateClass
+ };
+
+ private:
+ ArgClass Kind;
+
+ /// The option this argument is an instance of.
+ const Option *Opt;
+
+ /// The argument this argument was derived from (during tool chain
+ /// argument translation), if any.
+ const Arg *BaseArg;
+
+ /// The index at which this argument appears in the containing
+ /// ArgList.
+ unsigned Index;
+
+ /// Flag indicating whether this argument was used to effect
+ /// compilation; used for generating "argument unused"
+ /// diagnostics.
+ mutable bool Claimed;
+
+ protected:
+ Arg(ArgClass Kind, const Option *Opt, unsigned Index,
+ const Arg *BaseArg = 0);
+
+ public:
+ Arg(const Arg &);
+ virtual ~Arg();
+
+ ArgClass getKind() const { return Kind; }
+ const Option &getOption() const { return *Opt; }
+ unsigned getIndex() const { return Index; }
+
+ /// getBaseArg - Return the base argument which generated this
+ /// arg; this is either the argument itself or the argument it was
+ /// derived from during tool chain specific argument translation.
+ const Arg &getBaseArg() const {
+ return BaseArg ? *BaseArg : *this;
+ }
+ void setBaseArg(const Arg *_BaseArg) {
+ BaseArg = _BaseArg;
+ }
+
+ bool isClaimed() const { return getBaseArg().Claimed; }
+
+ /// claim - Set the Arg claimed bit.
+
+ // FIXME: We need to deal with derived arguments and set the bit
+ // in the original argument; not the derived one.
+ void claim() const { getBaseArg().Claimed = true; }
+
+ virtual unsigned getNumValues() const = 0;
+ virtual const char *getValue(const ArgList &Args, unsigned N=0) const = 0;
+
+ /// render - Append the argument onto the given array as strings.
+ virtual void render(const ArgList &Args, ArgStringList &Output) const = 0;
+
+ /// renderAsInput - Append the argument, render as an input, onto
+ /// the given array as strings. The distinction is that some
+ /// options only render their values when rendered as a input
+ /// (e.g., Xlinker).
+ void renderAsInput(const ArgList &Args, ArgStringList &Output) const;
+
+ static bool classof(const Arg *) { return true; }
+
+ void dump() const;
+
+ /// getAsString - Return a formatted version of the argument and
+ /// its values, for debugging and diagnostics.
+ std::string getAsString(const ArgList &Args) const;
+ };
+
+ /// FlagArg - An argument with no value.
+ class FlagArg : public Arg {
+ public:
+ FlagArg(const Option *Opt, unsigned Index, const Arg *BaseArg = 0);
+
+ virtual void render(const ArgList &Args, ArgStringList &Output) const;
+
+ virtual unsigned getNumValues() const { return 0; }
+ virtual const char *getValue(const ArgList &Args, unsigned N=0) const;
+
+ static bool classof(const Arg *A) {
+ return A->getKind() == Arg::FlagClass;
+ }
+ static bool classof(const FlagArg *) { return true; }
+ };
+
+ /// PositionalArg - A simple positional argument.
+ class PositionalArg : public Arg {
+ public:
+ PositionalArg(const Option *Opt, unsigned Index, const Arg *BaseArg = 0);
+
+ virtual void render(const ArgList &Args, ArgStringList &Output) const;
+
+ virtual unsigned getNumValues() const { return 1; }
+ virtual const char *getValue(const ArgList &Args, unsigned N=0) const;
+
+ static bool classof(const Arg *A) {
+ return A->getKind() == Arg::PositionalClass;
+ }
+ static bool classof(const PositionalArg *) { return true; }
+ };
+
+ /// JoinedArg - A single value argument where the value is joined
+ /// (suffixed) to the option.
+ class JoinedArg : public Arg {
+ public:
+ JoinedArg(const Option *Opt, unsigned Index, const Arg *BaseArg = 0);
+
+ virtual void render(const ArgList &Args, ArgStringList &Output) const;
+
+ virtual unsigned getNumValues() const { return 1; }
+ virtual const char *getValue(const ArgList &Args, unsigned N=0) const;
+
+ static bool classof(const Arg *A) {
+ return A->getKind() == Arg::JoinedClass;
+ }
+ static bool classof(const JoinedArg *) { return true; }
+ };
+
+ /// SeparateArg - An argument where one or more values follow the
+ /// option specifier immediately in the argument vector.
+ class SeparateArg : public Arg {
+ unsigned NumValues;
+
+ public:
+ SeparateArg(const Option *Opt, unsigned Index, unsigned NumValues,
+ const Arg *BaseArg = 0);
+
+ virtual void render(const ArgList &Args, ArgStringList &Output) const;
+
+ virtual unsigned getNumValues() const { return NumValues; }
+ virtual const char *getValue(const ArgList &Args, unsigned N=0) const;
+
+ static bool classof(const Arg *A) {
+ return A->getKind() == Arg::SeparateClass;
+ }
+ static bool classof(const SeparateArg *) { return true; }
+ };
+
+ /// CommaJoinedArg - An argument with multiple values joined by
+ /// commas and joined (suffixed) to the option specifier.
+ ///
+ /// The key point of this arg is that it renders its values into
+ /// separate arguments, which allows it to be used as a generic
+ /// mechanism for passing arguments through to tools.
+ class CommaJoinedArg : public Arg {
+ std::vector<std::string> Values;
+
+ public:
+ CommaJoinedArg(const Option *Opt, unsigned Index, const char *Str,
+ const Arg *BaseArg = 0);
+
+ virtual void render(const ArgList &Args, ArgStringList &Output) const;
+
+ virtual unsigned getNumValues() const { return Values.size(); }
+ virtual const char *getValue(const ArgList &Args, unsigned N=0) const;
+
+ static bool classof(const Arg *A) {
+ return A->getKind() == Arg::CommaJoinedClass;
+ }
+ static bool classof(const CommaJoinedArg *) { return true; }
+ };
+
+ /// JoinedAndSeparateArg - An argument with both joined and separate
+ /// values.
+ class JoinedAndSeparateArg : public Arg {
+ public:
+ JoinedAndSeparateArg(const Option *Opt, unsigned Index,
+ const Arg *BaseArg = 0);
+
+ virtual void render(const ArgList &Args, ArgStringList &Output) const;
+
+ virtual unsigned getNumValues() const { return 2; }
+ virtual const char *getValue(const ArgList &Args, unsigned N=0) const;
+
+ static bool classof(const Arg *A) {
+ return A->getKind() == Arg::JoinedAndSeparateClass;
+ }
+ static bool classof(const JoinedAndSeparateArg *) { return true; }
+ };
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h
new file mode 100644
index 000000000000..84e0329a375e
--- /dev/null
+++ b/include/clang/Driver/ArgList.h
@@ -0,0 +1,245 @@
+//===--- ArgList.h - Argument List Management ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_DRIVER_ARGLIST_H_
+#define CLANG_DRIVER_ARGLIST_H_
+
+#include "clang/Driver/Options.h"
+
+#include "clang/Driver/Util.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include <list>
+
+namespace clang {
+namespace driver {
+ class Arg;
+
+ /// ArgList - Ordered collection of driver arguments.
+ ///
+ /// The ArgList class manages a list of Arg instances as well as
+ /// auxiliary data and convenience methods to allow Tools to quickly
+ /// check for the presence of Arg instances for a particular Option
+ /// and to iterate over groups of arguments.
+ class ArgList {
+ public:
+ typedef llvm::SmallVector<Arg*, 16> arglist_type;
+ typedef arglist_type::iterator iterator;
+ typedef arglist_type::const_iterator const_iterator;
+ typedef arglist_type::reverse_iterator reverse_iterator;
+ typedef arglist_type::const_reverse_iterator const_reverse_iterator;
+
+ private:
+ /// The full list of arguments.
+ arglist_type &Args;
+
+ protected:
+ ArgList(arglist_type &Args);
+
+ public:
+ virtual ~ArgList();
+
+ /// @name Arg Access
+ /// @{
+
+ /// append - Append \arg A to the arg list.
+ void append(Arg *A);
+
+ arglist_type &getArgs() { return Args; }
+ const arglist_type &getArgs() const { return Args; }
+
+ unsigned size() const { return Args.size(); }
+
+ iterator begin() { return Args.begin(); }
+ iterator end() { return Args.end(); }
+
+ reverse_iterator rbegin() { return Args.rbegin(); }
+ reverse_iterator rend() { return Args.rend(); }
+
+ const_iterator begin() const { return Args.begin(); }
+ const_iterator end() const { return Args.end(); }
+
+ const_reverse_iterator rbegin() const { return Args.rbegin(); }
+ const_reverse_iterator rend() const { return Args.rend(); }
+
+ /// hasArg - Does the arg list contain any option matching \arg Id.
+ ///
+ /// \arg Claim Whether the argument should be claimed, if it exists.
+ bool hasArg(options::ID Id, bool Claim=true) const {
+ return getLastArg(Id, Claim) != 0;
+ }
+ bool hasArg(options::ID Id0, options::ID Id1, bool Claim=true) const {
+ return getLastArg(Id0, Id1, Claim) != 0;
+ }
+
+ /// getLastArg - Return the last argument matching \arg Id, or null.
+ ///
+ /// \arg Claim Whether the argument should be claimed, if it exists.
+ Arg *getLastArg(options::ID Id, bool Claim=true) const;
+ Arg *getLastArg(options::ID Id0, options::ID Id1, bool Claim=true) const;
+
+ /// getArgString - Return the input argument string at \arg Index.
+ virtual const char *getArgString(unsigned Index) const = 0;
+ /// @name Translation Utilities
+ /// @{
+
+ /// hasFlag - Given an option \arg Pos and its negative form \arg
+ /// Neg, return true if the option is present, false if the
+ /// negation is present, and \arg Default if neither option is
+ /// given. If both the option and its negation are present, the
+ /// last one wins.
+ bool hasFlag(options::ID Pos, options::ID Neg, bool Default=true) const;
+
+ /// AddLastArg - Render only the last argument match \arg Id0, if
+ /// present.
+ void AddLastArg(ArgStringList &Output, options::ID Id0) const;
+
+ /// AddAllArgs - Render all arguments matching the given ids.
+ void AddAllArgs(ArgStringList &Output, options::ID Id0) const;
+ void AddAllArgs(ArgStringList &Output, options::ID Id0,
+ options::ID Id1) const;
+ void AddAllArgs(ArgStringList &Output, options::ID Id0, options::ID Id1,
+ options::ID Id2) const;
+
+ /// AddAllArgValues - Render the argument values of all arguments
+ /// matching the given ids.
+ void AddAllArgValues(ArgStringList &Output, options::ID Id0) const;
+ void AddAllArgValues(ArgStringList &Output, options::ID Id0,
+ options::ID Id1) const;
+
+ /// AddAllArgsTranslated - Render all the arguments matching the
+ /// given ids, but forced to separate args and using the provided
+ /// name instead of the first option value.
+ ///
+ /// \param Joined - If true, render the argument as joined with
+ /// the option specifier.
+ void AddAllArgsTranslated(ArgStringList &Output, options::ID Id0,
+ const char *Translation,
+ bool Joined = false) const;
+
+ /// ClaimAllArgs - Claim all arguments which match the given
+ /// option id.
+ void ClaimAllArgs(options::ID Id0) const;
+
+ /// @}
+ /// @name Arg Synthesis
+ /// @{
+
+ /// MakeArgString - Construct a constant string pointer whose
+ /// lifetime will match that of the ArgList.
+ virtual const char *MakeArgString(const char *Str) const = 0;
+
+ /// @}
+ };
+
+ class InputArgList : public ArgList {
+ private:
+ /// The internal list of arguments.
+ arglist_type ActualArgs;
+
+ /// List of argument strings used by the contained Args.
+ ///
+ /// This is mutable since we treat the ArgList as being the list
+ /// of Args, and allow routines to add new strings (to have a
+ /// convenient place to store the memory) via MakeIndex.
+ mutable ArgStringList ArgStrings;
+
+ /// Strings for synthesized arguments.
+ ///
+ /// This is mutable since we treat the ArgList as being the list
+ /// of Args, and allow routines to add new strings (to have a
+ /// convenient place to store the memory) via MakeIndex.
+ mutable std::list<std::string> SynthesizedStrings;
+
+ /// The number of original input argument strings.
+ unsigned NumInputArgStrings;
+
+ public:
+ InputArgList(const char **ArgBegin, const char **ArgEnd);
+ InputArgList(const ArgList &);
+ ~InputArgList();
+
+ virtual const char *getArgString(unsigned Index) const {
+ return ArgStrings[Index];
+ }
+
+ /// getNumInputArgStrings - Return the number of original input
+ /// argument strings.
+ unsigned getNumInputArgStrings() const { return NumInputArgStrings; }
+
+ /// @name Arg Synthesis
+ /// @{
+
+ public:
+ /// MakeIndex - Get an index for the given string(s).
+ unsigned MakeIndex(const char *String0) const;
+ unsigned MakeIndex(const char *String0, const char *String1) const;
+
+ virtual const char *MakeArgString(const char *Str) const;
+
+ /// @}
+ };
+
+ /// DerivedArgList - An ordered collection of driver arguments,
+ /// whose storage may be in another argument list.
+ class DerivedArgList : public ArgList {
+ InputArgList &BaseArgs;
+
+ /// The internal list of arguments.
+ arglist_type ActualArgs;
+
+ /// The list of arguments we synthesized.
+ arglist_type SynthesizedArgs;
+
+ /// Is this only a proxy for the base ArgList?
+ bool OnlyProxy;
+
+ public:
+ /// Construct a new derived arg list from \arg BaseArgs.
+ ///
+ /// \param OnlyProxy - If true, this is only a proxy for the base
+ /// list (to adapt the type), and it's Args list is unused.
+ DerivedArgList(InputArgList &BaseArgs, bool OnlyProxy);
+ ~DerivedArgList();
+
+ virtual const char *getArgString(unsigned Index) const {
+ return BaseArgs.getArgString(Index);
+ }
+
+ /// @name Arg Synthesis
+ /// @{
+
+ virtual const char *MakeArgString(const char *Str) const;
+
+ /// MakeFlagArg - Construct a new FlagArg for the given option
+ /// \arg Id.
+ Arg *MakeFlagArg(const Arg *BaseArg, const Option *Opt) const;
+
+ /// MakePositionalArg - Construct a new Positional arg for the
+ /// given option \arg Id, with the provided \arg Value.
+ Arg *MakePositionalArg(const Arg *BaseArg, const Option *Opt,
+ const char *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,
+ const char *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,
+ const char *Value) const;
+
+ /// @}
+ };
+
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h
new file mode 100644
index 000000000000..4985f30ad553
--- /dev/null
+++ b/include/clang/Driver/Compilation.h
@@ -0,0 +1,127 @@
+//===--- Compilation.h - Compilation Task Data Structure --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_DRIVER_COMPILATION_H_
+#define CLANG_DRIVER_COMPILATION_H_
+
+#include "clang/Driver/Job.h"
+#include "clang/Driver/Util.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace llvm {
+ class raw_ostream;
+}
+
+namespace clang {
+namespace driver {
+ class DerivedArgList;
+ class Driver;
+ class InputArgList;
+ class JobList;
+ class ToolChain;
+
+/// Compilation - A set of tasks to perform for a single driver
+/// invocation.
+class Compilation {
+ /// The driver we were created by.
+ Driver &TheDriver;
+
+ /// The default tool chain.
+ ToolChain &DefaultToolChain;
+
+ /// The original (untranslated) input argument list.
+ InputArgList *Args;
+
+ /// The list of actions.
+ ActionList Actions;
+
+ /// The root list of jobs.
+ JobList Jobs;
+
+ /// Cache of translated arguments for a particular tool chain.
+ llvm::DenseMap<const ToolChain*, DerivedArgList*> TCArgs;
+
+ /// Temporary files which should be removed on exit.
+ ArgStringList TempFiles;
+
+ /// Result files which should be removed on failure.
+ ArgStringList ResultFiles;
+
+public:
+ Compilation(Driver &D, ToolChain &DefaultToolChain, InputArgList *Args);
+ ~Compilation();
+
+ const Driver &getDriver() const { return TheDriver; }
+
+ const ToolChain &getDefaultToolChain() const { return DefaultToolChain; }
+
+ const InputArgList &getArgs() const { return *Args; }
+
+ ActionList &getActions() { return Actions; }
+ const ActionList &getActions() const { return Actions; }
+
+ JobList &getJobs() { return Jobs; }
+
+ /// getArgsForToolChain - Return the derived argument list for the
+ /// tool chain \arg TC (or the default tool chain, if TC is not
+ /// specified).
+ const DerivedArgList &getArgsForToolChain(const ToolChain *TC = 0);
+
+ /// addTempFile - Add a file to remove on exit, and returns its
+ /// argument.
+ const char *addTempFile(const char *Name) {
+ TempFiles.push_back(Name);
+ return Name;
+ }
+
+ /// addResultFile - Add a file to remove on failure, and returns its
+ /// argument.
+ const char *addResultFile(const char *Name) {
+ ResultFiles.push_back(Name);
+ return Name;
+ }
+
+ /// Execute - Execute the compilation jobs and return an
+ /// appropriate exit code.
+ int Execute() const;
+
+private:
+ /// CleanupFileList - Remove the files in the given list.
+ ///
+ /// \param IssueErrors - Report failures as errors.
+ /// \return Whether all files were removed successfully.
+ bool CleanupFileList(const ArgStringList &Files,
+ bool IssueErrors=false) const;
+
+ /// PrintJob - Print one job in -### format.
+ ///
+ /// OS - The stream to print on.
+ /// J - The job to print.
+ /// Terminator - A string to print at the end of the line.
+ /// Quote - Should separate arguments be quoted.
+ void PrintJob(llvm::raw_ostream &OS, const Job &J,
+ const char *Terminator, bool Quote) const;
+
+ /// ExecuteCommand - Execute an actual command.
+ ///
+ /// \return The result code of the subprocess.
+ int ExecuteCommand(const Command &C) const;
+
+ /// ExecuteJob - Execute a single job.
+ ///
+ /// \return The accumulated result code of the job.
+ int ExecuteJob(const Job &J) const;
+};
+
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
new file mode 100644
index 000000000000..66e3b9787594
--- /dev/null
+++ b/include/clang/Driver/Driver.h
@@ -0,0 +1,271 @@
+//===--- Driver.h - Clang GCC Compatible Driver -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_DRIVER_DRIVER_H_
+#define CLANG_DRIVER_DRIVER_H_
+
+#include "clang/Basic/Diagnostic.h"
+
+#include "clang/Driver/Phases.h"
+#include "clang/Driver/Util.h"
+
+#include "llvm/System/Path.h" // FIXME: Kill when CompilationInfo
+ // lands.
+#include <list>
+#include <set>
+#include <string>
+
+namespace clang {
+namespace driver {
+ class Action;
+ class ArgList;
+ class Compilation;
+ class HostInfo;
+ class InputArgList;
+ class InputInfo;
+ class JobAction;
+ class OptTable;
+ class PipedJob;
+ class ToolChain;
+
+/// Driver - Encapsulate logic for constructing compilation processes
+/// from a set of gcc-driver-like command line arguments.
+class Driver {
+ OptTable *Opts;
+
+ Diagnostic &Diags;
+
+public:
+ // Diag - Forwarding function for diagnostics.
+ DiagnosticBuilder Diag(unsigned DiagID) const {
+ return Diags.Report(FullSourceLoc(), DiagID);
+ }
+
+ // FIXME: Privatize once interface is stable.
+public:
+ /// The name the driver was invoked as.
+ std::string Name;
+
+ /// The path the driver executable was in, as invoked from the
+ /// command line.
+ std::string Dir;
+
+ /// Default host triple.
+ std::string DefaultHostTriple;
+
+ /// Default name for linked images (e.g., "a.out").
+ std::string DefaultImageName;
+
+ /// Host information for the platform the driver is running as. This
+ /// will generally be the actual host platform, but not always.
+ const HostInfo *Host;
+
+ /// Information about the host which can be overriden by the user.
+ std::string HostBits, HostMachine, HostSystem, HostRelease;
+
+ /// Whether the driver should follow g++ like behavior.
+ bool CCCIsCXX : 1;
+
+ /// Echo commands while executing (in -v style).
+ bool CCCEcho : 1;
+
+ /// Only print tool bindings, don't build any jobs.
+ bool CCCPrintBindings : 1;
+
+ /// Name to use when calling the generic gcc.
+ std::string CCCGenericGCCName;
+
+private:
+ /// Use the clang compiler where possible.
+ bool CCCUseClang : 1;
+
+ /// Use clang for handling C++ and Objective-C++ inputs.
+ bool CCCUseClangCXX : 1;
+
+ /// Use clang as a preprocessor (clang's preprocessor will still be
+ /// used where an integrated CPP would).
+ bool CCCUseClangCPP : 1;
+
+public:
+ /// Use lazy precompiled headers for PCH support.
+ bool CCCUsePCH;
+
+private:
+ /// Only use clang for the given architectures (only used when
+ /// non-empty).
+ std::set<std::string> CCCClangArchs;
+
+ /// Certain options suppress the 'no input files' warning.
+ bool SuppressMissingInputWarning : 1;
+
+ std::list<std::string> TempFiles;
+ std::list<std::string> ResultFiles;
+
+public:
+ Driver(const char *_Name, const char *_Dir,
+ const char *_DefaultHostTriple,
+ const char *_DefaultImageName,
+ Diagnostic &_Diags);
+ ~Driver();
+
+ /// @name Accessors
+ /// @{
+
+ const OptTable &getOpts() const { return *Opts; }
+
+ const Diagnostic &getDiags() const { return Diags; }
+
+ /// @}
+ /// @name Primary Functionality
+ /// @{
+
+ /// BuildCompilation - Construct a compilation object for a command
+ /// line argument vector.
+ ///
+ /// \return A compilation, or 0 if none was built for the given
+ /// 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(int argc, const char **argv);
+
+ /// @name Driver Steps
+ /// @{
+
+ /// ParseArgStrings - Parse the given list of strings into an
+ /// ArgList.
+ InputArgList *ParseArgStrings(const char **ArgBegin, const char **ArgEnd);
+
+ /// BuildActions - Construct the list of actions to perform for the
+ /// given arguments, which are only done for a single architecture.
+ ///
+ /// \param Args - The input arguments.
+ /// \param Actions - The list to store the resulting actions onto.
+ void BuildActions(const ArgList &Args, ActionList &Actions) const;
+
+ /// BuildUniversalActions - Construct the list of actions to perform
+ /// for the given arguments, which may require a universal build.
+ ///
+ /// \param Args - The input arguments.
+ /// \param Actions - The list to store the resulting actions onto.
+ void BuildUniversalActions(const ArgList &Args, ActionList &Actions) const;
+
+ /// BuildJobs - Bind actions to concrete tools and translate
+ /// arguments to form the list of jobs to run.
+ ///
+ /// \arg C - The compilation that is being built.
+ void BuildJobs(Compilation &C) const;
+
+ /// @}
+ /// @name Helper Methods
+ /// @{
+
+ /// PrintActions - Print the list of actions.
+ void PrintActions(const Compilation &C) const;
+
+ /// PrintHelp - Print the help text.
+ ///
+ /// \param ShowHidden - Show hidden options.
+ void PrintHelp(bool ShowHidden) const;
+
+ /// PrintOptions - Print the list of arguments.
+ void PrintOptions(const ArgList &Args) const;
+
+ /// PrintVersion - Print the driver version.
+ void PrintVersion(const Compilation &C) const;
+
+ /// GetFilePath - Lookup \arg Name in the list of file search paths.
+ ///
+ /// \arg TC - The tool chain for additional information on
+ /// directories to search.
+ // FIXME: This should be in CompilationInfo.
+ llvm::sys::Path GetFilePath(const char *Name, const ToolChain &TC) const;
+
+ /// GetProgramPath - Lookup \arg Name in the list of program search
+ /// paths.
+ ///
+ /// \arg TC - The provided tool chain for additional information on
+ /// directories to search.
+ ///
+ /// \arg WantFile - False when searching for an executable file, otherwise
+ /// true. Defaults to false.
+ // FIXME: This should be in CompilationInfo.
+ llvm::sys::Path GetProgramPath(const char *Name, const ToolChain &TC,
+ bool WantFile = false) const;
+
+ /// HandleImmediateArgs - Handle any arguments which should be
+ /// treated before building actions or binding tools.
+ ///
+ /// \return Whether any compilation should be built for this
+ /// invocation.
+ bool HandleImmediateArgs(const Compilation &C);
+
+ /// ConstructAction - Construct the appropriate action to do for
+ /// \arg Phase on the \arg Input, taking in to account arguments
+ /// like -fsyntax-only or --analyze.
+ Action *ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
+ Action *Input) const;
+
+
+ /// BuildJobsForAction - Construct the jobs to perform for the
+ /// action \arg A.
+ void BuildJobsForAction(Compilation &C,
+ const Action *A,
+ const ToolChain *TC,
+ bool CanAcceptPipe,
+ bool AtTopLevel,
+ const char *LinkingOutput,
+ InputInfo &Result) const;
+
+ /// GetNamedOutputPath - Return the name to use for the output of
+ /// the action \arg JA. The result is appended to the compilation's
+ /// list of temporary or result files, as appropriate.
+ ///
+ /// \param C - The compilation.
+ /// \param JA - The action of interest.
+ /// \param BaseInput - The original input file that this action was
+ /// triggered by.
+ /// \param AtTopLevel - Whether this is a "top-level" action.
+ const char *GetNamedOutputPath(Compilation &C,
+ const JobAction &JA,
+ 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.
+ ///
+ /// GCC goes to extra lengths here to be a bit more robust.
+ std::string GetTemporaryPath(const char *Suffix) const;
+
+ /// GetHostInfo - Construct a new host info object for the given
+ /// host triple.
+ const HostInfo *GetHostInfo(const char *HostTriple) const;
+
+ /// ShouldUseClangCompilar - Should the clang compiler be used to
+ /// handle this action.
+ bool ShouldUseClangCompiler(const Compilation &C, const JobAction &JA,
+ const std::string &ArchName) const;
+
+ /// @}
+
+ /// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and
+ /// return the grouped values as integers. Numbers which are not
+ /// provided are set to 0.
+ ///
+ /// \return True if the entire string was parsed (9.2), or all
+ /// groups were parsed (10.3.5extrastuff). HadExtra is true if all
+ /// groups were parsed but extra characters remain at the end.
+ static bool GetReleaseVersion(const char *Str, unsigned &Major,
+ unsigned &Minor, unsigned &Micro,
+ bool &HadExtra);
+};
+
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Driver/DriverDiagnostic.h b/include/clang/Driver/DriverDiagnostic.h
new file mode 100644
index 000000000000..2a4413c24e07
--- /dev/null
+++ b/include/clang/Driver/DriverDiagnostic.h
@@ -0,0 +1,27 @@
+//===--- DiagnosticDriver.h - Diagnostics for libdriver ---------*- 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_DRIVERDIAGNOSTIC_H
+#define LLVM_CLANG_DRIVERDIAGNOSTIC_H
+
+#include "clang/Basic/Diagnostic.h"
+
+namespace clang {
+ namespace diag {
+ enum {
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM,
+#define DRIVERSTART
+#include "clang/Basic/DiagnosticDriverKinds.inc"
+#undef DIAG
+ NUM_BUILTIN_DRIVER_DIAGNOSTICS
+ };
+ } // end namespace diag
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Driver/HostInfo.h b/include/clang/Driver/HostInfo.h
new file mode 100644
index 000000000000..020bb3ab5a82
--- /dev/null
+++ b/include/clang/Driver/HostInfo.h
@@ -0,0 +1,84 @@
+//===--- HostInfo.h - Host specific information -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_DRIVER_HOSTINFO_H_
+#define CLANG_DRIVER_HOSTINFO_H_
+
+#include "clang/Driver/Types.h"
+#include "llvm/ADT/Triple.h"
+#include <string>
+
+namespace clang {
+namespace driver {
+ class ArgList;
+ class Driver;
+ class ToolChain;
+
+/// HostInfo - Config information about a particular host which may
+/// interact with driver behavior.
+///
+/// The host information is used for controlling the parts of the
+/// driver which interact with the platform the driver is ostensibly
+/// being run from. For testing purposes, the HostInfo used by the
+/// driver may differ from the actual host.
+class HostInfo {
+ const Driver &TheDriver;
+ const llvm::Triple Triple;
+
+protected:
+ HostInfo(const Driver &D, const llvm::Triple &_Triple);
+
+public:
+ virtual ~HostInfo();
+
+ const Driver &getDriver() const { return TheDriver; }
+
+ const llvm::Triple& getTriple() const { return Triple; }
+ std::string getArchName() const { return Triple.getArchName(); }
+ std::string getPlatformName() const { return Triple.getVendorName(); }
+ std::string getOSName() const { return Triple.getOSName(); }
+
+ /// useDriverDriver - Whether the driver should act as a driver
+ /// driver for this host and support -arch, -Xarch, etc.
+ virtual bool useDriverDriver() const = 0;
+
+ /// lookupTypeForExtension - Return the default language type to use
+ /// for the given extension.
+ virtual types::ID lookupTypeForExtension(const char *Ext) const = 0;
+
+ /// getToolChain - Construct the toolchain to use for this host.
+ ///
+ /// \param Args - The argument list, which may be used to alter the
+ /// default toolchain, for example in the presence of -m32 or -m64.
+ ///
+ /// \param ArchName - The architecture to return a toolchain for, or
+ /// 0 if unspecified. This will only ever be non-zero for hosts
+ /// which support a driver driver.
+
+ // FIXME: Pin down exactly what the HostInfo is allowed to use Args
+ // for here. Currently this is for -m32 / -m64 defaulting.
+ virtual ToolChain *getToolChain(const ArgList &Args,
+ const char *ArchName=0) const = 0;
+};
+
+const HostInfo *createDarwinHostInfo(const Driver &D,
+ const llvm::Triple& Triple);
+const HostInfo *createFreeBSDHostInfo(const Driver &D,
+ const llvm::Triple& Triple);
+const HostInfo *createDragonFlyHostInfo(const Driver &D,
+ const llvm::Triple& Triple);
+const HostInfo *createLinuxHostInfo(const Driver &D,
+ const llvm::Triple& Triple);
+const HostInfo *createUnknownHostInfo(const Driver &D,
+ const llvm::Triple& Triple);
+
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h
new file mode 100644
index 000000000000..f60f5146414c
--- /dev/null
+++ b/include/clang/Driver/Job.h
@@ -0,0 +1,138 @@
+//===--- Job.h - Commands to Execute ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_DRIVER_JOB_H_
+#define CLANG_DRIVER_JOB_H_
+
+#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;
+
+namespace clang {
+namespace driver {
+ class Command;
+
+class Job {
+public:
+ enum JobClass {
+ CommandClass,
+ PipedJobClass,
+ JobListClass
+ };
+
+private:
+ JobClass Kind;
+
+protected:
+ Job(JobClass _Kind) : Kind(_Kind) {}
+public:
+ virtual ~Job();
+
+ JobClass getKind() const { return Kind; }
+
+ /// addCommand - Append a command to the current job, which must be
+ /// either a piped job or a job list.
+ void addCommand(Command *C);
+
+ static bool classof(const Job *) { return true; }
+};
+
+ /// Command - An executable path/name and argument vector to
+ /// execute.
+class Command : public Job {
+ /// The executable to run.
+ const char *Executable;
+
+ /// The list of program arguments (not including the implicit first
+ /// argument, which will be the executable).
+ ArgStringList Arguments;
+
+public:
+ Command(const char *_Executable, const ArgStringList &_Arguments);
+
+ const char *getExecutable() const { return Executable; }
+ const ArgStringList &getArguments() const { return Arguments; }
+
+ static bool classof(const Job *J) {
+ return J->getKind() == CommandClass;
+ }
+ static bool classof(const Command *) { return true; }
+};
+
+ /// PipedJob - A list of Commands which should be executed together
+ /// with their standard inputs and outputs connected.
+class PipedJob : public Job {
+public:
+ typedef llvm::SmallVector<Command*, 4> list_type;
+ typedef list_type::size_type size_type;
+ typedef list_type::iterator iterator;
+ typedef list_type::const_iterator const_iterator;
+
+private:
+ list_type Commands;
+
+public:
+ PipedJob();
+
+ void addCommand(Command *C) { Commands.push_back(C); }
+
+ const list_type &getCommands() const { return Commands; }
+
+ size_type size() const { return Commands.size(); }
+ iterator begin() { return Commands.begin(); }
+ const_iterator begin() const { return Commands.begin(); }
+ iterator end() { return Commands.end(); }
+ const_iterator end() const { return Commands.end(); }
+
+ static bool classof(const Job *J) {
+ return J->getKind() == PipedJobClass;
+ }
+ static bool classof(const PipedJob *) { return true; }
+};
+
+ /// JobList - A sequence of jobs to perform.
+class JobList : public Job {
+public:
+ typedef llvm::SmallVector<Job*, 4> list_type;
+ typedef list_type::size_type size_type;
+ typedef list_type::iterator iterator;
+ typedef list_type::const_iterator const_iterator;
+
+private:
+ list_type Jobs;
+
+public:
+ JobList();
+
+ void addJob(Job *J) { Jobs.push_back(J); }
+
+ const list_type &getJobs() const { return Jobs; }
+
+ size_type size() const { return Jobs.size(); }
+ iterator begin() { return Jobs.begin(); }
+ const_iterator begin() const { return Jobs.begin(); }
+ iterator end() { return Jobs.end(); }
+ const_iterator end() const { return Jobs.end(); }
+
+ static bool classof(const Job *J) {
+ return J->getKind() == JobListClass;
+ }
+ static bool classof(const JobList *) { return true; }
+};
+
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Driver/Option.h b/include/clang/Driver/Option.h
new file mode 100644
index 000000000000..c59faef897ae
--- /dev/null
+++ b/include/clang/Driver/Option.h
@@ -0,0 +1,308 @@
+//===--- Option.h - Abstract Driver Options ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_DRIVER_OPTION_H_
+#define CLANG_DRIVER_OPTION_H_
+
+#include "Options.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;
+
+namespace clang {
+namespace driver {
+ class Arg;
+ class InputArgList;
+ class OptionGroup;
+
+ /// Option - Abstract representation for a single form of driver
+ /// argument.
+ ///
+ /// An Option class represents a form of option that the driver
+ /// takes, for example how many arguments the option has and how
+ /// they can be provided. Individual option instances store
+ /// additional information about what group the option is a member
+ /// of (if any), if the option is an alias, and a number of
+ /// flags. At runtime the driver parses the command line into
+ /// concrete Arg instances, each of which corresponds to a
+ /// particular Option instance.
+ class Option {
+ public:
+ enum OptionClass {
+ GroupClass = 0,
+ InputClass,
+ UnknownClass,
+ FlagClass,
+ JoinedClass,
+ SeparateClass,
+ CommaJoinedClass,
+ MultiArgClass,
+ JoinedOrSeparateClass,
+ JoinedAndSeparateClass
+ };
+
+ private:
+ OptionClass Kind;
+
+ options::ID ID;
+
+ /// The option name.
+ const char *Name;
+
+ /// Group this option is a member of, if any.
+ const OptionGroup *Group;
+
+ /// Option that this is an alias for, if any.
+ const Option *Alias;
+
+ /// Unsupported options will not be rejected.
+ bool Unsupported : 1;
+
+ /// Treat this option like a linker input?
+ bool LinkerInput : 1;
+
+ /// When rendering as an input, don't render the option.
+
+ // FIXME: We should ditch the render/renderAsInput distinction.
+ bool NoOptAsInput : 1;
+
+ /// Always render this option as separate form its value.
+ bool ForceSeparateRender : 1;
+
+ /// Always render this option joined with its value.
+ bool ForceJoinedRender : 1;
+
+ /// This option is only consumed by the driver.
+ bool DriverOption : 1;
+
+ /// This option should not report argument unused errors.
+ bool NoArgumentUnused : 1;
+
+ protected:
+ Option(OptionClass Kind, options::ID ID, const char *Name,
+ const OptionGroup *Group, const Option *Alias);
+ public:
+ virtual ~Option();
+
+ options::ID getId() const { return ID; }
+ OptionClass getKind() const { return Kind; }
+ const char *getName() const { return Name; }
+ const OptionGroup *getGroup() const { return Group; }
+ const Option *getAlias() const { return Alias; }
+
+ bool isUnsupported() const { return Unsupported; }
+ void setUnsupported(bool Value) { Unsupported = Value; }
+
+ bool isLinkerInput() const { return LinkerInput; }
+ void setLinkerInput(bool Value) { LinkerInput = Value; }
+
+ bool hasNoOptAsInput() const { return NoOptAsInput; }
+ void setNoOptAsInput(bool Value) { NoOptAsInput = Value; }
+
+ bool hasForceSeparateRender() const { return ForceSeparateRender; }
+ void setForceSeparateRender(bool Value) { ForceSeparateRender = Value; }
+
+ bool hasForceJoinedRender() const { return ForceJoinedRender; }
+ void setForceJoinedRender(bool Value) { ForceJoinedRender = Value; }
+
+ bool isDriverOption() const { return DriverOption; }
+ void setDriverOption(bool Value) { DriverOption = Value; }
+
+ bool hasNoArgumentUnused() const { return NoArgumentUnused; }
+ void setNoArgumentUnused(bool Value) { NoArgumentUnused = Value; }
+
+ bool hasForwardToGCC() const { return !DriverOption && !LinkerInput; }
+
+ /// getUnaliasedOption - Return the final option this option
+ /// aliases (itself, if the option has no alias).
+ const Option *getUnaliasedOption() const {
+ if (Alias) return Alias->getUnaliasedOption();
+ return this;
+ }
+
+ /// getRenderName - Return the name to use when rendering this
+ /// option.
+ const char *getRenderName() const {
+ return getUnaliasedOption()->getName();
+ }
+
+ /// matches - Predicate for whether this option is part of the
+ /// given option (which may be a group).
+ bool matches(const Option *Opt) const;
+ bool matches(options::ID Id) const;
+
+ /// accept - Potentially accept the current argument, returning a
+ /// new Arg instance, or 0 if the option does not accept this
+ /// argument (or the argument is missing values).
+ ///
+ /// If the option accepts the current argument, accept() sets
+ /// Index to the position where argument parsing should resume
+ /// (even if the argument is missing values).
+ virtual Arg *accept(const InputArgList &Args, unsigned &Index) const = 0;
+
+ void dump() const;
+
+ static bool classof(const Option *) { return true; }
+ };
+
+ /// OptionGroup - A set of options which are can be handled uniformly
+ /// by the driver.
+ class OptionGroup : public Option {
+ public:
+ OptionGroup(options::ID ID, const char *Name, const OptionGroup *Group);
+
+ virtual Arg *accept(const InputArgList &Args, unsigned &Index) const;
+
+ static bool classof(const Option *O) {
+ return O->getKind() == Option::GroupClass;
+ }
+ static bool classof(const OptionGroup *) { return true; }
+ };
+
+ // Dummy option classes.
+
+ /// InputOption - Dummy option class for representing driver inputs.
+ class InputOption : public Option {
+ public:
+ InputOption();
+
+ virtual Arg *accept(const InputArgList &Args, unsigned &Index) const;
+
+ static bool classof(const Option *O) {
+ return O->getKind() == Option::InputClass;
+ }
+ static bool classof(const InputOption *) { return true; }
+ };
+
+ /// UnknownOption - Dummy option class for represent unknown arguments.
+ class UnknownOption : public Option {
+ public:
+ UnknownOption();
+
+ virtual Arg *accept(const InputArgList &Args, unsigned &Index) const;
+
+ static bool classof(const Option *O) {
+ return O->getKind() == Option::UnknownClass;
+ }
+ static bool classof(const UnknownOption *) { return true; }
+ };
+
+ // Normal options.
+
+ class FlagOption : public Option {
+ public:
+ FlagOption(options::ID ID, const char *Name, const OptionGroup *Group,
+ const Option *Alias);
+
+ virtual Arg *accept(const InputArgList &Args, unsigned &Index) const;
+
+ static bool classof(const Option *O) {
+ return O->getKind() == Option::FlagClass;
+ }
+ static bool classof(const FlagOption *) { return true; }
+ };
+
+ class JoinedOption : public Option {
+ public:
+ JoinedOption(options::ID ID, const char *Name, const OptionGroup *Group,
+ const Option *Alias);
+
+ virtual Arg *accept(const InputArgList &Args, unsigned &Index) const;
+
+ static bool classof(const Option *O) {
+ return O->getKind() == Option::JoinedClass;
+ }
+ static bool classof(const JoinedOption *) { return true; }
+ };
+
+ class SeparateOption : public Option {
+ public:
+ SeparateOption(options::ID ID, const char *Name, const OptionGroup *Group,
+ const Option *Alias);
+
+ virtual Arg *accept(const InputArgList &Args, unsigned &Index) const;
+
+ static bool classof(const Option *O) {
+ return O->getKind() == Option::SeparateClass;
+ }
+ static bool classof(const SeparateOption *) { return true; }
+ };
+
+ class CommaJoinedOption : public Option {
+ public:
+ CommaJoinedOption(options::ID ID, const char *Name,
+ const OptionGroup *Group, const Option *Alias);
+
+ virtual Arg *accept(const InputArgList &Args, unsigned &Index) const;
+
+ static bool classof(const Option *O) {
+ return O->getKind() == Option::CommaJoinedClass;
+ }
+ static bool classof(const CommaJoinedOption *) { return true; }
+ };
+
+ // FIXME: Fold MultiArgOption into SeparateOption?
+
+ /// MultiArgOption - An option which takes multiple arguments (these
+ /// are always separate arguments).
+ class MultiArgOption : public Option {
+ unsigned NumArgs;
+
+ public:
+ MultiArgOption(options::ID ID, const char *Name, const OptionGroup *Group,
+ const Option *Alias, unsigned NumArgs);
+
+ unsigned getNumArgs() const { return NumArgs; }
+
+ virtual Arg *accept(const InputArgList &Args, unsigned &Index) const;
+
+ static bool classof(const Option *O) {
+ return O->getKind() == Option::MultiArgClass;
+ }
+ static bool classof(const MultiArgOption *) { return true; }
+ };
+
+ /// JoinedOrSeparateOption - An option which either literally
+ /// prefixes its (non-empty) value, or is follwed by a value.
+ class JoinedOrSeparateOption : public Option {
+ public:
+ JoinedOrSeparateOption(options::ID ID, const char *Name,
+ const OptionGroup *Group, const Option *Alias);
+
+ virtual Arg *accept(const InputArgList &Args, unsigned &Index) const;
+
+ static bool classof(const Option *O) {
+ return O->getKind() == Option::JoinedOrSeparateClass;
+ }
+ static bool classof(const JoinedOrSeparateOption *) { return true; }
+ };
+
+ /// JoinedAndSeparateOption - An option which literally prefixes its
+ /// value and is followed by another value.
+ class JoinedAndSeparateOption : public Option {
+ public:
+ JoinedAndSeparateOption(options::ID ID, const char *Name,
+ const OptionGroup *Group, const Option *Alias);
+
+ virtual Arg *accept(const InputArgList &Args, unsigned &Index) const;
+
+ static bool classof(const Option *O) {
+ return O->getKind() == Option::JoinedAndSeparateClass;
+ }
+ static bool classof(const JoinedAndSeparateOption *) { return true; }
+ };
+
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Driver/Options.def b/include/clang/Driver/Options.def
new file mode 100644
index 000000000000..c2981b934fc9
--- /dev/null
+++ b/include/clang/Driver/Options.def
@@ -0,0 +1,624 @@
+//===--- Options.def - Driver option info -----------------------*- 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 driver option information. Users of this file
+// must define the OPTION macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OPTION
+#error "Define OPTION prior to including this file!"
+#endif
+
+// OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM,
+// HELPTEXT, METAVARNAME)
+
+// The NAME value is the option name as a string.
+
+// The ID is the internal option id, which must be a valid
+// C++ identifier, and results in a clang::driver::options::OPT_XX
+// enum constant for XX.
+//
+// We want to unambiguously be able to refer to options from the
+// driver source code, for this reason the option name is mangled into
+// an id. This mangling isn't guaranteed to have an inverse, but for
+// practical purposes it does.
+//
+// The mangling scheme is to ignore the leading '-', and perform the
+// following substitutions:
+// _ => __
+// - => _
+// # => _HASH
+// , => _COMMA
+// = => _EQ
+// C++ => CXX
+
+// The KIND value is the option type, one of Group, Flag, Joined,
+// Separate, CommaJoined, JoinedOrSeparate, JoinedAndSeparate.
+
+// The GROUP value is the internal name of the option group, or
+// INVALID if the option is not part of a group.
+
+// The ALIAS value is the internal name of an aliased option, or
+// INVALID if the option is not an alias.
+
+// The PARAM value is a string containing option flags. Valid values:
+// d: The option is a "driver" option, and should not be forwarded to
+// gcc.
+//
+// i: The option should not render the name when rendered as an
+// input (i.e., the option is rendered as values).
+//
+// l: The option is a linker input.
+//
+// q: Don't report argument unused warnings for this option; this is
+// useful for options like -static or -dynamic which a user may
+// always end up passing, even if the platform defaults to (or
+// only supports) that option.
+//
+// u: The option is unsupported, and the driver will reject command
+// lines that use it.
+//
+// S: The option should be rendered separately, even if joined (only
+// sensible on joined options).
+//
+// J: The option should be rendered joined, even if separate (only
+// sensible on single value separate options).
+
+// The PARAM value is an arbitrary integer parameter; currently
+// this is only used for specifying the number of arguments for
+// Separate options.
+
+// The HELPTEXT value is the string to print for this option in
+// --help, or 0 if undocumented.
+
+// The METAVAR value is the name to use for this values arguments (if
+// any) in the help text. This must be defined if the help text is
+// specified and this option takes extra arguments.
+
+//
+
+// For now (pre-TableGen, that is) Options must be in order. The
+// ordering is *almost* lexicographic, with two exceptions. First,
+// '\0' comes at the end of the alphabet instead of the beginning
+// (thus options preceed any other options which prefix them). Second,
+// for options with the same name, the less permissive version should
+// come first; a Flag option should preceed a Joined option, for
+// example.
+
+/////////
+// Groups
+
+OPTION("<I group>", I_Group, Group, INVALID, INVALID, "", 0, 0, 0)
+OPTION("<M group>", M_Group, Group, INVALID, INVALID, "", 0, 0, 0)
+OPTION("<T group>", T_Group, Group, INVALID, INVALID, "", 0, 0, 0)
+OPTION("<O group>", O_Group, Group, INVALID, INVALID, "", 0, 0, 0)
+OPTION("<W group>", W_Group, Group, INVALID, INVALID, "", 0, 0, 0)
+OPTION("<X group>", X_Group, Group, INVALID, INVALID, "", 0, 0, 0)
+OPTION("<a group>", a_Group, Group, INVALID, INVALID, "", 0, 0, 0)
+OPTION("<d group>", d_Group, Group, INVALID, INVALID, "", 0, 0, 0)
+OPTION("<f group>", f_Group, Group, INVALID, INVALID, "", 0, 0, 0)
+OPTION("<g group>", g_Group, Group, INVALID, INVALID, "", 0, 0, 0)
+OPTION("<i group>", i_Group, Group, INVALID, INVALID, "", 0, 0, 0)
+OPTION("<clang i group>", clang_i_Group, Group, i_Group, INVALID, "", 0, 0, 0)
+OPTION("<m group>", m_Group, Group, INVALID, INVALID, "", 0, 0, 0)
+OPTION("<m x86 features group>", m_x86_Features_Group, Group, INVALID, INVALID, "", 0, 0, 0)
+OPTION("<u group>", u_Group, Group, INVALID, INVALID, "", 0, 0, 0)
+
+OPTION("<pedantic group>", pedantic_Group, Group, INVALID, INVALID, "", 0, 0, 0)
+
+// Temporary groups for clang options which we know we don't support,
+// but don't want to verbosely warn the user about.
+OPTION("<clang ignored f group>", clang_ignored_f_Group, Group, f_Group,
+ INVALID, "", 0, 0, 0)
+OPTION("<clang ignored m group>", clang_ignored_m_Group, Group, m_Group,
+ INVALID, "", 0, 0, 0)
+
+//////////
+// Options
+
+OPTION("-###", _HASH_HASH_HASH, Flag, INVALID, INVALID, "d", 0,
+ "Print the commands to run for this compilation", 0)
+OPTION("--CLASSPATH=", _CLASSPATH_EQ, Joined, INVALID, fclasspath_EQ, "", 0, 0, 0)
+OPTION("--CLASSPATH", _CLASSPATH, Separate, INVALID, fclasspath_EQ, "J", 0, 0, 0)
+OPTION("--all-warnings", _all_warnings, Flag, INVALID, Wall, "", 0, 0, 0)
+OPTION("--analyze-auto", _analyze_auto, Flag, INVALID, INVALID, "d", 0, 0, 0)
+OPTION("--analyzer-no-default-checks", _analyzer_no_default_checks, Flag, INVALID, INVALID, "d", 0, 0, 0)
+OPTION("--analyzer-output", _analyzer_output, JoinedOrSeparate, INVALID, INVALID, "d", 0, 0, 0)
+OPTION("--analyze", _analyze, Flag, INVALID, INVALID, "d", 0,
+ "Run the static analyzer", 0)
+OPTION("--ansi", _ansi, Flag, INVALID, ansi, "", 0, 0, 0)
+OPTION("--assemble", _assemble, Flag, INVALID, S, "", 0, 0, 0)
+OPTION("--assert=", _assert_EQ, Joined, INVALID, A, "S", 0, 0, 0)
+OPTION("--assert", _assert, Separate, INVALID, A, "", 0, 0, 0)
+OPTION("--bootclasspath=", _bootclasspath_EQ, Joined, INVALID, fbootclasspath_EQ, "", 0, 0, 0)
+OPTION("--bootclasspath", _bootclasspath, Separate, INVALID, fbootclasspath_EQ, "J", 0, 0, 0)
+OPTION("--classpath=", _classpath_EQ, Joined, INVALID, fclasspath_EQ, "", 0, 0, 0)
+OPTION("--classpath", _classpath, Separate, INVALID, fclasspath_EQ, "J", 0, 0, 0)
+OPTION("--combine", _combine, Flag, INVALID, combine, "u", 0, 0, 0)
+OPTION("--comments-in-macros", _comments_in_macros, Flag, INVALID, CC, "", 0, 0, 0)
+OPTION("--comments", _comments, Flag, INVALID, C, "", 0, 0, 0)
+OPTION("--compile", _compile, Flag, INVALID, c, "", 0, 0, 0)
+OPTION("--constant-cfstrings", _constant_cfstrings, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("--coverage", _coverage, Flag, INVALID, coverage, "", 0, 0, 0)
+OPTION("--debug=", _debug_EQ, Joined, INVALID, g_Flag, "u", 0, 0, 0)
+OPTION("--debug", _debug, Flag, INVALID, g_Flag, "u", 0, 0, 0)
+OPTION("--define-macro=", _define_macro_EQ, Joined, INVALID, D, "", 0, 0, 0)
+OPTION("--define-macro", _define_macro, Separate, INVALID, D, "J", 0, 0, 0)
+OPTION("--dependencies", _dependencies, Flag, INVALID, M, "", 0, 0, 0)
+OPTION("--encoding=", _encoding_EQ, Joined, INVALID, fencoding_EQ, "", 0, 0, 0)
+OPTION("--encoding", _encoding, Separate, INVALID, fencoding_EQ, "J", 0, 0, 0)
+OPTION("--entry", _entry, Flag, INVALID, e, "", 0, 0, 0)
+OPTION("--extdirs=", _extdirs_EQ, Joined, INVALID, fextdirs_EQ, "", 0, 0, 0)
+OPTION("--extdirs", _extdirs, Separate, INVALID, fextdirs_EQ, "J", 0, 0, 0)
+OPTION("--extra-warnings", _extra_warnings, Flag, INVALID, W_Joined, "", 0, 0, 0)
+OPTION("--for-linker=", _for_linker_EQ, Joined, INVALID, Xlinker, "liS", 0, 0, 0)
+OPTION("--for-linker", _for_linker, Separate, INVALID, Xlinker, "li", 0, 0, 0)
+OPTION("--force-link=", _force_link_EQ, Joined, INVALID, u, "S", 0, 0, 0)
+OPTION("--force-link", _force_link, Separate, INVALID, u, "", 0, 0, 0)
+OPTION("--help-hidden", _help_hidden, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("--help", _help, Flag, INVALID, INVALID, "", 0,
+ "Display available options", 0)
+OPTION("--imacros=", _imacros_EQ, Joined, INVALID, imacros, "S", 0, 0, 0)
+OPTION("--imacros", _imacros, Separate, INVALID, imacros, "", 0, 0, 0)
+OPTION("--include-barrier", _include_barrier, Flag, INVALID, I_, "", 0, 0, 0)
+OPTION("--include-directory-after=", _include_directory_after_EQ, Joined, INVALID, idirafter, "S", 0, 0, 0)
+OPTION("--include-directory-after", _include_directory_after, Separate, INVALID, idirafter, "", 0, 0, 0)
+OPTION("--include-directory=", _include_directory_EQ, Joined, INVALID, I, "", 0, 0, 0)
+OPTION("--include-directory", _include_directory, Separate, INVALID, I, "J", 0, 0, 0)
+OPTION("--include-prefix=", _include_prefix_EQ, Joined, INVALID, iprefix, "S", 0, 0, 0)
+OPTION("--include-prefix", _include_prefix, Separate, INVALID, iprefix, "", 0, 0, 0)
+OPTION("--include-with-prefix-after=", _include_with_prefix_after_EQ, Joined, INVALID, iwithprefix, "S", 0, 0, 0)
+OPTION("--include-with-prefix-after", _include_with_prefix_after, Separate, INVALID, iwithprefix, "", 0, 0, 0)
+OPTION("--include-with-prefix-before=", _include_with_prefix_before_EQ, Joined, INVALID, iwithprefixbefore, "S", 0, 0, 0)
+OPTION("--include-with-prefix-before", _include_with_prefix_before, Separate, INVALID, iwithprefixbefore, "", 0, 0, 0)
+OPTION("--include-with-prefix=", _include_with_prefix_EQ, Joined, INVALID, iwithprefix, "S", 0, 0, 0)
+OPTION("--include-with-prefix", _include_with_prefix, Separate, INVALID, iwithprefix, "", 0, 0, 0)
+OPTION("--include=", _include_EQ, Joined, INVALID, include, "S", 0, 0, 0)
+OPTION("--include", _include, Separate, INVALID, include, "", 0, 0, 0)
+OPTION("--language=", _language_EQ, Joined, INVALID, x, "S", 0, 0, 0)
+OPTION("--language", _language, Separate, INVALID, x, "", 0, 0, 0)
+OPTION("--library-directory=", _library_directory_EQ, Joined, INVALID, L, "S", 0, 0, 0)
+OPTION("--library-directory", _library_directory, Separate, INVALID, L, "", 0, 0, 0)
+OPTION("--machine-=", _machine__EQ, Joined, INVALID, m_Joined, "u", 0, 0, 0)
+OPTION("--machine-", _machine_, Joined, INVALID, m_Joined, "u", 0, 0, 0)
+OPTION("--machine=", _machine_EQ, Joined, INVALID, m_Joined, "", 0, 0, 0)
+OPTION("--machine", _machine, Separate, INVALID, m_Joined, "J", 0, 0, 0)
+OPTION("--no-integrated-cpp", _no_integrated_cpp, Flag, INVALID, no_integrated_cpp, "", 0, 0, 0)
+OPTION("--no-line-commands", _no_line_commands, Flag, INVALID, P, "", 0, 0, 0)
+OPTION("--no-standard-includes", _no_standard_includes, Flag, INVALID, nostdinc, "", 0, 0, 0)
+OPTION("--no-standard-libraries", _no_standard_libraries, Flag, INVALID, nostdlib, "", 0, 0, 0)
+OPTION("--no-warnings", _no_warnings, Flag, INVALID, w, "", 0, 0, 0)
+OPTION("--optimize=", _optimize_EQ, Joined, INVALID, O, "u", 0, 0, 0)
+OPTION("--optimize", _optimize, Flag, INVALID, O, "u", 0, 0, 0)
+OPTION("--output-class-directory=", _output_class_directory_EQ, Joined, INVALID, foutput_class_dir_EQ, "", 0, 0, 0)
+OPTION("--output-class-directory", _output_class_directory, Separate, INVALID, foutput_class_dir_EQ, "J", 0, 0, 0)
+OPTION("--output=", _output_EQ, Joined, INVALID, o, "S", 0, 0, 0)
+OPTION("--output", _output, Separate, INVALID, o, "", 0, 0, 0)
+OPTION("--param=", _param_EQ, Joined, INVALID, _param, "S", 0, 0, 0)
+OPTION("--param", _param, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("--pass-exit-codes", _pass_exit_codes, Flag, INVALID, pass_exit_codes, "", 0, 0, 0)
+OPTION("--pedantic-errors", _pedantic_errors, Flag, INVALID, pedantic_errors, "", 0, 0, 0)
+OPTION("--pedantic", _pedantic, Flag, INVALID, pedantic, "", 0, 0, 0)
+OPTION("--pipe", _pipe, Flag, INVALID, pipe, "d", 0, 0, 0)
+OPTION("--prefix=", _prefix_EQ, Joined, INVALID, B, "S", 0, 0, 0)
+OPTION("--prefix", _prefix, Separate, INVALID, B, "", 0, 0, 0)
+OPTION("--preprocess", _preprocess, Flag, INVALID, E, "", 0, 0, 0)
+OPTION("--print-file-name=", _print_file_name_EQ, Joined, INVALID, print_file_name_EQ, "", 0, 0, 0)
+OPTION("--print-file-name", _print_file_name, Separate, INVALID, print_file_name_EQ, "", 0, 0, 0)
+OPTION("--print-libgcc-file-name", _print_libgcc_file_name, Flag, INVALID, print_libgcc_file_name, "", 0, 0, 0)
+OPTION("--print-missing-file-dependencies", _print_missing_file_dependencies, Flag, INVALID, MG, "", 0, 0, 0)
+OPTION("--print-multi-directory", _print_multi_directory, Flag, INVALID, print_multi_directory, "", 0, 0, 0)
+OPTION("--print-multi-lib", _print_multi_lib, Flag, INVALID, print_multi_lib, "", 0, 0, 0)
+OPTION("--print-multi-os-directory", _print_multi_os_directory, Flag, INVALID, print_multi_os_directory, "", 0, 0, 0)
+OPTION("--print-prog-name=", _print_prog_name_EQ, Joined, INVALID, print_prog_name_EQ, "", 0, 0, 0)
+OPTION("--print-prog-name", _print_prog_name, Separate, INVALID, print_prog_name_EQ, "", 0, 0, 0)
+OPTION("--print-search-dirs", _print_search_dirs, Flag, INVALID, print_search_dirs, "", 0, 0, 0)
+OPTION("--profile-blocks", _profile_blocks, Flag, INVALID, a, "", 0, 0, 0)
+OPTION("--profile", _profile, Flag, INVALID, p, "", 0, 0, 0)
+OPTION("--resource=", _resource_EQ, Joined, INVALID, fcompile_resource_EQ, "", 0, 0, 0)
+OPTION("--resource", _resource, Separate, INVALID, fcompile_resource_EQ, "J", 0, 0, 0)
+OPTION("--save-temps", _save_temps, Flag, INVALID, save_temps, "", 0, 0, 0)
+OPTION("--shared", _shared, Flag, INVALID, shared, "", 0, 0, 0)
+OPTION("--specs=", _specs_EQ, Joined, INVALID, specs_EQ, "u", 0, 0, 0)
+OPTION("--specs", _specs, Separate, INVALID, specs_EQ, "uJ", 0, 0, 0)
+OPTION("--static", _static, Flag, INVALID, static, "", 0, 0, 0)
+OPTION("--std=", _std_EQ, Joined, INVALID, std_EQ, "", 0, 0, 0)
+OPTION("--std", _std, Separate, INVALID, std_EQ, "J", 0, 0, 0)
+OPTION("--sysroot=", _sysroot_EQ, Joined, INVALID, INVALID, "", 0, 0, 0)
+OPTION("--sysroot", _sysroot, Separate, INVALID, _sysroot_EQ, "J", 0, 0, 0)
+OPTION("--target-help", _target_help, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("--trace-includes", _trace_includes, Flag, INVALID, H, "", 0, 0, 0)
+OPTION("--traditional-cpp", _traditional_cpp, Flag, INVALID, traditional_cpp, "", 0, 0, 0)
+OPTION("--traditional", _traditional, Flag, INVALID, traditional, "", 0, 0, 0)
+OPTION("--trigraphs", _trigraphs, Flag, INVALID, trigraphs, "", 0, 0, 0)
+OPTION("--undefine-macro=", _undefine_macro_EQ, Joined, INVALID, U, "", 0, 0, 0)
+OPTION("--undefine-macro", _undefine_macro, Separate, INVALID, U, "J", 0, 0, 0)
+OPTION("--user-dependencies", _user_dependencies, Flag, INVALID, MM, "", 0, 0, 0)
+OPTION("--verbose", _verbose, Flag, INVALID, v, "", 0, 0, 0)
+OPTION("--version", _version, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("--warn-=", _warn__EQ, Joined, INVALID, W_Joined, "u", 0, 0, 0)
+OPTION("--warn-", _warn_, Joined, INVALID, W_Joined, "u", 0, 0, 0)
+OPTION("--write-dependencies", _write_dependencies, Flag, INVALID, MD, "", 0, 0, 0)
+OPTION("--write-user-dependencies", _write_user_dependencies, Flag, INVALID, MMD, "", 0, 0, 0)
+OPTION("--", _, Joined, INVALID, f, "u", 0, 0, 0)
+OPTION("-A", A, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-B", B, JoinedOrSeparate, INVALID, INVALID, "u", 0, 0, 0)
+OPTION("-CC", CC, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-C", C, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-D", D, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-E", E, Flag, INVALID, INVALID, "d", 0,
+ "Only run the preprocessor", 0)
+OPTION("-F", F, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-H", H, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-I-", I_, Flag, I_Group, INVALID, "", 0, 0, 0)
+OPTION("-I", I, JoinedOrSeparate, I_Group, INVALID, "", 0, 0, 0)
+OPTION("-L", L, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-MD", MD, Flag, M_Group, INVALID, "", 0, 0, 0)
+OPTION("-MF", MF, JoinedOrSeparate, M_Group, INVALID, "", 0, 0, 0)
+OPTION("-MG", MG, Flag, M_Group, INVALID, "", 0, 0, 0)
+OPTION("-MMD", MMD, Flag, M_Group, INVALID, "", 0, 0, 0)
+OPTION("-MM", MM, Flag, M_Group, INVALID, "", 0, 0, 0)
+OPTION("-MP", MP, Flag, M_Group, INVALID, "", 0, 0, 0)
+OPTION("-MQ", MQ, JoinedOrSeparate, M_Group, INVALID, "", 0, 0, 0)
+OPTION("-MT", MT, JoinedOrSeparate, M_Group, INVALID, "", 0, 0, 0)
+OPTION("-Mach", Mach, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-M", M, Flag, M_Group, INVALID, "", 0, 0, 0)
+OPTION("-O4", O4, Joined, O_Group, INVALID, "", 0, 0, 0)
+OPTION("-ObjC++", ObjCXX, Flag, INVALID, INVALID, "d", 0,
+ "Treat source input files as Objective-C++ inputs", 0)
+OPTION("-ObjC", ObjC, Flag, INVALID, INVALID, "d", 0,
+ "Treat source input files as Objective-C inputs", 0)
+OPTION("-O", O, Joined, O_Group, INVALID, "", 0, 0, 0)
+OPTION("-P", P, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-Qn", Qn, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-Qunused-arguments", Qunused_arguments, Flag, INVALID, INVALID, "d", 0,
+ "Don't emit warning for unused driver arguments", 0)
+OPTION("-Q", Q, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-R", R, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-S", S, Flag, INVALID, INVALID, "d", 0,
+ "Only run preprocess and compilation steps", 0)
+OPTION("-Tbss", Tbss, JoinedOrSeparate, T_Group, INVALID, "", 0, 0, 0)
+OPTION("-Tdata", Tdata, JoinedOrSeparate, T_Group, INVALID, "", 0, 0, 0)
+OPTION("-Ttext", Ttext, JoinedOrSeparate, T_Group, INVALID, "", 0, 0, 0)
+OPTION("-T", T, JoinedOrSeparate, T_Group, INVALID, "", 0, 0, 0)
+OPTION("-U", U, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-V", V, JoinedOrSeparate, INVALID, INVALID, "du", 0, 0, 0)
+OPTION("-Wa,", Wa_COMMA, CommaJoined, INVALID, INVALID, "", 0,
+ "Pass the comma separated arguments in <arg> to the assembler", "<arg>")
+OPTION("-Wall", Wall, Flag, W_Group, INVALID, "", 0, 0, 0)
+OPTION("-Wextra", Wextra, Flag, W_Group, INVALID, "", 0, 0, 0)
+OPTION("-Wl,", Wl_COMMA, CommaJoined, INVALID, INVALID, "li", 0,
+ "Pass the comma separated arguments in <arg> to the linker", "<arg>")
+OPTION("-Wno-nonportable-cfstrings", Wno_nonportable_cfstrings, Joined, W_Group, INVALID, "", 0, 0, 0)
+OPTION("-Wnonportable-cfstrings", Wnonportable_cfstrings, Joined, W_Group, INVALID, "", 0, 0, 0)
+OPTION("-Wp,", Wp_COMMA, CommaJoined, INVALID, INVALID, "", 0,
+ "Pass the comma separated arguments in <arg> to the preprocessor", "<arg>")
+OPTION("-W", W_Joined, Joined, W_Group, INVALID, "", 0, 0, 0)
+OPTION("-Xanalyzer", Xanalyzer, Separate, INVALID, INVALID, "", 0,
+ "Pass <arg> to the static analyzer", "<arg>")
+OPTION("-Xarch_", Xarch__, JoinedAndSeparate, INVALID, INVALID, "d", 0, 0, 0)
+OPTION("-Xassembler", Xassembler, Separate, INVALID, INVALID, "", 0,
+ "Pass <arg> to the assembler", "<arg>")
+OPTION("-Xclang", Xclang, Separate, INVALID, INVALID, "", 0,
+ "Pass <arg> to the clang compiler", "<arg>")
+OPTION("-Xlinker", Xlinker, Separate, INVALID, INVALID, "li", 0,
+ "Pass <arg> to the linker", "<arg>")
+OPTION("-Xpreprocessor", Xpreprocessor, Separate, INVALID, INVALID, "", 0,
+ "Pass <arg> to the preprocessor", "<arg>")
+OPTION("-X", X_Flag, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-X", X_Joined, Joined, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-Z", Z_Flag, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-Z", Z_Joined, Joined, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-all_load", all__load, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-allowable_client", allowable__client, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-ansi", ansi, Flag, a_Group, INVALID, "", 0, 0, 0)
+OPTION("-arch", arch, Separate, INVALID, INVALID, "d", 0, 0, 0)
+OPTION("-a", a, Joined, a_Group, INVALID, "", 0, 0, 0)
+OPTION("-bind_at_load", bind__at__load, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-bundle_loader", bundle__loader, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-bundle", bundle, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-b", b, JoinedOrSeparate, INVALID, INVALID, "u", 0, 0, 0)
+OPTION("-client_name", client__name, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-combine", combine, Flag, INVALID, INVALID, "du", 0, 0, 0)
+OPTION("-compatibility_version", compatibility__version, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-coverage", coverage, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-cpp-precomp", cpp_precomp, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-current_version", current__version, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-c", c, Flag, INVALID, INVALID, "d", 0,
+ "Only run preprocess, compile, and assemble steps", 0)
+OPTION("-dA", dA, Flag, d_Group, INVALID, "", 0, 0, 0)
+OPTION("-dD", dD, Flag, d_Group, INVALID, "", 0, 0, 0)
+OPTION("-dM", dM, Flag, d_Group, INVALID, "", 0, 0, 0)
+OPTION("-dead_strip", dead__strip, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-dependency-file", dependency_file, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-dumpmachine", dumpmachine, Flag, INVALID, INVALID, "u", 0, 0, 0)
+OPTION("-dumpspecs", dumpspecs, Flag, INVALID, INVALID, "u", 0, 0, 0)
+OPTION("-dumpversion", dumpversion, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-dylib_file", dylib__file, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-dylinker_install_name", dylinker__install__name, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-dylinker", dylinker, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-dynamiclib", dynamiclib, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-dynamic", dynamic, Flag, INVALID, INVALID, "q", 0, 0, 0)
+OPTION("-d", d_Flag, Flag, d_Group, INVALID, "", 0, 0, 0)
+OPTION("-d", d_Joined, Joined, d_Group, INVALID, "", 0, 0, 0)
+OPTION("-emit-llvm", emit_llvm, Flag, INVALID, INVALID, "", 0,
+ "Use the LLVM representation for assembler and object files", 0)
+OPTION("-exported_symbols_list", exported__symbols__list, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-e", e, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-fPIC", fPIC, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fPIE", fPIE, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fapple-kext", fapple_kext, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fasm-blocks", fasm_blocks, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fastcp", fastcp, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fastf", fastf, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fast", fast, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fasynchronous-unwind-tables", fasynchronous_unwind_tables, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fblocks", fblocks, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fbootclasspath=", fbootclasspath_EQ, Joined, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fbuiltin", fbuiltin, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fclasspath=", fclasspath_EQ, Joined, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fcommon", fcommon, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fcompile-resource=", fcompile_resource_EQ, Joined, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fconstant-cfstrings", fconstant_cfstrings, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fcreate-profile", fcreate_profile, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fdebug-pass-arguments", fdebug_pass_arguments, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fdebug-pass-structure", fdebug_pass_structure, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fdiagnostics-fixit-info", fdiagnostics_fixit_info, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fdiagnostics-print-source-range-info", fdiagnostics_print_source_range_info, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fdiagnostics-show-option", fdiagnostics_show_option, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fdollars-in-identifiers", fdollars_in_identifiers, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-feliminate-unused-debug-symbols", feliminate_unused_debug_symbols, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-femit-all-decls", femit_all_decls, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fencoding=", fencoding_EQ, Joined, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fexceptions", fexceptions, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fextdirs=", fextdirs_EQ, Joined, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-ffreestanding", ffreestanding, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fgnu-runtime", fgnu_runtime, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fheinous-gnu-extensions", fheinous_gnu_extensions, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-filelist", filelist, Separate, INVALID, INVALID, "l", 0, 0, 0)
+OPTION("-findirect-virtual-calls", findirect_virtual_calls, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-finline-functions", finline_functions, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0)
+OPTION("-finline", finline, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fkeep-inline-functions", fkeep_inline_functions, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0)
+OPTION("-flat_namespace", flat__namespace, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-flax-vector-conversions", flax_vector_conversions, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-flimited-precision=", flimited_precision_EQ, Joined, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-flto", flto, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fmath-errno", fmath_errno, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fmessage-length=", fmessage_length_EQ, Joined, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fms-extensions", fms_extensions, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fmudflapth", fmudflapth, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fmudflap", fmudflap, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fnested-functions", fnested_functions, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fnext-runtime", fnext_runtime, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-asynchronous-unwind-tables", fno_asynchronous_unwind_tables, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-blocks", fno_blocks, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-builtin", fno_builtin, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-caret-diagnostics", fno_caret_diagnostics, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-common", fno_common, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-constant-cfstrings", fno_constant_cfstrings, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-diagnostics-fixit-info", fno_diagnostics_fixit_info, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-diagnostics-show-option", fno_diagnostics_show_option, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-dollars-in-identifiers", fno_dollars_in_identifiers, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-eliminate-unused-debug-symbols", fno_eliminate_unused_debug_symbols, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-inline-functions", fno_inline_functions, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-inline", fno_inline, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-keep-inline-functions", fno_keep_inline_functions, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-math-errno", fno_math_errno, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-pascal-strings", fno_pascal_strings, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-show-column", fno_show_column, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-stack-protector", fno_stack_protector, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-strict-aliasing", fno_strict_aliasing, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-unit-at-a-time", fno_unit_at_a_time, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-unwind-tables", fno_unwind_tables, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-working-directory", fno_working_directory, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fno-zero-initialized-in-bss", fno_zero_initialized_in_bss, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fobjc-atdefs", fobjc_atdefs, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fobjc-call-cxx-cdtors", fobjc_call_cxx_cdtors, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fobjc-gc-only", fobjc_gc_only, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fobjc-gc", fobjc_gc, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fobjc-new-property", fobjc_new_property, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fobjc-nonfragile-abi", fobjc_nonfragile_abi, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fobjc-sender-dependent-dispatch", fobjc_sender_dependent_dispatch, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fobjc-tight-layout", fobjc_tight_layout, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fobjc", fobjc, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fomit-frame-pointer", fomit_frame_pointer, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fopenmp", fopenmp, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-force_cpusubtype_ALL", force__cpusubtype__ALL, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-force_flat_namespace", force__flat__namespace, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-foutput-class-dir=", foutput_class_dir_EQ, Joined, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fpascal-strings", fpascal_strings, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fpch-preprocess", fpch_preprocess, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fpic", fpic, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fpie", fpie, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fprofile-arcs", fprofile_arcs, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fprofile-generate", fprofile_generate, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-framework", framework, Separate, INVALID, INVALID, "l", 0, 0, 0)
+OPTION("-fsigned-bitfields", fsigned_bitfields, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fstack-protector", fstack_protector, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fstrict-aliasing", fstrict_aliasing, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fsyntax-only", fsyntax_only, Flag, INVALID, INVALID, "d", 0, 0, 0)
+OPTION("-ftemplate-depth-", ftemplate_depth_, Joined, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fterminated-vtables", fterminated_vtables, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-ftime-report", ftime_report, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-ftraditional", ftraditional, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-ftrapv", ftrapv, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-funit-at-a-time", funit_at_a_time, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-funsigned-bitfields", funsigned_bitfields, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-funwind-tables", funwind_tables, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fverbose-asm", fverbose_asm, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fvisibility=", fvisibility_EQ, Joined, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fwritable-strings", fwritable_strings, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fzero-initialized-in-bss", fzero_initialized_in_bss, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-f", f, Joined, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-g0", g0, Joined, g_Group, INVALID, "", 0, 0, 0)
+OPTION("-g3", g3, Joined, g_Group, INVALID, "", 0, 0, 0)
+OPTION("-gfull", gfull, Joined, g_Group, INVALID, "", 0, 0, 0)
+OPTION("-gstabs", gstabs, Joined, g_Group, INVALID, "", 0, 0, 0)
+OPTION("-gused", gused, Joined, g_Group, INVALID, "", 0, 0, 0)
+OPTION("-g", g_Flag, Flag, g_Group, INVALID, "", 0, 0, 0)
+OPTION("-g", g_Joined, Joined, g_Group, INVALID, "", 0, 0, 0)
+OPTION("-headerpad_max_install_names", headerpad__max__install__names, Joined, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-idirafter", idirafter, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0)
+OPTION("-iframework", iframework, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0)
+OPTION("-imacros", imacros, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0)
+OPTION("-image_base", image__base, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-include", include, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0)
+OPTION("-init", init, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-install_name", install__name, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-iprefix", iprefix, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0)
+OPTION("-iquote", iquote, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0)
+OPTION("-isysroot", isysroot, JoinedOrSeparate, i_Group, INVALID, "", 0, 0, 0)
+OPTION("-isystem", isystem, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0)
+OPTION("-iwithprefixbefore", iwithprefixbefore, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0)
+OPTION("-iwithprefix", iwithprefix, JoinedOrSeparate, clang_i_Group, INVALID, "", 0, 0, 0)
+OPTION("-iwithsysroot", iwithsysroot, JoinedOrSeparate, i_Group, INVALID, "", 0, 0, 0)
+OPTION("-i", i, Joined, i_Group, INVALID, "", 0, 0, 0)
+OPTION("-keep_private_externs", keep__private__externs, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-l", l, JoinedOrSeparate, INVALID, INVALID, "l", 0, 0, 0)
+OPTION("-m32", m32, Flag, m_Group, INVALID, "d", 0, 0, 0)
+OPTION("-m3dnowa", m3dnowa, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-m3dnow", m3dnow, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-m64", m64, Flag, m_Group, INVALID, "d", 0, 0, 0)
+OPTION("-march=", march_EQ, Joined, m_Group, INVALID, "d", 0, 0, 0)
+OPTION("-mconstant-cfstrings", mconstant_cfstrings, Flag, clang_ignored_m_Group, INVALID, "", 0, 0, 0)
+OPTION("-mdynamic-no-pic", mdynamic_no_pic, Joined, m_Group, INVALID, "q", 0, 0, 0)
+OPTION("-mfix-and-continue", mfix_and_continue, Flag, clang_ignored_m_Group, INVALID, "", 0, 0, 0)
+OPTION("-miphoneos-version-min=", miphoneos_version_min_EQ, Joined, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-mkernel", mkernel, Flag, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-mmacosx-version-min=", mmacosx_version_min_EQ, Joined, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-mmmx", mmmx, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-mno-3dnowa", mno_3dnowa, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-mno-3dnow", mno_3dnow, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-mno-constant-cfstrings", mno_constant_cfstrings, Flag, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-mno-mmx", mno_mmx, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-mno-pascal-strings", mno_pascal_strings, Flag, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-mno-red-zone", mno_red_zone, Flag, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-mno-soft-float", mno_soft_float, Flag, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-mno-sse2", mno_sse2, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-mno-sse3", mno_sse3, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-mno-sse4a", mno_sse4a, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-mno-sse4", mno_sse4, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-mno-sse", mno_sse, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-mno-ssse3", mno_ssse3, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-mno-warn-nonportable-cfstrings", mno_warn_nonportable_cfstrings, Flag, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-mpascal-strings", mpascal_strings, Flag, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-mred-zone", mred_zone, Flag, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-msoft-float", msoft_float, Flag, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-msse2", msse2, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-msse3", msse3, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-msse4a", msse4a, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-msse4", msse4, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-msse", msse, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-mssse3", mssse3, Flag, m_x86_Features_Group, INVALID, "", 0, 0, 0)
+OPTION("-mtune=", mtune_EQ, Joined, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-multi_module", multi__module, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-multiply_defined_unused", multiply__defined__unused, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-multiply_defined", multiply__defined, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-mwarn-nonportable-cfstrings", mwarn_nonportable_cfstrings, Flag, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-m", m_Separate, Separate, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-m", m_Joined, Joined, m_Group, INVALID, "", 0, 0, 0)
+OPTION("-no-cpp-precomp", no_cpp_precomp, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-no-integrated-cpp", no_integrated_cpp, Flag, INVALID, INVALID, "d", 0, 0, 0)
+OPTION("-no_dead_strip_inits_and_terms", no__dead__strip__inits__and__terms, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-nodefaultlibs", nodefaultlibs, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-nofixprebinding", nofixprebinding, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-nolibc", nolibc, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-nomultidefs", nomultidefs, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-noprebind", noprebind, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-noseglinkedit", noseglinkedit, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-nostartfiles", nostartfiles, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-nostdinc", nostdinc, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-nostdlib", nostdlib, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-object", object, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-o", o, JoinedOrSeparate, INVALID, INVALID, "di", 0,
+ "Write output to <file>", "<file>")
+OPTION("-pagezero_size", pagezero__size, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-pass-exit-codes", pass_exit_codes, Flag, INVALID, INVALID, "u", 0, 0, 0)
+OPTION("-pedantic-errors", pedantic_errors, Flag, pedantic_Group, INVALID, "", 0, 0, 0)
+OPTION("-pedantic", pedantic, Flag, pedantic_Group, INVALID, "", 0, 0, 0)
+OPTION("-pg", pg, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-pipe", pipe, Flag, INVALID, INVALID, "", 0,
+ "Use pipes between commands, when possible", 0)
+OPTION("-prebind_all_twolevel_modules", prebind__all__twolevel__modules, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-prebind", prebind, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-preload", preload, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-print-file-name=", print_file_name_EQ, Joined, INVALID, INVALID, "", 0,
+ "Print the full library path of <file>", "<file>")
+OPTION("-print-ivar-layout", print_ivar_layout, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-print-libgcc-file-name", print_libgcc_file_name, Flag, INVALID, INVALID, "", 0,
+ "Print the library path for \"libgcc.a\"", 0)
+OPTION("-print-multi-directory", print_multi_directory, Flag, INVALID, INVALID, "u", 0, 0, 0)
+OPTION("-print-multi-lib", print_multi_lib, Flag, INVALID, INVALID, "u", 0, 0, 0)
+OPTION("-print-multi-os-directory", print_multi_os_directory, Flag, INVALID, INVALID, "u", 0, 0, 0)
+OPTION("-print-prog-name=", print_prog_name_EQ, Joined, INVALID, INVALID, "", 0,
+ "Print the full program path of <name>", "<name>")
+OPTION("-print-search-dirs", print_search_dirs, Flag, INVALID, INVALID, "", 0,
+ "Print the paths used for finding libraries and programs", 0)
+OPTION("-private_bundle", private__bundle, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-pthreads", pthreads, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-pthread", pthread, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-p", p, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-read_only_relocs", read__only__relocs, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-remap", remap, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-r", r, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-save-temps", save_temps, Flag, INVALID, INVALID, "d", 0,
+ "Save intermediate compilation results", 0)
+OPTION("-sectalign", sectalign, MultiArg, INVALID, INVALID, "", 3, 0, 0)
+OPTION("-sectcreate", sectcreate, MultiArg, INVALID, INVALID, "", 3, 0, 0)
+OPTION("-sectobjectsymbols", sectobjectsymbols, MultiArg, INVALID, INVALID, "", 2, 0, 0)
+OPTION("-sectorder", sectorder, MultiArg, INVALID, INVALID, "", 3, 0, 0)
+OPTION("-seg1addr", seg1addr, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-seg_addr_table_filename", seg__addr__table__filename, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-seg_addr_table", seg__addr__table, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-segaddr", segaddr, MultiArg, INVALID, INVALID, "", 2, 0, 0)
+OPTION("-segcreate", segcreate, MultiArg, INVALID, INVALID, "", 3, 0, 0)
+OPTION("-seglinkedit", seglinkedit, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-segprot", segprot, MultiArg, INVALID, INVALID, "", 3, 0, 0)
+OPTION("-segs_read_only_addr", segs__read__only__addr, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-segs_read_write_addr", segs__read__write__addr, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-segs_read_", segs__read__, Joined, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-shared-libgcc", shared_libgcc, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-shared", shared, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-single_module", single__module, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-specs=", specs_EQ, Joined, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-specs", specs, Separate, INVALID, INVALID, "u", 0, 0, 0)
+OPTION("-static-libgcc", static_libgcc, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-static", static, Flag, INVALID, INVALID, "q", 0, 0, 0)
+OPTION("-std-default=", std_default_EQ, Joined, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-std=", std_EQ, Joined, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-sub_library", sub__library, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-sub_umbrella", sub__umbrella, JoinedOrSeparate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-s", s, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-time", time, Flag, INVALID, INVALID, "", 0,
+ "Time individual commands", 0)
+OPTION("-traditional-cpp", traditional_cpp, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-traditional", traditional, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-trigraphs", trigraphs, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-twolevel_namespace_hints", twolevel__namespace__hints, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-twolevel_namespace", twolevel__namespace, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-t", t, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-umbrella", umbrella, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-undefined", undefined, JoinedOrSeparate, u_Group, INVALID, "", 0, 0, 0)
+OPTION("-undef", undef, Flag, u_Group, INVALID, "", 0, 0, 0)
+OPTION("-unexported_symbols_list", unexported__symbols__list, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-u", u, JoinedOrSeparate, u_Group, INVALID, "", 0, 0, 0)
+OPTION("-v", v, Flag, INVALID, INVALID, "", 0,
+ "Show commands to run and use verbose output", 0)
+OPTION("-weak-l", weak_l, Joined, INVALID, INVALID, "l", 0, 0, 0)
+OPTION("-weak_framework", weak__framework, Separate, INVALID, INVALID, "l", 0, 0, 0)
+OPTION("-weak_library", weak__library, Separate, INVALID, INVALID, "l", 0, 0, 0)
+OPTION("-weak_reference_mismatches", weak__reference__mismatches, Separate, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-whatsloaded", whatsloaded, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-whyload", whyload, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-w", w, Flag, INVALID, INVALID, "", 0, 0, 0)
+OPTION("-x", x, JoinedOrSeparate, INVALID, INVALID, "d", 0,
+ "Treat subsequent input files as having type <language>", "<language>")
+OPTION("-y", y, Joined, INVALID, INVALID, "", 0, 0, 0)
diff --git a/include/clang/Driver/Options.h b/include/clang/Driver/Options.h
new file mode 100644
index 000000000000..8b959d369c0e
--- /dev/null
+++ b/include/clang/Driver/Options.h
@@ -0,0 +1,90 @@
+//===--- Options.h - Option info & table ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_DRIVER_OPTIONS_H_
+#define CLANG_DRIVER_OPTIONS_H_
+
+namespace clang {
+namespace driver {
+namespace options {
+ enum ID {
+ OPT_INVALID = 0, // This is not an option ID.
+ OPT_INPUT, // Reserved ID for input option.
+ OPT_UNKNOWN, // Reserved ID for unknown option.
+#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) OPT_##ID,
+#include "clang/Driver/Options.def"
+ LastOption
+#undef OPTION
+ };
+}
+
+ class Arg;
+ class InputArgList;
+ class Option;
+
+ /// OptTable - Provide access to the Option info table.
+ ///
+ /// The OptTable class provides a layer of indirection which allows
+ /// Option instance to be created lazily. In the common case, only a
+ /// few options will be needed at runtime; the OptTable class
+ /// maintains enough information to parse command lines without
+ /// instantiating Options, while letting other parts of the driver
+ /// still use Option instances where convient.
+ class OptTable {
+ /// The table of options which have been constructed, indexed by
+ /// option::ID - 1.
+ mutable Option **Options;
+
+ /// The index of the first option which can be parsed (i.e., is
+ /// not a special option like 'input' or 'unknown', and is not an
+ /// option group).
+ unsigned FirstSearchableOption;
+
+ Option *constructOption(options::ID id) const;
+
+ public:
+ OptTable();
+ ~OptTable();
+
+ unsigned getNumOptions() const;
+
+ const char *getOptionName(options::ID id) const;
+
+ /// getOption - Get the given \arg id's Option instance, lazily
+ /// creating it if necessary.
+ const Option *getOption(options::ID id) const;
+
+ /// getOptionKind - Get the kind of the given option.
+ unsigned getOptionKind(options::ID id) const;
+
+ /// getOptionHelpText - Get the help text to use to describe this
+ /// option.
+ const char *getOptionHelpText(options::ID id) const;
+
+ /// getOptionMetaVar - Get the meta-variable name to use when
+ /// describing this options values in the help text.
+ const char *getOptionMetaVar(options::ID id) const;
+
+ /// parseOneArg - Parse a single argument; returning the new
+ /// argument and updating Index.
+ ///
+ /// \param [in] [out] Index - The current parsing position in the
+ /// argument string list; on return this will be the index of the
+ /// next argument string to parse.
+ ///
+ /// \return - The parsed argument, or 0 if the argument is missing
+ /// values (in which case Index still points at the conceptual
+ /// next argument string to parse).
+ Arg *ParseOneArg(const InputArgList &Args, unsigned &Index) const;
+ };
+}
+}
+
+#endif
diff --git a/include/clang/Driver/Phases.h b/include/clang/Driver/Phases.h
new file mode 100644
index 000000000000..a0c42ea17362
--- /dev/null
+++ b/include/clang/Driver/Phases.h
@@ -0,0 +1,32 @@
+//===--- Phases.h - Transformations on Driver Types -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_DRIVER_PHASES_H_
+#define CLANG_DRIVER_PHASES_H_
+
+namespace clang {
+namespace driver {
+namespace phases {
+ /// ID - Ordered values for successive stages in the
+ /// compilation process which interact with user options.
+ enum ID {
+ Preprocess,
+ Precompile,
+ Compile,
+ Assemble,
+ Link
+ };
+
+ const char *getPhaseName(ID Id);
+
+} // end namespace phases
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h
new file mode 100644
index 000000000000..d8b37e9ead88
--- /dev/null
+++ b/include/clang/Driver/Tool.h
@@ -0,0 +1,69 @@
+//===--- Tool.h - Compilation Tools -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_DRIVER_TOOL_H_
+#define CLANG_DRIVER_TOOL_H_
+
+namespace llvm {
+ template<typename T, unsigned N> class SmallVector;
+}
+
+namespace clang {
+namespace driver {
+ class ArgList;
+ class Compilation;
+ class InputInfo;
+ class Job;
+ class JobAction;
+ class ToolChain;
+
+ typedef llvm::SmallVector<InputInfo, 4> InputInfoList;
+
+/// Tool - Information on a specific compilation tool.
+class Tool {
+ /// The tool name (for debugging).
+ const char *Name;
+
+ /// The tool chain this tool is a part of.
+ const ToolChain &TheToolChain;
+
+public:
+ Tool(const char *Name, const ToolChain &TC);
+
+public:
+ virtual ~Tool();
+
+ const char *getName() const { return Name; }
+
+ const ToolChain &getToolChain() const { return TheToolChain; }
+
+ virtual bool acceptsPipedInput() const = 0;
+ virtual bool canPipeOutput() const = 0;
+ virtual bool hasIntegratedCPP() const = 0;
+
+ /// ConstructJob - Construct jobs to perform the action \arg JA,
+ /// writing to \arg Output and with \arg Inputs.
+ ///
+ /// \param Dest - Where to put the resulting commands.
+ /// \param TCArgs - The argument list for this toolchain, with any
+ /// tool chain specific translations applied.
+ /// \param LinkingOutput - If this output will eventually feed the
+ /// linker, then this is the final output name of the linked image.
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const = 0;
+};
+
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
new file mode 100644
index 000000000000..6196c130266d
--- /dev/null
+++ b/include/clang/Driver/ToolChain.h
@@ -0,0 +1,105 @@
+//===--- ToolChain.h - Collections of tools for one platform ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_DRIVER_TOOLCHAIN_H_
+#define CLANG_DRIVER_TOOLCHAIN_H_
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/System/Path.h"
+#include <string>
+
+namespace clang {
+namespace driver {
+ class Compilation;
+ class DerivedArgList;
+ class HostInfo;
+ class InputArgList;
+ class JobAction;
+ class Tool;
+
+/// ToolChain - Access to tools for a single platform.
+class ToolChain {
+public:
+ typedef llvm::SmallVector<std::string, 4> path_list;
+
+private:
+ const HostInfo &Host;
+ const llvm::Triple Triple;
+
+ /// The list of toolchain specific path prefixes to search for
+ /// files.
+ path_list FilePaths;
+
+ /// The list of toolchain specific path prefixes to search for
+ /// programs.
+ path_list ProgramPaths;
+
+protected:
+ ToolChain(const HostInfo &Host, const llvm::Triple &_Triple);
+
+public:
+ virtual ~ToolChain();
+
+ // Accessors
+
+ const HostInfo &getHost() const { return Host; }
+ std::string getArchName() const { return Triple.getArchName(); }
+ std::string getPlatform() const { return Triple.getVendorName(); }
+ std::string getOS() const { return Triple.getOSName(); }
+
+ std::string getTripleString() const {
+ return Triple.getTriple();
+ }
+
+ path_list &getFilePaths() { return FilePaths; }
+ const path_list &getFilePaths() const { return FilePaths; }
+
+ path_list &getProgramPaths() { return ProgramPaths; }
+ const path_list &getProgramPaths() const { return ProgramPaths; }
+
+ // Tool access.
+
+ /// TranslateArgs - Create a new derived argument list for any
+ /// argument translations this ToolChain may wish to perform.
+ virtual DerivedArgList *TranslateArgs(InputArgList &Args) const = 0;
+
+ /// SelectTool - Choose a tool to use to handle the action \arg JA.
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const = 0;
+
+ // Helper methods
+
+ llvm::sys::Path GetFilePath(const Compilation &C, const char *Name) const;
+ llvm::sys::Path GetProgramPath(const Compilation &C, const char *Name,
+ bool WantFile = false) const;
+
+ // Platform defaults information
+
+ /// IsMathErrnoDefault - Does this tool chain set -fmath-errno by
+ /// default.
+ virtual bool IsMathErrnoDefault() const = 0;
+
+ /// IsUnwindTablesDefault - Does this tool chain use -funwind-tables
+ /// by default.
+ virtual bool IsUnwindTablesDefault() const = 0;
+
+ /// GetDefaultRelocationModel - Return the LLVM name of the default
+ /// relocation model for this tool chain.
+ virtual const char *GetDefaultRelocationModel() const = 0;
+
+ /// GetForcedPicModel - Return the LLVM name of the forced PIC model
+ /// for this tool chain, or 0 if this tool chain does not force a
+ /// particular PIC mode.
+ virtual const char *GetForcedPicModel() const = 0;
+};
+
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def
new file mode 100644
index 000000000000..8d24e5013fb0
--- /dev/null
+++ b/include/clang/Driver/Types.def
@@ -0,0 +1,78 @@
+//===--- Types.def - Driver Type info ---------------------------*- 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 driver type information. Users of this file
+// must define the TYPE macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TYPE
+#error "Define TYPE prior to including this file!"
+#endif
+
+// TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, FLAGS)
+
+// The first value is the type name as a string; for types which can
+// be user specified this should be the equivalent -x option.
+
+// The second value is the type id, which will result in a
+// clang::driver::types::TY_XX enum constant.
+
+// The third value is that id of the type for preprocessed inputs of
+// this type, or INVALID if this type is not preprocessed.
+
+// The fourth value is the suffix to use when creating temporary files
+// of this type, or null if unspecified.
+
+// The fifth value is a string containt option flags. Valid values:
+// a - The type should only be assembled.
+// p - The type should only be precompiled.
+// u - The type can be user specified (with -x).
+// A - The type's temporary suffix should be appended when generating
+// outputs of this type.
+
+
+// C family source language (with and without preprocessing).
+TYPE("cpp-output", PP_C, INVALID, "i", "u")
+TYPE("c", C, PP_C, 0, "u")
+TYPE("objective-c-cpp-output", PP_ObjC, 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("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("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")
+TYPE("c++-header", CXXHeader, PP_CXXHeader, 0, "pu")
+TYPE("objective-c++-header-cpp-output", PP_ObjCXXHeader, INVALID, "mii", "p")
+TYPE("objective-c++-header", ObjCXXHeader, PP_ObjCXXHeader, 0, "pu")
+
+// Other languages.
+TYPE("ada", Ada, INVALID, 0, "u")
+TYPE("assembler", PP_Asm, INVALID, "s", "au")
+TYPE("assembler-with-cpp", Asm, PP_Asm, 0, "au")
+TYPE("f95", PP_Fortran, INVALID, 0, "u")
+TYPE("f95-cpp-input", Fortran, PP_Fortran, 0, "u")
+TYPE("java", Java, INVALID, 0, "u")
+
+// Misc.
+TYPE("llvm-asm", LLVMAsm, INVALID, "s", "")
+TYPE("llvm-bc", LLVMBC, INVALID, "o", "")
+TYPE("plist", Plist, INVALID, "plist", "")
+TYPE("precompiled-header", PCH, INVALID, "gch", "A")
+TYPE("object", Object, INVALID, "o", "")
+TYPE("treelang", Treelang, INVALID, 0, "u")
+TYPE("image", Image, INVALID, "out", "")
+TYPE("dependencies", Dependencies, INVALID, "d", "")
+TYPE("none", Nothing, INVALID, 0, "u")
diff --git a/include/clang/Driver/Types.h b/include/clang/Driver/Types.h
new file mode 100644
index 000000000000..92520a77b33b
--- /dev/null
+++ b/include/clang/Driver/Types.h
@@ -0,0 +1,85 @@
+//===--- Types.h - Input & Temporary Driver Types ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_DRIVER_TYPES_H_
+#define CLANG_DRIVER_TYPES_H_
+
+#include "clang/Driver/Phases.h"
+
+namespace clang {
+namespace driver {
+namespace types {
+ enum ID {
+ TY_INVALID,
+#define TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, FLAGS) TY_##ID,
+#include "clang/Driver/Types.def"
+#undef TYPE
+ TY_LAST
+ };
+
+ /// getTypeName - Return the name of the type for \arg Id.
+ const char *getTypeName(ID Id);
+
+ /// getPreprocessedType - Get the ID of the type for this input when
+ /// it has been preprocessed, or INVALID if this input is not
+ /// preprocessed.
+ ID getPreprocessedType(ID Id);
+
+ /// getTypeTempSuffix - Return the suffix to use when creating a
+ /// temp file of this type, or null if unspecified.
+ const char *getTypeTempSuffix(ID Id);
+
+ /// onlyAssembleType - Should this type only be assembled.
+ bool onlyAssembleType(ID Id);
+
+ /// onlyPrecompileType - Should this type only be precompiled.
+ bool onlyPrecompileType(ID Id);
+
+ /// canTypeBeUserSpecified - Can this type be specified on the
+ /// command line (by the type name); this is used when forwarding
+ /// commands to gcc.
+ bool canTypeBeUserSpecified(ID Id);
+
+ /// appendSuffixForType - When generating outputs of this type,
+ /// should the suffix be appended (instead of replacing the existing
+ /// suffix).
+ bool appendSuffixForType(ID Id);
+
+ /// canLipoType - Is this type acceptable as the output of a
+ /// universal build (currently, just the Nothing, Image, and Object
+ /// types).
+ bool canLipoType(ID Id);
+
+ /// isAcceptedByClang - Can clang handle this input type.
+ bool isAcceptedByClang(ID Id);
+
+ /// isCXX - Is this a "C++" input (C++ and Obj-C++ sources and headers).
+ bool isCXX(ID Id);
+
+ /// lookupTypeForExtension - Lookup the type to use for the file
+ /// extension \arg Ext.
+ ID lookupTypeForExtension(const char *Ext);
+
+ /// lookupTypeForTypSpecifier - Lookup the type to use for a user
+ /// specified type name.
+ ID lookupTypeForTypeSpecifier(const char *Name);
+
+ /// getNumCompilationPhases - Return the complete number of phases
+ /// to be done for this type.
+ unsigned getNumCompilationPhases(ID Id);
+
+ /// getCompilationPhase - Return the \args N th compilation phase to
+ /// be done for this type.
+ phases::ID getCompilationPhase(ID Id, unsigned N);
+
+} // end namespace types
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Driver/Util.h b/include/clang/Driver/Util.h
new file mode 100644
index 000000000000..52f268d182a8
--- /dev/null
+++ b/include/clang/Driver/Util.h
@@ -0,0 +1,30 @@
+//===--- Util.h - Common Driver Utilities -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_DRIVER_UTIL_H_
+#define CLANG_DRIVER_UTIL_H_
+
+namespace llvm {
+ template<typename T, unsigned N> class SmallVector;
+}
+
+namespace clang {
+namespace driver {
+ class Action;
+
+ /// ArgStringList - Type used for constructing argv lists for subprocesses.
+ typedef llvm::SmallVector<const char*, 16> ArgStringList;
+
+ /// ActionList - Type used for lists of actions.
+ typedef llvm::SmallVector<Action*, 3> ActionList;
+
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h
new file mode 100644
index 000000000000..04365d7c78d8
--- /dev/null
+++ b/include/clang/Frontend/ASTConsumers.h
@@ -0,0 +1,107 @@
+//===--- ASTConsumers.h - ASTConsumer implementations -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// AST Consumers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef DRIVER_ASTCONSUMERS_H
+#define DRIVER_ASTCONSUMERS_H
+
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+#include <iosfwd>
+
+namespace llvm {
+ class Module;
+ namespace sys { class Path; }
+}
+namespace clang {
+
+class ASTConsumer;
+class Diagnostic;
+class FileManager;
+class Preprocessor;
+class PreprocessorFactory;
+struct CompileOptions;
+class LangOptions;
+
+// AST pretty-printer: prints out the AST in a format that is close to the
+// 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);
+
+// AST XML-printer: prints out the AST in a XML format
+// The output is intended to be in a format such that
+// clang or any other tool could re-parse the output back into the same AST,
+// but the implementation is still incomplete.
+ASTConsumer *CreateASTPrinterXML(llvm::raw_ostream* OS);
+
+// AST dumper: dumps the raw AST in human-readable form to stderr; this is
+// intended for debugging.
+ASTConsumer *CreateASTDumper();
+
+// Graphical AST viewer: for each function definition, creates a graph of
+// the AST and displays it with the graph viewer "dotty". Also outputs
+// function declarations to stderr.
+ASTConsumer *CreateASTViewer();
+
+// DeclContext printer: prints out the DeclContext tree in human-readable form
+// to stderr; this is intended for debugging.
+ASTConsumer *CreateDeclContextPrinter();
+
+// ObjC rewriter: attempts tp 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,
+ const LangOptions &LOpts,
+ bool SilenceRewriteMacroWarning);
+
+// LLVM code generator: uses the code generation backend to generate LLVM
+// assembly. This runs optimizations depending on the CompileOptions
+// parameter. The output depends on the Action parameter.
+enum BackendAction {
+ Backend_EmitAssembly, // Emit native assembly
+ Backend_EmitBC, // Emit LLVM bitcode file
+ Backend_EmitLL, // Emit human-readable LLVM assembly
+ Backend_EmitNothing // Don't emit anything (benchmarking mode)
+};
+ASTConsumer *CreateBackendConsumer(BackendAction Action,
+ Diagnostic &Diags,
+ const LangOptions &Features,
+ const CompileOptions &CompileOpts,
+ const std::string &ModuleID,
+ llvm::raw_ostream *OS);
+
+// HTML printer: uses the rewriter to convert source code to HTML with
+// syntax highlighting suitable for viewing in a web-browser.
+ASTConsumer* CreateHTMLPrinter(llvm::raw_ostream *OS, Diagnostic &D,
+ Preprocessor *PP, PreprocessorFactory *PPF);
+
+// PCH generator: generates a precompiled header file; this file can be
+// used later with the PCHReader (clang-cc option -include-pch)
+// to speed up compile times.
+ASTConsumer *CreatePCHGenerator(const Preprocessor &PP,
+ llvm::raw_ostream *OS);
+
+// Block rewriter: rewrites code using the Apple blocks extension to pure
+// C code. Output is always sent to stdout.
+ASTConsumer *CreateBlockRewriter(const std::string &InFile,
+ Diagnostic &Diags,
+ const LangOptions &LangOpts);
+
+// Inheritance viewer: for C++ code, creates a graph of the inheritance
+// tree for the given class and displays it with "dotty".
+ASTConsumer *CreateInheritanceViewer(const std::string& clsname);
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Frontend/Analyses.def b/include/clang/Frontend/Analyses.def
new file mode 100644
index 000000000000..3492d09c10aa
--- /dev/null
+++ b/include/clang/Frontend/Analyses.def
@@ -0,0 +1,77 @@
+//===-- Analyses.def - Metadata about Static Analyses -----------*- 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 set of static analyses used by AnalysisConsumer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ANALYSIS
+#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)
+#endif
+
+ANALYSIS(CFGDump, "cfg-dump",
+ "Display Control-Flow Graphs", Code)
+
+ANALYSIS(CFGView, "cfg-view",
+ "View Control-Flow Graphs using GraphViz", Code)
+
+ANALYSIS(DisplayLiveVariables, "dump-live-variables",
+ "Print results of live variable analysis", Code)
+
+ANALYSIS(WarnDeadStores, "warn-dead-stores",
+ "Warn about stores to dead variables", Code)
+
+ANALYSIS(WarnUninitVals, "warn-uninit-values",
+ "Warn about uses of uninitialized variables", Code)
+
+ANALYSIS(WarnObjCMethSigs, "warn-objc-methodsigs",
+ "Warn about Objective-C method signatures with type incompatibilities",
+ ObjCImplementation)
+
+ANALYSIS(WarnObjCDealloc, "warn-objc-missing-dealloc",
+ "Warn about Objective-C classes that lack a correct implementation of -dealloc",
+ ObjCImplementation)
+
+ANALYSIS(WarnObjCUnusedIvars, "warn-objc-unused-ivars",
+ "Warn about private ivars that are never used", ObjCImplementation)
+
+ANALYSIS(CheckerSimple, "checker-simple",
+ "Perform simple path-sensitive checks.", Code)
+
+ANALYSIS(CheckerCFRef, "checker-cfref",
+ "Run the [Core] Foundation reference count checker", Code)
+
+
+#ifndef ANALYSIS_STORE
+#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)
+
+#ifndef ANALYSIS_CONSTRAINTS
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN)
+#endif
+
+ANALYSIS_CONSTRAINTS(BasicConstraints, "basic", "Use basic constraint tracking", CreateBasicConstraintManager)
+ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of concrete value ranges", CreateRangeConstraintManager)
+
+#ifndef ANALYSIS_DIAGNOSTICS
+#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)
+
+#undef ANALYSIS
+#undef ANALYSIS_STORE
+#undef ANALYSIS_CONSTRAINTS
+#undef ANALYSIS_DIAGNOSTICS
+#undef ANALYSIS_STORE
+
diff --git a/include/clang/Frontend/AnalysisConsumer.h b/include/clang/Frontend/AnalysisConsumer.h
new file mode 100644
index 000000000000..0e4b09bd2a12
--- /dev/null
+++ b/include/clang/Frontend/AnalysisConsumer.h
@@ -0,0 +1,78 @@
+//===--- AnalysisConsumer.h - Front-end hooks for the analysis engine------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header contains the functions necessary for a front-end to run various
+// analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#include <string>
+#include <vector>
+
+namespace clang {
+class ASTConsumer;
+class Diagnostic;
+class Preprocessor;
+class PreprocessorFactory;
+class LangOptions;
+
+/// Analysis - Set of available source code analyses.
+enum Analyses {
+#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) NAME,
+#include "clang/Frontend/Analyses.def"
+NumAnalyses
+};
+
+/// AnalysisStores - Set of available analysis store models.
+enum AnalysisStores {
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) NAME##Model,
+#include "clang/Frontend/Analyses.def"
+NumStores
+};
+
+/// AnalysisConstraints - Set of available constraint models.
+enum AnalysisConstraints {
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) NAME##Model,
+#include "clang/Frontend/Analyses.def"
+NumConstraints
+};
+
+/// AnalysisDiagClients - Set of available diagnostic clients for rendering
+/// analysis results.
+enum AnalysisDiagClients {
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) PD_##NAME,
+#include "clang/Frontend/Analyses.def"
+NUM_ANALYSIS_DIAG_CLIENTS
+};
+
+struct AnalyzerOptions {
+ std::vector<Analyses> AnalysisList;
+ AnalysisStores AnalysisStoreOpt;
+ AnalysisConstraints AnalysisConstraintsOpt;
+ AnalysisDiagClients AnalysisDiagOpt;
+ bool VisualizeEGDot;
+ bool VisualizeEGUbi;
+ bool AnalyzeAll;
+ bool AnalyzerDisplayProgress;
+ bool PurgeDead;
+ bool EagerlyAssume;
+ std::string AnalyzeSpecificFunction;
+ bool TrimGraph;
+};
+
+/// CreateAnalysisConsumer - Creates an ASTConsumer to run various code
+/// analysis passes. (The set of analyses run is controlled by command-line
+/// options.)
+ASTConsumer* CreateAnalysisConsumer(Diagnostic &diags, Preprocessor *pp,
+ PreprocessorFactory *ppf,
+ const LangOptions &lopts,
+ const std::string &output,
+ const AnalyzerOptions& Opts);
+
+}
diff --git a/include/clang/Frontend/CompileOptions.h b/include/clang/Frontend/CompileOptions.h
new file mode 100644
index 000000000000..1af5e48ea119
--- /dev/null
+++ b/include/clang/Frontend/CompileOptions.h
@@ -0,0 +1,62 @@
+//===--- CompileOptions.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the CompileOptions interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_COMPILEOPTIONS_H
+#define LLVM_CLANG_FRONTEND_COMPILEOPTIONS_H
+
+#include <string>
+#include <vector>
+
+namespace clang {
+
+/// CompileOptions - Track various options which control how the code
+/// is optimized and passed to the backend.
+class CompileOptions {
+public:
+ unsigned OptimizationLevel : 3; /// The -O[0-4] option specified.
+ unsigned OptimizeSize : 1; /// If -Os is specified.
+ unsigned DebugInfo : 1; /// Should generate deubg info (-g).
+ unsigned UnitAtATime : 1; /// Unused. For mirroring GCC
+ /// optimization selection.
+ unsigned InlineFunctions : 1; /// Should functions be inlined?
+ unsigned SimplifyLibCalls : 1; /// Should standard library calls be
+ /// treated specially.
+ unsigned UnrollLoops : 1; /// Control whether loops are unrolled.
+ unsigned VerifyModule : 1; /// Control whether the module
+ /// should be run through the LLVM Verifier.
+ unsigned TimePasses : 1; /// Set when -ftime-report is enabled.
+ unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled.
+
+ /// CPU - An optional CPU to target.
+ std::string CPU;
+
+ /// Features - A list of subtarget features to pass to the code
+ /// generator.
+ std::vector<std::string> Features;
+
+public:
+ CompileOptions() {
+ OptimizationLevel = 0;
+ OptimizeSize = 0;
+ DebugInfo = 0;
+ UnitAtATime = 1;
+ InlineFunctions = SimplifyLibCalls = UnrollLoops = 0;
+ VerifyModule = 1;
+ TimePasses = 0;
+ NoCommon = 0;
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Frontend/DocumentXML.h b/include/clang/Frontend/DocumentXML.h
new file mode 100644
index 000000000000..99db717190dd
--- /dev/null
+++ b/include/clang/Frontend/DocumentXML.h
@@ -0,0 +1,128 @@
+//===--- DocumentXML.h - XML document for ASTs ------------------*- 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 XML document class, which provides the means to
+// dump out the AST in a XML form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_DOCUMENTXML_H
+#define LLVM_CLANG_FRONTEND_DOCUMENTXML_H
+
+#include <string>
+#include <map>
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeOrdering.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+
+//--------------------------------------------------------- forwards
+class DeclContext;
+class Decl;
+class NamedDecl;
+class FunctionDecl;
+class ASTContext;
+
+//---------------------------------------------------------
+namespace XML
+{
+ // id maps:
+ template<class T>
+ struct IdMap : llvm::DenseMap<T, unsigned> {};
+
+ template<>
+ struct IdMap<QualType> : std::map<QualType, unsigned, QualTypeOrdering> {};
+
+ template<>
+ struct IdMap<std::string> : std::map<std::string, unsigned> {};
+}
+
+//---------------------------------------------------------
+class DocumentXML
+{
+public:
+ DocumentXML(const std::string& rootName, llvm::raw_ostream& out);
+ ~DocumentXML();
+
+ void initialize(ASTContext &Context);
+ void PrintDecl(Decl *D);
+ void PrintStmt(const Stmt *S); // defined in StmtXML.cpp
+
+ void finalize();
+
+
+ DocumentXML& addSubNode(const std::string& name); // also enters the sub node, returns *this
+ DocumentXML& toParent(); // returns *this
+
+ template<class T>
+ void addAttribute(const char* pName, const T& value);
+
+ void addTypeAttribute(const QualType& pType);
+ void addRefAttribute(const NamedDecl* D);
+
+ enum tContextUsage { CONTEXT_AS_CONTEXT, CONTEXT_AS_ID };
+ void addContextAttribute(const DeclContext *DC, tContextUsage usage = CONTEXT_AS_CONTEXT);
+ void addSourceFileAttribute(const std::string& fileName);
+
+ PresumedLoc addLocation(const SourceLocation& Loc);
+ void addLocationRange(const SourceRange& R);
+
+ static std::string escapeString(const char* pStr, std::string::size_type len);
+
+private:
+ DocumentXML(const DocumentXML&); // not defined
+ DocumentXML& operator=(const DocumentXML&); // not defined
+
+ struct NodeXML;
+
+ NodeXML* Root;
+ NodeXML* CurrentNode; // always after Root
+ llvm::raw_ostream& Out;
+ ASTContext *Ctx;
+ int CurrentIndent;
+ bool HasCurrentNodeSubNodes;
+
+
+ XML::IdMap<QualType> Types;
+ XML::IdMap<const DeclContext*> Contexts;
+ XML::IdMap<const Type*> BasicTypes;
+ XML::IdMap<std::string> SourceFiles;
+ XML::IdMap<const NamedDecl*> Decls;
+
+ void addContextsRecursively(const DeclContext *DC);
+ void addBasicTypeRecursively(const Type* pType);
+ void addTypeRecursively(const QualType& pType);
+
+ void PrintFunctionDecl(FunctionDecl *FD);
+ void addDeclIdAttribute(const NamedDecl* D);
+ void addTypeIdAttribute(const Type* pType);
+ void Indent();
+};
+
+//--------------------------------------------------------- inlines
+
+inline void DocumentXML::initialize(ASTContext &Context)
+{
+ Ctx = &Context;
+}
+
+//---------------------------------------------------------
+template<class T>
+inline void DocumentXML::addAttribute(const char* pName, const T& value)
+{
+ Out << ' ' << pName << "=\"" << value << "\"";
+}
+
+//---------------------------------------------------------
+
+} //namespace clang
+
+#endif //LLVM_CLANG_DOCUMENTXML_H
diff --git a/include/clang/Frontend/FixItRewriter.h b/include/clang/Frontend/FixItRewriter.h
new file mode 100644
index 000000000000..7fcd682bf66c
--- /dev/null
+++ b/include/clang/Frontend/FixItRewriter.h
@@ -0,0 +1,95 @@
+//===--- FixItRewriter.h - Fix-It Rewriter Diagnostic Client ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a diagnostic client adaptor that performs rewrites as
+// suggested by code modification hints attached to diagnostics. It
+// then forwards any diagnostics to the adapted diagnostic client.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_FRONTEND_FIX_IT_REWRITER_H
+#define LLVM_CLANG_FRONTEND_FIX_IT_REWRITER_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+
+class SourceManager;
+class FileEntry;
+
+/// \brief Stores a source location in the form that it shows up on
+/// the Clang command line, e.g., file:line:column.
+///
+/// FIXME: Would prefer to use real SourceLocations, but I don't see a
+/// good way to resolve them during parsing.
+struct RequestedSourceLocation {
+ const FileEntry *File;
+ unsigned Line;
+ unsigned Column;
+};
+
+class FixItRewriter : public DiagnosticClient {
+ /// \brief The diagnostics machinery.
+ Diagnostic &Diags;
+
+ /// \brief The rewriter used to perform the various code
+ /// modifications.
+ Rewriter Rewrite;
+
+ /// \brief The diagnostic client that performs the actual formatting
+ /// of error messages.
+ DiagnosticClient *Client;
+
+ /// \brief The number of rewriter failures.
+ unsigned NumFailures;
+
+ /// \brief Locations at which we should perform fix-its.
+ ///
+ /// When empty, perform fix-it modifications everywhere.
+ llvm::SmallVector<RequestedSourceLocation, 4> FixItLocations;
+
+public:
+ /// \brief Initialize a new fix-it rewriter.
+ FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr,
+ const LangOptions &LangOpts);
+
+ /// \brief Destroy the fix-it rewriter.
+ ~FixItRewriter();
+
+ /// \brief Add a location where fix-it modifications should be
+ /// performed.
+ void addFixItLocation(RequestedSourceLocation Loc) {
+ FixItLocations.push_back(Loc);
+ }
+
+ /// \brief Write the modified source file.
+ ///
+ /// \returns true if there was an error, false otherwise.
+ bool WriteFixedFile(const std::string &InFileName,
+ const std::string &OutFileName = std::string());
+
+ /// 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.
+ 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);
+
+ /// \brief Emit a diagnostic via the adapted diagnostic client.
+ void Diag(FullSourceLoc Loc, unsigned DiagID);
+};
+
+}
+
+#endif // LLVM_CLANG_FRONTEND_FIX_IT_REWRITER_H
diff --git a/include/clang/Frontend/FrontendDiagnostic.h b/include/clang/Frontend/FrontendDiagnostic.h
new file mode 100644
index 000000000000..02432ca3a55c
--- /dev/null
+++ b/include/clang/Frontend/FrontendDiagnostic.h
@@ -0,0 +1,27 @@
+//===--- DiagnosticFrontend.h - Diagnostics for frontend --------*- 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_FRONTENDDIAGNOSTIC_H
+#define LLVM_CLANG_FRONTENDDIAGNOSTIC_H
+
+#include "clang/Basic/Diagnostic.h"
+
+namespace clang {
+ namespace diag {
+ enum {
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM,
+#define FRONTENDSTART
+#include "clang/Basic/DiagnosticFrontendKinds.inc"
+#undef DIAG
+ NUM_BUILTIN_FRONTEND_DIAGNOSTICS
+ };
+ } // end namespace diag
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Frontend/InitHeaderSearch.h b/include/clang/Frontend/InitHeaderSearch.h
new file mode 100644
index 000000000000..51516661c99e
--- /dev/null
+++ b/include/clang/Frontend/InitHeaderSearch.h
@@ -0,0 +1,74 @@
+//===--- InitHeaderSearch.h - Initialize header search paths ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the InitHeaderSearch class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_INIT_HEADER_SEARCH_H_
+#define LLVM_CLANG_FRONTEND_INIT_HEADER_SEARCH_H_
+
+#include <string>
+#include <vector>
+
+#include "clang/Lex/DirectoryLookup.h"
+
+namespace clang {
+
+class HeaderSearch;
+class LangOptions;
+
+/// InitHeaderSearch - This class makes it easier to set the search paths of
+/// a HeaderSearch object. InitHeaderSearch stores several search path lists
+/// internally, which can be sent to a HeaderSearch object in one swoop.
+class InitHeaderSearch {
+ std::vector<DirectoryLookup> IncludeGroup[4];
+ HeaderSearch& Headers;
+ bool Verbose;
+ std::string isysroot;
+
+public:
+ /// InitHeaderSearch::IncludeDirGroup - Identifies the several search path
+ /// lists stored internally.
+ enum IncludeDirGroup {
+ Quoted = 0, //< `#include ""` paths. Thing `gcc -iquote`.
+ Angled, //< Paths for both `#include ""` and `#include <>`. (`-I`)
+ System, //< Like Angled, but marks system directories.
+ After //< Like System, but searched after the system directories.
+ };
+
+ InitHeaderSearch(HeaderSearch &HS,
+ bool verbose = false, const std::string &iSysroot = "")
+ : Headers(HS), Verbose(verbose), isysroot(iSysroot) {}
+
+ /// AddPath - Add the specified path to the specified group list.
+ void AddPath(const std::string &Path, IncludeDirGroup Group,
+ bool isCXXAware, bool isUserSupplied,
+ bool isFramework, bool IgnoreSysRoot = false);
+
+ /// AddEnvVarPaths - Add a list of paths from an environment variable to a
+ /// header search list.
+ void AddEnvVarPaths(const char *Name);
+
+ /// AddDefaultEnvVarPaths - Adds list of paths from default environment
+ /// variables such as CPATH.
+ void AddDefaultEnvVarPaths(const LangOptions &Lang);
+
+ /// AddDefaultSystemIncludePaths - Adds the default system include paths so
+ /// that e.g. stdio.h is found.
+ void AddDefaultSystemIncludePaths(const LangOptions &Lang);
+
+ /// Realize - Merges all search path lists into one list and send it to
+ /// HeaderSearch.
+ void Realize();
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Frontend/InitPreprocessor.h b/include/clang/Frontend/InitPreprocessor.h
new file mode 100644
index 000000000000..eb03602dc57b
--- /dev/null
+++ b/include/clang/Frontend/InitPreprocessor.h
@@ -0,0 +1,70 @@
+//===--- InitPreprocessor.h - InitializePreprocessor function. --*- 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 clang::InitializePreprocessor function.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_INIT_PREPROCESSOR_H_
+#define LLVM_CLANG_FRONTEND_INIT_PREPROCESSOR_H_
+
+#include <string>
+#include <vector>
+
+namespace clang {
+
+class Preprocessor;
+class LangOptions;
+
+/// PreprocessorInitOptions - This class is used for passing the various
+/// options used in preprocessor initialization to InitializePreprocessor().
+class PreprocessorInitOptions {
+ std::vector<std::pair<std::string, bool/*isUndef*/> > Macros;
+ std::vector<std::pair<std::string, bool/*isPTH*/> > Includes;
+ std::vector<std::string> MacroIncludes;
+
+public:
+
+ void addMacroDef(const std::string &Name) {
+ Macros.push_back(std::make_pair(Name, false));
+ }
+ void addMacroUndef(const std::string &Name) {
+ Macros.push_back(std::make_pair(Name, true));
+ }
+ void addInclude(const std::string &Name, bool isPTH = false) {
+ Includes.push_back(std::make_pair(Name, isPTH));
+ }
+ void addMacroInclude(const std::string &Name) {
+ MacroIncludes.push_back(Name);
+ }
+
+ typedef std::vector<std::pair<std::string,
+ bool> >::const_iterator macro_iterator;
+ macro_iterator macro_begin() const { return Macros.begin(); }
+ macro_iterator macro_end() const { return Macros.end(); }
+
+ typedef std::vector<std::pair<std::string,
+ bool> >::const_iterator include_iterator;
+ include_iterator include_begin() const { return Includes.begin(); }
+ include_iterator include_end() const { return Includes.end(); }
+
+ typedef std::vector<std::string>::const_iterator imacro_iterator;
+ imacro_iterator imacro_begin() const { return MacroIncludes.begin(); }
+ imacro_iterator imacro_end() const { return MacroIncludes.end(); }
+};
+
+/// InitializePreprocessor - Initialize the preprocessor getting it and the
+/// environment ready to process a single file. This returns true on error.
+///
+bool InitializePreprocessor(Preprocessor &PP,
+ const PreprocessorInitOptions& InitOptions);
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Frontend/ManagerRegistry.h b/include/clang/Frontend/ManagerRegistry.h
new file mode 100644
index 000000000000..ecab67a3b676
--- /dev/null
+++ b/include/clang/Frontend/ManagerRegistry.h
@@ -0,0 +1,53 @@
+//===-- ManagerRegistry.h - Pluggable analyzer module registry --*- 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 ManagerRegistry and Register* classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_MANAGER_REGISTRY_H
+#define LLVM_CLANG_FRONTEND_MANAGER_REGISTRY_H
+
+#include "clang/Analysis/PathSensitive/GRState.h"
+
+namespace clang {
+
+/// ManagerRegistry - This class records manager creators registered at
+/// runtime. The information is communicated to AnalysisManager through static
+/// members. Better design is expected.
+
+class ManagerRegistry {
+public:
+ static StoreManagerCreator StoreMgrCreator;
+ static ConstraintManagerCreator ConstraintMgrCreator;
+};
+
+/// RegisterConstraintManager - This class is used to setup the constraint
+/// manager of the static analyzer. The constructor takes a creator function
+/// pointer for creating the constraint manager.
+///
+/// It is used like this:
+///
+/// class MyConstraintManager {};
+/// ConstraintManager* CreateMyConstraintManager(GRStateManager& statemgr) {
+/// return new MyConstraintManager(statemgr);
+/// }
+/// RegisterConstraintManager X(CreateMyConstraintManager);
+
+class RegisterConstraintManager {
+public:
+ RegisterConstraintManager(ConstraintManagerCreator CMC) {
+ assert(ManagerRegistry::ConstraintMgrCreator == 0
+ && "ConstraintMgrCreator already set!");
+ ManagerRegistry::ConstraintMgrCreator = CMC;
+ }
+};
+
+}
+#endif
diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h
new file mode 100644
index 000000000000..0862cd6390f4
--- /dev/null
+++ b/include/clang/Frontend/PCHBitCodes.h
@@ -0,0 +1,660 @@
+//===- PCHBitCodes.h - Enum values for the PCH bitcode format ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines Bitcode enum values for Clang precompiled header files.
+//
+// The enum values defined in this file should be considered permanent. If
+// new features are added, they should have values added at the end of the
+// respective lists.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_FRONTEND_PCHBITCODES_H
+#define LLVM_CLANG_FRONTEND_PCHBITCODES_H
+
+#include "llvm/Bitcode/BitCodes.h"
+#include "llvm/Support/DataTypes.h"
+
+namespace clang {
+ namespace pch {
+ /// \brief PCH major version number supported by this version of
+ /// Clang.
+ ///
+ /// Whenever the PCH format changes in a way that makes it
+ /// incompatible with previous versions (such that a reader
+ /// designed for the previous version could not support reading
+ /// the new version), this number should be increased.
+ const unsigned VERSION_MAJOR = 1;
+
+ /// \brief PCH minor version number supported by this version of
+ /// Clang.
+ ///
+ /// Whenever the PCH format changes in a way that is still
+ /// compatible with previous versions (such that a reader designed
+ /// for the previous version could still support reading the new
+ /// version by ignoring new kinds of subblocks), this number
+ /// should be increased.
+ const unsigned VERSION_MINOR = 0;
+
+ /// \brief An ID number that refers to a declaration in a PCH file.
+ ///
+ /// The ID numbers of types are consecutive (in order of
+ /// discovery) and start at 2. 0 is reserved for NULL, and 1 is
+ /// reserved for the translation unit declaration.
+ typedef uint32_t DeclID;
+
+ /// \brief An ID number that refers to a type in a PCH file.
+ ///
+ /// The ID of a type is partitioned into two parts: the lower
+ /// three bits are used to store the const/volatile/restrict
+ /// qualifiers (as with QualType) and the upper bits provide a
+ /// type index. The type index values are partitioned into two
+ /// sets. The values below NUM_PREDEF_TYPE_IDs are predefined type
+ /// IDs (based on the PREDEF_TYPE_*_ID constants), with 0 as a
+ /// placeholder for "no type". Values from NUM_PREDEF_TYPE_IDs are
+ /// other types that have serialized representations.
+ typedef uint32_t TypeID;
+
+ /// \brief An ID number that refers to an identifier in a PCH
+ /// file.
+ typedef uint32_t IdentID;
+
+ typedef uint32_t SelectorID;
+
+ /// \brief Describes the various kinds of blocks that occur within
+ /// a PCH file.
+ enum BlockIDs {
+ /// \brief The PCH block, which acts as a container around the
+ /// full PCH block.
+ PCH_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID,
+
+ /// \brief The block containing information about the source
+ /// manager.
+ SOURCE_MANAGER_BLOCK_ID,
+
+ /// \brief The block containing information about the
+ /// preprocessor.
+ PREPROCESSOR_BLOCK_ID,
+
+ /// \brief The block containing the definitions of all of the
+ /// types used within the PCH file.
+ TYPES_BLOCK_ID,
+
+ /// \brief The block containing the definitions of all of the
+ /// declarations stored in the PCH file.
+ DECLS_BLOCK_ID
+ };
+
+ /// \brief Record types that occur within the PCH block itself.
+ enum PCHRecordTypes {
+ /// \brief Offset of each type within the types block.
+ ///
+ /// The TYPE_OFFSET constant describes the record that occurs
+ /// within the block identified by TYPE_OFFSETS_BLOCK_ID within
+ /// the PCH file. The record itself is an array of offsets that
+ /// point into the types block (identified by TYPES_BLOCK_ID in
+ /// the PCH file). The index into the array is based on the ID
+ /// of a type. For a given type ID @c T, the lower three bits of
+ /// @c T are its qualifiers (const, volatile, restrict), as in
+ /// the QualType class. The upper bits, after being shifted and
+ /// subtracting NUM_PREDEF_TYPE_IDS, are used to index into the
+ /// TYPE_OFFSET block to determine the offset of that type's
+ /// corresponding record within the TYPES_BLOCK_ID block.
+ TYPE_OFFSET = 1,
+
+ /// \brief Record code for the offsets of each decl.
+ ///
+ /// The DECL_OFFSET constant describes the record that occurs
+ /// within the block identifier by DECL_OFFSETS_BLOCK_ID within
+ /// the PCH file. The record itself is an array of offsets that
+ /// point into the declarations block (identified by
+ /// DECLS_BLOCK_ID). The declaration ID is an index into this
+ /// record, after subtracting one to account for the use of
+ /// declaration ID 0 for a NULL declaration pointer. Index 0 is
+ /// reserved for the translation unit declaration.
+ DECL_OFFSET = 2,
+
+ /// \brief Record code for the language options table.
+ ///
+ /// The record with this code contains the contents of the
+ /// LangOptions structure. We serialize the entire contents of
+ /// the structure, and let the reader decide which options are
+ /// actually important to check.
+ LANGUAGE_OPTIONS = 3,
+
+ /// \brief PCH metadata, including the PCH file version number
+ /// and the target triple used to build the PCH file.
+ METADATA = 4,
+
+ /// \brief Record code for the table of offsets of each
+ /// identifier ID.
+ ///
+ /// The offset table contains offsets into the blob stored in
+ /// the IDENTIFIER_TABLE record. Each offset points to the
+ /// NULL-terminated string that corresponds to that identifier.
+ IDENTIFIER_OFFSET = 5,
+
+ /// \brief Record code for the identifier table.
+ ///
+ /// The identifier table is a simple blob that contains
+ /// NULL-terminated strings for all of the identifiers
+ /// referenced by the PCH file. The IDENTIFIER_OFFSET table
+ /// contains the mapping from identifier IDs to the characters
+ /// in this blob. Note that the starting offsets of all of the
+ /// identifiers are odd, so that, when the identifier offset
+ /// table is loaded in, we can use the low bit to distinguish
+ /// between offsets (for unresolved identifier IDs) and
+ /// IdentifierInfo pointers (for already-resolved identifier
+ /// IDs).
+ IDENTIFIER_TABLE = 6,
+
+ /// \brief Record code for the array of external definitions.
+ ///
+ /// The PCH file contains a list of all of the unnamed external
+ /// definitions present within the parsed headers, stored as an
+ /// array of declaration IDs. These external definitions will be
+ /// reported to the AST consumer after the PCH file has been
+ /// read, since their presence can affect the semantics of the
+ /// program (e.g., for code generation).
+ EXTERNAL_DEFINITIONS = 7,
+
+ /// \brief Record code for the set of non-builtin, special
+ /// types.
+ ///
+ /// This record contains the type IDs for the various type nodes
+ /// that are constructed during semantic analysis (e.g.,
+ /// __builtin_va_list). The SPECIAL_TYPE_* constants provide
+ /// offsets into this record.
+ SPECIAL_TYPES = 8,
+
+ /// \brief Record code for the extra statistics we gather while
+ /// generating a PCH file.
+ STATISTICS = 9,
+
+ /// \brief Record code for the array of tentative definitions.
+ TENTATIVE_DEFINITIONS = 10,
+
+ /// \brief Record code for the array of locally-scoped external
+ /// declarations.
+ LOCALLY_SCOPED_EXTERNAL_DECLS = 11,
+
+ /// \brief Record code for the table of offsets into the
+ /// Objective-C method pool.
+ SELECTOR_OFFSETS = 12,
+
+ /// \brief Record code for the Objective-C method pool,
+ METHOD_POOL = 13,
+
+ /// \brief The value of the next __COUNTER__ to dispense.
+ /// [PP_COUNTER_VALUE, Val]
+ PP_COUNTER_VALUE = 14,
+
+ /// \brief Record code for the table of offsets into the block
+ /// of source-location information.
+ SOURCE_LOCATION_OFFSETS = 15,
+
+ /// \brief Record code for the set of source location entries
+ /// that need to be preloaded by the PCH reader.
+ ///
+ /// This set contains the source location entry for the
+ /// predefines buffer and for any file entries that need to be
+ /// preloaded.
+ SOURCE_LOCATION_PRELOADS = 16,
+
+ /// \brief Record code for the stat() cache.
+ STAT_CACHE = 17,
+
+ /// \brief Record code for the set of ext_vector type names.
+ EXT_VECTOR_DECLS = 18,
+
+ /// \brief Record code for the set of Objective-C category
+ /// implementations.
+ OBJC_CATEGORY_IMPLEMENTATIONS = 19,
+
+ /// \brief Record code for the original file that was used to
+ /// generate the precompiled header.
+ ORIGINAL_FILE_NAME = 20
+ };
+
+ /// \brief Record types used within a source manager block.
+ enum SourceManagerRecordTypes {
+ /// \brief Describes a source location entry (SLocEntry) for a
+ /// file.
+ SM_SLOC_FILE_ENTRY = 1,
+ /// \brief Describes a source location entry (SLocEntry) for a
+ /// buffer.
+ SM_SLOC_BUFFER_ENTRY = 2,
+ /// \brief Describes a blob that contains the data for a buffer
+ /// entry. This kind of record always directly follows a
+ /// SM_SLOC_BUFFER_ENTRY record.
+ SM_SLOC_BUFFER_BLOB = 3,
+ /// \brief Describes a source location entry (SLocEntry) for a
+ /// macro instantiation.
+ SM_SLOC_INSTANTIATION_ENTRY = 4,
+ /// \brief Describes the SourceManager's line table, with
+ /// information about #line directives.
+ SM_LINE_TABLE = 5,
+ /// \brief Describes one header file info [isImport, DirInfo, NumIncludes]
+ /// ControllingMacro is optional.
+ SM_HEADER_FILE_INFO = 6
+ };
+
+ /// \brief Record types used within a preprocessor block.
+ enum PreprocessorRecordTypes {
+ // The macros in the PP section are a PP_MACRO_* instance followed by a
+ // list of PP_TOKEN instances for each token in the definition.
+
+ /// \brief An object-like macro definition.
+ /// [PP_MACRO_OBJECT_LIKE, IdentInfoID, SLoc, IsUsed]
+ PP_MACRO_OBJECT_LIKE = 1,
+
+ /// \brief A function-like macro definition.
+ /// [PP_MACRO_FUNCTION_LIKE, <ObjectLikeStuff>, IsC99Varargs, IsGNUVarars,
+ /// NumArgs, ArgIdentInfoID* ]
+ PP_MACRO_FUNCTION_LIKE = 2,
+
+ /// \brief Describes one token.
+ /// [PP_TOKEN, SLoc, Length, IdentInfoID, Kind, Flags]
+ PP_TOKEN = 3
+ };
+
+ /// \defgroup PCHAST Precompiled header AST constants
+ ///
+ /// The constants in this group describe various components of the
+ /// abstract syntax tree within a precompiled header.
+ ///
+ /// @{
+
+ /// \brief Predefined type IDs.
+ ///
+ /// These type IDs correspond to predefined types in the AST
+ /// context, such as built-in types (int) and special place-holder
+ /// types (the <overload> and <dependent> type markers). Such
+ /// types are never actually serialized, since they will be built
+ /// by the AST context when it is created.
+ enum PredefinedTypeIDs {
+ /// \brief The NULL type.
+ PREDEF_TYPE_NULL_ID = 0,
+ /// \brief The void type.
+ PREDEF_TYPE_VOID_ID = 1,
+ /// \brief The 'bool' or '_Bool' type.
+ PREDEF_TYPE_BOOL_ID = 2,
+ /// \brief The 'char' type, when it is unsigned.
+ PREDEF_TYPE_CHAR_U_ID = 3,
+ /// \brief The 'unsigned char' type.
+ PREDEF_TYPE_UCHAR_ID = 4,
+ /// \brief The 'unsigned short' type.
+ PREDEF_TYPE_USHORT_ID = 5,
+ /// \brief The 'unsigned int' type.
+ PREDEF_TYPE_UINT_ID = 6,
+ /// \brief The 'unsigned long' type.
+ PREDEF_TYPE_ULONG_ID = 7,
+ /// \brief The 'unsigned long long' type.
+ PREDEF_TYPE_ULONGLONG_ID = 8,
+ /// \brief The 'char' type, when it is signed.
+ PREDEF_TYPE_CHAR_S_ID = 9,
+ /// \brief The 'signed char' type.
+ PREDEF_TYPE_SCHAR_ID = 10,
+ /// \brief The C++ 'wchar_t' type.
+ PREDEF_TYPE_WCHAR_ID = 11,
+ /// \brief The (signed) 'short' type.
+ PREDEF_TYPE_SHORT_ID = 12,
+ /// \brief The (signed) 'int' type.
+ PREDEF_TYPE_INT_ID = 13,
+ /// \brief The (signed) 'long' type.
+ PREDEF_TYPE_LONG_ID = 14,
+ /// \brief The (signed) 'long long' type.
+ PREDEF_TYPE_LONGLONG_ID = 15,
+ /// \brief The 'float' type.
+ PREDEF_TYPE_FLOAT_ID = 16,
+ /// \brief The 'double' type.
+ PREDEF_TYPE_DOUBLE_ID = 17,
+ /// \brief The 'long double' type.
+ PREDEF_TYPE_LONGDOUBLE_ID = 18,
+ /// \brief The placeholder type for overloaded function sets.
+ PREDEF_TYPE_OVERLOAD_ID = 19,
+ /// \brief The placeholder type for dependent types.
+ PREDEF_TYPE_DEPENDENT_ID = 20,
+ /// \brief The '__uint128_t' type.
+ PREDEF_TYPE_UINT128_ID = 21,
+ /// \brief The '__int128_t' type.
+ PREDEF_TYPE_INT128_ID = 22,
+ /// \brief The type of 'nullptr'.
+ PREDEF_TYPE_NULLPTR_ID = 23
+ };
+
+ /// \brief The number of predefined type IDs that are reserved for
+ /// the PREDEF_TYPE_* constants.
+ ///
+ /// Type IDs for non-predefined types will start at
+ /// NUM_PREDEF_TYPE_IDs.
+ const unsigned NUM_PREDEF_TYPE_IDS = 100;
+
+ /// \brief Record codes for each kind of type.
+ ///
+ /// These constants describe the records that can occur within a
+ /// block identified by TYPES_BLOCK_ID in the PCH file. Each
+ /// constant describes a record for a specific type class in the
+ /// AST.
+ enum TypeCode {
+ /// \brief An ExtQualType record.
+ TYPE_EXT_QUAL = 1,
+ /// \brief A FixedWidthIntType record.
+ TYPE_FIXED_WIDTH_INT = 2,
+ /// \brief A ComplexType record.
+ TYPE_COMPLEX = 3,
+ /// \brief A PointerType record.
+ TYPE_POINTER = 4,
+ /// \brief A BlockPointerType record.
+ TYPE_BLOCK_POINTER = 5,
+ /// \brief An LValueReferenceType record.
+ TYPE_LVALUE_REFERENCE = 6,
+ /// \brief An RValueReferenceType record.
+ TYPE_RVALUE_REFERENCE = 7,
+ /// \brief A MemberPointerType record.
+ TYPE_MEMBER_POINTER = 8,
+ /// \brief A ConstantArrayType record.
+ TYPE_CONSTANT_ARRAY = 9,
+ /// \brief An IncompleteArrayType record.
+ TYPE_INCOMPLETE_ARRAY = 10,
+ /// \brief A VariableArrayType record.
+ TYPE_VARIABLE_ARRAY = 11,
+ /// \brief A VectorType record.
+ TYPE_VECTOR = 12,
+ /// \brief An ExtVectorType record.
+ TYPE_EXT_VECTOR = 13,
+ /// \brief A FunctionNoProtoType record.
+ TYPE_FUNCTION_NO_PROTO = 14,
+ /// \brief A FunctionProtoType record.
+ TYPE_FUNCTION_PROTO = 15,
+ /// \brief A TypedefType record.
+ TYPE_TYPEDEF = 16,
+ /// \brief A TypeOfExprType record.
+ TYPE_TYPEOF_EXPR = 17,
+ /// \brief A TypeOfType record.
+ TYPE_TYPEOF = 18,
+ /// \brief A RecordType record.
+ TYPE_RECORD = 19,
+ /// \brief An EnumType record.
+ TYPE_ENUM = 20,
+ /// \brief An ObjCInterfaceType record.
+ TYPE_OBJC_INTERFACE = 21,
+ /// \brief An ObjCQualifiedInterfaceType record.
+ TYPE_OBJC_QUALIFIED_INTERFACE = 22,
+ /// \brief An ObjCQualifiedIdType record.
+ TYPE_OBJC_QUALIFIED_ID = 23
+ };
+
+ /// \brief The type IDs for special types constructed by semantic
+ /// analysis.
+ ///
+ /// The constants in this enumeration are indices into the
+ /// SPECIAL_TYPES record.
+ 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,
+ /// \brief CFConstantString type
+ SPECIAL_TYPE_CF_CONSTANT_STRING = 5,
+ /// \brief Objective-C fast enumeration state type
+ SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE = 6
+ };
+
+ /// \brief Record codes for each kind of declaration.
+ ///
+ /// These constants describe the records that can occur within a
+ /// declarations block (identified by DECLS_BLOCK_ID). Each
+ /// constant describes a record for a specific declaration class
+ /// in the AST.
+ enum DeclCode {
+ /// \brief Attributes attached to a declaration.
+ DECL_ATTR = 1,
+ /// \brief A TranslationUnitDecl record.
+ DECL_TRANSLATION_UNIT,
+ /// \brief A TypedefDecl record.
+ DECL_TYPEDEF,
+ /// \brief An EnumDecl record.
+ DECL_ENUM,
+ /// \brief A RecordDecl record.
+ DECL_RECORD,
+ /// \brief An EnumConstantDecl record.
+ DECL_ENUM_CONSTANT,
+ /// \brief A FunctionDecl record.
+ DECL_FUNCTION,
+ /// \brief A ObjCMethodDecl record.
+ DECL_OBJC_METHOD,
+ /// \brief A ObjCInterfaceDecl record.
+ DECL_OBJC_INTERFACE,
+ /// \brief A ObjCProtocolDecl record.
+ DECL_OBJC_PROTOCOL,
+ /// \brief A ObjCIvarDecl record.
+ DECL_OBJC_IVAR,
+ /// \brief A ObjCAtDefsFieldDecl record.
+ DECL_OBJC_AT_DEFS_FIELD,
+ /// \brief A ObjCClassDecl record.
+ DECL_OBJC_CLASS,
+ /// \brief A ObjCForwardProtocolDecl record.
+ DECL_OBJC_FORWARD_PROTOCOL,
+ /// \brief A ObjCCategoryDecl record.
+ DECL_OBJC_CATEGORY,
+ /// \brief A ObjCCategoryImplDecl record.
+ DECL_OBJC_CATEGORY_IMPL,
+ /// \brief A ObjCImplementationDecl record.
+ DECL_OBJC_IMPLEMENTATION,
+ /// \brief A ObjCCompatibleAliasDecl record.
+ DECL_OBJC_COMPATIBLE_ALIAS,
+ /// \brief A ObjCPropertyDecl record.
+ DECL_OBJC_PROPERTY,
+ /// \brief A ObjCPropertyImplDecl record.
+ DECL_OBJC_PROPERTY_IMPL,
+ /// \brief A FieldDecl record.
+ DECL_FIELD,
+ /// \brief A VarDecl record.
+ DECL_VAR,
+ /// \brief An ImplicitParamDecl record.
+ DECL_IMPLICIT_PARAM,
+ /// \brief A ParmVarDecl record.
+ DECL_PARM_VAR,
+ /// \brief An OriginalParmVarDecl record.
+ DECL_ORIGINAL_PARM_VAR,
+ /// \brief A FileScopeAsmDecl record.
+ DECL_FILE_SCOPE_ASM,
+ /// \brief A BlockDecl record.
+ DECL_BLOCK,
+ /// \brief A record that stores the set of declarations that are
+ /// lexically stored within a given DeclContext.
+ ///
+ /// The record itself is an array of declaration IDs, in the
+ /// order in which those declarations were added to the
+ /// declaration context. This data is used when iterating over
+ /// the contents of a DeclContext, e.g., via
+ /// DeclContext::decls_begin()/DeclContext::decls_end().
+ DECL_CONTEXT_LEXICAL,
+ /// \brief A record that stores the set of declarations that are
+ /// visible from a given DeclContext.
+ ///
+ /// The record itself stores a set of mappings, each of which
+ /// associates a declaration name with one or more declaration
+ /// IDs. This data is used when performing qualified name lookup
+ /// into a DeclContext via DeclContext::lookup.
+ DECL_CONTEXT_VISIBLE
+ };
+
+ /// \brief Record codes for each kind of statement or expression.
+ ///
+ /// These constants describe the records that describe statements
+ /// or expressions. These records can occur within either the type
+ /// or declaration blocks, so they begin with record values of
+ /// 50. Each constant describes a record for a specific
+ /// statement or expression class in the AST.
+ enum StmtCode {
+ /// \brief A marker record that indicates that we are at the end
+ /// of an expression.
+ STMT_STOP = 50,
+ /// \brief A NULL expression.
+ STMT_NULL_PTR,
+ /// \brief A NullStmt record.
+ STMT_NULL,
+ /// \brief A CompoundStmt record.
+ STMT_COMPOUND,
+ /// \brief A CaseStmt record.
+ STMT_CASE,
+ /// \brief A DefaultStmt record.
+ STMT_DEFAULT,
+ /// \brief A LabelStmt record.
+ STMT_LABEL,
+ /// \brief An IfStmt record.
+ STMT_IF,
+ /// \brief A SwitchStmt record.
+ STMT_SWITCH,
+ /// \brief A WhileStmt record.
+ STMT_WHILE,
+ /// \brief A DoStmt record.
+ STMT_DO,
+ /// \brief A ForStmt record.
+ STMT_FOR,
+ /// \brief A GotoStmt record.
+ STMT_GOTO,
+ /// \brief An IndirectGotoStmt record.
+ STMT_INDIRECT_GOTO,
+ /// \brief A ContinueStmt record.
+ STMT_CONTINUE,
+ /// \brief A BreakStmt record.
+ STMT_BREAK,
+ /// \brief A ReturnStmt record.
+ STMT_RETURN,
+ /// \brief A DeclStmt record.
+ STMT_DECL,
+ /// \brief An AsmStmt record.
+ STMT_ASM,
+ /// \brief A PredefinedExpr record.
+ EXPR_PREDEFINED,
+ /// \brief A DeclRefExpr record.
+ EXPR_DECL_REF,
+ /// \brief An IntegerLiteral record.
+ EXPR_INTEGER_LITERAL,
+ /// \brief A FloatingLiteral record.
+ EXPR_FLOATING_LITERAL,
+ /// \brief An ImaginaryLiteral record.
+ EXPR_IMAGINARY_LITERAL,
+ /// \brief A StringLiteral record.
+ EXPR_STRING_LITERAL,
+ /// \brief A CharacterLiteral record.
+ EXPR_CHARACTER_LITERAL,
+ /// \brief A ParenExpr record.
+ EXPR_PAREN,
+ /// \brief A UnaryOperator record.
+ EXPR_UNARY_OPERATOR,
+ /// \brief A SizefAlignOfExpr record.
+ EXPR_SIZEOF_ALIGN_OF,
+ /// \brief An ArraySubscriptExpr record.
+ EXPR_ARRAY_SUBSCRIPT,
+ /// \brief A CallExpr record.
+ EXPR_CALL,
+ /// \brief A MemberExpr record.
+ EXPR_MEMBER,
+ /// \brief A BinaryOperator record.
+ EXPR_BINARY_OPERATOR,
+ /// \brief A CompoundAssignOperator record.
+ EXPR_COMPOUND_ASSIGN_OPERATOR,
+ /// \brief A ConditionOperator record.
+ EXPR_CONDITIONAL_OPERATOR,
+ /// \brief An ImplicitCastExpr record.
+ EXPR_IMPLICIT_CAST,
+ /// \brief A CStyleCastExpr record.
+ EXPR_CSTYLE_CAST,
+ /// \brief A CompoundLiteralExpr record.
+ EXPR_COMPOUND_LITERAL,
+ /// \brief An ExtVectorElementExpr record.
+ EXPR_EXT_VECTOR_ELEMENT,
+ /// \brief An InitListExpr record.
+ EXPR_INIT_LIST,
+ /// \brief A DesignatedInitExpr record.
+ EXPR_DESIGNATED_INIT,
+ /// \brief An ImplicitValueInitExpr record.
+ EXPR_IMPLICIT_VALUE_INIT,
+ /// \brief A VAArgExpr record.
+ EXPR_VA_ARG,
+ /// \brief An AddrLabelExpr record.
+ EXPR_ADDR_LABEL,
+ /// \brief A StmtExpr record.
+ EXPR_STMT,
+ /// \brief A TypesCompatibleExpr record.
+ EXPR_TYPES_COMPATIBLE,
+ /// \brief A ChooseExpr record.
+ EXPR_CHOOSE,
+ /// \brief A GNUNullExpr record.
+ EXPR_GNU_NULL,
+ /// \brief A ShuffleVectorExpr record.
+ EXPR_SHUFFLE_VECTOR,
+ /// \brief BlockExpr
+ EXPR_BLOCK,
+ /// \brief A BlockDeclRef record.
+ EXPR_BLOCK_DECL_REF,
+
+ // Objective-C
+
+ /// \brief An ObjCStringLiteral record.
+ EXPR_OBJC_STRING_LITERAL,
+ /// \brief An ObjCEncodeExpr record.
+ EXPR_OBJC_ENCODE,
+ /// \brief An ObjCSelectorExpr record.
+ EXPR_OBJC_SELECTOR_EXPR,
+ /// \brief An ObjCProtocolExpr record.
+ EXPR_OBJC_PROTOCOL_EXPR,
+ /// \brief An ObjCIvarRefExpr record.
+ EXPR_OBJC_IVAR_REF_EXPR,
+ /// \brief An ObjCPropertyRefExpr record.
+ EXPR_OBJC_PROPERTY_REF_EXPR,
+ /// \brief An ObjCKVCRefExpr record.
+ EXPR_OBJC_KVC_REF_EXPR,
+ /// \brief An ObjCMessageExpr record.
+ EXPR_OBJC_MESSAGE_EXPR,
+ /// \brief An ObjCSuperExpr record.
+ EXPR_OBJC_SUPER_EXPR,
+
+ /// \brief An ObjCForCollectionStmt record.
+ STMT_OBJC_FOR_COLLECTION,
+ /// \brief An ObjCAtCatchStmt record.
+ STMT_OBJC_CATCH,
+ /// \brief An ObjCAtFinallyStmt record.
+ STMT_OBJC_FINALLY,
+ /// \brief An ObjCAtTryStmt record.
+ STMT_OBJC_AT_TRY,
+ /// \brief An ObjCAtSynchronizedStmt record.
+ STMT_OBJC_AT_SYNCHRONIZED,
+ /// \brief An ObjCAtThrowStmt record.
+ STMT_OBJC_AT_THROW
+ };
+
+ /// \brief The kinds of designators that can occur in a
+ /// DesignatedInitExpr.
+ enum DesignatorTypes {
+ /// \brief Field designator where only the field name is known.
+ DESIG_FIELD_NAME = 0,
+ /// \brief Field designator where the field has been resolved to
+ /// a declaration.
+ DESIG_FIELD_DECL = 1,
+ /// \brief Array designator.
+ DESIG_ARRAY = 2,
+ /// \brief GNU array range designator.
+ DESIG_ARRAY_RANGE = 3
+ };
+
+ /// @}
+ }
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h
new file mode 100644
index 000000000000..1e00ae34137d
--- /dev/null
+++ b/include/clang/Frontend/PCHReader.h
@@ -0,0 +1,567 @@
+//===--- PCHReader.h - Precompiled Headers Reader ---------------*- 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 PCHReader class, which reads a precompiled header.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_PCH_READER_H
+#define LLVM_CLANG_FRONTEND_PCH_READER_H
+
+#include "clang/Frontend/PCHBitCodes.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/DataTypes.h"
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+ class MemoryBuffer;
+}
+
+namespace clang {
+
+class AddrLabelExpr;
+class ASTConsumer;
+class ASTContext;
+class Attr;
+class Decl;
+class DeclContext;
+class GotoStmt;
+class LabelStmt;
+class NamedDecl;
+class Preprocessor;
+class Sema;
+class SwitchCase;
+
+/// \brief Reads a precompiled head containing the contents of a
+/// translation unit.
+///
+/// The PCHReader class reads a bitstream (produced by the PCHWriter
+/// class) containing the serialized representation of a given
+/// abstract syntax tree and its supporting data structures. An
+/// instance of the PCHReader can be attached to an ASTContext object,
+/// which will provide access to the contents of the PCH file.
+///
+/// The PCH reader provides lazy de-serialization of declarations, as
+/// required when traversing the AST. Only those AST nodes that are
+/// actually required will be de-serialized.
+class PCHReader
+ : public ExternalSemaSource,
+ public IdentifierInfoLookup,
+ public ExternalIdentifierLookup,
+ public ExternalSLocEntrySource {
+public:
+ enum PCHReadResult { Success, Failure, IgnorePCH };
+
+private:
+ /// \brief The semantic analysis object that will be processing the
+ /// PCH file and the translation unit that uses it.
+ Sema *SemaObj;
+
+ /// \brief The preprocessor that will be loading the source file.
+ Preprocessor &PP;
+
+ /// \brief The AST context into which we'll read the PCH file.
+ ASTContext *Context;
+
+ /// \brief The AST consumer.
+ ASTConsumer *Consumer;
+
+ /// \brief The bitstream reader from which we'll read the PCH file.
+ llvm::BitstreamReader StreamFile;
+ llvm::BitstreamCursor Stream;
+
+ /// 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 file name of the PCH file.
+ std::string FileName;
+
+ /// \brief The memory buffer that stores the data associated with
+ /// this PCH file.
+ llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
+
+ /// \brief Offset type for all of the source location entries in the
+ /// PCH file.
+ const uint32_t *SLocOffsets;
+
+ /// \brief The number of source location entries in the PCH file.
+ unsigned TotalNumSLocEntries;
+
+ /// \brief Cursor used to read source location entries.
+ llvm::BitstreamCursor SLocEntryCursor;
+
+ /// \brief Offset of each type within the bitstream, indexed by the
+ /// type ID, or the representation of a Type*.
+ const uint32_t *TypeOffsets;
+
+ /// \brief Types that have already been loaded from the PCH file.
+ ///
+ /// When the pointer at index I is non-NULL, the type with
+ /// ID = (I + 1) << 3 has already been loaded from the PCH file.
+ std::vector<Type *> TypesLoaded;
+
+ /// \brief Offset of each declaration within the bitstream, indexed
+ /// by the declaration ID (-1).
+ const uint32_t *DeclOffsets;
+
+ /// \brief Declarations that have already been loaded from the PCH file.
+ ///
+ /// When the pointer at index I is non-NULL, the declaration with ID
+ /// = I + 1 has already been loaded.
+ std::vector<Decl *> DeclsLoaded;
+
+ typedef llvm::DenseMap<const DeclContext *, std::pair<uint64_t, uint64_t> >
+ DeclContextOffsetsMap;
+
+ /// \brief Offsets of the lexical and visible declarations for each
+ /// DeclContext.
+ DeclContextOffsetsMap DeclContextOffsets;
+
+ /// \brief Actual data for the on-disk hash table.
+ ///
+ // 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;
+
+ /// \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 A vector containing identifiers that have already been
+ /// loaded.
+ ///
+ /// If the pointer at index I is non-NULL, then it refers to the
+ /// IdentifierInfo for the identifier with ID=I+1 that has already
+ /// been loaded.
+ std::vector<IdentifierInfo *> IdentifiersLoaded;
+
+ /// \brief A pointer to an on-disk hash table of opaque type
+ /// PCHMethodPoolLookupTable.
+ ///
+ /// This hash table provides the instance and factory methods
+ /// associated with every selector known in the PCH file.
+ void *MethodPoolLookupTable;
+
+ /// \brief A pointer to the character data that comprises the method
+ /// pool.
+ ///
+ /// The SelectorOffsets table refers into this memory.
+ const unsigned char *MethodPoolLookupTableData;
+
+ /// \brief The number of selectors stored in the method pool itself.
+ unsigned TotalSelectorsInMethodPool;
+
+ /// \brief Offsets into the method pool lookup table's data array
+ /// where each selector resides.
+ const uint32_t *SelectorOffsets;
+
+ /// \brief The total number of selectors stored in the PCH file.
+ unsigned TotalNumSelectors;
+
+ /// \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;
+
+ /// \brief The set of external definitions stored in the the PCH
+ /// file.
+ llvm::SmallVector<uint64_t, 16> ExternalDefinitions;
+
+ /// \brief The set of tentative definitions stored in the the PCH
+ /// file.
+ llvm::SmallVector<uint64_t, 16> TentativeDefinitions;
+
+ /// \brief The set of locally-scoped external declarations stored in
+ /// the the PCH file.
+ llvm::SmallVector<uint64_t, 16> LocallyScopedExternalDecls;
+
+ /// \brief The set of ext_vector type declarations stored in the the
+ /// PCH file.
+ llvm::SmallVector<uint64_t, 4> ExtVectorDecls;
+
+ /// \brief The set of Objective-C category definitions stored in the
+ /// the PCH file.
+ llvm::SmallVector<uint64_t, 4> ObjCCategoryImpls;
+
+ /// \brief The original file name that was used to build the PCH
+ /// file.
+ std::string OriginalFileName;
+
+ /// \brief Mapping from switch-case IDs in the PCH file to
+ /// switch-case statements.
+ std::map<unsigned, SwitchCase *> SwitchCaseStmts;
+
+ /// \brief Mapping from label statement IDs in the PCH file to label
+ /// statements.
+ std::map<unsigned, LabelStmt *> LabelStmts;
+
+ /// \brief Mapping from label IDs to the set of "goto" statements
+ /// that point to that label before the label itself has been
+ /// de-serialized.
+ std::multimap<unsigned, GotoStmt *> UnresolvedGotoStmts;
+
+ /// \brief Mapping from label IDs to the set of address label
+ /// expressions that point to that label before the label itself has
+ /// been de-serialized.
+ std::multimap<unsigned, AddrLabelExpr *> UnresolvedAddrLabelExprs;
+
+ /// \brief The number of stat() calls that hit/missed the stat
+ /// cache.
+ unsigned NumStatHits, NumStatMisses;
+
+ /// \brief The number of source location entries de-serialized from
+ /// the PCH file.
+ unsigned NumSLocEntriesRead;
+
+ /// \brief The number of statements (and expressions) de-serialized
+ /// from the PCH file.
+ unsigned NumStatementsRead;
+
+ /// \brief The total number of statements (and expressions) stored
+ /// in the PCH file.
+ unsigned TotalNumStatements;
+
+ /// \brief The number of macros de-serialized from the PCH file.
+ unsigned NumMacrosRead;
+
+ /// \brief The number of method pool entries that have been read.
+ unsigned NumMethodPoolSelectorsRead;
+
+ /// \brief The number of times we have looked into the global method
+ /// pool and not found anything.
+ unsigned NumMethodPoolMisses;
+
+ /// \brief The total number of macros stored in the PCH file.
+ unsigned TotalNumMacros;
+
+ /// Number of lexical decl contexts read/total.
+ unsigned NumLexicalDeclContextsRead, TotalLexicalDeclContexts;
+
+ /// Number of visible decl contexts read/total.
+ unsigned NumVisibleDeclContextsRead, TotalVisibleDeclContexts;
+
+ /// \brief FIXME: document!
+ llvm::SmallVector<uint64_t, 4> SpecialTypes;
+
+ /// \brief Contains declarations and definitions that will be
+ /// "interesting" to the ASTConsumer, when we get that AST consumer.
+ ///
+ /// "Interesting" declarations are those that have data that may
+ /// need to be emitted, such as inline function definitions or
+ /// Objective-C protocols.
+ llvm::SmallVector<Decl *, 16> InterestingDecls;
+
+ /// \brief The file ID for the predefines buffer in the PCH file.
+ FileID PCHPredefinesBufferID;
+
+ /// \brief Pointer to the beginning of the predefines buffer in the
+ /// PCH file.
+ const char *PCHPredefines;
+
+ /// \brief Length of the predefines buffer in the PCH file.
+ unsigned PCHPredefinesLen;
+
+ /// \brief Suggested contents of the predefines buffer, after this
+ /// PCH file has been processed.
+ ///
+ /// In most cases, this string will be empty, because the predefines
+ /// buffer computed to build the PCH file will be identical to the
+ /// predefines buffer computed from the command line. However, when
+ /// there are differences that the PCH reader can work around, this
+ /// predefines buffer may contain additional definitions.
+ std::string SuggestedPredefines;
+
+ PCHReadResult ReadPCHBlock();
+ bool CheckPredefinesBuffer(const char *PCHPredef,
+ unsigned PCHPredefLen,
+ FileID PCHBufferID);
+ PCHReadResult ReadSourceManagerBlock();
+ PCHReadResult ReadSLocEntryRecord(unsigned ID);
+
+ bool ParseLanguageOptions(const llvm::SmallVectorImpl<uint64_t> &Record);
+ QualType ReadTypeRecord(uint64_t Offset);
+ void LoadedDecl(unsigned Index, Decl *D);
+ Decl *ReadDeclRecord(uint64_t Offset, unsigned Index);
+
+ /// \brief Produce an error diagnostic and return true.
+ ///
+ /// This routine should only be used for fatal errors that have to
+ /// do with non-routine failures (e.g., corrupted PCH file).
+ bool Error(const char *Msg);
+
+ PCHReader(const PCHReader&); // do not implement
+ PCHReader &operator=(const PCHReader &); // do not implement
+
+public:
+ typedef llvm::SmallVector<uint64_t, 64> RecordData;
+
+ explicit PCHReader(Preprocessor &PP, ASTContext *Context);
+ ~PCHReader();
+
+ /// \brief Load the precompiled header designated by the given file
+ /// name.
+ PCHReadResult ReadPCH(const std::string &FileName);
+
+ /// \brief Retrieve the name of the original source file name
+ const std::string &getOriginalSourceFile() { return OriginalFileName; }
+
+ /// \brief Retrieve the name of the original source file name
+ /// directly from the PCH file, without actually loading the PCH
+ /// file.
+ static std::string getOriginalSourceFile(const std::string &PCHFileName);
+
+ /// \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 Resolve a type ID into a type, potentially building a new
+ /// type.
+ virtual QualType GetType(pch::TypeID ID);
+
+ /// \brief Resolve a declaration ID into a declaration, potentially
+ /// building a new declaration.
+ virtual Decl *GetDecl(pch::DeclID ID);
+
+ /// \brief Resolve the offset of a statement into a statement.
+ ///
+ /// This operation will read a new statement from the external
+ /// source each time it is called, and is meant to be used via a
+ /// LazyOffsetPtr (which is used by Decls for the body of functions, etc).
+ virtual Stmt *GetDeclStmt(uint64_t Offset);
+
+ /// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the
+ /// specified cursor. Read the abbreviations that are at the top of the block
+ /// and then leave the cursor pointing into the block.
+ bool ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, unsigned BlockID);
+
+ /// \brief Read all of the declarations lexically stored in a
+ /// declaration context.
+ ///
+ /// \param DC The declaration context whose declarations will be
+ /// read.
+ ///
+ /// \param Decls Vector that will contain the declarations loaded
+ /// from the external source. The caller is responsible for merging
+ /// these declarations with any declarations already stored in the
+ /// declaration context.
+ ///
+ /// \returns true if there was an error while reading the
+ /// declarations for this declaration context.
+ virtual bool ReadDeclsLexicallyInContext(DeclContext *DC,
+ llvm::SmallVectorImpl<pch::DeclID> &Decls);
+
+ /// \brief Read all of the declarations visible from a declaration
+ /// context.
+ ///
+ /// \param DC The declaration context whose visible declarations
+ /// will be read.
+ ///
+ /// \param Decls A vector of visible declaration structures,
+ /// providing the mapping from each name visible in the declaration
+ /// context to the declaration IDs of declarations with that name.
+ ///
+ /// \returns true if there was an error while reading the
+ /// declarations for this declaration context.
+ ///
+ /// FIXME: Using this intermediate data structure results in an
+ /// extraneous copying of the data. Could we pass in a reference to
+ /// the StoredDeclsMap instead?
+ virtual bool ReadDeclsVisibleInContext(DeclContext *DC,
+ llvm::SmallVectorImpl<VisibleDeclaration> & Decls);
+
+ /// \brief Function that will be invoked when we begin parsing a new
+ /// translation unit involving this external AST source.
+ ///
+ /// This function will provide all of the external definitions to
+ /// the ASTConsumer.
+ virtual void StartTranslationUnit(ASTConsumer *Consumer);
+
+ /// \brief Print some statistics about PCH usage.
+ virtual void PrintStats();
+
+ /// \brief Initialize the semantic source with the Sema instance
+ /// being used to perform semantic analysis on the abstract syntax
+ /// tree.
+ virtual void InitializeSema(Sema &S);
+
+ /// \brief Retrieve the IdentifierInfo for the named identifier.
+ ///
+ /// This routine builds a new IdentifierInfo for the given
+ /// identifier. If any declarations with this name are visible from
+ /// translation unit scope, their declarations will be deserialized
+ /// and introduced into the declaration chain of the
+ /// identifier. FIXME: if this identifier names a macro, deserialize
+ /// the macro.
+ virtual IdentifierInfo* get(const char *NameStart, const char *NameEnd);
+
+ /// \brief Load the contents of the global method pool for a given
+ /// selector.
+ ///
+ /// \returns a pair of Objective-C methods lists containing the
+ /// instance and factory methods, respectively, with this selector.
+ virtual std::pair<ObjCMethodList, ObjCMethodList>
+ ReadMethodPool(Selector Sel);
+
+ void SetIdentifierInfo(unsigned ID, IdentifierInfo *II);
+
+ /// \brief Report a diagnostic.
+ DiagnosticBuilder Diag(unsigned DiagID);
+
+ /// \brief Report a diagnostic.
+ DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
+
+ IdentifierInfo *DecodeIdentifierInfo(unsigned Idx);
+
+ IdentifierInfo *GetIdentifierInfo(const RecordData &Record, unsigned &Idx) {
+ return DecodeIdentifierInfo(Record[Idx++]);
+ }
+
+ virtual IdentifierInfo *GetIdentifier(unsigned ID) {
+ return DecodeIdentifierInfo(ID);
+ }
+
+ /// \brief Read the source location entry with index ID.
+ virtual void ReadSLocEntry(unsigned ID);
+
+ Selector DecodeSelector(unsigned Idx);
+
+ Selector GetSelector(const RecordData &Record, unsigned &Idx) {
+ return DecodeSelector(Record[Idx++]);
+ }
+ DeclarationName ReadDeclarationName(const RecordData &Record, unsigned &Idx);
+
+ /// \brief Read an integral value
+ llvm::APInt ReadAPInt(const RecordData &Record, unsigned &Idx);
+
+ /// \brief Read a signed integral value
+ llvm::APSInt ReadAPSInt(const RecordData &Record, unsigned &Idx);
+
+ /// \brief Read a floating-point value
+ llvm::APFloat ReadAPFloat(const RecordData &Record, unsigned &Idx);
+
+ // \brief Read a string
+ std::string ReadString(const RecordData &Record, unsigned &Idx);
+
+ /// \brief Reads attributes from the current stream position.
+ Attr *ReadAttributes();
+
+ /// \brief ReadDeclExpr - Reads an expression from the current decl cursor.
+ Expr *ReadDeclExpr();
+
+ /// \brief ReadTypeExpr - Reads an expression from the current type cursor.
+ Expr *ReadTypeExpr();
+
+ /// \brief Reads a statement from the specified cursor.
+ Stmt *ReadStmt(llvm::BitstreamCursor &Cursor);
+
+ /// \brief Read a statement from the current DeclCursor.
+ Stmt *ReadDeclStmt() {
+ return ReadStmt(DeclsCursor);
+ }
+
+ /// \brief Reads the macro record located at the given offset.
+ void ReadMacroRecord(uint64_t Offset);
+
+ /// \brief Retrieve the AST context that this PCH reader
+ /// supplements.
+ ASTContext *getContext() { return Context; }
+
+ // \brief Contains declarations that were loaded before we have
+ // access to a Sema object.
+ llvm::SmallVector<NamedDecl *, 16> PreloadedDecls;
+
+ /// \brief Retrieve the semantic analysis object used to analyze the
+ /// translation unit in which the precompiled header is being
+ /// imported.
+ Sema *getSema() { return SemaObj; }
+
+ /// \brief Retrieve the stream that this PCH reader is reading from.
+ llvm::BitstreamCursor &getStream() { return Stream; }
+ llvm::BitstreamCursor &getDeclsCursor() { return DeclsCursor; }
+
+ /// \brief Retrieve the identifier table associated with the
+ /// preprocessor.
+ IdentifierTable &getIdentifierTable();
+
+ /// \brief Record that the given ID maps to the given switch-case
+ /// statement.
+ void RecordSwitchCaseID(SwitchCase *SC, unsigned ID);
+
+ /// \brief Retrieve the switch-case statement with the given ID.
+ SwitchCase *getSwitchCaseWithID(unsigned ID);
+
+ /// \brief Record that the given label statement has been
+ /// deserialized and has the given ID.
+ void RecordLabelStmt(LabelStmt *S, unsigned ID);
+
+ /// \brief Set the label of the given statement to the label
+ /// identified by ID.
+ ///
+ /// Depending on the order in which the label and other statements
+ /// referencing that label occur, this operation may complete
+ /// immediately (updating the statement) or it may queue the
+ /// statement to be back-patched later.
+ void SetLabelOf(GotoStmt *S, unsigned ID);
+
+ /// \brief Set the label of the given expression to the label
+ /// identified by ID.
+ ///
+ /// Depending on the order in which the label and other statements
+ /// referencing that label occur, this operation may complete
+ /// immediately (updating the statement) or it may queue the
+ /// statement to be back-patched later.
+ void SetLabelOf(AddrLabelExpr *S, unsigned ID);
+};
+
+/// \brief Helper class that saves the current stream position and
+/// then restores it when destroyed.
+struct SavedStreamPosition {
+ explicit SavedStreamPosition(llvm::BitstreamCursor &Cursor)
+ : Cursor(Cursor), Offset(Cursor.GetCurrentBitNo()) { }
+
+ ~SavedStreamPosition() {
+ Cursor.JumpToBit(Offset);
+ }
+
+private:
+ llvm::BitstreamCursor &Cursor;
+ uint64_t Offset;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h
new file mode 100644
index 000000000000..5cb939547f2c
--- /dev/null
+++ b/include/clang/Frontend/PCHWriter.h
@@ -0,0 +1,278 @@
+//===--- PCHWriter.h - Precompiled Headers Writer ---------------*- 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 PCHWriter class, which writes a precompiled
+// header containing a serialized representation of a translation
+// unit.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_FRONTEND_PCH_WRITER_H
+#define LLVM_CLANG_FRONTEND_PCH_WRITER_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/Frontend/PCHBitCodes.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include <map>
+#include <queue>
+
+namespace llvm {
+ class APFloat;
+ class APInt;
+ class BitstreamWriter;
+}
+
+namespace clang {
+
+class ASTContext;
+class LabelStmt;
+class MemorizeStatCalls;
+class Preprocessor;
+class Sema;
+class SourceManager;
+class SwitchCase;
+class TargetInfo;
+
+/// \brief Writes a precompiled header containing the contents of a
+/// translation unit.
+///
+/// The PCHWriter class produces a bitstream containing the serialized
+/// representation of a given abstract syntax tree and its supporting
+/// data structures. This bitstream can be de-serialized via an
+/// instance of the PCHReader class.
+class PCHWriter {
+public:
+ typedef llvm::SmallVector<uint64_t, 64> RecordData;
+
+private:
+ /// \brief The bitstream writer used to emit this precompiled header.
+ llvm::BitstreamWriter &Stream;
+
+ /// \brief Map that provides the ID numbers of each declaration within
+ /// the output stream.
+ ///
+ /// The ID numbers of declarations are consecutive (in order of
+ /// discovery) and start at 2. 1 is reserved for the translation
+ /// unit, while 0 is reserved for NULL.
+ llvm::DenseMap<const Decl *, pch::DeclID> DeclIDs;
+
+ /// \brief Offset of each declaration in the bitstream, indexed by
+ /// the declaration's ID.
+ std::vector<uint32_t> DeclOffsets;
+
+ /// \brief Queue containing the declarations that we still need to
+ /// emit.
+ std::queue<Decl *> DeclsToEmit;
+
+ /// \brief Map that provides the ID numbers of each type within the
+ /// output stream.
+ ///
+ /// 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 3 bits to
+ /// allow for the const/volatile/restrict qualifiers.
+ llvm::DenseMap<const Type *, pch::TypeID> TypeIDs;
+
+ /// \brief Offset of each type in the bitstream, indexed by
+ /// the type's ID.
+ std::vector<uint32_t> TypeOffsets;
+
+ /// \brief The type ID that will be assigned to the next new type.
+ pch::TypeID NextTypeID;
+
+ /// \brief Queue containing the types that we still need to
+ /// emit.
+ std::queue<const Type *> TypesToEmit;
+
+ /// \brief Map that provides the ID numbers of each identifier in
+ /// the output stream.
+ ///
+ /// The ID numbers for identifiers are consecutive (in order of
+ /// discovery), starting at 1. An ID of zero refers to a NULL
+ /// IdentifierInfo.
+ llvm::DenseMap<const IdentifierInfo *, pch::IdentID> IdentifierIDs;
+
+ /// \brief Offsets of each of the identifier IDs into the identifier
+ /// table.
+ std::vector<uint32_t> IdentifierOffsets;
+
+ /// \brief Map that provides the ID numbers of each Selector.
+ llvm::DenseMap<Selector, pch::SelectorID> SelectorIDs;
+
+ /// \brief Offset of each selector within the method pool/selector
+ /// table, indexed by the Selector ID (-1).
+ std::vector<uint32_t> SelectorOffsets;
+
+ /// \brief A vector of all Selectors (ordered by ID).
+ std::vector<Selector> SelVector;
+
+ /// \brief Offsets of each of the macro identifiers into the
+ /// bitstream.
+ ///
+ /// For each identifier that is associated with a macro, this map
+ /// provides the offset into the bitstream where that macro is
+ /// defined.
+ llvm::DenseMap<const IdentifierInfo *, uint64_t> MacroOffsets;
+
+ /// \brief Declarations encountered that might be external
+ /// definitions.
+ ///
+ /// We keep track of external definitions (as well as tentative
+ /// definitions) as we are emitting declarations to the PCH
+ /// file. The PCH file contains a separate record for these external
+ /// definitions, which are provided to the AST consumer by the PCH
+ /// reader. This is behavior is required to properly cope with,
+ /// e.g., tentative variable definitions that occur within
+ /// 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;
+
+ /// \brief Statements that we've encountered while serializing a
+ /// declaration or type.
+ llvm::SmallVector<Stmt *, 8> StmtsToEmit;
+
+ /// \brief Mapping from SwitchCase statements to IDs.
+ std::map<SwitchCase *, unsigned> SwitchCaseIDs;
+
+ /// \brief Mapping from LabelStmt statements to IDs.
+ std::map<LabelStmt *, unsigned> LabelIDs;
+
+ /// \brief The number of statements written to the PCH file.
+ unsigned NumStatements;
+
+ /// \brief The number of macros written to the PCH file.
+ unsigned NumMacros;
+
+ /// \brief The number of lexical declcontexts written to the PCH
+ /// file.
+ unsigned NumLexicalDeclContexts;
+
+ /// \brief The number of visible declcontexts written to the PCH
+ /// file.
+ unsigned NumVisibleDeclContexts;
+
+ void WriteBlockInfoBlock();
+ void WriteMetadata(ASTContext &Context);
+ void WriteLanguageOptions(const LangOptions &LangOpts);
+ void WriteStatCache(MemorizeStatCalls &StatCalls);
+ void WriteSourceManagerBlock(SourceManager &SourceMgr,
+ const Preprocessor &PP);
+ void WritePreprocessor(const Preprocessor &PP);
+ void WriteType(const Type *T);
+ void WriteTypesBlock(ASTContext &Context);
+ uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
+ uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
+
+ void WriteDeclsBlock(ASTContext &Context);
+ void WriteMethodPool(Sema &SemaRef);
+ void WriteIdentifierTable(Preprocessor &PP);
+ void WriteAttributeRecord(const Attr *Attr);
+
+ unsigned ParmVarDeclAbbrev;
+ void WriteDeclsBlockAbbrevs();
+
+public:
+ /// \brief Create a new precompiled header writer that outputs to
+ /// the given bitstream.
+ PCHWriter(llvm::BitstreamWriter &Stream);
+
+ /// \brief Write a precompiled header for the given semantic analysis.
+ void WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls);
+
+ /// \brief Emit a source location.
+ void AddSourceLocation(SourceLocation Loc, RecordData &Record);
+
+ /// \brief Emit an integral value.
+ void AddAPInt(const llvm::APInt &Value, RecordData &Record);
+
+ /// \brief Emit a signed integral value.
+ void AddAPSInt(const llvm::APSInt &Value, RecordData &Record);
+
+ /// \brief Emit a floating-point value.
+ void AddAPFloat(const llvm::APFloat &Value, RecordData &Record);
+
+ /// \brief Emit a reference to an identifier
+ void AddIdentifierRef(const IdentifierInfo *II, RecordData &Record);
+
+ /// \brief Emit a Selector (which is a smart pointer reference)
+ void AddSelectorRef(const Selector, RecordData &Record);
+
+ /// \brief Get the unique number used to refer to the given
+ /// identifier.
+ pch::IdentID getIdentifierRef(const IdentifierInfo *II);
+
+ /// \brief Retrieve the offset of the macro definition for the given
+ /// identifier.
+ ///
+ /// The identifier must refer to a macro.
+ uint64_t getMacroOffset(const IdentifierInfo *II) {
+ assert(MacroOffsets.find(II) != MacroOffsets.end() &&
+ "Identifier does not name a macro");
+ return MacroOffsets[II];
+ }
+
+ /// \brief Emit a reference to a type.
+ void AddTypeRef(QualType T, RecordData &Record);
+
+ /// \brief Emit a reference to a declaration.
+ void AddDeclRef(const Decl *D, RecordData &Record);
+
+ /// \brief Determine the declaration ID of an already-emitted
+ /// declaration.
+ pch::DeclID getDeclID(const Decl *D);
+
+ /// \brief Emit a declaration name.
+ void AddDeclarationName(DeclarationName Name, RecordData &Record);
+
+ /// \brief Add a string to the given record.
+ void AddString(const std::string &Str, RecordData &Record);
+
+ /// \brief Note that the identifier II occurs at the given offset
+ /// within the identifier table.
+ void SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset);
+
+ /// \brief Note that the selector Sel occurs at the given offset
+ /// within the method pool/selector table.
+ void SetSelectorOffset(Selector Sel, uint32_t Offset);
+
+ /// \brief Add the given statement or expression to the queue of
+ /// statements to emit.
+ ///
+ /// This routine should be used when emitting types and declarations
+ /// that have expressions as part of their formulation. Once the
+ /// type or declaration has been written, call FlushStmts() to write
+ /// the corresponding statements just after the type or
+ /// declaration.
+ void AddStmt(Stmt *S) { StmtsToEmit.push_back(S); }
+
+ /// \brief Write the given subexpression to the bitstream.
+ void WriteSubStmt(Stmt *S);
+
+ /// \brief Flush all of the statements and expressions that have
+ /// been added to the queue via AddStmt().
+ void FlushStmts();
+
+ /// \brief Record an ID for the given switch-case statement.
+ unsigned RecordSwitchCaseID(SwitchCase *S);
+
+ /// \brief Retrieve the ID for the given switch-case statement.
+ unsigned getSwitchCaseID(SwitchCase *S);
+
+ /// \brief Retrieve the ID for the given label statement, which may
+ /// or may not have been emitted yet.
+ unsigned GetLabelID(LabelStmt *S);
+
+ unsigned getParmVarDeclAbbrev() const { return ParmVarDeclAbbrev; }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Frontend/PathDiagnosticClients.h b/include/clang/Frontend/PathDiagnosticClients.h
new file mode 100644
index 000000000000..028cd8549272
--- /dev/null
+++ b/include/clang/Frontend/PathDiagnosticClients.h
@@ -0,0 +1,34 @@
+//===--- PathDiagnosticClients.h - Path Diagnostic Clients ------*- 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 to create different path diagostic clients.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_PATH_DIAGNOSTIC_CLIENTS_H
+#define LLVM_CLANG_FRONTEND_PATH_DIAGNOSTIC_CLiENTS_H
+
+#include <string>
+
+namespace clang {
+
+class PathDiagnosticClient;
+class Preprocessor;
+class PreprocessorFactory;
+
+PathDiagnosticClient* CreateHTMLDiagnosticClient(const std::string& prefix,
+ Preprocessor* PP = 0,
+ PreprocessorFactory* PPF = 0);
+
+PathDiagnosticClient* CreatePlistDiagnosticClient(const std::string& prefix,
+ Preprocessor* PP,
+ PreprocessorFactory* PPF);
+}
+
+#endif
diff --git a/include/clang/Frontend/TextDiagnosticBuffer.h b/include/clang/Frontend/TextDiagnosticBuffer.h
new file mode 100644
index 000000000000..4e907e1965ea
--- /dev/null
+++ b/include/clang/Frontend/TextDiagnosticBuffer.h
@@ -0,0 +1,48 @@
+//===--- TextDiagnosticBuffer.h - Buffer Text Diagnostics -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a concrete diagnostic client, which buffers the diagnostic messages.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_BUFFER_H_
+#define LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_BUFFER_H_
+
+#include "clang/Basic/Diagnostic.h"
+#include <vector>
+
+namespace clang {
+
+class Preprocessor;
+class SourceManager;
+
+class TextDiagnosticBuffer : public DiagnosticClient {
+public:
+ typedef std::vector<std::pair<SourceLocation, std::string> > DiagList;
+ typedef DiagList::iterator iterator;
+ typedef DiagList::const_iterator const_iterator;
+private:
+ DiagList Errors, Warnings, Notes;
+public:
+ const_iterator err_begin() const { return Errors.begin(); }
+ const_iterator err_end() const { return Errors.end(); }
+
+ const_iterator warn_begin() const { return Warnings.begin(); }
+ const_iterator warn_end() const { return Warnings.end(); }
+
+ 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);
+};
+
+} // end namspace clang
+
+#endif
diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h
new file mode 100644
index 000000000000..3c9dcb8d9c17
--- /dev/null
+++ b/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -0,0 +1,85 @@
+//===--- TextDiagnosticPrinter.h - Text Diagnostic Client -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a concrete diagnostic client, which prints the diagnostics to
+// standard error.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_PRINTER_H_
+#define LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_PRINTER_H_
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+
+namespace llvm {
+ class raw_ostream;
+}
+
+namespace clang {
+class SourceManager;
+class LangOptions;
+
+class TextDiagnosticPrinter : public DiagnosticClient {
+ llvm::raw_ostream &OS;
+ const LangOptions *LangOpts;
+ SourceLocation LastWarningLoc;
+ FullSourceLoc LastLoc;
+ bool LastCaretDiagnosticWasNote;
+
+ bool ShowColumn;
+ bool CaretDiagnostics;
+ bool ShowLocation;
+ bool PrintRangeInfo;
+ bool PrintDiagnosticOption;
+ bool PrintFixItInfo;
+ unsigned MessageLength;
+
+public:
+ TextDiagnosticPrinter(llvm::raw_ostream &os,
+ bool showColumn = true,
+ bool caretDiagnistics = true, bool showLocation = true,
+ bool printRangeInfo = true,
+ bool printDiagnosticOption = true,
+ bool printFixItInfo = true,
+ unsigned messageLength = 0)
+ : OS(os), LangOpts(0),
+ LastCaretDiagnosticWasNote(false), ShowColumn(showColumn),
+ CaretDiagnostics(caretDiagnistics), ShowLocation(showLocation),
+ PrintRangeInfo(printRangeInfo),
+ PrintDiagnosticOption(printDiagnosticOption),
+ PrintFixItInfo(printFixItInfo),
+ MessageLength(messageLength) {}
+
+ void setLangOptions(const LangOptions *LO) {
+ LangOpts = LO;
+ }
+
+ void PrintIncludeStack(SourceLocation Loc, const SourceManager &SM);
+
+ void HighlightRange(const SourceRange &R,
+ const SourceManager &SrcMgr,
+ unsigned LineNo, FileID FID,
+ std::string &CaretLine,
+ const std::string &SourceLine);
+
+ void EmitCaretDiagnostic(SourceLocation Loc,
+ SourceRange *Ranges, unsigned NumRanges,
+ SourceManager &SM,
+ const CodeModificationHint *Hints,
+ unsigned NumHints,
+ unsigned Columns);
+
+ virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info);
+};
+
+} // end namspace clang
+
+#endif
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
new file mode 100644
index 000000000000..41eb31a0fc35
--- /dev/null
+++ b/include/clang/Frontend/Utils.h
@@ -0,0 +1,79 @@
+//===--- Utils.h - Misc utilities for the front-end------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header contains miscellaneous utilities for various front-end actions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_UTILS_H
+#define LLVM_CLANG_FRONTEND_UTILS_H
+
+#include <vector>
+#include <string>
+
+namespace llvm {
+class raw_ostream;
+class raw_fd_ostream;
+}
+
+namespace clang {
+class Preprocessor;
+class MinimalAction;
+class TargetInfo;
+class Diagnostic;
+class ASTConsumer;
+class IdentifierTable;
+class SourceManager;
+class PreprocessorFactory;
+class LangOptions;
+
+/// ProcessWarningOptions - Initialize the diagnostic client and process the
+/// warning options specified on the command line.
+bool ProcessWarningOptions(Diagnostic &Diags,
+ std::vector<std::string> &Warnings,
+ bool Pedantic, bool PedanticErrors,
+ bool NoWarnings);
+
+/// DoPrintPreprocessedInput - Implement -E -dM mode.
+void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream* OS);
+
+/// DoPrintPreprocessedInput - Implement -E mode.
+void DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream* OS,
+ bool EnableCommentOutput,
+ bool EnableMacroCommentOutput,
+ bool DisableLineMarkers,
+ bool DumpDefines);
+
+/// RewriteMacrosInInput - Implement -rewrite-macros mode.
+void RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream* OS);
+
+/// RewriteMacrosInInput - A simple test for the TokenRewriter class.
+void DoRewriteTest(Preprocessor &PP, llvm::raw_ostream* OS);
+
+/// CreatePrintParserActionsAction - Return the actions implementation that
+/// implements the -parse-print-callbacks option.
+MinimalAction *CreatePrintParserActionsAction(Preprocessor &PP,
+ llvm::raw_ostream* OS);
+
+/// CheckDiagnostics - Gather the expected diagnostics and check them.
+bool CheckDiagnostics(Preprocessor &PP);
+
+/// AttachDependencyFileGen - Create a dependency file generator, and attach
+/// it to the given preprocessor. This takes ownership of the output stream.
+void AttachDependencyFileGen(Preprocessor *PP, llvm::raw_ostream *OS,
+ std::vector<std::string> &Targets,
+ bool IncludeSystemHeaders, bool PhonyTarget);
+
+/// CacheTokens - Cache tokens for use with PCH. Note that this requires
+/// a seekable stream.
+void CacheTokens(Preprocessor& PP, llvm::raw_fd_ostream* OS);
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/DirectoryLookup.h b/include/clang/Lex/DirectoryLookup.h
new file mode 100644
index 000000000000..618de39233db
--- /dev/null
+++ b/include/clang/Lex/DirectoryLookup.h
@@ -0,0 +1,133 @@
+//===--- DirectoryLookup.h - Info for searching for headers -----*- 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 DirectoryLookup interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LEX_DIRECTORYLOOKUP_H
+#define LLVM_CLANG_LEX_DIRECTORYLOOKUP_H
+
+#include "clang/Basic/SourceManager.h"
+
+namespace clang {
+class HeaderMap;
+class DirectoryEntry;
+class FileEntry;
+class HeaderSearch;
+
+/// DirectoryLookup - This class represents one entry in the search list that
+/// specifies the search order for directories in #include directives. It
+/// represents either a directory, a framework, or a headermap.
+///
+class DirectoryLookup {
+public:
+ enum LookupType_t {
+ LT_NormalDir,
+ LT_Framework,
+ LT_HeaderMap
+ };
+private:
+ union { // This union is discriminated by isHeaderMap.
+ /// Dir - This is the actual directory that we're referring to for a normal
+ /// directory or a framework.
+ const DirectoryEntry *Dir;
+
+ /// Map - This is the HeaderMap if this is a headermap lookup.
+ ///
+ const HeaderMap *Map;
+ } u;
+
+ /// DirCharacteristic - The type of directory this is: this is an instance of
+ /// SrcMgr::CharacteristicKind.
+ unsigned DirCharacteristic : 2;
+
+ /// UserSupplied - True if this is a user-supplied directory.
+ ///
+ bool UserSupplied : 1;
+
+ /// LookupType - This indicates whether this DirectoryLookup object is a
+ /// normal directory, a framework, or a headermap.
+ unsigned LookupType : 2;
+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) {
+ 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) {
+ u.Map = map;
+ }
+
+ /// getLookupType - Return the kind of directory lookup that this is: either a
+ /// normal directory, a framework path, or a HeaderMap.
+ LookupType_t getLookupType() const { return (LookupType_t)LookupType; }
+
+ /// getName - Return the directory or filename corresponding to this lookup
+ /// object.
+ const char *getName() const;
+
+ /// getDir - Return the directory that this entry refers to.
+ ///
+ const DirectoryEntry *getDir() const { return isNormalDir() ? u.Dir : 0; }
+
+ /// getFrameworkDir - Return the directory that this framework refers to.
+ ///
+ const DirectoryEntry *getFrameworkDir() const {
+ return isFramework() ? u.Dir : 0;
+ }
+
+ /// getHeaderMap - Return the directory that this entry refers to.
+ ///
+ const HeaderMap *getHeaderMap() const { return isHeaderMap() ? u.Map : 0; }
+
+ /// isNormalDir - Return true if this is a normal directory, not a header map.
+ bool isNormalDir() const { return getLookupType() == LT_NormalDir; }
+
+ /// isFramework - True if this is a framework directory.
+ ///
+ bool isFramework() const { return getLookupType() == LT_Framework; }
+
+ /// isHeaderMap - Return true if this is a header map, not a normal directory.
+ bool isHeaderMap() const { return getLookupType() == LT_HeaderMap; }
+
+ /// DirCharacteristic - The type of directory this is, one of the DirType enum
+ /// values.
+ SrcMgr::CharacteristicKind getDirCharacteristic() const {
+ return (SrcMgr::CharacteristicKind)DirCharacteristic;
+ }
+
+ /// isUserSupplied - True if this is a user-supplied directory.
+ ///
+ bool isUserSupplied() const { return UserSupplied; }
+
+
+ /// LookupFile - Lookup the specified file in this search path, returning it
+ /// if it exists or returning null if not.
+ const FileEntry *LookupFile(const char *FilenameStart,
+ const char *FilenameEnd, HeaderSearch &HS) const;
+
+private:
+ const FileEntry *DoFrameworkLookup(const char *FilenameStart,
+ const char *FilenameEnd,
+ HeaderSearch &HS) const;
+
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/HeaderMap.h b/include/clang/Lex/HeaderMap.h
new file mode 100644
index 000000000000..d8033093bd8e
--- /dev/null
+++ b/include/clang/Lex/HeaderMap.h
@@ -0,0 +1,67 @@
+//===--- HeaderMap.h - A file that acts like dir of symlinks ----*- 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 HeaderMap interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LEX_HEADERMAP_H
+#define LLVM_CLANG_LEX_HEADERMAP_H
+
+namespace llvm {
+ class MemoryBuffer;
+}
+namespace clang {
+ class FileEntry;
+ class FileManager;
+ struct HMapBucket;
+ struct HMapHeader;
+
+/// This class represents an Apple concept known as a 'header map'. To the
+/// #include file resolution process, it basically acts like a directory of
+/// symlinks to files. Its advantages are that it is dense and more efficient
+/// to create and process than a directory of symlinks.
+class HeaderMap {
+ HeaderMap(const HeaderMap&); // DO NOT IMPLEMENT
+ void operator=(const HeaderMap&); // DO NOT IMPLEMENT
+
+ const llvm::MemoryBuffer *FileBuffer;
+ bool NeedsBSwap;
+
+ HeaderMap(const llvm::MemoryBuffer *File, bool BSwap)
+ : FileBuffer(File), NeedsBSwap(BSwap) {
+ }
+public:
+ ~HeaderMap();
+
+ /// HeaderMap::Create - This attempts to load the specified file as a header
+ /// map. If it doesn't look like a HeaderMap, it gives up and returns null.
+ static const HeaderMap *Create(const FileEntry *FE);
+
+ /// LookupFile - Check to see if the specified relative filename is located in
+ /// this HeaderMap. If so, open it and return its FileEntry.
+ const FileEntry *LookupFile(const char *FilenameStart,const char *FilenameEnd,
+ FileManager &FM) const;
+
+ /// getFileName - Return the filename of the headermap.
+ const char *getFileName() const;
+
+ /// dump - Print the contents of this headermap to stderr.
+ void dump() const;
+
+private:
+ unsigned getEndianAdjustedWord(unsigned X) const;
+ const HMapHeader &getHeader() const;
+ HMapBucket getBucket(unsigned BucketNo) const;
+ const char *getString(unsigned StrTabIdx) const;
+};
+
+} // end namespace clang.
+
+#endif
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
new file mode 100644
index 000000000000..f21aab1b4015
--- /dev/null
+++ b/include/clang/Lex/HeaderSearch.h
@@ -0,0 +1,237 @@
+//===--- HeaderSearch.h - Resolve Header File Locations ---------*- 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 HeaderSearch interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LEX_HEADERSEARCH_H
+#define LLVM_CLANG_LEX_HEADERSEARCH_H
+
+#include "clang/Lex/DirectoryLookup.h"
+#include "llvm/ADT/StringMap.h"
+#include <vector>
+
+namespace clang {
+
+class ExternalIdentifierLookup;
+class FileEntry;
+class FileManager;
+class IdentifierInfo;
+
+/// HeaderFileInfo - The preprocessor keeps track of this information for each
+/// file that is #included.
+struct HeaderFileInfo {
+ /// isImport - True if this is a #import'd or #pragma once file.
+ bool isImport : 1;
+
+ /// DirInfo - Keep track of whether this is a system header, and if so,
+ /// whether it is C++ clean or not. This can be set by the include paths or
+ /// by #pragma gcc system_header. This is an instance of
+ /// SrcMgr::CharacteristicKind.
+ unsigned DirInfo : 2;
+
+ /// NumIncludes - This is the number of times the file has been included
+ /// already.
+ unsigned short NumIncludes;
+
+ /// ControllingMacro - If this file has a #ifndef XXX (or equivalent) guard
+ /// that protects the entire contents of the file, this is the identifier
+ /// for the macro that controls whether or not it has any effect.
+ ///
+ /// Note: Most clients should use getControllingMacro() to access
+ /// the controlling macro of this header, since
+ /// getControllingMacro() is able to load a controlling macro from
+ /// external storage.
+ const IdentifierInfo *ControllingMacro;
+
+ /// \brief The ID number of the controlling macro.
+ ///
+ /// This ID number will be non-zero when there is a controlling
+ /// macro whose IdentifierInfo may not yet have been loaded from
+ /// external storage.
+ unsigned ControllingMacroID;
+
+ HeaderFileInfo()
+ : isImport(false), DirInfo(SrcMgr::C_User),
+ NumIncludes(0), ControllingMacro(0), ControllingMacroID(0) {}
+
+ /// \brief Retrieve the controlling macro for this header file, if
+ /// any.
+ const IdentifierInfo *getControllingMacro(ExternalIdentifierLookup *External);
+};
+
+/// HeaderSearch - This class encapsulates the information needed to find the
+/// file referenced by a #include or #include_next, (sub-)framework lookup, etc.
+class HeaderSearch {
+ FileManager &FileMgr;
+
+ /// #include search path information. Requests for #include "x" search the
+ /// directory of the #including file first, then each directory in SearchDirs
+ /// consequtively. Requests for <x> search the current dir first, then each
+ /// directory in SearchDirs, starting at SystemDirIdx, consequtively. If
+ /// NoCurDirSearch is true, then the check for the file in the current
+ /// directory is supressed.
+ std::vector<DirectoryLookup> SearchDirs;
+ unsigned SystemDirIdx;
+ bool NoCurDirSearch;
+
+ /// FileInfo - This contains all of the preprocessor-specific data about files
+ /// that are included. The vector is indexed by the FileEntry's UID.
+ ///
+ std::vector<HeaderFileInfo> FileInfo;
+
+ /// LookupFileCache - This is keeps track of each lookup performed by
+ /// LookupFile. The first part of the value is the starting index in
+ /// SearchDirs that the cached search was performed from. If there is a hit
+ /// 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;
+
+
+ /// FrameworkMap - This is a collection mapping a framework or subframework
+ /// name like "Carbon" to the Carbon.framework directory.
+ llvm::StringMap<const DirectoryEntry *> 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 Entity used to resolve the identifier IDs of controlling
+ /// macros into IdentifierInfo pointers, as needed.
+ ExternalIdentifierLookup *ExternalLookup;
+
+ // Various statistics we track for performance analysis.
+ unsigned NumIncluded;
+ unsigned NumMultiIncludeFileOptzn;
+ unsigned NumFrameworkLookups, NumSubFrameworkLookups;
+
+ // HeaderSearch doesn't support default or copy construction.
+ explicit HeaderSearch();
+ explicit HeaderSearch(const HeaderSearch&);
+ void operator=(const HeaderSearch&);
+public:
+ HeaderSearch(FileManager &FM);
+ ~HeaderSearch();
+
+ FileManager &getFileMgr() const { return FileMgr; }
+
+ /// SetSearchPaths - Interface for setting the file search paths.
+ ///
+ void SetSearchPaths(const std::vector<DirectoryLookup> &dirs,
+ unsigned systemDirIdx, bool noCurDirSearch) {
+ SearchDirs = dirs;
+ SystemDirIdx = systemDirIdx;
+ NoCurDirSearch = noCurDirSearch;
+ //LookupFileCache.clear();
+ }
+
+ /// ClearFileInfo - Forget everything we know about headers so far.
+ void ClearFileInfo() {
+ FileInfo.clear();
+ }
+
+ void SetExternalLookup(ExternalIdentifierLookup *EIL) {
+ ExternalLookup = EIL;
+ }
+
+ /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
+ /// return null on failure. isAngled indicates whether the file reference is
+ /// a <> reference. If successful, this returns 'UsedDir', the
+ /// DirectoryLookup member the file was found in, or null if not applicable.
+ /// If CurDir is non-null, the file was found in the specified directory
+ /// search location. This is used to implement #include_next. CurFileEnt, if
+ /// non-null, indicates where the #including file is, in case a relative
+ /// search is needed.
+ const FileEntry *LookupFile(const char *FilenameStart,
+ const char *FilenameEnd, bool isAngled,
+ const DirectoryLookup *FromDir,
+ const DirectoryLookup *&CurDir,
+ const FileEntry *CurFileEnt);
+
+ /// LookupSubframeworkHeader - Look up a subframework for the specified
+ /// #include file. For example, if #include'ing <HIToolbox/HIToolbox.h> from
+ /// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
+ /// is a subframework within Carbon.framework. If so, return the FileEntry
+ /// for the designated file, otherwise return null.
+ const FileEntry *LookupSubframeworkHeader(const char *FilenameStart,
+ const char *FilenameEnd,
+ const FileEntry *RelativeFileEnt);
+
+ /// 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(const char *FWNameStart,
+ const char *FWNameEnd) {
+ return FrameworkMap.GetOrCreateValue(FWNameStart, FWNameEnd).getValue();
+ }
+
+ /// ShouldEnterIncludeFile - Mark the specified file as a target of of a
+ /// #include, #include_next, or #import directive. Return false if #including
+ /// the file will have no effect or true if we should include it.
+ bool ShouldEnterIncludeFile(const FileEntry *File, bool isImport);
+
+
+ /// getFileDirFlavor - Return whether the specified file is a normal header,
+ /// a system header, or a C++ friendly system header.
+ SrcMgr::CharacteristicKind getFileDirFlavor(const FileEntry *File) {
+ return (SrcMgr::CharacteristicKind)getFileInfo(File).DirInfo;
+ }
+
+ /// MarkFileIncludeOnce - Mark the specified file as a "once only" file, e.g.
+ /// due to #pragma once.
+ void MarkFileIncludeOnce(const FileEntry *File) {
+ getFileInfo(File).isImport = true;
+ }
+
+ /// MarkFileSystemHeader - Mark the specified file as a system header, e.g.
+ /// due to #pragma GCC system_header.
+ void MarkFileSystemHeader(const FileEntry *File) {
+ getFileInfo(File).DirInfo = SrcMgr::C_System;
+ }
+
+ /// IncrementIncludeCount - Increment the count for the number of times the
+ /// specified FileEntry has been entered.
+ void IncrementIncludeCount(const FileEntry *File) {
+ ++getFileInfo(File).NumIncludes;
+ }
+
+ /// SetFileControllingMacro - Mark the specified file as having a controlling
+ /// macro. This is used by the multiple-include optimization to eliminate
+ /// no-op #includes.
+ void SetFileControllingMacro(const FileEntry *File,
+ const IdentifierInfo *ControllingMacro) {
+ getFileInfo(File).ControllingMacro = ControllingMacro;
+ }
+
+ /// CreateHeaderMap - This method returns a HeaderMap for the specified
+ /// FileEntry, uniquing them through the the 'HeaderMaps' datastructure.
+ const HeaderMap *CreateHeaderMap(const FileEntry *FE);
+
+ void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; }
+
+ typedef std::vector<HeaderFileInfo>::iterator header_file_iterator;
+ header_file_iterator header_file_begin() { return FileInfo.begin(); }
+ header_file_iterator header_file_end() { return FileInfo.end(); }
+
+ // Used by PCHReader.
+ void setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID);
+
+ void PrintStats();
+private:
+
+ /// getFileInfo - Return the HeaderFileInfo structure for the specified
+ /// FileEntry.
+ HeaderFileInfo &getFileInfo(const FileEntry *FE);
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/LexDiagnostic.h b/include/clang/Lex/LexDiagnostic.h
new file mode 100644
index 000000000000..1502efb55e63
--- /dev/null
+++ b/include/clang/Lex/LexDiagnostic.h
@@ -0,0 +1,27 @@
+//===--- DiagnosticLex.h - Diagnostics for liblex ---------------*- 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_DIAGNOSTICLEX_H
+#define LLVM_CLANG_DIAGNOSTICLEX_H
+
+#include "clang/Basic/Diagnostic.h"
+
+namespace clang {
+ namespace diag {
+ enum {
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM,
+#define LEXSTART
+#include "clang/Basic/DiagnosticLexKinds.inc"
+#undef DIAG
+ NUM_BUILTIN_LEX_DIAGNOSTICS
+ };
+ } // end namespace diag
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
new file mode 100644
index 000000000000..3a73147152af
--- /dev/null
+++ b/include/clang/Lex/Lexer.h
@@ -0,0 +1,376 @@
+//===--- Lexer.h - C Language Family Lexer ----------------------*- 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 Lexer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LEXER_H
+#define LLVM_CLANG_LEXER_H
+
+#include "clang/Lex/PreprocessorLexer.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/SmallVector.h"
+#include <string>
+#include <vector>
+#include <cassert>
+
+namespace clang {
+class Diagnostic;
+class SourceManager;
+class Preprocessor;
+class DiagnosticBuilder;
+
+/// 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
+/// on the specified Preprocessor object to handle preprocessor directives, etc.
+class Lexer : public PreprocessorLexer {
+ //===--------------------------------------------------------------------===//
+ // Constant configuration values for this lexer.
+ const char *BufferStart; // Start of the buffer.
+ 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; // True if lexer for _Pragma handling.
+
+ //===--------------------------------------------------------------------===//
+ // Context-specific lexing flags set by the preprocessor.
+ //
+
+ /// ExtendedTokenMode - The lexer can optionally keep comments and whitespace
+ /// and return them as tokens. This is used for -C and -CC modes, and
+ /// whitespace preservation can be useful for some clients that want to lex
+ /// the file in raw mode and get every character from the file.
+ ///
+ /// When this is set to 2 it returns comments and whitespace. When set to 1
+ /// it returns comments, when it is set to 0 it returns normal tokens only.
+ unsigned char ExtendedTokenMode;
+
+ //===--------------------------------------------------------------------===//
+ // Context that changes as the file is lexed.
+ // NOTE: any state that mutates when in raw mode must have save/restore code
+ // in Lexer::isNextPPTokenLParen.
+
+ // BufferPtr - Current pointer into the buffer. This is the next character
+ // to be lexed.
+ const char *BufferPtr;
+
+ // IsAtStartOfLine - True if the next lexed token should get the "start of
+ // line" flag set on it.
+ bool IsAtStartOfLine;
+
+ Lexer(const Lexer&); // DO NOT IMPLEMENT
+ void operator=(const Lexer&); // DO NOT IMPLEMENT
+ friend class Preprocessor;
+
+ void InitLexer(const char *BufStart, const char *BufPtr, const char *BufEnd);
+public:
+
+ /// Lexer constructor - Create a new lexer object for the specified buffer
+ /// with the specified preprocessor managing the lexing process. This lexer
+ /// assumes that the associated file buffer and Preprocessor objects will
+ /// outlive it, so it doesn't take ownership of either of them.
+ Lexer(FileID FID, Preprocessor &PP);
+
+ /// Lexer constructor - Create a new raw lexer object. This object is only
+ /// suitable for calls to 'LexRawToken'. This lexer assumes that the text
+ /// range will outlive it, so it doesn't take ownership of it.
+ Lexer(SourceLocation FileLoc, const LangOptions &Features,
+ const char *BufStart, const char *BufPtr, const char *BufEnd);
+
+ /// Lexer constructor - Create a new raw lexer object. This object is only
+ /// suitable for calls to 'LexRawToken'. This lexer assumes that the text
+ /// range will outlive it, so it doesn't take ownership of it.
+ Lexer(FileID FID, const SourceManager &SM, const LangOptions &Features);
+
+ /// Create_PragmaLexer: Lexer constructor - Create a new lexer object for
+ /// _Pragma expansion. This has a variety of magic semantics that this method
+ /// sets up. It returns a new'd Lexer that must be delete'd when done.
+ static Lexer *Create_PragmaLexer(SourceLocation SpellingLoc,
+ SourceLocation InstantiationLocStart,
+ SourceLocation InstantiationLocEnd,
+ unsigned TokLen, Preprocessor &PP);
+
+
+ /// getFeatures - Return the language features currently enabled. NOTE: this
+ /// lexer modifies features as a file is parsed!
+ const LangOptions &getFeatures() const { return Features; }
+
+ /// getFileLoc - Return the File Location for the file we are lexing out of.
+ /// The physical location encodes the location where the characters come from,
+ /// the virtual location encodes where we should *claim* the characters came
+ /// from. Currently this is only used by _Pragma handling.
+ SourceLocation getFileLoc() const { return FileLoc; }
+
+ /// Lex - Return the next token in the file. If this is the end of file, it
+ /// return the tok::eof token. Return true if an error occurred and
+ /// compilation should terminate, false if normal. This implicitly involves
+ /// the preprocessor.
+ void Lex(Token &Result) {
+ // Start a new token.
+ Result.startToken();
+
+ // NOTE, any changes here should also change code after calls to
+ // Preprocessor::HandleDirective
+ if (IsAtStartOfLine) {
+ Result.setFlag(Token::StartOfLine);
+ IsAtStartOfLine = false;
+ }
+
+ // Get a token. Note that this may delete the current lexer if the end of
+ // file is reached.
+ LexTokenInternal(Result);
+ }
+
+ /// isPragmaLexer - Returns true if this Lexer is being used to lex a pragma.
+ bool isPragmaLexer() const { return Is_PragmaLexer; }
+
+ /// IndirectLex - An indirect call to 'Lex' that can be invoked via
+ /// the PreprocessorLexer interface.
+ void IndirectLex(Token &Result) { Lex(Result); }
+
+ /// LexFromRawLexer - Lex a token from a designated raw lexer (one with no
+ /// associated preprocessor object. Return true if the 'next character to
+ /// read' pointer points at the end of the lexer buffer, false otherwise.
+ bool LexFromRawLexer(Token &Result) {
+ assert(LexingRawMode && "Not already in raw mode!");
+ Lex(Result);
+ // Note that lexing to the end of the buffer doesn't implicitly delete the
+ // lexer when in raw mode.
+ return BufferPtr == BufferEnd;
+ }
+
+ /// isKeepWhitespaceMode - Return true if the lexer should return tokens for
+ /// every character in the file, including whitespace and comments. This
+ /// should only be used in raw mode, as the preprocessor is not prepared to
+ /// deal with the excess tokens.
+ bool isKeepWhitespaceMode() const {
+ return ExtendedTokenMode > 1;
+ }
+
+ /// SetKeepWhitespaceMode - This method lets clients enable or disable
+ /// whitespace retention mode.
+ void SetKeepWhitespaceMode(bool Val) {
+ assert((!Val || LexingRawMode) &&
+ "Can only enable whitespace retention in raw mode");
+ ExtendedTokenMode = Val ? 2 : 0;
+ }
+
+ /// inKeepCommentMode - Return true if the lexer should return comments as
+ /// tokens.
+ bool inKeepCommentMode() const {
+ return ExtendedTokenMode > 0;
+ }
+
+ /// SetCommentRetentionMode - Change the comment retention mode of the lexer
+ /// to the specified mode. This is really only useful when lexing in raw
+ /// mode, because otherwise the lexer needs to manage this.
+ void SetCommentRetentionState(bool Mode) {
+ assert(!isKeepWhitespaceMode() &&
+ "Can't play with comment retention state when retaining whitespace");
+ ExtendedTokenMode = Mode ? 1 : 0;
+ }
+
+ const char *getBufferStart() const { return BufferStart; }
+
+ /// ReadToEndOfLine - Read the rest of the current preprocessor line as an
+ /// uninterpreted string. This switches the lexer out of directive mode.
+ std::string ReadToEndOfLine();
+
+
+ /// Diag - Forwarding function for diagnostics. This translate a source
+ /// position in the current buffer into a SourceLocation object for rendering.
+ DiagnosticBuilder Diag(const char *Loc, unsigned DiagID) const;
+
+ /// getSourceLocation - Return a source location identifier for the specified
+ /// offset in the current file.
+ SourceLocation getSourceLocation(const char *Loc, unsigned TokLen = 1) const;
+
+ /// getSourceLocation - Return a source location for the next character in
+ /// the current file.
+ SourceLocation getSourceLocation() { return getSourceLocation(BufferPtr); }
+
+ /// Stringify - Convert the specified string into a C string by escaping '\'
+ /// and " characters. This does not add surrounding ""'s to the string.
+ /// If Charify is true, this escapes the ' character instead of ".
+ static std::string Stringify(const std::string &Str, bool Charify = false);
+
+ /// 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);
+
+ /// MeasureTokenLength - Relex the token at the specified location and return
+ /// its length in bytes in the input file. If the token needs cleaning (e.g.
+ /// includes a trigraph or an escaped newline) then this count includes bytes
+ /// that are part of that.
+ static unsigned MeasureTokenLength(SourceLocation Loc,
+ const SourceManager &SM,
+ const LangOptions &LangOpts);
+
+ //===--------------------------------------------------------------------===//
+ // Internal implementation interfaces.
+private:
+
+ /// LexTokenInternal - Internal interface to lex a preprocessing token. Called
+ /// by Lex.
+ ///
+ void LexTokenInternal(Token &Result);
+
+ /// FormTokenWithChars - When we lex a token, we have identified a span
+ /// starting at BufferPtr, going to TokEnd that forms the token. This method
+ /// takes that range and assigns it to the token as its location and size. In
+ /// addition, since tokens cannot overlap, this also updates BufferPtr to be
+ /// TokEnd.
+ void FormTokenWithChars(Token &Result, const char *TokEnd,
+ tok::TokenKind Kind) {
+ unsigned TokLen = TokEnd-BufferPtr;
+ Result.setLength(TokLen);
+ Result.setLocation(getSourceLocation(BufferPtr, TokLen));
+ Result.setKind(Kind);
+ BufferPtr = TokEnd;
+ }
+
+ /// isNextPPTokenLParen - Return 1 if the next unexpanded token will return a
+ /// tok::l_paren token, 0 if it is something else and 2 if there are no more
+ /// tokens in the buffer controlled by this lexer.
+ unsigned isNextPPTokenLParen();
+
+ //===--------------------------------------------------------------------===//
+ // Lexer character reading interfaces.
+public:
+
+ // This lexer is built on two interfaces for reading characters, both of which
+ // automatically provide phase 1/2 translation. getAndAdvanceChar is used
+ // when we know that we will be reading a character from the input buffer and
+ // that this character will be part of the result token. This occurs in (f.e.)
+ // string processing, because we know we need to read until we find the
+ // closing '"' character.
+ //
+ // The second interface is the combination of PeekCharAndSize with
+ // ConsumeChar. PeekCharAndSize reads a phase 1/2 translated character,
+ // returning it and its size. If the lexer decides that this character is
+ // part of the current token, it calls ConsumeChar on it. This two stage
+ // approach allows us to emit diagnostics for characters (e.g. warnings about
+ // trigraphs), knowing that they only are emitted if the character is
+ // consumed.
+
+ /// isObviouslySimpleCharacter - Return true if the specified character is
+ /// obviously the same in translation phase 1 and translation phase 3. This
+ /// can return false for characters that end up being the same, but it will
+ /// never return true for something that needs to be mapped.
+ static bool isObviouslySimpleCharacter(char C) {
+ return C != '?' && C != '\\';
+ }
+
+ /// getAndAdvanceChar - Read a single 'character' from the specified buffer,
+ /// advance over it, and return it. This is tricky in several cases. Here we
+ /// just handle the trivial case and fall-back to the non-inlined
+ /// getCharAndSizeSlow method to handle the hard case.
+ inline char getAndAdvanceChar(const char *&Ptr, Token &Tok) {
+ // If this is not a trigraph and not a UCN or escaped newline, return
+ // quickly.
+ if (isObviouslySimpleCharacter(Ptr[0])) return *Ptr++;
+
+ unsigned Size = 0;
+ char C = getCharAndSizeSlow(Ptr, Size, &Tok);
+ Ptr += Size;
+ return C;
+ }
+
+private:
+ /// ConsumeChar - When a character (identified by PeekCharAndSize) is consumed
+ /// and added to a given token, check to see if there are diagnostics that
+ /// need to be emitted or flags that need to be set on the token. If so, do
+ /// it.
+ const char *ConsumeChar(const char *Ptr, unsigned Size, Token &Tok) {
+ // Normal case, we consumed exactly one token. Just return it.
+ if (Size == 1)
+ return Ptr+Size;
+
+ // Otherwise, re-lex the character with a current token, allowing
+ // diagnostics to be emitted and flags to be set.
+ Size = 0;
+ getCharAndSizeSlow(Ptr, Size, &Tok);
+ return Ptr+Size;
+ }
+
+ /// getCharAndSize - Peek a single 'character' from the specified buffer,
+ /// get its size, and return it. This is tricky in several cases. Here we
+ /// just handle the trivial case and fall-back to the non-inlined
+ /// getCharAndSizeSlow method to handle the hard case.
+ inline char getCharAndSize(const char *Ptr, unsigned &Size) {
+ // If this is not a trigraph and not a UCN or escaped newline, return
+ // quickly.
+ if (isObviouslySimpleCharacter(Ptr[0])) {
+ Size = 1;
+ return *Ptr;
+ }
+
+ Size = 0;
+ return getCharAndSizeSlow(Ptr, Size);
+ }
+
+ /// getCharAndSizeSlow - Handle the slow/uncommon case of the getCharAndSize
+ /// method.
+ char getCharAndSizeSlow(const char *Ptr, unsigned &Size, Token *Tok = 0);
+public:
+
+ /// getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever
+ /// emit a warning.
+ static inline char getCharAndSizeNoWarn(const char *Ptr, unsigned &Size,
+ const LangOptions &Features) {
+ // If this is not a trigraph and not a UCN or escaped newline, return
+ // quickly.
+ if (isObviouslySimpleCharacter(Ptr[0])) {
+ Size = 1;
+ return *Ptr;
+ }
+
+ Size = 0;
+ return getCharAndSizeSlowNoWarn(Ptr, Size, Features);
+ }
+
+ /// getEscapedNewLineSize - Return the size of the specified escaped newline,
+ /// or 0 if it is not an escaped newline. P[-1] is known to be a "\" on entry
+ /// to this function.
+ static unsigned getEscapedNewLineSize(const char *P);
+
+ /// SkipEscapedNewLines - If P points to an escaped newline (or a series of
+ /// them), skip over them and return the first non-escaped-newline found,
+ /// otherwise return P.
+ static const char *SkipEscapedNewLines(const char *P);
+private:
+
+ /// getCharAndSizeSlowNoWarn - Same as getCharAndSizeSlow, but never emits a
+ /// diagnostic.
+ static char getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size,
+ const LangOptions &Features);
+
+ //===--------------------------------------------------------------------===//
+ // Other lexer functions.
+
+ // 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 LexAngledStringLiteral(Token &Result, const char *CurPtr);
+ void LexCharConstant (Token &Result, const char *CurPtr);
+ bool LexEndOfFile (Token &Result, const char *CurPtr);
+
+ bool SkipWhitespace (Token &Result, const char *CurPtr);
+ bool SkipBCPLComment (Token &Result, const char *CurPtr);
+ bool SkipBlockComment (Token &Result, const char *CurPtr);
+ bool SaveBCPLComment (Token &Result, const char *CurPtr);
+};
+
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
new file mode 100644
index 000000000000..8ee8ecf7359f
--- /dev/null
+++ b/include/clang/Lex/LiteralSupport.h
@@ -0,0 +1,176 @@
+//===--- LiteralSupport.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the NumericLiteralParser, CharLiteralParser, and
+// StringLiteralParser interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_LITERALSUPPORT_H
+#define CLANG_LITERALSUPPORT_H
+
+#include <string>
+#include "llvm/ADT/SmallString.h"
+
+namespace llvm {
+ class APInt;
+ class APFloat;
+ struct fltSemantics;
+}
+
+namespace clang {
+
+class Diagnostic;
+class Preprocessor;
+class Token;
+class SourceLocation;
+class TargetInfo;
+
+/// NumericLiteralParser - This performs strict semantic analysis of the content
+/// of a ppnumber, classifying it as either integer, floating, or erroneous,
+/// determines the radix of the value and can convert it to a useful value.
+class NumericLiteralParser {
+ Preprocessor &PP; // needed for diagnostics
+
+ const char *const ThisTokBegin;
+ const char *const ThisTokEnd;
+ const char *DigitsBegin, *SuffixBegin; // markers
+ const char *s; // cursor
+
+ unsigned radix;
+
+ bool saw_exponent, saw_period;
+
+public:
+ NumericLiteralParser(const char *begin, const char *end,
+ SourceLocation Loc, Preprocessor &PP);
+ bool hadError;
+ bool isUnsigned;
+ bool isLong; // This is *not* set for long long.
+ bool isLongLong;
+ bool isFloat; // 1.0f
+ bool isImaginary; // 1.0i
+
+ bool isIntegerLiteral() const {
+ return !saw_period && !saw_exponent;
+ }
+ bool isFloatingLiteral() const {
+ return saw_period || saw_exponent;
+ }
+ bool hasSuffix() const {
+ return SuffixBegin != ThisTokEnd;
+ }
+
+ unsigned getRadix() const { return radix; }
+
+ /// GetIntegerValue - Convert this numeric literal value to an APInt that
+ /// matches Val's input width. If there is an overflow (i.e., if the unsigned
+ /// value read is larger than the APInt's bits will hold), set Val to the low
+ /// bits of the result and return true. Otherwise, return false.
+ bool GetIntegerValue(llvm::APInt &Val);
+
+ /// GetFloatValue - Convert this numeric literal to a floating value, using
+ /// the specified APFloat fltSemantics (specifying float, double, etc).
+ /// The optional bool isExact (passed-by-reference) has its value
+ /// set to true if the returned APFloat can represent the number in the
+ /// literal exactly, and false otherwise.
+ llvm::APFloat GetFloatValue(const llvm::fltSemantics &Format,
+ bool* isExact = NULL);
+
+private:
+
+ void ParseNumberStartingWithZero(SourceLocation TokLoc);
+
+ /// SkipHexDigits - Read and skip over any hex digits, up to End.
+ /// Return a pointer to the first non-hex digit or End.
+ const char *SkipHexDigits(const char *ptr) {
+ while (ptr != ThisTokEnd && isxdigit(*ptr))
+ ptr++;
+ return ptr;
+ }
+
+ /// SkipOctalDigits - Read and skip over any octal digits, up to End.
+ /// Return a pointer to the first non-hex digit or End.
+ const char *SkipOctalDigits(const char *ptr) {
+ while (ptr != ThisTokEnd && ((*ptr >= '0') && (*ptr <= '7')))
+ ptr++;
+ return ptr;
+ }
+
+ /// SkipDigits - Read and skip over any digits, up to End.
+ /// Return a pointer to the first non-hex digit or End.
+ const char *SkipDigits(const char *ptr) {
+ while (ptr != ThisTokEnd && isdigit(*ptr))
+ ptr++;
+ return ptr;
+ }
+
+ /// SkipBinaryDigits - Read and skip over any binary digits, up to End.
+ /// Return a pointer to the first non-binary digit or End.
+ const char *SkipBinaryDigits(const char *ptr) {
+ while (ptr != ThisTokEnd && (*ptr == '0' || *ptr == '1'))
+ ptr++;
+ return ptr;
+ }
+
+};
+
+/// CharLiteralParser - Perform interpretation and semantic analysis of a
+/// character literal.
+class CharLiteralParser {
+ uint64_t Value;
+ bool IsWide;
+ bool IsMultiChar;
+ bool HadError;
+public:
+ CharLiteralParser(const char *begin, const char *end,
+ SourceLocation Loc, Preprocessor &PP);
+
+ bool hadError() const { return HadError; }
+ bool isWide() const { return IsWide; }
+ bool isMultiChar() const { return IsMultiChar; }
+ uint64_t getValue() const { return Value; }
+};
+
+/// StringLiteralParser - This decodes string escape characters and performs
+/// wide string analysis and Translation Phase #6 (concatenation of string
+/// literals) (C99 5.1.1.2p1).
+class StringLiteralParser {
+ Preprocessor &PP;
+
+ unsigned MaxTokenLength;
+ unsigned SizeBound;
+ unsigned wchar_tByteWidth;
+ llvm::SmallString<512> ResultBuf;
+ char *ResultPtr; // cursor
+public:
+ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
+ Preprocessor &PP);
+ bool hadError;
+ bool AnyWide;
+ bool Pascal;
+
+ const char *GetString() { return &ResultBuf[0]; }
+ unsigned GetStringLength() const { return ResultPtr-&ResultBuf[0]; }
+
+ unsigned GetNumStringChars() const {
+ if (AnyWide)
+ return GetStringLength() / wchar_tByteWidth;
+ return GetStringLength();
+ }
+ /// 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.
+ static unsigned getOffsetOfStringByte(const Token &TheTok, unsigned ByteNo,
+ Preprocessor &PP);
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h
new file mode 100644
index 000000000000..ccd13c80d354
--- /dev/null
+++ b/include/clang/Lex/MacroInfo.h
@@ -0,0 +1,218 @@
+//===--- MacroInfo.h - Information about #defined identifiers ---*- 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 MacroInfo interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_MACROINFO_H
+#define LLVM_CLANG_MACROINFO_H
+
+#include "clang/Lex/Token.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Allocator.h"
+#include <vector>
+#include <cassert>
+
+namespace clang {
+ class Preprocessor;
+
+/// MacroInfo - Each identifier that is #define'd has an instance of this class
+/// associated with it, used to implement macro expansion.
+class MacroInfo {
+ //===--------------------------------------------------------------------===//
+ // State set when the macro is defined.
+
+ /// Location - This is the place the macro is defined.
+ SourceLocation Location;
+ /// EndLocation - The location of the last token in the macro.
+ SourceLocation EndLocation;
+
+ /// Arguments - The list of arguments for a function-like macro. This can be
+ /// empty, for, e.g. "#define X()". In a C99-style variadic macro, this
+ /// includes the __VA_ARGS__ identifier on the list.
+ IdentifierInfo **ArgumentList;
+ unsigned NumArguments;
+
+ /// ReplacementTokens - This is the list of tokens that the macro is defined
+ /// to.
+ llvm::SmallVector<Token, 8> ReplacementTokens;
+
+ /// IsFunctionLike - True if this macro is a function-like macro, false if it
+ /// is an object-like macro.
+ bool IsFunctionLike : 1;
+
+ /// IsC99Varargs - True if this macro is of the form "#define X(...)" or
+ /// "#define X(Y,Z,...)". The __VA_ARGS__ token should be replaced with the
+ /// contents of "..." in an invocation.
+ bool IsC99Varargs : 1;
+
+ /// IsGNUVarargs - True if this macro is of the form "#define X(a...)". The
+ /// "a" identifier in the replacement list will be replaced with all arguments
+ /// of the macro starting with the specified one.
+ bool IsGNUVarargs : 1;
+
+ /// IsBuiltinMacro - True if this is a builtin macro, such as __LINE__, and if
+ /// it has not yet been redefined or undefined.
+ bool IsBuiltinMacro : 1;
+
+private:
+ //===--------------------------------------------------------------------===//
+ // State that changes as the macro is used.
+
+ /// IsDisabled - True if we have started an expansion of this macro already.
+ /// This disbles recursive expansion, which would be quite bad for things like
+ /// #define A A.
+ bool IsDisabled : 1;
+
+ /// IsUsed - True if this macro is either defined in the main file and has
+ /// been used, or if it is not defined in the main file. This is used to
+ /// emit -Wunused-macros diagnostics.
+ bool IsUsed : 1;
+
+ ~MacroInfo() {
+ assert(ArgumentList == 0 && "Didn't call destroy before dtor!");
+ }
+
+public:
+ MacroInfo(SourceLocation DefLoc);
+
+ /// FreeArgumentList - Free the argument list of the macro, restoring it to a
+ /// state where it can be reused for other devious purposes.
+ void FreeArgumentList(llvm::BumpPtrAllocator &PPAllocator) {
+ PPAllocator.Deallocate(ArgumentList);
+ ArgumentList = 0;
+ NumArguments = 0;
+ }
+
+ /// Destroy - destroy this MacroInfo object.
+ void Destroy(llvm::BumpPtrAllocator &PPAllocator) {
+ FreeArgumentList(PPAllocator);
+ this->~MacroInfo();
+ }
+
+ /// getDefinitionLoc - Return the location that the macro was defined at.
+ ///
+ SourceLocation getDefinitionLoc() const { return Location; }
+
+ /// setDefinitionEndLoc - Set the location of the last token in the macro.
+ ///
+ void setDefinitionEndLoc(SourceLocation EndLoc) { EndLocation = EndLoc; }
+ /// getDefinitionEndLoc - Return the location of the last token in the macro.
+ ///
+ SourceLocation getDefinitionEndLoc() const { return EndLocation; }
+
+ /// isIdenticalTo - Return true if the specified macro definition is equal to
+ /// this macro in spelling, arguments, and whitespace. This is used to emit
+ /// duplicate definition warnings. This implements the rules in C99 6.10.3.
+ bool isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const;
+
+ /// setIsBuiltinMacro - Set or clear the isBuiltinMacro flag.
+ ///
+ void setIsBuiltinMacro(bool Val = true) {
+ IsBuiltinMacro = Val;
+ }
+
+ /// setIsUsed - Set the value of the IsUsed flag.
+ ///
+ void setIsUsed(bool Val) {
+ IsUsed = Val;
+ }
+
+ /// setArgumentList - Set the specified list of identifiers as the argument
+ /// list for this macro.
+ void setArgumentList(IdentifierInfo* const *List, unsigned NumArgs,
+ llvm::BumpPtrAllocator &PPAllocator) {
+ assert(ArgumentList == 0 && NumArguments == 0 &&
+ "Argument list already set!");
+ if (NumArgs == 0) return;
+
+ NumArguments = NumArgs;
+ ArgumentList = PPAllocator.Allocate<IdentifierInfo*>(NumArgs);
+ for (unsigned i = 0; i != NumArgs; ++i)
+ ArgumentList[i] = List[i];
+ }
+
+ /// Arguments - The list of arguments for a function-like macro. This can be
+ /// empty, for, e.g. "#define X()".
+ typedef IdentifierInfo* const *arg_iterator;
+ bool arg_empty() const { return NumArguments == 0; }
+ arg_iterator arg_begin() const { return ArgumentList; }
+ arg_iterator arg_end() const { return ArgumentList+NumArguments; }
+ unsigned getNumArgs() const { return NumArguments; }
+
+ /// getArgumentNum - Return the argument number of the specified identifier,
+ /// or -1 if the identifier is not a formal argument identifier.
+ int getArgumentNum(IdentifierInfo *Arg) const {
+ for (arg_iterator I = arg_begin(), E = arg_end(); I != E; ++I)
+ if (*I == Arg) return I-arg_begin();
+ return -1;
+ }
+
+ /// Function/Object-likeness. Keep track of whether this macro has formal
+ /// parameters.
+ void setIsFunctionLike() { IsFunctionLike = true; }
+ bool isFunctionLike() const { return IsFunctionLike; }
+ bool isObjectLike() const { return !IsFunctionLike; }
+
+ /// Varargs querying methods. This can only be set for function-like macros.
+ void setIsC99Varargs() { IsC99Varargs = true; }
+ void setIsGNUVarargs() { IsGNUVarargs = true; }
+ bool isC99Varargs() const { return IsC99Varargs; }
+ bool isGNUVarargs() const { return IsGNUVarargs; }
+ bool isVariadic() const { return IsC99Varargs | IsGNUVarargs; }
+
+ /// isBuiltinMacro - Return true if this macro is a builtin macro, such as
+ /// __LINE__, which requires processing before expansion.
+ bool isBuiltinMacro() const { return IsBuiltinMacro; }
+
+ /// isUsed - Return false if this macro is defined in the main file and has
+ /// not yet been used.
+ bool isUsed() const { return IsUsed; }
+
+ /// getNumTokens - Return the number of tokens that this macro expands to.
+ ///
+ unsigned getNumTokens() const {
+ return ReplacementTokens.size();
+ }
+
+ const Token &getReplacementToken(unsigned Tok) const {
+ assert(Tok < ReplacementTokens.size() && "Invalid token #");
+ return ReplacementTokens[Tok];
+ }
+
+ typedef llvm::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(); }
+
+ /// AddTokenToBody - Add the specified token to the replacement text for the
+ /// macro.
+ void AddTokenToBody(const Token &Tok) {
+ ReplacementTokens.push_back(Tok);
+ }
+
+ /// isEnabled - Return true if this macro is enabled: in other words, that we
+ /// are not currently in an expansion of this macro.
+ bool isEnabled() const { return !IsDisabled; }
+
+ void EnableMacro() {
+ assert(IsDisabled && "Cannot enable an already-enabled macro!");
+ IsDisabled = false;
+ }
+
+ void DisableMacro() {
+ assert(!IsDisabled && "Cannot disable an already-disabled macro!");
+ IsDisabled = true;
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/MultipleIncludeOpt.h b/include/clang/Lex/MultipleIncludeOpt.h
new file mode 100644
index 000000000000..94d4677f9d29
--- /dev/null
+++ b/include/clang/Lex/MultipleIncludeOpt.h
@@ -0,0 +1,130 @@
+//===--- MultipleIncludeOpt.h - Header Multiple-Include Optzn ---*- 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 MultipleIncludeOpt interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_MULTIPLEINCLUDEOPT_H
+#define LLVM_CLANG_MULTIPLEINCLUDEOPT_H
+
+namespace clang {
+class IdentifierInfo;
+
+/// MultipleIncludeOpt - This class implements the simple state machine that the
+/// Lexer class uses to detect files subject to the 'multiple-include'
+/// optimization. The public methods in this class are triggered by various
+/// events that occur when a file is lexed, and after the entire file is lexed,
+/// information about which macro (if any) controls the header is returned.
+class MultipleIncludeOpt {
+ /// ReadAnyTokens - This is set to false when a file is first opened and true
+ /// any time a token is returned to the client or a (non-multiple-include)
+ /// directive is parsed. When the final #endif is parsed this is reset back
+ /// to false, that way any tokens before the first #ifdef or after the last
+ /// #endif can be easily detected.
+ bool ReadAnyTokens;
+
+ /// ReadAnyTokens - This is set to false when a file is first opened and true
+ /// any time a token is returned to the client or a (non-multiple-include)
+ /// directive is parsed. When the final #endif is parsed this is reset back
+ /// to false, that way any tokens before the first #ifdef or after the last
+ /// #endif can be easily detected.
+ bool DidMacroExpansion;
+
+ /// TheMacro - The controlling macro for a file, if valid.
+ ///
+ const IdentifierInfo *TheMacro;
+public:
+ MultipleIncludeOpt() {
+ ReadAnyTokens = false;
+ DidMacroExpansion = false;
+ TheMacro = 0;
+ }
+
+ /// Invalidate - Permenantly mark this file as not being suitable for the
+ /// include-file optimization.
+ void Invalidate() {
+ // If we have read tokens but have no controlling macro, the state-machine
+ // below can never "accept".
+ ReadAnyTokens = true;
+ TheMacro = 0;
+ }
+
+ /// getHasReadAnyTokensVal - This is used for the #ifndef hande-shake at the
+ /// top of the file when reading preprocessor directives. Otherwise, reading
+ /// the "ifndef x" would count as reading tokens.
+ bool getHasReadAnyTokensVal() const { return ReadAnyTokens; }
+
+ // If a token is read, remember that we have seen a side-effect in this file.
+ void ReadToken() { ReadAnyTokens = true; }
+
+ /// ExpandedMacro - When a macro is expanded with this lexer as the current
+ /// buffer, this method is called to disable the MIOpt if needed.
+ void ExpandedMacro() { DidMacroExpansion = true; }
+
+ /// EnterTopLevelIFNDEF - When entering a top-level #ifndef directive (or the
+ /// "#if !defined" equivalent) without any preceding tokens, this method is
+ /// called.
+ ///
+ /// Note, we don't care about the input value of 'ReadAnyTokens'. The caller
+ /// ensures that this is only called if there are no tokens read before the
+ /// #ifndef. The caller is required to do this, because reading the #if line
+ /// obviously reads in in tokens.
+ void EnterTopLevelIFNDEF(const IdentifierInfo *M) {
+ // If the macro is already set, this is after the top-level #endif.
+ if (TheMacro)
+ return Invalidate();
+
+ // If we have already expanded a macro by the end of the #ifndef line, then
+ // there is a macro expansion *in* the #ifndef line. This means that the
+ // condition could evaluate differently when subsequently #included. Reject
+ // this.
+ if (DidMacroExpansion)
+ return Invalidate();
+
+ // Remember that we're in the #if and that we have the macro.
+ ReadAnyTokens = true;
+ TheMacro = M;
+ }
+
+ /// EnterTopLevelConditional - This is invoked when a top level conditional
+ /// (except #ifndef) is found.
+ void EnterTopLevelConditional() {
+ /// If a conditional directive (except #ifndef) is found at the top level,
+ /// there is a chunk of the file not guarded by the controlling macro.
+ Invalidate();
+ }
+
+ /// ExitTopLevelConditional - This method is called when the lexer exits the
+ /// top-level conditional.
+ void ExitTopLevelConditional() {
+ // If we have a macro, that means the top of the file was ok. Set our state
+ // back to "not having read any tokens" so we can detect anything after the
+ // #endif.
+ if (!TheMacro) return Invalidate();
+
+ // At this point, we haven't "read any tokens" but we do have a controlling
+ // macro.
+ ReadAnyTokens = false;
+ }
+
+ /// GetControllingMacroAtEndOfFile - Once the entire file has been lexed, if
+ /// there is a controlling macro, return it.
+ const IdentifierInfo *GetControllingMacroAtEndOfFile() const {
+ // If we haven't read any tokens after the #endif, return the controlling
+ // macro if it's valid (if it isn't, it will be null).
+ if (!ReadAnyTokens)
+ return TheMacro;
+ return 0;
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
new file mode 100644
index 000000000000..e5cbeebd22aa
--- /dev/null
+++ b/include/clang/Lex/PPCallbacks.h
@@ -0,0 +1,122 @@
+//===--- PPCallbacks.h - Callbacks for Preprocessor actions -----*- 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 PPCallbacks interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LEX_PPCALLBACKS_H
+#define LLVM_CLANG_LEX_PPCALLBACKS_H
+
+#include "clang/Lex/DirectoryLookup.h"
+#include "clang/Basic/SourceLocation.h"
+#include <string>
+
+namespace clang {
+ class SourceLocation;
+ class Token;
+ class IdentifierInfo;
+ class MacroInfo;
+
+/// PPCallbacks - This interface provides a way to observe the actions of the
+/// preprocessor as it does its thing. Clients can define their hooks here to
+/// implement preprocessor level tools.
+class PPCallbacks {
+public:
+ virtual ~PPCallbacks();
+
+ enum FileChangeReason {
+ EnterFile, ExitFile, SystemHeaderPragma, RenameFile
+ };
+
+ /// FileChanged - This callback is invoked whenever a source file is
+ /// entered or exited. The SourceLocation indicates the new location, and
+ /// 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).
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType) {
+ }
+
+ /// Ident - This callback is invoked when a #ident or #sccs directive is read.
+ ///
+ virtual void Ident(SourceLocation Loc, const std::string &str) {
+ }
+
+ /// PragmaComment - This callback is invoked when a #pragma comment directive
+ /// is read.
+ ///
+ virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
+ const std::string &Str) {
+ }
+
+ /// MacroExpands - This is called by
+ /// Preprocessor::HandleMacroExpandedIdentifier when a macro invocation is
+ /// found.
+ virtual void MacroExpands(const Token &Id, const MacroInfo* MI) {
+ }
+
+ /// MacroDefined - This hook is called whenever a macro definition is seen.
+ virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI) {
+ }
+
+ /// MacroUndefined - This hook is called whenever a macro #undef is seen.
+ /// MI is released immediately following this callback.
+ virtual void MacroUndefined(const IdentifierInfo *II, const MacroInfo *MI) {
+ }
+};
+
+/// PPChainedCallbacks - Simple wrapper class for chaining callbacks.
+class PPChainedCallbacks : public PPCallbacks {
+ PPCallbacks *First, *Second;
+
+public:
+ PPChainedCallbacks(PPCallbacks *_First, PPCallbacks *_Second)
+ : First(_First), Second(_Second) {}
+ ~PPChainedCallbacks() {
+ delete Second;
+ delete First;
+ }
+
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType) {
+ First->FileChanged(Loc, Reason, FileType);
+ Second->FileChanged(Loc, Reason, FileType);
+ }
+
+ virtual void Ident(SourceLocation Loc, const std::string &str) {
+ First->Ident(Loc, str);
+ Second->Ident(Loc, str);
+ }
+
+ virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
+ const std::string &Str) {
+ First->PragmaComment(Loc, Kind, Str);
+ Second->PragmaComment(Loc, Kind, Str);
+ }
+
+ virtual void MacroExpands(const Token &Id, const MacroInfo* MI) {
+ First->MacroExpands(Id, MI);
+ Second->MacroExpands(Id, MI);
+ }
+
+ virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI) {
+ First->MacroDefined(II, MI);
+ Second->MacroDefined(II, MI);
+ }
+
+ virtual void MacroUndefined(const IdentifierInfo *II, const MacroInfo *MI) {
+ First->MacroUndefined(II, MI);
+ Second->MacroUndefined(II, MI);
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/PTHLexer.h b/include/clang/Lex/PTHLexer.h
new file mode 100644
index 000000000000..369b818a1fc9
--- /dev/null
+++ b/include/clang/Lex/PTHLexer.h
@@ -0,0 +1,104 @@
+//===--- PTHLexer.h - Lexer based on Pre-tokenized input --------*- 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 PTHLexer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PTHLEXER_H
+#define LLVM_CLANG_PTHLEXER_H
+
+#include "clang/Lex/PreprocessorLexer.h"
+#include <vector>
+
+namespace clang {
+
+class PTHManager;
+class PTHSpellingSearch;
+
+class PTHLexer : public PreprocessorLexer {
+ SourceLocation FileStartLoc;
+
+ /// TokBuf - Buffer from PTH file containing raw token data.
+ const unsigned char* TokBuf;
+
+ /// CurPtr - Pointer into current offset of the token buffer where
+ /// the next token will be read.
+ const unsigned char* CurPtr;
+
+ /// LastHashTokPtr - Pointer into TokBuf of the last processed '#'
+ /// token that appears at the start of a line.
+ const unsigned char* LastHashTokPtr;
+
+ /// PPCond - Pointer to a side table in the PTH file that provides a
+ /// a consise summary of the preproccessor conditional block structure.
+ /// This is used to perform quick skipping of conditional blocks.
+ const unsigned char* PPCond;
+
+ /// CurPPCondPtr - Pointer inside PPCond that refers to the next entry
+ /// to process when doing quick skipping of preprocessor blocks.
+ const unsigned char* CurPPCondPtr;
+
+ PTHLexer(const PTHLexer&); // DO NOT IMPLEMENT
+ void operator=(const PTHLexer&); // DO NOT IMPLEMENT
+
+ /// ReadToken - Used by PTHLexer to read tokens TokBuf.
+ void ReadToken(Token& T);
+
+ /// PTHMgr - The PTHManager object that created this PTHLexer.
+ PTHManager& PTHMgr;
+
+ Token EofToken;
+
+protected:
+ friend class PTHManager;
+
+ /// Create a PTHLexer for the specified token stream.
+ PTHLexer(Preprocessor& pp, FileID FID, const unsigned char *D,
+ const unsigned char* ppcond, PTHManager &PM);
+public:
+
+ ~PTHLexer() {}
+
+ /// Lex - Return the next token.
+ void Lex(Token &Tok);
+
+ void getEOF(Token &Tok);
+
+ /// DiscardToEndOfLine - Read the rest of the current preprocessor line as an
+ /// uninterpreted string. This switches the lexer out of directive mode.
+ void DiscardToEndOfLine();
+
+ /// isNextPPTokenLParen - Return 1 if the next unexpanded token will return a
+ /// tok::l_paren token, 0 if it is something else and 2 if there are no more
+ /// tokens controlled by this lexer.
+ unsigned isNextPPTokenLParen() {
+ // isNextPPTokenLParen is not on the hot path, and all we care about is
+ // whether or not we are at a token with kind tok::eof or tok::l_paren.
+ // Just read the first byte from the current token pointer to determine
+ // its kind.
+ tok::TokenKind x = (tok::TokenKind)*CurPtr;
+ return x == tok::eof ? 2 : x == tok::l_paren;
+ }
+
+ /// IndirectLex - An indirect call to 'Lex' that can be invoked via
+ /// the PreprocessorLexer interface.
+ void IndirectLex(Token &Result) { Lex(Result); }
+
+ /// getSourceLocation - Return a source location for the token in
+ /// the current file.
+ SourceLocation getSourceLocation();
+
+ /// SkipBlock - Used by Preprocessor to skip the current conditional block.
+ bool SkipBlock();
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/PTHManager.h b/include/clang/Lex/PTHManager.h
new file mode 100644
index 000000000000..507576473f60
--- /dev/null
+++ b/include/clang/Lex/PTHManager.h
@@ -0,0 +1,141 @@
+//===--- PTHManager.h - Manager object for PTH processing -------*- 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 PTHManager interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PTHMANAGER_H
+#define LLVM_CLANG_PTHMANAGER_H
+
+#include "clang/Lex/PTHLexer.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/Allocator.h"
+#include <string>
+
+namespace llvm {
+ class MemoryBuffer;
+}
+
+namespace clang {
+
+class FileEntry;
+class PTHLexer;
+class Diagnostic;
+class StatSysCallCache;
+
+class PTHManager : public IdentifierInfoLookup {
+ friend class PTHLexer;
+
+ /// The memory mapped PTH file.
+ const llvm::MemoryBuffer* Buf;
+
+ /// Alloc - Allocator used for IdentifierInfo objects.
+ llvm::BumpPtrAllocator Alloc;
+
+ /// IdMap - A lazily generated cache mapping from persistent identifiers to
+ /// IdentifierInfo*.
+ IdentifierInfo** PerIDCache;
+
+ /// FileLookup - Abstract data structure used for mapping between files
+ /// and token data in the PTH file.
+ void* FileLookup;
+
+ /// IdDataTable - Array representing the mapping from persistent IDs to the
+ /// data offset within the PTH file containing the information to
+ /// reconsitute an IdentifierInfo.
+ const unsigned char* const IdDataTable;
+
+ /// SortedIdTable - Abstract data structure mapping from strings to
+ /// persistent IDs. This is used by get().
+ void* StringIdLookup;
+
+ /// NumIds - The number of identifiers in the PTH file.
+ const unsigned NumIds;
+
+ /// PP - The Preprocessor object that will use this PTHManager to create
+ /// PTHLexer objects.
+ Preprocessor* PP;
+
+ /// SpellingBase - The base offset within the PTH memory buffer that
+ /// contains the cached spellings for literals.
+ const unsigned char* const SpellingBase;
+
+ /// OriginalSourceFile - A null-terminated C-string that specifies the name
+ /// if the file (if any) that was to used to generate the PTH cache.
+ const char* OriginalSourceFile;
+
+ /// This constructor is intended to only be called by the static 'Create'
+ /// method.
+ PTHManager(const llvm::MemoryBuffer* buf, void* fileLookup,
+ const unsigned char* idDataTable, IdentifierInfo** perIDCache,
+ void* stringIdLookup, unsigned numIds,
+ const unsigned char* spellingBase, const char *originalSourceFile);
+
+ // Do not implement.
+ PTHManager();
+ void operator=(const PTHManager&);
+
+ /// getSpellingAtPTHOffset - Used by PTHLexer classes to get the cached
+ /// spelling for a token.
+ unsigned getSpellingAtPTHOffset(unsigned PTHOffset, const char*& Buffer);
+
+ /// GetIdentifierInfo - Used to reconstruct IdentifierInfo objects from the
+ /// PTH file.
+ inline IdentifierInfo* GetIdentifierInfo(unsigned PersistentID) {
+ // Check if the IdentifierInfo has already been resolved.
+ if (IdentifierInfo* II = PerIDCache[PersistentID])
+ return II;
+ return LazilyCreateIdentifierInfo(PersistentID);
+ }
+ IdentifierInfo* LazilyCreateIdentifierInfo(unsigned PersistentID);
+
+public:
+ // The current PTH version.
+ enum { Version = 9 };
+
+ ~PTHManager();
+
+ /// getOriginalSourceFile - Return the full path to the original header
+ /// file name that was used to generate the PTH cache.
+ const char* getOriginalSourceFile() const {
+ return OriginalSourceFile;
+ }
+
+ /// get - Return the identifier token info for the specified named identifier.
+ /// Unlike the version in IdentifierTable, this returns a pointer instead
+ /// of a reference. If the pointer is NULL then the IdentifierInfo cannot
+ /// be found.
+ IdentifierInfo *get(const char *NameStart, const char *NameEnd);
+
+ /// 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 = 0,
+ Diagnostic::Level failureLevel=Diagnostic::Warning);
+
+ void setPreprocessor(Preprocessor *pp) { PP = pp; }
+
+ /// CreateLexer - Return a PTHLexer that "lexes" the cached tokens for the
+ /// specified file. This method returns NULL if no cached tokens exist.
+ /// It is the responsibility of the caller to 'delete' the returned object.
+ PTHLexer *CreateLexer(FileID FID);
+
+ /// createStatCache - Returns a StatSysCallCache object for use with
+ /// FileManager objects. These objects use the PTH data to speed up
+ /// calls to stat by memoizing their results from when the PTH file
+ /// was generated.
+ StatSysCallCache *createStatCache();
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/Pragma.h b/include/clang/Lex/Pragma.h
new file mode 100644
index 000000000000..136dc6fabfb6
--- /dev/null
+++ b/include/clang/Lex/Pragma.h
@@ -0,0 +1,90 @@
+//===--- Pragma.h - Pragma registration and handling ------------*- 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 PragmaHandler and PragmaTable interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PRAGMA_H
+#define LLVM_CLANG_PRAGMA_H
+
+#include <cassert>
+#include <vector>
+
+namespace clang {
+ class Preprocessor;
+ class Token;
+ class IdentifierInfo;
+ class PragmaNamespace;
+
+/// PragmaHandler - Instances of this interface defined to handle the various
+/// pragmas that the language front-end uses. Each handler optionally has a
+/// name (e.g. "pack") and the HandlePragma method is invoked when a pragma with
+/// that identifier is found. If a handler does not match any of the declared
+/// pragmas the handler with a null identifier is invoked, if it exists.
+///
+/// Note that the PragmaNamespace class can be used to subdivide pragmas, e.g.
+/// we treat "#pragma STDC" and "#pragma GCC" as namespaces that contain other
+/// pragmas.
+class PragmaHandler {
+ const IdentifierInfo *Name;
+public:
+ PragmaHandler(const IdentifierInfo *name) : Name(name) {}
+ virtual ~PragmaHandler();
+
+ const IdentifierInfo *getName() const { return Name; }
+ virtual void HandlePragma(Preprocessor &PP, Token &FirstToken) = 0;
+
+ /// getIfNamespace - If this is a namespace, return it. This is equivalent to
+ /// using a dynamic_cast, but doesn't require RTTI.
+ virtual PragmaNamespace *getIfNamespace() { return 0; }
+};
+
+/// PragmaNamespace - This PragmaHandler subdivides the namespace of pragmas,
+/// allowing hierarchical pragmas to be defined. Common examples of namespaces
+/// are "#pragma GCC", "#pragma STDC", and "#pragma omp", but any namespaces may
+/// be (potentially recursively) defined.
+class PragmaNamespace : public PragmaHandler {
+ /// Handlers - This is the list of handlers in this namespace.
+ ///
+ std::vector<PragmaHandler*> Handlers;
+public:
+ PragmaNamespace(const IdentifierInfo *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 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 *FindHandler(const IdentifierInfo *Name,
+ bool IgnoreNull = true) const;
+
+ /// AddPragma - Add a pragma to this namespace.
+ ///
+ void AddPragma(PragmaHandler *Handler) {
+ Handlers.push_back(Handler);
+ }
+
+ /// RemovePragmaHandler - Remove the given handler from the
+ /// namespace.
+ void RemovePragmaHandler(PragmaHandler *Handler);
+
+ bool IsEmpty() {
+ return Handlers.empty();
+ }
+
+ virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);
+
+ virtual PragmaNamespace *getIfNamespace() { return this; }
+};
+
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
new file mode 100644
index 000000000000..5b9959c32a2d
--- /dev/null
+++ b/include/clang/Lex/Preprocessor.h
@@ -0,0 +1,801 @@
+//===--- Preprocessor.h - C Language Family Preprocessor --------*- 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 Preprocessor interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LEX_PREPROCESSOR_H
+#define LLVM_CLANG_LEX_PREPROCESSOR_H
+
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/PTHLexer.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/TokenLexer.h"
+#include "clang/Lex/PTHManager.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/Allocator.h"
+
+namespace clang {
+
+class SourceManager;
+class FileManager;
+class FileEntry;
+class HeaderSearch;
+class PragmaNamespace;
+class PragmaHandler;
+class ScratchBuffer;
+class TargetInfo;
+class PPCallbacks;
+class DirectoryLookup;
+
+/// Preprocessor - This object engages in a tight little dance with the lexer to
+/// efficiently preprocess tokens. Lexers know only about tokens within a
+/// single source file, and don't know anything about preprocessor-level issues
+/// like the #include stack, token expansion, etc.
+///
+class Preprocessor {
+ Diagnostic *Diags;
+ const LangOptions &Features;
+ TargetInfo &Target;
+ FileManager &FileMgr;
+ SourceManager &SourceMgr;
+ ScratchBuffer *ScratchBuf;
+ HeaderSearch &HeaderInfo;
+
+ /// PTH - An optional PTHManager object used for getting tokens from
+ /// a token cache rather than lexing the original source file.
+ llvm::OwningPtr<PTHManager> PTH;
+
+ /// BP - A BumpPtrAllocator object used to quickly allocate and release
+ /// objects internal to the Preprocessor.
+ llvm::BumpPtrAllocator BP;
+
+ /// Identifiers for builtin macros and other builtins.
+ IdentifierInfo *Ident__LINE__, *Ident__FILE__; // __LINE__, __FILE__
+ IdentifierInfo *Ident__DATE__, *Ident__TIME__; // __DATE__, __TIME__
+ IdentifierInfo *Ident__INCLUDE_LEVEL__; // __INCLUDE_LEVEL__
+ IdentifierInfo *Ident__BASE_FILE__; // __BASE_FILE__
+ IdentifierInfo *Ident__TIMESTAMP__; // __TIMESTAMP__
+ IdentifierInfo *Ident__COUNTER__; // __COUNTER__
+ IdentifierInfo *Ident_Pragma, *Ident__VA_ARGS__; // _Pragma, __VA_ARGS__
+
+ SourceLocation DATELoc, TIMELoc;
+ unsigned CounterValue; // Next __COUNTER__ value.
+
+ enum {
+ /// MaxIncludeStackDepth - Maximum depth of #includes.
+ MaxAllowedIncludeStackDepth = 200
+ };
+
+ // State that is set before the preprocessor begins.
+ bool KeepComments : 1;
+ bool KeepMacroComments : 1;
+
+ // State that changes while the preprocessor runs:
+ bool DisableMacroExpansion : 1; // True if macro expansion is disabled.
+ bool InMacroArgs : 1; // True if parsing fn macro invocation args.
+
+ /// Identifiers - This is mapping/lookup information for all identifiers in
+ /// the program, including program keywords.
+ IdentifierTable Identifiers;
+
+ /// Selectors - This table contains all the selectors in the program. Unlike
+ /// IdentifierTable above, this table *isn't* populated by the preprocessor.
+ /// It is declared/instantiated here because it's role/lifetime is
+ /// conceptually similar the IdentifierTable. In addition, the current control
+ /// flow (in clang::ParseAST()), make it convenient to put here.
+ /// FIXME: Make sure the lifetime of Identifiers/Selectors *isn't* tied to
+ /// the lifetime fo the preprocessor.
+ SelectorTable Selectors;
+
+ /// PragmaHandlers - This tracks all of the pragmas that the client registered
+ /// with this preprocessor.
+ PragmaNamespace *PragmaHandlers;
+
+ /// CurLexer - This is the current top of the stack that we're lexing from if
+ /// not expanding a macro and we are lexing directly from source code.
+ /// Only one of CurLexer, CurPTHLexer, or CurTokenLexer will be non-null.
+ llvm::OwningPtr<Lexer> CurLexer;
+
+ /// CurPTHLexer - This is the current top of stack that we're lexing from if
+ /// not expanding from a macro and we are lexing from a PTH cache.
+ /// Only one of CurLexer, CurPTHLexer, or CurTokenLexer will be non-null.
+ llvm::OwningPtr<PTHLexer> CurPTHLexer;
+
+ /// CurPPLexer - This is the current top of the stack what we're lexing from
+ /// 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.
+ const DirectoryLookup *CurDirLookup;
+
+ /// CurTokenLexer - This is the current macro we are expanding, if we are
+ /// expanding a macro. One of CurLexer and CurTokenLexer must be null.
+ llvm::OwningPtr<TokenLexer> CurTokenLexer;
+
+ /// IncludeMacroStack - This keeps track of the stack of files currently
+ /// #included, and macros currently being expanded from, not counting
+ /// CurLexer/CurTokenLexer.
+ struct IncludeStackInfo {
+ Lexer *TheLexer;
+ PTHLexer *ThePTHLexer;
+ PreprocessorLexer *ThePPLexer;
+ TokenLexer *TheTokenLexer;
+ const DirectoryLookup *TheDirLookup;
+
+ IncludeStackInfo(Lexer *L, PTHLexer* P, PreprocessorLexer* PPL,
+ TokenLexer* TL, const DirectoryLookup *D)
+ : TheLexer(L), ThePTHLexer(P), ThePPLexer(PPL), TheTokenLexer(TL),
+ TheDirLookup(D) {}
+ };
+ std::vector<IncludeStackInfo> IncludeMacroStack;
+
+ /// Callbacks - These are actions invoked when some preprocessor activity is
+ /// encountered (e.g. a file is #included, etc).
+ PPCallbacks *Callbacks;
+
+ /// Macros - For each IdentifierInfo with 'HasMacro' set, we keep a mapping
+ /// to the actual definition of the macro.
+ llvm::DenseMap<IdentifierInfo*, MacroInfo*> Macros;
+
+ /// MICache - A "freelist" of MacroInfo objects that can be reused for quick
+ /// allocation.
+ std::vector<MacroInfo*> MICache;
+
+ // Various statistics we track for performance analysis.
+ unsigned NumDirectives, NumIncluded, NumDefined, NumUndefined, NumPragma;
+ unsigned NumIf, NumElse, NumEndif;
+ unsigned NumEnteredSourceFiles, MaxIncludeStackDepth;
+ unsigned NumMacroExpanded, NumFnMacroExpanded, NumBuiltinMacroExpanded;
+ unsigned NumFastMacroExpanded, NumTokenPaste, NumFastTokenPaste;
+ unsigned NumSkipped;
+
+ /// Predefines - This string is the predefined macros that preprocessor
+ /// should use from the command line etc.
+ std::string Predefines;
+
+ /// TokenLexerCache - Cache macro expanders to reduce malloc traffic.
+ enum { TokenLexerCacheSize = 8 };
+ unsigned NumCachedTokenLexers;
+ TokenLexer *TokenLexerCache[TokenLexerCacheSize];
+
+private: // Cached tokens state.
+ typedef std::vector<Token> CachedTokensTy;
+
+ /// CachedTokens - Cached tokens are stored here when we do backtracking or
+ /// lookahead. They are "lexed" by the CachingLex() method.
+ CachedTokensTy CachedTokens;
+
+ /// CachedLexPos - The position of the cached token that CachingLex() should
+ /// "lex" next. If it points beyond the CachedTokens vector, it means that
+ /// a normal Lex() should be invoked.
+ CachedTokensTy::size_type CachedLexPos;
+
+ /// BacktrackPositions - Stack of backtrack positions, allowing nested
+ /// backtracks. The EnableBacktrackAtThisPos() method pushes a position to
+ /// indicate where CachedLexPos should be set when the BackTrack() method is
+ /// invoked (at which point the last position is popped).
+ std::vector<CachedTokensTy::size_type> BacktrackPositions;
+
+public:
+ Preprocessor(Diagnostic &diags, const LangOptions &opts, TargetInfo &target,
+ SourceManager &SM, HeaderSearch &Headers,
+ IdentifierInfoLookup* IILookup = 0);
+
+ ~Preprocessor();
+
+ Diagnostic &getDiagnostics() const { return *Diags; }
+ void setDiagnostics(Diagnostic &D) { Diags = &D; }
+
+
+ const LangOptions &getLangOptions() const { return Features; }
+ TargetInfo &getTargetInfo() const { return Target; }
+ FileManager &getFileManager() const { return FileMgr; }
+ SourceManager &getSourceManager() const { return SourceMgr; }
+ HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; }
+
+ IdentifierTable &getIdentifierTable() { return Identifiers; }
+ SelectorTable &getSelectorTable() { return Selectors; }
+ llvm::BumpPtrAllocator &getPreprocessorAllocator() { return BP; }
+
+ void setPTHManager(PTHManager* pm);
+
+ PTHManager *getPTHManager() { return PTH.get(); }
+
+ /// SetCommentRetentionState - Control whether or not the preprocessor retains
+ /// comments in output.
+ void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments) {
+ this->KeepComments = KeepComments | KeepMacroComments;
+ this->KeepMacroComments = KeepMacroComments;
+ }
+
+ bool getCommentRetentionState() const { return KeepComments; }
+
+ /// isCurrentLexer - Return true if we are lexing directly from the specified
+ /// lexer.
+ bool isCurrentLexer(const PreprocessorLexer *L) const {
+ return CurPPLexer == L;
+ }
+
+ /// getCurrentLexer - Return the current file lexer being lexed from. Note
+ /// that this ignores any potentially active macro expansions and _Pragma
+ /// expansions going on at the time.
+ PreprocessorLexer *getCurrentFileLexer() const;
+
+ /// getPPCallbacks/setPPCallbacks - Accessors for preprocessor callbacks.
+ /// Note that this class takes ownership of any PPCallbacks object given to
+ /// it.
+ PPCallbacks *getPPCallbacks() const { return Callbacks; }
+ void setPPCallbacks(PPCallbacks *C) {
+ if (Callbacks)
+ C = new PPChainedCallbacks(C, Callbacks);
+ Callbacks = C;
+ }
+
+ /// getMacroInfo - Given an identifier, return the MacroInfo it is #defined to
+ /// or null if it isn't #define'd.
+ MacroInfo *getMacroInfo(IdentifierInfo *II) const {
+ return II->hasMacroDefinition() ? Macros.find(II)->second : 0;
+ }
+
+ /// setMacroInfo - Specify a macro for this identifier.
+ ///
+ void setMacroInfo(IdentifierInfo *II, MacroInfo *MI);
+
+ /// macro_iterator/macro_begin/macro_end - This allows you to walk the current
+ /// state of the macro table. This visits every currently-defined macro.
+ typedef llvm::DenseMap<IdentifierInfo*,
+ MacroInfo*>::const_iterator macro_iterator;
+ macro_iterator macro_begin() const { return Macros.begin(); }
+ macro_iterator macro_end() const { return Macros.end(); }
+
+
+
+ const std::string &getPredefines() const { return Predefines; }
+ /// setPredefines - Set the predefines for this Preprocessor. These
+ /// predefines are automatically injected when parsing the main file.
+ void setPredefines(const char *P) { Predefines = P; }
+ void setPredefines(const std::string &P) { Predefines = P; }
+
+ /// getIdentifierInfo - Return information about the specified preprocessor
+ /// identifier token. The version of this method that takes two character
+ /// pointers is preferred unless the identifier is already available as a
+ /// string (this avoids allocation and copying of memory to construct an
+ /// std::string).
+ IdentifierInfo *getIdentifierInfo(const char *NameStart,
+ const char *NameEnd) {
+ return &Identifiers.get(NameStart, NameEnd);
+ }
+ IdentifierInfo *getIdentifierInfo(const char *NameStr) {
+ return getIdentifierInfo(NameStr, NameStr+strlen(NameStr));
+ }
+
+ /// 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(const char *Namespace, PragmaHandler *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(const char *Namespace, PragmaHandler *Handler);
+
+ /// EnterMainSourceFile - Enter the specified FileID as the main source file,
+ /// which implicitly adds the builtin defines etc.
+ void EnterMainSourceFile();
+
+ /// EnterSourceFile - Add a source file to the top of the include stack and
+ /// start lexing tokens from it instead of the current buffer. If isMainFile
+ /// is true, this is the main file for the translation unit.
+ void EnterSourceFile(FileID CurFileID, const DirectoryLookup *Dir);
+
+ /// EnterMacro - Add a Macro to the top of the include stack and start lexing
+ /// tokens from it instead of the current buffer. Args specifies the
+ /// tokens input to a function-like macro.
+ ///
+ /// ILEnd specifies the location of the ')' for a function-like macro or the
+ /// identifier for an object-like macro.
+ void EnterMacro(Token &Identifier, SourceLocation ILEnd, MacroArgs *Args);
+
+ /// EnterTokenStream - Add a "macro" context to the top of the include stack,
+ /// which will cause the lexer to start returning the specified tokens.
+ ///
+ /// If DisableMacroExpansion is true, tokens lexed from the token stream will
+ /// not be subject to further macro expansion. Otherwise, these tokens will
+ /// be re-macro-expanded when/if expansion is enabled.
+ ///
+ /// If OwnsTokens is false, this method assumes that the specified stream of
+ /// tokens has a permanent owner somewhere, so they do not need to be copied.
+ /// If it is true, it assumes the array of tokens is allocated with new[] and
+ /// must be freed.
+ ///
+ void EnterTokenStream(const Token *Toks, unsigned NumToks,
+ bool DisableMacroExpansion, bool OwnsTokens);
+
+ /// RemoveTopOfLexerStack - Pop the current lexer/macro exp off the top of the
+ /// lexer stack. This should only be used in situations where the current
+ /// state of the top-of-stack lexer is known.
+ void RemoveTopOfLexerStack();
+
+ /// EnableBacktrackAtThisPos - From the point that this method is called, and
+ /// until CommitBacktrackedTokens() or Backtrack() is called, the Preprocessor
+ /// keeps track of the lexed tokens so that a subsequent Backtrack() call will
+ /// make the Preprocessor re-lex the same tokens.
+ ///
+ /// Nested backtracks are allowed, meaning that EnableBacktrackAtThisPos can
+ /// be called multiple times and CommitBacktrackedTokens/Backtrack calls will
+ /// be combined with the EnableBacktrackAtThisPos calls in reverse order.
+ ///
+ /// NOTE: *DO NOT* forget to call either CommitBacktrackedTokens or Backtrack
+ /// at some point after EnableBacktrackAtThisPos. If you don't, caching of
+ /// tokens will continue indefinitely.
+ ///
+ void EnableBacktrackAtThisPos();
+
+ /// CommitBacktrackedTokens - Disable the last EnableBacktrackAtThisPos call.
+ void CommitBacktrackedTokens();
+
+ /// Backtrack - Make Preprocessor re-lex the tokens that were lexed since
+ /// EnableBacktrackAtThisPos() was previously called.
+ void Backtrack();
+
+ /// isBacktrackEnabled - True if EnableBacktrackAtThisPos() was called and
+ /// caching of tokens is on.
+ bool isBacktrackEnabled() const { return !BacktrackPositions.empty(); }
+
+ /// Lex - To lex a token from the preprocessor, just pull a token from the
+ /// current lexer or macro object.
+ void Lex(Token &Result) {
+ if (CurLexer)
+ CurLexer->Lex(Result);
+ else if (CurPTHLexer)
+ CurPTHLexer->Lex(Result);
+ else if (CurTokenLexer)
+ CurTokenLexer->Lex(Result);
+ else
+ CachingLex(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.
+ void LexNonComment(Token &Result) {
+ do
+ Lex(Result);
+ while (Result.getKind() == tok::comment);
+ }
+
+ /// LexUnexpandedToken - This is just like Lex, but this disables macro
+ /// expansion of identifier tokens.
+ void LexUnexpandedToken(Token &Result) {
+ // Disable macro expansion.
+ bool OldVal = DisableMacroExpansion;
+ DisableMacroExpansion = true;
+ // Lex the token.
+ Lex(Result);
+
+ // Reenable it.
+ DisableMacroExpansion = OldVal;
+ }
+
+ /// 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
+ /// returns normal tokens after phase 5. As such, it is equivalent to using
+ /// 'Lex', not 'LexUnexpandedToken'.
+ const Token &LookAhead(unsigned N) {
+ if (CachedLexPos + N < CachedTokens.size())
+ return CachedTokens[CachedLexPos+N];
+ else
+ return PeekAhead(N+1);
+ }
+
+ /// RevertCachedTokens - When backtracking is enabled and tokens are cached,
+ /// this allows to revert a specific number of tokens.
+ /// Note that the number of tokens being reverted should be up to the last
+ /// backtrack position, not more.
+ void RevertCachedTokens(unsigned N) {
+ assert(isBacktrackEnabled() &&
+ "Should only be called when tokens are cached for backtracking");
+ assert(signed(CachedLexPos) - signed(N) >= signed(BacktrackPositions.back())
+ && "Should revert tokens up to the last backtrack position, not more");
+ assert(signed(CachedLexPos) - signed(N) >= 0 &&
+ "Corrupted backtrack positions ?");
+ CachedLexPos -= N;
+ }
+
+ /// EnterToken - Enters a token in the token stream to be lexed next. If
+ /// BackTrack() is called afterwards, the token will remain at the insertion
+ /// point.
+ void EnterToken(const Token &Tok) {
+ EnterCachingLexMode();
+ CachedTokens.insert(CachedTokens.begin()+CachedLexPos, Tok);
+ }
+
+ /// AnnotateCachedTokens - We notify the Preprocessor that if it is caching
+ /// tokens (because backtrack is enabled) it should replace the most recent
+ /// cached tokens with the given annotation token. This function has no effect
+ /// if backtracking is not enabled.
+ ///
+ /// Note that the use of this function is just for optimization; so that the
+ /// cached tokens doesn't get re-parsed and re-resolved after a backtrack is
+ /// invoked.
+ void AnnotateCachedTokens(const Token &Tok) {
+ assert(Tok.isAnnotation() && "Expected annotation token");
+ if (CachedLexPos != 0 && isBacktrackEnabled())
+ AnnotatePreviousCachedTokens(Tok);
+ }
+
+ /// \brief Replace the last token with an annotation token.
+ ///
+ /// Like AnnotateCachedTokens(), this routine replaces an
+ /// already-parsed (and resolved) token with an annotation
+ /// token. However, this routine only replaces the last token with
+ /// the annotation token; it does not affect any other cached
+ /// tokens. This function has no effect if backtracking is not
+ /// enabled.
+ void ReplaceLastTokenWithAnnotation(const Token &Tok) {
+ assert(Tok.isAnnotation() && "Expected annotation token");
+ if (CachedLexPos != 0 && isBacktrackEnabled())
+ CachedTokens[CachedLexPos-1] = Tok;
+ }
+
+ /// 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) {
+ return Diags->Report(FullSourceLoc(Loc, getSourceManager()), DiagID);
+ }
+
+ DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID) {
+ return Diags->Report(FullSourceLoc(Tok.getLocation(), getSourceManager()),
+ DiagID);
+ }
+
+ /// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a
+ /// token is the characters used to represent the token in the source file
+ /// after trigraph expansion and escaped-newline folding. In particular, this
+ /// wants to get the true, uncanonicalized, spelling of things like digraphs
+ /// UCNs, etc.
+ std::string getSpelling(const Token &Tok) const;
+
+ /// getSpelling - This method is used to get the spelling of a token into a
+ /// preallocated buffer, instead of as an std::string. The caller is required
+ /// to allocate enough space for the token, which is guaranteed to be at least
+ /// Tok.getLength() bytes long. The length of the actual result is returned.
+ ///
+ /// Note that this method may do two possible things: it may either fill in
+ /// the buffer specified with characters, or it may *change the input pointer*
+ /// to point to a constant buffer with the data already in it (avoiding a
+ /// copy). The caller is not allowed to modify the returned buffer pointer
+ /// if an internal buffer is returned.
+ unsigned getSpelling(const Token &Tok, const char *&Buffer) const;
+
+ /// getSpellingOfSingleCharacterNumericConstant - Tok is a numeric constant
+ /// with length 1, return the character.
+ char getSpellingOfSingleCharacterNumericConstant(const Token &Tok) const {
+ assert(Tok.is(tok::numeric_constant) &&
+ Tok.getLength() == 1 && "Called on unsupported token");
+ assert(!Tok.needsCleaning() && "Token can't need cleaning with length 1");
+
+ // If the token is carrying a literal data pointer, just use it.
+ if (const char *D = Tok.getLiteralData())
+ return *D;
+
+ // Otherwise, fall back on getCharacterData, which is slower, but always
+ // works.
+ return *SourceMgr.getCharacterData(Tok.getLocation());
+ }
+
+ /// 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 instantiation point of the token.
+ void CreateString(const char *Buf, unsigned Len,
+ Token &Tok, SourceLocation SourceLoc = SourceLocation());
+
+ /// \brief Computes the source location just past the end of the
+ /// token at this source location.
+ ///
+ /// This routine can be used to produce a source location that
+ /// points just past the end of the token referenced by \p Loc, and
+ /// is generally used when a diagnostic needs to point just after a
+ /// token where it expected something different that it received. If
+ /// the returned source location would not be meaningful (e.g., if
+ /// it points into a macro), this routine returns an invalid
+ /// source location.
+ SourceLocation getLocForEndOfToken(SourceLocation Loc);
+
+ /// DumpToken - Print the token to stderr, used for debugging.
+ ///
+ void DumpToken(const Token &Tok, bool DumpFlags = false) const;
+ void DumpLocation(SourceLocation Loc) const;
+ void DumpMacro(const MacroInfo &MI) const;
+
+ /// AdvanceToTokenCharacter - Given a location that specifies the start of a
+ /// token, return a new location that specifies a character within the token.
+ SourceLocation AdvanceToTokenCharacter(SourceLocation TokStart,unsigned Char);
+
+ /// IncrementPasteCounter - Increment the counters for the number of token
+ /// paste operations performed. If fast was specified, this is a 'fast paste'
+ /// case we handled.
+ ///
+ void IncrementPasteCounter(bool isFast) {
+ if (isFast)
+ ++NumFastTokenPaste;
+ else
+ ++NumTokenPaste;
+ }
+
+ void PrintStats();
+
+ /// HandleMicrosoftCommentPaste - When the macro expander pastes together a
+ /// comment (/##/) in microsoft mode, this method handles updating the current
+ /// state, returning the token on the next source line.
+ void HandleMicrosoftCommentPaste(Token &Tok);
+
+ //===--------------------------------------------------------------------===//
+ // Preprocessor callback methods. These are invoked by a lexer as various
+ // directives and events are found.
+
+ /// LookUpIdentifierInfo - Given a tok::identifier token, look up the
+ /// identifier information for the token and install it into the token.
+ IdentifierInfo *LookUpIdentifierInfo(Token &Identifier,
+ const char *BufPtr = 0);
+
+ /// HandleIdentifier - This callback is invoked when the lexer reads an
+ /// identifier and has filled in the tokens IdentifierInfo member. This
+ /// callback potentially macro expands it or turns it into a named token (like
+ /// 'for').
+ void HandleIdentifier(Token &Identifier);
+
+
+ /// HandleEndOfFile - This callback is invoked when the lexer hits the end of
+ /// the current file. This either returns the EOF token and returns true, or
+ /// pops a level off the include stack and returns false, at which point the
+ /// client should call lex again.
+ bool HandleEndOfFile(Token &Result, bool isEndOfMacro = false);
+
+ /// HandleEndOfTokenLexer - This callback is invoked when the current
+ /// TokenLexer hits the end of its token stream.
+ bool HandleEndOfTokenLexer(Token &Result);
+
+ /// HandleDirective - This callback is invoked when the lexer sees a # token
+ /// at the start of a line. This consumes the directive, modifies the
+ /// lexer/preprocessor state, and advances the lexer(s) so that the next token
+ /// read is the correct one.
+ void HandleDirective(Token &Result);
+
+ /// CheckEndOfDirective - Ensure that the next token is a tok::eom token. If
+ /// not, emit a diagnostic and consume up until the eom. If EnableMacros is
+ /// true, then we consider macros that expand to zero tokens as being ok.
+ void CheckEndOfDirective(const char *Directive, bool EnableMacros = false);
+
+ /// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the
+ /// current line until the tok::eom token is found.
+ void DiscardUntilEndOfDirective();
+
+ /// SawDateOrTime - This returns true if the preprocessor has seen a use of
+ /// __DATE__ or __TIME__ in the file so far.
+ bool SawDateOrTime() const {
+ return DATELoc != SourceLocation() || TIMELoc != SourceLocation();
+ }
+ unsigned getCounterValue() const { return CounterValue; }
+ void setCounterValue(unsigned V) { CounterValue = V; }
+
+ /// AllocateMacroInfo - Allocate a new MacroInfo object with the provide
+ /// SourceLocation.
+ MacroInfo* AllocateMacroInfo(SourceLocation L);
+
+private:
+
+ void PushIncludeMacroStack() {
+ IncludeMacroStack.push_back(IncludeStackInfo(CurLexer.take(),
+ CurPTHLexer.take(),
+ CurPPLexer,
+ CurTokenLexer.take(),
+ CurDirLookup));
+ CurPPLexer = 0;
+ }
+
+ void PopIncludeMacroStack() {
+ CurLexer.reset(IncludeMacroStack.back().TheLexer);
+ CurPTHLexer.reset(IncludeMacroStack.back().ThePTHLexer);
+ CurPPLexer = IncludeMacroStack.back().ThePPLexer;
+ CurTokenLexer.reset(IncludeMacroStack.back().TheTokenLexer);
+ CurDirLookup = IncludeMacroStack.back().TheDirLookup;
+ IncludeMacroStack.pop_back();
+ }
+
+ /// ReleaseMacroInfo - Release the specified MacroInfo. This memory will
+ /// be reused for allocating new MacroInfo objects.
+ void ReleaseMacroInfo(MacroInfo* MI);
+
+ /// isInPrimaryFile - Return true if we're in the top-level file, not in a
+ /// #include.
+ bool isInPrimaryFile() const;
+
+ /// ReadMacroName - Lex and validate a macro name, which occurs after a
+ /// #define or #undef. This emits a diagnostic, sets the token kind to eom,
+ /// and discards the rest of the macro line if the macro name is invalid.
+ void ReadMacroName(Token &MacroNameTok, char isDefineUndef = 0);
+
+ /// ReadMacroDefinitionArgList - The ( starting an argument list of a macro
+ /// definition has just been read. Lex the rest of the arguments and the
+ /// closing ), updating MI with what we learn. Return true if an error occurs
+ /// parsing the arg list.
+ bool ReadMacroDefinitionArgList(MacroInfo *MI);
+
+ /// SkipExcludedConditionalBlock - We just read a #if or related directive and
+ /// decided that the subsequent tokens are in the #if'd out portion of the
+ /// file. Lex the rest of the file, until we see an #endif. If
+ /// FoundNonSkipPortion is true, then we have already emitted code for part of
+ /// this #if directive, so #else/#elif blocks should never be entered. If
+ /// FoundElse is false, then #else directives are ok, if not, then we have
+ /// 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);
+
+ /// PTHSkipExcludedConditionalBlock - A fast PTH version of
+ /// SkipExcludedConditionalBlock.
+ void PTHSkipExcludedConditionalBlock();
+
+ /// EvaluateDirectiveExpression - Evaluate an integer constant expression that
+ /// may occur after a #if or #elif directive and return it as a bool. If the
+ /// expression is equivalent to "!defined(X)" return X in IfNDefMacro.
+ bool EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro);
+
+ /// RegisterBuiltinPragmas - Install the standard preprocessor pragmas:
+ /// #pragma GCC poison/system_header/dependency and #pragma once.
+ void RegisterBuiltinPragmas();
+
+ /// RegisterBuiltinMacros - Register builtin macros, such as __LINE__ with the
+ /// identifier table.
+ void RegisterBuiltinMacros();
+ IdentifierInfo *RegisterBuiltinMacro(const char *Name);
+
+ /// HandleMacroExpandedIdentifier - If an identifier token is read that is to
+ /// be expanded as a macro, handle it and return the next token as 'Tok'. If
+ /// the macro should not be expanded return true, otherwise return false.
+ bool HandleMacroExpandedIdentifier(Token &Tok, MacroInfo *MI);
+
+ /// isNextPPTokenLParen - Determine whether the next preprocessor token to be
+ /// lexed is a '('. If so, consume the token and return true, if not, this
+ /// method should have no observable side-effect on the lexed tokens.
+ bool isNextPPTokenLParen();
+
+ /// ReadFunctionLikeMacroArgs - After reading "MACRO(", this method is
+ /// invoked to read all of the formal arguments specified for the macro
+ /// invocation. This returns null on error.
+ MacroArgs *ReadFunctionLikeMacroArgs(Token &MacroName, MacroInfo *MI,
+ SourceLocation &InstantiationEnd);
+
+ /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded
+ /// as a builtin macro, handle it and return the next token as 'Tok'.
+ void ExpandBuiltinMacro(Token &Tok);
+
+ /// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then
+ /// return the first token after the directive. The _Pragma token has just
+ /// been read into 'Tok'.
+ void Handle_Pragma(Token &Tok);
+
+ /// EnterSourceFileWithLexer - Add a lexer to the top of the include stack and
+ /// start lexing tokens from it instead of the current buffer.
+ void EnterSourceFileWithLexer(Lexer *TheLexer, const DirectoryLookup *Dir);
+
+ /// EnterSourceFileWithPTH - Add a lexer to the top of the include stack and
+ /// start getting tokens from it using the PTH cache.
+ void EnterSourceFileWithPTH(PTHLexer *PL, const DirectoryLookup *Dir);
+
+ /// GetIncludeFilenameSpelling - Turn the specified lexer token into a fully
+ /// checked and spelled filename, e.g. as an operand of #include. This returns
+ /// true if the input filename was in <>'s or false if it were in ""'s. The
+ /// 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,
+ const char *&BufStart, const char *&BufEnd);
+
+ /// 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(const char *FilenameStart,const char *FilenameEnd,
+ bool isAngled, const DirectoryLookup *FromDir,
+ const DirectoryLookup *&CurDir);
+
+
+
+ /// IsFileLexer - Returns true if we are lexing from a file and not a
+ /// pragma or a macro.
+ static bool IsFileLexer(const Lexer* L, const PreprocessorLexer* P) {
+ return L ? !L->isPragmaLexer() : P != 0;
+ }
+
+ static bool IsFileLexer(const IncludeStackInfo& I) {
+ return IsFileLexer(I.TheLexer, I.ThePPLexer);
+ }
+
+ bool IsFileLexer() const {
+ return IsFileLexer(CurLexer.get(), CurPPLexer);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Caching stuff.
+ void CachingLex(Token &Result);
+ bool InCachingLexMode() const { return CurPPLexer == 0 && CurTokenLexer == 0;}
+ void EnterCachingLexMode();
+ void ExitCachingLexMode() {
+ if (InCachingLexMode())
+ RemoveTopOfLexerStack();
+ }
+ const Token &PeekAhead(unsigned N);
+ void AnnotatePreviousCachedTokens(const Token &Tok);
+
+ //===--------------------------------------------------------------------===//
+ /// Handle*Directive - implement the various preprocessor directives. These
+ /// should side-effect the current preprocessor object so that the next call
+ /// to Lex() will return the appropriate token next.
+ void HandleLineDirective(Token &Tok);
+ void HandleDigitDirective(Token &Tok);
+ void HandleUserDiagnosticDirective(Token &Tok, bool isWarning);
+ void HandleIdentSCCSDirective(Token &Tok);
+
+ // File inclusion.
+ void HandleIncludeDirective(Token &Tok,
+ const DirectoryLookup *LookupFrom = 0,
+ bool isImport = false);
+ void HandleIncludeNextDirective(Token &Tok);
+ void HandleIncludeMacrosDirective(Token &Tok);
+ void HandleImportDirective(Token &Tok);
+
+ // Macro handling.
+ void HandleDefineDirective(Token &Tok);
+ void HandleUndefDirective(Token &Tok);
+ // HandleAssertDirective(Token &Tok);
+ // HandleUnassertDirective(Token &Tok);
+
+ // Conditional Inclusion.
+ void HandleIfdefDirective(Token &Tok, bool isIfndef,
+ bool ReadAnyTokensBeforeDirective);
+ void HandleIfDirective(Token &Tok, bool ReadAnyTokensBeforeDirective);
+ void HandleEndifDirective(Token &Tok);
+ void HandleElseDirective(Token &Tok);
+ void HandleElifDirective(Token &Tok);
+
+ // Pragmas.
+ void HandlePragmaDirective();
+public:
+ void HandlePragmaOnce(Token &OnceTok);
+ void HandlePragmaMark();
+ void HandlePragmaPoison(Token &PoisonTok);
+ void HandlePragmaSystemHeader(Token &SysHeaderTok);
+ void HandlePragmaDependency(Token &DependencyTok);
+ void HandlePragmaComment(Token &CommentTok);
+};
+
+/// PreprocessorFactory - A generic factory interface for lazily creating
+/// Preprocessor objects on-demand when they are needed.
+class PreprocessorFactory {
+public:
+ virtual ~PreprocessorFactory();
+ virtual Preprocessor* CreatePreprocessor() = 0;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/PreprocessorLexer.h b/include/clang/Lex/PreprocessorLexer.h
new file mode 100644
index 000000000000..f98b5599658f
--- /dev/null
+++ b/include/clang/Lex/PreprocessorLexer.h
@@ -0,0 +1,161 @@
+//===--- PreprocessorLexer.h - C Language Family Lexer ----------*- 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 PreprocessorLexer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PreprocessorLexer_H
+#define LLVM_CLANG_PreprocessorLexer_H
+
+#include "clang/Lex/MultipleIncludeOpt.h"
+#include "clang/Lex/Token.h"
+#include "llvm/ADT/SmallVector.h"
+#include <string>
+
+namespace clang {
+
+class Preprocessor;
+
+class PreprocessorLexer {
+protected:
+ Preprocessor *PP; // Preprocessor object controlling lexing.
+
+ /// The SourceManager FileID corresponding to the file being lexed.
+ const FileID FID;
+
+ //===--------------------------------------------------------------------===//
+ // Context-specific lexing flags set by the preprocessor.
+ //===--------------------------------------------------------------------===//
+
+ /// ParsingPreprocessorDirective - This is true when parsing #XXX. This turns
+ /// '\n' into a tok::eom token.
+ bool ParsingPreprocessorDirective;
+
+ /// ParsingFilename - True after #include: this turns <xx> into a
+ /// tok::angle_string_literal token.
+ bool ParsingFilename;
+
+ /// LexingRawMode - True if in raw mode: This flag disables interpretation of
+ /// tokens and is a far faster mode to lex in than non-raw-mode. This flag:
+ /// 1. If EOF of the current lexer is found, the include stack isn't popped.
+ /// 2. Identifier information is not looked up for identifier tokens. As an
+ /// effect of this, implicit macro expansion is naturally disabled.
+ /// 3. "#" tokens at the start of a line are treated as normal tokens, not
+ /// implicitly transformed by the lexer.
+ /// 4. All diagnostic messages are disabled.
+ /// 5. No callbacks are made into the preprocessor.
+ ///
+ /// Note that in raw mode that the PP pointer may be null.
+ bool LexingRawMode;
+
+ /// MIOpt - This is a state machine that detects the #ifndef-wrapping a file
+ /// idiom for the multiple-include optimization.
+ MultipleIncludeOpt MIOpt;
+
+ /// ConditionalStack - Information about the set of #if/#ifdef/#ifndef blocks
+ /// we are currently in.
+ llvm::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()
+ : PP(0),
+ ParsingPreprocessorDirective(false),
+ ParsingFilename(false),
+ LexingRawMode(false) {}
+
+ virtual ~PreprocessorLexer() {}
+
+ virtual void IndirectLex(Token& Result) = 0;
+
+ /// getSourceLocation - Return the source location for the next observable
+ /// location.
+ virtual SourceLocation getSourceLocation() = 0;
+
+ //===--------------------------------------------------------------------===//
+ // #if directive handling.
+
+ /// pushConditionalLevel - When we enter a #if directive, this keeps track of
+ /// what we are currently in for diagnostic emission (e.g. #if with missing
+ /// #endif).
+ void pushConditionalLevel(SourceLocation DirectiveStart, bool WasSkipping,
+ bool FoundNonSkip, bool FoundElse) {
+ PPConditionalInfo CI;
+ CI.IfLoc = DirectiveStart;
+ CI.WasSkipping = WasSkipping;
+ CI.FoundNonSkip = FoundNonSkip;
+ CI.FoundElse = FoundElse;
+ ConditionalStack.push_back(CI);
+ }
+ void pushConditionalLevel(const PPConditionalInfo &CI) {
+ ConditionalStack.push_back(CI);
+ }
+
+ /// popConditionalLevel - Remove an entry off the top of the conditional
+ /// stack, returning information about it. If the conditional stack is empty,
+ /// this returns true and does not fill in the arguments.
+ bool popConditionalLevel(PPConditionalInfo &CI) {
+ if (ConditionalStack.empty()) return true;
+ CI = ConditionalStack.back();
+ ConditionalStack.pop_back();
+ return false;
+ }
+
+ /// peekConditionalLevel - Return the top of the conditional stack. This
+ /// requires that there be a conditional active.
+ PPConditionalInfo &peekConditionalLevel() {
+ assert(!ConditionalStack.empty() && "No conditionals active!");
+ return ConditionalStack.back();
+ }
+
+ unsigned getConditionalStackDepth() const { return ConditionalStack.size(); }
+
+public:
+
+ //===--------------------------------------------------------------------===//
+ // Misc. lexing methods.
+
+ /// LexIncludeFilename - After the preprocessor has parsed a #include, lex and
+ /// (potentially) macro expand the filename. If the sequence parsed is not
+ /// lexically legal, emit a diagnostic and return a result EOM token.
+ void LexIncludeFilename(Token &Result);
+
+ /// setParsingPreprocessorDirective - Inform the lexer whether or not
+ /// we are currently lexing a preprocessor directive.
+ void setParsingPreprocessorDirective(bool f) {
+ ParsingPreprocessorDirective = f;
+ }
+
+ /// isLexingRawMode - Return true if this lexer is in raw mode or not.
+ bool isLexingRawMode() const { return LexingRawMode; }
+
+ /// getPP - Return the preprocessor object for this lexer.
+ Preprocessor *getPP() const { return PP; }
+
+ FileID getFileID() const {
+ assert(PP &&
+ "PreprocessorLexer::getFileID() should only be used with a Preprocessor");
+ return FID;
+ }
+
+ /// getFileEntry - Return the FileEntry corresponding to this FileID. Like
+ /// getFileID(), this only works for lexers with attached preprocessors.
+ const FileEntry *getFileEntry() const;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/ScratchBuffer.h b/include/clang/Lex/ScratchBuffer.h
new file mode 100644
index 000000000000..6506f9262947
--- /dev/null
+++ b/include/clang/Lex/ScratchBuffer.h
@@ -0,0 +1,45 @@
+//===--- ScratchBuffer.h - Scratch space for forming tokens -----*- 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 ScratchBuffer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SCRATCHBUFFER_H
+#define LLVM_CLANG_SCRATCHBUFFER_H
+
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+ class SourceManager;
+
+/// ScratchBuffer - This class exposes a simple interface for the dynamic
+/// construction of tokens. This is used for builtin macros (e.g. __LINE__) as
+/// well as token pasting, etc.
+class ScratchBuffer {
+ SourceManager &SourceMgr;
+ char *CurBuffer;
+ SourceLocation BufferStartLoc;
+ unsigned BytesUsed;
+public:
+ ScratchBuffer(SourceManager &SM);
+
+ /// getToken - Splat the specified text into a temporary MemoryBuffer and
+ /// return a SourceLocation that refers to the token. This is just like the
+ /// previous method, but returns a location that indicates the physloc of the
+ /// token.
+ SourceLocation getToken(const char *Buf, unsigned Len, const char *&DestPtr);
+
+private:
+ void AllocScratchBuffer(unsigned RequestLen);
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h
new file mode 100644
index 000000000000..2c8f2ad3f2b6
--- /dev/null
+++ b/include/clang/Lex/Token.h
@@ -0,0 +1,312 @@
+//===--- Token.h - Token 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 Token interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOKEN_H
+#define LLVM_CLANG_TOKEN_H
+
+#include "clang/Basic/TemplateKinds.h"
+#include "clang/Basic/TokenKinds.h"
+#include "clang/Basic/SourceLocation.h"
+#include <cstdlib>
+
+namespace clang {
+
+class IdentifierInfo;
+
+/// Token - This structure provides full information about a lexed token.
+/// It is not intended to be space efficient, it is intended to return as much
+/// information as possible about each returned token. This is expected to be
+/// compressed into a smaller form if memory footprint is important.
+///
+/// The parser can create a special "annotation token" representing a stream of
+/// tokens that were parsed and semantically resolved, e.g.: "foo::MyClass<int>"
+/// can be represented by a single typename annotation token that carries
+/// information about the SourceRange of the tokens and the type object.
+class Token {
+ /// The location of the token.
+ SourceLocation Loc;
+
+ // Conceptually these next two fields could be in a union. However, this
+ // causes gcc 4.2 to pessimize LexTokenInternal, a very performance critical
+ // routine. Keeping as separate members with casts until a more beautiful fix
+ // presents itself.
+
+ /// UintData - This holds either the length of the token text, when
+ /// a normal token, or the end of the SourceRange when an annotation
+ /// token.
+ unsigned UintData;
+
+ /// PtrData - This is a union of four different pointer types, which depends
+ /// on what type of token this is:
+ /// Identifiers, keywords, etc:
+ /// This is an IdentifierInfo*, which contains the uniqued identifier
+ /// spelling.
+ /// Literals: isLiteral() returns true.
+ /// This is a pointer to the start of the token in a text buffer, which
+ /// may be dirty (have trigraphs / escaped newlines).
+ /// Annotations (resolved type names, C++ scopes, etc): isAnnotation().
+ /// This is a pointer to sema-specific data for the annotation token.
+ /// Other:
+ /// This is null.
+ void *PtrData;
+
+ /// Kind - The actual flavor of token this is.
+ ///
+ unsigned Kind : 8; // DON'T make Kind a 'tok::TokenKind';
+ // MSVC will treat it as a signed char and
+ // TokenKinds > 127 won't be handled correctly.
+
+ /// Flags - Bits we track about this token, members of the TokenFlags enum.
+ unsigned Flags : 8;
+public:
+
+ // Various flags set per token:
+ enum TokenFlags {
+ StartOfLine = 0x01, // At start of line or only after whitespace.
+ LeadingSpace = 0x02, // Whitespace exists before this token.
+ DisableExpand = 0x04, // This identifier may never be macro expanded.
+ NeedsCleaning = 0x08 // Contained an escaped newline or trigraph.
+ };
+
+ tok::TokenKind getKind() const { return (tok::TokenKind)Kind; }
+ void setKind(tok::TokenKind K) { Kind = K; }
+
+ /// is/isNot - Predicates to check if this token is a specific kind, as in
+ /// "if (Tok.is(tok::l_brace)) {...}".
+ bool is(tok::TokenKind K) const { return Kind == (unsigned) K; }
+ bool isNot(tok::TokenKind K) const { return Kind != (unsigned) K; }
+
+ /// isLiteral - Return true if this is a "literal", like a numeric
+ /// constant, string, etc.
+ bool isLiteral() const {
+ return is(tok::numeric_constant) || is(tok::char_constant) ||
+ is(tok::string_literal) || is(tok::wide_string_literal) ||
+ is(tok::angle_string_literal);
+ }
+
+ bool isAnnotation() const {
+ return is(tok::annot_typename) ||
+ is(tok::annot_cxxscope) ||
+ is(tok::annot_template_id);
+ }
+
+ /// getLocation - Return a source location identifier for the specified
+ /// offset in the current file.
+ SourceLocation getLocation() const { return Loc; }
+ unsigned getLength() const {
+ assert(!isAnnotation() && "Annotation tokens have no length field");
+ return UintData;
+ }
+
+ void setLocation(SourceLocation L) { Loc = L; }
+ void setLength(unsigned Len) {
+ assert(!isAnnotation() && "Annotation tokens have no length field");
+ UintData = Len;
+ }
+
+ SourceLocation getAnnotationEndLoc() const {
+ assert(isAnnotation() && "Used AnnotEndLocID on non-annotation token");
+ return SourceLocation::getFromRawEncoding(UintData);
+ }
+ void setAnnotationEndLoc(SourceLocation L) {
+ assert(isAnnotation() && "Used AnnotEndLocID on non-annotation token");
+ UintData = L.getRawEncoding();
+ }
+
+ /// getAnnotationRange - SourceRange of the group of tokens that this
+ /// annotation token represents.
+ SourceRange getAnnotationRange() const {
+ return SourceRange(getLocation(), getAnnotationEndLoc());
+ }
+ void setAnnotationRange(SourceRange R) {
+ setLocation(R.getBegin());
+ setAnnotationEndLoc(R.getEnd());
+ }
+
+ const char *getName() const {
+ return tok::getTokenName( (tok::TokenKind) Kind);
+ }
+
+ /// startToken - Reset all flags to cleared.
+ ///
+ void startToken() {
+ Kind = tok::unknown;
+ Flags = 0;
+ PtrData = 0;
+ Loc = SourceLocation();
+ }
+
+ IdentifierInfo *getIdentifierInfo() const {
+ assert(!isAnnotation() && "Used IdentInfo on annotation token!");
+ if (isLiteral()) return 0;
+ return (IdentifierInfo*) PtrData;
+ }
+ void setIdentifierInfo(IdentifierInfo *II) {
+ PtrData = (void*) II;
+ }
+
+ /// getLiteralData - For a literal token (numeric constant, string, etc), this
+ /// returns a pointer to the start of it in the text buffer if known, null
+ /// otherwise.
+ const char *getLiteralData() const {
+ assert(isLiteral() && "Cannot get literal data of non-literal");
+ return reinterpret_cast<const char*>(PtrData);
+ }
+ void setLiteralData(const char *Ptr) {
+ assert(isLiteral() && "Cannot set literal data of non-literal");
+ PtrData = (void*)Ptr;
+ }
+
+ void *getAnnotationValue() const {
+ assert(isAnnotation() && "Used AnnotVal on non-annotation token");
+ return PtrData;
+ }
+ void setAnnotationValue(void *val) {
+ assert(isAnnotation() && "Used AnnotVal on non-annotation token");
+ PtrData = val;
+ }
+
+ /// setFlag - Set the specified flag.
+ void setFlag(TokenFlags Flag) {
+ Flags |= Flag;
+ }
+
+ /// clearFlag - Unset the specified flag.
+ void clearFlag(TokenFlags Flag) {
+ Flags &= ~Flag;
+ }
+
+ /// getFlags - Return the internal represtation of the flags.
+ /// Only intended for low-level operations such as writing tokens to
+ // disk.
+ unsigned getFlags() const {
+ return Flags;
+ }
+
+ /// setFlagValue - Set a flag to either true or false.
+ void setFlagValue(TokenFlags Flag, bool Val) {
+ if (Val)
+ setFlag(Flag);
+ else
+ clearFlag(Flag);
+ }
+
+ /// isAtStartOfLine - Return true if this token is at the start of a line.
+ ///
+ bool isAtStartOfLine() const { return (Flags & StartOfLine) ? true : false; }
+
+ /// hasLeadingSpace - Return true if this token has whitespace before it.
+ ///
+ bool hasLeadingSpace() const { return (Flags & LeadingSpace) ? true : false; }
+
+ /// isExpandDisabled - Return true if this identifier token should never
+ /// be expanded in the future, due to C99 6.10.3.4p2.
+ bool isExpandDisabled() const {
+ return (Flags & DisableExpand) ? true : false;
+ }
+
+ /// isObjCAtKeyword - Return true if we have an ObjC keyword identifier.
+ bool isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const;
+
+ /// getObjCKeywordID - Return the ObjC keyword kind.
+ tok::ObjCKeywordKind getObjCKeywordID() const;
+
+ /// needsCleaning - Return true if this token has trigraphs or escaped
+ /// newlines in it.
+ ///
+ bool needsCleaning() const { return (Flags & NeedsCleaning) ? true : false; }
+};
+
+/// PPConditionalInfo - Information about the conditional stack (#if directives)
+/// currently active.
+struct PPConditionalInfo {
+ /// IfLoc - Location where the conditional started.
+ ///
+ SourceLocation IfLoc;
+
+ /// WasSkipping - True if this was contained in a skipping directive, e.g.
+ /// in a "#if 0" block.
+ bool WasSkipping;
+
+ /// FoundNonSkip - True if we have emitted tokens already, and now we're in
+ /// an #else block or something. Only useful in Skipping blocks.
+ bool FoundNonSkip;
+
+ /// FoundElse - True if we've seen a #else in this block. If so,
+ /// #elif/#else directives are not allowed.
+ bool FoundElse;
+};
+
+/// TemplateIdAnnotation - Information about a template-id annotation
+/// token, which contains the template declaration, template
+/// arguments, whether those template arguments were types or
+/// expressions, and the source locations for important tokens. All of
+/// the information about template arguments is allocated directly
+/// after this structure.
+struct TemplateIdAnnotation {
+ /// TemplateNameLoc - The location of the template name within the
+ /// source.
+ SourceLocation TemplateNameLoc;
+
+ /// FIXME: Temporarily stores the name of a specialization
+ IdentifierInfo *Name;
+
+ /// The declaration of the template corresponding to the
+ /// template-name. This is an Action::DeclTy*.
+ void *Template;
+
+ /// The kind of template that Template refers to.
+ TemplateNameKind Kind;
+
+ /// The location of the '<' before the template argument
+ /// list.
+ SourceLocation LAngleLoc;
+
+ /// The location of the '>' after the template argument
+ /// list.
+ SourceLocation RAngleLoc;
+
+ /// NumArgs - The number of template arguments.
+ unsigned NumArgs;
+
+ /// \brief Retrieves a pointer to the template arguments
+ void **getTemplateArgs() { return (void **)(this + 1); }
+
+ /// \brief Retrieves a pointer to the array of template argument
+ /// locations.
+ SourceLocation *getTemplateArgLocations() {
+ return (SourceLocation *)(getTemplateArgs() + NumArgs);
+ }
+
+ /// \brief Retrieves a pointer to the array of flags that states
+ /// whether the template arguments are types.
+ bool *getTemplateArgIsType() {
+ return (bool *)(getTemplateArgLocations() + NumArgs);
+ }
+
+ static TemplateIdAnnotation* Allocate(unsigned NumArgs) {
+ TemplateIdAnnotation *TemplateId
+ = (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) +
+ sizeof(void*) * NumArgs +
+ sizeof(SourceLocation) * NumArgs +
+ sizeof(bool) * NumArgs);
+ TemplateId->NumArgs = NumArgs;
+ return TemplateId;
+ }
+
+ void Destroy() { free(this); }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/TokenConcatenation.h b/include/clang/Lex/TokenConcatenation.h
new file mode 100644
index 000000000000..dfc05f4074e0
--- /dev/null
+++ b/include/clang/Lex/TokenConcatenation.h
@@ -0,0 +1,73 @@
+//===--- TokenConcatenation.h - Token Concatenation Avoidance ---*- 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 TokenConcatenation class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_LEX_TOKEN_CONCATENATION_H
+#define CLANG_LEX_TOKEN_CONCATENATION_H
+
+#include "clang/Basic/TokenKinds.h"
+
+namespace clang {
+ class Preprocessor;
+ class Token;
+
+ /// TokenConcatenation class, which answers the question of
+ /// "Is it safe to emit two tokens without a whitespace between them, or
+ /// would that cause implicit concatenation of the tokens?"
+ ///
+ /// For example, it emitting two identifiers "foo" and "bar" next to each
+ /// other would cause the lexer to produce one "foobar" token. Emitting "1"
+ /// and ")" next to each other is safe.
+ ///
+ class TokenConcatenation {
+ Preprocessor &PP;
+
+ enum AvoidConcatInfo {
+ /// By default, a token never needs to avoid concatenation. Most tokens
+ /// (e.g. ',', ')', etc) don't cause a problem when concatenated.
+ aci_never_avoid_concat = 0,
+
+ /// aci_custom_firstchar - AvoidConcat contains custom code to handle this
+ /// token's requirements, and it needs to know the first character of the
+ /// token.
+ aci_custom_firstchar = 1,
+
+ /// aci_custom - AvoidConcat contains custom code to handle this token's
+ /// requirements, but it doesn't need to know the first character of the
+ /// token.
+ aci_custom = 2,
+
+ /// aci_avoid_equal - Many tokens cannot be safely followed by an '='
+ /// character. For example, "<<" turns into "<<=" when followed by an =.
+ aci_avoid_equal = 4
+ };
+
+ /// TokenInfo - This array contains information for each token on what
+ /// action to take when avoiding concatenation of tokens in the AvoidConcat
+ /// method.
+ char TokenInfo[tok::NUM_TOKENS];
+ public:
+ TokenConcatenation(Preprocessor &PP);
+
+ bool AvoidConcat(const Token &PrevTok, 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;
+ };
+ } // end clang namespace
+
+#endif
diff --git a/include/clang/Lex/TokenLexer.h b/include/clang/Lex/TokenLexer.h
new file mode 100644
index 000000000000..c0a61cf93ee5
--- /dev/null
+++ b/include/clang/Lex/TokenLexer.h
@@ -0,0 +1,154 @@
+//===--- TokenLexer.h - Lex from a token buffer -----------------*- 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 TokenLexer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOKENLEXER_H
+#define LLVM_CLANG_TOKENLEXER_H
+
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+ class MacroInfo;
+ class Preprocessor;
+ class Token;
+ class MacroArgs;
+
+/// TokenLexer - This implements a lexer that returns token from a macro body
+/// or token stream instead of lexing from a character buffer. This is used for
+/// macro expansion and _Pragma handling, for example.
+///
+class TokenLexer {
+ /// Macro - The macro we are expanding from. This is null if expanding a
+ /// token stream.
+ ///
+ MacroInfo *Macro;
+
+ /// ActualArgs - The actual arguments specified for a function-like macro, or
+ /// null. The TokenLexer owns the pointed-to object.
+ MacroArgs *ActualArgs;
+
+ /// PP - The current preprocessor object we are expanding for.
+ ///
+ Preprocessor &PP;
+
+ /// Tokens - This is the pointer to an array of tokens that the macro is
+ /// defined to, with arguments expanded for function-like macros. If this is
+ /// a token stream, these are the tokens we are returning. This points into
+ /// the macro definition we are lexing from, a scratch buffer allocated from
+ /// the preprocessor's bump pointer allocator, or some other buffer that we
+ /// may or may not own (depending on OwnsTokens).
+ const Token *Tokens;
+
+ /// NumTokens - This is the length of the Tokens array.
+ ///
+ unsigned NumTokens;
+
+ /// CurToken - This is the next token that Lex will return.
+ ///
+ unsigned CurToken;
+
+ /// InstantiateLocStart/End - The source location range where this macro was
+ /// instantiated.
+ SourceLocation InstantiateLocStart, InstantiateLocEnd;
+
+ /// Lexical information about the expansion point of the macro: the identifier
+ /// that the macro expanded from had these properties.
+ bool AtStartOfLine : 1;
+ bool HasLeadingSpace : 1;
+
+ /// OwnsTokens - This is true if this TokenLexer allocated the Tokens
+ /// array, and thus needs to free it when destroyed. For simple object-like
+ /// macros (for example) we just point into the token buffer of the macro
+ /// definition, we don't make a copy of it.
+ bool OwnsTokens : 1;
+
+ /// DisableMacroExpansion - This is true when tokens lexed from the TokenLexer
+ /// should not be subject to further macro expansion.
+ bool DisableMacroExpansion : 1;
+
+ TokenLexer(const TokenLexer&); // DO NOT IMPLEMENT
+ void operator=(const TokenLexer&); // DO NOT IMPLEMENT
+public:
+ /// Create a TokenLexer for the specified macro with the specified actual
+ /// arguments. Note that this ctor takes ownership of the ActualArgs pointer.
+ /// ILEnd specifies the location of the ')' for a function-like macro or the
+ /// identifier for an object-like macro.
+ TokenLexer(Token &Tok, SourceLocation ILEnd, MacroArgs *ActualArgs,
+ Preprocessor &pp)
+ : Macro(0), ActualArgs(0), PP(pp), OwnsTokens(false) {
+ Init(Tok, ILEnd, ActualArgs);
+ }
+
+ /// Init - Initialize this TokenLexer to expand from the specified macro
+ /// with the specified argument information. Note that this ctor takes
+ /// ownership of the ActualArgs pointer. ILEnd specifies the location of the
+ /// ')' for a function-like macro or the identifier for an object-like macro.
+ void Init(Token &Tok, SourceLocation ILEnd, MacroArgs *ActualArgs);
+
+ /// Create a TokenLexer for the specified token stream. If 'OwnsTokens' is
+ /// specified, this takes ownership of the tokens and delete[]'s them when
+ /// the token lexer is empty.
+ TokenLexer(const Token *TokArray, unsigned NumToks, bool DisableExpansion,
+ bool ownsTokens, Preprocessor &pp)
+ : Macro(0), ActualArgs(0), PP(pp), OwnsTokens(false) {
+ Init(TokArray, NumToks, DisableExpansion, ownsTokens);
+ }
+
+ /// Init - Initialize this TokenLexer with the specified token stream.
+ /// This does not take ownership of the specified token vector.
+ ///
+ /// DisableExpansion is true when macro expansion of tokens lexed from this
+ /// stream should be disabled.
+ void Init(const Token *TokArray, unsigned NumToks,
+ bool DisableMacroExpansion, bool OwnsTokens);
+
+ ~TokenLexer() { destroy(); }
+
+ /// isNextTokenLParen - If the next token lexed will pop this macro off the
+ /// expansion stack, return 2. If the next unexpanded token is a '(', return
+ /// 1, otherwise return 0.
+ unsigned isNextTokenLParen() const;
+
+ /// Lex - Lex and return a token from this macro stream.
+ void Lex(Token &Tok);
+
+private:
+ void destroy();
+
+ /// isAtEnd - Return true if the next lex call will pop this macro off the
+ /// include stack.
+ bool isAtEnd() const {
+ return CurToken == NumTokens;
+ }
+
+ /// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ##
+ /// operator. Read the ## and RHS, and paste the LHS/RHS together. If there
+ /// are is another ## after it, chomp it iteratively. Return the result as
+ /// Tok. If this returns true, the caller should immediately return the
+ /// token.
+ bool PasteTokens(Token &Tok);
+
+ /// Expand the arguments of a function-like macro so that we can quickly
+ /// return preexpanded tokens from Tokens.
+ void ExpandFunctionArguments();
+
+ /// HandleMicrosoftCommentPaste - In microsoft compatibility mode, /##/ pastes
+ /// together to form a comment that comments out everything in the current
+ /// macro, other active macros, and anything left on the current physical
+ /// source line of the instantiated buffer. Handle this by returning the
+ /// first token on the next line.
+ void HandleMicrosoftCommentPaste(Token &Tok);
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Makefile b/include/clang/Makefile
new file mode 100644
index 000000000000..82a16d53ea33
--- /dev/null
+++ b/include/clang/Makefile
@@ -0,0 +1,4 @@
+LEVEL = ../../../..
+DIRS := Basic
+
+include $(LEVEL)/Makefile.common
diff --git a/include/clang/Parse/AccessSpecifier.h b/include/clang/Parse/AccessSpecifier.h
new file mode 100644
index 000000000000..8d2cee8ea43a
--- /dev/null
+++ b/include/clang/Parse/AccessSpecifier.h
@@ -0,0 +1,30 @@
+//===--- AccessSpecifier.h - C++ Access Specifiers -*- 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 interfaces used for C++ access specifiers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PARSE_ACCESS_SPECIFIER_H
+#define LLVM_CLANG_PARSE_ACCESS_SPECIFIER_H
+
+namespace clang {
+
+/// AccessSpecifier - A C++ access specifier (none, public, private,
+/// protected).
+enum AccessSpecifier {
+ AS_none,
+ AS_public,
+ AS_protected,
+ AS_private
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
new file mode 100644
index 000000000000..5c23f9ac6147
--- /dev/null
+++ b/include/clang/Parse/Action.h
@@ -0,0 +1,1839 @@
+//===--- Action.h - Parser Action 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 Action and EmptyAction interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PARSE_ACTION_H
+#define LLVM_CLANG_PARSE_ACTION_H
+
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/TemplateKinds.h"
+#include "clang/Basic/TypeTraits.h"
+#include "clang/Parse/AccessSpecifier.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Ownership.h"
+#include "llvm/Support/PrettyStackTrace.h"
+
+namespace clang {
+ // Semantic.
+ class DeclSpec;
+ class ObjCDeclSpec;
+ class CXXScopeSpec;
+ class Declarator;
+ class AttributeList;
+ struct FieldDeclarator;
+ // Parse.
+ class Scope;
+ class Action;
+ class Selector;
+ class Designation;
+ class InitListDesignations;
+ // Lex.
+ class Preprocessor;
+ class Token;
+
+ // We can re-use the low bit of expression, statement, base, and
+ // member-initializer pointers for the "invalid" flag of
+ // ActionResult.
+ template<> struct IsResultPtrLowBitFree<0> { static const bool value = true;};
+ template<> struct IsResultPtrLowBitFree<1> { static const bool value = true;};
+ template<> struct IsResultPtrLowBitFree<3> { static const bool value = true;};
+ template<> struct IsResultPtrLowBitFree<4> { static const bool value = true;};
+ template<> struct IsResultPtrLowBitFree<5> { static const bool value = true;};
+
+/// Action - As the parser reads the input file and recognizes the productions
+/// of the grammar, it invokes methods on this class to turn the parsed input
+/// into something useful: e.g. a parse tree.
+///
+/// The callback methods that this class provides are phrased as actions that
+/// the parser has just done or is about to do when the method is called. They
+/// are not requests that the actions module do the specified action.
+///
+/// All of the methods here are optional except getTypeName() and
+/// isCurrentClassName(), which must be specified in order for the
+/// parse to complete accurately. The MinimalAction class does this
+/// bare-minimum of tracking to implement this functionality.
+class Action : public ActionBase {
+public:
+ /// Out-of-line virtual destructor to provide home for this class.
+ virtual ~Action();
+
+ // Types - Though these don't actually enforce strong typing, they document
+ // what types are required to be identical for the actions.
+ typedef ActionBase::ExprTy ExprTy;
+ typedef ActionBase::StmtTy StmtTy;
+
+ /// Expr/Stmt/Type/BaseResult - Provide a unique type to wrap
+ /// ExprTy/StmtTy/TypeTy/BaseTy, providing strong typing and
+ /// allowing for failure.
+ typedef ActionResult<0> ExprResult;
+ typedef ActionResult<1> StmtResult;
+ typedef ActionResult<2> TypeResult;
+ typedef ActionResult<3> BaseResult;
+ typedef ActionResult<4> MemInitResult;
+ typedef ActionResult<5, DeclPtrTy> DeclResult;
+
+ /// Same, but with ownership.
+ typedef ASTOwningResult<&ActionBase::DeleteExpr> OwningExprResult;
+ typedef ASTOwningResult<&ActionBase::DeleteStmt> OwningStmtResult;
+ // Note that these will replace ExprResult and StmtResult when the transition
+ // is complete.
+
+ /// Single expressions or statements as arguments.
+#if !defined(DISABLE_SMART_POINTERS)
+ typedef ASTOwningResult<&ActionBase::DeleteExpr> ExprArg;
+ typedef ASTOwningResult<&ActionBase::DeleteStmt> StmtArg;
+#else
+ typedef ASTOwningPtr<&ActionBase::DeleteExpr> ExprArg;
+ typedef ASTOwningPtr<&ActionBase::DeleteStmt> StmtArg;
+#endif
+
+ /// Multiple expressions or statements as arguments.
+ typedef ASTMultiPtr<&ActionBase::DeleteExpr> MultiExprArg;
+ typedef ASTMultiPtr<&ActionBase::DeleteStmt> MultiStmtArg;
+ typedef ASTMultiPtr<&ActionBase::DeleteTemplateParams> MultiTemplateParamsArg;
+
+ class FullExprArg {
+ public:
+ // FIXME: The const_cast here is ugly. RValue references would make this
+ // much nicer (or we could duplicate a bunch of the move semantics
+ // emulation code from Ownership.h).
+ FullExprArg(const FullExprArg& Other)
+ : Expr(move(const_cast<FullExprArg&>(Other).Expr)) {}
+
+ OwningExprResult release() {
+ return move(Expr);
+ }
+
+ ExprArg* operator->() {
+ return &Expr;
+ }
+
+ private:
+ // FIXME: No need to make the entire Action class a friend when it's just
+ // Action::FullExpr that needs access to the constructor below.
+ friend class Action;
+
+ explicit FullExprArg(ExprArg expr)
+ : Expr(move(expr)) {}
+
+ ExprArg Expr;
+ };
+
+ template<typename T>
+ FullExprArg FullExpr(T &Arg) {
+ return FullExprArg(ActOnFinishFullExpr(move(Arg)));
+ }
+
+ // Utilities for Action implementations to return smart results.
+
+ OwningExprResult ExprError() { return OwningExprResult(*this, true); }
+ OwningStmtResult StmtError() { return OwningStmtResult(*this, true); }
+
+ OwningExprResult ExprError(const DiagnosticBuilder&) { return ExprError(); }
+ OwningStmtResult StmtError(const DiagnosticBuilder&) { return StmtError(); }
+
+ OwningExprResult ExprEmpty() { return OwningExprResult(*this, false); }
+ OwningStmtResult StmtEmpty() { return OwningStmtResult(*this, false); }
+
+ /// Statistics.
+ virtual void PrintStats() const {}
+
+ /// getDeclName - Return a pretty name for the specified decl if possible, or
+ /// an empty string if not. This is used for pretty crash reporting.
+ virtual std::string getDeclName(DeclPtrTy D) { return ""; }
+
+ //===--------------------------------------------------------------------===//
+ // Declaration Tracking Callbacks.
+ //===--------------------------------------------------------------------===//
+
+ /// ConvertDeclToDeclGroup - If the parser has one decl in a context where it
+ /// needs a decl group, it calls this to convert between the two
+ /// representations.
+ virtual DeclGroupPtrTy ConvertDeclToDeclGroup(DeclPtrTy Ptr) {
+ return DeclGroupPtrTy();
+ }
+
+ /// getTypeName - Return non-null if the specified identifier is a type name
+ /// in the current scope.
+ /// An optional CXXScopeSpec can be passed to indicate the C++ scope (class or
+ /// namespace) that the identifier must be a member of.
+ /// i.e. for "foo::bar", 'II' will be "bar" and 'SS' will be "foo::".
+ virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
+ Scope *S, const CXXScopeSpec *SS = 0) = 0;
+
+ /// isTagName() - This method is called *for error recovery purposes only*
+ /// to determine if the specified name is a valid tag name ("struct foo"). If
+ /// so, this returns the TST for the tag corresponding to it (TST_enum,
+ /// TST_union, TST_struct, TST_class). This is used to diagnose cases in C
+ /// where the user forgot to specify the tag.
+ virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S) {
+ return DeclSpec::TST_unspecified;
+ }
+
+ /// isCurrentClassName - Return true if the specified name is the
+ /// name of the innermost C++ class type currently being defined.
+ virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S,
+ const CXXScopeSpec *SS = 0) = 0;
+
+ /// \brief Determines whether the identifier II is a template name
+ /// in the current scope. If so, the kind of template name is
+ /// returned, and \p TemplateDecl receives the declaration. An
+ /// optional CXXScope can be passed to indicate the C++ scope in
+ /// which the identifier will be found.
+ virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
+ TemplateTy &Template,
+ const CXXScopeSpec *SS = 0) = 0;
+
+ /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
+ /// global scope ('::').
+ virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
+ SourceLocation CCLoc) {
+ return 0;
+ }
+
+ /// ActOnCXXNestedNameSpecifier - Called during parsing of a
+ /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
+ /// we want to resolve "bar::". 'SS' is empty or the previously parsed
+ /// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
+ /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
+ /// Returns a CXXScopeTy* object representing the C++ scope.
+ virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
+ const CXXScopeSpec &SS,
+ SourceLocation IdLoc,
+ SourceLocation CCLoc,
+ IdentifierInfo &II) {
+ return 0;
+ }
+
+ /// ActOnCXXNestedNameSpecifier - Called during parsing of a
+ /// nested-name-specifier that involves a template-id, e.g.,
+ /// "foo::bar<int, float>::", and now we need to build a scope
+ /// specifier. \p SS is empty or the previously parsed nested-name
+ /// part ("foo::"), \p Type is the already-parsed class template
+ /// specialization (or other template-id that names a type), \p
+ /// TypeRange is the source range where the type is located, and \p
+ /// CCLoc is the location of the trailing '::'.
+ virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
+ const CXXScopeSpec &SS,
+ TypeTy *Type,
+ SourceRange TypeRange,
+ SourceLocation CCLoc) {
+ return 0;
+ }
+
+ /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
+ /// scope or nested-name-specifier) is parsed, part of a declarator-id.
+ /// After this method is called, according to [C++ 3.4.3p3], names should be
+ /// looked up in the declarator-id's scope, until the declarator is parsed and
+ /// ActOnCXXExitDeclaratorScope is called.
+ /// The 'SS' should be a non-empty valid CXXScopeSpec.
+ virtual void ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
+ }
+
+ /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
+ /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same
+ /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well.
+ /// Used to indicate that names should revert to being looked up in the
+ /// defining scope.
+ virtual void ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
+ }
+
+ /// ActOnDeclarator - This callback is invoked when a declarator is parsed and
+ /// 'Init' specifies the initializer if any. This is for things like:
+ /// "int X = 4" or "typedef int foo".
+ ///
+ virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) {
+ return DeclPtrTy();
+ }
+
+ /// ActOnParamDeclarator - This callback is invoked when a parameter
+ /// declarator is parsed. This callback only occurs for functions
+ /// with prototypes. S is the function prototype scope for the
+ /// parameters (C++ [basic.scope.proto]).
+ virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D) {
+ return DeclPtrTy();
+ }
+
+ /// AddInitializerToDecl - This action is called immediately after
+ /// ActOnDeclarator (when an initializer is present). The code is factored
+ /// this way to make sure we are able to handle the following:
+ /// void func() { int xx = xx; }
+ /// This allows ActOnDeclarator to register "xx" prior to parsing the
+ /// initializer. The declaration above should still result in a warning,
+ /// since the reference to "xx" is uninitialized.
+ virtual void AddInitializerToDecl(DeclPtrTy Dcl, FullExprArg Init) {
+ return;
+ }
+
+ /// SetDeclDeleted - This action is called immediately after ActOnDeclarator
+ /// if =delete is parsed. C++0x [dcl.fct.def]p10
+ /// Note that this can be called even for variable declarations. It's the
+ /// action's job to reject it.
+ virtual void SetDeclDeleted(DeclPtrTy Dcl, SourceLocation DelLoc) {
+ return;
+ }
+
+ /// ActOnUninitializedDecl - This action is called immediately after
+ /// ActOnDeclarator (when an initializer is *not* present).
+ virtual void ActOnUninitializedDecl(DeclPtrTy Dcl) {
+ return;
+ }
+
+ /// FinalizeDeclaratorGroup - After a sequence of declarators are parsed, this
+ /// gives the actions implementation a chance to process the group as a whole.
+ virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec& DS,
+ DeclPtrTy *Group,
+ unsigned NumDecls) {
+ return DeclGroupPtrTy();
+ }
+
+
+ /// @brief Indicates that all K&R-style parameter declarations have
+ /// been parsed prior to a function definition.
+ /// @param S The function prototype scope.
+ /// @param D The function declarator.
+ virtual void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
+ SourceLocation LocAfterDecls) {
+ }
+
+ /// ActOnStartOfFunctionDef - This is called at the start of a function
+ /// definition, instead of calling ActOnDeclarator. The Declarator includes
+ /// information about formal arguments that are part of this function.
+ virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
+ // Default to ActOnDeclarator.
+ return ActOnStartOfFunctionDef(FnBodyScope,
+ ActOnDeclarator(FnBodyScope, D));
+ }
+
+ /// ActOnStartOfFunctionDef - This is called at the start of a function
+ /// definition, after the FunctionDecl has already been created.
+ virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
+ return D;
+ }
+
+ virtual void ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
+ return;
+ }
+
+ /// ActOnFinishFunctionBody - This is called when a function body has
+ /// completed parsing. Decl is returned by ParseStartOfFunctionDef.
+ virtual DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body) {
+ return Decl;
+ }
+
+ virtual DeclPtrTy ActOnFileScopeAsmDecl(SourceLocation Loc,
+ ExprArg AsmString) {
+ return DeclPtrTy();
+ }
+
+ /// ActOnPopScope - This callback is called immediately before the specified
+ /// scope is popped and deleted.
+ virtual void ActOnPopScope(SourceLocation Loc, Scope *S) {}
+
+ /// ActOnTranslationUnitScope - This callback is called once, immediately
+ /// after creating the translation unit scope (in Parser::Initialize).
+ virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {}
+
+ /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
+ /// no declarator (e.g. "struct foo;") is parsed.
+ virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
+ return DeclPtrTy();
+ }
+
+ /// ActOnStartLinkageSpecification - Parsed the beginning of a C++
+ /// linkage specification, including the language and (if present)
+ /// the '{'. ExternLoc is the location of the 'extern', LangLoc is
+ /// the location of the language string literal, which is provided
+ /// by Lang/StrSize. LBraceLoc, if valid, provides the location of
+ /// the '{' brace. Otherwise, this linkage specification does not
+ /// have any braces.
+ virtual DeclPtrTy ActOnStartLinkageSpecification(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation LangLoc,
+ const char *Lang,
+ unsigned StrSize,
+ SourceLocation LBraceLoc) {
+ return DeclPtrTy();
+ }
+
+ /// ActOnFinishLinkageSpecification - Completely the definition of
+ /// the C++ linkage specification LinkageSpec. If RBraceLoc is
+ /// valid, it's the position of the closing '}' brace in a linkage
+ /// specification that uses braces.
+ virtual DeclPtrTy ActOnFinishLinkageSpecification(Scope *S,
+ DeclPtrTy LinkageSpec,
+ SourceLocation RBraceLoc) {
+ return LinkageSpec;
+ }
+
+ /// 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.
+ virtual void ActOnEndOfTranslationUnit() {}
+
+ //===--------------------------------------------------------------------===//
+ // Type Parsing Callbacks.
+ //===--------------------------------------------------------------------===//
+
+ /// ActOnTypeName - A type-name (type-id in C++) was parsed.
+ virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) {
+ return TypeResult();
+ }
+
+ enum TagKind {
+ TK_Reference, // Reference to a tag: 'struct foo *X;'
+ TK_Declaration, // Fwd decl of a tag: 'struct foo;'
+ TK_Definition // Definition of a tag: 'struct foo { int X; } Y;'
+ };
+ virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
+ SourceLocation KWLoc, const CXXScopeSpec &SS,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ AttributeList *Attr, AccessSpecifier AS,
+ bool &OwnedDecl) {
+ // TagType is an instance of DeclSpec::TST, indicating what kind of tag this
+ // is (struct/union/enum/class).
+ return DeclPtrTy();
+ }
+
+ /// Act on @defs() element found when parsing a structure. ClassName is the
+ /// name of the referenced class.
+ virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
+ IdentifierInfo *ClassName,
+ llvm::SmallVectorImpl<DeclPtrTy> &Decls) {}
+ virtual DeclPtrTy ActOnField(Scope *S, DeclPtrTy TagD,
+ SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth) {
+ return DeclPtrTy();
+ }
+
+ virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth,
+ tok::ObjCKeywordKind visibility) {
+ return DeclPtrTy();
+ }
+
+ virtual void ActOnFields(Scope* S, SourceLocation RecLoc, DeclPtrTy TagDecl,
+ DeclPtrTy *Fields, unsigned NumFields,
+ SourceLocation LBrac, SourceLocation RBrac,
+ AttributeList *AttrList) {}
+
+ /// ActOnTagStartDefinition - Invoked when we have entered the
+ /// scope of a tag's definition (e.g., for an enumeration, class,
+ /// struct, or union).
+ virtual void ActOnTagStartDefinition(Scope *S, DeclPtrTy TagDecl) { }
+
+ /// ActOnTagFinishDefinition - Invoked once we have finished parsing
+ /// the definition of a tag (enumeration, class, struct, or union).
+ virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl) { }
+
+ virtual DeclPtrTy ActOnEnumConstant(Scope *S, DeclPtrTy EnumDecl,
+ DeclPtrTy LastEnumConstant,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ SourceLocation EqualLoc, ExprTy *Val) {
+ return DeclPtrTy();
+ }
+ virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
+ SourceLocation RBraceLoc, DeclPtrTy EnumDecl,
+ DeclPtrTy *Elements, unsigned NumElements) {}
+
+ //===--------------------------------------------------------------------===//
+ // Statement Parsing Callbacks.
+ //===--------------------------------------------------------------------===//
+
+ virtual OwningStmtResult ActOnNullStmt(SourceLocation SemiLoc) {
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R,
+ MultiStmtArg Elts,
+ bool isStmtExpr) {
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnDeclStmt(DeclGroupPtrTy Decl,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnExprStmt(FullExprArg Expr) {
+ return OwningStmtResult(*this, Expr->release());
+ }
+
+ /// ActOnCaseStmt - Note that this handles the GNU 'case 1 ... 4' extension,
+ /// which can specify an RHS value. The sub-statement of the case is
+ /// specified in a separate action.
+ virtual OwningStmtResult ActOnCaseStmt(SourceLocation CaseLoc, ExprArg LHSVal,
+ SourceLocation DotDotDotLoc,
+ ExprArg RHSVal,
+ SourceLocation ColonLoc) {
+ return StmtEmpty();
+ }
+
+ /// ActOnCaseStmtBody - This installs a statement as the body of a case.
+ virtual void ActOnCaseStmtBody(StmtTy *CaseStmt, StmtArg SubStmt) {}
+
+ virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt, Scope *CurScope){
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnLabelStmt(SourceLocation IdentLoc,
+ IdentifierInfo *II,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt) {
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc,
+ FullExprArg CondVal, StmtArg ThenVal,
+ SourceLocation ElseLoc,
+ StmtArg ElseVal) {
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond) {
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
+ StmtArg Switch, StmtArg Body) {
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
+ FullExprArg Cond, StmtArg Body) {
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
+ SourceLocation WhileLoc, ExprArg Cond) {
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc,
+ StmtArg First, ExprArg Second,
+ ExprArg Third, SourceLocation RParenLoc,
+ StmtArg Body) {
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc,
+ SourceLocation LParenLoc,
+ StmtArg First, ExprArg Second,
+ SourceLocation RParenLoc, StmtArg Body) {
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnGotoStmt(SourceLocation GotoLoc,
+ SourceLocation LabelLoc,
+ IdentifierInfo *LabelII) {
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc,
+ SourceLocation StarLoc,
+ ExprArg DestExp) {
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnContinueStmt(SourceLocation ContinueLoc,
+ Scope *CurScope) {
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnBreakStmt(SourceLocation GotoLoc,
+ Scope *CurScope) {
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc,
+ FullExprArg RetValExp) {
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnAsmStmt(SourceLocation AsmLoc,
+ bool IsSimple,
+ bool IsVolatile,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ std::string *Names,
+ MultiExprArg Constraints,
+ MultiExprArg Exprs,
+ ExprArg AsmString,
+ MultiExprArg Clobbers,
+ SourceLocation RParenLoc) {
+ return StmtEmpty();
+ }
+
+ // Objective-c statements
+ virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
+ SourceLocation RParen,
+ DeclPtrTy Parm, StmtArg Body,
+ StmtArg CatchList) {
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc,
+ StmtArg Body) {
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
+ StmtArg Try, StmtArg Catch,
+ StmtArg Finally) {
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
+ ExprArg Throw,
+ Scope *CurScope) {
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc,
+ ExprArg SynchExpr,
+ StmtArg SynchBody) {
+ return StmtEmpty();
+ }
+
+ // C++ Statements
+ virtual DeclPtrTy ActOnExceptionDeclarator(Scope *S, Declarator &D) {
+ return DeclPtrTy();
+ }
+
+ virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
+ DeclPtrTy ExceptionDecl,
+ StmtArg HandlerBlock) {
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc,
+ StmtArg TryBlock,
+ MultiStmtArg Handlers) {
+ return StmtEmpty();
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Expression Parsing Callbacks.
+ //===--------------------------------------------------------------------===//
+
+ // Primary Expressions.
+
+ /// \brief Retrieve the source range that corresponds to the given
+ /// expression.
+ virtual SourceRange getExprRange(ExprTy *E) const {
+ return SourceRange();
+ }
+
+ /// ActOnIdentifierExpr - Parse an identifier in expression context.
+ /// 'HasTrailingLParen' indicates whether or not the identifier has a '('
+ /// token immediately after it.
+ /// An optional CXXScopeSpec can be passed to indicate the C++ scope (class or
+ /// namespace) that the identifier must be a member of.
+ /// i.e. for "foo::bar", 'II' will be "bar" and 'SS' will be "foo::".
+ virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
+ IdentifierInfo &II,
+ bool HasTrailingLParen,
+ const CXXScopeSpec *SS = 0,
+ bool isAddressOfOperand = false){
+ return ExprEmpty();
+ }
+
+ /// ActOnOperatorFunctionIdExpr - Parse a C++ overloaded operator
+ /// name (e.g., @c operator+ ) as an expression. This is very
+ /// similar to ActOnIdentifierExpr, except that instead of providing
+ /// an identifier the parser provides the kind of overloaded
+ /// operator that was parsed.
+ virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(
+ Scope *S, SourceLocation OperatorLoc,
+ OverloadedOperatorKind Op,
+ bool HasTrailingLParen, const CXXScopeSpec &SS,
+ bool isAddressOfOperand = false) {
+ return ExprEmpty();
+ }
+
+ /// ActOnCXXConversionFunctionExpr - Parse a C++ conversion function
+ /// name (e.g., @c operator void const *) as an expression. This is
+ /// very similar to ActOnIdentifierExpr, except that instead of
+ /// providing an identifier the parser provides the type of the
+ /// conversion function.
+ virtual OwningExprResult ActOnCXXConversionFunctionExpr(
+ Scope *S, SourceLocation OperatorLoc,
+ TypeTy *Type, bool HasTrailingLParen,
+ const CXXScopeSpec &SS,
+ bool isAddressOfOperand = false) {
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc,
+ tok::TokenKind Kind) {
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnCharacterConstant(const Token &) {
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnNumericConstant(const Token &) {
+ return ExprEmpty();
+ }
+
+ /// ActOnStringLiteral - The specified tokens were lexed as pasted string
+ /// fragments (e.g. "foo" "bar" L"baz").
+ virtual OwningExprResult ActOnStringLiteral(const Token *Toks,
+ unsigned NumToks) {
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R,
+ ExprArg Val) {
+ return move(Val); // Default impl returns operand.
+ }
+
+ // Postfix Expressions.
+ virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
+ tok::TokenKind Kind,
+ ExprArg Input) {
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnArraySubscriptExpr(Scope *S, ExprArg Base,
+ SourceLocation LLoc,
+ ExprArg Idx,
+ SourceLocation RLoc) {
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation MemberLoc,
+ IdentifierInfo &Member,
+ DeclPtrTy ObjCImpDecl) {
+ return ExprEmpty();
+ }
+
+ /// 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. There are guaranteed to be one fewer commas than arguments,
+ /// unless there are zero arguments.
+ virtual OwningExprResult ActOnCallExpr(Scope *S, ExprArg Fn,
+ SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ return ExprEmpty();
+ }
+
+ // Unary Operators. 'Tok' is the token for the operator.
+ virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
+ tok::TokenKind Op, ExprArg Input) {
+ return ExprEmpty();
+ }
+ virtual OwningExprResult
+ ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
+ void *TyOrEx, const SourceRange &ArgRange) {
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParen,
+ TypeTy *Ty,
+ SourceLocation RParen,
+ ExprArg Op) {
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc,
+ MultiExprArg InitList,
+ SourceLocation RParenLoc) {
+ return ExprEmpty();
+ }
+ /// @brief Parsed a C99 designated initializer.
+ ///
+ /// @param Desig Contains the designation with one or more designators.
+ ///
+ /// @param Loc The location of the '=' or ':' prior to the
+ /// initialization expression.
+ ///
+ /// @param GNUSyntax If true, then this designated initializer used
+ /// the deprecated GNU syntax @c fieldname:foo or @c [expr]foo rather
+ /// than the C99 syntax @c .fieldname=foo or @c [expr]=foo.
+ ///
+ /// @param Init The value that the entity (or entities) described by
+ /// the designation will be initialized with.
+ virtual OwningExprResult ActOnDesignatedInitializer(Designation &Desig,
+ SourceLocation Loc,
+ bool GNUSyntax,
+ OwningExprResult Init) {
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
+ SourceLocation RParenLoc, ExprArg Op) {
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc,
+ tok::TokenKind Kind,
+ ExprArg LHS, ExprArg RHS) {
+ return ExprEmpty();
+ }
+
+ /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
+ /// in the case of a the GNU conditional expr extension.
+ virtual OwningExprResult ActOnConditionalOp(SourceLocation QuestionLoc,
+ SourceLocation ColonLoc,
+ ExprArg Cond, ExprArg LHS,
+ ExprArg RHS) {
+ return ExprEmpty();
+ }
+
+ //===---------------------- GNU Extension Expressions -------------------===//
+
+ virtual OwningExprResult ActOnAddrLabel(SourceLocation OpLoc,
+ SourceLocation LabLoc,
+ IdentifierInfo *LabelII) { // "&&foo"
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnStmtExpr(SourceLocation LPLoc, StmtArg SubStmt,
+ SourceLocation RPLoc) { // "({..})"
+ return ExprEmpty();
+ }
+
+ // __builtin_offsetof(type, identifier(.identifier|[expr])*)
+ struct OffsetOfComponent {
+ SourceLocation LocStart, LocEnd;
+ bool isBrackets; // true if [expr], false if .ident
+ union {
+ IdentifierInfo *IdentInfo;
+ ExprTy *E;
+ } U;
+ };
+
+ virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S,
+ SourceLocation BuiltinLoc,
+ SourceLocation TypeLoc,
+ TypeTy *Arg1,
+ OffsetOfComponent *CompPtr,
+ unsigned NumComponents,
+ SourceLocation RParenLoc) {
+ return ExprEmpty();
+ }
+
+ // __builtin_types_compatible_p(type1, type2)
+ virtual OwningExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
+ TypeTy *arg1, TypeTy *arg2,
+ SourceLocation RPLoc) {
+ return ExprEmpty();
+ }
+ // __builtin_choose_expr(constExpr, expr1, expr2)
+ virtual OwningExprResult ActOnChooseExpr(SourceLocation BuiltinLoc,
+ ExprArg cond, ExprArg expr1,
+ ExprArg expr2, SourceLocation RPLoc){
+ return ExprEmpty();
+ }
+
+ // __builtin_va_arg(expr, type)
+ virtual OwningExprResult ActOnVAArg(SourceLocation BuiltinLoc,
+ ExprArg expr, TypeTy *type,
+ SourceLocation RPLoc) {
+ return ExprEmpty();
+ }
+
+ /// ActOnGNUNullExpr - Parsed the GNU __null expression, the token
+ /// for which is at position TokenLoc.
+ virtual OwningExprResult ActOnGNUNullExpr(SourceLocation TokenLoc) {
+ return ExprEmpty();
+ }
+
+ //===------------------------- "Block" Extension ------------------------===//
+
+ /// ActOnBlockStart - This callback is invoked when a block literal is
+ /// started. The result pointer is passed into the block finalizers.
+ virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {}
+
+ /// ActOnBlockArguments - This callback allows processing of block arguments.
+ /// If there are no arguments, this is still invoked.
+ virtual void ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {}
+
+ /// ActOnBlockError - If there is an error parsing a block, this callback
+ /// is invoked to pop the information about the block from the action impl.
+ virtual void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {}
+
+ /// ActOnBlockStmtExpr - This is called when the body of a block statement
+ /// literal was successfully completed. ^(int x){...}
+ virtual OwningExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc,
+ StmtArg Body,
+ Scope *CurScope) {
+ return ExprEmpty();
+ }
+
+ //===------------------------- C++ Declarations -------------------------===//
+
+ /// ActOnStartNamespaceDef - This is called at the start of a namespace
+ /// definition.
+ virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc,
+ IdentifierInfo *Ident,
+ SourceLocation LBrace) {
+ return DeclPtrTy();
+ }
+
+ /// ActOnFinishNamespaceDef - This callback is called after a namespace is
+ /// exited. Decl is returned by ActOnStartNamespaceDef.
+ virtual void ActOnFinishNamespaceDef(DeclPtrTy Dcl, SourceLocation RBrace) {
+ return;
+ }
+
+ /// ActOnUsingDirective - This is called when using-directive is parsed.
+ virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope,
+ SourceLocation UsingLoc,
+ SourceLocation NamespcLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *NamespcName,
+ AttributeList *AttrList);
+
+ /// ActOnNamespaceAliasDef - This is called when a namespace alias definition
+ /// is parsed.
+ virtual DeclPtrTy ActOnNamespaceAliasDef(Scope *CurScope,
+ SourceLocation NamespaceLoc,
+ SourceLocation AliasLoc,
+ IdentifierInfo *Alias,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *Ident) {
+ return DeclPtrTy();
+ }
+
+ /// ActOnParamDefaultArgument - Parse default argument for function parameter
+ virtual void ActOnParamDefaultArgument(DeclPtrTy param,
+ SourceLocation EqualLoc,
+ ExprArg defarg) {
+ }
+
+ /// ActOnParamUnparsedDefaultArgument - We've seen a default
+ /// argument for a function parameter, but we can't parse it yet
+ /// because we're inside a class definition. Note that this default
+ /// argument will be parsed later.
+ virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
+ SourceLocation EqualLoc) { }
+
+ /// ActOnParamDefaultArgumentError - Parsing or semantic analysis of
+ /// the default argument for the parameter param failed.
+ virtual void ActOnParamDefaultArgumentError(DeclPtrTy param) { }
+
+ /// AddCXXDirectInitializerToDecl - This action is called immediately after
+ /// ActOnDeclarator, when a C++ direct initializer is present.
+ /// e.g: "int x(1);"
+ virtual void AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
+ SourceLocation LParenLoc,
+ MultiExprArg Exprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ return;
+ }
+
+ /// \brief Called when we re-enter a template parameter scope.
+ ///
+ /// This action occurs when we are going to parse an member
+ /// function's default arguments or inline definition after the
+ /// outermost class definition has been completed, and when one or
+ /// more of the class definitions enclosing the member function is a
+ /// template. The "entity" in the given scope will be set as it was
+ /// when we entered the scope of the template initially, and should
+ /// be used to, e.g., reintroduce the names of template parameters
+ /// into the current scope so that they can be found by name lookup.
+ ///
+ /// \param S The (new) template parameter scope.
+ ///
+ /// \param Template the class template declaration whose template
+ /// parameters should be reintroduced into the current scope.
+ virtual void ActOnReenterTemplateScope(Scope *S, DeclPtrTy Template) {
+ }
+
+ /// ActOnStartDelayedCXXMethodDeclaration - We have completed
+ /// parsing a top-level (non-nested) C++ class, and we are now
+ /// parsing those parts of the given Method declaration that could
+ /// not be parsed earlier (C++ [class.mem]p2), such as default
+ /// arguments. This action should enter the scope of the given
+ /// Method declaration as if we had just parsed the qualified method
+ /// name. However, it should not bring the parameters into scope;
+ /// that will be performed by ActOnDelayedCXXMethodParameter.
+ virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S,
+ DeclPtrTy Method) {
+ }
+
+ /// ActOnDelayedCXXMethodParameter - We've already started a delayed
+ /// C++ method declaration. We're (re-)introducing the given
+ /// function parameter into scope for use in parsing later parts of
+ /// the method declaration. For example, we could see an
+ /// ActOnParamDefaultArgument event for this parameter.
+ virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy Param) {
+ }
+
+ /// ActOnFinishDelayedCXXMethodDeclaration - We have finished
+ /// processing the delayed method declaration for Method. The method
+ /// declaration is now considered finished. There may be a separate
+ /// ActOnStartOfFunctionDef action later (not necessarily
+ /// immediately!) for this method, if it was also defined inside the
+ /// class body.
+ virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S,
+ DeclPtrTy Method) {
+ }
+
+ /// ActOnStaticAssertDeclaration - Parse a C++0x static_assert declaration.
+ virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
+ ExprArg AssertExpr,
+ ExprArg AssertMessageExpr) {
+ return DeclPtrTy();
+ }
+
+ /// ActOnFriendDecl - This action is called when a friend declaration is
+ /// encountered. Returns false on success.
+ virtual bool ActOnFriendDecl(Scope *S, SourceLocation FriendLoc,
+ DeclPtrTy Dcl) {
+ return false;
+ }
+
+
+ //===------------------------- C++ Expressions --------------------------===//
+
+ /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
+ virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
+ tok::TokenKind Kind,
+ SourceLocation LAngleBracketLoc,
+ TypeTy *Ty,
+ SourceLocation RAngleBracketLoc,
+ SourceLocation LParenLoc,
+ ExprArg Op,
+ SourceLocation RParenLoc) {
+ return ExprEmpty();
+ }
+
+ /// ActOnCXXTypeidOfType - Parse typeid( type-id ).
+ virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc,
+ SourceLocation LParenLoc, bool isType,
+ void *TyOrExpr,
+ SourceLocation RParenLoc) {
+ return ExprEmpty();
+ }
+
+ /// ActOnCXXThis - Parse the C++ 'this' pointer.
+ virtual OwningExprResult ActOnCXXThis(SourceLocation ThisLoc) {
+ return ExprEmpty();
+ }
+
+ /// ActOnCXXBoolLiteral - Parse {true,false} literals.
+ virtual OwningExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc,
+ tok::TokenKind Kind) {
+ return ExprEmpty();
+ }
+
+ /// ActOnCXXNullPtrLiteral - Parse 'nullptr'.
+ virtual OwningExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc) {
+ return ExprEmpty();
+ }
+
+ /// ActOnCXXThrow - Parse throw expressions.
+ virtual OwningExprResult ActOnCXXThrow(SourceLocation OpLoc, ExprArg Op) {
+ return ExprEmpty();
+ }
+
+ /// ActOnCXXTypeConstructExpr - Parse construction of a specified type.
+ /// Can be interpreted either as function-style casting ("int(x)")
+ /// or class type construction ("ClassType(x,y,z)")
+ /// or creation of a value-initialized type ("int()").
+ virtual OwningExprResult ActOnCXXTypeConstructExpr(SourceRange TypeRange,
+ TypeTy *TypeRep,
+ SourceLocation LParenLoc,
+ MultiExprArg Exprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ return ExprEmpty();
+ }
+
+ /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
+ /// C++ if/switch/while/for statement.
+ /// e.g: "if (int x = f()) {...}"
+ virtual OwningExprResult ActOnCXXConditionDeclarationExpr(Scope *S,
+ SourceLocation StartLoc,
+ Declarator &D,
+ SourceLocation EqualLoc,
+ ExprArg AssignExprVal) {
+ return ExprEmpty();
+ }
+
+ /// ActOnCXXNew - Parsed a C++ 'new' expression. UseGlobal is true if the
+ /// new was qualified (::new). In a full new like
+ /// @code new (p1, p2) type(c1, c2) @endcode
+ /// the p1 and p2 expressions will be in PlacementArgs and the c1 and c2
+ /// expressions in ConstructorArgs. The type is passed as a declarator.
+ virtual OwningExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
+ SourceLocation PlacementLParen,
+ MultiExprArg PlacementArgs,
+ SourceLocation PlacementRParen,
+ bool ParenTypeId, Declarator &D,
+ SourceLocation ConstructorLParen,
+ MultiExprArg ConstructorArgs,
+ SourceLocation ConstructorRParen) {
+ return ExprEmpty();
+ }
+
+ /// ActOnCXXDelete - Parsed a C++ 'delete' expression. UseGlobal is true if
+ /// the delete was qualified (::delete). ArrayForm is true if the array form
+ /// was used (delete[]).
+ virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc,
+ bool UseGlobal, bool ArrayForm,
+ ExprArg Operand) {
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
+ SourceLocation KWLoc,
+ SourceLocation LParen,
+ TypeTy *Ty,
+ SourceLocation RParen) {
+ return ExprEmpty();
+ }
+
+
+ /// ActOnFinishFullExpr - Called whenever a full expression has been parsed.
+ /// (C++ [intro.execution]p12).
+ virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr) {
+ return move(Expr);
+ }
+
+ //===---------------------------- C++ Classes ---------------------------===//
+ /// ActOnBaseSpecifier - Parsed a base specifier
+ virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl,
+ SourceRange SpecifierRange,
+ bool Virtual, AccessSpecifier Access,
+ TypeTy *basetype,
+ SourceLocation BaseLoc) {
+ return BaseResult();
+ }
+
+ virtual void ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
+ unsigned NumBases) {
+ }
+
+ /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
+ /// declarator is parsed. 'AS' is the access specifier, 'BitfieldWidth'
+ /// specifies the bitfield width if there is one and 'Init' specifies the
+ /// initializer if any. 'Deleted' is true if there's a =delete
+ /// specifier on the function.
+ virtual DeclPtrTy ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS,
+ Declarator &D,
+ ExprTy *BitfieldWidth,
+ ExprTy *Init,
+ bool Deleted = false) {
+ return DeclPtrTy();
+ }
+
+ virtual MemInitResult ActOnMemInitializer(DeclPtrTy ConstructorDecl,
+ Scope *S,
+ IdentifierInfo *MemberOrBase,
+ SourceLocation IdLoc,
+ SourceLocation LParenLoc,
+ ExprTy **Args, unsigned NumArgs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ return true;
+ }
+
+ /// ActOnMemInitializers - This is invoked when all of the member
+ /// initializers of a constructor have been parsed. ConstructorDecl
+ /// is the function declaration (which will be a C++ constructor in
+ /// a well-formed program), ColonLoc is the location of the ':' that
+ /// starts the constructor initializer, and MemInit/NumMemInits
+ /// contains the individual member (and base) initializers.
+ virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
+ SourceLocation ColonLoc,
+ MemInitTy **MemInits, unsigned NumMemInits){
+ }
+
+ /// ActOnFinishCXXMemberSpecification - Invoked after all member declarators
+ /// are parsed but *before* parsing of inline method definitions.
+ virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
+ DeclPtrTy TagDecl,
+ SourceLocation LBrac,
+ SourceLocation RBrac) {
+ }
+
+ //===---------------------------C++ Templates----------------------------===//
+
+ /// ActOnTypeParameter - Called when a C++ template type parameter
+ /// (e.g., "typename T") has been parsed. Typename specifies whether
+ /// the keyword "typename" was used to declare the type parameter
+ /// (otherwise, "class" was used), and KeyLoc is the location of the
+ /// "class" or "typename" keyword. ParamName is the name of the
+ /// parameter (NULL indicates an unnamed template parameter) and
+ /// ParamNameLoc is the location of the parameter name (if any).
+ /// If the type parameter has a default argument, it will be added
+ /// later via ActOnTypeParameterDefault. Depth and Position provide
+ /// the number of enclosing templates (see
+ /// ActOnTemplateParameterList) and the number of previous
+ /// parameters within this template parameter list.
+ virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename,
+ SourceLocation KeyLoc,
+ IdentifierInfo *ParamName,
+ SourceLocation ParamNameLoc,
+ unsigned Depth, unsigned Position) {
+ return DeclPtrTy();
+ }
+
+ /// ActOnTypeParameterDefault - Adds a default argument (the type
+ /// Default) to the given template type parameter (TypeParam).
+ virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam,
+ SourceLocation EqualLoc,
+ SourceLocation DefaultLoc,
+ TypeTy *Default) {
+ }
+
+ /// ActOnNonTypeTemplateParameter - Called when a C++ non-type
+ /// template parameter (e.g., "int Size" in "template<int Size>
+ /// class Array") has been parsed. S is the current scope and D is
+ /// the parsed declarator. Depth and Position provide the number of
+ /// enclosing templates (see
+ /// ActOnTemplateParameterList) and the number of previous
+ /// parameters within this template parameter list.
+ virtual DeclPtrTy ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
+ unsigned Depth,
+ unsigned Position) {
+ return DeclPtrTy();
+ }
+
+ /// \brief Adds a default argument to the given non-type template
+ /// parameter.
+ virtual void ActOnNonTypeTemplateParameterDefault(DeclPtrTy TemplateParam,
+ SourceLocation EqualLoc,
+ ExprArg Default) {
+ }
+
+ /// ActOnTemplateTemplateParameter - Called when a C++ template template
+ /// parameter (e.g., "int T" in "template<template <typename> class T> class
+ /// Array") has been parsed. TmpLoc is the location of the "template" keyword,
+ /// TemplateParams is the sequence of parameters required by the template,
+ /// ParamName is the name of the parameter (null if unnamed), and ParamNameLoc
+ /// is the source location of the identifier (if given).
+ virtual DeclPtrTy ActOnTemplateTemplateParameter(Scope *S,
+ SourceLocation TmpLoc,
+ TemplateParamsTy *Params,
+ IdentifierInfo *ParamName,
+ SourceLocation ParamNameLoc,
+ unsigned Depth,
+ unsigned Position) {
+ return DeclPtrTy();
+ }
+
+ /// \brief Adds a default argument to the given template template
+ /// parameter.
+ virtual void ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParam,
+ SourceLocation EqualLoc,
+ ExprArg Default) {
+ }
+
+ /// ActOnTemplateParameterList - Called when a complete template
+ /// parameter list has been parsed, e.g.,
+ ///
+ /// @code
+ /// export template<typename T, T Size>
+ /// @endcode
+ ///
+ /// Depth is the number of enclosing template parameter lists. This
+ /// value does not include templates from outer scopes. For example:
+ ///
+ /// @code
+ /// template<typename T> // depth = 0
+ /// class A {
+ /// template<typename U> // depth = 0
+ /// class B;
+ /// };
+ ///
+ /// template<typename T> // depth = 0
+ /// template<typename U> // depth = 1
+ /// class A<T>::B { ... };
+ /// @endcode
+ ///
+ /// ExportLoc, if valid, is the position of the "export"
+ /// keyword. Otherwise, "export" was not specified.
+ /// TemplateLoc is the position of the template keyword, LAngleLoc
+ /// is the position of the left angle bracket, and RAngleLoc is the
+ /// position of the corresponding right angle bracket.
+ /// Params/NumParams provides the template parameters that were
+ /// parsed as part of the template-parameter-list.
+ virtual TemplateParamsTy *
+ ActOnTemplateParameterList(unsigned Depth,
+ SourceLocation ExportLoc,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ DeclPtrTy *Params, unsigned NumParams,
+ SourceLocation RAngleLoc) {
+ return 0;
+ }
+
+ /// \brief Process the declaration or definition of a class template
+ /// with the given template parameter lists.
+ virtual DeclResult
+ ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
+ SourceLocation KWLoc, const CXXScopeSpec &SS,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ AttributeList *Attr,
+ MultiTemplateParamsArg TemplateParameterLists,
+ AccessSpecifier AS) {
+ return DeclResult();
+ }
+
+ /// \brief Form a type from a template and a list of template
+ /// arguments.
+ ///
+ /// This action merely forms the type for the template-id, possibly
+ /// checking well-formedness of the template arguments. It does not
+ /// imply the declaration of any entity.
+ ///
+ /// \param Template A template whose specialization results in a
+ /// type, e.g., a class template or template template parameter.
+ ///
+ /// \param IsSpecialization true when we are naming the class
+ /// template specialization as part of an explicit class
+ /// specialization or class template partial specialization.
+ virtual TypeResult ActOnTemplateIdType(TemplateTy Template,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgs,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc) {
+ return TypeResult();
+ };
+
+ /// \brief Form a dependent template name.
+ ///
+ /// This action forms a dependent template name given the template
+ /// name and its (presumably dependent) scope specifier. For
+ /// example, given "MetaFun::template apply", the scope specifier \p
+ /// SS will be "MetaFun::", \p TemplateKWLoc contains the location
+ /// of the "template" keyword, and "apply" is the \p Name.
+ virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
+ const IdentifierInfo &Name,
+ SourceLocation NameLoc,
+ const CXXScopeSpec &SS) {
+ return TemplateTy();
+ }
+
+ /// \brief Process the declaration or definition of an explicit
+ /// class template specialization or a class template partial
+ /// specialization.
+ ///
+ /// This routine is invoked when an explicit class template
+ /// specialization or a class template partial specialization is
+ /// declared or defined, to introduce the (partial) specialization
+ /// and produce a declaration for it. In the following example,
+ /// ActOnClassTemplateSpecialization will be invoked for the
+ /// declarations at both A and B:
+ ///
+ /// \code
+ /// template<typename T> class X;
+ /// template<> class X<int> { }; // A: explicit specialization
+ /// template<typename T> class X<T*> { }; // B: partial specialization
+ /// \endcode
+ ///
+ /// Note that it is the job of semantic analysis to determine which
+ /// of the two cases actually occurred in the source code, since
+ /// they are parsed through the same path. The formulation of the
+ /// template parameter lists describes which case we are in.
+ ///
+ /// \param S the current scope
+ ///
+ /// \param TagSpec whether this declares a class, struct, or union
+ /// (template)
+ ///
+ /// \param TK whether this is a declaration or a definition
+ ///
+ /// \param KWLoc the location of the 'class', 'struct', or 'union'
+ /// keyword.
+ ///
+ /// \param SS the scope specifier preceding the template-id
+ ///
+ /// \param Template the declaration of the class template that we
+ /// are specializing.
+ ///
+ /// \param Attr attributes on the specialization
+ ///
+ /// \param TemplateParameterLists the set of template parameter
+ /// lists that apply to this declaration. In a well-formed program,
+ /// the number of template parameter lists will be one more than the
+ /// number of template-ids in the scope specifier. However, it is
+ /// common for users to provide the wrong number of template
+ /// parameter lists (such as a missing \c template<> prior to a
+ /// specialization); the parser does not check this condition.
+ virtual DeclResult
+ ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
+ SourceLocation KWLoc,
+ const CXXScopeSpec &SS,
+ TemplateTy Template,
+ SourceLocation TemplateNameLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgs,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc,
+ AttributeList *Attr,
+ MultiTemplateParamsArg TemplateParameterLists) {
+ return DeclResult();
+ }
+
+ /// \brief Process the explicit instantiation of a class template
+ /// specialization.
+ ///
+ /// This routine is invoked when an explicit instantiation of a
+ /// class template specialization is encountered. In the following
+ /// example, ActOnExplicitInstantiation will be invoked to force the
+ /// instantiation of X<int>:
+ ///
+ /// \code
+ /// template<typename T> class X { /* ... */ };
+ /// template class X<int>; // explicit instantiation
+ /// \endcode
+ ///
+ /// \param S the current scope
+ ///
+ /// \param TemplateLoc the location of the 'template' keyword that
+ /// specifies that this is an explicit instantiation.
+ ///
+ /// \param TagSpec whether this declares a class, struct, or union
+ /// (template).
+ ///
+ /// \param KWLoc the location of the 'class', 'struct', or 'union'
+ /// keyword.
+ ///
+ /// \param SS the scope specifier preceding the template-id.
+ ///
+ /// \param Template the declaration of the class template that we
+ /// are instantiation.
+ ///
+ /// \param LAngleLoc the location of the '<' token in the template-id.
+ ///
+ /// \param TemplateArgs the template arguments used to form the
+ /// template-id.
+ ///
+ /// \param TemplateArgLocs the locations of the template arguments.
+ ///
+ /// \param RAngleLoc the location of the '>' token in the template-id.
+ ///
+ /// \param Attr attributes that apply to this instantiation.
+ virtual DeclResult
+ ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
+ unsigned TagSpec,
+ SourceLocation KWLoc,
+ const CXXScopeSpec &SS,
+ TemplateTy Template,
+ SourceLocation TemplateNameLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgs,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc,
+ AttributeList *Attr) {
+ return DeclResult();
+ }
+
+ /// \brief Process the explicit instantiation of a member class of a
+ /// class template specialization.
+ ///
+ /// This routine is invoked when an explicit instantiation of a
+ /// member class of a class template specialization is
+ /// encountered. In the following example,
+ /// ActOnExplicitInstantiation will be invoked to force the
+ /// instantiation of X<int>::Inner:
+ ///
+ /// \code
+ /// template<typename T> class X { class Inner { /* ... */}; };
+ /// template class X<int>::Inner; // explicit instantiation
+ /// \endcode
+ ///
+ /// \param S the current scope
+ ///
+ /// \param TemplateLoc the location of the 'template' keyword that
+ /// specifies that this is an explicit instantiation.
+ ///
+ /// \param TagSpec whether this declares a class, struct, or union
+ /// (template).
+ ///
+ /// \param KWLoc the location of the 'class', 'struct', or 'union'
+ /// keyword.
+ ///
+ /// \param SS the scope specifier preceding the template-id.
+ ///
+ /// \param Template the declaration of the class template that we
+ /// are instantiation.
+ ///
+ /// \param LAngleLoc the location of the '<' token in the template-id.
+ ///
+ /// \param TemplateArgs the template arguments used to form the
+ /// template-id.
+ ///
+ /// \param TemplateArgLocs the locations of the template arguments.
+ ///
+ /// \param RAngleLoc the location of the '>' token in the template-id.
+ ///
+ /// \param Attr attributes that apply to this instantiation.
+ virtual DeclResult
+ ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
+ unsigned TagSpec,
+ SourceLocation KWLoc,
+ const CXXScopeSpec &SS,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ AttributeList *Attr) {
+ return DeclResult();
+ }
+
+ /// \brief Called when the parser has parsed a C++ typename
+ /// specifier that ends in an identifier, e.g., "typename T::type".
+ ///
+ /// \param TypenameLoc the location of the 'typename' keyword
+ /// \param SS the nested-name-specifier following the typename (e.g., 'T::').
+ /// \param II the identifier we're retrieving (e.g., 'type' in the example).
+ /// \param IdLoc the location of the identifier.
+ virtual TypeResult
+ ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
+ const IdentifierInfo &II, SourceLocation IdLoc) {
+ return TypeResult();
+ }
+
+ /// \brief Called when the parser has parsed a C++ typename
+ /// specifier that ends in a template-id, e.g.,
+ /// "typename MetaFun::template apply<T1, T2>".
+ ///
+ /// \param TypenameLoc the location of the 'typename' keyword
+ /// \param SS the nested-name-specifier following the typename (e.g., 'T::').
+ /// \param TemplateLoc the location of the 'template' keyword, if any.
+ /// \param Ty the type that the typename specifier refers to.
+ virtual TypeResult
+ ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
+ SourceLocation TemplateLoc, TypeTy *Ty) {
+ return TypeResult();
+ }
+
+ //===----------------------- Obj-C Declarations -------------------------===//
+
+ // ActOnStartClassInterface - this action is called immediately after parsing
+ // the prologue for a class interface (before parsing the instance
+ // variables). Instance variables are processed by ActOnFields().
+ virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLoc,
+ IdentifierInfo *SuperName,
+ SourceLocation SuperLoc,
+ const DeclPtrTy *ProtoRefs,
+ unsigned NumProtoRefs,
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList) {
+ return DeclPtrTy();
+ }
+
+ /// ActOnCompatiblityAlias - this action is called after complete parsing of
+ /// @compaatibility_alias declaration. It sets up the alias relationships.
+ virtual DeclPtrTy ActOnCompatiblityAlias(
+ SourceLocation AtCompatibilityAliasLoc,
+ IdentifierInfo *AliasName, SourceLocation AliasLocation,
+ IdentifierInfo *ClassName, SourceLocation ClassLocation) {
+ return DeclPtrTy();
+ }
+
+ // ActOnStartProtocolInterface - this action is called immdiately after
+ // parsing the prologue for a protocol interface.
+ virtual DeclPtrTy ActOnStartProtocolInterface(SourceLocation AtProtoLoc,
+ IdentifierInfo *ProtocolName,
+ SourceLocation ProtocolLoc,
+ const DeclPtrTy *ProtoRefs,
+ unsigned NumProtoRefs,
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList) {
+ return DeclPtrTy();
+ }
+ // ActOnStartCategoryInterface - this action is called immdiately after
+ // parsing the prologue for a category interface.
+ virtual DeclPtrTy ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLoc,
+ IdentifierInfo *CategoryName,
+ SourceLocation CategoryLoc,
+ const DeclPtrTy *ProtoRefs,
+ unsigned NumProtoRefs,
+ SourceLocation EndProtoLoc) {
+ return DeclPtrTy();
+ }
+ // ActOnStartClassImplementation - this action is called immdiately after
+ // parsing the prologue for a class implementation. Instance variables are
+ // processed by ActOnFields().
+ virtual DeclPtrTy ActOnStartClassImplementation(
+ SourceLocation AtClassImplLoc,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLoc,
+ IdentifierInfo *SuperClassname,
+ SourceLocation SuperClassLoc) {
+ return DeclPtrTy();
+ }
+ // ActOnStartCategoryImplementation - this action is called immdiately after
+ // parsing the prologue for a category implementation.
+ virtual DeclPtrTy ActOnStartCategoryImplementation(
+ SourceLocation AtCatImplLoc,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLoc,
+ IdentifierInfo *CatName,
+ SourceLocation CatLoc) {
+ return DeclPtrTy();
+ }
+ // ActOnPropertyImplDecl - called for every property implementation
+ virtual DeclPtrTy ActOnPropertyImplDecl(
+ SourceLocation AtLoc, // location of the @synthesize/@dynamic
+ SourceLocation PropertyNameLoc, // location for the property name
+ bool ImplKind, // true for @synthesize, false for
+ // @dynamic
+ DeclPtrTy ClassImplDecl, // class or category implementation
+ IdentifierInfo *propertyId, // name of property
+ IdentifierInfo *propertyIvar) { // name of the ivar
+ return DeclPtrTy();
+ }
+
+ struct ObjCArgInfo {
+ IdentifierInfo *Name;
+ SourceLocation NameLoc;
+ // The Type is null if no type was specified, and the DeclSpec is invalid
+ // in this case.
+ TypeTy *Type;
+ ObjCDeclSpec DeclSpec;
+
+ /// ArgAttrs - Attribute list for this argument.
+ AttributeList *ArgAttrs;
+ };
+
+ // ActOnMethodDeclaration - called for all method declarations.
+ virtual DeclPtrTy ActOnMethodDeclaration(
+ SourceLocation BeginLoc, // location of the + or -.
+ SourceLocation EndLoc, // location of the ; or {.
+ tok::TokenKind MethodType, // tok::minus for instance, tok::plus for class.
+ DeclPtrTy ClassDecl, // class this methods belongs to.
+ ObjCDeclSpec &ReturnQT, // for return type's in inout etc.
+ TypeTy *ReturnType, // the method return type.
+ Selector Sel, // a unique name for the method.
+ ObjCArgInfo *ArgInfo, // ArgInfo: Has 'Sel.getNumArgs()' entries.
+ llvm::SmallVectorImpl<Declarator> &Cdecls, // c-style args
+ AttributeList *MethodAttrList, // optional
+ // tok::objc_not_keyword, tok::objc_optional, tok::objc_required
+ tok::ObjCKeywordKind impKind,
+ bool isVariadic = false) {
+ return DeclPtrTy();
+ }
+ // ActOnAtEnd - called to mark the @end. For declarations (interfaces,
+ // protocols, categories), the parser passes all methods/properties.
+ // For class implementations, these values default to 0. For implementations,
+ // methods are processed incrementally (by ActOnMethodDeclaration above).
+ virtual void ActOnAtEnd(SourceLocation AtEndLoc,
+ DeclPtrTy classDecl,
+ DeclPtrTy *allMethods = 0,
+ unsigned allNum = 0,
+ DeclPtrTy *allProperties = 0,
+ unsigned pNum = 0,
+ DeclGroupPtrTy *allTUVars = 0,
+ unsigned tuvNum = 0) {
+ }
+ // ActOnProperty - called to build one property AST
+ virtual DeclPtrTy ActOnProperty(Scope *S, SourceLocation AtLoc,
+ FieldDeclarator &FD, ObjCDeclSpec &ODS,
+ Selector GetterSel, Selector SetterSel,
+ DeclPtrTy ClassCategory,
+ bool *OverridingProperty,
+ tok::ObjCKeywordKind MethodImplKind) {
+ return DeclPtrTy();
+ }
+
+ virtual OwningExprResult ActOnClassPropertyRefExpr(
+ IdentifierInfo &receiverName,
+ IdentifierInfo &propertyName,
+ SourceLocation &receiverNameLoc,
+ SourceLocation &propertyNameLoc) {
+ return ExprEmpty();
+ }
+
+ // ActOnClassMessage - used for both unary and keyword messages.
+ // ArgExprs is optional - if it is present, the number of expressions
+ // is obtained from NumArgs.
+ virtual ExprResult ActOnClassMessage(
+ Scope *S,
+ IdentifierInfo *receivingClassName,
+ Selector Sel,
+ SourceLocation lbrac, SourceLocation receiverLoc,
+ SourceLocation selectorLoc,
+ SourceLocation rbrac,
+ ExprTy **ArgExprs, unsigned NumArgs) {
+ return ExprResult();
+ }
+ // ActOnInstanceMessage - used for both unary and keyword messages.
+ // ArgExprs is optional - if it is present, the number of expressions
+ // is obtained from NumArgs.
+ virtual ExprResult ActOnInstanceMessage(
+ ExprTy *receiver, Selector Sel,
+ SourceLocation lbrac, SourceLocation selectorLoc, SourceLocation rbrac,
+ ExprTy **ArgExprs, unsigned NumArgs) {
+ return ExprResult();
+ }
+ virtual DeclPtrTy ActOnForwardClassDeclaration(
+ SourceLocation AtClassLoc,
+ IdentifierInfo **IdentList,
+ unsigned NumElts) {
+ return DeclPtrTy();
+ }
+ virtual DeclPtrTy ActOnForwardProtocolDeclaration(
+ SourceLocation AtProtocolLoc,
+ const IdentifierLocPair*IdentList,
+ unsigned NumElts,
+ AttributeList *AttrList) {
+ return DeclPtrTy();
+ }
+
+ /// FindProtocolDeclaration - This routine looks up protocols and
+ /// issues error if they are not declared. It returns list of valid
+ /// protocols found.
+ virtual void FindProtocolDeclaration(bool WarnOnDeclarations,
+ const IdentifierLocPair *ProtocolId,
+ unsigned NumProtocols,
+ llvm::SmallVectorImpl<DeclPtrTy> &ResProtos) {
+ }
+
+ //===----------------------- Obj-C Expressions --------------------------===//
+
+ virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
+ ExprTy **Strings,
+ unsigned NumStrings) {
+ return ExprResult();
+ }
+
+ virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc,
+ SourceLocation EncLoc,
+ SourceLocation LParenLoc,
+ TypeTy *Ty,
+ SourceLocation RParenLoc) {
+ return ExprResult();
+ }
+
+ virtual ExprResult ParseObjCSelectorExpression(Selector Sel,
+ SourceLocation AtLoc,
+ SourceLocation SelLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ return ExprResult();
+ }
+
+ virtual ExprResult ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
+ SourceLocation AtLoc,
+ SourceLocation ProtoLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ return ExprResult();
+ }
+
+ //===---------------------------- Pragmas -------------------------------===//
+
+ enum PragmaPackKind {
+ PPK_Default, // #pragma pack([n])
+ PPK_Show, // #pragma pack(show), only supported by MSVC.
+ PPK_Push, // #pragma pack(push, [identifier], [n])
+ PPK_Pop // #pragma pack(pop, [identifier], [n])
+ };
+
+ /// ActOnPragmaPack - Called on well formed #pragma pack(...).
+ virtual void ActOnPragmaPack(PragmaPackKind Kind,
+ IdentifierInfo *Name,
+ ExprTy *Alignment,
+ SourceLocation PragmaLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ return;
+ }
+
+ /// ActOnPragmaPack - Called on well formed #pragma pack(...).
+ virtual void ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs,
+ SourceLocation PragmaLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ return;
+ }
+};
+
+/// MinimalAction - Minimal actions are used by light-weight clients of the
+/// parser that do not need name resolution or significant semantic analysis to
+/// be performed. The actions implemented here are in the form of unresolved
+/// identifiers. By using a simpler interface than the SemanticAction class,
+/// the parser doesn't have to build complex data structures and thus runs more
+/// quickly.
+class MinimalAction : public Action {
+ /// Translation Unit Scope - useful to Objective-C actions that need
+ /// to lookup file scope declarations in the "ordinary" C decl namespace.
+ /// For example, user-defined classes, built-in "id" type, etc.
+ Scope *TUScope;
+ IdentifierTable &Idents;
+ Preprocessor &PP;
+ void *TypeNameInfoTablePtr;
+public:
+ MinimalAction(Preprocessor &pp);
+ ~MinimalAction();
+
+ /// getTypeName - This looks at the IdentifierInfo::FETokenInfo field to
+ /// determine whether the name is a typedef or not in this scope.
+ virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
+ Scope *S, const CXXScopeSpec *SS);
+
+ /// isCurrentClassName - Always returns false, because MinimalAction
+ /// does not support C++ classes with constructors.
+ virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S,
+ const CXXScopeSpec *SS);
+
+ virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
+ TemplateTy &Template,
+ const CXXScopeSpec *SS = 0);
+
+ /// ActOnDeclarator - If this is a typedef declarator, we modify the
+ /// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is
+ /// popped.
+ virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D);
+
+ /// ActOnPopScope - When a scope is popped, if any typedefs are now
+ /// out-of-scope, they are removed from the IdentifierInfo::FETokenInfo field.
+ virtual void ActOnPopScope(SourceLocation Loc, Scope *S);
+ virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S);
+
+ virtual DeclPtrTy ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
+ IdentifierInfo **IdentList,
+ unsigned NumElts);
+
+ virtual DeclPtrTy ActOnStartClassInterface(SourceLocation interLoc,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLoc,
+ IdentifierInfo *SuperName,
+ SourceLocation SuperLoc,
+ const DeclPtrTy *ProtoRefs,
+ unsigned NumProtoRefs,
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList);
+};
+
+/// PrettyStackTraceActionsDecl - If a crash occurs in the parser while parsing
+/// something related to a virtualized decl, include that virtualized decl in
+/// the stack trace.
+class PrettyStackTraceActionsDecl : public llvm::PrettyStackTraceEntry {
+ Action::DeclPtrTy TheDecl;
+ SourceLocation Loc;
+ Action &Actions;
+ SourceManager &SM;
+ const char *Message;
+public:
+ PrettyStackTraceActionsDecl(Action::DeclPtrTy Decl, SourceLocation L,
+ Action &actions, SourceManager &sm,
+ const char *Msg)
+ : TheDecl(Decl), Loc(L), Actions(actions), SM(sm), Message(Msg) {}
+
+ virtual void print(llvm::raw_ostream &OS) const;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h
new file mode 100644
index 000000000000..8225c9d33abb
--- /dev/null
+++ b/include/clang/Parse/AttributeList.h
@@ -0,0 +1,173 @@
+//===--- AttributeList.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the AttributeList class interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ATTRLIST_H
+#define LLVM_CLANG_ATTRLIST_H
+
+#include "clang/Parse/Ownership.h"
+#include "clang/Basic/SourceLocation.h"
+#include <cassert>
+
+namespace clang {
+ class IdentifierInfo;
+ class Action;
+
+/// AttributeList - Represents GCC's __attribute__ declaration. There are
+/// 4 forms of this construct...they are:
+///
+/// 1: __attribute__(( const )). ParmName/Args/NumArgs will all be unused.
+/// 2: __attribute__(( mode(byte) )). ParmName used, Args/NumArgs unused.
+/// 3: __attribute__(( format(printf, 1, 2) )). ParmName/Args/NumArgs all used.
+/// 4: __attribute__(( aligned(16) )). ParmName is unused, Args/Num used.
+///
+class AttributeList {
+ IdentifierInfo *AttrName;
+ SourceLocation AttrLoc;
+ IdentifierInfo *ParmName;
+ SourceLocation ParmLoc;
+ ActionBase::ExprTy **Args;
+ unsigned NumArgs;
+ AttributeList *Next;
+ AttributeList(const AttributeList &); // DO NOT IMPLEMENT
+ void operator=(const AttributeList &); // DO NOT IMPLEMENT
+public:
+ AttributeList(IdentifierInfo *AttrName, SourceLocation AttrLoc,
+ IdentifierInfo *ParmName, SourceLocation ParmLoc,
+ ActionBase::ExprTy **args, unsigned numargs,
+ AttributeList *Next);
+ ~AttributeList();
+
+ enum Kind { // Please keep this list alphabetized.
+ AT_IBOutlet, // Clang-specific.
+ AT_address_space,
+ AT_alias,
+ AT_aligned,
+ AT_always_inline,
+ AT_analyzer_noreturn,
+ AT_annotate,
+ AT_blocks,
+ AT_cleanup,
+ AT_const,
+ AT_constructor,
+ AT_deprecated,
+ AT_destructor,
+ AT_dllexport,
+ AT_dllimport,
+ AT_ext_vector_type,
+ AT_fastcall,
+ AT_format,
+ AT_format_arg,
+ AT_gnu_inline,
+ AT_mode,
+ AT_nodebug,
+ AT_noinline,
+ AT_no_instrument_function,
+ AT_nonnull,
+ AT_noreturn,
+ AT_nothrow,
+ AT_nsobject,
+ AT_objc_exception,
+ AT_cf_returns_retained, // Clang-specific.
+ AT_ns_returns_retained, // Clang-specific.
+ AT_objc_gc,
+ AT_overloadable, // Clang-specific.
+ AT_packed,
+ AT_pure,
+ AT_regparm,
+ AT_section,
+ AT_sentinel,
+ AT_stdcall,
+ AT_transparent_union,
+ AT_unavailable,
+ AT_unused,
+ AT_used,
+ AT_vector_size,
+ AT_visibility,
+ AT_warn_unused_result,
+ AT_weak,
+ AT_weak_import,
+ IgnoredAttribute,
+ UnknownAttribute
+ };
+
+ IdentifierInfo *getName() const { return AttrName; }
+ SourceLocation getLoc() const { return AttrLoc; }
+ IdentifierInfo *getParameterName() const { return ParmName; }
+
+ Kind getKind() const { return getKind(getName()); }
+ static Kind getKind(const IdentifierInfo *Name);
+
+ AttributeList *getNext() const { return Next; }
+ void setNext(AttributeList *N) { Next = N; }
+
+ void addAttributeList(AttributeList *alist) {
+ assert((alist != 0) && "addAttributeList(): alist is null");
+ AttributeList *next = this, *prev;
+ do {
+ prev = next;
+ next = next->getNext();
+ } while (next);
+ prev->setNext(alist);
+ }
+
+ /// getNumArgs - Return the number of actual arguments to this attribute.
+ unsigned getNumArgs() const { return NumArgs; }
+
+ /// getArg - Return the specified argument.
+ ActionBase::ExprTy *getArg(unsigned Arg) const {
+ assert(Arg < NumArgs && "Arg access out of range!");
+ return Args[Arg];
+ }
+
+ class arg_iterator {
+ ActionBase::ExprTy** X;
+ unsigned Idx;
+ public:
+ arg_iterator(ActionBase::ExprTy** x, unsigned idx) : X(x), Idx(idx) {}
+
+ arg_iterator& operator++() {
+ ++Idx;
+ return *this;
+ }
+
+ bool operator==(const arg_iterator& I) const {
+ assert (X == I.X &&
+ "compared arg_iterators are for different argument lists");
+ return Idx == I.Idx;
+ }
+
+ bool operator!=(const arg_iterator& I) const {
+ return !operator==(I);
+ }
+
+ ActionBase::ExprTy* operator*() const {
+ return X[Idx];
+ }
+
+ unsigned getArgNum() const {
+ return Idx+1;
+ }
+ };
+
+ arg_iterator arg_begin() const {
+ return arg_iterator(Args, 0);
+ }
+
+ arg_iterator arg_end() const {
+ return arg_iterator(Args, NumArgs);
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h
new file mode 100644
index 000000000000..a0b9b1e7cc23
--- /dev/null
+++ b/include/clang/Parse/DeclSpec.h
@@ -0,0 +1,1086 @@
+//===--- SemaDeclSpec.h - Declaration Specifier Semantic Analys -*- 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 interfaces used for Declaration Specifiers and Declarators.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PARSE_DECLSPEC_H
+#define LLVM_CLANG_PARSE_DECLSPEC_H
+
+#include "clang/Parse/AttributeList.h"
+#include "clang/Lex/Token.h"
+#include "clang/Basic/OperatorKinds.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+ class LangOptions;
+ class Diagnostic;
+ class IdentifierInfo;
+ class Preprocessor;
+ class Declarator;
+
+/// DeclSpec - This class captures information about "declaration specifiers",
+/// which encompasses storage-class-specifiers, type-specifiers,
+/// type-qualifiers, and function-specifiers.
+class DeclSpec {
+public:
+ // storage-class-specifier
+ enum SCS {
+ SCS_unspecified,
+ SCS_typedef,
+ SCS_extern,
+ SCS_static,
+ SCS_auto,
+ SCS_register,
+ SCS_private_extern,
+ SCS_mutable
+ };
+
+ // type-specifier
+ enum TSW {
+ TSW_unspecified,
+ TSW_short,
+ TSW_long,
+ TSW_longlong
+ };
+
+ enum TSC {
+ TSC_unspecified,
+ TSC_imaginary,
+ TSC_complex
+ };
+
+ enum TSS {
+ TSS_unspecified,
+ TSS_signed,
+ TSS_unsigned
+ };
+
+ enum TST {
+ TST_unspecified,
+ TST_void,
+ TST_char,
+ TST_wchar, // C++ wchar_t
+ TST_int,
+ TST_float,
+ TST_double,
+ TST_bool, // _Bool
+ TST_decimal32, // _Decimal32
+ TST_decimal64, // _Decimal64
+ TST_decimal128, // _Decimal128
+ TST_enum,
+ TST_union,
+ TST_struct,
+ TST_class, // C++ class type
+ TST_typename, // Typedef, C++ class-name or enum name, etc.
+ TST_typeofType,
+ TST_typeofExpr,
+ TST_error // erroneous type
+ };
+
+ // type-qualifiers
+ enum TQ { // NOTE: These flags must be kept in sync with QualType::TQ.
+ TQ_unspecified = 0,
+ TQ_const = 1,
+ TQ_restrict = 2,
+ TQ_volatile = 4
+ };
+
+ /// ParsedSpecifiers - Flags to query which specifiers were applied. This is
+ /// returned by getParsedSpecifiers.
+ enum ParsedSpecifiers {
+ PQ_None = 0,
+ PQ_StorageClassSpecifier = 1,
+ PQ_TypeSpecifier = 2,
+ PQ_TypeQualifier = 4,
+ PQ_FunctionSpecifier = 8
+ };
+
+private:
+
+ // storage-class-specifier
+ /*SCS*/unsigned StorageClassSpec : 3;
+ bool SCS_thread_specified : 1;
+
+ // type-specifier
+ /*TSW*/unsigned TypeSpecWidth : 2;
+ /*TSC*/unsigned TypeSpecComplex : 2;
+ /*TSS*/unsigned TypeSpecSign : 2;
+ /*TST*/unsigned TypeSpecType : 5;
+ bool TypeSpecOwned : 1;
+
+ // type-qualifiers
+ unsigned TypeQualifiers : 3; // Bitwise OR of TQ.
+
+ // function-specifier
+ bool FS_inline_specified : 1;
+ bool FS_virtual_specified : 1;
+ bool FS_explicit_specified : 1;
+
+ // friend-specifier
+ bool Friend_specified : 1;
+
+ /// TypeRep - This contains action-specific information about a specific TST.
+ /// For example, for a typedef or struct, it might contain the declaration for
+ /// these.
+ void *TypeRep;
+
+ // attributes.
+ AttributeList *AttrList;
+
+ // List of protocol qualifiers for objective-c classes. Used for
+ // protocol-qualified interfaces "NString<foo>" and protocol-qualified id
+ // "id<foo>".
+ const ActionBase::DeclPtrTy *ProtocolQualifiers;
+ unsigned NumProtocolQualifiers;
+
+ // SourceLocation info. These are null if the item wasn't specified or if
+ // the setting was synthesized.
+ SourceRange Range;
+
+ SourceLocation StorageClassSpecLoc, SCS_threadLoc;
+ SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc;
+ SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc;
+ SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc;
+ SourceLocation FriendLoc;
+
+ bool BadSpecifier(TST T, const char *&PrevSpec);
+ bool BadSpecifier(TQ T, const char *&PrevSpec);
+ bool BadSpecifier(TSS T, const char *&PrevSpec);
+ bool BadSpecifier(TSC T, const char *&PrevSpec);
+ bool BadSpecifier(TSW T, const char *&PrevSpec);
+ bool BadSpecifier(SCS T, const char *&PrevSpec);
+
+ DeclSpec(const DeclSpec&); // DO NOT IMPLEMENT
+ void operator=(const DeclSpec&); // DO NOT IMPLEMENT
+public:
+
+ DeclSpec()
+ : StorageClassSpec(SCS_unspecified),
+ SCS_thread_specified(false),
+ TypeSpecWidth(TSW_unspecified),
+ TypeSpecComplex(TSC_unspecified),
+ TypeSpecSign(TSS_unspecified),
+ TypeSpecType(TST_unspecified),
+ TypeSpecOwned(false),
+ TypeQualifiers(TSS_unspecified),
+ FS_inline_specified(false),
+ FS_virtual_specified(false),
+ FS_explicit_specified(false),
+ Friend_specified(false),
+ TypeRep(0),
+ AttrList(0),
+ ProtocolQualifiers(0),
+ NumProtocolQualifiers(0) {
+ }
+ ~DeclSpec() {
+ delete AttrList;
+ delete [] ProtocolQualifiers;
+ }
+ // storage-class-specifier
+ SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; }
+ bool isThreadSpecified() const { return SCS_thread_specified; }
+
+ SourceLocation getStorageClassSpecLoc() const { return StorageClassSpecLoc; }
+ SourceLocation getThreadSpecLoc() const { return SCS_threadLoc; }
+
+ void ClearStorageClassSpecs() {
+ StorageClassSpec = DeclSpec::SCS_unspecified;
+ SCS_thread_specified = false;
+ StorageClassSpecLoc = SourceLocation();
+ SCS_threadLoc = SourceLocation();
+ }
+
+ // type-specifier
+ TSW getTypeSpecWidth() const { return (TSW)TypeSpecWidth; }
+ TSC getTypeSpecComplex() const { return (TSC)TypeSpecComplex; }
+ TSS getTypeSpecSign() const { return (TSS)TypeSpecSign; }
+ TST getTypeSpecType() const { return (TST)TypeSpecType; }
+ bool isTypeSpecOwned() const { return TypeSpecOwned; }
+ void *getTypeRep() const { return TypeRep; }
+
+ const SourceRange &getSourceRange() const { return Range; }
+ SourceLocation getTypeSpecWidthLoc() const { return TSWLoc; }
+ SourceLocation getTypeSpecComplexLoc() const { return TSCLoc; }
+ SourceLocation getTypeSpecSignLoc() const { return TSSLoc; }
+ SourceLocation getTypeSpecTypeLoc() const { return TSTLoc; }
+
+ /// getSpecifierName - Turn a type-specifier-type into a string like "_Bool"
+ /// or "union".
+ static const char *getSpecifierName(DeclSpec::TST T);
+ static const char *getSpecifierName(DeclSpec::SCS S);
+
+ // type-qualifiers
+
+ /// getTypeQualifiers - Return a set of TQs.
+ unsigned getTypeQualifiers() const { return TypeQualifiers; }
+ SourceLocation getConstSpecLoc() const { return TQ_constLoc; }
+ SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; }
+ SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; }
+
+ // function-specifier
+ bool isInlineSpecified() const { return FS_inline_specified; }
+ SourceLocation getInlineSpecLoc() const { return FS_inlineLoc; }
+
+ bool isVirtualSpecified() const { return FS_virtual_specified; }
+ SourceLocation getVirtualSpecLoc() const { return FS_virtualLoc; }
+
+ bool isExplicitSpecified() const { return FS_explicit_specified; }
+ SourceLocation getExplicitSpecLoc() const { return FS_explicitLoc; }
+
+ void ClearFunctionSpecs() {
+ FS_inline_specified = false;
+ FS_inlineLoc = SourceLocation();
+ FS_virtual_specified = false;
+ FS_virtualLoc = SourceLocation();
+ FS_explicit_specified = false;
+ FS_explicitLoc = SourceLocation();
+ }
+
+ /// hasTypeSpecifier - Return true if any type-specifier has been found.
+ bool hasTypeSpecifier() const {
+ return getTypeSpecType() != DeclSpec::TST_unspecified ||
+ getTypeSpecWidth() != DeclSpec::TSW_unspecified ||
+ getTypeSpecComplex() != DeclSpec::TSC_unspecified ||
+ getTypeSpecSign() != DeclSpec::TSS_unspecified;
+ }
+
+ /// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
+ /// DeclSpec includes.
+ ///
+ unsigned getParsedSpecifiers() const;
+
+ /// isEmpty - Return true if this declaration specifier is completely empty:
+ /// no tokens were parsed in the production of it.
+ bool isEmpty() const {
+ return getParsedSpecifiers() == DeclSpec::PQ_None;
+ }
+
+ void SetRangeStart(SourceLocation Loc) { Range.setBegin(Loc); }
+ void SetRangeEnd(SourceLocation Loc) { Range.setEnd(Loc); }
+
+ /// These methods set the specified attribute of the DeclSpec, but return true
+ /// and ignore the request if invalid (e.g. "extern" then "auto" is
+ /// specified). The name of the previous specifier is returned in prevspec.
+ bool SetStorageClassSpec(SCS S, SourceLocation Loc, const char *&PrevSpec);
+ bool SetStorageClassSpecThread(SourceLocation Loc, const char *&PrevSpec);
+ bool SetTypeSpecWidth(TSW W, SourceLocation Loc, const char *&PrevSpec);
+ bool SetTypeSpecComplex(TSC C, SourceLocation Loc, const char *&PrevSpec);
+ bool SetTypeSpecSign(TSS S, SourceLocation Loc, const char *&PrevSpec);
+ bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
+ void *Rep = 0, bool Owned = false);
+ bool SetTypeSpecError();
+
+ bool SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
+ const LangOptions &Lang);
+
+ bool SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec);
+ bool SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec);
+ bool SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec);
+
+ bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec);
+ bool isFriendSpecified() const { return Friend_specified; }
+ SourceLocation getFriendSpecLoc() const { return FriendLoc; }
+
+ /// AddAttributes - contatenates two attribute lists.
+ /// The GCC attribute syntax allows for the following:
+ ///
+ /// short __attribute__(( unused, deprecated ))
+ /// int __attribute__(( may_alias, aligned(16) )) var;
+ ///
+ /// This declares 4 attributes using 2 lists. The following syntax is
+ /// also allowed and equivalent to the previous declaration.
+ ///
+ /// short __attribute__((unused)) __attribute__((deprecated))
+ /// int __attribute__((may_alias)) __attribute__((aligned(16))) var;
+ ///
+ void AddAttributes(AttributeList *alist) {
+ if (!alist)
+ return; // we parsed __attribute__(()) or had a syntax error
+
+ if (AttrList)
+ alist->addAttributeList(AttrList);
+ AttrList = alist;
+ }
+ void SetAttributes(AttributeList *AL) { AttrList = AL; }
+ const AttributeList *getAttributes() const { return AttrList; }
+ AttributeList *getAttributes() { return AttrList; }
+
+ /// TakeAttributes - Return the current attribute list and remove them from
+ /// the DeclSpec so that it doesn't own them.
+ AttributeList *TakeAttributes() {
+ AttributeList *AL = AttrList;
+ AttrList = 0;
+ return AL;
+ }
+
+ typedef const ActionBase::DeclPtrTy *ProtocolQualifierListTy;
+ ProtocolQualifierListTy getProtocolQualifiers() const {
+ return ProtocolQualifiers;
+ }
+ unsigned getNumProtocolQualifiers() const {
+ return NumProtocolQualifiers;
+ }
+ void setProtocolQualifiers(const ActionBase::DeclPtrTy *Protos, unsigned NP) {
+ if (NP == 0) return;
+ ProtocolQualifiers = new ActionBase::DeclPtrTy[NP];
+ memcpy((void*)ProtocolQualifiers, Protos, sizeof(ActionBase::DeclPtrTy)*NP);
+ NumProtocolQualifiers = NP;
+ }
+
+ /// 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);
+
+ /// isMissingDeclaratorOk - This checks if this DeclSpec can stand alone,
+ /// without a Declarator. Only tag declspecs can stand alone.
+ bool isMissingDeclaratorOk();
+};
+
+/// ObjCDeclSpec - This class captures information about
+/// "declaration specifiers" specific to objective-c
+class ObjCDeclSpec {
+public:
+ /// ObjCDeclQualifier - Qualifier used on types in method declarations
+ enum ObjCDeclQualifier {
+ DQ_None = 0x0,
+ DQ_In = 0x1,
+ DQ_Inout = 0x2,
+ DQ_Out = 0x4,
+ DQ_Bycopy = 0x8,
+ DQ_Byref = 0x10,
+ DQ_Oneway = 0x20
+ };
+
+ /// PropertyAttributeKind - list of property attributes.
+ enum ObjCPropertyAttributeKind { DQ_PR_noattr = 0x0,
+ DQ_PR_readonly = 0x01,
+ DQ_PR_getter = 0x02,
+ DQ_PR_assign = 0x04,
+ DQ_PR_readwrite = 0x08,
+ DQ_PR_retain = 0x10,
+ DQ_PR_copy = 0x20,
+ DQ_PR_nonatomic = 0x40,
+ DQ_PR_setter = 0x80
+ };
+
+
+ ObjCDeclSpec() : objcDeclQualifier(DQ_None), PropertyAttributes(DQ_PR_noattr),
+ GetterName(0), SetterName(0)
+ {}
+ ObjCDeclQualifier getObjCDeclQualifier() const { return objcDeclQualifier; }
+ void setObjCDeclQualifier(ObjCDeclQualifier DQVal)
+ { objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier | DQVal); }
+
+ ObjCPropertyAttributeKind getPropertyAttributes() const
+ { return ObjCPropertyAttributeKind(PropertyAttributes); }
+ void setPropertyAttributes(ObjCPropertyAttributeKind PRVal) {
+ PropertyAttributes =
+ (ObjCPropertyAttributeKind) (PropertyAttributes | PRVal);
+ }
+
+ const IdentifierInfo *getGetterName() const { return GetterName; }
+ IdentifierInfo *getGetterName() { return GetterName; }
+ void setGetterName(IdentifierInfo *name) { GetterName = name; }
+
+ 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
+ // (space saving is negligible).
+ ObjCDeclQualifier objcDeclQualifier : 6;
+
+ // NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind
+ unsigned PropertyAttributes : 8;
+ IdentifierInfo *GetterName; // getter name of NULL if no getter
+ IdentifierInfo *SetterName; // setter name of NULL if no setter
+};
+
+/// CXXScopeSpec - Represents a C++ nested-name-specifier or a global scope
+/// specifier.
+class CXXScopeSpec {
+ SourceRange Range;
+ void *ScopeRep;
+
+public:
+ CXXScopeSpec() : Range(), ScopeRep() { }
+
+ const SourceRange &getRange() const { return Range; }
+ void setRange(const SourceRange &R) { Range = R; }
+ void setBeginLoc(SourceLocation Loc) { Range.setBegin(Loc); }
+ void setEndLoc(SourceLocation Loc) { Range.setEnd(Loc); }
+ SourceLocation getBeginLoc() const { return Range.getBegin(); }
+ SourceLocation getEndLoc() const { return Range.getEnd(); }
+
+ ActionBase::CXXScopeTy *getScopeRep() const { return ScopeRep; }
+ void setScopeRep(ActionBase::CXXScopeTy *S) { ScopeRep = S; }
+
+ bool isEmpty() const { return !Range.isValid(); }
+ bool isNotEmpty() const { return !isEmpty(); }
+
+ /// isInvalid - An error occured during parsing of the scope specifier.
+ bool isInvalid() const { return isNotEmpty() && ScopeRep == 0; }
+
+ /// isSet - A scope specifier was resolved to a valid C++ scope.
+ bool isSet() const { return ScopeRep != 0; }
+
+ void clear() {
+ Range = SourceRange();
+ ScopeRep = 0;
+ }
+};
+
+/// CachedTokens - A set of tokens that has been cached for later
+/// parsing.
+typedef llvm::SmallVector<Token, 4> CachedTokens;
+
+/// DeclaratorChunk - One instance of this struct is used for each type in a
+/// declarator that is parsed.
+///
+/// This is intended to be a small value object.
+struct DeclaratorChunk {
+ enum {
+ Pointer, Reference, Array, Function, BlockPointer, MemberPointer
+ } Kind;
+
+ /// Loc - The place where this type was defined.
+ SourceLocation Loc;
+
+ struct PointerTypeInfo {
+ /// The type qualifiers: const/volatile/restrict.
+ unsigned TypeQuals : 3;
+ AttributeList *AttrList;
+ void destroy() {
+ delete AttrList;
+ }
+ };
+
+ struct ReferenceTypeInfo {
+ /// The type qualifier: restrict. [GNU] C++ extension
+ bool HasRestrict : 1;
+ /// True if this is an lvalue reference, false if it's an rvalue reference.
+ bool LValueRef : 1;
+ AttributeList *AttrList;
+ void destroy() {
+ delete AttrList;
+ }
+ };
+
+ struct ArrayTypeInfo {
+ /// The type qualifiers for the array: const/volatile/restrict.
+ unsigned TypeQuals : 3;
+
+ /// True if this dimension included the 'static' keyword.
+ bool hasStatic : 1;
+
+ /// True if this dimension was [*]. In this case, NumElts is null.
+ bool isStar : 1;
+
+ /// This is the size of the array, or null if [] or [*] was specified.
+ /// Since the parser is multi-purpose, and we don't want to impose a root
+ /// expression class on all clients, NumElts is untyped.
+ ActionBase::ExprTy *NumElts;
+ void destroy() {}
+ };
+
+ /// ParamInfo - An array of paraminfo objects is allocated whenever a function
+ /// declarator is parsed. There are two interesting styles of arguments here:
+ /// K&R-style identifier lists and parameter type lists. K&R-style identifier
+ /// lists will have information about the identifier, but no type information.
+ /// Parameter type lists will have type info (if the actions module provides
+ /// it), but may have null identifier info: e.g. for 'void foo(int X, int)'.
+ struct ParamInfo {
+ IdentifierInfo *Ident;
+ SourceLocation IdentLoc;
+ ActionBase::DeclPtrTy Param;
+
+ /// DefaultArgTokens - When the parameter's default argument
+ /// cannot be parsed immediately (because it occurs within the
+ /// declaration of a member function), it will be stored here as a
+ /// sequence of tokens to be parsed once the class definition is
+ /// complete. Non-NULL indicates that there is a default argument.
+ CachedTokens *DefaultArgTokens;
+
+ ParamInfo() {}
+ ParamInfo(IdentifierInfo *ident, SourceLocation iloc,
+ ActionBase::DeclPtrTy param,
+ CachedTokens *DefArgTokens = 0)
+ : Ident(ident), IdentLoc(iloc), Param(param),
+ DefaultArgTokens(DefArgTokens) {}
+ };
+
+ struct TypeAndRange {
+ ActionBase::TypeTy *Ty;
+ SourceRange Range;
+ };
+
+ struct FunctionTypeInfo {
+ /// hasPrototype - This is true if the function had at least one typed
+ /// argument. If the function is () or (a,b,c), then it has no prototype,
+ /// and is treated as a K&R-style function.
+ bool hasPrototype : 1;
+
+ /// isVariadic - If this function has a prototype, and if that
+ /// proto ends with ',...)', this is true. When true, EllipsisLoc
+ /// contains the location of the ellipsis.
+ bool isVariadic : 1;
+
+ /// The type qualifiers: const/volatile/restrict.
+ /// The qualifier bitmask values are the same as in QualType.
+ unsigned TypeQuals : 3;
+
+ /// hasExceptionSpec - True if the function has an exception specification.
+ bool hasExceptionSpec : 1;
+
+ /// hasAnyExceptionSpec - True if the function has a throw(...) specifier.
+ bool hasAnyExceptionSpec : 1;
+
+ /// DeleteArgInfo - If this is true, we need to delete[] ArgInfo.
+ bool DeleteArgInfo : 1;
+
+ /// When isVariadic is true, the location of the ellipsis in the source.
+ unsigned EllipsisLoc;
+
+ /// NumArgs - This is the number of formal arguments provided for the
+ /// declarator.
+ unsigned NumArgs;
+
+ /// NumExceptions - This is the number of types in the exception-decl, if
+ /// the function has one.
+ unsigned NumExceptions;
+
+ /// ThrowLoc - When hasExceptionSpec is true, the location of the throw
+ /// keyword introducing the spec.
+ unsigned ThrowLoc;
+
+ /// ArgInfo - This is a pointer to a new[]'d array of ParamInfo objects that
+ /// describe the arguments for this function declarator. This is null if
+ /// there are no arguments specified.
+ ParamInfo *ArgInfo;
+
+ /// Exceptions - This is a pointer to a new[]'d array of TypeAndRange
+ /// objects that contain the types in the function's exception
+ /// specification and their locations.
+ TypeAndRange *Exceptions;
+
+ /// freeArgs - reset the argument list to having zero arguments. This is
+ /// used in various places for error recovery.
+ void freeArgs() {
+ if (DeleteArgInfo) {
+ delete[] ArgInfo;
+ DeleteArgInfo = false;
+ }
+ NumArgs = 0;
+ }
+
+ void destroy() {
+ if (DeleteArgInfo)
+ delete[] ArgInfo;
+ delete[] Exceptions;
+ }
+
+ SourceLocation getEllipsisLoc() const {
+ return SourceLocation::getFromRawEncoding(EllipsisLoc);
+ }
+ SourceLocation getThrowLoc() const {
+ return SourceLocation::getFromRawEncoding(ThrowLoc);
+ }
+ };
+
+ struct BlockPointerTypeInfo {
+ /// For now, sema will catch these as invalid.
+ /// The type qualifiers: const/volatile/restrict.
+ unsigned TypeQuals : 3;
+ AttributeList *AttrList;
+ void destroy() {
+ delete AttrList;
+ }
+ };
+
+ struct MemberPointerTypeInfo {
+ /// The type qualifiers: const/volatile/restrict.
+ unsigned TypeQuals : 3;
+ AttributeList *AttrList;
+ // CXXScopeSpec has a constructor, so it can't be a direct member.
+ // So we need some pointer-aligned storage and a bit of trickery.
+ union {
+ void *Aligner;
+ char Mem[sizeof(CXXScopeSpec)];
+ } ScopeMem;
+ CXXScopeSpec &Scope() {
+ return *reinterpret_cast<CXXScopeSpec*>(ScopeMem.Mem);
+ }
+ const CXXScopeSpec &Scope() const {
+ return *reinterpret_cast<const CXXScopeSpec*>(ScopeMem.Mem);
+ }
+ void destroy() {
+ delete AttrList;
+ Scope().~CXXScopeSpec();
+ }
+ };
+
+ union {
+ PointerTypeInfo Ptr;
+ ReferenceTypeInfo Ref;
+ ArrayTypeInfo Arr;
+ FunctionTypeInfo Fun;
+ BlockPointerTypeInfo Cls;
+ MemberPointerTypeInfo Mem;
+ };
+
+ void destroy() {
+ switch (Kind) {
+ default: assert(0 && "Unknown decl type!");
+ case DeclaratorChunk::Function: return Fun.destroy();
+ case DeclaratorChunk::Pointer: return Ptr.destroy();
+ case DeclaratorChunk::BlockPointer: return Cls.destroy();
+ case DeclaratorChunk::Reference: return Ref.destroy();
+ case DeclaratorChunk::Array: return Arr.destroy();
+ case DeclaratorChunk::MemberPointer: return Mem.destroy();
+ }
+ }
+
+ /// getAttrs - If there are attributes applied to this declaratorchunk, return
+ /// them.
+ const AttributeList *getAttrs() const {
+ switch (Kind) {
+ default: assert(0 && "Unknown declarator kind!");
+ case Pointer: return Ptr.AttrList;
+ case Reference: return Ref.AttrList;
+ case MemberPointer: return Mem.AttrList;
+ case Array: return 0;
+ case Function: return 0;
+ case BlockPointer: return Cls.AttrList;
+ }
+ }
+
+
+ /// getPointer - Return a DeclaratorChunk for a pointer.
+ ///
+ static DeclaratorChunk getPointer(unsigned TypeQuals, SourceLocation Loc,
+ AttributeList *AL) {
+ DeclaratorChunk I;
+ I.Kind = Pointer;
+ I.Loc = Loc;
+ I.Ptr.TypeQuals = TypeQuals;
+ I.Ptr.AttrList = AL;
+ return I;
+ }
+
+ /// getReference - Return a DeclaratorChunk for a reference.
+ ///
+ static DeclaratorChunk getReference(unsigned TypeQuals, SourceLocation Loc,
+ AttributeList *AL, bool lvalue) {
+ DeclaratorChunk I;
+ I.Kind = Reference;
+ I.Loc = Loc;
+ I.Ref.HasRestrict = (TypeQuals & DeclSpec::TQ_restrict) != 0;
+ I.Ref.LValueRef = lvalue;
+ I.Ref.AttrList = AL;
+ return I;
+ }
+
+ /// getArray - Return a DeclaratorChunk for an array.
+ ///
+ static DeclaratorChunk getArray(unsigned TypeQuals, bool isStatic,
+ bool isStar, void *NumElts,
+ SourceLocation Loc) {
+ DeclaratorChunk I;
+ I.Kind = Array;
+ I.Loc = Loc;
+ I.Arr.TypeQuals = TypeQuals;
+ I.Arr.hasStatic = isStatic;
+ I.Arr.isStar = isStar;
+ I.Arr.NumElts = NumElts;
+ return I;
+ }
+
+ /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
+ /// "TheDeclarator" is the declarator that this will be added to.
+ static DeclaratorChunk getFunction(bool hasProto, bool isVariadic,
+ SourceLocation EllipsisLoc,
+ ParamInfo *ArgInfo, unsigned NumArgs,
+ unsigned TypeQuals, bool hasExceptionSpec,
+ SourceLocation ThrowLoc,
+ bool hasAnyExceptionSpec,
+ ActionBase::TypeTy **Exceptions,
+ SourceRange *ExceptionRanges,
+ unsigned NumExceptions, SourceLocation Loc,
+ Declarator &TheDeclarator);
+
+ /// getBlockPointer - Return a DeclaratorChunk for a block.
+ ///
+ static DeclaratorChunk getBlockPointer(unsigned TypeQuals, SourceLocation Loc,
+ AttributeList *AL) {
+ DeclaratorChunk I;
+ I.Kind = BlockPointer;
+ I.Loc = Loc;
+ I.Cls.TypeQuals = TypeQuals;
+ I.Cls.AttrList = AL;
+ return I;
+ }
+
+ static DeclaratorChunk getMemberPointer(const CXXScopeSpec &SS,
+ unsigned TypeQuals,
+ SourceLocation Loc,
+ AttributeList *AL) {
+ DeclaratorChunk I;
+ I.Kind = MemberPointer;
+ I.Loc = Loc;
+ I.Mem.TypeQuals = TypeQuals;
+ I.Mem.AttrList = AL;
+ new (I.Mem.ScopeMem.Mem) CXXScopeSpec(SS);
+ return I;
+ }
+};
+
+/// Declarator - Information about one declarator, including the parsed type
+/// information and the identifier. When the declarator is fully formed, this
+/// is turned into the appropriate Decl object.
+///
+/// Declarators come in two types: normal declarators and abstract declarators.
+/// Abstract declarators are used when parsing types, and don't have an
+/// identifier. Normal declarators do have ID's.
+///
+/// Instances of this class should be a transient object that lives on the
+/// stack, not objects that are allocated in large quantities on the heap.
+class Declarator {
+public:
+ enum TheContext {
+ FileContext, // File scope declaration.
+ PrototypeContext, // Within a function prototype.
+ KNRTypeListContext, // K&R type definition list for formals.
+ TypeNameContext, // Abstract declarator for types.
+ MemberContext, // Struct/Union field.
+ BlockContext, // Declaration within a block in a function.
+ ForContext, // Declaration within first part of a for loop.
+ ConditionContext, // Condition declaration in a C++ if/switch/while/for.
+ TemplateParamContext,// Within a template parameter list.
+ CXXCatchContext, // C++ catch exception-declaration
+ BlockLiteralContext // Block literal declarator.
+ };
+
+ /// DeclaratorKind - The kind of declarator this represents.
+ enum DeclaratorKind {
+ DK_Abstract, // An abstract declarator (has no identifier)
+ DK_Normal, // A normal declarator (has an identifier).
+ DK_Constructor, // A C++ constructor (identifier is the class name)
+ DK_Destructor, // A C++ destructor (identifier is ~class name)
+ DK_Operator, // A C++ overloaded operator name
+ DK_Conversion // A C++ conversion function (identifier is
+ // "operator " then the type name)
+ };
+
+private:
+ const DeclSpec &DS;
+ CXXScopeSpec SS;
+ IdentifierInfo *Identifier;
+ SourceLocation IdentifierLoc;
+ SourceRange Range;
+
+ /// Context - Where we are parsing this declarator.
+ ///
+ TheContext Context;
+
+ /// Kind - What kind of declarator this is.
+ DeclaratorKind Kind;
+
+ /// DeclTypeInfo - This holds each type that the declarator includes as it is
+ /// 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;
+
+ /// InvalidType - Set by Sema::GetTypeForDeclarator().
+ bool InvalidType : 1;
+
+ /// GroupingParens - Set by Parser::ParseParenDeclarator().
+ bool GroupingParens : 1;
+
+ /// AttrList - Attributes.
+ AttributeList *AttrList;
+
+ /// AsmLabel - The asm label, if specified.
+ ActionBase::ExprTy *AsmLabel;
+
+ union {
+ // When Kind is DK_Constructor, DK_Destructor, or DK_Conversion, the
+ // type associated with the constructor, destructor, or conversion
+ // operator.
+ ActionBase::TypeTy *Type;
+
+ /// When Kind is DK_Operator, this is the actual overloaded
+ /// operator that this declarator names.
+ OverloadedOperatorKind OperatorKind;
+ };
+
+ /// InlineParams - This is a local array used for the first function decl
+ /// chunk to avoid going to the heap for the common case when we have one
+ /// function chunk in the declarator.
+ DeclaratorChunk::ParamInfo InlineParams[16];
+ bool InlineParamsUsed;
+
+ friend struct DeclaratorChunk;
+
+public:
+ Declarator(const DeclSpec &ds, TheContext C)
+ : DS(ds), Identifier(0), Range(ds.getSourceRange()), Context(C),
+ Kind(DK_Abstract),
+ InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error),
+ GroupingParens(false), AttrList(0), AsmLabel(0), Type(0),
+ InlineParamsUsed(false) {
+ }
+
+ ~Declarator() {
+ clear();
+ }
+
+ /// getDeclSpec - Return the declaration-specifier that this declarator was
+ /// declared with.
+ const DeclSpec &getDeclSpec() const { return DS; }
+
+ /// getMutableDeclSpec - Return a non-const version of the DeclSpec. This
+ /// should be used with extreme care: declspecs can often be shared between
+ /// multiple declarators, so mutating the DeclSpec affects all of the
+ /// Declarators. This should only be done when the declspec is known to not
+ /// be shared or when in error recovery etc.
+ DeclSpec &getMutableDeclSpec() { return const_cast<DeclSpec &>(DS); }
+
+ /// getCXXScopeSpec - Return the C++ scope specifier (global scope or
+ /// nested-name-specifier) that is part of the declarator-id.
+ const CXXScopeSpec &getCXXScopeSpec() const { return SS; }
+ CXXScopeSpec &getCXXScopeSpec() { return SS; }
+
+ TheContext getContext() const { return Context; }
+ DeclaratorKind getKind() const { return Kind; }
+
+ /// getSourceRange - Get the source range that spans this declarator.
+ const SourceRange &getSourceRange() const { return Range; }
+
+ void SetSourceRange(SourceRange R) { Range = R; }
+ /// SetRangeBegin - Set the start of the source range to Loc, unless it's
+ /// invalid.
+ void SetRangeBegin(SourceLocation Loc) {
+ if (!Loc.isInvalid())
+ Range.setBegin(Loc);
+ }
+ /// SetRangeEnd - Set the end of the source range to Loc, unless it's invalid.
+ void SetRangeEnd(SourceLocation Loc) {
+ if (!Loc.isInvalid())
+ Range.setEnd(Loc);
+ }
+ /// ExtendWithDeclSpec - Extend the declarator source range to include the
+ /// given declspec, unless its location is invalid. Adopts the range start if
+ /// the current range start is invalid.
+ void ExtendWithDeclSpec(const DeclSpec &DS) {
+ const SourceRange &SR = DS.getSourceRange();
+ if (Range.getBegin().isInvalid())
+ Range.setBegin(SR.getBegin());
+ if (!SR.getEnd().isInvalid())
+ Range.setEnd(SR.getEnd());
+ }
+
+ /// clear - Reset the contents of this Declarator.
+ void clear() {
+ SS.clear();
+ Identifier = 0;
+ IdentifierLoc = SourceLocation();
+ Range = DS.getSourceRange();
+ Kind = DK_Abstract;
+
+ for (unsigned i = 0, e = DeclTypeInfo.size(); i != e; ++i)
+ DeclTypeInfo[i].destroy();
+ DeclTypeInfo.clear();
+ delete AttrList;
+ AttrList = 0;
+ AsmLabel = 0;
+ Type = 0;
+ InlineParamsUsed = false;
+ }
+
+ /// mayOmitIdentifier - Return true if the identifier is either optional or
+ /// not allowed. This is true for typenames, prototypes, and template
+ /// parameter lists.
+ bool mayOmitIdentifier() const {
+ return Context == TypeNameContext || Context == PrototypeContext ||
+ Context == TemplateParamContext || Context == CXXCatchContext ||
+ Context == BlockLiteralContext;
+ }
+
+ /// mayHaveIdentifier - Return true if the identifier is either optional or
+ /// required. This is true for normal declarators and prototypes, but not
+ /// typenames.
+ bool mayHaveIdentifier() const {
+ return Context != TypeNameContext && Context != BlockLiteralContext;
+ }
+
+ /// mayBeFollowedByCXXDirectInit - Return true if the declarator can be
+ /// followed by a C++ direct initializer, e.g. "int x(1);".
+ bool mayBeFollowedByCXXDirectInit() const {
+ return !hasGroupingParens() &&
+ (Context == FileContext ||
+ Context == BlockContext ||
+ Context == ForContext);
+ }
+
+ /// isPastIdentifier - Return true if we have parsed beyond the point where
+ /// the
+ bool isPastIdentifier() const { return IdentifierLoc.isValid(); }
+
+ /// hasName - Whether this declarator has a name, which might be an
+ /// identifier (accessible via getIdentifier()) or some kind of
+ /// special C++ name (constructor, destructor, etc.).
+ bool hasName() const { return getKind() != DK_Abstract; }
+
+ IdentifierInfo *getIdentifier() const { return Identifier; }
+ SourceLocation getIdentifierLoc() const { return IdentifierLoc; }
+
+ void SetIdentifier(IdentifierInfo *ID, SourceLocation Loc) {
+ Identifier = ID;
+ IdentifierLoc = Loc;
+ if (ID)
+ Kind = DK_Normal;
+ else
+ Kind = DK_Abstract;
+ SetRangeEnd(Loc);
+ }
+
+ /// setConstructor - Set this declarator to be a C++ constructor
+ /// declarator. Also extends the range.
+ void setConstructor(ActionBase::TypeTy *Ty, SourceLocation Loc) {
+ IdentifierLoc = Loc;
+ Kind = DK_Constructor;
+ Type = Ty;
+ SetRangeEnd(Loc);
+ }
+
+ /// setDestructor - Set this declarator to be a C++ destructor
+ /// declarator. Also extends the range to End, which should be the identifier
+ /// token.
+ void setDestructor(ActionBase::TypeTy *Ty, SourceLocation Loc,
+ SourceLocation EndLoc) {
+ IdentifierLoc = Loc;
+ Kind = DK_Destructor;
+ Type = Ty;
+ if (!EndLoc.isInvalid())
+ SetRangeEnd(EndLoc);
+ }
+
+ /// setConversionFunction - Set this declarator to be a C++
+ /// conversion function declarator (e.g., @c operator int const *).
+ /// Also extends the range to EndLoc, which should be the last token of the
+ /// type name.
+ void setConversionFunction(ActionBase::TypeTy *Ty, SourceLocation Loc,
+ SourceLocation EndLoc) {
+ Identifier = 0;
+ IdentifierLoc = Loc;
+ Kind = DK_Conversion;
+ Type = Ty;
+ if (!EndLoc.isInvalid())
+ SetRangeEnd(EndLoc);
+ }
+
+ /// setOverloadedOperator - Set this declaration to be a C++
+ /// overloaded operator declarator (e.g., @c operator+).
+ /// Also extends the range to EndLoc, which should be the last token of the
+ /// operator.
+ void setOverloadedOperator(OverloadedOperatorKind Op, SourceLocation Loc,
+ SourceLocation EndLoc) {
+ IdentifierLoc = Loc;
+ Kind = DK_Operator;
+ OperatorKind = Op;
+ if (!EndLoc.isInvalid())
+ SetRangeEnd(EndLoc);
+ }
+
+ /// AddTypeInfo - Add a chunk to this declarator. Also extend the range to
+ /// EndLoc, which should be the last token of the chunk.
+ void AddTypeInfo(const DeclaratorChunk &TI, SourceLocation EndLoc) {
+ DeclTypeInfo.push_back(TI);
+ if (!EndLoc.isInvalid())
+ SetRangeEnd(EndLoc);
+ }
+
+ /// getNumTypeObjects() - Return the number of types applied to this
+ /// declarator.
+ unsigned getNumTypeObjects() const { return DeclTypeInfo.size(); }
+
+ /// Return the specified TypeInfo from this declarator. TypeInfo #0 is
+ /// closest to the identifier.
+ const DeclaratorChunk &getTypeObject(unsigned i) const {
+ assert(i < DeclTypeInfo.size() && "Invalid type chunk");
+ return DeclTypeInfo[i];
+ }
+ DeclaratorChunk &getTypeObject(unsigned i) {
+ assert(i < DeclTypeInfo.size() && "Invalid type chunk");
+ return DeclTypeInfo[i];
+ }
+
+ /// isFunctionDeclarator - Once this declarator is fully parsed and formed,
+ /// this method returns true if the identifier is a function declarator.
+ bool isFunctionDeclarator() const {
+ return !DeclTypeInfo.empty() &&
+ DeclTypeInfo[0].Kind == DeclaratorChunk::Function;
+ }
+
+ /// AddAttributes - simply adds the attribute list to the Declarator.
+ /// These examples both add 3 attributes to "var":
+ /// short int var __attribute__((aligned(16),common,deprecated));
+ /// short int x, __attribute__((aligned(16)) var
+ /// __attribute__((common,deprecated));
+ ///
+ /// Also extends the range of the declarator.
+ void AddAttributes(AttributeList *alist, SourceLocation LastLoc) {
+ if (!alist)
+ return; // we parsed __attribute__(()) or had a syntax error
+
+ if (AttrList)
+ alist->addAttributeList(AttrList);
+ AttrList = alist;
+
+ if (!LastLoc.isInvalid())
+ SetRangeEnd(LastLoc);
+ }
+
+ const AttributeList *getAttributes() const { return AttrList; }
+ AttributeList *getAttributes() { return AttrList; }
+
+ void setAsmLabel(ActionBase::ExprTy *E) { AsmLabel = E; }
+ ActionBase::ExprTy *getAsmLabel() const { return AsmLabel; }
+
+ ActionBase::TypeTy *getDeclaratorIdType() const { return Type; }
+
+ OverloadedOperatorKind getOverloadedOperator() const { return OperatorKind; }
+
+ void setInvalidType(bool Val = true) { InvalidType = Val; }
+ bool isInvalidType() const {
+ return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error;
+ }
+
+ void setGroupingParens(bool flag) { GroupingParens = flag; }
+ bool hasGroupingParens() const { return GroupingParens; }
+};
+
+/// FieldDeclarator - This little struct is used to capture information about
+/// structure field declarators, which is basically just a bitfield size.
+struct FieldDeclarator {
+ Declarator D;
+ ActionBase::ExprTy *BitfieldSize;
+ explicit FieldDeclarator(DeclSpec &DS) : D(DS, Declarator::MemberContext) {
+ BitfieldSize = 0;
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Parse/Designator.h b/include/clang/Parse/Designator.h
new file mode 100644
index 000000000000..026286d318fb
--- /dev/null
+++ b/include/clang/Parse/Designator.h
@@ -0,0 +1,239 @@
+//===--- Designator.h - Initialization Designator ---------------*- 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 interfaces used to represent Designators in the parser and
+// is the input to Actions module.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PARSE_DESIGNATOR_H
+#define LLVM_CLANG_PARSE_DESIGNATOR_H
+
+#include "clang/Parse/Action.h"
+
+namespace clang {
+
+/// Designator - This class is a discriminated union which holds the various
+/// different sorts of designators possible. A Designation is an array of
+/// these. An example of a designator are things like this:
+/// [8] .field [47] // C99 designation: 3 designators
+/// [8 ... 47] field: // GNU extensions: 2 designators
+/// These occur in initializers, e.g.:
+/// int a[10] = {2, 4, [8]=9, 10};
+///
+class Designator {
+public:
+ enum DesignatorKind {
+ FieldDesignator, ArrayDesignator, ArrayRangeDesignator
+ };
+private:
+ DesignatorKind Kind;
+
+ struct FieldDesignatorInfo {
+ const IdentifierInfo *II;
+ unsigned DotLoc;
+ unsigned NameLoc;
+ };
+ struct ArrayDesignatorInfo {
+ ActionBase::ExprTy *Index;
+ unsigned LBracketLoc;
+ mutable unsigned RBracketLoc;
+ };
+ struct ArrayRangeDesignatorInfo {
+ ActionBase::ExprTy *Start, *End;
+ unsigned LBracketLoc, EllipsisLoc;
+ mutable unsigned RBracketLoc;
+ };
+
+ union {
+ FieldDesignatorInfo FieldInfo;
+ ArrayDesignatorInfo ArrayInfo;
+ ArrayRangeDesignatorInfo ArrayRangeInfo;
+ };
+
+public:
+
+ DesignatorKind getKind() const { return Kind; }
+ bool isFieldDesignator() const { return Kind == FieldDesignator; }
+ bool isArrayDesignator() const { return Kind == ArrayDesignator; }
+ bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; }
+
+ const IdentifierInfo *getField() const {
+ assert(isFieldDesignator() && "Invalid accessor");
+ return FieldInfo.II;
+ }
+
+ SourceLocation getDotLoc() const {
+ assert(isFieldDesignator() && "Invalid accessor");
+ return SourceLocation::getFromRawEncoding(FieldInfo.DotLoc);
+ }
+
+ SourceLocation getFieldLoc() const {
+ assert(isFieldDesignator() && "Invalid accessor");
+ return SourceLocation::getFromRawEncoding(FieldInfo.NameLoc);
+ }
+
+ ActionBase::ExprTy *getArrayIndex() const {
+ assert(isArrayDesignator() && "Invalid accessor");
+ return ArrayInfo.Index;
+ }
+
+ ActionBase::ExprTy *getArrayRangeStart() const {
+ assert(isArrayRangeDesignator() && "Invalid accessor");
+ return ArrayRangeInfo.Start;
+ }
+ ActionBase::ExprTy *getArrayRangeEnd() const {
+ assert(isArrayRangeDesignator() && "Invalid accessor");
+ return ArrayRangeInfo.End;
+ }
+
+ SourceLocation getLBracketLoc() const {
+ assert((isArrayDesignator() || isArrayRangeDesignator()) &&
+ "Invalid accessor");
+ if (isArrayDesignator())
+ return SourceLocation::getFromRawEncoding(ArrayInfo.LBracketLoc);
+ else
+ return SourceLocation::getFromRawEncoding(ArrayRangeInfo.LBracketLoc);
+ }
+
+ SourceLocation getRBracketLoc() const {
+ assert((isArrayDesignator() || isArrayRangeDesignator()) &&
+ "Invalid accessor");
+ if (isArrayDesignator())
+ return SourceLocation::getFromRawEncoding(ArrayInfo.RBracketLoc);
+ else
+ return SourceLocation::getFromRawEncoding(ArrayRangeInfo.RBracketLoc);
+ }
+
+ SourceLocation getEllipsisLoc() const {
+ assert(isArrayRangeDesignator() && "Invalid accessor");
+ return SourceLocation::getFromRawEncoding(ArrayRangeInfo.EllipsisLoc);
+ }
+
+ static Designator getField(const IdentifierInfo *II, SourceLocation DotLoc,
+ SourceLocation NameLoc) {
+ Designator D;
+ D.Kind = FieldDesignator;
+ D.FieldInfo.II = II;
+ D.FieldInfo.DotLoc = DotLoc.getRawEncoding();
+ D.FieldInfo.NameLoc = NameLoc.getRawEncoding();
+ return D;
+ }
+
+ static Designator getArray(ActionBase::ExprTy *Index,
+ SourceLocation LBracketLoc) {
+ Designator D;
+ D.Kind = ArrayDesignator;
+ D.ArrayInfo.Index = Index;
+ D.ArrayInfo.LBracketLoc = LBracketLoc.getRawEncoding();
+ D.ArrayInfo.RBracketLoc = 0;
+ return D;
+ }
+
+ static Designator getArrayRange(ActionBase::ExprTy *Start,
+ ActionBase::ExprTy *End,
+ SourceLocation LBracketLoc,
+ SourceLocation EllipsisLoc) {
+ Designator D;
+ D.Kind = ArrayRangeDesignator;
+ D.ArrayRangeInfo.Start = Start;
+ D.ArrayRangeInfo.End = End;
+ D.ArrayRangeInfo.LBracketLoc = LBracketLoc.getRawEncoding();
+ D.ArrayRangeInfo.EllipsisLoc = EllipsisLoc.getRawEncoding();
+ D.ArrayRangeInfo.RBracketLoc = 0;
+ return D;
+ }
+
+ void setRBracketLoc(SourceLocation RBracketLoc) const {
+ assert((isArrayDesignator() || isArrayRangeDesignator()) &&
+ "Invalid accessor");
+ if (isArrayDesignator())
+ ArrayInfo.RBracketLoc = RBracketLoc.getRawEncoding();
+ else
+ ArrayRangeInfo.RBracketLoc = RBracketLoc.getRawEncoding();
+ }
+
+ /// ClearExprs - Null out any expression references, which prevents them from
+ /// being 'delete'd later.
+ void ClearExprs(Action &Actions) {
+ switch (Kind) {
+ case FieldDesignator: return;
+ case ArrayDesignator:
+ ArrayInfo.Index = 0;
+ return;
+ case ArrayRangeDesignator:
+ ArrayRangeInfo.Start = 0;
+ ArrayRangeInfo.End = 0;
+ return;
+ }
+ }
+
+ /// FreeExprs - Release any unclaimed memory for the expressions in this
+ /// designator.
+ void FreeExprs(Action &Actions) {
+ switch (Kind) {
+ case FieldDesignator: return; // nothing to free.
+ case ArrayDesignator:
+ Actions.DeleteExpr(getArrayIndex());
+ return;
+ case ArrayRangeDesignator:
+ Actions.DeleteExpr(getArrayRangeStart());
+ Actions.DeleteExpr(getArrayRangeEnd());
+ return;
+ }
+ }
+};
+
+
+/// Designation - Represent a full designation, which is a sequence of
+/// designators. This class is mostly a helper for InitListDesignations.
+class Designation {
+ /// InitIndex - The index of the initializer expression this is for. For
+ /// example, if the initializer were "{ A, .foo=B, C }" a Designation would
+ /// exist with InitIndex=1, because element #1 has a designation.
+ unsigned InitIndex;
+
+ /// Designators - The actual designators for this initializer.
+ llvm::SmallVector<Designator, 2> Designators;
+
+ Designation(unsigned Idx) : InitIndex(Idx) {}
+public:
+ Designation() : InitIndex(4000) {}
+
+ /// AddDesignator - Add a designator to the end of this list.
+ void AddDesignator(Designator D) {
+ Designators.push_back(D);
+ }
+
+ bool empty() const { return Designators.empty(); }
+
+ unsigned getNumDesignators() const { return Designators.size(); }
+ const Designator &getDesignator(unsigned Idx) const {
+ assert(Idx < Designators.size());
+ return Designators[Idx];
+ }
+
+ /// ClearExprs - Null out any expression references, which prevents them from
+ /// being 'delete'd later.
+ void ClearExprs(Action &Actions) {
+ for (unsigned i = 0, e = Designators.size(); i != e; ++i)
+ Designators[i].ClearExprs(Actions);
+ }
+
+ /// FreeExprs - Release any unclaimed memory for the expressions in this
+ /// designation.
+ void FreeExprs(Action &Actions) {
+ for (unsigned i = 0, e = Designators.size(); i != e; ++i)
+ Designators[i].FreeExprs(Actions);
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Parse/Ownership.h b/include/clang/Parse/Ownership.h
new file mode 100644
index 000000000000..59517930de95
--- /dev/null
+++ b/include/clang/Parse/Ownership.h
@@ -0,0 +1,830 @@
+//===--- Ownership.h - Parser Ownership Helpers -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains classes for managing ownership of Stmt and Expr nodes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PARSE_OWNERSHIP_H
+#define LLVM_CLANG_PARSE_OWNERSHIP_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/PointerIntPair.h"
+
+//===----------------------------------------------------------------------===//
+// OpaquePtr
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+ class ActionBase;
+
+ /// OpaquePtr - This is a very simple POD type that wraps a pointer that the
+ /// Parser doesn't know about but that Sema or another client does. The UID
+ /// template argument is used to make sure that "Decl" pointers are not
+ /// compatible with "Type" pointers for example.
+ template<int UID>
+ class OpaquePtr {
+ void *Ptr;
+ public:
+ OpaquePtr() : Ptr(0) {}
+
+ template <typename T>
+ T* getAs() const {
+ return llvm::PointerLikeTypeTraits<T*>::getFromVoidPointer(Ptr);
+ }
+
+ template <typename T>
+ T getAsVal() const {
+ return llvm::PointerLikeTypeTraits<T>::getFromVoidPointer(Ptr);
+ }
+
+ void *get() const { return Ptr; }
+
+ template<typename T>
+ static OpaquePtr make(T P) {
+ OpaquePtr R; R.set(P); return R;
+ }
+
+ template<typename T>
+ void set(T P) {
+ Ptr = llvm::PointerLikeTypeTraits<T>::getAsVoidPointer(P);
+ }
+
+ operator bool() const { return Ptr != 0; }
+ };
+}
+
+namespace llvm {
+ template <int UID>
+ class PointerLikeTypeTraits<clang::OpaquePtr<UID> > {
+ public:
+ static inline void *getAsVoidPointer(clang::OpaquePtr<UID> P) {
+ // FIXME: Doesn't work? return P.getAs< void >();
+ return P.get();
+ }
+ static inline clang::OpaquePtr<UID> getFromVoidPointer(void *P) {
+ return clang::OpaquePtr<UID>::make(P);
+ }
+ enum { NumLowBitsAvailable = 3 };
+ };
+}
+
+
+
+// -------------------------- About Move Emulation -------------------------- //
+// The smart pointer classes in this file attempt to emulate move semantics
+// as they appear in C++0x with rvalue references. Since C++03 doesn't have
+// rvalue references, some tricks are needed to get similar results.
+// Move semantics in C++0x have the following properties:
+// 1) "Moving" means transferring the value of an object to another object,
+// similar to copying, but without caring what happens to the old object.
+// In particular, this means that the new object can steal the old object's
+// resources instead of creating a copy.
+// 2) Since moving can modify the source object, it must either be explicitly
+// requested by the user, or the modifications must be unnoticeable.
+// 3) As such, C++0x moving is only allowed in three contexts:
+// * By explicitly using std::move() to request it.
+// * From a temporary object, since that object cannot be accessed
+// afterwards anyway, thus making the state unobservable.
+// * On function return, since the object is not observable afterwards.
+//
+// To sum up: moving from a named object should only be possible with an
+// explicit std::move(), or on function return. Moving from a temporary should
+// be implicitly done. Moving from a const object is forbidden.
+//
+// The emulation is not perfect, and has the following shortcomings:
+// * move() is not in namespace std.
+// * move() is required on function return.
+// * There are difficulties with implicit conversions.
+// * Microsoft's compiler must be given the /Za switch to successfully compile.
+//
+// -------------------------- Implementation -------------------------------- //
+// The move emulation relies on the peculiar reference binding semantics of
+// C++03: as a rule, a non-const reference may not bind to a temporary object,
+// except for the implicit object parameter in a member function call, which
+// can refer to a temporary even when not being const.
+// The moveable object has five important functions to facilitate moving:
+// * A private, unimplemented constructor taking a non-const reference to its
+// own class. This constructor serves a two-fold purpose.
+// - It prevents the creation of a copy constructor that takes a const
+// reference. Temporaries would be able to bind to the argument of such a
+// constructor, and that would be bad.
+// - Named objects will bind to the non-const reference, but since it's
+// private, this will fail to compile. This prevents implicit moving from
+// named objects.
+// There's also a copy assignment operator for the same purpose.
+// * An implicit, non-const conversion operator to a special mover type. This
+// type represents the rvalue reference of C++0x. Being a non-const member,
+// its implicit this parameter can bind to temporaries.
+// * A constructor that takes an object of this mover type. This constructor
+// performs the actual move operation. There is an equivalent assignment
+// operator.
+// There is also a free move() function that takes a non-const reference to
+// an object and returns a temporary. Internally, this function uses explicit
+// constructor calls to move the value from the referenced object to the return
+// value.
+//
+// There are now three possible scenarios of use.
+// * Copying from a const object. Constructor overload resolution will find the
+// non-const copy constructor, and the move constructor. The first is not
+// viable because the const object cannot be bound to the non-const reference.
+// The second fails because the conversion to the mover object is non-const.
+// Moving from a const object fails as intended.
+// * Copying from a named object. Constructor overload resolution will select
+// the non-const copy constructor, but fail as intended, because this
+// constructor is private.
+// * Copying from a temporary. Constructor overload resolution cannot select
+// the non-const copy constructor, because the temporary cannot be bound to
+// the non-const reference. It thus selects the move constructor. The
+// temporary can be bound to the implicit this parameter of the conversion
+// operator, because of the special binding rule. Construction succeeds.
+// Note that the Microsoft compiler, as an extension, allows binding
+// temporaries against non-const references. The compiler thus selects the
+// non-const copy constructor and fails, because the constructor is private.
+// Passing /Za (disable extensions) disables this behaviour.
+// The free move() function is used to move from a named object.
+//
+// Note that when passing an object of a different type (the classes below
+// have OwningResult and OwningPtr, which should be mixable), you get a problem.
+// Argument passing and function return use copy initialization rules. The
+// effect of this is that, when the source object is not already of the target
+// type, the compiler will first seek a way to convert the source object to the
+// target type, and only then attempt to copy the resulting object. This means
+// that when passing an OwningResult where an OwningPtr is expected, the
+// compiler will first seek a conversion from OwningResult to OwningPtr, then
+// copy the OwningPtr. The resulting conversion sequence is:
+// OwningResult object -> ResultMover -> OwningResult argument to
+// OwningPtr(OwningResult) -> OwningPtr -> PtrMover -> final OwningPtr
+// This conversion sequence is too complex to be allowed. Thus the special
+// move_* functions, which help the compiler out with some explicit
+// conversions.
+
+// Flip this switch to measure performance impact of the smart pointers.
+//#define DISABLE_SMART_POINTERS
+
+namespace llvm {
+ template<>
+ class PointerLikeTypeTraits<clang::ActionBase*> {
+ typedef clang::ActionBase* PT;
+ public:
+ static inline void *getAsVoidPointer(PT P) { return P; }
+ static inline PT getFromVoidPointer(void *P) {
+ return static_cast<PT>(P);
+ }
+ enum { NumLowBitsAvailable = 2 };
+ };
+}
+
+namespace clang {
+ // Basic
+ class DiagnosticBuilder;
+
+ // Determines whether the low bit of the result pointer for the
+ // given UID is always zero. If so, ActionResult will use that bit
+ // for it's "invalid" flag.
+ template<unsigned UID>
+ struct IsResultPtrLowBitFree {
+ static const bool value = false;
+ };
+
+ /// ActionBase - A small part split from Action because of the horrible
+ /// definition order dependencies between Action and the smart pointers.
+ class ActionBase {
+ public:
+ /// Out-of-line virtual destructor to provide home for this class.
+ virtual ~ActionBase();
+
+ // Types - Though these don't actually enforce strong typing, they document
+ // what types are required to be identical for the actions.
+ typedef OpaquePtr<0> DeclPtrTy;
+ typedef OpaquePtr<1> DeclGroupPtrTy;
+ typedef OpaquePtr<2> TemplateTy;
+ typedef void AttrTy;
+ typedef void BaseTy;
+ typedef void MemInitTy;
+ typedef void ExprTy;
+ typedef void StmtTy;
+ typedef void TemplateParamsTy;
+ typedef void CXXScopeTy;
+ typedef void TypeTy; // FIXME: Change TypeTy to use OpaquePtr<N>.
+
+ /// ActionResult - This structure is used while parsing/acting on
+ /// expressions, stmts, etc. It encapsulates both the object returned by
+ /// the action, plus a sense of whether or not it is valid.
+ /// When CompressInvalid is true, the "invalid" flag will be
+ /// stored in the low bit of the Val pointer.
+ template<unsigned UID,
+ typename PtrTy = void*,
+ bool CompressInvalid = IsResultPtrLowBitFree<UID>::value>
+ class ActionResult {
+ PtrTy Val;
+ bool Invalid;
+
+ public:
+ ActionResult(bool Invalid = false) : Val(PtrTy()), Invalid(Invalid) {}
+ template<typename ActualExprTy>
+ ActionResult(ActualExprTy val) : Val(val), Invalid(false) {}
+ ActionResult(const DiagnosticBuilder &) : Val(PtrTy()), Invalid(true) {}
+
+ PtrTy get() const { return Val; }
+ void set(PtrTy V) { Val = V; }
+ bool isInvalid() const { return Invalid; }
+
+ const ActionResult &operator=(PtrTy RHS) {
+ Val = RHS;
+ Invalid = false;
+ return *this;
+ }
+ };
+
+ // This ActionResult partial specialization places the "invalid"
+ // flag into the low bit of the pointer.
+ template<unsigned UID, typename PtrTy>
+ class ActionResult<UID, PtrTy, true> {
+ // A pointer whose low bit is 1 if this result is invalid, 0
+ // otherwise.
+ uintptr_t PtrWithInvalid;
+ typedef llvm::PointerLikeTypeTraits<PtrTy> PtrTraits;
+ public:
+ ActionResult(bool Invalid = false)
+ : PtrWithInvalid(static_cast<uintptr_t>(Invalid)) { }
+
+ template<typename ActualExprTy>
+ ActionResult(ActualExprTy *val) {
+ PtrTy V(val);
+ void *VP = PtrTraits::getAsVoidPointer(V);
+ PtrWithInvalid = reinterpret_cast<uintptr_t>(VP);
+ assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer");
+ }
+
+ ActionResult(PtrTy V) {
+ void *VP = PtrTraits::getAsVoidPointer(V);
+ PtrWithInvalid = reinterpret_cast<uintptr_t>(VP);
+ assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer");
+ }
+
+ ActionResult(const DiagnosticBuilder &) : PtrWithInvalid(0x01) { }
+
+ PtrTy get() const {
+ void *VP = reinterpret_cast<void *>(PtrWithInvalid & ~0x01);
+ return PtrTraits::getFromVoidPointer(VP);
+ }
+
+ void set(PtrTy V) {
+ void *VP = PtrTraits::getAsVoidPointer(V);
+ PtrWithInvalid = reinterpret_cast<uintptr_t>(VP);
+ assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer");
+ }
+
+ bool isInvalid() const { return PtrWithInvalid & 0x01; }
+
+ const ActionResult &operator=(PtrTy RHS) {
+ void *VP = PtrTraits::getAsVoidPointer(RHS);
+ PtrWithInvalid = reinterpret_cast<uintptr_t>(VP);
+ assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer");
+ return *this;
+ }
+ };
+
+ /// Deletion callbacks - Since the parser doesn't know the concrete types of
+ /// the AST nodes being generated, it must do callbacks to delete objects
+ /// when recovering from errors. These are in ActionBase because the smart
+ /// pointers need access to them.
+ virtual void DeleteExpr(ExprTy *E) {}
+ virtual void DeleteStmt(StmtTy *S) {}
+ virtual void DeleteTemplateParams(TemplateParamsTy *P) {}
+ };
+
+ /// ASTDestroyer - The type of an AST node destruction function pointer.
+ typedef void (ActionBase::*ASTDestroyer)(void *);
+
+ /// For the transition phase: translate from an ASTDestroyer to its
+ /// ActionResult UID.
+ template <ASTDestroyer Destroyer> struct DestroyerToUID;
+ template <> struct DestroyerToUID<&ActionBase::DeleteExpr> {
+ static const unsigned UID = 0;
+ };
+ template <> struct DestroyerToUID<&ActionBase::DeleteStmt> {
+ static const unsigned UID = 1;
+ };
+ /// ASTOwningResult - A moveable smart pointer for AST nodes that also
+ /// has an extra flag to indicate an additional success status.
+ template <ASTDestroyer Destroyer> class ASTOwningResult;
+
+ /// ASTMultiPtr - A moveable smart pointer to multiple AST nodes. Only owns
+ /// the individual pointers, not the array holding them.
+ template <ASTDestroyer Destroyer> class ASTMultiPtr;
+
+#if !defined(DISABLE_SMART_POINTERS)
+ namespace moving {
+ /// Move emulation helper for ASTOwningResult. NEVER EVER use this class
+ /// directly if you don't know what you're doing.
+ template <ASTDestroyer Destroyer>
+ class ASTResultMover
+ {
+ ASTOwningResult<Destroyer> &Moved;
+
+ public:
+ ASTResultMover(ASTOwningResult<Destroyer> &moved) : Moved(moved) {}
+
+ ASTOwningResult<Destroyer> * operator ->() { return &Moved; }
+ };
+
+ /// Move emulation helper for ASTMultiPtr. NEVER EVER use this class
+ /// directly if you don't know what you're doing.
+ template <ASTDestroyer Destroyer>
+ class ASTMultiMover
+ {
+ ASTMultiPtr<Destroyer> &Moved;
+
+ public:
+ ASTMultiMover(ASTMultiPtr<Destroyer> &moved) : Moved(moved) {}
+
+ ASTMultiPtr<Destroyer> * operator ->() { return &Moved; }
+
+ /// Reset the moved object's internal structures.
+ void release();
+ };
+ }
+#else
+
+ /// Kept only as a type-safe wrapper for a void pointer, when smart pointers
+ /// are disabled. When they are enabled, ASTOwningResult takes over.
+ template <ASTDestroyer Destroyer>
+ class ASTOwningPtr
+ {
+ void *Node;
+
+ public:
+ explicit ASTOwningPtr(ActionBase &) : Node(0) {}
+ ASTOwningPtr(ActionBase &, void *node) : Node(node) {}
+ // Normal copying operators are defined implicitly.
+ ASTOwningPtr(const ASTOwningResult<Destroyer> &o);
+
+ ASTOwningPtr & operator =(void *raw) {
+ Node = raw;
+ return *this;
+ }
+
+ /// Access to the raw pointer.
+ void * get() const { return Node; }
+
+ /// Release the raw pointer.
+ void * take() {
+ return Node;
+ }
+
+ /// Take outside ownership of the raw pointer and cast it down.
+ template<typename T>
+ T *takeAs() {
+ return static_cast<T*>(Node);
+ }
+
+ /// Alias for interface familiarity with unique_ptr.
+ void * release() {
+ return take();
+ }
+ };
+#endif
+
+ // Important: There are two different implementations of
+ // ASTOwningResult below, depending on whether
+ // DISABLE_SMART_POINTERS is defined. If you make changes that
+ // affect the interface, be sure to compile and test both ways!
+
+#if !defined(DISABLE_SMART_POINTERS)
+ template <ASTDestroyer Destroyer>
+ class ASTOwningResult
+ {
+ llvm::PointerIntPair<ActionBase*, 1, bool> ActionInv;
+ void *Ptr;
+
+ friend class moving::ASTResultMover<Destroyer>;
+
+ ASTOwningResult(ASTOwningResult&); // DO NOT IMPLEMENT
+ ASTOwningResult& operator =(ASTOwningResult&); // DO NOT IMPLEMENT
+
+ void destroy() {
+ if (Ptr) {
+ assert(ActionInv.getPointer() &&
+ "Smart pointer has node but no action.");
+ (ActionInv.getPointer()->*Destroyer)(Ptr);
+ Ptr = 0;
+ }
+ }
+
+ public:
+ typedef ActionBase::ActionResult<DestroyerToUID<Destroyer>::UID> DumbResult;
+
+ explicit ASTOwningResult(ActionBase &actions, bool invalid = false)
+ : ActionInv(&actions, invalid), Ptr(0) {}
+ ASTOwningResult(ActionBase &actions, void *node)
+ : ActionInv(&actions, false), Ptr(node) {}
+ ASTOwningResult(ActionBase &actions, const DumbResult &res)
+ : ActionInv(&actions, res.isInvalid()), Ptr(res.get()) {}
+ /// Move from another owning result
+ ASTOwningResult(moving::ASTResultMover<Destroyer> mover)
+ : ActionInv(mover->ActionInv),
+ Ptr(mover->Ptr) {
+ mover->Ptr = 0;
+ }
+
+ ~ASTOwningResult() {
+ destroy();
+ }
+
+ /// Move assignment from another owning result
+ ASTOwningResult &operator=(moving::ASTResultMover<Destroyer> mover) {
+ destroy();
+ ActionInv = mover->ActionInv;
+ Ptr = mover->Ptr;
+ mover->Ptr = 0;
+ return *this;
+ }
+
+ /// Assignment from a raw pointer. Takes ownership - beware!
+ ASTOwningResult &operator=(void *raw) {
+ destroy();
+ Ptr = raw;
+ ActionInv.setInt(false);
+ return *this;
+ }
+
+ /// Assignment from an ActionResult. Takes ownership - beware!
+ ASTOwningResult &operator=(const DumbResult &res) {
+ destroy();
+ Ptr = res.get();
+ ActionInv.setInt(res.isInvalid());
+ return *this;
+ }
+
+ /// Access to the raw pointer.
+ void *get() const { return Ptr; }
+
+ bool isInvalid() const { return ActionInv.getInt(); }
+
+ /// Does this point to a usable AST node? To be usable, the node must be
+ /// valid and non-null.
+ bool isUsable() const { return !isInvalid() && get(); }
+
+ /// Take outside ownership of the raw pointer.
+ void *take() {
+ if (isInvalid())
+ return 0;
+ void *tmp = Ptr;
+ Ptr = 0;
+ return tmp;
+ }
+
+ /// Take outside ownership of the raw pointer and cast it down.
+ template<typename T>
+ T *takeAs() {
+ return static_cast<T*>(take());
+ }
+
+ /// Alias for interface familiarity with unique_ptr.
+ void *release() { return take(); }
+
+ /// Pass ownership to a classical ActionResult.
+ DumbResult result() {
+ if (isInvalid())
+ return true;
+ return take();
+ }
+
+ /// Move hook
+ operator moving::ASTResultMover<Destroyer>() {
+ return moving::ASTResultMover<Destroyer>(*this);
+ }
+ };
+#else
+ template <ASTDestroyer Destroyer>
+ class ASTOwningResult
+ {
+ public:
+ typedef ActionBase::ActionResult<DestroyerToUID<Destroyer>::UID> DumbResult;
+
+ private:
+ DumbResult Result;
+
+ public:
+ explicit ASTOwningResult(ActionBase &actions, bool invalid = false)
+ : Result(invalid) { }
+ ASTOwningResult(ActionBase &actions, void *node) : Result(node) { }
+ ASTOwningResult(ActionBase &actions, const DumbResult &res) : Result(res) { }
+ // Normal copying semantics are defined implicitly.
+ ASTOwningResult(const ASTOwningPtr<Destroyer> &o) : Result(o.get()) { }
+
+ /// Assignment from a raw pointer. Takes ownership - beware!
+ ASTOwningResult & operator =(void *raw)
+ {
+ Result = raw;
+ return *this;
+ }
+
+ /// Assignment from an ActionResult. Takes ownership - beware!
+ ASTOwningResult & operator =(const DumbResult &res) {
+ Result = res;
+ return *this;
+ }
+
+ /// Access to the raw pointer.
+ void * get() const { return Result.get(); }
+
+ bool isInvalid() const { return Result.isInvalid(); }
+
+ /// Does this point to a usable AST node? To be usable, the node must be
+ /// valid and non-null.
+ bool isUsable() const { return !Result.isInvalid() && get(); }
+
+ /// Take outside ownership of the raw pointer.
+ void * take() {
+ return Result.get();
+ }
+
+ /// Take outside ownership of the raw pointer and cast it down.
+ template<typename T>
+ T *takeAs() {
+ return static_cast<T*>(take());
+ }
+
+ /// Alias for interface familiarity with unique_ptr.
+ void * release() { return take(); }
+
+ /// Pass ownership to a classical ActionResult.
+ DumbResult result() { return Result; }
+ };
+#endif
+
+ template <ASTDestroyer Destroyer>
+ class ASTMultiPtr
+ {
+#if !defined(DISABLE_SMART_POINTERS)
+ ActionBase &Actions;
+#endif
+ void **Nodes;
+ unsigned Count;
+
+#if !defined(DISABLE_SMART_POINTERS)
+ friend class moving::ASTMultiMover<Destroyer>;
+
+ ASTMultiPtr(ASTMultiPtr&); // DO NOT IMPLEMENT
+ // Reference member prevents copy assignment.
+
+ void destroy() {
+ assert((Count == 0 || Nodes) && "No nodes when count is not zero.");
+ for (unsigned i = 0; i < Count; ++i) {
+ if (Nodes[i])
+ (Actions.*Destroyer)(Nodes[i]);
+ }
+ }
+#endif
+
+ public:
+#if !defined(DISABLE_SMART_POINTERS)
+ explicit ASTMultiPtr(ActionBase &actions)
+ : Actions(actions), Nodes(0), Count(0) {}
+ ASTMultiPtr(ActionBase &actions, void **nodes, unsigned count)
+ : Actions(actions), Nodes(nodes), Count(count) {}
+ /// Move constructor
+ ASTMultiPtr(moving::ASTMultiMover<Destroyer> mover)
+ : Actions(mover->Actions), Nodes(mover->Nodes), Count(mover->Count) {
+ mover.release();
+ }
+#else
+ // Normal copying implicitly defined
+ explicit ASTMultiPtr(ActionBase &) : Nodes(0), Count(0) {}
+ ASTMultiPtr(ActionBase &, void **nodes, unsigned count)
+ : Nodes(nodes), Count(count) {}
+ // Fake mover in Parse/AstGuard.h needs this:
+ ASTMultiPtr(void **nodes, unsigned count) : Nodes(nodes), Count(count) {}
+#endif
+
+#if !defined(DISABLE_SMART_POINTERS)
+ /// Move assignment
+ ASTMultiPtr & operator =(moving::ASTMultiMover<Destroyer> mover) {
+ destroy();
+ Nodes = mover->Nodes;
+ Count = mover->Count;
+ mover.release();
+ return *this;
+ }
+#endif
+
+ /// Access to the raw pointers.
+ void ** get() const { return Nodes; }
+
+ /// Access to the count.
+ unsigned size() const { return Count; }
+
+ void ** release() {
+#if !defined(DISABLE_SMART_POINTERS)
+ void **tmp = Nodes;
+ Nodes = 0;
+ Count = 0;
+ return tmp;
+#else
+ return Nodes;
+#endif
+ }
+
+#if !defined(DISABLE_SMART_POINTERS)
+ /// Move hook
+ operator moving::ASTMultiMover<Destroyer>() {
+ return moving::ASTMultiMover<Destroyer>(*this);
+ }
+#endif
+ };
+
+ class ASTTemplateArgsPtr {
+#if !defined(DISABLE_SMART_POINTERS)
+ ActionBase &Actions;
+#endif
+ void **Args;
+ bool *ArgIsType;
+ mutable unsigned Count;
+
+#if !defined(DISABLE_SMART_POINTERS)
+ void destroy() {
+ if (!Count)
+ return;
+
+ for (unsigned i = 0; i != Count; ++i)
+ if (Args[i] && !ArgIsType[i])
+ Actions.DeleteExpr((ActionBase::ExprTy *)Args[i]);
+
+ Count = 0;
+ }
+#endif
+
+ public:
+ ASTTemplateArgsPtr(ActionBase &actions, void **args, bool *argIsType,
+ unsigned count) :
+#if !defined(DISABLE_SMART_POINTERS)
+ Actions(actions),
+#endif
+ Args(args), ArgIsType(argIsType), Count(count) { }
+
+ // FIXME: Lame, not-fully-type-safe emulation of 'move semantics'.
+ ASTTemplateArgsPtr(ASTTemplateArgsPtr &Other) :
+#if !defined(DISABLE_SMART_POINTERS)
+ Actions(Other.Actions),
+#endif
+ Args(Other.Args), ArgIsType(Other.ArgIsType), Count(Other.Count) {
+#if !defined(DISABLE_SMART_POINTERS)
+ Other.Count = 0;
+#endif
+ }
+
+ // FIXME: Lame, not-fully-type-safe emulation of 'move semantics'.
+ ASTTemplateArgsPtr& operator=(ASTTemplateArgsPtr &Other) {
+#if !defined(DISABLE_SMART_POINTERS)
+ Actions = Other.Actions;
+#endif
+ Args = Other.Args;
+ ArgIsType = Other.ArgIsType;
+ Count = Other.Count;
+#if !defined(DISABLE_SMART_POINTERS)
+ Other.Count = 0;
+#endif
+ return *this;
+ }
+
+#if !defined(DISABLE_SMART_POINTERS)
+ ~ASTTemplateArgsPtr() { destroy(); }
+#endif
+
+ void **getArgs() const { return Args; }
+ bool *getArgIsType() const {return ArgIsType; }
+ unsigned size() const { return Count; }
+
+ void reset(void **args, bool *argIsType, unsigned count) {
+#if !defined(DISABLE_SMART_POINTERS)
+ destroy();
+#endif
+ Args = args;
+ ArgIsType = argIsType;
+ Count = count;
+ }
+
+ void *operator[](unsigned Arg) const { return Args[Arg]; }
+
+ void **release() const {
+#if !defined(DISABLE_SMART_POINTERS)
+ Count = 0;
+#endif
+ return Args;
+ }
+ };
+
+ /// \brief A small vector that owns a set of AST nodes.
+ template <ASTDestroyer Destroyer, unsigned N = 8>
+ class ASTOwningVector : public llvm::SmallVector<void *, N> {
+#if !defined(DISABLE_SMART_POINTERS)
+ ActionBase &Actions;
+ bool Owned;
+#endif
+
+ ASTOwningVector(ASTOwningVector &); // do not implement
+ ASTOwningVector &operator=(ASTOwningVector &); // do not implement
+
+ public:
+ explicit ASTOwningVector(ActionBase &Actions)
+#if !defined(DISABLE_SMART_POINTERS)
+ : Actions(Actions), Owned(true)
+#endif
+ { }
+
+#if !defined(DISABLE_SMART_POINTERS)
+ ~ASTOwningVector() {
+ if (!Owned)
+ return;
+
+ for (unsigned I = 0, Last = this->size(); I != Last; ++I)
+ (Actions.*Destroyer)((*this)[I]);
+ }
+#endif
+
+ void **take() {
+#if !defined(DISABLE_SMART_POINTERS)
+ Owned = false;
+#endif
+ return &this->front();
+ }
+
+ template<typename T> T **takeAs() { return (T**)take(); }
+
+#if !defined(DISABLE_SMART_POINTERS)
+ ActionBase &getActions() const { return Actions; }
+#endif
+ };
+
+ /// A SmallVector of statements, with stack size 32 (as that is the only one
+ /// used.)
+ typedef ASTOwningVector<&ActionBase::DeleteStmt, 32> StmtVector;
+ /// A SmallVector of expressions, with stack size 12 (the maximum used.)
+ typedef ASTOwningVector<&ActionBase::DeleteExpr, 12> ExprVector;
+
+ template <ASTDestroyer Destroyer, unsigned N> inline
+ ASTMultiPtr<Destroyer> move_arg(ASTOwningVector<Destroyer, N> &vec) {
+#if !defined(DISABLE_SMART_POINTERS)
+ return ASTMultiPtr<Destroyer>(vec.getActions(), vec.take(), vec.size());
+#else
+ return ASTMultiPtr<Destroyer>(vec.take(), vec.size());
+#endif
+ }
+
+#if !defined(DISABLE_SMART_POINTERS)
+
+ // Out-of-line implementations due to definition dependencies
+
+ template <ASTDestroyer Destroyer> inline
+ void moving::ASTMultiMover<Destroyer>::release() {
+ Moved.Nodes = 0;
+ Moved.Count = 0;
+ }
+
+ // Move overloads.
+
+ template <ASTDestroyer Destroyer> inline
+ ASTOwningResult<Destroyer> move(ASTOwningResult<Destroyer> &ptr) {
+ return ASTOwningResult<Destroyer>(moving::ASTResultMover<Destroyer>(ptr));
+ }
+
+ template <ASTDestroyer Destroyer> inline
+ ASTMultiPtr<Destroyer> move(ASTMultiPtr<Destroyer> &ptr) {
+ return ASTMultiPtr<Destroyer>(moving::ASTMultiMover<Destroyer>(ptr));
+ }
+
+#else
+
+ template <ASTDestroyer Destroyer> inline
+ ASTOwningPtr<Destroyer>::ASTOwningPtr(const ASTOwningResult<Destroyer> &o)
+ : Node(o.get())
+ {}
+
+ // These versions are hopefully no-ops.
+ template <ASTDestroyer Destroyer> inline
+ ASTOwningResult<Destroyer>& move(ASTOwningResult<Destroyer> &ptr) {
+ return ptr;
+ }
+
+ template <ASTDestroyer Destroyer> inline
+ ASTOwningPtr<Destroyer>& move(ASTOwningPtr<Destroyer> &ptr) {
+ return ptr;
+ }
+
+ template <ASTDestroyer Destroyer> inline
+ ASTMultiPtr<Destroyer>& move(ASTMultiPtr<Destroyer> &ptr) {
+ return ptr;
+ }
+#endif
+}
+
+#endif
diff --git a/include/clang/Parse/ParseDiagnostic.h b/include/clang/Parse/ParseDiagnostic.h
new file mode 100644
index 000000000000..a85c6ad6ca7a
--- /dev/null
+++ b/include/clang/Parse/ParseDiagnostic.h
@@ -0,0 +1,27 @@
+//===--- DiagnosticParse.h - Diagnostics for libparse -----------*- 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_DIAGNOSTICPARSE_H
+#define LLVM_CLANG_DIAGNOSTICPARSE_H
+
+#include "clang/Basic/Diagnostic.h"
+
+namespace clang {
+ namespace diag {
+ enum {
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM,
+#define PARSESTART
+#include "clang/Basic/DiagnosticParseKinds.inc"
+#undef DIAG
+ NUM_BUILTIN_PARSE_DIAGNOSTICS
+ };
+ } // end namespace diag
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
new file mode 100644
index 000000000000..26e37e2806a0
--- /dev/null
+++ b/include/clang/Parse/Parser.h
@@ -0,0 +1,1208 @@
+//===--- Parser.h - C Language Parser ---------------------------*- 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 Parser interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PARSE_PARSER_H
+#define LLVM_CLANG_PARSE_PARSER_H
+
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/AccessSpecifier.h"
+#include "clang/Parse/Action.h"
+#include "clang/Parse/DeclSpec.h"
+#include "llvm/ADT/OwningPtr.h"
+#include <stack>
+#include <list>
+
+namespace clang {
+ class AttributeList;
+ class PragmaHandler;
+ class Scope;
+ class DiagnosticBuilder;
+ class Parser;
+ class PragmaUnusedHandler;
+
+/// PrettyStackTraceParserEntry - If a crash happens while the parser is active,
+/// an entry is printed for it.
+class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry {
+ const Parser &P;
+public:
+ PrettyStackTraceParserEntry(const Parser &p) : P(p) {}
+ virtual void print(llvm::raw_ostream &OS) const;
+};
+
+
+/// Parser - This implements a parser for the C family of languages. After
+/// parsing units of the grammar, productions are invoked to handle whatever has
+/// been read.
+///
+class Parser {
+ friend class PragmaUnusedHandler;
+ PrettyStackTraceParserEntry CrashInfo;
+
+ Preprocessor &PP;
+
+ /// Tok - The current token we are peeking ahead. All parsing methods assume
+ /// that this is valid.
+ Token Tok;
+
+ // PrevTokLocation - The location of the token we previously
+ // consumed. This token is used for diagnostics where we expected to
+ // see a token following another token (e.g., the ';' at the end of
+ // a statement).
+ SourceLocation PrevTokLocation;
+
+ unsigned short ParenCount, BracketCount, BraceCount;
+
+ /// Actions - These are the callbacks we invoke as we parse various constructs
+ /// in the file. This refers to the common base class between MinimalActions
+ /// and SemaActions for those uses that don't matter.
+ Action &Actions;
+
+ Scope *CurScope;
+ Diagnostic &Diags;
+
+ /// ScopeCache - Cache scopes to reduce malloc traffic.
+ enum { ScopeCacheSize = 16 };
+ unsigned NumCachedScopes;
+ Scope *ScopeCache[ScopeCacheSize];
+
+ /// Ident_super - IdentifierInfo for "super", to support fast
+ /// comparison.
+ IdentifierInfo *Ident_super;
+
+ llvm::OwningPtr<PragmaHandler> PackHandler;
+ llvm::OwningPtr<PragmaHandler> UnusedHandler;
+
+ /// Whether the '>' token acts as an operator or not. This will be
+ /// true except when we are parsing an expression within a C++
+ /// template argument list, where the '>' closes the template
+ /// argument list.
+ bool GreaterThanIsOperator;
+
+ /// \brief RAII object that makes '>' behave either as an operator
+ /// or as the closing angle bracket for a template argument list.
+ struct GreaterThanIsOperatorScope {
+ bool &GreaterThanIsOperator;
+ bool OldGreaterThanIsOperator;
+
+ GreaterThanIsOperatorScope(bool &GTIO, bool Val)
+ : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) {
+ GreaterThanIsOperator = Val;
+ }
+
+ ~GreaterThanIsOperatorScope() {
+ GreaterThanIsOperator = OldGreaterThanIsOperator;
+ }
+ };
+
+public:
+ Parser(Preprocessor &PP, Action &Actions);
+ ~Parser();
+
+ const LangOptions &getLang() const { return PP.getLangOptions(); }
+ TargetInfo &getTargetInfo() const { return PP.getTargetInfo(); }
+ Preprocessor &getPreprocessor() const { return PP; }
+ Action &getActions() const { return Actions; }
+
+ const Token &getCurToken() const { return Tok; }
+
+ // Type forwarding. All of these are statically 'void*', but they may all be
+ // different actual classes based on the actions in place.
+ typedef Action::ExprTy ExprTy;
+ typedef Action::StmtTy StmtTy;
+ typedef Action::DeclPtrTy DeclPtrTy;
+ typedef Action::DeclGroupPtrTy DeclGroupPtrTy;
+ typedef Action::TypeTy TypeTy;
+ typedef Action::BaseTy BaseTy;
+ typedef Action::MemInitTy MemInitTy;
+ typedef Action::CXXScopeTy CXXScopeTy;
+ typedef Action::TemplateParamsTy TemplateParamsTy;
+ typedef Action::TemplateTy TemplateTy;
+
+ typedef llvm::SmallVector<TemplateParamsTy *, 4> TemplateParameterLists;
+
+ typedef Action::ExprResult ExprResult;
+ typedef Action::StmtResult StmtResult;
+ typedef Action::BaseResult BaseResult;
+ typedef Action::MemInitResult MemInitResult;
+ typedef Action::TypeResult TypeResult;
+
+ typedef Action::OwningExprResult OwningExprResult;
+ typedef Action::OwningStmtResult OwningStmtResult;
+
+ typedef Action::ExprArg ExprArg;
+ typedef Action::MultiStmtArg MultiStmtArg;
+ typedef Action::FullExprArg FullExprArg;
+
+ /// Adorns a ExprResult with Actions to make it an OwningExprResult
+ OwningExprResult Owned(ExprResult res) {
+ return OwningExprResult(Actions, res);
+ }
+ /// Adorns a StmtResult with Actions to make it an OwningStmtResult
+ OwningStmtResult Owned(StmtResult res) {
+ return OwningStmtResult(Actions, res);
+ }
+
+ OwningExprResult ExprError() { return OwningExprResult(Actions, true); }
+ OwningStmtResult StmtError() { return OwningStmtResult(Actions, true); }
+
+ OwningExprResult ExprError(const DiagnosticBuilder &) { return ExprError(); }
+ OwningStmtResult StmtError(const DiagnosticBuilder &) { return StmtError(); }
+
+ OwningExprResult ExprEmpty() { return OwningExprResult(Actions, false); }
+
+ // Parsing methods.
+
+ /// ParseTranslationUnit - All in one method that initializes parses, and
+ /// shuts down the parser.
+ void ParseTranslationUnit();
+
+ /// Initialize - Warm up the parser.
+ ///
+ void Initialize();
+
+ /// ParseTopLevelDecl - Parse one top-level declaration. Returns true if
+ /// the EOF was encountered.
+ bool ParseTopLevelDecl(DeclGroupPtrTy &Result);
+
+private:
+ //===--------------------------------------------------------------------===//
+ // Low-Level token peeking and consumption methods.
+ //
+
+ /// isTokenParen - Return true if the cur token is '(' or ')'.
+ bool isTokenParen() const {
+ return Tok.getKind() == tok::l_paren || Tok.getKind() == tok::r_paren;
+ }
+ /// isTokenBracket - Return true if the cur token is '[' or ']'.
+ bool isTokenBracket() const {
+ return Tok.getKind() == tok::l_square || Tok.getKind() == tok::r_square;
+ }
+ /// isTokenBrace - Return true if the cur token is '{' or '}'.
+ bool isTokenBrace() const {
+ return Tok.getKind() == tok::l_brace || Tok.getKind() == tok::r_brace;
+ }
+
+ /// isTokenStringLiteral - True if this token is a string-literal.
+ ///
+ bool isTokenStringLiteral() const {
+ return Tok.getKind() == tok::string_literal ||
+ Tok.getKind() == tok::wide_string_literal;
+ }
+
+ /// ConsumeToken - Consume the current 'peek token' and lex the next one.
+ /// This does not work with all kinds of tokens: strings and specific other
+ /// tokens must be consumed with custom methods below. This returns the
+ /// location of the consumed token.
+ SourceLocation ConsumeToken() {
+ assert(!isTokenStringLiteral() && !isTokenParen() && !isTokenBracket() &&
+ !isTokenBrace() &&
+ "Should consume special tokens with Consume*Token");
+ PrevTokLocation = Tok.getLocation();
+ PP.Lex(Tok);
+ return PrevTokLocation;
+ }
+
+ /// ConsumeAnyToken - Dispatch to the right Consume* method based on the
+ /// current token type. This should only be used in cases where the type of
+ /// the token really isn't known, e.g. in error recovery.
+ SourceLocation ConsumeAnyToken() {
+ if (isTokenParen())
+ return ConsumeParen();
+ else if (isTokenBracket())
+ return ConsumeBracket();
+ else if (isTokenBrace())
+ return ConsumeBrace();
+ else if (isTokenStringLiteral())
+ return ConsumeStringToken();
+ else
+ return ConsumeToken();
+ }
+
+ /// ConsumeParen - This consume method keeps the paren count up-to-date.
+ ///
+ SourceLocation ConsumeParen() {
+ assert(isTokenParen() && "wrong consume method");
+ if (Tok.getKind() == tok::l_paren)
+ ++ParenCount;
+ else if (ParenCount)
+ --ParenCount; // Don't let unbalanced )'s drive the count negative.
+ PrevTokLocation = Tok.getLocation();
+ PP.Lex(Tok);
+ return PrevTokLocation;
+ }
+
+ /// ConsumeBracket - This consume method keeps the bracket count up-to-date.
+ ///
+ SourceLocation ConsumeBracket() {
+ assert(isTokenBracket() && "wrong consume method");
+ if (Tok.getKind() == tok::l_square)
+ ++BracketCount;
+ else if (BracketCount)
+ --BracketCount; // Don't let unbalanced ]'s drive the count negative.
+
+ PrevTokLocation = Tok.getLocation();
+ PP.Lex(Tok);
+ return PrevTokLocation;
+ }
+
+ /// ConsumeBrace - This consume method keeps the brace count up-to-date.
+ ///
+ SourceLocation ConsumeBrace() {
+ assert(isTokenBrace() && "wrong consume method");
+ if (Tok.getKind() == tok::l_brace)
+ ++BraceCount;
+ else if (BraceCount)
+ --BraceCount; // Don't let unbalanced }'s drive the count negative.
+
+ PrevTokLocation = Tok.getLocation();
+ PP.Lex(Tok);
+ return PrevTokLocation;
+ }
+
+ /// ConsumeStringToken - Consume the current 'peek token', lexing a new one
+ /// and returning the token kind. This method is specific to strings, as it
+ /// handles string literal concatenation, as per C99 5.1.1.2, translation
+ /// phase #6.
+ SourceLocation ConsumeStringToken() {
+ assert(isTokenStringLiteral() &&
+ "Should only consume string literals with this method");
+ PrevTokLocation = Tok.getLocation();
+ PP.Lex(Tok);
+ return PrevTokLocation;
+ }
+
+ /// GetLookAheadToken - This peeks ahead N tokens and returns that token
+ /// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1)
+ /// returns the token after Tok, etc.
+ ///
+ /// Note that this differs from the Preprocessor's LookAhead method, because
+ /// the Parser always has one token lexed that the preprocessor doesn't.
+ ///
+ const Token &GetLookAheadToken(unsigned N) {
+ if (N == 0 || Tok.is(tok::eof)) return Tok;
+ return PP.LookAhead(N-1);
+ }
+
+ /// NextToken - This peeks ahead one token and returns it without
+ /// consuming it.
+ const Token &NextToken() {
+ return PP.LookAhead(0);
+ }
+
+ /// TryAnnotateTypeOrScopeToken - If the current token position is on a
+ /// typename (possibly qualified in C++) or a C++ scope specifier not followed
+ /// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens
+ /// with a single annotation token representing the typename or C++ scope
+ /// respectively.
+ /// This simplifies handling of C++ scope specifiers and allows efficient
+ /// backtracking without the need to re-parse and resolve nested-names and
+ /// typenames.
+ /// It will mainly be called when we expect to treat identifiers as typenames
+ /// (if they are typenames). For example, in C we do not expect identifiers
+ /// inside expressions to be treated as typenames so it will not be called
+ /// for expressions in C.
+ ///
+ /// This returns true if the token was annotated.
+ bool TryAnnotateTypeOrScopeToken();
+
+ /// TryAnnotateCXXScopeToken - Like TryAnnotateTypeOrScopeToken but only
+ /// annotates C++ scope specifiers. This returns true if the token was
+ /// annotated.
+ bool TryAnnotateCXXScopeToken();
+
+ /// TentativeParsingAction - An object that is used as a kind of "tentative
+ /// parsing transaction". It gets instantiated to mark the token position and
+ /// after the token consumption is done, Commit() or Revert() is called to
+ /// either "commit the consumed tokens" or revert to the previously marked
+ /// token position. Example:
+ ///
+ /// TentativeParsingAction TPA;
+ /// ConsumeToken();
+ /// ....
+ /// TPA.Revert();
+ ///
+ class TentativeParsingAction {
+ Parser &P;
+ Token PrevTok;
+ bool isActive;
+
+ public:
+ explicit TentativeParsingAction(Parser& p) : P(p) {
+ PrevTok = P.Tok;
+ P.PP.EnableBacktrackAtThisPos();
+ isActive = true;
+ }
+ void Commit() {
+ assert(isActive && "Parsing action was finished!");
+ P.PP.CommitBacktrackedTokens();
+ isActive = false;
+ }
+ void Revert() {
+ assert(isActive && "Parsing action was finished!");
+ P.PP.Backtrack();
+ P.Tok = PrevTok;
+ isActive = false;
+ }
+ ~TentativeParsingAction() {
+ assert(!isActive && "Forgot to call Commit or Revert!");
+ }
+ };
+
+
+ /// 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 the specified diagnostic indicating
+ /// that the parser failed to match the RHS of the token at LHSLoc. LHSName
+ /// should be the name of the unmatched LHS token. This returns the location
+ /// of the consumed token.
+ SourceLocation MatchRHSPunctuation(tok::TokenKind RHSTok,
+ SourceLocation LHSLoc);
+
+ /// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the
+ /// input. If so, it is consumed and false is returned.
+ ///
+ /// If the input is malformed, this emits the specified diagnostic. Next, if
+ /// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is
+ /// returned.
+ bool ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned Diag,
+ const char *DiagMsg = "",
+ tok::TokenKind SkipToTok = tok::unknown);
+
+ //===--------------------------------------------------------------------===//
+ // Scope manipulation
+
+ /// ParseScope - Introduces a new scope for parsing. The kind of
+ /// scope is determined by ScopeFlags. Objects of this type should
+ /// be created on the stack to coincide with the position where the
+ /// parser enters the new scope, and this object's constructor will
+ /// create that new scope. Similarly, once the object is destroyed
+ /// the parser will exit the scope.
+ class ParseScope {
+ Parser *Self;
+ ParseScope(const ParseScope&); // do not implement
+ ParseScope& operator=(const ParseScope&); // do not implement
+
+ public:
+ // ParseScope - Construct a new object to manage a scope in the
+ // parser Self where the new Scope is created with the flags
+ // ScopeFlags, but only when ManageScope is true (the default). If
+ // ManageScope is false, this object does nothing.
+ ParseScope(Parser *Self, unsigned ScopeFlags, bool ManageScope = true)
+ : Self(Self) {
+ if (ManageScope)
+ Self->EnterScope(ScopeFlags);
+ else
+ this->Self = 0;
+ }
+
+ // Exit - Exit the scope associated with this object now, rather
+ // than waiting until the object is destroyed.
+ void Exit() {
+ if (Self) {
+ Self->ExitScope();
+ Self = 0;
+ }
+ }
+
+ ~ParseScope() {
+ Exit();
+ }
+ };
+
+ /// EnterScope - Start a new scope.
+ void EnterScope(unsigned ScopeFlags);
+
+ /// ExitScope - Pop a scope off the scope stack.
+ void ExitScope();
+
+ //===--------------------------------------------------------------------===//
+ // Diagnostic Emission and Error recovery.
+
+ DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
+ DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID);
+
+ void SuggestParentheses(SourceLocation Loc, unsigned DK,
+ SourceRange ParenRange);
+
+ /// SkipUntil - Read tokens until we get to the specified token, then consume
+ /// it (unless DontConsume is true). Because we cannot guarantee that the
+ /// token will ever occur, this skips to the next token, or to some likely
+ /// good stopping point. If StopAtSemi is true, skipping will stop at a ';'
+ /// character.
+ ///
+ /// If SkipUntil finds the specified token, it returns true, otherwise it
+ /// returns false.
+ bool SkipUntil(tok::TokenKind T, bool StopAtSemi = true,
+ bool DontConsume = false) {
+ return SkipUntil(&T, 1, StopAtSemi, DontConsume);
+ }
+ bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, bool StopAtSemi = true,
+ bool DontConsume = false) {
+ tok::TokenKind TokArray[] = {T1, T2};
+ return SkipUntil(TokArray, 2, StopAtSemi, DontConsume);
+ }
+ bool SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
+ bool StopAtSemi = true, bool DontConsume = false);
+
+ //===--------------------------------------------------------------------===//
+ // Lexing and parsing of C++ inline methods.
+
+ struct LexedMethod {
+ Action::DeclPtrTy D;
+ CachedTokens Toks;
+ explicit LexedMethod(Action::DeclPtrTy MD) : D(MD) {}
+ };
+
+ /// LateParsedDefaultArgument - Keeps track of a parameter that may
+ /// have a default argument that cannot be parsed yet because it
+ /// occurs within a member function declaration inside the class
+ /// (C++ [class.mem]p2).
+ struct LateParsedDefaultArgument {
+ explicit LateParsedDefaultArgument(Action::DeclPtrTy P,
+ CachedTokens *Toks = 0)
+ : Param(P), Toks(Toks) { }
+
+ /// Param - The parameter declaration for this parameter.
+ Action::DeclPtrTy Param;
+
+ /// Toks - The sequence of tokens that comprises the default
+ /// argument expression, not including the '=' or the terminating
+ /// ')' or ','. This will be NULL for parameters that have no
+ /// default argument.
+ CachedTokens *Toks;
+ };
+
+ /// LateParsedMethodDeclaration - A method declaration inside a class that
+ /// contains at least one entity whose parsing needs to be delayed
+ /// until the class itself is completely-defined, such as a default
+ /// argument (C++ [class.mem]p2).
+ struct LateParsedMethodDeclaration {
+ explicit LateParsedMethodDeclaration(Action::DeclPtrTy M) : Method(M) { }
+
+ /// Method - The method declaration.
+ Action::DeclPtrTy Method;
+
+ /// DefaultArgs - Contains the parameters of the function and
+ /// their default arguments. At least one of the parameters will
+ /// 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;
+ };
+
+ /// LateParsedMethodDecls - During parsing of a top (non-nested) C++
+ /// class, its method declarations that contain parts that won't be
+ /// parsed until after the definiton is completed (C++ [class.mem]p2),
+ /// the method declarations will be stored here with the tokens that
+ /// will be parsed to create those entities.
+ typedef std::list<LateParsedMethodDeclaration> LateParsedMethodDecls;
+
+ /// LexedMethodsForTopClass - During parsing of a top (non-nested) C++ class,
+ /// its inline method definitions and the inline method definitions of its
+ /// nested classes are lexed and stored here.
+ typedef std::list<LexedMethod> LexedMethodsForTopClass;
+
+ /// \brief Representation of a class that has been parsed, including
+ /// any member function declarations or definitions that need to be
+ /// parsed after the corresponding top-level class is complete.
+ struct ParsingClass {
+ ParsingClass(DeclPtrTy TagOrTemplate, bool TopLevelClass)
+ : TopLevelClass(TopLevelClass), TemplateScope(false),
+ TagOrTemplate(TagOrTemplate) { }
+
+ /// \brief Whether this is a "top-level" class, meaning that it is
+ /// not nested within another class.
+ bool TopLevelClass : 1;
+
+ /// \brief Whether this class had an associated template
+ /// scope. When true, TagOrTemplate is a template declaration;
+ /// othewise, it is a tag declaration.
+ bool TemplateScope : 1;
+
+ /// \brief The class or class template whose definition we are parsing.
+ DeclPtrTy TagOrTemplate;
+
+ /// MethodDecls - Method declarations that contain pieces whose
+ /// parsing will be delayed until the class is fully defined.
+ LateParsedMethodDecls MethodDecls;
+
+ /// MethodDefs - Methods whose definitions will be parsed once the
+ /// class has been fully defined.
+ LexedMethodsForTopClass MethodDefs;
+
+ /// \brief Nested classes inside this class.
+ llvm::SmallVector<ParsingClass*, 4> NestedClasses;
+ };
+
+ /// \brief The stack of classes that is currently being
+ /// parsed. Nested and local classes will be pushed onto this stack
+ /// when they are parsed, and removed afterward.
+ std::stack<ParsingClass *> ClassStack;
+
+ ParsingClass &getCurrentClass() {
+ assert(!ClassStack.empty() && "No lexed method stacks!");
+ return *ClassStack.top();
+ }
+
+ /// \brief RAII object used to
+ class ParsingClassDefinition {
+ Parser &P;
+ bool Popped;
+
+ public:
+ ParsingClassDefinition(Parser &P, DeclPtrTy TagOrTemplate, bool TopLevelClass)
+ : P(P), Popped(false) {
+ P.PushParsingClass(TagOrTemplate, TopLevelClass);
+ }
+
+ /// \brief Pop this class of the stack.
+ void Pop() {
+ assert(!Popped && "Nested class has already been popped");
+ Popped = true;
+ P.PopParsingClass();
+ }
+
+ ~ParsingClassDefinition() {
+ if (!Popped)
+ P.PopParsingClass();
+ }
+ };
+
+ void PushParsingClass(DeclPtrTy TagOrTemplate, bool TopLevelClass);
+ void DeallocateParsedClasses(ParsingClass *Class);
+ void PopParsingClass();
+
+ DeclPtrTy ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D);
+ void ParseLexedMethodDeclarations(ParsingClass &Class);
+ void ParseLexedMethodDefs(ParsingClass &Class);
+ bool ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
+ CachedTokens &Toks,
+ tok::TokenKind EarlyAbortIf = tok::unknown,
+ bool ConsumeFinalToken = true);
+
+ /// \brief Contains information about any template-specific
+ /// information that has been parsed prior to parsing declaration
+ /// specifiers.
+ struct ParsedTemplateInfo {
+ ParsedTemplateInfo()
+ : Kind(NonTemplate), TemplateParams(0), TemplateLoc() { }
+
+ ParsedTemplateInfo(TemplateParameterLists *TemplateParams,
+ bool isSpecialization)
+ : Kind(isSpecialization? ExplicitSpecialization : Template),
+ TemplateParams(TemplateParams) { }
+
+ explicit ParsedTemplateInfo(SourceLocation TemplateLoc)
+ : Kind(ExplicitInstantiation), TemplateParams(0),
+ TemplateLoc(TemplateLoc) { }
+
+ /// \brief The kind of template we are parsing.
+ enum {
+ /// \brief We are not parsing a template at all.
+ NonTemplate = 0,
+ /// \brief We are parsing a template declaration.
+ Template,
+ /// \brief We are parsing an explicit specialization.
+ ExplicitSpecialization,
+ /// \brief We are parsing an explicit instantiation.
+ ExplicitInstantiation
+ } Kind;
+
+ /// \brief The template parameter lists, for template declarations
+ /// and explicit specializations.
+ TemplateParameterLists *TemplateParams;
+
+ /// \brief The location of the 'template' keyword, for an explicit
+ /// instantiation.
+ SourceLocation TemplateLoc;
+ };
+
+ //===--------------------------------------------------------------------===//
+ // C99 6.9: External Definitions.
+ DeclGroupPtrTy ParseExternalDeclaration();
+ bool isDeclarationAfterDeclarator();
+ bool isStartOfFunctionDefinition();
+ DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(
+ AccessSpecifier AS = AS_none);
+
+ DeclPtrTy ParseFunctionDefinition(Declarator &D);
+ void ParseKNRParamDeclarations(Declarator &D);
+ // EndLoc, if non-NULL, is filled with the location of the last token of
+ // the simple-asm.
+ OwningExprResult ParseSimpleAsm(SourceLocation *EndLoc = 0);
+ OwningExprResult ParseAsmStringLiteral();
+
+ // Objective-C External Declarations
+ DeclPtrTy ParseObjCAtDirectives();
+ DeclPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc);
+ DeclPtrTy ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
+ AttributeList *prefixAttrs = 0);
+ void ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
+ SourceLocation atLoc);
+ bool ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &P,
+ bool WarnOnDeclarations,
+ SourceLocation &EndProtoLoc);
+ void ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
+ tok::ObjCKeywordKind contextKey);
+ DeclPtrTy ParseObjCAtProtocolDeclaration(SourceLocation atLoc,
+ AttributeList *prefixAttrs = 0);
+
+ DeclPtrTy ObjCImpDecl;
+
+ DeclPtrTy ParseObjCAtImplementationDeclaration(SourceLocation atLoc);
+ DeclPtrTy ParseObjCAtEndDeclaration(SourceLocation atLoc);
+ DeclPtrTy ParseObjCAtAliasDeclaration(SourceLocation atLoc);
+ DeclPtrTy ParseObjCPropertySynthesize(SourceLocation atLoc);
+ DeclPtrTy ParseObjCPropertyDynamic(SourceLocation atLoc);
+
+ IdentifierInfo *ParseObjCSelectorPiece(SourceLocation &MethodLocation);
+ // Definitions for Objective-c context sensitive keywords recognition.
+ enum ObjCTypeQual {
+ objc_in=0, objc_out, objc_inout, objc_oneway, objc_bycopy, objc_byref,
+ objc_NumQuals
+ };
+ IdentifierInfo *ObjCTypeQuals[objc_NumQuals];
+
+ bool isTokIdentifier_in() const;
+
+ TypeTy *ParseObjCTypeName(ObjCDeclSpec &DS);
+ void ParseObjCMethodRequirement();
+ DeclPtrTy ParseObjCMethodPrototype(DeclPtrTy classOrCat,
+ tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword);
+ DeclPtrTy ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType,
+ DeclPtrTy classDecl,
+ tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword);
+ void ParseObjCPropertyAttribute(ObjCDeclSpec &DS);
+
+ DeclPtrTy ParseObjCMethodDefinition();
+
+ //===--------------------------------------------------------------------===//
+ // C99 6.5: Expressions.
+
+ OwningExprResult ParseExpression();
+ OwningExprResult ParseConstantExpression();
+ // Expr that doesn't include commas.
+ OwningExprResult ParseAssignmentExpression();
+
+ OwningExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc);
+
+ OwningExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc);
+
+ OwningExprResult ParseRHSOfBinaryExpression(OwningExprResult LHS,
+ unsigned MinPrec);
+ OwningExprResult ParseCastExpression(bool isUnaryExpression,
+ bool isAddressOfOperand,
+ bool &NotCastExpr);
+ OwningExprResult ParseCastExpression(bool isUnaryExpression,
+ bool isAddressOfOperand = false);
+ OwningExprResult ParsePostfixExpressionSuffix(OwningExprResult LHS);
+ OwningExprResult ParseSizeofAlignofExpression();
+ OwningExprResult ParseBuiltinPrimaryExpression();
+
+ OwningExprResult ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
+ bool &isCastExpr,
+ TypeTy *&CastTy,
+ SourceRange &CastRange);
+
+ static const unsigned ExprListSize = 12;
+ typedef llvm::SmallVector<ExprTy*, ExprListSize> ExprListTy;
+ typedef llvm::SmallVector<SourceLocation, ExprListSize> CommaLocsTy;
+
+ /// ParseExpressionList - Used for C/C++ (argument-)expression-list.
+ bool ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs);
+
+ /// ParenParseOption - Control what ParseParenExpression will parse.
+ enum ParenParseOption {
+ SimpleExpr, // Only parse '(' expression ')'
+ CompoundStmt, // Also allow '(' compound-statement ')'
+ CompoundLiteral, // Also allow '(' type-name ')' '{' ... '}'
+ CastExpr // Also allow '(' type-name ')' <anything>
+ };
+ OwningExprResult ParseParenExpression(ParenParseOption &ExprType,
+ bool stopIfCastExpr,
+ TypeTy *&CastTy,
+ SourceLocation &RParenLoc);
+
+ OwningExprResult ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
+ TypeTy *&CastTy,
+ SourceLocation LParenLoc,
+ SourceLocation &RParenLoc);
+
+ OwningExprResult ParseCompoundLiteralExpression(TypeTy *Ty,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc);
+
+ OwningExprResult ParseStringLiteralExpression();
+
+ //===--------------------------------------------------------------------===//
+ // C++ Expressions
+ OwningExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);
+
+ /// ParseOptionalCXXScopeSpecifier - Parse global scope or
+ /// nested-name-specifier if present. Returns true if a nested-name-specifier
+ /// was parsed from the token stream. Note that this routine will not parse
+ /// ::new or ::delete, it will just leave them in the token stream.
+ ///
+ bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS);
+
+ //===--------------------------------------------------------------------===//
+ // C++ 5.2p1: C++ Casts
+ OwningExprResult ParseCXXCasts();
+
+ //===--------------------------------------------------------------------===//
+ // C++ 5.2p1: C++ Type Identification
+ OwningExprResult ParseCXXTypeid();
+
+ //===--------------------------------------------------------------------===//
+ // C++ 9.3.2: C++ 'this' pointer
+ OwningExprResult ParseCXXThis();
+
+ //===--------------------------------------------------------------------===//
+ // C++ 15: C++ Throw Expression
+ OwningExprResult ParseThrowExpression();
+ // EndLoc is filled with the location of the last token of the specification.
+ bool ParseExceptionSpecification(SourceLocation &EndLoc,
+ llvm::SmallVector<TypeTy*, 2> &Exceptions,
+ llvm::SmallVector<SourceRange, 2> &Ranges,
+ bool &hasAnyExceptionSpec);
+
+ //===--------------------------------------------------------------------===//
+ // C++ 2.13.5: C++ Boolean Literals
+ OwningExprResult ParseCXXBoolLiteral();
+
+ //===--------------------------------------------------------------------===//
+ // C++ 5.2.3: Explicit type conversion (functional notation)
+ OwningExprResult ParseCXXTypeConstructExpression(const DeclSpec &DS);
+
+ /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
+ /// This should only be called when the current token is known to be part of
+ /// simple-type-specifier.
+ void ParseCXXSimpleTypeSpecifier(DeclSpec &DS);
+
+ bool ParseCXXTypeSpecifierSeq(DeclSpec &DS);
+
+ //===--------------------------------------------------------------------===//
+ // C++ 5.3.4 and 5.3.5: C++ new and delete
+ bool ParseExpressionListOrTypeId(ExprListTy &Exprs, Declarator &D);
+ void ParseDirectNewDeclarator(Declarator &D);
+ OwningExprResult ParseCXXNewExpression(bool UseGlobal, SourceLocation Start);
+ OwningExprResult ParseCXXDeleteExpression(bool UseGlobal,
+ SourceLocation Start);
+
+ //===--------------------------------------------------------------------===//
+ // C++ if/switch/while/for condition expression.
+ OwningExprResult ParseCXXCondition();
+
+ //===--------------------------------------------------------------------===//
+ // C++ types
+
+ //===--------------------------------------------------------------------===//
+ // C99 6.7.8: Initialization.
+
+ /// ParseInitializer
+ /// initializer: [C99 6.7.8]
+ /// assignment-expression
+ /// '{' ...
+ OwningExprResult ParseInitializer() {
+ if (Tok.isNot(tok::l_brace))
+ return ParseAssignmentExpression();
+ return ParseBraceInitializer();
+ }
+ OwningExprResult ParseBraceInitializer();
+ OwningExprResult ParseInitializerWithPotentialDesignator();
+
+ //===--------------------------------------------------------------------===//
+ // clang Expressions
+
+ OwningExprResult ParseBlockLiteralExpression(); // ^{...}
+
+ //===--------------------------------------------------------------------===//
+ // Objective-C Expressions
+
+ bool isTokObjCMessageIdentifierReceiver() const {
+ if (!Tok.is(tok::identifier))
+ return false;
+
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (Actions.getTypeName(*II, Tok.getLocation(), CurScope))
+ return true;
+
+ return II == Ident_super;
+ }
+
+ OwningExprResult ParseObjCAtExpression(SourceLocation AtLocation);
+ OwningExprResult ParseObjCStringLiteral(SourceLocation AtLoc);
+ OwningExprResult ParseObjCEncodeExpression(SourceLocation AtLoc);
+ OwningExprResult ParseObjCSelectorExpression(SourceLocation AtLoc);
+ OwningExprResult ParseObjCProtocolExpression(SourceLocation AtLoc);
+ OwningExprResult ParseObjCMessageExpression();
+ OwningExprResult ParseObjCMessageExpressionBody(SourceLocation LBracloc,
+ SourceLocation NameLoc,
+ IdentifierInfo *ReceiverName,
+ ExprArg ReceiverExpr);
+ OwningExprResult ParseAssignmentExprWithObjCMessageExprStart(
+ SourceLocation LBracloc, SourceLocation NameLoc,
+ IdentifierInfo *ReceiverName, ExprArg ReceiverExpr);
+
+ //===--------------------------------------------------------------------===//
+ // C99 6.8: Statements and Blocks.
+
+ OwningStmtResult ParseStatement() {
+ return ParseStatementOrDeclaration(true);
+ }
+ OwningStmtResult ParseStatementOrDeclaration(bool OnlyStatement = false);
+ OwningStmtResult ParseLabeledStatement();
+ OwningStmtResult ParseCaseStatement();
+ OwningStmtResult ParseDefaultStatement();
+ OwningStmtResult ParseCompoundStatement(bool isStmtExpr = false);
+ OwningStmtResult ParseCompoundStatementBody(bool isStmtExpr = false);
+ bool ParseParenExprOrCondition(OwningExprResult &CondExp,
+ bool OnlyAllowCondition = false);
+ OwningStmtResult ParseIfStatement();
+ OwningStmtResult ParseSwitchStatement();
+ OwningStmtResult ParseWhileStatement();
+ OwningStmtResult ParseDoStatement();
+ OwningStmtResult ParseForStatement();
+ OwningStmtResult ParseGotoStatement();
+ OwningStmtResult ParseContinueStatement();
+ OwningStmtResult ParseBreakStatement();
+ OwningStmtResult ParseReturnStatement();
+ OwningStmtResult ParseAsmStatement(bool &msAsm);
+ OwningStmtResult FuzzyParseMicrosoftAsmStatement();
+ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names,
+ llvm::SmallVectorImpl<ExprTy*> &Constraints,
+ llvm::SmallVectorImpl<ExprTy*> &Exprs);
+
+ //===--------------------------------------------------------------------===//
+ // C++ 6: Statements and Blocks
+
+ OwningStmtResult ParseCXXTryBlock();
+ OwningStmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc);
+ OwningStmtResult ParseCXXCatchBlock();
+
+ //===--------------------------------------------------------------------===//
+ // Objective-C Statements
+
+ OwningStmtResult ParseObjCAtStatement(SourceLocation atLoc);
+ OwningStmtResult ParseObjCTryStmt(SourceLocation atLoc);
+ OwningStmtResult ParseObjCThrowStmt(SourceLocation atLoc);
+ OwningStmtResult ParseObjCSynchronizedStmt(SourceLocation atLoc);
+
+
+ //===--------------------------------------------------------------------===//
+ // C99 6.7: Declarations.
+
+ DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd);
+ DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context,
+ SourceLocation &DeclEnd,
+ bool RequireSemi = true);
+ DeclPtrTy ParseDeclarationAfterDeclarator(Declarator &D);
+ DeclGroupPtrTy ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D);
+ DeclPtrTy ParseFunctionStatementBody(DeclPtrTy Decl);
+ DeclPtrTy ParseFunctionTryBlock(DeclPtrTy Decl);
+
+ bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
+ const ParsedTemplateInfo &TemplateInfo,
+ AccessSpecifier AS);
+ void ParseDeclarationSpecifiers(DeclSpec &DS,
+ const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
+ AccessSpecifier AS = AS_none);
+ bool ParseOptionalTypeSpecifier(DeclSpec &DS, int &isInvalid,
+ const char *&PrevSpec,
+ const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
+
+ void ParseSpecifierQualifierList(DeclSpec &DS);
+
+ void ParseObjCTypeQualifierList(ObjCDeclSpec &DS);
+
+ void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS,
+ AccessSpecifier AS = AS_none);
+ void ParseEnumBody(SourceLocation StartLoc, DeclPtrTy TagDecl);
+ void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType,
+ DeclPtrTy TagDecl);
+ void ParseStructDeclaration(DeclSpec &DS,
+ llvm::SmallVectorImpl<FieldDeclarator> &Fields);
+
+ bool isDeclarationSpecifier();
+ bool isTypeSpecifierQualifier();
+ bool isTypeQualifier() const;
+
+ /// isDeclarationStatement - Disambiguates between a declaration or an
+ /// expression statement, when parsing function bodies.
+ /// Returns true for declaration, false for expression.
+ bool isDeclarationStatement() {
+ if (getLang().CPlusPlus)
+ return isCXXDeclarationStatement();
+ return isDeclarationSpecifier();
+ }
+
+ /// isSimpleDeclaration - Disambiguates between a declaration or an
+ /// expression, mainly used for the C 'clause-1' or the C++
+ // 'for-init-statement' part of a 'for' statement.
+ /// Returns true for declaration, false for expression.
+ bool isSimpleDeclaration() {
+ if (getLang().CPlusPlus)
+ return isCXXSimpleDeclaration();
+ return isDeclarationSpecifier();
+ }
+
+ /// \brief Specifies the context in which type-id/expression
+ /// disambiguation will occur.
+ enum TentativeCXXTypeIdContext {
+ TypeIdInParens,
+ TypeIdAsTemplateArgument
+ };
+
+
+ /// isTypeIdInParens - Assumes that a '(' was parsed and now we want to know
+ /// whether the parens contain an expression or a type-id.
+ /// Returns true for a type-id and false for an expression.
+ bool isTypeIdInParens(bool &isAmbiguous) {
+ if (getLang().CPlusPlus)
+ return isCXXTypeId(TypeIdInParens, isAmbiguous);
+ isAmbiguous = false;
+ return isTypeSpecifierQualifier();
+ }
+ bool isTypeIdInParens() {
+ bool isAmbiguous;
+ return isTypeIdInParens(isAmbiguous);
+ }
+
+ /// isCXXDeclarationStatement - C++-specialized function that disambiguates
+ /// between a declaration or an expression statement, when parsing function
+ /// bodies. Returns true for declaration, false for expression.
+ bool isCXXDeclarationStatement();
+
+ /// isCXXSimpleDeclaration - C++-specialized function that disambiguates
+ /// between a simple-declaration or an expression-statement.
+ /// If during the disambiguation process a parsing error is encountered,
+ /// the function returns true to let the declaration parsing code handle it.
+ /// Returns false if the statement is disambiguated as expression.
+ bool isCXXSimpleDeclaration();
+
+ /// isCXXFunctionDeclarator - Disambiguates between a function declarator or
+ /// a constructor-style initializer, when parsing declaration statements.
+ /// Returns true for function declarator and false for constructor-style
+ /// initializer. If 'warnIfAmbiguous' is true a warning will be emitted to
+ /// indicate that the parens were disambiguated as function declarator.
+ /// If during the disambiguation process a parsing error is encountered,
+ /// the function returns true to let the declaration parsing code handle it.
+ bool isCXXFunctionDeclarator(bool warnIfAmbiguous);
+
+ /// isCXXConditionDeclaration - Disambiguates between a declaration or an
+ /// expression for a condition of a if/switch/while/for statement.
+ /// If during the disambiguation process a parsing error is encountered,
+ /// the function returns true to let the declaration parsing code handle it.
+ bool isCXXConditionDeclaration();
+
+ bool isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous);
+ bool isCXXTypeId(TentativeCXXTypeIdContext Context) {
+ bool isAmbiguous;
+ return isCXXTypeId(Context, isAmbiguous);
+ }
+
+ /// TPResult - Used as the result value for functions whose purpose is to
+ /// disambiguate C++ constructs by "tentatively parsing" them.
+ /// This is a class instead of a simple enum because the implicit enum-to-bool
+ /// conversions may cause subtle bugs.
+ class TPResult {
+ enum Result {
+ TPR_true,
+ TPR_false,
+ TPR_ambiguous,
+ TPR_error
+ };
+ Result Res;
+ TPResult(Result result) : Res(result) {}
+ public:
+ static TPResult True() { return TPR_true; }
+ static TPResult False() { return TPR_false; }
+ static TPResult Ambiguous() { return TPR_ambiguous; }
+ static TPResult Error() { return TPR_error; }
+
+ bool operator==(const TPResult &RHS) const { return Res == RHS.Res; }
+ bool operator!=(const TPResult &RHS) const { return Res != RHS.Res; }
+ };
+
+ /// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a
+ /// declaration specifier, TPResult::False() if it is not,
+ /// TPResult::Ambiguous() if it could be either a decl-specifier or a
+ /// function-style cast, and TPResult::Error() if a parsing error was
+ /// encountered.
+ /// Doesn't consume tokens.
+ TPResult isCXXDeclarationSpecifier();
+
+ // "Tentative parsing" functions, used for disambiguation. If a parsing error
+ // is encountered they will return TPResult::Error().
+ // Returning TPResult::True()/False() indicates that the ambiguity was
+ // resolved and tentative parsing may stop. TPResult::Ambiguous() indicates
+ // that more tentative parsing is necessary for disambiguation.
+ // They all consume tokens, so backtracking should be used after calling them.
+
+ TPResult TryParseDeclarationSpecifier();
+ TPResult TryParseSimpleDeclaration();
+ TPResult TryParseTypeofSpecifier();
+ TPResult TryParseInitDeclaratorList();
+ TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier=true);
+ TPResult TryParseParameterDeclarationClause();
+ TPResult TryParseFunctionDeclarator();
+ TPResult TryParseBracketDeclarator();
+
+ TypeResult ParseTypeName(SourceRange *Range = 0);
+ void ParseBlockId();
+ // EndLoc, if non-NULL, is filled with the location of the last token of
+ // the attribute list.
+ AttributeList *ParseAttributes(SourceLocation *EndLoc = 0);
+ void FuzzyParseMicrosoftDeclSpec();
+ void ParseTypeofSpecifier(DeclSpec &DS);
+
+ /// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to
+ /// enter a new C++ declarator scope and exit it when the function is
+ /// finished.
+ class DeclaratorScopeObj {
+ Parser &P;
+ CXXScopeSpec &SS;
+ public:
+ DeclaratorScopeObj(Parser &p, CXXScopeSpec &ss) : P(p), SS(ss) {}
+
+ void EnterDeclaratorScope() {
+ if (SS.isSet())
+ P.Actions.ActOnCXXEnterDeclaratorScope(P.CurScope, SS);
+ }
+
+ ~DeclaratorScopeObj() {
+ if (SS.isSet())
+ P.Actions.ActOnCXXExitDeclaratorScope(P.CurScope, SS);
+ }
+ };
+
+ /// ParseDeclarator - Parse and verify a newly-initialized declarator.
+ void ParseDeclarator(Declarator &D);
+ /// A function that parses a variant of direct-declarator.
+ typedef void (Parser::*DirectDeclParseFunction)(Declarator&);
+ void ParseDeclaratorInternal(Declarator &D,
+ DirectDeclParseFunction DirectDeclParser);
+ void ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed = true);
+ void ParseDirectDeclarator(Declarator &D);
+ void ParseParenDeclarator(Declarator &D);
+ void ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
+ AttributeList *AttrList = 0,
+ bool RequiresArg = false);
+ void ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
+ Declarator &D);
+ void ParseBracketDeclarator(Declarator &D);
+
+ //===--------------------------------------------------------------------===//
+ // C++ 7: Declarations [dcl.dcl]
+
+ DeclPtrTy ParseNamespace(unsigned Context, SourceLocation &DeclEnd);
+ DeclPtrTy ParseLinkage(unsigned Context);
+ DeclPtrTy ParseUsingDirectiveOrDeclaration(unsigned Context,
+ SourceLocation &DeclEnd);
+ DeclPtrTy ParseUsingDirective(unsigned Context, SourceLocation UsingLoc,
+ SourceLocation &DeclEnd);
+ DeclPtrTy ParseUsingDeclaration(unsigned Context, SourceLocation UsingLoc,
+ SourceLocation &DeclEnd);
+ DeclPtrTy ParseStaticAssertDeclaration(SourceLocation &DeclEnd);
+ DeclPtrTy ParseNamespaceAlias(SourceLocation NamespaceLoc,
+ SourceLocation AliasLoc, IdentifierInfo *Alias,
+ SourceLocation &DeclEnd);
+
+ //===--------------------------------------------------------------------===//
+ // C++ 9: classes [class] and C structs/unions.
+ TypeResult ParseClassName(SourceLocation &EndLocation,
+ const CXXScopeSpec *SS = 0);
+ void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc,
+ DeclSpec &DS,
+ const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
+ AccessSpecifier AS = AS_none);
+ void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
+ DeclPtrTy TagDecl);
+ void ParseCXXClassMemberDeclaration(AccessSpecifier AS);
+ void ParseConstructorInitializer(DeclPtrTy ConstructorDecl);
+ MemInitResult ParseMemInitializer(DeclPtrTy ConstructorDecl);
+
+ //===--------------------------------------------------------------------===//
+ // C++ 10: Derived classes [class.derived]
+ void ParseBaseClause(DeclPtrTy ClassDecl);
+ BaseResult ParseBaseSpecifier(DeclPtrTy ClassDecl);
+ AccessSpecifier getAccessSpecifierIfPresent() const;
+
+ //===--------------------------------------------------------------------===//
+ // C++ 13.5: Overloaded operators [over.oper]
+ // EndLoc, if non-NULL, is filled with the location of the last token of
+ // the ID.
+ OverloadedOperatorKind TryParseOperatorFunctionId(SourceLocation *EndLoc = 0);
+ TypeTy *ParseConversionFunctionId(SourceLocation *EndLoc = 0);
+
+ //===--------------------------------------------------------------------===//
+ // C++ 14: Templates [temp]
+ typedef llvm::SmallVector<DeclPtrTy, 4> TemplateParameterList;
+
+ // C++ 14.1: Template Parameters [temp.param]
+ DeclPtrTy ParseDeclarationStartingWithTemplate(unsigned Context,
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS = AS_none);
+ DeclPtrTy ParseTemplateDeclarationOrSpecialization(unsigned Context,
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS);
+ DeclPtrTy ParseSingleDeclarationAfterTemplate(
+ unsigned Context,
+ const ParsedTemplateInfo &TemplateInfo,
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS=AS_none);
+ bool ParseTemplateParameters(unsigned Depth,
+ TemplateParameterList &TemplateParams,
+ SourceLocation &LAngleLoc,
+ SourceLocation &RAngleLoc);
+ bool ParseTemplateParameterList(unsigned Depth,
+ TemplateParameterList &TemplateParams);
+ DeclPtrTy ParseTemplateParameter(unsigned Depth, unsigned Position);
+ DeclPtrTy ParseTypeParameter(unsigned Depth, unsigned Position);
+ DeclPtrTy ParseTemplateTemplateParameter(unsigned Depth, unsigned Position);
+ DeclPtrTy ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position);
+ // C++ 14.3: Template arguments [temp.arg]
+ typedef llvm::SmallVector<void *, 16> TemplateArgList;
+ typedef llvm::SmallVector<bool, 16> TemplateArgIsTypeList;
+ typedef llvm::SmallVector<SourceLocation, 16> TemplateArgLocationList;
+
+ bool ParseTemplateIdAfterTemplateName(TemplateTy Template,
+ SourceLocation TemplateNameLoc,
+ const CXXScopeSpec *SS,
+ bool ConsumeLastToken,
+ SourceLocation &LAngleLoc,
+ TemplateArgList &TemplateArgs,
+ TemplateArgIsTypeList &TemplateArgIsType,
+ TemplateArgLocationList &TemplateArgLocations,
+ SourceLocation &RAngleLoc);
+
+ void AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
+ const CXXScopeSpec *SS,
+ SourceLocation TemplateKWLoc = SourceLocation(),
+ bool AllowTypeAnnotation = true);
+ void AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS = 0);
+ bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
+ TemplateArgIsTypeList &TemplateArgIsType,
+ TemplateArgLocationList &TemplateArgLocations);
+ void *ParseTemplateArgument(bool &ArgIsType);
+ DeclPtrTy ParseExplicitInstantiation(SourceLocation TemplateLoc,
+ SourceLocation &DeclEnd);
+
+ //===--------------------------------------------------------------------===//
+ // GNU G++: Type Traits [Type-Traits.html in the GCC manual]
+ OwningExprResult ParseUnaryTypeTrait();
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Parse/Scope.h b/include/clang/Parse/Scope.h
new file mode 100644
index 000000000000..84cc5d5c3461
--- /dev/null
+++ b/include/clang/Parse/Scope.h
@@ -0,0 +1,310 @@
+//===--- Scope.h - Scope 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 Scope interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PARSE_SCOPE_H
+#define LLVM_CLANG_PARSE_SCOPE_H
+
+#include "clang/Parse/Action.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+namespace clang {
+
+/// Scope - A scope is a transient data structure that is used while parsing the
+/// program. It assists with resolving identifiers to the appropriate
+/// declaration.
+///
+class Scope {
+public:
+ /// ScopeFlags - These are bitfields that are or'd together when creating a
+ /// scope, which defines the sorts of things the scope contains.
+ enum ScopeFlags {
+ /// FnScope - This indicates that the scope corresponds to a function, which
+ /// means that labels are set here.
+ FnScope = 0x01,
+
+ /// BreakScope - This is a while,do,switch,for, etc that can have break
+ /// stmts embedded into it.
+ BreakScope = 0x02,
+
+ /// ContinueScope - This is a while,do,for, which can have continue
+ /// stmt embedded into it.
+ ContinueScope = 0x04,
+
+ /// DeclScope - This is a scope that can contain a declaration. Some scopes
+ /// just contain loop constructs but don't contain decls.
+ DeclScope = 0x08,
+
+ /// ControlScope - The controlling scope in a if/switch/while/for statement.
+ ControlScope = 0x10,
+
+ /// ClassScope - The scope of a struct/union/class definition.
+ ClassScope = 0x20,
+
+ /// BlockScope - This is a scope that corresponds to a block object.
+ /// Blocks serve as top-level scopes for some objects like labels, they
+ /// also prevent things like break and continue. BlockScopes have the
+ /// other flags set as well.
+ BlockScope = 0x40,
+
+ /// TemplateParamScope - This is a scope that corresponds to the
+ /// template parameters of a C++ template. Template parameter
+ /// scope starts at the 'template' keyword and ends when the
+ /// template declaration ends.
+ TemplateParamScope = 0x80,
+
+ /// FunctionPrototypeScope - This is a scope that corresponds to the
+ /// parameters within a function prototype.
+ FunctionPrototypeScope = 0x100,
+
+ /// AtCatchScope - This is a scope that corresponds to the Objective-C
+ /// @catch statement.
+ AtCatchScope = 0x200
+ };
+private:
+ /// The parent scope for this scope. This is null for the translation-unit
+ /// scope.
+ Scope *AnyParent;
+
+ /// Depth - This is the depth of this scope. The translation-unit scope has
+ /// depth 0.
+ unsigned Depth : 16;
+
+ /// Flags - This contains a set of ScopeFlags, which indicates how the scope
+ /// interrelates with other control flow statements.
+ unsigned Flags : 10;
+
+ /// WithinElse - Whether this scope is part of the "else" branch in
+ /// its parent ControlScope.
+ bool WithinElse : 1;
+
+ /// FnParent - If this scope has a parent scope that is a function body, this
+ /// pointer is non-null and points to it. This is used for label processing.
+ Scope *FnParent;
+
+ /// BreakParent/ContinueParent - This is a direct link to the immediately
+ /// preceeding BreakParent/ContinueParent if this scope is not one, or null if
+ /// there is no containing break/continue scope.
+ Scope *BreakParent, *ContinueParent;
+
+ /// ControlParent - This is a direct link to the immediately
+ /// preceeding ControlParent if this scope is not one, or null if
+ /// there is no containing control scope.
+ Scope *ControlParent;
+
+ /// BlockParent - This is a direct link to the immediately containing
+ /// BlockScope if this scope is not one, or null if there is none.
+ Scope *BlockParent;
+
+ /// TemplateParamParent - This is a direct link to the
+ /// immediately containing template parameter scope. In the
+ /// case of nested templates, template parameter scopes can have
+ /// other template parameter scopes as parents.
+ Scope *TemplateParamParent;
+
+ /// DeclsInScope - This keeps track of all declarations in this scope. When
+ /// the declaration is added to the scope, it is set as the current
+ /// declaration for the identifier in the IdentifierTable. When the scope is
+ /// popped, these declarations are removed from the IdentifierTable's notion
+ /// of current declaration. It is up to the current Action implementation to
+ /// implement these semantics.
+ typedef llvm::SmallPtrSet<Action::DeclPtrTy, 32> DeclSetTy;
+ DeclSetTy DeclsInScope;
+
+ /// Entity - The entity with which this scope is associated. For
+ /// example, the entity of a class scope is the class itself, the
+ /// entity of a function scope is a function, etc. This field is
+ /// maintained by the Action implementation.
+ void *Entity;
+
+ typedef llvm::SmallVector<Action::DeclPtrTy, 2> UsingDirectivesTy;
+ UsingDirectivesTy UsingDirectives;
+
+public:
+ Scope(Scope *Parent, unsigned ScopeFlags) {
+ Init(Parent, ScopeFlags);
+ }
+
+ /// getFlags - Return the flags for this scope.
+ ///
+ unsigned getFlags() const { return Flags; }
+
+ /// isBlockScope - Return true if this scope does not correspond to a
+ /// closure.
+ bool isBlockScope() const { return Flags & BlockScope; }
+
+ /// getParent - Return the scope that this is nested in.
+ ///
+ const Scope *getParent() const { return AnyParent; }
+ Scope *getParent() { return AnyParent; }
+
+ /// getFnParent - Return the closest scope that is a function body.
+ ///
+ const Scope *getFnParent() const { return FnParent; }
+ Scope *getFnParent() { return FnParent; }
+
+ /// getContinueParent - Return the closest scope that a continue statement
+ /// would be affected by. If the closest scope is a closure scope, we know
+ /// that there is no loop *inside* the closure.
+ Scope *getContinueParent() {
+ if (ContinueParent && !ContinueParent->isBlockScope())
+ return ContinueParent;
+ return 0;
+ }
+
+ const Scope *getContinueParent() const {
+ return const_cast<Scope*>(this)->getContinueParent();
+ }
+
+ /// getBreakParent - Return the closest scope that a break statement
+ /// would be affected by. If the closest scope is a block scope, we know
+ /// that there is no loop *inside* the block.
+ Scope *getBreakParent() {
+ if (BreakParent && !BreakParent->isBlockScope())
+ return BreakParent;
+ return 0;
+ }
+ const Scope *getBreakParent() const {
+ return const_cast<Scope*>(this)->getBreakParent();
+ }
+
+ Scope *getControlParent() { return ControlParent; }
+ const Scope *getControlParent() const { return ControlParent; }
+
+ Scope *getBlockParent() { return BlockParent; }
+ const Scope *getBlockParent() const { return BlockParent; }
+
+ Scope *getTemplateParamParent() { return TemplateParamParent; }
+ const Scope *getTemplateParamParent() const { return TemplateParamParent; }
+
+ typedef DeclSetTy::iterator decl_iterator;
+ decl_iterator decl_begin() const { return DeclsInScope.begin(); }
+ decl_iterator decl_end() const { return DeclsInScope.end(); }
+ bool decl_empty() const { return DeclsInScope.empty(); }
+
+ void AddDecl(Action::DeclPtrTy D) {
+ DeclsInScope.insert(D);
+ }
+
+ void RemoveDecl(Action::DeclPtrTy D) {
+ DeclsInScope.erase(D);
+ }
+
+ /// isDeclScope - Return true if this is the scope that the specified decl is
+ /// declared in.
+ bool isDeclScope(Action::DeclPtrTy D) {
+ return DeclsInScope.count(D) != 0;
+ }
+
+ void* getEntity() const { return Entity; }
+ void setEntity(void *E) { Entity = E; }
+
+ /// isClassScope - Return true if this scope is a class/struct/union scope.
+ bool isClassScope() const {
+ return (getFlags() & Scope::ClassScope);
+ }
+
+ /// isInCXXInlineMethodScope - Return true if this scope is a C++ inline
+ /// method scope or is inside one.
+ bool isInCXXInlineMethodScope() const {
+ if (const Scope *FnS = getFnParent()) {
+ assert(FnS->getParent() && "TUScope not created?");
+ return FnS->getParent()->isClassScope();
+ }
+ return false;
+ }
+
+ /// isTemplateParamScope - Return true if this scope is a C++
+ /// template parameter scope.
+ bool isTemplateParamScope() const {
+ return getFlags() & Scope::TemplateParamScope;
+ }
+
+ /// isFunctionPrototypeScope - Return true if this scope is a
+ /// function prototype scope.
+ bool isFunctionPrototypeScope() const {
+ return getFlags() & Scope::FunctionPrototypeScope;
+ }
+
+ /// isAtCatchScope - Return true if this scope is @catch.
+ bool isAtCatchScope() const {
+ return getFlags() & Scope::AtCatchScope;
+ }
+
+ /// isWithinElse - Whether we are within the "else" of the
+ /// ControlParent (if any).
+ bool isWithinElse() const { return WithinElse; }
+
+ void setWithinElse(bool WE) { WithinElse = WE; }
+
+ typedef UsingDirectivesTy::iterator udir_iterator;
+ typedef UsingDirectivesTy::const_iterator const_udir_iterator;
+
+ void PushUsingDirective(Action::DeclPtrTy UDir) {
+ UsingDirectives.push_back(UDir);
+ }
+
+ udir_iterator using_directives_begin() {
+ return UsingDirectives.begin();
+ }
+
+ udir_iterator using_directives_end() {
+ return UsingDirectives.end();
+ }
+
+ const_udir_iterator using_directives_begin() const {
+ return UsingDirectives.begin();
+ }
+
+ const_udir_iterator using_directives_end() const {
+ return UsingDirectives.end();
+ }
+
+ /// Init - This is used by the parser to implement scope caching.
+ ///
+ void Init(Scope *Parent, unsigned ScopeFlags) {
+ AnyParent = Parent;
+ Depth = AnyParent ? AnyParent->Depth+1 : 0;
+ Flags = ScopeFlags;
+
+ if (AnyParent) {
+ FnParent = AnyParent->FnParent;
+ BreakParent = AnyParent->BreakParent;
+ ContinueParent = AnyParent->ContinueParent;
+ ControlParent = AnyParent->ControlParent;
+ BlockParent = AnyParent->BlockParent;
+ TemplateParamParent = AnyParent->TemplateParamParent;
+ WithinElse = AnyParent->WithinElse;
+
+ } else {
+ FnParent = BreakParent = ContinueParent = BlockParent = 0;
+ ControlParent = 0;
+ TemplateParamParent = 0;
+ WithinElse = false;
+ }
+
+ // If this scope is a function or contains breaks/continues, remember it.
+ if (Flags & FnScope) FnParent = this;
+ if (Flags & BreakScope) BreakParent = this;
+ if (Flags & ContinueScope) ContinueParent = this;
+ if (Flags & ControlScope) ControlParent = this;
+ if (Flags & BlockScope) BlockParent = this;
+ if (Flags & TemplateParamScope) TemplateParamParent = this;
+ DeclsInScope.clear();
+ UsingDirectives.clear();
+ Entity = 0;
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Rewrite/DeltaTree.h b/include/clang/Rewrite/DeltaTree.h
new file mode 100644
index 000000000000..7bf9305e2877
--- /dev/null
+++ b/include/clang/Rewrite/DeltaTree.h
@@ -0,0 +1,48 @@
+//===--- DeltaTree.h - B-Tree for Rewrite Delta tracking --------*- 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 DeltaTree class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_REWRITE_DELTATREE_H
+#define CLANG_REWRITE_DELTATREE_H
+
+namespace clang {
+
+ /// DeltaTree - a multiway search tree (BTree) structure with some fancy
+ /// features. B-Trees are are generally more memory and cache efficient than
+ /// binary trees, because they store multiple keys/values in each node. This
+ /// implements a key/value mapping from index to delta, and allows fast lookup
+ /// on index. However, an added (important) bonus is that it can also
+ /// efficiently tell us the full accumulated delta for a specific file offset
+ /// as well, without traversing the whole tree.
+ class DeltaTree {
+ void *Root; // "DeltaTreeNode *"
+ void operator=(const DeltaTree&); // DO NOT IMPLEMENT
+ public:
+ DeltaTree();
+
+ // Note: Currently we only support copying when the RHS is empty.
+ DeltaTree(const DeltaTree &RHS);
+ ~DeltaTree();
+
+ /// getDeltaAt - Return the accumulated delta at the specified file offset.
+ /// This includes all insertions or delections that occurred *before* the
+ /// specified file index.
+ int getDeltaAt(unsigned FileIndex) const;
+
+ /// AddDelta - When a change is made that shifts around the text buffer,
+ /// this method is used to record that info. It inserts a delta of 'Delta'
+ /// into the current DeltaTree at offset FileIndex.
+ void AddDelta(unsigned FileIndex, int Delta);
+ };
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Rewrite/HTMLRewrite.h b/include/clang/Rewrite/HTMLRewrite.h
new file mode 100644
index 000000000000..f49d49e710c9
--- /dev/null
+++ b/include/clang/Rewrite/HTMLRewrite.h
@@ -0,0 +1,82 @@
+//==- HTMLRewrite.h - Translate source code into prettified HTML ---*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a set of functions used for translating source code
+// into beautified HTML.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_HTMLREWRITER_H
+#define LLVM_CLANG_HTMLREWRITER_H
+
+#include "clang/Basic/SourceLocation.h"
+#include <string>
+
+namespace clang {
+
+class Rewriter;
+class RewriteBuffer;
+class Preprocessor;
+class PreprocessorFactory;
+
+namespace html {
+
+ /// HighlightRange - Highlight a range in the source code with the specified
+ /// start/end tags. B/E must be in the same file. This ensures that
+ /// start/end tags are placed at the start/end of each line if the range is
+ /// multiline.
+ void HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E,
+ const char *StartTag, const char *EndTag);
+
+ /// HighlightRange - Highlight a range in the source code with the specified
+ /// start/end tags. The Start/end of the range must be in the same file.
+ /// This ensures that start/end tags are placed at the start/end of each line
+ /// if the range is multiline.
+ inline void HighlightRange(Rewriter &R, SourceRange Range,
+ const char *StartTag, const char *EndTag) {
+ HighlightRange(R, Range.getBegin(), Range.getEnd(), StartTag, EndTag);
+ }
+
+ /// HighlightRange - This is the same as the above method, but takes
+ /// decomposed file locations.
+ void HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E,
+ const char *BufferStart,
+ const char *StartTag, const char *EndTag);
+
+ /// EscapeText - HTMLize a specified file so that special characters are
+ /// are translated so that they are not interpreted as HTML tags.
+ void EscapeText(Rewriter& R, FileID FID,
+ bool EscapeSpaces = false, bool ReplaceTabs = false);
+
+ /// EscapeText - HTMLized the provided string so that special characters
+ /// in 's' are not interpreted as HTML tags. Unlike the version of
+ /// EscapeText that rewrites a file, this version by default replaces tabs
+ /// with spaces.
+ std::string EscapeText(const std::string& s,
+ bool EscapeSpaces = false, bool ReplaceTabs = false);
+
+ void AddLineNumbers(Rewriter& R, FileID FID);
+
+ void AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID,
+ const char *title = NULL);
+
+ /// SyntaxHighlight - Relex the specified FileID and annotate the HTML with
+ /// information about keywords, comments, etc.
+ void SyntaxHighlight(Rewriter &R, FileID FID, Preprocessor &PP);
+
+ /// HighlightMacros - This uses the macro table state from the end of the
+ /// file, to reexpand macros and insert (into the HTML) information about the
+ /// macro expansions. This won't be perfectly perfect, but it will be
+ /// reasonably close.
+ void HighlightMacros(Rewriter &R, FileID FID, Preprocessor &PP);
+ void HighlightMacros(Rewriter &R, FileID FID, PreprocessorFactory &PPF);
+} // end html namespace
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Rewrite/RewriteRope.h b/include/clang/Rewrite/RewriteRope.h
new file mode 100644
index 000000000000..7faa451290e4
--- /dev/null
+++ b/include/clang/Rewrite/RewriteRope.h
@@ -0,0 +1,230 @@
+//===--- RewriteRope.h - Rope specialized for rewriter ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the RewriteRope class, which is a powerful string class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_REWRITEROPE_H
+#define LLVM_CLANG_REWRITEROPE_H
+
+#include "llvm/ADT/iterator.h"
+#include <cstring>
+#include <cassert>
+
+namespace clang {
+ //===--------------------------------------------------------------------===//
+ // RopeRefCountString Class
+ //===--------------------------------------------------------------------===//
+
+ /// RopeRefCountString - This struct is allocated with 'new char[]' from the
+ /// heap, and represents a reference counted chunk of string data. When its
+ /// ref count drops to zero, it is delete[]'d. This is primarily managed
+ /// through the RopePiece class below.
+ struct RopeRefCountString {
+ unsigned RefCount;
+ char Data[1]; // Variable sized.
+
+ void addRef() {
+ if (this) ++RefCount;
+ }
+
+ void dropRef() {
+ if (this && --RefCount == 0)
+ delete [] (char*)this;
+ }
+ };
+
+ //===--------------------------------------------------------------------===//
+ // RopePiece Class
+ //===--------------------------------------------------------------------===//
+
+ /// RopePiece - This class represents a view into a RopeRefCountString object.
+ /// This allows references to string data to be efficiently chopped up and
+ /// moved around without having to push around the string data itself.
+ ///
+ /// For example, we could have a 1M RopePiece and want to insert something
+ /// into the middle of it. To do this, we split it into two RopePiece objects
+ /// that both refer to the same underlying RopeRefCountString (just with
+ /// different offsets) which is a nice constant time operation.
+ struct RopePiece {
+ RopeRefCountString *StrData;
+ unsigned StartOffs;
+ unsigned EndOffs;
+
+ RopePiece() : StrData(0), StartOffs(0), EndOffs(0) {}
+
+ RopePiece(RopeRefCountString *Str, unsigned Start, unsigned End)
+ : StrData(Str), StartOffs(Start), EndOffs(End) {
+ StrData->addRef();
+ }
+ RopePiece(const RopePiece &RP)
+ : StrData(RP.StrData), StartOffs(RP.StartOffs), EndOffs(RP.EndOffs) {
+ StrData->addRef();
+ }
+
+ ~RopePiece() {
+ StrData->dropRef();
+ }
+
+ void operator=(const RopePiece &RHS) {
+ if (StrData != RHS.StrData) {
+ StrData->dropRef();
+ StrData = RHS.StrData;
+ StrData->addRef();
+ }
+ StartOffs = RHS.StartOffs;
+ EndOffs = RHS.EndOffs;
+ }
+
+ const char &operator[](unsigned Offset) const {
+ return StrData->Data[Offset+StartOffs];
+ }
+ char &operator[](unsigned Offset) {
+ return StrData->Data[Offset+StartOffs];
+ }
+
+ unsigned size() const { return EndOffs-StartOffs; }
+ };
+
+ //===--------------------------------------------------------------------===//
+ // RopePieceBTreeIterator Class
+ //===--------------------------------------------------------------------===//
+
+ /// RopePieceBTreeIterator - This class provides read-only forward iteration
+ /// over bytes that are in a RopePieceBTree. This first iterates over bytes
+ /// in a RopePiece, then iterates over RopePiece's in a RopePieceBTreeLeaf,
+ /// then iterates over RopePieceBTreeLeaf's in a RopePieceBTree.
+ class RopePieceBTreeIterator :
+ public forward_iterator<const char, ptrdiff_t> {
+ /// CurNode - The current B+Tree node that we are inspecting.
+ const void /*RopePieceBTreeLeaf*/ *CurNode;
+ /// CurPiece - The current RopePiece in the B+Tree node that we're
+ /// inspecting.
+ const RopePiece *CurPiece;
+ /// CurChar - The current byte in the RopePiece we are pointing to.
+ unsigned CurChar;
+ public:
+ // begin iterator.
+ RopePieceBTreeIterator(const void /*RopePieceBTreeNode*/ *N);
+ // end iterator
+ RopePieceBTreeIterator() : CurNode(0), CurPiece(0), CurChar(0) {}
+
+ char operator*() const {
+ return (*CurPiece)[CurChar];
+ }
+
+ bool operator==(const RopePieceBTreeIterator &RHS) const {
+ return CurPiece == RHS.CurPiece && CurChar == RHS.CurChar;
+ }
+ bool operator!=(const RopePieceBTreeIterator &RHS) const {
+ return !operator==(RHS);
+ }
+
+ RopePieceBTreeIterator& operator++() { // Preincrement
+ if (CurChar+1 < CurPiece->size())
+ ++CurChar;
+ else
+ MoveToNextPiece();
+ return *this;
+ }
+ inline RopePieceBTreeIterator operator++(int) { // Postincrement
+ RopePieceBTreeIterator tmp = *this; ++*this; return tmp;
+ }
+ private:
+ void MoveToNextPiece();
+ };
+
+ //===--------------------------------------------------------------------===//
+ // RopePieceBTree Class
+ //===--------------------------------------------------------------------===//
+
+ class RopePieceBTree {
+ void /*RopePieceBTreeNode*/ *Root;
+ void operator=(const RopePieceBTree &); // DO NOT IMPLEMENT
+ public:
+ RopePieceBTree();
+ RopePieceBTree(const RopePieceBTree &RHS);
+ ~RopePieceBTree();
+
+ typedef RopePieceBTreeIterator iterator;
+ iterator begin() const { return iterator(Root); }
+ iterator end() const { return iterator(); }
+ unsigned size() const;
+ unsigned empty() const { return size() == 0; }
+
+ void clear();
+
+ void insert(unsigned Offset, const RopePiece &R);
+
+ void erase(unsigned Offset, unsigned NumBytes);
+ };
+
+ //===--------------------------------------------------------------------===//
+ // RewriteRope Class
+ //===--------------------------------------------------------------------===//
+
+/// RewriteRope - A powerful string class. This class supports extremely
+/// efficient insertions and deletions into the middle of it, even for
+/// ridiculously long strings.
+class RewriteRope {
+ RopePieceBTree Chunks;
+
+ /// We allocate space for string data out of a buffer of size AllocChunkSize.
+ /// This keeps track of how much space is left.
+ RopeRefCountString *AllocBuffer;
+ unsigned AllocOffs;
+ enum { AllocChunkSize = 4080 };
+
+public:
+ RewriteRope() : AllocBuffer(0), AllocOffs(AllocChunkSize) {}
+ RewriteRope(const RewriteRope &RHS)
+ : Chunks(RHS.Chunks), AllocBuffer(0), AllocOffs(AllocChunkSize) {
+ }
+
+ ~RewriteRope() {
+ // If we had an allocation buffer, drop our reference to it.
+ AllocBuffer->dropRef();
+ }
+
+ typedef RopePieceBTree::iterator iterator;
+ typedef RopePieceBTree::iterator const_iterator;
+ iterator begin() const { return Chunks.begin(); }
+ iterator end() const { return Chunks.end(); }
+ unsigned size() const { return Chunks.size(); }
+
+ void clear() {
+ Chunks.clear();
+ }
+
+ void assign(const char *Start, const char *End) {
+ clear();
+ if (Start != End)
+ Chunks.insert(0, MakeRopeString(Start, End));
+ }
+
+ void insert(unsigned Offset, const char *Start, const char *End) {
+ assert(Offset <= size() && "Invalid position to insert!");
+ if (Start == End) return;
+ Chunks.insert(Offset, MakeRopeString(Start, End));
+ }
+
+ void erase(unsigned Offset, unsigned NumBytes) {
+ assert(Offset+NumBytes <= size() && "Invalid region to erase!");
+ if (NumBytes == 0) return;
+ Chunks.erase(Offset, NumBytes);
+ }
+
+private:
+ RopePiece MakeRopeString(const char *Start, const char *End);
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Rewrite/Rewriter.h b/include/clang/Rewrite/Rewriter.h
new file mode 100644
index 000000000000..c3ee0175c36f
--- /dev/null
+++ b/include/clang/Rewrite/Rewriter.h
@@ -0,0 +1,238 @@
+//===--- Rewriter.h - Code rewriting 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 Rewriter class, which is used for code
+// transformations.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_REWRITER_H
+#define LLVM_CLANG_REWRITER_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Rewrite/RewriteRope.h"
+#include <map>
+#include <vector>
+#include <cstring>
+#include <string>
+#include "clang/Rewrite/DeltaTree.h"
+
+namespace clang {
+ class SourceManager;
+ class LangOptions;
+ class Rewriter;
+ class Stmt;
+
+/// RewriteBuffer - As code is rewritten, SourceBuffer's from the original
+/// input with modifications get a new RewriteBuffer associated with them. The
+/// RewriteBuffer captures the modified text itself as well as information used
+/// to map between SourceLocation's in the original input and offsets in the
+/// RewriteBuffer. For example, if text is inserted into the buffer, any
+/// locations after the insertion point have to be mapped.
+class RewriteBuffer {
+ friend class Rewriter;
+ /// Deltas - Keep track of all the deltas in the source code due to insertions
+ /// and deletions.
+ DeltaTree Deltas;
+
+ /// Buffer - This is the actual buffer itself. Note that using a vector or
+ /// string is a horribly inefficient way to do this, we should use a rope
+ /// instead.
+ typedef RewriteRope BufferTy;
+ BufferTy Buffer;
+public:
+ typedef BufferTy::const_iterator iterator;
+ iterator begin() const { return Buffer.begin(); }
+ iterator end() const { return Buffer.end(); }
+ unsigned size() const { return Buffer.size(); }
+
+ /// RemoveText - Remove the specified text.
+ void RemoveText(unsigned OrigOffset, unsigned Size);
+
+ /// InsertText - 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 InsertText(unsigned OrigOffset, const char *StrData, unsigned StrLen,
+ bool InsertAfter = true);
+
+
+ /// InsertTextBefore - Insert some text before the specified point,
+ /// where the offset in the buffer is specified relative to the original
+ /// SourceBuffer.
+ ///
+ void InsertTextBefore(unsigned OrigOffset, const char *StrData,
+ unsigned StrLen) {
+ InsertText(OrigOffset, StrData, StrLen, false);
+ }
+
+ /// InsertText - 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. This is method is the
+ /// same as InsertText with "InsertAfter == false".
+ void InsertTextAfter(unsigned OrigOffset, const char *StrData,
+ unsigned StrLen) {
+ InsertText(OrigOffset, StrData, StrLen);
+ }
+
+ /// ReplaceText - This method replaces a range of characters in the input
+ /// buffer with a new string. This is effectively a combined "remove/insert"
+ /// operation.
+ void ReplaceText(unsigned OrigOffset, unsigned OrigLength,
+ const char *NewStr, unsigned NewLength);
+
+private: // Methods only usable by Rewriter.
+
+ /// Initialize - Start this rewrite buffer out with a copy of the unmodified
+ /// input buffer.
+ void Initialize(const char *BufStart, const char *BufEnd) {
+ Buffer.assign(BufStart, BufEnd);
+ }
+
+ /// getMappedOffset - Given an offset into the original SourceBuffer that this
+ /// RewriteBuffer is based on, map it into the offset space of the
+ /// RewriteBuffer. If AfterInserts is true and if the OrigOffset indicates a
+ /// position where text is inserted, the location returned will be after any
+ /// inserted text at the position.
+ unsigned getMappedOffset(unsigned OrigOffset,
+ bool AfterInserts = false) const{
+ return Deltas.getDeltaAt(2*OrigOffset+AfterInserts)+OrigOffset;
+ }
+
+ /// AddInsertDelta - When an insertion is made at a position, this
+ /// method is used to record that information.
+ void AddInsertDelta(unsigned OrigOffset, int Change) {
+ return Deltas.AddDelta(2*OrigOffset, Change);
+ }
+
+ /// AddReplaceDelta - When a replacement/deletion is made at a position, this
+ /// method is used to record that information.
+ void AddReplaceDelta(unsigned OrigOffset, int Change) {
+ return Deltas.AddDelta(2*OrigOffset+1, Change);
+ }
+};
+
+
+/// Rewriter - This is the main interface to the rewrite buffers. Its primary
+/// job is to dispatch high-level requests to the low-level RewriteBuffers that
+/// are involved.
+class Rewriter {
+ SourceManager *SourceMgr;
+ const LangOptions *LangOpts;
+ std::map<FileID, RewriteBuffer> RewriteBuffers;
+public:
+ explicit Rewriter(SourceManager &SM, const LangOptions &LO)
+ : SourceMgr(&SM), LangOpts(&LO) {}
+ explicit Rewriter() : SourceMgr(0), LangOpts(0) {}
+
+ void setSourceMgr(SourceManager &SM, const LangOptions &LO) {
+ SourceMgr = &SM;
+ LangOpts = &LO;
+ }
+ SourceManager &getSourceMgr() { return *SourceMgr; }
+ const LangOptions &getLangOpts() { return *LangOpts; }
+
+ /// isRewritable - Return true if this location is a raw file location, which
+ /// is rewritable. Locations from macros, etc are not rewritable.
+ static bool isRewritable(SourceLocation Loc) {
+ return Loc.isFileID();
+ }
+
+ /// getRangeSize - Return the size in bytes of the specified range if they
+ /// are in the same file. If not, this returns -1.
+ int getRangeSize(SourceRange Range) const;
+
+ /// getRewritenText - Return the rewritten form of the text in the specified
+ /// range. If the start or end of the range was unrewritable or if they are
+ /// in different buffers, this returns an empty string.
+ ///
+ /// Note that this method is not particularly efficient.
+ ///
+ std::string getRewritenText(SourceRange Range) const;
+
+ /// 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.
+ bool InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen,
+ bool InsertAfter = true);
+
+ /// InsertTextAfter - 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 after any other text that has been previously inserted
+ /// at the some point (the default behavior for InsertText).
+ bool InsertTextAfter(SourceLocation Loc, const char *StrData,
+ unsigned StrLen) {
+ return InsertText(Loc, StrData, StrLen);
+ }
+
+ /// 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, const char *StrData,
+ unsigned StrLen) {
+ return InsertText(Loc, StrData, StrLen, false);
+ }
+
+
+ bool InsertCStrBefore(SourceLocation Loc, const char* Str) {
+ return InsertTextBefore(Loc, Str, strlen(Str));
+ }
+
+
+ bool InsertCStrAfter(SourceLocation Loc, const char* Str) {
+ return InsertTextAfter(Loc, Str, strlen(Str));
+ }
+
+ bool InsertStrBefore(SourceLocation Loc, const std::string& S) {
+ return S.empty() ? false : InsertTextBefore(Loc, &S[0], S.size());
+ }
+
+ bool InsertStrAfter(SourceLocation Loc, const std::string& S) {
+ return S.empty() ? false : InsertTextAfter(Loc, &S[0], S.size());
+ }
+
+
+ /// RemoveText - Remove the specified text region.
+ bool RemoveText(SourceLocation Start, unsigned Length);
+
+ /// 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(SourceLocation Start, unsigned OrigLength,
+ const char *NewStr, unsigned NewLength);
+
+ /// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty
+ /// printer to generate the replacement code. This returns true if the input
+ /// could not be rewritten, or false if successful.
+ bool ReplaceStmt(Stmt *From, Stmt *To);
+
+ /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID.
+ /// If no modification has been made to it, return null.
+ const RewriteBuffer *getRewriteBufferFor(FileID FID) const {
+ std::map<FileID, RewriteBuffer>::const_iterator I =
+ RewriteBuffers.find(FID);
+ return I == RewriteBuffers.end() ? 0 : &I->second;
+ }
+
+ /// getEditBuffer - This is like getRewriteBufferFor, but always returns a
+ /// buffer, and allows you to write on it directly. This is useful if you
+ /// want efficient low-level access to apis for scribbling on one specific
+ /// FileID's buffer.
+ RewriteBuffer &getEditBuffer(FileID FID);
+
+private:
+ unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Rewrite/TokenRewriter.h b/include/clang/Rewrite/TokenRewriter.h
new file mode 100644
index 000000000000..c8fd0f532c25
--- /dev/null
+++ b/include/clang/Rewrite/TokenRewriter.h
@@ -0,0 +1,79 @@
+//===--- TokenRewriter.h - Token-based Rewriter -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the TokenRewriter class, which is used for code
+// transformations.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOKENREWRITER_H
+#define LLVM_CLANG_TOKENREWRITER_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/OwningPtr.h"
+#include <list>
+#include <map>
+
+namespace clang {
+ class Token;
+ class LangOptions;
+ class ScratchBuffer;
+
+ class TokenRewriter {
+ /// TokenList - This is the list of raw tokens that make up this file. Each
+ /// of these tokens has a unique SourceLocation, which is a FileID.
+ std::list<Token> TokenList;
+
+ /// TokenRefTy - This is the type used to refer to a token in the TokenList.
+ typedef std::list<Token>::iterator TokenRefTy;
+
+ /// TokenAtLoc - This map indicates which token exists at a specific
+ /// SourceLocation. Since each token has a unique SourceLocation, this is a
+ /// one to one map. The token can return its own location directly, to map
+ /// backwards.
+ std::map<SourceLocation, TokenRefTy> TokenAtLoc;
+
+ /// ScratchBuf - This is the buffer that we create scratch tokens from.
+ ///
+ llvm::OwningPtr<ScratchBuffer> ScratchBuf;
+
+ TokenRewriter(const TokenRewriter&); // DO NOT IMPLEMENT
+ void operator=(const TokenRewriter&); // DO NOT IMPLEMENT.
+ public:
+ /// TokenRewriter - This creates a TokenRewriter for the file with the
+ /// specified FileID.
+ TokenRewriter(FileID FID, SourceManager &SM, const LangOptions &LO);
+ ~TokenRewriter();
+
+ typedef std::list<Token>::const_iterator token_iterator;
+ token_iterator token_begin() const { return TokenList.begin(); }
+ token_iterator token_end() const { return TokenList.end(); }
+
+
+ token_iterator AddTokenBefore(token_iterator I, const char *Val);
+ token_iterator AddTokenAfter(token_iterator I, const char *Val) {
+ assert(I != token_end() && "Cannot insert after token_end()!");
+ return AddTokenBefore(++I, Val);
+ }
+
+ private:
+ /// RemapIterator - Convert from token_iterator (a const iterator) to
+ /// TokenRefTy (a non-const iterator).
+ TokenRefTy RemapIterator(token_iterator I);
+
+ /// AddToken - Add the specified token into the Rewriter before the other
+ /// position.
+ TokenRefTy AddToken(const Token &T, TokenRefTy Where);
+ };
+
+
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h
new file mode 100644
index 000000000000..0f0d375e9c30
--- /dev/null
+++ b/include/clang/Sema/ExternalSemaSource.h
@@ -0,0 +1,56 @@
+//===--- ExternalSemaSource.h - External Sema Interface ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ExternalSemaSource interface.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_SEMA_EXTERNAL_SEMA_SOURCE_H
+#define LLVM_CLANG_SEMA_EXTERNAL_SEMA_SOURCE_H
+
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExternalASTSource.h"
+
+namespace clang {
+
+class Sema;
+
+/// \brief An abstract interface that should be implemented by
+/// external AST sources that also provide information for semantic
+/// analysis.
+class ExternalSemaSource : public ExternalASTSource {
+public:
+ ExternalSemaSource() {
+ ExternalASTSource::SemaSource = true;
+ }
+
+ /// \brief Initialize the semantic source with the Sema instance
+ /// being used to perform semantic analysis on the abstract syntax
+ /// tree.
+ virtual void InitializeSema(Sema &S) {}
+
+ /// \brief Load the contents of the global method pool for a given
+ /// selector.
+ ///
+ /// \returns a pair of Objective-C methods lists containing the
+ /// instance and factory methods, respectively, with this selector.
+ virtual std::pair<ObjCMethodList, ObjCMethodList>
+ ReadMethodPool(Selector Sel) {
+ return std::pair<ObjCMethodList, ObjCMethodList>();
+ }
+
+ // isa/cast/dyn_cast support
+ static bool classof(const ExternalASTSource *Source) {
+ return Source->SemaSource;
+ }
+ static bool classof(const ExternalSemaSource *) { return true; }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Sema/ParseAST.h b/include/clang/Sema/ParseAST.h
new file mode 100644
index 000000000000..bdce5e95effb
--- /dev/null
+++ b/include/clang/Sema/ParseAST.h
@@ -0,0 +1,37 @@
+//===--- ParseAST.h - Define the ParseAST method ----------------*- 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 clang::ParseAST method.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_PARSEAST_H
+#define LLVM_CLANG_SEMA_PARSEAST_H
+
+namespace clang {
+ class Preprocessor;
+ class ASTConsumer;
+ class ASTContext;
+
+ /// \brief Parse the entire file specified, notifying the ASTConsumer as
+ /// the file is parsed.
+ ///
+ /// 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.
+ void ParseAST(Preprocessor &pp, ASTConsumer *C,
+ ASTContext &Ctx, bool PrintStats = false,
+ bool CompleteTranslationUnit = true);
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Sema/SemaConsumer.h b/include/clang/Sema/SemaConsumer.h
new file mode 100644
index 000000000000..e821947035c4
--- /dev/null
+++ b/include/clang/Sema/SemaConsumer.h
@@ -0,0 +1,45 @@
+//===--- SemaConsumer.h - Abstract interface for AST semantics --*- 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 SemaConsumer class, a subclass of
+// ASTConsumer that is used by AST clients that also require
+// additional semantic analysis.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_SEMA_SEMACONSUMER_H
+#define LLVM_CLANG_SEMA_SEMACONSUMER_H
+
+#include "clang/AST/ASTConsumer.h"
+
+namespace clang {
+ class Sema;
+
+ /// \brief An abstract interface that should be implemented by
+ /// clients that read ASTs and then require further semantic
+ /// analysis of the entities in those ASTs.
+ class SemaConsumer : public ASTConsumer {
+ public:
+ SemaConsumer() {
+ ASTConsumer::SemaConsumer = true;
+ }
+
+ /// \brief Initialize the semantic consumer with the Sema instance
+ /// being used to perform semantic analysis on the abstract syntax
+ /// tree.
+ virtual void InitializeSema(Sema &S) {}
+
+ // isa/cast/dyn_cast support
+ static bool classof(const ASTConsumer *Consumer) {
+ return Consumer->SemaConsumer;
+ }
+ static bool classof(const SemaConsumer *) { return true; }
+ };
+}
+
+#endif
diff --git a/include/clang/Sema/SemaDiagnostic.h b/include/clang/Sema/SemaDiagnostic.h
new file mode 100644
index 000000000000..e215ed48fbe5
--- /dev/null
+++ b/include/clang/Sema/SemaDiagnostic.h
@@ -0,0 +1,27 @@
+//===--- DiagnosticSema.h - Diagnostics for libsema -------------*- 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_DIAGNOSTICSEMA_H
+#define LLVM_CLANG_DIAGNOSTICSEMA_H
+
+#include "clang/Basic/Diagnostic.h"
+
+namespace clang {
+ namespace diag {
+ enum {
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM,
+#define SEMASTART
+#include "clang/Basic/DiagnosticSemaKinds.inc"
+#undef DIAG
+ NUM_BUILTIN_SEMA_DIAGNOSTICS
+ };
+ } // end namespace diag
+} // end namespace clang
+
+#endif
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
new file mode 100644
index 000000000000..4df7671c5a95
--- /dev/null
+++ b/lib/AST/APValue.cpp
@@ -0,0 +1,108 @@
+//===--- APValue.cpp - Union class for APFloat/APSInt/Complex -------------===//
+//
+// 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 APValue class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/APValue.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+
+const APValue &APValue::operator=(const APValue &RHS) {
+ if (Kind != RHS.Kind) {
+ MakeUninit();
+ if (RHS.isInt())
+ MakeInt();
+ else if (RHS.isFloat())
+ MakeFloat();
+ else if (RHS.isVector())
+ MakeVector();
+ else if (RHS.isComplexInt())
+ MakeComplexInt();
+ else if (RHS.isComplexFloat())
+ MakeComplexFloat();
+ else if (RHS.isLValue())
+ MakeLValue();
+ }
+ if (isInt())
+ setInt(RHS.getInt());
+ else if (isFloat())
+ setFloat(RHS.getFloat());
+ else if (isVector())
+ setVector(((Vec*)(void*)RHS.Data)->Elts, RHS.getVectorLength());
+ else if (isComplexInt())
+ setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag());
+ else if (isComplexFloat())
+ setComplexFloat(RHS.getComplexFloatReal(), RHS.getComplexFloatImag());
+ else if (isLValue())
+ setLValue(RHS.getLValueBase(), RHS.getLValueOffset());
+ return *this;
+}
+
+void APValue::MakeUninit() {
+ if (Kind == Int)
+ ((APSInt*)(void*)Data)->~APSInt();
+ else if (Kind == Float)
+ ((APFloat*)(void*)Data)->~APFloat();
+ else if (Kind == Vector)
+ ((Vec*)(void*)Data)->~Vec();
+ else if (Kind == ComplexInt)
+ ((ComplexAPSInt*)(void*)Data)->~ComplexAPSInt();
+ else if (Kind == ComplexFloat)
+ ((ComplexAPFloat*)(void*)Data)->~ComplexAPFloat();
+ else if (Kind == LValue) {
+ ((LV*)(void*)Data)->~LV();
+ }
+ Kind = Uninitialized;
+}
+
+void APValue::dump() const {
+ print(llvm::errs());
+ llvm::errs() << '\n';
+}
+
+static double GetApproxValue(const llvm::APFloat &F) {
+ llvm::APFloat V = F;
+ bool ignored;
+ V.convert(llvm::APFloat::IEEEdouble, llvm::APFloat::rmNearestTiesToEven,
+ &ignored);
+ return V.convertToDouble();
+}
+
+void APValue::print(llvm::raw_ostream &OS) const {
+ switch (getKind()) {
+ default: assert(0 && "Unknown APValue kind!");
+ case Uninitialized:
+ OS << "Uninitialized";
+ return;
+ case Int:
+ OS << "Int: " << getInt();
+ return;
+ case Float:
+ OS << "Float: " << GetApproxValue(getFloat());
+ return;
+ case Vector:
+ OS << "Vector: " << getVectorElt(0);
+ for (unsigned i = 1; i != getVectorLength(); ++i)
+ OS << ", " << getVectorElt(i);
+ return;
+ case ComplexInt:
+ OS << "ComplexInt: " << getComplexIntReal() << ", " << getComplexIntImag();
+ return;
+ case ComplexFloat:
+ OS << "ComplexFloat: " << GetApproxValue(getComplexFloatReal())
+ << ", " << GetApproxValue(getComplexFloatImag());
+ case LValue:
+ OS << "LValue: <todo>";
+ return;
+ }
+}
+
diff --git a/lib/AST/ASTConsumer.cpp b/lib/AST/ASTConsumer.cpp
new file mode 100644
index 000000000000..f37cbdea5480
--- /dev/null
+++ b/lib/AST/ASTConsumer.cpp
@@ -0,0 +1,19 @@
+//===--- ASTConsumer.cpp - Abstract interface for reading ASTs --*- 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 ASTConsumer class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclGroup.h"
+using namespace clang;
+
+void ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) {}
+
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
new file mode 100644
index 000000000000..29bca29f230c
--- /dev/null
+++ b/lib/AST/ASTContext.cpp
@@ -0,0 +1,3332 @@
+//===--- ASTContext.cpp - Context to hold long-lived AST nodes ------------===//
+//
+// 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 ASTContext interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+using namespace clang;
+
+enum FloatingRank {
+ FloatRank, DoubleRank, LongDoubleRank
+};
+
+ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
+ TargetInfo &t,
+ IdentifierTable &idents, SelectorTable &sels,
+ bool FreeMem, unsigned size_reserve,
+ bool InitializeBuiltins) :
+ GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0),
+ ObjCFastEnumerationStateTypeDecl(0), SourceMgr(SM), LangOpts(LOpts),
+ FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels),
+ ExternalSource(0) {
+ if (size_reserve > 0) Types.reserve(size_reserve);
+ InitBuiltinTypes();
+ TUDecl = TranslationUnitDecl::Create(*this);
+ BuiltinInfo.InitializeTargetBuiltins(Target);
+ if (InitializeBuiltins)
+ this->InitializeBuiltins(idents);
+ PrintingPolicy.CPlusPlus = LangOpts.CPlusPlus;
+}
+
+ASTContext::~ASTContext() {
+ // Deallocate all the types.
+ while (!Types.empty()) {
+ Types.back()->Destroy(*this);
+ Types.pop_back();
+ }
+
+ {
+ llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*>::iterator
+ I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end();
+ while (I != E) {
+ ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second);
+ delete R;
+ }
+ }
+
+ {
+ llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*>::iterator
+ I = ObjCLayouts.begin(), E = ObjCLayouts.end();
+ while (I != E) {
+ ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second);
+ delete R;
+ }
+ }
+
+ // Destroy nested-name-specifiers.
+ for (llvm::FoldingSet<NestedNameSpecifier>::iterator
+ NNS = NestedNameSpecifiers.begin(),
+ NNSEnd = NestedNameSpecifiers.end();
+ NNS != NNSEnd;
+ /* Increment in loop */)
+ (*NNS++).Destroy(*this);
+
+ if (GlobalNestedNameSpecifier)
+ GlobalNestedNameSpecifier->Destroy(*this);
+
+ TUDecl->Destroy(*this);
+}
+
+void ASTContext::InitializeBuiltins(IdentifierTable &idents) {
+ BuiltinInfo.InitializeBuiltins(idents, LangOpts.NoBuiltin);
+}
+
+void
+ASTContext::setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source) {
+ ExternalSource.reset(Source.take());
+}
+
+void ASTContext::PrintStats() const {
+ fprintf(stderr, "*** AST Context Stats:\n");
+ fprintf(stderr, " %d types total.\n", (int)Types.size());
+
+ unsigned counts[] = {
+#define TYPE(Name, Parent) 0,
+#define ABSTRACT_TYPE(Name, Parent)
+#include "clang/AST/TypeNodes.def"
+ 0 // Extra
+ };
+
+ for (unsigned i = 0, e = Types.size(); i != e; ++i) {
+ Type *T = Types[i];
+ counts[(unsigned)T->getTypeClass()]++;
+ }
+
+ unsigned Idx = 0;
+ unsigned TotalBytes = 0;
+#define TYPE(Name, Parent) \
+ if (counts[Idx]) \
+ fprintf(stderr, " %d %s types\n", (int)counts[Idx], #Name); \
+ TotalBytes += counts[Idx] * sizeof(Name##Type); \
+ ++Idx;
+#define ABSTRACT_TYPE(Name, Parent)
+#include "clang/AST/TypeNodes.def"
+
+ fprintf(stderr, "Total bytes = %d\n", int(TotalBytes));
+
+ if (ExternalSource.get()) {
+ fprintf(stderr, "\n");
+ ExternalSource->PrintStats();
+ }
+}
+
+
+void ASTContext::InitBuiltinType(QualType &R, BuiltinType::Kind K) {
+ Types.push_back((R = QualType(new (*this,8) BuiltinType(K),0)).getTypePtr());
+}
+
+void ASTContext::InitBuiltinTypes() {
+ assert(VoidTy.isNull() && "Context reinitialized?");
+
+ // C99 6.2.5p19.
+ InitBuiltinType(VoidTy, BuiltinType::Void);
+
+ // C99 6.2.5p2.
+ InitBuiltinType(BoolTy, BuiltinType::Bool);
+ // C99 6.2.5p3.
+ if (Target.isCharSigned())
+ InitBuiltinType(CharTy, BuiltinType::Char_S);
+ else
+ InitBuiltinType(CharTy, BuiltinType::Char_U);
+ // C99 6.2.5p4.
+ InitBuiltinType(SignedCharTy, BuiltinType::SChar);
+ InitBuiltinType(ShortTy, BuiltinType::Short);
+ InitBuiltinType(IntTy, BuiltinType::Int);
+ InitBuiltinType(LongTy, BuiltinType::Long);
+ InitBuiltinType(LongLongTy, BuiltinType::LongLong);
+
+ // C99 6.2.5p6.
+ InitBuiltinType(UnsignedCharTy, BuiltinType::UChar);
+ InitBuiltinType(UnsignedShortTy, BuiltinType::UShort);
+ InitBuiltinType(UnsignedIntTy, BuiltinType::UInt);
+ InitBuiltinType(UnsignedLongTy, BuiltinType::ULong);
+ InitBuiltinType(UnsignedLongLongTy, BuiltinType::ULongLong);
+
+ // C99 6.2.5p10.
+ InitBuiltinType(FloatTy, BuiltinType::Float);
+ InitBuiltinType(DoubleTy, BuiltinType::Double);
+ InitBuiltinType(LongDoubleTy, BuiltinType::LongDouble);
+
+ // GNU extension, 128-bit integers.
+ InitBuiltinType(Int128Ty, BuiltinType::Int128);
+ InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128);
+
+ if (LangOpts.CPlusPlus) // C++ 3.9.1p5
+ InitBuiltinType(WCharTy, BuiltinType::WChar);
+ else // C99
+ WCharTy = getFromTargetType(Target.getWCharType());
+
+ // Placeholder type for functions.
+ InitBuiltinType(OverloadTy, BuiltinType::Overload);
+
+ // Placeholder type for type-dependent expressions whose type is
+ // completely unknown. No code should ever check a type against
+ // DependentTy and users should never see it; however, it is here to
+ // help diagnose failures to properly check for type-dependent
+ // expressions.
+ InitBuiltinType(DependentTy, BuiltinType::Dependent);
+
+ // C99 6.2.5p11.
+ FloatComplexTy = getComplexType(FloatTy);
+ DoubleComplexTy = getComplexType(DoubleTy);
+ LongDoubleComplexTy = getComplexType(LongDoubleTy);
+
+ BuiltinVaListType = QualType();
+ ObjCIdType = QualType();
+ IdStructType = 0;
+ ObjCClassType = QualType();
+ ClassStructType = 0;
+
+ ObjCConstantStringType = QualType();
+
+ // void * type
+ VoidPtrTy = getPointerType(VoidTy);
+
+ // nullptr type (C++0x 2.14.7)
+ InitBuiltinType(NullPtrTy, BuiltinType::NullPtr);
+}
+
+//===----------------------------------------------------------------------===//
+// Type Sizing and Analysis
+//===----------------------------------------------------------------------===//
+
+/// getFloatTypeSemantics - Return the APFloat 'semantics' for the specified
+/// scalar floating point type.
+const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
+ const BuiltinType *BT = T->getAsBuiltinType();
+ 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();
+ }
+}
+
+/// getDeclAlign - Return a conservative estimate of the alignment of the
+/// specified decl. Note that bitfields do not have a valid alignment, so
+/// this method will assert on them.
+unsigned ASTContext::getDeclAlignInBytes(const Decl *D) {
+ unsigned Align = Target.getCharWidth();
+
+ if (const AlignedAttr* AA = D->getAttr<AlignedAttr>())
+ Align = std::max(Align, AA->getAlignment());
+
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
+ QualType T = VD->getType();
+ if (const ReferenceType* RT = T->getAsReferenceType()) {
+ unsigned AS = RT->getPointeeType().getAddressSpace();
+ Align = Target.getPointerAlign(AS);
+ } else if (!T->isIncompleteType() && !T->isFunctionType()) {
+ // Incomplete or function types default to 1.
+ while (isa<VariableArrayType>(T) || isa<IncompleteArrayType>(T))
+ T = cast<ArrayType>(T)->getElementType();
+
+ Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr()));
+ }
+ }
+
+ return Align / Target.getCharWidth();
+}
+
+/// getTypeSize - Return the size of the specified type, in bits. This method
+/// does not work on incomplete types.
+std::pair<uint64_t, unsigned>
+ASTContext::getTypeInfo(const Type *T) {
+ uint64_t Width=0;
+ unsigned Align=8;
+ switch (T->getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ assert(false && "Should not see dependent types");
+ break;
+
+ case Type::FunctionNoProto:
+ case Type::FunctionProto:
+ // GCC extension: alignof(function) = 32 bits
+ Width = 0;
+ Align = 32;
+ break;
+
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ Width = 0;
+ Align = getTypeAlign(cast<ArrayType>(T)->getElementType());
+ break;
+
+ case Type::ConstantArray: {
+ const ConstantArrayType *CAT = cast<ConstantArrayType>(T);
+
+ std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(CAT->getElementType());
+ Width = EltInfo.first*CAT->getSize().getZExtValue();
+ Align = EltInfo.second;
+ break;
+ }
+ case Type::ExtVector:
+ case Type::Vector: {
+ std::pair<uint64_t, unsigned> EltInfo =
+ getTypeInfo(cast<VectorType>(T)->getElementType());
+ Width = EltInfo.first*cast<VectorType>(T)->getNumElements();
+ Align = Width;
+ // If the alignment is not a power of 2, round up to the next power of 2.
+ // This happens for non-power-of-2 length vectors.
+ // FIXME: this should probably be a target property.
+ Align = 1 << llvm::Log2_32_Ceil(Align);
+ break;
+ }
+
+ case Type::Builtin:
+ switch (cast<BuiltinType>(T)->getKind()) {
+ default: assert(0 && "Unknown builtin type!");
+ case BuiltinType::Void:
+ // GCC extension: alignof(void) = 8 bits.
+ Width = 0;
+ Align = 8;
+ break;
+
+ case BuiltinType::Bool:
+ 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();
+ break;
+ case BuiltinType::WChar:
+ Width = Target.getWCharWidth();
+ Align = Target.getWCharAlign();
+ break;
+ case BuiltinType::UShort:
+ case BuiltinType::Short:
+ Width = Target.getShortWidth();
+ Align = Target.getShortAlign();
+ break;
+ case BuiltinType::UInt:
+ case BuiltinType::Int:
+ Width = Target.getIntWidth();
+ Align = Target.getIntAlign();
+ break;
+ case BuiltinType::ULong:
+ case BuiltinType::Long:
+ Width = Target.getLongWidth();
+ Align = Target.getLongAlign();
+ break;
+ case BuiltinType::ULongLong:
+ case BuiltinType::LongLong:
+ 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::Float:
+ Width = Target.getFloatWidth();
+ Align = Target.getFloatAlign();
+ break;
+ case BuiltinType::Double:
+ Width = Target.getDoubleWidth();
+ Align = Target.getDoubleAlign();
+ break;
+ case BuiltinType::LongDouble:
+ 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*)
+ break;
+ }
+ break;
+ case Type::FixedWidthInt:
+ // FIXME: This isn't precisely correct; the width/alignment should depend
+ // on the available types for the target
+ Width = cast<FixedWidthIntType>(T)->getWidth();
+ Width = std::max(llvm::NextPowerOf2(Width - 1), (uint64_t)8);
+ Align = Width;
+ break;
+ case Type::ExtQual:
+ // FIXME: Pointers into different addr spaces could have different sizes and
+ // alignment requirements: getPointerInfo should take an AddrSpace.
+ return getTypeInfo(QualType(cast<ExtQualType>(T)->getBaseType(), 0));
+ case Type::ObjCQualifiedId:
+ case Type::ObjCQualifiedInterface:
+ Width = Target.getPointerWidth(0);
+ Align = Target.getPointerAlign(0);
+ break;
+ case Type::BlockPointer: {
+ unsigned AS = cast<BlockPointerType>(T)->getPointeeType().getAddressSpace();
+ Width = Target.getPointerWidth(AS);
+ Align = Target.getPointerAlign(AS);
+ break;
+ }
+ case Type::Pointer: {
+ unsigned AS = cast<PointerType>(T)->getPointeeType().getAddressSpace();
+ Width = Target.getPointerWidth(AS);
+ Align = Target.getPointerAlign(AS);
+ break;
+ }
+ case Type::LValueReference:
+ case Type::RValueReference:
+ // "When applied to a reference or a reference type, the result is the size
+ // of the referenced type." C++98 5.3.3p2: expr.sizeof.
+ // FIXME: This is wrong for struct layout: a reference in a struct has
+ // pointer size.
+ return getTypeInfo(cast<ReferenceType>(T)->getPointeeType());
+ case Type::MemberPointer: {
+ // FIXME: This is ABI dependent. We use the Itanium C++ ABI.
+ // http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers
+ // If we ever want to support other ABIs this needs to be abstracted.
+
+ QualType Pointee = cast<MemberPointerType>(T)->getPointeeType();
+ std::pair<uint64_t, unsigned> PtrDiffInfo =
+ getTypeInfo(getPointerDiffType());
+ Width = PtrDiffInfo.first;
+ if (Pointee->isFunctionType())
+ Width *= 2;
+ Align = PtrDiffInfo.second;
+ break;
+ }
+ case Type::Complex: {
+ // Complex types have the same alignment as their elements, but twice the
+ // size.
+ std::pair<uint64_t, unsigned> EltInfo =
+ getTypeInfo(cast<ComplexType>(T)->getElementType());
+ Width = EltInfo.first*2;
+ Align = EltInfo.second;
+ break;
+ }
+ case Type::ObjCInterface: {
+ const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T);
+ const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl());
+ Width = Layout.getSize();
+ Align = Layout.getAlignment();
+ break;
+ }
+ case Type::Record:
+ case Type::Enum: {
+ const TagType *TT = cast<TagType>(T);
+
+ if (TT->getDecl()->isInvalidDecl()) {
+ Width = 1;
+ Align = 1;
+ break;
+ }
+
+ if (const EnumType *ET = dyn_cast<EnumType>(TT))
+ return getTypeInfo(ET->getDecl()->getIntegerType());
+
+ const RecordType *RT = cast<RecordType>(TT);
+ const ASTRecordLayout &Layout = getASTRecordLayout(RT->getDecl());
+ Width = Layout.getSize();
+ Align = Layout.getAlignment();
+ break;
+ }
+
+ case Type::Typedef: {
+ const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl();
+ if (const AlignedAttr *Aligned = Typedef->getAttr<AlignedAttr>()) {
+ Align = Aligned->getAlignment();
+ Width = getTypeSize(Typedef->getUnderlyingType().getTypePtr());
+ } else
+ return getTypeInfo(Typedef->getUnderlyingType().getTypePtr());
+ break;
+ }
+
+ case Type::TypeOfExpr:
+ return getTypeInfo(cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType()
+ .getTypePtr());
+
+ case Type::TypeOf:
+ return getTypeInfo(cast<TypeOfType>(T)->getUnderlyingType().getTypePtr());
+
+ case Type::QualifiedName:
+ return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr());
+
+ case Type::TemplateSpecialization:
+ assert(getCanonicalType(T) != T &&
+ "Cannot request the size of a dependent type");
+ // FIXME: this is likely to be wrong once we support template
+ // aliases, since a template alias could refer to a typedef that
+ // has an __aligned__ attribute on it.
+ return getTypeInfo(getCanonicalType(T));
+ }
+
+ assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2");
+ return std::make_pair(Width, Align);
+}
+
+/// getPreferredTypeAlign - Return the "preferred" alignment of the specified
+/// type for the current target in bits. This can be different than the ABI
+/// alignment in cases where it is beneficial for performance to overalign
+/// a data type.
+unsigned ASTContext::getPreferredTypeAlign(const Type *T) {
+ unsigned ABIAlign = getTypeAlign(T);
+
+ // Double and long long should be naturally aligned if possible.
+ if (const ComplexType* CT = T->getAsComplexType())
+ T = CT->getElementType().getTypePtr();
+ if (T->isSpecificBuiltinType(BuiltinType::Double) ||
+ T->isSpecificBuiltinType(BuiltinType::LongLong))
+ return std::max(ABIAlign, (unsigned)getTypeSize(T));
+
+ return ABIAlign;
+}
+
+
+/// LayoutField - Field layout.
+void ASTRecordLayout::LayoutField(const FieldDecl *FD, unsigned FieldNo,
+ bool IsUnion, unsigned StructPacking,
+ ASTContext &Context) {
+ unsigned FieldPacking = StructPacking;
+ uint64_t FieldOffset = IsUnion ? 0 : Size;
+ uint64_t FieldSize;
+ unsigned FieldAlign;
+
+ // FIXME: Should this override struct packing? Probably we want to
+ // take the minimum?
+ if (const PackedAttr *PA = FD->getAttr<PackedAttr>())
+ FieldPacking = PA->getAlignment();
+
+ if (const Expr *BitWidthExpr = FD->getBitWidth()) {
+ // TODO: Need to check this algorithm on other targets!
+ // (tested on Linux-X86)
+ FieldSize = BitWidthExpr->EvaluateAsInt(Context).getZExtValue();
+
+ std::pair<uint64_t, unsigned> FieldInfo =
+ Context.getTypeInfo(FD->getType());
+ uint64_t TypeSize = FieldInfo.first;
+
+ // Determine the alignment of this bitfield. The packing
+ // attributes define a maximum and the alignment attribute defines
+ // a minimum.
+ // FIXME: What is the right behavior when the specified alignment
+ // is smaller than the specified packing?
+ FieldAlign = FieldInfo.second;
+ if (FieldPacking)
+ FieldAlign = std::min(FieldAlign, FieldPacking);
+ if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>())
+ FieldAlign = std::max(FieldAlign, AA->getAlignment());
+
+ // Check if we need to add padding to give the field the correct
+ // alignment.
+ if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
+ FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
+
+ // Padding members don't affect overall alignment
+ if (!FD->getIdentifier())
+ FieldAlign = 1;
+ } else {
+ if (FD->getType()->isIncompleteArrayType()) {
+ // This is a flexible array member; we can't directly
+ // query getTypeInfo about these, so we figure it out here.
+ // Flexible array members don't have any size, but they
+ // have to be aligned appropriately for their element type.
+ FieldSize = 0;
+ const ArrayType* ATy = Context.getAsArrayType(FD->getType());
+ FieldAlign = Context.getTypeAlign(ATy->getElementType());
+ } else if (const ReferenceType *RT = FD->getType()->getAsReferenceType()) {
+ unsigned AS = RT->getPointeeType().getAddressSpace();
+ FieldSize = Context.Target.getPointerWidth(AS);
+ FieldAlign = Context.Target.getPointerAlign(AS);
+ } else {
+ std::pair<uint64_t, unsigned> FieldInfo =
+ Context.getTypeInfo(FD->getType());
+ FieldSize = FieldInfo.first;
+ FieldAlign = FieldInfo.second;
+ }
+
+ // Determine the alignment of this bitfield. The packing
+ // attributes define a maximum and the alignment attribute defines
+ // a minimum. Additionally, the packing alignment must be at least
+ // a byte for non-bitfields.
+ //
+ // FIXME: What is the right behavior when the specified alignment
+ // is smaller than the specified packing?
+ if (FieldPacking)
+ FieldAlign = std::min(FieldAlign, std::max(8U, FieldPacking));
+ if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>())
+ FieldAlign = std::max(FieldAlign, AA->getAlignment());
+
+ // Round up the current record size to the field's alignment boundary.
+ FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
+ }
+
+ // Place this field at the current location.
+ FieldOffsets[FieldNo] = FieldOffset;
+
+ // Reserve space for this field.
+ if (IsUnion) {
+ Size = std::max(Size, FieldSize);
+ } else {
+ Size = FieldOffset + FieldSize;
+ }
+
+ // Remember the next available offset.
+ NextOffset = Size;
+
+ // Remember max struct/class alignment.
+ Alignment = std::max(Alignment, FieldAlign);
+}
+
+static void CollectLocalObjCIvars(ASTContext *Ctx,
+ const ObjCInterfaceDecl *OI,
+ llvm::SmallVectorImpl<FieldDecl*> &Fields) {
+ for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(),
+ E = OI->ivar_end(); I != E; ++I) {
+ ObjCIvarDecl *IVDecl = *I;
+ if (!IVDecl->isInvalidDecl())
+ Fields.push_back(cast<FieldDecl>(IVDecl));
+ }
+}
+
+void ASTContext::CollectObjCIvars(const ObjCInterfaceDecl *OI,
+ llvm::SmallVectorImpl<FieldDecl*> &Fields) {
+ if (const ObjCInterfaceDecl *SuperClass = OI->getSuperClass())
+ CollectObjCIvars(SuperClass, Fields);
+ CollectLocalObjCIvars(this, OI, Fields);
+}
+
+void ASTContext::CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD,
+ llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
+ for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(*this),
+ E = PD->prop_end(*this); I != E; ++I)
+ if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl())
+ Ivars.push_back(Ivar);
+
+ // Also look into nested protocols.
+ for (ObjCProtocolDecl::protocol_iterator P = PD->protocol_begin(),
+ E = PD->protocol_end(); P != E; ++P)
+ CollectProtocolSynthesizedIvars(*P, Ivars);
+}
+
+/// CollectSynthesizedIvars -
+/// This routine collect synthesized ivars for the designated class.
+///
+void ASTContext::CollectSynthesizedIvars(const ObjCInterfaceDecl *OI,
+ llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
+ for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(*this),
+ E = OI->prop_end(*this); I != E; ++I) {
+ if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl())
+ Ivars.push_back(Ivar);
+ }
+ // Also look into interface's protocol list for properties declared
+ // in the protocol and whose ivars are synthesized.
+ for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(),
+ PE = OI->protocol_end(); P != PE; ++P) {
+ ObjCProtocolDecl *PD = (*P);
+ CollectProtocolSynthesizedIvars(PD, Ivars);
+ }
+}
+
+/// getInterfaceLayoutImpl - 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.
+const ASTRecordLayout &
+ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
+ const ObjCImplementationDecl *Impl) {
+ assert(!D->isForwardDecl() && "Invalid interface decl!");
+
+ // Look up this layout, if already laid out, return what we have.
+ ObjCContainerDecl *Key =
+ Impl ? (ObjCContainerDecl*) Impl : (ObjCContainerDecl*) D;
+ if (const ASTRecordLayout *Entry = ObjCLayouts[Key])
+ return *Entry;
+
+ unsigned FieldCount = D->ivar_size();
+ // Add in synthesized ivar count if laying out an implementation.
+ if (Impl) {
+ llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
+ CollectSynthesizedIvars(D, Ivars);
+ FieldCount += Ivars.size();
+ // If there aren't any sythesized ivars then reuse the interface
+ // entry. Note we can't cache this because we simply free all
+ // entries later; however we shouldn't look up implementations
+ // frequently.
+ if (FieldCount == D->ivar_size())
+ return getObjCLayout(D, 0);
+ }
+
+ ASTRecordLayout *NewEntry = NULL;
+ if (ObjCInterfaceDecl *SD = D->getSuperClass()) {
+ const ASTRecordLayout &SL = getASTObjCInterfaceLayout(SD);
+ unsigned Alignment = SL.getAlignment();
+
+ // We start laying out ivars not at the end of the superclass
+ // structure, but at the next byte following the last field.
+ uint64_t Size = llvm::RoundUpToAlignment(SL.NextOffset, 8);
+
+ ObjCLayouts[Key] = NewEntry = new ASTRecordLayout(Size, Alignment);
+ NewEntry->InitializeLayout(FieldCount);
+ } else {
+ ObjCLayouts[Key] = NewEntry = new ASTRecordLayout();
+ NewEntry->InitializeLayout(FieldCount);
+ }
+
+ unsigned StructPacking = 0;
+ if (const PackedAttr *PA = D->getAttr<PackedAttr>())
+ StructPacking = PA->getAlignment();
+
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ NewEntry->SetAlignment(std::max(NewEntry->getAlignment(),
+ AA->getAlignment()));
+
+ // Layout each ivar sequentially.
+ unsigned i = 0;
+ for (ObjCInterfaceDecl::ivar_iterator IVI = D->ivar_begin(),
+ IVE = D->ivar_end(); IVI != IVE; ++IVI) {
+ const ObjCIvarDecl* Ivar = (*IVI);
+ NewEntry->LayoutField(Ivar, i++, false, StructPacking, *this);
+ }
+ // And synthesized ivars, if this is an implementation.
+ if (Impl) {
+ // FIXME. Do we need to colltect twice?
+ llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
+ CollectSynthesizedIvars(D, Ivars);
+ for (unsigned k = 0, e = Ivars.size(); k != e; ++k)
+ NewEntry->LayoutField(Ivars[k], i++, false, StructPacking, *this);
+ }
+
+ // Finally, round the size of the total struct up to the alignment of the
+ // struct itself.
+ NewEntry->FinalizeLayout();
+ return *NewEntry;
+}
+
+const ASTRecordLayout &
+ASTContext::getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) {
+ return getObjCLayout(D, 0);
+}
+
+const ASTRecordLayout &
+ASTContext::getASTObjCImplementationLayout(const ObjCImplementationDecl *D) {
+ return getObjCLayout(D->getClassInterface(), D);
+}
+
+/// 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) {
+ D = D->getDefinition(*this);
+ assert(D && "Cannot get layout of forward declarations!");
+
+ // Look up this layout, if already laid out, return what we have.
+ const ASTRecordLayout *&Entry = ASTRecordLayouts[D];
+ if (Entry) return *Entry;
+
+ // Allocate and assign into ASTRecordLayouts here. The "Entry" reference can
+ // be invalidated (dangle) if the ASTRecordLayouts hashtable is inserted into.
+ ASTRecordLayout *NewEntry = new ASTRecordLayout();
+ Entry = NewEntry;
+
+ // FIXME: Avoid linear walk through the fields, if possible.
+ NewEntry->InitializeLayout(std::distance(D->field_begin(*this),
+ D->field_end(*this)));
+ bool IsUnion = D->isUnion();
+
+ unsigned StructPacking = 0;
+ if (const PackedAttr *PA = D->getAttr<PackedAttr>())
+ StructPacking = PA->getAlignment();
+
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ NewEntry->SetAlignment(std::max(NewEntry->getAlignment(),
+ AA->getAlignment()));
+
+ // Layout each field, for now, just sequentially, respecting alignment. In
+ // the future, this will need to be tweakable by targets.
+ unsigned FieldIdx = 0;
+ for (RecordDecl::field_iterator Field = D->field_begin(*this),
+ FieldEnd = D->field_end(*this);
+ Field != FieldEnd; (void)++Field, ++FieldIdx)
+ NewEntry->LayoutField(*Field, FieldIdx, IsUnion, StructPacking, *this);
+
+ // Finally, round the size of the total struct up to the alignment of the
+ // struct itself.
+ NewEntry->FinalizeLayout(getLangOptions().CPlusPlus);
+ return *NewEntry;
+}
+
+//===----------------------------------------------------------------------===//
+// Type creation/memoization methods
+//===----------------------------------------------------------------------===//
+
+QualType ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) {
+ QualType CanT = getCanonicalType(T);
+ if (CanT.getAddressSpace() == AddressSpace)
+ return T;
+
+ // If we are composing extended qualifiers together, merge together into one
+ // ExtQualType node.
+ unsigned CVRQuals = T.getCVRQualifiers();
+ QualType::GCAttrTypes GCAttr = QualType::GCNone;
+ Type *TypeNode = T.getTypePtr();
+
+ if (ExtQualType *EQT = dyn_cast<ExtQualType>(TypeNode)) {
+ // If this type already has an address space specified, it cannot get
+ // another one.
+ assert(EQT->getAddressSpace() == 0 &&
+ "Type cannot be in multiple addr spaces!");
+ GCAttr = EQT->getObjCGCAttr();
+ TypeNode = EQT->getBaseType();
+ }
+
+ // Check if we've already instantiated this type.
+ llvm::FoldingSetNodeID ID;
+ ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr);
+ void *InsertPos = 0;
+ if (ExtQualType *EXTQy = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(EXTQy, CVRQuals);
+
+ // If the base type isn't canonical, this won't be a canonical type either,
+ // so fill in the canonical type field.
+ QualType Canonical;
+ if (!TypeNode->isCanonical()) {
+ Canonical = getAddrSpaceQualType(CanT, AddressSpace);
+
+ // Update InsertPos, the previous call could have invalidated it.
+ ExtQualType *NewIP = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ }
+ ExtQualType *New =
+ new (*this, 8) ExtQualType(TypeNode, Canonical, AddressSpace, GCAttr);
+ ExtQualTypes.InsertNode(New, InsertPos);
+ Types.push_back(New);
+ return QualType(New, CVRQuals);
+}
+
+QualType ASTContext::getObjCGCQualType(QualType T,
+ QualType::GCAttrTypes GCAttr) {
+ QualType CanT = getCanonicalType(T);
+ if (CanT.getObjCGCAttr() == GCAttr)
+ return T;
+
+ // If we are composing extended qualifiers together, merge together into one
+ // ExtQualType node.
+ unsigned CVRQuals = T.getCVRQualifiers();
+ Type *TypeNode = T.getTypePtr();
+ unsigned AddressSpace = 0;
+
+ if (ExtQualType *EQT = dyn_cast<ExtQualType>(TypeNode)) {
+ // If this type already has an address space specified, it cannot get
+ // another one.
+ assert(EQT->getObjCGCAttr() == QualType::GCNone &&
+ "Type cannot be in multiple addr spaces!");
+ AddressSpace = EQT->getAddressSpace();
+ TypeNode = EQT->getBaseType();
+ }
+
+ // Check if we've already instantiated an gc qual'd type of this type.
+ llvm::FoldingSetNodeID ID;
+ ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr);
+ void *InsertPos = 0;
+ if (ExtQualType *EXTQy = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(EXTQy, CVRQuals);
+
+ // If the base type isn't canonical, this won't be a canonical type either,
+ // so fill in the canonical type field.
+ // FIXME: Isn't this also not canonical if the base type is a array
+ // or pointer type? I can't find any documentation for objc_gc, though...
+ QualType Canonical;
+ if (!T->isCanonical()) {
+ Canonical = getObjCGCQualType(CanT, GCAttr);
+
+ // Update InsertPos, the previous call could have invalidated it.
+ ExtQualType *NewIP = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ }
+ ExtQualType *New =
+ new (*this, 8) ExtQualType(TypeNode, Canonical, AddressSpace, GCAttr);
+ ExtQualTypes.InsertNode(New, InsertPos);
+ Types.push_back(New);
+ return QualType(New, CVRQuals);
+}
+
+/// getComplexType - Return the uniqued reference to the type for a complex
+/// number with the specified element type.
+QualType ASTContext::getComplexType(QualType T) {
+ // Unique pointers, to guarantee there is only one pointer of a particular
+ // structure.
+ llvm::FoldingSetNodeID ID;
+ ComplexType::Profile(ID, T);
+
+ void *InsertPos = 0;
+ if (ComplexType *CT = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(CT, 0);
+
+ // If the pointee 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 = getComplexType(getCanonicalType(T));
+
+ // Get the new insert position for the node we care about.
+ ComplexType *NewIP = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ }
+ ComplexType *New = new (*this,8) ComplexType(T, Canonical);
+ Types.push_back(New);
+ ComplexTypes.InsertNode(New, InsertPos);
+ return QualType(New, 0);
+}
+
+QualType ASTContext::getFixedWidthIntType(unsigned Width, bool Signed) {
+ llvm::DenseMap<unsigned, FixedWidthIntType*> &Map = Signed ?
+ SignedFixedWidthIntTypes : UnsignedFixedWidthIntTypes;
+ FixedWidthIntType *&Entry = Map[Width];
+ if (!Entry)
+ Entry = new FixedWidthIntType(Width, Signed);
+ return QualType(Entry, 0);
+}
+
+/// getPointerType - Return the uniqued reference to the type for a pointer to
+/// the specified type.
+QualType ASTContext::getPointerType(QualType T) {
+ // Unique pointers, to guarantee there is only one pointer of a particular
+ // structure.
+ llvm::FoldingSetNodeID ID;
+ PointerType::Profile(ID, T);
+
+ void *InsertPos = 0;
+ if (PointerType *PT = PointerTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(PT, 0);
+
+ // If the pointee 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 = getPointerType(getCanonicalType(T));
+
+ // Get the new insert position for the node we care about.
+ PointerType *NewIP = PointerTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ }
+ PointerType *New = new (*this,8) PointerType(T, Canonical);
+ Types.push_back(New);
+ PointerTypes.InsertNode(New, InsertPos);
+ return QualType(New, 0);
+}
+
+/// getBlockPointerType - Return the uniqued reference to the type for
+/// a pointer to the specified block.
+QualType ASTContext::getBlockPointerType(QualType T) {
+ assert(T->isFunctionType() && "block of function types only");
+ // Unique pointers, to guarantee there is only one block of a particular
+ // structure.
+ llvm::FoldingSetNodeID ID;
+ BlockPointerType::Profile(ID, T);
+
+ void *InsertPos = 0;
+ if (BlockPointerType *PT =
+ BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(PT, 0);
+
+ // If the block pointee 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 = getBlockPointerType(getCanonicalType(T));
+
+ // Get the new insert position for the node we care about.
+ BlockPointerType *NewIP =
+ BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ }
+ BlockPointerType *New = new (*this,8) BlockPointerType(T, Canonical);
+ Types.push_back(New);
+ BlockPointerTypes.InsertNode(New, InsertPos);
+ return QualType(New, 0);
+}
+
+/// getLValueReferenceType - Return the uniqued reference to the type for an
+/// lvalue reference to the specified type.
+QualType ASTContext::getLValueReferenceType(QualType T) {
+ // Unique pointers, to guarantee there is only one pointer of a particular
+ // structure.
+ llvm::FoldingSetNodeID ID;
+ ReferenceType::Profile(ID, T);
+
+ void *InsertPos = 0;
+ if (LValueReferenceType *RT =
+ LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(RT, 0);
+
+ // If the referencee 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 = getLValueReferenceType(getCanonicalType(T));
+
+ // Get the new insert position for the node we care about.
+ LValueReferenceType *NewIP =
+ LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ }
+
+ LValueReferenceType *New = new (*this,8) LValueReferenceType(T, Canonical);
+ Types.push_back(New);
+ LValueReferenceTypes.InsertNode(New, InsertPos);
+ return QualType(New, 0);
+}
+
+/// getRValueReferenceType - Return the uniqued reference to the type for an
+/// rvalue reference to the specified type.
+QualType ASTContext::getRValueReferenceType(QualType T) {
+ // Unique pointers, to guarantee there is only one pointer of a particular
+ // structure.
+ llvm::FoldingSetNodeID ID;
+ ReferenceType::Profile(ID, T);
+
+ void *InsertPos = 0;
+ if (RValueReferenceType *RT =
+ RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(RT, 0);
+
+ // If the referencee 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 = getRValueReferenceType(getCanonicalType(T));
+
+ // Get the new insert position for the node we care about.
+ RValueReferenceType *NewIP =
+ RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ }
+
+ RValueReferenceType *New = new (*this,8) RValueReferenceType(T, Canonical);
+ Types.push_back(New);
+ RValueReferenceTypes.InsertNode(New, InsertPos);
+ return QualType(New, 0);
+}
+
+/// getMemberPointerType - Return the uniqued reference to the type for a
+/// member pointer to the specified type, in the specified class.
+QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls)
+{
+ // Unique pointers, to guarantee there is only one pointer of a particular
+ // structure.
+ llvm::FoldingSetNodeID ID;
+ MemberPointerType::Profile(ID, T, Cls);
+
+ void *InsertPos = 0;
+ if (MemberPointerType *PT =
+ MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(PT, 0);
+
+ // If the pointee or class 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 = getMemberPointerType(getCanonicalType(T),getCanonicalType(Cls));
+
+ // Get the new insert position for the node we care about.
+ MemberPointerType *NewIP =
+ MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ }
+ MemberPointerType *New = new (*this,8) MemberPointerType(T, Cls, Canonical);
+ Types.push_back(New);
+ MemberPointerTypes.InsertNode(New, InsertPos);
+ return QualType(New, 0);
+}
+
+/// getConstantArrayType - Return the unique reference to the type for an
+/// array of the specified element type.
+QualType ASTContext::getConstantArrayType(QualType EltTy,
+ const llvm::APInt &ArySizeIn,
+ ArrayType::ArraySizeModifier ASM,
+ unsigned EltTypeQuals) {
+ assert((EltTy->isDependentType() || EltTy->isConstantSizeType()) &&
+ "Constant array of VLAs is illegal!");
+
+ // Convert the array size into a canonical width matching the pointer size for
+ // the target.
+ llvm::APInt ArySize(ArySizeIn);
+ ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace()));
+
+ llvm::FoldingSetNodeID ID;
+ ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, EltTypeQuals);
+
+ void *InsertPos = 0;
+ if (ConstantArrayType *ATP =
+ ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(ATP, 0);
+
+ // If the element type isn't canonical, this won't be a canonical type either,
+ // so fill in the canonical type field.
+ QualType Canonical;
+ if (!EltTy->isCanonical()) {
+ Canonical = getConstantArrayType(getCanonicalType(EltTy), ArySize,
+ ASM, EltTypeQuals);
+ // Get the new insert position for the node we care about.
+ ConstantArrayType *NewIP =
+ ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ }
+
+ ConstantArrayType *New =
+ new(*this,8)ConstantArrayType(EltTy, Canonical, ArySize, ASM, EltTypeQuals);
+ ConstantArrayTypes.InsertNode(New, InsertPos);
+ Types.push_back(New);
+ return QualType(New, 0);
+}
+
+/// getVariableArrayType - Returns a non-unique reference to the type for a
+/// variable array of the specified element type.
+QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts,
+ ArrayType::ArraySizeModifier ASM,
+ unsigned EltTypeQuals) {
+ // Since we don't unique expressions, it isn't possible to unique VLA's
+ // that have an expression provided for their size.
+
+ VariableArrayType *New =
+ new(*this,8)VariableArrayType(EltTy,QualType(), NumElts, ASM, EltTypeQuals);
+
+ VariableArrayTypes.push_back(New);
+ Types.push_back(New);
+ return QualType(New, 0);
+}
+
+/// getDependentSizedArrayType - Returns a non-unique reference to
+/// the type for a dependently-sized array of the specified element
+/// type. FIXME: We will need these to be uniqued, or at least
+/// comparable, at some point.
+QualType ASTContext::getDependentSizedArrayType(QualType EltTy, Expr *NumElts,
+ ArrayType::ArraySizeModifier ASM,
+ unsigned EltTypeQuals) {
+ assert((NumElts->isTypeDependent() || NumElts->isValueDependent()) &&
+ "Size must be type- or value-dependent!");
+
+ // Since we don't unique expressions, it isn't possible to unique
+ // dependently-sized array types.
+
+ DependentSizedArrayType *New =
+ new (*this,8) DependentSizedArrayType(EltTy, QualType(), NumElts,
+ ASM, EltTypeQuals);
+
+ DependentSizedArrayTypes.push_back(New);
+ Types.push_back(New);
+ return QualType(New, 0);
+}
+
+QualType ASTContext::getIncompleteArrayType(QualType EltTy,
+ ArrayType::ArraySizeModifier ASM,
+ unsigned EltTypeQuals) {
+ llvm::FoldingSetNodeID ID;
+ IncompleteArrayType::Profile(ID, EltTy, ASM, EltTypeQuals);
+
+ void *InsertPos = 0;
+ if (IncompleteArrayType *ATP =
+ IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(ATP, 0);
+
+ // If the element type isn't canonical, this won't be a canonical type
+ // either, so fill in the canonical type field.
+ QualType Canonical;
+
+ if (!EltTy->isCanonical()) {
+ Canonical = getIncompleteArrayType(getCanonicalType(EltTy),
+ ASM, EltTypeQuals);
+
+ // Get the new insert position for the node we care about.
+ IncompleteArrayType *NewIP =
+ IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ }
+
+ IncompleteArrayType *New = new (*this,8) IncompleteArrayType(EltTy, Canonical,
+ ASM, EltTypeQuals);
+
+ IncompleteArrayTypes.InsertNode(New, InsertPos);
+ Types.push_back(New);
+ return QualType(New, 0);
+}
+
+/// getVectorType - Return the unique reference to a vector type of
+/// the specified element type and size. VectorType must be a built-in type.
+QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) {
+ BuiltinType *baseType;
+
+ baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr());
+ assert(baseType != 0 && "getVectorType(): Expecting a built-in type");
+
+ // Check if we've already instantiated a vector of this type.
+ llvm::FoldingSetNodeID ID;
+ VectorType::Profile(ID, vecType, NumElts, Type::Vector);
+ void *InsertPos = 0;
+ if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(VTP, 0);
+
+ // If the element type isn't canonical, this won't be a canonical type either,
+ // so fill in the canonical type field.
+ QualType Canonical;
+ if (!vecType->isCanonical()) {
+ Canonical = getVectorType(getCanonicalType(vecType), NumElts);
+
+ // Get the new insert position for the node we care about.
+ VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ }
+ VectorType *New = new (*this,8) VectorType(vecType, NumElts, Canonical);
+ VectorTypes.InsertNode(New, InsertPos);
+ Types.push_back(New);
+ return QualType(New, 0);
+}
+
+/// getExtVectorType - Return the unique reference to an extended vector type of
+/// the specified element type and size. VectorType must be a built-in type.
+QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) {
+ BuiltinType *baseType;
+
+ baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr());
+ assert(baseType != 0 && "getExtVectorType(): Expecting a built-in type");
+
+ // Check if we've already instantiated a vector of this type.
+ llvm::FoldingSetNodeID ID;
+ VectorType::Profile(ID, vecType, NumElts, Type::ExtVector);
+ void *InsertPos = 0;
+ if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(VTP, 0);
+
+ // If the element type isn't canonical, this won't be a canonical type either,
+ // so fill in the canonical type field.
+ QualType Canonical;
+ if (!vecType->isCanonical()) {
+ Canonical = getExtVectorType(getCanonicalType(vecType), NumElts);
+
+ // Get the new insert position for the node we care about.
+ VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ }
+ ExtVectorType *New = new (*this,8) ExtVectorType(vecType, NumElts, Canonical);
+ VectorTypes.InsertNode(New, InsertPos);
+ Types.push_back(New);
+ return QualType(New, 0);
+}
+
+/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
+///
+QualType ASTContext::getFunctionNoProtoType(QualType ResultTy) {
+ // Unique functions, to guarantee there is only one function of a particular
+ // structure.
+ llvm::FoldingSetNodeID ID;
+ FunctionNoProtoType::Profile(ID, ResultTy);
+
+ void *InsertPos = 0;
+ if (FunctionNoProtoType *FT =
+ FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(FT, 0);
+
+ QualType Canonical;
+ if (!ResultTy->isCanonical()) {
+ Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy));
+
+ // Get the new insert position for the node we care about.
+ FunctionNoProtoType *NewIP =
+ FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ }
+
+ FunctionNoProtoType *New =new(*this,8)FunctionNoProtoType(ResultTy,Canonical);
+ Types.push_back(New);
+ FunctionNoProtoTypes.InsertNode(New, InsertPos);
+ return QualType(New, 0);
+}
+
+/// getFunctionType - Return a normal function type with a typed argument
+/// list. isVariadic indicates whether the argument list includes '...'.
+QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
+ unsigned NumArgs, bool isVariadic,
+ unsigned TypeQuals, bool hasExceptionSpec,
+ bool hasAnyExceptionSpec, unsigned NumExs,
+ const QualType *ExArray) {
+ // Unique functions, to guarantee there is only one function of a particular
+ // structure.
+ llvm::FoldingSetNodeID ID;
+ FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic,
+ TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
+ NumExs, ExArray);
+
+ void *InsertPos = 0;
+ if (FunctionProtoType *FTP =
+ FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(FTP, 0);
+
+ // Determine whether the type being created is already canonical or not.
+ bool isCanonical = ResultTy->isCanonical();
+ if (hasExceptionSpec)
+ isCanonical = false;
+ for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
+ if (!ArgArray[i]->isCanonical())
+ isCanonical = false;
+
+ // If this type isn't canonical, get the canonical version of it.
+ // The exception spec is not part of the canonical type.
+ QualType Canonical;
+ if (!isCanonical) {
+ llvm::SmallVector<QualType, 16> CanonicalArgs;
+ CanonicalArgs.reserve(NumArgs);
+ for (unsigned i = 0; i != NumArgs; ++i)
+ CanonicalArgs.push_back(getCanonicalType(ArgArray[i]));
+
+ Canonical = getFunctionType(getCanonicalType(ResultTy),
+ CanonicalArgs.data(), NumArgs,
+ isVariadic, TypeQuals);
+
+ // Get the new insert position for the node we care about.
+ FunctionProtoType *NewIP =
+ FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ }
+
+ // FunctionProtoType objects are allocated with extra bytes after them
+ // for two variable size arrays (for parameter and exception types) at the
+ // end of them.
+ FunctionProtoType *FTP =
+ (FunctionProtoType*)Allocate(sizeof(FunctionProtoType) +
+ NumArgs*sizeof(QualType) +
+ NumExs*sizeof(QualType), 8);
+ new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic,
+ TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
+ ExArray, NumExs, Canonical);
+ Types.push_back(FTP);
+ FunctionProtoTypes.InsertNode(FTP, InsertPos);
+ return QualType(FTP, 0);
+}
+
+/// getTypeDeclType - Return the unique reference to the type for the
+/// specified type declaration.
+QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) {
+ assert(Decl && "Passed null for Decl param");
+ if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
+
+ if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl))
+ return getTypedefType(Typedef);
+ else if (isa<TemplateTypeParmDecl>(Decl)) {
+ assert(false && "Template type parameter types are always available.");
+ } else if (ObjCInterfaceDecl *ObjCInterface = dyn_cast<ObjCInterfaceDecl>(Decl))
+ return getObjCInterfaceType(ObjCInterface);
+
+ if (RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) {
+ if (PrevDecl)
+ Decl->TypeForDecl = PrevDecl->TypeForDecl;
+ else
+ Decl->TypeForDecl = new (*this,8) RecordType(Record);
+ }
+ else if (EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) {
+ if (PrevDecl)
+ Decl->TypeForDecl = PrevDecl->TypeForDecl;
+ else
+ Decl->TypeForDecl = new (*this,8) EnumType(Enum);
+ }
+ else
+ assert(false && "TypeDecl without a type?");
+
+ if (!PrevDecl) Types.push_back(Decl->TypeForDecl);
+ return QualType(Decl->TypeForDecl, 0);
+}
+
+/// getTypedefType - Return the unique reference to the type for the
+/// specified typename decl.
+QualType ASTContext::getTypedefType(TypedefDecl *Decl) {
+ if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
+
+ QualType Canonical = getCanonicalType(Decl->getUnderlyingType());
+ Decl->TypeForDecl = new(*this,8) TypedefType(Type::Typedef, Decl, Canonical);
+ Types.push_back(Decl->TypeForDecl);
+ return QualType(Decl->TypeForDecl, 0);
+}
+
+/// getObjCInterfaceType - Return the unique reference to the type for the
+/// specified ObjC interface decl.
+QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) {
+ if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
+
+ ObjCInterfaceDecl *OID = const_cast<ObjCInterfaceDecl*>(Decl);
+ Decl->TypeForDecl = new(*this,8) ObjCInterfaceType(Type::ObjCInterface, OID);
+ Types.push_back(Decl->TypeForDecl);
+ return QualType(Decl->TypeForDecl, 0);
+}
+
+/// \brief Retrieve the template type parameter type for a template
+/// parameter with the given depth, index, and (optionally) name.
+QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
+ IdentifierInfo *Name) {
+ llvm::FoldingSetNodeID ID;
+ TemplateTypeParmType::Profile(ID, Depth, Index, Name);
+ void *InsertPos = 0;
+ TemplateTypeParmType *TypeParm
+ = TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (TypeParm)
+ return QualType(TypeParm, 0);
+
+ if (Name)
+ TypeParm = new (*this, 8) TemplateTypeParmType(Depth, Index, Name,
+ getTemplateTypeParmType(Depth, Index));
+ else
+ TypeParm = new (*this, 8) TemplateTypeParmType(Depth, Index);
+
+ Types.push_back(TypeParm);
+ TemplateTypeParmTypes.InsertNode(TypeParm, InsertPos);
+
+ return QualType(TypeParm, 0);
+}
+
+QualType
+ASTContext::getTemplateSpecializationType(TemplateName Template,
+ const TemplateArgument *Args,
+ unsigned NumArgs,
+ QualType Canon) {
+ if (!Canon.isNull())
+ Canon = getCanonicalType(Canon);
+
+ llvm::FoldingSetNodeID ID;
+ TemplateSpecializationType::Profile(ID, Template, Args, NumArgs);
+
+ void *InsertPos = 0;
+ TemplateSpecializationType *Spec
+ = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (Spec)
+ return QualType(Spec, 0);
+
+ void *Mem = Allocate((sizeof(TemplateSpecializationType) +
+ sizeof(TemplateArgument) * NumArgs),
+ 8);
+ Spec = new (Mem) TemplateSpecializationType(Template, Args, NumArgs, Canon);
+ Types.push_back(Spec);
+ TemplateSpecializationTypes.InsertNode(Spec, InsertPos);
+
+ return QualType(Spec, 0);
+}
+
+QualType
+ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS,
+ QualType NamedType) {
+ llvm::FoldingSetNodeID ID;
+ QualifiedNameType::Profile(ID, NNS, NamedType);
+
+ void *InsertPos = 0;
+ QualifiedNameType *T
+ = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (T)
+ return QualType(T, 0);
+
+ T = new (*this) QualifiedNameType(NNS, NamedType,
+ getCanonicalType(NamedType));
+ Types.push_back(T);
+ QualifiedNameTypes.InsertNode(T, InsertPos);
+ return QualType(T, 0);
+}
+
+QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name,
+ QualType Canon) {
+ assert(NNS->isDependent() && "nested-name-specifier must be dependent");
+
+ if (Canon.isNull()) {
+ NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
+ if (CanonNNS != NNS)
+ Canon = getTypenameType(CanonNNS, Name);
+ }
+
+ llvm::FoldingSetNodeID ID;
+ TypenameType::Profile(ID, NNS, Name);
+
+ void *InsertPos = 0;
+ TypenameType *T
+ = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (T)
+ return QualType(T, 0);
+
+ T = new (*this) TypenameType(NNS, Name, Canon);
+ Types.push_back(T);
+ TypenameTypes.InsertNode(T, InsertPos);
+ return QualType(T, 0);
+}
+
+QualType
+ASTContext::getTypenameType(NestedNameSpecifier *NNS,
+ const TemplateSpecializationType *TemplateId,
+ QualType Canon) {
+ assert(NNS->isDependent() && "nested-name-specifier must be dependent");
+
+ if (Canon.isNull()) {
+ NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
+ QualType CanonType = getCanonicalType(QualType(TemplateId, 0));
+ if (CanonNNS != NNS || CanonType != QualType(TemplateId, 0)) {
+ const TemplateSpecializationType *CanonTemplateId
+ = CanonType->getAsTemplateSpecializationType();
+ assert(CanonTemplateId &&
+ "Canonical type must also be a template specialization type");
+ Canon = getTypenameType(CanonNNS, CanonTemplateId);
+ }
+ }
+
+ llvm::FoldingSetNodeID ID;
+ TypenameType::Profile(ID, NNS, TemplateId);
+
+ void *InsertPos = 0;
+ TypenameType *T
+ = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (T)
+ return QualType(T, 0);
+
+ T = new (*this) TypenameType(NNS, TemplateId, Canon);
+ Types.push_back(T);
+ TypenameTypes.InsertNode(T, InsertPos);
+ return QualType(T, 0);
+}
+
+/// CmpProtocolNames - Comparison predicate for sorting protocols
+/// alphabetically.
+static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
+ const ObjCProtocolDecl *RHS) {
+ return LHS->getDeclName() < RHS->getDeclName();
+}
+
+static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols,
+ unsigned &NumProtocols) {
+ ObjCProtocolDecl **ProtocolsEnd = Protocols+NumProtocols;
+
+ // Sort protocols, keyed by name.
+ std::sort(Protocols, Protocols+NumProtocols, CmpProtocolNames);
+
+ // Remove duplicates.
+ ProtocolsEnd = std::unique(Protocols, ProtocolsEnd);
+ NumProtocols = ProtocolsEnd-Protocols;
+}
+
+
+/// getObjCQualifiedInterfaceType - Return a ObjCQualifiedInterfaceType type for
+/// the given interface decl and the conforming protocol list.
+QualType ASTContext::getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl,
+ ObjCProtocolDecl **Protocols, unsigned NumProtocols) {
+ // Sort the protocol list alphabetically to canonicalize it.
+ SortAndUniqueProtocols(Protocols, NumProtocols);
+
+ llvm::FoldingSetNodeID ID;
+ ObjCQualifiedInterfaceType::Profile(ID, Decl, Protocols, NumProtocols);
+
+ void *InsertPos = 0;
+ if (ObjCQualifiedInterfaceType *QT =
+ ObjCQualifiedInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(QT, 0);
+
+ // No Match;
+ ObjCQualifiedInterfaceType *QType =
+ new (*this,8) ObjCQualifiedInterfaceType(Decl, Protocols, NumProtocols);
+
+ Types.push_back(QType);
+ ObjCQualifiedInterfaceTypes.InsertNode(QType, InsertPos);
+ return QualType(QType, 0);
+}
+
+/// getObjCQualifiedIdType - Return an ObjCQualifiedIdType for the 'id' decl
+/// and the conforming protocol list.
+QualType ASTContext::getObjCQualifiedIdType(ObjCProtocolDecl **Protocols,
+ unsigned NumProtocols) {
+ // Sort the protocol list alphabetically to canonicalize it.
+ SortAndUniqueProtocols(Protocols, NumProtocols);
+
+ llvm::FoldingSetNodeID ID;
+ ObjCQualifiedIdType::Profile(ID, Protocols, NumProtocols);
+
+ void *InsertPos = 0;
+ if (ObjCQualifiedIdType *QT =
+ ObjCQualifiedIdTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(QT, 0);
+
+ // No Match;
+ ObjCQualifiedIdType *QType =
+ new (*this,8) ObjCQualifiedIdType(Protocols, NumProtocols);
+ Types.push_back(QType);
+ ObjCQualifiedIdTypes.InsertNode(QType, InsertPos);
+ return QualType(QType, 0);
+}
+
+/// getTypeOfExprType - Unlike many "get<Type>" functions, we can't unique
+/// TypeOfExprType AST's (since expression's are never shared). For example,
+/// multiple declarations that refer to "typeof(x)" all contain different
+/// DeclRefExpr's. This doesn't effect the type checker, since it operates
+/// on canonical type's (which are always unique).
+QualType ASTContext::getTypeOfExprType(Expr *tofExpr) {
+ QualType Canonical = getCanonicalType(tofExpr->getType());
+ TypeOfExprType *toe = new (*this,8) TypeOfExprType(tofExpr, Canonical);
+ Types.push_back(toe);
+ return QualType(toe, 0);
+}
+
+/// getTypeOfType - Unlike many "get<Type>" functions, we don't unique
+/// TypeOfType AST's. The only motivation to unique these nodes would be
+/// memory savings. Since typeof(t) is fairly uncommon, space shouldn't be
+/// an issue. This doesn't effect the type checker, since it operates
+/// on canonical type's (which are always unique).
+QualType ASTContext::getTypeOfType(QualType tofType) {
+ QualType Canonical = getCanonicalType(tofType);
+ TypeOfType *tot = new (*this,8) TypeOfType(tofType, Canonical);
+ Types.push_back(tot);
+ return QualType(tot, 0);
+}
+
+/// getTagDeclType - Return the unique reference to the type for the
+/// specified TagDecl (struct/union/class/enum) decl.
+QualType ASTContext::getTagDeclType(TagDecl *Decl) {
+ assert (Decl);
+ return getTypeDeclType(Decl);
+}
+
+/// getSizeType - Return the unique type for "size_t" (C99 7.17), the result
+/// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and
+/// needs to agree with the definition in <stddef.h>.
+QualType ASTContext::getSizeType() const {
+ return getFromTargetType(Target.getSizeType());
+}
+
+/// getSignedWCharType - Return the type of "signed wchar_t".
+/// Used when in C++, as a GCC extension.
+QualType ASTContext::getSignedWCharType() const {
+ // FIXME: derive from "Target" ?
+ return WCharTy;
+}
+
+/// getUnsignedWCharType - Return the type of "unsigned wchar_t".
+/// Used when in C++, as a GCC extension.
+QualType ASTContext::getUnsignedWCharType() const {
+ // FIXME: derive from "Target" ?
+ return UnsignedIntTy;
+}
+
+/// 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));
+}
+
+//===----------------------------------------------------------------------===//
+// Type Operators
+//===----------------------------------------------------------------------===//
+
+/// getCanonicalType - Return the canonical (structural) type corresponding to
+/// the specified potentially non-canonical type. The non-canonical version
+/// of a type may have many "decorated" versions of types. Decorators can
+/// include typedefs, 'typeof' operators, etc. The returned type is guaranteed
+/// to be free of any of these, allowing two canonical types to be compared
+/// for exact equality with a simple pointer comparison.
+QualType ASTContext::getCanonicalType(QualType T) {
+ QualType CanType = T.getTypePtr()->getCanonicalTypeInternal();
+
+ // If the result has type qualifiers, make sure to canonicalize them as well.
+ unsigned TypeQuals = T.getCVRQualifiers() | CanType.getCVRQualifiers();
+ if (TypeQuals == 0) return CanType;
+
+ // If the type qualifiers are on an array type, get the canonical type of the
+ // array with the qualifiers applied to the element type.
+ ArrayType *AT = dyn_cast<ArrayType>(CanType);
+ if (!AT)
+ return CanType.getQualifiedType(TypeQuals);
+
+ // Get the canonical version of the element with the extra qualifiers on it.
+ // This can recursively sink qualifiers through multiple levels of arrays.
+ QualType NewEltTy=AT->getElementType().getWithAdditionalQualifiers(TypeQuals);
+ NewEltTy = getCanonicalType(NewEltTy);
+
+ if (ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
+ return getConstantArrayType(NewEltTy, CAT->getSize(),CAT->getSizeModifier(),
+ CAT->getIndexTypeQualifier());
+ if (IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT))
+ return getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(),
+ IAT->getIndexTypeQualifier());
+
+ if (DependentSizedArrayType *DSAT = dyn_cast<DependentSizedArrayType>(AT))
+ return getDependentSizedArrayType(NewEltTy, DSAT->getSizeExpr(),
+ DSAT->getSizeModifier(),
+ DSAT->getIndexTypeQualifier());
+
+ VariableArrayType *VAT = cast<VariableArrayType>(AT);
+ return getVariableArrayType(NewEltTy, VAT->getSizeExpr(),
+ VAT->getSizeModifier(),
+ VAT->getIndexTypeQualifier());
+}
+
+Decl *ASTContext::getCanonicalDecl(Decl *D) {
+ if (!D)
+ return 0;
+
+ if (TagDecl *Tag = dyn_cast<TagDecl>(D)) {
+ QualType T = getTagDeclType(Tag);
+ return cast<TagDecl>(cast<TagType>(T.getTypePtr()->CanonicalType)
+ ->getDecl());
+ }
+
+ if (ClassTemplateDecl *Template = dyn_cast<ClassTemplateDecl>(D)) {
+ while (Template->getPreviousDeclaration())
+ Template = Template->getPreviousDeclaration();
+ return Template;
+ }
+
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ while (Function->getPreviousDeclaration())
+ Function = Function->getPreviousDeclaration();
+ return const_cast<FunctionDecl *>(Function);
+ }
+
+ if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ while (Var->getPreviousDeclaration())
+ Var = Var->getPreviousDeclaration();
+ return const_cast<VarDecl *>(Var);
+ }
+
+ return D;
+}
+
+TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) {
+ // If this template name refers to a template, the canonical
+ // template name merely stores the template itself.
+ if (TemplateDecl *Template = Name.getAsTemplateDecl())
+ return TemplateName(cast<TemplateDecl>(getCanonicalDecl(Template)));
+
+ DependentTemplateName *DTN = Name.getAsDependentTemplateName();
+ assert(DTN && "Non-dependent template names must refer to template decls.");
+ return DTN->CanonicalTemplateName;
+}
+
+NestedNameSpecifier *
+ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) {
+ if (!NNS)
+ return 0;
+
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ // Canonicalize the prefix but keep the identifier the same.
+ return NestedNameSpecifier::Create(*this,
+ getCanonicalNestedNameSpecifier(NNS->getPrefix()),
+ NNS->getAsIdentifier());
+
+ case NestedNameSpecifier::Namespace:
+ // A namespace is canonical; build a nested-name-specifier with
+ // this namespace and no prefix.
+ return NestedNameSpecifier::Create(*this, 0, NNS->getAsNamespace());
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ QualType T = getCanonicalType(QualType(NNS->getAsType(), 0));
+ NestedNameSpecifier *Prefix = 0;
+
+ // FIXME: This isn't the right check!
+ if (T->isDependentType())
+ Prefix = getCanonicalNestedNameSpecifier(NNS->getPrefix());
+
+ return NestedNameSpecifier::Create(*this, Prefix,
+ NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate,
+ T.getTypePtr());
+ }
+
+ case NestedNameSpecifier::Global:
+ // The global specifier is canonical and unique.
+ return NNS;
+ }
+
+ // Required to silence a GCC warning
+ return 0;
+}
+
+
+const ArrayType *ASTContext::getAsArrayType(QualType T) {
+ // Handle the non-qualified case efficiently.
+ if (T.getCVRQualifiers() == 0) {
+ // Handle the common positive case fast.
+ if (const ArrayType *AT = dyn_cast<ArrayType>(T))
+ return AT;
+ }
+
+ // Handle the common negative case fast, ignoring CVR qualifiers.
+ QualType CType = T->getCanonicalTypeInternal();
+
+ // Make sure to look through type qualifiers (like ExtQuals) for the negative
+ // test.
+ if (!isa<ArrayType>(CType) &&
+ !isa<ArrayType>(CType.getUnqualifiedType()))
+ return 0;
+
+ // Apply any CVR qualifiers from the array type to the element type. This
+ // implements C99 6.7.3p8: "If the specification of an array type includes
+ // any type qualifiers, the element type is so qualified, not the array type."
+
+ // If we get here, we either have type qualifiers on the type, or we have
+ // sugar such as a typedef in the way. If we have type qualifiers on the type
+ // we must propagate them down into the elemeng type.
+ unsigned CVRQuals = T.getCVRQualifiers();
+ unsigned AddrSpace = 0;
+ Type *Ty = T.getTypePtr();
+
+ // Rip through ExtQualType's and typedefs to get to a concrete type.
+ while (1) {
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(Ty)) {
+ AddrSpace = EXTQT->getAddressSpace();
+ Ty = EXTQT->getBaseType();
+ } else {
+ T = Ty->getDesugaredType();
+ if (T.getTypePtr() == Ty && T.getCVRQualifiers() == 0)
+ break;
+ CVRQuals |= T.getCVRQualifiers();
+ Ty = T.getTypePtr();
+ }
+ }
+
+ // If we have a simple case, just return now.
+ const ArrayType *ATy = dyn_cast<ArrayType>(Ty);
+ if (ATy == 0 || (AddrSpace == 0 && CVRQuals == 0))
+ return ATy;
+
+ // Otherwise, we have an array and we have qualifiers on it. Push the
+ // qualifiers into the array element type and return a new array type.
+ // Get the canonical version of the element with the extra qualifiers on it.
+ // This can recursively sink qualifiers through multiple levels of arrays.
+ QualType NewEltTy = ATy->getElementType();
+ if (AddrSpace)
+ NewEltTy = getAddrSpaceQualType(NewEltTy, AddrSpace);
+ NewEltTy = NewEltTy.getWithAdditionalQualifiers(CVRQuals);
+
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(ATy))
+ return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(),
+ CAT->getSizeModifier(),
+ CAT->getIndexTypeQualifier()));
+ if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(ATy))
+ return cast<ArrayType>(getIncompleteArrayType(NewEltTy,
+ IAT->getSizeModifier(),
+ IAT->getIndexTypeQualifier()));
+
+ if (const DependentSizedArrayType *DSAT
+ = dyn_cast<DependentSizedArrayType>(ATy))
+ return cast<ArrayType>(
+ getDependentSizedArrayType(NewEltTy,
+ DSAT->getSizeExpr(),
+ DSAT->getSizeModifier(),
+ DSAT->getIndexTypeQualifier()));
+
+ const VariableArrayType *VAT = cast<VariableArrayType>(ATy);
+ return cast<ArrayType>(getVariableArrayType(NewEltTy, VAT->getSizeExpr(),
+ VAT->getSizeModifier(),
+ VAT->getIndexTypeQualifier()));
+}
+
+
+/// getArrayDecayedType - Return the properly qualified result of decaying the
+/// specified array type to a pointer. This operation is non-trivial when
+/// handling typedefs etc. The canonical type of "T" must be an array type,
+/// this returns a pointer to a properly qualified element of the array.
+///
+/// See C99 6.7.5.3p7 and C99 6.3.2.1p3.
+QualType ASTContext::getArrayDecayedType(QualType Ty) {
+ // Get the element type with 'getAsArrayType' so that we don't lose any
+ // typedefs in the element type of the array. This also handles propagation
+ // of type qualifiers from the array type into the element type if present
+ // (C99 6.7.3p8).
+ const ArrayType *PrettyArrayType = getAsArrayType(Ty);
+ assert(PrettyArrayType && "Not an array type!");
+
+ QualType PtrTy = getPointerType(PrettyArrayType->getElementType());
+
+ // int x[restrict 4] -> int *restrict
+ return PtrTy.getQualifiedType(PrettyArrayType->getIndexTypeQualifier());
+}
+
+QualType ASTContext::getBaseElementType(const VariableArrayType *VAT) {
+ QualType ElemTy = VAT->getElementType();
+
+ if (const VariableArrayType *VAT = getAsVariableArrayType(ElemTy))
+ return getBaseElementType(VAT);
+
+ return ElemTy;
+}
+
+/// getFloatingRank - Return a relative rank for floating point types.
+/// This routine will assert if passed a built-in type that isn't a float.
+static FloatingRank getFloatingRank(QualType T) {
+ if (const ComplexType *CT = T->getAsComplexType())
+ return getFloatingRank(CT->getElementType());
+
+ assert(T->getAsBuiltinType() && "getFloatingRank(): not a floating type");
+ switch (T->getAsBuiltinType()->getKind()) {
+ default: assert(0 && "getFloatingRank(): not a floating type");
+ case BuiltinType::Float: return FloatRank;
+ case BuiltinType::Double: return DoubleRank;
+ case BuiltinType::LongDouble: return LongDoubleRank;
+ }
+}
+
+/// getFloatingTypeOfSizeWithinDomain - Returns a real floating
+/// point or a complex type (based on typeDomain/typeSize).
+/// 'typeDomain' is a real floating point or complex type.
+/// 'typeSize' is a real floating point or complex type.
+QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
+ QualType Domain) const {
+ FloatingRank EltRank = getFloatingRank(Size);
+ if (Domain->isComplexType()) {
+ switch (EltRank) {
+ default: assert(0 && "getFloatingRank(): illegal value for rank");
+ case FloatRank: return FloatComplexTy;
+ case DoubleRank: return DoubleComplexTy;
+ case LongDoubleRank: return LongDoubleComplexTy;
+ }
+ }
+
+ assert(Domain->isRealFloatingType() && "Unknown domain!");
+ switch (EltRank) {
+ default: assert(0 && "getFloatingRank(): illegal value for rank");
+ case FloatRank: return FloatTy;
+ case DoubleRank: return DoubleTy;
+ case LongDoubleRank: return LongDoubleTy;
+ }
+}
+
+/// getFloatingTypeOrder - Compare the rank of the two specified floating
+/// point types, ignoring the domain of the type (i.e. 'double' ==
+/// '_Complex double'). If LHS > RHS, return 1. If LHS == RHS, return 0. If
+/// LHS < RHS, return -1.
+int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) {
+ FloatingRank LHSR = getFloatingRank(LHS);
+ FloatingRank RHSR = getFloatingRank(RHS);
+
+ if (LHSR == RHSR)
+ return 0;
+ if (LHSR > RHSR)
+ return 1;
+ return -1;
+}
+
+/// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This
+/// routine will assert if passed a built-in type that isn't an integer or enum,
+/// or if it is not canonicalized.
+unsigned ASTContext::getIntegerRank(Type *T) {
+ assert(T->isCanonical() && "T should be canonicalized");
+ if (EnumType* ET = dyn_cast<EnumType>(T))
+ T = ET->getDecl()->getIntegerType().getTypePtr();
+
+ // There are two things which impact the integer rank: the width, and
+ // the ordering of builtins. The builtin ordering is encoded in the
+ // bottom three bits; the width is encoded in the bits above that.
+ if (FixedWidthIntType* FWIT = dyn_cast<FixedWidthIntType>(T)) {
+ return FWIT->getWidth() << 3;
+ }
+
+ switch (cast<BuiltinType>(T)->getKind()) {
+ default: assert(0 && "getIntegerRank(): not a built-in integer");
+ case BuiltinType::Bool:
+ return 1 + (getIntWidth(BoolTy) << 3);
+ case BuiltinType::Char_S:
+ case BuiltinType::Char_U:
+ case BuiltinType::SChar:
+ case BuiltinType::UChar:
+ return 2 + (getIntWidth(CharTy) << 3);
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ return 3 + (getIntWidth(ShortTy) << 3);
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ return 4 + (getIntWidth(IntTy) << 3);
+ case BuiltinType::Long:
+ case BuiltinType::ULong:
+ return 5 + (getIntWidth(LongTy) << 3);
+ case BuiltinType::LongLong:
+ case BuiltinType::ULongLong:
+ return 6 + (getIntWidth(LongLongTy) << 3);
+ case BuiltinType::Int128:
+ case BuiltinType::UInt128:
+ return 7 + (getIntWidth(Int128Ty) << 3);
+ }
+}
+
+/// getIntegerTypeOrder - Returns the highest ranked integer type:
+/// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If
+/// LHS < RHS, return -1.
+int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) {
+ Type *LHSC = getCanonicalType(LHS).getTypePtr();
+ Type *RHSC = getCanonicalType(RHS).getTypePtr();
+ if (LHSC == RHSC) return 0;
+
+ bool LHSUnsigned = LHSC->isUnsignedIntegerType();
+ bool RHSUnsigned = RHSC->isUnsignedIntegerType();
+
+ unsigned LHSRank = getIntegerRank(LHSC);
+ unsigned RHSRank = getIntegerRank(RHSC);
+
+ if (LHSUnsigned == RHSUnsigned) { // Both signed or both unsigned.
+ if (LHSRank == RHSRank) return 0;
+ return LHSRank > RHSRank ? 1 : -1;
+ }
+
+ // Otherwise, the LHS is signed and the RHS is unsigned or visa versa.
+ if (LHSUnsigned) {
+ // If the unsigned [LHS] type is larger, return it.
+ if (LHSRank >= RHSRank)
+ return 1;
+
+ // If the signed type can represent all values of the unsigned type, it
+ // wins. Because we are dealing with 2's complement and types that are
+ // powers of two larger than each other, this is always safe.
+ return -1;
+ }
+
+ // If the unsigned [RHS] type is larger, return it.
+ if (RHSRank >= LHSRank)
+ return -1;
+
+ // If the signed type can represent all values of the unsigned type, it
+ // wins. Because we are dealing with 2's complement and types that are
+ // powers of two larger than each other, this is always safe.
+ return 1;
+}
+
+// getCFConstantStringType - Return the type used for constant CFStrings.
+QualType ASTContext::getCFConstantStringType() {
+ if (!CFConstantStringTypeDecl) {
+ CFConstantStringTypeDecl =
+ RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get("NSConstantString"));
+ QualType FieldTypes[4];
+
+ // const int *isa;
+ FieldTypes[0] = getPointerType(IntTy.getQualifiedType(QualType::Const));
+ // int flags;
+ FieldTypes[1] = IntTy;
+ // const char *str;
+ FieldTypes[2] = getPointerType(CharTy.getQualifiedType(QualType::Const));
+ // long length;
+ FieldTypes[3] = LongTy;
+
+ // Create fields
+ for (unsigned i = 0; i < 4; ++i) {
+ FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl,
+ SourceLocation(), 0,
+ FieldTypes[i], /*BitWidth=*/0,
+ /*Mutable=*/false);
+ CFConstantStringTypeDecl->addDecl(*this, Field);
+ }
+
+ CFConstantStringTypeDecl->completeDefinition(*this);
+ }
+
+ return getTagDeclType(CFConstantStringTypeDecl);
+}
+
+void ASTContext::setCFConstantStringType(QualType T) {
+ const RecordType *Rec = T->getAsRecordType();
+ assert(Rec && "Invalid CFConstantStringType");
+ CFConstantStringTypeDecl = Rec->getDecl();
+}
+
+QualType ASTContext::getObjCFastEnumerationStateType()
+{
+ if (!ObjCFastEnumerationStateTypeDecl) {
+ ObjCFastEnumerationStateTypeDecl =
+ RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get("__objcFastEnumerationState"));
+
+ QualType FieldTypes[] = {
+ UnsignedLongTy,
+ getPointerType(ObjCIdType),
+ 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(), 0,
+ FieldTypes[i], /*BitWidth=*/0,
+ /*Mutable=*/false);
+ ObjCFastEnumerationStateTypeDecl->addDecl(*this, Field);
+ }
+
+ ObjCFastEnumerationStateTypeDecl->completeDefinition(*this);
+ }
+
+ return getTagDeclType(ObjCFastEnumerationStateTypeDecl);
+}
+
+void ASTContext::setObjCFastEnumerationStateType(QualType T) {
+ const RecordType *Rec = T->getAsRecordType();
+ assert(Rec && "Invalid ObjCFAstEnumerationStateType");
+ ObjCFastEnumerationStateTypeDecl = Rec->getDecl();
+}
+
+// This returns true if a type has been typedefed to BOOL:
+// typedef <type> BOOL;
+static bool isTypeTypedefedAsBOOL(QualType T) {
+ if (const TypedefType *TT = dyn_cast<TypedefType>(T))
+ if (IdentifierInfo *II = TT->getDecl()->getIdentifier())
+ return II->isStr("BOOL");
+
+ return false;
+}
+
+/// getObjCEncodingTypeSize returns size of type for objective-c encoding
+/// purpose.
+int ASTContext::getObjCEncodingTypeSize(QualType type) {
+ uint64_t sz = getTypeSize(type);
+
+ // Make all integer and enum types at least as large as an int
+ if (sz > 0 && type->isIntegralType())
+ sz = std::max(sz, getTypeSize(IntTy));
+ // Treat arrays as pointers, since that's how they're passed in.
+ else if (type->isArrayType())
+ sz = getTypeSize(VoidPtrTy);
+ return sz / getTypeSize(CharTy);
+}
+
+/// getObjCEncodingForMethodDecl - Return the encoded type for this method
+/// declaration.
+void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
+ std::string& S) {
+ // FIXME: This is not very efficient.
+ // Encode type qualifer, 'in', 'inout', etc. for the return type.
+ getObjCEncodingForTypeQualifier(Decl->getObjCDeclQualifier(), S);
+ // Encode result type.
+ getObjCEncodingForType(Decl->getResultType(), S);
+ // Compute size of all parameters.
+ // Start with computing size of a pointer in number of bytes.
+ // FIXME: There might(should) be a better way of doing this computation!
+ SourceLocation Loc;
+ int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy);
+ // The first two arguments (self and _cmd) are pointers; account for
+ // their size.
+ int ParmOffset = 2 * PtrSize;
+ for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
+ E = Decl->param_end(); PI != E; ++PI) {
+ QualType PType = (*PI)->getType();
+ int sz = getObjCEncodingTypeSize(PType);
+ assert (sz > 0 && "getObjCEncodingForMethodDecl - Incomplete param type");
+ ParmOffset += sz;
+ }
+ S += llvm::utostr(ParmOffset);
+ S += "@0:";
+ S += llvm::utostr(PtrSize);
+
+ // Argument types.
+ ParmOffset = 2 * PtrSize;
+ for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
+ E = Decl->param_end(); PI != E; ++PI) {
+ ParmVarDecl *PVDecl = *PI;
+ QualType PType = PVDecl->getOriginalType();
+ if (const ArrayType *AT =
+ dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) {
+ // Use array's original type only if it has known number of
+ // elements.
+ if (!isa<ConstantArrayType>(AT))
+ PType = PVDecl->getType();
+ } else if (PType->isFunctionType())
+ PType = PVDecl->getType();
+ // Process argument qualifiers for user supplied arguments; such as,
+ // 'in', 'inout', etc.
+ getObjCEncodingForTypeQualifier(PVDecl->getObjCDeclQualifier(), S);
+ getObjCEncodingForType(PType, S);
+ S += llvm::utostr(ParmOffset);
+ ParmOffset += getObjCEncodingTypeSize(PType);
+ }
+}
+
+/// getObjCEncodingForPropertyDecl - Return the encoded type for this
+/// property declaration. If non-NULL, Container must be either an
+/// ObjCCategoryImplDecl or ObjCImplementationDecl; it should only be
+/// NULL when getting encodings for protocol properties.
+/// Property attributes are stored as a comma-delimited C string. The simple
+/// attributes readonly and bycopy are encoded as single characters. The
+/// parametrized attributes, getter=name, setter=name, and ivar=name, are
+/// encoded as single characters, followed by an identifier. Property types
+/// are also encoded as a parametrized attribute. The characters used to encode
+/// these attributes are defined by the following enumeration:
+/// @code
+/// enum PropertyAttributes {
+/// kPropertyReadOnly = 'R', // property is read-only.
+/// kPropertyBycopy = 'C', // property is a copy of the value last assigned
+/// kPropertyByref = '&', // property is a reference to the value last assigned
+/// kPropertyDynamic = 'D', // property is dynamic
+/// kPropertyGetter = 'G', // followed by getter selector name
+/// kPropertySetter = 'S', // followed by setter selector name
+/// kPropertyInstanceVariable = 'V' // followed by instance variable name
+/// kPropertyType = 't' // followed by old-style type encoding.
+/// kPropertyWeak = 'W' // 'weak' property
+/// kPropertyStrong = 'P' // property GC'able
+/// kPropertyNonAtomic = 'N' // property non-atomic
+/// };
+/// @endcode
+void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
+ const Decl *Container,
+ std::string& S) {
+ // Collect information from the property implementation decl(s).
+ bool Dynamic = false;
+ ObjCPropertyImplDecl *SynthesizePID = 0;
+
+ // FIXME: Duplicated code due to poor abstraction.
+ if (Container) {
+ if (const ObjCCategoryImplDecl *CID =
+ dyn_cast<ObjCCategoryImplDecl>(Container)) {
+ for (ObjCCategoryImplDecl::propimpl_iterator
+ i = CID->propimpl_begin(*this), e = CID->propimpl_end(*this);
+ i != e; ++i) {
+ ObjCPropertyImplDecl *PID = *i;
+ if (PID->getPropertyDecl() == PD) {
+ if (PID->getPropertyImplementation()==ObjCPropertyImplDecl::Dynamic) {
+ Dynamic = true;
+ } else {
+ SynthesizePID = PID;
+ }
+ }
+ }
+ } else {
+ const ObjCImplementationDecl *OID=cast<ObjCImplementationDecl>(Container);
+ for (ObjCCategoryImplDecl::propimpl_iterator
+ i = OID->propimpl_begin(*this), e = OID->propimpl_end(*this);
+ i != e; ++i) {
+ ObjCPropertyImplDecl *PID = *i;
+ if (PID->getPropertyDecl() == PD) {
+ if (PID->getPropertyImplementation()==ObjCPropertyImplDecl::Dynamic) {
+ Dynamic = true;
+ } else {
+ SynthesizePID = PID;
+ }
+ }
+ }
+ }
+ }
+
+ // FIXME: This is not very efficient.
+ S = "T";
+
+ // Encode result type.
+ // GCC has some special rules regarding encoding of properties which
+ // closely resembles encoding of ivars.
+ getObjCEncodingForTypeImpl(PD->getType(), S, true, true, 0,
+ true /* outermost type */,
+ true /* encoding for property */);
+
+ if (PD->isReadOnly()) {
+ S += ",R";
+ } else {
+ switch (PD->getSetterKind()) {
+ case ObjCPropertyDecl::Assign: break;
+ case ObjCPropertyDecl::Copy: S += ",C"; break;
+ case ObjCPropertyDecl::Retain: S += ",&"; break;
+ }
+ }
+
+ // It really isn't clear at all what this means, since properties
+ // are "dynamic by default".
+ if (Dynamic)
+ S += ",D";
+
+ if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic)
+ S += ",N";
+
+ if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) {
+ S += ",G";
+ S += PD->getGetterName().getAsString();
+ }
+
+ if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) {
+ S += ",S";
+ S += PD->getSetterName().getAsString();
+ }
+
+ if (SynthesizePID) {
+ const ObjCIvarDecl *OID = SynthesizePID->getPropertyIvarDecl();
+ S += ",V";
+ S += OID->getNameAsString();
+ }
+
+ // FIXME: OBJCGC: weak & strong
+}
+
+/// getLegacyIntegralTypeEncoding -
+/// Another legacy compatibility encoding: 32-bit longs are encoded as
+/// 'l' or 'L' , but not always. For typedefs, we need to use
+/// 'i' or 'I' instead if encoding a struct field, or a pointer!
+///
+void ASTContext::getLegacyIntegralTypeEncoding (QualType &PointeeTy) const {
+ if (dyn_cast<TypedefType>(PointeeTy.getTypePtr())) {
+ if (const BuiltinType *BT = PointeeTy->getAsBuiltinType()) {
+ if (BT->getKind() == BuiltinType::ULong &&
+ ((const_cast<ASTContext *>(this))->getIntWidth(PointeeTy) == 32))
+ PointeeTy = UnsignedIntTy;
+ else
+ if (BT->getKind() == BuiltinType::Long &&
+ ((const_cast<ASTContext *>(this))->getIntWidth(PointeeTy) == 32))
+ PointeeTy = IntTy;
+ }
+ }
+}
+
+void ASTContext::getObjCEncodingForType(QualType T, std::string& S,
+ const FieldDecl *Field) {
+ // We follow the behavior of gcc, expanding structures which are
+ // directly pointed to, and expanding embedded structures. Note that
+ // these rules are sufficient to prevent recursive encoding of the
+ // same type.
+ getObjCEncodingForTypeImpl(T, S, true, true, Field,
+ true /* outermost type */);
+}
+
+static void EncodeBitField(const ASTContext *Context, std::string& S,
+ const FieldDecl *FD) {
+ const Expr *E = FD->getBitWidth();
+ assert(E && "bitfield width not there - getObjCEncodingForTypeImpl");
+ ASTContext *Ctx = const_cast<ASTContext*>(Context);
+ unsigned N = E->EvaluateAsInt(*Ctx).getZExtValue();
+ S += 'b';
+ S += llvm::utostr(N);
+}
+
+void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
+ bool ExpandPointedToStructures,
+ bool ExpandStructures,
+ const FieldDecl *FD,
+ bool OutermostType,
+ bool EncodingProperty) {
+ if (const BuiltinType *BT = T->getAsBuiltinType()) {
+ if (FD && FD->isBitField()) {
+ EncodeBitField(this, S, FD);
+ }
+ else {
+ char encoding;
+ switch (BT->getKind()) {
+ default: assert(0 && "Unhandled builtin type kind");
+ case BuiltinType::Void: encoding = 'v'; break;
+ case BuiltinType::Bool: encoding = 'B'; break;
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar: encoding = 'C'; break;
+ case BuiltinType::UShort: encoding = 'S'; break;
+ case BuiltinType::UInt: encoding = 'I'; break;
+ case BuiltinType::ULong:
+ encoding =
+ (const_cast<ASTContext *>(this))->getIntWidth(T) == 32 ? 'L' : 'Q';
+ break;
+ case BuiltinType::UInt128: encoding = 'T'; break;
+ case BuiltinType::ULongLong: encoding = 'Q'; break;
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar: encoding = 'c'; break;
+ case BuiltinType::Short: encoding = 's'; break;
+ case BuiltinType::Int: encoding = 'i'; break;
+ case BuiltinType::Long:
+ encoding =
+ (const_cast<ASTContext *>(this))->getIntWidth(T) == 32 ? 'l' : 'q';
+ break;
+ case BuiltinType::LongLong: encoding = 'q'; break;
+ case BuiltinType::Int128: encoding = 't'; break;
+ case BuiltinType::Float: encoding = 'f'; break;
+ case BuiltinType::Double: encoding = 'd'; break;
+ case BuiltinType::LongDouble: encoding = 'd'; break;
+ }
+
+ S += encoding;
+ }
+ } else if (const ComplexType *CT = T->getAsComplexType()) {
+ S += 'j';
+ getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false,
+ false);
+ } else if (T->isObjCQualifiedIdType()) {
+ getObjCEncodingForTypeImpl(getObjCIdType(), S,
+ ExpandPointedToStructures,
+ ExpandStructures, FD);
+ if (FD || EncodingProperty) {
+ // Note that we do extended encoding of protocol qualifer list
+ // Only when doing ivar or property encoding.
+ const ObjCQualifiedIdType *QIDT = T->getAsObjCQualifiedIdType();
+ S += '"';
+ for (ObjCQualifiedIdType::qual_iterator I = QIDT->qual_begin(),
+ E = QIDT->qual_end(); I != E; ++I) {
+ S += '<';
+ S += (*I)->getNameAsString();
+ S += '>';
+ }
+ S += '"';
+ }
+ return;
+ }
+ else if (const PointerType *PT = T->getAsPointerType()) {
+ QualType PointeeTy = PT->getPointeeType();
+ bool isReadOnly = false;
+ // For historical/compatibility reasons, the read-only qualifier of the
+ // pointee gets emitted _before_ the '^'. The read-only qualifier of
+ // the pointer itself gets ignored, _unless_ we are looking at a typedef!
+ // Also, do not emit the 'r' for anything but the outermost type!
+ if (dyn_cast<TypedefType>(T.getTypePtr())) {
+ if (OutermostType && T.isConstQualified()) {
+ isReadOnly = true;
+ S += 'r';
+ }
+ }
+ else if (OutermostType) {
+ QualType P = PointeeTy;
+ while (P->getAsPointerType())
+ P = P->getAsPointerType()->getPointeeType();
+ if (P.isConstQualified()) {
+ isReadOnly = true;
+ S += 'r';
+ }
+ }
+ if (isReadOnly) {
+ // Another legacy compatibility encoding. Some ObjC qualifier and type
+ // combinations need to be rearranged.
+ // Rewrite "in const" from "nr" to "rn"
+ const char * s = S.c_str();
+ int len = S.length();
+ if (len >= 2 && s[len-2] == 'n' && s[len-1] == 'r') {
+ std::string replace = "rn";
+ S.replace(S.end()-2, S.end(), replace);
+ }
+ }
+ if (isObjCIdStructType(PointeeTy)) {
+ S += '@';
+ return;
+ }
+ else if (PointeeTy->isObjCInterfaceType()) {
+ if (!EncodingProperty &&
+ isa<TypedefType>(PointeeTy.getTypePtr())) {
+ // Another historical/compatibility reason.
+ // We encode the underlying type which comes out as
+ // {...};
+ S += '^';
+ getObjCEncodingForTypeImpl(PointeeTy, S,
+ false, ExpandPointedToStructures,
+ NULL);
+ return;
+ }
+ S += '@';
+ if (FD || EncodingProperty) {
+ const ObjCInterfaceType *OIT =
+ PointeeTy.getUnqualifiedType()->getAsObjCInterfaceType();
+ ObjCInterfaceDecl *OI = OIT->getDecl();
+ S += '"';
+ S += OI->getNameAsCString();
+ for (ObjCInterfaceType::qual_iterator I = OIT->qual_begin(),
+ E = OIT->qual_end(); I != E; ++I) {
+ S += '<';
+ S += (*I)->getNameAsString();
+ S += '>';
+ }
+ S += '"';
+ }
+ return;
+ } else if (isObjCClassStructType(PointeeTy)) {
+ S += '#';
+ return;
+ } else if (isObjCSelType(PointeeTy)) {
+ S += ':';
+ return;
+ }
+
+ if (PointeeTy->isCharType()) {
+ // char pointer types should be encoded as '*' unless it is a
+ // type that has been typedef'd to 'BOOL'.
+ if (!isTypeTypedefedAsBOOL(PointeeTy)) {
+ S += '*';
+ return;
+ }
+ }
+
+ S += '^';
+ getLegacyIntegralTypeEncoding(PointeeTy);
+
+ getObjCEncodingForTypeImpl(PointeeTy, S,
+ false, ExpandPointedToStructures,
+ NULL);
+ } else if (const ArrayType *AT =
+ // Ignore type qualifiers etc.
+ dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) {
+ if (isa<IncompleteArrayType>(AT)) {
+ // Incomplete arrays are encoded as a pointer to the array element.
+ S += '^';
+
+ getObjCEncodingForTypeImpl(AT->getElementType(), S,
+ false, ExpandStructures, FD);
+ } else {
+ S += '[';
+
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
+ S += llvm::utostr(CAT->getSize().getZExtValue());
+ else {
+ //Variable length arrays are encoded as a regular array with 0 elements.
+ assert(isa<VariableArrayType>(AT) && "Unknown array type!");
+ S += '0';
+ }
+
+ getObjCEncodingForTypeImpl(AT->getElementType(), S,
+ false, ExpandStructures, FD);
+ S += ']';
+ }
+ } else if (T->getAsFunctionType()) {
+ S += '?';
+ } else if (const RecordType *RTy = T->getAsRecordType()) {
+ RecordDecl *RDecl = RTy->getDecl();
+ S += RDecl->isUnion() ? '(' : '{';
+ // Anonymous structures print as '?'
+ if (const IdentifierInfo *II = RDecl->getIdentifier()) {
+ S += II->getName();
+ } else {
+ S += '?';
+ }
+ if (ExpandStructures) {
+ S += '=';
+ for (RecordDecl::field_iterator Field = RDecl->field_begin(*this),
+ FieldEnd = RDecl->field_end(*this);
+ Field != FieldEnd; ++Field) {
+ if (FD) {
+ S += '"';
+ S += Field->getNameAsString();
+ S += '"';
+ }
+
+ // Special case bit-fields.
+ if (Field->isBitField()) {
+ getObjCEncodingForTypeImpl(Field->getType(), S, false, true,
+ (*Field));
+ } else {
+ QualType qt = Field->getType();
+ getLegacyIntegralTypeEncoding(qt);
+ getObjCEncodingForTypeImpl(qt, S, false, true,
+ FD);
+ }
+ }
+ }
+ S += RDecl->isUnion() ? ')' : '}';
+ } else if (T->isEnumeralType()) {
+ if (FD && FD->isBitField())
+ EncodeBitField(this, S, FD);
+ else
+ S += 'i';
+ } else if (T->isBlockPointerType()) {
+ S += "@?"; // Unlike a pointer-to-function, which is "^?".
+ } else if (T->isObjCInterfaceType()) {
+ // @encode(class_name)
+ ObjCInterfaceDecl *OI = T->getAsObjCInterfaceType()->getDecl();
+ S += '{';
+ const IdentifierInfo *II = OI->getIdentifier();
+ S += II->getName();
+ S += '=';
+ llvm::SmallVector<FieldDecl*, 32> RecFields;
+ CollectObjCIvars(OI, RecFields);
+ for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
+ if (RecFields[i]->isBitField())
+ getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true,
+ RecFields[i]);
+ else
+ getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true,
+ FD);
+ }
+ S += '}';
+ }
+ else
+ assert(0 && "@encode for type not implemented!");
+}
+
+void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
+ std::string& S) const {
+ if (QT & Decl::OBJC_TQ_In)
+ S += 'n';
+ if (QT & Decl::OBJC_TQ_Inout)
+ S += 'N';
+ if (QT & Decl::OBJC_TQ_Out)
+ S += 'o';
+ if (QT & Decl::OBJC_TQ_Bycopy)
+ S += 'O';
+ if (QT & Decl::OBJC_TQ_Byref)
+ S += 'R';
+ if (QT & Decl::OBJC_TQ_Oneway)
+ S += 'V';
+}
+
+void ASTContext::setBuiltinVaListType(QualType T)
+{
+ assert(BuiltinVaListType.isNull() && "__builtin_va_list type already set!");
+
+ BuiltinVaListType = T;
+}
+
+void ASTContext::setObjCIdType(QualType T)
+{
+ ObjCIdType = T;
+
+ const TypedefType *TT = T->getAsTypedefType();
+ if (!TT)
+ return;
+
+ TypedefDecl *TD = TT->getDecl();
+
+ // typedef struct objc_object *id;
+ const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType();
+ // User error - caller will issue diagnostics.
+ if (!ptr)
+ return;
+ const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
+ // User error - caller will issue diagnostics.
+ if (!rec)
+ return;
+ IdStructType = rec;
+}
+
+void ASTContext::setObjCSelType(QualType T)
+{
+ ObjCSelType = T;
+
+ const TypedefType *TT = T->getAsTypedefType();
+ if (!TT)
+ return;
+ TypedefDecl *TD = TT->getDecl();
+
+ // typedef struct objc_selector *SEL;
+ const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType();
+ if (!ptr)
+ return;
+ const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
+ if (!rec)
+ return;
+ SelStructType = rec;
+}
+
+void ASTContext::setObjCProtoType(QualType QT)
+{
+ ObjCProtoType = QT;
+}
+
+void ASTContext::setObjCClassType(QualType T)
+{
+ ObjCClassType = T;
+
+ const TypedefType *TT = T->getAsTypedefType();
+ if (!TT)
+ return;
+ TypedefDecl *TD = TT->getDecl();
+
+ // typedef struct objc_class *Class;
+ const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType();
+ assert(ptr && "'Class' incorrectly typed");
+ const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
+ assert(rec && "'Class' incorrectly typed");
+ ClassStructType = rec;
+}
+
+void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) {
+ assert(ObjCConstantStringType.isNull() &&
+ "'NSConstantString' type already set!");
+
+ ObjCConstantStringType = getObjCInterfaceType(Decl);
+}
+
+/// \brief Retrieve the template name that represents a qualified
+/// template name such as \c std::vector.
+TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
+ bool TemplateKeyword,
+ TemplateDecl *Template) {
+ llvm::FoldingSetNodeID ID;
+ QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template);
+
+ void *InsertPos = 0;
+ QualifiedTemplateName *QTN =
+ QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
+ if (!QTN) {
+ QTN = new (*this,4) QualifiedTemplateName(NNS, TemplateKeyword, Template);
+ QualifiedTemplateNames.InsertNode(QTN, InsertPos);
+ }
+
+ return TemplateName(QTN);
+}
+
+/// \brief Retrieve the template name that represents a dependent
+/// template name such as \c MetaFun::template apply.
+TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name) {
+ assert(NNS->isDependent() && "Nested name specifier must be dependent");
+
+ llvm::FoldingSetNodeID ID;
+ DependentTemplateName::Profile(ID, NNS, Name);
+
+ void *InsertPos = 0;
+ DependentTemplateName *QTN =
+ DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (QTN)
+ return TemplateName(QTN);
+
+ NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
+ if (CanonNNS == NNS) {
+ QTN = new (*this,4) DependentTemplateName(NNS, Name);
+ } else {
+ TemplateName Canon = getDependentTemplateName(CanonNNS, Name);
+ QTN = new (*this,4) DependentTemplateName(NNS, Name, Canon);
+ }
+
+ DependentTemplateNames.InsertNode(QTN, InsertPos);
+ return TemplateName(QTN);
+}
+
+/// getFromTargetType - Given one of the integer types provided by
+/// TargetInfo, produce the corresponding type. The unsigned @p Type
+/// is actually a value of type @c TargetInfo::IntType.
+QualType ASTContext::getFromTargetType(unsigned Type) const {
+ switch (Type) {
+ case TargetInfo::NoInt: return QualType();
+ case TargetInfo::SignedShort: return ShortTy;
+ case TargetInfo::UnsignedShort: return UnsignedShortTy;
+ case TargetInfo::SignedInt: return IntTy;
+ case TargetInfo::UnsignedInt: return UnsignedIntTy;
+ case TargetInfo::SignedLong: return LongTy;
+ case TargetInfo::UnsignedLong: return UnsignedLongTy;
+ case TargetInfo::SignedLongLong: return LongLongTy;
+ case TargetInfo::UnsignedLongLong: return UnsignedLongLongTy;
+ }
+
+ assert(false && "Unhandled TargetInfo::IntType value");
+ return QualType();
+}
+
+//===----------------------------------------------------------------------===//
+// Type Predicates.
+//===----------------------------------------------------------------------===//
+
+/// isObjCNSObjectType - Return true if this is an NSObject object using
+/// NSObject attribute on a c-style pointer type.
+/// FIXME - Make it work directly on types.
+///
+bool ASTContext::isObjCNSObjectType(QualType Ty) const {
+ if (TypedefType *TDT = dyn_cast<TypedefType>(Ty)) {
+ if (TypedefDecl *TD = TDT->getDecl())
+ if (TD->getAttr<ObjCNSObjectAttr>())
+ return true;
+ }
+ return false;
+}
+
+/// isObjCObjectPointerType - Returns true if type is an Objective-C pointer
+/// to an object type. This includes "id" and "Class" (two 'special' pointers
+/// to struct), Interface* (pointer to ObjCInterfaceType) and id<P> (qualified
+/// ID type).
+bool ASTContext::isObjCObjectPointerType(QualType Ty) const {
+ if (Ty->isObjCQualifiedIdType())
+ return true;
+
+ // Blocks are objects.
+ if (Ty->isBlockPointerType())
+ return true;
+
+ // All other object types are pointers.
+ const PointerType *PT = Ty->getAsPointerType();
+ if (PT == 0)
+ return false;
+
+ // If this a pointer to an interface (e.g. NSString*), it is ok.
+ if (PT->getPointeeType()->isObjCInterfaceType() ||
+ // If is has NSObject attribute, OK as well.
+ isObjCNSObjectType(Ty))
+ return true;
+
+ // Check to see if this is 'id' or 'Class', both of which are typedefs for
+ // pointer types. This looks for the typedef specifically, not for the
+ // underlying type. Iteratively strip off typedefs so that we can handle
+ // typedefs of typedefs.
+ while (TypedefType *TDT = dyn_cast<TypedefType>(Ty)) {
+ if (Ty.getUnqualifiedType() == getObjCIdType() ||
+ Ty.getUnqualifiedType() == getObjCClassType())
+ return true;
+
+ Ty = TDT->getDecl()->getUnderlyingType();
+ }
+
+ return false;
+}
+
+/// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's
+/// garbage collection attribute.
+///
+QualType::GCAttrTypes ASTContext::getObjCGCAttrKind(const QualType &Ty) const {
+ QualType::GCAttrTypes GCAttrs = QualType::GCNone;
+ if (getLangOptions().ObjC1 &&
+ getLangOptions().getGCMode() != LangOptions::NonGC) {
+ GCAttrs = Ty.getObjCGCAttr();
+ // Default behavious under objective-c's gc is for objective-c pointers
+ // (or pointers to them) be treated as though they were declared
+ // as __strong.
+ if (GCAttrs == QualType::GCNone) {
+ if (isObjCObjectPointerType(Ty))
+ GCAttrs = QualType::Strong;
+ else if (Ty->isPointerType())
+ return getObjCGCAttrKind(Ty->getAsPointerType()->getPointeeType());
+ }
+ // Non-pointers have none gc'able attribute regardless of the attribute
+ // set on them.
+ else if (!isObjCObjectPointerType(Ty) && !Ty->isPointerType())
+ return QualType::GCNone;
+ }
+ return GCAttrs;
+}
+
+//===----------------------------------------------------------------------===//
+// Type Compatibility Testing
+//===----------------------------------------------------------------------===//
+
+/// typesAreBlockCompatible - This routine is called when comparing two
+/// block types. Types must be strictly compatible here. For example,
+/// C unfortunately doesn't produce an error for the following:
+///
+/// int (*emptyArgFunc)();
+/// int (*intArgList)(int) = emptyArgFunc;
+///
+/// For blocks, we will produce an error for the following (similar to C++):
+///
+/// int (^emptyArgBlock)();
+/// int (^intArgBlock)(int) = emptyArgBlock;
+///
+/// FIXME: When the dust settles on this integration, fold this into mergeTypes.
+///
+bool ASTContext::typesAreBlockCompatible(QualType lhs, QualType rhs) {
+ const FunctionType *lbase = lhs->getAsFunctionType();
+ const FunctionType *rbase = rhs->getAsFunctionType();
+ const FunctionProtoType *lproto = dyn_cast<FunctionProtoType>(lbase);
+ const FunctionProtoType *rproto = dyn_cast<FunctionProtoType>(rbase);
+ if (lproto && rproto == 0)
+ return false;
+ return !mergeTypes(lhs, rhs).isNull();
+}
+
+/// areCompatVectorTypes - Return true if the two specified vector types are
+/// compatible.
+static bool areCompatVectorTypes(const VectorType *LHS,
+ const VectorType *RHS) {
+ assert(LHS->isCanonical() && RHS->isCanonical());
+ return LHS->getElementType() == RHS->getElementType() &&
+ LHS->getNumElements() == RHS->getNumElements();
+}
+
+/// canAssignObjCInterfaces - Return true if the two interface types are
+/// compatible for assignment from RHS to LHS. This handles validation of any
+/// protocol qualifiers on the LHS or RHS.
+///
+bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
+ const ObjCInterfaceType *RHS) {
+ // Verify that the base decls are compatible: the RHS must be a subclass of
+ // the LHS.
+ if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
+ return false;
+
+ // RHS must have a superset of the protocols in the LHS. If the LHS is not
+ // protocol qualified at all, then we are good.
+ if (!isa<ObjCQualifiedInterfaceType>(LHS))
+ return true;
+
+ // Okay, we know the LHS has protocol qualifiers. If the RHS doesn't, then it
+ // isn't a superset.
+ if (!isa<ObjCQualifiedInterfaceType>(RHS))
+ return true; // FIXME: should return false!
+
+ // Finally, we must have two protocol-qualified interfaces.
+ const ObjCQualifiedInterfaceType *LHSP =cast<ObjCQualifiedInterfaceType>(LHS);
+ const ObjCQualifiedInterfaceType *RHSP =cast<ObjCQualifiedInterfaceType>(RHS);
+
+ // All LHS protocols must have a presence on the RHS.
+ assert(LHSP->qual_begin() != LHSP->qual_end() && "Empty LHS protocol list?");
+
+ for (ObjCQualifiedInterfaceType::qual_iterator LHSPI = LHSP->qual_begin(),
+ LHSPE = LHSP->qual_end();
+ LHSPI != LHSPE; LHSPI++) {
+ bool RHSImplementsProtocol = false;
+
+ // If the RHS doesn't implement the protocol on the left, the types
+ // are incompatible.
+ for (ObjCQualifiedInterfaceType::qual_iterator RHSPI = RHSP->qual_begin(),
+ RHSPE = RHSP->qual_end();
+ !RHSImplementsProtocol && (RHSPI != RHSPE); RHSPI++) {
+ if ((*RHSPI)->lookupProtocolNamed((*LHSPI)->getIdentifier()))
+ RHSImplementsProtocol = true;
+ }
+ // FIXME: For better diagnostics, consider passing back the protocol name.
+ if (!RHSImplementsProtocol)
+ return false;
+ }
+ // The RHS implements all protocols listed on the LHS.
+ return true;
+}
+
+bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) {
+ // get the "pointed to" types
+ const PointerType *LHSPT = LHS->getAsPointerType();
+ const PointerType *RHSPT = RHS->getAsPointerType();
+
+ if (!LHSPT || !RHSPT)
+ return false;
+
+ QualType lhptee = LHSPT->getPointeeType();
+ QualType rhptee = RHSPT->getPointeeType();
+ const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType();
+ const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType();
+ // ID acts sort of like void* for ObjC interfaces
+ if (LHSIface && isObjCIdStructType(rhptee))
+ return true;
+ if (RHSIface && isObjCIdStructType(lhptee))
+ return true;
+ if (!LHSIface || !RHSIface)
+ return false;
+ return canAssignObjCInterfaces(LHSIface, RHSIface) ||
+ canAssignObjCInterfaces(RHSIface, LHSIface);
+}
+
+/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible,
+/// both shall have the identically qualified version of a compatible type.
+/// C99 6.2.7p1: Two types have compatible types if their types are the
+/// same. See 6.7.[2,3,5] for additional rules.
+bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) {
+ return !mergeTypes(LHS, RHS).isNull();
+}
+
+QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
+ const FunctionType *lbase = lhs->getAsFunctionType();
+ const FunctionType *rbase = rhs->getAsFunctionType();
+ const FunctionProtoType *lproto = dyn_cast<FunctionProtoType>(lbase);
+ const FunctionProtoType *rproto = dyn_cast<FunctionProtoType>(rbase);
+ bool allLTypes = true;
+ bool allRTypes = true;
+
+ // Check return type
+ QualType retType = mergeTypes(lbase->getResultType(), rbase->getResultType());
+ if (retType.isNull()) return QualType();
+ if (getCanonicalType(retType) != getCanonicalType(lbase->getResultType()))
+ allLTypes = false;
+ if (getCanonicalType(retType) != getCanonicalType(rbase->getResultType()))
+ allRTypes = false;
+
+ if (lproto && rproto) { // two C99 style function prototypes
+ assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() &&
+ "C++ shouldn't be here");
+ unsigned lproto_nargs = lproto->getNumArgs();
+ unsigned rproto_nargs = rproto->getNumArgs();
+
+ // Compatible functions must have the same number of arguments
+ if (lproto_nargs != rproto_nargs)
+ return QualType();
+
+ // Variadic and non-variadic functions aren't compatible
+ if (lproto->isVariadic() != rproto->isVariadic())
+ return QualType();
+
+ if (lproto->getTypeQuals() != rproto->getTypeQuals())
+ return QualType();
+
+ // Check argument compatibility
+ llvm::SmallVector<QualType, 10> types;
+ for (unsigned i = 0; i < lproto_nargs; i++) {
+ QualType largtype = lproto->getArgType(i).getUnqualifiedType();
+ QualType rargtype = rproto->getArgType(i).getUnqualifiedType();
+ QualType argtype = mergeTypes(largtype, rargtype);
+ if (argtype.isNull()) return QualType();
+ types.push_back(argtype);
+ if (getCanonicalType(argtype) != getCanonicalType(largtype))
+ allLTypes = false;
+ if (getCanonicalType(argtype) != getCanonicalType(rargtype))
+ allRTypes = false;
+ }
+ if (allLTypes) return lhs;
+ if (allRTypes) return rhs;
+ return getFunctionType(retType, types.begin(), types.size(),
+ lproto->isVariadic(), lproto->getTypeQuals());
+ }
+
+ if (lproto) allRTypes = false;
+ if (rproto) allLTypes = false;
+
+ const FunctionProtoType *proto = lproto ? lproto : rproto;
+ if (proto) {
+ assert(!proto->hasExceptionSpec() && "C++ shouldn't be here");
+ if (proto->isVariadic()) return QualType();
+ // Check that the types are compatible with the types that
+ // would result from default argument promotions (C99 6.7.5.3p15).
+ // The only types actually affected are promotable integer
+ // types and floats, which would be passed as a different
+ // type depending on whether the prototype is visible.
+ unsigned proto_nargs = proto->getNumArgs();
+ for (unsigned i = 0; i < proto_nargs; ++i) {
+ QualType argTy = proto->getArgType(i);
+ if (argTy->isPromotableIntegerType() ||
+ getCanonicalType(argTy).getUnqualifiedType() == FloatTy)
+ return QualType();
+ }
+
+ if (allLTypes) return lhs;
+ if (allRTypes) return rhs;
+ return getFunctionType(retType, proto->arg_type_begin(),
+ proto->getNumArgs(), lproto->isVariadic(),
+ lproto->getTypeQuals());
+ }
+
+ if (allLTypes) return lhs;
+ if (allRTypes) return rhs;
+ return getFunctionNoProtoType(retType);
+}
+
+QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
+ // C++ [expr]: If an expression initially has the type "reference to T", the
+ // type is adjusted to "T" prior to any further analysis, the expression
+ // designates the object or function denoted by the reference, and the
+ // expression is an lvalue unless the reference is an rvalue reference and
+ // the expression is a function call (possibly inside parentheses).
+ // FIXME: C++ shouldn't be going through here! The rules are different
+ // enough that they should be handled separately.
+ // FIXME: Merging of lvalue and rvalue references is incorrect. C++ *really*
+ // shouldn't be going through here!
+ if (const ReferenceType *RT = LHS->getAsReferenceType())
+ LHS = RT->getPointeeType();
+ if (const ReferenceType *RT = RHS->getAsReferenceType())
+ RHS = RT->getPointeeType();
+
+ QualType LHSCan = getCanonicalType(LHS),
+ RHSCan = getCanonicalType(RHS);
+
+ // If two types are identical, they are compatible.
+ if (LHSCan == RHSCan)
+ return LHS;
+
+ // If the qualifiers are different, the types aren't compatible
+ // Note that we handle extended qualifiers later, in the
+ // case for ExtQualType.
+ if (LHSCan.getCVRQualifiers() != RHSCan.getCVRQualifiers())
+ return QualType();
+
+ Type::TypeClass LHSClass = LHSCan->getTypeClass();
+ Type::TypeClass RHSClass = RHSCan->getTypeClass();
+
+ // We want to consider the two function types to be the same for these
+ // comparisons, just force one to the other.
+ if (LHSClass == Type::FunctionProto) LHSClass = Type::FunctionNoProto;
+ if (RHSClass == Type::FunctionProto) RHSClass = Type::FunctionNoProto;
+
+ // Strip off objc_gc attributes off the top level so they can be merged.
+ // This is a complete mess, but the attribute itself doesn't make much sense.
+ if (RHSClass == Type::ExtQual) {
+ QualType::GCAttrTypes GCAttr = RHSCan.getObjCGCAttr();
+ if (GCAttr != QualType::GCNone) {
+ RHS = QualType(cast<ExtQualType>(RHS.getDesugaredType())->getBaseType(),
+ RHS.getCVRQualifiers());
+ QualType Result = mergeTypes(LHS, RHS);
+ if (Result.getObjCGCAttr() == QualType::GCNone)
+ Result = getObjCGCQualType(Result, GCAttr);
+ else if (Result.getObjCGCAttr() != GCAttr)
+ Result = QualType();
+ return Result;
+ }
+ }
+ if (LHSClass == Type::ExtQual) {
+ QualType::GCAttrTypes GCAttr = LHSCan.getObjCGCAttr();
+ if (GCAttr != QualType::GCNone) {
+ LHS = QualType(cast<ExtQualType>(LHS.getDesugaredType())->getBaseType(),
+ LHS.getCVRQualifiers());
+ QualType Result = mergeTypes(LHS, RHS);
+ if (Result.getObjCGCAttr() == QualType::GCNone)
+ Result = getObjCGCQualType(Result, GCAttr);
+ else if (Result.getObjCGCAttr() != GCAttr)
+ Result = QualType();
+ return Result;
+ }
+ }
+
+ // Same as above for arrays
+ if (LHSClass == Type::VariableArray || LHSClass == Type::IncompleteArray)
+ LHSClass = Type::ConstantArray;
+ if (RHSClass == Type::VariableArray || RHSClass == Type::IncompleteArray)
+ RHSClass = Type::ConstantArray;
+
+ // Canonicalize ExtVector -> Vector.
+ if (LHSClass == Type::ExtVector) LHSClass = Type::Vector;
+ if (RHSClass == Type::ExtVector) RHSClass = Type::Vector;
+
+ // Consider qualified interfaces and interfaces the same.
+ if (LHSClass == Type::ObjCQualifiedInterface) LHSClass = Type::ObjCInterface;
+ if (RHSClass == Type::ObjCQualifiedInterface) RHSClass = Type::ObjCInterface;
+
+ // If the canonical type classes don't match.
+ if (LHSClass != RHSClass) {
+ const ObjCInterfaceType* LHSIface = LHS->getAsObjCInterfaceType();
+ const ObjCInterfaceType* RHSIface = RHS->getAsObjCInterfaceType();
+
+ // 'id' and 'Class' act sort of like void* for ObjC interfaces
+ if (LHSIface && (isObjCIdStructType(RHS) || isObjCClassStructType(RHS)))
+ return LHS;
+ if (RHSIface && (isObjCIdStructType(LHS) || isObjCClassStructType(LHS)))
+ return RHS;
+
+ // ID is compatible with all qualified id types.
+ if (LHS->isObjCQualifiedIdType()) {
+ if (const PointerType *PT = RHS->getAsPointerType()) {
+ QualType pType = PT->getPointeeType();
+ if (isObjCIdStructType(pType) || isObjCClassStructType(pType))
+ return LHS;
+ // FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true).
+ // Unfortunately, this API is part of Sema (which we don't have access
+ // to. Need to refactor. The following check is insufficient, since we
+ // need to make sure the class implements the protocol.
+ if (pType->isObjCInterfaceType())
+ return LHS;
+ }
+ }
+ if (RHS->isObjCQualifiedIdType()) {
+ if (const PointerType *PT = LHS->getAsPointerType()) {
+ QualType pType = PT->getPointeeType();
+ if (isObjCIdStructType(pType) || isObjCClassStructType(pType))
+ return RHS;
+ // FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true).
+ // Unfortunately, this API is part of Sema (which we don't have access
+ // to. Need to refactor. The following check is insufficient, since we
+ // need to make sure the class implements the protocol.
+ if (pType->isObjCInterfaceType())
+ return RHS;
+ }
+ }
+ // C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
+ // a signed integer type, or an unsigned integer type.
+ if (const EnumType* ETy = LHS->getAsEnumType()) {
+ if (ETy->getDecl()->getIntegerType() == RHSCan.getUnqualifiedType())
+ return RHS;
+ }
+ if (const EnumType* ETy = RHS->getAsEnumType()) {
+ if (ETy->getDecl()->getIntegerType() == LHSCan.getUnqualifiedType())
+ return LHS;
+ }
+
+ return QualType();
+ }
+
+ // The canonical type classes match.
+ switch (LHSClass) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#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();
+
+ case Type::LValueReference:
+ case Type::RValueReference:
+ case Type::MemberPointer:
+ assert(false && "C++ should never be in mergeTypes");
+ return QualType();
+
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::FunctionProto:
+ case Type::ExtVector:
+ case Type::ObjCQualifiedInterface:
+ assert(false && "Types are eliminated above");
+ return QualType();
+
+ case Type::Pointer:
+ {
+ // Merge two pointer types, while trying to preserve typedef info
+ QualType LHSPointee = LHS->getAsPointerType()->getPointeeType();
+ QualType RHSPointee = RHS->getAsPointerType()->getPointeeType();
+ QualType ResultType = mergeTypes(LHSPointee, RHSPointee);
+ if (ResultType.isNull()) return QualType();
+ if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType))
+ return LHS;
+ if (getCanonicalType(RHSPointee) == getCanonicalType(ResultType))
+ return RHS;
+ return getPointerType(ResultType);
+ }
+ case Type::BlockPointer:
+ {
+ // Merge two block pointer types, while trying to preserve typedef info
+ QualType LHSPointee = LHS->getAsBlockPointerType()->getPointeeType();
+ QualType RHSPointee = RHS->getAsBlockPointerType()->getPointeeType();
+ QualType ResultType = mergeTypes(LHSPointee, RHSPointee);
+ if (ResultType.isNull()) return QualType();
+ if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType))
+ return LHS;
+ if (getCanonicalType(RHSPointee) == getCanonicalType(ResultType))
+ return RHS;
+ return getBlockPointerType(ResultType);
+ }
+ case Type::ConstantArray:
+ {
+ const ConstantArrayType* LCAT = getAsConstantArrayType(LHS);
+ const ConstantArrayType* RCAT = getAsConstantArrayType(RHS);
+ if (LCAT && RCAT && RCAT->getSize() != LCAT->getSize())
+ return QualType();
+
+ QualType LHSElem = getAsArrayType(LHS)->getElementType();
+ QualType RHSElem = getAsArrayType(RHS)->getElementType();
+ QualType ResultType = mergeTypes(LHSElem, RHSElem);
+ if (ResultType.isNull()) return QualType();
+ if (LCAT && getCanonicalType(LHSElem) == getCanonicalType(ResultType))
+ return LHS;
+ if (RCAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType))
+ return RHS;
+ if (LCAT) return getConstantArrayType(ResultType, LCAT->getSize(),
+ ArrayType::ArraySizeModifier(), 0);
+ if (RCAT) return getConstantArrayType(ResultType, RCAT->getSize(),
+ ArrayType::ArraySizeModifier(), 0);
+ const VariableArrayType* LVAT = getAsVariableArrayType(LHS);
+ const VariableArrayType* RVAT = getAsVariableArrayType(RHS);
+ if (LVAT && getCanonicalType(LHSElem) == getCanonicalType(ResultType))
+ return LHS;
+ if (RVAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType))
+ return RHS;
+ if (LVAT) {
+ // FIXME: This isn't correct! But tricky to implement because
+ // the array's size has to be the size of LHS, but the type
+ // has to be different.
+ return LHS;
+ }
+ if (RVAT) {
+ // FIXME: This isn't correct! But tricky to implement because
+ // the array's size has to be the size of RHS, but the type
+ // has to be different.
+ return RHS;
+ }
+ if (getCanonicalType(LHSElem) == getCanonicalType(ResultType)) return LHS;
+ if (getCanonicalType(RHSElem) == getCanonicalType(ResultType)) return RHS;
+ return getIncompleteArrayType(ResultType, ArrayType::ArraySizeModifier(),0);
+ }
+ case Type::FunctionNoProto:
+ return mergeFunctionTypes(LHS, RHS);
+ case Type::Record:
+ case Type::Enum:
+ // FIXME: Why are these compatible?
+ if (isObjCIdStructType(LHS) && isObjCClassStructType(RHS)) return LHS;
+ if (isObjCClassStructType(LHS) && isObjCIdStructType(RHS)) return LHS;
+ return QualType();
+ case Type::Builtin:
+ // Only exactly equal builtin types are compatible, which is tested above.
+ return QualType();
+ case Type::Complex:
+ // Distinct complex types are incompatible.
+ return QualType();
+ case Type::Vector:
+ // FIXME: The merged type should be an ExtVector!
+ if (areCompatVectorTypes(LHS->getAsVectorType(), RHS->getAsVectorType()))
+ return LHS;
+ return QualType();
+ case Type::ObjCInterface: {
+ // Check if the interfaces are assignment compatible.
+ // FIXME: This should be type compatibility, e.g. whether
+ // "LHS x; RHS x;" at global scope is legal.
+ const ObjCInterfaceType* LHSIface = LHS->getAsObjCInterfaceType();
+ const ObjCInterfaceType* RHSIface = RHS->getAsObjCInterfaceType();
+ if (LHSIface && RHSIface &&
+ canAssignObjCInterfaces(LHSIface, RHSIface))
+ return LHS;
+
+ return QualType();
+ }
+ case Type::ObjCQualifiedId:
+ // Distinct qualified id's are not compatible.
+ return QualType();
+ case Type::FixedWidthInt:
+ // Distinct fixed-width integers are not compatible.
+ return QualType();
+ case Type::ExtQual:
+ // FIXME: ExtQual types can be compatible even if they're not
+ // identical!
+ return QualType();
+ // First attempt at an implementation, but I'm not really sure it's
+ // right...
+#if 0
+ ExtQualType* LQual = cast<ExtQualType>(LHSCan);
+ ExtQualType* RQual = cast<ExtQualType>(RHSCan);
+ if (LQual->getAddressSpace() != RQual->getAddressSpace() ||
+ LQual->getObjCGCAttr() != RQual->getObjCGCAttr())
+ return QualType();
+ QualType LHSBase, RHSBase, ResultType, ResCanUnqual;
+ LHSBase = QualType(LQual->getBaseType(), 0);
+ RHSBase = QualType(RQual->getBaseType(), 0);
+ ResultType = mergeTypes(LHSBase, RHSBase);
+ if (ResultType.isNull()) return QualType();
+ ResCanUnqual = getCanonicalType(ResultType).getUnqualifiedType();
+ if (LHSCan.getUnqualifiedType() == ResCanUnqual)
+ return LHS;
+ if (RHSCan.getUnqualifiedType() == ResCanUnqual)
+ return RHS;
+ ResultType = getAddrSpaceQualType(ResultType, LQual->getAddressSpace());
+ ResultType = getObjCGCQualType(ResultType, LQual->getObjCGCAttr());
+ ResultType.setCVRQualifiers(LHSCan.getCVRQualifiers());
+ return ResultType;
+#endif
+
+ case Type::TemplateSpecialization:
+ assert(false && "Dependent types have no size");
+ break;
+ }
+
+ return QualType();
+}
+
+//===----------------------------------------------------------------------===//
+// Integer Predicates
+//===----------------------------------------------------------------------===//
+
+unsigned ASTContext::getIntWidth(QualType T) {
+ if (T == BoolTy)
+ return 1;
+ if (FixedWidthIntType* FWIT = dyn_cast<FixedWidthIntType>(T)) {
+ return FWIT->getWidth();
+ }
+ // For builtin types, just use the standard type sizing method
+ return (unsigned)getTypeSize(T);
+}
+
+QualType ASTContext::getCorrespondingUnsignedType(QualType T) {
+ assert(T->isSignedIntegerType() && "Unexpected type");
+ if (const EnumType* ETy = T->getAsEnumType())
+ T = ETy->getDecl()->getIntegerType();
+ const BuiltinType* BTy = T->getAsBuiltinType();
+ assert (BTy && "Unexpected signed integer type");
+ switch (BTy->getKind()) {
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ return UnsignedCharTy;
+ case BuiltinType::Short:
+ return UnsignedShortTy;
+ case BuiltinType::Int:
+ return UnsignedIntTy;
+ case BuiltinType::Long:
+ return UnsignedLongTy;
+ case BuiltinType::LongLong:
+ return UnsignedLongLongTy;
+ case BuiltinType::Int128:
+ return UnsignedInt128Ty;
+ default:
+ assert(0 && "Unexpected signed integer type");
+ return QualType();
+ }
+}
+
+ExternalASTSource::~ExternalASTSource() { }
+
+void ExternalASTSource::PrintStats() { }
diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp
new file mode 100644
index 000000000000..8368febe5a05
--- /dev/null
+++ b/lib/AST/Builtins.cpp
@@ -0,0 +1,290 @@
+//===--- Builtins.cpp - Builtin function implementation -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements various things for builtin functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Builtins.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/TargetInfo.h"
+using namespace clang;
+
+static const Builtin::Info BuiltinInfo[] = {
+ { "not a builtin function", 0, 0, 0, false },
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false },
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false },
+#include "clang/AST/Builtins.def"
+};
+
+const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const {
+ if (ID < Builtin::FirstTSBuiltin)
+ return BuiltinInfo[ID];
+ assert(ID - Builtin::FirstTSBuiltin < NumTSRecords && "Invalid builtin ID!");
+ return TSRecords[ID - Builtin::FirstTSBuiltin];
+}
+
+/// \brief Load all of the target builtins. This must be called
+/// prior to initializing the builtin identifiers.
+void Builtin::Context::InitializeTargetBuiltins(const TargetInfo &Target) {
+ Target.getTargetBuiltins(TSRecords, NumTSRecords);
+}
+
+/// InitializeBuiltins - Mark the identifiers for all the builtins with their
+/// appropriate builtin ID # and mark any non-portable builtin identifiers as
+/// such.
+void Builtin::Context::InitializeBuiltins(IdentifierTable &Table,
+ bool NoBuiltins) {
+ // Step #1: mark all target-independent builtins with their ID's.
+ for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
+ if (!BuiltinInfo[i].Suppressed &&
+ (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f')))
+ Table.get(BuiltinInfo[i].Name).setBuiltinID(i);
+
+ // Step #2: Register target-specific builtins.
+ for (unsigned i = 0, e = NumTSRecords; i != e; ++i)
+ if (!TSRecords[i].Suppressed &&
+ (!NoBuiltins ||
+ (TSRecords[i].Attributes &&
+ !strchr(TSRecords[i].Attributes, 'f'))))
+ Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin);
+}
+
+void
+Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names,
+ bool NoBuiltins) {
+ // Final all target-independent names
+ for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
+ if (!BuiltinInfo[i].Suppressed &&
+ (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f')))
+ Names.push_back(BuiltinInfo[i].Name);
+
+ // Find target-specific names.
+ for (unsigned i = 0, e = NumTSRecords; i != e; ++i)
+ if (!TSRecords[i].Suppressed &&
+ (!NoBuiltins ||
+ (TSRecords[i].Attributes &&
+ !strchr(TSRecords[i].Attributes, 'f'))))
+ Names.push_back(TSRecords[i].Name);
+}
+
+bool
+Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,
+ bool &HasVAListArg) {
+ const char *Printf = strpbrk(GetRecord(ID).Attributes, "pP");
+ if (!Printf)
+ return false;
+
+ HasVAListArg = (*Printf == 'P');
+
+ ++Printf;
+ assert(*Printf == ':' && "p or P specifier must have be followed by a ':'");
+ ++Printf;
+
+ assert(strchr(Printf, ':') && "printf specifier must end with a ':'");
+ FormatIdx = strtol(Printf, 0, 10);
+ return true;
+}
+
+/// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the
+/// pointer over the consumed characters. This returns the resultant type.
+static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
+ Builtin::Context::GetBuiltinTypeError &Error,
+ bool AllowTypeModifiers = true) {
+ // Modifiers.
+ int HowLong = 0;
+ bool Signed = false, Unsigned = false;
+
+ // Read the modifiers first.
+ bool Done = false;
+ while (!Done) {
+ switch (*Str++) {
+ default: Done = true; --Str; break;
+ case 'S':
+ assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!");
+ assert(!Signed && "Can't use 'S' modifier multiple times!");
+ Signed = true;
+ break;
+ case 'U':
+ assert(!Signed && "Can't use both 'S' and 'U' modifiers!");
+ assert(!Unsigned && "Can't use 'S' modifier multiple times!");
+ Unsigned = true;
+ break;
+ case 'L':
+ assert(HowLong <= 2 && "Can't have LLLL modifier");
+ ++HowLong;
+ break;
+ }
+ }
+
+ QualType Type;
+
+ // Read the base type.
+ switch (*Str++) {
+ default: assert(0 && "Unknown builtin type letter!");
+ case 'v':
+ assert(HowLong == 0 && !Signed && !Unsigned &&
+ "Bad modifiers used with 'v'!");
+ Type = Context.VoidTy;
+ break;
+ case 'f':
+ assert(HowLong == 0 && !Signed && !Unsigned &&
+ "Bad modifiers used with 'f'!");
+ Type = Context.FloatTy;
+ break;
+ case 'd':
+ assert(HowLong < 2 && !Signed && !Unsigned &&
+ "Bad modifiers used with 'd'!");
+ if (HowLong)
+ Type = Context.LongDoubleTy;
+ else
+ Type = Context.DoubleTy;
+ break;
+ case 's':
+ assert(HowLong == 0 && "Bad modifiers used with 's'!");
+ if (Unsigned)
+ Type = Context.UnsignedShortTy;
+ else
+ Type = Context.ShortTy;
+ break;
+ case 'i':
+ if (HowLong == 3)
+ Type = Unsigned ? Context.UnsignedInt128Ty : Context.Int128Ty;
+ else if (HowLong == 2)
+ Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy;
+ else if (HowLong == 1)
+ Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy;
+ else
+ Type = Unsigned ? Context.UnsignedIntTy : Context.IntTy;
+ break;
+ case 'c':
+ assert(HowLong == 0 && "Bad modifiers used with 'c'!");
+ if (Signed)
+ Type = Context.SignedCharTy;
+ else if (Unsigned)
+ Type = Context.UnsignedCharTy;
+ else
+ Type = Context.CharTy;
+ break;
+ case 'b': // boolean
+ assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'b'!");
+ Type = Context.BoolTy;
+ break;
+ case 'z': // size_t.
+ assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'z'!");
+ Type = Context.getSizeType();
+ break;
+ case 'F':
+ Type = Context.getCFConstantStringType();
+ break;
+ case 'a':
+ Type = Context.getBuiltinVaListType();
+ assert(!Type.isNull() && "builtin va list type not initialized!");
+ break;
+ case 'A':
+ // This is a "reference" to a va_list; however, what exactly
+ // this means depends on how va_list is defined. There are two
+ // different kinds of va_list: ones passed by value, and ones
+ // passed by reference. An example of a by-value va_list is
+ // x86, where va_list is a char*. An example of by-ref va_list
+ // is x86-64, where va_list is a __va_list_tag[1]. For x86,
+ // we want this argument to be a char*&; for x86-64, we want
+ // it to be a __va_list_tag*.
+ Type = Context.getBuiltinVaListType();
+ assert(!Type.isNull() && "builtin va list type not initialized!");
+ if (Type->isArrayType()) {
+ Type = Context.getArrayDecayedType(Type);
+ } else {
+ Type = Context.getLValueReferenceType(Type);
+ }
+ break;
+ case 'V': {
+ char *End;
+
+ unsigned NumElements = strtoul(Str, &End, 10);
+ assert(End != Str && "Missing vector size");
+
+ Str = End;
+
+ QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false);
+ Type = Context.getVectorType(ElementType, NumElements);
+ break;
+ }
+ case 'P': {
+ IdentifierInfo *II = &Context.Idents.get("FILE");
+ DeclContext::lookup_result Lookup
+ = Context.getTranslationUnitDecl()->lookup(Context, II);
+ if (Lookup.first != Lookup.second && isa<TypeDecl>(*Lookup.first)) {
+ Type = Context.getTypeDeclType(cast<TypeDecl>(*Lookup.first));
+ break;
+ }
+ else {
+ Error = Builtin::Context::GE_Missing_FILE;
+ return QualType();
+ }
+ }
+ }
+
+ if (!AllowTypeModifiers)
+ return Type;
+
+ Done = false;
+ while (!Done) {
+ switch (*Str++) {
+ default: Done = true; --Str; break;
+ case '*':
+ Type = Context.getPointerType(Type);
+ break;
+ case '&':
+ Type = Context.getLValueReferenceType(Type);
+ break;
+ // FIXME: There's no way to have a built-in with an rvalue ref arg.
+ case 'C':
+ Type = Type.getQualifiedType(QualType::Const);
+ break;
+ }
+ }
+
+ return Type;
+}
+
+/// GetBuiltinType - Return the type for the specified builtin.
+QualType Builtin::Context::GetBuiltinType(unsigned id, ASTContext &Context,
+ GetBuiltinTypeError &Error) const {
+ const char *TypeStr = GetRecord(id).Type;
+
+ llvm::SmallVector<QualType, 8> ArgTypes;
+
+ Error = GE_None;
+ QualType ResType = DecodeTypeFromStr(TypeStr, Context, Error);
+ if (Error != GE_None)
+ return QualType();
+ while (TypeStr[0] && TypeStr[0] != '.') {
+ QualType Ty = DecodeTypeFromStr(TypeStr, Context, Error);
+ if (Error != GE_None)
+ return QualType();
+
+ // Do array -> pointer decay. The builtin should use the decayed type.
+ if (Ty->isArrayType())
+ Ty = Context.getArrayDecayedType(Ty);
+
+ ArgTypes.push_back(Ty);
+ }
+
+ assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
+ "'.' should only occur at end of builtin type list!");
+
+ // handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);".
+ if (ArgTypes.size() == 0 && TypeStr[0] == '.')
+ return Context.getFunctionNoProtoType(ResType);
+ return Context.getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(),
+ TypeStr[0] == '.', 0);
+}
diff --git a/lib/AST/CFG.cpp b/lib/AST/CFG.cpp
new file mode 100644
index 000000000000..9f2f2079a094
--- /dev/null
+++ b/lib/AST/CFG.cpp
@@ -0,0 +1,1913 @@
+//===--- CFG.cpp - Classes for representing and building 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 defines the CFG and CFGBuilder classes for representing and
+// building Control-Flow Graphs (CFGs) from ASTs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/CFG.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/GraphWriter.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/Compiler.h"
+#include <llvm/Support/Allocator.h>
+#include <llvm/Support/Format.h>
+#include <iomanip>
+#include <algorithm>
+#include <sstream>
+
+using namespace clang;
+
+namespace {
+
+// SaveAndRestore - A utility class that uses RIIA to save and restore
+// the value of a variable.
+template<typename T>
+struct VISIBILITY_HIDDEN SaveAndRestore {
+ SaveAndRestore(T& x) : X(x), old_value(x) {}
+ ~SaveAndRestore() { X = old_value; }
+ T get() { return old_value; }
+
+ T& X;
+ T old_value;
+};
+
+static SourceLocation GetEndLoc(Decl* D) {
+ if (VarDecl* VD = dyn_cast<VarDecl>(D))
+ if (Expr* Ex = VD->getInit())
+ return Ex->getSourceRange().getEnd();
+
+ return D->getLocation();
+}
+
+/// CFGBuilder - This class implements CFG construction from an AST.
+/// The builder is stateful: an instance of the builder should be used to only
+/// construct a single CFG.
+///
+/// Example usage:
+///
+/// CFGBuilder builder;
+/// CFG* cfg = builder.BuildAST(stmt1);
+///
+/// CFG construction is done via a recursive walk of an AST.
+/// We actually parse the AST in reverse order so that the successor
+/// of a basic block is constructed prior to its predecessor. This
+/// allows us to nicely capture implicit fall-throughs without extra
+/// basic blocks.
+///
+class VISIBILITY_HIDDEN CFGBuilder : public StmtVisitor<CFGBuilder,CFGBlock*> {
+ CFG* cfg;
+ CFGBlock* Block;
+ CFGBlock* Succ;
+ CFGBlock* ContinueTargetBlock;
+ CFGBlock* BreakTargetBlock;
+ CFGBlock* SwitchTerminatedBlock;
+ CFGBlock* DefaultCaseBlock;
+
+ // LabelMap records the mapping from Label expressions to their blocks.
+ typedef llvm::DenseMap<LabelStmt*,CFGBlock*> LabelMapTy;
+ LabelMapTy LabelMap;
+
+ // A list of blocks that end with a "goto" that must be backpatched to
+ // their resolved targets upon completion of CFG construction.
+ typedef std::vector<CFGBlock*> BackpatchBlocksTy;
+ BackpatchBlocksTy BackpatchBlocks;
+
+ // A list of labels whose address has been taken (for indirect gotos).
+ typedef llvm::SmallPtrSet<LabelStmt*,5> LabelSetTy;
+ LabelSetTy AddressTakenLabels;
+
+public:
+ explicit CFGBuilder() : cfg(NULL), Block(NULL), Succ(NULL),
+ ContinueTargetBlock(NULL), BreakTargetBlock(NULL),
+ SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) {
+ // Create an empty CFG.
+ cfg = new CFG();
+ }
+
+ ~CFGBuilder() { delete cfg; }
+
+ // buildCFG - Used by external clients to construct the CFG.
+ CFG* buildCFG(Stmt* Statement);
+
+ // Visitors to walk an AST and construct the CFG. Called by
+ // buildCFG. Do not call directly!
+
+ CFGBlock* VisitBreakStmt(BreakStmt* B);
+ CFGBlock* VisitCaseStmt(CaseStmt* Terminator);
+ CFGBlock* VisitCompoundStmt(CompoundStmt* C);
+ CFGBlock* VisitContinueStmt(ContinueStmt* C);
+ CFGBlock* VisitDefaultStmt(DefaultStmt* D);
+ CFGBlock* VisitDoStmt(DoStmt* D);
+ CFGBlock* VisitForStmt(ForStmt* F);
+ CFGBlock* VisitGotoStmt(GotoStmt* G);
+ CFGBlock* VisitIfStmt(IfStmt* I);
+ CFGBlock* VisitIndirectGotoStmt(IndirectGotoStmt* I);
+ CFGBlock* VisitLabelStmt(LabelStmt* L);
+ CFGBlock* VisitNullStmt(NullStmt* Statement);
+ CFGBlock* VisitObjCForCollectionStmt(ObjCForCollectionStmt* S);
+ CFGBlock* VisitReturnStmt(ReturnStmt* R);
+ CFGBlock* VisitStmt(Stmt* Statement);
+ CFGBlock* VisitSwitchStmt(SwitchStmt* Terminator);
+ CFGBlock* VisitWhileStmt(WhileStmt* W);
+
+ // FIXME: Add support for ObjC-specific control-flow structures.
+
+ // NYS == Not Yet Supported
+ CFGBlock* NYS() {
+ badCFG = true;
+ return Block;
+ }
+
+ CFGBlock* VisitObjCAtTryStmt(ObjCAtTryStmt* S);
+ CFGBlock* VisitObjCAtCatchStmt(ObjCAtCatchStmt* S) {
+ // FIXME: For now we pretend that @catch and the code it contains
+ // does not exit.
+ return Block;
+ }
+
+ // FIXME: This is not completely supported. We basically @throw like
+ // a 'return'.
+ CFGBlock* VisitObjCAtThrowStmt(ObjCAtThrowStmt* S);
+
+ CFGBlock* VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S);
+
+ // Blocks.
+ CFGBlock* VisitBlockExpr(BlockExpr* E) { return NYS(); }
+ CFGBlock* VisitBlockDeclRefExpr(BlockDeclRefExpr* E) { return NYS(); }
+
+private:
+ CFGBlock* createBlock(bool add_successor = true);
+ CFGBlock* addStmt(Stmt* Terminator);
+ CFGBlock* WalkAST(Stmt* Terminator, bool AlwaysAddStmt);
+ CFGBlock* WalkAST_VisitChildren(Stmt* Terminator);
+ CFGBlock* WalkAST_VisitDeclSubExpr(Decl* D);
+ CFGBlock* WalkAST_VisitStmtExpr(StmtExpr* Terminator);
+ bool FinishBlock(CFGBlock* B);
+
+ bool badCFG;
+};
+
+// FIXME: Add support for dependent-sized array types in C++?
+// Does it even make sense to build a CFG for an uninstantiated template?
+static VariableArrayType* FindVA(Type* t) {
+ while (ArrayType* vt = dyn_cast<ArrayType>(t)) {
+ if (VariableArrayType* vat = dyn_cast<VariableArrayType>(vt))
+ if (vat->getSizeExpr())
+ return vat;
+
+ t = vt->getElementType().getTypePtr();
+ }
+
+ return 0;
+}
+
+/// BuildCFG - Constructs a CFG from an AST (a Stmt*). The AST can
+/// represent an arbitrary statement. Examples include a single expression
+/// or a function 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(Stmt* Statement) {
+ assert (cfg);
+ if (!Statement) return NULL;
+
+ badCFG = false;
+
+ // Create an empty block that will serve as the exit block for the CFG.
+ // Since this is the first block added to the CFG, it will be implicitly
+ // registered as the exit block.
+ Succ = createBlock();
+ assert (Succ == &cfg->getExit());
+ Block = NULL; // the EXIT block is empty. Create all other blocks lazily.
+
+ // Visit the statements and create the CFG.
+ CFGBlock* B = Visit(Statement);
+ if (!B) B = Succ;
+
+ if (B) {
+ // Finalize the last constructed block. This usually involves
+ // reversing the order of the statements in the block.
+ if (Block) FinishBlock(B);
+
+ // Backpatch the gotos whose label -> block mappings we didn't know
+ // when we encountered them.
+ for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(),
+ E = BackpatchBlocks.end(); I != E; ++I ) {
+
+ CFGBlock* B = *I;
+ 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
+ // incomplete AST. Handle this by not registering a successor.
+ if (LI == LabelMap.end()) continue;
+
+ B->addSuccessor(LI->second);
+ }
+
+ // Add successors to the Indirect Goto Dispatch block (if we have one).
+ if (CFGBlock* B = cfg->getIndirectGotoBlock())
+ for (LabelSetTy::iterator I = AddressTakenLabels.begin(),
+ E = AddressTakenLabels.end(); I != E; ++I ) {
+
+ // Lookup the target block.
+ LabelMapTy::iterator LI = LabelMap.find(*I);
+
+ // If there is no target block that contains label, then we are looking
+ // at an incomplete AST. Handle this by not registering a successor.
+ if (LI == LabelMap.end()) continue;
+
+ B->addSuccessor(LI->second);
+ }
+
+ Succ = B;
+ }
+
+ // Create an empty entry block that has no predecessors.
+ cfg->setEntry(createBlock());
+
+ if (badCFG) {
+ delete cfg;
+ cfg = NULL;
+ return NULL;
+ }
+
+ // NULL out cfg so that repeated calls to the builder will fail and that
+ // the ownership of the constructed CFG is passed to the caller.
+ CFG* t = cfg;
+ cfg = NULL;
+ return t;
+}
+
+/// createBlock - Used to lazily create blocks that are connected
+/// to the current (global) succcessor.
+CFGBlock* CFGBuilder::createBlock(bool add_successor) {
+ CFGBlock* B = cfg->createBlock();
+ if (add_successor && Succ) B->addSuccessor(Succ);
+ return B;
+}
+
+/// FinishBlock - When the last statement has been added to the block,
+/// we must reverse the statements because they have been inserted
+/// in reverse order.
+bool CFGBuilder::FinishBlock(CFGBlock* B) {
+ if (badCFG)
+ return false;
+
+ assert (B);
+ B->reverseStmts();
+ return true;
+}
+
+/// addStmt - Used to add statements/expressions to the current CFGBlock
+/// "Block". This method calls WalkAST on the passed statement to see if it
+/// contains any short-circuit expressions. If so, it recursively creates
+/// the necessary blocks for such expressions. It returns the "topmost" block
+/// of the created blocks, or the original value of "Block" when this method
+/// was called if no additional blocks are created.
+CFGBlock* CFGBuilder::addStmt(Stmt* Terminator) {
+ if (!Block) Block = createBlock();
+ return WalkAST(Terminator,true);
+}
+
+/// WalkAST - Used by addStmt to 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::WalkAST(Stmt* Terminator, bool AlwaysAddStmt = false) {
+ switch (Terminator->getStmtClass()) {
+ case Stmt::ConditionalOperatorClass: {
+ ConditionalOperator* C = cast<ConditionalOperator>(Terminator);
+
+ // Create the confluence block that will "merge" the results
+ // of the ternary expression.
+ CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock();
+ ConfluenceBlock->appendStmt(C);
+ if (!FinishBlock(ConfluenceBlock))
+ return 0;
+
+ // Create a block for the LHS expression if there is an LHS expression.
+ // A GCC extension allows LHS to be NULL, causing the condition to
+ // be the value that is returned instead.
+ // e.g: x ?: y is shorthand for: x ? x : y;
+ Succ = ConfluenceBlock;
+ Block = NULL;
+ CFGBlock* LHSBlock = NULL;
+ if (C->getLHS()) {
+ LHSBlock = Visit(C->getLHS());
+ if (!FinishBlock(LHSBlock))
+ return 0;
+ Block = NULL;
+ }
+
+ // Create the block for the RHS expression.
+ Succ = ConfluenceBlock;
+ CFGBlock* RHSBlock = Visit(C->getRHS());
+ if (!FinishBlock(RHSBlock))
+ return 0;
+
+ // Create the block that will contain the condition.
+ Block = createBlock(false);
+
+ if (LHSBlock)
+ Block->addSuccessor(LHSBlock);
+ else {
+ // If we have no LHS expression, add the ConfluenceBlock as a direct
+ // successor for the block containing the condition. Moreover,
+ // we need to reverse the order of the predecessors in the
+ // ConfluenceBlock because the RHSBlock will have been added to
+ // the succcessors already, and we want the first predecessor to the
+ // the block containing the expression for the case when the ternary
+ // expression evaluates to true.
+ Block->addSuccessor(ConfluenceBlock);
+ assert (ConfluenceBlock->pred_size() == 2);
+ std::reverse(ConfluenceBlock->pred_begin(),
+ ConfluenceBlock->pred_end());
+ }
+
+ Block->addSuccessor(RHSBlock);
+
+ Block->setTerminator(C);
+ return addStmt(C->getCond());
+ }
+
+ case Stmt::ChooseExprClass: {
+ ChooseExpr* C = cast<ChooseExpr>(Terminator);
+
+ CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
+ ConfluenceBlock->appendStmt(C);
+ if (!FinishBlock(ConfluenceBlock))
+ return 0;
+
+ Succ = ConfluenceBlock;
+ Block = NULL;
+ CFGBlock* LHSBlock = Visit(C->getLHS());
+ if (!FinishBlock(LHSBlock))
+ return 0;
+
+ Succ = ConfluenceBlock;
+ Block = NULL;
+ CFGBlock* RHSBlock = Visit(C->getRHS());
+ if (!FinishBlock(RHSBlock))
+ return 0;
+
+ Block = createBlock(false);
+ Block->addSuccessor(LHSBlock);
+ Block->addSuccessor(RHSBlock);
+ Block->setTerminator(C);
+ return addStmt(C->getCond());
+ }
+
+ case Stmt::DeclStmtClass: {
+ DeclStmt *DS = cast<DeclStmt>(Terminator);
+ if (DS->isSingleDecl()) {
+ Block->appendStmt(Terminator);
+ return WalkAST_VisitDeclSubExpr(DS->getSingleDecl());
+ }
+
+ CFGBlock* B = 0;
+
+ // FIXME: Add a reverse iterator for DeclStmt to avoid this
+ // extra copy.
+ typedef llvm::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) {
+ // Get the alignment of the new DeclStmt, padding out to >=8 bytes.
+ unsigned A = llvm::AlignOf<DeclStmt>::Alignment < 8
+ ? 8 : llvm::AlignOf<DeclStmt>::Alignment;
+
+ // Allocate the DeclStmt using the BumpPtrAllocator. It will
+ // get automatically freed with the CFG.
+ DeclGroupRef DG(*I);
+ Decl* D = *I;
+ void* Mem = cfg->getAllocator().Allocate(sizeof(DeclStmt), A);
+
+ DeclStmt* DS = new (Mem) DeclStmt(DG, D->getLocation(), GetEndLoc(D));
+
+ // Append the fake DeclStmt to block.
+ Block->appendStmt(DS);
+ B = WalkAST_VisitDeclSubExpr(D);
+ }
+ return B;
+ }
+
+ case Stmt::AddrLabelExprClass: {
+ AddrLabelExpr* A = cast<AddrLabelExpr>(Terminator);
+ AddressTakenLabels.insert(A->getLabel());
+
+ if (AlwaysAddStmt) Block->appendStmt(Terminator);
+ return Block;
+ }
+
+ case Stmt::StmtExprClass:
+ return WalkAST_VisitStmtExpr(cast<StmtExpr>(Terminator));
+
+ case Stmt::SizeOfAlignOfExprClass: {
+ SizeOfAlignOfExpr* E = cast<SizeOfAlignOfExpr>(Terminator);
+
+ // VLA types have expressions that must be evaluated.
+ if (E->isArgumentType()) {
+ for (VariableArrayType* VA = FindVA(E->getArgumentType().getTypePtr());
+ VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
+ addStmt(VA->getSizeExpr());
+ }
+ // Expressions in sizeof/alignof are not evaluated and thus have no
+ // control flow.
+ else
+ Block->appendStmt(Terminator);
+
+ return Block;
+ }
+
+ case Stmt::BinaryOperatorClass: {
+ BinaryOperator* B = cast<BinaryOperator>(Terminator);
+
+ if (B->isLogicalOp()) { // && or ||
+ CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock();
+ ConfluenceBlock->appendStmt(B);
+ if (!FinishBlock(ConfluenceBlock))
+ return 0;
+
+ // create the block evaluating the LHS
+ CFGBlock* LHSBlock = createBlock(false);
+ LHSBlock->setTerminator(B);
+
+ // create the block evaluating the RHS
+ Succ = ConfluenceBlock;
+ Block = NULL;
+ CFGBlock* RHSBlock = Visit(B->getRHS());
+ if (!FinishBlock(RHSBlock))
+ return 0;
+
+ // Now link the LHSBlock with RHSBlock.
+ if (B->getOpcode() == BinaryOperator::LOr) {
+ LHSBlock->addSuccessor(ConfluenceBlock);
+ LHSBlock->addSuccessor(RHSBlock);
+ }
+ else {
+ assert (B->getOpcode() == BinaryOperator::LAnd);
+ LHSBlock->addSuccessor(RHSBlock);
+ LHSBlock->addSuccessor(ConfluenceBlock);
+ }
+
+ // Generate the blocks for evaluating the LHS.
+ Block = LHSBlock;
+ return addStmt(B->getLHS());
+ }
+ else if (B->getOpcode() == BinaryOperator::Comma) { // ,
+ Block->appendStmt(B);
+ addStmt(B->getRHS());
+ return addStmt(B->getLHS());
+ }
+
+ break;
+ }
+
+ // Blocks: No support for blocks ... yet
+ case Stmt::BlockExprClass:
+ case Stmt::BlockDeclRefExprClass:
+ return NYS();
+
+ case Stmt::ParenExprClass:
+ return WalkAST(cast<ParenExpr>(Terminator)->getSubExpr(), AlwaysAddStmt);
+
+ default:
+ break;
+ };
+
+ if (AlwaysAddStmt) Block->appendStmt(Terminator);
+ return WalkAST_VisitChildren(Terminator);
+}
+
+/// WalkAST_VisitDeclSubExpr - Utility method to add block-level expressions
+/// for initializers in Decls.
+CFGBlock* CFGBuilder::WalkAST_VisitDeclSubExpr(Decl* D) {
+ VarDecl* VD = dyn_cast<VarDecl>(D);
+
+ if (!VD)
+ return Block;
+
+ Expr* Init = VD->getInit();
+
+ if (Init) {
+ // Optimization: Don't create separate block-level statements for literals.
+ switch (Init->getStmtClass()) {
+ case Stmt::IntegerLiteralClass:
+ case Stmt::CharacterLiteralClass:
+ case Stmt::StringLiteralClass:
+ break;
+ default:
+ Block = addStmt(Init);
+ }
+ }
+
+ // If the type of VD is a VLA, then we must process its size expressions.
+ for (VariableArrayType* VA = FindVA(VD->getType().getTypePtr()); VA != 0;
+ VA = FindVA(VA->getElementType().getTypePtr()))
+ Block = addStmt(VA->getSizeExpr());
+
+ return Block;
+}
+
+/// WalkAST_VisitChildren - Utility method to call WalkAST on the
+/// children of a Stmt.
+CFGBlock* CFGBuilder::WalkAST_VisitChildren(Stmt* Terminator) {
+ CFGBlock* B = Block;
+ for (Stmt::child_iterator I = Terminator->child_begin(),
+ E = Terminator->child_end();
+ I != E; ++I)
+ if (*I) B = WalkAST(*I);
+
+ return B;
+}
+
+/// WalkAST_VisitStmtExpr - Utility method to handle (nested) statement
+/// expressions (a GCC extension).
+CFGBlock* CFGBuilder::WalkAST_VisitStmtExpr(StmtExpr* Terminator) {
+ Block->appendStmt(Terminator);
+ return VisitCompoundStmt(Terminator->getSubStmt());
+}
+
+/// VisitStmt - Handle statements with no branching control flow.
+CFGBlock* CFGBuilder::VisitStmt(Stmt* Statement) {
+ // We cannot assume that we are in the middle of a basic block, since
+ // the CFG might only be constructed for this single statement. If
+ // we have no current basic block, just create one lazily.
+ if (!Block) Block = createBlock();
+
+ // Simply add the statement to the current block. We actually
+ // insert statements in reverse order; this order is reversed later
+ // when processing the containing element in the AST.
+ addStmt(Statement);
+
+ return Block;
+}
+
+CFGBlock* CFGBuilder::VisitNullStmt(NullStmt* Statement) {
+ return Block;
+}
+
+CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) {
+
+ CFGBlock* LastBlock = NULL;
+
+ for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend();
+ I != E; ++I ) {
+ LastBlock = Visit(*I);
+ }
+
+ return LastBlock;
+}
+
+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 then we create the block containing
+ // the if statement. If we were in the middle of a block, we
+ // stop processing that block and reverse its statements. That block
+ // is then the implicit successor for the "then" and "else" clauses.
+
+ // The block we were proccessing is now finished. Make it the
+ // successor block.
+ if (Block) {
+ Succ = Block;
+ if (!FinishBlock(Block))
+ return 0;
+ }
+
+ // Process the false branch. NULL out Block so that the recursive
+ // call to Visit will create a new basic block.
+ // Null out Block so that all successor
+ CFGBlock* ElseBlock = Succ;
+
+ if (Stmt* Else = I->getElse()) {
+ SaveAndRestore<CFGBlock*> sv(Succ);
+
+ // NULL out Block so that the recursive call to Visit will
+ // create a new basic block.
+ Block = NULL;
+ ElseBlock = Visit(Else);
+
+ if (!ElseBlock) // Can occur when the Else body has all NullStmts.
+ ElseBlock = sv.get();
+ else if (Block) {
+ if (!FinishBlock(ElseBlock))
+ return 0;
+ }
+ }
+
+ // Process the true branch. NULL out Block so that the recursive
+ // call to Visit will create a new basic block.
+ // Null out Block so that all successor
+ CFGBlock* ThenBlock;
+ {
+ Stmt* Then = I->getThen();
+ assert (Then);
+ SaveAndRestore<CFGBlock*> sv(Succ);
+ Block = NULL;
+ ThenBlock = Visit(Then);
+
+ if (!ThenBlock) {
+ // We can reach here if the "then" body has all NullStmts.
+ // Create an empty block so we can distinguish between true and false
+ // branches in path-sensitive analyses.
+ ThenBlock = createBlock(false);
+ ThenBlock->addSuccessor(sv.get());
+ }
+ else if (Block) {
+ if (!FinishBlock(ThenBlock))
+ return 0;
+ }
+ }
+
+ // Now create a new block containing the if statement.
+ Block = createBlock(false);
+
+ // Set the terminator of the new block to the If statement.
+ Block->setTerminator(I);
+
+ // Now add the successors.
+ Block->addSuccessor(ThenBlock);
+ Block->addSuccessor(ElseBlock);
+
+ // Add the condition as the last statement in the new block. This
+ // may create new blocks as the condition may contain control-flow. Any
+ // newly created blocks will be pointed to be "Block".
+ return addStmt(I->getCond()->IgnoreParens());
+}
+
+
+CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) {
+ // If we were in the middle of a block we stop processing that block
+ // and reverse its statements.
+ //
+ // NOTE: If a "return" appears in the middle of a block, this means
+ // that the code afterwards is DEAD (unreachable). We still
+ // keep a basic block for that code; a simple "mark-and-sweep"
+ // from the entry block will be able to report such dead
+ // blocks.
+ if (Block) FinishBlock(Block);
+
+ // Create the new block.
+ Block = createBlock(false);
+
+ // The Exit block is the only successor.
+ Block->addSuccessor(&cfg->getExit());
+
+ // Add the return statement to the block. This may create new blocks
+ // if R contains control-flow (short-circuit operations).
+ return addStmt(R);
+}
+
+CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) {
+ // Get the block of the labeled statement. Add it to our map.
+ Visit(L->getSubStmt());
+ CFGBlock* LabelBlock = Block;
+
+ if (!LabelBlock) // This can happen when the body is empty, i.e.
+ LabelBlock=createBlock(); // scopes that only contains NullStmts.
+
+ assert (LabelMap.find(L) == LabelMap.end() && "label already in map");
+ LabelMap[ L ] = LabelBlock;
+
+ // Labels partition blocks, so this is the end of the basic block
+ // we were processing (L is the block's label). Because this is
+ // label (and we have already processed the substatement) there is no
+ // extra control-flow to worry about.
+ LabelBlock->setLabel(L);
+ if (!FinishBlock(LabelBlock))
+ return 0;
+
+ // We set Block to NULL to allow lazy creation of a new block
+ // (if necessary);
+ Block = NULL;
+
+ // This block is now the implicit successor of other blocks.
+ Succ = LabelBlock;
+
+ return LabelBlock;
+}
+
+CFGBlock* CFGBuilder::VisitGotoStmt(GotoStmt* G) {
+ // Goto is a control-flow statement. Thus we stop processing the
+ // current block and create a new one.
+ if (Block) FinishBlock(Block);
+ Block = createBlock(false);
+ Block->setTerminator(G);
+
+ // If we already know the mapping to the label block add the
+ // successor now.
+ LabelMapTy::iterator I = LabelMap.find(G->getLabel());
+
+ if (I == LabelMap.end())
+ // We will need to backpatch this block later.
+ BackpatchBlocks.push_back(Block);
+ else
+ Block->addSuccessor(I->second);
+
+ return Block;
+}
+
+CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
+ // "for" is a control-flow statement. Thus we stop processing the
+ // current block.
+
+ CFGBlock* LoopSuccessor = NULL;
+
+ if (Block) {
+ if (!FinishBlock(Block))
+ return 0;
+ LoopSuccessor = Block;
+ }
+ else LoopSuccessor = Succ;
+
+ // 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;
+
+ // 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()) {
+ Block = ExitConditionBlock;
+ EntryConditionBlock = addStmt(C);
+ if (Block) {
+ if (!FinishBlock(EntryConditionBlock))
+ return 0;
+ }
+ }
+
+ // The condition block is the implicit successor for the loop body as
+ // well as any code above the loop.
+ Succ = EntryConditionBlock;
+
+ // Now create the loop body.
+ {
+ assert (F->getBody());
+
+ // Save the current values for Block, Succ, and continue and break targets
+ SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
+ save_continue(ContinueTargetBlock),
+ save_break(BreakTargetBlock);
+
+ // Create a new block to contain the (bottom) of the loop body.
+ Block = NULL;
+
+ if (Stmt* I = F->getInc()) {
+ // Generate increment code in its own basic block. This is the target
+ // of continue statements.
+ Succ = Visit(I);
+ }
+ else {
+ // No increment code. Create a special, empty, block that is used as
+ // the target block for "looping back" to the start of the loop.
+ assert(Succ == EntryConditionBlock);
+ Succ = createBlock();
+ }
+
+ // Finish up the increment (or empty) block if it hasn't been already.
+ if (Block) {
+ assert(Block == Succ);
+ if (!FinishBlock(Block))
+ return 0;
+ Block = 0;
+ }
+
+ ContinueTargetBlock = Succ;
+
+ // The starting block for the loop increment is the block that should
+ // represent the 'loop target' for looping back to the start of the loop.
+ ContinueTargetBlock->setLoopTarget(F);
+
+ // All breaks should go to the code following the loop.
+ BreakTargetBlock = LoopSuccessor;
+
+ // Now populate the body block, and in the process create new blocks
+ // as we walk the body of the loop.
+ CFGBlock* BodyBlock = Visit(F->getBody());
+
+ if (!BodyBlock)
+ BodyBlock = EntryConditionBlock; // can happen for "for (...;...; ) ;"
+ else if (Block) {
+ if (!FinishBlock(BodyBlock))
+ return 0;
+ }
+
+ // This new body block is a successor to our "exit" condition block.
+ ExitConditionBlock->addSuccessor(BodyBlock);
+ }
+
+ // Link up the condition block with the code that follows the loop.
+ // (the false branch).
+ ExitConditionBlock->addSuccessor(LoopSuccessor);
+
+ // 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()) {
+ Block = createBlock();
+ return addStmt(I);
+ }
+ else {
+ // There is no loop initialization. We are thus basically a while
+ // loop. NULL out Block to force lazy block construction.
+ Block = NULL;
+ Succ = EntryConditionBlock;
+ return EntryConditionBlock;
+ }
+}
+
+CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
+ // Objective-C fast enumeration 'for' statements:
+ // http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC
+ //
+ // for ( Type newVariable in collection_expression ) { statements }
+ //
+ // becomes:
+ //
+ // prologue:
+ // 1. collection_expression
+ // T. jump to loop_entry
+ // loop_entry:
+ // 1. side-effects of element expression
+ // 1. ObjCForCollectionStmt [performs binding to newVariable]
+ // T. ObjCForCollectionStmt TB, FB [jumps to TB if newVariable != nil]
+ // TB:
+ // statements
+ // T. jump to loop_entry
+ // FB:
+ // what comes after
+ //
+ // and
+ //
+ // Type existingItem;
+ // for ( existingItem in expression ) { statements }
+ //
+ // becomes:
+ //
+ // the same with newVariable replaced with existingItem; the binding
+ // works the same except that for one ObjCForCollectionStmt::getElement()
+ // returns a DeclStmt and the other returns a DeclRefExpr.
+ //
+
+ CFGBlock* LoopSuccessor = 0;
+
+ if (Block) {
+ if (!FinishBlock(Block))
+ return 0;
+ LoopSuccessor = Block;
+ Block = 0;
+ }
+ else LoopSuccessor = Succ;
+
+ // Build the condition blocks.
+ CFGBlock* ExitConditionBlock = createBlock(false);
+ CFGBlock* EntryConditionBlock = ExitConditionBlock;
+
+ // Set the terminator for the "exit" condition block.
+ ExitConditionBlock->setTerminator(S);
+
+ // The last statement in the block should be the ObjCForCollectionStmt,
+ // which performs the actual binding to 'element' and determines if there
+ // are any more items in the collection.
+ ExitConditionBlock->appendStmt(S);
+ Block = ExitConditionBlock;
+
+ // Walk the 'element' expression to see if there are any side-effects. We
+ // generate new blocks as necesary. We DON'T add the statement by default
+ // to the CFG unless it contains control-flow.
+ EntryConditionBlock = WalkAST(S->getElement(), false);
+ if (Block) {
+ if (!FinishBlock(EntryConditionBlock))
+ return 0;
+ Block = 0;
+ }
+
+ // The condition block is the implicit successor for the loop body as
+ // well as any code above the loop.
+ Succ = EntryConditionBlock;
+
+ // Now create the true branch.
+ {
+ // Save the current values for Succ, continue and break targets.
+ SaveAndRestore<CFGBlock*> save_Succ(Succ),
+ save_continue(ContinueTargetBlock), save_break(BreakTargetBlock);
+
+ BreakTargetBlock = LoopSuccessor;
+ ContinueTargetBlock = EntryConditionBlock;
+
+ CFGBlock* BodyBlock = Visit(S->getBody());
+
+ if (!BodyBlock)
+ BodyBlock = EntryConditionBlock; // can happen for "for (X in Y) ;"
+ else if (Block) {
+ if (!FinishBlock(BodyBlock))
+ return 0;
+ }
+
+ // This new body block is a successor to our "exit" condition block.
+ ExitConditionBlock->addSuccessor(BodyBlock);
+ }
+
+ // Link up the condition block with the code that follows the loop.
+ // (the false branch).
+ ExitConditionBlock->addSuccessor(LoopSuccessor);
+
+ // Now create a prologue block to contain the collection expression.
+ Block = createBlock();
+ return addStmt(S->getCollection());
+}
+
+CFGBlock* CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S) {
+ // FIXME: Add locking 'primitives' to CFG for @synchronized.
+
+ // Inline the body.
+ CFGBlock *SyncBlock = Visit(S->getSynchBody());
+
+ // The sync body starts its own basic block. This makes it a little easier
+ // for diagnostic clients.
+ if (SyncBlock) {
+ if (!FinishBlock(SyncBlock))
+ return 0;
+
+ Block = 0;
+ }
+
+ Succ = SyncBlock;
+
+ // Inline the sync expression.
+ return Visit(S->getSynchExpr());
+}
+
+CFGBlock* CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt* S) {
+ return NYS();
+}
+
+CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
+ // "while" is a control-flow statement. Thus we stop processing the
+ // current block.
+
+ CFGBlock* LoopSuccessor = NULL;
+
+ if (Block) {
+ if (!FinishBlock(Block))
+ return 0;
+ LoopSuccessor = Block;
+ }
+ else LoopSuccessor = Succ;
+
+ // 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;
+
+ // Set the terminator for the "exit" condition block.
+ ExitConditionBlock->setTerminator(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()) {
+ Block = ExitConditionBlock;
+ EntryConditionBlock = addStmt(C);
+ assert(Block == EntryConditionBlock);
+ if (Block) {
+ if (!FinishBlock(EntryConditionBlock))
+ return 0;
+ }
+ }
+
+ // The condition block is the implicit successor for the loop body as
+ // well as any code above the loop.
+ Succ = EntryConditionBlock;
+
+ // Process the loop body.
+ {
+ assert(W->getBody());
+
+ // Save the current values for Block, Succ, and continue and break targets
+ SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
+ save_continue(ContinueTargetBlock),
+ save_break(BreakTargetBlock);
+
+ // Create an empty block to represent the transition block for looping
+ // back to the head of the loop.
+ Block = 0;
+ assert(Succ == EntryConditionBlock);
+ Succ = createBlock();
+ Succ->setLoopTarget(W);
+ ContinueTargetBlock = Succ;
+
+ // All breaks should go to the code following the loop.
+ BreakTargetBlock = LoopSuccessor;
+
+ // NULL out Block to force lazy instantiation of blocks for the body.
+ Block = NULL;
+
+ // Create the body. The returned block is the entry to the loop body.
+ CFGBlock* BodyBlock = Visit(W->getBody());
+
+ if (!BodyBlock)
+ BodyBlock = EntryConditionBlock; // can happen for "while(...) ;"
+ else if (Block) {
+ if (!FinishBlock(BodyBlock))
+ return 0;
+ }
+
+ // Add the loop body entry as a successor to the condition.
+ ExitConditionBlock->addSuccessor(BodyBlock);
+ }
+
+ // Link up the condition block with the code that follows the loop.
+ // (the false branch).
+ ExitConditionBlock->addSuccessor(LoopSuccessor);
+
+ // There can be no more statements in the condition block
+ // since we loop back to this block. NULL out Block to force
+ // lazy creation of another block.
+ Block = NULL;
+
+ // Return the condition block, which is the dominating block for the loop.
+ Succ = EntryConditionBlock;
+ return EntryConditionBlock;
+}
+
+CFGBlock* CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt* S) {
+ // FIXME: This isn't complete. We basically treat @throw like a return
+ // statement.
+
+ // If we were in the middle of a block we stop processing that block
+ // and reverse its statements.
+ if (Block) {
+ if (!FinishBlock(Block))
+ return 0;
+ }
+
+ // Create the new block.
+ Block = createBlock(false);
+
+ // The Exit block is the only successor.
+ Block->addSuccessor(&cfg->getExit());
+
+ // Add the statement to the block. This may create new blocks
+ // if S contains control-flow (short-circuit operations).
+ return addStmt(S);
+}
+
+CFGBlock* CFGBuilder::VisitDoStmt(DoStmt* D) {
+ // "do...while" is a control-flow statement. Thus we stop processing the
+ // current block.
+
+ CFGBlock* LoopSuccessor = NULL;
+
+ if (Block) {
+ if (!FinishBlock(Block))
+ return 0;
+ LoopSuccessor = Block;
+ }
+ else LoopSuccessor = Succ;
+
+ // 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;
+
+ // 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()) {
+ Block = ExitConditionBlock;
+ EntryConditionBlock = addStmt(C);
+ if (Block) {
+ if (!FinishBlock(EntryConditionBlock))
+ return 0;
+ }
+ }
+
+ // The condition block is the implicit successor for the loop body.
+ Succ = EntryConditionBlock;
+
+ // Process the loop body.
+ CFGBlock* BodyBlock = NULL;
+ {
+ assert (D->getBody());
+
+ // Save the current values for Block, Succ, and continue and break targets
+ SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
+ save_continue(ContinueTargetBlock),
+ save_break(BreakTargetBlock);
+
+ // All continues within this loop should go to the condition block
+ ContinueTargetBlock = EntryConditionBlock;
+
+ // All breaks should go to the code following the loop.
+ BreakTargetBlock = LoopSuccessor;
+
+ // NULL out Block to force lazy instantiation of blocks for the body.
+ Block = NULL;
+
+ // Create the body. The returned block is the entry to the loop body.
+ BodyBlock = Visit(D->getBody());
+
+ if (!BodyBlock)
+ BodyBlock = EntryConditionBlock; // can happen for "do ; while(...)"
+ else if (Block) {
+ if (!FinishBlock(BodyBlock))
+ return 0;
+ }
+
+ // Add an intermediate block between the BodyBlock and the
+ // ExitConditionBlock to represent the "loop back" transition.
+ // Create an empty block to represent the transition block for looping
+ // back to the head of the loop.
+ // FIXME: Can we do this more efficiently without adding another block?
+ Block = NULL;
+ Succ = BodyBlock;
+ CFGBlock *LoopBackBlock = createBlock();
+ LoopBackBlock->setLoopTarget(D);
+
+ // Add the loop body entry as a successor to the condition.
+ ExitConditionBlock->addSuccessor(LoopBackBlock);
+ }
+
+ // Link up the condition block with the code that follows the loop.
+ // (the false branch).
+ ExitConditionBlock->addSuccessor(LoopSuccessor);
+
+ // There can be no more statements in the body block(s)
+ // since we loop back to the body. NULL out Block to force
+ // lazy creation of another block.
+ Block = NULL;
+
+ // Return the loop body, which is the dominating block for the loop.
+ Succ = BodyBlock;
+ return BodyBlock;
+}
+
+CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) {
+ // "continue" is a control-flow statement. Thus we stop processing the
+ // current block.
+ if (Block) {
+ if (!FinishBlock(Block))
+ return 0;
+ }
+
+ // Now create a new block that ends with the continue statement.
+ Block = createBlock(false);
+ Block->setTerminator(C);
+
+ // If there is no target for the continue, then we are looking at an
+ // incomplete AST. This means the CFG cannot be constructed.
+ if (ContinueTargetBlock)
+ Block->addSuccessor(ContinueTargetBlock);
+ else
+ badCFG = true;
+
+ return Block;
+}
+
+CFGBlock* CFGBuilder::VisitBreakStmt(BreakStmt* B) {
+ // "break" is a control-flow statement. Thus we stop processing the
+ // current block.
+ if (Block) {
+ if (!FinishBlock(Block))
+ return 0;
+ }
+
+ // Now create a new block that ends with the continue statement.
+ Block = createBlock(false);
+ Block->setTerminator(B);
+
+ // If there is no target for the break, then we are looking at an
+ // incomplete AST. This means that the CFG cannot be constructed.
+ if (BreakTargetBlock)
+ Block->addSuccessor(BreakTargetBlock);
+ else
+ badCFG = true;
+
+
+ return Block;
+}
+
+CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
+ // "switch" is a control-flow statement. Thus we stop processing the
+ // current block.
+ CFGBlock* SwitchSuccessor = NULL;
+
+ if (Block) {
+ if (!FinishBlock(Block))
+ return 0;
+ SwitchSuccessor = Block;
+ }
+ else SwitchSuccessor = Succ;
+
+ // Save the current "switch" context.
+ SaveAndRestore<CFGBlock*> save_switch(SwitchTerminatedBlock),
+ save_break(BreakTargetBlock),
+ save_default(DefaultCaseBlock);
+
+ // Set the "default" case to be the block after the switch statement.
+ // If the switch statement contains a "default:", this value will
+ // be overwritten with the block for that code.
+ DefaultCaseBlock = SwitchSuccessor;
+
+ // Create a new block that will contain the switch statement.
+ SwitchTerminatedBlock = createBlock(false);
+
+ // Now process the switch body. The code after the switch is the implicit
+ // successor.
+ Succ = SwitchSuccessor;
+ BreakTargetBlock = SwitchSuccessor;
+
+ // When visiting the body, the case statements should automatically get
+ // linked up to the switch. We also don't keep a pointer to the body,
+ // since all control-flow from the switch goes to case/default statements.
+ assert (Terminator->getBody() && "switch must contain a non-NULL body");
+ Block = NULL;
+ CFGBlock *BodyBlock = Visit(Terminator->getBody());
+ if (Block) {
+ if (!FinishBlock(BodyBlock))
+ return 0;
+ }
+
+ // If we have no "default:" case, the default transition is to the
+ // code following the switch body.
+ SwitchTerminatedBlock->addSuccessor(DefaultCaseBlock);
+
+ // Add the terminator and condition in the switch block.
+ SwitchTerminatedBlock->setTerminator(Terminator);
+ assert (Terminator->getCond() && "switch condition must be non-NULL");
+ Block = SwitchTerminatedBlock;
+
+ return addStmt(Terminator->getCond());
+}
+
+CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* Terminator) {
+ // CaseStmts are essentially labels, so they are the
+ // first statement in a block.
+
+ if (Terminator->getSubStmt()) Visit(Terminator->getSubStmt());
+ CFGBlock* CaseBlock = Block;
+ if (!CaseBlock) CaseBlock = createBlock();
+
+ // Cases statements partition blocks, so this is the top of
+ // the basic block we were processing (the "case XXX:" is the label).
+ CaseBlock->setLabel(Terminator);
+ if (!FinishBlock(CaseBlock))
+ return 0;
+
+ // Add this block to the list of successors for the block with the
+ // switch statement.
+ assert (SwitchTerminatedBlock);
+ SwitchTerminatedBlock->addSuccessor(CaseBlock);
+
+ // We set Block to NULL to allow lazy creation of a new block (if necessary)
+ Block = NULL;
+
+ // This block is now the implicit successor of other blocks.
+ Succ = CaseBlock;
+
+ return CaseBlock;
+}
+
+CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* Terminator) {
+ if (Terminator->getSubStmt()) Visit(Terminator->getSubStmt());
+ DefaultCaseBlock = Block;
+ if (!DefaultCaseBlock) DefaultCaseBlock = createBlock();
+
+ // Default statements partition blocks, so this is the top of
+ // the basic block we were processing (the "default:" is the label).
+ DefaultCaseBlock->setLabel(Terminator);
+ if (!FinishBlock(DefaultCaseBlock))
+ return 0;
+
+ // Unlike case statements, we don't add the default block to the
+ // successors for the switch statement immediately. This is done
+ // when we finish processing the switch statement. This allows for
+ // the default case (including a fall-through to the code after the
+ // switch statement) to always be the last successor of a switch-terminated
+ // block.
+
+ // We set Block to NULL to allow lazy creation of a new block (if necessary)
+ Block = NULL;
+
+ // This block is now the implicit successor of other blocks.
+ Succ = DefaultCaseBlock;
+
+ return DefaultCaseBlock;
+}
+
+CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) {
+ // Lazily create the indirect-goto dispatch block if there isn't one
+ // already.
+ CFGBlock* IBlock = cfg->getIndirectGotoBlock();
+
+ if (!IBlock) {
+ IBlock = createBlock(false);
+ cfg->setIndirectGotoBlock(IBlock);
+ }
+
+ // IndirectGoto is a control-flow statement. Thus we stop processing the
+ // current block and create a new one.
+ if (Block) {
+ if (!FinishBlock(Block))
+ return 0;
+ }
+ Block = createBlock(false);
+ Block->setTerminator(I);
+ Block->addSuccessor(IBlock);
+ return addStmt(I->getTarget());
+}
+
+
+} // end anonymous namespace
+
+/// 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() {
+ bool first_block = begin() == end();
+
+ // Create the block.
+ Blocks.push_front(CFGBlock(NumBlockIDs++));
+
+ // If this is the first block, set it as the Entry and Exit.
+ if (first_block) Entry = Exit = &front();
+
+ // Return the block.
+ return &front();
+}
+
+/// buildCFG - Constructs a CFG from an AST. Ownership of the returned
+/// CFG is returned to the caller.
+CFG* CFG::buildCFG(Stmt* Statement) {
+ CFGBuilder Builder;
+ return Builder.buildCFG(Statement);
+}
+
+/// reverseStmts - Reverses the orders of statements within a CFGBlock.
+void CFGBlock::reverseStmts() { std::reverse(Stmts.begin(),Stmts.end()); }
+
+//===----------------------------------------------------------------------===//
+// CFG: Queries for BlkExprs.
+//===----------------------------------------------------------------------===//
+
+namespace {
+ typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy;
+}
+
+static void FindSubExprAssignments(Stmt* Terminator, llvm::SmallPtrSet<Expr*,50>& Set) {
+ if (!Terminator)
+ return;
+
+ for (Stmt::child_iterator I=Terminator->child_begin(), E=Terminator->child_end(); I!=E; ++I) {
+ if (!*I) continue;
+
+ if (BinaryOperator* B = dyn_cast<BinaryOperator>(*I))
+ if (B->isAssignmentOp()) Set.insert(B);
+
+ FindSubExprAssignments(*I, Set);
+ }
+}
+
+static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
+ BlkExprMapTy* M = new BlkExprMapTy();
+
+ // Look for assignments that are used as subexpressions. These are the
+ // only assignments that we want to *possibly* register as a block-level
+ // expression. Basically, if an assignment occurs both in a subexpression
+ // and at the block-level, it is a block-level expression.
+ llvm::SmallPtrSet<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)
+ FindSubExprAssignments(*BI, SubExprAssignments);
+
+ for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) {
+
+ // Iterate over the statements again on identify the Expr* and Stmt* at
+ // the block-level that are block-level expressions.
+
+ for (CFGBlock::iterator BI=I->begin(), EI=I->end(); BI != EI; ++BI)
+ if (Expr* Exp = dyn_cast<Expr>(*BI)) {
+
+ if (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* Terminator = 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 = Terminator->getSubStmt();
+ if (!C->body_empty()) {
+ unsigned x = M->size();
+ (*M)[C->body_back()] = x;
+ }
+ }
+
+ unsigned x = M->size();
+ (*M)[Exp] = x;
+ }
+
+ // Look at terminators. The condition is a block-level expression.
+
+ Stmt* S = I->getTerminatorCondition();
+
+ if (S && M->find(S) == M->end()) {
+ unsigned x = M->size();
+ (*M)[S] = x;
+ }
+ }
+
+ return M;
+}
+
+CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt* S) {
+ assert(S != NULL);
+ if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); }
+
+ BlkExprMapTy* M = reinterpret_cast<BlkExprMapTy*>(BlkExprMap);
+ BlkExprMapTy::iterator I = M->find(S);
+
+ if (I == M->end()) return CFG::BlkExprNumTy();
+ else return CFG::BlkExprNumTy(I->second);
+}
+
+unsigned CFG::getNumBlkExprs() {
+ if (const BlkExprMapTy* M = reinterpret_cast<const BlkExprMapTy*>(BlkExprMap))
+ return M->size();
+ else {
+ // We assume callers interested in the number of BlkExprs will want
+ // the map constructed if it doesn't already exist.
+ BlkExprMap = (void*) PopulateBlkExprMap(*this);
+ return reinterpret_cast<BlkExprMapTy*>(BlkExprMap)->size();
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Cleanup: CFG dstor.
+//===----------------------------------------------------------------------===//
+
+CFG::~CFG() {
+ delete reinterpret_cast<const BlkExprMapTy*>(BlkExprMap);
+}
+
+//===----------------------------------------------------------------------===//
+// CFG pretty printing
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class VISIBILITY_HIDDEN StmtPrinterHelper : public PrinterHelper {
+
+ typedef llvm::DenseMap<Stmt*,std::pair<unsigned,unsigned> > StmtMapTy;
+ StmtMapTy StmtMap;
+ signed CurrentBlock;
+ unsigned CurrentStmt;
+
+public:
+
+ StmtPrinterHelper(const CFG* cfg) : CurrentBlock(0), CurrentStmt(0) {
+ for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) {
+ unsigned j = 1;
+ for (CFGBlock::const_iterator BI = I->begin(), BEnd = I->end() ;
+ BI != BEnd; ++BI, ++j )
+ StmtMap[*BI] = std::make_pair(I->getBlockID(),j);
+ }
+ }
+
+ virtual ~StmtPrinterHelper() {}
+
+ void setBlockID(signed i) { CurrentBlock = i; }
+ void setStmtID(unsigned i) { CurrentStmt = i; }
+
+ virtual bool handledStmt(Stmt* Terminator, llvm::raw_ostream& OS) {
+
+ StmtMapTy::iterator I = StmtMap.find(Terminator);
+
+ if (I == StmtMap.end())
+ return false;
+
+ if (CurrentBlock >= 0 && I->second.first == (unsigned) CurrentBlock
+ && I->second.second == CurrentStmt)
+ return false;
+
+ OS << "[B" << I->second.first << "." << I->second.second << "]";
+ return true;
+ }
+};
+
+class VISIBILITY_HIDDEN CFGBlockTerminatorPrint
+ : public StmtVisitor<CFGBlockTerminatorPrint,void> {
+
+ llvm::raw_ostream& OS;
+ StmtPrinterHelper* Helper;
+ PrintingPolicy Policy;
+
+public:
+ CFGBlockTerminatorPrint(llvm::raw_ostream& os, StmtPrinterHelper* helper,
+ const PrintingPolicy &Policy = PrintingPolicy())
+ : OS(os), Helper(helper), Policy(Policy) {}
+
+ void VisitIfStmt(IfStmt* I) {
+ OS << "if ";
+ I->getCond()->printPretty(OS,Helper,Policy);
+ }
+
+ // Default case.
+ void VisitStmt(Stmt* Terminator) { Terminator->printPretty(OS, Helper, Policy); }
+
+ void VisitForStmt(ForStmt* F) {
+ OS << "for (" ;
+ if (F->getInit()) OS << "...";
+ OS << "; ";
+ if (Stmt* C = F->getCond()) C->printPretty(OS, Helper, Policy);
+ OS << "; ";
+ if (F->getInc()) OS << "...";
+ OS << ")";
+ }
+
+ void VisitWhileStmt(WhileStmt* W) {
+ OS << "while " ;
+ if (Stmt* C = W->getCond()) C->printPretty(OS, Helper, Policy);
+ }
+
+ void VisitDoStmt(DoStmt* D) {
+ OS << "do ... while ";
+ if (Stmt* C = D->getCond()) C->printPretty(OS, Helper, Policy);
+ }
+
+ void VisitSwitchStmt(SwitchStmt* Terminator) {
+ OS << "switch ";
+ Terminator->getCond()->printPretty(OS, Helper, Policy);
+ }
+
+ void VisitConditionalOperator(ConditionalOperator* C) {
+ C->getCond()->printPretty(OS, Helper, Policy);
+ OS << " ? ... : ...";
+ }
+
+ void VisitChooseExpr(ChooseExpr* C) {
+ OS << "__builtin_choose_expr( ";
+ C->getCond()->printPretty(OS, Helper, Policy);
+ OS << " )";
+ }
+
+ void VisitIndirectGotoStmt(IndirectGotoStmt* I) {
+ OS << "goto *";
+ I->getTarget()->printPretty(OS, Helper, Policy);
+ }
+
+ void VisitBinaryOperator(BinaryOperator* B) {
+ if (!B->isLogicalOp()) {
+ VisitExpr(B);
+ return;
+ }
+
+ B->getLHS()->printPretty(OS, Helper, Policy);
+
+ switch (B->getOpcode()) {
+ case BinaryOperator::LOr:
+ OS << " || ...";
+ return;
+ case BinaryOperator::LAnd:
+ OS << " && ...";
+ return;
+ default:
+ assert(false && "Invalid logical operator.");
+ }
+ }
+
+ void VisitExpr(Expr* E) {
+ E->printPretty(OS, Helper, Policy);
+ }
+};
+
+
+void print_stmt(llvm::raw_ostream&OS, StmtPrinterHelper* Helper, Stmt* Terminator) {
+ if (Helper) {
+ // special printing for statement-expressions.
+ if (StmtExpr* SE = dyn_cast<StmtExpr>(Terminator)) {
+ CompoundStmt* Sub = SE->getSubStmt();
+
+ if (Sub->child_begin() != Sub->child_end()) {
+ OS << "({ ... ; ";
+ Helper->handledStmt(*SE->getSubStmt()->body_rbegin(),OS);
+ OS << " })\n";
+ return;
+ }
+ }
+
+ // special printing for comma expressions.
+ if (BinaryOperator* B = dyn_cast<BinaryOperator>(Terminator)) {
+ if (B->getOpcode() == BinaryOperator::Comma) {
+ OS << "... , ";
+ Helper->handledStmt(B->getRHS(),OS);
+ OS << '\n';
+ return;
+ }
+ }
+ }
+
+ Terminator->printPretty(OS, Helper, /*FIXME:*/PrintingPolicy());
+
+ // Expressions need a newline.
+ if (isa<Expr>(Terminator)) OS << '\n';
+}
+
+void print_block(llvm::raw_ostream& OS, const CFG* cfg, const CFGBlock& B,
+ StmtPrinterHelper* Helper, bool print_edges) {
+
+ if (Helper) Helper->setBlockID(B.getBlockID());
+
+ // Print the header.
+ OS << "\n [ B" << B.getBlockID();
+
+ if (&B == &cfg->getEntry())
+ OS << " (ENTRY) ]\n";
+ else if (&B == &cfg->getExit())
+ OS << " (EXIT) ]\n";
+ else if (&B == cfg->getIndirectGotoBlock())
+ OS << " (INDIRECT GOTO DISPATCH) ]\n";
+ else
+ OS << " ]\n";
+
+ // Print the label of this block.
+ if (Stmt* Terminator = const_cast<Stmt*>(B.getLabel())) {
+
+ if (print_edges)
+ OS << " ";
+
+ if (LabelStmt* L = dyn_cast<LabelStmt>(Terminator))
+ OS << L->getName();
+ else if (CaseStmt* C = dyn_cast<CaseStmt>(Terminator)) {
+ OS << "case ";
+ C->getLHS()->printPretty(OS, Helper, /*FIXME:*/PrintingPolicy());
+ if (C->getRHS()) {
+ OS << " ... ";
+ C->getRHS()->printPretty(OS, Helper, /*FIXME:*/PrintingPolicy());
+ }
+ }
+ else if (isa<DefaultStmt>(Terminator))
+ OS << "default";
+ else
+ assert(false && "Invalid label statement in CFGBlock.");
+
+ OS << ":\n";
+ }
+
+ // Iterate through the statements in the block and print them.
+ unsigned j = 1;
+
+ for (CFGBlock::const_iterator I = B.begin(), E = B.end() ;
+ I != E ; ++I, ++j ) {
+
+ // Print the statement # in the basic block and the statement itself.
+ if (print_edges)
+ OS << " ";
+
+ OS << llvm::format("%3d", j) << ": ";
+
+ if (Helper)
+ Helper->setStmtID(j);
+
+ print_stmt(OS,Helper,*I);
+ }
+
+ // Print the terminator of this block.
+ if (B.getTerminator()) {
+ if (print_edges)
+ OS << " ";
+
+ OS << " T: ";
+
+ if (Helper) Helper->setBlockID(-1);
+
+ CFGBlockTerminatorPrint TPrinter(OS, Helper, /*FIXME*/PrintingPolicy());
+ TPrinter.Visit(const_cast<Stmt*>(B.getTerminator()));
+ OS << '\n';
+ }
+
+ if (print_edges) {
+ // Print the predecessors of this block.
+ OS << " Predecessors (" << B.pred_size() << "):";
+ unsigned i = 0;
+
+ for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.pred_end();
+ I != E; ++I, ++i) {
+
+ if (i == 8 || (i-8) == 0)
+ OS << "\n ";
+
+ OS << " B" << (*I)->getBlockID();
+ }
+
+ OS << '\n';
+
+ // Print the successors of this block.
+ OS << " Successors (" << B.succ_size() << "):";
+ i = 0;
+
+ for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end();
+ I != E; ++I, ++i) {
+
+ if (i == 8 || (i-8) % 10 == 0)
+ OS << "\n ";
+
+ OS << " B" << (*I)->getBlockID();
+ }
+
+ OS << '\n';
+ }
+}
+
+} // end anonymous namespace
+
+/// dump - A simple pretty printer of a CFG that outputs to stderr.
+void CFG::dump() const { print(llvm::errs()); }
+
+/// print - A simple pretty printer of a CFG that outputs to an ostream.
+void CFG::print(llvm::raw_ostream& OS) const {
+
+ StmtPrinterHelper Helper(this);
+
+ // Print the entry block.
+ print_block(OS, this, getEntry(), &Helper, true);
+
+ // Iterate through the CFGBlocks and print them one by one.
+ for (const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) {
+ // Skip the entry block, because we already printed it.
+ if (&(*I) == &getEntry() || &(*I) == &getExit())
+ continue;
+
+ print_block(OS, this, *I, &Helper, true);
+ }
+
+ // Print the exit block.
+ print_block(OS, this, getExit(), &Helper, true);
+ OS.flush();
+}
+
+/// dump - A simply pretty printer of a CFGBlock that outputs to stderr.
+void CFGBlock::dump(const CFG* cfg) const { print(llvm::errs(), cfg); }
+
+/// 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) const {
+ StmtPrinterHelper Helper(cfg);
+ 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) const {
+ CFGBlockTerminatorPrint TPrinter(OS,NULL);
+ TPrinter.Visit(const_cast<Stmt*>(getTerminator()));
+}
+
+Stmt* CFGBlock::getTerminatorCondition() {
+
+ if (!Terminator)
+ return NULL;
+
+ Expr* E = NULL;
+
+ switch (Terminator->getStmtClass()) {
+ default:
+ break;
+
+ case Stmt::ForStmtClass:
+ E = cast<ForStmt>(Terminator)->getCond();
+ break;
+
+ case Stmt::WhileStmtClass:
+ E = cast<WhileStmt>(Terminator)->getCond();
+ break;
+
+ case Stmt::DoStmtClass:
+ E = cast<DoStmt>(Terminator)->getCond();
+ break;
+
+ case Stmt::IfStmtClass:
+ E = cast<IfStmt>(Terminator)->getCond();
+ break;
+
+ case Stmt::ChooseExprClass:
+ E = cast<ChooseExpr>(Terminator)->getCond();
+ break;
+
+ case Stmt::IndirectGotoStmtClass:
+ E = cast<IndirectGotoStmt>(Terminator)->getTarget();
+ break;
+
+ case Stmt::SwitchStmtClass:
+ E = cast<SwitchStmt>(Terminator)->getCond();
+ break;
+
+ case Stmt::ConditionalOperatorClass:
+ E = cast<ConditionalOperator>(Terminator)->getCond();
+ break;
+
+ case Stmt::BinaryOperatorClass: // '&&' and '||'
+ E = cast<BinaryOperator>(Terminator)->getLHS();
+ break;
+
+ case Stmt::ObjCForCollectionStmtClass:
+ return Terminator;
+ }
+
+ return E ? E->IgnoreParens() : NULL;
+}
+
+bool CFGBlock::hasBinaryBranchTerminator() const {
+
+ if (!Terminator)
+ return false;
+
+ Expr* E = NULL;
+
+ switch (Terminator->getStmtClass()) {
+ default:
+ return false;
+
+ case Stmt::ForStmtClass:
+ case Stmt::WhileStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::IfStmtClass:
+ case Stmt::ChooseExprClass:
+ case Stmt::ConditionalOperatorClass:
+ case Stmt::BinaryOperatorClass:
+ return true;
+ }
+
+ return E ? E->IgnoreParens() : NULL;
+}
+
+
+//===----------------------------------------------------------------------===//
+// CFG Graphviz Visualization
+//===----------------------------------------------------------------------===//
+
+
+#ifndef NDEBUG
+static StmtPrinterHelper* GraphHelper;
+#endif
+
+void CFG::viewCFG() const {
+#ifndef NDEBUG
+ StmtPrinterHelper H(this);
+ GraphHelper = &H;
+ llvm::ViewGraph(this,"CFG");
+ GraphHelper = NULL;
+#endif
+}
+
+namespace llvm {
+template<>
+struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits {
+ static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph) {
+
+#ifndef NDEBUG
+ std::string OutSStr;
+ llvm::raw_string_ostream Out(OutSStr);
+ print_block(Out,Graph, *Node, GraphHelper, false);
+ std::string& OutStr = Out.str();
+
+ if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
+
+ // Process string output to make it nicer...
+ for (unsigned i = 0; i != OutStr.length(); ++i)
+ if (OutStr[i] == '\n') { // Left justify
+ OutStr[i] = '\\';
+ OutStr.insert(OutStr.begin()+i+1, 'l');
+ }
+
+ return OutStr;
+#else
+ return "";
+#endif
+ }
+};
+} // end namespace llvm
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
new file mode 100644
index 000000000000..19ab9f650eda
--- /dev/null
+++ b/lib/AST/CMakeLists.txt
@@ -0,0 +1,32 @@
+set(LLVM_NO_RTTI 1)
+
+add_clang_library(clangAST
+ APValue.cpp
+ ASTConsumer.cpp
+ ASTContext.cpp
+ Builtins.cpp
+ CFG.cpp
+ DeclarationName.cpp
+ DeclBase.cpp
+ Decl.cpp
+ DeclCXX.cpp
+ DeclGroup.cpp
+ DeclObjC.cpp
+ DeclPrinter.cpp
+ DeclTemplate.cpp
+ ExprConstant.cpp
+ Expr.cpp
+ ExprCXX.cpp
+ InheritViz.cpp
+ NestedNameSpecifier.cpp
+ ParentMap.cpp
+ Stmt.cpp
+ StmtDumper.cpp
+ StmtIterator.cpp
+ StmtPrinter.cpp
+ StmtViz.cpp
+ TemplateName.cpp
+ Type.cpp
+ )
+
+add_dependencies(clangAST ClangDiagnosticAST)
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
new file mode 100644
index 000000000000..cb3ec1f487da
--- /dev/null
+++ b/lib/AST/Decl.cpp
@@ -0,0 +1,630 @@
+//===--- Decl.cpp - Declaration AST Node Implementation -------------------===//
+//
+// 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 Decl subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/Basic/IdentifierTable.h"
+#include <vector>
+
+using namespace clang;
+
+void Attr::Destroy(ASTContext &C) {
+ if (Next) {
+ Next->Destroy(C);
+ Next = 0;
+ }
+ this->~Attr();
+ C.Deallocate((void*)this);
+}
+
+
+//===----------------------------------------------------------------------===//
+// Decl Allocation/Deallocation Method Implementations
+//===----------------------------------------------------------------------===//
+
+
+TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) {
+ return new (C) TranslationUnitDecl();
+}
+
+NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id) {
+ return new (C) NamespaceDecl(DC, L, Id);
+}
+
+void NamespaceDecl::Destroy(ASTContext& C) {
+ // NamespaceDecl uses "NextDeclarator" to chain namespace declarations
+ // together. They are all top-level Decls.
+
+ this->~NamespaceDecl();
+ C.Deallocate((void *)this);
+}
+
+
+ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id, QualType T) {
+ return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T);
+}
+
+const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
+ switch (SC) {
+ case VarDecl::None: break;
+ case VarDecl::Auto: return "auto"; break;
+ case VarDecl::Extern: return "extern"; break;
+ case VarDecl::PrivateExtern: return "__private_extern__"; break;
+ case VarDecl::Register: return "register"; break;
+ case VarDecl::Static: return "static"; break;
+ }
+
+ assert(0 && "Invalid storage class");
+ return 0;
+}
+
+ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ QualType T, StorageClass S,
+ Expr *DefArg) {
+ return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, S, DefArg);
+}
+
+QualType ParmVarDecl::getOriginalType() const {
+ if (const OriginalParmVarDecl *PVD =
+ dyn_cast<OriginalParmVarDecl>(this))
+ return PVD->OriginalType;
+ return getType();
+}
+
+void VarDecl::setInit(ASTContext &C, Expr *I) {
+ if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) {
+ Eval->~EvaluatedStmt();
+ C.Deallocate(Eval);
+ }
+
+ Init = I;
+ }
+
+bool VarDecl::isExternC(ASTContext &Context) const {
+ if (!Context.getLangOptions().CPlusPlus)
+ return (getDeclContext()->isTranslationUnit() &&
+ getStorageClass() != Static) ||
+ (getDeclContext()->isFunctionOrMethod() && hasExternalStorage());
+
+ for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit();
+ DC = DC->getParent()) {
+ if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) {
+ if (Linkage->getLanguage() == LinkageSpecDecl::lang_c)
+ return getStorageClass() != Static;
+
+ break;
+ }
+
+ if (DC->isFunctionOrMethod())
+ return false;
+ }
+
+ return false;
+}
+
+OriginalParmVarDecl *OriginalParmVarDecl::Create(
+ ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ QualType T, QualType OT, StorageClass S,
+ Expr *DefArg) {
+ return new (C) OriginalParmVarDecl(DC, L, Id, T, OT, S, DefArg);
+}
+
+FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ DeclarationName N, QualType T,
+ StorageClass S, bool isInline,
+ bool hasWrittenPrototype,
+ SourceLocation TypeSpecStartLoc) {
+ FunctionDecl *New
+ = new (C) FunctionDecl(Function, DC, L, N, T, S, isInline,
+ TypeSpecStartLoc);
+ New->HasWrittenPrototype = hasWrittenPrototype;
+ return New;
+}
+
+BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
+ return new (C) BlockDecl(DC, L);
+}
+
+FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType T, Expr *BW,
+ bool Mutable) {
+ return new (C) FieldDecl(Decl::Field, DC, L, Id, T, BW, Mutable);
+}
+
+bool FieldDecl::isAnonymousStructOrUnion() const {
+ if (!isImplicit() || getDeclName())
+ return false;
+
+ if (const RecordType *Record = getType()->getAsRecordType())
+ return Record->getDecl()->isAnonymousStructOrUnion();
+
+ return false;
+}
+
+EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
+ SourceLocation L,
+ IdentifierInfo *Id, QualType T,
+ Expr *E, const llvm::APSInt &V) {
+ return new (C) EnumConstantDecl(CD, L, Id, T, E, V);
+}
+
+void EnumConstantDecl::Destroy(ASTContext& C) {
+ if (Init) Init->Destroy(C);
+ Decl::Destroy(C);
+}
+
+TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ IdentifierInfo *Id, QualType T) {
+ return new (C) TypedefDecl(DC, L, Id, T);
+}
+
+EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id,
+ EnumDecl *PrevDecl) {
+ EnumDecl *Enum = new (C) EnumDecl(DC, L, Id);
+ C.getTypeDeclType(Enum, PrevDecl);
+ return Enum;
+}
+
+void EnumDecl::Destroy(ASTContext& C) {
+ Decl::Destroy(C);
+}
+
+void EnumDecl::completeDefinition(ASTContext &C, QualType NewType) {
+ assert(!isDefinition() && "Cannot redefine enums!");
+ IntegerType = NewType;
+ TagDecl::completeDefinition();
+}
+
+FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ StringLiteral *Str) {
+ return new (C) FileScopeAsmDecl(DC, L, Str);
+}
+
+//===----------------------------------------------------------------------===//
+// NamedDecl Implementation
+//===----------------------------------------------------------------------===//
+
+std::string NamedDecl::getQualifiedNameAsString() const {
+ std::vector<std::string> Names;
+ std::string QualName;
+ const DeclContext *Ctx = getDeclContext();
+
+ if (Ctx->isFunctionOrMethod())
+ return getNameAsString();
+
+ while (Ctx) {
+ if (Ctx->isFunctionOrMethod())
+ // FIXME: That probably will happen, when D was member of local
+ // scope class/struct/union. How do we handle this case?
+ break;
+
+ if (const ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ PrintingPolicy Policy;
+ Policy.CPlusPlus = true;
+ std::string TemplateArgsStr
+ = TemplateSpecializationType::PrintTemplateArgumentList(
+ TemplateArgs.getFlatArgumentList(),
+ TemplateArgs.flat_size(),
+ Policy);
+ Names.push_back(Spec->getIdentifier()->getName() + TemplateArgsStr);
+ } else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx))
+ Names.push_back(ND->getNameAsString());
+ else
+ break;
+
+ Ctx = Ctx->getParent();
+ }
+
+ std::vector<std::string>::reverse_iterator
+ I = Names.rbegin(),
+ End = Names.rend();
+
+ for (; I!=End; ++I)
+ QualName += *I + "::";
+
+ QualName += getNameAsString();
+
+ return QualName;
+}
+
+
+bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
+ assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch");
+
+ // UsingDirectiveDecl's are not really NamedDecl's, and all have same name.
+ // We want to keep it, unless it nominates same namespace.
+ if (getKind() == Decl::UsingDirective) {
+ return cast<UsingDirectiveDecl>(this)->getNominatedNamespace() ==
+ cast<UsingDirectiveDecl>(OldD)->getNominatedNamespace();
+ }
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this))
+ // For function declarations, we keep track of redeclarations.
+ return FD->getPreviousDeclaration() == OldD;
+
+ // For method declarations, we keep track of redeclarations.
+ if (isa<ObjCMethodDecl>(this))
+ return false;
+
+ // For non-function declarations, if the declarations are of the
+ // same kind then this must be a redeclaration, or semantic analysis
+ // would not have given us the new declaration.
+ return this->getKind() == OldD->getKind();
+}
+
+bool NamedDecl::hasLinkage() const {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(this))
+ return VD->hasExternalStorage() || VD->isFileVarDecl();
+
+ if (isa<FunctionDecl>(this) && !isa<CXXMethodDecl>(this))
+ return true;
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// VarDecl Implementation
+//===----------------------------------------------------------------------===//
+
+VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType T, StorageClass S,
+ SourceLocation TypeSpecStartLoc) {
+ return new (C) VarDecl(Var, DC, L, Id, T, S, TypeSpecStartLoc);
+}
+
+void VarDecl::Destroy(ASTContext& C) {
+ Expr *Init = getInit();
+ if (Init) {
+ Init->Destroy(C);
+ if (EvaluatedStmt *Eval = this->Init.dyn_cast<EvaluatedStmt *>()) {
+ Eval->~EvaluatedStmt();
+ C.Deallocate(Eval);
+ }
+ }
+ this->~VarDecl();
+ C.Deallocate((void *)this);
+}
+
+VarDecl::~VarDecl() {
+}
+
+bool VarDecl::isTentativeDefinition(ASTContext &Context) const {
+ if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus)
+ return false;
+
+ const VarDecl *Def = 0;
+ return (!getDefinition(Def) &&
+ (getStorageClass() == None || getStorageClass() == Static));
+}
+
+const Expr *VarDecl::getDefinition(const VarDecl *&Def) const {
+ Def = this;
+ while (Def && !Def->getInit())
+ Def = Def->getPreviousDeclaration();
+
+ return Def? Def->getInit() : 0;
+}
+
+//===----------------------------------------------------------------------===//
+// FunctionDecl Implementation
+//===----------------------------------------------------------------------===//
+
+void FunctionDecl::Destroy(ASTContext& C) {
+ if (Body && Body.isOffset())
+ Body.get(C.getExternalSource())->Destroy(C);
+
+ for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I)
+ (*I)->Destroy(C);
+
+ C.Deallocate(ParamInfo);
+
+ Decl::Destroy(C);
+}
+
+
+Stmt *FunctionDecl::getBody(ASTContext &Context,
+ const FunctionDecl *&Definition) const {
+ for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) {
+ if (FD->Body) {
+ Definition = FD;
+ return FD->Body.get(Context.getExternalSource());
+ }
+ }
+
+ return 0;
+}
+
+Stmt *FunctionDecl::getBodyIfAvailable() const {
+ for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) {
+ if (FD->Body && !FD->Body.isOffset()) {
+ return FD->Body.get(0);
+ }
+ }
+
+ return 0;
+}
+
+bool FunctionDecl::isMain() const {
+ return getDeclContext()->getLookupContext()->isTranslationUnit() &&
+ getIdentifier() && getIdentifier()->isStr("main");
+}
+
+bool FunctionDecl::isExternC(ASTContext &Context) const {
+ // In C, any non-static, non-overloadable function has external
+ // linkage.
+ if (!Context.getLangOptions().CPlusPlus)
+ return getStorageClass() != Static && !getAttr<OverloadableAttr>();
+
+ for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit();
+ DC = DC->getParent()) {
+ if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) {
+ if (Linkage->getLanguage() == LinkageSpecDecl::lang_c)
+ return getStorageClass() != Static && !getAttr<OverloadableAttr>();
+
+ break;
+ }
+ }
+
+ return false;
+}
+
+bool FunctionDecl::isGlobal() const {
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(this))
+ return Method->isStatic();
+
+ if (getStorageClass() == Static)
+ return false;
+
+ for (const DeclContext *DC = getDeclContext();
+ DC->isNamespace();
+ DC = DC->getParent()) {
+ if (const NamespaceDecl *Namespace = cast<NamespaceDecl>(DC)) {
+ if (!Namespace->getDeclName())
+ return false;
+ break;
+ }
+ }
+
+ return true;
+}
+
+/// \brief Returns a value indicating whether this function
+/// corresponds to a builtin function.
+///
+/// The function corresponds to a built-in function if it is
+/// declared at translation scope or within an extern "C" block and
+/// its name matches with the name of a builtin. The returned value
+/// will be 0 for functions that do not correspond to a builtin, a
+/// value of type \c Builtin::ID if in the target-independent range
+/// \c [1,Builtin::First), or a target-specific builtin value.
+unsigned FunctionDecl::getBuiltinID(ASTContext &Context) const {
+ if (!getIdentifier() || !getIdentifier()->getBuiltinID())
+ return 0;
+
+ unsigned BuiltinID = getIdentifier()->getBuiltinID();
+ if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
+ return BuiltinID;
+
+ // This function has the name of a known C library
+ // function. Determine whether it actually refers to the C library
+ // function or whether it just has the same name.
+
+ // If this is a static function, it's not a builtin.
+ if (getStorageClass() == Static)
+ return 0;
+
+ // If this function is at translation-unit scope and we're not in
+ // C++, it refers to the C library function.
+ if (!Context.getLangOptions().CPlusPlus &&
+ getDeclContext()->isTranslationUnit())
+ return BuiltinID;
+
+ // If the function is in an extern "C" linkage specification and is
+ // not marked "overloadable", it's the real function.
+ if (isa<LinkageSpecDecl>(getDeclContext()) &&
+ cast<LinkageSpecDecl>(getDeclContext())->getLanguage()
+ == LinkageSpecDecl::lang_c &&
+ !getAttr<OverloadableAttr>())
+ return BuiltinID;
+
+ // Not a builtin
+ return 0;
+}
+
+
+/// getNumParams - Return the number of parameters this function must have
+/// based on its FunctionType. This is the length of the PararmInfo array
+/// after it has been created.
+unsigned FunctionDecl::getNumParams() const {
+ const FunctionType *FT = getType()->getAsFunctionType();
+ if (isa<FunctionNoProtoType>(FT))
+ return 0;
+ return cast<FunctionProtoType>(FT)->getNumArgs();
+
+}
+
+void FunctionDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo,
+ unsigned NumParams) {
+ assert(ParamInfo == 0 && "Already has param info!");
+ assert(NumParams == 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);
+ }
+}
+
+/// getMinRequiredArguments - Returns the minimum number of arguments
+/// needed to call this function. This may be fewer than the number of
+/// function parameters, if some of the parameters have default
+/// arguments (in C++).
+unsigned FunctionDecl::getMinRequiredArguments() const {
+ unsigned NumRequiredArgs = getNumParams();
+ while (NumRequiredArgs > 0
+ && getParamDecl(NumRequiredArgs-1)->getDefaultArg())
+ --NumRequiredArgs;
+
+ return NumRequiredArgs;
+}
+
+bool FunctionDecl::hasActiveGNUInlineAttribute() const {
+ if (!isInline() || !hasAttr<GNUInlineAttr>())
+ return false;
+
+ for (const FunctionDecl *FD = getPreviousDeclaration(); FD;
+ FD = FD->getPreviousDeclaration()) {
+ if (FD->isInline() && !FD->hasAttr<GNUInlineAttr>())
+ return false;
+ }
+
+ return true;
+}
+
+bool FunctionDecl::isExternGNUInline() const {
+ if (!hasActiveGNUInlineAttribute())
+ return false;
+
+ for (const FunctionDecl *FD = this; FD; FD = FD->getPreviousDeclaration())
+ if (FD->getStorageClass() == Extern && FD->hasAttr<GNUInlineAttr>())
+ return true;
+
+ return false;
+}
+
+/// getOverloadedOperator - Which C++ overloaded operator this
+/// function represents, if any.
+OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
+ if (getDeclName().getNameKind() == DeclarationName::CXXOperatorName)
+ return getDeclName().getCXXOverloadedOperator();
+ else
+ return OO_None;
+}
+
+//===----------------------------------------------------------------------===//
+// TagDecl Implementation
+//===----------------------------------------------------------------------===//
+
+void TagDecl::startDefinition() {
+ TagType *TagT = const_cast<TagType *>(TypeForDecl->getAsTagType());
+ TagT->decl.setPointer(this);
+ TagT->getAsTagType()->decl.setInt(1);
+}
+
+void TagDecl::completeDefinition() {
+ assert((!TypeForDecl ||
+ TypeForDecl->getAsTagType()->decl.getPointer() == this) &&
+ "Attempt to redefine a tag definition?");
+ IsDefinition = true;
+ TagType *TagT = const_cast<TagType *>(TypeForDecl->getAsTagType());
+ TagT->decl.setPointer(this);
+ TagT->decl.setInt(0);
+}
+
+TagDecl* TagDecl::getDefinition(ASTContext& C) const {
+ QualType T = C.getTypeDeclType(const_cast<TagDecl*>(this));
+ TagDecl* D = cast<TagDecl>(T->getAsTagType()->getDecl());
+ return D->isDefinition() ? D : 0;
+}
+
+//===----------------------------------------------------------------------===//
+// RecordDecl Implementation
+//===----------------------------------------------------------------------===//
+
+RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id)
+ : TagDecl(DK, TK, DC, L, Id) {
+ HasFlexibleArrayMember = false;
+ AnonymousStructOrUnion = false;
+ assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
+}
+
+RecordDecl *RecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ RecordDecl* PrevDecl) {
+
+ RecordDecl* R = new (C) RecordDecl(Record, TK, DC, L, Id);
+ C.getTypeDeclType(R, PrevDecl);
+ return R;
+}
+
+RecordDecl::~RecordDecl() {
+}
+
+void RecordDecl::Destroy(ASTContext& C) {
+ TagDecl::Destroy(C);
+}
+
+bool RecordDecl::isInjectedClassName() const {
+ return isImplicit() && getDeclName() && getDeclContext()->isRecord() &&
+ cast<RecordDecl>(getDeclContext())->getDeclName() == getDeclName();
+}
+
+/// completeDefinition - Notes that the definition of this type is now
+/// complete.
+void RecordDecl::completeDefinition(ASTContext& C) {
+ assert(!isDefinition() && "Cannot redefine record!");
+ TagDecl::completeDefinition();
+}
+
+//===----------------------------------------------------------------------===//
+// BlockDecl Implementation
+//===----------------------------------------------------------------------===//
+
+BlockDecl::~BlockDecl() {
+}
+
+void BlockDecl::Destroy(ASTContext& C) {
+ if (Body)
+ Body->Destroy(C);
+
+ for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I)
+ (*I)->Destroy(C);
+
+ C.Deallocate(ParamInfo);
+ Decl::Destroy(C);
+}
+
+void BlockDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo,
+ unsigned NParms) {
+ assert(ParamInfo == 0 && "Already has param info!");
+
+ // Zero params -> null pointer.
+ if (NParms) {
+ NumParams = NParms;
+ void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams);
+ ParamInfo = new (Mem) ParmVarDecl*[NumParams];
+ memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
+ }
+}
+
+unsigned BlockDecl::getNumParams() const {
+ return NumParams;
+}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
new file mode 100644
index 000000000000..fd7de715db7f
--- /dev/null
+++ b/lib/AST/DeclBase.cpp
@@ -0,0 +1,756 @@
+//===--- DeclBase.cpp - Declaration AST Node Implementation ---------------===//
+//
+// 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 Decl and DeclContext classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclContextInternals.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/StmtCXX.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstdio>
+#include <vector>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Statistics
+//===----------------------------------------------------------------------===//
+
+#define DECL(Derived, Base) static int n##Derived##s = 0;
+#include "clang/AST/DeclNodes.def"
+
+static bool StatSwitch = false;
+
+// This keeps track of all decl attributes. Since so few decls have attrs, we
+// keep them in a hash map instead of wasting space in the Decl class.
+typedef llvm::DenseMap<const Decl*, Attr*> DeclAttrMapTy;
+
+static DeclAttrMapTy *DeclAttrs = 0;
+
+const char *Decl::getDeclKindName() const {
+ switch (DeclKind) {
+ default: assert(0 && "Declaration not in DeclNodes.def!");
+#define DECL(Derived, Base) case Derived: return #Derived;
+#include "clang/AST/DeclNodes.def"
+ }
+}
+
+const char *DeclContext::getDeclKindName() const {
+ switch (DeclKind) {
+ default: assert(0 && "Declaration context not in DeclNodes.def!");
+#define DECL(Derived, Base) case Decl::Derived: return #Derived;
+#include "clang/AST/DeclNodes.def"
+ }
+}
+
+bool Decl::CollectingStats(bool Enable) {
+ if (Enable)
+ StatSwitch = true;
+ return StatSwitch;
+}
+
+void Decl::PrintStats() {
+ fprintf(stderr, "*** Decl Stats:\n");
+
+ int totalDecls = 0;
+#define DECL(Derived, Base) totalDecls += n##Derived##s;
+#include "clang/AST/DeclNodes.def"
+ fprintf(stderr, " %d decls total.\n", totalDecls);
+
+ int totalBytes = 0;
+#define DECL(Derived, Base) \
+ if (n##Derived##s > 0) { \
+ totalBytes += (int)(n##Derived##s * sizeof(Derived##Decl)); \
+ fprintf(stderr, " %d " #Derived " decls, %d each (%d bytes)\n", \
+ n##Derived##s, (int)sizeof(Derived##Decl), \
+ (int)(n##Derived##s * sizeof(Derived##Decl))); \
+ }
+#include "clang/AST/DeclNodes.def"
+
+ fprintf(stderr, "Total bytes = %d\n", totalBytes);
+}
+
+void Decl::addDeclKind(Kind k) {
+ switch (k) {
+ default: assert(0 && "Declaration not in DeclNodes.def!");
+#define DECL(Derived, Base) case Derived: ++n##Derived##s; break;
+#include "clang/AST/DeclNodes.def"
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// PrettyStackTraceDecl Implementation
+//===----------------------------------------------------------------------===//
+
+void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const {
+ SourceLocation TheLoc = Loc;
+ if (TheLoc.isInvalid() && TheDecl)
+ TheLoc = TheDecl->getLocation();
+
+ if (TheLoc.isValid()) {
+ TheLoc.print(OS, SM);
+ OS << ": ";
+ }
+
+ OS << Message;
+
+ if (NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl))
+ OS << " '" << DN->getQualifiedNameAsString() << '\'';
+ OS << '\n';
+}
+
+//===----------------------------------------------------------------------===//
+// Decl Implementation
+//===----------------------------------------------------------------------===//
+
+// Out-of-line virtual method providing a home for Decl.
+Decl::~Decl() {
+ if (isOutOfSemaDC())
+ delete getMultipleDC();
+
+ assert(!HasAttrs && "attributes should have been freed by Destroy");
+}
+
+void Decl::setDeclContext(DeclContext *DC) {
+ if (isOutOfSemaDC())
+ delete getMultipleDC();
+
+ DeclCtx = DC;
+}
+
+void Decl::setLexicalDeclContext(DeclContext *DC) {
+ if (DC == getLexicalDeclContext())
+ return;
+
+ if (isInSemaDC()) {
+ MultipleDC *MDC = new MultipleDC();
+ MDC->SemanticDC = getDeclContext();
+ MDC->LexicalDC = DC;
+ DeclCtx = MDC;
+ } else {
+ getMultipleDC()->LexicalDC = DC;
+ }
+}
+
+unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
+ switch (DeclKind) {
+ default:
+ if (DeclKind >= FunctionFirst && DeclKind <= FunctionLast)
+ return IDNS_Ordinary;
+ assert(0 && "Unknown decl kind!");
+ case OverloadedFunction:
+ case Typedef:
+ case EnumConstant:
+ case Var:
+ case ImplicitParam:
+ case ParmVar:
+ case OriginalParmVar:
+ case NonTypeTemplateParm:
+ case ObjCMethod:
+ case ObjCContainer:
+ case ObjCCategory:
+ case ObjCInterface:
+ case ObjCProperty:
+ case ObjCCompatibleAlias:
+ return IDNS_Ordinary;
+
+ case ObjCProtocol:
+ return IDNS_ObjCProtocol;
+
+ case ObjCImplementation:
+ return IDNS_ObjCImplementation;
+
+ case ObjCCategoryImpl:
+ return IDNS_ObjCCategoryImpl;
+
+ case Field:
+ case ObjCAtDefsField:
+ case ObjCIvar:
+ return IDNS_Member;
+
+ case Record:
+ case CXXRecord:
+ case Enum:
+ case TemplateTypeParm:
+ return IDNS_Tag;
+
+ case Namespace:
+ case Template:
+ case FunctionTemplate:
+ case ClassTemplate:
+ case TemplateTemplateParm:
+ case NamespaceAlias:
+ return IDNS_Tag | IDNS_Ordinary;
+
+ // Never have names.
+ case LinkageSpec:
+ case FileScopeAsm:
+ case StaticAssert:
+ case ObjCClass:
+ case ObjCPropertyImpl:
+ case ObjCForwardProtocol:
+ case Block:
+ case TranslationUnit:
+
+ // Aren't looked up?
+ case UsingDirective:
+ case ClassTemplateSpecialization:
+ case ClassTemplatePartialSpecialization:
+ return 0;
+ }
+}
+
+void Decl::addAttr(Attr *NewAttr) {
+ if (!DeclAttrs)
+ DeclAttrs = new DeclAttrMapTy();
+
+ Attr *&ExistingAttr = (*DeclAttrs)[this];
+
+ NewAttr->setNext(ExistingAttr);
+ ExistingAttr = NewAttr;
+
+ HasAttrs = true;
+}
+
+void Decl::invalidateAttrs() {
+ if (!HasAttrs) return;
+
+ HasAttrs = false;
+ (*DeclAttrs)[this] = 0;
+ DeclAttrs->erase(this);
+
+ if (DeclAttrs->empty()) {
+ delete DeclAttrs;
+ DeclAttrs = 0;
+ }
+}
+
+const Attr *Decl::getAttrsImpl() const {
+ assert(HasAttrs && "getAttrs() should verify this!");
+ return (*DeclAttrs)[this];
+}
+
+void Decl::swapAttrs(Decl *RHS) {
+ bool HasLHSAttr = this->HasAttrs;
+ bool HasRHSAttr = RHS->HasAttrs;
+
+ // Usually, neither decl has attrs, nothing to do.
+ if (!HasLHSAttr && !HasRHSAttr) return;
+
+ // If 'this' has no attrs, swap the other way.
+ if (!HasLHSAttr)
+ return RHS->swapAttrs(this);
+
+ // Handle the case when both decls have attrs.
+ if (HasRHSAttr) {
+ std::swap((*DeclAttrs)[this], (*DeclAttrs)[RHS]);
+ return;
+ }
+
+ // Otherwise, LHS has an attr and RHS doesn't.
+ (*DeclAttrs)[RHS] = (*DeclAttrs)[this];
+ (*DeclAttrs).erase(this);
+ this->HasAttrs = false;
+ RHS->HasAttrs = true;
+}
+
+
+void Decl::Destroy(ASTContext &C) {
+ // Free attributes for this decl.
+ if (HasAttrs) {
+ DeclAttrMapTy::iterator it = DeclAttrs->find(this);
+ assert(it != DeclAttrs->end() && "No attrs found but HasAttrs is true!");
+
+ // release attributes.
+ it->second->Destroy(C);
+ invalidateAttrs();
+ HasAttrs = false;
+ }
+
+#if 0
+ // FIXME: Once ownership is fully understood, we can enable this code
+ if (DeclContext *DC = dyn_cast<DeclContext>(this))
+ DC->decls_begin()->Destroy(C);
+
+ // Observe the unrolled recursion. By setting N->NextDeclInContext = 0x0
+ // within the loop, only the Destroy method for the first Decl
+ // will deallocate all of the Decls in a chain.
+
+ Decl* N = getNextDeclInContext();
+
+ while (N) {
+ Decl* Tmp = N->getNextDeclInContext();
+ N->NextDeclInContext = 0;
+ N->Destroy(C);
+ N = Tmp;
+ }
+
+ this->~Decl();
+ C.Deallocate((void *)this);
+#endif
+}
+
+Decl *Decl::castFromDeclContext (const DeclContext *D) {
+ Decl::Kind DK = D->getDeclKind();
+ switch(DK) {
+#define DECL_CONTEXT(Name) \
+ case Decl::Name: \
+ return static_cast<Name##Decl*>(const_cast<DeclContext*>(D));
+#define DECL_CONTEXT_BASE(Name)
+#include "clang/AST/DeclNodes.def"
+ default:
+#define DECL_CONTEXT_BASE(Name) \
+ if (DK >= Decl::Name##First && DK <= Decl::Name##Last) \
+ return static_cast<Name##Decl*>(const_cast<DeclContext*>(D));
+#include "clang/AST/DeclNodes.def"
+ assert(false && "a decl that inherits DeclContext isn't handled");
+ return 0;
+ }
+}
+
+DeclContext *Decl::castToDeclContext(const Decl *D) {
+ Decl::Kind DK = D->getKind();
+ switch(DK) {
+#define DECL_CONTEXT(Name) \
+ case Decl::Name: \
+ return static_cast<Name##Decl*>(const_cast<Decl*>(D));
+#define DECL_CONTEXT_BASE(Name)
+#include "clang/AST/DeclNodes.def"
+ default:
+#define DECL_CONTEXT_BASE(Name) \
+ if (DK >= Decl::Name##First && DK <= Decl::Name##Last) \
+ return static_cast<Name##Decl*>(const_cast<Decl*>(D));
+#include "clang/AST/DeclNodes.def"
+ assert(false && "a decl that inherits DeclContext isn't handled");
+ return 0;
+ }
+}
+
+CompoundStmt* Decl::getCompoundBody(ASTContext &Context) const {
+ return dyn_cast_or_null<CompoundStmt>(getBody(Context));
+}
+
+SourceLocation Decl::getBodyRBrace(ASTContext &Context) const {
+ Stmt *Body = getBody(Context);
+ if (!Body)
+ return SourceLocation();
+ if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Body))
+ return CS->getRBracLoc();
+ assert(isa<CXXTryStmt>(Body) &&
+ "Body can only be CompoundStmt or CXXTryStmt");
+ return cast<CXXTryStmt>(Body)->getSourceRange().getEnd();
+}
+
+#ifndef NDEBUG
+void Decl::CheckAccessDeclContext() const {
+ assert((Access != AS_none || isa<TranslationUnitDecl>(this) ||
+ !isa<CXXRecordDecl>(getDeclContext())) &&
+ "Access specifier is AS_none inside a record decl");
+}
+
+#endif
+
+//===----------------------------------------------------------------------===//
+// DeclContext Implementation
+//===----------------------------------------------------------------------===//
+
+bool DeclContext::classof(const Decl *D) {
+ switch (D->getKind()) {
+#define DECL_CONTEXT(Name) case Decl::Name:
+#define DECL_CONTEXT_BASE(Name)
+#include "clang/AST/DeclNodes.def"
+ return true;
+ default:
+#define DECL_CONTEXT_BASE(Name) \
+ if (D->getKind() >= Decl::Name##First && \
+ D->getKind() <= Decl::Name##Last) \
+ return true;
+#include "clang/AST/DeclNodes.def"
+ return false;
+ }
+}
+
+DeclContext::~DeclContext() {
+ delete static_cast<StoredDeclsMap*>(LookupPtr);
+}
+
+void DeclContext::DestroyDecls(ASTContext &C) {
+ for (decl_iterator D = decls_begin(C); D != decls_end(C); )
+ (*D++)->Destroy(C);
+}
+
+bool DeclContext::isDependentContext() const {
+ if (isFileContext())
+ return false;
+
+ if (isa<ClassTemplatePartialSpecializationDecl>(this))
+ return true;
+
+ if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this))
+ if (Record->getDescribedClassTemplate())
+ return true;
+
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this))
+ if (Function->getDescribedFunctionTemplate())
+ return true;
+
+ return getParent() && getParent()->isDependentContext();
+}
+
+bool DeclContext::isTransparentContext() const {
+ if (DeclKind == Decl::Enum)
+ return true; // FIXME: Check for C++0x scoped enums
+ else if (DeclKind == Decl::LinkageSpec)
+ return true;
+ else if (DeclKind >= Decl::RecordFirst && DeclKind <= Decl::RecordLast)
+ return cast<RecordDecl>(this)->isAnonymousStructOrUnion();
+ else if (DeclKind == Decl::Namespace)
+ return false; // FIXME: Check for C++0x inline namespaces
+
+ return false;
+}
+
+DeclContext *DeclContext::getPrimaryContext() {
+ switch (DeclKind) {
+ case Decl::TranslationUnit:
+ case Decl::LinkageSpec:
+ case Decl::Block:
+ // There is only one DeclContext for these entities.
+ return this;
+
+ case Decl::Namespace:
+ // The original namespace is our primary context.
+ return static_cast<NamespaceDecl*>(this)->getOriginalNamespace();
+
+ case Decl::ObjCMethod:
+ return this;
+
+ case Decl::ObjCInterface:
+ case Decl::ObjCProtocol:
+ case Decl::ObjCCategory:
+ // FIXME: Can Objective-C interfaces be forward-declared?
+ return this;
+
+ case Decl::ObjCImplementation:
+ case Decl::ObjCCategoryImpl:
+ return this;
+
+ default:
+ if (DeclKind >= Decl::TagFirst && DeclKind <= Decl::TagLast) {
+ // If this is a tag type that has a definition or is currently
+ // being defined, that definition is our primary context.
+ if (const TagType *TagT =cast<TagDecl>(this)->TypeForDecl->getAsTagType())
+ if (TagT->isBeingDefined() ||
+ (TagT->getDecl() && TagT->getDecl()->isDefinition()))
+ return TagT->getDecl();
+ return this;
+ }
+
+ assert(DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast &&
+ "Unknown DeclContext kind");
+ return this;
+ }
+}
+
+DeclContext *DeclContext::getNextContext() {
+ switch (DeclKind) {
+ case Decl::Namespace:
+ // Return the next namespace
+ return static_cast<NamespaceDecl*>(this)->getNextNamespace();
+
+ default:
+ return 0;
+ }
+}
+
+/// \brief Load the declarations within this lexical storage from an
+/// external source.
+void
+DeclContext::LoadLexicalDeclsFromExternalStorage(ASTContext &Context) const {
+ ExternalASTSource *Source = Context.getExternalSource();
+ assert(hasExternalLexicalStorage() && Source && "No external storage?");
+
+ llvm::SmallVector<uint32_t, 64> Decls;
+ if (Source->ReadDeclsLexicallyInContext(const_cast<DeclContext *>(this),
+ Decls))
+ return;
+
+ // There is no longer any lexical storage in this context
+ ExternalLexicalStorage = false;
+
+ if (Decls.empty())
+ return;
+
+ // Resolve all of the declaration IDs into declarations, building 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) {
+ Decl *D = Source->GetDecl(Decls[I]);
+ if (PrevDecl)
+ PrevDecl->NextDeclInContext = D;
+ else
+ FirstNewDecl = D;
+
+ PrevDecl = D;
+ }
+
+ // Splice the newly-read declarations into the beginning of the list
+ // of declarations.
+ PrevDecl->NextDeclInContext = FirstDecl;
+ FirstDecl = FirstNewDecl;
+ if (!LastDecl)
+ LastDecl = PrevDecl;
+}
+
+void
+DeclContext::LoadVisibleDeclsFromExternalStorage(ASTContext &Context) const {
+ DeclContext *This = const_cast<DeclContext *>(this);
+ ExternalASTSource *Source = Context.getExternalSource();
+ assert(hasExternalVisibleStorage() && Source && "No external storage?");
+
+ llvm::SmallVector<VisibleDeclaration, 64> Decls;
+ if (Source->ReadDeclsVisibleInContext(This, Decls))
+ return;
+
+ // There is no longer any visible storage in this context
+ ExternalVisibleStorage = false;
+
+ // Load the declaration IDs for all of the names visible in this
+ // context.
+ assert(!LookupPtr && "Have a lookup map before de-serialization?");
+ StoredDeclsMap *Map = new StoredDeclsMap;
+ LookupPtr = Map;
+ for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
+ (*Map)[Decls[I].Name].setFromDeclIDs(Decls[I].Declarations);
+ }
+}
+
+DeclContext::decl_iterator DeclContext::decls_begin(ASTContext &Context) const {
+ if (hasExternalLexicalStorage())
+ LoadLexicalDeclsFromExternalStorage(Context);
+
+ // FIXME: Check whether we need to load some declarations from
+ // external storage.
+ return decl_iterator(FirstDecl);
+}
+
+DeclContext::decl_iterator DeclContext::decls_end(ASTContext &Context) const {
+ if (hasExternalLexicalStorage())
+ LoadLexicalDeclsFromExternalStorage(Context);
+
+ return decl_iterator();
+}
+
+bool DeclContext::decls_empty(ASTContext &Context) const {
+ if (hasExternalLexicalStorage())
+ LoadLexicalDeclsFromExternalStorage(Context);
+
+ return !FirstDecl;
+}
+
+void DeclContext::addDecl(ASTContext &Context, Decl *D) {
+ assert(D->getLexicalDeclContext() == this &&
+ "Decl inserted into wrong lexical context");
+ assert(!D->getNextDeclInContext() && D != LastDecl &&
+ "Decl already inserted into a DeclContext");
+
+ if (FirstDecl) {
+ LastDecl->NextDeclInContext = D;
+ LastDecl = D;
+ } else {
+ FirstDecl = LastDecl = D;
+ }
+
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ ND->getDeclContext()->makeDeclVisibleInContext(Context, ND);
+}
+
+/// buildLookup - Build the lookup data structure with all of the
+/// declarations in DCtx (and any other contexts linked to it or
+/// transparent contexts nested within it).
+void DeclContext::buildLookup(ASTContext &Context, DeclContext *DCtx) {
+ for (; DCtx; DCtx = DCtx->getNextContext()) {
+ for (decl_iterator D = DCtx->decls_begin(Context),
+ DEnd = DCtx->decls_end(Context);
+ D != DEnd; ++D) {
+ // Insert this declaration into the lookup structure
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
+ makeDeclVisibleInContextImpl(Context, ND);
+
+ // If this declaration is itself a transparent declaration context,
+ // add its members (recursively).
+ if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D))
+ if (InnerCtx->isTransparentContext())
+ buildLookup(Context, InnerCtx->getPrimaryContext());
+ }
+ }
+}
+
+DeclContext::lookup_result
+DeclContext::lookup(ASTContext &Context, DeclarationName Name) {
+ DeclContext *PrimaryContext = getPrimaryContext();
+ if (PrimaryContext != this)
+ return PrimaryContext->lookup(Context, Name);
+
+ if (hasExternalVisibleStorage())
+ LoadVisibleDeclsFromExternalStorage(Context);
+
+ /// If there is no lookup data structure, build one now by walking
+ /// all of the linked DeclContexts (in declaration order!) and
+ /// inserting their values.
+ if (!LookupPtr) {
+ buildLookup(Context, this);
+
+ if (!LookupPtr)
+ return lookup_result(0, 0);
+ }
+
+ StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(LookupPtr);
+ StoredDeclsMap::iterator Pos = Map->find(Name);
+ if (Pos == Map->end())
+ return lookup_result(0, 0);
+ return Pos->second.getLookupResult(Context);
+}
+
+DeclContext::lookup_const_result
+DeclContext::lookup(ASTContext &Context, DeclarationName Name) const {
+ return const_cast<DeclContext*>(this)->lookup(Context, Name);
+}
+
+DeclContext *DeclContext::getLookupContext() {
+ DeclContext *Ctx = this;
+ // Skip through transparent contexts.
+ while (Ctx->isTransparentContext())
+ Ctx = Ctx->getParent();
+ return Ctx;
+}
+
+DeclContext *DeclContext::getEnclosingNamespaceContext() {
+ DeclContext *Ctx = this;
+ // Skip through non-namespace, non-translation-unit contexts.
+ while (!Ctx->isFileContext() || Ctx->isTransparentContext())
+ Ctx = Ctx->getParent();
+ return Ctx->getPrimaryContext();
+}
+
+void DeclContext::makeDeclVisibleInContext(ASTContext &Context, NamedDecl *D) {
+ // FIXME: This feels like a hack. Should DeclarationName support
+ // template-ids, or is there a better way to keep specializations
+ // from being visible?
+ if (isa<ClassTemplateSpecializationDecl>(D))
+ return;
+
+ DeclContext *PrimaryContext = getPrimaryContext();
+ if (PrimaryContext != this) {
+ PrimaryContext->makeDeclVisibleInContext(Context, D);
+ return;
+ }
+
+ // If we already have a lookup data structure, perform the insertion
+ // into it. Otherwise, be lazy and don't build that structure until
+ // someone asks for it.
+ if (LookupPtr)
+ makeDeclVisibleInContextImpl(Context, D);
+
+ // If we are a transparent context, insert into our parent context,
+ // too. This operation is recursive.
+ if (isTransparentContext())
+ getParent()->makeDeclVisibleInContext(Context, D);
+}
+
+void DeclContext::makeDeclVisibleInContextImpl(ASTContext &Context,
+ NamedDecl *D) {
+ // Skip unnamed declarations.
+ if (!D->getDeclName())
+ return;
+
+ // FIXME: This feels like a hack. Should DeclarationName support
+ // template-ids, or is there a better way to keep specializations
+ // from being visible?
+ if (isa<ClassTemplateSpecializationDecl>(D))
+ return;
+
+ if (!LookupPtr)
+ LookupPtr = new StoredDeclsMap;
+
+ // Insert this declaration into the map.
+ StoredDeclsMap &Map = *static_cast<StoredDeclsMap*>(LookupPtr);
+ StoredDeclsList &DeclNameEntries = Map[D->getDeclName()];
+ if (DeclNameEntries.isNull()) {
+ DeclNameEntries.setOnlyValue(D);
+ return;
+ }
+
+ // If it is possible that this is a redeclaration, check to see if there is
+ // already a decl for which declarationReplaces returns true. If there is
+ // one, just replace it and return.
+ if (DeclNameEntries.HandleRedeclaration(Context, D))
+ return;
+
+ // Put this declaration into the appropriate slot.
+ DeclNameEntries.AddSubsequentDecl(D);
+}
+
+/// Returns iterator range [First, Last) of UsingDirectiveDecls stored within
+/// this context.
+DeclContext::udir_iterator_range
+DeclContext::getUsingDirectives(ASTContext &Context) const {
+ lookup_const_result Result = lookup(Context, UsingDirectiveDecl::getName());
+ return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first),
+ reinterpret_cast<udir_iterator>(Result.second));
+}
+
+void StoredDeclsList::materializeDecls(ASTContext &Context) {
+ if (isNull())
+ return;
+
+ switch ((DataKind)(Data & 0x03)) {
+ case DK_Decl:
+ case DK_Decl_Vector:
+ break;
+
+ case DK_DeclID: {
+ // Resolve this declaration ID to an actual declaration by
+ // querying the external AST source.
+ unsigned DeclID = Data >> 2;
+
+ ExternalASTSource *Source = Context.getExternalSource();
+ assert(Source && "No external AST source available!");
+
+ Data = reinterpret_cast<uintptr_t>(Source->GetDecl(DeclID));
+ break;
+ }
+
+ case DK_ID_Vector: {
+ // We have a vector of declaration IDs. Resolve all of them to
+ // actual declarations.
+ VectorTy &Vector = *getAsVector();
+ ExternalASTSource *Source = Context.getExternalSource();
+ assert(Source && "No external AST source available!");
+
+ for (unsigned I = 0, N = Vector.size(); I != N; ++I)
+ Vector[I] = reinterpret_cast<uintptr_t>(Source->GetDecl(Vector[I]));
+
+ Data = (Data & ~0x03) | DK_Decl_Vector;
+ break;
+ }
+ }
+}
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
new file mode 100644
index 000000000000..19f89582770e
--- /dev/null
+++ b/lib/AST/DeclCXX.cpp
@@ -0,0 +1,462 @@
+//===--- DeclCXX.cpp - C++ Declaration AST Node Implementation ------------===//
+//
+// 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 C++ related Decl classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/STLExtras.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Decl Allocation/Deallocation Method Implementations
+//===----------------------------------------------------------------------===//
+
+CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id)
+ : RecordDecl(K, TK, DC, L, Id),
+ UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
+ UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
+ Aggregate(true), PlainOldData(true), Polymorphic(false), Abstract(false),
+ HasTrivialConstructor(true), HasTrivialDestructor(true),
+ Bases(0), NumBases(0), Conversions(DC, DeclarationName()),
+ TemplateOrInstantiation() { }
+
+CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ CXXRecordDecl* PrevDecl,
+ bool DelayTypeCreation) {
+ CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id);
+ if (!DelayTypeCreation)
+ C.getTypeDeclType(R, PrevDecl);
+ return R;
+}
+
+CXXRecordDecl::~CXXRecordDecl() {
+ delete [] Bases;
+}
+
+void
+CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
+ unsigned NumBases) {
+ // C++ [dcl.init.aggr]p1:
+ // An aggregate is an array or a class (clause 9) with [...]
+ // no base classes [...].
+ Aggregate = false;
+
+ if (this->Bases)
+ delete [] this->Bases;
+
+ // FIXME: allocate using the ASTContext
+ this->Bases = new CXXBaseSpecifier[NumBases];
+ this->NumBases = NumBases;
+ for (unsigned i = 0; i < NumBases; ++i)
+ this->Bases[i] = *Bases[i];
+}
+
+bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
+ QualType ClassType
+ = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
+ DeclarationName ConstructorName
+ = Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(ClassType));
+ unsigned TypeQuals;
+ DeclContext::lookup_const_iterator Con, ConEnd;
+ for (llvm::tie(Con, ConEnd) = this->lookup(Context, ConstructorName);
+ Con != ConEnd; ++Con) {
+ if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context, TypeQuals) &&
+ (TypeQuals & QualType::Const) != 0)
+ return true;
+ }
+
+ return false;
+}
+
+bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const {
+ QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
+ const_cast<CXXRecordDecl*>(this)));
+ DeclarationName OpName =Context.DeclarationNames.getCXXOperatorName(OO_Equal);
+
+ DeclContext::lookup_const_iterator Op, OpEnd;
+ for (llvm::tie(Op, OpEnd) = this->lookup(Context, OpName);
+ Op != OpEnd; ++Op) {
+ // C++ [class.copy]p9:
+ // A user-declared copy assignment operator is a non-static non-template
+ // member function of class X with exactly one parameter of type X, X&,
+ // const X&, volatile X& or const volatile X&.
+ const CXXMethodDecl* Method = cast<CXXMethodDecl>(*Op);
+ if (Method->isStatic())
+ continue;
+ // TODO: Skip templates? Or is this implicitly done due to parameter types?
+ const FunctionProtoType *FnType =
+ Method->getType()->getAsFunctionProtoType();
+ assert(FnType && "Overloaded operator has no prototype.");
+ // Don't assert on this; an invalid decl might have been left in the AST.
+ if (FnType->getNumArgs() != 1 || FnType->isVariadic())
+ continue;
+ bool AcceptsConst = true;
+ QualType ArgType = FnType->getArgType(0);
+ if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType()) {
+ ArgType = Ref->getPointeeType();
+ // Is it a non-const lvalue reference?
+ if (!ArgType.isConstQualified())
+ AcceptsConst = false;
+ }
+ if (Context.getCanonicalType(ArgType).getUnqualifiedType() != ClassType)
+ continue;
+
+ // We have a single argument of type cv X or cv X&, i.e. we've found the
+ // copy assignment operator. Return whether it accepts const arguments.
+ return AcceptsConst;
+ }
+ assert(isInvalidDecl() &&
+ "No copy assignment operator declared in valid code.");
+ return false;
+}
+
+void
+CXXRecordDecl::addedConstructor(ASTContext &Context,
+ CXXConstructorDecl *ConDecl) {
+ if (!ConDecl->isImplicit()) {
+ // Note that we have a user-declared constructor.
+ UserDeclaredConstructor = true;
+
+ // C++ [dcl.init.aggr]p1:
+ // An aggregate is an array or a class (clause 9) with no
+ // user-declared constructors (12.1) [...].
+ Aggregate = false;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class [...]
+ PlainOldData = false;
+
+ // C++ [class.ctor]p5:
+ // A constructor is trivial if it is an implicitly-declared default
+ // constructor.
+ HasTrivialConstructor = false;
+
+ // Note when we have a user-declared copy constructor, which will
+ // suppress the implicit declaration of a copy constructor.
+ if (ConDecl->isCopyConstructor(Context))
+ UserDeclaredCopyConstructor = true;
+ }
+}
+
+void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
+ CXXMethodDecl *OpDecl) {
+ // We're interested specifically in copy assignment operators.
+ // Unlike addedConstructor, this method is not called for implicit
+ // declarations.
+ const FunctionProtoType *FnType = OpDecl->getType()->getAsFunctionProtoType();
+ assert(FnType && "Overloaded operator has no proto function type.");
+ assert(FnType->getNumArgs() == 1 && !FnType->isVariadic());
+ QualType ArgType = FnType->getArgType(0);
+ if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType())
+ ArgType = Ref->getPointeeType();
+
+ ArgType = ArgType.getUnqualifiedType();
+ QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
+ const_cast<CXXRecordDecl*>(this)));
+
+ if (ClassType != Context.getCanonicalType(ArgType))
+ return;
+
+ // This is a copy assignment operator.
+ // Suppress the implicit declaration of a copy constructor.
+ UserDeclaredCopyAssignment = true;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class that [...] has no user-defined copy
+ // assignment operator [...].
+ PlainOldData = false;
+}
+
+void CXXRecordDecl::addConversionFunction(ASTContext &Context,
+ CXXConversionDecl *ConvDecl) {
+ Conversions.addOverload(ConvDecl);
+}
+
+const CXXDestructorDecl *
+CXXRecordDecl::getDestructor(ASTContext &Context) {
+ QualType ClassType = Context.getTypeDeclType(this);
+
+ DeclarationName Name
+ = Context.DeclarationNames.getCXXDestructorName(ClassType);
+
+ DeclContext::lookup_iterator I, E;
+ llvm::tie(I, E) = lookup(Context, Name);
+ assert(I != E && "Did not find a destructor!");
+
+ const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I);
+ assert(++I == E && "Found more than one destructor!");
+
+ return Dtor;
+}
+
+CXXMethodDecl *
+CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation L, DeclarationName N,
+ QualType T, bool isStatic, bool isInline) {
+ return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, isStatic, isInline);
+}
+
+
+typedef llvm::DenseMap<const CXXMethodDecl*,
+ std::vector<const CXXMethodDecl *> *>
+ OverriddenMethodsMapTy;
+
+static OverriddenMethodsMapTy *OverriddenMethods = 0;
+
+void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
+ // FIXME: The CXXMethodDecl dtor needs to remove and free the entry.
+
+ if (!OverriddenMethods)
+ OverriddenMethods = new OverriddenMethodsMapTy();
+
+ std::vector<const CXXMethodDecl *> *&Methods = (*OverriddenMethods)[this];
+ if (!Methods)
+ Methods = new std::vector<const CXXMethodDecl *>;
+
+ Methods->push_back(MD);
+}
+
+CXXMethodDecl::method_iterator CXXMethodDecl::begin_overridden_methods() const {
+ if (!OverriddenMethods)
+ return 0;
+
+ OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this);
+ if (it == OverriddenMethods->end())
+ return 0;
+ return &(*it->second)[0];
+}
+
+CXXMethodDecl::method_iterator CXXMethodDecl::end_overridden_methods() const {
+ if (!OverriddenMethods)
+ return 0;
+
+ OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this);
+ if (it == OverriddenMethods->end())
+ return 0;
+
+ return &(*it->second)[it->second->size()];
+}
+
+QualType CXXMethodDecl::getThisType(ASTContext &C) const {
+ // C++ 9.3.2p1: The type of this in a member function of a class X is X*.
+ // If the member function is declared const, the type of this is const X*,
+ // if the member function is declared volatile, the type of this is
+ // volatile X*, and if the member function is declared const volatile,
+ // the type of this is const volatile X*.
+
+ assert(isInstance() && "No 'this' for static methods!");
+ QualType ClassTy = C.getTagDeclType(const_cast<CXXRecordDecl*>(getParent()));
+ ClassTy = ClassTy.getWithAdditionalQualifiers(getTypeQualifiers());
+ return C.getPointerType(ClassTy).withConst();
+}
+
+CXXBaseOrMemberInitializer::
+CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs)
+ : Args(0), NumArgs(0) {
+ BaseOrMember = reinterpret_cast<uintptr_t>(BaseType.getTypePtr());
+ assert((BaseOrMember & 0x01) == 0 && "Invalid base class type pointer");
+ BaseOrMember |= 0x01;
+
+ if (NumArgs > 0) {
+ this->NumArgs = NumArgs;
+ this->Args = new Expr*[NumArgs];
+ for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
+ this->Args[Idx] = Args[Idx];
+ }
+}
+
+CXXBaseOrMemberInitializer::
+CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs)
+ : Args(0), NumArgs(0) {
+ BaseOrMember = reinterpret_cast<uintptr_t>(Member);
+ assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer");
+
+ if (NumArgs > 0) {
+ this->NumArgs = NumArgs;
+ this->Args = new Expr*[NumArgs];
+ for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
+ this->Args[Idx] = Args[Idx];
+ }
+}
+
+CXXBaseOrMemberInitializer::~CXXBaseOrMemberInitializer() {
+ delete [] Args;
+}
+
+CXXConstructorDecl *
+CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation L, DeclarationName N,
+ QualType T, bool isExplicit,
+ bool isInline, bool isImplicitlyDeclared) {
+ assert(N.getNameKind() == DeclarationName::CXXConstructorName &&
+ "Name must refer to a constructor");
+ return new (C) CXXConstructorDecl(RD, L, N, T, isExplicit, isInline,
+ isImplicitlyDeclared);
+}
+
+bool CXXConstructorDecl::isDefaultConstructor() const {
+ // C++ [class.ctor]p5:
+ // A default constructor for a class X is a constructor of class
+ // X that can be called without an argument.
+ return (getNumParams() == 0) ||
+ (getNumParams() > 0 && getParamDecl(0)->getDefaultArg() != 0);
+}
+
+bool
+CXXConstructorDecl::isCopyConstructor(ASTContext &Context,
+ unsigned &TypeQuals) const {
+ // C++ [class.copy]p2:
+ // A non-template constructor for class X is a copy constructor
+ // if its first parameter is of type X&, const X&, volatile X& or
+ // const volatile X&, and either there are no other parameters
+ // or else all other parameters have default arguments (8.3.6).
+ if ((getNumParams() < 1) ||
+ (getNumParams() > 1 && getParamDecl(1)->getDefaultArg() == 0))
+ return false;
+
+ const ParmVarDecl *Param = getParamDecl(0);
+
+ // Do we have a reference type? Rvalue references don't count.
+ const LValueReferenceType *ParamRefType =
+ Param->getType()->getAsLValueReferenceType();
+ if (!ParamRefType)
+ return false;
+
+ // Is it a reference to our class type?
+ QualType PointeeType
+ = Context.getCanonicalType(ParamRefType->getPointeeType());
+ QualType ClassTy
+ = Context.getTagDeclType(const_cast<CXXRecordDecl*>(getParent()));
+ if (PointeeType.getUnqualifiedType() != ClassTy)
+ return false;
+
+ // We have a copy constructor.
+ TypeQuals = PointeeType.getCVRQualifiers();
+ return true;
+}
+
+bool CXXConstructorDecl::isConvertingConstructor() const {
+ // C++ [class.conv.ctor]p1:
+ // A constructor declared without the function-specifier explicit
+ // that can be called with a single parameter specifies a
+ // conversion from the type of its first parameter to the type of
+ // its class. Such a constructor is called a converting
+ // constructor.
+ if (isExplicit())
+ return false;
+
+ return (getNumParams() == 0 &&
+ getType()->getAsFunctionProtoType()->isVariadic()) ||
+ (getNumParams() == 1) ||
+ (getNumParams() > 1 && getParamDecl(1)->getDefaultArg() != 0);
+}
+
+CXXDestructorDecl *
+CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation L, DeclarationName N,
+ QualType T, bool isInline,
+ bool isImplicitlyDeclared) {
+ assert(N.getNameKind() == DeclarationName::CXXDestructorName &&
+ "Name must refer to a destructor");
+ return new (C) CXXDestructorDecl(RD, L, N, T, isInline,
+ isImplicitlyDeclared);
+}
+
+CXXConversionDecl *
+CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation L, DeclarationName N,
+ QualType T, bool isInline, bool isExplicit) {
+ assert(N.getNameKind() == DeclarationName::CXXConversionFunctionName &&
+ "Name must refer to a conversion function");
+ return new (C) CXXConversionDecl(RD, L, N, T, isInline, isExplicit);
+}
+
+OverloadedFunctionDecl *
+OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC,
+ DeclarationName N) {
+ return new (C) OverloadedFunctionDecl(DC, N);
+}
+
+LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
+ DeclContext *DC,
+ SourceLocation L,
+ LanguageIDs Lang, bool Braces) {
+ return new (C) LinkageSpecDecl(DC, L, Lang, Braces);
+}
+
+UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ SourceLocation NamespaceLoc,
+ SourceRange QualifierRange,
+ NestedNameSpecifier *Qualifier,
+ SourceLocation IdentLoc,
+ NamespaceDecl *Used,
+ DeclContext *CommonAncestor) {
+ return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierRange,
+ Qualifier, IdentLoc, Used, CommonAncestor);
+}
+
+NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ SourceLocation AliasLoc,
+ IdentifierInfo *Alias,
+ SourceRange QualifierRange,
+ NestedNameSpecifier *Qualifier,
+ SourceLocation IdentLoc,
+ NamedDecl *Namespace) {
+ return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange,
+ Qualifier, IdentLoc, Namespace);
+}
+
+StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, Expr *AssertExpr,
+ StringLiteral *Message) {
+ return new (C) StaticAssertDecl(DC, L, AssertExpr, Message);
+}
+
+void StaticAssertDecl::Destroy(ASTContext& C) {
+ AssertExpr->Destroy(C);
+ Message->Destroy(C);
+ this->~StaticAssertDecl();
+ C.Deallocate((void *)this);
+}
+
+StaticAssertDecl::~StaticAssertDecl() {
+}
+
+static const char *getAccessName(AccessSpecifier AS) {
+ switch (AS) {
+ default:
+ case AS_none:
+ assert("Invalid access specifier!");
+ return 0;
+ case AS_public:
+ return "public";
+ case AS_private:
+ return "private";
+ case AS_protected:
+ return "protected";
+ }
+}
+
+const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
+ AccessSpecifier AS) {
+ return DB << getAccessName(AS);
+}
+
+
diff --git a/lib/AST/DeclGroup.cpp b/lib/AST/DeclGroup.cpp
new file mode 100644
index 000000000000..5bdc88173461
--- /dev/null
+++ b/lib/AST/DeclGroup.cpp
@@ -0,0 +1,37 @@
+//===--- DeclGroup.cpp - Classes for representing groups of Decls -*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the DeclGroup and DeclGroupRef classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclGroup.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/Support/Allocator.h"
+using namespace clang;
+
+DeclGroup* DeclGroup::Create(ASTContext &C, Decl **Decls, unsigned NumDecls) {
+ assert(NumDecls > 1 && "Invalid DeclGroup");
+ unsigned Size = sizeof(DeclGroup) + sizeof(Decl*) * NumDecls;
+ void* Mem = C.Allocate(Size, llvm::AlignOf<DeclGroup>::Alignment);
+ new (Mem) DeclGroup(NumDecls, Decls);
+ return static_cast<DeclGroup*>(Mem);
+}
+
+DeclGroup::DeclGroup(unsigned numdecls, Decl** decls) : NumDecls(numdecls) {
+ assert(numdecls > 0);
+ assert(decls);
+ memcpy(this+1, decls, numdecls * sizeof(*decls));
+}
+
+void DeclGroup::Destroy(ASTContext& C) {
+ this->~DeclGroup();
+ C.Deallocate((void*) this);
+}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
new file mode 100644
index 000000000000..f4bb89573074
--- /dev/null
+++ b/lib/AST/DeclObjC.cpp
@@ -0,0 +1,693 @@
+//===--- DeclObjC.cpp - ObjC Declaration AST Node Implementation ----------===//
+//
+// 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 Objective-C related Decl classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Stmt.h"
+#include "llvm/ADT/STLExtras.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// ObjCListBase
+//===----------------------------------------------------------------------===//
+
+void ObjCListBase::Destroy(ASTContext &Ctx) {
+ Ctx.Deallocate(List);
+ NumElts = 0;
+ List = 0;
+}
+
+void ObjCListBase::set(void *const* InList, unsigned Elts, ASTContext &Ctx) {
+ assert(List == 0 && "Elements already set!");
+ if (Elts == 0) return; // Setting to an empty list is a noop.
+
+
+ List = new (Ctx) void*[Elts];
+ NumElts = Elts;
+ memcpy(List, InList, sizeof(void*)*Elts);
+}
+
+
+//===----------------------------------------------------------------------===//
+// ObjCInterfaceDecl
+//===----------------------------------------------------------------------===//
+
+// Get the local instance method declared in this interface.
+ObjCMethodDecl *
+ObjCContainerDecl::getInstanceMethod(ASTContext &Context, Selector Sel) const {
+ // Since instance & class methods can have the same name, the loop below
+ // ensures we get the correct method.
+ //
+ // @interface Whatever
+ // - (int) class_method;
+ // + (float) class_method;
+ // @end
+ //
+ lookup_const_iterator Meth, MethEnd;
+ for (llvm::tie(Meth, MethEnd) = lookup(Context, Sel);
+ Meth != MethEnd; ++Meth) {
+ ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
+ if (MD && MD->isInstanceMethod())
+ return MD;
+ }
+ return 0;
+}
+
+// Get the local class method declared in this interface.
+ObjCMethodDecl *
+ObjCContainerDecl::getClassMethod(ASTContext &Context, Selector Sel) const {
+ // Since instance & class methods can have the same name, the loop below
+ // ensures we get the correct method.
+ //
+ // @interface Whatever
+ // - (int) class_method;
+ // + (float) class_method;
+ // @end
+ //
+ lookup_const_iterator Meth, MethEnd;
+ for (llvm::tie(Meth, MethEnd) = lookup(Context, Sel);
+ Meth != MethEnd; ++Meth) {
+ ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
+ if (MD && MD->isClassMethod())
+ return MD;
+ }
+ return 0;
+}
+
+/// FindPropertyDeclaration - Finds declaration of the property given its name
+/// in 'PropertyId' and returns it. It returns 0, if not found.
+/// FIXME: Convert to DeclContext lookup...
+///
+ObjCPropertyDecl *
+ObjCContainerDecl::FindPropertyDeclaration(ASTContext &Context,
+ IdentifierInfo *PropertyId) const {
+ for (prop_iterator I = prop_begin(Context), E = prop_end(Context);
+ I != E; ++I)
+ if ((*I)->getIdentifier() == PropertyId)
+ return *I;
+
+ const ObjCProtocolDecl *PID = dyn_cast<ObjCProtocolDecl>(this);
+ if (PID) {
+ for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
+ E = PID->protocol_end(); I != E; ++I)
+ if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(Context,
+ PropertyId))
+ return P;
+ }
+
+ if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(this)) {
+ // Look through categories.
+ for (ObjCCategoryDecl *Category = OID->getCategoryList();
+ Category; Category = Category->getNextClassCategory()) {
+ if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(Context,
+ PropertyId))
+ return P;
+ }
+ // Look through protocols.
+ for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(),
+ E = OID->protocol_end(); I != E; ++I) {
+ if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(Context,
+ PropertyId))
+ return P;
+ }
+ if (OID->getSuperClass())
+ return OID->getSuperClass()->FindPropertyDeclaration(Context,
+ PropertyId);
+ } else if (const ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(this)) {
+ // Look through protocols.
+ for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(),
+ E = OCD->protocol_end(); I != E; ++I) {
+ if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(Context,
+ PropertyId))
+ return P;
+ }
+ }
+ return 0;
+}
+
+ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(
+ ASTContext &Context, IdentifierInfo *ID, ObjCInterfaceDecl *&clsDeclared) {
+ ObjCInterfaceDecl* ClassDecl = this;
+ while (ClassDecl != NULL) {
+ for (ivar_iterator I = ClassDecl->ivar_begin(), E = ClassDecl->ivar_end();
+ I != E; ++I) {
+ if ((*I)->getIdentifier() == ID) {
+ clsDeclared = ClassDecl;
+ return *I;
+ }
+ }
+ // look into properties.
+ for (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(Context),
+ E = ClassDecl->prop_end(Context); I != E; ++I) {
+ ObjCPropertyDecl *PDecl = (*I);
+ if (ObjCIvarDecl *IV = PDecl->getPropertyIvarDecl())
+ if (IV->getIdentifier() == ID) {
+ clsDeclared = ClassDecl;
+ return IV;
+ }
+ }
+ ClassDecl = ClassDecl->getSuperClass();
+ }
+ return NULL;
+}
+
+/// lookupInheritedClass - This method returns ObjCInterfaceDecl * of the super
+/// class whose name is passed as argument. If it is not one of the super classes
+/// the it returns NULL.
+ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass(
+ const IdentifierInfo*ICName) {
+ ObjCInterfaceDecl* ClassDecl = this;
+ while (ClassDecl != NULL) {
+ if (ClassDecl->getIdentifier() == ICName)
+ return ClassDecl;
+ ClassDecl = ClassDecl->getSuperClass();
+ }
+ return NULL;
+}
+
+/// lookupInstanceMethod - This method returns an instance method by looking in
+/// the class, its categories, and its super classes (using a linear search).
+ObjCMethodDecl *ObjCInterfaceDecl::lookupInstanceMethod(ASTContext &Context,
+ Selector Sel) {
+ ObjCInterfaceDecl* ClassDecl = this;
+ ObjCMethodDecl *MethodDecl = 0;
+
+ while (ClassDecl != NULL) {
+ if ((MethodDecl = ClassDecl->getInstanceMethod(Context, Sel)))
+ return MethodDecl;
+
+ // Didn't find one yet - look through protocols.
+ const ObjCList<ObjCProtocolDecl> &Protocols =
+ ClassDecl->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end(); I != E; ++I)
+ if ((MethodDecl = (*I)->lookupInstanceMethod(Context, Sel)))
+ return MethodDecl;
+
+ // Didn't find one yet - now look through categories.
+ ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList();
+ while (CatDecl) {
+ if ((MethodDecl = CatDecl->getInstanceMethod(Context, Sel)))
+ return MethodDecl;
+
+ // Didn't find one yet - look through protocols.
+ const ObjCList<ObjCProtocolDecl> &Protocols =
+ CatDecl->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end(); I != E; ++I)
+ if ((MethodDecl = (*I)->lookupInstanceMethod(Context, Sel)))
+ return MethodDecl;
+ CatDecl = CatDecl->getNextClassCategory();
+ }
+ ClassDecl = ClassDecl->getSuperClass();
+ }
+ return NULL;
+}
+
+// lookupClassMethod - This method returns a class method by looking in the
+// class, its categories, and its super classes (using a linear search).
+ObjCMethodDecl *ObjCInterfaceDecl::lookupClassMethod(ASTContext &Context,
+ Selector Sel) {
+ ObjCInterfaceDecl* ClassDecl = this;
+ ObjCMethodDecl *MethodDecl = 0;
+
+ while (ClassDecl != NULL) {
+ if ((MethodDecl = ClassDecl->getClassMethod(Context, Sel)))
+ return MethodDecl;
+
+ // Didn't find one yet - look through protocols.
+ for (ObjCInterfaceDecl::protocol_iterator I = ClassDecl->protocol_begin(),
+ E = ClassDecl->protocol_end(); I != E; ++I)
+ if ((MethodDecl = (*I)->lookupClassMethod(Context, Sel)))
+ return MethodDecl;
+
+ // Didn't find one yet - now look through categories.
+ ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList();
+ while (CatDecl) {
+ if ((MethodDecl = CatDecl->getClassMethod(Context, Sel)))
+ return MethodDecl;
+
+ // Didn't find one yet - look through protocols.
+ const ObjCList<ObjCProtocolDecl> &Protocols =
+ CatDecl->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end(); I != E; ++I)
+ if ((MethodDecl = (*I)->lookupClassMethod(Context, Sel)))
+ return MethodDecl;
+ CatDecl = CatDecl->getNextClassCategory();
+ }
+ ClassDecl = ClassDecl->getSuperClass();
+ }
+ return NULL;
+}
+
+
+
+//===----------------------------------------------------------------------===//
+// ObjCMethodDecl
+//===----------------------------------------------------------------------===//
+
+ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C,
+ SourceLocation beginLoc,
+ SourceLocation endLoc,
+ Selector SelInfo, QualType T,
+ DeclContext *contextDecl,
+ bool isInstance,
+ bool isVariadic,
+ bool isSynthesized,
+ ImplementationControl impControl) {
+ return new (C) ObjCMethodDecl(beginLoc, endLoc,
+ SelInfo, T, contextDecl,
+ isInstance,
+ isVariadic, isSynthesized, impControl);
+}
+
+void ObjCMethodDecl::Destroy(ASTContext &C) {
+ if (Body) Body->Destroy(C);
+ if (SelfDecl) SelfDecl->Destroy(C);
+
+ for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I)
+ if (*I) (*I)->Destroy(C);
+
+ ParamInfo.Destroy(C);
+
+ Decl::Destroy(C);
+}
+
+void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
+ const ObjCInterfaceDecl *OID) {
+ QualType selfTy;
+ if (isInstanceMethod()) {
+ // There may be no interface context due to error in declaration
+ // of the interface (which has been reported). Recover gracefully.
+ if (OID) {
+ selfTy = Context.getObjCInterfaceType(OID);
+ selfTy = Context.getPointerType(selfTy);
+ } else {
+ selfTy = Context.getObjCIdType();
+ }
+ } else // we have a factory method.
+ selfTy = Context.getObjCClassType();
+
+ setSelfDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(),
+ &Context.Idents.get("self"), selfTy));
+
+ setCmdDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(),
+ &Context.Idents.get("_cmd"),
+ Context.getObjCSelType()));
+}
+
+
+
+/// getSynthesizedMethodSize - Compute size of synthesized method name
+/// as done be the rewrite.
+///
+unsigned ObjCMethodDecl::getSynthesizedMethodSize() const {
+ // syntesized method name is a concatenation of -/+[class-name selector]
+ // Get length of this name.
+ unsigned length = 3; // _I_ or _C_
+ length += getClassInterface()->getNameAsString().size()+1; // extra for _
+ if (const ObjCCategoryImplDecl *CID =
+ dyn_cast<ObjCCategoryImplDecl>(getDeclContext()))
+ length += CID->getNameAsString().size()+1;
+ length += getSelector().getAsString().size(); // selector name
+ return length;
+}
+
+ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() {
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(getDeclContext()))
+ return ID;
+ if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(getDeclContext()))
+ return CD->getClassInterface();
+ if (ObjCImplementationDecl *IMD =
+ dyn_cast<ObjCImplementationDecl>(getDeclContext()))
+ return IMD->getClassInterface();
+ if (ObjCCategoryImplDecl *CID =
+ dyn_cast<ObjCCategoryImplDecl>(getDeclContext()))
+ return CID->getClassInterface();
+ assert(false && "unknown method context");
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// ObjCInterfaceDecl
+//===----------------------------------------------------------------------===//
+
+ObjCInterfaceDecl *ObjCInterfaceDecl::Create(ASTContext &C,
+ DeclContext *DC,
+ SourceLocation atLoc,
+ IdentifierInfo *Id,
+ SourceLocation ClassLoc,
+ bool ForwardDecl, bool isInternal){
+ return new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc, ForwardDecl,
+ isInternal);
+}
+
+ObjCInterfaceDecl::
+ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
+ SourceLocation CLoc, bool FD, bool isInternal)
+ : ObjCContainerDecl(ObjCInterface, DC, atLoc, Id),
+ TypeForDecl(0), SuperClass(0),
+ CategoryList(0), ForwardDecl(FD), InternalInterface(isInternal),
+ ClassLoc(CLoc) {
+}
+
+void ObjCInterfaceDecl::Destroy(ASTContext &C) {
+ for (ivar_iterator I = ivar_begin(), E = ivar_end(); I != E; ++I)
+ if (*I) (*I)->Destroy(C);
+
+ IVars.Destroy(C);
+ // FIXME: CategoryList?
+
+ // FIXME: Because there is no clear ownership
+ // role between ObjCInterfaceDecls and the ObjCPropertyDecls that they
+ // reference, we destroy ObjCPropertyDecls in ~TranslationUnit.
+ Decl::Destroy(C);
+}
+
+
+/// FindCategoryDeclaration - Finds category declaration in the list of
+/// categories for this class and returns it. Name of the category is passed
+/// in 'CategoryId'. If category not found, return 0;
+///
+ObjCCategoryDecl *
+ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const {
+ for (ObjCCategoryDecl *Category = getCategoryList();
+ Category; Category = Category->getNextClassCategory())
+ if (Category->getIdentifier() == CategoryId)
+ return Category;
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// ObjCIvarDecl
+//===----------------------------------------------------------------------===//
+
+ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ QualType T, AccessControl ac, Expr *BW) {
+ return new (C) ObjCIvarDecl(DC, L, Id, T, ac, BW);
+}
+
+
+
+//===----------------------------------------------------------------------===//
+// ObjCAtDefsFieldDecl
+//===----------------------------------------------------------------------===//
+
+ObjCAtDefsFieldDecl
+*ObjCAtDefsFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType T, Expr *BW) {
+ return new (C) ObjCAtDefsFieldDecl(DC, L, Id, T, BW);
+}
+
+void ObjCAtDefsFieldDecl::Destroy(ASTContext& C) {
+ this->~ObjCAtDefsFieldDecl();
+ C.Deallocate((void *)this);
+}
+
+//===----------------------------------------------------------------------===//
+// ObjCProtocolDecl
+//===----------------------------------------------------------------------===//
+
+ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ IdentifierInfo *Id) {
+ return new (C) ObjCProtocolDecl(DC, L, Id);
+}
+
+void ObjCProtocolDecl::Destroy(ASTContext &C) {
+ ReferencedProtocols.Destroy(C);
+ ObjCContainerDecl::Destroy(C);
+}
+
+ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) {
+ ObjCProtocolDecl *PDecl = this;
+
+ if (Name == getIdentifier())
+ return PDecl;
+
+ for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I)
+ if ((PDecl = (*I)->lookupProtocolNamed(Name)))
+ return PDecl;
+
+ return NULL;
+}
+
+// lookupInstanceMethod - Lookup a instance method in the protocol and protocols
+// it inherited.
+ObjCMethodDecl *ObjCProtocolDecl::lookupInstanceMethod(ASTContext &Context,
+ Selector Sel) {
+ ObjCMethodDecl *MethodDecl = NULL;
+
+ if ((MethodDecl = getInstanceMethod(Context, Sel)))
+ return MethodDecl;
+
+ for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I)
+ if ((MethodDecl = (*I)->lookupInstanceMethod(Context, Sel)))
+ return MethodDecl;
+ return NULL;
+}
+
+// lookupInstanceMethod - Lookup a class method in the protocol and protocols
+// it inherited.
+ObjCMethodDecl *ObjCProtocolDecl::lookupClassMethod(ASTContext &Context,
+ Selector Sel) {
+ ObjCMethodDecl *MethodDecl = NULL;
+
+ if ((MethodDecl = getClassMethod(Context, Sel)))
+ return MethodDecl;
+
+ for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I)
+ if ((MethodDecl = (*I)->lookupClassMethod(Context, Sel)))
+ return MethodDecl;
+ return NULL;
+}
+
+//===----------------------------------------------------------------------===//
+// ObjCClassDecl
+//===----------------------------------------------------------------------===//
+
+ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L,
+ ObjCInterfaceDecl *const *Elts, unsigned nElts,
+ ASTContext &C)
+ : Decl(ObjCClass, DC, L) {
+ ForwardDecls.set(Elts, nElts, C);
+}
+
+
+ObjCClassDecl *ObjCClassDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ ObjCInterfaceDecl *const *Elts,
+ unsigned nElts) {
+ return new (C) ObjCClassDecl(DC, L, Elts, nElts, C);
+}
+
+void ObjCClassDecl::Destroy(ASTContext &C) {
+
+ // FIXME: There is no clear ownership policy now for referenced
+ // ObjCInterfaceDecls. Some of them can be forward declarations that
+ // are never later defined (in which case the ObjCClassDecl owns them)
+ // or the ObjCInterfaceDecl later becomes a real definition later. Ideally
+ // we should have separate objects for forward declarations and definitions,
+ // obviating this problem. Because of this situation, referenced
+ // ObjCInterfaceDecls are destroyed in ~TranslationUnit.
+
+ ForwardDecls.Destroy(C);
+ Decl::Destroy(C);
+}
+
+//===----------------------------------------------------------------------===//
+// ObjCForwardProtocolDecl
+//===----------------------------------------------------------------------===//
+
+ObjCForwardProtocolDecl::
+ObjCForwardProtocolDecl(DeclContext *DC, SourceLocation L,
+ ObjCProtocolDecl *const *Elts, unsigned nElts,
+ ASTContext &C)
+: Decl(ObjCForwardProtocol, DC, L) {
+ ReferencedProtocols.set(Elts, nElts, C);
+}
+
+
+ObjCForwardProtocolDecl *
+ObjCForwardProtocolDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ ObjCProtocolDecl *const *Elts,
+ unsigned NumElts) {
+ return new (C) ObjCForwardProtocolDecl(DC, L, Elts, NumElts, C);
+}
+
+void ObjCForwardProtocolDecl::Destroy(ASTContext &C) {
+ ReferencedProtocols.Destroy(C);
+ Decl::Destroy(C);
+}
+
+//===----------------------------------------------------------------------===//
+// ObjCCategoryDecl
+//===----------------------------------------------------------------------===//
+
+ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ IdentifierInfo *Id) {
+ return new (C) ObjCCategoryDecl(DC, L, Id);
+}
+
+//===----------------------------------------------------------------------===//
+// ObjCCategoryImplDecl
+//===----------------------------------------------------------------------===//
+
+ObjCCategoryImplDecl *
+ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,IdentifierInfo *Id,
+ ObjCInterfaceDecl *ClassInterface) {
+ return new (C) ObjCCategoryImplDecl(DC, L, Id, ClassInterface);
+}
+
+
+void ObjCImplDecl::addPropertyImplementation(ASTContext &Context,
+ ObjCPropertyImplDecl *property) {
+ // FIXME: The context should be correct before we get here.
+ property->setLexicalDeclContext(this);
+ addDecl(Context, property);
+}
+
+/// FindPropertyImplIvarDecl - This method lookup the ivar in the list of
+/// properties implemented in this category @implementation block and returns
+/// the implemented property that uses it.
+///
+ObjCPropertyImplDecl *ObjCImplDecl::
+FindPropertyImplIvarDecl(ASTContext &Context, IdentifierInfo *ivarId) const {
+ for (propimpl_iterator i = propimpl_begin(Context), e = propimpl_end(Context);
+ i != e; ++i){
+ ObjCPropertyImplDecl *PID = *i;
+ if (PID->getPropertyIvarDecl() &&
+ PID->getPropertyIvarDecl()->getIdentifier() == ivarId)
+ return PID;
+ }
+ return 0;
+}
+
+/// FindPropertyImplDecl - This method looks up a previous ObjCPropertyImplDecl
+/// added to the list of those properties @synthesized/@dynamic in this
+/// category @implementation block.
+///
+ObjCPropertyImplDecl *ObjCImplDecl::
+FindPropertyImplDecl(ASTContext &Context, IdentifierInfo *Id) const {
+ for (propimpl_iterator i = propimpl_begin(Context), e = propimpl_end(Context);
+ i != e; ++i){
+ ObjCPropertyImplDecl *PID = *i;
+ if (PID->getPropertyDecl()->getIdentifier() == Id)
+ return PID;
+ }
+ return 0;
+}
+
+// getInstanceMethod - This method returns an instance method by looking in
+// the class implementation. Unlike interfaces, we don't look outside the
+// implementation.
+ObjCMethodDecl *ObjCImplDecl::getInstanceMethod(ASTContext &Context,
+ Selector Sel) const {
+ // Since instance & class methods can have the same name, the loop below
+ // ensures we get the correct method.
+ //
+ // @interface Whatever
+ // - (int) class_method;
+ // + (float) class_method;
+ // @end
+ //
+ lookup_const_iterator Meth, MethEnd;
+ for (llvm::tie(Meth, MethEnd) = lookup(Context, Sel);
+ Meth != MethEnd; ++Meth) {
+ ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
+ if (MD && MD->isInstanceMethod())
+ return MD;
+ }
+ return 0;
+}
+
+// getClassMethod - This method returns an instance method by looking in
+// the class implementation. Unlike interfaces, we don't look outside the
+// implementation.
+ObjCMethodDecl *ObjCImplDecl::getClassMethod(ASTContext &Context,
+ Selector Sel) const {
+ // Since instance & class methods can have the same name, the loop below
+ // ensures we get the correct method.
+ //
+ // @interface Whatever
+ // - (int) class_method;
+ // + (float) class_method;
+ // @end
+ //
+ lookup_const_iterator Meth, MethEnd;
+ for (llvm::tie(Meth, MethEnd) = lookup(Context, Sel);
+ Meth != MethEnd; ++Meth) {
+ ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
+ if (MD && MD->isClassMethod())
+ return MD;
+ }
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// ObjCImplementationDecl
+//===----------------------------------------------------------------------===//
+
+ObjCImplementationDecl *
+ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ ObjCInterfaceDecl *ClassInterface,
+ ObjCInterfaceDecl *SuperDecl) {
+ return new (C) ObjCImplementationDecl(DC, L, ClassInterface, SuperDecl);
+}
+
+//===----------------------------------------------------------------------===//
+// ObjCCompatibleAliasDecl
+//===----------------------------------------------------------------------===//
+
+ObjCCompatibleAliasDecl *
+ObjCCompatibleAliasDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ IdentifierInfo *Id,
+ ObjCInterfaceDecl* AliasedClass) {
+ return new (C) ObjCCompatibleAliasDecl(DC, L, Id, AliasedClass);
+}
+
+//===----------------------------------------------------------------------===//
+// ObjCPropertyDecl
+//===----------------------------------------------------------------------===//
+
+ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ IdentifierInfo *Id,
+ QualType T,
+ PropertyControl propControl) {
+ return new (C) ObjCPropertyDecl(DC, L, Id, T);
+}
+
+
+//===----------------------------------------------------------------------===//
+// ObjCPropertyImplDecl
+//===----------------------------------------------------------------------===//
+
+ObjCPropertyImplDecl *ObjCPropertyImplDecl::Create(ASTContext &C,
+ DeclContext *DC,
+ SourceLocation atLoc,
+ SourceLocation L,
+ ObjCPropertyDecl *property,
+ Kind PK,
+ ObjCIvarDecl *ivar) {
+ return new (C) ObjCPropertyImplDecl(DC, atLoc, L, property, PK, ivar);
+}
+
+
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
new file mode 100644
index 000000000000..f29da8b9f4c8
--- /dev/null
+++ b/lib/AST/DeclPrinter.cpp
@@ -0,0 +1,722 @@
+//===--- DeclPrinter.cpp - Printing implementation for Decl ASTs ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Decl::dump method, which pretty print the
+// AST back out to C/Objective-C/C++/Objective-C++ code.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+namespace {
+ class VISIBILITY_HIDDEN DeclPrinter : public DeclVisitor<DeclPrinter> {
+ llvm::raw_ostream &Out;
+ ASTContext &Context;
+ PrintingPolicy Policy;
+ unsigned Indentation;
+
+ llvm::raw_ostream& Indent();
+ void ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls);
+
+ public:
+ DeclPrinter(llvm::raw_ostream &Out, ASTContext &Context,
+ const PrintingPolicy &Policy,
+ unsigned Indentation = 0)
+ : Out(Out), Context(Context), Policy(Policy), Indentation(Indentation) { }
+
+ void VisitDeclContext(DeclContext *DC, bool Indent = true);
+
+ void VisitTranslationUnitDecl(TranslationUnitDecl *D);
+ void VisitTypedefDecl(TypedefDecl *D);
+ void VisitEnumDecl(EnumDecl *D);
+ void VisitRecordDecl(RecordDecl *D);
+ void VisitEnumConstantDecl(EnumConstantDecl *D);
+ void VisitFunctionDecl(FunctionDecl *D);
+ void VisitFieldDecl(FieldDecl *D);
+ void VisitVarDecl(VarDecl *D);
+ void VisitParmVarDecl(ParmVarDecl *D);
+ void VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
+ void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
+ void VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D);
+ void VisitNamespaceDecl(NamespaceDecl *D);
+ void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
+ void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
+ void VisitCXXRecordDecl(CXXRecordDecl *D);
+ void VisitLinkageSpecDecl(LinkageSpecDecl *D);
+ void VisitTemplateDecl(TemplateDecl *D);
+ void VisitObjCMethodDecl(ObjCMethodDecl *D);
+ void VisitObjCClassDecl(ObjCClassDecl *D);
+ void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
+ void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+ void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
+ void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
+ void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
+ void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
+ void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
+ void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
+ void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+ };
+}
+
+void Decl::print(llvm::raw_ostream &Out, ASTContext &Context,
+ unsigned Indentation) {
+ print(Out, Context, Context.PrintingPolicy, Indentation);
+}
+
+void Decl::print(llvm::raw_ostream &Out, ASTContext &Context,
+ const PrintingPolicy &Policy, unsigned Indentation) {
+ DeclPrinter Printer(Out, Context, Policy, Indentation);
+ Printer.Visit(this);
+}
+
+static QualType GetBaseType(QualType T) {
+ // FIXME: This should be on the Type class!
+ QualType BaseType = T;
+ while (!BaseType->isSpecifierType()) {
+ if (isa<TypedefType>(BaseType))
+ break;
+ else if (const PointerType* PTy = BaseType->getAsPointerType())
+ BaseType = PTy->getPointeeType();
+ else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType))
+ BaseType = ATy->getElementType();
+ else if (const FunctionType* FTy = BaseType->getAsFunctionType())
+ BaseType = FTy->getResultType();
+ else
+ assert(0 && "Unknown declarator!");
+ }
+ return BaseType;
+}
+
+static QualType getDeclType(Decl* D) {
+ if (TypedefDecl* TDD = dyn_cast<TypedefDecl>(D))
+ return TDD->getUnderlyingType();
+ if (ValueDecl* VD = dyn_cast<ValueDecl>(D))
+ return VD->getType();
+ return QualType();
+}
+
+void Decl::printGroup(Decl** Begin, unsigned NumDecls,
+ llvm::raw_ostream &Out, ASTContext &Context,
+ const PrintingPolicy &Policy,
+ unsigned Indentation) {
+ if (NumDecls == 1) {
+ (*Begin)->print(Out, Context, Policy, Indentation);
+ return;
+ }
+
+ Decl** End = Begin + NumDecls;
+ TagDecl* TD = dyn_cast<TagDecl>(*Begin);
+ if (TD)
+ ++Begin;
+
+ PrintingPolicy SubPolicy(Policy);
+ if (TD && TD->isDefinition()) {
+ TD->print(Out, Context, Policy, Indentation);
+ Out << " ";
+ SubPolicy.SuppressTag = true;
+ }
+
+ bool isFirst = true;
+ for ( ; Begin != End; ++Begin) {
+ if (isFirst) {
+ SubPolicy.SuppressSpecifiers = false;
+ isFirst = false;
+ } else {
+ if (!isFirst) Out << ", ";
+ SubPolicy.SuppressSpecifiers = true;
+ }
+
+ (*Begin)->print(Out, Context, SubPolicy, Indentation);
+ }
+}
+
+void Decl::dump(ASTContext &Context) {
+ print(llvm::errs(), Context);
+}
+
+llvm::raw_ostream& DeclPrinter::Indent() {
+ for (unsigned i = 0; i < Indentation; ++i)
+ Out << " ";
+ return Out;
+}
+
+void DeclPrinter::ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls) {
+ this->Indent();
+ Decl::printGroup(Decls.data(), Decls.size(), Out, Context,
+ Policy, Indentation);
+ Out << ";\n";
+ Decls.clear();
+
+}
+
+//----------------------------------------------------------------------------
+// Common C declarations
+//----------------------------------------------------------------------------
+
+void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
+ if (Indent)
+ Indentation += Policy.Indentation;
+
+ llvm::SmallVector<Decl*, 2> Decls;
+ for (DeclContext::decl_iterator D = DC->decls_begin(Context),
+ DEnd = DC->decls_end(Context);
+ D != DEnd; ++D) {
+ if (!Policy.Dump) {
+ // Skip over implicit declarations in pretty-printing mode.
+ if (D->isImplicit()) continue;
+ // FIXME: Ugly hack so we don't pretty-print the builtin declaration
+ // of __builtin_va_list. There should be some other way to check that.
+ if (isa<NamedDecl>(*D) && cast<NamedDecl>(*D)->getNameAsString() ==
+ "__builtin_va_list")
+ continue;
+ }
+
+ // The next bits of code handles stuff like "struct {int x;} a,b"; we're
+ // forced to merge the declarations because there's no other way to
+ // refer to the struct in question. This limited merging is safe without
+ // a bunch of other checks because it only merges declarations directly
+ // referring to the tag, not typedefs.
+ //
+ // Check whether the current declaration should be grouped with a previous
+ // unnamed struct.
+ QualType CurDeclType = getDeclType(*D);
+ if (!Decls.empty() && !CurDeclType.isNull()) {
+ QualType BaseType = GetBaseType(CurDeclType);
+ if (!BaseType.isNull() && isa<TagType>(BaseType) &&
+ cast<TagType>(BaseType)->getDecl() == Decls[0]) {
+ Decls.push_back(*D);
+ continue;
+ }
+ }
+
+ // If we have a merged group waiting to be handled, handle it now.
+ if (!Decls.empty())
+ ProcessDeclGroup(Decls);
+
+ // If the current declaration is an unnamed tag type, save it
+ // so we can merge it with the subsequent declaration(s) using it.
+ if (isa<TagDecl>(*D) && !cast<TagDecl>(*D)->getIdentifier()) {
+ Decls.push_back(*D);
+ continue;
+ }
+ this->Indent();
+ Visit(*D);
+
+ // FIXME: Need to be able to tell the DeclPrinter when
+ const char *Terminator = 0;
+ if (isa<FunctionDecl>(*D) &&
+ cast<FunctionDecl>(*D)->isThisDeclarationADefinition())
+ Terminator = 0;
+ else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->getBody())
+ Terminator = 0;
+ else if (isa<NamespaceDecl>(*D) || isa<LinkageSpecDecl>(*D) ||
+ isa<ObjCImplementationDecl>(*D) ||
+ isa<ObjCInterfaceDecl>(*D) ||
+ isa<ObjCProtocolDecl>(*D) ||
+ isa<ObjCCategoryImplDecl>(*D) ||
+ isa<ObjCCategoryDecl>(*D))
+ Terminator = 0;
+ else if (isa<EnumConstantDecl>(*D)) {
+ DeclContext::decl_iterator Next = D;
+ ++Next;
+ if (Next != DEnd)
+ Terminator = ",";
+ } else
+ Terminator = ";";
+
+ if (Terminator)
+ Out << Terminator;
+ Out << "\n";
+ }
+
+ if (!Decls.empty())
+ ProcessDeclGroup(Decls);
+
+ if (Indent)
+ Indentation -= Policy.Indentation;
+}
+
+void DeclPrinter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
+ VisitDeclContext(D, false);
+}
+
+void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
+ std::string S = D->getNameAsString();
+ D->getUnderlyingType().getAsStringInternal(S, Policy);
+ if (!Policy.SuppressSpecifiers)
+ Out << "typedef ";
+ Out << S;
+}
+
+void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
+ Out << "enum " << D->getNameAsString() << " {\n";
+ VisitDeclContext(D);
+ Indent() << "}";
+}
+
+void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
+ Out << D->getKindName();
+ if (D->getIdentifier()) {
+ Out << " ";
+ Out << D->getNameAsString();
+ }
+
+ if (D->isDefinition()) {
+ Out << " {\n";
+ VisitDeclContext(D);
+ Indent() << "}";
+ }
+}
+
+void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
+ Out << D->getNameAsString();
+ if (Expr *Init = D->getInitExpr()) {
+ Out << " = ";
+ Init->printPretty(Out, Context, 0, Policy, Indentation);
+ }
+}
+
+void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
+ if (!Policy.SuppressSpecifiers) {
+ switch (D->getStorageClass()) {
+ case FunctionDecl::None: break;
+ case FunctionDecl::Extern: Out << "extern "; break;
+ case FunctionDecl::Static: Out << "static "; break;
+ case FunctionDecl::PrivateExtern: Out << "__private_extern__ "; break;
+ }
+
+ if (D->isInline()) Out << "inline ";
+ if (D->isVirtualAsWritten()) Out << "virtual ";
+ }
+
+ PrintingPolicy SubPolicy(Policy);
+ SubPolicy.SuppressSpecifiers = false;
+ std::string Proto = D->getNameAsString();
+ if (isa<FunctionType>(D->getType().getTypePtr())) {
+ const FunctionType *AFT = D->getType()->getAsFunctionType();
+
+ const FunctionProtoType *FT = 0;
+ if (D->hasWrittenPrototype())
+ FT = dyn_cast<FunctionProtoType>(AFT);
+
+ Proto += "(";
+ if (FT) {
+ llvm::raw_string_ostream POut(Proto);
+ DeclPrinter ParamPrinter(POut, Context, SubPolicy, Indentation);
+ for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
+ if (i) POut << ", ";
+ ParamPrinter.VisitParmVarDecl(D->getParamDecl(i));
+ }
+
+ if (FT->isVariadic()) {
+ if (D->getNumParams()) POut << ", ";
+ POut << "...";
+ }
+ } else if (D->isThisDeclarationADefinition() && !D->hasPrototype()) {
+ for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
+ if (i)
+ Proto += ", ";
+ Proto += D->getParamDecl(i)->getNameAsString();
+ }
+ }
+
+ Proto += ")";
+ AFT->getResultType().getAsStringInternal(Proto, Policy);
+ } else {
+ D->getType().getAsStringInternal(Proto, Policy);
+ }
+
+ Out << Proto;
+
+ if (D->isPure())
+ Out << " = 0";
+ else if (D->isDeleted())
+ Out << " = delete";
+ else if (D->isThisDeclarationADefinition()) {
+ if (!D->hasPrototype() && D->getNumParams()) {
+ // This is a K&R function definition, so we need to print the
+ // parameters.
+ Out << '\n';
+ DeclPrinter ParamPrinter(Out, Context, SubPolicy, Indentation);
+ Indentation += Policy.Indentation;
+ for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
+ Indent();
+ ParamPrinter.VisitParmVarDecl(D->getParamDecl(i));
+ Out << ";\n";
+ }
+ Indentation -= Policy.Indentation;
+ } else
+ Out << ' ';
+
+ D->getBody(Context)->printPretty(Out, Context, 0, SubPolicy, Indentation);
+ Out << '\n';
+ }
+}
+
+void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
+ if (!Policy.SuppressSpecifiers && D->isMutable())
+ Out << "mutable ";
+
+ std::string Name = D->getNameAsString();
+ D->getType().getAsStringInternal(Name, Policy);
+ Out << Name;
+
+ if (D->isBitField()) {
+ Out << " : ";
+ D->getBitWidth()->printPretty(Out, Context, 0, Policy, Indentation);
+ }
+}
+
+void DeclPrinter::VisitVarDecl(VarDecl *D) {
+ if (!Policy.SuppressSpecifiers && D->getStorageClass() != VarDecl::None)
+ Out << VarDecl::getStorageClassSpecifierString(D->getStorageClass()) << " ";
+
+ if (!Policy.SuppressSpecifiers && D->isThreadSpecified())
+ Out << "__thread ";
+
+ std::string Name = D->getNameAsString();
+ QualType T = D->getType();
+ if (OriginalParmVarDecl *Parm = dyn_cast<OriginalParmVarDecl>(D))
+ T = Parm->getOriginalType();
+ T.getAsStringInternal(Name, Policy);
+ Out << Name;
+ if (D->getInit()) {
+ if (D->hasCXXDirectInitializer())
+ Out << "(";
+ else
+ Out << " = ";
+ D->getInit()->printPretty(Out, Context, 0, Policy, Indentation);
+ if (D->hasCXXDirectInitializer())
+ Out << ")";
+ }
+}
+
+void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) {
+ VisitVarDecl(D);
+}
+
+void DeclPrinter::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) {
+ VisitVarDecl(D);
+}
+
+void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
+ Out << "__asm (";
+ D->getAsmString()->printPretty(Out, Context, 0, Policy, Indentation);
+ Out << ")";
+}
+
+//----------------------------------------------------------------------------
+// C++ declarations
+//----------------------------------------------------------------------------
+void DeclPrinter::VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D) {
+ assert(false &&
+ "OverloadedFunctionDecls aren't really decls and are never printed");
+}
+
+void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) {
+ Out << "namespace " << D->getNameAsString() << " {\n";
+ VisitDeclContext(D);
+ Indent() << "}";
+}
+
+void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
+ Out << "using namespace ";
+ if (D->getQualifier())
+ D->getQualifier()->print(Out, Policy);
+ Out << D->getNominatedNamespace()->getNameAsString();
+}
+
+void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+ Out << "namespace " << D->getNameAsString() << " = ";
+ if (D->getQualifier())
+ D->getQualifier()->print(Out, Policy);
+ Out << D->getAliasedNamespace()->getNameAsString();
+}
+
+void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
+ Out << D->getKindName();
+ if (D->getIdentifier()) {
+ Out << " ";
+ Out << D->getNameAsString();
+ }
+
+ if (D->isDefinition()) {
+ // Print the base classes
+ if (D->getNumBases()) {
+ Out << " : ";
+ for(CXXRecordDecl::base_class_iterator Base = D->bases_begin(),
+ BaseEnd = D->bases_end();
+ Base != BaseEnd; ++Base) {
+ if (Base != D->bases_begin())
+ Out << ", ";
+
+ if (Base->isVirtual())
+ Out << "virtual ";
+
+ switch(Base->getAccessSpecifierAsWritten()) {
+ case AS_none: break;
+ case AS_public: Out << "public "; break;
+ case AS_protected: Out << "protected "; break;
+ case AS_private: Out << " private "; break;
+ }
+
+ Out << Base->getType().getAsString(Policy);
+ }
+ }
+
+ // Print the class definition
+ // FIXME: Doesn't print access specifiers, e.g., "public:"
+ Out << " {\n";
+ VisitDeclContext(D);
+ Indent() << "}";
+ }
+}
+
+void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ const char *l;
+ if (D->getLanguage() == LinkageSpecDecl::lang_c)
+ l = "C";
+ else {
+ assert(D->getLanguage() == LinkageSpecDecl::lang_cxx &&
+ "unknown language in linkage specification");
+ l = "C++";
+ }
+
+ Out << "extern \"" << l << "\" ";
+ if (D->hasBraces()) {
+ Out << "{\n";
+ VisitDeclContext(D);
+ Indent() << "}";
+ } else
+ Visit(*D->decls_begin(Context));
+}
+
+void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) {
+ // TODO: Write template parameters.
+ Out << "template <...> ";
+ Visit(D->getTemplatedDecl());
+}
+
+//----------------------------------------------------------------------------
+// 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)->getNameAsString();
+ }
+}
+
+void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
+ if (OMD->isInstanceMethod())
+ Out << "- ";
+ else
+ Out << "+ ";
+ if (!OMD->getResultType().isNull())
+ Out << '(' << OMD->getResultType().getAsString(Policy) << ")";
+
+ std::string name = OMD->getSelector().getAsString();
+ std::string::size_type pos, lastPos = 0;
+ 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);
+ Out << " " << name.substr(lastPos, pos - lastPos);
+ Out << ":(" << (*PI)->getType().getAsString(Policy) << ")"
+ << (*PI)->getNameAsString();
+ lastPos = pos + 1;
+ }
+
+ if (OMD->param_begin() == OMD->param_end())
+ Out << " " << name;
+
+ if (OMD->isVariadic())
+ Out << ", ...";
+
+ if (OMD->getBody()) {
+ Out << ' ';
+ OMD->getBody()->printPretty(Out, Context, 0, Policy);
+ Out << '\n';
+ }
+}
+
+void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
+ std::string I = OID->getNameAsString();
+ ObjCInterfaceDecl *SID = OID->getSuperClass();
+
+ if (SID)
+ Out << "@implementation " << I << " : " << SID->getNameAsString();
+ else
+ Out << "@implementation " << I;
+ Out << "\n";
+ VisitDeclContext(OID, false);
+ Out << "@end";
+}
+
+void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
+ std::string I = OID->getNameAsString();
+ ObjCInterfaceDecl *SID = OID->getSuperClass();
+
+ if (SID)
+ Out << "@interface " << I << " : " << SID->getNameAsString();
+ else
+ Out << "@interface " << I;
+
+ // Protocols?
+ const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
+ if (!Protocols.empty()) {
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end(); I != E; ++I)
+ Out << (I == Protocols.begin() ? '<' : ',') << (*I)->getNameAsString();
+ }
+
+ if (!Protocols.empty())
+ Out << "> ";
+
+ if (OID->ivar_size() > 0) {
+ Out << "{\n";
+ Indentation += Policy.Indentation;
+ for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(),
+ E = OID->ivar_end(); I != E; ++I) {
+ Indent() << (*I)->getType().getAsString(Policy)
+ << ' ' << (*I)->getNameAsString() << ";\n";
+ }
+ Indentation -= Policy.Indentation;
+ Out << "}\n";
+ }
+
+ VisitDeclContext(OID, false);
+ Out << "@end";
+ // FIXME: implement the rest...
+}
+
+void DeclPrinter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
+ Out << "@protocol ";
+ for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(),
+ E = D->protocol_end();
+ I != E; ++I) {
+ if (I != D->protocol_begin()) Out << ", ";
+ Out << (*I)->getNameAsString();
+ }
+}
+
+void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
+ Out << "@protocol " << PID->getNameAsString() << '\n';
+ VisitDeclContext(PID, false);
+ Out << "@end";
+}
+
+void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
+ Out << "@implementation "
+ << PID->getClassInterface()->getNameAsString()
+ << '(' << PID->getNameAsString() << ")\n";
+
+ VisitDeclContext(PID, false);
+ Out << "@end";
+ // FIXME: implement the rest...
+}
+
+void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
+ Out << "@interface "
+ << PID->getClassInterface()->getNameAsString()
+ << '(' << PID->getNameAsString() << ")\n";
+ VisitDeclContext(PID, false);
+ Out << "@end";
+
+ // FIXME: implement the rest...
+}
+
+void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) {
+ Out << "@compatibility_alias " << AID->getNameAsString()
+ << ' ' << AID->getClassInterface()->getNameAsString() << ";\n";
+}
+
+/// PrintObjCPropertyDecl - print a property declaration.
+///
+void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
+ if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Required)
+ Out << "@required\n";
+ else if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Optional)
+ Out << "@optional\n";
+
+ Out << "@property";
+ if (PDecl->getPropertyAttributes() != ObjCPropertyDecl::OBJC_PR_noattr) {
+ bool first = true;
+ Out << " (";
+ if (PDecl->getPropertyAttributes() &
+ 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_assign) {
+ Out << (first ? ' ' : ',') << "assign";
+ 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_copy) {
+ Out << (first ? ' ' : ',') << "copy";
+ first = false;
+ }
+
+ if (PDecl->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_nonatomic) {
+ Out << (first ? ' ' : ',') << "nonatomic";
+ first = false;
+ }
+ Out << " )";
+ }
+ Out << ' ' << PDecl->getType().getAsString(Policy)
+ << ' ' << PDecl->getNameAsString();
+}
+
+void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
+ if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize)
+ Out << "@synthesize ";
+ else
+ Out << "@dynamic ";
+ Out << PID->getPropertyDecl()->getNameAsString();
+ if (PID->getPropertyIvarDecl())
+ Out << "=" << PID->getPropertyIvarDecl()->getNameAsString();
+}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
new file mode 100644
index 000000000000..f38ee825106e
--- /dev/null
+++ b/lib/AST/DeclTemplate.cpp
@@ -0,0 +1,324 @@
+//===--- DeclCXX.cpp - C++ Declaration AST Node Implementation ------------===//
+//
+// 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 C++ related Decl classes for templates.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/STLExtras.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// TemplateParameterList Implementation
+//===----------------------------------------------------------------------===//
+
+TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ Decl **Params, unsigned NumParams,
+ SourceLocation RAngleLoc)
+ : TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
+ NumParams(NumParams) {
+ for (unsigned Idx = 0; Idx < NumParams; ++Idx)
+ begin()[Idx] = Params[Idx];
+}
+
+TemplateParameterList *
+TemplateParameterList::Create(ASTContext &C, SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc, Decl **Params,
+ unsigned NumParams, SourceLocation RAngleLoc) {
+ unsigned Size = sizeof(TemplateParameterList) + sizeof(Decl *) * NumParams;
+ unsigned Align = llvm::AlignOf<TemplateParameterList>::Alignment;
+ void *Mem = C.Allocate(Size, Align);
+ return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params,
+ NumParams, RAngleLoc);
+}
+
+unsigned TemplateParameterList::getMinRequiredArguments() const {
+ unsigned NumRequiredArgs = size();
+ iterator Param = const_cast<TemplateParameterList *>(this)->end(),
+ ParamBegin = const_cast<TemplateParameterList *>(this)->begin();
+ while (Param != ParamBegin) {
+ --Param;
+ if (!(isa<TemplateTypeParmDecl>(*Param) &&
+ cast<TemplateTypeParmDecl>(*Param)->hasDefaultArgument()) &&
+ !(isa<NonTypeTemplateParmDecl>(*Param) &&
+ cast<NonTypeTemplateParmDecl>(*Param)->hasDefaultArgument()) &&
+ !(isa<TemplateTemplateParmDecl>(*Param) &&
+ cast<TemplateTemplateParmDecl>(*Param)->hasDefaultArgument()))
+ break;
+
+ --NumRequiredArgs;
+ }
+
+ return NumRequiredArgs;
+}
+
+//===----------------------------------------------------------------------===//
+// TemplateDecl Implementation
+//===----------------------------------------------------------------------===//
+
+TemplateDecl::~TemplateDecl() {
+}
+
+//===----------------------------------------------------------------------===//
+// FunctionTemplateDecl Implementation
+//===----------------------------------------------------------------------===//
+
+FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C,
+ DeclContext *DC,
+ SourceLocation L,
+ DeclarationName Name,
+ TemplateParameterList *Params,
+ NamedDecl *Decl) {
+ return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl);
+}
+
+//===----------------------------------------------------------------------===//
+// ClassTemplateDecl Implementation
+//===----------------------------------------------------------------------===//
+
+ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
+ DeclContext *DC,
+ SourceLocation L,
+ DeclarationName Name,
+ TemplateParameterList *Params,
+ NamedDecl *Decl,
+ ClassTemplateDecl *PrevDecl) {
+ Common *CommonPtr;
+ if (PrevDecl)
+ CommonPtr = PrevDecl->CommonPtr;
+ else
+ CommonPtr = new (C) Common;
+
+ return new (C) ClassTemplateDecl(DC, L, Name, Params, Decl, PrevDecl,
+ CommonPtr);
+}
+
+ClassTemplateDecl::~ClassTemplateDecl() {
+ assert(CommonPtr == 0 && "ClassTemplateDecl must be explicitly destroyed");
+}
+
+void ClassTemplateDecl::Destroy(ASTContext& C) {
+ if (!PreviousDeclaration) {
+ CommonPtr->~Common();
+ C.Deallocate((void*)CommonPtr);
+ }
+ CommonPtr = 0;
+
+ this->~ClassTemplateDecl();
+ C.Deallocate((void*)this);
+}
+
+QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) {
+ if (!CommonPtr->InjectedClassNameType.isNull())
+ return CommonPtr->InjectedClassNameType;
+
+ // FIXME: n2800 14.6.1p1 should say how the template arguments
+ // corresponding to template parameter packs should be pack
+ // expansions. We already say that in 14.6.2.1p2, so it would be
+ // better to fix that redundancy.
+
+ TemplateParameterList *Params = getTemplateParameters();
+
+ llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+ llvm::SmallVector<TemplateArgument, 16> CanonTemplateArgs;
+ TemplateArgs.reserve(Params->size());
+ CanonTemplateArgs.reserve(Params->size());
+
+ for (TemplateParameterList::iterator
+ Param = Params->begin(), ParamEnd = Params->end();
+ Param != ParamEnd; ++Param) {
+ if (isa<TemplateTypeParmDecl>(*Param)) {
+ QualType ParamType = Context.getTypeDeclType(cast<TypeDecl>(*Param));
+ TemplateArgs.push_back(TemplateArgument((*Param)->getLocation(),
+ ParamType));
+ CanonTemplateArgs.push_back(
+ TemplateArgument((*Param)->getLocation(),
+ Context.getCanonicalType(ParamType)));
+ } else if (NonTypeTemplateParmDecl *NTTP =
+ dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
+ // FIXME: Build canonical expression, too!
+ Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(),
+ NTTP->getLocation(),
+ NTTP->getType()->isDependentType(),
+ /*Value-dependent=*/true);
+ TemplateArgs.push_back(TemplateArgument(E));
+ CanonTemplateArgs.push_back(TemplateArgument(E));
+ } else {
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
+ TemplateArgs.push_back(TemplateArgument(TTP->getLocation(), TTP));
+ CanonTemplateArgs.push_back(TemplateArgument(TTP->getLocation(),
+ Context.getCanonicalDecl(TTP)));
+ }
+ }
+
+ // FIXME: I should really move the "build-the-canonical-type" logic
+ // into ASTContext::getTemplateSpecializationType.
+ TemplateName Name = TemplateName(this);
+ QualType CanonType = Context.getTemplateSpecializationType(
+ Context.getCanonicalTemplateName(Name),
+ &CanonTemplateArgs[0],
+ CanonTemplateArgs.size());
+
+ CommonPtr->InjectedClassNameType
+ = Context.getTemplateSpecializationType(Name,
+ &TemplateArgs[0],
+ TemplateArgs.size(),
+ CanonType);
+ return CommonPtr->InjectedClassNameType;
+}
+
+//===----------------------------------------------------------------------===//
+// TemplateTypeParm Allocation/Deallocation Method Implementations
+//===----------------------------------------------------------------------===//
+
+TemplateTypeParmDecl *
+TemplateTypeParmDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, unsigned D, unsigned P,
+ IdentifierInfo *Id, bool Typename) {
+ QualType Type = C.getTemplateTypeParmType(D, P, Id);
+ return new (C) TemplateTypeParmDecl(DC, L, Id, Typename, Type);
+}
+
+//===----------------------------------------------------------------------===//
+// NonTypeTemplateParmDecl Method Implementations
+//===----------------------------------------------------------------------===//
+
+NonTypeTemplateParmDecl *
+NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, unsigned D, unsigned P,
+ IdentifierInfo *Id, QualType T,
+ SourceLocation TypeSpecStartLoc) {
+ return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T,
+ TypeSpecStartLoc);
+}
+
+SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
+ return DefaultArgument? DefaultArgument->getSourceRange().getBegin()
+ : SourceLocation();
+}
+
+//===----------------------------------------------------------------------===//
+// TemplateTemplateParmDecl Method Implementations
+//===----------------------------------------------------------------------===//
+
+TemplateTemplateParmDecl *
+TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, unsigned D, unsigned P,
+ IdentifierInfo *Id,
+ TemplateParameterList *Params) {
+ return new (C) TemplateTemplateParmDecl(DC, L, D, P, Id, Params);
+}
+
+SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const {
+ return DefaultArgument? DefaultArgument->getSourceRange().getBegin()
+ : SourceLocation();
+}
+
+//===----------------------------------------------------------------------===//
+// TemplateArgument Implementation
+//===----------------------------------------------------------------------===//
+
+TemplateArgument::TemplateArgument(Expr *E) : Kind(Expression) {
+ TypeOrValue = reinterpret_cast<uintptr_t>(E);
+ StartLoc = E->getSourceRange().getBegin();
+}
+
+//===----------------------------------------------------------------------===//
+// TemplateArgumentList Implementation
+//===----------------------------------------------------------------------===//
+TemplateArgumentList::TemplateArgumentList(ASTContext &Context,
+ TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ bool CopyArgs)
+ : NumArguments(NumTemplateArgs) {
+ if (!CopyArgs) {
+ Arguments.setPointer(TemplateArgs);
+ Arguments.setInt(1);
+ return;
+ }
+
+ unsigned Size = sizeof(TemplateArgument) * NumTemplateArgs;
+ unsigned Align = llvm::AlignOf<TemplateArgument>::Alignment;
+ void *Mem = Context.Allocate(Size, Align);
+ Arguments.setPointer((TemplateArgument *)Mem);
+ Arguments.setInt(0);
+
+ TemplateArgument *Args = (TemplateArgument *)Mem;
+ for (unsigned I = 0; I != NumTemplateArgs; ++I)
+ new (Args + I) TemplateArgument(TemplateArgs[I]);
+}
+
+TemplateArgumentList::~TemplateArgumentList() {
+ // FIXME: Deallocate template arguments
+}
+
+//===----------------------------------------------------------------------===//
+// ClassTemplateSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+ClassTemplateSpecializationDecl::
+ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
+ DeclContext *DC, SourceLocation L,
+ ClassTemplateDecl *SpecializedTemplate,
+ TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs)
+ : CXXRecordDecl(DK,
+ SpecializedTemplate->getTemplatedDecl()->getTagKind(),
+ DC, L,
+ // FIXME: Should we use DeclarationName for the name of
+ // class template specializations?
+ SpecializedTemplate->getIdentifier()),
+ SpecializedTemplate(SpecializedTemplate),
+ TemplateArgs(Context, TemplateArgs, NumTemplateArgs, /*CopyArgs=*/true),
+ SpecializationKind(TSK_Undeclared) {
+}
+
+ClassTemplateSpecializationDecl *
+ClassTemplateSpecializationDecl::Create(ASTContext &Context,
+ DeclContext *DC, SourceLocation L,
+ ClassTemplateDecl *SpecializedTemplate,
+ TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ ClassTemplateSpecializationDecl *PrevDecl) {
+ ClassTemplateSpecializationDecl *Result
+ = new (Context)ClassTemplateSpecializationDecl(Context,
+ ClassTemplateSpecialization,
+ DC, L,
+ SpecializedTemplate,
+ TemplateArgs,
+ NumTemplateArgs);
+ Context.getTypeDeclType(Result, PrevDecl);
+ return Result;
+}
+
+//===----------------------------------------------------------------------===//
+// ClassTemplatePartialSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+ClassTemplatePartialSpecializationDecl *
+ClassTemplatePartialSpecializationDecl::
+Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
+ TemplateParameterList *Params,
+ ClassTemplateDecl *SpecializedTemplate,
+ TemplateArgument *TemplateArgs, unsigned NumTemplateArgs,
+ ClassTemplatePartialSpecializationDecl *PrevDecl) {
+ ClassTemplatePartialSpecializationDecl *Result
+ = new (Context)ClassTemplatePartialSpecializationDecl(Context,
+ DC, L, Params,
+ SpecializedTemplate,
+ TemplateArgs,
+ NumTemplateArgs);
+ Result->setSpecializationKind(TSK_ExplicitSpecialization);
+ Context.getTypeDeclType(Result, PrevDecl);
+ return Result;
+}
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
new file mode 100644
index 000000000000..a17abde77730
--- /dev/null
+++ b/lib/AST/DeclarationName.cpp
@@ -0,0 +1,355 @@
+//===-- DeclarationName.cpp - Declaration names implementation --*- 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 DeclarationName and DeclarationNameTable
+// classes.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/Decl.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
+using namespace clang;
+
+namespace clang {
+/// CXXSpecialName - Records the type associated with one of the
+/// "special" kinds of declaration names in C++, e.g., constructors,
+/// destructors, and conversion functions.
+class CXXSpecialName
+ : public DeclarationNameExtra, public llvm::FoldingSetNode {
+public:
+ /// Type - The type associated with this declaration name.
+ QualType Type;
+
+ /// FETokenInfo - Extra information associated with this declaration
+ /// name that can be used by the front end.
+ void *FETokenInfo;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ ID.AddInteger(ExtraKindOrNumArgs);
+ ID.AddPointer(Type.getAsOpaquePtr());
+ }
+};
+
+/// CXXOperatorIdName - Contains extra information for the name of an
+/// overloaded operator in C++, such as "operator+.
+class CXXOperatorIdName : public DeclarationNameExtra {
+public:
+ /// FETokenInfo - Extra information associated with this operator
+ /// name that can be used by the front end.
+ void *FETokenInfo;
+};
+
+bool operator<(DeclarationName LHS, DeclarationName RHS) {
+ if (IdentifierInfo *LhsId = LHS.getAsIdentifierInfo())
+ if (IdentifierInfo *RhsId = RHS.getAsIdentifierInfo())
+ return strcmp(LhsId->getName(), RhsId->getName()) < 0;
+
+ return LHS.getAsOpaqueInteger() < RHS.getAsOpaqueInteger();
+}
+
+} // end namespace clang
+
+DeclarationName::DeclarationName(Selector Sel) {
+ if (!Sel.getAsOpaquePtr()) {
+ Ptr = StoredObjCZeroArgSelector;
+ return;
+ }
+
+ switch (Sel.getNumArgs()) {
+ case 0:
+ Ptr = reinterpret_cast<uintptr_t>(Sel.getAsIdentifierInfo());
+ assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo");
+ Ptr |= StoredObjCZeroArgSelector;
+ break;
+
+ case 1:
+ Ptr = reinterpret_cast<uintptr_t>(Sel.getAsIdentifierInfo());
+ assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo");
+ Ptr |= StoredObjCOneArgSelector;
+ break;
+
+ default:
+ Ptr = Sel.InfoPtr & ~Selector::ArgFlags;
+ assert((Ptr & PtrMask) == 0 && "Improperly aligned MultiKeywordSelector");
+ Ptr |= StoredDeclarationNameExtra;
+ break;
+ }
+}
+
+DeclarationName::NameKind DeclarationName::getNameKind() const {
+ switch (getStoredNameKind()) {
+ case StoredIdentifier: return Identifier;
+ case StoredObjCZeroArgSelector: return ObjCZeroArgSelector;
+ case StoredObjCOneArgSelector: return ObjCOneArgSelector;
+
+ case StoredDeclarationNameExtra:
+ switch (getExtra()->ExtraKindOrNumArgs) {
+ case DeclarationNameExtra::CXXConstructor:
+ return CXXConstructorName;
+
+ case DeclarationNameExtra::CXXDestructor:
+ return CXXDestructorName;
+
+ case DeclarationNameExtra::CXXConversionFunction:
+ return CXXConversionFunctionName;
+
+ case DeclarationNameExtra::CXXUsingDirective:
+ return CXXUsingDirective;
+
+ default:
+ // Check if we have one of the CXXOperator* enumeration values.
+ if (getExtra()->ExtraKindOrNumArgs <
+ DeclarationNameExtra::CXXUsingDirective)
+ return CXXOperatorName;
+
+ return ObjCMultiArgSelector;
+ }
+ break;
+ }
+
+ // Can't actually get here.
+ assert(0 && "This should be unreachable!");
+ return Identifier;
+}
+
+std::string DeclarationName::getAsString() const {
+ switch (getNameKind()) {
+ case Identifier:
+ if (const IdentifierInfo *II = getAsIdentifierInfo())
+ return II->getName();
+ return "";
+
+ case ObjCZeroArgSelector:
+ case ObjCOneArgSelector:
+ case ObjCMultiArgSelector:
+ return getObjCSelector().getAsString();
+
+ case CXXConstructorName: {
+ QualType ClassType = getCXXNameType();
+ if (const RecordType *ClassRec = ClassType->getAsRecordType())
+ return ClassRec->getDecl()->getNameAsString();
+ return ClassType.getAsString();
+ }
+
+ case CXXDestructorName: {
+ std::string Result = "~";
+ QualType Type = getCXXNameType();
+ if (const RecordType *Rec = Type->getAsRecordType())
+ Result += Rec->getDecl()->getNameAsString();
+ else
+ Result += Type.getAsString();
+ return Result;
+ }
+
+ case CXXOperatorName: {
+ static const char *OperatorNames[NUM_OVERLOADED_OPERATORS] = {
+ 0,
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ Spelling,
+#include "clang/Basic/OperatorKinds.def"
+ };
+ const char *OpName = OperatorNames[getCXXOverloadedOperator()];
+ assert(OpName && "not an overloaded operator");
+
+ std::string Result = "operator";
+ if (OpName[0] >= 'a' && OpName[0] <= 'z')
+ Result += ' ';
+ Result += OpName;
+ return Result;
+ }
+
+ case CXXConversionFunctionName: {
+ std::string Result = "operator ";
+ QualType Type = getCXXNameType();
+ if (const RecordType *Rec = Type->getAsRecordType())
+ Result += Rec->getDecl()->getNameAsString();
+ else
+ Result += Type.getAsString();
+ return Result;
+ }
+ case CXXUsingDirective:
+ return "<using-directive>";
+ }
+
+ assert(false && "Unexpected declaration name kind");
+ return "";
+}
+
+QualType DeclarationName::getCXXNameType() const {
+ if (CXXSpecialName *CXXName = getAsCXXSpecialName())
+ return CXXName->Type;
+ else
+ return QualType();
+}
+
+OverloadedOperatorKind DeclarationName::getCXXOverloadedOperator() const {
+ if (CXXOperatorIdName *CXXOp = getAsCXXOperatorIdName()) {
+ unsigned value
+ = CXXOp->ExtraKindOrNumArgs - DeclarationNameExtra::CXXConversionFunction;
+ return static_cast<OverloadedOperatorKind>(value);
+ } else {
+ return OO_None;
+ }
+}
+
+Selector DeclarationName::getObjCSelector() const {
+ switch (getNameKind()) {
+ case ObjCZeroArgSelector:
+ return Selector(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask), 0);
+
+ case ObjCOneArgSelector:
+ return Selector(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask), 1);
+
+ case ObjCMultiArgSelector:
+ return Selector(reinterpret_cast<MultiKeywordSelector *>(Ptr & ~PtrMask));
+
+ default:
+ break;
+ }
+
+ return Selector();
+}
+
+void *DeclarationName::getFETokenInfoAsVoid() const {
+ switch (getNameKind()) {
+ case Identifier:
+ return getAsIdentifierInfo()->getFETokenInfo<void>();
+
+ case CXXConstructorName:
+ case CXXDestructorName:
+ case CXXConversionFunctionName:
+ return getAsCXXSpecialName()->FETokenInfo;
+
+ case CXXOperatorName:
+ return getAsCXXOperatorIdName()->FETokenInfo;
+
+ default:
+ assert(false && "Declaration name has no FETokenInfo");
+ }
+ return 0;
+}
+
+void DeclarationName::setFETokenInfo(void *T) {
+ switch (getNameKind()) {
+ case Identifier:
+ getAsIdentifierInfo()->setFETokenInfo(T);
+ break;
+
+ case CXXConstructorName:
+ case CXXDestructorName:
+ case CXXConversionFunctionName:
+ getAsCXXSpecialName()->FETokenInfo = T;
+ break;
+
+ case CXXOperatorName:
+ getAsCXXOperatorIdName()->FETokenInfo = T;
+ break;
+
+ default:
+ assert(false && "Declaration name has no FETokenInfo");
+ }
+}
+
+DeclarationName DeclarationName::getUsingDirectiveName() {
+ // Single instance of DeclarationNameExtra for using-directive
+ static DeclarationNameExtra UDirExtra =
+ { DeclarationNameExtra::CXXUsingDirective };
+
+ uintptr_t Ptr = reinterpret_cast<uintptr_t>(&UDirExtra);
+ Ptr |= StoredDeclarationNameExtra;
+
+ return DeclarationName(Ptr);
+}
+
+DeclarationNameTable::DeclarationNameTable() {
+ CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>;
+
+ // Initialize the overloaded operator names.
+ CXXOperatorNames = new CXXOperatorIdName[NUM_OVERLOADED_OPERATORS];
+ for (unsigned Op = 0; Op < NUM_OVERLOADED_OPERATORS; ++Op) {
+ CXXOperatorNames[Op].ExtraKindOrNumArgs
+ = Op + DeclarationNameExtra::CXXConversionFunction;
+ CXXOperatorNames[Op].FETokenInfo = 0;
+ }
+}
+
+DeclarationNameTable::~DeclarationNameTable() {
+ llvm::FoldingSet<CXXSpecialName> *set =
+ static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl);
+ llvm::FoldingSetIterator<CXXSpecialName> I = set->begin(), E = set->end();
+
+ while (I != E) {
+ CXXSpecialName *n = &*I++;
+ delete n;
+ }
+
+ delete set;
+ delete [] CXXOperatorNames;
+}
+
+DeclarationName
+DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind,
+ QualType Ty) {
+ assert(Kind >= DeclarationName::CXXConstructorName &&
+ Kind <= DeclarationName::CXXConversionFunctionName &&
+ "Kind must be a C++ special name kind");
+ assert(Ty->isCanonical() &&
+ "Can only build C++ special names from canonical types");
+ llvm::FoldingSet<CXXSpecialName> *SpecialNames
+ = static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl);
+
+ DeclarationNameExtra::ExtraKind EKind;
+ switch (Kind) {
+ case DeclarationName::CXXConstructorName:
+ EKind = DeclarationNameExtra::CXXConstructor;
+ assert(Ty.getCVRQualifiers() == 0 &&"Constructor type must be unqualified");
+ break;
+ case DeclarationName::CXXDestructorName:
+ EKind = DeclarationNameExtra::CXXDestructor;
+ assert(Ty.getCVRQualifiers() == 0 && "Destructor type must be unqualified");
+ break;
+ case DeclarationName::CXXConversionFunctionName:
+ EKind = DeclarationNameExtra::CXXConversionFunction;
+ break;
+ default:
+ return DeclarationName();
+ }
+
+ // Unique selector, to guarantee there is one per name.
+ llvm::FoldingSetNodeID ID;
+ ID.AddInteger(EKind);
+ ID.AddPointer(Ty.getAsOpaquePtr());
+
+ void *InsertPos = 0;
+ if (CXXSpecialName *Name = SpecialNames->FindNodeOrInsertPos(ID, InsertPos))
+ return DeclarationName(Name);
+
+ CXXSpecialName *SpecialName = new CXXSpecialName;
+ SpecialName->ExtraKindOrNumArgs = EKind;
+ SpecialName->Type = Ty;
+ SpecialName->FETokenInfo = 0;
+
+ SpecialNames->InsertNode(SpecialName, InsertPos);
+ return DeclarationName(SpecialName);
+}
+
+DeclarationName
+DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) {
+ return DeclarationName(&CXXOperatorNames[(unsigned)Op]);
+}
+
+unsigned
+llvm::DenseMapInfo<clang::DeclarationName>::
+getHashValue(clang::DeclarationName N) {
+ return DenseMapInfo<void*>::getHashValue(N.getAsOpaquePtr());
+}
+
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
new file mode 100644
index 000000000000..4a53a4123d11
--- /dev/null
+++ b/lib/AST/Expr.cpp
@@ -0,0 +1,2059 @@
+//===--- Expr.cpp - Expression AST Node Implementation --------------------===//
+//
+// 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 Expr class and subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Expr.h"
+#include "clang/AST/APValue.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/TargetInfo.h"
+#include <algorithm>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Primary Expressions.
+//===----------------------------------------------------------------------===//
+
+PredefinedExpr* PredefinedExpr::Clone(ASTContext &C) const {
+ return new (C) PredefinedExpr(Loc, getType(), Type);
+}
+
+IntegerLiteral* IntegerLiteral::Clone(ASTContext &C) const {
+ return new (C) IntegerLiteral(Value, getType(), Loc);
+}
+
+CharacterLiteral* CharacterLiteral::Clone(ASTContext &C) const {
+ return new (C) CharacterLiteral(Value, IsWide, getType(), Loc);
+}
+
+FloatingLiteral* FloatingLiteral::Clone(ASTContext &C) const {
+ bool exact = IsExact;
+ return new (C) FloatingLiteral(Value, &exact, getType(), Loc);
+}
+
+ImaginaryLiteral* ImaginaryLiteral::Clone(ASTContext &C) const {
+ // FIXME: Use virtual Clone(), once it is available
+ Expr *ClonedVal = 0;
+ if (const IntegerLiteral *IntLit = dyn_cast<IntegerLiteral>(Val))
+ ClonedVal = IntLit->Clone(C);
+ else
+ ClonedVal = cast<FloatingLiteral>(Val)->Clone(C);
+ return new (C) ImaginaryLiteral(ClonedVal, getType());
+}
+
+GNUNullExpr* GNUNullExpr::Clone(ASTContext &C) const {
+ return new (C) GNUNullExpr(getType(), TokenLoc);
+}
+
+/// getValueAsApproximateDouble - This returns the value as an inaccurate
+/// double. Note that this may cause loss of precision, but is useful for
+/// debugging dumps, etc.
+double FloatingLiteral::getValueAsApproximateDouble() const {
+ llvm::APFloat V = getValue();
+ bool ignored;
+ V.convert(llvm::APFloat::IEEEdouble, llvm::APFloat::rmNearestTiesToEven,
+ &ignored);
+ return V.convertToDouble();
+}
+
+StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData,
+ unsigned ByteLength, bool Wide,
+ QualType Ty,
+ const SourceLocation *Loc,
+ unsigned NumStrs) {
+ // Allocate enough space for the StringLiteral plus an array of locations for
+ // any concatenated string tokens.
+ void *Mem = C.Allocate(sizeof(StringLiteral)+
+ sizeof(SourceLocation)*(NumStrs-1),
+ llvm::alignof<StringLiteral>());
+ StringLiteral *SL = new (Mem) StringLiteral(Ty);
+
+ // OPTIMIZE: could allocate this appended to the StringLiteral.
+ char *AStrData = new (C, 1) char[ByteLength];
+ memcpy(AStrData, StrData, ByteLength);
+ SL->StrData = AStrData;
+ SL->ByteLength = ByteLength;
+ SL->IsWide = Wide;
+ SL->TokLocs[0] = Loc[0];
+ SL->NumConcatenated = NumStrs;
+
+ if (NumStrs != 1)
+ memcpy(&SL->TokLocs[1], Loc+1, sizeof(SourceLocation)*(NumStrs-1));
+ return SL;
+}
+
+StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) {
+ void *Mem = C.Allocate(sizeof(StringLiteral)+
+ sizeof(SourceLocation)*(NumStrs-1),
+ llvm::alignof<StringLiteral>());
+ StringLiteral *SL = new (Mem) StringLiteral(QualType());
+ SL->StrData = 0;
+ SL->ByteLength = 0;
+ SL->NumConcatenated = NumStrs;
+ return SL;
+}
+
+StringLiteral* StringLiteral::Clone(ASTContext &C) const {
+ return Create(C, StrData, ByteLength, IsWide, getType(),
+ TokLocs, NumConcatenated);
+}
+
+void StringLiteral::Destroy(ASTContext &C) {
+ C.Deallocate(const_cast<char*>(StrData));
+ this->~StringLiteral();
+ C.Deallocate(this);
+}
+
+void StringLiteral::setStrData(ASTContext &C, const char *Str, unsigned Len) {
+ if (StrData)
+ C.Deallocate(const_cast<char*>(StrData));
+
+ char *AStrData = new (C, 1) char[Len];
+ memcpy(AStrData, Str, Len);
+ StrData = AStrData;
+ ByteLength = Len;
+}
+
+/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
+/// corresponds to, e.g. "sizeof" or "[pre]++".
+const char *UnaryOperator::getOpcodeStr(Opcode Op) {
+ switch (Op) {
+ default: assert(0 && "Unknown unary operator");
+ case PostInc: return "++";
+ case PostDec: return "--";
+ case PreInc: return "++";
+ case PreDec: return "--";
+ case AddrOf: return "&";
+ case Deref: return "*";
+ case Plus: return "+";
+ case Minus: return "-";
+ case Not: return "~";
+ case LNot: return "!";
+ case Real: return "__real";
+ case Imag: return "__imag";
+ case Extension: return "__extension__";
+ case OffsetOf: return "__builtin_offsetof";
+ }
+}
+
+UnaryOperator::Opcode
+UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) {
+ switch (OO) {
+ default: assert(false && "No unary operator for overloaded function");
+ case OO_PlusPlus: return Postfix ? PostInc : PreInc;
+ case OO_MinusMinus: return Postfix ? PostDec : PreDec;
+ case OO_Amp: return AddrOf;
+ case OO_Star: return Deref;
+ case OO_Plus: return Plus;
+ case OO_Minus: return Minus;
+ case OO_Tilde: return Not;
+ case OO_Exclaim: return LNot;
+ }
+}
+
+OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) {
+ switch (Opc) {
+ case PostInc: case PreInc: return OO_PlusPlus;
+ case PostDec: case PreDec: return OO_MinusMinus;
+ case AddrOf: return OO_Amp;
+ case Deref: return OO_Star;
+ case Plus: return OO_Plus;
+ case Minus: return OO_Minus;
+ case Not: return OO_Tilde;
+ case LNot: return OO_Exclaim;
+ default: return OO_None;
+ }
+}
+
+
+//===----------------------------------------------------------------------===//
+// Postfix Operators.
+//===----------------------------------------------------------------------===//
+
+CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, Expr **args,
+ unsigned numargs, QualType t, SourceLocation rparenloc)
+ : Expr(SC, t,
+ fn->isTypeDependent() || hasAnyTypeDependentArguments(args, numargs),
+ fn->isValueDependent() || hasAnyValueDependentArguments(args,numargs)),
+ NumArgs(numargs) {
+
+ SubExprs = new (C) Stmt*[numargs+1];
+ SubExprs[FN] = fn;
+ for (unsigned i = 0; i != numargs; ++i)
+ SubExprs[i+ARGS_START] = args[i];
+
+ RParenLoc = rparenloc;
+}
+
+CallExpr::CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs,
+ QualType t, SourceLocation rparenloc)
+ : Expr(CallExprClass, t,
+ fn->isTypeDependent() || hasAnyTypeDependentArguments(args, numargs),
+ fn->isValueDependent() || hasAnyValueDependentArguments(args,numargs)),
+ NumArgs(numargs) {
+
+ SubExprs = new (C) Stmt*[numargs+1];
+ SubExprs[FN] = fn;
+ for (unsigned i = 0; i != numargs; ++i)
+ SubExprs[i+ARGS_START] = args[i];
+
+ RParenLoc = rparenloc;
+}
+
+CallExpr::CallExpr(ASTContext &C, EmptyShell Empty)
+ : Expr(CallExprClass, Empty), SubExprs(0), NumArgs(0) {
+ SubExprs = new (C) Stmt*[1];
+}
+
+void CallExpr::Destroy(ASTContext& C) {
+ DestroyChildren(C);
+ if (SubExprs) C.Deallocate(SubExprs);
+ this->~CallExpr();
+ C.Deallocate(this);
+}
+
+/// setNumArgs - This changes the number of arguments present in this call.
+/// Any orphaned expressions are deleted by this, and any new operands are set
+/// to null.
+void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) {
+ // No change, just return.
+ if (NumArgs == getNumArgs()) return;
+
+ // If shrinking # arguments, just delete the extras and forgot them.
+ if (NumArgs < getNumArgs()) {
+ for (unsigned i = NumArgs, e = getNumArgs(); i != e; ++i)
+ getArg(i)->Destroy(C);
+ this->NumArgs = NumArgs;
+ return;
+ }
+
+ // Otherwise, we are growing the # arguments. New an bigger argument array.
+ Stmt **NewSubExprs = new Stmt*[NumArgs+1];
+ // Copy over args.
+ for (unsigned i = 0; i != getNumArgs()+ARGS_START; ++i)
+ NewSubExprs[i] = SubExprs[i];
+ // Null out new args.
+ for (unsigned i = getNumArgs()+ARGS_START; i != NumArgs+ARGS_START; ++i)
+ NewSubExprs[i] = 0;
+
+ if (SubExprs) C.Deallocate(SubExprs);
+ SubExprs = NewSubExprs;
+ this->NumArgs = NumArgs;
+}
+
+/// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If
+/// not, return 0.
+unsigned CallExpr::isBuiltinCall(ASTContext &Context) const {
+ // All simple function calls (e.g. func()) are implicitly cast to pointer to
+ // function. As a result, we try and obtain the DeclRefExpr from the
+ // ImplicitCastExpr.
+ const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(getCallee());
+ if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()).
+ return 0;
+
+ const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr());
+ if (!DRE)
+ return 0;
+
+ const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl());
+ if (!FDecl)
+ return 0;
+
+ if (!FDecl->getIdentifier())
+ return 0;
+
+ return FDecl->getBuiltinID(Context);
+}
+
+QualType CallExpr::getCallReturnType() const {
+ QualType CalleeType = getCallee()->getType();
+ if (const PointerType *FnTypePtr = CalleeType->getAsPointerType())
+ CalleeType = FnTypePtr->getPointeeType();
+ else if (const BlockPointerType *BPT = CalleeType->getAsBlockPointerType())
+ CalleeType = BPT->getPointeeType();
+
+ const FunctionType *FnType = CalleeType->getAsFunctionType();
+ return FnType->getResultType();
+}
+
+/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
+/// corresponds to, e.g. "<<=".
+const char *BinaryOperator::getOpcodeStr(Opcode Op) {
+ switch (Op) {
+ case PtrMemD: return ".*";
+ case PtrMemI: return "->*";
+ case Mul: return "*";
+ case Div: return "/";
+ case Rem: return "%";
+ case Add: return "+";
+ case Sub: return "-";
+ case Shl: return "<<";
+ case Shr: return ">>";
+ case LT: return "<";
+ case GT: return ">";
+ case LE: return "<=";
+ case GE: return ">=";
+ case EQ: return "==";
+ case NE: return "!=";
+ case And: return "&";
+ case Xor: return "^";
+ case Or: return "|";
+ case LAnd: return "&&";
+ case LOr: return "||";
+ case Assign: return "=";
+ case MulAssign: return "*=";
+ case DivAssign: return "/=";
+ case RemAssign: return "%=";
+ case AddAssign: return "+=";
+ case SubAssign: return "-=";
+ case ShlAssign: return "<<=";
+ case ShrAssign: return ">>=";
+ case AndAssign: return "&=";
+ case XorAssign: return "^=";
+ case OrAssign: return "|=";
+ case Comma: return ",";
+ }
+
+ return "";
+}
+
+BinaryOperator::Opcode
+BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) {
+ switch (OO) {
+ default: assert(false && "Not an overloadable binary operator");
+ case OO_Plus: return Add;
+ case OO_Minus: return Sub;
+ case OO_Star: return Mul;
+ case OO_Slash: return Div;
+ case OO_Percent: return Rem;
+ case OO_Caret: return Xor;
+ case OO_Amp: return And;
+ case OO_Pipe: return Or;
+ case OO_Equal: return Assign;
+ case OO_Less: return LT;
+ case OO_Greater: return GT;
+ case OO_PlusEqual: return AddAssign;
+ case OO_MinusEqual: return SubAssign;
+ case OO_StarEqual: return MulAssign;
+ case OO_SlashEqual: return DivAssign;
+ case OO_PercentEqual: return RemAssign;
+ case OO_CaretEqual: return XorAssign;
+ case OO_AmpEqual: return AndAssign;
+ case OO_PipeEqual: return OrAssign;
+ case OO_LessLess: return Shl;
+ case OO_GreaterGreater: return Shr;
+ case OO_LessLessEqual: return ShlAssign;
+ case OO_GreaterGreaterEqual: return ShrAssign;
+ case OO_EqualEqual: return EQ;
+ case OO_ExclaimEqual: return NE;
+ case OO_LessEqual: return LE;
+ case OO_GreaterEqual: return GE;
+ case OO_AmpAmp: return LAnd;
+ case OO_PipePipe: return LOr;
+ case OO_Comma: return Comma;
+ case OO_ArrowStar: return PtrMemI;
+ }
+}
+
+OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
+ static const OverloadedOperatorKind OverOps[] = {
+ /* .* Cannot be overloaded */OO_None, OO_ArrowStar,
+ OO_Star, OO_Slash, OO_Percent,
+ OO_Plus, OO_Minus,
+ OO_LessLess, OO_GreaterGreater,
+ OO_Less, OO_Greater, OO_LessEqual, OO_GreaterEqual,
+ OO_EqualEqual, OO_ExclaimEqual,
+ OO_Amp,
+ OO_Caret,
+ OO_Pipe,
+ OO_AmpAmp,
+ OO_PipePipe,
+ OO_Equal, OO_StarEqual,
+ OO_SlashEqual, OO_PercentEqual,
+ OO_PlusEqual, OO_MinusEqual,
+ OO_LessLessEqual, OO_GreaterGreaterEqual,
+ OO_AmpEqual, OO_CaretEqual,
+ OO_PipeEqual,
+ OO_Comma
+ };
+ return OverOps[Opc];
+}
+
+InitListExpr::InitListExpr(SourceLocation lbraceloc,
+ Expr **initExprs, unsigned numInits,
+ SourceLocation rbraceloc)
+ : Expr(InitListExprClass, QualType(),
+ hasAnyTypeDependentArguments(initExprs, numInits),
+ hasAnyValueDependentArguments(initExprs, numInits)),
+ LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0),
+ UnionFieldInit(0), HadArrayRangeDesignator(false) {
+
+ InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits);
+}
+
+void InitListExpr::reserveInits(unsigned NumInits) {
+ if (NumInits > InitExprs.size())
+ InitExprs.reserve(NumInits);
+}
+
+void InitListExpr::resizeInits(ASTContext &Context, unsigned NumInits) {
+ for (unsigned Idx = NumInits, LastIdx = InitExprs.size();
+ Idx < LastIdx; ++Idx)
+ InitExprs[Idx]->Destroy(Context);
+ InitExprs.resize(NumInits, 0);
+}
+
+Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) {
+ if (Init >= InitExprs.size()) {
+ InitExprs.insert(InitExprs.end(), Init - InitExprs.size() + 1, 0);
+ InitExprs.back() = expr;
+ return 0;
+ }
+
+ Expr *Result = cast_or_null<Expr>(InitExprs[Init]);
+ InitExprs[Init] = expr;
+ return Result;
+}
+
+/// getFunctionType - Return the underlying function type for this block.
+///
+const FunctionType *BlockExpr::getFunctionType() const {
+ return getType()->getAsBlockPointerType()->
+ getPointeeType()->getAsFunctionType();
+}
+
+SourceLocation BlockExpr::getCaretLocation() const {
+ return TheBlock->getCaretLocation();
+}
+const Stmt *BlockExpr::getBody() const {
+ return TheBlock->getBody();
+}
+Stmt *BlockExpr::getBody() {
+ return TheBlock->getBody();
+}
+
+
+//===----------------------------------------------------------------------===//
+// Generic Expression Routines
+//===----------------------------------------------------------------------===//
+
+/// isUnusedResultAWarning - Return true if this immediate expression should
+/// be warned about if the result is unused. If so, fill in Loc and Ranges
+/// with location to warn on and the source range[s] to report with the
+/// warning.
+bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
+ SourceRange &R2) const {
+ // Don't warn if the expr is type dependent. The type could end up
+ // instantiating to void.
+ if (isTypeDependent())
+ return false;
+
+ switch (getStmtClass()) {
+ default:
+ Loc = getExprLoc();
+ R1 = getSourceRange();
+ return true;
+ case ParenExprClass:
+ return cast<ParenExpr>(this)->getSubExpr()->
+ isUnusedResultAWarning(Loc, R1, R2);
+ case UnaryOperatorClass: {
+ const UnaryOperator *UO = cast<UnaryOperator>(this);
+
+ switch (UO->getOpcode()) {
+ default: break;
+ case UnaryOperator::PostInc:
+ case UnaryOperator::PostDec:
+ case UnaryOperator::PreInc:
+ case UnaryOperator::PreDec: // ++/--
+ return false; // Not a warning.
+ case UnaryOperator::Deref:
+ // Dereferencing a volatile pointer is a side-effect.
+ if (getType().isVolatileQualified())
+ return false;
+ break;
+ case UnaryOperator::Real:
+ case UnaryOperator::Imag:
+ // accessing a piece of a volatile complex is a side-effect.
+ if (UO->getSubExpr()->getType().isVolatileQualified())
+ return false;
+ break;
+ case UnaryOperator::Extension:
+ return UO->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2);
+ }
+ Loc = UO->getOperatorLoc();
+ R1 = UO->getSubExpr()->getSourceRange();
+ return true;
+ }
+ case BinaryOperatorClass: {
+ const BinaryOperator *BO = cast<BinaryOperator>(this);
+ // Consider comma to have side effects if the LHS or RHS does.
+ if (BO->getOpcode() == BinaryOperator::Comma)
+ return BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2) ||
+ BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2);
+
+ if (BO->isAssignmentOp())
+ return false;
+ Loc = BO->getOperatorLoc();
+ R1 = BO->getLHS()->getSourceRange();
+ R2 = BO->getRHS()->getSourceRange();
+ return true;
+ }
+ case CompoundAssignOperatorClass:
+ return false;
+
+ case ConditionalOperatorClass: {
+ // The condition must be evaluated, but if either the LHS or RHS is a
+ // warning, warn about them.
+ const ConditionalOperator *Exp = cast<ConditionalOperator>(this);
+ if (Exp->getLHS() && Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2))
+ return true;
+ return Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2);
+ }
+
+ case MemberExprClass:
+ // If the base pointer or element is to a volatile pointer/field, accessing
+ // it is a side effect.
+ if (getType().isVolatileQualified())
+ return false;
+ Loc = cast<MemberExpr>(this)->getMemberLoc();
+ R1 = SourceRange(Loc, Loc);
+ R2 = cast<MemberExpr>(this)->getBase()->getSourceRange();
+ return true;
+
+ case ArraySubscriptExprClass:
+ // If the base pointer or element is to a volatile pointer/field, accessing
+ // it is a side effect.
+ if (getType().isVolatileQualified())
+ return false;
+ Loc = cast<ArraySubscriptExpr>(this)->getRBracketLoc();
+ R1 = cast<ArraySubscriptExpr>(this)->getLHS()->getSourceRange();
+ R2 = cast<ArraySubscriptExpr>(this)->getRHS()->getSourceRange();
+ return true;
+
+ case CallExprClass:
+ case CXXOperatorCallExprClass:
+ case CXXMemberCallExprClass: {
+ // If this is a direct call, get the callee.
+ const CallExpr *CE = cast<CallExpr>(this);
+ const Expr *CalleeExpr = CE->getCallee()->IgnoreParenCasts();
+ if (const DeclRefExpr *CalleeDRE = dyn_cast<DeclRefExpr>(CalleeExpr)) {
+ // If the callee has attribute pure, const, or warn_unused_result, warn
+ // about it. void foo() { strlen("bar"); } should warn.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CalleeDRE->getDecl()))
+ if (FD->getAttr<WarnUnusedResultAttr>() ||
+ FD->getAttr<PureAttr>() || FD->getAttr<ConstAttr>()) {
+ Loc = CE->getCallee()->getLocStart();
+ R1 = CE->getCallee()->getSourceRange();
+
+ if (unsigned NumArgs = CE->getNumArgs())
+ R2 = SourceRange(CE->getArg(0)->getLocStart(),
+ CE->getArg(NumArgs-1)->getLocEnd());
+ return true;
+ }
+ }
+ return false;
+ }
+ case ObjCMessageExprClass:
+ return false;
+ case StmtExprClass: {
+ // Statement exprs don't logically have side effects themselves, but are
+ // sometimes used in macros in ways that give them a type that is unused.
+ // For example ({ blah; foo(); }) will end up with a type if foo has a type.
+ // however, if the result of the stmt expr is dead, we don't want to emit a
+ // warning.
+ const CompoundStmt *CS = cast<StmtExpr>(this)->getSubStmt();
+ if (!CS->body_empty())
+ if (const Expr *E = dyn_cast<Expr>(CS->body_back()))
+ return E->isUnusedResultAWarning(Loc, R1, R2);
+
+ Loc = cast<StmtExpr>(this)->getLParenLoc();
+ R1 = getSourceRange();
+ return true;
+ }
+ case CStyleCastExprClass:
+ // If this is a cast to void, check the operand. Otherwise, the result of
+ // the cast is unused.
+ if (getType()->isVoidType())
+ return cast<CastExpr>(this)->getSubExpr()->isUnusedResultAWarning(Loc,
+ R1, R2);
+ Loc = cast<CStyleCastExpr>(this)->getLParenLoc();
+ R1 = cast<CStyleCastExpr>(this)->getSubExpr()->getSourceRange();
+ return true;
+ case CXXFunctionalCastExprClass:
+ // If this is a cast to void, check the operand. Otherwise, the result of
+ // the cast is unused.
+ if (getType()->isVoidType())
+ return cast<CastExpr>(this)->getSubExpr()->isUnusedResultAWarning(Loc,
+ R1, R2);
+ Loc = cast<CXXFunctionalCastExpr>(this)->getTypeBeginLoc();
+ R1 = cast<CXXFunctionalCastExpr>(this)->getSubExpr()->getSourceRange();
+ return true;
+
+ case ImplicitCastExprClass:
+ // Check the operand, since implicit casts are inserted by Sema
+ return cast<ImplicitCastExpr>(this)
+ ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2);
+
+ case CXXDefaultArgExprClass:
+ return cast<CXXDefaultArgExpr>(this)
+ ->getExpr()->isUnusedResultAWarning(Loc, R1, R2);
+
+ case CXXNewExprClass:
+ // FIXME: In theory, there might be new expressions that don't have side
+ // effects (e.g. a placement new with an uninitialized POD).
+ case CXXDeleteExprClass:
+ return false;
+ case CXXExprWithTemporariesClass:
+ return cast<CXXExprWithTemporaries>(this)
+ ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2);
+ }
+}
+
+/// DeclCanBeLvalue - Determine whether the given declaration can be
+/// an lvalue. This is a helper routine for isLvalue.
+static bool DeclCanBeLvalue(const NamedDecl *Decl, ASTContext &Ctx) {
+ // C++ [temp.param]p6:
+ // A non-type non-reference template-parameter is not an lvalue.
+ if (const NonTypeTemplateParmDecl *NTTParm
+ = dyn_cast<NonTypeTemplateParmDecl>(Decl))
+ return NTTParm->getType()->isReferenceType();
+
+ return isa<VarDecl>(Decl) || isa<FieldDecl>(Decl) ||
+ // C++ 3.10p2: An lvalue refers to an object or function.
+ (Ctx.getLangOptions().CPlusPlus &&
+ (isa<FunctionDecl>(Decl) || isa<OverloadedFunctionDecl>(Decl)));
+}
+
+/// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or an
+/// incomplete type other than void. Nonarray expressions that can be lvalues:
+/// - name, where name must be a variable
+/// - e[i]
+/// - (e), where e must be an lvalue
+/// - e.name, where e must be an lvalue
+/// - e->name
+/// - *e, the type of e cannot be a function type
+/// - string-constant
+/// - (__real__ e) and (__imag__ e) where e is an lvalue [GNU extension]
+/// - reference type [C++ [expr]]
+///
+Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
+ assert(!TR->isReferenceType() && "Expressions can't have reference type.");
+
+ isLvalueResult Res = isLvalueInternal(Ctx);
+ if (Res != LV_Valid || Ctx.getLangOptions().CPlusPlus)
+ return Res;
+
+ // first, check the type (C99 6.3.2.1). Expressions with function
+ // type in C are not lvalues, but they can be lvalues in C++.
+ if (TR->isFunctionType())
+ return LV_NotObjectType;
+
+ // Allow qualified void which is an incomplete type other than void (yuck).
+ if (TR->isVoidType() && !Ctx.getCanonicalType(TR).getCVRQualifiers())
+ return LV_IncompleteVoidType;
+
+ return LV_Valid;
+}
+
+// Check whether the expression can be sanely treated like an l-value
+Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
+ switch (getStmtClass()) {
+ case StringLiteralClass: // C99 6.5.1p4
+ case ObjCEncodeExprClass: // @encode behaves like its string in every way.
+ return LV_Valid;
+ case ArraySubscriptExprClass: // C99 6.5.3p4 (e1[e2] == (*((e1)+(e2))))
+ // For vectors, make sure base is an lvalue (i.e. not a function call).
+ if (cast<ArraySubscriptExpr>(this)->getBase()->getType()->isVectorType())
+ return cast<ArraySubscriptExpr>(this)->getBase()->isLvalue(Ctx);
+ return LV_Valid;
+ case DeclRefExprClass:
+ case QualifiedDeclRefExprClass: { // C99 6.5.1p2
+ const NamedDecl *RefdDecl = cast<DeclRefExpr>(this)->getDecl();
+ if (DeclCanBeLvalue(RefdDecl, Ctx))
+ return LV_Valid;
+ break;
+ }
+ case BlockDeclRefExprClass: {
+ const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(this);
+ if (isa<VarDecl>(BDR->getDecl()))
+ return LV_Valid;
+ break;
+ }
+ case MemberExprClass: {
+ const MemberExpr *m = cast<MemberExpr>(this);
+ if (Ctx.getLangOptions().CPlusPlus) { // C++ [expr.ref]p4:
+ NamedDecl *Member = m->getMemberDecl();
+ // C++ [expr.ref]p4:
+ // If E2 is declared to have type "reference to T", then E1.E2
+ // is an lvalue.
+ if (ValueDecl *Value = dyn_cast<ValueDecl>(Member))
+ if (Value->getType()->isReferenceType())
+ return LV_Valid;
+
+ // -- If E2 is a static data member [...] then E1.E2 is an lvalue.
+ if (isa<VarDecl>(Member) && Member->getDeclContext()->isRecord())
+ return LV_Valid;
+
+ // -- If E2 is a non-static data member [...]. If E1 is an
+ // lvalue, then E1.E2 is an lvalue.
+ if (isa<FieldDecl>(Member))
+ return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx);
+
+ // -- If it refers to a static member function [...], then
+ // E1.E2 is an lvalue.
+ // -- Otherwise, if E1.E2 refers to a non-static member
+ // function [...], then E1.E2 is not an lvalue.
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member))
+ return Method->isStatic()? LV_Valid : LV_MemberFunction;
+
+ // -- If E2 is a member enumerator [...], the expression E1.E2
+ // is not an lvalue.
+ if (isa<EnumConstantDecl>(Member))
+ return LV_InvalidExpression;
+
+ // Not an lvalue.
+ return LV_InvalidExpression;
+ }
+
+ // C99 6.5.2.3p4
+ return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx);
+ }
+ case UnaryOperatorClass:
+ if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref)
+ return LV_Valid; // C99 6.5.3p4
+
+ if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Real ||
+ cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Imag ||
+ cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Extension)
+ return cast<UnaryOperator>(this)->getSubExpr()->isLvalue(Ctx); // GNU.
+
+ if (Ctx.getLangOptions().CPlusPlus && // C++ [expr.pre.incr]p1
+ (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::PreInc ||
+ cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::PreDec))
+ return LV_Valid;
+ break;
+ case ImplicitCastExprClass:
+ return cast<ImplicitCastExpr>(this)->isLvalueCast()? LV_Valid
+ : LV_InvalidExpression;
+ case ParenExprClass: // C99 6.5.1p5
+ return cast<ParenExpr>(this)->getSubExpr()->isLvalue(Ctx);
+ case BinaryOperatorClass:
+ case CompoundAssignOperatorClass: {
+ const BinaryOperator *BinOp = cast<BinaryOperator>(this);
+
+ if (Ctx.getLangOptions().CPlusPlus && // C++ [expr.comma]p1
+ BinOp->getOpcode() == BinaryOperator::Comma)
+ return BinOp->getRHS()->isLvalue(Ctx);
+
+ // C++ [expr.mptr.oper]p6
+ if ((BinOp->getOpcode() == BinaryOperator::PtrMemD ||
+ BinOp->getOpcode() == BinaryOperator::PtrMemI) &&
+ !BinOp->getType()->isFunctionType())
+ return BinOp->getLHS()->isLvalue(Ctx);
+
+ if (!BinOp->isAssignmentOp())
+ return LV_InvalidExpression;
+
+ if (Ctx.getLangOptions().CPlusPlus)
+ // C++ [expr.ass]p1:
+ // The result of an assignment operation [...] is an lvalue.
+ return LV_Valid;
+
+
+ // C99 6.5.16:
+ // An assignment expression [...] is not an lvalue.
+ return LV_InvalidExpression;
+ }
+ case CallExprClass:
+ case CXXOperatorCallExprClass:
+ case CXXMemberCallExprClass: {
+ // C++0x [expr.call]p10
+ // A function call is an lvalue if and only if the result type
+ // is an lvalue reference.
+ QualType ReturnType = cast<CallExpr>(this)->getCallReturnType();
+ if (ReturnType->isLValueReferenceType())
+ return LV_Valid;
+
+ break;
+ }
+ case CompoundLiteralExprClass: // C99 6.5.2.5p5
+ return LV_Valid;
+ case ChooseExprClass:
+ // __builtin_choose_expr is an lvalue if the selected operand is.
+ return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)->isLvalue(Ctx);
+ case ExtVectorElementExprClass:
+ if (cast<ExtVectorElementExpr>(this)->containsDuplicateElements())
+ return LV_DuplicateVectorComponents;
+ return LV_Valid;
+ case ObjCIvarRefExprClass: // ObjC instance variables are lvalues.
+ return LV_Valid;
+ case ObjCPropertyRefExprClass: // FIXME: check if read-only property.
+ return LV_Valid;
+ case ObjCKVCRefExprClass: // FIXME: check if read-only property.
+ return LV_Valid;
+ case PredefinedExprClass:
+ return LV_Valid;
+ case CXXDefaultArgExprClass:
+ return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue(Ctx);
+ case CXXConditionDeclExprClass:
+ return LV_Valid;
+ case CStyleCastExprClass:
+ case CXXFunctionalCastExprClass:
+ case CXXStaticCastExprClass:
+ case CXXDynamicCastExprClass:
+ case CXXReinterpretCastExprClass:
+ case CXXConstCastExprClass:
+ // The result of an explicit cast is an lvalue if the type we are
+ // casting to is an lvalue reference type. See C++ [expr.cast]p1,
+ // C++ [expr.static.cast]p2, C++ [expr.dynamic.cast]p2,
+ // C++ [expr.reinterpret.cast]p1, C++ [expr.const.cast]p1.
+ if (cast<ExplicitCastExpr>(this)->getTypeAsWritten()->
+ isLValueReferenceType())
+ return LV_Valid;
+ break;
+ case CXXTypeidExprClass:
+ // C++ 5.2.8p1: The result of a typeid expression is an lvalue of ...
+ return LV_Valid;
+ case ConditionalOperatorClass: {
+ // Complicated handling is only for C++.
+ if (!Ctx.getLangOptions().CPlusPlus)
+ return LV_InvalidExpression;
+
+ // Sema should have taken care to ensure that a CXXTemporaryObjectExpr is
+ // everywhere there's an object converted to an rvalue. Also, any other
+ // casts should be wrapped by ImplicitCastExprs. There's just the special
+ // case involving throws to work out.
+ const ConditionalOperator *Cond = cast<ConditionalOperator>(this);
+ Expr *True = Cond->getTrueExpr();
+ Expr *False = Cond->getFalseExpr();
+ // C++0x 5.16p2
+ // If either the second or the third operand has type (cv) void, [...]
+ // the result [...] is an rvalue.
+ if (True->getType()->isVoidType() || False->getType()->isVoidType())
+ return LV_InvalidExpression;
+
+ // Both sides must be lvalues for the result to be an lvalue.
+ if (True->isLvalue(Ctx) != LV_Valid || False->isLvalue(Ctx) != LV_Valid)
+ return LV_InvalidExpression;
+
+ // That's it.
+ return LV_Valid;
+ }
+
+ default:
+ break;
+ }
+ return LV_InvalidExpression;
+}
+
+/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type,
+/// does not have an incomplete type, does not have a const-qualified type, and
+/// if it is a structure or union, does not have any member (including,
+/// recursively, any member or element of all contained aggregates or unions)
+/// with a const-qualified type.
+Expr::isModifiableLvalueResult
+Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
+ isLvalueResult lvalResult = isLvalue(Ctx);
+
+ switch (lvalResult) {
+ case LV_Valid:
+ // C++ 3.10p11: Functions cannot be modified, but pointers to
+ // functions can be modifiable.
+ if (Ctx.getLangOptions().CPlusPlus && TR->isFunctionType())
+ return MLV_NotObjectType;
+ break;
+
+ case LV_NotObjectType: return MLV_NotObjectType;
+ case LV_IncompleteVoidType: return MLV_IncompleteVoidType;
+ case LV_DuplicateVectorComponents: return MLV_DuplicateVectorComponents;
+ case LV_InvalidExpression:
+ // If the top level is a C-style cast, and the subexpression is a valid
+ // lvalue, then this is probably a use of the old-school "cast as lvalue"
+ // GCC extension. We don't support it, but we want to produce good
+ // diagnostics when it happens so that the user knows why.
+ if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(IgnoreParens())) {
+ if (CE->getSubExpr()->isLvalue(Ctx) == LV_Valid) {
+ if (Loc)
+ *Loc = CE->getLParenLoc();
+ return MLV_LValueCast;
+ }
+ }
+ return MLV_InvalidExpression;
+ case LV_MemberFunction: return MLV_MemberFunction;
+ }
+
+ // The following is illegal:
+ // void takeclosure(void (^C)(void));
+ // void func() { int x = 1; takeclosure(^{ x = 7; }); }
+ //
+ if (isa<BlockDeclRefExpr>(this)) {
+ const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(this);
+ if (!BDR->isByRef() && isa<VarDecl>(BDR->getDecl()))
+ return MLV_NotBlockQualified;
+ }
+
+ QualType CT = Ctx.getCanonicalType(getType());
+
+ if (CT.isConstQualified())
+ return MLV_ConstQualified;
+ if (CT->isArrayType())
+ return MLV_ArrayType;
+ if (CT->isIncompleteType())
+ return MLV_IncompleteType;
+
+ if (const RecordType *r = CT->getAsRecordType()) {
+ if (r->hasConstFields())
+ return MLV_ConstQualified;
+ }
+
+ // Assigning to an 'implicit' property?
+ else if (isa<ObjCKVCRefExpr>(this)) {
+ const ObjCKVCRefExpr* KVCExpr = cast<ObjCKVCRefExpr>(this);
+ if (KVCExpr->getSetterMethod() == 0)
+ return MLV_NoSetterProperty;
+ }
+ return MLV_Valid;
+}
+
+/// hasGlobalStorage - Return true if this expression has static storage
+/// duration. This means that the address of this expression is a link-time
+/// constant.
+bool Expr::hasGlobalStorage() const {
+ switch (getStmtClass()) {
+ default:
+ return false;
+ case BlockExprClass:
+ return true;
+ case ParenExprClass:
+ return cast<ParenExpr>(this)->getSubExpr()->hasGlobalStorage();
+ case ImplicitCastExprClass:
+ return cast<ImplicitCastExpr>(this)->getSubExpr()->hasGlobalStorage();
+ case CompoundLiteralExprClass:
+ return cast<CompoundLiteralExpr>(this)->isFileScope();
+ case DeclRefExprClass:
+ case QualifiedDeclRefExprClass: {
+ const Decl *D = cast<DeclRefExpr>(this)->getDecl();
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ return VD->hasGlobalStorage();
+ if (isa<FunctionDecl>(D))
+ return true;
+ return false;
+ }
+ case MemberExprClass: {
+ const MemberExpr *M = cast<MemberExpr>(this);
+ return !M->isArrow() && M->getBase()->hasGlobalStorage();
+ }
+ case ArraySubscriptExprClass:
+ return cast<ArraySubscriptExpr>(this)->getBase()->hasGlobalStorage();
+ case PredefinedExprClass:
+ return true;
+ case CXXDefaultArgExprClass:
+ return cast<CXXDefaultArgExpr>(this)->getExpr()->hasGlobalStorage();
+ }
+}
+
+/// isOBJCGCCandidate - Check if an expression is objc gc'able.
+///
+bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
+ switch (getStmtClass()) {
+ default:
+ return false;
+ case ObjCIvarRefExprClass:
+ return true;
+ case Expr::UnaryOperatorClass:
+ return cast<UnaryOperator>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
+ case ParenExprClass:
+ return cast<ParenExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
+ case ImplicitCastExprClass:
+ return cast<ImplicitCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
+ case CStyleCastExprClass:
+ return cast<CStyleCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
+ case DeclRefExprClass:
+ case QualifiedDeclRefExprClass: {
+ const Decl *D = cast<DeclRefExpr>(this)->getDecl();
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (VD->hasGlobalStorage())
+ return true;
+ QualType T = VD->getType();
+ // dereferencing to an object pointer is always a gc'able candidate
+ if (T->isPointerType() &&
+ Ctx.isObjCObjectPointerType(T->getAsPointerType()->getPointeeType()))
+ return true;
+
+ }
+ return false;
+ }
+ case MemberExprClass: {
+ const MemberExpr *M = cast<MemberExpr>(this);
+ return M->getBase()->isOBJCGCCandidate(Ctx);
+ }
+ case ArraySubscriptExprClass:
+ return cast<ArraySubscriptExpr>(this)->getBase()->isOBJCGCCandidate(Ctx);
+ }
+}
+Expr* Expr::IgnoreParens() {
+ Expr* E = this;
+ while (ParenExpr* P = dyn_cast<ParenExpr>(E))
+ E = P->getSubExpr();
+
+ return E;
+}
+
+/// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr
+/// or CastExprs or ImplicitCastExprs, returning their operand.
+Expr *Expr::IgnoreParenCasts() {
+ Expr *E = this;
+ while (true) {
+ if (ParenExpr *P = dyn_cast<ParenExpr>(E))
+ E = P->getSubExpr();
+ else if (CastExpr *P = dyn_cast<CastExpr>(E))
+ E = P->getSubExpr();
+ else
+ return E;
+ }
+}
+
+/// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the
+/// value (including ptr->int casts of the same size). Strip off any
+/// ParenExpr or CastExprs, returning their operand.
+Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
+ Expr *E = this;
+ while (true) {
+ if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
+ E = P->getSubExpr();
+ continue;
+ }
+
+ if (CastExpr *P = dyn_cast<CastExpr>(E)) {
+ // We ignore integer <-> casts that are of the same width, ptr<->ptr and
+ // ptr<->int casts of the same width. We also ignore all identify casts.
+ Expr *SE = P->getSubExpr();
+
+ if (Ctx.hasSameUnqualifiedType(E->getType(), SE->getType())) {
+ E = SE;
+ continue;
+ }
+
+ if ((E->getType()->isPointerType() || E->getType()->isIntegralType()) &&
+ (SE->getType()->isPointerType() || SE->getType()->isIntegralType()) &&
+ Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SE->getType())) {
+ E = SE;
+ continue;
+ }
+ }
+
+ return E;
+ }
+}
+
+
+/// hasAnyTypeDependentArguments - Determines if any of the expressions
+/// in Exprs is type-dependent.
+bool Expr::hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs) {
+ for (unsigned I = 0; I < NumExprs; ++I)
+ if (Exprs[I]->isTypeDependent())
+ return true;
+
+ return false;
+}
+
+/// hasAnyValueDependentArguments - Determines if any of the expressions
+/// in Exprs is value-dependent.
+bool Expr::hasAnyValueDependentArguments(Expr** Exprs, unsigned NumExprs) {
+ for (unsigned I = 0; I < NumExprs; ++I)
+ if (Exprs[I]->isValueDependent())
+ return true;
+
+ return false;
+}
+
+bool Expr::isConstantInitializer(ASTContext &Ctx) const {
+ // This function is attempting whether an expression is an initializer
+ // which can be evaluated at compile-time. isEvaluatable handles most
+ // of the cases, but it can't deal with some initializer-specific
+ // expressions, and it can't deal with aggregates; we deal with those here,
+ // and fall back to isEvaluatable for the other cases.
+
+ // FIXME: This function assumes the variable being assigned to
+ // isn't a reference type!
+
+ switch (getStmtClass()) {
+ default: break;
+ case StringLiteralClass:
+ case ObjCEncodeExprClass:
+ return true;
+ case CompoundLiteralExprClass: {
+ // This handles gcc's extension that allows global initializers like
+ // "struct x {int x;} x = (struct x) {};".
+ // FIXME: This accepts other cases it shouldn't!
+ const Expr *Exp = cast<CompoundLiteralExpr>(this)->getInitializer();
+ return Exp->isConstantInitializer(Ctx);
+ }
+ case InitListExprClass: {
+ // FIXME: This doesn't deal with fields with reference types correctly.
+ // FIXME: This incorrectly allows pointers cast to integers to be assigned
+ // to bitfields.
+ const InitListExpr *Exp = cast<InitListExpr>(this);
+ unsigned numInits = Exp->getNumInits();
+ for (unsigned i = 0; i < numInits; i++) {
+ if (!Exp->getInit(i)->isConstantInitializer(Ctx))
+ return false;
+ }
+ return true;
+ }
+ case ImplicitValueInitExprClass:
+ return true;
+ case ParenExprClass: {
+ return cast<ParenExpr>(this)->getSubExpr()->isConstantInitializer(Ctx);
+ }
+ case UnaryOperatorClass: {
+ const UnaryOperator* Exp = cast<UnaryOperator>(this);
+ if (Exp->getOpcode() == UnaryOperator::Extension)
+ return Exp->getSubExpr()->isConstantInitializer(Ctx);
+ break;
+ }
+ case ImplicitCastExprClass:
+ case CStyleCastExprClass:
+ // Handle casts with a destination that's a struct or union; this
+ // deals with both the gcc no-op struct cast extension and the
+ // cast-to-union extension.
+ if (getType()->isRecordType())
+ return cast<CastExpr>(this)->getSubExpr()->isConstantInitializer(Ctx);
+ break;
+ }
+
+ return isEvaluatable(Ctx);
+}
+
+/// isIntegerConstantExpr - this recursive routine will test if an expression is
+/// an integer constant expression.
+
+/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero,
+/// comma, etc
+///
+/// FIXME: Handle offsetof. Two things to do: Handle GCC's __builtin_offsetof
+/// to support gcc 4.0+ and handle the idiom GCC recognizes with a null pointer
+/// cast+dereference.
+
+// CheckICE - This function does the fundamental ICE checking: the returned
+// ICEDiag contains a Val of 0, 1, or 2, and a possibly null SourceLocation.
+// Note that to reduce code duplication, this helper does no evaluation
+// itself; the caller checks whether the expression is evaluatable, and
+// in the rare cases where CheckICE actually cares about the evaluated
+// value, it calls into Evalute.
+//
+// Meanings of Val:
+// 0: This expression is an ICE if it can be evaluated by Evaluate.
+// 1: This expression is not an ICE, but if it isn't evaluated, it's
+// a legal subexpression for an ICE. This return value is used to handle
+// the comma operator in C99 mode.
+// 2: This expression is not an ICE, and is not a legal subexpression for one.
+
+struct ICEDiag {
+ unsigned Val;
+ SourceLocation Loc;
+
+ public:
+ ICEDiag(unsigned v, SourceLocation l) : Val(v), Loc(l) {}
+ ICEDiag() : Val(0) {}
+};
+
+ICEDiag NoDiag() { return ICEDiag(); }
+
+static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) {
+ Expr::EvalResult EVResult;
+ if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects ||
+ !EVResult.Val.isInt()) {
+ return ICEDiag(2, E->getLocStart());
+ }
+ return NoDiag();
+}
+
+static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
+ assert(!E->isValueDependent() && "Should not see value dependent exprs!");
+ if (!E->getType()->isIntegralType()) {
+ return ICEDiag(2, E->getLocStart());
+ }
+
+ switch (E->getStmtClass()) {
+ default:
+ return ICEDiag(2, E->getLocStart());
+ case Expr::ParenExprClass:
+ return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx);
+ case Expr::IntegerLiteralClass:
+ case Expr::CharacterLiteralClass:
+ case Expr::CXXBoolLiteralExprClass:
+ case Expr::CXXZeroInitValueExprClass:
+ case Expr::TypesCompatibleExprClass:
+ case Expr::UnaryTypeTraitExprClass:
+ return NoDiag();
+ case Expr::CallExprClass:
+ case Expr::CXXOperatorCallExprClass: {
+ const CallExpr *CE = cast<CallExpr>(E);
+ if (CE->isBuiltinCall(Ctx))
+ return CheckEvalInICE(E, Ctx);
+ return ICEDiag(2, E->getLocStart());
+ }
+ case Expr::DeclRefExprClass:
+ case Expr::QualifiedDeclRefExprClass:
+ if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
+ return NoDiag();
+ if (Ctx.getLangOptions().CPlusPlus &&
+ E->getType().getCVRQualifiers() == QualType::Const) {
+ // C++ 7.1.5.1p2
+ // A variable of non-volatile const-qualified integral or enumeration
+ // type initialized by an ICE can be used in ICEs.
+ if (const VarDecl *Dcl =
+ dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) {
+ if (Dcl->isInitKnownICE()) {
+ // We have already checked whether this subexpression is an
+ // integral constant expression.
+ if (Dcl->isInitICE())
+ return NoDiag();
+ else
+ return ICEDiag(2, E->getLocStart());
+ }
+
+ if (const Expr *Init = Dcl->getInit()) {
+ ICEDiag Result = CheckICE(Init, Ctx);
+ // Cache the result of the ICE test.
+ Dcl->setInitKnownICE(Ctx, Result.Val == 0);
+ return Result;
+ }
+ }
+ }
+ return ICEDiag(2, E->getLocStart());
+ case Expr::UnaryOperatorClass: {
+ const UnaryOperator *Exp = cast<UnaryOperator>(E);
+ switch (Exp->getOpcode()) {
+ default:
+ return ICEDiag(2, E->getLocStart());
+ case UnaryOperator::Extension:
+ case UnaryOperator::LNot:
+ case UnaryOperator::Plus:
+ case UnaryOperator::Minus:
+ case UnaryOperator::Not:
+ case UnaryOperator::Real:
+ case UnaryOperator::Imag:
+ return CheckICE(Exp->getSubExpr(), Ctx);
+ case UnaryOperator::OffsetOf:
+ // Note that per C99, offsetof must be an ICE. And AFAIK, using
+ // Evaluate matches the proposed gcc behavior for cases like
+ // "offsetof(struct s{int x[4];}, x[!.0])". This doesn't affect
+ // compliance: we should warn earlier for offsetof expressions with
+ // array subscripts that aren't ICEs, and if the array subscripts
+ // are ICEs, the value of the offsetof must be an integer constant.
+ return CheckEvalInICE(E, Ctx);
+ }
+ }
+ case Expr::SizeOfAlignOfExprClass: {
+ const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E);
+ if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType())
+ return ICEDiag(2, E->getLocStart());
+ return NoDiag();
+ }
+ case Expr::BinaryOperatorClass: {
+ const BinaryOperator *Exp = cast<BinaryOperator>(E);
+ switch (Exp->getOpcode()) {
+ default:
+ return ICEDiag(2, E->getLocStart());
+ case BinaryOperator::Mul:
+ case BinaryOperator::Div:
+ case BinaryOperator::Rem:
+ case BinaryOperator::Add:
+ case BinaryOperator::Sub:
+ case BinaryOperator::Shl:
+ case BinaryOperator::Shr:
+ case BinaryOperator::LT:
+ case BinaryOperator::GT:
+ case BinaryOperator::LE:
+ case BinaryOperator::GE:
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ case BinaryOperator::And:
+ case BinaryOperator::Xor:
+ case BinaryOperator::Or:
+ case BinaryOperator::Comma: {
+ ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
+ ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
+ if (Exp->getOpcode() == BinaryOperator::Div ||
+ Exp->getOpcode() == BinaryOperator::Rem) {
+ // Evaluate gives an error for undefined Div/Rem, so make sure
+ // we don't evaluate one.
+ if (LHSResult.Val != 2 && RHSResult.Val != 2) {
+ llvm::APSInt REval = Exp->getRHS()->EvaluateAsInt(Ctx);
+ if (REval == 0)
+ return ICEDiag(1, E->getLocStart());
+ if (REval.isSigned() && REval.isAllOnesValue()) {
+ llvm::APSInt LEval = Exp->getLHS()->EvaluateAsInt(Ctx);
+ if (LEval.isMinSignedValue())
+ return ICEDiag(1, E->getLocStart());
+ }
+ }
+ }
+ if (Exp->getOpcode() == BinaryOperator::Comma) {
+ if (Ctx.getLangOptions().C99) {
+ // C99 6.6p3 introduces a strange edge case: comma can be in an ICE
+ // if it isn't evaluated.
+ if (LHSResult.Val == 0 && RHSResult.Val == 0)
+ return ICEDiag(1, E->getLocStart());
+ } else {
+ // In both C89 and C++, commas in ICEs are illegal.
+ return ICEDiag(2, E->getLocStart());
+ }
+ }
+ if (LHSResult.Val >= RHSResult.Val)
+ return LHSResult;
+ return RHSResult;
+ }
+ case BinaryOperator::LAnd:
+ case BinaryOperator::LOr: {
+ ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
+ ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
+ if (LHSResult.Val == 0 && RHSResult.Val == 1) {
+ // Rare case where the RHS has a comma "side-effect"; we need
+ // to actually check the condition to see whether the side
+ // with the comma is evaluated.
+ if ((Exp->getOpcode() == BinaryOperator::LAnd) !=
+ (Exp->getLHS()->EvaluateAsInt(Ctx) == 0))
+ return RHSResult;
+ return NoDiag();
+ }
+
+ if (LHSResult.Val >= RHSResult.Val)
+ return LHSResult;
+ return RHSResult;
+ }
+ }
+ }
+ case Expr::ImplicitCastExprClass:
+ case Expr::CStyleCastExprClass:
+ case Expr::CXXFunctionalCastExprClass: {
+ const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr();
+ if (SubExpr->getType()->isIntegralType())
+ return CheckICE(SubExpr, Ctx);
+ if (isa<FloatingLiteral>(SubExpr->IgnoreParens()))
+ return NoDiag();
+ return ICEDiag(2, E->getLocStart());
+ }
+ case Expr::ConditionalOperatorClass: {
+ const ConditionalOperator *Exp = cast<ConditionalOperator>(E);
+ // If the condition (ignoring parens) is a __builtin_constant_p call,
+ // then only the true side is actually considered in an integer constant
+ // expression, and it is fully evaluated. This is an important GNU
+ // extension. See GCC PR38377 for discussion.
+ if (const CallExpr *CallCE = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
+ if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) {
+ Expr::EvalResult EVResult;
+ if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects ||
+ !EVResult.Val.isInt()) {
+ return ICEDiag(2, E->getLocStart());
+ }
+ return NoDiag();
+ }
+ ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
+ ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
+ ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
+ if (CondResult.Val == 2)
+ return CondResult;
+ if (TrueResult.Val == 2)
+ return TrueResult;
+ if (FalseResult.Val == 2)
+ return FalseResult;
+ if (CondResult.Val == 1)
+ return CondResult;
+ if (TrueResult.Val == 0 && FalseResult.Val == 0)
+ return NoDiag();
+ // Rare case where the diagnostics depend on which side is evaluated
+ // Note that if we get here, CondResult is 0, and at least one of
+ // TrueResult and FalseResult is non-zero.
+ if (Exp->getCond()->EvaluateAsInt(Ctx) == 0) {
+ return FalseResult;
+ }
+ return TrueResult;
+ }
+ case Expr::CXXDefaultArgExprClass:
+ return CheckICE(cast<CXXDefaultArgExpr>(E)->getExpr(), Ctx);
+ case Expr::ChooseExprClass: {
+ return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx);
+ }
+ }
+}
+
+bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
+ SourceLocation *Loc, bool isEvaluated) const {
+ ICEDiag d = CheckICE(this, Ctx);
+ if (d.Val != 0) {
+ if (Loc) *Loc = d.Loc;
+ return false;
+ }
+ EvalResult EvalResult;
+ if (!Evaluate(EvalResult, Ctx))
+ assert(0 && "ICE cannot be evaluated!");
+ assert(!EvalResult.HasSideEffects && "ICE with side effects!");
+ assert(EvalResult.Val.isInt() && "ICE that isn't integer!");
+ Result = EvalResult.Val.getInt();
+ return true;
+}
+
+/// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an
+/// integer constant expression with the value zero, or if this is one that is
+/// cast to void*.
+bool Expr::isNullPointerConstant(ASTContext &Ctx) const
+{
+ // Strip off a cast to void*, if it exists. Except in C++.
+ if (const ExplicitCastExpr *CE = dyn_cast<ExplicitCastExpr>(this)) {
+ if (!Ctx.getLangOptions().CPlusPlus) {
+ // Check that it is a cast to void*.
+ if (const PointerType *PT = CE->getType()->getAsPointerType()) {
+ QualType Pointee = PT->getPointeeType();
+ if (Pointee.getCVRQualifiers() == 0 &&
+ Pointee->isVoidType() && // to void*
+ CE->getSubExpr()->getType()->isIntegerType()) // from int.
+ return CE->getSubExpr()->isNullPointerConstant(Ctx);
+ }
+ }
+ } else if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(this)) {
+ // Ignore the ImplicitCastExpr type entirely.
+ return ICE->getSubExpr()->isNullPointerConstant(Ctx);
+ } else if (const ParenExpr *PE = dyn_cast<ParenExpr>(this)) {
+ // Accept ((void*)0) as a null pointer constant, as many other
+ // implementations do.
+ return PE->getSubExpr()->isNullPointerConstant(Ctx);
+ } else if (const CXXDefaultArgExpr *DefaultArg
+ = dyn_cast<CXXDefaultArgExpr>(this)) {
+ // See through default argument expressions
+ return DefaultArg->getExpr()->isNullPointerConstant(Ctx);
+ } else if (isa<GNUNullExpr>(this)) {
+ // The GNU __null extension is always a null pointer constant.
+ return true;
+ }
+
+ // C++0x nullptr_t is always a null pointer constant.
+ if (getType()->isNullPtrType())
+ return true;
+
+ // This expression must be an integer type.
+ if (!getType()->isIntegerType())
+ return false;
+
+ // If we have an integer constant expression, we need to *evaluate* it and
+ // test for the value 0.
+ llvm::APSInt Result;
+ return isIntegerConstantExpr(Result, Ctx) && Result == 0;
+}
+
+FieldDecl *Expr::getBitField() {
+ Expr *E = this->IgnoreParenCasts();
+
+ if (MemberExpr *MemRef = dyn_cast<MemberExpr>(E))
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(MemRef->getMemberDecl()))
+ if (Field->isBitField())
+ return Field;
+
+ if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E))
+ if (BinOp->isAssignmentOp() && BinOp->getLHS())
+ return BinOp->getLHS()->getBitField();
+
+ return 0;
+}
+
+/// isArrow - Return true if the base expression is a pointer to vector,
+/// return false if the base expression is a vector.
+bool ExtVectorElementExpr::isArrow() const {
+ return getBase()->getType()->isPointerType();
+}
+
+unsigned ExtVectorElementExpr::getNumElements() const {
+ if (const VectorType *VT = getType()->getAsVectorType())
+ return VT->getNumElements();
+ return 1;
+}
+
+/// containsDuplicateElements - Return true if any element access is repeated.
+bool ExtVectorElementExpr::containsDuplicateElements() const {
+ const char *compStr = Accessor->getName();
+ unsigned length = Accessor->getLength();
+
+ // Halving swizzles do not contain duplicate elements.
+ if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") ||
+ !strcmp(compStr, "even") || !strcmp(compStr, "odd"))
+ return false;
+
+ // Advance past s-char prefix on hex swizzles.
+ if (*compStr == 's') {
+ compStr++;
+ length--;
+ }
+
+ for (unsigned i = 0; i != length-1; i++) {
+ const char *s = compStr+i;
+ for (const char c = *s++; *s; s++)
+ if (c == *s)
+ return true;
+ }
+ return false;
+}
+
+/// getEncodedElementAccess - We encode the fields as a llvm ConstantArray.
+void ExtVectorElementExpr::getEncodedElementAccess(
+ llvm::SmallVectorImpl<unsigned> &Elts) const {
+ const char *compStr = Accessor->getName();
+ if (*compStr == 's')
+ compStr++;
+
+ bool isHi = !strcmp(compStr, "hi");
+ bool isLo = !strcmp(compStr, "lo");
+ bool isEven = !strcmp(compStr, "even");
+ bool isOdd = !strcmp(compStr, "odd");
+
+ for (unsigned i = 0, e = getNumElements(); i != e; ++i) {
+ uint64_t Index;
+
+ if (isHi)
+ Index = e + i;
+ else if (isLo)
+ Index = i;
+ else if (isEven)
+ Index = 2 * i;
+ else if (isOdd)
+ Index = 2 * i + 1;
+ else
+ Index = ExtVectorType::getAccessorIdx(compStr[i]);
+
+ Elts.push_back(Index);
+ }
+}
+
+// constructor for instance messages.
+ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo,
+ QualType retType, ObjCMethodDecl *mproto,
+ SourceLocation LBrac, SourceLocation RBrac,
+ Expr **ArgExprs, unsigned nargs)
+ : Expr(ObjCMessageExprClass, retType), SelName(selInfo),
+ MethodProto(mproto) {
+ NumArgs = nargs;
+ SubExprs = new Stmt*[NumArgs+1];
+ SubExprs[RECEIVER] = receiver;
+ if (NumArgs) {
+ for (unsigned i = 0; i != NumArgs; ++i)
+ SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]);
+ }
+ LBracloc = LBrac;
+ RBracloc = RBrac;
+}
+
+// constructor for class messages.
+// FIXME: clsName should be typed to ObjCInterfaceType
+ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo,
+ QualType retType, ObjCMethodDecl *mproto,
+ SourceLocation LBrac, SourceLocation RBrac,
+ Expr **ArgExprs, unsigned nargs)
+ : Expr(ObjCMessageExprClass, retType), SelName(selInfo),
+ MethodProto(mproto) {
+ NumArgs = nargs;
+ SubExprs = new Stmt*[NumArgs+1];
+ SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | IsClsMethDeclUnknown);
+ if (NumArgs) {
+ for (unsigned i = 0; i != NumArgs; ++i)
+ SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]);
+ }
+ LBracloc = LBrac;
+ RBracloc = RBrac;
+}
+
+// constructor for class messages.
+ObjCMessageExpr::ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo,
+ QualType retType, ObjCMethodDecl *mproto,
+ SourceLocation LBrac, SourceLocation RBrac,
+ Expr **ArgExprs, unsigned nargs)
+: Expr(ObjCMessageExprClass, retType), SelName(selInfo),
+MethodProto(mproto) {
+ NumArgs = nargs;
+ SubExprs = new Stmt*[NumArgs+1];
+ SubExprs[RECEIVER] = (Expr*) ((uintptr_t) cls | IsClsMethDeclKnown);
+ if (NumArgs) {
+ for (unsigned i = 0; i != NumArgs; ++i)
+ SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]);
+ }
+ LBracloc = LBrac;
+ RBracloc = RBrac;
+}
+
+ObjCMessageExpr::ClassInfo ObjCMessageExpr::getClassInfo() const {
+ uintptr_t x = (uintptr_t) SubExprs[RECEIVER];
+ switch (x & Flags) {
+ default:
+ assert(false && "Invalid ObjCMessageExpr.");
+ case IsInstMeth:
+ return ClassInfo(0, 0);
+ case IsClsMethDeclUnknown:
+ return ClassInfo(0, (IdentifierInfo*) (x & ~Flags));
+ case IsClsMethDeclKnown: {
+ ObjCInterfaceDecl* D = (ObjCInterfaceDecl*) (x & ~Flags);
+ return ClassInfo(D, D->getIdentifier());
+ }
+ }
+}
+
+void ObjCMessageExpr::setClassInfo(const ObjCMessageExpr::ClassInfo &CI) {
+ if (CI.first == 0 && CI.second == 0)
+ SubExprs[RECEIVER] = (Expr*)((uintptr_t)0 | IsInstMeth);
+ else if (CI.first == 0)
+ SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.second | IsClsMethDeclUnknown);
+ else
+ SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.first | IsClsMethDeclKnown);
+}
+
+
+bool ChooseExpr::isConditionTrue(ASTContext &C) const {
+ return getCond()->EvaluateAsInt(C) != 0;
+}
+
+void ShuffleVectorExpr::setExprs(Expr ** Exprs, unsigned NumExprs) {
+ if (NumExprs)
+ delete [] SubExprs;
+
+ SubExprs = new Stmt* [NumExprs];
+ this->NumExprs = NumExprs;
+ memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs);
+}
+
+void SizeOfAlignOfExpr::Destroy(ASTContext& C) {
+ // Override default behavior of traversing children. If this has a type
+ // operand and the type is a variable-length array, the child iteration
+ // will iterate over the size expression. However, this expression belongs
+ // to the type, not to this, so we don't want to delete it.
+ // We still want to delete this expression.
+ if (isArgumentType()) {
+ this->~SizeOfAlignOfExpr();
+ C.Deallocate(this);
+ }
+ else
+ Expr::Destroy(C);
+}
+
+//===----------------------------------------------------------------------===//
+// DesignatedInitExpr
+//===----------------------------------------------------------------------===//
+
+IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() {
+ assert(Kind == FieldDesignator && "Only valid on a field designator");
+ if (Field.NameOrField & 0x01)
+ return reinterpret_cast<IdentifierInfo *>(Field.NameOrField&~0x01);
+ else
+ return getField()->getIdentifier();
+}
+
+DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
+ const Designator *Designators,
+ SourceLocation EqualOrColonLoc,
+ bool GNUSyntax,
+ Expr **IndexExprs,
+ unsigned NumIndexExprs,
+ Expr *Init)
+ : Expr(DesignatedInitExprClass, Ty,
+ Init->isTypeDependent(), Init->isValueDependent()),
+ EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
+ NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) {
+ this->Designators = new Designator[NumDesignators];
+
+ // Record the initializer itself.
+ child_iterator Child = child_begin();
+ *Child++ = Init;
+
+ // Copy the designators and their subexpressions, computing
+ // value-dependence along the way.
+ unsigned IndexIdx = 0;
+ for (unsigned I = 0; I != NumDesignators; ++I) {
+ this->Designators[I] = Designators[I];
+
+ if (this->Designators[I].isArrayDesignator()) {
+ // Compute type- and value-dependence.
+ Expr *Index = IndexExprs[IndexIdx];
+ ValueDependent = ValueDependent ||
+ Index->isTypeDependent() || Index->isValueDependent();
+
+ // Copy the index expressions into permanent storage.
+ *Child++ = IndexExprs[IndexIdx++];
+ } else if (this->Designators[I].isArrayRangeDesignator()) {
+ // Compute type- and value-dependence.
+ Expr *Start = IndexExprs[IndexIdx];
+ Expr *End = IndexExprs[IndexIdx + 1];
+ ValueDependent = ValueDependent ||
+ Start->isTypeDependent() || Start->isValueDependent() ||
+ End->isTypeDependent() || End->isValueDependent();
+
+ // Copy the start/end expressions into permanent storage.
+ *Child++ = IndexExprs[IndexIdx++];
+ *Child++ = IndexExprs[IndexIdx++];
+ }
+ }
+
+ assert(IndexIdx == NumIndexExprs && "Wrong number of index expressions");
+}
+
+DesignatedInitExpr *
+DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
+ unsigned NumDesignators,
+ Expr **IndexExprs, unsigned NumIndexExprs,
+ SourceLocation ColonOrEqualLoc,
+ bool UsesColonSyntax, Expr *Init) {
+ void *Mem = C.Allocate(sizeof(DesignatedInitExpr) +
+ sizeof(Stmt *) * (NumIndexExprs + 1), 8);
+ return new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators, Designators,
+ ColonOrEqualLoc, UsesColonSyntax,
+ IndexExprs, NumIndexExprs, Init);
+}
+
+DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C,
+ unsigned NumIndexExprs) {
+ void *Mem = C.Allocate(sizeof(DesignatedInitExpr) +
+ sizeof(Stmt *) * (NumIndexExprs + 1), 8);
+ return new (Mem) DesignatedInitExpr(NumIndexExprs + 1);
+}
+
+void DesignatedInitExpr::setDesignators(const Designator *Desigs,
+ unsigned NumDesigs) {
+ if (Designators)
+ delete [] Designators;
+
+ Designators = new Designator[NumDesigs];
+ NumDesignators = NumDesigs;
+ for (unsigned I = 0; I != NumDesigs; ++I)
+ Designators[I] = Desigs[I];
+}
+
+SourceRange DesignatedInitExpr::getSourceRange() const {
+ SourceLocation StartLoc;
+ Designator &First =
+ *const_cast<DesignatedInitExpr*>(this)->designators_begin();
+ if (First.isFieldDesignator()) {
+ if (GNUSyntax)
+ StartLoc = SourceLocation::getFromRawEncoding(First.Field.FieldLoc);
+ else
+ StartLoc = SourceLocation::getFromRawEncoding(First.Field.DotLoc);
+ } else
+ StartLoc =
+ SourceLocation::getFromRawEncoding(First.ArrayOrRange.LBracketLoc);
+ return SourceRange(StartLoc, getInit()->getSourceRange().getEnd());
+}
+
+Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) {
+ assert(D.Kind == Designator::ArrayDesignator && "Requires array designator");
+ char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ Ptr += sizeof(DesignatedInitExpr);
+ Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+ return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
+}
+
+Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) {
+ assert(D.Kind == Designator::ArrayRangeDesignator &&
+ "Requires array range designator");
+ char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ Ptr += sizeof(DesignatedInitExpr);
+ Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+ return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
+}
+
+Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) {
+ assert(D.Kind == Designator::ArrayRangeDesignator &&
+ "Requires array range designator");
+ char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ Ptr += sizeof(DesignatedInitExpr);
+ Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+ return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 2));
+}
+
+/// \brief Replaces the designator at index @p Idx with the series
+/// of designators in [First, Last).
+void DesignatedInitExpr::ExpandDesignator(unsigned Idx,
+ const Designator *First,
+ const Designator *Last) {
+ unsigned NumNewDesignators = Last - First;
+ if (NumNewDesignators == 0) {
+ std::copy_backward(Designators + Idx + 1,
+ Designators + NumDesignators,
+ Designators + Idx);
+ --NumNewDesignators;
+ return;
+ } else if (NumNewDesignators == 1) {
+ Designators[Idx] = *First;
+ return;
+ }
+
+ Designator *NewDesignators
+ = new Designator[NumDesignators - 1 + NumNewDesignators];
+ std::copy(Designators, Designators + Idx, NewDesignators);
+ std::copy(First, Last, NewDesignators + Idx);
+ std::copy(Designators + Idx + 1, Designators + NumDesignators,
+ NewDesignators + Idx + NumNewDesignators);
+ delete [] Designators;
+ Designators = NewDesignators;
+ NumDesignators = NumDesignators - 1 + NumNewDesignators;
+}
+
+void DesignatedInitExpr::Destroy(ASTContext &C) {
+ delete [] Designators;
+ Expr::Destroy(C);
+}
+
+ImplicitValueInitExpr *ImplicitValueInitExpr::Clone(ASTContext &C) const {
+ return new (C) ImplicitValueInitExpr(getType());
+}
+
+//===----------------------------------------------------------------------===//
+// ExprIterator.
+//===----------------------------------------------------------------------===//
+
+Expr* ExprIterator::operator[](size_t idx) { return cast<Expr>(I[idx]); }
+Expr* ExprIterator::operator*() const { return cast<Expr>(*I); }
+Expr* ExprIterator::operator->() const { return cast<Expr>(*I); }
+const Expr* ConstExprIterator::operator[](size_t idx) const {
+ return cast<Expr>(I[idx]);
+}
+const Expr* ConstExprIterator::operator*() const { return cast<Expr>(*I); }
+const Expr* ConstExprIterator::operator->() const { return cast<Expr>(*I); }
+
+//===----------------------------------------------------------------------===//
+// Child Iterators for iterating over subexpressions/substatements
+//===----------------------------------------------------------------------===//
+
+// DeclRefExpr
+Stmt::child_iterator DeclRefExpr::child_begin() { return child_iterator(); }
+Stmt::child_iterator DeclRefExpr::child_end() { return child_iterator(); }
+
+// ObjCIvarRefExpr
+Stmt::child_iterator ObjCIvarRefExpr::child_begin() { return &Base; }
+Stmt::child_iterator ObjCIvarRefExpr::child_end() { return &Base+1; }
+
+// ObjCPropertyRefExpr
+Stmt::child_iterator ObjCPropertyRefExpr::child_begin() { return &Base; }
+Stmt::child_iterator ObjCPropertyRefExpr::child_end() { return &Base+1; }
+
+// ObjCKVCRefExpr
+Stmt::child_iterator ObjCKVCRefExpr::child_begin() { return &Base; }
+Stmt::child_iterator ObjCKVCRefExpr::child_end() { return &Base+1; }
+
+// ObjCSuperExpr
+Stmt::child_iterator ObjCSuperExpr::child_begin() { return child_iterator(); }
+Stmt::child_iterator ObjCSuperExpr::child_end() { return child_iterator(); }
+
+// PredefinedExpr
+Stmt::child_iterator PredefinedExpr::child_begin() { return child_iterator(); }
+Stmt::child_iterator PredefinedExpr::child_end() { return child_iterator(); }
+
+// IntegerLiteral
+Stmt::child_iterator IntegerLiteral::child_begin() { return child_iterator(); }
+Stmt::child_iterator IntegerLiteral::child_end() { return child_iterator(); }
+
+// CharacterLiteral
+Stmt::child_iterator CharacterLiteral::child_begin() { return child_iterator();}
+Stmt::child_iterator CharacterLiteral::child_end() { return child_iterator(); }
+
+// FloatingLiteral
+Stmt::child_iterator FloatingLiteral::child_begin() { return child_iterator(); }
+Stmt::child_iterator FloatingLiteral::child_end() { return child_iterator(); }
+
+// ImaginaryLiteral
+Stmt::child_iterator ImaginaryLiteral::child_begin() { return &Val; }
+Stmt::child_iterator ImaginaryLiteral::child_end() { return &Val+1; }
+
+// StringLiteral
+Stmt::child_iterator StringLiteral::child_begin() { return child_iterator(); }
+Stmt::child_iterator StringLiteral::child_end() { return child_iterator(); }
+
+// ParenExpr
+Stmt::child_iterator ParenExpr::child_begin() { return &Val; }
+Stmt::child_iterator ParenExpr::child_end() { return &Val+1; }
+
+// UnaryOperator
+Stmt::child_iterator UnaryOperator::child_begin() { return &Val; }
+Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; }
+
+// SizeOfAlignOfExpr
+Stmt::child_iterator SizeOfAlignOfExpr::child_begin() {
+ // If this is of a type and the type is a VLA type (and not a typedef), the
+ // size expression of the VLA needs to be treated as an executable expression.
+ // Why isn't this weirdness documented better in StmtIterator?
+ if (isArgumentType()) {
+ if (VariableArrayType* T = dyn_cast<VariableArrayType>(
+ getArgumentType().getTypePtr()))
+ return child_iterator(T);
+ return child_iterator();
+ }
+ return child_iterator(&Argument.Ex);
+}
+Stmt::child_iterator SizeOfAlignOfExpr::child_end() {
+ if (isArgumentType())
+ return child_iterator();
+ return child_iterator(&Argument.Ex + 1);
+}
+
+// ArraySubscriptExpr
+Stmt::child_iterator ArraySubscriptExpr::child_begin() {
+ return &SubExprs[0];
+}
+Stmt::child_iterator ArraySubscriptExpr::child_end() {
+ return &SubExprs[0]+END_EXPR;
+}
+
+// CallExpr
+Stmt::child_iterator CallExpr::child_begin() {
+ return &SubExprs[0];
+}
+Stmt::child_iterator CallExpr::child_end() {
+ return &SubExprs[0]+NumArgs+ARGS_START;
+}
+
+// MemberExpr
+Stmt::child_iterator MemberExpr::child_begin() { return &Base; }
+Stmt::child_iterator MemberExpr::child_end() { return &Base+1; }
+
+// ExtVectorElementExpr
+Stmt::child_iterator ExtVectorElementExpr::child_begin() { return &Base; }
+Stmt::child_iterator ExtVectorElementExpr::child_end() { return &Base+1; }
+
+// CompoundLiteralExpr
+Stmt::child_iterator CompoundLiteralExpr::child_begin() { return &Init; }
+Stmt::child_iterator CompoundLiteralExpr::child_end() { return &Init+1; }
+
+// CastExpr
+Stmt::child_iterator CastExpr::child_begin() { return &Op; }
+Stmt::child_iterator CastExpr::child_end() { return &Op+1; }
+
+// BinaryOperator
+Stmt::child_iterator BinaryOperator::child_begin() {
+ return &SubExprs[0];
+}
+Stmt::child_iterator BinaryOperator::child_end() {
+ return &SubExprs[0]+END_EXPR;
+}
+
+// ConditionalOperator
+Stmt::child_iterator ConditionalOperator::child_begin() {
+ return &SubExprs[0];
+}
+Stmt::child_iterator ConditionalOperator::child_end() {
+ return &SubExprs[0]+END_EXPR;
+}
+
+// AddrLabelExpr
+Stmt::child_iterator AddrLabelExpr::child_begin() { return child_iterator(); }
+Stmt::child_iterator AddrLabelExpr::child_end() { return child_iterator(); }
+
+// StmtExpr
+Stmt::child_iterator StmtExpr::child_begin() { return &SubStmt; }
+Stmt::child_iterator StmtExpr::child_end() { return &SubStmt+1; }
+
+// TypesCompatibleExpr
+Stmt::child_iterator TypesCompatibleExpr::child_begin() {
+ return child_iterator();
+}
+
+Stmt::child_iterator TypesCompatibleExpr::child_end() {
+ return child_iterator();
+}
+
+// ChooseExpr
+Stmt::child_iterator ChooseExpr::child_begin() { return &SubExprs[0]; }
+Stmt::child_iterator ChooseExpr::child_end() { return &SubExprs[0]+END_EXPR; }
+
+// GNUNullExpr
+Stmt::child_iterator GNUNullExpr::child_begin() { return child_iterator(); }
+Stmt::child_iterator GNUNullExpr::child_end() { return child_iterator(); }
+
+// ShuffleVectorExpr
+Stmt::child_iterator ShuffleVectorExpr::child_begin() {
+ return &SubExprs[0];
+}
+Stmt::child_iterator ShuffleVectorExpr::child_end() {
+ return &SubExprs[0]+NumExprs;
+}
+
+// VAArgExpr
+Stmt::child_iterator VAArgExpr::child_begin() { return &Val; }
+Stmt::child_iterator VAArgExpr::child_end() { return &Val+1; }
+
+// InitListExpr
+Stmt::child_iterator InitListExpr::child_begin() {
+ return InitExprs.size() ? &InitExprs[0] : 0;
+}
+Stmt::child_iterator InitListExpr::child_end() {
+ return InitExprs.size() ? &InitExprs[0] + InitExprs.size() : 0;
+}
+
+// DesignatedInitExpr
+Stmt::child_iterator DesignatedInitExpr::child_begin() {
+ char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ Ptr += sizeof(DesignatedInitExpr);
+ return reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+}
+Stmt::child_iterator DesignatedInitExpr::child_end() {
+ return child_iterator(&*child_begin() + NumSubExprs);
+}
+
+// ImplicitValueInitExpr
+Stmt::child_iterator ImplicitValueInitExpr::child_begin() {
+ return child_iterator();
+}
+
+Stmt::child_iterator ImplicitValueInitExpr::child_end() {
+ return child_iterator();
+}
+
+// ObjCStringLiteral
+Stmt::child_iterator ObjCStringLiteral::child_begin() {
+ return &String;
+}
+Stmt::child_iterator ObjCStringLiteral::child_end() {
+ return &String+1;
+}
+
+// ObjCEncodeExpr
+Stmt::child_iterator ObjCEncodeExpr::child_begin() { return child_iterator(); }
+Stmt::child_iterator ObjCEncodeExpr::child_end() { return child_iterator(); }
+
+// ObjCSelectorExpr
+Stmt::child_iterator ObjCSelectorExpr::child_begin() {
+ return child_iterator();
+}
+Stmt::child_iterator ObjCSelectorExpr::child_end() {
+ return child_iterator();
+}
+
+// ObjCProtocolExpr
+Stmt::child_iterator ObjCProtocolExpr::child_begin() {
+ return child_iterator();
+}
+Stmt::child_iterator ObjCProtocolExpr::child_end() {
+ return child_iterator();
+}
+
+// ObjCMessageExpr
+Stmt::child_iterator ObjCMessageExpr::child_begin() {
+ return getReceiver() ? &SubExprs[0] : &SubExprs[0] + ARGS_START;
+}
+Stmt::child_iterator ObjCMessageExpr::child_end() {
+ return &SubExprs[0]+ARGS_START+getNumArgs();
+}
+
+// Blocks
+Stmt::child_iterator BlockExpr::child_begin() { return child_iterator(); }
+Stmt::child_iterator BlockExpr::child_end() { return child_iterator(); }
+
+Stmt::child_iterator BlockDeclRefExpr::child_begin() { return child_iterator();}
+Stmt::child_iterator BlockDeclRefExpr::child_end() { return child_iterator(); }
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
new file mode 100644
index 000000000000..4a15245591e3
--- /dev/null
+++ b/lib/AST/ExprCXX.cpp
@@ -0,0 +1,424 @@
+//===--- ExprCXX.cpp - (C++) Expression AST Node Implementation -----------===//
+//
+// 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 subclesses of Expr class declared in ExprCXX.h
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+using namespace clang;
+
+void CXXConditionDeclExpr::Destroy(ASTContext& C) {
+ // FIXME: Cannot destroy the decl here, because it is linked into the
+ // DeclContext's chain.
+ //getVarDecl()->Destroy(C);
+ this->~CXXConditionDeclExpr();
+ C.Deallocate(this);
+}
+
+//===----------------------------------------------------------------------===//
+// Child Iterators for iterating over subexpressions/substatements
+//===----------------------------------------------------------------------===//
+
+// CXXTypeidExpr - has child iterators if the operand is an expression
+Stmt::child_iterator CXXTypeidExpr::child_begin() {
+ return isTypeOperand() ? child_iterator() : &Operand.Ex;
+}
+Stmt::child_iterator CXXTypeidExpr::child_end() {
+ return isTypeOperand() ? child_iterator() : &Operand.Ex+1;
+}
+
+// CXXBoolLiteralExpr
+Stmt::child_iterator CXXBoolLiteralExpr::child_begin() {
+ return child_iterator();
+}
+Stmt::child_iterator CXXBoolLiteralExpr::child_end() {
+ return child_iterator();
+}
+
+// CXXNullPtrLiteralExpr
+Stmt::child_iterator CXXNullPtrLiteralExpr::child_begin() {
+ return child_iterator();
+}
+Stmt::child_iterator CXXNullPtrLiteralExpr::child_end() {
+ return child_iterator();
+}
+
+// CXXThisExpr
+Stmt::child_iterator CXXThisExpr::child_begin() { return child_iterator(); }
+Stmt::child_iterator CXXThisExpr::child_end() { return child_iterator(); }
+
+// CXXThrowExpr
+Stmt::child_iterator CXXThrowExpr::child_begin() { return &Op; }
+Stmt::child_iterator CXXThrowExpr::child_end() {
+ // If Op is 0, we are processing throw; which has no children.
+ return Op ? &Op+1 : &Op;
+}
+
+// CXXDefaultArgExpr
+Stmt::child_iterator CXXDefaultArgExpr::child_begin() {
+ return child_iterator();
+}
+Stmt::child_iterator CXXDefaultArgExpr::child_end() {
+ return child_iterator();
+}
+
+// CXXZeroInitValueExpr
+Stmt::child_iterator CXXZeroInitValueExpr::child_begin() {
+ return child_iterator();
+}
+Stmt::child_iterator CXXZeroInitValueExpr::child_end() {
+ return child_iterator();
+}
+
+// CXXConditionDeclExpr
+Stmt::child_iterator CXXConditionDeclExpr::child_begin() {
+ return getVarDecl();
+}
+Stmt::child_iterator CXXConditionDeclExpr::child_end() {
+ return child_iterator();
+}
+
+// CXXNewExpr
+CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew,
+ Expr **placementArgs, unsigned numPlaceArgs,
+ bool parenTypeId, Expr *arraySize,
+ CXXConstructorDecl *constructor, bool initializer,
+ Expr **constructorArgs, unsigned numConsArgs,
+ FunctionDecl *operatorDelete, QualType ty,
+ SourceLocation startLoc, SourceLocation endLoc)
+ : Expr(CXXNewExprClass, ty, ty->isDependentType(), ty->isDependentType()),
+ GlobalNew(globalNew), ParenTypeId(parenTypeId),
+ Initializer(initializer), Array(arraySize), NumPlacementArgs(numPlaceArgs),
+ NumConstructorArgs(numConsArgs), OperatorNew(operatorNew),
+ OperatorDelete(operatorDelete), Constructor(constructor),
+ StartLoc(startLoc), EndLoc(endLoc)
+{
+ unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs;
+ SubExprs = new Stmt*[TotalSize];
+ unsigned i = 0;
+ if (Array)
+ SubExprs[i++] = arraySize;
+ for (unsigned j = 0; j < NumPlacementArgs; ++j)
+ SubExprs[i++] = placementArgs[j];
+ for (unsigned j = 0; j < NumConstructorArgs; ++j)
+ SubExprs[i++] = constructorArgs[j];
+ assert(i == TotalSize);
+}
+
+Stmt::child_iterator CXXNewExpr::child_begin() { return &SubExprs[0]; }
+Stmt::child_iterator CXXNewExpr::child_end() {
+ return &SubExprs[0] + Array + getNumPlacementArgs() + getNumConstructorArgs();
+}
+
+// CXXDeleteExpr
+Stmt::child_iterator CXXDeleteExpr::child_begin() { return &Argument; }
+Stmt::child_iterator CXXDeleteExpr::child_end() { return &Argument+1; }
+
+// UnresolvedFunctionNameExpr
+Stmt::child_iterator UnresolvedFunctionNameExpr::child_begin() {
+ return child_iterator();
+}
+Stmt::child_iterator UnresolvedFunctionNameExpr::child_end() {
+ return child_iterator();
+}
+
+UnresolvedFunctionNameExpr*
+UnresolvedFunctionNameExpr::Clone(ASTContext &C) const {
+ return new (C) UnresolvedFunctionNameExpr(Name, getType(), Loc);
+}
+
+// UnaryTypeTraitExpr
+Stmt::child_iterator UnaryTypeTraitExpr::child_begin() {
+ return child_iterator();
+}
+Stmt::child_iterator UnaryTypeTraitExpr::child_end() {
+ return child_iterator();
+}
+
+// UnresolvedDeclRefExpr
+StmtIterator UnresolvedDeclRefExpr::child_begin() {
+ return child_iterator();
+}
+
+StmtIterator UnresolvedDeclRefExpr::child_end() {
+ return child_iterator();
+}
+
+bool UnaryTypeTraitExpr::EvaluateTrait() const {
+ switch(UTT) {
+ default: assert(false && "Unknown type trait or not implemented");
+ case UTT_IsPOD: return QueriedType->isPODType();
+ case UTT_IsClass: // Fallthrough
+ case UTT_IsUnion:
+ if (const RecordType *Record = QueriedType->getAsRecordType()) {
+ bool Union = Record->getDecl()->isUnion();
+ return UTT == UTT_IsUnion ? Union : !Union;
+ }
+ return false;
+ case UTT_IsEnum: return QueriedType->isEnumeralType();
+ case UTT_IsPolymorphic:
+ if (const RecordType *Record = QueriedType->getAsRecordType()) {
+ // Type traits are only parsed in C++, so we've got CXXRecords.
+ return cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic();
+ }
+ return false;
+ case UTT_IsAbstract:
+ if (const RecordType *RT = QueriedType->getAsRecordType())
+ return cast<CXXRecordDecl>(RT->getDecl())->isAbstract();
+ return false;
+ case UTT_HasTrivialConstructor:
+ if (const RecordType *RT = QueriedType->getAsRecordType())
+ return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor();
+ return false;
+ case UTT_HasTrivialDestructor:
+ if (const RecordType *RT = QueriedType->getAsRecordType())
+ return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor();
+ return false;
+ }
+}
+
+SourceRange CXXOperatorCallExpr::getSourceRange() const {
+ OverloadedOperatorKind Kind = getOperator();
+ if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) {
+ if (getNumArgs() == 1)
+ // Prefix operator
+ return SourceRange(getOperatorLoc(),
+ getArg(0)->getSourceRange().getEnd());
+ else
+ // Postfix operator
+ return SourceRange(getArg(0)->getSourceRange().getEnd(),
+ getOperatorLoc());
+ } else if (Kind == OO_Call) {
+ return SourceRange(getArg(0)->getSourceRange().getBegin(), getRParenLoc());
+ } else if (Kind == OO_Subscript) {
+ return SourceRange(getArg(0)->getSourceRange().getBegin(), getRParenLoc());
+ } else if (getNumArgs() == 1) {
+ return SourceRange(getOperatorLoc(), getArg(0)->getSourceRange().getEnd());
+ } else if (getNumArgs() == 2) {
+ return SourceRange(getArg(0)->getSourceRange().getBegin(),
+ getArg(1)->getSourceRange().getEnd());
+ } else {
+ return SourceRange();
+ }
+}
+
+Expr *CXXMemberCallExpr::getImplicitObjectArgument() {
+ if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(getCallee()->IgnoreParens()))
+ return MemExpr->getBase();
+
+ // FIXME: Will eventually need to cope with member pointers.
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// Named casts
+//===----------------------------------------------------------------------===//
+
+/// getCastName - Get the name of the C++ cast being used, e.g.,
+/// "static_cast", "dynamic_cast", "reinterpret_cast", or
+/// "const_cast". The returned pointer must not be freed.
+const char *CXXNamedCastExpr::getCastName() const {
+ switch (getStmtClass()) {
+ case CXXStaticCastExprClass: return "static_cast";
+ case CXXDynamicCastExprClass: return "dynamic_cast";
+ case CXXReinterpretCastExprClass: return "reinterpret_cast";
+ case CXXConstCastExprClass: return "const_cast";
+ default: return "<invalid cast>";
+ }
+}
+
+CXXTemporary *CXXTemporary::Create(ASTContext &C,
+ const CXXDestructorDecl *Destructor) {
+ return new (C) CXXTemporary(Destructor);
+}
+
+void CXXTemporary::Destroy(ASTContext &C) {
+ this->~CXXTemporary();
+ C.Deallocate(this);
+}
+
+CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C,
+ CXXTemporary *Temp,
+ Expr* SubExpr) {
+ assert(SubExpr->getType()->isRecordType() &&
+ "Expression bound to a temporary must have record type!");
+
+ return new (C) CXXBindTemporaryExpr(Temp, SubExpr);
+}
+
+void CXXBindTemporaryExpr::Destroy(ASTContext &C) {
+ Temp->Destroy(C);
+ this->~CXXBindTemporaryExpr();
+ C.Deallocate(this);
+}
+
+CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
+ CXXConstructorDecl *Cons,
+ QualType writtenTy,
+ SourceLocation tyBeginLoc,
+ Expr **Args,
+ unsigned NumArgs,
+ SourceLocation rParenLoc)
+ : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, Cons,
+ false, Args, NumArgs),
+ TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {
+}
+
+CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
+ CXXConstructorDecl *D, bool Elidable,
+ Expr **Args, unsigned NumArgs) {
+ return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, D, Elidable,
+ Args, NumArgs);
+}
+
+CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
+ CXXConstructorDecl *D, bool elidable,
+ Expr **args, unsigned numargs)
+: Expr(SC, T,
+ T->isDependentType(),
+ (T->isDependentType() ||
+ CallExpr::hasAnyValueDependentArguments(args, numargs))),
+ Constructor(D), Elidable(elidable), Args(0), NumArgs(numargs) {
+ if (NumArgs > 0) {
+ Args = new (C) Stmt*[NumArgs];
+ for (unsigned i = 0; i < NumArgs; ++i)
+ Args[i] = args[i];
+ }
+}
+
+void CXXConstructExpr::Destroy(ASTContext &C) {
+ DestroyChildren(C);
+ if (Args)
+ C.Deallocate(Args);
+ this->~CXXConstructExpr();
+ C.Deallocate(this);
+}
+
+CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr,
+ CXXTemporary **temps,
+ unsigned numtemps)
+: Expr(CXXExprWithTemporariesClass, subexpr->getType(),
+ subexpr->isTypeDependent(), subexpr->isValueDependent()),
+ SubExpr(subexpr), Temps(0), NumTemps(numtemps) {
+ if (NumTemps > 0) {
+ Temps = new CXXTemporary*[NumTemps];
+ for (unsigned i = 0; i < NumTemps; ++i)
+ Temps[i] = temps[i];
+ }
+}
+
+CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C,
+ Expr *SubExpr,
+ CXXTemporary **Temps,
+ unsigned NumTemps) {
+ return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps);
+}
+
+void CXXExprWithTemporaries::Destroy(ASTContext &C) {
+ DestroyChildren(C);
+ this->~CXXExprWithTemporaries();
+ C.Deallocate(this);
+}
+
+CXXExprWithTemporaries::~CXXExprWithTemporaries() {
+ delete[] Temps;
+}
+
+// CXXBindTemporaryExpr
+Stmt::child_iterator CXXBindTemporaryExpr::child_begin() {
+ return &SubExpr;
+}
+
+Stmt::child_iterator CXXBindTemporaryExpr::child_end() {
+ return &SubExpr + 1;
+}
+
+// CXXConstructExpr
+Stmt::child_iterator CXXConstructExpr::child_begin() {
+ return &Args[0];
+}
+Stmt::child_iterator CXXConstructExpr::child_end() {
+ return &Args[0]+NumArgs;
+}
+
+// CXXExprWithTemporaries
+Stmt::child_iterator CXXExprWithTemporaries::child_begin() {
+ return &SubExpr;
+}
+
+Stmt::child_iterator CXXExprWithTemporaries::child_end() {
+ return &SubExpr + 1;
+}
+
+CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(
+ SourceLocation TyBeginLoc,
+ QualType T,
+ SourceLocation LParenLoc,
+ Expr **Args,
+ unsigned NumArgs,
+ SourceLocation RParenLoc)
+ : Expr(CXXUnresolvedConstructExprClass, T.getNonReferenceType(),
+ T->isDependentType(), true),
+ TyBeginLoc(TyBeginLoc),
+ Type(T),
+ LParenLoc(LParenLoc),
+ RParenLoc(RParenLoc),
+ NumArgs(NumArgs) {
+ Stmt **StoredArgs = reinterpret_cast<Stmt **>(this + 1);
+ memcpy(StoredArgs, Args, sizeof(Expr *) * NumArgs);
+}
+
+CXXUnresolvedConstructExpr *
+CXXUnresolvedConstructExpr::Create(ASTContext &C,
+ SourceLocation TyBegin,
+ QualType T,
+ SourceLocation LParenLoc,
+ Expr **Args,
+ unsigned NumArgs,
+ SourceLocation RParenLoc) {
+ void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) +
+ sizeof(Expr *) * NumArgs);
+ return new (Mem) CXXUnresolvedConstructExpr(TyBegin, T, LParenLoc,
+ Args, NumArgs, RParenLoc);
+}
+
+Stmt::child_iterator CXXUnresolvedConstructExpr::child_begin() {
+ return child_iterator(reinterpret_cast<Stmt **>(this + 1));
+}
+
+Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() {
+ return child_iterator(reinterpret_cast<Stmt **>(this + 1) + NumArgs);
+}
+
+Stmt::child_iterator CXXUnresolvedMemberExpr::child_begin() {
+ return child_iterator(&Base);
+}
+
+Stmt::child_iterator CXXUnresolvedMemberExpr::child_end() {
+ return child_iterator(&Base + 1);
+}
+
+//===----------------------------------------------------------------------===//
+// Cloners
+//===----------------------------------------------------------------------===//
+
+CXXBoolLiteralExpr* CXXBoolLiteralExpr::Clone(ASTContext &C) const {
+ return new (C) CXXBoolLiteralExpr(Value, getType(), Loc);
+}
+
+CXXNullPtrLiteralExpr* CXXNullPtrLiteralExpr::Clone(ASTContext &C) const {
+ return new (C) CXXNullPtrLiteralExpr(getType(), Loc);
+}
+
+CXXZeroInitValueExpr* CXXZeroInitValueExpr::Clone(ASTContext &C) const {
+ return new (C) CXXZeroInitValueExpr(getType(), TyBeginLoc, RParenLoc);
+}
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
new file mode 100644
index 000000000000..50fdcfd6eb2b
--- /dev/null
+++ b/lib/AST/ExprConstant.cpp
@@ -0,0 +1,1723 @@
+//===--- ExprConstant.cpp - Expression Constant Evaluator -----------------===//
+//
+// 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 Expr constant evaluator.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/APValue.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Compiler.h"
+#include <cstring>
+
+using namespace clang;
+using llvm::APSInt;
+using llvm::APFloat;
+
+/// EvalInfo - This is a private struct used by the evaluator to capture
+/// information about a subexpression as it is folded. It retains information
+/// about the AST context, but also maintains information about the folded
+/// expression.
+///
+/// If an expression could be evaluated, it is still possible it is not a C
+/// "integer constant expression" or constant expression. If not, this struct
+/// captures information about how and why not.
+///
+/// One bit of information passed *into* the request for constant folding
+/// indicates whether the subexpression is "evaluated" or not according to C
+/// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
+/// evaluate the expression regardless of what the RHS is, but C only allows
+/// certain things in certain situations.
+struct EvalInfo {
+ ASTContext &Ctx;
+
+ /// EvalResult - Contains information about the evaluation.
+ Expr::EvalResult &EvalResult;
+
+ EvalInfo(ASTContext &ctx, Expr::EvalResult& evalresult) : Ctx(ctx),
+ EvalResult(evalresult) {}
+};
+
+
+static bool EvaluateLValue(const Expr *E, APValue &Result, EvalInfo &Info);
+static bool EvaluatePointer(const Expr *E, APValue &Result, EvalInfo &Info);
+static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info);
+static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result, EvalInfo &Info);
+static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
+static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info);
+
+//===----------------------------------------------------------------------===//
+// Misc utilities
+//===----------------------------------------------------------------------===//
+
+static bool HandleConversionToBool(Expr* E, bool& Result, EvalInfo &Info) {
+ if (E->getType()->isIntegralType()) {
+ APSInt IntResult;
+ if (!EvaluateInteger(E, IntResult, Info))
+ return false;
+ Result = IntResult != 0;
+ return true;
+ } else if (E->getType()->isRealFloatingType()) {
+ APFloat FloatResult(0.0);
+ if (!EvaluateFloat(E, FloatResult, Info))
+ return false;
+ Result = !FloatResult.isZero();
+ return true;
+ } else if (E->getType()->hasPointerRepresentation()) {
+ APValue PointerResult;
+ if (!EvaluatePointer(E, PointerResult, Info))
+ return false;
+ // FIXME: Is this accurate for all kinds of bases? If not, what would
+ // the check look like?
+ Result = PointerResult.getLValueBase() || PointerResult.getLValueOffset();
+ return true;
+ } else if (E->getType()->isAnyComplexType()) {
+ APValue ComplexResult;
+ if (!EvaluateComplex(E, ComplexResult, Info))
+ return false;
+ if (ComplexResult.isComplexFloat()) {
+ Result = !ComplexResult.getComplexFloatReal().isZero() ||
+ !ComplexResult.getComplexFloatImag().isZero();
+ } else {
+ Result = ComplexResult.getComplexIntReal().getBoolValue() ||
+ ComplexResult.getComplexIntImag().getBoolValue();
+ }
+ return true;
+ }
+
+ return false;
+}
+
+static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType,
+ APFloat &Value, ASTContext &Ctx) {
+ unsigned DestWidth = Ctx.getIntWidth(DestType);
+ // Determine whether we are converting to unsigned or signed.
+ bool DestSigned = DestType->isSignedIntegerType();
+
+ // FIXME: Warning for overflow.
+ uint64_t Space[4];
+ bool ignored;
+ (void)Value.convertToInteger(Space, DestWidth, DestSigned,
+ llvm::APFloat::rmTowardZero, &ignored);
+ return APSInt(llvm::APInt(DestWidth, 4, Space), !DestSigned);
+}
+
+static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType,
+ APFloat &Value, ASTContext &Ctx) {
+ bool ignored;
+ APFloat Result = Value;
+ Result.convert(Ctx.getFloatTypeSemantics(DestType),
+ APFloat::rmNearestTiesToEven, &ignored);
+ return Result;
+}
+
+static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType,
+ APSInt &Value, ASTContext &Ctx) {
+ unsigned DestWidth = Ctx.getIntWidth(DestType);
+ APSInt Result = Value;
+ // Figure out if this is a truncate, extend or noop cast.
+ // If the input is signed, do a sign extend, noop, or truncate.
+ Result.extOrTrunc(DestWidth);
+ Result.setIsUnsigned(DestType->isUnsignedIntegerType());
+ return Result;
+}
+
+static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType,
+ APSInt &Value, ASTContext &Ctx) {
+
+ APFloat Result(Ctx.getFloatTypeSemantics(DestType), 1);
+ Result.convertFromAPInt(Value, Value.isSigned(),
+ APFloat::rmNearestTiesToEven);
+ return Result;
+}
+
+//===----------------------------------------------------------------------===//
+// LValue Evaluation
+//===----------------------------------------------------------------------===//
+namespace {
+class VISIBILITY_HIDDEN LValueExprEvaluator
+ : public StmtVisitor<LValueExprEvaluator, APValue> {
+ EvalInfo &Info;
+public:
+
+ LValueExprEvaluator(EvalInfo &info) : Info(info) {}
+
+ APValue VisitStmt(Stmt *S) {
+ return APValue();
+ }
+
+ APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ APValue VisitDeclRefExpr(DeclRefExpr *E);
+ APValue VisitBlockExpr(BlockExpr *E);
+ APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E, 0); }
+ APValue VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
+ APValue VisitMemberExpr(MemberExpr *E);
+ APValue VisitStringLiteral(StringLiteral *E) { return APValue(E, 0); }
+ APValue VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return APValue(E, 0); }
+ APValue VisitArraySubscriptExpr(ArraySubscriptExpr *E);
+ APValue VisitUnaryDeref(UnaryOperator *E);
+ APValue VisitUnaryExtension(const UnaryOperator *E)
+ { return Visit(E->getSubExpr()); }
+ APValue VisitChooseExpr(const ChooseExpr *E)
+ { return Visit(E->getChosenSubExpr(Info.Ctx)); }
+ // FIXME: Missing: __real__, __imag__
+};
+} // end anonymous namespace
+
+static bool EvaluateLValue(const Expr* E, APValue& Result, EvalInfo &Info) {
+ Result = LValueExprEvaluator(Info).Visit(const_cast<Expr*>(E));
+ return Result.isLValue();
+}
+
+APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E)
+{
+ if (!E->hasGlobalStorage())
+ return APValue();
+
+ if (isa<FunctionDecl>(E->getDecl())) {
+ return APValue(E, 0);
+ } else if (VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) {
+ if (!VD->getType()->isReferenceType())
+ return APValue(E, 0);
+ if (VD->getInit())
+ return Visit(VD->getInit());
+ }
+
+ return APValue();
+}
+
+APValue LValueExprEvaluator::VisitBlockExpr(BlockExpr *E)
+{
+ if (E->hasBlockDeclRefExprs())
+ return APValue();
+
+ return APValue(E, 0);
+}
+
+APValue LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ if (E->isFileScope())
+ return APValue(E, 0);
+ return APValue();
+}
+
+APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
+ APValue result;
+ QualType Ty;
+ if (E->isArrow()) {
+ if (!EvaluatePointer(E->getBase(), result, Info))
+ return APValue();
+ Ty = E->getBase()->getType()->getAsPointerType()->getPointeeType();
+ } else {
+ result = Visit(E->getBase());
+ if (result.isUninit())
+ return APValue();
+ Ty = E->getBase()->getType();
+ }
+
+ RecordDecl *RD = Ty->getAsRecordType()->getDecl();
+ const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
+
+ FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
+ if (!FD) // FIXME: deal with other kinds of member expressions
+ return APValue();
+
+ if (FD->getType()->isReferenceType())
+ return APValue();
+
+ // FIXME: This is linear time.
+ unsigned i = 0;
+ for (RecordDecl::field_iterator Field = RD->field_begin(Info.Ctx),
+ FieldEnd = RD->field_end(Info.Ctx);
+ Field != FieldEnd; (void)++Field, ++i) {
+ if (*Field == FD)
+ break;
+ }
+
+ result.setLValue(result.getLValueBase(),
+ result.getLValueOffset() + RL.getFieldOffset(i) / 8);
+
+ return result;
+}
+
+APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E)
+{
+ APValue Result;
+
+ if (!EvaluatePointer(E->getBase(), Result, Info))
+ return APValue();
+
+ APSInt Index;
+ if (!EvaluateInteger(E->getIdx(), Index, Info))
+ return APValue();
+
+ uint64_t ElementSize = Info.Ctx.getTypeSize(E->getType()) / 8;
+
+ uint64_t Offset = Index.getSExtValue() * ElementSize;
+ Result.setLValue(Result.getLValueBase(),
+ Result.getLValueOffset() + Offset);
+ return Result;
+}
+
+APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E)
+{
+ APValue Result;
+ if (!EvaluatePointer(E->getSubExpr(), Result, Info))
+ return APValue();
+ return Result;
+}
+
+//===----------------------------------------------------------------------===//
+// Pointer Evaluation
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN PointerExprEvaluator
+ : public StmtVisitor<PointerExprEvaluator, APValue> {
+ EvalInfo &Info;
+public:
+
+ PointerExprEvaluator(EvalInfo &info) : Info(info) {}
+
+ APValue VisitStmt(Stmt *S) {
+ return APValue();
+ }
+
+ APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+
+ APValue VisitBinaryOperator(const BinaryOperator *E);
+ APValue VisitCastExpr(const CastExpr* E);
+ APValue VisitUnaryExtension(const UnaryOperator *E)
+ { return Visit(E->getSubExpr()); }
+ APValue VisitUnaryAddrOf(const UnaryOperator *E);
+ APValue VisitObjCStringLiteral(ObjCStringLiteral *E)
+ { return APValue(E, 0); }
+ APValue VisitAddrLabelExpr(AddrLabelExpr *E)
+ { return APValue(E, 0); }
+ APValue VisitCallExpr(CallExpr *E);
+ APValue VisitBlockExpr(BlockExpr *E) {
+ if (!E->hasBlockDeclRefExprs())
+ return APValue(E, 0);
+ return APValue();
+ }
+ APValue VisitImplicitValueInitExpr(ImplicitValueInitExpr *E)
+ { return APValue((Expr*)0, 0); }
+ APValue VisitConditionalOperator(ConditionalOperator *E);
+ APValue VisitChooseExpr(ChooseExpr *E)
+ { return Visit(E->getChosenSubExpr(Info.Ctx)); }
+ APValue VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E)
+ { return APValue((Expr*)0, 0); }
+ // FIXME: Missing: @protocol, @selector
+};
+} // end anonymous namespace
+
+static bool EvaluatePointer(const Expr* E, APValue& Result, EvalInfo &Info) {
+ if (!E->getType()->hasPointerRepresentation())
+ return false;
+ Result = PointerExprEvaluator(Info).Visit(const_cast<Expr*>(E));
+ return Result.isLValue();
+}
+
+APValue PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
+ if (E->getOpcode() != BinaryOperator::Add &&
+ E->getOpcode() != BinaryOperator::Sub)
+ return APValue();
+
+ const Expr *PExp = E->getLHS();
+ const Expr *IExp = E->getRHS();
+ if (IExp->getType()->isPointerType())
+ std::swap(PExp, IExp);
+
+ APValue ResultLValue;
+ if (!EvaluatePointer(PExp, ResultLValue, Info))
+ return APValue();
+
+ llvm::APSInt AdditionalOffset(32);
+ if (!EvaluateInteger(IExp, AdditionalOffset, Info))
+ return APValue();
+
+ QualType PointeeType = PExp->getType()->getAsPointerType()->getPointeeType();
+ uint64_t SizeOfPointee;
+
+ // Explicitly handle GNU void* and function pointer arithmetic extensions.
+ if (PointeeType->isVoidType() || PointeeType->isFunctionType())
+ SizeOfPointee = 1;
+ else
+ SizeOfPointee = Info.Ctx.getTypeSize(PointeeType) / 8;
+
+ uint64_t Offset = ResultLValue.getLValueOffset();
+
+ if (E->getOpcode() == BinaryOperator::Add)
+ Offset += AdditionalOffset.getLimitedValue() * SizeOfPointee;
+ else
+ Offset -= AdditionalOffset.getLimitedValue() * SizeOfPointee;
+
+ return APValue(ResultLValue.getLValueBase(), Offset);
+}
+
+APValue PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
+ APValue result;
+ if (EvaluateLValue(E->getSubExpr(), result, Info))
+ return result;
+ return APValue();
+}
+
+
+APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
+ const Expr* SubExpr = E->getSubExpr();
+
+ // Check for pointer->pointer cast
+ if (SubExpr->getType()->isPointerType()) {
+ APValue Result;
+ if (EvaluatePointer(SubExpr, Result, Info))
+ return Result;
+ return APValue();
+ }
+
+ if (SubExpr->getType()->isIntegralType()) {
+ APValue Result;
+ if (!EvaluateIntegerOrLValue(SubExpr, Result, Info))
+ return APValue();
+
+ if (Result.isInt()) {
+ Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
+ return APValue(0, Result.getInt().getZExtValue());
+ }
+
+ // Cast is of an lvalue, no need to change value.
+ return Result;
+ }
+
+ if (SubExpr->getType()->isFunctionType() ||
+ SubExpr->getType()->isBlockPointerType() ||
+ SubExpr->getType()->isArrayType()) {
+ APValue Result;
+ if (EvaluateLValue(SubExpr, Result, Info))
+ return Result;
+ return APValue();
+ }
+
+ return APValue();
+}
+
+APValue PointerExprEvaluator::VisitCallExpr(CallExpr *E) {
+ if (E->isBuiltinCall(Info.Ctx) ==
+ Builtin::BI__builtin___CFStringMakeConstantString)
+ return APValue(E, 0);
+ return APValue();
+}
+
+APValue PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
+ bool BoolResult;
+ if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
+ return APValue();
+
+ Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
+
+ APValue Result;
+ if (EvaluatePointer(EvalExpr, Result, Info))
+ return Result;
+ return APValue();
+}
+
+//===----------------------------------------------------------------------===//
+// Vector Evaluation
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class VISIBILITY_HIDDEN VectorExprEvaluator
+ : public StmtVisitor<VectorExprEvaluator, APValue> {
+ EvalInfo &Info;
+ APValue GetZeroVector(QualType VecType);
+ public:
+
+ VectorExprEvaluator(EvalInfo &info) : Info(info) {}
+
+ APValue VisitStmt(Stmt *S) {
+ return APValue();
+ }
+
+ APValue VisitParenExpr(ParenExpr *E)
+ { return Visit(E->getSubExpr()); }
+ APValue VisitUnaryExtension(const UnaryOperator *E)
+ { return Visit(E->getSubExpr()); }
+ APValue VisitUnaryPlus(const UnaryOperator *E)
+ { return Visit(E->getSubExpr()); }
+ 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);
+ APValue VisitConditionalOperator(const ConditionalOperator *E);
+ APValue VisitChooseExpr(const ChooseExpr *E)
+ { return Visit(E->getChosenSubExpr(Info.Ctx)); }
+ APValue VisitUnaryImag(const UnaryOperator *E);
+ // FIXME: Missing: unary -, unary ~, binary add/sub/mul/div,
+ // binary comparisons, binary and/or/xor,
+ // shufflevector, ExtVectorElementExpr
+ // (Note that these require implementing conversions
+ // between vector types.)
+ };
+} // end anonymous namespace
+
+static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) {
+ if (!E->getType()->isVectorType())
+ return false;
+ Result = VectorExprEvaluator(Info).Visit(const_cast<Expr*>(E));
+ return !Result.isUninit();
+}
+
+APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
+ const Expr* SE = E->getSubExpr();
+
+ // Check for vector->vector bitcast.
+ if (SE->getType()->isVectorType())
+ return this->Visit(const_cast<Expr*>(SE));
+
+ return APValue();
+}
+
+APValue
+VectorExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
+ return this->Visit(const_cast<Expr*>(E->getInitializer()));
+}
+
+APValue
+VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
+ const VectorType *VT = E->getType()->getAsVectorType();
+ unsigned NumInits = E->getNumInits();
+ unsigned NumElements = VT->getNumElements();
+
+ QualType EltTy = VT->getElementType();
+ llvm::SmallVector<APValue, 4> Elements;
+
+ for (unsigned i = 0; i < NumElements; i++) {
+ if (EltTy->isIntegerType()) {
+ llvm::APSInt sInt(32);
+ if (i < NumInits) {
+ if (!EvaluateInteger(E->getInit(i), sInt, Info))
+ return APValue();
+ } else {
+ sInt = Info.Ctx.MakeIntValue(0, EltTy);
+ }
+ Elements.push_back(APValue(sInt));
+ } else {
+ llvm::APFloat f(0.0);
+ if (i < NumInits) {
+ if (!EvaluateFloat(E->getInit(i), f, Info))
+ return APValue();
+ } else {
+ f = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(EltTy));
+ }
+ Elements.push_back(APValue(f));
+ }
+ }
+ return APValue(&Elements[0], Elements.size());
+}
+
+APValue
+VectorExprEvaluator::GetZeroVector(QualType T) {
+ const VectorType *VT = T->getAsVectorType();
+ QualType EltTy = VT->getElementType();
+ APValue ZeroElement;
+ if (EltTy->isIntegerType())
+ ZeroElement = APValue(Info.Ctx.MakeIntValue(0, EltTy));
+ else
+ ZeroElement =
+ APValue(APFloat::getZero(Info.Ctx.getFloatTypeSemantics(EltTy)));
+
+ llvm::SmallVector<APValue, 4> Elements(VT->getNumElements(), ZeroElement);
+ return APValue(&Elements[0], Elements.size());
+}
+
+APValue VectorExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
+ bool BoolResult;
+ if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
+ return APValue();
+
+ Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
+
+ APValue Result;
+ if (EvaluateVector(EvalExpr, Result, Info))
+ return Result;
+ return APValue();
+}
+
+APValue VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
+ if (!E->getSubExpr()->isEvaluatable(Info.Ctx))
+ Info.EvalResult.HasSideEffects = true;
+ return GetZeroVector(E->getType());
+}
+
+//===----------------------------------------------------------------------===//
+// Integer Evaluation
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN IntExprEvaluator
+ : public StmtVisitor<IntExprEvaluator, bool> {
+ EvalInfo &Info;
+ APValue &Result;
+public:
+ IntExprEvaluator(EvalInfo &info, APValue &result)
+ : Info(info), Result(result) {}
+
+ bool Success(const llvm::APSInt &SI, const Expr *E) {
+ assert(E->getType()->isIntegralType() && "Invalid evaluation result.");
+ assert(SI.isSigned() == E->getType()->isSignedIntegerType() &&
+ "Invalid evaluation result.");
+ assert(SI.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) &&
+ "Invalid evaluation result.");
+ Result = APValue(SI);
+ return true;
+ }
+
+ bool Success(const llvm::APInt &I, const Expr *E) {
+ assert(E->getType()->isIntegralType() && "Invalid evaluation result.");
+ assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) &&
+ "Invalid evaluation result.");
+ Result = APValue(APSInt(I));
+ Result.getInt().setIsUnsigned(E->getType()->isUnsignedIntegerType());
+ return true;
+ }
+
+ bool Success(uint64_t Value, const Expr *E) {
+ assert(E->getType()->isIntegralType() && "Invalid evaluation result.");
+ Result = APValue(Info.Ctx.MakeIntValue(Value, E->getType()));
+ return true;
+ }
+
+ bool Error(SourceLocation L, diag::kind D, const Expr *E) {
+ // Take the first error.
+ if (Info.EvalResult.Diag == 0) {
+ Info.EvalResult.DiagLoc = L;
+ Info.EvalResult.Diag = D;
+ Info.EvalResult.DiagExpr = E;
+ }
+ return false;
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Visitor Methods
+ //===--------------------------------------------------------------------===//
+
+ bool VisitStmt(Stmt *) {
+ assert(0 && "This should be called on integers, stmts are not integers");
+ return false;
+ }
+
+ bool VisitExpr(Expr *E) {
+ return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+ }
+
+ bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+
+ bool VisitIntegerLiteral(const IntegerLiteral *E) {
+ return Success(E->getValue(), E);
+ }
+ bool VisitCharacterLiteral(const CharacterLiteral *E) {
+ return Success(E->getValue(), E);
+ }
+ bool VisitTypesCompatibleExpr(const TypesCompatibleExpr *E) {
+ // Per gcc docs "this built-in function ignores top level
+ // qualifiers". We need to use the canonical version to properly
+ // be able to strip CRV qualifiers from the type.
+ QualType T0 = Info.Ctx.getCanonicalType(E->getArgType1());
+ QualType T1 = Info.Ctx.getCanonicalType(E->getArgType2());
+ return Success(Info.Ctx.typesAreCompatible(T0.getUnqualifiedType(),
+ T1.getUnqualifiedType()),
+ E);
+ }
+ bool VisitDeclRefExpr(const DeclRefExpr *E);
+ bool VisitCallExpr(const CallExpr *E);
+ bool VisitBinaryOperator(const BinaryOperator *E);
+ bool VisitUnaryOperator(const UnaryOperator *E);
+ bool VisitConditionalOperator(const ConditionalOperator *E);
+
+ bool VisitCastExpr(CastExpr* E);
+ bool VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E);
+
+ bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) {
+ return Success(E->getValue(), E);
+ }
+
+ bool VisitGNUNullExpr(const GNUNullExpr *E) {
+ return Success(0, E);
+ }
+
+ bool VisitCXXZeroInitValueExpr(const CXXZeroInitValueExpr *E) {
+ return Success(0, E);
+ }
+
+ bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
+ return Success(0, E);
+ }
+
+ bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) {
+ return Success(E->EvaluateTrait(), E);
+ }
+
+ bool VisitChooseExpr(const ChooseExpr *E) {
+ return Visit(E->getChosenSubExpr(Info.Ctx));
+ }
+
+ bool VisitUnaryReal(const UnaryOperator *E);
+ bool VisitUnaryImag(const UnaryOperator *E);
+
+private:
+ unsigned GetAlignOfExpr(const Expr *E);
+ unsigned GetAlignOfType(QualType T);
+ // FIXME: Missing: array subscript of vector, member of vector
+};
+} // end anonymous namespace
+
+static bool EvaluateIntegerOrLValue(const Expr* E, APValue &Result, EvalInfo &Info) {
+ if (!E->getType()->isIntegralType())
+ return false;
+
+ return IntExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
+}
+
+static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) {
+ APValue Val;
+ if (!EvaluateIntegerOrLValue(E, Val, Info) || !Val.isInt())
+ return false;
+ Result = Val.getInt();
+ return true;
+}
+
+bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
+ // Enums are integer constant exprs.
+ if (const EnumConstantDecl *D = dyn_cast<EnumConstantDecl>(E->getDecl())) {
+ // FIXME: This is an ugly hack around the fact that enums don't set their
+ // signedness consistently; see PR3173.
+ APSInt SI = D->getInitVal();
+ SI.setIsUnsigned(!E->getType()->isSignedIntegerType());
+ // FIXME: This is an ugly hack around the fact that enums don't
+ // set their width (!?!) consistently; see PR3173.
+ SI.extOrTrunc(Info.Ctx.getIntWidth(E->getType()));
+ return Success(SI, E);
+ }
+
+ // In C++, const, non-volatile integers initialized with ICEs are ICEs.
+ // In C, they can also be folded, although they are not ICEs.
+ if (E->getType().getCVRQualifiers() == QualType::Const) {
+ if (const VarDecl *D = dyn_cast<VarDecl>(E->getDecl())) {
+ if (APValue *V = D->getEvaluatedValue())
+ return Success(V->getInt(), E);
+ if (const Expr *Init = D->getInit()) {
+ if (Visit(const_cast<Expr*>(Init))) {
+ // Cache the evaluated value in the variable declaration.
+ D->setEvaluatedValue(Info.Ctx, Result);
+ return true;
+ }
+
+ return false;
+ }
+ }
+ }
+
+ // Otherwise, random variable references are not constants.
+ return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+}
+
+/// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way
+/// as GCC.
+static int EvaluateBuiltinClassifyType(const CallExpr *E) {
+ // The following enum mimics the values returned by GCC.
+ // FIXME: Does GCC differ between lvalue and rvalue references here?
+ enum gcc_type_class {
+ no_type_class = -1,
+ void_type_class, integer_type_class, char_type_class,
+ enumeral_type_class, boolean_type_class,
+ pointer_type_class, reference_type_class, offset_type_class,
+ real_type_class, complex_type_class,
+ function_type_class, method_type_class,
+ record_type_class, union_type_class,
+ array_type_class, string_type_class,
+ lang_type_class
+ };
+
+ // If no argument was supplied, default to "no_type_class". This isn't
+ // ideal, however it is what gcc does.
+ if (E->getNumArgs() == 0)
+ return no_type_class;
+
+ QualType ArgTy = E->getArg(0)->getType();
+ if (ArgTy->isVoidType())
+ return void_type_class;
+ else if (ArgTy->isEnumeralType())
+ return enumeral_type_class;
+ else if (ArgTy->isBooleanType())
+ return boolean_type_class;
+ else if (ArgTy->isCharType())
+ return string_type_class; // gcc doesn't appear to use char_type_class
+ else if (ArgTy->isIntegerType())
+ return integer_type_class;
+ else if (ArgTy->isPointerType())
+ return pointer_type_class;
+ else if (ArgTy->isReferenceType())
+ return reference_type_class;
+ else if (ArgTy->isRealType())
+ return real_type_class;
+ else if (ArgTy->isComplexType())
+ return complex_type_class;
+ else if (ArgTy->isFunctionType())
+ return function_type_class;
+ else if (ArgTy->isStructureType())
+ return record_type_class;
+ else if (ArgTy->isUnionType())
+ return union_type_class;
+ else if (ArgTy->isArrayType())
+ return array_type_class;
+ 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");
+ return -1;
+}
+
+bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
+ switch (E->isBuiltinCall(Info.Ctx)) {
+ default:
+ return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+ case Builtin::BI__builtin_classify_type:
+ return Success(EvaluateBuiltinClassifyType(E), E);
+
+ case Builtin::BI__builtin_constant_p:
+ // __builtin_constant_p always has one operand: it returns true if that
+ // operand can be folded, false otherwise.
+ return Success(E->getArg(0)->isEvaluatable(Info.Ctx), E);
+ }
+}
+
+bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
+ if (E->getOpcode() == BinaryOperator::Comma) {
+ if (!Visit(E->getRHS()))
+ return false;
+
+ // If we can't evaluate the LHS, it might have side effects;
+ // conservatively mark it.
+ if (!E->getLHS()->isEvaluatable(Info.Ctx))
+ Info.EvalResult.HasSideEffects = true;
+
+ return true;
+ }
+
+ if (E->isLogicalOp()) {
+ // These need to be handled specially because the operands aren't
+ // necessarily integral
+ bool lhsResult, rhsResult;
+
+ if (HandleConversionToBool(E->getLHS(), lhsResult, Info)) {
+ // We were able to evaluate the LHS, see if we can get away with not
+ // evaluating the RHS: 0 && X -> 0, 1 || X -> 1
+ if (lhsResult == (E->getOpcode() == BinaryOperator::LOr))
+ return Success(lhsResult, E);
+
+ if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) {
+ if (E->getOpcode() == BinaryOperator::LOr)
+ return Success(lhsResult || rhsResult, E);
+ else
+ return Success(lhsResult && rhsResult, E);
+ }
+ } else {
+ if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) {
+ // We can't evaluate the LHS; however, sometimes the result
+ // is determined by the RHS: X && 0 -> 0, X || 1 -> 1.
+ if (rhsResult == (E->getOpcode() == BinaryOperator::LOr) ||
+ !rhsResult == (E->getOpcode() == BinaryOperator::LAnd)) {
+ // Since we weren't able to evaluate the left hand side, it
+ // must have had side effects.
+ Info.EvalResult.HasSideEffects = true;
+
+ return Success(rhsResult, E);
+ }
+ }
+ }
+
+ return false;
+ }
+
+ QualType LHSTy = E->getLHS()->getType();
+ QualType RHSTy = E->getRHS()->getType();
+
+ if (LHSTy->isAnyComplexType()) {
+ assert(RHSTy->isAnyComplexType() && "Invalid comparison");
+ APValue LHS, RHS;
+
+ if (!EvaluateComplex(E->getLHS(), LHS, Info))
+ return false;
+
+ if (!EvaluateComplex(E->getRHS(), RHS, Info))
+ return false;
+
+ if (LHS.isComplexFloat()) {
+ APFloat::cmpResult CR_r =
+ LHS.getComplexFloatReal().compare(RHS.getComplexFloatReal());
+ APFloat::cmpResult CR_i =
+ LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag());
+
+ if (E->getOpcode() == BinaryOperator::EQ)
+ return Success((CR_r == APFloat::cmpEqual &&
+ CR_i == APFloat::cmpEqual), E);
+ else {
+ assert(E->getOpcode() == BinaryOperator::NE &&
+ "Invalid complex comparison.");
+ return Success(((CR_r == APFloat::cmpGreaterThan ||
+ CR_r == APFloat::cmpLessThan) &&
+ (CR_i == APFloat::cmpGreaterThan ||
+ CR_i == APFloat::cmpLessThan)), E);
+ }
+ } else {
+ if (E->getOpcode() == BinaryOperator::EQ)
+ return Success((LHS.getComplexIntReal() == RHS.getComplexIntReal() &&
+ LHS.getComplexIntImag() == RHS.getComplexIntImag()), E);
+ else {
+ assert(E->getOpcode() == BinaryOperator::NE &&
+ "Invalid compex comparison.");
+ return Success((LHS.getComplexIntReal() != RHS.getComplexIntReal() ||
+ LHS.getComplexIntImag() != RHS.getComplexIntImag()), E);
+ }
+ }
+ }
+
+ if (LHSTy->isRealFloatingType() &&
+ RHSTy->isRealFloatingType()) {
+ APFloat RHS(0.0), LHS(0.0);
+
+ if (!EvaluateFloat(E->getRHS(), RHS, Info))
+ return false;
+
+ if (!EvaluateFloat(E->getLHS(), LHS, Info))
+ return false;
+
+ APFloat::cmpResult CR = LHS.compare(RHS);
+
+ switch (E->getOpcode()) {
+ default:
+ assert(0 && "Invalid binary operator!");
+ case BinaryOperator::LT:
+ return Success(CR == APFloat::cmpLessThan, E);
+ case BinaryOperator::GT:
+ return Success(CR == APFloat::cmpGreaterThan, E);
+ case BinaryOperator::LE:
+ return Success(CR == APFloat::cmpLessThan || CR == APFloat::cmpEqual, E);
+ case BinaryOperator::GE:
+ return Success(CR == APFloat::cmpGreaterThan || CR == APFloat::cmpEqual,
+ E);
+ case BinaryOperator::EQ:
+ return Success(CR == APFloat::cmpEqual, E);
+ case BinaryOperator::NE:
+ return Success(CR == APFloat::cmpGreaterThan
+ || CR == APFloat::cmpLessThan, E);
+ }
+ }
+
+ if (LHSTy->isPointerType() && RHSTy->isPointerType()) {
+ if (E->getOpcode() == BinaryOperator::Sub || E->isEqualityOp()) {
+ APValue LHSValue;
+ if (!EvaluatePointer(E->getLHS(), LHSValue, Info))
+ return false;
+
+ APValue RHSValue;
+ if (!EvaluatePointer(E->getRHS(), RHSValue, Info))
+ return false;
+
+ // Reject any bases; this is conservative, but good enough for
+ // common uses
+ if (LHSValue.getLValueBase() || RHSValue.getLValueBase())
+ return false;
+
+ if (E->getOpcode() == BinaryOperator::Sub) {
+ const QualType Type = E->getLHS()->getType();
+ const QualType ElementType = Type->getAsPointerType()->getPointeeType();
+
+ uint64_t D = LHSValue.getLValueOffset() - RHSValue.getLValueOffset();
+ D /= Info.Ctx.getTypeSize(ElementType) / 8;
+
+ return Success(D, E);
+ }
+ bool Result;
+ if (E->getOpcode() == BinaryOperator::EQ) {
+ Result = LHSValue.getLValueOffset() == RHSValue.getLValueOffset();
+ } else {
+ Result = LHSValue.getLValueOffset() != RHSValue.getLValueOffset();
+ }
+ return Success(Result, E);
+ }
+ }
+ if (!LHSTy->isIntegralType() ||
+ !RHSTy->isIntegralType()) {
+ // We can't continue from here for non-integral types, and they
+ // could potentially confuse the following operations.
+ return false;
+ }
+
+ // The LHS of a constant expr is always evaluated and needed.
+ if (!Visit(E->getLHS()))
+ return false; // error in subexpression.
+
+ APValue RHSVal;
+ if (!EvaluateIntegerOrLValue(E->getRHS(), RHSVal, Info))
+ return false;
+
+ // Handle cases like (unsigned long)&a + 4.
+ if (E->isAdditiveOp() && Result.isLValue() && RHSVal.isInt()) {
+ uint64_t offset = Result.getLValueOffset();
+ if (E->getOpcode() == BinaryOperator::Add)
+ offset += RHSVal.getInt().getZExtValue();
+ else
+ offset -= RHSVal.getInt().getZExtValue();
+ Result = APValue(Result.getLValueBase(), offset);
+ return true;
+ }
+
+ // Handle cases like 4 + (unsigned long)&a
+ if (E->getOpcode() == BinaryOperator::Add &&
+ RHSVal.isLValue() && Result.isInt()) {
+ uint64_t offset = RHSVal.getLValueOffset();
+ offset += Result.getInt().getZExtValue();
+ Result = APValue(RHSVal.getLValueBase(), offset);
+ return true;
+ }
+
+ // All the following cases expect both operands to be an integer
+ if (!Result.isInt() || !RHSVal.isInt())
+ return false;
+
+ APSInt& RHS = RHSVal.getInt();
+
+ switch (E->getOpcode()) {
+ default:
+ return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E);
+ case BinaryOperator::Mul: return Success(Result.getInt() * RHS, E);
+ case BinaryOperator::Add: return Success(Result.getInt() + RHS, E);
+ case BinaryOperator::Sub: return Success(Result.getInt() - RHS, E);
+ case BinaryOperator::And: return Success(Result.getInt() & RHS, E);
+ case BinaryOperator::Xor: return Success(Result.getInt() ^ RHS, E);
+ case BinaryOperator::Or: return Success(Result.getInt() | RHS, E);
+ case BinaryOperator::Div:
+ if (RHS == 0)
+ return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E);
+ return Success(Result.getInt() / RHS, E);
+ case BinaryOperator::Rem:
+ if (RHS == 0)
+ return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E);
+ return Success(Result.getInt() % RHS, E);
+ case BinaryOperator::Shl: {
+ // FIXME: Warn about out of range shift amounts!
+ unsigned SA =
+ (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1);
+ return Success(Result.getInt() << SA, E);
+ }
+ case BinaryOperator::Shr: {
+ unsigned SA =
+ (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1);
+ return Success(Result.getInt() >> SA, E);
+ }
+
+ case BinaryOperator::LT: return Success(Result.getInt() < RHS, E);
+ case BinaryOperator::GT: return Success(Result.getInt() > RHS, E);
+ case BinaryOperator::LE: return Success(Result.getInt() <= RHS, E);
+ case BinaryOperator::GE: return Success(Result.getInt() >= RHS, E);
+ case BinaryOperator::EQ: return Success(Result.getInt() == RHS, E);
+ case BinaryOperator::NE: return Success(Result.getInt() != RHS, E);
+ }
+}
+
+bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
+ bool Cond;
+ if (!HandleConversionToBool(E->getCond(), Cond, Info))
+ return false;
+
+ return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr());
+}
+
+unsigned IntExprEvaluator::GetAlignOfType(QualType T) {
+ // Get information about the alignment.
+ unsigned CharSize = Info.Ctx.Target.getCharWidth();
+
+ // __alignof is defined to return the preferred alignment.
+ return Info.Ctx.getPreferredTypeAlign(T.getTypePtr()) / CharSize;
+}
+
+unsigned IntExprEvaluator::GetAlignOfExpr(const Expr *E) {
+ E = E->IgnoreParens();
+
+ // alignof decl is always accepted, even if it doesn't make sense: we default
+ // to 1 in those cases.
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ return Info.Ctx.getDeclAlignInBytes(DRE->getDecl());
+
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
+ return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl());
+
+ return GetAlignOfType(E->getType());
+}
+
+
+/// VisitSizeAlignOfExpr - Evaluate a sizeof or alignof with a result as the
+/// expression's type.
+bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
+ QualType DstTy = E->getType();
+
+ // Handle alignof separately.
+ if (!E->isSizeOf()) {
+ if (E->isArgumentType())
+ return Success(GetAlignOfType(E->getArgumentType()), E);
+ else
+ return Success(GetAlignOfExpr(E->getArgumentExpr()), E);
+ }
+
+ QualType SrcTy = E->getTypeOfArgument();
+
+ // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
+ // extension.
+ if (SrcTy->isVoidType() || SrcTy->isFunctionType())
+ return Success(1, E);
+
+ // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
+ if (!SrcTy->isConstantSizeType())
+ return false;
+
+ // Get information about the size.
+ unsigned BitWidth = Info.Ctx.getTypeSize(SrcTy);
+ return Success(BitWidth / Info.Ctx.Target.getCharWidth(), E);
+}
+
+bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
+ // Special case unary operators that do not need their subexpression
+ // evaluated. offsetof/sizeof/alignof are all special.
+ if (E->isOffsetOfOp()) {
+ // The AST for offsetof is defined in such a way that we can just
+ // directly Evaluate it as an l-value.
+ APValue LV;
+ if (!EvaluateLValue(E->getSubExpr(), LV, Info))
+ return false;
+ if (LV.getLValueBase())
+ return false;
+ return Success(LV.getLValueOffset(), E);
+ }
+
+ if (E->getOpcode() == UnaryOperator::LNot) {
+ // LNot's operand isn't necessarily an integer, so we handle it specially.
+ bool bres;
+ if (!HandleConversionToBool(E->getSubExpr(), bres, Info))
+ return false;
+ return Success(!bres, E);
+ }
+
+ // Only handle integral operations...
+ if (!E->getSubExpr()->getType()->isIntegralType())
+ return false;
+
+ // Get the operand value into 'Result'.
+ if (!Visit(E->getSubExpr()))
+ return false;
+
+ switch (E->getOpcode()) {
+ default:
+ // Address, indirect, pre/post inc/dec, etc are not valid constant exprs.
+ // See C99 6.6p3.
+ return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E);
+ case UnaryOperator::Extension:
+ // FIXME: Should extension allow i-c-e extension expressions in its scope?
+ // If so, we could clear the diagnostic ID.
+ return true;
+ case UnaryOperator::Plus:
+ // The result is always just the subexpr.
+ return true;
+ case UnaryOperator::Minus:
+ if (!Result.isInt()) return false;
+ return Success(-Result.getInt(), E);
+ case UnaryOperator::Not:
+ if (!Result.isInt()) return false;
+ return Success(~Result.getInt(), E);
+ }
+}
+
+/// HandleCast - This is used to evaluate implicit or explicit casts where the
+/// result type is integer.
+bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
+ Expr *SubExpr = E->getSubExpr();
+ QualType DestType = E->getType();
+ QualType SrcType = SubExpr->getType();
+
+ if (DestType->isBooleanType()) {
+ bool BoolResult;
+ if (!HandleConversionToBool(SubExpr, BoolResult, Info))
+ return false;
+ return Success(BoolResult, E);
+ }
+
+ // Handle simple integer->integer casts.
+ if (SrcType->isIntegralType()) {
+ if (!Visit(SubExpr))
+ return false;
+
+ if (!Result.isInt()) {
+ // Only allow casts of lvalues if they are lossless.
+ return Info.Ctx.getTypeSize(DestType) == Info.Ctx.getTypeSize(SrcType);
+ }
+
+ return Success(HandleIntToIntCast(DestType, SrcType,
+ Result.getInt(), Info.Ctx), E);
+ }
+
+ // FIXME: Clean this up!
+ if (SrcType->isPointerType()) {
+ APValue LV;
+ if (!EvaluatePointer(SubExpr, LV, Info))
+ return false;
+
+ if (LV.getLValueBase()) {
+ // Only allow based lvalue casts if they are lossless.
+ if (Info.Ctx.getTypeSize(DestType) != Info.Ctx.getTypeSize(SrcType))
+ return false;
+
+ Result = LV;
+ return true;
+ }
+
+ APSInt AsInt = Info.Ctx.MakeIntValue(LV.getLValueOffset(), SrcType);
+ return Success(HandleIntToIntCast(DestType, SrcType, AsInt, Info.Ctx), E);
+ }
+
+ if (SrcType->isArrayType() || SrcType->isFunctionType()) {
+ // This handles double-conversion cases, where there's both
+ // an l-value promotion and an implicit conversion to int.
+ APValue LV;
+ if (!EvaluateLValue(SubExpr, LV, Info))
+ return false;
+
+ if (Info.Ctx.getTypeSize(DestType) != Info.Ctx.getTypeSize(Info.Ctx.VoidPtrTy))
+ return false;
+
+ Result = LV;
+ return true;
+ }
+
+ if (SrcType->isAnyComplexType()) {
+ APValue C;
+ if (!EvaluateComplex(SubExpr, C, Info))
+ return false;
+ if (C.isComplexFloat())
+ return Success(HandleFloatToIntCast(DestType, SrcType,
+ C.getComplexFloatReal(), Info.Ctx),
+ E);
+ else
+ return Success(HandleIntToIntCast(DestType, SrcType,
+ C.getComplexIntReal(), Info.Ctx), E);
+ }
+ // FIXME: Handle vectors
+
+ if (!SrcType->isRealFloatingType())
+ return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E);
+
+ APFloat F(0.0);
+ if (!EvaluateFloat(SubExpr, F, Info))
+ return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E);
+
+ return Success(HandleFloatToIntCast(DestType, SrcType, F, Info.Ctx), E);
+}
+
+bool IntExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
+ if (E->getSubExpr()->getType()->isAnyComplexType()) {
+ APValue LV;
+ if (!EvaluateComplex(E->getSubExpr(), LV, Info) || !LV.isComplexInt())
+ return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E);
+ return Success(LV.getComplexIntReal(), E);
+ }
+
+ return Visit(E->getSubExpr());
+}
+
+bool IntExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
+ if (E->getSubExpr()->getType()->isComplexIntegerType()) {
+ APValue LV;
+ if (!EvaluateComplex(E->getSubExpr(), LV, Info) || !LV.isComplexInt())
+ return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E);
+ return Success(LV.getComplexIntImag(), E);
+ }
+
+ if (!E->getSubExpr()->isEvaluatable(Info.Ctx))
+ Info.EvalResult.HasSideEffects = true;
+ return Success(0, E);
+}
+
+//===----------------------------------------------------------------------===//
+// Float Evaluation
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN FloatExprEvaluator
+ : public StmtVisitor<FloatExprEvaluator, bool> {
+ EvalInfo &Info;
+ APFloat &Result;
+public:
+ FloatExprEvaluator(EvalInfo &info, APFloat &result)
+ : Info(info), Result(result) {}
+
+ bool VisitStmt(Stmt *S) {
+ return false;
+ }
+
+ bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitCallExpr(const CallExpr *E);
+
+ bool VisitUnaryOperator(const UnaryOperator *E);
+ bool VisitBinaryOperator(const BinaryOperator *E);
+ bool VisitFloatingLiteral(const FloatingLiteral *E);
+ bool VisitCastExpr(CastExpr *E);
+ bool VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E);
+
+ bool VisitChooseExpr(const ChooseExpr *E)
+ { return Visit(E->getChosenSubExpr(Info.Ctx)); }
+ bool VisitUnaryExtension(const UnaryOperator *E)
+ { return Visit(E->getSubExpr()); }
+
+ // FIXME: Missing: __real__/__imag__, array subscript of vector,
+ // member of vector, ImplicitValueInitExpr,
+ // conditional ?:, comma
+};
+} // end anonymous namespace
+
+static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) {
+ return FloatExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
+}
+
+bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
+ switch (E->isBuiltinCall(Info.Ctx)) {
+ default: return false;
+ case Builtin::BI__builtin_huge_val:
+ case Builtin::BI__builtin_huge_valf:
+ case Builtin::BI__builtin_huge_vall:
+ case Builtin::BI__builtin_inf:
+ case Builtin::BI__builtin_inff:
+ case Builtin::BI__builtin_infl: {
+ const llvm::fltSemantics &Sem =
+ Info.Ctx.getFloatTypeSemantics(E->getType());
+ Result = llvm::APFloat::getInf(Sem);
+ return true;
+ }
+
+ case Builtin::BI__builtin_nan:
+ case Builtin::BI__builtin_nanf:
+ case Builtin::BI__builtin_nanl:
+ // If this is __builtin_nan() turn this into a nan, otherwise we
+ // can't constant fold it.
+ if (const StringLiteral *S =
+ dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenCasts())) {
+ if (!S->isWide()) {
+ const llvm::fltSemantics &Sem =
+ Info.Ctx.getFloatTypeSemantics(E->getType());
+ llvm::SmallString<16> s;
+ s.append(S->getStrData(), S->getStrData() + S->getByteLength());
+ s += '\0';
+ long l;
+ char *endp;
+ l = strtol(&s[0], &endp, 0);
+ if (endp != s.end()-1)
+ return false;
+ unsigned type = (unsigned int)l;;
+ Result = llvm::APFloat::getNaN(Sem, false, type);
+ return true;
+ }
+ }
+ return false;
+
+ case Builtin::BI__builtin_fabs:
+ case Builtin::BI__builtin_fabsf:
+ case Builtin::BI__builtin_fabsl:
+ if (!EvaluateFloat(E->getArg(0), Result, Info))
+ return false;
+
+ if (Result.isNegative())
+ Result.changeSign();
+ return true;
+
+ case Builtin::BI__builtin_copysign:
+ case Builtin::BI__builtin_copysignf:
+ case Builtin::BI__builtin_copysignl: {
+ APFloat RHS(0.);
+ if (!EvaluateFloat(E->getArg(0), Result, Info) ||
+ !EvaluateFloat(E->getArg(1), RHS, Info))
+ return false;
+ Result.copySign(RHS);
+ return true;
+ }
+ }
+}
+
+bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
+ if (E->getOpcode() == UnaryOperator::Deref)
+ return false;
+
+ if (!EvaluateFloat(E->getSubExpr(), Result, Info))
+ return false;
+
+ switch (E->getOpcode()) {
+ default: return false;
+ case UnaryOperator::Plus:
+ return true;
+ case UnaryOperator::Minus:
+ Result.changeSign();
+ return true;
+ }
+}
+
+bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
+ // FIXME: Diagnostics? I really don't understand how the warnings
+ // and errors are supposed to work.
+ APFloat RHS(0.0);
+ if (!EvaluateFloat(E->getLHS(), Result, Info))
+ return false;
+ if (!EvaluateFloat(E->getRHS(), RHS, Info))
+ return false;
+
+ switch (E->getOpcode()) {
+ default: return false;
+ case BinaryOperator::Mul:
+ Result.multiply(RHS, APFloat::rmNearestTiesToEven);
+ return true;
+ case BinaryOperator::Add:
+ Result.add(RHS, APFloat::rmNearestTiesToEven);
+ return true;
+ case BinaryOperator::Sub:
+ Result.subtract(RHS, APFloat::rmNearestTiesToEven);
+ return true;
+ case BinaryOperator::Div:
+ Result.divide(RHS, APFloat::rmNearestTiesToEven);
+ return true;
+ }
+}
+
+bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {
+ Result = E->getValue();
+ return true;
+}
+
+bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) {
+ Expr* SubExpr = E->getSubExpr();
+
+ if (SubExpr->getType()->isIntegralType()) {
+ APSInt IntResult;
+ if (!EvaluateInteger(SubExpr, IntResult, Info))
+ return false;
+ Result = HandleIntToFloatCast(E->getType(), SubExpr->getType(),
+ IntResult, Info.Ctx);
+ return true;
+ }
+ if (SubExpr->getType()->isRealFloatingType()) {
+ if (!Visit(SubExpr))
+ return false;
+ Result = HandleFloatToFloatCast(E->getType(), SubExpr->getType(),
+ Result, Info.Ctx);
+ return true;
+ }
+ // FIXME: Handle complex types
+
+ return false;
+}
+
+bool FloatExprEvaluator::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
+ Result = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(E->getType()));
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Complex Evaluation (for float and integer)
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN ComplexExprEvaluator
+ : public StmtVisitor<ComplexExprEvaluator, APValue> {
+ EvalInfo &Info;
+
+public:
+ ComplexExprEvaluator(EvalInfo &info) : Info(info) {}
+
+ //===--------------------------------------------------------------------===//
+ // Visitor Methods
+ //===--------------------------------------------------------------------===//
+
+ APValue VisitStmt(Stmt *S) {
+ return APValue();
+ }
+
+ APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+
+ APValue VisitImaginaryLiteral(ImaginaryLiteral *E) {
+ Expr* SubExpr = E->getSubExpr();
+
+ if (SubExpr->getType()->isRealFloatingType()) {
+ APFloat Result(0.0);
+
+ if (!EvaluateFloat(SubExpr, Result, Info))
+ return APValue();
+
+ return APValue(APFloat(Result.getSemantics(), APFloat::fcZero, false),
+ Result);
+ } else {
+ assert(SubExpr->getType()->isIntegerType() &&
+ "Unexpected imaginary literal.");
+
+ llvm::APSInt Result;
+ if (!EvaluateInteger(SubExpr, Result, Info))
+ return APValue();
+
+ llvm::APSInt Zero(Result.getBitWidth(), !Result.isSigned());
+ Zero = 0;
+ return APValue(Zero, Result);
+ }
+ }
+
+ APValue VisitCastExpr(CastExpr *E) {
+ Expr* SubExpr = E->getSubExpr();
+ QualType EltType = E->getType()->getAsComplexType()->getElementType();
+ QualType SubType = SubExpr->getType();
+
+ if (SubType->isRealFloatingType()) {
+ APFloat Result(0.0);
+
+ if (!EvaluateFloat(SubExpr, Result, Info))
+ return APValue();
+
+ if (EltType->isRealFloatingType()) {
+ Result = HandleFloatToFloatCast(EltType, SubType, Result, Info.Ctx);
+ return APValue(Result,
+ APFloat(Result.getSemantics(), APFloat::fcZero, false));
+ } else {
+ llvm::APSInt IResult;
+ IResult = HandleFloatToIntCast(EltType, SubType, Result, Info.Ctx);
+ llvm::APSInt Zero(IResult.getBitWidth(), !IResult.isSigned());
+ Zero = 0;
+ return APValue(IResult, Zero);
+ }
+ } else if (SubType->isIntegerType()) {
+ APSInt Result;
+
+ if (!EvaluateInteger(SubExpr, Result, Info))
+ return APValue();
+
+ if (EltType->isRealFloatingType()) {
+ APFloat FResult =
+ HandleIntToFloatCast(EltType, SubType, Result, Info.Ctx);
+ return APValue(FResult,
+ APFloat(FResult.getSemantics(), APFloat::fcZero, false));
+ } else {
+ Result = HandleIntToIntCast(EltType, SubType, Result, Info.Ctx);
+ llvm::APSInt Zero(Result.getBitWidth(), !Result.isSigned());
+ Zero = 0;
+ return APValue(Result, Zero);
+ }
+ } else if (const ComplexType *CT = SubType->getAsComplexType()) {
+ APValue Src;
+
+ if (!EvaluateComplex(SubExpr, Src, Info))
+ return APValue();
+
+ QualType SrcType = CT->getElementType();
+
+ if (Src.isComplexFloat()) {
+ if (EltType->isRealFloatingType()) {
+ return APValue(HandleFloatToFloatCast(EltType, SrcType,
+ Src.getComplexFloatReal(),
+ Info.Ctx),
+ HandleFloatToFloatCast(EltType, SrcType,
+ Src.getComplexFloatImag(),
+ Info.Ctx));
+ } else {
+ return APValue(HandleFloatToIntCast(EltType, SrcType,
+ Src.getComplexFloatReal(),
+ Info.Ctx),
+ HandleFloatToIntCast(EltType, SrcType,
+ Src.getComplexFloatImag(),
+ Info.Ctx));
+ }
+ } else {
+ assert(Src.isComplexInt() && "Invalid evaluate result.");
+ if (EltType->isRealFloatingType()) {
+ return APValue(HandleIntToFloatCast(EltType, SrcType,
+ Src.getComplexIntReal(),
+ Info.Ctx),
+ HandleIntToFloatCast(EltType, SrcType,
+ Src.getComplexIntImag(),
+ Info.Ctx));
+ } else {
+ return APValue(HandleIntToIntCast(EltType, SrcType,
+ Src.getComplexIntReal(),
+ Info.Ctx),
+ HandleIntToIntCast(EltType, SrcType,
+ Src.getComplexIntImag(),
+ Info.Ctx));
+ }
+ }
+ }
+
+ // FIXME: Handle more casts.
+ return APValue();
+ }
+
+ APValue VisitBinaryOperator(const BinaryOperator *E);
+ APValue VisitChooseExpr(const ChooseExpr *E)
+ { return Visit(E->getChosenSubExpr(Info.Ctx)); }
+ APValue VisitUnaryExtension(const UnaryOperator *E)
+ { return Visit(E->getSubExpr()); }
+ // FIXME Missing: unary +/-/~, binary div, ImplicitValueInitExpr,
+ // conditional ?:, comma
+};
+} // end anonymous namespace
+
+static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info)
+{
+ Result = ComplexExprEvaluator(Info).Visit(const_cast<Expr*>(E));
+ assert((!Result.isComplexFloat() ||
+ (&Result.getComplexFloatReal().getSemantics() ==
+ &Result.getComplexFloatImag().getSemantics())) &&
+ "Invalid complex evaluation.");
+ return Result.isComplexFloat() || Result.isComplexInt();
+}
+
+APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E)
+{
+ APValue Result, RHS;
+
+ if (!EvaluateComplex(E->getLHS(), Result, Info))
+ return APValue();
+
+ if (!EvaluateComplex(E->getRHS(), RHS, Info))
+ return APValue();
+
+ assert(Result.isComplexFloat() == RHS.isComplexFloat() &&
+ "Invalid operands to binary operator.");
+ switch (E->getOpcode()) {
+ default: return APValue();
+ case BinaryOperator::Add:
+ if (Result.isComplexFloat()) {
+ Result.getComplexFloatReal().add(RHS.getComplexFloatReal(),
+ APFloat::rmNearestTiesToEven);
+ Result.getComplexFloatImag().add(RHS.getComplexFloatImag(),
+ APFloat::rmNearestTiesToEven);
+ } else {
+ Result.getComplexIntReal() += RHS.getComplexIntReal();
+ Result.getComplexIntImag() += RHS.getComplexIntImag();
+ }
+ break;
+ case BinaryOperator::Sub:
+ if (Result.isComplexFloat()) {
+ Result.getComplexFloatReal().subtract(RHS.getComplexFloatReal(),
+ APFloat::rmNearestTiesToEven);
+ Result.getComplexFloatImag().subtract(RHS.getComplexFloatImag(),
+ APFloat::rmNearestTiesToEven);
+ } else {
+ Result.getComplexIntReal() -= RHS.getComplexIntReal();
+ Result.getComplexIntImag() -= RHS.getComplexIntImag();
+ }
+ break;
+ case BinaryOperator::Mul:
+ if (Result.isComplexFloat()) {
+ APValue LHS = Result;
+ APFloat &LHS_r = LHS.getComplexFloatReal();
+ APFloat &LHS_i = LHS.getComplexFloatImag();
+ APFloat &RHS_r = RHS.getComplexFloatReal();
+ APFloat &RHS_i = RHS.getComplexFloatImag();
+
+ APFloat Tmp = LHS_r;
+ Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven);
+ Result.getComplexFloatReal() = Tmp;
+ Tmp = LHS_i;
+ Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven);
+ Result.getComplexFloatReal().subtract(Tmp, APFloat::rmNearestTiesToEven);
+
+ Tmp = LHS_r;
+ Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven);
+ Result.getComplexFloatImag() = Tmp;
+ Tmp = LHS_i;
+ Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven);
+ Result.getComplexFloatImag().add(Tmp, APFloat::rmNearestTiesToEven);
+ } else {
+ APValue LHS = Result;
+ Result.getComplexIntReal() =
+ (LHS.getComplexIntReal() * RHS.getComplexIntReal() -
+ LHS.getComplexIntImag() * RHS.getComplexIntImag());
+ Result.getComplexIntImag() =
+ (LHS.getComplexIntReal() * RHS.getComplexIntImag() +
+ LHS.getComplexIntImag() * RHS.getComplexIntReal());
+ }
+ break;
+ }
+
+ return Result;
+}
+
+//===----------------------------------------------------------------------===//
+// Top level Expr::Evaluate method.
+//===----------------------------------------------------------------------===//
+
+/// Evaluate - Return true if this is a constant which we can fold using
+/// any crazy technique (that has nothing to do with language standards) that
+/// we want to. If this function returns true, it returns the folded constant
+/// in Result.
+bool Expr::Evaluate(EvalResult &Result, ASTContext &Ctx) const {
+ EvalInfo Info(Ctx, Result);
+
+ if (getType()->isVectorType()) {
+ if (!EvaluateVector(this, Result.Val, Info))
+ return false;
+ } else if (getType()->isIntegerType()) {
+ if (!IntExprEvaluator(Info, Result.Val).Visit(const_cast<Expr*>(this)))
+ return false;
+ } else if (getType()->hasPointerRepresentation()) {
+ if (!EvaluatePointer(this, Result.Val, Info))
+ return false;
+ } else if (getType()->isRealFloatingType()) {
+ llvm::APFloat f(0.0);
+ if (!EvaluateFloat(this, f, Info))
+ return false;
+
+ Result.Val = APValue(f);
+ } else if (getType()->isAnyComplexType()) {
+ if (!EvaluateComplex(this, Result.Val, Info))
+ return false;
+ } else
+ return false;
+
+ return true;
+}
+
+bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const {
+ EvalInfo Info(Ctx, Result);
+
+ return EvaluateLValue(this, Result.Val, Info) && !Result.HasSideEffects;
+}
+
+/// isEvaluatable - Call Evaluate to see if this expression can be constant
+/// folded, but discard the result.
+bool Expr::isEvaluatable(ASTContext &Ctx) const {
+ EvalResult Result;
+ return Evaluate(Result, Ctx) && !Result.HasSideEffects;
+}
+
+APSInt Expr::EvaluateAsInt(ASTContext &Ctx) const {
+ EvalResult EvalResult;
+ bool Result = Evaluate(EvalResult, Ctx);
+ Result = Result;
+ assert(Result && "Could not evaluate expression");
+ assert(EvalResult.Val.isInt() && "Expression did not evaluate to integer");
+
+ return EvalResult.Val.getInt();
+}
diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp
new file mode 100644
index 000000000000..dd2fc14ab2a4
--- /dev/null
+++ b/lib/AST/InheritViz.cpp
@@ -0,0 +1,168 @@
+//===- InheritViz.cpp - Graphviz visualization for inheritance --*- 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 CXXRecordDecl::viewInheritance, which
+// generates a GraphViz DOT file that depicts the class inheritance
+// diagram and then calls Graphviz/dot+gv on it.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/TypeOrdering.h"
+#include "llvm/Support/GraphWriter.h"
+#include "llvm/Support/raw_ostream.h"
+#include <map>
+
+using namespace llvm;
+
+namespace clang {
+
+/// InheritanceHierarchyWriter - Helper class that writes out a
+/// GraphViz file that diagrams the inheritance hierarchy starting at
+/// a given C++ class type. Note that we do not use LLVM's
+/// GraphWriter, because the interface does not permit us to properly
+/// differentiate between uses of types as virtual bases
+/// vs. non-virtual bases.
+class InheritanceHierarchyWriter {
+ ASTContext& Context;
+ llvm::raw_ostream &Out;
+ std::map<QualType, int, QualTypeOrdering> DirectBaseCount;
+ std::set<QualType, QualTypeOrdering> KnownVirtualBases;
+
+public:
+ InheritanceHierarchyWriter(ASTContext& Context, llvm::raw_ostream& Out)
+ : Context(Context), Out(Out) { }
+
+ void WriteGraph(QualType Type) {
+ Out << "digraph \"" << DOT::EscapeString(Type.getAsString()) << "\" {\n";
+ WriteNode(Type, false);
+ Out << "}\n";
+ }
+
+protected:
+ /// WriteNode - Write out the description of node in the inheritance
+ /// diagram, which may be a base class or it may be the root node.
+ void 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& WriteNodeReference(QualType Type, bool FromVirtual);
+};
+
+void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
+ QualType CanonType = Context.getCanonicalType(Type);
+
+ if (FromVirtual) {
+ if (KnownVirtualBases.find(CanonType) != KnownVirtualBases.end())
+ return;
+
+ // We haven't seen this virtual base before, so display it and
+ // its bases.
+ KnownVirtualBases.insert(CanonType);
+ }
+
+ // Declare the node itself.
+ Out << " ";
+ WriteNodeReference(Type, FromVirtual);
+
+ // Give the node a label based on the name of the class.
+ std::string TypeName = Type.getAsString();
+ Out << " [ shape=\"box\", label=\"" << DOT::EscapeString(TypeName);
+
+ // If the name of the class was a typedef or something different
+ // from the "real" class name, show the real class name in
+ // parentheses so we don't confuse ourselves.
+ if (TypeName != CanonType.getAsString()) {
+ Out << "\\n(" << CanonType.getAsString() << ")";
+ }
+
+ // Finished describing the node.
+ Out << " \"];\n";
+
+ // Display the base classes.
+ const CXXRecordDecl *Decl
+ = static_cast<const CXXRecordDecl *>(Type->getAsRecordType()->getDecl());
+ for (CXXRecordDecl::base_class_const_iterator Base = Decl->bases_begin();
+ Base != Decl->bases_end(); ++Base) {
+ QualType CanonBaseType = Context.getCanonicalType(Base->getType());
+
+ // If this is not virtual inheritance, bump the direct base
+ // count for the type.
+ if (!Base->isVirtual())
+ ++DirectBaseCount[CanonBaseType];
+
+ // Write out the node (if we need to).
+ WriteNode(Base->getType(), Base->isVirtual());
+
+ // Write out the edge.
+ Out << " ";
+ WriteNodeReference(Type, FromVirtual);
+ Out << " -> ";
+ WriteNodeReference(Base->getType(), Base->isVirtual());
+
+ // Write out edge attributes to show the kind of inheritance.
+ if (Base->isVirtual()) {
+ Out << " [ style=\"dashed\" ]";
+ }
+ Out << ";";
+ }
+}
+
+/// 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&
+InheritanceHierarchyWriter::WriteNodeReference(QualType Type,
+ bool FromVirtual) {
+ QualType CanonType = Context.getCanonicalType(Type);
+
+ Out << "Class_" << CanonType.getAsOpaquePtr();
+ if (!FromVirtual)
+ Out << "_" << DirectBaseCount[CanonType];
+ return Out;
+}
+
+/// viewInheritance - Display the inheritance hierarchy of this C++
+/// class using GraphViz.
+void CXXRecordDecl::viewInheritance(ASTContext& Context) const {
+ QualType Self = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
+ std::string ErrMsg;
+ sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
+ if (Filename.isEmpty()) {
+ llvm::errs() << "Error: " << ErrMsg << "\n";
+ return;
+ }
+ Filename.appendComponent(Self.getAsString() + ".dot");
+ if (Filename.makeUnique(true,&ErrMsg)) {
+ llvm::errs() << "Error: " << ErrMsg << "\n";
+ return;
+ }
+
+ llvm::errs() << "Writing '" << Filename.c_str() << "'... ";
+
+ llvm::raw_fd_ostream O(Filename.c_str(), false, ErrMsg);
+
+ if (ErrMsg.empty()) {
+ InheritanceHierarchyWriter Writer(Context, O);
+ Writer.WriteGraph(Self);
+ llvm::errs() << " done. \n";
+
+ O.close();
+
+ // Display the graph
+ DisplayGraph(Filename);
+ } else {
+ llvm::errs() << "error opening file for writing!\n";
+ }
+}
+
+}
diff --git a/lib/AST/Makefile b/lib/AST/Makefile
new file mode 100644
index 000000000000..f7d4e9f62d5f
--- /dev/null
+++ b/lib/AST/Makefile
@@ -0,0 +1,22 @@
+##===- clang/lib/AST/Makefile ------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements the AST library for the C-Language front-end.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+LIBRARYNAME := clangAST
+BUILD_ARCHIVE = 1
+CXXFLAGS = -fno-rtti
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
new file mode 100644
index 000000000000..09522a20863c
--- /dev/null
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -0,0 +1,160 @@
+//===--- NestedNameSpecifier.cpp - C++ nested name specifiers -----*- 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 NestedNameSpecifier class, which represents
+// a C++ nested-name-specifier.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/Type.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+
+using namespace clang;
+
+NestedNameSpecifier *
+NestedNameSpecifier::FindOrInsert(ASTContext &Context,
+ const NestedNameSpecifier &Mockup) {
+ llvm::FoldingSetNodeID ID;
+ Mockup.Profile(ID);
+
+ void *InsertPos = 0;
+ NestedNameSpecifier *NNS
+ = Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos);
+ if (!NNS) {
+ NNS = new (Context, 4) NestedNameSpecifier(Mockup);
+ Context.NestedNameSpecifiers.InsertNode(NNS, InsertPos);
+ }
+
+ return NNS;
+}
+
+NestedNameSpecifier *
+NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
+ IdentifierInfo *II) {
+ assert(II && "Identifier cannot be NULL");
+ assert(Prefix && Prefix->isDependent() && "Prefix must be dependent");
+
+ NestedNameSpecifier Mockup;
+ Mockup.Prefix.setPointer(Prefix);
+ Mockup.Prefix.setInt(Identifier);
+ Mockup.Specifier = II;
+ return FindOrInsert(Context, Mockup);
+}
+
+NestedNameSpecifier *
+NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
+ NamespaceDecl *NS) {
+ assert(NS && "Namespace cannot be NULL");
+ assert((!Prefix ||
+ (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
+ "Broken nested name specifier");
+ NestedNameSpecifier Mockup;
+ Mockup.Prefix.setPointer(Prefix);
+ Mockup.Prefix.setInt(Namespace);
+ Mockup.Specifier = NS;
+ return FindOrInsert(Context, Mockup);
+}
+
+NestedNameSpecifier *
+NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
+ bool Template, Type *T) {
+ assert(T && "Type cannot be NULL");
+ NestedNameSpecifier Mockup;
+ Mockup.Prefix.setPointer(Prefix);
+ Mockup.Prefix.setInt(Template? TypeSpecWithTemplate : TypeSpec);
+ Mockup.Specifier = T;
+ return FindOrInsert(Context, Mockup);
+}
+
+NestedNameSpecifier *NestedNameSpecifier::GlobalSpecifier(ASTContext &Context) {
+ if (!Context.GlobalNestedNameSpecifier)
+ Context.GlobalNestedNameSpecifier = new (Context, 4) NestedNameSpecifier();
+ return Context.GlobalNestedNameSpecifier;
+}
+
+/// \brief Whether this nested name specifier refers to a dependent
+/// type or not.
+bool NestedNameSpecifier::isDependent() const {
+ switch (getKind()) {
+ case Identifier:
+ // Identifier specifiers always represent dependent types
+ return true;
+
+ case Namespace:
+ case Global:
+ return false;
+
+ case TypeSpec:
+ case TypeSpecWithTemplate:
+ return getAsType()->isDependentType();
+ }
+
+ // Necessary to suppress a GCC warning.
+ return false;
+}
+
+/// \brief Print this nested name specifier to the given output
+/// stream.
+void
+NestedNameSpecifier::print(llvm::raw_ostream &OS,
+ const PrintingPolicy &Policy) const {
+ if (getPrefix())
+ getPrefix()->print(OS, Policy);
+
+ switch (getKind()) {
+ case Identifier:
+ OS << getAsIdentifier()->getName();
+ break;
+
+ case Namespace:
+ OS << getAsNamespace()->getIdentifier()->getName();
+ break;
+
+ case Global:
+ break;
+
+ case TypeSpecWithTemplate:
+ OS << "template ";
+ // Fall through to print the type.
+
+ case TypeSpec: {
+ std::string TypeStr;
+ Type *T = getAsType();
+
+ // If this is a qualified name type, suppress the qualification:
+ // it's part of our nested-name-specifier sequence anyway. FIXME:
+ // We should be able to assert that this doesn't happen.
+ if (const QualifiedNameType *QualT = dyn_cast<QualifiedNameType>(T))
+ T = QualT->getNamedType().getTypePtr();
+
+ PrintingPolicy InnerPolicy(Policy);
+ InnerPolicy.SuppressTagKind = true;
+ T->getAsStringInternal(TypeStr, InnerPolicy);
+ OS << TypeStr;
+ break;
+ }
+ }
+
+ OS << "::";
+}
+
+void NestedNameSpecifier::Destroy(ASTContext &Context) {
+ this->~NestedNameSpecifier();
+ Context.Deallocate((void *)this);
+}
+
+void NestedNameSpecifier::dump() {
+ PrintingPolicy Policy;
+ Policy.CPlusPlus = true;
+ print(llvm::errs(), Policy);
+}
diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp
new file mode 100644
index 000000000000..9d87daa0bfd8
--- /dev/null
+++ b/lib/AST/ParentMap.cpp
@@ -0,0 +1,94 @@
+//===--- ParentMap.cpp - Mappings from Stmts to their Parents ---*- 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 ParentMap class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ParentMap.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "llvm/ADT/DenseMap.h"
+
+using namespace clang;
+
+typedef llvm::DenseMap<Stmt*, Stmt*> MapTy;
+
+static void BuildParentMap(MapTy& M, Stmt* S) {
+ for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
+ if (*I) {
+ M[*I] = S;
+ BuildParentMap(M, *I);
+ }
+}
+
+ParentMap::ParentMap(Stmt* S) : Impl(0) {
+ if (S) {
+ MapTy *M = new MapTy();
+ BuildParentMap(*M, S);
+ Impl = M;
+ }
+}
+
+ParentMap::~ParentMap() {
+ delete (MapTy*) Impl;
+}
+
+Stmt* ParentMap::getParent(Stmt* S) const {
+ MapTy* M = (MapTy*) Impl;
+ MapTy::iterator I = M->find(S);
+ return I == M->end() ? 0 : I->second;
+}
+
+Stmt *ParentMap::getParentIgnoreParens(Stmt *S) const {
+ do { S = getParent(S); } while (S && isa<ParenExpr>(S));
+ return S;
+}
+
+bool ParentMap::isConsumedExpr(Expr* E) const {
+ Stmt *P = getParent(E);
+ Stmt *DirectChild = E;
+
+ // Ignore parents that are parentheses or casts.
+ while (P && (isa<ParenExpr>(P) || isa<CastExpr>(P))) {
+ DirectChild = P;
+ P = getParent(P);
+ }
+
+ if (!P)
+ return false;
+
+ switch (P->getStmtClass()) {
+ default:
+ return isa<Expr>(P);
+ case Stmt::DeclStmtClass:
+ return true;
+ case Stmt::BinaryOperatorClass: {
+ BinaryOperator *BE = cast<BinaryOperator>(P);
+ // If it is a comma, only the right side is consumed.
+ // If it isn't a comma, both sides are consumed.
+ return BE->getOpcode()!=BinaryOperator::Comma ||DirectChild==BE->getRHS();
+ }
+ case Stmt::ForStmtClass:
+ return DirectChild == cast<ForStmt>(P)->getCond();
+ case Stmt::WhileStmtClass:
+ return DirectChild == cast<WhileStmt>(P)->getCond();
+ case Stmt::DoStmtClass:
+ return DirectChild == cast<DoStmt>(P)->getCond();
+ case Stmt::IfStmtClass:
+ return DirectChild == cast<IfStmt>(P)->getCond();
+ case Stmt::IndirectGotoStmtClass:
+ return DirectChild == cast<IndirectGotoStmt>(P)->getTarget();
+ case Stmt::SwitchStmtClass:
+ return DirectChild == cast<SwitchStmt>(P)->getCond();
+ case Stmt::ReturnStmtClass:
+ return true;
+ }
+}
+
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
new file mode 100644
index 000000000000..17577910d2a3
--- /dev/null
+++ b/lib/AST/Stmt.cpp
@@ -0,0 +1,587 @@
+//===--- Stmt.cpp - Statement AST Node Implementation ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Stmt class and statement subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Stmt.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
+using namespace clang;
+
+static struct StmtClassNameTable {
+ const char *Name;
+ unsigned Counter;
+ unsigned Size;
+} StmtClassInfo[Stmt::lastExprConstant+1];
+
+static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
+ static bool Initialized = false;
+ if (Initialized)
+ return StmtClassInfo[E];
+
+ // Intialize the table on the first use.
+ Initialized = true;
+#define STMT(CLASS, PARENT) \
+ StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \
+ StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS);
+#include "clang/AST/StmtNodes.def"
+
+ return StmtClassInfo[E];
+}
+
+const char *Stmt::getStmtClassName() const {
+ return getStmtInfoTableEntry(sClass).Name;
+}
+
+void Stmt::DestroyChildren(ASTContext &C) {
+ for (child_iterator I = child_begin(), E = child_end(); I !=E; )
+ if (Stmt* Child = *I++) Child->Destroy(C);
+}
+
+void Stmt::Destroy(ASTContext &C) {
+ DestroyChildren(C);
+ // FIXME: Eventually all Stmts should be allocated with the allocator
+ // in ASTContext, just like with Decls.
+ this->~Stmt();
+ C.Deallocate((void *)this);
+}
+
+void DeclStmt::Destroy(ASTContext &C) {
+ this->~DeclStmt();
+ C.Deallocate((void *)this);
+}
+
+void Stmt::PrintStats() {
+ // Ensure the table is primed.
+ getStmtInfoTableEntry(Stmt::NullStmtClass);
+
+ unsigned sum = 0;
+ fprintf(stderr, "*** Stmt/Expr Stats:\n");
+ for (int i = 0; i != Stmt::lastExprConstant+1; i++) {
+ if (StmtClassInfo[i].Name == 0) continue;
+ sum += StmtClassInfo[i].Counter;
+ }
+ fprintf(stderr, " %d stmts/exprs total.\n", sum);
+ sum = 0;
+ for (int i = 0; i != Stmt::lastExprConstant+1; i++) {
+ if (StmtClassInfo[i].Name == 0) continue;
+ if (StmtClassInfo[i].Counter == 0) continue;
+ fprintf(stderr, " %d %s, %d each (%d bytes)\n",
+ StmtClassInfo[i].Counter, StmtClassInfo[i].Name,
+ StmtClassInfo[i].Size,
+ StmtClassInfo[i].Counter*StmtClassInfo[i].Size);
+ sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size;
+ }
+ fprintf(stderr, "Total bytes = %d\n", sum);
+}
+
+void Stmt::addStmtClass(StmtClass s) {
+ ++getStmtInfoTableEntry(s).Counter;
+}
+
+static bool StatSwitch = false;
+
+bool Stmt::CollectingStats(bool enable) {
+ if (enable) StatSwitch = true;
+ return StatSwitch;
+}
+
+NullStmt* NullStmt::Clone(ASTContext &C) const {
+ return new (C) NullStmt(SemiLoc);
+}
+
+ContinueStmt* ContinueStmt::Clone(ASTContext &C) const {
+ return new (C) ContinueStmt(ContinueLoc);
+}
+
+BreakStmt* BreakStmt::Clone(ASTContext &C) const {
+ return new (C) BreakStmt(BreakLoc);
+}
+
+void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) {
+ if (this->Body)
+ C.Deallocate(Body);
+ this->NumStmts = NumStmts;
+
+ Body = new (C) Stmt*[NumStmts];
+ memcpy(Body, Stmts, sizeof(Stmt *) * NumStmts);
+}
+
+const char *LabelStmt::getName() const {
+ return getID()->getName();
+}
+
+// This is defined here to avoid polluting Stmt.h with importing Expr.h
+SourceRange ReturnStmt::getSourceRange() const {
+ if (RetExpr)
+ return SourceRange(RetLoc, RetExpr->getLocEnd());
+ else
+ return SourceRange(RetLoc);
+}
+
+bool Stmt::hasImplicitControlFlow() const {
+ switch (sClass) {
+ default:
+ return false;
+
+ case CallExprClass:
+ case ConditionalOperatorClass:
+ case ChooseExprClass:
+ case StmtExprClass:
+ case DeclStmtClass:
+ return true;
+
+ case Stmt::BinaryOperatorClass: {
+ const BinaryOperator* B = cast<BinaryOperator>(this);
+ if (B->isLogicalOp() || B->getOpcode() == BinaryOperator::Comma)
+ return true;
+ else
+ return false;
+ }
+ }
+}
+
+Expr *AsmStmt::getOutputExpr(unsigned i) {
+ return cast<Expr>(Exprs[i]);
+}
+
+/// getOutputConstraint - Return the constraint string for the specified
+/// output operand. All output constraints are known to be non-empty (either
+/// '=' or '+').
+std::string AsmStmt::getOutputConstraint(unsigned i) const {
+ return std::string(Constraints[i]->getStrData(),
+ Constraints[i]->getByteLength());
+}
+
+/// getNumPlusOperands - Return the number of output operands that have a "+"
+/// constraint.
+unsigned AsmStmt::getNumPlusOperands() const {
+ unsigned Res = 0;
+ for (unsigned i = 0, e = getNumOutputs(); i != e; ++i)
+ if (isOutputPlusConstraint(i))
+ ++Res;
+ return Res;
+}
+
+
+
+Expr *AsmStmt::getInputExpr(unsigned i) {
+ return cast<Expr>(Exprs[i + NumOutputs]);
+}
+
+/// getInputConstraint - Return the specified input constraint. Unlike output
+/// constraints, these can be empty.
+std::string AsmStmt::getInputConstraint(unsigned i) const {
+ return std::string(Constraints[i + NumOutputs]->getStrData(),
+ Constraints[i + NumOutputs]->getByteLength());
+}
+
+
+void AsmStmt::setOutputsAndInputs(unsigned NumOutputs,
+ unsigned NumInputs,
+ const std::string *Names,
+ StringLiteral **Constraints,
+ Stmt **Exprs) {
+ this->NumOutputs = NumOutputs;
+ this->NumInputs = NumInputs;
+ this->Names.clear();
+ this->Names.insert(this->Names.end(), Names, Names + NumOutputs + NumInputs);
+ this->Constraints.clear();
+ this->Constraints.insert(this->Constraints.end(),
+ Constraints, Constraints + NumOutputs + NumInputs);
+ this->Exprs.clear();
+ this->Exprs.insert(this->Exprs.end(), Exprs, Exprs + NumOutputs + NumInputs);
+}
+
+/// 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(const std::string &SymbolicName) const {
+ unsigned NumPlusOperands = 0;
+
+ // Check if this is an output operand.
+ for (unsigned i = 0, e = getNumOutputs(); i != e; ++i) {
+ if (getOutputName(i) == SymbolicName)
+ return i;
+ }
+
+ for (unsigned i = 0, e = getNumInputs(); i != e; ++i)
+ if (getInputName(i) == SymbolicName)
+ return getNumOutputs() + NumPlusOperands + i;
+
+ // Not found.
+ return -1;
+}
+
+void AsmStmt::setClobbers(StringLiteral **Clobbers, unsigned NumClobbers) {
+ this->Clobbers.clear();
+ this->Clobbers.insert(this->Clobbers.end(), Clobbers, Clobbers + NumClobbers);
+}
+
+/// 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,
+ ASTContext &C, unsigned &DiagOffs) const {
+ const char *StrStart = getAsmString()->getStrData();
+ const char *StrEnd = StrStart + getAsmString()->getByteLength();
+ const char *CurPtr = StrStart;
+
+ // "Simple" inline asms have no constraints or operands, just convert the asm
+ // string to escape $'s.
+ if (isSimple()) {
+ std::string Result;
+ for (; CurPtr != StrEnd; ++CurPtr) {
+ switch (*CurPtr) {
+ case '$':
+ Result += "$$";
+ break;
+ default:
+ Result += *CurPtr;
+ break;
+ }
+ }
+ Pieces.push_back(AsmStringPiece(Result));
+ return 0;
+ }
+
+ // CurStringPiece - The current string that we are building up as we scan the
+ // asm string.
+ std::string CurStringPiece;
+
+ while (1) {
+ // Done with the string?
+ if (CurPtr == StrEnd) {
+ if (!CurStringPiece.empty())
+ Pieces.push_back(AsmStringPiece(CurStringPiece));
+ return 0;
+ }
+
+ char CurChar = *CurPtr++;
+ if (CurChar == '$') {
+ CurStringPiece += "$$";
+ continue;
+ } else if (CurChar != '%') {
+ CurStringPiece += CurChar;
+ continue;
+ }
+
+ // Escaped "%" character in asm string.
+ if (CurPtr == StrEnd) {
+ // % at end of string is invalid (no escape).
+ DiagOffs = CurPtr-StrStart-1;
+ return diag::err_asm_invalid_escape;
+ }
+
+ char EscapedChar = *CurPtr++;
+ if (EscapedChar == '%') { // %% -> %
+ // Escaped percentage sign.
+ CurStringPiece += '%';
+ continue;
+ }
+
+ if (EscapedChar == '=') { // %= -> Generate an unique ID.
+ CurStringPiece += "${:uid}";
+ continue;
+ }
+
+ // Otherwise, we have an operand. If we have accumulated a string so far,
+ // add it to the Pieces list.
+ if (!CurStringPiece.empty()) {
+ Pieces.push_back(AsmStringPiece(CurStringPiece));
+ CurStringPiece.clear();
+ }
+
+ // Handle %x4 and %x[foo] by capturing x as the modifier character.
+ char Modifier = '\0';
+ if (isalpha(EscapedChar)) {
+ Modifier = EscapedChar;
+ EscapedChar = *CurPtr++;
+ }
+
+ if (isdigit(EscapedChar)) {
+ // %n - Assembler operand n
+ unsigned N = 0;
+
+ --CurPtr;
+ while (CurPtr != StrEnd && isdigit(*CurPtr))
+ N = N*10 + ((*CurPtr++)-'0');
+
+ unsigned NumOperands =
+ getNumOutputs() + getNumPlusOperands() + getNumInputs();
+ if (N >= NumOperands) {
+ DiagOffs = CurPtr-StrStart-1;
+ return diag::err_asm_invalid_operand_number;
+ }
+
+ Pieces.push_back(AsmStringPiece(N, Modifier));
+ continue;
+ }
+
+ // Handle %[foo], a symbolic operand reference.
+ if (EscapedChar == '[') {
+ DiagOffs = CurPtr-StrStart-1;
+
+ // Find the ']'.
+ const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr);
+ if (NameEnd == 0)
+ return diag::err_asm_unterminated_symbolic_operand_name;
+ if (NameEnd == CurPtr)
+ return diag::err_asm_empty_symbolic_operand_name;
+
+ std::string SymbolicName(CurPtr, NameEnd);
+
+ int N = getNamedOperand(SymbolicName);
+ if (N == -1) {
+ // Verify that an operand with that name exists.
+ DiagOffs = CurPtr-StrStart;
+ return diag::err_asm_unknown_symbolic_operand_name;
+ }
+ Pieces.push_back(AsmStringPiece(N, Modifier));
+
+ CurPtr = NameEnd+1;
+ continue;
+ }
+
+ DiagOffs = CurPtr-StrStart-1;
+ return diag::err_asm_invalid_escape;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Constructors
+//===----------------------------------------------------------------------===//
+
+AsmStmt::AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile,
+ unsigned numoutputs, unsigned numinputs,
+ std::string *names, StringLiteral **constraints,
+ Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
+ StringLiteral **clobbers, SourceLocation rparenloc)
+ : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr)
+ , IsSimple(issimple), IsVolatile(isvolatile)
+ , NumOutputs(numoutputs), NumInputs(numinputs) {
+ for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) {
+ Names.push_back(names[i]);
+ Exprs.push_back(exprs[i]);
+ Constraints.push_back(constraints[i]);
+ }
+
+ for (unsigned i = 0; i != numclobbers; i++)
+ Clobbers.push_back(clobbers[i]);
+}
+
+ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
+ Stmt *Body, SourceLocation FCL,
+ SourceLocation RPL)
+: Stmt(ObjCForCollectionStmtClass) {
+ SubExprs[ELEM] = Elem;
+ SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(Collect);
+ SubExprs[BODY] = Body;
+ ForLoc = FCL;
+ RParenLoc = RPL;
+}
+
+
+ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc,
+ SourceLocation rparenloc,
+ ParmVarDecl *catchVarDecl, Stmt *atCatchStmt,
+ Stmt *atCatchList)
+: Stmt(ObjCAtCatchStmtClass) {
+ ExceptionDecl = catchVarDecl;
+ SubExprs[BODY] = atCatchStmt;
+ SubExprs[NEXT_CATCH] = NULL;
+ // FIXME: O(N^2) in number of catch blocks.
+ if (atCatchList) {
+ ObjCAtCatchStmt *AtCatchList = static_cast<ObjCAtCatchStmt*>(atCatchList);
+
+ while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt())
+ AtCatchList = NextCatch;
+
+ AtCatchList->SubExprs[NEXT_CATCH] = this;
+ }
+ AtCatchLoc = atCatchLoc;
+ RParenLoc = rparenloc;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Child Iterators for iterating over subexpressions/substatements
+//===----------------------------------------------------------------------===//
+
+// DeclStmt
+Stmt::child_iterator DeclStmt::child_begin() {
+ return StmtIterator(DG.begin(), DG.end());
+}
+
+Stmt::child_iterator DeclStmt::child_end() {
+ return StmtIterator(DG.end(), DG.end());
+}
+
+// NullStmt
+Stmt::child_iterator NullStmt::child_begin() { return child_iterator(); }
+Stmt::child_iterator NullStmt::child_end() { return child_iterator(); }
+
+// CompoundStmt
+Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; }
+Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+NumStmts; }
+
+// CaseStmt
+Stmt::child_iterator CaseStmt::child_begin() { return &SubExprs[0]; }
+Stmt::child_iterator CaseStmt::child_end() { return &SubExprs[END_EXPR]; }
+
+// DefaultStmt
+Stmt::child_iterator DefaultStmt::child_begin() { return &SubStmt; }
+Stmt::child_iterator DefaultStmt::child_end() { return &SubStmt+1; }
+
+// LabelStmt
+Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; }
+Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; }
+
+// IfStmt
+Stmt::child_iterator IfStmt::child_begin() { return &SubExprs[0]; }
+Stmt::child_iterator IfStmt::child_end() { return &SubExprs[0]+END_EXPR; }
+
+// SwitchStmt
+Stmt::child_iterator SwitchStmt::child_begin() { return &SubExprs[0]; }
+Stmt::child_iterator SwitchStmt::child_end() { return &SubExprs[0]+END_EXPR; }
+
+// WhileStmt
+Stmt::child_iterator WhileStmt::child_begin() { return &SubExprs[0]; }
+Stmt::child_iterator WhileStmt::child_end() { return &SubExprs[0]+END_EXPR; }
+
+// DoStmt
+Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; }
+Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; }
+
+// ForStmt
+Stmt::child_iterator ForStmt::child_begin() { return &SubExprs[0]; }
+Stmt::child_iterator ForStmt::child_end() { return &SubExprs[0]+END_EXPR; }
+
+// ObjCForCollectionStmt
+Stmt::child_iterator ObjCForCollectionStmt::child_begin() {
+ return &SubExprs[0];
+}
+Stmt::child_iterator ObjCForCollectionStmt::child_end() {
+ return &SubExprs[0]+END_EXPR;
+}
+
+// GotoStmt
+Stmt::child_iterator GotoStmt::child_begin() { return child_iterator(); }
+Stmt::child_iterator GotoStmt::child_end() { return child_iterator(); }
+
+// IndirectGotoStmt
+Expr* IndirectGotoStmt::getTarget() { return cast<Expr>(Target); }
+const Expr* IndirectGotoStmt::getTarget() const { return cast<Expr>(Target); }
+
+Stmt::child_iterator IndirectGotoStmt::child_begin() { return &Target; }
+Stmt::child_iterator IndirectGotoStmt::child_end() { return &Target+1; }
+
+// ContinueStmt
+Stmt::child_iterator ContinueStmt::child_begin() { return child_iterator(); }
+Stmt::child_iterator ContinueStmt::child_end() { return child_iterator(); }
+
+// BreakStmt
+Stmt::child_iterator BreakStmt::child_begin() { return child_iterator(); }
+Stmt::child_iterator BreakStmt::child_end() { return child_iterator(); }
+
+// ReturnStmt
+const Expr* ReturnStmt::getRetValue() const {
+ return cast_or_null<Expr>(RetExpr);
+}
+Expr* ReturnStmt::getRetValue() {
+ return cast_or_null<Expr>(RetExpr);
+}
+
+Stmt::child_iterator ReturnStmt::child_begin() {
+ return &RetExpr;
+}
+Stmt::child_iterator ReturnStmt::child_end() {
+ return RetExpr ? &RetExpr+1 : &RetExpr;
+}
+
+// AsmStmt
+Stmt::child_iterator AsmStmt::child_begin() {
+ return Exprs.empty() ? 0 : &Exprs[0];
+}
+Stmt::child_iterator AsmStmt::child_end() {
+ return Exprs.empty() ? 0 : &Exprs[0] + Exprs.size();
+}
+
+// ObjCAtCatchStmt
+Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; }
+Stmt::child_iterator ObjCAtCatchStmt::child_end() {
+ return &SubExprs[0]+END_EXPR;
+}
+
+// ObjCAtFinallyStmt
+Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; }
+Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; }
+
+// ObjCAtTryStmt
+Stmt::child_iterator ObjCAtTryStmt::child_begin() { return &SubStmts[0]; }
+Stmt::child_iterator ObjCAtTryStmt::child_end() {
+ return &SubStmts[0]+END_EXPR;
+}
+
+// ObjCAtThrowStmt
+Stmt::child_iterator ObjCAtThrowStmt::child_begin() {
+ return &Throw;
+}
+
+Stmt::child_iterator ObjCAtThrowStmt::child_end() {
+ return &Throw+1;
+}
+
+// ObjCAtSynchronizedStmt
+Stmt::child_iterator ObjCAtSynchronizedStmt::child_begin() {
+ return &SubStmts[0];
+}
+
+Stmt::child_iterator ObjCAtSynchronizedStmt::child_end() {
+ return &SubStmts[0]+END_EXPR;
+}
+
+// CXXCatchStmt
+Stmt::child_iterator CXXCatchStmt::child_begin() {
+ return &HandlerBlock;
+}
+
+Stmt::child_iterator CXXCatchStmt::child_end() {
+ return &HandlerBlock + 1;
+}
+
+QualType CXXCatchStmt::getCaughtType() {
+ if (ExceptionDecl)
+ return ExceptionDecl->getType();
+ return QualType();
+}
+
+void CXXCatchStmt::Destroy(ASTContext& C) {
+ if (ExceptionDecl)
+ ExceptionDecl->Destroy(C);
+ Stmt::Destroy(C);
+}
+
+// CXXTryStmt
+Stmt::child_iterator CXXTryStmt::child_begin() { return &Stmts[0]; }
+Stmt::child_iterator CXXTryStmt::child_end() { return &Stmts[0]+Stmts.size(); }
+
+CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
+ Stmt **handlers, unsigned numHandlers)
+ : Stmt(CXXTryStmtClass), TryLoc(tryLoc) {
+ Stmts.push_back(tryBlock);
+ Stmts.insert(Stmts.end(), handlers, handlers + numHandlers);
+}
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
new file mode 100644
index 000000000000..b24e912582d5
--- /dev/null
+++ b/lib/AST/StmtDumper.cpp
@@ -0,0 +1,542 @@
+//===--- StmtDumper.cpp - Dumping implementation for Stmt ASTs ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Stmt::dump/Stmt::print methods, which dump out the
+// AST in a form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/Compiler.h"
+#include <cstdio>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// StmtDumper Visitor
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class VISIBILITY_HIDDEN StmtDumper : public StmtVisitor<StmtDumper> {
+ SourceManager *SM;
+ FILE *F;
+ unsigned IndentLevel;
+
+ /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump
+ /// the first few levels of an AST. This keeps track of how many ast levels
+ /// are left.
+ unsigned MaxDepth;
+
+ /// LastLocFilename/LastLocLine - Keep track of the last location we print
+ /// out so that we can print out deltas from then on out.
+ const char *LastLocFilename;
+ unsigned LastLocLine;
+
+ PrintingPolicy Policy;
+ public:
+ StmtDumper(SourceManager *sm, FILE *f, unsigned maxDepth)
+ : SM(sm), F(f), IndentLevel(0-1), MaxDepth(maxDepth) {
+ LastLocFilename = "";
+ LastLocLine = ~0U;
+ }
+
+ void DumpSubTree(Stmt *S) {
+ // Prune the recursion if not using dump all.
+ if (MaxDepth == 0) return;
+
+ ++IndentLevel;
+ if (S) {
+ if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
+ VisitDeclStmt(DS);
+ else {
+ Visit(S);
+
+ // Print out children.
+ Stmt::child_iterator CI = S->child_begin(), CE = S->child_end();
+ if (CI != CE) {
+ while (CI != CE) {
+ fprintf(F, "\n");
+ DumpSubTree(*CI++);
+ }
+ }
+ fprintf(F, ")");
+ }
+ } else {
+ Indent();
+ fprintf(F, "<<<NULL>>>");
+ }
+ --IndentLevel;
+ }
+
+ void DumpDeclarator(Decl *D);
+
+ void Indent() const {
+ for (int i = 0, e = IndentLevel; i < e; ++i)
+ fprintf(F, " ");
+ }
+
+ void DumpType(QualType T) {
+ fprintf(F, "'%s'", T.getAsString().c_str());
+
+ if (!T.isNull()) {
+ // If the type is directly a typedef, strip off typedefness to give at
+ // least one level of concreteness.
+ if (TypedefType *TDT = dyn_cast<TypedefType>(T)) {
+ QualType Simplified =
+ TDT->LookThroughTypedefs().getQualifiedType(T.getCVRQualifiers());
+ fprintf(F, ":'%s'", Simplified.getAsString().c_str());
+ }
+ }
+ }
+ void DumpStmt(const Stmt *Node) {
+ Indent();
+ fprintf(F, "(%s %p", Node->getStmtClassName(), (void*)Node);
+ DumpSourceRange(Node);
+ }
+ void DumpExpr(const Expr *Node) {
+ DumpStmt(Node);
+ fprintf(F, " ");
+ DumpType(Node->getType());
+ }
+ void DumpSourceRange(const Stmt *Node);
+ void DumpLocation(SourceLocation Loc);
+
+ // Stmts.
+ void VisitStmt(Stmt *Node);
+ void VisitDeclStmt(DeclStmt *Node);
+ void VisitLabelStmt(LabelStmt *Node);
+ void VisitGotoStmt(GotoStmt *Node);
+
+ // Exprs
+ void VisitExpr(Expr *Node);
+ void VisitDeclRefExpr(DeclRefExpr *Node);
+ void VisitPredefinedExpr(PredefinedExpr *Node);
+ void VisitCharacterLiteral(CharacterLiteral *Node);
+ void VisitIntegerLiteral(IntegerLiteral *Node);
+ void VisitFloatingLiteral(FloatingLiteral *Node);
+ void VisitStringLiteral(StringLiteral *Str);
+ void VisitUnaryOperator(UnaryOperator *Node);
+ void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node);
+ void VisitMemberExpr(MemberExpr *Node);
+ void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
+ void VisitBinaryOperator(BinaryOperator *Node);
+ void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
+ void VisitAddrLabelExpr(AddrLabelExpr *Node);
+ void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node);
+
+ // C++
+ void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
+ void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node);
+ void VisitCXXThisExpr(CXXThisExpr *Node);
+ void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node);
+
+ // ObjC
+ void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
+ void VisitObjCMessageExpr(ObjCMessageExpr* Node);
+ void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
+ void VisitObjCProtocolExpr(ObjCProtocolExpr *Node);
+ void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node);
+ void VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node);
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
+ void VisitObjCSuperExpr(ObjCSuperExpr *Node);
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// Utilities
+//===----------------------------------------------------------------------===//
+
+void StmtDumper::DumpLocation(SourceLocation Loc) {
+ SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
+
+ if (SpellingLoc.isInvalid()) {
+ fprintf(stderr, "<invalid sloc>");
+ return;
+ }
+
+ // The general format we print out is filename:line:col, but we drop pieces
+ // that haven't changed since the last loc printed.
+ PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc);
+
+ if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
+ fprintf(stderr, "%s:%u:%u", PLoc.getFilename(), PLoc.getLine(),
+ PLoc.getColumn());
+ LastLocFilename = PLoc.getFilename();
+ LastLocLine = PLoc.getLine();
+ } else if (PLoc.getLine() != LastLocLine) {
+ fprintf(stderr, "line:%u:%u", PLoc.getLine(), PLoc.getColumn());
+ LastLocLine = PLoc.getLine();
+ } else {
+ fprintf(stderr, "col:%u", PLoc.getColumn());
+ }
+}
+
+void StmtDumper::DumpSourceRange(const Stmt *Node) {
+ // Can't translate locations if a SourceManager isn't available.
+ if (SM == 0) return;
+
+ // TODO: If the parent expression is available, we can print a delta vs its
+ // location.
+ SourceRange R = Node->getSourceRange();
+
+ fprintf(stderr, " <");
+ DumpLocation(R.getBegin());
+ if (R.getBegin() != R.getEnd()) {
+ fprintf(stderr, ", ");
+ DumpLocation(R.getEnd());
+ }
+ fprintf(stderr, ">");
+
+ // <t2.c:123:421[blah], t2.c:412:321>
+
+}
+
+
+//===----------------------------------------------------------------------===//
+// Stmt printing methods.
+//===----------------------------------------------------------------------===//
+
+void StmtDumper::VisitStmt(Stmt *Node) {
+ DumpStmt(Node);
+}
+
+void StmtDumper::DumpDeclarator(Decl *D) {
+ // FIXME: Need to complete/beautify this... this code simply shows the
+ // nodes are where they need to be.
+ if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
+ fprintf(F, "\"typedef %s %s\"",
+ localType->getUnderlyingType().getAsString().c_str(),
+ localType->getNameAsString().c_str());
+ } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
+ fprintf(F, "\"");
+ // Emit storage class for vardecls.
+ if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
+ if (V->getStorageClass() != VarDecl::None)
+ fprintf(F, "%s ",
+ VarDecl::getStorageClassSpecifierString(V->getStorageClass()));
+ }
+
+ std::string Name = VD->getNameAsString();
+ VD->getType().getAsStringInternal(Name, Policy);
+ fprintf(F, "%s", Name.c_str());
+
+ // If this is a vardecl with an initializer, emit it.
+ if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
+ if (V->getInit()) {
+ fprintf(F, " =\n");
+ DumpSubTree(V->getInit());
+ }
+ }
+ fprintf(F, "\"");
+ } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ // print a free standing tag decl (e.g. "struct x;").
+ const char *tagname;
+ if (const IdentifierInfo *II = TD->getIdentifier())
+ tagname = II->getName();
+ else
+ tagname = "<anonymous>";
+ fprintf(F, "\"%s %s;\"", TD->getKindName(), tagname);
+ // FIXME: print tag bodies.
+ } else if (UsingDirectiveDecl *UD = dyn_cast<UsingDirectiveDecl>(D)) {
+ // print using-directive decl (e.g. "using namespace x;")
+ const char *ns;
+ if (const IdentifierInfo *II = UD->getNominatedNamespace()->getIdentifier())
+ ns = II->getName();
+ else
+ ns = "<anonymous>";
+ fprintf(F, "\"%s %s;\"",UD->getDeclKindName(), ns);
+ } else {
+ assert(0 && "Unexpected decl");
+ }
+}
+
+void StmtDumper::VisitDeclStmt(DeclStmt *Node) {
+ DumpStmt(Node);
+ fprintf(F,"\n");
+ for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
+ DI != DE; ++DI) {
+ Decl* D = *DI;
+ ++IndentLevel;
+ Indent();
+ fprintf(F, "%p ", (void*) D);
+ DumpDeclarator(D);
+ if (DI+1 != DE)
+ fprintf(F,"\n");
+ --IndentLevel;
+ }
+}
+
+void StmtDumper::VisitLabelStmt(LabelStmt *Node) {
+ DumpStmt(Node);
+ fprintf(F, " '%s'", Node->getName());
+}
+
+void StmtDumper::VisitGotoStmt(GotoStmt *Node) {
+ DumpStmt(Node);
+ fprintf(F, " '%s':%p", Node->getLabel()->getName(), (void*)Node->getLabel());
+}
+
+//===----------------------------------------------------------------------===//
+// Expr printing methods.
+//===----------------------------------------------------------------------===//
+
+void StmtDumper::VisitExpr(Expr *Node) {
+ DumpExpr(Node);
+}
+
+void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
+ DumpExpr(Node);
+
+ fprintf(F, " ");
+ switch (Node->getDecl()->getKind()) {
+ case Decl::Function: fprintf(F,"FunctionDecl"); break;
+ case Decl::Var: fprintf(F,"Var"); break;
+ case Decl::ParmVar: fprintf(F,"ParmVar"); break;
+ case Decl::EnumConstant: fprintf(F,"EnumConstant"); break;
+ case Decl::Typedef: fprintf(F,"Typedef"); break;
+ case Decl::Record: fprintf(F,"Record"); break;
+ case Decl::Enum: fprintf(F,"Enum"); break;
+ case Decl::CXXRecord: fprintf(F,"CXXRecord"); break;
+ case Decl::ObjCInterface: fprintf(F,"ObjCInterface"); break;
+ case Decl::ObjCClass: fprintf(F,"ObjCClass"); break;
+ default: fprintf(F,"Decl"); break;
+ }
+
+ fprintf(F, "='%s' %p", Node->getDecl()->getNameAsString().c_str(),
+ (void*)Node->getDecl());
+}
+
+void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
+ DumpExpr(Node);
+
+ fprintf(F, " %sDecl='%s' %p", Node->getDecl()->getDeclKindName(),
+ Node->getDecl()->getNameAsString().c_str(), (void*)Node->getDecl());
+ if (Node->isFreeIvar())
+ fprintf(F, " isFreeIvar");
+}
+
+void StmtDumper::VisitPredefinedExpr(PredefinedExpr *Node) {
+ DumpExpr(Node);
+ switch (Node->getIdentType()) {
+ default: assert(0 && "unknown case");
+ case PredefinedExpr::Func: fprintf(F, " __func__"); break;
+ case PredefinedExpr::Function: fprintf(F, " __FUNCTION__"); break;
+ case PredefinedExpr::PrettyFunction: fprintf(F, " __PRETTY_FUNCTION__");break;
+ }
+}
+
+void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) {
+ DumpExpr(Node);
+ fprintf(F, " %d", Node->getValue());
+}
+
+void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) {
+ DumpExpr(Node);
+
+ bool isSigned = Node->getType()->isSignedIntegerType();
+ fprintf(F, " %s", Node->getValue().toString(10, isSigned).c_str());
+}
+void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) {
+ DumpExpr(Node);
+ fprintf(F, " %f", Node->getValueAsApproximateDouble());
+}
+
+void StmtDumper::VisitStringLiteral(StringLiteral *Str) {
+ DumpExpr(Str);
+ // FIXME: this doesn't print wstrings right.
+ fprintf(F, " %s\"", Str->isWide() ? "L" : "");
+
+ for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) {
+ switch (char C = Str->getStrData()[i]) {
+ default:
+ if (isprint(C))
+ fputc(C, F);
+ else
+ fprintf(F, "\\%03o", C);
+ break;
+ // Handle some common ones to make dumps prettier.
+ case '\\': fprintf(F, "\\\\"); break;
+ case '"': fprintf(F, "\\\""); break;
+ case '\n': fprintf(F, "\\n"); break;
+ case '\t': fprintf(F, "\\t"); break;
+ case '\a': fprintf(F, "\\a"); break;
+ case '\b': fprintf(F, "\\b"); break;
+ }
+ }
+ fprintf(F, "\"");
+}
+
+void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) {
+ DumpExpr(Node);
+ fprintf(F, " %s '%s'", Node->isPostfix() ? "postfix" : "prefix",
+ UnaryOperator::getOpcodeStr(Node->getOpcode()));
+}
+void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
+ DumpExpr(Node);
+ fprintf(F, " %s ", Node->isSizeOf() ? "sizeof" : "alignof");
+ if (Node->isArgumentType())
+ DumpType(Node->getArgumentType());
+}
+
+void StmtDumper::VisitMemberExpr(MemberExpr *Node) {
+ DumpExpr(Node);
+ fprintf(F, " %s%s %p", Node->isArrow() ? "->" : ".",
+ Node->getMemberDecl()->getNameAsString().c_str(),
+ (void*)Node->getMemberDecl());
+}
+void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
+ DumpExpr(Node);
+ fprintf(F, " %s", Node->getAccessor().getName());
+}
+void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) {
+ DumpExpr(Node);
+ fprintf(F, " '%s'", BinaryOperator::getOpcodeStr(Node->getOpcode()));
+}
+void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
+ DumpExpr(Node);
+ fprintf(F, " '%s' ComputeLHSTy=",
+ BinaryOperator::getOpcodeStr(Node->getOpcode()));
+ DumpType(Node->getComputationLHSType());
+ fprintf(F, " ComputeResultTy=");
+ DumpType(Node->getComputationResultType());
+}
+
+// GNU extensions.
+
+void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
+ DumpExpr(Node);
+ fprintf(F, " %s %p", Node->getLabel()->getName(), (void*)Node->getLabel());
+}
+
+void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
+ DumpExpr(Node);
+ fprintf(F, " ");
+ DumpType(Node->getArgType1());
+ fprintf(F, " ");
+ DumpType(Node->getArgType2());
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Expressions
+//===----------------------------------------------------------------------===//
+
+void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
+ DumpExpr(Node);
+ fprintf(F, " %s<%s>", Node->getCastName(),
+ Node->getTypeAsWritten().getAsString().c_str());
+}
+
+void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
+ DumpExpr(Node);
+ fprintf(F, " %s", Node->getValue() ? "true" : "false");
+}
+
+void StmtDumper::VisitCXXThisExpr(CXXThisExpr *Node) {
+ DumpExpr(Node);
+ fprintf(F, " this");
+}
+
+void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
+ DumpExpr(Node);
+ fprintf(F, " functional cast to %s",
+ Node->getTypeAsWritten().getAsString().c_str());
+}
+
+//===----------------------------------------------------------------------===//
+// Obj-C Expressions
+//===----------------------------------------------------------------------===//
+
+void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
+ DumpExpr(Node);
+ fprintf(F, " selector=%s", Node->getSelector().getAsString().c_str());
+ IdentifierInfo* clsName = Node->getClassName();
+ if (clsName) fprintf(F, " class=%s", clsName->getName());
+}
+
+void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
+ DumpExpr(Node);
+
+ fprintf(F, " ");
+ DumpType(Node->getEncodedType());
+}
+
+void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
+ DumpExpr(Node);
+
+ fprintf(F, " ");
+ fprintf(F, "%s", Node->getSelector().getAsString().c_str());
+}
+
+void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
+ DumpExpr(Node);
+
+ fprintf(F, " ");
+ fprintf(F, "%s", Node->getProtocol()->getNameAsString().c_str());
+}
+
+void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
+ DumpExpr(Node);
+
+ fprintf(F, " Kind=PropertyRef Property=\"%s\"",
+ Node->getProperty()->getNameAsString().c_str());
+}
+
+void StmtDumper::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) {
+ DumpExpr(Node);
+
+ ObjCMethodDecl *Getter = Node->getGetterMethod();
+ ObjCMethodDecl *Setter = Node->getSetterMethod();
+ fprintf(F, " Kind=MethodRef Getter=\"%s\" Setter=\"%s\"",
+ Getter->getSelector().getAsString().c_str(),
+ Setter ? Setter->getSelector().getAsString().c_str() : "(null)");
+}
+
+void StmtDumper::VisitObjCSuperExpr(ObjCSuperExpr *Node) {
+ DumpExpr(Node);
+ fprintf(F, " super");
+}
+
+//===----------------------------------------------------------------------===//
+// Stmt method implementations
+//===----------------------------------------------------------------------===//
+
+/// dump - This does a local dump of the specified AST fragment. It dumps the
+/// specified node and a few nodes underneath it, but not the whole subtree.
+/// This is useful in a debugger.
+void Stmt::dump(SourceManager &SM) const {
+ StmtDumper P(&SM, stderr, 4);
+ P.DumpSubTree(const_cast<Stmt*>(this));
+ fprintf(stderr, "\n");
+}
+
+/// dump - This does a local dump of the specified AST fragment. It dumps the
+/// specified node and a few nodes underneath it, but not the whole subtree.
+/// This is useful in a debugger.
+void Stmt::dump() const {
+ StmtDumper P(0, stderr, 4);
+ P.DumpSubTree(const_cast<Stmt*>(this));
+ fprintf(stderr, "\n");
+}
+
+/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
+void Stmt::dumpAll(SourceManager &SM) const {
+ StmtDumper P(&SM, stderr, ~0U);
+ P.DumpSubTree(const_cast<Stmt*>(this));
+ fprintf(stderr, "\n");
+}
+
+/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
+void Stmt::dumpAll() const {
+ StmtDumper P(0, stderr, ~0U);
+ P.DumpSubTree(const_cast<Stmt*>(this));
+ fprintf(stderr, "\n");
+}
diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp
new file mode 100644
index 000000000000..5c22e28894f9
--- /dev/null
+++ b/lib/AST/StmtIterator.cpp
@@ -0,0 +1,155 @@
+//===--- StmtIterator.cpp - Iterators for Statements ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines internal methods for StmtIterator.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/StmtIterator.h"
+#include "clang/AST/Decl.h"
+
+using namespace clang;
+
+// FIXME: Add support for dependent-sized array types in C++?
+// Does it even make sense to build a CFG for an uninstantiated template?
+static inline VariableArrayType* FindVA(Type* t) {
+ while (ArrayType* vt = dyn_cast<ArrayType>(t)) {
+ if (VariableArrayType* vat = dyn_cast<VariableArrayType>(vt))
+ if (vat->getSizeExpr())
+ return vat;
+
+ t = vt->getElementType().getTypePtr();
+ }
+
+ return NULL;
+}
+
+void StmtIteratorBase::NextVA() {
+ assert (getVAPtr());
+
+ VariableArrayType* p = getVAPtr();
+ p = FindVA(p->getElementType().getTypePtr());
+ setVAPtr(p);
+
+ if (p)
+ return;
+
+ if (inDecl()) {
+ if (VarDecl* VD = dyn_cast<VarDecl>(decl))
+ if (VD->Init)
+ return;
+
+ NextDecl();
+ }
+ else if (inDeclGroup()) {
+ if (VarDecl* VD = dyn_cast<VarDecl>(*DGI))
+ if (VD->Init)
+ return;
+
+ NextDecl();
+ }
+ else {
+ assert (inSizeOfTypeVA());
+ assert(!decl);
+ RawVAPtr = 0;
+ }
+}
+
+void StmtIteratorBase::NextDecl(bool ImmediateAdvance) {
+ assert (getVAPtr() == NULL);
+
+ if (inDecl()) {
+ assert (decl);
+
+ // FIXME: SIMPLIFY AWAY.
+ if (ImmediateAdvance)
+ decl = 0;
+ else if (HandleDecl(decl))
+ return;
+ }
+ else {
+ assert (inDeclGroup());
+
+ if (ImmediateAdvance)
+ ++DGI;
+
+ for ( ; DGI != DGE; ++DGI)
+ if (HandleDecl(*DGI))
+ return;
+ }
+
+ RawVAPtr = 0;
+}
+
+bool StmtIteratorBase::HandleDecl(Decl* D) {
+
+ if (VarDecl* VD = dyn_cast<VarDecl>(D)) {
+ if (VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) {
+ setVAPtr(VAPtr);
+ return true;
+ }
+
+ if (VD->getInit())
+ return true;
+ }
+ else if (TypedefDecl* TD = dyn_cast<TypedefDecl>(D)) {
+ if (VariableArrayType* VAPtr =
+ FindVA(TD->getUnderlyingType().getTypePtr())) {
+ setVAPtr(VAPtr);
+ return true;
+ }
+ }
+ else if (EnumConstantDecl* ECD = dyn_cast<EnumConstantDecl>(D)) {
+ if (ECD->getInitExpr())
+ return true;
+ }
+
+ return false;
+}
+
+StmtIteratorBase::StmtIteratorBase(Decl* d)
+ : decl(d), RawVAPtr(DeclMode) {
+ assert (decl);
+ NextDecl(false);
+}
+
+StmtIteratorBase::StmtIteratorBase(Decl** dgi, Decl** dge)
+ : DGI(dgi), RawVAPtr(DeclGroupMode), DGE(dge) {
+ NextDecl(false);
+}
+
+StmtIteratorBase::StmtIteratorBase(VariableArrayType* t)
+: decl(0), RawVAPtr(SizeOfTypeVAMode) {
+ RawVAPtr |= reinterpret_cast<uintptr_t>(t);
+}
+
+Stmt*& StmtIteratorBase::GetDeclExpr() const {
+
+ if (VariableArrayType* VAPtr = getVAPtr()) {
+ assert (VAPtr->SizeExpr);
+ return VAPtr->SizeExpr;
+ }
+
+ assert (inDecl() || inDeclGroup());
+
+ if (inDeclGroup()) {
+ VarDecl* VD = cast<VarDecl>(*DGI);
+ return *VD->getInitAddress();
+ }
+
+ assert (inDecl());
+
+ if (VarDecl* VD = dyn_cast<VarDecl>(decl)) {
+ assert (VD->Init);
+ return *VD->getInitAddress();
+ }
+
+ EnumConstantDecl* ECD = cast<EnumConstantDecl>(decl);
+ return ECD->Init;
+}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
new file mode 100644
index 000000000000..710da6386133
--- /dev/null
+++ b/lib/AST/StmtPrinter.cpp
@@ -0,0 +1,1239 @@
+//===--- StmtPrinter.cpp - Printing implementation for Stmt ASTs ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Stmt::dumpPretty/Stmt::printPretty methods, which
+// pretty print the AST back out to C code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/Format.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// StmtPrinter Visitor
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor<StmtPrinter> {
+ llvm::raw_ostream &OS;
+ ASTContext &Context;
+ unsigned IndentLevel;
+ clang::PrinterHelper* Helper;
+ PrintingPolicy Policy;
+
+ public:
+ StmtPrinter(llvm::raw_ostream &os, ASTContext &C, PrinterHelper* helper,
+ const PrintingPolicy &Policy = PrintingPolicy(),
+ unsigned Indentation = 0)
+ : OS(os), Context(C), IndentLevel(Indentation), Helper(helper),
+ Policy(Policy) {}
+
+ void PrintStmt(Stmt *S) {
+ PrintStmt(S, Policy.Indentation);
+ }
+
+ void PrintStmt(Stmt *S, int SubIndent) {
+ IndentLevel += SubIndent;
+ if (S && isa<Expr>(S)) {
+ // If this is an expr used in a stmt context, indent and newline it.
+ Indent();
+ Visit(S);
+ OS << ";\n";
+ } else if (S) {
+ Visit(S);
+ } else {
+ Indent() << "<<<NULL STATEMENT>>>\n";
+ }
+ IndentLevel -= SubIndent;
+ }
+
+ void PrintRawCompoundStmt(CompoundStmt *S);
+ void PrintRawDecl(Decl *D);
+ void PrintRawDeclStmt(DeclStmt *S);
+ void PrintRawIfStmt(IfStmt *If);
+ void PrintRawCXXCatchStmt(CXXCatchStmt *Catch);
+
+ void PrintExpr(Expr *E) {
+ if (E)
+ Visit(E);
+ else
+ OS << "<null expr>";
+ }
+
+ llvm::raw_ostream &Indent(int Delta = 0) {
+ for (int i = 0, e = IndentLevel+Delta; i < e; ++i)
+ OS << " ";
+ return OS;
+ }
+
+ bool PrintOffsetOfDesignator(Expr *E);
+ void VisitUnaryOffsetOf(UnaryOperator *Node);
+
+ void Visit(Stmt* S) {
+ if (Helper && Helper->handledStmt(S,OS))
+ return;
+ else StmtVisitor<StmtPrinter>::Visit(S);
+ }
+
+ void VisitStmt(Stmt *Node);
+#define STMT(CLASS, PARENT) \
+ void Visit##CLASS(CLASS *Node);
+#include "clang/AST/StmtNodes.def"
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// Stmt printing methods.
+//===----------------------------------------------------------------------===//
+
+void StmtPrinter::VisitStmt(Stmt *Node) {
+ Indent() << "<<unknown stmt type>>\n";
+}
+
+/// PrintRawCompoundStmt - Print a compound stmt without indenting the {, and
+/// with no newline after the }.
+void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) {
+ OS << "{\n";
+ for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end();
+ I != E; ++I)
+ PrintStmt(*I);
+
+ Indent() << "}";
+}
+
+void StmtPrinter::PrintRawDecl(Decl *D) {
+ D->print(OS, Context, Policy, IndentLevel);
+}
+
+void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) {
+ DeclStmt::decl_iterator Begin = S->decl_begin(), End = S->decl_end();
+ llvm::SmallVector<Decl*, 2> Decls;
+ for ( ; Begin != End; ++Begin)
+ Decls.push_back(*Begin);
+
+ Decl::printGroup(Decls.data(), Decls.size(), OS, Context, Policy,
+ IndentLevel);
+}
+
+void StmtPrinter::VisitNullStmt(NullStmt *Node) {
+ Indent() << ";\n";
+}
+
+void StmtPrinter::VisitDeclStmt(DeclStmt *Node) {
+ Indent();
+ PrintRawDeclStmt(Node);
+ OS << ";\n";
+}
+
+void StmtPrinter::VisitCompoundStmt(CompoundStmt *Node) {
+ Indent();
+ PrintRawCompoundStmt(Node);
+ OS << "\n";
+}
+
+void StmtPrinter::VisitCaseStmt(CaseStmt *Node) {
+ Indent(-1) << "case ";
+ PrintExpr(Node->getLHS());
+ if (Node->getRHS()) {
+ OS << " ... ";
+ PrintExpr(Node->getRHS());
+ }
+ OS << ":\n";
+
+ PrintStmt(Node->getSubStmt(), 0);
+}
+
+void StmtPrinter::VisitDefaultStmt(DefaultStmt *Node) {
+ Indent(-1) << "default:\n";
+ PrintStmt(Node->getSubStmt(), 0);
+}
+
+void StmtPrinter::VisitLabelStmt(LabelStmt *Node) {
+ Indent(-1) << Node->getName() << ":\n";
+ PrintStmt(Node->getSubStmt(), 0);
+}
+
+void StmtPrinter::PrintRawIfStmt(IfStmt *If) {
+ OS << "if (";
+ PrintExpr(If->getCond());
+ OS << ')';
+
+ if (CompoundStmt *CS = dyn_cast<CompoundStmt>(If->getThen())) {
+ OS << ' ';
+ PrintRawCompoundStmt(CS);
+ OS << (If->getElse() ? ' ' : '\n');
+ } else {
+ OS << '\n';
+ PrintStmt(If->getThen());
+ if (If->getElse()) Indent();
+ }
+
+ if (Stmt *Else = If->getElse()) {
+ OS << "else";
+
+ if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Else)) {
+ OS << ' ';
+ PrintRawCompoundStmt(CS);
+ OS << '\n';
+ } else if (IfStmt *ElseIf = dyn_cast<IfStmt>(Else)) {
+ OS << ' ';
+ PrintRawIfStmt(ElseIf);
+ } else {
+ OS << '\n';
+ PrintStmt(If->getElse());
+ }
+ }
+}
+
+void StmtPrinter::VisitIfStmt(IfStmt *If) {
+ Indent();
+ PrintRawIfStmt(If);
+}
+
+void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) {
+ Indent() << "switch (";
+ PrintExpr(Node->getCond());
+ OS << ")";
+
+ // Pretty print compoundstmt bodies (very common).
+ if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
+ OS << " ";
+ PrintRawCompoundStmt(CS);
+ OS << "\n";
+ } else {
+ OS << "\n";
+ PrintStmt(Node->getBody());
+ }
+}
+
+void StmtPrinter::VisitSwitchCase(SwitchCase*) {
+ assert(0 && "SwitchCase is an abstract class");
+}
+
+void StmtPrinter::VisitWhileStmt(WhileStmt *Node) {
+ Indent() << "while (";
+ PrintExpr(Node->getCond());
+ OS << ")\n";
+ PrintStmt(Node->getBody());
+}
+
+void StmtPrinter::VisitDoStmt(DoStmt *Node) {
+ Indent() << "do ";
+ if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
+ PrintRawCompoundStmt(CS);
+ OS << " ";
+ } else {
+ OS << "\n";
+ PrintStmt(Node->getBody());
+ Indent();
+ }
+
+ OS << "while (";
+ PrintExpr(Node->getCond());
+ OS << ");\n";
+}
+
+void StmtPrinter::VisitForStmt(ForStmt *Node) {
+ Indent() << "for (";
+ if (Node->getInit()) {
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(Node->getInit()))
+ PrintRawDeclStmt(DS);
+ else
+ PrintExpr(cast<Expr>(Node->getInit()));
+ }
+ OS << ";";
+ if (Node->getCond()) {
+ OS << " ";
+ PrintExpr(Node->getCond());
+ }
+ OS << ";";
+ if (Node->getInc()) {
+ OS << " ";
+ PrintExpr(Node->getInc());
+ }
+ OS << ") ";
+
+ if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
+ PrintRawCompoundStmt(CS);
+ OS << "\n";
+ } else {
+ OS << "\n";
+ PrintStmt(Node->getBody());
+ }
+}
+
+void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) {
+ Indent() << "for (";
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(Node->getElement()))
+ PrintRawDeclStmt(DS);
+ else
+ PrintExpr(cast<Expr>(Node->getElement()));
+ OS << " in ";
+ PrintExpr(Node->getCollection());
+ OS << ") ";
+
+ if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) {
+ PrintRawCompoundStmt(CS);
+ OS << "\n";
+ } else {
+ OS << "\n";
+ PrintStmt(Node->getBody());
+ }
+}
+
+void StmtPrinter::VisitGotoStmt(GotoStmt *Node) {
+ Indent() << "goto " << Node->getLabel()->getName() << ";\n";
+}
+
+void StmtPrinter::VisitIndirectGotoStmt(IndirectGotoStmt *Node) {
+ Indent() << "goto *";
+ PrintExpr(Node->getTarget());
+ OS << ";\n";
+}
+
+void StmtPrinter::VisitContinueStmt(ContinueStmt *Node) {
+ Indent() << "continue;\n";
+}
+
+void StmtPrinter::VisitBreakStmt(BreakStmt *Node) {
+ Indent() << "break;\n";
+}
+
+
+void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) {
+ Indent() << "return";
+ if (Node->getRetValue()) {
+ OS << " ";
+ PrintExpr(Node->getRetValue());
+ }
+ OS << ";\n";
+}
+
+
+void StmtPrinter::VisitAsmStmt(AsmStmt *Node) {
+ Indent() << "asm ";
+
+ if (Node->isVolatile())
+ OS << "volatile ";
+
+ OS << "(";
+ VisitStringLiteral(Node->getAsmString());
+
+ // Outputs
+ if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 ||
+ Node->getNumClobbers() != 0)
+ OS << " : ";
+
+ for (unsigned i = 0, e = Node->getNumOutputs(); i != e; ++i) {
+ if (i != 0)
+ OS << ", ";
+
+ if (!Node->getOutputName(i).empty()) {
+ OS << '[';
+ OS << Node->getOutputName(i);
+ OS << "] ";
+ }
+
+ VisitStringLiteral(Node->getOutputConstraintLiteral(i));
+ OS << " ";
+ Visit(Node->getOutputExpr(i));
+ }
+
+ // Inputs
+ if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0)
+ OS << " : ";
+
+ for (unsigned i = 0, e = Node->getNumInputs(); i != e; ++i) {
+ if (i != 0)
+ OS << ", ";
+
+ if (!Node->getInputName(i).empty()) {
+ OS << '[';
+ OS << Node->getInputName(i);
+ OS << "] ";
+ }
+
+ VisitStringLiteral(Node->getInputConstraintLiteral(i));
+ OS << " ";
+ Visit(Node->getInputExpr(i));
+ }
+
+ // Clobbers
+ if (Node->getNumClobbers() != 0)
+ OS << " : ";
+
+ for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) {
+ if (i != 0)
+ OS << ", ";
+
+ VisitStringLiteral(Node->getClobber(i));
+ }
+
+ OS << ");\n";
+}
+
+void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) {
+ Indent() << "@try";
+ if (CompoundStmt *TS = dyn_cast<CompoundStmt>(Node->getTryBody())) {
+ PrintRawCompoundStmt(TS);
+ OS << "\n";
+ }
+
+ for (ObjCAtCatchStmt *catchStmt =
+ static_cast<ObjCAtCatchStmt *>(Node->getCatchStmts());
+ catchStmt;
+ catchStmt =
+ static_cast<ObjCAtCatchStmt *>(catchStmt->getNextCatchStmt())) {
+ Indent() << "@catch(";
+ if (catchStmt->getCatchParamDecl()) {
+ if (Decl *DS = catchStmt->getCatchParamDecl())
+ PrintRawDecl(DS);
+ }
+ OS << ")";
+ if (CompoundStmt *CS = dyn_cast<CompoundStmt>(catchStmt->getCatchBody()))
+ {
+ PrintRawCompoundStmt(CS);
+ OS << "\n";
+ }
+ }
+
+ if (ObjCAtFinallyStmt *FS =static_cast<ObjCAtFinallyStmt *>(
+ Node->getFinallyStmt())) {
+ Indent() << "@finally";
+ PrintRawCompoundStmt(dyn_cast<CompoundStmt>(FS->getFinallyBody()));
+ OS << "\n";
+ }
+}
+
+void StmtPrinter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *Node) {
+}
+
+void StmtPrinter::VisitObjCAtCatchStmt (ObjCAtCatchStmt *Node) {
+ Indent() << "@catch (...) { /* todo */ } \n";
+}
+
+void StmtPrinter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *Node) {
+ Indent() << "@throw";
+ if (Node->getThrowExpr()) {
+ OS << " ";
+ PrintExpr(Node->getThrowExpr());
+ }
+ OS << ";\n";
+}
+
+void StmtPrinter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Node) {
+ Indent() << "@synchronized (";
+ PrintExpr(Node->getSynchExpr());
+ OS << ")";
+ PrintRawCompoundStmt(Node->getSynchBody());
+ OS << "\n";
+}
+
+void StmtPrinter::PrintRawCXXCatchStmt(CXXCatchStmt *Node) {
+ OS << "catch (";
+ if (Decl *ExDecl = Node->getExceptionDecl())
+ PrintRawDecl(ExDecl);
+ else
+ OS << "...";
+ OS << ") ";
+ PrintRawCompoundStmt(cast<CompoundStmt>(Node->getHandlerBlock()));
+}
+
+void StmtPrinter::VisitCXXCatchStmt(CXXCatchStmt *Node) {
+ Indent();
+ PrintRawCXXCatchStmt(Node);
+ OS << "\n";
+}
+
+void StmtPrinter::VisitCXXTryStmt(CXXTryStmt *Node) {
+ Indent() << "try ";
+ PrintRawCompoundStmt(Node->getTryBlock());
+ for(unsigned i = 0, e = Node->getNumHandlers(); i < e; ++i) {
+ OS << " ";
+ PrintRawCXXCatchStmt(Node->getHandler(i));
+ }
+ OS << "\n";
+}
+
+//===----------------------------------------------------------------------===//
+// Expr printing methods.
+//===----------------------------------------------------------------------===//
+
+void StmtPrinter::VisitExpr(Expr *Node) {
+ OS << "<<unknown expr type>>";
+}
+
+void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
+ OS << Node->getDecl()->getNameAsString();
+}
+
+void StmtPrinter::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *Node) {
+ NamedDecl *D = Node->getDecl();
+
+ Node->getQualifier()->print(OS, Policy);
+ OS << D->getNameAsString();
+}
+
+void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) {
+ Node->getQualifier()->print(OS, Policy);
+ OS << Node->getDeclName().getAsString();
+}
+
+void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
+ if (Node->getBase()) {
+ PrintExpr(Node->getBase());
+ OS << (Node->isArrow() ? "->" : ".");
+ }
+ OS << Node->getDecl()->getNameAsString();
+}
+
+void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
+ if (Node->getBase()) {
+ PrintExpr(Node->getBase());
+ OS << ".";
+ }
+ OS << Node->getProperty()->getNameAsCString();
+}
+
+void StmtPrinter::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) {
+ if (Node->getBase()) {
+ PrintExpr(Node->getBase());
+ OS << ".";
+ }
+ // FIXME: Setter/Getter names
+}
+
+void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
+ switch (Node->getIdentType()) {
+ default:
+ assert(0 && "unknown case");
+ case PredefinedExpr::Func:
+ OS << "__func__";
+ break;
+ case PredefinedExpr::Function:
+ OS << "__FUNCTION__";
+ break;
+ case PredefinedExpr::PrettyFunction:
+ OS << "__PRETTY_FUNCTION__";
+ break;
+ }
+}
+
+void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
+ unsigned value = Node->getValue();
+ if (Node->isWide())
+ OS << "L";
+ switch (value) {
+ case '\\':
+ OS << "'\\\\'";
+ break;
+ case '\'':
+ OS << "'\\''";
+ break;
+ case '\a':
+ // TODO: K&R: the meaning of '\\a' is different in traditional C
+ OS << "'\\a'";
+ break;
+ case '\b':
+ OS << "'\\b'";
+ break;
+ // Nonstandard escape sequence.
+ /*case '\e':
+ OS << "'\\e'";
+ break;*/
+ case '\f':
+ OS << "'\\f'";
+ break;
+ case '\n':
+ OS << "'\\n'";
+ break;
+ case '\r':
+ OS << "'\\r'";
+ break;
+ case '\t':
+ OS << "'\\t'";
+ break;
+ case '\v':
+ OS << "'\\v'";
+ break;
+ default:
+ if (value < 256 && isprint(value)) {
+ OS << "'" << (char)value << "'";
+ } else if (value < 256) {
+ OS << "'\\x" << llvm::format("%x", value) << "'";
+ } else {
+ // FIXME what to really do here?
+ OS << value;
+ }
+ }
+}
+
+void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
+ bool isSigned = Node->getType()->isSignedIntegerType();
+ OS << Node->getValue().toString(10, isSigned);
+
+ // Emit suffixes. Integer literals are always a builtin integer type.
+ switch (Node->getType()->getAsBuiltinType()->getKind()) {
+ default: assert(0 && "Unexpected type for integer literal!");
+ case BuiltinType::Int: break; // no suffix.
+ case BuiltinType::UInt: OS << 'U'; break;
+ case BuiltinType::Long: OS << 'L'; break;
+ case BuiltinType::ULong: OS << "UL"; break;
+ case BuiltinType::LongLong: OS << "LL"; break;
+ case BuiltinType::ULongLong: OS << "ULL"; break;
+ }
+}
+void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) {
+ // FIXME: print value more precisely.
+ OS << Node->getValueAsApproximateDouble();
+}
+
+void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) {
+ PrintExpr(Node->getSubExpr());
+ OS << "i";
+}
+
+void StmtPrinter::VisitStringLiteral(StringLiteral *Str) {
+ if (Str->isWide()) OS << 'L';
+ OS << '"';
+
+ // FIXME: this doesn't print wstrings right.
+ for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) {
+ unsigned char Char = Str->getStrData()[i];
+
+ switch (Char) {
+ default:
+ if (isprint(Char))
+ OS << (char)Char;
+ else // Output anything hard as an octal escape.
+ OS << '\\'
+ << (char)('0'+ ((Char >> 6) & 7))
+ << (char)('0'+ ((Char >> 3) & 7))
+ << (char)('0'+ ((Char >> 0) & 7));
+ break;
+ // Handle some common non-printable cases to make dumps prettier.
+ case '\\': OS << "\\\\"; break;
+ case '"': OS << "\\\""; break;
+ case '\n': OS << "\\n"; break;
+ case '\t': OS << "\\t"; break;
+ case '\a': OS << "\\a"; break;
+ case '\b': OS << "\\b"; break;
+ }
+ }
+ OS << '"';
+}
+void StmtPrinter::VisitParenExpr(ParenExpr *Node) {
+ OS << "(";
+ PrintExpr(Node->getSubExpr());
+ OS << ")";
+}
+void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) {
+ if (!Node->isPostfix()) {
+ OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
+
+ // Print a space if this is an "identifier operator" like __real.
+ switch (Node->getOpcode()) {
+ default: break;
+ case UnaryOperator::Real:
+ case UnaryOperator::Imag:
+ case UnaryOperator::Extension:
+ OS << ' ';
+ break;
+ }
+ }
+ PrintExpr(Node->getSubExpr());
+
+ if (Node->isPostfix())
+ OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
+}
+
+bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) {
+ if (isa<UnaryOperator>(E)) {
+ // Base case, print the type and comma.
+ OS << E->getType().getAsString() << ", ";
+ return true;
+ } else if (ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
+ PrintOffsetOfDesignator(ASE->getLHS());
+ OS << "[";
+ PrintExpr(ASE->getRHS());
+ OS << "]";
+ return false;
+ } else {
+ MemberExpr *ME = cast<MemberExpr>(E);
+ bool IsFirst = PrintOffsetOfDesignator(ME->getBase());
+ OS << (IsFirst ? "" : ".") << ME->getMemberDecl()->getNameAsString();
+ return false;
+ }
+}
+
+void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) {
+ OS << "__builtin_offsetof(";
+ PrintOffsetOfDesignator(Node->getSubExpr());
+ OS << ")";
+}
+
+void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
+ OS << (Node->isSizeOf() ? "sizeof" : "__alignof");
+ if (Node->isArgumentType())
+ OS << "(" << Node->getArgumentType().getAsString() << ")";
+ else {
+ OS << " ";
+ PrintExpr(Node->getArgumentExpr());
+ }
+}
+void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
+ PrintExpr(Node->getLHS());
+ OS << "[";
+ PrintExpr(Node->getRHS());
+ OS << "]";
+}
+
+void StmtPrinter::VisitCallExpr(CallExpr *Call) {
+ PrintExpr(Call->getCallee());
+ OS << "(";
+ for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) {
+ if (isa<CXXDefaultArgExpr>(Call->getArg(i))) {
+ // Don't print any defaulted arguments
+ break;
+ }
+
+ if (i) OS << ", ";
+ PrintExpr(Call->getArg(i));
+ }
+ OS << ")";
+}
+void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
+ // FIXME: Suppress printing implicit bases (like "this")
+ PrintExpr(Node->getBase());
+ OS << (Node->isArrow() ? "->" : ".");
+ // FIXME: Suppress printing references to unnamed objects
+ // representing anonymous unions/structs
+ OS << Node->getMemberDecl()->getNameAsString();
+}
+void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
+ PrintExpr(Node->getBase());
+ OS << ".";
+ OS << Node->getAccessor().getName();
+}
+void StmtPrinter::VisitCastExpr(CastExpr *) {
+ assert(0 && "CastExpr is an abstract class");
+}
+void StmtPrinter::VisitExplicitCastExpr(ExplicitCastExpr *) {
+ assert(0 && "ExplicitCastExpr is an abstract class");
+}
+void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) {
+ OS << "(" << Node->getType().getAsString() << ")";
+ PrintExpr(Node->getSubExpr());
+}
+void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) {
+ OS << "(" << Node->getType().getAsString() << ")";
+ PrintExpr(Node->getInitializer());
+}
+void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
+ // No need to print anything, simply forward to the sub expression.
+ PrintExpr(Node->getSubExpr());
+}
+void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) {
+ PrintExpr(Node->getLHS());
+ OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " ";
+ PrintExpr(Node->getRHS());
+}
+void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
+ PrintExpr(Node->getLHS());
+ OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " ";
+ PrintExpr(Node->getRHS());
+}
+void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) {
+ PrintExpr(Node->getCond());
+
+ if (Node->getLHS()) {
+ OS << " ? ";
+ PrintExpr(Node->getLHS());
+ OS << " : ";
+ }
+ else { // Handle GCC extension where LHS can be NULL.
+ OS << " ?: ";
+ }
+
+ PrintExpr(Node->getRHS());
+}
+
+// GNU extensions.
+
+void StmtPrinter::VisitAddrLabelExpr(AddrLabelExpr *Node) {
+ OS << "&&" << Node->getLabel()->getName();
+}
+
+void StmtPrinter::VisitStmtExpr(StmtExpr *E) {
+ OS << "(";
+ PrintRawCompoundStmt(E->getSubStmt());
+ OS << ")";
+}
+
+void StmtPrinter::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
+ OS << "__builtin_types_compatible_p(";
+ OS << Node->getArgType1().getAsString() << ",";
+ OS << Node->getArgType2().getAsString() << ")";
+}
+
+void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) {
+ OS << "__builtin_choose_expr(";
+ PrintExpr(Node->getCond());
+ OS << ", ";
+ PrintExpr(Node->getLHS());
+ OS << ", ";
+ PrintExpr(Node->getRHS());
+ OS << ")";
+}
+
+void StmtPrinter::VisitGNUNullExpr(GNUNullExpr *) {
+ OS << "__null";
+}
+
+void StmtPrinter::VisitShuffleVectorExpr(ShuffleVectorExpr *Node) {
+ OS << "__builtin_shufflevector(";
+ for (unsigned i = 0, e = Node->getNumSubExprs(); i != e; ++i) {
+ if (i) OS << ", ";
+ PrintExpr(Node->getExpr(i));
+ }
+ OS << ")";
+}
+
+void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
+ if (Node->getSyntacticForm()) {
+ Visit(Node->getSyntacticForm());
+ return;
+ }
+
+ OS << "{ ";
+ for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) {
+ if (i) OS << ", ";
+ if (Node->getInit(i))
+ PrintExpr(Node->getInit(i));
+ else
+ OS << "0";
+ }
+ OS << " }";
+}
+
+void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
+ for (DesignatedInitExpr::designators_iterator D = Node->designators_begin(),
+ DEnd = Node->designators_end();
+ D != DEnd; ++D) {
+ if (D->isFieldDesignator()) {
+ if (D->getDotLoc().isInvalid())
+ OS << D->getFieldName()->getName() << ":";
+ else
+ OS << "." << D->getFieldName()->getName();
+ } else {
+ OS << "[";
+ if (D->isArrayDesignator()) {
+ PrintExpr(Node->getArrayIndex(*D));
+ } else {
+ PrintExpr(Node->getArrayRangeStart(*D));
+ OS << " ... ";
+ PrintExpr(Node->getArrayRangeEnd(*D));
+ }
+ OS << "]";
+ }
+ }
+
+ OS << " = ";
+ PrintExpr(Node->getInit());
+}
+
+void StmtPrinter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *Node) {
+ if (Policy.CPlusPlus)
+ OS << "/*implicit*/" << Node->getType().getAsString(Policy) << "()";
+ else {
+ OS << "/*implicit*/(" << Node->getType().getAsString(Policy) << ")";
+ if (Node->getType()->isRecordType())
+ OS << "{}";
+ else
+ OS << 0;
+ }
+}
+
+void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
+ OS << "__builtin_va_arg(";
+ PrintExpr(Node->getSubExpr());
+ OS << ", ";
+ OS << Node->getType().getAsString();
+ OS << ")";
+}
+
+// C++
+void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) {
+ const char *OpStrings[NUM_OVERLOADED_OPERATORS] = {
+ "",
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ Spelling,
+#include "clang/Basic/OperatorKinds.def"
+ };
+
+ OverloadedOperatorKind Kind = Node->getOperator();
+ if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) {
+ if (Node->getNumArgs() == 1) {
+ OS << OpStrings[Kind] << ' ';
+ PrintExpr(Node->getArg(0));
+ } else {
+ PrintExpr(Node->getArg(0));
+ OS << ' ' << OpStrings[Kind];
+ }
+ } else if (Kind == OO_Call) {
+ PrintExpr(Node->getArg(0));
+ OS << '(';
+ for (unsigned ArgIdx = 1; ArgIdx < Node->getNumArgs(); ++ArgIdx) {
+ if (ArgIdx > 1)
+ OS << ", ";
+ if (!isa<CXXDefaultArgExpr>(Node->getArg(ArgIdx)))
+ PrintExpr(Node->getArg(ArgIdx));
+ }
+ OS << ')';
+ } else if (Kind == OO_Subscript) {
+ PrintExpr(Node->getArg(0));
+ OS << '[';
+ PrintExpr(Node->getArg(1));
+ OS << ']';
+ } else if (Node->getNumArgs() == 1) {
+ OS << OpStrings[Kind] << ' ';
+ PrintExpr(Node->getArg(0));
+ } else if (Node->getNumArgs() == 2) {
+ PrintExpr(Node->getArg(0));
+ OS << ' ' << OpStrings[Kind] << ' ';
+ PrintExpr(Node->getArg(1));
+ } else {
+ assert(false && "unknown overloaded operator");
+ }
+}
+
+void StmtPrinter::VisitCXXMemberCallExpr(CXXMemberCallExpr *Node) {
+ VisitCallExpr(cast<CallExpr>(Node));
+}
+
+void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
+ OS << Node->getCastName() << '<';
+ OS << Node->getTypeAsWritten().getAsString() << ">(";
+ PrintExpr(Node->getSubExpr());
+ OS << ")";
+}
+
+void StmtPrinter::VisitCXXStaticCastExpr(CXXStaticCastExpr *Node) {
+ VisitCXXNamedCastExpr(Node);
+}
+
+void StmtPrinter::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *Node) {
+ VisitCXXNamedCastExpr(Node);
+}
+
+void StmtPrinter::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *Node) {
+ VisitCXXNamedCastExpr(Node);
+}
+
+void StmtPrinter::VisitCXXConstCastExpr(CXXConstCastExpr *Node) {
+ VisitCXXNamedCastExpr(Node);
+}
+
+void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
+ OS << "typeid(";
+ if (Node->isTypeOperand()) {
+ OS << Node->getTypeOperand().getAsString();
+ } else {
+ PrintExpr(Node->getExprOperand());
+ }
+ OS << ")";
+}
+
+void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
+ OS << (Node->getValue() ? "true" : "false");
+}
+
+void StmtPrinter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *Node) {
+ OS << "nullptr";
+}
+
+void StmtPrinter::VisitCXXThisExpr(CXXThisExpr *Node) {
+ OS << "this";
+}
+
+void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) {
+ if (Node->getSubExpr() == 0)
+ OS << "throw";
+ else {
+ OS << "throw ";
+ PrintExpr(Node->getSubExpr());
+ }
+}
+
+void StmtPrinter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) {
+ // Nothing to print: we picked up the default argument
+}
+
+void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
+ OS << Node->getType().getAsString();
+ OS << "(";
+ PrintExpr(Node->getSubExpr());
+ OS << ")";
+}
+
+void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
+ PrintExpr(Node->getSubExpr());
+}
+
+void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
+ OS << Node->getType().getAsString();
+ OS << "(";
+ for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(),
+ ArgEnd = Node->arg_end();
+ Arg != ArgEnd; ++Arg) {
+ if (Arg != Node->arg_begin())
+ OS << ", ";
+ PrintExpr(*Arg);
+ }
+ OS << ")";
+}
+
+void StmtPrinter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *Node) {
+ OS << Node->getType().getAsString() << "()";
+}
+
+void
+StmtPrinter::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *E) {
+ PrintRawDecl(E->getVarDecl());
+}
+
+void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
+ if (E->isGlobalNew())
+ OS << "::";
+ OS << "new ";
+ unsigned NumPlace = E->getNumPlacementArgs();
+ if (NumPlace > 0) {
+ OS << "(";
+ PrintExpr(E->getPlacementArg(0));
+ for (unsigned i = 1; i < NumPlace; ++i) {
+ OS << ", ";
+ PrintExpr(E->getPlacementArg(i));
+ }
+ OS << ") ";
+ }
+ if (E->isParenTypeId())
+ OS << "(";
+ std::string TypeS;
+ if (Expr *Size = E->getArraySize()) {
+ llvm::raw_string_ostream s(TypeS);
+ Size->printPretty(s, Context, Helper, Policy);
+ s.flush();
+ TypeS = "[" + TypeS + "]";
+ }
+ E->getAllocatedType().getAsStringInternal(TypeS, Policy);
+ OS << TypeS;
+ if (E->isParenTypeId())
+ OS << ")";
+
+ if (E->hasInitializer()) {
+ OS << "(";
+ unsigned NumCons = E->getNumConstructorArgs();
+ if (NumCons > 0) {
+ PrintExpr(E->getConstructorArg(0));
+ for (unsigned i = 1; i < NumCons; ++i) {
+ OS << ", ";
+ PrintExpr(E->getConstructorArg(i));
+ }
+ }
+ OS << ")";
+ }
+}
+
+void StmtPrinter::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
+ if (E->isGlobalDelete())
+ OS << "::";
+ OS << "delete ";
+ if (E->isArrayForm())
+ OS << "[] ";
+ PrintExpr(E->getArgument());
+}
+
+void StmtPrinter::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *E) {
+ OS << E->getName().getAsString();
+}
+
+void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ // Nothing to print.
+}
+
+void StmtPrinter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
+ // Just forward to the sub expression.
+ PrintExpr(E->getSubExpr());
+}
+
+void
+StmtPrinter::VisitCXXUnresolvedConstructExpr(
+ CXXUnresolvedConstructExpr *Node) {
+ OS << Node->getTypeAsWritten().getAsString();
+ OS << "(";
+ for (CXXUnresolvedConstructExpr::arg_iterator Arg = Node->arg_begin(),
+ ArgEnd = Node->arg_end();
+ Arg != ArgEnd; ++Arg) {
+ if (Arg != Node->arg_begin())
+ OS << ", ";
+ PrintExpr(*Arg);
+ }
+ OS << ")";
+}
+
+void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) {
+ PrintExpr(Node->getBase());
+ OS << (Node->isArrow() ? "->" : ".");
+ OS << Node->getMember().getAsString();
+}
+
+static const char *getTypeTraitName(UnaryTypeTrait UTT) {
+ switch (UTT) {
+ default: assert(false && "Unknown type trait");
+ case UTT_HasNothrowAssign: return "__has_nothrow_assign";
+ case UTT_HasNothrowCopy: return "__has_nothrow_copy";
+ case UTT_HasNothrowConstructor: return "__has_nothrow_constructor";
+ case UTT_HasTrivialAssign: return "__has_trivial_assign";
+ case UTT_HasTrivialCopy: return "__has_trivial_copy";
+ case UTT_HasTrivialConstructor: return "__has_trivial_constructor";
+ case UTT_HasTrivialDestructor: return "__has_trivial_destructor";
+ case UTT_HasVirtualDestructor: return "__has_virtual_destructor";
+ case UTT_IsAbstract: return "__is_abstract";
+ case UTT_IsClass: return "__is_class";
+ case UTT_IsEmpty: return "__is_empty";
+ case UTT_IsEnum: return "__is_enum";
+ case UTT_IsPOD: return "__is_pod";
+ case UTT_IsPolymorphic: return "__is_polymorphic";
+ case UTT_IsUnion: return "__is_union";
+ }
+}
+
+void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
+ OS << getTypeTraitName(E->getTrait()) << "("
+ << E->getQueriedType().getAsString() << ")";
+}
+
+// Obj-C
+
+void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
+ OS << "@";
+ VisitStringLiteral(Node->getString());
+}
+
+void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
+ OS << "@encode(" << Node->getEncodedType().getAsString() << ')';
+}
+
+void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
+ OS << "@selector(" << Node->getSelector().getAsString() << ')';
+}
+
+void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
+ OS << "@protocol(" << Node->getProtocol()->getNameAsString() << ')';
+}
+
+void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
+ OS << "[";
+ Expr *receiver = Mess->getReceiver();
+ if (receiver) PrintExpr(receiver);
+ else OS << Mess->getClassName()->getName();
+ OS << ' ';
+ Selector selector = Mess->getSelector();
+ if (selector.isUnarySelector()) {
+ OS << selector.getIdentifierInfoForSlot(0)->getName();
+ } else {
+ for (unsigned i = 0, e = Mess->getNumArgs(); i != e; ++i) {
+ if (i < selector.getNumArgs()) {
+ if (i > 0) OS << ' ';
+ if (selector.getIdentifierInfoForSlot(i))
+ OS << selector.getIdentifierInfoForSlot(i)->getName() << ':';
+ else
+ OS << ":";
+ }
+ else OS << ", "; // Handle variadic methods.
+
+ PrintExpr(Mess->getArg(i));
+ }
+ }
+ OS << "]";
+}
+
+void StmtPrinter::VisitObjCSuperExpr(ObjCSuperExpr *) {
+ OS << "super";
+}
+
+void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
+ BlockDecl *BD = Node->getBlockDecl();
+ OS << "^";
+
+ const FunctionType *AFT = Node->getFunctionType();
+
+ if (isa<FunctionNoProtoType>(AFT)) {
+ OS << "()";
+ } else if (!BD->param_empty() || cast<FunctionProtoType>(AFT)->isVariadic()) {
+ OS << '(';
+ std::string ParamStr;
+ for (BlockDecl::param_iterator AI = BD->param_begin(),
+ E = BD->param_end(); AI != E; ++AI) {
+ if (AI != BD->param_begin()) OS << ", ";
+ ParamStr = (*AI)->getNameAsString();
+ (*AI)->getType().getAsStringInternal(ParamStr, Policy);
+ OS << ParamStr;
+ }
+
+ const FunctionProtoType *FT = cast<FunctionProtoType>(AFT);
+ if (FT->isVariadic()) {
+ if (!BD->param_empty()) OS << ", ";
+ OS << "...";
+ }
+ OS << ')';
+ }
+}
+
+void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) {
+ OS << Node->getDecl()->getNameAsString();
+}
+//===----------------------------------------------------------------------===//
+// Stmt method implementations
+//===----------------------------------------------------------------------===//
+
+void Stmt::dumpPretty(ASTContext& Context) const {
+ printPretty(llvm::errs(), Context, 0, PrintingPolicy());
+}
+
+void Stmt::printPretty(llvm::raw_ostream &OS, ASTContext& Context,
+ PrinterHelper* Helper,
+ const PrintingPolicy &Policy,
+ unsigned Indentation) const {
+ if (this == 0) {
+ OS << "<NULL>";
+ return;
+ }
+
+ if (Policy.Dump) {
+ dump();
+ return;
+ }
+
+ StmtPrinter P(OS, Context, Helper, Policy, Indentation);
+ P.Visit(const_cast<Stmt*>(this));
+}
+
+//===----------------------------------------------------------------------===//
+// PrinterHelper
+//===----------------------------------------------------------------------===//
+
+// Implement virtual destructor.
+PrinterHelper::~PrinterHelper() {}
diff --git a/lib/AST/StmtViz.cpp b/lib/AST/StmtViz.cpp
new file mode 100644
index 000000000000..1316d3551d91
--- /dev/null
+++ b/lib/AST/StmtViz.cpp
@@ -0,0 +1,61 @@
+//===--- StmtViz.cpp - Graphviz visualization for Stmt ASTs -----*- 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 Stmt::viewAST, which generates a Graphviz DOT file
+// that depicts the AST and then calls Graphviz/dot+gv on it.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/StmtGraphTraits.h"
+#include "clang/AST/Decl.h"
+#include "llvm/Support/GraphWriter.h"
+#include <sstream>
+
+using namespace clang;
+
+void Stmt::viewAST() const {
+#ifndef NDEBUG
+ llvm::ViewGraph(this,"AST");
+#else
+ llvm::cerr << "Stmt::viewAST is only available in debug builds on "
+ << "systems with Graphviz or gv!\n";
+#endif
+}
+
+namespace llvm {
+template<>
+struct DOTGraphTraits<const Stmt*> : public DefaultDOTGraphTraits {
+ static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph) {
+
+#ifndef NDEBUG
+ std::string OutSStr;
+ llvm::raw_string_ostream Out(OutSStr);
+
+ if (Node)
+ Out << Node->getStmtClassName();
+ else
+ Out << "<NULL>";
+
+ std::string OutStr = Out.str();
+ if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
+
+ // Process string output to make it nicer...
+ for (unsigned i = 0; i != OutStr.length(); ++i)
+ if (OutStr[i] == '\n') { // Left justify
+ OutStr[i] = '\\';
+ OutStr.insert(OutStr.begin()+i+1, 'l');
+ }
+
+ return OutStr;
+#else
+ return "";
+#endif
+ }
+};
+} // end namespace llvm
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
new file mode 100644
index 000000000000..3613da77b342
--- /dev/null
+++ b/lib/AST/TemplateName.cpp
@@ -0,0 +1,65 @@
+//===--- TemplateName.h - C++ Template Name Representation-------*- 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 TemplateName interface and subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/TemplateName.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+TemplateDecl *TemplateName::getAsTemplateDecl() const {
+ if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
+ return Template;
+
+ if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName())
+ return QTN->getTemplateDecl();
+
+ return 0;
+}
+
+bool TemplateName::isDependent() const {
+ if (TemplateDecl *Template = getAsTemplateDecl()) {
+ // FIXME: We don't yet have a notion of dependent
+ // declarations. When we do, check that. This hack won't last
+ // long!.
+ return isa<TemplateTemplateParmDecl>(Template);
+ }
+
+ return true;
+}
+
+void
+TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
+ bool SuppressNNS) const {
+ if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
+ OS << Template->getIdentifier()->getName();
+ else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
+ if (!SuppressNNS)
+ QTN->getQualifier()->print(OS, Policy);
+ if (QTN->hasTemplateKeyword())
+ OS << "template ";
+ OS << QTN->getTemplateDecl()->getIdentifier()->getName();
+ } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
+ if (!SuppressNNS)
+ DTN->getQualifier()->print(OS, Policy);
+ OS << "template ";
+ OS << DTN->getName()->getName();
+ }
+}
+
+void TemplateName::dump() const {
+ PrintingPolicy Policy;
+ Policy.CPlusPlus = true;
+ print(llvm::errs(), Policy);
+}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
new file mode 100644
index 000000000000..b2ee58f3f355
--- /dev/null
+++ b/lib/AST/Type.cpp
@@ -0,0 +1,1658 @@
+//===--- Type.cpp - Type representation and manipulation ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements type-related functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+bool QualType::isConstant(ASTContext &Ctx) const {
+ if (isConstQualified())
+ return true;
+
+ if (getTypePtr()->isArrayType())
+ return Ctx.getAsArrayType(*this)->getElementType().isConstant(Ctx);
+
+ return false;
+}
+
+void Type::Destroy(ASTContext& C) {
+ this->~Type();
+ C.Deallocate(this);
+}
+
+void VariableArrayType::Destroy(ASTContext& C) {
+ if (SizeExpr)
+ SizeExpr->Destroy(C);
+ this->~VariableArrayType();
+ C.Deallocate(this);
+}
+
+void DependentSizedArrayType::Destroy(ASTContext& C) {
+ SizeExpr->Destroy(C);
+ this->~DependentSizedArrayType();
+ C.Deallocate(this);
+}
+
+/// getArrayElementTypeNoTypeQual - If this is an array type, return the
+/// element type of the array, potentially with type qualifiers missing.
+/// This method should never be used when type qualifiers are meaningful.
+const Type *Type::getArrayElementTypeNoTypeQual() const {
+ // If this is directly an array type, return it.
+ if (const ArrayType *ATy = dyn_cast<ArrayType>(this))
+ return ATy->getElementType().getTypePtr();
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<ArrayType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (ArrayType *AT = dyn_cast<ArrayType>(CanonicalType.getUnqualifiedType()))
+ return AT->getElementType().getTypePtr();
+ return 0;
+ }
+
+ // If this is a typedef for an array type, strip the typedef off without
+ // losing all typedef information.
+ return cast<ArrayType>(getDesugaredType())->getElementType().getTypePtr();
+}
+
+/// getDesugaredType - Return the specified type with any "sugar" removed from
+/// the type. This takes off typedefs, typeof's etc. If the outer level of
+/// the type is already concrete, it returns it unmodified. This is similar
+/// to getting the canonical type, but it doesn't remove *all* typedefs. For
+/// example, it returns "T*" as "T*", (not as "int*"), because the pointer is
+/// concrete.
+///
+/// \param ForDisplay When true, the desugaring is provided for
+/// display purposes only. In this case, we apply more heuristics to
+/// decide whether it is worth providing a desugared form of the type
+/// or not.
+QualType QualType::getDesugaredType(bool ForDisplay) const {
+ return getTypePtr()->getDesugaredType(ForDisplay)
+ .getWithAdditionalQualifiers(getCVRQualifiers());
+}
+
+/// getDesugaredType - Return the specified type with any "sugar" removed from
+/// type type. This takes off typedefs, typeof's etc. If the outer level of
+/// the type is already concrete, it returns it unmodified. This is similar
+/// to getting the canonical type, but it doesn't remove *all* typedefs. For
+/// example, it return "T*" as "T*", (not as "int*"), because the pointer is
+/// concrete.
+///
+/// \param ForDisplay When true, the desugaring is provided for
+/// display purposes only. In this case, we apply more heuristics to
+/// decide whether it is worth providing a desugared form of the type
+/// or not.
+QualType Type::getDesugaredType(bool ForDisplay) const {
+ if (const TypedefType *TDT = dyn_cast<TypedefType>(this))
+ return TDT->LookThroughTypedefs().getDesugaredType();
+ if (const TypeOfExprType *TOE = dyn_cast<TypeOfExprType>(this))
+ return TOE->getUnderlyingExpr()->getType().getDesugaredType();
+ if (const TypeOfType *TOT = dyn_cast<TypeOfType>(this))
+ return TOT->getUnderlyingType().getDesugaredType();
+ if (const TemplateSpecializationType *Spec
+ = dyn_cast<TemplateSpecializationType>(this)) {
+ if (ForDisplay)
+ return QualType(this, 0);
+
+ QualType Canon = Spec->getCanonicalTypeInternal();
+ if (Canon->getAsTemplateSpecializationType())
+ return QualType(this, 0);
+ return Canon->getDesugaredType();
+ }
+ if (const QualifiedNameType *QualName = dyn_cast<QualifiedNameType>(this)) {
+ if (ForDisplay) {
+ // If desugaring the type that the qualified name is referring to
+ // produces something interesting, that's our desugared type.
+ QualType NamedType = QualName->getNamedType().getDesugaredType();
+ if (NamedType != QualName->getNamedType())
+ return NamedType;
+ } else
+ return QualName->getNamedType().getDesugaredType();
+ }
+
+ return QualType(this, 0);
+}
+
+/// isVoidType - Helper method to determine if this is the 'void' type.
+bool Type::isVoidType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::Void;
+ if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType))
+ return AS->getBaseType()->isVoidType();
+ return false;
+}
+
+bool Type::isObjectType() const {
+ if (isa<FunctionType>(CanonicalType) || isa<ReferenceType>(CanonicalType) ||
+ isa<IncompleteArrayType>(CanonicalType) || isVoidType())
+ return false;
+ if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType))
+ return AS->getBaseType()->isObjectType();
+ return true;
+}
+
+bool Type::isDerivedType() const {
+ switch (CanonicalType->getTypeClass()) {
+ case ExtQual:
+ return cast<ExtQualType>(CanonicalType)->getBaseType()->isDerivedType();
+ case Pointer:
+ case VariableArray:
+ case ConstantArray:
+ case IncompleteArray:
+ case FunctionProto:
+ case FunctionNoProto:
+ case LValueReference:
+ case RValueReference:
+ case Record:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Type::isClassType() const {
+ if (const RecordType *RT = getAsRecordType())
+ return RT->getDecl()->isClass();
+ return false;
+}
+bool Type::isStructureType() const {
+ if (const RecordType *RT = getAsRecordType())
+ return RT->getDecl()->isStruct();
+ return false;
+}
+bool Type::isUnionType() const {
+ if (const RecordType *RT = getAsRecordType())
+ return RT->getDecl()->isUnion();
+ return false;
+}
+
+bool Type::isComplexType() const {
+ if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType))
+ return CT->getElementType()->isFloatingType();
+ if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType))
+ return AS->getBaseType()->isComplexType();
+ return false;
+}
+
+bool Type::isComplexIntegerType() const {
+ // Check for GCC complex integer extension.
+ if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType))
+ return CT->getElementType()->isIntegerType();
+ if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType))
+ return AS->getBaseType()->isComplexIntegerType();
+ return false;
+}
+
+const ComplexType *Type::getAsComplexIntegerType() const {
+ // Are we directly a complex type?
+ if (const ComplexType *CTy = dyn_cast<ComplexType>(this)) {
+ if (CTy->getElementType()->isIntegerType())
+ return CTy;
+ return 0;
+ }
+
+ // If the canonical form of this type isn't what we want, reject it.
+ if (!isa<ComplexType>(CanonicalType)) {
+ // Look through type qualifiers (e.g. ExtQualType's).
+ if (isa<ComplexType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsComplexIntegerType();
+ return 0;
+ }
+
+ // If this is a typedef for a complex type, strip the typedef off without
+ // losing all typedef information.
+ return cast<ComplexType>(getDesugaredType());
+}
+
+const BuiltinType *Type::getAsBuiltinType() const {
+ // If this is directly a builtin type, return it.
+ if (const BuiltinType *BTy = dyn_cast<BuiltinType>(this))
+ return BTy;
+
+ // If the canonical form of this type isn't a builtin type, reject it.
+ if (!isa<BuiltinType>(CanonicalType)) {
+ // Look through type qualifiers (e.g. ExtQualType's).
+ if (isa<BuiltinType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsBuiltinType();
+ return 0;
+ }
+
+ // If this is a typedef for a builtin type, strip the typedef off without
+ // losing all typedef information.
+ return cast<BuiltinType>(getDesugaredType());
+}
+
+const FunctionType *Type::getAsFunctionType() const {
+ // If this is directly a function type, return it.
+ if (const FunctionType *FTy = dyn_cast<FunctionType>(this))
+ return FTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<FunctionType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<FunctionType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsFunctionType();
+ return 0;
+ }
+
+ // If this is a typedef for a function type, strip the typedef off without
+ // losing all typedef information.
+ return cast<FunctionType>(getDesugaredType());
+}
+
+const FunctionNoProtoType *Type::getAsFunctionNoProtoType() const {
+ return dyn_cast_or_null<FunctionNoProtoType>(getAsFunctionType());
+}
+
+const FunctionProtoType *Type::getAsFunctionProtoType() const {
+ return dyn_cast_or_null<FunctionProtoType>(getAsFunctionType());
+}
+
+
+const PointerType *Type::getAsPointerType() const {
+ // If this is directly a pointer type, return it.
+ if (const PointerType *PTy = dyn_cast<PointerType>(this))
+ return PTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<PointerType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<PointerType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsPointerType();
+ return 0;
+ }
+
+ // If this is a typedef for a pointer type, strip the typedef off without
+ // losing all typedef information.
+ return cast<PointerType>(getDesugaredType());
+}
+
+const BlockPointerType *Type::getAsBlockPointerType() const {
+ // If this is directly a block pointer type, return it.
+ if (const BlockPointerType *PTy = dyn_cast<BlockPointerType>(this))
+ return PTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<BlockPointerType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<BlockPointerType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsBlockPointerType();
+ return 0;
+ }
+
+ // If this is a typedef for a block pointer type, strip the typedef off
+ // without losing all typedef information.
+ return cast<BlockPointerType>(getDesugaredType());
+}
+
+const ReferenceType *Type::getAsReferenceType() const {
+ // If this is directly a reference type, return it.
+ if (const ReferenceType *RTy = dyn_cast<ReferenceType>(this))
+ return RTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<ReferenceType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<ReferenceType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsReferenceType();
+ return 0;
+ }
+
+ // If this is a typedef for a reference type, strip the typedef off without
+ // losing all typedef information.
+ return cast<ReferenceType>(getDesugaredType());
+}
+
+const LValueReferenceType *Type::getAsLValueReferenceType() const {
+ // If this is directly an lvalue reference type, return it.
+ if (const LValueReferenceType *RTy = dyn_cast<LValueReferenceType>(this))
+ return RTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<LValueReferenceType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<LValueReferenceType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsLValueReferenceType();
+ return 0;
+ }
+
+ // If this is a typedef for an lvalue reference type, strip the typedef off
+ // without losing all typedef information.
+ return cast<LValueReferenceType>(getDesugaredType());
+}
+
+const RValueReferenceType *Type::getAsRValueReferenceType() const {
+ // If this is directly an rvalue reference type, return it.
+ if (const RValueReferenceType *RTy = dyn_cast<RValueReferenceType>(this))
+ return RTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<RValueReferenceType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<RValueReferenceType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsRValueReferenceType();
+ return 0;
+ }
+
+ // If this is a typedef for an rvalue reference type, strip the typedef off
+ // without losing all typedef information.
+ return cast<RValueReferenceType>(getDesugaredType());
+}
+
+const MemberPointerType *Type::getAsMemberPointerType() const {
+ // If this is directly a member pointer type, return it.
+ if (const MemberPointerType *MTy = dyn_cast<MemberPointerType>(this))
+ return MTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<MemberPointerType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<MemberPointerType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsMemberPointerType();
+ return 0;
+ }
+
+ // If this is a typedef for a member pointer type, strip the typedef off
+ // without losing all typedef information.
+ return cast<MemberPointerType>(getDesugaredType());
+}
+
+/// isVariablyModifiedType (C99 6.7.5p3) - Return true for variable length
+/// array types and types that contain variable array types in their
+/// declarator
+bool Type::isVariablyModifiedType() const {
+ // A VLA is a variably modified type.
+ if (isVariableArrayType())
+ return true;
+
+ // An array can contain a variably modified type
+ if (const Type *T = getArrayElementTypeNoTypeQual())
+ return T->isVariablyModifiedType();
+
+ // A pointer can point to a variably modified type.
+ // Also, C++ references and member pointers can point to a variably modified
+ // type, where VLAs appear as an extension to C++, and should be treated
+ // correctly.
+ if (const PointerType *PT = getAsPointerType())
+ return PT->getPointeeType()->isVariablyModifiedType();
+ if (const ReferenceType *RT = getAsReferenceType())
+ return RT->getPointeeType()->isVariablyModifiedType();
+ if (const MemberPointerType *PT = getAsMemberPointerType())
+ return PT->getPointeeType()->isVariablyModifiedType();
+
+ // A function can return a variably modified type
+ // This one isn't completely obvious, but it follows from the
+ // definition in C99 6.7.5p3. Because of this rule, it's
+ // illegal to declare a function returning a variably modified type.
+ if (const FunctionType *FT = getAsFunctionType())
+ return FT->getResultType()->isVariablyModifiedType();
+
+ return false;
+}
+
+const RecordType *Type::getAsRecordType() const {
+ // If this is directly a record type, return it.
+ if (const RecordType *RTy = dyn_cast<RecordType>(this))
+ return RTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<RecordType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<RecordType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsRecordType();
+ return 0;
+ }
+
+ // If this is a typedef for a record type, strip the typedef off without
+ // losing all typedef information.
+ return cast<RecordType>(getDesugaredType());
+}
+
+const TagType *Type::getAsTagType() const {
+ // If this is directly a tag type, return it.
+ if (const TagType *TagTy = dyn_cast<TagType>(this))
+ return TagTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<TagType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<TagType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsTagType();
+ return 0;
+ }
+
+ // If this is a typedef for a tag type, strip the typedef off without
+ // losing all typedef information.
+ return cast<TagType>(getDesugaredType());
+}
+
+const RecordType *Type::getAsStructureType() const {
+ // If this is directly a structure type, return it.
+ if (const RecordType *RT = dyn_cast<RecordType>(this)) {
+ if (RT->getDecl()->isStruct())
+ return RT;
+ }
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) {
+ if (!RT->getDecl()->isStruct())
+ return 0;
+
+ // If this is a typedef for a structure type, strip the typedef off without
+ // losing all typedef information.
+ return cast<RecordType>(getDesugaredType());
+ }
+ // Look through type qualifiers
+ if (isa<RecordType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsStructureType();
+ return 0;
+}
+
+const RecordType *Type::getAsUnionType() const {
+ // If this is directly a union type, return it.
+ if (const RecordType *RT = dyn_cast<RecordType>(this)) {
+ if (RT->getDecl()->isUnion())
+ return RT;
+ }
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) {
+ if (!RT->getDecl()->isUnion())
+ return 0;
+
+ // If this is a typedef for a union type, strip the typedef off without
+ // losing all typedef information.
+ return cast<RecordType>(getDesugaredType());
+ }
+
+ // Look through type qualifiers
+ if (isa<RecordType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsUnionType();
+ return 0;
+}
+
+const EnumType *Type::getAsEnumType() const {
+ // Check the canonicalized unqualified type directly; the more complex
+ // version is unnecessary because there isn't any typedef information
+ // to preserve.
+ return dyn_cast<EnumType>(CanonicalType.getUnqualifiedType());
+}
+
+const ComplexType *Type::getAsComplexType() const {
+ // Are we directly a complex type?
+ if (const ComplexType *CTy = dyn_cast<ComplexType>(this))
+ return CTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<ComplexType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<ComplexType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsComplexType();
+ return 0;
+ }
+
+ // If this is a typedef for a complex type, strip the typedef off without
+ // losing all typedef information.
+ return cast<ComplexType>(getDesugaredType());
+}
+
+const VectorType *Type::getAsVectorType() const {
+ // Are we directly a vector type?
+ if (const VectorType *VTy = dyn_cast<VectorType>(this))
+ return VTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<VectorType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<VectorType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsVectorType();
+ return 0;
+ }
+
+ // If this is a typedef for a vector type, strip the typedef off without
+ // losing all typedef information.
+ return cast<VectorType>(getDesugaredType());
+}
+
+const ExtVectorType *Type::getAsExtVectorType() const {
+ // Are we directly an OpenCU vector type?
+ if (const ExtVectorType *VTy = dyn_cast<ExtVectorType>(this))
+ return VTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<ExtVectorType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<ExtVectorType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsExtVectorType();
+ return 0;
+ }
+
+ // If this is a typedef for an extended vector type, strip the typedef off
+ // without losing all typedef information.
+ return cast<ExtVectorType>(getDesugaredType());
+}
+
+const ObjCInterfaceType *Type::getAsObjCInterfaceType() const {
+ // There is no sugar for ObjCInterfaceType's, just return the canonical
+ // type pointer if it is the right class. There is no typedef information to
+ // return and these cannot be Address-space qualified.
+ return dyn_cast<ObjCInterfaceType>(CanonicalType.getUnqualifiedType());
+}
+
+const ObjCQualifiedInterfaceType *
+Type::getAsObjCQualifiedInterfaceType() const {
+ // There is no sugar for ObjCQualifiedInterfaceType's, just return the
+ // canonical type pointer if it is the right class.
+ return dyn_cast<ObjCQualifiedInterfaceType>(CanonicalType.getUnqualifiedType());
+}
+
+const ObjCQualifiedIdType *Type::getAsObjCQualifiedIdType() const {
+ // There is no sugar for ObjCQualifiedIdType's, just return the canonical
+ // type pointer if it is the right class.
+ return dyn_cast<ObjCQualifiedIdType>(CanonicalType.getUnqualifiedType());
+}
+
+const TemplateTypeParmType *Type::getAsTemplateTypeParmType() const {
+ // There is no sugar for template type parameters, so just return
+ // the canonical type pointer if it is the right class.
+ // FIXME: can these be address-space qualified?
+ return dyn_cast<TemplateTypeParmType>(CanonicalType);
+}
+
+const TemplateSpecializationType *
+Type::getAsTemplateSpecializationType() const {
+ // There is no sugar for class template specialization types, so
+ // just return the canonical type pointer if it is the right class.
+ return dyn_cast<TemplateSpecializationType>(CanonicalType);
+}
+
+bool Type::isIntegerType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::Int128;
+ if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
+ // Incomplete enum types are not treated as integer types.
+ // FIXME: In C++, enum types are never integer types.
+ if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
+ return true;
+ if (isa<FixedWidthIntType>(CanonicalType))
+ return true;
+ if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
+ return VT->getElementType()->isIntegerType();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isIntegerType();
+ return false;
+}
+
+bool Type::isIntegralType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::LongLong;
+ if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
+ if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
+ return true; // Complete enum types are integral.
+ // FIXME: In C++, enum types are never integral.
+ if (isa<FixedWidthIntType>(CanonicalType))
+ return true;
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isIntegralType();
+ return false;
+}
+
+bool Type::isEnumeralType() const {
+ if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
+ return TT->getDecl()->isEnum();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isEnumeralType();
+ return false;
+}
+
+bool Type::isBooleanType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::Bool;
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isBooleanType();
+ return false;
+}
+
+bool Type::isCharType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::Char_U ||
+ BT->getKind() == BuiltinType::UChar ||
+ BT->getKind() == BuiltinType::Char_S ||
+ BT->getKind() == BuiltinType::SChar;
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isCharType();
+ return false;
+}
+
+bool Type::isWideCharType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::WChar;
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isWideCharType();
+ return false;
+}
+
+/// isSignedIntegerType - Return true if this is an integer type that is
+/// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..],
+/// an enum decl which has a signed representation, or a vector of signed
+/// integer element type.
+bool Type::isSignedIntegerType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
+ return BT->getKind() >= BuiltinType::Char_S &&
+ BT->getKind() <= BuiltinType::LongLong;
+ }
+
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ return ET->getDecl()->getIntegerType()->isSignedIntegerType();
+
+ if (const FixedWidthIntType *FWIT =
+ dyn_cast<FixedWidthIntType>(CanonicalType))
+ return FWIT->isSigned();
+
+ if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
+ return VT->getElementType()->isSignedIntegerType();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isSignedIntegerType();
+ return false;
+}
+
+/// isUnsignedIntegerType - Return true if this is an integer type that is
+/// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], an enum
+/// decl which has an unsigned representation, or a vector of unsigned integer
+/// element type.
+bool Type::isUnsignedIntegerType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::ULongLong;
+ }
+
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ return ET->getDecl()->getIntegerType()->isUnsignedIntegerType();
+
+ if (const FixedWidthIntType *FWIT =
+ dyn_cast<FixedWidthIntType>(CanonicalType))
+ return !FWIT->isSigned();
+
+ if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
+ return VT->getElementType()->isUnsignedIntegerType();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isUnsignedIntegerType();
+ return false;
+}
+
+bool Type::isFloatingType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Float &&
+ BT->getKind() <= BuiltinType::LongDouble;
+ if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType))
+ return CT->getElementType()->isFloatingType();
+ if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
+ return VT->getElementType()->isFloatingType();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isFloatingType();
+ return false;
+}
+
+bool Type::isRealFloatingType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Float &&
+ BT->getKind() <= BuiltinType::LongDouble;
+ if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
+ return VT->getElementType()->isRealFloatingType();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isRealFloatingType();
+ return false;
+}
+
+bool Type::isRealType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::LongDouble;
+ if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
+ return TT->getDecl()->isEnum() && TT->getDecl()->isDefinition();
+ if (isa<FixedWidthIntType>(CanonicalType))
+ return true;
+ if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
+ return VT->getElementType()->isRealType();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isRealType();
+ return false;
+}
+
+bool Type::isArithmeticType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::LongDouble;
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ // GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2).
+ // If a body isn't seen by the time we get here, return false.
+ return ET->getDecl()->isDefinition();
+ if (isa<FixedWidthIntType>(CanonicalType))
+ return true;
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isArithmeticType();
+ return isa<ComplexType>(CanonicalType) || isa<VectorType>(CanonicalType);
+}
+
+bool Type::isScalarType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() != BuiltinType::Void;
+ if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) {
+ // Enums are scalar types, but only if they are defined. Incomplete enums
+ // are not treated as scalar types.
+ if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
+ return true;
+ return false;
+ }
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isScalarType();
+ if (isa<FixedWidthIntType>(CanonicalType))
+ return true;
+ return isa<PointerType>(CanonicalType) ||
+ isa<BlockPointerType>(CanonicalType) ||
+ isa<MemberPointerType>(CanonicalType) ||
+ isa<ComplexType>(CanonicalType) ||
+ isa<ObjCQualifiedIdType>(CanonicalType);
+}
+
+/// \brief Determines whether the type is a C++ aggregate type or C
+/// aggregate or union type.
+///
+/// An aggregate type is an array or a class type (struct, union, or
+/// class) that has no user-declared constructors, no private or
+/// protected non-static data members, no base classes, and no virtual
+/// functions (C++ [dcl.init.aggr]p1). The notion of an aggregate type
+/// subsumes the notion of C aggregates (C99 6.2.5p21) because it also
+/// includes union types.
+bool Type::isAggregateType() const {
+ if (const RecordType *Record = dyn_cast<RecordType>(CanonicalType)) {
+ if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(Record->getDecl()))
+ return ClassDecl->isAggregate();
+
+ return true;
+ }
+
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isAggregateType();
+ return isa<ArrayType>(CanonicalType);
+}
+
+/// isConstantSizeType - Return true if this is not a variable sized type,
+/// according to the rules of C99 6.7.5p3. It is not legal to call this on
+/// incomplete types or dependent types.
+bool Type::isConstantSizeType() const {
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isConstantSizeType();
+ assert(!isIncompleteType() && "This doesn't make sense for incomplete types");
+ assert(!isDependentType() && "This doesn't make sense for dependent types");
+ // The VAT must have a size, as it is known to be complete.
+ return !isa<VariableArrayType>(CanonicalType);
+}
+
+/// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1)
+/// - a type that can describe objects, but which lacks information needed to
+/// determine its size.
+bool Type::isIncompleteType() const {
+ switch (CanonicalType->getTypeClass()) {
+ default: return false;
+ case ExtQual:
+ return cast<ExtQualType>(CanonicalType)->getBaseType()->isIncompleteType();
+ case Builtin:
+ // Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never
+ // be completed.
+ return isVoidType();
+ case Record:
+ case Enum:
+ // 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();
+ case IncompleteArray:
+ // An array of unknown size is an incomplete type (C99 6.2.5p22).
+ return true;
+ case ObjCInterface:
+ case ObjCQualifiedInterface:
+ // ObjC interfaces are incomplete if they are @class, not @interface.
+ return cast<ObjCInterfaceType>(this)->getDecl()->isForwardDecl();
+ }
+}
+
+/// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10)
+bool Type::isPODType() const {
+ // The compiler shouldn't query this for incomplete types, but the user might.
+ // We return false for that case.
+ if (isIncompleteType())
+ return false;
+
+ switch (CanonicalType->getTypeClass()) {
+ // Everything not explicitly mentioned is not POD.
+ default: return false;
+ case ExtQual:
+ return cast<ExtQualType>(CanonicalType)->getBaseType()->isPODType();
+ case VariableArray:
+ case ConstantArray:
+ // IncompleteArray is caught by isIncompleteType() above.
+ return cast<ArrayType>(CanonicalType)->getElementType()->isPODType();
+
+ case Builtin:
+ case Complex:
+ case Pointer:
+ case MemberPointer:
+ case Vector:
+ case ExtVector:
+ case ObjCQualifiedId:
+ return true;
+
+ case Enum:
+ return true;
+
+ case Record:
+ if (CXXRecordDecl *ClassDecl
+ = dyn_cast<CXXRecordDecl>(cast<RecordType>(CanonicalType)->getDecl()))
+ return ClassDecl->isPOD();
+
+ // C struct/union is POD.
+ return true;
+ }
+}
+
+bool Type::isPromotableIntegerType() const {
+ if (const BuiltinType *BT = getAsBuiltinType())
+ switch (BT->getKind()) {
+ case BuiltinType::Bool:
+ case BuiltinType::Char_S:
+ case BuiltinType::Char_U:
+ case BuiltinType::SChar:
+ case BuiltinType::UChar:
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
+bool Type::isNullPtrType() const {
+ if (const BuiltinType *BT = getAsBuiltinType())
+ return BT->getKind() == BuiltinType::NullPtr;
+ return false;
+}
+
+bool Type::isSpecifierType() const {
+ // Note that this intentionally does not use the canonical type.
+ switch (getTypeClass()) {
+ case Builtin:
+ case Record:
+ case Enum:
+ case Typedef:
+ case Complex:
+ case TypeOfExpr:
+ case TypeOf:
+ case TemplateTypeParm:
+ case TemplateSpecialization:
+ case QualifiedName:
+ case Typename:
+ case ObjCInterface:
+ case ObjCQualifiedInterface:
+ case ObjCQualifiedId:
+ return true;
+ default:
+ return false;
+ }
+}
+
+const char *BuiltinType::getName(bool CPlusPlus) const {
+ switch (getKind()) {
+ default: assert(0 && "Unknown builtin type!");
+ case Void: return "void";
+ case Bool: return CPlusPlus? "bool" : "_Bool";
+ case Char_S: return "char";
+ case Char_U: return "char";
+ case SChar: return "signed char";
+ case Short: return "short";
+ case Int: return "int";
+ case Long: return "long";
+ case LongLong: return "long long";
+ case Int128: return "__int128_t";
+ case UChar: return "unsigned char";
+ case UShort: return "unsigned short";
+ case UInt: return "unsigned int";
+ case ULong: return "unsigned long";
+ case ULongLong: return "unsigned long long";
+ case UInt128: return "__uint128_t";
+ case Float: return "float";
+ case Double: return "double";
+ case LongDouble: return "long double";
+ case WChar: return "wchar_t";
+ case NullPtr: return "nullptr_t";
+ case Overload: return "<overloaded function type>";
+ case Dependent: return "<dependent type>";
+ }
+}
+
+void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
+ arg_type_iterator ArgTys,
+ unsigned NumArgs, bool isVariadic,
+ unsigned TypeQuals, bool hasExceptionSpec,
+ bool anyExceptionSpec, unsigned NumExceptions,
+ exception_iterator Exs) {
+ ID.AddPointer(Result.getAsOpaquePtr());
+ for (unsigned i = 0; i != NumArgs; ++i)
+ ID.AddPointer(ArgTys[i].getAsOpaquePtr());
+ ID.AddInteger(isVariadic);
+ ID.AddInteger(TypeQuals);
+ ID.AddInteger(hasExceptionSpec);
+ if (hasExceptionSpec) {
+ ID.AddInteger(anyExceptionSpec);
+ for(unsigned i = 0; i != NumExceptions; ++i)
+ ID.AddPointer(Exs[i].getAsOpaquePtr());
+ }
+}
+
+void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(),
+ getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(),
+ getNumExceptions(), exception_begin());
+}
+
+void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
+ const ObjCInterfaceDecl *Decl,
+ ObjCProtocolDecl **protocols,
+ unsigned NumProtocols) {
+ ID.AddPointer(Decl);
+ for (unsigned i = 0; i != NumProtocols; i++)
+ ID.AddPointer(protocols[i]);
+}
+
+void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getDecl(), &Protocols[0], getNumProtocols());
+}
+
+void ObjCQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID,
+ ObjCProtocolDecl **protocols,
+ unsigned NumProtocols) {
+ for (unsigned i = 0; i != NumProtocols; i++)
+ ID.AddPointer(protocols[i]);
+}
+
+void ObjCQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, &Protocols[0], getNumProtocols());
+}
+
+/// LookThroughTypedefs - Return the ultimate type this typedef corresponds to
+/// potentially looking through *all* consequtive typedefs. This returns the
+/// sum of the type qualifiers, so if you have:
+/// typedef const int A;
+/// typedef volatile A B;
+/// looking through the typedefs for B will give you "const volatile A".
+///
+QualType TypedefType::LookThroughTypedefs() const {
+ // Usually, there is only a single level of typedefs, be fast in that case.
+ QualType FirstType = getDecl()->getUnderlyingType();
+ if (!isa<TypedefType>(FirstType))
+ return FirstType;
+
+ // Otherwise, do the fully general loop.
+ unsigned TypeQuals = 0;
+ const TypedefType *TDT = this;
+ while (1) {
+ QualType CurType = TDT->getDecl()->getUnderlyingType();
+
+
+ /// FIXME:
+ /// FIXME: This is incorrect for ExtQuals!
+ /// FIXME:
+ TypeQuals |= CurType.getCVRQualifiers();
+
+ TDT = dyn_cast<TypedefType>(CurType);
+ if (TDT == 0)
+ return QualType(CurType.getTypePtr(), TypeQuals);
+ }
+}
+
+TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
+ : Type(TypeOfExpr, can, E->isTypeDependent()), TOExpr(E) {
+ assert(!isa<TypedefType>(can) && "Invalid canonical type");
+}
+
+TagType::TagType(TypeClass TC, TagDecl *D, QualType can)
+ : Type(TC, can, D->isDependentType()), decl(D, 0) {}
+
+bool RecordType::classof(const TagType *TT) {
+ return isa<RecordDecl>(TT->getDecl());
+}
+
+bool EnumType::classof(const TagType *TT) {
+ return isa<EnumDecl>(TT->getDecl());
+}
+
+bool
+TemplateSpecializationType::
+anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) {
+ for (unsigned Idx = 0; Idx < NumArgs; ++Idx) {
+ switch (Args[Idx].getKind()) {
+ case TemplateArgument::Type:
+ if (Args[Idx].getAsType()->isDependentType())
+ return true;
+ break;
+
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Integral:
+ // Never dependent
+ break;
+
+ case TemplateArgument::Expression:
+ if (Args[Idx].getAsExpr()->isTypeDependent() ||
+ Args[Idx].getAsExpr()->isValueDependent())
+ return true;
+ break;
+ }
+ }
+
+ return false;
+}
+
+TemplateSpecializationType::
+TemplateSpecializationType(TemplateName T, const TemplateArgument *Args,
+ unsigned NumArgs, QualType Canon)
+ : Type(TemplateSpecialization,
+ Canon.isNull()? QualType(this, 0) : Canon,
+ T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)),
+ Template(T), NumArgs(NumArgs)
+{
+ assert((!Canon.isNull() ||
+ T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) &&
+ "No canonical type for non-dependent class template specialization");
+
+ TemplateArgument *TemplateArgs
+ = reinterpret_cast<TemplateArgument *>(this + 1);
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
+ new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
+}
+
+void TemplateSpecializationType::Destroy(ASTContext& C) {
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ // FIXME: Not all expressions get cloned, so we can't yet perform
+ // this destruction.
+ // if (Expr *E = getArg(Arg).getAsExpr())
+ // E->Destroy(C);
+ }
+}
+
+TemplateSpecializationType::iterator
+TemplateSpecializationType::end() const {
+ return begin() + getNumArgs();
+}
+
+const TemplateArgument &
+TemplateSpecializationType::getArg(unsigned Idx) const {
+ assert(Idx < getNumArgs() && "Template argument out of range");
+ return getArgs()[Idx];
+}
+
+void
+TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
+ TemplateName T,
+ const TemplateArgument *Args,
+ unsigned NumArgs) {
+ T.Profile(ID);
+ for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
+ Args[Idx].Profile(ID);
+}
+
+//===----------------------------------------------------------------------===//
+// Type Printing
+//===----------------------------------------------------------------------===//
+
+void QualType::dump(const char *msg) const {
+ PrintingPolicy Policy;
+ std::string R = "identifier";
+ getAsStringInternal(R, Policy);
+ if (msg)
+ fprintf(stderr, "%s: %s\n", msg, R.c_str());
+ else
+ fprintf(stderr, "%s\n", R.c_str());
+}
+void QualType::dump() const {
+ dump("");
+}
+
+void Type::dump() const {
+ std::string S = "identifier";
+ getAsStringInternal(S, PrintingPolicy());
+ fprintf(stderr, "%s\n", S.c_str());
+}
+
+
+
+static void AppendTypeQualList(std::string &S, unsigned TypeQuals) {
+ // Note: funkiness to ensure we get a space only between quals.
+ bool NonePrinted = true;
+ if (TypeQuals & QualType::Const)
+ S += "const", NonePrinted = false;
+ if (TypeQuals & QualType::Volatile)
+ S += (NonePrinted+" volatile"), NonePrinted = false;
+ if (TypeQuals & QualType::Restrict)
+ S += (NonePrinted+" restrict"), NonePrinted = false;
+}
+
+std::string QualType::getAsString() const {
+ std::string S;
+ getAsStringInternal(S, PrintingPolicy());
+ return S;
+}
+
+void
+QualType::getAsStringInternal(std::string &S,
+ const PrintingPolicy &Policy) const {
+ if (isNull()) {
+ S += "NULL TYPE";
+ return;
+ }
+
+ if (Policy.SuppressSpecifiers && getTypePtr()->isSpecifierType())
+ return;
+
+ // Print qualifiers as appropriate.
+ if (unsigned Tq = getCVRQualifiers()) {
+ std::string TQS;
+ AppendTypeQualList(TQS, Tq);
+ if (!S.empty())
+ S = TQS + ' ' + S;
+ else
+ S = TQS;
+ }
+
+ getTypePtr()->getAsStringInternal(S, Policy);
+}
+
+void BuiltinType::getAsStringInternal(std::string &S,
+ const PrintingPolicy &Policy) const {
+ if (S.empty()) {
+ S = getName(Policy.CPlusPlus);
+ } else {
+ // Prefix the basic type, e.g. 'int X'.
+ S = ' ' + S;
+ S = getName(Policy.CPlusPlus) + S;
+ }
+}
+
+void FixedWidthIntType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ // FIXME: Once we get bitwidth attribute, write as
+ // "int __attribute__((bitwidth(x)))".
+ std::string prefix = "__clang_fixedwidth";
+ prefix += llvm::utostr_32(Width);
+ prefix += (char)(Signed ? 'S' : 'U');
+ if (S.empty()) {
+ S = prefix;
+ } else {
+ // Prefix the basic type, e.g. 'int X'.
+ S = prefix + S;
+ }
+}
+
+
+void ComplexType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ ElementType->getAsStringInternal(S, Policy);
+ S = "_Complex " + S;
+}
+
+void ExtQualType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ bool NeedsSpace = false;
+ if (AddressSpace) {
+ S = "__attribute__((address_space("+llvm::utostr_32(AddressSpace)+")))" + S;
+ NeedsSpace = true;
+ }
+ if (GCAttrType != QualType::GCNone) {
+ if (NeedsSpace)
+ S += ' ';
+ S += "__attribute__((objc_gc(";
+ if (GCAttrType == QualType::Weak)
+ S += "weak";
+ else
+ S += "strong";
+ S += ")))";
+ }
+ BaseType->getAsStringInternal(S, Policy);
+}
+
+void PointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S = '*' + S;
+
+ // Handle things like 'int (*A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(getPointeeType()))
+ S = '(' + S + ')';
+
+ getPointeeType().getAsStringInternal(S, Policy);
+}
+
+void BlockPointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S = '^' + S;
+ PointeeType.getAsStringInternal(S, Policy);
+}
+
+void LValueReferenceType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S = '&' + S;
+
+ // Handle things like 'int (&A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(getPointeeType()))
+ S = '(' + S + ')';
+
+ getPointeeType().getAsStringInternal(S, Policy);
+}
+
+void RValueReferenceType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S = "&&" + S;
+
+ // Handle things like 'int (&&A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(getPointeeType()))
+ S = '(' + S + ')';
+
+ getPointeeType().getAsStringInternal(S, Policy);
+}
+
+void MemberPointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ std::string C;
+ Class->getAsStringInternal(C, Policy);
+ C += "::*";
+ S = C + S;
+
+ // Handle things like 'int (Cls::*A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(getPointeeType()))
+ S = '(' + S + ')';
+
+ getPointeeType().getAsStringInternal(S, Policy);
+}
+
+void ConstantArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S += '[';
+ S += llvm::utostr(getSize().getZExtValue());
+ S += ']';
+
+ getElementType().getAsStringInternal(S, Policy);
+}
+
+void IncompleteArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S += "[]";
+
+ getElementType().getAsStringInternal(S, Policy);
+}
+
+void VariableArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S += '[';
+
+ if (getIndexTypeQualifier()) {
+ AppendTypeQualList(S, getIndexTypeQualifier());
+ S += ' ';
+ }
+
+ if (getSizeModifier() == Static)
+ S += "static";
+ else if (getSizeModifier() == Star)
+ S += '*';
+
+ if (getSizeExpr()) {
+ std::string SStr;
+ llvm::raw_string_ostream s(SStr);
+ getSizeExpr()->printPretty(s, 0, Policy);
+ S += s.str();
+ }
+ S += ']';
+
+ getElementType().getAsStringInternal(S, Policy);
+}
+
+void DependentSizedArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S += '[';
+
+ if (getIndexTypeQualifier()) {
+ AppendTypeQualList(S, getIndexTypeQualifier());
+ S += ' ';
+ }
+
+ if (getSizeModifier() == Static)
+ S += "static";
+ else if (getSizeModifier() == Star)
+ S += '*';
+
+ if (getSizeExpr()) {
+ std::string SStr;
+ llvm::raw_string_ostream s(SStr);
+ getSizeExpr()->printPretty(s, 0, Policy);
+ S += s.str();
+ }
+ S += ']';
+
+ getElementType().getAsStringInternal(S, Policy);
+}
+
+void VectorType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ // FIXME: We prefer to print the size directly here, but have no way
+ // to get the size of the type.
+ S += " __attribute__((__vector_size__(";
+ S += llvm::utostr_32(NumElements); // convert back to bytes.
+ S += " * sizeof(" + ElementType.getAsString() + "))))";
+ ElementType.getAsStringInternal(S, Policy);
+}
+
+void ExtVectorType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S += " __attribute__((ext_vector_type(";
+ S += llvm::utostr_32(NumElements);
+ S += ")))";
+ ElementType.getAsStringInternal(S, Policy);
+}
+
+void TypeOfExprType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(e) X'.
+ InnerString = ' ' + InnerString;
+ std::string Str;
+ llvm::raw_string_ostream s(Str);
+ getUnderlyingExpr()->printPretty(s, 0, Policy);
+ InnerString = "typeof " + s.str() + InnerString;
+}
+
+void TypeOfType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(t) X'.
+ InnerString = ' ' + InnerString;
+ std::string Tmp;
+ getUnderlyingType().getAsStringInternal(Tmp, Policy);
+ InnerString = "typeof(" + Tmp + ")" + InnerString;
+}
+
+void FunctionNoProtoType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ // If needed for precedence reasons, wrap the inner part in grouping parens.
+ if (!S.empty())
+ S = "(" + S + ")";
+
+ S += "()";
+ getResultType().getAsStringInternal(S, Policy);
+}
+
+void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ // If needed for precedence reasons, wrap the inner part in grouping parens.
+ if (!S.empty())
+ S = "(" + S + ")";
+
+ S += "(";
+ std::string Tmp;
+ PrintingPolicy ParamPolicy(Policy);
+ ParamPolicy.SuppressSpecifiers = false;
+ for (unsigned i = 0, e = getNumArgs(); i != e; ++i) {
+ if (i) S += ", ";
+ getArgType(i).getAsStringInternal(Tmp, ParamPolicy);
+ S += Tmp;
+ Tmp.clear();
+ }
+
+ if (isVariadic()) {
+ if (getNumArgs())
+ S += ", ";
+ S += "...";
+ } else if (getNumArgs() == 0) {
+ // Do not emit int() if we have a proto, emit 'int(void)'.
+ S += "void";
+ }
+
+ S += ")";
+ getResultType().getAsStringInternal(S, Policy);
+}
+
+
+void TypedefType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ InnerString = ' ' + InnerString;
+ InnerString = getDecl()->getIdentifier()->getName() + InnerString;
+}
+
+void TemplateTypeParmType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'parmname X'.
+ InnerString = ' ' + InnerString;
+
+ if (!Name)
+ InnerString = "type-parameter-" + llvm::utostr_32(Depth) + '-' +
+ llvm::utostr_32(Index) + InnerString;
+ else
+ InnerString = Name->getName() + InnerString;
+}
+
+std::string
+TemplateSpecializationType::PrintTemplateArgumentList(
+ const TemplateArgument *Args,
+ unsigned NumArgs,
+ const PrintingPolicy &Policy) {
+ std::string SpecString;
+ SpecString += '<';
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ if (Arg)
+ SpecString += ", ";
+
+ // Print the argument into a string.
+ std::string ArgString;
+ switch (Args[Arg].getKind()) {
+ case TemplateArgument::Type:
+ Args[Arg].getAsType().getAsStringInternal(ArgString, Policy);
+ break;
+
+ case TemplateArgument::Declaration:
+ ArgString = cast<NamedDecl>(Args[Arg].getAsDecl())->getNameAsString();
+ break;
+
+ case TemplateArgument::Integral:
+ ArgString = Args[Arg].getAsIntegral()->toString(10, true);
+ break;
+
+ case TemplateArgument::Expression: {
+ llvm::raw_string_ostream s(ArgString);
+ Args[Arg].getAsExpr()->printPretty(s, 0, Policy);
+ break;
+ }
+ }
+
+ // If this is the first argument and its string representation
+ // begins with the global scope specifier ('::foo'), add a space
+ // to avoid printing the diagraph '<:'.
+ if (!Arg && !ArgString.empty() && ArgString[0] == ':')
+ SpecString += ' ';
+
+ SpecString += ArgString;
+ }
+
+ // If the last character of our string is '>', add another space to
+ // keep the two '>''s separate tokens. We don't *have* to do this in
+ // C++0x, but it's still good hygiene.
+ if (SpecString[SpecString.size() - 1] == '>')
+ SpecString += ' ';
+
+ SpecString += '>';
+
+ return SpecString;
+}
+
+void
+TemplateSpecializationType::
+getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ std::string SpecString;
+
+ {
+ llvm::raw_string_ostream OS(SpecString);
+ Template.print(OS, Policy);
+ }
+
+ SpecString += PrintTemplateArgumentList(getArgs(), getNumArgs(), Policy);
+ if (InnerString.empty())
+ InnerString.swap(SpecString);
+ else
+ InnerString = SpecString + ' ' + InnerString;
+}
+
+void QualifiedNameType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ std::string MyString;
+
+ {
+ llvm::raw_string_ostream OS(MyString);
+ NNS->print(OS, Policy);
+ }
+
+ std::string TypeStr;
+ PrintingPolicy InnerPolicy(Policy);
+ InnerPolicy.SuppressTagKind = true;
+ NamedType.getAsStringInternal(TypeStr, InnerPolicy);
+
+ MyString += TypeStr;
+ if (InnerString.empty())
+ InnerString.swap(MyString);
+ else
+ InnerString = MyString + ' ' + InnerString;
+}
+
+void TypenameType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ std::string MyString;
+
+ {
+ llvm::raw_string_ostream OS(MyString);
+ OS << "typename ";
+ NNS->print(OS, Policy);
+
+ if (const IdentifierInfo *Ident = getIdentifier())
+ OS << Ident->getName();
+ else if (const TemplateSpecializationType *Spec = getTemplateId()) {
+ Spec->getTemplateName().print(OS, Policy, true);
+ OS << TemplateSpecializationType::PrintTemplateArgumentList(
+ Spec->getArgs(),
+ Spec->getNumArgs(),
+ Policy);
+ }
+ }
+
+ if (InnerString.empty())
+ InnerString.swap(MyString);
+ else
+ InnerString = MyString + ' ' + InnerString;
+}
+
+void ObjCInterfaceType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ InnerString = ' ' + InnerString;
+ InnerString = getDecl()->getIdentifier()->getName() + InnerString;
+}
+
+void
+ObjCQualifiedInterfaceType::getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const {
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ InnerString = ' ' + InnerString;
+ std::string ObjCQIString = getDecl()->getNameAsString();
+ ObjCQIString += '<';
+ bool isFirst = true;
+ for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) {
+ if (isFirst)
+ isFirst = false;
+ else
+ ObjCQIString += ',';
+ ObjCQIString += (*I)->getNameAsString();
+ }
+ ObjCQIString += '>';
+ InnerString = ObjCQIString + InnerString;
+}
+
+void ObjCQualifiedIdType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ InnerString = ' ' + InnerString;
+ std::string ObjCQIString = "id";
+ ObjCQIString += '<';
+ for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) {
+ ObjCQIString += (*I)->getNameAsString();
+ if (I+1 != E)
+ ObjCQIString += ',';
+ }
+ ObjCQIString += '>';
+ InnerString = ObjCQIString + InnerString;
+}
+
+void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ if (Policy.SuppressTag)
+ return;
+
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ InnerString = ' ' + InnerString;
+
+ const char *Kind = Policy.SuppressTagKind? 0 : getDecl()->getKindName();
+ const char *ID;
+ if (const IdentifierInfo *II = getDecl()->getIdentifier())
+ ID = II->getName();
+ else if (TypedefDecl *Typedef = getDecl()->getTypedefForAnonDecl()) {
+ Kind = 0;
+ assert(Typedef->getIdentifier() && "Typedef without identifier?");
+ ID = Typedef->getIdentifier()->getName();
+ } else
+ ID = "<anonymous>";
+
+ // If this is a class template specialization, print the template
+ // arguments.
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(getDecl())) {
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ std::string TemplateArgsStr
+ = TemplateSpecializationType::PrintTemplateArgumentList(
+ TemplateArgs.getFlatArgumentList(),
+ TemplateArgs.flat_size(),
+ Policy);
+ InnerString = TemplateArgsStr + InnerString;
+ }
+
+ if (Kind) {
+ // Compute the full nested-name-specifier for this type. In C,
+ // this will always be empty.
+ std::string ContextStr;
+ for (DeclContext *DC = getDecl()->getDeclContext();
+ !DC->isTranslationUnit(); DC = DC->getParent()) {
+ std::string MyPart;
+ if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
+ if (NS->getIdentifier())
+ MyPart = NS->getNameAsString();
+ } else if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ std::string TemplateArgsStr
+ = TemplateSpecializationType::PrintTemplateArgumentList(
+ TemplateArgs.getFlatArgumentList(),
+ TemplateArgs.flat_size(),
+ Policy);
+ MyPart = Spec->getIdentifier()->getName() + TemplateArgsStr;
+ } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
+ if (TypedefDecl *Typedef = Tag->getTypedefForAnonDecl())
+ MyPart = Typedef->getIdentifier()->getName();
+ else if (Tag->getIdentifier())
+ MyPart = Tag->getIdentifier()->getName();
+ }
+
+ if (!MyPart.empty())
+ ContextStr = MyPart + "::" + ContextStr;
+ }
+
+ InnerString = std::string(Kind) + " " + ContextStr + ID + InnerString;
+ } else
+ InnerString = ID + InnerString;
+}
diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp
new file mode 100644
index 000000000000..b2722141d955
--- /dev/null
+++ b/lib/Analysis/BasicConstraintManager.cpp
@@ -0,0 +1,342 @@
+//== BasicConstraintManager.cpp - Manage basic constraints.------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines BasicConstraintManager, a class that tracks simple
+// equality and inequality constraints on symbolic values of GRState.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SimpleConstraintManager.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/PathSensitive/GRStateTrait.h"
+#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+
+namespace { class VISIBILITY_HIDDEN ConstNotEq {}; }
+namespace { class VISIBILITY_HIDDEN ConstEq {}; }
+
+typedef llvm::ImmutableMap<SymbolRef,GRState::IntSetTy> ConstNotEqTy;
+typedef llvm::ImmutableMap<SymbolRef,const llvm::APSInt*> ConstEqTy;
+
+static int ConstEqIndex = 0;
+static int ConstNotEqIndex = 0;
+
+namespace clang {
+template<>
+struct GRStateTrait<ConstNotEq> : public GRStatePartialTrait<ConstNotEqTy> {
+ static inline void* GDMIndex() { return &ConstNotEqIndex; }
+};
+
+template<>
+struct GRStateTrait<ConstEq> : public GRStatePartialTrait<ConstEqTy> {
+ static inline void* GDMIndex() { return &ConstEqIndex; }
+};
+}
+
+namespace {
+// BasicConstraintManager only tracks equality and inequality constraints of
+// constants and integer variables.
+class VISIBILITY_HIDDEN BasicConstraintManager
+ : public SimpleConstraintManager {
+ GRState::IntSetTy::Factory ISetFactory;
+public:
+ BasicConstraintManager(GRStateManager& statemgr)
+ : SimpleConstraintManager(statemgr), ISetFactory(statemgr.getAllocator()) {}
+
+ const GRState* AssumeSymNE(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible);
+
+ const GRState* AssumeSymEQ(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible);
+
+ const GRState* AssumeSymLT(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible);
+
+ const GRState* AssumeSymGT(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible);
+
+ const GRState* AssumeSymGE(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible);
+
+ const GRState* AssumeSymLE(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible);
+
+ const GRState* AddEQ(const GRState* St, SymbolRef sym, const llvm::APSInt& V);
+
+ const GRState* AddNE(const GRState* St, SymbolRef sym, const llvm::APSInt& V);
+
+ const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) const;
+ bool isNotEqual(const GRState* St, SymbolRef sym, const llvm::APSInt& V)
+ const;
+ bool isEqual(const GRState* St, SymbolRef sym, const llvm::APSInt& V)
+ const;
+
+ const GRState* RemoveDeadBindings(const GRState* St, SymbolReaper& SymReaper);
+
+ void print(const GRState* St, std::ostream& Out,
+ const char* nl, const char *sep);
+};
+
+} // end anonymous namespace
+
+ConstraintManager* clang::CreateBasicConstraintManager(GRStateManager& StateMgr)
+{
+ return new BasicConstraintManager(StateMgr);
+}
+
+const GRState*
+BasicConstraintManager::AssumeSymNE(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible) {
+ // First, determine if sym == X, where X != V.
+ if (const llvm::APSInt* X = getSymVal(St, sym)) {
+ isFeasible = (*X != V);
+ return St;
+ }
+
+ // Second, determine if sym != V.
+ if (isNotEqual(St, sym, V)) {
+ isFeasible = true;
+ return St;
+ }
+
+ // If we reach here, sym is not a constant and we don't know if it is != V.
+ // Make that assumption.
+ isFeasible = true;
+ return AddNE(St, sym, V);
+}
+
+const GRState*
+BasicConstraintManager::AssumeSymEQ(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible) {
+ // First, determine if sym == X, where X != V.
+ if (const llvm::APSInt* X = getSymVal(St, sym)) {
+ isFeasible = *X == V;
+ return St;
+ }
+
+ // Second, determine if sym != V.
+ if (isNotEqual(St, sym, V)) {
+ isFeasible = false;
+ return St;
+ }
+
+ // If we reach here, sym is not a constant and we don't know if it is == V.
+ // Make that assumption.
+
+ isFeasible = true;
+ return AddEQ(St, sym, V);
+}
+
+// These logic will be handled in another ConstraintManager.
+const GRState*
+BasicConstraintManager::AssumeSymLT(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible) {
+
+ // Is 'V' the smallest possible value?
+ if (V == llvm::APSInt::getMinValue(V.getBitWidth(), V.isUnsigned())) {
+ // sym cannot be any value less than 'V'. This path is infeasible.
+ isFeasible = false;
+ return St;
+ }
+
+ // FIXME: For now have assuming x < y be the same as assuming sym != V;
+ return AssumeSymNE(St, sym, V, isFeasible);
+}
+
+const GRState*
+BasicConstraintManager::AssumeSymGT(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible) {
+
+ // Is 'V' the largest possible value?
+ if (V == llvm::APSInt::getMaxValue(V.getBitWidth(), V.isUnsigned())) {
+ // sym cannot be any value greater than 'V'. This path is infeasible.
+ isFeasible = false;
+ return St;
+ }
+
+ // FIXME: For now have assuming x > y be the same as assuming sym != V;
+ return AssumeSymNE(St, sym, V, isFeasible);
+}
+
+const GRState*
+BasicConstraintManager::AssumeSymGE(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible) {
+
+ // Reject a path if the value of sym is a constant X and !(X >= V).
+ if (const llvm::APSInt* X = getSymVal(St, sym)) {
+ isFeasible = *X >= V;
+ return St;
+ }
+
+ // Sym is not a constant, but it is worth looking to see if V is the
+ // maximum integer value.
+ if (V == llvm::APSInt::getMaxValue(V.getBitWidth(), V.isUnsigned())) {
+ // If we know that sym != V, then this condition is infeasible since
+ // there is no other value greater than V.
+ isFeasible = !isNotEqual(St, sym, V);
+
+ // If the path is still feasible then as a consequence we know that
+ // 'sym == V' because we cannot have 'sym > V' (no larger values).
+ // Add this constraint.
+ if (isFeasible)
+ return AddEQ(St, sym, V);
+ }
+ else
+ isFeasible = true;
+
+ return St;
+}
+
+const GRState*
+BasicConstraintManager::AssumeSymLE(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible) {
+
+ // Reject a path if the value of sym is a constant X and !(X <= V).
+ if (const llvm::APSInt* X = getSymVal(St, sym)) {
+ isFeasible = *X <= V;
+ return St;
+ }
+
+ // Sym is not a constant, but it is worth looking to see if V is the
+ // minimum integer value.
+ if (V == llvm::APSInt::getMinValue(V.getBitWidth(), V.isUnsigned())) {
+ // If we know that sym != V, then this condition is infeasible since
+ // there is no other value less than V.
+ isFeasible = !isNotEqual(St, sym, V);
+
+ // If the path is still feasible then as a consequence we know that
+ // 'sym == V' because we cannot have 'sym < V' (no smaller values).
+ // Add this constraint.
+ if (isFeasible)
+ return AddEQ(St, sym, V);
+ }
+ else
+ isFeasible = true;
+
+ return St;
+}
+
+const GRState* BasicConstraintManager::AddEQ(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V) {
+ // Create a new state with the old binding replaced.
+ GRStateRef state(St, StateMgr);
+ return state.set<ConstEq>(sym, &V);
+}
+
+const GRState* BasicConstraintManager::AddNE(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V) {
+
+ GRStateRef state(St, StateMgr);
+
+ // 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();
+
+
+ // Now add V to the NE set.
+ S = ISetFactory.Add(S, &V);
+
+ // Create a new state with the old binding replaced.
+ return state.set<ConstNotEq>(sym, S);
+}
+
+const llvm::APSInt* BasicConstraintManager::getSymVal(const GRState* St,
+ SymbolRef sym) const {
+ const ConstEqTy::data_type* T = St->get<ConstEq>(sym);
+ return T ? *T : NULL;
+}
+
+bool BasicConstraintManager::isNotEqual(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V) const {
+
+ // Retrieve the NE-set associated with the given symbol.
+ const ConstNotEqTy::data_type* T = St->get<ConstNotEq>(sym);
+
+ // See if V is present in the NE-set.
+ return T ? T->contains(&V) : false;
+}
+
+bool BasicConstraintManager::isEqual(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V) const {
+ // Retrieve the EQ-set associated with the given symbol.
+ const ConstEqTy::data_type* T = St->get<ConstEq>(sym);
+ // See if V is present in the EQ-set.
+ return T ? **T == V : false;
+}
+
+/// Scan all symbols referenced by the constraints. If the symbol is not alive
+/// as marked in LSymbols, mark it as dead in DSymbols.
+const GRState*
+BasicConstraintManager::RemoveDeadBindings(const GRState* St,
+ SymbolReaper& SymReaper) {
+
+ GRStateRef state(St, StateMgr);
+ ConstEqTy CE = state.get<ConstEq>();
+ ConstEqTy::Factory& CEFactory = state.get_context<ConstEq>();
+
+ for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) {
+ SymbolRef sym = I.getKey();
+ if (SymReaper.maybeDead(sym)) CE = CEFactory.Remove(CE, sym);
+ }
+ state = state.set<ConstEq>(CE);
+
+ ConstNotEqTy CNE = state.get<ConstNotEq>();
+ ConstNotEqTy::Factory& CNEFactory = state.get_context<ConstNotEq>();
+
+ for (ConstNotEqTy::iterator I = CNE.begin(), E = CNE.end(); I != E; ++I) {
+ SymbolRef sym = I.getKey();
+ if (SymReaper.maybeDead(sym)) CNE = CNEFactory.Remove(CNE, sym);
+ }
+
+ return state.set<ConstNotEq>(CNE);
+}
+
+void BasicConstraintManager::print(const GRState* St, std::ostream& Out,
+ const char* nl, const char *sep) {
+ // Print equality constraints.
+
+ ConstEqTy CE = St->get<ConstEq>();
+
+ if (!CE.isEmpty()) {
+ Out << nl << sep << "'==' constraints:";
+
+ for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) {
+ Out << nl << " $" << I.getKey();
+ llvm::raw_os_ostream OS(Out);
+ OS << " : " << *I.getData();
+ }
+ }
+
+ // Print != constraints.
+
+ ConstNotEqTy CNE = St->get<ConstNotEq>();
+
+ if (!CNE.isEmpty()) {
+ Out << nl << sep << "'!=' constraints:";
+
+ for (ConstNotEqTy::iterator I = CNE.begin(), EI = CNE.end(); I!=EI; ++I) {
+ Out << nl << " $" << I.getKey() << " : ";
+ bool isFirst = true;
+
+ GRState::IntSetTy::iterator J = I.getData().begin(),
+ EJ = I.getData().end();
+
+ for ( ; J != EJ; ++J) {
+ if (isFirst) isFirst = false;
+ else Out << ", ";
+
+ Out << (*J)->getSExtValue(); // Hack: should print to raw_ostream.
+ }
+ }
+ }
+}
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
new file mode 100644
index 000000000000..98e9551d4b3d
--- /dev/null
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -0,0 +1,492 @@
+//== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- 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 BasicObjCFoundationChecks, a class that encapsulates
+// a set of simple checks to run on Objective-C code using Apple's Foundation
+// classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BasicObjCFoundationChecks.h"
+
+#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
+#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/MemRegion.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Analysis/LocalCheckers.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace clang;
+
+static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
+ Expr* Receiver = ME->getReceiver();
+
+ if (!Receiver)
+ return NULL;
+
+ QualType X = Receiver->getType();
+
+ if (X->isPointerType()) {
+ Type* TP = X.getTypePtr();
+ const PointerType* T = TP->getAsPointerType();
+ return dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
+ }
+
+ // FIXME: Support ObjCQualifiedIdType?
+ return NULL;
+}
+
+static const char* GetReceiverNameType(ObjCMessageExpr* ME) {
+ ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
+ return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName()
+ : NULL;
+}
+
+namespace {
+
+class VISIBILITY_HIDDEN APIMisuse : public BugType {
+public:
+ APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
+};
+
+class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
+ APIMisuse *BT;
+ BugReporter& BR;
+ ASTContext &Ctx;
+ GRStateManager* VMgr;
+
+ SVal GetSVal(const GRState* St, Expr* E) { return VMgr->GetSVal(St, E); }
+
+ bool isNSString(ObjCInterfaceType* T, const char* suffix);
+ bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
+
+ void Warn(NodeTy* N, Expr* E, const std::string& s);
+ void WarnNilArg(NodeTy* N, Expr* E);
+
+ bool CheckNilArg(NodeTy* N, unsigned Arg);
+
+public:
+ BasicObjCFoundationChecks(ASTContext& ctx, GRStateManager* vmgr,
+ BugReporter& br)
+ : BT(0), BR(br), Ctx(ctx), VMgr(vmgr) {}
+
+ bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
+
+private:
+ void WarnNilArg(NodeTy* N, ObjCMessageExpr* ME, unsigned Arg) {
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+ os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
+ << ME->getSelector().getAsString() << "' cannot be nil.";
+
+ // Lazily create the BugType object for NilArg. This will be owned
+ // by the BugReporter object 'BR' once we call BR.EmitWarning.
+ if (!BT) BT = new APIMisuse("nil argument");
+
+ RangedBugReport *R = new RangedBugReport(*BT, os.str().c_str(), N);
+ R->addRange(ME->getArg(Arg)->getSourceRange());
+ BR.EmitReport(R);
+ }
+};
+
+} // end anonymous namespace
+
+
+GRSimpleAPICheck*
+clang::CreateBasicObjCFoundationChecks(ASTContext& Ctx,
+ GRStateManager* VMgr, BugReporter& BR) {
+
+ return new BasicObjCFoundationChecks(Ctx, VMgr, BR);
+}
+
+
+
+bool BasicObjCFoundationChecks::Audit(ExplodedNode<GRState>* N,
+ GRStateManager&) {
+
+ ObjCMessageExpr* ME =
+ cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
+
+ ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
+
+ if (!ReceiverType)
+ return false;
+
+ const char* name = ReceiverType->getDecl()->getIdentifier()->getName();
+
+ if (!name)
+ return false;
+
+ if (name[0] != 'N' || name[1] != 'S')
+ return false;
+
+ name += 2;
+
+ // FIXME: Make all of this faster.
+
+ if (isNSString(ReceiverType, name))
+ return AuditNSString(N, ME);
+
+ return false;
+}
+
+static inline bool isNil(SVal X) {
+ return isa<loc::ConcreteInt>(X);
+}
+
+//===----------------------------------------------------------------------===//
+// Error reporting.
+//===----------------------------------------------------------------------===//
+
+bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) {
+ ObjCMessageExpr* ME =
+ cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
+
+ Expr * E = ME->getArg(Arg);
+
+ if (isNil(GetSVal(N->getState(), E))) {
+ WarnNilArg(N, ME, Arg);
+ return true;
+ }
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// NSString checking.
+//===----------------------------------------------------------------------===//
+
+bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
+ const char* suffix) {
+
+ return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
+}
+
+bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N,
+ ObjCMessageExpr* ME) {
+
+ Selector S = ME->getSelector();
+
+ if (S.isUnarySelector())
+ return false;
+
+ // FIXME: This is going to be really slow doing these checks with
+ // lexical comparisons.
+
+ std::string name = S.getAsString();
+ assert (!name.empty());
+ const char* cstr = &name[0];
+ unsigned len = name.size();
+
+ switch (len) {
+ default:
+ break;
+ case 8:
+ if (!strcmp(cstr, "compare:"))
+ return CheckNilArg(N, 0);
+
+ break;
+
+ case 15:
+ // FIXME: Checking for initWithFormat: will not work in most cases
+ // yet because [NSString alloc] returns id, not NSString*. We will
+ // need support for tracking expected-type information in the analyzer
+ // to find these errors.
+ if (!strcmp(cstr, "initWithFormat:"))
+ return CheckNilArg(N, 0);
+
+ break;
+
+ case 16:
+ if (!strcmp(cstr, "compare:options:"))
+ return CheckNilArg(N, 0);
+
+ break;
+
+ case 22:
+ if (!strcmp(cstr, "compare:options:range:"))
+ return CheckNilArg(N, 0);
+
+ break;
+
+ case 23:
+
+ if (!strcmp(cstr, "caseInsensitiveCompare:"))
+ return CheckNilArg(N, 0);
+
+ break;
+
+ case 29:
+ if (!strcmp(cstr, "compare:options:range:locale:"))
+ return CheckNilArg(N, 0);
+
+ break;
+
+ case 37:
+ if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:"))
+ return CheckNilArg(N, 0);
+
+ break;
+ }
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Error reporting.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck {
+ APIMisuse* BT;
+
+ // FIXME: Either this should be refactored into GRSimpleAPICheck, or
+ // it should always be passed with a call to Audit. The latter
+ // approach makes this class more stateless.
+ ASTContext& Ctx;
+ IdentifierInfo* II;
+ GRStateManager* VMgr;
+ BugReporter& BR;
+
+ SVal GetSVal(const GRState* St, Expr* E) { return VMgr->GetSVal(St, E); }
+
+public:
+ AuditCFNumberCreate(ASTContext& ctx, GRStateManager* vmgr, BugReporter& br)
+ : BT(0), Ctx(ctx), II(&Ctx.Idents.get("CFNumberCreate")), VMgr(vmgr), BR(br){}
+
+ ~AuditCFNumberCreate() {}
+
+ bool Audit(ExplodedNode<GRState>* N, GRStateManager&);
+
+private:
+ void AddError(const TypedRegion* R, Expr* Ex, ExplodedNode<GRState> *N,
+ uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
+};
+} // end anonymous namespace
+
+enum CFNumberType {
+ kCFNumberSInt8Type = 1,
+ kCFNumberSInt16Type = 2,
+ kCFNumberSInt32Type = 3,
+ kCFNumberSInt64Type = 4,
+ kCFNumberFloat32Type = 5,
+ kCFNumberFloat64Type = 6,
+ kCFNumberCharType = 7,
+ kCFNumberShortType = 8,
+ kCFNumberIntType = 9,
+ kCFNumberLongType = 10,
+ kCFNumberLongLongType = 11,
+ kCFNumberFloatType = 12,
+ kCFNumberDoubleType = 13,
+ kCFNumberCFIndexType = 14,
+ kCFNumberNSIntegerType = 15,
+ kCFNumberCGFloatType = 16
+};
+
+namespace {
+ template<typename T>
+ class Optional {
+ bool IsKnown;
+ T Val;
+ public:
+ Optional() : IsKnown(false), Val(0) {}
+ Optional(const T& val) : IsKnown(true), Val(val) {}
+
+ bool isKnown() const { return IsKnown; }
+
+ const T& getValue() const {
+ assert (isKnown());
+ return Val;
+ }
+
+ operator const T&() const {
+ return getValue();
+ }
+ };
+}
+
+static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
+ static unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
+
+ if (i < kCFNumberCharType)
+ return FixedSize[i-1];
+
+ QualType T;
+
+ switch (i) {
+ case kCFNumberCharType: T = Ctx.CharTy; break;
+ case kCFNumberShortType: T = Ctx.ShortTy; break;
+ case kCFNumberIntType: T = Ctx.IntTy; break;
+ case kCFNumberLongType: T = Ctx.LongTy; break;
+ case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
+ case kCFNumberFloatType: T = Ctx.FloatTy; break;
+ case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
+ case kCFNumberCFIndexType:
+ case kCFNumberNSIntegerType:
+ case kCFNumberCGFloatType:
+ // FIXME: We need a way to map from names to Type*.
+ default:
+ return Optional<uint64_t>();
+ }
+
+ return Ctx.getTypeSize(T);
+}
+
+#if 0
+static const char* GetCFNumberTypeStr(uint64_t i) {
+ static const char* Names[] = {
+ "kCFNumberSInt8Type",
+ "kCFNumberSInt16Type",
+ "kCFNumberSInt32Type",
+ "kCFNumberSInt64Type",
+ "kCFNumberFloat32Type",
+ "kCFNumberFloat64Type",
+ "kCFNumberCharType",
+ "kCFNumberShortType",
+ "kCFNumberIntType",
+ "kCFNumberLongType",
+ "kCFNumberLongLongType",
+ "kCFNumberFloatType",
+ "kCFNumberDoubleType",
+ "kCFNumberCFIndexType",
+ "kCFNumberNSIntegerType",
+ "kCFNumberCGFloatType"
+ };
+
+ return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
+}
+#endif
+
+bool AuditCFNumberCreate::Audit(ExplodedNode<GRState>* N,GRStateManager&){
+ CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
+ Expr* Callee = CE->getCallee();
+ SVal CallV = GetSVal(N->getState(), Callee);
+ const FunctionDecl* FD = CallV.getAsFunctionDecl();
+
+ if (!FD || FD->getIdentifier() != II || CE->getNumArgs()!=3)
+ return false;
+
+ // Get the value of the "theType" argument.
+ SVal TheTypeVal = GetSVal(N->getState(), CE->getArg(1));
+
+ // FIXME: We really should allow ranges of valid theType values, and
+ // bifurcate the state appropriately.
+ nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
+
+ if (!V)
+ return false;
+
+ uint64_t NumberKind = V->getValue().getLimitedValue();
+ Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
+
+ // FIXME: In some cases we can emit an error.
+ if (!TargetSize.isKnown())
+ return false;
+
+ // Look at the value of the integer being passed by reference. Essentially
+ // we want to catch cases where the value passed in is not equal to the
+ // size of the type being created.
+ SVal TheValueExpr = GetSVal(N->getState(), CE->getArg(2));
+
+ // FIXME: Eventually we should handle arbitrary locations. We can do this
+ // by having an enhanced memory model that does low-level typing.
+ loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
+
+ if (!LV)
+ return false;
+
+ const TypedRegion* R = dyn_cast<TypedRegion>(LV->getRegion());
+ if (!R) return false;
+
+ while (const TypedViewRegion* ATR = dyn_cast<TypedViewRegion>(R)) {
+ R = dyn_cast<TypedRegion>(ATR->getSuperRegion());
+ if (!R) return false;
+ }
+
+ QualType T = Ctx.getCanonicalType(R->getValueType(Ctx));
+
+ // FIXME: If the pointee isn't an integer type, should we flag a warning?
+ // People can do weird stuff with pointers.
+
+ if (!T->isIntegerType())
+ return false;
+
+ uint64_t SourceSize = Ctx.getTypeSize(T);
+
+ // CHECK: is SourceSize == TargetSize
+
+ if (SourceSize == TargetSize)
+ return false;
+
+ AddError(R, CE->getArg(2), N, SourceSize, TargetSize, NumberKind);
+
+ // FIXME: We can actually create an abstract "CFNumber" object that has
+ // the bits initialized to the provided values.
+ return SourceSize < TargetSize;
+}
+
+void AuditCFNumberCreate::AddError(const TypedRegion* R, Expr* Ex,
+ ExplodedNode<GRState> *N,
+ uint64_t SourceSize, uint64_t TargetSize,
+ uint64_t NumberKind) {
+
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+
+ os << (SourceSize == 8 ? "An " : "A ")
+ << SourceSize << " bit integer is used to initialize a CFNumber "
+ "object that represents "
+ << (TargetSize == 8 ? "an " : "a ")
+ << TargetSize << " bit integer. ";
+
+ if (SourceSize < TargetSize)
+ os << (TargetSize - SourceSize)
+ << " bits of the CFNumber value will be garbage." ;
+ else
+ os << (SourceSize - TargetSize)
+ << " bits of the input integer will be lost.";
+
+ // Lazily create the BugType object. This will be owned
+ // by the BugReporter object 'BR' once we call BR.EmitWarning.
+ if (!BT) BT = new APIMisuse("Bad use of CFNumberCreate");
+ RangedBugReport *report = new RangedBugReport(*BT, os.str().c_str(), N);
+ report->addRange(Ex->getSourceRange());
+ BR.EmitReport(report);
+}
+
+GRSimpleAPICheck*
+clang::CreateAuditCFNumberCreate(ASTContext& Ctx,
+ GRStateManager* VMgr, BugReporter& BR) {
+ return new AuditCFNumberCreate(Ctx, VMgr, BR);
+}
+
+//===----------------------------------------------------------------------===//
+// Check registration.
+
+void clang::RegisterAppleChecks(GRExprEngine& Eng) {
+ ASTContext& Ctx = Eng.getContext();
+ GRStateManager* VMgr = &Eng.getStateManager();
+ BugReporter &BR = Eng.getBugReporter();
+
+ Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, VMgr, BR),
+ Stmt::ObjCMessageExprClass);
+
+ Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, VMgr, BR),
+ Stmt::CallExprClass);
+
+ RegisterNSErrorChecks(BR, Eng);
+}
diff --git a/lib/Analysis/BasicObjCFoundationChecks.h b/lib/Analysis/BasicObjCFoundationChecks.h
new file mode 100644
index 000000000000..6c594ea72199
--- /dev/null
+++ b/lib/Analysis/BasicObjCFoundationChecks.h
@@ -0,0 +1,47 @@
+//== BasicObjCFoundationChecks.h - Simple Apple-Foundation checks -*- 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 BasicObjCFoundationChecks, a class that encapsulates
+// a set of simple checks to run on Objective-C code using Apple's Foundation
+// classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
+#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/Support/Compiler.h"
+
+#ifndef LLVM_CLANG_ANALYSIS_BASICOBJCFOUNDATIONCHECKS
+#define LLVM_CLANG_ANALYSIS_BASICOBJCFOUNDATIONCHECKS
+
+namespace clang {
+
+class GRSimpleAPICheck;
+class ASTContext;
+class GRStateManager;
+class BugReporter;
+class GRExprEngine;
+
+GRSimpleAPICheck* CreateBasicObjCFoundationChecks(ASTContext& Ctx,
+ GRStateManager* VMgr,
+ BugReporter& BR);
+
+GRSimpleAPICheck* CreateAuditCFNumberCreate(ASTContext& Ctx,
+ GRStateManager* VMgr,
+ BugReporter& BR);
+
+void RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng);
+
+} // end clang namespace
+
+#endif
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp
new file mode 100644
index 000000000000..2dd46c385343
--- /dev/null
+++ b/lib/Analysis/BasicStore.cpp
@@ -0,0 +1,637 @@
+//== 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/ExprObjC.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Streams.h"
+
+using namespace clang;
+
+typedef llvm::ImmutableMap<const MemRegion*,SVal> BindingsTy;
+
+namespace {
+
+class VISIBILITY_HIDDEN BasicStoreSubRegionMap : public SubRegionMap {
+public:
+ BasicStoreSubRegionMap() {}
+
+ bool iterSubRegions(const MemRegion* R, Visitor& V) const {
+ return true; // Do nothing. No subregions.
+ }
+};
+
+class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager {
+ BindingsTy::Factory VBFactory;
+ const MemRegion* SelfRegion;
+
+public:
+ BasicStoreManager(GRStateManager& mgr)
+ : StoreManager(mgr),
+ VBFactory(mgr.getAllocator()),
+ SelfRegion(0) {}
+
+ ~BasicStoreManager() {}
+
+ SubRegionMap* getSubRegionMap(const GRState *state) {
+ return new BasicStoreSubRegionMap();
+ }
+
+ SVal Retrieve(const GRState *state, Loc loc, QualType T = QualType());
+
+ const GRState* Bind(const GRState* St, Loc L, SVal V) {
+ Store store = BindInternal(St->getStore(), L, V);
+ return StateMgr.MakeStateWithStore(St, store);
+ }
+
+ Store scanForIvars(Stmt *B, const Decl* SelfDecl, Store St);
+
+ Store BindInternal(Store St, Loc loc, SVal V);
+ Store Remove(Store St, Loc loc);
+ Store getInitialStore();
+
+ // FIXME: Investigate what is using this. This method should be removed.
+ virtual Loc getLoc(const VarDecl* VD) {
+ return Loc::MakeVal(MRMgr.getVarRegion(VD));
+ }
+
+ const GRState* BindCompoundLiteral(const GRState* St,
+ const CompoundLiteralExpr* CL,
+ SVal V) {
+ return St;
+ }
+
+ SVal getLValueVar(const GRState* St, const VarDecl* VD);
+ SVal getLValueString(const GRState* St, const StringLiteral* S);
+ SVal getLValueCompoundLiteral(const GRState* St,
+ const CompoundLiteralExpr* CL);
+ SVal getLValueIvar(const GRState* St, const ObjCIvarDecl* D, SVal Base);
+ SVal getLValueField(const GRState* St, SVal Base, const FieldDecl* D);
+ SVal getLValueElement(const GRState* St, QualType elementType,
+ SVal Base, SVal Offset);
+
+ /// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit
+ /// conversions between arrays and pointers.
+ SVal ArrayToPointer(Loc Array) { return Array; }
+
+ /// getSelfRegion - Returns the region for the 'self' (Objective-C) or
+ /// 'this' object (C++). When used when analyzing a normal function this
+ /// method returns NULL.
+ const MemRegion* getSelfRegion(Store) { return SelfRegion; }
+
+ /// RemoveDeadBindings - Scans a BasicStore of 'state' for dead values.
+ /// It returns a new Store with these values removed, and populates LSymbols
+ /// and DSymbols with the known set of live and dead symbols respectively.
+ Store
+ RemoveDeadBindings(const GRState* state, Stmt* Loc,
+ SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
+
+ void iterBindings(Store store, BindingsHandler& f);
+
+ const GRState* BindDecl(const GRState* St, const VarDecl* VD, SVal InitVal) {
+ Store store = BindDeclInternal(St->getStore(), VD, &InitVal);
+ return StateMgr.MakeStateWithStore(St, store);
+ }
+
+ const GRState* BindDeclWithNoInit(const GRState* St, const VarDecl* VD) {
+ Store store = BindDeclInternal(St->getStore(), VD, 0);
+ return StateMgr.MakeStateWithStore(St, store);
+ }
+
+ Store BindDeclInternal(Store store, const VarDecl* VD, SVal* InitVal);
+
+ static inline BindingsTy GetBindings(Store store) {
+ return BindingsTy(static_cast<const BindingsTy::TreeTy*>(store));
+ }
+
+ void print(Store store, std::ostream& Out, const char* nl, const char *sep);
+
+private:
+ ASTContext& getContext() { return StateMgr.getContext(); }
+};
+
+} // end anonymous namespace
+
+
+StoreManager* clang::CreateBasicStoreManager(GRStateManager& StMgr) {
+ return new BasicStoreManager(StMgr);
+}
+
+SVal BasicStoreManager::getLValueVar(const GRState* St, const VarDecl* VD) {
+ return Loc::MakeVal(MRMgr.getVarRegion(VD));
+}
+
+SVal BasicStoreManager::getLValueString(const GRState* St,
+ const StringLiteral* S) {
+ return Loc::MakeVal(MRMgr.getStringRegion(S));
+}
+
+SVal BasicStoreManager::getLValueCompoundLiteral(const GRState* St,
+ const CompoundLiteralExpr* CL){
+ return Loc::MakeVal(MRMgr.getCompoundLiteralRegion(CL));
+}
+
+SVal BasicStoreManager::getLValueIvar(const GRState* St, const ObjCIvarDecl* D,
+ SVal Base) {
+
+ if (Base.isUnknownOrUndef())
+ return Base;
+
+ Loc BaseL = cast<Loc>(Base);
+
+ if (isa<loc::MemRegionVal>(BaseL)) {
+ const MemRegion *BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
+
+ if (BaseR == SelfRegion)
+ return loc::MemRegionVal(MRMgr.getObjCIvarRegion(D, BaseR));
+ }
+
+ return UnknownVal();
+}
+
+SVal BasicStoreManager::getLValueField(const GRState* St, SVal Base,
+ const FieldDecl* D) {
+
+ if (Base.isUnknownOrUndef())
+ return Base;
+
+ Loc BaseL = cast<Loc>(Base);
+ const MemRegion* BaseR = 0;
+
+ switch(BaseL.getSubKind()) {
+ case loc::GotoLabelKind:
+ return UndefinedVal();
+
+ case loc::MemRegionKind:
+ BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
+ break;
+
+ case loc::ConcreteIntKind:
+ // While these seem funny, this can happen through casts.
+ // FIXME: What we should return is the field offset. For example,
+ // add the field offset to the integer value. That way funny things
+ // like this work properly: &(((struct foo *) 0xa)->f)
+ return Base;
+
+ default:
+ assert ("Unhandled Base.");
+ return Base;
+ }
+
+ return Loc::MakeVal(MRMgr.getFieldRegion(D, BaseR));
+}
+
+SVal BasicStoreManager::getLValueElement(const GRState* St,
+ QualType elementType,
+ SVal Base, SVal Offset) {
+
+ if (Base.isUnknownOrUndef())
+ return Base;
+
+ Loc BaseL = cast<Loc>(Base);
+ const TypedRegion* BaseR = 0;
+
+ switch(BaseL.getSubKind()) {
+ case loc::GotoLabelKind:
+ // Technically we can get here if people do funny things with casts.
+ return UndefinedVal();
+
+ case loc::MemRegionKind: {
+ const MemRegion *R = cast<loc::MemRegionVal>(BaseL).getRegion();
+
+ if (isa<ElementRegion>(R)) {
+ // int x;
+ // char* y = (char*) &x;
+ // 'y' => ElementRegion(0, VarRegion('x'))
+ // y[0] = 'a';
+ return Base;
+ }
+
+
+ if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+ BaseR = TR;
+ break;
+ }
+
+ if (const SymbolicRegion* SR = dyn_cast<SymbolicRegion>(R)) {
+ SymbolRef Sym = SR->getSymbol();
+ BaseR = MRMgr.getTypedViewRegion(Sym->getType(getContext()), SR);
+ }
+
+ break;
+ }
+
+ case loc::ConcreteIntKind:
+ // While these seem funny, this can happen through casts.
+ // FIXME: What we should return is the field offset. For example,
+ // add the field offset to the integer value. That way funny things
+ // like this work properly: &(((struct foo *) 0xa)->f)
+ return Base;
+
+ default:
+ assert ("Unhandled Base.");
+ return Base;
+ }
+
+ if (BaseR)
+ return Loc::MakeVal(MRMgr.getElementRegion(elementType, UnknownVal(),
+ BaseR));
+ else
+ return UnknownVal();
+}
+
+static bool isHigherOrderRawPtr(QualType T, ASTContext &C) {
+ bool foundPointer = false;
+ while (1) {
+ const PointerType *PT = T->getAsPointerType();
+ 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::Retrieve(const GRState* state, 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 (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ // Just support void**, void***, intptr_t*, intptr_t**, etc., for now.
+ // This is needed to handle OSCompareAndSwapPtr() and friends.
+ ASTContext &Ctx = StateMgr.getContext();
+ QualType T = ER->getLocationType(Ctx);
+
+ if (!isHigherOrderRawPtr(T, Ctx))
+ return UnknownVal();
+
+ // FIXME: Should check for element 0.
+ // Otherwise, strip the element region.
+ R = ER->getSuperRegion();
+ }
+
+ if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
+ return UnknownVal();
+
+ BindingsTy B = GetBindings(state->getStore());
+ BindingsTy::data_type* T = B.lookup(R);
+ return T ? *T : UnknownVal();
+ }
+
+ case loc::ConcreteIntKind:
+ // Some clients may call GetSVal with such an option simply because
+ // they are doing a quick scan through their Locs (potentially to
+ // invalidate their bindings). Just return Undefined.
+ return UndefinedVal();
+
+ default:
+ assert (false && "Invalid Loc.");
+ break;
+ }
+
+ return UnknownVal();
+}
+
+Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) {
+ switch (loc.getSubKind()) {
+ case loc::MemRegionKind: {
+ const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion();
+ ASTContext &C = StateMgr.getContext();
+
+ // 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(C);
+
+ if (isHigherOrderRawPtr(T, C))
+ R = ER->getSuperRegion();
+ }
+
+ if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
+ return store;
+
+ // We only track bindings to self.ivar.
+ if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R))
+ if (IVR->getSuperRegion() != SelfRegion)
+ return store;
+
+ 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 (const TypedRegion *TyR = dyn_cast<TypedRegion>(R)) {
+ if (TyR->isBoundable(C) &&
+ Loc::IsLocType(TyR->getValueType(C)))
+ V = X->getLoc();
+ }
+ }
+
+ BindingsTy B = GetBindings(store);
+ return V.isUnknown()
+ ? VBFactory.Remove(B, R).getRoot()
+ : VBFactory.Add(B, R, V).getRoot();
+ }
+ default:
+ assert ("SetSVal for given Loc type not yet implemented.");
+ return store;
+ }
+}
+
+Store 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)))
+ return store;
+
+ return VBFactory.Remove(GetBindings(store), R).getRoot();
+ }
+ default:
+ assert ("Remove for given Loc type not yet implemented.");
+ return store;
+ }
+}
+
+Store
+BasicStoreManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
+ SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
+{
+
+ Store store = state->getStore();
+ 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(Loc, VR->getDecl()))
+ RegionRoots.push_back(VR);
+ else
+ continue;
+ }
+ else if (isa<ObjCIvarRegion>(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)) {
+ if (Marked.count(MR))
+ break;
+
+ Marked.insert(MR);
+ SVal X = Retrieve(state, 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.
+ for (BindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) {
+ const MemRegion* R = I.getKey();
+
+ if (!Marked.count(R)) {
+ store = Remove(store, Loc::MakeVal(R));
+ SVal X = I.getData();
+
+ for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
+ SymReaper.maybeDead(*SI);
+ }
+ }
+
+ return store;
+}
+
+Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl, Store St) {
+ 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 MemRegion *IVR = MRMgr.getObjCIvarRegion(IV->getDecl(),
+ SelfRegion);
+ SVal X = ValMgr.getRegionValueSymbolVal(IVR);
+ St = BindInternal(St, Loc::MakeVal(IVR), X);
+ }
+ }
+ }
+ else
+ St = scanForIvars(*CI, SelfDecl, St);
+ }
+
+ return St;
+}
+
+Store BasicStoreManager::getInitialStore() {
+ // 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 = StateMgr.getLiveVariables().getAnalysisData();
+ Store St = VBFactory.GetEmptyMap().getRoot();
+
+ for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) {
+ NamedDecl* ND = const_cast<NamedDecl*>(I->first);
+
+ // Handle implicit parameters.
+ if (ImplicitParamDecl* PD = dyn_cast<ImplicitParamDecl>(ND)) {
+ const Decl& CD = StateMgr.getCodeDecl();
+ if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CD)) {
+ if (MD->getSelfDecl() == PD) {
+ // Create a region for "self".
+ assert (SelfRegion == 0);
+ SelfRegion = MRMgr.getObjCObjectRegion(MD->getClassInterface(),
+ MRMgr.getHeapRegion());
+
+ St = BindInternal(St, Loc::MakeVal(MRMgr.getVarRegion(PD)),
+ Loc::MakeVal(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(getContext()), PD, St);
+ }
+ }
+ }
+ else if (VarDecl* VD = dyn_cast<VarDecl>(ND)) {
+ // Punt on static variables for now.
+ if (VD->getStorageClass() == VarDecl::Static)
+ continue;
+
+ // Only handle simple types that we can symbolicate.
+ if (!SymbolManager::canSymbolicate(VD->getType()))
+ continue;
+
+ // Initialize globals and parameters to symbolic values.
+ // Initialize local variables to undefined.
+ const MemRegion *R = StateMgr.getRegion(VD);
+ SVal X = (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD) ||
+ isa<ImplicitParamDecl>(VD))
+ ? ValMgr.getRegionValueSymbolVal(R)
+ : UndefinedVal();
+
+ St = BindInternal(St, Loc::MakeVal(R), X);
+ }
+ }
+ return St;
+}
+
+Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD,
+ SVal* InitVal) {
+
+ BasicValueFactory& BasicVals = StateMgr.getBasicVals();
+
+ // BasicStore does not model arrays and structs.
+ if (VD->getType()->isArrayType() || VD->getType()->isStructureType())
+ return store;
+
+ 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() == VarDecl::Static &&
+ VD->isFileVarDecl()));
+
+ // Process static variables.
+ if (VD->getStorageClass() == VarDecl::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))
+ store = BindInternal(store, getLoc(VD),
+ loc::ConcreteInt(BasicVals.getValue(0, T)));
+ else if (T->isIntegerType())
+ store = BindInternal(store, getLoc(VD),
+ nonloc::ConcreteInt(BasicVals.getValue(0, T)));
+ else {
+ // assert(0 && "ignore other types of variables");
+ }
+ } else {
+ store = BindInternal(store, getLoc(VD), *InitVal);
+ }
+ }
+ } else {
+ // Process local scalar variables.
+ QualType T = VD->getType();
+ if (Loc::IsLocType(T) || T->isIntegerType()) {
+ SVal V = InitVal ? *InitVal : UndefinedVal();
+ store = BindInternal(store, getLoc(VD), V);
+ }
+ }
+
+ return store;
+}
+
+void BasicStoreManager::print(Store store, std::ostream& O,
+ const char* nl, const char *sep) {
+
+ llvm::raw_os_ostream Out(O);
+ 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().print(Out);
+ }
+}
+
+
+void BasicStoreManager::iterBindings(Store store, BindingsHandler& f) {
+ BindingsTy B = GetBindings(store);
+
+ for (BindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I)
+ f.HandleBinding(*this, store, I.getKey(), I.getData());
+
+}
+
+StoreManager::BindingsHandler::~BindingsHandler() {}
diff --git a/lib/Analysis/BasicValueFactory.cpp b/lib/Analysis/BasicValueFactory.cpp
new file mode 100644
index 000000000000..72ad0a5ed8f1
--- /dev/null
+++ b/lib/Analysis/BasicValueFactory.cpp
@@ -0,0 +1,264 @@
+//=== BasicValueFactory.cpp - Basic values for Path Sens 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 BasicValueFactory, a class that manages the lifetime
+// of APSInt objects and symbolic constraints used by GRExprEngine
+// and related classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/BasicValueFactory.h"
+
+using namespace clang;
+
+void CompoundValData::Profile(llvm::FoldingSetNodeID& ID, QualType T,
+ llvm::ImmutableList<SVal> L) {
+ T.Profile(ID);
+ ID.AddPointer(L.getInternalPointer());
+}
+
+typedef std::pair<SVal, uintptr_t> SValData;
+typedef std::pair<SVal, SVal> SValPair;
+
+namespace llvm {
+template<> struct FoldingSetTrait<SValData> {
+ static inline void Profile(const SValData& X, llvm::FoldingSetNodeID& ID) {
+ X.first.Profile(ID);
+ ID.AddPointer( (void*) X.second);
+ }
+};
+
+template<> struct FoldingSetTrait<SValPair> {
+ static inline void Profile(const SValPair& X, llvm::FoldingSetNodeID& ID) {
+ X.first.Profile(ID);
+ X.second.Profile(ID);
+ }
+};
+}
+
+typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<SValData> >
+ PersistentSValsTy;
+
+typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<SValPair> >
+ PersistentSValPairsTy;
+
+BasicValueFactory::~BasicValueFactory() {
+ // Note that the dstor for the contents of APSIntSet will never be called,
+ // so we iterate over the set and invoke the dstor for each APSInt. This
+ // frees an aux. memory allocated to represent very large constants.
+ for (APSIntSetTy::iterator I=APSIntSet.begin(), E=APSIntSet.end(); I!=E; ++I)
+ I->getValue().~APSInt();
+
+ delete (PersistentSValsTy*) PersistentSVals;
+ delete (PersistentSValPairsTy*) PersistentSValPairs;
+}
+
+const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) {
+ llvm::FoldingSetNodeID ID;
+ void* InsertPos;
+ typedef llvm::FoldingSetNodeWrapper<llvm::APSInt> FoldNodeTy;
+
+ X.Profile(ID);
+ FoldNodeTy* P = APSIntSet.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (!P) {
+ P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>();
+ new (P) FoldNodeTy(X);
+ APSIntSet.InsertNode(P, InsertPos);
+ }
+
+ return *P;
+}
+
+const llvm::APSInt& BasicValueFactory::getValue(const llvm::APInt& X,
+ bool isUnsigned) {
+ llvm::APSInt V(X, isUnsigned);
+ return getValue(V);
+}
+
+const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, unsigned BitWidth,
+ bool isUnsigned) {
+ llvm::APSInt V(BitWidth, isUnsigned);
+ V = X;
+ return getValue(V);
+}
+
+const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, QualType T) {
+
+ unsigned bits = Ctx.getTypeSize(T);
+ llvm::APSInt V(bits, T->isUnsignedIntegerType() || Loc::IsLocType(T));
+ V = X;
+ return getValue(V);
+}
+
+const CompoundValData*
+BasicValueFactory::getCompoundValData(QualType T,
+ llvm::ImmutableList<SVal> Vals) {
+
+ llvm::FoldingSetNodeID ID;
+ CompoundValData::Profile(ID, T, Vals);
+ void* InsertPos;
+
+ CompoundValData* D = CompoundValDataSet.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (!D) {
+ D = (CompoundValData*) BPAlloc.Allocate<CompoundValData>();
+ new (D) CompoundValData(T, Vals);
+ CompoundValDataSet.InsertNode(D, InsertPos);
+ }
+
+ return D;
+}
+
+const llvm::APSInt*
+BasicValueFactory::EvaluateAPSInt(BinaryOperator::Opcode Op,
+ const llvm::APSInt& V1, const llvm::APSInt& V2) {
+
+ switch (Op) {
+ default:
+ assert (false && "Invalid Opcode.");
+
+ case BinaryOperator::Mul:
+ return &getValue( V1 * V2 );
+
+ case BinaryOperator::Div:
+ return &getValue( V1 / V2 );
+
+ case BinaryOperator::Rem:
+ return &getValue( V1 % V2 );
+
+ case BinaryOperator::Add:
+ return &getValue( V1 + V2 );
+
+ case BinaryOperator::Sub:
+ return &getValue( V1 - V2 );
+
+ case BinaryOperator::Shl: {
+
+ // FIXME: This logic should probably go higher up, where we can
+ // test these conditions symbolically.
+
+ // FIXME: Expand these checks to include all undefined behavior.
+
+ if (V2.isSigned() && V2.isNegative())
+ return NULL;
+
+ uint64_t Amt = V2.getZExtValue();
+
+ if (Amt > V1.getBitWidth())
+ return NULL;
+
+ return &getValue( V1.operator<<( (unsigned) Amt ));
+ }
+
+ case BinaryOperator::Shr: {
+
+ // FIXME: This logic should probably go higher up, where we can
+ // test these conditions symbolically.
+
+ // FIXME: Expand these checks to include all undefined behavior.
+
+ if (V2.isSigned() && V2.isNegative())
+ return NULL;
+
+ uint64_t Amt = V2.getZExtValue();
+
+ if (Amt > V1.getBitWidth())
+ return NULL;
+
+ return &getValue( V1.operator>>( (unsigned) Amt ));
+ }
+
+ case BinaryOperator::LT:
+ return &getTruthValue( V1 < V2 );
+
+ case BinaryOperator::GT:
+ return &getTruthValue( V1 > V2 );
+
+ case BinaryOperator::LE:
+ return &getTruthValue( V1 <= V2 );
+
+ case BinaryOperator::GE:
+ return &getTruthValue( V1 >= V2 );
+
+ case BinaryOperator::EQ:
+ return &getTruthValue( V1 == V2 );
+
+ case BinaryOperator::NE:
+ return &getTruthValue( V1 != V2 );
+
+ // Note: LAnd, LOr, Comma are handled specially by higher-level logic.
+
+ case BinaryOperator::And:
+ return &getValue( V1 & V2 );
+
+ case BinaryOperator::Or:
+ return &getValue( V1 | V2 );
+
+ case BinaryOperator::Xor:
+ return &getValue( V1 ^ V2 );
+ }
+}
+
+
+const std::pair<SVal, uintptr_t>&
+BasicValueFactory::getPersistentSValWithData(const SVal& V, uintptr_t Data) {
+
+ // Lazily create the folding set.
+ if (!PersistentSVals) PersistentSVals = new PersistentSValsTy();
+
+ llvm::FoldingSetNodeID ID;
+ void* InsertPos;
+ V.Profile(ID);
+ ID.AddPointer((void*) Data);
+
+ PersistentSValsTy& Map = *((PersistentSValsTy*) PersistentSVals);
+
+ typedef llvm::FoldingSetNodeWrapper<SValData> FoldNodeTy;
+ FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (!P) {
+ P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>();
+ new (P) FoldNodeTy(std::make_pair(V, Data));
+ Map.InsertNode(P, InsertPos);
+ }
+
+ return P->getValue();
+}
+
+const std::pair<SVal, SVal>&
+BasicValueFactory::getPersistentSValPair(const SVal& V1, const SVal& V2) {
+
+ // Lazily create the folding set.
+ if (!PersistentSValPairs) PersistentSValPairs = new PersistentSValPairsTy();
+
+ llvm::FoldingSetNodeID ID;
+ void* InsertPos;
+ V1.Profile(ID);
+ V2.Profile(ID);
+
+ PersistentSValPairsTy& Map = *((PersistentSValPairsTy*) PersistentSValPairs);
+
+ typedef llvm::FoldingSetNodeWrapper<SValPair> FoldNodeTy;
+ FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (!P) {
+ P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>();
+ new (P) FoldNodeTy(std::make_pair(V1, V2));
+ Map.InsertNode(P, InsertPos);
+ }
+
+ return P->getValue();
+}
+
+const SVal* BasicValueFactory::getPersistentSVal(SVal X) {
+ return &getPersistentSValWithData(X, 0).first;
+}
+
+
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
new file mode 100644
index 000000000000..32998e1c4256
--- /dev/null
+++ b/lib/Analysis/BugReporter.cpp
@@ -0,0 +1,1697 @@
+// BugReporter.cpp - Generate PathDiagnostics for Bugs ------------*- 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 BugReporter, a utility class for generating
+// PathDiagnostics for analyses based on GRSimpleVals.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/CFG.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/OwningPtr.h"
+#include <queue>
+
+using namespace clang;
+
+BugReporterVisitor::~BugReporterVisitor() {}
+BugReporterContext::~BugReporterContext() {
+ for (visitor_iterator I = visitor_begin(), E = visitor_end(); I != E; ++I)
+ if ((*I)->isOwnedByReporterContext()) delete *I;
+}
+
+//===----------------------------------------------------------------------===//
+// Helper routines for walking the ExplodedGraph and fetching statements.
+//===----------------------------------------------------------------------===//
+
+static inline Stmt* GetStmt(ProgramPoint P) {
+ if (const PostStmt* PS = dyn_cast<PostStmt>(&P))
+ return PS->getStmt();
+ else if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P))
+ return BE->getSrc()->getTerminator();
+
+ return 0;
+}
+
+static inline const ExplodedNode<GRState>*
+GetPredecessorNode(const ExplodedNode<GRState>* N) {
+ return N->pred_empty() ? NULL : *(N->pred_begin());
+}
+
+static inline const ExplodedNode<GRState>*
+GetSuccessorNode(const ExplodedNode<GRState>* N) {
+ return N->succ_empty() ? NULL : *(N->succ_begin());
+}
+
+static Stmt* GetPreviousStmt(const ExplodedNode<GRState>* N) {
+ for (N = GetPredecessorNode(N); N; N = GetPredecessorNode(N))
+ if (Stmt *S = GetStmt(N->getLocation()))
+ return S;
+
+ return 0;
+}
+
+static Stmt* GetNextStmt(const ExplodedNode<GRState>* N) {
+ for (N = GetSuccessorNode(N); N; N = GetSuccessorNode(N))
+ if (Stmt *S = GetStmt(N->getLocation())) {
+ // Check if the statement is '?' or '&&'/'||'. These are "merges",
+ // not actual statement points.
+ switch (S->getStmtClass()) {
+ case Stmt::ChooseExprClass:
+ case Stmt::ConditionalOperatorClass: continue;
+ case Stmt::BinaryOperatorClass: {
+ BinaryOperator::Opcode Op = cast<BinaryOperator>(S)->getOpcode();
+ if (Op == BinaryOperator::LAnd || Op == BinaryOperator::LOr)
+ continue;
+ break;
+ }
+ default:
+ break;
+ }
+ return S;
+ }
+
+ return 0;
+}
+
+static inline Stmt* GetCurrentOrPreviousStmt(const ExplodedNode<GRState>* N) {
+ if (Stmt *S = GetStmt(N->getLocation()))
+ return S;
+
+ return GetPreviousStmt(N);
+}
+
+static inline Stmt* GetCurrentOrNextStmt(const ExplodedNode<GRState>* N) {
+ if (Stmt *S = GetStmt(N->getLocation()))
+ return S;
+
+ return GetNextStmt(N);
+}
+
+//===----------------------------------------------------------------------===//
+// PathDiagnosticBuilder and its associated routines and helper objects.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::DenseMap<const ExplodedNode<GRState>*,
+const ExplodedNode<GRState>*> NodeBackMap;
+
+namespace {
+class VISIBILITY_HIDDEN NodeMapClosure : public BugReport::NodeResolver {
+ NodeBackMap& M;
+public:
+ NodeMapClosure(NodeBackMap *m) : M(*m) {}
+ ~NodeMapClosure() {}
+
+ const ExplodedNode<GRState>* getOriginalNode(const ExplodedNode<GRState>* N) {
+ NodeBackMap::iterator I = M.find(N);
+ return I == M.end() ? 0 : I->second;
+ }
+};
+
+class VISIBILITY_HIDDEN PathDiagnosticBuilder : public BugReporterContext {
+ BugReport *R;
+ PathDiagnosticClient *PDC;
+ llvm::OwningPtr<ParentMap> PM;
+ NodeMapClosure NMC;
+public:
+ PathDiagnosticBuilder(GRBugReporter &br,
+ BugReport *r, NodeBackMap *Backmap,
+ PathDiagnosticClient *pdc)
+ : BugReporterContext(br),
+ R(r), PDC(pdc), NMC(Backmap)
+ {
+ addVisitor(R);
+ }
+
+ PathDiagnosticLocation ExecutionContinues(const ExplodedNode<GRState>* N);
+
+ PathDiagnosticLocation ExecutionContinues(llvm::raw_string_ostream& os,
+ const ExplodedNode<GRState>* N);
+
+ ParentMap& getParentMap() {
+ if (PM.get() == 0)
+ PM.reset(new ParentMap(getCodeDecl().getBody(getASTContext())));
+ return *PM.get();
+ }
+
+ const Stmt *getParent(const Stmt *S) {
+ return getParentMap().getParent(S);
+ }
+
+ virtual NodeMapClosure& getNodeResolver() { return NMC; }
+ BugReport& getReport() { return *R; }
+
+ PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S);
+
+ PathDiagnosticLocation
+ getEnclosingStmtLocation(const PathDiagnosticLocation &L) {
+ if (const Stmt *S = L.asStmt())
+ return getEnclosingStmtLocation(S);
+
+ return L;
+ }
+
+ PathDiagnosticClient::PathGenerationScheme getGenerationScheme() const {
+ return PDC ? PDC->getGenerationScheme() : PathDiagnosticClient::Extensive;
+ }
+
+ bool supportsLogicalOpControlFlow() const {
+ return PDC ? PDC->supportsLogicalOpControlFlow() : true;
+ }
+};
+} // end anonymous namespace
+
+PathDiagnosticLocation
+PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode<GRState>* N) {
+ if (Stmt *S = GetNextStmt(N))
+ return PathDiagnosticLocation(S, getSourceManager());
+
+ return FullSourceLoc(getCodeDecl().getBodyRBrace(getASTContext()),
+ getSourceManager());
+}
+
+PathDiagnosticLocation
+PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream& os,
+ const ExplodedNode<GRState>* N) {
+
+ // Slow, but probably doesn't matter.
+ if (os.str().empty())
+ os << ' ';
+
+ const PathDiagnosticLocation &Loc = ExecutionContinues(N);
+
+ if (Loc.asStmt())
+ os << "Execution continues on line "
+ << getSourceManager().getInstantiationLineNumber(Loc.asLocation())
+ << '.';
+ else
+ os << "Execution jumps to the end of the "
+ << (isa<ObjCMethodDecl>(getCodeDecl()) ? "method" : "function") << '.';
+
+ return Loc;
+}
+
+static bool IsNested(const Stmt *S, ParentMap &PM) {
+ if (isa<Expr>(S) && PM.isConsumedExpr(cast<Expr>(S)))
+ return true;
+
+ const Stmt *Parent = PM.getParentIgnoreParens(S);
+
+ if (Parent)
+ switch (Parent->getStmtClass()) {
+ case Stmt::ForStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::WhileStmtClass:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+PathDiagnosticLocation
+PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
+ assert(S && "Null Stmt* passed to getEnclosingStmtLocation");
+ ParentMap &P = getParentMap();
+ SourceManager &SMgr = getSourceManager();
+
+ while (IsNested(S, P)) {
+ const Stmt *Parent = P.getParentIgnoreParens(S);
+
+ if (!Parent)
+ break;
+
+ switch (Parent->getStmtClass()) {
+ case Stmt::BinaryOperatorClass: {
+ const BinaryOperator *B = cast<BinaryOperator>(Parent);
+ if (B->isLogicalOp())
+ return PathDiagnosticLocation(S, SMgr);
+ break;
+ }
+ case Stmt::CompoundStmtClass:
+ case Stmt::StmtExprClass:
+ return PathDiagnosticLocation(S, SMgr);
+ 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);
+ else
+ return PathDiagnosticLocation(S, SMgr);
+ case Stmt::ConditionalOperatorClass:
+ // For '?', if we are referring to condition, just have the edge point
+ // to the entire '?' expression.
+ if (cast<ConditionalOperator>(Parent)->getCond() == S)
+ return PathDiagnosticLocation(Parent, SMgr);
+ else
+ return PathDiagnosticLocation(S, SMgr);
+ case Stmt::DoStmtClass:
+ return PathDiagnosticLocation(S, SMgr);
+ case Stmt::ForStmtClass:
+ if (cast<ForStmt>(Parent)->getBody() == S)
+ return PathDiagnosticLocation(S, SMgr);
+ break;
+ case Stmt::IfStmtClass:
+ if (cast<IfStmt>(Parent)->getCond() != S)
+ return PathDiagnosticLocation(S, SMgr);
+ break;
+ case Stmt::ObjCForCollectionStmtClass:
+ if (cast<ObjCForCollectionStmt>(Parent)->getBody() == S)
+ return PathDiagnosticLocation(S, SMgr);
+ break;
+ case Stmt::WhileStmtClass:
+ if (cast<WhileStmt>(Parent)->getCond() != S)
+ return PathDiagnosticLocation(S, SMgr);
+ break;
+ default:
+ break;
+ }
+
+ S = Parent;
+ }
+
+ assert(S && "Cannot have null Stmt for PathDiagnosticLocation");
+
+ // Special case: DeclStmts can appear in for statement declarations, in which
+ // case the ForStmt is the context.
+ if (isa<DeclStmt>(S)) {
+ if (const Stmt *Parent = P.getParent(S)) {
+ switch (Parent->getStmtClass()) {
+ case Stmt::ForStmtClass:
+ case Stmt::ObjCForCollectionStmtClass:
+ return PathDiagnosticLocation(Parent, SMgr);
+ default:
+ break;
+ }
+ }
+ }
+ else if (isa<BinaryOperator>(S)) {
+ // Special case: the binary operator represents the initialization
+ // code in a for statement (this can happen when the variable being
+ // initialized is an old variable.
+ if (const ForStmt *FS =
+ dyn_cast_or_null<ForStmt>(P.getParentIgnoreParens(S))) {
+ if (FS->getInit() == S)
+ return PathDiagnosticLocation(FS, SMgr);
+ }
+ }
+
+ return PathDiagnosticLocation(S, SMgr);
+}
+
+//===----------------------------------------------------------------------===//
+// ScanNotableSymbols: closure-like callback for scanning Store bindings.
+//===----------------------------------------------------------------------===//
+
+static const VarDecl*
+GetMostRecentVarDeclBinding(const ExplodedNode<GRState>* N,
+ GRStateManager& VMgr, SVal X) {
+
+ for ( ; N ; N = N->pred_empty() ? 0 : *N->pred_begin()) {
+
+ ProgramPoint P = N->getLocation();
+
+ if (!isa<PostStmt>(P))
+ continue;
+
+ DeclRefExpr* DR = dyn_cast<DeclRefExpr>(cast<PostStmt>(P).getStmt());
+
+ if (!DR)
+ continue;
+
+ SVal Y = VMgr.GetSVal(N->getState(), DR);
+
+ if (X != Y)
+ continue;
+
+ VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl());
+
+ if (!VD)
+ continue;
+
+ return VD;
+ }
+
+ return 0;
+}
+
+namespace {
+class VISIBILITY_HIDDEN NotableSymbolHandler
+: public StoreManager::BindingsHandler {
+
+ SymbolRef Sym;
+ const GRState* PrevSt;
+ const Stmt* S;
+ GRStateManager& VMgr;
+ const ExplodedNode<GRState>* Pred;
+ PathDiagnostic& PD;
+ BugReporter& BR;
+
+public:
+
+ NotableSymbolHandler(SymbolRef sym, const GRState* prevst, const Stmt* s,
+ GRStateManager& vmgr, const ExplodedNode<GRState>* 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) {
+
+ SymbolRef ScanSym = V.getAsSymbol();
+
+ if (ScanSym != Sym)
+ return true;
+
+ // Check if the previous state has this binding.
+ SVal X = VMgr.GetSVal(PrevSt, loc::MemRegionVal(R));
+
+ if (X == V) // Same binding?
+ return true;
+
+ // Different binding. Only handle assignments for now. We don't pull
+ // this check out of the loop because we will eventually handle other
+ // cases.
+
+ VarDecl *VD = 0;
+
+ if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
+ if (!B->isAssignmentOp())
+ return true;
+
+ // What variable did we assign to?
+ 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)) {
+ // FIXME: Eventually CFGs won't have DeclStmts. Right now we
+ // assume that each DeclStmt has a single Decl. This invariant
+ // holds by contruction in the CFG.
+ VD = dyn_cast<VarDecl>(*DS->decl_begin());
+ }
+
+ if (!VD)
+ return true;
+
+ // What is the most recently referenced variable with this binding?
+ 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));
+ }
+
+ return true;
+ }
+};
+}
+
+static void HandleNotableSymbol(const ExplodedNode<GRState>* N,
+ const Stmt* S,
+ SymbolRef Sym, BugReporter& BR,
+ PathDiagnostic& PD) {
+
+ const ExplodedNode<GRState>* Pred = N->pred_empty() ? 0 : *N->pred_begin();
+ const GRState* 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();
+ NotableSymbolHandler H(Sym, PrevSt, S, VMgr, Pred, PD, BR);
+ cast<GRBugReporter>(BR).getStateManager().iterBindings(N->getState(), H);
+}
+
+namespace {
+class VISIBILITY_HIDDEN ScanNotableSymbols
+: public StoreManager::BindingsHandler {
+
+ llvm::SmallSet<SymbolRef, 10> AlreadyProcessed;
+ const ExplodedNode<GRState>* N;
+ Stmt* S;
+ GRBugReporter& BR;
+ PathDiagnostic& PD;
+
+public:
+ ScanNotableSymbols(const ExplodedNode<GRState>* n, Stmt* s, GRBugReporter& br,
+ PathDiagnostic& pd)
+ : N(n), S(s), BR(br), PD(pd) {}
+
+ bool HandleBinding(StoreManager& SMgr, Store store,
+ const MemRegion* R, SVal V) {
+
+ SymbolRef ScanSym = V.getAsSymbol();
+
+ if (!ScanSym)
+ return true;
+
+ if (!BR.isNotable(ScanSym))
+ return true;
+
+ if (AlreadyProcessed.count(ScanSym))
+ return true;
+
+ AlreadyProcessed.insert(ScanSym);
+
+ HandleNotableSymbol(N, S, ScanSym, BR, PD);
+ return true;
+ }
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// "Minimal" path diagnostic generation algorithm.
+//===----------------------------------------------------------------------===//
+
+static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM);
+
+static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
+ PathDiagnosticBuilder &PDB,
+ const ExplodedNode<GRState> *N) {
+
+ SourceManager& SMgr = PDB.getSourceManager();
+ const ExplodedNode<GRState>* NextNode = N->pred_empty()
+ ? NULL : *(N->pred_begin());
+ while (NextNode) {
+ N = NextNode;
+ NextNode = GetPredecessorNode(N);
+
+ ProgramPoint P = N->getLocation();
+
+ if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {
+ CFGBlock* Src = BE->getSrc();
+ CFGBlock* Dst = BE->getDst();
+ Stmt* T = Src->getTerminator();
+
+ if (!T)
+ continue;
+
+ FullSourceLoc Start(T->getLocStart(), SMgr);
+
+ switch (T->getStmtClass()) {
+ default:
+ break;
+
+ case Stmt::GotoStmtClass:
+ case Stmt::IndirectGotoStmtClass: {
+ Stmt* S = GetNextStmt(N);
+
+ if (!S)
+ continue;
+
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+ const PathDiagnosticLocation &End = PDB.getEnclosingStmtLocation(S);
+
+ os << "Control jumps to line "
+ << End.asLocation().getInstantiationLineNumber();
+ PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ os.str()));
+ break;
+ }
+
+ case Stmt::SwitchStmtClass: {
+ // Figure out what case arm we took.
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+
+ if (Stmt* S = Dst->getLabel()) {
+ PathDiagnosticLocation End(S, SMgr);
+
+ switch (S->getStmtClass()) {
+ default:
+ os << "No cases match in the switch statement. "
+ "Control jumps to line "
+ << End.asLocation().getInstantiationLineNumber();
+ break;
+ case Stmt::DefaultStmtClass:
+ os << "Control jumps to the 'default' case at line "
+ << End.asLocation().getInstantiationLineNumber();
+ break;
+
+ case Stmt::CaseStmtClass: {
+ os << "Control jumps to 'case ";
+ CaseStmt* Case = cast<CaseStmt>(S);
+ Expr* LHS = Case->getLHS()->IgnoreParenCasts();
+
+ // Determine if it is an enum.
+ bool GetRawInt = true;
+
+ if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(LHS)) {
+ // FIXME: Maybe this should be an assertion. Are there cases
+ // were it is not an EnumConstantDecl?
+ EnumConstantDecl* D =
+ dyn_cast<EnumConstantDecl>(DR->getDecl());
+
+ if (D) {
+ GetRawInt = false;
+ os << D->getNameAsString();
+ }
+ }
+
+ if (GetRawInt)
+ os << LHS->EvaluateAsInt(PDB.getASTContext());
+
+ os << ":' at line "
+ << End.asLocation().getInstantiationLineNumber();
+ break;
+ }
+ }
+ PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ os.str()));
+ }
+ else {
+ os << "'Default' branch taken. ";
+ const PathDiagnosticLocation &End = PDB.ExecutionContinues(os, N);
+ PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ os.str()));
+ }
+
+ break;
+ }
+
+ case Stmt::BreakStmtClass:
+ case Stmt::ContinueStmtClass: {
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+ PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
+ PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ os.str()));
+ break;
+ }
+
+ // Determine control-flow for ternary '?'.
+ case Stmt::ConditionalOperatorClass: {
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+ os << "'?' condition is ";
+
+ if (*(Src->succ_begin()+1) == Dst)
+ os << "false";
+ else
+ os << "true";
+
+ PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+
+ if (const Stmt *S = End.asStmt())
+ End = PDB.getEnclosingStmtLocation(S);
+
+ PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ os.str()));
+ break;
+ }
+
+ // Determine control-flow for short-circuited '&&' and '||'.
+ case Stmt::BinaryOperatorClass: {
+ if (!PDB.supportsLogicalOpControlFlow())
+ break;
+
+ BinaryOperator *B = cast<BinaryOperator>(T);
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+ os << "Left side of '";
+
+ if (B->getOpcode() == BinaryOperator::LAnd) {
+ os << "&&" << "' is ";
+
+ if (*(Src->succ_begin()+1) == Dst) {
+ os << "false";
+ PathDiagnosticLocation End(B->getLHS(), SMgr);
+ PathDiagnosticLocation Start(B->getOperatorLoc(), SMgr);
+ PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ os.str()));
+ }
+ else {
+ os << "true";
+ PathDiagnosticLocation Start(B->getLHS(), SMgr);
+ PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+ PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ os.str()));
+ }
+ }
+ else {
+ assert(B->getOpcode() == BinaryOperator::LOr);
+ os << "||" << "' is ";
+
+ if (*(Src->succ_begin()+1) == Dst) {
+ os << "false";
+ PathDiagnosticLocation Start(B->getLHS(), SMgr);
+ 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);
+ PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ os.str()));
+ }
+ }
+
+ break;
+ }
+
+ case Stmt::DoStmtClass: {
+ if (*(Src->succ_begin()) == Dst) {
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+
+ os << "Loop condition is true. ";
+ PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
+
+ if (const Stmt *S = End.asStmt())
+ End = PDB.getEnclosingStmtLocation(S);
+
+ PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ os.str()));
+ }
+ else {
+ PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+
+ if (const Stmt *S = End.asStmt())
+ End = PDB.getEnclosingStmtLocation(S);
+
+ PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ "Loop condition is false. Exiting loop"));
+ }
+
+ break;
+ }
+
+ case Stmt::WhileStmtClass:
+ case Stmt::ForStmtClass: {
+ if (*(Src->succ_begin()+1) == Dst) {
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+
+ os << "Loop condition is false. ";
+ PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
+ if (const Stmt *S = End.asStmt())
+ End = PDB.getEnclosingStmtLocation(S);
+
+ PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ os.str()));
+ }
+ else {
+ PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+ if (const Stmt *S = End.asStmt())
+ End = PDB.getEnclosingStmtLocation(S);
+
+ PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ "Loop condition is true. Entering loop body"));
+ }
+
+ break;
+ }
+
+ case Stmt::IfStmtClass: {
+ PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+
+ if (const Stmt *S = End.asStmt())
+ End = PDB.getEnclosingStmtLocation(S);
+
+ if (*(Src->succ_begin()+1) == Dst)
+ PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ "Taking false branch"));
+ else
+ PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ "Taking true branch"));
+
+ break;
+ }
+ }
+ }
+
+ 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))
+ PD.push_front(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);
+ PDB.getStateManager().iterBindings(N->getState(), SNS);
+ }
+ }
+
+ // After constructing the full PathDiagnostic, do a pass over it to compact
+ // PathDiagnosticPieces that occur within a macro.
+ CompactPathDiagnostic(PD, PDB.getSourceManager());
+}
+
+//===----------------------------------------------------------------------===//
+// "Extensive" PathDiagnostic generation.
+//===----------------------------------------------------------------------===//
+
+static bool IsControlFlowExpr(const Stmt *S) {
+ const Expr *E = dyn_cast<Expr>(S);
+
+ if (!E)
+ return false;
+
+ E = E->IgnoreParenCasts();
+
+ if (isa<ConditionalOperator>(E))
+ return true;
+
+ if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E))
+ if (B->isLogicalOp())
+ return true;
+
+ return false;
+}
+
+namespace {
+class VISIBILITY_HIDDEN ContextLocation : public PathDiagnosticLocation {
+ bool IsDead;
+public:
+ ContextLocation(const PathDiagnosticLocation &L, bool isdead = false)
+ : PathDiagnosticLocation(L), IsDead(isdead) {}
+
+ void markDead() { IsDead = true; }
+ bool isDead() const { return IsDead; }
+};
+
+class VISIBILITY_HIDDEN EdgeBuilder {
+ std::vector<ContextLocation> CLocs;
+ typedef std::vector<ContextLocation>::iterator iterator;
+ PathDiagnostic &PD;
+ PathDiagnosticBuilder &PDB;
+ PathDiagnosticLocation PrevLoc;
+
+ bool IsConsumedExpr(const PathDiagnosticLocation &L);
+
+ bool containsLocation(const PathDiagnosticLocation &Container,
+ const PathDiagnosticLocation &Containee);
+
+ PathDiagnosticLocation getContextLocation(const PathDiagnosticLocation &L);
+
+ PathDiagnosticLocation cleanUpLocation(PathDiagnosticLocation L,
+ bool firstCharOnly = false) {
+ if (const Stmt *S = L.asStmt()) {
+ const Stmt *Original = S;
+ while (1) {
+ // Adjust the location for some expressions that are best referenced
+ // by one of their subexpressions.
+ switch (S->getStmtClass()) {
+ default:
+ break;
+ case Stmt::ParenExprClass:
+ S = cast<ParenExpr>(S)->IgnoreParens();
+ firstCharOnly = true;
+ continue;
+ case Stmt::ConditionalOperatorClass:
+ S = cast<ConditionalOperator>(S)->getCond();
+ firstCharOnly = true;
+ continue;
+ case Stmt::ChooseExprClass:
+ S = cast<ChooseExpr>(S)->getCond();
+ firstCharOnly = true;
+ continue;
+ case Stmt::BinaryOperatorClass:
+ S = cast<BinaryOperator>(S)->getLHS();
+ firstCharOnly = true;
+ continue;
+ }
+
+ break;
+ }
+
+ if (S != Original)
+ L = PathDiagnosticLocation(S, L.getManager());
+ }
+
+ if (firstCharOnly)
+ L = PathDiagnosticLocation(L.asLocation());
+
+ return L;
+ }
+
+ void popLocation() {
+ if (!CLocs.back().isDead() && CLocs.back().asLocation().isFileID()) {
+ // For contexts, we only one the first character as the range.
+ rawAddEdge(cleanUpLocation(CLocs.back(), true));
+ }
+ CLocs.pop_back();
+ }
+
+ PathDiagnosticLocation IgnoreParens(const PathDiagnosticLocation &L);
+
+public:
+ EdgeBuilder(PathDiagnostic &pd, PathDiagnosticBuilder &pdb)
+ : PD(pd), PDB(pdb) {
+
+ // If the PathDiagnostic already has pieces, add the enclosing statement
+ // of the first piece as a context as well.
+ if (!PD.empty()) {
+ PrevLoc = PD.begin()->getLocation();
+
+ if (const Stmt *S = PrevLoc.asStmt())
+ addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
+ }
+ }
+
+ ~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 =
+ PDB.getCodeDecl().getCompoundBody(PDB.getASTContext()))
+ if (!CS->body_empty()) {
+ SourceLocation Loc = (*CS->body_begin())->getLocStart();
+ rawAddEdge(PathDiagnosticLocation(Loc, PDB.getSourceManager()));
+ }
+
+ }
+
+ void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false);
+
+ void addEdge(const Stmt *S, bool alwaysAdd = false) {
+ addEdge(PathDiagnosticLocation(S, PDB.getSourceManager()), alwaysAdd);
+ }
+
+ void rawAddEdge(PathDiagnosticLocation NewLoc);
+
+ void addContext(const Stmt *S);
+ void addExtendedContext(const Stmt *S);
+};
+} // end anonymous namespace
+
+
+PathDiagnosticLocation
+EdgeBuilder::getContextLocation(const PathDiagnosticLocation &L) {
+ if (const Stmt *S = L.asStmt()) {
+ if (IsControlFlowExpr(S))
+ return L;
+
+ return PDB.getEnclosingStmtLocation(S);
+ }
+
+ return L;
+}
+
+bool EdgeBuilder::containsLocation(const PathDiagnosticLocation &Container,
+ const PathDiagnosticLocation &Containee) {
+
+ if (Container == Containee)
+ return true;
+
+ if (Container.asDecl())
+ return true;
+
+ if (const Stmt *S = Containee.asStmt())
+ if (const Stmt *ContainerS = Container.asStmt()) {
+ while (S) {
+ if (S == ContainerS)
+ return true;
+ S = PDB.getParent(S);
+ }
+ return false;
+ }
+
+ // Less accurate: compare using source ranges.
+ SourceRange ContainerR = Container.asRange();
+ 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());
+
+ unsigned ContainerBegLine = SM.getInstantiationLineNumber(ContainerRBeg);
+ unsigned ContainerEndLine = SM.getInstantiationLineNumber(ContainerREnd);
+ unsigned ContaineeBegLine = SM.getInstantiationLineNumber(ContaineeRBeg);
+ unsigned ContaineeEndLine = SM.getInstantiationLineNumber(ContaineeREnd);
+
+ assert(ContainerBegLine <= ContainerEndLine);
+ assert(ContaineeBegLine <= ContaineeEndLine);
+
+ return (ContainerBegLine <= ContaineeBegLine &&
+ ContainerEndLine >= ContaineeEndLine &&
+ (ContainerBegLine != ContaineeBegLine ||
+ SM.getInstantiationColumnNumber(ContainerRBeg) <=
+ SM.getInstantiationColumnNumber(ContaineeRBeg)) &&
+ (ContainerEndLine != ContaineeEndLine ||
+ SM.getInstantiationColumnNumber(ContainerREnd) >=
+ SM.getInstantiationColumnNumber(ContainerREnd)));
+}
+
+PathDiagnosticLocation
+EdgeBuilder::IgnoreParens(const PathDiagnosticLocation &L) {
+ if (const Expr* E = dyn_cast_or_null<Expr>(L.asStmt()))
+ return PathDiagnosticLocation(E->IgnoreParenCasts(),
+ PDB.getSourceManager());
+ return L;
+}
+
+void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) {
+ if (!PrevLoc.isValid()) {
+ PrevLoc = NewLoc;
+ return;
+ }
+
+ const PathDiagnosticLocation &NewLocClean = cleanUpLocation(NewLoc);
+ const PathDiagnosticLocation &PrevLocClean = cleanUpLocation(PrevLoc);
+
+ if (NewLocClean.asLocation() == PrevLocClean.asLocation())
+ return;
+
+ // FIXME: Ignore intra-macro edges for now.
+ if (NewLocClean.asLocation().getInstantiationLoc() ==
+ PrevLocClean.asLocation().getInstantiationLoc())
+ return;
+
+ PD.push_front(new PathDiagnosticControlFlowPiece(NewLocClean, PrevLocClean));
+ PrevLoc = NewLoc;
+}
+
+void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) {
+
+ if (!alwaysAdd && NewLoc.asLocation().isMacroID())
+ return;
+
+ const PathDiagnosticLocation &CLoc = getContextLocation(NewLoc);
+
+ while (!CLocs.empty()) {
+ ContextLocation &TopContextLoc = CLocs.back();
+
+ // Is the top location context the same as the one for the new location?
+ if (TopContextLoc == CLoc) {
+ if (alwaysAdd) {
+ if (IsConsumedExpr(TopContextLoc) &&
+ !IsControlFlowExpr(TopContextLoc.asStmt()))
+ TopContextLoc.markDead();
+
+ rawAddEdge(NewLoc);
+ }
+
+ return;
+ }
+
+ if (containsLocation(TopContextLoc, CLoc)) {
+ if (alwaysAdd) {
+ rawAddEdge(NewLoc);
+
+ if (IsConsumedExpr(CLoc) && !IsControlFlowExpr(CLoc.asStmt())) {
+ CLocs.push_back(ContextLocation(CLoc, true));
+ return;
+ }
+ }
+
+ CLocs.push_back(CLoc);
+ return;
+ }
+
+ // Context does not contain the location. Flush it.
+ popLocation();
+ }
+
+ // If we reach here, there is no enclosing context. Just add the edge.
+ rawAddEdge(NewLoc);
+}
+
+bool EdgeBuilder::IsConsumedExpr(const PathDiagnosticLocation &L) {
+ if (const Expr *X = dyn_cast_or_null<Expr>(L.asStmt()))
+ return PDB.getParentMap().isConsumedExpr(X) && !IsControlFlowExpr(X);
+
+ return false;
+}
+
+void EdgeBuilder::addExtendedContext(const Stmt *S) {
+ if (!S)
+ return;
+
+ const Stmt *Parent = PDB.getParent(S);
+ while (Parent) {
+ if (isa<CompoundStmt>(Parent))
+ Parent = PDB.getParent(Parent);
+ else
+ break;
+ }
+
+ if (Parent) {
+ switch (Parent->getStmtClass()) {
+ case Stmt::DoStmtClass:
+ case Stmt::ObjCAtSynchronizedStmtClass:
+ addContext(Parent);
+ default:
+ break;
+ }
+ }
+
+ addContext(S);
+}
+
+void EdgeBuilder::addContext(const Stmt *S) {
+ if (!S)
+ return;
+
+ PathDiagnosticLocation L(S, PDB.getSourceManager());
+
+ while (!CLocs.empty()) {
+ const PathDiagnosticLocation &TopContextLoc = CLocs.back();
+
+ // Is the top location context the same as the one for the new location?
+ if (TopContextLoc == L)
+ return;
+
+ if (containsLocation(TopContextLoc, L)) {
+ CLocs.push_back(L);
+ return;
+ }
+
+ // Context does not contain the location. Flush it.
+ popLocation();
+ }
+
+ CLocs.push_back(L);
+}
+
+static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
+ PathDiagnosticBuilder &PDB,
+ const ExplodedNode<GRState> *N) {
+
+
+ EdgeBuilder EB(PD, PDB);
+
+ const ExplodedNode<GRState>* NextNode = N->pred_empty()
+ ? NULL : *(N->pred_begin());
+ while (NextNode) {
+ N = NextNode;
+ NextNode = GetPredecessorNode(N);
+ ProgramPoint P = N->getLocation();
+
+ do {
+ // Block edges.
+ if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ const CFGBlock &Blk = *BE->getSrc();
+ const Stmt *Term = Blk.getTerminator();
+
+ // Are we jumping to the head of a loop? Add a special diagnostic.
+ if (const Stmt *Loop = BE->getDst()->getLoopTarget()) {
+ PathDiagnosticLocation L(Loop, PDB.getSourceManager());
+ const CompoundStmt *CS = NULL;
+
+ if (!Term) {
+ if (const ForStmt *FS = dyn_cast<ForStmt>(Loop))
+ CS = dyn_cast<CompoundStmt>(FS->getBody());
+ else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
+ CS = dyn_cast<CompoundStmt>(WS->getBody());
+ }
+
+ PathDiagnosticEventPiece *p =
+ new PathDiagnosticEventPiece(L,
+ "Looping back to the head of the loop");
+
+ EB.addEdge(p->getLocation(), true);
+ PD.push_front(p);
+
+ if (CS) {
+ PathDiagnosticLocation BL(CS->getRBracLoc(),
+ PDB.getSourceManager());
+ BL = PathDiagnosticLocation(BL.asLocation());
+ EB.addEdge(BL);
+ }
+ }
+
+ if (Term)
+ EB.addContext(Term);
+
+ break;
+ }
+
+ if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
+ if (const Stmt* S = BE->getFirstStmt()) {
+ if (IsControlFlowExpr(S)) {
+ // Add the proper context for '&&', '||', and '?'.
+ EB.addContext(S);
+ }
+ else
+ EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
+ }
+
+ break;
+ }
+ } while (0);
+
+ 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)) {
+ const PathDiagnosticLocation &Loc = p->getLocation();
+ EB.addEdge(Loc, true);
+ PD.push_front(p);
+ if (const Stmt *S = Loc.asStmt())
+ EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
+ }
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Methods for BugType and subclasses.
+//===----------------------------------------------------------------------===//
+BugType::~BugType() {}
+void BugType::FlushReports(BugReporter &BR) {}
+
+//===----------------------------------------------------------------------===//
+// Methods for BugReport and subclasses.
+//===----------------------------------------------------------------------===//
+BugReport::~BugReport() {}
+RangedBugReport::~RangedBugReport() {}
+
+Stmt* BugReport::getStmt(BugReporter& BR) const {
+ ProgramPoint ProgP = EndNode->getLocation();
+ Stmt *S = NULL;
+
+ if (BlockEntrance* BE = dyn_cast<BlockEntrance>(&ProgP)) {
+ if (BE->getBlock() == &BR.getCFG()->getExit()) S = GetPreviousStmt(EndNode);
+ }
+ if (!S) S = GetStmt(ProgP);
+
+ return S;
+}
+
+PathDiagnosticPiece*
+BugReport::getEndPath(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* EndPathNode) {
+
+ Stmt* S = getStmt(BRC.getBugReporter());
+
+ if (!S)
+ return NULL;
+
+ const SourceRange *Beg, *End;
+ getRanges(BRC.getBugReporter(), Beg, End);
+ 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);
+
+ for (; Beg != End; ++Beg)
+ P->addRange(*Beg);
+
+ return P;
+}
+
+void BugReport::getRanges(BugReporter& BR, const SourceRange*& beg,
+ const SourceRange*& end) {
+
+ if (Expr* E = dyn_cast_or_null<Expr>(getStmt(BR))) {
+ R = E->getSourceRange();
+ assert(R.isValid());
+ beg = &R;
+ end = beg+1;
+ }
+ else
+ beg = end = 0;
+}
+
+SourceLocation BugReport::getLocation() const {
+ if (EndNode)
+ if (Stmt* S = GetCurrentOrPreviousStmt(EndNode)) {
+ // For member expressions, return the location of the '.' or '->'.
+ if (MemberExpr* ME = dyn_cast<MemberExpr>(S))
+ return ME->getMemberLoc();
+
+ return S->getLocStart();
+ }
+
+ return FullSourceLoc();
+}
+
+PathDiagnosticPiece* BugReport::VisitNode(const ExplodedNode<GRState>* N,
+ const ExplodedNode<GRState>* PrevN,
+ BugReporterContext &BRC) {
+ return NULL;
+}
+
+//===----------------------------------------------------------------------===//
+// Methods for BugReporter and subclasses.
+//===----------------------------------------------------------------------===//
+
+BugReportEquivClass::~BugReportEquivClass() {
+ for (iterator I=begin(), E=end(); I!=E; ++I) delete *I;
+}
+
+GRBugReporter::~GRBugReporter() { FlushReports(); }
+BugReporterData::~BugReporterData() {}
+
+ExplodedGraph<GRState>&
+GRBugReporter::getGraph() { return Eng.getGraph(); }
+
+GRStateManager&
+GRBugReporter::getStateManager() { return Eng.getStateManager(); }
+
+BugReporter::~BugReporter() { FlushReports(); }
+
+void BugReporter::FlushReports() {
+ if (BugTypes.isEmpty())
+ return;
+
+ // First flush the warnings for each BugType. This may end up creating new
+ // warnings and new BugTypes. Because ImmutableSet is a functional data
+ // structure, we do not need to worry about the iterators being invalidated.
+ for (BugTypesTy::iterator I=BugTypes.begin(), E=BugTypes.end(); I!=E; ++I)
+ const_cast<BugType*>(*I)->FlushReports(*this);
+
+ // Iterate through BugTypes a second time. BugTypes may have been updated
+ // with new BugType objects and new warnings.
+ for (BugTypesTy::iterator I=BugTypes.begin(), E=BugTypes.end(); I!=E; ++I) {
+ BugType *BT = const_cast<BugType*>(*I);
+
+ typedef llvm::FoldingSet<BugReportEquivClass> SetTy;
+ SetTy& EQClasses = BT->EQClasses;
+
+ for (SetTy::iterator EI=EQClasses.begin(), EE=EQClasses.end(); EI!=EE;++EI){
+ BugReportEquivClass& EQ = *EI;
+ FlushReport(EQ);
+ }
+
+ // Delete the BugType object. This will also delete the equivalence
+ // classes.
+ delete BT;
+ }
+
+ // Remove all references to the BugType objects.
+ BugTypes = F.GetEmptySet();
+}
+
+//===----------------------------------------------------------------------===//
+// PathDiagnostics generation.
+//===----------------------------------------------------------------------===//
+
+static std::pair<std::pair<ExplodedGraph<GRState>*, NodeBackMap*>,
+ std::pair<ExplodedNode<GRState>*, unsigned> >
+MakeReportGraph(const ExplodedGraph<GRState>* G,
+ const ExplodedNode<GRState>** NStart,
+ const ExplodedNode<GRState>** NEnd) {
+
+ // Create the trimmed graph. It will contain the shortest paths from the
+ // error nodes to the root. In the new graph we should only have one
+ // error node unless there are two or more error nodes with the same minimum
+ // path length.
+ ExplodedGraph<GRState>* GTrim;
+ InterExplodedGraphMap<GRState>* NMap;
+
+ llvm::DenseMap<const void*, const void*> InverseMap;
+ llvm::tie(GTrim, NMap) = G->Trim(NStart, NEnd, &InverseMap);
+
+ // Create owning pointers for GTrim and NMap just to ensure that they are
+ // released when this function exists.
+ llvm::OwningPtr<ExplodedGraph<GRState> > AutoReleaseGTrim(GTrim);
+ llvm::OwningPtr<InterExplodedGraphMap<GRState> > AutoReleaseNMap(NMap);
+
+ // Find the (first) error node in the trimmed graph. We just need to consult
+ // the node map (NMap) which maps from nodes in the original graph to nodes
+ // in the new graph.
+
+ std::queue<const ExplodedNode<GRState>*> WS;
+ typedef llvm::DenseMap<const ExplodedNode<GRState>*,unsigned> IndexMapTy;
+ IndexMapTy IndexMap;
+
+ for (const ExplodedNode<GRState>** I = NStart; I != NEnd; ++I)
+ if (const ExplodedNode<GRState> *N = NMap->getMappedNode(*I)) {
+ unsigned NodeIndex = (I - NStart) / sizeof(*I);
+ WS.push(N);
+ IndexMap[*I] = NodeIndex;
+ }
+
+ assert(!WS.empty() && "No error node found in the trimmed graph.");
+
+ // Create a new (third!) graph with a single path. This is the graph
+ // that will be returned to the caller.
+ ExplodedGraph<GRState> *GNew =
+ new ExplodedGraph<GRState>(GTrim->getCFG(), GTrim->getCodeDecl(),
+ GTrim->getContext());
+
+ // Sometimes the trimmed graph can contain a cycle. Perform a reverse BFS
+ // to the root node, and then construct a new graph that contains only
+ // a single path.
+ llvm::DenseMap<const void*,unsigned> Visited;
+
+ unsigned cnt = 0;
+ const ExplodedNode<GRState>* Root = 0;
+
+ while (!WS.empty()) {
+ const ExplodedNode<GRState>* Node = WS.front();
+ WS.pop();
+
+ if (Visited.find(Node) != Visited.end())
+ continue;
+
+ Visited[Node] = cnt++;
+
+ if (Node->pred_empty()) {
+ Root = Node;
+ break;
+ }
+
+ for (ExplodedNode<GRState>::const_pred_iterator I=Node->pred_begin(),
+ E=Node->pred_end(); I!=E; ++I)
+ WS.push(*I);
+ }
+
+ assert(Root);
+
+ // Now walk from the root down the BFS path, always taking the successor
+ // with the lowest number.
+ ExplodedNode<GRState> *Last = 0, *First = 0;
+ NodeBackMap *BM = new NodeBackMap();
+ unsigned NodeIndex = 0;
+
+ for ( const ExplodedNode<GRState> *N = Root ;;) {
+ // Lookup the number associated with the current node.
+ llvm::DenseMap<const void*,unsigned>::iterator I = Visited.find(N);
+ assert(I != Visited.end());
+
+ // Create the equivalent node in the new graph with the same state
+ // and location.
+ ExplodedNode<GRState>* 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);
+ assert(IMitr != InverseMap.end() && "No mapping to original node.");
+ (*BM)[NewN] = (const ExplodedNode<GRState>*) IMitr->second;
+
+ // Link up the new node with the previous node.
+ if (Last)
+ NewN->addPredecessor(Last);
+
+ Last = NewN;
+
+ // Are we at the final node?
+ IndexMapTy::iterator IMI =
+ IndexMap.find((const ExplodedNode<GRState>*)(IMitr->second));
+ if (IMI != IndexMap.end()) {
+ First = NewN;
+ NodeIndex = IMI->second;
+ break;
+ }
+
+ // Find the next successor node. We choose the node that is marked
+ // with the lowest DFS number.
+ ExplodedNode<GRState>::const_succ_iterator SI = N->succ_begin();
+ ExplodedNode<GRState>::const_succ_iterator SE = N->succ_end();
+ N = 0;
+
+ for (unsigned MinVal = 0; SI != SE; ++SI) {
+
+ I = Visited.find(*SI);
+
+ if (I == Visited.end())
+ continue;
+
+ if (!N || I->second < MinVal) {
+ N = *SI;
+ MinVal = I->second;
+ }
+ }
+
+ assert(N);
+ }
+
+ assert(First);
+
+ return std::make_pair(std::make_pair(GNew, BM),
+ std::make_pair(First, NodeIndex));
+}
+
+/// CompactPathDiagnostic - This function postprocesses a PathDiagnostic object
+/// and collapses PathDiagosticPieces that are expanded by macros.
+static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
+ typedef std::vector<std::pair<PathDiagnosticMacroPiece*, SourceLocation> >
+ MacroStackTy;
+
+ typedef std::vector<PathDiagnosticPiece*>
+ PiecesTy;
+
+ MacroStackTy MacroStack;
+ PiecesTy Pieces;
+
+ for (PathDiagnostic::iterator I = PD.begin(), E = PD.end(); I!=E; ++I) {
+ // Get the location of the PathDiagnosticPiece.
+ const FullSourceLoc Loc = I->getLocation().asLocation();
+
+ // Determine the instantiation location, which is the location we group
+ // related PathDiagnosticPieces.
+ SourceLocation InstantiationLoc = Loc.isMacroID() ?
+ SM.getInstantiationLoc(Loc) :
+ SourceLocation();
+
+ if (Loc.isFileID()) {
+ MacroStack.clear();
+ Pieces.push_back(&*I);
+ continue;
+ }
+
+ assert(Loc.isMacroID());
+
+ // Is the PathDiagnosticPiece within the same macro group?
+ if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
+ MacroStack.back().first->push_back(&*I);
+ continue;
+ }
+
+ // We aren't in the same group. Are we descending into a new macro
+ // or are part of an old one?
+ PathDiagnosticMacroPiece *MacroGroup = 0;
+
+ SourceLocation ParentInstantiationLoc = InstantiationLoc.isMacroID() ?
+ SM.getInstantiationLoc(Loc) :
+ SourceLocation();
+
+ // Walk the entire macro stack.
+ while (!MacroStack.empty()) {
+ if (InstantiationLoc == MacroStack.back().second) {
+ MacroGroup = MacroStack.back().first;
+ break;
+ }
+
+ if (ParentInstantiationLoc == MacroStack.back().second) {
+ MacroGroup = MacroStack.back().first;
+ break;
+ }
+
+ MacroStack.pop_back();
+ }
+
+ if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
+ // Create a new macro group and add it to the stack.
+ PathDiagnosticMacroPiece *NewGroup = new PathDiagnosticMacroPiece(Loc);
+
+ if (MacroGroup)
+ MacroGroup->push_back(NewGroup);
+ else {
+ assert(InstantiationLoc.isFileID());
+ Pieces.push_back(NewGroup);
+ }
+
+ MacroGroup = NewGroup;
+ MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
+ }
+
+ // Finally, add the PathDiagnosticPiece to the group.
+ MacroGroup->push_back(&*I);
+ }
+
+ // Now take the pieces and construct a new PathDiagnostic.
+ PD.resetPath(false);
+
+ for (PiecesTy::iterator I=Pieces.begin(), E=Pieces.end(); I!=E; ++I) {
+ if (PathDiagnosticMacroPiece *MP=dyn_cast<PathDiagnosticMacroPiece>(*I))
+ if (!MP->containsEvent()) {
+ delete MP;
+ continue;
+ }
+
+ PD.push_back(*I);
+ }
+}
+
+void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
+ BugReportEquivClass& EQ) {
+
+ std::vector<const ExplodedNode<GRState>*> Nodes;
+
+ for (BugReportEquivClass::iterator I=EQ.begin(), E=EQ.end(); I!=E; ++I) {
+ const ExplodedNode<GRState>* N = I->getEndNode();
+ if (N) Nodes.push_back(N);
+ }
+
+ if (Nodes.empty())
+ return;
+
+ // Construct a new graph that contains only a single path from the error
+ // node to a root.
+ const std::pair<std::pair<ExplodedGraph<GRState>*, NodeBackMap*>,
+ std::pair<ExplodedNode<GRState>*, unsigned> >&
+ GPair = MakeReportGraph(&getGraph(), &Nodes[0], &Nodes[0] + Nodes.size());
+
+ // Find the BugReport with the original location.
+ BugReport *R = 0;
+ unsigned i = 0;
+ for (BugReportEquivClass::iterator I=EQ.begin(), E=EQ.end(); I!=E; ++I, ++i)
+ if (i == GPair.second.second) { R = *I; break; }
+
+ assert(R && "No original report found for sliced graph.");
+
+ llvm::OwningPtr<ExplodedGraph<GRState> > ReportGraph(GPair.first.first);
+ llvm::OwningPtr<NodeBackMap> BackMap(GPair.first.second);
+ const ExplodedNode<GRState> *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);
+ else
+ return;
+
+ R->registerInitialVisitors(PDB, N);
+
+ switch (PDB.getGenerationScheme()) {
+ case PathDiagnosticClient::Extensive:
+ GenerateExtensivePathDiagnostic(PD, PDB, N);
+ break;
+ case PathDiagnosticClient::Minimal:
+ GenerateMinimalPathDiagnostic(PD, PDB, N);
+ break;
+ }
+}
+
+void BugReporter::Register(BugType *BT) {
+ BugTypes = F.Add(BugTypes, BT);
+}
+
+void BugReporter::EmitReport(BugReport* R) {
+ // Compute the bug report's hash to determine its equivalence class.
+ llvm::FoldingSetNodeID ID;
+ R->Profile(ID);
+
+ // Lookup the equivance class. If there isn't one, create it.
+ BugType& BT = R->getBugType();
+ Register(&BT);
+ void *InsertPos;
+ BugReportEquivClass* EQ = BT.EQClasses.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (!EQ) {
+ EQ = new BugReportEquivClass(R);
+ BT.EQClasses.InsertNode(EQ, InsertPos);
+ }
+ else
+ EQ->AddReport(R);
+}
+
+void BugReporter::FlushReport(BugReportEquivClass& EQ) {
+ assert(!EQ.Reports.empty());
+ BugReport &R = **EQ.begin();
+ PathDiagnosticClient* PD = getPathDiagnosticClient();
+
+ // FIXME: Make sure we use the 'R' for the path that was actually used.
+ // Probably doesn't make a difference in practice.
+ BugType& BT = R.getBugType();
+
+ llvm::OwningPtr<PathDiagnostic>
+ D(new PathDiagnostic(R.getBugType().getName(),
+ !PD || PD->useVerboseDescription()
+ ? R.getDescription() : R.getShortDescription(),
+ BT.getCategory()));
+
+ GeneratePathDiagnostic(*D.get(), EQ);
+
+ // Get the meta data.
+ std::pair<const char**, const char**> Meta = R.getExtraDescriptiveText();
+ for (const char** s = Meta.first; s != Meta.second; ++s) D->addMeta(*s);
+
+ // Emit a summary diagnostic to the regular Diagnostics engine.
+ const SourceRange *Beg = 0, *End = 0;
+ R.getRanges(*this, Beg, End);
+ Diagnostic& Diag = getDiagnostic();
+ FullSourceLoc L(R.getLocation(), getSourceManager());
+ unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning,
+ R.getShortDescription().c_str());
+
+ switch (End-Beg) {
+ default: assert(0 && "Don't handle this many ranges yet!");
+ case 0: Diag.Report(L, ErrorDiag); break;
+ case 1: Diag.Report(L, ErrorDiag) << Beg[0]; break;
+ case 2: Diag.Report(L, ErrorDiag) << Beg[0] << Beg[1]; break;
+ case 3: Diag.Report(L, ErrorDiag) << Beg[0] << Beg[1] << Beg[2]; break;
+ }
+
+ // Emit a full diagnostic for the path if we have a PathDiagnosticClient.
+ if (!PD)
+ return;
+
+ if (D->empty()) {
+ PathDiagnosticPiece* piece =
+ new PathDiagnosticEventPiece(L, R.getDescription());
+
+ for ( ; Beg != End; ++Beg) piece->addRange(*Beg);
+ D->push_back(piece);
+ }
+
+ PD->HandlePathDiagnostic(D.take());
+}
+
+void BugReporter::EmitBasicReport(const char* name, const char* str,
+ SourceLocation Loc,
+ SourceRange* RBeg, unsigned NumRanges) {
+ EmitBasicReport(name, "", str, Loc, RBeg, NumRanges);
+}
+
+void BugReporter::EmitBasicReport(const char* name, const char* category,
+ const char* str, SourceLocation Loc,
+ SourceRange* RBeg, unsigned NumRanges) {
+
+ // 'BT' will be owned by BugReporter as soon as we call 'EmitReport'.
+ BugType *BT = new BugType(name, category);
+ FullSourceLoc L = getContext().getFullLoc(Loc);
+ RangedBugReport *R = new DiagBugReport(*BT, str, L);
+ for ( ; NumRanges > 0 ; --NumRanges, ++RBeg) R->addRange(*RBeg);
+ EmitReport(R);
+}
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
new file mode 100644
index 000000000000..30ff67f4a564
--- /dev/null
+++ b/lib/Analysis/CFRefCount.cpp
@@ -0,0 +1,3635 @@
+// CFRefCount.cpp - Transfer functions for tracking simple 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 defines the methods for CFRefCount, which implements
+// a reference count checker for Core Foundation (Mac OS X).
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRSimpleVals.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
+#include "clang/Analysis/PathSensitive/GRStateTrait.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/SymbolManager.h"
+#include "clang/AST/DeclObjC.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/ADT/STLExtras.h"
+#include <ostream>
+#include <stdarg.h>
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Utility functions.
+//===----------------------------------------------------------------------===//
+
+// The "fundamental rule" for naming conventions of methods:
+// (url broken into two lines)
+// http://developer.apple.com/documentation/Cocoa/Conceptual/
+// MemoryMgmt/Tasks/MemoryManagementRules.html
+//
+// "You take ownership of an object if you create it using a method whose name
+// begins with “alloc†or “new†or contains “copy†(for example, alloc,
+// newObject, or mutableCopy), or if you send it a retain message. You are
+// responsible for relinquishing ownership of objects you own using release
+// or autorelease. Any other time you receive an object, you must
+// not release it."
+//
+
+using llvm::CStrInCStrNoCase;
+using llvm::StringsEqualNoCase;
+
+enum NamingConvention { NoConvention, CreateRule, InitRule };
+
+static inline bool isWordEnd(char ch, char prev, char next) {
+ return ch == '\0'
+ || (islower(prev) && isupper(ch)) // xxxC
+ || (isupper(prev) && isupper(ch) && islower(next)) // XXCreate
+ || !isalpha(ch);
+}
+
+static inline const char* parseWord(const char* s) {
+ char ch = *s, prev = '\0';
+ assert(ch != '\0');
+ char next = *(s+1);
+ while (!isWordEnd(ch, prev, next)) {
+ prev = ch;
+ ch = next;
+ next = *((++s)+1);
+ }
+ return s;
+}
+
+static NamingConvention deriveNamingConvention(Selector S) {
+ IdentifierInfo *II = S.getIdentifierInfoForSlot(0);
+
+ if (!II)
+ return NoConvention;
+
+ const char *s = II->getName();
+
+ // A method/function name may contain a prefix. We don't know it is there,
+ // however, until we encounter the first '_'.
+ bool InPossiblePrefix = true;
+ bool AtBeginning = true;
+ NamingConvention C = NoConvention;
+
+ while (*s != '\0') {
+ // Skip '_'.
+ if (*s == '_') {
+ if (InPossiblePrefix) {
+ InPossiblePrefix = false;
+ AtBeginning = true;
+ // Discard whatever 'convention' we
+ // had already derived since it occurs
+ // in the prefix.
+ C = NoConvention;
+ }
+ ++s;
+ continue;
+ }
+
+ // Skip numbers, ':', etc.
+ if (!isalpha(*s)) {
+ ++s;
+ continue;
+ }
+
+ const char *wordEnd = parseWord(s);
+ assert(wordEnd > s);
+ unsigned len = wordEnd - s;
+
+ switch (len) {
+ default:
+ break;
+ case 3:
+ // Methods starting with 'new' follow the create rule.
+ if (AtBeginning && StringsEqualNoCase("new", s, len))
+ C = CreateRule;
+ break;
+ case 4:
+ // Methods starting with 'alloc' or contain 'copy' follow the
+ // create rule
+ if (C == NoConvention && StringsEqualNoCase("copy", s, len))
+ C = CreateRule;
+ else // Methods starting with 'init' follow the init rule.
+ if (AtBeginning && StringsEqualNoCase("init", s, len))
+ C = InitRule;
+ break;
+ case 5:
+ if (AtBeginning && StringsEqualNoCase("alloc", s, len))
+ C = CreateRule;
+ break;
+ }
+
+ // If we aren't in the prefix and have a derived convention then just
+ // return it now.
+ if (!InPossiblePrefix && C != NoConvention)
+ return C;
+
+ AtBeginning = false;
+ s = wordEnd;
+ }
+
+ // We will get here if there wasn't more than one word
+ // after the prefix.
+ return C;
+}
+
+static bool followsFundamentalRule(Selector S) {
+ return deriveNamingConvention(S) == CreateRule;
+}
+
+static const ObjCMethodDecl*
+ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD, ASTContext &Context) {
+ ObjCInterfaceDecl *ID =
+ const_cast<ObjCInterfaceDecl*>(MD->getClassInterface());
+
+ return MD->isInstanceMethod()
+ ? ID->lookupInstanceMethod(Context, MD->getSelector())
+ : ID->lookupClassMethod(Context, MD->getSelector());
+}
+
+namespace {
+class VISIBILITY_HIDDEN GenericNodeBuilder {
+ GRStmtNodeBuilder<GRState> *SNB;
+ Stmt *S;
+ const void *tag;
+ GREndPathNodeBuilder<GRState> *ENB;
+public:
+ GenericNodeBuilder(GRStmtNodeBuilder<GRState> &snb, Stmt *s,
+ const void *t)
+ : SNB(&snb), S(s), tag(t), ENB(0) {}
+ GenericNodeBuilder(GREndPathNodeBuilder<GRState> &enb)
+ : SNB(0), S(0), tag(0), ENB(&enb) {}
+
+ ExplodedNode<GRState> *MakeNode(const GRState *state,
+ ExplodedNode<GRState> *Pred) {
+ if (SNB)
+ return SNB->generateNode(PostStmt(S, tag), state, Pred);
+
+ assert(ENB);
+ return ENB->generateNode(state, Pred);
+ }
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Selector creation functions.
+//===----------------------------------------------------------------------===//
+
+static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
+ IdentifierInfo* II = &Ctx.Idents.get(name);
+ return Ctx.Selectors.getSelector(0, &II);
+}
+
+static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) {
+ IdentifierInfo* II = &Ctx.Idents.get(name);
+ return Ctx.Selectors.getSelector(1, &II);
+}
+
+//===----------------------------------------------------------------------===//
+// Type querying functions.
+//===----------------------------------------------------------------------===//
+
+static bool hasPrefix(const char* s, const char* prefix) {
+ if (!prefix)
+ return true;
+
+ char c = *s;
+ char cP = *prefix;
+
+ while (c != '\0' && cP != '\0') {
+ if (c != cP) break;
+ c = *(++s);
+ cP = *(++prefix);
+ }
+
+ return cP == '\0';
+}
+
+static bool hasSuffix(const char* s, const char* suffix) {
+ const char* loc = strstr(s, suffix);
+ return loc && strcmp(suffix, loc) == 0;
+}
+
+static bool isRefType(QualType RetTy, const char* prefix,
+ ASTContext* Ctx = 0, const char* name = 0) {
+
+ // Recursively walk the typedef stack, allowing typedefs of reference types.
+ while (1) {
+ if (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
+ const char* TDName = TD->getDecl()->getIdentifier()->getName();
+ if (hasPrefix(TDName, prefix) && hasSuffix(TDName, "Ref"))
+ return true;
+
+ RetTy = TD->getDecl()->getUnderlyingType();
+ continue;
+ }
+ break;
+ }
+
+ if (!Ctx || !name)
+ return false;
+
+ // Is the type void*?
+ const PointerType* PT = RetTy->getAsPointerType();
+ if (!(PT->getPointeeType().getUnqualifiedType() == Ctx->VoidTy))
+ return false;
+
+ // Does the name start with the prefix?
+ return hasPrefix(name, prefix);
+}
+
+//===----------------------------------------------------------------------===//
+// Primitives used for constructing summaries for function/method calls.
+//===----------------------------------------------------------------------===//
+
+/// ArgEffect is used to summarize a function/method call's effect on a
+/// particular argument.
+enum ArgEffect { Autorelease, Dealloc, DecRef, DecRefMsg, DoNothing,
+ DoNothingByRef, IncRefMsg, IncRef, MakeCollectable, MayEscape,
+ NewAutoreleasePool, SelfOwn, StopTracking };
+
+namespace llvm {
+template <> struct FoldingSetTrait<ArgEffect> {
+static inline void Profile(const ArgEffect X, FoldingSetNodeID& ID) {
+ ID.AddInteger((unsigned) X);
+}
+};
+} // end llvm namespace
+
+/// ArgEffects summarizes the effects of a function/method call on all of
+/// its arguments.
+typedef llvm::ImmutableMap<unsigned,ArgEffect> ArgEffects;
+
+namespace {
+
+/// RetEffect is used to summarize a function/method call's behavior with
+/// respect to its return value.
+class VISIBILITY_HIDDEN RetEffect {
+public:
+ enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol,
+ NotOwnedSymbol, GCNotOwnedSymbol, ReceiverAlias,
+ OwnedWhenTrackedReceiver };
+
+ enum ObjKind { CF, ObjC, AnyObj };
+
+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) {}
+
+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;
+ }
+
+ 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);
+ }
+ static RetEffect MakeNotOwned(ObjKind o) {
+ return RetEffect(NotOwnedSymbol, o);
+ }
+ static RetEffect MakeGCNotOwned() {
+ return RetEffect(GCNotOwnedSymbol, ObjC);
+ }
+
+ static RetEffect MakeNoRet() {
+ return RetEffect(NoRet);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddInteger((unsigned)K);
+ ID.AddInteger((unsigned)O);
+ ID.AddInteger(index);
+ }
+};
+
+
+class VISIBILITY_HIDDEN RetainSummary {
+ /// Args - an ordered vector of (index, ArgEffect) pairs, where index
+ /// specifies the argument (starting from 0). This can be sparsely
+ /// populated; arguments with no entry in Args use 'DefaultArgEffect'.
+ ArgEffects Args;
+
+ /// DefaultArgEffect - The default ArgEffect to apply to arguments that
+ /// do not have an entry in Args.
+ ArgEffect DefaultArgEffect;
+
+ /// Receiver - If this summary applies to an Objective-C message expression,
+ /// this is the effect applied to the state of the receiver.
+ 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.
+ 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) {}
+
+ /// getArg - Return the argument effect on the argument specified by
+ /// idx (starting from 0).
+ ArgEffect getArg(unsigned idx) const {
+ if (const ArgEffect *AE = Args.lookup(idx))
+ return *AE;
+
+ return DefaultArgEffect;
+ }
+
+ /// setDefaultArgEffect - Set the default argument effect.
+ void setDefaultArgEffect(ArgEffect E) {
+ DefaultArgEffect = E;
+ }
+
+ /// setArg - Set the argument effect on the argument specified by idx.
+ void setArgEffect(ArgEffects::Factory& AF, unsigned idx, ArgEffect E) {
+ Args = AF.Add(Args, idx, E);
+ }
+
+ /// getRetEffect - Returns the effect on the return value of the call.
+ RetEffect getRetEffect() const { return Ret; }
+
+ /// 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; }
+
+ /// 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; }
+
+ /// setReceiverEffect - Set the effect on the receiver of the call.
+ void setReceiverEffect(ArgEffect E) { Receiver = E; }
+
+ typedef ArgEffects::iterator ExprIterator;
+
+ ExprIterator begin_args() const { return Args.begin(); }
+ ExprIterator end_args() const { return Args.end(); }
+
+ static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects A,
+ RetEffect RetEff, ArgEffect DefaultEff,
+ ArgEffect ReceiverEff, bool EndPath) {
+ ID.Add(A);
+ ID.Add(RetEff);
+ ID.AddInteger((unsigned) DefaultEff);
+ ID.AddInteger((unsigned) ReceiverEff);
+ ID.AddInteger((unsigned) EndPath);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ Profile(ID, Args, Ret, DefaultArgEffect, Receiver, EndPath);
+ }
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Data structures for constructing summaries.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN ObjCSummaryKey {
+ IdentifierInfo* II;
+ Selector S;
+public:
+ ObjCSummaryKey(IdentifierInfo* ii, Selector s)
+ : II(ii), S(s) {}
+
+ ObjCSummaryKey(const ObjCInterfaceDecl* d, Selector s)
+ : II(d ? d->getIdentifier() : 0), S(s) {}
+
+ ObjCSummaryKey(const ObjCInterfaceDecl* d, IdentifierInfo *ii, Selector s)
+ : II(d ? d->getIdentifier() : ii), S(s) {}
+
+ ObjCSummaryKey(Selector s)
+ : II(0), S(s) {}
+
+ IdentifierInfo* getIdentifier() const { return II; }
+ Selector getSelector() const { return S; }
+};
+}
+
+namespace llvm {
+template <> struct DenseMapInfo<ObjCSummaryKey> {
+ static inline ObjCSummaryKey getEmptyKey() {
+ return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getEmptyKey(),
+ DenseMapInfo<Selector>::getEmptyKey());
+ }
+
+ static inline ObjCSummaryKey getTombstoneKey() {
+ return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getTombstoneKey(),
+ DenseMapInfo<Selector>::getTombstoneKey());
+ }
+
+ static unsigned getHashValue(const ObjCSummaryKey &V) {
+ return (DenseMapInfo<IdentifierInfo*>::getHashValue(V.getIdentifier())
+ & 0x88888888)
+ | (DenseMapInfo<Selector>::getHashValue(V.getSelector())
+ & 0x55555555);
+ }
+
+ static bool isEqual(const ObjCSummaryKey& LHS, const ObjCSummaryKey& RHS) {
+ return DenseMapInfo<IdentifierInfo*>::isEqual(LHS.getIdentifier(),
+ RHS.getIdentifier()) &&
+ DenseMapInfo<Selector>::isEqual(LHS.getSelector(),
+ RHS.getSelector());
+ }
+
+ static bool isPod() {
+ return DenseMapInfo<ObjCInterfaceDecl*>::isPod() &&
+ DenseMapInfo<Selector>::isPod();
+ }
+};
+} // end llvm namespace
+
+namespace {
+class VISIBILITY_HIDDEN ObjCSummaryCache {
+ typedef llvm::DenseMap<ObjCSummaryKey, RetainSummary*> MapTy;
+ MapTy M;
+public:
+ ObjCSummaryCache() {}
+
+ typedef MapTy::iterator iterator;
+
+ iterator 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);
+ }
+
+ iterator 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);
+ MapTy::iterator I = M.find(K);
+
+ if (I != M.end() || !D)
+ return I;
+
+ // Walk the super chain. If we find a hit with a parent, we'll end
+ // up returning that summary. We actually allow that key (null,S), as
+ // we cache summaries for the null ObjCInterfaceDecl* to allow us to
+ // 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()) {
+ if ((I = M.find(ObjCSummaryKey(C, S))) != M.end())
+ break;
+
+ if (!C)
+ return I;
+ }
+
+ // Cache the summary with original key to make the next lookup faster
+ // and return the iterator.
+ M[K] = I->second;
+ return I;
+ }
+
+
+ iterator find(Expr* Receiver, Selector S) {
+ return find(getReceiverDecl(Receiver), S);
+ }
+
+ iterator 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.
+ iterator I = M.find(ObjCSummaryKey(II, S));
+ return I == M.end() ? M.find(ObjCSummaryKey(S)) : I;
+ }
+
+ ObjCInterfaceDecl* getReceiverDecl(Expr* E) {
+
+ const PointerType* PT = E->getType()->getAsPointerType();
+ if (!PT) return 0;
+
+ ObjCInterfaceType* OI = dyn_cast<ObjCInterfaceType>(PT->getPointeeType());
+ if (!OI) return 0;
+
+ return OI ? OI->getDecl() : 0;
+ }
+
+ iterator end() { return M.end(); }
+
+ RetainSummary*& operator[](ObjCMessageExpr* ME) {
+
+ Selector S = ME->getSelector();
+
+ if (Expr* Receiver = ME->getReceiver()) {
+ ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
+ return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
+ }
+
+ return M[ObjCSummaryKey(ME->getClassName(), S)];
+ }
+
+ RetainSummary*& operator[](ObjCSummaryKey K) {
+ return M[K];
+ }
+
+ RetainSummary*& operator[](Selector S) {
+ return M[ ObjCSummaryKey(S) ];
+ }
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Data structures for managing collections of summaries.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN RetainSummaryManager {
+
+ //==-----------------------------------------------------------------==//
+ // Typedefs.
+ //==-----------------------------------------------------------------==//
+
+ typedef llvm::DenseMap<FunctionDecl*, RetainSummary*>
+ FuncSummariesTy;
+
+ typedef ObjCSummaryCache ObjCMethodSummariesTy;
+
+ //==-----------------------------------------------------------------==//
+ // Data.
+ //==-----------------------------------------------------------------==//
+
+ /// Ctx - The ASTContext object for the analyzed ASTs.
+ ASTContext& Ctx;
+
+ /// CFDictionaryCreateII - An IdentifierInfo* representing the indentifier
+ /// "CFDictionaryCreate".
+ IdentifierInfo* CFDictionaryCreateII;
+
+ /// GCEnabled - Records whether or not the analyzed code runs in GC mode.
+ const bool GCEnabled;
+
+ /// FuncSummaries - A map from FunctionDecls to summaries.
+ FuncSummariesTy FuncSummaries;
+
+ /// ObjCClassMethodSummaries - A map from selectors (for instance methods)
+ /// to summaries.
+ ObjCMethodSummariesTy ObjCClassMethodSummaries;
+
+ /// ObjCMethodSummaries - A map from selectors to summaries.
+ ObjCMethodSummariesTy ObjCMethodSummaries;
+
+ /// BPAlloc - A BumpPtrAllocator used for allocating summaries, ArgEffects,
+ /// and all other data used by the checker.
+ llvm::BumpPtrAllocator BPAlloc;
+
+ /// AF - A factory for ArgEffects objects.
+ ArgEffects::Factory AF;
+
+ /// ScratchArgs - A holding buffer for construct ArgEffects.
+ ArgEffects ScratchArgs;
+
+ /// ObjCAllocRetE - Default return effect for methods returning Objective-C
+ /// objects.
+ RetEffect ObjCAllocRetE;
+
+ RetainSummary DefaultSummary;
+ RetainSummary* StopSummary;
+
+ //==-----------------------------------------------------------------==//
+ // Methods.
+ //==-----------------------------------------------------------------==//
+
+ /// getArgEffects - Returns a persistent ArgEffects object based on the
+ /// data in ScratchArgs.
+ ArgEffects getArgEffects();
+
+ enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable };
+
+public:
+ RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
+
+ RetainSummary *getDefaultSummary() {
+ RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
+ return new (Summ) RetainSummary(DefaultSummary);
+ }
+
+ RetainSummary* getUnarySummary(const FunctionType* FT, UnaryFuncKind func);
+
+ RetainSummary* getCFSummaryCreateRule(FunctionDecl* FD);
+ RetainSummary* getCFSummaryGetRule(FunctionDecl* FD);
+ RetainSummary* getCFCreateGetRuleSummary(FunctionDecl* FD, const char* FName);
+
+ RetainSummary* getPersistentSummary(ArgEffects AE, RetEffect RetEff,
+ ArgEffect ReceiverEff = DoNothing,
+ ArgEffect DefaultEff = MayEscape,
+ bool isEndPath = false);
+
+ RetainSummary* getPersistentSummary(RetEffect RE,
+ ArgEffect ReceiverEff = DoNothing,
+ ArgEffect DefaultEff = MayEscape) {
+ return getPersistentSummary(getArgEffects(), RE, ReceiverEff, DefaultEff);
+ }
+
+ RetainSummary *getPersistentStopSummary() {
+ if (StopSummary)
+ return StopSummary;
+
+ StopSummary = getPersistentSummary(RetEffect::MakeNoRet(),
+ StopTracking, StopTracking);
+
+ return StopSummary;
+ }
+
+ RetainSummary *getInitMethodSummary(QualType RetTy);
+
+ void InitializeClassMethodSummaries();
+ void InitializeMethodSummaries();
+
+ bool isTrackedObjCObjectType(QualType T);
+ bool isTrackedCFObjectType(QualType T);
+
+private:
+
+ void addClsMethSummary(IdentifierInfo* ClsII, Selector S,
+ RetainSummary* Summ) {
+ ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
+ }
+
+ void addNSObjectClsMethSummary(Selector S, RetainSummary *Summ) {
+ ObjCClassMethodSummaries[S] = Summ;
+ }
+
+ void addNSObjectMethSummary(Selector S, RetainSummary *Summ) {
+ ObjCMethodSummaries[S] = Summ;
+ }
+
+ void addClassMethSummary(const char* Cls, const char* nullaryName,
+ 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) {
+ 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;
+
+ while (const char* s = va_arg(argp, const char*))
+ II.push_back(&Ctx.Idents.get(s));
+
+ return Ctx.Selectors.getSelector(II.size(), &II[0]);
+ }
+
+ void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy& Summaries,
+ RetainSummary* Summ, va_list argp) {
+ Selector S = generateSelector(argp);
+ Summaries[ObjCSummaryKey(ClsII, S)] = Summ;
+ }
+
+ void addInstMethSummary(const char* Cls, 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, ...) {
+ va_list argp;
+ va_start(argp, Summ);
+ addMethodSummary(&Ctx.Idents.get(Cls),ObjCClassMethodSummaries, Summ, argp);
+ va_end(argp);
+ }
+
+ void addClsMethSummary(IdentifierInfo *II, 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)
+ : Ctx(ctx),
+ CFDictionaryCreateII(&ctx.Idents.get("CFDictionaryCreate")),
+ GCEnabled(gcenabled), AF(BPAlloc), ScratchArgs(AF.GetEmptyMap()),
+ ObjCAllocRetE(gcenabled ? RetEffect::MakeGCNotOwned()
+ : RetEffect::MakeOwned(RetEffect::ObjC, true)),
+ DefaultSummary(AF.GetEmptyMap() /* per-argument effects (none) */,
+ RetEffect::MakeNoRet() /* return effect */,
+ MayEscape, /* default argument effect */
+ DoNothing /* receiver effect */),
+ StopSummary(0) {
+
+ InitializeClassMethodSummaries();
+ InitializeMethodSummaries();
+ }
+
+ ~RetainSummaryManager();
+
+ RetainSummary* getSummary(FunctionDecl* FD);
+
+ RetainSummary* getInstanceMethodSummary(ObjCMessageExpr* ME,
+ const ObjCInterfaceDecl* ID) {
+ return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(),
+ ID, ME->getMethodDecl(), ME->getType());
+ }
+
+ 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);
+
+ RetainSummary *getClassMethodSummary(ObjCMessageExpr *ME) {
+ return getClassMethodSummary(ME->getSelector(), ME->getClassName(),
+ ME->getClassInfo().first,
+ ME->getMethodDecl(), ME->getType());
+ }
+
+ /// getMethodSummary - This version of getMethodSummary is used to query
+ /// the summary for the current method being analyzed.
+ 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, Ctx))
+ 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);
+
+ void updateSummaryFromAnnotations(RetainSummary &Summ,
+ const ObjCMethodDecl *MD);
+
+ void updateSummaryFromAnnotations(RetainSummary &Summ,
+ const FunctionDecl *FD);
+
+ bool isGCEnabled() const { return GCEnabled; }
+
+ RetainSummary *copySummary(RetainSummary *OldSumm) {
+ RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
+ new (Summ) RetainSummary(*OldSumm);
+ return Summ;
+ }
+};
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Implementation of checker data structures.
+//===----------------------------------------------------------------------===//
+
+RetainSummaryManager::~RetainSummaryManager() {}
+
+ArgEffects RetainSummaryManager::getArgEffects() {
+ ArgEffects AE = ScratchArgs;
+ ScratchArgs = AF.GetEmptyMap();
+ return AE;
+}
+
+RetainSummary*
+RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff,
+ ArgEffect ReceiverEff,
+ ArgEffect DefaultEff,
+ bool isEndPath) {
+ // Create the summary and return it.
+ RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
+ new (Summ) RetainSummary(AE, RetEff, DefaultEff, ReceiverEff, isEndPath);
+ return Summ;
+}
+
+//===----------------------------------------------------------------------===//
+// Predicates.
+//===----------------------------------------------------------------------===//
+
+bool RetainSummaryManager::isTrackedObjCObjectType(QualType Ty) {
+ if (!Ctx.isObjCObjectPointerType(Ty))
+ return false;
+
+ // We assume that id<..>, id, and "Class" all represent tracked objects.
+ const PointerType *PT = Ty->getAsPointerType();
+ if (PT == 0)
+ return true;
+
+ const ObjCInterfaceType *OT = PT->getPointeeType()->getAsObjCInterfaceType();
+
+ // We assume that id<..>, id, and "Class" all represent tracked objects.
+ if (!OT)
+ return true;
+
+ // Does the interface subclass NSObject?
+ // FIXME: We can memoize here if this gets too expensive.
+ ObjCInterfaceDecl* ID = OT->getDecl();
+
+ // Assume that anything declared with a forward declaration and no
+ // @interface subclasses NSObject.
+ if (ID->isForwardDecl())
+ return true;
+
+ IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
+
+
+ for ( ; ID ; ID = ID->getSuperClass())
+ if (ID->getIdentifier() == NSObjectII)
+ return true;
+
+ return false;
+}
+
+bool RetainSummaryManager::isTrackedCFObjectType(QualType T) {
+ return isRefType(T, "CF") || // Core Foundation.
+ isRefType(T, "CG") || // Core Graphics.
+ isRefType(T, "DADisk") || // Disk Arbitration API.
+ isRefType(T, "DADissenter") ||
+ isRefType(T, "DASessionRef");
+}
+
+//===----------------------------------------------------------------------===//
+// Summary creation for functions (largely uses of Core Foundation).
+//===----------------------------------------------------------------------===//
+
+static bool isRetain(FunctionDecl* FD, const char* FName) {
+ const char* loc = strstr(FName, "Retain");
+ return loc && loc[sizeof("Retain")-1] == '\0';
+}
+
+static bool isRelease(FunctionDecl* FD, const char* FName) {
+ const char* loc = strstr(FName, "Release");
+ return loc && loc[sizeof("Release")-1] == '\0';
+}
+
+RetainSummary* RetainSummaryManager::getSummary(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;
+
+ do {
+ // We generate "stop" summaries for implicitly defined functions.
+ if (FD->isImplicit()) {
+ S = getPersistentStopSummary();
+ break;
+ }
+
+ // [PR 3337] Use 'getAsFunctionType' to strip away any typedefs on the
+ // function's type.
+ const FunctionType* FT = FD->getType()->getAsFunctionType();
+ const char* FName = FD->getIdentifier()->getName();
+
+ // Strip away preceding '_'. Doing this here will effect all the checks
+ // down below.
+ while (*FName == '_') ++FName;
+
+ // Inspect the result type.
+ QualType RetTy = FT->getResultType();
+
+ // FIXME: This should all be refactored into a chain of "summary lookup"
+ // filters.
+ if (strcmp(FName, "IOServiceGetMatchingServices") == 0) {
+ // FIXES: <rdar://problem/6326900>
+ // This should be addressed using a API table. This strcmp is also
+ // a little gross, but there is no need to super optimize here.
+ assert (ScratchArgs.isEmpty());
+ ScratchArgs = AF.Add(ScratchArgs, 1, DecRef);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ break;
+ }
+
+ // Enable this code once the semantics of NSDeallocateObject are resolved
+ // for GC. <rdar://problem/6619988>
+#if 0
+ // Handle: NSDeallocateObject(id anObject);
+ // This method does allow 'nil' (although we don't check it now).
+ if (strcmp(FName, "NSDeallocateObject") == 0) {
+ return RetTy == Ctx.VoidTy
+ ? getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, Dealloc)
+ : getPersistentStopSummary();
+ }
+#endif
+
+ // Handle: id NSMakeCollectable(CFTypeRef)
+ if (strcmp(FName, "NSMakeCollectable") == 0) {
+ S = (RetTy == Ctx.getObjCIdType())
+ ? getUnarySummary(FT, cfmakecollectable)
+ : getPersistentStopSummary();
+
+ break;
+ }
+
+ if (RetTy->isPointerType()) {
+ // For CoreFoundation ('CF') types.
+ if (isRefType(RetTy, "CF", &Ctx, FName)) {
+ if (isRetain(FD, FName))
+ S = getUnarySummary(FT, cfretain);
+ else if (strstr(FName, "MakeCollectable"))
+ S = getUnarySummary(FT, cfmakecollectable);
+ else
+ S = getCFCreateGetRuleSummary(FD, FName);
+
+ break;
+ }
+
+ // For CoreGraphics ('CG') types.
+ if (isRefType(RetTy, "CG", &Ctx, FName)) {
+ if (isRetain(FD, FName))
+ S = getUnarySummary(FT, cfretain);
+ else
+ S = getCFCreateGetRuleSummary(FD, FName);
+
+ break;
+ }
+
+ // For the Disk Arbitration API (DiskArbitration/DADisk.h)
+ if (isRefType(RetTy, "DADisk") ||
+ isRefType(RetTy, "DADissenter") ||
+ isRefType(RetTy, "DASessionRef")) {
+ S = getCFCreateGetRuleSummary(FD, FName);
+ break;
+ }
+
+ break;
+ }
+
+ // Check for release functions, the only kind of functions that we care
+ // about that don't return a pointer type.
+ if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G')) {
+ // Test for 'CGCF'.
+ if (FName[1] == 'G' && FName[2] == 'C' && FName[3] == 'F')
+ FName += 4;
+ else
+ FName += 2;
+
+ if (isRelease(FD, FName))
+ S = getUnarySummary(FT, cfrelease);
+ else {
+ assert (ScratchArgs.isEmpty());
+ // Remaining CoreFoundation and CoreGraphics functions.
+ // We use to assume that they all strictly followed the ownership idiom
+ // and that ownership cannot be transferred. While this is technically
+ // correct, many methods allow a tracked object to escape. For example:
+ //
+ // CFMutableDictionaryRef x = CFDictionaryCreateMutable(...);
+ // CFDictionaryAddValue(y, key, x);
+ // CFRelease(x);
+ // ... it is okay to use 'x' since 'y' has a reference to it
+ //
+ // We handle this and similar cases with the follow heuristic. If the
+ // function name contains "InsertValue", "SetValue" or "AddValue" then
+ // we assume that arguments may "escape."
+ //
+ ArgEffect E = (CStrInCStrNoCase(FName, "InsertValue") ||
+ CStrInCStrNoCase(FName, "AddValue") ||
+ CStrInCStrNoCase(FName, "SetValue") ||
+ CStrInCStrNoCase(FName, "AppendValue"))
+ ? MayEscape : DoNothing;
+
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, E);
+ }
+ }
+ }
+ while (0);
+
+ if (!S)
+ S = getDefaultSummary();
+
+ // Annotations override defaults.
+ assert(S);
+ updateSummaryFromAnnotations(*S, FD);
+
+ FuncSummaries[FD] = S;
+ return S;
+}
+
+RetainSummary*
+RetainSummaryManager::getCFCreateGetRuleSummary(FunctionDecl* FD,
+ const char* FName) {
+
+ if (strstr(FName, "Create") || strstr(FName, "Copy"))
+ return getCFSummaryCreateRule(FD);
+
+ if (strstr(FName, "Get"))
+ return getCFSummaryGetRule(FD);
+
+ return getDefaultSummary();
+}
+
+RetainSummary*
+RetainSummaryManager::getUnarySummary(const FunctionType* FT,
+ UnaryFuncKind func) {
+
+ // Sanity check that this is *really* a unary function. This can
+ // happen if people do weird things.
+ const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT);
+ if (!FTP || FTP->getNumArgs() != 1)
+ return getPersistentStopSummary();
+
+ assert (ScratchArgs.isEmpty());
+
+ 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();
+ }
+}
+
+RetainSummary* RetainSummaryManager::getCFSummaryCreateRule(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(FunctionDecl* FD) {
+ assert (ScratchArgs.isEmpty());
+ return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF),
+ DoNothing, DoNothing);
+}
+
+//===----------------------------------------------------------------------===//
+// Summary creation for Selectors.
+//===----------------------------------------------------------------------===//
+
+RetainSummary*
+RetainSummaryManager::getInitMethodSummary(QualType RetTy) {
+ assert(ScratchArgs.isEmpty());
+ // 'init' methods conceptually return a newly allocated object and claim
+ // the receiver.
+ if (isTrackedObjCObjectType(RetTy) || isTrackedCFObjectType(RetTy))
+ return getPersistentSummary(RetEffect::MakeOwnedWhenTrackedReceiver(),
+ DecRefMsg);
+
+ return getDefaultSummary();
+}
+
+void
+RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
+ const FunctionDecl *FD) {
+ if (!FD)
+ return;
+
+ // Determine if there is a special return effect for this method.
+ if (isTrackedObjCObjectType(FD->getResultType())) {
+ if (FD->getAttr<NSReturnsRetainedAttr>()) {
+ Summ.setRetEffect(ObjCAllocRetE);
+ }
+ else if (FD->getAttr<CFReturnsRetainedAttr>()) {
+ Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
+ }
+ }
+}
+
+void
+RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
+ const ObjCMethodDecl *MD) {
+ if (!MD)
+ return;
+
+ // Determine if there is a special return effect for this method.
+ if (isTrackedObjCObjectType(MD->getResultType())) {
+ if (MD->getAttr<NSReturnsRetainedAttr>()) {
+ Summ.setRetEffect(ObjCAllocRetE);
+ }
+ else if (MD->getAttr<CFReturnsRetainedAttr>()) {
+ Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
+ }
+ }
+}
+
+RetainSummary*
+RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
+ Selector S, QualType RetTy) {
+
+ if (MD) {
+ // Scan the method decl for 'void*' arguments. These should be treated
+ // as 'StopTracking' because they are often used with delegates.
+ // Delegates are a frequent form of false positives with the retain
+ // count checker.
+ unsigned i = 0;
+ for (ObjCMethodDecl::param_iterator I = MD->param_begin(),
+ E = MD->param_end(); I != E; ++I, ++i)
+ if (ParmVarDecl *PD = *I) {
+ QualType Ty = Ctx.getCanonicalType(PD->getType());
+ if (Ty.getUnqualifiedType() == Ctx.VoidPtrTy)
+ ScratchArgs = AF.Add(ScratchArgs, i, StopTracking);
+ }
+ }
+
+ // Any special effect for the receiver?
+ ArgEffect ReceiverEff = DoNothing;
+
+ // If one of the arguments in the selector has the keyword 'delegate' we
+ // should stop tracking the reference count for the receiver. This is
+ // because the reference count is quite possibly handled by a delegate
+ // method.
+ if (S.isKeywordSelector()) {
+ const std::string &str = S.getAsString();
+ assert(!str.empty());
+ if (CStrInCStrNoCase(&str[0], "delegate:")) ReceiverEff = StopTracking;
+ }
+
+ // Look for methods that return an owned object.
+ if (isTrackedObjCObjectType(RetTy)) {
+ // EXPERIMENTAL: Assume the Cocoa conventions for all objects returned
+ // by instance methods.
+ RetEffect E = followsFundamentalRule(S)
+ ? ObjCAllocRetE : RetEffect::MakeNotOwned(RetEffect::ObjC);
+
+ return getPersistentSummary(E, ReceiverEff, MayEscape);
+ }
+
+ // Look for methods that return an owned core foundation object.
+ if (isTrackedCFObjectType(RetTy)) {
+ RetEffect E = followsFundamentalRule(S)
+ ? RetEffect::MakeOwned(RetEffect::CF, true)
+ : RetEffect::MakeNotOwned(RetEffect::CF);
+
+ return getPersistentSummary(E, ReceiverEff, MayEscape);
+ }
+
+ if (ScratchArgs.isEmpty() && ReceiverEff == DoNothing)
+ return getDefaultSummary();
+
+ return getPersistentSummary(RetEffect::MakeNoRet(), ReceiverEff, MayEscape);
+}
+
+RetainSummary*
+RetainSummaryManager::getInstanceMethodSummary(Selector S,
+ IdentifierInfo *ClsName,
+ const ObjCInterfaceDecl* ID,
+ const ObjCMethodDecl *MD,
+ QualType RetTy) {
+
+ // Look up a summary in our summary cache.
+ ObjCMethodSummariesTy::iterator I = ObjCMethodSummaries.find(ID, ClsName, S);
+
+ if (I != ObjCMethodSummaries.end())
+ return I->second;
+
+ assert(ScratchArgs.isEmpty());
+ RetainSummary *Summ = 0;
+
+ // "initXXX": pass-through for receiver.
+ if (deriveNamingConvention(S) == InitRule)
+ Summ = getInitMethodSummary(RetTy);
+ else
+ Summ = getCommonMethodSummary(MD, S, RetTy);
+
+ // Annotations override defaults.
+ updateSummaryFromAnnotations(*Summ, MD);
+
+ // Memoize the summary.
+ ObjCMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ;
+ return Summ;
+}
+
+RetainSummary*
+RetainSummaryManager::getClassMethodSummary(Selector S, IdentifierInfo *ClsName,
+ const ObjCInterfaceDecl *ID,
+ const ObjCMethodDecl *MD,
+ QualType RetTy) {
+
+ assert(ClsName && "Class name must be specified.");
+ ObjCMethodSummariesTy::iterator I =
+ ObjCClassMethodSummaries.find(ID, ClsName, S);
+
+ if (I != ObjCClassMethodSummaries.end())
+ return I->second;
+
+ RetainSummary *Summ = getCommonMethodSummary(MD, S, RetTy);
+
+ // Annotations override defaults.
+ updateSummaryFromAnnotations(*Summ, MD);
+
+ // Memoize the summary.
+ ObjCClassMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ;
+ return Summ;
+}
+
+void RetainSummaryManager::InitializeClassMethodSummaries() {
+ assert(ScratchArgs.isEmpty());
+ RetainSummary* Summ = getPersistentSummary(ObjCAllocRetE);
+
+ // Create the summaries for "alloc", "new", and "allocWithZone:" for
+ // NSObject and its derivatives.
+ addNSObjectClsMethSummary(GetNullarySelector("alloc", Ctx), Summ);
+ addNSObjectClsMethSummary(GetNullarySelector("new", Ctx), Summ);
+ addNSObjectClsMethSummary(GetUnarySelector("allocWithZone", Ctx), Summ);
+
+ // Create the [NSAssertionHandler currentHander] summary.
+ addClsMethSummary(&Ctx.Idents.get("NSAssertionHandler"),
+ GetNullarySelector("currentHandler", Ctx),
+ getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC)));
+
+ // Create the [NSAutoreleasePool addObject:] summary.
+ ScratchArgs = AF.Add(ScratchArgs, 0, Autorelease);
+ addClsMethSummary(&Ctx.Idents.get("NSAutoreleasePool"),
+ GetUnarySelector("addObject", Ctx),
+ getPersistentSummary(RetEffect::MakeNoRet(),
+ DoNothing, Autorelease));
+
+ // Create the summaries for [NSObject performSelector...]. We treat
+ // these as 'stop tracking' for the arguments because they are often
+ // 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);
+ IdentifierInfo *NSObjectII = &Ctx.Idents.get("NSObject");
+ addClsMethSummary(NSObjectII, Summ, "performSelector", "withObject",
+ "afterDelay", NULL);
+ addClsMethSummary(NSObjectII, Summ, "performSelector", "withObject",
+ "afterDelay", "inModes", NULL);
+ addClsMethSummary(NSObjectII, Summ, "performSelectorOnMainThread",
+ "withObject", "waitUntilDone", NULL);
+ addClsMethSummary(NSObjectII, Summ, "performSelectorOnMainThread",
+ "withObject", "waitUntilDone", "modes", NULL);
+ addClsMethSummary(NSObjectII, Summ, "performSelector", "onThread",
+ "withObject", "waitUntilDone", NULL);
+ addClsMethSummary(NSObjectII, Summ, "performSelector", "onThread",
+ "withObject", "waitUntilDone", "modes", NULL);
+ addClsMethSummary(NSObjectII, Summ, "performSelectorInBackground",
+ "withObject", NULL);
+
+ // Specially handle NSData.
+ RetainSummary *dataWithBytesNoCopySumm =
+ getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC), DoNothing,
+ DoNothing);
+ addClsMethSummary("NSData", dataWithBytesNoCopySumm,
+ "dataWithBytesNoCopy", "length", NULL);
+ addClsMethSummary("NSData", dataWithBytesNoCopySumm,
+ "dataWithBytesNoCopy", "length", "freeWhenDone", NULL);
+}
+
+void RetainSummaryManager::InitializeMethodSummaries() {
+
+ assert (ScratchArgs.isEmpty());
+
+ // Create the "init" selector. It just acts as a pass-through for the
+ // receiver.
+ addNSObjectMethSummary(GetNullarySelector("init", Ctx),
+ getPersistentSummary(RetEffect::MakeOwnedWhenTrackedReceiver(),
+ DecRefMsg));
+
+ // The next methods are allocators.
+ RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE);
+
+ // Create the "copy" selector.
+ addNSObjectMethSummary(GetNullarySelector("copy", Ctx), AllocSumm);
+
+ // Create the "mutableCopy" selector.
+ addNSObjectMethSummary(GetNullarySelector("mutableCopy", Ctx), AllocSumm);
+
+ // Create the "retain" selector.
+ RetEffect E = RetEffect::MakeReceiverAlias();
+ RetainSummary *Summ = getPersistentSummary(E, IncRefMsg);
+ addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ);
+
+ // Create the "release" selector.
+ Summ = getPersistentSummary(E, DecRefMsg);
+ addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ);
+
+ // Create the "drain" selector.
+ Summ = getPersistentSummary(E, isGCEnabled() ? DoNothing : DecRef);
+ addNSObjectMethSummary(GetNullarySelector("drain", Ctx), Summ);
+
+ // Create the -dealloc summary.
+ Summ = getPersistentSummary(RetEffect::MakeNoRet(), Dealloc);
+ addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ);
+
+ // Create the "autorelease" selector.
+ Summ = getPersistentSummary(E, Autorelease);
+ addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ);
+
+ // Specially handle NSAutoreleasePool.
+ addInstMethSummary("NSAutoreleasePool", "init",
+ getPersistentSummary(RetEffect::MakeReceiverAlias(),
+ NewAutoreleasePool));
+
+ // For NSWindow, allocated objects are (initially) self-owned.
+ // FIXME: For now we opt for false negatives with NSWindow, as these objects
+ // self-own themselves. However, they only do this once they are displayed.
+ // 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(),
+ StopTracking,
+ StopTracking);
+
+ addClassMethSummary("NSWindow", "alloc", NoTrackYet);
+
+#if 0
+ addInstMethSummary("NSWindow", NoTrackYet, "initWithContentRect",
+ "styleMask", "backing", "defer", NULL);
+
+ addInstMethSummary("NSWindow", NoTrackYet, "initWithContentRect",
+ "styleMask", "backing", "defer", "screen", NULL);
+#endif
+
+ // For NSPanel (which subclasses NSWindow), allocated objects are not
+ // self-owned.
+ // FIXME: For now we don't track NSPanels. object for the same reason
+ // as for NSWindow objects.
+ addClassMethSummary("NSPanel", "alloc", NoTrackYet);
+
+#if 0
+ addInstMethSummary("NSPanel", NoTrackYet, "initWithContentRect",
+ "styleMask", "backing", "defer", NULL);
+
+ addInstMethSummary("NSPanel", NoTrackYet, "initWithContentRect",
+ "styleMask", "backing", "defer", "screen", NULL);
+#endif
+
+ // Don't track allocated autorelease pools yet, as it is okay to prematurely
+ // 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);
+ addInstMethSummary("QCView", AllocSumm,
+ "createSnapshotImageOfType", NULL);
+
+ // Create summaries for CIContext, 'createCGImage'.
+ addInstMethSummary("CIContext", AllocSumm,
+ "createCGImage", "fromRect", NULL);
+ addInstMethSummary("CIContext", AllocSumm,
+ "createCGImage", "fromRect", "format", "colorSpace", NULL);
+}
+
+//===----------------------------------------------------------------------===//
+// Reference-counting logic (typestate + counts).
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class VISIBILITY_HIDDEN RefVal {
+public:
+ enum Kind {
+ Owned = 0, // Owning reference.
+ NotOwned, // Reference is not owned by still valid (not freed).
+ Released, // Object has been released.
+ ReturnedOwned, // Returned object passes ownership to caller.
+ ReturnedNotOwned, // Return object does not pass ownership to caller.
+ ERROR_START,
+ ErrorDeallocNotOwned, // -dealloc called on non-owned object.
+ ErrorDeallocGC, // Calling -dealloc with GC enabled.
+ ErrorUseAfterRelease, // Object used after released.
+ ErrorReleaseNotOwned, // Release of an object that was not owned.
+ ERROR_LEAK_START,
+ ErrorLeak, // A memory leak due to excessive reference counts.
+ ErrorLeakReturned, // A memory leak due to the returning method not having
+ // the correct naming conventions.
+ ErrorGCLeakReturned,
+ ErrorOverAutorelease,
+ ErrorReturnedNotOwned
+ };
+
+private:
+ Kind kind;
+ RetEffect::ObjKind okind;
+ unsigned Cnt;
+ unsigned ACnt;
+ QualType T;
+
+ RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t)
+ : kind(k), okind(o), Cnt(cnt), ACnt(acnt), T(t) {}
+
+ RefVal(Kind k, unsigned cnt = 0)
+ : kind(k), okind(RetEffect::AnyObj), Cnt(cnt), ACnt(0) {}
+
+public:
+ Kind getKind() const { return kind; }
+
+ RetEffect::ObjKind getObjKind() const { return okind; }
+
+ unsigned getCount() const { return Cnt; }
+ unsigned getAutoreleaseCount() const { return ACnt; }
+ unsigned getCombinedCounts() const { return Cnt + ACnt; }
+ void clearCounts() { Cnt = 0; ACnt = 0; }
+ void setCount(unsigned i) { Cnt = i; }
+ void setAutoreleaseCount(unsigned i) { ACnt = i; }
+
+ QualType getType() const { return T; }
+
+ // Useful predicates.
+
+ static bool isError(Kind k) { return k >= ERROR_START; }
+
+ static bool isLeak(Kind k) { return k >= ERROR_LEAK_START; }
+
+ bool isOwned() const {
+ return getKind() == Owned;
+ }
+
+ bool isNotOwned() const {
+ return getKind() == NotOwned;
+ }
+
+ bool isReturnedOwned() const {
+ return getKind() == ReturnedOwned;
+ }
+
+ bool isReturnedNotOwned() const {
+ return getKind() == ReturnedNotOwned;
+ }
+
+ bool isNonLeakError() const {
+ Kind k = getKind();
+ return isError(k) && !isLeak(k);
+ }
+
+ static RefVal makeOwned(RetEffect::ObjKind o, QualType t,
+ unsigned Count = 1) {
+ return RefVal(Owned, o, Count, 0, t);
+ }
+
+ static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t,
+ unsigned Count = 0) {
+ return RefVal(NotOwned, o, Count, 0, t);
+ }
+
+ // Comparison, profiling, and pretty-printing.
+
+ bool operator==(const RefVal& X) const {
+ return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt;
+ }
+
+ RefVal operator-(size_t i) const {
+ return RefVal(getKind(), getObjKind(), getCount() - i,
+ getAutoreleaseCount(), getType());
+ }
+
+ RefVal operator+(size_t i) const {
+ return RefVal(getKind(), getObjKind(), getCount() + i,
+ getAutoreleaseCount(), getType());
+ }
+
+ RefVal operator^(Kind k) const {
+ return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(),
+ getType());
+ }
+
+ RefVal autorelease() const {
+ return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1,
+ getType());
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddInteger((unsigned) kind);
+ ID.AddInteger(Cnt);
+ ID.AddInteger(ACnt);
+ ID.Add(T);
+ }
+
+ void print(std::ostream& Out) const;
+};
+
+void RefVal::print(std::ostream& Out) const {
+ if (!T.isNull())
+ Out << "Tracked Type:" << T.getAsString() << '\n';
+
+ switch (getKind()) {
+ default: assert(false);
+ case Owned: {
+ Out << "Owned";
+ unsigned cnt = getCount();
+ if (cnt) Out << " (+ " << cnt << ")";
+ break;
+ }
+
+ case NotOwned: {
+ Out << "NotOwned";
+ unsigned cnt = getCount();
+ if (cnt) Out << " (+ " << cnt << ")";
+ break;
+ }
+
+ case ReturnedOwned: {
+ Out << "ReturnedOwned";
+ unsigned cnt = getCount();
+ if (cnt) Out << " (+ " << cnt << ")";
+ break;
+ }
+
+ case ReturnedNotOwned: {
+ Out << "ReturnedNotOwned";
+ unsigned cnt = getCount();
+ if (cnt) Out << " (+ " << cnt << ")";
+ break;
+ }
+
+ case Released:
+ Out << "Released";
+ break;
+
+ case ErrorDeallocGC:
+ Out << "-dealloc (GC)";
+ break;
+
+ case ErrorDeallocNotOwned:
+ Out << "-dealloc (not-owned)";
+ break;
+
+ case ErrorLeak:
+ Out << "Leaked";
+ break;
+
+ case ErrorLeakReturned:
+ Out << "Leaked (Bad naming)";
+ break;
+
+ case ErrorGCLeakReturned:
+ Out << "Leaked (GC-ed at return)";
+ break;
+
+ case ErrorUseAfterRelease:
+ Out << "Use-After-Release [ERROR]";
+ break;
+
+ case ErrorReleaseNotOwned:
+ Out << "Release of Not-Owned [ERROR]";
+ break;
+
+ case RefVal::ErrorOverAutorelease:
+ Out << "Over autoreleased";
+ break;
+
+ case RefVal::ErrorReturnedNotOwned:
+ Out << "Non-owned object returned instead of owned";
+ break;
+ }
+
+ if (ACnt) {
+ Out << " [ARC +" << ACnt << ']';
+ }
+}
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// RefBindings - State used to track object reference counts.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings;
+static int RefBIndex = 0;
+
+namespace clang {
+ template<>
+ struct GRStateTrait<RefBindings> : public GRStatePartialTrait<RefBindings> {
+ static inline void* GDMIndex() { return &RefBIndex; }
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// AutoreleaseBindings - State used to track objects in autorelease pools.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::ImmutableMap<SymbolRef, unsigned> ARCounts;
+typedef llvm::ImmutableMap<SymbolRef, ARCounts> ARPoolContents;
+typedef llvm::ImmutableList<SymbolRef> ARStack;
+
+static int AutoRCIndex = 0;
+static int AutoRBIndex = 0;
+
+namespace { class VISIBILITY_HIDDEN AutoreleasePoolContents {}; }
+namespace { class VISIBILITY_HIDDEN AutoreleaseStack {}; }
+
+namespace clang {
+template<> struct GRStateTrait<AutoreleaseStack>
+ : public GRStatePartialTrait<ARStack> {
+ static inline void* GDMIndex() { return &AutoRBIndex; }
+};
+
+template<> struct GRStateTrait<AutoreleasePoolContents>
+ : public GRStatePartialTrait<ARPoolContents> {
+ static inline void* GDMIndex() { return &AutoRCIndex; }
+};
+} // end clang namespace
+
+static SymbolRef GetCurrentAutoreleasePool(const GRState* state) {
+ ARStack stack = state->get<AutoreleaseStack>();
+ return stack.isEmpty() ? SymbolRef() : stack.getHead();
+}
+
+static GRStateRef SendAutorelease(GRStateRef state, ARCounts::Factory &F,
+ SymbolRef sym) {
+
+ SymbolRef pool = GetCurrentAutoreleasePool(state);
+ const ARCounts *cnts = state.get<AutoreleasePoolContents>(pool);
+ ARCounts newCnts(0);
+
+ if (cnts) {
+ const unsigned *cnt = (*cnts).lookup(sym);
+ newCnts = F.Add(*cnts, sym, cnt ? *cnt + 1 : 1);
+ }
+ else
+ newCnts = F.Add(F.GetEmptyMap(), sym, 1);
+
+ return state.set<AutoreleasePoolContents>(pool, newCnts);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer functions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class VISIBILITY_HIDDEN CFRefCount : public GRSimpleVals {
+public:
+ class BindingsPrinter : public GRState::Printer {
+ public:
+ virtual void Print(std::ostream& Out, const GRState* state,
+ const char* nl, const char* sep);
+ };
+
+private:
+ typedef llvm::DenseMap<const GRExprEngine::NodeTy*, 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;
+
+ GRStateRef Update(GRStateRef state, SymbolRef sym, RefVal V, ArgEffect E,
+ RefVal::Kind& hasErr);
+
+ void ProcessNonLeakError(ExplodedNodeSet<GRState>& Dst,
+ GRStmtNodeBuilder<GRState>& Builder,
+ Expr* NodeExpr, Expr* ErrorExpr,
+ ExplodedNode<GRState>* Pred,
+ const GRState* St,
+ RefVal::Kind hasErr, SymbolRef Sym);
+
+ GRStateRef HandleSymbolDeath(GRStateRef state, SymbolRef sid, RefVal V,
+ llvm::SmallVectorImpl<SymbolRef> &Leaked);
+
+ ExplodedNode<GRState>* ProcessLeaks(GRStateRef state,
+ llvm::SmallVectorImpl<SymbolRef> &Leaked,
+ GenericNodeBuilder &Builder,
+ GRExprEngine &Eng,
+ ExplodedNode<GRState> *Pred = 0);
+
+public:
+ CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
+ : Summaries(Ctx, gcenabled),
+ LOpts(lopts), useAfterRelease(0), releaseNotOwned(0),
+ deallocGC(0), deallocNotOwned(0),
+ leakWithinFunction(0), leakAtReturn(0), overAutorelease(0),
+ returnNotOwnedForOwned(0), BR(0) {}
+
+ virtual ~CFRefCount() {}
+
+ void RegisterChecks(BugReporter &BR);
+
+ virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {
+ Printers.push_back(new BindingsPrinter());
+ }
+
+ bool isGCEnabled() const { return Summaries.isGCEnabled(); }
+ const LangOptions& getLangOptions() const { return LOpts; }
+
+ const RetainSummary *getSummaryOfNode(const ExplodedNode<GRState> *N) const {
+ SummaryLogTy::const_iterator I = SummaryLog.find(N);
+ return I == SummaryLog.end() ? 0 : I->second;
+ }
+
+ // Calls.
+
+ void EvalSummary(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Eng,
+ GRStmtNodeBuilder<GRState>& Builder,
+ Expr* Ex,
+ Expr* Receiver,
+ const RetainSummary& Summ,
+ ExprIterator arg_beg, ExprIterator arg_end,
+ ExplodedNode<GRState>* Pred);
+
+ virtual void EvalCall(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Eng,
+ GRStmtNodeBuilder<GRState>& Builder,
+ CallExpr* CE, SVal L,
+ ExplodedNode<GRState>* Pred);
+
+
+ virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder<GRState>& Builder,
+ ObjCMessageExpr* ME,
+ ExplodedNode<GRState>* Pred);
+
+ bool EvalObjCMessageExprAux(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder<GRState>& Builder,
+ ObjCMessageExpr* ME,
+ ExplodedNode<GRState>* Pred);
+
+ // Stores.
+ virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val);
+
+ // End-of-path.
+
+ virtual void EvalEndPath(GRExprEngine& Engine,
+ GREndPathNodeBuilder<GRState>& Builder);
+
+ virtual void EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder<GRState>& Builder,
+ ExplodedNode<GRState>* Pred,
+ Stmt* S, const GRState* state,
+ SymbolReaper& SymReaper);
+
+ std::pair<ExplodedNode<GRState>*, GRStateRef>
+ HandleAutoreleaseCounts(GRStateRef state, GenericNodeBuilder Bd,
+ ExplodedNode<GRState>* Pred, GRExprEngine &Eng,
+ SymbolRef Sym, RefVal V, bool &stop);
+ // Return statements.
+
+ virtual void EvalReturn(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder<GRState>& Builder,
+ ReturnStmt* S,
+ ExplodedNode<GRState>* Pred);
+
+ // Assumptions.
+
+ virtual const GRState* EvalAssume(GRStateManager& VMgr,
+ const GRState* St, SVal Cond,
+ bool Assumption, bool& isFeasible);
+};
+
+} // end anonymous namespace
+
+static void PrintPool(std::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(std::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 {
+
+ //===-------------===//
+ // Bug Descriptions. //
+ //===-------------===//
+
+ class VISIBILITY_HIDDEN CFRefBug : public BugType {
+ protected:
+ CFRefCount& TF;
+
+ CFRefBug(CFRefCount* tf, const char* name)
+ : BugType(name, "Memory (Core Foundation/Objective-C)"), TF(*tf) {}
+ public:
+
+ CFRefCount& getTF() { return TF; }
+ const CFRefCount& getTF() const { return TF; }
+
+ // FIXME: Eventually remove.
+ virtual const char* getDescription() const = 0;
+
+ virtual bool isLeak() const { return false; }
+ };
+
+ class VISIBILITY_HIDDEN UseAfterRelease : public CFRefBug {
+ public:
+ UseAfterRelease(CFRefCount* tf)
+ : CFRefBug(tf, "Use-after-release") {}
+
+ const char* getDescription() const {
+ return "Reference-counted object is used after it is released";
+ }
+ };
+
+ class VISIBILITY_HIDDEN BadRelease : public CFRefBug {
+ public:
+ BadRelease(CFRefCount* tf) : CFRefBug(tf, "Bad release") {}
+
+ const char* getDescription() const {
+ return "Incorrect decrement of the reference count of an "
+ "object is not owned at this point by the caller";
+ }
+ };
+
+ class VISIBILITY_HIDDEN DeallocGC : public CFRefBug {
+ public:
+ DeallocGC(CFRefCount *tf)
+ : CFRefBug(tf, "-dealloc called while using garbage collection") {}
+
+ const char *getDescription() const {
+ return "-dealloc called while using garbage collection";
+ }
+ };
+
+ class VISIBILITY_HIDDEN DeallocNotOwned : public CFRefBug {
+ public:
+ DeallocNotOwned(CFRefCount *tf)
+ : CFRefBug(tf, "-dealloc sent to non-exclusively owned object") {}
+
+ const char *getDescription() const {
+ return "-dealloc sent to object that may be referenced elsewhere";
+ }
+ };
+
+ class VISIBILITY_HIDDEN OverAutorelease : public CFRefBug {
+ public:
+ OverAutorelease(CFRefCount *tf) :
+ CFRefBug(tf, "Object sent -autorelease too many times") {}
+
+ const char *getDescription() const {
+ return "Object sent -autorelease too many times";
+ }
+ };
+
+ class VISIBILITY_HIDDEN ReturnedNotOwnedForOwned : public CFRefBug {
+ public:
+ ReturnedNotOwnedForOwned(CFRefCount *tf) :
+ CFRefBug(tf, "Method should return an owned object") {}
+
+ const char *getDescription() const {
+ return "Object with +0 retain counts returned to caller where a +1 "
+ "(owning) retain count is expected";
+ }
+ };
+
+ class VISIBILITY_HIDDEN Leak : public CFRefBug {
+ const bool isReturn;
+ protected:
+ Leak(CFRefCount* tf, const char* name, bool isRet)
+ : CFRefBug(tf, name), isReturn(isRet) {}
+ public:
+
+ const char* getDescription() const { return ""; }
+
+ bool isLeak() const { return true; }
+ };
+
+ class VISIBILITY_HIDDEN LeakAtReturn : public Leak {
+ public:
+ LeakAtReturn(CFRefCount* tf, const char* name)
+ : Leak(tf, name, true) {}
+ };
+
+ class VISIBILITY_HIDDEN LeakWithinFunction : public Leak {
+ public:
+ LeakWithinFunction(CFRefCount* tf, const char* name)
+ : Leak(tf, name, false) {}
+ };
+
+ //===---------===//
+ // Bug Reports. //
+ //===---------===//
+
+ class VISIBILITY_HIDDEN CFRefReport : public RangedBugReport {
+ protected:
+ SymbolRef Sym;
+ const CFRefCount &TF;
+ public:
+ CFRefReport(CFRefBug& D, const CFRefCount &tf,
+ ExplodedNode<GRState> *n, SymbolRef sym)
+ : RangedBugReport(D, D.getDescription(), n), Sym(sym), TF(tf) {}
+
+ CFRefReport(CFRefBug& D, const CFRefCount &tf,
+ ExplodedNode<GRState> *n, SymbolRef sym, const char* endText)
+ : RangedBugReport(D, D.getDescription(), endText, n), Sym(sym), TF(tf) {}
+
+ virtual ~CFRefReport() {}
+
+ CFRefBug& getBugType() {
+ return (CFRefBug&) RangedBugReport::getBugType();
+ }
+ const CFRefBug& getBugType() const {
+ return (const CFRefBug&) RangedBugReport::getBugType();
+ }
+
+ virtual void getRanges(BugReporter& BR, const SourceRange*& beg,
+ const SourceRange*& end) {
+
+ if (!getBugType().isLeak())
+ RangedBugReport::getRanges(BR, beg, end);
+ else
+ beg = end = 0;
+ }
+
+ SymbolRef getSymbol() const { return Sym; }
+
+ PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N);
+
+ std::pair<const char**,const char**> getExtraDescriptiveText();
+
+ PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N,
+ const ExplodedNode<GRState>* PrevN,
+ BugReporterContext& BRC);
+ };
+
+ class VISIBILITY_HIDDEN CFRefLeakReport : public CFRefReport {
+ SourceLocation AllocSite;
+ const MemRegion* AllocBinding;
+ public:
+ CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
+ ExplodedNode<GRState> *n, SymbolRef sym,
+ GRExprEngine& Eng);
+
+ PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N);
+
+ SourceLocation getLocation() const { return AllocSite; }
+ };
+} // end anonymous namespace
+
+void CFRefCount::RegisterChecks(BugReporter& BR) {
+ 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";
+ }
+
+ leakAtReturn = new LeakAtReturn(this, name);
+ 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";
+ }
+
+ leakWithinFunction = new LeakWithinFunction(this, name);
+ BR.Register(leakWithinFunction);
+
+ // Save the reference to the BugReporter.
+ this->BR = &BR;
+}
+
+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);
+ }
+}
+
+static inline bool contains(const llvm::SmallVectorImpl<ArgEffect>& V,
+ ArgEffect X) {
+ for (llvm::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<GRState>* N,
+ const ExplodedNode<GRState>* PrevN,
+ BugReporterContext& BRC) {
+
+ if (!isa<PostStmt>(N->getLocation()))
+ return NULL;
+
+ // Check if the type state has changed.
+ GRStateManager &StMgr = BRC.getStateManager();
+ GRStateRef PrevSt(PrevN->getState(), StMgr);
+ GRStateRef CurrSt(N->getState(), StMgr);
+
+ const RefVal* CurrT = CurrSt.get<RefBindings>(Sym);
+ if (!CurrT) return NULL;
+
+ const RefVal& CurrV = *CurrT;
+ const RefVal* PrevT = PrevSt.get<RefBindings>(Sym);
+
+ // Create a string buffer to constain all the useful things we want
+ // to tell the user.
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+
+ // This is the allocation site since the previous node had no bindings
+ // for this symbol.
+ if (!PrevT) {
+ Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+
+ if (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->getNameAsString() <<'\'';
+ else
+ os << "function call";
+ }
+ else {
+ assert (isa<ObjCMessageExpr>(S));
+ os << "Method";
+ }
+
+ if (CurrV.getObjKind() == RetEffect::CF) {
+ os << " returns a Core Foundation object with a ";
+ }
+ else {
+ assert (CurrV.getObjKind() == RetEffect::ObjC);
+ os << " returns an Objective-C object with a ";
+ }
+
+ if (CurrV.isOwned()) {
+ os << "+1 retain count (owning reference).";
+
+ if (static_cast<CFRefBug&>(getBugType()).getTF().isGCEnabled()) {
+ assert(CurrV.getObjKind() == RetEffect::CF);
+ os << " "
+ "Core Foundation objects are not automatically garbage collected.";
+ }
+ }
+ else {
+ assert (CurrV.isNotOwned());
+ os << "+0 retain count (non-owning reference).";
+ }
+
+ PathDiagnosticLocation Pos(S, BRC.getSourceManager());
+ 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;
+
+ if (const RetainSummary *Summ =
+ TF.getSummaryOfNode(BRC.getNodeResolver().getOriginalNode(N))) {
+ // We only have summaries attached to nodes after evaluating CallExpr and
+ // ObjCMessageExprs.
+ Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ // Iterate through the parameter expressions and see if the symbol
+ // was ever passed as an argument.
+ unsigned i = 0;
+
+ for (CallExpr::arg_iterator AI=CE->arg_begin(), AE=CE->arg_end();
+ AI!=AE; ++AI, ++i) {
+
+ // Retrieve the value of the argument. Is it the symbol
+ // we are interested in?
+ if (CurrSt.GetSValAsScalarOrLoc(*AI).getAsLocSymbol() != Sym)
+ continue;
+
+ // We have an argument. Get the effect!
+ AEffects.push_back(Summ->getArg(i));
+ }
+ }
+ else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
+ if (Expr *receiver = ME->getReceiver())
+ if (CurrSt.GetSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) {
+ // The symbol we are tracking is the receiver.
+ AEffects.push_back(Summ->getReceiverEffect());
+ }
+ }
+ }
+
+ do {
+ // Get the previous type state.
+ RefVal PrevV = *PrevT;
+
+ // Specially handle -dealloc.
+ if (!TF.isGCEnabled() && 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.
+ // This case is handled elsewhere.
+ if (CurrV.getKind() == RefVal::Released) {
+ assert(CurrV.getCombinedCounts() == 0);
+ os << "Object released by directly sending the '-dealloc' message";
+ break;
+ }
+ }
+
+ // Specially handle CFMakeCollectable and friends.
+ if (contains(AEffects, MakeCollectable)) {
+ // Get the name of the function.
+ Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+ SVal X = CurrSt.GetSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee());
+ const FunctionDecl* FD = X.getAsFunctionDecl();
+ const std::string& FName = FD->getNameAsString();
+
+ if (TF.isGCEnabled()) {
+ // 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
+ << "' decrements an object's retain count and registers the "
+ "object with the garbage collector. ";
+
+ if (CurrV.getKind() == RefVal::Released) {
+ assert(CurrV.getCount() == 0);
+ os << "Since it now has a 0 retain count the object can be "
+ "automatically collected by the garbage collector.";
+ }
+ else
+ os << "An object must have a 0 retain count to be garbage collected. "
+ "After this call its retain count is +" << CurrV.getCount()
+ << '.';
+ }
+ else
+ os << "When GC is not enabled a call to '" << FName
+ << "' has no effect on its argument.";
+
+ // Nothing more to say.
+ break;
+ }
+
+ // Determine if the typestate has changed.
+ if (!(PrevV == CurrV))
+ switch (CurrV.getKind()) {
+ case RefVal::Owned:
+ case RefVal::NotOwned:
+
+ if (PrevV.getCount() == CurrV.getCount()) {
+ // Did an autorelease message get sent?
+ if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount())
+ return 0;
+
+ assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount());
+ os << "Object sent -autorelease message";
+ break;
+ }
+
+ if (PrevV.getCount() > CurrV.getCount())
+ os << "Reference count decremented.";
+ else
+ os << "Reference count incremented.";
+
+ if (unsigned Count = CurrV.getCount())
+ os << " The object now has a +" << Count << " retain count.";
+
+ if (PrevV.getKind() == RefVal::Released) {
+ assert(TF.isGCEnabled() && CurrV.getCount() > 0);
+ os << " The object is not eligible for garbage collection until the "
+ "retain count reaches 0 again.";
+ }
+
+ break;
+
+ case RefVal::Released:
+ os << "Object released.";
+ break;
+
+ case RefVal::ReturnedOwned:
+ os << "Object returned to caller as an owning reference (single retain "
+ "count transferred to caller).";
+ break;
+
+ case RefVal::ReturnedNotOwned:
+ os << "Object returned to caller with a +0 (non-owning) retain count.";
+ break;
+
+ default:
+ return NULL;
+ }
+
+ // Emit any remaining diagnostics for the argument effects (if any).
+ for (llvm::SmallVectorImpl<ArgEffect>::iterator I=AEffects.begin(),
+ E=AEffects.end(); I != E; ++I) {
+
+ // A bunch of things have alternate behavior under GC.
+ if (TF.isGCEnabled())
+ switch (*I) {
+ default: break;
+ case Autorelease:
+ os << "In GC mode an 'autorelease' has no effect.";
+ continue;
+ case IncRefMsg:
+ os << "In GC mode the 'retain' message has no effect.";
+ continue;
+ case DecRefMsg:
+ os << "In GC mode the 'release' message has no effect.";
+ continue;
+ }
+ }
+ } while(0);
+
+ if (os.str().empty())
+ return 0; // We have nothing to say!
+
+ Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+ PathDiagnosticLocation Pos(S, BRC.getSourceManager());
+ PathDiagnosticPiece* P = new PathDiagnosticEventPiece(Pos, os.str());
+
+ // Add the range by scanning the children of the statement for any bindings
+ // to Sym.
+ for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
+ if (Expr* Exp = dyn_cast_or_null<Expr>(*I))
+ if (CurrSt.GetSValAsScalarOrLoc(Exp).getAsLocSymbol() == Sym) {
+ P->addRange(Exp->getSourceRange());
+ break;
+ }
+
+ return P;
+}
+
+namespace {
+ class VISIBILITY_HIDDEN FindUniqueBinding :
+ public StoreManager::BindingsHandler {
+ SymbolRef Sym;
+ const MemRegion* Binding;
+ bool First;
+
+ public:
+ FindUniqueBinding(SymbolRef sym) : Sym(sym), Binding(0), First(true) {}
+
+ bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
+ SVal val) {
+
+ SymbolRef SymV = val.getAsSymbol();
+ if (!SymV || SymV != Sym)
+ return true;
+
+ if (Binding) {
+ First = false;
+ return false;
+ }
+ else
+ Binding = R;
+
+ return true;
+ }
+
+ operator bool() { return First && Binding; }
+ const MemRegion* getRegion() { return Binding; }
+ };
+}
+
+static std::pair<const ExplodedNode<GRState>*,const MemRegion*>
+GetAllocationSite(GRStateManager& StateMgr, const ExplodedNode<GRState>* N,
+ SymbolRef Sym) {
+
+ // Find both first node that referred to the tracked symbol and the
+ // memory location that value was store to.
+ const ExplodedNode<GRState>* Last = N;
+ const MemRegion* FirstBinding = 0;
+
+ while (N) {
+ const GRState* St = N->getState();
+ RefBindings B = St->get<RefBindings>();
+
+ if (!B.lookup(Sym))
+ break;
+
+ FindUniqueBinding FB(Sym);
+ StateMgr.iterBindings(St, FB);
+ if (FB) FirstBinding = FB.getRegion();
+
+ Last = N;
+ N = N->pred_empty() ? NULL : *(N->pred_begin());
+ }
+
+ return std::make_pair(Last, FirstBinding);
+}
+
+PathDiagnosticPiece*
+CFRefReport::getEndPath(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* EndN) {
+ // Tell the BugReporterContext to report cases when the tracked symbol is
+ // assigned to different variables, etc.
+ BRC.addNotableSymbol(Sym);
+ return RangedBugReport::getEndPath(BRC, EndN);
+}
+
+PathDiagnosticPiece*
+CFRefLeakReport::getEndPath(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* EndN){
+
+ // Tell the BugReporterContext to report cases when the tracked symbol is
+ // assigned to different variables, etc.
+ BRC.addNotableSymbol(Sym);
+
+ // 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<GRState>* AllocNode = 0;
+ const MemRegion* FirstBinding = 0;
+
+ llvm::tie(AllocNode, FirstBinding) =
+ GetAllocationSite(BRC.getStateManager(), EndN, Sym);
+
+ // Get the allocate site.
+ assert(AllocNode);
+ Stmt* FirstStmt = cast<PostStmt>(AllocNode->getLocation()).getStmt();
+
+ SourceManager& SMgr = BRC.getSourceManager();
+ unsigned AllocLine =SMgr.getInstantiationLineNumber(FirstStmt->getLocStart());
+
+ // 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<GRState>* 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 = BRC.getCodeDecl();
+ L = PathDiagnosticLocation(D.getBodyRBrace(BRC.getASTContext()), SMgr);
+ }
+
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+
+ os << "Object allocated on line " << AllocLine;
+
+ if (FirstBinding)
+ os << " and stored into '" << FirstBinding->getString() << '\'';
+
+ // Get the retain count.
+ const RefVal* RV = EndN->getState()->get<RefBindings>(Sym);
+
+ if (RV->getKind() == RefVal::ErrorLeakReturned) {
+ // FIXME: Per comments in rdar://6320065, "create" only applies to CF
+ // ojbects. Only "copy", "alloc", "retain" and "new" transfer ownership
+ // to the caller for NS objects.
+ ObjCMethodDecl& MD = cast<ObjCMethodDecl>(BRC.getCodeDecl());
+ os << " is returned from a method whose name ('"
+ << MD.getSelector().getAsString()
+ << "') does not contain 'copy' or otherwise starts with"
+ " 'new' or 'alloc'. This violates the naming convention rules given"
+ " in the Memory Management Guide for Cocoa (object leaked)";
+ }
+ else if (RV->getKind() == RefVal::ErrorGCLeakReturned) {
+ ObjCMethodDecl& MD = cast<ObjCMethodDecl>(BRC.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 "
+ "count since they expect the object to be managed by the garbage "
+ "collector";
+ }
+ else
+ os << " is no longer referenced after this point and has a retain count of"
+ " +" << RV->getCount() << " (object leaked)";
+
+ return new PathDiagnosticEventPiece(L, os.str());
+}
+
+CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
+ ExplodedNode<GRState> *n,
+ SymbolRef sym, GRExprEngine& Eng)
+: CFRefReport(D, tf, n, sym)
+{
+
+ // Most bug reports are cached at the location where they occured.
+ // With leaks, we want to unique them by the location where they were
+ // allocated, and only report a single path. To do this, we need to find
+ // the allocation site of a piece of tracked memory, which we do via a
+ // call to GetAllocationSite. This will walk the ExplodedGraph backwards.
+ // 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<GRState>* AllocNode = 0;
+
+ llvm::tie(AllocNode, AllocBinding) = // Set AllocBinding.
+ GetAllocationSite(Eng.getStateManager(), getEndNode(), getSymbol());
+
+ // Get the SourceLocation for the allocation site.
+ ProgramPoint P = AllocNode->getLocation();
+ AllocSite = cast<PostStmt>(P).getStmt()->getLocStart();
+
+ // 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);
+ os << "Potential leak ";
+ if (tf.isGCEnabled()) {
+ 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() << '\'';
+}
+
+//===----------------------------------------------------------------------===//
+// Main checker logic.
+//===----------------------------------------------------------------------===//
+
+/// 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(Expr* RetE, ASTContext& Ctx) {
+
+ QualType RetTy = RetE->getType();
+
+ // FIXME: We aren't handling id<...>.
+ const PointerType* PT = RetTy->getAsPointerType();
+ if (!PT)
+ return RetTy;
+
+ // If RetEx is not a message expression just return its type.
+ // If RetEx is a message expression, return its types if it is something
+ /// more specific than id.
+
+ ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(RetE);
+
+ if (!ME || !Ctx.isObjCIdStructType(PT->getPointeeType()))
+ return RetTy;
+
+ ObjCInterfaceDecl* D = ME->getClassInfo().first;
+
+ // At this point we know the return type of the message expression is id.
+ // If we have an ObjCInterceDecl, we know this is a call to a class method
+ // whose type we can resolve. In such cases, promote the return type to
+ // Class*.
+ return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
+}
+
+
+void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Eng,
+ GRStmtNodeBuilder<GRState>& Builder,
+ Expr* Ex,
+ Expr* Receiver,
+ const RetainSummary& Summ,
+ ExprIterator arg_beg, ExprIterator arg_end,
+ ExplodedNode<GRState>* Pred) {
+
+ // Get the state.
+ GRStateManager& StateMgr = Eng.getStateManager();
+ GRStateRef state(Builder.GetState(Pred), StateMgr);
+ ASTContext& Ctx = StateMgr.getContext();
+ ValueManager &ValMgr = Eng.getValueManager();
+
+ // Evaluate the effect of the arguments.
+ RefVal::Kind hasErr = (RefVal::Kind) 0;
+ unsigned idx = 0;
+ Expr* ErrorExpr = NULL;
+ SymbolRef ErrorSym = 0;
+
+ for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) {
+ SVal V = state.GetSValAsScalarOrLoc(*I);
+ SymbolRef Sym = V.getAsLocSymbol();
+
+ if (Sym)
+ if (RefBindings::data_type* T = state.get<RefBindings>(Sym)) {
+ state = Update(state, Sym, *T, Summ.getArg(idx), hasErr);
+ if (hasErr) {
+ ErrorExpr = *I;
+ ErrorSym = Sym;
+ break;
+ }
+ continue;
+ }
+
+ 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.
+
+ // FIXME: Either this logic should also be replicated in GRSimpleVals
+ // or should be pulled into a separate "constraint engine."
+
+ // 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.
+
+ const TypedRegion* R = dyn_cast<TypedRegion>(MR->getRegion());
+
+ if (R) {
+ // 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()->isIntegralType()) {
+ 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?
+ }
+
+ // Is the invalidated variable something that we were tracking?
+ SymbolRef Sym = state.GetSValAsScalarOrLoc(R).getAsLocSymbol();
+
+ // Remove any existing reference-count binding.
+ if (Sym) state = state.remove<RefBindings>(Sym);
+
+ if (R->isBoundable(Ctx)) {
+ // Set the value of the variable to be a conjured symbol.
+ unsigned Count = Builder.getCurrentBlockCount();
+ QualType T = R->getValueType(Ctx);
+
+ if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())){
+ ValueManager &ValMgr = Eng.getValueManager();
+ SVal V = ValMgr.getConjuredSymbolVal(*I, T, Count);
+ state = state.BindLoc(Loc::MakeVal(R), V);
+ }
+ else if (const RecordType *RT = T->getAsStructureType()) {
+ // Handle structs in a not so awesome way. Here we just
+ // eagerly bind new symbols to the fields. In reality we
+ // should have the store manager handle this. The idea is just
+ // to prototype some basic functionality here. All of this logic
+ // should one day soon just go away.
+ const RecordDecl *RD = RT->getDecl()->getDefinition(Ctx);
+
+ // No record definition. There is nothing we can do.
+ if (!RD)
+ continue;
+
+ MemRegionManager &MRMgr = state.getManager().getRegionManager();
+
+ // Iterate through the fields and construct new symbols.
+ for (RecordDecl::field_iterator FI=RD->field_begin(Ctx),
+ FE=RD->field_end(Ctx); FI!=FE; ++FI) {
+
+ // For now just handle scalar fields.
+ FieldDecl *FD = *FI;
+ QualType FT = FD->getType();
+
+ if (Loc::IsLocType(FT) ||
+ (FT->isIntegerType() && FT->isScalarType())) {
+ const FieldRegion* FR = MRMgr.getFieldRegion(FD, R);
+
+ SVal V = ValMgr.getConjuredSymbolVal(*I, FT, Count);
+ state = state.BindLoc(Loc::MakeVal(FR), V);
+ }
+ }
+ } else if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
+ // Set the default value of the array to conjured symbol.
+ StoreManager& StoreMgr = Eng.getStateManager().getStoreManager();
+ SVal V = ValMgr.getConjuredSymbolVal(*I, AT->getElementType(),
+ Count);
+ state = GRStateRef(StoreMgr.setDefaultValue(state, R, V),
+ StateMgr);
+ } else {
+ // Just blast away other values.
+ state = state.BindLoc(*MR, UnknownVal());
+ }
+ }
+ }
+ else
+ state = state.BindLoc(*MR, UnknownVal());
+ }
+ else {
+ // Nuke all other arguments passed by reference.
+ state = state.Unbind(cast<Loc>(V));
+ }
+ }
+ else if (isa<nonloc::LocAsInteger>(V))
+ state = state.Unbind(cast<nonloc::LocAsInteger>(V).getLoc());
+ }
+
+ // Evaluate the effect on the message receiver.
+ if (!ErrorExpr && Receiver) {
+ SymbolRef Sym = state.GetSValAsScalarOrLoc(Receiver).getAsLocSymbol();
+ if (Sym) {
+ if (const RefVal* T = state.get<RefBindings>(Sym)) {
+ state = Update(state, Sym, *T, Summ.getReceiverEffect(), hasErr);
+ if (hasErr) {
+ ErrorExpr = Receiver;
+ ErrorSym = Sym;
+ }
+ }
+ }
+ }
+
+ // Process any errors.
+ if (hasErr) {
+ ProcessNonLeakError(Dst, Builder, Ex, ErrorExpr, Pred, state,
+ hasErr, ErrorSym);
+ return;
+ }
+
+ // Consult the summary for the return value.
+ RetEffect RE = Summ.getRetEffect();
+
+ if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
+ assert(Receiver);
+ SVal V = state.GetSValAsScalarOrLoc(Receiver);
+ bool found = false;
+ if (SymbolRef Sym = V.getAsLocSymbol())
+ if (state.get<RefBindings>(Sym)) {
+ found = true;
+ RE = Summaries.getObjAllocRetEffect();
+ }
+
+ if (!found)
+ 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: This is basically copy-and-paste from GRSimpleVals. We
+ // should compose behavior, not copy it.
+
+ // FIXME: We eventually should handle structs and other compound types
+ // that are returned by value.
+
+ QualType T = Ex->getType();
+
+ if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
+ unsigned Count = Builder.getCurrentBlockCount();
+ ValueManager &ValMgr = Eng.getValueManager();
+ SVal X = ValMgr.getConjuredSymbolVal(Ex, T, Count);
+ state = state.BindExpr(Ex, X, false);
+ }
+
+ break;
+ }
+
+ case RetEffect::Alias: {
+ unsigned idx = RE.getIndex();
+ assert (arg_end >= arg_beg);
+ assert (idx < (unsigned) (arg_end - arg_beg));
+ SVal V = state.GetSValAsScalarOrLoc(*(arg_beg+idx));
+ state = state.BindExpr(Ex, V, false);
+ break;
+ }
+
+ case RetEffect::ReceiverAlias: {
+ assert (Receiver);
+ SVal V = state.GetSValAsScalarOrLoc(Receiver);
+ state = state.BindExpr(Ex, V, false);
+ break;
+ }
+
+ case RetEffect::OwnedAllocatedSymbol:
+ case RetEffect::OwnedSymbol: {
+ unsigned Count = Builder.getCurrentBlockCount();
+ ValueManager &ValMgr = Eng.getValueManager();
+ SymbolRef Sym = ValMgr.getConjuredSymbol(Ex, Count);
+ QualType RetT = GetReturnType(Ex, ValMgr.getContext());
+ state = state.set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(),
+ RetT));
+ state = state.BindExpr(Ex, ValMgr.makeRegionVal(Sym), false);
+
+ // FIXME: Add a flag to the checker where allocations are assumed to
+ // *not fail.
+#if 0
+ if (RE.getKind() == RetEffect::OwnedAllocatedSymbol) {
+ bool isFeasible;
+ state = state.Assume(loc::SymbolVal(Sym), true, isFeasible);
+ assert(isFeasible && "Cannot assume fresh symbol is non-null.");
+ }
+#endif
+
+ break;
+ }
+
+ case RetEffect::GCNotOwnedSymbol:
+ case RetEffect::NotOwnedSymbol: {
+ unsigned Count = Builder.getCurrentBlockCount();
+ ValueManager &ValMgr = Eng.getValueManager();
+ SymbolRef Sym = ValMgr.getConjuredSymbol(Ex, Count);
+ QualType RetT = GetReturnType(Ex, ValMgr.getContext());
+ state = state.set<RefBindings>(Sym, RefVal::makeNotOwned(RE.getObjKind(),
+ RetT));
+ state = state.BindExpr(Ex, ValMgr.makeRegionVal(Sym), false);
+ break;
+ }
+ }
+
+ // Generate a sink node if we are at the end of a path.
+ GRExprEngine::NodeTy *NewNode =
+ Summ.isEndPath() ? Builder.MakeSinkNode(Dst, Ex, Pred, state)
+ : Builder.MakeNode(Dst, Ex, Pred, state);
+
+ // Annotate the edge with summary we used.
+ if (NewNode) SummaryLog[NewNode] = &Summ;
+}
+
+
+void CFRefCount::EvalCall(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Eng,
+ GRStmtNodeBuilder<GRState>& Builder,
+ CallExpr* CE, SVal L,
+ ExplodedNode<GRState>* Pred) {
+ const FunctionDecl* FD = L.getAsFunctionDecl();
+ RetainSummary* Summ = !FD ? Summaries.getDefaultSummary()
+ : Summaries.getSummary(const_cast<FunctionDecl*>(FD));
+
+ assert(Summ);
+ EvalSummary(Dst, Eng, Builder, CE, 0, *Summ,
+ CE->arg_begin(), CE->arg_end(), Pred);
+}
+
+void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Eng,
+ GRStmtNodeBuilder<GRState>& Builder,
+ ObjCMessageExpr* ME,
+ ExplodedNode<GRState>* Pred) {
+ RetainSummary* Summ = 0;
+
+ if (Expr* Receiver = ME->getReceiver()) {
+ // We need the type-information of the tracked receiver object
+ // Retrieve it from the state.
+ const ObjCInterfaceDecl* ID = 0;
+
+ // FIXME: Wouldn't it be great if this code could be reduced? It's just
+ // a chain of lookups.
+ // FIXME: Is this really working as expected? There are cases where
+ // we just use the 'ID' from the message expression.
+ const GRState* St = Builder.GetState(Pred);
+ SVal V = Eng.getStateManager().GetSValAsScalarOrLoc(St, Receiver);
+
+ SymbolRef Sym = V.getAsLocSymbol();
+ if (Sym) {
+ if (const RefVal* T = St->get<RefBindings>(Sym)) {
+ QualType Ty = T->getType();
+
+ if (const PointerType* PT = Ty->getAsPointerType()) {
+ QualType PointeeTy = PT->getPointeeType();
+
+ if (ObjCInterfaceType* IT = dyn_cast<ObjCInterfaceType>(PointeeTy))
+ ID = IT->getDecl();
+ }
+ }
+ }
+
+ // FIXME: this is a hack. This may or may not be the actual method
+ // that is called.
+ if (!ID) {
+ if (const PointerType *PT = Receiver->getType()->getAsPointerType())
+ if (const ObjCInterfaceType *p =
+ PT->getPointeeType()->getAsObjCInterfaceType())
+ ID = p->getDecl();
+ }
+
+ // FIXME: The receiver could be a reference to a class, meaning that
+ // we should use the class method.
+ Summ = Summaries.getInstanceMethodSummary(ME, ID);
+
+ // Special-case: are we sending a mesage to "self"?
+ // This is a hack. When we have full-IP this should be removed.
+ if (isa<ObjCMethodDecl>(&Eng.getGraph().getCodeDecl())) {
+ if (Expr* Receiver = ME->getReceiver()) {
+ SVal X = Eng.getStateManager().GetSValAsScalarOrLoc(St, Receiver);
+ if (loc::MemRegionVal* L = dyn_cast<loc::MemRegionVal>(&X))
+ if (L->getRegion() == Eng.getStateManager().getSelfRegion(St)) {
+ // Update the summary to make the default argument effect
+ // 'StopTracking'.
+ Summ = Summaries.copySummary(Summ);
+ Summ->setDefaultArgEffect(StopTracking);
+ }
+ }
+ }
+ }
+ else
+ Summ = Summaries.getClassMethodSummary(ME);
+
+ if (!Summ)
+ Summ = Summaries.getDefaultSummary();
+
+ EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ,
+ ME->arg_begin(), ME->arg_end(), Pred);
+}
+
+namespace {
+class VISIBILITY_HIDDEN StopTrackingCallback : public SymbolVisitor {
+ GRStateRef state;
+public:
+ StopTrackingCallback(GRStateRef st) : state(st) {}
+ GRStateRef getState() { return state; }
+
+ bool VisitSymbol(SymbolRef sym) {
+ state = state.remove<RefBindings>(sym);
+ return true;
+ }
+
+ const GRState* getState() const { return state.getState(); }
+};
+} // end anonymous namespace
+
+
+void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) {
+ // Are we storing to something that causes the value to "escape"?
+ bool escapes = false;
+
+ // 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.
+ GRStateRef state = B.getState();
+
+ if (!isa<loc::MemRegionVal>(location))
+ escapes = true;
+ else {
+ const MemRegion* R = cast<loc::MemRegionVal>(location).getRegion();
+ escapes = !B.getStateManager().hasStackStorage(R);
+
+ 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())));
+ }
+ }
+
+ // 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.
+ B.MakeNode(state.scanReachableSymbols<StopTrackingCallback>(val).getState());
+}
+
+
+ // Return statements.
+
+void CFRefCount::EvalReturn(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Eng,
+ GRStmtNodeBuilder<GRState>& Builder,
+ ReturnStmt* S,
+ ExplodedNode<GRState>* Pred) {
+
+ Expr* RetE = S->getRetValue();
+ if (!RetE)
+ return;
+
+ GRStateRef state(Builder.GetState(Pred), Eng.getStateManager());
+ SymbolRef Sym = state.GetSValAsScalarOrLoc(RetE).getAsLocSymbol();
+
+ if (!Sym)
+ return;
+
+ // Get the reference count binding (if any).
+ const RefVal* T = state.get<RefBindings>(Sym);
+
+ if (!T)
+ return;
+
+ // Change the reference count.
+ RefVal X = *T;
+
+ switch (X.getKind()) {
+ case RefVal::Owned: {
+ unsigned cnt = X.getCount();
+ assert (cnt > 0);
+ X.setCount(cnt - 1);
+ X = X ^ RefVal::ReturnedOwned;
+ break;
+ }
+
+ case RefVal::NotOwned: {
+ unsigned cnt = X.getCount();
+ if (cnt) {
+ X.setCount(cnt - 1);
+ X = X ^ RefVal::ReturnedOwned;
+ }
+ else {
+ X = X ^ RefVal::ReturnedNotOwned;
+ }
+ break;
+ }
+
+ default:
+ return;
+ }
+
+ // Update the binding.
+ state = state.set<RefBindings>(Sym, X);
+ Pred = Builder.MakeNode(Dst, S, Pred, state);
+
+ // Did we cache out?
+ if (!Pred)
+ return;
+
+ // Update the autorelease counts.
+ static unsigned autoreleasetag = 0;
+ GenericNodeBuilder Bd(Builder, S, &autoreleasetag);
+ bool stop = false;
+ llvm::tie(Pred, state) = HandleAutoreleaseCounts(state , Bd, Pred, Eng, Sym,
+ X, stop);
+
+ // Did we cache out?
+ if (!Pred || stop)
+ return;
+
+ // Get the updated binding.
+ T = state.get<RefBindings>(Sym);
+ assert(T);
+ X = *T;
+
+ // Any leaks or other errors?
+ if (X.isReturnedOwned() && X.getCount() == 0) {
+ const Decl *CD = &Eng.getStateManager().getCodeDecl();
+ if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
+ const RetainSummary &Summ = *Summaries.getMethodSummary(MD);
+ RetEffect RE = Summ.getRetEffect();
+ bool hasError = false;
+
+ if (RE.getKind() != RetEffect::NoRet) {
+ if (isGCEnabled() && 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
+ // method should return ownership unless it returns a CF object.
+ X = X ^ RefVal::ErrorGCLeakReturned;
+
+ // Keep this false until this is properly tested.
+ hasError = true;
+ }
+ else if (!RE.isOwned()) {
+ // Either we are using GC and the returned object is a CF type
+ // or we aren't using GC. In either case, we expect that the
+ // enclosing method is expected to return ownership.
+ hasError = true;
+ X = X ^ RefVal::ErrorLeakReturned;
+ }
+ }
+
+ if (hasError) {
+ // Generate an error node.
+ static int ReturnOwnLeakTag = 0;
+ state = state.set<RefBindings>(Sym, X);
+ ExplodedNode<GRState> *N =
+ Builder.generateNode(PostStmt(S, &ReturnOwnLeakTag), state, Pred);
+ if (N) {
+ CFRefReport *report =
+ new CFRefLeakReport(*static_cast<CFRefBug*>(leakAtReturn), *this,
+ N, Sym, Eng);
+ BR->EmitReport(report);
+ }
+ }
+ }
+ }
+ else if (X.isReturnedNotOwned()) {
+ const Decl *CD = &Eng.getStateManager().getCodeDecl();
+ if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
+ const RetainSummary &Summ = *Summaries.getMethodSummary(MD);
+ if (Summ.getRetEffect().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<GRState> *N =
+ Builder.generateNode(PostStmt(S, &ReturnNotOwnedForOwnedTag),
+ state, Pred)) {
+ CFRefReport *report =
+ new CFRefReport(*static_cast<CFRefBug*>(returnNotOwnedForOwned),
+ *this, N, Sym);
+ BR->EmitReport(report);
+ }
+ }
+ }
+ }
+}
+
+// Assumptions.
+
+const GRState* CFRefCount::EvalAssume(GRStateManager& VMgr,
+ const GRState* St,
+ SVal Cond, bool Assumption,
+ bool& isFeasible) {
+
+ // FIXME: We may add to the interface of EvalAssume the list of symbols
+ // whose assumptions have changed. For now we just iterate through the
+ // bindings and check if any of the tracked symbols are NULL. This isn't
+ // too bad since the number of symbols we will track in practice are
+ // probably small and EvalAssume is only called at branches and a few
+ // other places.
+ RefBindings B = St->get<RefBindings>();
+
+ if (B.isEmpty())
+ return St;
+
+ bool changed = false;
+
+ GRStateRef state(St, VMgr);
+ RefBindings::Factory& RefBFactory = state.get_context<RefBindings>();
+
+ for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
+ // Check if the symbol is null (or equal to any constant).
+ // If this is the case, stop tracking the symbol.
+ if (VMgr.getSymVal(St, I.getKey())) {
+ changed = true;
+ B = RefBFactory.Remove(B, I.getKey());
+ }
+ }
+
+ if (changed)
+ state = state.set<RefBindings>(B);
+
+ return state;
+}
+
+GRStateRef CFRefCount::Update(GRStateRef 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 = isGCEnabled() ? DoNothing : IncRef; break;
+ case DecRefMsg: E = isGCEnabled() ? DoNothing : DecRef; break;
+ case MakeCollectable: E = isGCEnabled() ? DecRef : DoNothing; break;
+ case NewAutoreleasePool: E = isGCEnabled() ? DoNothing :
+ NewAutoreleasePool; break;
+ }
+
+ // Handle all use-after-releases.
+ if (!isGCEnabled() && V.getKind() == RefVal::Released) {
+ V = V ^ RefVal::ErrorUseAfterRelease;
+ hasErr = V.getKind();
+ return state.set<RefBindings>(sym, V);
+ }
+
+ switch (E) {
+ default:
+ assert (false && "Unhandled CFRef transition.");
+
+ 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:
+ switch (V.getKind()) {
+ default:
+ // case 'RefVal::Released' handled above.
+ assert (false);
+
+ case RefVal::Owned:
+ assert(V.getCount() > 0);
+ if (V.getCount() == 1) V = V ^ 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;
+ }
+ return state.set<RefBindings>(sym, V);
+}
+
+//===----------------------------------------------------------------------===//
+// Handle dead symbols and end-of-path.
+//===----------------------------------------------------------------------===//
+
+std::pair<ExplodedNode<GRState>*, GRStateRef>
+CFRefCount::HandleAutoreleaseCounts(GRStateRef state, GenericNodeBuilder Bd,
+ ExplodedNode<GRState>* Pred,
+ GRExprEngine &Eng,
+ SymbolRef Sym, RefVal V, bool &stop) {
+
+ 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?");
+ unsigned Cnt = V.getCount();
+
+ // FIXME: Handle sending 'autorelease' to already released object.
+
+ if (V.getKind() == RefVal::ReturnedOwned)
+ ++Cnt;
+
+ if (ACnt <= Cnt) {
+ if (ACnt == Cnt) {
+ V.clearCounts();
+ if (V.getKind() == RefVal::ReturnedOwned)
+ V = V ^ RefVal::ReturnedNotOwned;
+ else
+ V = V ^ RefVal::NotOwned;
+ }
+ else {
+ V.setCount(Cnt - ACnt);
+ V.setAutoreleaseCount(0);
+ }
+ state = state.set<RefBindings>(Sym, V);
+ ExplodedNode<GRState> *N = Bd.MakeNode(state, Pred);
+ stop = (N == 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<GRState> *N = Bd.MakeNode(state, Pred)) {
+ N->markAsSink();
+
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+ os << "Object over-autoreleased: object was sent -autorelease";
+ if (V.getAutoreleaseCount() > 1)
+ os << V.getAutoreleaseCount() << " times";
+ os << " but the object has ";
+ if (V.getCount() == 0)
+ os << "zero (locally visible)";
+ else
+ os << "+" << V.getCount();
+ os << " retain counts";
+
+ CFRefReport *report =
+ new CFRefReport(*static_cast<CFRefBug*>(overAutorelease),
+ *this, N, Sym, os.str().c_str());
+ BR->EmitReport(report);
+ }
+
+ return std::make_pair((ExplodedNode<GRState>*)0, state);
+}
+
+GRStateRef
+CFRefCount::HandleSymbolDeath(GRStateRef state, SymbolRef sid, RefVal V,
+ llvm::SmallVectorImpl<SymbolRef> &Leaked) {
+
+ bool hasLeak = V.isOwned() ||
+ ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0);
+
+ if (!hasLeak)
+ return state.remove<RefBindings>(sid);
+
+ Leaked.push_back(sid);
+ return state.set<RefBindings>(sid, V ^ RefVal::ErrorLeak);
+}
+
+ExplodedNode<GRState>*
+CFRefCount::ProcessLeaks(GRStateRef state,
+ llvm::SmallVectorImpl<SymbolRef> &Leaked,
+ GenericNodeBuilder &Builder,
+ GRExprEngine& Eng,
+ ExplodedNode<GRState> *Pred) {
+
+ if (Leaked.empty())
+ return Pred;
+
+ // Generate an intermediate node representing the leak point.
+ ExplodedNode<GRState> *N = Builder.MakeNode(state, Pred);
+
+ if (N) {
+ for (llvm::SmallVectorImpl<SymbolRef>::iterator
+ I = Leaked.begin(), E = Leaked.end(); I != E; ++I) {
+
+ CFRefBug *BT = static_cast<CFRefBug*>(Pred ? leakWithinFunction
+ : leakAtReturn);
+ assert(BT && "BugType not initialized.");
+ CFRefLeakReport* report = new CFRefLeakReport(*BT, *this, N, *I, Eng);
+ BR->EmitReport(report);
+ }
+ }
+
+ return N;
+}
+
+void CFRefCount::EvalEndPath(GRExprEngine& Eng,
+ GREndPathNodeBuilder<GRState>& Builder) {
+
+ GRStateRef state(Builder.getState(), Eng.getStateManager());
+ GenericNodeBuilder Bd(Builder);
+ RefBindings B = state.get<RefBindings>();
+ ExplodedNode<GRState> *Pred = 0;
+
+ 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)
+ return;
+ }
+
+ B = state.get<RefBindings>();
+ llvm::SmallVector<SymbolRef, 10> Leaked;
+
+ for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I)
+ state = HandleSymbolDeath(state, (*I).first, (*I).second, Leaked);
+
+ ProcessLeaks(state, Leaked, Bd, Eng, Pred);
+}
+
+void CFRefCount::EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Eng,
+ GRStmtNodeBuilder<GRState>& Builder,
+ ExplodedNode<GRState>* Pred,
+ Stmt* S,
+ const GRState* St,
+ SymbolReaper& SymReaper) {
+
+ GRStateRef state(St, Eng.getStateManager());
+ 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)){
+ // Use the symbol as the tag.
+ // FIXME: This might not be as unique as we would like.
+ GenericNodeBuilder Bd(Builder, S, Sym);
+ bool stop = false;
+ llvm::tie(Pred, state) = HandleAutoreleaseCounts(state, Bd, Pred, Eng,
+ Sym, *T, stop);
+ if (stop)
+ return;
+ }
+ }
+
+ B = state.get<RefBindings>();
+ llvm::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);
+ }
+
+ static unsigned LeakPPTag = 0;
+ {
+ GenericNodeBuilder Bd(Builder, S, &LeakPPTag);
+ Pred = ProcessLeaks(state, Leaked, Bd, Eng, Pred);
+ }
+
+ // Did we cache out?
+ if (!Pred)
+ return;
+
+ // Now generate a new node that nukes the old bindings.
+ RefBindings::Factory& F = state.get_context<RefBindings>();
+
+ for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
+ 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<GRState>& Dst,
+ GRStmtNodeBuilder<GRState>& Builder,
+ Expr* NodeExpr, Expr* ErrorExpr,
+ ExplodedNode<GRState>* Pred,
+ const GRState* St,
+ RefVal::Kind hasErr, SymbolRef Sym) {
+ Builder.BuildSinks = true;
+ GRExprEngine::NodeTy* 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(ErrorExpr->getSourceRange());
+ BR->EmitReport(report);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function creation for external clients.
+//===----------------------------------------------------------------------===//
+
+GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
+ const LangOptions& lopts) {
+ return new CFRefCount(Ctx, GCEnabled, lopts);
+}
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
new file mode 100644
index 000000000000..9e8248fe48be
--- /dev/null
+++ b/lib/Analysis/CMakeLists.txt
@@ -0,0 +1,36 @@
+set(LLVM_NO_RTTI 1)
+
+add_clang_library(clangAnalysis
+ BasicConstraintManager.cpp
+ BasicObjCFoundationChecks.cpp
+ BasicStore.cpp
+ BasicValueFactory.cpp
+ BugReporter.cpp
+ CFRefCount.cpp
+ CheckDeadStores.cpp
+ CheckNSError.cpp
+ CheckObjCDealloc.cpp
+ CheckObjCInstMethSignature.cpp
+ CheckObjCUnusedIVars.cpp
+ Environment.cpp
+ ExplodedGraph.cpp
+ GRBlockCounter.cpp
+ GRCoreEngine.cpp
+ GRExprEngine.cpp
+ GRExprEngineInternalChecks.cpp
+ GRSimpleVals.cpp
+ GRState.cpp
+ GRTransferFuncs.cpp
+ LiveVariables.cpp
+ MemRegion.cpp
+ PathDiagnostic.cpp
+ RangeConstraintManager.cpp
+ RegionStore.cpp
+ SimpleConstraintManager.cpp
+ Store.cpp
+ SVals.cpp
+ SymbolManager.cpp
+ UninitializedValues.cpp
+ )
+
+add_dependencies(clangAnalysis ClangDiagnosticAnalysis)
diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp
new file mode 100644
index 000000000000..69433d6396a5
--- /dev/null
+++ b/lib/Analysis/CheckDeadStores.cpp
@@ -0,0 +1,259 @@
+//==- DeadStores.cpp - Check for stores to dead variables --------*- 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 a DeadStores, a flow-sensitive checker that looks for
+// stores to variables that are no longer live.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ParentMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace clang;
+
+namespace {
+
+class VISIBILITY_HIDDEN DeadStoreObs : public LiveVariables::ObserverTy {
+ ASTContext &Ctx;
+ BugReporter& BR;
+ ParentMap& Parents;
+ llvm::SmallPtrSet<VarDecl*, 20> Escaped;
+
+ enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
+
+public:
+ DeadStoreObs(ASTContext &ctx, BugReporter& br, ParentMap& parents,
+ llvm::SmallPtrSet<VarDecl*, 20> &escaped)
+ : Ctx(ctx), BR(br), Parents(parents), Escaped(escaped) {}
+
+ virtual ~DeadStoreObs() {}
+
+ void Report(VarDecl* V, DeadStoreKind dsk, SourceLocation L, SourceRange R) {
+ if (Escaped.count(V))
+ return;
+
+ std::string name = V->getNameAsString();
+
+ const char* BugType = 0;
+ std::string msg;
+
+ switch (dsk) {
+ default:
+ assert(false && "Impossible dead store type.");
+
+ case DeadInit:
+ BugType = "Dead initialization";
+ msg = "Value stored to '" + name +
+ "' 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";
+ break;
+
+ case Enclosing:
+ BugType = "Dead nested assignment";
+ msg = "Although the value stored to '" + name +
+ "' is used in the enclosing expression, the value is never actually"
+ " read from '" + name + "'";
+ break;
+ }
+
+ BR.EmitBasicReport(BugType, "Dead store", msg.c_str(), L, R);
+ }
+
+ void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val,
+ DeadStoreKind dsk,
+ const LiveVariables::AnalysisDataTy& AD,
+ const LiveVariables::ValTy& Live) {
+
+ if (VD->hasLocalStorage() && !Live(VD, AD) && !VD->getAttr<UnusedAttr>())
+ Report(VD, dsk, Ex->getSourceRange().getBegin(),
+ 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);
+ }
+
+ bool isIncrement(VarDecl* VD, BinaryOperator* B) {
+ if (B->isCompoundAssignmentOp())
+ return true;
+
+ Expr* RHS = B->getRHS()->IgnoreParenCasts();
+ BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS);
+
+ if (!BRHS)
+ return false;
+
+ DeclRefExpr *DR;
+
+ if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts())))
+ if (DR->getDecl() == VD)
+ return true;
+
+ if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts())))
+ if (DR->getDecl() == VD)
+ return true;
+
+ return false;
+ }
+
+ virtual void ObserveStmt(Stmt* S,
+ const LiveVariables::AnalysisDataTy& AD,
+ const LiveVariables::ValTy& Live) {
+
+ // Skip statements in macros.
+ if (S->getLocStart().isMacroID())
+ return;
+
+ if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
+ if (!B->isAssignmentOp()) return; // Skip non-assignments.
+
+ if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()))
+ if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ Expr* RHS = B->getRHS()->IgnoreParenCasts();
+
+ // Special case: check for assigning null to a pointer.
+ // This is a common form of defensive programming.
+ if (VD->getType()->isPointerType()) {
+ if (IntegerLiteral* L = dyn_cast<IntegerLiteral>(RHS))
+ // FIXME: Probably should have an Expr::isNullPointerConstant.
+ if (L->getValue() == 0)
+ return;
+ }
+ // Special case: self-assignments. These are often used to shut up
+ // "unused variable" compiler warnings.
+ if (DeclRefExpr* RhsDR = dyn_cast<DeclRefExpr>(RHS))
+ if (VD == dyn_cast<VarDecl>(RhsDR->getDecl()))
+ return;
+
+ // Otherwise, issue a warning.
+ DeadStoreKind dsk = Parents.isConsumedExpr(B)
+ ? Enclosing
+ : (isIncrement(VD,B) ? DeadIncrement : Standard);
+
+ CheckVarDecl(VD, DR, B->getRHS(), dsk, AD, Live);
+ }
+ }
+ else if (UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
+ if (!U->isIncrementOp())
+ return;
+
+ // Handle: ++x within a subexpression. The solution is not warn
+ // about preincrements to dead variables when the preincrement occurs
+ // as a subexpression. This can lead to false negatives, e.g. "(++x);"
+ // A generalized dead code checker should find such issues.
+ if (U->isPrefix() && Parents.isConsumedExpr(U))
+ return;
+
+ Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
+
+ if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(Ex))
+ CheckDeclRef(DR, U, DeadIncrement, AD, Live);
+ }
+ else if (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();
+ DI != DE; ++DI) {
+
+ VarDecl* V = dyn_cast<VarDecl>(*DI);
+
+ if (!V)
+ continue;
+
+ if (V->hasLocalStorage())
+ if (Expr* E = V->getInit()) {
+ // 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) {
+ // Special case: check for initializations with constants.
+ //
+ // e.g. : int x = 0;
+ //
+ // If x is EVER assigned a new value later, don't issue
+ // a warning. This is because such initialization can be
+ // due to defensive programming.
+ if (E->isConstantInitializer(Ctx))
+ return;
+
+ // Special case: check for initializations from constant
+ // variables.
+ //
+ // e.g. extern const int MyConstant;
+ // int x = MyConstant;
+ //
+ if (DeclRefExpr *DRE=dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
+ if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+ if (VD->hasGlobalStorage() &&
+ VD->getType().isConstQualified()) return;
+
+ Report(V, DeadInit, V->getLocation(), E->getSourceRange());
+ }
+ }
+ }
+ }
+};
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Driver function to invoke the Dead-Stores checker on a CFG.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{
+ CFG *cfg;
+public:
+ FindEscaped(CFG *c) : cfg(c) {}
+
+ CFG& getCFG() { return *cfg; }
+
+ llvm::SmallPtrSet<VarDecl*, 20> Escaped;
+
+ void VisitUnaryOperator(UnaryOperator* U) {
+ // Check for '&'. Any VarDecl whose value has its address-taken we
+ // treat as escaped.
+ Expr* E = U->getSubExpr()->IgnoreParenCasts();
+ if (U->getOpcode() == UnaryOperator::AddrOf)
+ if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E))
+ if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ Escaped.insert(VD);
+ return;
+ }
+ Visit(E);
+ }
+};
+} // end anonymous namespace
+
+
+void clang::CheckDeadStores(LiveVariables& L, BugReporter& BR) {
+ FindEscaped FS(BR.getCFG());
+ FS.getCFG().VisitBlockStmts(FS);
+ DeadStoreObs A(BR.getContext(), BR, BR.getParentMap(), FS.Escaped);
+ L.runOnAllBlocks(*BR.getCFG(), &A);
+}
diff --git a/lib/Analysis/CheckNSError.cpp b/lib/Analysis/CheckNSError.cpp
new file mode 100644
index 000000000000..ff9da0f659c3
--- /dev/null
+++ b/lib/Analysis/CheckNSError.cpp
@@ -0,0 +1,231 @@
+//=- CheckNSError.cpp - Coding conventions for uses of NSError ---*- 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 a CheckNSError, a flow-insenstive check
+// that determines if an Objective-C class interface correctly returns
+// a non-void return type.
+//
+// File under feature request PR 2600.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "BasicObjCFoundationChecks.h"
+#include "llvm/Support/Compiler.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Decl.h"
+#include "llvm/ADT/SmallVector.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN NSErrorCheck : public BugType {
+ const bool isNSErrorWarning;
+ IdentifierInfo * const II;
+ GRExprEngine &Eng;
+
+ void CheckSignature(ObjCMethodDecl& MD, QualType& ResultTy,
+ llvm::SmallVectorImpl<VarDecl*>& ErrorParams);
+
+ void CheckSignature(FunctionDecl& MD, QualType& ResultTy,
+ llvm::SmallVectorImpl<VarDecl*>& ErrorParams);
+
+ bool CheckNSErrorArgument(QualType ArgTy);
+ bool CheckCFErrorArgument(QualType ArgTy);
+
+ void CheckParamDeref(VarDecl* V, GRStateRef state, BugReporter& BR);
+
+ void EmitRetTyWarning(BugReporter& BR, Decl& CodeDecl);
+
+public:
+ NSErrorCheck(bool isNSError, GRExprEngine& eng)
+ : BugType(isNSError ? "NSError** null dereference"
+ : "CFErrorRef* null dereference",
+ "Coding Conventions (Apple)"),
+ isNSErrorWarning(isNSError),
+ II(&eng.getContext().Idents.get(isNSErrorWarning ? "NSError":"CFErrorRef")),
+ Eng(eng) {}
+
+ void FlushReports(BugReporter& BR);
+};
+
+} // end anonymous namespace
+
+void clang::RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng) {
+ BR.Register(new NSErrorCheck(true, Eng));
+ BR.Register(new NSErrorCheck(false, Eng));
+}
+
+void NSErrorCheck::FlushReports(BugReporter& BR) {
+ // Get the analysis engine and the exploded analysis graph.
+ GRExprEngine::GraphTy& G = Eng.getGraph();
+
+ // Get the declaration of the method/function that was analyzed.
+ Decl& CodeDecl = G.getCodeDecl();
+
+ // Get the ASTContext, which is useful for querying type information.
+ ASTContext &Ctx = BR.getContext();
+
+ QualType ResultTy;
+ llvm::SmallVector<VarDecl*, 5> ErrorParams;
+
+ if (ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CodeDecl))
+ CheckSignature(*MD, ResultTy, ErrorParams);
+ else if (FunctionDecl* FD = dyn_cast<FunctionDecl>(&CodeDecl))
+ CheckSignature(*FD, ResultTy, ErrorParams);
+ else
+ return;
+
+ if (ErrorParams.empty())
+ return;
+
+ if (ResultTy == Ctx.VoidTy) EmitRetTyWarning(BR, CodeDecl);
+
+ for (GRExprEngine::GraphTy::roots_iterator RI=G.roots_begin(),
+ RE=G.roots_end(); RI!=RE; ++RI) {
+ // Scan the parameters for an implicit null dereference.
+ for (llvm::SmallVectorImpl<VarDecl*>::iterator I=ErrorParams.begin(),
+ E=ErrorParams.end(); I!=E; ++I)
+ CheckParamDeref(*I, GRStateRef((*RI)->getState(),Eng.getStateManager()),
+ BR);
+
+ }
+}
+
+void NSErrorCheck::EmitRetTyWarning(BugReporter& BR, Decl& CodeDecl) {
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+
+ if (isa<ObjCMethodDecl>(CodeDecl))
+ os << "Method";
+ else
+ os << "Function";
+
+ os << " accepting ";
+ os << (isNSErrorWarning ? "NSError**" : "CFErrorRef*");
+ os << " should have a non-void return value to indicate whether or not an "
+ "error occured.";
+
+ BR.EmitBasicReport(isNSErrorWarning
+ ? "Bad return type when passing NSError**"
+ : "Bad return type when passing CFError*",
+ getCategory().c_str(), os.str().c_str(),
+ CodeDecl.getLocation());
+}
+
+void
+NSErrorCheck::CheckSignature(ObjCMethodDecl& M, QualType& ResultTy,
+ llvm::SmallVectorImpl<VarDecl*>& ErrorParams) {
+
+ ResultTy = M.getResultType();
+
+ for (ObjCMethodDecl::param_iterator I=M.param_begin(),
+ E=M.param_end(); I!=E; ++I) {
+
+ QualType T = (*I)->getType();
+
+ if (isNSErrorWarning) {
+ if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I);
+ }
+ else if (CheckCFErrorArgument(T))
+ ErrorParams.push_back(*I);
+ }
+}
+
+void
+NSErrorCheck::CheckSignature(FunctionDecl& F, QualType& ResultTy,
+ llvm::SmallVectorImpl<VarDecl*>& ErrorParams) {
+
+ ResultTy = F.getResultType();
+
+ for (FunctionDecl::param_iterator I=F.param_begin(),
+ E=F.param_end(); I!=E; ++I) {
+
+ QualType T = (*I)->getType();
+
+ if (isNSErrorWarning) {
+ if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I);
+ }
+ else if (CheckCFErrorArgument(T))
+ ErrorParams.push_back(*I);
+ }
+}
+
+
+bool NSErrorCheck::CheckNSErrorArgument(QualType ArgTy) {
+
+ const PointerType* PPT = ArgTy->getAsPointerType();
+ if (!PPT) return false;
+
+ const PointerType* PT = PPT->getPointeeType()->getAsPointerType();
+ if (!PT) return false;
+
+ const ObjCInterfaceType *IT =
+ PT->getPointeeType()->getAsObjCInterfaceType();
+
+ if (!IT) return false;
+ return IT->getDecl()->getIdentifier() == II;
+}
+
+bool NSErrorCheck::CheckCFErrorArgument(QualType ArgTy) {
+
+ const PointerType* PPT = ArgTy->getAsPointerType();
+ if (!PPT) return false;
+
+ const TypedefType* TT = PPT->getPointeeType()->getAsTypedefType();
+ if (!TT) return false;
+
+ return TT->getDecl()->getIdentifier() == II;
+}
+
+void NSErrorCheck::CheckParamDeref(VarDecl* Param, GRStateRef rootState,
+ BugReporter& BR) {
+
+ SVal ParamL = rootState.GetLValue(Param);
+ const MemRegion* ParamR = cast<loc::MemRegionVal>(ParamL).getRegionAs<VarRegion>();
+ assert (ParamR && "Parameters always have VarRegions.");
+ SVal ParamSVal = rootState.GetSVal(ParamR);
+
+ // FIXME: For now assume that ParamSVal is symbolic. We need to generalize
+ // this later.
+ SymbolRef ParamSym = ParamSVal.getAsLocSymbol();
+ if (!ParamSym)
+ return;
+
+ // Iterate over the implicit-null dereferences.
+ for (GRExprEngine::null_deref_iterator I=Eng.implicit_null_derefs_begin(),
+ E=Eng.implicit_null_derefs_end(); I!=E; ++I) {
+
+ GRStateRef state = GRStateRef((*I)->getState(), Eng.getStateManager());
+ const SVal* X = state.get<GRState::NullDerefTag>();
+
+ if (!X || X->getAsSymbol() != ParamSym)
+ continue;
+
+ // Emit an error.
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+ os << "Potential null dereference. According to coding standards ";
+
+ if (isNSErrorWarning)
+ os << "in 'Creating and Returning NSError Objects' the parameter '";
+ else
+ os << "documented in CoreFoundation/CFError.h the parameter '";
+
+ os << Param->getNameAsString() << "' may be null.";
+
+ BugReport *report = new BugReport(*this, os.str().c_str(), *I);
+ // FIXME: Notable symbols are now part of the report. We should
+ // add support for notable symbols in BugReport.
+ // BR.addNotableSymbol(SV->getSymbol());
+ BR.EmitReport(report);
+ }
+}
diff --git a/lib/Analysis/CheckObjCDealloc.cpp b/lib/Analysis/CheckObjCDealloc.cpp
new file mode 100644
index 000000000000..f50d7a19c420
--- /dev/null
+++ b/lib/Analysis/CheckObjCDealloc.cpp
@@ -0,0 +1,257 @@
+//==- CheckObjCDealloc.cpp - Check ObjC -dealloc implementation --*- 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 a CheckObjCDealloc, a checker that
+// analyzes an Objective-C class's implementation to determine if it
+// correctly implements -dealloc.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+static bool scan_dealloc(Stmt* S, Selector Dealloc) {
+
+ if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
+ if (ME->getSelector() == Dealloc)
+ if(ME->getReceiver())
+ if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
+ return isa<ObjCSuperExpr>(Receiver);
+
+ // Recurse to children.
+
+ for (Stmt::child_iterator I = S->child_begin(), E= S->child_end(); I!=E; ++I)
+ if (*I && scan_dealloc(*I, Dealloc))
+ return true;
+
+ return false;
+}
+
+static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID,
+ const ObjCPropertyDecl* PD,
+ Selector Release,
+ IdentifierInfo* SelfII,
+ ASTContext& Ctx) {
+
+ // [mMyIvar release]
+ if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
+ if (ME->getSelector() == Release)
+ if(ME->getReceiver())
+ if (Expr* Receiver = ME->getReceiver()->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(ME->getReceiver())
+ if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
+ if (DeclRefExpr* E = dyn_cast<DeclRefExpr>(Receiver))
+ if (E->getDecl()->getIdentifier() == SelfII)
+ if (ME->getMethodDecl() == PD->getSetterMethodDecl() &&
+ ME->getNumArgs() == 1 &&
+ ME->getArg(0)->isNullPointerConstant(Ctx))
+ return true;
+
+ // self.myIvar = nil;
+ if (BinaryOperator* BO = dyn_cast<BinaryOperator>(S))
+ if (BO->isAssignmentOp())
+ if(ObjCPropertyRefExpr* PRE =
+ dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParenCasts()))
+ if(PRE->getProperty() == PD)
+ if(BO->getRHS()->isNullPointerConstant(Ctx)) {
+ // This is only a 'release' if the property kind is not
+ // 'assign'.
+ return PD->getSetterKind() != ObjCPropertyDecl::Assign;;
+ }
+
+ // Recurse to children.
+ for (Stmt::child_iterator I = S->child_begin(), E= S->child_end(); I!=E; ++I)
+ if (*I && scan_ivar_release(*I, ID, PD, Release, SelfII, Ctx))
+ return true;
+
+ return false;
+}
+
+void clang::CheckObjCDealloc(ObjCImplementationDecl* D,
+ const LangOptions& LOpts, BugReporter& BR) {
+
+ assert (LOpts.getGCMode() != LangOptions::GCOnly);
+
+ ASTContext& Ctx = BR.getContext();
+ ObjCInterfaceDecl* ID = D->getClassInterface();
+
+ // Does the class contain any ivars that are pointers (or id<...>)?
+ // If not, skip the check entirely.
+ // NOTE: This is motivated by PR 2517:
+ // http://llvm.org/bugs/show_bug.cgi?id=2517
+
+ bool containsPointerIvar = false;
+
+ for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end();
+ I!=E; ++I) {
+
+ ObjCIvarDecl* ID = *I;
+ QualType T = ID->getType();
+
+ if (!Ctx.isObjCObjectPointerType(T) ||
+ ID->getAttr<IBOutletAttr>()) // Skip IBOutlets.
+ continue;
+
+ containsPointerIvar = true;
+ break;
+ }
+
+ if (!containsPointerIvar)
+ return;
+
+ // Determine if the class subclasses NSObject.
+ IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
+ IdentifierInfo* SenTestCaseII = &Ctx.Idents.get("SenTestCase");
+
+
+ for ( ; ID ; ID = ID->getSuperClass()) {
+ IdentifierInfo *II = ID->getIdentifier();
+
+ if (II == NSObjectII)
+ break;
+
+ // FIXME: For now, ignore classes that subclass SenTestCase, as these don't
+ // need to implement -dealloc. They implement tear down in another way,
+ // which we should try and catch later.
+ // http://llvm.org/bugs/show_bug.cgi?id=3187
+ if (II == SenTestCaseII)
+ return;
+ }
+
+ if (!ID)
+ return;
+
+ // Get the "dealloc" selector.
+ IdentifierInfo* II = &Ctx.Idents.get("dealloc");
+ Selector S = Ctx.Selectors.getSelector(0, &II);
+ ObjCMethodDecl* MD = 0;
+
+ // Scan the instance methods for "dealloc".
+ for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(Ctx),
+ E = D->instmeth_end(Ctx); I!=E; ++I) {
+
+ if ((*I)->getSelector() == S) {
+ MD = *I;
+ break;
+ }
+ }
+
+ if (!MD) { // No dealloc found.
+
+ const char* name = LOpts.getGCMode() == LangOptions::NonGC
+ ? "missing -dealloc"
+ : "missing -dealloc (Hybrid MM, non-GC)";
+
+ std::string buf;
+ llvm::raw_string_ostream os(buf);
+ os << "Objective-C class '" << D->getNameAsString()
+ << "' lacks a 'dealloc' instance method";
+
+ BR.EmitBasicReport(name, os.str().c_str(), D->getLocStart());
+ return;
+ }
+
+ // dealloc found. Scan for missing [super dealloc].
+ if (MD->getBody(Ctx) && !scan_dealloc(MD->getBody(Ctx), S)) {
+
+ const char* name = LOpts.getGCMode() == LangOptions::NonGC
+ ? "missing [super dealloc]"
+ : "missing [super dealloc] (Hybrid MM, non-GC)";
+
+ std::string buf;
+ llvm::raw_string_ostream os(buf);
+ os << "The 'dealloc' instance method in Objective-C class '"
+ << D->getNameAsString()
+ << "' does not send a 'dealloc' message to its super class"
+ " (missing [super dealloc])";
+
+ BR.EmitBasicReport(name, os.str().c_str(), D->getLocStart());
+ return;
+ }
+
+ // Get the "release" selector.
+ IdentifierInfo* RII = &Ctx.Idents.get("release");
+ Selector RS = Ctx.Selectors.getSelector(0, &RII);
+
+ // Get the "self" identifier
+ IdentifierInfo* SelfII = &Ctx.Idents.get("self");
+
+ // Scan for missing and extra releases of ivars used by implementations
+ // of synthesized properties
+ for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(Ctx),
+ E = D->propimpl_end(Ctx); I!=E; ++I) {
+
+ // We can only check the synthesized properties
+ if((*I)->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
+ continue;
+
+ ObjCIvarDecl* ID = (*I)->getPropertyIvarDecl();
+ if (!ID)
+ continue;
+
+ QualType T = ID->getType();
+ if (!Ctx.isObjCObjectPointerType(T)) // Skip non-pointer ivars
+ continue;
+
+ 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;
+
+ // ivar must be released if and only if the kind of setter was not 'assign'
+ bool requiresRelease = PD->getSetterKind() != ObjCPropertyDecl::Assign;
+ if(scan_ivar_release(MD->getBody(Ctx), ID, PD, RS, SelfII, Ctx)
+ != requiresRelease) {
+ const char *name;
+ const char* category = "Memory (Core Foundation/Objective-C)";
+
+ std::string buf;
+ llvm::raw_string_ostream os(buf);
+
+ if(requiresRelease) {
+ name = LOpts.getGCMode() == LangOptions::NonGC
+ ? "missing ivar release (leak)"
+ : "missing ivar release (Hybrid MM, non-GC)";
+
+ os << "The '" << ID->getNameAsString()
+ << "' instance variable was retained by a synthesized property but "
+ "wasn't released in 'dealloc'";
+ } else {
+ name = LOpts.getGCMode() == LangOptions::NonGC
+ ? "extra ivar release (use-after-release)"
+ : "extra ivar release (Hybrid MM, non-GC)";
+
+ os << "The '" << ID->getNameAsString()
+ << "' instance variable was not retained by a synthesized property "
+ "but was released in 'dealloc'";
+ }
+
+ BR.EmitBasicReport(name, category,
+ os.str().c_str(), (*I)->getLocation());
+ }
+ }
+}
+
diff --git a/lib/Analysis/CheckObjCInstMethSignature.cpp b/lib/Analysis/CheckObjCInstMethSignature.cpp
new file mode 100644
index 000000000000..9fec7c1dc111
--- /dev/null
+++ b/lib/Analysis/CheckObjCInstMethSignature.cpp
@@ -0,0 +1,120 @@
+//=- CheckObjCInstMethodRetTy.cpp - Check ObjC method signatures -*- 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 a CheckObjCInstMethSignature, a flow-insenstive check
+// that determines if an Objective-C class interface incorrectly redefines
+// the method signature in a subclass.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/ASTContext.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+static bool AreTypesCompatible(QualType Derived, QualType Ancestor,
+ ASTContext& C) {
+
+ // Right now don't compare the compatibility of pointers. That involves
+ // looking at subtyping relationships. FIXME: Future patch.
+ if ((Derived->isPointerType() || Derived->isObjCQualifiedIdType()) &&
+ (Ancestor->isPointerType() || Ancestor->isObjCQualifiedIdType()))
+ return true;
+
+ return C.typesAreCompatible(Derived, Ancestor);
+}
+
+static void CompareReturnTypes(ObjCMethodDecl* MethDerived,
+ ObjCMethodDecl* MethAncestor,
+ BugReporter& BR, ASTContext& Ctx,
+ ObjCImplementationDecl* ID) {
+
+ QualType ResDerived = MethDerived->getResultType();
+ QualType ResAncestor = MethAncestor->getResultType();
+
+ if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) {
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+
+ os << "The Objective-C class '"
+ << MethDerived->getClassInterface()->getNameAsString()
+ << "', which is derived from class '"
+ << MethAncestor->getClassInterface()->getNameAsString()
+ << "', 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()->getNameAsString()
+ << "' and has a return type of '"
+ << ResAncestor.getAsString()
+ << "'. These two types are incompatible, and may result in undefined "
+ "behavior for clients of these classes.";
+
+ BR.EmitBasicReport("Incompatible instance method return type",
+ os.str().c_str(), MethDerived->getLocStart());
+ }
+}
+
+void clang::CheckObjCInstMethSignature(ObjCImplementationDecl* ID,
+ BugReporter& BR) {
+
+ ObjCInterfaceDecl* D = ID->getClassInterface();
+ ObjCInterfaceDecl* C = D->getSuperClass();
+
+ if (!C)
+ return;
+
+ ASTContext& Ctx = BR.getContext();
+
+ // Build a DenseMap of the methods for quick querying.
+ typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy;
+ MapTy IMeths;
+ unsigned NumMethods = 0;
+
+ for (ObjCImplementationDecl::instmeth_iterator I=ID->instmeth_begin(Ctx),
+ E=ID->instmeth_end(Ctx); I!=E; ++I) {
+
+ ObjCMethodDecl* M = *I;
+ IMeths[M->getSelector()] = M;
+ ++NumMethods;
+ }
+
+ // Now recurse the class hierarchy chain looking for methods with the
+ // same signatures.
+ while (C && NumMethods) {
+ for (ObjCInterfaceDecl::instmeth_iterator I=C->instmeth_begin(Ctx),
+ E=C->instmeth_end(Ctx); I!=E; ++I) {
+
+ ObjCMethodDecl* M = *I;
+ Selector S = M->getSelector();
+
+ MapTy::iterator MI = IMeths.find(S);
+
+ if (MI == IMeths.end() || MI->second == 0)
+ continue;
+
+ --NumMethods;
+ ObjCMethodDecl* MethDerived = MI->second;
+ MI->second = 0;
+
+ CompareReturnTypes(MethDerived, M, BR, Ctx, ID);
+ }
+
+ C = C->getSuperClass();
+ }
+}
diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Analysis/CheckObjCUnusedIVars.cpp
new file mode 100644
index 000000000000..7979f9c942e6
--- /dev/null
+++ b/lib/Analysis/CheckObjCUnusedIVars.cpp
@@ -0,0 +1,111 @@
+//==- CheckObjCUnusedIVars.cpp - Check for unused ivars ----------*- 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 a CheckObjCUnusedIvars, a checker that
+// analyzes an Objective-C class's interface/implementation to determine if it
+// has any ivars that are never accessed.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/LangOptions.h"
+#include <sstream>
+
+using namespace clang;
+
+enum IVarState { Unused, Used };
+typedef llvm::DenseMap<ObjCIvarDecl*,IVarState> IvarUsageMap;
+
+static void Scan(IvarUsageMap& M, Stmt* S) {
+ if (!S)
+ return;
+
+ if (ObjCIvarRefExpr* Ex = dyn_cast<ObjCIvarRefExpr>(S)) {
+ ObjCIvarDecl* D = Ex->getDecl();
+ IvarUsageMap::iterator I = M.find(D);
+ if (I != M.end()) I->second = Used;
+ return;
+ }
+
+ for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E;++I)
+ Scan(M, *I);
+}
+
+static void Scan(IvarUsageMap& M, ObjCPropertyImplDecl* D) {
+ if (!D)
+ return;
+
+ ObjCIvarDecl* ID = D->getPropertyIvarDecl();
+
+ if (!ID)
+ return;
+
+ IvarUsageMap::iterator I = M.find(ID);
+ if (I != M.end()) I->second = Used;
+}
+
+void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) {
+
+ ObjCInterfaceDecl* ID = D->getClassInterface();
+ IvarUsageMap M;
+
+
+ ASTContext &Ctx = BR.getContext();
+
+ // Iterate over the ivars.
+ for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end();
+ I!=E; ++I) {
+
+ ObjCIvarDecl* ID = *I;
+
+ // Ignore ivars that aren't private.
+ if (ID->getAccessControl() != ObjCIvarDecl::Private)
+ continue;
+
+ // Skip IB Outlets.
+ if (ID->getAttr<IBOutletAttr>())
+ continue;
+
+ M[ID] = Unused;
+ }
+
+ if (M.empty())
+ return;
+
+ // Now scan the methods for accesses.
+ for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(Ctx),
+ E = D->instmeth_end(Ctx); I!=E; ++I)
+ Scan(M, (*I)->getBody(Ctx));
+
+ // Scan for @synthesized property methods that act as setters/getters
+ // to an ivar.
+ for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(Ctx),
+ E = D->propimpl_end(Ctx); I!=E; ++I)
+ Scan(M, *I);
+
+ // Find ivars that are unused.
+ for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
+ if (I->second == Unused) {
+
+ std::ostringstream os;
+ os << "Instance variable '" << I->first->getNameAsString()
+ << "' in class '" << ID->getNameAsString()
+ << "' is never used by the methods in its @implementation "
+ "(although it may be used by category methods).";
+
+ BR.EmitBasicReport("Unused instance variable", "Optimization",
+ os.str().c_str(), I->first->getLocation());
+ }
+}
+
diff --git a/lib/Analysis/Environment.cpp b/lib/Analysis/Environment.cpp
new file mode 100644
index 000000000000..2bc071a265ed
--- /dev/null
+++ b/lib/Analysis/Environment.cpp
@@ -0,0 +1,167 @@
+//== Environment.cpp - Map from Stmt* to Locations/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 Environment and EnvironmentManager classes.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace clang;
+
+SVal Environment::GetSVal(Stmt* E, BasicValueFactory& BasicVals) const {
+
+ for (;;) {
+
+ switch (E->getStmtClass()) {
+
+ case Stmt::AddrLabelExprClass:
+ return Loc::MakeVal(cast<AddrLabelExpr>(E));
+
+ // ParenExprs are no-ops.
+
+ case Stmt::ParenExprClass:
+ E = cast<ParenExpr>(E)->getSubExpr();
+ continue;
+
+ case Stmt::CharacterLiteralClass: {
+ CharacterLiteral* C = cast<CharacterLiteral>(E);
+ return NonLoc::MakeVal(BasicVals, C->getValue(), C->getType());
+ }
+
+ case Stmt::IntegerLiteralClass: {
+ return NonLoc::MakeVal(BasicVals, cast<IntegerLiteral>(E));
+ }
+
+ // Casts where the source and target type are the same
+ // are no-ops. We blast through these to get the descendant
+ // subexpression that has a value.
+
+ case Stmt::ImplicitCastExprClass:
+ case Stmt::CStyleCastExprClass: {
+ CastExpr* C = cast<CastExpr>(E);
+ QualType CT = C->getType();
+
+ if (CT->isVoidType())
+ return UnknownVal();
+
+ break;
+ }
+
+ // Handle all other Stmt* using a lookup.
+
+ default:
+ break;
+ };
+
+ break;
+ }
+
+ return LookupExpr(E);
+}
+
+SVal Environment::GetBlkExprSVal(Stmt* E, BasicValueFactory& BasicVals) const {
+
+ while (1) {
+ switch (E->getStmtClass()) {
+ case Stmt::ParenExprClass:
+ E = cast<ParenExpr>(E)->getSubExpr();
+ continue;
+
+ case Stmt::CharacterLiteralClass: {
+ CharacterLiteral* C = cast<CharacterLiteral>(E);
+ return NonLoc::MakeVal(BasicVals, C->getValue(), C->getType());
+ }
+
+ case Stmt::IntegerLiteralClass: {
+ return NonLoc::MakeVal(BasicVals, cast<IntegerLiteral>(E));
+ }
+
+ default:
+ return LookupBlkExpr(E);
+ }
+ }
+}
+
+Environment EnvironmentManager::BindExpr(const Environment& Env, Stmt* E,SVal V,
+ bool isBlkExpr, bool Invalidate) {
+ assert (E);
+
+ if (V.isUnknown()) {
+ if (Invalidate)
+ return isBlkExpr ? RemoveBlkExpr(Env, E) : RemoveSubExpr(Env, E);
+ else
+ return Env;
+ }
+
+ return isBlkExpr ? AddBlkExpr(Env, E, V) : AddSubExpr(Env, E, V);
+}
+
+namespace {
+class VISIBILITY_HIDDEN MarkLiveCallback : public SymbolVisitor {
+ SymbolReaper &SymReaper;
+public:
+ MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
+ bool VisitSymbol(SymbolRef sym) { SymReaper.markLive(sym); return true; }
+};
+} // end anonymous namespace
+
+// RemoveDeadBindings:
+// - Remove subexpression bindings.
+// - Remove dead block expression bindings.
+// - Keep live block expression bindings:
+// - Mark their reachable symbols live in SymbolReaper,
+// see ScanReachableSymbols.
+// - Mark the region in DRoots if the binding is a loc::MemRegionVal.
+
+Environment
+EnvironmentManager::RemoveDeadBindings(Environment Env, Stmt* Loc,
+ SymbolReaper& SymReaper,
+ GRStateManager& StateMgr,
+ const GRState *state,
+ llvm::SmallVectorImpl<const MemRegion*>& DRoots) {
+
+ // Drop bindings for subexpressions.
+ Env = RemoveSubExprBindings(Env);
+
+ // Iterate over the block-expr bindings.
+ for (Environment::beb_iterator I = Env.beb_begin(), E = Env.beb_end();
+ I != E; ++I) {
+ Stmt* BlkExpr = I.getKey();
+
+ if (SymReaper.isLive(Loc, BlkExpr)) {
+ SVal X = I.getData();
+
+ // If the block expr's value is a memory region, then mark that region.
+ if (isa<loc::MemRegionVal>(X))
+ DRoots.push_back(cast<loc::MemRegionVal>(X).getRegion());
+
+ // Mark all symbols in the block expr's value live.
+ MarkLiveCallback cb(SymReaper);
+ StateMgr.scanReachableSymbols(X, state, cb);
+ } else {
+ // The block expr is dead.
+ SVal X = I.getData();
+
+ // Do not misclean LogicalExpr or ConditionalOperator. It is dead at the
+ // beginning of itself, but we need its UndefinedVal to determine its
+ // SVal.
+
+ if (X.isUndef() && cast<UndefinedVal>(X).getData())
+ continue;
+
+ Env = RemoveBlkExpr(Env, BlkExpr);
+ }
+ }
+
+ return Env;
+}
diff --git a/lib/Analysis/ExplodedGraph.cpp b/lib/Analysis/ExplodedGraph.cpp
new file mode 100644
index 000000000000..20de6c48c387
--- /dev/null
+++ b/lib/Analysis/ExplodedGraph.cpp
@@ -0,0 +1,241 @@
+//=-- ExplodedGraph.cpp - Local, Path-Sens. "Exploded Graph" -*- 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 template classes ExplodedNode and ExplodedGraph,
+// which represent a path-sensitive, intra-procedural "exploded graph."
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
+#include "clang/AST/Stmt.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include <vector>
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Node auditing.
+//===----------------------------------------------------------------------===//
+
+// An out of line virtual method to provide a home for the class vtable.
+ExplodedNodeImpl::Auditor::~Auditor() {}
+
+#ifndef NDEBUG
+static ExplodedNodeImpl::Auditor* NodeAuditor = 0;
+#endif
+
+void ExplodedNodeImpl::SetAuditor(ExplodedNodeImpl::Auditor* A) {
+#ifndef NDEBUG
+ NodeAuditor = A;
+#endif
+}
+
+//===----------------------------------------------------------------------===//
+// ExplodedNodeImpl.
+//===----------------------------------------------------------------------===//
+
+static inline std::vector<ExplodedNodeImpl*>& getVector(void* P) {
+ return *reinterpret_cast<std::vector<ExplodedNodeImpl*>*>(P);
+}
+
+void ExplodedNodeImpl::addPredecessor(ExplodedNodeImpl* V) {
+ assert (!V->isSink());
+ Preds.addNode(V);
+ V->Succs.addNode(this);
+#ifndef NDEBUG
+ if (NodeAuditor) NodeAuditor->AddEdge(V, this);
+#endif
+}
+
+void ExplodedNodeImpl::NodeGroup::addNode(ExplodedNodeImpl* N) {
+
+ assert ((reinterpret_cast<uintptr_t>(N) & Mask) == 0x0);
+ assert (!getFlag());
+
+ if (getKind() == Size1) {
+ if (ExplodedNodeImpl* NOld = getNode()) {
+ std::vector<ExplodedNodeImpl*>* V = new std::vector<ExplodedNodeImpl*>();
+ assert ((reinterpret_cast<uintptr_t>(V) & Mask) == 0x0);
+ V->push_back(NOld);
+ V->push_back(N);
+ P = reinterpret_cast<uintptr_t>(V) | SizeOther;
+ assert (getPtr() == (void*) V);
+ assert (getKind() == SizeOther);
+ }
+ else {
+ P = reinterpret_cast<uintptr_t>(N);
+ assert (getKind() == Size1);
+ }
+ }
+ else {
+ assert (getKind() == SizeOther);
+ getVector(getPtr()).push_back(N);
+ }
+}
+
+
+unsigned ExplodedNodeImpl::NodeGroup::size() const {
+ if (getFlag())
+ return 0;
+
+ if (getKind() == Size1)
+ return getNode() ? 1 : 0;
+ else
+ return getVector(getPtr()).size();
+}
+
+ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::begin() const {
+ if (getFlag())
+ return NULL;
+
+ if (getKind() == Size1)
+ return (ExplodedNodeImpl**) (getPtr() ? &P : NULL);
+ else
+ return const_cast<ExplodedNodeImpl**>(&*(getVector(getPtr()).begin()));
+}
+
+ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::end() const {
+ if (getFlag())
+ return NULL;
+
+ if (getKind() == Size1)
+ return (ExplodedNodeImpl**) (getPtr() ? &P+1 : NULL);
+ else {
+ // Dereferencing end() is undefined behaviour. The vector is not empty, so
+ // we can dereference the last elem and then add 1 to the result.
+ return const_cast<ExplodedNodeImpl**>(&getVector(getPtr()).back()) + 1;
+ }
+}
+
+ExplodedNodeImpl::NodeGroup::~NodeGroup() {
+ if (getKind() == SizeOther) delete &getVector(getPtr());
+}
+
+ExplodedGraphImpl*
+ExplodedGraphImpl::Trim(const ExplodedNodeImpl* const* BeginSources,
+ const ExplodedNodeImpl* const* EndSources,
+ InterExplodedGraphMapImpl* M,
+ llvm::DenseMap<const void*, const void*> *InverseMap)
+const {
+
+ typedef llvm::DenseSet<const ExplodedNodeImpl*> Pass1Ty;
+ Pass1Ty Pass1;
+
+ typedef llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> Pass2Ty;
+ Pass2Ty& Pass2 = M->M;
+
+ llvm::SmallVector<const ExplodedNodeImpl*, 10> WL1, WL2;
+
+ // ===- Pass 1 (reverse DFS) -===
+ for (const ExplodedNodeImpl* const* I = BeginSources; I != EndSources; ++I) {
+ assert(*I);
+ WL1.push_back(*I);
+ }
+
+ // Process the first worklist until it is empty. Because it is a std::list
+ // it acts like a FIFO queue.
+ while (!WL1.empty()) {
+ const ExplodedNodeImpl *N = WL1.back();
+ WL1.pop_back();
+
+ // Have we already visited this node? If so, continue to the next one.
+ if (Pass1.count(N))
+ continue;
+
+ // Otherwise, mark this node as visited.
+ Pass1.insert(N);
+
+ // If this is a root enqueue it to the second worklist.
+ if (N->Preds.empty()) {
+ WL2.push_back(N);
+ continue;
+ }
+
+ // Visit our predecessors and enqueue them.
+ for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I)
+ WL1.push_back(*I);
+ }
+
+ // We didn't hit a root? Return with a null pointer for the new graph.
+ if (WL2.empty())
+ return 0;
+
+ // Create an empty graph.
+ ExplodedGraphImpl* G = MakeEmptyGraph();
+
+ // ===- Pass 2 (forward DFS to construct the new graph) -===
+ while (!WL2.empty()) {
+ const ExplodedNodeImpl* N = WL2.back();
+ WL2.pop_back();
+
+ // Skip this node if we have already processed it.
+ if (Pass2.find(N) != Pass2.end())
+ continue;
+
+ // Create the corresponding node in the new graph and record the mapping
+ // from the old node to the new node.
+ ExplodedNodeImpl* NewN = G->getNodeImpl(N->getLocation(), N->State, NULL);
+ Pass2[N] = NewN;
+
+ // Also record the reverse mapping from the new node to the old node.
+ if (InverseMap) (*InverseMap)[NewN] = N;
+
+ // If this node is a root, designate it as such in the graph.
+ if (N->Preds.empty())
+ G->addRoot(NewN);
+
+ // In the case that some of the intended predecessors of NewN have already
+ // been created, we should hook them up as predecessors.
+
+ // Walk through the predecessors of 'N' and hook up their corresponding
+ // nodes in the new graph (if any) to the freshly created node.
+ for (ExplodedNodeImpl **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) {
+ Pass2Ty::iterator PI = Pass2.find(*I);
+ if (PI == Pass2.end())
+ continue;
+
+ NewN->addPredecessor(PI->second);
+ }
+
+ // In the case that some of the intended successors of NewN have already
+ // been created, we should hook them up as successors. Otherwise, enqueue
+ // the new nodes from the original graph that should have nodes created
+ // in the new graph.
+ for (ExplodedNodeImpl **I=N->Succs.begin(), **E=N->Succs.end(); I!=E; ++I) {
+ Pass2Ty::iterator PI = Pass2.find(*I);
+ if (PI != Pass2.end()) {
+ PI->second->addPredecessor(NewN);
+ continue;
+ }
+
+ // Enqueue nodes to the worklist that were marked during pass 1.
+ if (Pass1.count(*I))
+ WL2.push_back(*I);
+ }
+
+ // Finally, explictly mark all nodes without any successors as sinks.
+ if (N->isSink())
+ NewN->markAsSink();
+ }
+
+ return G;
+}
+
+ExplodedNodeImpl*
+InterExplodedGraphMapImpl::getMappedImplNode(const ExplodedNodeImpl* N) const {
+ llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*>::iterator I =
+ M.find(N);
+
+ return I == M.end() ? 0 : I->second;
+}
+
+InterExplodedGraphMapImpl::InterExplodedGraphMapImpl() {}
+
diff --git a/lib/Analysis/GRBlockCounter.cpp b/lib/Analysis/GRBlockCounter.cpp
new file mode 100644
index 000000000000..f69a16da401c
--- /dev/null
+++ b/lib/Analysis/GRBlockCounter.cpp
@@ -0,0 +1,54 @@
+//==- GRBlockCounter.h - ADT for counting block visits -------------*- 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 GRBlockCounter, an abstract data type used to count
+// the number of times a given block has been visited along a path
+// analyzed by GRCoreEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
+#include "llvm/ADT/ImmutableMap.h"
+
+using namespace clang;
+
+typedef llvm::ImmutableMap<unsigned,unsigned> CountMap;
+
+static inline CountMap GetMap(void* D) {
+ return CountMap(static_cast<CountMap::TreeTy*>(D));
+}
+
+static inline CountMap::Factory& GetFactory(void* F) {
+ return *static_cast<CountMap::Factory*>(F);
+}
+
+unsigned GRBlockCounter::getNumVisited(unsigned BlockID) const {
+ CountMap M = GetMap(Data);
+ CountMap::data_type* T = M.lookup(BlockID);
+ return T ? *T : 0;
+}
+
+GRBlockCounter::Factory::Factory(llvm::BumpPtrAllocator& Alloc) {
+ F = new CountMap::Factory(Alloc);
+}
+
+GRBlockCounter::Factory::~Factory() {
+ delete static_cast<CountMap::Factory*>(F);
+}
+
+GRBlockCounter
+GRBlockCounter::Factory::IncrementCount(GRBlockCounter BC, unsigned BlockID) {
+ return GRBlockCounter(GetFactory(F).Add(GetMap(BC.Data), BlockID,
+ BC.getNumVisited(BlockID)+1).getRoot());
+}
+
+GRBlockCounter
+GRBlockCounter::Factory::GetEmptyCounter() {
+ return GRBlockCounter(GetFactory(F).GetEmptyMap().getRoot());
+}
diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Analysis/GRCoreEngine.cpp
new file mode 100644
index 000000000000..ff7b548bc054
--- /dev/null
+++ b/lib/Analysis/GRCoreEngine.cpp
@@ -0,0 +1,576 @@
+//==- GRCoreEngine.cpp - Path-Sensitive Dataflow Engine ------------*- 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 a generic engine for intraprocedural, path-sensitive,
+// dataflow analysis via graph reachability engine.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
+#include "clang/AST/Expr.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/ADT/DenseMap.h"
+#include <vector>
+#include <queue>
+
+using llvm::cast;
+using llvm::isa;
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Worklist classes for exploration of reachable states.
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class VISIBILITY_HIDDEN DFS : public GRWorkList {
+ llvm::SmallVector<GRWorkListUnit,20> Stack;
+public:
+ virtual bool hasWork() const {
+ return !Stack.empty();
+ }
+
+ virtual void Enqueue(const GRWorkListUnit& U) {
+ Stack.push_back(U);
+ }
+
+ virtual GRWorkListUnit Dequeue() {
+ assert (!Stack.empty());
+ const GRWorkListUnit& U = Stack.back();
+ Stack.pop_back(); // This technically "invalidates" U, but we are fine.
+ return U;
+ }
+};
+
+class VISIBILITY_HIDDEN BFS : public GRWorkList {
+ std::queue<GRWorkListUnit> Queue;
+public:
+ virtual bool hasWork() const {
+ return !Queue.empty();
+ }
+
+ virtual void Enqueue(const GRWorkListUnit& U) {
+ Queue.push(U);
+ }
+
+ virtual GRWorkListUnit Dequeue() {
+ // Don't use const reference. The subsequent pop_back() might make it
+ // unsafe.
+ GRWorkListUnit U = Queue.front();
+ Queue.pop();
+ return U;
+ }
+};
+
+} // end anonymous namespace
+
+// Place the dstor for GRWorkList here because it contains virtual member
+// functions, and we the code for the dstor generated in one compilation unit.
+GRWorkList::~GRWorkList() {}
+
+GRWorkList *GRWorkList::MakeDFS() { return new DFS(); }
+GRWorkList *GRWorkList::MakeBFS() { return new BFS(); }
+
+namespace {
+ class VISIBILITY_HIDDEN BFSBlockDFSContents : public GRWorkList {
+ std::queue<GRWorkListUnit> Queue;
+ llvm::SmallVector<GRWorkListUnit,20> Stack;
+ public:
+ virtual bool hasWork() const {
+ return !Queue.empty() || !Stack.empty();
+ }
+
+ virtual void Enqueue(const GRWorkListUnit& U) {
+ if (isa<BlockEntrance>(U.getNode()->getLocation()))
+ Queue.push(U);
+ else
+ Stack.push_back(U);
+ }
+
+ virtual GRWorkListUnit Dequeue() {
+ // Process all basic blocks to completion.
+ if (!Stack.empty()) {
+ const GRWorkListUnit& U = Stack.back();
+ Stack.pop_back(); // This technically "invalidates" U, but we are fine.
+ return U;
+ }
+
+ assert(!Queue.empty());
+ // Don't use const reference. The subsequent pop_back() might make it
+ // unsafe.
+ GRWorkListUnit U = Queue.front();
+ Queue.pop();
+ return U;
+ }
+ };
+} // end anonymous namespace
+
+GRWorkList* GRWorkList::MakeBFSBlockDFSContents() {
+ return new BFSBlockDFSContents();
+}
+
+//===----------------------------------------------------------------------===//
+// Core analysis engine.
+//===----------------------------------------------------------------------===//
+
+/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
+bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) {
+
+ if (G->num_roots() == 0) { // Initialize the analysis by constructing
+ // the root if none exists.
+
+ CFGBlock* Entry = &getCFG().getEntry();
+
+ assert (Entry->empty() &&
+ "Entry block must be empty.");
+
+ assert (Entry->succ_size() == 1 &&
+ "Entry block must have 1 successor.");
+
+ // Get the solitary successor.
+ CFGBlock* Succ = *(Entry->succ_begin());
+
+ // Construct an edge representing the
+ // starting location in the function.
+ BlockEdge StartLoc(Entry, Succ);
+
+ // Set the current block counter to being empty.
+ WList->setBlockCounter(BCounterFactory.GetEmptyCounter());
+
+ // Generate the root.
+ GenerateNode(StartLoc, getInitialState(), 0);
+ }
+
+ while (Steps && WList->hasWork()) {
+ --Steps;
+ const GRWorkListUnit& WU = WList->Dequeue();
+
+ // Set the current block counter.
+ WList->setBlockCounter(WU.getBlockCounter());
+
+ // Retrieve the node.
+ ExplodedNodeImpl* Node = WU.getNode();
+
+ // Dispatch on the location type.
+ switch (Node->getLocation().getKind()) {
+ case ProgramPoint::BlockEdgeKind:
+ HandleBlockEdge(cast<BlockEdge>(Node->getLocation()), Node);
+ break;
+
+ case ProgramPoint::BlockEntranceKind:
+ HandleBlockEntrance(cast<BlockEntrance>(Node->getLocation()), Node);
+ break;
+
+ case ProgramPoint::BlockExitKind:
+ assert (false && "BlockExit location never occur in forward analysis.");
+ break;
+
+ default:
+ assert(isa<PostStmt>(Node->getLocation()));
+ HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(),
+ WU.getIndex(), Node);
+ break;
+ }
+ }
+
+ return WList->hasWork();
+}
+
+void GRCoreEngineImpl::HandleBlockEdge(const BlockEdge& L,
+ ExplodedNodeImpl* Pred) {
+
+ CFGBlock* Blk = L.getDst();
+
+ // Check if we are entering the EXIT block.
+ if (Blk == &getCFG().getExit()) {
+
+ assert (getCFG().getExit().size() == 0
+ && "EXIT block cannot contain Stmts.");
+
+ // Process the final state transition.
+ GREndPathNodeBuilderImpl Builder(Blk, Pred, this);
+ ProcessEndPath(Builder);
+
+ // This path is done. Don't enqueue any more nodes.
+ return;
+ }
+
+ // FIXME: Should we allow ProcessBlockEntrance to also manipulate state?
+
+ if (ProcessBlockEntrance(Blk, Pred->State, WList->getBlockCounter()))
+ GenerateNode(BlockEntrance(Blk), Pred->State, Pred);
+}
+
+void GRCoreEngineImpl::HandleBlockEntrance(const BlockEntrance& L,
+ ExplodedNodeImpl* Pred) {
+
+ // Increment the block counter.
+ GRBlockCounter Counter = WList->getBlockCounter();
+ Counter = BCounterFactory.IncrementCount(Counter, L.getBlock()->getBlockID());
+ WList->setBlockCounter(Counter);
+
+ // Process the entrance of the block.
+ if (Stmt* S = L.getFirstStmt()) {
+ GRStmtNodeBuilderImpl Builder(L.getBlock(), 0, Pred, this);
+ ProcessStmt(S, Builder);
+ }
+ else
+ HandleBlockExit(L.getBlock(), Pred);
+}
+
+GRCoreEngineImpl::~GRCoreEngineImpl() {
+ delete WList;
+}
+
+void GRCoreEngineImpl::HandleBlockExit(CFGBlock * B, ExplodedNodeImpl* Pred) {
+
+ if (Stmt* Term = B->getTerminator()) {
+ switch (Term->getStmtClass()) {
+ default:
+ assert(false && "Analysis for this terminator not implemented.");
+ break;
+
+ case Stmt::BinaryOperatorClass: // '&&' and '||'
+ HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
+ return;
+
+ case Stmt::ConditionalOperatorClass:
+ HandleBranch(cast<ConditionalOperator>(Term)->getCond(), Term, B, Pred);
+ return;
+
+ // FIXME: Use constant-folding in CFG construction to simplify this
+ // case.
+
+ case Stmt::ChooseExprClass:
+ HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred);
+ return;
+
+ case Stmt::DoStmtClass:
+ HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
+ return;
+
+ case Stmt::ForStmtClass:
+ HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred);
+ return;
+
+ case Stmt::ContinueStmtClass:
+ case Stmt::BreakStmtClass:
+ case Stmt::GotoStmtClass:
+ break;
+
+ case Stmt::IfStmtClass:
+ HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred);
+ return;
+
+ case Stmt::IndirectGotoStmtClass: {
+ // Only 1 successor: the indirect goto dispatch block.
+ assert (B->succ_size() == 1);
+
+ GRIndirectGotoNodeBuilderImpl
+ builder(Pred, B, cast<IndirectGotoStmt>(Term)->getTarget(),
+ *(B->succ_begin()), this);
+
+ ProcessIndirectGoto(builder);
+ return;
+ }
+
+ case Stmt::ObjCForCollectionStmtClass: {
+ // In the case of ObjCForCollectionStmt, it appears twice in a CFG:
+ //
+ // (1) inside a basic block, which represents the binding of the
+ // 'element' variable to a value.
+ // (2) in a terminator, which represents the branch.
+ //
+ // For (1), subengines will bind a value (i.e., 0 or 1) indicating
+ // whether or not collection contains any more elements. We cannot
+ // just test to see if the element is nil because a container can
+ // contain nil elements.
+ HandleBranch(Term, Term, B, Pred);
+ return;
+ }
+
+ case Stmt::SwitchStmtClass: {
+ GRSwitchNodeBuilderImpl builder(Pred, B,
+ cast<SwitchStmt>(Term)->getCond(),
+ this);
+
+ ProcessSwitch(builder);
+ return;
+ }
+
+ case Stmt::WhileStmtClass:
+ HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
+ return;
+ }
+ }
+
+ assert (B->succ_size() == 1 &&
+ "Blocks with no terminator should have at most 1 successor.");
+
+ GenerateNode(BlockEdge(B, *(B->succ_begin())), Pred->State, Pred);
+}
+
+void GRCoreEngineImpl::HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock * B,
+ ExplodedNodeImpl* Pred) {
+ assert (B->succ_size() == 2);
+
+ GRBranchNodeBuilderImpl Builder(B, *(B->succ_begin()), *(B->succ_begin()+1),
+ Pred, this);
+
+ ProcessBranch(Cond, Term, Builder);
+}
+
+void GRCoreEngineImpl::HandlePostStmt(const PostStmt& L, CFGBlock* B,
+ unsigned StmtIdx, ExplodedNodeImpl* Pred) {
+
+ assert (!B->empty());
+
+ if (StmtIdx == B->size())
+ HandleBlockExit(B, Pred);
+ else {
+ GRStmtNodeBuilderImpl Builder(B, StmtIdx, Pred, this);
+ ProcessStmt((*B)[StmtIdx], Builder);
+ }
+}
+
+/// GenerateNode - Utility method to generate nodes, hook up successors,
+/// and add nodes to the worklist.
+void GRCoreEngineImpl::GenerateNode(const ProgramPoint& Loc, const void* State,
+ ExplodedNodeImpl* Pred) {
+
+ bool IsNew;
+ ExplodedNodeImpl* Node = G->getNodeImpl(Loc, State, &IsNew);
+
+ if (Pred)
+ Node->addPredecessor(Pred); // Link 'Node' with its predecessor.
+ else {
+ assert (IsNew);
+ G->addRoot(Node); // 'Node' has no predecessor. Make it a root.
+ }
+
+ // Only add 'Node' to the worklist if it was freshly generated.
+ if (IsNew) WList->Enqueue(Node);
+}
+
+GRStmtNodeBuilderImpl::GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx,
+ ExplodedNodeImpl* N, GRCoreEngineImpl* e)
+ : Eng(*e), B(*b), Idx(idx), Pred(N), LastNode(N) {
+ Deferred.insert(N);
+}
+
+GRStmtNodeBuilderImpl::~GRStmtNodeBuilderImpl() {
+ for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I)
+ if (!(*I)->isSink())
+ GenerateAutoTransition(*I);
+}
+
+void GRStmtNodeBuilderImpl::GenerateAutoTransition(ExplodedNodeImpl* N) {
+ assert (!N->isSink());
+
+ PostStmt Loc(getStmt());
+
+ if (Loc == N->getLocation()) {
+ // Note: 'N' should be a fresh node because otherwise it shouldn't be
+ // a member of Deferred.
+ Eng.WList->Enqueue(N, B, Idx+1);
+ return;
+ }
+
+ bool IsNew;
+ ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(Loc, N->State, &IsNew);
+ Succ->addPredecessor(N);
+
+ if (IsNew)
+ Eng.WList->Enqueue(Succ, B, Idx+1);
+}
+
+static inline PostStmt GetPostLoc(Stmt* S, ProgramPoint::Kind K,
+ const void *tag) {
+ switch (K) {
+ default:
+ assert(false && "Invalid PostXXXKind.");
+
+ case ProgramPoint::PostStmtKind:
+ return PostStmt(S, tag);
+
+ case ProgramPoint::PostLoadKind:
+ return PostLoad(S, tag);
+
+ case ProgramPoint::PostUndefLocationCheckFailedKind:
+ return PostUndefLocationCheckFailed(S, tag);
+
+ case ProgramPoint::PostLocationChecksSucceedKind:
+ return PostLocationChecksSucceed(S, tag);
+
+ case ProgramPoint::PostOutOfBoundsCheckFailedKind:
+ return PostOutOfBoundsCheckFailed(S, tag);
+
+ case ProgramPoint::PostNullCheckFailedKind:
+ return PostNullCheckFailed(S, tag);
+
+ case ProgramPoint::PostStoreKind:
+ return PostStore(S, tag);
+
+ case ProgramPoint::PostLValueKind:
+ return PostLValue(S, tag);
+
+ case ProgramPoint::PostPurgeDeadSymbolsKind:
+ return PostPurgeDeadSymbols(S, tag);
+ }
+}
+
+ExplodedNodeImpl*
+GRStmtNodeBuilderImpl::generateNodeImpl(Stmt* S, const void* State,
+ ExplodedNodeImpl* Pred,
+ ProgramPoint::Kind K,
+ const void *tag) {
+ return generateNodeImpl(GetPostLoc(S, K, tag), State, Pred);
+}
+
+ExplodedNodeImpl*
+GRStmtNodeBuilderImpl::generateNodeImpl(PostStmt Loc, const void* State,
+ ExplodedNodeImpl* Pred) {
+ bool IsNew;
+ ExplodedNodeImpl* N = Eng.G->getNodeImpl(Loc, State, &IsNew);
+ N->addPredecessor(Pred);
+ Deferred.erase(Pred);
+
+ if (IsNew) {
+ Deferred.insert(N);
+ LastNode = N;
+ return N;
+ }
+
+ LastNode = NULL;
+ return NULL;
+}
+
+ExplodedNodeImpl* GRBranchNodeBuilderImpl::generateNodeImpl(const void* State,
+ bool branch) {
+ bool IsNew;
+
+ ExplodedNodeImpl* Succ =
+ Eng.G->getNodeImpl(BlockEdge(Src, branch ? DstT : DstF), State, &IsNew);
+
+ Succ->addPredecessor(Pred);
+
+ if (branch) GeneratedTrue = true;
+ else GeneratedFalse = true;
+
+ if (IsNew) {
+ Deferred.push_back(Succ);
+ return Succ;
+ }
+
+ return NULL;
+}
+
+GRBranchNodeBuilderImpl::~GRBranchNodeBuilderImpl() {
+ if (!GeneratedTrue) generateNodeImpl(Pred->State, true);
+ if (!GeneratedFalse) generateNodeImpl(Pred->State, false);
+
+ for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I)
+ if (!(*I)->isSink()) Eng.WList->Enqueue(*I);
+}
+
+
+ExplodedNodeImpl*
+GRIndirectGotoNodeBuilderImpl::generateNodeImpl(const Iterator& I,
+ const void* St,
+ bool isSink) {
+ bool IsNew;
+
+ ExplodedNodeImpl* Succ =
+ Eng.G->getNodeImpl(BlockEdge(Src, I.getBlock()), St, &IsNew);
+
+ Succ->addPredecessor(Pred);
+
+ if (IsNew) {
+
+ if (isSink)
+ Succ->markAsSink();
+ else
+ Eng.WList->Enqueue(Succ);
+
+ return Succ;
+ }
+
+ return NULL;
+}
+
+
+ExplodedNodeImpl*
+GRSwitchNodeBuilderImpl::generateCaseStmtNodeImpl(const Iterator& I,
+ const void* St) {
+
+ bool IsNew;
+
+ ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(BlockEdge(Src, I.getBlock()),
+ St, &IsNew);
+ Succ->addPredecessor(Pred);
+
+ if (IsNew) {
+ Eng.WList->Enqueue(Succ);
+ return Succ;
+ }
+
+ return NULL;
+}
+
+
+ExplodedNodeImpl*
+GRSwitchNodeBuilderImpl::generateDefaultCaseNodeImpl(const void* St,
+ bool isSink) {
+
+ // Get the block for the default case.
+ assert (Src->succ_rbegin() != Src->succ_rend());
+ CFGBlock* DefaultBlock = *Src->succ_rbegin();
+
+ bool IsNew;
+
+ ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(BlockEdge(Src, DefaultBlock),
+ St, &IsNew);
+ Succ->addPredecessor(Pred);
+
+ if (IsNew) {
+ if (isSink)
+ Succ->markAsSink();
+ else
+ Eng.WList->Enqueue(Succ);
+
+ return Succ;
+ }
+
+ return NULL;
+}
+
+GREndPathNodeBuilderImpl::~GREndPathNodeBuilderImpl() {
+ // Auto-generate an EOP node if one has not been generated.
+ if (!HasGeneratedNode) generateNodeImpl(Pred->State);
+}
+
+ExplodedNodeImpl*
+GREndPathNodeBuilderImpl::generateNodeImpl(const void* State,
+ const void *tag,
+ ExplodedNodeImpl* P) {
+ HasGeneratedNode = true;
+ bool IsNew;
+
+ ExplodedNodeImpl* Node =
+ Eng.G->getNodeImpl(BlockEntrance(&B, tag), State, &IsNew);
+
+ Node->addPredecessor(P ? P : Pred);
+
+ if (IsNew) {
+ Eng.G->addEndOfPath(Node);
+ return Node;
+ }
+
+ return NULL;
+}
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
new file mode 100644
index 000000000000..e8c5be51d6ac
--- /dev/null
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -0,0 +1,3426 @@
+//=-- GRExprEngine.cpp - Path-Sensitive Expression-Level Dataflow ---*- 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 a meta-engine for path-sensitive dataflow analysis that
+// is built on GREngine, but provides the boilerplate to execute transfer
+// functions and build the ExplodedGraph at the expression level.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/PrettyStackTrace.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+
+#ifndef NDEBUG
+#include "llvm/Support/GraphWriter.h"
+#include <sstream>
+#endif
+
+using namespace clang;
+using llvm::dyn_cast;
+using llvm::cast;
+using llvm::APSInt;
+
+//===----------------------------------------------------------------------===//
+// Engine construction and deletion.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class VISIBILITY_HIDDEN MappedBatchAuditor : public GRSimpleAPICheck {
+ typedef llvm::ImmutableList<GRSimpleAPICheck*> Checks;
+ typedef llvm::DenseMap<void*,Checks> MapTy;
+
+ MapTy M;
+ Checks::Factory F;
+ Checks AllStmts;
+
+public:
+ MappedBatchAuditor(llvm::BumpPtrAllocator& Alloc) :
+ F(Alloc), AllStmts(F.GetEmptyList()) {}
+
+ virtual ~MappedBatchAuditor() {
+ llvm::DenseSet<GRSimpleAPICheck*> AlreadyVisited;
+
+ for (MapTy::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI)
+ for (Checks::iterator I=MI->second.begin(), E=MI->second.end(); I!=E;++I){
+
+ GRSimpleAPICheck* check = *I;
+
+ if (AlreadyVisited.count(check))
+ continue;
+
+ AlreadyVisited.insert(check);
+ delete check;
+ }
+ }
+
+ void AddCheck(GRSimpleAPICheck *A, Stmt::StmtClass C) {
+ assert (A && "Check cannot be null.");
+ void* key = reinterpret_cast<void*>((uintptr_t) C);
+ MapTy::iterator I = M.find(key);
+ M[key] = F.Concat(A, I == M.end() ? F.GetEmptyList() : I->second);
+ }
+
+ void AddCheck(GRSimpleAPICheck *A) {
+ assert (A && "Check cannot be null.");
+ AllStmts = F.Concat(A, AllStmts);
+ }
+
+ virtual bool Audit(NodeTy* N, GRStateManager& VMgr) {
+ // First handle the auditors that accept all statements.
+ bool isSink = false;
+ for (Checks::iterator I = AllStmts.begin(), E = AllStmts.end(); I!=E; ++I)
+ isSink |= (*I)->Audit(N, VMgr);
+
+ // Next handle the auditors that accept only specific statements.
+ Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+ void* key = reinterpret_cast<void*>((uintptr_t) S->getStmtClass());
+ MapTy::iterator MI = M.find(key);
+ if (MI != M.end()) {
+ for (Checks::iterator I=MI->second.begin(), E=MI->second.end(); I!=E; ++I)
+ isSink |= (*I)->Audit(N, VMgr);
+ }
+
+ return isSink;
+ }
+};
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Engine construction and deletion.
+//===----------------------------------------------------------------------===//
+
+static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
+ IdentifierInfo* II = &Ctx.Idents.get(name);
+ return Ctx.Selectors.getSelector(0, &II);
+}
+
+
+GRExprEngine::GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx,
+ LiveVariables& L, BugReporterData& BRD,
+ bool purgeDead, bool eagerlyAssume,
+ StoreManagerCreator SMC,
+ ConstraintManagerCreator CMC)
+ : CoreEngine(cfg, CD, Ctx, *this),
+ G(CoreEngine.getGraph()),
+ Liveness(L),
+ Builder(NULL),
+ StateMgr(G.getContext(), SMC, CMC, G.getAllocator(), cfg, CD, L),
+ SymMgr(StateMgr.getSymbolManager()),
+ ValMgr(StateMgr.getValueManager()),
+ CurrentStmt(NULL),
+ NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
+ RaiseSel(GetNullarySelector("raise", G.getContext())),
+ PurgeDead(purgeDead),
+ BR(BRD, *this),
+ EagerlyAssume(eagerlyAssume) {}
+
+GRExprEngine::~GRExprEngine() {
+ BR.FlushReports();
+ delete [] NSExceptionInstanceRaiseSelectors;
+}
+
+//===----------------------------------------------------------------------===//
+// Utility methods.
+//===----------------------------------------------------------------------===//
+
+
+void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) {
+ StateMgr.TF = tf;
+ tf->RegisterChecks(getBugReporter());
+ tf->RegisterPrinters(getStateManager().Printers);
+}
+
+void GRExprEngine::AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C) {
+ if (!BatchAuditor)
+ BatchAuditor.reset(new MappedBatchAuditor(getGraph().getAllocator()));
+
+ ((MappedBatchAuditor*) BatchAuditor.get())->AddCheck(A, C);
+}
+
+void GRExprEngine::AddCheck(GRSimpleAPICheck *A) {
+ if (!BatchAuditor)
+ BatchAuditor.reset(new MappedBatchAuditor(getGraph().getAllocator()));
+
+ ((MappedBatchAuditor*) BatchAuditor.get())->AddCheck(A);
+}
+
+const GRState* GRExprEngine::getInitialState() {
+ const GRState *state = StateMgr.getInitialState();
+
+ // Precondition: the first argument of 'main' is an integer guaranteed
+ // to be > 0.
+ // FIXME: It would be nice if we had a more general mechanism to add
+ // such preconditions. Some day.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(&StateMgr.getCodeDecl()))
+ if (strcmp(FD->getIdentifier()->getName(), "main") == 0 &&
+ FD->getNumParams() > 0) {
+ const ParmVarDecl *PD = FD->getParamDecl(0);
+ QualType T = PD->getType();
+ if (T->isIntegerType())
+ if (const MemRegion *R = StateMgr.getRegion(PD)) {
+ SVal V = GetSVal(state, loc::MemRegionVal(R));
+ SVal Constraint = EvalBinOp(state, BinaryOperator::GT, V,
+ ValMgr.makeZeroVal(T),
+ getContext().IntTy);
+ bool isFeasible = false;
+ const GRState *newState = Assume(state, Constraint, true,
+ isFeasible);
+ if (newState) state = newState;
+ }
+ }
+
+ return state;
+}
+
+//===----------------------------------------------------------------------===//
+// Top-level transfer function logic (Dispatcher).
+//===----------------------------------------------------------------------===//
+
+void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) {
+
+ PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+ S->getLocStart(),
+ "Error evaluating statement");
+
+ Builder = &builder;
+ EntryNode = builder.getLastNode();
+
+ // FIXME: Consolidate.
+ CurrentStmt = S;
+ StateMgr.CurrentStmt = S;
+
+ // Set up our simple checks.
+ if (BatchAuditor)
+ Builder->setAuditor(BatchAuditor.get());
+
+ // Create the cleaned state.
+ SymbolReaper SymReaper(Liveness, SymMgr);
+ CleanedState = PurgeDead ? StateMgr.RemoveDeadBindings(EntryNode->getState(),
+ CurrentStmt, SymReaper)
+ : EntryNode->getState();
+
+ // Process any special transfer function for dead symbols.
+ NodeSet Tmp;
+
+ if (!SymReaper.hasDeadSymbols())
+ Tmp.Add(EntryNode);
+ else {
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
+
+ SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols);
+ Builder->PurgingDeadSymbols = true;
+
+ getTF().EvalDeadSymbols(Tmp, *this, *Builder, EntryNode, S,
+ CleanedState, SymReaper);
+
+ if (!Builder->BuildSinks && !Builder->HasGeneratedNode)
+ Tmp.Add(EntryNode);
+ }
+
+ bool HasAutoGenerated = false;
+
+ for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+
+ NodeSet Dst;
+
+ // Set the cleaned state.
+ Builder->SetCleanedState(*I == EntryNode ? CleanedState : GetState(*I));
+
+ // Visit the statement.
+ Visit(S, *I, Dst);
+
+ // Do we need to auto-generate a node? We only need to do this to generate
+ // a node with a "cleaned" state; GRCoreEngine will actually handle
+ // auto-transitions for other cases.
+ if (Dst.size() == 1 && *Dst.begin() == EntryNode
+ && !Builder->HasGeneratedNode && !HasAutoGenerated) {
+ HasAutoGenerated = true;
+ builder.generateNode(S, GetState(EntryNode), *I);
+ }
+ }
+
+ // NULL out these variables to cleanup.
+ CleanedState = NULL;
+ EntryNode = NULL;
+
+ // FIXME: Consolidate.
+ StateMgr.CurrentStmt = 0;
+ CurrentStmt = 0;
+
+ Builder = NULL;
+}
+
+void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
+ PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+ S->getLocStart(),
+ "Error evaluating statement");
+
+ // FIXME: add metadata to the CFG so that we can disable
+ // this check when we KNOW that there is no block-level subexpression.
+ // The motivation is that this check requires a hashtable lookup.
+
+ if (S != CurrentStmt && getCFG().isBlkExpr(S)) {
+ Dst.Add(Pred);
+ return;
+ }
+
+ switch (S->getStmtClass()) {
+
+ default:
+ // Cases we intentionally have "default" handle:
+ // AddrLabelExpr, IntegerLiteral, CharacterLiteral
+
+ Dst.Add(Pred); // No-op. Simply propagate the current state unchanged.
+ break;
+
+ case Stmt::ArraySubscriptExprClass:
+ VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst, false);
+ break;
+
+ case Stmt::AsmStmtClass:
+ VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
+ break;
+
+ case Stmt::BinaryOperatorClass: {
+ BinaryOperator* B = cast<BinaryOperator>(S);
+
+ if (B->isLogicalOp()) {
+ VisitLogicalExpr(B, Pred, Dst);
+ break;
+ }
+ else if (B->getOpcode() == BinaryOperator::Comma) {
+ const GRState* state = GetState(Pred);
+ MakeNode(Dst, B, Pred, BindExpr(state, B, GetSVal(state, B->getRHS())));
+ break;
+ }
+
+ if (EagerlyAssume && (B->isRelationalOp() || B->isEqualityOp())) {
+ NodeSet Tmp;
+ VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp);
+ EvalEagerlyAssume(Dst, Tmp, cast<Expr>(S));
+ }
+ else
+ VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
+
+ break;
+ }
+
+ case Stmt::CallExprClass:
+ case Stmt::CXXOperatorCallExprClass: {
+ CallExpr* C = cast<CallExpr>(S);
+ VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
+ break;
+ }
+
+ // FIXME: ChooseExpr is really a constant. We need to fix
+ // the CFG do not model them as explicit control-flow.
+
+ case Stmt::ChooseExprClass: { // __builtin_choose_expr
+ ChooseExpr* C = cast<ChooseExpr>(S);
+ VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
+ break;
+ }
+
+ case Stmt::CompoundAssignOperatorClass:
+ VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
+ break;
+
+ case Stmt::CompoundLiteralExprClass:
+ VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(S), Pred, Dst, false);
+ break;
+
+ case Stmt::ConditionalOperatorClass: { // '?' operator
+ ConditionalOperator* C = cast<ConditionalOperator>(S);
+ VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
+ break;
+ }
+
+ case Stmt::DeclRefExprClass:
+ case Stmt::QualifiedDeclRefExprClass:
+ VisitDeclRefExpr(cast<DeclRefExpr>(S), Pred, Dst, false);
+ break;
+
+ case Stmt::DeclStmtClass:
+ VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst);
+ break;
+
+ case Stmt::ImplicitCastExprClass:
+ case Stmt::CStyleCastExprClass: {
+ CastExpr* C = cast<CastExpr>(S);
+ VisitCast(C, C->getSubExpr(), Pred, Dst);
+ break;
+ }
+
+ case Stmt::InitListExprClass:
+ VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
+ break;
+
+ case Stmt::MemberExprClass:
+ VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst, false);
+ break;
+
+ case Stmt::ObjCIvarRefExprClass:
+ VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(S), Pred, Dst, false);
+ break;
+
+ case Stmt::ObjCForCollectionStmtClass:
+ VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst);
+ break;
+
+ case Stmt::ObjCMessageExprClass: {
+ VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst);
+ break;
+ }
+
+ case Stmt::ObjCAtThrowStmtClass: {
+ // FIXME: This is not complete. We basically treat @throw as
+ // an abort.
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+ Builder->BuildSinks = true;
+ MakeNode(Dst, S, Pred, GetState(Pred));
+ break;
+ }
+
+ case Stmt::ParenExprClass:
+ Visit(cast<ParenExpr>(S)->getSubExpr()->IgnoreParens(), Pred, Dst);
+ break;
+
+ case Stmt::ReturnStmtClass:
+ VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
+ break;
+
+ case Stmt::SizeOfAlignOfExprClass:
+ VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), Pred, Dst);
+ break;
+
+ case Stmt::StmtExprClass: {
+ StmtExpr* SE = cast<StmtExpr>(S);
+
+ if (SE->getSubStmt()->body_empty()) {
+ // Empty statement expression.
+ assert(SE->getType() == getContext().VoidTy
+ && "Empty statement expression must have void type.");
+ Dst.Add(Pred);
+ break;
+ }
+
+ if (Expr* LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) {
+ const GRState* state = GetState(Pred);
+ MakeNode(Dst, SE, Pred, BindExpr(state, SE, GetSVal(state, LastExpr)));
+ }
+ else
+ Dst.Add(Pred);
+
+ break;
+ }
+
+ case Stmt::StringLiteralClass:
+ VisitLValue(cast<StringLiteral>(S), Pred, Dst);
+ break;
+
+ case Stmt::UnaryOperatorClass: {
+ UnaryOperator *U = cast<UnaryOperator>(S);
+ if (EagerlyAssume && (U->getOpcode() == UnaryOperator::LNot)) {
+ NodeSet Tmp;
+ VisitUnaryOperator(U, Pred, Tmp, false);
+ EvalEagerlyAssume(Dst, Tmp, U);
+ }
+ else
+ VisitUnaryOperator(U, Pred, Dst, false);
+ break;
+ }
+ }
+}
+
+void GRExprEngine::VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst) {
+
+ Ex = Ex->IgnoreParens();
+
+ if (Ex != CurrentStmt && getCFG().isBlkExpr(Ex)) {
+ Dst.Add(Pred);
+ return;
+ }
+
+ switch (Ex->getStmtClass()) {
+
+ case Stmt::ArraySubscriptExprClass:
+ VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(Ex), Pred, Dst, true);
+ return;
+
+ case Stmt::DeclRefExprClass:
+ case Stmt::QualifiedDeclRefExprClass:
+ VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true);
+ return;
+
+ case Stmt::ObjCIvarRefExprClass:
+ VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(Ex), Pred, Dst, true);
+ return;
+
+ case Stmt::UnaryOperatorClass:
+ VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true);
+ return;
+
+ case Stmt::MemberExprClass:
+ VisitMemberExpr(cast<MemberExpr>(Ex), Pred, Dst, true);
+ return;
+
+ case Stmt::CompoundLiteralExprClass:
+ VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(Ex), Pred, Dst, true);
+ return;
+
+ case Stmt::ObjCPropertyRefExprClass:
+ case Stmt::ObjCKVCRefExprClass:
+ // FIXME: Property assignments are lvalues, but not really "locations".
+ // e.g.: self.x = something;
+ // Here the "self.x" really can translate to a method call (setter) when
+ // the assignment is made. Moreover, the entire assignment expression
+ // evaluate to whatever "something" is, not calling the "getter" for
+ // the property (which would make sense since it can have side effects).
+ // We'll probably treat this as a location, but not one that we can
+ // take the address of. Perhaps we need a new SVal class for cases
+ // like thsis?
+ // Note that we have a similar problem for bitfields, since they don't
+ // have "locations" in the sense that we can take their address.
+ Dst.Add(Pred);
+ return;
+
+ case Stmt::StringLiteralClass: {
+ const GRState* state = GetState(Pred);
+ SVal V = StateMgr.GetLValue(state, cast<StringLiteral>(Ex));
+ MakeNode(Dst, Ex, Pred, BindExpr(state, Ex, V));
+ return;
+ }
+
+ default:
+ // Arbitrary subexpressions can return aggregate temporaries that
+ // can be used in a lvalue context. We need to enhance our support
+ // of such temporaries in both the environment and the store, so right
+ // now we just do a regular visit.
+ assert ((Ex->getType()->isAggregateType()) &&
+ "Other kinds of expressions with non-aggregate/union types do"
+ " not have lvalues.");
+
+ Visit(Ex, Pred, Dst);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Block entrance. (Update counters).
+//===----------------------------------------------------------------------===//
+
+bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const GRState*,
+ GRBlockCounter BC) {
+
+ return BC.getNumVisited(B->getBlockID()) < 3;
+}
+
+//===----------------------------------------------------------------------===//
+// Generic node creation.
+//===----------------------------------------------------------------------===//
+
+GRExprEngine::NodeTy* GRExprEngine::MakeNode(NodeSet& Dst, Stmt* S,
+ NodeTy* Pred,
+ const GRState* St,
+ ProgramPoint::Kind K,
+ const void *tag) {
+
+ assert (Builder && "GRStmtNodeBuilder not present.");
+ SaveAndRestore<const void*> OldTag(Builder->Tag);
+ Builder->Tag = tag;
+ return Builder->MakeNode(Dst, S, Pred, St, K);
+}
+
+//===----------------------------------------------------------------------===//
+// Branch processing.
+//===----------------------------------------------------------------------===//
+
+const GRState* GRExprEngine::MarkBranch(const GRState* state,
+ Stmt* Terminator,
+ bool branchTaken) {
+
+ switch (Terminator->getStmtClass()) {
+ default:
+ return state;
+
+ case Stmt::BinaryOperatorClass: { // '&&' and '||'
+
+ BinaryOperator* B = cast<BinaryOperator>(Terminator);
+ BinaryOperator::Opcode Op = B->getOpcode();
+
+ assert (Op == BinaryOperator::LAnd || Op == BinaryOperator::LOr);
+
+ // For &&, if we take the true branch, then the value of the whole
+ // expression is that of the RHS expression.
+ //
+ // For ||, if we take the false branch, then the value of the whole
+ // expression is that of the RHS expression.
+
+ Expr* Ex = (Op == BinaryOperator::LAnd && branchTaken) ||
+ (Op == BinaryOperator::LOr && !branchTaken)
+ ? B->getRHS() : B->getLHS();
+
+ return BindBlkExpr(state, B, UndefinedVal(Ex));
+ }
+
+ case Stmt::ConditionalOperatorClass: { // ?:
+
+ ConditionalOperator* C = cast<ConditionalOperator>(Terminator);
+
+ // For ?, if branchTaken == true then the value is either the LHS or
+ // the condition itself. (GNU extension).
+
+ Expr* Ex;
+
+ if (branchTaken)
+ Ex = C->getLHS() ? C->getLHS() : C->getCond();
+ else
+ Ex = C->getRHS();
+
+ return BindBlkExpr(state, C, UndefinedVal(Ex));
+ }
+
+ case Stmt::ChooseExprClass: { // ?:
+
+ ChooseExpr* C = cast<ChooseExpr>(Terminator);
+
+ Expr* Ex = branchTaken ? C->getLHS() : C->getRHS();
+ return BindBlkExpr(state, C, UndefinedVal(Ex));
+ }
+ }
+}
+
+/// RecoverCastedSymbol - A helper function for ProcessBranch that is used
+/// to try to recover some path-sensitivity for casts of symbolic
+/// 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,
+ Stmt* Condition, ASTContext& Ctx) {
+
+ Expr *Ex = dyn_cast<Expr>(Condition);
+ if (!Ex)
+ return UnknownVal();
+
+ uint64_t bits = 0;
+ bool bitsInit = false;
+
+ while (CastExpr *CE = dyn_cast<CastExpr>(Ex)) {
+ QualType T = CE->getType();
+
+ if (!T->isIntegerType())
+ return UnknownVal();
+
+ uint64_t newBits = Ctx.getTypeSize(T);
+ if (!bitsInit || newBits < bits) {
+ bitsInit = true;
+ bits = newBits;
+ }
+
+ Ex = CE->getSubExpr();
+ }
+
+ // We reached a non-cast. Is it a symbolic value?
+ QualType T = Ex->getType();
+
+ if (!bitsInit || !T->isIntegerType() || Ctx.getTypeSize(T) > bits)
+ return UnknownVal();
+
+ return StateMgr.GetSVal(state, Ex);
+}
+
+void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term,
+ BranchNodeBuilder& builder) {
+
+ // Remove old bindings for subexpressions.
+ const GRState* PrevState =
+ StateMgr.RemoveSubExprBindings(builder.getState());
+
+ // Check for NULL conditions; e.g. "for(;;)"
+ if (!Condition) {
+ builder.markInfeasible(false);
+ return;
+ }
+
+ PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+ Condition->getLocStart(),
+ "Error evaluating branch");
+
+ SVal V = GetSVal(PrevState, Condition);
+
+ switch (V.getBaseKind()) {
+ default:
+ break;
+
+ case SVal::UnknownKind: {
+ if (Expr *Ex = dyn_cast<Expr>(Condition)) {
+ if (Ex->getType()->isIntegerType()) {
+ // Try to recover some path-sensitivity. Right now casts of symbolic
+ // integers that promote their values are currently not tracked well.
+ // If 'Condition' is such an expression, try and recover the
+ // underlying value and use that instead.
+ SVal recovered = RecoverCastedSymbol(getStateManager(),
+ builder.getState(), Condition,
+ getContext());
+
+ if (!recovered.isUnknown()) {
+ V = recovered;
+ break;
+ }
+ }
+ }
+
+ builder.generateNode(MarkBranch(PrevState, Term, true), true);
+ builder.generateNode(MarkBranch(PrevState, Term, false), false);
+ return;
+ }
+
+ case SVal::UndefinedKind: {
+ NodeTy* N = builder.generateNode(PrevState, true);
+
+ if (N) {
+ N->markAsSink();
+ UndefBranches.insert(N);
+ }
+
+ builder.markInfeasible(false);
+ return;
+ }
+ }
+
+ // Process the true branch.
+
+ bool isFeasible = false;
+ const GRState* state = Assume(PrevState, V, true, isFeasible);
+
+ if (isFeasible)
+ builder.generateNode(MarkBranch(state, Term, true), true);
+ else
+ builder.markInfeasible(true);
+
+ // Process the false branch.
+
+ isFeasible = false;
+ state = Assume(PrevState, V, false, isFeasible);
+
+ if (isFeasible)
+ builder.generateNode(MarkBranch(state, Term, false), false);
+ else
+ builder.markInfeasible(false);
+}
+
+/// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor
+/// nodes by processing the 'effects' of a computed goto jump.
+void GRExprEngine::ProcessIndirectGoto(IndirectGotoNodeBuilder& builder) {
+
+ const GRState* state = builder.getState();
+ SVal V = GetSVal(state, builder.getTarget());
+
+ // Three possibilities:
+ //
+ // (1) We know the computed label.
+ // (2) The label is NULL (or some other constant), or Undefined.
+ // (3) We have no clue about the label. Dispatch to all targets.
+ //
+
+ typedef IndirectGotoNodeBuilder::iterator iterator;
+
+ if (isa<loc::GotoLabel>(V)) {
+ LabelStmt* L = cast<loc::GotoLabel>(V).getLabel();
+
+ for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) {
+ if (I.getLabel() == L) {
+ builder.generateNode(I, state);
+ return;
+ }
+ }
+
+ assert (false && "No block with label.");
+ return;
+ }
+
+ if (isa<loc::ConcreteInt>(V) || isa<UndefinedVal>(V)) {
+ // Dispatch to the first target and mark it as a sink.
+ NodeTy* N = builder.generateNode(builder.begin(), state, true);
+ UndefBranches.insert(N);
+ return;
+ }
+
+ // This is really a catch-all. We don't support symbolics yet.
+ // FIXME: Implement dispatch for symbolic pointers.
+
+ for (iterator I=builder.begin(), E=builder.end(); I != E; ++I)
+ builder.generateNode(I, state);
+}
+
+
+void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R,
+ NodeTy* Pred, NodeSet& Dst) {
+
+ assert (Ex == CurrentStmt && getCFG().isBlkExpr(Ex));
+
+ const GRState* state = GetState(Pred);
+ SVal X = GetBlkExprSVal(state, Ex);
+
+ assert (X.isUndef());
+
+ Expr* SE = (Expr*) cast<UndefinedVal>(X).getData();
+
+ assert (SE);
+
+ X = GetBlkExprSVal(state, SE);
+
+ // Make sure that we invalidate the previous binding.
+ MakeNode(Dst, Ex, Pred, StateMgr.BindExpr(state, Ex, X, true, true));
+}
+
+/// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
+/// nodes by processing the 'effects' of a switch statement.
+void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) {
+ typedef SwitchNodeBuilder::iterator iterator;
+ const GRState* state = builder.getState();
+ Expr* CondE = builder.getCondition();
+ SVal CondV = GetSVal(state, CondE);
+
+ if (CondV.isUndef()) {
+ NodeTy* N = builder.generateDefaultCaseNode(state, true);
+ UndefBranches.insert(N);
+ return;
+ }
+
+ const GRState* DefaultSt = state;
+ bool DefaultFeasible = false;
+
+ for (iterator I = builder.begin(), EI = builder.end(); I != EI; ++I) {
+ CaseStmt* Case = cast<CaseStmt>(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.");
+ b = b; // silence unused variable warning
+ assert(V1.Val.getInt().getBitWidth() ==
+ getContext().getTypeSize(CondE->getType()));
+
+ // Get the RHS of the case, if it exists.
+ Expr::EvalResult V2;
+
+ if (Expr* E = Case->getRHS()) {
+ b = E->Evaluate(V2, getContext());
+ assert(b && V2.Val.isInt() && !V2.HasSideEffects
+ && "Case condition must evaluate to an integer constant.");
+ b = b; // silence unused variable warning
+ }
+ else
+ V2 = V1;
+
+ // FIXME: Eventually we should replace the logic below with a range
+ // comparison, rather than concretize the values within the range.
+ // This should be easy once we have "ranges" for NonLVals.
+
+ do {
+ nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt()));
+ SVal Res = EvalBinOp(DefaultSt, BinaryOperator::EQ, CondV, CaseVal,
+ getContext().IntTy);
+
+ // Now "assume" that the case matches.
+ bool isFeasible = false;
+ const GRState* StNew = Assume(state, Res, true, isFeasible);
+
+ if (isFeasible) {
+ builder.generateCaseStmtNode(I, StNew);
+
+ // If CondV evaluates to a constant, then we know that this
+ // is the *only* case that we can take, so stop evaluating the
+ // others.
+ if (isa<nonloc::ConcreteInt>(CondV))
+ return;
+ }
+
+ // Now "assume" that the case doesn't match. Add this state
+ // to the default state (if it is feasible).
+
+ isFeasible = false;
+ StNew = Assume(DefaultSt, Res, false, isFeasible);
+
+ if (isFeasible) {
+ DefaultFeasible = true;
+ DefaultSt = StNew;
+ }
+
+ // Concretize the next value in the range.
+ if (V1.Val.getInt() == V2.Val.getInt())
+ break;
+
+ ++V1.Val.getInt();
+ assert (V1.Val.getInt() <= V2.Val.getInt());
+
+ } while (true);
+ }
+
+ // If we reach here, than we know that the default branch is
+ // possible.
+ if (DefaultFeasible) builder.generateDefaultCaseNode(DefaultSt);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer functions: logical operations ('&&', '||').
+//===----------------------------------------------------------------------===//
+
+void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred,
+ NodeSet& Dst) {
+
+ assert (B->getOpcode() == BinaryOperator::LAnd ||
+ B->getOpcode() == BinaryOperator::LOr);
+
+ assert (B == CurrentStmt && getCFG().isBlkExpr(B));
+
+ const GRState* state = GetState(Pred);
+ SVal X = GetBlkExprSVal(state, B);
+
+ assert (X.isUndef());
+
+ Expr* Ex = (Expr*) cast<UndefinedVal>(X).getData();
+
+ assert (Ex);
+
+ if (Ex == B->getRHS()) {
+
+ X = GetBlkExprSVal(state, Ex);
+
+ // Handle undefined values.
+
+ if (X.isUndef()) {
+ MakeNode(Dst, B, Pred, BindBlkExpr(state, B, X));
+ return;
+ }
+
+ // 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.
+
+ bool isFeasible = false;
+ const GRState* NewState = Assume(state, X, true, isFeasible);
+
+ if (isFeasible)
+ MakeNode(Dst, B, Pred,
+ BindBlkExpr(NewState, B, MakeConstantVal(1U, B)));
+
+ isFeasible = false;
+ NewState = Assume(state, X, false, isFeasible);
+
+ if (isFeasible)
+ MakeNode(Dst, B, Pred,
+ BindBlkExpr(NewState, B, MakeConstantVal(0U, B)));
+ }
+ 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 = MakeConstantVal( B->getOpcode() == BinaryOperator::LAnd ? 0U : 1U, B);
+ MakeNode(Dst, B, Pred, BindBlkExpr(state, B, X));
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer functions: Loads and stores.
+//===----------------------------------------------------------------------===//
+
+void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* Ex, NodeTy* Pred, NodeSet& Dst,
+ bool asLValue) {
+
+ const GRState* state = GetState(Pred);
+
+ const NamedDecl* D = Ex->getDecl();
+
+ if (const VarDecl* VD = dyn_cast<VarDecl>(D)) {
+
+ SVal V = StateMgr.GetLValue(state, VD);
+
+ if (asLValue)
+ MakeNode(Dst, Ex, Pred, BindExpr(state, Ex, V),
+ ProgramPoint::PostLValueKind);
+ else
+ EvalLoad(Dst, Ex, Pred, state, V);
+ return;
+
+ } else if (const EnumConstantDecl* ED = dyn_cast<EnumConstantDecl>(D)) {
+ assert(!asLValue && "EnumConstantDecl does not have lvalue.");
+
+ BasicValueFactory& BasicVals = StateMgr.getBasicVals();
+ SVal V = nonloc::ConcreteInt(BasicVals.getValue(ED->getInitVal()));
+ MakeNode(Dst, Ex, Pred, BindExpr(state, Ex, V));
+ return;
+
+ } else if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) {
+ assert(asLValue);
+ SVal V = ValMgr.getFunctionPointer(FD);
+ MakeNode(Dst, Ex, Pred, BindExpr(state, Ex, V),
+ ProgramPoint::PostLValueKind);
+ return;
+ }
+
+ assert (false &&
+ "ValueDecl support for this ValueDecl not implemented.");
+}
+
+/// VisitArraySubscriptExpr - Transfer function for array accesses
+void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A, NodeTy* Pred,
+ NodeSet& Dst, bool asLValue) {
+
+ Expr* Base = A->getBase()->IgnoreParens();
+ Expr* Idx = A->getIdx()->IgnoreParens();
+ NodeSet Tmp;
+
+ if (Base->getType()->isVectorType()) {
+ // For vector types get its lvalue.
+ // FIXME: This may not be correct. Is the rvalue of a vector its location?
+ // In fact, I think this is just a hack. We need to get the right
+ // semantics.
+ VisitLValue(Base, Pred, Tmp);
+ }
+ else
+ Visit(Base, Pred, Tmp); // Get Base's rvalue, which should be an LocVal.
+
+ for (NodeSet::iterator I1=Tmp.begin(), E1=Tmp.end(); I1!=E1; ++I1) {
+ NodeSet Tmp2;
+ Visit(Idx, *I1, Tmp2); // Evaluate the index.
+
+ for (NodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end(); I2!=E2; ++I2) {
+ const GRState* state = GetState(*I2);
+ SVal V = StateMgr.GetLValue(state, A->getType(),
+ GetSVal(state, Base),
+ GetSVal(state, Idx));
+
+ if (asLValue)
+ MakeNode(Dst, A, *I2, BindExpr(state, A, V),
+ ProgramPoint::PostLValueKind);
+ else
+ EvalLoad(Dst, A, *I2, state, V);
+ }
+ }
+}
+
+/// VisitMemberExpr - Transfer function for member expressions.
+void GRExprEngine::VisitMemberExpr(MemberExpr* M, NodeTy* Pred,
+ NodeSet& Dst, bool asLValue) {
+
+ Expr* Base = M->getBase()->IgnoreParens();
+ NodeSet Tmp;
+
+ if (M->isArrow())
+ Visit(Base, Pred, Tmp); // p->f = ... or ... = p->f
+ else
+ VisitLValue(Base, Pred, Tmp); // x.f = ... or ... = x.f
+
+ FieldDecl *Field = dyn_cast<FieldDecl>(M->getMemberDecl());
+ if (!Field) // FIXME: skipping member expressions for non-fields
+ return;
+
+ for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
+ const GRState* state = GetState(*I);
+ // 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).
+ SVal L = StateMgr.GetLValue(state, GetSVal(state, Base), Field);
+
+ if (asLValue)
+ MakeNode(Dst, M, *I, BindExpr(state, M, L),
+ ProgramPoint::PostLValueKind);
+ else
+ EvalLoad(Dst, M, *I, 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 GRExprEngine::EvalBind(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
+ const GRState* state, SVal location, SVal Val) {
+
+ const GRState* newState = 0;
+
+ 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 = StateMgr.BindLoc(state, cast<Loc>(location), Val);
+ }
+
+ // The next thing to do is check if the GRTransferFuncs 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.
+ GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, Pred, newState, Ex,
+ newState != state);
+
+ getTF().EvalBind(BuilderRef, location, Val);
+}
+
+/// EvalStore - Handle the semantics of a store via an assignment.
+/// @param Dst The node set to store generated state nodes
+/// @param Ex The expression representing the location of the store
+/// @param state The current simulation state
+/// @param location The location to store the value
+/// @param Val The value to be stored
+void GRExprEngine::EvalStore(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
+ const GRState* state, SVal location, SVal Val,
+ const void *tag) {
+
+ assert (Builder && "GRStmtNodeBuilder must be defined.");
+
+ // Evaluate the location (checks for bad dereferences).
+ Pred = EvalLocation(Ex, Pred, state, location, tag);
+
+ if (!Pred)
+ return;
+
+ assert (!location.isUndef());
+ state = GetState(Pred);
+
+ // Proceed with the store.
+ SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
+ SaveAndRestore<const void*> OldTag(Builder->Tag);
+ Builder->PointKind = ProgramPoint::PostStoreKind;
+ Builder->Tag = tag;
+ EvalBind(Dst, Ex, Pred, state, location, Val);
+}
+
+void GRExprEngine::EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
+ const GRState* state, SVal location,
+ const void *tag) {
+
+ // Evaluate the location (checks for bad dereferences).
+ Pred = EvalLocation(Ex, Pred, state, location, tag);
+
+ if (!Pred)
+ return;
+
+ state = GetState(Pred);
+
+ // Proceed with the load.
+ ProgramPoint::Kind K = ProgramPoint::PostLoadKind;
+
+ // FIXME: Currently symbolic analysis "generates" new symbols
+ // for the contents of values. We need a better approach.
+
+ if (location.isUnknown()) {
+ // This is important. We must nuke the old binding.
+ MakeNode(Dst, Ex, Pred, BindExpr(state, Ex, UnknownVal()), K, tag);
+ }
+ else {
+ SVal V = GetSVal(state, cast<Loc>(location), Ex->getType());
+ MakeNode(Dst, Ex, Pred, BindExpr(state, Ex, V), K, tag);
+ }
+}
+
+void GRExprEngine::EvalStore(NodeSet& Dst, Expr* Ex, Expr* StoreE, NodeTy* Pred,
+ const GRState* state, SVal location, SVal Val,
+ const void *tag) {
+
+ NodeSet TmpDst;
+ EvalStore(TmpDst, StoreE, Pred, state, location, Val, tag);
+
+ for (NodeSet::iterator I=TmpDst.begin(), E=TmpDst.end(); I!=E; ++I)
+ MakeNode(Dst, Ex, *I, (*I)->getState(), ProgramPoint::PostStmtKind, tag);
+}
+
+GRExprEngine::NodeTy* GRExprEngine::EvalLocation(Stmt* Ex, NodeTy* Pred,
+ const GRState* state,
+ SVal location,
+ const void *tag) {
+
+ SaveAndRestore<const void*> OldTag(Builder->Tag);
+ Builder->Tag = tag;
+
+ // Check for loads/stores from/to undefined values.
+ if (location.isUndef()) {
+ NodeTy* N =
+ Builder->generateNode(Ex, state, Pred,
+ ProgramPoint::PostUndefLocationCheckFailedKind);
+
+ if (N) {
+ N->markAsSink();
+ UndefDeref.insert(N);
+ }
+
+ return 0;
+ }
+
+ // Check for loads/stores from/to unknown locations. Treat as No-Ops.
+ if (location.isUnknown())
+ return Pred;
+
+ // During a load, one of two possible situations arise:
+ // (1) A crash, because the location (pointer) was NULL.
+ // (2) The location (pointer) is not NULL, and the dereference works.
+ //
+ // We add these assumptions.
+
+ Loc LV = cast<Loc>(location);
+
+ // "Assume" that the pointer is not NULL.
+ bool isFeasibleNotNull = false;
+ const GRState* StNotNull = Assume(state, LV, true, isFeasibleNotNull);
+
+ // "Assume" that the pointer is NULL.
+ bool isFeasibleNull = false;
+ GRStateRef StNull = GRStateRef(Assume(state, LV, false, isFeasibleNull),
+ getStateManager());
+
+ if (isFeasibleNull) {
+
+ // Use the Generic Data Map to mark in the state what lval was null.
+ const SVal* PersistentLV = getBasicVals().getPersistentSVal(LV);
+ StNull = StNull.set<GRState::NullDerefTag>(PersistentLV);
+
+ // We don't use "MakeNode" here because the node will be a sink
+ // and we have no intention of processing it later.
+ NodeTy* NullNode =
+ Builder->generateNode(Ex, StNull, Pred,
+ ProgramPoint::PostNullCheckFailedKind);
+
+ if (NullNode) {
+
+ NullNode->markAsSink();
+
+ if (isFeasibleNotNull) ImplicitNullDeref.insert(NullNode);
+ else ExplicitNullDeref.insert(NullNode);
+ }
+ }
+
+ if (!isFeasibleNotNull)
+ return 0;
+
+ // Check for out-of-bound array access.
+ if (isa<loc::MemRegionVal>(LV)) {
+ const MemRegion* R = cast<loc::MemRegionVal>(LV).getRegion();
+ if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) {
+ // Get the index of the accessed element.
+ SVal Idx = ER->getIndex();
+ // Get the extent of the array.
+ SVal NumElements = getStoreManager().getSizeInElements(StNotNull,
+ ER->getSuperRegion());
+
+ bool isFeasibleInBound = false;
+ const GRState* StInBound = AssumeInBound(StNotNull, Idx, NumElements,
+ true, isFeasibleInBound);
+
+ bool isFeasibleOutBound = false;
+ const GRState* StOutBound = AssumeInBound(StNotNull, Idx, NumElements,
+ false, isFeasibleOutBound);
+
+ if (isFeasibleOutBound) {
+ // Report warning. Make sink node manually.
+ NodeTy* OOBNode =
+ Builder->generateNode(Ex, StOutBound, Pred,
+ ProgramPoint::PostOutOfBoundsCheckFailedKind);
+
+ if (OOBNode) {
+ OOBNode->markAsSink();
+
+ if (isFeasibleInBound)
+ ImplicitOOBMemAccesses.insert(OOBNode);
+ else
+ ExplicitOOBMemAccesses.insert(OOBNode);
+ }
+ }
+
+ if (!isFeasibleInBound)
+ return 0;
+
+ StNotNull = StInBound;
+ }
+ }
+
+ // Generate a new node indicating the checks succeed.
+ return Builder->generateNode(Ex, StNotNull, Pred,
+ ProgramPoint::PostLocationChecksSucceedKind);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function: OSAtomics.
+//
+// FIXME: Eventually refactor into a more "plugin" infrastructure.
+//===----------------------------------------------------------------------===//
+
+// Mac OS X:
+// http://developer.apple.com/documentation/Darwin/Reference/Manpages/man3
+// atomic.3.html
+//
+static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder<GRState>& Builder,
+ CallExpr* CE, SVal L,
+ ExplodedNode<GRState>* Pred) {
+
+ // Not enough arguments to match OSAtomicCompareAndSwap?
+ if (CE->getNumArgs() != 3)
+ return false;
+
+ ASTContext &C = Engine.getContext();
+ Expr *oldValueExpr = CE->getArg(0);
+ QualType oldValueType = C.getCanonicalType(oldValueExpr->getType());
+
+ Expr *newValueExpr = CE->getArg(1);
+ QualType newValueType = C.getCanonicalType(newValueExpr->getType());
+
+ // Do the types of 'oldValue' and 'newValue' match?
+ if (oldValueType != newValueType)
+ return false;
+
+ Expr *theValueExpr = CE->getArg(2);
+ const PointerType *theValueType = theValueExpr->getType()->getAsPointerType();
+
+ // theValueType not a pointer?
+ if (!theValueType)
+ return false;
+
+ QualType theValueTypePointee =
+ C.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
+
+ // The pointee must match newValueType and oldValueType.
+ 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;
+
+ // Load 'theValue'.
+ GRStateManager &StateMgr = Engine.getStateManager();
+ const GRState *state = Pred->getState();
+ ExplodedNodeSet<GRState> Tmp;
+ SVal location = StateMgr.GetSVal(state, theValueExpr);
+ Engine.EvalLoad(Tmp, theValueExpr, Pred, state, location, OSAtomicLoadTag);
+
+ for (ExplodedNodeSet<GRState>::iterator I = Tmp.begin(), E = Tmp.end();
+ I != E; ++I) {
+
+ ExplodedNode<GRState> *N = *I;
+ const GRState *stateLoad = N->getState();
+ SVal theValueVal = StateMgr.GetSVal(stateLoad, theValueExpr);
+ SVal oldValueVal = StateMgr.GetSVal(stateLoad, oldValueExpr);
+
+ // Perform the comparison.
+ SVal Cmp = Engine.EvalBinOp(stateLoad,
+ BinaryOperator::EQ, theValueVal, oldValueVal,
+ Engine.getContext().IntTy);
+ bool isFeasible = false;
+ const GRState *stateEqual = StateMgr.Assume(stateLoad, Cmp, true,
+ isFeasible);
+
+ // Were they equal?
+ if (isFeasible) {
+ // Perform the store.
+ ExplodedNodeSet<GRState> TmpStore;
+ Engine.EvalStore(TmpStore, theValueExpr, N, stateEqual, location,
+ StateMgr.GetSVal(stateEqual, newValueExpr),
+ OSAtomicStoreTag);
+
+ // Now bind the result of the comparison.
+ for (ExplodedNodeSet<GRState>::iterator I2 = TmpStore.begin(),
+ E2 = TmpStore.end(); I2 != E2; ++I2) {
+ ExplodedNode<GRState> *predNew = *I2;
+ const GRState *stateNew = predNew->getState();
+ SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType());
+ Engine.MakeNode(Dst, CE, predNew, Engine.BindExpr(stateNew, CE, Res));
+ }
+ }
+
+ // Were they not equal?
+ isFeasible = false;
+ const GRState *stateNotEqual = StateMgr.Assume(stateLoad, Cmp, false,
+ isFeasible);
+
+ if (isFeasible) {
+ SVal Res = Engine.getValueManager().makeTruthVal(false, CE->getType());
+ Engine.MakeNode(Dst, CE, N, Engine.BindExpr(stateNotEqual, CE, Res));
+ }
+ }
+
+ return true;
+}
+
+static bool EvalOSAtomic(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder<GRState>& Builder,
+ CallExpr* CE, SVal L,
+ ExplodedNode<GRState>* Pred) {
+ const FunctionDecl* FD = L.getAsFunctionDecl();
+ if (!FD)
+ return false;
+
+ const char *FName = FD->getNameAsCString();
+
+ // Check for compare and swap.
+ if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 ||
+ strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0)
+ return EvalOSAtomicCompareAndSwap(Dst, Engine, Builder, CE, L, Pred);
+
+ // FIXME: Other atomics.
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function: Function calls.
+//===----------------------------------------------------------------------===//
+
+void GRExprEngine::EvalCall(NodeSet& Dst, CallExpr* CE, SVal L, NodeTy* Pred) {
+ assert (Builder && "GRStmtNodeBuilder must be defined.");
+
+ // FIXME: Allow us to chain together transfer functions.
+ if (EvalOSAtomic(Dst, *this, *Builder, CE, L, Pred))
+ return;
+
+ getTF().EvalCall(Dst, *this, *Builder, CE, L, Pred);
+}
+
+void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred,
+ CallExpr::arg_iterator AI,
+ CallExpr::arg_iterator AE,
+ NodeSet& 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->getAsPointerType())
+ Proto = FnTypePtr->getPointeeType()->getAsFunctionProtoType();
+
+ VisitCallRec(CE, Pred, AI, AE, Dst, Proto, /*ParamIdx=*/0);
+}
+
+void GRExprEngine::VisitCallRec(CallExpr* CE, NodeTy* Pred,
+ CallExpr::arg_iterator AI,
+ CallExpr::arg_iterator AE,
+ NodeSet& Dst, const FunctionProtoType *Proto,
+ unsigned ParamIdx) {
+
+ // Process the arguments.
+ if (AI != AE) {
+ // If the call argument is being bound to a reference parameter,
+ // visit it as an lvalue, not an rvalue.
+ bool VisitAsLvalue = false;
+ if (Proto && ParamIdx < Proto->getNumArgs())
+ VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();
+
+ NodeSet DstTmp;
+ if (VisitAsLvalue)
+ VisitLValue(*AI, Pred, DstTmp);
+ else
+ Visit(*AI, Pred, DstTmp);
+ ++AI;
+
+ for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE; ++DI)
+ VisitCallRec(CE, *DI, AI, AE, Dst, Proto, ParamIdx + 1);
+
+ return;
+ }
+
+ // If we reach here we have processed all of the arguments. Evaluate
+ // the callee expression.
+
+ NodeSet DstTmp;
+ Expr* Callee = CE->getCallee()->IgnoreParens();
+
+ Visit(Callee, Pred, DstTmp);
+
+ // Finally, evaluate the function call.
+ for (NodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI!=DE; ++DI) {
+
+ const GRState* state = GetState(*DI);
+ SVal L = GetSVal(state, Callee);
+
+ // FIXME: Add support for symbolic function calls (calls involving
+ // function pointer values that are symbolic).
+
+ // Check for undefined control-flow or calls to NULL.
+
+ if (L.isUndef() || isa<loc::ConcreteInt>(L)) {
+ NodeTy* N = Builder->generateNode(CE, state, *DI);
+
+ if (N) {
+ N->markAsSink();
+ BadCalls.insert(N);
+ }
+
+ continue;
+ }
+
+ // Check for the "noreturn" attribute.
+
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+ const FunctionDecl* FD = L.getAsFunctionDecl();
+ if (FD) {
+ if (FD->getAttr<NoReturnAttr>() || FD->getAttr<AnalyzerNoReturnAttr>())
+ Builder->BuildSinks = true;
+ else {
+ // HACK: Some functions are not marked noreturn, and don't return.
+ // Here are a few hardwired ones. If this takes too long, we can
+ // potentially cache these results.
+ const char* s = FD->getIdentifier()->getName();
+ unsigned n = strlen(s);
+
+ switch (n) {
+ default:
+ break;
+
+ case 4:
+ if (!memcmp(s, "exit", 4)) Builder->BuildSinks = true;
+ break;
+
+ case 5:
+ if (!memcmp(s, "panic", 5)) Builder->BuildSinks = true;
+ else if (!memcmp(s, "error", 5)) {
+ if (CE->getNumArgs() > 0) {
+ SVal X = GetSVal(state, *CE->arg_begin());
+ // FIXME: use Assume to inspect the possible symbolic value of
+ // X. Also check the specific signature of error().
+ nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&X);
+ if (CI && CI->getValue() != 0)
+ Builder->BuildSinks = true;
+ }
+ }
+ break;
+
+ case 6:
+ if (!memcmp(s, "Assert", 6)) {
+ Builder->BuildSinks = true;
+ break;
+ }
+
+ // FIXME: This is just a wrapper around throwing an exception.
+ // Eventually inter-procedural analysis should handle this easily.
+ if (!memcmp(s, "ziperr", 6)) Builder->BuildSinks = true;
+
+ break;
+
+ case 7:
+ if (!memcmp(s, "assfail", 7)) Builder->BuildSinks = true;
+ break;
+
+ case 8:
+ if (!memcmp(s ,"db_error", 8) ||
+ !memcmp(s, "__assert", 8))
+ Builder->BuildSinks = true;
+ break;
+
+ case 12:
+ if (!memcmp(s, "__assert_rtn", 12)) Builder->BuildSinks = true;
+ break;
+
+ case 13:
+ if (!memcmp(s, "__assert_fail", 13)) Builder->BuildSinks = true;
+ break;
+
+ case 14:
+ if (!memcmp(s, "dtrace_assfail", 14) ||
+ !memcmp(s, "yy_fatal_error", 14))
+ Builder->BuildSinks = true;
+ break;
+
+ case 26:
+ if (!memcmp(s, "_XCAssertionFailureHandler", 26) ||
+ !memcmp(s, "_DTAssertionFailureHandler", 26) ||
+ !memcmp(s, "_TSAssertionFailureHandler", 26))
+ Builder->BuildSinks = true;
+
+ break;
+ }
+
+ }
+ }
+
+ // Evaluate the call.
+
+ if (FD) {
+
+ if (unsigned id = FD->getBuiltinID(getContext()))
+ switch (id) {
+ case Builtin::BI__builtin_expect: {
+ // For __builtin_expect, just return the value of the subexpression.
+ assert (CE->arg_begin() != CE->arg_end());
+ SVal X = GetSVal(state, *(CE->arg_begin()));
+ MakeNode(Dst, CE, *DI, BindExpr(state, CE, X));
+ continue;
+ }
+
+ case Builtin::BI__builtin_alloca: {
+ // FIXME: Refactor into StoreManager itself?
+ MemRegionManager& RM = getStateManager().getRegionManager();
+ const MemRegion* R =
+ RM.getAllocaRegion(CE, Builder->getCurrentBlockCount());
+
+ // Set the extent of the region in bytes. This enables us to use the
+ // SVal of the argument directly. If we save the extent in bits, we
+ // cannot represent values like symbol*8.
+ SVal Extent = GetSVal(state, *(CE->arg_begin()));
+ state = getStoreManager().setExtent(state, R, Extent);
+
+ MakeNode(Dst, CE, *DI, BindExpr(state, CE, loc::MemRegionVal(R)));
+ continue;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ // Check any arguments passed-by-value against being undefined.
+
+ bool badArg = false;
+
+ for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
+ I != E; ++I) {
+
+ if (GetSVal(GetState(*DI), *I).isUndef()) {
+ NodeTy* N = Builder->generateNode(CE, GetState(*DI), *DI);
+
+ if (N) {
+ N->markAsSink();
+ UndefArgs[N] = *I;
+ }
+
+ badArg = true;
+ break;
+ }
+ }
+
+ if (badArg)
+ continue;
+
+ // Dispatch to the plug-in transfer function.
+
+ unsigned size = Dst.size();
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
+ EvalCall(Dst, CE, L, *DI);
+
+ // 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() == size &&
+ !Builder->HasGeneratedNode)
+ MakeNode(Dst, CE, *DI, state);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function: Objective-C ivar references.
+//===----------------------------------------------------------------------===//
+
+static std::pair<const void*,const void*> EagerlyAssumeTag
+ = std::pair<const void*,const void*>(&EagerlyAssumeTag,0);
+
+void GRExprEngine::EvalEagerlyAssume(NodeSet &Dst, NodeSet &Src, Expr *Ex) {
+ for (NodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) {
+ NodeTy *Pred = *I;
+
+ // Test if the previous node was as the same expression. This can happen
+ // when the expression fails to evaluate to anything meaningful and
+ // (as an optimization) we don't generate a node.
+ ProgramPoint P = Pred->getLocation();
+ if (!isa<PostStmt>(P) || cast<PostStmt>(P).getStmt() != Ex) {
+ Dst.Add(Pred);
+ continue;
+ }
+
+ const GRState* state = Pred->getState();
+ SVal V = GetSVal(state, Ex);
+ if (isa<nonloc::SymExprVal>(V)) {
+ // First assume that the condition is true.
+ bool isFeasible = false;
+ const GRState *stateTrue = Assume(state, V, true, isFeasible);
+ if (isFeasible) {
+ stateTrue = BindExpr(stateTrue, Ex, MakeConstantVal(1U, Ex));
+ Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag),
+ stateTrue, Pred));
+ }
+
+ // Next, assume that the condition is false.
+ isFeasible = false;
+ const GRState *stateFalse = Assume(state, V, false, isFeasible);
+ if (isFeasible) {
+ stateFalse = BindExpr(stateFalse, Ex, MakeConstantVal(0U, Ex));
+ Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag),
+ stateFalse, Pred));
+ }
+ }
+ else
+ Dst.Add(Pred);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function: Objective-C ivar references.
+//===----------------------------------------------------------------------===//
+
+void GRExprEngine::VisitObjCIvarRefExpr(ObjCIvarRefExpr* Ex,
+ NodeTy* Pred, NodeSet& Dst,
+ bool asLValue) {
+
+ Expr* Base = cast<Expr>(Ex->getBase());
+ NodeSet Tmp;
+ Visit(Base, Pred, Tmp);
+
+ for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ const GRState* state = GetState(*I);
+ SVal BaseVal = GetSVal(state, Base);
+ SVal location = StateMgr.GetLValue(state, Ex->getDecl(), BaseVal);
+
+ if (asLValue)
+ MakeNode(Dst, Ex, *I, BindExpr(state, Ex, location));
+ else
+ EvalLoad(Dst, Ex, *I, state, location);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function: Objective-C fast enumeration 'for' statements.
+//===----------------------------------------------------------------------===//
+
+void GRExprEngine::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S,
+ NodeTy* Pred, NodeSet& 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.
+
+ Stmt* elem = S->getElement();
+ SVal ElementV;
+
+ if (DeclStmt* DS = dyn_cast<DeclStmt>(elem)) {
+ VarDecl* ElemD = cast<VarDecl>(DS->getSingleDecl());
+ assert (ElemD->getInit() == 0);
+ ElementV = getStateManager().GetLValue(GetState(Pred), ElemD);
+ VisitObjCForCollectionStmtAux(S, Pred, Dst, ElementV);
+ return;
+ }
+
+ NodeSet Tmp;
+ VisitLValue(cast<Expr>(elem), Pred, Tmp);
+
+ for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
+ const GRState* state = GetState(*I);
+ VisitObjCForCollectionStmtAux(S, *I, Dst, GetSVal(state, elem));
+ }
+}
+
+void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S,
+ NodeTy* Pred, NodeSet& Dst,
+ SVal ElementV) {
+
+
+
+ // Get the current state. Use 'EvalLocation' to determine if it is a null
+ // pointer, etc.
+ Stmt* elem = S->getElement();
+
+ Pred = EvalLocation(elem, Pred, GetState(Pred), ElementV);
+ if (!Pred)
+ return;
+
+ GRStateRef state = GRStateRef(GetState(Pred), getStateManager());
+
+ // Handle the case where the container still has elements.
+ QualType IntTy = getContext().IntTy;
+ SVal TrueV = NonLoc::MakeVal(getBasicVals(), 1, IntTy);
+ GRStateRef hasElems = state.BindExpr(S, TrueV);
+
+ // Handle the case where the container has no elements.
+ SVal FalseV = NonLoc::MakeVal(getBasicVals(), 0, IntTy);
+ GRStateRef 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(getContext());
+ assert (Loc::IsLocType(T));
+ unsigned Count = Builder->getCurrentBlockCount();
+ SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
+ SVal V = Loc::MakeVal(getStoreManager().getRegionManager().getSymbolicRegion(Sym));
+ hasElems = hasElems.BindLoc(ElementV, V);
+
+ // Bind the location to 'nil' on the false branch.
+ SVal nilV = loc::ConcreteInt(getBasicVals().getValue(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.
+//===----------------------------------------------------------------------===//
+
+void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred,
+ NodeSet& Dst){
+
+ VisitObjCMessageExprArgHelper(ME, ME->arg_begin(), ME->arg_end(),
+ Pred, Dst);
+}
+
+void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
+ ObjCMessageExpr::arg_iterator AI,
+ ObjCMessageExpr::arg_iterator AE,
+ NodeTy* Pred, NodeSet& Dst) {
+ if (AI == AE) {
+
+ // Process the receiver.
+
+ if (Expr* Receiver = ME->getReceiver()) {
+ NodeSet Tmp;
+ Visit(Receiver, Pred, Tmp);
+
+ for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
+ VisitObjCMessageExprDispatchHelper(ME, *NI, Dst);
+
+ return;
+ }
+
+ VisitObjCMessageExprDispatchHelper(ME, Pred, Dst);
+ return;
+ }
+
+ NodeSet Tmp;
+ Visit(*AI, Pred, Tmp);
+
+ ++AI;
+
+ for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
+ VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst);
+}
+
+void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
+ NodeTy* Pred,
+ NodeSet& Dst) {
+
+ // FIXME: More logic for the processing the method call.
+
+ const GRState* state = GetState(Pred);
+ bool RaisesException = false;
+
+
+ if (Expr* Receiver = ME->getReceiver()) {
+
+ SVal L = GetSVal(state, Receiver);
+
+ // Check for undefined control-flow.
+ if (L.isUndef()) {
+ NodeTy* N = Builder->generateNode(ME, state, Pred);
+
+ if (N) {
+ N->markAsSink();
+ UndefReceivers.insert(N);
+ }
+
+ return;
+ }
+
+ // "Assume" that the receiver is not NULL.
+ bool isFeasibleNotNull = false;
+ const GRState *StNotNull = Assume(state, L, true, isFeasibleNotNull);
+
+ // "Assume" that the receiver is NULL.
+ bool isFeasibleNull = false;
+ const GRState *StNull = Assume(state, L, false, isFeasibleNull);
+
+ if (isFeasibleNull) {
+ QualType RetTy = ME->getType();
+
+ // Check if the receiver was nil and the return value a struct.
+ if(RetTy->isRecordType()) {
+ if (BR.getParentMap().isConsumedExpr(ME)) {
+ // The [0 ...] expressions will return garbage. Flag either an
+ // explicit or implicit error. Because of the structure of this
+ // function we currently do not bifurfacte the state graph at
+ // this point.
+ // FIXME: We should bifurcate and fill the returned struct with
+ // garbage.
+ if (NodeTy* N = Builder->generateNode(ME, StNull, Pred)) {
+ N->markAsSink();
+ if (isFeasibleNotNull)
+ NilReceiverStructRetImplicit.insert(N);
+ else
+ NilReceiverStructRetExplicit.insert(N);
+ }
+ }
+ }
+ else {
+ ASTContext& Ctx = getContext();
+ if (RetTy != Ctx.VoidTy) {
+ if (BR.getParentMap().isConsumedExpr(ME)) {
+ // sizeof(void *)
+ const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
+ // sizeof(return type)
+ const uint64_t returnTypeSize = Ctx.getTypeSize(ME->getType());
+
+ if(voidPtrSize < returnTypeSize) {
+ if (NodeTy* N = Builder->generateNode(ME, StNull, Pred)) {
+ N->markAsSink();
+ if(isFeasibleNotNull)
+ NilReceiverLargerThanVoidPtrRetImplicit.insert(N);
+ else
+ NilReceiverLargerThanVoidPtrRetExplicit.insert(N);
+ }
+ }
+ else if (!isFeasibleNotNull) {
+ // Handle the safe cases where the return value is 0 if the
+ // receiver is nil.
+ //
+ // FIXME: For now take the conservative approach that we only
+ // return null values if we *know* that the receiver is nil.
+ // This is because we can have surprises like:
+ //
+ // ... = [[NSScreens screens] objectAtIndex:0];
+ //
+ // What can happen is that [... screens] could return nil, but
+ // it most likely isn't nil. We should assume the semantics
+ // of this case unless we have *a lot* more knowledge.
+ //
+ SVal V = ValMgr.makeZeroVal(ME->getType());
+ MakeNode(Dst, ME, Pred, BindExpr(StNull, ME, V));
+ return;
+ }
+ }
+ }
+ }
+ // We have handled the cases where the receiver is nil. The remainder
+ // of this method should assume that the receiver is not nil.
+ if (!StNotNull)
+ return;
+
+ state = StNotNull;
+ }
+
+ // Check if the "raise" message was sent.
+ if (ME->getSelector() == RaiseSel)
+ RaisesException = true;
+ }
+ else {
+
+ IdentifierInfo* ClsName = ME->getClassName();
+ Selector S = ME->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 for any arguments that are uninitialized/undefined.
+
+ for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end();
+ I != E; ++I) {
+
+ if (GetSVal(state, *I).isUndef()) {
+
+ // Generate an error node for passing an uninitialized/undefined value
+ // as an argument to a message expression. This node is a sink.
+ NodeTy* N = Builder->generateNode(ME, state, Pred);
+
+ if (N) {
+ N->markAsSink();
+ MsgExprUndefArgs[N] = *I;
+ }
+
+ return;
+ }
+ }
+
+ // Check if we raise an exception. For now treat these as sinks. Eventually
+ // we will want to handle exceptions properly.
+
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+
+ if (RaisesException)
+ Builder->BuildSinks = true;
+
+ // Dispatch to plug-in transfer function.
+
+ unsigned size = Dst.size();
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
+
+ EvalObjCMessageExpr(Dst, ME, 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() == size && !Builder->HasGeneratedNode)
+ MakeNode(Dst, ME, Pred, state);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer functions: Miscellaneous statements.
+//===----------------------------------------------------------------------===//
+
+void GRExprEngine::VisitCastPointerToInteger(SVal V, const GRState* state,
+ QualType PtrTy,
+ Expr* CastE, NodeTy* Pred,
+ NodeSet& Dst) {
+ if (!V.isUnknownOrUndef()) {
+ // FIXME: Determine if the number of bits of the target type is
+ // equal or exceeds the number of bits to store the pointer value.
+ // If not, flag an error.
+ MakeNode(Dst, CastE, Pred, BindExpr(state, CastE, EvalCast(cast<Loc>(V),
+ CastE->getType())));
+ }
+ else
+ MakeNode(Dst, CastE, Pred, BindExpr(state, CastE, V));
+}
+
+
+void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){
+ NodeSet S1;
+ QualType T = CastE->getType();
+ QualType ExTy = Ex->getType();
+
+ if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
+ T = ExCast->getTypeAsWritten();
+
+ if (ExTy->isArrayType() || ExTy->isFunctionType() || T->isReferenceType())
+ VisitLValue(Ex, Pred, S1);
+ else
+ Visit(Ex, Pred, S1);
+
+ // Check for casting to "void".
+ if (T->isVoidType()) {
+ for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1)
+ Dst.Add(*I1);
+
+ return;
+ }
+
+ // FIXME: The rest of this should probably just go into EvalCall, and
+ // let the transfer function object be responsible for constructing
+ // nodes.
+
+ for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) {
+ NodeTy* N = *I1;
+ const GRState* state = GetState(N);
+ SVal V = GetSVal(state, Ex);
+ ASTContext& C = getContext();
+
+ // Unknown?
+ if (V.isUnknown()) {
+ Dst.Add(N);
+ continue;
+ }
+
+ // Undefined?
+ if (V.isUndef())
+ goto PassThrough;
+
+ // For const casts, just propagate the value.
+ if (C.getCanonicalType(T).getUnqualifiedType() ==
+ C.getCanonicalType(ExTy).getUnqualifiedType())
+ goto PassThrough;
+
+ // Check for casts from pointers to integers.
+ if (T->isIntegerType() && Loc::IsLocType(ExTy)) {
+ VisitCastPointerToInteger(V, state, ExTy, CastE, N, Dst);
+ continue;
+ }
+
+ // Check for casts from integers to pointers.
+ if (Loc::IsLocType(T) && ExTy->isIntegerType()) {
+ if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&V)) {
+ // Just unpackage the lval and return it.
+ V = LV->getLoc();
+ MakeNode(Dst, CastE, N, BindExpr(state, CastE, V));
+ continue;
+ }
+
+ goto DispatchCast;
+ }
+
+ // Just pass through function and block pointers.
+ if (ExTy->isBlockPointerType() || ExTy->isFunctionPointerType()) {
+ assert(Loc::IsLocType(T));
+ goto PassThrough;
+ }
+
+ // Check for casts from array type to another type.
+ if (ExTy->isArrayType()) {
+ // We will always decay to a pointer.
+ V = StateMgr.ArrayToPointer(cast<Loc>(V));
+
+ // Are we casting from an array to a pointer? If so just pass on
+ // the decayed value.
+ if (T->isPointerType())
+ goto PassThrough;
+
+ // Are we casting from an array to an integer? If so, cast the decayed
+ // pointer value to an integer.
+ assert(T->isIntegerType());
+ QualType ElemTy = cast<ArrayType>(ExTy)->getElementType();
+ QualType PointerTy = getContext().getPointerType(ElemTy);
+ VisitCastPointerToInteger(V, state, PointerTy, CastE, N, Dst);
+ continue;
+ }
+
+ // Check for casts from a region to a specific type.
+ if (loc::MemRegionVal *RV = dyn_cast<loc::MemRegionVal>(&V)) {
+ // FIXME: For TypedViewRegions, we should handle the case where the
+ // underlying symbolic pointer is a function pointer or
+ // block pointer.
+
+ // FIXME: We should handle the case where we strip off view layers to get
+ // to a desugared type.
+
+ assert(Loc::IsLocType(T));
+ // We get a symbolic function pointer for a dereference of a function
+ // pointer, but it is of function type. Example:
+
+ // struct FPRec {
+ // void (*my_func)(int * x);
+ // };
+ //
+ // int bar(int x);
+ //
+ // int f1_a(struct FPRec* foo) {
+ // int x;
+ // (*foo->my_func)(&x);
+ // return bar(x)+1; // no-warning
+ // }
+
+ assert(Loc::IsLocType(ExTy) || ExTy->isFunctionType());
+
+ const MemRegion* R = RV->getRegion();
+ StoreManager& StoreMgr = getStoreManager();
+
+ // Delegate to store manager to get the result of casting a region
+ // to a different type.
+ const StoreManager::CastResult& Res = StoreMgr.CastRegion(state, R, T);
+
+ // Inspect the result. If the MemRegion* returned is NULL, this
+ // expression evaluates to UnknownVal.
+ R = Res.getRegion();
+ if (R) { V = loc::MemRegionVal(R); } else { V = UnknownVal(); }
+
+ // Generate the new node in the ExplodedGraph.
+ MakeNode(Dst, CastE, N, BindExpr(Res.getState(), CastE, V));
+ continue;
+ }
+ // All other cases.
+ DispatchCast: {
+ MakeNode(Dst, CastE, N, BindExpr(state, CastE,
+ EvalCast(V, CastE->getType())));
+ continue;
+ }
+
+ PassThrough: {
+ MakeNode(Dst, CastE, N, BindExpr(state, CastE, V));
+ }
+ }
+}
+
+void GRExprEngine::VisitCompoundLiteralExpr(CompoundLiteralExpr* CL,
+ NodeTy* Pred, NodeSet& Dst,
+ bool asLValue) {
+ InitListExpr* ILE = cast<InitListExpr>(CL->getInitializer()->IgnoreParens());
+ NodeSet Tmp;
+ Visit(ILE, Pred, Tmp);
+
+ for (NodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) {
+ const GRState* state = GetState(*I);
+ SVal ILV = GetSVal(state, ILE);
+ state = StateMgr.BindCompoundLiteral(state, CL, ILV);
+
+ if (asLValue)
+ MakeNode(Dst, CL, *I, BindExpr(state, CL, StateMgr.GetLValue(state, CL)));
+ else
+ MakeNode(Dst, CL, *I, BindExpr(state, CL, ILV));
+ }
+}
+
+void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) {
+
+ // The CFG has one DeclStmt per Decl.
+ Decl* D = *DS->decl_begin();
+
+ if (!D || !isa<VarDecl>(D))
+ return;
+
+ const VarDecl* VD = dyn_cast<VarDecl>(D);
+ Expr* InitEx = const_cast<Expr*>(VD->getInit());
+
+ // FIXME: static variables may have an initializer, but the second
+ // time a function is called those values may not be current.
+ NodeSet Tmp;
+
+ if (InitEx)
+ Visit(InitEx, Pred, Tmp);
+
+ if (Tmp.empty())
+ Tmp.Add(Pred);
+
+ for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ const GRState* state = GetState(*I);
+ unsigned Count = Builder->getCurrentBlockCount();
+
+ // Check if 'VD' is a VLA and if so check if has a non-zero size.
+ QualType T = getContext().getCanonicalType(VD->getType());
+ if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
+ // FIXME: Handle multi-dimensional VLAs.
+
+ Expr* SE = VLA->getSizeExpr();
+ SVal Size = GetSVal(state, SE);
+
+ if (Size.isUndef()) {
+ if (NodeTy* N = Builder->generateNode(DS, state, Pred)) {
+ N->markAsSink();
+ ExplicitBadSizedVLA.insert(N);
+ }
+ continue;
+ }
+
+ bool isFeasibleZero = false;
+ const GRState* ZeroSt = Assume(state, Size, false, isFeasibleZero);
+
+ bool isFeasibleNotZero = false;
+ state = Assume(state, Size, true, isFeasibleNotZero);
+
+ if (isFeasibleZero) {
+ if (NodeTy* N = Builder->generateNode(DS, ZeroSt, Pred)) {
+ N->markAsSink();
+ if (isFeasibleNotZero) ImplicitBadSizedVLA.insert(N);
+ else ExplicitBadSizedVLA.insert(N);
+ }
+ }
+
+ if (!isFeasibleNotZero)
+ continue;
+ }
+
+ // Decls without InitExpr are not initialized explicitly.
+ if (InitEx) {
+ SVal InitVal = GetSVal(state, InitEx);
+ QualType T = VD->getType();
+
+ // Recover some path-sensitivity if a scalar value evaluated to
+ // UnknownVal.
+ if (InitVal.isUnknown() ||
+ !getConstraintManager().canReasonAbout(InitVal)) {
+ InitVal = ValMgr.getConjuredSymbolVal(InitEx, Count);
+ }
+
+ state = StateMgr.BindDecl(state, VD, InitVal);
+
+ // The next thing to do is check if the GRTransferFuncs 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.
+ GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, state, DS,true);
+ getTF().EvalBind(BuilderRef, loc::MemRegionVal(StateMgr.getRegion(VD)),
+ InitVal);
+ }
+ else {
+ state = StateMgr.BindDeclWithNoInit(state, VD);
+ 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 VISIBILITY_HIDDEN InitListWLItem {
+public:
+ llvm::ImmutableList<SVal> Vals;
+ GRExprEngine::NodeTy* N;
+ InitListExpr::reverse_iterator Itr;
+
+ InitListWLItem(GRExprEngine::NodeTy* n, llvm::ImmutableList<SVal> vals,
+ InitListExpr::reverse_iterator itr)
+ : Vals(vals), N(n), Itr(itr) {}
+};
+}
+
+
+void GRExprEngine::VisitInitListExpr(InitListExpr* E, NodeTy* Pred,
+ NodeSet& Dst) {
+
+ const GRState* state = GetState(Pred);
+ QualType T = getContext().getCanonicalType(E->getType());
+ unsigned NumInitElements = E->getNumInits();
+
+ if (T->isArrayType() || T->isStructureType()) {
+
+ 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 = NonLoc::MakeCompoundVal(T, StartVals, getBasicVals());
+ MakeNode(Dst, E, Pred, BindExpr(state, 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::reverse_iterator ItrEnd = E->rend();
+
+ // Process the worklist until it is empty.
+ while (!WorkList.empty()) {
+ InitListWLItem X = WorkList.back();
+ WorkList.pop_back();
+
+ NodeSet Tmp;
+ Visit(*X.Itr, X.N, Tmp);
+
+ InitListExpr::reverse_iterator NewItr = X.Itr + 1;
+
+ for (NodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
+ // Get the last initializer value.
+ state = GetState(*NI);
+ SVal InitV = GetSVal(state, 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 = NonLoc::MakeCompoundVal(T, NewVals, getBasicVals());
+
+ // Make final state and node.
+ MakeNode(Dst, E, *NI, BindExpr(state, E, V));
+ }
+ else {
+ // Still some initializer values to go. Push them onto the worklist.
+ WorkList.push_back(InitListWLItem(*NI, NewVals, NewItr));
+ }
+ }
+ }
+
+ return;
+ }
+
+ if (T->isUnionType() || T->isVectorType()) {
+ // FIXME: to be implemented.
+ // Note: That vectors can return true for T->isIntegerType()
+ MakeNode(Dst, E, Pred, state);
+ return;
+ }
+
+ if (Loc::IsLocType(T) || T->isIntegerType()) {
+ assert (E->getNumInits() == 1);
+ NodeSet Tmp;
+ Expr* Init = E->getInit(0);
+ Visit(Init, Pred, Tmp);
+ for (NodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I != EI; ++I) {
+ state = GetState(*I);
+ MakeNode(Dst, E, *I, BindExpr(state, E, GetSVal(state, Init)));
+ }
+ return;
+ }
+
+
+ printf("InitListExpr type = %s\n", T.getAsString().c_str());
+ assert(0 && "unprocessed InitListExpr type");
+}
+
+/// VisitSizeOfAlignOfExpr - Transfer function for sizeof(type).
+void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
+ NodeTy* Pred,
+ NodeSet& Dst) {
+ QualType T = Ex->getTypeOfArgument();
+ uint64_t amt;
+
+ if (Ex->isSizeOf()) {
+ if (T == getContext().VoidTy) {
+ // sizeof(void) == 1 byte.
+ amt = 1;
+ }
+ else if (!T.getTypePtr()->isConstantSizeType()) {
+ // FIXME: Add support for VLAs.
+ return;
+ }
+ else if (T->isObjCInterfaceType()) {
+ // Some code tries to take the sizeof an ObjCInterfaceType, relying that
+ // the compiler has laid out its representation. Just report Unknown
+ // for these.
+ return;
+ }
+ else {
+ // All other cases.
+ amt = getContext().getTypeSize(T) / 8;
+ }
+ }
+ else // Get alignment of the type.
+ amt = getContext().getTypeAlign(T) / 8;
+
+ MakeNode(Dst, Ex, Pred,
+ BindExpr(GetState(Pred), Ex,
+ NonLoc::MakeVal(getBasicVals(), amt, Ex->getType())));
+}
+
+
+void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
+ NodeSet& Dst, bool asLValue) {
+
+ switch (U->getOpcode()) {
+
+ default:
+ break;
+
+ case UnaryOperator::Deref: {
+
+ Expr* Ex = U->getSubExpr()->IgnoreParens();
+ NodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
+
+ for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+
+ const GRState* state = GetState(*I);
+ SVal location = GetSVal(state, Ex);
+
+ if (asLValue)
+ MakeNode(Dst, U, *I, BindExpr(state, U, location),
+ ProgramPoint::PostLValueKind);
+ else
+ EvalLoad(Dst, U, *I, state, location);
+ }
+
+ return;
+ }
+
+ case UnaryOperator::Real: {
+
+ Expr* Ex = U->getSubExpr()->IgnoreParens();
+ NodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
+
+ for (NodeSet::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, UnaryOperator::Real is an identity operation.
+ assert (U->getType() == Ex->getType());
+ const GRState* state = GetState(*I);
+ MakeNode(Dst, U, *I, BindExpr(state, U, GetSVal(state, Ex)));
+ }
+
+ return;
+ }
+
+ case UnaryOperator::Imag: {
+
+ Expr* Ex = U->getSubExpr()->IgnoreParens();
+ NodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
+
+ for (NodeSet::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, UnaryOperator::Float returns 0.
+ assert (Ex->getType()->isIntegerType());
+ const GRState* state = GetState(*I);
+ SVal X = NonLoc::MakeVal(getBasicVals(), 0, Ex->getType());
+ MakeNode(Dst, U, *I, BindExpr(state, U, X));
+ }
+
+ return;
+ }
+
+ // FIXME: Just report "Unknown" for OffsetOf.
+ case UnaryOperator::OffsetOf:
+ Dst.Add(Pred);
+ return;
+
+ case UnaryOperator::Plus: assert (!asLValue); // FALL-THROUGH.
+ case UnaryOperator::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.
+
+ Expr* Ex = U->getSubExpr()->IgnoreParens();
+ NodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
+
+ for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ const GRState* state = GetState(*I);
+ MakeNode(Dst, U, *I, BindExpr(state, U, GetSVal(state, Ex)));
+ }
+
+ return;
+ }
+
+ case UnaryOperator::AddrOf: {
+
+ assert(!asLValue);
+ Expr* Ex = U->getSubExpr()->IgnoreParens();
+ NodeSet Tmp;
+ VisitLValue(Ex, Pred, Tmp);
+
+ for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ const GRState* state = GetState(*I);
+ SVal V = GetSVal(state, Ex);
+ state = BindExpr(state, U, V);
+ MakeNode(Dst, U, *I, state);
+ }
+
+ return;
+ }
+
+ case UnaryOperator::LNot:
+ case UnaryOperator::Minus:
+ case UnaryOperator::Not: {
+
+ assert (!asLValue);
+ Expr* Ex = U->getSubExpr()->IgnoreParens();
+ NodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
+
+ for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ const GRState* state = GetState(*I);
+
+ // Get the value of the subexpression.
+ SVal V = GetSVal(state, Ex);
+
+ if (V.isUnknownOrUndef()) {
+ MakeNode(Dst, U, *I, BindExpr(state, 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 UnaryOperator::Not:
+ // FIXME: Do we need to handle promotions?
+ state = BindExpr(state, U, EvalComplement(cast<NonLoc>(V)));
+ break;
+
+ case UnaryOperator::Minus:
+ // FIXME: Do we need to handle promotions?
+ state = BindExpr(state, U, EvalMinus(U, cast<NonLoc>(V)));
+ break;
+
+ case UnaryOperator::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".
+
+ if (isa<Loc>(V)) {
+ Loc X = Loc::MakeNull(getBasicVals());
+ SVal Result = EvalBinOp(state,BinaryOperator::EQ, cast<Loc>(V), X,
+ U->getType());
+ state = BindExpr(state, U, Result);
+ }
+ else {
+ nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
+#if 0
+ SVal Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X);
+ state = SetSVal(state, U, Result);
+#else
+ EvalBinOp(Dst, U, BinaryOperator::EQ, cast<NonLoc>(V), X, *I,
+ U->getType());
+ continue;
+#endif
+ }
+
+ break;
+ }
+
+ MakeNode(Dst, U, *I, state);
+ }
+
+ return;
+ }
+ }
+
+ // Handle ++ and -- (both pre- and post-increment).
+
+ assert (U->isIncrementDecrementOp());
+ NodeSet Tmp;
+ Expr* Ex = U->getSubExpr()->IgnoreParens();
+ VisitLValue(Ex, Pred, Tmp);
+
+ for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
+
+ const GRState* state = GetState(*I);
+ SVal V1 = GetSVal(state, Ex);
+
+ // Perform a load.
+ NodeSet Tmp2;
+ EvalLoad(Tmp2, Ex, *I, state, V1);
+
+ for (NodeSet::iterator I2 = Tmp2.begin(), E2 = Tmp2.end(); I2!=E2; ++I2) {
+
+ state = GetState(*I2);
+ SVal V2 = GetSVal(state, Ex);
+
+ // Propagate unknown and undefined values.
+ if (V2.isUnknownOrUndef()) {
+ MakeNode(Dst, U, *I2, BindExpr(state, U, V2));
+ continue;
+ }
+
+ // Handle all other values.
+ BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add
+ : BinaryOperator::Sub;
+
+ SVal Result = EvalBinOp(state, Op, V2, MakeConstantVal(1U, U),
+ U->getType());
+
+ // Conjure a new symbol if necessary to recover precision.
+ if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){
+ Result = ValMgr.getConjuredSymbolVal(Ex,
+ Builder->getCurrentBlockCount());
+
+ // 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())) {
+ SVal Constraint = EvalBinOp(state, BinaryOperator::EQ, V2,
+ ValMgr.makeZeroVal(U->getType()),
+ getContext().IntTy);
+
+ bool isFeasible = false;
+ Assume(state, Constraint, true, isFeasible);
+ if (!isFeasible) {
+ // It isn't feasible for the original value to be null.
+ // Propagate this constraint.
+ Constraint = EvalBinOp(state, BinaryOperator::EQ, Result,
+ ValMgr.makeZeroVal(U->getType()),
+ getContext().IntTy);
+
+ bool isFeasible = false;
+ state = Assume(state, Constraint, false, isFeasible);
+ assert(isFeasible && state);
+ }
+ }
+ }
+
+ state = BindExpr(state, U, U->isPostfix() ? V2 : Result);
+
+ // Perform the store.
+ EvalStore(Dst, U, *I2, state, V1, Result);
+ }
+ }
+}
+
+void GRExprEngine::VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst) {
+ VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst);
+}
+
+void GRExprEngine::VisitAsmStmtHelperOutputs(AsmStmt* A,
+ AsmStmt::outputs_iterator I,
+ AsmStmt::outputs_iterator E,
+ NodeTy* Pred, NodeSet& Dst) {
+ if (I == E) {
+ VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst);
+ return;
+ }
+
+ NodeSet Tmp;
+ VisitLValue(*I, Pred, Tmp);
+
+ ++I;
+
+ for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
+ VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst);
+}
+
+void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A,
+ AsmStmt::inputs_iterator I,
+ AsmStmt::inputs_iterator E,
+ NodeTy* Pred, NodeSet& Dst) {
+ if (I == E) {
+
+ // We have processed both the inputs and the outputs. All of the outputs
+ // should evaluate to Locs. Nuke all of their values.
+
+ // FIXME: Some day in the future it would be nice to allow a "plug-in"
+ // which interprets the inline asm and stores proper results in the
+ // outputs.
+
+ const GRState* state = GetState(Pred);
+
+ for (AsmStmt::outputs_iterator OI = A->begin_outputs(),
+ OE = A->end_outputs(); OI != OE; ++OI) {
+
+ SVal X = GetSVal(state, *OI);
+ assert (!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
+
+ if (isa<Loc>(X))
+ state = BindLoc(state, cast<Loc>(X), UnknownVal());
+ }
+
+ MakeNode(Dst, A, Pred, state);
+ return;
+ }
+
+ NodeSet Tmp;
+ Visit(*I, Pred, Tmp);
+
+ ++I;
+
+ for (NodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI)
+ VisitAsmStmtHelperInputs(A, I, E, *NI, Dst);
+}
+
+void GRExprEngine::EvalReturn(NodeSet& Dst, ReturnStmt* S, NodeTy* Pred) {
+ assert (Builder && "GRStmtNodeBuilder must be defined.");
+
+ unsigned size = Dst.size();
+
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
+
+ getTF().EvalReturn(Dst, *this, *Builder, S, Pred);
+
+ // Handle the case where no nodes where generated.
+
+ if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode)
+ MakeNode(Dst, S, Pred, GetState(Pred));
+}
+
+void GRExprEngine::VisitReturnStmt(ReturnStmt* S, NodeTy* Pred, NodeSet& Dst) {
+
+ Expr* R = S->getRetValue();
+
+ if (!R) {
+ EvalReturn(Dst, S, Pred);
+ return;
+ }
+
+ NodeSet Tmp;
+ Visit(R, Pred, Tmp);
+
+ for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
+ SVal X = GetSVal((*I)->getState(), R);
+
+ // Check if we return the address of a stack variable.
+ if (isa<loc::MemRegionVal>(X)) {
+ // Determine if the value is on the stack.
+ const MemRegion* R = cast<loc::MemRegionVal>(&X)->getRegion();
+
+ if (R && getStateManager().hasStackStorage(R)) {
+ // Create a special node representing the error.
+ if (NodeTy* N = Builder->generateNode(S, GetState(*I), *I)) {
+ N->markAsSink();
+ RetsStackAddr.insert(N);
+ }
+ continue;
+ }
+ }
+ // Check if we return an undefined value.
+ else if (X.isUndef()) {
+ if (NodeTy* N = Builder->generateNode(S, GetState(*I), *I)) {
+ N->markAsSink();
+ RetsUndef.insert(N);
+ }
+ continue;
+ }
+
+ EvalReturn(Dst, S, *I);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer functions: Binary operators.
+//===----------------------------------------------------------------------===//
+
+const GRState* GRExprEngine::CheckDivideZero(Expr* Ex, const GRState* state,
+ NodeTy* Pred, SVal Denom) {
+
+ // Divide by undefined? (potentially zero)
+
+ if (Denom.isUndef()) {
+ NodeTy* DivUndef = Builder->generateNode(Ex, state, Pred);
+
+ if (DivUndef) {
+ DivUndef->markAsSink();
+ ExplicitBadDivides.insert(DivUndef);
+ }
+
+ return 0;
+ }
+
+ // Check for divide/remainder-by-zero.
+ // First, "assume" that the denominator is 0 or undefined.
+
+ bool isFeasibleZero = false;
+ const GRState* ZeroSt = Assume(state, Denom, false, isFeasibleZero);
+
+ // Second, "assume" that the denominator cannot be 0.
+
+ bool isFeasibleNotZero = false;
+ state = Assume(state, Denom, true, isFeasibleNotZero);
+
+ // Create the node for the divide-by-zero (if it occurred).
+
+ if (isFeasibleZero)
+ if (NodeTy* DivZeroNode = Builder->generateNode(Ex, ZeroSt, Pred)) {
+ DivZeroNode->markAsSink();
+
+ if (isFeasibleNotZero)
+ ImplicitBadDivides.insert(DivZeroNode);
+ else
+ ExplicitBadDivides.insert(DivZeroNode);
+
+ }
+
+ return isFeasibleNotZero ? state : 0;
+}
+
+void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
+ GRExprEngine::NodeTy* Pred,
+ GRExprEngine::NodeSet& Dst) {
+
+ NodeSet Tmp1;
+ Expr* LHS = B->getLHS()->IgnoreParens();
+ Expr* RHS = B->getRHS()->IgnoreParens();
+
+ // FIXME: Add proper support for ObjCKVCRefExpr.
+ if (isa<ObjCKVCRefExpr>(LHS)) {
+ Visit(RHS, Pred, Dst);
+ return;
+ }
+
+ if (B->isAssignmentOp())
+ VisitLValue(LHS, Pred, Tmp1);
+ else
+ Visit(LHS, Pred, Tmp1);
+
+ for (NodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1 != E1; ++I1) {
+
+ SVal LeftV = GetSVal((*I1)->getState(), LHS);
+
+ // Process the RHS.
+
+ NodeSet Tmp2;
+ Visit(RHS, *I1, Tmp2);
+
+ // With both the LHS and RHS evaluated, process the operation itself.
+
+ for (NodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end(); I2 != E2; ++I2) {
+
+ const GRState* state = GetState(*I2);
+ const GRState* OldSt = state;
+
+ SVal RightV = GetSVal(state, RHS);
+ BinaryOperator::Opcode Op = B->getOpcode();
+
+ switch (Op) {
+
+ case BinaryOperator::Assign: {
+
+ // EXPERIMENTAL: "Conjured" symbols.
+ // FIXME: Handle structs.
+ QualType T = RHS->getType();
+
+ if ((RightV.isUnknown() ||
+ !getConstraintManager().canReasonAbout(RightV))
+ && (Loc::IsLocType(T) ||
+ (T->isScalarType() && T->isIntegerType()))) {
+ unsigned Count = Builder->getCurrentBlockCount();
+ RightV = ValMgr.getConjuredSymbolVal(B->getRHS(), Count);
+ }
+
+ // Simulate the effects of a "store": bind the value of the RHS
+ // to the L-Value represented by the LHS.
+ EvalStore(Dst, B, LHS, *I2, BindExpr(state, B, RightV), LeftV,
+ RightV);
+ continue;
+ }
+
+ case BinaryOperator::Div:
+ case BinaryOperator::Rem:
+
+ // Special checking for integer denominators.
+ if (RHS->getType()->isIntegerType() &&
+ RHS->getType()->isScalarType()) {
+
+ state = CheckDivideZero(B, state, *I2, RightV);
+ if (!state) continue;
+ }
+
+ // FALL-THROUGH.
+
+ default: {
+
+ if (B->isAssignmentOp())
+ break;
+
+ // Process non-assignements except commas or short-circuited
+ // logical expressions (LAnd and LOr).
+
+ SVal Result = EvalBinOp(state, Op, LeftV, RightV, B->getType());
+
+ if (Result.isUnknown()) {
+ if (OldSt != state) {
+ // Generate a new node if we have already created a new state.
+ MakeNode(Dst, B, *I2, state);
+ }
+ else
+ Dst.Add(*I2);
+
+ continue;
+ }
+
+ if (Result.isUndef() && !LeftV.isUndef() && !RightV.isUndef()) {
+
+ // The operands were *not* undefined, but the result is undefined.
+ // This is a special node that should be flagged as an error.
+
+ if (NodeTy* UndefNode = Builder->generateNode(B, state, *I2)) {
+ UndefNode->markAsSink();
+ UndefResults.insert(UndefNode);
+ }
+
+ continue;
+ }
+
+ // Otherwise, create a new node.
+
+ MakeNode(Dst, B, *I2, BindExpr(state, B, Result));
+ continue;
+ }
+ }
+
+ assert (B->isCompoundAssignmentOp());
+
+ switch (Op) {
+ default:
+ assert(0 && "Invalid opcode for compound assignment.");
+ case BinaryOperator::MulAssign: Op = BinaryOperator::Mul; break;
+ case BinaryOperator::DivAssign: Op = BinaryOperator::Div; break;
+ case BinaryOperator::RemAssign: Op = BinaryOperator::Rem; break;
+ case BinaryOperator::AddAssign: Op = BinaryOperator::Add; break;
+ case BinaryOperator::SubAssign: Op = BinaryOperator::Sub; break;
+ case BinaryOperator::ShlAssign: Op = BinaryOperator::Shl; break;
+ case BinaryOperator::ShrAssign: Op = BinaryOperator::Shr; break;
+ case BinaryOperator::AndAssign: Op = BinaryOperator::And; break;
+ case BinaryOperator::XorAssign: Op = BinaryOperator::Xor; break;
+ case BinaryOperator::OrAssign: Op = BinaryOperator::Or; break;
+ }
+
+ // Perform a load (the LHS). This performs the checks for
+ // null dereferences, and so on.
+ NodeSet Tmp3;
+ SVal location = GetSVal(state, LHS);
+ EvalLoad(Tmp3, LHS, *I2, state, location);
+
+ for (NodeSet::iterator I3=Tmp3.begin(), E3=Tmp3.end(); I3!=E3; ++I3) {
+
+ state = GetState(*I3);
+ SVal V = GetSVal(state, LHS);
+
+ // Check for divide-by-zero.
+ if ((Op == BinaryOperator::Div || Op == BinaryOperator::Rem)
+ && RHS->getType()->isIntegerType()
+ && RHS->getType()->isScalarType()) {
+
+ // CheckDivideZero returns a new state where the denominator
+ // is assumed to be non-zero.
+ state = CheckDivideZero(B, state, *I3, RightV);
+
+ if (!state)
+ continue;
+ }
+
+ // Propagate undefined values (left-side).
+ if (V.isUndef()) {
+ EvalStore(Dst, B, LHS, *I3, BindExpr(state, B, V), location, V);
+ continue;
+ }
+
+ // Propagate unknown values (left and right-side).
+ if (RightV.isUnknown() || V.isUnknown()) {
+ EvalStore(Dst, B, LHS, *I3, BindExpr(state, B, UnknownVal()),
+ location, UnknownVal());
+ continue;
+ }
+
+ // At this point:
+ //
+ // The LHS is not Undef/Unknown.
+ // The RHS is not Unknown.
+
+ // Get the computation type.
+ QualType CTy = cast<CompoundAssignOperator>(B)->getComputationResultType();
+ CTy = getContext().getCanonicalType(CTy);
+
+ QualType CLHSTy = cast<CompoundAssignOperator>(B)->getComputationLHSType();
+ CLHSTy = getContext().getCanonicalType(CTy);
+
+ QualType LTy = getContext().getCanonicalType(LHS->getType());
+ QualType RTy = getContext().getCanonicalType(RHS->getType());
+
+ // Promote LHS.
+ V = EvalCast(V, CLHSTy);
+
+ // Evaluate operands and promote to result type.
+ if (RightV.isUndef()) {
+ // Propagate undefined values (right-side).
+ EvalStore(Dst, B, LHS, *I3, BindExpr(state, B, RightV), location,
+ RightV);
+ continue;
+ }
+
+ // Compute the result of the operation.
+ SVal Result = EvalCast(EvalBinOp(state, Op, V, RightV, CTy),
+ B->getType());
+
+ if (Result.isUndef()) {
+ // The operands were not undefined, but the result is undefined.
+ if (NodeTy* UndefNode = Builder->generateNode(B, state, *I3)) {
+ UndefNode->markAsSink();
+ UndefResults.insert(UndefNode);
+ }
+ continue;
+ }
+
+ // EXPERIMENTAL: "Conjured" symbols.
+ // FIXME: Handle structs.
+
+ SVal LHSVal;
+
+ if ((Result.isUnknown() ||
+ !getConstraintManager().canReasonAbout(Result))
+ && (Loc::IsLocType(CTy)
+ || (CTy->isScalarType() && CTy->isIntegerType()))) {
+
+ 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 = ValMgr.getConjuredSymbolVal(B->getRHS(), LTy, Count);
+
+ // However, we need to convert the symbol to the computation type.
+ Result = (LTy == CTy) ? LHSVal : EvalCast(LHSVal,CTy);
+ }
+ else {
+ // The left-hand side may bind to a different value then the
+ // computation type.
+ LHSVal = (LTy == CTy) ? Result : EvalCast(Result,LTy);
+ }
+
+ EvalStore(Dst, B, LHS, *I3, BindExpr(state, B, Result), location,
+ LHSVal);
+ }
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer-function Helpers.
+//===----------------------------------------------------------------------===//
+
+void GRExprEngine::EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex,
+ BinaryOperator::Opcode Op,
+ NonLoc L, NonLoc R,
+ ExplodedNode<GRState>* Pred, QualType T) {
+
+ GRStateSet OStates;
+ EvalBinOp(OStates, GetState(Pred), Ex, Op, L, R, T);
+
+ for (GRStateSet::iterator I=OStates.begin(), E=OStates.end(); I!=E; ++I)
+ MakeNode(Dst, Ex, Pred, *I);
+}
+
+void GRExprEngine::EvalBinOp(GRStateSet& OStates, const GRState* state,
+ Expr* Ex, BinaryOperator::Opcode Op,
+ NonLoc L, NonLoc R, QualType T) {
+
+ GRStateSet::AutoPopulate AP(OStates, state);
+ if (R.isValid()) getTF().EvalBinOpNN(OStates, *this, state, Ex, Op, L, R, T);
+}
+
+SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op,
+ SVal L, SVal R, QualType T) {
+
+ if (L.isUndef() || R.isUndef())
+ return UndefinedVal();
+
+ if (L.isUnknown() || R.isUnknown())
+ return UnknownVal();
+
+ if (isa<Loc>(L)) {
+ if (isa<Loc>(R))
+ return getTF().EvalBinOp(*this, Op, cast<Loc>(L), cast<Loc>(R));
+ else
+ return getTF().EvalBinOp(*this, state, Op, cast<Loc>(L), cast<NonLoc>(R));
+ }
+
+ if (isa<Loc>(R)) {
+ // Support pointer arithmetic where the increment/decrement operand
+ // is on the left and the pointer on the right.
+
+ assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub);
+
+ // Commute the operands.
+ return getTF().EvalBinOp(*this, state, Op, cast<Loc>(R), cast<NonLoc>(L));
+ }
+ else
+ return getTF().DetermEvalBinOpNN(*this, Op, cast<NonLoc>(L),
+ cast<NonLoc>(R), T);
+}
+
+//===----------------------------------------------------------------------===//
+// Visualization.
+//===----------------------------------------------------------------------===//
+
+#ifndef NDEBUG
+static GRExprEngine* GraphPrintCheckerState;
+static SourceManager* GraphPrintSourceManager;
+
+namespace llvm {
+template<>
+struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
+ public DefaultDOTGraphTraits {
+
+ static std::string getNodeAttributes(const GRExprEngine::NodeTy* N, void*) {
+
+ if (GraphPrintCheckerState->isImplicitNullDeref(N) ||
+ GraphPrintCheckerState->isExplicitNullDeref(N) ||
+ GraphPrintCheckerState->isUndefDeref(N) ||
+ GraphPrintCheckerState->isUndefStore(N) ||
+ GraphPrintCheckerState->isUndefControlFlow(N) ||
+ GraphPrintCheckerState->isExplicitBadDivide(N) ||
+ GraphPrintCheckerState->isImplicitBadDivide(N) ||
+ GraphPrintCheckerState->isUndefResult(N) ||
+ GraphPrintCheckerState->isBadCall(N) ||
+ GraphPrintCheckerState->isUndefArg(N))
+ return "color=\"red\",style=\"filled\"";
+
+ if (GraphPrintCheckerState->isNoReturnCall(N))
+ return "color=\"blue\",style=\"filled\"";
+
+ return "";
+ }
+
+ static std::string getNodeLabel(const GRExprEngine::NodeTy* N, void*) {
+ std::ostringstream Out;
+
+ // Program Location.
+ ProgramPoint Loc = N->getLocation();
+
+ switch (Loc.getKind()) {
+ case ProgramPoint::BlockEntranceKind:
+ Out << "Block Entrance: B"
+ << cast<BlockEntrance>(Loc).getBlock()->getBlockID();
+ break;
+
+ case ProgramPoint::BlockExitKind:
+ assert (false);
+ break;
+
+ default: {
+ if (isa<PostStmt>(Loc)) {
+ const PostStmt& L = cast<PostStmt>(Loc);
+ Stmt* S = L.getStmt();
+ SourceLocation SLoc = S->getLocStart();
+
+ Out << S->getStmtClassName() << ' ' << (void*) S << ' ';
+ llvm::raw_os_ostream OutS(Out);
+ S->printPretty(OutS);
+ OutS.flush();
+
+ if (SLoc.isFileID()) {
+ Out << "\\lline="
+ << GraphPrintSourceManager->getInstantiationLineNumber(SLoc)
+ << " col="
+ << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc)
+ << "\\l";
+ }
+
+ if (isa<PostLoad>(Loc))
+ Out << "\\lPostLoad\\l;";
+ else if (isa<PostStore>(Loc))
+ Out << "\\lPostStore\\l";
+ else if (isa<PostLValue>(Loc))
+ Out << "\\lPostLValue\\l";
+ else if (isa<PostLocationChecksSucceed>(Loc))
+ Out << "\\lPostLocationChecksSucceed\\l";
+ else if (isa<PostNullCheckFailed>(Loc))
+ Out << "\\lPostNullCheckFailed\\l";
+
+ if (GraphPrintCheckerState->isImplicitNullDeref(N))
+ Out << "\\|Implicit-Null Dereference.\\l";
+ else if (GraphPrintCheckerState->isExplicitNullDeref(N))
+ Out << "\\|Explicit-Null Dereference.\\l";
+ else if (GraphPrintCheckerState->isUndefDeref(N))
+ Out << "\\|Dereference of undefialied value.\\l";
+ else if (GraphPrintCheckerState->isUndefStore(N))
+ Out << "\\|Store to Undefined Loc.";
+ else if (GraphPrintCheckerState->isExplicitBadDivide(N))
+ Out << "\\|Explicit divide-by zero or undefined value.";
+ else if (GraphPrintCheckerState->isImplicitBadDivide(N))
+ Out << "\\|Implicit divide-by zero or undefined value.";
+ else if (GraphPrintCheckerState->isUndefResult(N))
+ Out << "\\|Result of operation is undefined.";
+ else if (GraphPrintCheckerState->isNoReturnCall(N))
+ Out << "\\|Call to function marked \"noreturn\".";
+ else if (GraphPrintCheckerState->isBadCall(N))
+ Out << "\\|Call to NULL/Undefined.";
+ else if (GraphPrintCheckerState->isUndefArg(N))
+ Out << "\\|Argument in call is undefined";
+
+ break;
+ }
+
+ const BlockEdge& E = cast<BlockEdge>(Loc);
+ Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B"
+ << E.getDst()->getBlockID() << ')';
+
+ if (Stmt* T = E.getSrc()->getTerminator()) {
+
+ SourceLocation SLoc = T->getLocStart();
+
+ Out << "\\|Terminator: ";
+
+ llvm::raw_os_ostream OutS(Out);
+ E.getSrc()->printTerminator(OutS);
+ OutS.flush();
+
+ if (SLoc.isFileID()) {
+ Out << "\\lline="
+ << GraphPrintSourceManager->getInstantiationLineNumber(SLoc)
+ << " col="
+ << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc);
+ }
+
+ if (isa<SwitchStmt>(T)) {
+ Stmt* Label = E.getDst()->getLabel();
+
+ if (Label) {
+ if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
+ Out << "\\lcase ";
+ llvm::raw_os_ostream OutS(Out);
+ C->getLHS()->printPretty(OutS);
+ OutS.flush();
+
+ if (Stmt* RHS = C->getRHS()) {
+ Out << " .. ";
+ RHS->printPretty(OutS);
+ OutS.flush();
+ }
+
+ Out << ":";
+ }
+ else {
+ assert (isa<DefaultStmt>(Label));
+ Out << "\\ldefault:";
+ }
+ }
+ else
+ Out << "\\l(implicit) default:";
+ }
+ else if (isa<IndirectGotoStmt>(T)) {
+ // FIXME
+ }
+ else {
+ Out << "\\lCondition: ";
+ if (*E.getSrc()->succ_begin() == E.getDst())
+ Out << "true";
+ else
+ Out << "false";
+ }
+
+ Out << "\\l";
+ }
+
+ if (GraphPrintCheckerState->isUndefControlFlow(N)) {
+ Out << "\\|Control-flow based on\\lUndefined value.\\l";
+ }
+ }
+ }
+
+ Out << "\\|StateID: " << (void*) N->getState() << "\\|";
+
+ GRStateRef state(N->getState(), GraphPrintCheckerState->getStateManager());
+ state.printDOT(Out);
+
+ Out << "\\l";
+ return Out.str();
+ }
+};
+} // end llvm namespace
+#endif
+
+#ifndef NDEBUG
+template <typename ITERATOR>
+GRExprEngine::NodeTy* GetGraphNode(ITERATOR I) { return *I; }
+
+template <>
+GRExprEngine::NodeTy*
+GetGraphNode<llvm::DenseMap<GRExprEngine::NodeTy*, Expr*>::iterator>
+ (llvm::DenseMap<GRExprEngine::NodeTy*, Expr*>::iterator I) {
+ return I->first;
+}
+#endif
+
+void GRExprEngine::ViewGraph(bool trim) {
+#ifndef NDEBUG
+ if (trim) {
+ std::vector<NodeTy*> Src;
+
+ // Flush any outstanding reports to make sure we cover all the nodes.
+ // This does not cause them to get displayed.
+ for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I)
+ const_cast<BugType*>(*I)->FlushReports(BR);
+
+ // Iterate through the reports and get their nodes.
+ for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I) {
+ for (BugType::const_iterator I2=(*I)->begin(), E2=(*I)->end(); I2!=E2; ++I2) {
+ const BugReportEquivClass& EQ = *I2;
+ const BugReport &R = **EQ.begin();
+ NodeTy *N = const_cast<NodeTy*>(R.getEndNode());
+ if (N) Src.push_back(N);
+ }
+ }
+
+ ViewGraph(&Src[0], &Src[0]+Src.size());
+ }
+ else {
+ GraphPrintCheckerState = this;
+ GraphPrintSourceManager = &getContext().getSourceManager();
+
+ llvm::ViewGraph(*G.roots_begin(), "GRExprEngine");
+
+ GraphPrintCheckerState = NULL;
+ GraphPrintSourceManager = NULL;
+ }
+#endif
+}
+
+void GRExprEngine::ViewGraph(NodeTy** Beg, NodeTy** End) {
+#ifndef NDEBUG
+ GraphPrintCheckerState = this;
+ GraphPrintSourceManager = &getContext().getSourceManager();
+
+ std::auto_ptr<GRExprEngine::GraphTy> TrimmedG(G.Trim(Beg, End).first);
+
+ if (!TrimmedG.get())
+ llvm::cerr << "warning: Trimmed ExplodedGraph is empty.\n";
+ else
+ llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedGRExprEngine");
+
+ GraphPrintCheckerState = NULL;
+ GraphPrintSourceManager = NULL;
+#endif
+}
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp
new file mode 100644
index 000000000000..9aea12447dd5
--- /dev/null
+++ b/lib/Analysis/GRExprEngineInternalChecks.cpp
@@ -0,0 +1,961 @@
+//=-- GRExprEngineInternalChecks.cpp - Builtin GRExprEngine Checks---*- 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 BugType classes used by GRExprEngine to report
+// bugs derived from builtin checks in the path-sensitive engine.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Utility functions.
+//===----------------------------------------------------------------------===//
+
+template <typename ITERATOR> inline
+ExplodedNode<GRState>* GetNode(ITERATOR I) {
+ return *I;
+}
+
+template <> inline
+ExplodedNode<GRState>* GetNode(GRExprEngine::undef_arg_iterator I) {
+ return I->first;
+}
+
+//===----------------------------------------------------------------------===//
+// Forward declarations for bug reporter visitors.
+//===----------------------------------------------------------------------===//
+
+static const Stmt *GetDerefExpr(const ExplodedNode<GRState> *N);
+static const Stmt *GetReceiverExpr(const ExplodedNode<GRState> *N);
+static const Stmt *GetDenomExpr(const ExplodedNode<GRState> *N);
+static const Stmt *GetCalleeExpr(const ExplodedNode<GRState> *N);
+static const Stmt *GetRetValExpr(const ExplodedNode<GRState> *N);
+
+static void registerTrackNullOrUndefValue(BugReporterContext& BRC,
+ const Stmt *ValExpr,
+ const ExplodedNode<GRState>* N);
+
+//===----------------------------------------------------------------------===//
+// Bug Descriptions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class VISIBILITY_HIDDEN BuiltinBugReport : public RangedBugReport {
+public:
+ BuiltinBugReport(BugType& bt, const char* desc,
+ ExplodedNode<GRState> *n)
+ : RangedBugReport(bt, desc, n) {}
+
+ BuiltinBugReport(BugType& bt, const char *shortDesc, const char *desc,
+ ExplodedNode<GRState> *n)
+ : RangedBugReport(bt, shortDesc, desc, n) {}
+
+ void registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N);
+};
+
+class VISIBILITY_HIDDEN BuiltinBug : public BugType {
+ GRExprEngine &Eng;
+protected:
+ const std::string desc;
+public:
+ BuiltinBug(GRExprEngine *eng, const char* n, const char* d)
+ : BugType(n, "Logic errors"), Eng(*eng), desc(d) {}
+
+ BuiltinBug(GRExprEngine *eng, const char* n)
+ : BugType(n, "Logic errors"), Eng(*eng), desc(n) {}
+
+ virtual void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) = 0;
+
+ void FlushReports(BugReporter& BR) { FlushReportsImpl(BR, Eng); }
+
+ virtual void registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N,
+ BuiltinBugReport *R) {}
+
+ template <typename ITER> void Emit(BugReporter& BR, ITER I, ITER E);
+};
+
+
+template <typename ITER>
+void BuiltinBug::Emit(BugReporter& BR, ITER I, ITER E) {
+ for (; I != E; ++I) BR.EmitReport(new BuiltinBugReport(*this, desc.c_str(),
+ GetNode(I)));
+}
+
+void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N) {
+ static_cast<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this);
+}
+
+class VISIBILITY_HIDDEN NullDeref : public BuiltinBug {
+public:
+ NullDeref(GRExprEngine* eng)
+ : BuiltinBug(eng,"Null dereference", "Dereference of null pointer") {}
+
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
+ Emit(BR, Eng.null_derefs_begin(), Eng.null_derefs_end());
+ }
+
+ void registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N,
+ BuiltinBugReport *R) {
+ registerTrackNullOrUndefValue(BRC, GetDerefExpr(N), N);
+ }
+};
+
+class VISIBILITY_HIDDEN NilReceiverStructRet : public BuiltinBug {
+public:
+ NilReceiverStructRet(GRExprEngine* eng) :
+ BuiltinBug(eng, "'nil' receiver with struct return type") {}
+
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
+ for (GRExprEngine::nil_receiver_struct_ret_iterator
+ I=Eng.nil_receiver_struct_ret_begin(),
+ E=Eng.nil_receiver_struct_ret_end(); I!=E; ++I) {
+
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+ PostStmt P = cast<PostStmt>((*I)->getLocation());
+ ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt());
+ os << "The receiver in the message expression is 'nil' and results in the"
+ " returned value (of type '"
+ << ME->getType().getAsString()
+ << "') to be garbage or otherwise undefined.";
+
+ BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I);
+ R->addRange(ME->getReceiver()->getSourceRange());
+ BR.EmitReport(R);
+ }
+ }
+
+ void registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N,
+ BuiltinBugReport *R) {
+ registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
+ }
+};
+
+class VISIBILITY_HIDDEN NilReceiverLargerThanVoidPtrRet : public BuiltinBug {
+public:
+ NilReceiverLargerThanVoidPtrRet(GRExprEngine* eng) :
+ BuiltinBug(eng,
+ "'nil' receiver with return type larger than sizeof(void *)") {}
+
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
+ for (GRExprEngine::nil_receiver_larger_than_voidptr_ret_iterator
+ I=Eng.nil_receiver_larger_than_voidptr_ret_begin(),
+ E=Eng.nil_receiver_larger_than_voidptr_ret_end(); I!=E; ++I) {
+
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+ PostStmt P = cast<PostStmt>((*I)->getLocation());
+ ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt());
+ os << "The receiver in the message expression is 'nil' and results in the"
+ " returned value (of type '"
+ << ME->getType().getAsString()
+ << "' and of size "
+ << Eng.getContext().getTypeSize(ME->getType()) / 8
+ << " bytes) to be garbage or otherwise undefined.";
+
+ BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I);
+ R->addRange(ME->getReceiver()->getSourceRange());
+ BR.EmitReport(R);
+ }
+ }
+ void registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N,
+ BuiltinBugReport *R) {
+ registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
+ }
+};
+
+class VISIBILITY_HIDDEN UndefinedDeref : public BuiltinBug {
+public:
+ UndefinedDeref(GRExprEngine* eng)
+ : BuiltinBug(eng,"Dereference of undefined pointer value") {}
+
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
+ Emit(BR, Eng.undef_derefs_begin(), Eng.undef_derefs_end());
+ }
+
+ void registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N,
+ BuiltinBugReport *R) {
+ registerTrackNullOrUndefValue(BRC, GetDerefExpr(N), N);
+ }
+};
+
+class VISIBILITY_HIDDEN DivZero : public BuiltinBug {
+public:
+ DivZero(GRExprEngine* eng)
+ : BuiltinBug(eng,"Division-by-zero",
+ "Division by zero or undefined value.") {}
+
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
+ Emit(BR, Eng.explicit_bad_divides_begin(), Eng.explicit_bad_divides_end());
+ }
+
+ void registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N,
+ BuiltinBugReport *R) {
+ registerTrackNullOrUndefValue(BRC, GetDenomExpr(N), N);
+ }
+};
+
+class VISIBILITY_HIDDEN UndefResult : public BuiltinBug {
+public:
+ UndefResult(GRExprEngine* eng) : BuiltinBug(eng,"Undefined result",
+ "Result of operation is undefined.") {}
+
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
+ Emit(BR, Eng.undef_results_begin(), Eng.undef_results_end());
+ }
+};
+
+class VISIBILITY_HIDDEN BadCall : public BuiltinBug {
+public:
+ BadCall(GRExprEngine *eng)
+ : BuiltinBug(eng, "Invalid function call",
+ "Called function pointer is a null or undefined pointer value") {}
+
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
+ Emit(BR, Eng.bad_calls_begin(), Eng.bad_calls_end());
+ }
+
+ void registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N,
+ BuiltinBugReport *R) {
+ registerTrackNullOrUndefValue(BRC, GetCalleeExpr(N), N);
+ }
+};
+
+
+class VISIBILITY_HIDDEN ArgReport : public BuiltinBugReport {
+ const Stmt *Arg;
+public:
+ ArgReport(BugType& bt, const char* desc, ExplodedNode<GRState> *n,
+ const Stmt *arg)
+ : BuiltinBugReport(bt, desc, n), Arg(arg) {}
+
+ ArgReport(BugType& bt, const char *shortDesc, const char *desc,
+ ExplodedNode<GRState> *n, const Stmt *arg)
+ : BuiltinBugReport(bt, shortDesc, desc, n), Arg(arg) {}
+
+ const Stmt *getArg() const { return Arg; }
+};
+
+class VISIBILITY_HIDDEN BadArg : public BuiltinBug {
+public:
+ BadArg(GRExprEngine* eng) : BuiltinBug(eng,"Uninitialized argument",
+ "Pass-by-value argument in function call is undefined.") {}
+
+ BadArg(GRExprEngine* eng, const char* d)
+ : BuiltinBug(eng,"Uninitialized argument", d) {}
+
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
+ for (GRExprEngine::UndefArgsTy::iterator I = Eng.undef_arg_begin(),
+ E = Eng.undef_arg_end(); I!=E; ++I) {
+ // Generate a report for this bug.
+ ArgReport *report = new ArgReport(*this, desc.c_str(), I->first,
+ I->second);
+ report->addRange(I->second->getSourceRange());
+ BR.EmitReport(report);
+ }
+ }
+
+ void registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N,
+ BuiltinBugReport *R) {
+ registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
+ N);
+ }
+};
+
+class VISIBILITY_HIDDEN BadMsgExprArg : public BadArg {
+public:
+ BadMsgExprArg(GRExprEngine* eng)
+ : BadArg(eng,"Pass-by-value argument in message expression is undefined"){}
+
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
+ for (GRExprEngine::UndefArgsTy::iterator I=Eng.msg_expr_undef_arg_begin(),
+ E = Eng.msg_expr_undef_arg_end(); I!=E; ++I) {
+ // Generate a report for this bug.
+ ArgReport *report = new ArgReport(*this, desc.c_str(), I->first,
+ I->second);
+ report->addRange(I->second->getSourceRange());
+ BR.EmitReport(report);
+ }
+ }
+};
+
+class VISIBILITY_HIDDEN BadReceiver : public BuiltinBug {
+public:
+ BadReceiver(GRExprEngine* eng)
+ : BuiltinBug(eng,"Uninitialized receiver",
+ "Receiver in message expression is an uninitialized value") {}
+
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
+ for (GRExprEngine::ErrorNodes::iterator I=Eng.undef_receivers_begin(),
+ End = Eng.undef_receivers_end(); I!=End; ++I) {
+
+ // Generate a report for this bug.
+ BuiltinBugReport *report = new BuiltinBugReport(*this, desc.c_str(), *I);
+ ExplodedNode<GRState>* N = *I;
+ Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
+ Expr* E = cast<ObjCMessageExpr>(S)->getReceiver();
+ assert (E && "Receiver cannot be NULL");
+ report->addRange(E->getSourceRange());
+ BR.EmitReport(report);
+ }
+ }
+
+ void registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N,
+ BuiltinBugReport *R) {
+ registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
+ }
+};
+
+class VISIBILITY_HIDDEN RetStack : public BuiltinBug {
+public:
+ RetStack(GRExprEngine* eng)
+ : BuiltinBug(eng, "Return of address to stack-allocated memory") {}
+
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
+ for (GRExprEngine::ret_stackaddr_iterator I=Eng.ret_stackaddr_begin(),
+ End = Eng.ret_stackaddr_end(); I!=End; ++I) {
+
+ ExplodedNode<GRState>* N = *I;
+ Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
+ Expr* E = cast<ReturnStmt>(S)->getRetValue();
+ assert (E && "Return expression cannot be NULL");
+
+ // Get the value associated with E.
+ loc::MemRegionVal V =
+ cast<loc::MemRegionVal>(Eng.getStateManager().GetSVal(N->getState(),
+ E));
+
+ // Generate a report for this bug.
+ std::string buf;
+ llvm::raw_string_ostream os(buf);
+ SourceRange R;
+
+ // Check if the region is a compound literal.
+ if (const CompoundLiteralRegion* CR =
+ dyn_cast<CompoundLiteralRegion>(V.getRegion())) {
+
+ const CompoundLiteralExpr* CL = CR->getLiteralExpr();
+ os << "Address of stack memory associated with a compound literal "
+ "declared on line "
+ << BR.getSourceManager()
+ .getInstantiationLineNumber(CL->getLocStart())
+ << " returned.";
+
+ R = CL->getSourceRange();
+ }
+ else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(V.getRegion())) {
+ const Expr* ARE = AR->getExpr();
+ SourceLocation L = ARE->getLocStart();
+ R = ARE->getSourceRange();
+
+ os << "Address of stack memory allocated by call to alloca() on line "
+ << BR.getSourceManager().getInstantiationLineNumber(L)
+ << " returned.";
+ }
+ else {
+ os << "Address of stack memory associated with local variable '"
+ << V.getRegion()->getString() << "' returned.";
+ }
+
+ RangedBugReport *report = new RangedBugReport(*this, os.str().c_str(), N);
+ report->addRange(E->getSourceRange());
+ if (R.isValid()) report->addRange(R);
+ BR.EmitReport(report);
+ }
+ }
+};
+
+class VISIBILITY_HIDDEN RetUndef : public BuiltinBug {
+public:
+ RetUndef(GRExprEngine* eng) : BuiltinBug(eng, "Uninitialized return value",
+ "Uninitialized or undefined value returned to caller.") {}
+
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
+ Emit(BR, Eng.ret_undef_begin(), Eng.ret_undef_end());
+ }
+
+ void registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N,
+ BuiltinBugReport *R) {
+ registerTrackNullOrUndefValue(BRC, GetRetValExpr(N), N);
+ }
+};
+
+class VISIBILITY_HIDDEN UndefBranch : public BuiltinBug {
+ struct VISIBILITY_HIDDEN FindUndefExpr {
+ GRStateManager& VM;
+ const GRState* St;
+
+ FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {}
+
+ Expr* FindExpr(Expr* Ex) {
+ if (!MatchesCriteria(Ex))
+ return 0;
+
+ for (Stmt::child_iterator I=Ex->child_begin(), E=Ex->child_end();I!=E;++I)
+ if (Expr* ExI = dyn_cast_or_null<Expr>(*I)) {
+ Expr* E2 = FindExpr(ExI);
+ if (E2) return E2;
+ }
+
+ return Ex;
+ }
+
+ bool MatchesCriteria(Expr* Ex) { return VM.GetSVal(St, Ex).isUndef(); }
+ };
+
+public:
+ UndefBranch(GRExprEngine *eng)
+ : BuiltinBug(eng,"Use of uninitialized value",
+ "Branch condition evaluates to an uninitialized value.") {}
+
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
+ for (GRExprEngine::undef_branch_iterator I=Eng.undef_branches_begin(),
+ E=Eng.undef_branches_end(); I!=E; ++I) {
+
+ // What's going on here: we want to highlight the subexpression of the
+ // condition that is the most likely source of the "uninitialized
+ // 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>((*I)->getLocation());
+ 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 (!(*I)->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.
+ ExplodedNode<GRState> *N = *(*I)->pred_begin();
+ ProgramPoint P = N->getLocation();
+ const GRState* St = (*I)->getState();
+
+ if (PostStmt* PS = dyn_cast<PostStmt>(&P))
+ if (PS->getStmt() == Ex)
+ St = N->getState();
+
+ FindUndefExpr FindIt(Eng.getStateManager(), St);
+ Ex = FindIt.FindExpr(Ex);
+
+ ArgReport *R = new ArgReport(*this, desc.c_str(), *I, Ex);
+ R->addRange(Ex->getSourceRange());
+ BR.EmitReport(R);
+ }
+ }
+
+ void registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N,
+ BuiltinBugReport *R) {
+ registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
+ N);
+ }
+};
+
+class VISIBILITY_HIDDEN OutOfBoundMemoryAccess : public BuiltinBug {
+public:
+ OutOfBoundMemoryAccess(GRExprEngine* eng)
+ : BuiltinBug(eng,"Out-of-bounds memory access",
+ "Load or store into an out-of-bound memory position.") {}
+
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
+ Emit(BR, Eng.explicit_oob_memacc_begin(), Eng.explicit_oob_memacc_end());
+ }
+};
+
+class VISIBILITY_HIDDEN BadSizeVLA : public BuiltinBug {
+public:
+ BadSizeVLA(GRExprEngine* eng) :
+ BuiltinBug(eng, "Bad variable-length array (VLA) size") {}
+
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
+ for (GRExprEngine::ErrorNodes::iterator
+ I = Eng.ExplicitBadSizedVLA.begin(),
+ E = Eng.ExplicitBadSizedVLA.end(); I!=E; ++I) {
+
+ // Determine whether this was a 'zero-sized' VLA or a VLA with an
+ // undefined size.
+ GRExprEngine::NodeTy* N = *I;
+ PostStmt PS = cast<PostStmt>(N->getLocation());
+ DeclStmt *DS = cast<DeclStmt>(PS.getStmt());
+ VarDecl* VD = cast<VarDecl>(*DS->decl_begin());
+ QualType T = Eng.getContext().getCanonicalType(VD->getType());
+ VariableArrayType* VT = cast<VariableArrayType>(T);
+ Expr* SizeExpr = VT->getSizeExpr();
+
+ std::string buf;
+ llvm::raw_string_ostream os(buf);
+ os << "The expression used to specify the number of elements in the "
+ "variable-length array (VLA) '"
+ << VD->getNameAsString() << "' evaluates to ";
+
+ bool isUndefined = Eng.getStateManager().GetSVal(N->getState(),
+ SizeExpr).isUndef();
+
+ if (isUndefined)
+ os << "an undefined or garbage value.";
+ else
+ os << "0. VLAs with no elements have undefined behavior.";
+
+ std::string shortBuf;
+ llvm::raw_string_ostream os_short(shortBuf);
+ os_short << "Variable-length array '" << VD->getNameAsString() << "' "
+ << (isUndefined ? "garbage value for array size"
+ : "has zero elements (undefined behavior)");
+
+ ArgReport *report = new ArgReport(*this, os_short.str().c_str(),
+ os.str().c_str(), N, SizeExpr);
+
+ report->addRange(SizeExpr->getSourceRange());
+ BR.EmitReport(report);
+ }
+ }
+
+ void registerInitialVisitors(BugReporterContext& BRC,
+ const ExplodedNode<GRState>* N,
+ BuiltinBugReport *R) {
+ registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
+ N);
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// __attribute__(nonnull) checking
+
+class VISIBILITY_HIDDEN CheckAttrNonNull : public GRSimpleAPICheck {
+ BugType *BT;
+ BugReporter &BR;
+
+public:
+ CheckAttrNonNull(BugReporter &br) : BT(0), BR(br) {}
+
+ virtual bool Audit(ExplodedNode<GRState>* N, GRStateManager& VMgr) {
+ CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
+ const GRState* state = N->getState();
+
+ SVal X = VMgr.GetSVal(state, CE->getCallee());
+
+ const FunctionDecl* FD = X.getAsFunctionDecl();
+ if (!FD)
+ return false;
+
+ const NonNullAttr* Att = FD->getAttr<NonNullAttr>();
+
+ if (!Att)
+ return false;
+
+ // Iterate through the arguments of CE and check them for null.
+ unsigned idx = 0;
+ bool hasError = false;
+
+ for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
+ ++I, ++idx) {
+
+ if (!VMgr.isEqual(state, *I, 0) || !Att->isNonNull(idx))
+ continue;
+
+ // Lazily allocate the BugType object if it hasn't already been created.
+ // Ownership is transferred to the BugReporter object once the BugReport
+ // is passed to 'EmitWarning'.
+ if (!BT) BT =
+ new BugType("Argument with 'nonnull' attribute passed null", "API");
+
+ RangedBugReport *R = new RangedBugReport(*BT,
+ "Null pointer passed as an argument to a "
+ "'nonnull' parameter", N);
+
+ R->addRange((*I)->getSourceRange());
+ BR.EmitReport(R);
+ hasError = true;
+ }
+
+ return hasError;
+ }
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Definitions for bug reporter visitors.
+//===----------------------------------------------------------------------===//
+
+static const Stmt *GetDerefExpr(const ExplodedNode<GRState> *N) {
+ // Pattern match for a few useful cases (do something smarter later):
+ // a[0], p->f, *p
+ const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
+
+ if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) {
+ if (U->getOpcode() == UnaryOperator::Deref)
+ return U->getSubExpr()->IgnoreParenCasts();
+ }
+ else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
+ 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();
+ }
+
+ return NULL;
+}
+
+static const Stmt *GetReceiverExpr(const ExplodedNode<GRState> *N) {
+ const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
+ if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
+ return ME->getReceiver();
+ return NULL;
+}
+
+static const Stmt *GetDenomExpr(const ExplodedNode<GRState> *N) {
+ const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
+ if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
+ return BE->getRHS();
+ return NULL;
+}
+
+static const Stmt *GetCalleeExpr(const ExplodedNode<GRState> *N) {
+ const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
+ if (const CallExpr *CE = dyn_cast<CallExpr>(S))
+ return CE->getCallee();
+ return NULL;
+}
+
+static const Stmt *GetRetValExpr(const ExplodedNode<GRState> *N) {
+ const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
+ if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(S))
+ return RS->getRetValue();
+ return NULL;
+}
+
+namespace {
+class VISIBILITY_HIDDEN FindLastStoreBRVisitor : public BugReporterVisitor {
+ const MemRegion *R;
+ SVal V;
+ bool satisfied;
+ const ExplodedNode<GRState> *StoreSite;
+public:
+ FindLastStoreBRVisitor(SVal v, const MemRegion *r)
+ : R(r), V(v), satisfied(false), StoreSite(0) {}
+
+ PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState> *N,
+ const ExplodedNode<GRState> *PrevN,
+ BugReporterContext& BRC) {
+
+ if (satisfied)
+ return NULL;
+
+ if (!StoreSite) {
+ GRStateManager &StateMgr = BRC.getStateManager();
+ const ExplodedNode<GRState> *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;
+ }
+ }
+
+ if (StateMgr.GetSVal(Node->getState(), R) != V)
+ break;
+ }
+
+ if (!Node || !Last) {
+ satisfied = true;
+ return NULL;
+ }
+
+ StoreSite = Last;
+ }
+
+ if (StoreSite != N)
+ return NULL;
+
+ satisfied = true;
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+
+ 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()->getNameAsString() << "' ";
+ }
+ else
+ return NULL;
+
+ if (isa<loc::ConcreteInt>(V)) {
+ bool b = false;
+ ASTContext &C = BRC.getASTContext();
+ if (R->isBoundable(C)) {
+ if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+ if (C.isObjCObjectPointerType(TR->getValueType(C))) {
+ os << "initialized to nil";
+ b = true;
+ }
+ }
+ }
+
+ if (!b)
+ os << "initialized to a null pointer value";
+ }
+ else if (isa<nonloc::ConcreteInt>(V)) {
+ os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue();
+ }
+ 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 (os.str().empty()) {
+ if (isa<loc::ConcreteInt>(V)) {
+ bool b = false;
+ ASTContext &C = BRC.getASTContext();
+ if (R->isBoundable(C)) {
+ if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+ if (C.isObjCObjectPointerType(TR->getValueType(C))) {
+ os << "nil object reference stored to ";
+ b = true;
+ }
+ }
+ }
+
+ if (!b)
+ os << "Null pointer value stored to ";
+ }
+ else if (V.isUndef()) {
+ os << "Uninitialized value stored to ";
+ }
+ else
+ return NULL;
+
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ os << '\'' << VR->getDecl()->getNameAsString() << '\'';
+ }
+ else
+ return NULL;
+ }
+
+ // FIXME: Refactor this into BugReporterContext.
+ Stmt *S = 0;
+ ProgramPoint P = N->getLocation();
+
+ if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ CFGBlock *BSrc = BE->getSrc();
+ S = BSrc->getTerminatorCondition();
+ }
+ else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
+ S = PS->getStmt();
+ }
+
+ if (!S)
+ return NULL;
+
+ // Construct a new PathDiagnosticPiece.
+ PathDiagnosticLocation L(S, BRC.getSourceManager());
+ return new PathDiagnosticEventPiece(L, os.str());
+ }
+};
+
+
+static void registerFindLastStore(BugReporterContext& BRC, const MemRegion *R,
+ SVal V) {
+ BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
+}
+
+class VISIBILITY_HIDDEN TrackConstraintBRVisitor : public BugReporterVisitor {
+ SVal Constraint;
+ const bool Assumption;
+ bool isSatisfied;
+public:
+ TrackConstraintBRVisitor(SVal constraint, bool assumption)
+ : Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
+
+ PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState> *N,
+ const ExplodedNode<GRState> *PrevN,
+ BugReporterContext& BRC) {
+ if (isSatisfied)
+ return NULL;
+
+ // Check if in the previous state it was feasible for this constraint
+ // to *not* be true.
+
+ GRStateManager &StateMgr = BRC.getStateManager();
+ bool isFeasible = false;
+ if (StateMgr.Assume(PrevN->getState(), Constraint, !Assumption,
+ isFeasible)) {
+ assert(isFeasible); // Eventually we don't need 'isFeasible'.
+
+ 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.
+ isFeasible = false;
+ if (StateMgr.Assume(N->getState(), Constraint, !Assumption,
+ isFeasible)) {
+ assert(isFeasible);
+ 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);
+
+ if (isa<Loc>(Constraint)) {
+ os << "Assuming pointer value is ";
+ os << (Assumption ? "non-null" : "null");
+ }
+
+ if (os.str().empty())
+ return NULL;
+
+ // FIXME: Refactor this into BugReporterContext.
+ Stmt *S = 0;
+ ProgramPoint P = N->getLocation();
+
+ if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ CFGBlock *BSrc = BE->getSrc();
+ S = BSrc->getTerminatorCondition();
+ }
+ else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
+ S = PS->getStmt();
+ }
+
+ if (!S)
+ return NULL;
+
+ // Construct a new PathDiagnosticPiece.
+ PathDiagnosticLocation L(S, BRC.getSourceManager());
+ return new PathDiagnosticEventPiece(L, os.str());
+ }
+
+ return NULL;
+ }
+};
+} // end anonymous namespace
+
+static void registerTrackConstraint(BugReporterContext& BRC, SVal Constraint,
+ bool Assumption) {
+ BRC.addVisitor(new TrackConstraintBRVisitor(Constraint, Assumption));
+}
+
+static void registerTrackNullOrUndefValue(BugReporterContext& BRC,
+ const Stmt *S,
+ const ExplodedNode<GRState>* N) {
+
+ if (!S)
+ return;
+
+ GRStateManager &StateMgr = BRC.getStateManager();
+ const GRState *state = N->getState();
+
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ const VarRegion *R =
+ StateMgr.getRegionManager().getVarRegion(VD);
+
+ // What did we load?
+ SVal V = StateMgr.GetSVal(state, S);
+
+ if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
+ || V.isUndef()) {
+ registerFindLastStore(BRC, R, V);
+ }
+ }
+ }
+
+ SVal V = StateMgr.GetSValAsScalarOrLoc(state, S);
+
+ // Uncomment this to find cases where we aren't properly getting the
+ // base value that was dereferenced.
+ // assert(!V.isUnknownOrUndef());
+
+ // Is it a symbolic value?
+ if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
+ const SubRegion *R = cast<SubRegion>(L->getRegion());
+ while (R && !isa<SymbolicRegion>(R)) {
+ R = dyn_cast<SubRegion>(R->getSuperRegion());
+ }
+
+ if (R) {
+ assert(isa<SymbolicRegion>(R));
+ registerTrackConstraint(BRC, loc::MemRegionVal(R), false);
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Check registration.
+//===----------------------------------------------------------------------===//
+
+void GRExprEngine::RegisterInternalChecks() {
+ // Register internal "built-in" BugTypes with the BugReporter. These BugTypes
+ // are different than what probably many checks will do since they don't
+ // create BugReports on-the-fly but instead wait until GRExprEngine finishes
+ // analyzing a function. Generation of BugReport objects is done via a call
+ // to 'FlushReports' from BugReporter.
+ BR.Register(new NullDeref(this));
+ BR.Register(new UndefinedDeref(this));
+ BR.Register(new UndefBranch(this));
+ BR.Register(new DivZero(this));
+ BR.Register(new UndefResult(this));
+ BR.Register(new BadCall(this));
+ BR.Register(new RetStack(this));
+ BR.Register(new RetUndef(this));
+ BR.Register(new BadArg(this));
+ BR.Register(new BadMsgExprArg(this));
+ BR.Register(new BadReceiver(this));
+ BR.Register(new OutOfBoundMemoryAccess(this));
+ BR.Register(new BadSizeVLA(this));
+ BR.Register(new NilReceiverStructRet(this));
+ BR.Register(new NilReceiverLargerThanVoidPtrRet(this));
+
+ // The following checks do not need to have their associated BugTypes
+ // explicitly registered with the BugReporter. If they issue any BugReports,
+ // their associated BugType will get registered with the BugReporter
+ // automatically. Note that the check itself is owned by the GRExprEngine
+ // object.
+ AddCheck(new CheckAttrNonNull(BR), Stmt::CallExprClass);
+}
diff --git a/lib/Analysis/GRSimpleVals.cpp b/lib/Analysis/GRSimpleVals.cpp
new file mode 100644
index 000000000000..e1c4848f4559
--- /dev/null
+++ b/lib/Analysis/GRSimpleVals.cpp
@@ -0,0 +1,416 @@
+// GRSimpleVals.cpp - Transfer functions for tracking simple 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 defines GRSimpleVals, a sub-class of GRTransferFuncs that
+// provides transfer functions for performing simple value tracking with
+// limited support for symbolics.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRSimpleVals.h"
+#include "BasicObjCFoundationChecks.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "llvm/Support/Compiler.h"
+#include <sstream>
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Transfer Function creation for External clients.
+//===----------------------------------------------------------------------===//
+
+GRTransferFuncs* clang::MakeGRSimpleValsTF() { return new GRSimpleVals(); }
+
+//===----------------------------------------------------------------------===//
+// Transfer function for Casts.
+//===----------------------------------------------------------------------===//
+
+SVal GRSimpleVals::EvalCast(GRExprEngine& Eng, NonLoc X, QualType T) {
+
+ if (!isa<nonloc::ConcreteInt>(X))
+ return UnknownVal();
+
+ bool isLocType = Loc::IsLocType(T);
+
+ // Only handle casts from integers to integers.
+ if (!isLocType && !T->isIntegerType())
+ return UnknownVal();
+
+ BasicValueFactory& BasicVals = Eng.getBasicVals();
+
+ llvm::APSInt V = cast<nonloc::ConcreteInt>(X).getValue();
+ V.setIsUnsigned(T->isUnsignedIntegerType() || Loc::IsLocType(T));
+ V.extOrTrunc(Eng.getContext().getTypeSize(T));
+
+ if (isLocType)
+ return loc::ConcreteInt(BasicVals.getValue(V));
+ else
+ return nonloc::ConcreteInt(BasicVals.getValue(V));
+}
+
+// Casts.
+
+SVal GRSimpleVals::EvalCast(GRExprEngine& Eng, Loc X, QualType T) {
+
+ // Casts from pointers -> pointers, just return the lval.
+ //
+ // Casts from pointers -> references, just return the lval. These
+ // can be introduced by the frontend for corner cases, e.g
+ // casting from va_list* to __builtin_va_list&.
+ //
+ assert (!X.isUnknownOrUndef());
+
+ if (Loc::IsLocType(T) || T->isReferenceType())
+ return X;
+
+ // FIXME: Handle transparent unions where a value can be "transparently"
+ // lifted into a union type.
+ if (T->isUnionType())
+ return UnknownVal();
+
+ assert (T->isIntegerType());
+ BasicValueFactory& BasicVals = Eng.getBasicVals();
+ unsigned BitWidth = Eng.getContext().getTypeSize(T);
+
+ if (!isa<loc::ConcreteInt>(X))
+ return nonloc::LocAsInteger::Make(BasicVals, X, BitWidth);
+
+ llvm::APSInt V = cast<loc::ConcreteInt>(X).getValue();
+ V.setIsUnsigned(T->isUnsignedIntegerType() || Loc::IsLocType(T));
+ V.extOrTrunc(BitWidth);
+ return nonloc::ConcreteInt(BasicVals.getValue(V));
+}
+
+// Unary operators.
+
+SVal GRSimpleVals::EvalMinus(GRExprEngine& Eng, UnaryOperator* U, NonLoc X){
+
+ switch (X.getSubKind()) {
+
+ case nonloc::ConcreteIntKind:
+ return cast<nonloc::ConcreteInt>(X).EvalMinus(Eng.getBasicVals(), U);
+
+ default:
+ return UnknownVal();
+ }
+}
+
+SVal GRSimpleVals::EvalComplement(GRExprEngine& Eng, NonLoc X) {
+
+ switch (X.getSubKind()) {
+
+ case nonloc::ConcreteIntKind:
+ return cast<nonloc::ConcreteInt>(X).EvalComplement(Eng.getBasicVals());
+
+ default:
+ return UnknownVal();
+ }
+}
+
+// Binary operators.
+
+static unsigned char LNotOpMap[] = {
+ (unsigned char) BinaryOperator::GE, /* LT => GE */
+ (unsigned char) BinaryOperator::LE, /* GT => LE */
+ (unsigned char) BinaryOperator::GT, /* LE => GT */
+ (unsigned char) BinaryOperator::LT, /* GE => LT */
+ (unsigned char) BinaryOperator::NE, /* EQ => NE */
+ (unsigned char) BinaryOperator::EQ /* NE => EQ */
+};
+
+SVal GRSimpleVals::DetermEvalBinOpNN(GRExprEngine& Eng,
+ BinaryOperator::Opcode Op,
+ NonLoc L, NonLoc R,
+ QualType T) {
+
+ BasicValueFactory& BasicVals = Eng.getBasicVals();
+ unsigned subkind = L.getSubKind();
+
+ while (1) {
+
+ switch (subkind) {
+ default:
+ return UnknownVal();
+
+ case nonloc::LocAsIntegerKind: {
+ Loc LL = cast<nonloc::LocAsInteger>(L).getLoc();
+
+ switch (R.getSubKind()) {
+ case nonloc::LocAsIntegerKind:
+ return EvalBinOp(Eng, Op, LL,
+ cast<nonloc::LocAsInteger>(R).getLoc());
+
+ case nonloc::ConcreteIntKind: {
+ // Transform the integer into a location and compare.
+ ASTContext& Ctx = Eng.getContext();
+ llvm::APSInt V = cast<nonloc::ConcreteInt>(R).getValue();
+ V.setIsUnsigned(true);
+ V.extOrTrunc(Ctx.getTypeSize(Ctx.VoidPtrTy));
+ return EvalBinOp(Eng, Op, LL,
+ loc::ConcreteInt(BasicVals.getValue(V)));
+ }
+
+ default:
+ switch (Op) {
+ case BinaryOperator::EQ:
+ return NonLoc::MakeIntTruthVal(BasicVals, false);
+ case BinaryOperator::NE:
+ return NonLoc::MakeIntTruthVal(BasicVals, true);
+ default:
+ // This case also handles pointer arithmetic.
+ return UnknownVal();
+ }
+ }
+ }
+
+ case nonloc::SymExprValKind: {
+ // Logical not?
+ if (!(Op == BinaryOperator::EQ && R.isZeroConstant()))
+ return UnknownVal();
+
+ const SymExpr &SE=*cast<nonloc::SymExprVal>(L).getSymbolicExpression();
+
+ // Only handle ($sym op constant) for now.
+ if (const SymIntExpr *E = dyn_cast<SymIntExpr>(&SE)) {
+ BinaryOperator::Opcode Opc = E->getOpcode();
+
+ if (Opc < BinaryOperator::LT || Opc > BinaryOperator::NE)
+ return UnknownVal();
+
+ // For comparison operators, translate the constraint by
+ // changing the opcode.
+ int idx = (unsigned) Opc - (unsigned) BinaryOperator::LT;
+
+ assert (idx >= 0 &&
+ (unsigned) idx < sizeof(LNotOpMap)/sizeof(unsigned char));
+
+ Opc = (BinaryOperator::Opcode) LNotOpMap[idx];
+ assert(E->getType(Eng.getContext()) == T);
+ E = Eng.getSymbolManager().getSymIntExpr(E->getLHS(), Opc,
+ E->getRHS(), T);
+ return nonloc::SymExprVal(E);
+ }
+
+ return UnknownVal();
+ }
+
+ case nonloc::ConcreteIntKind:
+
+ if (isa<nonloc::ConcreteInt>(R)) {
+ const nonloc::ConcreteInt& L_CI = cast<nonloc::ConcreteInt>(L);
+ const nonloc::ConcreteInt& R_CI = cast<nonloc::ConcreteInt>(R);
+ return L_CI.EvalBinOp(BasicVals, Op, R_CI);
+ }
+ else {
+ subkind = R.getSubKind();
+ NonLoc tmp = R;
+ R = L;
+ L = tmp;
+
+ // Swap the operators.
+ switch (Op) {
+ case BinaryOperator::LT: Op = BinaryOperator::GT; break;
+ case BinaryOperator::GT: Op = BinaryOperator::LT; break;
+ case BinaryOperator::LE: Op = BinaryOperator::GE; break;
+ case BinaryOperator::GE: Op = BinaryOperator::LE; break;
+ default: break;
+ }
+
+ continue;
+ }
+
+ case nonloc::SymbolValKind:
+ if (isa<nonloc::ConcreteInt>(R)) {
+ ValueManager &ValMgr = Eng.getValueManager();
+ return ValMgr.makeNonLoc(cast<nonloc::SymbolVal>(L).getSymbol(), Op,
+ cast<nonloc::ConcreteInt>(R).getValue(), T);
+ }
+ else
+ return UnknownVal();
+ }
+ }
+}
+
+
+// Binary Operators (except assignments and comma).
+
+SVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
+ Loc L, Loc R) {
+
+ switch (Op) {
+ default:
+ return UnknownVal();
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ return EvalEquality(Eng, L, R, Op == BinaryOperator::EQ);
+ }
+}
+
+SVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, const GRState *state,
+ BinaryOperator::Opcode Op, Loc L, NonLoc R) {
+
+ // Special case: 'R' is an integer that has the same width as a pointer and
+ // we are using the integer location in a comparison. Normally this cannot be
+ // triggered, but transfer functions like those for OSCommpareAndSwapBarrier32
+ // can generate comparisons that trigger this code.
+ // FIXME: Are all locations guaranteed to have pointer width?
+ if (BinaryOperator::isEqualityOp(Op)) {
+ if (nonloc::ConcreteInt *RInt = dyn_cast<nonloc::ConcreteInt>(&R)) {
+ const llvm::APSInt *X = &RInt->getValue();
+ ASTContext &C = Eng.getContext();
+ if (C.getTypeSize(C.VoidPtrTy) == X->getBitWidth()) {
+ // Convert the signedness of the integer (if necessary).
+ if (X->isSigned())
+ X = &Eng.getBasicVals().getValue(*X, true);
+
+ return EvalBinOp(Eng, Op, L, loc::ConcreteInt(*X));
+ }
+ }
+ }
+
+ // Delegate pointer arithmetic to store manager.
+ return Eng.getStoreManager().EvalBinOp(state, Op, L, R);
+}
+
+// Equality operators for Locs.
+// FIXME: All this logic will be revamped when we have MemRegion::getLocation()
+// implemented.
+
+SVal GRSimpleVals::EvalEquality(GRExprEngine& Eng, Loc L, Loc R, bool isEqual) {
+
+ BasicValueFactory& BasicVals = Eng.getBasicVals();
+
+ switch (L.getSubKind()) {
+
+ default:
+ assert(false && "EQ/NE not implemented for this Loc.");
+ return UnknownVal();
+
+ case loc::ConcreteIntKind:
+
+ if (isa<loc::ConcreteInt>(R)) {
+ bool b = cast<loc::ConcreteInt>(L).getValue() ==
+ cast<loc::ConcreteInt>(R).getValue();
+
+ // Are we computing '!='? Flip the result.
+ if (!isEqual)
+ b = !b;
+
+ return NonLoc::MakeIntTruthVal(BasicVals, b);
+ }
+ else if (SymbolRef Sym = R.getAsSymbol()) {
+ const SymIntExpr * SE =
+ Eng.getSymbolManager().getSymIntExpr(Sym,
+ isEqual ? BinaryOperator::EQ
+ : BinaryOperator::NE,
+ cast<loc::ConcreteInt>(L).getValue(),
+ Eng.getContext().IntTy);
+ return nonloc::SymExprVal(SE);
+ }
+
+ break;
+
+ case loc::MemRegionKind: {
+ if (SymbolRef LSym = L.getAsLocSymbol()) {
+ if (isa<loc::ConcreteInt>(R)) {
+ const SymIntExpr *SE =
+ Eng.getSymbolManager().getSymIntExpr(LSym,
+ isEqual ? BinaryOperator::EQ
+ : BinaryOperator::NE,
+ cast<loc::ConcreteInt>(R).getValue(),
+ Eng.getContext().IntTy);
+
+ return nonloc::SymExprVal(SE);
+ }
+ }
+ }
+
+ // Fall-through.
+
+ case loc::GotoLabelKind:
+ return NonLoc::MakeIntTruthVal(BasicVals, isEqual ? L == R : L != R);
+ }
+
+ return NonLoc::MakeIntTruthVal(BasicVals, isEqual ? false : true);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function for function calls.
+//===----------------------------------------------------------------------===//
+
+void GRSimpleVals::EvalCall(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Eng,
+ GRStmtNodeBuilder<GRState>& Builder,
+ CallExpr* CE, SVal L,
+ ExplodedNode<GRState>* Pred) {
+
+ GRStateManager& StateMgr = Eng.getStateManager();
+ const GRState* St = Builder.GetState(Pred);
+
+ // Invalidate all arguments passed in by reference (Locs).
+
+ for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
+ I != E; ++I) {
+
+ SVal V = StateMgr.GetSVal(St, *I);
+
+ if (isa<loc::MemRegionVal>(V))
+ St = StateMgr.BindLoc(St, cast<Loc>(V), UnknownVal());
+ else if (isa<nonloc::LocAsInteger>(V))
+ St = StateMgr.BindLoc(St, cast<nonloc::LocAsInteger>(V).getLoc(),
+ UnknownVal());
+
+ }
+
+ // Make up a symbol for the return value of this function.
+ // FIXME: We eventually should handle structs and other compound types
+ // that are returned by value.
+ QualType T = CE->getType();
+ if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
+ unsigned Count = Builder.getCurrentBlockCount();
+ SVal X = Eng.getValueManager().getConjuredSymbolVal(CE, Count);
+ St = StateMgr.BindExpr(St, CE, X, Eng.getCFG().isBlkExpr(CE), false);
+ }
+
+ Builder.MakeNode(Dst, CE, Pred, St);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function for Objective-C message expressions.
+//===----------------------------------------------------------------------===//
+
+void GRSimpleVals::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Eng,
+ GRStmtNodeBuilder<GRState>& Builder,
+ ObjCMessageExpr* ME,
+ ExplodedNode<GRState>* Pred) {
+
+
+ // The basic transfer function logic for message expressions does nothing.
+ // We just invalidate all arguments passed in by references.
+
+ GRStateManager& StateMgr = Eng.getStateManager();
+ const GRState* St = Builder.GetState(Pred);
+
+ for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end();
+ I != E; ++I) {
+
+ SVal V = StateMgr.GetSVal(St, *I);
+
+ if (isa<Loc>(V))
+ St = StateMgr.BindLoc(St, cast<Loc>(V), UnknownVal());
+ }
+
+ Builder.MakeNode(Dst, ME, Pred, St);
+}
diff --git a/lib/Analysis/GRSimpleVals.h b/lib/Analysis/GRSimpleVals.h
new file mode 100644
index 000000000000..6ef49dcdd22e
--- /dev/null
+++ b/lib/Analysis/GRSimpleVals.h
@@ -0,0 +1,86 @@
+// GRSimpleVals.h - Transfer functions for tracking simple 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 defines GRSimpleVals, a sub-class of GRTransferFuncs that
+// provides transfer functions for performing simple value tracking with
+// limited support for symbolics.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRSIMPLEVALS
+#define LLVM_CLANG_ANALYSIS_GRSIMPLEVALS
+
+#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+
+namespace clang {
+
+class PathDiagnostic;
+class ASTContext;
+
+class GRSimpleVals : public GRTransferFuncs {
+protected:
+
+ virtual SVal DetermEvalBinOpNN(GRExprEngine& Eng,
+ BinaryOperator::Opcode Op,
+ NonLoc L, NonLoc R, QualType T);
+
+public:
+ GRSimpleVals() {}
+ virtual ~GRSimpleVals() {}
+
+ // Casts.
+
+ virtual SVal EvalCast(GRExprEngine& Engine, NonLoc V, QualType CastT);
+ virtual SVal EvalCast(GRExprEngine& Engine, Loc V, QualType CastT);
+
+ // Unary Operators.
+
+ virtual SVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLoc X);
+
+ virtual SVal EvalComplement(GRExprEngine& Engine, NonLoc X);
+
+ // Binary Operators.
+
+ virtual SVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
+ Loc L, Loc R);
+
+ // Pointer arithmetic.
+
+ virtual SVal EvalBinOp(GRExprEngine& Engine, const GRState *state,
+ BinaryOperator::Opcode Op, Loc L, NonLoc R);
+
+ // Calls.
+
+ virtual void EvalCall(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder<GRState>& Builder,
+ CallExpr* CE, SVal L,
+ ExplodedNode<GRState>* Pred);
+
+ virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder<GRState>& Builder,
+ ObjCMessageExpr* ME,
+ ExplodedNode<GRState>* Pred);
+
+
+
+ static void GeneratePathDiagnostic(PathDiagnostic& PD, ASTContext& Ctx,
+ ExplodedNode<GRState>* N);
+
+protected:
+
+ // Equality (==, !=) operators for Locs.
+ SVal EvalEquality(GRExprEngine& Engine, Loc L, Loc R, bool isEqual);
+};
+
+} // end clang namespace
+
+#endif
diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp
new file mode 100644
index 000000000000..e0e478c30717
--- /dev/null
+++ b/lib/Analysis/GRState.cpp
@@ -0,0 +1,318 @@
+//= GRState*cpp - Path-Sens. "State" for tracking valuues -----*- 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 SymbolRef, ExprBindKey, and GRState*
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/GRStateTrait.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+// Give the vtable for ConstraintManager somewhere to live.
+ConstraintManager::~ConstraintManager() {}
+
+GRStateManager::~GRStateManager() {
+ for (std::vector<GRState::Printer*>::iterator I=Printers.begin(),
+ E=Printers.end(); I!=E; ++I)
+ delete *I;
+
+ 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, Stmt* Loc,
+ SymbolReaper& SymReaper) {
+
+ // This code essentially performs a "mark-and-sweep" of the VariableBindings.
+ // The roots are any Block-level exprs and Decls that our liveness algorithm
+ // tells us are live. We then see what Decls they may reference, and keep
+ // 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;
+
+ NewState.Env = EnvMgr.RemoveDeadBindings(NewState.Env, Loc, SymReaper, *this,
+ state, RegionRoots);
+
+ // Clean up the store.
+ NewState.St = StoreMgr->RemoveDeadBindings(&NewState, Loc, SymReaper,
+ RegionRoots);
+
+ return ConstraintMgr->RemoveDeadBindings(getPersistentState(NewState),
+ SymReaper);
+}
+
+const GRState* GRStateManager::Unbind(const GRState* St, Loc LV) {
+ Store OldStore = St->getStore();
+ Store NewStore = StoreMgr->Remove(OldStore, LV);
+
+ if (NewStore == OldStore)
+ return St;
+
+ GRState NewSt = *St;
+ NewSt.St = NewStore;
+ return getPersistentState(NewSt);
+}
+
+const GRState* GRStateManager::getInitialState() {
+
+ GRState StateImpl(EnvMgr.getInitialEnvironment(),
+ StoreMgr->getInitialStore(),
+ GDMFactory.GetEmptyMap());
+
+ return getPersistentState(StateImpl);
+}
+
+const GRState* GRStateManager::getPersistentState(GRState& State) {
+
+ llvm::FoldingSetNodeID ID;
+ State.Profile(ID);
+ void* InsertPos;
+
+ if (GRState* I = StateSet.FindNodeOrInsertPos(ID, InsertPos))
+ return I;
+
+ GRState* I = (GRState*) Alloc.Allocate<GRState>();
+ new (I) GRState(State);
+ StateSet.InsertNode(I, InsertPos);
+ return I;
+}
+
+const GRState* GRStateManager::MakeStateWithStore(const GRState* St,
+ Store store) {
+ GRState NewSt = *St;
+ NewSt.St = store;
+ return getPersistentState(NewSt);
+}
+
+
+//===----------------------------------------------------------------------===//
+// State pretty-printing.
+//===----------------------------------------------------------------------===//
+
+void GRState::print(std::ostream& Out, StoreManager& StoreMgr,
+ ConstraintManager& ConstraintMgr,
+ Printer** Beg, Printer** End,
+ const char* nl, const char* sep) const {
+
+ // Print the store.
+ StoreMgr.print(getStore(), Out, nl, sep);
+
+ // Print Subexpression bindings.
+ bool isFirst = true;
+
+ for (seb_iterator I = seb_begin(), E = seb_end(); I != E; ++I) {
+
+ if (isFirst) {
+ Out << nl << nl << "Sub-Expressions:" << nl;
+ isFirst = false;
+ }
+ else { Out << nl; }
+
+ Out << " (" << (void*) I.getKey() << ") ";
+ llvm::raw_os_ostream OutS(Out);
+ I.getKey()->printPretty(OutS);
+ OutS.flush();
+ Out << " : ";
+ I.getData().print(Out);
+ }
+
+ // Print block-expression bindings.
+ isFirst = true;
+
+ for (beb_iterator I = beb_begin(), E = beb_end(); I != E; ++I) {
+
+ if (isFirst) {
+ Out << nl << nl << "Block-level Expressions:" << nl;
+ isFirst = false;
+ }
+ else { Out << nl; }
+
+ Out << " (" << (void*) I.getKey() << ") ";
+ llvm::raw_os_ostream OutS(Out);
+ I.getKey()->printPretty(OutS);
+ OutS.flush();
+ Out << " : ";
+ I.getData().print(Out);
+ }
+
+ ConstraintMgr.print(this, Out, nl, sep);
+
+ // Print checker-specific data.
+ for ( ; Beg != End ; ++Beg) (*Beg)->Print(Out, this, nl, sep);
+}
+
+void GRStateRef::printDOT(std::ostream& Out) const {
+ print(Out, "\\l", "\\|");
+}
+
+void GRStateRef::printStdErr() const {
+ print(*llvm::cerr);
+}
+
+void GRStateRef::print(std::ostream& Out, const char* nl, const char* sep)const{
+ GRState::Printer **beg = Mgr->Printers.empty() ? 0 : &Mgr->Printers[0];
+ GRState::Printer **end = !beg ? 0 : beg + Mgr->Printers.size();
+ St->print(Out, *Mgr->StoreMgr, *Mgr->ConstraintMgr, beg, end, nl, sep);
+}
+
+//===----------------------------------------------------------------------===//
+// Generic Data Map.
+//===----------------------------------------------------------------------===//
+
+void* const* GRState::FindGDM(void* K) const {
+ return GDM.lookup(K);
+}
+
+void*
+GRStateManager::FindGDMContext(void* K,
+ void* (*CreateContext)(llvm::BumpPtrAllocator&),
+ void (*DeleteContext)(void*)) {
+
+ std::pair<void*, void (*)(void*)>& p = GDMContexts[K];
+ if (!p.first) {
+ p.first = CreateContext(Alloc);
+ p.second = DeleteContext;
+ }
+
+ 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);
+
+ if (M1 == M2)
+ return St;
+
+ GRState NewSt = *St;
+ NewSt.GDM = M2;
+ return getPersistentState(NewSt);
+}
+
+//===----------------------------------------------------------------------===//
+// Utility.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN ScanReachableSymbols : public SubRegionMap::Visitor {
+ typedef llvm::DenseSet<const MemRegion*> VisitedRegionsTy;
+
+ VisitedRegionsTy visited;
+ GRStateRef state;
+ SymbolVisitor &visitor;
+ llvm::OwningPtr<SubRegionMap> SRM;
+public:
+
+ ScanReachableSymbols(GRStateManager* sm, const GRState *st, SymbolVisitor& v)
+ : state(st, *sm), 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))
+ return false;
+
+ return true;
+}
+
+bool ScanReachableSymbols::scan(SVal val) {
+ if (loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&val))
+ return scan(X->getRegion());
+
+ if (SymbolRef Sym = val.getAsSymbol())
+ return visitor.VisitSymbol(Sym);
+
+ if (nonloc::CompoundVal *X = dyn_cast<nonloc::CompoundVal>(&val))
+ return scan(*X);
+
+ return true;
+}
+
+bool ScanReachableSymbols::scan(const MemRegion *R) {
+ if (isa<MemSpaceRegion>(R) || visited.count(R))
+ return true;
+
+ visited.insert(R);
+
+ // If this is a symbolic region, visit the symbol for the region.
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
+ if (!visitor.VisitSymbol(SR->getSymbol()))
+ return false;
+
+ // If this is a subregion, also visit the parent regions.
+ if (const SubRegion *SR = dyn_cast<SubRegion>(R))
+ if (!scan(SR->getSuperRegion()))
+ return false;
+
+ // Now look at the binding to this region (if any).
+ if (!scan(state.GetSValAsScalarOrLoc(R)))
+ return false;
+
+ // Now look at the subregions.
+ if (!SRM.get())
+ SRM.reset(state.getManager().getStoreManager().getSubRegionMap(state));
+
+ return SRM->iterSubRegions(R, *this);
+}
+
+bool GRStateManager::scanReachableSymbols(SVal val, const GRState* state,
+ SymbolVisitor& visitor) {
+ ScanReachableSymbols S(this, state, visitor);
+ return S.scan(val);
+}
+
+//===----------------------------------------------------------------------===//
+// Queries.
+//===----------------------------------------------------------------------===//
+
+bool GRStateManager::isEqual(const GRState* state, Expr* Ex,
+ const llvm::APSInt& Y) {
+
+ SVal V = GetSVal(state, Ex);
+
+ if (loc::ConcreteInt* X = dyn_cast<loc::ConcreteInt>(&V))
+ return X->getValue() == Y;
+
+ if (nonloc::ConcreteInt* X = dyn_cast<nonloc::ConcreteInt>(&V))
+ return X->getValue() == Y;
+
+ if (SymbolRef Sym = V.getAsSymbol())
+ return ConstraintMgr->isEqual(state, Sym, Y);
+
+ return false;
+}
+
+bool GRStateManager::isEqual(const GRState* state, Expr* Ex, uint64_t x) {
+ return isEqual(state, Ex, getBasicVals().getValue(x, Ex->getType()));
+}
+
+//===----------------------------------------------------------------------===//
+// Persistent values for indexing into the Generic Data Map.
+
+int GRState::NullDerefTag::TagInt = 0;
+
diff --git a/lib/Analysis/GRTransferFuncs.cpp b/lib/Analysis/GRTransferFuncs.cpp
new file mode 100644
index 000000000000..69c09d9a2ec5
--- /dev/null
+++ b/lib/Analysis/GRTransferFuncs.cpp
@@ -0,0 +1,28 @@
+//== GRTransferFuncs.cpp - 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 GRTransferFuncs, which provides a base-class that
+// defines an interface for transfer functions used by GRExprEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+
+using namespace clang;
+
+void GRTransferFuncs::EvalBinOpNN(GRStateSet& OStates,
+ GRExprEngine& Eng,
+ const GRState *St, Expr* Ex,
+ BinaryOperator::Opcode Op,
+ NonLoc L, NonLoc R, QualType T) {
+
+ OStates.Add(Eng.getStateManager().BindExpr(St, Ex,
+ DetermEvalBinOpNN(Eng, Op, L, R, T)));
+}
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
new file mode 100644
index 000000000000..b0eb37b06524
--- /dev/null
+++ b/lib/Analysis/LiveVariables.cpp
@@ -0,0 +1,359 @@
+//=- 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/CFG.h"
+#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
+#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Compiler.h"
+
+#include <string.h>
+#include <stdio.h>
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Useful constants.
+//===----------------------------------------------------------------------===//
+
+static const bool Alive = true;
+static const bool Dead = false;
+
+//===----------------------------------------------------------------------===//
+// Dataflow initialization logic.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN RegisterDecls
+ : public CFGRecStmtDeclVisitor<RegisterDecls> {
+
+ LiveVariables::AnalysisDataTy& AD;
+
+ typedef llvm::SmallVector<VarDecl*, 20> AlwaysLiveTy;
+ AlwaysLiveTy AlwaysLive;
+
+
+public:
+ RegisterDecls(LiveVariables::AnalysisDataTy& ad) : AD(ad) {}
+
+ ~RegisterDecls() {
+
+ AD.AlwaysLive.resetValues(AD);
+
+ 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 VisitVarDecl(VarDecl* VD) {
+ // Register the VarDecl for tracking.
+ AD.Register(VD);
+
+ // Does the variable have global storage? If so, it is always live.
+ if (VD->hasGlobalStorage())
+ AlwaysLive.push_back(VD);
+ }
+
+ CFG& getCFG() { return AD.getCFG(); }
+};
+} // end anonymous namespace
+
+LiveVariables::LiveVariables(ASTContext& Ctx, CFG& cfg) {
+ // Register all referenced VarDecls.
+ getAnalysisData().setCFG(cfg);
+ getAnalysisData().setContext(Ctx);
+
+ RegisterDecls R(getAnalysisData());
+ cfg.VisitBlockStmts(R);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer functions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class VISIBILITY_HIDDEN TransferFuncs : public CFGRecStmtVisitor<TransferFuncs>{
+ LiveVariables::AnalysisDataTy& AD;
+ LiveVariables::ValTy LiveState;
+public:
+ TransferFuncs(LiveVariables::AnalysisDataTy& ad) : AD(ad) {}
+
+ LiveVariables::ValTy& getVal() { return LiveState; }
+ CFG& getCFG() { return AD.getCFG(); }
+
+ void VisitDeclRefExpr(DeclRefExpr* DR);
+ void VisitBinaryOperator(BinaryOperator* 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);
+
+ void SetTopValue(LiveVariables::ValTy& V) {
+ V = AD.AlwaysLive;
+ }
+
+};
+
+void TransferFuncs::Visit(Stmt *S) {
+
+ if (S == getCurrentBlkStmt()) {
+
+ if (AD.Observer)
+ AD.Observer->ObserveStmt(S,AD,LiveState);
+
+ if (getCFG().isBlkExpr(S)) LiveState(S,AD) = Dead;
+ StmtVisitor<TransferFuncs,void>::Visit(S);
+ }
+ else if (!getCFG().isBlkExpr(S)) {
+
+ if (AD.Observer)
+ AD.Observer->ObserveStmt(S,AD,LiveState);
+
+ StmtVisitor<TransferFuncs,void>::Visit(S);
+
+ }
+ else
+ // For block-level expressions, mark that they are live.
+ LiveState(S,AD) = Alive;
+}
+
+void TransferFuncs::VisitTerminator(CFGBlock* B) {
+
+ const Stmt* E = B->getTerminatorCondition();
+
+ if (!E)
+ return;
+
+ assert (getCFG().isBlkExpr(E));
+ LiveState(E, AD) = Alive;
+}
+
+void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
+ if (VarDecl* V = dyn_cast<VarDecl>(DR->getDecl()))
+ LiveState(V,AD) = Alive;
+}
+
+void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
+ if (B->isAssignmentOp()) VisitAssign(B);
+ else VisitStmt(B);
+}
+
+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());
+
+ // This represents a 'kill' for the variable.
+ Stmt* Element = S->getElement();
+ DeclRefExpr* DR = 0;
+ VarDecl* VD = 0;
+
+ 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;
+ }
+ }
+
+ if (VD) {
+ LiveState(VD, AD) = Dead;
+ if (AD.Observer && DR) { AD.Observer->ObserverKill(DR); }
+ }
+}
+
+
+void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
+ Expr *E = U->getSubExpr();
+
+ switch (U->getOpcode()) {
+ case UnaryOperator::PostInc:
+ case UnaryOperator::PostDec:
+ case UnaryOperator::PreInc:
+ case UnaryOperator::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);
+ }
+}
+
+void TransferFuncs::VisitAssign(BinaryOperator* B) {
+ Expr* LHS = B->getLHS();
+
+ // Assigning to a variable?
+ if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParens())) {
+
+ // 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() != BinaryOperator::Assign)
+ VisitDeclRefExpr(DR);
+ }
+ else // Not assigning to a variable. Process LHS as usual.
+ Visit(LHS);
+
+ Visit(B->getRHS());
+}
+
+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)) {
+ // The initializer is evaluated after the variable comes into scope.
+ // Since this is a reverse dataflow analysis, we must evaluate the
+ // transfer function for this expression first.
+ 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);
+ }
+
+ // Update liveness information by killing the VarDecl.
+ unsigned bit = AD.getIdx(VD);
+ LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit);
+ }
+}
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Merge operator: if something is live on any successor block, it is live
+// in the current block (a set union).
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+struct Merge {
+ typedef StmtDeclBitVector_Types::ValTy ValTy;
+
+ void operator()(ValTy& Dst, const ValTy& Src) {
+ Dst.OrDeclBits(Src);
+ Dst.OrBlkExprBits(Src);
+ }
+};
+
+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);
+ ObserverTy* OldObserver = getAnalysisData().Observer;
+ getAnalysisData().Observer = Obs;
+ S.runOnAllBlocks(cfg, recordStmtValues);
+ getAnalysisData().Observer = OldObserver;
+}
+
+//===----------------------------------------------------------------------===//
+// 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;
+}
+
+bool LiveVariables::isLive(const ValTy& Live, const VarDecl* D) const {
+ DeclBitVector_Types::Idx i = getAnalysisData().getIdx(D);
+ return i.isValid() ? Live.getBit(i) : false;
+}
+
+bool LiveVariables::isLive(const Stmt* Loc, const Stmt* StmtVal) const {
+ return getStmtData(Loc)(StmtVal,getAnalysisData());
+}
+
+bool LiveVariables::isLive(const Stmt* Loc, const VarDecl* D) const {
+ return getStmtData(Loc)(D,getAnalysisData());
+}
+
+//===----------------------------------------------------------------------===//
+// printing liveness state for debugging
+//
+
+void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const {
+ const AnalysisDataTy& AD = getAnalysisData();
+
+ for (AnalysisDataTy::decl_iterator I = AD.begin_decl(),
+ E = AD.end_decl(); I!=E; ++I)
+ if (V.getDeclBit(I->second)) {
+ fprintf(stderr, " %s <", I->first->getIdentifier()->getName());
+ I->first->getLocation().dump(SM);
+ fprintf(stderr, ">\n");
+ }
+}
+
+void LiveVariables::dumpBlockLiveness(SourceManager& M) const {
+ for (BlockDataMapTy::iterator I = getBlockDataMap().begin(),
+ E = getBlockDataMap().end(); I!=E; ++I) {
+ fprintf(stderr, "\n[ B%d (live variables at block exit) ]\n",
+ I->first->getBlockID());
+
+ dumpLiveness(I->second,M);
+ }
+
+ fprintf(stderr,"\n");
+}
diff --git a/lib/Analysis/Makefile b/lib/Analysis/Makefile
new file mode 100644
index 000000000000..c597254fd2d7
--- /dev/null
+++ b/lib/Analysis/Makefile
@@ -0,0 +1,22 @@
+##===- clang/lib/Analysis/Makefile -------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements analyses built on top of source-level CFGs.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+LIBRARYNAME := clangAnalysis
+BUILD_ARCHIVE = 1
+CXXFLAGS = -fno-rtti
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp
new file mode 100644
index 000000000000..9f066f44692f
--- /dev/null
+++ b/lib/Analysis/MemRegion.cpp
@@ -0,0 +1,494 @@
+//== MemRegion.cpp - Abstract memory regions for static 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 MemRegion and its subclasses. MemRegion defines a
+// partially-typed abstraction of memory useful for path-sensitive dataflow
+// analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/raw_ostream.h"
+#include "clang/Analysis/PathSensitive/MemRegion.h"
+
+using namespace clang;
+
+
+MemRegion::~MemRegion() {}
+
+bool SubRegion::isSubRegionOf(const MemRegion* R) const {
+ const MemRegion* r = getSuperRegion();
+ while (r != 0) {
+ if (r == R)
+ return true;
+ if (const SubRegion* sr = dyn_cast<SubRegion>(r))
+ r = sr->getSuperRegion();
+ else
+ break;
+ }
+ return false;
+}
+
+void MemSpaceRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddInteger((unsigned)getKind());
+}
+
+void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const StringLiteral* Str,
+ const MemRegion* superRegion) {
+ ID.AddInteger((unsigned) StringRegionKind);
+ ID.AddPointer(Str);
+ ID.AddPointer(superRegion);
+}
+
+void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const Expr* Ex, unsigned cnt) {
+ ID.AddInteger((unsigned) AllocaRegionKind);
+ ID.AddPointer(Ex);
+ ID.AddInteger(cnt);
+}
+
+void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ ProfileRegion(ID, Ex, Cnt);
+}
+
+void TypedViewRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, QualType T,
+ const MemRegion* superRegion) {
+ ID.AddInteger((unsigned) TypedViewRegionKind);
+ ID.Add(T);
+ ID.AddPointer(superRegion);
+}
+
+void CompoundLiteralRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ CompoundLiteralRegion::ProfileRegion(ID, CL, superRegion);
+}
+
+void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const CompoundLiteralExpr* CL,
+ const MemRegion* superRegion) {
+ ID.AddInteger((unsigned) CompoundLiteralRegionKind);
+ ID.AddPointer(CL);
+ ID.AddPointer(superRegion);
+}
+
+void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
+ const MemRegion* superRegion, Kind k) {
+ ID.AddInteger((unsigned) k);
+ ID.AddPointer(D);
+ ID.AddPointer(superRegion);
+}
+
+void DeclRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ DeclRegion::ProfileRegion(ID, D, superRegion, getKind());
+}
+
+void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym) {
+ ID.AddInteger((unsigned) MemRegion::SymbolicRegionKind);
+ ID.Add(sym);
+}
+
+void SymbolicRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ SymbolicRegion::ProfileRegion(ID, sym);
+}
+
+void ElementRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ QualType ElementType, SVal Idx,
+ const MemRegion* superRegion) {
+ ID.AddInteger(MemRegion::ElementRegionKind);
+ ID.Add(ElementType);
+ ID.AddPointer(superRegion);
+ Idx.Profile(ID);
+}
+
+void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ ElementRegion::ProfileRegion(ID, ElementType, Index, superRegion);
+}
+
+void CodeTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const void* data,
+ QualType t) {
+ ID.AddInteger(MemRegion::CodeTextRegionKind);
+ ID.AddPointer(data);
+ ID.Add(t);
+}
+
+void CodeTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ CodeTextRegion::ProfileRegion(ID, Data, LocationType);
+}
+
+//===----------------------------------------------------------------------===//
+// Region pretty-printing.
+//===----------------------------------------------------------------------===//
+
+std::string MemRegion::getString() const {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+ print(os);
+ return os.str();
+}
+
+void MemRegion::print(llvm::raw_ostream& os) const {
+ os << "<Unknown Region>";
+}
+
+void AllocaRegion::print(llvm::raw_ostream& os) const {
+ os << "alloca{" << (void*) Ex << ',' << Cnt << '}';
+}
+
+void CodeTextRegion::print(llvm::raw_ostream& os) const {
+ os << "code{";
+ if (isDeclared())
+ os << getDecl()->getDeclName().getAsString();
+ else
+ os << '$' << getSymbol();
+
+ os << '}';
+}
+
+void CompoundLiteralRegion::print(llvm::raw_ostream& os) const {
+ // FIXME: More elaborate pretty-printing.
+ os << "{ " << (void*) CL << " }";
+}
+
+void ElementRegion::print(llvm::raw_ostream& os) const {
+ superRegion->print(os);
+ os << '['; Index.print(os); os << ']';
+}
+
+void FieldRegion::print(llvm::raw_ostream& os) const {
+ superRegion->print(os);
+ os << "->" << getDecl()->getNameAsString();
+}
+
+void StringRegion::print(llvm::raw_ostream& os) const {
+ Str->printPretty(os);
+}
+
+void SymbolicRegion::print(llvm::raw_ostream& os) const {
+ os << "SymRegion-" << sym;
+}
+
+void TypedViewRegion::print(llvm::raw_ostream& os) const {
+ os << "typed_view{" << LValueType.getAsString() << ',';
+ getSuperRegion()->print(os);
+ os << '}';
+}
+
+void VarRegion::print(llvm::raw_ostream& os) const {
+ os << cast<VarDecl>(D)->getNameAsString();
+}
+
+//===----------------------------------------------------------------------===//
+// MemRegionManager methods.
+//===----------------------------------------------------------------------===//
+
+MemSpaceRegion* MemRegionManager::LazyAllocate(MemSpaceRegion*& region) {
+
+ if (!region) {
+ region = (MemSpaceRegion*) A.Allocate<MemSpaceRegion>();
+ new (region) MemSpaceRegion();
+ }
+
+ return region;
+}
+
+MemSpaceRegion* MemRegionManager::getStackRegion() {
+ return LazyAllocate(stack);
+}
+
+MemSpaceRegion* MemRegionManager::getGlobalsRegion() {
+ return LazyAllocate(globals);
+}
+
+MemSpaceRegion* MemRegionManager::getHeapRegion() {
+ return LazyAllocate(heap);
+}
+
+MemSpaceRegion* MemRegionManager::getUnknownRegion() {
+ return LazyAllocate(unknown);
+}
+
+MemSpaceRegion* MemRegionManager::getCodeRegion() {
+ return LazyAllocate(code);
+}
+
+bool MemRegionManager::onStack(const MemRegion* R) {
+ while (const SubRegion* SR = dyn_cast<SubRegion>(R))
+ R = SR->getSuperRegion();
+
+ return (R != 0) && (R == stack);
+}
+
+bool MemRegionManager::onHeap(const MemRegion* R) {
+ while (const SubRegion* SR = dyn_cast<SubRegion>(R))
+ R = SR->getSuperRegion();
+
+ return (R != 0) && (R == heap);
+}
+
+StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) {
+ llvm::FoldingSetNodeID ID;
+ MemSpaceRegion* GlobalsR = getGlobalsRegion();
+
+ StringRegion::ProfileRegion(ID, Str, GlobalsR);
+
+ void* InsertPos;
+ MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+ StringRegion* R = cast_or_null<StringRegion>(data);
+
+ if (!R) {
+ R = (StringRegion*) A.Allocate<StringRegion>();
+ new (R) StringRegion(Str, GlobalsR);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+VarRegion* MemRegionManager::getVarRegion(const VarDecl* d) {
+
+ const MemRegion* superRegion = d->hasLocalStorage() ? getStackRegion()
+ : getGlobalsRegion();
+
+ llvm::FoldingSetNodeID ID;
+ DeclRegion::ProfileRegion(ID, d, superRegion, MemRegion::VarRegionKind);
+
+ void* InsertPos;
+ MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+ VarRegion* R = cast_or_null<VarRegion>(data);
+
+ if (!R) {
+ R = (VarRegion*) A.Allocate<VarRegion>();
+ new (R) VarRegion(d, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+CompoundLiteralRegion*
+MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) {
+ // Is this compound literal allocated on the stack or is part of the
+ // global constant pool?
+ const MemRegion* superRegion = CL->isFileScope() ?
+ getGlobalsRegion() : getStackRegion();
+
+ // Profile the compound literal.
+ llvm::FoldingSetNodeID ID;
+ CompoundLiteralRegion::ProfileRegion(ID, CL, superRegion);
+
+ void* InsertPos;
+ MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+ CompoundLiteralRegion* R = cast_or_null<CompoundLiteralRegion>(data);
+
+ if (!R) {
+ R = (CompoundLiteralRegion*) A.Allocate<CompoundLiteralRegion>();
+ new (R) CompoundLiteralRegion(CL, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+ElementRegion*
+MemRegionManager::getElementRegion(QualType elementType, SVal Idx,
+ const MemRegion* superRegion){
+
+ llvm::FoldingSetNodeID ID;
+ ElementRegion::ProfileRegion(ID, elementType, Idx, superRegion);
+
+ void* InsertPos;
+ MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+ ElementRegion* R = cast_or_null<ElementRegion>(data);
+
+ if (!R) {
+ R = (ElementRegion*) A.Allocate<ElementRegion>();
+ new (R) ElementRegion(elementType, Idx, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+CodeTextRegion* MemRegionManager::getCodeTextRegion(const FunctionDecl* fd,
+ QualType t) {
+ llvm::FoldingSetNodeID ID;
+ CodeTextRegion::ProfileRegion(ID, fd, t);
+ void* InsertPos;
+ MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+ CodeTextRegion* R = cast_or_null<CodeTextRegion>(data);
+
+ if (!R) {
+ R = (CodeTextRegion*) A.Allocate<CodeTextRegion>();
+ new (R) CodeTextRegion(fd, t, getCodeRegion());
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+CodeTextRegion* MemRegionManager::getCodeTextRegion(SymbolRef sym, QualType t) {
+ llvm::FoldingSetNodeID ID;
+ CodeTextRegion::ProfileRegion(ID, sym, t);
+ void* InsertPos;
+ MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+ CodeTextRegion* R = cast_or_null<CodeTextRegion>(data);
+
+ if (!R) {
+ R = (CodeTextRegion*) A.Allocate<CodeTextRegion>();
+ new (R) CodeTextRegion(sym, t, getCodeRegion());
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
+SymbolicRegion* MemRegionManager::getSymbolicRegion(SymbolRef sym) {
+ llvm::FoldingSetNodeID ID;
+ SymbolicRegion::ProfileRegion(ID, sym);
+ void* InsertPos;
+ MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+ SymbolicRegion* R = cast_or_null<SymbolicRegion>(data);
+
+ if (!R) {
+ R = (SymbolicRegion*) A.Allocate<SymbolicRegion>();
+ // SymbolicRegion's storage class is usually unknown.
+ new (R) SymbolicRegion(sym, getUnknownRegion());
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d,
+ const MemRegion* superRegion) {
+ llvm::FoldingSetNodeID ID;
+ DeclRegion::ProfileRegion(ID, d, superRegion, MemRegion::FieldRegionKind);
+
+ void* InsertPos;
+ MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+ FieldRegion* R = cast_or_null<FieldRegion>(data);
+
+ if (!R) {
+ R = (FieldRegion*) A.Allocate<FieldRegion>();
+ new (R) FieldRegion(d, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+ObjCIvarRegion*
+MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
+ const MemRegion* superRegion) {
+ llvm::FoldingSetNodeID ID;
+ DeclRegion::ProfileRegion(ID, d, superRegion, MemRegion::ObjCIvarRegionKind);
+
+ void* InsertPos;
+ MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+ ObjCIvarRegion* R = cast_or_null<ObjCIvarRegion>(data);
+
+ if (!R) {
+ R = (ObjCIvarRegion*) A.Allocate<ObjCIvarRegion>();
+ new (R) ObjCIvarRegion(d, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+ObjCObjectRegion*
+MemRegionManager::getObjCObjectRegion(const ObjCInterfaceDecl* d,
+ const MemRegion* superRegion) {
+ llvm::FoldingSetNodeID ID;
+ DeclRegion::ProfileRegion(ID, d, superRegion,
+ MemRegion::ObjCObjectRegionKind);
+
+ void* InsertPos;
+ MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+ ObjCObjectRegion* R = cast_or_null<ObjCObjectRegion>(data);
+
+ if (!R) {
+ R = (ObjCObjectRegion*) A.Allocate<ObjCObjectRegion>();
+ new (R) ObjCObjectRegion(d, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+TypedViewRegion*
+MemRegionManager::getTypedViewRegion(QualType t, const MemRegion* superRegion) {
+ llvm::FoldingSetNodeID ID;
+ TypedViewRegion::ProfileRegion(ID, t, superRegion);
+
+ void* InsertPos;
+ MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+ TypedViewRegion* R = cast_or_null<TypedViewRegion>(data);
+
+ if (!R) {
+ R = (TypedViewRegion*) A.Allocate<TypedViewRegion>();
+ new (R) TypedViewRegion(t, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+AllocaRegion* MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt) {
+ llvm::FoldingSetNodeID ID;
+ AllocaRegion::ProfileRegion(ID, E, cnt);
+
+ void* InsertPos;
+ MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+ AllocaRegion* R = cast_or_null<AllocaRegion>(data);
+
+ if (!R) {
+ R = (AllocaRegion*) A.Allocate<AllocaRegion>();
+ new (R) AllocaRegion(E, cnt, getStackRegion());
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
+
+bool MemRegionManager::hasStackStorage(const MemRegion* R) {
+
+ // Only subregions can have stack storage.
+ const SubRegion* SR = dyn_cast<SubRegion>(R);
+
+ if (!SR)
+ return false;
+
+ MemSpaceRegion* S = getStackRegion();
+
+ while (SR) {
+ R = SR->getSuperRegion();
+ if (R == S)
+ return true;
+
+ SR = dyn_cast<SubRegion>(R);
+ }
+
+ return false;
+}
+
+
+//===----------------------------------------------------------------------===//
+// View handling.
+//===----------------------------------------------------------------------===//
+
+const MemRegion *TypedViewRegion::removeViews() const {
+ const SubRegion *SR = this;
+ const MemRegion *R = SR;
+ while (SR && isa<TypedViewRegion>(SR)) {
+ R = SR->getSuperRegion();
+ SR = dyn_cast<SubRegion>(R);
+ }
+ return R;
+}
diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Analysis/PathDiagnostic.cpp
new file mode 100644
index 000000000000..ec96329852d4
--- /dev/null
+++ b/lib/Analysis/PathDiagnostic.cpp
@@ -0,0 +1,242 @@
+//===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- 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 PathDiagnostic-related interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/StmtCXX.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Casting.h"
+#include <sstream>
+using namespace clang;
+using llvm::dyn_cast;
+using llvm::isa;
+
+bool PathDiagnosticMacroPiece::containsEvent() const {
+ for (const_iterator I = begin(), E = end(); I!=E; ++I) {
+ if (isa<PathDiagnosticEventPiece>(*I))
+ return true;
+
+ if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
+ if (MP->containsEvent())
+ return true;
+ }
+
+ return false;
+}
+
+static size_t GetNumCharsToLastNonPeriod(const char *s) {
+ const char *start = s;
+ const char *lastNonPeriod = 0;
+
+ for ( ; *s != '\0' ; ++s)
+ if (*s != '.') lastNonPeriod = s;
+
+ if (!lastNonPeriod)
+ return 0;
+
+ return (lastNonPeriod - start) + 1;
+}
+
+static inline size_t GetNumCharsToLastNonPeriod(const std::string &s) {
+ return s.empty () ? 0 : GetNumCharsToLastNonPeriod(&s[0]);
+}
+
+PathDiagnosticPiece::PathDiagnosticPiece(const std::string& s,
+ Kind k, DisplayHint hint)
+ : str(s, 0, GetNumCharsToLastNonPeriod(s)), kind(k), Hint(hint) {}
+
+PathDiagnosticPiece::PathDiagnosticPiece(const char* s, Kind k,
+ DisplayHint hint)
+ : str(s, GetNumCharsToLastNonPeriod(s)), kind(k), Hint(hint) {}
+
+PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
+ : kind(k), Hint(hint) {}
+
+PathDiagnosticPiece::~PathDiagnosticPiece() {}
+PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
+PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
+
+PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {
+ for (iterator I = begin(), E = end(); I != E; ++I) delete *I;
+}
+
+PathDiagnostic::PathDiagnostic() : Size(0) {}
+
+PathDiagnostic::~PathDiagnostic() {
+ for (iterator I = begin(), E = end(); I != E; ++I) delete &*I;
+}
+
+void PathDiagnostic::resetPath(bool deletePieces) {
+ Size = 0;
+
+ if (deletePieces)
+ for (iterator I=begin(), E=end(); I!=E; ++I)
+ delete &*I;
+
+ path.clear();
+}
+
+
+PathDiagnostic::PathDiagnostic(const char* bugtype, const char* desc,
+ const char* category)
+ : Size(0),
+ BugType(bugtype, GetNumCharsToLastNonPeriod(bugtype)),
+ Desc(desc, GetNumCharsToLastNonPeriod(desc)),
+ Category(category, GetNumCharsToLastNonPeriod(category)) {}
+
+PathDiagnostic::PathDiagnostic(const std::string& bugtype,
+ const std::string& desc,
+ const std::string& category)
+ : Size(0),
+ BugType(bugtype, 0, GetNumCharsToLastNonPeriod(bugtype)),
+ Desc(desc, 0, GetNumCharsToLastNonPeriod(desc)),
+ Category(category, 0, GetNumCharsToLastNonPeriod(category)) {}
+
+void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info) {
+
+ // Create a PathDiagnostic with a single piece.
+
+ PathDiagnostic* D = new PathDiagnostic();
+
+ 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;
+ }
+
+ llvm::SmallString<100> StrC;
+ StrC += LevelStr;
+ Info.FormatDiagnostic(StrC);
+
+ PathDiagnosticPiece *P =
+ new PathDiagnosticEventPiece(Info.getLocation(),
+ std::string(StrC.begin(), StrC.end()));
+
+ for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
+ P->addRange(Info.getRange(i));
+ for (unsigned i = 0, e = Info.getNumCodeModificationHints(); i != e; ++i)
+ P->addCodeModificationHint(Info.getCodeModificationHint(i));
+ D->push_front(P);
+
+ HandlePathDiagnostic(D);
+}
+
+//===----------------------------------------------------------------------===//
+// PathDiagnosticLocation methods.
+//===----------------------------------------------------------------------===//
+
+FullSourceLoc PathDiagnosticLocation::asLocation() 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:
+ case RangeK:
+ break;
+ case StmtK:
+ return FullSourceLoc(S->getLocStart(), const_cast<SourceManager&>(*SM));
+ case DeclK:
+ return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
+ }
+
+ return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM));
+}
+
+PathDiagnosticRange PathDiagnosticLocation::asRange() 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);
+ case RangeK:
+ break;
+ case StmtK: {
+ const Stmt *S = asStmt();
+ switch (S->getStmtClass()) {
+ default:
+ break;
+ case Stmt::DeclStmtClass: {
+ const DeclStmt *DS = cast<DeclStmt>(S);
+ if (DS->isSingleDecl()) {
+ // Should always be the case, but we'll be defensive.
+ return SourceRange(DS->getLocStart(),
+ DS->getSingleDecl()->getLocation());
+ }
+ break;
+ }
+ // FIXME: Provide better range information for different
+ // terminators.
+ case Stmt::IfStmtClass:
+ case Stmt::WhileStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::ForStmtClass:
+ case Stmt::ChooseExprClass:
+ case Stmt::IndirectGotoStmtClass:
+ case Stmt::SwitchStmtClass:
+ case Stmt::ConditionalOperatorClass:
+ case Stmt::ObjCForCollectionStmtClass: {
+ SourceLocation L = S->getLocStart();
+ return SourceRange(L, L);
+ }
+ }
+
+ return S->getSourceRange();
+ }
+ case DeclK:
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ return MD->getSourceRange();
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // FIXME: We would like to always get the function body, even
+ // when it needs to be de-serialized, but getting the
+ // ASTContext here requires significant changes.
+ if (Stmt *Body = FD->getBodyIfAvailable()) {
+ if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Body))
+ return CS->getSourceRange();
+ else
+ return cast<CXXTryStmt>(Body)->getSourceRange();
+ }
+ }
+ else {
+ SourceLocation L = D->getLocation();
+ return PathDiagnosticRange(SourceRange(L, L), true);
+ }
+ }
+
+ return R;
+}
+
+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;
+ }
+}
+
+
diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp
new file mode 100644
index 000000000000..f6ac2b9748c4
--- /dev/null
+++ b/lib/Analysis/RangeConstraintManager.cpp
@@ -0,0 +1,363 @@
+//== RangeConstraintManager.cpp - Manage range constraints.------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines RangeConstraintManager, a class that tracks simple
+// equality and inequality constraints on symbolic values of GRState.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SimpleConstraintManager.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/PathSensitive/GRStateTrait.h"
+#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Frontend/ManagerRegistry.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableSet.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+namespace { class VISIBILITY_HIDDEN ConstraintRange {}; }
+static int ConstraintRangeIndex = 0;
+
+/// A Range represents the closed range [from, to]. The caller must
+/// guarantee that from <= to. Note that Range is immutable, so as not
+/// to subvert RangeSet's immutability.
+namespace {
+class VISIBILITY_HIDDEN Range : public std::pair<const llvm::APSInt*,
+ const llvm::APSInt*> {
+public:
+ Range(const llvm::APSInt &from, const llvm::APSInt &to)
+ : std::pair<const llvm::APSInt*, const llvm::APSInt*>(&from, &to) {
+ assert(from <= to);
+ }
+ bool Includes(const llvm::APSInt &v) const {
+ return *first <= v && v <= *second;
+ }
+ const llvm::APSInt &From() const {
+ return *first;
+ }
+ const llvm::APSInt &To() const {
+ return *second;
+ }
+ const llvm::APSInt *getConcreteValue() const {
+ return &From() == &To() ? &From() : NULL;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(&From());
+ ID.AddPointer(&To());
+ }
+};
+
+
+class VISIBILITY_HIDDEN RangeTrait : public llvm::ImutContainerInfo<Range> {
+public:
+ // When comparing if one Range is less than another, we should compare
+ // the actual APSInt values instead of their pointers. This keeps the order
+ // consistent (instead of comparing by pointer values) and can potentially
+ // be used to speed up some of the operations in RangeSet.
+ static inline bool isLess(key_type_ref lhs, key_type_ref rhs) {
+ return *lhs.first < *rhs.first || (!(*rhs.first < *lhs.first) &&
+ *lhs.second < *rhs.second);
+ }
+};
+
+/// RangeSet contains a set of ranges. If the set is empty, then
+/// there the value of a symbol is overly constrained and there are no
+/// possible values for that symbol.
+class VISIBILITY_HIDDEN RangeSet {
+ typedef llvm::ImmutableSet<Range, RangeTrait> PrimRangeSet;
+ PrimRangeSet ranges; // no need to make const, since it is an
+ // ImmutableSet - this allows default operator=
+ // to work.
+public:
+ typedef PrimRangeSet::Factory Factory;
+ typedef PrimRangeSet::iterator iterator;
+
+ RangeSet(PrimRangeSet RS) : ranges(RS) {}
+ RangeSet(Factory& F) : ranges(F.GetEmptySet()) {}
+
+ iterator begin() const { return ranges.begin(); }
+ iterator end() const { return ranges.end(); }
+
+ bool isEmpty() const { return ranges.isEmpty(); }
+
+ /// Construct a new RangeSet representing '{ [from, to] }'.
+ RangeSet(Factory &F, const llvm::APSInt &from, const llvm::APSInt &to)
+ : ranges(F.Add(F.GetEmptySet(), Range(from, to))) {}
+
+ /// Profile - Generates a hash profile of this RangeSet for use
+ /// by FoldingSet.
+ void Profile(llvm::FoldingSetNodeID &ID) const { ranges.Profile(ID); }
+
+ /// getConcreteValue - If a symbol is contrained to equal a specific integer
+ /// constant then this method returns that value. Otherwise, it returns
+ /// NULL.
+ const llvm::APSInt* getConcreteValue() const {
+ return ranges.isSingleton() ? ranges.begin()->getConcreteValue() : 0;
+ }
+
+ /// AddEQ - Create a new RangeSet with the additional constraint that the
+ /// value be equal to V.
+ RangeSet AddEQ(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
+ // Search for a range that includes 'V'. If so, return a new RangeSet
+ // representing { [V, V] }.
+ for (PrimRangeSet::iterator i = begin(), e = end(); i!=e; ++i)
+ if (i->Includes(V))
+ return RangeSet(F, V, V);
+
+ return RangeSet(F);
+ }
+
+ /// AddNE - Create a new RangeSet with the additional constraint that the
+ /// value be not be equal to V.
+ RangeSet AddNE(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
+ PrimRangeSet newRanges = ranges;
+
+ // FIXME: We can perhaps enhance ImmutableSet to do this search for us
+ // in log(N) time using the sorted property of the internal AVL tree.
+ for (iterator i = begin(), e = end(); i != e; ++i) {
+ if (i->Includes(V)) {
+ // Remove the old range.
+ newRanges = F.Remove(newRanges, *i);
+ // Split the old range into possibly one or two ranges.
+ if (V != i->From())
+ newRanges = F.Add(newRanges, Range(i->From(), BV.Sub1(V)));
+ if (V != i->To())
+ newRanges = F.Add(newRanges, Range(BV.Add1(V), i->To()));
+ // All of the ranges are non-overlapping, so we can stop.
+ break;
+ }
+ }
+
+ return newRanges;
+ }
+
+ /// AddNE - Create a new RangeSet with the additional constraint that the
+ /// value be less than V.
+ RangeSet AddLT(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
+ PrimRangeSet newRanges = F.GetEmptySet();
+
+ for (iterator i = begin(), e = end() ; i != e ; ++i) {
+ if (i->Includes(V) && i->From() < V)
+ newRanges = F.Add(newRanges, Range(i->From(), BV.Sub1(V)));
+ else if (i->To() < V)
+ newRanges = F.Add(newRanges, *i);
+ }
+
+ return newRanges;
+ }
+
+ RangeSet AddLE(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
+ PrimRangeSet newRanges = F.GetEmptySet();
+
+ for (iterator i = begin(), e = end(); i != e; ++i) {
+ // Strictly we should test for includes *V + 1, but no harm is
+ // done by this formulation
+ if (i->Includes(V))
+ newRanges = F.Add(newRanges, Range(i->From(), V));
+ else if (i->To() <= V)
+ newRanges = F.Add(newRanges, *i);
+ }
+
+ return newRanges;
+ }
+
+ RangeSet AddGT(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
+ PrimRangeSet newRanges = F.GetEmptySet();
+
+ for (PrimRangeSet::iterator i = begin(), e = end(); i != e; ++i) {
+ if (i->Includes(V) && i->To() > V)
+ newRanges = F.Add(newRanges, Range(BV.Add1(V), i->To()));
+ else if (i->From() > V)
+ newRanges = F.Add(newRanges, *i);
+ }
+
+ return newRanges;
+ }
+
+ RangeSet AddGE(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
+ PrimRangeSet newRanges = F.GetEmptySet();
+
+ for (PrimRangeSet::iterator i = begin(), e = end(); i != e; ++i) {
+ // Strictly we should test for includes *V - 1, but no harm is
+ // done by this formulation
+ if (i->Includes(V))
+ newRanges = F.Add(newRanges, Range(V, i->To()));
+ else if (i->From() >= V)
+ newRanges = F.Add(newRanges, *i);
+ }
+
+ return newRanges;
+ }
+
+ void Print(std::ostream &os) const {
+ bool isFirst = true;
+ os << "{ ";
+ for (iterator i = begin(), e = end(); i != e; ++i) {
+ if (isFirst)
+ isFirst = false;
+ else
+ os << ", ";
+
+ os << '[' << i->From().toString(10) << ", " << i->To().toString(10)
+ << ']';
+ }
+ os << " }";
+ }
+
+ bool operator==(const RangeSet &other) const {
+ return ranges == other.ranges;
+ }
+};
+} // end anonymous namespace
+
+typedef llvm::ImmutableMap<SymbolRef,RangeSet> ConstraintRangeTy;
+
+namespace clang {
+template<>
+struct GRStateTrait<ConstraintRange>
+ : public GRStatePartialTrait<ConstraintRangeTy> {
+ static inline void* GDMIndex() { return &ConstraintRangeIndex; }
+};
+}
+
+namespace {
+class VISIBILITY_HIDDEN RangeConstraintManager : public SimpleConstraintManager{
+ RangeSet GetRange(GRStateRef state, SymbolRef sym);
+public:
+ RangeConstraintManager(GRStateManager& statemgr)
+ : SimpleConstraintManager(statemgr) {}
+
+ const GRState* AssumeSymNE(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible);
+
+ const GRState* AssumeSymEQ(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible);
+
+ const GRState* AssumeSymLT(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible);
+
+ const GRState* AssumeSymGT(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible);
+
+ const GRState* AssumeSymGE(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible);
+
+ const GRState* AssumeSymLE(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V, bool& isFeasible);
+
+ const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) const;
+
+ // FIXME: Refactor into SimpleConstraintManager?
+ bool isEqual(const GRState* 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);
+
+ void print(const GRState* St, std::ostream& Out,
+ const char* nl, const char *sep);
+
+private:
+ RangeSet::Factory F;
+};
+
+} // end anonymous namespace
+
+ConstraintManager* clang::CreateRangeConstraintManager(GRStateManager& StateMgr)
+{
+ return new RangeConstraintManager(StateMgr);
+}
+
+const llvm::APSInt* RangeConstraintManager::getSymVal(const GRState* St,
+ SymbolRef sym) const {
+ const ConstraintRangeTy::data_type *T = St->get<ConstraintRange>(sym);
+ return T ? T->getConcreteValue() : NULL;
+}
+
+/// 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* St,
+ SymbolReaper& SymReaper) {
+ GRStateRef state(St, StateMgr);
+
+ ConstraintRangeTy CR = state.get<ConstraintRange>();
+ ConstraintRangeTy::Factory& CRFactory = state.get_context<ConstraintRange>();
+
+ for (ConstraintRangeTy::iterator I = CR.begin(), E = CR.end(); I != E; ++I) {
+ SymbolRef sym = I.getKey();
+ if (SymReaper.maybeDead(sym))
+ CR = CRFactory.Remove(CR, sym);
+ }
+
+ return state.set<ConstraintRange>(CR);
+}
+
+//===------------------------------------------------------------------------===
+// AssumeSymX methods: public interface for RangeConstraintManager.
+//===------------------------------------------------------------------------===/
+
+RangeSet
+RangeConstraintManager::GetRange(GRStateRef state, SymbolRef sym) {
+ if (ConstraintRangeTy::data_type* V = state.get<ConstraintRange>(sym))
+ return *V;
+
+ // Lazily generate a new RangeSet representing all possible values for the
+ // given symbol type.
+ QualType T = state.getSymbolManager().getType(sym);
+ BasicValueFactory& BV = state.getBasicVals();
+ return RangeSet(F, BV.getMinValue(T), BV.getMaxValue(T));
+}
+
+//===------------------------------------------------------------------------===
+// AssumeSymX methods: public interface for RangeConstraintManager.
+//===------------------------------------------------------------------------===/
+
+#define AssumeX(OP)\
+const GRState*\
+RangeConstraintManager::AssumeSym ## OP(const GRState* St, SymbolRef sym,\
+ const llvm::APSInt& V, bool& isFeasible){\
+ GRStateRef state(St, StateMgr);\
+ const RangeSet& R = GetRange(state, sym).Add##OP(state.getBasicVals(), F, V);\
+ isFeasible = !R.isEmpty();\
+ return isFeasible ? state.set<ConstraintRange>(sym, R).getState() : 0;\
+}
+
+AssumeX(EQ)
+AssumeX(NE)
+AssumeX(LT)
+AssumeX(GT)
+AssumeX(LE)
+AssumeX(GE)
+
+//===------------------------------------------------------------------------===
+// Pretty-printing.
+//===------------------------------------------------------------------------===/
+
+void RangeConstraintManager::print(const GRState* St, std::ostream& Out,
+ const char* nl, const char *sep) {
+
+ ConstraintRangeTy Ranges = St->get<ConstraintRange>();
+
+ if (Ranges.isEmpty())
+ return;
+
+ Out << nl << sep << "ranges of symbol values:";
+
+ for (ConstraintRangeTy::iterator I=Ranges.begin(), E=Ranges.end(); I!=E; ++I){
+ Out << nl << ' ' << I.getKey() << " : ";
+ I.getData().Print(Out);
+ }
+}
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
new file mode 100644
index 000000000000..02d3d1f885f9
--- /dev/null
+++ b/lib/Analysis/RegionStore.cpp
@@ -0,0 +1,1304 @@
+//== RegionStore.cpp - Field-sensitive store model --------------*- 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 a basic region store model. In this model, we do have field
+// sensitivity. But we assume nothing about the heap shape. So recursive data
+// structures are largely ignored. Basically we do 1-limiting analysis.
+// Parameter pointers are assumed with no aliasing. Pointee objects of
+// parameters are created lazily.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Analysis/PathSensitive/MemRegion.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/PathSensitive/GRStateTrait.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Basic/TargetInfo.h"
+
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace clang;
+
+// Actual Store type.
+typedef llvm::ImmutableMap<const MemRegion*, SVal> RegionBindingsTy;
+
+//===----------------------------------------------------------------------===//
+// Region "Views"
+//===----------------------------------------------------------------------===//
+//
+// MemRegions can be layered on top of each other. This GDM entry tracks
+// what are the MemRegions that layer a given MemRegion.
+//
+typedef llvm::ImmutableSet<const MemRegion*> RegionViews;
+namespace { class VISIBILITY_HIDDEN RegionViewMap {}; }
+static int RegionViewMapIndex = 0;
+namespace clang {
+ template<> struct GRStateTrait<RegionViewMap>
+ : public GRStatePartialTrait<llvm::ImmutableMap<const MemRegion*,
+ RegionViews> > {
+
+ static void* GDMIndex() { return &RegionViewMapIndex; }
+ };
+}
+
+// RegionCasts records the current cast type of a region.
+namespace { class VISIBILITY_HIDDEN RegionCasts {}; }
+static int RegionCastsIndex = 0;
+namespace clang {
+ template<> struct GRStateTrait<RegionCasts>
+ : public GRStatePartialTrait<llvm::ImmutableMap<const MemRegion*,
+ QualType> > {
+ static void* GDMIndex() { return &RegionCastsIndex; }
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// Region "Extents"
+//===----------------------------------------------------------------------===//
+//
+// MemRegions represent chunks of memory with a size (their "extent"). This
+// GDM entry tracks the extents for regions. Extents are in bytes.
+//
+namespace { class VISIBILITY_HIDDEN RegionExtents {}; }
+static int RegionExtentsIndex = 0;
+namespace clang {
+ template<> struct GRStateTrait<RegionExtents>
+ : public GRStatePartialTrait<llvm::ImmutableMap<const MemRegion*, SVal> > {
+ static void* GDMIndex() { return &RegionExtentsIndex; }
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// Region "killsets".
+//===----------------------------------------------------------------------===//
+//
+// RegionStore lazily adds value bindings to regions when the analyzer handles
+// assignment statements. Killsets track which default values have been
+// killed, thus distinguishing between "unknown" values and default
+// values. Regions are added to killset only when they are assigned "unknown"
+// directly, otherwise we should have their value in the region bindings.
+//
+namespace { class VISIBILITY_HIDDEN RegionKills {}; }
+static int RegionKillsIndex = 0;
+namespace clang {
+ template<> struct GRStateTrait<RegionKills>
+ : public GRStatePartialTrait< llvm::ImmutableSet<const MemRegion*> > {
+ static void* GDMIndex() { return &RegionKillsIndex; }
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// Regions with default values.
+//===----------------------------------------------------------------------===//
+//
+// This GDM entry tracks what regions have a default value if they have no bound
+// value and have not been killed.
+//
+namespace { class VISIBILITY_HIDDEN RegionDefaultValue {}; }
+static int RegionDefaultValueIndex = 0;
+namespace clang {
+ template<> struct GRStateTrait<RegionDefaultValue>
+ : public GRStatePartialTrait<llvm::ImmutableMap<const MemRegion*, SVal> > {
+ static void* GDMIndex() { return &RegionDefaultValueIndex; }
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// Main RegionStore logic.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class VISIBILITY_HIDDEN RegionStoreSubRegionMap : public SubRegionMap {
+ typedef llvm::DenseMap<const MemRegion*,
+ llvm::ImmutableSet<const MemRegion*> > Map;
+
+ llvm::ImmutableSet<const MemRegion*>::Factory F;
+ Map M;
+
+public:
+ void add(const MemRegion* Parent, const MemRegion* SubRegion) {
+ Map::iterator I = M.find(Parent);
+ M.insert(std::make_pair(Parent,
+ F.Add(I == M.end() ? F.GetEmptySet() : I->second, SubRegion)));
+ }
+
+ ~RegionStoreSubRegionMap() {}
+
+ bool iterSubRegions(const MemRegion* Parent, Visitor& V) const {
+ Map::iterator I = M.find(Parent);
+
+ if (I == M.end())
+ return true;
+
+ llvm::ImmutableSet<const MemRegion*> S = I->second;
+ for (llvm::ImmutableSet<const MemRegion*>::iterator SI=S.begin(),SE=S.end();
+ SI != SE; ++SI) {
+ if (!V.Visit(Parent, *SI))
+ return false;
+ }
+
+ return true;
+ }
+};
+
+class VISIBILITY_HIDDEN RegionStoreManager : public StoreManager {
+ RegionBindingsTy::Factory RBFactory;
+ RegionViews::Factory RVFactory;
+
+ const MemRegion* SelfRegion;
+ const ImplicitParamDecl *SelfDecl;
+
+public:
+ RegionStoreManager(GRStateManager& mgr)
+ : StoreManager(mgr),
+ RBFactory(mgr.getAllocator()),
+ RVFactory(mgr.getAllocator()),
+ SelfRegion(0), SelfDecl(0) {
+ if (const ObjCMethodDecl* MD =
+ dyn_cast<ObjCMethodDecl>(&StateMgr.getCodeDecl()))
+ SelfDecl = MD->getSelfDecl();
+ }
+
+ virtual ~RegionStoreManager() {}
+
+ SubRegionMap* getSubRegionMap(const GRState *state);
+
+ const GRState* BindCompoundLiteral(const GRState* St,
+ const CompoundLiteralExpr* CL, SVal V);
+
+ /// getLValueString - Returns an SVal representing the lvalue of a
+ /// StringLiteral. Within RegionStore a StringLiteral has an
+ /// associated StringRegion, and the lvalue of a StringLiteral is
+ /// the lvalue of that region.
+ SVal getLValueString(const GRState* St, const StringLiteral* S);
+
+ /// getLValueCompoundLiteral - Returns an SVal representing the
+ /// lvalue of a compound literal. Within RegionStore a compound
+ /// literal has an associated region, and the lvalue of the
+ /// compound literal is the lvalue of that region.
+ SVal getLValueCompoundLiteral(const GRState* St, const CompoundLiteralExpr*);
+
+ /// getLValueVar - Returns an SVal that represents the lvalue of a
+ /// variable. Within RegionStore a variable has an associated
+ /// VarRegion, and the lvalue of the variable is the lvalue of that region.
+ SVal getLValueVar(const GRState* St, const VarDecl* VD);
+
+ SVal getLValueIvar(const GRState* St, const ObjCIvarDecl* D, SVal Base);
+
+ SVal getLValueField(const GRState* St, SVal Base, const FieldDecl* D);
+
+ SVal getLValueFieldOrIvar(const GRState* St, SVal Base, const Decl* D);
+
+ SVal getLValueElement(const GRState* St, QualType elementType,
+ SVal Base, SVal Offset);
+
+ SVal getSizeInElements(const GRState* St, const MemRegion* R);
+
+ /// ArrayToPointer - Emulates the "decay" of an array to a pointer
+ /// type. 'Array' represents the lvalue of the array being decayed
+ /// to a pointer, and the returned SVal represents the decayed
+ /// version of that lvalue (i.e., a pointer to the first element of
+ /// the array). This is called by GRExprEngine when evaluating
+ /// casts from arrays to pointers.
+ SVal ArrayToPointer(Loc Array);
+
+ CastResult CastRegion(const GRState* state, const MemRegion* R,
+ QualType CastToTy);
+
+ SVal EvalBinOp(const GRState *state,BinaryOperator::Opcode Op,Loc L,NonLoc R);
+
+ /// The high level logic for this method is this:
+ /// Retrieve (L)
+ /// if L has binding
+ /// return L's binding
+ /// else if L is in killset
+ /// return unknown
+ /// else
+ /// if L is on stack or heap
+ /// return undefined
+ /// else
+ /// return symbolic
+ SVal Retrieve(const GRState* state, Loc L, QualType T = QualType());
+
+ const GRState* Bind(const GRState* St, Loc LV, SVal V);
+
+ Store Remove(Store store, Loc LV);
+
+ Store getInitialStore() { return RBFactory.GetEmptyMap().getRoot(); }
+
+ /// getSelfRegion - Returns the region for the 'self' (Objective-C) or
+ /// 'this' object (C++). When used when analyzing a normal function this
+ /// method returns NULL.
+ const MemRegion* getSelfRegion(Store) {
+ if (!SelfDecl)
+ return 0;
+
+ if (!SelfRegion) {
+ const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(&StateMgr.getCodeDecl());
+ SelfRegion = MRMgr.getObjCObjectRegion(MD->getClassInterface(),
+ MRMgr.getHeapRegion());
+ }
+
+ return SelfRegion;
+ }
+
+ /// RemoveDeadBindings - Scans the RegionStore of 'state' for dead values.
+ /// It returns a new Store with these values removed, and populates LSymbols
+ // and DSymbols with the known set of live and dead symbols respectively.
+ Store RemoveDeadBindings(const GRState* state, Stmt* Loc,
+ SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
+
+ const GRState* BindDecl(const GRState* St, const VarDecl* VD, SVal InitVal);
+
+ const GRState* BindDeclWithNoInit(const GRState* St, const VarDecl* VD) {
+ return St;
+ }
+
+ const GRState* setExtent(const GRState* St, const MemRegion* R, SVal Extent);
+ const GRState* setCastType(const GRState* St, const MemRegion* R, QualType T);
+
+ static inline RegionBindingsTy GetRegionBindings(Store store) {
+ return RegionBindingsTy(static_cast<const RegionBindingsTy::TreeTy*>(store));
+ }
+
+ void print(Store store, std::ostream& Out, const char* nl, const char *sep);
+
+ void iterBindings(Store store, BindingsHandler& f) {
+ // FIXME: Implement.
+ }
+ const GRState* setDefaultValue(const GRState* St, const MemRegion* R, SVal V);
+private:
+ const GRState* BindArray(const GRState* St, const TypedRegion* R, SVal V);
+
+ /// Retrieve the values in a struct and return a CompoundVal, used when doing
+ /// struct copy:
+ /// struct s x, y;
+ /// x = y;
+ /// y's value is retrieved by this method.
+ SVal RetrieveStruct(const GRState* St, const TypedRegion* R);
+
+ SVal RetrieveArray(const GRState* St, const TypedRegion* R);
+
+ const GRState* BindStruct(const GRState* St, const TypedRegion* R, SVal V);
+
+ /// KillStruct - Set the entire struct to unknown.
+ const GRState* KillStruct(const GRState* St, const TypedRegion* R);
+
+ // Utility methods.
+ BasicValueFactory& getBasicVals() { return StateMgr.getBasicVals(); }
+ ASTContext& getContext() { return StateMgr.getContext(); }
+
+ SymbolManager& getSymbolManager() { return StateMgr.getSymbolManager(); }
+
+ const GRState* AddRegionView(const GRState* St,
+ const MemRegion* View, const MemRegion* Base);
+ const GRState* RemoveRegionView(const GRState* St,
+ const MemRegion* View, const MemRegion* Base);
+};
+
+} // end anonymous namespace
+
+StoreManager* clang::CreateRegionStoreManager(GRStateManager& StMgr) {
+ return new RegionStoreManager(StMgr);
+}
+
+SubRegionMap* RegionStoreManager::getSubRegionMap(const GRState *state) {
+ RegionBindingsTy B = GetRegionBindings(state->getStore());
+ RegionStoreSubRegionMap *M = new RegionStoreSubRegionMap();
+
+ for (RegionBindingsTy::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
+ if (const SubRegion* R = dyn_cast<SubRegion>(I.getKey()))
+ M->add(R->getSuperRegion(), R);
+ }
+
+ return M;
+}
+
+/// getLValueString - Returns an SVal representing the lvalue of a
+/// StringLiteral. Within RegionStore a StringLiteral has an
+/// associated StringRegion, and the lvalue of a StringLiteral is the
+/// lvalue of that region.
+SVal RegionStoreManager::getLValueString(const GRState* St,
+ const StringLiteral* S) {
+ return loc::MemRegionVal(MRMgr.getStringRegion(S));
+}
+
+/// getLValueVar - Returns an SVal that represents the lvalue of a
+/// variable. Within RegionStore a variable has an associated
+/// VarRegion, and the lvalue of the variable is the lvalue of that region.
+SVal RegionStoreManager::getLValueVar(const GRState* St, const VarDecl* VD) {
+ return loc::MemRegionVal(MRMgr.getVarRegion(VD));
+}
+
+/// getLValueCompoundLiteral - Returns an SVal representing the lvalue
+/// of a compound literal. Within RegionStore a compound literal
+/// has an associated region, and the lvalue of the compound literal
+/// is the lvalue of that region.
+SVal
+RegionStoreManager::getLValueCompoundLiteral(const GRState* St,
+ const CompoundLiteralExpr* CL) {
+ return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL));
+}
+
+SVal RegionStoreManager::getLValueIvar(const GRState* St, const ObjCIvarDecl* D,
+ SVal Base) {
+ return getLValueFieldOrIvar(St, Base, D);
+}
+
+SVal RegionStoreManager::getLValueField(const GRState* St, SVal Base,
+ const FieldDecl* D) {
+ return getLValueFieldOrIvar(St, Base, D);
+}
+
+SVal RegionStoreManager::getLValueFieldOrIvar(const GRState* St, SVal Base,
+ const Decl* D) {
+ if (Base.isUnknownOrUndef())
+ return Base;
+
+ Loc BaseL = cast<Loc>(Base);
+ const MemRegion* BaseR = 0;
+
+ switch (BaseL.getSubKind()) {
+ case loc::MemRegionKind:
+ BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
+ break;
+
+ case loc::GotoLabelKind:
+ // These are anormal cases. Flag an undefined value.
+ return UndefinedVal();
+
+ case loc::ConcreteIntKind:
+ // While these seem funny, this can happen through casts.
+ // FIXME: What we should return is the field offset. For example,
+ // add the field offset to the integer value. That way funny things
+ // like this work properly: &(((struct foo *) 0xa)->f)
+ return Base;
+
+ default:
+ assert(0 && "Unhandled Base.");
+ return Base;
+ }
+
+ // NOTE: We must have this check first because ObjCIvarDecl is a subclass
+ // of FieldDecl.
+ if (const ObjCIvarDecl *ID = dyn_cast<ObjCIvarDecl>(D))
+ return loc::MemRegionVal(MRMgr.getObjCIvarRegion(ID, BaseR));
+
+ return loc::MemRegionVal(MRMgr.getFieldRegion(cast<FieldDecl>(D), BaseR));
+}
+
+SVal RegionStoreManager::getLValueElement(const GRState* St,
+ QualType elementType,
+ SVal Base, SVal Offset) {
+
+ // If the base is an unknown or undefined value, just return it back.
+ // FIXME: For absolute pointer addresses, we just return that value back as
+ // well, although in reality we should return the offset added to that
+ // value.
+ if (Base.isUnknownOrUndef() || isa<loc::ConcreteInt>(Base))
+ return Base;
+
+ // Only handle integer offsets... for now.
+ if (!isa<nonloc::ConcreteInt>(Offset))
+ return UnknownVal();
+
+ const MemRegion* BaseRegion = cast<loc::MemRegionVal>(Base).getRegion();
+
+ // Pointer of any type can be cast and used as array base.
+ const ElementRegion *ElemR = dyn_cast<ElementRegion>(BaseRegion);
+
+ if (!ElemR) {
+ //
+ // If the base region is not an ElementRegion, create one.
+ // This can happen in the following example:
+ //
+ // char *p = __builtin_alloc(10);
+ // p[1] = 8;
+ //
+ // Observe that 'p' binds to an AllocaRegion.
+ //
+
+ // Offset might be unsigned. We have to convert it to signed ConcreteInt.
+ if (nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&Offset)) {
+ const llvm::APSInt& OffI = CI->getValue();
+ if (OffI.isUnsigned()) {
+ llvm::APSInt Tmp = OffI;
+ Tmp.setIsSigned(true);
+ Offset = NonLoc::MakeVal(getBasicVals(), Tmp);
+ }
+ }
+ return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset,
+ BaseRegion));
+ }
+
+ SVal BaseIdx = ElemR->getIndex();
+
+ if (!isa<nonloc::ConcreteInt>(BaseIdx))
+ return UnknownVal();
+
+ const llvm::APSInt& BaseIdxI = cast<nonloc::ConcreteInt>(BaseIdx).getValue();
+ const llvm::APSInt& OffI = cast<nonloc::ConcreteInt>(Offset).getValue();
+ assert(BaseIdxI.isSigned());
+
+ // FIXME: This appears to be the assumption of this code. We should review
+ // whether or not BaseIdxI.getBitWidth() < OffI.getBitWidth(). If it
+ // can't we need to put a comment here. If it can, we should handle it.
+ assert(BaseIdxI.getBitWidth() >= OffI.getBitWidth());
+
+ const MemRegion *ArrayR = ElemR->getSuperRegion();
+ SVal NewIdx;
+
+ if (OffI.isUnsigned() || OffI.getBitWidth() < BaseIdxI.getBitWidth()) {
+ // 'Offset' might be unsigned. We have to convert it to signed and
+ // possibly extend it.
+ llvm::APSInt Tmp = OffI;
+
+ if (OffI.getBitWidth() < BaseIdxI.getBitWidth())
+ Tmp.extend(BaseIdxI.getBitWidth());
+
+ Tmp.setIsSigned(true);
+ Tmp += BaseIdxI; // Compute the new offset.
+ NewIdx = NonLoc::MakeVal(getBasicVals(), Tmp);
+ }
+ else
+ NewIdx = nonloc::ConcreteInt(getBasicVals().getValue(BaseIdxI + OffI));
+
+ return loc::MemRegionVal(MRMgr.getElementRegion(elementType, NewIdx, ArrayR));
+}
+
+SVal RegionStoreManager::getSizeInElements(const GRState* St,
+ const MemRegion* R) {
+ if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
+ // Get the type of the variable.
+ QualType T = VR->getDesugaredValueType(getContext());
+
+ // FIXME: Handle variable-length arrays.
+ if (isa<VariableArrayType>(T))
+ return UnknownVal();
+
+ if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(T)) {
+ // return the size as signed integer.
+ return NonLoc::MakeVal(getBasicVals(), CAT->getSize(), false);
+ }
+
+ GRStateRef state(St, StateMgr);
+ const QualType* CastTy = state.get<RegionCasts>(VR);
+
+ // If the VarRegion is cast to other type, compute the size with respect to
+ // that type.
+ if (CastTy) {
+ QualType EleTy =cast<PointerType>(CastTy->getTypePtr())->getPointeeType();
+ QualType VarTy = VR->getValueType(getContext());
+ uint64_t EleSize = getContext().getTypeSize(EleTy);
+ uint64_t VarSize = getContext().getTypeSize(VarTy);
+ return NonLoc::MakeIntVal(getBasicVals(), VarSize / EleSize, false);
+ }
+
+ // Clients can use ordinary variables as if they were arrays. These
+ // essentially are arrays of size 1.
+ return NonLoc::MakeIntVal(getBasicVals(), 1, false);
+ }
+
+ if (const StringRegion* SR = dyn_cast<StringRegion>(R)) {
+ const StringLiteral* Str = SR->getStringLiteral();
+ // We intentionally made the size value signed because it participates in
+ // operations with signed indices.
+ return NonLoc::MakeIntVal(getBasicVals(), Str->getByteLength()+1, false);
+ }
+
+ if (const FieldRegion* FR = dyn_cast<FieldRegion>(R)) {
+ // FIXME: Unsupported yet.
+ FR = 0;
+ return UnknownVal();
+ }
+
+ if (isa<SymbolicRegion>(R)) {
+ return UnknownVal();
+ }
+
+ if (isa<AllocaRegion>(R)) {
+ return UnknownVal();
+ }
+
+ if (isa<ElementRegion>(R)) {
+ return UnknownVal();
+ }
+
+ assert(0 && "Other regions are not supported yet.");
+ return UnknownVal();
+}
+
+/// ArrayToPointer - Emulates the "decay" of an array to a pointer
+/// type. 'Array' represents the lvalue of the array being decayed
+/// to a pointer, and the returned SVal represents the decayed
+/// version of that lvalue (i.e., a pointer to the first element of
+/// the array). This is called by GRExprEngine when evaluating casts
+/// from arrays to pointers.
+SVal RegionStoreManager::ArrayToPointer(Loc Array) {
+ if (!isa<loc::MemRegionVal>(Array))
+ return UnknownVal();
+
+ const MemRegion* R = cast<loc::MemRegionVal>(&Array)->getRegion();
+ const TypedRegion* ArrayR = dyn_cast<TypedRegion>(R);
+
+ if (!ArrayR)
+ return UnknownVal();
+
+ // Strip off typedefs from the ArrayRegion's ValueType.
+ QualType T = ArrayR->getValueType(getContext())->getDesugaredType();
+ ArrayType *AT = cast<ArrayType>(T);
+ T = AT->getElementType();
+
+ nonloc::ConcreteInt Idx(getBasicVals().getZeroWithPtrWidth(false));
+ ElementRegion* ER = MRMgr.getElementRegion(T, Idx, ArrayR);
+
+ return loc::MemRegionVal(ER);
+}
+
+RegionStoreManager::CastResult
+RegionStoreManager::CastRegion(const GRState* state, const MemRegion* R,
+ QualType CastToTy) {
+
+ ASTContext& Ctx = StateMgr.getContext();
+
+ // We need to know the real type of CastToTy.
+ QualType ToTy = Ctx.getCanonicalType(CastToTy);
+
+ // Check cast to ObjCQualifiedID type.
+ if (isa<ObjCQualifiedIdType>(ToTy)) {
+ // FIXME: Record the type information aside.
+ return CastResult(state, R);
+ }
+
+ // CodeTextRegion should be cast to only function pointer type.
+ if (isa<CodeTextRegion>(R)) {
+ assert(CastToTy->isFunctionPointerType() || CastToTy->isBlockPointerType());
+ return CastResult(state, R);
+ }
+
+ // Now assume we are casting from pointer to pointer. Other cases should
+ // already be handled.
+ QualType PointeeTy = cast<PointerType>(ToTy.getTypePtr())->getPointeeType();
+
+ // Process region cast according to the kind of the region being cast.
+
+ // FIXME: Need to handle arbitrary downcasts.
+ if (isa<SymbolicRegion>(R) || isa<AllocaRegion>(R)) {
+ state = setCastType(state, R, ToTy);
+ return CastResult(state, R);
+ }
+
+ // VarRegion, ElementRegion, and FieldRegion has an inherent type. Normally
+ // they should not be cast. We only layer an ElementRegion when the cast-to
+ // pointee type is of smaller size. In other cases, we return the original
+ // VarRegion.
+ if (isa<VarRegion>(R) || isa<ElementRegion>(R) || isa<FieldRegion>(R)
+ || isa<ObjCIvarRegion>(R) || isa<CompoundLiteralRegion>(R)) {
+ // If the pointee type is incomplete, do not compute its size, and return
+ // the original region.
+ if (const RecordType *RT = dyn_cast<RecordType>(PointeeTy.getTypePtr())) {
+ const RecordDecl *D = RT->getDecl();
+ if (!D->getDefinition(getContext()))
+ return CastResult(state, R);
+ }
+
+ QualType ObjTy = cast<TypedRegion>(R)->getValueType(getContext());
+ uint64_t PointeeTySize = getContext().getTypeSize(PointeeTy);
+ uint64_t ObjTySize = getContext().getTypeSize(ObjTy);
+
+ if ((PointeeTySize > 0 && PointeeTySize < ObjTySize) ||
+ (ObjTy->isAggregateType() && PointeeTy->isScalarType())) {
+ // Record the cast type of the region.
+ state = setCastType(state, R, ToTy);
+
+ SVal Idx = ValMgr.makeZeroArrayIndex();
+ ElementRegion* ER = MRMgr.getElementRegion(PointeeTy, Idx, R);
+ return CastResult(state, ER);
+ } else
+ return CastResult(state, R);
+ }
+
+ if (isa<ObjCObjectRegion>(R)) {
+ return CastResult(state, R);
+ }
+
+ assert(0 && "Unprocessed region.");
+ return 0;
+}
+
+SVal RegionStoreManager::EvalBinOp(const GRState *state,
+ BinaryOperator::Opcode Op, Loc L, NonLoc R) {
+ // Assume the base location is MemRegionVal.
+ if (!isa<loc::MemRegionVal>(L))
+ return UnknownVal();
+
+ const MemRegion* MR = cast<loc::MemRegionVal>(L).getRegion();
+ const ElementRegion *ER = 0;
+
+ // If the operand is a symbolic or alloca region, create the first element
+ // region on it.
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) {
+ // Get symbol's type. It should be a pointer type.
+ SymbolRef Sym = SR->getSymbol();
+ QualType T = Sym->getType(getContext());
+ QualType EleTy = cast<PointerType>(T.getTypePtr())->getPointeeType();
+
+ SVal ZeroIdx = ValMgr.makeZeroArrayIndex();
+ ER = MRMgr.getElementRegion(EleTy, ZeroIdx, SR);
+ }
+ else if (const AllocaRegion *AR = dyn_cast<AllocaRegion>(MR)) {
+ // Get the alloca region's current cast type.
+ GRStateRef StRef(state, StateMgr);
+
+ GRStateTrait<RegionCasts>::lookup_type T = StRef.get<RegionCasts>(AR);
+ assert(T && "alloca region has no type.");
+ QualType EleTy = cast<PointerType>(T->getTypePtr())->getPointeeType();
+ SVal ZeroIdx = ValMgr.makeZeroArrayIndex();
+ ER = MRMgr.getElementRegion(EleTy, ZeroIdx, AR);
+ }
+ else
+ ER = cast<ElementRegion>(MR);
+
+ SVal Idx = ER->getIndex();
+
+ nonloc::ConcreteInt* Base = dyn_cast<nonloc::ConcreteInt>(&Idx);
+ nonloc::ConcreteInt* Offset = dyn_cast<nonloc::ConcreteInt>(&R);
+
+ // Only support concrete integer indexes for now.
+ if (Base && Offset) {
+ // FIXME: For now, convert the signedness and bitwidth of offset in case
+ // they don't match. This can result from pointer arithmetic. In reality,
+ // we should figure out what are the proper semantics and implement them.
+ //
+ // This addresses the test case test/Analysis/ptr-arith.c
+ //
+ nonloc::ConcreteInt OffConverted(getBasicVals().Convert(Base->getValue(),
+ Offset->getValue()));
+ SVal NewIdx = Base->EvalBinOp(getBasicVals(), Op, OffConverted);
+ const MemRegion* NewER =
+ MRMgr.getElementRegion(ER->getElementType(), NewIdx,ER->getSuperRegion());
+ return Loc::MakeVal(NewER);
+
+ }
+
+ return UnknownVal();
+}
+
+SVal RegionStoreManager::Retrieve(const GRState* St, Loc L, QualType T) {
+ assert(!isa<UnknownVal>(L) && "location unknown");
+ assert(!isa<UndefinedVal>(L) && "location undefined");
+
+ // FIXME: Is this even possible? Shouldn't this be treated as a null
+ // dereference at a higher level?
+ if (isa<loc::ConcreteInt>(L))
+ return UndefinedVal();
+
+ const MemRegion* MR = cast<loc::MemRegionVal>(L).getRegion();
+
+ // FIXME: return symbolic value for these cases.
+ // Example:
+ // void f(int* p) { int x = *p; }
+ // char* p = alloca();
+ // read(p);
+ // c = *p;
+ if (isa<SymbolicRegion>(MR) || isa<AllocaRegion>(MR))
+ return UnknownVal();
+
+ // 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);
+ assert(R && "bad region");
+
+ // FIXME: We should eventually handle funny addressing. e.g.:
+ //
+ // int x = ...;
+ // int *p = &x;
+ // char *q = (char*) p;
+ // char c = *q; // returns the first byte of 'x'.
+ //
+ // Such funny addressing will occur due to layering of regions.
+
+ QualType RTy = R->getValueType(getContext());
+
+ if (RTy->isStructureType())
+ return RetrieveStruct(St, R);
+
+ if (RTy->isArrayType())
+ return RetrieveArray(St, R);
+
+ // FIXME: handle Vector types.
+ if (RTy->isVectorType())
+ return UnknownVal();
+
+ RegionBindingsTy B = GetRegionBindings(St->getStore());
+ RegionBindingsTy::data_type* V = B.lookup(R);
+
+ // Check if the region has a binding.
+ if (V)
+ return *V;
+
+ GRStateRef state(St, StateMgr);
+
+ // Check if the region is in killset.
+ if (state.contains<RegionKills>(R))
+ return UnknownVal();
+
+ // Check if the region is an element region of a string literal.
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ if (const StringRegion *StrR=dyn_cast<StringRegion>(ER->getSuperRegion())) {
+ const StringLiteral *Str = StrR->getStringLiteral();
+ SVal Idx = ER->getIndex();
+ if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) {
+ int64_t i = CI->getValue().getSExtValue();
+ char c;
+ if (i == Str->getByteLength())
+ c = '\0';
+ else
+ c = Str->getStrData()[i];
+ const llvm::APSInt &V = getBasicVals().getValue(c, getContext().CharTy);
+ return nonloc::ConcreteInt(V);
+ }
+ }
+ }
+
+ // If the region is an element or field, it may have a default value.
+ if (isa<ElementRegion>(R) || isa<FieldRegion>(R)) {
+ const MemRegion* SuperR = cast<SubRegion>(R)->getSuperRegion();
+ GRStateTrait<RegionDefaultValue>::lookup_type D =
+ state.get<RegionDefaultValue>(SuperR);
+ if (D) {
+ // If the default value is symbolic, we need to create a new symbol.
+ if (D->hasConjuredSymbol())
+ return ValMgr.getRegionValueSymbolVal(R);
+ else
+ return *D;
+ }
+ }
+
+ if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
+ const MemRegion *SR = IVR->getSuperRegion();
+
+ // If the super region is 'self' then return the symbol representing
+ // the value of the ivar upon entry to the method.
+ if (SR == SelfRegion) {
+ // FIXME: Do we need to handle the case where the super region
+ // has a view? We want to canonicalize the bindings.
+ return ValMgr.getRegionValueSymbolVal(R);
+ }
+
+ // Otherwise, we need a new symbol. For now return Unknown.
+ return UnknownVal();
+ }
+
+ // The location does not have a bound value. This means that it has
+ // the value it had upon its creation and/or entry to the analyzed
+ // function/method. These are either symbolic values or 'undefined'.
+
+ // We treat function parameters as symbolic values.
+ if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
+ const VarDecl *VD = VR->getDecl();
+
+ if (VD == SelfDecl)
+ return loc::MemRegionVal(getSelfRegion(0));
+
+ if (isa<ParmVarDecl>(VD) || isa<ImplicitParamDecl>(VD) ||
+ VD->hasGlobalStorage()) {
+ QualType VTy = VD->getType();
+ if (Loc::IsLocType(VTy) || VTy->isIntegerType())
+ return ValMgr.getRegionValueSymbolVal(VR);
+ else
+ return UnknownVal();
+ }
+ }
+
+ if (MRMgr.onStack(R) || MRMgr.onHeap(R)) {
+ // All stack variables are considered to have undefined values
+ // upon creation. All heap allocated blocks are considered to
+ // have undefined values as well unless they are explicitly bound
+ // to specific values.
+ return UndefinedVal();
+ }
+
+ // All other integer values are symbolic.
+ if (Loc::IsLocType(RTy) || RTy->isIntegerType())
+ return ValMgr.getRegionValueSymbolVal(R);
+ else
+ return UnknownVal();
+}
+
+SVal RegionStoreManager::RetrieveStruct(const GRState* St,const TypedRegion* R){
+ QualType T = R->getValueType(getContext());
+ assert(T->isStructureType());
+
+ const RecordType* RT = cast<RecordType>(T.getTypePtr());
+ RecordDecl* RD = RT->getDecl();
+ assert(RD->isDefinition());
+
+ llvm::ImmutableList<SVal> StructVal = getBasicVals().getEmptySValList();
+
+ std::vector<FieldDecl *> Fields(RD->field_begin(getContext()),
+ RD->field_end(getContext()));
+
+ for (std::vector<FieldDecl *>::reverse_iterator Field = Fields.rbegin(),
+ FieldEnd = Fields.rend();
+ Field != FieldEnd; ++Field) {
+ FieldRegion* FR = MRMgr.getFieldRegion(*Field, R);
+ QualType FTy = (*Field)->getType();
+ SVal FieldValue = Retrieve(St, loc::MemRegionVal(FR), FTy);
+ StructVal = getBasicVals().consVals(FieldValue, StructVal);
+ }
+
+ return NonLoc::MakeCompoundVal(T, StructVal, getBasicVals());
+}
+
+SVal RegionStoreManager::RetrieveArray(const GRState* St, const TypedRegion* R){
+ QualType T = R->getValueType(getContext());
+ ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr());
+
+ llvm::ImmutableList<SVal> ArrayVal = getBasicVals().getEmptySValList();
+ llvm::APSInt Size(CAT->getSize(), false);
+ llvm::APSInt i = getBasicVals().getZeroWithPtrWidth(false);
+
+ for (; i < Size; ++i) {
+ SVal Idx = NonLoc::MakeVal(getBasicVals(), i);
+ ElementRegion* ER = MRMgr.getElementRegion(CAT->getElementType(), Idx, R);
+ QualType ETy = ER->getElementType();
+ SVal ElementVal = Retrieve(St, loc::MemRegionVal(ER), ETy);
+ ArrayVal = getBasicVals().consVals(ElementVal, ArrayVal);
+ }
+
+ return NonLoc::MakeCompoundVal(T, ArrayVal, getBasicVals());
+}
+
+const GRState* RegionStoreManager::Bind(const GRState* St, Loc L, SVal V) {
+ // If we get here, the location should be a region.
+ const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion();
+ assert(R);
+
+ // Check if the region is a struct region.
+ if (const TypedRegion* TR = dyn_cast<TypedRegion>(R))
+ if (TR->getValueType(getContext())->isStructureType())
+ return BindStruct(St, TR, V);
+
+ Store store = St->getStore();
+ RegionBindingsTy B = GetRegionBindings(store);
+
+ if (V.isUnknown()) {
+ // Remove the binding.
+ store = RBFactory.Remove(B, R).getRoot();
+
+ // Add the region to the killset.
+ GRStateRef state(St, StateMgr);
+ St = state.add<RegionKills>(R);
+ }
+ else
+ store = RBFactory.Add(B, R, V).getRoot();
+
+ return StateMgr.MakeStateWithStore(St, store);
+}
+
+Store RegionStoreManager::Remove(Store store, Loc L) {
+ const MemRegion* R = 0;
+
+ if (isa<loc::MemRegionVal>(L))
+ R = cast<loc::MemRegionVal>(L).getRegion();
+
+ if (R) {
+ RegionBindingsTy B = GetRegionBindings(store);
+ return RBFactory.Remove(B, R).getRoot();
+ }
+
+ return store;
+}
+
+const GRState* RegionStoreManager::BindDecl(const GRState* St,
+ const VarDecl* VD, SVal InitVal) {
+
+ QualType T = VD->getType();
+ VarRegion* VR = MRMgr.getVarRegion(VD);
+
+ if (T->isArrayType())
+ return BindArray(St, VR, InitVal);
+ if (T->isStructureType())
+ return BindStruct(St, VR, InitVal);
+
+ return Bind(St, Loc::MakeVal(VR), InitVal);
+}
+
+// FIXME: this method should be merged into Bind().
+const GRState*
+RegionStoreManager::BindCompoundLiteral(const GRState* St,
+ const CompoundLiteralExpr* CL, SVal V) {
+ CompoundLiteralRegion* R = MRMgr.getCompoundLiteralRegion(CL);
+ return Bind(St, loc::MemRegionVal(R), V);
+}
+
+const GRState* RegionStoreManager::setExtent(const GRState* St,
+ const MemRegion* R, SVal Extent) {
+ GRStateRef state(St, StateMgr);
+ return state.set<RegionExtents>(R, Extent);
+}
+
+
+static void UpdateLiveSymbols(SVal X, SymbolReaper& SymReaper) {
+ if (loc::MemRegionVal *XR = dyn_cast<loc::MemRegionVal>(&X)) {
+ const MemRegion *R = XR->getRegion();
+
+ while (R) {
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
+ SymReaper.markLive(SR->getSymbol());
+ return;
+ }
+
+ if (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
+ R = SR->getSuperRegion();
+ continue;
+ }
+
+ break;
+ }
+
+ return;
+ }
+
+ for (SVal::symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end();SI!=SE;++SI)
+ SymReaper.markLive(*SI);
+}
+
+Store RegionStoreManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
+ SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
+{
+
+ Store store = state->getStore();
+ RegionBindingsTy B = GetRegionBindings(store);
+
+ // Lazily constructed backmap from MemRegions to SubRegions.
+ typedef llvm::ImmutableSet<const MemRegion*> SubRegionsTy;
+ typedef llvm::ImmutableMap<const MemRegion*, SubRegionsTy> SubRegionsMapTy;
+
+ // FIXME: As a future optimization we can modifiy BumpPtrAllocator to have
+ // the ability to reuse memory. This way we can keep TmpAlloc around as
+ // an instance variable of RegionStoreManager (avoiding repeated malloc
+ // overhead).
+ llvm::BumpPtrAllocator TmpAlloc;
+
+ // Factory objects.
+ SubRegionsMapTy::Factory SubRegMapF(TmpAlloc);
+ SubRegionsTy::Factory SubRegF(TmpAlloc);
+
+ // The backmap from regions to subregions.
+ SubRegionsMapTy SubRegMap = SubRegMapF.GetEmptyMap();
+
+ // Do a pass over the regions in the store. For VarRegions we check if
+ // the variable is still live and if so add it to the list of live roots.
+ // For other regions we populate our region backmap.
+
+ llvm::SmallVector<const MemRegion*, 10> IntermediateRoots;
+
+ for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ IntermediateRoots.push_back(I.getKey());
+ }
+
+ while (!IntermediateRoots.empty()) {
+ const MemRegion* R = IntermediateRoots.back();
+ IntermediateRoots.pop_back();
+
+ if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
+ if (SymReaper.isLive(Loc, VR->getDecl()))
+ RegionRoots.push_back(VR); // This is a live "root".
+ }
+ else if (const SymbolicRegion* SR = dyn_cast<SymbolicRegion>(R)) {
+ if (SymReaper.isLive(SR->getSymbol()))
+ RegionRoots.push_back(SR);
+ }
+ else {
+ // Get the super region for R.
+ const MemRegion* SuperR = cast<SubRegion>(R)->getSuperRegion();
+
+ // Get the current set of subregions for SuperR.
+ const SubRegionsTy* SRptr = SubRegMap.lookup(SuperR);
+ SubRegionsTy SRs = SRptr ? *SRptr : SubRegF.GetEmptySet();
+
+ // Add R to the subregions of SuperR.
+ SubRegMap = SubRegMapF.Add(SubRegMap, SuperR, SubRegF.Add(SRs, R));
+
+ // Super region may be VarRegion or subregion of another VarRegion. Add it
+ // to the work list.
+ if (isa<SubRegion>(SuperR))
+ IntermediateRoots.push_back(SuperR);
+ }
+ }
+
+ // Process the worklist of RegionRoots. This performs a "mark-and-sweep"
+ // of the store. We want to find all live symbols and dead regions.
+ llvm::SmallPtrSet<const MemRegion*, 10> Marked;
+
+ while (!RegionRoots.empty()) {
+ // Dequeue the next region on the worklist.
+ const MemRegion* R = RegionRoots.back();
+ RegionRoots.pop_back();
+
+ // Check if we have already processed this region.
+ if (Marked.count(R)) continue;
+
+ // Mark this region as processed. This is needed for termination in case
+ // a region is referenced more than once.
+ Marked.insert(R);
+
+ // Mark the symbol for any live SymbolicRegion as "live". This means we
+ // should continue to track that symbol.
+ if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
+ SymReaper.markLive(SymR->getSymbol());
+
+ // Get the data binding for R (if any).
+ RegionBindingsTy::data_type* Xptr = B.lookup(R);
+ if (Xptr) {
+ SVal X = *Xptr;
+ UpdateLiveSymbols(X, SymReaper); // Update the set of live symbols.
+
+ // If X is a region, then add it the RegionRoots.
+ if (loc::MemRegionVal* RegionX = dyn_cast<loc::MemRegionVal>(&X))
+ RegionRoots.push_back(RegionX->getRegion());
+ }
+
+ // Get the subregions of R. These are RegionRoots as well since they
+ // represent values that are also bound to R.
+ const SubRegionsTy* SRptr = SubRegMap.lookup(R);
+ if (!SRptr) continue;
+ SubRegionsTy SR = *SRptr;
+
+ for (SubRegionsTy::iterator I=SR.begin(), E=SR.end(); I!=E; ++I)
+ RegionRoots.push_back(*I);
+ }
+
+ // We have now scanned the store, marking reachable regions and symbols
+ // as live. We now remove all the regions that are dead from the store
+ // as well as update DSymbols with the set symbols that are now dead.
+ for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ const MemRegion* R = I.getKey();
+
+ // If this region live? Is so, none of its symbols are dead.
+ if (Marked.count(R))
+ continue;
+
+ // Remove this dead region from the store.
+ store = Remove(store, Loc::MakeVal(R));
+
+ // Mark all non-live symbols that this region references as dead.
+ if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
+ SymReaper.maybeDead(SymR->getSymbol());
+
+ SVal X = I.getData();
+ SVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
+ for (; SI != SE; ++SI) SymReaper.maybeDead(*SI);
+ }
+
+ return store;
+}
+
+void RegionStoreManager::print(Store store, std::ostream& Out,
+ const char* nl, const char *sep) {
+ llvm::raw_os_ostream OS(Out);
+ RegionBindingsTy B = GetRegionBindings(store);
+ OS << "Store:" << nl;
+
+ for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ OS << ' '; I.getKey()->print(OS); OS << " : ";
+ I.getData().print(OS); OS << nl;
+ }
+}
+
+const GRState* RegionStoreManager::BindArray(const GRState* St,
+ const TypedRegion* R, SVal Init) {
+ QualType T = R->getValueType(getContext());
+ assert(T->isArrayType());
+
+ // When we are binding the whole array, it always has default value 0.
+ GRStateRef state(St, StateMgr);
+ St = state.set<RegionDefaultValue>(R, NonLoc::MakeIntVal(getBasicVals(), 0,
+ false));
+
+ ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr());
+
+ llvm::APSInt Size(CAT->getSize(), false);
+ llvm::APSInt i = getBasicVals().getValue(0, Size.getBitWidth(),
+ Size.isUnsigned());
+
+ // Check if the init expr is a StringLiteral.
+ if (isa<loc::MemRegionVal>(Init)) {
+ const MemRegion* InitR = cast<loc::MemRegionVal>(Init).getRegion();
+ const StringLiteral* S = cast<StringRegion>(InitR)->getStringLiteral();
+ const char* str = S->getStrData();
+ unsigned len = S->getByteLength();
+ unsigned j = 0;
+
+ // Copy bytes from the string literal into the target array. Trailing bytes
+ // in the array that are not covered by the string literal are initialized
+ // to zero.
+ for (; i < Size; ++i, ++j) {
+ if (j >= len)
+ break;
+
+ SVal Idx = NonLoc::MakeVal(getBasicVals(), i);
+ ElementRegion* ER =
+ MRMgr.getElementRegion(cast<ArrayType>(T)->getElementType(),
+ Idx, R);
+
+ SVal V = NonLoc::MakeVal(getBasicVals(), str[j], sizeof(char)*8, true);
+ St = Bind(St, loc::MemRegionVal(ER), V);
+ }
+
+ return St;
+ }
+
+ nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(Init);
+ nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
+
+ for (; i < Size; ++i, ++VI) {
+ // The init list might be shorter than the array decl.
+ if (VI == VE)
+ break;
+
+ SVal Idx = NonLoc::MakeVal(getBasicVals(), i);
+ ElementRegion* ER =
+ MRMgr.getElementRegion(cast<ArrayType>(T)->getElementType(),
+ Idx, R);
+
+ if (CAT->getElementType()->isStructureType())
+ St = BindStruct(St, ER, *VI);
+ else
+ St = Bind(St, Loc::MakeVal(ER), *VI);
+ }
+
+ return St;
+}
+
+const GRState*
+RegionStoreManager::BindStruct(const GRState* St, const TypedRegion* R, SVal V){
+ QualType T = R->getValueType(getContext());
+ assert(T->isStructureType());
+
+ const RecordType* RT = T->getAsRecordType();
+ RecordDecl* RD = RT->getDecl();
+
+ if (!RD->isDefinition())
+ return St;
+
+ if (V.isUnknown())
+ return KillStruct(St, R);
+
+ nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V);
+ nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
+ RecordDecl::field_iterator FI = RD->field_begin(getContext()),
+ FE = RD->field_end(getContext());
+
+ for (; FI != FE; ++FI, ++VI) {
+
+ // There may be fewer values than fields only when we are initializing a
+ // struct decl. In this case, mark the region as having default value.
+ if (VI == VE) {
+ GRStateRef state(St, StateMgr);
+ const NonLoc& Idx = NonLoc::MakeIntVal(getBasicVals(), 0, false);
+ St = state.set<RegionDefaultValue>(R, Idx);
+ break;
+ }
+
+ QualType FTy = (*FI)->getType();
+ FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
+
+ if (Loc::IsLocType(FTy) || FTy->isIntegerType())
+ St = Bind(St, Loc::MakeVal(FR), *VI);
+
+ else if (FTy->isArrayType())
+ St = BindArray(St, FR, *VI);
+
+ else if (FTy->isStructureType())
+ St = BindStruct(St, FR, *VI);
+ }
+
+ return St;
+}
+
+const GRState* RegionStoreManager::KillStruct(const GRState* St,
+ const TypedRegion* R){
+ GRStateRef state(St, StateMgr);
+
+ // Kill the struct region because it is assigned "unknown".
+ St = state.add<RegionKills>(R);
+
+ // Set the default value of the struct region to "unknown".
+ St = state.set<RegionDefaultValue>(R, UnknownVal());
+
+ Store store = St->getStore();
+ RegionBindingsTy B = GetRegionBindings(store);
+
+ // Remove all bindings for the subregions of the struct.
+ for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ const MemRegion* r = I.getKey();
+ if (const SubRegion* sr = dyn_cast<SubRegion>(r))
+ if (sr->isSubRegionOf(R))
+ store = Remove(store, Loc::MakeVal(sr));
+ // FIXME: Maybe we should also remove the bindings for the "views" of the
+ // subregions.
+ }
+
+ return StateMgr.MakeStateWithStore(St, store);
+}
+
+const GRState* RegionStoreManager::AddRegionView(const GRState* St,
+ const MemRegion* View,
+ const MemRegion* Base) {
+ GRStateRef state(St, StateMgr);
+
+ // First, retrieve the region view of the base region.
+ const RegionViews* d = state.get<RegionViewMap>(Base);
+ RegionViews L = d ? *d : RVFactory.GetEmptySet();
+
+ // Now add View to the region view.
+ L = RVFactory.Add(L, View);
+
+ // Create a new state with the new region view.
+ return state.set<RegionViewMap>(Base, L);
+}
+
+const GRState* RegionStoreManager::RemoveRegionView(const GRState* St,
+ const MemRegion* View,
+ const MemRegion* Base) {
+ GRStateRef state(St, StateMgr);
+
+ // Retrieve the region view of the base region.
+ const RegionViews* d = state.get<RegionViewMap>(Base);
+
+ // If the base region has no view, return.
+ if (!d)
+ return St;
+
+ // Remove the view.
+ RegionViews V = *d;
+ V = RVFactory.Remove(V, View);
+
+ return state.set<RegionViewMap>(Base, V);
+}
+
+const GRState* RegionStoreManager::setCastType(const GRState* St,
+ const MemRegion* R, QualType T) {
+ GRStateRef state(St, StateMgr);
+ return state.set<RegionCasts>(R, T);
+}
+
+const GRState* RegionStoreManager::setDefaultValue(const GRState* St,
+ const MemRegion* R, SVal V) {
+ GRStateRef state(St, StateMgr);
+ return state.set<RegionDefaultValue>(R, V);
+}
diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp
new file mode 100644
index 000000000000..e19b16867b39
--- /dev/null
+++ b/lib/Analysis/SVals.cpp
@@ -0,0 +1,513 @@
+//= RValues.cpp - Abstract RValues for Path-Sens. Value Tracking -*- 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 SVal, Loc, and NonLoc, classes that represent
+// abstract r-values for use with path-sensitive value tracking.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "llvm/Support/Streams.h"
+
+using namespace clang;
+using llvm::dyn_cast;
+using llvm::cast;
+using llvm::APSInt;
+
+//===----------------------------------------------------------------------===//
+// Symbol iteration within an SVal.
+//===----------------------------------------------------------------------===//
+
+
+//===----------------------------------------------------------------------===//
+// Utility methods.
+//===----------------------------------------------------------------------===//
+
+bool SVal::hasConjuredSymbol() const {
+ if (const nonloc::SymbolVal* SV = dyn_cast<nonloc::SymbolVal>(this)) {
+ SymbolRef sym = SV->getSymbol();
+ if (isa<SymbolConjured>(sym))
+ return true;
+ }
+
+ if (const loc::MemRegionVal *RV = dyn_cast<loc::MemRegionVal>(this)) {
+ const MemRegion *R = RV->getRegion();
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
+ SymbolRef sym = SR->getSymbol();
+ if (isa<SymbolConjured>(sym))
+ return true;
+ } else if (const CodeTextRegion *CTR = dyn_cast<CodeTextRegion>(R)) {
+ if (CTR->isSymbolic()) {
+ SymbolRef sym = CTR->getSymbol();
+ if (isa<SymbolConjured>(sym))
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+const FunctionDecl* SVal::getAsFunctionDecl() const {
+ if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(this)) {
+ const MemRegion* R = X->getRegion();
+ if (const CodeTextRegion* CTR = R->getAs<CodeTextRegion>()) {
+ if (CTR->isDeclared())
+ return CTR->getDecl();
+ }
+ }
+
+ return 0;
+}
+
+/// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
+/// wraps a symbol, return that SymbolRef. Otherwise return 0.
+// FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
+SymbolRef SVal::getAsLocSymbol() const {
+ if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) {
+ const MemRegion *R = X->getRegion();
+
+ while (R) {
+ // Blast through region views.
+ if (const TypedViewRegion *View = dyn_cast<TypedViewRegion>(R)) {
+ R = View->getSuperRegion();
+ continue;
+ }
+
+ if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
+ return SymR->getSymbol();
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
+/// Otherwise return 0.
+// FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
+SymbolRef SVal::getAsSymbol() const {
+ if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
+ return X->getSymbol();
+
+ if (const nonloc::SymExprVal *X = dyn_cast<nonloc::SymExprVal>(this))
+ if (SymbolRef Y = dyn_cast<SymbolData>(X->getSymbolicExpression()))
+ return Y;
+
+ return getAsLocSymbol();
+}
+
+/// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
+/// return that expression. Otherwise return NULL.
+const SymExpr *SVal::getAsSymbolicExpression() const {
+ if (const nonloc::SymExprVal *X = dyn_cast<nonloc::SymExprVal>(this))
+ return X->getSymbolicExpression();
+
+ return getAsSymbol();
+}
+
+bool SVal::symbol_iterator::operator==(const symbol_iterator &X) const {
+ return itr == X.itr;
+}
+
+bool SVal::symbol_iterator::operator!=(const symbol_iterator &X) const {
+ return itr != X.itr;
+}
+
+SVal::symbol_iterator::symbol_iterator(const SymExpr *SE) {
+ itr.push_back(SE);
+ while (!isa<SymbolData>(itr.back())) expand();
+}
+
+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();
+ if (!itr.empty())
+ while (!isa<SymbolData>(itr.back())) expand();
+ return *this;
+}
+
+SymbolRef SVal::symbol_iterator::operator*() {
+ assert(!itr.empty() && "attempting to dereference an 'end' iterator");
+ return cast<SymbolData>(itr.back());
+}
+
+void SVal::symbol_iterator::expand() {
+ const SymExpr *SE = itr.back();
+ itr.pop_back();
+
+ if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SE)) {
+ itr.push_back(SIE->getLHS());
+ return;
+ }
+ else if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(SE)) {
+ itr.push_back(SSE->getLHS());
+ itr.push_back(SSE->getRHS());
+ return;
+ }
+
+ assert(false && "unhandled expansion case");
+}
+
+//===----------------------------------------------------------------------===//
+// Other Iterators.
+//===----------------------------------------------------------------------===//
+
+nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const {
+ return getValue()->begin();
+}
+
+nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
+ return getValue()->end();
+}
+
+//===----------------------------------------------------------------------===//
+// Useful predicates.
+//===----------------------------------------------------------------------===//
+
+bool SVal::isZeroConstant() const {
+ if (isa<loc::ConcreteInt>(*this))
+ return cast<loc::ConcreteInt>(*this).getValue() == 0;
+ else if (isa<nonloc::ConcreteInt>(*this))
+ return cast<nonloc::ConcreteInt>(*this).getValue() == 0;
+ else
+ return false;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Transfer function dispatch for Non-Locs.
+//===----------------------------------------------------------------------===//
+
+SVal nonloc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
+ BinaryOperator::Opcode Op,
+ const nonloc::ConcreteInt& R) const {
+
+ const llvm::APSInt* X =
+ BasicVals.EvaluateAPSInt(Op, getValue(), R.getValue());
+
+ if (X)
+ return nonloc::ConcreteInt(*X);
+ else
+ return UndefinedVal();
+}
+
+ // Bitwise-Complement.
+
+nonloc::ConcreteInt
+nonloc::ConcreteInt::EvalComplement(BasicValueFactory& BasicVals) const {
+ return BasicVals.getValue(~getValue());
+}
+
+ // Unary Minus.
+
+nonloc::ConcreteInt
+nonloc::ConcreteInt::EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U) const {
+ assert (U->getType() == U->getSubExpr()->getType());
+ assert (U->getType()->isIntegerType());
+ return BasicVals.getValue(-getValue());
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function dispatch for Locs.
+//===----------------------------------------------------------------------===//
+
+SVal loc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
+ BinaryOperator::Opcode Op,
+ const loc::ConcreteInt& R) const {
+
+ assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub ||
+ (Op >= BinaryOperator::LT && Op <= BinaryOperator::NE));
+
+ const llvm::APSInt* X = BasicVals.EvaluateAPSInt(Op, getValue(), R.getValue());
+
+ if (X)
+ return loc::ConcreteInt(*X);
+ else
+ return UndefinedVal();
+}
+
+//===----------------------------------------------------------------------===//
+// Utility methods for constructing SVals.
+//===----------------------------------------------------------------------===//
+
+SVal ValueManager::makeZeroVal(QualType T) {
+ if (Loc::IsLocType(T))
+ return Loc::MakeNull(BasicVals);
+
+ if (T->isIntegerType())
+ return NonLoc::MakeVal(BasicVals, 0, T);
+
+ // FIXME: Handle floats.
+ // FIXME: Handle structs.
+ return UnknownVal();
+}
+
+SVal ValueManager::makeZeroArrayIndex() {
+ return nonloc::ConcreteInt(BasicVals.getZeroWithPtrWidth(false));
+}
+
+//===----------------------------------------------------------------------===//
+// Utility methods for constructing Non-Locs.
+//===----------------------------------------------------------------------===//
+
+NonLoc ValueManager::makeNonLoc(SymbolRef sym) {
+ return nonloc::SymbolVal(sym);
+}
+
+NonLoc ValueManager::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const APSInt& v, QualType T) {
+ // The Environment ensures we always get a persistent APSInt in
+ // BasicValueFactory, so we don't need to get the APSInt from
+ // BasicValueFactory again.
+ assert(!Loc::IsLocType(T));
+ return nonloc::SymExprVal(SymMgr.getSymIntExpr(lhs, op, v, T));
+}
+
+NonLoc ValueManager::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const SymExpr *rhs, QualType T) {
+ assert(SymMgr.getType(lhs) == SymMgr.getType(rhs));
+ assert(!Loc::IsLocType(T));
+ return nonloc::SymExprVal(SymMgr.getSymSymExpr(lhs, op, rhs, T));
+}
+
+NonLoc NonLoc::MakeIntVal(BasicValueFactory& BasicVals, uint64_t X,
+ bool isUnsigned) {
+ return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned));
+}
+
+NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, uint64_t X,
+ unsigned BitWidth, bool isUnsigned) {
+ return nonloc::ConcreteInt(BasicVals.getValue(X, BitWidth, isUnsigned));
+}
+
+NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, uint64_t X, QualType T) {
+ return nonloc::ConcreteInt(BasicVals.getValue(X, T));
+}
+
+NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, IntegerLiteral* I) {
+
+ return nonloc::ConcreteInt(BasicVals.getValue(APSInt(I->getValue(),
+ I->getType()->isUnsignedIntegerType())));
+}
+
+NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, const llvm::APInt& I,
+ bool isUnsigned) {
+ return nonloc::ConcreteInt(BasicVals.getValue(I, isUnsigned));
+}
+
+NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, const llvm::APSInt& I) {
+ return nonloc::ConcreteInt(BasicVals.getValue(I));
+}
+
+NonLoc NonLoc::MakeIntTruthVal(BasicValueFactory& BasicVals, bool b) {
+ return nonloc::ConcreteInt(BasicVals.getTruthValue(b));
+}
+
+NonLoc ValueManager::makeTruthVal(bool b, QualType T) {
+ return nonloc::ConcreteInt(BasicVals.getTruthValue(b, T));
+}
+
+NonLoc NonLoc::MakeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals,
+ BasicValueFactory& BasicVals) {
+ return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals));
+}
+
+SVal ValueManager::getRegionValueSymbolVal(const MemRegion* R) {
+ SymbolRef sym = SymMgr.getRegionValueSymbol(R);
+
+ if (const TypedRegion* TR = dyn_cast<TypedRegion>(R)) {
+ QualType T = TR->getValueType(SymMgr.getContext());
+
+ // If T is of function pointer type, create a CodeTextRegion wrapping a
+ // symbol.
+ if (T->isFunctionPointerType()) {
+ return Loc::MakeVal(MemMgr.getCodeTextRegion(sym, T));
+ }
+
+ if (Loc::IsLocType(T))
+ return Loc::MakeVal(MemMgr.getSymbolicRegion(sym));
+
+ // Only handle integers for now.
+ if (T->isIntegerType() && T->isScalarType())
+ return makeNonLoc(sym);
+ }
+
+ return UnknownVal();
+}
+
+SVal ValueManager::getConjuredSymbolVal(const Expr* E, unsigned Count) {
+ QualType T = E->getType();
+ SymbolRef sym = SymMgr.getConjuredSymbol(E, Count);
+
+ // If T is of function pointer type, create a CodeTextRegion wrapping a
+ // symbol.
+ if (T->isFunctionPointerType()) {
+ return Loc::MakeVal(MemMgr.getCodeTextRegion(sym, T));
+ }
+
+ if (Loc::IsLocType(T))
+ return Loc::MakeVal(MemMgr.getSymbolicRegion(sym));
+
+ if (T->isIntegerType() && T->isScalarType())
+ return makeNonLoc(sym);
+
+ return UnknownVal();
+}
+
+SVal ValueManager::getConjuredSymbolVal(const Expr* E, QualType T,
+ unsigned Count) {
+
+ SymbolRef sym = SymMgr.getConjuredSymbol(E, T, Count);
+
+ // If T is of function pointer type, create a CodeTextRegion wrapping a
+ // symbol.
+ if (T->isFunctionPointerType()) {
+ return Loc::MakeVal(MemMgr.getCodeTextRegion(sym, T));
+ }
+
+ if (Loc::IsLocType(T))
+ return Loc::MakeVal(MemMgr.getSymbolicRegion(sym));
+
+ if (T->isIntegerType() && T->isScalarType())
+ return makeNonLoc(sym);
+
+ return UnknownVal();
+}
+
+SVal ValueManager::getFunctionPointer(const FunctionDecl* FD) {
+ CodeTextRegion* R
+ = MemMgr.getCodeTextRegion(FD, Context.getPointerType(FD->getType()));
+ return loc::MemRegionVal(R);
+}
+
+nonloc::LocAsInteger nonloc::LocAsInteger::Make(BasicValueFactory& Vals, Loc V,
+ unsigned Bits) {
+ return LocAsInteger(Vals.getPersistentSValWithData(V, Bits));
+}
+
+//===----------------------------------------------------------------------===//
+// Utility methods for constructing Locs.
+//===----------------------------------------------------------------------===//
+
+Loc Loc::MakeVal(const MemRegion* R) { return loc::MemRegionVal(R); }
+
+Loc Loc::MakeVal(AddrLabelExpr* E) { return loc::GotoLabel(E->getLabel()); }
+
+Loc Loc::MakeNull(BasicValueFactory &BasicVals) {
+ return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth());
+}
+
+//===----------------------------------------------------------------------===//
+// Pretty-Printing.
+//===----------------------------------------------------------------------===//
+
+void SVal::printStdErr() const { print(llvm::errs()); }
+
+void SVal::print(std::ostream& Out) const {
+ llvm::raw_os_ostream out(Out);
+ print(out);
+}
+
+void SVal::print(llvm::raw_ostream& Out) const {
+
+ switch (getBaseKind()) {
+
+ case UnknownKind:
+ Out << "Invalid"; break;
+
+ case NonLocKind:
+ cast<NonLoc>(this)->print(Out); break;
+
+ case LocKind:
+ cast<Loc>(this)->print(Out); break;
+
+ case UndefinedKind:
+ Out << "Undefined"; break;
+
+ default:
+ assert (false && "Invalid SVal.");
+ }
+}
+
+void NonLoc::print(llvm::raw_ostream& Out) const {
+
+ switch (getSubKind()) {
+
+ case nonloc::ConcreteIntKind:
+ Out << cast<nonloc::ConcreteInt>(this)->getValue().getZExtValue();
+
+ if (cast<nonloc::ConcreteInt>(this)->getValue().isUnsigned())
+ Out << 'U';
+
+ break;
+
+ case nonloc::SymbolValKind:
+ Out << '$' << cast<nonloc::SymbolVal>(this)->getSymbol();
+ break;
+
+ case nonloc::SymExprValKind: {
+ const nonloc::SymExprVal& C = *cast<nonloc::SymExprVal>(this);
+ const SymExpr *SE = C.getSymbolicExpression();
+ Out << SE;
+ break;
+ }
+
+ case nonloc::LocAsIntegerKind: {
+ const nonloc::LocAsInteger& C = *cast<nonloc::LocAsInteger>(this);
+ C.getLoc().print(Out);
+ Out << " [as " << C.getNumBits() << " bit integer]";
+ break;
+ }
+
+ case nonloc::CompoundValKind: {
+ const nonloc::CompoundVal& C = *cast<nonloc::CompoundVal>(this);
+ Out << " {";
+ bool first = true;
+ for (nonloc::CompoundVal::iterator I=C.begin(), E=C.end(); I!=E; ++I) {
+ if (first) { Out << ' '; first = false; }
+ else Out << ", ";
+ (*I).print(Out);
+ }
+ Out << " }";
+ break;
+ }
+
+ default:
+ assert (false && "Pretty-printed not implemented for this NonLoc.");
+ break;
+ }
+}
+
+void Loc::print(llvm::raw_ostream& Out) const {
+
+ switch (getSubKind()) {
+
+ case loc::ConcreteIntKind:
+ Out << cast<loc::ConcreteInt>(this)->getValue().getZExtValue()
+ << " (Loc)";
+ break;
+
+ case loc::GotoLabelKind:
+ Out << "&&"
+ << cast<loc::GotoLabel>(this)->getLabel()->getID()->getName();
+ break;
+
+ case loc::MemRegionKind:
+ Out << '&' << cast<loc::MemRegionVal>(this)->getRegion()->getString();
+ break;
+
+ default:
+ assert (false && "Pretty-printing not implemented for this Loc.");
+ break;
+ }
+}
diff --git a/lib/Analysis/SimpleConstraintManager.cpp b/lib/Analysis/SimpleConstraintManager.cpp
new file mode 100644
index 000000000000..f79dba0cc5ee
--- /dev/null
+++ b/lib/Analysis/SimpleConstraintManager.cpp
@@ -0,0 +1,263 @@
+//== SimpleConstraintManager.cpp --------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SimpleConstraintManager, a class that holds code shared
+// between BasicConstraintManager and RangeConstraintManager.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SimpleConstraintManager.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+
+namespace clang {
+
+SimpleConstraintManager::~SimpleConstraintManager() {}
+
+bool SimpleConstraintManager::canReasonAbout(SVal X) const {
+ if (nonloc::SymExprVal *SymVal = dyn_cast<nonloc::SymExprVal>(&X)) {
+ const SymExpr *SE = SymVal->getSymbolicExpression();
+
+ if (isa<SymbolData>(SE))
+ return true;
+
+ if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SE)) {
+ switch (SIE->getOpcode()) {
+ // We don't reason yet about bitwise-constraints on symbolic values.
+ case BinaryOperator::And:
+ case BinaryOperator::Or:
+ case BinaryOperator::Xor:
+ return false;
+ // We don't reason yet about arithmetic constraints on symbolic values.
+ case BinaryOperator::Mul:
+ case BinaryOperator::Div:
+ case BinaryOperator::Rem:
+ case BinaryOperator::Add:
+ case BinaryOperator::Sub:
+ case BinaryOperator::Shl:
+ case BinaryOperator::Shr:
+ return false;
+ // All other cases.
+ default:
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+const GRState*
+SimpleConstraintManager::Assume(const GRState* St, SVal Cond, bool Assumption,
+ bool& isFeasible) {
+ if (Cond.isUnknown()) {
+ isFeasible = true;
+ return St;
+ }
+
+ if (isa<NonLoc>(Cond))
+ return Assume(St, cast<NonLoc>(Cond), Assumption, isFeasible);
+ else
+ return Assume(St, cast<Loc>(Cond), Assumption, isFeasible);
+}
+
+const GRState*
+SimpleConstraintManager::Assume(const GRState* St, Loc Cond, bool Assumption,
+ bool& isFeasible) {
+ St = AssumeAux(St, Cond, Assumption, isFeasible);
+
+ if (!isFeasible)
+ return St;
+
+ // EvalAssume is used to call into the GRTransferFunction object to perform
+ // any checker-specific update of the state based on this assumption being
+ // true or false.
+ return StateMgr.getTransferFuncs().EvalAssume(StateMgr, St, Cond, Assumption,
+ isFeasible);
+}
+
+const GRState*
+SimpleConstraintManager::AssumeAux(const GRState* St, Loc Cond, bool Assumption,
+ bool& isFeasible) {
+ BasicValueFactory& BasicVals = StateMgr.getBasicVals();
+
+ switch (Cond.getSubKind()) {
+ default:
+ assert (false && "'Assume' not implemented for this Loc.");
+ return St;
+
+ case loc::MemRegionKind: {
+ // FIXME: Should this go into the storemanager?
+
+ const MemRegion* R = cast<loc::MemRegionVal>(Cond).getRegion();
+ const SubRegion* SubR = dyn_cast<SubRegion>(R);
+
+ while (SubR) {
+ // FIXME: now we only find the first symbolic region.
+ if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(SubR)) {
+ if (Assumption)
+ return AssumeSymNE(St, SymR->getSymbol(),
+ BasicVals.getZeroWithPtrWidth(), isFeasible);
+ else
+ return AssumeSymEQ(St, SymR->getSymbol(),
+ BasicVals.getZeroWithPtrWidth(), isFeasible);
+ }
+ SubR = dyn_cast<SubRegion>(SubR->getSuperRegion());
+ }
+
+ // FALL-THROUGH.
+ }
+
+ case loc::GotoLabelKind:
+ isFeasible = Assumption;
+ return St;
+
+ case loc::ConcreteIntKind: {
+ bool b = cast<loc::ConcreteInt>(Cond).getValue() != 0;
+ isFeasible = b ? Assumption : !Assumption;
+ return St;
+ }
+ } // end switch
+}
+
+const GRState*
+SimpleConstraintManager::Assume(const GRState* St, NonLoc Cond, bool Assumption,
+ bool& isFeasible) {
+ St = AssumeAux(St, Cond, Assumption, isFeasible);
+
+ if (!isFeasible)
+ return St;
+
+ // EvalAssume is used to call into the GRTransferFunction object to perform
+ // any checker-specific update of the state based on this assumption being
+ // true or false.
+ return StateMgr.getTransferFuncs().EvalAssume(StateMgr, St, Cond, Assumption,
+ isFeasible);
+}
+
+const GRState*
+SimpleConstraintManager::AssumeAux(const GRState* St,NonLoc Cond,
+ bool Assumption, bool& isFeasible) {
+ // We cannot reason about SymIntExpr and SymSymExpr.
+ if (!canReasonAbout(Cond)) {
+ isFeasible = true;
+ return St;
+ }
+
+ BasicValueFactory& BasicVals = StateMgr.getBasicVals();
+ SymbolManager& SymMgr = StateMgr.getSymbolManager();
+
+ switch (Cond.getSubKind()) {
+ default:
+ assert(false && "'Assume' not implemented for this NonLoc");
+
+ case nonloc::SymbolValKind: {
+ nonloc::SymbolVal& SV = cast<nonloc::SymbolVal>(Cond);
+ SymbolRef sym = SV.getSymbol();
+ QualType T = SymMgr.getType(sym);
+
+ if (Assumption)
+ return AssumeSymNE(St, sym, BasicVals.getValue(0, T), isFeasible);
+ else
+ return AssumeSymEQ(St, sym, BasicVals.getValue(0, T), isFeasible);
+ }
+
+ case nonloc::SymExprValKind: {
+ nonloc::SymExprVal V = cast<nonloc::SymExprVal>(Cond);
+ if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(V.getSymbolicExpression()))
+ return AssumeSymInt(St, Assumption, SE, isFeasible);
+
+ isFeasible = true;
+ return St;
+ }
+
+ case nonloc::ConcreteIntKind: {
+ bool b = cast<nonloc::ConcreteInt>(Cond).getValue() != 0;
+ isFeasible = b ? Assumption : !Assumption;
+ return St;
+ }
+
+ case nonloc::LocAsIntegerKind:
+ return AssumeAux(St, cast<nonloc::LocAsInteger>(Cond).getLoc(),
+ Assumption, isFeasible);
+ } // end switch
+}
+
+const GRState*
+SimpleConstraintManager::AssumeSymInt(const GRState* St, bool Assumption,
+ const SymIntExpr *SE, bool& isFeasible) {
+
+
+ // Here we assume that LHS is a symbol. This is consistent with the
+ // rest of the constraint manager logic.
+ SymbolRef Sym = cast<SymbolData>(SE->getLHS());
+ const llvm::APSInt &Int = SE->getRHS();
+
+ switch (SE->getOpcode()) {
+ default:
+ // No logic yet for other operators.
+ isFeasible = true;
+ return St;
+
+ case BinaryOperator::EQ:
+ return Assumption ? AssumeSymEQ(St, Sym, Int, isFeasible)
+ : AssumeSymNE(St, Sym, Int, isFeasible);
+
+ case BinaryOperator::NE:
+ return Assumption ? AssumeSymNE(St, Sym, Int, isFeasible)
+ : AssumeSymEQ(St, Sym, Int, isFeasible);
+
+ case BinaryOperator::GT:
+ return Assumption ? AssumeSymGT(St, Sym, Int, isFeasible)
+ : AssumeSymLE(St, Sym, Int, isFeasible);
+
+ case BinaryOperator::GE:
+ return Assumption ? AssumeSymGE(St, Sym, Int, isFeasible)
+ : AssumeSymLT(St, Sym, Int, isFeasible);
+
+ case BinaryOperator::LT:
+ return Assumption ? AssumeSymLT(St, Sym, Int, isFeasible)
+ : AssumeSymGE(St, Sym, Int, isFeasible);
+
+ case BinaryOperator::LE:
+ return Assumption ? AssumeSymLE(St, Sym, Int, isFeasible)
+ : AssumeSymGT(St, Sym, Int, isFeasible);
+ } // end switch
+}
+
+const GRState*
+SimpleConstraintManager::AssumeInBound(const GRState* St, SVal Idx,
+ SVal UpperBound, bool Assumption,
+ bool& isFeasible) {
+ // Only support ConcreteInt for now.
+ if (!(isa<nonloc::ConcreteInt>(Idx) && isa<nonloc::ConcreteInt>(UpperBound))){
+ isFeasible = true;
+ return St;
+ }
+
+ const llvm::APSInt& Zero = getBasicVals().getZeroWithPtrWidth(false);
+ llvm::APSInt IdxV = cast<nonloc::ConcreteInt>(Idx).getValue();
+ // IdxV might be too narrow.
+ if (IdxV.getBitWidth() < Zero.getBitWidth())
+ IdxV.extend(Zero.getBitWidth());
+ // UBV might be too narrow, too.
+ llvm::APSInt UBV = cast<nonloc::ConcreteInt>(UpperBound).getValue();
+ if (UBV.getBitWidth() < Zero.getBitWidth())
+ UBV.extend(Zero.getBitWidth());
+
+ bool InBound = (Zero <= IdxV) && (IdxV < UBV);
+
+ isFeasible = Assumption ? InBound : !InBound;
+
+ return St;
+}
+
+} // end of namespace clang
diff --git a/lib/Analysis/SimpleConstraintManager.h b/lib/Analysis/SimpleConstraintManager.h
new file mode 100644
index 000000000000..fb41e2f1dab2
--- /dev/null
+++ b/lib/Analysis/SimpleConstraintManager.h
@@ -0,0 +1,84 @@
+//== SimpleConstraintManager.h ----------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Code shared between BasicConstraintManager and RangeConstraintManager.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_SIMPLE_CONSTRAINT_MANAGER_H
+#define LLVM_CLANG_ANALYSIS_SIMPLE_CONSTRAINT_MANAGER_H
+
+#include "clang/Analysis/PathSensitive/ConstraintManager.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+
+namespace clang {
+
+class SimpleConstraintManager : public ConstraintManager {
+protected:
+ GRStateManager& StateMgr;
+public:
+ SimpleConstraintManager(GRStateManager& statemgr)
+ : StateMgr(statemgr) {}
+ virtual ~SimpleConstraintManager();
+
+ bool canReasonAbout(SVal X) const;
+
+ virtual const GRState* Assume(const GRState* St, SVal Cond, bool Assumption,
+ bool& isFeasible);
+
+ const GRState* Assume(const GRState* St, Loc Cond, bool Assumption,
+ bool& isFeasible);
+
+ const GRState* AssumeAux(const GRState* St, Loc Cond,bool Assumption,
+ bool& isFeasible);
+
+ const GRState* Assume(const GRState* St, NonLoc Cond, bool Assumption,
+ bool& isFeasible);
+
+ const GRState* AssumeAux(const GRState* St, NonLoc Cond, bool Assumption,
+ bool& isFeasible);
+
+ const GRState* AssumeSymInt(const GRState* St, bool Assumption,
+ const SymIntExpr *SE, bool& isFeasible);
+
+ virtual const GRState* AssumeSymNE(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V,
+ bool& isFeasible) = 0;
+
+ virtual const GRState* AssumeSymEQ(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V,
+ bool& isFeasible) = 0;
+
+ virtual const GRState* AssumeSymLT(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V,
+ bool& isFeasible) = 0;
+
+ virtual const GRState* AssumeSymGT(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V,
+ bool& isFeasible) = 0;
+
+ virtual const GRState* AssumeSymLE(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V,
+ bool& isFeasible) = 0;
+
+ virtual const GRState* AssumeSymGE(const GRState* St, SymbolRef sym,
+ const llvm::APSInt& V,
+ bool& isFeasible) = 0;
+
+ const GRState* AssumeInBound(const GRState* St, SVal Idx, SVal UpperBound,
+ bool Assumption, bool& isFeasible);
+
+private:
+ BasicValueFactory& getBasicVals() { return StateMgr.getBasicVals(); }
+ SymbolManager& getSymbolManager() const { return StateMgr.getSymbolManager(); }
+};
+
+} // end clang namespace
+
+#endif
diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp
new file mode 100644
index 000000000000..13326ab31f82
--- /dev/null
+++ b/lib/Analysis/Store.cpp
@@ -0,0 +1,110 @@
+//== Store.cpp - Interface for maps 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 types Store and StoreManager.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/Store.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+
+using namespace clang;
+
+StoreManager::StoreManager(GRStateManager &stateMgr)
+ : ValMgr(stateMgr.getValueManager()),
+ StateMgr(stateMgr),
+ MRMgr(ValMgr.getRegionManager()) {}
+
+StoreManager::CastResult
+StoreManager::CastRegion(const GRState* state, const MemRegion* R,
+ QualType CastToTy) {
+
+ ASTContext& Ctx = StateMgr.getContext();
+
+ // We need to know the real type of CastToTy.
+ QualType ToTy = Ctx.getCanonicalType(CastToTy);
+
+ // Return the same region if the region types are compatible.
+ if (const TypedRegion* TR = dyn_cast<TypedRegion>(R)) {
+ QualType Ta = Ctx.getCanonicalType(TR->getLocationType(Ctx));
+
+ if (Ta == ToTy)
+ return CastResult(state, R);
+ }
+
+ if (const PointerType* PTy = dyn_cast<PointerType>(ToTy.getTypePtr())) {
+ // Check if we are casting to 'void*'.
+ // FIXME: Handle arbitrary upcasts.
+ QualType Pointee = PTy->getPointeeType();
+ if (Pointee->isVoidType()) {
+
+ do {
+ if (const TypedViewRegion *TR = dyn_cast<TypedViewRegion>(R)) {
+ // Casts to void* removes TypedViewRegion. This happens when:
+ //
+ // void foo(void*);
+ // ...
+ // void bar() {
+ // int x;
+ // foo(&x);
+ // }
+ //
+ R = TR->removeViews();
+ continue;
+ }
+ else if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ // Casts to void* also removes ElementRegions. This happens when:
+ //
+ // void foo(void*);
+ // ...
+ // void bar() {
+ // int x;
+ // foo((char*)&x);
+ // }
+ //
+ R = ER->getSuperRegion();
+ continue;
+ }
+ else
+ break;
+ }
+ while (0);
+
+ return CastResult(state, R);
+ }
+ else if (Pointee->isIntegerType()) {
+ // FIXME: At some point, it stands to reason that this 'dyn_cast' should
+ // become a 'cast' and that 'R' will always be a TypedRegion.
+ if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+ // Check if we are casting to a region with an integer type. We now
+ // the types aren't the same, so we construct an ElementRegion.
+ SVal Idx = ValMgr.makeZeroArrayIndex();
+
+ // If the super region is an element region, strip it away.
+ // FIXME: Is this the right thing to do in all cases?
+ const TypedRegion *Base = isa<ElementRegion>(TR) ?
+ cast<TypedRegion>(TR->getSuperRegion()) : TR;
+ ElementRegion* ER = MRMgr.getElementRegion(Pointee, Idx, Base);
+ return CastResult(state, ER);
+ }
+ }
+ }
+
+ // FIXME: Need to handle arbitrary downcasts.
+ // FIXME: Handle the case where a TypedViewRegion (layering a SymbolicRegion
+ // or an AllocaRegion is cast to another view, thus causing the memory
+ // to be re-used for a different purpose.
+
+ if (isa<SymbolicRegion>(R) || isa<AllocaRegion>(R)) {
+ const MemRegion* ViewR = MRMgr.getTypedViewRegion(CastToTy, R);
+ return CastResult(AddRegionView(state, ViewR, R), ViewR);
+ }
+
+ return CastResult(state, R);
+}
diff --git a/lib/Analysis/SymbolManager.cpp b/lib/Analysis/SymbolManager.cpp
new file mode 100644
index 000000000000..5c885cd6e15a
--- /dev/null
+++ b/lib/Analysis/SymbolManager.cpp
@@ -0,0 +1,203 @@
+//== SymbolManager.h - Management of Symbolic Values ------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SymbolManager, a class that manages symbolic values
+// created for use by GRExprEngine and related classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/SymbolManager.h"
+#include "clang/Analysis/PathSensitive/MemRegion.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+static void print(llvm::raw_ostream& os, const SymExpr *SE);
+
+static void print(llvm::raw_ostream& os, BinaryOperator::Opcode Op) {
+ switch (Op) {
+ default:
+ assert(false && "operator printing not implemented");
+ break;
+ case BinaryOperator::Mul: os << '*' ; break;
+ case BinaryOperator::Div: os << '/' ; break;
+ case BinaryOperator::Rem: os << '%' ; break;
+ case BinaryOperator::Add: os << '+' ; break;
+ case BinaryOperator::Sub: os << '-' ; break;
+ case BinaryOperator::Shl: os << "<<" ; break;
+ case BinaryOperator::Shr: os << ">>" ; break;
+ case BinaryOperator::LT: os << "<" ; break;
+ case BinaryOperator::GT: os << '>' ; break;
+ case BinaryOperator::LE: os << "<=" ; break;
+ case BinaryOperator::GE: os << ">=" ; break;
+ case BinaryOperator::EQ: os << "==" ; break;
+ case BinaryOperator::NE: os << "!=" ; break;
+ case BinaryOperator::And: os << '&' ; break;
+ case BinaryOperator::Xor: os << '^' ; break;
+ case BinaryOperator::Or: os << '|' ; break;
+ }
+}
+
+static void print(llvm::raw_ostream& os, const SymIntExpr *SE) {
+ os << '(';
+ print(os, SE->getLHS());
+ os << ") ";
+ print(os, SE->getOpcode());
+ os << ' ' << SE->getRHS().getZExtValue();
+ if (SE->getRHS().isUnsigned()) os << 'U';
+}
+
+static void print(llvm::raw_ostream& os, const SymSymExpr *SE) {
+ os << '(';
+ print(os, SE->getLHS());
+ os << ") ";
+ os << '(';
+ print(os, SE->getRHS());
+ os << ')';
+}
+
+static void print(llvm::raw_ostream& os, const SymExpr *SE) {
+ switch (SE->getKind()) {
+ case SymExpr::BEGIN_SYMBOLS:
+ case SymExpr::RegionValueKind:
+ case SymExpr::ConjuredKind:
+ case SymExpr::END_SYMBOLS:
+ os << '$' << cast<SymbolData>(SE)->getSymbolID();
+ return;
+ case SymExpr::SymIntKind:
+ print(os, cast<SymIntExpr>(SE));
+ return;
+ case SymExpr::SymSymKind:
+ print(os, cast<SymSymExpr>(SE));
+ return;
+ }
+}
+
+
+llvm::raw_ostream& llvm::operator<<(llvm::raw_ostream& os, const SymExpr *SE) {
+ print(os, SE);
+ return os;
+}
+
+std::ostream& std::operator<<(std::ostream& os, const SymExpr *SE) {
+ llvm::raw_os_ostream O(os);
+ print(O, SE);
+ return os;
+}
+
+const SymbolRegionValue*
+SymbolManager::getRegionValueSymbol(const MemRegion* R) {
+ llvm::FoldingSetNodeID profile;
+ SymbolRegionValue::Profile(profile, R);
+ void* InsertPos;
+ SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
+ if (!SD) {
+ SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>();
+ new (SD) SymbolRegionValue(SymbolCounter, R);
+ DataSet.InsertNode(SD, InsertPos);
+ ++SymbolCounter;
+ }
+
+ return cast<SymbolRegionValue>(SD);
+}
+
+const SymbolConjured*
+SymbolManager::getConjuredSymbol(const Stmt* E, QualType T, unsigned Count,
+ const void* SymbolTag) {
+
+ llvm::FoldingSetNodeID profile;
+ SymbolConjured::Profile(profile, E, T, Count, SymbolTag);
+ void* InsertPos;
+ SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
+ if (!SD) {
+ SD = (SymExpr*) BPAlloc.Allocate<SymbolConjured>();
+ new (SD) SymbolConjured(SymbolCounter, E, T, Count, SymbolTag);
+ DataSet.InsertNode(SD, InsertPos);
+ ++SymbolCounter;
+ }
+
+ return cast<SymbolConjured>(SD);
+}
+
+const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs,
+ BinaryOperator::Opcode op,
+ const llvm::APSInt& v,
+ QualType t) {
+ llvm::FoldingSetNodeID ID;
+ SymIntExpr::Profile(ID, lhs, op, v, t);
+ void *InsertPos;
+ SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (!data) {
+ data = (SymIntExpr*) BPAlloc.Allocate<SymIntExpr>();
+ new (data) SymIntExpr(lhs, op, v, t);
+ DataSet.InsertNode(data, InsertPos);
+ }
+
+ return cast<SymIntExpr>(data);
+}
+
+const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs,
+ BinaryOperator::Opcode op,
+ const SymExpr *rhs,
+ QualType t) {
+ llvm::FoldingSetNodeID ID;
+ SymSymExpr::Profile(ID, lhs, op, rhs, t);
+ void *InsertPos;
+ SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (!data) {
+ data = (SymSymExpr*) BPAlloc.Allocate<SymSymExpr>();
+ new (data) SymSymExpr(lhs, op, rhs, t);
+ DataSet.InsertNode(data, InsertPos);
+ }
+
+ return cast<SymSymExpr>(data);
+}
+
+QualType SymbolConjured::getType(ASTContext&) const {
+ return T;
+}
+
+QualType SymbolRegionValue::getType(ASTContext& C) const {
+ if (const TypedRegion* TR = dyn_cast<TypedRegion>(R))
+ return TR->getValueType(C);
+
+ return QualType();
+}
+
+SymbolManager::~SymbolManager() {}
+
+bool SymbolManager::canSymbolicate(QualType T) {
+ return Loc::IsLocType(T) || T->isIntegerType();
+}
+
+void SymbolReaper::markLive(SymbolRef sym) {
+ TheLiving = F.Add(TheLiving, sym);
+ TheDead = F.Remove(TheDead, sym);
+}
+
+bool SymbolReaper::maybeDead(SymbolRef sym) {
+ if (isLive(sym))
+ return false;
+
+ TheDead = F.Add(TheDead, sym);
+ return true;
+}
+
+bool SymbolReaper::isLive(SymbolRef sym) {
+ if (TheLiving.contains(sym))
+ return true;
+
+ // Interogate the symbol. It may derive from an input value to
+ // the analyzed function/method.
+ return isa<SymbolRegionValue>(sym);
+}
+
+SymbolVisitor::~SymbolVisitor() {}
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
new file mode 100644
index 000000000000..014ea8255e68
--- /dev/null
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -0,0 +1,312 @@
+//==- UninitializedValues.cpp - Find Uninitialized 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 implements Uninitialized Values analysis for source-level CFGs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
+#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Analysis/AnalysisDiagnostic.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
+#include "llvm/Support/Compiler.h"
+
+#include "llvm/ADT/SmallPtrSet.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Dataflow initialization logic.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class VISIBILITY_HIDDEN RegisterDecls
+ : public CFGRecStmtDeclVisitor<RegisterDecls> {
+
+ UninitializedValues::AnalysisDataTy& AD;
+public:
+ RegisterDecls(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {}
+
+ void VisitVarDecl(VarDecl* VD) { AD.Register(VD); }
+ CFG& getCFG() { return AD.getCFG(); }
+};
+
+} // end anonymous namespace
+
+void UninitializedValues::InitializeValues(const CFG& cfg) {
+ RegisterDecls R(getAnalysisData());
+ cfg.VisitBlockStmts(R);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer functions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN TransferFuncs
+ : public CFGStmtVisitor<TransferFuncs,bool> {
+
+ UninitializedValues::ValTy V;
+ UninitializedValues::AnalysisDataTy& AD;
+public:
+ TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {}
+
+ UninitializedValues::ValTy& getVal() { return V; }
+ CFG& getCFG() { return AD.getCFG(); }
+
+ void SetTopValue(UninitializedValues::ValTy& X) {
+ X.setDeclValues(AD);
+ X.resetBlkExprValues(AD);
+ }
+
+ bool VisitDeclRefExpr(DeclRefExpr* DR);
+ bool VisitBinaryOperator(BinaryOperator* B);
+ bool VisitUnaryOperator(UnaryOperator* U);
+ bool VisitStmt(Stmt* S);
+ bool VisitCallExpr(CallExpr* C);
+ bool VisitDeclStmt(DeclStmt* D);
+ bool VisitConditionalOperator(ConditionalOperator* C);
+ bool BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S);
+
+ bool Visit(Stmt *S);
+ bool BlockStmt_VisitExpr(Expr* E);
+
+ void VisitTerminator(CFGBlock* B) { }
+};
+
+static const bool Initialized = false;
+static const bool Uninitialized = true;
+
+bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
+
+ if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
+ if (VD->isBlockVarDecl()) {
+
+ if (AD.Observer)
+ AD.Observer->ObserveDeclRefExpr(V, AD, DR, VD);
+
+ // Pseudo-hack to prevent cascade of warnings. If an accessed variable
+ // is uninitialized, then we are already going to flag a warning for
+ // this variable, which a "source" of uninitialized values.
+ // We can otherwise do a full "taint" of uninitialized values. The
+ // client has both options by toggling AD.FullUninitTaint.
+
+ if (AD.FullUninitTaint)
+ return V(VD,AD);
+ }
+
+ return Initialized;
+}
+
+static VarDecl* FindBlockVarDecl(Expr* E) {
+
+ // Blast through casts and parentheses to find any DeclRefExprs that
+ // refer to a block VarDecl.
+
+ if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
+ if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
+ if (VD->isBlockVarDecl()) return VD;
+
+ return NULL;
+}
+
+bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
+
+ if (VarDecl* VD = FindBlockVarDecl(B->getLHS()))
+ if (B->isAssignmentOp()) {
+ if (B->getOpcode() == BinaryOperator::Assign)
+ return V(VD,AD) = Visit(B->getRHS());
+ else // Handle +=, -=, *=, etc. We do want '&', not '&&'.
+ return V(VD,AD) = Visit(B->getLHS()) & Visit(B->getRHS());
+ }
+
+ return VisitStmt(B);
+}
+
+bool TransferFuncs::VisitDeclStmt(DeclStmt* S) {
+ for (DeclStmt::decl_iterator I=S->decl_begin(), E=S->decl_end(); I!=E; ++I) {
+ VarDecl *VD = dyn_cast<VarDecl>(*I);
+ if (VD && VD->isBlockVarDecl()) {
+ if (Stmt* I = VD->getInit())
+ V(VD,AD) = AD.FullUninitTaint ? V(cast<Expr>(I),AD) : Initialized;
+ else {
+ // Special case for declarations of array types. For things like:
+ //
+ // char x[10];
+ //
+ // we should treat "x" as being initialized, because the variable
+ // "x" really refers to the memory block. Clearly x[1] is
+ // uninitialized, but expressions like "(char *) x" really do refer to
+ // an initialized value. This simple dataflow analysis does not reason
+ // about the contents of arrays, although it could be potentially
+ // extended to do so if the array were of constant size.
+ if (VD->getType()->isArrayType())
+ V(VD,AD) = Initialized;
+ else
+ V(VD,AD) = Uninitialized;
+ }
+ }
+ }
+ return Uninitialized; // Value is never consumed.
+}
+
+bool TransferFuncs::VisitCallExpr(CallExpr* C) {
+ VisitChildren(C);
+ return Initialized;
+}
+
+bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
+ switch (U->getOpcode()) {
+ case UnaryOperator::AddrOf: {
+ VarDecl* VD = FindBlockVarDecl(U->getSubExpr());
+ if (VD && VD->isBlockVarDecl())
+ return V(VD,AD) = Initialized;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return Visit(U->getSubExpr());
+}
+
+bool
+TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
+ // This represents a use of the 'collection'
+ bool x = Visit(S->getCollection());
+
+ if (x == Uninitialized)
+ return Uninitialized;
+
+ // This represents an initialization of the 'element' value.
+ Stmt* Element = S->getElement();
+ VarDecl* VD = 0;
+
+ if (DeclStmt* DS = dyn_cast<DeclStmt>(Element))
+ VD = cast<VarDecl>(DS->getSingleDecl());
+ else {
+ Expr* ElemExpr = cast<Expr>(Element)->IgnoreParens();
+
+ // Initialize the value of the reference variable.
+ if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(ElemExpr))
+ VD = cast<VarDecl>(DR->getDecl());
+ else
+ return Visit(ElemExpr);
+ }
+
+ V(VD,AD) = Initialized;
+ return Initialized;
+}
+
+
+bool TransferFuncs::VisitConditionalOperator(ConditionalOperator* C) {
+ Visit(C->getCond());
+
+ bool rhsResult = Visit(C->getRHS());
+ // Handle the GNU extension for missing LHS.
+ if (Expr *lhs = C->getLHS())
+ return Visit(lhs) & rhsResult; // Yes: we want &, not &&.
+ else
+ return rhsResult;
+}
+
+bool TransferFuncs::VisitStmt(Stmt* S) {
+ bool x = Initialized;
+
+ // We don't stop at the first subexpression that is Uninitialized because
+ // evaluating some subexpressions may result in propogating "Uninitialized"
+ // or "Initialized" to variables referenced in the other subexpressions.
+ for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
+ if (*I && Visit(*I) == Uninitialized) x = Uninitialized;
+
+ return x;
+}
+
+bool TransferFuncs::Visit(Stmt *S) {
+ if (AD.isTracked(static_cast<Expr*>(S))) return V(static_cast<Expr*>(S),AD);
+ else return static_cast<CFGStmtVisitor<TransferFuncs,bool>*>(this)->Visit(S);
+}
+
+bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) {
+ bool x = static_cast<CFGStmtVisitor<TransferFuncs,bool>*>(this)->Visit(E);
+ if (AD.isTracked(E)) V(E,AD) = x;
+ return x;
+}
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Merge operator.
+//
+// In our transfer functions we take the approach that any
+// combination of uninitialized values, e.g.
+// Uninitialized + ___ = Uninitialized.
+//
+// Merges take the same approach, preferring soundness. At a confluence point,
+// if any predecessor has a variable marked uninitialized, the value is
+// uninitialized at the confluence point.
+//===----------------------------------------------------------------------===//
+
+namespace {
+ typedef StmtDeclBitVector_Types::Union Merge;
+ typedef DataflowSolver<UninitializedValues,TransferFuncs,Merge> Solver;
+}
+
+//===----------------------------------------------------------------------===//
+// Uninitialized values checker. Scan an AST and flag variable uses
+//===----------------------------------------------------------------------===//
+
+UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {}
+
+namespace {
+class VISIBILITY_HIDDEN UninitializedValuesChecker
+ : public UninitializedValues::ObserverTy {
+
+ ASTContext &Ctx;
+ Diagnostic &Diags;
+ llvm::SmallPtrSet<VarDecl*,10> AlreadyWarned;
+
+public:
+ UninitializedValuesChecker(ASTContext &ctx, Diagnostic &diags)
+ : Ctx(ctx), Diags(diags) {}
+
+ virtual void ObserveDeclRefExpr(UninitializedValues::ValTy& V,
+ UninitializedValues::AnalysisDataTy& AD,
+ DeclRefExpr* DR, VarDecl* VD) {
+
+ assert ( AD.isTracked(VD) && "Unknown VarDecl.");
+
+ if (V(VD,AD) == Uninitialized)
+ if (AlreadyWarned.insert(VD))
+ Diags.Report(Ctx.getFullLoc(DR->getSourceRange().getBegin()),
+ diag::warn_uninit_val);
+ }
+};
+} // end anonymous namespace
+
+namespace clang {
+void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags,
+ bool FullUninitTaint) {
+
+ // Compute the uninitialized values information.
+ UninitializedValues U(cfg);
+ U.getAnalysisData().FullUninitTaint = FullUninitTaint;
+ Solver S(U);
+ S.runOnCFG(cfg);
+
+ // Scan for DeclRefExprs that use uninitialized values.
+ UninitializedValuesChecker Observer(Ctx,Diags);
+ U.getAnalysisData().Observer = &Observer;
+ S.runOnAllBlocks(cfg);
+}
+} // end namespace clang
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
new file mode 100644
index 000000000000..1cbf11c2bfbb
--- /dev/null
+++ b/lib/Basic/CMakeLists.txt
@@ -0,0 +1,24 @@
+set(LLVM_NO_RTTI 1)
+
+add_clang_library(clangBasic
+ ConvertUTF.c
+ Diagnostic.cpp
+ FileManager.cpp
+ IdentifierTable.cpp
+ SourceLocation.cpp
+ SourceManager.cpp
+ TargetInfo.cpp
+ Targets.cpp
+ TokenKinds.cpp
+ )
+
+add_dependencies(clangBasic
+ ClangDiagnosticAnalysis
+ ClangDiagnosticAST
+ ClangDiagnosticCommon
+ ClangDiagnosticDriver
+ ClangDiagnosticFrontend
+ ClangDiagnosticGroups
+ ClangDiagnosticLex
+ ClangDiagnosticParse
+ ClangDiagnosticSema)
diff --git a/lib/Basic/ConvertUTF.c b/lib/Basic/ConvertUTF.c
new file mode 100644
index 000000000000..e5dd3e6bf570
--- /dev/null
+++ b/lib/Basic/ConvertUTF.c
@@ -0,0 +1,547 @@
+/*===--- ConvertUTF.c - Universal Character Names conversions ---------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ *
+ *===------------------------------------------------------------------------=*/
+/*
+ * Copyright 2001-2004 Unicode, Inc.
+ *
+ * Disclaimer
+ *
+ * This source code is provided as is by Unicode, Inc. No claims are
+ * made as to fitness for any particular purpose. No warranties of any
+ * kind are expressed or implied. The recipient agrees to determine
+ * applicability of information provided. If this file has been
+ * purchased on magnetic or optical media from Unicode, Inc., the
+ * sole remedy for any claim will be exchange of defective media
+ * within 90 days of receipt.
+ *
+ * Limitations on Rights to Redistribute This Code
+ *
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+
+/* ---------------------------------------------------------------------
+
+ Conversions between UTF32, UTF-16, and UTF-8. Source code file.
+ Author: Mark E. Davis, 1994.
+ Rev History: Rick McGowan, fixes & updates May 2001.
+ Sept 2001: fixed const & error conditions per
+ mods suggested by S. Parent & A. Lillich.
+ June 2002: Tim Dodd added detection and handling of incomplete
+ source sequences, enhanced error detection, added casts
+ to eliminate compiler warnings.
+ July 2003: slight mods to back out aggressive FFFE detection.
+ Jan 2004: updated switches in from-UTF8 conversions.
+ Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
+
+ See the header file "ConvertUTF.h" for complete documentation.
+
+------------------------------------------------------------------------ */
+
+
+#include "clang/Basic/ConvertUTF.h"
+#ifdef CVTUTF_DEBUG
+#include <stdio.h>
+#endif
+
+static const int halfShift = 10; /* used for shifting by 10 bits */
+
+static const UTF32 halfBase = 0x0010000UL;
+static const UTF32 halfMask = 0x3FFUL;
+
+#define UNI_SUR_HIGH_START (UTF32)0xD800
+#define UNI_SUR_HIGH_END (UTF32)0xDBFF
+#define UNI_SUR_LOW_START (UTF32)0xDC00
+#define UNI_SUR_LOW_END (UTF32)0xDFFF
+#define false 0
+#define true 1
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Index into the table below with the first byte of a UTF-8 sequence to
+ * get the number of trailing bytes that are supposed to follow it.
+ * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
+ * left as-is for anyone who may want to do such conversion, which was
+ * allowed in earlier algorithms.
+ */
+static const char trailingBytesForUTF8[256] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
+};
+
+/*
+ * Magic values subtracted from a buffer value during UTF8 conversion.
+ * This table contains as many values as there might be trailing bytes
+ * in a UTF-8 sequence.
+ */
+static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
+ 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
+
+/*
+ * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
+ * into the first byte, depending on how many bytes follow. There are
+ * as many entries in this table as there are UTF-8 sequence types.
+ * (I.e., one byte sequence, two byte... etc.). Remember that sequencs
+ * for *legal* UTF-8 will be 4 or fewer bytes total.
+ */
+static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+/* --------------------------------------------------------------------- */
+
+/* The interface converts a whole buffer to avoid function-call overhead.
+ * Constants have been gathered. Loops & conditionals have been removed as
+ * much as possible for efficiency, in favor of drop-through switches.
+ * (See "Note A" at the bottom of the file for equivalent code.)
+ * If your compiler supports it, the "isLegalUTF8" call can be turned
+ * into an inline function.
+ */
+
+#ifdef CLANG_NEEDS_THESE_ONE_DAY
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF32toUTF16 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF32* source = *sourceStart;
+ UTF16* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ if (target >= targetEnd) {
+ result = targetExhausted; break;
+ }
+ ch = *source++;
+ if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+ /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = (UTF16)ch; /* normal case */
+ }
+ } else if (ch > UNI_MAX_LEGAL_UTF32) {
+ if (flags == strictConversion) {
+ result = sourceIllegal;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ /* target is a character in range 0xFFFF - 0x10FFFF. */
+ if (target + 1 >= targetEnd) {
+ --source; /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ ch -= halfBase;
+ *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+ *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF16toUTF32 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF16* source = *sourceStart;
+ UTF32* target = *targetStart;
+ UTF32 ch, ch2;
+ while (source < sourceEnd) {
+ const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
+ ch = *source++;
+ /* If we have a surrogate pair, convert to UTF32 first. */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+ /* If the 16 bits following the high surrogate are in the source buffer... */
+ if (source < sourceEnd) {
+ ch2 = *source;
+ /* If it's a low surrogate, convert to UTF32. */
+ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+ ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ + (ch2 - UNI_SUR_LOW_START) + halfBase;
+ ++source;
+ } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ } else { /* We don't have the 16 bits following the high surrogate. */
+ --source; /* return to the high surrogate */
+ result = sourceExhausted;
+ break;
+ }
+ } else if (flags == strictConversion) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ if (target >= targetEnd) {
+ source = oldSource; /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ *target++ = ch;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+#ifdef CVTUTF_DEBUG
+if (result == sourceIllegal) {
+ fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
+ fflush(stderr);
+}
+#endif
+ return result;
+}
+ConversionResult ConvertUTF16toUTF8 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF16* source = *sourceStart;
+ UTF8* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ unsigned short bytesToWrite = 0;
+ const UTF32 byteMask = 0xBF;
+ const UTF32 byteMark = 0x80;
+ const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
+ ch = *source++;
+ /* If we have a surrogate pair, convert to UTF32 first. */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+ /* If the 16 bits following the high surrogate are in the source buffer... */
+ if (source < sourceEnd) {
+ UTF32 ch2 = *source;
+ /* If it's a low surrogate, convert to UTF32. */
+ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+ ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ + (ch2 - UNI_SUR_LOW_START) + halfBase;
+ ++source;
+ } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ } else { /* We don't have the 16 bits following the high surrogate. */
+ --source; /* return to the high surrogate */
+ result = sourceExhausted;
+ break;
+ }
+ } else if (flags == strictConversion) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ /* Figure out how many bytes the result will require */
+ if (ch < (UTF32)0x80) { bytesToWrite = 1;
+ } else if (ch < (UTF32)0x800) { bytesToWrite = 2;
+ } else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
+ } else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
+ } else { bytesToWrite = 3;
+ ch = UNI_REPLACEMENT_CHAR;
+ }
+
+ target += bytesToWrite;
+ if (target > targetEnd) {
+ source = oldSource; /* Back up source pointer! */
+ target -= bytesToWrite; result = targetExhausted; break;
+ }
+ switch (bytesToWrite) { /* note: everything falls through. */
+ case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF32toUTF8 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF32* source = *sourceStart;
+ UTF8* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ unsigned short bytesToWrite = 0;
+ const UTF32 byteMask = 0xBF;
+ const UTF32 byteMark = 0x80;
+ ch = *source++;
+ if (flags == strictConversion ) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ /*
+ * Figure out how many bytes the result will require. Turn any
+ * illegally large UTF32 things (> Plane 17) into replacement chars.
+ */
+ if (ch < (UTF32)0x80) { bytesToWrite = 1;
+ } else if (ch < (UTF32)0x800) { bytesToWrite = 2;
+ } else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
+ } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
+ } else { bytesToWrite = 3;
+ ch = UNI_REPLACEMENT_CHAR;
+ result = sourceIllegal;
+ }
+
+ target += bytesToWrite;
+ if (target > targetEnd) {
+ --source; /* Back up source pointer! */
+ target -= bytesToWrite; result = targetExhausted; break;
+ }
+ switch (bytesToWrite) { /* note: everything falls through. */
+ case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF8toUTF32 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF8* source = *sourceStart;
+ UTF32* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch = 0;
+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (source + extraBytesToRead >= sourceEnd) {
+ result = sourceExhausted; break;
+ }
+ /* Do this check whether lenient or strict */
+ if (!isLegalUTF8(source, extraBytesToRead+1)) {
+ result = sourceIllegal;
+ break;
+ }
+ /*
+ * The cases all fall through. See "Note A" below.
+ */
+ switch (extraBytesToRead) {
+ case 5: ch += *source++; ch <<= 6;
+ case 4: ch += *source++; ch <<= 6;
+ case 3: ch += *source++; ch <<= 6;
+ case 2: ch += *source++; ch <<= 6;
+ case 1: ch += *source++; ch <<= 6;
+ case 0: ch += *source++;
+ }
+ ch -= offsetsFromUTF8[extraBytesToRead];
+
+ if (target >= targetEnd) {
+ source -= (extraBytesToRead+1); /* Back up the source pointer! */
+ result = targetExhausted; break;
+ }
+ if (ch <= UNI_MAX_LEGAL_UTF32) {
+ /*
+ * UTF-16 surrogate values are illegal in UTF-32, and anything
+ * over Plane 17 (> 0x10FFFF) is illegal.
+ */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ source -= (extraBytesToRead+1); /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = ch;
+ }
+ } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
+ result = sourceIllegal;
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Utility routine to tell whether a sequence of bytes is legal UTF-8.
+ * This must be called with the length pre-determined by the first byte.
+ * If not calling this from ConvertUTF8to*, then the length can be set by:
+ * length = trailingBytesForUTF8[*source]+1;
+ * and the sequence is illegal right away if there aren't that many bytes
+ * available.
+ * If presented with a length > 4, this returns false. The Unicode
+ * definition of UTF-8 goes up to 4-byte sequences.
+ */
+
+static Boolean isLegalUTF8(const UTF8 *source, int length) {
+ UTF8 a;
+ const UTF8 *srcptr = source+length;
+ switch (length) {
+ default: return false;
+ /* Everything else falls through when "true"... */
+ case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+ case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+ case 2: if ((a = (*--srcptr)) > 0xBF) return false;
+
+ switch (*source) {
+ /* no fall-through in this inner switch */
+ case 0xE0: if (a < 0xA0) return false; break;
+ case 0xED: if (a > 0x9F) return false; break;
+ case 0xF0: if (a < 0x90) return false; break;
+ case 0xF4: if (a > 0x8F) return false; break;
+ default: if (a < 0x80) return false;
+ }
+
+ case 1: if (*source >= 0x80 && *source < 0xC2) return false;
+ }
+ if (*source > 0xF4) return false;
+ return true;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Exported function to return whether a UTF-8 sequence is legal or not.
+ * This is not used here; it's just exported.
+ */
+Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
+ int length = trailingBytesForUTF8[*source]+1;
+ if (source+length > sourceEnd) {
+ return false;
+ }
+ return isLegalUTF8(source, length);
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF8toUTF16 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF8* source = *sourceStart;
+ UTF16* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch = 0;
+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (source + extraBytesToRead >= sourceEnd) {
+ result = sourceExhausted; break;
+ }
+ /* Do this check whether lenient or strict */
+ if (!isLegalUTF8(source, extraBytesToRead+1)) {
+ result = sourceIllegal;
+ break;
+ }
+ /*
+ * The cases all fall through. See "Note A" below.
+ */
+ switch (extraBytesToRead) {
+ case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+ case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+ case 3: ch += *source++; ch <<= 6;
+ case 2: ch += *source++; ch <<= 6;
+ case 1: ch += *source++; ch <<= 6;
+ case 0: ch += *source++;
+ }
+ ch -= offsetsFromUTF8[extraBytesToRead];
+
+ if (target >= targetEnd) {
+ source -= (extraBytesToRead+1); /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ source -= (extraBytesToRead+1); /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = (UTF16)ch; /* normal case */
+ }
+ } else if (ch > UNI_MAX_UTF16) {
+ if (flags == strictConversion) {
+ result = sourceIllegal;
+ source -= (extraBytesToRead+1); /* return to the start */
+ break; /* Bail out; shouldn't continue */
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ /* target is a character in range 0xFFFF - 0x10FFFF. */
+ if (target + 1 >= targetEnd) {
+ source -= (extraBytesToRead+1); /* Back up source pointer! */
+ result = targetExhausted; break;
+ }
+ ch -= halfBase;
+ *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+ *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* ---------------------------------------------------------------------
+
+ Note A.
+ The fall-through switches in UTF-8 reading code save a
+ temp variable, some decrements & conditionals. The switches
+ are equivalent to the following loop:
+ {
+ int tmpBytesToRead = extraBytesToRead+1;
+ do {
+ ch += *source++;
+ --tmpBytesToRead;
+ if (tmpBytesToRead) ch <<= 6;
+ } while (tmpBytesToRead > 0);
+ }
+ In UTF-8 writing code, the switches on "bytesToWrite" are
+ similarly unrolled loops.
+
+ --------------------------------------------------------------------- */
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
new file mode 100644
index 000000000000..3b3d61b08d0d
--- /dev/null
+++ b/lib/Basic/Diagnostic.cpp
@@ -0,0 +1,788 @@
+//===--- Diagnostic.cpp - C Language Family Diagnostic Handling -----------===//
+//
+// 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 Diagnostic-related interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Analysis/AnalysisDiagnostic.h"
+#include "clang/Driver/DriverDiagnostic.h"
+
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include <vector>
+#include <map>
+#include <cstring>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Builtin Diagnostic information
+//===----------------------------------------------------------------------===//
+
+// Diagnostic classes.
+enum {
+ CLASS_NOTE = 0x01,
+ CLASS_WARNING = 0x02,
+ CLASS_EXTENSION = 0x03,
+ CLASS_ERROR = 0x04
+};
+
+struct StaticDiagInfoRec {
+ unsigned short DiagID;
+ unsigned Mapping : 3;
+ unsigned Class : 3;
+ const char *Description;
+ const char *OptionGroup;
+
+ bool operator<(const StaticDiagInfoRec &RHS) const {
+ return DiagID < RHS.DiagID;
+ }
+ bool operator>(const StaticDiagInfoRec &RHS) const {
+ return DiagID > RHS.DiagID;
+ }
+};
+
+static const StaticDiagInfoRec StaticDiagInfo[] = {
+#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP) \
+ { diag::ENUM, DEFAULT_MAPPING, CLASS, DESC, GROUP },
+#include "clang/Basic/DiagnosticCommonKinds.inc"
+#include "clang/Basic/DiagnosticDriverKinds.inc"
+#include "clang/Basic/DiagnosticFrontendKinds.inc"
+#include "clang/Basic/DiagnosticLexKinds.inc"
+#include "clang/Basic/DiagnosticParseKinds.inc"
+#include "clang/Basic/DiagnosticASTKinds.inc"
+#include "clang/Basic/DiagnosticSemaKinds.inc"
+#include "clang/Basic/DiagnosticAnalysisKinds.inc"
+{ 0, 0, 0, 0, 0 }
+};
+#undef DIAG
+
+/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
+/// or null if the ID is invalid.
+static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
+ unsigned NumDiagEntries = sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1;
+
+ // If assertions are enabled, verify that the StaticDiagInfo array is sorted.
+#ifndef NDEBUG
+ static bool IsFirst = true;
+ if (IsFirst) {
+ for (unsigned i = 1; i != NumDiagEntries; ++i)
+ assert(StaticDiagInfo[i-1] < StaticDiagInfo[i] &&
+ "Improperly sorted diag info");
+ IsFirst = false;
+ }
+#endif
+
+ // Search the diagnostic table with a binary search.
+ StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0 };
+
+ const StaticDiagInfoRec *Found =
+ std::lower_bound(StaticDiagInfo, StaticDiagInfo + NumDiagEntries, Find);
+ if (Found == StaticDiagInfo + NumDiagEntries ||
+ Found->DiagID != DiagID)
+ return 0;
+
+ return Found;
+}
+
+static unsigned GetDefaultDiagMapping(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->Mapping;
+ return diag::MAP_FATAL;
+}
+
+/// 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.
+const char *Diagnostic::getWarningOptionForDiag(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->OptionGroup;
+ return 0;
+}
+
+/// getDiagClass - Return the class field of the diagnostic.
+///
+static unsigned getBuiltinDiagClass(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->Class;
+ return ~0U;
+}
+
+//===----------------------------------------------------------------------===//
+// Custom Diagnostic information
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+ namespace diag {
+ class CustomDiagInfo {
+ typedef std::pair<Diagnostic::Level, std::string> DiagDesc;
+ std::vector<DiagDesc> DiagInfo;
+ std::map<DiagDesc, unsigned> DiagIDs;
+ public:
+
+ /// getDescription - Return the description of the specified custom
+ /// diagnostic.
+ const char *getDescription(unsigned DiagID) const {
+ assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
+ "Invalid diagnosic ID");
+ return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second.c_str();
+ }
+
+ /// getLevel - Return the level of the specified custom diagnostic.
+ Diagnostic::Level getLevel(unsigned DiagID) const {
+ assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
+ "Invalid diagnosic ID");
+ return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
+ }
+
+ unsigned getOrCreateDiagID(Diagnostic::Level L, const char *Message,
+ Diagnostic &Diags) {
+ DiagDesc D(L, Message);
+ // Check to see if it already exists.
+ std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
+ if (I != DiagIDs.end() && I->first == D)
+ return I->second;
+
+ // If not, assign a new ID.
+ unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT;
+ DiagIDs.insert(std::make_pair(D, ID));
+ DiagInfo.push_back(D);
+ return ID;
+ }
+ };
+
+ } // end diag namespace
+} // end clang namespace
+
+
+//===----------------------------------------------------------------------===//
+// Common Diagnostic implementation
+//===----------------------------------------------------------------------===//
+
+static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT,
+ const char *Modifier, unsigned ML,
+ const char *Argument, unsigned ArgLen,
+ llvm::SmallVectorImpl<char> &Output,
+ void *Cookie) {
+ const char *Str = "<can't format argument>";
+ Output.append(Str, Str+strlen(Str));
+}
+
+
+Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
+ AllExtensionsSilenced = 0;
+ IgnoreAllWarnings = false;
+ WarningsAsErrors = false;
+ SuppressSystemWarnings = false;
+ ExtBehavior = Ext_Ignore;
+
+ ErrorOccurred = false;
+ FatalErrorOccurred = false;
+ NumDiagnostics = 0;
+ NumErrors = 0;
+ CustomDiagInfo = 0;
+ CurDiagID = ~0U;
+ LastDiagLevel = Ignored;
+
+ ArgToStringFn = DummyArgToStringFn;
+ ArgToStringCookie = 0;
+
+ // Set all mappings to 'unset'.
+ memset(DiagMappings, 0, sizeof(DiagMappings));
+}
+
+Diagnostic::~Diagnostic() {
+ delete CustomDiagInfo;
+}
+
+/// 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 Diagnostic::getCustomDiagID(Level L, const char *Message) {
+ if (CustomDiagInfo == 0)
+ CustomDiagInfo = new diag::CustomDiagInfo();
+ return CustomDiagInfo->getOrCreateDiagID(L, Message, *this);
+}
+
+
+/// 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.
+bool Diagnostic::isBuiltinWarningOrExtension(unsigned DiagID) {
+ return DiagID < diag::DIAG_UPPER_LIMIT &&
+ getBuiltinDiagClass(DiagID) != CLASS_ERROR;
+}
+
+/// \brief Determine whether the given built-in diagnostic ID is a
+/// Note.
+bool Diagnostic::isBuiltinNote(unsigned DiagID) {
+ return DiagID < diag::DIAG_UPPER_LIMIT &&
+ getBuiltinDiagClass(DiagID) == CLASS_NOTE;
+}
+
+/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
+/// ID is for an extension of some sort.
+///
+bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID) {
+ return DiagID < diag::DIAG_UPPER_LIMIT &&
+ getBuiltinDiagClass(DiagID) == CLASS_EXTENSION;
+}
+
+
+/// getDescription - Given a diagnostic ID, return a description of the
+/// issue.
+const char *Diagnostic::getDescription(unsigned DiagID) const {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->Description;
+ 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.
+Diagnostic::Level Diagnostic::getDiagnosticLevel(unsigned DiagID) 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);
+}
+
+/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
+/// object, classify the specified diagnostic ID into a Level, consumable by
+/// the DiagnosticClient.
+Diagnostic::Level
+Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const {
+ // Specific non-error diagnostics may be mapped to various levels from ignored
+ // to error. Errors can only be mapped to fatal.
+ Diagnostic::Level Result = Diagnostic::Fatal;
+
+ // Get the mapping information, if unset, compute it lazily.
+ unsigned MappingInfo = getDiagnosticMappingInfo((diag::kind)DiagID);
+ if (MappingInfo == 0) {
+ MappingInfo = GetDefaultDiagMapping(DiagID);
+ setDiagnosticMappingInternal(DiagID, MappingInfo, false);
+ }
+
+ switch (MappingInfo & 7) {
+ default: assert(0 && "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
+ ExtBehavior == Ext_Ignore || // Extensions ignored anyway
+ (MappingInfo & 8) != 0) // User explicitly mapped it.
+ return Diagnostic::Ignored;
+ Result = Diagnostic::Warning;
+ if (ExtBehavior == Ext_Error) Result = Diagnostic::Error;
+ break;
+ case diag::MAP_ERROR:
+ Result = Diagnostic::Error;
+ break;
+ case diag::MAP_FATAL:
+ Result = Diagnostic::Fatal;
+ break;
+ case diag::MAP_WARNING:
+ // If warnings are globally mapped to ignore or error, do it.
+ if (IgnoreAllWarnings)
+ return Diagnostic::Ignored;
+
+ Result = Diagnostic::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 (ExtBehavior == Ext_Error &&
+ (MappingInfo & 8) == 0 &&
+ isBuiltinExtensionDiag(DiagID))
+ Result = Diagnostic::Error;
+
+ if (WarningsAsErrors)
+ Result = Diagnostic::Error;
+ break;
+
+ 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 = Diagnostic::Warning;
+
+ // If warnings are globally mapped to ignore or error, do it.
+ if (IgnoreAllWarnings)
+ return Diagnostic::Ignored;
+
+ break;
+ }
+
+ // 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 (AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID))
+ return Diagnostic::Ignored;
+
+ return Result;
+}
+
+struct WarningOption {
+ const char *Name;
+ const short *Members;
+ const char *SubGroups;
+};
+
+#define GET_DIAG_ARRAYS
+#include "clang/Basic/DiagnosticGroups.inc"
+#undef GET_DIAG_ARRAYS
+
+// Second the table of options, sorted by name for fast binary lookup.
+static const WarningOption OptionTable[] = {
+#define GET_DIAG_TABLE
+#include "clang/Basic/DiagnosticGroups.inc"
+#undef GET_DIAG_TABLE
+};
+static const size_t OptionTableSize =
+sizeof(OptionTable) / sizeof(OptionTable[0]);
+
+static bool WarningOptionCompare(const WarningOption &LHS,
+ const WarningOption &RHS) {
+ return strcmp(LHS.Name, RHS.Name) < 0;
+}
+
+static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping,
+ Diagnostic &Diags) {
+ // Option exists, poke all the members of its diagnostic set.
+ if (const short *Member = Group->Members) {
+ for (; *Member != -1; ++Member)
+ Diags.setDiagnosticMapping(*Member, Mapping);
+ }
+
+ // Enable/disable all subgroups along with this one.
+ if (const char *SubGroups = Group->SubGroups) {
+ for (; *SubGroups != (char)-1; ++SubGroups)
+ MapGroupMembers(&OptionTable[(unsigned char)*SubGroups], Mapping, 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 Diagnostic::setDiagnosticGroupMapping(const char *Group,
+ diag::Mapping Map) {
+
+ WarningOption Key = { Group, 0, 0 };
+ const WarningOption *Found =
+ std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key,
+ WarningOptionCompare);
+ if (Found == OptionTable + OptionTableSize ||
+ strcmp(Found->Name, Group) != 0)
+ return true; // Option not found.
+
+ MapGroupMembers(Found, Map, *this);
+ return false;
+}
+
+
+/// ProcessDiag - This is the method used to report a diagnostic that is
+/// finally fully formed.
+void Diagnostic::ProcessDiag() {
+ DiagnosticInfo Info(this);
+
+ // Figure out the diagnostic level of this message.
+ Diagnostic::Level DiagLevel;
+ unsigned DiagID = Info.getID();
+
+ // ShouldEmitInSystemHeader - True if this diagnostic should be produced even
+ // in a system header.
+ bool ShouldEmitInSystemHeader;
+
+ if (DiagID >= diag::DIAG_UPPER_LIMIT) {
+ // Handle custom diagnostics, which cannot be mapped.
+ DiagLevel = CustomDiagInfo->getLevel(DiagID);
+
+ // Custom diagnostics always are emitted in system headers.
+ ShouldEmitInSystemHeader = true;
+ } else {
+ // Get the class of the diagnostic. If this is a NOTE, map it onto whatever
+ // the diagnostic level was for the previous diagnostic so that it is
+ // filtered the same as the previous diagnostic.
+ unsigned DiagClass = getBuiltinDiagClass(DiagID);
+ if (DiagClass == CLASS_NOTE) {
+ DiagLevel = Diagnostic::Note;
+ ShouldEmitInSystemHeader = false; // extra consideration is needed
+ } else {
+ // If this is not an error and we are in a system header, we ignore it.
+ // Check the original Diag ID here, because we also want to ignore
+ // extensions and warnings in -Werror and -pedantic-errors modes, which
+ // *map* warnings/extensions to errors.
+ ShouldEmitInSystemHeader = DiagClass == CLASS_ERROR;
+
+ DiagLevel = getDiagnosticLevel(DiagID, DiagClass);
+ }
+ }
+
+ if (DiagLevel != Diagnostic::Note) {
+ // Record that a fatal error occurred only when we see a second
+ // non-note diagnostic. This allows notes to be attached to the
+ // fatal error, but suppresses any diagnostics that follow those
+ // notes.
+ if (LastDiagLevel == Diagnostic::Fatal)
+ FatalErrorOccurred = true;
+
+ LastDiagLevel = DiagLevel;
+ }
+
+ // If a fatal error has already been emitted, silence all subsequent
+ // diagnostics.
+ if (FatalErrorOccurred)
+ return;
+
+ // If the client doesn't care about this message, don't issue it. If this is
+ // a note and the last real diagnostic was ignored, ignore it too.
+ if (DiagLevel == Diagnostic::Ignored ||
+ (DiagLevel == Diagnostic::Note && LastDiagLevel == Diagnostic::Ignored))
+ return;
+
+ // If this diagnostic is in a system header and is not a clang error, suppress
+ // it.
+ if (SuppressSystemWarnings && !ShouldEmitInSystemHeader &&
+ Info.getLocation().isValid() &&
+ Info.getLocation().getSpellingLoc().isInSystemHeader() &&
+ (DiagLevel != Diagnostic::Note || LastDiagLevel == Diagnostic::Ignored)) {
+ LastDiagLevel = Diagnostic::Ignored;
+ return;
+ }
+
+ if (DiagLevel >= Diagnostic::Error) {
+ ErrorOccurred = true;
+ ++NumErrors;
+ }
+
+ // Finally, report it.
+ Client->HandleDiagnostic(DiagLevel, Info);
+ if (Client->IncludeInDiagnosticCounts()) ++NumDiagnostics;
+
+ CurDiagID = ~0U;
+}
+
+
+DiagnosticClient::~DiagnosticClient() {}
+
+
+/// ModifierIs - Return true if the specified modifier matches specified string.
+template <std::size_t StrLen>
+static bool ModifierIs(const char *Modifier, unsigned ModifierLen,
+ const char (&Str)[StrLen]) {
+ return StrLen-1 == ModifierLen && !memcmp(Modifier, Str, StrLen-1);
+}
+
+/// HandleSelectModifier - Handle the integer 'select' modifier. This is used
+/// like this: %select{foo|bar|baz}2. This means that the integer argument
+/// "%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(unsigned ValNo,
+ const char *Argument, unsigned ArgumentLen,
+ llvm::SmallVectorImpl<char> &OutStr) {
+ const char *ArgumentEnd = Argument+ArgumentLen;
+
+ // Skip over 'ValNo' |'s.
+ while (ValNo) {
+ const char *NextVal = std::find(Argument, ArgumentEnd, '|');
+ assert(NextVal != ArgumentEnd && "Value for integer select modifier was"
+ " larger than the number of options in the diagnostic string!");
+ Argument = NextVal+1; // Skip this string.
+ --ValNo;
+ }
+
+ // Get the end of the value. This is either the } or the |.
+ const char *EndPtr = std::find(Argument, ArgumentEnd, '|');
+ // Add the value to the output string.
+ OutStr.append(Argument, EndPtr);
+}
+
+/// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the
+/// 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) {
+ if (ValNo != 1)
+ OutStr.push_back('s');
+}
+
+
+/// PluralNumber - Parse an unsigned integer and advance Start.
+static unsigned PluralNumber(const char *&Start, const char *End) {
+ // Programming 101: Parse a decimal number :-)
+ unsigned Val = 0;
+ while (Start != End && *Start >= '0' && *Start <= '9') {
+ Val *= 10;
+ Val += *Start - '0';
+ ++Start;
+ }
+ return Val;
+}
+
+/// TestPluralRange - Test if Val is in the parsed range. Modifies Start.
+static bool TestPluralRange(unsigned Val, const char *&Start, const char *End) {
+ if (*Start != '[') {
+ unsigned Ref = PluralNumber(Start, End);
+ return Ref == Val;
+ }
+
+ ++Start;
+ unsigned Low = PluralNumber(Start, End);
+ assert(*Start == ',' && "Bad plural expression syntax: expected ,");
+ ++Start;
+ unsigned High = PluralNumber(Start, End);
+ assert(*Start == ']' && "Bad plural expression syntax: expected )");
+ ++Start;
+ return Low <= Val && Val <= High;
+}
+
+/// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
+static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) {
+ // Empty condition?
+ if (*Start == ':')
+ return true;
+
+ while (1) {
+ char C = *Start;
+ if (C == '%') {
+ // Modulo expression
+ ++Start;
+ unsigned Arg = PluralNumber(Start, End);
+ assert(*Start == '=' && "Bad plural expression syntax: expected =");
+ ++Start;
+ unsigned ValMod = ValNo % Arg;
+ if (TestPluralRange(ValMod, Start, End))
+ return true;
+ } else {
+ assert((C == '[' || (C >= '0' && C <= '9')) &&
+ "Bad plural expression syntax: unexpected character");
+ // Range expression
+ if (TestPluralRange(ValNo, Start, End))
+ return true;
+ }
+
+ // Scan for next or-expr part.
+ Start = std::find(Start, End, ',');
+ if(Start == End)
+ break;
+ ++Start;
+ }
+ return false;
+}
+
+/// HandlePluralModifier - Handle the integer 'plural' modifier. This is used
+/// for complex plural forms, or in languages where all plurals are complex.
+/// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are
+/// conditions that are tested in order, the form corresponding to the first
+/// that applies being emitted. The empty condition is always true, making the
+/// last form a default case.
+/// Conditions are simple boolean expressions, where n is the number argument.
+/// Here are the rules.
+/// condition := expression | empty
+/// empty := -> always true
+/// expression := numeric [',' expression] -> logical or
+/// numeric := range -> true if n in range
+/// | '%' number '=' range -> true if n % number in range
+/// range := number
+/// | '[' number ',' number ']' -> ranges are inclusive both ends
+///
+/// Here are some examples from the GNU gettext manual written in this form:
+/// English:
+/// {1:form0|:form1}
+/// Latvian:
+/// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0}
+/// Gaeilge:
+/// {1:form0|2:form1|:form2}
+/// Romanian:
+/// {1:form0|0,%100=[1,19]:form1|:form2}
+/// Lithuanian:
+/// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1}
+/// Russian (requires repeated form):
+/// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2}
+/// Slovak
+/// {1:form0|[2,4]:form1|:form2}
+/// Polish (requires repeated form):
+/// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2}
+static void HandlePluralModifier(unsigned ValNo,
+ const char *Argument, unsigned ArgumentLen,
+ llvm::SmallVectorImpl<char> &OutStr) {
+ const char *ArgumentEnd = Argument + ArgumentLen;
+ while (1) {
+ assert(Argument < ArgumentEnd && "Plural expression didn't match.");
+ const char *ExprEnd = Argument;
+ while (*ExprEnd != ':') {
+ assert(ExprEnd != ArgumentEnd && "Plural missing expression end");
+ ++ExprEnd;
+ }
+ if (EvalPluralExpr(ValNo, Argument, ExprEnd)) {
+ Argument = ExprEnd + 1;
+ ExprEnd = std::find(Argument, ArgumentEnd, '|');
+ OutStr.append(Argument, ExprEnd);
+ return;
+ }
+ Argument = std::find(Argument, ArgumentEnd - 1, '|') + 1;
+ }
+}
+
+
+/// 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 {
+ const char *DiagStr = getDiags()->getDescription(getID());
+ const char *DiagEnd = DiagStr+strlen(DiagStr);
+
+ while (DiagStr != DiagEnd) {
+ if (DiagStr[0] != '%') {
+ // Append non-%0 substrings to Str if we have one.
+ const char *StrEnd = std::find(DiagStr, DiagEnd, '%');
+ OutStr.append(DiagStr, StrEnd);
+ DiagStr = StrEnd;
+ continue;
+ } else if (DiagStr[1] == '%') {
+ OutStr.push_back('%'); // %% -> %.
+ DiagStr += 2;
+ continue;
+ }
+
+ // Skip the %.
+ ++DiagStr;
+
+ // This must be a placeholder for a diagnostic argument. The format for a
+ // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0".
+ // The digit is a number from 0-9 indicating which argument this comes from.
+ // The modifier is a string of digits from the set [-a-z]+, arguments is a
+ // brace enclosed string.
+ const char *Modifier = 0, *Argument = 0;
+ unsigned ModifierLen = 0, ArgumentLen = 0;
+
+ // Check to see if we have a modifier. If so eat it.
+ if (!isdigit(DiagStr[0])) {
+ Modifier = DiagStr;
+ while (DiagStr[0] == '-' ||
+ (DiagStr[0] >= 'a' && DiagStr[0] <= 'z'))
+ ++DiagStr;
+ ModifierLen = DiagStr-Modifier;
+
+ // If we have an argument, get it next.
+ if (DiagStr[0] == '{') {
+ ++DiagStr; // Skip {.
+ Argument = DiagStr;
+
+ for (; DiagStr[0] != '}'; ++DiagStr)
+ assert(DiagStr[0] && "Mismatched {}'s in diagnostic string!");
+ ArgumentLen = DiagStr-Argument;
+ ++DiagStr; // Skip }.
+ }
+ }
+
+ assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic");
+ unsigned ArgNo = *DiagStr++ - '0';
+
+ switch (getArgKind(ArgNo)) {
+ // ---- STRINGS ----
+ case Diagnostic::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: {
+ const char *S = getArgCStr(ArgNo);
+ assert(ModifierLen == 0 && "No modifiers for strings yet");
+
+ // Don't crash if get passed a null pointer by accident.
+ if (!S)
+ S = "(null)";
+
+ OutStr.append(S, S + strlen(S));
+ break;
+ }
+ // ---- INTEGERS ----
+ case Diagnostic::ak_sint: {
+ int Val = getArgSInt(ArgNo);
+
+ if (ModifierIs(Modifier, ModifierLen, "select")) {
+ HandleSelectModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
+ } else if (ModifierIs(Modifier, ModifierLen, "s")) {
+ HandleIntegerSModifier(Val, OutStr);
+ } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
+ HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
+ } else {
+ assert(ModifierLen == 0 && "Unknown integer modifier");
+ // FIXME: Optimize
+ std::string S = llvm::itostr(Val);
+ OutStr.append(S.begin(), S.end());
+ }
+ break;
+ }
+ case Diagnostic::ak_uint: {
+ unsigned Val = getArgUInt(ArgNo);
+
+ if (ModifierIs(Modifier, ModifierLen, "select")) {
+ HandleSelectModifier(Val, Argument, ArgumentLen, OutStr);
+ } else if (ModifierIs(Modifier, ModifierLen, "s")) {
+ HandleIntegerSModifier(Val, OutStr);
+ } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
+ HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
+ } else {
+ assert(ModifierLen == 0 && "Unknown integer modifier");
+
+ // FIXME: Optimize
+ std::string S = llvm::utostr_32(Val);
+ OutStr.append(S.begin(), S.end());
+ }
+ break;
+ }
+ // ---- NAMES and TYPES ----
+ case Diagnostic::ak_identifierinfo: {
+ const IdentifierInfo *II = getArgIdentifier(ArgNo);
+ assert(ModifierLen == 0 && "No modifiers for strings yet");
+
+ // Don't crash if get passed a null pointer by accident.
+ if (!II) {
+ const char *S = "(null)";
+ OutStr.append(S, S + strlen(S));
+ continue;
+ }
+
+ OutStr.push_back('\'');
+ OutStr.append(II->getName(), II->getName() + II->getLength());
+ OutStr.push_back('\'');
+ break;
+ }
+ case Diagnostic::ak_qualtype:
+ case Diagnostic::ak_declarationname:
+ case Diagnostic::ak_nameddecl:
+ getDiags()->ConvertArgToString(getArgKind(ArgNo), getRawArg(ArgNo),
+ Modifier, ModifierLen,
+ Argument, ArgumentLen, OutStr);
+ break;
+ }
+ }
+}
+
+/// 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; }
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
new file mode 100644
index 000000000000..cc25d3305158
--- /dev/null
+++ b/lib/Basic/FileManager.cpp
@@ -0,0 +1,302 @@
+///===--- FileManager.cpp - File System Probing and Caching ----------------===//
+//
+// 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 FileManager interface.
+//
+//===----------------------------------------------------------------------===//
+//
+// TODO: This should index all interesting directories with dirent calls.
+// getdirentries ?
+// opendir/readdir_r/closedir ?
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/FileManager.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/System/Path.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Config/config.h"
+using namespace clang;
+
+// FIXME: Enhance libsystem to support inode and other fields.
+#include <sys/stat.h>
+
+#if defined(_MSC_VER)
+#define S_ISDIR(s) (_S_IFDIR & s)
+#endif
+
+/// NON_EXISTENT_DIR - A special value distinct from null that is used to
+/// represent a dir name that doesn't exist on the disk.
+#define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
+
+//===----------------------------------------------------------------------===//
+// Windows.
+//===----------------------------------------------------------------------===//
+
+#ifdef LLVM_ON_WIN32
+
+#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/' || (x) == '\\')
+
+namespace {
+ static std::string GetFullPath(const char *relPath)
+ {
+ char *absPathStrPtr = _fullpath(NULL, relPath, 0);
+ assert(absPathStrPtr && "_fullpath() returned NULL!");
+
+ std::string absPath(absPathStrPtr);
+
+ free(absPathStrPtr);
+ return absPath;
+ }
+}
+
+class FileManager::UniqueDirContainer {
+ /// UniqueDirs - Cache from full path to existing directories/files.
+ ///
+ llvm::StringMap<DirectoryEntry> UniqueDirs;
+
+public:
+ DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
+ std::string FullPath(GetFullPath(Name));
+ return UniqueDirs.GetOrCreateValue(
+ FullPath.c_str(),
+ FullPath.c_str() + FullPath.size()
+ ).getValue();
+ }
+
+ size_t size() { return UniqueDirs.size(); }
+};
+
+class FileManager::UniqueFileContainer {
+ /// UniqueFiles - Cache from full path to existing directories/files.
+ ///
+ llvm::StringMap<FileEntry, llvm::BumpPtrAllocator> UniqueFiles;
+
+public:
+ FileEntry &getFile(const char *Name, struct stat &StatBuf) {
+ std::string FullPath(GetFullPath(Name));
+ return UniqueFiles.GetOrCreateValue(
+ FullPath.c_str(),
+ FullPath.c_str() + FullPath.size()
+ ).getValue();
+ }
+
+ size_t size() { return UniqueFiles.size(); }
+};
+
+//===----------------------------------------------------------------------===//
+// Unix-like Systems.
+//===----------------------------------------------------------------------===//
+
+#else
+
+#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/')
+
+class FileManager::UniqueDirContainer {
+ /// UniqueDirs - Cache from ID's to existing directories/files.
+ ///
+ std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs;
+
+public:
+ DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
+ return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
+ }
+
+ size_t size() { return UniqueDirs.size(); }
+};
+
+class FileManager::UniqueFileContainer {
+ /// UniqueFiles - Cache from ID's to existing directories/files.
+ ///
+ std::set<FileEntry> UniqueFiles;
+
+public:
+ FileEntry &getFile(const char *Name, struct stat &StatBuf) {
+ return
+ const_cast<FileEntry&>(
+ *UniqueFiles.insert(FileEntry(StatBuf.st_dev,
+ StatBuf.st_ino,
+ StatBuf.st_mode)).first);
+ }
+
+ size_t size() { return UniqueFiles.size(); }
+};
+
+#endif
+
+//===----------------------------------------------------------------------===//
+// Common logic.
+//===----------------------------------------------------------------------===//
+
+FileManager::FileManager()
+ : UniqueDirs(*new UniqueDirContainer),
+ UniqueFiles(*new UniqueFileContainer),
+ DirEntries(64), FileEntries(64), NextFileUID(0) {
+ NumDirLookups = NumFileLookups = 0;
+ NumDirCacheMisses = NumFileCacheMisses = 0;
+}
+
+FileManager::~FileManager() {
+ delete &UniqueDirs;
+ delete &UniqueFiles;
+}
+
+/// getDirectory - Lookup, cache, and verify the specified directory. This
+/// returns null if the directory doesn't exist.
+///
+const DirectoryEntry *FileManager::getDirectory(const char *NameStart,
+ const char *NameEnd) {
+ ++NumDirLookups;
+ llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
+ DirEntries.GetOrCreateValue(NameStart, NameEnd);
+
+ // See if there is already an entry in the map.
+ if (NamedDirEnt.getValue())
+ return NamedDirEnt.getValue() == NON_EXISTENT_DIR
+ ? 0 : NamedDirEnt.getValue();
+
+ ++NumDirCacheMisses;
+
+ // By default, initialize it to invalid.
+ NamedDirEnt.setValue(NON_EXISTENT_DIR);
+
+ // Get the null-terminated directory name as stored as the key of the
+ // DirEntries map.
+ const char *InterndDirName = NamedDirEnt.getKeyData();
+
+ // Check to see if the directory exists.
+ struct stat StatBuf;
+ if (stat_cached(InterndDirName, &StatBuf) || // Error stat'ing.
+ !S_ISDIR(StatBuf.st_mode)) // Not a directory?
+ return 0;
+
+ // It exists. See if we have already opened a directory with the same inode.
+ // This occurs when one dir is symlinked to another, for example.
+ DirectoryEntry &UDE = UniqueDirs.getDirectory(InterndDirName, StatBuf);
+
+ NamedDirEnt.setValue(&UDE);
+ if (UDE.getName()) // Already have an entry with this inode, return it.
+ return &UDE;
+
+ // Otherwise, we don't have this directory yet, add it. We use the string
+ // key from the DirEntries map as the string.
+ UDE.Name = InterndDirName;
+ return &UDE;
+}
+
+/// NON_EXISTENT_FILE - A special value distinct from null that is used to
+/// represent a filename that doesn't exist on the disk.
+#define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
+
+/// getFile - Lookup, cache, and verify the specified file. This returns null
+/// if the file doesn't exist.
+///
+const FileEntry *FileManager::getFile(const char *NameStart,
+ const char *NameEnd) {
+ ++NumFileLookups;
+
+ // See if there is already an entry in the map.
+ llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
+ FileEntries.GetOrCreateValue(NameStart, NameEnd);
+
+ // See if there is already an entry in the map.
+ if (NamedFileEnt.getValue())
+ return NamedFileEnt.getValue() == NON_EXISTENT_FILE
+ ? 0 : NamedFileEnt.getValue();
+
+ ++NumFileCacheMisses;
+
+ // By default, initialize it to invalid.
+ NamedFileEnt.setValue(NON_EXISTENT_FILE);
+
+ // Figure out what directory it is in. If the string contains a / in it,
+ // strip off everything after it.
+ // FIXME: this logic should be in sys::Path.
+ const char *SlashPos = NameEnd-1;
+ while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0]))
+ --SlashPos;
+
+ const DirectoryEntry *DirInfo;
+ if (SlashPos < NameStart) {
+ // Use the current directory if file has no path component.
+ const char *Name = ".";
+ DirInfo = getDirectory(Name, Name+1);
+ } else if (SlashPos == NameEnd-1)
+ return 0; // If filename ends with a /, it's a directory.
+ else
+ DirInfo = getDirectory(NameStart, SlashPos);
+
+ if (DirInfo == 0) // Directory doesn't exist, file can't exist.
+ return 0;
+
+ // Get the null-terminated file name as stored as the key of the
+ // FileEntries map.
+ const char *InterndFileName = NamedFileEnt.getKeyData();
+
+ // FIXME: Use the directory info to prune this, before doing the stat syscall.
+ // FIXME: This will reduce the # syscalls.
+
+ // Nope, there isn't. Check to see if the file exists.
+ struct stat StatBuf;
+ //llvm::cerr << "STATING: " << Filename;
+ if (stat_cached(InterndFileName, &StatBuf) || // Error stat'ing.
+ S_ISDIR(StatBuf.st_mode)) { // A directory?
+ // If this file doesn't exist, we leave a null in FileEntries for this path.
+ //llvm::cerr << ": Not existing\n";
+ return 0;
+ }
+ //llvm::cerr << ": exists\n";
+
+ // It exists. See if we have already opened a file with the same inode.
+ // This occurs when one dir is symlinked to another, for example.
+ FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf);
+
+ NamedFileEnt.setValue(&UFE);
+ if (UFE.getName()) // Already have an entry with this inode, return it.
+ return &UFE;
+
+ // Otherwise, we don't have this directory yet, add it.
+ // FIXME: Change the name to be a char* that points back to the 'FileEntries'
+ // key.
+ UFE.Name = InterndFileName;
+ UFE.Size = StatBuf.st_size;
+ UFE.ModTime = StatBuf.st_mtime;
+ UFE.Dir = DirInfo;
+ UFE.UID = NextFileUID++;
+ return &UFE;
+}
+
+void FileManager::PrintStats() const {
+ llvm::cerr << "\n*** File Manager Stats:\n";
+ llvm::cerr << UniqueFiles.size() << " files found, "
+ << UniqueDirs.size() << " dirs found.\n";
+ llvm::cerr << NumDirLookups << " dir lookups, "
+ << NumDirCacheMisses << " dir cache misses.\n";
+ llvm::cerr << NumFileLookups << " file lookups, "
+ << NumFileCacheMisses << " file cache misses.\n";
+
+ //llvm::cerr << PagesMapped << BytesOfPagesMapped << FSLookups;
+}
+
+int MemorizeStatCalls::stat(const char *path, struct stat *buf) {
+ int result = ::stat(path, buf);
+
+ if (result != 0) {
+ // Cache failed 'stat' results.
+ struct stat empty;
+ StatCalls[path] = StatResult(result, empty);
+ }
+ else if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) {
+ // Cache file 'stat' results and directories with absolutely
+ // paths.
+ StatCalls[path] = StatResult(result, *buf);
+ }
+
+ return result;
+}
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
new file mode 100644
index 000000000000..cf78da986926
--- /dev/null
+++ b/lib/Basic/IdentifierTable.cpp
@@ -0,0 +1,388 @@
+//===--- IdentifierTable.cpp - Hash table for identifier lookup -----------===//
+//
+// 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 IdentifierInfo, IdentifierVisitor, and
+// IdentifierTable interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/DenseMap.h"
+#include <cstdio>
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// IdentifierInfo Implementation
+//===----------------------------------------------------------------------===//
+
+IdentifierInfo::IdentifierInfo() {
+ TokenID = tok::identifier;
+ ObjCOrBuiltinID = 0;
+ HasMacro = false;
+ IsExtension = false;
+ IsPoisoned = false;
+ IsCPPOperatorKeyword = false;
+ NeedsHandleIdentifier = false;
+ FETokenInfo = 0;
+ Entry = 0;
+}
+
+//===----------------------------------------------------------------------===//
+// IdentifierTable Implementation
+//===----------------------------------------------------------------------===//
+
+IdentifierInfoLookup::~IdentifierInfoLookup() {}
+
+ExternalIdentifierLookup::~ExternalIdentifierLookup() {}
+
+IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
+ IdentifierInfoLookup* externalLookup)
+ : HashTable(8192), // Start with space for 8K identifiers.
+ ExternalLookup(externalLookup) {
+
+ // Populate the identifier table with info about keywords for the current
+ // language.
+ AddKeywords(LangOpts);
+}
+
+//===----------------------------------------------------------------------===//
+// Language Keyword Implementation
+//===----------------------------------------------------------------------===//
+
+// Constants for TokenKinds.def
+namespace {
+ enum {
+ KEYALL = 1,
+ KEYC99 = 2,
+ KEYCXX = 4,
+ KEYCXX0X = 8,
+ KEYGNU = 16,
+ KEYMS = 32
+ };
+}
+
+/// AddKeyword - This method is used to associate a token ID with specific
+/// 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 0 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 2 if disabled in the
+/// specified language.
+static void AddKeyword(const char *Keyword, unsigned KWLen,
+ tok::TokenKind TokenCode, unsigned Flags,
+ const LangOptions &LangOpts, IdentifierTable &Table) {
+ unsigned AddResult = 0;
+ if (Flags & KEYALL) AddResult = 2;
+ else if (LangOpts.CPlusPlus && (Flags & KEYCXX)) AddResult = 2;
+ else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2;
+ else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2;
+ else if (LangOpts.GNUMode && (Flags & KEYGNU)) AddResult = 1;
+ else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1;
+
+ // Don't add this keyword if disabled in this language.
+ if (AddResult == 0) return;
+
+ IdentifierInfo &Info = Table.get(Keyword, Keyword+KWLen);
+ Info.setTokenID(TokenCode);
+ Info.setIsExtensionToken(AddResult == 1);
+}
+
+/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative
+/// representations.
+static void AddCXXOperatorKeyword(const char *Keyword, unsigned KWLen,
+ tok::TokenKind TokenCode,
+ IdentifierTable &Table) {
+ IdentifierInfo &Info = Table.get(Keyword, Keyword + KWLen);
+ Info.setTokenID(TokenCode);
+ Info.setIsCPlusPlusOperatorKeyword();
+}
+
+/// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or
+/// "property".
+static void AddObjCKeyword(tok::ObjCKeywordKind ObjCID,
+ const char *Name, unsigned NameLen,
+ IdentifierTable &Table) {
+ Table.get(Name, Name+NameLen).setObjCKeywordID(ObjCID);
+}
+
+/// AddKeywords - Add all keywords to the symbol table.
+///
+void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
+ // Add keywords and tokens for the current language.
+#define KEYWORD(NAME, FLAGS) \
+ AddKeyword(#NAME, strlen(#NAME), tok::kw_ ## NAME, \
+ FLAGS, LangOpts, *this);
+#define ALIAS(NAME, TOK, FLAGS) \
+ AddKeyword(NAME, strlen(NAME), tok::kw_ ## TOK, \
+ FLAGS, LangOpts, *this);
+#define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \
+ if (LangOpts.CXXOperatorNames) \
+ AddCXXOperatorKeyword(#NAME, strlen(#NAME), tok::ALIAS, *this);
+#define OBJC1_AT_KEYWORD(NAME) \
+ if (LangOpts.ObjC1) \
+ AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this);
+#define OBJC2_AT_KEYWORD(NAME) \
+ if (LangOpts.ObjC2) \
+ AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this);
+#include "clang/Basic/TokenKinds.def"
+}
+
+tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
+ // We use a perfect hash function here involving the length of the keyword,
+ // the first and third character. For preprocessor ID's there are no
+ // collisions (if there were, the switch below would complain about duplicate
+ // case values). Note that this depends on 'if' being null terminated.
+
+#define HASH(LEN, FIRST, THIRD) \
+ (LEN << 5) + (((FIRST-'a') + (THIRD-'a')) & 31)
+#define CASE(LEN, FIRST, THIRD, NAME) \
+ case HASH(LEN, FIRST, THIRD): \
+ return memcmp(Name, #NAME, LEN) ? tok::pp_not_keyword : tok::pp_ ## NAME
+
+ unsigned Len = getLength();
+ if (Len < 2) return tok::pp_not_keyword;
+ const char *Name = getName();
+ switch (HASH(Len, Name[0], Name[2])) {
+ default: return tok::pp_not_keyword;
+ CASE( 2, 'i', '\0', if);
+ CASE( 4, 'e', 'i', elif);
+ CASE( 4, 'e', 's', else);
+ CASE( 4, 'l', 'n', line);
+ CASE( 4, 's', 'c', sccs);
+ CASE( 5, 'e', 'd', endif);
+ CASE( 5, 'e', 'r', error);
+ CASE( 5, 'i', 'e', ident);
+ CASE( 5, 'i', 'd', ifdef);
+ CASE( 5, 'u', 'd', undef);
+
+ CASE( 6, 'a', 's', assert);
+ CASE( 6, 'd', 'f', define);
+ CASE( 6, 'i', 'n', ifndef);
+ CASE( 6, 'i', 'p', import);
+ CASE( 6, 'p', 'a', pragma);
+
+ CASE( 7, 'd', 'f', defined);
+ CASE( 7, 'i', 'c', include);
+ CASE( 7, 'w', 'r', warning);
+
+ CASE( 8, 'u', 'a', unassert);
+ CASE(12, 'i', 'c', include_next);
+
+ CASE(16, '_', 'i', __include_macros);
+#undef CASE
+#undef HASH
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Stats Implementation
+//===----------------------------------------------------------------------===//
+
+/// PrintStats - Print statistics about how well the identifier table is doing
+/// at hashing identifiers.
+void IdentifierTable::PrintStats() const {
+ unsigned NumBuckets = HashTable.getNumBuckets();
+ unsigned NumIdentifiers = HashTable.getNumItems();
+ unsigned NumEmptyBuckets = NumBuckets-NumIdentifiers;
+ unsigned AverageIdentifierSize = 0;
+ unsigned MaxIdentifierLength = 0;
+
+ // TODO: Figure out maximum times an identifier had to probe for -stats.
+ for (llvm::StringMap<IdentifierInfo*, llvm::BumpPtrAllocator>::const_iterator
+ I = HashTable.begin(), E = HashTable.end(); I != E; ++I) {
+ unsigned IdLen = I->getKeyLength();
+ AverageIdentifierSize += IdLen;
+ if (MaxIdentifierLength < IdLen)
+ MaxIdentifierLength = IdLen;
+ }
+
+ fprintf(stderr, "\n*** Identifier Table Stats:\n");
+ fprintf(stderr, "# Identifiers: %d\n", NumIdentifiers);
+ fprintf(stderr, "# Empty Buckets: %d\n", NumEmptyBuckets);
+ fprintf(stderr, "Hash density (#identifiers per bucket): %f\n",
+ NumIdentifiers/(double)NumBuckets);
+ fprintf(stderr, "Ave identifier length: %f\n",
+ (AverageIdentifierSize/(double)NumIdentifiers));
+ fprintf(stderr, "Max identifier length: %d\n", MaxIdentifierLength);
+
+ // Compute statistics about the memory allocated for identifiers.
+ HashTable.getAllocator().PrintStats();
+}
+
+//===----------------------------------------------------------------------===//
+// SelectorTable Implementation
+//===----------------------------------------------------------------------===//
+
+unsigned llvm::DenseMapInfo<clang::Selector>::getHashValue(clang::Selector S) {
+ return DenseMapInfo<void*>::getHashValue(S.getAsOpaquePtr());
+}
+
+namespace clang {
+/// MultiKeywordSelector - One of these variable length records is kept for each
+/// selector containing more than one keyword. We use a folding set
+/// to unique aggregate names (keyword selectors in ObjC parlance). Access to
+/// this class is provided strictly through Selector.
+class MultiKeywordSelector
+ : public DeclarationNameExtra, public llvm::FoldingSetNode {
+ MultiKeywordSelector(unsigned nKeys) {
+ ExtraKindOrNumArgs = NUM_EXTRA_KINDS + nKeys;
+ }
+public:
+ // Constructor for keyword selectors.
+ MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) {
+ assert((nKeys > 1) && "not a multi-keyword selector");
+ ExtraKindOrNumArgs = NUM_EXTRA_KINDS + nKeys;
+
+ // Fill in the trailing keyword array.
+ IdentifierInfo **KeyInfo = reinterpret_cast<IdentifierInfo **>(this+1);
+ for (unsigned i = 0; i != nKeys; ++i)
+ KeyInfo[i] = IIV[i];
+ }
+
+ // getName - Derive the full selector name and return it.
+ std::string getName() const;
+
+ unsigned getNumArgs() const { return ExtraKindOrNumArgs - NUM_EXTRA_KINDS; }
+
+ typedef IdentifierInfo *const *keyword_iterator;
+ keyword_iterator keyword_begin() const {
+ return reinterpret_cast<keyword_iterator>(this+1);
+ }
+ keyword_iterator keyword_end() const {
+ return keyword_begin()+getNumArgs();
+ }
+ IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const {
+ assert(i < getNumArgs() && "getIdentifierInfoForSlot(): illegal index");
+ return keyword_begin()[i];
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ keyword_iterator ArgTys, unsigned NumArgs) {
+ ID.AddInteger(NumArgs);
+ for (unsigned i = 0; i != NumArgs; ++i)
+ ID.AddPointer(ArgTys[i]);
+ }
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, keyword_begin(), getNumArgs());
+ }
+};
+} // end namespace clang.
+
+unsigned Selector::getNumArgs() const {
+ unsigned IIF = getIdentifierInfoFlag();
+ if (IIF == ZeroArg)
+ return 0;
+ if (IIF == OneArg)
+ return 1;
+ // We point to a MultiKeywordSelector (pointer doesn't contain any flags).
+ MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
+ return SI->getNumArgs();
+}
+
+IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const {
+ if (getIdentifierInfoFlag()) {
+ assert(argIndex == 0 && "illegal keyword index");
+ return getAsIdentifierInfo();
+ }
+ // We point to a MultiKeywordSelector (pointer doesn't contain any flags).
+ MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
+ return SI->getIdentifierInfoForSlot(argIndex);
+}
+
+std::string MultiKeywordSelector::getName() const {
+ std::string Result;
+ unsigned Length = 0;
+ for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) {
+ if (*I)
+ Length += (*I)->getLength();
+ ++Length; // :
+ }
+
+ Result.reserve(Length);
+
+ for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) {
+ if (*I)
+ Result.insert(Result.end(), (*I)->getName(),
+ (*I)->getName()+(*I)->getLength());
+ Result.push_back(':');
+ }
+
+ return Result;
+}
+
+std::string Selector::getAsString() const {
+ if (InfoPtr == 0)
+ return "<null selector>";
+
+ if (InfoPtr & ArgFlags) {
+ IdentifierInfo *II = getAsIdentifierInfo();
+
+ // If the number of arguments is 0 then II is guaranteed to not be null.
+ if (getNumArgs() == 0)
+ return II->getName();
+
+ std::string Res = II ? II->getName() : "";
+ Res += ":";
+ return Res;
+ }
+
+ // We have a multiple keyword selector (no embedded flags).
+ return reinterpret_cast<MultiKeywordSelector *>(InfoPtr)->getName();
+}
+
+
+namespace {
+ struct SelectorTableImpl {
+ llvm::FoldingSet<MultiKeywordSelector> Table;
+ llvm::BumpPtrAllocator Allocator;
+ };
+} // end anonymous namespace.
+
+static SelectorTableImpl &getSelectorTableImpl(void *P) {
+ return *static_cast<SelectorTableImpl*>(P);
+}
+
+
+Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) {
+ if (nKeys < 2)
+ return Selector(IIV[0], nKeys);
+
+ SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl);
+
+ // Unique selector, to guarantee there is one per name.
+ llvm::FoldingSetNodeID ID;
+ MultiKeywordSelector::Profile(ID, IIV, nKeys);
+
+ void *InsertPos = 0;
+ if (MultiKeywordSelector *SI =
+ SelTabImpl.Table.FindNodeOrInsertPos(ID, InsertPos))
+ return Selector(SI);
+
+ // MultiKeywordSelector objects are not allocated with new because they have a
+ // variable size array (for parameter types) at the end of them.
+ unsigned Size = sizeof(MultiKeywordSelector) + nKeys*sizeof(IdentifierInfo *);
+ MultiKeywordSelector *SI =
+ (MultiKeywordSelector*)SelTabImpl.Allocator.Allocate(Size,
+ llvm::alignof<MultiKeywordSelector>());
+ new (SI) MultiKeywordSelector(nKeys, IIV);
+ SelTabImpl.Table.InsertNode(SI, InsertPos);
+ return Selector(SI);
+}
+
+SelectorTable::SelectorTable() {
+ Impl = new SelectorTableImpl();
+}
+
+SelectorTable::~SelectorTable() {
+ delete &getSelectorTableImpl(Impl);
+}
+
diff --git a/lib/Basic/Makefile b/lib/Basic/Makefile
new file mode 100644
index 000000000000..3fd6c2c15384
--- /dev/null
+++ b/lib/Basic/Makefile
@@ -0,0 +1,22 @@
+##===- clang/lib/Basic/Makefile ----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements the Basic library for the C-Language front-end.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+LIBRARYNAME := clangBasic
+BUILD_ARCHIVE = 1
+CXXFLAGS = -fno-rtti
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp
new file mode 100644
index 000000000000..f21ec8b1e9d7
--- /dev/null
+++ b/lib/Basic/SourceLocation.cpp
@@ -0,0 +1,125 @@
+//==--- SourceLocation.cpp - Compact identifier for Source Files -*- 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 accessor methods for the FullSourceLoc class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdio>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// PrettyStackTraceLoc
+//===----------------------------------------------------------------------===//
+
+void PrettyStackTraceLoc::print(llvm::raw_ostream &OS) const {
+ if (Loc.isValid()) {
+ Loc.print(OS, SM);
+ OS << ": ";
+ }
+ OS << Message << '\n';
+}
+
+//===----------------------------------------------------------------------===//
+// SourceLocation
+//===----------------------------------------------------------------------===//
+
+void SourceLocation::print(llvm::raw_ostream &OS, const SourceManager &SM)const{
+ if (!isValid()) {
+ OS << "<invalid loc>";
+ return;
+ }
+
+ if (isFileID()) {
+ PresumedLoc PLoc = SM.getPresumedLoc(*this);
+ // The instantiation and spelling pos is identical for file locs.
+ OS << PLoc.getFilename() << ':' << PLoc.getLine()
+ << ':' << PLoc.getColumn();
+ return;
+ }
+
+ SM.getInstantiationLoc(*this).print(OS, SM);
+
+ OS << " <Spelling=";
+ SM.getSpellingLoc(*this).print(OS, SM);
+ OS << '>';
+}
+
+void SourceLocation::dump(const SourceManager &SM) const {
+ print(llvm::errs(), SM);
+}
+
+//===----------------------------------------------------------------------===//
+// FullSourceLoc
+//===----------------------------------------------------------------------===//
+
+FileID FullSourceLoc::getFileID() const {
+ assert(isValid());
+ return SrcMgr->getFileID(*this);
+}
+
+
+FullSourceLoc FullSourceLoc::getInstantiationLoc() const {
+ assert(isValid());
+ return FullSourceLoc(SrcMgr->getInstantiationLoc(*this), *SrcMgr);
+}
+
+FullSourceLoc FullSourceLoc::getSpellingLoc() const {
+ assert(isValid());
+ return FullSourceLoc(SrcMgr->getSpellingLoc(*this), *SrcMgr);
+}
+
+unsigned FullSourceLoc::getInstantiationLineNumber() const {
+ assert(isValid());
+ return SrcMgr->getInstantiationLineNumber(*this);
+}
+
+unsigned FullSourceLoc::getInstantiationColumnNumber() const {
+ assert(isValid());
+ return SrcMgr->getInstantiationColumnNumber(*this);
+}
+
+unsigned FullSourceLoc::getSpellingLineNumber() const {
+ assert(isValid());
+ return SrcMgr->getSpellingLineNumber(*this);
+}
+
+unsigned FullSourceLoc::getSpellingColumnNumber() const {
+ assert(isValid());
+ return SrcMgr->getSpellingColumnNumber(*this);
+}
+
+bool FullSourceLoc::isInSystemHeader() const {
+ assert(isValid());
+ return SrcMgr->isInSystemHeader(*this);
+}
+
+const char *FullSourceLoc::getCharacterData() const {
+ assert(isValid());
+ return SrcMgr->getCharacterData(*this);
+}
+
+const llvm::MemoryBuffer* FullSourceLoc::getBuffer() const {
+ assert(isValid());
+ return SrcMgr->getBuffer(SrcMgr->getFileID(*this));
+}
+
+std::pair<const char*, const char*> FullSourceLoc::getBufferData() const {
+ const llvm::MemoryBuffer *Buf = getBuffer();
+ return std::make_pair(Buf->getBufferStart(), Buf->getBufferEnd());
+}
+
+std::pair<FileID, unsigned> FullSourceLoc::getDecomposedLoc() const {
+ return SrcMgr->getDecomposedLoc(*this);
+}
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
new file mode 100644
index 000000000000..7d2d0ae17253
--- /dev/null
+++ b/lib/Basic/SourceManager.cpp
@@ -0,0 +1,943 @@
+//===--- SourceManager.cpp - Track and cache source files -----------------===//
+//
+// 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 SourceManager interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/SourceManagerInternals.h"
+#include "clang/Basic/FileManager.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/System/Path.h"
+#include "llvm/Support/Streams.h"
+#include <algorithm>
+#include <iostream>
+using namespace clang;
+using namespace SrcMgr;
+using llvm::MemoryBuffer;
+
+//===----------------------------------------------------------------------===//
+// SourceManager Helper Classes
+//===----------------------------------------------------------------------===//
+
+ContentCache::~ContentCache() {
+ delete Buffer;
+}
+
+/// getSizeBytesMapped - Returns the number of bytes actually mapped for
+/// this ContentCache. This can be 0 if the MemBuffer was not actually
+/// instantiated.
+unsigned ContentCache::getSizeBytesMapped() const {
+ return Buffer ? Buffer->getBufferSize() : 0;
+}
+
+/// getSize - Returns the size of the content encapsulated by this ContentCache.
+/// This can be the size of the source file or the size of an arbitrary
+/// scratch buffer. If the ContentCache encapsulates a source file, that
+/// file is not lazily brought in from disk to satisfy this query.
+unsigned ContentCache::getSize() const {
+ return Entry ? Entry->getSize() : Buffer->getBufferSize();
+}
+
+const llvm::MemoryBuffer *ContentCache::getBuffer() const {
+ // Lazily create the Buffer for ContentCaches that wrap files.
+ if (!Buffer && Entry) {
+ // FIXME: Should we support a way to not have to do this check over
+ // and over if we cannot open the file?
+ Buffer = MemoryBuffer::getFile(Entry->getName(), 0, Entry->getSize());
+ }
+ return Buffer;
+}
+
+unsigned LineTableInfo::getLineTableFilenameID(const char *Ptr, unsigned Len) {
+ // Look up the filename in the string table, returning the pre-existing value
+ // if it exists.
+ llvm::StringMapEntry<unsigned> &Entry =
+ FilenameIDs.GetOrCreateValue(Ptr, Ptr+Len, ~0U);
+ if (Entry.getValue() != ~0U)
+ return Entry.getValue();
+
+ // Otherwise, assign this the next available ID.
+ Entry.setValue(FilenamesByID.size());
+ FilenamesByID.push_back(&Entry);
+ return FilenamesByID.size()-1;
+}
+
+/// 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,
+ unsigned LineNo, int FilenameID) {
+ std::vector<LineEntry> &Entries = LineEntries[FID];
+
+ assert((Entries.empty() || Entries.back().FileOffset < Offset) &&
+ "Adding line entries out of order!");
+
+ SrcMgr::CharacteristicKind Kind = SrcMgr::C_User;
+ unsigned IncludeOffset = 0;
+
+ if (!Entries.empty()) {
+ // If this is a '#line 4' after '#line 42 "foo.h"', make sure to remember
+ // that we are still in "foo.h".
+ if (FilenameID == -1)
+ FilenameID = Entries.back().FilenameID;
+
+ // If we are after a line marker that switched us to system header mode, or
+ // that set #include information, preserve it.
+ Kind = Entries.back().FileKind;
+ IncludeOffset = Entries.back().IncludeOffset;
+ }
+
+ Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, Kind,
+ IncludeOffset));
+}
+
+/// AddLineNote This is the same as the previous version of AddLineNote, but is
+/// used for GNU line markers. If EntryExit is 0, then this doesn't change the
+/// 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,
+ unsigned LineNo, int FilenameID,
+ unsigned EntryExit,
+ SrcMgr::CharacteristicKind FileKind) {
+ assert(FilenameID != -1 && "Unspecified filename should use other accessor");
+
+ std::vector<LineEntry> &Entries = LineEntries[FID];
+
+ assert((Entries.empty() || Entries.back().FileOffset < Offset) &&
+ "Adding line entries out of order!");
+
+ unsigned IncludeOffset = 0;
+ if (EntryExit == 0) { // No #include stack change.
+ IncludeOffset = Entries.empty() ? 0 : Entries.back().IncludeOffset;
+ } else if (EntryExit == 1) {
+ IncludeOffset = Offset-1;
+ } else if (EntryExit == 2) {
+ assert(!Entries.empty() && Entries.back().IncludeOffset &&
+ "PPDirectives should have caught case when popping empty include stack");
+
+ // Get the include loc of the last entries' include loc as our include loc.
+ IncludeOffset = 0;
+ if (const LineEntry *PrevEntry =
+ FindNearestLineEntry(FID, Entries.back().IncludeOffset))
+ IncludeOffset = PrevEntry->IncludeOffset;
+ }
+
+ Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, FileKind,
+ IncludeOffset));
+}
+
+
+/// 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,
+ unsigned Offset) {
+ const std::vector<LineEntry> &Entries = LineEntries[FID];
+ assert(!Entries.empty() && "No #line entries for this FID after all!");
+
+ // It is very common for the query to be after the last #line, check this
+ // first.
+ if (Entries.back().FileOffset <= Offset)
+ return &Entries.back();
+
+ // Do a binary search to find the maximal element that is still before Offset.
+ std::vector<LineEntry>::const_iterator I =
+ std::upper_bound(Entries.begin(), Entries.end(), Offset);
+ if (I == Entries.begin()) return 0;
+ return &*--I;
+}
+
+/// \brief Add a new line entry that has already been encoded into
+/// the internal representation of the line table.
+void LineTableInfo::AddEntry(unsigned FID,
+ const std::vector<LineEntry> &Entries) {
+ LineEntries[FID] = Entries;
+}
+
+/// getLineTableFilenameID - Return the uniqued ID for the specified filename.
+///
+unsigned SourceManager::getLineTableFilenameID(const char *Ptr, unsigned Len) {
+ if (LineTable == 0)
+ LineTable = new LineTableInfo();
+ return LineTable->getLineTableFilenameID(Ptr, Len);
+}
+
+
+/// 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
+/// unspecified.
+void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
+ int FilenameID) {
+ std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
+
+ const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile();
+
+ // Remember that this file has #line directives now if it doesn't already.
+ const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
+
+ if (LineTable == 0)
+ LineTable = new LineTableInfo();
+ LineTable->AddLineNote(LocInfo.first.ID, LocInfo.second, LineNo, FilenameID);
+}
+
+/// AddLineNote - Add a GNU line marker to the line table.
+void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
+ int FilenameID, bool IsFileEntry,
+ bool IsFileExit, bool IsSystemHeader,
+ bool IsExternCHeader) {
+ // If there is no filename and no flags, this is treated just like a #line,
+ // which does not change the flags of the previous line marker.
+ if (FilenameID == -1) {
+ assert(!IsFileEntry && !IsFileExit && !IsSystemHeader && !IsExternCHeader &&
+ "Can't set flags without setting the filename!");
+ return AddLineNote(Loc, LineNo, FilenameID);
+ }
+
+ std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
+ const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile();
+
+ // Remember that this file has #line directives now if it doesn't already.
+ const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
+
+ if (LineTable == 0)
+ LineTable = new LineTableInfo();
+
+ SrcMgr::CharacteristicKind FileKind;
+ if (IsExternCHeader)
+ FileKind = SrcMgr::C_ExternCSystem;
+ else if (IsSystemHeader)
+ FileKind = SrcMgr::C_System;
+ else
+ FileKind = SrcMgr::C_User;
+
+ unsigned EntryExit = 0;
+ if (IsFileEntry)
+ EntryExit = 1;
+ else if (IsFileExit)
+ EntryExit = 2;
+
+ LineTable->AddLineNote(LocInfo.first.ID, LocInfo.second, LineNo, FilenameID,
+ EntryExit, FileKind);
+}
+
+LineTableInfo &SourceManager::getLineTable() {
+ if (LineTable == 0)
+ LineTable = new LineTableInfo();
+ return *LineTable;
+}
+
+//===----------------------------------------------------------------------===//
+// Private 'Create' methods.
+//===----------------------------------------------------------------------===//
+
+SourceManager::~SourceManager() {
+ delete LineTable;
+
+ // Delete FileEntry objects corresponding to content caches. Since the actual
+ // content cache objects are bump pointer allocated, we just have to run the
+ // dtors, but we call the deallocate method for completeness.
+ for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i) {
+ MemBufferInfos[i]->~ContentCache();
+ ContentCacheAlloc.Deallocate(MemBufferInfos[i]);
+ }
+ for (llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>::iterator
+ I = FileInfos.begin(), E = FileInfos.end(); I != E; ++I) {
+ I->second->~ContentCache();
+ ContentCacheAlloc.Deallocate(I->second);
+ }
+}
+
+void SourceManager::clearIDTables() {
+ MainFileID = FileID();
+ SLocEntryTable.clear();
+ LastLineNoFileIDQuery = FileID();
+ LastLineNoContentCache = 0;
+ LastFileIDLookup = FileID();
+
+ if (LineTable)
+ LineTable->clear();
+
+ // Use up FileID #0 as an invalid instantiation.
+ NextOffset = 0;
+ createInstantiationLoc(SourceLocation(),SourceLocation(),SourceLocation(), 1);
+}
+
+/// getOrCreateContentCache - Create or return a cached ContentCache for the
+/// specified file.
+const ContentCache *
+SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) {
+ assert(FileEnt && "Didn't specify a file entry to use?");
+
+ // Do we already have information about this file?
+ ContentCache *&Entry = FileInfos[FileEnt];
+ if (Entry) return Entry;
+
+ // Nope, create a new Cache entry. Make sure it is at least 8-byte aligned
+ // so that FileInfo can use the low 3 bits of the pointer for its own
+ // nefarious purposes.
+ unsigned EntryAlign = llvm::AlignOf<ContentCache>::Alignment;
+ EntryAlign = std::max(8U, EntryAlign);
+ Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign);
+ new (Entry) ContentCache(FileEnt);
+ return Entry;
+}
+
+
+/// createMemBufferContentCache - Create a new ContentCache for the specified
+/// memory buffer. This does no caching.
+const ContentCache*
+SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) {
+ // Add a new ContentCache to the MemBufferInfos list and return it. Make sure
+ // it is at least 8-byte aligned so that FileInfo can use the low 3 bits of
+ // the pointer for its own nefarious purposes.
+ unsigned EntryAlign = llvm::AlignOf<ContentCache>::Alignment;
+ EntryAlign = std::max(8U, EntryAlign);
+ ContentCache *Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign);
+ new (Entry) ContentCache();
+ MemBufferInfos.push_back(Entry);
+ Entry->setBuffer(Buffer);
+ return Entry;
+}
+
+void SourceManager::PreallocateSLocEntries(ExternalSLocEntrySource *Source,
+ unsigned NumSLocEntries,
+ unsigned NextOffset) {
+ ExternalSLocEntries = Source;
+ this->NextOffset = NextOffset;
+ SLocEntryLoaded.resize(NumSLocEntries + 1);
+ SLocEntryLoaded[0] = true;
+ SLocEntryTable.resize(SLocEntryTable.size() + NumSLocEntries);
+}
+
+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;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Methods to create new FileID's and instantiations.
+//===----------------------------------------------------------------------===//
+
+/// createFileID - Create a new fileID for the specified ContentCache and
+/// include position. This works regardless of whether the ContentCache
+/// corresponds to a file or some other input source.
+FileID SourceManager::createFileID(const ContentCache *File,
+ SourceLocation IncludePos,
+ SrcMgr::CharacteristicKind FileCharacter,
+ unsigned PreallocatedID,
+ unsigned Offset) {
+ SLocEntry NewEntry = SLocEntry::get(NextOffset,
+ FileInfo::get(IncludePos, File,
+ FileCharacter));
+ 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;
+ return LastFileIDLookup = FileID::get(PreallocatedID);
+ }
+
+ SLocEntryTable.push_back(SLocEntry::get(NextOffset,
+ FileInfo::get(IncludePos, File,
+ FileCharacter)));
+ unsigned FileSize = File->getSize();
+ assert(NextOffset+FileSize+1 > NextOffset && "Ran out of source locations!");
+ NextOffset += FileSize+1;
+
+ // Set LastFileIDLookup to the newly created file. The next getFileID call is
+ // almost guaranteed to be from that file.
+ return LastFileIDLookup = FileID::get(SLocEntryTable.size()-1);
+}
+
+/// createInstantiationLoc - Return a new SourceLocation that encodes the fact
+/// that a token from SpellingLoc should actually be referenced from
+/// InstantiationLoc.
+SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc,
+ SourceLocation ILocStart,
+ SourceLocation ILocEnd,
+ unsigned TokLength,
+ unsigned PreallocatedID,
+ unsigned Offset) {
+ InstantiationInfo II = InstantiationInfo::get(ILocStart,ILocEnd, SpellingLoc);
+ 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);
+ }
+ 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));
+}
+
+/// getBufferData - Return a pointer to the start and end of the source buffer
+/// data for the specified FileID.
+std::pair<const char*, const char*>
+SourceManager::getBufferData(FileID FID) const {
+ const llvm::MemoryBuffer *Buf = getBuffer(FID);
+ return std::make_pair(Buf->getBufferStart(), Buf->getBufferEnd());
+}
+
+
+//===----------------------------------------------------------------------===//
+// 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.
+///
+FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
+ assert(SLocOffset && "Invalid FileID");
+
+ // 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
+ // 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
+ // then we fall back to a less cache efficient, but more scalable, binary
+ // search to find the location.
+
+ // See if this is near the file point - worst case we start scanning from the
+ // most newly created FileID.
+ std::vector<SrcMgr::SLocEntry>::const_iterator I;
+
+ if (SLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset) {
+ // Neither loc prunes our search.
+ I = SLocEntryTable.end();
+ } else {
+ // Perhaps it is near the file point.
+ I = SLocEntryTable.begin()+LastFileIDLookup.ID;
+ }
+
+ // Find the FileID that contains this. "I" is an iterator that points to a
+ // FileID whose offset is known to be larger than SLocOffset.
+ unsigned NumProbes = 0;
+ while (1) {
+ --I;
+ if (ExternalSLocEntries)
+ getSLocEntry(FileID::get(I - SLocEntryTable.begin()));
+ 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())
+ LastFileIDLookup = Res;
+ NumLinearScans += NumProbes+1;
+ return Res;
+ }
+ if (++NumProbes == 8)
+ break;
+ }
+
+ // 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();
+ // 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.
+ unsigned LessIndex = 0;
+ NumProbes = 0;
+ while (1) {
+ unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex;
+ unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex)).getOffset();
+
+ ++NumProbes;
+
+ // If the offset of the midpoint is too large, chop the high side of the
+ // range to the midpoint.
+ if (MidOffset > SLocOffset) {
+ GreaterIndex = MiddleIndex;
+ continue;
+ }
+
+ // If the middle index contains the value, succeed and return.
+ 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
+ // across FileID lookups.
+ if (!I->isInstantiation())
+ LastFileIDLookup = Res;
+ NumBinaryProbes += NumProbes;
+ return Res;
+ }
+
+ // Otherwise, move the low-side up to the middle index.
+ LessIndex = MiddleIndex;
+ }
+}
+
+SourceLocation SourceManager::
+getInstantiationLocSlowCase(SourceLocation Loc) const {
+ do {
+ std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc);
+ Loc = getSLocEntry(LocInfo.first).getInstantiation()
+ .getInstantiationLocStart();
+ Loc = Loc.getFileLocWithOffset(LocInfo.second);
+ } while (!Loc.isFileID());
+
+ return Loc;
+}
+
+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);
+ } while (!Loc.isFileID());
+ return Loc;
+}
+
+
+std::pair<FileID, unsigned>
+SourceManager::getDecomposedInstantiationLocSlowCase(const SrcMgr::SLocEntry *E,
+ unsigned Offset) const {
+ // If this is an instantiation record, walk through all the instantiation
+ // points.
+ FileID FID;
+ SourceLocation Loc;
+ do {
+ Loc = E->getInstantiation().getInstantiationLocStart();
+
+ FID = getFileID(Loc);
+ E = &getSLocEntry(FID);
+ Offset += Loc.getOffset()-E->getOffset();
+ } while (!Loc.isFileID());
+
+ return std::make_pair(FID, Offset);
+}
+
+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.
+ FileID FID;
+ SourceLocation Loc;
+ do {
+ Loc = E->getInstantiation().getSpellingLoc();
+
+ FID = getFileID(Loc);
+ E = &getSLocEntry(FID);
+ Offset += Loc.getOffset()-E->getOffset();
+ } while (!Loc.isFileID());
+
+ return std::make_pair(FID, Offset);
+}
+
+/// getImmediateSpellingLoc - Given a SourceLocation object, return the
+/// spelling location referenced by the ID. This is the first level down
+/// towards the place where the characters that make up the lexed token can be
+/// found. This should not generally be used by clients.
+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);
+}
+
+
+/// getImmediateInstantiationRange - Loc is required to be an instantiation
+/// location. Return the start/end of the instantiation 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();
+}
+
+/// getInstantiationRange - Given a SourceLocation object, return the
+/// range of tokens covered by the instantiation in the ultimate file.
+std::pair<SourceLocation,SourceLocation>
+SourceManager::getInstantiationRange(SourceLocation Loc) const {
+ if (Loc.isFileID()) return std::make_pair(Loc, Loc);
+
+ std::pair<SourceLocation,SourceLocation> Res =
+ getImmediateInstantiationRange(Loc);
+
+ // Fully resolve the start and end locations to their ultimate instantiation
+ // points.
+ while (!Res.first.isFileID())
+ Res.first = getImmediateInstantiationRange(Res.first).first;
+ while (!Res.second.isFileID())
+ Res.second = getImmediateInstantiationRange(Res.second).second;
+ return Res;
+}
+
+
+
+//===----------------------------------------------------------------------===//
+// Queries about the code at a SourceLocation.
+//===----------------------------------------------------------------------===//
+
+/// getCharacterData - Return a pointer to the start of the specified location
+/// in the appropriate MemoryBuffer.
+const char *SourceManager::getCharacterData(SourceLocation SL) const {
+ // Note that this is a hot function in the getSpelling() path, which is
+ // heavily used by -E mode.
+ std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(SL);
+
+ // Note that calling 'getBuffer()' may lazily page in a source file.
+ return getSLocEntry(LocInfo.first).getFile().getContentCache()
+ ->getBuffer()->getBufferStart() + LocInfo.second;
+}
+
+
+/// getColumnNumber - Return the column # for the specified file position.
+/// this is significantly cheaper to compute than the line number.
+unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos) const {
+ const char *Buf = getBuffer(FID)->getBufferStart();
+
+ unsigned LineStart = FilePos;
+ while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r')
+ --LineStart;
+ return FilePos-LineStart+1;
+}
+
+unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc) const {
+ if (Loc.isInvalid()) return 0;
+ std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
+ return getColumnNumber(LocInfo.first, LocInfo.second);
+}
+
+unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc) const {
+ if (Loc.isInvalid()) return 0;
+ std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
+ return getColumnNumber(LocInfo.first, LocInfo.second);
+}
+
+
+
+static void ComputeLineNumbers(ContentCache* FI,
+ llvm::BumpPtrAllocator &Alloc) DISABLE_INLINE;
+static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){
+ // Note that calling 'getBuffer()' may lazily page in the file.
+ const MemoryBuffer *Buffer = FI->getBuffer();
+
+ // Find the file offsets of all of the *physical* source lines. This does
+ // not look at trigraphs, escaped newlines, or anything else tricky.
+ std::vector<unsigned> LineOffsets;
+
+ // Line #1 starts at char 0.
+ LineOffsets.push_back(0);
+
+ const unsigned char *Buf = (const unsigned char *)Buffer->getBufferStart();
+ const unsigned char *End = (const unsigned char *)Buffer->getBufferEnd();
+ unsigned Offs = 0;
+ while (1) {
+ // Skip over the contents of the line.
+ // TODO: Vectorize this? This is very performance sensitive for programs
+ // with lots of diagnostics and in -E mode.
+ const unsigned char *NextBuf = (const unsigned char *)Buf;
+ while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0')
+ ++NextBuf;
+ Offs += NextBuf-Buf;
+ Buf = NextBuf;
+
+ if (Buf[0] == '\n' || Buf[0] == '\r') {
+ // If this is \n\r or \r\n, skip both characters.
+ if ((Buf[1] == '\n' || Buf[1] == '\r') && Buf[0] != Buf[1])
+ ++Offs, ++Buf;
+ ++Offs, ++Buf;
+ LineOffsets.push_back(Offs);
+ } else {
+ // Otherwise, this is a null. If end of file, exit.
+ if (Buf == End) break;
+ // Otherwise, skip the null.
+ ++Offs, ++Buf;
+ }
+ }
+
+ // Copy the offsets into the FileInfo structure.
+ FI->NumLines = LineOffsets.size();
+ FI->SourceLineCache = Alloc.Allocate<unsigned>(LineOffsets.size());
+ std::copy(LineOffsets.begin(), LineOffsets.end(), FI->SourceLineCache);
+}
+
+/// getLineNumber - Given a SourceLocation, return the spelling line number
+/// for the position indicated. This requires building and caching a table of
+/// line offsets for the MemoryBuffer, so this is not cheap: use only when
+/// about to emit a diagnostic.
+unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const {
+ ContentCache *Content;
+ if (LastLineNoFileIDQuery == FID)
+ Content = LastLineNoContentCache;
+ else
+ Content = const_cast<ContentCache*>(getSLocEntry(FID)
+ .getFile().getContentCache());
+
+ // If this is the first use of line information for this buffer, compute the
+ /// SourceLineCache for it on demand.
+ if (Content->SourceLineCache == 0)
+ ComputeLineNumbers(Content, ContentCacheAlloc);
+
+ // Okay, we know we have a line number table. Do a binary search to find the
+ // line number that this character position lands on.
+ unsigned *SourceLineCache = Content->SourceLineCache;
+ unsigned *SourceLineCacheStart = SourceLineCache;
+ unsigned *SourceLineCacheEnd = SourceLineCache + Content->NumLines;
+
+ unsigned QueriedFilePos = FilePos+1;
+
+ // FIXME: I would like to be convinced that this code is worth being as
+ // complicated as it is, binary search isn't that slow.
+ //
+ // If it is worth being optimized, then in my opinion it could be more
+ // performant, simpler, and more obviously correct by just "galloping" outward
+ // from the queried file position. In fact, this could be incorporated into a
+ // generic algorithm such as lower_bound_with_hint.
+ //
+ // If someone gives me a test case where this matters, and I will do it! - DWD
+
+ // If the previous query was to the same file, we know both the file pos from
+ // that query and the line number returned. This allows us to narrow the
+ // search space from the entire file to something near the match.
+ if (LastLineNoFileIDQuery == FID) {
+ if (QueriedFilePos >= LastLineNoFilePos) {
+ // FIXME: Potential overflow?
+ SourceLineCache = SourceLineCache+LastLineNoResult-1;
+
+ // The query is likely to be nearby the previous one. Here we check to
+ // see if it is within 5, 10 or 20 lines. It can be far away in cases
+ // where big comment blocks and vertical whitespace eat up lines but
+ // contribute no tokens.
+ if (SourceLineCache+5 < SourceLineCacheEnd) {
+ if (SourceLineCache[5] > QueriedFilePos)
+ SourceLineCacheEnd = SourceLineCache+5;
+ else if (SourceLineCache+10 < SourceLineCacheEnd) {
+ if (SourceLineCache[10] > QueriedFilePos)
+ SourceLineCacheEnd = SourceLineCache+10;
+ else if (SourceLineCache+20 < SourceLineCacheEnd) {
+ if (SourceLineCache[20] > QueriedFilePos)
+ SourceLineCacheEnd = SourceLineCache+20;
+ }
+ }
+ }
+ } else {
+ if (LastLineNoResult < Content->NumLines)
+ SourceLineCacheEnd = SourceLineCache+LastLineNoResult+1;
+ }
+ }
+
+ // If the spread is large, do a "radix" test as our initial guess, based on
+ // the assumption that lines average to approximately the same length.
+ // NOTE: This is currently disabled, as it does not appear to be profitable in
+ // initial measurements.
+ if (0 && SourceLineCacheEnd-SourceLineCache > 20) {
+ unsigned FileLen = Content->SourceLineCache[Content->NumLines-1];
+
+ // Take a stab at guessing where it is.
+ unsigned ApproxPos = Content->NumLines*QueriedFilePos / FileLen;
+
+ // Check for -10 and +10 lines.
+ unsigned LowerBound = std::max(int(ApproxPos-10), 0);
+ unsigned UpperBound = std::min(ApproxPos+10, FileLen);
+
+ // If the computed lower bound is less than the query location, move it in.
+ if (SourceLineCache < SourceLineCacheStart+LowerBound &&
+ SourceLineCacheStart[LowerBound] < QueriedFilePos)
+ SourceLineCache = SourceLineCacheStart+LowerBound;
+
+ // If the computed upper bound is greater than the query location, move it.
+ if (SourceLineCacheEnd > SourceLineCacheStart+UpperBound &&
+ SourceLineCacheStart[UpperBound] >= QueriedFilePos)
+ SourceLineCacheEnd = SourceLineCacheStart+UpperBound;
+ }
+
+ unsigned *Pos
+ = std::lower_bound(SourceLineCache, SourceLineCacheEnd, QueriedFilePos);
+ unsigned LineNo = Pos-SourceLineCacheStart;
+
+ LastLineNoFileIDQuery = FID;
+ LastLineNoContentCache = Content;
+ LastLineNoFilePos = QueriedFilePos;
+ LastLineNoResult = LineNo;
+ return LineNo;
+}
+
+unsigned SourceManager::getInstantiationLineNumber(SourceLocation Loc) const {
+ if (Loc.isInvalid()) return 0;
+ std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
+ return getLineNumber(LocInfo.first, LocInfo.second);
+}
+unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc) const {
+ if (Loc.isInvalid()) return 0;
+ std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
+ return getLineNumber(LocInfo.first, LocInfo.second);
+}
+
+/// getFileCharacteristic - return the file characteristic of the specified
+/// source location, indicating whether this is a normal file, a system
+/// header, or an "implicit extern C" system header.
+///
+/// This state can be modified with flags on GNU linemarker directives like:
+/// # 4 "foo.h" 3
+/// which changes all source locations in the current file after that to be
+/// considered to be from a system header.
+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);
+ const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile();
+
+ // If there are no #line directives in this file, just return the whole-file
+ // state.
+ if (!FI.hasLineDirectives())
+ return FI.getFileCharacteristic();
+
+ assert(LineTable && "Can't have linetable entries without a LineTable!");
+ // See if there is a #line directive before the location.
+ const LineEntry *Entry =
+ LineTable->FindNearestLineEntry(LocInfo.first.ID, LocInfo.second);
+
+ // If this is before the first line marker, use the file characteristic.
+ if (!Entry)
+ return FI.getFileCharacteristic();
+
+ return Entry->FileKind;
+}
+
+/// Return the filename or buffer identifier of the buffer the location is in.
+/// Note that this name does not respect #line directives. Use getPresumedLoc
+/// for normal clients.
+const char *SourceManager::getBufferName(SourceLocation Loc) const {
+ if (Loc.isInvalid()) return "<invalid loc>";
+
+ return getBuffer(getFileID(Loc))->getBufferIdentifier();
+}
+
+
+/// getPresumedLoc - This method returns the "presumed" location of a
+/// SourceLocation specifies. A "presumed location" can be modified by #line
+/// 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.
+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);
+
+ const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile();
+ const SrcMgr::ContentCache *C = FI.getContentCache();
+
+ // To get the source name, first consult the FileEntry (if one exists)
+ // before the MemBuffer as this will avoid unnecessarily paging in the
+ // MemBuffer.
+ const char *Filename =
+ C->Entry ? C->Entry->getName() : C->getBuffer()->getBufferIdentifier();
+ unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second);
+ unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second);
+ SourceLocation IncludeLoc = FI.getIncludeLoc();
+
+ // If we have #line directives in this file, update and overwrite the physical
+ // location info if appropriate.
+ if (FI.hasLineDirectives()) {
+ assert(LineTable && "Can't have linetable entries without a LineTable!");
+ // See if there is a #line directive before this. If so, get it.
+ if (const LineEntry *Entry =
+ LineTable->FindNearestLineEntry(LocInfo.first.ID, LocInfo.second)) {
+ // If the LineEntry indicates a filename, use it.
+ if (Entry->FilenameID != -1)
+ Filename = LineTable->getFilename(Entry->FilenameID);
+
+ // Use the line number specified by the LineEntry. This line number may
+ // be multiple lines down from the line entry. Add the difference in
+ // physical line numbers from the query point and the line marker to the
+ // total.
+ unsigned MarkerLineNo = getLineNumber(LocInfo.first, Entry->FileOffset);
+ LineNo = Entry->LineNo + (LineNo-MarkerLineNo-1);
+
+ // Note that column numbers are not molested by line markers.
+
+ // Handle virtual #include manipulation.
+ if (Entry->IncludeOffset) {
+ IncludeLoc = getLocForStartOfFile(LocInfo.first);
+ IncludeLoc = IncludeLoc.getFileLocWithOffset(Entry->IncludeOffset);
+ }
+ }
+ }
+
+ return PresumedLoc(Filename, LineNo, ColNo, IncludeLoc);
+}
+
+//===----------------------------------------------------------------------===//
+// Other miscellaneous methods.
+//===----------------------------------------------------------------------===//
+
+
+/// PrintStats - Print statistics to stderr.
+///
+void SourceManager::PrintStats() const {
+ llvm::cerr << "\n*** Source Manager Stats:\n";
+ llvm::cerr << FileInfos.size() << " files mapped, " << MemBufferInfos.size()
+ << " mem buffers mapped.\n";
+ llvm::cerr << SLocEntryTable.size() << " SLocEntry's allocated, "
+ << NextOffset << "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();
+ }
+
+ llvm::cerr << NumFileBytesMapped << " bytes of files mapped, "
+ << NumLineNumsComputed << " files with line #'s computed.\n";
+ llvm::cerr << "FileID scans: " << NumLinearScans << " linear, "
+ << NumBinaryProbes << " binary.\n";
+}
+
+ExternalSLocEntrySource::~ExternalSLocEntrySource() { }
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
new file mode 100644
index 000000000000..1e8ca2bd56c4
--- /dev/null
+++ b/lib/Basic/TargetInfo.cpp
@@ -0,0 +1,295 @@
+//===--- TargetInfo.cpp - Information about Target machine ----------------===//
+//
+// 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 TargetInfo and TargetInfoImpl interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/STLExtras.h"
+#include <cstdlib>
+using namespace clang;
+
+// TargetInfo Constructor.
+TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
+ // Set defaults. Defaults are set for a 32-bit RISC platform,
+ // like PPC or SPARC.
+ // These should be overridden by concrete targets as needed.
+ CharIsSigned = true;
+ TLSSupported = true;
+ PointerWidth = PointerAlign = 32;
+ WCharWidth = WCharAlign = 32;
+ IntWidth = IntAlign = 32;
+ LongWidth = LongAlign = 32;
+ LongLongWidth = LongLongAlign = 64;
+ FloatWidth = 32;
+ FloatAlign = 32;
+ DoubleWidth = 64;
+ DoubleAlign = 64;
+ LongDoubleWidth = 64;
+ LongDoubleAlign = 64;
+ IntMaxTWidth = 64;
+ SizeType = UnsignedLong;
+ PtrDiffType = SignedLong;
+ IntMaxType = SignedLongLong;
+ UIntMaxType = UnsignedLongLong;
+ IntPtrType = SignedLong;
+ WCharType = SignedInt;
+ FloatFormat = &llvm::APFloat::IEEEsingle;
+ DoubleFormat = &llvm::APFloat::IEEEdouble;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble;
+ 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";
+ UserLabelPrefix = "_";
+}
+
+// Out of line virtual dtor for TargetInfo.
+TargetInfo::~TargetInfo() {}
+
+/// getTypeName - Return the user string for the specified integer type enum.
+/// For example, SignedShort -> "short".
+const char *TargetInfo::getTypeName(IntType T) {
+ switch (T) {
+ default: assert(0 && "not an integer!");
+ case SignedShort: return "short";
+ case UnsignedShort: return "unsigned short";
+ case SignedInt: return "int";
+ case UnsignedInt: return "unsigned int";
+ case SignedLong: return "long int";
+ case UnsignedLong: return "long unsigned int";
+ case SignedLongLong: return "long long int";
+ case UnsignedLongLong: return "long long unsigned int";
+ }
+}
+
+//===----------------------------------------------------------------------===//
+
+
+static void removeGCCRegisterPrefix(const char *&Name) {
+ if (Name[0] == '%' || Name[0] == '#')
+ Name++;
+}
+
+/// 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(const char *Name) const {
+ const char * const *Names;
+ unsigned NumNames;
+
+ // Get rid of any register prefix.
+ removeGCCRegisterPrefix(Name);
+
+
+ if (strcmp(Name, "memory") == 0 ||
+ strcmp(Name, "cc") == 0)
+ return true;
+
+ getGCCRegNames(Names, NumNames);
+
+ // If we have a number it maps to an entry in the register name array.
+ if (isdigit(Name[0])) {
+ char *End;
+ int n = (int)strtol(Name, &End, 0);
+ if (*End == 0)
+ return n >= 0 && (unsigned)n < NumNames;
+ }
+
+ // Check register names.
+ for (unsigned i = 0; i < NumNames; i++) {
+ if (strcmp(Name, Names[i]) == 0)
+ return true;
+ }
+
+ // Now check aliases.
+ const GCCRegAlias *Aliases;
+ unsigned NumAliases;
+
+ getGCCRegAliases(Aliases, NumAliases);
+ for (unsigned i = 0; i < NumAliases; i++) {
+ for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
+ if (!Aliases[i].Aliases[j])
+ break;
+ if (strcmp(Aliases[i].Aliases[j], Name) == 0)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const {
+ assert(isValidGCCRegisterName(Name) && "Invalid register passed in");
+
+ removeGCCRegisterPrefix(Name);
+
+ const char * const *Names;
+ unsigned NumNames;
+
+ getGCCRegNames(Names, NumNames);
+
+ // First, check if we have a number.
+ if (isdigit(Name[0])) {
+ char *End;
+ int n = (int)strtol(Name, &End, 0);
+ if (*End == 0) {
+ assert(n >= 0 && (unsigned)n < NumNames &&
+ "Out of bounds register number!");
+ return Names[n];
+ }
+ }
+
+ // Now check aliases.
+ const GCCRegAlias *Aliases;
+ unsigned NumAliases;
+
+ getGCCRegAliases(Aliases, NumAliases);
+ for (unsigned i = 0; i < NumAliases; i++) {
+ for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
+ if (!Aliases[i].Aliases[j])
+ break;
+ if (strcmp(Aliases[i].Aliases[j], Name) == 0)
+ return Aliases[i].Register;
+ }
+ }
+
+ return Name;
+}
+
+bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const {
+ const char *Name = Info.getConstraintStr().c_str();
+ // An output constraint must start with '=' or '+'
+ if (*Name != '=' && *Name != '+')
+ return false;
+
+ if (*Name == '+')
+ Info.setIsReadWrite();
+
+ Name++;
+ while (*Name) {
+ switch (*Name) {
+ default:
+ if (!validateAsmConstraint(Name, Info)) {
+ // FIXME: We temporarily return false
+ // so we can add more constraints as we hit it.
+ // Eventually, an unknown constraint should just be treated as 'g'.
+ return false;
+ }
+ case '&': // early clobber.
+ break;
+ case 'r': // general register.
+ Info.setAllowsRegister();
+ break;
+ case 'm': // memory operand.
+ Info.setAllowsMemory();
+ break;
+ case 'g': // general register, memory operand or immediate integer.
+ case 'X': // any operand.
+ Info.setAllowsRegister();
+ Info.setAllowsMemory();
+ break;
+ }
+
+ Name++;
+ }
+
+ return true;
+}
+
+bool TargetInfo::resolveSymbolicName(const char *&Name,
+ ConstraintInfo *OutputConstraints,
+ unsigned NumOutputs,
+ unsigned &Index) const {
+ assert(*Name == '[' && "Symbolic name did not start with '['");
+ Name++;
+ const char *Start = Name;
+ while (*Name && *Name != ']')
+ Name++;
+
+ if (!*Name) {
+ // Missing ']'
+ return false;
+ }
+
+ std::string SymbolicName(Start, Name - Start);
+
+ for (Index = 0; Index != NumOutputs; ++Index)
+ if (SymbolicName == OutputConstraints[Index].getName())
+ return true;
+
+ return false;
+}
+
+bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
+ unsigned NumOutputs,
+ ConstraintInfo &Info) const {
+ const char *Name = Info.ConstraintStr.c_str();
+
+ while (*Name) {
+ switch (*Name) {
+ default:
+ // Check if we have a matching constraint
+ if (*Name >= '0' && *Name <= '9') {
+ unsigned i = *Name - '0';
+
+ // Check if matching constraint is out of bounds.
+ if (i >= NumOutputs)
+ return false;
+
+ // The constraint should have the same info as the respective
+ // output constraint.
+ Info.setTiedOperand(i, OutputConstraints[i]);
+ } else if (!validateAsmConstraint(Name, Info)) {
+ // FIXME: This error return is in place temporarily so we can
+ // add more constraints as we hit it. Eventually, an unknown
+ // constraint should just be treated as 'g'.
+ return false;
+ }
+ break;
+ case '[': {
+ unsigned Index = 0;
+ if (!resolveSymbolicName(Name, OutputConstraints, NumOutputs, Index))
+ return false;
+
+ break;
+ }
+ case '%': // commutative
+ // FIXME: Fail if % is used with the last operand.
+ break;
+ case 'i': // immediate integer.
+ case 'n': // immediate integer with a known value.
+ break;
+ case 'I': // Various constant constraints with target-specific meanings.
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ break;
+ case 'r': // general register.
+ Info.setAllowsRegister();
+ break;
+ case 'm': // memory operand.
+ Info.setAllowsMemory();
+ break;
+ case 'g': // general register, memory operand or immediate integer.
+ case 'X': // any operand.
+ Info.setAllowsRegister();
+ Info.setAllowsMemory();
+ break;
+ }
+
+ Name++;
+ }
+
+ return true;
+}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
new file mode 100644
index 000000000000..4b94bcfc432c
--- /dev/null
+++ b/lib/Basic/Targets.cpp
@@ -0,0 +1,1500 @@
+//===--- Targets.cpp - Implement -arch option and targets -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements construction of a TargetInfo object from a
+// target triple.
+//
+//===----------------------------------------------------------------------===//
+
+// FIXME: Layering violation
+#include "clang/AST/Builtins.h"
+#include "clang/AST/TargetBuiltins.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/SmallString.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Common code shared among targets.
+//===----------------------------------------------------------------------===//
+
+static void Define(std::vector<char> &Buf, const char *Macro,
+ const char *Val = "1") {
+ const char *Def = "#define ";
+ Buf.insert(Buf.end(), Def, Def+strlen(Def));
+ Buf.insert(Buf.end(), Macro, Macro+strlen(Macro));
+ Buf.push_back(' ');
+ Buf.insert(Buf.end(), Val, Val+strlen(Val));
+ Buf.push_back('\n');
+}
+
+/// 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(std::vector<char> &Buf, const char *MacroName,
+ const LangOptions &Opts) {
+ assert(MacroName[0] != '_' && "Identifier should be in the user's namespace");
+
+ // If in GNU mode (e.g. -std=gnu99 but not -std=c99) define the raw identifier
+ // in the user's namespace.
+ if (Opts.GNUMode)
+ Define(Buf, MacroName);
+
+ // Define __unix.
+ llvm::SmallString<20> TmpStr;
+ TmpStr = "__";
+ TmpStr += MacroName;
+ Define(Buf, TmpStr.c_str());
+
+ // Define __unix__.
+ TmpStr += "__";
+ Define(Buf, TmpStr.c_str());
+}
+
+//===----------------------------------------------------------------------===//
+// Defines specific to certain operating systems.
+//===----------------------------------------------------------------------===//
+
+static void getSolarisDefines(const LangOptions &Opts, std::vector<char> &Defs) {
+ DefineStd(Defs, "sun", Opts);
+ DefineStd(Defs, "unix", Opts);
+ Define(Defs, "__ELF__");
+ Define(Defs, "__svr4__");
+ Define(Defs, "__SVR4");
+}
+
+static void getFreeBSDDefines(const LangOptions &Opts, bool is64Bit,
+ const char *Triple, std::vector<char> &Defs) {
+ // FreeBSD defines; list based off of gcc output
+
+ const char *FreeBSD = strstr(Triple, "-freebsd");
+ FreeBSD += strlen("-freebsd");
+ char release[] = "X";
+ release[0] = FreeBSD[0];
+ char version[] = "X00001";
+ version[0] = FreeBSD[0];
+
+ Define(Defs, "__FreeBSD__", release);
+ Define(Defs, "__FreeBSD_cc_version", version);
+ Define(Defs, "__KPRINTF_ATTRIBUTE__");
+ DefineStd(Defs, "unix", Opts);
+ Define(Defs, "__ELF__", "1");
+ if (is64Bit) {
+ Define(Defs, "__LP64__");
+ }
+}
+
+static void getDragonFlyDefines(const LangOptions &Opts,
+ std::vector<char> &Defs) {
+ // DragonFly defines; list based off of gcc output
+ Define(Defs, "__DragonFly__");
+ Define(Defs, "__DragonFly_cc_version", "100001");
+ Define(Defs, "__ELF__");
+ Define(Defs, "__KPRINTF_ATTRIBUTE__");
+ Define(Defs, "__tune_i386__");
+ DefineStd(Defs, "unix", Opts);
+}
+
+static void getLinuxDefines(const LangOptions &Opts, std::vector<char> &Defs) {
+ // Linux defines; list based off of gcc output
+ DefineStd(Defs, "unix", Opts);
+ DefineStd(Defs, "linux", Opts);
+ Define(Defs, "__gnu_linux__");
+ Define(Defs, "__ELF__", "1");
+}
+
+/// getDarwinNumber - Parse the 'darwin number' out of the specific targe
+/// triple. For example, if we have darwin8.5 return 8,5,0. If any entry is
+/// not defined, return 0's. Return true if we have -darwin in the string or
+/// false otherwise.
+static bool getDarwinNumber(const char *Triple, unsigned &Maj, unsigned &Min, unsigned &Revision) {
+ Maj = Min = Revision = 0;
+ const char *Darwin = strstr(Triple, "-darwin");
+ if (Darwin == 0) return false;
+
+ Darwin += strlen("-darwin");
+ if (Darwin[0] < '0' || Darwin[0] > '9')
+ return true;
+
+ Maj = Darwin[0]-'0';
+ ++Darwin;
+
+ // Handle "darwin11".
+ if (Maj == 1 && Darwin[0] >= '0' && Darwin[0] <= '9') {
+ Maj = Maj*10 + (Darwin[0] - '0');
+ ++Darwin;
+ }
+
+ // Handle minor version: 10.4.9 -> darwin8.9 -> "1049"
+ if (Darwin[0] != '.')
+ return true;
+
+ ++Darwin;
+ if (Darwin[0] < '0' || Darwin[0] > '9')
+ return true;
+
+ Min = Darwin[0]-'0';
+ ++Darwin;
+
+ // Handle 10.4.11 -> darwin8.11
+ if (Min == 1 && Darwin[0] >= '0' && Darwin[0] <= '9') {
+ Min = Min*10 + (Darwin[0] - '0');
+ ++Darwin;
+ }
+
+ // Handle revision darwin8.9.1
+ if (Darwin[0] != '.')
+ return true;
+
+ ++Darwin;
+ if (Darwin[0] < '0' || Darwin[0] > '9')
+ return true;
+
+ Revision = Darwin[0]-'0';
+ ++Darwin;
+
+ if (Revision == 1 && Darwin[0] >= '0' && Darwin[0] <= '9') {
+ Revision = Revision*10 + (Darwin[0] - '0');
+ ++Darwin;
+ }
+
+ return true;
+}
+
+static void getDarwinDefines(std::vector<char> &Defs, const LangOptions &Opts) {
+ Define(Defs, "__APPLE__");
+ Define(Defs, "__MACH__");
+ Define(Defs, "OBJC_NEW_PROPERTIES");
+
+ // __weak is always defined, for use in blocks and with objc pointers.
+ Define(Defs, "__weak", "__attribute__((objc_gc(weak)))");
+
+ // Darwin defines __strong even in C mode (just to nothing).
+ if (!Opts.ObjC1 || Opts.getGCMode() == LangOptions::NonGC)
+ Define(Defs, "__strong", "");
+ else
+ Define(Defs, "__strong", "__attribute__((objc_gc(strong)))");
+}
+
+static void getDarwinOSXDefines(std::vector<char> &Defs, const char *Triple) {
+ // Figure out which "darwin number" the target triple is. "darwin9" -> 10.5.
+ unsigned Maj, Min, Rev;
+ if (getDarwinNumber(Triple, Maj, Min, Rev)) {
+ char MacOSXStr[] = "1000";
+ if (Maj >= 4 && Maj <= 13) { // 10.0-10.9
+ // darwin7 -> 1030, darwin8 -> 1040, darwin9 -> 1050, etc.
+ MacOSXStr[2] = '0' + Maj-4;
+ }
+
+ // Handle minor version: 10.4.9 -> darwin8.9 -> "1049"
+ // Cap 10.4.11 -> darwin8.11 -> "1049"
+ MacOSXStr[3] = std::min(Min, 9U)+'0';
+ Define(Defs, "__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", MacOSXStr);
+ }
+}
+
+static void getDarwinIPhoneOSDefines(std::vector<char> &Defs,
+ const char *Triple) {
+ // Figure out which "darwin number" the target triple is. "darwin9" -> 10.5.
+ unsigned Maj, Min, Rev;
+ if (getDarwinNumber(Triple, Maj, Min, Rev)) {
+ // When targetting iPhone OS, interpret the minor version and
+ // revision as the iPhone OS version
+ char iPhoneOSStr[] = "10000";
+ if (Min >= 2 && Min <= 9) { // iPhone OS 2.0-9.0
+ // darwin9.2.0 -> 20000, darwin9.3.0 -> 30000, etc.
+ iPhoneOSStr[0] = '0' + Min;
+ }
+
+ // Handle minor version: 2.2 -> darwin9.2.2 -> 20200
+ iPhoneOSStr[2] = std::min(Rev, 9U)+'0';
+ Define(Defs, "__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__",
+ iPhoneOSStr);
+ }
+}
+
+/// GetDarwinLanguageOptions - Set the default language options for darwin.
+static void GetDarwinLanguageOptions(LangOptions &Opts,
+ const char *Triple) {
+ Opts.NeXTRuntime = true;
+
+ unsigned Maj, Min, Rev;
+ if (!getDarwinNumber(Triple, Maj, Min, Rev))
+ return;
+
+ // Blocks default to on for 10.6 (darwin10) and beyond.
+ // As does nonfragile-abi for 64bit mode
+ if (Maj > 9)
+ Opts.Blocks = 1;
+
+ if (Maj >= 9 && Opts.ObjC1 && !strncmp(Triple, "x86_64", 6))
+ Opts.ObjCNonFragileABI = 1;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Specific target implementations.
+//===----------------------------------------------------------------------===//
+
+namespace {
+// PPC abstract base class
+class PPCTargetInfo : public TargetInfo {
+ static const Builtin::Info BuiltinInfo[];
+ static const char * const GCCRegNames[];
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+
+public:
+ PPCTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ CharIsSigned = false;
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ Records = BuiltinInfo;
+ NumRecords = clang::PPC::LastTSBuiltin-Builtin::FirstTSBuiltin;
+ }
+
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const;
+
+ virtual const char *getVAListDeclaration() const {
+ return "typedef char* __builtin_va_list;";
+ // This is the right definition for ABI/V4: System V.4/eabi.
+ /*return "typedef struct __va_list_tag {"
+ " unsigned char gpr;"
+ " unsigned char fpr;"
+ " unsigned short reserved;"
+ " void* overflow_arg_area;"
+ " void* reg_save_area;"
+ "} __builtin_va_list[1];";*/
+ }
+ virtual const char *getTargetPrefix() const {
+ return "ppc";
+ }
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const;
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const;
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const {
+ switch (*Name) {
+ default: return false;
+ case 'O': // Zero
+ return true;
+ case 'b': // Base register
+ case 'f': // Floating point register
+ Info.setAllowsRegister();
+ return true;
+ }
+ }
+ virtual const char *getClobbers() const {
+ return "";
+ }
+};
+
+const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false },
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false },
+#include "clang/AST/PPCBuiltins.def"
+};
+
+
+/// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific
+/// #defines that are not tied to a specific subtarget.
+void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defs) const {
+ // Target identification.
+ Define(Defs, "__ppc__");
+ Define(Defs, "_ARCH_PPC");
+ Define(Defs, "__POWERPC__");
+ if (PointerWidth == 64) {
+ Define(Defs, "_ARCH_PPC64");
+ Define(Defs, "_LP64");
+ Define(Defs, "__LP64__");
+ Define(Defs, "__ppc64__");
+ } else {
+ Define(Defs, "__ppc__");
+ }
+
+ // Target properties.
+ Define(Defs, "_BIG_ENDIAN");
+ Define(Defs, "__BIG_ENDIAN__");
+
+ // Subtarget options.
+ Define(Defs, "__NATURAL_ALIGNMENT__");
+ Define(Defs, "__REGISTER_PREFIX__", "");
+
+ // FIXME: Should be controlled by command line option.
+ Define(Defs, "__LONG_DOUBLE_128__");
+}
+
+
+const char * const PPCTargetInfo::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", "29", "30", "31",
+ "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", "29", "30", "31",
+ "mq", "lr", "ctr", "ap",
+ "0", "1", "2", "3", "4", "5", "6", "7",
+ "xer",
+ "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", "29", "30", "31",
+ "vrsave", "vscr",
+ "spe_acc", "spefscr",
+ "sfp"
+};
+
+void PPCTargetInfo::getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+}
+
+const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = {
+ // While some of these aliases do map to different registers
+ // they still share the same register name.
+ { { "cc", "cr0", "fr0", "r0", "v0"}, "0" },
+ { { "cr1", "fr1", "r1", "sp", "v1"}, "1" },
+ { { "cr2", "fr2", "r2", "toc", "v2"}, "2" },
+ { { "cr3", "fr3", "r3", "v3"}, "3" },
+ { { "cr4", "fr4", "r4", "v4"}, "4" },
+ { { "cr5", "fr5", "r5", "v5"}, "5" },
+ { { "cr6", "fr6", "r6", "v6"}, "6" },
+ { { "cr7", "fr7", "r7", "v7"}, "7" },
+ { { "fr8", "r8", "v8"}, "8" },
+ { { "fr9", "r9", "v9"}, "9" },
+ { { "fr10", "r10", "v10"}, "10" },
+ { { "fr11", "r11", "v11"}, "11" },
+ { { "fr12", "r12", "v12"}, "12" },
+ { { "fr13", "r13", "v13"}, "13" },
+ { { "fr14", "r14", "v14"}, "14" },
+ { { "fr15", "r15", "v15"}, "15" },
+ { { "fr16", "r16", "v16"}, "16" },
+ { { "fr17", "r17", "v17"}, "17" },
+ { { "fr18", "r18", "v18"}, "18" },
+ { { "fr19", "r19", "v19"}, "19" },
+ { { "fr20", "r20", "v20"}, "20" },
+ { { "fr21", "r21", "v21"}, "21" },
+ { { "fr22", "r22", "v22"}, "22" },
+ { { "fr23", "r23", "v23"}, "23" },
+ { { "fr24", "r24", "v24"}, "24" },
+ { { "fr25", "r25", "v25"}, "25" },
+ { { "fr26", "r26", "v26"}, "26" },
+ { { "fr27", "r27", "v27"}, "27" },
+ { { "fr28", "r28", "v28"}, "28" },
+ { { "fr29", "r29", "v29"}, "29" },
+ { { "fr30", "r30", "v30"}, "30" },
+ { { "fr31", "r31", "v31"}, "31" },
+};
+
+void PPCTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ Aliases = GCCRegAliases;
+ NumAliases = llvm::array_lengthof(GCCRegAliases);
+}
+} // end anonymous namespace.
+
+namespace {
+class PPC32TargetInfo : public PPCTargetInfo {
+public:
+ PPC32TargetInfo(const std::string& triple) : PPCTargetInfo(triple) {
+ DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
+ "i64:64:64-f32:32:32-f64:64:64-v128:128:128";
+ }
+};
+} // end anonymous namespace.
+
+namespace {
+class PPC64TargetInfo : public PPCTargetInfo {
+public:
+ PPC64TargetInfo(const std::string& triple) : PPCTargetInfo(triple) {
+ LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
+ DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
+ "i64:64:64-f32:32:32-f64:64:64-v128:128:128";
+ }
+};
+} // end anonymous namespace.
+
+
+namespace {
+class DarwinPPCTargetInfo : public PPC32TargetInfo {
+public:
+ DarwinPPCTargetInfo(const std::string& triple) : PPC32TargetInfo(triple) {}
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ PPC32TargetInfo::getTargetDefines(Opts, Defines);
+ getDarwinDefines(Defines, Opts);
+ getDarwinOSXDefines(Defines, getTargetTriple());
+ }
+
+ /// getDefaultLangOptions - Allow the target to specify default settings for
+ /// various language options. These may be overridden by command line
+ /// options.
+ virtual void getDefaultLangOptions(LangOptions &Opts) {
+ GetDarwinLanguageOptions(Opts, getTargetTriple());
+ }
+};
+} // end anonymous namespace.
+
+namespace {
+class DarwinPPC64TargetInfo : public PPC64TargetInfo {
+public:
+ DarwinPPC64TargetInfo(const std::string& triple) : PPC64TargetInfo(triple) {}
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ PPC64TargetInfo::getTargetDefines(Opts, Defines);
+ getDarwinDefines(Defines, Opts);
+ getDarwinOSXDefines(Defines, getTargetTriple());
+ }
+
+ /// getDefaultLangOptions - Allow the target to specify default settings for
+ /// various language options. These may be overridden by command line
+ /// options.
+ virtual void getDefaultLangOptions(LangOptions &Opts) {
+ GetDarwinLanguageOptions(Opts, getTargetTriple());
+ }
+};
+} // end anonymous namespace.
+
+namespace {
+// Namespace for x86 abstract base class
+const Builtin::Info BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false },
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false },
+#include "clang/AST/X86Builtins.def"
+};
+
+const char *GCCRegNames[] = {
+ "ax", "dx", "cx", "bx", "si", "di", "bp", "sp",
+ "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
+ "argp", "flags", "fspr", "dirflag", "frame",
+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
+ "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
+};
+
+const TargetInfo::GCCRegAlias GCCRegAliases[] = {
+ { { "al", "ah", "eax", "rax" }, "ax" },
+ { { "bl", "bh", "ebx", "rbx" }, "bx" },
+ { { "cl", "ch", "ecx", "rcx" }, "cx" },
+ { { "dl", "dh", "edx", "rdx" }, "dx" },
+ { { "esi", "rsi" }, "si" },
+ { { "edi", "rdi" }, "di" },
+ { { "esp", "rsp" }, "sp" },
+ { { "ebp", "rbp" }, "bp" },
+};
+
+// X86 target abstract base class; x86-32 and x86-64 are very close, so
+// most of the implementation can be shared.
+class X86TargetInfo : public TargetInfo {
+ enum X86SSEEnum {
+ NoMMXSSE, MMX, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42
+ } SSELevel;
+public:
+ X86TargetInfo(const std::string& triple)
+ : TargetInfo(triple), SSELevel(NoMMXSSE) {
+ LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ Records = BuiltinInfo;
+ NumRecords = clang::X86::LastTSBuiltin-Builtin::FirstTSBuiltin;
+ }
+ virtual const char *getTargetPrefix() const {
+ return "x86";
+ }
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+ }
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ Aliases = GCCRegAliases;
+ NumAliases = llvm::array_lengthof(GCCRegAliases);
+ }
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const;
+ virtual std::string convertConstraint(const char Constraint) const;
+ virtual const char *getClobbers() const {
+ return "~{dirflag},~{fpsr},~{flags}";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const;
+ 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 HandleTargetFeatures(const llvm::StringMap<bool> &Features);
+};
+
+void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
+ llvm::StringMap<bool> &Features) const {
+ // FIXME: This should not be here.
+ Features["3dnow"] = false;
+ Features["3dnowa"] = false;
+ Features["mmx"] = false;
+ Features["sse"] = false;
+ Features["sse2"] = false;
+ Features["sse3"] = false;
+ Features["ssse3"] = false;
+ Features["sse41"] = false;
+ Features["sse42"] = false;
+
+ // LLVM does not currently recognize this.
+ // Features["sse4a"] = false;
+
+ // FIXME: This *really* should not be here.
+
+ // X86_64 always has SSE2.
+ 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")
+ setFeatureEnabled(Features, "mmx", true);
+ else if (CPU == "pentium3")
+ setFeatureEnabled(Features, "sse", true);
+ else if (CPU == "pentium-m" || CPU == "pentium4" || CPU == "x86-64")
+ setFeatureEnabled(Features, "sse2", true);
+ else if (CPU == "yonah" || CPU == "prescott" || CPU == "nocona")
+ setFeatureEnabled(Features, "sse3", true);
+ else if (CPU == "core2")
+ setFeatureEnabled(Features, "ssse3", true);
+ else if (CPU == "penryn") {
+ setFeatureEnabled(Features, "sse4", true);
+ Features["sse42"] = false;
+ } else if (CPU == "atom")
+ setFeatureEnabled(Features, "sse3", true);
+ else if (CPU == "corei7")
+ setFeatureEnabled(Features, "sse4", true);
+ else if (CPU == "k6" || CPU == "winchip-c6")
+ setFeatureEnabled(Features, "mmx", true);
+ else if (CPU == "k6-2" || CPU == "k6-3" || CPU == "athlon" ||
+ CPU == "athlon-tbird" || CPU == "winchip2" || CPU == "c3") {
+ setFeatureEnabled(Features, "mmx", true);
+ setFeatureEnabled(Features, "3dnow", true);
+ } else if (CPU == "athlon-4" || CPU == "athlon-xp" || CPU == "athlon-mp") {
+ setFeatureEnabled(Features, "sse", true);
+ setFeatureEnabled(Features, "3dnowa", true);
+ } else if (CPU == "k8" || CPU == "opteron" || CPU == "athlon64" ||
+ CPU == "athlon-fx") {
+ setFeatureEnabled(Features, "sse2", true);
+ setFeatureEnabled(Features, "3dnowa", true);
+ } else if (CPU == "c3-2")
+ setFeatureEnabled(Features, "sse", true);
+}
+
+bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
+ const std::string &Name,
+ bool Enabled) const {
+ // FIXME: This *really* should not be here.
+ if (!Features.count(Name) && Name != "sse4")
+ return false;
+
+ if (Enabled) {
+ if (Name == "mmx")
+ Features["mmx"] = true;
+ else if (Name == "sse")
+ Features["mmx"] = Features["sse"] = true;
+ else if (Name == "sse2")
+ Features["mmx"] = Features["sse"] = Features["sse2"] = true;
+ else if (Name == "sse3")
+ Features["mmx"] = Features["sse"] = Features["sse2"] =
+ Features["sse3"] = true;
+ else if (Name == "ssse3")
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["ssse3"] = true;
+ else if (Name == "sse4")
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["ssse3"] = Features["sse41"] = Features["sse42"] = true;
+ else if (Name == "3dnow")
+ Features["3dnowa"] = true;
+ else if (Name == "3dnowa")
+ Features["3dnow"] = Features["3dnowa"] = true;
+ } else {
+ if (Name == "mmx")
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["ssse3"] = Features["sse41"] = Features["sse42"] = false;
+ else if (Name == "sse")
+ Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["ssse3"] = Features["sse41"] = Features["sse42"] = false;
+ else if (Name == "sse2")
+ Features["sse2"] = Features["sse3"] = Features["ssse3"] =
+ Features["sse41"] = Features["sse42"] = false;
+ else if (Name == "sse3")
+ Features["sse3"] = Features["ssse3"] = Features["sse41"] =
+ Features["sse42"] = false;
+ else if (Name == "ssse3")
+ Features["ssse3"] = Features["sse41"] = Features["sse42"] = false;
+ else if (Name == "sse4")
+ Features["sse41"] = Features["sse42"] = false;
+ else if (Name == "3dnow")
+ Features["3dnow"] = Features["3dnowa"] = false;
+ else if (Name == "3dnowa")
+ Features["3dnowa"] = false;
+ }
+
+ return true;
+}
+
+/// HandleTargetOptions - Perform initialization based on the user
+/// configured set of features.
+void X86TargetInfo::HandleTargetFeatures(const llvm::StringMap<bool>&Features) {
+ if (Features.lookup("sse42"))
+ SSELevel = SSE42;
+ else if (Features.lookup("sse41"))
+ SSELevel = SSE41;
+ else if (Features.lookup("ssse3"))
+ SSELevel = SSSE3;
+ else if (Features.lookup("sse3"))
+ SSELevel = SSE3;
+ else if (Features.lookup("sse2"))
+ SSELevel = SSE2;
+ else if (Features.lookup("sse"))
+ SSELevel = SSE1;
+ else if (Features.lookup("mmx"))
+ SSELevel = MMX;
+}
+
+/// X86TargetInfo::getTargetDefines - Return a set of the X86-specific #defines
+/// that are not tied to a specific subtarget.
+void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defs) const {
+ // Target identification.
+ if (PointerWidth == 64) {
+ Define(Defs, "_LP64");
+ Define(Defs, "__LP64__");
+ Define(Defs, "__amd64__");
+ Define(Defs, "__amd64");
+ Define(Defs, "__x86_64");
+ Define(Defs, "__x86_64__");
+ } else {
+ DefineStd(Defs, "i386", Opts);
+ }
+
+ // Target properties.
+ Define(Defs, "__LITTLE_ENDIAN__");
+
+ // Subtarget options.
+ Define(Defs, "__nocona");
+ Define(Defs, "__nocona__");
+ Define(Defs, "__tune_nocona__");
+ Define(Defs, "__REGISTER_PREFIX__", "");
+
+ // Define __NO_MATH_INLINES on linux/x86 so that we don't get inline
+ // functions in glibc header files that use FP Stack inline asm which the
+ // backend can't deal with (PR879).
+ Define(Defs, "__NO_MATH_INLINES");
+
+ // Each case falls through to the previous one here.
+ switch (SSELevel) {
+ case SSE42:
+ Define(Defs, "__SSE4_2__");
+ case SSE41:
+ Define(Defs, "__SSE4_1__");
+ case SSSE3:
+ Define(Defs, "__SSSE3__");
+ case SSE3:
+ Define(Defs, "__SSE3__");
+ case SSE2:
+ Define(Defs, "__SSE2__");
+ Define(Defs, "__SSE2_MATH__"); // -mfp-math=sse always implied.
+ case SSE1:
+ Define(Defs, "__SSE__");
+ Define(Defs, "__SSE_MATH__"); // -mfp-math=sse always implied.
+ case MMX:
+ Define(Defs, "__MMX__");
+ case NoMMXSSE:
+ break;
+ }
+}
+
+
+bool
+X86TargetInfo::validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const {
+ switch (*Name) {
+ default: return false;
+ case 'a': // eax.
+ case 'b': // ebx.
+ case 'c': // ecx.
+ case 'd': // edx.
+ case 'S': // esi.
+ case 'D': // edi.
+ case 'A': // edx:eax.
+ case 't': // top of floating point stack.
+ case 'u': // second from top of floating point stack.
+ case 'q': // Any register accessible as [r]l: a, b, c, and d.
+ case 'y': // Any MMX register.
+ case 'x': // Any SSE register.
+ case 'Q': // Any register accessible as [r]h: a, b, c, and d.
+ case 'e': // 32-bit signed integer constant for use with zero-extending
+ // x86_64 instructions.
+ case 'Z': // 32-bit unsigned integer constant for use with zero-extending
+ // x86_64 instructions.
+ case 'N': // unsigned 8-bit integer constant for use with in and out
+ // instructions.
+ Info.setAllowsRegister();
+ return true;
+ }
+}
+
+std::string
+X86TargetInfo::convertConstraint(const char Constraint) const {
+ switch (Constraint) {
+ case 'a': return std::string("{ax}");
+ case 'b': return std::string("{bx}");
+ case 'c': return std::string("{cx}");
+ case 'd': return std::string("{dx}");
+ case 'S': return std::string("{si}");
+ case 'D': return std::string("{di}");
+ case 't': // top of floating point stack.
+ return std::string("{st}");
+ case 'u': // second from top of floating point stack.
+ return std::string("{st(1)}"); // second from top of floating point stack.
+ default:
+ return std::string(1, Constraint);
+ }
+}
+} // end anonymous namespace
+
+namespace {
+// X86-32 generic target
+class X86_32TargetInfo : public X86TargetInfo {
+public:
+ X86_32TargetInfo(const std::string& triple) : X86TargetInfo(triple) {
+ DoubleAlign = LongLongAlign = 32;
+ LongDoubleWidth = 96;
+ 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";
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ IntPtrType = SignedInt;
+ RegParmMax = 3;
+ }
+ virtual const char *getVAListDeclaration() const {
+ return "typedef char* __builtin_va_list;";
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-32 Darwin (OS X) target
+class DarwinI386TargetInfo : public X86_32TargetInfo {
+public:
+ DarwinI386TargetInfo(const std::string& triple) : X86_32TargetInfo(triple) {
+ LongDoubleWidth = 128;
+ LongDoubleAlign = 128;
+ SizeType = UnsignedLong;
+ 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";
+ TLSSupported = false;
+ }
+
+ virtual const char *getStringSymbolPrefix(bool IsConstant) const {
+ return IsConstant ? "\01LC" : "\01lC";
+ }
+
+ virtual const char *getUnicodeStringSymbolPrefix() const {
+ return "__utf16_string_";
+ }
+
+ virtual const char *getUnicodeStringSection() const {
+ return "__TEXT,__ustring";
+ }
+
+ virtual const char *getCFStringSymbolPrefix() const {
+ return "\01LC";
+ }
+
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ X86_32TargetInfo::getTargetDefines(Opts, Defines);
+ getDarwinDefines(Defines, Opts);
+ getDarwinOSXDefines(Defines, getTargetTriple());
+ }
+
+ /// getDefaultLangOptions - Allow the target to specify default settings for
+ /// various language options. These may be overridden by command line
+ /// options.
+ virtual void getDefaultLangOptions(LangOptions &Opts) {
+ GetDarwinLanguageOptions(Opts, getTargetTriple());
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-32 FreeBSD target
+class FreeBSDX86_32TargetInfo : public X86_32TargetInfo {
+public:
+ FreeBSDX86_32TargetInfo(const std::string& triple) :
+ X86_32TargetInfo(triple) { }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ X86_32TargetInfo::getTargetDefines(Opts, Defines);
+ getFreeBSDDefines(Opts, 0, getTargetTriple(), Defines);
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-32 DragonFly target
+class DragonFlyX86_32TargetInfo : public X86_32TargetInfo {
+public:
+ DragonFlyX86_32TargetInfo(const std::string& triple) :
+ X86_32TargetInfo(triple) { }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ X86_32TargetInfo::getTargetDefines(Opts, Defines);
+ getDragonFlyDefines(Opts, Defines);
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-32 Linux target
+class LinuxX86_32TargetInfo : public X86_32TargetInfo {
+public:
+ LinuxX86_32TargetInfo(const std::string& triple) : X86_32TargetInfo(triple) {
+ UserLabelPrefix = "";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ X86_32TargetInfo::getTargetDefines(Opts, Defines);
+ getLinuxDefines(Opts, Defines);
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-32 Solaris target
+class SolarisX86_32TargetInfo : public X86_32TargetInfo {
+public:
+ SolarisX86_32TargetInfo(const std::string& triple) : X86_32TargetInfo(triple) {
+ UserLabelPrefix = "";
+ WCharType = SignedLong;
+ // FIXME: WIntType should be SignedLong
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ X86_32TargetInfo::getTargetDefines(Opts, Defines);
+ getSolarisDefines(Opts, Defines);
+ }
+};
+} // end anonymous namespace
+
+
+namespace {
+// x86-32 Windows target
+class WindowsX86_32TargetInfo : public X86_32TargetInfo {
+public:
+ WindowsX86_32TargetInfo(const std::string& triple)
+ : X86_32TargetInfo(triple) {
+ TLSSupported = false;
+ // FIXME: Fix wchar_t.
+ // FIXME: We should probably enable -fms-extensions by default for
+ // this target.
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ X86_32TargetInfo::getTargetDefines(Opts, Defines);
+ // This list is based off of the the list of things MingW defines
+ Define(Defines, "_WIN32");
+ DefineStd(Defines, "WIN32", Opts);
+ DefineStd(Defines, "WINNT", Opts);
+ Define(Defines, "_X86_");
+ Define(Defines, "__MSVCRT__");
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-64 generic target
+class X86_64TargetInfo : public X86TargetInfo {
+public:
+ X86_64TargetInfo(const std::string &triple) : X86TargetInfo(triple) {
+ LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
+ DoubleAlign = LongLongAlign = 64;
+ LongDoubleWidth = 128;
+ LongDoubleAlign = 128;
+ IntMaxType = SignedLong;
+ UIntMaxType = UnsignedLong;
+ RegParmMax = 6;
+
+ 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-f80:128:128";
+ }
+ virtual const char *getVAListDeclaration() const {
+ return "typedef struct __va_list_tag {"
+ " unsigned gp_offset;"
+ " unsigned fp_offset;"
+ " void* overflow_arg_area;"
+ " void* reg_save_area;"
+ "} __builtin_va_list[1];";
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-64 FreeBSD target
+class FreeBSDX86_64TargetInfo : public X86_64TargetInfo {
+public:
+ FreeBSDX86_64TargetInfo(const std::string &triple)
+ : X86_64TargetInfo(triple) {}
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ X86_64TargetInfo::getTargetDefines(Opts, Defines);
+ getFreeBSDDefines(Opts, 1, getTargetTriple(), Defines);
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-64 Linux target
+class LinuxX86_64TargetInfo : public X86_64TargetInfo {
+public:
+ LinuxX86_64TargetInfo(const std::string& triple) : X86_64TargetInfo(triple) {
+ UserLabelPrefix = "";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ X86_64TargetInfo::getTargetDefines(Opts, Defines);
+ getLinuxDefines(Opts, Defines);
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-64 Solaris target
+class SolarisX86_64TargetInfo : public X86_64TargetInfo {
+public:
+ SolarisX86_64TargetInfo(const std::string& triple) : X86_64TargetInfo(triple) {
+ UserLabelPrefix = "";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ X86_64TargetInfo::getTargetDefines(Opts, Defines);
+ getSolarisDefines(Opts, Defines);
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-64 Darwin (OS X) target
+class DarwinX86_64TargetInfo : public X86_64TargetInfo {
+public:
+ DarwinX86_64TargetInfo(const std::string& triple) : X86_64TargetInfo(triple) {
+ TLSSupported = false;
+ }
+
+ virtual const char *getStringSymbolPrefix(bool IsConstant) const {
+ return IsConstant ? "\01LC" : "\01lC";
+ }
+
+ virtual const char *getUnicodeStringSymbolPrefix() const {
+ return "__utf16_string_";
+ }
+
+ virtual const char *getUnicodeStringSection() const {
+ return "__TEXT,__ustring";
+ }
+
+ virtual const char *getCFStringSymbolPrefix() const {
+ return "\01L_unnamed_cfstring_";
+ }
+
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ X86_64TargetInfo::getTargetDefines(Opts, Defines);
+ getDarwinDefines(Defines, Opts);
+ getDarwinOSXDefines(Defines, getTargetTriple());
+ }
+
+ /// getDefaultLangOptions - Allow the target to specify default settings for
+ /// various language options. These may be overridden by command line
+ /// options.
+ virtual void getDefaultLangOptions(LangOptions &Opts) {
+ GetDarwinLanguageOptions(Opts, getTargetTriple());
+ }
+};
+} // end anonymous namespace.
+
+namespace {
+class ARMTargetInfo : public TargetInfo {
+ enum {
+ Armv4t,
+ Armv5,
+ Armv6,
+ XScale
+ } ArmArch;
+public:
+ ARMTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ // FIXME: Are the defaults correct for ARM?
+ 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:64";
+ if (triple.find("arm-") == 0 || triple.find("armv6-") == 0)
+ ArmArch = Armv6;
+ else if (triple.find("armv5-") == 0)
+ ArmArch = Armv5;
+ else if (triple.find("armv4t-") == 0)
+ ArmArch = Armv4t;
+ else if (triple.find("xscale-") == 0)
+ ArmArch = XScale;
+ else if (triple.find("armv") == 0) {
+ // FIXME: fuzzy match for other random weird arm triples. This is useful
+ // for the static analyzer and other clients, but probably should be
+ // re-evaluated when codegen is brought up.
+ ArmArch = Armv6;
+ }
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defs) const {
+ // Target identification.
+ Define(Defs, "__arm");
+ Define(Defs, "__arm__");
+
+ // Target properties.
+ Define(Defs, "__LITTLE_ENDIAN__");
+
+ // Subtarget options.
+ if (ArmArch == Armv6) {
+ Define(Defs, "__ARM_ARCH_6K__");
+ Define(Defs, "__THUMB_INTERWORK__");
+ } else if (ArmArch == Armv5) {
+ Define(Defs, "__ARM_ARCH_5TEJ__");
+ Define(Defs, "__THUMB_INTERWORK__");
+ Define(Defs, "__SOFTFP__");
+ } else if (ArmArch == Armv4t) {
+ Define(Defs, "__ARM_ARCH_4T__");
+ Define(Defs, "__SOFTFP__");
+ } else if (ArmArch == XScale) {
+ Define(Defs, "__ARM_ARCH_5TE__");
+ Define(Defs, "__XSCALE__");
+ Define(Defs, "__SOFTFP__");
+ }
+ Define(Defs, "__ARMEL__");
+ Define(Defs, "__APCS_32__");
+ Define(Defs, "__VFP_FP__");
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ // FIXME: Implement.
+ Records = 0;
+ NumRecords = 0;
+ }
+ virtual const char *getVAListDeclaration() const {
+ return "typedef char* __builtin_va_list;";
+ }
+ virtual const char *getTargetPrefix() const {
+ return "arm";
+ }
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ // FIXME: Implement.
+ Names = 0;
+ NumNames = 0;
+ }
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ // FIXME: Implement.
+ Aliases = 0;
+ NumAliases = 0;
+ }
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const {
+ // FIXME: Check if this is complete
+ switch (*Name) {
+ default:
+ case 'l': // r0-r7
+ case 'h': // r8-r15
+ case 'w': // VFP Floating point register single precision
+ case 'P': // VFP Floating point register double precision
+ Info.setAllowsRegister();
+ return true;
+ }
+ return false;
+ }
+ virtual const char *getClobbers() const {
+ // FIXME: Is this really right?
+ return "";
+ }
+};
+} // end anonymous namespace.
+
+
+namespace {
+class DarwinARMTargetInfo : public ARMTargetInfo {
+public:
+ DarwinARMTargetInfo(const std::string& triple) : ARMTargetInfo(triple) {
+ TLSSupported = false;
+ }
+
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ ARMTargetInfo::getTargetDefines(Opts, Defines);
+ getDarwinDefines(Defines, Opts);
+ getDarwinIPhoneOSDefines(Defines, getTargetTriple());
+ }
+};
+} // end anonymous namespace.
+
+namespace {
+// arm FreeBSD target
+class FreeBSDARMTargetInfo : public ARMTargetInfo {
+public:
+ FreeBSDARMTargetInfo(const std::string& triple) : ARMTargetInfo(triple) {}
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ ARMTargetInfo::getTargetDefines(Opts, Defines);
+ getFreeBSDDefines(Opts, 0, getTargetTriple(), Defines);
+ }
+};
+} // end anonymous namespace
+
+namespace {
+class SparcV8TargetInfo : public TargetInfo {
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+ static const char * const GCCRegNames[];
+public:
+ SparcV8TargetInfo(const std::string& triple) : TargetInfo(triple) {
+ // FIXME: Support Sparc quad-precision long double?
+ DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
+ "i64:64:64-f32:32:32-f64:64:64-v64:64:64";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ DefineStd(Defines, "sparc", Opts);
+ Define(Defines, "__sparcv8");
+ Define(Defines, "__REGISTER_PREFIX__", "");
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ // FIXME: Implement!
+ }
+ virtual const char *getVAListDeclaration() const {
+ return "typedef void* __builtin_va_list;";
+ }
+ virtual const char *getTargetPrefix() const {
+ return "sparc";
+ }
+ 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 {
+ // FIXME: Implement!
+ return false;
+ }
+ virtual const char *getClobbers() const {
+ // FIXME: Implement!
+ return "";
+ }
+};
+
+const char * const SparcV8TargetInfo::GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+};
+
+void SparcV8TargetInfo::getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+}
+
+const TargetInfo::GCCRegAlias SparcV8TargetInfo::GCCRegAliases[] = {
+ { { "g0" }, "r0" },
+ { { "g1" }, "r1" },
+ { { "g2" }, "r2" },
+ { { "g3" }, "r3" },
+ { { "g4" }, "r4" },
+ { { "g5" }, "r5" },
+ { { "g6" }, "r6" },
+ { { "g7" }, "r7" },
+ { { "o0" }, "r8" },
+ { { "o1" }, "r9" },
+ { { "o2" }, "r10" },
+ { { "o3" }, "r11" },
+ { { "o4" }, "r12" },
+ { { "o5" }, "r13" },
+ { { "o6", "sp" }, "r14" },
+ { { "o7" }, "r15" },
+ { { "l0" }, "r16" },
+ { { "l1" }, "r17" },
+ { { "l2" }, "r18" },
+ { { "l3" }, "r19" },
+ { { "l4" }, "r20" },
+ { { "l5" }, "r21" },
+ { { "l6" }, "r22" },
+ { { "l7" }, "r23" },
+ { { "i0" }, "r24" },
+ { { "i1" }, "r25" },
+ { { "i2" }, "r26" },
+ { { "i3" }, "r27" },
+ { { "i4" }, "r28" },
+ { { "i5" }, "r29" },
+ { { "i6", "fp" }, "r30" },
+ { { "i7" }, "r31" },
+};
+
+void SparcV8TargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ Aliases = GCCRegAliases;
+ NumAliases = llvm::array_lengthof(GCCRegAliases);
+}
+} // end anonymous namespace.
+
+namespace {
+class SolarisSparcV8TargetInfo : public SparcV8TargetInfo {
+public:
+ SolarisSparcV8TargetInfo(const std::string& triple) :
+ SparcV8TargetInfo(triple) {
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ WCharType = SignedLong;
+ // FIXME: WIntType should be SignedLong
+ UserLabelPrefix = "";
+ }
+
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ SparcV8TargetInfo::getTargetDefines(Opts, Defines);
+ getSolarisDefines(Opts, Defines);
+ }
+};
+} // end anonymous namespace.
+
+namespace {
+ class PIC16TargetInfo : public TargetInfo{
+ public:
+ PIC16TargetInfo(const std::string& triple) : TargetInfo(triple) {
+ TLSSupported = false;
+ IntWidth = 16;
+ LongWidth = LongLongWidth = 32;
+ IntMaxTWidth = 32;
+ PointerWidth = 16;
+ IntAlign = 8;
+ LongAlign = LongLongAlign = 8;
+ PointerAlign = 8;
+ SizeType = UnsignedInt;
+ IntMaxType = SignedLong;
+ UIntMaxType = UnsignedLong;
+ IntPtrType = SignedShort;
+ PtrDiffType = SignedInt;
+ FloatWidth = 32;
+ FloatAlign = 32;
+ DoubleWidth = 32;
+ DoubleAlign = 32;
+ LongDoubleWidth = 32;
+ LongDoubleAlign = 32;
+ FloatFormat = &llvm::APFloat::IEEEsingle;
+ DoubleFormat = &llvm::APFloat::IEEEsingle;
+ LongDoubleFormat = &llvm::APFloat::IEEEsingle;
+ DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-f32:32:32";
+
+ }
+ virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return 16; }
+ virtual uint64_t getPointerAlignV(unsigned AddrSpace) const { return 8; }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ Define(Defines, "__pic16");
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {}
+ virtual const char *getVAListDeclaration() const { return "";}
+ virtual const char *getClobbers() const {return "";}
+ virtual const char *getTargetPrefix() const {return "pic16";}
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {}
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const {
+ return true;
+ }
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {}
+ virtual bool useGlobalsForAutomaticVariables() const {return true;}
+ };
+}
+
+namespace {
+ class MSP430TargetInfo : public TargetInfo {
+ static const char * const GCCRegNames[];
+ public:
+ MSP430TargetInfo(const std::string& triple) : TargetInfo(triple) {
+ TLSSupported = false;
+ IntWidth = 16;
+ LongWidth = LongLongWidth = 32;
+ IntMaxTWidth = 32;
+ PointerWidth = 16;
+ IntAlign = 8;
+ LongAlign = LongLongAlign = 8;
+ PointerAlign = 8;
+ SizeType = UnsignedInt;
+ IntMaxType = SignedLong;
+ UIntMaxType = UnsignedLong;
+ IntPtrType = SignedShort;
+ PtrDiffType = SignedInt;
+ DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ Define(Defines, "MSP430");
+ Define(Defines, "__MSP430__");
+ // FIXME: defines for different 'flavours' of MCU
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ // FIXME: Implement.
+ Records = 0;
+ NumRecords = 0;
+ }
+ virtual const char *getTargetPrefix() const {
+ return "msp430";
+ }
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const;
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ // No aliases.
+ Aliases = 0;
+ NumAliases = 0;
+ }
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const {
+ // FIXME: implement
+ return true;
+ }
+ virtual const char *getClobbers() const {
+ // FIXME: Is this really right?
+ return "";
+ }
+ virtual const char *getVAListDeclaration() const {
+ // FIXME: implement
+ return "typedef char* __builtin_va_list;";
+ }
+ };
+
+ const char * const MSP430TargetInfo::GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+ };
+
+ void MSP430TargetInfo::getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+ }
+}
+
+
+//===----------------------------------------------------------------------===//
+// Driver code
+//===----------------------------------------------------------------------===//
+
+static inline bool IsX86(const std::string& TT) {
+ return (TT.size() >= 5 && TT[0] == 'i' && TT[2] == '8' && TT[3] == '6' &&
+ TT[4] == '-' && TT[1] - '3' < 6);
+}
+
+/// CreateTargetInfo - Return the target info object for the specified target
+/// triple.
+TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) {
+ // OS detection; this isn't really anywhere near complete.
+ // Additions and corrections are welcome.
+ bool isDarwin = T.find("-darwin") != std::string::npos;
+ bool isDragonFly = T.find("-dragonfly") != std::string::npos;
+ bool isFreeBSD = T.find("-freebsd") != std::string::npos;
+ bool isSolaris = T.find("-solaris") != std::string::npos;
+ bool isLinux = T.find("-linux") != std::string::npos;
+ bool isWindows = T.find("-windows") != std::string::npos ||
+ T.find("-win32") != std::string::npos ||
+ T.find("-mingw") != std::string::npos;
+
+ if (T.find("ppc-") == 0 || T.find("powerpc-") == 0) {
+ if (isDarwin)
+ return new DarwinPPCTargetInfo(T);
+ return new PPC32TargetInfo(T);
+ }
+
+ if (T.find("ppc64-") == 0 || T.find("powerpc64-") == 0) {
+ if (isDarwin)
+ return new DarwinPPC64TargetInfo(T);
+ return new PPC64TargetInfo(T);
+ }
+
+ if (T.find("armv") == 0 || T.find("arm-") == 0 || T.find("xscale") == 0) {
+ if (isDarwin)
+ return new DarwinARMTargetInfo(T);
+ if (isFreeBSD)
+ return new FreeBSDARMTargetInfo(T);
+ return new ARMTargetInfo(T);
+ }
+
+ if (T.find("sparc-") == 0) {
+ if (isSolaris)
+ return new SolarisSparcV8TargetInfo(T);
+ return new SparcV8TargetInfo(T);
+ }
+
+ if (T.find("x86_64-") == 0 || T.find("amd64-") == 0) {
+ if (isDarwin)
+ return new DarwinX86_64TargetInfo(T);
+ if (isLinux)
+ return new LinuxX86_64TargetInfo(T);
+ if (isFreeBSD)
+ return new FreeBSDX86_64TargetInfo(T);
+ if (isSolaris)
+ return new SolarisX86_64TargetInfo(T);
+ return new X86_64TargetInfo(T);
+ }
+
+ if (T.find("pic16-") == 0)
+ return new PIC16TargetInfo(T);
+
+ if (T.find("msp430-") == 0)
+ return new MSP430TargetInfo(T);
+
+ if (IsX86(T)) {
+ if (isDarwin)
+ return new DarwinI386TargetInfo(T);
+ if (isLinux)
+ return new LinuxX86_32TargetInfo(T);
+ if (isDragonFly)
+ return new DragonFlyX86_32TargetInfo(T);
+ if (isFreeBSD)
+ return new FreeBSDX86_32TargetInfo(T);
+ if (isSolaris)
+ return new SolarisX86_32TargetInfo(T);
+ if (isWindows)
+ return new WindowsX86_32TargetInfo(T);
+ return new X86_32TargetInfo(T);
+ }
+
+ return NULL;
+}
diff --git a/lib/Basic/TokenKinds.cpp b/lib/Basic/TokenKinds.cpp
new file mode 100644
index 000000000000..4afeaf01b776
--- /dev/null
+++ b/lib/Basic/TokenKinds.cpp
@@ -0,0 +1,90 @@
+//===--- TokenKinds.cpp - Token Kinds Support -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the TokenKind enum and support functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/TokenKinds.h"
+
+#include <cassert>
+using namespace clang;
+
+static const char * const TokNames[] = {
+#define TOK(X) #X,
+#define KEYWORD(X,Y) #X,
+#include "clang/Basic/TokenKinds.def"
+ 0
+};
+
+const char *tok::getTokenName(enum TokenKind Kind) {
+ assert(Kind < tok::NUM_TOKENS);
+ return TokNames[Kind];
+}
+
+const char *tok::getTokenSimpleSpelling(enum TokenKind Kind) {
+ switch (Kind) {
+ case tok::l_square: return "[";
+ case tok::r_square: return "]";
+ case tok::l_paren: return "(";
+ case tok::r_paren: return ")";
+ case tok::l_brace: return "{";
+ case tok::r_brace: return "}";
+ case tok::period: return ".";
+ case tok::ellipsis: return "...";
+ case tok::amp: return "&";
+ case tok::ampamp: return "&&";
+ case tok::ampequal: return "&=";
+ case tok::star: return "*";
+ case tok::starequal: return "*=";
+ case tok::plus: return "+";
+ case tok::plusplus: return "++";
+ case tok::plusequal: return "+=";
+ case tok::minus: return "-";
+ case tok::arrow: return "->";
+ case tok::minusminus: return "--";
+ case tok::minusequal: return "-=";
+ case tok::tilde: return "~";
+ case tok::exclaim: return "!";
+ case tok::exclaimequal: return "!=";
+ case tok::slash: return "/";
+ case tok::slashequal: return "/=";
+ case tok::percent: return "%";
+ case tok::percentequal: return "%=";
+ case tok::less: return "<";
+ case tok::lessless: return "<<";
+ case tok::lessequal: return "<=";
+ case tok::lesslessequal: return "<<=";
+ case tok::greater: return ">";
+ case tok::greatergreater: return ">>";
+ case tok::greaterequal: return ">=";
+ case tok::greatergreaterequal: return ">>=";
+ case tok::caret: return "^";
+ case tok::caretequal: return "^=";
+ case tok::pipe: return "|";
+ case tok::pipepipe: return "||";
+ case tok::pipeequal: return "|=";
+ case tok::question: return "?";
+ case tok::colon: return ":";
+ case tok::semi: return ";";
+ case tok::equal: return "=";
+ case tok::equalequal: return "==";
+ case tok::comma: return ",";
+ case tok::hash: return "#";
+ case tok::hashhash: return "##";
+ case tok::hashat: return "#@";
+ case tok::periodstar: return ".*";
+ case tok::arrowstar: return "->*";
+ case tok::coloncolon: return "::";
+ case tok::at: return "@";
+ default: break;
+ }
+
+ return 0;
+}
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
new file mode 100644
index 000000000000..e3da531011ee
--- /dev/null
+++ b/lib/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_subdirectory(Headers)
+add_subdirectory(Basic)
+add_subdirectory(Lex)
+add_subdirectory(Parse)
+add_subdirectory(AST)
+add_subdirectory(Sema)
+add_subdirectory(CodeGen)
+add_subdirectory(Analysis)
+add_subdirectory(Rewrite)
+add_subdirectory(Driver)
+add_subdirectory(Frontend)
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
new file mode 100644
index 000000000000..3de461242ab0
--- /dev/null
+++ b/lib/CodeGen/ABIInfo.h
@@ -0,0 +1,133 @@
+//===----- ABIInfo.h - ABI information access & encapsulation ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_ABIINFO_H
+#define CLANG_CODEGEN_ABIINFO_H
+
+namespace llvm {
+ class Type;
+}
+
+namespace clang {
+ class ASTContext;
+
+ // FIXME: This is a layering issue if we want to move ABIInfo
+ // down. Fortunately CGFunctionInfo has no real tie to CodeGen.
+ namespace CodeGen {
+ class CGFunctionInfo;
+ class CodeGenFunction;
+ }
+
+ /* FIXME: All of this stuff should be part of the target interface
+ somehow. It is currently here because it is not clear how to factor
+ the targets to support this, since the Targets currently live in a
+ layer below types n'stuff.
+ */
+
+ /// ABIArgInfo - Helper class to encapsulate information about how a
+ /// specific C type should be passed to or returned from a function.
+ class ABIArgInfo {
+ public:
+ enum Kind {
+ Direct, /// Pass the argument directly using the normal
+ /// converted LLVM type. Complex and structure types
+ /// are passed using first class aggregates.
+
+ Indirect, /// Pass the argument indirectly via a hidden pointer
+ /// with the specified alignment (0 indicates default
+ /// alignment).
+
+ Ignore, /// Ignore the argument (treat as void). Useful for
+ /// void and empty structs.
+
+ Coerce, /// Only valid for aggregate return types, the argument
+ /// should be accessed by coercion to a provided type.
+
+ Expand, /// Only valid for aggregate argument types. The
+ /// structure should be expanded into consecutive
+ /// arguments for its constituent fields. Currently
+ /// expand is only allowed on structures whose fields
+ /// are all scalar types or are themselves expandable
+ /// types.
+
+ KindFirst=Direct, KindLast=Expand
+ };
+
+ private:
+ Kind TheKind;
+ const llvm::Type *TypeData;
+ unsigned UIntData;
+
+ ABIArgInfo(Kind K, const llvm::Type *TD=0,
+ unsigned UI=0) : TheKind(K),
+ TypeData(TD),
+ UIntData(UI) {}
+ public:
+ ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {}
+
+ static ABIArgInfo getDirect() {
+ return ABIArgInfo(Direct);
+ }
+ static ABIArgInfo getIgnore() {
+ return ABIArgInfo(Ignore);
+ }
+ static ABIArgInfo getCoerce(const llvm::Type *T) {
+ return ABIArgInfo(Coerce, T);
+ }
+ static ABIArgInfo getIndirect(unsigned Alignment) {
+ return ABIArgInfo(Indirect, 0, Alignment);
+ }
+ static ABIArgInfo getExpand() {
+ return ABIArgInfo(Expand);
+ }
+
+ Kind getKind() const { return TheKind; }
+ bool isDirect() const { return TheKind == Direct; }
+ bool isIgnore() const { return TheKind == Ignore; }
+ bool isCoerce() const { return TheKind == Coerce; }
+ bool isIndirect() const { return TheKind == Indirect; }
+ bool isExpand() const { return TheKind == Expand; }
+
+ // Coerce accessors
+ const llvm::Type *getCoerceToType() const {
+ assert(TheKind == Coerce && "Invalid kind!");
+ return TypeData;
+ }
+
+ // ByVal accessors
+ unsigned getIndirectAlign() const {
+ assert(TheKind == Indirect && "Invalid kind!");
+ return UIntData;
+ }
+
+ void dump() const;
+ };
+
+ /// ABIInfo - Target specific hooks for defining how a type should be
+ /// passed or returned from functions.
+ class ABIInfo {
+ public:
+ virtual ~ABIInfo();
+
+ virtual void computeInfo(CodeGen::CGFunctionInfo &FI,
+ ASTContext &Ctx) const = 0;
+
+ /// EmitVAArg - Emit the target dependent code to load a value of
+ /// \arg Ty from the va_list pointed to by \arg VAListAddr.
+
+ // FIXME: This is a gaping layering violation if we wanted to drop
+ // the ABI information any lower than CodeGen. Of course, for
+ // VAArg handling it has to be at this level; there is no way to
+ // abstract this out.
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGen::CodeGenFunction &CGF) const = 0;
+ };
+} // end namespace clang
+
+#endif
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
new file mode 100644
index 000000000000..ead689cc01bf
--- /dev/null
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -0,0 +1,1037 @@
+//===--- CGBlocks.cpp - Emit LLVM Code for declarations -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit blocks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "clang/AST/DeclObjC.h"
+#include "llvm/Module.h"
+#include "llvm/Target/TargetData.h"
+#include <algorithm>
+using namespace clang;
+using namespace CodeGen;
+
+llvm::Constant *CodeGenFunction::
+BuildDescriptorBlockDecl(bool BlockHasCopyDispose, uint64_t Size,
+ const llvm::StructType* Ty,
+ std::vector<HelperInfo> *NoteForHelper) {
+ const llvm::Type *UnsignedLongTy
+ = CGM.getTypes().ConvertType(getContext().UnsignedLongTy);
+ llvm::Constant *C;
+ std::vector<llvm::Constant*> Elts;
+
+ // reserved
+ C = llvm::ConstantInt::get(UnsignedLongTy, 0);
+ Elts.push_back(C);
+
+ // Size
+ // FIXME: What is the right way to say this doesn't fit? We should give
+ // a user diagnostic in that case. Better fix would be to change the
+ // API to size_t.
+ C = llvm::ConstantInt::get(UnsignedLongTy, Size);
+ Elts.push_back(C);
+
+ if (BlockHasCopyDispose) {
+ // copy_func_helper_decl
+ Elts.push_back(BuildCopyHelper(Ty, NoteForHelper));
+
+ // destroy_func_decl
+ Elts.push_back(BuildDestroyHelper(Ty, NoteForHelper));
+ }
+
+ C = llvm::ConstantStruct::get(Elts);
+
+ C = new llvm::GlobalVariable(C->getType(), true,
+ llvm::GlobalValue::InternalLinkage,
+ C, "__block_descriptor_tmp", &CGM.getModule());
+ return C;
+}
+
+llvm::Constant *BlockModule::getNSConcreteGlobalBlock() {
+ if (NSConcreteGlobalBlock == 0)
+ NSConcreteGlobalBlock = CGM.CreateRuntimeVariable(PtrToInt8Ty,
+ "_NSConcreteGlobalBlock");
+ return NSConcreteGlobalBlock;
+}
+
+llvm::Constant *BlockModule::getNSConcreteStackBlock() {
+ if (NSConcreteStackBlock == 0)
+ NSConcreteStackBlock = CGM.CreateRuntimeVariable(PtrToInt8Ty,
+ "_NSConcreteStackBlock");
+ return NSConcreteStackBlock;
+}
+
+static void CollectBlockDeclRefInfo(const Stmt *S,
+ CodeGenFunction::BlockInfo &Info) {
+ for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
+ I != E; ++I)
+ if (*I)
+ CollectBlockDeclRefInfo(*I, Info);
+
+ if (const BlockDeclRefExpr *DE = dyn_cast<BlockDeclRefExpr>(S)) {
+ // FIXME: Handle enums.
+ if (isa<FunctionDecl>(DE->getDecl()))
+ return;
+
+ if (DE->isByRef())
+ Info.ByRefDeclRefs.push_back(DE);
+ else
+ Info.ByCopyDeclRefs.push_back(DE);
+ }
+}
+
+/// CanBlockBeGlobal - Given a BlockInfo struct, determines if a block can be
+/// declared as a global variable instead of on the stack.
+static bool CanBlockBeGlobal(const CodeGenFunction::BlockInfo &Info) {
+ return Info.ByRefDeclRefs.empty() && Info.ByCopyDeclRefs.empty();
+}
+
+// FIXME: Push most into CGM, passing down a few bits, like current function
+// name.
+llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
+
+ std::string Name = CurFn->getName();
+ CodeGenFunction::BlockInfo Info(0, Name.c_str());
+ CollectBlockDeclRefInfo(BE->getBody(), Info);
+
+ // Check if the block can be global.
+ // FIXME: This test doesn't work for nested blocks yet. Longer term, I'd like
+ // to just have one code path. We should move this function into CGM and pass
+ // CGF, then we can just check to see if CGF is 0.
+ if (0 && CanBlockBeGlobal(Info))
+ return CGM.GetAddrOfGlobalBlock(BE, Name.c_str());
+
+ std::vector<llvm::Constant*> Elts(5);
+ llvm::Constant *C;
+ llvm::Value *V;
+
+ {
+ // C = BuildBlockStructInitlist();
+ unsigned int flags = BLOCK_HAS_DESCRIPTOR;
+
+ // We run this first so that we set BlockHasCopyDispose from the entire
+ // block literal.
+ // __invoke
+ uint64_t subBlockSize, subBlockAlign;
+ llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
+ bool subBlockHasCopyDispose = false;
+ llvm::Function *Fn
+ = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, CurFuncDecl, LocalDeclMap,
+ subBlockSize,
+ subBlockAlign,
+ subBlockDeclRefDecls,
+ subBlockHasCopyDispose);
+ BlockHasCopyDispose |= subBlockHasCopyDispose;
+ Elts[3] = Fn;
+
+ // FIXME: Don't use BlockHasCopyDispose, it is set more often then
+ // necessary, for example: { ^{ __block int i; ^{ i = 1; }(); }(); }
+ if (subBlockHasCopyDispose)
+ flags |= BLOCK_HAS_COPY_DISPOSE;
+
+ // __isa
+ C = CGM.getNSConcreteStackBlock();
+ C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty);
+ Elts[0] = C;
+
+ // __flags
+ const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(
+ CGM.getTypes().ConvertType(CGM.getContext().IntTy));
+ C = llvm::ConstantInt::get(IntTy, flags);
+ Elts[1] = C;
+
+ // __reserved
+ C = llvm::ConstantInt::get(IntTy, 0);
+ Elts[2] = C;
+
+ if (subBlockDeclRefDecls.size() == 0) {
+ // __descriptor
+ Elts[4] = BuildDescriptorBlockDecl(subBlockHasCopyDispose, subBlockSize, 0, 0);
+
+ // Optimize to being a global block.
+ Elts[0] = CGM.getNSConcreteGlobalBlock();
+ Elts[1] = llvm::ConstantInt::get(IntTy, flags|BLOCK_IS_GLOBAL);
+
+ C = llvm::ConstantStruct::get(Elts);
+
+ char Name[32];
+ sprintf(Name, "__block_holder_tmp_%d", CGM.getGlobalUniqueCount());
+ C = new llvm::GlobalVariable(C->getType(), true,
+ llvm::GlobalValue::InternalLinkage,
+ C, Name, &CGM.getModule());
+ QualType BPT = BE->getType();
+ C = llvm::ConstantExpr::getBitCast(C, ConvertType(BPT));
+ return C;
+ }
+
+ std::vector<const llvm::Type *> Types(5+subBlockDeclRefDecls.size());
+ for (int i=0; i<4; ++i)
+ Types[i] = Elts[i]->getType();
+ Types[4] = PtrToInt8Ty;
+
+ for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) {
+ const Expr *E = subBlockDeclRefDecls[i];
+ const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
+ QualType Ty = E->getType();
+ if (BDRE && BDRE->isByRef()) {
+ uint64_t Align = getContext().getDeclAlignInBytes(BDRE->getDecl());
+ Types[i+5] = llvm::PointerType::get(BuildByRefType(Ty, Align), 0);
+ } else
+ Types[i+5] = ConvertType(Ty);
+ }
+
+ llvm::StructType *Ty = llvm::StructType::get(Types, true);
+
+ llvm::AllocaInst *A = CreateTempAlloca(Ty);
+ A->setAlignment(subBlockAlign);
+ V = A;
+
+ std::vector<HelperInfo> NoteForHelper(subBlockDeclRefDecls.size());
+ int helpersize = 0;
+
+ for (unsigned i=0; i<4; ++i)
+ Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp"));
+
+ for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i)
+ {
+ // FIXME: Push const down.
+ Expr *E = const_cast<Expr*>(subBlockDeclRefDecls[i]);
+ DeclRefExpr *DR;
+ ValueDecl *VD;
+
+ DR = dyn_cast<DeclRefExpr>(E);
+ // Skip padding.
+ if (DR) continue;
+
+ BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
+ VD = BDRE->getDecl();
+
+ llvm::Value* Addr = Builder.CreateStructGEP(V, i+5, "tmp");
+ NoteForHelper[helpersize].index = i+5;
+ NoteForHelper[helpersize].RequiresCopying = BlockRequiresCopying(VD->getType());
+ NoteForHelper[helpersize].flag
+ = VD->getType()->isBlockPointerType() ? BLOCK_FIELD_IS_BLOCK : BLOCK_FIELD_IS_OBJECT;
+
+ if (LocalDeclMap[VD]) {
+ if (BDRE->isByRef()) {
+ NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF |
+ // FIXME: Someone double check this.
+ (VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0);
+ const llvm::Type *Ty = Types[i+5];
+ llvm::Value *Loc = LocalDeclMap[VD];
+ Loc = Builder.CreateStructGEP(Loc, 1, "forwarding");
+ Loc = Builder.CreateLoad(Loc, false);
+ Loc = Builder.CreateBitCast(Loc, Ty);
+ Builder.CreateStore(Loc, Addr);
+ ++helpersize;
+ continue;
+ } else
+ E = new (getContext()) DeclRefExpr (cast<NamedDecl>(VD),
+ VD->getType(), SourceLocation(),
+ false, false);
+ }
+ if (BDRE->isByRef()) {
+ NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF |
+ // FIXME: Someone double check this.
+ (VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0);
+ E = new (getContext())
+ UnaryOperator(E, UnaryOperator::AddrOf,
+ getContext().getPointerType(E->getType()),
+ SourceLocation());
+ }
+ ++helpersize;
+
+ RValue r = EmitAnyExpr(E, Addr, false);
+ if (r.isScalar()) {
+ llvm::Value *Loc = r.getScalarVal();
+ const llvm::Type *Ty = Types[i+5];
+ if (BDRE->isByRef()) {
+ // E is now the address of the value field, instead, we want the
+ // address of the actual ByRef struct. We optimize this slightly
+ // compared to gcc by not grabbing the forwarding slot as this must
+ // be done during Block_copy for us, and we can postpone the work
+ // until then.
+ uint64_t offset = BlockDecls[BDRE->getDecl()];
+
+ llvm::Value *BlockLiteral = LoadBlockStruct();
+
+ Loc = Builder.CreateGEP(BlockLiteral,
+ llvm::ConstantInt::get(llvm::Type::Int64Ty,
+ offset),
+ "block.literal");
+ Ty = llvm::PointerType::get(Ty, 0);
+ Loc = Builder.CreateBitCast(Loc, Ty);
+ Loc = Builder.CreateLoad(Loc, false);
+ // Loc = Builder.CreateBitCast(Loc, Ty);
+ }
+ Builder.CreateStore(Loc, Addr);
+ } else if (r.isComplex())
+ // FIXME: implement
+ ErrorUnsupported(BE, "complex in block literal");
+ else if (r.isAggregate())
+ ; // Already created into the destination
+ else
+ assert (0 && "bad block variable");
+ // FIXME: Ensure that the offset created by the backend for
+ // the struct matches the previously computed offset in BlockDecls.
+ }
+ NoteForHelper.resize(helpersize);
+
+ // __descriptor
+ llvm::Value *Descriptor = BuildDescriptorBlockDecl(subBlockHasCopyDispose,
+ subBlockSize, Ty,
+ &NoteForHelper);
+ Descriptor = Builder.CreateBitCast(Descriptor, PtrToInt8Ty);
+ Builder.CreateStore(Descriptor, Builder.CreateStructGEP(V, 4, "block.tmp"));
+ }
+
+ QualType BPT = BE->getType();
+ return Builder.CreateBitCast(V, ConvertType(BPT));
+}
+
+
+const llvm::Type *BlockModule::getBlockDescriptorType() {
+ if (BlockDescriptorType)
+ return BlockDescriptorType;
+
+ const llvm::Type *UnsignedLongTy =
+ getTypes().ConvertType(getContext().UnsignedLongTy);
+
+ // struct __block_descriptor {
+ // unsigned long reserved;
+ // unsigned long block_size;
+ // };
+ BlockDescriptorType = llvm::StructType::get(UnsignedLongTy,
+ UnsignedLongTy,
+ NULL);
+
+ getModule().addTypeName("struct.__block_descriptor",
+ BlockDescriptorType);
+
+ return BlockDescriptorType;
+}
+
+const llvm::Type *BlockModule::getGenericBlockLiteralType() {
+ if (GenericBlockLiteralType)
+ return GenericBlockLiteralType;
+
+ const llvm::Type *BlockDescPtrTy =
+ llvm::PointerType::getUnqual(getBlockDescriptorType());
+
+ const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(
+ getTypes().ConvertType(getContext().IntTy));
+
+ // struct __block_literal_generic {
+ // void *__isa;
+ // int __flags;
+ // int __reserved;
+ // void (*__invoke)(void *);
+ // struct __block_descriptor *__descriptor;
+ // };
+ GenericBlockLiteralType = llvm::StructType::get(PtrToInt8Ty,
+ IntTy,
+ IntTy,
+ PtrToInt8Ty,
+ BlockDescPtrTy,
+ NULL);
+
+ getModule().addTypeName("struct.__block_literal_generic",
+ GenericBlockLiteralType);
+
+ return GenericBlockLiteralType;
+}
+
+const llvm::Type *BlockModule::getGenericExtendedBlockLiteralType() {
+ if (GenericExtendedBlockLiteralType)
+ return GenericExtendedBlockLiteralType;
+
+ const llvm::Type *BlockDescPtrTy =
+ llvm::PointerType::getUnqual(getBlockDescriptorType());
+
+ const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(
+ getTypes().ConvertType(getContext().IntTy));
+
+ // struct __block_literal_generic {
+ // void *__isa;
+ // int __flags;
+ // int __reserved;
+ // void (*__invoke)(void *);
+ // struct __block_descriptor *__descriptor;
+ // void *__copy_func_helper_decl;
+ // void *__destroy_func_decl;
+ // };
+ GenericExtendedBlockLiteralType = llvm::StructType::get(PtrToInt8Ty,
+ IntTy,
+ IntTy,
+ PtrToInt8Ty,
+ BlockDescPtrTy,
+ PtrToInt8Ty,
+ PtrToInt8Ty,
+ NULL);
+
+ getModule().addTypeName("struct.__block_literal_extended_generic",
+ GenericExtendedBlockLiteralType);
+
+ return GenericExtendedBlockLiteralType;
+}
+
+RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) {
+ const BlockPointerType *BPT =
+ E->getCallee()->getType()->getAsBlockPointerType();
+
+ llvm::Value *Callee = EmitScalarExpr(E->getCallee());
+
+ // Get a pointer to the generic block literal.
+ const llvm::Type *BlockLiteralTy =
+ llvm::PointerType::getUnqual(CGM.getGenericBlockLiteralType());
+
+ // Bitcast the callee to a block literal.
+ llvm::Value *BlockLiteral =
+ Builder.CreateBitCast(Callee, BlockLiteralTy, "block.literal");
+
+ // Get the function pointer from the literal.
+ llvm::Value *FuncPtr = Builder.CreateStructGEP(BlockLiteral, 3, "tmp");
+
+ BlockLiteral =
+ Builder.CreateBitCast(BlockLiteral,
+ llvm::PointerType::getUnqual(llvm::Type::Int8Ty),
+ "tmp");
+
+ // Add the block literal.
+ QualType VoidPtrTy = getContext().getPointerType(getContext().VoidTy);
+ CallArgList Args;
+ Args.push_back(std::make_pair(RValue::get(BlockLiteral), VoidPtrTy));
+
+ QualType FnType = BPT->getPointeeType();
+
+ // And the rest of the arguments.
+ EmitCallArgs(Args, FnType->getAsFunctionProtoType(),
+ E->arg_begin(), E->arg_end());
+
+ // Load the function.
+ llvm::Value *Func = Builder.CreateLoad(FuncPtr, false, "tmp");
+
+ QualType ResultType = FnType->getAsFunctionType()->getResultType();
+
+ const CGFunctionInfo &FnInfo =
+ CGM.getTypes().getFunctionInfo(ResultType, Args);
+
+ // Cast the function pointer to the right type.
+ const llvm::Type *BlockFTy =
+ CGM.getTypes().GetFunctionType(FnInfo, false);
+
+ const llvm::Type *BlockFTyPtr = llvm::PointerType::getUnqual(BlockFTy);
+ Func = Builder.CreateBitCast(Func, BlockFTyPtr);
+
+ // And call the block.
+ return EmitCall(FnInfo, Func, Args);
+}
+
+llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
+ uint64_t &offset = BlockDecls[E->getDecl()];
+
+ const llvm::Type *Ty;
+ Ty = CGM.getTypes().ConvertType(E->getDecl()->getType());
+
+ // See if we have already allocated an offset for this variable.
+ if (offset == 0) {
+ // Don't run the expensive check, unless we have to.
+ if (!BlockHasCopyDispose && BlockRequiresCopying(E->getType()))
+ BlockHasCopyDispose = true;
+ // if not, allocate one now.
+ offset = getBlockOffset(E);
+ }
+
+ llvm::Value *BlockLiteral = LoadBlockStruct();
+ llvm::Value *V = Builder.CreateGEP(BlockLiteral,
+ llvm::ConstantInt::get(llvm::Type::Int64Ty,
+ offset),
+ "block.literal");
+ if (E->isByRef()) {
+ bool needsCopyDispose = BlockRequiresCopying(E->getType());
+ uint64_t Align = getContext().getDeclAlignInBytes(E->getDecl());
+ const llvm::Type *PtrStructTy
+ = llvm::PointerType::get(BuildByRefType(E->getType(), Align), 0);
+ // The block literal will need a copy/destroy helper.
+ BlockHasCopyDispose = true;
+ Ty = PtrStructTy;
+ Ty = llvm::PointerType::get(Ty, 0);
+ V = Builder.CreateBitCast(V, Ty);
+ V = Builder.CreateLoad(V, false);
+ V = Builder.CreateStructGEP(V, 1, "forwarding");
+ V = Builder.CreateLoad(V, false);
+ V = Builder.CreateBitCast(V, PtrStructTy);
+ V = Builder.CreateStructGEP(V, needsCopyDispose*2 + 4, "x");
+ } else {
+ Ty = llvm::PointerType::get(Ty, 0);
+ V = Builder.CreateBitCast(V, Ty);
+ }
+ return V;
+}
+
+void CodeGenFunction::BlockForwardSelf() {
+ const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
+ ImplicitParamDecl *SelfDecl = OMD->getSelfDecl();
+ llvm::Value *&DMEntry = LocalDeclMap[SelfDecl];
+ if (DMEntry)
+ return;
+ // FIXME - Eliminate BlockDeclRefExprs, clients don't need/want to care
+ BlockDeclRefExpr *BDRE = new (getContext())
+ BlockDeclRefExpr(SelfDecl,
+ SelfDecl->getType(), SourceLocation(), false);
+ DMEntry = GetAddrOfBlockDecl(BDRE);
+}
+
+llvm::Constant *
+BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
+ // Generate the block descriptor.
+ const llvm::Type *UnsignedLongTy = Types.ConvertType(Context.UnsignedLongTy);
+ const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(
+ getTypes().ConvertType(getContext().IntTy));
+
+ llvm::Constant *DescriptorFields[2];
+
+ // Reserved
+ DescriptorFields[0] = llvm::Constant::getNullValue(UnsignedLongTy);
+
+ // Block literal size. For global blocks we just use the size of the generic
+ // block literal struct.
+ uint64_t BlockLiteralSize =
+ TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType()) / 8;
+ DescriptorFields[1] = llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize);
+
+ llvm::Constant *DescriptorStruct =
+ llvm::ConstantStruct::get(&DescriptorFields[0], 2);
+
+ llvm::GlobalVariable *Descriptor =
+ new llvm::GlobalVariable(DescriptorStruct->getType(), true,
+ llvm::GlobalVariable::InternalLinkage,
+ DescriptorStruct, "__block_descriptor_global",
+ &getModule());
+
+ // Generate the constants for the block literal.
+ llvm::Constant *LiteralFields[5];
+
+ CodeGenFunction::BlockInfo Info(0, n);
+ uint64_t subBlockSize, subBlockAlign;
+ llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
+ bool subBlockHasCopyDispose = false;
+ llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
+ llvm::Function *Fn
+ = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap,
+ subBlockSize,
+ subBlockAlign,
+ subBlockDeclRefDecls,
+ subBlockHasCopyDispose);
+ assert(subBlockSize == BlockLiteralSize
+ && "no imports allowed for global block");
+
+ // isa
+ LiteralFields[0] = getNSConcreteGlobalBlock();
+
+ // Flags
+ LiteralFields[1] =
+ llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_DESCRIPTOR);
+
+ // Reserved
+ LiteralFields[2] = llvm::Constant::getNullValue(IntTy);
+
+ // Function
+ LiteralFields[3] = Fn;
+
+ // Descriptor
+ LiteralFields[4] = Descriptor;
+
+ llvm::Constant *BlockLiteralStruct =
+ llvm::ConstantStruct::get(&LiteralFields[0], 5);
+
+ llvm::GlobalVariable *BlockLiteral =
+ new llvm::GlobalVariable(BlockLiteralStruct->getType(), true,
+ llvm::GlobalVariable::InternalLinkage,
+ BlockLiteralStruct, "__block_literal_global",
+ &getModule());
+
+ return BlockLiteral;
+}
+
+llvm::Value *CodeGenFunction::LoadBlockStruct() {
+ return Builder.CreateLoad(LocalDeclMap[getBlockStructDecl()], "self");
+}
+
+llvm::Function *
+CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
+ const BlockInfo& Info,
+ const Decl *OuterFuncDecl,
+ llvm::DenseMap<const Decl*, llvm::Value*> ldm,
+ uint64_t &Size,
+ uint64_t &Align,
+ llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls,
+ bool &subBlockHasCopyDispose) {
+
+ // Check if we should generate debug info for this block.
+ if (CGM.getDebugInfo())
+ DebugInfo = CGM.getDebugInfo();
+
+ // Arrange for local static and local extern declarations to appear
+ // to be local to this function as well, as they are directly referenced
+ // in a block.
+ for (llvm::DenseMap<const Decl *, llvm::Value*>::iterator i = ldm.begin();
+ i != ldm.end();
+ ++i) {
+ const VarDecl *VD = dyn_cast<VarDecl>(i->first);
+
+ if (VD->getStorageClass() == VarDecl::Static || VD->hasExternalStorage())
+ LocalDeclMap[VD] = i->second;
+ }
+
+ // FIXME: We need to rearrange the code for copy/dispose so we have this
+ // sooner, so we can calculate offsets correctly.
+ if (!BlockHasCopyDispose)
+ BlockOffset = CGM.getTargetData()
+ .getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8;
+ else
+ BlockOffset = CGM.getTargetData()
+ .getTypeStoreSizeInBits(CGM.getGenericExtendedBlockLiteralType()) / 8;
+ BlockAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
+
+ const FunctionType *BlockFunctionType = BExpr->getFunctionType();
+ QualType ResultType;
+ bool IsVariadic;
+ if (const FunctionProtoType *FTy =
+ dyn_cast<FunctionProtoType>(BlockFunctionType)) {
+ ResultType = FTy->getResultType();
+ IsVariadic = FTy->isVariadic();
+ }
+ else {
+ // K&R style block.
+ ResultType = BlockFunctionType->getResultType();
+ IsVariadic = false;
+ }
+
+ FunctionArgList Args;
+
+ const BlockDecl *BD = BExpr->getBlockDecl();
+
+ // FIXME: This leaks
+ ImplicitParamDecl *SelfDecl =
+ ImplicitParamDecl::Create(getContext(), 0,
+ SourceLocation(), 0,
+ getContext().getPointerType(getContext().VoidTy));
+
+ Args.push_back(std::make_pair(SelfDecl, SelfDecl->getType()));
+ BlockStructDecl = SelfDecl;
+
+ for (BlockDecl::param_const_iterator i = BD->param_begin(),
+ e = BD->param_end(); i != e; ++i)
+ Args.push_back(std::make_pair(*i, (*i)->getType()));
+
+ const CGFunctionInfo &FI =
+ CGM.getTypes().getFunctionInfo(ResultType, Args);
+
+ std::string Name = std::string("__") + Info.Name + "_block_invoke_";
+ CodeGenTypes &Types = CGM.getTypes();
+ const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic);
+
+ llvm::Function *Fn =
+ llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
+ Name,
+ &CGM.getModule());
+
+ CGM.SetInternalFunctionAttributes(BD, Fn, FI);
+
+ StartFunction(BD, ResultType, Fn, Args,
+ BExpr->getBody()->getLocEnd());
+ CurFuncDecl = OuterFuncDecl;
+ CurCodeDecl = BD;
+ EmitStmt(BExpr->getBody());
+ FinishFunction(cast<CompoundStmt>(BExpr->getBody())->getRBracLoc());
+
+ // The runtime needs a minimum alignment of a void *.
+ uint64_t MinAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
+ BlockOffset = llvm::RoundUpToAlignment(BlockOffset, MinAlign);
+
+ Size = BlockOffset;
+ Align = BlockAlign;
+ subBlockDeclRefDecls = BlockDeclRefDecls;
+ subBlockHasCopyDispose |= BlockHasCopyDispose;
+ return Fn;
+}
+
+uint64_t BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
+ const ValueDecl *D = dyn_cast<ValueDecl>(BDRE->getDecl());
+
+ uint64_t Size = getContext().getTypeSize(D->getType()) / 8;
+ uint64_t Align = getContext().getDeclAlignInBytes(D);
+
+ if (BDRE->isByRef()) {
+ Size = getContext().getTypeSize(getContext().VoidPtrTy) / 8;
+ Align = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
+ }
+
+ assert ((Align > 0) && "alignment must be 1 byte or more");
+
+ uint64_t OldOffset = BlockOffset;
+
+ // Ensure proper alignment, even if it means we have to have a gap
+ BlockOffset = llvm::RoundUpToAlignment(BlockOffset, Align);
+ BlockAlign = std::max(Align, BlockAlign);
+
+ uint64_t Pad = BlockOffset - OldOffset;
+ if (Pad) {
+ llvm::ArrayType::get(llvm::Type::Int8Ty, Pad);
+ QualType PadTy = getContext().getConstantArrayType(getContext().CharTy,
+ llvm::APInt(32, Pad),
+ ArrayType::Normal, 0);
+ ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(),
+ 0, QualType(PadTy), VarDecl::None,
+ SourceLocation());
+ Expr *E;
+ E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(),
+ SourceLocation(), false, false);
+ BlockDeclRefDecls.push_back(E);
+ }
+ BlockDeclRefDecls.push_back(BDRE);
+
+ BlockOffset += Size;
+ return BlockOffset-Size;
+}
+
+llvm::Constant *BlockFunction::
+GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T,
+ std::vector<HelperInfo> *NoteForHelperp) {
+ QualType R = getContext().VoidTy;
+
+ FunctionArgList Args;
+ // FIXME: This leaks
+ ImplicitParamDecl *Dst =
+ ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0,
+ getContext().getPointerType(getContext().VoidTy));
+ Args.push_back(std::make_pair(Dst, Dst->getType()));
+ ImplicitParamDecl *Src =
+ ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0,
+ getContext().getPointerType(getContext().VoidTy));
+ Args.push_back(std::make_pair(Src, Src->getType()));
+
+ const CGFunctionInfo &FI =
+ CGM.getTypes().getFunctionInfo(R, Args);
+
+ std::string Name = std::string("__copy_helper_block_");
+ CodeGenTypes &Types = CGM.getTypes();
+ const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
+
+ llvm::Function *Fn =
+ llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
+ Name,
+ &CGM.getModule());
+
+ IdentifierInfo *II
+ = &CGM.getContext().Idents.get("__copy_helper_block_");
+
+ FunctionDecl *FD = FunctionDecl::Create(getContext(),
+ getContext().getTranslationUnitDecl(),
+ SourceLocation(), II, R,
+ FunctionDecl::Static, false,
+ true);
+ CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
+
+ llvm::Value *SrcObj = CGF.GetAddrOfLocalVar(Src);
+ llvm::Type *PtrPtrT;
+
+ if (NoteForHelperp) {
+ std::vector<HelperInfo> &NoteForHelper = *NoteForHelperp;
+
+ PtrPtrT = llvm::PointerType::get(llvm::PointerType::get(T, 0), 0);
+ SrcObj = Builder.CreateBitCast(SrcObj, PtrPtrT);
+ SrcObj = Builder.CreateLoad(SrcObj);
+
+ llvm::Value *DstObj = CGF.GetAddrOfLocalVar(Dst);
+ llvm::Type *PtrPtrT;
+ PtrPtrT = llvm::PointerType::get(llvm::PointerType::get(T, 0), 0);
+ DstObj = Builder.CreateBitCast(DstObj, PtrPtrT);
+ DstObj = Builder.CreateLoad(DstObj);
+
+ for (unsigned i=0; i < NoteForHelper.size(); ++i) {
+ int flag = NoteForHelper[i].flag;
+ int index = NoteForHelper[i].index;
+
+ if ((NoteForHelper[i].flag & BLOCK_FIELD_IS_BYREF)
+ || NoteForHelper[i].RequiresCopying) {
+ llvm::Value *Srcv = SrcObj;
+ Srcv = Builder.CreateStructGEP(Srcv, index);
+ Srcv = Builder.CreateBitCast(Srcv,
+ llvm::PointerType::get(PtrToInt8Ty, 0));
+ Srcv = Builder.CreateLoad(Srcv);
+
+ llvm::Value *Dstv = Builder.CreateStructGEP(DstObj, index);
+ Dstv = Builder.CreateBitCast(Dstv, PtrToInt8Ty);
+
+ llvm::Value *N = llvm::ConstantInt::get(llvm::Type::Int32Ty, flag);
+ llvm::Value *F = getBlockObjectAssign();
+ Builder.CreateCall3(F, Dstv, Srcv, N);
+ }
+ }
+ }
+
+ CGF.FinishFunction();
+
+ return llvm::ConstantExpr::getBitCast(Fn, PtrToInt8Ty);
+}
+
+llvm::Constant *BlockFunction::
+GenerateDestroyHelperFunction(bool BlockHasCopyDispose,
+ const llvm::StructType* T,
+ std::vector<HelperInfo> *NoteForHelperp) {
+ QualType R = getContext().VoidTy;
+
+ FunctionArgList Args;
+ // FIXME: This leaks
+ ImplicitParamDecl *Src =
+ ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0,
+ getContext().getPointerType(getContext().VoidTy));
+
+ Args.push_back(std::make_pair(Src, Src->getType()));
+
+ const CGFunctionInfo &FI =
+ CGM.getTypes().getFunctionInfo(R, Args);
+
+ std::string Name = std::string("__destroy_helper_block_");
+ CodeGenTypes &Types = CGM.getTypes();
+ const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
+
+ llvm::Function *Fn =
+ llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
+ Name,
+ &CGM.getModule());
+
+ IdentifierInfo *II
+ = &CGM.getContext().Idents.get("__destroy_helper_block_");
+
+ FunctionDecl *FD = FunctionDecl::Create(getContext(),
+ getContext().getTranslationUnitDecl(),
+ SourceLocation(), II, R,
+ FunctionDecl::Static, false,
+ true);
+ CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
+
+ if (NoteForHelperp) {
+ std::vector<HelperInfo> &NoteForHelper = *NoteForHelperp;
+
+ llvm::Value *SrcObj = CGF.GetAddrOfLocalVar(Src);
+ llvm::Type *PtrPtrT;
+ PtrPtrT = llvm::PointerType::get(llvm::PointerType::get(T, 0), 0);
+ SrcObj = Builder.CreateBitCast(SrcObj, PtrPtrT);
+ SrcObj = Builder.CreateLoad(SrcObj);
+
+ for (unsigned i=0; i < NoteForHelper.size(); ++i) {
+ int flag = NoteForHelper[i].flag;
+ int index = NoteForHelper[i].index;
+
+ if ((NoteForHelper[i].flag & BLOCK_FIELD_IS_BYREF)
+ || NoteForHelper[i].RequiresCopying) {
+ llvm::Value *Srcv = SrcObj;
+ Srcv = Builder.CreateStructGEP(Srcv, index);
+ Srcv = Builder.CreateBitCast(Srcv,
+ llvm::PointerType::get(PtrToInt8Ty, 0));
+ Srcv = Builder.CreateLoad(Srcv);
+
+ BuildBlockRelease(Srcv, flag);
+ }
+ }
+ }
+
+ CGF.FinishFunction();
+
+ return llvm::ConstantExpr::getBitCast(Fn, PtrToInt8Ty);
+}
+
+llvm::Constant *BlockFunction::BuildCopyHelper(const llvm::StructType *T,
+ std::vector<HelperInfo> *NoteForHelper) {
+ return CodeGenFunction(CGM).GenerateCopyHelperFunction(BlockHasCopyDispose,
+ T, NoteForHelper);
+}
+
+llvm::Constant *BlockFunction::BuildDestroyHelper(const llvm::StructType *T,
+ std::vector<HelperInfo> *NoteForHelperp) {
+ return CodeGenFunction(CGM).GenerateDestroyHelperFunction(BlockHasCopyDispose,
+ T, NoteForHelperp);
+}
+
+llvm::Constant *BlockFunction::
+GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) {
+ QualType R = getContext().VoidTy;
+
+ FunctionArgList Args;
+ // FIXME: This leaks
+ ImplicitParamDecl *Dst =
+ ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0,
+ getContext().getPointerType(getContext().VoidTy));
+ Args.push_back(std::make_pair(Dst, Dst->getType()));
+
+ // FIXME: This leaks
+ ImplicitParamDecl *Src =
+ ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0,
+ getContext().getPointerType(getContext().VoidTy));
+ Args.push_back(std::make_pair(Src, Src->getType()));
+
+ const CGFunctionInfo &FI =
+ CGM.getTypes().getFunctionInfo(R, Args);
+
+ std::string Name = std::string("__Block_byref_id_object_copy_");
+ CodeGenTypes &Types = CGM.getTypes();
+ const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
+
+ llvm::Function *Fn =
+ llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
+ Name,
+ &CGM.getModule());
+
+ IdentifierInfo *II
+ = &CGM.getContext().Idents.get("__Block_byref_id_object_copy_");
+
+ FunctionDecl *FD = FunctionDecl::Create(getContext(),
+ getContext().getTranslationUnitDecl(),
+ SourceLocation(), II, R,
+ FunctionDecl::Static, false,
+ true);
+ CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
+
+ // dst->x
+ llvm::Value *V = CGF.GetAddrOfLocalVar(Dst);
+ V = Builder.CreateBitCast(V, llvm::PointerType::get(T, 0));
+ V = Builder.CreateLoad(V);
+ V = Builder.CreateStructGEP(V, 6, "x");
+ llvm::Value *DstObj = Builder.CreateBitCast(V, PtrToInt8Ty);
+
+ // src->x
+ V = CGF.GetAddrOfLocalVar(Src);
+ V = Builder.CreateLoad(V);
+ V = Builder.CreateBitCast(V, T);
+ V = Builder.CreateStructGEP(V, 6, "x");
+ V = Builder.CreateBitCast(V, llvm::PointerType::get(PtrToInt8Ty, 0));
+ llvm::Value *SrcObj = Builder.CreateLoad(V);
+
+ flag |= BLOCK_BYREF_CALLER;
+
+ llvm::Value *N = llvm::ConstantInt::get(llvm::Type::Int32Ty, flag);
+ llvm::Value *F = getBlockObjectAssign();
+ Builder.CreateCall3(F, DstObj, SrcObj, N);
+
+ CGF.FinishFunction();
+
+ return llvm::ConstantExpr::getBitCast(Fn, PtrToInt8Ty);
+}
+
+llvm::Constant *
+BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
+ int flag) {
+ QualType R = getContext().VoidTy;
+
+ FunctionArgList Args;
+ // FIXME: This leaks
+ ImplicitParamDecl *Src =
+ ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0,
+ getContext().getPointerType(getContext().VoidTy));
+
+ Args.push_back(std::make_pair(Src, Src->getType()));
+
+ const CGFunctionInfo &FI =
+ CGM.getTypes().getFunctionInfo(R, Args);
+
+ std::string Name = std::string("__Block_byref_id_object_dispose_");
+ CodeGenTypes &Types = CGM.getTypes();
+ const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
+
+ llvm::Function *Fn =
+ llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
+ Name,
+ &CGM.getModule());
+
+ IdentifierInfo *II
+ = &CGM.getContext().Idents.get("__Block_byref_id_object_dispose_");
+
+ FunctionDecl *FD = FunctionDecl::Create(getContext(),
+ getContext().getTranslationUnitDecl(),
+ SourceLocation(), II, R,
+ FunctionDecl::Static, false,
+ true);
+ CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
+
+ llvm::Value *V = CGF.GetAddrOfLocalVar(Src);
+ V = Builder.CreateBitCast(V, llvm::PointerType::get(T, 0));
+ V = Builder.CreateLoad(V);
+ V = Builder.CreateStructGEP(V, 6, "x");
+ V = Builder.CreateBitCast(V, llvm::PointerType::get(PtrToInt8Ty, 0));
+ V = Builder.CreateLoad(V);
+
+ flag |= BLOCK_BYREF_CALLER;
+ BuildBlockRelease(V, flag);
+ CGF.FinishFunction();
+
+ return llvm::ConstantExpr::getBitCast(Fn, PtrToInt8Ty);
+}
+
+llvm::Constant *BlockFunction::BuildbyrefCopyHelper(const llvm::Type *T,
+ int flag) {
+ return CodeGenFunction(CGM).GeneratebyrefCopyHelperFunction(T, flag);
+}
+
+llvm::Constant *BlockFunction::BuildbyrefDestroyHelper(const llvm::Type *T,
+ int flag) {
+ return CodeGenFunction(CGM).GeneratebyrefDestroyHelperFunction(T, flag);
+}
+
+llvm::Value *BlockFunction::getBlockObjectDispose() {
+ if (CGM.BlockObjectDispose == 0) {
+ const llvm::FunctionType *FTy;
+ std::vector<const llvm::Type*> ArgTys;
+ const llvm::Type *ResultType = llvm::Type::VoidTy;
+ ArgTys.push_back(PtrToInt8Ty);
+ ArgTys.push_back(llvm::Type::Int32Ty);
+ FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
+ CGM.BlockObjectDispose
+ = CGM.CreateRuntimeFunction(FTy, "_Block_object_dispose");
+ }
+ return CGM.BlockObjectDispose;
+}
+
+llvm::Value *BlockFunction::getBlockObjectAssign() {
+ if (CGM.BlockObjectAssign == 0) {
+ const llvm::FunctionType *FTy;
+ std::vector<const llvm::Type*> ArgTys;
+ const llvm::Type *ResultType = llvm::Type::VoidTy;
+ ArgTys.push_back(PtrToInt8Ty);
+ ArgTys.push_back(PtrToInt8Ty);
+ ArgTys.push_back(llvm::Type::Int32Ty);
+ FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
+ CGM.BlockObjectAssign
+ = CGM.CreateRuntimeFunction(FTy, "_Block_object_assign");
+ }
+ return CGM.BlockObjectAssign;
+}
+
+void BlockFunction::BuildBlockRelease(llvm::Value *V, int flag) {
+ llvm::Value *F = getBlockObjectDispose();
+ llvm::Value *N;
+ V = Builder.CreateBitCast(V, PtrToInt8Ty);
+ N = llvm::ConstantInt::get(llvm::Type::Int32Ty, flag);
+ Builder.CreateCall2(F, V, N);
+}
+
+ASTContext &BlockFunction::getContext() const { return CGM.getContext(); }
+
+BlockFunction::BlockFunction(CodeGenModule &cgm, CodeGenFunction &cgf,
+ CGBuilderTy &B)
+ : CGM(cgm), CGF(cgf), Builder(B) {
+ PtrToInt8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+
+ BlockHasCopyDispose = false;
+}
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
new file mode 100644
index 000000000000..56d3a2d3b10f
--- /dev/null
+++ b/lib/CodeGen/CGBlocks.h
@@ -0,0 +1,223 @@
+//===-- CGBlocks.h - state for LLVM CodeGen for blocks ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the internal state used for llvm translation for block literals.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CGBLOCKS_H
+#define CLANG_CODEGEN_CGBLOCKS_H
+
+#include "CodeGenTypes.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+
+#include <vector>
+#include <map>
+
+#include "CGBuilder.h"
+#include "CGCall.h"
+#include "CGValue.h"
+
+namespace llvm {
+ class Module;
+ class Constant;
+ class Function;
+ class GlobalValue;
+ class TargetData;
+ class FunctionType;
+ class Value;
+}
+
+namespace clang {
+
+namespace CodeGen {
+class CodeGenModule;
+
+class BlockBase {
+public:
+ enum {
+ BLOCK_NEEDS_FREE = (1 << 24),
+ BLOCK_HAS_COPY_DISPOSE = (1 << 25),
+ BLOCK_HAS_CXX_OBJ = (1 << 26),
+ BLOCK_IS_GC = (1 << 27),
+ BLOCK_IS_GLOBAL = (1 << 28),
+ BLOCK_HAS_DESCRIPTOR = (1 << 29)
+ };
+};
+
+class BlockModule : public BlockBase {
+ ASTContext &Context;
+ llvm::Module &TheModule;
+ const llvm::TargetData &TheTargetData;
+ CodeGenTypes &Types;
+ CodeGenModule &CGM;
+
+ ASTContext &getContext() const { return Context; }
+ llvm::Module &getModule() const { return TheModule; }
+ CodeGenTypes &getTypes() { return Types; }
+ const llvm::TargetData &getTargetData() const { return TheTargetData; }
+public:
+ llvm::Constant *getNSConcreteGlobalBlock();
+ llvm::Constant *getNSConcreteStackBlock();
+ int getGlobalUniqueCount() { return ++Block.GlobalUniqueCount; }
+ const llvm::Type *getBlockDescriptorType();
+
+ const llvm::Type *getGenericBlockLiteralType();
+ const llvm::Type *getGenericExtendedBlockLiteralType();
+
+ llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE, const char *);
+
+ /// NSConcreteGlobalBlock - Cached reference to the class pointer for global
+ /// blocks.
+ llvm::Constant *NSConcreteGlobalBlock;
+
+ /// NSConcreteStackBlock - Cached reference to the class poinnter for stack
+ /// blocks.
+ llvm::Constant *NSConcreteStackBlock;
+
+ const llvm::Type *BlockDescriptorType;
+ const llvm::Type *GenericBlockLiteralType;
+ const llvm::Type *GenericExtendedBlockLiteralType;
+ struct {
+ int GlobalUniqueCount;
+ } Block;
+
+ llvm::Value *BlockObjectAssign;
+ llvm::Value *BlockObjectDispose;
+ const llvm::Type *PtrToInt8Ty;
+
+ BlockModule(ASTContext &C, llvm::Module &M, const llvm::TargetData &TD,
+ CodeGenTypes &T, CodeGenModule &CodeGen)
+ : Context(C), TheModule(M), TheTargetData(TD), Types(T),
+ CGM(CodeGen),
+ NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), BlockDescriptorType(0),
+ GenericBlockLiteralType(0), GenericExtendedBlockLiteralType(0),
+ BlockObjectAssign(0), BlockObjectDispose(0) {
+ Block.GlobalUniqueCount = 0;
+ PtrToInt8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ }
+};
+
+class BlockFunction : public BlockBase {
+ CodeGenModule &CGM;
+ CodeGenFunction &CGF;
+ ASTContext &getContext() const;
+
+public:
+ const llvm::Type *PtrToInt8Ty;
+ struct HelperInfo {
+ int index;
+ int flag;
+ bool RequiresCopying;
+ };
+
+ enum {
+ BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)),
+ block, ... */
+ BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */
+ BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the __block
+ variable */
+ BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy
+ helpers */
+ BLOCK_BYREF_CALLER = 128 /* called from __block (byref) copy/dispose
+ support routines */
+ };
+
+ /// BlockInfo - Information to generate a block literal.
+ struct BlockInfo {
+ /// BlockLiteralTy - The type of the block literal.
+ const llvm::Type *BlockLiteralTy;
+
+ /// Name - the name of the function this block was created for, if any.
+ const char *Name;
+
+ /// ByCopyDeclRefs - Variables from parent scopes that have been imported
+ /// into this block.
+ llvm::SmallVector<const BlockDeclRefExpr *, 8> ByCopyDeclRefs;
+
+ // ByRefDeclRefs - __block variables from parent scopes that have been
+ // imported into this block.
+ llvm::SmallVector<const BlockDeclRefExpr *, 8> ByRefDeclRefs;
+
+ BlockInfo(const llvm::Type *blt, const char *n)
+ : BlockLiteralTy(blt), Name(n) {
+ // Skip asm prefix, if any.
+ if (Name && Name[0] == '\01')
+ ++Name;
+ }
+ };
+
+ CGBuilderTy &Builder;
+
+ BlockFunction(CodeGenModule &cgm, CodeGenFunction &cgf, CGBuilderTy &B);
+
+ /// BlockOffset - The offset in bytes for the next allocation of an
+ /// imported block variable.
+ uint64_t BlockOffset;
+ /// BlockAlign - Maximal alignment needed for the Block expressed in bytes.
+ uint64_t BlockAlign;
+
+ /// getBlockOffset - Allocate an offset for the ValueDecl from a
+ /// BlockDeclRefExpr in a block literal (BlockExpr).
+ uint64_t getBlockOffset(const BlockDeclRefExpr *E);
+
+ /// BlockHasCopyDispose - True iff the block uses copy/dispose.
+ bool BlockHasCopyDispose;
+
+ /// BlockDeclRefDecls - Decls from BlockDeclRefExprs in apperance order
+ /// in a block literal. Decls without names are used for padding.
+ llvm::SmallVector<const Expr *, 8> BlockDeclRefDecls;
+
+ /// BlockDecls - Offsets for all Decls in BlockDeclRefExprs.
+ std::map<const Decl*, uint64_t> BlockDecls;
+
+ ImplicitParamDecl *BlockStructDecl;
+ ImplicitParamDecl *getBlockStructDecl() { return BlockStructDecl; }
+
+ llvm::Constant *GenerateCopyHelperFunction(bool, const llvm::StructType *,
+ std::vector<HelperInfo> *);
+ llvm::Constant *GenerateDestroyHelperFunction(bool, const llvm::StructType *,
+ std::vector<HelperInfo> *);
+
+ llvm::Constant *BuildCopyHelper(const llvm::StructType *,
+ std::vector<HelperInfo> *);
+ llvm::Constant *BuildDestroyHelper(const llvm::StructType *,
+ std::vector<HelperInfo> *);
+
+ llvm::Constant *GeneratebyrefCopyHelperFunction(const llvm::Type *, int flag);
+ llvm::Constant *GeneratebyrefDestroyHelperFunction(const llvm::Type *T, int);
+
+ llvm::Constant *BuildbyrefCopyHelper(const llvm::Type *T, int flag);
+ llvm::Constant *BuildbyrefDestroyHelper(const llvm::Type *T, int flag);
+
+ llvm::Value *getBlockObjectAssign();
+ llvm::Value *getBlockObjectDispose();
+ void BuildBlockRelease(llvm::Value *DeclPtr, int flag = BLOCK_FIELD_IS_BYREF);
+
+ bool BlockRequiresCopying(QualType Ty) {
+ if (Ty->isBlockPointerType())
+ return true;
+ if (getContext().isObjCNSObjectType(Ty))
+ return true;
+ if (getContext().isObjCObjectPointerType(Ty))
+ return true;
+ return false;
+ }
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/lib/CodeGen/CGBuilder.h b/lib/CodeGen/CGBuilder.h
new file mode 100644
index 000000000000..ed56bd913779
--- /dev/null
+++ b/lib/CodeGen/CGBuilder.h
@@ -0,0 +1,26 @@
+//===-- CGBuilder.h - Choose IRBuilder implementation ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CGBUILDER_H
+#define CLANG_CODEGEN_CGBUILDER_H
+
+#include "llvm/Support/IRBuilder.h"
+
+namespace clang {
+namespace CodeGen {
+ // Don't preserve names on values in an optimized build.
+#ifdef NDEBUG
+ typedef llvm::IRBuilder<false> CGBuilderTy;
+#else
+ typedef llvm::IRBuilder<> CGBuilderTy;
+#endif
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
new file mode 100644
index 000000000000..d813bbae7f06
--- /dev/null
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -0,0 +1,1037 @@
+//===---- CGBuiltin.cpp - Emit LLVM Code for builtins ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit Builtin calls as LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/AST/APValue.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/TargetBuiltins.h"
+#include "llvm/Intrinsics.h"
+using namespace clang;
+using namespace CodeGen;
+using namespace llvm;
+
+/// 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) {
+ const llvm::Type *ResType[2];
+ ResType[0] = CGF.ConvertType(E->getType());
+ ResType[1] = CGF.ConvertType(E->getArg(0)->getType());
+ Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2);
+ return RValue::get(CGF.Builder.CreateCall2(AtomF,
+ CGF.EmitScalarExpr(E->getArg(0)),
+ CGF.EmitScalarExpr(E->getArg(1))));
+}
+
+/// Utility to insert an atomic instruction based Instrinsic::ID and
+// the expression node, where the return value is the result of the
+// operation.
+static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF,
+ Intrinsic::ID Id, const CallExpr *E,
+ Instruction::BinaryOps Op) {
+ const llvm::Type *ResType[2];
+ ResType[0] = CGF.ConvertType(E->getType());
+ ResType[1] = CGF.ConvertType(E->getArg(0)->getType());
+ Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2);
+ Value *Ptr = CGF.EmitScalarExpr(E->getArg(0));
+ Value *Operand = CGF.EmitScalarExpr(E->getArg(1));
+ Value *Result = CGF.Builder.CreateCall2(AtomF, Ptr, Operand);
+
+ if (Id == Intrinsic::atomic_load_nand)
+ Result = CGF.Builder.CreateNot(Result);
+
+
+ return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Operand));
+}
+
+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.
+ Expr::EvalResult Result;
+ if (E->Evaluate(Result, CGM.getContext())) {
+ if (Result.Val.isInt())
+ return RValue::get(llvm::ConstantInt::get(Result.Val.getInt()));
+ else if (Result.Val.isFloat())
+ return RValue::get(llvm::ConstantFP::get(Result.Val.getFloat()));
+ }
+
+ switch (BuiltinID) {
+ default: break; // Handle intrinsics and libm functions below.
+ case Builtin::BI__builtin___CFStringMakeConstantString:
+ return RValue::get(CGM.EmitConstantExpr(E, E->getType(), 0));
+ case Builtin::BI__builtin_stdarg_start:
+ case Builtin::BI__builtin_va_start:
+ case Builtin::BI__builtin_va_end: {
+ Value *ArgValue = EmitVAListRef(E->getArg(0));
+ const llvm::Type *DestType =
+ llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ if (ArgValue->getType() != DestType)
+ ArgValue = Builder.CreateBitCast(ArgValue, DestType,
+ ArgValue->getNameStart());
+
+ Intrinsic::ID inst = (BuiltinID == Builtin::BI__builtin_va_end) ?
+ Intrinsic::vaend : Intrinsic::vastart;
+ return RValue::get(Builder.CreateCall(CGM.getIntrinsic(inst), ArgValue));
+ }
+ case Builtin::BI__builtin_va_copy: {
+ Value *DstPtr = EmitVAListRef(E->getArg(0));
+ Value *SrcPtr = EmitVAListRef(E->getArg(1));
+
+ const llvm::Type *Type =
+ llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+
+ DstPtr = Builder.CreateBitCast(DstPtr, Type);
+ SrcPtr = Builder.CreateBitCast(SrcPtr, Type);
+ return RValue::get(Builder.CreateCall2(CGM.getIntrinsic(Intrinsic::vacopy),
+ DstPtr, SrcPtr));
+ }
+ case Builtin::BI__builtin_abs: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+
+ Value *NegOp = Builder.CreateNeg(ArgValue, "neg");
+ Value *CmpResult =
+ Builder.CreateICmpSGE(ArgValue, Constant::getNullValue(ArgValue->getType()),
+ "abscond");
+ Value *Result =
+ Builder.CreateSelect(CmpResult, ArgValue, NegOp, "abs");
+
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_ctz:
+ case Builtin::BI__builtin_ctzl:
+ case Builtin::BI__builtin_ctzll: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+
+ const llvm::Type *ArgType = ArgValue->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::cttz, &ArgType, 1);
+
+ const llvm::Type *ResultType = ConvertType(E->getType());
+ Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, "cast");
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_clz:
+ case Builtin::BI__builtin_clzl:
+ case Builtin::BI__builtin_clzll: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+
+ const llvm::Type *ArgType = ArgValue->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::ctlz, &ArgType, 1);
+
+ const llvm::Type *ResultType = ConvertType(E->getType());
+ Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, "cast");
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_ffs:
+ case Builtin::BI__builtin_ffsl:
+ case Builtin::BI__builtin_ffsll: {
+ // ffs(x) -> x ? cttz(x) + 1 : 0
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+
+ const llvm::Type *ArgType = ArgValue->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::cttz, &ArgType, 1);
+
+ const llvm::Type *ResultType = ConvertType(E->getType());
+ Value *Tmp = Builder.CreateAdd(Builder.CreateCall(F, ArgValue, "tmp"),
+ ConstantInt::get(ArgType, 1), "tmp");
+ Value *Zero = llvm::Constant::getNullValue(ArgType);
+ Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero, "iszero");
+ Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp, "ffs");
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, "cast");
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_parity:
+ case Builtin::BI__builtin_parityl:
+ case Builtin::BI__builtin_parityll: {
+ // parity(x) -> ctpop(x) & 1
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+
+ const llvm::Type *ArgType = ArgValue->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::ctpop, &ArgType, 1);
+
+ const llvm::Type *ResultType = ConvertType(E->getType());
+ Value *Tmp = Builder.CreateCall(F, ArgValue, "tmp");
+ Value *Result = Builder.CreateAnd(Tmp, ConstantInt::get(ArgType, 1),
+ "tmp");
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, "cast");
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_popcount:
+ case Builtin::BI__builtin_popcountl:
+ case Builtin::BI__builtin_popcountll: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+
+ const llvm::Type *ArgType = ArgValue->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::ctpop, &ArgType, 1);
+
+ const llvm::Type *ResultType = ConvertType(E->getType());
+ Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
+ if (Result->getType() != ResultType)
+ Result = Builder.CreateIntCast(Result, ResultType, "cast");
+ return RValue::get(Result);
+ }
+ case Builtin::BI__builtin_expect:
+ // FIXME: pass expect through to LLVM
+ return RValue::get(EmitScalarExpr(E->getArg(0)));
+ case Builtin::BI__builtin_bswap32:
+ case Builtin::BI__builtin_bswap64: {
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ const llvm::Type *ArgType = ArgValue->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::bswap, &ArgType, 1);
+ return RValue::get(Builder.CreateCall(F, ArgValue, "tmp"));
+ }
+ case Builtin::BI__builtin_object_size: {
+ // FIXME: Implement. For now we just always fail and pretend we
+ // don't know the object size.
+ llvm::APSInt TypeArg = E->getArg(1)->EvaluateAsInt(CGM.getContext());
+ const llvm::Type *ResType = ConvertType(E->getType());
+ // bool UseSubObject = TypeArg.getZExtValue() & 1;
+ bool UseMinimum = TypeArg.getZExtValue() & 2;
+ return RValue::get(ConstantInt::get(ResType, UseMinimum ? 0 : -1LL));
+ }
+ case Builtin::BI__builtin_prefetch: {
+ Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
+ // FIXME: Technically these constants should of type 'int', yes?
+ RW = (E->getNumArgs() > 1) ? EmitScalarExpr(E->getArg(1)) :
+ ConstantInt::get(llvm::Type::Int32Ty, 0);
+ Locality = (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) :
+ ConstantInt::get(llvm::Type::Int32Ty, 3);
+ Value *F = CGM.getIntrinsic(Intrinsic::prefetch, 0, 0);
+ return RValue::get(Builder.CreateCall3(F, Address, RW, Locality));
+ }
+ case Builtin::BI__builtin_trap: {
+ Value *F = CGM.getIntrinsic(Intrinsic::trap, 0, 0);
+ return RValue::get(Builder.CreateCall(F));
+ }
+
+ case Builtin::BI__builtin_powi:
+ case Builtin::BI__builtin_powif:
+ case Builtin::BI__builtin_powil: {
+ Value *Base = EmitScalarExpr(E->getArg(0));
+ Value *Exponent = EmitScalarExpr(E->getArg(1));
+ const llvm::Type *ArgType = Base->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::powi, &ArgType, 1);
+ return RValue::get(Builder.CreateCall2(F, Base, Exponent, "tmp"));
+ }
+
+ case Builtin::BI__builtin_isgreater:
+ case Builtin::BI__builtin_isgreaterequal:
+ case Builtin::BI__builtin_isless:
+ case Builtin::BI__builtin_islessequal:
+ case Builtin::BI__builtin_islessgreater:
+ case Builtin::BI__builtin_isunordered: {
+ // Ordered comparisons: we know the arguments to these are matching scalar
+ // floating point values.
+ Value *LHS = EmitScalarExpr(E->getArg(0));
+ Value *RHS = EmitScalarExpr(E->getArg(1));
+
+ switch (BuiltinID) {
+ default: assert(0 && "Unknown ordered comparison");
+ case Builtin::BI__builtin_isgreater:
+ LHS = Builder.CreateFCmpOGT(LHS, RHS, "cmp");
+ break;
+ case Builtin::BI__builtin_isgreaterequal:
+ LHS = Builder.CreateFCmpOGE(LHS, RHS, "cmp");
+ break;
+ case Builtin::BI__builtin_isless:
+ LHS = Builder.CreateFCmpOLT(LHS, RHS, "cmp");
+ break;
+ case Builtin::BI__builtin_islessequal:
+ LHS = Builder.CreateFCmpOLE(LHS, RHS, "cmp");
+ break;
+ case Builtin::BI__builtin_islessgreater:
+ LHS = Builder.CreateFCmpONE(LHS, RHS, "cmp");
+ break;
+ case Builtin::BI__builtin_isunordered:
+ LHS = Builder.CreateFCmpUNO(LHS, RHS, "cmp");
+ break;
+ }
+ // ZExt bool to int type.
+ return RValue::get(Builder.CreateZExt(LHS, ConvertType(E->getType()),
+ "tmp"));
+ }
+ case Builtin::BIalloca:
+ case Builtin::BI__builtin_alloca: {
+ // FIXME: LLVM IR Should allow alloca with an i64 size!
+ Value *Size = EmitScalarExpr(E->getArg(0));
+ Size = Builder.CreateIntCast(Size, llvm::Type::Int32Ty, false, "tmp");
+ return RValue::get(Builder.CreateAlloca(llvm::Type::Int8Ty, Size, "tmp"));
+ }
+ case Builtin::BI__builtin_bzero: {
+ Value *Address = EmitScalarExpr(E->getArg(0));
+ Builder.CreateCall4(CGM.getMemSetFn(), Address,
+ llvm::ConstantInt::get(llvm::Type::Int8Ty, 0),
+ EmitScalarExpr(E->getArg(1)),
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, 1));
+ return RValue::get(Address);
+ }
+ case Builtin::BI__builtin_memcpy: {
+ Value *Address = EmitScalarExpr(E->getArg(0));
+ Builder.CreateCall4(CGM.getMemCpyFn(), Address,
+ EmitScalarExpr(E->getArg(1)),
+ EmitScalarExpr(E->getArg(2)),
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, 1));
+ return RValue::get(Address);
+ }
+ case Builtin::BI__builtin_memmove: {
+ Value *Address = EmitScalarExpr(E->getArg(0));
+ Builder.CreateCall4(CGM.getMemMoveFn(), Address,
+ EmitScalarExpr(E->getArg(1)),
+ EmitScalarExpr(E->getArg(2)),
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, 1));
+ return RValue::get(Address);
+ }
+ case Builtin::BI__builtin_memset: {
+ Value *Address = EmitScalarExpr(E->getArg(0));
+ Builder.CreateCall4(CGM.getMemSetFn(), Address,
+ Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)),
+ llvm::Type::Int8Ty),
+ EmitScalarExpr(E->getArg(2)),
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, 1));
+ return RValue::get(Address);
+ }
+ case Builtin::BI__builtin_return_address: {
+ Value *F = CGM.getIntrinsic(Intrinsic::returnaddress, 0, 0);
+ return RValue::get(Builder.CreateCall(F, EmitScalarExpr(E->getArg(0))));
+ }
+ case Builtin::BI__builtin_frame_address: {
+ Value *F = CGM.getIntrinsic(Intrinsic::frameaddress, 0, 0);
+ return RValue::get(Builder.CreateCall(F, EmitScalarExpr(E->getArg(0))));
+ }
+ case Builtin::BI__builtin_extract_return_addr: {
+ // FIXME: There should be a target hook for this
+ return RValue::get(EmitScalarExpr(E->getArg(0)));
+ }
+ case Builtin::BI__builtin_unwind_init: {
+ Value *F = CGM.getIntrinsic(Intrinsic::eh_unwind_init, 0, 0);
+ return RValue::get(Builder.CreateCall(F));
+ }
+#if 0
+ // FIXME: Finish/enable when LLVM backend support stabilizes
+ case Builtin::BI__builtin_setjmp: {
+ Value *Buf = EmitScalarExpr(E->getArg(0));
+ // Store the frame pointer to the buffer
+ Value *FrameAddrF = CGM.getIntrinsic(Intrinsic::frameaddress, 0, 0);
+ Value *FrameAddr =
+ Builder.CreateCall(FrameAddrF,
+ Constant::getNullValue(llvm::Type::Int32Ty));
+ Builder.CreateStore(FrameAddr, Buf);
+ // Call the setjmp intrinsic
+ Value *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_setjmp, 0, 0);
+ const llvm::Type *DestType =
+ llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ Buf = Builder.CreateBitCast(Buf, DestType);
+ return RValue::get(Builder.CreateCall(F, Buf));
+ }
+ case Builtin::BI__builtin_longjmp: {
+ Value *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_longjmp, 0, 0);
+ Value *Buf = EmitScalarExpr(E->getArg(0));
+ const llvm::Type *DestType =
+ llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ Buf = Builder.CreateBitCast(Buf, DestType);
+ return RValue::get(Builder.CreateCall(F, Buf));
+ }
+#endif
+ case Builtin::BI__sync_fetch_and_add:
+ case Builtin::BI__sync_fetch_and_sub:
+ case Builtin::BI__sync_fetch_and_or:
+ case Builtin::BI__sync_fetch_and_and:
+ case Builtin::BI__sync_fetch_and_xor:
+ case Builtin::BI__sync_add_and_fetch:
+ case Builtin::BI__sync_sub_and_fetch:
+ case Builtin::BI__sync_and_and_fetch:
+ case Builtin::BI__sync_or_and_fetch:
+ case Builtin::BI__sync_xor_and_fetch:
+ case Builtin::BI__sync_val_compare_and_swap:
+ case Builtin::BI__sync_bool_compare_and_swap:
+ case Builtin::BI__sync_lock_test_and_set:
+ case Builtin::BI__sync_lock_release:
+ assert(0 && "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);
+ 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);
+ 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);
+ 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);
+ 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);
+ case Builtin::BI__sync_fetch_and_nand_1:
+ case Builtin::BI__sync_fetch_and_nand_2:
+ case Builtin::BI__sync_fetch_and_nand_4:
+ case Builtin::BI__sync_fetch_and_nand_8:
+ case Builtin::BI__sync_fetch_and_nand_16:
+ return EmitBinaryAtomic(*this, Intrinsic::atomic_load_nand, E);
+
+ // Clang extensions: not overloaded yet.
+ case Builtin::BI__sync_fetch_and_min:
+ return EmitBinaryAtomic(*this, Intrinsic::atomic_load_min, E);
+ case Builtin::BI__sync_fetch_and_max:
+ return EmitBinaryAtomic(*this, Intrinsic::atomic_load_max, E);
+ case Builtin::BI__sync_fetch_and_umin:
+ return EmitBinaryAtomic(*this, Intrinsic::atomic_load_umin, E);
+ case Builtin::BI__sync_fetch_and_umax:
+ return EmitBinaryAtomic(*this, Intrinsic::atomic_load_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,
+ 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,
+ 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,
+ 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,
+ 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,
+ llvm::Instruction::Xor);
+ case Builtin::BI__sync_nand_and_fetch_1:
+ case Builtin::BI__sync_nand_and_fetch_2:
+ case Builtin::BI__sync_nand_and_fetch_4:
+ case Builtin::BI__sync_nand_and_fetch_8:
+ case Builtin::BI__sync_nand_and_fetch_16:
+ return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_nand, E,
+ llvm::Instruction::And);
+
+ case Builtin::BI__sync_val_compare_and_swap_1:
+ case Builtin::BI__sync_val_compare_and_swap_2:
+ case Builtin::BI__sync_val_compare_and_swap_4:
+ case Builtin::BI__sync_val_compare_and_swap_8:
+ case Builtin::BI__sync_val_compare_and_swap_16:
+ {
+ const llvm::Type *ResType[2];
+ ResType[0]= ConvertType(E->getType());
+ ResType[1] = ConvertType(E->getArg(0)->getType());
+ Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2);
+ return RValue::get(Builder.CreateCall3(AtomF,
+ EmitScalarExpr(E->getArg(0)),
+ EmitScalarExpr(E->getArg(1)),
+ EmitScalarExpr(E->getArg(2))));
+ }
+
+ case Builtin::BI__sync_bool_compare_and_swap_1:
+ case Builtin::BI__sync_bool_compare_and_swap_2:
+ case Builtin::BI__sync_bool_compare_and_swap_4:
+ case Builtin::BI__sync_bool_compare_and_swap_8:
+ case Builtin::BI__sync_bool_compare_and_swap_16:
+ {
+ const llvm::Type *ResType[2];
+ ResType[0]= ConvertType(E->getArg(1)->getType());
+ ResType[1] = llvm::PointerType::getUnqual(ResType[0]);
+ Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2);
+ Value *OldVal = EmitScalarExpr(E->getArg(1));
+ Value *PrevVal = Builder.CreateCall3(AtomF,
+ EmitScalarExpr(E->getArg(0)),
+ OldVal,
+ EmitScalarExpr(E->getArg(2)));
+ Value *Result = Builder.CreateICmpEQ(PrevVal, OldVal);
+ // zext bool to int.
+ return RValue::get(Builder.CreateZExt(Result, ConvertType(E->getType())));
+ }
+
+ 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);
+ case Builtin::BI__sync_lock_release_1:
+ case Builtin::BI__sync_lock_release_2:
+ case Builtin::BI__sync_lock_release_4:
+ case Builtin::BI__sync_lock_release_8:
+ case Builtin::BI__sync_lock_release_16: {
+ Value *Ptr = EmitScalarExpr(E->getArg(0));
+ const llvm::Type *ElTy =
+ cast<llvm::PointerType>(Ptr->getType())->getElementType();
+ Builder.CreateStore(llvm::Constant::getNullValue(ElTy), Ptr, true);
+ return RValue::get(0);
+ }
+
+ case Builtin::BI__sync_synchronize: {
+ Value *C[5];
+ C[0] = C[1] = C[2] = C[3] = llvm::ConstantInt::get(llvm::Type::Int1Ty, 1);
+ C[4] = ConstantInt::get(llvm::Type::Int1Ty, 0);
+ Builder.CreateCall(CGM.getIntrinsic(Intrinsic::memory_barrier), C, C + 5);
+ return RValue::get(0);
+ }
+
+ // Library functions with special handling.
+ case Builtin::BIsqrt:
+ case Builtin::BIsqrtf:
+ case Builtin::BIsqrtl: {
+ // Rewrite sqrt to intrinsic if allowed.
+ if (!FD->hasAttr<ConstAttr>())
+ break;
+ Value *Arg0 = EmitScalarExpr(E->getArg(0));
+ const llvm::Type *ArgType = Arg0->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::sqrt, &ArgType, 1);
+ return RValue::get(Builder.CreateCall(F, Arg0, "tmp"));
+ }
+
+ case Builtin::BIpow:
+ case Builtin::BIpowf:
+ case Builtin::BIpowl: {
+ // Rewrite sqrt to intrinsic if allowed.
+ if (!FD->hasAttr<ConstAttr>())
+ break;
+ Value *Base = EmitScalarExpr(E->getArg(0));
+ Value *Exponent = EmitScalarExpr(E->getArg(1));
+ const llvm::Type *ArgType = Base->getType();
+ Value *F = CGM.getIntrinsic(Intrinsic::pow, &ArgType, 1);
+ return RValue::get(Builder.CreateCall2(F, Base, Exponent, "tmp"));
+ }
+ }
+
+ // 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(CGM.getBuiltinLibFunction(BuiltinID),
+ E->getCallee()->getType(), E->arg_begin(),
+ E->arg_end());
+
+ // See if we have a target specific intrinsic.
+ const char *Name = getContext().BuiltinInfo.GetName(BuiltinID);
+ Intrinsic::ID IntrinsicID =
+ Intrinsic::getIntrinsicForGCCBuiltin(Target.getTargetPrefix(), Name);
+
+ if (IntrinsicID != Intrinsic::not_intrinsic) {
+ SmallVector<Value*, 16> Args;
+
+ Function *F = CGM.getIntrinsic(IntrinsicID);
+ const llvm::FunctionType *FTy = F->getFunctionType();
+
+ for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
+ Value *ArgValue = EmitScalarExpr(E->getArg(i));
+
+ // 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);
+ if (PTy != ArgValue->getType()) {
+ assert(PTy->canLosslesslyBitCastTo(FTy->getParamType(i)) &&
+ "Must be able to losslessly bit cast to param");
+ ArgValue = Builder.CreateBitCast(ArgValue, PTy);
+ }
+
+ Args.push_back(ArgValue);
+ }
+
+ Value *V = Builder.CreateCall(F, Args.data(), Args.data() + Args.size());
+ QualType BuiltinRetType = E->getType();
+
+ const llvm::Type *RetTy = llvm::Type::VoidTy;
+ if (!BuiltinRetType->isVoidType()) RetTy = ConvertType(BuiltinRetType);
+
+ if (RetTy != V->getType()) {
+ assert(V->getType()->canLosslesslyBitCastTo(RetTy) &&
+ "Must be able to losslessly bit cast result type");
+ V = Builder.CreateBitCast(V, RetTy);
+ }
+
+ return RValue::get(V);
+ }
+
+ // See if we have a target specific builtin that needs to be lowered.
+ if (Value *V = EmitTargetBuiltinExpr(BuiltinID, E))
+ return RValue::get(V);
+
+ ErrorUnsupported(E, "builtin function");
+
+ // Unknown builtin, for now just dump it out and return undef.
+ if (hasAggregateLLVMType(E->getType()))
+ return RValue::getAggregate(CreateTempAlloca(ConvertType(E->getType())));
+ return RValue::get(UndefValue::get(ConvertType(E->getType())));
+}
+
+Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
+ const CallExpr *E) {
+ const char *TargetPrefix = Target.getTargetPrefix();
+ if (strcmp(TargetPrefix, "x86") == 0)
+ return EmitX86BuiltinExpr(BuiltinID, E);
+ else if (strcmp(TargetPrefix, "ppc") == 0)
+ return EmitPPCBuiltinExpr(BuiltinID, E);
+ return 0;
+}
+
+Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
+ const CallExpr *E) {
+
+ llvm::SmallVector<Value*, 4> Ops;
+
+ for (unsigned i = 0, e = E->getNumArgs(); i != e; i++)
+ Ops.push_back(EmitScalarExpr(E->getArg(i)));
+
+ switch (BuiltinID) {
+ default: return 0;
+ case X86::BI__builtin_ia32_mulps:
+ return Builder.CreateMul(Ops[0], Ops[1], "mulps");
+ case X86::BI__builtin_ia32_mulpd:
+ return Builder.CreateMul(Ops[0], Ops[1], "mulpd");
+ case X86::BI__builtin_ia32_pand:
+ case X86::BI__builtin_ia32_pand128:
+ return Builder.CreateAnd(Ops[0], Ops[1], "pand");
+ case X86::BI__builtin_ia32_por:
+ case X86::BI__builtin_ia32_por128:
+ return Builder.CreateOr(Ops[0], Ops[1], "por");
+ case X86::BI__builtin_ia32_pxor:
+ case X86::BI__builtin_ia32_pxor128:
+ return Builder.CreateXor(Ops[0], Ops[1], "pxor");
+ case X86::BI__builtin_ia32_pandn:
+ case X86::BI__builtin_ia32_pandn128:
+ Ops[0] = Builder.CreateNot(Ops[0], "tmp");
+ return Builder.CreateAnd(Ops[0], Ops[1], "pandn");
+ case X86::BI__builtin_ia32_paddb:
+ case X86::BI__builtin_ia32_paddb128:
+ case X86::BI__builtin_ia32_paddd:
+ case X86::BI__builtin_ia32_paddd128:
+ case X86::BI__builtin_ia32_paddq:
+ case X86::BI__builtin_ia32_paddq128:
+ case X86::BI__builtin_ia32_paddw:
+ case X86::BI__builtin_ia32_paddw128:
+ case X86::BI__builtin_ia32_addps:
+ case X86::BI__builtin_ia32_addpd:
+ return Builder.CreateAdd(Ops[0], Ops[1], "add");
+ case X86::BI__builtin_ia32_psubb:
+ case X86::BI__builtin_ia32_psubb128:
+ case X86::BI__builtin_ia32_psubd:
+ case X86::BI__builtin_ia32_psubd128:
+ case X86::BI__builtin_ia32_psubq:
+ case X86::BI__builtin_ia32_psubq128:
+ case X86::BI__builtin_ia32_psubw:
+ case X86::BI__builtin_ia32_psubw128:
+ case X86::BI__builtin_ia32_subps:
+ case X86::BI__builtin_ia32_subpd:
+ return Builder.CreateSub(Ops[0], Ops[1], "sub");
+ case X86::BI__builtin_ia32_divps:
+ return Builder.CreateFDiv(Ops[0], Ops[1], "divps");
+ case X86::BI__builtin_ia32_divpd:
+ return Builder.CreateFDiv(Ops[0], Ops[1], "divpd");
+ case X86::BI__builtin_ia32_pmullw:
+ case X86::BI__builtin_ia32_pmullw128:
+ return Builder.CreateMul(Ops[0], Ops[1], "pmul");
+ case X86::BI__builtin_ia32_punpckhbw:
+ return EmitShuffleVector(Ops[0], Ops[1], 4, 12, 5, 13, 6, 14, 7, 15,
+ "punpckhbw");
+ case X86::BI__builtin_ia32_punpckhbw128:
+ return EmitShuffleVector(Ops[0], Ops[1], 8, 24, 9, 25, 10, 26, 11, 27,
+ 12, 28, 13, 29, 14, 30, 15, 31,
+ "punpckhbw");
+ case X86::BI__builtin_ia32_punpckhwd:
+ return EmitShuffleVector(Ops[0], Ops[1], 2, 6, 3, 7, "punpckhwd");
+ case X86::BI__builtin_ia32_punpckhwd128:
+ return EmitShuffleVector(Ops[0], Ops[1], 4, 12, 5, 13, 6, 14, 7, 15,
+ "punpckhwd");
+ case X86::BI__builtin_ia32_punpckhdq:
+ return EmitShuffleVector(Ops[0], Ops[1], 1, 3, "punpckhdq");
+ case X86::BI__builtin_ia32_punpckhdq128:
+ return EmitShuffleVector(Ops[0], Ops[1], 2, 6, 3, 7, "punpckhdq");
+ case X86::BI__builtin_ia32_punpckhqdq128:
+ return EmitShuffleVector(Ops[0], Ops[1], 1, 3, "punpckhqdq");
+ case X86::BI__builtin_ia32_punpcklbw:
+ return EmitShuffleVector(Ops[0], Ops[1], 0, 8, 1, 9, 2, 10, 3, 11,
+ "punpcklbw");
+ case X86::BI__builtin_ia32_punpcklwd:
+ return EmitShuffleVector(Ops[0], Ops[1], 0, 4, 1, 5, "punpcklwd");
+ case X86::BI__builtin_ia32_punpckldq:
+ return EmitShuffleVector(Ops[0], Ops[1], 0, 2, "punpckldq");
+ case X86::BI__builtin_ia32_punpckldq128:
+ return EmitShuffleVector(Ops[0], Ops[1], 0, 4, 1, 5, "punpckldq");
+ case X86::BI__builtin_ia32_punpcklqdq128:
+ return EmitShuffleVector(Ops[0], Ops[1], 0, 2, "punpcklqdq");
+ case X86::BI__builtin_ia32_pslldi128:
+ case X86::BI__builtin_ia32_psllqi128:
+ case X86::BI__builtin_ia32_psllwi128:
+ case X86::BI__builtin_ia32_psradi128:
+ case X86::BI__builtin_ia32_psrawi128:
+ case X86::BI__builtin_ia32_psrldi128:
+ case X86::BI__builtin_ia32_psrlqi128:
+ case X86::BI__builtin_ia32_psrlwi128: {
+ Ops[1] = Builder.CreateZExt(Ops[1], llvm::Type::Int64Ty, "zext");
+ const llvm::Type *Ty = llvm::VectorType::get(llvm::Type::Int64Ty, 2);
+ llvm::Value *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
+ Ops[1] = Builder.CreateInsertElement(llvm::UndefValue::get(Ty),
+ Ops[1], Zero, "insert");
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ops[0]->getType(), "bitcast");
+ const char *name = 0;
+ Intrinsic::ID ID = Intrinsic::not_intrinsic;
+
+ switch (BuiltinID) {
+ default: assert(0 && "Unsupported shift intrinsic!");
+ case X86::BI__builtin_ia32_pslldi128:
+ name = "pslldi";
+ ID = Intrinsic::x86_sse2_psll_d;
+ break;
+ case X86::BI__builtin_ia32_psllqi128:
+ name = "psllqi";
+ ID = Intrinsic::x86_sse2_psll_q;
+ break;
+ case X86::BI__builtin_ia32_psllwi128:
+ name = "psllwi";
+ ID = Intrinsic::x86_sse2_psll_w;
+ break;
+ case X86::BI__builtin_ia32_psradi128:
+ name = "psradi";
+ ID = Intrinsic::x86_sse2_psra_d;
+ break;
+ case X86::BI__builtin_ia32_psrawi128:
+ name = "psrawi";
+ ID = Intrinsic::x86_sse2_psra_w;
+ break;
+ case X86::BI__builtin_ia32_psrldi128:
+ name = "psrldi";
+ ID = Intrinsic::x86_sse2_psrl_d;
+ break;
+ case X86::BI__builtin_ia32_psrlqi128:
+ name = "psrlqi";
+ ID = Intrinsic::x86_sse2_psrl_q;
+ break;
+ case X86::BI__builtin_ia32_psrlwi128:
+ name = "psrlwi";
+ ID = Intrinsic::x86_sse2_psrl_w;
+ break;
+ }
+ llvm::Function *F = CGM.getIntrinsic(ID);
+ return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
+ }
+ case X86::BI__builtin_ia32_pslldi:
+ case X86::BI__builtin_ia32_psllqi:
+ case X86::BI__builtin_ia32_psllwi:
+ case X86::BI__builtin_ia32_psradi:
+ case X86::BI__builtin_ia32_psrawi:
+ case X86::BI__builtin_ia32_psrldi:
+ case X86::BI__builtin_ia32_psrlqi:
+ case X86::BI__builtin_ia32_psrlwi: {
+ Ops[1] = Builder.CreateZExt(Ops[1], llvm::Type::Int64Ty, "zext");
+ const llvm::Type *Ty = llvm::VectorType::get(llvm::Type::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!");
+ case X86::BI__builtin_ia32_pslldi:
+ name = "pslldi";
+ ID = Intrinsic::x86_mmx_psll_d;
+ break;
+ case X86::BI__builtin_ia32_psllqi:
+ name = "psllqi";
+ ID = Intrinsic::x86_mmx_psll_q;
+ break;
+ case X86::BI__builtin_ia32_psllwi:
+ name = "psllwi";
+ ID = Intrinsic::x86_mmx_psll_w;
+ break;
+ case X86::BI__builtin_ia32_psradi:
+ name = "psradi";
+ ID = Intrinsic::x86_mmx_psra_d;
+ break;
+ case X86::BI__builtin_ia32_psrawi:
+ name = "psrawi";
+ ID = Intrinsic::x86_mmx_psra_w;
+ break;
+ case X86::BI__builtin_ia32_psrldi:
+ name = "psrldi";
+ ID = Intrinsic::x86_mmx_psrl_d;
+ break;
+ case X86::BI__builtin_ia32_psrlqi:
+ name = "psrlqi";
+ ID = Intrinsic::x86_mmx_psrl_q;
+ break;
+ case X86::BI__builtin_ia32_psrlwi:
+ name = "psrlwi";
+ ID = Intrinsic::x86_mmx_psrl_w;
+ break;
+ }
+ llvm::Function *F = CGM.getIntrinsic(ID);
+ return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
+ }
+ case X86::BI__builtin_ia32_pshufw: {
+ unsigned i = cast<ConstantInt>(Ops[1])->getZExtValue();
+ return EmitShuffleVector(Ops[0], Ops[0],
+ i & 0x3, (i & 0xc) >> 2,
+ (i & 0x30) >> 4, (i & 0xc0) >> 6,
+ "pshufw");
+ }
+ case X86::BI__builtin_ia32_pshuflw: {
+ unsigned i = cast<ConstantInt>(Ops[1])->getZExtValue();
+ return EmitShuffleVector(Ops[0], Ops[0],
+ i & 0x3, (i & 0xc) >> 2,
+ (i & 0x30) >> 4, (i & 0xc0) >> 6, 4, 5, 6, 7,
+ "pshuflw");
+ }
+ case X86::BI__builtin_ia32_pshufhw: {
+ unsigned i = cast<ConstantInt>(Ops[1])->getZExtValue();
+ return EmitShuffleVector(Ops[0], Ops[0], 0, 1, 2, 3,
+ 4 + (i & 0x3), 4 + ((i & 0xc) >> 2),
+ 4 + ((i & 0x30) >> 4), 4 + ((i & 0xc0) >> 6),
+ "pshufhw");
+ }
+ case X86::BI__builtin_ia32_pshufd: {
+ unsigned i = cast<ConstantInt>(Ops[1])->getZExtValue();
+ return EmitShuffleVector(Ops[0], Ops[0],
+ i & 0x3, (i & 0xc) >> 2,
+ (i & 0x30) >> 4, (i & 0xc0) >> 6,
+ "pshufd");
+ }
+ case X86::BI__builtin_ia32_vec_init_v4hi:
+ case X86::BI__builtin_ia32_vec_init_v8qi:
+ case X86::BI__builtin_ia32_vec_init_v2si:
+ return EmitVector(&Ops[0], Ops.size());
+ case X86::BI__builtin_ia32_vec_ext_v2si:
+ case X86::BI__builtin_ia32_vec_ext_v2di:
+ case X86::BI__builtin_ia32_vec_ext_v4sf:
+ case X86::BI__builtin_ia32_vec_ext_v4si:
+ case X86::BI__builtin_ia32_vec_ext_v8hi:
+ case X86::BI__builtin_ia32_vec_ext_v4hi:
+ case X86::BI__builtin_ia32_vec_ext_v2df:
+ return Builder.CreateExtractElement(Ops[0], Ops[1], "result");
+ case X86::BI__builtin_ia32_cmpps: {
+ llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ps);
+ return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "cmpps");
+ }
+ case X86::BI__builtin_ia32_cmpss: {
+ llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ss);
+ return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "cmpss");
+ }
+ case X86::BI__builtin_ia32_ldmxcsr: {
+ llvm::Type *PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ Value *One = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1);
+ Value *Tmp = Builder.CreateAlloca(llvm::Type::Int32Ty, One, "tmp");
+ Builder.CreateStore(Ops[0], Tmp);
+ return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_ldmxcsr),
+ Builder.CreateBitCast(Tmp, PtrTy));
+ }
+ case X86::BI__builtin_ia32_stmxcsr: {
+ llvm::Type *PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ Value *One = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1);
+ Value *Tmp = Builder.CreateAlloca(llvm::Type::Int32Ty, One, "tmp");
+ One = Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_stmxcsr),
+ Builder.CreateBitCast(Tmp, PtrTy));
+ return Builder.CreateLoad(Tmp, "stmxcsr");
+ }
+ case X86::BI__builtin_ia32_cmppd: {
+ llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_cmp_pd);
+ return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "cmppd");
+ }
+ case X86::BI__builtin_ia32_cmpsd: {
+ llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_cmp_sd);
+ return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "cmpsd");
+ }
+ case X86::BI__builtin_ia32_movss:
+ return EmitShuffleVector(Ops[0], Ops[1], 4, 1, 2, 3, "movss");
+ case X86::BI__builtin_ia32_shufps: {
+ unsigned i = cast<ConstantInt>(Ops[2])->getZExtValue();
+ return EmitShuffleVector(Ops[0], Ops[1],
+ i & 0x3, (i & 0xc) >> 2,
+ ((i & 0x30) >> 4) + 4,
+ ((i & 0xc0) >> 6) + 4, "shufps");
+ }
+ case X86::BI__builtin_ia32_shufpd: {
+ unsigned i = cast<ConstantInt>(Ops[2])->getZExtValue();
+ return EmitShuffleVector(Ops[0], Ops[1], i & 1,
+ ((i & 2) >> 1)+2, "shufpd");
+ }
+ case X86::BI__builtin_ia32_punpcklbw128:
+ return EmitShuffleVector(Ops[0], Ops[1], 0, 16, 1, 17, 2, 18, 3, 19,
+ 4, 20, 5, 21, 6, 22, 7, 23,
+ "punpcklbw");
+ case X86::BI__builtin_ia32_punpcklwd128:
+ return EmitShuffleVector(Ops[0], Ops[1], 0, 8, 1, 9, 2, 10, 3, 11,
+ "punpcklwd");
+ case X86::BI__builtin_ia32_movlhps:
+ return EmitShuffleVector(Ops[0], Ops[1], 0, 1, 4, 5, "movlhps");
+ case X86::BI__builtin_ia32_movhlps:
+ return EmitShuffleVector(Ops[0], Ops[1], 6, 7, 2, 3, "movhlps");
+ case X86::BI__builtin_ia32_unpckhps:
+ return EmitShuffleVector(Ops[0], Ops[1], 2, 6, 3, 7, "unpckhps");
+ case X86::BI__builtin_ia32_unpcklps:
+ return EmitShuffleVector(Ops[0], Ops[1], 0, 4, 1, 5, "unpcklps");
+ case X86::BI__builtin_ia32_unpckhpd:
+ return EmitShuffleVector(Ops[0], Ops[1], 1, 3, "unpckhpd");
+ case X86::BI__builtin_ia32_unpcklpd:
+ return EmitShuffleVector(Ops[0], Ops[1], 0, 2, "unpcklpd");
+ case X86::BI__builtin_ia32_movsd:
+ return EmitShuffleVector(Ops[0], Ops[1], 2, 1, "movsd");
+ case X86::BI__builtin_ia32_loadlps:
+ case X86::BI__builtin_ia32_loadhps: {
+ // FIXME: This should probably be represented as
+ // shuffle (dst, (v4f32 (insert undef, (load i64), 0)), shuf mask hi/lo)
+ const llvm::Type *EltTy = llvm::Type::DoubleTy;
+ const llvm::Type *VecTy = llvm::VectorType::get(EltTy, 2);
+ const llvm::Type *OrigTy = Ops[0]->getType();
+ unsigned Index = BuiltinID == X86::BI__builtin_ia32_loadlps ? 0 : 1;
+ llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, Index);
+ Ops[1] = Builder.CreateBitCast(Ops[1], llvm::PointerType::getUnqual(EltTy));
+ Ops[1] = Builder.CreateLoad(Ops[1], "tmp");
+ Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast");
+ Ops[0] = Builder.CreateInsertElement(Ops[0], Ops[1], Idx, "loadps");
+ return Builder.CreateBitCast(Ops[0], OrigTy, "loadps");
+ }
+ case X86::BI__builtin_ia32_loadlpd:
+ case X86::BI__builtin_ia32_loadhpd: {
+ Ops[1] = Builder.CreateLoad(Ops[1], "tmp");
+ unsigned Index = BuiltinID == X86::BI__builtin_ia32_loadlpd ? 0 : 1;
+ llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, Index);
+ return Builder.CreateInsertElement(Ops[0], Ops[1], Idx, "loadpd");
+ }
+ case X86::BI__builtin_ia32_storehps:
+ case X86::BI__builtin_ia32_storelps: {
+ const llvm::Type *EltTy = llvm::Type::Int64Ty;
+ llvm::Type *PtrTy = llvm::PointerType::getUnqual(EltTy);
+ llvm::Type *VecTy = llvm::VectorType::get(EltTy, 2);
+
+ // cast val v2i64
+ Ops[1] = Builder.CreateBitCast(Ops[1], VecTy, "cast");
+
+ // extract (0, 1)
+ unsigned Index = BuiltinID == X86::BI__builtin_ia32_storelps ? 0 : 1;
+ llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, Index);
+ Ops[1] = Builder.CreateExtractElement(Ops[1], Idx, "extract");
+
+ // cast pointer to i64 & store
+ Ops[0] = Builder.CreateBitCast(Ops[0], PtrTy);
+ return Builder.CreateStore(Ops[1], Ops[0]);
+ }
+ case X86::BI__builtin_ia32_loadlv4si: {
+ // load i64
+ const llvm::Type *EltTy = llvm::Type::Int64Ty;
+ llvm::Type *PtrTy = llvm::PointerType::getUnqual(EltTy);
+ Ops[0] = Builder.CreateBitCast(Ops[0], PtrTy);
+ Ops[0] = Builder.CreateLoad(Ops[0], "load");
+
+ // scalar to vector: insert i64 into 2 x i64 undef
+ llvm::Type *VecTy = llvm::VectorType::get(EltTy, 2);
+ llvm::Value *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
+ Ops[0] = Builder.CreateInsertElement(llvm::UndefValue::get(VecTy),
+ Ops[0], Zero, "s2v");
+
+ // shuffle into zero vector.
+ std::vector<llvm::Constant *>Elts;
+ Elts.resize(2, llvm::ConstantInt::get(EltTy, 0));
+ llvm::Value *ZV = ConstantVector::get(Elts);
+ Ops[0] = EmitShuffleVector(ZV, Ops[0], 2, 1, "loadl");
+
+ // bitcast to result.
+ return Builder.CreateBitCast(Ops[0],
+ llvm::VectorType::get(llvm::Type::Int32Ty, 4));
+ }
+ case X86::BI__builtin_ia32_vec_set_v4hi:
+ case X86::BI__builtin_ia32_vec_set_v8hi:
+ return Builder.CreateInsertElement(Ops[0], Ops[1], Ops[2], "pinsrw");
+ case X86::BI__builtin_ia32_vec_set_v4si:
+ return Builder.CreateInsertElement(Ops[0], Ops[1], Ops[2], "pinsrd");
+ case X86::BI__builtin_ia32_vec_set_v2di:
+ return Builder.CreateInsertElement(Ops[0], Ops[1], Ops[2], "pinsrq");
+ case X86::BI__builtin_ia32_andps:
+ case X86::BI__builtin_ia32_andpd:
+ case X86::BI__builtin_ia32_andnps:
+ case X86::BI__builtin_ia32_andnpd:
+ case X86::BI__builtin_ia32_orps:
+ case X86::BI__builtin_ia32_orpd:
+ case X86::BI__builtin_ia32_xorpd:
+ case X86::BI__builtin_ia32_xorps: {
+ const llvm::Type *ITy = llvm::VectorType::get(llvm::Type::Int32Ty, 4);
+ const llvm::Type *FTy = Ops[0]->getType();
+ Ops[0] = Builder.CreateBitCast(Ops[0], ITy, "bitcast");
+ Ops[1] = Builder.CreateBitCast(Ops[1], ITy, "bitcast");
+ switch (BuiltinID) {
+ case X86::BI__builtin_ia32_andps:
+ Ops[0] = Builder.CreateAnd(Ops[0], Ops[1], "andps");
+ break;
+ case X86::BI__builtin_ia32_andpd:
+ Ops[0] = Builder.CreateAnd(Ops[0], Ops[1], "andpd");
+ break;
+ case X86::BI__builtin_ia32_andnps:
+ Ops[0] = Builder.CreateNot(Ops[0], "not");
+ Ops[0] = Builder.CreateAnd(Ops[0], Ops[1], "andnps");
+ break;
+ case X86::BI__builtin_ia32_andnpd:
+ Ops[0] = Builder.CreateNot(Ops[0], "not");
+ Ops[0] = Builder.CreateAnd(Ops[0], Ops[1], "andnpd");
+ break;
+ case X86::BI__builtin_ia32_orps:
+ Ops[0] = Builder.CreateOr(Ops[0], Ops[1], "orps");
+ break;
+ case X86::BI__builtin_ia32_orpd:
+ Ops[0] = Builder.CreateOr(Ops[0], Ops[1], "orpd");
+ break;
+ case X86::BI__builtin_ia32_xorps:
+ Ops[0] = Builder.CreateXor(Ops[0], Ops[1], "xorps");
+ break;
+ case X86::BI__builtin_ia32_xorpd:
+ Ops[0] = Builder.CreateXor(Ops[0], Ops[1], "xorpd");
+ break;
+ }
+ return Builder.CreateBitCast(Ops[0], FTy, "bitcast");
+ }
+ }
+}
+
+Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
+ const CallExpr *E) {
+ switch (BuiltinID) {
+ default: return 0;
+ }
+}
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
new file mode 100644
index 000000000000..731e38c5146d
--- /dev/null
+++ b/lib/CodeGen/CGCXX.cpp
@@ -0,0 +1,454 @@
+//===--- CGDecl.cpp - Emit LLVM Code for declarations ---------------------===//
+//
+// 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 C++ code generation.
+//
+//===----------------------------------------------------------------------===//
+
+// We might split this into multiple files if it gets too unwieldy
+
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "Mangle.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "llvm/ADT/StringExtras.h"
+using namespace clang;
+using namespace CodeGen;
+
+void
+CodeGenFunction::GenerateStaticCXXBlockVarDeclInit(const VarDecl &D,
+ llvm::GlobalVariable *GV) {
+ // FIXME: This should use __cxa_guard_{acquire,release}?
+
+ assert(!getContext().getLangOptions().ThreadsafeStatics &&
+ "thread safe statics are currently not supported!");
+
+ llvm::SmallString<256> GuardVName;
+ llvm::raw_svector_ostream GuardVOut(GuardVName);
+ mangleGuardVariable(&D, getContext(), GuardVOut);
+
+ // Create the guard variable.
+ llvm::GlobalValue *GuardV =
+ new llvm::GlobalVariable(llvm::Type::Int64Ty, false,
+ GV->getLinkage(),
+ llvm::Constant::getNullValue(llvm::Type::Int64Ty),
+ GuardVName.c_str(),
+ &CGM.getModule());
+
+ // Load the first byte of the guard variable.
+ const llvm::Type *PtrTy = llvm::PointerType::get(llvm::Type::Int8Ty, 0);
+ llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy),
+ "tmp");
+
+ // Compare it against 0.
+ llvm::Value *nullValue = llvm::Constant::getNullValue(llvm::Type::Int8Ty);
+ llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool");
+
+ llvm::BasicBlock *InitBlock = createBasicBlock("init");
+ llvm::BasicBlock *EndBlock = createBasicBlock("init.end");
+
+ // If the guard variable is 0, jump to the initializer code.
+ Builder.CreateCondBr(ICmp, InitBlock, EndBlock);
+
+ EmitBlock(InitBlock);
+
+ const Expr *Init = D.getInit();
+ if (!hasAggregateLLVMType(Init->getType())) {
+ llvm::Value *V = EmitScalarExpr(Init);
+ Builder.CreateStore(V, GV, D.getType().isVolatileQualified());
+ } else if (Init->getType()->isAnyComplexType()) {
+ EmitComplexExprIntoAddr(Init, GV, D.getType().isVolatileQualified());
+ } else {
+ EmitAggExpr(Init, GV, D.getType().isVolatileQualified());
+ }
+
+ Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::Int8Ty, 1),
+ Builder.CreateBitCast(GuardV, PtrTy));
+
+ EmitBlock(EndBlock);
+}
+
+RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
+ llvm::Value *Callee,
+ llvm::Value *This,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) {
+ assert(MD->isInstance() &&
+ "Trying to emit a member call expr on a static method!");
+
+ const FunctionProtoType *FPT = MD->getType()->getAsFunctionProtoType();
+
+ CallArgList Args;
+
+ // Push the this ptr.
+ Args.push_back(std::make_pair(RValue::get(This),
+ MD->getThisType(getContext())));
+
+ // And the rest of the call args
+ EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
+
+ QualType ResultType = MD->getType()->getAsFunctionType()->getResultType();
+ return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args),
+ Callee, Args, MD);
+}
+
+RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
+ const MemberExpr *ME = cast<MemberExpr>(CE->getCallee());
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
+
+ const FunctionProtoType *FPT = MD->getType()->getAsFunctionProtoType();
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+ llvm::Constant *Callee = CGM.GetAddrOfFunction(GlobalDecl(MD), Ty);
+
+ llvm::Value *This;
+
+ if (ME->isArrow())
+ This = EmitScalarExpr(ME->getBase());
+ else {
+ LValue BaseLV = EmitLValue(ME->getBase());
+ This = BaseLV.getAddress();
+ }
+
+ return EmitCXXMemberCall(MD, Callee, This,
+ CE->arg_begin(), CE->arg_end());
+}
+
+RValue
+CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
+ const CXXMethodDecl *MD) {
+ assert(MD->isInstance() &&
+ "Trying to emit a member call expr on a static method!");
+
+
+ const FunctionProtoType *FPT = MD->getType()->getAsFunctionProtoType();
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+ llvm::Constant *Callee = CGM.GetAddrOfFunction(GlobalDecl(MD), Ty);
+
+ llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
+
+ return EmitCXXMemberCall(MD, Callee, This,
+ E->arg_begin() + 1, E->arg_end());
+}
+
+llvm::Value *CodeGenFunction::LoadCXXThis() {
+ assert(isa<CXXMethodDecl>(CurFuncDecl) &&
+ "Must be in a C++ member function decl to load 'this'");
+ assert(cast<CXXMethodDecl>(CurFuncDecl)->isInstance() &&
+ "Must be in a C++ member function decl to load 'this'");
+
+ // FIXME: What if we're inside a block?
+ // ans: See how CodeGenFunction::LoadObjCSelf() uses
+ // CodeGenFunction::BlockForwardSelf() for how to do this.
+ return Builder.CreateLoad(LocalDeclMap[CXXThisDecl], "this");
+}
+
+void
+CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ llvm::Value *This,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) {
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
+
+ EmitCXXMemberCall(D, Callee, This, ArgBeg, ArgEnd);
+}
+
+void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *D,
+ CXXDtorType Type,
+ llvm::Value *This) {
+ llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(D, Type);
+
+ EmitCXXMemberCall(D, Callee, This, 0, 0);
+}
+
+void
+CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
+ const CXXConstructExpr *E) {
+ assert(Dest && "Must have a destination!");
+
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(E->getType()->getAsRecordType()->getDecl());
+ if (RD->hasTrivialConstructor())
+ return;
+
+ // Call the constructor.
+ EmitCXXConstructorCall(E->getConstructor(), Ctor_Complete, Dest,
+ E->arg_begin(), E->arg_end());
+}
+
+void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
+ llvm::Value *Ptr) {
+ LiveTemporaries.push_back(Temporary);
+
+ // Make a cleanup scope and emit the destructor.
+ {
+ CleanupScope Scope(*this);
+
+ EmitCXXDestructorCall(Temporary->getDestructor(), Dtor_Complete, Ptr);
+ }
+}
+
+RValue
+CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
+ llvm::Value *AggLoc,
+ bool isAggLocVolatile) {
+ // Keep track of the current cleanup stack depth.
+ size_t CleanupStackDepth = CleanupEntries.size();
+
+ unsigned OldNumLiveTemporaries = LiveTemporaries.size();
+
+ RValue RV = EmitAnyExpr(E->getSubExpr(), AggLoc, isAggLocVolatile);
+
+ // Go through the temporaries backwards.
+ for (unsigned i = E->getNumTemporaries(); i != 0; --i) {
+ assert(LiveTemporaries.back() == E->getTemporary(i - 1));
+ LiveTemporaries.pop_back();
+ }
+
+ assert(OldNumLiveTemporaries == LiveTemporaries.size() &&
+ "Live temporary stack mismatch!");
+
+ EmitCleanupBlocks(CleanupStackDepth);
+
+ return RV;
+}
+
+llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
+ if (E->isArray()) {
+ ErrorUnsupported(E, "new[] expression");
+ return llvm::UndefValue::get(ConvertType(E->getType()));
+ }
+
+ QualType AllocType = E->getAllocatedType();
+ FunctionDecl *NewFD = E->getOperatorNew();
+ const FunctionProtoType *NewFTy = NewFD->getType()->getAsFunctionProtoType();
+
+ CallArgList NewArgs;
+
+ // The allocation size is the first argument.
+ QualType SizeTy = getContext().getSizeType();
+ llvm::Value *AllocSize =
+ llvm::ConstantInt::get(ConvertType(SizeTy),
+ getContext().getTypeSize(AllocType) / 8);
+
+ NewArgs.push_back(std::make_pair(RValue::get(AllocSize), SizeTy));
+
+ // Emit the rest of the arguments.
+ // FIXME: Ideally, this should just use EmitCallArgs.
+ CXXNewExpr::const_arg_iterator NewArg = E->placement_arg_begin();
+
+ // First, use the types from the function type.
+ // We start at 1 here because the first argument (the allocation size)
+ // has already been emitted.
+ for (unsigned i = 1, e = NewFTy->getNumArgs(); i != e; ++i, ++NewArg) {
+ QualType ArgType = NewFTy->getArgType(i);
+
+ assert(getContext().getCanonicalType(ArgType.getNonReferenceType()).
+ getTypePtr() ==
+ getContext().getCanonicalType(NewArg->getType()).getTypePtr() &&
+ "type mismatch in call argument!");
+
+ NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType),
+ ArgType));
+
+ }
+
+ // Either we've emitted all the call args, or we have a call to a
+ // variadic function.
+ assert((NewArg == E->placement_arg_end() || NewFTy->isVariadic()) &&
+ "Extra arguments in non-variadic function!");
+
+ // If we still have any arguments, emit them using the type of the argument.
+ for (CXXNewExpr::const_arg_iterator NewArgEnd = E->placement_arg_end();
+ NewArg != NewArgEnd; ++NewArg) {
+ QualType ArgType = NewArg->getType();
+ NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType),
+ ArgType));
+ }
+
+ // Emit the call to new.
+ RValue RV =
+ EmitCall(CGM.getTypes().getFunctionInfo(NewFTy->getResultType(), NewArgs),
+ CGM.GetAddrOfFunction(GlobalDecl(NewFD)),
+ NewArgs, NewFD);
+
+ // If an allocation function is declared with an empty exception specification
+ // it returns null to indicate failure to allocate storage. [expr.new]p13.
+ // (We don't need to check for null when there's no new initializer and
+ // we're allocating a POD type).
+ bool NullCheckResult = NewFTy->hasEmptyExceptionSpec() &&
+ !(AllocType->isPODType() && !E->hasInitializer());
+
+ llvm::BasicBlock *NewNull = 0;
+ llvm::BasicBlock *NewNotNull = 0;
+ llvm::BasicBlock *NewEnd = 0;
+
+ llvm::Value *NewPtr = RV.getScalarVal();
+
+ if (NullCheckResult) {
+ NewNull = createBasicBlock("new.null");
+ NewNotNull = createBasicBlock("new.notnull");
+ NewEnd = createBasicBlock("new.end");
+
+ llvm::Value *IsNull =
+ Builder.CreateICmpEQ(NewPtr,
+ llvm::Constant::getNullValue(NewPtr->getType()),
+ "isnull");
+
+ Builder.CreateCondBr(IsNull, NewNull, NewNotNull);
+ EmitBlock(NewNotNull);
+ }
+
+ NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType()));
+
+ if (AllocType->isPODType()) {
+ if (E->getNumConstructorArgs() > 0) {
+ assert(E->getNumConstructorArgs() == 1 &&
+ "Can only have one argument to initializer of POD type.");
+
+ const Expr *Init = E->getConstructorArg(0);
+
+ if (!hasAggregateLLVMType(AllocType))
+ Builder.CreateStore(EmitScalarExpr(Init), NewPtr);
+ else if (AllocType->isAnyComplexType())
+ EmitComplexExprIntoAddr(Init, NewPtr, AllocType.isVolatileQualified());
+ else
+ EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified());
+ }
+ } else {
+ // Call the constructor.
+ CXXConstructorDecl *Ctor = E->getConstructor();
+
+ EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr,
+ E->constructor_arg_begin(),
+ E->constructor_arg_end());
+ }
+
+ if (NullCheckResult) {
+ Builder.CreateBr(NewEnd);
+ EmitBlock(NewNull);
+ Builder.CreateBr(NewEnd);
+ EmitBlock(NewEnd);
+
+ llvm::PHINode *PHI = Builder.CreatePHI(NewPtr->getType());
+ PHI->reserveOperandSpace(2);
+ PHI->addIncoming(NewPtr, NewNotNull);
+ PHI->addIncoming(llvm::Constant::getNullValue(NewPtr->getType()), NewNull);
+
+ NewPtr = PHI;
+ }
+
+ return NewPtr;
+}
+
+static bool canGenerateCXXstructor(const CXXRecordDecl *RD,
+ ASTContext &Context) {
+ // The class has base classes - we don't support that right now.
+ if (RD->getNumBases() > 0)
+ return false;
+
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(Context),
+ E = RD->field_end(Context); I != E; ++I) {
+ // We don't support ctors for fields that aren't POD.
+ if (!I->getType()->isPODType())
+ return false;
+ }
+
+ return true;
+}
+
+void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) {
+ if (!canGenerateCXXstructor(D->getParent(), getContext())) {
+ ErrorUnsupported(D, "C++ constructor", true);
+ return;
+ }
+
+ EmitGlobal(GlobalDecl(D, Ctor_Complete));
+ EmitGlobal(GlobalDecl(D, Ctor_Base));
+}
+
+void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D,
+ CXXCtorType Type) {
+
+ llvm::Function *Fn = GetAddrOfCXXConstructor(D, Type);
+
+ CodeGenFunction(*this).GenerateCode(D, Fn);
+
+ SetFunctionDefinitionAttributes(D, Fn);
+ SetLLVMFunctionAttributesForDefinition(D, Fn);
+}
+
+llvm::Function *
+CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
+ CXXCtorType Type) {
+ const llvm::FunctionType *FTy =
+ getTypes().GetFunctionType(getTypes().getFunctionInfo(D), false);
+
+ const char *Name = getMangledCXXCtorName(D, Type);
+ return cast<llvm::Function>(
+ GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type)));
+}
+
+const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D,
+ CXXCtorType Type) {
+ llvm::SmallString<256> Name;
+ llvm::raw_svector_ostream Out(Name);
+ mangleCXXCtor(D, Type, Context, Out);
+
+ Name += '\0';
+ return UniqueMangledName(Name.begin(), Name.end());
+}
+
+void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) {
+ if (!canGenerateCXXstructor(D->getParent(), getContext())) {
+ ErrorUnsupported(D, "C++ destructor", true);
+ return;
+ }
+
+ EmitCXXDestructor(D, Dtor_Complete);
+ EmitCXXDestructor(D, Dtor_Base);
+}
+
+void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D,
+ CXXDtorType Type) {
+ llvm::Function *Fn = GetAddrOfCXXDestructor(D, Type);
+
+ CodeGenFunction(*this).GenerateCode(D, Fn);
+
+ SetFunctionDefinitionAttributes(D, Fn);
+ SetLLVMFunctionAttributesForDefinition(D, Fn);
+}
+
+llvm::Function *
+CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D,
+ CXXDtorType Type) {
+ const llvm::FunctionType *FTy =
+ getTypes().GetFunctionType(getTypes().getFunctionInfo(D), false);
+
+ const char *Name = getMangledCXXDtorName(D, Type);
+ return cast<llvm::Function>(
+ GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type)));
+}
+
+const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D,
+ CXXDtorType Type) {
+ llvm::SmallString<256> Name;
+ llvm::raw_svector_ostream Out(Name);
+ mangleCXXDtor(D, Type, Context, Out);
+
+ Name += '\0';
+ return UniqueMangledName(Name.begin(), Name.end());
+}
diff --git a/lib/CodeGen/CGCXX.h b/lib/CodeGen/CGCXX.h
new file mode 100644
index 000000000000..6051d9133c02
--- /dev/null
+++ b/lib/CodeGen/CGCXX.h
@@ -0,0 +1,36 @@
+//===----- CGCXX.h - C++ related code CodeGen declarations ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes wrap the information about a call or function
+// definition used to handle ABI compliancy.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CGCXX_H
+#define CLANG_CODEGEN_CGCXX_H
+
+namespace clang {
+
+/// CXXCtorType - C++ constructor types
+enum CXXCtorType {
+ Ctor_Complete, // Complete object ctor
+ Ctor_Base, // Base object ctor
+ Ctor_CompleteAllocating // Complete object allocating ctor
+};
+
+/// CXXDtorType - C++ destructor types
+enum CXXDtorType {
+ Dtor_Deleting, // Deleting dtor
+ Dtor_Complete, // Complete object dtor
+ Dtor_Base // Base object dtor
+};
+
+} // end namespace clang
+
+#endif // CLANG_CODEGEN_CGCXX_H
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
new file mode 100644
index 000000000000..ea0b887c64c6
--- /dev/null
+++ b/lib/CodeGen/CGCall.cpp
@@ -0,0 +1,2196 @@
+//===----- CGCall.h - Encapsulate calling convention details ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes wrap the information about a call or function
+// definition used to handle ABI compliancy.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGCall.h"
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/RecordLayout.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Attributes.h"
+#include "llvm/Support/CallSite.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Target/TargetData.h"
+
+#include "ABIInfo.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+/***/
+
+// FIXME: Use iterator and sidestep silly type array creation.
+
+const
+CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionNoProtoType *FTNP) {
+ return getFunctionInfo(FTNP->getResultType(),
+ llvm::SmallVector<QualType, 16>());
+}
+
+const
+CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionProtoType *FTP) {
+ llvm::SmallVector<QualType, 16> ArgTys;
+ // FIXME: Kill copy.
+ for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
+ ArgTys.push_back(FTP->getArgType(i));
+ return getFunctionInfo(FTP->getResultType(), ArgTys);
+}
+
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
+ llvm::SmallVector<QualType, 16> ArgTys;
+ // Add the 'this' pointer unless this is a static method.
+ if (MD->isInstance())
+ ArgTys.push_back(MD->getThisType(Context));
+
+ const FunctionProtoType *FTP = MD->getType()->getAsFunctionProtoType();
+ for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
+ ArgTys.push_back(FTP->getArgType(i));
+ return getFunctionInfo(FTP->getResultType(), ArgTys);
+}
+
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) {
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
+ if (MD->isInstance())
+ return getFunctionInfo(MD);
+
+ const FunctionType *FTy = FD->getType()->getAsFunctionType();
+ if (const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FTy))
+ return getFunctionInfo(FTP);
+ return getFunctionInfo(cast<FunctionNoProtoType>(FTy));
+}
+
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
+ llvm::SmallVector<QualType, 16> ArgTys;
+ ArgTys.push_back(MD->getSelfDecl()->getType());
+ ArgTys.push_back(Context.getObjCSelType());
+ // FIXME: Kill copy?
+ for (ObjCMethodDecl::param_iterator i = MD->param_begin(),
+ e = MD->param_end(); i != e; ++i)
+ ArgTys.push_back((*i)->getType());
+ return getFunctionInfo(MD->getResultType(), ArgTys);
+}
+
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
+ const CallArgList &Args) {
+ // FIXME: Kill copy.
+ llvm::SmallVector<QualType, 16> ArgTys;
+ for (CallArgList::const_iterator i = Args.begin(), e = Args.end();
+ i != e; ++i)
+ ArgTys.push_back(i->second);
+ return getFunctionInfo(ResTy, ArgTys);
+}
+
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
+ const FunctionArgList &Args) {
+ // FIXME: Kill copy.
+ llvm::SmallVector<QualType, 16> ArgTys;
+ for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
+ i != e; ++i)
+ ArgTys.push_back(i->second);
+ return getFunctionInfo(ResTy, ArgTys);
+}
+
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
+ const llvm::SmallVector<QualType, 16> &ArgTys) {
+ // Lookup or create unique function info.
+ llvm::FoldingSetNodeID ID;
+ CGFunctionInfo::Profile(ID, ResTy, ArgTys.begin(), ArgTys.end());
+
+ void *InsertPos = 0;
+ CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, InsertPos);
+ if (FI)
+ return *FI;
+
+ // Construct the function info.
+ FI = new CGFunctionInfo(ResTy, ArgTys);
+ FunctionInfos.InsertNode(FI, InsertPos);
+
+ // Compute ABI information.
+ getABIInfo().computeInfo(*FI, getContext());
+
+ return *FI;
+}
+
+/***/
+
+ABIInfo::~ABIInfo() {}
+
+void ABIArgInfo::dump() const {
+ fprintf(stderr, "(ABIArgInfo Kind=");
+ switch (TheKind) {
+ case Direct:
+ fprintf(stderr, "Direct");
+ break;
+ case Ignore:
+ fprintf(stderr, "Ignore");
+ break;
+ case Coerce:
+ fprintf(stderr, "Coerce Type=");
+ getCoerceToType()->print(llvm::errs());
+ break;
+ case Indirect:
+ fprintf(stderr, "Indirect Align=%d", getIndirectAlign());
+ break;
+ case Expand:
+ fprintf(stderr, "Expand");
+ break;
+ }
+ fprintf(stderr, ")\n");
+}
+
+/***/
+
+static bool isEmptyRecord(ASTContext &Context, QualType T);
+
+/// isEmptyField - Return true iff a the field is "empty", that is it
+/// is an unnamed bit-field or an (array of) empty record(s).
+static bool isEmptyField(ASTContext &Context, const FieldDecl *FD) {
+ if (FD->isUnnamedBitfield())
+ return true;
+
+ QualType FT = FD->getType();
+ // Constant arrays of empty records count as empty, strip them off.
+ while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT))
+ FT = AT->getElementType();
+
+ return isEmptyRecord(Context, FT);
+}
+
+/// isEmptyRecord - Return true iff a structure contains only empty
+/// fields. Note that a structure with a flexible array member is not
+/// considered empty.
+static bool isEmptyRecord(ASTContext &Context, QualType T) {
+ const RecordType *RT = T->getAsRecordType();
+ if (!RT)
+ return 0;
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->hasFlexibleArrayMember())
+ return false;
+ for (RecordDecl::field_iterator i = RD->field_begin(Context),
+ e = RD->field_end(Context); i != e; ++i)
+ if (!isEmptyField(Context, *i))
+ return false;
+ return true;
+}
+
+/// isSingleElementStruct - Determine if a structure is a "single
+/// element struct", i.e. it has exactly one non-empty field or
+/// exactly one field which is itself a single element
+/// struct. Structures with flexible array members are never
+/// considered single element structs.
+///
+/// \return The field declaration for the single non-empty field, if
+/// it exists.
+static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
+ const RecordType *RT = T->getAsStructureType();
+ if (!RT)
+ return 0;
+
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->hasFlexibleArrayMember())
+ return 0;
+
+ const Type *Found = 0;
+ for (RecordDecl::field_iterator i = RD->field_begin(Context),
+ e = RD->field_end(Context); i != e; ++i) {
+ const FieldDecl *FD = *i;
+ QualType FT = FD->getType();
+
+ // Ignore empty fields.
+ if (isEmptyField(Context, FD))
+ continue;
+
+ // If we already found an element then this isn't a single-element
+ // struct.
+ if (Found)
+ return 0;
+
+ // Treat single element arrays as the element.
+ while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {
+ if (AT->getSize().getZExtValue() != 1)
+ break;
+ FT = AT->getElementType();
+ }
+
+ if (!CodeGenFunction::hasAggregateLLVMType(FT)) {
+ Found = FT.getTypePtr();
+ } else {
+ Found = isSingleElementStruct(FT, Context);
+ if (!Found)
+ return 0;
+ }
+ }
+
+ return Found;
+}
+
+static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) {
+ if (!Ty->getAsBuiltinType() && !Ty->isPointerType())
+ return false;
+
+ uint64_t Size = Context.getTypeSize(Ty);
+ return Size == 32 || Size == 64;
+}
+
+static bool areAllFields32Or64BitBasicType(const RecordDecl *RD,
+ ASTContext &Context) {
+ for (RecordDecl::field_iterator i = RD->field_begin(Context),
+ e = RD->field_end(Context); i != e; ++i) {
+ const FieldDecl *FD = *i;
+
+ if (!is32Or64BitBasicType(FD->getType(), Context))
+ return false;
+
+ // FIXME: Reject bit-fields wholesale; there are two problems, we don't know
+ // how to expand them yet, and the predicate for telling if a bitfield still
+ // counts as "basic" is more complicated than what we were doing previously.
+ if (FD->isBitField())
+ return false;
+ }
+
+ return true;
+}
+
+namespace {
+/// DefaultABIInfo - The default implementation for ABI specific
+/// details. This implementation provides information which results in
+/// self-consistent and sensible LLVM IR generation, but does not
+/// conform to any particular ABI.
+class DefaultABIInfo : public ABIInfo {
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ ASTContext &Context) const;
+
+ ABIArgInfo classifyArgumentType(QualType RetTy,
+ ASTContext &Context) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type, Context);
+ }
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+/// X86_32ABIInfo - The X86-32 ABI information.
+class X86_32ABIInfo : public ABIInfo {
+ ASTContext &Context;
+ bool IsDarwin;
+
+ static bool isRegisterSize(unsigned Size) {
+ return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
+ }
+
+ static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context);
+
+public:
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ ASTContext &Context) const;
+
+ ABIArgInfo classifyArgumentType(QualType RetTy,
+ ASTContext &Context) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type, Context);
+ }
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+
+ X86_32ABIInfo(ASTContext &Context, bool d)
+ : ABIInfo(), Context(Context), IsDarwin(d) {}
+};
+}
+
+
+/// shouldReturnTypeInRegister - Determine if the given type should be
+/// passed in a register (for the Darwin ABI).
+bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
+ ASTContext &Context) {
+ uint64_t Size = Context.getTypeSize(Ty);
+
+ // Type must be register sized.
+ if (!isRegisterSize(Size))
+ return false;
+
+ if (Ty->isVectorType()) {
+ // 64- and 128- bit vectors inside structures are not returned in
+ // registers.
+ if (Size == 64 || Size == 128)
+ return false;
+
+ return true;
+ }
+
+ // If this is a builtin, pointer, or complex type, it is ok.
+ if (Ty->getAsBuiltinType() || Ty->isPointerType() || Ty->isAnyComplexType())
+ return true;
+
+ // Arrays are treated like records.
+ if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty))
+ return shouldReturnTypeInRegister(AT->getElementType(), Context);
+
+ // Otherwise, it must be a record type.
+ const RecordType *RT = Ty->getAsRecordType();
+ if (!RT) return false;
+
+ // Structure types are passed in register if all fields would be
+ // passed in a register.
+ for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(Context),
+ e = RT->getDecl()->field_end(Context); i != e; ++i) {
+ const FieldDecl *FD = *i;
+
+ // Empty fields are ignored.
+ if (isEmptyField(Context, FD))
+ continue;
+
+ // Check fields recursively.
+ if (!shouldReturnTypeInRegister(FD->getType(), Context))
+ return false;
+ }
+
+ return true;
+}
+
+ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context) const {
+ if (RetTy->isVoidType()) {
+ return ABIArgInfo::getIgnore();
+ } else if (const VectorType *VT = RetTy->getAsVectorType()) {
+ // On Darwin, some vectors are returned in registers.
+ if (IsDarwin) {
+ uint64_t Size = Context.getTypeSize(RetTy);
+
+ // 128-bit vectors are a special case; they are returned in
+ // registers and we need to make sure to pick a type the LLVM
+ // backend will like.
+ if (Size == 128)
+ return ABIArgInfo::getCoerce(llvm::VectorType::get(llvm::Type::Int64Ty,
+ 2));
+
+ // Always return in register if it fits in a general purpose
+ // register, or if it is 64 bits and has a single element.
+ if ((Size == 8 || Size == 16 || Size == 32) ||
+ (Size == 64 && VT->getNumElements() == 1))
+ return ABIArgInfo::getCoerce(llvm::IntegerType::get(Size));
+
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ return ABIArgInfo::getDirect();
+ } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ // Structures with flexible arrays are always indirect.
+ if (const RecordType *RT = RetTy->getAsStructureType())
+ if (RT->getDecl()->hasFlexibleArrayMember())
+ return ABIArgInfo::getIndirect(0);
+
+ // Outside of Darwin, structs and unions are always indirect.
+ if (!IsDarwin && !RetTy->isAnyComplexType())
+ return ABIArgInfo::getIndirect(0);
+
+ // Classify "single element" structs as their element type.
+ if (const Type *SeltTy = isSingleElementStruct(RetTy, Context)) {
+ if (const BuiltinType *BT = SeltTy->getAsBuiltinType()) {
+ if (BT->isIntegerType()) {
+ // We need to use the size of the structure, padding
+ // bit-fields can adjust that to be larger than the single
+ // element type.
+ uint64_t Size = Context.getTypeSize(RetTy);
+ return ABIArgInfo::getCoerce(llvm::IntegerType::get((unsigned) Size));
+ } else if (BT->getKind() == BuiltinType::Float) {
+ assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) &&
+ "Unexpect single element structure size!");
+ return ABIArgInfo::getCoerce(llvm::Type::FloatTy);
+ } else if (BT->getKind() == BuiltinType::Double) {
+ assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) &&
+ "Unexpect single element structure size!");
+ return ABIArgInfo::getCoerce(llvm::Type::DoubleTy);
+ }
+ } else if (SeltTy->isPointerType()) {
+ // FIXME: It would be really nice if this could come out as the proper
+ // pointer type.
+ llvm::Type *PtrTy =
+ llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ return ABIArgInfo::getCoerce(PtrTy);
+ } else if (SeltTy->isVectorType()) {
+ // 64- and 128-bit vectors are never returned in a
+ // register when inside a structure.
+ uint64_t Size = Context.getTypeSize(RetTy);
+ if (Size == 64 || Size == 128)
+ return ABIArgInfo::getIndirect(0);
+
+ return classifyReturnType(QualType(SeltTy, 0), Context);
+ }
+ }
+
+ // Small structures which are register sized are generally returned
+ // in a register.
+ if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, Context)) {
+ uint64_t Size = Context.getTypeSize(RetTy);
+ return ABIArgInfo::getCoerce(llvm::IntegerType::get(Size));
+ }
+
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return ABIArgInfo::getDirect();
+ }
+}
+
+ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
+ ASTContext &Context) const {
+ // FIXME: Set alignment on indirect arguments.
+ if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ // Structures with flexible arrays are always indirect.
+ if (const RecordType *RT = Ty->getAsStructureType())
+ if (RT->getDecl()->hasFlexibleArrayMember())
+ return ABIArgInfo::getIndirect(0);
+
+ // Ignore empty structs.
+ uint64_t Size = Context.getTypeSize(Ty);
+ if (Ty->isStructureType() && Size == 0)
+ return ABIArgInfo::getIgnore();
+
+ // Expand structs with size <= 128-bits which consist only of
+ // basic types (int, long long, float, double, xxx*). This is
+ // non-recursive and does not ignore empty fields.
+ if (const RecordType *RT = Ty->getAsStructureType()) {
+ if (Context.getTypeSize(Ty) <= 4*32 &&
+ areAllFields32Or64BitBasicType(RT->getDecl(), Context))
+ return ABIArgInfo::getExpand();
+ }
+
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return ABIArgInfo::getDirect();
+ }
+}
+
+llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ const 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");
+ llvm::Type *PTy =
+ llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
+
+ uint64_t Offset =
+ llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4);
+ llvm::Value *NextAddr =
+ Builder.CreateGEP(Addr,
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, Offset),
+ "ap.next");
+ Builder.CreateStore(NextAddr, VAListAddrAsBPP);
+
+ return AddrTyped;
+}
+
+namespace {
+/// X86_64ABIInfo - The X86_64 ABI information.
+class X86_64ABIInfo : public ABIInfo {
+ enum Class {
+ Integer = 0,
+ SSE,
+ SSEUp,
+ X87,
+ X87Up,
+ ComplexX87,
+ NoClass,
+ Memory
+ };
+
+ /// merge - Implement the X86_64 ABI merging algorithm.
+ ///
+ /// Merge an accumulating classification \arg Accum with a field
+ /// classification \arg Field.
+ ///
+ /// \param Accum - The accumulating classification. This should
+ /// always be either NoClass or the result of a previous merge
+ /// call. In addition, this should never be Memory (the caller
+ /// should just return Memory for the aggregate).
+ Class merge(Class Accum, Class Field) const;
+
+ /// classify - Determine the x86_64 register classes in which the
+ /// given type T should be passed.
+ ///
+ /// \param Lo - The classification for the parts of the type
+ /// residing in the low word of the containing object.
+ ///
+ /// \param Hi - The classification for the parts of the type
+ /// residing in the high word of the containing object.
+ ///
+ /// \param OffsetBase - The bit offset of this type in the
+ /// containing object. Some parameters are classified different
+ /// depending on whether they straddle an eightbyte boundary.
+ ///
+ /// If a word is unused its result will be NoClass; if a type should
+ /// be passed in Memory then at least the classification of \arg Lo
+ /// will be Memory.
+ ///
+ /// The \arg Lo class will be NoClass iff the argument is ignored.
+ ///
+ /// If the \arg Lo class is ComplexX87, then the \arg Hi class will
+ /// also be ComplexX87.
+ void classify(QualType T, ASTContext &Context, uint64_t OffsetBase,
+ Class &Lo, Class &Hi) const;
+
+ /// getCoerceResult - Given a source type \arg Ty and an LLVM type
+ /// to coerce to, chose the best way to pass Ty in the same place
+ /// that \arg CoerceTo would be passed, but while keeping the
+ /// emitted code as simple as possible.
+ ///
+ /// FIXME: Note, this should be cleaned up to just take an enumeration of all
+ /// the ways we might want to pass things, instead of constructing an LLVM
+ /// type. This makes this code more explicit, and it makes it clearer that we
+ /// are also doing this for correctness in the case of passing scalar types.
+ ABIArgInfo getCoerceResult(QualType Ty,
+ const llvm::Type *CoerceTo,
+ ASTContext &Context) const;
+
+ /// getIndirectResult - Give a source type \arg Ty, return a suitable result
+ /// such that the argument will be passed in memory.
+ ABIArgInfo getIndirectResult(QualType Ty,
+ ASTContext &Context) const;
+
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ ASTContext &Context) const;
+
+ ABIArgInfo classifyArgumentType(QualType Ty,
+ ASTContext &Context,
+ unsigned &neededInt,
+ unsigned &neededSSE) const;
+
+public:
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const;
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+}
+
+X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum,
+ Class Field) const {
+ // AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is
+ // classified recursively so that always two fields are
+ // considered. The resulting class is calculated according to
+ // the classes of the fields in the eightbyte:
+ //
+ // (a) If both classes are equal, this is the resulting class.
+ //
+ // (b) If one of the classes is NO_CLASS, the resulting class is
+ // the other class.
+ //
+ // (c) If one of the classes is MEMORY, the result is the MEMORY
+ // class.
+ //
+ // (d) If one of the classes is INTEGER, the result is the
+ // INTEGER.
+ //
+ // (e) If one of the classes is X87, X87UP, COMPLEX_X87 class,
+ // MEMORY is used as class.
+ //
+ // (f) Otherwise class SSE is used.
+
+ // Accum should never be memory (we should have returned) or
+ // ComplexX87 (because this cannot be passed in a structure).
+ assert((Accum != Memory && Accum != ComplexX87) &&
+ "Invalid accumulated classification during merge.");
+ if (Accum == Field || Field == NoClass)
+ return Accum;
+ else if (Field == Memory)
+ return Memory;
+ else if (Accum == NoClass)
+ return Field;
+ else if (Accum == Integer || Field == Integer)
+ return Integer;
+ else if (Field == X87 || Field == X87Up || Field == ComplexX87 ||
+ Accum == X87 || Accum == X87Up)
+ return Memory;
+ else
+ return SSE;
+}
+
+void X86_64ABIInfo::classify(QualType Ty,
+ ASTContext &Context,
+ uint64_t OffsetBase,
+ Class &Lo, Class &Hi) const {
+ // FIXME: This code can be simplified by introducing a simple value class for
+ // Class pairs with appropriate constructor methods for the various
+ // situations.
+
+ // FIXME: Some of the split computations are wrong; unaligned vectors
+ // shouldn't be passed in registers for example, so there is no chance they
+ // can straddle an eightbyte. Verify & simplify.
+
+ Lo = Hi = NoClass;
+
+ Class &Current = OffsetBase < 64 ? Lo : Hi;
+ Current = Memory;
+
+ if (const BuiltinType *BT = Ty->getAsBuiltinType()) {
+ BuiltinType::Kind k = BT->getKind();
+
+ if (k == BuiltinType::Void) {
+ Current = NoClass;
+ } else if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) {
+ Lo = Integer;
+ Hi = Integer;
+ } else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) {
+ Current = Integer;
+ } else if (k == BuiltinType::Float || k == BuiltinType::Double) {
+ Current = SSE;
+ } else if (k == BuiltinType::LongDouble) {
+ Lo = X87;
+ Hi = X87Up;
+ }
+ // FIXME: _Decimal32 and _Decimal64 are SSE.
+ // FIXME: _float128 and _Decimal128 are (SSE, SSEUp).
+ } else if (const EnumType *ET = Ty->getAsEnumType()) {
+ // Classify the underlying integer type.
+ classify(ET->getDecl()->getIntegerType(), Context, OffsetBase, Lo, Hi);
+ } else if (Ty->hasPointerRepresentation()) {
+ Current = Integer;
+ } else if (const VectorType *VT = Ty->getAsVectorType()) {
+ uint64_t Size = Context.getTypeSize(VT);
+ if (Size == 32) {
+ // gcc passes all <4 x char>, <2 x short>, <1 x int>, <1 x
+ // float> as integer.
+ Current = Integer;
+
+ // If this type crosses an eightbyte boundary, it should be
+ // split.
+ uint64_t EB_Real = (OffsetBase) / 64;
+ uint64_t EB_Imag = (OffsetBase + Size - 1) / 64;
+ if (EB_Real != EB_Imag)
+ Hi = Lo;
+ } else if (Size == 64) {
+ // gcc passes <1 x double> in memory. :(
+ if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::Double))
+ return;
+
+ // gcc passes <1 x long long> as INTEGER.
+ if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::LongLong))
+ Current = Integer;
+ else
+ Current = SSE;
+
+ // If this type crosses an eightbyte boundary, it should be
+ // split.
+ if (OffsetBase && OffsetBase != 64)
+ Hi = Lo;
+ } else if (Size == 128) {
+ Lo = SSE;
+ Hi = SSEUp;
+ }
+ } else if (const ComplexType *CT = Ty->getAsComplexType()) {
+ QualType ET = Context.getCanonicalType(CT->getElementType());
+
+ uint64_t Size = Context.getTypeSize(Ty);
+ if (ET->isIntegralType()) {
+ if (Size <= 64)
+ Current = Integer;
+ else if (Size <= 128)
+ Lo = Hi = Integer;
+ } else if (ET == Context.FloatTy)
+ Current = SSE;
+ else if (ET == Context.DoubleTy)
+ Lo = Hi = SSE;
+ else if (ET == Context.LongDoubleTy)
+ Current = ComplexX87;
+
+ // If this complex type crosses an eightbyte boundary then it
+ // should be split.
+ uint64_t EB_Real = (OffsetBase) / 64;
+ uint64_t EB_Imag = (OffsetBase + Context.getTypeSize(ET)) / 64;
+ if (Hi == NoClass && EB_Real != EB_Imag)
+ Hi = Lo;
+ } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) {
+ // Arrays are treated like structures.
+
+ uint64_t Size = Context.getTypeSize(Ty);
+
+ // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
+ // than two eightbytes, ..., it has class MEMORY.
+ if (Size > 128)
+ return;
+
+ // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned
+ // fields, it has class MEMORY.
+ //
+ // Only need to check alignment of array base.
+ if (OffsetBase % Context.getTypeAlign(AT->getElementType()))
+ return;
+
+ // Otherwise implement simplified merge. We could be smarter about
+ // this, but it isn't worth it and would be harder to verify.
+ Current = NoClass;
+ uint64_t EltSize = Context.getTypeSize(AT->getElementType());
+ uint64_t ArraySize = AT->getSize().getZExtValue();
+ for (uint64_t i=0, Offset=OffsetBase; i<ArraySize; ++i, Offset += EltSize) {
+ Class FieldLo, FieldHi;
+ classify(AT->getElementType(), Context, Offset, FieldLo, FieldHi);
+ Lo = merge(Lo, FieldLo);
+ Hi = merge(Hi, FieldHi);
+ if (Lo == Memory || Hi == Memory)
+ break;
+ }
+
+ // Do post merger cleanup (see below). Only case we worry about is Memory.
+ if (Hi == Memory)
+ Lo = Memory;
+ assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp array classification.");
+ } else if (const RecordType *RT = Ty->getAsRecordType()) {
+ uint64_t Size = Context.getTypeSize(Ty);
+
+ // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
+ // than two eightbytes, ..., it has class MEMORY.
+ if (Size > 128)
+ return;
+
+ const RecordDecl *RD = RT->getDecl();
+
+ // Assume variable sized types are passed in memory.
+ if (RD->hasFlexibleArrayMember())
+ return;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ // Reset Lo class, this will be recomputed.
+ Current = NoClass;
+ unsigned idx = 0;
+ for (RecordDecl::field_iterator i = RD->field_begin(Context),
+ e = RD->field_end(Context); i != e; ++i, ++idx) {
+ uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx);
+ bool BitField = i->isBitField();
+
+ // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned
+ // fields, it has class MEMORY.
+ //
+ // Note, skip this test for bit-fields, see below.
+ if (!BitField && Offset % Context.getTypeAlign(i->getType())) {
+ Lo = Memory;
+ return;
+ }
+
+ // Classify this field.
+ //
+ // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate
+ // exceeds a single eightbyte, each is classified
+ // separately. Each eightbyte gets initialized to class
+ // NO_CLASS.
+ Class FieldLo, FieldHi;
+
+ // Bit-fields require special handling, they do not force the
+ // structure to be passed in memory even if unaligned, and
+ // therefore they can straddle an eightbyte.
+ if (BitField) {
+ // Ignore padding bit-fields.
+ if (i->isUnnamedBitfield())
+ continue;
+
+ uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx);
+ uint64_t Size = i->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
+
+ uint64_t EB_Lo = Offset / 64;
+ uint64_t EB_Hi = (Offset + Size - 1) / 64;
+ FieldLo = FieldHi = NoClass;
+ if (EB_Lo) {
+ assert(EB_Hi == EB_Lo && "Invalid classification, type > 16 bytes.");
+ FieldLo = NoClass;
+ FieldHi = Integer;
+ } else {
+ FieldLo = Integer;
+ FieldHi = EB_Hi ? Integer : NoClass;
+ }
+ } else
+ classify(i->getType(), Context, Offset, FieldLo, FieldHi);
+ Lo = merge(Lo, FieldLo);
+ Hi = merge(Hi, FieldHi);
+ if (Lo == Memory || Hi == Memory)
+ break;
+ }
+
+ // AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done:
+ //
+ // (a) If one of the classes is MEMORY, the whole argument is
+ // passed in memory.
+ //
+ // (b) If SSEUP is not preceeded by SSE, it is converted to SSE.
+
+ // The first of these conditions is guaranteed by how we implement
+ // the merge (just bail).
+ //
+ // The second condition occurs in the case of unions; for example
+ // union { _Complex double; unsigned; }.
+ if (Hi == Memory)
+ Lo = Memory;
+ if (Hi == SSEUp && Lo != SSE)
+ Hi = SSE;
+ }
+}
+
+ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty,
+ const llvm::Type *CoerceTo,
+ ASTContext &Context) const {
+ if (CoerceTo == llvm::Type::Int64Ty) {
+ // Integer and pointer types will end up in a general purpose
+ // register.
+ if (Ty->isIntegralType() || Ty->isPointerType())
+ return ABIArgInfo::getDirect();
+
+ } else if (CoerceTo == llvm::Type::DoubleTy) {
+ // FIXME: It would probably be better to make CGFunctionInfo only map using
+ // canonical types than to canonize here.
+ QualType CTy = Context.getCanonicalType(Ty);
+
+ // Float and double end up in a single SSE reg.
+ if (CTy == Context.FloatTy || CTy == Context.DoubleTy)
+ return ABIArgInfo::getDirect();
+
+ }
+
+ return ABIArgInfo::getCoerce(CoerceTo);
+}
+
+ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
+ ASTContext &Context) const {
+ // If this is a scalar LLVM value then assume LLVM will pass it in the right
+ // place naturally.
+ if (!CodeGenFunction::hasAggregateLLVMType(Ty))
+ return ABIArgInfo::getDirect();
+
+ // FIXME: Set alignment correctly.
+ return ABIArgInfo::getIndirect(0);
+}
+
+ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context) const {
+ // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the
+ // classification algorithm.
+ X86_64ABIInfo::Class Lo, Hi;
+ classify(RetTy, Context, 0, Lo, Hi);
+
+ // Check some invariants.
+ assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
+ assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification.");
+ assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification.");
+
+ const llvm::Type *ResType = 0;
+ switch (Lo) {
+ case NoClass:
+ return ABIArgInfo::getIgnore();
+
+ case SSEUp:
+ case X87Up:
+ assert(0 && "Invalid classification for lo word.");
+
+ // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via
+ // hidden argument.
+ case Memory:
+ return getIndirectResult(RetTy, Context);
+
+ // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next
+ // available register of the sequence %rax, %rdx is used.
+ case Integer:
+ ResType = llvm::Type::Int64Ty; break;
+
+ // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next
+ // available SSE register of the sequence %xmm0, %xmm1 is used.
+ case SSE:
+ ResType = llvm::Type::DoubleTy; break;
+
+ // AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is
+ // returned on the X87 stack in %st0 as 80-bit x87 number.
+ case X87:
+ ResType = llvm::Type::X86_FP80Ty; break;
+
+ // AMD64-ABI 3.2.3p4: Rule 8. If the class is COMPLEX_X87, the real
+ // part of the value is returned in %st0 and the imaginary part in
+ // %st1.
+ case ComplexX87:
+ assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification.");
+ ResType = llvm::StructType::get(llvm::Type::X86_FP80Ty,
+ llvm::Type::X86_FP80Ty,
+ NULL);
+ break;
+ }
+
+ switch (Hi) {
+ // Memory was handled previously and X87 should
+ // never occur as a hi class.
+ case Memory:
+ case X87:
+ assert(0 && "Invalid classification for hi word.");
+
+ case ComplexX87: // Previously handled.
+ case NoClass: break;
+
+ case Integer:
+ ResType = llvm::StructType::get(ResType, llvm::Type::Int64Ty, NULL);
+ break;
+ case SSE:
+ ResType = llvm::StructType::get(ResType, llvm::Type::DoubleTy, NULL);
+ break;
+
+ // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte
+ // is passed in the upper half of the last used SSE register.
+ //
+ // SSEUP should always be preceeded by SSE, just widen.
+ case SSEUp:
+ assert(Lo == SSE && "Unexpected SSEUp classification.");
+ ResType = llvm::VectorType::get(llvm::Type::DoubleTy, 2);
+ break;
+
+ // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is
+ // returned together with the previous X87 value in %st0.
+ case X87Up:
+ // If X87Up is preceeded by X87, we don't need to do
+ // anything. However, in some cases with unions it may not be
+ // preceeded by X87. In such situations we follow gcc and pass the
+ // extra bits in an SSE reg.
+ if (Lo != X87)
+ ResType = llvm::StructType::get(ResType, llvm::Type::DoubleTy, NULL);
+ break;
+ }
+
+ return getCoerceResult(RetTy, ResType, Context);
+}
+
+ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
+ unsigned &neededInt,
+ unsigned &neededSSE) const {
+ X86_64ABIInfo::Class Lo, Hi;
+ classify(Ty, Context, 0, Lo, Hi);
+
+ // Check some invariants.
+ // FIXME: Enforce these by construction.
+ assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
+ assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification.");
+ assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification.");
+
+ neededInt = 0;
+ neededSSE = 0;
+ const llvm::Type *ResType = 0;
+ switch (Lo) {
+ case NoClass:
+ return ABIArgInfo::getIgnore();
+
+ // AMD64-ABI 3.2.3p3: Rule 1. If the class is MEMORY, pass the argument
+ // on the stack.
+ case Memory:
+
+ // AMD64-ABI 3.2.3p3: Rule 5. If the class is X87, X87UP or
+ // COMPLEX_X87, it is passed in memory.
+ case X87:
+ case ComplexX87:
+ return getIndirectResult(Ty, Context);
+
+ case SSEUp:
+ case X87Up:
+ assert(0 && "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
+ // and %r9 is used.
+ case Integer:
+ ++neededInt;
+ ResType = llvm::Type::Int64Ty;
+ break;
+
+ // AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next
+ // available SSE register is used, the registers are taken in the
+ // order from %xmm0 to %xmm7.
+ case SSE:
+ ++neededSSE;
+ ResType = llvm::Type::DoubleTy;
+ break;
+ }
+
+ switch (Hi) {
+ // Memory was handled previously, ComplexX87 and X87 should
+ // never occur as hi classes, and X87Up must be preceed by X87,
+ // which is passed in memory.
+ case Memory:
+ case X87:
+ case ComplexX87:
+ assert(0 && "Invalid classification for hi word.");
+ break;
+
+ case NoClass: break;
+ case Integer:
+ ResType = llvm::StructType::get(ResType, llvm::Type::Int64Ty, NULL);
+ ++neededInt;
+ break;
+
+ // X87Up generally doesn't occur here (long double is passed in
+ // memory), except in situations involving unions.
+ case X87Up:
+ case SSE:
+ ResType = llvm::StructType::get(ResType, llvm::Type::DoubleTy, NULL);
+ ++neededSSE;
+ break;
+
+ // AMD64-ABI 3.2.3p3: Rule 4. If the class is SSEUP, the
+ // eightbyte is passed in the upper half of the last used SSE
+ // register.
+ case SSEUp:
+ assert(Lo == SSE && "Unexpected SSEUp classification.");
+ ResType = llvm::VectorType::get(llvm::Type::DoubleTy, 2);
+ break;
+ }
+
+ return getCoerceResult(Ty, ResType, Context);
+}
+
+void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context);
+
+ // Keep track of the number of assigned registers.
+ unsigned freeIntRegs = 6, freeSSERegs = 8;
+
+ // If the return value is indirect, then the hidden argument is consuming one
+ // integer register.
+ if (FI.getReturnInfo().isIndirect())
+ --freeIntRegs;
+
+ // AMD64-ABI 3.2.3p3: Once arguments are classified, the registers
+ // get assigned (in left-to-right order) for passing as follows...
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it) {
+ unsigned neededInt, neededSSE;
+ it->info = classifyArgumentType(it->type, Context, neededInt, neededSSE);
+
+ // AMD64-ABI 3.2.3p3: If there are no registers available for any
+ // eightbyte of an argument, the whole argument is passed on the
+ // stack. If registers have already been assigned for some
+ // eightbytes of such an argument, the assignments get reverted.
+ if (freeIntRegs >= neededInt && freeSSERegs >= neededSSE) {
+ freeIntRegs -= neededInt;
+ freeSSERegs -= neededSSE;
+ } else {
+ it->info = getIndirectResult(it->type, Context);
+ }
+ }
+}
+
+static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr,
+ QualType Ty,
+ CodeGenFunction &CGF) {
+ llvm::Value *overflow_arg_area_p =
+ CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_p");
+ llvm::Value *overflow_arg_area =
+ CGF.Builder.CreateLoad(overflow_arg_area_p, "overflow_arg_area");
+
+ // AMD64-ABI 3.5.7p5: Step 7. Align l->overflow_arg_area upwards to a 16
+ // byte boundary if alignment needed by type exceeds 8 byte boundary.
+ uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8;
+ if (Align > 8) {
+ // Note that we follow the ABI & gcc here, even though the type
+ // could in theory have an alignment greater than 16. This case
+ // shouldn't ever matter in practice.
+
+ // overflow_arg_area = (overflow_arg_area + 15) & ~15;
+ llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, 15);
+ overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset);
+ llvm::Value *AsInt = CGF.Builder.CreatePtrToInt(overflow_arg_area,
+ llvm::Type::Int64Ty);
+ llvm::Value *Mask = llvm::ConstantInt::get(llvm::Type::Int64Ty, ~15LL);
+ overflow_arg_area =
+ CGF.Builder.CreateIntToPtr(CGF.Builder.CreateAnd(AsInt, Mask),
+ overflow_arg_area->getType(),
+ "overflow_arg_area.align");
+ }
+
+ // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area.
+ const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty);
+ llvm::Value *Res =
+ CGF.Builder.CreateBitCast(overflow_arg_area,
+ llvm::PointerType::getUnqual(LTy));
+
+ // AMD64-ABI 3.5.7p5: Step 9. Set l->overflow_arg_area to:
+ // l->overflow_arg_area + sizeof(type).
+ // AMD64-ABI 3.5.7p5: Step 10. Align l->overflow_arg_area upwards to
+ // an 8 byte boundary.
+
+ uint64_t SizeInBytes = (CGF.getContext().getTypeSize(Ty) + 7) / 8;
+ llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ (SizeInBytes + 7) & ~7);
+ overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset,
+ "overflow_arg_area.next");
+ CGF.Builder.CreateStore(overflow_arg_area, overflow_arg_area_p);
+
+ // AMD64-ABI 3.5.7p5: Step 11. Return the fetched type.
+ return Res;
+}
+
+llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ // Assume that va_list type is correct; should be pointer to LLVM type:
+ // struct {
+ // i32 gp_offset;
+ // i32 fp_offset;
+ // i8* overflow_arg_area;
+ // i8* reg_save_area;
+ // };
+ unsigned neededInt, neededSSE;
+ ABIArgInfo AI = classifyArgumentType(Ty, CGF.getContext(),
+ neededInt, neededSSE);
+
+ // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed
+ // in the registers. If not go to step 7.
+ if (!neededInt && !neededSSE)
+ return EmitVAArgFromMemory(VAListAddr, Ty, CGF);
+
+ // AMD64-ABI 3.5.7p5: Step 2. Compute num_gp to hold the number of
+ // general purpose registers needed to pass type and num_fp to hold
+ // the number of floating point registers needed.
+
+ // AMD64-ABI 3.5.7p5: Step 3. Verify whether arguments fit into
+ // registers. In the case: l->gp_offset > 48 - num_gp * 8 or
+ // l->fp_offset > 304 - num_fp * 16 go to step 7.
+ //
+ // NOTE: 304 is a typo, there are (6 * 8 + 8 * 16) = 176 bytes of
+ // register save space).
+
+ llvm::Value *InRegs = 0;
+ llvm::Value *gp_offset_p = 0, *gp_offset = 0;
+ llvm::Value *fp_offset_p = 0, *fp_offset = 0;
+ if (neededInt) {
+ gp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "gp_offset_p");
+ gp_offset = CGF.Builder.CreateLoad(gp_offset_p, "gp_offset");
+ InRegs =
+ CGF.Builder.CreateICmpULE(gp_offset,
+ llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ 48 - neededInt * 8),
+ "fits_in_gp");
+ }
+
+ if (neededSSE) {
+ fp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 1, "fp_offset_p");
+ fp_offset = CGF.Builder.CreateLoad(fp_offset_p, "fp_offset");
+ llvm::Value *FitsInFP =
+ CGF.Builder.CreateICmpULE(fp_offset,
+ llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ 176 - neededSSE * 16),
+ "fits_in_fp");
+ InRegs = InRegs ? CGF.Builder.CreateAnd(InRegs, FitsInFP) : FitsInFP;
+ }
+
+ llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg");
+ llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem");
+ llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end");
+ CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock);
+
+ // Emit code to load the value if it was passed in registers.
+
+ CGF.EmitBlock(InRegBlock);
+
+ // AMD64-ABI 3.5.7p5: Step 4. Fetch type from l->reg_save_area with
+ // an offset of l->gp_offset and/or l->fp_offset. This may require
+ // copying to a temporary location in case the parameter is passed
+ // in different register classes or requires an alignment greater
+ // than 8 for general purpose registers and 16 for XMM registers.
+ //
+ // FIXME: This really results in shameful code when we end up needing to
+ // 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::Value *RegAddr =
+ CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(VAListAddr, 3),
+ "reg_save_area");
+ if (neededInt && neededSSE) {
+ // FIXME: Cleanup.
+ assert(AI.isCoerce() && "Unexpected ABI info for mixed regs");
+ const 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);
+ assert((TyLo->isFloatingPoint() ^ TyHi->isFloatingPoint()) &&
+ "Unexpected ABI info for mixed regs");
+ const llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo);
+ const 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->isFloatingPoint() ? FPAddr : GPAddr;
+ llvm::Value *RegHiAddr = TyLo->isFloatingPoint() ? GPAddr : FPAddr;
+ llvm::Value *V =
+ CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegLoAddr, PTyLo));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
+ V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegHiAddr, PTyHi));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1));
+
+ RegAddr = CGF.Builder.CreateBitCast(Tmp, llvm::PointerType::getUnqual(LTy));
+ } else if (neededInt) {
+ RegAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset);
+ RegAddr = CGF.Builder.CreateBitCast(RegAddr,
+ llvm::PointerType::getUnqual(LTy));
+ } else {
+ if (neededSSE == 1) {
+ RegAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset);
+ RegAddr = CGF.Builder.CreateBitCast(RegAddr,
+ llvm::PointerType::getUnqual(LTy));
+ } else {
+ assert(neededSSE == 2 && "Invalid number of needed registers!");
+ // SSE registers are spaced 16 bytes apart in the register save
+ // area, we need to collect the two eightbytes together.
+ llvm::Value *RegAddrLo = CGF.Builder.CreateGEP(RegAddr, fp_offset);
+ llvm::Value *RegAddrHi =
+ CGF.Builder.CreateGEP(RegAddrLo,
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, 16));
+ const llvm::Type *DblPtrTy =
+ llvm::PointerType::getUnqual(llvm::Type::DoubleTy);
+ const llvm::StructType *ST = llvm::StructType::get(llvm::Type::DoubleTy,
+ llvm::Type::DoubleTy,
+ NULL);
+ llvm::Value *V, *Tmp = CGF.CreateTempAlloca(ST);
+ V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo,
+ DblPtrTy));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
+ V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrHi,
+ DblPtrTy));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1));
+ RegAddr = CGF.Builder.CreateBitCast(Tmp,
+ llvm::PointerType::getUnqual(LTy));
+ }
+ }
+
+ // AMD64-ABI 3.5.7p5: Step 5. Set:
+ // l->gp_offset = l->gp_offset + num_gp * 8
+ // l->fp_offset = l->fp_offset + num_fp * 16.
+ if (neededInt) {
+ llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ neededInt * 8);
+ CGF.Builder.CreateStore(CGF.Builder.CreateAdd(gp_offset, Offset),
+ gp_offset_p);
+ }
+ if (neededSSE) {
+ llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ neededSSE * 16);
+ CGF.Builder.CreateStore(CGF.Builder.CreateAdd(fp_offset, Offset),
+ fp_offset_p);
+ }
+ CGF.EmitBranch(ContBlock);
+
+ // Emit code to load the value if it was passed in memory.
+
+ CGF.EmitBlock(InMemBlock);
+ llvm::Value *MemAddr = EmitVAArgFromMemory(VAListAddr, Ty, CGF);
+
+ // Return the appropriate result.
+
+ CGF.EmitBlock(ContBlock);
+ llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(RegAddr->getType(),
+ "vaarg.addr");
+ ResAddr->reserveOperandSpace(2);
+ ResAddr->addIncoming(RegAddr, InRegBlock);
+ ResAddr->addIncoming(MemAddr, InMemBlock);
+
+ return ResAddr;
+}
+
+// ABI Info for PIC16
+class PIC16ABIInfo : public ABIInfo {
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ ASTContext &Context) const;
+
+ ABIArgInfo classifyArgumentType(QualType RetTy,
+ ASTContext &Context) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type, Context);
+ }
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+
+};
+
+ABIArgInfo PIC16ABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context) const {
+ if (RetTy->isVoidType()) {
+ return ABIArgInfo::getIgnore();
+ } else {
+ return ABIArgInfo::getDirect();
+ }
+}
+
+ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty,
+ ASTContext &Context) const {
+ return ABIArgInfo::getDirect();
+}
+
+llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ return 0;
+}
+
+class ARMABIInfo : public ABIInfo {
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ ASTContext &Context) const;
+
+ ABIArgInfo classifyArgumentType(QualType RetTy,
+ ASTContext &Context) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const;
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it) {
+ it->info = classifyArgumentType(it->type, Context);
+ }
+}
+
+ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty,
+ ASTContext &Context) const {
+ if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ return ABIArgInfo::getDirect();
+ }
+ // 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;
+ unsigned SizeRegs;
+ if (Context.getTypeAlign(Ty) > 32) {
+ ElemTy = llvm::Type::Int64Ty;
+ SizeRegs = (Context.getTypeSize(Ty) + 63) / 64;
+ } else {
+ ElemTy = llvm::Type::Int32Ty;
+ SizeRegs = (Context.getTypeSize(Ty) + 31) / 32;
+ }
+ std::vector<const llvm::Type*> LLVMFields;
+ LLVMFields.push_back(llvm::ArrayType::get(ElemTy, SizeRegs));
+ const llvm::Type* STy = llvm::StructType::get(LLVMFields, true);
+ return ABIArgInfo::getCoerce(STy);
+}
+
+ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context) const {
+ if (RetTy->isVoidType()) {
+ return ABIArgInfo::getIgnore();
+ } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ // Aggregates <= 4 bytes are returned in r0; other aggregates
+ // are returned indirectly.
+ uint64_t Size = Context.getTypeSize(RetTy);
+ if (Size <= 32)
+ return ABIArgInfo::getCoerce(llvm::Type::Int32Ty);
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return ABIArgInfo::getDirect();
+ }
+}
+
+llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ // FIXME: Need to handle alignment
+ const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ const 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");
+ llvm::Type *PTy =
+ llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
+
+ uint64_t Offset =
+ llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4);
+ llvm::Value *NextAddr =
+ Builder.CreateGEP(Addr,
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, Offset),
+ "ap.next");
+ Builder.CreateStore(NextAddr, VAListAddrAsBPP);
+
+ return AddrTyped;
+}
+
+ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context) const {
+ if (RetTy->isVoidType()) {
+ return ABIArgInfo::getIgnore();
+ } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return ABIArgInfo::getDirect();
+ }
+}
+
+ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty,
+ ASTContext &Context) const {
+ if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return ABIArgInfo::getDirect();
+ }
+}
+
+llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ return 0;
+}
+
+const ABIInfo &CodeGenTypes::getABIInfo() const {
+ if (TheABIInfo)
+ return *TheABIInfo;
+
+ // For now we just cache this in the CodeGenTypes and don't bother
+ // to free it.
+ const char *TargetPrefix = getContext().Target.getTargetPrefix();
+ if (strcmp(TargetPrefix, "x86") == 0) {
+ bool IsDarwin = strstr(getContext().Target.getTargetTriple(), "darwin");
+ switch (getContext().Target.getPointerWidth(0)) {
+ case 32:
+ return *(TheABIInfo = new X86_32ABIInfo(Context, IsDarwin));
+ case 64:
+ return *(TheABIInfo = new X86_64ABIInfo());
+ }
+ } else if (strcmp(TargetPrefix, "arm") == 0) {
+ // FIXME: Support for OABI?
+ return *(TheABIInfo = new ARMABIInfo());
+ } else if (strcmp(TargetPrefix, "pic16") == 0) {
+ return *(TheABIInfo = new PIC16ABIInfo());
+ }
+
+ return *(TheABIInfo = new DefaultABIInfo);
+}
+
+/***/
+
+CGFunctionInfo::CGFunctionInfo(QualType ResTy,
+ const llvm::SmallVector<QualType, 16> &ArgTys) {
+ NumArgs = ArgTys.size();
+ Args = new ArgInfo[1 + NumArgs];
+ Args[0].type = ResTy;
+ for (unsigned i = 0; i < NumArgs; ++i)
+ Args[1 + i].type = ArgTys[i];
+}
+
+/***/
+
+void CodeGenTypes::GetExpandedTypes(QualType Ty,
+ std::vector<const llvm::Type*> &ArgTys) {
+ const RecordType *RT = Ty->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(Context),
+ e = RD->field_end(Context); i != e; ++i) {
+ const FieldDecl *FD = *i;
+ assert(!FD->isBitField() &&
+ "Cannot expand structure with bit-field members.");
+
+ QualType FT = FD->getType();
+ if (CodeGenFunction::hasAggregateLLVMType(FT)) {
+ GetExpandedTypes(FT, ArgTys);
+ } else {
+ ArgTys.push_back(ConvertType(FT));
+ }
+ }
+}
+
+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(getContext()),
+ e = RD->field_end(getContext()); i != e; ++i) {
+ FieldDecl *FD = *i;
+ QualType FT = FD->getType();
+
+ // FIXME: What are the right qualifiers here?
+ LValue LV = EmitLValueForField(Addr, FD, false, 0);
+ if (CodeGenFunction::hasAggregateLLVMType(FT)) {
+ AI = ExpandTypeFromArgs(FT, LV, AI);
+ } else {
+ EmitStoreThroughLValue(RValue::get(AI), LV, FT);
+ ++AI;
+ }
+ }
+
+ return AI;
+}
+
+void
+CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
+ llvm::SmallVector<llvm::Value*, 16> &Args) {
+ 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(getContext()),
+ e = RD->field_end(getContext()); i != e; ++i) {
+ FieldDecl *FD = *i;
+ QualType FT = FD->getType();
+
+ // FIXME: What are the right qualifiers here?
+ LValue LV = EmitLValueForField(Addr, FD, false, 0);
+ if (CodeGenFunction::hasAggregateLLVMType(FT)) {
+ ExpandTypeToArgs(FT, RValue::getAggregate(LV.getAddress()), Args);
+ } else {
+ RValue RV = EmitLoadOfLValue(LV, FT);
+ assert(RV.isScalar() &&
+ "Unexpected non-scalar rvalue during struct expansion.");
+ Args.push_back(RV.getScalarVal());
+ }
+ }
+}
+
+/// CreateCoercedLoad - Create a load from \arg SrcPtr interpreted as
+/// a pointer to an object of type \arg Ty.
+///
+/// This safely handles the case when the src type is smaller than the
+/// 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,
+ CodeGenFunction &CGF) {
+ const llvm::Type *SrcTy =
+ cast<llvm::PointerType>(SrcPtr->getType())->getElementType();
+ uint64_t SrcSize = CGF.CGM.getTargetData().getTypeAllocSize(SrcTy);
+ uint64_t DstSize = CGF.CGM.getTargetData().getTypeAllocSize(Ty);
+
+ // If load is legal, just bitcast the src pointer.
+ if (SrcSize >= DstSize) {
+ // Generally SrcSize is never greater than DstSize, since this means we are
+ // losing bits. However, this can happen in cases where the structure has
+ // additional padding, for example due to a user specified alignment.
+ //
+ // FIXME: Assert that we aren't truncating non-padding bits when have access
+ // to that information.
+ llvm::Value *Casted =
+ CGF.Builder.CreateBitCast(SrcPtr, llvm::PointerType::getUnqual(Ty));
+ llvm::LoadInst *Load = CGF.Builder.CreateLoad(Casted);
+ // FIXME: Use better alignment / avoid requiring aligned load.
+ Load->setAlignment(1);
+ return Load;
+ } else {
+ // Otherwise do coercion through memory. This is stupid, but
+ // simple.
+ llvm::Value *Tmp = CGF.CreateTempAlloca(Ty);
+ llvm::Value *Casted =
+ CGF.Builder.CreateBitCast(Tmp, llvm::PointerType::getUnqual(SrcTy));
+ llvm::StoreInst *Store =
+ CGF.Builder.CreateStore(CGF.Builder.CreateLoad(SrcPtr), Casted);
+ // FIXME: Use better alignment / avoid requiring aligned store.
+ Store->setAlignment(1);
+ return CGF.Builder.CreateLoad(Tmp);
+ }
+}
+
+/// CreateCoercedStore - Create a store to \arg DstPtr from \arg Src,
+/// where the source and destination may have different types.
+///
+/// This safely handles the case when the src type is larger than the
+/// destination type; the upper bits of the src will be lost.
+static void CreateCoercedStore(llvm::Value *Src,
+ llvm::Value *DstPtr,
+ CodeGenFunction &CGF) {
+ const llvm::Type *SrcTy = Src->getType();
+ const llvm::Type *DstTy =
+ cast<llvm::PointerType>(DstPtr->getType())->getElementType();
+
+ uint64_t SrcSize = CGF.CGM.getTargetData().getTypeAllocSize(SrcTy);
+ uint64_t DstSize = CGF.CGM.getTargetData().getTypeAllocSize(DstTy);
+
+ // If store is legal, just bitcast the src pointer.
+ if (SrcSize >= DstSize) {
+ // Generally SrcSize is never greater than DstSize, since this means we are
+ // losing bits. However, this can happen in cases where the structure has
+ // additional padding, for example due to a user specified alignment.
+ //
+ // FIXME: Assert that we aren't truncating non-padding bits when have access
+ // to that information.
+ llvm::Value *Casted =
+ CGF.Builder.CreateBitCast(DstPtr, llvm::PointerType::getUnqual(SrcTy));
+ // FIXME: Use better alignment / avoid requiring aligned store.
+ CGF.Builder.CreateStore(Src, Casted)->setAlignment(1);
+ } else {
+ // Otherwise do coercion through memory. This is stupid, but
+ // simple.
+ llvm::Value *Tmp = CGF.CreateTempAlloca(SrcTy);
+ CGF.Builder.CreateStore(Src, Tmp);
+ llvm::Value *Casted =
+ CGF.Builder.CreateBitCast(Tmp, llvm::PointerType::getUnqual(DstTy));
+ llvm::LoadInst *Load = CGF.Builder.CreateLoad(Casted);
+ // FIXME: Use better alignment / avoid requiring aligned load.
+ Load->setAlignment(1);
+ CGF.Builder.CreateStore(Load, DstPtr);
+ }
+}
+
+/***/
+
+bool CodeGenModule::ReturnTypeUsesSret(const CGFunctionInfo &FI) {
+ return FI.getReturnInfo().isIndirect();
+}
+
+const llvm::FunctionType *
+CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic) {
+ std::vector<const llvm::Type*> ArgTys;
+
+ const llvm::Type *ResultType = 0;
+
+ QualType RetTy = FI.getReturnType();
+ const ABIArgInfo &RetAI = FI.getReturnInfo();
+ switch (RetAI.getKind()) {
+ case ABIArgInfo::Expand:
+ assert(0 && "Invalid ABI kind for return argument");
+
+ case ABIArgInfo::Direct:
+ ResultType = ConvertType(RetTy);
+ break;
+
+ case ABIArgInfo::Indirect: {
+ assert(!RetAI.getIndirectAlign() && "Align unused on indirect return.");
+ ResultType = llvm::Type::VoidTy;
+ const llvm::Type *STy = ConvertType(RetTy);
+ ArgTys.push_back(llvm::PointerType::get(STy, RetTy.getAddressSpace()));
+ break;
+ }
+
+ case ABIArgInfo::Ignore:
+ ResultType = llvm::Type::VoidTy;
+ break;
+
+ case ABIArgInfo::Coerce:
+ ResultType = RetAI.getCoerceToType();
+ break;
+ }
+
+ for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
+ ie = FI.arg_end(); it != ie; ++it) {
+ const ABIArgInfo &AI = it->info;
+
+ switch (AI.getKind()) {
+ case ABIArgInfo::Ignore:
+ break;
+
+ case ABIArgInfo::Coerce:
+ ArgTys.push_back(AI.getCoerceToType());
+ break;
+
+ case ABIArgInfo::Indirect: {
+ // indirect arguments are always on the stack, which is addr space #0.
+ const llvm::Type *LTy = ConvertTypeForMem(it->type);
+ ArgTys.push_back(llvm::PointerType::getUnqual(LTy));
+ break;
+ }
+
+ case ABIArgInfo::Direct:
+ ArgTys.push_back(ConvertType(it->type));
+ break;
+
+ case ABIArgInfo::Expand:
+ GetExpandedTypes(it->type, ArgTys);
+ break;
+ }
+ }
+
+ return llvm::FunctionType::get(ResultType, ArgTys, IsVariadic);
+}
+
+void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
+ const Decl *TargetDecl,
+ AttributeListType &PAL) {
+ unsigned FuncAttrs = 0;
+ unsigned RetAttrs = 0;
+
+ // FIXME: handle sseregparm someday...
+ if (TargetDecl) {
+ if (TargetDecl->hasAttr<NoThrowAttr>())
+ FuncAttrs |= llvm::Attribute::NoUnwind;
+ if (TargetDecl->hasAttr<NoReturnAttr>())
+ FuncAttrs |= llvm::Attribute::NoReturn;
+ if (TargetDecl->hasAttr<ConstAttr>())
+ FuncAttrs |= llvm::Attribute::ReadNone;
+ else if (TargetDecl->hasAttr<PureAttr>())
+ FuncAttrs |= llvm::Attribute::ReadOnly;
+ }
+
+ QualType RetTy = FI.getReturnType();
+ unsigned Index = 1;
+ const ABIArgInfo &RetAI = FI.getReturnInfo();
+ switch (RetAI.getKind()) {
+ case ABIArgInfo::Direct:
+ if (RetTy->isPromotableIntegerType()) {
+ if (RetTy->isSignedIntegerType()) {
+ RetAttrs |= llvm::Attribute::SExt;
+ } else if (RetTy->isUnsignedIntegerType()) {
+ RetAttrs |= llvm::Attribute::ZExt;
+ }
+ }
+ break;
+
+ case ABIArgInfo::Indirect:
+ PAL.push_back(llvm::AttributeWithIndex::get(Index,
+ llvm::Attribute::StructRet |
+ llvm::Attribute::NoAlias));
+ ++Index;
+ // sret disables readnone and readonly
+ FuncAttrs &= ~(llvm::Attribute::ReadOnly |
+ llvm::Attribute::ReadNone);
+ break;
+
+ case ABIArgInfo::Ignore:
+ case ABIArgInfo::Coerce:
+ break;
+
+ case ABIArgInfo::Expand:
+ assert(0 && "Invalid ABI kind for return argument");
+ }
+
+ if (RetAttrs)
+ PAL.push_back(llvm::AttributeWithIndex::get(0, RetAttrs));
+
+ // FIXME: we need to honour command line settings also...
+ // FIXME: RegParm should be reduced in case of nested functions and/or global
+ // register variable.
+ signed RegParm = 0;
+ if (TargetDecl)
+ if (const RegparmAttr *RegParmAttr = TargetDecl->getAttr<RegparmAttr>())
+ RegParm = RegParmAttr->getNumParams();
+
+ unsigned PointerWidth = getContext().Target.getPointerWidth(0);
+ for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
+ ie = FI.arg_end(); it != ie; ++it) {
+ QualType ParamType = it->type;
+ const ABIArgInfo &AI = it->info;
+ unsigned Attributes = 0;
+
+ switch (AI.getKind()) {
+ case ABIArgInfo::Coerce:
+ break;
+
+ case ABIArgInfo::Indirect:
+ Attributes |= llvm::Attribute::ByVal;
+ Attributes |=
+ llvm::Attribute::constructAlignmentFromInt(AI.getIndirectAlign());
+ // byval disables readnone and readonly.
+ FuncAttrs &= ~(llvm::Attribute::ReadOnly |
+ llvm::Attribute::ReadNone);
+ break;
+
+ case ABIArgInfo::Direct:
+ if (ParamType->isPromotableIntegerType()) {
+ if (ParamType->isSignedIntegerType()) {
+ Attributes |= llvm::Attribute::SExt;
+ } else if (ParamType->isUnsignedIntegerType()) {
+ Attributes |= llvm::Attribute::ZExt;
+ }
+ }
+ if (RegParm > 0 &&
+ (ParamType->isIntegerType() || ParamType->isPointerType())) {
+ RegParm -=
+ (Context.getTypeSize(ParamType) + PointerWidth - 1) / PointerWidth;
+ if (RegParm >= 0)
+ Attributes |= llvm::Attribute::InReg;
+ }
+ // FIXME: handle sseregparm someday...
+ break;
+
+ case ABIArgInfo::Ignore:
+ // Skip increment, no matching LLVM parameter.
+ continue;
+
+ case ABIArgInfo::Expand: {
+ std::vector<const llvm::Type*> Tys;
+ // 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.
+ getTypes().GetExpandedTypes(ParamType, Tys);
+ Index += Tys.size();
+ continue;
+ }
+ }
+
+ if (Attributes)
+ PAL.push_back(llvm::AttributeWithIndex::get(Index, Attributes));
+ ++Index;
+ }
+ if (FuncAttrs)
+ PAL.push_back(llvm::AttributeWithIndex::get(~0, FuncAttrs));
+}
+
+void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
+ llvm::Function *Fn,
+ const FunctionArgList &Args) {
+ // FIXME: We no longer need the types from FunctionArgList; lift up and
+ // simplify.
+
+ // Emit allocs for param decls. Give the LLVM Argument nodes names.
+ llvm::Function::arg_iterator AI = Fn->arg_begin();
+
+ // Name the struct return argument.
+ if (CGM.ReturnTypeUsesSret(FI)) {
+ AI->setName("agg.result");
+ ++AI;
+ }
+
+ assert(FI.arg_size() == Args.size() &&
+ "Mismatch between function signature & arguments.");
+ CGFunctionInfo::const_arg_iterator info_it = FI.arg_begin();
+ for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
+ i != e; ++i, ++info_it) {
+ const VarDecl *Arg = i->first;
+ QualType Ty = info_it->type;
+ const ABIArgInfo &ArgI = info_it->info;
+
+ switch (ArgI.getKind()) {
+ case ABIArgInfo::Indirect: {
+ llvm::Value* V = AI;
+ if (hasAggregateLLVMType(Ty)) {
+ // Do nothing, aggregates and complex variables are accessed by
+ // reference.
+ } else {
+ // Load scalar value from indirect argument.
+ V = EmitLoadOfScalar(V, false, Ty);
+ if (!getContext().typesAreCompatible(Ty, Arg->getType())) {
+ // This must be a promotion, for something like
+ // "void a(x) short x; {..."
+ V = EmitScalarConversion(V, Ty, Arg->getType());
+ }
+ }
+ EmitParmDecl(*Arg, V);
+ break;
+ }
+
+ case ABIArgInfo::Direct: {
+ assert(AI != Fn->arg_end() && "Argument mismatch!");
+ llvm::Value* V = AI;
+ if (hasAggregateLLVMType(Ty)) {
+ // Create a temporary alloca to hold the argument; the rest of
+ // codegen expects to access aggregates & complex values by
+ // reference.
+ V = CreateTempAlloca(ConvertTypeForMem(Ty));
+ Builder.CreateStore(AI, V);
+ } else {
+ if (!getContext().typesAreCompatible(Ty, Arg->getType())) {
+ // This must be a promotion, for something like
+ // "void a(x) short x; {..."
+ V = EmitScalarConversion(V, Ty, Arg->getType());
+ }
+ }
+ EmitParmDecl(*Arg, V);
+ break;
+ }
+
+ case ABIArgInfo::Expand: {
+ // If this structure was expanded into multiple arguments then
+ // we need to create a temporary and reconstruct it from the
+ // arguments.
+ std::string Name = Arg->getNameAsString();
+ llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(Ty),
+ (Name + ".addr").c_str());
+ // FIXME: What are the right qualifiers here?
+ llvm::Function::arg_iterator End =
+ ExpandTypeFromArgs(Ty, LValue::MakeAddr(Temp,0), AI);
+ EmitParmDecl(*Arg, Temp);
+
+ // Name the arguments used in expansion and increment AI.
+ unsigned Index = 0;
+ for (; AI != End; ++AI, ++Index)
+ AI->setName(Name + "." + llvm::utostr(Index));
+ continue;
+ }
+
+ case ABIArgInfo::Ignore:
+ // Initialize the local variable appropriately.
+ if (hasAggregateLLVMType(Ty)) {
+ EmitParmDecl(*Arg, CreateTempAlloca(ConvertTypeForMem(Ty)));
+ } else {
+ EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType())));
+ }
+
+ // Skip increment, no matching LLVM parameter.
+ continue;
+
+ case ABIArgInfo::Coerce: {
+ assert(AI != Fn->arg_end() && "Argument mismatch!");
+ // FIXME: This is very wasteful; EmitParmDecl is just going to drop the
+ // result in a new alloca anyway, so we could just store into that
+ // directly if we broke the abstraction down more.
+ llvm::Value *V = CreateTempAlloca(ConvertTypeForMem(Ty), "coerce");
+ CreateCoercedStore(AI, V, *this);
+ // Match to what EmitParmDecl is expecting for this type.
+ if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ V = EmitLoadOfScalar(V, false, Ty);
+ if (!getContext().typesAreCompatible(Ty, Arg->getType())) {
+ // This must be a promotion, for something like
+ // "void a(x) short x; {..."
+ V = EmitScalarConversion(V, Ty, Arg->getType());
+ }
+ }
+ EmitParmDecl(*Arg, V);
+ break;
+ }
+ }
+
+ ++AI;
+ }
+ assert(AI == Fn->arg_end() && "Argument mismatch!");
+}
+
+void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
+ llvm::Value *ReturnValue) {
+ llvm::Value *RV = 0;
+
+ // Functions with no result always return void.
+ if (ReturnValue) {
+ QualType RetTy = FI.getReturnType();
+ const ABIArgInfo &RetAI = FI.getReturnInfo();
+
+ switch (RetAI.getKind()) {
+ case ABIArgInfo::Indirect:
+ if (RetTy->isAnyComplexType()) {
+ ComplexPairTy RT = LoadComplexFromAddr(ReturnValue, false);
+ StoreComplexToAddr(RT, CurFn->arg_begin(), false);
+ } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ EmitAggregateCopy(CurFn->arg_begin(), ReturnValue, RetTy);
+ } else {
+ EmitStoreOfScalar(Builder.CreateLoad(ReturnValue), CurFn->arg_begin(),
+ false, RetTy);
+ }
+ break;
+
+ case ABIArgInfo::Direct:
+ // The internal return value temp always will have
+ // pointer-to-return-type type.
+ RV = Builder.CreateLoad(ReturnValue);
+ break;
+
+ case ABIArgInfo::Ignore:
+ break;
+
+ case ABIArgInfo::Coerce:
+ RV = CreateCoercedLoad(ReturnValue, RetAI.getCoerceToType(), *this);
+ break;
+
+ case ABIArgInfo::Expand:
+ assert(0 && "Invalid ABI kind for return argument");
+ }
+ }
+
+ if (RV) {
+ Builder.CreateRet(RV);
+ } else {
+ Builder.CreateRetVoid();
+ }
+}
+
+RValue CodeGenFunction::EmitCallArg(const Expr *E, QualType ArgType) {
+ if (ArgType->isReferenceType())
+ return EmitReferenceBindingToExpr(E, ArgType);
+
+ return EmitAnyExprToTemp(E);
+}
+
+RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
+ llvm::Value *Callee,
+ const CallArgList &CallArgs,
+ const Decl *TargetDecl) {
+ // FIXME: We no longer need the types from CallArgs; lift up and simplify.
+ llvm::SmallVector<llvm::Value*, 16> Args;
+
+ // Handle struct-return functions by passing a pointer to the
+ // location that we would like to return into.
+ QualType RetTy = CallInfo.getReturnType();
+ const ABIArgInfo &RetAI = CallInfo.getReturnInfo();
+ if (CGM.ReturnTypeUsesSret(CallInfo)) {
+ // Create a temporary alloca to hold the result of the call. :(
+ Args.push_back(CreateTempAlloca(ConvertTypeForMem(RetTy)));
+ }
+
+ assert(CallInfo.arg_size() == CallArgs.size() &&
+ "Mismatch between function signature & arguments.");
+ CGFunctionInfo::const_arg_iterator info_it = CallInfo.arg_begin();
+ for (CallArgList::const_iterator I = CallArgs.begin(), E = CallArgs.end();
+ I != E; ++I, ++info_it) {
+ const ABIArgInfo &ArgInfo = info_it->info;
+ RValue RV = I->first;
+
+ switch (ArgInfo.getKind()) {
+ case ABIArgInfo::Indirect:
+ if (RV.isScalar() || RV.isComplex()) {
+ // Make a temporary alloca to pass the argument.
+ Args.push_back(CreateTempAlloca(ConvertTypeForMem(I->second)));
+ if (RV.isScalar())
+ EmitStoreOfScalar(RV.getScalarVal(), Args.back(), false, I->second);
+ else
+ StoreComplexToAddr(RV.getComplexVal(), Args.back(), false);
+ } else {
+ Args.push_back(RV.getAggregateAddr());
+ }
+ break;
+
+ case ABIArgInfo::Direct:
+ if (RV.isScalar()) {
+ Args.push_back(RV.getScalarVal());
+ } else if (RV.isComplex()) {
+ llvm::Value *Tmp = llvm::UndefValue::get(ConvertType(I->second));
+ Tmp = Builder.CreateInsertValue(Tmp, RV.getComplexVal().first, 0);
+ Tmp = Builder.CreateInsertValue(Tmp, RV.getComplexVal().second, 1);
+ Args.push_back(Tmp);
+ } else {
+ Args.push_back(Builder.CreateLoad(RV.getAggregateAddr()));
+ }
+ break;
+
+ case ABIArgInfo::Ignore:
+ break;
+
+ case ABIArgInfo::Coerce: {
+ // FIXME: Avoid the conversion through memory if possible.
+ llvm::Value *SrcPtr;
+ if (RV.isScalar()) {
+ SrcPtr = CreateTempAlloca(ConvertTypeForMem(I->second), "coerce");
+ EmitStoreOfScalar(RV.getScalarVal(), SrcPtr, false, I->second);
+ } else if (RV.isComplex()) {
+ SrcPtr = CreateTempAlloca(ConvertTypeForMem(I->second), "coerce");
+ StoreComplexToAddr(RV.getComplexVal(), SrcPtr, false);
+ } else
+ SrcPtr = RV.getAggregateAddr();
+ Args.push_back(CreateCoercedLoad(SrcPtr, ArgInfo.getCoerceToType(),
+ *this));
+ break;
+ }
+
+ case ABIArgInfo::Expand:
+ ExpandTypeToArgs(I->second, RV, Args);
+ break;
+ }
+ }
+
+ llvm::BasicBlock *InvokeDest = getInvokeDest();
+ CodeGen::AttributeListType AttributeList;
+ CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList);
+ llvm::AttrListPtr Attrs = llvm::AttrListPtr::get(AttributeList.begin(),
+ AttributeList.end());
+
+ llvm::CallSite CS;
+ if (!InvokeDest || (Attrs.getFnAttributes() & llvm::Attribute::NoUnwind)) {
+ CS = Builder.CreateCall(Callee, Args.data(), Args.data()+Args.size());
+ } else {
+ llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
+ CS = Builder.CreateInvoke(Callee, Cont, InvokeDest,
+ Args.data(), Args.data()+Args.size());
+ EmitBlock(Cont);
+ }
+
+ CS.setAttributes(Attrs);
+ if (const llvm::Function *F = dyn_cast<llvm::Function>(Callee->stripPointerCasts()))
+ CS.setCallingConv(F->getCallingConv());
+
+ // If the call doesn't return, finish the basic block and clear the
+ // insertion point; this allows the rest of IRgen to discard
+ // unreachable code.
+ if (CS.doesNotReturn()) {
+ Builder.CreateUnreachable();
+ Builder.ClearInsertionPoint();
+
+ // FIXME: For now, emit a dummy basic block because expr emitters in
+ // generally are not ready to handle emitting expressions at unreachable
+ // points.
+ EnsureInsertPoint();
+
+ // Return a reasonable RValue.
+ return GetUndefRValue(RetTy);
+ }
+
+ llvm::Instruction *CI = CS.getInstruction();
+ if (Builder.isNamePreserving() && CI->getType() != llvm::Type::VoidTy)
+ CI->setName("call");
+
+ switch (RetAI.getKind()) {
+ case ABIArgInfo::Indirect:
+ if (RetTy->isAnyComplexType())
+ return RValue::getComplex(LoadComplexFromAddr(Args[0], false));
+ if (CodeGenFunction::hasAggregateLLVMType(RetTy))
+ return RValue::getAggregate(Args[0]);
+ return RValue::get(EmitLoadOfScalar(Args[0], false, RetTy));
+
+ case ABIArgInfo::Direct:
+ if (RetTy->isAnyComplexType()) {
+ llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
+ llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
+ return RValue::getComplex(std::make_pair(Real, Imag));
+ }
+ if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ llvm::Value *V = CreateTempAlloca(ConvertTypeForMem(RetTy), "agg.tmp");
+ Builder.CreateStore(CI, V);
+ return RValue::getAggregate(V);
+ }
+ return RValue::get(CI);
+
+ case ABIArgInfo::Ignore:
+ // If we are ignoring an argument that had a result, make sure to
+ // construct the appropriate return value for our caller.
+ return GetUndefRValue(RetTy);
+
+ case ABIArgInfo::Coerce: {
+ // FIXME: Avoid the conversion through memory if possible.
+ llvm::Value *V = CreateTempAlloca(ConvertTypeForMem(RetTy), "coerce");
+ CreateCoercedStore(CI, V, *this);
+ if (RetTy->isAnyComplexType())
+ return RValue::getComplex(LoadComplexFromAddr(V, false));
+ if (CodeGenFunction::hasAggregateLLVMType(RetTy))
+ return RValue::getAggregate(V);
+ return RValue::get(EmitLoadOfScalar(V, false, RetTy));
+ }
+
+ case ABIArgInfo::Expand:
+ assert(0 && "Invalid ABI kind for return argument");
+ }
+
+ assert(0 && "Unhandled ABIArgInfo::Kind");
+ return RValue::get(0);
+}
+
+/* VarArg handling */
+
+llvm::Value *CodeGenFunction::EmitVAArg(llvm::Value *VAListAddr, QualType Ty) {
+ return CGM.getTypes().getABIInfo().EmitVAArg(VAListAddr, Ty, *this);
+}
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
new file mode 100644
index 000000000000..daf6f0004501
--- /dev/null
+++ b/lib/CodeGen/CGCall.h
@@ -0,0 +1,104 @@
+//===----- CGCall.h - Encapsulate calling convention details ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes wrap the information about a call or function
+// definition used to handle ABI compliancy.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CGCALL_H
+#define CLANG_CODEGEN_CGCALL_H
+
+#include <llvm/ADT/FoldingSet.h>
+#include "clang/AST/Type.h"
+
+#include "CGValue.h"
+
+// FIXME: Restructure so we don't have to expose so much stuff.
+#include "ABIInfo.h"
+
+namespace llvm {
+ struct AttributeWithIndex;
+ class Function;
+ class Type;
+ class Value;
+
+ template<typename T, unsigned> class SmallVector;
+}
+
+namespace clang {
+ class ASTContext;
+ class Decl;
+ class FunctionDecl;
+ class ObjCMethodDecl;
+ class VarDecl;
+
+namespace CodeGen {
+ typedef llvm::SmallVector<llvm::AttributeWithIndex, 8> AttributeListType;
+
+ /// CallArgList - Type for representing both the value and type of
+ /// arguments in a call.
+ typedef llvm::SmallVector<std::pair<RValue, QualType>, 16> CallArgList;
+
+ /// FunctionArgList - Type for representing both the decl and type
+ /// of parameters to a function. The decl must be either a
+ /// ParmVarDecl or ImplicitParamDecl.
+ typedef llvm::SmallVector<std::pair<const VarDecl*, QualType>,
+ 16> FunctionArgList;
+
+ /// CGFunctionInfo - Class to encapsulate the information about a
+ /// function definition.
+ class CGFunctionInfo : public llvm::FoldingSetNode {
+ struct ArgInfo {
+ QualType type;
+ ABIArgInfo info;
+ };
+
+ unsigned NumArgs;
+ ArgInfo *Args;
+
+ public:
+ typedef const ArgInfo *const_arg_iterator;
+ typedef ArgInfo *arg_iterator;
+
+ CGFunctionInfo(QualType ResTy,
+ const llvm::SmallVector<QualType, 16> &ArgTys);
+ ~CGFunctionInfo() { delete[] Args; }
+
+ const_arg_iterator arg_begin() const { return Args + 1; }
+ const_arg_iterator arg_end() const { return Args + 1 + NumArgs; }
+ arg_iterator arg_begin() { return Args + 1; }
+ arg_iterator arg_end() { return Args + 1 + NumArgs; }
+
+ unsigned arg_size() const { return NumArgs; }
+
+ QualType getReturnType() const { return Args[0].type; }
+
+ ABIArgInfo &getReturnInfo() { return Args[0].info; }
+ const ABIArgInfo &getReturnInfo() const { return Args[0].info; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ getReturnType().Profile(ID);
+ for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it)
+ it->type.Profile(ID);
+ }
+ template<class Iterator>
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ QualType ResTy,
+ Iterator begin,
+ Iterator end) {
+ ResTy.Profile(ID);
+ for (; begin != end; ++begin)
+ begin->Profile(ID);
+ }
+ };
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
new file mode 100644
index 000000000000..049e716c7c1b
--- /dev/null
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -0,0 +1,987 @@
+//===--- CGDebugInfo.cpp - Emit Debug Information for a Module ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This coordinates the debug information generation while generating code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGDebugInfo.h"
+#include "CodeGenModule.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/CompileOptions.h"
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Instructions.h"
+#include "llvm/Intrinsics.h"
+#include "llvm/Module.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/System/Path.h"
+#include "llvm/Target/TargetMachine.h"
+using namespace clang;
+using namespace clang::CodeGen;
+
+CGDebugInfo::CGDebugInfo(CodeGenModule *m)
+ : M(m), isMainCompileUnitCreated(false), DebugFactory(M->getModule()),
+ BlockLiteralGenericSet(false) {
+}
+
+CGDebugInfo::~CGDebugInfo() {
+ assert(RegionStack.empty() && "Region stack mismatch, stack not empty!");
+}
+
+void CGDebugInfo::setLocation(SourceLocation Loc) {
+ if (Loc.isValid())
+ CurLoc = M->getContext().getSourceManager().getInstantiationLoc(Loc);
+}
+
+/// getOrCreateCompileUnit - Get the compile unit from the cache or create a new
+/// one if necessary. This returns null for invalid source locations.
+llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
+ // Get source file information.
+ const char *FileName = "<unknown>";
+ SourceManager &SM = M->getContext().getSourceManager();
+ unsigned FID = 0;
+ if (Loc.isValid()) {
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+ FileName = PLoc.getFilename();
+ FID = PLoc.getIncludeLoc().getRawEncoding();
+ }
+
+ // See if this compile unit has been used before.
+ llvm::DICompileUnit &Unit = CompileUnitCache[FID];
+ if (!Unit.isNull()) return Unit;
+
+ // Get absolute path name.
+ llvm::sys::Path AbsFileName(FileName);
+ if (!AbsFileName.isAbsolute()) {
+ llvm::sys::Path tmp = llvm::sys::Path::GetCurrentDirectory();
+ tmp.appendComponent(FileName);
+ AbsFileName = tmp;
+ }
+
+ // See if thie compile unit is representing main source file. Each source
+ // file has corresponding compile unit. There is only one main source
+ // file at a time.
+ bool isMain = false;
+ const LangOptions &LO = M->getLangOptions();
+ const char *MainFileName = LO.getMainFileName();
+ if (isMainCompileUnitCreated == false) {
+ if (MainFileName) {
+ if (!strcmp(AbsFileName.getLast().c_str(), MainFileName))
+ isMain = true;
+ } else {
+ if (Loc.isValid() && SM.isFromMainFile(Loc))
+ isMain = true;
+ }
+ if (isMain)
+ isMainCompileUnitCreated = true;
+ }
+
+ unsigned LangTag;
+ if (LO.CPlusPlus) {
+ if (LO.ObjC1)
+ LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus;
+ else
+ LangTag = llvm::dwarf::DW_LANG_C_plus_plus;
+ } else if (LO.ObjC1) {
+ LangTag = llvm::dwarf::DW_LANG_ObjC;
+ } else if (LO.C99) {
+ LangTag = llvm::dwarf::DW_LANG_C99;
+ } else {
+ LangTag = llvm::dwarf::DW_LANG_C89;
+ }
+
+ std::string Producer = "clang 1.0";// FIXME: clang version.
+ bool isOptimized = LO.Optimize;
+ const char *Flags = ""; // FIXME: Encode command line options.
+
+ // Figure out which version of the ObjC runtime we have.
+ unsigned RuntimeVers = 0;
+ if (LO.ObjC1)
+ RuntimeVers = LO.ObjCNonFragileABI ? 2 : 1;
+
+ // Create new compile unit.
+ return Unit = DebugFactory.CreateCompileUnit(LangTag, AbsFileName.getLast(),
+ AbsFileName.getDirname(),
+ Producer, isMain, isOptimized,
+ Flags, RuntimeVers);
+}
+
+/// CreateType - Get the Basic type from the cache or create a new
+/// one if necessary.
+llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT,
+ llvm::DICompileUnit Unit) {
+ unsigned Encoding = 0;
+ switch (BT->getKind()) {
+ default:
+ case BuiltinType::Void:
+ return llvm::DIType();
+ case BuiltinType::UChar:
+ 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::UShort:
+ case BuiltinType::UInt:
+ case BuiltinType::ULong:
+ case BuiltinType::ULongLong: Encoding = llvm::dwarf::DW_ATE_unsigned; break;
+ case BuiltinType::Short:
+ case BuiltinType::Int:
+ case BuiltinType::Long:
+ case BuiltinType::LongLong: Encoding = llvm::dwarf::DW_ATE_signed; break;
+ case BuiltinType::Bool: Encoding = llvm::dwarf::DW_ATE_boolean; break;
+ case BuiltinType::Float:
+ case BuiltinType::Double: Encoding = llvm::dwarf::DW_ATE_float; break;
+ }
+ // Bit size, align and offset of the type.
+ uint64_t Size = M->getContext().getTypeSize(BT);
+ uint64_t Align = M->getContext().getTypeAlign(BT);
+ uint64_t Offset = 0;
+
+ return DebugFactory.CreateBasicType(Unit,
+ BT->getName(M->getContext().getLangOptions().CPlusPlus),
+ Unit, 0, Size, Align,
+ Offset, /*flags*/ 0, Encoding);
+}
+
+llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty,
+ llvm::DICompileUnit Unit) {
+ // Bit size, align and offset of the type.
+ unsigned Encoding = llvm::dwarf::DW_ATE_complex_float;
+ if (Ty->isComplexIntegerType())
+ Encoding = llvm::dwarf::DW_ATE_lo_user;
+
+ uint64_t Size = M->getContext().getTypeSize(Ty);
+ uint64_t Align = M->getContext().getTypeAlign(Ty);
+ uint64_t Offset = 0;
+
+ return DebugFactory.CreateBasicType(Unit, "complex",
+ Unit, 0, Size, Align,
+ Offset, /*flags*/ 0, Encoding);
+}
+
+/// getOrCreateCVRType - Get the CVR qualified type from the cache or create
+/// a new one if necessary.
+llvm::DIType CGDebugInfo::CreateCVRType(QualType Ty, llvm::DICompileUnit Unit) {
+ // We will create one Derived type for one qualifier and recurse to handle any
+ // additional ones.
+ llvm::DIType FromTy;
+ unsigned Tag;
+ if (Ty.isConstQualified()) {
+ Tag = llvm::dwarf::DW_TAG_const_type;
+ Ty.removeConst();
+ FromTy = getOrCreateType(Ty, Unit);
+ } else if (Ty.isVolatileQualified()) {
+ Tag = llvm::dwarf::DW_TAG_volatile_type;
+ Ty.removeVolatile();
+ FromTy = getOrCreateType(Ty, Unit);
+ } else {
+ assert(Ty.isRestrictQualified() && "Unknown type qualifier for debug info");
+ Tag = llvm::dwarf::DW_TAG_restrict_type;
+ Ty.removeRestrict();
+ FromTy = getOrCreateType(Ty, Unit);
+ }
+
+ // No need to fill in the Name, Line, Size, Alignment, Offset in case of
+ // CVR derived types.
+ return DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(),
+ 0, 0, 0, 0, 0, FromTy);
+}
+
+llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty,
+ llvm::DICompileUnit Unit) {
+ llvm::DIType EltTy = getOrCreateType(Ty->getPointeeType(), Unit);
+
+ // Bit size, align and offset of the type.
+ uint64_t Size = M->getContext().getTypeSize(Ty);
+ uint64_t Align = M->getContext().getTypeAlign(Ty);
+
+ return DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit,
+ "", llvm::DICompileUnit(),
+ 0, Size, Align, 0, 0, EltTy);
+}
+
+llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
+ llvm::DICompileUnit Unit) {
+ if (BlockLiteralGenericSet)
+ return BlockLiteralGeneric;
+
+ llvm::DICompileUnit DefUnit;
+ unsigned Tag = llvm::dwarf::DW_TAG_structure_type;
+
+ llvm::SmallVector<llvm::DIDescriptor, 5> EltTys;
+
+ llvm::DIType FieldTy;
+
+ QualType FType;
+ uint64_t FieldSize, FieldOffset;
+ unsigned FieldAlign;
+
+ llvm::DIArray Elements;
+ llvm::DIType EltTy, DescTy;
+
+ FieldOffset = 0;
+ FType = M->getContext().UnsignedLongTy;
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = M->getContext().getTypeSize(FType);
+ FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ "reserved", DefUnit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+
+ FieldOffset += FieldSize;
+ FType = M->getContext().UnsignedLongTy;
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = M->getContext().getTypeSize(FType);
+ FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ "Size", DefUnit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+
+ FieldOffset += FieldSize;
+ Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
+ EltTys.clear();
+
+ EltTy = DebugFactory.CreateCompositeType(Tag, Unit, "__block_descriptor",
+ DefUnit, 0, FieldOffset, 0, 0, 0,
+ llvm::DIType(), Elements);
+
+ // Bit size, align and offset of the type.
+ uint64_t Size = M->getContext().getTypeSize(Ty);
+ uint64_t Align = M->getContext().getTypeAlign(Ty);
+
+ DescTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type,
+ Unit, "", llvm::DICompileUnit(),
+ 0, Size, Align, 0, 0, EltTy);
+
+ FieldOffset = 0;
+ FType = M->getContext().getPointerType(M->getContext().VoidTy);
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = M->getContext().getTypeSize(FType);
+ FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ "__isa", DefUnit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+
+ FieldOffset += FieldSize;
+ FType = M->getContext().IntTy;
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = M->getContext().getTypeSize(FType);
+ FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ "__flags", DefUnit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+
+ FieldOffset += FieldSize;
+ FType = M->getContext().IntTy;
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = M->getContext().getTypeSize(FType);
+ FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ "__reserved", DefUnit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+
+ FieldOffset += FieldSize;
+ FType = M->getContext().getPointerType(M->getContext().VoidTy);
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = M->getContext().getTypeSize(FType);
+ FieldAlign = M->getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ "__FuncPtr", DefUnit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+
+ FieldOffset += FieldSize;
+ FType = M->getContext().getPointerType(M->getContext().VoidTy);
+ FieldTy = DescTy;
+ FieldSize = M->getContext().getTypeSize(Ty);
+ FieldAlign = M->getContext().getTypeAlign(Ty);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ "__descriptor", DefUnit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+
+ FieldOffset += FieldSize;
+ Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
+
+ EltTy = DebugFactory.CreateCompositeType(Tag, Unit, "__block_literal_generic",
+ DefUnit, 0, FieldOffset, 0, 0, 0,
+ llvm::DIType(), Elements);
+
+ BlockLiteralGenericSet = true;
+ BlockLiteralGeneric
+ = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit,
+ "", llvm::DICompileUnit(),
+ 0, Size, Align, 0, 0, EltTy);
+ return BlockLiteralGeneric;
+}
+
+llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
+ llvm::DICompileUnit Unit) {
+ // Typedefs are derived from some other type. If we have a typedef of a
+ // typedef, make sure to emit the whole chain.
+ llvm::DIType Src = getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit);
+
+ // We don't set size information, but do specify where the typedef was
+ // declared.
+ std::string TyName = Ty->getDecl()->getNameAsString();
+ SourceLocation DefLoc = Ty->getDecl()->getLocation();
+ llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc);
+
+ SourceManager &SM = M->getContext().getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(DefLoc);
+ unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine();
+
+ return DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef, Unit,
+ TyName, DefUnit, Line, 0, 0, 0, 0, Src);
+}
+
+llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
+ llvm::DICompileUnit Unit) {
+ llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
+
+ // Add the result type at least.
+ EltTys.push_back(getOrCreateType(Ty->getResultType(), Unit));
+
+ // Set up remainder of arguments if there is a prototype.
+ // FIXME: IF NOT, HOW IS THIS REPRESENTED? llvm-gcc doesn't represent '...'!
+ if (const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(Ty)) {
+ for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
+ EltTys.push_back(getOrCreateType(FTP->getArgType(i), Unit));
+ } else {
+ // FIXME: Handle () case in C. llvm-gcc doesn't do it either.
+ }
+
+ llvm::DIArray EltTypeArray =
+ DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
+
+ return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type,
+ Unit, "", llvm::DICompileUnit(),
+ 0, 0, 0, 0, 0,
+ llvm::DIType(), EltTypeArray);
+}
+
+/// CreateType - get structure or union type.
+llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
+ llvm::DICompileUnit Unit) {
+ RecordDecl *Decl = Ty->getDecl();
+
+ unsigned Tag;
+ if (Decl->isStruct())
+ Tag = llvm::dwarf::DW_TAG_structure_type;
+ else if (Decl->isUnion())
+ Tag = llvm::dwarf::DW_TAG_union_type;
+ else {
+ assert(Decl->isClass() && "Unknown RecordType!");
+ Tag = llvm::dwarf::DW_TAG_class_type;
+ }
+
+ SourceManager &SM = M->getContext().getSourceManager();
+
+ // Get overall information about the record type for the debug info.
+ std::string Name = Decl->getNameAsString();
+
+ PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ llvm::DICompileUnit DefUnit;
+ unsigned Line = 0;
+ if (!PLoc.isInvalid()) {
+ DefUnit = getOrCreateCompileUnit(Decl->getLocation());
+ Line = PLoc.getLine();
+ }
+
+ // Records and classes and unions can all be recursive. To handle them, 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 =
+ DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, 0, 0, 0, 0,
+ llvm::DIType(), llvm::DIArray());
+
+ // If this is just a forward declaration, return it.
+ if (!Decl->getDefinition(M->getContext()))
+ return FwdDecl;
+
+ // Otherwise, insert it into the TypeCache so that recursive uses will find
+ // it.
+ TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
+
+ // Convert all the elements.
+ llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
+
+ const ASTRecordLayout &RL = M->getContext().getASTRecordLayout(Decl);
+
+ unsigned FieldNo = 0;
+ for (RecordDecl::field_iterator I = Decl->field_begin(M->getContext()),
+ E = Decl->field_end(M->getContext());
+ I != E; ++I, ++FieldNo) {
+ FieldDecl *Field = *I;
+ llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
+
+ std::string FieldName = Field->getNameAsString();
+
+ // Ignore unnamed fields.
+ if (FieldName.empty())
+ continue;
+
+ // Get the location for the field.
+ SourceLocation FieldDefLoc = Field->getLocation();
+ PresumedLoc PLoc = SM.getPresumedLoc(FieldDefLoc);
+ llvm::DICompileUnit FieldDefUnit;
+ unsigned FieldLine = 0;
+
+ if (!PLoc.isInvalid()) {
+ FieldDefUnit = getOrCreateCompileUnit(FieldDefLoc);
+ FieldLine = PLoc.getLine();
+ }
+
+ QualType FType = Field->getType();
+ uint64_t FieldSize = 0;
+ unsigned FieldAlign = 0;
+ if (!FType->isIncompleteArrayType()) {
+
+ // Bit size, align and offset of the type.
+ FieldSize = M->getContext().getTypeSize(FType);
+ Expr *BitWidth = Field->getBitWidth();
+ if (BitWidth)
+ FieldSize = BitWidth->EvaluateAsInt(M->getContext()).getZExtValue();
+
+ FieldAlign = M->getContext().getTypeAlign(FType);
+ }
+
+ uint64_t FieldOffset = RL.getFieldOffset(FieldNo);
+
+ // Create a DW_TAG_member node to remember the offset of this field in the
+ // struct. FIXME: This is an absolutely insane way to capture this
+ // information. When we gut debug info, this should be fixed.
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ FieldName, FieldDefUnit,
+ FieldLine, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ }
+
+ llvm::DIArray Elements =
+ DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
+
+ // Bit size, align and offset of the type.
+ uint64_t Size = M->getContext().getTypeSize(Ty);
+ uint64_t Align = M->getContext().getTypeAlign(Ty);
+
+ llvm::DIType RealDecl =
+ DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, Size,
+ Align, 0, 0, llvm::DIType(), Elements);
+
+ // Now that we have a real decl for the struct, replace anything using the
+ // old decl with the new one. This will recursively update the debug info.
+ FwdDecl.getGV()->replaceAllUsesWith(RealDecl.getGV());
+ FwdDecl.getGV()->eraseFromParent();
+
+ return RealDecl;
+}
+
+/// CreateType - get objective-c interface type.
+llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
+ llvm::DICompileUnit Unit) {
+ ObjCInterfaceDecl *Decl = Ty->getDecl();
+
+ unsigned Tag = llvm::dwarf::DW_TAG_structure_type;
+ SourceManager &SM = M->getContext().getSourceManager();
+
+ // Get overall information about the record type for the debug info.
+ std::string Name = Decl->getNameAsString();
+
+ llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(Decl->getLocation());
+ PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine();
+
+
+ unsigned RuntimeLang = DefUnit.getLanguage();
+
+ // 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.
+ llvm::DIType FwdDecl =
+ DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, 0, 0, 0, 0,
+ llvm::DIType(), llvm::DIArray(),
+ RuntimeLang);
+
+ // If this is just a forward declaration, return it.
+ if (Decl->isForwardDecl())
+ return FwdDecl;
+
+ // Otherwise, insert it into the TypeCache so that recursive uses will find
+ // it.
+ TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
+
+ // Convert all the elements.
+ llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
+
+ ObjCInterfaceDecl *SClass = Decl->getSuperClass();
+ if (SClass) {
+ llvm::DIType SClassTy =
+ getOrCreateType(M->getContext().getObjCInterfaceType(SClass), Unit);
+ llvm::DIType InhTag =
+ DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_inheritance,
+ Unit, "", llvm::DICompileUnit(), 0, 0, 0,
+ 0 /* offset */, 0, SClassTy);
+ EltTys.push_back(InhTag);
+ }
+
+ const ASTRecordLayout &RL = M->getContext().getASTObjCInterfaceLayout(Decl);
+
+ unsigned FieldNo = 0;
+ for (ObjCInterfaceDecl::ivar_iterator I = Decl->ivar_begin(),
+ E = Decl->ivar_end(); I != E; ++I, ++FieldNo) {
+ ObjCIvarDecl *Field = *I;
+ llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
+
+ std::string FieldName = Field->getNameAsString();
+
+ // Ignore unnamed fields.
+ if (FieldName.empty())
+ continue;
+
+ // Get the location for the field.
+ SourceLocation FieldDefLoc = Field->getLocation();
+ llvm::DICompileUnit FieldDefUnit = getOrCreateCompileUnit(FieldDefLoc);
+ PresumedLoc PLoc = SM.getPresumedLoc(FieldDefLoc);
+ unsigned FieldLine = PLoc.isInvalid() ? 0 : PLoc.getLine();
+
+
+ QualType FType = Field->getType();
+ uint64_t FieldSize = 0;
+ unsigned FieldAlign = 0;
+
+ if (!FType->isIncompleteArrayType()) {
+
+ // Bit size, align and offset of the type.
+ FieldSize = M->getContext().getTypeSize(FType);
+ Expr *BitWidth = Field->getBitWidth();
+ if (BitWidth)
+ FieldSize = BitWidth->EvaluateAsInt(M->getContext()).getZExtValue();
+
+ FieldAlign = M->getContext().getTypeAlign(FType);
+ }
+
+ uint64_t FieldOffset = RL.getFieldOffset(FieldNo);
+
+ unsigned Flags = 0;
+ if (Field->getAccessControl() == ObjCIvarDecl::Protected)
+ Flags = llvm::DIType::FlagProtected;
+ else if (Field->getAccessControl() == ObjCIvarDecl::Private)
+ Flags = llvm::DIType::FlagPrivate;
+
+ // Create a DW_TAG_member node to remember the offset of this field in the
+ // struct. FIXME: This is an absolutely insane way to capture this
+ // information. When we gut debug info, this should be fixed.
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ FieldName, FieldDefUnit,
+ FieldLine, FieldSize, FieldAlign,
+ FieldOffset, Flags, FieldTy);
+ EltTys.push_back(FieldTy);
+ }
+
+ llvm::DIArray Elements =
+ DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
+
+ // Bit size, align and offset of the type.
+ uint64_t Size = M->getContext().getTypeSize(Ty);
+ uint64_t Align = M->getContext().getTypeAlign(Ty);
+
+ llvm::DIType RealDecl =
+ DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, Size,
+ Align, 0, 0, llvm::DIType(), Elements,
+ RuntimeLang);
+
+ // Now that we have a real decl for the struct, replace anything using the
+ // old decl with the new one. This will recursively update the debug info.
+ FwdDecl.getGV()->replaceAllUsesWith(RealDecl.getGV());
+ FwdDecl.getGV()->eraseFromParent();
+
+ return RealDecl;
+}
+
+llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
+ llvm::DICompileUnit Unit) {
+ EnumDecl *Decl = Ty->getDecl();
+
+ llvm::SmallVector<llvm::DIDescriptor, 32> Enumerators;
+
+ // Create DIEnumerator elements for each enumerator.
+ for (EnumDecl::enumerator_iterator
+ Enum = Decl->enumerator_begin(M->getContext()),
+ EnumEnd = Decl->enumerator_end(M->getContext());
+ Enum != EnumEnd; ++Enum) {
+ Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getNameAsString(),
+ Enum->getInitVal().getZExtValue()));
+ }
+
+ // Return a CompositeType for the enum itself.
+ llvm::DIArray EltArray =
+ DebugFactory.GetOrCreateArray(Enumerators.data(), Enumerators.size());
+
+ std::string EnumName = Decl->getNameAsString();
+ SourceLocation DefLoc = Decl->getLocation();
+ llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc);
+ SourceManager &SM = M->getContext().getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(DefLoc);
+ unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine();
+
+
+ // Size and align of the type.
+ uint64_t Size = 0;
+ unsigned Align = 0;
+ if (!Ty->isIncompleteType()) {
+ Size = M->getContext().getTypeSize(Ty);
+ Align = M->getContext().getTypeAlign(Ty);
+ }
+
+ return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type,
+ Unit, EnumName, DefUnit, Line,
+ Size, Align, 0, 0,
+ llvm::DIType(), EltArray);
+}
+
+llvm::DIType CGDebugInfo::CreateType(const TagType *Ty,
+ llvm::DICompileUnit Unit) {
+ if (const RecordType *RT = dyn_cast<RecordType>(Ty))
+ return CreateType(RT, Unit);
+ else if (const EnumType *ET = dyn_cast<EnumType>(Ty))
+ return CreateType(ET, Unit);
+
+ return llvm::DIType();
+}
+
+llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
+ llvm::DICompileUnit Unit) {
+ uint64_t Size;
+ uint64_t Align;
+
+
+ // FIXME: make getTypeAlign() aware of VLAs and incomplete array types
+ if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(Ty)) {
+ Size = 0;
+ Align =
+ M->getContext().getTypeAlign(M->getContext().getBaseElementType(VAT));
+ } else if (Ty->isIncompleteArrayType()) {
+ Size = 0;
+ Align = M->getContext().getTypeAlign(Ty->getElementType());
+ } else {
+ // Size and align of the whole array, not the element type.
+ Size = M->getContext().getTypeSize(Ty);
+ Align = M->getContext().getTypeAlign(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::DIDescriptor, 8> Subscripts;
+ QualType EltTy(Ty, 0);
+ while ((Ty = dyn_cast<ArrayType>(EltTy))) {
+ uint64_t Upper = 0;
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
+ Upper = CAT->getSize().getZExtValue() - 1;
+ // FIXME: Verify this is right for VLAs.
+ Subscripts.push_back(DebugFactory.GetOrCreateSubrange(0, Upper));
+ EltTy = Ty->getElementType();
+ }
+
+ llvm::DIArray SubscriptArray =
+ DebugFactory.GetOrCreateArray(Subscripts.data(), Subscripts.size());
+
+ return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_array_type,
+ Unit, "", llvm::DICompileUnit(),
+ 0, Size, Align, 0, 0,
+ getOrCreateType(EltTy, Unit),
+ SubscriptArray);
+}
+
+
+/// getOrCreateType - Get the type from the cache or create a new
+/// one if necessary.
+llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
+ llvm::DICompileUnit Unit) {
+ if (Ty.isNull())
+ return llvm::DIType();
+
+ // Check to see if the compile unit already has created this type.
+ llvm::DIType &Slot = TypeCache[Ty.getAsOpaquePtr()];
+ if (!Slot.isNull()) return Slot;
+
+ // Handle CVR qualifiers, which recursively handles what they refer to.
+ if (Ty.getCVRQualifiers())
+ return Slot = CreateCVRType(Ty, Unit);
+
+ // Work out details of type.
+ switch (Ty->getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ assert(false && "Dependent types cannot show up in debug information");
+
+ case Type::LValueReference:
+ case Type::RValueReference:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::ExtQual:
+ case Type::FixedWidthInt:
+ case Type::MemberPointer:
+ case Type::TemplateSpecialization:
+ case Type::QualifiedName:
+ // Unsupported types
+ return llvm::DIType();
+ case Type::ObjCQualifiedId: // Encode id<p> in debug info just like id.
+ return Slot = getOrCreateType(M->getContext().getObjCIdType(), Unit);
+
+ case Type::ObjCQualifiedInterface: // Drop protocols from interface.
+ case Type::ObjCInterface:
+ return Slot = CreateType(cast<ObjCInterfaceType>(Ty), Unit);
+ case Type::Builtin: return Slot = CreateType(cast<BuiltinType>(Ty), Unit);
+ case Type::Complex: return Slot = CreateType(cast<ComplexType>(Ty), Unit);
+ case Type::Pointer: return Slot = CreateType(cast<PointerType>(Ty), Unit);
+ case Type::BlockPointer:
+ return Slot = CreateType(cast<BlockPointerType>(Ty), Unit);
+ case Type::Typedef: return Slot = CreateType(cast<TypedefType>(Ty), Unit);
+ case Type::Record:
+ case Type::Enum:
+ return Slot = CreateType(cast<TagType>(Ty), Unit);
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ return Slot = CreateType(cast<FunctionType>(Ty), Unit);
+
+ case Type::ConstantArray:
+ case Type::VariableArray:
+ case Type::IncompleteArray:
+ return Slot = CreateType(cast<ArrayType>(Ty), Unit);
+ case Type::TypeOfExpr:
+ return Slot = getOrCreateType(cast<TypeOfExprType>(Ty)->getUnderlyingExpr()
+ ->getType(), Unit);
+ case Type::TypeOf:
+ return Slot = getOrCreateType(cast<TypeOfType>(Ty)->getUnderlyingType(),
+ Unit);
+ }
+
+ return Slot;
+}
+
+/// EmitFunctionStart - Constructs the debug code for entering a function -
+/// "llvm.dbg.func.start.".
+void CGDebugInfo::EmitFunctionStart(const char *Name, QualType ReturnType,
+ llvm::Function *Fn,
+ CGBuilderTy &Builder) {
+ const char *LinkageName = Name;
+
+ // Skip the asm prefix if it exists.
+ //
+ // FIXME: This should probably be the unmangled name?
+ if (Name[0] == '\01')
+ ++Name;
+
+ // FIXME: Why is this using CurLoc???
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc);
+ SourceManager &SM = M->getContext().getSourceManager();
+ unsigned LineNo = SM.getPresumedLoc(CurLoc).getLine();
+
+ llvm::DISubprogram SP =
+ DebugFactory.CreateSubprogram(Unit, Name, Name, LinkageName, Unit, LineNo,
+ getOrCreateType(ReturnType, Unit),
+ Fn->hasInternalLinkage(), true/*definition*/);
+
+ DebugFactory.InsertSubprogramStart(SP, Builder.GetInsertBlock());
+
+ // Push function on region stack.
+ RegionStack.push_back(SP);
+}
+
+
+void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) {
+ if (CurLoc.isInvalid() || CurLoc.isMacroID()) return;
+
+ // Don't bother if things are the same as last time.
+ SourceManager &SM = M->getContext().getSourceManager();
+ if (CurLoc == PrevLoc
+ || (SM.getInstantiationLineNumber(CurLoc) ==
+ SM.getInstantiationLineNumber(PrevLoc)
+ && SM.isFromSameFile(CurLoc, PrevLoc)))
+ return;
+
+ // Update last state.
+ PrevLoc = CurLoc;
+
+ // Get the appropriate compile unit.
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc);
+ PresumedLoc PLoc = SM.getPresumedLoc(CurLoc);
+ DebugFactory.InsertStopPoint(Unit, PLoc.getLine(), PLoc.getColumn(),
+ Builder.GetInsertBlock());
+}
+
+/// EmitRegionStart- Constructs the debug code for entering a declarative
+/// region - "llvm.dbg.region.start.".
+void CGDebugInfo::EmitRegionStart(llvm::Function *Fn, CGBuilderTy &Builder) {
+ llvm::DIDescriptor D;
+ if (!RegionStack.empty())
+ D = RegionStack.back();
+ D = DebugFactory.CreateBlock(D);
+ RegionStack.push_back(D);
+ DebugFactory.InsertRegionStart(D, Builder.GetInsertBlock());
+}
+
+/// EmitRegionEnd - Constructs the debug code for exiting a declarative
+/// region - "llvm.dbg.region.end."
+void CGDebugInfo::EmitRegionEnd(llvm::Function *Fn, CGBuilderTy &Builder) {
+ assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
+
+ // Provide an region stop point.
+ EmitStopPoint(Fn, Builder);
+
+ DebugFactory.InsertRegionEnd(RegionStack.back(), Builder.GetInsertBlock());
+ RegionStack.pop_back();
+}
+
+/// EmitDeclare - Emit local variable declaration debug info.
+void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
+ llvm::Value *Storage, CGBuilderTy &Builder) {
+ assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
+
+ // Do not emit variable debug information while generating optimized code.
+ // The llvm optimizer and code generator are not yet ready to support
+ // optimized code debugging.
+ const CompileOptions &CO = M->getCompileOpts();
+ if (CO.OptimizationLevel)
+ return;
+
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
+ llvm::DIType Ty = getOrCreateType(Decl->getType(), Unit);
+
+ // Get location information.
+ SourceManager &SM = M->getContext().getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ unsigned Line = 0;
+ if (!PLoc.isInvalid())
+ Line = PLoc.getLine();
+ else
+ Unit = llvm::DICompileUnit();
+
+
+ // Create the descriptor for the variable.
+ llvm::DIVariable D =
+ DebugFactory.CreateVariable(Tag, RegionStack.back(),Decl->getNameAsString(),
+ Unit, Line, Ty);
+ // Insert an llvm.dbg.declare into the current block.
+ DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock());
+}
+
+void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *Decl,
+ llvm::Value *Storage,
+ CGBuilderTy &Builder) {
+ EmitDeclare(Decl, llvm::dwarf::DW_TAG_auto_variable, Storage, Builder);
+}
+
+/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
+/// variable declaration.
+void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI,
+ CGBuilderTy &Builder) {
+ EmitDeclare(Decl, llvm::dwarf::DW_TAG_arg_variable, AI, Builder);
+}
+
+
+
+/// EmitGlobalVariable - Emit information about a global variable.
+void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
+ const VarDecl *Decl) {
+
+ // Do not emit variable debug information while generating optimized code.
+ // The llvm optimizer and code generator are not yet ready to support
+ // optimized code debugging.
+ const CompileOptions &CO = M->getCompileOpts();
+ if (CO.OptimizationLevel)
+ return;
+
+ // Create global variable debug descriptor.
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
+ SourceManager &SM = M->getContext().getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
+
+ std::string Name = Decl->getNameAsString();
+
+ QualType T = Decl->getType();
+ if (T->isIncompleteArrayType()) {
+
+ // CodeGen turns int[] into int[1] so we'll do the same here.
+ llvm::APSInt ConstVal(32);
+
+ ConstVal = 1;
+ QualType ET = M->getContext().getAsArrayType(T)->getElementType();
+
+ T = M->getContext().getConstantArrayType(ET, ConstVal,
+ ArrayType::Normal, 0);
+ }
+
+ DebugFactory.CreateGlobalVariable(Unit, Name, Name, "", Unit, LineNo,
+ getOrCreateType(T, Unit),
+ Var->hasInternalLinkage(),
+ true/*definition*/, Var);
+}
+
+/// EmitGlobalVariable - Emit information about an objective-c interface.
+void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
+ ObjCInterfaceDecl *Decl) {
+ // Create global variable debug descriptor.
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
+ SourceManager &SM = M->getContext().getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
+
+ std::string Name = Decl->getNameAsString();
+
+ QualType T = M->getContext().getObjCInterfaceType(Decl);
+ if (T->isIncompleteArrayType()) {
+
+ // CodeGen turns int[] into int[1] so we'll do the same here.
+ llvm::APSInt ConstVal(32);
+
+ ConstVal = 1;
+ QualType ET = M->getContext().getAsArrayType(T)->getElementType();
+
+ T = M->getContext().getConstantArrayType(ET, ConstVal,
+ ArrayType::Normal, 0);
+ }
+
+ DebugFactory.CreateGlobalVariable(Unit, Name, Name, "", Unit, LineNo,
+ getOrCreateType(T, Unit),
+ Var->hasInternalLinkage(),
+ true/*definition*/, Var);
+}
+
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
new file mode 100644
index 000000000000..de655800fa08
--- /dev/null
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -0,0 +1,126 @@
+//===--- CGDebugInfo.h - DebugInfo for LLVM CodeGen -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the source level debug info generator for llvm translation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CGDEBUGINFO_H
+#define CLANG_CODEGEN_CGDEBUGINFO_H
+
+#include "clang/AST/Type.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Analysis/DebugInfo.h"
+#include <map>
+
+#include "CGBuilder.h"
+
+namespace clang {
+ class VarDecl;
+ class ObjCInterfaceDecl;
+
+namespace CodeGen {
+ class CodeGenModule;
+
+/// CGDebugInfo - This class gathers all debug information during compilation
+/// and is responsible for emitting to llvm globals or pass directly to
+/// the backend.
+class CGDebugInfo {
+ CodeGenModule *M;
+ bool isMainCompileUnitCreated;
+ llvm::DIFactory DebugFactory;
+
+ SourceLocation CurLoc, PrevLoc;
+
+ /// CompileUnitCache - Cache of previously constructed CompileUnits.
+ llvm::DenseMap<unsigned, llvm::DICompileUnit> CompileUnitCache;
+
+ /// TypeCache - Cache of previously constructed Types.
+ // FIXME: Eliminate this map. Be careful of iterator invalidation.
+ std::map<void *, llvm::DIType> TypeCache;
+
+ bool BlockLiteralGenericSet;
+ llvm::DIType BlockLiteralGeneric;
+
+ std::vector<llvm::DIDescriptor> RegionStack;
+
+ /// Helper functions for getOrCreateType.
+ llvm::DIType CreateType(const BuiltinType *Ty, llvm::DICompileUnit U);
+ llvm::DIType CreateType(const ComplexType *Ty, llvm::DICompileUnit U);
+ llvm::DIType CreateCVRType(QualType Ty, llvm::DICompileUnit U);
+ llvm::DIType CreateType(const TypedefType *Ty, llvm::DICompileUnit U);
+ llvm::DIType CreateType(const PointerType *Ty, llvm::DICompileUnit U);
+ llvm::DIType CreateType(const BlockPointerType *Ty, llvm::DICompileUnit U);
+ llvm::DIType CreateType(const FunctionType *Ty, llvm::DICompileUnit U);
+ llvm::DIType CreateType(const TagType *Ty, llvm::DICompileUnit U);
+ llvm::DIType CreateType(const RecordType *Ty, llvm::DICompileUnit U);
+ llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DICompileUnit U);
+ llvm::DIType CreateType(const EnumType *Ty, llvm::DICompileUnit U);
+ llvm::DIType CreateType(const ArrayType *Ty, llvm::DICompileUnit U);
+
+public:
+ CGDebugInfo(CodeGenModule *m);
+ ~CGDebugInfo();
+
+ /// 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(llvm::Function *Fn, CGBuilderTy &Builder);
+
+ /// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate
+ /// start of a new function.
+ void EmitFunctionStart(const char *Name, QualType ReturnType,
+ llvm::Function *Fn, CGBuilderTy &Builder);
+
+ /// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start
+ /// of a new block.
+ void EmitRegionStart(llvm::Function *Fn, CGBuilderTy &Builder);
+
+ /// EmitRegionEnd - Emit call to llvm.dbg.region.end to indicate end of a
+ /// block.
+ void EmitRegionEnd(llvm::Function *Fn, CGBuilderTy &Builder);
+
+ /// EmitDeclareOfAutoVariable - Emit call to llvm.dbg.declare for an automatic
+ /// variable declaration.
+ void EmitDeclareOfAutoVariable(const VarDecl *Decl, llvm::Value *AI,
+ CGBuilderTy &Builder);
+
+ /// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
+ /// variable declaration.
+ void EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI,
+ CGBuilderTy &Builder);
+
+ /// EmitGlobalVariable - Emit information about a global variable.
+ void EmitGlobalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl);
+
+ /// EmitGlobalVariable - Emit information about an objective-c interface.
+ void EmitGlobalVariable(llvm::GlobalVariable *GV, ObjCInterfaceDecl *Decl);
+
+private:
+ /// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration.
+ void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI,
+ CGBuilderTy &Builder);
+
+
+ /// getOrCreateCompileUnit - Get the compile unit from the cache or create a
+ /// new one if necessary.
+ llvm::DICompileUnit getOrCreateCompileUnit(SourceLocation Loc);
+
+ /// getOrCreateType - Get the type from the cache or create a new type if
+ /// necessary.
+ llvm::DIType getOrCreateType(QualType Ty, llvm::DICompileUnit Unit);
+};
+} // namespace CodeGen
+} // namespace clang
+
+#endif
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
new file mode 100644
index 000000000000..bcad77be51c2
--- /dev/null
+++ b/lib/CodeGen/CGDecl.cpp
@@ -0,0 +1,489 @@
+//===--- CGDecl.cpp - Emit LLVM Code for declarations ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit Decl nodes as LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGDebugInfo.h"
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/GlobalVariable.h"
+#include "llvm/Intrinsics.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Type.h"
+using namespace clang;
+using namespace CodeGen;
+
+
+void CodeGenFunction::EmitDecl(const Decl &D) {
+ switch (D.getKind()) {
+ default: assert(0 && "Unknown decl kind!");
+ case Decl::ParmVar:
+ assert(0 && "Parmdecls should not be in declstmts!");
+ case Decl::Function: // void X();
+ case Decl::Record: // struct/union/class X;
+ case Decl::Enum: // enum X;
+ case Decl::EnumConstant: // enum ? { X = ? }
+ case Decl::CXXRecord: // struct/union/class X; [C++]
+ // None of these decls require codegen support.
+ return;
+
+ case Decl::Var: {
+ const VarDecl &VD = cast<VarDecl>(D);
+ assert(VD.isBlockVarDecl() &&
+ "Should not see file-scope variables inside a function!");
+ return EmitBlockVarDecl(VD);
+ }
+
+ case Decl::Typedef: { // typedef int X;
+ const TypedefDecl &TD = cast<TypedefDecl>(D);
+ QualType Ty = TD.getUnderlyingType();
+
+ if (Ty->isVariablyModifiedType())
+ EmitVLASize(Ty);
+ }
+ }
+}
+
+/// EmitBlockVarDecl - This method handles emission of any variable declaration
+/// inside a function, including static vars etc.
+void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) {
+ if (D.hasAttr<AsmLabelAttr>())
+ CGM.ErrorUnsupported(&D, "__asm__");
+
+ switch (D.getStorageClass()) {
+ case VarDecl::None:
+ case VarDecl::Auto:
+ case VarDecl::Register:
+ return EmitLocalBlockVarDecl(D);
+ case VarDecl::Static:
+ return EmitStaticBlockVarDecl(D);
+ case VarDecl::Extern:
+ case VarDecl::PrivateExtern:
+ // Don't emit it now, allow it to be emitted lazily on its first use.
+ return;
+ }
+
+ assert(0 && "Unknown storage class");
+}
+
+llvm::GlobalVariable *
+CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D,
+ const char *Separator,
+ llvm::GlobalValue::LinkageTypes
+ Linkage) {
+ QualType Ty = D.getType();
+ assert(Ty->isConstantSizeType() && "VLAs can't be static");
+
+ std::string Name;
+ if (getContext().getLangOptions().CPlusPlus) {
+ Name = CGM.getMangledName(&D);
+ } else {
+ std::string ContextName;
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurFuncDecl))
+ ContextName = CGM.getMangledName(FD);
+ else if (isa<ObjCMethodDecl>(CurFuncDecl))
+ ContextName = std::string(CurFn->getNameStart(),
+ CurFn->getNameStart() + CurFn->getNameLen());
+ else
+ assert(0 && "Unknown context for block var decl");
+
+ Name = ContextName + Separator + D.getNameAsString();
+ }
+
+ const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
+ return new llvm::GlobalVariable(LTy, Ty.isConstant(getContext()), Linkage,
+ llvm::Constant::getNullValue(LTy), Name,
+ &CGM.getModule(), D.isThreadSpecified(),
+ Ty.getAddressSpace());
+}
+
+void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
+
+ llvm::Value *&DMEntry = LocalDeclMap[&D];
+ assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
+
+ llvm::GlobalVariable *GV =
+ CreateStaticBlockVarDecl(D, ".", llvm::GlobalValue::InternalLinkage);
+
+ // Store into LocalDeclMap before generating initializer to handle
+ // circular references.
+ DMEntry = GV;
+
+ // Make sure to evaluate VLA bounds now so that we have them for later.
+ if (D.getType()->isVariablyModifiedType())
+ EmitVLASize(D.getType());
+
+ if (D.getType()->isReferenceType()) {
+ CGM.ErrorUnsupported(&D, "static declaration with reference type");
+ return;
+ }
+
+ if (D.getInit()) {
+ llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), D.getType(), this);
+
+ // If constant emission failed, then this should be a C++ static
+ // initializer.
+ if (!Init) {
+ if (!getContext().getLangOptions().CPlusPlus)
+ CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
+ else
+ GenerateStaticCXXBlockVarDeclInit(D, GV);
+ } else {
+ // The initializer may differ in type from the global. Rewrite
+ // the global to match the initializer. (We have to do this
+ // because some types, like unions, can't be completely represented
+ // in the LLVM type system.)
+ if (GV->getType() != Init->getType()) {
+ llvm::GlobalVariable *OldGV = GV;
+
+ GV = new llvm::GlobalVariable(Init->getType(), OldGV->isConstant(),
+ OldGV->getLinkage(), Init, "",
+ &CGM.getModule(), D.isThreadSpecified(),
+ D.getType().getAddressSpace());
+
+ // 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);
+ }
+ }
+
+ // 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 (const SectionAttr *SA = D.getAttr<SectionAttr>())
+ GV->setSection(SA->getName());
+
+ if (D.hasAttr<UsedAttr>())
+ CGM.AddUsedGlobal(GV);
+
+ // We may have to cast the constant because of the initializer
+ // mismatch above.
+ //
+ // 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::PointerType::get(LTy, D.getType().getAddressSpace());
+ DMEntry = llvm::ConstantExpr::getBitCast(GV, LPtrTy);
+
+ // Emit global variable debug descriptor for static vars.
+ CGDebugInfo *DI = getDebugInfo();
+ if (DI) {
+ DI->setLocation(D.getLocation());
+ DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(GV), &D);
+ }
+}
+
+/// BuildByRefType - This routine changes a __block variable declared as T x
+/// into:
+///
+/// struct {
+/// void *__isa;
+/// void *__forwarding;
+/// int32_t __flags;
+/// int32_t __size;
+/// void *__copy_helper;
+/// void *__destroy_helper;
+/// T x;
+/// } x
+///
+/// Align is the alignment needed in bytes for x.
+const llvm::Type *CodeGenFunction::BuildByRefType(QualType Ty,
+ uint64_t Align) {
+ const llvm::Type *LTy = ConvertType(Ty);
+ bool needsCopyDispose = BlockRequiresCopying(Ty);
+ std::vector<const llvm::Type *> Types(needsCopyDispose*2+5);
+ const llvm::PointerType *PtrToInt8Ty
+ = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ Types[0] = PtrToInt8Ty;
+ Types[1] = PtrToInt8Ty;
+ Types[2] = llvm::Type::Int32Ty;
+ Types[3] = llvm::Type::Int32Ty;
+ if (needsCopyDispose) {
+ Types[4] = PtrToInt8Ty;
+ Types[5] = PtrToInt8Ty;
+ }
+ // FIXME: Align this on at least an Align boundary.
+ Types[needsCopyDispose*2 + 4] = LTy;
+ return llvm::StructType::get(Types, false);
+}
+
+/// EmitLocalBlockVarDecl - Emit code and set up an entry in LocalDeclMap for a
+/// variable declaration with auto, register, or no storage class specifier.
+/// These turn into simple stack objects, or GlobalValues depending on target.
+void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
+ QualType Ty = D.getType();
+ bool isByRef = D.hasAttr<BlocksAttr>();
+ bool needsDispose = false;
+
+ llvm::Value *DeclPtr;
+ if (Ty->isConstantSizeType()) {
+ if (!Target.useGlobalsForAutomaticVariables()) {
+ // A normal fixed sized variable becomes an alloca in the entry block.
+ const llvm::Type *LTy = ConvertTypeForMem(Ty);
+ if (isByRef)
+ LTy = BuildByRefType(Ty, getContext().getDeclAlignInBytes(&D));
+ llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
+ Alloc->setName(D.getNameAsString().c_str());
+
+ if (isByRef)
+ Alloc->setAlignment(std::max(getContext().getDeclAlignInBytes(&D),
+ unsigned(Target.getPointerAlign(0) / 8)));
+ else
+ Alloc->setAlignment(getContext().getDeclAlignInBytes(&D));
+ DeclPtr = Alloc;
+ } else {
+ // Targets that don't support recursion emit locals as globals.
+ const char *Class =
+ D.getStorageClass() == VarDecl::Register ? ".reg." : ".auto.";
+ DeclPtr = CreateStaticBlockVarDecl(D, Class,
+ llvm::GlobalValue
+ ::InternalLinkage);
+ }
+
+ if (Ty->isVariablyModifiedType())
+ EmitVLASize(Ty);
+ } else {
+ if (!DidCallStackSave) {
+ // Save the stack.
+ const llvm::Type *LTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ llvm::Value *Stack = CreateTempAlloca(LTy, "saved_stack");
+
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stacksave);
+ llvm::Value *V = Builder.CreateCall(F);
+
+ Builder.CreateStore(V, Stack);
+
+ DidCallStackSave = true;
+
+ {
+ // Push a cleanup block and restore the stack there.
+ CleanupScope scope(*this);
+
+ V = Builder.CreateLoad(Stack, "tmp");
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stackrestore);
+ Builder.CreateCall(F, V);
+ }
+ }
+
+ // Get the element type.
+ const llvm::Type *LElemTy = ConvertTypeForMem(Ty);
+ const llvm::Type *LElemPtrTy =
+ llvm::PointerType::get(LElemTy, D.getType().getAddressSpace());
+
+ llvm::Value *VLASize = EmitVLASize(Ty);
+
+ // Downcast the VLA size expression
+ VLASize = Builder.CreateIntCast(VLASize, llvm::Type::Int32Ty, false, "tmp");
+
+ // Allocate memory for the array.
+ llvm::Value *VLA = Builder.CreateAlloca(llvm::Type::Int8Ty, VLASize, "vla");
+ DeclPtr = Builder.CreateBitCast(VLA, LElemPtrTy, "tmp");
+ }
+
+ llvm::Value *&DMEntry = LocalDeclMap[&D];
+ assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
+ DMEntry = DeclPtr;
+
+ // Emit debug info for local var declaration.
+ if (CGDebugInfo *DI = getDebugInfo()) {
+ DI->setLocation(D.getLocation());
+ if (Target.useGlobalsForAutomaticVariables()) {
+ DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(DeclPtr), &D);
+ }
+ else if (isByRef) {
+ llvm::Value *Loc;
+ bool needsCopyDispose = BlockRequiresCopying(Ty);
+ Loc = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
+ Loc = Builder.CreateLoad(Loc, false);
+ Loc = Builder.CreateBitCast(Loc, DeclPtr->getType());
+ Loc = Builder.CreateStructGEP(Loc, needsCopyDispose*2+4, "x");
+ DI->EmitDeclareOfAutoVariable(&D, Loc, Builder);
+ } else
+ DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
+ }
+
+ // If this local has an initializer, emit it now.
+ if (const Expr *Init = D.getInit()) {
+ llvm::Value *Loc = DeclPtr;
+ if (isByRef) {
+ bool needsCopyDispose = BlockRequiresCopying(Ty);
+ Loc = Builder.CreateStructGEP(DeclPtr, needsCopyDispose*2+4, "x");
+ }
+ if (Ty->isReferenceType()) {
+ llvm::Value *V = EmitReferenceBindingToExpr(Init, Ty).getScalarVal();
+ EmitStoreOfScalar(V, Loc, false, Ty);
+ } else if (!hasAggregateLLVMType(Init->getType())) {
+ llvm::Value *V = EmitScalarExpr(Init);
+ EmitStoreOfScalar(V, Loc, D.getType().isVolatileQualified(),
+ D.getType());
+ } else if (Init->getType()->isAnyComplexType()) {
+ EmitComplexExprIntoAddr(Init, Loc, D.getType().isVolatileQualified());
+ } else {
+ EmitAggExpr(Init, Loc, D.getType().isVolatileQualified());
+ }
+ }
+ if (isByRef) {
+ const llvm::PointerType *PtrToInt8Ty
+ = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+
+ llvm::Value *isa_field = Builder.CreateStructGEP(DeclPtr, 0);
+ llvm::Value *forwarding_field = Builder.CreateStructGEP(DeclPtr, 1);
+ llvm::Value *flags_field = Builder.CreateStructGEP(DeclPtr, 2);
+ llvm::Value *size_field = Builder.CreateStructGEP(DeclPtr, 3);
+ llvm::Value *V;
+ int flag = 0;
+ int flags = 0;
+
+ needsDispose = true;
+
+ if (Ty->isBlockPointerType()) {
+ flag |= BLOCK_FIELD_IS_BLOCK;
+ flags |= BLOCK_HAS_COPY_DISPOSE;
+ } else if (BlockRequiresCopying(Ty)) {
+ flag |= BLOCK_FIELD_IS_OBJECT;
+ flags |= BLOCK_HAS_COPY_DISPOSE;
+ }
+
+ // FIXME: Someone double check this.
+ if (Ty.isObjCGCWeak())
+ flag |= BLOCK_FIELD_IS_WEAK;
+
+ int isa = 0;
+ if (flag&BLOCK_FIELD_IS_WEAK)
+ isa = 1;
+ V = llvm::ConstantInt::get(llvm::Type::Int32Ty, isa);
+ V = Builder.CreateIntToPtr(V, PtrToInt8Ty, "isa");
+ Builder.CreateStore(V, isa_field);
+
+ V = Builder.CreateBitCast(DeclPtr, PtrToInt8Ty, "forwarding");
+ Builder.CreateStore(V, forwarding_field);
+
+ V = llvm::ConstantInt::get(llvm::Type::Int32Ty, flags);
+ Builder.CreateStore(V, flags_field);
+
+ const llvm::Type *V1;
+ V1 = cast<llvm::PointerType>(DeclPtr->getType())->getElementType();
+ V = llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ (CGM.getTargetData().getTypeStoreSizeInBits(V1)
+ / 8));
+ Builder.CreateStore(V, size_field);
+
+ if (flags & BLOCK_HAS_COPY_DISPOSE) {
+ BlockHasCopyDispose = true;
+ llvm::Value *copy_helper = Builder.CreateStructGEP(DeclPtr, 4);
+ Builder.CreateStore(BuildbyrefCopyHelper(DeclPtr->getType(), flag),
+ copy_helper);
+
+ llvm::Value *destroy_helper = Builder.CreateStructGEP(DeclPtr, 5);
+ Builder.CreateStore(BuildbyrefDestroyHelper(DeclPtr->getType(), flag),
+ destroy_helper);
+ }
+ }
+
+ // Handle the cleanup attribute
+ if (const CleanupAttr *CA = D.getAttr<CleanupAttr>()) {
+ const FunctionDecl *FD = CA->getFunctionDecl();
+
+ llvm::Constant* F = CGM.GetAddrOfFunction(GlobalDecl(FD));
+ assert(F && "Could not find function!");
+
+ CleanupScope scope(*this);
+
+ const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD);
+
+ // In some cases, the type of the function argument will be different from
+ // the type of the pointer. An example of this is
+ // void f(void* arg);
+ // __attribute__((cleanup(f))) void *g;
+ //
+ // To fix this we insert a bitcast here.
+ QualType ArgTy = Info.arg_begin()->type;
+ DeclPtr = Builder.CreateBitCast(DeclPtr, ConvertType(ArgTy));
+
+ CallArgList Args;
+ Args.push_back(std::make_pair(RValue::get(DeclPtr),
+ getContext().getPointerType(D.getType())));
+
+ EmitCall(Info, F, Args);
+ }
+
+ if (needsDispose && CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) {
+ CleanupScope scope(*this);
+ llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
+ V = Builder.CreateLoad(V, false);
+ BuildBlockRelease(V);
+ }
+}
+
+/// Emit an alloca (or GlobalValue depending on target)
+/// for the specified parameter and set up LocalDeclMap.
+void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) {
+ // FIXME: Why isn't ImplicitParamDecl a ParmVarDecl?
+ assert((isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)) &&
+ "Invalid argument to EmitParmDecl");
+ QualType Ty = D.getType();
+
+ llvm::Value *DeclPtr;
+ if (!Ty->isConstantSizeType()) {
+ // Variable sized values always are passed by-reference.
+ DeclPtr = Arg;
+ } else {
+ // A fixed sized single-value variable becomes an alloca in the entry block.
+ const llvm::Type *LTy = ConvertTypeForMem(Ty);
+ if (LTy->isSingleValueType()) {
+ // TODO: Alignment
+ std::string Name = D.getNameAsString();
+ Name += ".addr";
+ DeclPtr = CreateTempAlloca(LTy);
+ DeclPtr->setName(Name.c_str());
+
+ // Store the initial value into the alloca.
+ EmitStoreOfScalar(Arg, DeclPtr, Ty.isVolatileQualified(), Ty);
+ } else {
+ // Otherwise, if this is an aggregate, just use the input pointer.
+ DeclPtr = Arg;
+ }
+ Arg->setName(D.getNameAsString());
+ }
+
+ llvm::Value *&DMEntry = LocalDeclMap[&D];
+ assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
+ DMEntry = DeclPtr;
+
+ // Emit debug info for param declaration.
+ if (CGDebugInfo *DI = getDebugInfo()) {
+ DI->setLocation(D.getLocation());
+ DI->EmitDeclareOfArgVariable(&D, DeclPtr, Builder);
+ }
+}
+
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
new file mode 100644
index 000000000000..c5f23879d1c3
--- /dev/null
+++ b/lib/CodeGen/CGExpr.cpp
@@ -0,0 +1,1324 @@
+//===--- CGExpr.cpp - Emit LLVM Code from Expressions ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit Expr nodes as LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "CGCall.h"
+#include "CGObjCRuntime.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "llvm/Target/TargetData.h"
+using namespace clang;
+using namespace CodeGen;
+
+//===--------------------------------------------------------------------===//
+// Miscellaneous Helper Methods
+//===--------------------------------------------------------------------===//
+
+/// CreateTempAlloca - This creates a alloca and inserts it into the entry
+/// block.
+llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty,
+ const char *Name) {
+ if (!Builder.isNamePreserving())
+ Name = "";
+ return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt);
+}
+
+/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
+/// expression and compare the result against zero, returning an Int1Ty value.
+llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) {
+ QualType BoolTy = getContext().BoolTy;
+ if (!E->getType()->isAnyComplexType())
+ return EmitScalarConversion(EmitScalarExpr(E), E->getType(), BoolTy);
+
+ return EmitComplexToScalarConversion(EmitComplexExpr(E), E->getType(),BoolTy);
+}
+
+/// EmitAnyExpr - Emit code to compute the specified expression which can have
+/// any type. The result is returned as an RValue struct. If this is an
+/// aggregate expression, the aggloc/agglocvolatile arguments indicate where
+/// the result should be returned.
+RValue CodeGenFunction::EmitAnyExpr(const Expr *E, llvm::Value *AggLoc,
+ bool isAggLocVolatile, bool IgnoreResult) {
+ if (!hasAggregateLLVMType(E->getType()))
+ return RValue::get(EmitScalarExpr(E, IgnoreResult));
+ else if (E->getType()->isAnyComplexType())
+ return RValue::getComplex(EmitComplexExpr(E, false, false,
+ IgnoreResult, IgnoreResult));
+
+ EmitAggExpr(E, AggLoc, isAggLocVolatile, IgnoreResult);
+ return RValue::getAggregate(AggLoc, isAggLocVolatile);
+}
+
+/// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result
+/// will always be accessible even if no aggregate location is
+/// provided.
+RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E, llvm::Value *AggLoc,
+ bool isAggLocVolatile) {
+ if (!AggLoc && hasAggregateLLVMType(E->getType()) &&
+ !E->getType()->isAnyComplexType())
+ AggLoc = CreateTempAlloca(ConvertType(E->getType()), "agg.tmp");
+ return EmitAnyExpr(E, AggLoc, isAggLocVolatile);
+}
+
+RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
+ QualType DestType) {
+ RValue Val;
+ if (E->isLvalue(getContext()) == Expr::LV_Valid) {
+ // Emit the expr as an lvalue.
+ LValue LV = EmitLValue(E);
+ if (LV.isSimple())
+ return RValue::get(LV.getAddress());
+ Val = EmitLoadOfLValue(LV, E->getType());
+ } else {
+ Val = EmitAnyExprToTemp(E);
+ }
+
+ if (Val.isAggregate()) {
+ Val = RValue::get(Val.getAggregateAddr());
+ } else {
+ // Create a temporary variable that we can bind the reference to.
+ llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()),
+ "reftmp");
+ if (Val.isScalar())
+ EmitStoreOfScalar(Val.getScalarVal(), Temp, false, E->getType());
+ else
+ StoreComplexToAddr(Val.getComplexVal(), Temp, false);
+ Val = RValue::get(Temp);
+ }
+
+ return Val;
+}
+
+
+/// getAccessedFieldNo - Given an encoded value and a result number, return
+/// the input field number being accessed.
+unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx,
+ const llvm::Constant *Elts) {
+ if (isa<llvm::ConstantAggregateZero>(Elts))
+ return 0;
+
+ return cast<llvm::ConstantInt>(Elts->getOperand(Idx))->getZExtValue();
+}
+
+
+//===----------------------------------------------------------------------===//
+// LValue Expression Emission
+//===----------------------------------------------------------------------===//
+
+RValue CodeGenFunction::GetUndefRValue(QualType Ty) {
+ if (Ty->isVoidType()) {
+ return RValue::get(0);
+ } else if (const ComplexType *CTy = Ty->getAsComplexType()) {
+ const llvm::Type *EltTy = ConvertType(CTy->getElementType());
+ llvm::Value *U = llvm::UndefValue::get(EltTy);
+ return RValue::getComplex(std::make_pair(U, U));
+ } else if (hasAggregateLLVMType(Ty)) {
+ const llvm::Type *LTy = llvm::PointerType::getUnqual(ConvertType(Ty));
+ return RValue::getAggregate(llvm::UndefValue::get(LTy));
+ } else {
+ return RValue::get(llvm::UndefValue::get(ConvertType(Ty)));
+ }
+}
+
+RValue CodeGenFunction::EmitUnsupportedRValue(const Expr *E,
+ const char *Name) {
+ ErrorUnsupported(E, Name);
+ return GetUndefRValue(E->getType());
+}
+
+LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E,
+ const char *Name) {
+ ErrorUnsupported(E, Name);
+ llvm::Type *Ty = llvm::PointerType::getUnqual(ConvertType(E->getType()));
+ return LValue::MakeAddr(llvm::UndefValue::get(Ty),
+ E->getType().getCVRQualifiers(),
+ getContext().getObjCGCAttrKind(E->getType()));
+}
+
+/// EmitLValue - Emit code to compute a designator that specifies the location
+/// of the expression.
+///
+/// This can return one of two things: a simple address or a bitfield
+/// reference. In either case, the LLVM Value* in the LValue structure is
+/// guaranteed to be an LLVM pointer type.
+///
+/// If this returns a bitfield reference, nothing about the pointee type of
+/// the LLVM value is known: For example, it may not be a pointer to an
+/// integer.
+///
+/// If this returns a normal address, and if the lvalue's C type is fixed
+/// size, this method guarantees that the returned pointer type will point to
+/// an LLVM type of the same size of the lvalue's type. If the lvalue has a
+/// variable length type, this is not possible.
+///
+LValue CodeGenFunction::EmitLValue(const Expr *E) {
+ switch (E->getStmtClass()) {
+ default: return EmitUnsupportedLValue(E, "l-value expression");
+
+ case Expr::BinaryOperatorClass:
+ return EmitBinaryOperatorLValue(cast<BinaryOperator>(E));
+ case Expr::CallExprClass:
+ case Expr::CXXOperatorCallExprClass:
+ return EmitCallExprLValue(cast<CallExpr>(E));
+ case Expr::VAArgExprClass:
+ return EmitVAArgExprLValue(cast<VAArgExpr>(E));
+ case Expr::DeclRefExprClass:
+ case Expr::QualifiedDeclRefExprClass:
+ return EmitDeclRefLValue(cast<DeclRefExpr>(E));
+ case Expr::ParenExprClass:return EmitLValue(cast<ParenExpr>(E)->getSubExpr());
+ case Expr::PredefinedExprClass:
+ return EmitPredefinedLValue(cast<PredefinedExpr>(E));
+ case Expr::StringLiteralClass:
+ return EmitStringLiteralLValue(cast<StringLiteral>(E));
+ case Expr::ObjCEncodeExprClass:
+ return EmitObjCEncodeExprLValue(cast<ObjCEncodeExpr>(E));
+
+ case Expr::BlockDeclRefExprClass:
+ return EmitBlockDeclRefLValue(cast<BlockDeclRefExpr>(E));
+
+ case Expr::CXXConditionDeclExprClass:
+ return EmitCXXConditionDeclLValue(cast<CXXConditionDeclExpr>(E));
+ case Expr::CXXTemporaryObjectExprClass:
+ case Expr::CXXConstructExprClass:
+ return EmitCXXConstructLValue(cast<CXXConstructExpr>(E));
+ case Expr::CXXBindTemporaryExprClass:
+ return EmitCXXBindTemporaryLValue(cast<CXXBindTemporaryExpr>(E));
+
+ case Expr::ObjCMessageExprClass:
+ return EmitObjCMessageExprLValue(cast<ObjCMessageExpr>(E));
+ case Expr::ObjCIvarRefExprClass:
+ return EmitObjCIvarRefLValue(cast<ObjCIvarRefExpr>(E));
+ case Expr::ObjCPropertyRefExprClass:
+ return EmitObjCPropertyRefLValue(cast<ObjCPropertyRefExpr>(E));
+ case Expr::ObjCKVCRefExprClass:
+ return EmitObjCKVCRefLValue(cast<ObjCKVCRefExpr>(E));
+ case Expr::ObjCSuperExprClass:
+ return EmitObjCSuperExprLValue(cast<ObjCSuperExpr>(E));
+
+ case Expr::StmtExprClass:
+ return EmitStmtExprLValue(cast<StmtExpr>(E));
+ case Expr::UnaryOperatorClass:
+ return EmitUnaryOpLValue(cast<UnaryOperator>(E));
+ case Expr::ArraySubscriptExprClass:
+ return EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E));
+ case Expr::ExtVectorElementExprClass:
+ return EmitExtVectorElementExpr(cast<ExtVectorElementExpr>(E));
+ case Expr::MemberExprClass: return EmitMemberExpr(cast<MemberExpr>(E));
+ case Expr::CompoundLiteralExprClass:
+ return EmitCompoundLiteralLValue(cast<CompoundLiteralExpr>(E));
+ case Expr::ConditionalOperatorClass:
+ return EmitConditionalOperator(cast<ConditionalOperator>(E));
+ case Expr::ChooseExprClass:
+ return EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr(getContext()));
+ case Expr::ImplicitCastExprClass:
+ case Expr::CStyleCastExprClass:
+ case Expr::CXXFunctionalCastExprClass:
+ case Expr::CXXStaticCastExprClass:
+ case Expr::CXXDynamicCastExprClass:
+ case Expr::CXXReinterpretCastExprClass:
+ case Expr::CXXConstCastExprClass:
+ return EmitCastLValue(cast<CastExpr>(E));
+ }
+}
+
+llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
+ QualType Ty) {
+ llvm::Value *V = Builder.CreateLoad(Addr, Volatile, "tmp");
+
+ // Bool can have different representation in memory than in registers.
+ if (Ty->isBooleanType())
+ if (V->getType() != llvm::Type::Int1Ty)
+ V = Builder.CreateTrunc(V, llvm::Type::Int1Ty, "tobool");
+
+ return V;
+}
+
+void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
+ bool Volatile, QualType Ty) {
+
+ if (Ty->isBooleanType()) {
+ // Bool can have different representation in memory than in registers.
+ const llvm::Type *SrcTy = Value->getType();
+ const llvm::PointerType *DstPtr = cast<llvm::PointerType>(Addr->getType());
+ if (DstPtr->getElementType() != SrcTy) {
+ const llvm::Type *MemTy =
+ llvm::PointerType::get(SrcTy, DstPtr->getAddressSpace());
+ Addr = Builder.CreateBitCast(Addr, MemTy, "storetmp");
+ }
+ }
+
+ Builder.CreateStore(Value, Addr, Volatile);
+}
+
+/// EmitLoadOfLValue - Given an expression that represents a value lvalue,
+/// this method emits the address of the lvalue, then loads the result as an
+/// rvalue, returning the rvalue.
+RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) {
+ if (LV.isObjCWeak()) {
+ // load of a __weak object.
+ llvm::Value *AddrWeakObj = LV.getAddress();
+ llvm::Value *read_weak = CGM.getObjCRuntime().EmitObjCWeakRead(*this,
+ AddrWeakObj);
+ return RValue::get(read_weak);
+ }
+
+ if (LV.isSimple()) {
+ llvm::Value *Ptr = LV.getAddress();
+ const llvm::Type *EltTy =
+ cast<llvm::PointerType>(Ptr->getType())->getElementType();
+
+ // Simple scalar l-value.
+ if (EltTy->isSingleValueType())
+ return RValue::get(EmitLoadOfScalar(Ptr, LV.isVolatileQualified(),
+ ExprType));
+
+ assert(ExprType->isFunctionType() && "Unknown scalar value");
+ return RValue::get(Ptr);
+ }
+
+ if (LV.isVectorElt()) {
+ llvm::Value *Vec = Builder.CreateLoad(LV.getVectorAddr(),
+ LV.isVolatileQualified(), "tmp");
+ return RValue::get(Builder.CreateExtractElement(Vec, LV.getVectorIdx(),
+ "vecext"));
+ }
+
+ // If this is a reference to a subset of the elements of a vector, either
+ // shuffle the input or extract/insert them as appropriate.
+ if (LV.isExtVectorElt())
+ return EmitLoadOfExtVectorElementLValue(LV, ExprType);
+
+ if (LV.isBitfield())
+ return EmitLoadOfBitfieldLValue(LV, ExprType);
+
+ if (LV.isPropertyRef())
+ return EmitLoadOfPropertyRefLValue(LV, ExprType);
+
+ assert(LV.isKVCRef() && "Unknown LValue type!");
+ return EmitLoadOfKVCRefLValue(LV, ExprType);
+}
+
+RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV,
+ QualType ExprType) {
+ unsigned StartBit = LV.getBitfieldStartBit();
+ unsigned BitfieldSize = LV.getBitfieldSize();
+ llvm::Value *Ptr = LV.getBitfieldAddr();
+
+ const llvm::Type *EltTy =
+ cast<llvm::PointerType>(Ptr->getType())->getElementType();
+ unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy);
+
+ // In some cases the bitfield may straddle two memory locations.
+ // Currently we load the entire bitfield, then do the magic to
+ // sign-extend it if necessary. This results in somewhat more code
+ // than necessary for the common case (one load), since two shifts
+ // accomplish both the masking and sign extension.
+ unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit);
+ llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(), "tmp");
+
+ // Shift to proper location.
+ if (StartBit)
+ Val = Builder.CreateLShr(Val, llvm::ConstantInt::get(EltTy, StartBit),
+ "bf.lo");
+
+ // Mask off unused bits.
+ llvm::Constant *LowMask =
+ llvm::ConstantInt::get(llvm::APInt::getLowBitsSet(EltTySize, LowBits));
+ Val = Builder.CreateAnd(Val, LowMask, "bf.lo.cleared");
+
+ // Fetch the high bits if necessary.
+ if (LowBits < BitfieldSize) {
+ unsigned HighBits = BitfieldSize - LowBits;
+ llvm::Value *HighPtr =
+ Builder.CreateGEP(Ptr, llvm::ConstantInt::get(llvm::Type::Int32Ty, 1),
+ "bf.ptr.hi");
+ llvm::Value *HighVal = Builder.CreateLoad(HighPtr,
+ LV.isVolatileQualified(),
+ "tmp");
+
+ // Mask off unused bits.
+ llvm::Constant *HighMask =
+ llvm::ConstantInt::get(llvm::APInt::getLowBitsSet(EltTySize, HighBits));
+ HighVal = Builder.CreateAnd(HighVal, HighMask, "bf.lo.cleared");
+
+ // Shift to proper location and or in to bitfield value.
+ HighVal = Builder.CreateShl(HighVal,
+ llvm::ConstantInt::get(EltTy, LowBits));
+ Val = Builder.CreateOr(Val, HighVal, "bf.val");
+ }
+
+ // Sign extend if necessary.
+ if (LV.isBitfieldSigned()) {
+ llvm::Value *ExtraBits = llvm::ConstantInt::get(EltTy,
+ EltTySize - BitfieldSize);
+ Val = Builder.CreateAShr(Builder.CreateShl(Val, ExtraBits),
+ ExtraBits, "bf.val.sext");
+ }
+
+ // The bitfield type and the normal type differ when the storage sizes
+ // differ (currently just _Bool).
+ Val = Builder.CreateIntCast(Val, ConvertType(ExprType), false, "tmp");
+
+ return RValue::get(Val);
+}
+
+RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
+ QualType ExprType) {
+ return EmitObjCPropertyGet(LV.getPropertyRefExpr());
+}
+
+RValue CodeGenFunction::EmitLoadOfKVCRefLValue(LValue LV,
+ QualType ExprType) {
+ return EmitObjCPropertyGet(LV.getKVCRefExpr());
+}
+
+// If this is a reference to a subset of the elements of a vector, create an
+// appropriate shufflevector.
+RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV,
+ QualType ExprType) {
+ llvm::Value *Vec = Builder.CreateLoad(LV.getExtVectorAddr(),
+ LV.isVolatileQualified(), "tmp");
+
+ const llvm::Constant *Elts = LV.getExtVectorElts();
+
+ // If the result of the expression is a non-vector type, we must be
+ // extracting a single element. Just codegen as an extractelement.
+ const VectorType *ExprVT = ExprType->getAsVectorType();
+ if (!ExprVT) {
+ unsigned InIdx = getAccessedFieldNo(0, Elts);
+ llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx);
+ return RValue::get(Builder.CreateExtractElement(Vec, Elt, "tmp"));
+ }
+
+ // Always use shuffle vector to try to retain the original program structure
+ unsigned NumResultElts = ExprVT->getNumElements();
+
+ llvm::SmallVector<llvm::Constant*, 4> Mask;
+ for (unsigned i = 0; i != NumResultElts; ++i) {
+ unsigned InIdx = getAccessedFieldNo(i, Elts);
+ Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx));
+ }
+
+ llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size());
+ Vec = Builder.CreateShuffleVector(Vec,
+ llvm::UndefValue::get(Vec->getType()),
+ MaskV, "tmp");
+ return RValue::get(Vec);
+}
+
+
+
+/// EmitStoreThroughLValue - Store the specified rvalue into the specified
+/// lvalue, where both are guaranteed to the have the same type, and that type
+/// is 'Ty'.
+void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
+ QualType Ty) {
+ if (!Dst.isSimple()) {
+ if (Dst.isVectorElt()) {
+ // Read/modify/write the vector, inserting the new element.
+ llvm::Value *Vec = Builder.CreateLoad(Dst.getVectorAddr(),
+ Dst.isVolatileQualified(), "tmp");
+ Vec = Builder.CreateInsertElement(Vec, Src.getScalarVal(),
+ Dst.getVectorIdx(), "vecins");
+ Builder.CreateStore(Vec, Dst.getVectorAddr(),Dst.isVolatileQualified());
+ return;
+ }
+
+ // If this is an update of extended vector elements, insert them as
+ // appropriate.
+ if (Dst.isExtVectorElt())
+ return EmitStoreThroughExtVectorComponentLValue(Src, Dst, Ty);
+
+ if (Dst.isBitfield())
+ return EmitStoreThroughBitfieldLValue(Src, Dst, Ty);
+
+ if (Dst.isPropertyRef())
+ return EmitStoreThroughPropertyRefLValue(Src, Dst, Ty);
+
+ if (Dst.isKVCRef())
+ return EmitStoreThroughKVCRefLValue(Src, Dst, Ty);
+
+ assert(0 && "Unknown LValue type");
+ }
+
+ if (Dst.isObjCWeak() && !Dst.isNonGC()) {
+ // load of a __weak object.
+ llvm::Value *LvalueDst = Dst.getAddress();
+ llvm::Value *src = Src.getScalarVal();
+ CGM.getObjCRuntime().EmitObjCWeakAssign(*this, src, LvalueDst);
+ return;
+ }
+
+ if (Dst.isObjCStrong() && !Dst.isNonGC()) {
+ // load of a __strong object.
+ llvm::Value *LvalueDst = Dst.getAddress();
+ llvm::Value *src = Src.getScalarVal();
+#if 0
+ // FIXME. We cannot positively determine if we have an 'ivar' assignment,
+ // object assignment or an unknown assignment. For now, generate call to
+ // objc_assign_strongCast assignment which is a safe, but consevative
+ // assumption.
+ if (Dst.isObjCIvar())
+ CGM.getObjCRuntime().EmitObjCIvarAssign(*this, src, LvalueDst);
+ else
+ CGM.getObjCRuntime().EmitObjCGlobalAssign(*this, src, LvalueDst);
+#endif
+ if (Dst.isGlobalObjCRef())
+ CGM.getObjCRuntime().EmitObjCGlobalAssign(*this, src, LvalueDst);
+ else
+ CGM.getObjCRuntime().EmitObjCStrongCastAssign(*this, src, LvalueDst);
+ return;
+ }
+
+ assert(Src.isScalar() && "Can't emit an agg store with this method");
+ EmitStoreOfScalar(Src.getScalarVal(), Dst.getAddress(),
+ Dst.isVolatileQualified(), Ty);
+}
+
+void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
+ QualType Ty,
+ llvm::Value **Result) {
+ unsigned StartBit = Dst.getBitfieldStartBit();
+ unsigned BitfieldSize = Dst.getBitfieldSize();
+ llvm::Value *Ptr = Dst.getBitfieldAddr();
+
+ const llvm::Type *EltTy =
+ cast<llvm::PointerType>(Ptr->getType())->getElementType();
+ unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy);
+
+ // Get the new value, cast to the appropriate type and masked to
+ // exactly the size of the bit-field.
+ llvm::Value *SrcVal = Src.getScalarVal();
+ llvm::Value *NewVal = Builder.CreateIntCast(SrcVal, EltTy, false, "tmp");
+ llvm::Constant *Mask =
+ llvm::ConstantInt::get(llvm::APInt::getLowBitsSet(EltTySize, BitfieldSize));
+ NewVal = Builder.CreateAnd(NewVal, Mask, "bf.value");
+
+ // Return the new value of the bit-field, if requested.
+ if (Result) {
+ // Cast back to the proper type for result.
+ const llvm::Type *SrcTy = SrcVal->getType();
+ llvm::Value *SrcTrunc = Builder.CreateIntCast(NewVal, SrcTy, false,
+ "bf.reload.val");
+
+ // Sign extend if necessary.
+ if (Dst.isBitfieldSigned()) {
+ unsigned SrcTySize = CGM.getTargetData().getTypeSizeInBits(SrcTy);
+ llvm::Value *ExtraBits = llvm::ConstantInt::get(SrcTy,
+ SrcTySize - BitfieldSize);
+ SrcTrunc = Builder.CreateAShr(Builder.CreateShl(SrcTrunc, ExtraBits),
+ ExtraBits, "bf.reload.sext");
+ }
+
+ *Result = SrcTrunc;
+ }
+
+ // In some cases the bitfield may straddle two memory locations.
+ // Emit the low part first and check to see if the high needs to be
+ // done.
+ unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit);
+ llvm::Value *LowVal = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(),
+ "bf.prev.low");
+
+ // Compute the mask for zero-ing the low part of this bitfield.
+ llvm::Constant *InvMask =
+ llvm::ConstantInt::get(~llvm::APInt::getBitsSet(EltTySize, StartBit,
+ StartBit + LowBits));
+
+ // Compute the new low part as
+ // LowVal = (LowVal & InvMask) | (NewVal << StartBit),
+ // with the shift of NewVal implicitly stripping the high bits.
+ llvm::Value *NewLowVal =
+ Builder.CreateShl(NewVal, llvm::ConstantInt::get(EltTy, StartBit),
+ "bf.value.lo");
+ LowVal = Builder.CreateAnd(LowVal, InvMask, "bf.prev.lo.cleared");
+ LowVal = Builder.CreateOr(LowVal, NewLowVal, "bf.new.lo");
+
+ // Write back.
+ Builder.CreateStore(LowVal, Ptr, Dst.isVolatileQualified());
+
+ // If the low part doesn't cover the bitfield emit a high part.
+ if (LowBits < BitfieldSize) {
+ unsigned HighBits = BitfieldSize - LowBits;
+ llvm::Value *HighPtr =
+ Builder.CreateGEP(Ptr, llvm::ConstantInt::get(llvm::Type::Int32Ty, 1),
+ "bf.ptr.hi");
+ llvm::Value *HighVal = Builder.CreateLoad(HighPtr,
+ Dst.isVolatileQualified(),
+ "bf.prev.hi");
+
+ // Compute the mask for zero-ing the high part of this bitfield.
+ llvm::Constant *InvMask =
+ llvm::ConstantInt::get(~llvm::APInt::getLowBitsSet(EltTySize, HighBits));
+
+ // Compute the new high part as
+ // HighVal = (HighVal & InvMask) | (NewVal lshr LowBits),
+ // where the high bits of NewVal have already been cleared and the
+ // shift stripping the low bits.
+ llvm::Value *NewHighVal =
+ Builder.CreateLShr(NewVal, llvm::ConstantInt::get(EltTy, LowBits),
+ "bf.value.high");
+ HighVal = Builder.CreateAnd(HighVal, InvMask, "bf.prev.hi.cleared");
+ HighVal = Builder.CreateOr(HighVal, NewHighVal, "bf.new.hi");
+
+ // Write back.
+ Builder.CreateStore(HighVal, HighPtr, Dst.isVolatileQualified());
+ }
+}
+
+void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src,
+ LValue Dst,
+ QualType Ty) {
+ EmitObjCPropertySet(Dst.getPropertyRefExpr(), Src);
+}
+
+void CodeGenFunction::EmitStoreThroughKVCRefLValue(RValue Src,
+ LValue Dst,
+ QualType Ty) {
+ EmitObjCPropertySet(Dst.getKVCRefExpr(), Src);
+}
+
+void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
+ LValue Dst,
+ QualType Ty) {
+ // 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");
+ const llvm::Constant *Elts = Dst.getExtVectorElts();
+
+ llvm::Value *SrcVal = Src.getScalarVal();
+
+ if (const VectorType *VTy = Ty->getAsVectorType()) {
+ unsigned NumSrcElts = VTy->getNumElements();
+ unsigned NumDstElts =
+ cast<llvm::VectorType>(Vec->getType())->getNumElements();
+ if (NumDstElts == NumSrcElts) {
+ // Use shuffle vector is the src and destination are the same number
+ // of elements
+ llvm::SmallVector<llvm::Constant*, 4> Mask;
+ for (unsigned i = 0; i != NumSrcElts; ++i) {
+ unsigned InIdx = getAccessedFieldNo(i, Elts);
+ Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx));
+ }
+
+ llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size());
+ Vec = Builder.CreateShuffleVector(SrcVal,
+ llvm::UndefValue::get(Vec->getType()),
+ MaskV, "tmp");
+ }
+ 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;
+ unsigned i;
+ for (i = 0; i != NumSrcElts; ++i)
+ ExtMask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, i));
+ for (; i != NumDstElts; ++i)
+ ExtMask.push_back(llvm::UndefValue::get(llvm::Type::Int32Ty));
+ llvm::Value *ExtMaskV = llvm::ConstantVector::get(&ExtMask[0],
+ ExtMask.size());
+ llvm::Value *ExtSrcVal =
+ Builder.CreateShuffleVector(SrcVal,
+ llvm::UndefValue::get(SrcVal->getType()),
+ ExtMaskV, "tmp");
+ // build identity
+ llvm::SmallVector<llvm::Constant*, 4> Mask;
+ for (unsigned i = 0; i != NumDstElts; ++i) {
+ Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, i));
+ }
+ // modify when what gets shuffled in
+ for (unsigned i = 0; i != NumSrcElts; ++i) {
+ unsigned Idx = getAccessedFieldNo(i, Elts);
+ Mask[Idx] =llvm::ConstantInt::get(llvm::Type::Int32Ty, i+NumDstElts);
+ }
+ llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size());
+ Vec = Builder.CreateShuffleVector(Vec, ExtSrcVal, MaskV, "tmp");
+ }
+ else {
+ // We should never shorten the vector
+ assert(0 && "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(llvm::Type::Int32Ty, InIdx);
+ Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt, "tmp");
+ }
+
+ Builder.CreateStore(Vec, Dst.getExtVectorAddr(), Dst.isVolatileQualified());
+}
+
+LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
+ const VarDecl *VD = dyn_cast<VarDecl>(E->getDecl());
+
+ if (VD && (VD->isBlockVarDecl() || isa<ParmVarDecl>(VD) ||
+ isa<ImplicitParamDecl>(VD))) {
+ LValue LV;
+ bool NonGCable = VD->hasLocalStorage() && !VD->hasAttr<BlocksAttr>();
+ if (VD->hasExternalStorage()) {
+ llvm::Value *V = CGM.GetAddrOfGlobalVar(VD);
+ if (VD->getType()->isReferenceType())
+ V = Builder.CreateLoad(V, "tmp");
+ LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(),
+ getContext().getObjCGCAttrKind(E->getType()));
+ }
+ else {
+ llvm::Value *V = LocalDeclMap[VD];
+ assert(V && "DeclRefExpr not entered in LocalDeclMap?");
+ // local variables do not get their gc attribute set.
+ QualType::GCAttrTypes attr = QualType::GCNone;
+ // local static?
+ if (!NonGCable)
+ attr = getContext().getObjCGCAttrKind(E->getType());
+ if (VD->hasAttr<BlocksAttr>()) {
+ bool needsCopyDispose = BlockRequiresCopying(VD->getType());
+ const llvm::Type *PtrStructTy = V->getType();
+ const llvm::Type *Ty = PtrStructTy;
+ Ty = llvm::PointerType::get(Ty, 0);
+ V = Builder.CreateStructGEP(V, 1, "forwarding");
+ V = Builder.CreateBitCast(V, Ty);
+ V = Builder.CreateLoad(V, false);
+ V = Builder.CreateBitCast(V, PtrStructTy);
+ V = Builder.CreateStructGEP(V, needsCopyDispose*2 + 4, "x");
+ }
+ if (VD->getType()->isReferenceType())
+ V = Builder.CreateLoad(V, "tmp");
+ LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(), attr);
+ }
+ LValue::SetObjCNonGC(LV, NonGCable);
+ return LV;
+ } else if (VD && VD->isFileVarDecl()) {
+ llvm::Value *V = CGM.GetAddrOfGlobalVar(VD);
+ if (VD->getType()->isReferenceType())
+ V = Builder.CreateLoad(V, "tmp");
+ LValue LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(),
+ getContext().getObjCGCAttrKind(E->getType()));
+ if (LV.isObjCStrong())
+ LV.SetGlobalObjCRef(LV, true);
+ return LV;
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(E->getDecl())) {
+ llvm::Value* V = CGM.GetAddrOfFunction(GlobalDecl(FD));
+ if (!FD->hasPrototype()) {
+ if (const FunctionProtoType *Proto =
+ FD->getType()->getAsFunctionProtoType()) {
+ // Ugly case: for a K&R-style definition, the type of the definition
+ // isn't the same as the type of a use. Correct for this with a
+ // bitcast.
+ QualType NoProtoType =
+ getContext().getFunctionNoProtoType(Proto->getResultType());
+ NoProtoType = getContext().getPointerType(NoProtoType);
+ V = Builder.CreateBitCast(V, ConvertType(NoProtoType), "tmp");
+ }
+ }
+ return LValue::MakeAddr(V, E->getType().getCVRQualifiers(),
+ getContext().getObjCGCAttrKind(E->getType()));
+ }
+ else if (const ImplicitParamDecl *IPD =
+ dyn_cast<ImplicitParamDecl>(E->getDecl())) {
+ llvm::Value *V = LocalDeclMap[IPD];
+ assert(V && "BlockVarDecl not entered in LocalDeclMap?");
+ return LValue::MakeAddr(V, E->getType().getCVRQualifiers(),
+ getContext().getObjCGCAttrKind(E->getType()));
+ }
+ assert(0 && "Unimp declref");
+ //an invalid LValue, but the assert will
+ //ensure that this point is never reached.
+ return LValue();
+}
+
+LValue CodeGenFunction::EmitBlockDeclRefLValue(const BlockDeclRefExpr *E) {
+ return LValue::MakeAddr(GetAddrOfBlockDecl(E),
+ E->getType().getCVRQualifiers(),
+ getContext().getObjCGCAttrKind(E->getType()));
+}
+
+LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
+ // __extension__ doesn't affect lvalue-ness.
+ if (E->getOpcode() == UnaryOperator::Extension)
+ return EmitLValue(E->getSubExpr());
+
+ QualType ExprTy = getContext().getCanonicalType(E->getSubExpr()->getType());
+ switch (E->getOpcode()) {
+ default: assert(0 && "Unknown unary operator lvalue!");
+ case UnaryOperator::Deref:
+ {
+ QualType T =
+ E->getSubExpr()->getType()->getAsPointerType()->getPointeeType();
+ LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()),
+ ExprTy->getAsPointerType()->getPointeeType()
+ .getCVRQualifiers(),
+ getContext().getObjCGCAttrKind(T));
+ // We should not generate __weak write barrier on indirect reference
+ // of a pointer to object; as in void foo (__weak id *param); *param = 0;
+ // But, we continue to generate __strong write barrier on indirect write
+ // into a pointer to object.
+ if (getContext().getLangOptions().ObjC1 &&
+ getContext().getLangOptions().getGCMode() != LangOptions::NonGC &&
+ LV.isObjCWeak())
+ LValue::SetObjCNonGC(LV, !E->isOBJCGCCandidate(getContext()));
+ return LV;
+ }
+ case UnaryOperator::Real:
+ case UnaryOperator::Imag:
+ LValue LV = EmitLValue(E->getSubExpr());
+ unsigned Idx = E->getOpcode() == UnaryOperator::Imag;
+ return LValue::MakeAddr(Builder.CreateStructGEP(LV.getAddress(),
+ Idx, "idx"),
+ ExprTy.getCVRQualifiers());
+ }
+}
+
+LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) {
+ return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromLiteral(E), 0);
+}
+
+LValue CodeGenFunction::EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E) {
+ return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromObjCEncode(E), 0);
+}
+
+
+LValue CodeGenFunction::EmitPredefinedFunctionName(unsigned Type) {
+ std::string GlobalVarName;
+
+ switch (Type) {
+ default:
+ assert(0 && "Invalid type");
+ case PredefinedExpr::Func:
+ GlobalVarName = "__func__.";
+ break;
+ case PredefinedExpr::Function:
+ GlobalVarName = "__FUNCTION__.";
+ break;
+ case PredefinedExpr::PrettyFunction:
+ // FIXME:: Demangle C++ method names
+ GlobalVarName = "__PRETTY_FUNCTION__.";
+ break;
+ }
+
+ // FIXME: This isn't right at all. The logic for computing this should go
+ // into a method on PredefinedExpr. This would allow sema and codegen to be
+ // consistent for things like sizeof(__func__) etc.
+ std::string FunctionName;
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurCodeDecl)) {
+ FunctionName = CGM.getMangledName(FD);
+ } else {
+ // Just get the mangled name; skipping the asm prefix if it
+ // exists.
+ FunctionName = CurFn->getName();
+ if (FunctionName[0] == '\01')
+ FunctionName = FunctionName.substr(1, std::string::npos);
+ }
+
+ GlobalVarName += FunctionName;
+ llvm::Constant *C =
+ CGM.GetAddrOfConstantCString(FunctionName, GlobalVarName.c_str());
+ return LValue::MakeAddr(C, 0);
+}
+
+LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
+ switch (E->getIdentType()) {
+ default:
+ return EmitUnsupportedLValue(E, "predefined expression");
+ case PredefinedExpr::Func:
+ case PredefinedExpr::Function:
+ case PredefinedExpr::PrettyFunction:
+ return EmitPredefinedFunctionName(E->getIdentType());
+ }
+}
+
+LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+ // The index must always be an integer, which is not an aggregate. Emit it.
+ llvm::Value *Idx = EmitScalarExpr(E->getIdx());
+
+ // If the base is a vector type, then we are forming a vector element lvalue
+ // with this subscript.
+ if (E->getBase()->getType()->isVectorType()) {
+ // Emit the vector as an lvalue to get its address.
+ LValue LHS = EmitLValue(E->getBase());
+ assert(LHS.isSimple() && "Can only subscript lvalue vectors here!");
+ // FIXME: This should properly sign/zero/extend or truncate Idx to i32.
+ return LValue::MakeVectorElt(LHS.getAddress(), Idx,
+ E->getBase()->getType().getCVRQualifiers());
+ }
+
+ // The base must be a pointer, which is not an aggregate. Emit it.
+ llvm::Value *Base = EmitScalarExpr(E->getBase());
+
+ // Extend or truncate the index type to 32 or 64-bits.
+ QualType IdxTy = E->getIdx()->getType();
+ bool IdxSigned = IdxTy->isSignedIntegerType();
+ unsigned IdxBitwidth = cast<llvm::IntegerType>(Idx->getType())->getBitWidth();
+ if (IdxBitwidth != LLVMPointerWidth)
+ Idx = Builder.CreateIntCast(Idx, llvm::IntegerType::get(LLVMPointerWidth),
+ IdxSigned, "idxprom");
+
+ // We know that the pointer points to a type of the correct size,
+ // unless the size is a VLA or Objective-C interface.
+ llvm::Value *Address = 0;
+ if (const VariableArrayType *VAT =
+ getContext().getAsVariableArrayType(E->getType())) {
+ llvm::Value *VLASize = VLASizeMap[VAT];
+
+ Idx = Builder.CreateMul(Idx, VLASize);
+
+ QualType BaseType = getContext().getBaseElementType(VAT);
+
+ uint64_t BaseTypeSize = getContext().getTypeSize(BaseType) / 8;
+ Idx = Builder.CreateUDiv(Idx,
+ llvm::ConstantInt::get(Idx->getType(),
+ BaseTypeSize));
+ Address = Builder.CreateGEP(Base, Idx, "arrayidx");
+ } else if (const ObjCInterfaceType *OIT =
+ dyn_cast<ObjCInterfaceType>(E->getType())) {
+ llvm::Value *InterfaceSize =
+ llvm::ConstantInt::get(Idx->getType(),
+ getContext().getTypeSize(OIT) / 8);
+
+ Idx = Builder.CreateMul(Idx, InterfaceSize);
+
+ llvm::Type *i8PTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ Address = Builder.CreateGEP(Builder.CreateBitCast(Base, i8PTy),
+ Idx, "arrayidx");
+ Address = Builder.CreateBitCast(Address, Base->getType());
+ } else {
+ Address = Builder.CreateGEP(Base, Idx, "arrayidx");
+ }
+
+ QualType T = E->getBase()->getType()->getAsPointerType()->getPointeeType();
+ LValue LV = LValue::MakeAddr(Address,
+ T.getCVRQualifiers(),
+ getContext().getObjCGCAttrKind(T));
+ if (getContext().getLangOptions().ObjC1 &&
+ getContext().getLangOptions().getGCMode() != LangOptions::NonGC)
+ LValue::SetObjCNonGC(LV, !E->isOBJCGCCandidate(getContext()));
+ return LV;
+}
+
+static
+llvm::Constant *GenerateConstantVector(llvm::SmallVector<unsigned, 4> &Elts) {
+ llvm::SmallVector<llvm::Constant *, 4> CElts;
+
+ for (unsigned i = 0, e = Elts.size(); i != e; ++i)
+ CElts.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, Elts[i]));
+
+ return llvm::ConstantVector::get(&CElts[0], CElts.size());
+}
+
+LValue CodeGenFunction::
+EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
+ // Emit the base vector as an l-value.
+ LValue Base;
+
+ // ExtVectorElementExpr's base can either be a vector or pointer to vector.
+ if (!E->isArrow()) {
+ assert(E->getBase()->getType()->isVectorType());
+ Base = EmitLValue(E->getBase());
+ } else {
+ const PointerType *PT = E->getBase()->getType()->getAsPointerType();
+ llvm::Value *Ptr = EmitScalarExpr(E->getBase());
+ Base = LValue::MakeAddr(Ptr, PT->getPointeeType().getCVRQualifiers());
+ }
+
+ // Encode the element access list into a vector of unsigned indices.
+ llvm::SmallVector<unsigned, 4> Indices;
+ E->getEncodedElementAccess(Indices);
+
+ if (Base.isSimple()) {
+ llvm::Constant *CV = GenerateConstantVector(Indices);
+ return LValue::MakeExtVectorElt(Base.getAddress(), CV,
+ Base.getQualifiers());
+ }
+ assert(Base.isExtVectorElt() && "Can only subscript lvalue vec elts here!");
+
+ llvm::Constant *BaseElts = Base.getExtVectorElts();
+ llvm::SmallVector<llvm::Constant *, 4> CElts;
+
+ for (unsigned i = 0, e = Indices.size(); i != e; ++i) {
+ if (isa<llvm::ConstantAggregateZero>(BaseElts))
+ CElts.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0));
+ else
+ CElts.push_back(BaseElts->getOperand(Indices[i]));
+ }
+ llvm::Constant *CV = llvm::ConstantVector::get(&CElts[0], CElts.size());
+ return LValue::MakeExtVectorElt(Base.getExtVectorAddr(), CV,
+ Base.getQualifiers());
+}
+
+LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
+ bool isUnion = false;
+ bool isIvar = false;
+ bool isNonGC = false;
+ Expr *BaseExpr = E->getBase();
+ llvm::Value *BaseValue = NULL;
+ unsigned CVRQualifiers=0;
+
+ // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
+ if (E->isArrow()) {
+ BaseValue = EmitScalarExpr(BaseExpr);
+ const PointerType *PTy =
+ BaseExpr->getType()->getAsPointerType();
+ if (PTy->getPointeeType()->isUnionType())
+ isUnion = true;
+ CVRQualifiers = PTy->getPointeeType().getCVRQualifiers();
+ } else if (isa<ObjCPropertyRefExpr>(BaseExpr) ||
+ isa<ObjCKVCRefExpr>(BaseExpr)) {
+ RValue RV = EmitObjCPropertyGet(BaseExpr);
+ BaseValue = RV.getAggregateAddr();
+ if (BaseExpr->getType()->isUnionType())
+ isUnion = true;
+ CVRQualifiers = BaseExpr->getType().getCVRQualifiers();
+ } else {
+ LValue BaseLV = EmitLValue(BaseExpr);
+ if (BaseLV.isObjCIvar())
+ isIvar = true;
+ if (BaseLV.isNonGC())
+ isNonGC = true;
+ // FIXME: this isn't right for bitfields.
+ BaseValue = BaseLV.getAddress();
+ if (BaseExpr->getType()->isUnionType())
+ isUnion = true;
+ CVRQualifiers = BaseExpr->getType().getCVRQualifiers();
+ }
+
+ FieldDecl *Field = dyn_cast<FieldDecl>(E->getMemberDecl());
+ // FIXME: Handle non-field member expressions
+ assert(Field && "No code generation for non-field member references");
+ LValue MemExpLV = EmitLValueForField(BaseValue, Field, isUnion,
+ CVRQualifiers);
+ LValue::SetObjCIvar(MemExpLV, isIvar);
+ LValue::SetObjCNonGC(MemExpLV, isNonGC);
+ return MemExpLV;
+}
+
+LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue,
+ FieldDecl* Field,
+ unsigned CVRQualifiers) {
+ unsigned idx = CGM.getTypes().getLLVMFieldNo(Field);
+ // FIXME: CodeGenTypes should expose a method to get the appropriate type for
+ // FieldTy (the appropriate type is ABI-dependent).
+ const llvm::Type *FieldTy =
+ CGM.getTypes().ConvertTypeForMem(Field->getType());
+ const llvm::PointerType *BaseTy =
+ cast<llvm::PointerType>(BaseValue->getType());
+ unsigned AS = BaseTy->getAddressSpace();
+ BaseValue = Builder.CreateBitCast(BaseValue,
+ llvm::PointerType::get(FieldTy, AS),
+ "tmp");
+ llvm::Value *V = Builder.CreateGEP(BaseValue,
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, idx),
+ "tmp");
+
+ CodeGenTypes::BitFieldInfo bitFieldInfo =
+ CGM.getTypes().getBitFieldInfo(Field);
+ return LValue::MakeBitfield(V, bitFieldInfo.Begin, bitFieldInfo.Size,
+ Field->getType()->isSignedIntegerType(),
+ Field->getType().getCVRQualifiers()|CVRQualifiers);
+}
+
+LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue,
+ FieldDecl* Field,
+ bool isUnion,
+ unsigned CVRQualifiers)
+{
+ if (Field->isBitField())
+ return EmitLValueForBitfield(BaseValue, Field, CVRQualifiers);
+
+ unsigned idx = CGM.getTypes().getLLVMFieldNo(Field);
+ llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp");
+
+ // Match union field type.
+ if (isUnion) {
+ const llvm::Type *FieldTy =
+ CGM.getTypes().ConvertTypeForMem(Field->getType());
+ const llvm::PointerType * BaseTy =
+ cast<llvm::PointerType>(BaseValue->getType());
+ unsigned AS = BaseTy->getAddressSpace();
+ V = Builder.CreateBitCast(V,
+ llvm::PointerType::get(FieldTy, AS),
+ "tmp");
+ }
+ if (Field->getType()->isReferenceType())
+ V = Builder.CreateLoad(V, "tmp");
+
+ QualType::GCAttrTypes attr = QualType::GCNone;
+ if (CGM.getLangOptions().ObjC1 &&
+ CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ QualType Ty = Field->getType();
+ attr = Ty.getObjCGCAttr();
+ if (attr != QualType::GCNone) {
+ // __weak attribute on a field is ignored.
+ if (attr == QualType::Weak)
+ attr = QualType::GCNone;
+ }
+ else if (getContext().isObjCObjectPointerType(Ty))
+ attr = QualType::Strong;
+ }
+ LValue LV =
+ LValue::MakeAddr(V,
+ Field->getType().getCVRQualifiers()|CVRQualifiers,
+ attr);
+ return LV;
+}
+
+LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){
+ const llvm::Type *LTy = ConvertType(E->getType());
+ llvm::Value *DeclPtr = CreateTempAlloca(LTy, ".compoundliteral");
+
+ const Expr* InitExpr = E->getInitializer();
+ LValue Result = LValue::MakeAddr(DeclPtr, E->getType().getCVRQualifiers());
+
+ if (E->getType()->isComplexType()) {
+ EmitComplexExprIntoAddr(InitExpr, DeclPtr, false);
+ } else if (hasAggregateLLVMType(E->getType())) {
+ EmitAnyExpr(InitExpr, DeclPtr, false);
+ } else {
+ EmitStoreThroughLValue(EmitAnyExpr(InitExpr), Result, E->getType());
+ }
+
+ return Result;
+}
+
+LValue CodeGenFunction::EmitConditionalOperator(const ConditionalOperator* E) {
+ // We don't handle vectors yet.
+ if (E->getType()->isVectorType())
+ return EmitUnsupportedLValue(E, "conditional operator");
+
+ // ?: here should be an aggregate.
+ assert((hasAggregateLLVMType(E->getType()) &&
+ !E->getType()->isAnyComplexType()) &&
+ "Unexpected conditional operator!");
+
+ llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType()));
+ EmitAggExpr(E, Temp, false);
+
+ return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(),
+ getContext().getObjCGCAttrKind(E->getType()));
+
+}
+
+/// EmitCastLValue - Casts are never lvalues. If a cast is needed by the code
+/// generator in an lvalue context, then it must mean that we need the address
+/// of an aggregate in order to access one of its fields. This can happen for
+/// all the reasons that casts are permitted with aggregate result, including
+/// noop aggregate casts, and cast from scalar to union.
+LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
+ // If this is an aggregate-to-aggregate cast, just use the input's address as
+ // the lvalue.
+ if (getContext().hasSameUnqualifiedType(E->getType(),
+ E->getSubExpr()->getType()))
+ return EmitLValue(E->getSubExpr());
+
+ // Otherwise, we must have a cast from scalar to union.
+ assert(E->getType()->isUnionType() && "Expected scalar-to-union cast");
+
+ // Casts are only lvalues when the source and destination types are the same.
+ llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType()));
+ EmitAnyExpr(E->getSubExpr(), Temp, false);
+
+ return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(),
+ getContext().getObjCGCAttrKind(E->getType()));
+}
+
+//===--------------------------------------------------------------------===//
+// Expression Emission
+//===--------------------------------------------------------------------===//
+
+
+RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) {
+ // Builtins never have block type.
+ if (E->getCallee()->getType()->isBlockPointerType())
+ return EmitBlockCallExpr(E);
+
+ if (const CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(E))
+ return EmitCXXMemberCallExpr(CE);
+
+ 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(getContext()))
+ return EmitBuiltinExpr(FD, builtinID, E);
+ }
+ }
+
+ if (const CXXOperatorCallExpr *CE = dyn_cast<CXXOperatorCallExpr>(E)) {
+ if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(TargetDecl))
+ return EmitCXXOperatorMemberCallExpr(CE, MD);
+ }
+
+ llvm::Value *Callee = EmitScalarExpr(E->getCallee());
+ return EmitCall(Callee, E->getCallee()->getType(),
+ E->arg_begin(), E->arg_end(), TargetDecl);
+}
+
+LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
+ // Comma expressions just emit their LHS then their RHS as an l-value.
+ if (E->getOpcode() == BinaryOperator::Comma) {
+ EmitAnyExpr(E->getLHS());
+ return EmitLValue(E->getRHS());
+ }
+
+ // Can only get l-value for binary operator expressions which are a
+ // simple assignment of aggregate type.
+ if (E->getOpcode() != BinaryOperator::Assign)
+ return EmitUnsupportedLValue(E, "binary l-value expression");
+
+ llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType()));
+ EmitAggExpr(E, Temp, false);
+ // FIXME: Are these qualifiers correct?
+ return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(),
+ getContext().getObjCGCAttrKind(E->getType()));
+}
+
+LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
+ RValue RV = EmitCallExpr(E);
+
+ if (RV.isScalar()) {
+ assert(E->getCallReturnType()->isReferenceType() &&
+ "Can't have a scalar return unless the return type is a "
+ "reference type!");
+
+ return LValue::MakeAddr(RV.getScalarVal(), E->getType().getCVRQualifiers(),
+ getContext().getObjCGCAttrKind(E->getType()));
+ }
+
+ return LValue::MakeAddr(RV.getAggregateAddr(),
+ E->getType().getCVRQualifiers(),
+ getContext().getObjCGCAttrKind(E->getType()));
+}
+
+LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) {
+ // FIXME: This shouldn't require another copy.
+ llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType()));
+ EmitAggExpr(E, Temp, false);
+ return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers());
+}
+
+LValue
+CodeGenFunction::EmitCXXConditionDeclLValue(const CXXConditionDeclExpr *E) {
+ EmitLocalBlockVarDecl(*E->getVarDecl());
+ return EmitDeclRefLValue(E);
+}
+
+LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) {
+ llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()), "tmp");
+ EmitCXXConstructExpr(Temp, E);
+ return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers());
+}
+
+LValue
+CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) {
+ LValue LV = EmitLValue(E->getSubExpr());
+
+ PushCXXTemporary(E->getTemporary(), LV.getAddress());
+
+ return LV;
+}
+
+LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) {
+ // Can only get l-value for message expression returning aggregate type
+ RValue RV = EmitObjCMessageExpr(E);
+ // FIXME: can this be volatile?
+ return LValue::MakeAddr(RV.getAggregateAddr(),
+ E->getType().getCVRQualifiers(),
+ getContext().getObjCGCAttrKind(E->getType()));
+}
+
+llvm::Value *CodeGenFunction::EmitIvarOffset(const ObjCInterfaceDecl *Interface,
+ const ObjCIvarDecl *Ivar) {
+ return CGM.getObjCRuntime().EmitIvarOffset(*this, Interface, Ivar);
+}
+
+LValue CodeGenFunction::EmitLValueForIvar(QualType ObjectTy,
+ llvm::Value *BaseValue,
+ const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers) {
+ return CGM.getObjCRuntime().EmitObjCValueForIvar(*this, ObjectTy, BaseValue,
+ Ivar, CVRQualifiers);
+}
+
+LValue CodeGenFunction::EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E) {
+ // FIXME: A lot of the code below could be shared with EmitMemberExpr.
+ llvm::Value *BaseValue = 0;
+ const Expr *BaseExpr = E->getBase();
+ unsigned CVRQualifiers = 0;
+ QualType ObjectTy;
+ if (E->isArrow()) {
+ BaseValue = EmitScalarExpr(BaseExpr);
+ const PointerType *PTy = BaseExpr->getType()->getAsPointerType();
+ ObjectTy = PTy->getPointeeType();
+ CVRQualifiers = ObjectTy.getCVRQualifiers();
+ } else {
+ LValue BaseLV = EmitLValue(BaseExpr);
+ // FIXME: this isn't right for bitfields.
+ BaseValue = BaseLV.getAddress();
+ ObjectTy = BaseExpr->getType();
+ CVRQualifiers = ObjectTy.getCVRQualifiers();
+ }
+
+ return EmitLValueForIvar(ObjectTy, BaseValue, E->getDecl(), CVRQualifiers);
+}
+
+LValue
+CodeGenFunction::EmitObjCPropertyRefLValue(const ObjCPropertyRefExpr *E) {
+ // This is a special l-value that just issues sends when we load or
+ // store through it.
+ return LValue::MakePropertyRef(E, E->getType().getCVRQualifiers());
+}
+
+LValue
+CodeGenFunction::EmitObjCKVCRefLValue(const ObjCKVCRefExpr *E) {
+ // This is a special l-value that just issues sends when we load or
+ // store through it.
+ return LValue::MakeKVCRef(E, E->getType().getCVRQualifiers());
+}
+
+LValue
+CodeGenFunction::EmitObjCSuperExprLValue(const ObjCSuperExpr *E) {
+ return EmitUnsupportedLValue(E, "use of super");
+}
+
+LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
+
+ // Can only get l-value for message expression returning aggregate type
+ RValue RV = EmitAnyExprToTemp(E);
+ // FIXME: can this be volatile?
+ return LValue::MakeAddr(RV.getAggregateAddr(),
+ E->getType().getCVRQualifiers(),
+ getContext().getObjCGCAttrKind(E->getType()));
+}
+
+
+RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd,
+ const Decl *TargetDecl) {
+ // Get the actual function type. The callee type will always be a
+ // pointer to function type or a block pointer type.
+ assert(CalleeType->isFunctionPointerType() &&
+ "Call must have function pointer type!");
+
+ QualType FnType = CalleeType->getAsPointerType()->getPointeeType();
+ QualType ResultType = FnType->getAsFunctionType()->getResultType();
+
+ CallArgList Args;
+ EmitCallArgs(Args, FnType->getAsFunctionProtoType(), ArgBeg, ArgEnd);
+
+ return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args),
+ Callee, Args, TargetDecl);
+}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
new file mode 100644
index 000000000000..469c8306b9dd
--- /dev/null
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -0,0 +1,554 @@
+//===--- CGExprAgg.cpp - Emit LLVM Code from Aggregate Expressions --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit Aggregate Expr nodes as LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/Constants.h"
+#include "llvm/Function.h"
+#include "llvm/GlobalVariable.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Intrinsics.h"
+using namespace clang;
+using namespace CodeGen;
+
+//===----------------------------------------------------------------------===//
+// Aggregate Expression Emitter
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN AggExprEmitter : public StmtVisitor<AggExprEmitter> {
+ CodeGenFunction &CGF;
+ CGBuilderTy &Builder;
+ llvm::Value *DestPtr;
+ bool VolatileDest;
+ bool IgnoreResult;
+
+public:
+ AggExprEmitter(CodeGenFunction &cgf, llvm::Value *destPtr, bool v,
+ bool ignore)
+ : CGF(cgf), Builder(CGF.Builder),
+ DestPtr(destPtr), VolatileDest(v), IgnoreResult(ignore) {
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Utilities
+ //===--------------------------------------------------------------------===//
+
+ /// EmitAggLoadOfLValue - Given an expression with aggregate type that
+ /// represents a value lvalue, this method emits the address of the lvalue,
+ /// then loads the result into DestPtr.
+ void EmitAggLoadOfLValue(const Expr *E);
+
+ /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
+ void EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore = false);
+ void EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore = false);
+
+ //===--------------------------------------------------------------------===//
+ // Visitor Methods
+ //===--------------------------------------------------------------------===//
+
+ void VisitStmt(Stmt *S) {
+ CGF.ErrorUnsupported(S, "aggregate expression");
+ }
+ void VisitParenExpr(ParenExpr *PE) { Visit(PE->getSubExpr()); }
+ void VisitUnaryExtension(UnaryOperator *E) { Visit(E->getSubExpr()); }
+
+ // l-values.
+ void VisitDeclRefExpr(DeclRefExpr *DRE) { EmitAggLoadOfLValue(DRE); }
+ void VisitMemberExpr(MemberExpr *ME) { EmitAggLoadOfLValue(ME); }
+ void VisitUnaryDeref(UnaryOperator *E) { EmitAggLoadOfLValue(E); }
+ void VisitStringLiteral(StringLiteral *E) { EmitAggLoadOfLValue(E); }
+ void VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ EmitAggLoadOfLValue(E);
+ }
+ void VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+ EmitAggLoadOfLValue(E);
+ }
+ void VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
+ EmitAggLoadOfLValue(E);
+ }
+ void VisitPredefinedExpr(const PredefinedExpr *E) {
+ EmitAggLoadOfLValue(E);
+ }
+
+ // Operators.
+ void VisitCStyleCastExpr(CStyleCastExpr *E);
+ void VisitImplicitCastExpr(ImplicitCastExpr *E);
+ void VisitCallExpr(const CallExpr *E);
+ void VisitStmtExpr(const StmtExpr *E);
+ void VisitBinaryOperator(const BinaryOperator *BO);
+ void VisitBinAssign(const BinaryOperator *E);
+ void VisitBinComma(const BinaryOperator *E);
+
+ void VisitObjCMessageExpr(ObjCMessageExpr *E);
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ EmitAggLoadOfLValue(E);
+ }
+ void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
+ void VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
+
+ void VisitConditionalOperator(const ConditionalOperator *CO);
+ void VisitInitListExpr(InitListExpr *E);
+ void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
+ Visit(DAE->getExpr());
+ }
+ void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E);
+ void VisitCXXConstructExpr(const CXXConstructExpr *E);
+ void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E);
+
+ void VisitVAArgExpr(VAArgExpr *E);
+
+ void EmitInitializationToLValue(Expr *E, LValue Address);
+ void EmitNullInitializationToLValue(LValue Address, QualType T);
+ // case Expr::ChooseExprClass:
+
+};
+} // end anonymous namespace.
+
+//===----------------------------------------------------------------------===//
+// Utilities
+//===----------------------------------------------------------------------===//
+
+/// EmitAggLoadOfLValue - Given an expression with aggregate type that
+/// represents a value lvalue, this method emits the address of the lvalue,
+/// then loads the result into DestPtr.
+void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) {
+ LValue LV = CGF.EmitLValue(E);
+ EmitFinalDestCopy(E, LV);
+}
+
+/// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
+void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) {
+ assert(Src.isAggregate() && "value must be aggregate value!");
+
+ // If the result is ignored, don't copy from the value.
+ if (DestPtr == 0) {
+ if (!Src.isVolatileQualified() || (IgnoreResult && Ignore))
+ return;
+ // If the source is volatile, we must read from it; to do that, we need
+ // some place to put it.
+ DestPtr = CGF.CreateTempAlloca(CGF.ConvertType(E->getType()), "agg.tmp");
+ }
+
+ // If the result of the assignment is used, copy the LHS there also.
+ // FIXME: Pass VolatileDest as well. I think we also need to merge volatile
+ // from the source as well, as we can't eliminate it if either operand
+ // is volatile, unless copy has volatile for both source and destination..
+ CGF.EmitAggregateCopy(DestPtr, Src.getAggregateAddr(), E->getType(),
+ VolatileDest|Src.isVolatileQualified());
+}
+
+/// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
+void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) {
+ assert(Src.isSimple() && "Can't have aggregate bitfield, vector, etc");
+
+ EmitFinalDestCopy(E, RValue::getAggregate(Src.getAddress(),
+ Src.isVolatileQualified()),
+ Ignore);
+}
+
+//===----------------------------------------------------------------------===//
+// Visitor Methods
+//===----------------------------------------------------------------------===//
+
+void AggExprEmitter::VisitCStyleCastExpr(CStyleCastExpr *E) {
+ // GCC union extension
+ if (E->getType()->isUnionType()) {
+ RecordDecl *SD = E->getType()->getAsRecordType()->getDecl();
+ LValue FieldLoc = CGF.EmitLValueForField(DestPtr,
+ *SD->field_begin(CGF.getContext()),
+ true, 0);
+ EmitInitializationToLValue(E->getSubExpr(), FieldLoc);
+ return;
+ }
+
+ Visit(E->getSubExpr());
+}
+
+void AggExprEmitter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ assert(CGF.getContext().hasSameUnqualifiedType(E->getSubExpr()->getType(),
+ E->getType()) &&
+ "Implicit cast types must be compatible");
+ Visit(E->getSubExpr());
+}
+
+void AggExprEmitter::VisitCallExpr(const CallExpr *E) {
+ if (E->getCallReturnType()->isReferenceType()) {
+ EmitAggLoadOfLValue(E);
+ return;
+ }
+
+ RValue RV = CGF.EmitCallExpr(E);
+ EmitFinalDestCopy(E, RV);
+}
+
+void AggExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ RValue RV = CGF.EmitObjCMessageExpr(E);
+ EmitFinalDestCopy(E, RV);
+}
+
+void AggExprEmitter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
+ RValue RV = CGF.EmitObjCPropertyGet(E);
+ EmitFinalDestCopy(E, RV);
+}
+
+void AggExprEmitter::VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
+ RValue RV = CGF.EmitObjCPropertyGet(E);
+ EmitFinalDestCopy(E, RV);
+}
+
+void AggExprEmitter::VisitBinComma(const BinaryOperator *E) {
+ CGF.EmitAnyExpr(E->getLHS(), 0, false, true);
+ CGF.EmitAggExpr(E->getRHS(), DestPtr, VolatileDest);
+}
+
+void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) {
+ CGF.EmitCompoundStmt(*E->getSubStmt(), true, DestPtr, VolatileDest);
+}
+
+void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) {
+ CGF.ErrorUnsupported(E, "aggregate binary expression");
+}
+
+void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
+ // For an assignment to work, the value on the right has
+ // to be compatible with the value on the left.
+ assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(),
+ E->getRHS()->getType())
+ && "Invalid assignment");
+ LValue LHS = CGF.EmitLValue(E->getLHS());
+
+ // We have to special case property setters, otherwise we must have
+ // a simple lvalue (no aggregates inside vectors, bitfields).
+ if (LHS.isPropertyRef()) {
+ llvm::Value *AggLoc = DestPtr;
+ if (!AggLoc)
+ AggLoc = CGF.CreateTempAlloca(CGF.ConvertType(E->getRHS()->getType()));
+ CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest);
+ CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(),
+ RValue::getAggregate(AggLoc, VolatileDest));
+ }
+ else if (LHS.isKVCRef()) {
+ llvm::Value *AggLoc = DestPtr;
+ if (!AggLoc)
+ AggLoc = CGF.CreateTempAlloca(CGF.ConvertType(E->getRHS()->getType()));
+ CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest);
+ CGF.EmitObjCPropertySet(LHS.getKVCRefExpr(),
+ RValue::getAggregate(AggLoc, VolatileDest));
+ } else {
+ // Codegen the RHS so that it stores directly into the LHS.
+ CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), LHS.isVolatileQualified());
+ EmitFinalDestCopy(E, LHS, true);
+ }
+}
+
+void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) {
+ llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true");
+ llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
+ llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
+
+ llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond());
+ Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
+
+ CGF.EmitBlock(LHSBlock);
+
+ // Handle the GNU extension for missing LHS.
+ assert(E->getLHS() && "Must have LHS for aggregate value");
+
+ Visit(E->getLHS());
+ CGF.EmitBranch(ContBlock);
+
+ CGF.EmitBlock(RHSBlock);
+
+ Visit(E->getRHS());
+ CGF.EmitBranch(ContBlock);
+
+ CGF.EmitBlock(ContBlock);
+}
+
+void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
+ llvm::Value *ArgValue = CGF.EmitVAListRef(VE->getSubExpr());
+ llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType());
+
+ if (!ArgPtr) {
+ CGF.ErrorUnsupported(VE, "aggregate va_arg expression");
+ return;
+ }
+
+ EmitFinalDestCopy(VE, LValue::MakeAddr(ArgPtr, 0));
+}
+
+void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+ llvm::Value *Val = DestPtr;
+
+ if (!Val) {
+ // Create a temporary variable.
+ Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
+
+ // FIXME: volatile
+ CGF.EmitAggExpr(E->getSubExpr(), Val, false);
+ } else
+ Visit(E->getSubExpr());
+
+ CGF.PushCXXTemporary(E->getTemporary(), Val);
+}
+
+void
+AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
+ llvm::Value *Val = DestPtr;
+
+ if (!Val) {
+ // Create a temporary variable.
+ Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
+ }
+
+ CGF.EmitCXXConstructExpr(Val, E);
+}
+
+void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
+ CGF.EmitCXXExprWithTemporaries(E, DestPtr, VolatileDest);
+}
+
+void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
+ // FIXME: Ignore result?
+ // FIXME: Are initializers affected by volatile?
+ if (isa<ImplicitValueInitExpr>(E)) {
+ EmitNullInitializationToLValue(LV, E->getType());
+ } else if (E->getType()->isComplexType()) {
+ CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
+ } else if (CGF.hasAggregateLLVMType(E->getType())) {
+ CGF.EmitAnyExpr(E, LV.getAddress(), false);
+ } else {
+ CGF.EmitStoreThroughLValue(CGF.EmitAnyExpr(E), LV, E->getType());
+ }
+}
+
+void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) {
+ if (!CGF.hasAggregateLLVMType(T)) {
+ // For non-aggregates, we can store zero
+ llvm::Value *Null = llvm::Constant::getNullValue(CGF.ConvertType(T));
+ CGF.EmitStoreThroughLValue(RValue::get(Null), LV, T);
+ } else {
+ // Otherwise, just memset the whole thing to zero. This is legal
+ // because in LLVM, all default initializers are guaranteed to have a
+ // bit pattern of all zeros.
+ // FIXME: That isn't true for member pointers!
+ // There's a potential optimization opportunity in combining
+ // memsets; that would be easy for arrays, but relatively
+ // difficult for structures with the current code.
+ CGF.EmitMemSetToZero(LV.getAddress(), T);
+ }
+}
+
+void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
+#if 0
+ // FIXME: Disabled while we figure out what to do about
+ // test/CodeGen/bitfield.c
+ //
+ // If we can, prefer a copy from a global; this is a lot less code for long
+ // globals, and it's easier for the current optimizers to analyze.
+ // FIXME: Should we really be doing this? Should we try to avoid cases where
+ // we emit a global with a lot of zeros? Should we try to avoid short
+ // globals?
+ if (E->isConstantInitializer(CGF.getContext(), 0)) {
+ llvm::Constant* C = CGF.CGM.EmitConstantExpr(E, &CGF);
+ llvm::GlobalVariable* GV =
+ new llvm::GlobalVariable(C->getType(), true,
+ llvm::GlobalValue::InternalLinkage,
+ C, "", &CGF.CGM.getModule(), 0);
+ EmitFinalDestCopy(E, LValue::MakeAddr(GV, 0));
+ return;
+ }
+#endif
+ if (E->hadArrayRangeDesignator()) {
+ CGF.ErrorUnsupported(E, "GNU array range designator extension");
+ }
+
+ // Handle initialization of an array.
+ if (E->getType()->isArrayType()) {
+ const llvm::PointerType *APType =
+ cast<llvm::PointerType>(DestPtr->getType());
+ const llvm::ArrayType *AType =
+ cast<llvm::ArrayType>(APType->getElementType());
+
+ uint64_t NumInitElements = E->getNumInits();
+
+ if (E->getNumInits() > 0) {
+ QualType T1 = E->getType();
+ QualType T2 = E->getInit(0)->getType();
+ if (CGF.getContext().hasSameUnqualifiedType(T1, T2)) {
+ EmitAggLoadOfLValue(E->getInit(0));
+ return;
+ }
+ }
+
+ uint64_t NumArrayElements = AType->getNumElements();
+ QualType ElementType = CGF.getContext().getCanonicalType(E->getType());
+ ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType();
+
+ unsigned CVRqualifier = ElementType.getCVRQualifiers();
+
+ for (uint64_t i = 0; i != NumArrayElements; ++i) {
+ llvm::Value *NextVal = Builder.CreateStructGEP(DestPtr, i, ".array");
+ if (i < NumInitElements)
+ EmitInitializationToLValue(E->getInit(i),
+ LValue::MakeAddr(NextVal, CVRqualifier));
+ else
+ EmitNullInitializationToLValue(LValue::MakeAddr(NextVal, CVRqualifier),
+ ElementType);
+ }
+ return;
+ }
+
+ assert(E->getType()->isRecordType() && "Only support structs/unions here!");
+
+ // Do struct initialization; this code just sets each individual member
+ // to the approprate value. This makes bitfield support automatic;
+ // the disadvantage is that the generated code is more difficult for
+ // the optimizer, especially with bitfields.
+ unsigned NumInitElements = E->getNumInits();
+ RecordDecl *SD = E->getType()->getAsRecordType()->getDecl();
+ unsigned CurInitVal = 0;
+
+ if (E->getType()->isUnionType()) {
+ // Only initialize one field of a union. The field itself is
+ // specified by the initializer list.
+ if (!E->getInitializedFieldInUnion()) {
+ // Empty union; we have nothing to do.
+
+#ifndef NDEBUG
+ // Make sure that it's really an empty and not a failure of
+ // semantic analysis.
+ for (RecordDecl::field_iterator Field = SD->field_begin(CGF.getContext()),
+ FieldEnd = SD->field_end(CGF.getContext());
+ Field != FieldEnd; ++Field)
+ assert(Field->isUnnamedBitfield() && "Only unnamed bitfields allowed");
+#endif
+ return;
+ }
+
+ // FIXME: volatility
+ FieldDecl *Field = E->getInitializedFieldInUnion();
+ LValue FieldLoc = CGF.EmitLValueForField(DestPtr, Field, true, 0);
+
+ if (NumInitElements) {
+ // Store the initializer into the field
+ EmitInitializationToLValue(E->getInit(0), FieldLoc);
+ } else {
+ // Default-initialize to null
+ EmitNullInitializationToLValue(FieldLoc, Field->getType());
+ }
+
+ return;
+ }
+
+ // Here we iterate over the fields; this makes it simpler to both
+ // default-initialize fields and skip over unnamed fields.
+ for (RecordDecl::field_iterator Field = SD->field_begin(CGF.getContext()),
+ FieldEnd = SD->field_end(CGF.getContext());
+ Field != FieldEnd; ++Field) {
+ // We're done once we hit the flexible array member
+ if (Field->getType()->isIncompleteArrayType())
+ break;
+
+ if (Field->isUnnamedBitfield())
+ continue;
+
+ // FIXME: volatility
+ LValue FieldLoc = CGF.EmitLValueForField(DestPtr, *Field, false, 0);
+ // We never generate write-barries for initialized fields.
+ LValue::SetObjCNonGC(FieldLoc, true);
+ if (CurInitVal < NumInitElements) {
+ // Store the initializer into the field
+ EmitInitializationToLValue(E->getInit(CurInitVal++), FieldLoc);
+ } else {
+ // We're out of initalizers; default-initialize to null
+ EmitNullInitializationToLValue(FieldLoc, Field->getType());
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Entry Points into this File
+//===----------------------------------------------------------------------===//
+
+/// EmitAggExpr - Emit the computation of the specified expression of aggregate
+/// type. The result is computed into DestPtr. Note that if DestPtr is null,
+/// the value of the aggregate expression is not needed. If VolatileDest is
+/// true, DestPtr cannot be 0.
+void CodeGenFunction::EmitAggExpr(const Expr *E, llvm::Value *DestPtr,
+ bool VolatileDest, bool IgnoreResult) {
+ assert(E && hasAggregateLLVMType(E->getType()) &&
+ "Invalid aggregate expression to emit");
+ assert ((DestPtr != 0 || VolatileDest == false)
+ && "volatile aggregate can't be 0");
+
+ AggExprEmitter(*this, DestPtr, VolatileDest, IgnoreResult)
+ .Visit(const_cast<Expr*>(E));
+}
+
+void CodeGenFunction::EmitAggregateClear(llvm::Value *DestPtr, QualType Ty) {
+ assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
+
+ EmitMemSetToZero(DestPtr, Ty);
+}
+
+void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
+ llvm::Value *SrcPtr, QualType Ty,
+ bool isVolatile) {
+ assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
+
+ // Aggregate assignment turns into llvm.memcpy. This is almost valid per
+ // C99 6.5.16.1p3, which states "If the value being stored in an object is
+ // read from another object that overlaps in anyway the storage of the first
+ // object, then the overlap shall be exact and the two objects shall have
+ // qualified or unqualified versions of a compatible type."
+ //
+ // memcpy is not defined if the source and destination pointers are exactly
+ // equal, but other compilers do this optimization, and almost every memcpy
+ // implementation handles this case safely. If there is a libc that does not
+ // safely handle this, we can add a target hook.
+ const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ if (DestPtr->getType() != BP)
+ DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp");
+ if (SrcPtr->getType() != BP)
+ SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp");
+
+ // Get size and alignment info for this aggregate.
+ std::pair<uint64_t, unsigned> TypeInfo = getContext().getTypeInfo(Ty);
+
+ // FIXME: Handle variable sized types.
+ const llvm::Type *IntPtr = llvm::IntegerType::get(LLVMPointerWidth);
+
+ // FIXME: If we have a volatile struct, the optimizer can remove what might
+ // appear to be `extra' memory ops:
+ //
+ // volatile struct { int i; } a, b;
+ //
+ // int main() {
+ // a = b;
+ // a = b;
+ // }
+ //
+ // we need to use a differnt call here. We use isVolatile to indicate when
+ // either the source or the destination is volatile.
+ Builder.CreateCall4(CGM.getMemCpyFn(),
+ DestPtr, SrcPtr,
+ // TypeInfo.first describes size in bits.
+ llvm::ConstantInt::get(IntPtr, TypeInfo.first/8),
+ llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ TypeInfo.second/8));
+}
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
new file mode 100644
index 000000000000..41fb725fdf72
--- /dev/null
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -0,0 +1,663 @@
+//===--- CGExprComplex.cpp - Emit LLVM Code for Complex Exprs -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit Expr nodes with complex types as LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/Constants.h"
+#include "llvm/Function.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Compiler.h"
+using namespace clang;
+using namespace CodeGen;
+
+//===----------------------------------------------------------------------===//
+// Complex Expression Emitter
+//===----------------------------------------------------------------------===//
+
+typedef CodeGenFunction::ComplexPairTy ComplexPairTy;
+
+namespace {
+class VISIBILITY_HIDDEN ComplexExprEmitter
+ : public StmtVisitor<ComplexExprEmitter, ComplexPairTy> {
+ CodeGenFunction &CGF;
+ CGBuilderTy &Builder;
+ // True is we should ignore the value of a
+ bool IgnoreReal;
+ bool IgnoreImag;
+ // True if we should ignore the value of a=b
+ bool IgnoreRealAssign;
+ bool IgnoreImagAssign;
+public:
+ ComplexExprEmitter(CodeGenFunction &cgf, bool ir=false, bool ii=false,
+ bool irn=false, bool iin=false)
+ : CGF(cgf), Builder(CGF.Builder), IgnoreReal(ir), IgnoreImag(ii),
+ IgnoreRealAssign(irn), IgnoreImagAssign(iin) {
+ }
+
+
+ //===--------------------------------------------------------------------===//
+ // Utilities
+ //===--------------------------------------------------------------------===//
+
+ bool TestAndClearIgnoreReal() {
+ bool I = IgnoreReal;
+ IgnoreReal = false;
+ return I;
+ }
+ bool TestAndClearIgnoreImag() {
+ bool I = IgnoreImag;
+ IgnoreImag = false;
+ return I;
+ }
+ bool TestAndClearIgnoreRealAssign() {
+ bool I = IgnoreRealAssign;
+ IgnoreRealAssign = false;
+ return I;
+ }
+ bool TestAndClearIgnoreImagAssign() {
+ bool I = IgnoreImagAssign;
+ IgnoreImagAssign = false;
+ return I;
+ }
+
+ /// EmitLoadOfLValue - Given an expression with complex type that represents a
+ /// value l-value, this method emits the address of the l-value, then loads
+ /// and returns the result.
+ ComplexPairTy EmitLoadOfLValue(const Expr *E) {
+ LValue LV = CGF.EmitLValue(E);
+ return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified());
+ }
+
+ /// EmitLoadOfComplex - Given a pointer to a complex value, emit code to load
+ /// the real and imaginary pieces.
+ ComplexPairTy EmitLoadOfComplex(llvm::Value *SrcPtr, bool isVolatile);
+
+ /// EmitStoreOfComplex - Store the specified real/imag parts into the
+ /// specified value pointer.
+ void EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *ResPtr, bool isVol);
+
+ /// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType.
+ ComplexPairTy EmitComplexToComplexCast(ComplexPairTy Val, QualType SrcType,
+ QualType DestType);
+
+ //===--------------------------------------------------------------------===//
+ // Visitor Methods
+ //===--------------------------------------------------------------------===//
+
+ ComplexPairTy VisitStmt(Stmt *S) {
+ S->dump(CGF.getContext().getSourceManager());
+ assert(0 && "Stmt can't have complex result type!");
+ return ComplexPairTy();
+ }
+ ComplexPairTy VisitExpr(Expr *S);
+ ComplexPairTy VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr());}
+ ComplexPairTy VisitImaginaryLiteral(const ImaginaryLiteral *IL);
+
+ // l-values.
+ ComplexPairTy VisitDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); }
+ ComplexPairTy VisitArraySubscriptExpr(Expr *E) { return EmitLoadOfLValue(E); }
+ ComplexPairTy VisitMemberExpr(const Expr *E) { return EmitLoadOfLValue(E); }
+
+ // FIXME: CompoundLiteralExpr
+
+ ComplexPairTy EmitCast(Expr *Op, QualType DestTy);
+ ComplexPairTy VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ // Unlike for scalars, we don't have to worry about function->ptr demotion
+ // here.
+ return EmitCast(E->getSubExpr(), E->getType());
+ }
+ ComplexPairTy VisitCastExpr(CastExpr *E) {
+ return EmitCast(E->getSubExpr(), E->getType());
+ }
+ ComplexPairTy VisitCallExpr(const CallExpr *E);
+ ComplexPairTy VisitStmtExpr(const StmtExpr *E);
+
+ // Operators.
+ ComplexPairTy VisitPrePostIncDec(const UnaryOperator *E,
+ bool isInc, bool isPre);
+ ComplexPairTy VisitUnaryPostDec(const UnaryOperator *E) {
+ return VisitPrePostIncDec(E, false, false);
+ }
+ ComplexPairTy VisitUnaryPostInc(const UnaryOperator *E) {
+ return VisitPrePostIncDec(E, true, false);
+ }
+ ComplexPairTy VisitUnaryPreDec(const UnaryOperator *E) {
+ return VisitPrePostIncDec(E, false, true);
+ }
+ ComplexPairTy VisitUnaryPreInc(const UnaryOperator *E) {
+ return VisitPrePostIncDec(E, true, true);
+ }
+ ComplexPairTy VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); }
+ ComplexPairTy VisitUnaryPlus (const UnaryOperator *E) {
+ TestAndClearIgnoreReal();
+ TestAndClearIgnoreImag();
+ TestAndClearIgnoreRealAssign();
+ TestAndClearIgnoreImagAssign();
+ return Visit(E->getSubExpr());
+ }
+ ComplexPairTy VisitUnaryMinus (const UnaryOperator *E);
+ ComplexPairTy VisitUnaryNot (const UnaryOperator *E);
+ // LNot,Real,Imag never return complex.
+ ComplexPairTy VisitUnaryExtension(const UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
+ ComplexPairTy VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
+ return Visit(DAE->getExpr());
+ }
+ ComplexPairTy VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
+ return CGF.EmitCXXExprWithTemporaries(E).getComplexVal();
+ }
+ ComplexPairTy VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
+ assert(E->getType()->isAnyComplexType() && "Expected complex type!");
+ QualType Elem = E->getType()->getAsComplexType()->getElementType();
+ llvm::Constant *Null = llvm::Constant::getNullValue(CGF.ConvertType(Elem));
+ return ComplexPairTy(Null, Null);
+ }
+ ComplexPairTy VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
+ assert(E->getType()->isAnyComplexType() && "Expected complex type!");
+ QualType Elem = E->getType()->getAsComplexType()->getElementType();
+ llvm::Constant *Null = llvm::Constant::getNullValue(CGF.ConvertType(Elem));
+ return ComplexPairTy(Null, Null);
+ }
+
+ struct BinOpInfo {
+ ComplexPairTy LHS;
+ ComplexPairTy RHS;
+ QualType Ty; // Computation Type.
+ };
+
+ BinOpInfo EmitBinOps(const BinaryOperator *E);
+ ComplexPairTy EmitCompoundAssign(const CompoundAssignOperator *E,
+ ComplexPairTy (ComplexExprEmitter::*Func)
+ (const BinOpInfo &));
+
+ ComplexPairTy EmitBinAdd(const BinOpInfo &Op);
+ ComplexPairTy EmitBinSub(const BinOpInfo &Op);
+ ComplexPairTy EmitBinMul(const BinOpInfo &Op);
+ ComplexPairTy EmitBinDiv(const BinOpInfo &Op);
+
+ ComplexPairTy VisitBinMul(const BinaryOperator *E) {
+ return EmitBinMul(EmitBinOps(E));
+ }
+ ComplexPairTy VisitBinAdd(const BinaryOperator *E) {
+ return EmitBinAdd(EmitBinOps(E));
+ }
+ ComplexPairTy VisitBinSub(const BinaryOperator *E) {
+ return EmitBinSub(EmitBinOps(E));
+ }
+ ComplexPairTy VisitBinDiv(const BinaryOperator *E) {
+ return EmitBinDiv(EmitBinOps(E));
+ }
+
+ // Compound assignments.
+ ComplexPairTy VisitBinAddAssign(const CompoundAssignOperator *E) {
+ return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinAdd);
+ }
+ ComplexPairTy VisitBinSubAssign(const CompoundAssignOperator *E) {
+ return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinSub);
+ }
+ ComplexPairTy VisitBinMulAssign(const CompoundAssignOperator *E) {
+ return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinMul);
+ }
+ ComplexPairTy VisitBinDivAssign(const CompoundAssignOperator *E) {
+ return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinDiv);
+ }
+
+ // GCC rejects rem/and/or/xor for integer complex.
+ // Logical and/or always return int, never complex.
+
+ // No comparisons produce a complex result.
+ ComplexPairTy VisitBinAssign (const BinaryOperator *E);
+ ComplexPairTy VisitBinComma (const BinaryOperator *E);
+
+
+ ComplexPairTy VisitConditionalOperator(const ConditionalOperator *CO);
+ ComplexPairTy VisitChooseExpr(ChooseExpr *CE);
+
+ ComplexPairTy VisitInitListExpr(InitListExpr *E);
+
+ ComplexPairTy VisitVAArgExpr(VAArgExpr *E);
+};
+} // end anonymous namespace.
+
+//===----------------------------------------------------------------------===//
+// Utilities
+//===----------------------------------------------------------------------===//
+
+/// EmitLoadOfComplex - Given an RValue reference for a complex, emit code to
+/// load the real and imaginary pieces, returning them as Real/Imag.
+ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr,
+ bool isVolatile) {
+ llvm::SmallString<64> Name(SrcPtr->getNameStart(),
+ SrcPtr->getNameStart()+SrcPtr->getNameLen());
+
+ llvm::Value *Real=0, *Imag=0;
+
+ if (!IgnoreReal) {
+ Name += ".realp";
+ llvm::Value *RealPtr = Builder.CreateStructGEP(SrcPtr, 0, Name.c_str());
+
+ Name.pop_back(); // .realp -> .real
+ Real = Builder.CreateLoad(RealPtr, isVolatile, Name.c_str());
+ Name.resize(Name.size()-4); // .real -> .imagp
+ }
+
+ if (!IgnoreImag) {
+ Name += "imagp";
+
+ llvm::Value *ImagPtr = Builder.CreateStructGEP(SrcPtr, 1, Name.c_str());
+
+ Name.pop_back(); // .imagp -> .imag
+ Imag = Builder.CreateLoad(ImagPtr, isVolatile, Name.c_str());
+ }
+ return ComplexPairTy(Real, Imag);
+}
+
+/// EmitStoreOfComplex - Store the specified real/imag parts into the
+/// specified value pointer.
+void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr,
+ bool isVolatile) {
+ llvm::Value *RealPtr = Builder.CreateStructGEP(Ptr, 0, "real");
+ llvm::Value *ImagPtr = Builder.CreateStructGEP(Ptr, 1, "imag");
+
+ Builder.CreateStore(Val.first, RealPtr, isVolatile);
+ Builder.CreateStore(Val.second, ImagPtr, isVolatile);
+}
+
+
+
+//===----------------------------------------------------------------------===//
+// Visitor Methods
+//===----------------------------------------------------------------------===//
+
+ComplexPairTy ComplexExprEmitter::VisitExpr(Expr *E) {
+ CGF.ErrorUnsupported(E, "complex expression");
+ const llvm::Type *EltTy =
+ CGF.ConvertType(E->getType()->getAsComplexType()->getElementType());
+ llvm::Value *U = llvm::UndefValue::get(EltTy);
+ return ComplexPairTy(U, U);
+}
+
+ComplexPairTy ComplexExprEmitter::
+VisitImaginaryLiteral(const ImaginaryLiteral *IL) {
+ llvm::Value *Imag = CGF.EmitScalarExpr(IL->getSubExpr());
+ return ComplexPairTy(llvm::Constant::getNullValue(Imag->getType()), Imag);
+}
+
+
+ComplexPairTy ComplexExprEmitter::VisitCallExpr(const CallExpr *E) {
+ if (E->getCallReturnType()->isReferenceType())
+ return EmitLoadOfLValue(E);
+
+ return CGF.EmitCallExpr(E).getComplexVal();
+}
+
+ComplexPairTy ComplexExprEmitter::VisitStmtExpr(const StmtExpr *E) {
+ return CGF.EmitCompoundStmt(*E->getSubStmt(), true).getComplexVal();
+}
+
+/// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType.
+ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val,
+ QualType SrcType,
+ QualType DestType) {
+ // Get the src/dest element type.
+ SrcType = SrcType->getAsComplexType()->getElementType();
+ DestType = DestType->getAsComplexType()->getElementType();
+
+ // C99 6.3.1.6: When a value of complex type is converted to another
+ // complex type, both the real and imaginary parts follow the conversion
+ // rules for the corresponding real types.
+ Val.first = CGF.EmitScalarConversion(Val.first, SrcType, DestType);
+ Val.second = CGF.EmitScalarConversion(Val.second, SrcType, DestType);
+ return Val;
+}
+
+ComplexPairTy ComplexExprEmitter::EmitCast(Expr *Op, QualType DestTy) {
+ // Two cases here: cast from (complex to complex) and (scalar to complex).
+ if (Op->getType()->isAnyComplexType())
+ return EmitComplexToComplexCast(Visit(Op), Op->getType(), DestTy);
+
+ // C99 6.3.1.7: When a value of real type is converted to a complex type, the
+ // real part of the complex result value is determined by the rules of
+ // conversion to the corresponding real type and the imaginary part of the
+ // complex result value is a positive zero or an unsigned zero.
+ llvm::Value *Elt = CGF.EmitScalarExpr(Op);
+
+ // Convert the input element to the element type of the complex.
+ DestTy = DestTy->getAsComplexType()->getElementType();
+ Elt = CGF.EmitScalarConversion(Elt, Op->getType(), DestTy);
+
+ // Return (realval, 0).
+ return ComplexPairTy(Elt, llvm::Constant::getNullValue(Elt->getType()));
+}
+
+ComplexPairTy ComplexExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
+ bool isInc, bool isPre) {
+ LValue LV = CGF.EmitLValue(E->getSubExpr());
+ ComplexPairTy InVal = EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified());
+
+ llvm::Value *NextVal;
+ if (isa<llvm::IntegerType>(InVal.first->getType())) {
+ uint64_t AmountVal = isInc ? 1 : -1;
+ NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal, true);
+ } else {
+ QualType ElemTy = E->getType()->getAsComplexType()->getElementType();
+ llvm::APFloat FVal(CGF.getContext().getFloatTypeSemantics(ElemTy), 1);
+ if (!isInc)
+ FVal.changeSign();
+ NextVal = llvm::ConstantFP::get(FVal);
+ }
+
+ // Add the inc/dec to the real part.
+ NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
+
+ ComplexPairTy IncVal(NextVal, InVal.second);
+
+ // Store the updated result through the lvalue.
+ EmitStoreOfComplex(IncVal, LV.getAddress(), LV.isVolatileQualified());
+
+ // If this is a postinc, return the value read from memory, otherwise use the
+ // updated value.
+ return isPre ? IncVal : InVal;
+}
+
+ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
+ TestAndClearIgnoreReal();
+ TestAndClearIgnoreImag();
+ TestAndClearIgnoreRealAssign();
+ TestAndClearIgnoreImagAssign();
+ ComplexPairTy Op = Visit(E->getSubExpr());
+ llvm::Value *ResR = Builder.CreateNeg(Op.first, "neg.r");
+ llvm::Value *ResI = Builder.CreateNeg(Op.second, "neg.i");
+ return ComplexPairTy(ResR, ResI);
+}
+
+ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
+ TestAndClearIgnoreReal();
+ TestAndClearIgnoreImag();
+ TestAndClearIgnoreRealAssign();
+ TestAndClearIgnoreImagAssign();
+ // ~(a+ib) = a + i*-b
+ ComplexPairTy Op = Visit(E->getSubExpr());
+ llvm::Value *ResI = Builder.CreateNeg(Op.second, "conj.i");
+ return ComplexPairTy(Op.first, ResI);
+}
+
+ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) {
+ llvm::Value *ResR = Builder.CreateAdd(Op.LHS.first, Op.RHS.first, "add.r");
+ llvm::Value *ResI = Builder.CreateAdd(Op.LHS.second, Op.RHS.second, "add.i");
+ return ComplexPairTy(ResR, ResI);
+}
+
+ComplexPairTy ComplexExprEmitter::EmitBinSub(const BinOpInfo &Op) {
+ llvm::Value *ResR = Builder.CreateSub(Op.LHS.first, Op.RHS.first, "sub.r");
+ llvm::Value *ResI = Builder.CreateSub(Op.LHS.second, Op.RHS.second, "sub.i");
+ return ComplexPairTy(ResR, ResI);
+}
+
+
+ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
+ llvm::Value *ResRl = Builder.CreateMul(Op.LHS.first, Op.RHS.first, "mul.rl");
+ llvm::Value *ResRr = Builder.CreateMul(Op.LHS.second, Op.RHS.second,"mul.rr");
+ llvm::Value *ResR = Builder.CreateSub(ResRl, ResRr, "mul.r");
+
+ llvm::Value *ResIl = Builder.CreateMul(Op.LHS.second, Op.RHS.first, "mul.il");
+ llvm::Value *ResIr = Builder.CreateMul(Op.LHS.first, Op.RHS.second, "mul.ir");
+ llvm::Value *ResI = Builder.CreateAdd(ResIl, ResIr, "mul.i");
+ return ComplexPairTy(ResR, ResI);
+}
+
+ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
+ llvm::Value *LHSr = Op.LHS.first, *LHSi = Op.LHS.second;
+ llvm::Value *RHSr = Op.RHS.first, *RHSi = Op.RHS.second;
+
+ // (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 *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 *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 *DSTr, *DSTi;
+ if (Tmp3->getType()->isFloatingPoint()) {
+ DSTr = Builder.CreateFDiv(Tmp3, Tmp6, "tmp");
+ DSTi = Builder.CreateFDiv(Tmp9, Tmp6, "tmp");
+ } else {
+ if (Op.Ty->getAsComplexType()->getElementType()->isUnsignedIntegerType()) {
+ DSTr = Builder.CreateUDiv(Tmp3, Tmp6, "tmp");
+ DSTi = Builder.CreateUDiv(Tmp9, Tmp6, "tmp");
+ } else {
+ DSTr = Builder.CreateSDiv(Tmp3, Tmp6, "tmp");
+ DSTi = Builder.CreateSDiv(Tmp9, Tmp6, "tmp");
+ }
+ }
+
+ return ComplexPairTy(DSTr, DSTi);
+}
+
+ComplexExprEmitter::BinOpInfo
+ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) {
+ TestAndClearIgnoreReal();
+ TestAndClearIgnoreImag();
+ TestAndClearIgnoreRealAssign();
+ TestAndClearIgnoreImagAssign();
+ BinOpInfo Ops;
+ Ops.LHS = Visit(E->getLHS());
+ Ops.RHS = Visit(E->getRHS());
+ Ops.Ty = E->getType();
+ return Ops;
+}
+
+
+// Compound assignments.
+ComplexPairTy ComplexExprEmitter::
+EmitCompoundAssign(const CompoundAssignOperator *E,
+ ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&)){
+ TestAndClearIgnoreReal();
+ TestAndClearIgnoreImag();
+ bool ignreal = TestAndClearIgnoreRealAssign();
+ bool ignimag = TestAndClearIgnoreImagAssign();
+ QualType LHSTy = E->getLHS()->getType(), RHSTy = E->getRHS()->getType();
+
+ BinOpInfo OpInfo;
+
+ // Load the RHS and LHS operands.
+ // __block variables need to have the rhs evaluated first, plus this should
+ // improve codegen a little. It is possible for the RHS to be complex or
+ // scalar.
+ OpInfo.Ty = E->getComputationResultType();
+ OpInfo.RHS = EmitCast(E->getRHS(), OpInfo.Ty);
+
+ LValue LHSLV = CGF.EmitLValue(E->getLHS());
+
+
+ // We know the LHS is a complex lvalue.
+ OpInfo.LHS=EmitLoadOfComplex(LHSLV.getAddress(),LHSLV.isVolatileQualified());
+ OpInfo.LHS=EmitComplexToComplexCast(OpInfo.LHS, LHSTy, OpInfo.Ty);
+
+ // Expand the binary operator.
+ ComplexPairTy Result = (this->*Func)(OpInfo);
+
+ // Truncate the result back to the LHS type.
+ Result = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy);
+
+ // Store the result value into the LHS lvalue.
+ EmitStoreOfComplex(Result, LHSLV.getAddress(), LHSLV.isVolatileQualified());
+ // And now return the LHS
+ IgnoreReal = ignreal;
+ IgnoreImag = ignimag;
+ IgnoreRealAssign = ignreal;
+ IgnoreImagAssign = ignimag;
+ return EmitLoadOfComplex(LHSLV.getAddress(), LHSLV.isVolatileQualified());
+}
+
+ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
+ TestAndClearIgnoreReal();
+ TestAndClearIgnoreImag();
+ bool ignreal = TestAndClearIgnoreRealAssign();
+ bool ignimag = TestAndClearIgnoreImagAssign();
+ assert(CGF.getContext().getCanonicalType(E->getLHS()->getType()) ==
+ CGF.getContext().getCanonicalType(E->getRHS()->getType()) &&
+ "Invalid assignment");
+ // Emit the RHS.
+ ComplexPairTy Val = Visit(E->getRHS());
+
+ // Compute the address to store into.
+ LValue LHS = CGF.EmitLValue(E->getLHS());
+
+ // Store into it.
+ EmitStoreOfComplex(Val, LHS.getAddress(), LHS.isVolatileQualified());
+ // And now return the LHS
+ IgnoreReal = ignreal;
+ IgnoreImag = ignimag;
+ IgnoreRealAssign = ignreal;
+ IgnoreImagAssign = ignimag;
+ return EmitLoadOfComplex(LHS.getAddress(), LHS.isVolatileQualified());
+}
+
+ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) {
+ CGF.EmitStmt(E->getLHS());
+ CGF.EnsureInsertPoint();
+ return Visit(E->getRHS());
+}
+
+ComplexPairTy ComplexExprEmitter::
+VisitConditionalOperator(const ConditionalOperator *E) {
+ TestAndClearIgnoreReal();
+ TestAndClearIgnoreImag();
+ TestAndClearIgnoreRealAssign();
+ TestAndClearIgnoreImagAssign();
+ llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true");
+ llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
+ llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
+
+ llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond());
+ Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
+
+ CGF.EmitBlock(LHSBlock);
+
+ // Handle the GNU extension for missing LHS.
+ assert(E->getLHS() && "Must have LHS for complex value");
+
+ ComplexPairTy LHS = Visit(E->getLHS());
+ LHSBlock = Builder.GetInsertBlock();
+ CGF.EmitBranch(ContBlock);
+
+ CGF.EmitBlock(RHSBlock);
+
+ ComplexPairTy RHS = Visit(E->getRHS());
+ RHSBlock = Builder.GetInsertBlock();
+ CGF.EmitBranch(ContBlock);
+
+ CGF.EmitBlock(ContBlock);
+
+ // Create a PHI node for the real part.
+ llvm::PHINode *RealPN = Builder.CreatePHI(LHS.first->getType(), "cond.r");
+ RealPN->reserveOperandSpace(2);
+ RealPN->addIncoming(LHS.first, LHSBlock);
+ RealPN->addIncoming(RHS.first, RHSBlock);
+
+ // Create a PHI node for the imaginary part.
+ llvm::PHINode *ImagPN = Builder.CreatePHI(LHS.first->getType(), "cond.i");
+ ImagPN->reserveOperandSpace(2);
+ ImagPN->addIncoming(LHS.second, LHSBlock);
+ ImagPN->addIncoming(RHS.second, RHSBlock);
+
+ return ComplexPairTy(RealPN, ImagPN);
+}
+
+ComplexPairTy ComplexExprEmitter::VisitChooseExpr(ChooseExpr *E) {
+ return Visit(E->getChosenSubExpr(CGF.getContext()));
+}
+
+ComplexPairTy ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) {
+ bool Ignore = TestAndClearIgnoreReal();
+ (void)Ignore;
+ assert (Ignore == false && "init list ignored");
+ Ignore = TestAndClearIgnoreImag();
+ (void)Ignore;
+ assert (Ignore == false && "init list ignored");
+ if (E->getNumInits())
+ return Visit(E->getInit(0));
+
+ // Empty init list intializes to null
+ QualType Ty = E->getType()->getAsComplexType()->getElementType();
+ const llvm::Type* LTy = CGF.ConvertType(Ty);
+ llvm::Value* zeroConstant = llvm::Constant::getNullValue(LTy);
+ return ComplexPairTy(zeroConstant, zeroConstant);
+}
+
+ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
+ llvm::Value *ArgValue = CGF.EmitVAListRef(E->getSubExpr());
+ llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, E->getType());
+
+ if (!ArgPtr) {
+ CGF.ErrorUnsupported(E, "complex va_arg expression");
+ const llvm::Type *EltTy =
+ CGF.ConvertType(E->getType()->getAsComplexType()->getElementType());
+ llvm::Value *U = llvm::UndefValue::get(EltTy);
+ return ComplexPairTy(U, U);
+ }
+
+ // FIXME Volatility.
+ return EmitLoadOfComplex(ArgPtr, false);
+}
+
+//===----------------------------------------------------------------------===//
+// Entry Point into this File
+//===----------------------------------------------------------------------===//
+
+/// EmitComplexExpr - Emit the computation of the specified expression of
+/// complex type, ignoring the result.
+ComplexPairTy CodeGenFunction::EmitComplexExpr(const Expr *E, bool IgnoreReal,
+ bool IgnoreImag, bool IgnoreRealAssign, bool IgnoreImagAssign) {
+ assert(E && E->getType()->isAnyComplexType() &&
+ "Invalid complex expression to emit");
+
+ return ComplexExprEmitter(*this, IgnoreReal, IgnoreImag, IgnoreRealAssign,
+ IgnoreImagAssign)
+ .Visit(const_cast<Expr*>(E));
+}
+
+/// EmitComplexExprIntoAddr - Emit the computation of the specified expression
+/// of complex type, storing into the specified Value*.
+void CodeGenFunction::EmitComplexExprIntoAddr(const Expr *E,
+ llvm::Value *DestAddr,
+ bool DestIsVolatile) {
+ assert(E && E->getType()->isAnyComplexType() &&
+ "Invalid complex expression to emit");
+ ComplexExprEmitter Emitter(*this);
+ ComplexPairTy Val = Emitter.Visit(const_cast<Expr*>(E));
+ Emitter.EmitStoreOfComplex(Val, DestAddr, DestIsVolatile);
+}
+
+/// StoreComplexToAddr - Store a complex number into the specified address.
+void CodeGenFunction::StoreComplexToAddr(ComplexPairTy V,
+ llvm::Value *DestAddr,
+ bool DestIsVolatile) {
+ ComplexExprEmitter(*this).EmitStoreOfComplex(V, DestAddr, DestIsVolatile);
+}
+
+/// LoadComplexFromAddr - Load a complex number from the specified address.
+ComplexPairTy CodeGenFunction::LoadComplexFromAddr(llvm::Value *SrcAddr,
+ bool SrcIsVolatile) {
+ return ComplexExprEmitter(*this).EmitLoadOfComplex(SrcAddr, SrcIsVolatile);
+}
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
new file mode 100644
index 000000000000..b30bafb51051
--- /dev/null
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -0,0 +1,588 @@
+//===--- CGExprConstant.cpp - Emit LLVM Code from Constant Expressions ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit Constant Expr nodes as LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "CGObjCRuntime.h"
+#include "clang/AST/APValue.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/Constants.h"
+#include "llvm/Function.h"
+#include "llvm/GlobalVariable.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Target/TargetData.h"
+using namespace clang;
+using namespace CodeGen;
+
+namespace {
+class VISIBILITY_HIDDEN ConstExprEmitter :
+ public StmtVisitor<ConstExprEmitter, llvm::Constant*> {
+ CodeGenModule &CGM;
+ CodeGenFunction *CGF;
+public:
+ ConstExprEmitter(CodeGenModule &cgm, CodeGenFunction *cgf)
+ : CGM(cgm), CGF(cgf) {
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Visitor Methods
+ //===--------------------------------------------------------------------===//
+
+ llvm::Constant *VisitStmt(Stmt *S) {
+ return 0;
+ }
+
+ llvm::Constant *VisitParenExpr(ParenExpr *PE) {
+ return Visit(PE->getSubExpr());
+ }
+
+ llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ return Visit(E->getInitializer());
+ }
+
+ llvm::Constant *VisitCastExpr(CastExpr* E) {
+ // GCC cast to union extension
+ if (E->getType()->isUnionType()) {
+ const llvm::Type *Ty = ConvertType(E->getType());
+ Expr *SubExpr = E->getSubExpr();
+ return EmitUnion(CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF),
+ Ty);
+ }
+ // Explicit and implicit no-op casts
+ QualType Ty = E->getType(), SubTy = E->getSubExpr()->getType();
+ if (CGM.getContext().hasSameUnqualifiedType(Ty, SubTy)) {
+ return Visit(E->getSubExpr());
+ }
+ return 0;
+ }
+
+ llvm::Constant *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
+ return Visit(DAE->getExpr());
+ }
+
+ llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) {
+ std::vector<llvm::Constant*> Elts;
+ const llvm::ArrayType *AType =
+ cast<llvm::ArrayType>(ConvertType(ILE->getType()));
+ unsigned NumInitElements = ILE->getNumInits();
+ // FIXME: Check for wide strings
+ // FIXME: Check for NumInitElements exactly equal to 1??
+ if (NumInitElements > 0 &&
+ (isa<StringLiteral>(ILE->getInit(0)) ||
+ isa<ObjCEncodeExpr>(ILE->getInit(0))) &&
+ ILE->getType()->getArrayElementTypeNoTypeQual()->isCharType())
+ return Visit(ILE->getInit(0));
+ const llvm::Type *ElemTy = AType->getElementType();
+ unsigned NumElements = AType->getNumElements();
+
+ // Initialising an array requires us to automatically
+ // initialise any elements that have not been initialised explicitly
+ unsigned NumInitableElts = std::min(NumInitElements, NumElements);
+
+ // Copy initializer elements.
+ unsigned i = 0;
+ bool RewriteType = false;
+ for (; i < NumInitableElts; ++i) {
+ Expr *Init = ILE->getInit(i);
+ llvm::Constant *C = CGM.EmitConstantExpr(Init, Init->getType(), CGF);
+ if (!C)
+ return 0;
+ RewriteType |= (C->getType() != ElemTy);
+ Elts.push_back(C);
+ }
+
+ // Initialize remaining array elements.
+ // FIXME: This doesn't handle member pointers correctly!
+ for (; i < NumElements; ++i)
+ Elts.push_back(llvm::Constant::getNullValue(ElemTy));
+
+ if (RewriteType) {
+ // FIXME: Try to avoid packing the array
+ std::vector<const llvm::Type*> Types;
+ for (unsigned i = 0; i < Elts.size(); ++i)
+ Types.push_back(Elts[i]->getType());
+ const llvm::StructType *SType = llvm::StructType::get(Types, true);
+ return llvm::ConstantStruct::get(SType, Elts);
+ }
+
+ return llvm::ConstantArray::get(AType, Elts);
+ }
+
+ void InsertBitfieldIntoStruct(std::vector<llvm::Constant*>& Elts,
+ FieldDecl* Field, Expr* E) {
+ // Calculate the value to insert
+ llvm::Constant *C = CGM.EmitConstantExpr(E, Field->getType(), CGF);
+ if (!C)
+ return;
+
+ llvm::ConstantInt *CI = dyn_cast<llvm::ConstantInt>(C);
+ if (!CI) {
+ CGM.ErrorUnsupported(E, "bitfield initialization");
+ return;
+ }
+ llvm::APInt V = CI->getValue();
+
+ // Calculate information about the relevant field
+ const llvm::Type* Ty = CI->getType();
+ const llvm::TargetData &TD = CGM.getTypes().getTargetData();
+ unsigned size = TD.getTypeAllocSizeInBits(Ty);
+ unsigned fieldOffset = CGM.getTypes().getLLVMFieldNo(Field) * size;
+ CodeGenTypes::BitFieldInfo bitFieldInfo =
+ CGM.getTypes().getBitFieldInfo(Field);
+ fieldOffset += bitFieldInfo.Begin;
+
+ // Find where to start the insertion
+ // FIXME: This is O(n^2) in the number of bit-fields!
+ // FIXME: This won't work if the struct isn't completely packed!
+ unsigned offset = 0, i = 0;
+ while (offset < (fieldOffset & -8))
+ offset += TD.getTypeAllocSizeInBits(Elts[i++]->getType());
+
+ // Advance over 0 sized elements (must terminate in bounds since
+ // the bitfield must have a size).
+ while (TD.getTypeAllocSizeInBits(Elts[i]->getType()) == 0)
+ ++i;
+
+ // Promote the size of V if necessary
+ // FIXME: This should never occur, but currently it can because initializer
+ // constants are cast to bool, and because clang is not enforcing bitfield
+ // width limits.
+ if (bitFieldInfo.Size > V.getBitWidth())
+ V.zext(bitFieldInfo.Size);
+
+ // Insert the bits into the struct
+ // FIXME: This algorthm is only correct on X86!
+ // FIXME: THis algorthm assumes bit-fields only have byte-size elements!
+ unsigned bitsToInsert = bitFieldInfo.Size;
+ unsigned curBits = std::min(8 - (fieldOffset & 7), bitsToInsert);
+ unsigned byte = V.getLoBits(curBits).getZExtValue() << (fieldOffset & 7);
+ do {
+ llvm::Constant* byteC = llvm::ConstantInt::get(llvm::Type::Int8Ty, byte);
+ Elts[i] = llvm::ConstantExpr::getOr(Elts[i], byteC);
+ ++i;
+ V = V.lshr(curBits);
+ bitsToInsert -= curBits;
+
+ if (!bitsToInsert)
+ break;
+
+ curBits = bitsToInsert > 8 ? 8 : bitsToInsert;
+ byte = V.getLoBits(curBits).getZExtValue();
+ } while (true);
+ }
+
+ llvm::Constant *EmitStructInitialization(InitListExpr *ILE) {
+ const llvm::StructType *SType =
+ cast<llvm::StructType>(ConvertType(ILE->getType()));
+ RecordDecl *RD = ILE->getType()->getAsRecordType()->getDecl();
+ std::vector<llvm::Constant*> Elts;
+
+ // Initialize the whole structure to zero.
+ // FIXME: This doesn't handle member pointers correctly!
+ for (unsigned i = 0; i < SType->getNumElements(); ++i) {
+ const llvm::Type *FieldTy = SType->getElementType(i);
+ Elts.push_back(llvm::Constant::getNullValue(FieldTy));
+ }
+
+ // Copy initializer elements. Skip padding fields.
+ unsigned EltNo = 0; // Element no in ILE
+ int FieldNo = 0; // Field no in RecordDecl
+ bool RewriteType = false;
+ for (RecordDecl::field_iterator Field = RD->field_begin(CGM.getContext()),
+ FieldEnd = RD->field_end(CGM.getContext());
+ EltNo < ILE->getNumInits() && Field != FieldEnd; ++Field) {
+ FieldNo++;
+ if (!Field->getIdentifier())
+ continue;
+
+ if (Field->isBitField()) {
+ InsertBitfieldIntoStruct(Elts, *Field, ILE->getInit(EltNo));
+ } else {
+ unsigned FieldNo = CGM.getTypes().getLLVMFieldNo(*Field);
+ llvm::Constant *C = CGM.EmitConstantExpr(ILE->getInit(EltNo),
+ Field->getType(), CGF);
+ if (!C) return 0;
+ RewriteType |= (C->getType() != Elts[FieldNo]->getType());
+ Elts[FieldNo] = C;
+ }
+ EltNo++;
+ }
+
+ if (RewriteType) {
+ // FIXME: Make this work for non-packed structs
+ assert(SType->isPacked() && "Cannot recreate unpacked structs");
+ std::vector<const llvm::Type*> Types;
+ for (unsigned i = 0; i < Elts.size(); ++i)
+ Types.push_back(Elts[i]->getType());
+ SType = llvm::StructType::get(Types, true);
+ }
+
+ return llvm::ConstantStruct::get(SType, Elts);
+ }
+
+ llvm::Constant *EmitUnion(llvm::Constant *C, const llvm::Type *Ty) {
+ if (!C)
+ return 0;
+
+ // Build a struct with the union sub-element as the first member,
+ // and padded to the appropriate size
+ std::vector<llvm::Constant*> Elts;
+ std::vector<const llvm::Type*> Types;
+ Elts.push_back(C);
+ Types.push_back(C->getType());
+ unsigned CurSize = CGM.getTargetData().getTypeAllocSize(C->getType());
+ unsigned TotalSize = CGM.getTargetData().getTypeAllocSize(Ty);
+ while (CurSize < TotalSize) {
+ Elts.push_back(llvm::Constant::getNullValue(llvm::Type::Int8Ty));
+ Types.push_back(llvm::Type::Int8Ty);
+ CurSize++;
+ }
+
+ // This always generates a packed struct
+ // FIXME: Try to generate an unpacked struct when we can
+ llvm::StructType* STy = llvm::StructType::get(Types, true);
+ return llvm::ConstantStruct::get(STy, Elts);
+ }
+
+ llvm::Constant *EmitUnionInitialization(InitListExpr *ILE) {
+ const llvm::Type *Ty = ConvertType(ILE->getType());
+
+ FieldDecl* curField = ILE->getInitializedFieldInUnion();
+ if (!curField) {
+ // There's no field to initialize, so value-initialize the union.
+#ifndef NDEBUG
+ // Make sure that it's really an empty and not a failure of
+ // semantic analysis.
+ RecordDecl *RD = ILE->getType()->getAsRecordType()->getDecl();
+ for (RecordDecl::field_iterator Field = RD->field_begin(CGM.getContext()),
+ FieldEnd = RD->field_end(CGM.getContext());
+ Field != FieldEnd; ++Field)
+ assert(Field->isUnnamedBitfield() && "Only unnamed bitfields allowed");
+#endif
+ return llvm::Constant::getNullValue(Ty);
+ }
+
+ if (curField->isBitField()) {
+ // Create a dummy struct for bit-field insertion
+ unsigned NumElts = CGM.getTargetData().getTypeAllocSize(Ty);
+ llvm::Constant* NV = llvm::Constant::getNullValue(llvm::Type::Int8Ty);
+ std::vector<llvm::Constant*> Elts(NumElts, NV);
+
+ InsertBitfieldIntoStruct(Elts, curField, ILE->getInit(0));
+ const llvm::ArrayType *RetTy =
+ llvm::ArrayType::get(NV->getType(), NumElts);
+ return llvm::ConstantArray::get(RetTy, Elts);
+ }
+
+ llvm::Constant *InitElem;
+ if (ILE->getNumInits() > 0) {
+ Expr *Init = ILE->getInit(0);
+ InitElem = CGM.EmitConstantExpr(Init, Init->getType(), CGF);
+ } else {
+ InitElem = CGM.EmitNullConstant(curField->getType());
+ }
+ return EmitUnion(InitElem, Ty);
+ }
+
+ llvm::Constant *EmitVectorInitialization(InitListExpr *ILE) {
+ const llvm::VectorType *VType =
+ cast<llvm::VectorType>(ConvertType(ILE->getType()));
+ const llvm::Type *ElemTy = VType->getElementType();
+ std::vector<llvm::Constant*> Elts;
+ unsigned NumElements = VType->getNumElements();
+ unsigned NumInitElements = ILE->getNumInits();
+
+ unsigned NumInitableElts = std::min(NumInitElements, NumElements);
+
+ // Copy initializer elements.
+ unsigned i = 0;
+ for (; i < NumInitableElts; ++i) {
+ Expr *Init = ILE->getInit(i);
+ llvm::Constant *C = CGM.EmitConstantExpr(Init, Init->getType(), CGF);
+ if (!C)
+ return 0;
+ Elts.push_back(C);
+ }
+
+ for (; i < NumElements; ++i)
+ Elts.push_back(llvm::Constant::getNullValue(ElemTy));
+
+ return llvm::ConstantVector::get(VType, Elts);
+ }
+
+ llvm::Constant *VisitImplicitValueInitExpr(ImplicitValueInitExpr* E) {
+ return CGM.EmitNullConstant(E->getType());
+ }
+
+ llvm::Constant *VisitInitListExpr(InitListExpr *ILE) {
+ if (ILE->getType()->isScalarType()) {
+ // We have a scalar in braces. Just use the first element.
+ if (ILE->getNumInits() > 0) {
+ Expr *Init = ILE->getInit(0);
+ return CGM.EmitConstantExpr(Init, Init->getType(), CGF);
+ }
+ return CGM.EmitNullConstant(ILE->getType());
+ }
+
+ if (ILE->getType()->isArrayType())
+ return EmitArrayInitialization(ILE);
+
+ if (ILE->getType()->isStructureType())
+ return EmitStructInitialization(ILE);
+
+ if (ILE->getType()->isUnionType())
+ return EmitUnionInitialization(ILE);
+
+ if (ILE->getType()->isVectorType())
+ return EmitVectorInitialization(ILE);
+
+ assert(0 && "Unable to handle InitListExpr");
+ // Get rid of control reaches end of void function warning.
+ // Not reached.
+ return 0;
+ }
+
+ llvm::Constant *VisitStringLiteral(StringLiteral *E) {
+ assert(!E->getType()->isPointerType() && "Strings are always arrays");
+
+ // This must be a string initializing an array in a static initializer.
+ // Don't emit it as the address of the string, emit the string data itself
+ // as an inline array.
+ return llvm::ConstantArray::get(CGM.GetStringForStringLiteral(E), false);
+ }
+
+ llvm::Constant *VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
+ // This must be an @encode initializing an array in a static initializer.
+ // Don't emit it as the address of the string, emit the string data itself
+ // as an inline array.
+ std::string Str;
+ CGM.getContext().getObjCEncodingForType(E->getEncodedType(), Str);
+ const ConstantArrayType *CAT = cast<ConstantArrayType>(E->getType());
+
+ // Resize the string to the right size, adding zeros at the end, or
+ // truncating as needed.
+ Str.resize(CAT->getSize().getZExtValue(), '\0');
+ return llvm::ConstantArray::get(Str, false);
+ }
+
+ llvm::Constant *VisitUnaryExtension(const UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
+
+ // Utility methods
+ const llvm::Type *ConvertType(QualType T) {
+ return CGM.getTypes().ConvertType(T);
+ }
+
+public:
+ llvm::Constant *EmitLValue(Expr *E) {
+ switch (E->getStmtClass()) {
+ default: break;
+ case Expr::CompoundLiteralExprClass: {
+ // Note that due to the nature of compound literals, this is guaranteed
+ // to be the only use of the variable, so we just generate it here.
+ CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E);
+ llvm::Constant* C = Visit(CLE->getInitializer());
+ // FIXME: "Leaked" on failure.
+ if (C)
+ C = new llvm::GlobalVariable(C->getType(),
+ E->getType().isConstQualified(),
+ llvm::GlobalValue::InternalLinkage,
+ C, ".compoundliteral", &CGM.getModule());
+ return C;
+ }
+ case Expr::DeclRefExprClass:
+ case Expr::QualifiedDeclRefExprClass: {
+ NamedDecl *Decl = cast<DeclRefExpr>(E)->getDecl();
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl))
+ return CGM.GetAddrOfFunction(GlobalDecl(FD));
+ if (const VarDecl* VD = dyn_cast<VarDecl>(Decl)) {
+ // We can never refer to a variable with local storage.
+ if (!VD->hasLocalStorage()) {
+ if (VD->isFileVarDecl() || VD->hasExternalStorage())
+ return CGM.GetAddrOfGlobalVar(VD);
+ else if (VD->isBlockVarDecl()) {
+ assert(CGF && "Can't access static local vars without CGF");
+ return CGF->GetAddrOfStaticLocalVar(VD);
+ }
+ }
+ }
+ break;
+ }
+ case Expr::StringLiteralClass:
+ return CGM.GetAddrOfConstantStringFromLiteral(cast<StringLiteral>(E));
+ case Expr::ObjCEncodeExprClass:
+ return CGM.GetAddrOfConstantStringFromObjCEncode(cast<ObjCEncodeExpr>(E));
+ case Expr::ObjCStringLiteralClass: {
+ ObjCStringLiteral* SL = cast<ObjCStringLiteral>(E);
+ llvm::Constant *C = CGM.getObjCRuntime().GenerateConstantString(SL);
+ return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType()));
+ }
+ case Expr::PredefinedExprClass: {
+ // __func__/__FUNCTION__ -> "". __PRETTY_FUNCTION__ -> "top level".
+ std::string Str;
+ if (cast<PredefinedExpr>(E)->getIdentType() ==
+ PredefinedExpr::PrettyFunction)
+ Str = "top level";
+
+ return CGM.GetAddrOfConstantCString(Str, ".tmp");
+ }
+ case Expr::AddrLabelExprClass: {
+ assert(CGF && "Invalid address of label expression outside function.");
+ unsigned id = CGF->GetIDForAddrOfLabel(cast<AddrLabelExpr>(E)->getLabel());
+ llvm::Constant *C = llvm::ConstantInt::get(llvm::Type::Int32Ty, id);
+ return llvm::ConstantExpr::getIntToPtr(C, ConvertType(E->getType()));
+ }
+ case Expr::CallExprClass: {
+ CallExpr* CE = cast<CallExpr>(E);
+ if (CE->isBuiltinCall(CGM.getContext()) !=
+ Builtin::BI__builtin___CFStringMakeConstantString)
+ break;
+ const Expr *Arg = CE->getArg(0)->IgnoreParenCasts();
+ const StringLiteral *Literal = cast<StringLiteral>(Arg);
+ // FIXME: need to deal with UCN conversion issues.
+ return CGM.GetAddrOfConstantCFString(Literal);
+ }
+ case Expr::BlockExprClass: {
+ std::string FunctionName;
+ if (CGF)
+ FunctionName = CGF->CurFn->getName();
+ else
+ FunctionName = "global";
+
+ return CGM.GetAddrOfGlobalBlock(cast<BlockExpr>(E), FunctionName.c_str());
+ }
+ }
+
+ return 0;
+ }
+};
+
+} // end anonymous namespace.
+
+llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
+ QualType DestType,
+ CodeGenFunction *CGF) {
+ Expr::EvalResult Result;
+
+ bool Success = false;
+
+ if (DestType->isReferenceType())
+ Success = E->EvaluateAsLValue(Result, Context);
+ else
+ Success = E->Evaluate(Result, Context);
+
+ if (Success) {
+ assert(!Result.HasSideEffects &&
+ "Constant expr should not have any side effects!");
+ switch (Result.Val.getKind()) {
+ case APValue::Uninitialized:
+ assert(0 && "Constant expressions should be initialized.");
+ return 0;
+ case APValue::LValue: {
+ const llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType);
+ llvm::Constant *Offset =
+ llvm::ConstantInt::get(llvm::Type::Int64Ty,
+ Result.Val.getLValueOffset());
+
+ llvm::Constant *C;
+ if (const Expr *LVBase = Result.Val.getLValueBase()) {
+ C = ConstExprEmitter(*this, CGF).EmitLValue(const_cast<Expr*>(LVBase));
+
+ // Apply offset if necessary.
+ if (!Offset->isNullValue()) {
+ const llvm::Type *Type =
+ llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, Type);
+ Casted = llvm::ConstantExpr::getGetElementPtr(Casted, &Offset, 1);
+ C = llvm::ConstantExpr::getBitCast(Casted, C->getType());
+ }
+
+ // Convert to the appropriate type; this could be an lvalue for
+ // an integer.
+ if (isa<llvm::PointerType>(DestTy))
+ return llvm::ConstantExpr::getBitCast(C, DestTy);
+
+ return llvm::ConstantExpr::getPtrToInt(C, DestTy);
+ } else {
+ C = Offset;
+
+ // Convert to the appropriate type; this could be an lvalue for
+ // an integer.
+ if (isa<llvm::PointerType>(DestTy))
+ return llvm::ConstantExpr::getIntToPtr(C, DestTy);
+
+ // If the types don't match this should only be a truncate.
+ if (C->getType() != DestTy)
+ return llvm::ConstantExpr::getTrunc(C, DestTy);
+
+ return C;
+ }
+ }
+ case APValue::Int: {
+ llvm::Constant *C = llvm::ConstantInt::get(Result.Val.getInt());
+
+ if (C->getType() == llvm::Type::Int1Ty) {
+ const llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
+ C = llvm::ConstantExpr::getZExt(C, BoolTy);
+ }
+ return C;
+ }
+ case APValue::ComplexInt: {
+ llvm::Constant *Complex[2];
+
+ Complex[0] = llvm::ConstantInt::get(Result.Val.getComplexIntReal());
+ Complex[1] = llvm::ConstantInt::get(Result.Val.getComplexIntImag());
+
+ return llvm::ConstantStruct::get(Complex, 2);
+ }
+ case APValue::Float:
+ return llvm::ConstantFP::get(Result.Val.getFloat());
+ case APValue::ComplexFloat: {
+ llvm::Constant *Complex[2];
+
+ Complex[0] = llvm::ConstantFP::get(Result.Val.getComplexFloatReal());
+ Complex[1] = llvm::ConstantFP::get(Result.Val.getComplexFloatImag());
+
+ return llvm::ConstantStruct::get(Complex, 2);
+ }
+ case APValue::Vector: {
+ llvm::SmallVector<llvm::Constant *, 4> Inits;
+ unsigned NumElts = Result.Val.getVectorLength();
+
+ for (unsigned i = 0; i != NumElts; ++i) {
+ APValue &Elt = Result.Val.getVectorElt(i);
+ if (Elt.isInt())
+ Inits.push_back(llvm::ConstantInt::get(Elt.getInt()));
+ else
+ Inits.push_back(llvm::ConstantFP::get(Elt.getFloat()));
+ }
+ return llvm::ConstantVector::get(&Inits[0], Inits.size());
+ }
+ }
+ }
+
+ llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E));
+ if (C && C->getType() == llvm::Type::Int1Ty) {
+ const llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
+ C = llvm::ConstantExpr::getZExt(C, BoolTy);
+ }
+ return C;
+}
+
+llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
+ // Always return an LLVM null constant for now; this will change when we
+ // get support for IRGen of member pointers.
+ return llvm::Constant::getNullValue(getTypes().ConvertType(T));
+}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
new file mode 100644
index 000000000000..950e9e55095c
--- /dev/null
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -0,0 +1,1575 @@
+//===--- CGExprScalar.cpp - Emit LLVM Code for Scalar Exprs ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit Expr nodes with scalar LLVM types as LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/Constants.h"
+#include "llvm/Function.h"
+#include "llvm/GlobalVariable.h"
+#include "llvm/Intrinsics.h"
+#include "llvm/Module.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/CFG.h"
+#include "llvm/Target/TargetData.h"
+#include <cstdarg>
+
+using namespace clang;
+using namespace CodeGen;
+using llvm::Value;
+
+//===----------------------------------------------------------------------===//
+// Scalar Expression Emitter
+//===----------------------------------------------------------------------===//
+
+struct BinOpInfo {
+ Value *LHS;
+ Value *RHS;
+ QualType Ty; // Computation Type.
+ const BinaryOperator *E;
+};
+
+namespace {
+class VISIBILITY_HIDDEN ScalarExprEmitter
+ : public StmtVisitor<ScalarExprEmitter, Value*> {
+ CodeGenFunction &CGF;
+ CGBuilderTy &Builder;
+ bool IgnoreResultAssign;
+
+public:
+
+ ScalarExprEmitter(CodeGenFunction &cgf, bool ira=false)
+ : CGF(cgf), Builder(CGF.Builder), IgnoreResultAssign(ira) {
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Utilities
+ //===--------------------------------------------------------------------===//
+
+ bool TestAndClearIgnoreResultAssign() {
+ bool I = IgnoreResultAssign; IgnoreResultAssign = false;
+ return I; }
+
+ const llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); }
+ LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); }
+
+ Value *EmitLoadOfLValue(LValue LV, QualType T) {
+ return CGF.EmitLoadOfLValue(LV, T).getScalarVal();
+ }
+
+ /// EmitLoadOfLValue - Given an expression with complex type that represents a
+ /// value l-value, this method emits the address of the l-value, then loads
+ /// and returns the result.
+ Value *EmitLoadOfLValue(const Expr *E) {
+ return EmitLoadOfLValue(EmitLValue(E), E->getType());
+ }
+
+ /// EmitConversionToBool - Convert the specified expression value to a
+ /// boolean (i1) truth value. This is equivalent to "Val != 0".
+ Value *EmitConversionToBool(Value *Src, QualType DstTy);
+
+ /// EmitScalarConversion - Emit a conversion from the specified type to the
+ /// specified destination type, both of which are LLVM scalar types.
+ Value *EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy);
+
+ /// EmitComplexToScalarConversion - Emit a conversion from the specified
+ /// complex type to the specified destination type, where the destination
+ /// type is an LLVM scalar type.
+ Value *EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
+ QualType SrcTy, QualType DstTy);
+
+ //===--------------------------------------------------------------------===//
+ // Visitor Methods
+ //===--------------------------------------------------------------------===//
+
+ Value *VisitStmt(Stmt *S) {
+ S->dump(CGF.getContext().getSourceManager());
+ assert(0 && "Stmt can't have complex result type!");
+ return 0;
+ }
+ Value *VisitExpr(Expr *S);
+ Value *VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr()); }
+
+ // Leaves.
+ Value *VisitIntegerLiteral(const IntegerLiteral *E) {
+ return llvm::ConstantInt::get(E->getValue());
+ }
+ Value *VisitFloatingLiteral(const FloatingLiteral *E) {
+ return llvm::ConstantFP::get(E->getValue());
+ }
+ Value *VisitCharacterLiteral(const CharacterLiteral *E) {
+ return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
+ }
+ Value *VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) {
+ return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
+ }
+ Value *VisitCXXZeroInitValueExpr(const CXXZeroInitValueExpr *E) {
+ return llvm::Constant::getNullValue(ConvertType(E->getType()));
+ }
+ Value *VisitGNUNullExpr(const GNUNullExpr *E) {
+ return llvm::Constant::getNullValue(ConvertType(E->getType()));
+ }
+ Value *VisitTypesCompatibleExpr(const TypesCompatibleExpr *E) {
+ return llvm::ConstantInt::get(ConvertType(E->getType()),
+ CGF.getContext().typesAreCompatible(
+ E->getArgType1(), E->getArgType2()));
+ }
+ Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E);
+ Value *VisitAddrLabelExpr(const AddrLabelExpr *E) {
+ llvm::Value *V =
+ llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ CGF.GetIDForAddrOfLabel(E->getLabel()));
+
+ return Builder.CreateIntToPtr(V, ConvertType(E->getType()));
+ }
+
+ // l-values.
+ Value *VisitDeclRefExpr(DeclRefExpr *E) {
+ if (const EnumConstantDecl *EC = dyn_cast<EnumConstantDecl>(E->getDecl()))
+ return llvm::ConstantInt::get(EC->getInitVal());
+ return EmitLoadOfLValue(E);
+ }
+ Value *VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
+ return CGF.EmitObjCSelectorExpr(E);
+ }
+ Value *VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
+ return CGF.EmitObjCProtocolExpr(E);
+ }
+ Value *VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ return EmitLoadOfLValue(E);
+ }
+ Value *VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
+ return EmitLoadOfLValue(E);
+ }
+ Value *VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
+ return EmitLoadOfLValue(E);
+ }
+ Value *VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ return CGF.EmitObjCMessageExpr(E).getScalarVal();
+ }
+
+ Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E);
+ Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E);
+ Value *VisitMemberExpr(Expr *E) { return EmitLoadOfLValue(E); }
+ Value *VisitExtVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); }
+ Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ return EmitLoadOfLValue(E);
+ }
+ Value *VisitStringLiteral(Expr *E) { return EmitLValue(E).getAddress(); }
+ Value *VisitObjCEncodeExpr(const ObjCEncodeExpr *E) {
+ return EmitLValue(E).getAddress();
+ }
+
+ Value *VisitPredefinedExpr(Expr *E) { return EmitLValue(E).getAddress(); }
+
+ Value *VisitInitListExpr(InitListExpr *E) {
+ bool Ignore = TestAndClearIgnoreResultAssign();
+ (void)Ignore;
+ assert (Ignore == false && "init list ignored");
+ unsigned NumInitElements = E->getNumInits();
+
+ if (E->hadArrayRangeDesignator()) {
+ CGF.ErrorUnsupported(E, "GNU array range designator extension");
+ }
+
+ const llvm::VectorType *VType =
+ dyn_cast<llvm::VectorType>(ConvertType(E->getType()));
+
+ // We have a scalar in braces. Just use the first element.
+ if (!VType)
+ return Visit(E->getInit(0));
+
+ unsigned NumVectorElements = VType->getNumElements();
+ const llvm::Type *ElementType = VType->getElementType();
+
+ // Emit individual vector element stores.
+ llvm::Value *V = llvm::UndefValue::get(VType);
+
+ // Emit initializers
+ unsigned i;
+ for (i = 0; i < NumInitElements; ++i) {
+ Value *NewV = Visit(E->getInit(i));
+ Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i);
+ V = Builder.CreateInsertElement(V, NewV, Idx);
+ }
+
+ // Emit remaining default initializers
+ for (/* Do not initialize i*/; i < NumVectorElements; ++i) {
+ Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i);
+ llvm::Value *NewV = llvm::Constant::getNullValue(ElementType);
+ V = Builder.CreateInsertElement(V, NewV, Idx);
+ }
+
+ return V;
+ }
+
+ Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
+ return llvm::Constant::getNullValue(ConvertType(E->getType()));
+ }
+ Value *VisitImplicitCastExpr(const ImplicitCastExpr *E);
+ Value *VisitCastExpr(const CastExpr *E) {
+ // Make sure to evaluate VLA bounds now so that we have them for later.
+ if (E->getType()->isVariablyModifiedType())
+ CGF.EmitVLASize(E->getType());
+
+ return EmitCastExpr(E->getSubExpr(), E->getType());
+ }
+ Value *EmitCastExpr(const Expr *E, QualType T);
+
+ Value *VisitCallExpr(const CallExpr *E) {
+ if (E->getCallReturnType()->isReferenceType())
+ return EmitLoadOfLValue(E);
+
+ return CGF.EmitCallExpr(E).getScalarVal();
+ }
+
+ Value *VisitStmtExpr(const StmtExpr *E);
+
+ Value *VisitBlockDeclRefExpr(const BlockDeclRefExpr *E);
+
+ // Unary Operators.
+ Value *VisitPrePostIncDec(const UnaryOperator *E, bool isInc, bool isPre);
+ Value *VisitUnaryPostDec(const UnaryOperator *E) {
+ return VisitPrePostIncDec(E, false, false);
+ }
+ Value *VisitUnaryPostInc(const UnaryOperator *E) {
+ return VisitPrePostIncDec(E, true, false);
+ }
+ Value *VisitUnaryPreDec(const UnaryOperator *E) {
+ return VisitPrePostIncDec(E, false, true);
+ }
+ Value *VisitUnaryPreInc(const UnaryOperator *E) {
+ return VisitPrePostIncDec(E, true, true);
+ }
+ Value *VisitUnaryAddrOf(const UnaryOperator *E) {
+ return EmitLValue(E->getSubExpr()).getAddress();
+ }
+ Value *VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); }
+ Value *VisitUnaryPlus(const UnaryOperator *E) {
+ // This differs from gcc, though, most likely due to a bug in gcc.
+ TestAndClearIgnoreResultAssign();
+ return Visit(E->getSubExpr());
+ }
+ Value *VisitUnaryMinus (const UnaryOperator *E);
+ Value *VisitUnaryNot (const UnaryOperator *E);
+ Value *VisitUnaryLNot (const UnaryOperator *E);
+ Value *VisitUnaryReal (const UnaryOperator *E);
+ Value *VisitUnaryImag (const UnaryOperator *E);
+ Value *VisitUnaryExtension(const UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
+ Value *VisitUnaryOffsetOf(const UnaryOperator *E);
+
+ // C++
+ Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
+ return Visit(DAE->getExpr());
+ }
+ Value *VisitCXXThisExpr(CXXThisExpr *TE) {
+ return CGF.LoadCXXThis();
+ }
+
+ Value *VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
+ return CGF.EmitCXXExprWithTemporaries(E).getScalarVal();
+ }
+ Value *VisitCXXNewExpr(const CXXNewExpr *E) {
+ return CGF.EmitCXXNewExpr(E);
+ }
+
+ // Binary Operators.
+ Value *EmitMul(const BinOpInfo &Ops) {
+ if (CGF.getContext().getLangOptions().OverflowChecking
+ && Ops.Ty->isSignedIntegerType())
+ return EmitOverflowCheckedBinOp(Ops);
+ return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
+ }
+ /// Create a binary op that checks for overflow.
+ /// Currently only supports +, - and *.
+ Value *EmitOverflowCheckedBinOp(const BinOpInfo &Ops);
+ Value *EmitDiv(const BinOpInfo &Ops);
+ Value *EmitRem(const BinOpInfo &Ops);
+ Value *EmitAdd(const BinOpInfo &Ops);
+ Value *EmitSub(const BinOpInfo &Ops);
+ Value *EmitShl(const BinOpInfo &Ops);
+ Value *EmitShr(const BinOpInfo &Ops);
+ Value *EmitAnd(const BinOpInfo &Ops) {
+ return Builder.CreateAnd(Ops.LHS, Ops.RHS, "and");
+ }
+ Value *EmitXor(const BinOpInfo &Ops) {
+ return Builder.CreateXor(Ops.LHS, Ops.RHS, "xor");
+ }
+ Value *EmitOr (const BinOpInfo &Ops) {
+ return Builder.CreateOr(Ops.LHS, Ops.RHS, "or");
+ }
+
+ BinOpInfo EmitBinOps(const BinaryOperator *E);
+ Value *EmitCompoundAssign(const CompoundAssignOperator *E,
+ Value *(ScalarExprEmitter::*F)(const BinOpInfo &));
+
+ // Binary operators and binary compound assignment operators.
+#define HANDLEBINOP(OP) \
+ Value *VisitBin ## OP(const BinaryOperator *E) { \
+ return Emit ## OP(EmitBinOps(E)); \
+ } \
+ Value *VisitBin ## OP ## Assign(const CompoundAssignOperator *E) { \
+ return EmitCompoundAssign(E, &ScalarExprEmitter::Emit ## OP); \
+ }
+ HANDLEBINOP(Mul);
+ HANDLEBINOP(Div);
+ HANDLEBINOP(Rem);
+ HANDLEBINOP(Add);
+ HANDLEBINOP(Sub);
+ HANDLEBINOP(Shl);
+ HANDLEBINOP(Shr);
+ HANDLEBINOP(And);
+ HANDLEBINOP(Xor);
+ HANDLEBINOP(Or);
+#undef HANDLEBINOP
+
+ // Comparisons.
+ Value *EmitCompare(const BinaryOperator *E, unsigned UICmpOpc,
+ unsigned SICmpOpc, unsigned FCmpOpc);
+#define VISITCOMP(CODE, UI, SI, FP) \
+ Value *VisitBin##CODE(const BinaryOperator *E) { \
+ return EmitCompare(E, llvm::ICmpInst::UI, llvm::ICmpInst::SI, \
+ llvm::FCmpInst::FP); }
+ VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT);
+ VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT);
+ VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE);
+ VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE);
+ VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ);
+ VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE);
+#undef VISITCOMP
+
+ Value *VisitBinAssign (const BinaryOperator *E);
+
+ Value *VisitBinLAnd (const BinaryOperator *E);
+ Value *VisitBinLOr (const BinaryOperator *E);
+ Value *VisitBinComma (const BinaryOperator *E);
+
+ // Other Operators.
+ Value *VisitBlockExpr(const BlockExpr *BE);
+ Value *VisitConditionalOperator(const ConditionalOperator *CO);
+ Value *VisitChooseExpr(ChooseExpr *CE);
+ Value *VisitVAArgExpr(VAArgExpr *VE);
+ Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) {
+ return CGF.EmitObjCStringLiteral(E);
+ }
+};
+} // end anonymous namespace.
+
+//===----------------------------------------------------------------------===//
+// Utilities
+//===----------------------------------------------------------------------===//
+
+/// EmitConversionToBool - Convert the specified expression value to a
+/// boolean (i1) truth value. This is equivalent to "Val != 0".
+Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) {
+ assert(SrcType->isCanonical() && "EmitScalarConversion strips typedefs");
+
+ if (SrcType->isRealFloatingType()) {
+ // Compare against 0.0 for fp scalars.
+ llvm::Value *Zero = llvm::Constant::getNullValue(Src->getType());
+ return Builder.CreateFCmpUNE(Src, Zero, "tobool");
+ }
+
+ assert((SrcType->isIntegerType() || isa<llvm::PointerType>(Src->getType())) &&
+ "Unknown scalar type to convert");
+
+ // Because of the type rules of C, we often end up computing a logical value,
+ // then zero extending it to int, then wanting it as a logical value again.
+ // Optimize this common case.
+ if (llvm::ZExtInst *ZI = dyn_cast<llvm::ZExtInst>(Src)) {
+ if (ZI->getOperand(0)->getType() == llvm::Type::Int1Ty) {
+ Value *Result = ZI->getOperand(0);
+ // If there aren't any more uses, zap the instruction to save space.
+ // Note that there can be more uses, for example if this
+ // is the result of an assignment.
+ if (ZI->use_empty())
+ ZI->eraseFromParent();
+ return Result;
+ }
+ }
+
+ // Compare against an integer or pointer null.
+ llvm::Value *Zero = llvm::Constant::getNullValue(Src->getType());
+ return Builder.CreateICmpNE(Src, Zero, "tobool");
+}
+
+/// EmitScalarConversion - Emit a conversion from the specified type to the
+/// specified destination type, both of which are LLVM scalar types.
+Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
+ QualType DstType) {
+ SrcType = CGF.getContext().getCanonicalType(SrcType);
+ DstType = CGF.getContext().getCanonicalType(DstType);
+ if (SrcType == DstType) return Src;
+
+ if (DstType->isVoidType()) return 0;
+
+ // Handle conversions to bool first, they are special: comparisons against 0.
+ if (DstType->isBooleanType())
+ return EmitConversionToBool(Src, SrcType);
+
+ const llvm::Type *DstTy = ConvertType(DstType);
+
+ // Ignore conversions like int -> uint.
+ if (Src->getType() == DstTy)
+ return Src;
+
+ // Handle pointer conversions next: pointers can only be converted
+ // to/from other pointers and integers. Check for pointer types in
+ // terms of LLVM, as 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()))
+ 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 = llvm::IntegerType::get(CGF.LLVMPointerWidth);
+ bool InputSigned = SrcType->isSignedIntegerType();
+ llvm::Value* IntResult =
+ Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv");
+ // Then, cast to pointer.
+ return Builder.CreateIntToPtr(IntResult, DstTy, "conv");
+ }
+
+ if (isa<llvm::PointerType>(Src->getType())) {
+ // Must be an ptr to int cast.
+ assert(isa<llvm::IntegerType>(DstTy) && "not ptr->int?");
+ return Builder.CreatePtrToInt(Src, DstTy, "conv");
+ }
+
+ // A scalar can be splatted to an extended vector of the same element type
+ if (DstType->isExtVectorType() && !isa<VectorType>(SrcType)) {
+ // Cast the scalar to element type
+ QualType EltTy = DstType->getAsExtVectorType()->getElementType();
+ llvm::Value *Elt = EmitScalarConversion(Src, SrcType, EltTy);
+
+ // Insert the element in element zero of an undef vector
+ llvm::Value *UnV = llvm::UndefValue::get(DstTy);
+ llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
+ UnV = Builder.CreateInsertElement(UnV, Elt, Idx, "tmp");
+
+ // Splat the element across to all elements
+ llvm::SmallVector<llvm::Constant*, 16> Args;
+ unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
+ for (unsigned i = 0; i < NumElements; i++)
+ Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0));
+
+ llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements);
+ llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat");
+ return Yay;
+ }
+
+ // Allow bitcast from vector to integer/fp of the same size.
+ if (isa<llvm::VectorType>(Src->getType()) ||
+ 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())) {
+ bool InputSigned = SrcType->isSignedIntegerType();
+ if (isa<llvm::IntegerType>(DstTy))
+ return Builder.CreateIntCast(Src, DstTy, InputSigned, "conv");
+ else if (InputSigned)
+ return Builder.CreateSIToFP(Src, DstTy, "conv");
+ else
+ return Builder.CreateUIToFP(Src, DstTy, "conv");
+ }
+
+ assert(Src->getType()->isFloatingPoint() && "Unknown real conversion");
+ if (isa<llvm::IntegerType>(DstTy)) {
+ if (DstType->isSignedIntegerType())
+ return Builder.CreateFPToSI(Src, DstTy, "conv");
+ else
+ return Builder.CreateFPToUI(Src, DstTy, "conv");
+ }
+
+ assert(DstTy->isFloatingPoint() && "Unknown real conversion");
+ if (DstTy->getTypeID() < Src->getType()->getTypeID())
+ return Builder.CreateFPTrunc(Src, DstTy, "conv");
+ else
+ return Builder.CreateFPExt(Src, DstTy, "conv");
+}
+
+/// EmitComplexToScalarConversion - Emit a conversion from the specified
+/// complex type to the specified destination type, where the destination
+/// type is an LLVM scalar type.
+Value *ScalarExprEmitter::
+EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
+ QualType SrcTy, QualType DstTy) {
+ // Get the source element type.
+ SrcTy = SrcTy->getAsComplexType()->getElementType();
+
+ // Handle conversions to bool first, they are special: comparisons against 0.
+ if (DstTy->isBooleanType()) {
+ // Complex != 0 -> (Real != 0) | (Imag != 0)
+ Src.first = EmitScalarConversion(Src.first, SrcTy, DstTy);
+ Src.second = EmitScalarConversion(Src.second, SrcTy, DstTy);
+ return Builder.CreateOr(Src.first, Src.second, "tobool");
+ }
+
+ // C99 6.3.1.7p2: "When a value of complex type is converted to a real type,
+ // the imaginary part of the complex value is discarded and the value of the
+ // real part is converted according to the conversion rules for the
+ // corresponding real type.
+ return EmitScalarConversion(Src.first, SrcTy, DstTy);
+}
+
+
+//===----------------------------------------------------------------------===//
+// Visitor Methods
+//===----------------------------------------------------------------------===//
+
+Value *ScalarExprEmitter::VisitExpr(Expr *E) {
+ CGF.ErrorUnsupported(E, "scalar expression");
+ if (E->getType()->isVoidType())
+ return 0;
+ return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
+}
+
+Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
+ llvm::SmallVector<llvm::Constant*, 32> indices;
+ for (unsigned i = 2; i < E->getNumSubExprs(); i++) {
+ indices.push_back(cast<llvm::Constant>(CGF.EmitScalarExpr(E->getExpr(i))));
+ }
+ Value* V1 = CGF.EmitScalarExpr(E->getExpr(0));
+ Value* V2 = CGF.EmitScalarExpr(E->getExpr(1));
+ Value* SV = llvm::ConstantVector::get(indices.begin(), indices.size());
+ return Builder.CreateShuffleVector(V1, V2, SV, "shuffle");
+}
+
+Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+ TestAndClearIgnoreResultAssign();
+
+ // Emit subscript expressions in rvalue context's. For most cases, this just
+ // loads the lvalue formed by the subscript expr. However, we have to be
+ // careful, because the base of a vector subscript is occasionally an rvalue,
+ // so we can't get it as an lvalue.
+ if (!E->getBase()->getType()->isVectorType())
+ return EmitLoadOfLValue(E);
+
+ // Handle the vector case. The base must be a vector, the index must be an
+ // integer value.
+ Value *Base = Visit(E->getBase());
+ Value *Idx = Visit(E->getIdx());
+ bool IdxSigned = E->getIdx()->getType()->isSignedIntegerType();
+ Idx = Builder.CreateIntCast(Idx, llvm::Type::Int32Ty, IdxSigned,
+ "vecidxcast");
+ return Builder.CreateExtractElement(Base, Idx, "vecext");
+}
+
+/// VisitImplicitCastExpr - Implicit casts are the same as normal casts, but
+/// also handle things like function to pointer-to-function decay, and array to
+/// pointer decay.
+Value *ScalarExprEmitter::VisitImplicitCastExpr(const ImplicitCastExpr *E) {
+ const Expr *Op = E->getSubExpr();
+
+ // If this is due to array->pointer conversion, emit the array expression as
+ // an l-value.
+ if (Op->getType()->isArrayType()) {
+ Value *V = EmitLValue(Op).getAddress(); // Bitfields can't be arrays.
+
+ // Note that VLA pointers are always decayed, so we don't need to do
+ // anything here.
+ if (!Op->getType()->isVariableArrayType()) {
+ assert(isa<llvm::PointerType>(V->getType()) && "Expected pointer");
+ assert(isa<llvm::ArrayType>(cast<llvm::PointerType>(V->getType())
+ ->getElementType()) &&
+ "Expected pointer to array");
+ V = Builder.CreateStructGEP(V, 0, "arraydecay");
+ }
+
+ // The resultant pointer type can be implicitly casted to other pointer
+ // types as well (e.g. void*) and can be implicitly converted to integer.
+ const llvm::Type *DestTy = ConvertType(E->getType());
+ if (V->getType() != DestTy) {
+ if (isa<llvm::PointerType>(DestTy))
+ V = Builder.CreateBitCast(V, DestTy, "ptrconv");
+ else {
+ assert(isa<llvm::IntegerType>(DestTy) && "Unknown array decay");
+ V = Builder.CreatePtrToInt(V, DestTy, "ptrconv");
+ }
+ }
+ return V;
+ }
+
+ return EmitCastExpr(Op, E->getType());
+}
+
+
+// VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts
+// have to handle a more broad range of conversions than explicit casts, as they
+// handle things like function to ptr-to-function decay etc.
+Value *ScalarExprEmitter::EmitCastExpr(const Expr *E, QualType DestTy) {
+ if (!DestTy->isVoidType())
+ TestAndClearIgnoreResultAssign();
+
+ // Handle cases where the source is an non-complex type.
+
+ if (!CGF.hasAggregateLLVMType(E->getType())) {
+ Value *Src = Visit(const_cast<Expr*>(E));
+
+ // Use EmitScalarConversion to perform the conversion.
+ return EmitScalarConversion(Src, E->getType(), DestTy);
+ }
+
+ if (E->getType()->isAnyComplexType()) {
+ // Handle cases where the source is a complex type.
+ bool IgnoreImag = true;
+ bool IgnoreImagAssign = true;
+ bool IgnoreReal = IgnoreResultAssign;
+ bool IgnoreRealAssign = IgnoreResultAssign;
+ if (DestTy->isBooleanType())
+ IgnoreImagAssign = IgnoreImag = false;
+ else if (DestTy->isVoidType()) {
+ IgnoreReal = IgnoreImag = false;
+ IgnoreRealAssign = IgnoreImagAssign = true;
+ }
+ CodeGenFunction::ComplexPairTy V
+ = CGF.EmitComplexExpr(E, IgnoreReal, IgnoreImag, IgnoreRealAssign,
+ IgnoreImagAssign);
+ return EmitComplexToScalarConversion(V, E->getType(), DestTy);
+ }
+
+ // Okay, this is a cast from an aggregate. It must be a cast to void. Just
+ // evaluate the result and return.
+ CGF.EmitAggExpr(E, 0, false, true);
+ return 0;
+}
+
+Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) {
+ return CGF.EmitCompoundStmt(*E->getSubStmt(),
+ !E->getType()->isVoidType()).getScalarVal();
+}
+
+Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
+ return Builder.CreateLoad(CGF.GetAddrOfBlockDecl(E), false, "tmp");
+}
+
+//===----------------------------------------------------------------------===//
+// Unary Operators
+//===----------------------------------------------------------------------===//
+
+Value *ScalarExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
+ bool isInc, bool isPre) {
+ LValue LV = EmitLValue(E->getSubExpr());
+ QualType ValTy = E->getSubExpr()->getType();
+ Value *InVal = CGF.EmitLoadOfLValue(LV, ValTy).getScalarVal();
+
+ int AmountVal = isInc ? 1 : -1;
+
+ if (ValTy->isPointerType() &&
+ ValTy->getAsPointerType()->isVariableArrayType()) {
+ // The amount of the addition/subtraction needs to account for the VLA size
+ CGF.ErrorUnsupported(E, "VLA pointer inc/dec");
+ }
+
+ Value *NextVal;
+ if (const llvm::PointerType *PT =
+ dyn_cast<llvm::PointerType>(InVal->getType())) {
+ llvm::Constant *Inc =llvm::ConstantInt::get(llvm::Type::Int32Ty, AmountVal);
+ if (!isa<llvm::FunctionType>(PT->getElementType())) {
+ NextVal = Builder.CreateGEP(InVal, Inc, "ptrincdec");
+ } else {
+ const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ NextVal = Builder.CreateBitCast(InVal, i8Ty, "tmp");
+ NextVal = Builder.CreateGEP(NextVal, Inc, "ptrincdec");
+ NextVal = Builder.CreateBitCast(NextVal, InVal->getType());
+ }
+ } else if (InVal->getType() == llvm::Type::Int1Ty && isInc) {
+ // Bool++ is an interesting case, due to promotion rules, we get:
+ // Bool++ -> Bool = Bool+1 -> Bool = (int)Bool+1 ->
+ // Bool = ((int)Bool+1) != 0
+ // An interesting aspect of this is that increment is always true.
+ // Decrement does not have this property.
+ NextVal = llvm::ConstantInt::getTrue();
+ } else {
+ // Add the inc/dec to the real part.
+ if (isa<llvm::IntegerType>(InVal->getType()))
+ NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal);
+ else if (InVal->getType() == llvm::Type::FloatTy)
+ NextVal =
+ llvm::ConstantFP::get(llvm::APFloat(static_cast<float>(AmountVal)));
+ else if (InVal->getType() == llvm::Type::DoubleTy)
+ NextVal =
+ llvm::ConstantFP::get(llvm::APFloat(static_cast<double>(AmountVal)));
+ else {
+ llvm::APFloat F(static_cast<float>(AmountVal));
+ bool ignored;
+ F.convert(CGF.Target.getLongDoubleFormat(), llvm::APFloat::rmTowardZero,
+ &ignored);
+ NextVal = llvm::ConstantFP::get(F);
+ }
+ NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec");
+ }
+
+ // Store the updated result through the lvalue.
+ if (LV.isBitfield())
+ CGF.EmitStoreThroughBitfieldLValue(RValue::get(NextVal), LV, ValTy,
+ &NextVal);
+ else
+ CGF.EmitStoreThroughLValue(RValue::get(NextVal), LV, ValTy);
+
+ // If this is a postinc, return the value read from memory, otherwise use the
+ // updated value.
+ return isPre ? NextVal : InVal;
+}
+
+
+Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
+ TestAndClearIgnoreResultAssign();
+ Value *Op = Visit(E->getSubExpr());
+ return Builder.CreateNeg(Op, "neg");
+}
+
+Value *ScalarExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
+ TestAndClearIgnoreResultAssign();
+ Value *Op = Visit(E->getSubExpr());
+ return Builder.CreateNot(Op, "neg");
+}
+
+Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
+ // Compare operand to zero.
+ Value *BoolVal = CGF.EvaluateExprAsBool(E->getSubExpr());
+
+ // Invert value.
+ // TODO: Could dynamically modify easy computations here. For example, if
+ // the operand is an icmp ne, turn into icmp eq.
+ BoolVal = Builder.CreateNot(BoolVal, "lnot");
+
+ // ZExt result to the expr type.
+ return Builder.CreateZExt(BoolVal, ConvertType(E->getType()), "lnot.ext");
+}
+
+/// VisitSizeOfAlignOfExpr - Return the size or alignment of the type of
+/// argument of the sizeof expression as an integer.
+Value *
+ScalarExprEmitter::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
+ QualType TypeToSize = E->getTypeOfArgument();
+ if (E->isSizeOf()) {
+ if (const VariableArrayType *VAT =
+ CGF.getContext().getAsVariableArrayType(TypeToSize)) {
+ if (E->isArgumentType()) {
+ // sizeof(type) - make sure to emit the VLA size.
+ CGF.EmitVLASize(TypeToSize);
+ } else {
+ // C99 6.5.3.4p2: If the argument is an expression of type
+ // VLA, it is evaluated.
+ CGF.EmitAnyExpr(E->getArgumentExpr());
+ }
+
+ return CGF.GetVLASize(VAT);
+ }
+ }
+
+ // If this isn't sizeof(vla), the result must be constant; use the
+ // constant folding logic so we don't have to duplicate it here.
+ Expr::EvalResult Result;
+ E->Evaluate(Result, CGF.getContext());
+ return llvm::ConstantInt::get(Result.Val.getInt());
+}
+
+Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) {
+ Expr *Op = E->getSubExpr();
+ if (Op->getType()->isAnyComplexType())
+ return CGF.EmitComplexExpr(Op, false, true, false, true).first;
+ return Visit(Op);
+}
+Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) {
+ Expr *Op = E->getSubExpr();
+ if (Op->getType()->isAnyComplexType())
+ return CGF.EmitComplexExpr(Op, true, false, true, false).second;
+
+ // __imag on a scalar returns zero. Emit the subexpr to ensure side
+ // effects are evaluated, but not the actual value.
+ if (E->isLvalue(CGF.getContext()) == Expr::LV_Valid)
+ CGF.EmitLValue(Op);
+ else
+ CGF.EmitScalarExpr(Op, true);
+ return llvm::Constant::getNullValue(ConvertType(E->getType()));
+}
+
+Value *ScalarExprEmitter::VisitUnaryOffsetOf(const UnaryOperator *E)
+{
+ Value* ResultAsPtr = EmitLValue(E->getSubExpr()).getAddress();
+ const llvm::Type* ResultType = ConvertType(E->getType());
+ return Builder.CreatePtrToInt(ResultAsPtr, ResultType, "offsetof");
+}
+
+//===----------------------------------------------------------------------===//
+// Binary Operators
+//===----------------------------------------------------------------------===//
+
+BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) {
+ TestAndClearIgnoreResultAssign();
+ BinOpInfo Result;
+ Result.LHS = Visit(E->getLHS());
+ Result.RHS = Visit(E->getRHS());
+ Result.Ty = E->getType();
+ Result.E = E;
+ return Result;
+}
+
+Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
+ Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
+ bool Ignore = TestAndClearIgnoreResultAssign();
+ QualType LHSTy = E->getLHS()->getType(), RHSTy = E->getRHS()->getType();
+
+ BinOpInfo OpInfo;
+
+ if (E->getComputationResultType()->isAnyComplexType()) {
+ // This needs to go through the complex expression emitter, but
+ // it's a tad complicated to do that... I'm leaving it out for now.
+ // (Note that we do actually need the imaginary part of the RHS for
+ // multiplication and division.)
+ CGF.ErrorUnsupported(E, "complex compound assignment");
+ return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
+ }
+
+ // Emit the RHS first. __block variables need to have the rhs evaluated
+ // first, plus this should improve codegen a little.
+ OpInfo.RHS = Visit(E->getRHS());
+ OpInfo.Ty = E->getComputationResultType();
+ OpInfo.E = E;
+ // Load/convert the LHS.
+ LValue LHSLV = EmitLValue(E->getLHS());
+ OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy);
+ OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy,
+ E->getComputationLHSType());
+
+ // Expand the binary operator.
+ Value *Result = (this->*Func)(OpInfo);
+
+ // Convert the result back to the LHS type.
+ Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy);
+
+ // Store the result value into the LHS lvalue. Bit-fields are
+ // handled specially because the result is altered by the store,
+ // i.e., [C99 6.5.16p1] 'An assignment expression has the value of
+ // the left operand after the assignment...'.
+ if (LHSLV.isBitfield()) {
+ if (!LHSLV.isVolatileQualified()) {
+ CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy,
+ &Result);
+ return Result;
+ } else
+ CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy);
+ } else
+ CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, LHSTy);
+ if (Ignore)
+ return 0;
+ return EmitLoadOfLValue(LHSLV, E->getType());
+}
+
+
+Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
+ if (Ops.LHS->getType()->isFPOrFPVector())
+ return Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
+ else if (Ops.Ty->isUnsignedIntegerType())
+ return Builder.CreateUDiv(Ops.LHS, Ops.RHS, "div");
+ else
+ return Builder.CreateSDiv(Ops.LHS, Ops.RHS, "div");
+}
+
+Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) {
+ // Rem in C can't be a floating point type: C99 6.5.5p2.
+ if (Ops.Ty->isUnsignedIntegerType())
+ return Builder.CreateURem(Ops.LHS, Ops.RHS, "rem");
+ else
+ return Builder.CreateSRem(Ops.LHS, Ops.RHS, "rem");
+}
+
+Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
+ unsigned IID;
+ unsigned OpID = 0;
+
+ switch (Ops.E->getOpcode()) {
+ case BinaryOperator::Add:
+ case BinaryOperator::AddAssign:
+ OpID = 1;
+ IID = llvm::Intrinsic::sadd_with_overflow;
+ break;
+ case BinaryOperator::Sub:
+ case BinaryOperator::SubAssign:
+ OpID = 2;
+ IID = llvm::Intrinsic::ssub_with_overflow;
+ break;
+ case BinaryOperator::Mul:
+ case BinaryOperator::MulAssign:
+ OpID = 3;
+ IID = llvm::Intrinsic::smul_with_overflow;
+ break;
+ default:
+ assert(false && "Unsupported operation for overflow detection");
+ IID = 0;
+ }
+ OpID <<= 1;
+ OpID |= 1;
+
+ const llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(Ops.Ty);
+
+ llvm::Function *intrinsic = CGF.CGM.getIntrinsic(IID, &opTy, 1);
+
+ Value *resultAndOverflow = Builder.CreateCall2(intrinsic, Ops.LHS, Ops.RHS);
+ Value *result = Builder.CreateExtractValue(resultAndOverflow, 0);
+ Value *overflow = Builder.CreateExtractValue(resultAndOverflow, 1);
+
+ // Branch in case of overflow.
+ llvm::BasicBlock *initialBB = Builder.GetInsertBlock();
+ llvm::BasicBlock *overflowBB =
+ CGF.createBasicBlock("overflow", CGF.CurFn);
+ llvm::BasicBlock *continueBB =
+ CGF.createBasicBlock("overflow.continue", CGF.CurFn);
+
+ Builder.CreateCondBr(overflow, overflowBB, continueBB);
+
+ // Handle overflow
+
+ Builder.SetInsertPoint(overflowBB);
+
+ // Handler is:
+ // long long *__overflow_handler)(long long a, long long b, char op,
+ // char width)
+ std::vector<const llvm::Type*> handerArgTypes;
+ handerArgTypes.push_back(llvm::Type::Int64Ty);
+ handerArgTypes.push_back(llvm::Type::Int64Ty);
+ handerArgTypes.push_back(llvm::Type::Int8Ty);
+ handerArgTypes.push_back(llvm::Type::Int8Ty);
+ llvm::FunctionType *handlerTy = llvm::FunctionType::get(llvm::Type::Int64Ty,
+ handerArgTypes, false);
+ llvm::Value *handlerFunction =
+ CGF.CGM.getModule().getOrInsertGlobal("__overflow_handler",
+ llvm::PointerType::getUnqual(handlerTy));
+ handlerFunction = Builder.CreateLoad(handlerFunction);
+
+ llvm::Value *handlerResult = Builder.CreateCall4(handlerFunction,
+ Builder.CreateSExt(Ops.LHS, llvm::Type::Int64Ty),
+ Builder.CreateSExt(Ops.RHS, llvm::Type::Int64Ty),
+ llvm::ConstantInt::get(llvm::Type::Int8Ty, OpID),
+ llvm::ConstantInt::get(llvm::Type::Int8Ty,
+ cast<llvm::IntegerType>(opTy)->getBitWidth()));
+
+ handlerResult = Builder.CreateTrunc(handlerResult, opTy);
+
+ Builder.CreateBr(continueBB);
+
+ // Set up the continuation
+ Builder.SetInsertPoint(continueBB);
+ // Get the correct result
+ llvm::PHINode *phi = Builder.CreatePHI(opTy);
+ phi->reserveOperandSpace(2);
+ phi->addIncoming(result, initialBB);
+ phi->addIncoming(handlerResult, overflowBB);
+
+ return phi;
+}
+
+Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
+ if (!Ops.Ty->isPointerType()) {
+ if (CGF.getContext().getLangOptions().OverflowChecking
+ && Ops.Ty->isSignedIntegerType())
+ return EmitOverflowCheckedBinOp(Ops);
+ return Builder.CreateAdd(Ops.LHS, Ops.RHS, "add");
+ }
+
+ if (Ops.Ty->getAsPointerType()->isVariableArrayType()) {
+ // The amount of the addition needs to account for the VLA size
+ CGF.ErrorUnsupported(Ops.E, "VLA pointer addition");
+ }
+ Value *Ptr, *Idx;
+ Expr *IdxExp;
+ const PointerType *PT;
+ if ((PT = Ops.E->getLHS()->getType()->getAsPointerType())) {
+ Ptr = Ops.LHS;
+ Idx = Ops.RHS;
+ IdxExp = Ops.E->getRHS();
+ } else { // int + pointer
+ PT = Ops.E->getRHS()->getType()->getAsPointerType();
+ assert(PT && "Invalid add expr");
+ Ptr = Ops.RHS;
+ Idx = Ops.LHS;
+ IdxExp = Ops.E->getLHS();
+ }
+
+ unsigned Width = cast<llvm::IntegerType>(Idx->getType())->getBitWidth();
+ if (Width < CGF.LLVMPointerWidth) {
+ // Zero or sign extend the pointer value based on whether the index is
+ // signed or not.
+ const llvm::Type *IdxType = llvm::IntegerType::get(CGF.LLVMPointerWidth);
+ if (IdxExp->getType()->isSignedIntegerType())
+ Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext");
+ else
+ Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
+ }
+
+ const QualType ElementType = PT->getPointeeType();
+ // Handle interface types, which are not represented with a concrete
+ // type.
+ if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(ElementType)) {
+ llvm::Value *InterfaceSize =
+ llvm::ConstantInt::get(Idx->getType(),
+ CGF.getContext().getTypeSize(OIT) / 8);
+ Idx = Builder.CreateMul(Idx, InterfaceSize);
+ const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ Value *Casted = Builder.CreateBitCast(Ptr, i8Ty);
+ Value *Res = Builder.CreateGEP(Casted, Idx, "add.ptr");
+ return Builder.CreateBitCast(Res, Ptr->getType());
+ }
+
+ // Explicitly handle GNU void* and function pointer arithmetic
+ // extensions. The GNU void* casts amount to no-ops since our void*
+ // type is i8*, but this is future proof.
+ if (ElementType->isVoidType() || ElementType->isFunctionType()) {
+ const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ Value *Casted = Builder.CreateBitCast(Ptr, i8Ty);
+ Value *Res = Builder.CreateGEP(Casted, Idx, "add.ptr");
+ return Builder.CreateBitCast(Res, Ptr->getType());
+ }
+
+ return Builder.CreateGEP(Ptr, Idx, "add.ptr");
+}
+
+Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
+ if (!isa<llvm::PointerType>(Ops.LHS->getType())) {
+ if (CGF.getContext().getLangOptions().OverflowChecking
+ && Ops.Ty->isSignedIntegerType())
+ return EmitOverflowCheckedBinOp(Ops);
+ return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub");
+ }
+
+ if (Ops.E->getLHS()->getType()->getAsPointerType()->isVariableArrayType()) {
+ // The amount of the addition needs to account for the VLA size for
+ // ptr-int
+ // The amount of the division needs to account for the VLA size for
+ // ptr-ptr.
+ CGF.ErrorUnsupported(Ops.E, "VLA pointer subtraction");
+ }
+
+ const QualType LHSType = Ops.E->getLHS()->getType();
+ const QualType LHSElementType = LHSType->getAsPointerType()->getPointeeType();
+ if (!isa<llvm::PointerType>(Ops.RHS->getType())) {
+ // pointer - int
+ Value *Idx = Ops.RHS;
+ unsigned Width = cast<llvm::IntegerType>(Idx->getType())->getBitWidth();
+ if (Width < CGF.LLVMPointerWidth) {
+ // Zero or sign extend the pointer value based on whether the index is
+ // signed or not.
+ const llvm::Type *IdxType = llvm::IntegerType::get(CGF.LLVMPointerWidth);
+ if (Ops.E->getRHS()->getType()->isSignedIntegerType())
+ Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext");
+ else
+ Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
+ }
+ Idx = Builder.CreateNeg(Idx, "sub.ptr.neg");
+
+ // Handle interface types, which are not represented with a concrete
+ // type.
+ if (const ObjCInterfaceType *OIT =
+ dyn_cast<ObjCInterfaceType>(LHSElementType)) {
+ llvm::Value *InterfaceSize =
+ llvm::ConstantInt::get(Idx->getType(),
+ CGF.getContext().getTypeSize(OIT) / 8);
+ Idx = Builder.CreateMul(Idx, InterfaceSize);
+ const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ Value *LHSCasted = Builder.CreateBitCast(Ops.LHS, i8Ty);
+ Value *Res = Builder.CreateGEP(LHSCasted, Idx, "add.ptr");
+ return Builder.CreateBitCast(Res, Ops.LHS->getType());
+ }
+
+ // Explicitly handle GNU void* and function pointer arithmetic
+ // extensions. The GNU void* casts amount to no-ops since our
+ // void* type is i8*, but this is future proof.
+ if (LHSElementType->isVoidType() || LHSElementType->isFunctionType()) {
+ const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ Value *LHSCasted = Builder.CreateBitCast(Ops.LHS, i8Ty);
+ Value *Res = Builder.CreateGEP(LHSCasted, Idx, "sub.ptr");
+ return Builder.CreateBitCast(Res, Ops.LHS->getType());
+ }
+
+ return Builder.CreateGEP(Ops.LHS, Idx, "sub.ptr");
+ } else {
+ // pointer - pointer
+ Value *LHS = Ops.LHS;
+ Value *RHS = Ops.RHS;
+
+ uint64_t ElementSize;
+
+ // Handle GCC extension for pointer arithmetic on void* and function pointer
+ // types.
+ if (LHSElementType->isVoidType() || LHSElementType->isFunctionType()) {
+ ElementSize = 1;
+ } else {
+ ElementSize = CGF.getContext().getTypeSize(LHSElementType) / 8;
+ }
+
+ const llvm::Type *ResultType = ConvertType(Ops.Ty);
+ LHS = Builder.CreatePtrToInt(LHS, ResultType, "sub.ptr.lhs.cast");
+ RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast");
+ Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub");
+
+ // Optimize out the shift for element size of 1.
+ if (ElementSize == 1)
+ return BytesBetween;
+
+ // HACK: LLVM doesn't have an divide instruction that 'knows' there is no
+ // remainder. As such, we handle common power-of-two cases here to generate
+ // better code. See PR2247.
+ if (llvm::isPowerOf2_64(ElementSize)) {
+ Value *ShAmt =
+ llvm::ConstantInt::get(ResultType, llvm::Log2_64(ElementSize));
+ return Builder.CreateAShr(BytesBetween, ShAmt, "sub.ptr.shr");
+ }
+
+ // Otherwise, do a full sdiv.
+ Value *BytesPerElt = llvm::ConstantInt::get(ResultType, ElementSize);
+ return Builder.CreateSDiv(BytesBetween, BytesPerElt, "sub.ptr.div");
+ }
+}
+
+Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
+ // LLVM requires the LHS and RHS to be the same type: promote or truncate the
+ // RHS to the same size as the LHS.
+ Value *RHS = Ops.RHS;
+ if (Ops.LHS->getType() != RHS->getType())
+ RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
+
+ return Builder.CreateShl(Ops.LHS, RHS, "shl");
+}
+
+Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
+ // LLVM requires the LHS and RHS to be the same type: promote or truncate the
+ // RHS to the same size as the LHS.
+ Value *RHS = Ops.RHS;
+ if (Ops.LHS->getType() != RHS->getType())
+ RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
+
+ if (Ops.Ty->isUnsignedIntegerType())
+ return Builder.CreateLShr(Ops.LHS, RHS, "shr");
+ return Builder.CreateAShr(Ops.LHS, RHS, "shr");
+}
+
+Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
+ unsigned SICmpOpc, unsigned FCmpOpc) {
+ TestAndClearIgnoreResultAssign();
+ Value *Result;
+ QualType LHSTy = E->getLHS()->getType();
+ if (!LHSTy->isAnyComplexType() && !LHSTy->isVectorType()) {
+ Value *LHS = Visit(E->getLHS());
+ Value *RHS = Visit(E->getRHS());
+
+ if (LHS->getType()->isFloatingPoint()) {
+ Result = Builder.CreateFCmp((llvm::CmpInst::Predicate)FCmpOpc,
+ LHS, RHS, "cmp");
+ } else if (LHSTy->isSignedIntegerType()) {
+ Result = Builder.CreateICmp((llvm::ICmpInst::Predicate)SICmpOpc,
+ LHS, RHS, "cmp");
+ } else {
+ // Unsigned integers and pointers.
+ Result = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc,
+ LHS, RHS, "cmp");
+ }
+ } else if (LHSTy->isVectorType()) {
+ Value *LHS = Visit(E->getLHS());
+ Value *RHS = Visit(E->getRHS());
+
+ if (LHS->getType()->isFPOrFPVector()) {
+ Result = Builder.CreateVFCmp((llvm::CmpInst::Predicate)FCmpOpc,
+ LHS, RHS, "cmp");
+ } else if (LHSTy->isUnsignedIntegerType()) {
+ Result = Builder.CreateVICmp((llvm::CmpInst::Predicate)UICmpOpc,
+ LHS, RHS, "cmp");
+ } else {
+ // Signed integers and pointers.
+ Result = Builder.CreateVICmp((llvm::CmpInst::Predicate)SICmpOpc,
+ LHS, RHS, "cmp");
+ }
+ return Result;
+ } else {
+ // Complex Comparison: can only be an equality comparison.
+ CodeGenFunction::ComplexPairTy LHS = CGF.EmitComplexExpr(E->getLHS());
+ CodeGenFunction::ComplexPairTy RHS = CGF.EmitComplexExpr(E->getRHS());
+
+ QualType CETy = LHSTy->getAsComplexType()->getElementType();
+
+ Value *ResultR, *ResultI;
+ if (CETy->isRealFloatingType()) {
+ ResultR = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc,
+ LHS.first, RHS.first, "cmp.r");
+ ResultI = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc,
+ LHS.second, RHS.second, "cmp.i");
+ } else {
+ // Complex comparisons can only be equality comparisons. As such, signed
+ // and unsigned opcodes are the same.
+ ResultR = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc,
+ LHS.first, RHS.first, "cmp.r");
+ ResultI = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc,
+ LHS.second, RHS.second, "cmp.i");
+ }
+
+ if (E->getOpcode() == BinaryOperator::EQ) {
+ Result = Builder.CreateAnd(ResultR, ResultI, "and.ri");
+ } else {
+ assert(E->getOpcode() == BinaryOperator::NE &&
+ "Complex comparison other than == or != ?");
+ Result = Builder.CreateOr(ResultR, ResultI, "or.ri");
+ }
+ }
+
+ return EmitScalarConversion(Result, CGF.getContext().BoolTy, E->getType());
+}
+
+Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
+ bool Ignore = TestAndClearIgnoreResultAssign();
+
+ // __block variables need to have the rhs evaluated first, plus this should
+ // improve codegen just a little.
+ Value *RHS = Visit(E->getRHS());
+ LValue LHS = EmitLValue(E->getLHS());
+
+ // Store the value into the LHS. Bit-fields are handled specially
+ // because the result is altered by the store, i.e., [C99 6.5.16p1]
+ // 'An assignment expression has the value of the left operand after
+ // the assignment...'.
+ if (LHS.isBitfield()) {
+ if (!LHS.isVolatileQualified()) {
+ CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, E->getType(),
+ &RHS);
+ return RHS;
+ } else
+ CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, E->getType());
+ } else
+ CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS, E->getType());
+ if (Ignore)
+ return 0;
+ return EmitLoadOfLValue(LHS, E->getType());
+}
+
+Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
+ // 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.
+ if (int Cond = CGF.ConstantFoldsToSimpleInteger(E->getLHS())) {
+ if (Cond == 1) { // If we have 1 && X, just emit X.
+ Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
+ // ZExt result to int.
+ return Builder.CreateZExt(RHSCond, CGF.LLVMIntTy, "land.ext");
+ }
+
+ // 0 && RHS: If it is safe, just elide the RHS, and return 0.
+ if (!CGF.ContainsLabel(E->getRHS()))
+ return llvm::Constant::getNullValue(CGF.LLVMIntTy);
+ }
+
+ llvm::BasicBlock *ContBlock = CGF.createBasicBlock("land.end");
+ llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("land.rhs");
+
+ // Branch on the LHS first. If it is false, go to the failure (cont) block.
+ CGF.EmitBranchOnBoolExpr(E->getLHS(), RHSBlock, ContBlock);
+
+ // Any edges into the ContBlock are now from an (indeterminate number of)
+ // edges from this first condition. All of these values will be false. Start
+ // setting up the PHI node in the Cont Block for this.
+ llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::Int1Ty, "", ContBlock);
+ PN->reserveOperandSpace(2); // Normal case, two inputs.
+ for (llvm::pred_iterator PI = pred_begin(ContBlock), PE = pred_end(ContBlock);
+ PI != PE; ++PI)
+ PN->addIncoming(llvm::ConstantInt::getFalse(), *PI);
+
+ CGF.EmitBlock(RHSBlock);
+ Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
+
+ // Reaquire the RHS block, as there may be subblocks inserted.
+ RHSBlock = Builder.GetInsertBlock();
+
+ // Emit an unconditional branch from this block to ContBlock. Insert an entry
+ // into the phi node for the edge with the value of RHSCond.
+ CGF.EmitBlock(ContBlock);
+ PN->addIncoming(RHSCond, RHSBlock);
+
+ // ZExt result to int.
+ return Builder.CreateZExt(PN, CGF.LLVMIntTy, "land.ext");
+}
+
+Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
+ // 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.
+ if (int Cond = CGF.ConstantFoldsToSimpleInteger(E->getLHS())) {
+ if (Cond == -1) { // If we have 0 || X, just emit X.
+ Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
+ // ZExt result to int.
+ return Builder.CreateZExt(RHSCond, CGF.LLVMIntTy, "lor.ext");
+ }
+
+ // 1 || RHS: If it is safe, just elide the RHS, and return 1.
+ if (!CGF.ContainsLabel(E->getRHS()))
+ return llvm::ConstantInt::get(CGF.LLVMIntTy, 1);
+ }
+
+ llvm::BasicBlock *ContBlock = CGF.createBasicBlock("lor.end");
+ llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("lor.rhs");
+
+ // Branch on the LHS first. If it is true, go to the success (cont) block.
+ CGF.EmitBranchOnBoolExpr(E->getLHS(), ContBlock, RHSBlock);
+
+ // Any edges into the ContBlock are now from an (indeterminate number of)
+ // edges from this first condition. All of these values will be true. Start
+ // setting up the PHI node in the Cont Block for this.
+ llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::Int1Ty, "", ContBlock);
+ PN->reserveOperandSpace(2); // Normal case, two inputs.
+ for (llvm::pred_iterator PI = pred_begin(ContBlock), PE = pred_end(ContBlock);
+ PI != PE; ++PI)
+ PN->addIncoming(llvm::ConstantInt::getTrue(), *PI);
+
+ // Emit the RHS condition as a bool value.
+ CGF.EmitBlock(RHSBlock);
+ Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
+
+ // Reaquire the RHS block, as there may be subblocks inserted.
+ RHSBlock = Builder.GetInsertBlock();
+
+ // Emit an unconditional branch from this block to ContBlock. Insert an entry
+ // into the phi node for the edge with the value of RHSCond.
+ CGF.EmitBlock(ContBlock);
+ PN->addIncoming(RHSCond, RHSBlock);
+
+ // ZExt result to int.
+ return Builder.CreateZExt(PN, CGF.LLVMIntTy, "lor.ext");
+}
+
+Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) {
+ CGF.EmitStmt(E->getLHS());
+ CGF.EnsureInsertPoint();
+ return Visit(E->getRHS());
+}
+
+//===----------------------------------------------------------------------===//
+// Other Operators
+//===----------------------------------------------------------------------===//
+
+/// isCheapEnoughToEvaluateUnconditionally - Return true if the specified
+/// expression is cheap enough and side-effect-free enough to evaluate
+/// unconditionally instead of conditionally. This is used to convert control
+/// flow into selects in some cases.
+static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E) {
+ if (const ParenExpr *PE = dyn_cast<ParenExpr>(E))
+ return isCheapEnoughToEvaluateUnconditionally(PE->getSubExpr());
+
+ // TODO: Allow anything we can constant fold to an integer or fp constant.
+ if (isa<IntegerLiteral>(E) || isa<CharacterLiteral>(E) ||
+ isa<FloatingLiteral>(E))
+ return true;
+
+ // Non-volatile automatic variables too, to get "cond ? X : Y" where
+ // X and Y are local variables.
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+ if (VD->hasLocalStorage() && !VD->getType().isVolatileQualified())
+ return true;
+
+ return false;
+}
+
+
+Value *ScalarExprEmitter::
+VisitConditionalOperator(const ConditionalOperator *E) {
+ TestAndClearIgnoreResultAssign();
+ // If the condition constant folds and can be elided, try to avoid emitting
+ // the condition and the dead arm.
+ if (int Cond = CGF.ConstantFoldsToSimpleInteger(E->getCond())){
+ Expr *Live = E->getLHS(), *Dead = E->getRHS();
+ if (Cond == -1)
+ std::swap(Live, Dead);
+
+ // If the dead side doesn't have labels we need, and if the Live side isn't
+ // the gnu missing ?: extension (which we could handle, but don't bother
+ // to), just emit the Live part.
+ if ((!Dead || !CGF.ContainsLabel(Dead)) && // No labels in dead part
+ Live) // Live part isn't missing.
+ return Visit(Live);
+ }
+
+
+ // If this is a really simple expression (like x ? 4 : 5), emit this as a
+ // select instead of as control flow. We can only do this if it is cheap and
+ // safe to evaluate the LHS and RHS unconditionally.
+ if (E->getLHS() && isCheapEnoughToEvaluateUnconditionally(E->getLHS()) &&
+ isCheapEnoughToEvaluateUnconditionally(E->getRHS())) {
+ llvm::Value *CondV = CGF.EvaluateExprAsBool(E->getCond());
+ llvm::Value *LHS = Visit(E->getLHS());
+ llvm::Value *RHS = Visit(E->getRHS());
+ return Builder.CreateSelect(CondV, LHS, RHS, "cond");
+ }
+
+
+ llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true");
+ llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
+ llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
+ Value *CondVal = 0;
+
+ // If we don't have the GNU missing condition extension, emit a branch on
+ // bool the normal way.
+ if (E->getLHS()) {
+ // Otherwise, just use EmitBranchOnBoolExpr to get small and simple code for
+ // the branch on bool.
+ CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
+ } else {
+ // Otherwise, for the ?: extension, evaluate the conditional and then
+ // convert it to bool the hard way. We do this explicitly because we need
+ // the unconverted value for the missing middle value of the ?:.
+ CondVal = CGF.EmitScalarExpr(E->getCond());
+
+ // In some cases, EmitScalarConversion will delete the "CondVal" expression
+ // if there are no extra uses (an optimization). Inhibit this by making an
+ // extra dead use, because we're going to add a use of CondVal later. We
+ // don't use the builder for this, because we don't want it to get optimized
+ // away. This leaves dead code, but the ?: extension isn't common.
+ new llvm::BitCastInst(CondVal, CondVal->getType(), "dummy?:holder",
+ Builder.GetInsertBlock());
+
+ Value *CondBoolVal =
+ CGF.EmitScalarConversion(CondVal, E->getCond()->getType(),
+ CGF.getContext().BoolTy);
+ Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock);
+ }
+
+ CGF.EmitBlock(LHSBlock);
+
+ // Handle the GNU extension for missing LHS.
+ Value *LHS;
+ if (E->getLHS())
+ LHS = Visit(E->getLHS());
+ else // Perform promotions, to handle cases like "short ?: int"
+ LHS = EmitScalarConversion(CondVal, E->getCond()->getType(), E->getType());
+
+ LHSBlock = Builder.GetInsertBlock();
+ CGF.EmitBranch(ContBlock);
+
+ CGF.EmitBlock(RHSBlock);
+
+ Value *RHS = Visit(E->getRHS());
+ RHSBlock = Builder.GetInsertBlock();
+ CGF.EmitBranch(ContBlock);
+
+ CGF.EmitBlock(ContBlock);
+
+ if (!LHS || !RHS) {
+ assert(E->getType()->isVoidType() && "Non-void value should have a value");
+ return 0;
+ }
+
+ // Create a PHI node for the real part.
+ llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), "cond");
+ PN->reserveOperandSpace(2);
+ PN->addIncoming(LHS, LHSBlock);
+ PN->addIncoming(RHS, RHSBlock);
+ return PN;
+}
+
+Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) {
+ return Visit(E->getChosenSubExpr(CGF.getContext()));
+}
+
+Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
+ llvm::Value *ArgValue = CGF.EmitVAListRef(VE->getSubExpr());
+ llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType());
+
+ // If EmitVAArg fails, we fall back to the LLVM instruction.
+ if (!ArgPtr)
+ return Builder.CreateVAArg(ArgValue, ConvertType(VE->getType()));
+
+ // FIXME Volatility.
+ return Builder.CreateLoad(ArgPtr);
+}
+
+Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *BE) {
+ return CGF.BuildBlockLiteralTmp(BE);
+}
+
+//===----------------------------------------------------------------------===//
+// Entry Point into this File
+//===----------------------------------------------------------------------===//
+
+/// EmitScalarExpr - Emit the computation of the specified expression of
+/// scalar type, ignoring the result.
+Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign) {
+ assert(E && !hasAggregateLLVMType(E->getType()) &&
+ "Invalid scalar expression to emit");
+
+ return ScalarExprEmitter(*this, IgnoreResultAssign)
+ .Visit(const_cast<Expr*>(E));
+}
+
+/// EmitScalarConversion - Emit a conversion from the specified type to the
+/// specified destination type, both of which are LLVM scalar types.
+Value *CodeGenFunction::EmitScalarConversion(Value *Src, QualType SrcTy,
+ QualType DstTy) {
+ assert(!hasAggregateLLVMType(SrcTy) && !hasAggregateLLVMType(DstTy) &&
+ "Invalid scalar expression to emit");
+ return ScalarExprEmitter(*this).EmitScalarConversion(Src, SrcTy, DstTy);
+}
+
+/// EmitComplexToScalarConversion - Emit a conversion from the specified
+/// complex type to the specified destination type, where the destination
+/// type is an LLVM scalar type.
+Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src,
+ QualType SrcTy,
+ QualType DstTy) {
+ assert(SrcTy->isAnyComplexType() && !hasAggregateLLVMType(DstTy) &&
+ "Invalid complex -> scalar conversion");
+ return ScalarExprEmitter(*this).EmitComplexToScalarConversion(Src, SrcTy,
+ DstTy);
+}
+
+Value *CodeGenFunction::EmitShuffleVector(Value* V1, Value *V2, ...) {
+ assert(V1->getType() == V2->getType() &&
+ "Vector operands must be of the same type");
+ unsigned NumElements =
+ cast<llvm::VectorType>(V1->getType())->getNumElements();
+
+ va_list va;
+ va_start(va, V2);
+
+ llvm::SmallVector<llvm::Constant*, 16> Args;
+ for (unsigned i = 0; i < NumElements; i++) {
+ int n = va_arg(va, int);
+ assert(n >= 0 && n < (int)NumElements * 2 &&
+ "Vector shuffle index out of bounds!");
+ Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, n));
+ }
+
+ const char *Name = va_arg(va, const char *);
+ va_end(va);
+
+ llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements);
+
+ return Builder.CreateShuffleVector(V1, V2, Mask, Name);
+}
+
+llvm::Value *CodeGenFunction::EmitVector(llvm::Value * const *Vals,
+ unsigned NumVals, bool isSplat) {
+ llvm::Value *Vec
+ = llvm::UndefValue::get(llvm::VectorType::get(Vals[0]->getType(), NumVals));
+
+ for (unsigned i = 0, e = NumVals; i != e; ++i) {
+ llvm::Value *Val = isSplat ? Vals[0] : Vals[i];
+ llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i);
+ Vec = Builder.CreateInsertElement(Vec, Val, Idx, "tmp");
+ }
+
+ return Vec;
+}
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
new file mode 100644
index 000000000000..51f9a7657928
--- /dev/null
+++ b/lib/CodeGen/CGObjC.cpp
@@ -0,0 +1,644 @@
+//===---- CGBuiltin.cpp - Emit LLVM Code for builtins ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit Objective-C code as LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGObjCRuntime.h"
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Target/TargetData.h"
+using namespace clang;
+using namespace CodeGen;
+
+/// Emits an instance of NSConstantString representing the object.
+llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E)
+{
+ llvm::Constant *C = CGM.getObjCRuntime().GenerateConstantString(E);
+ // FIXME: This bitcast should just be made an invariant on the Runtime.
+ return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType()));
+}
+
+/// Emit a selector.
+llvm::Value *CodeGenFunction::EmitObjCSelectorExpr(const ObjCSelectorExpr *E) {
+ // Untyped selector.
+ // Note that this implementation allows for non-constant strings to be passed
+ // as arguments to @selector(). Currently, the only thing preventing this
+ // behaviour is the type checking in the front end.
+ return CGM.getObjCRuntime().GetSelector(Builder, E->getSelector());
+}
+
+llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) {
+ // FIXME: This should pass the Decl not the name.
+ return CGM.getObjCRuntime().GenerateProtocolRef(Builder, E->getProtocol());
+}
+
+
+RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
+ // Only the lookup mechanism and first two arguments of the method
+ // implementation vary between runtimes. We can get the receiver and
+ // arguments in generic code.
+
+ CGObjCRuntime &Runtime = CGM.getObjCRuntime();
+ const Expr *ReceiverExpr = E->getReceiver();
+ bool isSuperMessage = false;
+ bool isClassMessage = false;
+ // Find the receiver
+ llvm::Value *Receiver;
+ if (!ReceiverExpr) {
+ const ObjCInterfaceDecl *OID = E->getClassInfo().first;
+
+ // Very special case, super send in class method. The receiver is
+ // self (the class object) and the send uses super semantics.
+ if (!OID) {
+ assert(E->getClassName()->isStr("super") &&
+ "Unexpected missing class interface in message send.");
+ isSuperMessage = true;
+ Receiver = LoadObjCSelf();
+ } else {
+ Receiver = Runtime.GetClass(Builder, OID);
+ }
+
+ isClassMessage = true;
+ } else if (isa<ObjCSuperExpr>(E->getReceiver())) {
+ isSuperMessage = true;
+ Receiver = LoadObjCSelf();
+ } else {
+ Receiver = EmitScalarExpr(E->getReceiver());
+ }
+
+ CallArgList Args;
+ EmitCallArgs(Args, E->getMethodDecl(), E->arg_begin(), E->arg_end());
+
+ if (isSuperMessage) {
+ // super is only valid in an Objective-C method
+ const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
+ bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext());
+ return Runtime.GenerateMessageSendSuper(*this, E->getType(),
+ E->getSelector(),
+ OMD->getClassInterface(),
+ isCategoryImpl,
+ Receiver,
+ isClassMessage,
+ Args);
+ }
+ return Runtime.GenerateMessageSend(*this, E->getType(), E->getSelector(),
+ Receiver, isClassMessage, Args,
+ E->getMethodDecl());
+}
+
+/// StartObjCMethod - Begin emission of an ObjCMethod. This generates
+/// the LLVM function and sets the other context used by
+/// CodeGenFunction.
+void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) {
+ FunctionArgList Args;
+ llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD);
+
+ const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(OMD);
+ CGM.SetInternalFunctionAttributes(OMD, Fn, FI);
+
+ Args.push_back(std::make_pair(OMD->getSelfDecl(),
+ OMD->getSelfDecl()->getType()));
+ Args.push_back(std::make_pair(OMD->getCmdDecl(),
+ OMD->getCmdDecl()->getType()));
+
+ for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
+ E = OMD->param_end(); PI != E; ++PI)
+ Args.push_back(std::make_pair(*PI, (*PI)->getType()));
+
+ StartFunction(OMD, OMD->getResultType(), Fn, Args, OMD->getLocEnd());
+}
+
+/// 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) {
+ // Check if we should generate debug info for this method.
+ if (CGM.getDebugInfo() && !OMD->hasAttr<NodebugAttr>())
+ DebugInfo = CGM.getDebugInfo();
+ StartObjCMethod(OMD, OMD->getClassInterface());
+ EmitStmt(OMD->getBody(getContext()));
+ FinishFunction(OMD->getBodyRBrace(getContext()));
+}
+
+// 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.
+
+/// 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();
+ ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
+ assert(OMD && "Invalid call to generate getter (empty method)");
+ // FIXME: This is rather murky, we create this here since they will not have
+ // been created by Sema for us.
+ OMD->createImplicitParams(getContext(), IMP->getClassInterface());
+ StartObjCMethod(OMD, IMP->getClassInterface());
+
+ // 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 &&
+ !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) &&
+ (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();
+ 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.push_back(std::make_pair(RValue::get(SelfAsId), IdTy));
+ Args.push_back(std::make_pair(RValue::get(CmdVal), Cmd->getType()));
+ Args.push_back(std::make_pair(RValue::get(Offset), getContext().LongTy));
+ Args.push_back(std::make_pair(RValue::get(True), 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),
+ GetPropertyFn, 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());
+ } else {
+ LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0);
+ if (hasAggregateLLVMType(Ivar->getType())) {
+ EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType());
+ }
+ else {
+ CodeGenTypes &Types = CGM.getTypes();
+ RValue RV = EmitLoadOfLValue(LV, Ivar->getType());
+ RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(),
+ Types.ConvertType(PD->getType())));
+ EmitReturnOfRValue(RV, PD->getType());
+ }
+ }
+
+ FinishFunction();
+}
+
+/// GenerateObjCSetter - Generate an Objective-C property setter
+/// function. The given Decl must be an ObjCImplementationDecl. @synthesize
+/// 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)");
+ // FIXME: This is rather murky, we create this here since they will not have
+ // been created by Sema for us.
+ OMD->createImplicitParams(getContext(), IMP->getClassInterface());
+ StartObjCMethod(OMD, IMP->getClassInterface());
+
+ 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.push_back(std::make_pair(RValue::get(SelfAsId), IdTy));
+ Args.push_back(std::make_pair(RValue::get(CmdVal), Cmd->getType()));
+ Args.push_back(std::make_pair(RValue::get(Offset), getContext().LongTy));
+ Args.push_back(std::make_pair(RValue::get(ArgAsId), IdTy));
+ Args.push_back(std::make_pair(RValue::get(IsAtomic ? True : False),
+ getContext().BoolTy));
+ Args.push_back(std::make_pair(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),
+ SetPropertyFn, Args);
+ } else {
+ SourceLocation Loc = PD->getLocation();
+ ValueDecl *Self = OMD->getSelfDecl();
+ ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl();
+ DeclRefExpr Base(Self, Self->getType(), Loc);
+ ParmVarDecl *ArgDecl = *OMD->param_begin();
+ DeclRefExpr Arg(ArgDecl, ArgDecl->getType(), Loc);
+ ObjCIvarRefExpr IvarRef(Ivar, Ivar->getType(), Loc, &Base,
+ true, true);
+ BinaryOperator Assign(&IvarRef, &Arg, BinaryOperator::Assign,
+ Ivar->getType(), Loc);
+ EmitStmt(&Assign);
+ }
+
+ FinishFunction();
+}
+
+llvm::Value *CodeGenFunction::LoadObjCSelf() {
+ const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
+ // See if we need to lazily forward self inside a block literal.
+ BlockForwardSelf();
+ return Builder.CreateLoad(LocalDeclMap[OMD->getSelfDecl()], "self");
+}
+
+QualType CodeGenFunction::TypeOfSelfObject() {
+ const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
+ ImplicitParamDecl *selfDecl = OMD->getSelfDecl();
+ const PointerType *PTy =
+ cast<PointerType>(getContext().getCanonicalType(selfDecl->getType()));
+ return PTy->getPointeeType();
+}
+
+RValue CodeGenFunction::EmitObjCSuperPropertyGet(const Expr *Exp,
+ const Selector &S) {
+ llvm::Value *Receiver = LoadObjCSelf();
+ const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
+ bool isClassMessage = OMD->isClassMethod();
+ bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext());
+ return CGM.getObjCRuntime().GenerateMessageSendSuper(*this,
+ Exp->getType(),
+ S,
+ OMD->getClassInterface(),
+ isCategoryImpl,
+ Receiver,
+ isClassMessage,
+ CallArgList());
+
+}
+
+RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) {
+ // FIXME: Split it into two separate routines.
+ if (const ObjCPropertyRefExpr *E = dyn_cast<ObjCPropertyRefExpr>(Exp)) {
+ Selector S = E->getProperty()->getGetterName();
+ if (isa<ObjCSuperExpr>(E->getBase()))
+ return EmitObjCSuperPropertyGet(E, S);
+ return CGM.getObjCRuntime().
+ GenerateMessageSend(*this, Exp->getType(), S,
+ EmitScalarExpr(E->getBase()),
+ false, CallArgList());
+ }
+ else {
+ const ObjCKVCRefExpr *KE = cast<ObjCKVCRefExpr>(Exp);
+ Selector S = KE->getGetterMethod()->getSelector();
+ llvm::Value *Receiver;
+ if (KE->getClassProp()) {
+ const ObjCInterfaceDecl *OID = KE->getClassProp();
+ Receiver = CGM.getObjCRuntime().GetClass(Builder, OID);
+ }
+ else if (isa<ObjCSuperExpr>(KE->getBase()))
+ return EmitObjCSuperPropertyGet(KE, S);
+ else
+ Receiver = EmitScalarExpr(KE->getBase());
+ return CGM.getObjCRuntime().
+ GenerateMessageSend(*this, Exp->getType(), S,
+ Receiver,
+ KE->getClassProp() != 0, CallArgList());
+ }
+}
+
+void CodeGenFunction::EmitObjCSuperPropertySet(const Expr *Exp,
+ const Selector &S,
+ RValue Src) {
+ CallArgList Args;
+ llvm::Value *Receiver = LoadObjCSelf();
+ const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
+ bool isClassMessage = OMD->isClassMethod();
+ bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext());
+ Args.push_back(std::make_pair(Src, Exp->getType()));
+ CGM.getObjCRuntime().GenerateMessageSendSuper(*this,
+ Exp->getType(),
+ S,
+ OMD->getClassInterface(),
+ isCategoryImpl,
+ Receiver,
+ isClassMessage,
+ Args);
+ return;
+}
+
+void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp,
+ RValue Src) {
+ // FIXME: Split it into two separate routines.
+ if (const ObjCPropertyRefExpr *E = dyn_cast<ObjCPropertyRefExpr>(Exp)) {
+ Selector S = E->getProperty()->getSetterName();
+ if (isa<ObjCSuperExpr>(E->getBase())) {
+ EmitObjCSuperPropertySet(E, S, Src);
+ return;
+ }
+ CallArgList Args;
+ Args.push_back(std::make_pair(Src, E->getType()));
+ CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S,
+ EmitScalarExpr(E->getBase()),
+ false, Args);
+ }
+ else if (const ObjCKVCRefExpr *E = dyn_cast<ObjCKVCRefExpr>(Exp)) {
+ Selector S = E->getSetterMethod()->getSelector();
+ CallArgList Args;
+ llvm::Value *Receiver;
+ if (E->getClassProp()) {
+ const ObjCInterfaceDecl *OID = E->getClassProp();
+ Receiver = CGM.getObjCRuntime().GetClass(Builder, OID);
+ }
+ else if (isa<ObjCSuperExpr>(E->getBase())) {
+ EmitObjCSuperPropertySet(E, S, Src);
+ return;
+ }
+ else
+ Receiver = EmitScalarExpr(E->getBase());
+ Args.push_back(std::make_pair(Src, E->getType()));
+ CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S,
+ Receiver,
+ E->getClassProp() != 0, Args);
+ }
+ else
+ assert (0 && "bad expression node in EmitObjCPropertySet");
+}
+
+void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
+ llvm::Constant *EnumerationMutationFn =
+ CGM.getObjCRuntime().EnumerationMutationFunction();
+ llvm::Value *DeclAddress;
+ QualType ElementTy;
+
+ if (!EnumerationMutationFn) {
+ CGM.ErrorUnsupported(&S, "Obj-C fast enumeration for this runtime");
+ return;
+ }
+
+ if (const DeclStmt *SD = dyn_cast<DeclStmt>(S.getElement())) {
+ EmitStmt(SD);
+ assert(HaveInsertPoint() && "DeclStmt destroyed insert point!");
+ const Decl* D = SD->getSingleDecl();
+ ElementTy = cast<ValueDecl>(D)->getType();
+ DeclAddress = LocalDeclMap[D];
+ } else {
+ ElementTy = cast<Expr>(S.getElement())->getType();
+ DeclAddress = 0;
+ }
+
+ // Fast enumeration state.
+ QualType StateTy = getContext().getObjCFastEnumerationStateType();
+ llvm::AllocaInst *StatePtr = CreateTempAlloca(ConvertType(StateTy),
+ "state.ptr");
+ StatePtr->setAlignment(getContext().getTypeAlign(StateTy) >> 3);
+ EmitMemSetToZero(StatePtr, StateTy);
+
+ // Number of elements in the items array.
+ static const unsigned NumItems = 16;
+
+ // Get selector
+ llvm::SmallVector<IdentifierInfo*, 3> II;
+ II.push_back(&CGM.getContext().Idents.get("countByEnumeratingWithState"));
+ II.push_back(&CGM.getContext().Idents.get("objects"));
+ II.push_back(&CGM.getContext().Idents.get("count"));
+ Selector FastEnumSel = CGM.getContext().Selectors.getSelector(II.size(),
+ &II[0]);
+
+ QualType ItemsTy =
+ getContext().getConstantArrayType(getContext().getObjCIdType(),
+ llvm::APInt(32, NumItems),
+ ArrayType::Normal, 0);
+ llvm::Value *ItemsPtr = CreateTempAlloca(ConvertType(ItemsTy), "items.ptr");
+
+ llvm::Value *Collection = EmitScalarExpr(S.getCollection());
+
+ CallArgList Args;
+ Args.push_back(std::make_pair(RValue::get(StatePtr),
+ getContext().getPointerType(StateTy)));
+
+ Args.push_back(std::make_pair(RValue::get(ItemsPtr),
+ getContext().getPointerType(ItemsTy)));
+
+ const llvm::Type *UnsignedLongLTy = ConvertType(getContext().UnsignedLongTy);
+ llvm::Constant *Count = llvm::ConstantInt::get(UnsignedLongLTy, NumItems);
+ Args.push_back(std::make_pair(RValue::get(Count),
+ getContext().UnsignedLongTy));
+
+ RValue CountRV =
+ CGM.getObjCRuntime().GenerateMessageSend(*this,
+ getContext().UnsignedLongTy,
+ FastEnumSel,
+ Collection, false, Args);
+
+ llvm::Value *LimitPtr = CreateTempAlloca(UnsignedLongLTy, "limit.ptr");
+ Builder.CreateStore(CountRV.getScalarVal(), LimitPtr);
+
+ llvm::BasicBlock *NoElements = createBasicBlock("noelements");
+ llvm::BasicBlock *SetStartMutations = createBasicBlock("setstartmutations");
+
+ llvm::Value *Limit = Builder.CreateLoad(LimitPtr);
+ llvm::Value *Zero = llvm::Constant::getNullValue(UnsignedLongLTy);
+
+ llvm::Value *IsZero = Builder.CreateICmpEQ(Limit, Zero, "iszero");
+ Builder.CreateCondBr(IsZero, NoElements, SetStartMutations);
+
+ EmitBlock(SetStartMutations);
+
+ llvm::Value *StartMutationsPtr =
+ CreateTempAlloca(UnsignedLongLTy);
+
+ llvm::Value *StateMutationsPtrPtr =
+ Builder.CreateStructGEP(StatePtr, 2, "mutationsptr.ptr");
+ llvm::Value *StateMutationsPtr = Builder.CreateLoad(StateMutationsPtrPtr,
+ "mutationsptr");
+
+ llvm::Value *StateMutations = Builder.CreateLoad(StateMutationsPtr,
+ "mutations");
+
+ Builder.CreateStore(StateMutations, StartMutationsPtr);
+
+ llvm::BasicBlock *LoopStart = createBasicBlock("loopstart");
+ EmitBlock(LoopStart);
+
+ llvm::Value *CounterPtr = CreateTempAlloca(UnsignedLongLTy, "counter.ptr");
+ Builder.CreateStore(Zero, CounterPtr);
+
+ llvm::BasicBlock *LoopBody = createBasicBlock("loopbody");
+ EmitBlock(LoopBody);
+
+ StateMutationsPtr = Builder.CreateLoad(StateMutationsPtrPtr, "mutationsptr");
+ StateMutations = Builder.CreateLoad(StateMutationsPtr, "statemutations");
+
+ llvm::Value *StartMutations = Builder.CreateLoad(StartMutationsPtr,
+ "mutations");
+ llvm::Value *MutationsEqual = Builder.CreateICmpEQ(StateMutations,
+ StartMutations,
+ "tobool");
+
+
+ llvm::BasicBlock *WasMutated = createBasicBlock("wasmutated");
+ llvm::BasicBlock *WasNotMutated = createBasicBlock("wasnotmutated");
+
+ Builder.CreateCondBr(MutationsEqual, WasNotMutated, WasMutated);
+
+ EmitBlock(WasMutated);
+ llvm::Value *V =
+ Builder.CreateBitCast(Collection,
+ ConvertType(getContext().getObjCIdType()),
+ "tmp");
+ CallArgList Args2;
+ Args2.push_back(std::make_pair(RValue::get(V),
+ getContext().getObjCIdType()));
+ // FIXME: We shouldn't need to get the function info here, the runtime already
+ // should have computed it to build the function.
+ EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2),
+ EnumerationMutationFn, Args2);
+
+ EmitBlock(WasNotMutated);
+
+ llvm::Value *StateItemsPtr =
+ Builder.CreateStructGEP(StatePtr, 1, "stateitems.ptr");
+
+ llvm::Value *Counter = Builder.CreateLoad(CounterPtr, "counter");
+
+ llvm::Value *EnumStateItems = Builder.CreateLoad(StateItemsPtr,
+ "stateitems");
+
+ llvm::Value *CurrentItemPtr =
+ Builder.CreateGEP(EnumStateItems, Counter, "currentitem.ptr");
+
+ llvm::Value *CurrentItem = Builder.CreateLoad(CurrentItemPtr, "currentitem");
+
+ // Cast the item to the right type.
+ CurrentItem = Builder.CreateBitCast(CurrentItem,
+ ConvertType(ElementTy), "tmp");
+
+ if (!DeclAddress) {
+ LValue LV = EmitLValue(cast<Expr>(S.getElement()));
+
+ // Set the value to null.
+ Builder.CreateStore(CurrentItem, LV.getAddress());
+ } else
+ Builder.CreateStore(CurrentItem, DeclAddress);
+
+ // Increment the counter.
+ Counter = Builder.CreateAdd(Counter,
+ llvm::ConstantInt::get(UnsignedLongLTy, 1));
+ Builder.CreateStore(Counter, CounterPtr);
+
+ llvm::BasicBlock *LoopEnd = createBasicBlock("loopend");
+ llvm::BasicBlock *AfterBody = createBasicBlock("afterbody");
+
+ BreakContinueStack.push_back(BreakContinue(LoopEnd, AfterBody));
+
+ EmitStmt(S.getBody());
+
+ BreakContinueStack.pop_back();
+
+ EmitBlock(AfterBody);
+
+ llvm::BasicBlock *FetchMore = createBasicBlock("fetchmore");
+
+ Counter = Builder.CreateLoad(CounterPtr);
+ Limit = Builder.CreateLoad(LimitPtr);
+ llvm::Value *IsLess = Builder.CreateICmpULT(Counter, Limit, "isless");
+ Builder.CreateCondBr(IsLess, LoopBody, FetchMore);
+
+ // Fetch more elements.
+ EmitBlock(FetchMore);
+
+ CountRV =
+ CGM.getObjCRuntime().GenerateMessageSend(*this,
+ getContext().UnsignedLongTy,
+ FastEnumSel,
+ Collection, false, Args);
+ Builder.CreateStore(CountRV.getScalarVal(), LimitPtr);
+ Limit = Builder.CreateLoad(LimitPtr);
+
+ IsZero = Builder.CreateICmpEQ(Limit, Zero, "iszero");
+ Builder.CreateCondBr(IsZero, NoElements, LoopStart);
+
+ // No more elements.
+ EmitBlock(NoElements);
+
+ if (!DeclAddress) {
+ // If the element was not a declaration, set it to be null.
+
+ LValue LV = EmitLValue(cast<Expr>(S.getElement()));
+
+ // Set the value to null.
+ Builder.CreateStore(llvm::Constant::getNullValue(ConvertType(ElementTy)),
+ LV.getAddress());
+ }
+
+ EmitBlock(LoopEnd);
+}
+
+void CodeGenFunction::EmitObjCAtTryStmt(const ObjCAtTryStmt &S)
+{
+ CGM.getObjCRuntime().EmitTryOrSynchronizedStmt(*this, S);
+}
+
+void CodeGenFunction::EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S)
+{
+ CGM.getObjCRuntime().EmitThrowStmt(*this, S);
+}
+
+void CodeGenFunction::EmitObjCAtSynchronizedStmt(
+ const ObjCAtSynchronizedStmt &S)
+{
+ CGM.getObjCRuntime().EmitTryOrSynchronizedStmt(*this, S);
+}
+
+CGObjCRuntime::~CGObjCRuntime() {}
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
new file mode 100644
index 000000000000..5e7eec9819c8
--- /dev/null
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -0,0 +1,1582 @@
+//===------- CGObjCGNU.cpp - Emit LLVM Code from ASTs for a Module --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides Objective-C code generation targetting the GNU runtime. The
+// class in this file generates structures used by the GNU Objective-C runtime
+// library. These structures are defined in objc/objc.h and objc/objc-api.h in
+// the GNU runtime distribution.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGObjCRuntime.h"
+#include "CodeGenModule.h"
+#include "CodeGenFunction.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/StmtObjC.h"
+
+#include "llvm/Intrinsics.h"
+#include "llvm/Module.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Target/TargetData.h"
+
+#include <map>
+
+
+using namespace clang;
+using namespace CodeGen;
+using llvm::dyn_cast;
+
+// The version of the runtime that this class targets. Must match the version
+// in the runtime.
+static const int RuntimeVersion = 8;
+static const int NonFragileRuntimeVersion = 9;
+static const int ProtocolVersion = 2;
+
+namespace {
+class CGObjCGNU : public CodeGen::CGObjCRuntime {
+private:
+ CodeGen::CodeGenModule &CGM;
+ llvm::Module &TheModule;
+ const llvm::PointerType *SelectorTy;
+ const llvm::PointerType *PtrToInt8Ty;
+ const llvm::FunctionType *IMPTy;
+ const llvm::PointerType *IdTy;
+ const llvm::IntegerType *IntTy;
+ const llvm::PointerType *PtrTy;
+ const llvm::IntegerType *LongTy;
+ const llvm::PointerType *PtrToIntTy;
+ llvm::GlobalAlias *ClassPtrAlias;
+ llvm::GlobalAlias *MetaClassPtrAlias;
+ std::vector<llvm::Constant*> Classes;
+ std::vector<llvm::Constant*> Categories;
+ std::vector<llvm::Constant*> ConstantStrings;
+ llvm::Function *LoadFunction;
+ llvm::StringMap<llvm::Constant*> ExistingProtocols;
+ typedef std::pair<std::string, std::string> TypedSelector;
+ std::map<TypedSelector, llvm::GlobalAlias*> TypedSelectors;
+ llvm::StringMap<llvm::GlobalAlias*> UntypedSelectors;
+ // Some zeros used for GEPs in lots of places.
+ llvm::Constant *Zeros[2];
+ llvm::Constant *NULLPtr;
+private:
+ llvm::Constant *GenerateIvarList(
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames,
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarTypes,
+ const llvm::SmallVectorImpl<llvm::Constant *> &IvarOffsets);
+ llvm::Constant *GenerateMethodList(const std::string &ClassName,
+ const std::string &CategoryName,
+ const llvm::SmallVectorImpl<Selector> &MethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes,
+ bool isClassMethodList);
+ llvm::Constant *GenerateEmptyProtocol(const std::string &ProtocolName);
+ llvm::Constant *GenerateProtocolList(
+ const llvm::SmallVectorImpl<std::string> &Protocols);
+ llvm::Constant *GenerateClassStructure(
+ llvm::Constant *MetaClass,
+ llvm::Constant *SuperClass,
+ unsigned info,
+ const char *Name,
+ llvm::Constant *Version,
+ llvm::Constant *InstanceSize,
+ llvm::Constant *IVars,
+ llvm::Constant *Methods,
+ llvm::Constant *Protocols);
+ llvm::Constant *GenerateProtocolMethodList(
+ const llvm::SmallVectorImpl<llvm::Constant *> &MethodNames,
+ const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes);
+ llvm::Constant *MakeConstantString(const std::string &Str, const std::string
+ &Name="");
+ llvm::Constant *MakeGlobal(const llvm::StructType *Ty,
+ std::vector<llvm::Constant*> &V, const std::string &Name="");
+ llvm::Constant *MakeGlobal(const llvm::ArrayType *Ty,
+ std::vector<llvm::Constant*> &V, const std::string &Name="");
+ llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
+ const ObjCIvarDecl *Ivar);
+public:
+ CGObjCGNU(CodeGen::CodeGenModule &cgm);
+ virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *);
+ virtual CodeGen::RValue
+ GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ llvm::Value *Receiver,
+ bool IsClassMessage,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method);
+ virtual CodeGen::RValue
+ GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ const ObjCInterfaceDecl *Class,
+ bool isCategoryImpl,
+ llvm::Value *Receiver,
+ bool IsClassMessage,
+ const CallArgList &CallArgs);
+ virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *OID);
+ virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel);
+ virtual llvm::Value *GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
+ *Method);
+
+ virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD);
+ virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
+ virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
+ virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ const ObjCProtocolDecl *PD);
+ virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
+ virtual llvm::Function *ModuleInitFunction();
+ virtual llvm::Function *GetPropertyGetFunction();
+ virtual llvm::Function *GetPropertySetFunction();
+ virtual llvm::Function *EnumerationMutationFunction();
+
+ virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
+ const Stmt &S);
+ virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
+ const ObjCAtThrowStmt &S);
+ virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *AddrWeakObj);
+ virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst);
+ virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest);
+ virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest);
+ virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest);
+ virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
+ QualType ObjectTy,
+ llvm::Value *BaseValue,
+ const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers);
+ virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *Interface,
+ const ObjCIvarDecl *Ivar);
+};
+} // end anonymous namespace
+
+
+
+static std::string SymbolNameForClass(const std::string &ClassName) {
+ return "___objc_class_name_" + ClassName;
+}
+
+static std::string SymbolNameForMethod(const std::string &ClassName, const
+ std::string &CategoryName, const std::string &MethodName, bool isClassMethod)
+{
+ return "._objc_method_" + ClassName +"("+CategoryName+")"+
+ (isClassMethod ? "+" : "-") + MethodName;
+}
+
+CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
+ : CGM(cgm), TheModule(CGM.getModule()), ClassPtrAlias(0),
+ MetaClassPtrAlias(0) {
+ IntTy = cast<llvm::IntegerType>(
+ CGM.getTypes().ConvertType(CGM.getContext().IntTy));
+ LongTy = cast<llvm::IntegerType>(
+ CGM.getTypes().ConvertType(CGM.getContext().LongTy));
+
+ Zeros[0] = llvm::ConstantInt::get(LongTy, 0);
+ Zeros[1] = Zeros[0];
+ NULLPtr = llvm::ConstantPointerNull::get(
+ llvm::PointerType::getUnqual(llvm::Type::Int8Ty));
+ // C string type. Used in lots of places.
+ PtrToInt8Ty =
+ llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ // Get the selector Type.
+ SelectorTy = cast<llvm::PointerType>(
+ CGM.getTypes().ConvertType(CGM.getContext().getObjCSelType()));
+
+ PtrToIntTy = llvm::PointerType::getUnqual(IntTy);
+ PtrTy = PtrToInt8Ty;
+
+ // Object type
+ IdTy = cast<llvm::PointerType>(
+ CGM.getTypes().ConvertType(CGM.getContext().getObjCIdType()));
+
+ // IMP type
+ std::vector<const llvm::Type*> IMPArgs;
+ IMPArgs.push_back(IdTy);
+ IMPArgs.push_back(SelectorTy);
+ IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
+}
+// This has to perform the lookup every time, since posing and related
+// techniques can modify the name -> class mapping.
+llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *OID) {
+ llvm::Value *ClassName = CGM.GetAddrOfConstantCString(OID->getNameAsString());
+ ClassName = Builder.CreateStructGEP(ClassName, 0);
+
+ std::vector<const llvm::Type*> Params(1, PtrToInt8Ty);
+ llvm::Constant *ClassLookupFn =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy,
+ Params,
+ true),
+ "objc_lookup_class");
+ return Builder.CreateCall(ClassLookupFn, ClassName);
+}
+
+llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel) {
+ llvm::GlobalAlias *&US = UntypedSelectors[Sel.getAsString()];
+ if (US == 0)
+ US = new llvm::GlobalAlias(llvm::PointerType::getUnqual(SelectorTy),
+ llvm::GlobalValue::InternalLinkage,
+ ".objc_untyped_selector_alias",
+ NULL, &TheModule);
+
+ return Builder.CreateLoad(US);
+}
+
+llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
+ *Method) {
+
+ std::string SelName = Method->getSelector().getAsString();
+ std::string SelTypes;
+ CGM.getContext().getObjCEncodingForMethodDecl(Method, SelTypes);
+ // Typed selectors
+ TypedSelector Selector = TypedSelector(SelName,
+ SelTypes);
+
+ // If it's already cached, return it.
+ if (TypedSelectors[Selector])
+ {
+ return Builder.CreateLoad(TypedSelectors[Selector]);
+ }
+
+ // If it isn't, cache it.
+ llvm::GlobalAlias *Sel = new llvm::GlobalAlias(
+ llvm::PointerType::getUnqual(SelectorTy),
+ llvm::GlobalValue::InternalLinkage, SelName,
+ NULL, &TheModule);
+ TypedSelectors[Selector] = Sel;
+
+ return Builder.CreateLoad(Sel);
+}
+
+llvm::Constant *CGObjCGNU::MakeConstantString(const std::string &Str,
+ const std::string &Name) {
+ llvm::Constant * ConstStr = llvm::ConstantArray::get(Str);
+ ConstStr = new llvm::GlobalVariable(ConstStr->getType(), true,
+ llvm::GlobalValue::InternalLinkage,
+ ConstStr, Name, &TheModule);
+ return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2);
+}
+llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty,
+ std::vector<llvm::Constant*> &V, const std::string &Name) {
+ llvm::Constant *C = llvm::ConstantStruct::get(Ty, V);
+ return new llvm::GlobalVariable(Ty, false,
+ llvm::GlobalValue::InternalLinkage, C, Name, &TheModule);
+}
+llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty,
+ std::vector<llvm::Constant*> &V, const std::string &Name) {
+ llvm::Constant *C = llvm::ConstantArray::get(Ty, V);
+ return new llvm::GlobalVariable(Ty, false,
+ llvm::GlobalValue::InternalLinkage, C, Name, &TheModule);
+}
+
+/// Generate an NSConstantString object.
+//TODO: In case there are any crazy people still using the GNU runtime without
+//an OpenStep implementation, this should let them select their own class for
+//constant strings.
+llvm::Constant *CGObjCGNU::GenerateConstantString(const ObjCStringLiteral *SL) {
+ std::string Str(SL->getString()->getStrData(),
+ SL->getString()->getByteLength());
+ std::vector<llvm::Constant*> Ivars;
+ Ivars.push_back(NULLPtr);
+ Ivars.push_back(MakeConstantString(Str));
+ Ivars.push_back(llvm::ConstantInt::get(IntTy, Str.size()));
+ llvm::Constant *ObjCStr = MakeGlobal(
+ llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL),
+ Ivars, ".objc_str");
+ ConstantStrings.push_back(
+ llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty));
+ return ObjCStr;
+}
+
+///Generates a message send where the super is the receiver. This is a message
+///send to self with special delivery semantics indicating which class's method
+///should be called.
+CodeGen::RValue
+CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ const ObjCInterfaceDecl *Class,
+ bool isCategoryImpl,
+ llvm::Value *Receiver,
+ bool IsClassMessage,
+ const CallArgList &CallArgs) {
+ llvm::Value *cmd = GetSelector(CGF.Builder, Sel);
+
+ CallArgList ActualArgs;
+
+ ActualArgs.push_back(
+ std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)),
+ CGF.getContext().getObjCIdType()));
+ ActualArgs.push_back(std::make_pair(RValue::get(cmd),
+ CGF.getContext().getObjCSelType()));
+ ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
+
+ CodeGenTypes &Types = CGM.getTypes();
+ const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs);
+ const llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, false);
+
+ llvm::Value *ReceiverClass = 0;
+ if (isCategoryImpl) {
+ llvm::Constant *classLookupFunction = 0;
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(PtrTy);
+ if (IsClassMessage) {
+ classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
+ IdTy, Params, true), "objc_get_meta_class");
+ } else {
+ classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
+ IdTy, Params, true), "objc_get_class");
+ }
+ ReceiverClass = CGF.Builder.CreateCall(classLookupFunction,
+ MakeConstantString(Class->getNameAsString()));
+ } else {
+ // Set up global aliases for the metaclass or class pointer if they do not
+ // already exist. These will are forward-references which will be set to
+ // pointers to the class and metaclass structure created for the runtime load
+ // function. To send a message to super, we look up the value of the
+ // super_class pointer from either the class or metaclass structure.
+ if (IsClassMessage) {
+ if (!MetaClassPtrAlias) {
+ MetaClassPtrAlias = new llvm::GlobalAlias(IdTy,
+ llvm::GlobalValue::InternalLinkage, ".objc_metaclass_ref" +
+ Class->getNameAsString(), NULL, &TheModule);
+ }
+ ReceiverClass = MetaClassPtrAlias;
+ } else {
+ if (!ClassPtrAlias) {
+ ClassPtrAlias = new llvm::GlobalAlias(IdTy,
+ llvm::GlobalValue::InternalLinkage, ".objc_class_ref" +
+ Class->getNameAsString(), NULL, &TheModule);
+ }
+ ReceiverClass = ClassPtrAlias;
+ }
+ }
+ // Cast the pointer to a simplified version of the class structure
+ ReceiverClass = CGF.Builder.CreateBitCast(ReceiverClass,
+ llvm::PointerType::getUnqual(llvm::StructType::get(IdTy, IdTy, NULL)));
+ // Get the superclass pointer
+ ReceiverClass = CGF.Builder.CreateStructGEP(ReceiverClass, 1);
+ // Load the superclass pointer
+ ReceiverClass = CGF.Builder.CreateLoad(ReceiverClass);
+ // Construct the structure used to look up the IMP
+ llvm::StructType *ObjCSuperTy = llvm::StructType::get(Receiver->getType(),
+ IdTy, NULL);
+ llvm::Value *ObjCSuper = CGF.Builder.CreateAlloca(ObjCSuperTy);
+
+ CGF.Builder.CreateStore(Receiver, CGF.Builder.CreateStructGEP(ObjCSuper, 0));
+ CGF.Builder.CreateStore(ReceiverClass,
+ CGF.Builder.CreateStructGEP(ObjCSuper, 1));
+
+ // Get the IMP
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(llvm::PointerType::getUnqual(ObjCSuperTy));
+ Params.push_back(SelectorTy);
+ llvm::Constant *lookupFunction =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(
+ llvm::PointerType::getUnqual(impType), Params, true),
+ "objc_msg_lookup_super");
+
+ llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
+ llvm::Value *imp = CGF.Builder.CreateCall(lookupFunction, lookupArgs,
+ lookupArgs+2);
+
+ return CGF.EmitCall(FnInfo, imp, ActualArgs);
+}
+
+/// Generate code for a message send expression.
+CodeGen::RValue
+CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ llvm::Value *Receiver,
+ bool IsClassMessage,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method) {
+ llvm::Value *cmd;
+ if (Method)
+ cmd = GetSelector(CGF.Builder, Method);
+ else
+ cmd = GetSelector(CGF.Builder, Sel);
+ CallArgList ActualArgs;
+
+ ActualArgs.push_back(
+ std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)),
+ CGF.getContext().getObjCIdType()));
+ ActualArgs.push_back(std::make_pair(RValue::get(cmd),
+ CGF.getContext().getObjCSelType()));
+ ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
+
+ CodeGenTypes &Types = CGM.getTypes();
+ const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs);
+ const llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, false);
+
+ llvm::Value *imp;
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(Receiver->getType());
+ Params.push_back(SelectorTy);
+ // For sender-aware dispatch, we pass the sender as the third argument to a
+ // lookup function. When sending messages from C code, the sender is nil.
+ // objc_msg_lookup_sender(id receiver, SEL selector, id sender);
+ if (CGM.getContext().getLangOptions().ObjCSenderDispatch) {
+ llvm::Value *self;
+
+ if (isa<ObjCMethodDecl>(CGF.CurFuncDecl)) {
+ self = CGF.LoadObjCSelf();
+ } else {
+ self = llvm::ConstantPointerNull::get(IdTy);
+ }
+ Params.push_back(self->getType());
+ llvm::Constant *lookupFunction =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(
+ llvm::PointerType::getUnqual(impType), Params, true),
+ "objc_msg_lookup_sender");
+
+ imp = CGF.Builder.CreateCall3(lookupFunction, Receiver, cmd, self);
+ } else {
+ llvm::Constant *lookupFunction =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(
+ llvm::PointerType::getUnqual(impType), Params, true),
+ "objc_msg_lookup");
+
+ imp = CGF.Builder.CreateCall2(lookupFunction, Receiver, cmd);
+ }
+
+ return CGF.EmitCall(FnInfo, imp, ActualArgs);
+}
+
+/// Generates a MethodList. Used in construction of a objc_class and
+/// objc_category structures.
+llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName,
+ const std::string &CategoryName,
+ const llvm::SmallVectorImpl<Selector> &MethodSels,
+ const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes,
+ bool isClassMethodList) {
+ // Get the method structure type.
+ llvm::StructType *ObjCMethodTy = llvm::StructType::get(
+ PtrToInt8Ty, // Really a selector, but the runtime creates it us.
+ PtrToInt8Ty, // Method types
+ llvm::PointerType::getUnqual(IMPTy), //Method pointer
+ NULL);
+ std::vector<llvm::Constant*> Methods;
+ std::vector<llvm::Constant*> Elements;
+ for (unsigned int i = 0, e = MethodTypes.size(); i < e; ++i) {
+ Elements.clear();
+ if (llvm::Constant *Method =
+ TheModule.getFunction(SymbolNameForMethod(ClassName, CategoryName,
+ MethodSels[i].getAsString(),
+ isClassMethodList))) {
+ llvm::Constant *C =
+ CGM.GetAddrOfConstantCString(MethodSels[i].getAsString());
+ Elements.push_back(llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2));
+ Elements.push_back(
+ llvm::ConstantExpr::getGetElementPtr(MethodTypes[i], Zeros, 2));
+ Method = llvm::ConstantExpr::getBitCast(Method,
+ llvm::PointerType::getUnqual(IMPTy));
+ Elements.push_back(Method);
+ Methods.push_back(llvm::ConstantStruct::get(ObjCMethodTy, Elements));
+ }
+ }
+
+ // Array of method structures
+ llvm::ArrayType *ObjCMethodArrayTy = llvm::ArrayType::get(ObjCMethodTy,
+ Methods.size());
+ llvm::Constant *MethodArray = llvm::ConstantArray::get(ObjCMethodArrayTy,
+ Methods);
+
+ // Structure containing list pointer, array and array count
+ llvm::SmallVector<const llvm::Type*, 16> ObjCMethodListFields;
+ llvm::PATypeHolder OpaqueNextTy = llvm::OpaqueType::get();
+ llvm::Type *NextPtrTy = llvm::PointerType::getUnqual(OpaqueNextTy);
+ llvm::StructType *ObjCMethodListTy = llvm::StructType::get(NextPtrTy,
+ IntTy,
+ ObjCMethodArrayTy,
+ NULL);
+ // Refine next pointer type to concrete type
+ llvm::cast<llvm::OpaqueType>(
+ OpaqueNextTy.get())->refineAbstractTypeTo(ObjCMethodListTy);
+ ObjCMethodListTy = llvm::cast<llvm::StructType>(OpaqueNextTy.get());
+
+ Methods.clear();
+ Methods.push_back(llvm::ConstantPointerNull::get(
+ llvm::PointerType::getUnqual(ObjCMethodListTy)));
+ Methods.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ MethodTypes.size()));
+ Methods.push_back(MethodArray);
+
+ // Create an instance of the structure
+ return MakeGlobal(ObjCMethodListTy, Methods, ".objc_method_list");
+}
+
+/// 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) {
+ // Get the method structure type.
+ llvm::StructType *ObjCIvarTy = llvm::StructType::get(
+ PtrToInt8Ty,
+ PtrToInt8Ty,
+ IntTy,
+ NULL);
+ std::vector<llvm::Constant*> Ivars;
+ std::vector<llvm::Constant*> Elements;
+ for (unsigned int i = 0, e = IvarNames.size() ; i < e ; i++) {
+ Elements.clear();
+ Elements.push_back( llvm::ConstantExpr::getGetElementPtr(IvarNames[i],
+ Zeros, 2));
+ Elements.push_back( llvm::ConstantExpr::getGetElementPtr(IvarTypes[i],
+ Zeros, 2));
+ Elements.push_back(IvarOffsets[i]);
+ Ivars.push_back(llvm::ConstantStruct::get(ObjCIvarTy, Elements));
+ }
+
+ // Array of method structures
+ llvm::ArrayType *ObjCIvarArrayTy = llvm::ArrayType::get(ObjCIvarTy,
+ IvarNames.size());
+
+
+ Elements.clear();
+ Elements.push_back(llvm::ConstantInt::get(IntTy, (int)IvarNames.size()));
+ Elements.push_back(llvm::ConstantArray::get(ObjCIvarArrayTy, Ivars));
+ // Structure containing array and array count
+ llvm::StructType *ObjCIvarListTy = llvm::StructType::get(IntTy,
+ ObjCIvarArrayTy,
+ NULL);
+
+ // Create an instance of the structure
+ return MakeGlobal(ObjCIvarListTy, Elements, ".objc_ivar_list");
+}
+
+/// Generate a class structure
+llvm::Constant *CGObjCGNU::GenerateClassStructure(
+ llvm::Constant *MetaClass,
+ llvm::Constant *SuperClass,
+ unsigned info,
+ const char *Name,
+ llvm::Constant *Version,
+ llvm::Constant *InstanceSize,
+ llvm::Constant *IVars,
+ llvm::Constant *Methods,
+ llvm::Constant *Protocols) {
+ // Set up the class structure
+ // Note: Several of these are char*s when they should be ids. This is
+ // because the runtime performs this translation on load.
+ llvm::StructType *ClassTy = llvm::StructType::get(
+ PtrToInt8Ty, // class_pointer
+ PtrToInt8Ty, // super_class
+ PtrToInt8Ty, // name
+ LongTy, // version
+ LongTy, // info
+ LongTy, // instance_size
+ IVars->getType(), // ivars
+ Methods->getType(), // methods
+ // These are all filled in by the runtime, so we pretend
+ PtrTy, // dtable
+ PtrTy, // subclass_list
+ PtrTy, // sibling_class
+ PtrTy, // protocols
+ PtrTy, // gc_object_type
+ NULL);
+ llvm::Constant *Zero = llvm::ConstantInt::get(LongTy, 0);
+ llvm::Constant *NullP =
+ llvm::ConstantPointerNull::get(PtrTy);
+ // Fill in the structure
+ std::vector<llvm::Constant*> Elements;
+ Elements.push_back(llvm::ConstantExpr::getBitCast(MetaClass, PtrToInt8Ty));
+ Elements.push_back(SuperClass);
+ Elements.push_back(MakeConstantString(Name, ".class_name"));
+ Elements.push_back(Zero);
+ Elements.push_back(llvm::ConstantInt::get(LongTy, info));
+ Elements.push_back(InstanceSize);
+ Elements.push_back(IVars);
+ Elements.push_back(Methods);
+ Elements.push_back(NullP);
+ Elements.push_back(NullP);
+ Elements.push_back(NullP);
+ Elements.push_back(llvm::ConstantExpr::getBitCast(Protocols, PtrTy));
+ Elements.push_back(NullP);
+ // Create an instance of the structure
+ return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name));
+}
+
+llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
+ const llvm::SmallVectorImpl<llvm::Constant *> &MethodNames,
+ const llvm::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.
+ PtrToInt8Ty,
+ NULL);
+ std::vector<llvm::Constant*> Methods;
+ std::vector<llvm::Constant*> Elements;
+ for (unsigned int i = 0, e = MethodTypes.size() ; i < e ; i++) {
+ Elements.clear();
+ Elements.push_back( llvm::ConstantExpr::getGetElementPtr(MethodNames[i],
+ Zeros, 2));
+ Elements.push_back(
+ llvm::ConstantExpr::getGetElementPtr(MethodTypes[i], Zeros, 2));
+ Methods.push_back(llvm::ConstantStruct::get(ObjCMethodDescTy, Elements));
+ }
+ llvm::ArrayType *ObjCMethodArrayTy = llvm::ArrayType::get(ObjCMethodDescTy,
+ MethodNames.size());
+ llvm::Constant *Array = llvm::ConstantArray::get(ObjCMethodArrayTy, Methods);
+ llvm::StructType *ObjCMethodDescListTy = llvm::StructType::get(
+ IntTy, ObjCMethodArrayTy, NULL);
+ Methods.clear();
+ Methods.push_back(llvm::ConstantInt::get(IntTy, MethodNames.size()));
+ Methods.push_back(Array);
+ return MakeGlobal(ObjCMethodDescListTy, Methods, ".objc_method_list");
+}
+// Create the protocol list structure used in classes, categories and so on
+llvm::Constant *CGObjCGNU::GenerateProtocolList(
+ const llvm::SmallVectorImpl<std::string> &Protocols) {
+ llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrToInt8Ty,
+ Protocols.size());
+ llvm::StructType *ProtocolListTy = llvm::StructType::get(
+ PtrTy, //Should be a recurisve pointer, but it's always NULL here.
+ LongTy,//FIXME: Should be size_t
+ ProtocolArrayTy,
+ NULL);
+ std::vector<llvm::Constant*> Elements;
+ for (const std::string *iter = Protocols.begin(), *endIter = Protocols.end();
+ iter != endIter ; iter++) {
+ llvm::Constant *protocol = ExistingProtocols[*iter];
+ if (!protocol)
+ protocol = GenerateEmptyProtocol(*iter);
+ llvm::Constant *Ptr =
+ llvm::ConstantExpr::getBitCast(protocol, PtrToInt8Ty);
+ Elements.push_back(Ptr);
+ }
+ llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy,
+ Elements);
+ Elements.clear();
+ Elements.push_back(NULLPtr);
+ Elements.push_back(llvm::ConstantInt::get(LongTy, Protocols.size()));
+ Elements.push_back(ProtocolArray);
+ return MakeGlobal(ProtocolListTy, Elements, ".objc_protocol_list");
+}
+
+llvm::Value *CGObjCGNU::GenerateProtocolRef(CGBuilderTy &Builder,
+ const ObjCProtocolDecl *PD) {
+ llvm::Value *protocol = ExistingProtocols[PD->getNameAsString()];
+ const 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;
+
+ llvm::Constant *ProtocolList = GenerateProtocolList(EmptyStringVector);
+ llvm::Constant *InstanceMethodList =
+ GenerateProtocolMethodList(EmptyConstantVector, EmptyConstantVector);
+ llvm::Constant *ClassMethodList =
+ GenerateProtocolMethodList(EmptyConstantVector, EmptyConstantVector);
+ // Protocols are objects containing lists of the methods implemented and
+ // protocols adopted.
+ llvm::StructType *ProtocolTy = llvm::StructType::get(IdTy,
+ PtrToInt8Ty,
+ ProtocolList->getType(),
+ InstanceMethodList->getType(),
+ ClassMethodList->getType(),
+ NULL);
+ std::vector<llvm::Constant*> Elements;
+ // 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::Int32Ty, ProtocolVersion), IdTy));
+ Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name"));
+ Elements.push_back(ProtocolList);
+ Elements.push_back(InstanceMethodList);
+ Elements.push_back(ClassMethodList);
+ return MakeGlobal(ProtocolTy, Elements, ".objc_protocol");
+}
+
+void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
+ ASTContext &Context = CGM.getContext();
+ std::string ProtocolName = PD->getNameAsString();
+ llvm::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;
+ for (ObjCProtocolDecl::instmeth_iterator iter = PD->instmeth_begin(Context),
+ E = PD->instmeth_end(Context); iter != E; iter++) {
+ std::string TypeStr;
+ Context.getObjCEncodingForMethodDecl(*iter, TypeStr);
+ InstanceMethodNames.push_back(
+ CGM.GetAddrOfConstantCString((*iter)->getSelector().getAsString()));
+ InstanceMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
+ }
+ // Collect information about class methods:
+ llvm::SmallVector<llvm::Constant*, 16> ClassMethodNames;
+ llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes;
+ for (ObjCProtocolDecl::classmeth_iterator
+ iter = PD->classmeth_begin(Context),
+ endIter = PD->classmeth_end(Context) ; iter != endIter ; iter++) {
+ std::string TypeStr;
+ Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
+ ClassMethodNames.push_back(
+ CGM.GetAddrOfConstantCString((*iter)->getSelector().getAsString()));
+ ClassMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
+ }
+
+ llvm::Constant *ProtocolList = GenerateProtocolList(Protocols);
+ llvm::Constant *InstanceMethodList =
+ GenerateProtocolMethodList(InstanceMethodNames, InstanceMethodTypes);
+ llvm::Constant *ClassMethodList =
+ GenerateProtocolMethodList(ClassMethodNames, ClassMethodTypes);
+ // Protocols are objects containing lists of the methods implemented and
+ // protocols adopted.
+ llvm::StructType *ProtocolTy = llvm::StructType::get(IdTy,
+ PtrToInt8Ty,
+ ProtocolList->getType(),
+ InstanceMethodList->getType(),
+ ClassMethodList->getType(),
+ NULL);
+ std::vector<llvm::Constant*> Elements;
+ // 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::Int32Ty, ProtocolVersion), IdTy));
+ Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name"));
+ Elements.push_back(ProtocolList);
+ Elements.push_back(InstanceMethodList);
+ Elements.push_back(ClassMethodList);
+ ExistingProtocols[ProtocolName] =
+ llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolTy, Elements,
+ ".objc_protocol"), IdTy);
+}
+
+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;
+ for (ObjCCategoryImplDecl::instmeth_iterator
+ iter = OCD->instmeth_begin(CGM.getContext()),
+ endIter = OCD->instmeth_end(CGM.getContext());
+ iter != endIter ; iter++) {
+ InstanceMethodSels.push_back((*iter)->getSelector());
+ std::string TypeStr;
+ CGM.getContext().getObjCEncodingForMethodDecl(*iter,TypeStr);
+ InstanceMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
+ }
+
+ // Collect information about class methods
+ llvm::SmallVector<Selector, 16> ClassMethodSels;
+ llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes;
+ for (ObjCCategoryImplDecl::classmeth_iterator
+ iter = OCD->classmeth_begin(CGM.getContext()),
+ endIter = OCD->classmeth_end(CGM.getContext());
+ iter != endIter ; iter++) {
+ ClassMethodSels.push_back((*iter)->getSelector());
+ std::string TypeStr;
+ CGM.getContext().getObjCEncodingForMethodDecl(*iter,TypeStr);
+ ClassMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
+ }
+
+ // Collect the names of referenced protocols
+ llvm::SmallVector<std::string, 16> Protocols;
+ const ObjCInterfaceDecl *ClassDecl = OCD->getClassInterface();
+ const ObjCList<ObjCProtocolDecl> &Protos =ClassDecl->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protos.begin(),
+ E = Protos.end(); I != E; ++I)
+ Protocols.push_back((*I)->getNameAsString());
+
+ std::vector<llvm::Constant*> Elements;
+ Elements.push_back(MakeConstantString(CategoryName));
+ Elements.push_back(MakeConstantString(ClassName));
+ // Instance method list
+ Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList(
+ ClassName, CategoryName, InstanceMethodSels, InstanceMethodTypes,
+ false), PtrTy));
+ // Class method list
+ Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList(
+ ClassName, CategoryName, ClassMethodSels, ClassMethodTypes, true),
+ PtrTy));
+ // Protocol list
+ Elements.push_back(llvm::ConstantExpr::getBitCast(
+ GenerateProtocolList(Protocols), PtrTy));
+ Categories.push_back(llvm::ConstantExpr::getBitCast(
+ MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, PtrTy,
+ PtrTy, PtrTy, NULL), Elements), PtrTy));
+}
+
+void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
+ ASTContext &Context = CGM.getContext();
+
+ // Get the superclass name.
+ const ObjCInterfaceDecl * SuperClassDecl =
+ OID->getClassInterface()->getSuperClass();
+ std::string SuperClassName;
+ if (SuperClassDecl)
+ SuperClassName = SuperClassDecl->getNameAsString();
+
+ // Get the class name
+ ObjCInterfaceDecl *ClassDecl =
+ const_cast<ObjCInterfaceDecl *>(OID->getClassInterface());
+ std::string ClassName = ClassDecl->getNameAsString();
+
+ // Get the size of instances.
+ int instanceSize = Context.getASTObjCImplementationLayout(OID).getSize() / 8;
+
+ // Collect information about instance variables.
+ llvm::SmallVector<llvm::Constant*, 16> IvarNames;
+ llvm::SmallVector<llvm::Constant*, 16> IvarTypes;
+ llvm::SmallVector<llvm::Constant*, 16> IvarOffsets;
+
+ int superInstanceSize = !SuperClassDecl ? 0 :
+ Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize() / 8;
+ // For non-fragile ivars, set the instance size to 0 - {the size of just this
+ // class}. The runtime will then set this to the correct value on load.
+ if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
+ instanceSize = 0 - (instanceSize - superInstanceSize);
+ }
+ for (ObjCInterfaceDecl::ivar_iterator iter = ClassDecl->ivar_begin(),
+ endIter = ClassDecl->ivar_end() ; iter != endIter ; iter++) {
+ // Store the name
+ IvarNames.push_back(CGM.GetAddrOfConstantCString((*iter)
+ ->getNameAsString()));
+ // Get the type encoding for this ivar
+ std::string TypeStr;
+ Context.getObjCEncodingForType((*iter)->getType(), TypeStr);
+ IvarTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
+ // Get the offset
+ uint64_t Offset;
+ if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
+ Offset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter) -
+ superInstanceSize;
+ ObjCIvarOffsetVariable(ClassDecl, *iter);
+ } else {
+ Offset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter);
+ }
+ IvarOffsets.push_back(
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, Offset));
+ }
+
+ // Collect information about instance methods
+ llvm::SmallVector<Selector, 16> InstanceMethodSels;
+ llvm::SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
+ for (ObjCImplementationDecl::instmeth_iterator
+ iter = OID->instmeth_begin(CGM.getContext()),
+ endIter = OID->instmeth_end(CGM.getContext());
+ iter != endIter ; iter++) {
+ InstanceMethodSels.push_back((*iter)->getSelector());
+ std::string TypeStr;
+ Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
+ InstanceMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
+ }
+ for (ObjCImplDecl::propimpl_iterator
+ iter = OID->propimpl_begin(CGM.getContext()),
+ endIter = OID->propimpl_end(CGM.getContext());
+ iter != endIter ; iter++) {
+ ObjCPropertyDecl *property = (*iter)->getPropertyDecl();
+ if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) {
+ InstanceMethodSels.push_back(getter->getSelector());
+ std::string TypeStr;
+ Context.getObjCEncodingForMethodDecl(getter,TypeStr);
+ InstanceMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
+ }
+ if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) {
+ InstanceMethodSels.push_back(setter->getSelector());
+ std::string TypeStr;
+ Context.getObjCEncodingForMethodDecl(setter,TypeStr);
+ InstanceMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
+ }
+ }
+
+ // Collect information about class methods
+ llvm::SmallVector<Selector, 16> ClassMethodSels;
+ llvm::SmallVector<llvm::Constant*, 16> ClassMethodTypes;
+ for (ObjCImplementationDecl::classmeth_iterator
+ iter = OID->classmeth_begin(CGM.getContext()),
+ endIter = OID->classmeth_end(CGM.getContext());
+ iter != endIter ; iter++) {
+ ClassMethodSels.push_back((*iter)->getSelector());
+ std::string TypeStr;
+ Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
+ ClassMethodTypes.push_back(CGM.GetAddrOfConstantCString(TypeStr));
+ }
+ // Collect the names of referenced protocols
+ llvm::SmallVector<std::string, 16> Protocols;
+ const ObjCList<ObjCProtocolDecl> &Protos =ClassDecl->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protos.begin(),
+ E = Protos.end(); I != E; ++I)
+ Protocols.push_back((*I)->getNameAsString());
+
+
+
+ // Get the superclass pointer.
+ llvm::Constant *SuperClass;
+ if (!SuperClassName.empty()) {
+ SuperClass = MakeConstantString(SuperClassName, ".super_class_name");
+ } else {
+ SuperClass = llvm::ConstantPointerNull::get(PtrToInt8Ty);
+ }
+ // Empty vector used to construct empty method lists
+ llvm::SmallVector<llvm::Constant*, 1> empty;
+ // Generate the method and instance variable lists
+ llvm::Constant *MethodList = GenerateMethodList(ClassName, "",
+ InstanceMethodSels, InstanceMethodTypes, false);
+ llvm::Constant *ClassMethodList = GenerateMethodList(ClassName, "",
+ ClassMethodSels, ClassMethodTypes, true);
+ llvm::Constant *IvarList = GenerateIvarList(IvarNames, IvarTypes,
+ IvarOffsets);
+ //Generate metaclass for class methods
+ llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr,
+ NULLPtr, 0x2L, /*name*/"", 0, Zeros[0], GenerateIvarList(
+ empty, empty, empty), ClassMethodList, NULLPtr);
+
+ // Generate the class structure
+ llvm::Constant *ClassStruct =
+ GenerateClassStructure(MetaClassStruct, SuperClass, 0x1L,
+ ClassName.c_str(), 0,
+ llvm::ConstantInt::get(LongTy, instanceSize), IvarList,
+ MethodList, GenerateProtocolList(Protocols));
+
+ // Resolve the class aliases, if they exist.
+ if (ClassPtrAlias) {
+ ClassPtrAlias->setAliasee(
+ llvm::ConstantExpr::getBitCast(ClassStruct, IdTy));
+ ClassPtrAlias = 0;
+ }
+ if (MetaClassPtrAlias) {
+ MetaClassPtrAlias->setAliasee(
+ llvm::ConstantExpr::getBitCast(MetaClassStruct, IdTy));
+ MetaClassPtrAlias = 0;
+ }
+
+ // Add class structure to list to be added to the symtab later
+ ClassStruct = llvm::ConstantExpr::getBitCast(ClassStruct, PtrToInt8Ty);
+ Classes.push_back(ClassStruct);
+}
+
+llvm::Function *CGObjCGNU::ModuleInitFunction() {
+ // Only emit an ObjC load function if no Objective-C stuff has been called
+ if (Classes.empty() && Categories.empty() && ConstantStrings.empty() &&
+ ExistingProtocols.empty() && TypedSelectors.empty() &&
+ UntypedSelectors.empty())
+ return NULL;
+
+ const llvm::StructType *SelStructTy = dyn_cast<llvm::StructType>(
+ SelectorTy->getElementType());
+ const llvm::Type *SelStructPtrTy = SelectorTy;
+ bool isSelOpaque = false;
+ if (SelStructTy == 0) {
+ SelStructTy = llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, NULL);
+ SelStructPtrTy = llvm::PointerType::getUnqual(SelStructTy);
+ isSelOpaque = true;
+ }
+
+ // Name the ObjC types to make the IR a bit easier to read
+ TheModule.addTypeName(".objc_selector", SelStructPtrTy);
+ TheModule.addTypeName(".objc_id", IdTy);
+ TheModule.addTypeName(".objc_imp", IMPTy);
+
+ std::vector<llvm::Constant*> Elements;
+ llvm::Constant *Statics = NULLPtr;
+ // Generate statics list:
+ if (ConstantStrings.size()) {
+ llvm::ArrayType *StaticsArrayTy = llvm::ArrayType::get(PtrToInt8Ty,
+ ConstantStrings.size() + 1);
+ ConstantStrings.push_back(NULLPtr);
+ Elements.push_back(MakeConstantString("NSConstantString",
+ ".objc_static_class_name"));
+ Elements.push_back(llvm::ConstantArray::get(StaticsArrayTy,
+ ConstantStrings));
+ llvm::StructType *StaticsListTy =
+ llvm::StructType::get(PtrToInt8Ty, StaticsArrayTy, NULL);
+ llvm::Type *StaticsListPtrTy = llvm::PointerType::getUnqual(StaticsListTy);
+ Statics = MakeGlobal(StaticsListTy, Elements, ".objc_statics");
+ llvm::ArrayType *StaticsListArrayTy =
+ llvm::ArrayType::get(StaticsListPtrTy, 2);
+ Elements.clear();
+ Elements.push_back(Statics);
+ Elements.push_back(llvm::Constant::getNullValue(StaticsListPtrTy));
+ Statics = MakeGlobal(StaticsListArrayTy, Elements, ".objc_statics_ptr");
+ Statics = llvm::ConstantExpr::getBitCast(Statics, PtrTy);
+ }
+ // Array of classes, categories, and constant objects
+ llvm::ArrayType *ClassListTy = llvm::ArrayType::get(PtrToInt8Ty,
+ Classes.size() + Categories.size() + 2);
+ llvm::StructType *SymTabTy = llvm::StructType::get(LongTy, SelStructPtrTy,
+ llvm::Type::Int16Ty,
+ llvm::Type::Int16Ty,
+ ClassListTy, NULL);
+
+ Elements.clear();
+ // Pointer to an array of selectors used in this module.
+ std::vector<llvm::Constant*> Selectors;
+ for (std::map<TypedSelector, llvm::GlobalAlias*>::iterator
+ iter = TypedSelectors.begin(), iterEnd = TypedSelectors.end();
+ iter != iterEnd ; ++iter) {
+ Elements.push_back(MakeConstantString(iter->first.first, ".objc_sel_name"));
+ Elements.push_back(MakeConstantString(iter->first.second,
+ ".objc_sel_types"));
+ Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
+ Elements.clear();
+ }
+ for (llvm::StringMap<llvm::GlobalAlias*>::iterator
+ iter = UntypedSelectors.begin(), iterEnd = UntypedSelectors.end();
+ iter != iterEnd; ++iter) {
+ Elements.push_back(
+ MakeConstantString(iter->getKeyData(), ".objc_sel_name"));
+ Elements.push_back(NULLPtr);
+ Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
+ Elements.clear();
+ }
+ Elements.push_back(NULLPtr);
+ Elements.push_back(NULLPtr);
+ Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
+ Elements.clear();
+ // Number of static selectors
+ Elements.push_back(llvm::ConstantInt::get(LongTy, Selectors.size() ));
+ llvm::Constant *SelectorList = MakeGlobal(
+ llvm::ArrayType::get(SelStructTy, Selectors.size()), Selectors,
+ ".objc_selector_list");
+ Elements.push_back(llvm::ConstantExpr::getBitCast(SelectorList,
+ SelStructPtrTy));
+
+ // Now that all of the static selectors exist, create pointers to them.
+ int index = 0;
+ for (std::map<TypedSelector, llvm::GlobalAlias*>::iterator
+ iter=TypedSelectors.begin(), iterEnd =TypedSelectors.end();
+ iter != iterEnd; ++iter) {
+ llvm::Constant *Idxs[] = {Zeros[0],
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, index++), Zeros[0]};
+ llvm::Constant *SelPtr = new llvm::GlobalVariable(SelStructPtrTy,
+ true, llvm::GlobalValue::InternalLinkage,
+ llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2),
+ ".objc_sel_ptr", &TheModule);
+ // If selectors are defined as an opaque type, cast the pointer to this
+ // type.
+ if (isSelOpaque) {
+ SelPtr = llvm::ConstantExpr::getBitCast(SelPtr,
+ llvm::PointerType::getUnqual(SelectorTy));
+ }
+ (*iter).second->setAliasee(SelPtr);
+ }
+ for (llvm::StringMap<llvm::GlobalAlias*>::iterator
+ iter=UntypedSelectors.begin(), iterEnd = UntypedSelectors.end();
+ iter != iterEnd; iter++) {
+ llvm::Constant *Idxs[] = {Zeros[0],
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, index++), Zeros[0]};
+ llvm::Constant *SelPtr = new llvm::GlobalVariable(SelStructPtrTy, true,
+ llvm::GlobalValue::InternalLinkage,
+ llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2),
+ ".objc_sel_ptr", &TheModule);
+ // If selectors are defined as an opaque type, cast the pointer to this
+ // type.
+ if (isSelOpaque) {
+ SelPtr = llvm::ConstantExpr::getBitCast(SelPtr,
+ llvm::PointerType::getUnqual(SelectorTy));
+ }
+ (*iter).second->setAliasee(SelPtr);
+ }
+ // Number of classes defined.
+ Elements.push_back(llvm::ConstantInt::get(llvm::Type::Int16Ty,
+ Classes.size()));
+ // Number of categories defined
+ Elements.push_back(llvm::ConstantInt::get(llvm::Type::Int16Ty,
+ Categories.size()));
+ // Create an array of classes, then categories, then static object instances
+ Classes.insert(Classes.end(), Categories.begin(), Categories.end());
+ // NULL-terminated list of static object instances (mainly constant strings)
+ Classes.push_back(Statics);
+ Classes.push_back(NULLPtr);
+ llvm::Constant *ClassList = llvm::ConstantArray::get(ClassListTy, Classes);
+ Elements.push_back(ClassList);
+ // Construct the symbol table
+ llvm::Constant *SymTab= MakeGlobal(SymTabTy, Elements);
+
+ // The symbol table is contained in a module which has some version-checking
+ // constants
+ llvm::StructType * ModuleTy = llvm::StructType::get(LongTy, LongTy,
+ PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy), NULL);
+ Elements.clear();
+ // Runtime version used for compatibility checking.
+ if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
+ Elements.push_back(llvm::ConstantInt::get(LongTy,
+ NonFragileRuntimeVersion));
+ } else {
+ Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
+ }
+ // sizeof(ModuleTy)
+ llvm::TargetData td = llvm::TargetData::TargetData(&TheModule);
+ Elements.push_back(llvm::ConstantInt::get(LongTy, td.getTypeSizeInBits(ModuleTy)/8));
+ //FIXME: Should be the path to the file where this module was declared
+ Elements.push_back(NULLPtr);
+ Elements.push_back(SymTab);
+ llvm::Value *Module = MakeGlobal(ModuleTy, Elements);
+
+ // Create the load function calling the runtime entry point with the module
+ // structure
+ std::vector<const llvm::Type*> VoidArgs;
+ llvm::Function * LoadFunction = llvm::Function::Create(
+ llvm::FunctionType::get(llvm::Type::VoidTy, VoidArgs, false),
+ llvm::GlobalValue::InternalLinkage, ".objc_load_function",
+ &TheModule);
+ llvm::BasicBlock *EntryBB = llvm::BasicBlock::Create("entry", LoadFunction);
+ CGBuilderTy Builder;
+ Builder.SetInsertPoint(EntryBB);
+
+ std::vector<const llvm::Type*> Params(1,
+ llvm::PointerType::getUnqual(ModuleTy));
+ llvm::Value *Register = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
+ llvm::Type::VoidTy, Params, true), "__objc_exec_class");
+ Builder.CreateCall(Register, Module);
+ Builder.CreateRetVoid();
+
+ return LoadFunction;
+}
+
+llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) {
+ const ObjCCategoryImplDecl *OCD =
+ dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext());
+ std::string CategoryName = OCD ? OCD->getNameAsString() : "";
+ std::string ClassName = OMD->getClassInterface()->getNameAsString();
+ std::string MethodName = OMD->getSelector().getAsString();
+ bool isClassMethod = !OMD->isInstanceMethod();
+
+ CodeGenTypes &Types = CGM.getTypes();
+ const llvm::FunctionType *MethodTy =
+ Types.GetFunctionType(Types.getFunctionInfo(OMD), OMD->isVariadic());
+ std::string FunctionName = SymbolNameForMethod(ClassName, CategoryName,
+ MethodName, isClassMethod);
+
+ llvm::Function *Method = llvm::Function::Create(MethodTy,
+ llvm::GlobalValue::InternalLinkage,
+ FunctionName,
+ &TheModule);
+ return Method;
+}
+
+llvm::Function *CGObjCGNU::GetPropertyGetFunction() {
+ std::vector<const llvm::Type*> Params;
+ const llvm::Type *BoolTy =
+ CGM.getTypes().ConvertType(CGM.getContext().BoolTy);
+ Params.push_back(IdTy);
+ Params.push_back(SelectorTy);
+ // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64
+ Params.push_back(LongTy);
+ Params.push_back(BoolTy);
+ // void objc_getProperty (id, SEL, ptrdiff_t, bool)
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(IdTy, Params, false);
+ return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy,
+ "objc_getProperty"));
+}
+
+llvm::Function *CGObjCGNU::GetPropertySetFunction() {
+ std::vector<const llvm::Type*> Params;
+ const llvm::Type *BoolTy =
+ CGM.getTypes().ConvertType(CGM.getContext().BoolTy);
+ Params.push_back(IdTy);
+ Params.push_back(SelectorTy);
+ // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64
+ Params.push_back(LongTy);
+ Params.push_back(IdTy);
+ Params.push_back(BoolTy);
+ Params.push_back(BoolTy);
+ // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool)
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::VoidTy, Params, false);
+ return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy,
+ "objc_setProperty"));
+}
+
+llvm::Function *CGObjCGNU::EnumerationMutationFunction() {
+ std::vector<const llvm::Type*> Params(1, IdTy);
+ return cast<llvm::Function>(CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(llvm::Type::VoidTy, Params, true),
+ "objc_enumerationMutation"));
+}
+
+void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
+ const Stmt &S) {
+ // Pointer to the personality function
+ llvm::Constant *Personality =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::Int32Ty,
+ std::vector<const llvm::Type*>(), true),
+ "__gnu_objc_personality_v0");
+ Personality = llvm::ConstantExpr::getBitCast(Personality, PtrTy);
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(PtrTy);
+ llvm::Value *RethrowFn =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
+ Params, false), "_Unwind_Resume_or_Rethrow");
+
+ bool isTry = isa<ObjCAtTryStmt>(S);
+ llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try");
+ llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest();
+ llvm::BasicBlock *TryHandler = CGF.createBasicBlock("try.handler");
+ llvm::BasicBlock *CatchInCatch = CGF.createBasicBlock("catch.rethrow");
+ llvm::BasicBlock *FinallyBlock = CGF.createBasicBlock("finally");
+ llvm::BasicBlock *FinallyRethrow = CGF.createBasicBlock("finally.throw");
+ llvm::BasicBlock *FinallyEnd = CGF.createBasicBlock("finally.end");
+
+ // GNU runtime does not currently support @synchronized()
+ if (!isTry) {
+ std::vector<const llvm::Type*> Args(1, IdTy);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::VoidTy, Args, false);
+ llvm::Value *SyncEnter = CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
+ llvm::Value *SyncArg =
+ CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
+ SyncArg = CGF.Builder.CreateBitCast(SyncArg, IdTy);
+ CGF.Builder.CreateCall(SyncEnter, SyncArg);
+ }
+
+
+ // Push an EH context entry, used for handling rethrows and jumps
+ // through finally.
+ CGF.PushCleanupBlock(FinallyBlock);
+
+ // Emit the statements in the @try {} block
+ CGF.setInvokeDest(TryHandler);
+
+ CGF.EmitBlock(TryBlock);
+ CGF.EmitStmt(isTry ? cast<ObjCAtTryStmt>(S).getTryBody()
+ : cast<ObjCAtSynchronizedStmt>(S).getSynchBody());
+
+ // Jump to @finally if there is no exception
+ CGF.EmitBranchThroughCleanup(FinallyEnd);
+
+ // Emit the handlers
+ CGF.EmitBlock(TryHandler);
+
+ // Get the correct versions of the exception handling intrinsics
+ llvm::TargetData td = llvm::TargetData::TargetData(&TheModule);
+ int PointerWidth = td.getTypeSizeInBits(PtrTy);
+ assert((PointerWidth == 32 || PointerWidth == 64) &&
+ "Can't yet handle exceptions if pointers are not 32 or 64 bits");
+ llvm::Value *llvm_eh_exception =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
+ llvm::Value *llvm_eh_selector = PointerWidth == 32 ?
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector_i32) :
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector_i64);
+ llvm::Value *llvm_eh_typeid_for = PointerWidth == 32 ?
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for_i32) :
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for_i64);
+
+ // Exception object
+ llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
+ llvm::Value *RethrowPtr = CGF.CreateTempAlloca(Exc->getType(), "_rethrow");
+
+ llvm::SmallVector<llvm::Value*, 8> ESelArgs;
+ llvm::SmallVector<std::pair<const ParmVarDecl*, const Stmt*>, 8> Handlers;
+
+ ESelArgs.push_back(Exc);
+ ESelArgs.push_back(Personality);
+
+ bool HasCatchAll = false;
+ // Only @try blocks are allowed @catch blocks, but both can have @finally
+ if (isTry) {
+ if (const ObjCAtCatchStmt* CatchStmt =
+ cast<ObjCAtTryStmt>(S).getCatchStmts()) {
+ CGF.setInvokeDest(CatchInCatch);
+
+ for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
+ const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
+ Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody()));
+
+ // @catch() and @catch(id) both catch any ObjC exception
+ if (!CatchDecl || CGF.getContext().isObjCIdType(CatchDecl->getType())
+ || CatchDecl->getType()->isObjCQualifiedIdType()) {
+ // Use i8* null here to signal this is a catch all, not a cleanup.
+ ESelArgs.push_back(NULLPtr);
+ HasCatchAll = true;
+ // No further catches after this one will ever by reached
+ break;
+ }
+
+ // All other types should be Objective-C interface pointer types.
+ const PointerType *PT = CatchDecl->getType()->getAsPointerType();
+ assert(PT && "Invalid @catch type.");
+ const ObjCInterfaceType *IT =
+ PT->getPointeeType()->getAsObjCInterfaceType();
+ assert(IT && "Invalid @catch type.");
+ llvm::Value *EHType =
+ MakeConstantString(IT->getDecl()->getNameAsString());
+ ESelArgs.push_back(EHType);
+ }
+ }
+ }
+
+ // We use a cleanup unless there was already a catch all.
+ if (!HasCatchAll) {
+ ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0));
+ Handlers.push_back(std::make_pair((const ParmVarDecl*) 0, (const Stmt*) 0));
+ }
+
+ // Find which handler was matched.
+ llvm::Value *ESelector = CGF.Builder.CreateCall(llvm_eh_selector,
+ ESelArgs.begin(), ESelArgs.end(), "selector");
+
+ for (unsigned i = 0, e = Handlers.size(); i != e; ++i) {
+ const ParmVarDecl *CatchParam = Handlers[i].first;
+ const Stmt *CatchBody = Handlers[i].second;
+
+ llvm::BasicBlock *Next = 0;
+
+ // The last handler always matches.
+ if (i + 1 != e) {
+ assert(CatchParam && "Only last handler can be a catch all.");
+
+ // Test whether this block matches the type for the selector and branch
+ // to Match if it does, or to the next BB if it doesn't.
+ llvm::BasicBlock *Match = CGF.createBasicBlock("match");
+ Next = CGF.createBasicBlock("catch.next");
+ llvm::Value *Id = CGF.Builder.CreateCall(llvm_eh_typeid_for,
+ CGF.Builder.CreateBitCast(ESelArgs[i+2], PtrTy));
+ CGF.Builder.CreateCondBr(CGF.Builder.CreateICmpEQ(ESelector, Id), Match,
+ Next);
+
+ CGF.EmitBlock(Match);
+ }
+
+ if (CatchBody) {
+ llvm::Value *ExcObject = CGF.Builder.CreateBitCast(Exc,
+ CGF.ConvertType(CatchParam->getType()));
+
+ // Bind the catch parameter if it exists.
+ if (CatchParam) {
+ // CatchParam is a ParmVarDecl because of the grammar
+ // construction used to handle this, but for codegen purposes
+ // we treat this as a local decl.
+ CGF.EmitLocalBlockVarDecl(*CatchParam);
+ CGF.Builder.CreateStore(ExcObject, CGF.GetAddrOfLocalVar(CatchParam));
+ }
+
+ CGF.ObjCEHValueStack.push_back(ExcObject);
+ CGF.EmitStmt(CatchBody);
+ CGF.ObjCEHValueStack.pop_back();
+
+ CGF.EmitBranchThroughCleanup(FinallyEnd);
+
+ if (Next)
+ CGF.EmitBlock(Next);
+ } else {
+ assert(!Next && "catchup should be last handler.");
+
+ CGF.Builder.CreateStore(Exc, RethrowPtr);
+ CGF.EmitBranchThroughCleanup(FinallyRethrow);
+ }
+ }
+ // The @finally block is a secondary landing pad for any exceptions thrown in
+ // @catch() blocks
+ CGF.EmitBlock(CatchInCatch);
+ Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
+ ESelArgs.clear();
+ ESelArgs.push_back(Exc);
+ ESelArgs.push_back(Personality);
+ ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0));
+ CGF.Builder.CreateCall(llvm_eh_selector, ESelArgs.begin(), ESelArgs.end(),
+ "selector");
+ CGF.Builder.CreateCall(llvm_eh_typeid_for,
+ CGF.Builder.CreateIntToPtr(ESelArgs[2], PtrTy));
+ CGF.Builder.CreateStore(Exc, RethrowPtr);
+ CGF.EmitBranchThroughCleanup(FinallyRethrow);
+
+ CodeGenFunction::CleanupBlockInfo Info = CGF.PopCleanupBlock();
+
+ CGF.setInvokeDest(PrevLandingPad);
+
+ CGF.EmitBlock(FinallyBlock);
+
+
+ if (isTry) {
+ if (const ObjCAtFinallyStmt* FinallyStmt =
+ cast<ObjCAtTryStmt>(S).getFinallyStmt())
+ CGF.EmitStmt(FinallyStmt->getFinallyBody());
+ } else {
+ // Emit 'objc_sync_exit(expr)' as finally's sole statement for
+ // @synchronized.
+ std::vector<const llvm::Type*> Args(1, IdTy);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::VoidTy, Args, false);
+ llvm::Value *SyncExit = CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
+ llvm::Value *SyncArg =
+ CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
+ SyncArg = CGF.Builder.CreateBitCast(SyncArg, IdTy);
+ CGF.Builder.CreateCall(SyncExit, SyncArg);
+ }
+
+ if (Info.SwitchBlock)
+ CGF.EmitBlock(Info.SwitchBlock);
+ if (Info.EndBlock)
+ CGF.EmitBlock(Info.EndBlock);
+
+ // Branch around the rethrow code.
+ CGF.EmitBranch(FinallyEnd);
+
+ CGF.EmitBlock(FinallyRethrow);
+ CGF.Builder.CreateCall(RethrowFn, CGF.Builder.CreateLoad(RethrowPtr));
+ CGF.Builder.CreateUnreachable();
+
+ CGF.EmitBlock(FinallyEnd);
+
+}
+
+void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
+ const ObjCAtThrowStmt &S) {
+ llvm::Value *ExceptionAsObject;
+
+ std::vector<const llvm::Type*> Args(1, IdTy);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::VoidTy, Args, false);
+ llvm::Value *ThrowFn =
+ CGM.CreateRuntimeFunction(FTy, "objc_exception_throw");
+
+ if (const Expr *ThrowExpr = S.getThrowExpr()) {
+ llvm::Value *Exception = CGF.EmitScalarExpr(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");
+
+ // Note: This may have to be an invoke, if we want to support constructs like:
+ // @try {
+ // @throw(obj);
+ // }
+ // @catch(id) ...
+ //
+ // This is effectively turning @throw into an incredibly-expensive goto, but
+ // it may happen as a result of inlining followed by missed optimizations, or
+ // as a result of stupidity.
+ llvm::BasicBlock *UnwindBB = CGF.getInvokeDest();
+ if (!UnwindBB) {
+ CGF.Builder.CreateCall(ThrowFn, ExceptionAsObject);
+ CGF.Builder.CreateUnreachable();
+ } else {
+ CGF.Builder.CreateInvoke(ThrowFn, UnwindBB, UnwindBB, &ExceptionAsObject,
+ &ExceptionAsObject+1);
+ }
+ // Clear the insertion point to indicate we are in unreachable code.
+ CGF.Builder.ClearInsertionPoint();
+}
+
+llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *AddrWeakObj)
+{
+ return 0;
+}
+
+void CGObjCGNU::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst)
+{
+ return;
+}
+
+void CGObjCGNU::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst)
+{
+ return;
+}
+
+void CGObjCGNU::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst)
+{
+ return;
+}
+
+void CGObjCGNU::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst)
+{
+ return;
+}
+
+llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
+ const ObjCInterfaceDecl *ID,
+ const ObjCIvarDecl *Ivar) {
+ const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString()
+ + '.' + Ivar->getNameAsString();
+ // Emit the variable and initialize it with what we think the correct value
+ // is. This allows code compiled with non-fragile ivars to work correctly
+ // when linked against code which isn't (most of the time).
+ llvm::GlobalVariable *IvarOffsetGV = CGM.getModule().getGlobalVariable(Name);
+ if (!IvarOffsetGV) {
+ uint64_t Offset = ComputeIvarBaseOffset(CGM, ID, Ivar);
+ llvm::ConstantInt *OffsetGuess =
+ llvm::ConstantInt::get(LongTy, Offset, "ivar");
+ IvarOffsetGV = new llvm::GlobalVariable(LongTy, false,
+ llvm::GlobalValue::CommonLinkage, OffsetGuess, Name, &TheModule);
+ }
+ return IvarOffsetGV;
+}
+
+LValue CGObjCGNU::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
+ QualType ObjectTy,
+ llvm::Value *BaseValue,
+ const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers) {
+ const ObjCInterfaceDecl *ID = ObjectTy->getAsObjCInterfaceType()->getDecl();
+ return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
+ EmitIvarOffset(CGF, ID, Ivar));
+}
+static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context,
+ const ObjCInterfaceDecl *OID,
+ const ObjCIvarDecl *OIVD) {
+ for (ObjCInterfaceDecl::ivar_iterator IVI = OID->ivar_begin(),
+ IVE = OID->ivar_end(); IVI != IVE; ++IVI)
+ if (OIVD == *IVI)
+ return OID;
+
+ // Also look in synthesized ivars.
+ llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
+ Context.CollectSynthesizedIvars(OID, Ivars);
+ for (unsigned k = 0, e = Ivars.size(); k != e; ++k) {
+ if (OIVD == Ivars[k])
+ return OID;
+ }
+
+ // Otherwise check in the super class.
+ if (const ObjCInterfaceDecl *Super = OID->getSuperClass())
+ return FindIvarInterface(Context, Super, OIVD);
+
+ return 0;
+}
+
+llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *Interface,
+ const ObjCIvarDecl *Ivar) {
+ if (CGF.getContext().getLangOptions().ObjCNonFragileABI)
+ {
+ Interface = FindIvarInterface(CGM.getContext(), Interface, Ivar);
+ return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar),
+ false, "ivar");
+ }
+ uint64_t Offset = ComputeIvarBaseOffset(CGF.CGM, Interface, Ivar);
+ return llvm::ConstantInt::get(LongTy, Offset, "ivar");
+}
+
+CodeGen::CGObjCRuntime *CodeGen::CreateGNUObjCRuntime(CodeGen::CodeGenModule &CGM){
+ return new CGObjCGNU(CGM);
+}
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
new file mode 100644
index 000000000000..8f1404da65dd
--- /dev/null
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -0,0 +1,5780 @@
+//===------- CGObjCMac.cpp - Interface to Apple Objective-C Runtime -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides Objective-C code generation targetting the Apple runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGObjCRuntime.h"
+
+#include "CodeGenModule.h"
+#include "CodeGenFunction.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/Basic/LangOptions.h"
+
+#include "llvm/Intrinsics.h"
+#include "llvm/Module.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Target/TargetData.h"
+#include <sstream>
+
+using namespace clang;
+using namespace CodeGen;
+
+// Common CGObjCRuntime functions, these don't belong here, but they
+// don't belong in CGObjCRuntime either so we will live with it for
+// now.
+
+/// FindIvarInterface - Find the interface containing the ivar.
+///
+/// FIXME: We shouldn't need to do this, the containing context should
+/// be fixed.
+static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context,
+ const ObjCInterfaceDecl *OID,
+ const ObjCIvarDecl *OIVD,
+ unsigned &Index) {
+ // FIXME: The index here is closely tied to how
+ // ASTContext::getObjCLayout is implemented. This should be fixed to
+ // get the information from the layout directly.
+ Index = 0;
+ for (ObjCInterfaceDecl::ivar_iterator IVI = OID->ivar_begin(),
+ IVE = OID->ivar_end(); IVI != IVE; ++IVI, ++Index)
+ if (OIVD == *IVI)
+ return OID;
+
+ // Also look in synthesized ivars.
+ llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
+ Context.CollectSynthesizedIvars(OID, Ivars);
+ for (unsigned k = 0, e = Ivars.size(); k != e; ++k) {
+ if (OIVD == Ivars[k])
+ return OID;
+ ++Index;
+ }
+
+ // Otherwise check in the super class.
+ if (const ObjCInterfaceDecl *Super = OID->getSuperClass())
+ return FindIvarInterface(Context, Super, OIVD, Index);
+
+ return 0;
+}
+
+static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM,
+ const ObjCInterfaceDecl *OID,
+ const ObjCImplementationDecl *ID,
+ const ObjCIvarDecl *Ivar) {
+ unsigned Index;
+ const ObjCInterfaceDecl *Container =
+ FindIvarInterface(CGM.getContext(), OID, Ivar, Index);
+ assert(Container && "Unable to find ivar container");
+
+ // If we know have an implementation (and the ivar is in it) then
+ // look up in the implementation layout.
+ const ASTRecordLayout *RL;
+ if (ID && ID->getClassInterface() == Container)
+ RL = &CGM.getContext().getASTObjCImplementationLayout(ID);
+ else
+ RL = &CGM.getContext().getASTObjCInterfaceLayout(Container);
+ return RL->getFieldOffset(Index);
+}
+
+uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
+ const ObjCInterfaceDecl *OID,
+ const ObjCIvarDecl *Ivar) {
+ return LookupFieldBitOffset(CGM, OID, 0, Ivar) / 8;
+}
+
+uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
+ const ObjCImplementationDecl *OID,
+ const ObjCIvarDecl *Ivar) {
+ return LookupFieldBitOffset(CGM, OID->getClassInterface(), OID, Ivar) / 8;
+}
+
+LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *OID,
+ llvm::Value *BaseValue,
+ const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers,
+ llvm::Value *Offset) {
+ // Compute (type*) ( (char *) BaseValue + Offset)
+ llvm::Type *I8Ptr = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ QualType IvarTy = Ivar->getType();
+ const llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy);
+ llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, I8Ptr);
+ V = CGF.Builder.CreateGEP(V, Offset, "add.ptr");
+ V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy));
+
+ if (Ivar->isBitField()) {
+ // We need to compute the bit offset for the bit-field, the offset
+ // is to the byte. Note, there is a subtle invariant here: we can
+ // only call this routine on non-sythesized ivars but we may be
+ // called for synthesized ivars. However, a synthesized ivar can
+ // never be a bit-field so this is safe.
+ uint64_t BitOffset = LookupFieldBitOffset(CGF.CGM, OID, 0, Ivar) % 8;
+
+ uint64_t BitFieldSize =
+ Ivar->getBitWidth()->EvaluateAsInt(CGF.getContext()).getZExtValue();
+ return LValue::MakeBitfield(V, BitOffset, BitFieldSize,
+ IvarTy->isSignedIntegerType(),
+ IvarTy.getCVRQualifiers()|CVRQualifiers);
+ }
+
+ LValue LV = LValue::MakeAddr(V, IvarTy.getCVRQualifiers()|CVRQualifiers,
+ CGF.CGM.getContext().getObjCGCAttrKind(IvarTy));
+ LValue::SetObjCIvar(LV, true);
+ return LV;
+}
+
+///
+
+namespace {
+
+ typedef std::vector<llvm::Constant*> ConstantVector;
+
+ // FIXME: We should find a nicer way to make the labels for metadata, string
+ // concatenation is lame.
+
+class ObjCCommonTypesHelper {
+private:
+ llvm::Constant *getMessageSendFn() const {
+ // id objc_msgSend (id, SEL, ...)
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(ObjectPtrTy);
+ Params.push_back(SelectorPtrTy);
+ return
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
+ Params, true),
+ "objc_msgSend");
+ }
+
+ llvm::Constant *getMessageSendStretFn() const {
+ // id objc_msgSend_stret (id, SEL, ...)
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(ObjectPtrTy);
+ Params.push_back(SelectorPtrTy);
+ return
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
+ Params, true),
+ "objc_msgSend_stret");
+
+ }
+
+ llvm::Constant *getMessageSendFpretFn() const {
+ // FIXME: This should be long double on x86_64?
+ // [double | long double] objc_msgSend_fpret(id self, SEL op, ...)
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(ObjectPtrTy);
+ Params.push_back(SelectorPtrTy);
+ return
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::DoubleTy,
+ Params,
+ true),
+ "objc_msgSend_fpret");
+
+ }
+
+ llvm::Constant *getMessageSendSuperFn() const {
+ // id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
+ const char *SuperName = "objc_msgSendSuper";
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(SuperPtrTy);
+ Params.push_back(SelectorPtrTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
+ Params, true),
+ SuperName);
+ }
+
+ llvm::Constant *getMessageSendSuperFn2() const {
+ // id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
+ const char *SuperName = "objc_msgSendSuper2";
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(SuperPtrTy);
+ Params.push_back(SelectorPtrTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
+ Params, true),
+ SuperName);
+ }
+
+ llvm::Constant *getMessageSendSuperStretFn() const {
+ // void objc_msgSendSuper_stret(void * stretAddr, struct objc_super *super,
+ // SEL op, ...)
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(Int8PtrTy);
+ Params.push_back(SuperPtrTy);
+ Params.push_back(SelectorPtrTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
+ Params, true),
+ "objc_msgSendSuper_stret");
+ }
+
+ llvm::Constant *getMessageSendSuperStretFn2() const {
+ // void objc_msgSendSuper2_stret(void * stretAddr, struct objc_super *super,
+ // SEL op, ...)
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(Int8PtrTy);
+ Params.push_back(SuperPtrTy);
+ Params.push_back(SelectorPtrTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
+ Params, true),
+ "objc_msgSendSuper2_stret");
+ }
+
+ llvm::Constant *getMessageSendSuperFpretFn() const {
+ // There is no objc_msgSendSuper_fpret? How can that work?
+ return getMessageSendSuperFn();
+ }
+
+ llvm::Constant *getMessageSendSuperFpretFn2() const {
+ // There is no objc_msgSendSuper_fpret? How can that work?
+ return getMessageSendSuperFn2();
+ }
+
+protected:
+ CodeGen::CodeGenModule &CGM;
+
+public:
+ const llvm::Type *ShortTy, *IntTy, *LongTy, *LongLongTy;
+ const llvm::Type *Int8PtrTy;
+
+ /// ObjectPtrTy - LLVM type for object handles (typeof(id))
+ const llvm::Type *ObjectPtrTy;
+
+ /// PtrObjectPtrTy - LLVM type for id *
+ const llvm::Type *PtrObjectPtrTy;
+
+ /// SelectorPtrTy - LLVM type for selector handles (typeof(SEL))
+ const llvm::Type *SelectorPtrTy;
+ /// ProtocolPtrTy - LLVM type for external protocol handles
+ /// (typeof(Protocol))
+ const llvm::Type *ExternalProtocolPtrTy;
+
+ // SuperCTy - clang type for struct objc_super.
+ QualType SuperCTy;
+ // SuperPtrCTy - clang type for struct objc_super *.
+ QualType SuperPtrCTy;
+
+ /// SuperTy - LLVM type for struct objc_super.
+ const llvm::StructType *SuperTy;
+ /// SuperPtrTy - LLVM type for struct objc_super *.
+ const llvm::Type *SuperPtrTy;
+
+ /// PropertyTy - LLVM type for struct objc_property (struct _prop_t
+ /// in GCC parlance).
+ const llvm::StructType *PropertyTy;
+
+ /// PropertyListTy - LLVM type for struct objc_property_list
+ /// (_prop_list_t in GCC parlance).
+ const llvm::StructType *PropertyListTy;
+ /// PropertyListPtrTy - LLVM type for struct objc_property_list*.
+ const llvm::Type *PropertyListPtrTy;
+
+ // MethodTy - LLVM type for struct objc_method.
+ const llvm::StructType *MethodTy;
+
+ /// CacheTy - LLVM type for struct objc_cache.
+ const llvm::Type *CacheTy;
+ /// CachePtrTy - LLVM type for struct objc_cache *.
+ const llvm::Type *CachePtrTy;
+
+ llvm::Constant *getGetPropertyFn() {
+ CodeGen::CodeGenTypes &Types = CGM.getTypes();
+ ASTContext &Ctx = CGM.getContext();
+ // id objc_getProperty (id, SEL, ptrdiff_t, bool)
+ llvm::SmallVector<QualType,16> Params;
+ QualType IdType = Ctx.getObjCIdType();
+ QualType SelType = Ctx.getObjCSelType();
+ Params.push_back(IdType);
+ Params.push_back(SelType);
+ Params.push_back(Ctx.LongTy);
+ Params.push_back(Ctx.BoolTy);
+ const llvm::FunctionType *FTy =
+ Types.GetFunctionType(Types.getFunctionInfo(IdType, Params), false);
+ return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
+ }
+
+ llvm::Constant *getSetPropertyFn() {
+ CodeGen::CodeGenTypes &Types = CGM.getTypes();
+ ASTContext &Ctx = CGM.getContext();
+ // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool)
+ llvm::SmallVector<QualType,16> Params;
+ QualType IdType = Ctx.getObjCIdType();
+ QualType SelType = Ctx.getObjCSelType();
+ Params.push_back(IdType);
+ Params.push_back(SelType);
+ Params.push_back(Ctx.LongTy);
+ Params.push_back(IdType);
+ Params.push_back(Ctx.BoolTy);
+ Params.push_back(Ctx.BoolTy);
+ const llvm::FunctionType *FTy =
+ Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false);
+ return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
+ }
+
+ llvm::Constant *getEnumerationMutationFn() {
+ // void objc_enumerationMutation (id)
+ std::vector<const llvm::Type*> Args;
+ Args.push_back(ObjectPtrTy);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::VoidTy, Args, false);
+ return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
+ }
+
+ /// GcReadWeakFn -- LLVM objc_read_weak (id *src) function.
+ llvm::Constant *getGcReadWeakFn() {
+ // id objc_read_weak (id *)
+ std::vector<const llvm::Type*> Args;
+ Args.push_back(ObjectPtrTy->getPointerTo());
+ llvm::FunctionType *FTy = llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ return CGM.CreateRuntimeFunction(FTy, "objc_read_weak");
+ }
+
+ /// GcAssignWeakFn -- LLVM objc_assign_weak function.
+ llvm::Constant *getGcAssignWeakFn() {
+ // id objc_assign_weak (id, id *)
+ std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
+ Args.push_back(ObjectPtrTy->getPointerTo());
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ return CGM.CreateRuntimeFunction(FTy, "objc_assign_weak");
+ }
+
+ /// GcAssignGlobalFn -- LLVM objc_assign_global function.
+ llvm::Constant *getGcAssignGlobalFn() {
+ // id objc_assign_global(id, id *)
+ std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
+ Args.push_back(ObjectPtrTy->getPointerTo());
+ llvm::FunctionType *FTy = llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ return CGM.CreateRuntimeFunction(FTy, "objc_assign_global");
+ }
+
+ /// GcAssignIvarFn -- LLVM objc_assign_ivar function.
+ llvm::Constant *getGcAssignIvarFn() {
+ // id objc_assign_ivar(id, id *)
+ std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
+ Args.push_back(ObjectPtrTy->getPointerTo());
+ llvm::FunctionType *FTy = llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ return CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar");
+ }
+
+ /// GcAssignStrongCastFn -- LLVM objc_assign_strongCast function.
+ llvm::Constant *getGcAssignStrongCastFn() {
+ // id objc_assign_global(id, id *)
+ std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
+ Args.push_back(ObjectPtrTy->getPointerTo());
+ llvm::FunctionType *FTy = llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ return CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast");
+ }
+
+ /// ExceptionThrowFn - LLVM objc_exception_throw function.
+ llvm::Constant *getExceptionThrowFn() {
+ // void objc_exception_throw(id)
+ std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::VoidTy, Args, false);
+ return CGM.CreateRuntimeFunction(FTy, "objc_exception_throw");
+ }
+
+ /// SyncEnterFn - LLVM object_sync_enter function.
+ llvm::Constant *getSyncEnterFn() {
+ // void objc_sync_enter (id)
+ std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::VoidTy, Args, false);
+ return CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
+ }
+
+ /// SyncExitFn - LLVM object_sync_exit function.
+ llvm::Constant *getSyncExitFn() {
+ // void objc_sync_exit (id)
+ std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::VoidTy, Args, false);
+ return CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
+ }
+
+ llvm::Constant *getSendFn(bool IsSuper) const {
+ return IsSuper ? getMessageSendSuperFn() : getMessageSendFn();
+ }
+
+ llvm::Constant *getSendFn2(bool IsSuper) const {
+ return IsSuper ? getMessageSendSuperFn2() : getMessageSendFn();
+ }
+
+ llvm::Constant *getSendStretFn(bool IsSuper) const {
+ return IsSuper ? getMessageSendSuperStretFn() : getMessageSendStretFn();
+ }
+
+ llvm::Constant *getSendStretFn2(bool IsSuper) const {
+ return IsSuper ? getMessageSendSuperStretFn2() : getMessageSendStretFn();
+ }
+
+ llvm::Constant *getSendFpretFn(bool IsSuper) const {
+ return IsSuper ? getMessageSendSuperFpretFn() : getMessageSendFpretFn();
+ }
+
+ llvm::Constant *getSendFpretFn2(bool IsSuper) const {
+ return IsSuper ? getMessageSendSuperFpretFn2() : getMessageSendFpretFn();
+ }
+
+ ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm);
+ ~ObjCCommonTypesHelper(){}
+};
+
+/// ObjCTypesHelper - Helper class that encapsulates lazy
+/// construction of varies types used during ObjC generation.
+class ObjCTypesHelper : public ObjCCommonTypesHelper {
+public:
+ /// SymtabTy - LLVM type for struct objc_symtab.
+ const llvm::StructType *SymtabTy;
+ /// SymtabPtrTy - LLVM type for struct objc_symtab *.
+ const llvm::Type *SymtabPtrTy;
+ /// ModuleTy - LLVM type for struct objc_module.
+ const llvm::StructType *ModuleTy;
+
+ /// ProtocolTy - LLVM type for struct objc_protocol.
+ const llvm::StructType *ProtocolTy;
+ /// ProtocolPtrTy - LLVM type for struct objc_protocol *.
+ const llvm::Type *ProtocolPtrTy;
+ /// ProtocolExtensionTy - LLVM type for struct
+ /// objc_protocol_extension.
+ const llvm::StructType *ProtocolExtensionTy;
+ /// ProtocolExtensionTy - LLVM type for struct
+ /// objc_protocol_extension *.
+ const llvm::Type *ProtocolExtensionPtrTy;
+ /// MethodDescriptionTy - LLVM type for struct
+ /// objc_method_description.
+ const llvm::StructType *MethodDescriptionTy;
+ /// MethodDescriptionListTy - LLVM type for struct
+ /// objc_method_description_list.
+ const llvm::StructType *MethodDescriptionListTy;
+ /// MethodDescriptionListPtrTy - LLVM type for struct
+ /// objc_method_description_list *.
+ const llvm::Type *MethodDescriptionListPtrTy;
+ /// ProtocolListTy - LLVM type for struct objc_property_list.
+ const llvm::Type *ProtocolListTy;
+ /// ProtocolListPtrTy - LLVM type for struct objc_property_list*.
+ const llvm::Type *ProtocolListPtrTy;
+ /// CategoryTy - LLVM type for struct objc_category.
+ const llvm::StructType *CategoryTy;
+ /// ClassTy - LLVM type for struct objc_class.
+ const llvm::StructType *ClassTy;
+ /// ClassPtrTy - LLVM type for struct objc_class *.
+ const llvm::Type *ClassPtrTy;
+ /// ClassExtensionTy - LLVM type for struct objc_class_ext.
+ const llvm::StructType *ClassExtensionTy;
+ /// ClassExtensionPtrTy - LLVM type for struct objc_class_ext *.
+ const llvm::Type *ClassExtensionPtrTy;
+ // IvarTy - LLVM type for struct objc_ivar.
+ const llvm::StructType *IvarTy;
+ /// IvarListTy - LLVM type for struct objc_ivar_list.
+ const llvm::Type *IvarListTy;
+ /// IvarListPtrTy - LLVM type for struct objc_ivar_list *.
+ const llvm::Type *IvarListPtrTy;
+ /// MethodListTy - LLVM type for struct objc_method_list.
+ const llvm::Type *MethodListTy;
+ /// MethodListPtrTy - LLVM type for struct objc_method_list *.
+ const llvm::Type *MethodListPtrTy;
+
+ /// ExceptionDataTy - LLVM type for struct _objc_exception_data.
+ const llvm::Type *ExceptionDataTy;
+
+ /// ExceptionTryEnterFn - LLVM objc_exception_try_enter function.
+ llvm::Constant *getExceptionTryEnterFn() {
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(llvm::PointerType::getUnqual(ExceptionDataTy));
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
+ Params, false),
+ "objc_exception_try_enter");
+ }
+
+ /// ExceptionTryExitFn - LLVM objc_exception_try_exit function.
+ llvm::Constant *getExceptionTryExitFn() {
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(llvm::PointerType::getUnqual(ExceptionDataTy));
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
+ Params, false),
+ "objc_exception_try_exit");
+ }
+
+ /// ExceptionExtractFn - LLVM objc_exception_extract function.
+ llvm::Constant *getExceptionExtractFn() {
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(llvm::PointerType::getUnqual(ExceptionDataTy));
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
+ Params, false),
+ "objc_exception_extract");
+
+ }
+
+ /// ExceptionMatchFn - LLVM objc_exception_match function.
+ llvm::Constant *getExceptionMatchFn() {
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(ClassPtrTy);
+ Params.push_back(ObjectPtrTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::Int32Ty,
+ Params, false),
+ "objc_exception_match");
+
+ }
+
+ /// SetJmpFn - LLVM _setjmp function.
+ llvm::Constant *getSetJmpFn() {
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(llvm::PointerType::getUnqual(llvm::Type::Int32Ty));
+ return
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::Int32Ty,
+ Params, false),
+ "_setjmp");
+
+ }
+
+public:
+ ObjCTypesHelper(CodeGen::CodeGenModule &cgm);
+ ~ObjCTypesHelper() {}
+};
+
+/// ObjCNonFragileABITypesHelper - will have all types needed by objective-c's
+/// modern abi
+class ObjCNonFragileABITypesHelper : public ObjCCommonTypesHelper {
+public:
+
+ // MethodListnfABITy - LLVM for struct _method_list_t
+ const llvm::StructType *MethodListnfABITy;
+
+ // MethodListnfABIPtrTy - LLVM for struct _method_list_t*
+ const llvm::Type *MethodListnfABIPtrTy;
+
+ // ProtocolnfABITy = LLVM for struct _protocol_t
+ const llvm::StructType *ProtocolnfABITy;
+
+ // ProtocolnfABIPtrTy = LLVM for struct _protocol_t*
+ const llvm::Type *ProtocolnfABIPtrTy;
+
+ // ProtocolListnfABITy - LLVM for struct _objc_protocol_list
+ const llvm::StructType *ProtocolListnfABITy;
+
+ // ProtocolListnfABIPtrTy - LLVM for struct _objc_protocol_list*
+ const llvm::Type *ProtocolListnfABIPtrTy;
+
+ // ClassnfABITy - LLVM for struct _class_t
+ const llvm::StructType *ClassnfABITy;
+
+ // ClassnfABIPtrTy - LLVM for struct _class_t*
+ const llvm::Type *ClassnfABIPtrTy;
+
+ // IvarnfABITy - LLVM for struct _ivar_t
+ const llvm::StructType *IvarnfABITy;
+
+ // IvarListnfABITy - LLVM for struct _ivar_list_t
+ const llvm::StructType *IvarListnfABITy;
+
+ // IvarListnfABIPtrTy = LLVM for struct _ivar_list_t*
+ const llvm::Type *IvarListnfABIPtrTy;
+
+ // ClassRonfABITy - LLVM for struct _class_ro_t
+ const llvm::StructType *ClassRonfABITy;
+
+ // ImpnfABITy - LLVM for id (*)(id, SEL, ...)
+ const llvm::Type *ImpnfABITy;
+
+ // CategorynfABITy - LLVM for struct _category_t
+ const llvm::StructType *CategorynfABITy;
+
+ // New types for nonfragile abi messaging.
+
+ // MessageRefTy - LLVM for:
+ // struct _message_ref_t {
+ // IMP messenger;
+ // SEL name;
+ // };
+ const llvm::StructType *MessageRefTy;
+ // MessageRefCTy - clang type for struct _message_ref_t
+ QualType MessageRefCTy;
+
+ // MessageRefPtrTy - LLVM for struct _message_ref_t*
+ const llvm::Type *MessageRefPtrTy;
+ // MessageRefCPtrTy - clang type for struct _message_ref_t*
+ QualType MessageRefCPtrTy;
+
+ // MessengerTy - Type of the messenger (shown as IMP above)
+ const llvm::FunctionType *MessengerTy;
+
+ // SuperMessageRefTy - LLVM for:
+ // struct _super_message_ref_t {
+ // SUPER_IMP messenger;
+ // SEL name;
+ // };
+ const llvm::StructType *SuperMessageRefTy;
+
+ // SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
+ const llvm::Type *SuperMessageRefPtrTy;
+
+ llvm::Constant *getMessageSendFixupFn() {
+ // id objc_msgSend_fixup(id, struct message_ref_t*, ...)
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(ObjectPtrTy);
+ Params.push_back(MessageRefPtrTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
+ Params, true),
+ "objc_msgSend_fixup");
+ }
+
+ llvm::Constant *getMessageSendFpretFixupFn() {
+ // id objc_msgSend_fpret_fixup(id, struct message_ref_t*, ...)
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(ObjectPtrTy);
+ Params.push_back(MessageRefPtrTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
+ Params, true),
+ "objc_msgSend_fpret_fixup");
+ }
+
+ llvm::Constant *getMessageSendStretFixupFn() {
+ // id objc_msgSend_stret_fixup(id, struct message_ref_t*, ...)
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(ObjectPtrTy);
+ Params.push_back(MessageRefPtrTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
+ Params, true),
+ "objc_msgSend_stret_fixup");
+ }
+
+ llvm::Constant *getMessageSendIdFixupFn() {
+ // id objc_msgSendId_fixup(id, struct message_ref_t*, ...)
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(ObjectPtrTy);
+ Params.push_back(MessageRefPtrTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
+ Params, true),
+ "objc_msgSendId_fixup");
+ }
+
+ llvm::Constant *getMessageSendIdStretFixupFn() {
+ // id objc_msgSendId_stret_fixup(id, struct message_ref_t*, ...)
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(ObjectPtrTy);
+ Params.push_back(MessageRefPtrTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
+ Params, true),
+ "objc_msgSendId_stret_fixup");
+ }
+ llvm::Constant *getMessageSendSuper2FixupFn() {
+ // id objc_msgSendSuper2_fixup (struct objc_super *,
+ // struct _super_message_ref_t*, ...)
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(SuperPtrTy);
+ Params.push_back(SuperMessageRefPtrTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
+ Params, true),
+ "objc_msgSendSuper2_fixup");
+ }
+
+ llvm::Constant *getMessageSendSuper2StretFixupFn() {
+ // id objc_msgSendSuper2_stret_fixup(struct objc_super *,
+ // struct _super_message_ref_t*, ...)
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(SuperPtrTy);
+ Params.push_back(SuperMessageRefPtrTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
+ Params, true),
+ "objc_msgSendSuper2_stret_fixup");
+ }
+
+
+
+ /// EHPersonalityPtr - LLVM value for an i8* to the Objective-C
+ /// exception personality function.
+ llvm::Value *getEHPersonalityPtr() {
+ llvm::Constant *Personality =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::Int32Ty,
+ std::vector<const llvm::Type*>(),
+ true),
+ "__objc_personality_v0");
+ return llvm::ConstantExpr::getBitCast(Personality, Int8PtrTy);
+ }
+
+ llvm::Constant *getUnwindResumeOrRethrowFn() {
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(Int8PtrTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
+ Params, false),
+ "_Unwind_Resume_or_Rethrow");
+ }
+
+ llvm::Constant *getObjCEndCatchFn() {
+ std::vector<const llvm::Type*> Params;
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
+ Params, false),
+ "objc_end_catch");
+
+ }
+
+ llvm::Constant *getObjCBeginCatchFn() {
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(Int8PtrTy);
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(Int8PtrTy,
+ Params, false),
+ "objc_begin_catch");
+ }
+
+ const llvm::StructType *EHTypeTy;
+ const llvm::Type *EHTypePtrTy;
+
+ ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm);
+ ~ObjCNonFragileABITypesHelper(){}
+};
+
+class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
+public:
+ // FIXME - accessibility
+ class GC_IVAR {
+ public:
+ unsigned ivar_bytepos;
+ unsigned ivar_size;
+ GC_IVAR(unsigned bytepos = 0, unsigned size = 0)
+ : ivar_bytepos(bytepos), ivar_size(size) {}
+
+ // Allow sorting based on byte pos.
+ bool operator<(const GC_IVAR &b) const {
+ return ivar_bytepos < b.ivar_bytepos;
+ }
+ };
+
+ class SKIP_SCAN {
+ public:
+ unsigned skip;
+ unsigned scan;
+ SKIP_SCAN(unsigned _skip = 0, unsigned _scan = 0)
+ : skip(_skip), scan(_scan) {}
+ };
+
+protected:
+ CodeGen::CodeGenModule &CGM;
+ // FIXME! May not be needing this after all.
+ unsigned ObjCABI;
+
+ // gc ivar layout bitmap calculation helper caches.
+ llvm::SmallVector<GC_IVAR, 16> SkipIvars;
+ llvm::SmallVector<GC_IVAR, 16> IvarsInfo;
+
+ /// LazySymbols - Symbols to generate a lazy reference for. See
+ /// DefinedSymbols and FinishModule().
+ std::set<IdentifierInfo*> LazySymbols;
+
+ /// DefinedSymbols - External symbols which are defined by this
+ /// module. The symbols in this list and LazySymbols are used to add
+ /// special linker symbols which ensure that Objective-C modules are
+ /// linked properly.
+ std::set<IdentifierInfo*> DefinedSymbols;
+
+ /// ClassNames - uniqued class names.
+ llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> ClassNames;
+
+ /// MethodVarNames - uniqued method variable names.
+ llvm::DenseMap<Selector, llvm::GlobalVariable*> MethodVarNames;
+
+ /// MethodVarTypes - uniqued method type signatures. We have to use
+ /// a StringMap here because have no other unique reference.
+ llvm::StringMap<llvm::GlobalVariable*> MethodVarTypes;
+
+ /// MethodDefinitions - map of methods which have been defined in
+ /// this translation unit.
+ llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> MethodDefinitions;
+
+ /// PropertyNames - uniqued method variable names.
+ llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> PropertyNames;
+
+ /// ClassReferences - uniqued class references.
+ llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> ClassReferences;
+
+ /// SelectorReferences - uniqued selector references.
+ llvm::DenseMap<Selector, llvm::GlobalVariable*> SelectorReferences;
+
+ /// Protocols - Protocols for which an objc_protocol structure has
+ /// been emitted. Forward declarations are handled by creating an
+ /// empty structure whose initializer is filled in when/if defined.
+ llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> Protocols;
+
+ /// DefinedProtocols - Protocols which have actually been
+ /// defined. We should not need this, see FIXME in GenerateProtocol.
+ llvm::DenseSet<IdentifierInfo*> DefinedProtocols;
+
+ /// DefinedClasses - List of defined classes.
+ std::vector<llvm::GlobalValue*> DefinedClasses;
+
+ /// DefinedNonLazyClasses - List of defined "non-lazy" classes.
+ std::vector<llvm::GlobalValue*> DefinedNonLazyClasses;
+
+ /// DefinedCategories - List of defined categories.
+ std::vector<llvm::GlobalValue*> DefinedCategories;
+
+ /// DefinedNonLazyCategories - List of defined "non-lazy" categories.
+ std::vector<llvm::GlobalValue*> DefinedNonLazyCategories;
+
+ /// UsedGlobals - List of globals to pack into the llvm.used metadata
+ /// to prevent them from being clobbered.
+ std::vector<llvm::GlobalVariable*> UsedGlobals;
+
+ /// GetNameForMethod - Return a name for the given method.
+ /// \param[out] NameOut - The return value.
+ void GetNameForMethod(const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD,
+ std::string &NameOut);
+
+ /// GetMethodVarName - Return a unique constant for the given
+ /// selector's name. The return value has type char *.
+ llvm::Constant *GetMethodVarName(Selector Sel);
+ llvm::Constant *GetMethodVarName(IdentifierInfo *Ident);
+ llvm::Constant *GetMethodVarName(const std::string &Name);
+
+ /// GetMethodVarType - Return a unique constant for the given
+ /// selector's name. The return value has type char *.
+
+ // FIXME: This is a horrible name.
+ llvm::Constant *GetMethodVarType(const ObjCMethodDecl *D);
+ llvm::Constant *GetMethodVarType(const FieldDecl *D);
+
+ /// GetPropertyName - Return a unique constant for the given
+ /// name. The return value has type char *.
+ llvm::Constant *GetPropertyName(IdentifierInfo *Ident);
+
+ // FIXME: This can be dropped once string functions are unified.
+ llvm::Constant *GetPropertyTypeString(const ObjCPropertyDecl *PD,
+ const Decl *Container);
+
+ /// GetClassName - Return a unique constant for the given selector's
+ /// name. The return value has type char *.
+ llvm::Constant *GetClassName(IdentifierInfo *Ident);
+
+ /// BuildIvarLayout - Builds ivar layout bitmap for the class
+ /// implementation for the __strong or __weak case.
+ ///
+ llvm::Constant *BuildIvarLayout(const ObjCImplementationDecl *OI,
+ bool ForStrongLayout);
+
+ void BuildAggrIvarRecordLayout(const RecordType *RT,
+ unsigned int BytePos, bool ForStrongLayout,
+ bool &HasUnion);
+ void BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
+ const llvm::StructLayout *Layout,
+ const RecordDecl *RD,
+ const llvm::SmallVectorImpl<FieldDecl*> &RecFields,
+ unsigned int BytePos, bool ForStrongLayout,
+ bool &HasUnion);
+
+ /// GetIvarLayoutName - Returns a unique constant for the given
+ /// ivar layout bitmap.
+ llvm::Constant *GetIvarLayoutName(IdentifierInfo *Ident,
+ const ObjCCommonTypesHelper &ObjCTypes);
+
+ /// EmitPropertyList - Emit the given property list. The return
+ /// value has type PropertyListPtrTy.
+ llvm::Constant *EmitPropertyList(const std::string &Name,
+ const Decl *Container,
+ const ObjCContainerDecl *OCD,
+ const ObjCCommonTypesHelper &ObjCTypes);
+
+ /// GetProtocolRef - Return a reference to the internal protocol
+ /// description, creating an empty one if it has not been
+ /// defined. The return value has type ProtocolPtrTy.
+ llvm::Constant *GetProtocolRef(const ObjCProtocolDecl *PD);
+
+ /// CreateMetadataVar - Create a global variable with internal
+ /// linkage for use by the Objective-C runtime.
+ ///
+ /// This is a convenience wrapper which not only creates the
+ /// variable, but also sets the section and alignment and adds the
+ /// global to the UsedGlobals list.
+ ///
+ /// \param Name - The variable name.
+ /// \param Init - The variable initializer; this is also used to
+ /// define the type of the variable.
+ /// \param Section - The section the variable should go into, or 0.
+ /// \param Align - The alignment for the variable, or 0.
+ /// \param AddToUsed - Whether the variable should be added to
+ /// "llvm.used".
+ llvm::GlobalVariable *CreateMetadataVar(const std::string &Name,
+ llvm::Constant *Init,
+ const char *Section,
+ unsigned Align,
+ bool AddToUsed);
+
+ /// GetNamedIvarList - Return the list of ivars in the interface
+ /// itself (not including super classes and not including unnamed
+ /// bitfields).
+ ///
+ /// For the non-fragile ABI, this also includes synthesized property
+ /// ivars.
+ void GetNamedIvarList(const ObjCInterfaceDecl *OID,
+ llvm::SmallVector<ObjCIvarDecl*, 16> &Res) const;
+
+ CodeGen::RValue EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ llvm::Value *Sel,
+ llvm::Value *Arg0,
+ QualType Arg0Ty,
+ bool IsSuper,
+ const CallArgList &CallArgs,
+ const ObjCCommonTypesHelper &ObjCTypes);
+
+public:
+ CGObjCCommonMac(CodeGen::CodeGenModule &cgm) : CGM(cgm)
+ { }
+
+ virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *SL);
+
+ virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD=0);
+
+ virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
+
+ /// GetOrEmitProtocol - Get the protocol object for the given
+ /// declaration, emitting it if necessary. The return value has type
+ /// ProtocolPtrTy.
+ virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD)=0;
+
+ /// GetOrEmitProtocolRef - Get a forward reference to the protocol
+ /// object for the given declaration, emitting it if needed. These
+ /// forward references will be filled in with empty bodies if no
+ /// definition is seen. The return value has type ProtocolPtrTy.
+ virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0;
+};
+
+class CGObjCMac : public CGObjCCommonMac {
+private:
+ ObjCTypesHelper ObjCTypes;
+ /// EmitImageInfo - Emit the image info marker used to encode some module
+ /// level information.
+ void EmitImageInfo();
+
+ /// EmitModuleInfo - Another marker encoding module level
+ /// information.
+ void EmitModuleInfo();
+
+ /// EmitModuleSymols - Emit module symbols, the list of defined
+ /// classes and categories. The result has type SymtabPtrTy.
+ llvm::Constant *EmitModuleSymbols();
+
+ /// FinishModule - Write out global data structures at the end of
+ /// processing a translation unit.
+ void FinishModule();
+
+ /// EmitClassExtension - Generate the class extension structure used
+ /// to store the weak ivar layout and properties. The return value
+ /// has type ClassExtensionPtrTy.
+ llvm::Constant *EmitClassExtension(const ObjCImplementationDecl *ID);
+
+ /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
+ /// for the given class.
+ llvm::Value *EmitClassRef(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *ID);
+
+ CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ llvm::Value *Arg0,
+ QualType Arg0Ty,
+ bool IsSuper,
+ const CallArgList &CallArgs);
+
+ /// EmitIvarList - Emit the ivar list for the given
+ /// implementation. If ForClass is true the list of class ivars
+ /// (i.e. metaclass ivars) is emitted, otherwise the list of
+ /// interface ivars will be emitted. The return value has type
+ /// IvarListPtrTy.
+ llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID,
+ bool ForClass);
+
+ /// EmitMetaClass - Emit a forward reference to the class structure
+ /// for the metaclass of the given interface. The return value has
+ /// type ClassPtrTy.
+ llvm::Constant *EmitMetaClassRef(const ObjCInterfaceDecl *ID);
+
+ /// EmitMetaClass - Emit a class structure for the metaclass of the
+ /// given implementation. The return value has type ClassPtrTy.
+ llvm::Constant *EmitMetaClass(const ObjCImplementationDecl *ID,
+ llvm::Constant *Protocols,
+ const ConstantVector &Methods);
+
+ llvm::Constant *GetMethodConstant(const ObjCMethodDecl *MD);
+
+ llvm::Constant *GetMethodDescriptionConstant(const ObjCMethodDecl *MD);
+
+ /// EmitMethodList - Emit the method list for the given
+ /// implementation. The return value has type MethodListPtrTy.
+ llvm::Constant *EmitMethodList(const std::string &Name,
+ const char *Section,
+ const ConstantVector &Methods);
+
+ /// EmitMethodDescList - Emit a method description list for a list of
+ /// method declarations.
+ /// - TypeName: The name for the type containing the methods.
+ /// - IsProtocol: True iff these methods are for a protocol.
+ /// - ClassMethds: True iff these are class methods.
+ /// - Required: When true, only "required" methods are
+ /// listed. Similarly, when false only "optional" methods are
+ /// listed. For classes this should always be true.
+ /// - begin, end: The method list to output.
+ ///
+ /// The return value has type MethodDescriptionListPtrTy.
+ llvm::Constant *EmitMethodDescList(const std::string &Name,
+ const char *Section,
+ const ConstantVector &Methods);
+
+ /// GetOrEmitProtocol - Get the protocol object for the given
+ /// declaration, emitting it if necessary. The return value has type
+ /// ProtocolPtrTy.
+ virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD);
+
+ /// GetOrEmitProtocolRef - Get a forward reference to the protocol
+ /// object for the given declaration, emitting it if needed. These
+ /// forward references will be filled in with empty bodies if no
+ /// definition is seen. The return value has type ProtocolPtrTy.
+ virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD);
+
+ /// EmitProtocolExtension - Generate the protocol extension
+ /// structure used to store optional instance and class methods, and
+ /// protocol properties. The return value has type
+ /// ProtocolExtensionPtrTy.
+ llvm::Constant *
+ EmitProtocolExtension(const ObjCProtocolDecl *PD,
+ const ConstantVector &OptInstanceMethods,
+ const ConstantVector &OptClassMethods);
+
+ /// EmitProtocolList - Generate the list of referenced
+ /// protocols. The return value has type ProtocolListPtrTy.
+ llvm::Constant *EmitProtocolList(const std::string &Name,
+ ObjCProtocolDecl::protocol_iterator begin,
+ ObjCProtocolDecl::protocol_iterator end);
+
+ /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
+ /// for the given selector.
+ llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel);
+
+ public:
+ CGObjCMac(CodeGen::CodeGenModule &cgm);
+
+ virtual llvm::Function *ModuleInitFunction();
+
+ virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ llvm::Value *Receiver,
+ bool IsClassMessage,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method);
+
+ virtual CodeGen::RValue
+ GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ const ObjCInterfaceDecl *Class,
+ bool isCategoryImpl,
+ llvm::Value *Receiver,
+ bool IsClassMessage,
+ const CallArgList &CallArgs);
+
+ virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *ID);
+
+ virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel);
+
+ /// The NeXT/Apple runtimes do not support typed selectors; just emit an
+ /// untyped one.
+ virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ const ObjCMethodDecl *Method);
+
+ virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
+
+ virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
+
+ virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ const ObjCProtocolDecl *PD);
+
+ virtual llvm::Constant *GetPropertyGetFunction();
+ virtual llvm::Constant *GetPropertySetFunction();
+ virtual llvm::Constant *EnumerationMutationFunction();
+
+ virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
+ const Stmt &S);
+ virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
+ const ObjCAtThrowStmt &S);
+ virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *AddrWeakObj);
+ virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst);
+ virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest);
+ virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest);
+ virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest);
+
+ virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
+ QualType ObjectTy,
+ llvm::Value *BaseValue,
+ const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers);
+ virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *Interface,
+ const ObjCIvarDecl *Ivar);
+};
+
+class CGObjCNonFragileABIMac : public CGObjCCommonMac {
+private:
+ ObjCNonFragileABITypesHelper ObjCTypes;
+ llvm::GlobalVariable* ObjCEmptyCacheVar;
+ llvm::GlobalVariable* ObjCEmptyVtableVar;
+
+ /// SuperClassReferences - uniqued super class references.
+ llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> SuperClassReferences;
+
+ /// MetaClassReferences - uniqued meta class references.
+ llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> MetaClassReferences;
+
+ /// EHTypeReferences - uniqued class ehtype references.
+ llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> EHTypeReferences;
+
+ /// NonLegacyDispatchMethods - List of methods for which we do *not* generate
+ /// legacy messaging dispatch.
+ llvm::DenseSet<Selector> NonLegacyDispatchMethods;
+
+ /// LegacyDispatchedSelector - Returns true if SEL is not in the list of
+ /// NonLegacyDispatchMethods; false otherwise.
+ bool LegacyDispatchedSelector(Selector Sel);
+
+ /// FinishNonFragileABIModule - Write out global data structures at the end of
+ /// processing a translation unit.
+ void FinishNonFragileABIModule();
+
+ /// AddModuleClassList - Add the given list of class pointers to the
+ /// module with the provided symbol and section names.
+ void AddModuleClassList(const std::vector<llvm::GlobalValue*> &Container,
+ const char *SymbolName,
+ const char *SectionName);
+
+ llvm::GlobalVariable * BuildClassRoTInitializer(unsigned flags,
+ unsigned InstanceStart,
+ unsigned InstanceSize,
+ const ObjCImplementationDecl *ID);
+ llvm::GlobalVariable * BuildClassMetaData(std::string &ClassName,
+ llvm::Constant *IsAGV,
+ llvm::Constant *SuperClassGV,
+ llvm::Constant *ClassRoGV,
+ bool HiddenVisibility);
+
+ llvm::Constant *GetMethodConstant(const ObjCMethodDecl *MD);
+
+ llvm::Constant *GetMethodDescriptionConstant(const ObjCMethodDecl *MD);
+
+ /// EmitMethodList - Emit the method list for the given
+ /// implementation. The return value has type MethodListnfABITy.
+ llvm::Constant *EmitMethodList(const std::string &Name,
+ const char *Section,
+ const ConstantVector &Methods);
+ /// EmitIvarList - Emit the ivar list for the given
+ /// implementation. If ForClass is true the list of class ivars
+ /// (i.e. metaclass ivars) is emitted, otherwise the list of
+ /// interface ivars will be emitted. The return value has type
+ /// IvarListnfABIPtrTy.
+ llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID);
+
+ llvm::Constant *EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
+ const ObjCIvarDecl *Ivar,
+ unsigned long int offset);
+
+ /// GetOrEmitProtocol - Get the protocol object for the given
+ /// declaration, emitting it if necessary. The return value has type
+ /// ProtocolPtrTy.
+ virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD);
+
+ /// GetOrEmitProtocolRef - Get a forward reference to the protocol
+ /// object for the given declaration, emitting it if needed. These
+ /// forward references will be filled in with empty bodies if no
+ /// definition is seen. The return value has type ProtocolPtrTy.
+ virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD);
+
+ /// EmitProtocolList - Generate the list of referenced
+ /// protocols. The return value has type ProtocolListPtrTy.
+ llvm::Constant *EmitProtocolList(const std::string &Name,
+ ObjCProtocolDecl::protocol_iterator begin,
+ ObjCProtocolDecl::protocol_iterator end);
+
+ CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ llvm::Value *Receiver,
+ QualType Arg0Ty,
+ bool IsSuper,
+ const CallArgList &CallArgs);
+
+ /// GetClassGlobal - Return the global variable for the Objective-C
+ /// class of the given name.
+ llvm::GlobalVariable *GetClassGlobal(const std::string &Name);
+
+ /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
+ /// for the given class reference.
+ llvm::Value *EmitClassRef(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *ID);
+
+ /// EmitSuperClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
+ /// for the given super class reference.
+ llvm::Value *EmitSuperClassRef(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *ID);
+
+ /// EmitMetaClassRef - Return a Value * of the address of _class_t
+ /// meta-data
+ llvm::Value *EmitMetaClassRef(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *ID);
+
+ /// ObjCIvarOffsetVariable - Returns the ivar offset variable for
+ /// the given ivar.
+ ///
+ llvm::GlobalVariable * ObjCIvarOffsetVariable(
+ const ObjCInterfaceDecl *ID,
+ const ObjCIvarDecl *Ivar);
+
+ /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
+ /// for the given selector.
+ llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel);
+
+ /// GetInterfaceEHType - Get the cached ehtype for the given Objective-C
+ /// interface. The return value has type EHTypePtrTy.
+ llvm::Value *GetInterfaceEHType(const ObjCInterfaceDecl *ID,
+ bool ForDefinition);
+
+ const char *getMetaclassSymbolPrefix() const {
+ return "OBJC_METACLASS_$_";
+ }
+
+ const char *getClassSymbolPrefix() const {
+ return "OBJC_CLASS_$_";
+ }
+
+ void GetClassSizeInfo(const ObjCImplementationDecl *OID,
+ uint32_t &InstanceStart,
+ uint32_t &InstanceSize);
+
+ // Shamelessly stolen from Analysis/CFRefCount.cpp
+ Selector GetNullarySelector(const char* name) const {
+ IdentifierInfo* II = &CGM.getContext().Idents.get(name);
+ return CGM.getContext().Selectors.getSelector(0, &II);
+ }
+
+ Selector GetUnarySelector(const char* name) const {
+ IdentifierInfo* II = &CGM.getContext().Idents.get(name);
+ return CGM.getContext().Selectors.getSelector(1, &II);
+ }
+
+ /// ImplementationIsNonLazy - Check whether the given category or
+ /// class implementation is "non-lazy".
+ bool ImplementationIsNonLazy(const ObjCImplDecl *OD) const;
+
+public:
+ CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm);
+ // FIXME. All stubs for now!
+ virtual llvm::Function *ModuleInitFunction();
+
+ virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ llvm::Value *Receiver,
+ bool IsClassMessage,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method);
+
+ virtual CodeGen::RValue
+ GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ const ObjCInterfaceDecl *Class,
+ bool isCategoryImpl,
+ llvm::Value *Receiver,
+ bool IsClassMessage,
+ const CallArgList &CallArgs);
+
+ virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *ID);
+
+ virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel)
+ { return EmitSelector(Builder, Sel); }
+
+ /// The NeXT/Apple runtimes do not support typed selectors; just emit an
+ /// untyped one.
+ virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ const ObjCMethodDecl *Method)
+ { return EmitSelector(Builder, Method->getSelector()); }
+
+ virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
+
+ virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
+ virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ const ObjCProtocolDecl *PD);
+
+ virtual llvm::Constant *GetPropertyGetFunction() {
+ return ObjCTypes.getGetPropertyFn();
+ }
+ virtual llvm::Constant *GetPropertySetFunction() {
+ return ObjCTypes.getSetPropertyFn();
+ }
+ virtual llvm::Constant *EnumerationMutationFunction() {
+ return ObjCTypes.getEnumerationMutationFn();
+ }
+
+ virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
+ const Stmt &S);
+ virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
+ const ObjCAtThrowStmt &S);
+ virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *AddrWeakObj);
+ virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst);
+ virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest);
+ virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest);
+ virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest);
+ virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
+ QualType ObjectTy,
+ llvm::Value *BaseValue,
+ const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers);
+ virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *Interface,
+ const ObjCIvarDecl *Ivar);
+};
+
+} // end anonymous namespace
+
+/* *** Helper Functions *** */
+
+/// getConstantGEP() - Help routine to construct simple GEPs.
+static llvm::Constant *getConstantGEP(llvm::Constant *C,
+ unsigned idx0,
+ unsigned idx1) {
+ llvm::Value *Idxs[] = {
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, idx0),
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, idx1)
+ };
+ return llvm::ConstantExpr::getGetElementPtr(C, Idxs, 2);
+}
+
+/// hasObjCExceptionAttribute - Return true if this class or any super
+/// class has the __objc_exception__ attribute.
+static bool hasObjCExceptionAttribute(const ObjCInterfaceDecl *OID) {
+ if (OID->hasAttr<ObjCExceptionAttr>())
+ return true;
+ if (const ObjCInterfaceDecl *Super = OID->getSuperClass())
+ return hasObjCExceptionAttribute(Super);
+ return false;
+}
+
+/* *** CGObjCMac Public Interface *** */
+
+CGObjCMac::CGObjCMac(CodeGen::CodeGenModule &cgm) : CGObjCCommonMac(cgm),
+ ObjCTypes(cgm)
+{
+ ObjCABI = 1;
+ EmitImageInfo();
+}
+
+/// GetClass - Return a reference to the class for the given interface
+/// decl.
+llvm::Value *CGObjCMac::GetClass(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *ID) {
+ return EmitClassRef(Builder, ID);
+}
+
+/// GetSelector - Return the pointer to the unique'd string for this selector.
+llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, Selector Sel) {
+ return EmitSelector(Builder, Sel);
+}
+llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
+ *Method) {
+ return EmitSelector(Builder, Method->getSelector());
+}
+
+/// Generate a constant CFString object.
+/*
+ struct __builtin_CFString {
+ const int *isa; // point to __CFConstantStringClassReference
+ int flags;
+ const char *str;
+ long length;
+ };
+*/
+
+llvm::Constant *CGObjCCommonMac::GenerateConstantString(
+ const ObjCStringLiteral *SL) {
+ return CGM.GetAddrOfConstantCFString(SL->getString());
+}
+
+/// Generates a message send where the super is the receiver. This is
+/// a message send to self with special delivery semantics indicating
+/// which class's method should be called.
+CodeGen::RValue
+CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ const ObjCInterfaceDecl *Class,
+ bool isCategoryImpl,
+ llvm::Value *Receiver,
+ bool IsClassMessage,
+ const CodeGen::CallArgList &CallArgs) {
+ // Create and init a super structure; this is a (receiver, class)
+ // pair we will pass to objc_msgSendSuper.
+ llvm::Value *ObjCSuper =
+ CGF.Builder.CreateAlloca(ObjCTypes.SuperTy, 0, "objc_super");
+ llvm::Value *ReceiverAsObject =
+ CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
+ CGF.Builder.CreateStore(ReceiverAsObject,
+ CGF.Builder.CreateStructGEP(ObjCSuper, 0));
+
+ // If this is a class message the metaclass is passed as the target.
+ llvm::Value *Target;
+ if (IsClassMessage) {
+ if (isCategoryImpl) {
+ // Message sent to 'super' in a class method defined in a category
+ // implementation requires an odd treatment.
+ // If we are in a class method, we must retrieve the
+ // _metaclass_ for the current class, pointed at by
+ // the class's "isa" pointer. The following assumes that
+ // isa" is the first ivar in a class (which it must be).
+ Target = EmitClassRef(CGF.Builder, Class->getSuperClass());
+ Target = CGF.Builder.CreateStructGEP(Target, 0);
+ Target = CGF.Builder.CreateLoad(Target);
+ }
+ else {
+ llvm::Value *MetaClassPtr = EmitMetaClassRef(Class);
+ llvm::Value *SuperPtr = CGF.Builder.CreateStructGEP(MetaClassPtr, 1);
+ llvm::Value *Super = CGF.Builder.CreateLoad(SuperPtr);
+ Target = Super;
+ }
+ } else {
+ Target = EmitClassRef(CGF.Builder, Class->getSuperClass());
+ }
+ // FIXME: We shouldn't need to do this cast, rectify the ASTContext and
+ // ObjCTypes types.
+ const llvm::Type *ClassTy =
+ CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
+ Target = CGF.Builder.CreateBitCast(Target, ClassTy);
+ CGF.Builder.CreateStore(Target,
+ CGF.Builder.CreateStructGEP(ObjCSuper, 1));
+ return EmitLegacyMessageSend(CGF, ResultType,
+ EmitSelector(CGF.Builder, Sel),
+ ObjCSuper, ObjCTypes.SuperPtrCTy,
+ true, CallArgs, ObjCTypes);
+}
+
+/// Generate code for a message send expression.
+CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ llvm::Value *Receiver,
+ bool IsClassMessage,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method) {
+ return EmitLegacyMessageSend(CGF, ResultType,
+ EmitSelector(CGF.Builder, Sel),
+ Receiver, CGF.getContext().getObjCIdType(),
+ false, CallArgs, ObjCTypes);
+}
+
+CodeGen::RValue CGObjCCommonMac::EmitLegacyMessageSend(
+ CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ llvm::Value *Sel,
+ llvm::Value *Arg0,
+ QualType Arg0Ty,
+ bool IsSuper,
+ const CallArgList &CallArgs,
+ const ObjCCommonTypesHelper &ObjCTypes) {
+ CallArgList ActualArgs;
+ if (!IsSuper)
+ Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp");
+ ActualArgs.push_back(std::make_pair(RValue::get(Arg0), Arg0Ty));
+ ActualArgs.push_back(std::make_pair(RValue::get(Sel),
+ CGF.getContext().getObjCSelType()));
+ ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
+
+ CodeGenTypes &Types = CGM.getTypes();
+ const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs);
+ // In 64bit ABI, type must be assumed VARARG. In 32bit abi,
+ // it seems not to matter.
+ const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo, (ObjCABI == 2));
+
+ llvm::Constant *Fn = NULL;
+ if (CGM.ReturnTypeUsesSret(FnInfo)) {
+ Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
+ : ObjCTypes.getSendStretFn(IsSuper);
+ } else if (ResultType->isFloatingType()) {
+ if (ObjCABI == 2) {
+ if (const BuiltinType *BT = ResultType->getAsBuiltinType()) {
+ BuiltinType::Kind k = BT->getKind();
+ Fn = (k == BuiltinType::LongDouble) ? ObjCTypes.getSendFpretFn2(IsSuper)
+ : ObjCTypes.getSendFn2(IsSuper);
+ }
+ }
+ else
+ // FIXME. This currently matches gcc's API for x86-32. May need to change
+ // for others if we have their API.
+ Fn = ObjCTypes.getSendFpretFn(IsSuper);
+ } else {
+ Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
+ : ObjCTypes.getSendFn(IsSuper);
+ }
+ assert(Fn && "EmitLegacyMessageSend - unknown API");
+ Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy));
+ return CGF.EmitCall(FnInfo, Fn, ActualArgs);
+}
+
+llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder,
+ const ObjCProtocolDecl *PD) {
+ // FIXME: I don't understand why gcc generates this, or where it is
+ // resolved. Investigate. Its also wasteful to look this up over and over.
+ LazySymbols.insert(&CGM.getContext().Idents.get("Protocol"));
+
+ return llvm::ConstantExpr::getBitCast(GetProtocolRef(PD),
+ ObjCTypes.ExternalProtocolPtrTy);
+}
+
+void CGObjCCommonMac::GenerateProtocol(const ObjCProtocolDecl *PD) {
+ // FIXME: We shouldn't need this, the protocol decl should contain enough
+ // information to tell us whether this was a declaration or a definition.
+ DefinedProtocols.insert(PD->getIdentifier());
+
+ // If we have generated a forward reference to this protocol, emit
+ // it now. Otherwise do nothing, the protocol objects are lazily
+ // emitted.
+ if (Protocols.count(PD->getIdentifier()))
+ GetOrEmitProtocol(PD);
+}
+
+llvm::Constant *CGObjCCommonMac::GetProtocolRef(const ObjCProtocolDecl *PD) {
+ if (DefinedProtocols.count(PD->getIdentifier()))
+ return GetOrEmitProtocol(PD);
+ return GetOrEmitProtocolRef(PD);
+}
+
+/*
+ // APPLE LOCAL radar 4585769 - Objective-C 1.0 extensions
+ struct _objc_protocol {
+ struct _objc_protocol_extension *isa;
+ char *protocol_name;
+ struct _objc_protocol_list *protocol_list;
+ struct _objc__method_prototype_list *instance_methods;
+ struct _objc__method_prototype_list *class_methods
+ };
+
+ See EmitProtocolExtension().
+*/
+llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
+ llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
+
+ // Early exit if a defining object has already been generated.
+ if (Entry && Entry->hasInitializer())
+ return Entry;
+
+ // FIXME: I don't understand why gcc generates this, or where it is
+ // resolved. Investigate. Its also wasteful to look this up over and over.
+ LazySymbols.insert(&CGM.getContext().Idents.get("Protocol"));
+
+ const char *ProtocolName = PD->getNameAsCString();
+
+ // Construct method lists.
+ std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
+ std::vector<llvm::Constant*> OptInstanceMethods, OptClassMethods;
+ for (ObjCProtocolDecl::instmeth_iterator
+ i = PD->instmeth_begin(CGM.getContext()),
+ e = PD->instmeth_end(CGM.getContext()); i != e; ++i) {
+ ObjCMethodDecl *MD = *i;
+ llvm::Constant *C = GetMethodDescriptionConstant(MD);
+ if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
+ OptInstanceMethods.push_back(C);
+ } else {
+ InstanceMethods.push_back(C);
+ }
+ }
+
+ for (ObjCProtocolDecl::classmeth_iterator
+ i = PD->classmeth_begin(CGM.getContext()),
+ e = PD->classmeth_end(CGM.getContext()); i != e; ++i) {
+ ObjCMethodDecl *MD = *i;
+ llvm::Constant *C = GetMethodDescriptionConstant(MD);
+ if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
+ OptClassMethods.push_back(C);
+ } else {
+ ClassMethods.push_back(C);
+ }
+ }
+
+ std::vector<llvm::Constant*> Values(5);
+ Values[0] = EmitProtocolExtension(PD, OptInstanceMethods, OptClassMethods);
+ Values[1] = GetClassName(PD->getIdentifier());
+ Values[2] =
+ EmitProtocolList("\01L_OBJC_PROTOCOL_REFS_" + PD->getNameAsString(),
+ PD->protocol_begin(),
+ PD->protocol_end());
+ Values[3] =
+ EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_"
+ + PD->getNameAsString(),
+ "__OBJC,__cat_inst_meth,regular,no_dead_strip",
+ InstanceMethods);
+ Values[4] =
+ EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_"
+ + PD->getNameAsString(),
+ "__OBJC,__cat_cls_meth,regular,no_dead_strip",
+ ClassMethods);
+ llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolTy,
+ Values);
+
+ if (Entry) {
+ // Already created, fix the linkage and update the initializer.
+ Entry->setLinkage(llvm::GlobalValue::InternalLinkage);
+ Entry->setInitializer(Init);
+ } else {
+ Entry =
+ new llvm::GlobalVariable(ObjCTypes.ProtocolTy, false,
+ llvm::GlobalValue::InternalLinkage,
+ Init,
+ std::string("\01L_OBJC_PROTOCOL_")+ProtocolName,
+ &CGM.getModule());
+ Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
+ Entry->setAlignment(4);
+ UsedGlobals.push_back(Entry);
+ // FIXME: Is this necessary? Why only for protocol?
+ Entry->setAlignment(4);
+ }
+
+ return Entry;
+}
+
+llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) {
+ llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
+
+ if (!Entry) {
+ // We use the initializer as a marker of whether this is a forward
+ // reference or not. At module finalization we add the empty
+ // contents for protocols which were referenced but never defined.
+ Entry =
+ new llvm::GlobalVariable(ObjCTypes.ProtocolTy, false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0,
+ "\01L_OBJC_PROTOCOL_" + PD->getNameAsString(),
+ &CGM.getModule());
+ Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
+ Entry->setAlignment(4);
+ UsedGlobals.push_back(Entry);
+ // FIXME: Is this necessary? Why only for protocol?
+ Entry->setAlignment(4);
+ }
+
+ return Entry;
+}
+
+/*
+ struct _objc_protocol_extension {
+ uint32_t size;
+ struct objc_method_description_list *optional_instance_methods;
+ struct objc_method_description_list *optional_class_methods;
+ struct objc_property_list *instance_properties;
+ };
+*/
+llvm::Constant *
+CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
+ const ConstantVector &OptInstanceMethods,
+ const ConstantVector &OptClassMethods) {
+ uint64_t Size =
+ CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy);
+ std::vector<llvm::Constant*> Values(4);
+ Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
+ Values[1] =
+ EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_OPT_"
+ + PD->getNameAsString(),
+ "__OBJC,__cat_inst_meth,regular,no_dead_strip",
+ OptInstanceMethods);
+ Values[2] =
+ EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_OPT_"
+ + PD->getNameAsString(),
+ "__OBJC,__cat_cls_meth,regular,no_dead_strip",
+ OptClassMethods);
+ Values[3] = EmitPropertyList("\01L_OBJC_$_PROP_PROTO_LIST_" +
+ PD->getNameAsString(),
+ 0, PD, ObjCTypes);
+
+ // Return null if no extension bits are used.
+ if (Values[1]->isNullValue() && Values[2]->isNullValue() &&
+ Values[3]->isNullValue())
+ return llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
+
+ llvm::Constant *Init =
+ llvm::ConstantStruct::get(ObjCTypes.ProtocolExtensionTy, Values);
+
+ // No special section, but goes in llvm.used
+ return CreateMetadataVar("\01L_OBJC_PROTOCOLEXT_" + PD->getNameAsString(),
+ Init,
+ 0, 0, true);
+}
+
+/*
+ struct objc_protocol_list {
+ struct objc_protocol_list *next;
+ long count;
+ Protocol *list[];
+ };
+*/
+llvm::Constant *
+CGObjCMac::EmitProtocolList(const std::string &Name,
+ ObjCProtocolDecl::protocol_iterator begin,
+ ObjCProtocolDecl::protocol_iterator end) {
+ std::vector<llvm::Constant*> ProtocolRefs;
+
+ for (; begin != end; ++begin)
+ ProtocolRefs.push_back(GetProtocolRef(*begin));
+
+ // Just return null for empty protocol lists
+ if (ProtocolRefs.empty())
+ return llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
+
+ // This list is null terminated.
+ ProtocolRefs.push_back(llvm::Constant::getNullValue(ObjCTypes.ProtocolPtrTy));
+
+ std::vector<llvm::Constant*> Values(3);
+ // This field is only used by the runtime.
+ Values[0] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
+ Values[1] = llvm::ConstantInt::get(ObjCTypes.LongTy, ProtocolRefs.size() - 1);
+ Values[2] =
+ llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.ProtocolPtrTy,
+ ProtocolRefs.size()),
+ ProtocolRefs);
+
+ llvm::Constant *Init = llvm::ConstantStruct::get(Values);
+ llvm::GlobalVariable *GV =
+ CreateMetadataVar(Name, Init, "__OBJC,__cat_cls_meth,regular,no_dead_strip",
+ 4, false);
+ return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListPtrTy);
+}
+
+/*
+ struct _objc_property {
+ const char * const name;
+ const char * const attributes;
+ };
+
+ struct _objc_property_list {
+ uint32_t entsize; // sizeof (struct _objc_property)
+ uint32_t prop_count;
+ struct _objc_property[prop_count];
+ };
+*/
+llvm::Constant *CGObjCCommonMac::EmitPropertyList(const std::string &Name,
+ const Decl *Container,
+ const ObjCContainerDecl *OCD,
+ const ObjCCommonTypesHelper &ObjCTypes) {
+ std::vector<llvm::Constant*> Properties, Prop(2);
+ for (ObjCContainerDecl::prop_iterator I = OCD->prop_begin(CGM.getContext()),
+ E = OCD->prop_end(CGM.getContext()); I != E; ++I) {
+ const ObjCPropertyDecl *PD = *I;
+ Prop[0] = GetPropertyName(PD->getIdentifier());
+ Prop[1] = GetPropertyTypeString(PD, Container);
+ Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy,
+ Prop));
+ }
+
+ // Return null for empty list.
+ if (Properties.empty())
+ return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
+
+ unsigned PropertySize =
+ CGM.getTargetData().getTypeAllocSize(ObjCTypes.PropertyTy);
+ std::vector<llvm::Constant*> Values(3);
+ Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, PropertySize);
+ Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Properties.size());
+ llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.PropertyTy,
+ Properties.size());
+ Values[2] = llvm::ConstantArray::get(AT, Properties);
+ llvm::Constant *Init = llvm::ConstantStruct::get(Values);
+
+ llvm::GlobalVariable *GV =
+ CreateMetadataVar(Name, Init,
+ (ObjCABI == 2) ? "__DATA, __objc_const" :
+ "__OBJC,__property,regular,no_dead_strip",
+ (ObjCABI == 2) ? 8 : 4,
+ true);
+ return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.PropertyListPtrTy);
+}
+
+/*
+ struct objc_method_description_list {
+ int count;
+ struct objc_method_description list[];
+ };
+*/
+llvm::Constant *
+CGObjCMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
+ std::vector<llvm::Constant*> Desc(2);
+ Desc[0] = llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
+ ObjCTypes.SelectorPtrTy);
+ Desc[1] = GetMethodVarType(MD);
+ return llvm::ConstantStruct::get(ObjCTypes.MethodDescriptionTy,
+ Desc);
+}
+
+llvm::Constant *CGObjCMac::EmitMethodDescList(const std::string &Name,
+ const char *Section,
+ const ConstantVector &Methods) {
+ // Return null for empty list.
+ if (Methods.empty())
+ return llvm::Constant::getNullValue(ObjCTypes.MethodDescriptionListPtrTy);
+
+ std::vector<llvm::Constant*> Values(2);
+ Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size());
+ llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodDescriptionTy,
+ Methods.size());
+ Values[1] = llvm::ConstantArray::get(AT, Methods);
+ llvm::Constant *Init = llvm::ConstantStruct::get(Values);
+
+ llvm::GlobalVariable *GV = CreateMetadataVar(Name, Init, Section, 4, true);
+ return llvm::ConstantExpr::getBitCast(GV,
+ ObjCTypes.MethodDescriptionListPtrTy);
+}
+
+/*
+ struct _objc_category {
+ char *category_name;
+ char *class_name;
+ struct _objc_method_list *instance_methods;
+ struct _objc_method_list *class_methods;
+ struct _objc_protocol_list *protocols;
+ uint32_t size; // <rdar://4585769>
+ struct _objc_property_list *instance_properties;
+ };
+ */
+void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
+ unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.CategoryTy);
+
+ // FIXME: This is poor design, the OCD should have a pointer to the category
+ // decl. Additionally, note that Category can be null for the @implementation
+ // w/o an @interface case. Sema should just create one for us as it does for
+ // @implementation so everyone else can live life under a clear blue sky.
+ const ObjCInterfaceDecl *Interface = OCD->getClassInterface();
+ const ObjCCategoryDecl *Category =
+ Interface->FindCategoryDeclaration(OCD->getIdentifier());
+ std::string ExtName(Interface->getNameAsString() + "_" +
+ OCD->getNameAsString());
+
+ std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
+ for (ObjCCategoryImplDecl::instmeth_iterator
+ i = OCD->instmeth_begin(CGM.getContext()),
+ e = OCD->instmeth_end(CGM.getContext()); i != e; ++i) {
+ // Instance methods should always be defined.
+ InstanceMethods.push_back(GetMethodConstant(*i));
+ }
+ for (ObjCCategoryImplDecl::classmeth_iterator
+ i = OCD->classmeth_begin(CGM.getContext()),
+ e = OCD->classmeth_end(CGM.getContext()); i != e; ++i) {
+ // Class methods should always be defined.
+ ClassMethods.push_back(GetMethodConstant(*i));
+ }
+
+ std::vector<llvm::Constant*> Values(7);
+ Values[0] = GetClassName(OCD->getIdentifier());
+ Values[1] = GetClassName(Interface->getIdentifier());
+ LazySymbols.insert(Interface->getIdentifier());
+ Values[2] =
+ EmitMethodList(std::string("\01L_OBJC_CATEGORY_INSTANCE_METHODS_") +
+ ExtName,
+ "__OBJC,__cat_inst_meth,regular,no_dead_strip",
+ InstanceMethods);
+ Values[3] =
+ EmitMethodList(std::string("\01L_OBJC_CATEGORY_CLASS_METHODS_") + ExtName,
+ "__OBJC,__cat_cls_meth,regular,no_dead_strip",
+ ClassMethods);
+ if (Category) {
+ Values[4] =
+ EmitProtocolList(std::string("\01L_OBJC_CATEGORY_PROTOCOLS_") + ExtName,
+ Category->protocol_begin(),
+ Category->protocol_end());
+ } else {
+ Values[4] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
+ }
+ Values[5] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
+
+ // If there is no category @interface then there can be no properties.
+ if (Category) {
+ Values[6] = EmitPropertyList(std::string("\01l_OBJC_$_PROP_LIST_") + ExtName,
+ OCD, Category, ObjCTypes);
+ } else {
+ Values[6] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
+ }
+
+ llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.CategoryTy,
+ Values);
+
+ llvm::GlobalVariable *GV =
+ CreateMetadataVar(std::string("\01L_OBJC_CATEGORY_")+ExtName, Init,
+ "__OBJC,__category,regular,no_dead_strip",
+ 4, true);
+ DefinedCategories.push_back(GV);
+}
+
+// FIXME: Get from somewhere?
+enum ClassFlags {
+ eClassFlags_Factory = 0x00001,
+ eClassFlags_Meta = 0x00002,
+ // <rdr://5142207>
+ eClassFlags_HasCXXStructors = 0x02000,
+ eClassFlags_Hidden = 0x20000,
+ eClassFlags_ABI2_Hidden = 0x00010,
+ eClassFlags_ABI2_HasCXXStructors = 0x00004 // <rdr://4923634>
+};
+
+/*
+ struct _objc_class {
+ Class isa;
+ Class super_class;
+ const char *name;
+ long version;
+ long info;
+ long instance_size;
+ struct _objc_ivar_list *ivars;
+ struct _objc_method_list *methods;
+ struct _objc_cache *cache;
+ struct _objc_protocol_list *protocols;
+ // Objective-C 1.0 extensions (<rdr://4585769>)
+ const char *ivar_layout;
+ struct _objc_class_ext *ext;
+ };
+
+ See EmitClassExtension();
+ */
+void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
+ DefinedSymbols.insert(ID->getIdentifier());
+
+ std::string ClassName = ID->getNameAsString();
+ // FIXME: Gross
+ ObjCInterfaceDecl *Interface =
+ const_cast<ObjCInterfaceDecl*>(ID->getClassInterface());
+ llvm::Constant *Protocols =
+ EmitProtocolList("\01L_OBJC_CLASS_PROTOCOLS_" + ID->getNameAsString(),
+ Interface->protocol_begin(),
+ Interface->protocol_end());
+ unsigned Flags = eClassFlags_Factory;
+ unsigned Size =
+ CGM.getContext().getASTObjCImplementationLayout(ID).getSize() / 8;
+
+ // FIXME: Set CXX-structors flag.
+ if (CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden)
+ Flags |= eClassFlags_Hidden;
+
+ std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
+ for (ObjCImplementationDecl::instmeth_iterator
+ i = ID->instmeth_begin(CGM.getContext()),
+ e = ID->instmeth_end(CGM.getContext()); i != e; ++i) {
+ // Instance methods should always be defined.
+ InstanceMethods.push_back(GetMethodConstant(*i));
+ }
+ for (ObjCImplementationDecl::classmeth_iterator
+ i = ID->classmeth_begin(CGM.getContext()),
+ e = ID->classmeth_end(CGM.getContext()); i != e; ++i) {
+ // Class methods should always be defined.
+ ClassMethods.push_back(GetMethodConstant(*i));
+ }
+
+ for (ObjCImplementationDecl::propimpl_iterator
+ i = ID->propimpl_begin(CGM.getContext()),
+ e = ID->propimpl_end(CGM.getContext()); i != e; ++i) {
+ ObjCPropertyImplDecl *PID = *i;
+
+ if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
+ ObjCPropertyDecl *PD = PID->getPropertyDecl();
+
+ if (ObjCMethodDecl *MD = PD->getGetterMethodDecl())
+ if (llvm::Constant *C = GetMethodConstant(MD))
+ InstanceMethods.push_back(C);
+ if (ObjCMethodDecl *MD = PD->getSetterMethodDecl())
+ if (llvm::Constant *C = GetMethodConstant(MD))
+ InstanceMethods.push_back(C);
+ }
+ }
+
+ std::vector<llvm::Constant*> Values(12);
+ Values[ 0] = EmitMetaClass(ID, Protocols, ClassMethods);
+ if (ObjCInterfaceDecl *Super = Interface->getSuperClass()) {
+ // Record a reference to the super class.
+ LazySymbols.insert(Super->getIdentifier());
+
+ Values[ 1] =
+ llvm::ConstantExpr::getBitCast(GetClassName(Super->getIdentifier()),
+ ObjCTypes.ClassPtrTy);
+ } else {
+ Values[ 1] = llvm::Constant::getNullValue(ObjCTypes.ClassPtrTy);
+ }
+ Values[ 2] = GetClassName(ID->getIdentifier());
+ // Version is always 0.
+ Values[ 3] = llvm::ConstantInt::get(ObjCTypes.LongTy, 0);
+ Values[ 4] = llvm::ConstantInt::get(ObjCTypes.LongTy, Flags);
+ Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size);
+ Values[ 6] = EmitIvarList(ID, false);
+ Values[ 7] =
+ EmitMethodList("\01L_OBJC_INSTANCE_METHODS_" + ID->getNameAsString(),
+ "__OBJC,__inst_meth,regular,no_dead_strip",
+ InstanceMethods);
+ // cache is always NULL.
+ Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy);
+ Values[ 9] = Protocols;
+ Values[10] = BuildIvarLayout(ID, true);
+ Values[11] = EmitClassExtension(ID);
+ llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy,
+ Values);
+
+ llvm::GlobalVariable *GV =
+ CreateMetadataVar(std::string("\01L_OBJC_CLASS_")+ClassName, Init,
+ "__OBJC,__class,regular,no_dead_strip",
+ 4, true);
+ DefinedClasses.push_back(GV);
+}
+
+llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
+ llvm::Constant *Protocols,
+ const ConstantVector &Methods) {
+ unsigned Flags = eClassFlags_Meta;
+ unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassTy);
+
+ if (CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden)
+ Flags |= eClassFlags_Hidden;
+
+ std::vector<llvm::Constant*> Values(12);
+ // The isa for the metaclass is the root of the hierarchy.
+ const ObjCInterfaceDecl *Root = ID->getClassInterface();
+ while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
+ Root = Super;
+ Values[ 0] =
+ llvm::ConstantExpr::getBitCast(GetClassName(Root->getIdentifier()),
+ ObjCTypes.ClassPtrTy);
+ // The super class for the metaclass is emitted as the name of the
+ // super class. The runtime fixes this up to point to the
+ // *metaclass* for the super class.
+ if (ObjCInterfaceDecl *Super = ID->getClassInterface()->getSuperClass()) {
+ Values[ 1] =
+ llvm::ConstantExpr::getBitCast(GetClassName(Super->getIdentifier()),
+ ObjCTypes.ClassPtrTy);
+ } else {
+ Values[ 1] = llvm::Constant::getNullValue(ObjCTypes.ClassPtrTy);
+ }
+ Values[ 2] = GetClassName(ID->getIdentifier());
+ // Version is always 0.
+ Values[ 3] = llvm::ConstantInt::get(ObjCTypes.LongTy, 0);
+ Values[ 4] = llvm::ConstantInt::get(ObjCTypes.LongTy, Flags);
+ Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size);
+ Values[ 6] = EmitIvarList(ID, true);
+ Values[ 7] =
+ EmitMethodList("\01L_OBJC_CLASS_METHODS_" + ID->getNameAsString(),
+ "__OBJC,__cls_meth,regular,no_dead_strip",
+ Methods);
+ // cache is always NULL.
+ Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy);
+ Values[ 9] = Protocols;
+ // ivar_layout for metaclass is always NULL.
+ Values[10] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
+ // The class extension is always unused for metaclasses.
+ Values[11] = llvm::Constant::getNullValue(ObjCTypes.ClassExtensionPtrTy);
+ llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy,
+ Values);
+
+ std::string Name("\01L_OBJC_METACLASS_");
+ Name += ID->getNameAsCString();
+
+ // Check for a forward reference.
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
+ if (GV) {
+ assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
+ "Forward metaclass reference has incorrect type.");
+ GV->setLinkage(llvm::GlobalValue::InternalLinkage);
+ GV->setInitializer(Init);
+ } else {
+ GV = new llvm::GlobalVariable(ObjCTypes.ClassTy, false,
+ llvm::GlobalValue::InternalLinkage,
+ Init, Name,
+ &CGM.getModule());
+ }
+ GV->setSection("__OBJC,__meta_class,regular,no_dead_strip");
+ GV->setAlignment(4);
+ UsedGlobals.push_back(GV);
+
+ return GV;
+}
+
+llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) {
+ std::string Name = "\01L_OBJC_METACLASS_" + ID->getNameAsString();
+
+ // FIXME: Should we look these up somewhere other than the module. Its a bit
+ // silly since we only generate these while processing an implementation, so
+ // exactly one pointer would work if know when we entered/exitted an
+ // implementation block.
+
+ // Check for an existing forward reference.
+ // Previously, metaclass with internal linkage may have been defined.
+ // pass 'true' as 2nd argument so it is returned.
+ if (llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true)) {
+ assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
+ "Forward metaclass reference has incorrect type.");
+ return GV;
+ } else {
+ // Generate as an external reference to keep a consistent
+ // module. This will be patched up when we emit the metaclass.
+ return new llvm::GlobalVariable(ObjCTypes.ClassTy, false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0,
+ Name,
+ &CGM.getModule());
+ }
+}
+
+/*
+ struct objc_class_ext {
+ uint32_t size;
+ const char *weak_ivar_layout;
+ struct _objc_property_list *properties;
+ };
+*/
+llvm::Constant *
+CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) {
+ uint64_t Size =
+ CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassExtensionTy);
+
+ std::vector<llvm::Constant*> Values(3);
+ Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
+ Values[1] = BuildIvarLayout(ID, false);
+ Values[2] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getNameAsString(),
+ ID, ID->getClassInterface(), ObjCTypes);
+
+ // Return null if no extension bits are used.
+ if (Values[1]->isNullValue() && Values[2]->isNullValue())
+ return llvm::Constant::getNullValue(ObjCTypes.ClassExtensionPtrTy);
+
+ llvm::Constant *Init =
+ llvm::ConstantStruct::get(ObjCTypes.ClassExtensionTy, Values);
+ return CreateMetadataVar("\01L_OBJC_CLASSEXT_" + ID->getNameAsString(),
+ Init, "__OBJC,__class_ext,regular,no_dead_strip",
+ 4, true);
+}
+
+/*
+ struct objc_ivar {
+ char *ivar_name;
+ char *ivar_type;
+ int ivar_offset;
+ };
+
+ struct objc_ivar_list {
+ int ivar_count;
+ struct objc_ivar list[count];
+ };
+ */
+llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
+ bool ForClass) {
+ std::vector<llvm::Constant*> Ivars, Ivar(3);
+
+ // When emitting the root class GCC emits ivar entries for the
+ // actual class structure. It is not clear if we need to follow this
+ // behavior; for now lets try and get away with not doing it. If so,
+ // the cleanest solution would be to make up an ObjCInterfaceDecl
+ // for the class.
+ if (ForClass)
+ return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy);
+
+ ObjCInterfaceDecl *OID =
+ const_cast<ObjCInterfaceDecl*>(ID->getClassInterface());
+
+ llvm::SmallVector<ObjCIvarDecl*, 16> OIvars;
+ GetNamedIvarList(OID, OIvars);
+
+ for (unsigned i = 0, e = OIvars.size(); i != e; ++i) {
+ ObjCIvarDecl *IVD = OIvars[i];
+ Ivar[0] = GetMethodVarName(IVD->getIdentifier());
+ Ivar[1] = GetMethodVarType(IVD);
+ Ivar[2] = llvm::ConstantInt::get(ObjCTypes.IntTy,
+ ComputeIvarBaseOffset(CGM, OID, IVD));
+ Ivars.push_back(llvm::ConstantStruct::get(ObjCTypes.IvarTy, Ivar));
+ }
+
+ // Return null for empty list.
+ if (Ivars.empty())
+ return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy);
+
+ std::vector<llvm::Constant*> Values(2);
+ Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Ivars.size());
+ llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.IvarTy,
+ Ivars.size());
+ Values[1] = llvm::ConstantArray::get(AT, Ivars);
+ llvm::Constant *Init = llvm::ConstantStruct::get(Values);
+
+ llvm::GlobalVariable *GV;
+ if (ForClass)
+ GV = CreateMetadataVar("\01L_OBJC_CLASS_VARIABLES_" + ID->getNameAsString(),
+ Init, "__OBJC,__class_vars,regular,no_dead_strip",
+ 4, true);
+ else
+ GV = CreateMetadataVar("\01L_OBJC_INSTANCE_VARIABLES_"
+ + ID->getNameAsString(),
+ Init, "__OBJC,__instance_vars,regular,no_dead_strip",
+ 4, true);
+ return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListPtrTy);
+}
+
+/*
+ struct objc_method {
+ SEL method_name;
+ char *method_types;
+ void *method;
+ };
+
+ struct objc_method_list {
+ struct objc_method_list *obsolete;
+ int count;
+ struct objc_method methods_list[count];
+ };
+*/
+
+/// GetMethodConstant - Return a struct objc_method constant for the
+/// given method if it has been defined. The result is null if the
+/// method has not been defined. The return value has type MethodPtrTy.
+llvm::Constant *CGObjCMac::GetMethodConstant(const ObjCMethodDecl *MD) {
+ // FIXME: Use DenseMap::lookup
+ llvm::Function *Fn = MethodDefinitions[MD];
+ if (!Fn)
+ return 0;
+
+ std::vector<llvm::Constant*> Method(3);
+ Method[0] =
+ llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
+ ObjCTypes.SelectorPtrTy);
+ Method[1] = GetMethodVarType(MD);
+ Method[2] = llvm::ConstantExpr::getBitCast(Fn, ObjCTypes.Int8PtrTy);
+ return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Method);
+}
+
+llvm::Constant *CGObjCMac::EmitMethodList(const std::string &Name,
+ const char *Section,
+ const ConstantVector &Methods) {
+ // Return null for empty list.
+ if (Methods.empty())
+ return llvm::Constant::getNullValue(ObjCTypes.MethodListPtrTy);
+
+ std::vector<llvm::Constant*> Values(3);
+ Values[0] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
+ Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size());
+ llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodTy,
+ Methods.size());
+ Values[2] = llvm::ConstantArray::get(AT, Methods);
+ llvm::Constant *Init = llvm::ConstantStruct::get(Values);
+
+ llvm::GlobalVariable *GV = CreateMetadataVar(Name, Init, Section, 4, true);
+ return llvm::ConstantExpr::getBitCast(GV,
+ ObjCTypes.MethodListPtrTy);
+}
+
+llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) {
+ std::string Name;
+ GetNameForMethod(OMD, CD, Name);
+
+ CodeGenTypes &Types = CGM.getTypes();
+ const llvm::FunctionType *MethodTy =
+ Types.GetFunctionType(Types.getFunctionInfo(OMD), OMD->isVariadic());
+ llvm::Function *Method =
+ llvm::Function::Create(MethodTy,
+ llvm::GlobalValue::InternalLinkage,
+ Name,
+ &CGM.getModule());
+ MethodDefinitions.insert(std::make_pair(OMD, Method));
+
+ return Method;
+}
+
+llvm::GlobalVariable *
+CGObjCCommonMac::CreateMetadataVar(const std::string &Name,
+ llvm::Constant *Init,
+ const char *Section,
+ unsigned Align,
+ bool AddToUsed) {
+ const llvm::Type *Ty = Init->getType();
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(Ty, false,
+ llvm::GlobalValue::InternalLinkage,
+ Init,
+ Name,
+ &CGM.getModule());
+ if (Section)
+ GV->setSection(Section);
+ if (Align)
+ GV->setAlignment(Align);
+ if (AddToUsed)
+ UsedGlobals.push_back(GV);
+ return GV;
+}
+
+llvm::Function *CGObjCMac::ModuleInitFunction() {
+ // Abuse this interface function as a place to finalize.
+ FinishModule();
+
+ return NULL;
+}
+
+llvm::Constant *CGObjCMac::GetPropertyGetFunction() {
+ return ObjCTypes.getGetPropertyFn();
+}
+
+llvm::Constant *CGObjCMac::GetPropertySetFunction() {
+ return ObjCTypes.getSetPropertyFn();
+}
+
+llvm::Constant *CGObjCMac::EnumerationMutationFunction() {
+ return ObjCTypes.getEnumerationMutationFn();
+}
+
+/*
+
+Objective-C setjmp-longjmp (sjlj) Exception Handling
+--
+
+The basic framework for a @try-catch-finally is as follows:
+{
+ objc_exception_data d;
+ id _rethrow = null;
+ bool _call_try_exit = true;
+
+ objc_exception_try_enter(&d);
+ if (!setjmp(d.jmp_buf)) {
+ ... try body ...
+ } else {
+ // exception path
+ id _caught = objc_exception_extract(&d);
+
+ // enter new try scope for handlers
+ if (!setjmp(d.jmp_buf)) {
+ ... match exception and execute catch blocks ...
+
+ // fell off end, rethrow.
+ _rethrow = _caught;
+ ... jump-through-finally to finally_rethrow ...
+ } else {
+ // exception in catch block
+ _rethrow = objc_exception_extract(&d);
+ _call_try_exit = false;
+ ... jump-through-finally to finally_rethrow ...
+ }
+ }
+ ... jump-through-finally to finally_end ...
+
+finally:
+ if (_call_try_exit)
+ objc_exception_try_exit(&d);
+
+ ... finally block ....
+ ... dispatch to finally destination ...
+
+finally_rethrow:
+ objc_exception_throw(_rethrow);
+
+finally_end:
+}
+
+This framework differs slightly from the one gcc uses, in that gcc
+uses _rethrow to determine if objc_exception_try_exit should be called
+and if the object should be rethrown. This breaks in the face of
+throwing nil and introduces unnecessary branches.
+
+We specialize this framework for a few particular circumstances:
+
+ - If there are no catch blocks, then we avoid emitting the second
+ exception handling context.
+
+ - If there is a catch-all catch block (i.e. @catch(...) or @catch(id
+ e)) we avoid emitting the code to rethrow an uncaught exception.
+
+ - FIXME: If there is no @finally block we can do a few more
+ simplifications.
+
+Rethrows and Jumps-Through-Finally
+--
+
+Support for implicit rethrows and jumping through the finally block is
+handled by storing the current exception-handling context in
+ObjCEHStack.
+
+In order to implement proper @finally semantics, we support one basic
+mechanism for jumping through the finally block to an arbitrary
+destination. Constructs which generate exits from a @try or @catch
+block use this mechanism to implement the proper semantics by chaining
+jumps, as necessary.
+
+This mechanism works like the one used for indirect goto: we
+arbitrarily assign an ID to each destination and store the ID for the
+destination in a variable prior to entering the finally block. At the
+end of the finally block we simply create a switch to the proper
+destination.
+
+Code gen for @synchronized(expr) stmt;
+Effectively generating code for:
+objc_sync_enter(expr);
+@try stmt @finally { objc_sync_exit(expr); }
+*/
+
+void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
+ const Stmt &S) {
+ bool isTry = isa<ObjCAtTryStmt>(S);
+ // Create various blocks we refer to for handling @finally.
+ llvm::BasicBlock *FinallyBlock = CGF.createBasicBlock("finally");
+ llvm::BasicBlock *FinallyExit = CGF.createBasicBlock("finally.exit");
+ llvm::BasicBlock *FinallyNoExit = CGF.createBasicBlock("finally.noexit");
+ llvm::BasicBlock *FinallyRethrow = CGF.createBasicBlock("finally.throw");
+ llvm::BasicBlock *FinallyEnd = CGF.createBasicBlock("finally.end");
+
+ // For @synchronized, call objc_sync_enter(sync.expr). The
+ // evaluation of the expression must occur before we enter the
+ // @synchronized. We can safely avoid a temp here because jumps into
+ // @synchronized are illegal & this will dominate uses.
+ llvm::Value *SyncArg = 0;
+ if (!isTry) {
+ SyncArg =
+ CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
+ SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy);
+ CGF.Builder.CreateCall(ObjCTypes.getSyncEnterFn(), SyncArg);
+ }
+
+ // Push an EH context entry, used for handling rethrows and jumps
+ // through finally.
+ CGF.PushCleanupBlock(FinallyBlock);
+
+ CGF.ObjCEHValueStack.push_back(0);
+
+ // Allocate memory for the exception data and rethrow pointer.
+ llvm::Value *ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy,
+ "exceptiondata.ptr");
+ llvm::Value *RethrowPtr = CGF.CreateTempAlloca(ObjCTypes.ObjectPtrTy,
+ "_rethrow");
+ llvm::Value *CallTryExitPtr = CGF.CreateTempAlloca(llvm::Type::Int1Ty,
+ "_call_try_exit");
+ CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(), CallTryExitPtr);
+
+ // Enter a new try block and call setjmp.
+ CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData);
+ llvm::Value *JmpBufPtr = CGF.Builder.CreateStructGEP(ExceptionData, 0,
+ "jmpbufarray");
+ JmpBufPtr = CGF.Builder.CreateStructGEP(JmpBufPtr, 0, "tmp");
+ llvm::Value *SetJmpResult = CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(),
+ JmpBufPtr, "result");
+
+ llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try");
+ llvm::BasicBlock *TryHandler = CGF.createBasicBlock("try.handler");
+ CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNotNull(SetJmpResult, "threw"),
+ TryHandler, TryBlock);
+
+ // Emit the @try block.
+ CGF.EmitBlock(TryBlock);
+ CGF.EmitStmt(isTry ? cast<ObjCAtTryStmt>(S).getTryBody()
+ : cast<ObjCAtSynchronizedStmt>(S).getSynchBody());
+ CGF.EmitBranchThroughCleanup(FinallyEnd);
+
+ // Emit the "exception in @try" block.
+ CGF.EmitBlock(TryHandler);
+
+ // Retrieve the exception object. We may emit multiple blocks but
+ // nothing can cross this so the value is already in SSA form.
+ llvm::Value *Caught =
+ CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
+ ExceptionData, "caught");
+ CGF.ObjCEHValueStack.back() = Caught;
+ if (!isTry)
+ {
+ CGF.Builder.CreateStore(Caught, RethrowPtr);
+ CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(), CallTryExitPtr);
+ CGF.EmitBranchThroughCleanup(FinallyRethrow);
+ }
+ else if (const ObjCAtCatchStmt* CatchStmt =
+ cast<ObjCAtTryStmt>(S).getCatchStmts())
+ {
+ // Enter a new exception try block (in case a @catch block throws
+ // an exception).
+ CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData);
+
+ llvm::Value *SetJmpResult = CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(),
+ JmpBufPtr, "result");
+ llvm::Value *Threw = CGF.Builder.CreateIsNotNull(SetJmpResult, "threw");
+
+ llvm::BasicBlock *CatchBlock = CGF.createBasicBlock("catch");
+ llvm::BasicBlock *CatchHandler = CGF.createBasicBlock("catch.handler");
+ CGF.Builder.CreateCondBr(Threw, CatchHandler, CatchBlock);
+
+ CGF.EmitBlock(CatchBlock);
+
+ // Handle catch list. As a special case we check if everything is
+ // matched and avoid generating code for falling off the end if
+ // so.
+ bool AllMatched = false;
+ for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
+ llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch");
+
+ const ParmVarDecl *CatchParam = CatchStmt->getCatchParamDecl();
+ const PointerType *PT = 0;
+
+ // catch(...) always matches.
+ if (!CatchParam) {
+ AllMatched = true;
+ } else {
+ PT = CatchParam->getType()->getAsPointerType();
+
+ // catch(id e) always matches.
+ // FIXME: For the time being we also match id<X>; this should
+ // be rejected by Sema instead.
+ if ((PT && CGF.getContext().isObjCIdStructType(PT->getPointeeType())) ||
+ CatchParam->getType()->isObjCQualifiedIdType())
+ AllMatched = true;
+ }
+
+ if (AllMatched) {
+ if (CatchParam) {
+ CGF.EmitLocalBlockVarDecl(*CatchParam);
+ assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?");
+ CGF.Builder.CreateStore(Caught, CGF.GetAddrOfLocalVar(CatchParam));
+ }
+
+ CGF.EmitStmt(CatchStmt->getCatchBody());
+ CGF.EmitBranchThroughCleanup(FinallyEnd);
+ break;
+ }
+
+ assert(PT && "Unexpected non-pointer type in @catch");
+ QualType T = PT->getPointeeType();
+ const ObjCInterfaceType *ObjCType = T->getAsObjCInterfaceType();
+ assert(ObjCType && "Catch parameter must have Objective-C type!");
+
+ // Check if the @catch block matches the exception object.
+ llvm::Value *Class = EmitClassRef(CGF.Builder, ObjCType->getDecl());
+
+ llvm::Value *Match =
+ CGF.Builder.CreateCall2(ObjCTypes.getExceptionMatchFn(),
+ Class, Caught, "match");
+
+ llvm::BasicBlock *MatchedBlock = CGF.createBasicBlock("matched");
+
+ CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNotNull(Match, "matched"),
+ MatchedBlock, NextCatchBlock);
+
+ // Emit the @catch block.
+ CGF.EmitBlock(MatchedBlock);
+ CGF.EmitLocalBlockVarDecl(*CatchParam);
+ assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?");
+
+ llvm::Value *Tmp =
+ CGF.Builder.CreateBitCast(Caught, CGF.ConvertType(CatchParam->getType()),
+ "tmp");
+ CGF.Builder.CreateStore(Tmp, CGF.GetAddrOfLocalVar(CatchParam));
+
+ CGF.EmitStmt(CatchStmt->getCatchBody());
+ CGF.EmitBranchThroughCleanup(FinallyEnd);
+
+ CGF.EmitBlock(NextCatchBlock);
+ }
+
+ if (!AllMatched) {
+ // None of the handlers caught the exception, so store it to be
+ // rethrown at the end of the @finally block.
+ CGF.Builder.CreateStore(Caught, RethrowPtr);
+ CGF.EmitBranchThroughCleanup(FinallyRethrow);
+ }
+
+ // Emit the exception handler for the @catch blocks.
+ CGF.EmitBlock(CatchHandler);
+ CGF.Builder.CreateStore(
+ CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
+ ExceptionData),
+ RethrowPtr);
+ CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(), CallTryExitPtr);
+ CGF.EmitBranchThroughCleanup(FinallyRethrow);
+ } else {
+ CGF.Builder.CreateStore(Caught, RethrowPtr);
+ CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(), CallTryExitPtr);
+ CGF.EmitBranchThroughCleanup(FinallyRethrow);
+ }
+
+ // Pop the exception-handling stack entry. It is important to do
+ // this now, because the code in the @finally block is not in this
+ // context.
+ CodeGenFunction::CleanupBlockInfo Info = CGF.PopCleanupBlock();
+
+ CGF.ObjCEHValueStack.pop_back();
+
+ // Emit the @finally block.
+ CGF.EmitBlock(FinallyBlock);
+ llvm::Value* CallTryExit = CGF.Builder.CreateLoad(CallTryExitPtr, "tmp");
+
+ CGF.Builder.CreateCondBr(CallTryExit, FinallyExit, FinallyNoExit);
+
+ CGF.EmitBlock(FinallyExit);
+ CGF.Builder.CreateCall(ObjCTypes.getExceptionTryExitFn(), ExceptionData);
+
+ CGF.EmitBlock(FinallyNoExit);
+ if (isTry) {
+ if (const ObjCAtFinallyStmt* FinallyStmt =
+ cast<ObjCAtTryStmt>(S).getFinallyStmt())
+ CGF.EmitStmt(FinallyStmt->getFinallyBody());
+ } else {
+ // Emit objc_sync_exit(expr); as finally's sole statement for
+ // @synchronized.
+ CGF.Builder.CreateCall(ObjCTypes.getSyncExitFn(), SyncArg);
+ }
+
+ // Emit the switch block
+ if (Info.SwitchBlock)
+ CGF.EmitBlock(Info.SwitchBlock);
+ if (Info.EndBlock)
+ CGF.EmitBlock(Info.EndBlock);
+
+ CGF.EmitBlock(FinallyRethrow);
+ CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(),
+ CGF.Builder.CreateLoad(RethrowPtr));
+ CGF.Builder.CreateUnreachable();
+
+ CGF.EmitBlock(FinallyEnd);
+}
+
+void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
+ const ObjCAtThrowStmt &S) {
+ llvm::Value *ExceptionAsObject;
+
+ if (const Expr *ThrowExpr = S.getThrowExpr()) {
+ llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr);
+ ExceptionAsObject =
+ CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy, "tmp");
+ } else {
+ assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) &&
+ "Unexpected rethrow outside @catch block.");
+ ExceptionAsObject = CGF.ObjCEHValueStack.back();
+ }
+
+ CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject);
+ CGF.Builder.CreateUnreachable();
+
+ // Clear the insertion point to indicate we are in unreachable code.
+ CGF.Builder.ClearInsertionPoint();
+}
+
+/// EmitObjCWeakRead - Code gen for loading value of a __weak
+/// object: objc_read_weak (id *src)
+///
+llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *AddrWeakObj)
+{
+ const llvm::Type* DestTy =
+ cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType();
+ AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy);
+ llvm::Value *read_weak = CGF.Builder.CreateCall(ObjCTypes.getGcReadWeakFn(),
+ AddrWeakObj, "weakread");
+ read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
+ return read_weak;
+}
+
+/// EmitObjCWeakAssign - Code gen for assigning to a __weak object.
+/// objc_assign_weak (id src, id *dst)
+///
+void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst)
+{
+ const llvm::Type * SrcTy = src->getType();
+ if (!isa<llvm::PointerType>(SrcTy)) {
+ unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ assert(Size <= 8 && "does not support size > 8");
+ src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
+ : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
+ src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
+ }
+ src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
+ dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
+ CGF.Builder.CreateCall2(ObjCTypes.getGcAssignWeakFn(),
+ src, dst, "weakassign");
+ return;
+}
+
+/// EmitObjCGlobalAssign - Code gen for assigning to a __strong object.
+/// objc_assign_global (id src, id *dst)
+///
+void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst)
+{
+ const llvm::Type * SrcTy = src->getType();
+ if (!isa<llvm::PointerType>(SrcTy)) {
+ unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ assert(Size <= 8 && "does not support size > 8");
+ src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
+ : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
+ src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
+ }
+ src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
+ dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
+ CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(),
+ src, dst, "globalassign");
+ return;
+}
+
+/// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
+/// objc_assign_ivar (id src, id *dst)
+///
+void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst)
+{
+ const llvm::Type * SrcTy = src->getType();
+ if (!isa<llvm::PointerType>(SrcTy)) {
+ unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ assert(Size <= 8 && "does not support size > 8");
+ src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
+ : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
+ src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
+ }
+ src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
+ dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
+ CGF.Builder.CreateCall2(ObjCTypes.getGcAssignIvarFn(),
+ src, dst, "assignivar");
+ return;
+}
+
+/// EmitObjCStrongCastAssign - Code gen for assigning to a __strong cast object.
+/// objc_assign_strongCast (id src, id *dst)
+///
+void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst)
+{
+ const llvm::Type * SrcTy = src->getType();
+ if (!isa<llvm::PointerType>(SrcTy)) {
+ unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ assert(Size <= 8 && "does not support size > 8");
+ src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
+ : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
+ src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
+ }
+ src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
+ dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
+ CGF.Builder.CreateCall2(ObjCTypes.getGcAssignStrongCastFn(),
+ src, dst, "weakassign");
+ return;
+}
+
+/// EmitObjCValueForIvar - Code Gen for ivar reference.
+///
+LValue CGObjCMac::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
+ QualType ObjectTy,
+ llvm::Value *BaseValue,
+ const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers) {
+ const ObjCInterfaceDecl *ID = ObjectTy->getAsObjCInterfaceType()->getDecl();
+ return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
+ EmitIvarOffset(CGF, ID, Ivar));
+}
+
+llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *Interface,
+ const ObjCIvarDecl *Ivar) {
+ uint64_t Offset = ComputeIvarBaseOffset(CGM, Interface, Ivar);
+ return llvm::ConstantInt::get(
+ CGM.getTypes().ConvertType(CGM.getContext().LongTy),
+ Offset);
+}
+
+/* *** Private Interface *** */
+
+/// EmitImageInfo - Emit the image info marker used to encode some module
+/// level information.
+///
+/// See: <rdr://4810609&4810587&4810587>
+/// struct IMAGE_INFO {
+/// unsigned version;
+/// unsigned flags;
+/// };
+enum ImageInfoFlags {
+ eImageInfo_FixAndContinue = (1 << 0), // FIXME: Not sure what
+ // this implies.
+ eImageInfo_GarbageCollected = (1 << 1),
+ eImageInfo_GCOnly = (1 << 2),
+ eImageInfo_OptimizedByDyld = (1 << 3), // FIXME: When is this set.
+
+ // A flag indicating that the module has no instances of an
+ // @synthesize of a superclass variable. <rdar://problem/6803242>
+ eImageInfo_CorrectedSynthesize = (1 << 4)
+};
+
+void CGObjCMac::EmitImageInfo() {
+ unsigned version = 0; // Version is unused?
+ unsigned flags = 0;
+
+ // FIXME: Fix and continue?
+ if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC)
+ flags |= eImageInfo_GarbageCollected;
+ if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly)
+ flags |= eImageInfo_GCOnly;
+
+ // We never allow @synthesize of a superclass property.
+ flags |= eImageInfo_CorrectedSynthesize;
+
+ // Emitted as int[2];
+ llvm::Constant *values[2] = {
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, version),
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, flags)
+ };
+ llvm::ArrayType *AT = llvm::ArrayType::get(llvm::Type::Int32Ty, 2);
+
+ const char *Section;
+ if (ObjCABI == 1)
+ Section = "__OBJC, __image_info,regular";
+ else
+ Section = "__DATA, __objc_imageinfo, regular, no_dead_strip";
+ llvm::GlobalVariable *GV =
+ CreateMetadataVar("\01L_OBJC_IMAGE_INFO",
+ llvm::ConstantArray::get(AT, values, 2),
+ Section,
+ 0,
+ true);
+ GV->setConstant(true);
+}
+
+
+// struct objc_module {
+// unsigned long version;
+// unsigned long size;
+// const char *name;
+// Symtab symtab;
+// };
+
+// FIXME: Get from somewhere
+static const int ModuleVersion = 7;
+
+void CGObjCMac::EmitModuleInfo() {
+ uint64_t Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ModuleTy);
+
+ std::vector<llvm::Constant*> Values(4);
+ Values[0] = llvm::ConstantInt::get(ObjCTypes.LongTy, ModuleVersion);
+ Values[1] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size);
+ // This used to be the filename, now it is unused. <rdr://4327263>
+ Values[2] = GetClassName(&CGM.getContext().Idents.get(""));
+ Values[3] = EmitModuleSymbols();
+ CreateMetadataVar("\01L_OBJC_MODULES",
+ llvm::ConstantStruct::get(ObjCTypes.ModuleTy, Values),
+ "__OBJC,__module_info,regular,no_dead_strip",
+ 4, true);
+}
+
+llvm::Constant *CGObjCMac::EmitModuleSymbols() {
+ unsigned NumClasses = DefinedClasses.size();
+ unsigned NumCategories = DefinedCategories.size();
+
+ // Return null if no symbols were defined.
+ if (!NumClasses && !NumCategories)
+ return llvm::Constant::getNullValue(ObjCTypes.SymtabPtrTy);
+
+ std::vector<llvm::Constant*> Values(5);
+ Values[0] = llvm::ConstantInt::get(ObjCTypes.LongTy, 0);
+ Values[1] = llvm::Constant::getNullValue(ObjCTypes.SelectorPtrTy);
+ Values[2] = llvm::ConstantInt::get(ObjCTypes.ShortTy, NumClasses);
+ Values[3] = llvm::ConstantInt::get(ObjCTypes.ShortTy, NumCategories);
+
+ // The runtime expects exactly the list of defined classes followed
+ // by the list of defined categories, in a single array.
+ std::vector<llvm::Constant*> Symbols(NumClasses + NumCategories);
+ for (unsigned i=0; i<NumClasses; i++)
+ Symbols[i] = llvm::ConstantExpr::getBitCast(DefinedClasses[i],
+ ObjCTypes.Int8PtrTy);
+ for (unsigned i=0; i<NumCategories; i++)
+ Symbols[NumClasses + i] =
+ llvm::ConstantExpr::getBitCast(DefinedCategories[i],
+ ObjCTypes.Int8PtrTy);
+
+ Values[4] =
+ llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
+ NumClasses + NumCategories),
+ Symbols);
+
+ llvm::Constant *Init = llvm::ConstantStruct::get(Values);
+
+ llvm::GlobalVariable *GV =
+ CreateMetadataVar("\01L_OBJC_SYMBOLS", Init,
+ "__OBJC,__symbols,regular,no_dead_strip",
+ 4, true);
+ return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy);
+}
+
+llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *ID) {
+ LazySymbols.insert(ID->getIdentifier());
+
+ llvm::GlobalVariable *&Entry = ClassReferences[ID->getIdentifier()];
+
+ if (!Entry) {
+ llvm::Constant *Casted =
+ llvm::ConstantExpr::getBitCast(GetClassName(ID->getIdentifier()),
+ ObjCTypes.ClassPtrTy);
+ Entry =
+ CreateMetadataVar("\01L_OBJC_CLASS_REFERENCES_", Casted,
+ "__OBJC,__cls_refs,literal_pointers,no_dead_strip",
+ 4, true);
+ }
+
+ return Builder.CreateLoad(Entry, false, "tmp");
+}
+
+llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel) {
+ llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
+
+ if (!Entry) {
+ llvm::Constant *Casted =
+ llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
+ ObjCTypes.SelectorPtrTy);
+ Entry =
+ CreateMetadataVar("\01L_OBJC_SELECTOR_REFERENCES_", Casted,
+ "__OBJC,__message_refs,literal_pointers,no_dead_strip",
+ 4, true);
+ }
+
+ return Builder.CreateLoad(Entry, false, "tmp");
+}
+
+llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) {
+ llvm::GlobalVariable *&Entry = ClassNames[Ident];
+
+ if (!Entry)
+ Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
+ llvm::ConstantArray::get(Ident->getName()),
+ "__TEXT,__cstring,cstring_literals",
+ 1, true);
+
+ return getConstantGEP(Entry, 0, 0);
+}
+
+/// GetIvarLayoutName - Returns a unique constant for the given
+/// ivar layout bitmap.
+llvm::Constant *CGObjCCommonMac::GetIvarLayoutName(IdentifierInfo *Ident,
+ const ObjCCommonTypesHelper &ObjCTypes) {
+ return llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
+}
+
+static QualType::GCAttrTypes GetGCAttrTypeForType(ASTContext &Ctx,
+ QualType FQT) {
+ if (FQT.isObjCGCStrong())
+ return QualType::Strong;
+
+ if (FQT.isObjCGCWeak())
+ return QualType::Weak;
+
+ if (Ctx.isObjCObjectPointerType(FQT))
+ return QualType::Strong;
+
+ if (const PointerType *PT = FQT->getAsPointerType())
+ return GetGCAttrTypeForType(Ctx, PT->getPointeeType());
+
+ return QualType::GCNone;
+}
+
+void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT,
+ unsigned int BytePos,
+ bool ForStrongLayout,
+ bool &HasUnion) {
+ const RecordDecl *RD = RT->getDecl();
+ // FIXME - Use iterator.
+ llvm::SmallVector<FieldDecl*, 16> Fields(RD->field_begin(CGM.getContext()),
+ RD->field_end(CGM.getContext()));
+ const llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
+ const llvm::StructLayout *RecLayout =
+ CGM.getTargetData().getStructLayout(cast<llvm::StructType>(Ty));
+
+ BuildAggrIvarLayout(0, RecLayout, RD, Fields, BytePos,
+ ForStrongLayout, HasUnion);
+}
+
+void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
+ const llvm::StructLayout *Layout,
+ const RecordDecl *RD,
+ const llvm::SmallVectorImpl<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 *LastFieldBitfield = 0;
+ uint64_t MaxFieldOffset = 0;
+ uint64_t MaxSkippedFieldOffset = 0;
+ uint64_t LastBitfieldOffset = 0;
+
+ if (RecFields.empty())
+ return;
+ unsigned WordSizeInBits = CGM.getContext().Target.getPointerWidth(0);
+ unsigned ByteSizeInBits = CGM.getContext().Target.getCharWidth();
+
+ for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
+ FieldDecl *Field = RecFields[i];
+ uint64_t FieldOffset;
+ if (RD)
+ FieldOffset =
+ Layout->getElementOffset(CGM.getTypes().getLLVMFieldNo(Field));
+ else
+ FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field));
+
+ // Skip over unnamed or bitfields
+ if (!Field->getIdentifier() || Field->isBitField()) {
+ LastFieldBitfield = Field;
+ LastBitfieldOffset = FieldOffset;
+ continue;
+ }
+
+ LastFieldBitfield = 0;
+ QualType FQT = Field->getType();
+ if (FQT->isRecordType() || FQT->isUnionType()) {
+ if (FQT->isUnionType())
+ HasUnion = true;
+
+ BuildAggrIvarRecordLayout(FQT->getAsRecordType(),
+ BytePos + FieldOffset,
+ ForStrongLayout, HasUnion);
+ continue;
+ }
+
+ if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
+ const ConstantArrayType *CArray =
+ dyn_cast_or_null<ConstantArrayType>(Array);
+ uint64_t ElCount = CArray->getSize().getZExtValue();
+ assert(CArray && "only array with known element size is supported");
+ FQT = CArray->getElementType();
+ while (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
+ const ConstantArrayType *CArray =
+ dyn_cast_or_null<ConstantArrayType>(Array);
+ ElCount *= CArray->getSize().getZExtValue();
+ FQT = CArray->getElementType();
+ }
+
+ assert(!FQT->isUnionType() &&
+ "layout for array of unions not supported");
+ if (FQT->isRecordType()) {
+ int OldIndex = IvarsInfo.size() - 1;
+ int OldSkIndex = SkipIvars.size() -1;
+
+ const RecordType *RT = FQT->getAsRecordType();
+ BuildAggrIvarRecordLayout(RT, BytePos + FieldOffset,
+ ForStrongLayout, HasUnion);
+
+ // Replicate layout information for each array element. Note that
+ // one element is already done.
+ uint64_t ElIx = 1;
+ for (int FirstIndex = IvarsInfo.size() - 1,
+ FirstSkIndex = SkipIvars.size() - 1 ;ElIx < ElCount; ElIx++) {
+ uint64_t Size = CGM.getContext().getTypeSize(RT)/ByteSizeInBits;
+ for (int i = OldIndex+1; i <= FirstIndex; ++i)
+ IvarsInfo.push_back(GC_IVAR(IvarsInfo[i].ivar_bytepos + Size*ElIx,
+ IvarsInfo[i].ivar_size));
+ for (int i = OldSkIndex+1; i <= FirstSkIndex; ++i)
+ SkipIvars.push_back(GC_IVAR(SkipIvars[i].ivar_bytepos + Size*ElIx,
+ SkipIvars[i].ivar_size));
+ }
+ continue;
+ }
+ }
+ // At this point, we are done with Record/Union and array there of.
+ // For other arrays we are down to its element type.
+ QualType::GCAttrTypes GCAttr = GetGCAttrTypeForType(CGM.getContext(), FQT);
+
+ unsigned FieldSize = CGM.getContext().getTypeSize(Field->getType());
+ if ((ForStrongLayout && GCAttr == QualType::Strong)
+ || (!ForStrongLayout && GCAttr == QualType::Weak)) {
+ if (IsUnion) {
+ uint64_t UnionIvarSize = FieldSize / WordSizeInBits;
+ if (UnionIvarSize > MaxUnionIvarSize) {
+ MaxUnionIvarSize = UnionIvarSize;
+ MaxField = Field;
+ MaxFieldOffset = FieldOffset;
+ }
+ } else {
+ IvarsInfo.push_back(GC_IVAR(BytePos + FieldOffset,
+ FieldSize / WordSizeInBits));
+ }
+ } else if ((ForStrongLayout &&
+ (GCAttr == QualType::GCNone || GCAttr == QualType::Weak))
+ || (!ForStrongLayout && GCAttr != QualType::Weak)) {
+ if (IsUnion) {
+ // FIXME: Why the asymmetry? We divide by word size in bits on other
+ // side.
+ uint64_t UnionIvarSize = FieldSize;
+ if (UnionIvarSize > MaxSkippedUnionIvarSize) {
+ MaxSkippedUnionIvarSize = UnionIvarSize;
+ MaxSkippedField = Field;
+ MaxSkippedFieldOffset = FieldOffset;
+ }
+ } else {
+ // FIXME: Why the asymmetry, we divide by byte size in bits here?
+ SkipIvars.push_back(GC_IVAR(BytePos + FieldOffset,
+ FieldSize / ByteSizeInBits));
+ }
+ }
+ }
+
+ if (LastFieldBitfield) {
+ // Last field was a bitfield. Must update skip info.
+ Expr *BitWidth = LastFieldBitfield->getBitWidth();
+ uint64_t BitFieldSize =
+ BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue();
+ GC_IVAR skivar;
+ skivar.ivar_bytepos = BytePos + LastBitfieldOffset;
+ skivar.ivar_size = (BitFieldSize / ByteSizeInBits)
+ + ((BitFieldSize % ByteSizeInBits) != 0);
+ SkipIvars.push_back(skivar);
+ }
+
+ if (MaxField)
+ IvarsInfo.push_back(GC_IVAR(BytePos + MaxFieldOffset,
+ MaxUnionIvarSize));
+ if (MaxSkippedField)
+ SkipIvars.push_back(GC_IVAR(BytePos + MaxSkippedFieldOffset,
+ MaxSkippedUnionIvarSize));
+}
+
+/// BuildIvarLayout - Builds ivar layout bitmap for the class
+/// implementation for the __strong or __weak case.
+/// The layout map displays which words in ivar list must be skipped
+/// and which must be scanned by GC (see below). String is built of bytes.
+/// Each byte is divided up in two nibbles (4-bit each). Left nibble is count
+/// of words to skip and right nibble is count of words to scan. So, each
+/// nibble represents up to 15 workds to skip or scan. Skipping the rest is
+/// represented by a 0x00 byte which also ends the string.
+/// 1. when ForStrongLayout is true, following ivars are scanned:
+/// - id, Class
+/// - object *
+/// - __strong anything
+///
+/// 2. When ForStrongLayout is false, following ivars are scanned:
+/// - __weak anything
+///
+llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
+ const ObjCImplementationDecl *OMD,
+ bool ForStrongLayout) {
+ bool hasUnion = false;
+
+ unsigned int WordsToScan, WordsToSkip;
+ const llvm::Type *PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC)
+ return llvm::Constant::getNullValue(PtrTy);
+
+ llvm::SmallVector<FieldDecl*, 32> RecFields;
+ const ObjCInterfaceDecl *OI = OMD->getClassInterface();
+ CGM.getContext().CollectObjCIvars(OI, RecFields);
+
+ // Add this implementations synthesized ivars.
+ llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
+ CGM.getContext().CollectSynthesizedIvars(OI, Ivars);
+ for (unsigned k = 0, e = Ivars.size(); k != e; ++k)
+ RecFields.push_back(cast<FieldDecl>(Ivars[k]));
+
+ if (RecFields.empty())
+ return llvm::Constant::getNullValue(PtrTy);
+
+ SkipIvars.clear();
+ IvarsInfo.clear();
+
+ BuildAggrIvarLayout(OMD, 0, 0, RecFields, 0, ForStrongLayout, hasUnion);
+ if (IvarsInfo.empty())
+ return llvm::Constant::getNullValue(PtrTy);
+
+ // Sort on byte position in case we encounterred a union nested in
+ // the ivar list.
+ if (hasUnion && !IvarsInfo.empty())
+ std::sort(IvarsInfo.begin(), IvarsInfo.end());
+ if (hasUnion && !SkipIvars.empty())
+ std::sort(SkipIvars.begin(), SkipIvars.end());
+
+ // Build the string of skip/scan nibbles
+ llvm::SmallVector<SKIP_SCAN, 32> SkipScanIvars;
+ unsigned int WordSize =
+ CGM.getTypes().getTargetData().getTypeAllocSize(PtrTy);
+ if (IvarsInfo[0].ivar_bytepos == 0) {
+ WordsToSkip = 0;
+ WordsToScan = IvarsInfo[0].ivar_size;
+ } else {
+ WordsToSkip = IvarsInfo[0].ivar_bytepos/WordSize;
+ WordsToScan = IvarsInfo[0].ivar_size;
+ }
+ for (unsigned int i=1, Last=IvarsInfo.size(); i != Last; i++) {
+ unsigned int TailPrevGCObjC =
+ IvarsInfo[i-1].ivar_bytepos + IvarsInfo[i-1].ivar_size * WordSize;
+ if (IvarsInfo[i].ivar_bytepos == TailPrevGCObjC) {
+ // consecutive 'scanned' object pointers.
+ WordsToScan += IvarsInfo[i].ivar_size;
+ } else {
+ // Skip over 'gc'able object pointer which lay over each other.
+ if (TailPrevGCObjC > IvarsInfo[i].ivar_bytepos)
+ continue;
+ // Must skip over 1 or more words. We save current skip/scan values
+ // and start a new pair.
+ SKIP_SCAN SkScan;
+ SkScan.skip = WordsToSkip;
+ SkScan.scan = WordsToScan;
+ SkipScanIvars.push_back(SkScan);
+
+ // Skip the hole.
+ SkScan.skip = (IvarsInfo[i].ivar_bytepos - TailPrevGCObjC) / WordSize;
+ SkScan.scan = 0;
+ SkipScanIvars.push_back(SkScan);
+ WordsToSkip = 0;
+ WordsToScan = IvarsInfo[i].ivar_size;
+ }
+ }
+ if (WordsToScan > 0) {
+ SKIP_SCAN SkScan;
+ SkScan.skip = WordsToSkip;
+ SkScan.scan = WordsToScan;
+ SkipScanIvars.push_back(SkScan);
+ }
+
+ bool BytesSkipped = false;
+ if (!SkipIvars.empty()) {
+ unsigned int LastIndex = SkipIvars.size()-1;
+ int LastByteSkipped =
+ SkipIvars[LastIndex].ivar_bytepos + SkipIvars[LastIndex].ivar_size;
+ LastIndex = IvarsInfo.size()-1;
+ int LastByteScanned =
+ IvarsInfo[LastIndex].ivar_bytepos +
+ IvarsInfo[LastIndex].ivar_size * WordSize;
+ BytesSkipped = (LastByteSkipped > LastByteScanned);
+ // Compute number of bytes to skip at the tail end of the last ivar scanned.
+ if (BytesSkipped) {
+ unsigned int TotalWords = (LastByteSkipped + (WordSize -1)) / WordSize;
+ SKIP_SCAN SkScan;
+ SkScan.skip = TotalWords - (LastByteScanned/WordSize);
+ SkScan.scan = 0;
+ SkipScanIvars.push_back(SkScan);
+ }
+ }
+ // Mini optimization of nibbles such that an 0xM0 followed by 0x0N is produced
+ // as 0xMN.
+ int SkipScan = SkipScanIvars.size()-1;
+ for (int i = 0; i <= SkipScan; i++) {
+ if ((i < SkipScan) && SkipScanIvars[i].skip && SkipScanIvars[i].scan == 0
+ && SkipScanIvars[i+1].skip == 0 && SkipScanIvars[i+1].scan) {
+ // 0xM0 followed by 0x0N detected.
+ SkipScanIvars[i].scan = SkipScanIvars[i+1].scan;
+ for (int j = i+1; j < SkipScan; j++)
+ SkipScanIvars[j] = SkipScanIvars[j+1];
+ --SkipScan;
+ }
+ }
+
+ // Generate the string.
+ std::string BitMap;
+ for (int i = 0; i <= SkipScan; i++) {
+ unsigned char byte;
+ unsigned int skip_small = SkipScanIvars[i].skip % 0xf;
+ unsigned int scan_small = SkipScanIvars[i].scan % 0xf;
+ unsigned int skip_big = SkipScanIvars[i].skip / 0xf;
+ unsigned int scan_big = SkipScanIvars[i].scan / 0xf;
+
+ if (skip_small > 0 || skip_big > 0)
+ BytesSkipped = true;
+ // first skip big.
+ for (unsigned int ix = 0; ix < skip_big; ix++)
+ BitMap += (unsigned char)(0xf0);
+
+ // next (skip small, scan)
+ if (skip_small) {
+ byte = skip_small << 4;
+ if (scan_big > 0) {
+ byte |= 0xf;
+ --scan_big;
+ } else if (scan_small) {
+ byte |= scan_small;
+ scan_small = 0;
+ }
+ BitMap += byte;
+ }
+ // next scan big
+ for (unsigned int ix = 0; ix < scan_big; ix++)
+ BitMap += (unsigned char)(0x0f);
+ // last scan small
+ if (scan_small) {
+ byte = scan_small;
+ BitMap += byte;
+ }
+ }
+ // null terminate string.
+ unsigned char zero = 0;
+ BitMap += zero;
+
+ if (CGM.getLangOptions().ObjCGCBitmapPrint) {
+ printf("\n%s ivar layout for class '%s': ",
+ ForStrongLayout ? "strong" : "weak",
+ OMD->getClassInterface()->getNameAsCString());
+ const unsigned char *s = (unsigned char*)BitMap.c_str();
+ for (unsigned i = 0; i < BitMap.size(); i++)
+ if (!(s[i] & 0xf0))
+ printf("0x0%x%s", s[i], s[i] != 0 ? ", " : "");
+ else
+ printf("0x%x%s", s[i], s[i] != 0 ? ", " : "");
+ printf("\n");
+ }
+
+ // if ivar_layout bitmap is all 1 bits (nothing skipped) then use NULL as
+ // final layout.
+ if (ForStrongLayout && !BytesSkipped)
+ return llvm::Constant::getNullValue(PtrTy);
+ llvm::GlobalVariable * Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
+ llvm::ConstantArray::get(BitMap.c_str()),
+ "__TEXT,__cstring,cstring_literals",
+ 1, true);
+ return getConstantGEP(Entry, 0, 0);
+}
+
+llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) {
+ llvm::GlobalVariable *&Entry = MethodVarNames[Sel];
+
+ // FIXME: Avoid std::string copying.
+ if (!Entry)
+ Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_NAME_",
+ llvm::ConstantArray::get(Sel.getAsString()),
+ "__TEXT,__cstring,cstring_literals",
+ 1, true);
+
+ return getConstantGEP(Entry, 0, 0);
+}
+
+// FIXME: Merge into a single cstring creation function.
+llvm::Constant *CGObjCCommonMac::GetMethodVarName(IdentifierInfo *ID) {
+ return GetMethodVarName(CGM.getContext().Selectors.getNullarySelector(ID));
+}
+
+// FIXME: Merge into a single cstring creation function.
+llvm::Constant *CGObjCCommonMac::GetMethodVarName(const std::string &Name) {
+ return GetMethodVarName(&CGM.getContext().Idents.get(Name));
+}
+
+llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) {
+ std::string TypeStr;
+ CGM.getContext().getObjCEncodingForType(Field->getType(), TypeStr, Field);
+
+ llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
+
+ if (!Entry)
+ Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_",
+ llvm::ConstantArray::get(TypeStr),
+ "__TEXT,__cstring,cstring_literals",
+ 1, true);
+
+ return getConstantGEP(Entry, 0, 0);
+}
+
+llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D) {
+ std::string TypeStr;
+ CGM.getContext().getObjCEncodingForMethodDecl(const_cast<ObjCMethodDecl*>(D),
+ TypeStr);
+
+ llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
+
+ if (!Entry)
+ Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_",
+ llvm::ConstantArray::get(TypeStr),
+ "__TEXT,__cstring,cstring_literals",
+ 1, true);
+
+ return getConstantGEP(Entry, 0, 0);
+}
+
+// FIXME: Merge into a single cstring creation function.
+llvm::Constant *CGObjCCommonMac::GetPropertyName(IdentifierInfo *Ident) {
+ llvm::GlobalVariable *&Entry = PropertyNames[Ident];
+
+ if (!Entry)
+ Entry = CreateMetadataVar("\01L_OBJC_PROP_NAME_ATTR_",
+ llvm::ConstantArray::get(Ident->getName()),
+ "__TEXT,__cstring,cstring_literals",
+ 1, true);
+
+ return getConstantGEP(Entry, 0, 0);
+}
+
+// FIXME: Merge into a single cstring creation function.
+// FIXME: This Decl should be more precise.
+llvm::Constant *
+ CGObjCCommonMac::GetPropertyTypeString(const ObjCPropertyDecl *PD,
+ const Decl *Container) {
+ std::string TypeStr;
+ CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container, TypeStr);
+ return GetPropertyName(&CGM.getContext().Idents.get(TypeStr));
+}
+
+void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D,
+ const ObjCContainerDecl *CD,
+ std::string &NameOut) {
+ NameOut = '\01';
+ NameOut += (D->isInstanceMethod() ? '-' : '+');
+ NameOut += '[';
+ assert (CD && "Missing container decl in GetNameForMethod");
+ NameOut += CD->getNameAsString();
+ if (const ObjCCategoryImplDecl *CID =
+ dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext())) {
+ NameOut += '(';
+ NameOut += CID->getNameAsString();
+ NameOut+= ')';
+ }
+ NameOut += ' ';
+ NameOut += D->getSelector().getAsString();
+ NameOut += ']';
+}
+
+void CGObjCMac::FinishModule() {
+ EmitModuleInfo();
+
+ // Emit the dummy bodies for any protocols which were referenced but
+ // never defined.
+ for (llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*>::iterator
+ i = Protocols.begin(), e = Protocols.end(); i != e; ++i) {
+ if (i->second->hasInitializer())
+ continue;
+
+ std::vector<llvm::Constant*> Values(5);
+ Values[0] = llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
+ Values[1] = GetClassName(i->first);
+ Values[2] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
+ Values[3] = Values[4] =
+ llvm::Constant::getNullValue(ObjCTypes.MethodDescriptionListPtrTy);
+ i->second->setLinkage(llvm::GlobalValue::InternalLinkage);
+ i->second->setInitializer(llvm::ConstantStruct::get(ObjCTypes.ProtocolTy,
+ Values));
+ }
+
+ std::vector<llvm::Constant*> Used;
+ for (std::vector<llvm::GlobalVariable*>::iterator i = UsedGlobals.begin(),
+ e = UsedGlobals.end(); i != e; ++i) {
+ Used.push_back(llvm::ConstantExpr::getBitCast(*i, ObjCTypes.Int8PtrTy));
+ }
+
+ llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.Int8PtrTy, Used.size());
+ llvm::GlobalValue *GV =
+ new llvm::GlobalVariable(AT, false,
+ llvm::GlobalValue::AppendingLinkage,
+ llvm::ConstantArray::get(AT, Used),
+ "llvm.used",
+ &CGM.getModule());
+
+ GV->setSection("llvm.metadata");
+
+ // Add assembler directives to add lazy undefined symbol references
+ // for classes which are referenced but not defined. This is
+ // important for correct linker interaction.
+
+ // FIXME: Uh, this isn't particularly portable.
+ std::stringstream s;
+
+ if (!CGM.getModule().getModuleInlineAsm().empty())
+ s << "\n";
+
+ for (std::set<IdentifierInfo*>::iterator i = LazySymbols.begin(),
+ e = LazySymbols.end(); i != e; ++i) {
+ s << "\t.lazy_reference .objc_class_name_" << (*i)->getName() << "\n";
+ }
+ for (std::set<IdentifierInfo*>::iterator i = DefinedSymbols.begin(),
+ e = DefinedSymbols.end(); i != e; ++i) {
+ s << "\t.objc_class_name_" << (*i)->getName() << "=0\n"
+ << "\t.globl .objc_class_name_" << (*i)->getName() << "\n";
+ }
+
+ CGM.getModule().appendModuleInlineAsm(s.str());
+}
+
+CGObjCNonFragileABIMac::CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm)
+ : CGObjCCommonMac(cgm),
+ ObjCTypes(cgm)
+{
+ ObjCEmptyCacheVar = ObjCEmptyVtableVar = NULL;
+ ObjCABI = 2;
+}
+
+/* *** */
+
+ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
+: CGM(cgm)
+{
+ CodeGen::CodeGenTypes &Types = CGM.getTypes();
+ ASTContext &Ctx = CGM.getContext();
+
+ ShortTy = Types.ConvertType(Ctx.ShortTy);
+ IntTy = Types.ConvertType(Ctx.IntTy);
+ LongTy = Types.ConvertType(Ctx.LongTy);
+ LongLongTy = Types.ConvertType(Ctx.LongLongTy);
+ Int8PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+
+ ObjectPtrTy = Types.ConvertType(Ctx.getObjCIdType());
+ PtrObjectPtrTy = llvm::PointerType::getUnqual(ObjectPtrTy);
+ SelectorPtrTy = Types.ConvertType(Ctx.getObjCSelType());
+
+ // 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());
+ ExternalProtocolPtrTy = llvm::PointerType::getUnqual(T);
+
+ // I'm not sure I like this. The implicit coordination is a bit
+ // gross. We should solve this in a reasonable fashion because this
+ // is a pretty common task (match some runtime data structure with
+ // an LLVM data structure).
+
+ // FIXME: This is leaked.
+ // FIXME: Merge with rewriter code?
+
+ // struct _objc_super {
+ // id self;
+ // Class cls;
+ // }
+ RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0,
+ SourceLocation(),
+ &Ctx.Idents.get("_objc_super"));
+ RD->addDecl(Ctx, FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
+ Ctx.getObjCIdType(), 0, false));
+ RD->addDecl(Ctx, FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
+ Ctx.getObjCClassType(), 0, false));
+ RD->completeDefinition(Ctx);
+
+ SuperCTy = Ctx.getTagDeclType(RD);
+ SuperPtrCTy = Ctx.getPointerType(SuperCTy);
+
+ SuperTy = cast<llvm::StructType>(Types.ConvertType(SuperCTy));
+ SuperPtrTy = llvm::PointerType::getUnqual(SuperTy);
+
+ // struct _prop_t {
+ // char *name;
+ // char *attributes;
+ // }
+ PropertyTy = llvm::StructType::get(Int8PtrTy, Int8PtrTy, NULL);
+ CGM.getModule().addTypeName("struct._prop_t",
+ PropertyTy);
+
+ // struct _prop_list_t {
+ // uint32_t entsize; // sizeof(struct _prop_t)
+ // uint32_t count_of_properties;
+ // struct _prop_t prop_list[count_of_properties];
+ // }
+ PropertyListTy = llvm::StructType::get(IntTy,
+ IntTy,
+ llvm::ArrayType::get(PropertyTy, 0),
+ NULL);
+ CGM.getModule().addTypeName("struct._prop_list_t",
+ PropertyListTy);
+ // struct _prop_list_t *
+ PropertyListPtrTy = llvm::PointerType::getUnqual(PropertyListTy);
+
+ // struct _objc_method {
+ // SEL _cmd;
+ // char *method_type;
+ // char *_imp;
+ // }
+ MethodTy = llvm::StructType::get(SelectorPtrTy,
+ Int8PtrTy,
+ Int8PtrTy,
+ NULL);
+ CGM.getModule().addTypeName("struct._objc_method", MethodTy);
+
+ // struct _objc_cache *
+ CacheTy = llvm::OpaqueType::get();
+ CGM.getModule().addTypeName("struct._objc_cache", CacheTy);
+ CachePtrTy = llvm::PointerType::getUnqual(CacheTy);
+}
+
+ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
+ : ObjCCommonTypesHelper(cgm)
+{
+ // struct _objc_method_description {
+ // SEL name;
+ // char *types;
+ // }
+ MethodDescriptionTy =
+ llvm::StructType::get(SelectorPtrTy,
+ Int8PtrTy,
+ NULL);
+ CGM.getModule().addTypeName("struct._objc_method_description",
+ MethodDescriptionTy);
+
+ // struct _objc_method_description_list {
+ // int count;
+ // struct _objc_method_description[1];
+ // }
+ MethodDescriptionListTy =
+ llvm::StructType::get(IntTy,
+ llvm::ArrayType::get(MethodDescriptionTy, 0),
+ NULL);
+ CGM.getModule().addTypeName("struct._objc_method_description_list",
+ MethodDescriptionListTy);
+
+ // struct _objc_method_description_list *
+ MethodDescriptionListPtrTy =
+ llvm::PointerType::getUnqual(MethodDescriptionListTy);
+
+ // Protocol description structures
+
+ // struct _objc_protocol_extension {
+ // uint32_t size; // sizeof(struct _objc_protocol_extension)
+ // struct _objc_method_description_list *optional_instance_methods;
+ // struct _objc_method_description_list *optional_class_methods;
+ // struct _objc_property_list *instance_properties;
+ // }
+ ProtocolExtensionTy =
+ llvm::StructType::get(IntTy,
+ MethodDescriptionListPtrTy,
+ MethodDescriptionListPtrTy,
+ PropertyListPtrTy,
+ NULL);
+ CGM.getModule().addTypeName("struct._objc_protocol_extension",
+ ProtocolExtensionTy);
+
+ // struct _objc_protocol_extension *
+ ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy);
+
+ // Handle recursive construction of Protocol and ProtocolList types
+
+ llvm::PATypeHolder ProtocolTyHolder = llvm::OpaqueType::get();
+ llvm::PATypeHolder ProtocolListTyHolder = llvm::OpaqueType::get();
+
+ const llvm::Type *T =
+ llvm::StructType::get(llvm::PointerType::getUnqual(ProtocolListTyHolder),
+ LongTy,
+ llvm::ArrayType::get(ProtocolTyHolder, 0),
+ NULL);
+ cast<llvm::OpaqueType>(ProtocolListTyHolder.get())->refineAbstractTypeTo(T);
+
+ // struct _objc_protocol {
+ // struct _objc_protocol_extension *isa;
+ // char *protocol_name;
+ // struct _objc_protocol **_objc_protocol_list;
+ // struct _objc_method_description_list *instance_methods;
+ // struct _objc_method_description_list *class_methods;
+ // }
+ T = llvm::StructType::get(ProtocolExtensionPtrTy,
+ Int8PtrTy,
+ llvm::PointerType::getUnqual(ProtocolListTyHolder),
+ MethodDescriptionListPtrTy,
+ MethodDescriptionListPtrTy,
+ NULL);
+ cast<llvm::OpaqueType>(ProtocolTyHolder.get())->refineAbstractTypeTo(T);
+
+ ProtocolListTy = cast<llvm::StructType>(ProtocolListTyHolder.get());
+ CGM.getModule().addTypeName("struct._objc_protocol_list",
+ ProtocolListTy);
+ // struct _objc_protocol_list *
+ ProtocolListPtrTy = llvm::PointerType::getUnqual(ProtocolListTy);
+
+ ProtocolTy = cast<llvm::StructType>(ProtocolTyHolder.get());
+ CGM.getModule().addTypeName("struct._objc_protocol", ProtocolTy);
+ ProtocolPtrTy = llvm::PointerType::getUnqual(ProtocolTy);
+
+ // Class description structures
+
+ // struct _objc_ivar {
+ // char *ivar_name;
+ // char *ivar_type;
+ // int ivar_offset;
+ // }
+ IvarTy = llvm::StructType::get(Int8PtrTy,
+ Int8PtrTy,
+ IntTy,
+ NULL);
+ CGM.getModule().addTypeName("struct._objc_ivar", IvarTy);
+
+ // struct _objc_ivar_list *
+ IvarListTy = llvm::OpaqueType::get();
+ CGM.getModule().addTypeName("struct._objc_ivar_list", IvarListTy);
+ IvarListPtrTy = llvm::PointerType::getUnqual(IvarListTy);
+
+ // struct _objc_method_list *
+ MethodListTy = llvm::OpaqueType::get();
+ CGM.getModule().addTypeName("struct._objc_method_list", MethodListTy);
+ MethodListPtrTy = llvm::PointerType::getUnqual(MethodListTy);
+
+ // struct _objc_class_extension *
+ ClassExtensionTy =
+ llvm::StructType::get(IntTy,
+ Int8PtrTy,
+ PropertyListPtrTy,
+ NULL);
+ CGM.getModule().addTypeName("struct._objc_class_extension", ClassExtensionTy);
+ ClassExtensionPtrTy = llvm::PointerType::getUnqual(ClassExtensionTy);
+
+ llvm::PATypeHolder ClassTyHolder = llvm::OpaqueType::get();
+
+ // struct _objc_class {
+ // Class isa;
+ // Class super_class;
+ // char *name;
+ // long version;
+ // long info;
+ // long instance_size;
+ // struct _objc_ivar_list *ivars;
+ // struct _objc_method_list *methods;
+ // struct _objc_cache *cache;
+ // struct _objc_protocol_list *protocols;
+ // char *ivar_layout;
+ // struct _objc_class_ext *ext;
+ // };
+ T = llvm::StructType::get(llvm::PointerType::getUnqual(ClassTyHolder),
+ llvm::PointerType::getUnqual(ClassTyHolder),
+ Int8PtrTy,
+ LongTy,
+ LongTy,
+ LongTy,
+ IvarListPtrTy,
+ MethodListPtrTy,
+ CachePtrTy,
+ ProtocolListPtrTy,
+ Int8PtrTy,
+ ClassExtensionPtrTy,
+ NULL);
+ cast<llvm::OpaqueType>(ClassTyHolder.get())->refineAbstractTypeTo(T);
+
+ ClassTy = cast<llvm::StructType>(ClassTyHolder.get());
+ CGM.getModule().addTypeName("struct._objc_class", ClassTy);
+ ClassPtrTy = llvm::PointerType::getUnqual(ClassTy);
+
+ // struct _objc_category {
+ // char *category_name;
+ // char *class_name;
+ // struct _objc_method_list *instance_method;
+ // struct _objc_method_list *class_method;
+ // uint32_t size; // sizeof(struct _objc_category)
+ // struct _objc_property_list *instance_properties;// category's @property
+ // }
+ CategoryTy = llvm::StructType::get(Int8PtrTy,
+ Int8PtrTy,
+ MethodListPtrTy,
+ MethodListPtrTy,
+ ProtocolListPtrTy,
+ IntTy,
+ PropertyListPtrTy,
+ NULL);
+ CGM.getModule().addTypeName("struct._objc_category", CategoryTy);
+
+ // Global metadata structures
+
+ // struct _objc_symtab {
+ // long sel_ref_cnt;
+ // SEL *refs;
+ // short cls_def_cnt;
+ // short cat_def_cnt;
+ // char *defs[cls_def_cnt + cat_def_cnt];
+ // }
+ SymtabTy = llvm::StructType::get(LongTy,
+ SelectorPtrTy,
+ ShortTy,
+ ShortTy,
+ llvm::ArrayType::get(Int8PtrTy, 0),
+ NULL);
+ CGM.getModule().addTypeName("struct._objc_symtab", SymtabTy);
+ SymtabPtrTy = llvm::PointerType::getUnqual(SymtabTy);
+
+ // struct _objc_module {
+ // long version;
+ // long size; // sizeof(struct _objc_module)
+ // char *name;
+ // struct _objc_symtab* symtab;
+ // }
+ ModuleTy =
+ llvm::StructType::get(LongTy,
+ LongTy,
+ Int8PtrTy,
+ SymtabPtrTy,
+ NULL);
+ CGM.getModule().addTypeName("struct._objc_module", ModuleTy);
+
+
+ // FIXME: This is the size of the setjmp buffer and should be target
+ // specific. 18 is what's used on 32-bit X86.
+ uint64_t SetJmpBufferSize = 18;
+
+ // Exceptions
+ const llvm::Type *StackPtrTy =
+ llvm::ArrayType::get(llvm::PointerType::getUnqual(llvm::Type::Int8Ty), 4);
+
+ ExceptionDataTy =
+ llvm::StructType::get(llvm::ArrayType::get(llvm::Type::Int32Ty,
+ SetJmpBufferSize),
+ StackPtrTy, NULL);
+ CGM.getModule().addTypeName("struct._objc_exception_data",
+ ExceptionDataTy);
+
+}
+
+ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm)
+: ObjCCommonTypesHelper(cgm)
+{
+ // struct _method_list_t {
+ // uint32_t entsize; // sizeof(struct _objc_method)
+ // uint32_t method_count;
+ // struct _objc_method method_list[method_count];
+ // }
+ MethodListnfABITy = llvm::StructType::get(IntTy,
+ IntTy,
+ llvm::ArrayType::get(MethodTy, 0),
+ NULL);
+ CGM.getModule().addTypeName("struct.__method_list_t",
+ MethodListnfABITy);
+ // struct method_list_t *
+ MethodListnfABIPtrTy = llvm::PointerType::getUnqual(MethodListnfABITy);
+
+ // struct _protocol_t {
+ // id isa; // NULL
+ // const char * const protocol_name;
+ // const struct _protocol_list_t * protocol_list; // super protocols
+ // const struct method_list_t * const instance_methods;
+ // const struct method_list_t * const class_methods;
+ // const struct method_list_t *optionalInstanceMethods;
+ // const struct method_list_t *optionalClassMethods;
+ // const struct _prop_list_t * properties;
+ // const uint32_t size; // sizeof(struct _protocol_t)
+ // const uint32_t flags; // = 0
+ // }
+
+ // Holder for struct _protocol_list_t *
+ llvm::PATypeHolder ProtocolListTyHolder = llvm::OpaqueType::get();
+
+ ProtocolnfABITy = llvm::StructType::get(ObjectPtrTy,
+ Int8PtrTy,
+ llvm::PointerType::getUnqual(
+ ProtocolListTyHolder),
+ MethodListnfABIPtrTy,
+ MethodListnfABIPtrTy,
+ MethodListnfABIPtrTy,
+ MethodListnfABIPtrTy,
+ PropertyListPtrTy,
+ IntTy,
+ IntTy,
+ NULL);
+ CGM.getModule().addTypeName("struct._protocol_t",
+ ProtocolnfABITy);
+
+ // struct _protocol_t*
+ ProtocolnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolnfABITy);
+
+ // struct _protocol_list_t {
+ // long protocol_count; // Note, this is 32/64 bit
+ // struct _protocol_t *[protocol_count];
+ // }
+ ProtocolListnfABITy = llvm::StructType::get(LongTy,
+ llvm::ArrayType::get(
+ ProtocolnfABIPtrTy, 0),
+ NULL);
+ CGM.getModule().addTypeName("struct._objc_protocol_list",
+ ProtocolListnfABITy);
+ cast<llvm::OpaqueType>(ProtocolListTyHolder.get())->refineAbstractTypeTo(
+ ProtocolListnfABITy);
+
+ // struct _objc_protocol_list*
+ ProtocolListnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolListnfABITy);
+
+ // struct _ivar_t {
+ // unsigned long int *offset; // pointer to ivar offset location
+ // char *name;
+ // char *type;
+ // uint32_t alignment;
+ // uint32_t size;
+ // }
+ IvarnfABITy = llvm::StructType::get(llvm::PointerType::getUnqual(LongTy),
+ Int8PtrTy,
+ Int8PtrTy,
+ IntTy,
+ IntTy,
+ NULL);
+ CGM.getModule().addTypeName("struct._ivar_t", IvarnfABITy);
+
+ // struct _ivar_list_t {
+ // uint32 entsize; // sizeof(struct _ivar_t)
+ // uint32 count;
+ // struct _iver_t list[count];
+ // }
+ IvarListnfABITy = llvm::StructType::get(IntTy,
+ IntTy,
+ llvm::ArrayType::get(
+ IvarnfABITy, 0),
+ NULL);
+ CGM.getModule().addTypeName("struct._ivar_list_t", IvarListnfABITy);
+
+ IvarListnfABIPtrTy = llvm::PointerType::getUnqual(IvarListnfABITy);
+
+ // struct _class_ro_t {
+ // uint32_t const flags;
+ // uint32_t const instanceStart;
+ // uint32_t const instanceSize;
+ // uint32_t const reserved; // only when building for 64bit targets
+ // const uint8_t * const ivarLayout;
+ // const char *const name;
+ // const struct _method_list_t * const baseMethods;
+ // const struct _objc_protocol_list *const baseProtocols;
+ // const struct _ivar_list_t *const ivars;
+ // const uint8_t * const weakIvarLayout;
+ // const struct _prop_list_t * const properties;
+ // }
+
+ // FIXME. Add 'reserved' field in 64bit abi mode!
+ ClassRonfABITy = llvm::StructType::get(IntTy,
+ IntTy,
+ IntTy,
+ Int8PtrTy,
+ Int8PtrTy,
+ MethodListnfABIPtrTy,
+ ProtocolListnfABIPtrTy,
+ IvarListnfABIPtrTy,
+ Int8PtrTy,
+ PropertyListPtrTy,
+ NULL);
+ CGM.getModule().addTypeName("struct._class_ro_t",
+ ClassRonfABITy);
+
+ // ImpnfABITy - LLVM for id (*)(id, SEL, ...)
+ std::vector<const llvm::Type*> Params;
+ Params.push_back(ObjectPtrTy);
+ Params.push_back(SelectorPtrTy);
+ ImpnfABITy = llvm::PointerType::getUnqual(
+ llvm::FunctionType::get(ObjectPtrTy, Params, false));
+
+ // struct _class_t {
+ // struct _class_t *isa;
+ // struct _class_t * const superclass;
+ // void *cache;
+ // IMP *vtable;
+ // struct class_ro_t *ro;
+ // }
+
+ llvm::PATypeHolder ClassTyHolder = llvm::OpaqueType::get();
+ ClassnfABITy = llvm::StructType::get(llvm::PointerType::getUnqual(ClassTyHolder),
+ llvm::PointerType::getUnqual(ClassTyHolder),
+ CachePtrTy,
+ llvm::PointerType::getUnqual(ImpnfABITy),
+ llvm::PointerType::getUnqual(
+ ClassRonfABITy),
+ NULL);
+ CGM.getModule().addTypeName("struct._class_t", ClassnfABITy);
+
+ cast<llvm::OpaqueType>(ClassTyHolder.get())->refineAbstractTypeTo(
+ ClassnfABITy);
+
+ // LLVM for struct _class_t *
+ ClassnfABIPtrTy = llvm::PointerType::getUnqual(ClassnfABITy);
+
+ // struct _category_t {
+ // const char * const name;
+ // struct _class_t *const cls;
+ // const struct _method_list_t * const instance_methods;
+ // const struct _method_list_t * const class_methods;
+ // const struct _protocol_list_t * const protocols;
+ // const struct _prop_list_t * const properties;
+ // }
+ CategorynfABITy = llvm::StructType::get(Int8PtrTy,
+ ClassnfABIPtrTy,
+ MethodListnfABIPtrTy,
+ MethodListnfABIPtrTy,
+ ProtocolListnfABIPtrTy,
+ PropertyListPtrTy,
+ NULL);
+ CGM.getModule().addTypeName("struct._category_t", CategorynfABITy);
+
+ // New types for nonfragile abi messaging.
+ CodeGen::CodeGenTypes &Types = CGM.getTypes();
+ ASTContext &Ctx = CGM.getContext();
+
+ // MessageRefTy - LLVM for:
+ // struct _message_ref_t {
+ // IMP messenger;
+ // SEL name;
+ // };
+
+ // First the clang type for struct _message_ref_t
+ RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0,
+ SourceLocation(),
+ &Ctx.Idents.get("_message_ref_t"));
+ RD->addDecl(Ctx, FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
+ Ctx.VoidPtrTy, 0, false));
+ RD->addDecl(Ctx, FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
+ Ctx.getObjCSelType(), 0, false));
+ RD->completeDefinition(Ctx);
+
+ MessageRefCTy = Ctx.getTagDeclType(RD);
+ MessageRefCPtrTy = Ctx.getPointerType(MessageRefCTy);
+ MessageRefTy = cast<llvm::StructType>(Types.ConvertType(MessageRefCTy));
+
+ // MessageRefPtrTy - LLVM for struct _message_ref_t*
+ MessageRefPtrTy = llvm::PointerType::getUnqual(MessageRefTy);
+
+ // SuperMessageRefTy - LLVM for:
+ // struct _super_message_ref_t {
+ // SUPER_IMP messenger;
+ // SEL name;
+ // };
+ SuperMessageRefTy = llvm::StructType::get(ImpnfABITy,
+ SelectorPtrTy,
+ NULL);
+ CGM.getModule().addTypeName("struct._super_message_ref_t", SuperMessageRefTy);
+
+ // SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
+ SuperMessageRefPtrTy = llvm::PointerType::getUnqual(SuperMessageRefTy);
+
+
+ // struct objc_typeinfo {
+ // const void** vtable; // objc_ehtype_vtable + 2
+ // const char* name; // c++ typeinfo string
+ // Class cls;
+ // };
+ EHTypeTy = llvm::StructType::get(llvm::PointerType::getUnqual(Int8PtrTy),
+ Int8PtrTy,
+ ClassnfABIPtrTy,
+ NULL);
+ CGM.getModule().addTypeName("struct._objc_typeinfo", EHTypeTy);
+ EHTypePtrTy = llvm::PointerType::getUnqual(EHTypeTy);
+}
+
+llvm::Function *CGObjCNonFragileABIMac::ModuleInitFunction() {
+ FinishNonFragileABIModule();
+
+ return NULL;
+}
+
+void CGObjCNonFragileABIMac::AddModuleClassList(const
+ std::vector<llvm::GlobalValue*>
+ &Container,
+ const char *SymbolName,
+ const char *SectionName) {
+ unsigned NumClasses = Container.size();
+
+ if (!NumClasses)
+ return;
+
+ std::vector<llvm::Constant*> Symbols(NumClasses);
+ for (unsigned i=0; i<NumClasses; i++)
+ Symbols[i] = llvm::ConstantExpr::getBitCast(Container[i],
+ ObjCTypes.Int8PtrTy);
+ llvm::Constant* Init =
+ llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
+ NumClasses),
+ Symbols);
+
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(Init->getType(), false,
+ llvm::GlobalValue::InternalLinkage,
+ Init,
+ SymbolName,
+ &CGM.getModule());
+ GV->setAlignment(8);
+ GV->setSection(SectionName);
+ UsedGlobals.push_back(GV);
+}
+
+void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
+ // nonfragile abi has no module definition.
+
+ // Build list of all implemented class addresses in array
+ // L_OBJC_LABEL_CLASS_$.
+ AddModuleClassList(DefinedClasses,
+ "\01L_OBJC_LABEL_CLASS_$",
+ "__DATA, __objc_classlist, regular, no_dead_strip");
+ AddModuleClassList(DefinedNonLazyClasses,
+ "\01L_OBJC_LABEL_NONLAZY_CLASS_$",
+ "__DATA, __objc_nlclslist, regular, no_dead_strip");
+
+ // Build list of all implemented category addresses in array
+ // L_OBJC_LABEL_CATEGORY_$.
+ AddModuleClassList(DefinedCategories,
+ "\01L_OBJC_LABEL_CATEGORY_$",
+ "__DATA, __objc_catlist, regular, no_dead_strip");
+ AddModuleClassList(DefinedNonLazyCategories,
+ "\01L_OBJC_LABEL_NONLAZY_CATEGORY_$",
+ "__DATA, __objc_nlcatlist, regular, no_dead_strip");
+
+ // static int L_OBJC_IMAGE_INFO[2] = { 0, flags };
+ // FIXME. flags can be 0 | 1 | 2 | 6. For now just use 0
+ std::vector<llvm::Constant*> Values(2);
+ Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, 0);
+ unsigned int flags = 0;
+ // FIXME: Fix and continue?
+ if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC)
+ flags |= eImageInfo_GarbageCollected;
+ if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly)
+ flags |= eImageInfo_GCOnly;
+ Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags);
+ llvm::Constant* Init = llvm::ConstantArray::get(
+ llvm::ArrayType::get(ObjCTypes.IntTy, 2),
+ Values);
+ llvm::GlobalVariable *IMGV =
+ new llvm::GlobalVariable(Init->getType(), false,
+ llvm::GlobalValue::InternalLinkage,
+ Init,
+ "\01L_OBJC_IMAGE_INFO",
+ &CGM.getModule());
+ IMGV->setSection("__DATA, __objc_imageinfo, regular, no_dead_strip");
+ IMGV->setConstant(true);
+ UsedGlobals.push_back(IMGV);
+
+ std::vector<llvm::Constant*> Used;
+
+ for (std::vector<llvm::GlobalVariable*>::iterator i = UsedGlobals.begin(),
+ e = UsedGlobals.end(); i != e; ++i) {
+ Used.push_back(llvm::ConstantExpr::getBitCast(*i, ObjCTypes.Int8PtrTy));
+ }
+
+ llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.Int8PtrTy, Used.size());
+ llvm::GlobalValue *GV =
+ new llvm::GlobalVariable(AT, false,
+ llvm::GlobalValue::AppendingLinkage,
+ llvm::ConstantArray::get(AT, Used),
+ "llvm.used",
+ &CGM.getModule());
+
+ GV->setSection("llvm.metadata");
+
+}
+
+/// LegacyDispatchedSelector - Returns true if SEL is not in the list of
+/// NonLegacyDispatchMethods; false otherwise. What this means is that
+/// except for the 19 selectors in the list, we generate 32bit-style
+/// message dispatch call for all the rest.
+///
+bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) {
+ if (NonLegacyDispatchMethods.empty()) {
+ NonLegacyDispatchMethods.insert(GetNullarySelector("alloc"));
+ NonLegacyDispatchMethods.insert(GetNullarySelector("class"));
+ NonLegacyDispatchMethods.insert(GetNullarySelector("self"));
+ NonLegacyDispatchMethods.insert(GetNullarySelector("isFlipped"));
+ NonLegacyDispatchMethods.insert(GetNullarySelector("length"));
+ NonLegacyDispatchMethods.insert(GetNullarySelector("count"));
+ NonLegacyDispatchMethods.insert(GetNullarySelector("retain"));
+ NonLegacyDispatchMethods.insert(GetNullarySelector("release"));
+ NonLegacyDispatchMethods.insert(GetNullarySelector("autorelease"));
+ NonLegacyDispatchMethods.insert(GetNullarySelector("hash"));
+
+ NonLegacyDispatchMethods.insert(GetUnarySelector("allocWithZone"));
+ NonLegacyDispatchMethods.insert(GetUnarySelector("isKindOfClass"));
+ NonLegacyDispatchMethods.insert(GetUnarySelector("respondsToSelector"));
+ NonLegacyDispatchMethods.insert(GetUnarySelector("objectForKey"));
+ NonLegacyDispatchMethods.insert(GetUnarySelector("objectAtIndex"));
+ NonLegacyDispatchMethods.insert(GetUnarySelector("isEqualToString"));
+ NonLegacyDispatchMethods.insert(GetUnarySelector("isEqual"));
+ NonLegacyDispatchMethods.insert(GetUnarySelector("addObject"));
+ // "countByEnumeratingWithState:objects:count"
+ IdentifierInfo *KeyIdents[] = {
+ &CGM.getContext().Idents.get("countByEnumeratingWithState"),
+ &CGM.getContext().Idents.get("objects"),
+ &CGM.getContext().Idents.get("count")
+ };
+ NonLegacyDispatchMethods.insert(
+ CGM.getContext().Selectors.getSelector(3, KeyIdents));
+ }
+ return (NonLegacyDispatchMethods.count(Sel) == 0);
+}
+
+// Metadata flags
+enum MetaDataDlags {
+ CLS = 0x0,
+ CLS_META = 0x1,
+ CLS_ROOT = 0x2,
+ OBJC2_CLS_HIDDEN = 0x10,
+ CLS_EXCEPTION = 0x20
+};
+/// BuildClassRoTInitializer - generate meta-data for:
+/// struct _class_ro_t {
+/// uint32_t const flags;
+/// uint32_t const instanceStart;
+/// uint32_t const instanceSize;
+/// uint32_t const reserved; // only when building for 64bit targets
+/// const uint8_t * const ivarLayout;
+/// const char *const name;
+/// const struct _method_list_t * const baseMethods;
+/// const struct _protocol_list_t *const baseProtocols;
+/// const struct _ivar_list_t *const ivars;
+/// const uint8_t * const weakIvarLayout;
+/// const struct _prop_list_t * const properties;
+/// }
+///
+llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
+ unsigned flags,
+ unsigned InstanceStart,
+ unsigned InstanceSize,
+ const ObjCImplementationDecl *ID) {
+ std::string ClassName = ID->getNameAsString();
+ std::vector<llvm::Constant*> Values(10); // 11 for 64bit targets!
+ Values[ 0] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags);
+ Values[ 1] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceStart);
+ Values[ 2] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceSize);
+ // FIXME. For 64bit targets add 0 here.
+ Values[ 3] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes)
+ : BuildIvarLayout(ID, true);
+ Values[ 4] = GetClassName(ID->getIdentifier());
+ // const struct _method_list_t * const baseMethods;
+ std::vector<llvm::Constant*> Methods;
+ std::string MethodListName("\01l_OBJC_$_");
+ if (flags & CLS_META) {
+ MethodListName += "CLASS_METHODS_" + ID->getNameAsString();
+ for (ObjCImplementationDecl::classmeth_iterator
+ i = ID->classmeth_begin(CGM.getContext()),
+ e = ID->classmeth_end(CGM.getContext()); i != e; ++i) {
+ // Class methods should always be defined.
+ Methods.push_back(GetMethodConstant(*i));
+ }
+ } else {
+ MethodListName += "INSTANCE_METHODS_" + ID->getNameAsString();
+ for (ObjCImplementationDecl::instmeth_iterator
+ i = ID->instmeth_begin(CGM.getContext()),
+ e = ID->instmeth_end(CGM.getContext()); i != e; ++i) {
+ // Instance methods should always be defined.
+ Methods.push_back(GetMethodConstant(*i));
+ }
+ for (ObjCImplementationDecl::propimpl_iterator
+ i = ID->propimpl_begin(CGM.getContext()),
+ e = ID->propimpl_end(CGM.getContext()); i != e; ++i) {
+ ObjCPropertyImplDecl *PID = *i;
+
+ if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize){
+ ObjCPropertyDecl *PD = PID->getPropertyDecl();
+
+ if (ObjCMethodDecl *MD = PD->getGetterMethodDecl())
+ if (llvm::Constant *C = GetMethodConstant(MD))
+ Methods.push_back(C);
+ if (ObjCMethodDecl *MD = PD->getSetterMethodDecl())
+ if (llvm::Constant *C = GetMethodConstant(MD))
+ Methods.push_back(C);
+ }
+ }
+ }
+ Values[ 5] = EmitMethodList(MethodListName,
+ "__DATA, __objc_const", Methods);
+
+ const ObjCInterfaceDecl *OID = ID->getClassInterface();
+ assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer");
+ Values[ 6] = EmitProtocolList("\01l_OBJC_CLASS_PROTOCOLS_$_"
+ + OID->getNameAsString(),
+ OID->protocol_begin(),
+ OID->protocol_end());
+
+ if (flags & CLS_META)
+ Values[ 7] = llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
+ else
+ Values[ 7] = EmitIvarList(ID);
+ Values[ 8] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes)
+ : BuildIvarLayout(ID, false);
+ if (flags & CLS_META)
+ Values[ 9] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
+ else
+ Values[ 9] =
+ EmitPropertyList(
+ "\01l_OBJC_$_PROP_LIST_" + ID->getNameAsString(),
+ ID, ID->getClassInterface(), ObjCTypes);
+ llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassRonfABITy,
+ Values);
+ llvm::GlobalVariable *CLASS_RO_GV =
+ new llvm::GlobalVariable(ObjCTypes.ClassRonfABITy, false,
+ llvm::GlobalValue::InternalLinkage,
+ Init,
+ (flags & CLS_META) ?
+ std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName :
+ std::string("\01l_OBJC_CLASS_RO_$_")+ClassName,
+ &CGM.getModule());
+ CLASS_RO_GV->setAlignment(
+ CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ClassRonfABITy));
+ CLASS_RO_GV->setSection("__DATA, __objc_const");
+ return CLASS_RO_GV;
+
+}
+
+/// BuildClassMetaData - This routine defines that to-level meta-data
+/// for the given ClassName for:
+/// struct _class_t {
+/// struct _class_t *isa;
+/// struct _class_t * const superclass;
+/// void *cache;
+/// IMP *vtable;
+/// struct class_ro_t *ro;
+/// }
+///
+llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData(
+ std::string &ClassName,
+ llvm::Constant *IsAGV,
+ llvm::Constant *SuperClassGV,
+ llvm::Constant *ClassRoGV,
+ bool HiddenVisibility) {
+ std::vector<llvm::Constant*> Values(5);
+ Values[0] = IsAGV;
+ Values[1] = SuperClassGV
+ ? SuperClassGV
+ : llvm::Constant::getNullValue(ObjCTypes.ClassnfABIPtrTy);
+ Values[2] = ObjCEmptyCacheVar; // &ObjCEmptyCacheVar
+ Values[3] = ObjCEmptyVtableVar; // &ObjCEmptyVtableVar
+ Values[4] = ClassRoGV; // &CLASS_RO_GV
+ llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassnfABITy,
+ Values);
+ llvm::GlobalVariable *GV = GetClassGlobal(ClassName);
+ GV->setInitializer(Init);
+ GV->setSection("__DATA, __objc_data");
+ GV->setAlignment(
+ CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ClassnfABITy));
+ if (HiddenVisibility)
+ GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ return GV;
+}
+
+bool
+CGObjCNonFragileABIMac::ImplementationIsNonLazy(const ObjCImplDecl *OD) const {
+ return OD->getClassMethod(CGM.getContext(), GetNullarySelector("load")) != 0;
+}
+
+void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID,
+ uint32_t &InstanceStart,
+ uint32_t &InstanceSize) {
+ const ASTRecordLayout &RL =
+ CGM.getContext().getASTObjCImplementationLayout(OID);
+
+ // InstanceSize is really instance end.
+ InstanceSize = llvm::RoundUpToAlignment(RL.getNextOffset(), 8) / 8;
+
+ // If there are no fields, the start is the same as the end.
+ if (!RL.getFieldCount())
+ InstanceStart = InstanceSize;
+ else
+ InstanceStart = RL.getFieldOffset(0) / 8;
+}
+
+void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
+ std::string ClassName = ID->getNameAsString();
+ if (!ObjCEmptyCacheVar) {
+ ObjCEmptyCacheVar = new llvm::GlobalVariable(
+ ObjCTypes.CacheTy,
+ false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0,
+ "_objc_empty_cache",
+ &CGM.getModule());
+
+ ObjCEmptyVtableVar = new llvm::GlobalVariable(
+ ObjCTypes.ImpnfABITy,
+ false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0,
+ "_objc_empty_vtable",
+ &CGM.getModule());
+ }
+ assert(ID->getClassInterface() &&
+ "CGObjCNonFragileABIMac::GenerateClass - class is 0");
+ // FIXME: Is this correct (that meta class size is never computed)?
+ uint32_t InstanceStart =
+ CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassnfABITy);
+ uint32_t InstanceSize = InstanceStart;
+ uint32_t flags = CLS_META;
+ std::string ObjCMetaClassName(getMetaclassSymbolPrefix());
+ std::string ObjCClassName(getClassSymbolPrefix());
+
+ llvm::GlobalVariable *SuperClassGV, *IsAGV;
+
+ bool classIsHidden =
+ CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden;
+ if (classIsHidden)
+ flags |= OBJC2_CLS_HIDDEN;
+ if (!ID->getClassInterface()->getSuperClass()) {
+ // class is root
+ flags |= CLS_ROOT;
+ SuperClassGV = GetClassGlobal(ObjCClassName + ClassName);
+ IsAGV = GetClassGlobal(ObjCMetaClassName + ClassName);
+ } else {
+ // Has a root. Current class is not a root.
+ const ObjCInterfaceDecl *Root = ID->getClassInterface();
+ while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
+ Root = Super;
+ IsAGV = GetClassGlobal(ObjCMetaClassName + Root->getNameAsString());
+ // work on super class metadata symbol.
+ std::string SuperClassName =
+ ObjCMetaClassName + ID->getClassInterface()->getSuperClass()->getNameAsString();
+ SuperClassGV = GetClassGlobal(SuperClassName);
+ }
+ llvm::GlobalVariable *CLASS_RO_GV = BuildClassRoTInitializer(flags,
+ InstanceStart,
+ InstanceSize,ID);
+ std::string TClassName = ObjCMetaClassName + ClassName;
+ llvm::GlobalVariable *MetaTClass =
+ BuildClassMetaData(TClassName, IsAGV, SuperClassGV, CLASS_RO_GV,
+ classIsHidden);
+
+ // Metadata for the class
+ flags = CLS;
+ if (classIsHidden)
+ flags |= OBJC2_CLS_HIDDEN;
+
+ if (hasObjCExceptionAttribute(ID->getClassInterface()))
+ flags |= CLS_EXCEPTION;
+
+ if (!ID->getClassInterface()->getSuperClass()) {
+ flags |= CLS_ROOT;
+ SuperClassGV = 0;
+ } else {
+ // Has a root. Current class is not a root.
+ std::string RootClassName =
+ ID->getClassInterface()->getSuperClass()->getNameAsString();
+ SuperClassGV = GetClassGlobal(ObjCClassName + RootClassName);
+ }
+ GetClassSizeInfo(ID, InstanceStart, InstanceSize);
+ CLASS_RO_GV = BuildClassRoTInitializer(flags,
+ InstanceStart,
+ InstanceSize,
+ ID);
+
+ TClassName = ObjCClassName + ClassName;
+ llvm::GlobalVariable *ClassMD =
+ BuildClassMetaData(TClassName, MetaTClass, SuperClassGV, CLASS_RO_GV,
+ classIsHidden);
+ DefinedClasses.push_back(ClassMD);
+
+ // Determine if this class is also "non-lazy".
+ if (ImplementationIsNonLazy(ID))
+ DefinedNonLazyClasses.push_back(ClassMD);
+
+ // Force the definition of the EHType if necessary.
+ if (flags & CLS_EXCEPTION)
+ GetInterfaceEHType(ID->getClassInterface(), true);
+}
+
+/// GenerateProtocolRef - This routine is called to generate code for
+/// a protocol reference expression; as in:
+/// @code
+/// @protocol(Proto1);
+/// @endcode
+/// It generates a weak reference to l_OBJC_PROTOCOL_REFERENCE_$_Proto1
+/// which will hold address of the protocol meta-data.
+///
+llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
+ const ObjCProtocolDecl *PD) {
+
+ // This routine is called for @protocol only. So, we must build definition
+ // of protocol's meta-data (not a reference to it!)
+ //
+ llvm::Constant *Init = llvm::ConstantExpr::getBitCast(GetOrEmitProtocol(PD),
+ ObjCTypes.ExternalProtocolPtrTy);
+
+ std::string ProtocolName("\01l_OBJC_PROTOCOL_REFERENCE_$_");
+ ProtocolName += PD->getNameAsCString();
+
+ llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName);
+ if (PTGV)
+ return Builder.CreateLoad(PTGV, false, "tmp");
+ PTGV = new llvm::GlobalVariable(
+ Init->getType(), false,
+ llvm::GlobalValue::WeakAnyLinkage,
+ Init,
+ ProtocolName,
+ &CGM.getModule());
+ PTGV->setSection("__DATA, __objc_protorefs, coalesced, no_dead_strip");
+ PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ UsedGlobals.push_back(PTGV);
+ return Builder.CreateLoad(PTGV, false, "tmp");
+}
+
+/// GenerateCategory - Build metadata for a category implementation.
+/// struct _category_t {
+/// const char * const name;
+/// struct _class_t *const cls;
+/// const struct _method_list_t * const instance_methods;
+/// const struct _method_list_t * const class_methods;
+/// const struct _protocol_list_t * const protocols;
+/// const struct _prop_list_t * const properties;
+/// }
+///
+void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
+ const ObjCInterfaceDecl *Interface = OCD->getClassInterface();
+ const char *Prefix = "\01l_OBJC_$_CATEGORY_";
+ std::string ExtCatName(Prefix + Interface->getNameAsString()+
+ "_$_" + OCD->getNameAsString());
+ std::string ExtClassName(getClassSymbolPrefix() +
+ Interface->getNameAsString());
+
+ std::vector<llvm::Constant*> Values(6);
+ Values[0] = GetClassName(OCD->getIdentifier());
+ // meta-class entry symbol
+ llvm::GlobalVariable *ClassGV = GetClassGlobal(ExtClassName);
+ Values[1] = ClassGV;
+ std::vector<llvm::Constant*> Methods;
+ std::string MethodListName(Prefix);
+ MethodListName += "INSTANCE_METHODS_" + Interface->getNameAsString() +
+ "_$_" + OCD->getNameAsString();
+
+ for (ObjCCategoryImplDecl::instmeth_iterator
+ i = OCD->instmeth_begin(CGM.getContext()),
+ e = OCD->instmeth_end(CGM.getContext()); i != e; ++i) {
+ // Instance methods should always be defined.
+ Methods.push_back(GetMethodConstant(*i));
+ }
+
+ Values[2] = EmitMethodList(MethodListName,
+ "__DATA, __objc_const",
+ Methods);
+
+ MethodListName = Prefix;
+ MethodListName += "CLASS_METHODS_" + Interface->getNameAsString() + "_$_" +
+ OCD->getNameAsString();
+ Methods.clear();
+ for (ObjCCategoryImplDecl::classmeth_iterator
+ i = OCD->classmeth_begin(CGM.getContext()),
+ e = OCD->classmeth_end(CGM.getContext()); i != e; ++i) {
+ // Class methods should always be defined.
+ Methods.push_back(GetMethodConstant(*i));
+ }
+
+ Values[3] = EmitMethodList(MethodListName,
+ "__DATA, __objc_const",
+ Methods);
+ const ObjCCategoryDecl *Category =
+ Interface->FindCategoryDeclaration(OCD->getIdentifier());
+ if (Category) {
+ std::string ExtName(Interface->getNameAsString() + "_$_" +
+ OCD->getNameAsString());
+ Values[4] = EmitProtocolList("\01l_OBJC_CATEGORY_PROTOCOLS_$_"
+ + Interface->getNameAsString() + "_$_"
+ + Category->getNameAsString(),
+ Category->protocol_begin(),
+ Category->protocol_end());
+ Values[5] =
+ EmitPropertyList(std::string("\01l_OBJC_$_PROP_LIST_") + ExtName,
+ OCD, Category, ObjCTypes);
+ }
+ else {
+ Values[4] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy);
+ Values[5] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
+ }
+
+ llvm::Constant *Init =
+ llvm::ConstantStruct::get(ObjCTypes.CategorynfABITy,
+ Values);
+ llvm::GlobalVariable *GCATV
+ = new llvm::GlobalVariable(ObjCTypes.CategorynfABITy,
+ false,
+ llvm::GlobalValue::InternalLinkage,
+ Init,
+ ExtCatName,
+ &CGM.getModule());
+ GCATV->setAlignment(
+ CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.CategorynfABITy));
+ GCATV->setSection("__DATA, __objc_const");
+ UsedGlobals.push_back(GCATV);
+ DefinedCategories.push_back(GCATV);
+
+ // Determine if this category is also "non-lazy".
+ if (ImplementationIsNonLazy(OCD))
+ DefinedNonLazyCategories.push_back(GCATV);
+}
+
+/// GetMethodConstant - Return a struct objc_method constant for the
+/// given method if it has been defined. The result is null if the
+/// method has not been defined. The return value has type MethodPtrTy.
+llvm::Constant *CGObjCNonFragileABIMac::GetMethodConstant(
+ const ObjCMethodDecl *MD) {
+ // FIXME: Use DenseMap::lookup
+ llvm::Function *Fn = MethodDefinitions[MD];
+ if (!Fn)
+ return 0;
+
+ std::vector<llvm::Constant*> Method(3);
+ Method[0] =
+ llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
+ ObjCTypes.SelectorPtrTy);
+ Method[1] = GetMethodVarType(MD);
+ Method[2] = llvm::ConstantExpr::getBitCast(Fn, ObjCTypes.Int8PtrTy);
+ return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Method);
+}
+
+/// EmitMethodList - Build meta-data for method declarations
+/// struct _method_list_t {
+/// uint32_t entsize; // sizeof(struct _objc_method)
+/// uint32_t method_count;
+/// struct _objc_method method_list[method_count];
+/// }
+///
+llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(
+ const std::string &Name,
+ const char *Section,
+ const ConstantVector &Methods) {
+ // Return null for empty list.
+ if (Methods.empty())
+ return llvm::Constant::getNullValue(ObjCTypes.MethodListnfABIPtrTy);
+
+ std::vector<llvm::Constant*> Values(3);
+ // sizeof(struct _objc_method)
+ unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.MethodTy);
+ Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
+ // method_count
+ Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size());
+ llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodTy,
+ Methods.size());
+ Values[2] = llvm::ConstantArray::get(AT, Methods);
+ llvm::Constant *Init = llvm::ConstantStruct::get(Values);
+
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(Init->getType(), false,
+ llvm::GlobalValue::InternalLinkage,
+ Init,
+ Name,
+ &CGM.getModule());
+ GV->setAlignment(
+ CGM.getTargetData().getPrefTypeAlignment(Init->getType()));
+ GV->setSection(Section);
+ UsedGlobals.push_back(GV);
+ return llvm::ConstantExpr::getBitCast(GV,
+ ObjCTypes.MethodListnfABIPtrTy);
+}
+
+/// ObjCIvarOffsetVariable - Returns the ivar offset variable for
+/// the given ivar.
+llvm::GlobalVariable * CGObjCNonFragileABIMac::ObjCIvarOffsetVariable(
+ const ObjCInterfaceDecl *ID,
+ const ObjCIvarDecl *Ivar) {
+ // FIXME: We shouldn't need to do this lookup.
+ unsigned Index;
+ const ObjCInterfaceDecl *Container =
+ FindIvarInterface(CGM.getContext(), ID, Ivar, Index);
+ assert(Container && "Unable to find ivar container!");
+ std::string Name = "OBJC_IVAR_$_" + Container->getNameAsString() +
+ '.' + Ivar->getNameAsString();
+ llvm::GlobalVariable *IvarOffsetGV =
+ CGM.getModule().getGlobalVariable(Name);
+ if (!IvarOffsetGV)
+ IvarOffsetGV =
+ new llvm::GlobalVariable(ObjCTypes.LongTy,
+ false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0,
+ Name,
+ &CGM.getModule());
+ return IvarOffsetGV;
+}
+
+llvm::Constant * CGObjCNonFragileABIMac::EmitIvarOffsetVar(
+ const ObjCInterfaceDecl *ID,
+ const ObjCIvarDecl *Ivar,
+ unsigned long int Offset) {
+ llvm::GlobalVariable *IvarOffsetGV = ObjCIvarOffsetVariable(ID, Ivar);
+ IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy,
+ Offset));
+ IvarOffsetGV->setAlignment(
+ CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.LongTy));
+
+ // FIXME: This matches gcc, but shouldn't the visibility be set on the use as
+ // well (i.e., in ObjCIvarOffsetVariable).
+ if (Ivar->getAccessControl() == ObjCIvarDecl::Private ||
+ Ivar->getAccessControl() == ObjCIvarDecl::Package ||
+ CGM.getDeclVisibilityMode(ID) == LangOptions::Hidden)
+ IvarOffsetGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ else
+ IvarOffsetGV->setVisibility(llvm::GlobalValue::DefaultVisibility);
+ IvarOffsetGV->setSection("__DATA, __objc_const");
+ return IvarOffsetGV;
+}
+
+/// EmitIvarList - Emit the ivar list for the given
+/// implementation. The return value has type
+/// IvarListnfABIPtrTy.
+/// struct _ivar_t {
+/// unsigned long int *offset; // pointer to ivar offset location
+/// char *name;
+/// char *type;
+/// uint32_t alignment;
+/// uint32_t size;
+/// }
+/// struct _ivar_list_t {
+/// uint32 entsize; // sizeof(struct _ivar_t)
+/// uint32 count;
+/// struct _iver_t list[count];
+/// }
+///
+
+void CGObjCCommonMac::GetNamedIvarList(const ObjCInterfaceDecl *OID,
+ llvm::SmallVector<ObjCIvarDecl*, 16> &Res) const {
+ for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(),
+ E = OID->ivar_end(); I != E; ++I) {
+ // Ignore unnamed bit-fields.
+ if (!(*I)->getDeclName())
+ continue;
+
+ Res.push_back(*I);
+ }
+
+ // Also save synthesize ivars.
+ // FIXME. Why can't we just use passed in Res small vector?
+ llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
+ CGM.getContext().CollectSynthesizedIvars(OID, Ivars);
+ for (unsigned k = 0, e = Ivars.size(); k != e; ++k)
+ Res.push_back(Ivars[k]);
+}
+
+llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
+ const ObjCImplementationDecl *ID) {
+
+ std::vector<llvm::Constant*> Ivars, Ivar(5);
+
+ const ObjCInterfaceDecl *OID = ID->getClassInterface();
+ assert(OID && "CGObjCNonFragileABIMac::EmitIvarList - null interface");
+
+ // FIXME. Consolidate this with similar code in GenerateClass.
+
+ // Collect declared and synthesized ivars in a small vector.
+ llvm::SmallVector<ObjCIvarDecl*, 16> OIvars;
+ GetNamedIvarList(OID, OIvars);
+
+ for (unsigned i = 0, e = OIvars.size(); i != e; ++i) {
+ ObjCIvarDecl *IVD = OIvars[i];
+ Ivar[0] = EmitIvarOffsetVar(ID->getClassInterface(), IVD,
+ ComputeIvarBaseOffset(CGM, ID, IVD));
+ Ivar[1] = GetMethodVarName(IVD->getIdentifier());
+ Ivar[2] = GetMethodVarType(IVD);
+ const llvm::Type *FieldTy =
+ CGM.getTypes().ConvertTypeForMem(IVD->getType());
+ unsigned Size = CGM.getTargetData().getTypeAllocSize(FieldTy);
+ unsigned Align = CGM.getContext().getPreferredTypeAlign(
+ IVD->getType().getTypePtr()) >> 3;
+ Align = llvm::Log2_32(Align);
+ Ivar[3] = llvm::ConstantInt::get(ObjCTypes.IntTy, Align);
+ // NOTE. Size of a bitfield does not match gcc's, because of the
+ // way bitfields are treated special in each. But I am told that
+ // 'size' for bitfield ivars is ignored by the runtime so it does
+ // not matter. If it matters, there is enough info to get the
+ // bitfield right!
+ Ivar[4] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
+ Ivars.push_back(llvm::ConstantStruct::get(ObjCTypes.IvarnfABITy, Ivar));
+ }
+ // Return null for empty list.
+ if (Ivars.empty())
+ return llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
+ std::vector<llvm::Constant*> Values(3);
+ unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.IvarnfABITy);
+ Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
+ Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Ivars.size());
+ llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.IvarnfABITy,
+ Ivars.size());
+ Values[2] = llvm::ConstantArray::get(AT, Ivars);
+ llvm::Constant *Init = llvm::ConstantStruct::get(Values);
+ const char *Prefix = "\01l_OBJC_$_INSTANCE_VARIABLES_";
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(Init->getType(), false,
+ llvm::GlobalValue::InternalLinkage,
+ Init,
+ Prefix + OID->getNameAsString(),
+ &CGM.getModule());
+ GV->setAlignment(
+ CGM.getTargetData().getPrefTypeAlignment(Init->getType()));
+ GV->setSection("__DATA, __objc_const");
+
+ UsedGlobals.push_back(GV);
+ return llvm::ConstantExpr::getBitCast(GV,
+ ObjCTypes.IvarListnfABIPtrTy);
+}
+
+llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef(
+ const ObjCProtocolDecl *PD) {
+ llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
+
+ if (!Entry) {
+ // We use the initializer as a marker of whether this is a forward
+ // reference or not. At module finalization we add the empty
+ // contents for protocols which were referenced but never defined.
+ Entry =
+ new llvm::GlobalVariable(ObjCTypes.ProtocolnfABITy, false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0,
+ "\01l_OBJC_PROTOCOL_$_" + PD->getNameAsString(),
+ &CGM.getModule());
+ Entry->setSection("__DATA,__datacoal_nt,coalesced");
+ UsedGlobals.push_back(Entry);
+ }
+
+ return Entry;
+}
+
+/// GetOrEmitProtocol - Generate the protocol meta-data:
+/// @code
+/// struct _protocol_t {
+/// id isa; // NULL
+/// const char * const protocol_name;
+/// const struct _protocol_list_t * protocol_list; // super protocols
+/// const struct method_list_t * const instance_methods;
+/// const struct method_list_t * const class_methods;
+/// const struct method_list_t *optionalInstanceMethods;
+/// const struct method_list_t *optionalClassMethods;
+/// const struct _prop_list_t * properties;
+/// const uint32_t size; // sizeof(struct _protocol_t)
+/// const uint32_t flags; // = 0
+/// }
+/// @endcode
+///
+
+llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
+ const ObjCProtocolDecl *PD) {
+ llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
+
+ // Early exit if a defining object has already been generated.
+ if (Entry && Entry->hasInitializer())
+ return Entry;
+
+ const char *ProtocolName = PD->getNameAsCString();
+
+ // Construct method lists.
+ std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
+ std::vector<llvm::Constant*> OptInstanceMethods, OptClassMethods;
+ for (ObjCProtocolDecl::instmeth_iterator
+ i = PD->instmeth_begin(CGM.getContext()),
+ e = PD->instmeth_end(CGM.getContext());
+ i != e; ++i) {
+ ObjCMethodDecl *MD = *i;
+ llvm::Constant *C = GetMethodDescriptionConstant(MD);
+ if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
+ OptInstanceMethods.push_back(C);
+ } else {
+ InstanceMethods.push_back(C);
+ }
+ }
+
+ for (ObjCProtocolDecl::classmeth_iterator
+ i = PD->classmeth_begin(CGM.getContext()),
+ e = PD->classmeth_end(CGM.getContext());
+ i != e; ++i) {
+ ObjCMethodDecl *MD = *i;
+ llvm::Constant *C = GetMethodDescriptionConstant(MD);
+ if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
+ OptClassMethods.push_back(C);
+ } else {
+ ClassMethods.push_back(C);
+ }
+ }
+
+ std::vector<llvm::Constant*> Values(10);
+ // isa is NULL
+ Values[0] = llvm::Constant::getNullValue(ObjCTypes.ObjectPtrTy);
+ Values[1] = GetClassName(PD->getIdentifier());
+ Values[2] = EmitProtocolList(
+ "\01l_OBJC_$_PROTOCOL_REFS_" + PD->getNameAsString(),
+ PD->protocol_begin(),
+ PD->protocol_end());
+
+ Values[3] = EmitMethodList("\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_"
+ + PD->getNameAsString(),
+ "__DATA, __objc_const",
+ InstanceMethods);
+ Values[4] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_"
+ + PD->getNameAsString(),
+ "__DATA, __objc_const",
+ ClassMethods);
+ Values[5] = EmitMethodList("\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_OPT_"
+ + PD->getNameAsString(),
+ "__DATA, __objc_const",
+ OptInstanceMethods);
+ Values[6] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_OPT_"
+ + PD->getNameAsString(),
+ "__DATA, __objc_const",
+ OptClassMethods);
+ Values[7] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + PD->getNameAsString(),
+ 0, PD, ObjCTypes);
+ uint32_t Size =
+ CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolnfABITy);
+ Values[8] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
+ Values[9] = llvm::Constant::getNullValue(ObjCTypes.IntTy);
+ llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolnfABITy,
+ Values);
+
+ if (Entry) {
+ // Already created, fix the linkage and update the initializer.
+ Entry->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
+ Entry->setInitializer(Init);
+ } else {
+ Entry =
+ new llvm::GlobalVariable(ObjCTypes.ProtocolnfABITy, false,
+ llvm::GlobalValue::WeakAnyLinkage,
+ Init,
+ std::string("\01l_OBJC_PROTOCOL_$_")+ProtocolName,
+ &CGM.getModule());
+ Entry->setAlignment(
+ CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABITy));
+ Entry->setSection("__DATA,__datacoal_nt,coalesced");
+ }
+ Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
+
+ // Use this protocol meta-data to build protocol list table in section
+ // __DATA, __objc_protolist
+ llvm::GlobalVariable *PTGV = new llvm::GlobalVariable(
+ ObjCTypes.ProtocolnfABIPtrTy, false,
+ llvm::GlobalValue::WeakAnyLinkage,
+ Entry,
+ std::string("\01l_OBJC_LABEL_PROTOCOL_$_")
+ +ProtocolName,
+ &CGM.getModule());
+ PTGV->setAlignment(
+ CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
+ PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip");
+ PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ UsedGlobals.push_back(PTGV);
+ return Entry;
+}
+
+/// EmitProtocolList - Generate protocol list meta-data:
+/// @code
+/// struct _protocol_list_t {
+/// long protocol_count; // Note, this is 32/64 bit
+/// struct _protocol_t[protocol_count];
+/// }
+/// @endcode
+///
+llvm::Constant *
+CGObjCNonFragileABIMac::EmitProtocolList(const std::string &Name,
+ ObjCProtocolDecl::protocol_iterator begin,
+ ObjCProtocolDecl::protocol_iterator end) {
+ std::vector<llvm::Constant*> ProtocolRefs;
+
+ // Just return null for empty protocol lists
+ if (begin == end)
+ return llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy);
+
+ // FIXME: We shouldn't need to do this lookup here, should we?
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
+ if (GV)
+ return llvm::ConstantExpr::getBitCast(GV,
+ ObjCTypes.ProtocolListnfABIPtrTy);
+
+ for (; begin != end; ++begin)
+ ProtocolRefs.push_back(GetProtocolRef(*begin)); // Implemented???
+
+ // This list is null terminated.
+ ProtocolRefs.push_back(llvm::Constant::getNullValue(
+ ObjCTypes.ProtocolnfABIPtrTy));
+
+ std::vector<llvm::Constant*> Values(2);
+ Values[0] = llvm::ConstantInt::get(ObjCTypes.LongTy, ProtocolRefs.size() - 1);
+ Values[1] =
+ llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.ProtocolnfABIPtrTy,
+ ProtocolRefs.size()),
+ ProtocolRefs);
+
+ llvm::Constant *Init = llvm::ConstantStruct::get(Values);
+ GV = new llvm::GlobalVariable(Init->getType(), false,
+ llvm::GlobalValue::InternalLinkage,
+ Init,
+ Name,
+ &CGM.getModule());
+ GV->setSection("__DATA, __objc_const");
+ GV->setAlignment(
+ CGM.getTargetData().getPrefTypeAlignment(Init->getType()));
+ UsedGlobals.push_back(GV);
+ return llvm::ConstantExpr::getBitCast(GV,
+ ObjCTypes.ProtocolListnfABIPtrTy);
+}
+
+/// GetMethodDescriptionConstant - This routine build following meta-data:
+/// struct _objc_method {
+/// SEL _cmd;
+/// char *method_type;
+/// char *_imp;
+/// }
+
+llvm::Constant *
+CGObjCNonFragileABIMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
+ std::vector<llvm::Constant*> Desc(3);
+ Desc[0] = llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
+ ObjCTypes.SelectorPtrTy);
+ Desc[1] = GetMethodVarType(MD);
+ // Protocol methods have no implementation. So, this entry is always NULL.
+ Desc[2] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
+ return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Desc);
+}
+
+/// EmitObjCValueForIvar - Code Gen for nonfragile ivar reference.
+/// This code gen. amounts to generating code for:
+/// @code
+/// (type *)((char *)base + _OBJC_IVAR_$_.ivar;
+/// @encode
+///
+LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar(
+ CodeGen::CodeGenFunction &CGF,
+ QualType ObjectTy,
+ llvm::Value *BaseValue,
+ const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers) {
+ const ObjCInterfaceDecl *ID = ObjectTy->getAsObjCInterfaceType()->getDecl();
+ return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
+ EmitIvarOffset(CGF, ID, Ivar));
+}
+
+llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset(
+ CodeGen::CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *Interface,
+ const ObjCIvarDecl *Ivar) {
+ return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar),
+ false, "ivar");
+}
+
+CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
+ CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ llvm::Value *Receiver,
+ QualType Arg0Ty,
+ bool IsSuper,
+ const CallArgList &CallArgs) {
+ // FIXME. Even though IsSuper is passes. This function doese not handle calls
+ // to 'super' receivers.
+ CodeGenTypes &Types = CGM.getTypes();
+ llvm::Value *Arg0 = Receiver;
+ if (!IsSuper)
+ Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp");
+
+ // Find the message function name.
+ // FIXME. This is too much work to get the ABI-specific result type needed to
+ // find the message name.
+ const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType,
+ llvm::SmallVector<QualType, 16>());
+ llvm::Constant *Fn = 0;
+ std::string Name("\01l_");
+ if (CGM.ReturnTypeUsesSret(FnInfo)) {
+#if 0
+ // unlike what is documented. gcc never generates this API!!
+ if (Receiver->getType() == ObjCTypes.ObjectPtrTy) {
+ Fn = ObjCTypes.getMessageSendIdStretFixupFn();
+ // FIXME. Is there a better way of getting these names.
+ // They are available in RuntimeFunctions vector pair.
+ Name += "objc_msgSendId_stret_fixup";
+ }
+ else
+#endif
+ if (IsSuper) {
+ Fn = ObjCTypes.getMessageSendSuper2StretFixupFn();
+ Name += "objc_msgSendSuper2_stret_fixup";
+ }
+ else
+ {
+ Fn = ObjCTypes.getMessageSendStretFixupFn();
+ Name += "objc_msgSend_stret_fixup";
+ }
+ }
+ else if (!IsSuper && ResultType->isFloatingType()) {
+ if (const BuiltinType *BT = ResultType->getAsBuiltinType()) {
+ BuiltinType::Kind k = BT->getKind();
+ if (k == BuiltinType::LongDouble) {
+ Fn = ObjCTypes.getMessageSendFpretFixupFn();
+ Name += "objc_msgSend_fpret_fixup";
+ }
+ else {
+ Fn = ObjCTypes.getMessageSendFixupFn();
+ Name += "objc_msgSend_fixup";
+ }
+ }
+ }
+ else {
+#if 0
+// unlike what is documented. gcc never generates this API!!
+ if (Receiver->getType() == ObjCTypes.ObjectPtrTy) {
+ Fn = ObjCTypes.getMessageSendIdFixupFn();
+ Name += "objc_msgSendId_fixup";
+ }
+ else
+#endif
+ if (IsSuper) {
+ Fn = ObjCTypes.getMessageSendSuper2FixupFn();
+ Name += "objc_msgSendSuper2_fixup";
+ }
+ else
+ {
+ Fn = ObjCTypes.getMessageSendFixupFn();
+ Name += "objc_msgSend_fixup";
+ }
+ }
+ assert(Fn && "CGObjCNonFragileABIMac::EmitMessageSend");
+ Name += '_';
+ std::string SelName(Sel.getAsString());
+ // Replace all ':' in selector name with '_' ouch!
+ for(unsigned i = 0; i < SelName.size(); i++)
+ if (SelName[i] == ':')
+ SelName[i] = '_';
+ Name += SelName;
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
+ if (!GV) {
+ // Build message ref table entry.
+ std::vector<llvm::Constant*> Values(2);
+ Values[0] = Fn;
+ Values[1] = GetMethodVarName(Sel);
+ llvm::Constant *Init = llvm::ConstantStruct::get(Values);
+ GV = new llvm::GlobalVariable(Init->getType(), false,
+ llvm::GlobalValue::WeakAnyLinkage,
+ Init,
+ Name,
+ &CGM.getModule());
+ GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ GV->setAlignment(16);
+ GV->setSection("__DATA, __objc_msgrefs, coalesced");
+ }
+ llvm::Value *Arg1 = CGF.Builder.CreateBitCast(GV, ObjCTypes.MessageRefPtrTy);
+
+ CallArgList ActualArgs;
+ ActualArgs.push_back(std::make_pair(RValue::get(Arg0), Arg0Ty));
+ ActualArgs.push_back(std::make_pair(RValue::get(Arg1),
+ ObjCTypes.MessageRefCPtrTy));
+ ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
+ const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs);
+ llvm::Value *Callee = CGF.Builder.CreateStructGEP(Arg1, 0);
+ Callee = CGF.Builder.CreateLoad(Callee);
+ const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo1, true);
+ Callee = CGF.Builder.CreateBitCast(Callee,
+ llvm::PointerType::getUnqual(FTy));
+ return CGF.EmitCall(FnInfo1, Callee, ActualArgs);
+}
+
+/// Generate code for a message send expression in the nonfragile abi.
+CodeGen::RValue CGObjCNonFragileABIMac::GenerateMessageSend(
+ CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ llvm::Value *Receiver,
+ bool IsClassMessage,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method) {
+ return LegacyDispatchedSelector(Sel)
+ ? EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel),
+ Receiver, CGF.getContext().getObjCIdType(),
+ false, CallArgs, ObjCTypes)
+ : EmitMessageSend(CGF, ResultType, Sel,
+ Receiver, CGF.getContext().getObjCIdType(),
+ false, CallArgs);
+}
+
+llvm::GlobalVariable *
+CGObjCNonFragileABIMac::GetClassGlobal(const std::string &Name) {
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
+
+ if (!GV) {
+ GV = new llvm::GlobalVariable(ObjCTypes.ClassnfABITy, false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0, Name, &CGM.getModule());
+ }
+
+ return GV;
+}
+
+llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *ID) {
+ llvm::GlobalVariable *&Entry = ClassReferences[ID->getIdentifier()];
+
+ if (!Entry) {
+ std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
+ llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName);
+ Entry =
+ new llvm::GlobalVariable(ObjCTypes.ClassnfABIPtrTy, false,
+ llvm::GlobalValue::InternalLinkage,
+ ClassGV,
+ "\01L_OBJC_CLASSLIST_REFERENCES_$_",
+ &CGM.getModule());
+ Entry->setAlignment(
+ CGM.getTargetData().getPrefTypeAlignment(
+ ObjCTypes.ClassnfABIPtrTy));
+ Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
+ UsedGlobals.push_back(Entry);
+ }
+
+ return Builder.CreateLoad(Entry, false, "tmp");
+}
+
+llvm::Value *
+CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *ID) {
+ llvm::GlobalVariable *&Entry = SuperClassReferences[ID->getIdentifier()];
+
+ if (!Entry) {
+ std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
+ llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName);
+ Entry =
+ new llvm::GlobalVariable(ObjCTypes.ClassnfABIPtrTy, false,
+ llvm::GlobalValue::InternalLinkage,
+ ClassGV,
+ "\01L_OBJC_CLASSLIST_SUP_REFS_$_",
+ &CGM.getModule());
+ Entry->setAlignment(
+ CGM.getTargetData().getPrefTypeAlignment(
+ ObjCTypes.ClassnfABIPtrTy));
+ Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
+ UsedGlobals.push_back(Entry);
+ }
+
+ return Builder.CreateLoad(Entry, false, "tmp");
+}
+
+/// EmitMetaClassRef - Return a Value * of the address of _class_t
+/// meta-data
+///
+llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *ID) {
+ llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()];
+ if (Entry)
+ return Builder.CreateLoad(Entry, false, "tmp");
+
+ std::string MetaClassName(getMetaclassSymbolPrefix() + ID->getNameAsString());
+ llvm::GlobalVariable *MetaClassGV = GetClassGlobal(MetaClassName);
+ Entry =
+ new llvm::GlobalVariable(ObjCTypes.ClassnfABIPtrTy, false,
+ llvm::GlobalValue::InternalLinkage,
+ MetaClassGV,
+ "\01L_OBJC_CLASSLIST_SUP_REFS_$_",
+ &CGM.getModule());
+ Entry->setAlignment(
+ CGM.getTargetData().getPrefTypeAlignment(
+ ObjCTypes.ClassnfABIPtrTy));
+
+ Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
+ UsedGlobals.push_back(Entry);
+
+ return Builder.CreateLoad(Entry, false, "tmp");
+}
+
+/// GetClass - Return a reference to the class for the given interface
+/// decl.
+llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *ID) {
+ return EmitClassRef(Builder, ID);
+}
+
+/// Generates a message send where the super is the receiver. This is
+/// a message send to self with special delivery semantics indicating
+/// which class's method should be called.
+CodeGen::RValue
+CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ const ObjCInterfaceDecl *Class,
+ bool isCategoryImpl,
+ llvm::Value *Receiver,
+ bool IsClassMessage,
+ const CodeGen::CallArgList &CallArgs) {
+ // ...
+ // Create and init a super structure; this is a (receiver, class)
+ // pair we will pass to objc_msgSendSuper.
+ llvm::Value *ObjCSuper =
+ CGF.Builder.CreateAlloca(ObjCTypes.SuperTy, 0, "objc_super");
+
+ llvm::Value *ReceiverAsObject =
+ CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
+ CGF.Builder.CreateStore(ReceiverAsObject,
+ CGF.Builder.CreateStructGEP(ObjCSuper, 0));
+
+ // If this is a class message the metaclass is passed as the target.
+ llvm::Value *Target;
+ if (IsClassMessage) {
+ if (isCategoryImpl) {
+ // Message sent to "super' in a class method defined in
+ // a category implementation.
+ Target = EmitClassRef(CGF.Builder, Class);
+ Target = CGF.Builder.CreateStructGEP(Target, 0);
+ Target = CGF.Builder.CreateLoad(Target);
+ }
+ else
+ Target = EmitMetaClassRef(CGF.Builder, Class);
+ }
+ else
+ Target = EmitSuperClassRef(CGF.Builder, Class);
+
+ // FIXME: We shouldn't need to do this cast, rectify the ASTContext and
+ // ObjCTypes types.
+ const llvm::Type *ClassTy =
+ CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
+ Target = CGF.Builder.CreateBitCast(Target, ClassTy);
+ CGF.Builder.CreateStore(Target,
+ CGF.Builder.CreateStructGEP(ObjCSuper, 1));
+
+ return (LegacyDispatchedSelector(Sel))
+ ? EmitLegacyMessageSend(CGF, ResultType,EmitSelector(CGF.Builder, Sel),
+ ObjCSuper, ObjCTypes.SuperPtrCTy,
+ true, CallArgs,
+ ObjCTypes)
+ : EmitMessageSend(CGF, ResultType, Sel,
+ ObjCSuper, ObjCTypes.SuperPtrCTy,
+ true, CallArgs);
+}
+
+llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
+ Selector Sel) {
+ llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
+
+ if (!Entry) {
+ llvm::Constant *Casted =
+ llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
+ ObjCTypes.SelectorPtrTy);
+ Entry =
+ new llvm::GlobalVariable(ObjCTypes.SelectorPtrTy, false,
+ llvm::GlobalValue::InternalLinkage,
+ Casted, "\01L_OBJC_SELECTOR_REFERENCES_",
+ &CGM.getModule());
+ Entry->setSection("__DATA, __objc_selrefs, literal_pointers, no_dead_strip");
+ UsedGlobals.push_back(Entry);
+ }
+
+ return Builder.CreateLoad(Entry, false, "tmp");
+}
+/// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
+/// objc_assign_ivar (id src, id *dst)
+///
+void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst)
+{
+ const llvm::Type * SrcTy = src->getType();
+ if (!isa<llvm::PointerType>(SrcTy)) {
+ unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ assert(Size <= 8 && "does not support size > 8");
+ src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
+ : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
+ src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
+ }
+ src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
+ dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
+ CGF.Builder.CreateCall2(ObjCTypes.getGcAssignIvarFn(),
+ src, dst, "assignivar");
+ return;
+}
+
+/// EmitObjCStrongCastAssign - Code gen for assigning to a __strong cast object.
+/// objc_assign_strongCast (id src, id *dst)
+///
+void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
+ CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst)
+{
+ const llvm::Type * SrcTy = src->getType();
+ if (!isa<llvm::PointerType>(SrcTy)) {
+ unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ assert(Size <= 8 && "does not support size > 8");
+ src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
+ : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
+ src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
+ }
+ src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
+ dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
+ CGF.Builder.CreateCall2(ObjCTypes.getGcAssignStrongCastFn(),
+ src, dst, "weakassign");
+ return;
+}
+
+/// EmitObjCWeakRead - Code gen for loading value of a __weak
+/// object: objc_read_weak (id *src)
+///
+llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead(
+ CodeGen::CodeGenFunction &CGF,
+ llvm::Value *AddrWeakObj)
+{
+ const llvm::Type* DestTy =
+ cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType();
+ AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy);
+ llvm::Value *read_weak = CGF.Builder.CreateCall(ObjCTypes.getGcReadWeakFn(),
+ AddrWeakObj, "weakread");
+ read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
+ return read_weak;
+}
+
+/// EmitObjCWeakAssign - Code gen for assigning to a __weak object.
+/// objc_assign_weak (id src, id *dst)
+///
+void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst)
+{
+ const llvm::Type * SrcTy = src->getType();
+ if (!isa<llvm::PointerType>(SrcTy)) {
+ unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ assert(Size <= 8 && "does not support size > 8");
+ src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
+ : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
+ src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
+ }
+ src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
+ dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
+ CGF.Builder.CreateCall2(ObjCTypes.getGcAssignWeakFn(),
+ src, dst, "weakassign");
+ return;
+}
+
+/// EmitObjCGlobalAssign - Code gen for assigning to a __strong object.
+/// objc_assign_global (id src, id *dst)
+///
+void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst)
+{
+ const llvm::Type * SrcTy = src->getType();
+ if (!isa<llvm::PointerType>(SrcTy)) {
+ unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ assert(Size <= 8 && "does not support size > 8");
+ src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
+ : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
+ src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy);
+ }
+ src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
+ dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
+ CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(),
+ src, dst, "globalassign");
+ return;
+}
+
+void
+CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
+ const Stmt &S) {
+ bool isTry = isa<ObjCAtTryStmt>(S);
+ llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try");
+ llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest();
+ llvm::BasicBlock *TryHandler = CGF.createBasicBlock("try.handler");
+ llvm::BasicBlock *FinallyBlock = CGF.createBasicBlock("finally");
+ llvm::BasicBlock *FinallyRethrow = CGF.createBasicBlock("finally.throw");
+ llvm::BasicBlock *FinallyEnd = CGF.createBasicBlock("finally.end");
+
+ // For @synchronized, call objc_sync_enter(sync.expr). The
+ // evaluation of the expression must occur before we enter the
+ // @synchronized. We can safely avoid a temp here because jumps into
+ // @synchronized are illegal & this will dominate uses.
+ llvm::Value *SyncArg = 0;
+ if (!isTry) {
+ SyncArg =
+ CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
+ SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy);
+ CGF.Builder.CreateCall(ObjCTypes.getSyncEnterFn(), SyncArg);
+ }
+
+ // Push an EH context entry, used for handling rethrows and jumps
+ // through finally.
+ CGF.PushCleanupBlock(FinallyBlock);
+
+ CGF.setInvokeDest(TryHandler);
+
+ CGF.EmitBlock(TryBlock);
+ CGF.EmitStmt(isTry ? cast<ObjCAtTryStmt>(S).getTryBody()
+ : cast<ObjCAtSynchronizedStmt>(S).getSynchBody());
+ CGF.EmitBranchThroughCleanup(FinallyEnd);
+
+ // Emit the exception handler.
+
+ CGF.EmitBlock(TryHandler);
+
+ llvm::Value *llvm_eh_exception =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
+ llvm::Value *llvm_eh_selector_i64 =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector_i64);
+ llvm::Value *llvm_eh_typeid_for_i64 =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for_i64);
+ llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
+ llvm::Value *RethrowPtr = CGF.CreateTempAlloca(Exc->getType(), "_rethrow");
+
+ llvm::SmallVector<llvm::Value*, 8> SelectorArgs;
+ SelectorArgs.push_back(Exc);
+ SelectorArgs.push_back(ObjCTypes.getEHPersonalityPtr());
+
+ // Construct the lists of (type, catch body) to handle.
+ llvm::SmallVector<std::pair<const ParmVarDecl*, const Stmt*>, 8> Handlers;
+ bool HasCatchAll = false;
+ if (isTry) {
+ if (const ObjCAtCatchStmt* CatchStmt =
+ cast<ObjCAtTryStmt>(S).getCatchStmts()) {
+ for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
+ const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
+ Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody()));
+
+ // catch(...) always matches.
+ if (!CatchDecl) {
+ // Use i8* null here to signal this is a catch all, not a cleanup.
+ llvm::Value *Null = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
+ SelectorArgs.push_back(Null);
+ HasCatchAll = true;
+ break;
+ }
+
+ if (CGF.getContext().isObjCIdType(CatchDecl->getType()) ||
+ CatchDecl->getType()->isObjCQualifiedIdType()) {
+ llvm::Value *IDEHType =
+ CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
+ if (!IDEHType)
+ IDEHType =
+ new llvm::GlobalVariable(ObjCTypes.EHTypeTy, false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0, "OBJC_EHTYPE_id", &CGM.getModule());
+ SelectorArgs.push_back(IDEHType);
+ HasCatchAll = true;
+ break;
+ }
+
+ // All other types should be Objective-C interface pointer types.
+ const PointerType *PT = CatchDecl->getType()->getAsPointerType();
+ assert(PT && "Invalid @catch type.");
+ const ObjCInterfaceType *IT =
+ PT->getPointeeType()->getAsObjCInterfaceType();
+ assert(IT && "Invalid @catch type.");
+ llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false);
+ SelectorArgs.push_back(EHType);
+ }
+ }
+ }
+
+ // We use a cleanup unless there was already a catch all.
+ if (!HasCatchAll) {
+ SelectorArgs.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0));
+ Handlers.push_back(std::make_pair((const ParmVarDecl*) 0, (const Stmt*) 0));
+ }
+
+ llvm::Value *Selector =
+ CGF.Builder.CreateCall(llvm_eh_selector_i64,
+ SelectorArgs.begin(), SelectorArgs.end(),
+ "selector");
+ for (unsigned i = 0, e = Handlers.size(); i != e; ++i) {
+ const ParmVarDecl *CatchParam = Handlers[i].first;
+ const Stmt *CatchBody = Handlers[i].second;
+
+ llvm::BasicBlock *Next = 0;
+
+ // The last handler always matches.
+ if (i + 1 != e) {
+ assert(CatchParam && "Only last handler can be a catch all.");
+
+ llvm::BasicBlock *Match = CGF.createBasicBlock("match");
+ Next = CGF.createBasicBlock("catch.next");
+ llvm::Value *Id =
+ CGF.Builder.CreateCall(llvm_eh_typeid_for_i64,
+ CGF.Builder.CreateBitCast(SelectorArgs[i+2],
+ ObjCTypes.Int8PtrTy));
+ CGF.Builder.CreateCondBr(CGF.Builder.CreateICmpEQ(Selector, Id),
+ Match, Next);
+
+ CGF.EmitBlock(Match);
+ }
+
+ if (CatchBody) {
+ llvm::BasicBlock *MatchEnd = CGF.createBasicBlock("match.end");
+ llvm::BasicBlock *MatchHandler = CGF.createBasicBlock("match.handler");
+
+ // Cleanups must call objc_end_catch.
+ //
+ // FIXME: It seems incorrect for objc_begin_catch to be inside this
+ // context, but this matches gcc.
+ CGF.PushCleanupBlock(MatchEnd);
+ CGF.setInvokeDest(MatchHandler);
+
+ llvm::Value *ExcObject =
+ CGF.Builder.CreateCall(ObjCTypes.getObjCBeginCatchFn(), Exc);
+
+ // Bind the catch parameter if it exists.
+ if (CatchParam) {
+ ExcObject =
+ CGF.Builder.CreateBitCast(ExcObject,
+ CGF.ConvertType(CatchParam->getType()));
+ // CatchParam is a ParmVarDecl because of the grammar
+ // construction used to handle this, but for codegen purposes
+ // we treat this as a local decl.
+ CGF.EmitLocalBlockVarDecl(*CatchParam);
+ CGF.Builder.CreateStore(ExcObject, CGF.GetAddrOfLocalVar(CatchParam));
+ }
+
+ CGF.ObjCEHValueStack.push_back(ExcObject);
+ CGF.EmitStmt(CatchBody);
+ CGF.ObjCEHValueStack.pop_back();
+
+ CGF.EmitBranchThroughCleanup(FinallyEnd);
+
+ CGF.EmitBlock(MatchHandler);
+
+ llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
+ // We are required to emit this call to satisfy LLVM, even
+ // though we don't use the result.
+ llvm::SmallVector<llvm::Value*, 8> Args;
+ Args.push_back(Exc);
+ Args.push_back(ObjCTypes.getEHPersonalityPtr());
+ Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ 0));
+ CGF.Builder.CreateCall(llvm_eh_selector_i64, Args.begin(), Args.end());
+ CGF.Builder.CreateStore(Exc, RethrowPtr);
+ CGF.EmitBranchThroughCleanup(FinallyRethrow);
+
+ CodeGenFunction::CleanupBlockInfo Info = CGF.PopCleanupBlock();
+
+ CGF.EmitBlock(MatchEnd);
+
+ // Unfortunately, we also have to generate another EH frame here
+ // in case this throws.
+ llvm::BasicBlock *MatchEndHandler =
+ CGF.createBasicBlock("match.end.handler");
+ llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
+ CGF.Builder.CreateInvoke(ObjCTypes.getObjCEndCatchFn(),
+ Cont, MatchEndHandler,
+ Args.begin(), Args.begin());
+
+ CGF.EmitBlock(Cont);
+ if (Info.SwitchBlock)
+ CGF.EmitBlock(Info.SwitchBlock);
+ if (Info.EndBlock)
+ CGF.EmitBlock(Info.EndBlock);
+
+ CGF.EmitBlock(MatchEndHandler);
+ Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
+ // We are required to emit this call to satisfy LLVM, even
+ // though we don't use the result.
+ Args.clear();
+ Args.push_back(Exc);
+ Args.push_back(ObjCTypes.getEHPersonalityPtr());
+ Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ 0));
+ CGF.Builder.CreateCall(llvm_eh_selector_i64, Args.begin(), Args.end());
+ CGF.Builder.CreateStore(Exc, RethrowPtr);
+ CGF.EmitBranchThroughCleanup(FinallyRethrow);
+
+ if (Next)
+ CGF.EmitBlock(Next);
+ } else {
+ assert(!Next && "catchup should be last handler.");
+
+ CGF.Builder.CreateStore(Exc, RethrowPtr);
+ CGF.EmitBranchThroughCleanup(FinallyRethrow);
+ }
+ }
+
+ // Pop the cleanup entry, the @finally is outside this cleanup
+ // scope.
+ CodeGenFunction::CleanupBlockInfo Info = CGF.PopCleanupBlock();
+ CGF.setInvokeDest(PrevLandingPad);
+
+ CGF.EmitBlock(FinallyBlock);
+
+ if (isTry) {
+ if (const ObjCAtFinallyStmt* FinallyStmt =
+ cast<ObjCAtTryStmt>(S).getFinallyStmt())
+ CGF.EmitStmt(FinallyStmt->getFinallyBody());
+ } else {
+ // Emit 'objc_sync_exit(expr)' as finally's sole statement for
+ // @synchronized.
+ CGF.Builder.CreateCall(ObjCTypes.getSyncExitFn(), SyncArg);
+ }
+
+ if (Info.SwitchBlock)
+ CGF.EmitBlock(Info.SwitchBlock);
+ if (Info.EndBlock)
+ CGF.EmitBlock(Info.EndBlock);
+
+ // Branch around the rethrow code.
+ CGF.EmitBranch(FinallyEnd);
+
+ CGF.EmitBlock(FinallyRethrow);
+ CGF.Builder.CreateCall(ObjCTypes.getUnwindResumeOrRethrowFn(),
+ CGF.Builder.CreateLoad(RethrowPtr));
+ CGF.Builder.CreateUnreachable();
+
+ CGF.EmitBlock(FinallyEnd);
+}
+
+/// EmitThrowStmt - Generate code for a throw statement.
+void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
+ const ObjCAtThrowStmt &S) {
+ llvm::Value *Exception;
+ if (const Expr *ThrowExpr = S.getThrowExpr()) {
+ Exception = CGF.EmitScalarExpr(ThrowExpr);
+ } else {
+ assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) &&
+ "Unexpected rethrow outside @catch block.");
+ Exception = CGF.ObjCEHValueStack.back();
+ }
+
+ llvm::Value *ExceptionAsObject =
+ CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy, "tmp");
+ llvm::BasicBlock *InvokeDest = CGF.getInvokeDest();
+ if (InvokeDest) {
+ llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
+ CGF.Builder.CreateInvoke(ObjCTypes.getExceptionThrowFn(),
+ Cont, InvokeDest,
+ &ExceptionAsObject, &ExceptionAsObject + 1);
+ CGF.EmitBlock(Cont);
+ } else
+ CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject);
+ CGF.Builder.CreateUnreachable();
+
+ // Clear the insertion point to indicate we are in unreachable code.
+ CGF.Builder.ClearInsertionPoint();
+}
+
+llvm::Value *
+CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
+ bool ForDefinition) {
+ llvm::GlobalVariable * &Entry = EHTypeReferences[ID->getIdentifier()];
+
+ // If we don't need a definition, return the entry if found or check
+ // if we use an external reference.
+ if (!ForDefinition) {
+ if (Entry)
+ return Entry;
+
+ // If this type (or a super class) has the __objc_exception__
+ // attribute, emit an external reference.
+ if (hasObjCExceptionAttribute(ID))
+ return Entry =
+ new llvm::GlobalVariable(ObjCTypes.EHTypeTy, false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0,
+ (std::string("OBJC_EHTYPE_$_") +
+ ID->getIdentifier()->getName()),
+ &CGM.getModule());
+ }
+
+ // Otherwise we need to either make a new entry or fill in the
+ // initializer.
+ assert((!Entry || !Entry->hasInitializer()) && "Duplicate EHType definition");
+ std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
+ std::string VTableName = "objc_ehtype_vtable";
+ llvm::GlobalVariable *VTableGV =
+ CGM.getModule().getGlobalVariable(VTableName);
+ if (!VTableGV)
+ VTableGV = new llvm::GlobalVariable(ObjCTypes.Int8PtrTy, false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0, VTableName, &CGM.getModule());
+
+ llvm::Value *VTableIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, 2);
+
+ std::vector<llvm::Constant*> Values(3);
+ Values[0] = llvm::ConstantExpr::getGetElementPtr(VTableGV, &VTableIdx, 1);
+ Values[1] = GetClassName(ID->getIdentifier());
+ Values[2] = GetClassGlobal(ClassName);
+ llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.EHTypeTy, Values);
+
+ if (Entry) {
+ Entry->setInitializer(Init);
+ } else {
+ Entry = new llvm::GlobalVariable(ObjCTypes.EHTypeTy, false,
+ llvm::GlobalValue::WeakAnyLinkage,
+ Init,
+ (std::string("OBJC_EHTYPE_$_") +
+ ID->getIdentifier()->getName()),
+ &CGM.getModule());
+ }
+
+ if (CGM.getLangOptions().getVisibilityMode() == LangOptions::Hidden)
+ Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ Entry->setAlignment(8);
+
+ if (ForDefinition) {
+ Entry->setSection("__DATA,__objc_const");
+ Entry->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ } else {
+ Entry->setSection("__DATA,__datacoal_nt,coalesced");
+ }
+
+ return Entry;
+}
+
+/* *** */
+
+CodeGen::CGObjCRuntime *
+CodeGen::CreateMacObjCRuntime(CodeGen::CodeGenModule &CGM) {
+ return new CGObjCMac(CGM);
+}
+
+CodeGen::CGObjCRuntime *
+CodeGen::CreateMacNonFragileABIObjCRuntime(CodeGen::CodeGenModule &CGM) {
+ return new CGObjCNonFragileABIMac(CGM);
+}
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
new file mode 100644
index 000000000000..b8cf026b35a9
--- /dev/null
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -0,0 +1,206 @@
+//===----- CGObjCRuntime.h - Interface to ObjC 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 Objective-C code generation. Concrete
+// subclasses of this implement code generation for specific Objective-C
+// runtime libraries.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_OBCJRUNTIME_H
+#define CLANG_CODEGEN_OBCJRUNTIME_H
+#include "clang/Basic/IdentifierTable.h" // Selector
+#include "llvm/ADT/SmallVector.h"
+#include "clang/AST/DeclObjC.h"
+#include <string>
+
+#include "CGBuilder.h"
+#include "CGCall.h"
+#include "CGValue.h"
+
+namespace llvm {
+ class Constant;
+ class Function;
+ class Module;
+ class StructLayout;
+ class StructType;
+ class Type;
+ class Value;
+}
+
+namespace clang {
+namespace CodeGen {
+ class CodeGenFunction;
+}
+
+ class FieldDecl;
+ class ObjCAtTryStmt;
+ class ObjCAtThrowStmt;
+ class ObjCAtSynchronizedStmt;
+ class ObjCContainerDecl;
+ class ObjCCategoryImplDecl;
+ class ObjCImplementationDecl;
+ class ObjCInterfaceDecl;
+ class ObjCMessageExpr;
+ class ObjCMethodDecl;
+ class ObjCProtocolDecl;
+ class Selector;
+ class ObjCIvarDecl;
+ class ObjCStringLiteral;
+
+namespace CodeGen {
+ class CodeGenModule;
+
+// FIXME: Several methods should be pure virtual but aren't to avoid the
+// partially-implemented subclass breaking.
+
+/// Implements runtime-specific code generation functions.
+class CGObjCRuntime {
+public:
+ // Utility functions for unified ivar access. These need to
+ // eventually be folded into other places (the structure layout
+ // code).
+
+protected:
+ /// Compute an offset to the given ivar, suitable for passing to
+ /// EmitValueForIvarAtOffset. Note that the correct handling of
+ /// bit-fields is carefully coordinated by these two, use caution!
+ ///
+ /// The latter overload is suitable for computing the offset of a
+ /// sythesized ivar.
+ uint64_t ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
+ const ObjCInterfaceDecl *OID,
+ const ObjCIvarDecl *Ivar);
+ uint64_t ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
+ const ObjCImplementationDecl *OID,
+ const ObjCIvarDecl *Ivar);
+
+ LValue EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *OID,
+ llvm::Value *BaseValue,
+ const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers,
+ llvm::Value *Offset);
+
+public:
+ virtual ~CGObjCRuntime();
+
+ /// Generate the function required to register all Objective-C components in
+ /// this compilation unit with the runtime library.
+ virtual llvm::Function *ModuleInitFunction() = 0;
+
+ /// Get a selector for the specified name and type values. The
+ /// return value should have the LLVM type for pointer-to
+ /// ASTContext::getObjCSelType().
+ virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ Selector Sel) = 0;
+
+ /// Get a typed selector.
+ virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ const ObjCMethodDecl *Method) = 0;
+
+ /// Generate a constant string object.
+ virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *) = 0;
+
+ /// Generate a category. A category contains a list of methods (and
+ /// accompanying metadata) and a list of protocols.
+ virtual void GenerateCategory(const ObjCCategoryImplDecl *OCD) = 0;
+
+ /// Generate a class stucture for this class.
+ virtual void GenerateClass(const ObjCImplementationDecl *OID) = 0;
+
+ /// Generate an Objective-C message send operation.
+ virtual CodeGen::RValue
+ GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ llvm::Value *Receiver,
+ bool IsClassMessage,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method=0) = 0;
+
+ /// Generate an Objective-C message send operation to the super
+ /// class initiated in a method for Class and with the given Self
+ /// object.
+ virtual CodeGen::RValue
+ GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+ QualType ResultType,
+ Selector Sel,
+ const ObjCInterfaceDecl *Class,
+ bool isCategoryImpl,
+ llvm::Value *Self,
+ bool IsClassMessage,
+ const CallArgList &CallArgs) = 0;
+
+ /// Emit the code to return the named protocol as an object, as in a
+ /// @protocol expression.
+ virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ const ObjCProtocolDecl *OPD) = 0;
+
+ /// Generate the named protocol. Protocols contain method metadata but no
+ /// implementations.
+ virtual void GenerateProtocol(const ObjCProtocolDecl *OPD) = 0;
+
+ /// Generate a function preamble for a method with the specified
+ /// types.
+
+ // FIXME: Current this just generates the Function definition, but really this
+ // should also be generating the loads of the parameters, as the runtime
+ // should have full control over how parameters are passed.
+ virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) = 0;
+
+ /// Return the runtime function for getting properties.
+ virtual llvm::Constant *GetPropertyGetFunction() = 0;
+
+ /// Return the runtime function for setting properties.
+ virtual llvm::Constant *GetPropertySetFunction() = 0;
+
+ /// GetClass - Return a reference to the class for the given
+ /// interface decl.
+ virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ const ObjCInterfaceDecl *OID) = 0;
+
+ /// EnumerationMutationFunction - Return the function that's called by the
+ /// compiler when a mutation is detected during foreach iteration.
+ virtual llvm::Constant *EnumerationMutationFunction() = 0;
+
+ virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
+ const Stmt &S) = 0;
+ virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
+ const ObjCAtThrowStmt &S) = 0;
+ virtual llvm::Value *EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *AddrWeakObj) = 0;
+ virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest) = 0;
+ virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest) = 0;
+ virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest) = 0;
+ virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest) = 0;
+
+ virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
+ QualType ObjectTy,
+ llvm::Value *BaseValue,
+ const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers) = 0;
+ virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *Interface,
+ const ObjCIvarDecl *Ivar) = 0;
+};
+
+/// Creates an instance of an Objective-C runtime class.
+//TODO: This should include some way of selecting which runtime to target.
+CGObjCRuntime *CreateGNUObjCRuntime(CodeGenModule &CGM);
+CGObjCRuntime *CreateMacObjCRuntime(CodeGenModule &CGM);
+CGObjCRuntime *CreateMacNonFragileABIObjCRuntime(CodeGenModule &CGM);
+}
+}
+#endif
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
new file mode 100644
index 000000000000..b67996c67630
--- /dev/null
+++ b/lib/CodeGen/CGStmt.cpp
@@ -0,0 +1,1022 @@
+//===--- CGStmt.cpp - Emit LLVM Code from Statements ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit Stmt nodes as LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGDebugInfo.h"
+#include "CodeGenModule.h"
+#include "CodeGenFunction.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/InlineAsm.h"
+#include "llvm/Intrinsics.h"
+#include "llvm/Target/TargetData.h"
+using namespace clang;
+using namespace CodeGen;
+
+//===----------------------------------------------------------------------===//
+// Statement Emission
+//===----------------------------------------------------------------------===//
+
+void CodeGenFunction::EmitStopPoint(const Stmt *S) {
+ if (CGDebugInfo *DI = getDebugInfo()) {
+ DI->setLocation(S->getLocStart());
+ DI->EmitStopPoint(CurFn, Builder);
+ }
+}
+
+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.
+ if (EmitSimpleStmt(S))
+ return;
+
+ // If we happen to be at an unreachable point just create a dummy
+ // basic block to hold the code. We could change parts of irgen to
+ // simply not generate this code, but this situation is rare and
+ // probably not worth the effort.
+ // FIXME: Verify previous performance/effort claim.
+ EnsureInsertPoint();
+
+ // Generate a stoppoint if we are emitting debug info.
+ EmitStopPoint(S);
+
+ switch (S->getStmtClass()) {
+ default:
+ // Must be an expression in a stmt context. Emit the value (to get
+ // side-effects) and ignore the result.
+ if (const Expr *E = dyn_cast<Expr>(S)) {
+ EmitAnyExpr(E, 0, false, true);
+ } else {
+ ErrorUnsupported(S, "statement");
+ }
+ break;
+ case Stmt::IndirectGotoStmtClass:
+ EmitIndirectGotoStmt(cast<IndirectGotoStmt>(*S)); break;
+
+ case Stmt::IfStmtClass: EmitIfStmt(cast<IfStmt>(*S)); break;
+ case Stmt::WhileStmtClass: EmitWhileStmt(cast<WhileStmt>(*S)); break;
+ case Stmt::DoStmtClass: EmitDoStmt(cast<DoStmt>(*S)); break;
+ case Stmt::ForStmtClass: EmitForStmt(cast<ForStmt>(*S)); break;
+
+ case Stmt::ReturnStmtClass: EmitReturnStmt(cast<ReturnStmt>(*S)); break;
+ case Stmt::DeclStmtClass: EmitDeclStmt(cast<DeclStmt>(*S)); break;
+
+ case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break;
+ case Stmt::AsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break;
+
+ case Stmt::ObjCAtTryStmtClass:
+ EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S));
+ break;
+ case Stmt::ObjCAtCatchStmtClass:
+ assert(0 && "@catch statements should be handled by EmitObjCAtTryStmt");
+ break;
+ case Stmt::ObjCAtFinallyStmtClass:
+ assert(0 && "@finally statements should be handled by EmitObjCAtTryStmt");
+ break;
+ case Stmt::ObjCAtThrowStmtClass:
+ EmitObjCAtThrowStmt(cast<ObjCAtThrowStmt>(*S));
+ break;
+ case Stmt::ObjCAtSynchronizedStmtClass:
+ EmitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(*S));
+ break;
+ case Stmt::ObjCForCollectionStmtClass:
+ EmitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(*S));
+ break;
+ }
+}
+
+bool CodeGenFunction::EmitSimpleStmt(const Stmt *S) {
+ switch (S->getStmtClass()) {
+ default: return false;
+ case Stmt::NullStmtClass: break;
+ case Stmt::CompoundStmtClass: EmitCompoundStmt(cast<CompoundStmt>(*S)); break;
+ case Stmt::LabelStmtClass: EmitLabelStmt(cast<LabelStmt>(*S)); break;
+ case Stmt::GotoStmtClass: EmitGotoStmt(cast<GotoStmt>(*S)); break;
+ case Stmt::BreakStmtClass: EmitBreakStmt(cast<BreakStmt>(*S)); break;
+ case Stmt::ContinueStmtClass: EmitContinueStmt(cast<ContinueStmt>(*S)); break;
+ case Stmt::DefaultStmtClass: EmitDefaultStmt(cast<DefaultStmt>(*S)); break;
+ case Stmt::CaseStmtClass: EmitCaseStmt(cast<CaseStmt>(*S)); break;
+ }
+
+ return true;
+}
+
+/// EmitCompoundStmt - Emit a compound statement {..} node. If GetLast is true,
+/// this captures the expression result of the last sub-statement and returns it
+/// (for use by the statement expression extension).
+RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
+ llvm::Value *AggLoc, bool isAggVol) {
+ PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),S.getLBracLoc(),
+ "LLVM IR generation of compound statement ('{}')");
+
+ CGDebugInfo *DI = getDebugInfo();
+ if (DI) {
+ EnsureInsertPoint();
+ DI->setLocation(S.getLBracLoc());
+ // FIXME: The llvm backend is currently not ready to deal with region_end
+ // for block scoping. In the presence of always_inline functions it gets so
+ // confused that it doesn't emit any debug info. Just disable this for now.
+ //DI->EmitRegionStart(CurFn, Builder);
+ }
+
+ // Keep track of the current cleanup stack depth.
+ size_t CleanupStackDepth = CleanupEntries.size();
+ bool OldDidCallStackSave = DidCallStackSave;
+ DidCallStackSave = false;
+
+ for (CompoundStmt::const_body_iterator I = S.body_begin(),
+ E = S.body_end()-GetLast; I != E; ++I)
+ EmitStmt(*I);
+
+ if (DI) {
+ EnsureInsertPoint();
+ DI->setLocation(S.getRBracLoc());
+
+ // FIXME: The llvm backend is currently not ready to deal with region_end
+ // for block scoping. In the presence of always_inline functions it gets so
+ // confused that it doesn't emit any debug info. Just disable this for now.
+ //DI->EmitRegionEnd(CurFn, Builder);
+ }
+
+ RValue RV;
+ if (!GetLast)
+ RV = RValue::get(0);
+ else {
+ // We have to special case labels here. They are statements, but when put
+ // at the end of a statement expression, they yield the value of their
+ // subexpression. Handle this by walking through all labels we encounter,
+ // emitting them before we evaluate the subexpr.
+ const Stmt *LastStmt = S.body_back();
+ while (const LabelStmt *LS = dyn_cast<LabelStmt>(LastStmt)) {
+ EmitLabel(*LS);
+ LastStmt = LS->getSubStmt();
+ }
+
+ EnsureInsertPoint();
+
+ RV = EmitAnyExpr(cast<Expr>(LastStmt), AggLoc);
+ }
+
+ DidCallStackSave = OldDidCallStackSave;
+
+ EmitCleanupBlocks(CleanupStackDepth);
+
+ return RV;
+}
+
+void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) {
+ llvm::BranchInst *BI = dyn_cast<llvm::BranchInst>(BB->getTerminator());
+
+ // If there is a cleanup stack, then we it isn't worth trying to
+ // simplify this block (we would need to remove it from the scope map
+ // and cleanup entry).
+ if (!CleanupEntries.empty())
+ return;
+
+ // Can only simplify direct branches.
+ if (!BI || !BI->isUnconditional())
+ return;
+
+ BB->replaceAllUsesWith(BI->getSuccessor(0));
+ BI->eraseFromParent();
+ BB->eraseFromParent();
+}
+
+void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) {
+ // Fall out of the current block (if necessary).
+ EmitBranch(BB);
+
+ if (IsFinished && BB->use_empty()) {
+ delete BB;
+ return;
+ }
+
+ // If necessary, associate the block with the cleanup stack size.
+ if (!CleanupEntries.empty()) {
+ // Check if the basic block has already been inserted.
+ BlockScopeMap::iterator I = BlockScopes.find(BB);
+ if (I != BlockScopes.end()) {
+ assert(I->second == CleanupEntries.size() - 1);
+ } else {
+ BlockScopes[BB] = CleanupEntries.size() - 1;
+ CleanupEntries.back().Blocks.push_back(BB);
+ }
+ }
+
+ CurFn->getBasicBlockList().push_back(BB);
+ Builder.SetInsertPoint(BB);
+}
+
+void CodeGenFunction::EmitBranch(llvm::BasicBlock *Target) {
+ // Emit a branch from the current block to the target one if this
+ // was a real block. If this was just a fall-through block after a
+ // terminator, don't emit it.
+ llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
+
+ if (!CurBB || CurBB->getTerminator()) {
+ // If there is no insert point or the previous block is already
+ // terminated, don't touch it.
+ } else {
+ // Otherwise, create a fall-through branch.
+ Builder.CreateBr(Target);
+ }
+
+ Builder.ClearInsertionPoint();
+}
+
+void CodeGenFunction::EmitLabel(const LabelStmt &S) {
+ EmitBlock(getBasicBlockForLabel(&S));
+}
+
+
+void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
+ EmitLabel(S);
+ EmitStmt(S.getSubStmt());
+}
+
+void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
+ // If this code is reachable then emit a stop point (if generating
+ // debug info). We have to do this ourselves because we are on the
+ // "simple" statement path.
+ if (HaveInsertPoint())
+ EmitStopPoint(&S);
+
+ EmitBranchThroughCleanup(getBasicBlockForLabel(S.getLabel()));
+}
+
+void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) {
+ // Emit initial switch which will be patched up later by
+ // EmitIndirectSwitches(). We need a default dest, so we use the
+ // current BB, but this is overwritten.
+ llvm::Value *V = Builder.CreatePtrToInt(EmitScalarExpr(S.getTarget()),
+ llvm::Type::Int32Ty,
+ "addr");
+ llvm::SwitchInst *I = Builder.CreateSwitch(V, Builder.GetInsertBlock());
+ IndirectSwitches.push_back(I);
+
+ // Clear the insertion point to indicate we are in unreachable code.
+ Builder.ClearInsertionPoint();
+}
+
+void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
+ // C99 6.8.4.1: The first substatement is executed if the expression compares
+ // unequal to 0. The condition must be a scalar type.
+
+ // If the condition constant folds and can be elided, try to avoid emitting
+ // the condition and the dead arm of the if/else.
+ if (int Cond = ConstantFoldsToSimpleInteger(S.getCond())) {
+ // Figure out which block (then or else) is executed.
+ const Stmt *Executed = S.getThen(), *Skipped = S.getElse();
+ if (Cond == -1) // Condition false?
+ std::swap(Executed, Skipped);
+
+ // If the skipped block has no labels in it, just emit the executed block.
+ // This avoids emitting dead code and simplifies the CFG substantially.
+ if (!ContainsLabel(Skipped)) {
+ if (Executed)
+ EmitStmt(Executed);
+ return;
+ }
+ }
+
+ // Otherwise, the condition did not fold, or we couldn't elide it. Just emit
+ // the conditional branch.
+ llvm::BasicBlock *ThenBlock = createBasicBlock("if.then");
+ llvm::BasicBlock *ContBlock = createBasicBlock("if.end");
+ llvm::BasicBlock *ElseBlock = ContBlock;
+ if (S.getElse())
+ ElseBlock = createBasicBlock("if.else");
+ EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock);
+
+ // Emit the 'then' code.
+ EmitBlock(ThenBlock);
+ EmitStmt(S.getThen());
+ EmitBranch(ContBlock);
+
+ // Emit the 'else' code if present.
+ if (const Stmt *Else = S.getElse()) {
+ EmitBlock(ElseBlock);
+ EmitStmt(Else);
+ EmitBranch(ContBlock);
+ }
+
+ // Emit the continuation block for code after the if.
+ EmitBlock(ContBlock, true);
+}
+
+void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
+ // Emit the header for the loop, insert it, which will create an uncond br to
+ // it.
+ llvm::BasicBlock *LoopHeader = createBasicBlock("while.cond");
+ EmitBlock(LoopHeader);
+
+ // Create an exit block for when the condition fails, create a block for the
+ // body of the loop.
+ llvm::BasicBlock *ExitBlock = createBasicBlock("while.end");
+ llvm::BasicBlock *LoopBody = createBasicBlock("while.body");
+
+ // Store the blocks to use for break and continue.
+ BreakContinueStack.push_back(BreakContinue(ExitBlock, LoopHeader));
+
+ // Evaluate the conditional in the while header. C99 6.8.5.1: The
+ // evaluation of the controlling expression takes place before each
+ // execution of the loop body.
+ llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
+
+ // while(1) is common, avoid extra exit blocks. Be sure
+ // to correctly handle break/continue though.
+ bool EmitBoolCondBranch = true;
+ if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
+ if (C->isOne())
+ EmitBoolCondBranch = false;
+
+ // As long as the condition is true, go to the loop body.
+ if (EmitBoolCondBranch)
+ Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock);
+
+ // Emit the loop body.
+ EmitBlock(LoopBody);
+ EmitStmt(S.getBody());
+
+ BreakContinueStack.pop_back();
+
+ // Cycle to the condition.
+ EmitBranch(LoopHeader);
+
+ // Emit the exit block.
+ EmitBlock(ExitBlock, true);
+
+ // The LoopHeader typically is just a branch if we skipped emitting
+ // a branch, try to erase it.
+ if (!EmitBoolCondBranch)
+ SimplifyForwardingBlocks(LoopHeader);
+}
+
+void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
+ // Emit the body for the loop, insert it, which will create an uncond br to
+ // it.
+ llvm::BasicBlock *LoopBody = createBasicBlock("do.body");
+ llvm::BasicBlock *AfterDo = createBasicBlock("do.end");
+ EmitBlock(LoopBody);
+
+ llvm::BasicBlock *DoCond = createBasicBlock("do.cond");
+
+ // Store the blocks to use for break and continue.
+ BreakContinueStack.push_back(BreakContinue(AfterDo, DoCond));
+
+ // Emit the body of the loop into the block.
+ EmitStmt(S.getBody());
+
+ BreakContinueStack.pop_back();
+
+ EmitBlock(DoCond);
+
+ // C99 6.8.5.2: "The evaluation of the controlling expression takes place
+ // after each execution of the loop body."
+
+ // Evaluate the conditional in the while header.
+ // C99 6.8.5p2/p4: The first substatement is executed if the expression
+ // compares unequal to 0. The condition must be a scalar type.
+ llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
+
+ // "do {} while (0)" is common in macros, avoid extra blocks. Be sure
+ // to correctly handle break/continue though.
+ bool EmitBoolCondBranch = true;
+ if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
+ if (C->isZero())
+ EmitBoolCondBranch = false;
+
+ // As long as the condition is true, iterate the loop.
+ if (EmitBoolCondBranch)
+ Builder.CreateCondBr(BoolCondVal, LoopBody, AfterDo);
+
+ // Emit the exit block.
+ EmitBlock(AfterDo);
+
+ // The DoCond block typically is just a branch if we skipped
+ // emitting a branch, try to erase it.
+ if (!EmitBoolCondBranch)
+ SimplifyForwardingBlocks(DoCond);
+}
+
+void CodeGenFunction::EmitForStmt(const ForStmt &S) {
+ // FIXME: What do we do if the increment (f.e.) contains a stmt expression,
+ // which contains a continue/break?
+
+ // Evaluate the first part before the loop.
+ if (S.getInit())
+ EmitStmt(S.getInit());
+
+ // Start the loop with a block that tests the condition.
+ llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
+ llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
+
+ EmitBlock(CondBlock);
+
+ // Evaluate the condition if present. If not, treat it as a
+ // non-zero-constant according to 6.8.5.3p2, aka, true.
+ if (S.getCond()) {
+ // As long as the condition is true, iterate the loop.
+ llvm::BasicBlock *ForBody = createBasicBlock("for.body");
+
+ // C99 6.8.5p2/p4: The first substatement is executed if the expression
+ // compares unequal to 0. The condition must be a scalar type.
+ EmitBranchOnBoolExpr(S.getCond(), ForBody, AfterFor);
+
+ EmitBlock(ForBody);
+ } else {
+ // Treat it as a non-zero constant. Don't even create a new block for the
+ // body, just fall into it.
+ }
+
+ // If the for loop doesn't have an increment we can just use the
+ // condition as the continue block.
+ llvm::BasicBlock *ContinueBlock;
+ if (S.getInc())
+ ContinueBlock = createBasicBlock("for.inc");
+ else
+ ContinueBlock = CondBlock;
+
+ // Store the blocks to use for break and continue.
+ BreakContinueStack.push_back(BreakContinue(AfterFor, ContinueBlock));
+
+ // If the condition is true, execute the body of the for stmt.
+ EmitStmt(S.getBody());
+
+ BreakContinueStack.pop_back();
+
+ // If there is an increment, emit it next.
+ if (S.getInc()) {
+ EmitBlock(ContinueBlock);
+ EmitStmt(S.getInc());
+ }
+
+ // Finally, branch back up to the condition for the next iteration.
+ EmitBranch(CondBlock);
+
+ // Emit the fall-through block.
+ EmitBlock(AfterFor, true);
+}
+
+void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
+ if (RV.isScalar()) {
+ Builder.CreateStore(RV.getScalarVal(), ReturnValue);
+ } else if (RV.isAggregate()) {
+ EmitAggregateCopy(ReturnValue, RV.getAggregateAddr(), Ty);
+ } else {
+ StoreComplexToAddr(RV.getComplexVal(), ReturnValue, false);
+ }
+ EmitBranchThroughCleanup(ReturnBlock);
+}
+
+/// EmitReturnStmt - Note that due to GCC extensions, this can have an operand
+/// if the function returns void, or may be missing one if the function returns
+/// non-void. Fun stuff :).
+void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
+ // Emit the result value, even if unused, to evalute the side effects.
+ const Expr *RV = S.getRetValue();
+
+ // FIXME: Clean this up by using an LValue for ReturnTemp,
+ // EmitStoreThroughLValue, and EmitAnyExpr.
+ if (!ReturnValue) {
+ // Make sure not to return anything, but evaluate the expression
+ // for side effects.
+ if (RV)
+ EmitAnyExpr(RV);
+ } else if (RV == 0) {
+ // Do nothing (return value is left uninitialized)
+ } else if (FnRetTy->isReferenceType()) {
+ // If this function returns a reference, take the address of the expression
+ // rather than the value.
+ Builder.CreateStore(EmitLValue(RV).getAddress(), ReturnValue);
+ } else if (!hasAggregateLLVMType(RV->getType())) {
+ Builder.CreateStore(EmitScalarExpr(RV), ReturnValue);
+ } else if (RV->getType()->isAnyComplexType()) {
+ EmitComplexExprIntoAddr(RV, ReturnValue, false);
+ } else {
+ EmitAggExpr(RV, ReturnValue, false);
+ }
+
+ EmitBranchThroughCleanup(ReturnBlock);
+}
+
+void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) {
+ for (DeclStmt::const_decl_iterator I = S.decl_begin(), E = S.decl_end();
+ I != E; ++I)
+ EmitDecl(**I);
+}
+
+void CodeGenFunction::EmitBreakStmt(const BreakStmt &S) {
+ assert(!BreakContinueStack.empty() && "break stmt not in a loop or switch!");
+
+ // If this code is reachable then emit a stop point (if generating
+ // debug info). We have to do this ourselves because we are on the
+ // "simple" statement path.
+ if (HaveInsertPoint())
+ EmitStopPoint(&S);
+
+ llvm::BasicBlock *Block = BreakContinueStack.back().BreakBlock;
+ EmitBranchThroughCleanup(Block);
+}
+
+void CodeGenFunction::EmitContinueStmt(const ContinueStmt &S) {
+ assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
+
+ // If this code is reachable then emit a stop point (if generating
+ // debug info). We have to do this ourselves because we are on the
+ // "simple" statement path.
+ if (HaveInsertPoint())
+ EmitStopPoint(&S);
+
+ llvm::BasicBlock *Block = BreakContinueStack.back().ContinueBlock;
+ EmitBranchThroughCleanup(Block);
+}
+
+/// EmitCaseStmtRange - If case statement range is not too big then
+/// add multiple cases to switch instruction, one for each value within
+/// the range. If range is too big then emit "if" condition check.
+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());
+
+ // Emit the code for this case. We do this first to make sure it is
+ // properly chained from our predecessor before generating the
+ // switch machinery to enter this block.
+ EmitBlock(createBasicBlock("sw.bb"));
+ llvm::BasicBlock *CaseDest = Builder.GetInsertBlock();
+ EmitStmt(S.getSubStmt());
+
+ // If range is empty, do nothing.
+ if (LHS.isSigned() ? RHS.slt(LHS) : RHS.ult(LHS))
+ return;
+
+ llvm::APInt Range = RHS - LHS;
+ // FIXME: parameters such as this should not be hardcoded.
+ if (Range.ult(llvm::APInt(Range.getBitWidth(), 64))) {
+ // Range is small enough to add multiple switch instruction cases.
+ for (unsigned i = 0, e = Range.getZExtValue() + 1; i != e; ++i) {
+ SwitchInsn->addCase(llvm::ConstantInt::get(LHS), CaseDest);
+ LHS++;
+ }
+ return;
+ }
+
+ // The range is too big. Emit "if" condition into a new block,
+ // making sure to save and restore the current insertion point.
+ llvm::BasicBlock *RestoreBB = Builder.GetInsertBlock();
+
+ // Push this test onto the chain of range checks (which terminates
+ // in the default basic block). The switch's default will be changed
+ // to the top of this chain after switch emission is complete.
+ llvm::BasicBlock *FalseDest = CaseRangeBlock;
+ CaseRangeBlock = createBasicBlock("sw.caserange");
+
+ CurFn->getBasicBlockList().push_back(CaseRangeBlock);
+ Builder.SetInsertPoint(CaseRangeBlock);
+
+ // Emit range check.
+ llvm::Value *Diff =
+ Builder.CreateSub(SwitchInsn->getCondition(), llvm::ConstantInt::get(LHS),
+ "tmp");
+ llvm::Value *Cond =
+ Builder.CreateICmpULE(Diff, llvm::ConstantInt::get(Range), "tmp");
+ Builder.CreateCondBr(Cond, CaseDest, FalseDest);
+
+ // Restore the appropriate insertion point.
+ if (RestoreBB)
+ Builder.SetInsertPoint(RestoreBB);
+ else
+ Builder.ClearInsertionPoint();
+}
+
+void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
+ if (S.getRHS()) {
+ EmitCaseStmtRange(S);
+ return;
+ }
+
+ EmitBlock(createBasicBlock("sw.bb"));
+ llvm::BasicBlock *CaseDest = Builder.GetInsertBlock();
+ llvm::APSInt CaseVal = S.getLHS()->EvaluateAsInt(getContext());
+ SwitchInsn->addCase(llvm::ConstantInt::get(CaseVal), CaseDest);
+
+ // Recursively emitting the statement is acceptable, but is not wonderful for
+ // code where we have many case statements nested together, i.e.:
+ // case 1:
+ // case 2:
+ // case 3: etc.
+ // Handling this recursively will create a new block for each case statement
+ // that falls through to the next case which is IR intensive. It also causes
+ // deep recursion which can run into stack depth limitations. Handle
+ // sequential non-range case statements specially.
+ const CaseStmt *CurCase = &S;
+ const CaseStmt *NextCase = dyn_cast<CaseStmt>(S.getSubStmt());
+
+ // Otherwise, iteratively add consequtive cases to this switch stmt.
+ while (NextCase && NextCase->getRHS() == 0) {
+ CurCase = NextCase;
+ CaseVal = CurCase->getLHS()->EvaluateAsInt(getContext());
+ SwitchInsn->addCase(llvm::ConstantInt::get(CaseVal), CaseDest);
+
+ NextCase = dyn_cast<CaseStmt>(CurCase->getSubStmt());
+ }
+
+ // Normal default recursion for non-cases.
+ EmitStmt(CurCase->getSubStmt());
+}
+
+void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S) {
+ llvm::BasicBlock *DefaultBlock = SwitchInsn->getDefaultDest();
+ assert(DefaultBlock->empty() &&
+ "EmitDefaultStmt: Default block already defined?");
+ EmitBlock(DefaultBlock);
+ EmitStmt(S.getSubStmt());
+}
+
+void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
+ llvm::Value *CondV = EmitScalarExpr(S.getCond());
+
+ // Handle nested switch statements.
+ llvm::SwitchInst *SavedSwitchInsn = SwitchInsn;
+ llvm::BasicBlock *SavedCRBlock = CaseRangeBlock;
+
+ // Create basic block to hold stuff that comes after switch
+ // statement. We also need to create a default block now so that
+ // explicit case ranges tests can have a place to jump to on
+ // failure.
+ llvm::BasicBlock *NextBlock = createBasicBlock("sw.epilog");
+ llvm::BasicBlock *DefaultBlock = createBasicBlock("sw.default");
+ SwitchInsn = Builder.CreateSwitch(CondV, DefaultBlock);
+ CaseRangeBlock = DefaultBlock;
+
+ // Clear the insertion point to indicate we are in unreachable code.
+ Builder.ClearInsertionPoint();
+
+ // All break statements jump to NextBlock. If BreakContinueStack is non empty
+ // then reuse last ContinueBlock.
+ llvm::BasicBlock *ContinueBlock = 0;
+ if (!BreakContinueStack.empty())
+ ContinueBlock = BreakContinueStack.back().ContinueBlock;
+
+ // Ensure any vlas created between there and here, are undone
+ BreakContinueStack.push_back(BreakContinue(NextBlock, ContinueBlock));
+
+ // Emit switch body.
+ EmitStmt(S.getBody());
+
+ BreakContinueStack.pop_back();
+
+ // Update the default block in case explicit case range tests have
+ // been chained on top.
+ SwitchInsn->setSuccessor(0, CaseRangeBlock);
+
+ // If a default was never emitted then reroute any jumps to it and
+ // discard.
+ if (!DefaultBlock->getParent()) {
+ DefaultBlock->replaceAllUsesWith(NextBlock);
+ delete DefaultBlock;
+ }
+
+ // Emit continuation.
+ EmitBlock(NextBlock, true);
+
+ SwitchInsn = SavedSwitchInsn;
+ CaseRangeBlock = SavedCRBlock;
+}
+
+static std::string
+SimplifyConstraint(const char *Constraint, TargetInfo &Target,
+ llvm::SmallVectorImpl<TargetInfo::ConstraintInfo> *OutCons=0) {
+ std::string Result;
+
+ while (*Constraint) {
+ switch (*Constraint) {
+ default:
+ Result += Target.convertConstraint(*Constraint);
+ break;
+ // Ignore these
+ case '*':
+ case '?':
+ case '!':
+ break;
+ case 'g':
+ Result += "imr";
+ break;
+ case '[': {
+ assert(OutCons &&
+ "Must pass output names to constraints with a symbolic name");
+ unsigned Index;
+ bool result = Target.resolveSymbolicName(Constraint,
+ &(*OutCons)[0],
+ OutCons->size(), Index);
+ assert(result && "Could not resolve symbolic name"); result=result;
+ Result += llvm::utostr(Index);
+ break;
+ }
+ }
+
+ Constraint++;
+ }
+
+ return Result;
+}
+
+llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S,
+ const TargetInfo::ConstraintInfo &Info,
+ const Expr *InputExpr,
+ std::string &ConstraintStr) {
+ llvm::Value *Arg;
+ if (Info.allowsRegister() || !Info.allowsMemory()) {
+ const llvm::Type *Ty = ConvertType(InputExpr->getType());
+
+ if (Ty->isSingleValueType()) {
+ Arg = EmitScalarExpr(InputExpr);
+ } else {
+ InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
+ LValue Dest = EmitLValue(InputExpr);
+
+ uint64_t Size = CGM.getTargetData().getTypeSizeInBits(Ty);
+ if (Size <= 64 && llvm::isPowerOf2_64(Size)) {
+ Ty = llvm::IntegerType::get(Size);
+ Ty = llvm::PointerType::getUnqual(Ty);
+
+ Arg = Builder.CreateLoad(Builder.CreateBitCast(Dest.getAddress(), Ty));
+ } else {
+ Arg = Dest.getAddress();
+ ConstraintStr += '*';
+ }
+ }
+ } else {
+ InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
+ LValue Dest = EmitLValue(InputExpr);
+ Arg = Dest.getAddress();
+ ConstraintStr += '*';
+ }
+
+ return Arg;
+}
+
+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;
+ unsigned DiagOffs;
+ S.AnalyzeAsmString(Pieces, getContext(), DiagOffs);
+
+ // Assemble the pieces into the final asm string.
+ std::string AsmString;
+ for (unsigned i = 0, e = Pieces.size(); i != e; ++i) {
+ if (Pieces[i].isString())
+ AsmString += Pieces[i].getString();
+ else if (Pieces[i].getModifier() == '\0')
+ AsmString += '$' + llvm::utostr(Pieces[i].getOperandNo());
+ else
+ AsmString += "${" + llvm::utostr(Pieces[i].getOperandNo()) + ':' +
+ Pieces[i].getModifier() + '}';
+ }
+
+ // Get all the output and input constraints together.
+ llvm::SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
+ llvm::SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
+
+ for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
+ TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i),
+ S.getOutputName(i));
+ bool result = Target.validateOutputConstraint(Info);
+ assert(result && "Failed to parse output constraint"); result=result;
+ OutputConstraintInfos.push_back(Info);
+ }
+
+ for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) {
+ TargetInfo::ConstraintInfo Info(S.getInputConstraint(i),
+ S.getInputName(i));
+ bool result = Target.validateInputConstraint(OutputConstraintInfos.data(),
+ S.getNumOutputs(),
+ Info); result=result;
+ assert(result && "Failed to parse input constraint");
+ InputConstraintInfos.push_back(Info);
+ }
+
+ std::string Constraints;
+
+ std::vector<LValue> ResultRegDests;
+ std::vector<QualType> ResultRegQualTys;
+ std::vector<const llvm::Type *> ResultRegTypes;
+ std::vector<const llvm::Type *> ResultTruncRegTypes;
+ std::vector<const llvm::Type*> ArgTypes;
+ std::vector<llvm::Value*> Args;
+
+ // Keep track of inout constraints.
+ std::string InOutConstraints;
+ std::vector<llvm::Value*> InOutArgs;
+ std::vector<const llvm::Type*> InOutArgTypes;
+
+ for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
+ TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i];
+
+ // Simplify the output constraint.
+ std::string OutputConstraint(S.getOutputConstraint(i));
+ OutputConstraint = SimplifyConstraint(OutputConstraint.c_str() + 1, Target);
+
+ const Expr *OutExpr = S.getOutputExpr(i);
+ OutExpr = OutExpr->IgnoreParenNoopCasts(getContext());
+
+ LValue Dest = EmitLValue(OutExpr);
+ if (!Constraints.empty())
+ Constraints += ',';
+
+ // If this is a register output, then make the inline asm return it
+ // by-value. If this is a memory result, return the value by-reference.
+ if (!Info.allowsMemory() && !hasAggregateLLVMType(OutExpr->getType())) {
+ Constraints += "=" + OutputConstraint;
+ ResultRegQualTys.push_back(OutExpr->getType());
+ ResultRegDests.push_back(Dest);
+ ResultRegTypes.push_back(ConvertTypeForMem(OutExpr->getType()));
+ ResultTruncRegTypes.push_back(ResultRegTypes.back());
+
+ // If this output is tied to an input, and if the input is larger, then
+ // we need to set the actual result type of the inline asm node to be the
+ // same as the input type.
+ if (Info.hasMatchingInput()) {
+ unsigned InputNo;
+ for (InputNo = 0; InputNo != S.getNumInputs(); ++InputNo) {
+ TargetInfo::ConstraintInfo &Input = InputConstraintInfos[InputNo];
+ if (Input.hasTiedOperand() &&
+ Input.getTiedOperand() == i)
+ break;
+ }
+ assert(InputNo != S.getNumInputs() && "Didn't find matching input!");
+
+ QualType InputTy = S.getInputExpr(InputNo)->getType();
+ QualType OutputTy = OutExpr->getType();
+
+ uint64_t InputSize = getContext().getTypeSize(InputTy);
+ if (getContext().getTypeSize(OutputTy) < InputSize) {
+ // Form the asm to return the value as a larger integer type.
+ ResultRegTypes.back() = llvm::IntegerType::get((unsigned)InputSize);
+ }
+ }
+
+ } else {
+ ArgTypes.push_back(Dest.getAddress()->getType());
+ Args.push_back(Dest.getAddress());
+ Constraints += "=*";
+ Constraints += OutputConstraint;
+ }
+
+ if (Info.isReadWrite()) {
+ InOutConstraints += ',';
+
+ const Expr *InputExpr = S.getOutputExpr(i);
+ llvm::Value *Arg = EmitAsmInput(S, Info, InputExpr, InOutConstraints);
+
+ if (Info.allowsRegister())
+ InOutConstraints += llvm::utostr(i);
+ else
+ InOutConstraints += OutputConstraint;
+
+ InOutArgTypes.push_back(Arg->getType());
+ InOutArgs.push_back(Arg);
+ }
+ }
+
+ unsigned NumConstraints = S.getNumOutputs() + S.getNumInputs();
+
+ for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) {
+ const Expr *InputExpr = S.getInputExpr(i);
+
+ TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
+
+ if (!Constraints.empty())
+ Constraints += ',';
+
+ // Simplify the input constraint.
+ std::string InputConstraint(S.getInputConstraint(i));
+ InputConstraint = SimplifyConstraint(InputConstraint.c_str(), Target,
+ &OutputConstraintInfos);
+
+ llvm::Value *Arg = EmitAsmInput(S, Info, InputExpr, Constraints);
+
+ // If this input argument is tied to a larger output result, extend the
+ // input to be the same size as the output. The LLVM backend wants to see
+ // the input and output of a matching constraint be the same size. Note
+ // that GCC does not define what the top bits are here. We use zext because
+ // that is usually cheaper, but LLVM IR should really get an anyext someday.
+ if (Info.hasTiedOperand()) {
+ unsigned Output = Info.getTiedOperand();
+ QualType OutputTy = S.getOutputExpr(Output)->getType();
+ QualType InputTy = InputExpr->getType();
+
+ if (getContext().getTypeSize(OutputTy) >
+ getContext().getTypeSize(InputTy)) {
+ // Use ptrtoint as appropriate so that we can do our extension.
+ if (isa<llvm::PointerType>(Arg->getType()))
+ Arg = Builder.CreatePtrToInt(Arg,
+ llvm::IntegerType::get(LLVMPointerWidth));
+ unsigned OutputSize = (unsigned)getContext().getTypeSize(OutputTy);
+ Arg = Builder.CreateZExt(Arg, llvm::IntegerType::get(OutputSize));
+ }
+ }
+
+
+ ArgTypes.push_back(Arg->getType());
+ Args.push_back(Arg);
+ Constraints += InputConstraint;
+ }
+
+ // Append the "input" part of inout constraints last.
+ for (unsigned i = 0, e = InOutArgs.size(); i != e; i++) {
+ ArgTypes.push_back(InOutArgTypes[i]);
+ Args.push_back(InOutArgs[i]);
+ }
+ Constraints += InOutConstraints;
+
+ // Clobbers
+ for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) {
+ std::string Clobber(S.getClobber(i)->getStrData(),
+ S.getClobber(i)->getByteLength());
+
+ Clobber = Target.getNormalizedGCCRegisterName(Clobber.c_str());
+
+ if (i != 0 || NumConstraints != 0)
+ Constraints += ',';
+
+ Constraints += "~{";
+ Constraints += Clobber;
+ Constraints += '}';
+ }
+
+ // Add machine specific clobbers
+ std::string MachineClobbers = Target.getClobbers();
+ if (!MachineClobbers.empty()) {
+ if (!Constraints.empty())
+ Constraints += ',';
+ Constraints += MachineClobbers;
+ }
+
+ const llvm::Type *ResultType;
+ if (ResultRegTypes.empty())
+ ResultType = llvm::Type::VoidTy;
+ else if (ResultRegTypes.size() == 1)
+ ResultType = ResultRegTypes[0];
+ else
+ ResultType = llvm::StructType::get(ResultRegTypes);
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(ResultType, ArgTypes, false);
+
+ llvm::InlineAsm *IA =
+ llvm::InlineAsm::get(FTy, AsmString, Constraints,
+ S.isVolatile() || S.getNumOutputs() == 0);
+ llvm::CallInst *Result = Builder.CreateCall(IA, Args.begin(), Args.end());
+ Result->addAttribute(~0, llvm::Attribute::NoUnwind);
+
+
+ // Extract all of the register value results from the asm.
+ std::vector<llvm::Value*> RegResults;
+ if (ResultRegTypes.size() == 1) {
+ RegResults.push_back(Result);
+ } else {
+ for (unsigned i = 0, e = ResultRegTypes.size(); i != e; ++i) {
+ llvm::Value *Tmp = Builder.CreateExtractValue(Result, i, "asmresult");
+ RegResults.push_back(Tmp);
+ }
+ }
+
+ for (unsigned i = 0, e = RegResults.size(); i != e; ++i) {
+ llvm::Value *Tmp = RegResults[i];
+
+ // 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];
+ // Truncate the integer result to the right size, note that
+ // ResultTruncRegTypes can be a pointer.
+ uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy);
+ Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get((unsigned)ResSize));
+
+ if (Tmp->getType() != TruncTy) {
+ assert(isa<llvm::PointerType>(TruncTy));
+ Tmp = Builder.CreateIntToPtr(Tmp, TruncTy);
+ }
+ }
+
+ EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i],
+ ResultRegQualTys[i]);
+ }
+}
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
new file mode 100644
index 000000000000..820e1bd6c3ec
--- /dev/null
+++ b/lib/CodeGen/CGValue.h
@@ -0,0 +1,323 @@
+//===-- CGValue.h - LLVM CodeGen wrappers for llvm::Value* ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes implement wrappers around llvm::Value in order to
+// fully represent the range of values for C L- and R- values.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CGVALUE_H
+#define CLANG_CODEGEN_CGVALUE_H
+
+#include "clang/AST/Type.h"
+
+namespace llvm {
+ class Constant;
+ class Value;
+}
+
+namespace clang {
+ class ObjCPropertyRefExpr;
+ class ObjCKVCRefExpr;
+
+namespace CodeGen {
+
+/// RValue - This trivial value class is used to represent the result of an
+/// expression that is evaluated. It can be one of three things: either a
+/// simple LLVM SSA value, a pair of SSA values for complex numbers, or the
+/// address of an aggregate value in memory.
+class RValue {
+ llvm::Value *V1, *V2;
+ // TODO: Encode this into the low bit of pointer for more efficient
+ // return-by-value.
+ enum { Scalar, Complex, Aggregate } Flavor;
+
+ bool Volatile:1;
+public:
+
+ bool isScalar() const { return Flavor == Scalar; }
+ bool isComplex() const { return Flavor == Complex; }
+ bool isAggregate() const { return Flavor == Aggregate; }
+
+ bool isVolatileQualified() const { return Volatile; }
+
+ /// getScalar() - Return the Value* of this scalar value.
+ llvm::Value *getScalarVal() const {
+ assert(isScalar() && "Not a scalar!");
+ return V1;
+ }
+
+ /// getComplexVal - Return the real/imag components of this complex value.
+ ///
+ std::pair<llvm::Value *, llvm::Value *> getComplexVal() const {
+ return std::pair<llvm::Value *, llvm::Value *>(V1, V2);
+ }
+
+ /// getAggregateAddr() - Return the Value* of the address of the aggregate.
+ llvm::Value *getAggregateAddr() const {
+ assert(isAggregate() && "Not an aggregate!");
+ return V1;
+ }
+
+ static RValue get(llvm::Value *V) {
+ RValue ER;
+ ER.V1 = V;
+ ER.Flavor = Scalar;
+ ER.Volatile = false;
+ return ER;
+ }
+ static RValue getComplex(llvm::Value *V1, llvm::Value *V2) {
+ RValue ER;
+ ER.V1 = V1;
+ ER.V2 = V2;
+ ER.Flavor = Complex;
+ ER.Volatile = false;
+ return ER;
+ }
+ static RValue getComplex(const std::pair<llvm::Value *, llvm::Value *> &C) {
+ RValue ER;
+ ER.V1 = C.first;
+ ER.V2 = C.second;
+ ER.Flavor = Complex;
+ ER.Volatile = false;
+ return ER;
+ }
+ // FIXME: Aggregate rvalues need to retain information about whether they are
+ // volatile or not. Remove default to find all places that probably get this
+ // wrong.
+ static RValue getAggregate(llvm::Value *V, bool Vol = false) {
+ RValue ER;
+ ER.V1 = V;
+ ER.Flavor = Aggregate;
+ ER.Volatile = Vol;
+ return ER;
+ }
+};
+
+
+/// LValue - This represents an lvalue references. Because C/C++ allow
+/// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a
+/// bitrange.
+class LValue {
+ // FIXME: alignment?
+
+ enum {
+ Simple, // This is a normal l-value, use getAddress().
+ VectorElt, // This is a vector element l-value (V[i]), use getVector*
+ BitField, // This is a bitfield l-value, use getBitfield*.
+ ExtVectorElt, // This is an extended vector subset, use getExtVectorComp
+ PropertyRef, // This is an Objective-C property reference, use
+ // getPropertyRefExpr
+ KVCRef // This is an objective-c 'implicit' property ref,
+ // use getKVCRefExpr
+ } LVType;
+
+ enum ObjCType {
+ None = 0, // object with no gc attribute.
+ Weak, // __weak object expression
+ Strong // __strong object expression
+ };
+
+ llvm::Value *V;
+
+ union {
+ // Index into a vector subscript: V[i]
+ llvm::Value *VectorIdx;
+
+ // ExtVector element subset: V.xyx
+ llvm::Constant *VectorElts;
+
+ // BitField start bit and size
+ struct {
+ unsigned short StartBit;
+ unsigned short Size;
+ bool IsSigned;
+ } BitfieldData;
+
+ // Obj-C property reference expression
+ const ObjCPropertyRefExpr *PropertyRefExpr;
+ // ObjC 'implicit' property reference expression
+ const ObjCKVCRefExpr *KVCRefExpr;
+ };
+
+ bool Volatile:1;
+ // FIXME: set but never used, what effect should it have?
+ bool Restrict:1;
+
+ // objective-c's ivar
+ bool Ivar:1;
+
+ // LValue is non-gc'able for any reason, including being a parameter or local
+ // variable.
+ bool NonGC: 1;
+
+ // Lvalue is a global reference of an objective-c object
+ bool GlobalObjCRef : 1;
+
+ // objective-c's gc attributes
+ unsigned ObjCType : 2;
+
+
+
+private:
+ static void SetQualifiers(unsigned Qualifiers, LValue& R) {
+ R.Volatile = (Qualifiers&QualType::Volatile)!=0;
+ R.Restrict = (Qualifiers&QualType::Restrict)!=0;
+ // FIXME: Convenient place to set objc flags to 0. This should really be
+ // done in a user-defined constructor instead.
+ R.ObjCType = None;
+ R.Ivar = R.NonGC = R.GlobalObjCRef = false;
+ }
+
+public:
+ bool isSimple() const { return LVType == Simple; }
+ bool isVectorElt() const { return LVType == VectorElt; }
+ bool isBitfield() const { return LVType == BitField; }
+ bool isExtVectorElt() const { return LVType == ExtVectorElt; }
+ bool isPropertyRef() const { return LVType == PropertyRef; }
+ bool isKVCRef() const { return LVType == KVCRef; }
+
+ bool isVolatileQualified() const { return Volatile; }
+ bool isRestrictQualified() const { return Restrict; }
+ unsigned getQualifiers() const {
+ return (Volatile ? QualType::Volatile : 0) |
+ (Restrict ? QualType::Restrict : 0);
+ }
+
+ bool isObjCIvar() const { return Ivar; }
+ bool isNonGC () const { return NonGC; }
+ bool isGlobalObjCRef() const { return GlobalObjCRef; }
+ bool isObjCWeak() const { return ObjCType == Weak; }
+ bool isObjCStrong() const { return ObjCType == Strong; }
+
+ static void SetObjCIvar(LValue& R, bool iValue) {
+ R.Ivar = iValue;
+ }
+
+ static void SetGlobalObjCRef(LValue& R, bool iValue) {
+ R.GlobalObjCRef = iValue;
+ }
+
+ static void SetObjCNonGC(LValue& R, bool iValue) {
+ R.NonGC = iValue;
+ }
+ static void SetObjCType(QualType::GCAttrTypes GCAttrs, LValue& R) {
+ if (GCAttrs == QualType::Weak)
+ R.ObjCType = Weak;
+ else if (GCAttrs == QualType::Strong)
+ R.ObjCType = Strong;
+ else
+ R.ObjCType = None;
+ }
+
+ // simple lvalue
+ llvm::Value *getAddress() const { assert(isSimple()); return V; }
+ // vector elt lvalue
+ llvm::Value *getVectorAddr() const { assert(isVectorElt()); return V; }
+ llvm::Value *getVectorIdx() const { assert(isVectorElt()); return VectorIdx; }
+ // extended vector elements.
+ llvm::Value *getExtVectorAddr() const { assert(isExtVectorElt()); return V; }
+ llvm::Constant *getExtVectorElts() const {
+ assert(isExtVectorElt());
+ return VectorElts;
+ }
+ // bitfield lvalue
+ llvm::Value *getBitfieldAddr() const { assert(isBitfield()); return V; }
+ unsigned short getBitfieldStartBit() const {
+ assert(isBitfield());
+ return BitfieldData.StartBit;
+ }
+ unsigned short getBitfieldSize() const {
+ assert(isBitfield());
+ return BitfieldData.Size;
+ }
+ bool isBitfieldSigned() const {
+ assert(isBitfield());
+ return BitfieldData.IsSigned;
+ }
+ // property ref lvalue
+ const ObjCPropertyRefExpr *getPropertyRefExpr() const {
+ assert(isPropertyRef());
+ return PropertyRefExpr;
+ }
+
+ // 'implicit' property ref lvalue
+ const ObjCKVCRefExpr *getKVCRefExpr() const {
+ assert(isKVCRef());
+ return KVCRefExpr;
+ }
+
+ static LValue MakeAddr(llvm::Value *V, unsigned Qualifiers,
+ QualType::GCAttrTypes GCAttrs = QualType::GCNone) {
+ LValue R;
+ R.LVType = Simple;
+ R.V = V;
+ SetQualifiers(Qualifiers,R);
+ SetObjCType(GCAttrs, R);
+ return R;
+ }
+
+ static LValue MakeVectorElt(llvm::Value *Vec, llvm::Value *Idx,
+ unsigned Qualifiers) {
+ LValue R;
+ R.LVType = VectorElt;
+ R.V = Vec;
+ R.VectorIdx = Idx;
+ SetQualifiers(Qualifiers,R);
+ return R;
+ }
+
+ static LValue MakeExtVectorElt(llvm::Value *Vec, llvm::Constant *Elts,
+ unsigned Qualifiers) {
+ LValue R;
+ R.LVType = ExtVectorElt;
+ R.V = Vec;
+ R.VectorElts = Elts;
+ SetQualifiers(Qualifiers,R);
+ return R;
+ }
+
+ static LValue MakeBitfield(llvm::Value *V, unsigned short StartBit,
+ unsigned short Size, bool IsSigned,
+ unsigned Qualifiers) {
+ LValue R;
+ R.LVType = BitField;
+ R.V = V;
+ R.BitfieldData.StartBit = StartBit;
+ R.BitfieldData.Size = Size;
+ R.BitfieldData.IsSigned = IsSigned;
+ SetQualifiers(Qualifiers,R);
+ return R;
+ }
+
+ // FIXME: It is probably bad that we aren't emitting the target when we build
+ // the lvalue. However, this complicates the code a bit, and I haven't figured
+ // out how to make it go wrong yet.
+ static LValue MakePropertyRef(const ObjCPropertyRefExpr *E,
+ unsigned Qualifiers) {
+ LValue R;
+ R.LVType = PropertyRef;
+ R.PropertyRefExpr = E;
+ SetQualifiers(Qualifiers,R);
+ return R;
+ }
+
+ static LValue MakeKVCRef(const ObjCKVCRefExpr *E, unsigned Qualifiers) {
+ LValue R;
+ R.LVType = KVCRef;
+ R.KVCRefExpr = E;
+ SetQualifiers(Qualifiers,R);
+ return R;
+ }
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
new file mode 100644
index 000000000000..d6c46a8adc12
--- /dev/null
+++ b/lib/CodeGen/CMakeLists.txt
@@ -0,0 +1,24 @@
+set(LLVM_NO_RTTI 1)
+
+add_clang_library(clangCodeGen
+ CGBuiltin.cpp
+ CGBlocks.cpp
+ CGCall.cpp
+ CGCXX.cpp
+ CGDebugInfo.cpp
+ CGDecl.cpp
+ CGExprAgg.cpp
+ CGExprComplex.cpp
+ CGExprConstant.cpp
+ CGExpr.cpp
+ CGExprScalar.cpp
+ CGObjC.cpp
+ CGObjCGNU.cpp
+ CGObjCMac.cpp
+ CGStmt.cpp
+ CodeGenFunction.cpp
+ CodeGenModule.cpp
+ CodeGenTypes.cpp
+ Mangle.cpp
+ ModuleBuilder.cpp
+ )
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
new file mode 100644
index 000000000000..672f6da502b1
--- /dev/null
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -0,0 +1,714 @@
+//===--- CodeGenFunction.cpp - Emit LLVM Code from ASTs for a Function ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This coordinates the per-function state used while generating code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "CGDebugInfo.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/AST/APValue.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "llvm/Support/CFG.h"
+#include "llvm/Target/TargetData.h"
+using namespace clang;
+using namespace CodeGen;
+
+CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
+ : BlockFunction(cgm, *this, Builder), CGM(cgm),
+ Target(CGM.getContext().Target),
+ DebugInfo(0), SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0),
+ CXXThisDecl(0) {
+ LLVMIntTy = ConvertType(getContext().IntTy);
+ LLVMPointerWidth = Target.getPointerWidth(0);
+}
+
+ASTContext &CodeGenFunction::getContext() const {
+ return CGM.getContext();
+}
+
+
+llvm::BasicBlock *CodeGenFunction::getBasicBlockForLabel(const LabelStmt *S) {
+ llvm::BasicBlock *&BB = LabelMap[S];
+ if (BB) return BB;
+
+ // Create, but don't insert, the new block.
+ return BB = createBasicBlock(S->getName());
+}
+
+llvm::Value *CodeGenFunction::GetAddrOfLocalVar(const VarDecl *VD) {
+ llvm::Value *Res = LocalDeclMap[VD];
+ assert(Res && "Invalid argument to GetAddrOfLocalVar(), no decl!");
+ return Res;
+}
+
+llvm::Constant *
+CodeGenFunction::GetAddrOfStaticLocalVar(const VarDecl *BVD) {
+ return cast<llvm::Constant>(GetAddrOfLocalVar(BVD));
+}
+
+const llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) {
+ return CGM.getTypes().ConvertTypeForMem(T);
+}
+
+const llvm::Type *CodeGenFunction::ConvertType(QualType T) {
+ return CGM.getTypes().ConvertType(T);
+}
+
+bool CodeGenFunction::hasAggregateLLVMType(QualType T) {
+ // FIXME: Use positive checks instead of negative ones to be more robust in
+ // the face of extension.
+ return !T->hasPointerRepresentation() &&!T->isRealType() &&
+ !T->isVoidType() && !T->isVectorType() && !T->isFunctionType() &&
+ !T->isBlockPointerType();
+}
+
+void CodeGenFunction::EmitReturnBlock() {
+ // For cleanliness, we try to avoid emitting the return block for
+ // simple cases.
+ llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
+
+ if (CurBB) {
+ assert(!CurBB->getTerminator() && "Unexpected terminated block.");
+
+ // We have a valid insert point, reuse it if there are no explicit
+ // jumps to the return block.
+ if (ReturnBlock->use_empty())
+ delete ReturnBlock;
+ else
+ EmitBlock(ReturnBlock);
+ return;
+ }
+
+ // Otherwise, if the return block is the target of a single direct
+ // branch then we can just put the code in that block instead. This
+ // cleans up functions which started with a unified return block.
+ if (ReturnBlock->hasOneUse()) {
+ llvm::BranchInst *BI =
+ dyn_cast<llvm::BranchInst>(*ReturnBlock->use_begin());
+ if (BI && BI->isUnconditional() && BI->getSuccessor(0) == ReturnBlock) {
+ // Reset insertion point and delete the branch.
+ Builder.SetInsertPoint(BI->getParent());
+ BI->eraseFromParent();
+ delete ReturnBlock;
+ return;
+ }
+ }
+
+ // FIXME: We are at an unreachable point, there is no reason to emit the block
+ // unless it has uses. However, we still need a place to put the debug
+ // region.end for now.
+
+ EmitBlock(ReturnBlock);
+}
+
+void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
+ // Finish emission of indirect switches.
+ EmitIndirectSwitches();
+
+ assert(BreakContinueStack.empty() &&
+ "mismatched push/pop in break/continue stack!");
+ assert(BlockScopes.empty() &&
+ "did not remove all blocks from block scope map!");
+ assert(CleanupEntries.empty() &&
+ "mismatched push/pop in cleanup stack!");
+
+ // Emit function epilog (to return).
+ EmitReturnBlock();
+
+ // Emit debug descriptor for function end.
+ if (CGDebugInfo *DI = getDebugInfo()) {
+ DI->setLocation(EndLoc);
+ DI->EmitRegionEnd(CurFn, Builder);
+ }
+
+ EmitFunctionEpilog(*CurFnInfo, ReturnValue);
+
+ // Remove the AllocaInsertPt instruction, which is just a convenience for us.
+ llvm::Instruction *Ptr = AllocaInsertPt;
+ AllocaInsertPt = 0;
+ Ptr->eraseFromParent();
+}
+
+void CodeGenFunction::StartFunction(const Decl *D, QualType RetTy,
+ llvm::Function *Fn,
+ const FunctionArgList &Args,
+ SourceLocation StartLoc) {
+ DidCallStackSave = false;
+ CurCodeDecl = CurFuncDecl = D;
+ FnRetTy = RetTy;
+ CurFn = Fn;
+ assert(CurFn->isDeclaration() && "Function already has body?");
+
+ llvm::BasicBlock *EntryBB = createBasicBlock("entry", CurFn);
+
+ // Create a marker to make it easy to insert allocas into the entryblock
+ // later. Don't create this with the builder, because we don't want it
+ // folded.
+ llvm::Value *Undef = llvm::UndefValue::get(llvm::Type::Int32Ty);
+ AllocaInsertPt = new llvm::BitCastInst(Undef, llvm::Type::Int32Ty, "",
+ EntryBB);
+ if (Builder.isNamePreserving())
+ AllocaInsertPt->setName("allocapt");
+
+ ReturnBlock = createBasicBlock("return");
+ ReturnValue = 0;
+ if (!RetTy->isVoidType())
+ ReturnValue = CreateTempAlloca(ConvertType(RetTy), "retval");
+
+ Builder.SetInsertPoint(EntryBB);
+
+ // Emit subprogram debug descriptor.
+ // FIXME: The cast here is a huge hack.
+ if (CGDebugInfo *DI = getDebugInfo()) {
+ DI->setLocation(StartLoc);
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ DI->EmitFunctionStart(CGM.getMangledName(FD), RetTy, CurFn, Builder);
+ } else {
+ // Just use LLVM function name.
+ DI->EmitFunctionStart(Fn->getName().c_str(),
+ RetTy, CurFn, Builder);
+ }
+ }
+
+ // FIXME: Leaked.
+ CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args);
+ EmitFunctionProlog(*CurFnInfo, CurFn, Args);
+
+ // If any of the arguments have a variably modified type, make sure to
+ // emit the type size.
+ for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
+ i != e; ++i) {
+ QualType Ty = i->second;
+
+ if (Ty->isVariablyModifiedType())
+ EmitVLASize(Ty);
+ }
+}
+
+void CodeGenFunction::GenerateCode(const FunctionDecl *FD,
+ llvm::Function *Fn) {
+ // Check if we should generate debug info for this function.
+ if (CGM.getDebugInfo() && !FD->hasAttr<NodebugAttr>())
+ DebugInfo = CGM.getDebugInfo();
+
+ FunctionArgList Args;
+
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ if (MD->isInstance()) {
+ // Create the implicit 'this' decl.
+ // FIXME: I'm not entirely sure I like using a fake decl just for code
+ // generation. Maybe we can come up with a better way?
+ CXXThisDecl = ImplicitParamDecl::Create(getContext(), 0, SourceLocation(),
+ &getContext().Idents.get("this"),
+ MD->getThisType(getContext()));
+ Args.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType()));
+ }
+ }
+
+ if (FD->getNumParams()) {
+ const FunctionProtoType* FProto = FD->getType()->getAsFunctionProtoType();
+ assert(FProto && "Function def must have prototype!");
+
+ for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i)
+ Args.push_back(std::make_pair(FD->getParamDecl(i),
+ FProto->getArgType(i)));
+ }
+
+ // FIXME: Support CXXTryStmt here, too.
+ if (const CompoundStmt *S = FD->getCompoundBody(getContext())) {
+ StartFunction(FD, FD->getResultType(), Fn, Args, S->getLBracLoc());
+ EmitStmt(S);
+ FinishFunction(S->getRBracLoc());
+ }
+
+ // Destroy the 'this' declaration.
+ if (CXXThisDecl)
+ CXXThisDecl->Destroy(getContext());
+}
+
+/// ContainsLabel - Return true if the statement contains a label in it. If
+/// this statement is not executed normally, it not containing a label means
+/// that we can just remove the code.
+bool CodeGenFunction::ContainsLabel(const Stmt *S, bool IgnoreCaseStmts) {
+ // Null statement, not a label!
+ if (S == 0) return false;
+
+ // If this is a label, we have to emit the code, consider something like:
+ // if (0) { ... foo: bar(); } goto foo;
+ if (isa<LabelStmt>(S))
+ return true;
+
+ // If this is a case/default statement, and we haven't seen a switch, we have
+ // to emit the code.
+ if (isa<SwitchCase>(S) && !IgnoreCaseStmts)
+ return true;
+
+ // If this is a switch statement, we want to ignore cases below it.
+ if (isa<SwitchStmt>(S))
+ IgnoreCaseStmts = true;
+
+ // Scan subexpressions for verboten labels.
+ for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
+ I != E; ++I)
+ if (ContainsLabel(*I, IgnoreCaseStmts))
+ return true;
+
+ return false;
+}
+
+
+/// ConstantFoldsToSimpleInteger - If the sepcified expression does not fold to
+/// a constant, or if it does but contains a label, return 0. If it constant
+/// folds to 'true' and does not contain a label, return 1, if it constant folds
+/// to 'false' and does not contain a label, return -1.
+int CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond) {
+ // FIXME: Rename and handle conversion of other evaluatable things
+ // to bool.
+ Expr::EvalResult Result;
+ if (!Cond->Evaluate(Result, getContext()) || !Result.Val.isInt() ||
+ Result.HasSideEffects)
+ return 0; // Not foldable, not integer or not fully evaluatable.
+
+ if (CodeGenFunction::ContainsLabel(Cond))
+ return 0; // Contains a label.
+
+ return Result.Val.getInt().getBoolValue() ? 1 : -1;
+}
+
+
+/// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g. for an if
+/// statement) to the specified blocks. Based on the condition, this might try
+/// to simplify the codegen of the conditional based on the branch.
+///
+void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
+ llvm::BasicBlock *TrueBlock,
+ llvm::BasicBlock *FalseBlock) {
+ if (const ParenExpr *PE = dyn_cast<ParenExpr>(Cond))
+ return EmitBranchOnBoolExpr(PE->getSubExpr(), TrueBlock, FalseBlock);
+
+ if (const BinaryOperator *CondBOp = dyn_cast<BinaryOperator>(Cond)) {
+ // Handle X && Y in a condition.
+ if (CondBOp->getOpcode() == BinaryOperator::LAnd) {
+ // If we have "1 && X", simplify the code. "0 && X" would have constant
+ // folded if the case was simple enough.
+ if (ConstantFoldsToSimpleInteger(CondBOp->getLHS()) == 1) {
+ // br(1 && X) -> br(X).
+ return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
+ }
+
+ // If we have "X && 1", simplify the code to use an uncond branch.
+ // "X && 0" would have been constant folded to 0.
+ if (ConstantFoldsToSimpleInteger(CondBOp->getRHS()) == 1) {
+ // br(X && 1) -> br(X).
+ return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock);
+ }
+
+ // Emit the LHS as a conditional. If the LHS conditional is false, we
+ // want to jump to the FalseBlock.
+ llvm::BasicBlock *LHSTrue = createBasicBlock("land.lhs.true");
+ EmitBranchOnBoolExpr(CondBOp->getLHS(), LHSTrue, FalseBlock);
+ EmitBlock(LHSTrue);
+
+ EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
+ return;
+ } else if (CondBOp->getOpcode() == BinaryOperator::LOr) {
+ // If we have "0 || X", simplify the code. "1 || X" would have constant
+ // folded if the case was simple enough.
+ if (ConstantFoldsToSimpleInteger(CondBOp->getLHS()) == -1) {
+ // br(0 || X) -> br(X).
+ return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
+ }
+
+ // If we have "X || 0", simplify the code to use an uncond branch.
+ // "X || 1" would have been constant folded to 1.
+ if (ConstantFoldsToSimpleInteger(CondBOp->getRHS()) == -1) {
+ // br(X || 0) -> br(X).
+ return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock);
+ }
+
+ // Emit the LHS as a conditional. If the LHS conditional is true, we
+ // want to jump to the TrueBlock.
+ llvm::BasicBlock *LHSFalse = createBasicBlock("lor.lhs.false");
+ EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, LHSFalse);
+ EmitBlock(LHSFalse);
+
+ EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
+ return;
+ }
+ }
+
+ if (const UnaryOperator *CondUOp = dyn_cast<UnaryOperator>(Cond)) {
+ // br(!x, t, f) -> br(x, f, t)
+ if (CondUOp->getOpcode() == UnaryOperator::LNot)
+ return EmitBranchOnBoolExpr(CondUOp->getSubExpr(), FalseBlock, TrueBlock);
+ }
+
+ if (const ConditionalOperator *CondOp = dyn_cast<ConditionalOperator>(Cond)) {
+ // Handle ?: operator.
+
+ // Just ignore GNU ?: extension.
+ if (CondOp->getLHS()) {
+ // br(c ? x : y, t, f) -> br(c, br(x, t, f), br(y, t, f))
+ llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true");
+ llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false");
+ EmitBranchOnBoolExpr(CondOp->getCond(), LHSBlock, RHSBlock);
+ EmitBlock(LHSBlock);
+ EmitBranchOnBoolExpr(CondOp->getLHS(), TrueBlock, FalseBlock);
+ EmitBlock(RHSBlock);
+ EmitBranchOnBoolExpr(CondOp->getRHS(), TrueBlock, FalseBlock);
+ return;
+ }
+ }
+
+ // Emit the code with the fully general case.
+ llvm::Value *CondV = EvaluateExprAsBool(Cond);
+ Builder.CreateCondBr(CondV, TrueBlock, FalseBlock);
+}
+
+/// getCGRecordLayout - Return record layout info.
+const CGRecordLayout *CodeGenFunction::getCGRecordLayout(CodeGenTypes &CGT,
+ QualType Ty) {
+ const RecordType *RTy = Ty->getAsRecordType();
+ assert (RTy && "Unexpected type. RecordType expected here.");
+
+ return CGT.getCGRecordLayout(RTy->getDecl());
+}
+
+/// ErrorUnsupported - Print out an error that codegen doesn't support the
+/// specified stmt yet.
+void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type,
+ bool OmitOnError) {
+ CGM.ErrorUnsupported(S, Type, OmitOnError);
+}
+
+unsigned CodeGenFunction::GetIDForAddrOfLabel(const LabelStmt *L) {
+ // Use LabelIDs.size() as the new ID if one hasn't been assigned.
+ return LabelIDs.insert(std::make_pair(L, LabelIDs.size())).first->second;
+}
+
+void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) {
+ const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ if (DestPtr->getType() != BP)
+ DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp");
+
+ // Get size and alignment info for this aggregate.
+ std::pair<uint64_t, unsigned> TypeInfo = getContext().getTypeInfo(Ty);
+
+ // Don't bother emitting a zero-byte memset.
+ if (TypeInfo.first == 0)
+ return;
+
+ // FIXME: Handle variable sized types.
+ const llvm::Type *IntPtr = llvm::IntegerType::get(LLVMPointerWidth);
+
+ Builder.CreateCall4(CGM.getMemSetFn(), DestPtr,
+ llvm::ConstantInt::getNullValue(llvm::Type::Int8Ty),
+ // TypeInfo.first describes size in bits.
+ llvm::ConstantInt::get(IntPtr, TypeInfo.first/8),
+ llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ TypeInfo.second/8));
+}
+
+void CodeGenFunction::EmitIndirectSwitches() {
+ llvm::BasicBlock *Default;
+
+ if (IndirectSwitches.empty())
+ return;
+
+ if (!LabelIDs.empty()) {
+ Default = getBasicBlockForLabel(LabelIDs.begin()->first);
+ } else {
+ // No possible targets for indirect goto, just emit an infinite
+ // loop.
+ Default = createBasicBlock("indirectgoto.loop", CurFn);
+ llvm::BranchInst::Create(Default, Default);
+ }
+
+ for (std::vector<llvm::SwitchInst*>::iterator i = IndirectSwitches.begin(),
+ e = IndirectSwitches.end(); i != e; ++i) {
+ llvm::SwitchInst *I = *i;
+
+ I->setSuccessor(0, Default);
+ for (std::map<const LabelStmt*,unsigned>::iterator LI = LabelIDs.begin(),
+ LE = LabelIDs.end(); LI != LE; ++LI) {
+ I->addCase(llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ LI->second),
+ getBasicBlockForLabel(LI->first));
+ }
+ }
+}
+
+llvm::Value *CodeGenFunction::GetVLASize(const VariableArrayType *VAT)
+{
+ llvm::Value *&SizeEntry = VLASizeMap[VAT];
+
+ assert(SizeEntry && "Did not emit size for type");
+ return SizeEntry;
+}
+
+llvm::Value *CodeGenFunction::EmitVLASize(QualType Ty)
+{
+ assert(Ty->isVariablyModifiedType() &&
+ "Must pass variably modified type to EmitVLASizes!");
+
+ if (const VariableArrayType *VAT = getContext().getAsVariableArrayType(Ty)) {
+ llvm::Value *&SizeEntry = VLASizeMap[VAT];
+
+ if (!SizeEntry) {
+ // Get the element size;
+ llvm::Value *ElemSize;
+
+ QualType ElemTy = VAT->getElementType();
+
+ const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
+
+ if (ElemTy->isVariableArrayType())
+ ElemSize = EmitVLASize(ElemTy);
+ else {
+ ElemSize = llvm::ConstantInt::get(SizeTy,
+ getContext().getTypeSize(ElemTy) / 8);
+ }
+
+ llvm::Value *NumElements = EmitScalarExpr(VAT->getSizeExpr());
+ NumElements = Builder.CreateIntCast(NumElements, SizeTy, false, "tmp");
+
+ SizeEntry = Builder.CreateMul(ElemSize, NumElements);
+ }
+
+ return SizeEntry;
+ } else if (const ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
+ EmitVLASize(AT->getElementType());
+ } else if (const PointerType *PT = Ty->getAsPointerType())
+ EmitVLASize(PT->getPointeeType());
+ else {
+ assert(0 && "unknown VM type!");
+ }
+
+ return 0;
+}
+
+llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) {
+ if (CGM.getContext().getBuiltinVaListType()->isArrayType()) {
+ return EmitScalarExpr(E);
+ }
+ return EmitLValue(E).getAddress();
+}
+
+void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupBlock)
+{
+ CleanupEntries.push_back(CleanupEntry(CleanupBlock));
+}
+
+void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize)
+{
+ assert(CleanupEntries.size() >= OldCleanupStackSize &&
+ "Cleanup stack mismatch!");
+
+ while (CleanupEntries.size() > OldCleanupStackSize)
+ EmitCleanupBlock();
+}
+
+CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock()
+{
+ CleanupEntry &CE = CleanupEntries.back();
+
+ llvm::BasicBlock *CleanupBlock = CE.CleanupBlock;
+
+ std::vector<llvm::BasicBlock *> Blocks;
+ std::swap(Blocks, CE.Blocks);
+
+ std::vector<llvm::BranchInst *> BranchFixups;
+ std::swap(BranchFixups, CE.BranchFixups);
+
+ CleanupEntries.pop_back();
+
+ // Check if any branch fixups pointed to the scope we just popped. If so,
+ // we can remove them.
+ for (size_t i = 0, e = BranchFixups.size(); i != e; ++i) {
+ llvm::BasicBlock *Dest = BranchFixups[i]->getSuccessor(0);
+ BlockScopeMap::iterator I = BlockScopes.find(Dest);
+
+ if (I == BlockScopes.end())
+ continue;
+
+ assert(I->second <= CleanupEntries.size() && "Invalid branch fixup!");
+
+ if (I->second == CleanupEntries.size()) {
+ // We don't need to do this branch fixup.
+ BranchFixups[i] = BranchFixups.back();
+ BranchFixups.pop_back();
+ i--;
+ e--;
+ continue;
+ }
+ }
+
+ llvm::BasicBlock *SwitchBlock = 0;
+ llvm::BasicBlock *EndBlock = 0;
+ if (!BranchFixups.empty()) {
+ SwitchBlock = createBasicBlock("cleanup.switch");
+ EndBlock = createBasicBlock("cleanup.end");
+
+ llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
+
+ Builder.SetInsertPoint(SwitchBlock);
+
+ llvm::Value *DestCodePtr = CreateTempAlloca(llvm::Type::Int32Ty,
+ "cleanup.dst");
+ llvm::Value *DestCode = Builder.CreateLoad(DestCodePtr, "tmp");
+
+ // Create a switch instruction to determine where to jump next.
+ llvm::SwitchInst *SI = Builder.CreateSwitch(DestCode, EndBlock,
+ BranchFixups.size());
+
+ // Restore the current basic block (if any)
+ if (CurBB) {
+ Builder.SetInsertPoint(CurBB);
+
+ // If we had a current basic block, we also need to emit an instruction
+ // to initialize the cleanup destination.
+ Builder.CreateStore(llvm::Constant::getNullValue(llvm::Type::Int32Ty),
+ DestCodePtr);
+ } else
+ Builder.ClearInsertionPoint();
+
+ for (size_t i = 0, e = BranchFixups.size(); i != e; ++i) {
+ llvm::BranchInst *BI = BranchFixups[i];
+ llvm::BasicBlock *Dest = BI->getSuccessor(0);
+
+ // Fixup the branch instruction to point to the cleanup block.
+ BI->setSuccessor(0, CleanupBlock);
+
+ if (CleanupEntries.empty()) {
+ llvm::ConstantInt *ID;
+
+ // Check if we already have a destination for this block.
+ if (Dest == SI->getDefaultDest())
+ ID = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
+ else {
+ ID = SI->findCaseDest(Dest);
+ if (!ID) {
+ // No code found, get a new unique one by using the number of
+ // switch successors.
+ ID = llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ SI->getNumSuccessors());
+ SI->addCase(ID, Dest);
+ }
+ }
+
+ // Store the jump destination before the branch instruction.
+ new llvm::StoreInst(ID, DestCodePtr, BI);
+ } else {
+ // We need to jump through another cleanup block. Create a pad block
+ // with a branch instruction that jumps to the final destination and
+ // add it as a branch fixup to the current cleanup scope.
+
+ // Create the pad block.
+ llvm::BasicBlock *CleanupPad = createBasicBlock("cleanup.pad", CurFn);
+
+ // Create a unique case ID.
+ llvm::ConstantInt *ID = llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ SI->getNumSuccessors());
+
+ // Store the jump destination before the branch instruction.
+ new llvm::StoreInst(ID, DestCodePtr, BI);
+
+ // Add it as the destination.
+ SI->addCase(ID, CleanupPad);
+
+ // Create the branch to the final destination.
+ llvm::BranchInst *BI = llvm::BranchInst::Create(Dest);
+ CleanupPad->getInstList().push_back(BI);
+
+ // And add it as a branch fixup.
+ CleanupEntries.back().BranchFixups.push_back(BI);
+ }
+ }
+ }
+
+ // Remove all blocks from the block scope map.
+ for (size_t i = 0, e = Blocks.size(); i != e; ++i) {
+ assert(BlockScopes.count(Blocks[i]) &&
+ "Did not find block in scope map!");
+
+ BlockScopes.erase(Blocks[i]);
+ }
+
+ return CleanupBlockInfo(CleanupBlock, SwitchBlock, EndBlock);
+}
+
+void CodeGenFunction::EmitCleanupBlock()
+{
+ CleanupBlockInfo Info = PopCleanupBlock();
+
+ llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
+ if (CurBB && !CurBB->getTerminator() &&
+ Info.CleanupBlock->getNumUses() == 0) {
+ CurBB->getInstList().splice(CurBB->end(), Info.CleanupBlock->getInstList());
+ delete Info.CleanupBlock;
+ } else
+ EmitBlock(Info.CleanupBlock);
+
+ if (Info.SwitchBlock)
+ EmitBlock(Info.SwitchBlock);
+ if (Info.EndBlock)
+ EmitBlock(Info.EndBlock);
+}
+
+void CodeGenFunction::AddBranchFixup(llvm::BranchInst *BI)
+{
+ assert(!CleanupEntries.empty() &&
+ "Trying to add branch fixup without cleanup block!");
+
+ // FIXME: We could be more clever here and check if there's already a branch
+ // fixup for this destination and recycle it.
+ CleanupEntries.back().BranchFixups.push_back(BI);
+}
+
+void CodeGenFunction::EmitBranchThroughCleanup(llvm::BasicBlock *Dest)
+{
+ if (!HaveInsertPoint())
+ return;
+
+ llvm::BranchInst* BI = Builder.CreateBr(Dest);
+
+ Builder.ClearInsertionPoint();
+
+ // The stack is empty, no need to do any cleanup.
+ if (CleanupEntries.empty())
+ return;
+
+ if (!Dest->getParent()) {
+ // We are trying to branch to a block that hasn't been inserted yet.
+ AddBranchFixup(BI);
+ return;
+ }
+
+ BlockScopeMap::iterator I = BlockScopes.find(Dest);
+ if (I == BlockScopes.end()) {
+ // We are trying to jump to a block that is outside of any cleanup scope.
+ AddBranchFixup(BI);
+ return;
+ }
+
+ assert(I->second < CleanupEntries.size() &&
+ "Trying to branch into cleanup region");
+
+ if (I->second == CleanupEntries.size() - 1) {
+ // We have a branch to a block in the same scope.
+ return;
+ }
+
+ AddBranchFixup(BI);
+}
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
new file mode 100644
index 000000000000..b7894a4068aa
--- /dev/null
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -0,0 +1,900 @@
+//===-- CodeGenFunction.h - Per-Function state for LLVM CodeGen -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the internal per-function state used for llvm translation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CODEGENFUNCTION_H
+#define CLANG_CODEGEN_CODEGENFUNCTION_H
+
+#include "clang/AST/Type.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/ValueHandle.h"
+#include <map>
+#include "CGBlocks.h"
+#include "CGBuilder.h"
+#include "CGCall.h"
+#include "CGCXX.h"
+#include "CGValue.h"
+
+namespace llvm {
+ class BasicBlock;
+ class Module;
+ class SwitchInst;
+ class Value;
+}
+
+namespace clang {
+ class ASTContext;
+ class CXXDestructorDecl;
+ class Decl;
+ class EnumConstantDecl;
+ class FunctionDecl;
+ class FunctionProtoType;
+ class LabelStmt;
+ class ObjCContainerDecl;
+ class ObjCInterfaceDecl;
+ class ObjCIvarDecl;
+ class ObjCMethodDecl;
+ class ObjCImplementationDecl;
+ class ObjCPropertyImplDecl;
+ class TargetInfo;
+ class VarDecl;
+ class ObjCForCollectionStmt;
+ class ObjCAtTryStmt;
+ class ObjCAtThrowStmt;
+ class ObjCAtSynchronizedStmt;
+
+namespace CodeGen {
+ class CodeGenModule;
+ class CodeGenTypes;
+ class CGDebugInfo;
+ class CGFunctionInfo;
+ class CGRecordLayout;
+
+/// CodeGenFunction - This class organizes the per-function state that is used
+/// while generating LLVM code.
+class CodeGenFunction : public BlockFunction {
+ CodeGenFunction(const CodeGenFunction&); // DO NOT IMPLEMENT
+ void operator=(const CodeGenFunction&); // DO NOT IMPLEMENT
+public:
+ CodeGenModule &CGM; // Per-module state.
+ TargetInfo &Target;
+
+ typedef std::pair<llvm::Value *, llvm::Value *> ComplexPairTy;
+ CGBuilderTy Builder;
+
+ /// CurFuncDecl - Holds the Decl for the current function or ObjC method.
+ /// This excludes BlockDecls.
+ const Decl *CurFuncDecl;
+ /// CurCodeDecl - This is the inner-most code context, which includes blocks.
+ const Decl *CurCodeDecl;
+ const CGFunctionInfo *CurFnInfo;
+ QualType FnRetTy;
+ llvm::Function *CurFn;
+
+ /// ReturnBlock - Unified return block.
+ llvm::BasicBlock *ReturnBlock;
+ /// ReturnValue - The temporary alloca to hold the return value. This is null
+ /// iff the function has no return value.
+ llvm::Instruction *ReturnValue;
+
+ /// AllocaInsertPoint - This is an instruction in the entry block before which
+ /// we prefer to insert allocas.
+ llvm::AssertingVH<llvm::Instruction> AllocaInsertPt;
+
+ const llvm::Type *LLVMIntTy;
+ uint32_t LLVMPointerWidth;
+
+public:
+ /// ObjCEHValueStack - Stack of Objective-C exception values, used for
+ /// rethrows.
+ llvm::SmallVector<llvm::Value*, 8> ObjCEHValueStack;
+
+ /// PushCleanupBlock - Push a new cleanup entry on the stack and set the
+ /// passed in block as the cleanup block.
+ void PushCleanupBlock(llvm::BasicBlock *CleanupBlock);
+
+ /// CleanupBlockInfo - A struct representing a popped cleanup block.
+ struct CleanupBlockInfo {
+ /// CleanupBlock - the cleanup block
+ llvm::BasicBlock *CleanupBlock;
+
+ /// SwitchBlock - the block (if any) containing the switch instruction used
+ /// for jumping to the final destination.
+ llvm::BasicBlock *SwitchBlock;
+
+ /// EndBlock - the default destination for the switch instruction.
+ llvm::BasicBlock *EndBlock;
+
+ CleanupBlockInfo(llvm::BasicBlock *cb, llvm::BasicBlock *sb,
+ llvm::BasicBlock *eb)
+ : CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb) {}
+ };
+
+ /// PopCleanupBlock - Will pop the cleanup entry on the stack, process all
+ /// branch fixups and return a block info struct with the switch block and end
+ /// block.
+ CleanupBlockInfo PopCleanupBlock();
+
+ /// CleanupScope - RAII object that will create a cleanup block and set the
+ /// insert point to that block. When destructed, it sets the insert point to
+ /// the previous block and pushes a new cleanup entry on the stack.
+ class CleanupScope {
+ CodeGenFunction& CGF;
+ llvm::BasicBlock *CurBB;
+ llvm::BasicBlock *CleanupBB;
+
+ public:
+ CleanupScope(CodeGenFunction &cgf)
+ : CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()) {
+ CleanupBB = CGF.createBasicBlock("cleanup");
+ CGF.Builder.SetInsertPoint(CleanupBB);
+ }
+
+ ~CleanupScope() {
+ CGF.PushCleanupBlock(CleanupBB);
+ CGF.Builder.SetInsertPoint(CurBB);
+ }
+ };
+
+ /// EmitCleanupBlocks - Takes the old cleanup stack size and emits the cleanup
+ /// blocks that have been added.
+ void EmitCleanupBlocks(size_t OldCleanupStackSize);
+
+ /// EmitBranchThroughCleanup - Emit a branch from the current insert block
+ /// through the cleanup handling code (if any) and then on to \arg Dest.
+ ///
+ /// FIXME: Maybe this should really be in EmitBranch? Don't we always want
+ /// this behavior for branches?
+ void EmitBranchThroughCleanup(llvm::BasicBlock *Dest);
+
+private:
+ CGDebugInfo* DebugInfo;
+
+ /// LabelIDs - Track arbitrary ids assigned to labels for use in implementing
+ /// the GCC address-of-label extension and indirect goto. IDs are assigned to
+ /// labels inside getIDForAddrOfLabel().
+ std::map<const LabelStmt*, unsigned> LabelIDs;
+
+ /// IndirectSwitches - Record the list of switches for indirect
+ /// gotos. Emission of the actual switching code needs to be delayed until all
+ /// AddrLabelExprs have been seen.
+ std::vector<llvm::SwitchInst*> IndirectSwitches;
+
+ /// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C
+ /// decls.
+ llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
+
+ /// LabelMap - This keeps track of the LLVM basic block for each C label.
+ llvm::DenseMap<const LabelStmt*, llvm::BasicBlock*> LabelMap;
+
+ // BreakContinueStack - This keeps track of where break and continue
+ // statements should jump to.
+ struct BreakContinue {
+ BreakContinue(llvm::BasicBlock *bb, llvm::BasicBlock *cb)
+ : BreakBlock(bb), ContinueBlock(cb) {}
+
+ llvm::BasicBlock *BreakBlock;
+ llvm::BasicBlock *ContinueBlock;
+ };
+ llvm::SmallVector<BreakContinue, 8> BreakContinueStack;
+
+ /// SwitchInsn - This is nearest current switch instruction. It is null if if
+ /// current context is not in a switch.
+ llvm::SwitchInst *SwitchInsn;
+
+ /// CaseRangeBlock - This block holds if condition check for last case
+ /// statement range in current switch instruction.
+ llvm::BasicBlock *CaseRangeBlock;
+
+ /// InvokeDest - This is the nearest exception target for calls
+ /// which can unwind, when exceptions are being used.
+ llvm::BasicBlock *InvokeDest;
+
+ // VLASizeMap - This keeps track of the associated size for each VLA type.
+ // FIXME: Maybe this could be a stack of maps that is pushed/popped as we
+ // enter/leave scopes.
+ llvm::DenseMap<const VariableArrayType*, llvm::Value*> VLASizeMap;
+
+ /// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
+ /// calling llvm.stacksave for multiple VLAs in the same scope.
+ bool DidCallStackSave;
+
+ struct CleanupEntry {
+ /// CleanupBlock - The block of code that does the actual cleanup.
+ llvm::BasicBlock *CleanupBlock;
+
+ /// Blocks - Basic blocks that were emitted in the current cleanup scope.
+ std::vector<llvm::BasicBlock *> Blocks;
+
+ /// BranchFixups - Branch instructions to basic blocks that haven't been
+ /// inserted into the current function yet.
+ std::vector<llvm::BranchInst *> BranchFixups;
+
+ explicit CleanupEntry(llvm::BasicBlock *cb)
+ : CleanupBlock(cb) {}
+ };
+
+ /// CleanupEntries - Stack of cleanup entries.
+ llvm::SmallVector<CleanupEntry, 8> CleanupEntries;
+
+ typedef llvm::DenseMap<llvm::BasicBlock*, size_t> BlockScopeMap;
+
+ /// BlockScopes - Map of which "cleanup scope" scope basic blocks have.
+ BlockScopeMap BlockScopes;
+
+ /// CXXThisDecl - When parsing an C++ function, this will hold the implicit
+ /// 'this' declaration.
+ ImplicitParamDecl *CXXThisDecl;
+
+ llvm::SmallVector<const CXXTemporary*, 4> LiveTemporaries;
+
+public:
+ CodeGenFunction(CodeGenModule &cgm);
+
+ ASTContext &getContext() const;
+ CGDebugInfo *getDebugInfo() { return DebugInfo; }
+
+ llvm::BasicBlock *getInvokeDest() { return InvokeDest; }
+ void setInvokeDest(llvm::BasicBlock *B) { InvokeDest = B; }
+
+ //===--------------------------------------------------------------------===//
+ // Objective-C
+ //===--------------------------------------------------------------------===//
+
+ void GenerateObjCMethod(const ObjCMethodDecl *OMD);
+
+ void StartObjCMethod(const ObjCMethodDecl *MD,
+ const ObjCContainerDecl *CD);
+
+ /// GenerateObjCGetter - Synthesize an Objective-C property getter function.
+ void GenerateObjCGetter(ObjCImplementationDecl *IMP,
+ const ObjCPropertyImplDecl *PID);
+
+ /// GenerateObjCSetter - Synthesize an Objective-C property setter function
+ /// for the given property.
+ void GenerateObjCSetter(ObjCImplementationDecl *IMP,
+ const ObjCPropertyImplDecl *PID);
+
+ //===--------------------------------------------------------------------===//
+ // Block Bits
+ //===--------------------------------------------------------------------===//
+
+ llvm::Value *BuildBlockLiteralTmp(const BlockExpr *);
+ llvm::Constant *BuildDescriptorBlockDecl(bool BlockHasCopyDispose,
+ uint64_t Size,
+ const llvm::StructType *,
+ std::vector<HelperInfo> *);
+
+ llvm::Function *GenerateBlockFunction(const BlockExpr *BExpr,
+ const BlockInfo& Info,
+ const Decl *OuterFuncDecl,
+ llvm::DenseMap<const Decl*, llvm::Value*> ldm,
+ uint64_t &Size, uint64_t &Align,
+ llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls,
+ bool &subBlockHasCopyDispose);
+
+ void BlockForwardSelf();
+ llvm::Value *LoadBlockStruct();
+
+ llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E);
+
+ const llvm::Type *BuildByRefType(QualType Ty, uint64_t Align);
+
+ void GenerateCode(const FunctionDecl *FD,
+ llvm::Function *Fn);
+ void StartFunction(const Decl *D, QualType RetTy,
+ llvm::Function *Fn,
+ const FunctionArgList &Args,
+ SourceLocation StartLoc);
+
+ /// EmitReturnBlock - Emit the unified return block, trying to avoid its
+ /// emission when possible.
+ void EmitReturnBlock();
+
+ /// FinishFunction - Complete IR generation of the current function. It is
+ /// legal to call this function even if there is no current insertion point.
+ void FinishFunction(SourceLocation EndLoc=SourceLocation());
+
+ /// EmitFunctionProlog - Emit the target specific LLVM code to load the
+ /// arguments for the given function. This is also responsible for naming the
+ /// LLVM function arguments.
+ void EmitFunctionProlog(const CGFunctionInfo &FI,
+ llvm::Function *Fn,
+ const FunctionArgList &Args);
+
+ /// EmitFunctionEpilog - Emit the target specific LLVM code to return the
+ /// given temporary.
+ void EmitFunctionEpilog(const CGFunctionInfo &FI, llvm::Value *ReturnValue);
+
+ const llvm::Type *ConvertTypeForMem(QualType T);
+ const llvm::Type *ConvertType(QualType T);
+
+ /// LoadObjCSelf - Load the value of self. This function is only valid while
+ /// generating code for an Objective-C method.
+ llvm::Value *LoadObjCSelf();
+
+ /// TypeOfSelfObject - Return type of object that this self represents.
+ QualType TypeOfSelfObject();
+
+ /// hasAggregateLLVMType - Return true if the specified AST type will map into
+ /// an aggregate LLVM type or is void.
+ static bool hasAggregateLLVMType(QualType T);
+
+ /// createBasicBlock - Create an LLVM basic block.
+ llvm::BasicBlock *createBasicBlock(const char *Name="",
+ llvm::Function *Parent=0,
+ llvm::BasicBlock *InsertBefore=0) {
+#ifdef NDEBUG
+ return llvm::BasicBlock::Create("", Parent, InsertBefore);
+#else
+ return llvm::BasicBlock::Create(Name, Parent, InsertBefore);
+#endif
+ }
+
+ /// getBasicBlockForLabel - Return the LLVM basicblock that the specified
+ /// label maps to.
+ llvm::BasicBlock *getBasicBlockForLabel(const LabelStmt *S);
+
+ /// SimplifyForwardingBlocks - If the given basic block is only a
+ /// branch to another basic block, simplify it. This assumes that no
+ /// other code could potentially reference the basic block.
+ void SimplifyForwardingBlocks(llvm::BasicBlock *BB);
+
+ /// EmitBlock - Emit the given block \arg BB and set it as the insert point,
+ /// adding a fall-through branch from the current insert block if
+ /// necessary. It is legal to call this function even if there is no current
+ /// insertion point.
+ ///
+ /// IsFinished - If true, indicates that the caller has finished emitting
+ /// branches to the given block and does not expect to emit code into it. This
+ /// means the block can be ignored if it is unreachable.
+ void EmitBlock(llvm::BasicBlock *BB, bool IsFinished=false);
+
+ /// 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
+ /// insertion point.
+ ///
+ /// This function clears the current insertion point. The caller should follow
+ /// calls to this function with calls to Emit*Block prior to generation new
+ /// code.
+ void EmitBranch(llvm::BasicBlock *Block);
+
+ /// HaveInsertPoint - True if an insertion point is defined. If not, this
+ /// indicates that the current code being emitted is unreachable.
+ bool HaveInsertPoint() const {
+ return Builder.GetInsertBlock() != 0;
+ }
+
+ /// EnsureInsertPoint - Ensure that an insertion point is defined so that
+ /// emitted IR has a place to go. Note that by definition, if this function
+ /// creates a block then that block is unreachable; callers may do better to
+ /// detect when no insertion point is defined and simply skip IR generation.
+ void EnsureInsertPoint() {
+ if (!HaveInsertPoint())
+ EmitBlock(createBasicBlock());
+ }
+
+ /// ErrorUnsupported - Print out an error that codegen doesn't support the
+ /// specified stmt yet.
+ void ErrorUnsupported(const Stmt *S, const char *Type,
+ bool OmitOnError=false);
+
+ //===--------------------------------------------------------------------===//
+ // Helpers
+ //===--------------------------------------------------------------------===//
+
+ /// CreateTempAlloca - This creates a alloca and inserts it into the entry
+ /// block.
+ llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty,
+ const char *Name = "tmp");
+
+ /// EvaluateExprAsBool - Perform the usual unary conversions on the specified
+ /// expression and compare the result against zero, returning an Int1Ty value.
+ llvm::Value *EvaluateExprAsBool(const Expr *E);
+
+ /// EmitAnyExpr - Emit code to compute the specified expression which can have
+ /// any type. The result is returned as an RValue struct. If this is an
+ /// aggregate expression, the aggloc/agglocvolatile arguments indicate where
+ /// the result should be returned.
+ ///
+ /// \param IgnoreResult - True if the resulting value isn't used.
+ RValue EmitAnyExpr(const Expr *E, llvm::Value *AggLoc = 0,
+ bool isAggLocVolatile = false, bool IgnoreResult = false);
+
+ // EmitVAListRef - Emit a "reference" to a va_list; this is either the address
+ // or the value of the expression, depending on how va_list is defined.
+ llvm::Value *EmitVAListRef(const Expr *E);
+
+ /// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result will
+ /// always be accessible even if no aggregate location is provided.
+ RValue EmitAnyExprToTemp(const Expr *E, llvm::Value *AggLoc = 0,
+ bool isAggLocVolatile = false);
+
+ /// EmitAggregateCopy - Emit an aggrate copy.
+ ///
+ /// \param isVolatile - True iff either the source or the destination is
+ /// volatile.
+ void EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr,
+ QualType EltTy, bool isVolatile=false);
+
+ void EmitAggregateClear(llvm::Value *DestPtr, QualType Ty);
+
+ /// StartBlock - Start new block named N. If insert block is a dummy block
+ /// then reuse it.
+ void StartBlock(const char *N);
+
+ /// getCGRecordLayout - Return record layout info.
+ const CGRecordLayout *getCGRecordLayout(CodeGenTypes &CGT, QualType RTy);
+
+ /// GetAddrOfStaticLocalVar - Return the address of a static local variable.
+ llvm::Constant *GetAddrOfStaticLocalVar(const VarDecl *BVD);
+
+ /// GetAddrOfLocalVar - Return the address of a local variable.
+ llvm::Value *GetAddrOfLocalVar(const VarDecl *VD);
+
+ /// getAccessedFieldNo - Given an encoded value and a result number, return
+ /// the input field number being accessed.
+ static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts);
+
+ unsigned GetIDForAddrOfLabel(const LabelStmt *L);
+
+ /// EmitMemSetToZero - Generate code to memset a value of the given type to 0.
+ void EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty);
+
+ // EmitVAArg - Generate code to get an argument from the passed in pointer
+ // and update it accordingly. The return value is a pointer to the argument.
+ // FIXME: We should be able to get rid of this method and use the va_arg
+ // instruction in LLVM instead once it works well enough.
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty);
+
+ // EmitVLASize - Generate code for any VLA size expressions that might occur
+ // in a variably modified type. If Ty is a VLA, will return the value that
+ // corresponds to the size in bytes of the VLA type. Will return 0 otherwise.
+ llvm::Value *EmitVLASize(QualType Ty);
+
+ // GetVLASize - Returns an LLVM value that corresponds to the size in bytes
+ // of a variable length array type.
+ llvm::Value *GetVLASize(const VariableArrayType *);
+
+ /// LoadCXXThis - Load the value of 'this'. This function is only valid while
+ /// generating code for an C++ member function.
+ llvm::Value *LoadCXXThis();
+
+ void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
+ llvm::Value *This,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd);
+
+ void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type,
+ llvm::Value *This);
+
+ void PushCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr);
+
+ llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E);
+
+ //===--------------------------------------------------------------------===//
+ // Declaration Emission
+ //===--------------------------------------------------------------------===//
+
+ void EmitDecl(const Decl &D);
+ void EmitBlockVarDecl(const VarDecl &D);
+ void EmitLocalBlockVarDecl(const VarDecl &D);
+ void EmitStaticBlockVarDecl(const VarDecl &D);
+
+ /// EmitParmDecl - Emit a ParmVarDecl or an ImplicitParamDecl.
+ void EmitParmDecl(const VarDecl &D, llvm::Value *Arg);
+
+ //===--------------------------------------------------------------------===//
+ // Statement Emission
+ //===--------------------------------------------------------------------===//
+
+ /// EmitStopPoint - Emit a debug stoppoint if we are emitting debug info.
+ void EmitStopPoint(const Stmt *S);
+
+ /// EmitStmt - Emit the code for the statement \arg S. It is legal to call
+ /// this function even if there is no current insertion point.
+ ///
+ /// This function may clear the current insertion point; callers should use
+ /// EnsureInsertPoint if they wish to subsequently generate code without first
+ /// calling EmitBlock, EmitBranch, or EmitStmt.
+ void EmitStmt(const Stmt *S);
+
+ /// EmitSimpleStmt - Try to emit a "simple" statement which does not
+ /// necessarily require an insertion point or debug information; typically
+ /// because the statement amounts to a jump or a container of other
+ /// statements.
+ ///
+ /// \return True if the statement was handled.
+ bool EmitSimpleStmt(const Stmt *S);
+
+ RValue EmitCompoundStmt(const CompoundStmt &S, bool GetLast = false,
+ llvm::Value *AggLoc = 0, bool isAggVol = false);
+
+ /// EmitLabel - Emit the block for the given label. It is legal to call this
+ /// function even if there is no current insertion point.
+ void EmitLabel(const LabelStmt &S); // helper for EmitLabelStmt.
+
+ void EmitLabelStmt(const LabelStmt &S);
+ void EmitGotoStmt(const GotoStmt &S);
+ void EmitIndirectGotoStmt(const IndirectGotoStmt &S);
+ void EmitIfStmt(const IfStmt &S);
+ void EmitWhileStmt(const WhileStmt &S);
+ void EmitDoStmt(const DoStmt &S);
+ void EmitForStmt(const ForStmt &S);
+ void EmitReturnStmt(const ReturnStmt &S);
+ void EmitDeclStmt(const DeclStmt &S);
+ void EmitBreakStmt(const BreakStmt &S);
+ void EmitContinueStmt(const ContinueStmt &S);
+ void EmitSwitchStmt(const SwitchStmt &S);
+ void EmitDefaultStmt(const DefaultStmt &S);
+ void EmitCaseStmt(const CaseStmt &S);
+ void EmitCaseStmtRange(const CaseStmt &S);
+ void EmitAsmStmt(const AsmStmt &S);
+
+ void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S);
+ void EmitObjCAtTryStmt(const ObjCAtTryStmt &S);
+ void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S);
+ void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S);
+
+ //===--------------------------------------------------------------------===//
+ // LValue Expression Emission
+ //===--------------------------------------------------------------------===//
+
+ /// GetUndefRValue - Get an appropriate 'undef' rvalue for the given type.
+ RValue GetUndefRValue(QualType Ty);
+
+ /// EmitUnsupportedRValue - Emit a dummy r-value using the type of E
+ /// and issue an ErrorUnsupported style diagnostic (using the
+ /// provided Name).
+ RValue EmitUnsupportedRValue(const Expr *E,
+ const char *Name);
+
+ /// EmitUnsupportedLValue - Emit a dummy l-value using the type of E and issue
+ /// an ErrorUnsupported style diagnostic (using the provided Name).
+ LValue EmitUnsupportedLValue(const Expr *E,
+ const char *Name);
+
+ /// EmitLValue - Emit code to compute a designator that specifies the location
+ /// of the expression.
+ ///
+ /// This can return one of two things: a simple address or a bitfield
+ /// reference. In either case, the LLVM Value* in the LValue structure is
+ /// guaranteed to be an LLVM pointer type.
+ ///
+ /// If this returns a bitfield reference, nothing about the pointee type of
+ /// the LLVM value is known: For example, it may not be a pointer to an
+ /// integer.
+ ///
+ /// If this returns a normal address, and if the lvalue's C type is fixed
+ /// size, this method guarantees that the returned pointer type will point to
+ /// an LLVM type of the same size of the lvalue's type. If the lvalue has a
+ /// variable length type, this is not possible.
+ ///
+ LValue EmitLValue(const Expr *E);
+
+ /// EmitLoadOfScalar - Load a scalar value from an address, taking
+ /// care to appropriately convert from the memory representation to
+ /// the LLVM value representation.
+ llvm::Value *EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
+ QualType Ty);
+
+ /// EmitStoreOfScalar - Store a scalar value to an address, taking
+ /// care to appropriately convert from the memory representation to
+ /// the LLVM value representation.
+ void EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
+ bool Volatile, QualType Ty);
+
+ /// EmitLoadOfLValue - Given an expression that represents a value lvalue,
+ /// this method emits the address of the lvalue, then loads the result as an
+ /// rvalue, returning the rvalue.
+ RValue EmitLoadOfLValue(LValue V, QualType LVType);
+ RValue EmitLoadOfExtVectorElementLValue(LValue V, QualType LVType);
+ RValue EmitLoadOfBitfieldLValue(LValue LV, QualType ExprType);
+ RValue EmitLoadOfPropertyRefLValue(LValue LV, QualType ExprType);
+ RValue EmitLoadOfKVCRefLValue(LValue LV, QualType ExprType);
+
+
+ /// EmitStoreThroughLValue - Store the specified rvalue into the specified
+ /// lvalue, where both are guaranteed to the have the same type, and that type
+ /// is 'Ty'.
+ void EmitStoreThroughLValue(RValue Src, LValue Dst, QualType Ty);
+ void EmitStoreThroughExtVectorComponentLValue(RValue Src, LValue Dst,
+ QualType Ty);
+ void EmitStoreThroughPropertyRefLValue(RValue Src, LValue Dst, QualType Ty);
+ void EmitStoreThroughKVCRefLValue(RValue Src, LValue Dst, QualType Ty);
+
+ /// EmitStoreThroughLValue - Store Src into Dst with same constraints as
+ /// EmitStoreThroughLValue.
+ ///
+ /// \param Result [out] - If non-null, this will be set to a Value* for the
+ /// bit-field contents after the store, appropriate for use as the result of
+ /// an assignment to the bit-field.
+ void EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, QualType Ty,
+ llvm::Value **Result=0);
+
+ // Note: only availabe for agg return types
+ LValue EmitBinaryOperatorLValue(const BinaryOperator *E);
+ // Note: only available for agg return types
+ LValue EmitCallExprLValue(const CallExpr *E);
+ // Note: only available for agg return types
+ LValue EmitVAArgExprLValue(const VAArgExpr *E);
+ LValue EmitDeclRefLValue(const DeclRefExpr *E);
+ LValue EmitStringLiteralLValue(const StringLiteral *E);
+ LValue EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E);
+ LValue EmitPredefinedFunctionName(unsigned Type);
+ LValue EmitPredefinedLValue(const PredefinedExpr *E);
+ LValue EmitUnaryOpLValue(const UnaryOperator *E);
+ LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E);
+ LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E);
+ LValue EmitMemberExpr(const MemberExpr *E);
+ LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E);
+ LValue EmitConditionalOperator(const ConditionalOperator *E);
+ LValue EmitCastLValue(const CastExpr *E);
+
+ llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
+ const ObjCIvarDecl *Ivar);
+ LValue EmitLValueForField(llvm::Value* Base, FieldDecl* Field,
+ bool isUnion, unsigned CVRQualifiers);
+ LValue EmitLValueForIvar(QualType ObjectTy,
+ llvm::Value* Base, const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers);
+
+ LValue EmitLValueForBitfield(llvm::Value* Base, FieldDecl* Field,
+ unsigned CVRQualifiers);
+
+ LValue EmitBlockDeclRefLValue(const BlockDeclRefExpr *E);
+
+ LValue EmitCXXConditionDeclLValue(const CXXConditionDeclExpr *E);
+ LValue EmitCXXConstructLValue(const CXXConstructExpr *E);
+ LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E);
+
+ LValue EmitObjCMessageExprLValue(const ObjCMessageExpr *E);
+ LValue EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E);
+ LValue EmitObjCPropertyRefLValue(const ObjCPropertyRefExpr *E);
+ LValue EmitObjCKVCRefLValue(const ObjCKVCRefExpr *E);
+ LValue EmitObjCSuperExprLValue(const ObjCSuperExpr *E);
+ LValue EmitStmtExprLValue(const StmtExpr *E);
+
+ //===--------------------------------------------------------------------===//
+ // Scalar Expression Emission
+ //===--------------------------------------------------------------------===//
+
+ /// EmitCall - Generate a call of the given function, expecting the given
+ /// result type, and using the given argument list which specifies both the
+ /// LLVM arguments and the types they were derived from.
+ ///
+ /// \param TargetDecl - If given, the decl of the function in a
+ /// direct call; used to set attributes on the call (noreturn,
+ /// etc.).
+ RValue EmitCall(const CGFunctionInfo &FnInfo,
+ llvm::Value *Callee,
+ const CallArgList &Args,
+ const Decl *TargetDecl = 0);
+
+ RValue EmitCall(llvm::Value *Callee, QualType FnType,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd,
+ const Decl *TargetDecl = 0);
+ RValue EmitCallExpr(const CallExpr *E);
+
+ RValue EmitCXXMemberCall(const CXXMethodDecl *MD,
+ llvm::Value *Callee,
+ llvm::Value *This,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd);
+ RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E);
+
+ RValue EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
+ const CXXMethodDecl *MD);
+
+ RValue EmitBuiltinExpr(const FunctionDecl *FD,
+ unsigned BuiltinID, const CallExpr *E);
+
+ RValue EmitBlockCallExpr(const CallExpr *E);
+
+ /// EmitTargetBuiltinExpr - Emit the given builtin call. Returns 0 if the call
+ /// is unhandled by the current target.
+ llvm::Value *EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
+
+ llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
+ llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
+
+ llvm::Value *EmitShuffleVector(llvm::Value* V1, llvm::Value *V2, ...);
+ llvm::Value *EmitVector(llvm::Value * const *Vals, unsigned NumVals,
+ bool isSplat = false);
+
+ llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E);
+ llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E);
+ llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E);
+ RValue EmitObjCMessageExpr(const ObjCMessageExpr *E);
+ RValue EmitObjCPropertyGet(const Expr *E);
+ RValue EmitObjCSuperPropertyGet(const Expr *Exp, const Selector &S);
+ void EmitObjCPropertySet(const Expr *E, RValue Src);
+ void EmitObjCSuperPropertySet(const Expr *E, const Selector &S, RValue Src);
+
+
+ /// EmitReferenceBindingToExpr - Emits a reference binding to the passed in
+ /// expression. Will emit a temporary variable if E is not an LValue.
+ RValue EmitReferenceBindingToExpr(const Expr* E, QualType DestType);
+
+ //===--------------------------------------------------------------------===//
+ // Expression Emission
+ //===--------------------------------------------------------------------===//
+
+ // Expressions are broken into three classes: scalar, complex, aggregate.
+
+ /// EmitScalarExpr - Emit the computation of the specified expression of LLVM
+ /// scalar type, returning the result.
+ llvm::Value *EmitScalarExpr(const Expr *E , bool IgnoreResultAssign=false);
+
+ /// EmitScalarConversion - Emit a conversion from the specified type to the
+ /// specified destination type, both of which are LLVM scalar types.
+ llvm::Value *EmitScalarConversion(llvm::Value *Src, QualType SrcTy,
+ QualType DstTy);
+
+ /// EmitComplexToScalarConversion - Emit a conversion from the specified
+ /// complex type to the specified destination type, where the destination type
+ /// is an LLVM scalar type.
+ llvm::Value *EmitComplexToScalarConversion(ComplexPairTy Src, QualType SrcTy,
+ QualType DstTy);
+
+
+ /// EmitAggExpr - Emit the computation of the specified expression of
+ /// aggregate type. The result is computed into DestPtr. Note that if
+ /// DestPtr is null, the value of the aggregate expression is not needed.
+ void EmitAggExpr(const Expr *E, llvm::Value *DestPtr, bool VolatileDest,
+ bool IgnoreResult = false);
+
+ /// EmitComplexExpr - Emit the computation of the specified expression of
+ /// complex type, returning the result.
+ ComplexPairTy EmitComplexExpr(const Expr *E, bool IgnoreReal = false,
+ bool IgnoreImag = false,
+ bool IgnoreRealAssign = false,
+ bool IgnoreImagAssign = false);
+
+ /// EmitComplexExprIntoAddr - Emit the computation of the specified expression
+ /// of complex type, storing into the specified Value*.
+ void EmitComplexExprIntoAddr(const Expr *E, llvm::Value *DestAddr,
+ bool DestIsVolatile);
+
+ /// StoreComplexToAddr - Store a complex number into the specified address.
+ void StoreComplexToAddr(ComplexPairTy V, llvm::Value *DestAddr,
+ bool DestIsVolatile);
+ /// LoadComplexFromAddr - Load a complex number from the specified address.
+ ComplexPairTy LoadComplexFromAddr(llvm::Value *SrcAddr, bool SrcIsVolatile);
+
+ /// CreateStaticBlockVarDecl - Create a zero-initialized LLVM global
+ /// for a static block var decl.
+ llvm::GlobalVariable * CreateStaticBlockVarDecl(const VarDecl &D,
+ const char *Separator,
+ llvm::GlobalValue::LinkageTypes
+ Linkage);
+
+ /// GenerateStaticCXXBlockVarDecl - Create the initializer for a C++
+ /// runtime initialized static block var decl.
+ void GenerateStaticCXXBlockVarDeclInit(const VarDecl &D,
+ llvm::GlobalVariable *GV);
+
+ void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E);
+
+ RValue EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
+ llvm::Value *AggLoc = 0,
+ bool isAggLocVolatile = false);
+
+ //===--------------------------------------------------------------------===//
+ // Internal Helpers
+ //===--------------------------------------------------------------------===//
+
+ /// ContainsLabel - Return true if the statement contains a label in it. If
+ /// this statement is not executed normally, it not containing a label means
+ /// that we can just remove the code.
+ static bool ContainsLabel(const Stmt *S, bool IgnoreCaseStmts = false);
+
+ /// ConstantFoldsToSimpleInteger - If the specified expression does not fold
+ /// to a constant, or if it does but contains a label, return 0. If it
+ /// constant folds to 'true' and does not contain a label, return 1, if it
+ /// constant folds to 'false' and does not contain a label, return -1.
+ int ConstantFoldsToSimpleInteger(const Expr *Cond);
+
+ /// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g. for an
+ /// if statement) to the specified blocks. Based on the condition, this might
+ /// try to simplify the codegen of the conditional based on the branch.
+ void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock,
+ llvm::BasicBlock *FalseBlock);
+private:
+
+ /// EmitIndirectSwitches - Emit code for all of the switch
+ /// instructions in IndirectSwitches.
+ void EmitIndirectSwitches();
+
+ void EmitReturnOfRValue(RValue RV, QualType Ty);
+
+ /// ExpandTypeFromArgs - Reconstruct a structure of type \arg Ty
+ /// from function arguments into \arg Dst. See ABIArgInfo::Expand.
+ ///
+ /// \param AI - The first function argument of the expansion.
+ /// \return The argument following the last expanded function
+ /// argument.
+ llvm::Function::arg_iterator
+ ExpandTypeFromArgs(QualType Ty, LValue Dst,
+ llvm::Function::arg_iterator AI);
+
+ /// ExpandTypeToArgs - Expand an RValue \arg Src, with the LLVM type for \arg
+ /// 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);
+
+ llvm::Value* EmitAsmInput(const AsmStmt &S,
+ const TargetInfo::ConstraintInfo &Info,
+ const Expr *InputExpr, std::string &ConstraintStr);
+
+ /// EmitCleanupBlock - emits a single cleanup block.
+ void EmitCleanupBlock();
+
+ /// AddBranchFixup - adds a branch instruction to the list of fixups for the
+ /// current cleanup scope.
+ void AddBranchFixup(llvm::BranchInst *BI);
+
+ /// EmitCallArg - Emit a single call argument.
+ RValue EmitCallArg(const Expr *E, QualType ArgType);
+
+ /// EmitCallArgs - Emit call arguments for a function.
+ /// The CallArgTypeInfo parameter is used for iterating over the known
+ /// argument types of the function being called.
+ template<typename T>
+ void EmitCallArgs(CallArgList& Args, const T* CallArgTypeInfo,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) {
+ CallExpr::const_arg_iterator Arg = ArgBeg;
+
+ // First, use the argument types that the type info knows about
+ if (CallArgTypeInfo) {
+ for (typename T::arg_type_iterator I = CallArgTypeInfo->arg_type_begin(),
+ E = CallArgTypeInfo->arg_type_end(); I != E; ++I, ++Arg) {
+ QualType ArgType = *I;
+
+ assert(getContext().getCanonicalType(ArgType.getNonReferenceType()).
+ getTypePtr() ==
+ getContext().getCanonicalType(Arg->getType()).getTypePtr() &&
+ "type mismatch in call argument!");
+
+ Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType),
+ ArgType));
+ }
+
+ // Either we've emitted all the call args, or we have a call to a
+ // variadic function.
+ assert((Arg == ArgEnd || CallArgTypeInfo->isVariadic()) &&
+ "Extra arguments in non-variadic function!");
+
+ }
+
+ // If we still have any arguments, emit them using the type of the argument.
+ for (; Arg != ArgEnd; ++Arg) {
+ QualType ArgType = Arg->getType();
+ Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType),
+ ArgType));
+ }
+ }
+};
+
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
new file mode 100644
index 000000000000..b69301ed5893
--- /dev/null
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -0,0 +1,1543 @@
+//===--- CodeGenModule.cpp - Emit LLVM Code from ASTs for a Module --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This coordinates the per-module state used while generating code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenModule.h"
+#include "CGDebugInfo.h"
+#include "CodeGenFunction.h"
+#include "CGCall.h"
+#include "CGObjCRuntime.h"
+#include "Mangle.h"
+#include "clang/Frontend/CompileOptions.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/ConvertUTF.h"
+#include "llvm/CallingConv.h"
+#include "llvm/Module.h"
+#include "llvm/Intrinsics.h"
+#include "llvm/Target/TargetData.h"
+using namespace clang;
+using namespace CodeGen;
+
+
+CodeGenModule::CodeGenModule(ASTContext &C, const CompileOptions &compileOpts,
+ llvm::Module &M, const llvm::TargetData &TD,
+ Diagnostic &diags)
+ : BlockModule(C, M, TD, Types, *this), Context(C),
+ Features(C.getLangOptions()), CompileOpts(compileOpts), TheModule(M),
+ TheTargetData(TD), Diags(diags), Types(C, M, TD), Runtime(0),
+ MemCpyFn(0), MemMoveFn(0), MemSetFn(0), CFConstantStringClassRef(0) {
+
+ if (!Features.ObjC1)
+ Runtime = 0;
+ else if (!Features.NeXTRuntime)
+ Runtime = CreateGNUObjCRuntime(*this);
+ else if (Features.ObjCNonFragileABI)
+ Runtime = CreateMacNonFragileABIObjCRuntime(*this);
+ else
+ Runtime = CreateMacObjCRuntime(*this);
+
+ // If debug info generation is enabled, create the CGDebugInfo object.
+ DebugInfo = CompileOpts.DebugInfo ? new CGDebugInfo(this) : 0;
+}
+
+CodeGenModule::~CodeGenModule() {
+ delete Runtime;
+ delete DebugInfo;
+}
+
+void CodeGenModule::Release() {
+ EmitDeferred();
+ if (Runtime)
+ if (llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction())
+ AddGlobalCtor(ObjCInitFunction);
+ EmitCtorList(GlobalCtors, "llvm.global_ctors");
+ EmitCtorList(GlobalDtors, "llvm.global_dtors");
+ EmitAnnotations();
+ EmitLLVMUsed();
+}
+
+/// ErrorUnsupported - Print out an error that codegen doesn't support the
+/// specified stmt yet.
+void CodeGenModule::ErrorUnsupported(const Stmt *S, const char *Type,
+ bool OmitOnError) {
+ if (OmitOnError && getDiags().hasErrorOccurred())
+ return;
+ unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Error,
+ "cannot compile this %0 yet");
+ std::string Msg = Type;
+ getDiags().Report(Context.getFullLoc(S->getLocStart()), DiagID)
+ << Msg << S->getSourceRange();
+}
+
+/// ErrorUnsupported - Print out an error that codegen doesn't support the
+/// specified decl yet.
+void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type,
+ bool OmitOnError) {
+ if (OmitOnError && getDiags().hasErrorOccurred())
+ return;
+ unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Error,
+ "cannot compile this %0 yet");
+ std::string Msg = Type;
+ getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg;
+}
+
+LangOptions::VisibilityMode
+CodeGenModule::getDeclVisibilityMode(const Decl *D) const {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ if (VD->getStorageClass() == VarDecl::PrivateExtern)
+ return LangOptions::Hidden;
+
+ if (const VisibilityAttr *attr = D->getAttr<VisibilityAttr>()) {
+ switch (attr->getVisibility()) {
+ default: assert(0 && "Unknown visibility!");
+ case VisibilityAttr::DefaultVisibility:
+ return LangOptions::Default;
+ case VisibilityAttr::HiddenVisibility:
+ return LangOptions::Hidden;
+ case VisibilityAttr::ProtectedVisibility:
+ return LangOptions::Protected;
+ }
+ }
+
+ return getLangOptions().getVisibilityMode();
+}
+
+void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV,
+ const Decl *D) const {
+ // Internal definitions always have default visibility.
+ if (GV->hasLocalLinkage()) {
+ GV->setVisibility(llvm::GlobalValue::DefaultVisibility);
+ return;
+ }
+
+ switch (getDeclVisibilityMode(D)) {
+ default: assert(0 && "Unknown visibility!");
+ case LangOptions::Default:
+ return GV->setVisibility(llvm::GlobalValue::DefaultVisibility);
+ case LangOptions::Hidden:
+ return GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ case LangOptions::Protected:
+ return GV->setVisibility(llvm::GlobalValue::ProtectedVisibility);
+ }
+}
+
+const char *CodeGenModule::getMangledName(const GlobalDecl &GD) {
+ const NamedDecl *ND = GD.getDecl();
+
+ if (const CXXConstructorDecl *D = dyn_cast<CXXConstructorDecl>(ND))
+ return getMangledCXXCtorName(D, GD.getCtorType());
+ if (const CXXDestructorDecl *D = dyn_cast<CXXDestructorDecl>(ND))
+ return getMangledCXXDtorName(D, GD.getDtorType());
+
+ return getMangledName(ND);
+}
+
+/// \brief Retrieves the mangled name for the given declaration.
+///
+/// If the given declaration requires a mangled name, returns an
+/// const char* containing the mangled name. Otherwise, returns
+/// the unmangled name.
+///
+const char *CodeGenModule::getMangledName(const NamedDecl *ND) {
+ // In C, functions with no attributes never need to be mangled. Fastpath them.
+ if (!getLangOptions().CPlusPlus && !ND->hasAttrs()) {
+ assert(ND->getIdentifier() && "Attempt to mangle unnamed decl.");
+ return ND->getNameAsCString();
+ }
+
+ llvm::SmallString<256> Name;
+ llvm::raw_svector_ostream Out(Name);
+ if (!mangleName(ND, Context, Out)) {
+ assert(ND->getIdentifier() && "Attempt to mangle unnamed decl.");
+ return ND->getNameAsCString();
+ }
+
+ Name += '\0';
+ return UniqueMangledName(Name.begin(), Name.end());
+}
+
+const char *CodeGenModule::UniqueMangledName(const char *NameStart,
+ const char *NameEnd) {
+ assert(*(NameEnd - 1) == '\0' && "Mangled name must be null terminated!");
+
+ return MangledNames.GetOrCreateValue(NameStart, NameEnd).getKeyData();
+}
+
+/// AddGlobalCtor - Add a function to the list that will be called before
+/// main() runs.
+void CodeGenModule::AddGlobalCtor(llvm::Function * Ctor, int Priority) {
+ // FIXME: Type coercion of void()* types.
+ GlobalCtors.push_back(std::make_pair(Ctor, Priority));
+}
+
+/// AddGlobalDtor - Add a function to the list that will be called
+/// when the module is unloaded.
+void CodeGenModule::AddGlobalDtor(llvm::Function * Dtor, int Priority) {
+ // FIXME: Type coercion of void()* types.
+ GlobalDtors.push_back(std::make_pair(Dtor, Priority));
+}
+
+void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) {
+ // Ctor function type is void()*.
+ llvm::FunctionType* CtorFTy =
+ llvm::FunctionType::get(llvm::Type::VoidTy,
+ std::vector<const llvm::Type*>(),
+ false);
+ llvm::Type *CtorPFTy = llvm::PointerType::getUnqual(CtorFTy);
+
+ // Get the type of a ctor entry, { i32, void ()* }.
+ llvm::StructType* CtorStructTy =
+ llvm::StructType::get(llvm::Type::Int32Ty,
+ llvm::PointerType::getUnqual(CtorFTy), NULL);
+
+ // Construct the constructor and destructor arrays.
+ std::vector<llvm::Constant*> Ctors;
+ for (CtorList::const_iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) {
+ std::vector<llvm::Constant*> S;
+ S.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, I->second, false));
+ S.push_back(llvm::ConstantExpr::getBitCast(I->first, CtorPFTy));
+ Ctors.push_back(llvm::ConstantStruct::get(CtorStructTy, S));
+ }
+
+ if (!Ctors.empty()) {
+ llvm::ArrayType *AT = llvm::ArrayType::get(CtorStructTy, Ctors.size());
+ new llvm::GlobalVariable(AT, false,
+ llvm::GlobalValue::AppendingLinkage,
+ llvm::ConstantArray::get(AT, Ctors),
+ GlobalName,
+ &TheModule);
+ }
+}
+
+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(Array->getType(), false,
+ llvm::GlobalValue::AppendingLinkage, Array,
+ "llvm.global.annotations", &TheModule);
+ gv->setSection("llvm.metadata");
+}
+
+static CodeGenModule::GVALinkage
+GetLinkageForFunction(const FunctionDecl *FD, const LangOptions &Features) {
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ // C++ member functions defined inside the class are always inline.
+ if (MD->isInline() || !MD->isOutOfLineDefinition())
+ return CodeGenModule::GVA_CXXInline;
+
+ return CodeGenModule::GVA_StrongExternal;
+ }
+
+ // "static" functions get internal linkage.
+ if (FD->getStorageClass() == FunctionDecl::Static)
+ return CodeGenModule::GVA_Internal;
+
+ if (!FD->isInline())
+ return CodeGenModule::GVA_StrongExternal;
+
+ // If the inline function explicitly has the GNU inline attribute on it, or if
+ // this is C89 mode, we use to GNU semantics.
+ if (!Features.C99 && !Features.CPlusPlus) {
+ // extern inline in GNU mode is like C99 inline.
+ if (FD->getStorageClass() == FunctionDecl::Extern)
+ return CodeGenModule::GVA_C99Inline;
+ // Normal inline is a strong symbol.
+ return CodeGenModule::GVA_StrongExternal;
+ } else if (FD->hasActiveGNUInlineAttribute()) {
+ // GCC in C99 mode seems to use a different decision-making
+ // process for extern inline, which factors in previous
+ // declarations.
+ if (FD->isExternGNUInline())
+ return CodeGenModule::GVA_C99Inline;
+ // Normal inline is a strong symbol.
+ return CodeGenModule::GVA_StrongExternal;
+ }
+
+ // The definition of inline changes based on the language. Note that we
+ // have already handled "static inline" above, with the GVA_Internal case.
+ if (Features.CPlusPlus) // inline and extern inline.
+ return CodeGenModule::GVA_CXXInline;
+
+ assert(Features.C99 && "Must be in C99 mode if not in C89 or C++ mode");
+ if (FD->isC99InlineDefinition())
+ return CodeGenModule::GVA_C99Inline;
+
+ return CodeGenModule::GVA_StrongExternal;
+}
+
+/// SetFunctionDefinitionAttributes - Set attributes for a global.
+///
+/// FIXME: This is currently only done for aliases and functions, but not for
+/// variables (these details are set in EmitGlobalVarDefinition for variables).
+void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D,
+ llvm::GlobalValue *GV) {
+ GVALinkage Linkage = GetLinkageForFunction(D, Features);
+
+ if (Linkage == GVA_Internal) {
+ GV->setLinkage(llvm::Function::InternalLinkage);
+ } else if (D->hasAttr<DLLExportAttr>()) {
+ GV->setLinkage(llvm::Function::DLLExportLinkage);
+ } else if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakImportAttr>()) {
+ GV->setLinkage(llvm::Function::WeakAnyLinkage);
+ } else if (Linkage == GVA_C99Inline) {
+ // In C99 mode, 'inline' functions are guaranteed to have a strong
+ // definition somewhere else, so we can use available_externally linkage.
+ GV->setLinkage(llvm::Function::AvailableExternallyLinkage);
+ } else if (Linkage == GVA_CXXInline) {
+ // 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
+ // don't need to codegen it. b) if the function persists, it needs to be
+ // merged with other definitions. c) C++ has the ODR, so we know the
+ // definition is dependable.
+ GV->setLinkage(llvm::Function::LinkOnceODRLinkage);
+ } else {
+ assert(Linkage == GVA_StrongExternal);
+ // Otherwise, we have strong external linkage.
+ GV->setLinkage(llvm::Function::ExternalLinkage);
+ }
+
+ SetCommonAttributes(D, GV);
+}
+
+void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D,
+ const CGFunctionInfo &Info,
+ llvm::Function *F) {
+ AttributeListType AttributeList;
+ ConstructAttributeList(Info, D, AttributeList);
+
+ F->setAttributes(llvm::AttrListPtr::get(AttributeList.begin(),
+ AttributeList.size()));
+
+ // Set the appropriate calling convention for the Function.
+ if (D->hasAttr<FastCallAttr>())
+ F->setCallingConv(llvm::CallingConv::X86_FastCall);
+
+ if (D->hasAttr<StdCallAttr>())
+ F->setCallingConv(llvm::CallingConv::X86_StdCall);
+}
+
+void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
+ llvm::Function *F) {
+ if (!Features.Exceptions && !Features.ObjCNonFragileABI)
+ F->addFnAttr(llvm::Attribute::NoUnwind);
+
+ if (D->hasAttr<AlwaysInlineAttr>())
+ F->addFnAttr(llvm::Attribute::AlwaysInline);
+
+ if (D->hasAttr<NoinlineAttr>())
+ F->addFnAttr(llvm::Attribute::NoInline);
+}
+
+void CodeGenModule::SetCommonAttributes(const Decl *D,
+ llvm::GlobalValue *GV) {
+ setGlobalVisibility(GV, D);
+
+ if (D->hasAttr<UsedAttr>())
+ AddUsedGlobal(GV);
+
+ if (const SectionAttr *SA = D->getAttr<SectionAttr>())
+ GV->setSection(SA->getName());
+}
+
+void CodeGenModule::SetInternalFunctionAttributes(const Decl *D,
+ llvm::Function *F,
+ const CGFunctionInfo &FI) {
+ SetLLVMFunctionAttributes(D, FI, F);
+ SetLLVMFunctionAttributesForDefinition(D, F);
+
+ F->setLinkage(llvm::Function::InternalLinkage);
+
+ SetCommonAttributes(D, F);
+}
+
+void CodeGenModule::SetFunctionAttributes(const FunctionDecl *FD,
+ llvm::Function *F,
+ bool IsIncompleteFunction) {
+ if (!IsIncompleteFunction)
+ SetLLVMFunctionAttributes(FD, getTypes().getFunctionInfo(FD), F);
+
+ // Only a few attributes are set on declarations; these may later be
+ // overridden by a definition.
+
+ if (FD->hasAttr<DLLImportAttr>()) {
+ F->setLinkage(llvm::Function::DLLImportLinkage);
+ } else if (FD->hasAttr<WeakAttr>() || FD->hasAttr<WeakImportAttr>()) {
+ // "extern_weak" is overloaded in LLVM; we probably should have
+ // separate linkage types for this.
+ F->setLinkage(llvm::Function::ExternalWeakLinkage);
+ } else {
+ F->setLinkage(llvm::Function::ExternalLinkage);
+ }
+
+ if (const SectionAttr *SA = FD->getAttr<SectionAttr>())
+ F->setSection(SA->getName());
+}
+
+void CodeGenModule::AddUsedGlobal(llvm::GlobalValue *GV) {
+ assert(!GV->isDeclaration() &&
+ "Only globals with definition can force usage.");
+ LLVMUsed.push_back(GV);
+}
+
+void CodeGenModule::EmitLLVMUsed() {
+ // Don't create llvm.used if there is no need.
+ if (LLVMUsed.empty())
+ return;
+
+ llvm::Type *i8PTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, LLVMUsed.size());
+
+ // Convert LLVMUsed to what ConstantArray needs.
+ std::vector<llvm::Constant*> UsedArray;
+ UsedArray.resize(LLVMUsed.size());
+ for (unsigned i = 0, e = LLVMUsed.size(); i != e; ++i) {
+ UsedArray[i] =
+ llvm::ConstantExpr::getBitCast(cast<llvm::Constant>(&*LLVMUsed[i]), i8PTy);
+ }
+
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(ATy, false,
+ llvm::GlobalValue::AppendingLinkage,
+ llvm::ConstantArray::get(ATy, UsedArray),
+ "llvm.used", &getModule());
+
+ GV->setSection("llvm.metadata");
+}
+
+void CodeGenModule::EmitDeferred() {
+ // Emit code for any potentially referenced deferred decls. Since a
+ // previously unused static decl may become used during the generation of code
+ // for a static function, iterate until no changes are made.
+ while (!DeferredDeclsToEmit.empty()) {
+ GlobalDecl D = DeferredDeclsToEmit.back();
+ DeferredDeclsToEmit.pop_back();
+
+ // The mangled name for the decl must have been emitted in GlobalDeclMap.
+ // Look it up to see if it was defined with a stronger definition (e.g. an
+ // extern inline function with a strong function redefinition). If so,
+ // just ignore the deferred decl.
+ llvm::GlobalValue *CGRef = GlobalDeclMap[getMangledName(D)];
+ assert(CGRef && "Deferred decl wasn't referenced?");
+
+ if (!CGRef->isDeclaration())
+ continue;
+
+ // Otherwise, emit the definition and move on to the next one.
+ EmitGlobalDefinition(D);
+ }
+}
+
+/// 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.
+///
+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::PointerType::getUnqual(llvm::Type::Int8Ty);
+ llvm::Constant *anno = llvm::ConstantArray::get(AA->getAnnotation(), true);
+ llvm::Constant *unit = llvm::ConstantArray::get(M->getModuleIdentifier(),
+ true);
+
+ // Get the two global values corresponding to the ConstantArrays we just
+ // created to hold the bytes of the strings.
+ const char *StringPrefix = getContext().Target.getStringSymbolPrefix(true);
+ llvm::GlobalValue *annoGV =
+ new llvm::GlobalVariable(anno->getType(), false,
+ llvm::GlobalValue::InternalLinkage, anno,
+ GV->getName() + StringPrefix, M);
+ // translation unit name string, emitted into the llvm.metadata section.
+ llvm::GlobalValue *unitGV =
+ new llvm::GlobalVariable(unit->getType(), false,
+ llvm::GlobalValue::InternalLinkage, unit,
+ StringPrefix, M);
+
+ // 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::Int32Ty, LineNo)
+ };
+ return llvm::ConstantStruct::get(Fields, 4, false);
+}
+
+bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
+ // Never defer when EmitAllDecls is specified or the decl has
+ // attribute used.
+ if (Features.EmitAllDecls || Global->hasAttr<UsedAttr>())
+ return false;
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Global)) {
+ // Constructors and destructors should never be deferred.
+ if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
+ return false;
+
+ GVALinkage Linkage = GetLinkageForFunction(FD, Features);
+
+ // static, static inline, always_inline, and extern inline functions can
+ // always be deferred. Normal inline functions can be deferred in C99/C++.
+ if (Linkage == GVA_Internal || Linkage == GVA_C99Inline ||
+ Linkage == GVA_CXXInline)
+ return true;
+ return false;
+ }
+
+ const VarDecl *VD = cast<VarDecl>(Global);
+ assert(VD->isFileVarDecl() && "Invalid decl");
+
+ return VD->getStorageClass() == VarDecl::Static;
+}
+
+void CodeGenModule::EmitGlobal(GlobalDecl GD) {
+ const ValueDecl *Global = GD.getDecl();
+
+ // If this is an alias definition (which otherwise looks like a declaration)
+ // emit it now.
+ if (Global->hasAttr<AliasAttr>())
+ return EmitAliasDefinition(Global);
+
+ // 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->isThisDeclarationADefinition())
+ return;
+ } else {
+ const VarDecl *VD = cast<VarDecl>(Global);
+ assert(VD->isFileVarDecl() && "Cannot emit local var decl as global.");
+
+ // In C++, if this is marked "extern", defer code generation.
+ if (getLangOptions().CPlusPlus && !VD->getInit() &&
+ (VD->getStorageClass() == VarDecl::Extern ||
+ VD->isExternC(getContext())))
+ return;
+
+ // In C, if this isn't a definition, defer code generation.
+ if (!getLangOptions().CPlusPlus && !VD->getInit())
+ return;
+ }
+
+ // Defer code generation when possible if this is a static definition, inline
+ // function etc. These we only want to emit if they are used.
+ if (MayDeferGeneration(Global)) {
+ // If the value has already been used, add it directly to the
+ // DeferredDeclsToEmit list.
+ const char *MangledName = getMangledName(GD);
+ if (GlobalDeclMap.count(MangledName))
+ DeferredDeclsToEmit.push_back(GD);
+ else {
+ // Otherwise, remember that we saw a deferred decl with this name. The
+ // first use of the mangled name will cause it to move into
+ // DeferredDeclsToEmit.
+ DeferredDecls[MangledName] = GD;
+ }
+ return;
+ }
+
+ // Otherwise emit the definition.
+ EmitGlobalDefinition(GD);
+}
+
+void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
+ const ValueDecl *D = GD.getDecl();
+
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
+ EmitCXXConstructor(CD, GD.getCtorType());
+ else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D))
+ EmitCXXDestructor(DD, GD.getDtorType());
+ else if (isa<FunctionDecl>(D))
+ EmitGlobalFunctionDefinition(GD);
+ else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ EmitGlobalVarDefinition(VD);
+ else {
+ assert(0 && "Invalid argument to EmitGlobalDefinition()");
+ }
+}
+
+/// GetOrCreateLLVMFunction - If the specified mangled name is not in the
+/// module, create and return an llvm Function with the specified type. If there
+/// is something in the module with the specified name, return it potentially
+/// bitcasted to the right type.
+///
+/// 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(const char *MangledName,
+ const llvm::Type *Ty,
+ GlobalDecl D) {
+ // Lookup the entry, lazily creating it if necessary.
+ llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
+ if (Entry) {
+ if (Entry->getType()->getElementType() == Ty)
+ return Entry;
+
+ // Make sure the result is of the correct type.
+ const llvm::Type *PTy = llvm::PointerType::getUnqual(Ty);
+ return llvm::ConstantExpr::getBitCast(Entry, PTy);
+ }
+
+ // This is the first use or definition of a mangled name. If there is a
+ // deferred decl with this name, remember that we need to emit it at the end
+ // of the file.
+ llvm::DenseMap<const char*, GlobalDecl>::iterator DDI =
+ DeferredDecls.find(MangledName);
+ if (DDI != DeferredDecls.end()) {
+ // Move the potentially referenced deferred decl to the DeferredDeclsToEmit
+ // list, and remove it from DeferredDecls (since we don't need it anymore).
+ DeferredDeclsToEmit.push_back(DDI->second);
+ DeferredDecls.erase(DDI);
+ } else if (const FunctionDecl *FD = cast_or_null<FunctionDecl>(D.getDecl())) {
+ // If this the first reference to a C++ inline function in a class, queue up
+ // the deferred function body for emission. These are not seen as
+ // top-level declarations.
+ if (FD->isThisDeclarationADefinition() && MayDeferGeneration(FD))
+ DeferredDeclsToEmit.push_back(D);
+ }
+
+ // This function doesn't have a complete type (for example, the return
+ // type is an incomplete struct). Use a fake type instead, and make
+ // sure not to try to set attributes.
+ bool IsIncompleteFunction = false;
+ if (!isa<llvm::FunctionType>(Ty)) {
+ Ty = llvm::FunctionType::get(llvm::Type::VoidTy,
+ std::vector<const llvm::Type*>(), false);
+ IsIncompleteFunction = true;
+ }
+ llvm::Function *F = llvm::Function::Create(cast<llvm::FunctionType>(Ty),
+ llvm::Function::ExternalLinkage,
+ "", &getModule());
+ F->setName(MangledName);
+ if (D.getDecl())
+ SetFunctionAttributes(cast<FunctionDecl>(D.getDecl()), F,
+ IsIncompleteFunction);
+ Entry = F;
+ return F;
+}
+
+/// 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 (this occurs when we see a definition of the function).
+llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD,
+ const llvm::Type *Ty) {
+ // If there was no specific requested type, just convert it now.
+ if (!Ty)
+ Ty = getTypes().ConvertType(GD.getDecl()->getType());
+ return GetOrCreateLLVMFunction(getMangledName(GD.getDecl()), Ty, GD);
+}
+
+/// CreateRuntimeFunction - Create a new runtime function with the specified
+/// type and name.
+llvm::Constant *
+CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy,
+ const char *Name) {
+ // Convert Name to be a uniqued string from the IdentifierInfo table.
+ Name = getContext().Idents.get(Name).getName();
+ return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl());
+}
+
+/// GetOrCreateLLVMGlobal - If the specified mangled name is not in the module,
+/// create and return an llvm GlobalVariable with the specified type. If there
+/// is something in the module with the specified name, return it potentially
+/// bitcasted to the right type.
+///
+/// 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(const char *MangledName,
+ const llvm::PointerType*Ty,
+ const VarDecl *D) {
+ // Lookup the entry, lazily creating it if necessary.
+ llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
+ if (Entry) {
+ if (Entry->getType() == Ty)
+ return Entry;
+
+ // Make sure the result is of the correct type.
+ return llvm::ConstantExpr::getBitCast(Entry, Ty);
+ }
+
+ // This is the first use or definition of a mangled name. If there is a
+ // deferred decl with this name, remember that we need to emit it at the end
+ // of the file.
+ llvm::DenseMap<const char*, GlobalDecl>::iterator DDI =
+ DeferredDecls.find(MangledName);
+ if (DDI != DeferredDecls.end()) {
+ // Move the potentially referenced deferred decl to the DeferredDeclsToEmit
+ // list, and remove it from DeferredDecls (since we don't need it anymore).
+ DeferredDeclsToEmit.push_back(DDI->second);
+ DeferredDecls.erase(DDI);
+ }
+
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(Ty->getElementType(), false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0, "", &getModule(),
+ false, Ty->getAddressSpace());
+ GV->setName(MangledName);
+
+ // Handle things which are present even on external declarations.
+ if (D) {
+ // FIXME: This code is overly simple and should be merged with other global
+ // handling.
+ GV->setConstant(D->getType().isConstant(Context));
+
+ // FIXME: Merge with other attribute handling code.
+ if (D->getStorageClass() == VarDecl::PrivateExtern)
+ GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+
+ if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakImportAttr>())
+ GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
+
+ GV->setThreadLocal(D->isThreadSpecified());
+ }
+
+ return Entry = GV;
+}
+
+
+/// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the
+/// given global variable. If Ty is non-null and if the global doesn't exist,
+/// 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) {
+ assert(D->hasGlobalStorage() && "Not a global variable");
+ QualType ASTTy = D->getType();
+ if (Ty == 0)
+ Ty = getTypes().ConvertTypeForMem(ASTTy);
+
+ const llvm::PointerType *PTy =
+ llvm::PointerType::get(Ty, ASTTy.getAddressSpace());
+ return GetOrCreateLLVMGlobal(getMangledName(D), PTy, D);
+}
+
+/// CreateRuntimeVariable - Create a new runtime global variable with the
+/// specified type and name.
+llvm::Constant *
+CodeGenModule::CreateRuntimeVariable(const llvm::Type *Ty,
+ const char *Name) {
+ // Convert Name to be a uniqued string from the IdentifierInfo table.
+ Name = getContext().Idents.get(Name).getName();
+ return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0);
+}
+
+void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
+ assert(!D->getInit() && "Cannot emit definite definitions here!");
+
+ if (MayDeferGeneration(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.
+ const char *MangledName = getMangledName(D);
+ if (GlobalDeclMap.count(MangledName) == 0) {
+ DeferredDecls[MangledName] = GlobalDecl(D);
+ return;
+ }
+ }
+
+ // The tentative definition is the only definition.
+ EmitGlobalVarDefinition(D);
+}
+
+void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
+ llvm::Constant *Init = 0;
+ QualType ASTTy = D->getType();
+
+ if (D->getInit() == 0) {
+ // This is a tentative definition; tentative definitions are
+ // implicitly initialized with { 0 }.
+ //
+ // Note that tentative definitions are only emitted at the end of
+ // a translation unit, so they should never have incomplete
+ // type. In addition, EmitTentativeDefinition makes sure that we
+ // never attempt to emit a tentative definition if a real one
+ // exists. A use may still exists, however, so we still may need
+ // to do a RAUW.
+ assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type");
+ Init = llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(ASTTy));
+ } else {
+ Init = EmitConstantExpr(D->getInit(), D->getType());
+ if (!Init) {
+ ErrorUnsupported(D, "static initializer");
+ QualType T = D->getInit()->getType();
+ Init = llvm::UndefValue::get(getTypes().ConvertType(T));
+ }
+ }
+
+ const llvm::Type* InitType = Init->getType();
+ llvm::Constant *Entry = GetAddrOfGlobalVar(D, InitType);
+
+ // Strip off a bitcast if we got one back.
+ if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(Entry)) {
+ assert(CE->getOpcode() == llvm::Instruction::BitCast);
+ Entry = CE->getOperand(0);
+ }
+
+ // Entry is now either a Function or GlobalVariable.
+ llvm::GlobalVariable *GV = dyn_cast<llvm::GlobalVariable>(Entry);
+
+ // We have a definition after a declaration with the wrong type.
+ // We must make a new GlobalVariable* and update everything that used OldGV
+ // (a declaration or tentative definition) with the new GlobalVariable*
+ // (which will be a definition).
+ //
+ // This happens if there is a prototype for a global (e.g.
+ // "extern int x[];") and then a definition of a different type (e.g.
+ // "int x[10];"). This also happens when an initializer has a different type
+ // from the type of the global (this happens with unions).
+ if (GV == 0 ||
+ GV->getType()->getElementType() != InitType ||
+ GV->getType()->getAddressSpace() != ASTTy.getAddressSpace()) {
+
+ // Remove the old entry from GlobalDeclMap so that we'll create a new one.
+ GlobalDeclMap.erase(getMangledName(D));
+
+ // Make a new global with the correct type, this is now guaranteed to work.
+ GV = cast<llvm::GlobalVariable>(GetAddrOfGlobalVar(D, InitType));
+ GV->takeName(cast<llvm::GlobalValue>(Entry));
+
+ // Replace all uses of the old global with the new global
+ llvm::Constant *NewPtrForOldDecl =
+ llvm::ConstantExpr::getBitCast(GV, Entry->getType());
+ Entry->replaceAllUsesWith(NewPtrForOldDecl);
+
+ // Erase the old global, since it is no longer used.
+ cast<llvm::GlobalValue>(Entry)->eraseFromParent();
+ }
+
+ if (const AnnotateAttr *AA = D->getAttr<AnnotateAttr>()) {
+ SourceManager &SM = Context.getSourceManager();
+ AddAnnotation(EmitAnnotateAttr(GV, AA,
+ SM.getInstantiationLineNumber(D->getLocation())));
+ }
+
+ GV->setInitializer(Init);
+ GV->setConstant(D->getType().isConstant(Context));
+ GV->setAlignment(getContext().getDeclAlignInBytes(D));
+
+ // Set the llvm linkage type as appropriate.
+ if (D->getStorageClass() == VarDecl::Static)
+ GV->setLinkage(llvm::Function::InternalLinkage);
+ else if (D->hasAttr<DLLImportAttr>())
+ GV->setLinkage(llvm::Function::DLLImportLinkage);
+ else if (D->hasAttr<DLLExportAttr>())
+ GV->setLinkage(llvm::Function::DLLExportLinkage);
+ else if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakImportAttr>())
+ GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
+ else if (!CompileOpts.NoCommon &&
+ (!D->hasExternalStorage() && !D->getInit()))
+ GV->setLinkage(llvm::GlobalVariable::CommonLinkage);
+ else
+ GV->setLinkage(llvm::GlobalVariable::ExternalLinkage);
+
+ SetCommonAttributes(D, GV);
+
+ // Emit global variable debug information.
+ if (CGDebugInfo *DI = getDebugInfo()) {
+ DI->setLocation(D->getLocation());
+ DI->EmitGlobalVariable(GV, D);
+ }
+}
+
+/// ReplaceUsesOfNonProtoTypeWithRealFunction - This function is called when we
+/// implement a function with no prototype, e.g. "int foo() {}". If there are
+/// existing call uses of the old function in the module, this adjusts them to
+/// call the new function directly.
+///
+/// This is not just a cleanup: the always_inline pass requires direct calls to
+/// functions to be able to inline them. If there is a bitcast in the way, it
+/// won't inline them. Instcombine normally deletes these calls, but it isn't
+/// run at -O0.
+static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
+ llvm::Function *NewFn) {
+ // If we're redefining a global as a function, don't transform it.
+ llvm::Function *OldFn = dyn_cast<llvm::Function>(Old);
+ if (OldFn == 0) return;
+
+ const llvm::Type *NewRetTy = NewFn->getReturnType();
+ llvm::SmallVector<llvm::Value*, 4> ArgList;
+
+ for (llvm::Value::use_iterator UI = OldFn->use_begin(), E = OldFn->use_end();
+ UI != E; ) {
+ // TODO: Do invokes ever occur in C code? If so, we should handle them too.
+ llvm::CallInst *CI = dyn_cast<llvm::CallInst>(*UI++);
+ if (!CI) continue;
+
+ // If the return types don't match exactly, and if the call isn't dead, then
+ // we can't transform this call.
+ if (CI->getType() != NewRetTy && !CI->use_empty())
+ continue;
+
+ // If the function was passed too few arguments, don't transform. If extra
+ // arguments were passed, we silently drop them. If any of the types
+ // mismatch, we don't transform.
+ unsigned ArgNo = 0;
+ bool DontTransform = false;
+ for (llvm::Function::arg_iterator AI = NewFn->arg_begin(),
+ E = NewFn->arg_end(); AI != E; ++AI, ++ArgNo) {
+ if (CI->getNumOperands()-1 == ArgNo ||
+ CI->getOperand(ArgNo+1)->getType() != AI->getType()) {
+ DontTransform = true;
+ break;
+ }
+ }
+ if (DontTransform)
+ continue;
+
+ // Okay, we can transform this. Create the new call instruction and copy
+ // over the required information.
+ ArgList.append(CI->op_begin()+1, CI->op_begin()+1+ArgNo);
+ llvm::CallInst *NewCall = llvm::CallInst::Create(NewFn, ArgList.begin(),
+ ArgList.end(), "", CI);
+ ArgList.clear();
+ if (NewCall->getType() != llvm::Type::VoidTy)
+ NewCall->takeName(CI);
+ NewCall->setCallingConv(CI->getCallingConv());
+ NewCall->setAttributes(CI->getAttributes());
+
+ // Finally, remove the old call, replacing any uses with the new one.
+ if (!CI->use_empty())
+ CI->replaceAllUsesWith(NewCall);
+ CI->eraseFromParent();
+ }
+}
+
+
+void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
+ const llvm::FunctionType *Ty;
+ const FunctionDecl *D = cast<FunctionDecl>(GD.getDecl());
+
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+ bool isVariadic = D->getType()->getAsFunctionProtoType()->isVariadic();
+
+ Ty = getTypes().GetFunctionType(getTypes().getFunctionInfo(MD), isVariadic);
+ } else {
+ Ty = cast<llvm::FunctionType>(getTypes().ConvertType(D->getType()));
+
+ // As a special case, make sure that definitions of K&R function
+ // "type foo()" aren't declared as varargs (which forces the backend
+ // to do unnecessary work).
+ if (D->getType()->isFunctionNoProtoType()) {
+ assert(Ty->isVarArg() && "Didn't lower type as expected");
+ // Due to stret, the lowered function could have arguments.
+ // Just create the same type as was lowered by ConvertType
+ // but strip off the varargs bit.
+ std::vector<const llvm::Type*> Args(Ty->param_begin(), Ty->param_end());
+ Ty = llvm::FunctionType::get(Ty->getReturnType(), Args, false);
+ }
+ }
+
+ // Get or create the prototype for the function.
+ llvm::Constant *Entry = GetAddrOfFunction(GD, Ty);
+
+ // Strip off a bitcast if we got one back.
+ if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(Entry)) {
+ assert(CE->getOpcode() == llvm::Instruction::BitCast);
+ Entry = CE->getOperand(0);
+ }
+
+
+ if (cast<llvm::GlobalValue>(Entry)->getType()->getElementType() != Ty) {
+ llvm::GlobalValue *OldFn = cast<llvm::GlobalValue>(Entry);
+
+ // If the types mismatch then we have to rewrite the definition.
+ assert(OldFn->isDeclaration() &&
+ "Shouldn't replace non-declaration");
+
+ // F is the Function* for the one with the wrong type, we must make a new
+ // Function* and update everything that used F (a declaration) with the new
+ // Function* (which will be a definition).
+ //
+ // This happens if there is a prototype for a function
+ // (e.g. "int f()") and then a definition of a different type
+ // (e.g. "int f(int x)"). Start by making a new function of the
+ // correct type, RAUW, then steal the name.
+ GlobalDeclMap.erase(getMangledName(D));
+ llvm::Function *NewFn = cast<llvm::Function>(GetAddrOfFunction(GD, Ty));
+ NewFn->takeName(OldFn);
+
+ // If this is an implementation of a function without a prototype, try to
+ // replace any existing uses of the function (which may be calls) with uses
+ // of the new function
+ if (D->getType()->isFunctionNoProtoType()) {
+ ReplaceUsesOfNonProtoTypeWithRealFunction(OldFn, NewFn);
+ OldFn->removeDeadConstantUsers();
+ }
+
+ // Replace uses of F with the Function we will endow with a body.
+ if (!Entry->use_empty()) {
+ llvm::Constant *NewPtrForOldDecl =
+ llvm::ConstantExpr::getBitCast(NewFn, Entry->getType());
+ Entry->replaceAllUsesWith(NewPtrForOldDecl);
+ }
+
+ // Ok, delete the old function now, which is dead.
+ OldFn->eraseFromParent();
+
+ Entry = NewFn;
+ }
+
+ llvm::Function *Fn = cast<llvm::Function>(Entry);
+
+ CodeGenFunction(*this).GenerateCode(D, Fn);
+
+ SetFunctionDefinitionAttributes(D, Fn);
+ SetLLVMFunctionAttributesForDefinition(D, Fn);
+
+ if (const ConstructorAttr *CA = D->getAttr<ConstructorAttr>())
+ AddGlobalCtor(Fn, CA->getPriority());
+ if (const DestructorAttr *DA = D->getAttr<DestructorAttr>())
+ AddGlobalDtor(Fn, DA->getPriority());
+}
+
+void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) {
+ const AliasAttr *AA = D->getAttr<AliasAttr>();
+ assert(AA && "Not an alias?");
+
+ const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType());
+
+ // Unique the name through the identifier table.
+ const char *AliaseeName = AA->getAliasee().c_str();
+ AliaseeName = getContext().Idents.get(AliaseeName).getName();
+
+ // Create a reference to the named value. This ensures that it is emitted
+ // if a deferred decl.
+ llvm::Constant *Aliasee;
+ if (isa<llvm::FunctionType>(DeclTy))
+ Aliasee = GetOrCreateLLVMFunction(AliaseeName, DeclTy, GlobalDecl());
+ else
+ Aliasee = GetOrCreateLLVMGlobal(AliaseeName,
+ llvm::PointerType::getUnqual(DeclTy), 0);
+
+ // Create the new alias itself, but don't set a name yet.
+ llvm::GlobalValue *GA =
+ new llvm::GlobalAlias(Aliasee->getType(),
+ llvm::Function::ExternalLinkage,
+ "", Aliasee, &getModule());
+
+ // See if there is already something with the alias' name in the module.
+ const char *MangledName = getMangledName(D);
+ llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
+
+ if (Entry && !Entry->isDeclaration()) {
+ // 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.
+ GA->eraseFromParent();
+ return;
+ }
+
+ if (Entry) {
+ // If there is a declaration in the module, then we had an extern followed
+ // by the alias, as in:
+ // extern int test6();
+ // ...
+ // int test6() __attribute__((alias("test7")));
+ //
+ // Remove it and replace uses of it with the alias.
+
+ Entry->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GA,
+ Entry->getType()));
+ Entry->eraseFromParent();
+ }
+
+ // Now we know that there is no conflict, set the name.
+ Entry = GA;
+ GA->setName(MangledName);
+
+ // Set attributes which are particular to an alias; this is a
+ // specialization of the attributes which may be set on a global
+ // variable/function.
+ if (D->hasAttr<DLLExportAttr>()) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // The dllexport attribute is ignored for undefined symbols.
+ if (FD->getBody(getContext()))
+ GA->setLinkage(llvm::Function::DLLExportLinkage);
+ } else {
+ GA->setLinkage(llvm::Function::DLLExportLinkage);
+ }
+ } else if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakImportAttr>()) {
+ GA->setLinkage(llvm::Function::WeakAnyLinkage);
+ }
+
+ SetCommonAttributes(D, GA);
+}
+
+/// getBuiltinLibFunction - Given a builtin id for a function like
+/// "__builtin_fabsf", return a Function* for "fabsf".
+llvm::Value *CodeGenModule::getBuiltinLibFunction(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).
+ const char *Name = Context.BuiltinInfo.GetName(BuiltinID);
+ if (Context.BuiltinInfo.isLibFunction(BuiltinID))
+ Name += 10;
+
+ // Get the type for the builtin.
+ Builtin::Context::GetBuiltinTypeError Error;
+ QualType Type = Context.BuiltinInfo.GetBuiltinType(BuiltinID, Context, Error);
+ assert(Error == Builtin::Context::GE_None && "Can't get builtin type");
+
+ const llvm::FunctionType *Ty =
+ cast<llvm::FunctionType>(getTypes().ConvertType(Type));
+
+ // Unique the name through the identifier table.
+ Name = getContext().Idents.get(Name).getName();
+ // FIXME: param attributes for sext/zext etc.
+ return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl());
+}
+
+llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,const llvm::Type **Tys,
+ unsigned NumTys) {
+ return llvm::Intrinsic::getDeclaration(&getModule(),
+ (llvm::Intrinsic::ID)IID, Tys, NumTys);
+}
+
+llvm::Function *CodeGenModule::getMemCpyFn() {
+ if (MemCpyFn) return MemCpyFn;
+ const llvm::Type *IntPtr = TheTargetData.getIntPtrType();
+ return MemCpyFn = getIntrinsic(llvm::Intrinsic::memcpy, &IntPtr, 1);
+}
+
+llvm::Function *CodeGenModule::getMemMoveFn() {
+ if (MemMoveFn) return MemMoveFn;
+ const llvm::Type *IntPtr = TheTargetData.getIntPtrType();
+ return MemMoveFn = getIntrinsic(llvm::Intrinsic::memmove, &IntPtr, 1);
+}
+
+llvm::Function *CodeGenModule::getMemSetFn() {
+ if (MemSetFn) return MemSetFn;
+ const llvm::Type *IntPtr = TheTargetData.getIntPtrType();
+ return MemSetFn = getIntrinsic(llvm::Intrinsic::memset, &IntPtr, 1);
+}
+
+static void appendFieldAndPadding(CodeGenModule &CGM,
+ std::vector<llvm::Constant*>& Fields,
+ FieldDecl *FieldD, FieldDecl *NextFieldD,
+ llvm::Constant* Field,
+ RecordDecl* RD, const llvm::StructType *STy) {
+ // Append the field.
+ Fields.push_back(Field);
+
+ int StructFieldNo = CGM.getTypes().getLLVMFieldNo(FieldD);
+
+ int NextStructFieldNo;
+ if (!NextFieldD) {
+ NextStructFieldNo = STy->getNumElements();
+ } else {
+ NextStructFieldNo = CGM.getTypes().getLLVMFieldNo(NextFieldD);
+ }
+
+ // Append padding
+ for (int i = StructFieldNo + 1; i < NextStructFieldNo; i++) {
+ llvm::Constant *C =
+ llvm::Constant::getNullValue(STy->getElementType(StructFieldNo + 1));
+
+ Fields.push_back(C);
+ }
+}
+
+llvm::Constant *CodeGenModule::
+GetAddrOfConstantCFString(const StringLiteral *Literal) {
+ std::string str;
+ unsigned StringLength = 0;
+
+ bool isUTF16 = false;
+ if (Literal->containsNonAsciiOrNull()) {
+ // Convert from UTF-8 to UTF-16.
+ llvm::SmallVector<UTF16, 128> ToBuf(Literal->getByteLength());
+ const UTF8 *FromPtr = (UTF8 *)Literal->getStrData();
+ UTF16 *ToPtr = &ToBuf[0];
+
+ ConversionResult Result;
+ Result = ConvertUTF8toUTF16(&FromPtr, FromPtr+Literal->getByteLength(),
+ &ToPtr, ToPtr+Literal->getByteLength(),
+ strictConversion);
+ if (Result == conversionOK) {
+ // FIXME: Storing UTF-16 in a C string is a hack to test Unicode strings
+ // without doing more surgery to this routine. Since we aren't explicitly
+ // checking for endianness here, it's also a bug (when generating code for
+ // a target that doesn't match the host endianness). Modeling this as an
+ // i16 array is likely the cleanest solution.
+ StringLength = ToPtr-&ToBuf[0];
+ str.assign((char *)&ToBuf[0], StringLength*2);// Twice as many UTF8 chars.
+ isUTF16 = true;
+ } else if (Result == sourceIllegal) {
+ // FIXME: Have Sema::CheckObjCString() validate the UTF-8 string.
+ str.assign(Literal->getStrData(), Literal->getByteLength());
+ StringLength = str.length();
+ } else
+ assert(Result == conversionOK && "UTF-8 to UTF-16 conversion failed");
+
+ } else {
+ str.assign(Literal->getStrData(), Literal->getByteLength());
+ StringLength = str.length();
+ }
+ llvm::StringMapEntry<llvm::Constant *> &Entry =
+ CFConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]);
+
+ if (llvm::Constant *C = Entry.getValue())
+ return C;
+
+ llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty);
+ llvm::Constant *Zeros[] = { Zero, Zero };
+
+ if (!CFConstantStringClassRef) {
+ const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
+ Ty = llvm::ArrayType::get(Ty, 0);
+
+ // FIXME: This is fairly broken if __CFConstantStringClassReference is
+ // already defined, in that it will get renamed and the user will most
+ // likely see an opaque error message. This is a general issue with relying
+ // on particular names.
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(Ty, false,
+ llvm::GlobalVariable::ExternalLinkage, 0,
+ "__CFConstantStringClassReference",
+ &getModule());
+
+ // Decay array -> ptr
+ CFConstantStringClassRef =
+ llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
+ }
+
+ QualType CFTy = getContext().getCFConstantStringType();
+ RecordDecl *CFRD = CFTy->getAsRecordType()->getDecl();
+
+ const llvm::StructType *STy =
+ cast<llvm::StructType>(getTypes().ConvertType(CFTy));
+
+ std::vector<llvm::Constant*> Fields;
+ RecordDecl::field_iterator Field = CFRD->field_begin(getContext());
+
+ // Class pointer.
+ FieldDecl *CurField = *Field++;
+ FieldDecl *NextField = *Field++;
+ appendFieldAndPadding(*this, Fields, CurField, NextField,
+ CFConstantStringClassRef, CFRD, STy);
+
+ // Flags.
+ CurField = NextField;
+ NextField = *Field++;
+ const llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy);
+ appendFieldAndPadding(*this, Fields, CurField, NextField,
+ isUTF16 ? llvm::ConstantInt::get(Ty, 0x07d0)
+ : llvm::ConstantInt::get(Ty, 0x07C8),
+ CFRD, STy);
+
+ // String pointer.
+ CurField = NextField;
+ NextField = *Field++;
+ llvm::Constant *C = llvm::ConstantArray::get(str);
+
+ const char *Sect, *Prefix;
+ bool isConstant;
+ if (isUTF16) {
+ Prefix = getContext().Target.getUnicodeStringSymbolPrefix();
+ Sect = getContext().Target.getUnicodeStringSection();
+ // FIXME: Why does GCC not set constant here?
+ isConstant = false;
+ } else {
+ Prefix = getContext().Target.getStringSymbolPrefix(true);
+ Sect = getContext().Target.getCFStringDataSection();
+ // FIXME: -fwritable-strings should probably affect this, but we
+ // are following gcc here.
+ isConstant = true;
+ }
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(C->getType(), isConstant,
+ llvm::GlobalValue::InternalLinkage,
+ C, Prefix, &getModule());
+ if (Sect)
+ GV->setSection(Sect);
+ if (isUTF16) {
+ unsigned Align = getContext().getTypeAlign(getContext().ShortTy)/8;
+ GV->setAlignment(Align);
+ }
+ appendFieldAndPadding(*this, Fields, CurField, NextField,
+ llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2),
+ CFRD, STy);
+
+ // String length.
+ CurField = NextField;
+ NextField = 0;
+ Ty = getTypes().ConvertType(getContext().LongTy);
+ appendFieldAndPadding(*this, Fields, CurField, NextField,
+ llvm::ConstantInt::get(Ty, StringLength), CFRD, STy);
+
+ // The struct.
+ C = llvm::ConstantStruct::get(STy, Fields);
+ GV = new llvm::GlobalVariable(C->getType(), true,
+ llvm::GlobalVariable::InternalLinkage, C,
+ getContext().Target.getCFStringSymbolPrefix(),
+ &getModule());
+ if (const char *Sect = getContext().Target.getCFStringSection())
+ GV->setSection(Sect);
+ Entry.setValue(GV);
+
+ return GV;
+}
+
+/// GetStringForStringLiteral - Return the appropriate bytes for a
+/// string literal, properly padded to match the literal type.
+std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) {
+ const char *StrData = E->getStrData();
+ unsigned Len = E->getByteLength();
+
+ const ConstantArrayType *CAT =
+ getContext().getAsConstantArrayType(E->getType());
+ assert(CAT && "String isn't pointer or array!");
+
+ // Resize the string to the right size.
+ std::string Str(StrData, StrData+Len);
+ uint64_t RealLen = CAT->getSize().getZExtValue();
+
+ if (E->isWide())
+ RealLen *= getContext().Target.getWCharWidth()/8;
+
+ Str.resize(RealLen, '\0');
+
+ return Str;
+}
+
+/// GetAddrOfConstantStringFromLiteral - Return a pointer to a
+/// constant array for the given string literal.
+llvm::Constant *
+CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) {
+ // FIXME: This can be more efficient.
+ return GetAddrOfConstantString(GetStringForStringLiteral(S));
+}
+
+/// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant
+/// array for the given ObjCEncodeExpr node.
+llvm::Constant *
+CodeGenModule::GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *E) {
+ std::string Str;
+ getContext().getObjCEncodingForType(E->getEncodedType(), Str);
+
+ return GetAddrOfConstantCString(Str);
+}
+
+
+/// GenerateWritableString -- Creates storage for a string literal.
+static llvm::Constant *GenerateStringLiteral(const std::string &str,
+ bool constant,
+ CodeGenModule &CGM,
+ const char *GlobalName) {
+ // Create Constant for this string literal. Don't add a '\0'.
+ llvm::Constant *C = llvm::ConstantArray::get(str, false);
+
+ // Create a global variable for this string
+ return new llvm::GlobalVariable(C->getType(), constant,
+ llvm::GlobalValue::InternalLinkage,
+ C, GlobalName, &CGM.getModule());
+}
+
+/// GetAddrOfConstantString - Returns a pointer to a character array
+/// containing the literal. This contents are exactly that of the
+/// given string, i.e. it will not be null terminated automatically;
+/// see GetAddrOfConstantCString. Note that whether the result is
+/// actually a pointer to an LLVM constant depends on
+/// Feature.WriteableStrings.
+///
+/// The result has pointer to array type.
+llvm::Constant *CodeGenModule::GetAddrOfConstantString(const std::string &str,
+ const char *GlobalName) {
+ bool IsConstant = !Features.WritableStrings;
+
+ // Get the default prefix if a name wasn't specified.
+ if (!GlobalName)
+ GlobalName = getContext().Target.getStringSymbolPrefix(IsConstant);
+
+ // Don't share any string literals if strings aren't constant.
+ if (!IsConstant)
+ return GenerateStringLiteral(str, false, *this, GlobalName);
+
+ llvm::StringMapEntry<llvm::Constant *> &Entry =
+ ConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]);
+
+ if (Entry.getValue())
+ return Entry.getValue();
+
+ // Create a global variable for this.
+ llvm::Constant *C = GenerateStringLiteral(str, true, *this, GlobalName);
+ Entry.setValue(C);
+ return C;
+}
+
+/// GetAddrOfConstantCString - Returns a pointer to a character
+/// array containing the literal and a terminating '\-'
+/// character. The result has pointer to array type.
+llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &str,
+ const char *GlobalName){
+ return GetAddrOfConstantString(str + '\0', GlobalName);
+}
+
+/// EmitObjCPropertyImplementations - Emit information for synthesized
+/// properties for an implementation.
+void CodeGenModule::EmitObjCPropertyImplementations(const
+ ObjCImplementationDecl *D) {
+ for (ObjCImplementationDecl::propimpl_iterator
+ i = D->propimpl_begin(getContext()),
+ e = D->propimpl_end(getContext()); i != e; ++i) {
+ ObjCPropertyImplDecl *PID = *i;
+
+ // Dynamic is just for type-checking.
+ if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
+ ObjCPropertyDecl *PD = PID->getPropertyDecl();
+
+ // Determine which methods need to be implemented, some may have
+ // been overridden. Note that ::isSynthesized is not the method
+ // we want, that just indicates if the decl came from a
+ // property. What we want to know is if the method is defined in
+ // this implementation.
+ if (!D->getInstanceMethod(getContext(), PD->getGetterName()))
+ CodeGenFunction(*this).GenerateObjCGetter(
+ const_cast<ObjCImplementationDecl *>(D), PID);
+ if (!PD->isReadOnly() &&
+ !D->getInstanceMethod(getContext(), PD->getSetterName()))
+ CodeGenFunction(*this).GenerateObjCSetter(
+ const_cast<ObjCImplementationDecl *>(D), PID);
+ }
+ }
+}
+
+/// EmitNamespace - Emit all declarations in a namespace.
+void CodeGenModule::EmitNamespace(const NamespaceDecl *ND) {
+ for (RecordDecl::decl_iterator I = ND->decls_begin(getContext()),
+ E = ND->decls_end(getContext());
+ I != E; ++I)
+ EmitTopLevelDecl(*I);
+}
+
+// EmitLinkageSpec - Emit all declarations in a linkage spec.
+void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) {
+ if (LSD->getLanguage() != LinkageSpecDecl::lang_c) {
+ ErrorUnsupported(LSD, "linkage spec");
+ return;
+ }
+
+ for (RecordDecl::decl_iterator I = LSD->decls_begin(getContext()),
+ E = LSD->decls_end(getContext());
+ I != E; ++I)
+ EmitTopLevelDecl(*I);
+}
+
+/// EmitTopLevelDecl - Emit code for a single top level declaration.
+void CodeGenModule::EmitTopLevelDecl(Decl *D) {
+ // If an error has occurred, stop code generation, but continue
+ // parsing and semantic analysis (to ensure all warnings and errors
+ // are emitted).
+ if (Diags.hasErrorOccurred())
+ return;
+
+ switch (D->getKind()) {
+ case Decl::CXXMethod:
+ case Decl::Function:
+ case Decl::Var:
+ EmitGlobal(GlobalDecl(cast<ValueDecl>(D)));
+ break;
+
+ // C++ Decls
+ case Decl::Namespace:
+ EmitNamespace(cast<NamespaceDecl>(D));
+ break;
+ case Decl::CXXConstructor:
+ EmitCXXConstructors(cast<CXXConstructorDecl>(D));
+ break;
+ case Decl::CXXDestructor:
+ EmitCXXDestructors(cast<CXXDestructorDecl>(D));
+ break;
+
+ // Objective-C Decls
+
+ // Forward declarations, no (immediate) code generation.
+ case Decl::ObjCClass:
+ case Decl::ObjCForwardProtocol:
+ case Decl::ObjCCategory:
+ case Decl::ObjCInterface:
+ break;
+
+ case Decl::ObjCProtocol:
+ Runtime->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));
+ break;
+
+ case Decl::ObjCImplementation: {
+ ObjCImplementationDecl *OMD = cast<ObjCImplementationDecl>(D);
+ EmitObjCPropertyImplementations(OMD);
+ Runtime->GenerateClass(OMD);
+ break;
+ }
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(D);
+ // If this is not a prototype, emit the body.
+ if (OMD->getBody(getContext()))
+ CodeGenFunction(*this).GenerateObjCMethod(OMD);
+ break;
+ }
+ case Decl::ObjCCompatibleAlias:
+ // compatibility-alias is a directive and has no code gen.
+ break;
+
+ case Decl::LinkageSpec:
+ EmitLinkageSpec(cast<LinkageSpecDecl>(D));
+ break;
+
+ case Decl::FileScopeAsm: {
+ FileScopeAsmDecl *AD = cast<FileScopeAsmDecl>(D);
+ std::string AsmString(AD->getAsmString()->getStrData(),
+ AD->getAsmString()->getByteLength());
+
+ const std::string &S = getModule().getModuleInlineAsm();
+ if (S.empty())
+ getModule().setModuleInlineAsm(AsmString);
+ else
+ getModule().setModuleInlineAsm(S + '\n' + AsmString);
+ break;
+ }
+
+ default:
+ // Make sure we handled everything we should, every other kind is a
+ // non-top-level decl. FIXME: Would be nice to have an isTopLevelDeclKind
+ // function. Need to recode Decl::Kind to do that easily.
+ assert(isa<TypeDecl>(D) && "Unsupported decl kind");
+ }
+}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
new file mode 100644
index 000000000000..4d50e8946bd6
--- /dev/null
+++ b/lib/CodeGen/CodeGenModule.h
@@ -0,0 +1,467 @@
+//===--- CodeGenModule.h - Per-Module state for LLVM CodeGen ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the internal per-translation-unit state used for llvm translation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CODEGENMODULE_H
+#define CLANG_CODEGEN_CODEGENMODULE_H
+
+#include "clang/Basic/LangOptions.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclCXX.h"
+#include "CGBlocks.h"
+#include "CGCall.h"
+#include "CGCXX.h"
+#include "CodeGenTypes.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/ValueHandle.h"
+#include <list>
+
+namespace llvm {
+ class Module;
+ class Constant;
+ class Function;
+ class GlobalValue;
+ class TargetData;
+ class FunctionType;
+}
+
+namespace clang {
+ class ASTContext;
+ class FunctionDecl;
+ class IdentifierInfo;
+ class ObjCMethodDecl;
+ class ObjCImplementationDecl;
+ class ObjCCategoryImplDecl;
+ class ObjCProtocolDecl;
+ class ObjCEncodeExpr;
+ class BlockExpr;
+ class Decl;
+ class Expr;
+ class Stmt;
+ class StringLiteral;
+ class NamedDecl;
+ class ValueDecl;
+ class VarDecl;
+ class LangOptions;
+ class CompileOptions;
+ class Diagnostic;
+ class AnnotateAttr;
+ class CXXDestructorDecl;
+
+namespace CodeGen {
+
+ class CodeGenFunction;
+ class CGDebugInfo;
+ class CGObjCRuntime;
+
+/// GlobalDecl - represents a global declaration. This can either be a
+/// CXXConstructorDecl and the constructor type (Base, Complete).
+/// a CXXDestructorDecl and the destructor type (Base, Complete) or
+// a regular VarDecl or a FunctionDecl.
+class GlobalDecl {
+ llvm::PointerIntPair<const ValueDecl*, 2> Value;
+
+public:
+ GlobalDecl() {}
+
+ explicit GlobalDecl(const ValueDecl *VD) : Value(VD, 0) {
+ assert(!isa<CXXConstructorDecl>(VD) && "Use other ctor with ctor decls!");
+ assert(!isa<CXXDestructorDecl>(VD) && "Use other ctor with dtor decls!");
+ }
+ GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type)
+ : Value(D, Type) {}
+ GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type)
+ : Value(D, Type) {}
+
+ const ValueDecl *getDecl() const { return Value.getPointer(); }
+
+ CXXCtorType getCtorType() const {
+ assert(isa<CXXConstructorDecl>(getDecl()) && "Decl is not a ctor!");
+ return static_cast<CXXCtorType>(Value.getInt());
+ }
+
+ CXXDtorType getDtorType() const {
+ assert(isa<CXXDestructorDecl>(getDecl()) && "Decl is not a dtor!");
+ return static_cast<CXXDtorType>(Value.getInt());
+ }
+};
+
+/// CodeGenModule - This class organizes the cross-function state that is used
+/// while generating LLVM code.
+class CodeGenModule : public BlockModule {
+ CodeGenModule(const CodeGenModule&); // DO NOT IMPLEMENT
+ void operator=(const CodeGenModule&); // DO NOT IMPLEMENT
+
+ typedef std::vector< std::pair<llvm::Constant*, int> > CtorList;
+
+ ASTContext &Context;
+ const LangOptions &Features;
+ const CompileOptions &CompileOpts;
+ llvm::Module &TheModule;
+ const llvm::TargetData &TheTargetData;
+ Diagnostic &Diags;
+ CodeGenTypes Types;
+ CGObjCRuntime* Runtime;
+ CGDebugInfo* DebugInfo;
+
+ llvm::Function *MemCpyFn;
+ llvm::Function *MemMoveFn;
+ llvm::Function *MemSetFn;
+
+ /// GlobalDeclMap - Mapping of decl names (represented as unique
+ /// character pointers from either the identifier table or the set
+ /// of mangled names) to global variables we have already
+ /// emitted. Note that the entries in this map are the actual
+ /// globals and therefore may not be of the same type as the decl,
+ /// they should be bitcasted on retrieval. Also note that the
+ /// globals are keyed on their source mangled name, not the global name
+ /// (which may change with attributes such as asm-labels). The key
+ /// to this map should be generated using getMangledName().
+ ///
+ /// Note that this map always lines up exactly with the contents of the LLVM
+ /// IR symbol table, but this is quicker to query since it is doing uniqued
+ /// pointer lookups instead of full string lookups.
+ llvm::DenseMap<const char*, llvm::GlobalValue*> GlobalDeclMap;
+
+ /// \brief Contains the strings used for mangled names.
+ ///
+ /// FIXME: Eventually, this should map from the semantic/canonical
+ /// declaration for each global entity to its mangled name (if it
+ /// has one).
+ llvm::StringSet<> MangledNames;
+
+ /// DeferredDecls - This contains all the decls which have definitions but
+ /// which are deferred for emission and therefore should only be output if
+ /// they are actually used. If a decl is in this, then it is known to have
+ /// not been referenced yet. The key to this map is a uniqued mangled name.
+ llvm::DenseMap<const char*, GlobalDecl> DeferredDecls;
+
+ /// DeferredDeclsToEmit - This is a list of deferred decls which we have seen
+ /// that *are* actually referenced. These get code generated when the module
+ /// is done.
+ std::vector<GlobalDecl> DeferredDeclsToEmit;
+
+ /// LLVMUsed - List of global values which are required to be
+ /// present in the object file; bitcast to i8*. This is used for
+ /// forcing visibility of symbols which may otherwise be optimized
+ /// out.
+ std::vector<llvm::WeakVH> LLVMUsed;
+
+ /// GlobalCtors - Store the list of global constructors and their respective
+ /// priorities to be emitted when the translation unit is complete.
+ CtorList GlobalCtors;
+
+ /// GlobalDtors - Store the list of global destructors and their respective
+ /// priorities to be emitted when the translation unit is complete.
+ CtorList GlobalDtors;
+
+ std::vector<llvm::Constant*> Annotations;
+
+ llvm::StringMap<llvm::Constant*> CFConstantStringMap;
+ llvm::StringMap<llvm::Constant*> ConstantStringMap;
+
+ /// 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;
+public:
+ CodeGenModule(ASTContext &C, const CompileOptions &CompileOpts,
+ llvm::Module &M, const llvm::TargetData &TD, Diagnostic &Diags);
+
+ ~CodeGenModule();
+
+ /// Release - Finalize LLVM code generation.
+ void Release();
+
+ /// getObjCRuntime() - Return a reference to the configured
+ /// Objective-C runtime.
+ CGObjCRuntime &getObjCRuntime() {
+ assert(Runtime && "No Objective-C runtime has been configured.");
+ return *Runtime;
+ }
+
+ /// hasObjCRuntime() - Return true iff an Objective-C runtime has
+ /// been configured.
+ bool hasObjCRuntime() { return !!Runtime; }
+
+ CGDebugInfo *getDebugInfo() { return DebugInfo; }
+ ASTContext &getContext() const { return Context; }
+ const CompileOptions &getCompileOpts() const { return CompileOpts; }
+ const LangOptions &getLangOptions() const { return Features; }
+ llvm::Module &getModule() const { return TheModule; }
+ CodeGenTypes &getTypes() { return Types; }
+ Diagnostic &getDiags() const { return Diags; }
+ const llvm::TargetData &getTargetData() const { return TheTargetData; }
+
+ /// getDeclVisibilityMode - Compute the visibility of the decl \arg D.
+ LangOptions::VisibilityMode getDeclVisibilityMode(const Decl *D) const;
+
+ /// setGlobalVisibility - Set the visibility for the given LLVM
+ /// GlobalValue.
+ void setGlobalVisibility(llvm::GlobalValue *GV, const Decl *D) const;
+
+ /// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the
+ /// given global variable. If Ty is non-null and if the global doesn't exist,
+ /// 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);
+
+ /// 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);
+
+ /// GetStringForStringLiteral - Return the appropriate bytes for a string
+ /// literal, properly padded to match the literal type. If only the address of
+ /// a constant is needed consider using GetAddrOfConstantStringLiteral.
+ std::string GetStringForStringLiteral(const StringLiteral *E);
+
+ /// GetAddrOfConstantCFString - Return a pointer to a constant CFString object
+ /// for the given string.
+ llvm::Constant *GetAddrOfConstantCFString(const StringLiteral *Literal);
+
+ /// GetAddrOfConstantStringFromLiteral - Return a pointer to a constant array
+ /// for the given string literal.
+ llvm::Constant *GetAddrOfConstantStringFromLiteral(const StringLiteral *S);
+
+ /// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant
+ /// array for the given ObjCEncodeExpr node.
+ llvm::Constant *GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *);
+
+ /// GetAddrOfConstantString - Returns a pointer to a character array
+ /// containing the literal. This contents are exactly that of the given
+ /// string, i.e. it will not be null terminated automatically; see
+ /// GetAddrOfConstantCString. Note that whether the result is actually a
+ /// pointer to an LLVM constant depends on Feature.WriteableStrings.
+ ///
+ /// The result has pointer to array type.
+ ///
+ /// \param GlobalName If provided, the name to use for the global
+ /// (if one is created).
+ llvm::Constant *GetAddrOfConstantString(const std::string& str,
+ const char *GlobalName=0);
+
+ /// GetAddrOfConstantCString - Returns a pointer to a character array
+ /// containing the literal and a terminating '\0' character. The result has
+ /// pointer to array type.
+ ///
+ /// \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);
+
+ /// GetAddrOfCXXConstructor - Return the address of the constructor of the
+ /// given type.
+ llvm::Function *GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
+ CXXCtorType Type);
+
+ /// GetAddrOfCXXDestructor - Return the address of the constructor of the
+ /// given type.
+ llvm::Function *GetAddrOfCXXDestructor(const CXXDestructorDecl *D,
+ CXXDtorType Type);
+
+ /// getBuiltinLibFunction - Given a builtin id for a function like
+ /// "__builtin_fabsf", return a Function* for "fabsf".
+ llvm::Value *getBuiltinLibFunction(unsigned BuiltinID);
+
+ llvm::Function *getMemCpyFn();
+ llvm::Function *getMemMoveFn();
+ llvm::Function *getMemSetFn();
+ llvm::Function *getIntrinsic(unsigned IID, const llvm::Type **Tys = 0,
+ unsigned NumTys = 0);
+
+ /// EmitTopLevelDecl - Emit code for a single top level declaration.
+ void EmitTopLevelDecl(Decl *D);
+
+ /// AddUsedGlobal - Add a global which should be forced to be
+ /// present in the object file; these are emitted to the llvm.used
+ /// metadata global.
+ void AddUsedGlobal(llvm::GlobalValue *GV);
+
+ void AddAnnotation(llvm::Constant *C) { Annotations.push_back(C); }
+
+ /// CreateRuntimeFunction - Create a new runtime function with the specified
+ /// type and name.
+ llvm::Constant *CreateRuntimeFunction(const llvm::FunctionType *Ty,
+ const char *Name);
+ /// CreateRuntimeVariable - Create a new runtime global variable with the
+ /// specified type and name.
+ llvm::Constant *CreateRuntimeVariable(const llvm::Type *Ty,
+ const char *Name);
+
+ void UpdateCompletedType(const TagDecl *TD) {
+ // Make sure that this type is translated.
+ Types.UpdateCompletedType(TD);
+ }
+
+ /// EmitConstantExpr - Try to emit the given expression as a
+ /// constant; returns 0 if the expression cannot be emitted as a
+ /// constant.
+ llvm::Constant *EmitConstantExpr(const Expr *E, QualType DestType,
+ CodeGenFunction *CGF = 0);
+
+ /// EmitNullConstant - Return the result of value-initializing the given
+ /// type, i.e. a null expression of the given type. This is usually,
+ /// but not always, an LLVM null constant.
+ llvm::Constant *EmitNullConstant(QualType T);
+
+ llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV,
+ const AnnotateAttr *AA, unsigned LineNo);
+
+ /// ErrorUnsupported - Print out an error that codegen doesn't support the
+ /// specified stmt yet.
+ /// \param OmitOnError - If true, then this error should only be emitted if no
+ /// other errors have been reported.
+ void ErrorUnsupported(const Stmt *S, const char *Type,
+ bool OmitOnError=false);
+
+ /// ErrorUnsupported - Print out an error that codegen doesn't support the
+ /// specified decl yet.
+ /// \param OmitOnError - If true, then this error should only be emitted if no
+ /// other errors have been reported.
+ void ErrorUnsupported(const Decl *D, const char *Type,
+ bool OmitOnError=false);
+
+ /// SetInternalFunctionAttributes - Set the attributes on the LLVM
+ /// function for the given decl and function info. This applies
+ /// attributes necessary for handling the ABI as well as user
+ /// specified attributes like section.
+ void SetInternalFunctionAttributes(const Decl *D, llvm::Function *F,
+ const CGFunctionInfo &FI);
+
+ /// SetLLVMFunctionAttributes - Set the LLVM function attributes
+ /// (sext, zext, etc).
+ void SetLLVMFunctionAttributes(const Decl *D,
+ const CGFunctionInfo &Info,
+ llvm::Function *F);
+
+ /// SetLLVMFunctionAttributesForDefinition - Set the LLVM function attributes
+ /// which only apply to a function definintion.
+ void SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F);
+
+ /// ReturnTypeUsesSret - Return true iff the given type uses 'sret' when used
+ /// as a return type.
+ bool ReturnTypeUsesSret(const CGFunctionInfo &FI);
+
+ void ConstructAttributeList(const CGFunctionInfo &Info,
+ const Decl *TargetDecl,
+ AttributeListType &PAL);
+
+ const char *getMangledName(const GlobalDecl &D);
+
+ const char *getMangledName(const NamedDecl *ND);
+ const char *getMangledCXXCtorName(const CXXConstructorDecl *D,
+ CXXCtorType Type);
+ const char *getMangledCXXDtorName(const CXXDestructorDecl *D,
+ CXXDtorType Type);
+
+ void EmitTentativeDefinition(const VarDecl *D);
+
+ enum GVALinkage {
+ GVA_Internal,
+ GVA_C99Inline,
+ GVA_CXXInline,
+ GVA_StrongExternal
+ };
+
+private:
+ /// UniqueMangledName - Unique a name by (if necessary) inserting it into the
+ /// MangledNames string map.
+ const char *UniqueMangledName(const char *NameStart, const char *NameEnd);
+
+ llvm::Constant *GetOrCreateLLVMFunction(const char *MangledName,
+ const llvm::Type *Ty,
+ GlobalDecl D);
+ llvm::Constant *GetOrCreateLLVMGlobal(const char *MangledName,
+ const llvm::PointerType *PTy,
+ const VarDecl *D);
+
+ /// SetCommonAttributes - Set attributes which are common to any
+ /// form of a global definition (alias, Objective-C method,
+ /// function, global variable).
+ ///
+ /// NOTE: This should only be called for definitions.
+ void SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV);
+
+ /// SetFunctionDefinitionAttributes - Set attributes for a global definition.
+ void SetFunctionDefinitionAttributes(const FunctionDecl *D,
+ llvm::GlobalValue *GV);
+
+ /// SetFunctionAttributes - Set function attributes for a function
+ /// declaration.
+ void SetFunctionAttributes(const FunctionDecl *FD,
+ llvm::Function *F,
+ bool IsIncompleteFunction);
+
+ /// EmitGlobal - Emit code for a singal global function or var decl. Forward
+ /// declarations are emitted lazily.
+ void EmitGlobal(GlobalDecl D);
+
+ void EmitGlobalDefinition(GlobalDecl D);
+
+ void EmitGlobalFunctionDefinition(GlobalDecl GD);
+ void EmitGlobalVarDefinition(const VarDecl *D);
+ void EmitAliasDefinition(const ValueDecl *D);
+ void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
+
+ // C++ related functions.
+
+ void EmitNamespace(const NamespaceDecl *D);
+ void EmitLinkageSpec(const LinkageSpecDecl *D);
+
+ /// EmitCXXConstructors - Emit constructors (base, complete) from a
+ /// C++ constructor Decl.
+ void EmitCXXConstructors(const CXXConstructorDecl *D);
+
+ /// EmitCXXConstructor - Emit a single constructor with the given type from
+ /// a C++ constructor Decl.
+ void EmitCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type);
+
+ /// EmitCXXDestructors - Emit destructors (base, complete) from a
+ /// C++ destructor Decl.
+ void EmitCXXDestructors(const CXXDestructorDecl *D);
+
+ /// EmitCXXDestructor - Emit a single destructor with the given type from
+ /// a C++ destructor Decl.
+ void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type);
+
+ // FIXME: Hardcoding priority here is gross.
+ void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535);
+ void AddGlobalDtor(llvm::Function *Dtor, int Priority=65535);
+
+ /// EmitCtorList - Generates a global array of functions and priorities using
+ /// the given list and name. This array will have appending linkage and is
+ /// suitable for use as a LLVM constructor or destructor array.
+ void EmitCtorList(const CtorList &Fns, const char *GlobalName);
+
+ void EmitAnnotations(void);
+
+ /// EmitDeferred - Emit any needed decls for which code generation
+ /// was deferred.
+ void EmitDeferred(void);
+
+ /// EmitLLVMUsed - Emit the llvm.used metadata used to force
+ /// references to global which may otherwise be optimized out.
+ void EmitLLVMUsed(void);
+
+ /// MayDeferGeneration - Determine if the given decl can be emitted
+ /// lazily; this is only relevant for definitions. The given decl
+ /// must be either a function or var decl.
+ bool MayDeferGeneration(const ValueDecl *D);
+};
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
new file mode 100644
index 000000000000..af791f63186c
--- /dev/null
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -0,0 +1,614 @@
+//===--- CodeGenTypes.cpp - Type translation for LLVM CodeGen -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the code that handles AST -> LLVM type lowering.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenTypes.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/RecordLayout.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Module.h"
+#include "llvm/Target/TargetData.h"
+
+#include "CGCall.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+namespace {
+ /// RecordOrganizer - This helper class, used by CGRecordLayout, layouts
+ /// structs and unions. It manages transient information used during layout.
+ /// FIXME : Handle field aligments. Handle packed structs.
+ class RecordOrganizer {
+ public:
+ explicit RecordOrganizer(CodeGenTypes &Types, const RecordDecl& Record) :
+ CGT(Types), RD(Record), STy(NULL) {}
+
+ /// layoutStructFields - Do the actual work and lay out all fields. Create
+ /// corresponding llvm struct type. This should be invoked only after
+ /// all fields are added.
+ void layoutStructFields(const ASTRecordLayout &RL);
+
+ /// layoutUnionFields - Do the actual work and lay out all fields. Create
+ /// corresponding llvm struct type. This should be invoked only after
+ /// all fields are added.
+ void layoutUnionFields(const ASTRecordLayout &RL);
+
+ /// getLLVMType - Return associated llvm struct type. This may be NULL
+ /// if fields are not laid out.
+ llvm::Type *getLLVMType() const {
+ return STy;
+ }
+
+ llvm::SmallSet<unsigned, 8> &getPaddingFields() {
+ return PaddingFields;
+ }
+
+ private:
+ CodeGenTypes &CGT;
+ const RecordDecl& RD;
+ llvm::Type *STy;
+ llvm::SmallSet<unsigned, 8> PaddingFields;
+ };
+}
+
+CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M,
+ const llvm::TargetData &TD)
+ : Context(Ctx), Target(Ctx.Target), TheModule(M), TheTargetData(TD),
+ TheABIInfo(0) {
+}
+
+CodeGenTypes::~CodeGenTypes() {
+ for(llvm::DenseMap<const Type *, CGRecordLayout *>::iterator
+ I = CGRecordLayouts.begin(), E = CGRecordLayouts.end();
+ I != E; ++I)
+ delete I->second;
+ CGRecordLayouts.clear();
+}
+
+/// ConvertType - Convert the specified type to its LLVM form.
+const llvm::Type *CodeGenTypes::ConvertType(QualType T) {
+ llvm::PATypeHolder Result = ConvertTypeRecursive(T);
+
+ // Any pointers that were converted defered evaluation of their pointee type,
+ // creating an opaque type instead. This is in order to avoid problems with
+ // circular types. Loop through all these defered pointees, if any, and
+ // resolve them now.
+ while (!PointersToResolve.empty()) {
+ std::pair<QualType, llvm::OpaqueType*> P =
+ PointersToResolve.back();
+ PointersToResolve.pop_back();
+ // We can handle bare pointers here because we know that the only pointers
+ // to the Opaque type are P.second and from other types. Refining the
+ // opqaue type away will invalidate P.second, but we don't mind :).
+ const llvm::Type *NT = ConvertTypeForMemRecursive(P.first);
+ P.second->refineAbstractTypeTo(NT);
+ }
+
+ return Result;
+}
+
+const llvm::Type *CodeGenTypes::ConvertTypeRecursive(QualType T) {
+ T = Context.getCanonicalType(T);
+
+ // See if type is already cached.
+ llvm::DenseMap<Type *, llvm::PATypeHolder>::iterator
+ I = TypeCache.find(T.getTypePtr());
+ // If type is found in map and this is not a definition for a opaque
+ // place holder type then use it. Otherwise, convert type T.
+ if (I != TypeCache.end())
+ return I->second.get();
+
+ const llvm::Type *ResultType = ConvertNewType(T);
+ TypeCache.insert(std::make_pair(T.getTypePtr(),
+ llvm::PATypeHolder(ResultType)));
+ return ResultType;
+}
+
+const llvm::Type *CodeGenTypes::ConvertTypeForMemRecursive(QualType T) {
+ const llvm::Type *ResultType = ConvertTypeRecursive(T);
+ if (ResultType == llvm::Type::Int1Ty)
+ return llvm::IntegerType::get((unsigned)Context.getTypeSize(T));
+ return ResultType;
+}
+
+/// ConvertTypeForMem - Convert type T into a llvm::Type. This differs from
+/// ConvertType in that it is used to convert to the memory representation for
+/// a type. For example, the scalar representation for _Bool is i1, but the
+/// memory representation is usually i8 or i32, depending on the target.
+const llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) {
+ const llvm::Type *R = ConvertType(T);
+
+ // If this is a non-bool type, don't map it.
+ if (R != llvm::Type::Int1Ty)
+ return R;
+
+ // Otherwise, return an integer of the target-specified size.
+ return llvm::IntegerType::get((unsigned)Context.getTypeSize(T));
+
+}
+
+// Code to verify a given function type is complete, i.e. the return type
+// and all of the argument types are complete.
+static const TagType *VerifyFuncTypeComplete(const Type* T) {
+ const FunctionType *FT = cast<FunctionType>(T);
+ if (const TagType* TT = FT->getResultType()->getAsTagType())
+ if (!TT->getDecl()->isDefinition())
+ return TT;
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(T))
+ for (unsigned i = 0; i < FPT->getNumArgs(); i++)
+ if (const TagType* TT = FPT->getArgType(i)->getAsTagType())
+ if (!TT->getDecl()->isDefinition())
+ return TT;
+ return 0;
+}
+
+/// UpdateCompletedType - When we find the full definition for a TagDecl,
+/// replace the 'opaque' type we previously made for it if applicable.
+void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) {
+ const Type *Key =
+ Context.getTagDeclType(const_cast<TagDecl*>(TD)).getTypePtr();
+ llvm::DenseMap<const Type*, llvm::PATypeHolder>::iterator TDTI =
+ TagDeclTypes.find(Key);
+ if (TDTI == TagDeclTypes.end()) return;
+
+ // Remember the opaque LLVM type for this tagdecl.
+ llvm::PATypeHolder OpaqueHolder = TDTI->second;
+ assert(isa<llvm::OpaqueType>(OpaqueHolder.get()) &&
+ "Updating compilation of an already non-opaque type?");
+
+ // Remove it from TagDeclTypes so that it will be regenerated.
+ TagDeclTypes.erase(TDTI);
+
+ // Generate the new type.
+ const llvm::Type *NT = ConvertTagDeclType(TD);
+
+ // Refine the old opaque type to its new definition.
+ cast<llvm::OpaqueType>(OpaqueHolder.get())->refineAbstractTypeTo(NT);
+
+ // Since we just completed a tag type, check to see if any function types
+ // were completed along with the tag type.
+ // FIXME: This is very inefficient; if we track which function types depend
+ // on which tag types, though, it should be reasonably efficient.
+ llvm::DenseMap<const Type*, llvm::PATypeHolder>::iterator i;
+ for (i = FunctionTypes.begin(); i != FunctionTypes.end(); ++i) {
+ if (const TagType* TT = VerifyFuncTypeComplete(i->first)) {
+ // This function type still depends on an incomplete tag type; make sure
+ // that tag type has an associated opaque type.
+ ConvertTagDeclType(TT->getDecl());
+ } else {
+ // This function no longer depends on an incomplete tag type; create the
+ // function type, and refine the opaque type to the new function type.
+ llvm::PATypeHolder OpaqueHolder = i->second;
+ const llvm::Type *NFT = ConvertNewType(QualType(i->first, 0));
+ cast<llvm::OpaqueType>(OpaqueHolder.get())->refineAbstractTypeTo(NFT);
+ FunctionTypes.erase(i);
+ }
+ }
+}
+
+static const llvm::Type* getTypeForFormat(const llvm::fltSemantics &format) {
+ if (&format == &llvm::APFloat::IEEEsingle)
+ return llvm::Type::FloatTy;
+ if (&format == &llvm::APFloat::IEEEdouble)
+ return llvm::Type::DoubleTy;
+ if (&format == &llvm::APFloat::IEEEquad)
+ return llvm::Type::FP128Ty;
+ if (&format == &llvm::APFloat::PPCDoubleDouble)
+ return llvm::Type::PPC_FP128Ty;
+ if (&format == &llvm::APFloat::x87DoubleExtended)
+ return llvm::Type::X86_FP80Ty;
+ assert(0 && "Unknown float format!");
+ return 0;
+}
+
+const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
+ const clang::Type &Ty = *Context.getCanonicalType(T);
+
+ switch (Ty.getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#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 or dependent types aren't possible.");
+ break;
+
+ case Type::Builtin: {
+ switch (cast<BuiltinType>(Ty).getKind()) {
+ default: assert(0 && "Unknown builtin type!");
+ case BuiltinType::Void:
+ // LLVM void type can only be used as the result of a function call. Just
+ // map to the same as char.
+ return llvm::IntegerType::get(8);
+
+ case BuiltinType::Bool:
+ // Note that we always return bool as i1 for use as a scalar type.
+ return llvm::Type::Int1Ty;
+
+ case BuiltinType::Char_S:
+ case BuiltinType::Char_U:
+ case BuiltinType::SChar:
+ case BuiltinType::UChar:
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ case BuiltinType::Long:
+ case BuiltinType::ULong:
+ case BuiltinType::LongLong:
+ case BuiltinType::ULongLong:
+ case BuiltinType::WChar:
+ return llvm::IntegerType::get(
+ static_cast<unsigned>(Context.getTypeSize(T)));
+
+ case BuiltinType::Float:
+ case BuiltinType::Double:
+ case BuiltinType::LongDouble:
+ return getTypeForFormat(Context.getFloatTypeSemantics(T));
+
+ case BuiltinType::UInt128:
+ case BuiltinType::Int128:
+ return llvm::IntegerType::get(128);
+ }
+ break;
+ }
+ case Type::FixedWidthInt:
+ return llvm::IntegerType::get(cast<FixedWidthIntType>(T)->getWidth());
+ case Type::Complex: {
+ const llvm::Type *EltTy =
+ ConvertTypeRecursive(cast<ComplexType>(Ty).getElementType());
+ return llvm::StructType::get(EltTy, EltTy, NULL);
+ }
+ case Type::LValueReference:
+ case Type::RValueReference: {
+ const ReferenceType &RTy = cast<ReferenceType>(Ty);
+ QualType ETy = RTy.getPointeeType();
+ llvm::OpaqueType *PointeeType = llvm::OpaqueType::get();
+ PointersToResolve.push_back(std::make_pair(ETy, PointeeType));
+ return llvm::PointerType::get(PointeeType, ETy.getAddressSpace());
+ }
+ case Type::Pointer: {
+ const PointerType &PTy = cast<PointerType>(Ty);
+ QualType ETy = PTy.getPointeeType();
+ llvm::OpaqueType *PointeeType = llvm::OpaqueType::get();
+ PointersToResolve.push_back(std::make_pair(ETy, PointeeType));
+ return llvm::PointerType::get(PointeeType, ETy.getAddressSpace());
+ }
+
+ case Type::VariableArray: {
+ const VariableArrayType &A = cast<VariableArrayType>(Ty);
+ assert(A.getIndexTypeQualifier() == 0 &&
+ "FIXME: We only handle trivial array types so far!");
+ // VLAs resolve to the innermost element type; this matches
+ // the return of alloca, and there isn't any obviously better choice.
+ return ConvertTypeForMemRecursive(A.getElementType());
+ }
+ case Type::IncompleteArray: {
+ const IncompleteArrayType &A = cast<IncompleteArrayType>(Ty);
+ assert(A.getIndexTypeQualifier() == 0 &&
+ "FIXME: We only handle trivial array types so far!");
+ // int X[] -> [0 x int]
+ return llvm::ArrayType::get(ConvertTypeForMemRecursive(A.getElementType()), 0);
+ }
+ case Type::ConstantArray: {
+ const ConstantArrayType &A = cast<ConstantArrayType>(Ty);
+ const llvm::Type *EltTy = ConvertTypeForMemRecursive(A.getElementType());
+ return llvm::ArrayType::get(EltTy, A.getSize().getZExtValue());
+ }
+ case Type::ExtVector:
+ case Type::Vector: {
+ const VectorType &VT = cast<VectorType>(Ty);
+ return llvm::VectorType::get(ConvertTypeRecursive(VT.getElementType()),
+ VT.getNumElements());
+ }
+ case Type::FunctionNoProto:
+ case Type::FunctionProto: {
+ // First, check whether we can build the full function type.
+ if (const TagType* TT = VerifyFuncTypeComplete(&Ty)) {
+ // This function's type depends on an incomplete tag type; make sure
+ // we have an opaque type corresponding to the tag type.
+ ConvertTagDeclType(TT->getDecl());
+ // Create an opaque type for this function type, save it, and return it.
+ llvm::Type *ResultType = llvm::OpaqueType::get();
+ FunctionTypes.insert(std::make_pair(&Ty, ResultType));
+ return ResultType;
+ }
+ // The function type can be built; call the appropriate routines to
+ // build it.
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(&Ty))
+ return GetFunctionType(getFunctionInfo(FPT), FPT->isVariadic());
+
+ const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(&Ty);
+ return GetFunctionType(getFunctionInfo(FNPT), true);
+ }
+
+ case Type::ExtQual:
+ return
+ ConvertTypeRecursive(QualType(cast<ExtQualType>(Ty).getBaseType(), 0));
+
+ case Type::ObjCQualifiedInterface: {
+ // Lower foo<P1,P2> just like foo.
+ ObjCInterfaceDecl *ID = cast<ObjCQualifiedInterfaceType>(Ty).getDecl();
+ return ConvertTypeRecursive(Context.getObjCInterfaceType(ID));
+ }
+
+ case Type::ObjCInterface: {
+ // Objective-C interfaces are always opaque (outside of the
+ // runtime, which can do whatever it likes); we never refine
+ // these.
+ const llvm::Type *&T = InterfaceTypes[cast<ObjCInterfaceType>(&Ty)];
+ if (!T)
+ T = llvm::OpaqueType::get();
+ return T;
+ }
+
+ case Type::ObjCQualifiedId:
+ // Protocols don't influence the LLVM type.
+ return ConvertTypeRecursive(Context.getObjCIdType());
+
+ case Type::Record:
+ case Type::Enum: {
+ const TagDecl *TD = cast<TagType>(Ty).getDecl();
+ const llvm::Type *Res = ConvertTagDeclType(TD);
+
+ std::string TypeName(TD->getKindName());
+ TypeName += '.';
+
+ // Name the codegen type after the typedef name
+ // if there is no tag type name available
+ if (TD->getIdentifier())
+ TypeName += TD->getNameAsString();
+ else if (const TypedefType *TdT = dyn_cast<TypedefType>(T))
+ TypeName += TdT->getDecl()->getNameAsString();
+ else
+ TypeName += "anon";
+
+ TheModule.addTypeName(TypeName, Res);
+ return Res;
+ }
+
+ case Type::BlockPointer: {
+ const QualType FTy = cast<BlockPointerType>(Ty).getPointeeType();
+ llvm::OpaqueType *PointeeType = llvm::OpaqueType::get();
+ PointersToResolve.push_back(std::make_pair(FTy, PointeeType));
+ return llvm::PointerType::get(PointeeType, FTy.getAddressSpace());
+ }
+
+ case Type::MemberPointer: {
+ // FIXME: This is ABI dependent. We use the Itanium C++ ABI.
+ // http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers
+ // If we ever want to support other ABIs this needs to be abstracted.
+
+ QualType ETy = cast<MemberPointerType>(Ty).getPointeeType();
+ if (ETy->isFunctionType()) {
+ return llvm::StructType::get(ConvertType(Context.getPointerDiffType()),
+ ConvertType(Context.getPointerDiffType()),
+ NULL);
+ } else
+ return ConvertType(Context.getPointerDiffType());
+ }
+
+ case Type::TemplateSpecialization:
+ assert(false && "Dependent types can't get here");
+ }
+
+ // FIXME: implement.
+ return llvm::OpaqueType::get();
+}
+
+/// ConvertTagDeclType - Lay out a tagged decl type like struct or union or
+/// enum.
+const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
+ // TagDecl's are not necessarily unique, instead use the (clang)
+ // type connected to the decl.
+ const Type *Key =
+ Context.getTagDeclType(const_cast<TagDecl*>(TD)).getTypePtr();
+ llvm::DenseMap<const Type*, llvm::PATypeHolder>::iterator TDTI =
+ TagDeclTypes.find(Key);
+
+ // If we've already compiled this tag type, use the previous definition.
+ if (TDTI != TagDeclTypes.end())
+ return TDTI->second;
+
+ // If this is still a forward definition, just define an opaque type to use
+ // for this tagged decl.
+ if (!TD->isDefinition()) {
+ llvm::Type *ResultType = llvm::OpaqueType::get();
+ TagDeclTypes.insert(std::make_pair(Key, ResultType));
+ return ResultType;
+ }
+
+ // Okay, this is a definition of a type. Compile the implementation now.
+
+ if (TD->isEnum()) {
+ // Don't bother storing enums in TagDeclTypes.
+ return ConvertTypeRecursive(cast<EnumDecl>(TD)->getIntegerType());
+ }
+
+ // This decl could well be recursive. In this case, insert an opaque
+ // definition of this type, which the recursive uses will get. We will then
+ // refine this opaque version later.
+
+ // Create new OpaqueType now for later use in case this is a recursive
+ // type. This will later be refined to the actual type.
+ llvm::PATypeHolder ResultHolder = llvm::OpaqueType::get();
+ TagDeclTypes.insert(std::make_pair(Key, ResultHolder));
+
+ const llvm::Type *ResultType;
+ const RecordDecl *RD = cast<const RecordDecl>(TD);
+
+ // There isn't any extra information for empty structures/unions.
+ if (RD->field_empty(getContext())) {
+ ResultType = llvm::StructType::get(std::vector<const llvm::Type*>());
+ } else {
+ // Layout fields.
+ RecordOrganizer RO(*this, *RD);
+
+ if (TD->isStruct() || TD->isClass())
+ RO.layoutStructFields(Context.getASTRecordLayout(RD));
+ else {
+ assert(TD->isUnion() && "unknown tag decl kind!");
+ RO.layoutUnionFields(Context.getASTRecordLayout(RD));
+ }
+
+ // Get llvm::StructType.
+ const Type *Key =
+ Context.getTagDeclType(const_cast<TagDecl*>(TD)).getTypePtr();
+ CGRecordLayouts[Key] = new CGRecordLayout(RO.getLLVMType(),
+ RO.getPaddingFields());
+ ResultType = RO.getLLVMType();
+ }
+
+ // Refine our Opaque type to ResultType. This can invalidate ResultType, so
+ // make sure to read the result out of the holder.
+ cast<llvm::OpaqueType>(ResultHolder.get())
+ ->refineAbstractTypeTo(ResultType);
+
+ return ResultHolder.get();
+}
+
+/// getLLVMFieldNo - Return llvm::StructType element number
+/// that corresponds to the field FD.
+unsigned CodeGenTypes::getLLVMFieldNo(const FieldDecl *FD) {
+ llvm::DenseMap<const FieldDecl*, unsigned>::iterator I = FieldInfo.find(FD);
+ assert (I != FieldInfo.end() && "Unable to find field info");
+ return I->second;
+}
+
+/// addFieldInfo - Assign field number to field FD.
+void CodeGenTypes::addFieldInfo(const FieldDecl *FD, unsigned No) {
+ FieldInfo[FD] = No;
+}
+
+/// getBitFieldInfo - Return the BitFieldInfo that corresponds to the field FD.
+CodeGenTypes::BitFieldInfo CodeGenTypes::getBitFieldInfo(const FieldDecl *FD) {
+ llvm::DenseMap<const FieldDecl *, BitFieldInfo>::iterator
+ I = BitFields.find(FD);
+ assert (I != BitFields.end() && "Unable to find bitfield info");
+ return I->second;
+}
+
+/// addBitFieldInfo - Assign a start bit and a size to field FD.
+void CodeGenTypes::addBitFieldInfo(const FieldDecl *FD, unsigned Begin,
+ unsigned Size) {
+ BitFields.insert(std::make_pair(FD, BitFieldInfo(Begin, Size)));
+}
+
+/// getCGRecordLayout - Return record layout info for the given llvm::Type.
+const CGRecordLayout *
+CodeGenTypes::getCGRecordLayout(const TagDecl *TD) const {
+ const Type *Key =
+ Context.getTagDeclType(const_cast<TagDecl*>(TD)).getTypePtr();
+ llvm::DenseMap<const Type*, CGRecordLayout *>::iterator I
+ = CGRecordLayouts.find(Key);
+ assert (I != CGRecordLayouts.end()
+ && "Unable to find record layout information for type");
+ return I->second;
+}
+
+/// layoutStructFields - Do the actual work and lay out all fields. Create
+/// corresponding llvm struct type.
+/// Note that this doesn't actually try to do struct layout; it depends on
+/// the layout built by the AST. (We have to do struct layout to do Sema,
+/// and there's no point to duplicating the work.)
+void RecordOrganizer::layoutStructFields(const ASTRecordLayout &RL) {
+ // FIXME: This code currently always generates packed structures.
+ // Unpacked structures are more readable, and sometimes more efficient!
+ // (But note that any changes here are likely to impact CGExprConstant,
+ // which makes some messy assumptions.)
+ uint64_t llvmSize = 0;
+ // FIXME: Make this a SmallVector
+ std::vector<const llvm::Type*> LLVMFields;
+
+ unsigned curField = 0;
+ for (RecordDecl::field_iterator Field = RD.field_begin(CGT.getContext()),
+ FieldEnd = RD.field_end(CGT.getContext());
+ Field != FieldEnd; ++Field) {
+ uint64_t offset = RL.getFieldOffset(curField);
+ const llvm::Type *Ty = CGT.ConvertTypeForMemRecursive(Field->getType());
+ uint64_t size = CGT.getTargetData().getTypeAllocSizeInBits(Ty);
+
+ if (Field->isBitField()) {
+ uint64_t BitFieldSize =
+ Field->getBitWidth()->EvaluateAsInt(CGT.getContext()).getZExtValue();
+
+ // Bitfield field info is different from other field info;
+ // it actually ignores the underlying LLVM struct because
+ // there isn't any convenient mapping.
+ CGT.addFieldInfo(*Field, offset / size);
+ CGT.addBitFieldInfo(*Field, offset % size, BitFieldSize);
+ } else {
+ // Put the element into the struct. This would be simpler
+ // if we didn't bother, but it seems a bit too strange to
+ // allocate all structs as i8 arrays.
+ while (llvmSize < offset) {
+ LLVMFields.push_back(llvm::Type::Int8Ty);
+ llvmSize += 8;
+ }
+
+ llvmSize += size;
+ CGT.addFieldInfo(*Field, LLVMFields.size());
+ LLVMFields.push_back(Ty);
+ }
+ ++curField;
+ }
+
+ while (llvmSize < RL.getSize()) {
+ LLVMFields.push_back(llvm::Type::Int8Ty);
+ llvmSize += 8;
+ }
+
+ STy = llvm::StructType::get(LLVMFields, true);
+ assert(CGT.getTargetData().getTypeAllocSizeInBits(STy) == RL.getSize());
+}
+
+/// layoutUnionFields - Do the actual work and lay out all fields. Create
+/// corresponding llvm struct type. This should be invoked only after
+/// all fields are added.
+void RecordOrganizer::layoutUnionFields(const ASTRecordLayout &RL) {
+ unsigned curField = 0;
+ for (RecordDecl::field_iterator Field = RD.field_begin(CGT.getContext()),
+ FieldEnd = RD.field_end(CGT.getContext());
+ Field != FieldEnd; ++Field) {
+ // The offset should usually be zero, but bitfields could be strange
+ uint64_t offset = RL.getFieldOffset(curField);
+ CGT.ConvertTypeRecursive(Field->getType());
+
+ if (Field->isBitField()) {
+ Expr *BitWidth = Field->getBitWidth();
+ uint64_t BitFieldSize =
+ BitWidth->EvaluateAsInt(CGT.getContext()).getZExtValue();
+
+ CGT.addFieldInfo(*Field, 0);
+ CGT.addBitFieldInfo(*Field, offset, BitFieldSize);
+ } else {
+ CGT.addFieldInfo(*Field, 0);
+ }
+ ++curField;
+ }
+
+ // This looks stupid, but it is correct in the sense that
+ // it works no matter how complicated the sizes and alignments
+ // of the union elements are. The natural alignment
+ // of the result doesn't matter because anyone allocating
+ // structures should be aligning them appropriately anyway.
+ // FIXME: We can be a bit more intuitive in a lot of cases.
+ // FIXME: Make this a struct type to work around PR2399; the
+ // C backend doesn't like structs using array types.
+ std::vector<const llvm::Type*> LLVMFields;
+ LLVMFields.push_back(llvm::ArrayType::get(llvm::Type::Int8Ty,
+ RL.getSize() / 8));
+ STy = llvm::StructType::get(LLVMFields, true);
+ assert(CGT.getTargetData().getTypeAllocSizeInBits(STy) == RL.getSize());
+}
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
new file mode 100644
index 000000000000..b72d8e92013a
--- /dev/null
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -0,0 +1,212 @@
+//===--- CodeGenTypes.h - Type translation for LLVM CodeGen -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the code that handles AST -> LLVM type lowering.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CODEGENTYPES_H
+#define CLANG_CODEGEN_CODEGENTYPES_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallSet.h"
+#include <vector>
+
+#include "CGCall.h"
+
+namespace llvm {
+ class FunctionType;
+ class Module;
+ class OpaqueType;
+ class PATypeHolder;
+ class TargetData;
+ class Type;
+}
+
+namespace clang {
+ class ABIInfo;
+ class ASTContext;
+ class CXXMethodDecl;
+ class FieldDecl;
+ class FunctionProtoType;
+ class ObjCInterfaceDecl;
+ class ObjCIvarDecl;
+ class PointerType;
+ class QualType;
+ class RecordDecl;
+ class TagDecl;
+ class TargetInfo;
+ class Type;
+
+namespace CodeGen {
+ class CodeGenTypes;
+
+ /// CGRecordLayout - This class handles struct and union layout info while
+ /// lowering AST types to LLVM types.
+ class CGRecordLayout {
+ CGRecordLayout(); // DO NOT IMPLEMENT
+ public:
+ CGRecordLayout(llvm::Type *T, llvm::SmallSet<unsigned, 8> &PF)
+ : STy(T), PaddingFields(PF) {
+ // FIXME : Collect info about fields that requires adjustments
+ // (i.e. fields that do not directly map to llvm struct fields.)
+ }
+
+ /// getLLVMType - Return llvm type associated with this record.
+ llvm::Type *getLLVMType() const {
+ return STy;
+ }
+
+ bool isPaddingField(unsigned No) const {
+ return PaddingFields.count(No) != 0;
+ }
+
+ unsigned getNumPaddingFields() {
+ return PaddingFields.size();
+ }
+
+ private:
+ llvm::Type *STy;
+ llvm::SmallSet<unsigned, 8> PaddingFields;
+ };
+
+/// CodeGenTypes - This class organizes the cross-module state that is used
+/// while lowering AST types to LLVM types.
+class CodeGenTypes {
+ ASTContext &Context;
+ TargetInfo &Target;
+ llvm::Module& TheModule;
+ const llvm::TargetData& TheTargetData;
+ mutable const ABIInfo* TheABIInfo;
+
+ llvm::SmallVector<std::pair<QualType,
+ llvm::OpaqueType *>, 8> PointersToResolve;
+
+ llvm::DenseMap<const Type*, llvm::PATypeHolder> TagDeclTypes;
+
+ llvm::DenseMap<const Type*, llvm::PATypeHolder> FunctionTypes;
+
+ /// The opaque type map for Objective-C interfaces. All direct
+ /// manipulation is done by the runtime interfaces, which are
+ /// responsible for coercing to the appropriate type; these opaque
+ /// types are never refined.
+ llvm::DenseMap<const ObjCInterfaceType*, const llvm::Type *> InterfaceTypes;
+
+ /// CGRecordLayouts - This maps llvm struct type with corresponding
+ /// record layout info.
+ /// FIXME : If CGRecordLayout is less than 16 bytes then use
+ /// inline it in the map.
+ llvm::DenseMap<const Type*, CGRecordLayout *> CGRecordLayouts;
+
+ /// FieldInfo - This maps struct field with corresponding llvm struct type
+ /// field no. This info is populated by record organizer.
+ llvm::DenseMap<const FieldDecl *, unsigned> FieldInfo;
+
+ /// FunctionInfos - Hold memoized CGFunctionInfo results.
+ llvm::FoldingSet<CGFunctionInfo> FunctionInfos;
+
+public:
+ class BitFieldInfo {
+ public:
+ explicit BitFieldInfo(unsigned short B, unsigned short S)
+ : Begin(B), Size(S) {}
+
+ unsigned short Begin;
+ unsigned short Size;
+ };
+
+private:
+ llvm::DenseMap<const FieldDecl *, BitFieldInfo> BitFields;
+
+ /// TypeCache - This map keeps cache of llvm::Types (through PATypeHolder)
+ /// and maps llvm::Types to corresponding clang::Type. llvm::PATypeHolder is
+ /// used instead of llvm::Type because it allows us to bypass potential
+ /// dangling type pointers due to type refinement on llvm side.
+ llvm::DenseMap<Type *, llvm::PATypeHolder> TypeCache;
+
+ /// ConvertNewType - Convert type T into a llvm::Type. Do not use this
+ /// method directly because it does not do any type caching. This method
+ /// is available only for ConvertType(). CovertType() is preferred
+ /// interface to convert type T into a llvm::Type.
+ const llvm::Type *ConvertNewType(QualType T);
+public:
+ CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD);
+ ~CodeGenTypes();
+
+ const llvm::TargetData &getTargetData() const { return TheTargetData; }
+ TargetInfo &getTarget() const { return Target; }
+ ASTContext &getContext() const { return Context; }
+ const ABIInfo &getABIInfo() const;
+
+ /// ConvertType - Convert type T into a llvm::Type.
+ const llvm::Type *ConvertType(QualType T);
+ const llvm::Type *ConvertTypeRecursive(QualType T);
+
+ /// ConvertTypeForMem - Convert type T into a llvm::Type. This differs from
+ /// ConvertType in that it is used to convert to the memory representation for
+ /// a type. For example, the scalar representation for _Bool is i1, but the
+ /// memory representation is usually i8 or i32, depending on the target.
+ const llvm::Type *ConvertTypeForMem(QualType T);
+ const llvm::Type *ConvertTypeForMemRecursive(QualType T);
+
+ /// GetFunctionType - Get the LLVM function type for \arg Info.
+ const llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info,
+ bool IsVariadic);
+
+ const CGRecordLayout *getCGRecordLayout(const TagDecl*) const;
+
+ /// getLLVMFieldNo - Return llvm::StructType element number
+ /// that corresponds to the field FD.
+ unsigned getLLVMFieldNo(const FieldDecl *FD);
+
+ /// UpdateCompletedType - When we find the full definition for a TagDecl,
+ /// replace the 'opaque' type we previously made for it if applicable.
+ void UpdateCompletedType(const TagDecl *TD);
+
+ /// getFunctionInfo - Get the CGFunctionInfo for this function signature.
+ const CGFunctionInfo &getFunctionInfo(QualType RetTy,
+ const llvm::SmallVector<QualType,16>
+ &ArgTys);
+
+ const CGFunctionInfo &getFunctionInfo(const FunctionNoProtoType *FTNP);
+ const CGFunctionInfo &getFunctionInfo(const FunctionProtoType *FTP);
+ const CGFunctionInfo &getFunctionInfo(const FunctionDecl *FD);
+ const CGFunctionInfo &getFunctionInfo(const CXXMethodDecl *MD);
+ const CGFunctionInfo &getFunctionInfo(const ObjCMethodDecl *MD);
+ const CGFunctionInfo &getFunctionInfo(QualType ResTy,
+ const CallArgList &Args);
+public:
+ const CGFunctionInfo &getFunctionInfo(QualType ResTy,
+ const FunctionArgList &Args);
+
+public: // These are internal details of CGT that shouldn't be used externally.
+ /// addFieldInfo - Assign field number to field FD.
+ void addFieldInfo(const FieldDecl *FD, unsigned No);
+
+ /// addBitFieldInfo - Assign a start bit and a size to field FD.
+ void addBitFieldInfo(const FieldDecl *FD, unsigned Begin, unsigned Size);
+
+ /// getBitFieldInfo - Return the BitFieldInfo that corresponds to the field
+ /// FD.
+ BitFieldInfo getBitFieldInfo(const FieldDecl *FD);
+
+ /// ConvertTagDeclType - Lay out a tagged decl type like struct or union or
+ /// enum.
+ const llvm::Type *ConvertTagDeclType(const TagDecl *TD);
+
+ /// GetExpandedTypes - Expand the type \arg Ty into the LLVM
+ /// argument types it would be passed as on the provided vector \arg
+ /// ArgTys. See ABIArgInfo::Expand.
+ void GetExpandedTypes(QualType Ty, std::vector<const llvm::Type*> &ArgTys);
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/lib/CodeGen/Makefile b/lib/CodeGen/Makefile
new file mode 100644
index 000000000000..e716fe78bc60
--- /dev/null
+++ b/lib/CodeGen/Makefile
@@ -0,0 +1,23 @@
+##===- clang/lib/CodeGen/Makefile --------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements the AST -> LLVM code generation library for the
+# C-Language front-end.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+LIBRARYNAME := clangCodeGen
+BUILD_ARCHIVE = 1
+CXXFLAGS = -fno-rtti
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
new file mode 100644
index 000000000000..6ee1223a0059
--- /dev/null
+++ b/lib/CodeGen/Mangle.cpp
@@ -0,0 +1,772 @@
+//===--- Mangle.cpp - Mangle C++ Names --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements C++ name mangling according to the Itanium C++ ABI,
+// which is used in GCC 3.2 and newer (and many compilers that are
+// ABI-compatible with GCC):
+//
+// http://www.codesourcery.com/public/cxx-abi/abi.html
+//
+//===----------------------------------------------------------------------===//
+#include "Mangle.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+namespace {
+ class VISIBILITY_HIDDEN CXXNameMangler {
+ ASTContext &Context;
+ llvm::raw_ostream &Out;
+
+ const CXXMethodDecl *Structor;
+ unsigned StructorType;
+ CXXCtorType CtorType;
+
+ public:
+ CXXNameMangler(ASTContext &C, llvm::raw_ostream &os)
+ : Context(C), Out(os), Structor(0), StructorType(0) { }
+
+ bool mangle(const NamedDecl *D);
+ void mangleGuardVariable(const VarDecl *D);
+
+ void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type);
+ void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type);
+
+ private:
+ bool mangleFunctionDecl(const FunctionDecl *FD);
+
+ void mangleFunctionEncoding(const FunctionDecl *FD);
+ void mangleName(const NamedDecl *ND);
+ void mangleUnqualifiedName(const NamedDecl *ND);
+ void mangleSourceName(const IdentifierInfo *II);
+ void mangleLocalName(const NamedDecl *ND);
+ void mangleNestedName(const NamedDecl *ND);
+ void manglePrefix(const DeclContext *DC);
+ void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
+ void mangleCVQualifiers(unsigned Quals);
+ void mangleType(QualType T);
+ void mangleType(const BuiltinType *T);
+ void mangleType(const FunctionType *T);
+ void mangleBareFunctionType(const FunctionType *T, bool MangleReturnType);
+ void mangleType(const TagType *T);
+ void mangleType(const ArrayType *T);
+ void mangleType(const MemberPointerType *T);
+ void mangleType(const TemplateTypeParmType *T);
+ void mangleType(const ObjCInterfaceType *T);
+ void mangleExpression(Expr *E);
+ void mangleCXXCtorType(CXXCtorType T);
+ void mangleCXXDtorType(CXXDtorType T);
+
+ void mangleTemplateArgumentList(const TemplateArgumentList &L);
+ void mangleTemplateArgument(const TemplateArgument &A);
+ };
+}
+
+static bool isInCLinkageSpecification(const Decl *D) {
+ for (const DeclContext *DC = D->getDeclContext();
+ !DC->isTranslationUnit(); DC = DC->getParent()) {
+ if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC))
+ return Linkage->getLanguage() == LinkageSpecDecl::lang_c;
+ }
+
+ return false;
+}
+
+bool CXXNameMangler::mangleFunctionDecl(const FunctionDecl *FD) {
+ // Clang's "overloadable" attribute extension to C/C++ implies
+ // name mangling (always).
+ if (FD->hasAttr<OverloadableAttr>()) {
+ ; // fall into mangling code unconditionally.
+ } else if (// C functions are not mangled
+ !Context.getLangOptions().CPlusPlus ||
+ // "main" is not mangled in C++
+ FD->isMain() ||
+ // No mangling in an "implicit extern C" header.
+ (FD->getLocation().isValid() &&
+ Context.getSourceManager().getFileCharacteristic(FD->getLocation()))
+ == SrcMgr::C_ExternCSystem ||
+ // No name mangling in a C linkage specification.
+ isInCLinkageSpecification(FD))
+ return false;
+
+ // If we get here, mangle the decl name!
+ Out << "_Z";
+ mangleFunctionEncoding(FD);
+ return true;
+}
+
+bool CXXNameMangler::mangle(const NamedDecl *D) {
+ // Any decl can be declared with __asm("foo") on it, and this takes
+ // precedence over all other naming in the .o file.
+ if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
+ // If we have an asm name, then we use it as the mangling.
+ Out << '\01'; // LLVM IR Marker for __asm("foo")
+ Out << ALA->getLabel();
+ return true;
+ }
+
+ // <mangled-name> ::= _Z <encoding>
+ // ::= <data name>
+ // ::= <special-name>
+
+ // FIXME: Actually use a visitor to decode these?
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ return mangleFunctionDecl(FD);
+
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (!Context.getLangOptions().CPlusPlus ||
+ isInCLinkageSpecification(D) ||
+ D->getDeclContext()->isTranslationUnit())
+ return false;
+
+ Out << "_Z";
+ mangleName(VD);
+ return true;
+ }
+
+ return false;
+}
+
+void CXXNameMangler::mangleCXXCtor(const CXXConstructorDecl *D,
+ CXXCtorType Type) {
+ assert(!Structor && "Structor already set!");
+ Structor = D;
+ StructorType = Type;
+
+ mangle(D);
+}
+
+void CXXNameMangler::mangleCXXDtor(const CXXDestructorDecl *D,
+ CXXDtorType Type) {
+ assert(!Structor && "Structor already set!");
+ Structor = D;
+ StructorType = Type;
+
+ mangle(D);
+}
+
+void CXXNameMangler::mangleGuardVariable(const VarDecl *D)
+{
+ // <special-name> ::= GV <object name> # Guard variable for one-time
+ // # initialization
+
+ Out << "_ZGV";
+ mangleName(D);
+}
+
+void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
+ // <encoding> ::= <function name> <bare-function-type>
+ mangleName(FD);
+ mangleBareFunctionType(FD->getType()->getAsFunctionType(), false);
+}
+
+static bool isStdNamespace(const DeclContext *DC) {
+ if (!DC->isNamespace() || !DC->getParent()->isTranslationUnit())
+ return false;
+
+ const NamespaceDecl *NS = cast<NamespaceDecl>(DC);
+ return NS->getOriginalNamespace()->getIdentifier()->isStr("std");
+}
+
+void CXXNameMangler::mangleName(const NamedDecl *ND) {
+ // <name> ::= <nested-name>
+ // ::= <unscoped-name>
+ // ::= <unscoped-template-name> <template-args>
+ // ::= <local-name> # See Scope Encoding below
+ //
+ // <unscoped-name> ::= <unqualified-name>
+ // ::= St <unqualified-name> # ::std::
+ if (ND->getDeclContext()->isTranslationUnit())
+ mangleUnqualifiedName(ND);
+ else if (isStdNamespace(ND->getDeclContext())) {
+ Out << "St";
+ mangleUnqualifiedName(ND);
+ } else if (isa<FunctionDecl>(ND->getDeclContext()))
+ mangleLocalName(ND);
+ else
+ mangleNestedName(ND);
+}
+
+void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
+ // <unqualified-name> ::= <operator-name>
+ // ::= <ctor-dtor-name>
+ // ::= <source-name>
+ DeclarationName Name = ND->getDeclName();
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier:
+ mangleSourceName(Name.getAsIdentifierInfo());
+ break;
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ assert(false && "Can't mangle Objective-C selector names here!");
+ break;
+
+ case DeclarationName::CXXConstructorName:
+ if (ND == Structor)
+ // If the named decl is the C++ constructor we're mangling, use the
+ // type we were given.
+ mangleCXXCtorType(static_cast<CXXCtorType>(StructorType));
+ else
+ // Otherwise, use the complete constructor name. This is relevant if a
+ // class with a constructor is declared within a constructor.
+ mangleCXXCtorType(Ctor_Complete);
+ break;
+
+ case DeclarationName::CXXDestructorName:
+ if (ND == Structor)
+ // If the named decl is the C++ destructor we're mangling, use the
+ // type we were given.
+ mangleCXXDtorType(static_cast<CXXDtorType>(StructorType));
+ else
+ // Otherwise, use the complete destructor name. This is relevant if a
+ // class with a destructor is declared within a destructor.
+ mangleCXXDtorType(Dtor_Complete);
+ break;
+
+ case DeclarationName::CXXConversionFunctionName:
+ // <operator-name> ::= cv <type> # (cast)
+ Out << "cv";
+ mangleType(Context.getCanonicalType(Name.getCXXNameType()));
+ break;
+
+ case DeclarationName::CXXOperatorName:
+ mangleOperatorName(Name.getCXXOverloadedOperator(),
+ cast<FunctionDecl>(ND)->getNumParams());
+ break;
+
+ case DeclarationName::CXXUsingDirective:
+ assert(false && "Can't mangle a using directive name!");
+ break;
+ }
+}
+
+void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
+ // <source-name> ::= <positive length number> <identifier>
+ // <number> ::= [n] <non-negative decimal integer>
+ // <identifier> ::= <unqualified source code identifier>
+ Out << II->getLength() << II->getName();
+}
+
+void CXXNameMangler::mangleNestedName(const NamedDecl *ND) {
+ // <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
+ // ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+ // FIXME: no template support
+ Out << 'N';
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND))
+ mangleCVQualifiers(Method->getTypeQualifiers());
+ manglePrefix(ND->getDeclContext());
+ mangleUnqualifiedName(ND);
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
+ // <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+ // := Z <function encoding> E s [<discriminator>]
+ // <discriminator> := _ <non-negative number>
+ Out << 'Z';
+ mangleFunctionEncoding(cast<FunctionDecl>(ND->getDeclContext()));
+ Out << 'E';
+ mangleSourceName(ND->getIdentifier());
+}
+
+void CXXNameMangler::manglePrefix(const DeclContext *DC) {
+ // <prefix> ::= <prefix> <unqualified-name>
+ // ::= <template-prefix> <template-args>
+ // ::= <template-param>
+ // ::= # empty
+ // ::= <substitution>
+ // FIXME: We only handle mangling of namespaces and classes at the moment.
+ if (!DC->getParent()->isTranslationUnit())
+ manglePrefix(DC->getParent());
+
+ if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(DC))
+ mangleSourceName(Namespace->getIdentifier());
+ else if (const RecordDecl *Record = dyn_cast<RecordDecl>(DC)) {
+ if (const ClassTemplateSpecializationDecl *D =
+ dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
+ mangleType(QualType(D->getTypeForDecl(), 0));
+ } else
+ mangleSourceName(Record->getIdentifier());
+ }
+}
+
+void
+CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
+ switch (OO) {
+ // <operator-name> ::= nw # new
+ case OO_New: Out << "nw"; break;
+ // ::= na # new[]
+ case OO_Array_New: Out << "na"; break;
+ // ::= dl # delete
+ case OO_Delete: Out << "dl"; break;
+ // ::= da # delete[]
+ case OO_Array_Delete: Out << "da"; break;
+ // ::= ps # + (unary)
+ // ::= pl # +
+ case OO_Plus: Out << (Arity == 1? "ps" : "pl"); break;
+ // ::= ng # - (unary)
+ // ::= mi # -
+ case OO_Minus: Out << (Arity == 1? "ng" : "mi"); break;
+ // ::= ad # & (unary)
+ // ::= an # &
+ case OO_Amp: Out << (Arity == 1? "ad" : "an"); break;
+ // ::= de # * (unary)
+ // ::= ml # *
+ case OO_Star: Out << (Arity == 1? "de" : "ml"); break;
+ // ::= co # ~
+ case OO_Tilde: Out << "co"; break;
+ // ::= dv # /
+ case OO_Slash: Out << "dv"; break;
+ // ::= rm # %
+ case OO_Percent: Out << "rm"; break;
+ // ::= or # |
+ case OO_Pipe: Out << "or"; break;
+ // ::= eo # ^
+ case OO_Caret: Out << "eo"; break;
+ // ::= aS # =
+ case OO_Equal: Out << "aS"; break;
+ // ::= pL # +=
+ case OO_PlusEqual: Out << "pL"; break;
+ // ::= mI # -=
+ case OO_MinusEqual: Out << "mI"; break;
+ // ::= mL # *=
+ case OO_StarEqual: Out << "mL"; break;
+ // ::= dV # /=
+ case OO_SlashEqual: Out << "dV"; break;
+ // ::= rM # %=
+ case OO_PercentEqual: Out << "rM"; break;
+ // ::= aN # &=
+ case OO_AmpEqual: Out << "aN"; break;
+ // ::= oR # |=
+ case OO_PipeEqual: Out << "oR"; break;
+ // ::= eO # ^=
+ case OO_CaretEqual: Out << "eO"; break;
+ // ::= ls # <<
+ case OO_LessLess: Out << "ls"; break;
+ // ::= rs # >>
+ case OO_GreaterGreater: Out << "rs"; break;
+ // ::= lS # <<=
+ case OO_LessLessEqual: Out << "lS"; break;
+ // ::= rS # >>=
+ case OO_GreaterGreaterEqual: Out << "rS"; break;
+ // ::= eq # ==
+ case OO_EqualEqual: Out << "eq"; break;
+ // ::= ne # !=
+ case OO_ExclaimEqual: Out << "ne"; break;
+ // ::= lt # <
+ case OO_Less: Out << "lt"; break;
+ // ::= gt # >
+ case OO_Greater: Out << "gt"; break;
+ // ::= le # <=
+ case OO_LessEqual: Out << "le"; break;
+ // ::= ge # >=
+ case OO_GreaterEqual: Out << "ge"; break;
+ // ::= nt # !
+ case OO_Exclaim: Out << "nt"; break;
+ // ::= aa # &&
+ case OO_AmpAmp: Out << "aa"; break;
+ // ::= oo # ||
+ case OO_PipePipe: Out << "oo"; break;
+ // ::= pp # ++
+ case OO_PlusPlus: Out << "pp"; break;
+ // ::= mm # --
+ case OO_MinusMinus: Out << "mm"; break;
+ // ::= cm # ,
+ case OO_Comma: Out << "cm"; break;
+ // ::= pm # ->*
+ case OO_ArrowStar: Out << "pm"; break;
+ // ::= pt # ->
+ case OO_Arrow: Out << "pt"; break;
+ // ::= cl # ()
+ case OO_Call: Out << "cl"; break;
+ // ::= ix # []
+ case OO_Subscript: Out << "ix"; break;
+ // UNSUPPORTED: ::= qu # ?
+
+ case OO_None:
+ case OO_Conditional:
+ case NUM_OVERLOADED_OPERATORS:
+ assert(false && "Not an overloaded operator");
+ break;
+ }
+}
+
+void CXXNameMangler::mangleCVQualifiers(unsigned Quals) {
+ // <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const
+ if (Quals & QualType::Restrict)
+ Out << 'r';
+ if (Quals & QualType::Volatile)
+ Out << 'V';
+ if (Quals & QualType::Const)
+ Out << 'K';
+}
+
+void CXXNameMangler::mangleType(QualType T) {
+ // Only operate on the canonical type!
+ T = Context.getCanonicalType(T);
+
+ // FIXME: Should we have a TypeNodes.def to make this easier? (YES!)
+
+ // <type> ::= <CV-qualifiers> <type>
+ mangleCVQualifiers(T.getCVRQualifiers());
+
+ // ::= <builtin-type>
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr()))
+ mangleType(BT);
+ // ::= <function-type>
+ else if (const FunctionType *FT = dyn_cast<FunctionType>(T.getTypePtr()))
+ mangleType(FT);
+ // ::= <class-enum-type>
+ else if (const TagType *TT = dyn_cast<TagType>(T.getTypePtr()))
+ mangleType(TT);
+ // ::= <array-type>
+ else if (const ArrayType *AT = dyn_cast<ArrayType>(T.getTypePtr()))
+ mangleType(AT);
+ // ::= <pointer-to-member-type>
+ else if (const MemberPointerType *MPT
+ = dyn_cast<MemberPointerType>(T.getTypePtr()))
+ mangleType(MPT);
+ // ::= <template-param>
+ else if (const TemplateTypeParmType *TypeParm
+ = dyn_cast<TemplateTypeParmType>(T.getTypePtr()))
+ mangleType(TypeParm);
+ // FIXME: ::= <template-template-param> <template-args>
+ // FIXME: ::= <substitution> # See Compression below
+ // ::= P <type> # pointer-to
+ else if (const PointerType *PT = dyn_cast<PointerType>(T.getTypePtr())) {
+ Out << 'P';
+ mangleType(PT->getPointeeType());
+ }
+ // ::= R <type> # reference-to
+ else if (const LValueReferenceType *RT =
+ dyn_cast<LValueReferenceType>(T.getTypePtr())) {
+ Out << 'R';
+ mangleType(RT->getPointeeType());
+ }
+ // ::= O <type> # rvalue reference-to (C++0x)
+ else if (const RValueReferenceType *RT =
+ dyn_cast<RValueReferenceType>(T.getTypePtr())) {
+ Out << 'O';
+ mangleType(RT->getPointeeType());
+ }
+ // ::= C <type> # complex pair (C 2000)
+ else if (const ComplexType *CT = dyn_cast<ComplexType>(T.getTypePtr())) {
+ Out << 'C';
+ mangleType(CT->getElementType());
+ } else if (const VectorType *VT = dyn_cast<VectorType>(T.getTypePtr())) {
+ // GNU extension: vector types
+ Out << "U8__vector";
+ mangleType(VT->getElementType());
+ } else if (const ObjCInterfaceType *IT =
+ dyn_cast<ObjCInterfaceType>(T.getTypePtr())) {
+ mangleType(IT);
+ }
+ // FIXME: ::= G <type> # imaginary (C 2000)
+ // FIXME: ::= U <source-name> <type> # vendor extended type qualifier
+ else
+ assert(false && "Cannot mangle unknown type");
+}
+
+void CXXNameMangler::mangleType(const BuiltinType *T) {
+ // <builtin-type> ::= v # void
+ // ::= w # wchar_t
+ // ::= b # bool
+ // ::= c # char
+ // ::= a # signed char
+ // ::= h # unsigned char
+ // ::= s # short
+ // ::= t # unsigned short
+ // ::= i # int
+ // ::= j # unsigned int
+ // ::= l # long
+ // ::= m # unsigned long
+ // ::= x # long long, __int64
+ // ::= y # unsigned long long, __int64
+ // ::= n # __int128
+ // UNSUPPORTED: ::= o # unsigned __int128
+ // ::= f # float
+ // ::= d # double
+ // ::= e # long double, __float80
+ // UNSUPPORTED: ::= g # __float128
+ // 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)
+ // UNSUPPORTED: ::= Di # char32_t
+ // UNSUPPORTED: ::= Ds # char16_t
+ // ::= u <source-name> # vendor extended type
+ // From our point of view, std::nullptr_t is a builtin, but as far as mangling
+ // is concerned, it's a type called std::nullptr_t.
+ switch (T->getKind()) {
+ case BuiltinType::Void: Out << 'v'; break;
+ case BuiltinType::Bool: Out << 'b'; break;
+ case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'c'; break;
+ case BuiltinType::UChar: Out << 'h'; break;
+ case BuiltinType::UShort: Out << 't'; break;
+ case BuiltinType::UInt: Out << 'j'; break;
+ case BuiltinType::ULong: Out << 'm'; break;
+ case BuiltinType::ULongLong: Out << 'y'; break;
+ case BuiltinType::UInt128: Out << 'o'; break;
+ case BuiltinType::SChar: Out << 'a'; break;
+ case BuiltinType::WChar: Out << 'w'; break;
+ case BuiltinType::Short: Out << 's'; break;
+ case BuiltinType::Int: Out << 'i'; break;
+ case BuiltinType::Long: Out << 'l'; break;
+ case BuiltinType::LongLong: Out << 'x'; break;
+ case BuiltinType::Int128: Out << 'n'; break;
+ case BuiltinType::Float: Out << 'f'; break;
+ case BuiltinType::Double: Out << 'd'; break;
+ case BuiltinType::LongDouble: Out << 'e'; break;
+ case BuiltinType::NullPtr: Out << "St9nullptr_t"; break;
+
+ case BuiltinType::Overload:
+ case BuiltinType::Dependent:
+ assert(false &&
+ "Overloaded and dependent types shouldn't get to name mangling");
+ break;
+ }
+}
+
+void CXXNameMangler::mangleType(const FunctionType *T) {
+ // <function-type> ::= F [Y] <bare-function-type> E
+ Out << 'F';
+ // FIXME: We don't have enough information in the AST to produce the 'Y'
+ // encoding for extern "C" function types.
+ mangleBareFunctionType(T, /*MangleReturnType=*/true);
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
+ bool MangleReturnType) {
+ // <bare-function-type> ::= <signature type>+
+ if (MangleReturnType)
+ mangleType(T->getResultType());
+
+ const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(T);
+ assert(Proto && "Can't mangle K&R function prototypes");
+
+ if (Proto->getNumArgs() == 0) {
+ Out << 'v';
+ return;
+ }
+
+ for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
+ ArgEnd = Proto->arg_type_end();
+ Arg != ArgEnd; ++Arg)
+ mangleType(*Arg);
+
+ // <builtin-type> ::= z # ellipsis
+ if (Proto->isVariadic())
+ Out << 'z';
+}
+
+void CXXNameMangler::mangleType(const TagType *T) {
+ // <class-enum-type> ::= <name>
+
+ if (!T->getDecl()->getIdentifier())
+ mangleName(T->getDecl()->getTypedefForAnonDecl());
+ else
+ mangleName(T->getDecl());
+
+ // If this is a class template specialization, mangle the template
+ // arguments.
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl()))
+ mangleTemplateArgumentList(Spec->getTemplateArgs());
+}
+
+void CXXNameMangler::mangleType(const ArrayType *T) {
+ // <array-type> ::= A <positive dimension number> _ <element type>
+ // ::= A [<dimension expression>] _ <element type>
+ Out << 'A';
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T))
+ Out << CAT->getSize();
+ else if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(T))
+ mangleExpression(VAT->getSizeExpr());
+ else if (const DependentSizedArrayType *DSAT
+ = dyn_cast<DependentSizedArrayType>(T))
+ mangleExpression(DSAT->getSizeExpr());
+
+ Out << '_';
+ mangleType(T->getElementType());
+}
+
+void CXXNameMangler::mangleType(const MemberPointerType *T) {
+ // <pointer-to-member-type> ::= M <class type> <member type>
+ Out << 'M';
+ mangleType(QualType(T->getClass(), 0));
+ QualType PointeeType = T->getPointeeType();
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(PointeeType)) {
+ mangleCVQualifiers(FPT->getTypeQuals());
+ mangleType(FPT);
+ } else
+ mangleType(PointeeType);
+}
+
+void CXXNameMangler::mangleType(const TemplateTypeParmType *T) {
+ // <template-param> ::= T_ # first template parameter
+ // ::= T <parameter-2 non-negative number> _
+ if (T->getIndex() == 0)
+ Out << "T_";
+ else
+ Out << 'T' << (T->getIndex() - 1) << '_';
+}
+
+void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
+ mangleSourceName(T->getDecl()->getIdentifier());
+}
+
+void CXXNameMangler::mangleExpression(Expr *E) {
+ assert(false && "Cannot mangle expressions yet");
+}
+
+void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) {
+ // <ctor-dtor-name> ::= C1 # complete object constructor
+ // ::= C2 # base object constructor
+ // ::= C3 # complete object allocating constructor
+ //
+ switch (T) {
+ case Ctor_Complete:
+ Out << "C1";
+ break;
+ case Ctor_Base:
+ Out << "C2";
+ break;
+ case Ctor_CompleteAllocating:
+ Out << "C3";
+ break;
+ }
+}
+
+void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
+ // <ctor-dtor-name> ::= D0 # deleting destructor
+ // ::= D1 # complete object destructor
+ // ::= D2 # base object destructor
+ //
+ switch (T) {
+ case Dtor_Deleting:
+ Out << "D0";
+ break;
+ case Dtor_Complete:
+ Out << "D1";
+ break;
+ case Dtor_Base:
+ Out << "D2";
+ break;
+ }
+}
+
+void CXXNameMangler::mangleTemplateArgumentList(const TemplateArgumentList &L) {
+ // <template-args> ::= I <template-arg>+ E
+ Out << "I";
+
+ for (unsigned i = 0, e = L.size(); i != e; ++i) {
+ const TemplateArgument &A = L[i];
+
+ mangleTemplateArgument(A);
+ }
+
+ Out << "E";
+}
+
+void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) {
+ // <template-arg> ::= <type> # type or template
+ // ::= X <expression> E # expression
+ // ::= <expr-primary> # simple expressions
+ // ::= I <template-arg>* E # argument pack
+ // ::= sp <expression> # pack expansion of (C++0x)
+ switch (A.getKind()) {
+ default:
+ assert(0 && "Unknown template argument kind!");
+ case TemplateArgument::Type:
+ mangleType(A.getAsType());
+ break;
+ case TemplateArgument::Integral:
+ // <expr-primary> ::= L <type> <value number> E # integer literal
+
+ Out << 'L';
+
+ mangleType(A.getIntegralType());
+
+ const llvm::APSInt *Integral = A.getAsIntegral();
+ if (A.getIntegralType()->isBooleanType()) {
+ // Boolean values are encoded as 0/1.
+ Out << (Integral->getBoolValue() ? '1' : '0');
+ } else {
+ if (Integral->isNegative())
+ Out << 'n';
+ Integral->abs().print(Out, false);
+ }
+
+ Out << 'E';
+ break;
+ }
+}
+
+namespace clang {
+ /// \brief Mangles the name of the declaration D and emits that name
+ /// to the given output stream.
+ ///
+ /// If the declaration D requires a mangled name, this routine will
+ /// emit that mangled name to \p os and return true. Otherwise, \p
+ /// os will be unchanged and this routine will return false. In this
+ /// case, the caller should just emit the identifier of the declaration
+ /// (\c D->getIdentifier()) as its name.
+ bool mangleName(const NamedDecl *D, ASTContext &Context,
+ llvm::raw_ostream &os) {
+ assert(!isa<CXXConstructorDecl>(D) &&
+ "Use mangleCXXCtor for constructor decls!");
+ assert(!isa<CXXDestructorDecl>(D) &&
+ "Use mangleCXXDtor for destructor decls!");
+
+ CXXNameMangler Mangler(Context, os);
+ if (!Mangler.mangle(D))
+ return false;
+
+ os.flush();
+ return true;
+ }
+
+ /// mangleGuardVariable - Returns the mangled name for a guard variable
+ /// for the passed in VarDecl.
+ void mangleGuardVariable(const VarDecl *D, ASTContext &Context,
+ llvm::raw_ostream &os) {
+ CXXNameMangler Mangler(Context, os);
+ Mangler.mangleGuardVariable(D);
+
+ os.flush();
+ }
+
+ void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
+ ASTContext &Context, llvm::raw_ostream &os) {
+ CXXNameMangler Mangler(Context, os);
+ Mangler.mangleCXXCtor(D, Type);
+
+ os.flush();
+ }
+
+ void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
+ ASTContext &Context, llvm::raw_ostream &os) {
+ CXXNameMangler Mangler(Context, os);
+ Mangler.mangleCXXDtor(D, Type);
+
+ os.flush();
+ }
+
+
+}
+
diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h
new file mode 100644
index 000000000000..77cbd9775191
--- /dev/null
+++ b/lib/CodeGen/Mangle.h
@@ -0,0 +1,44 @@
+//===--- Mangle.h - Mangle C++ Names ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements C++ name mangling according to the Itanium C++ ABI,
+// which is used in GCC 3.2 and newer (and many compilers that are
+// ABI-compatible with GCC):
+//
+// http://www.codesourcery.com/public/cxx-abi/abi.html
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGEN_MANGLE_H
+#define LLVM_CLANG_CODEGEN_MANGLE_H
+
+#include "CGCXX.h"
+
+namespace llvm {
+ class raw_ostream;
+}
+
+namespace clang {
+ class ASTContext;
+ class CXXConstructorDecl;
+ class CXXDestructorDecl;
+ class NamedDecl;
+ class VarDecl;
+
+ bool mangleName(const NamedDecl *D, ASTContext &Context,
+ llvm::raw_ostream &os);
+ void mangleGuardVariable(const VarDecl *D, ASTContext &Context,
+ llvm::raw_ostream &os);
+ void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
+ ASTContext &Context, llvm::raw_ostream &os);
+ void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
+ ASTContext &Context, llvm::raw_ostream &os);
+}
+
+#endif
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
new file mode 100644
index 000000000000..9b85df61da05
--- /dev/null
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -0,0 +1,100 @@
+//===--- ModuleBuilder.cpp - Emit LLVM Code from ASTs ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This builds an AST and converts it to LLVM Code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "CodeGenModule.h"
+#include "clang/Frontend/CompileOptions.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/Module.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/ADT/OwningPtr.h"
+using namespace clang;
+
+
+namespace {
+ class VISIBILITY_HIDDEN CodeGeneratorImpl : public CodeGenerator {
+ Diagnostic &Diags;
+ llvm::OwningPtr<const llvm::TargetData> TD;
+ ASTContext *Ctx;
+ const CompileOptions CompileOpts; // Intentionally copied in.
+ protected:
+ llvm::OwningPtr<llvm::Module> M;
+ llvm::OwningPtr<CodeGen::CodeGenModule> Builder;
+ public:
+ CodeGeneratorImpl(Diagnostic &diags, const std::string& ModuleName,
+ const CompileOptions &CO)
+ : Diags(diags), CompileOpts(CO), M(new llvm::Module(ModuleName)) {}
+
+ virtual ~CodeGeneratorImpl() {}
+
+ virtual llvm::Module* GetModule() {
+ return M.get();
+ }
+
+ virtual llvm::Module* ReleaseModule() {
+ return M.take();
+ }
+
+ virtual void Initialize(ASTContext &Context) {
+ Ctx = &Context;
+
+ M->setTargetTriple(Ctx->Target.getTargetTriple());
+ M->setDataLayout(Ctx->Target.getTargetDescription());
+ TD.reset(new llvm::TargetData(Ctx->Target.getTargetDescription()));
+ Builder.reset(new CodeGen::CodeGenModule(Context, CompileOpts,
+ *M, *TD, Diags));
+ }
+
+ virtual void HandleTopLevelDecl(DeclGroupRef DG) {
+ // Make sure to emit all elements of a Decl.
+ for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
+ Builder->EmitTopLevelDecl(*I);
+ }
+
+ /// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
+ /// to (e.g. struct, union, enum, class) is completed. This allows the
+ /// client hack on the type, which can occur at any point in the file
+ /// (because these can be defined in declspecs).
+ virtual void HandleTagDeclDefinition(TagDecl *D) {
+ Builder->UpdateCompletedType(D);
+ }
+
+ virtual void HandleTranslationUnit(ASTContext &Ctx) {
+ if (Diags.hasErrorOccurred()) {
+ M.reset();
+ return;
+ }
+
+ if (Builder)
+ Builder->Release();
+ };
+
+ virtual void CompleteTentativeDefinition(VarDecl *D) {
+ if (Diags.hasErrorOccurred())
+ return;
+
+ Builder->EmitTentativeDefinition(D);
+ }
+ };
+}
+
+CodeGenerator *clang::CreateLLVMCodeGen(Diagnostic &Diags,
+ const std::string& ModuleName,
+ const CompileOptions &CO) {
+ return new CodeGeneratorImpl(Diags, ModuleName, CO);
+}
diff --git a/lib/CodeGen/README.txt b/lib/CodeGen/README.txt
new file mode 100644
index 000000000000..f60cd03ad649
--- /dev/null
+++ b/lib/CodeGen/README.txt
@@ -0,0 +1,65 @@
+IRgen optimization opportunities.
+
+//===---------------------------------------------------------------------===//
+
+The common pattern of
+--
+short x; // or char, etc
+(x == 10)
+--
+generates an zext/sext of x which can easily be avoided.
+
+//===---------------------------------------------------------------------===//
+
+Bitfields accesses can be shifted to simplify masking and sign
+extension. For example, if the bitfield width is 8 and it is
+appropriately aligned then is is a lot shorter to just load the char
+directly.
+
+//===---------------------------------------------------------------------===//
+
+It may be worth avoiding creation of alloca's for formal arguments
+for the common situation where the argument is never written to or has
+its address taken. The idea would be to begin generating code by using
+the argument directly and if its address is taken or it is stored to
+then generate the alloca and patch up the existing code.
+
+In theory, the same optimization could be a win for block local
+variables as long as the declaration dominates all statements in the
+block.
+
+NOTE: The main case we care about this for is for -O0 -g compile time
+performance, and in that scenario we will need to emit the alloca
+anyway currently to emit proper debug info. So this is blocked by
+being able to emit debug information which refers to an LLVM
+temporary, not an alloca.
+
+//===---------------------------------------------------------------------===//
+
+We should try and avoid generating basic blocks which only contain
+jumps. At -O0, this penalizes us all the way from IRgen (malloc &
+instruction overhead), all the way down through code generation and
+assembly time.
+
+On 176.gcc:expr.ll, it looks like over 12% of basic blocks are just
+direct branches!
+
+//===---------------------------------------------------------------------===//
+
+There are some more places where we could avoid generating unreachable code. For
+example:
+ void f0(int a) { abort(); if (a) printf("hi"); }
+still generates a call to printf. This doesn't occur much in real
+code, but would still be nice to clean up.
+
+//===---------------------------------------------------------------------===//
+
+Deferred generation of statics incurs some additional
+overhead. Currently it is even possible to construct test cases with
+O(N^2) behavior! For at least simple cases where we can tell a global
+is used, it is probably not worth deferring it. This doesn't solve the
+O(N^2) cases, ,though...
+
+PR3810
+
+//===---------------------------------------------------------------------===//
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp
new file mode 100644
index 000000000000..cabc33eaec28
--- /dev/null
+++ b/lib/Driver/Action.cpp
@@ -0,0 +1,79 @@
+//===--- Action.cpp - Abstract compilation steps ------------------------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Action.h"
+
+#include <cassert>
+using namespace clang::driver;
+
+Action::~Action() {
+ // FIXME: Free the inputs. The problem is that BindArchAction shares
+ // inputs; so we can't just walk the inputs.
+}
+
+const char *Action::getClassName(ActionClass AC) {
+ switch (AC) {
+ case InputClass: return "input";
+ case BindArchClass: return "bind-arch";
+ case PreprocessJobClass: return "preprocessor";
+ case PrecompileJobClass: return "precompiler";
+ case AnalyzeJobClass: return "analyzer";
+ case CompileJobClass: return "compiler";
+ case AssembleJobClass: return "assembler";
+ case LinkJobClass: return "linker";
+ case LipoJobClass: return "lipo";
+ }
+
+ assert(0 && "invalid class");
+ return 0;
+}
+
+InputAction::InputAction(const Arg &_Input, types::ID _Type)
+ : Action(InputClass, _Type), Input(_Input) {
+}
+
+BindArchAction::BindArchAction(Action *Input, const char *_ArchName)
+ : Action(BindArchClass, Input, Input->getType()), ArchName(_ArchName) {
+}
+
+JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type)
+ : Action(Kind, Input, Type) {
+}
+
+JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
+ : Action(Kind, Inputs, Type) {
+}
+
+PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType)
+ : JobAction(PreprocessJobClass, Input, OutputType) {
+}
+
+PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType)
+ : JobAction(PrecompileJobClass, Input, OutputType) {
+}
+
+AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)
+ : JobAction(AnalyzeJobClass, Input, OutputType) {
+}
+
+CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType)
+ : JobAction(CompileJobClass, Input, OutputType) {
+}
+
+AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
+ : JobAction(AssembleJobClass, Input, OutputType) {
+}
+
+LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type)
+ : JobAction(LinkJobClass, Inputs, Type) {
+}
+
+LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type)
+ : JobAction(LipoJobClass, Inputs, Type) {
+}
diff --git a/lib/Driver/Arg.cpp b/lib/Driver/Arg.cpp
new file mode 100644
index 000000000000..e227d7e2ea15
--- /dev/null
+++ b/lib/Driver/Arg.cpp
@@ -0,0 +1,192 @@
+//===--- Arg.cpp - Argument Implementations -----------------------------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Option.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang::driver;
+
+Arg::Arg(ArgClass _Kind, const Option *_Opt, unsigned _Index,
+ const Arg *_BaseArg)
+ : Kind(_Kind), Opt(_Opt), BaseArg(_BaseArg), Index(_Index), Claimed(false)
+{
+}
+
+Arg::~Arg() { }
+
+void Arg::dump() const {
+ llvm::errs() << "<";
+ switch (Kind) {
+ default:
+ assert(0 && "Invalid kind");
+#define P(N) case N: llvm::errs() << #N; break
+ P(FlagClass);
+ P(PositionalClass);
+ P(JoinedClass);
+ P(SeparateClass);
+ P(CommaJoinedClass);
+ P(JoinedAndSeparateClass);
+#undef P
+ }
+
+ llvm::errs() << " Opt:";
+ Opt->dump();
+
+ llvm::errs() << " Index:" << Index;
+
+ if (isa<CommaJoinedArg>(this) || isa<SeparateArg>(this))
+ llvm::errs() << " NumValues:" << getNumValues();
+
+ llvm::errs() << ">\n";
+}
+
+std::string Arg::getAsString(const ArgList &Args) const {
+ std::string Res;
+ llvm::raw_string_ostream OS(Res);
+
+ ArgStringList ASL;
+ render(Args, ASL);
+ for (ArgStringList::iterator
+ it = ASL.begin(), ie = ASL.end(); it != ie; ++it) {
+ if (it != ASL.begin())
+ OS << ' ';
+ OS << *it;
+ }
+
+ return OS.str();
+}
+
+void Arg::renderAsInput(const ArgList &Args, ArgStringList &Output) const {
+ if (!getOption().hasNoOptAsInput()) {
+ render(Args, Output);
+ return;
+ }
+
+ for (unsigned i = 0, e = getNumValues(); i != e; ++i)
+ Output.push_back(getValue(Args, i));
+}
+
+FlagArg::FlagArg(const Option *Opt, unsigned Index, const Arg *BaseArg)
+ : Arg(FlagClass, Opt, Index, BaseArg) {
+}
+
+void FlagArg::render(const ArgList &Args, ArgStringList &Output) const {
+ Output.push_back(Args.getArgString(getIndex()));
+}
+
+const char *FlagArg::getValue(const ArgList &Args, unsigned N) const {
+ assert(0 && "Invalid index.");
+ return 0;
+}
+
+PositionalArg::PositionalArg(const Option *Opt, unsigned Index,
+ const Arg *BaseArg)
+ : Arg(PositionalClass, Opt, Index, BaseArg) {
+}
+
+void PositionalArg::render(const ArgList &Args, ArgStringList &Output) const {
+ Output.push_back(Args.getArgString(getIndex()));
+}
+
+const char *PositionalArg::getValue(const ArgList &Args, unsigned N) const {
+ assert(N < getNumValues() && "Invalid index.");
+ return Args.getArgString(getIndex());
+}
+
+JoinedArg::JoinedArg(const Option *Opt, unsigned Index, const Arg *BaseArg)
+ : Arg(JoinedClass, Opt, Index, BaseArg) {
+}
+
+void JoinedArg::render(const ArgList &Args, ArgStringList &Output) const {
+ if (getOption().hasForceSeparateRender()) {
+ Output.push_back(getOption().getName());
+ Output.push_back(getValue(Args, 0));
+ } else {
+ Output.push_back(Args.getArgString(getIndex()));
+ }
+}
+
+const char *JoinedArg::getValue(const ArgList &Args, unsigned N) const {
+ assert(N < getNumValues() && "Invalid index.");
+ // FIXME: Avoid strlen.
+ return Args.getArgString(getIndex()) + strlen(getOption().getName());
+}
+
+CommaJoinedArg::CommaJoinedArg(const Option *Opt, unsigned Index,
+ const char *Str, const Arg *BaseArg)
+ : Arg(CommaJoinedClass, Opt, Index, BaseArg) {
+ const char *Prev = Str;
+ for (;; ++Str) {
+ char c = *Str;
+
+ if (!c) {
+ if (Prev != Str)
+ Values.push_back(std::string(Prev, Str));
+ break;
+ } else if (c == ',') {
+ if (Prev != Str)
+ Values.push_back(std::string(Prev, Str));
+ Prev = Str + 1;
+ }
+ }
+}
+
+void CommaJoinedArg::render(const ArgList &Args, ArgStringList &Output) const {
+ Output.push_back(Args.getArgString(getIndex()));
+}
+
+const char *CommaJoinedArg::getValue(const ArgList &Args, unsigned N) const {
+ assert(N < getNumValues() && "Invalid index.");
+ return Values[N].c_str();
+}
+
+SeparateArg::SeparateArg(const Option *Opt, unsigned Index, unsigned _NumValues,
+ const Arg *BaseArg)
+ : Arg(SeparateClass, Opt, Index, BaseArg), NumValues(_NumValues) {
+}
+
+void SeparateArg::render(const ArgList &Args, ArgStringList &Output) const {
+ if (getOption().hasForceJoinedRender()) {
+ assert(getNumValues() == 1 && "Cannot force joined render with > 1 args.");
+ // FIXME: Avoid std::string.
+ std::string Joined(getOption().getName());
+ Joined += Args.getArgString(getIndex());
+ Output.push_back(Args.MakeArgString(Joined.c_str()));
+ } else {
+ Output.push_back(Args.getArgString(getIndex()));
+ for (unsigned i = 0; i < NumValues; ++i)
+ Output.push_back(Args.getArgString(getIndex() + 1 + i));
+ }
+}
+
+const char *SeparateArg::getValue(const ArgList &Args, unsigned N) const {
+ assert(N < getNumValues() && "Invalid index.");
+ return Args.getArgString(getIndex() + 1 + N);
+}
+
+JoinedAndSeparateArg::JoinedAndSeparateArg(const Option *Opt, unsigned Index,
+ const Arg *BaseArg)
+ : Arg(JoinedAndSeparateClass, Opt, Index, BaseArg) {
+}
+
+void JoinedAndSeparateArg::render(const ArgList &Args,
+ ArgStringList &Output) const {
+ Output.push_back(Args.getArgString(getIndex()));
+ Output.push_back(Args.getArgString(getIndex() + 1));
+}
+
+const char *JoinedAndSeparateArg::getValue(const ArgList &Args,
+ unsigned N) const {
+ assert(N < getNumValues() && "Invalid index.");
+ if (N == 0)
+ return Args.getArgString(getIndex()) + strlen(getOption().getName());
+ return Args.getArgString(getIndex() + 1);
+}
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
new file mode 100644
index 000000000000..593694cfbbf6
--- /dev/null
+++ b/lib/Driver/ArgList.cpp
@@ -0,0 +1,232 @@
+//===--- ArgList.cpp - Argument List Management -------------------------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/Option.h"
+
+using namespace clang::driver;
+
+ArgList::ArgList(arglist_type &_Args) : Args(_Args) {
+}
+
+ArgList::~ArgList() {
+}
+
+void ArgList::append(Arg *A) {
+ Args.push_back(A);
+}
+
+Arg *ArgList::getLastArg(options::ID Id, bool Claim) const {
+ // FIXME: Make search efficient?
+ for (const_reverse_iterator it = rbegin(), ie = rend(); it != ie; ++it) {
+ if ((*it)->getOption().matches(Id)) {
+ if (Claim) (*it)->claim();
+ return *it;
+ }
+ }
+
+ return 0;
+}
+
+Arg *ArgList::getLastArg(options::ID Id0, options::ID Id1, bool Claim) const {
+ Arg *Res, *A0 = getLastArg(Id0, false), *A1 = getLastArg(Id1, false);
+
+ if (A0 && A1)
+ Res = A0->getIndex() > A1->getIndex() ? A0 : A1;
+ else
+ Res = A0 ? A0 : A1;
+
+ if (Claim && Res)
+ Res->claim();
+
+ return Res;
+}
+
+bool ArgList::hasFlag(options::ID Pos, options::ID Neg, bool Default) const {
+ if (Arg *A = getLastArg(Pos, Neg))
+ return A->getOption().matches(Pos);
+ return Default;
+}
+
+void ArgList::AddLastArg(ArgStringList &Output, options::ID Id) const {
+ if (Arg *A = getLastArg(Id)) {
+ A->claim();
+ A->render(*this, Output);
+ }
+}
+
+void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0) const {
+ // FIXME: Make fast.
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ const Arg *A = *it;
+ if (A->getOption().matches(Id0)) {
+ A->claim();
+ A->render(*this, Output);
+ }
+ }
+}
+
+void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0,
+ options::ID Id1) const {
+ // FIXME: Make fast.
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ const Arg *A = *it;
+ if (A->getOption().matches(Id0) || A->getOption().matches(Id1)) {
+ A->claim();
+ A->render(*this, Output);
+ }
+ }
+}
+
+void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0,
+ options::ID Id1, options::ID Id2) const {
+ // FIXME: Make fast.
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ const Arg *A = *it;
+ if (A->getOption().matches(Id0) || A->getOption().matches(Id1) ||
+ A->getOption().matches(Id2)) {
+ A->claim();
+ A->render(*this, Output);
+ }
+ }
+}
+
+void ArgList::AddAllArgValues(ArgStringList &Output, options::ID Id0) const {
+ // FIXME: Make fast.
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ const Arg *A = *it;
+ if (A->getOption().matches(Id0)) {
+ A->claim();
+ for (unsigned i = 0, e = A->getNumValues(); i != e; ++i)
+ Output.push_back(A->getValue(*this, i));
+ }
+ }
+}
+
+void ArgList::AddAllArgValues(ArgStringList &Output, options::ID Id0,
+ options::ID Id1) const {
+ // FIXME: Make fast.
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ const Arg *A = *it;
+ if (A->getOption().matches(Id0) || A->getOption().matches(Id1)) {
+ A->claim();
+ for (unsigned i = 0, e = A->getNumValues(); i != e; ++i)
+ Output.push_back(A->getValue(*this, i));
+ }
+ }
+}
+
+void ArgList::AddAllArgsTranslated(ArgStringList &Output, options::ID Id0,
+ const char *Translation,
+ bool Joined) const {
+ // FIXME: Make fast.
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ const Arg *A = *it;
+ if (A->getOption().matches(Id0)) {
+ A->claim();
+
+ if (Joined) {
+ std::string Value = Translation;
+ Value += A->getValue(*this, 0);
+ Output.push_back(MakeArgString(Value.c_str()));
+ } else {
+ Output.push_back(Translation);
+ Output.push_back(A->getValue(*this, 0));
+ }
+ }
+ }
+}
+
+void ArgList::ClaimAllArgs(options::ID Id0) const {
+ // FIXME: Make fast.
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ const Arg *A = *it;
+ if (A->getOption().matches(Id0))
+ A->claim();
+ }
+}
+
+//
+
+InputArgList::InputArgList(const char **ArgBegin, const char **ArgEnd)
+ : ArgList(ActualArgs), NumInputArgStrings(ArgEnd - ArgBegin)
+{
+ ArgStrings.append(ArgBegin, ArgEnd);
+}
+
+InputArgList::~InputArgList() {
+ // An InputArgList always owns its arguments.
+ for (iterator it = begin(), ie = end(); it != ie; ++it)
+ delete *it;
+}
+
+unsigned InputArgList::MakeIndex(const char *String0) const {
+ unsigned Index = ArgStrings.size();
+
+ // Tuck away so we have a reliable const char *.
+ SynthesizedStrings.push_back(String0);
+ ArgStrings.push_back(SynthesizedStrings.back().c_str());
+
+ return Index;
+}
+
+unsigned InputArgList::MakeIndex(const char *String0,
+ const char *String1) const {
+ unsigned Index0 = MakeIndex(String0);
+ unsigned Index1 = MakeIndex(String1);
+ assert(Index0 + 1 == Index1 && "Unexpected non-consecutive indices!");
+ (void) Index1;
+ return Index0;
+}
+
+const char *InputArgList::MakeArgString(const char *Str) const {
+ return getArgString(MakeIndex(Str));
+}
+
+//
+
+DerivedArgList::DerivedArgList(InputArgList &_BaseArgs, bool _OnlyProxy)
+ : ArgList(_OnlyProxy ? _BaseArgs.getArgs() : ActualArgs),
+ BaseArgs(_BaseArgs), OnlyProxy(_OnlyProxy)
+{
+}
+
+DerivedArgList::~DerivedArgList() {
+ // We only own the arguments we explicitly synthesized.
+ for (iterator it = SynthesizedArgs.begin(), ie = SynthesizedArgs.end();
+ it != ie; ++it)
+ delete *it;
+}
+
+const char *DerivedArgList::MakeArgString(const char *Str) const {
+ return BaseArgs.MakeArgString(Str);
+}
+
+Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option *Opt) const {
+ return new FlagArg(Opt, BaseArgs.MakeIndex(Opt->getName()), BaseArg);
+}
+
+Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option *Opt,
+ const char *Value) const {
+ return new PositionalArg(Opt, BaseArgs.MakeIndex(Value), BaseArg);
+}
+
+Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option *Opt,
+ const char *Value) const {
+ return new SeparateArg(Opt, BaseArgs.MakeIndex(Opt->getName(), Value), 1,
+ BaseArg);
+}
+
+Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option *Opt,
+ const char *Value) const {
+ std::string Joined(Opt->getName());
+ Joined += Value;
+ return new JoinedArg(Opt, BaseArgs.MakeIndex(Joined.c_str()), BaseArg);
+}
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
new file mode 100644
index 000000000000..7147d8f0be60
--- /dev/null
+++ b/lib/Driver/CMakeLists.txt
@@ -0,0 +1,19 @@
+set(LLVM_NO_RTTI 1)
+
+add_clang_library(clangDriver
+ Action.cpp
+ Arg.cpp
+ ArgList.cpp
+ Compilation.cpp
+ Driver.cpp
+ HostInfo.cpp
+ Job.cpp
+ OptTable.cpp
+ Option.cpp
+ Phases.cpp
+ Tool.cpp
+ ToolChain.cpp
+ ToolChains.cpp
+ Tools.cpp
+ Types.cpp
+ )
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
new file mode 100644
index 000000000000..1e044c6b8fdc
--- /dev/null
+++ b/lib/Driver/Compilation.cpp
@@ -0,0 +1,174 @@
+//===--- Compilation.cpp - Compilation Task Implementation --------------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Compilation.h"
+
+#include "clang/Driver/Action.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/ToolChain.h"
+
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Program.h"
+#include <sys/stat.h>
+#include <errno.h>
+using namespace clang::driver;
+
+Compilation::Compilation(Driver &D,
+ ToolChain &_DefaultToolChain,
+ InputArgList *_Args)
+ : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args) {
+}
+
+Compilation::~Compilation() {
+ delete Args;
+
+ // Free any derived arg lists.
+ for (llvm::DenseMap<const ToolChain*, DerivedArgList*>::iterator
+ it = TCArgs.begin(), ie = TCArgs.end(); it != ie; ++it)
+ delete it->second;
+
+ // Free the actions, if built.
+ for (ActionList::iterator it = Actions.begin(), ie = Actions.end();
+ it != ie; ++it)
+ delete *it;
+}
+
+const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC) {
+ if (!TC)
+ TC = &DefaultToolChain;
+
+ DerivedArgList *&Entry = TCArgs[TC];
+ if (!Entry)
+ Entry = TC->TranslateArgs(*Args);
+
+ return *Entry;
+}
+
+void Compilation::PrintJob(llvm::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) {
+ if (Quote)
+ OS << " \"" << *it << '"';
+ else
+ OS << ' ' << *it;
+ }
+ OS << Terminator;
+ } else if (const PipedJob *PJ = dyn_cast<PipedJob>(&J)) {
+ for (PipedJob::const_iterator
+ it = PJ->begin(), ie = PJ->end(); it != ie; ++it)
+ PrintJob(OS, **it, (it + 1 != PJ->end()) ? " |\n" : "\n", Quote);
+ } else {
+ const JobList *Jobs = cast<JobList>(&J);
+ for (JobList::const_iterator
+ it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
+ PrintJob(OS, **it, Terminator, Quote);
+ }
+}
+
+bool Compilation::CleanupFileList(const ArgStringList &Files,
+ bool IssueErrors) const {
+ bool Success = true;
+
+ for (ArgStringList::const_iterator
+ it = Files.begin(), ie = Files.end(); it != ie; ++it) {
+ llvm::sys::Path P(*it);
+ std::string Error;
+
+ if (P.eraseFromDisk(false, &Error)) {
+ // Failure is only failure if the file doesn't exist. There is a
+ // race condition here due to the limited interface of
+ // llvm::sys::Path, we want to know if the removal gave E_NOENT.
+
+ // FIXME: Grumble, P.exists() is broken. PR3837.
+ struct stat buf;
+ if (::stat(P.c_str(), &buf) == 0
+ || errno != ENOENT) {
+ if (IssueErrors)
+ getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
+ << Error;
+ Success = false;
+ }
+ }
+ }
+
+ return Success;
+}
+
+int Compilation::ExecuteCommand(const Command &C) const {
+ llvm::sys::Path Prog(C.getExecutable());
+ const char **Argv = new const char*[C.getArguments().size() + 2];
+ Argv[0] = C.getExecutable();
+ std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1);
+ Argv[C.getArguments().size() + 1] = 0;
+
+ if (getDriver().CCCEcho || getArgs().hasArg(options::OPT_v))
+ PrintJob(llvm::errs(), C, "\n", false);
+
+ std::string Error;
+ int Res =
+ llvm::sys::Program::ExecuteAndWait(Prog, Argv,
+ /*env*/0, /*redirects*/0,
+ /*secondsToWait*/0, /*memoryLimit*/0,
+ &Error);
+ if (!Error.empty()) {
+ assert(Res && "Error string set with 0 result code!");
+ getDriver().Diag(clang::diag::err_drv_command_failure) << Error;
+ }
+
+ delete[] Argv;
+ return Res;
+}
+
+int Compilation::ExecuteJob(const Job &J) const {
+ if (const Command *C = dyn_cast<Command>(&J)) {
+ return ExecuteCommand(*C);
+ } else if (const PipedJob *PJ = dyn_cast<PipedJob>(&J)) {
+ // Piped commands with a single job are easy.
+ if (PJ->size() == 1)
+ return ExecuteCommand(**PJ->begin());
+
+ getDriver().Diag(clang::diag::err_drv_unsupported_opt) << "-pipe";
+ return 1;
+ } else {
+ const JobList *Jobs = cast<JobList>(&J);
+ for (JobList::const_iterator
+ it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
+ if (int Res = ExecuteJob(**it))
+ return Res;
+ return 0;
+ }
+}
+
+int Compilation::Execute() const {
+ // Just print if -### was present.
+ if (getArgs().hasArg(options::OPT__HASH_HASH_HASH)) {
+ PrintJob(llvm::errs(), Jobs, "\n", true);
+ return 0;
+ }
+
+ // If there were errors building the compilation, quit now.
+ if (getDriver().getDiags().getNumErrors())
+ return 1;
+
+ int Res = ExecuteJob(Jobs);
+
+ // Remove temp files.
+ CleanupFileList(TempFiles);
+
+ // If the compilation failed, remove result files as well.
+ if (Res != 0 && !getArgs().hasArg(options::OPT_save_temps))
+ CleanupFileList(ResultFiles, true);
+
+ return Res;
+}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
new file mode 100644
index 000000000000..d8c6a0aeead6
--- /dev/null
+++ b/lib/Driver/Driver.cpp
@@ -0,0 +1,1254 @@
+//===--- Driver.cpp - Clang GCC Compatible Driver -----------------------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Driver.h"
+
+#include "clang/Driver/Action.h"
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/HostInfo.h"
+#include "clang/Driver/Job.h"
+#include "clang/Driver/Option.h"
+#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"
+
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+#include "llvm/System/Program.h"
+
+#include "InputInfo.h"
+
+#include <map>
+
+using namespace clang::driver;
+using namespace clang;
+
+Driver::Driver(const char *_Name, const char *_Dir,
+ const char *_DefaultHostTriple,
+ const char *_DefaultImageName,
+ Diagnostic &_Diags)
+ : Opts(new OptTable()), Diags(_Diags),
+ Name(_Name), Dir(_Dir), DefaultHostTriple(_DefaultHostTriple),
+ DefaultImageName(_DefaultImageName),
+ Host(0),
+ CCCIsCXX(false), CCCEcho(false), CCCPrintBindings(false),
+ CCCGenericGCCName("gcc"), CCCUseClang(true), CCCUseClangCXX(false),
+ CCCUseClangCPP(true), CCCUsePCH(true),
+ SuppressMissingInputWarning(false)
+{
+ // Only use clang on i386 and x86_64 by default.
+ CCCClangArchs.insert("i386");
+ CCCClangArchs.insert("x86_64");
+}
+
+Driver::~Driver() {
+ delete Opts;
+ delete Host;
+}
+
+InputArgList *Driver::ParseArgStrings(const char **ArgBegin,
+ const char **ArgEnd) {
+ llvm::PrettyStackTraceString CrashInfo("Command line argument parsing");
+ InputArgList *Args = new InputArgList(ArgBegin, ArgEnd);
+
+ // FIXME: Handle '@' args (or at least error on them).
+
+ unsigned Index = 0, End = ArgEnd - ArgBegin;
+ while (Index < End) {
+ // gcc's handling of empty arguments doesn't make
+ // sense, but this is not a common use case. :)
+ //
+ // We just ignore them here (note that other things may
+ // still take them as arguments).
+ if (Args->getArgString(Index)[0] == '\0') {
+ ++Index;
+ continue;
+ }
+
+ unsigned Prev = Index;
+ Arg *A = getOpts().ParseOneArg(*Args, Index);
+ assert(Index > Prev && "Parser failed to consume argument.");
+
+ // Check for missing argument error.
+ if (!A) {
+ assert(Index >= End && "Unexpected parser error.");
+ Diag(clang::diag::err_drv_missing_argument)
+ << Args->getArgString(Prev)
+ << (Index - Prev - 1);
+ break;
+ }
+
+ if (A->getOption().isUnsupported()) {
+ Diag(clang::diag::err_drv_unsupported_opt) << A->getAsString(*Args);
+ continue;
+ }
+ Args->append(A);
+ }
+
+ return Args;
+}
+
+Compilation *Driver::BuildCompilation(int argc, const char **argv) {
+ 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, QA_OVERRIDE_GCC3_OPTIONS.
+
+ // FIXME: What are we going to do with -V and -b?
+
+ // FIXME: This stuff needs to go into the Compilation, not the
+ // driver.
+ bool CCCPrintOptions = false, CCCPrintActions = false;
+
+ const char **Start = argv + 1, **End = argv + argc;
+ const char *HostTriple = DefaultHostTriple.c_str();
+
+ // Read -ccc args.
+ //
+ // FIXME: We need to figure out where this behavior should
+ // live. Most of it should be outside in the client; the parts that
+ // aren't should have proper options, either by introducing new ones
+ // or by overloading gcc ones like -V or -b.
+ for (; Start != End && memcmp(*Start, "-ccc-", 5) == 0; ++Start) {
+ const char *Opt = *Start + 5;
+
+ if (!strcmp(Opt, "print-options")) {
+ CCCPrintOptions = true;
+ } else if (!strcmp(Opt, "print-phases")) {
+ CCCPrintActions = true;
+ } else if (!strcmp(Opt, "print-bindings")) {
+ CCCPrintBindings = true;
+ } else if (!strcmp(Opt, "cxx")) {
+ CCCIsCXX = true;
+ } else if (!strcmp(Opt, "echo")) {
+ CCCEcho = true;
+
+ } else if (!strcmp(Opt, "gcc-name")) {
+ assert(Start+1 < End && "FIXME: -ccc- argument handling.");
+ CCCGenericGCCName = *++Start;
+
+ } else if (!strcmp(Opt, "clang-cxx")) {
+ CCCUseClangCXX = true;
+ } else if (!strcmp(Opt, "pch-is-pch")) {
+ CCCUsePCH = true;
+ } else if (!strcmp(Opt, "pch-is-pth")) {
+ CCCUsePCH = false;
+ } else if (!strcmp(Opt, "no-clang")) {
+ CCCUseClang = false;
+ } else if (!strcmp(Opt, "no-clang-cpp")) {
+ CCCUseClangCPP = false;
+ } else if (!strcmp(Opt, "clang-archs")) {
+ assert(Start+1 < End && "FIXME: -ccc- argument handling.");
+ const char *Cur = *++Start;
+
+ CCCClangArchs.clear();
+ for (;;) {
+ const char *Next = strchr(Cur, ',');
+
+ if (Next) {
+ if (Cur != Next)
+ CCCClangArchs.insert(std::string(Cur, Next));
+ Cur = Next + 1;
+ } else {
+ if (*Cur != '\0')
+ CCCClangArchs.insert(std::string(Cur));
+ break;
+ }
+ }
+
+ } else if (!strcmp(Opt, "host-triple")) {
+ assert(Start+1 < End && "FIXME: -ccc- argument handling.");
+ HostTriple = *++Start;
+
+ } else {
+ // FIXME: Error handling.
+ llvm::errs() << "invalid option: " << *Start << "\n";
+ exit(1);
+ }
+ }
+
+ InputArgList *Args = ParseArgStrings(Start, End);
+
+ Host = GetHostInfo(HostTriple);
+
+ // The compilation takes ownership of Args.
+ Compilation *C = new Compilation(*this, *Host->getToolChain(*Args), Args);
+
+ // FIXME: This behavior shouldn't be here.
+ if (CCCPrintOptions) {
+ PrintOptions(C->getArgs());
+ return C;
+ }
+
+ if (!HandleImmediateArgs(*C))
+ return C;
+
+ // Construct the list of abstract actions to perform for this
+ // compilation. We avoid passing a Compilation here simply to
+ // enforce the abstraction that pipelining is not host or toolchain
+ // dependent (other than the driver driver test).
+ if (Host->useDriverDriver())
+ BuildUniversalActions(C->getArgs(), C->getActions());
+ else
+ BuildActions(C->getArgs(), C->getActions());
+
+ if (CCCPrintActions) {
+ PrintActions(*C);
+ return C;
+ }
+
+ BuildJobs(*C);
+
+ return C;
+}
+
+void Driver::PrintOptions(const ArgList &Args) const {
+ unsigned i = 0;
+ for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
+ it != ie; ++it, ++i) {
+ Arg *A = *it;
+ llvm::errs() << "Option " << i << " - "
+ << "Name: \"" << A->getOption().getName() << "\", "
+ << "Values: {";
+ for (unsigned j = 0; j < A->getNumValues(); ++j) {
+ if (j)
+ llvm::errs() << ", ";
+ llvm::errs() << '"' << A->getValue(Args, j) << '"';
+ }
+ llvm::errs() << "}\n";
+ }
+}
+
+static std::string getOptionHelpName(const OptTable &Opts, options::ID Id) {
+ std::string Name = Opts.getOptionName(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.");
+
+ case Option::MultiArgClass: case Option::JoinedAndSeparateClass:
+ assert(0 && "Cannot print metavar for this kind of option.");
+
+ case Option::FlagClass:
+ break;
+
+ case Option::SeparateClass: case Option::JoinedOrSeparateClass:
+ Name += ' ';
+ // FALLTHROUGH
+ case Option::JoinedClass: case Option::CommaJoinedClass:
+ Name += Opts.getOptionMetaVar(Id);
+ break;
+ }
+
+ return Name;
+}
+
+void Driver::PrintHelp(bool ShowHidden) const {
+ llvm::raw_ostream &OS = llvm::outs();
+
+ OS << "OVERVIEW: clang \"gcc-compatible\" driver\n";
+ OS << '\n';
+ OS << "USAGE: " << Name << " [options] <input files>\n";
+ OS << '\n';
+ OS << "OPTIONS:\n";
+
+ // Render help text into (option, help) pairs.
+ std::vector< std::pair<std::string, const char*> > OptionHelp;
+
+ for (unsigned i = options::OPT_INPUT, e = options::LastOption; i != e; ++i) {
+ options::ID Id = (options::ID) i;
+ if (const char *Text = getOpts().getOptionHelpText(Id))
+ OptionHelp.push_back(std::make_pair(getOptionHelpName(getOpts(), Id),
+ Text));
+ }
+
+ if (ShowHidden) {
+ OptionHelp.push_back(std::make_pair("\nDRIVER OPTIONS:",""));
+ OptionHelp.push_back(std::make_pair("-ccc-cxx",
+ "Act as a C++ driver"));
+ OptionHelp.push_back(std::make_pair("-ccc-gcc-name",
+ "Name for native GCC compiler"));
+ OptionHelp.push_back(std::make_pair("-ccc-clang-cxx",
+ "Use the clang compiler for C++"));
+ OptionHelp.push_back(std::make_pair("-ccc-no-clang",
+ "Never use the clang compiler"));
+ OptionHelp.push_back(std::make_pair("-ccc-no-clang-cpp",
+ "Never use the clang preprocessor"));
+ OptionHelp.push_back(std::make_pair("-ccc-clang-archs",
+ "Comma separate list of architectures "
+ "to use the clang compiler for"));
+ OptionHelp.push_back(std::make_pair("-ccc-pch-is-pch",
+ "Use lazy PCH for precompiled headers"));
+ OptionHelp.push_back(std::make_pair("-ccc-pch-is-pth",
+ "Use pretokenized headers for precompiled headers"));
+
+ OptionHelp.push_back(std::make_pair("\nDEBUG/DEVELOPMENT OPTIONS:",""));
+ OptionHelp.push_back(std::make_pair("-ccc-host-triple",
+ "Simulate running on the given target"));
+ OptionHelp.push_back(std::make_pair("-ccc-print-options",
+ "Dump parsed command line arguments"));
+ OptionHelp.push_back(std::make_pair("-ccc-print-phases",
+ "Dump list of actions to perform"));
+ OptionHelp.push_back(std::make_pair("-ccc-print-bindings",
+ "Show bindings of tools to actions"));
+ OptionHelp.push_back(std::make_pair("CCC_ADD_ARGS",
+ "(ENVIRONMENT VARIABLE) Comma separated list of "
+ "arguments to prepend to the command line"));
+ }
+
+ // Find the maximum option length.
+ unsigned OptionFieldWidth = 0;
+ for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
+ // Skip titles.
+ if (!OptionHelp[i].second)
+ continue;
+
+ // Limit the amount of padding we are willing to give up for
+ // alignment.
+ unsigned Length = OptionHelp[i].first.size();
+ if (Length <= 23)
+ OptionFieldWidth = std::max(OptionFieldWidth, Length);
+ }
+
+ for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
+ const std::string &Option = OptionHelp[i].first;
+ OS << " " << Option;
+ for (int j = Option.length(), e = OptionFieldWidth; j < e; ++j)
+ OS << ' ';
+ OS << ' ' << OptionHelp[i].second << '\n';
+ }
+
+ OS.flush();
+}
+
+void Driver::PrintVersion(const Compilation &C) const {
+ static char buf[] = "$URL: https://ed@llvm.org/svn/llvm-project/cfe/trunk/lib/Driver/Driver.cpp $";
+ char *zap = strstr(buf, "/lib/Driver");
+ if (zap)
+ *zap = 0;
+ zap = strstr(buf, "/clang/tools/clang");
+ if (zap)
+ *zap = 0;
+ const char *vers = buf+6;
+ // FIXME: Add cmake support and remove #ifdef
+#ifdef SVN_REVISION
+ const char *revision = SVN_REVISION;
+#else
+ const char *revision = "";
+#endif
+ // FIXME: The following handlers should use a callback mechanism, we
+ // don't know what the client would like to do.
+
+ llvm::errs() << "clang version " CLANG_VERSION_STRING " ("
+ << vers << " " << revision << ")" << "\n";
+
+ const ToolChain &TC = C.getDefaultToolChain();
+ llvm::errs() << "Target: " << TC.getTripleString() << '\n';
+}
+
+bool Driver::HandleImmediateArgs(const Compilation &C) {
+ // The order these options are handled in in gcc is all over the
+ // place, but we don't expect inconsistencies w.r.t. that to matter
+ // in practice.
+
+ if (C.getArgs().hasArg(options::OPT_dumpversion)) {
+ llvm::outs() << CLANG_VERSION_STRING "\n";
+ return false;
+ }
+
+ if (C.getArgs().hasArg(options::OPT__help) ||
+ C.getArgs().hasArg(options::OPT__help_hidden)) {
+ PrintHelp(C.getArgs().hasArg(options::OPT__help_hidden));
+ return false;
+ }
+
+ if (C.getArgs().hasArg(options::OPT__version)) {
+ PrintVersion(C);
+ return false;
+ }
+
+ if (C.getArgs().hasArg(options::OPT_v) ||
+ C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) {
+ PrintVersion(C);
+ SuppressMissingInputWarning = true;
+ }
+
+ const ToolChain &TC = C.getDefaultToolChain();
+ if (C.getArgs().hasArg(options::OPT_print_search_dirs)) {
+ llvm::outs() << "programs: =";
+ for (ToolChain::path_list::const_iterator it = TC.getProgramPaths().begin(),
+ ie = TC.getProgramPaths().end(); it != ie; ++it) {
+ if (it != TC.getProgramPaths().begin())
+ llvm::outs() << ':';
+ llvm::outs() << *it;
+ }
+ llvm::outs() << "\n";
+ llvm::outs() << "libraries: =";
+ 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() << *it;
+ }
+ llvm::outs() << "\n";
+ return false;
+ }
+
+ // FIXME: The following handlers should use a callback mechanism, we
+ // don't know what the client would like to do.
+ if (Arg *A = C.getArgs().getLastArg(options::OPT_print_file_name_EQ)) {
+ llvm::outs() << GetFilePath(A->getValue(C.getArgs()), TC).toString()
+ << "\n";
+ return false;
+ }
+
+ if (Arg *A = C.getArgs().getLastArg(options::OPT_print_prog_name_EQ)) {
+ llvm::outs() << GetProgramPath(A->getValue(C.getArgs()), TC).toString()
+ << "\n";
+ return false;
+ }
+
+ if (C.getArgs().hasArg(options::OPT_print_libgcc_file_name)) {
+ llvm::outs() << GetFilePath("libgcc.a", TC).toString() << "\n";
+ return false;
+ }
+
+ return true;
+}
+
+static unsigned PrintActions1(const Compilation &C,
+ Action *A,
+ std::map<Action*, unsigned> &Ids) {
+ if (Ids.count(A))
+ return Ids[A];
+
+ std::string str;
+ llvm::raw_string_ostream os(str);
+
+ os << Action::getClassName(A->getKind()) << ", ";
+ if (InputAction *IA = dyn_cast<InputAction>(A)) {
+ os << "\"" << IA->getInputArg().getValue(C.getArgs()) << "\"";
+ } else if (BindArchAction *BIA = dyn_cast<BindArchAction>(A)) {
+ os << '"' << (BIA->getArchName() ? BIA->getArchName() :
+ C.getDefaultToolChain().getArchName()) << '"'
+ << ", {" << PrintActions1(C, *BIA->begin(), Ids) << "}";
+ } else {
+ os << "{";
+ for (Action::iterator it = A->begin(), ie = A->end(); it != ie;) {
+ os << PrintActions1(C, *it, Ids);
+ ++it;
+ if (it != ie)
+ os << ", ";
+ }
+ os << "}";
+ }
+
+ unsigned Id = Ids.size();
+ Ids[A] = Id;
+ llvm::errs() << Id << ": " << os.str() << ", "
+ << types::getTypeName(A->getType()) << "\n";
+
+ return Id;
+}
+
+void Driver::PrintActions(const Compilation &C) const {
+ std::map<Action*, unsigned> Ids;
+ for (ActionList::const_iterator it = C.getActions().begin(),
+ ie = C.getActions().end(); it != ie; ++it)
+ PrintActions1(C, *it, Ids);
+}
+
+void Driver::BuildUniversalActions(const ArgList &Args,
+ ActionList &Actions) const {
+ llvm::PrettyStackTraceString CrashInfo("Building actions for universal build");
+ // 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;
+ for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
+ it != ie; ++it) {
+ Arg *A = *it;
+
+ if (A->getOption().getId() == options::OPT_arch) {
+ const char *Name = A->getValue(Args);
+
+ // FIXME: We need to handle canonicalization of the specified
+ // arch?
+
+ A->claim();
+ if (ArchNames.insert(Name))
+ Archs.push_back(Name);
+ }
+ }
+
+ // When there is no explicit arch for this platform, make sure we
+ // still bind the architecture (to the default) so that -Xarch_ is
+ // handled correctly.
+ if (!Archs.size())
+ Archs.push_back(0);
+
+ // FIXME: We killed off some others but these aren't yet detected in
+ // a functional manner. If we added information to jobs about which
+ // "auxiliary" files they wrote then we could detect the conflict
+ // these cause downstream.
+ if (Archs.size() > 1) {
+ // No recovery needed, the point of this is just to prevent
+ // overwriting the same files.
+ if (const Arg *A = Args.getLastArg(options::OPT_save_temps))
+ Diag(clang::diag::err_drv_invalid_opt_with_multiple_archs)
+ << A->getAsString(Args);
+ }
+
+ ActionList SingleActions;
+ BuildActions(Args, SingleActions);
+
+ // Add in arch binding and lipo (if necessary) for every top level
+ // action.
+ for (unsigned i = 0, e = SingleActions.size(); i != e; ++i) {
+ Action *Act = SingleActions[i];
+
+ // Make sure we can lipo this kind of output. If not (and it is an
+ // actual output) then we disallow, since we can't create an
+ // output file with the right name without overwriting it. We
+ // could remove this oddity by just changing the output names to
+ // include the arch, which would also fix
+ // -save-temps. Compatibility wins for now.
+
+ if (Archs.size() > 1 && !types::canLipoType(Act->getType()))
+ Diag(clang::diag::err_drv_invalid_output_with_multiple_archs)
+ << types::getTypeName(Act->getType());
+
+ ActionList Inputs;
+ for (unsigned i = 0, e = Archs.size(); i != e; ++i)
+ Inputs.push_back(new BindArchAction(Act, Archs[i]));
+
+ // Lipo if necessary, We do it this way because we need to set the
+ // arch flag so that -Xarch_ gets overwritten.
+ if (Inputs.size() == 1 || Act->getType() == types::TY_Nothing)
+ Actions.append(Inputs.begin(), Inputs.end());
+ else
+ Actions.push_back(new LipoJobAction(Inputs, Act->getType()));
+ }
+}
+
+void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
+ llvm::PrettyStackTraceString CrashInfo("Building compilation actions");
+ // Start by constructing the list of inputs and their types.
+
+ // 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;
+
+ if (isa<InputOption>(A->getOption())) {
+ const char *Value = A->getValue(Args);
+ types::ID Ty = types::TY_INVALID;
+
+ // Infer the input type if necessary.
+ if (InputType == types::TY_Nothing) {
+ // If there was an explicit arg for this, claim it.
+ if (InputTypeArg)
+ InputTypeArg->claim();
+
+ // stdin must be handled specially.
+ if (memcmp(Value, "-", 2) == 0) {
+ // If running with -E, treat as a C input (this changes the
+ // builtin macros, for example). This may be overridden by
+ // -ObjC below.
+ //
+ // Otherwise emit an error but still use a valid type to
+ // avoid spurious errors (e.g., no inputs).
+ if (!Args.hasArg(options::OPT_E, false))
+ Diag(clang::diag::err_drv_unknown_stdin_type);
+ Ty = types::TY_C;
+ } else {
+ // Otherwise lookup by extension, and fallback to ObjectType
+ // if not found. We use a host hook here because Darwin at
+ // least has its own idea of what .s is.
+ if (const char *Ext = strrchr(Value, '.'))
+ Ty = Host->lookupTypeForExtension(Ext + 1);
+
+ if (Ty == types::TY_INVALID)
+ Ty = types::TY_Object;
+ }
+
+ // -ObjC and -ObjC++ override the default language, but only for "source
+ // files". We just treat everything that isn't a linker input as a
+ // source file.
+ //
+ // FIXME: Clean this up if we move the phase sequence into the type.
+ if (Ty != types::TY_Object) {
+ if (Args.hasArg(options::OPT_ObjC))
+ Ty = types::TY_ObjC;
+ else if (Args.hasArg(options::OPT_ObjCXX))
+ Ty = types::TY_ObjCXX;
+ }
+ } else {
+ assert(InputTypeArg && "InputType set w/o InputTypeArg");
+ InputTypeArg->claim();
+ Ty = InputType;
+ }
+
+ // Check that the file exists. It isn't clear this is worth
+ // doing, since the tool presumably does this anyway, and this
+ // just adds an extra stat to the equation, but this is gcc
+ // compatible.
+ if (memcmp(Value, "-", 2) != 0 && !llvm::sys::Path(Value).exists())
+ Diag(clang::diag::err_drv_no_such_file) << A->getValue(Args);
+ else
+ Inputs.push_back(std::make_pair(Ty, A));
+
+ } else if (A->getOption().isLinkerInput()) {
+ // Just treat as object type, we could make a special type for
+ // this if necessary.
+ Inputs.push_back(std::make_pair(types::TY_Object, A));
+
+ } else if (A->getOption().getId() == options::OPT_x) {
+ InputTypeArg = A;
+ InputType = types::lookupTypeForTypeSpecifier(A->getValue(Args));
+
+ // Follow gcc behavior and treat as linker input for invalid -x
+ // options. Its not clear why we shouldn't just revert to
+ // unknown; but this isn't very important, we might as well be
+ // bug comatible.
+ if (!InputType) {
+ Diag(clang::diag::err_drv_unknown_language) << A->getValue(Args);
+ InputType = types::TY_Object;
+ }
+ }
+ }
+
+ 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 ((FinalPhaseArg = Args.getLastArg(options::OPT_E)) ||
+ (FinalPhaseArg = Args.getLastArg(options::OPT_M)) ||
+ (FinalPhaseArg = Args.getLastArg(options::OPT_MM))) {
+ FinalPhase = phases::Preprocess;
+
+ // -{fsyntax-only,-analyze,emit-llvm,S} only run up to the compiler.
+ } else if ((FinalPhaseArg = Args.getLastArg(options::OPT_fsyntax_only)) ||
+ (FinalPhaseArg = Args.getLastArg(options::OPT__analyze,
+ options::OPT__analyze_auto)) ||
+ (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;
+
+ // Reject -Z* at the top level, these options should never have been
+ // exposed by gcc.
+ if (Arg *A = Args.getLastArg(options::OPT_Z_Joined))
+ Diag(clang::diag::err_drv_use_of_Z_option) << A->getAsString(Args);
+
+ // Construct the actions to perform.
+ ActionList LinkerInputs;
+ for (unsigned i = 0, e = Inputs.size(); i != e; ++i) {
+ types::ID InputType = Inputs[i].first;
+ const Arg *InputArg = Inputs[i].second;
+
+ unsigned NumSteps = types::getNumCompilationPhases(InputType);
+ assert(NumSteps && "Invalid number of steps!");
+
+ // If the first step comes after the final phase we are doing as
+ // part of this compilation, warn the user about it.
+ phases::ID InitialPhase = types::getCompilationPhase(InputType, 0);
+ if (InitialPhase > FinalPhase) {
+ // Claim here to avoid the more general unused warning.
+ InputArg->claim();
+ Diag(clang::diag::warn_drv_input_file_unused)
+ << InputArg->getAsString(Args)
+ << getPhaseName(InitialPhase)
+ << FinalPhaseArg->getOption().getName();
+ continue;
+ }
+
+ // Build the pipeline for this file.
+ Action *Current = new InputAction(*InputArg, InputType);
+ for (unsigned i = 0; i != NumSteps; ++i) {
+ phases::ID Phase = types::getCompilationPhase(InputType, i);
+
+ // We are done if this step is past what the user requested.
+ if (Phase > FinalPhase)
+ break;
+
+ // Queue linker inputs.
+ if (Phase == phases::Link) {
+ assert(i + 1 == NumSteps && "linking must be final compilation step.");
+ LinkerInputs.push_back(Current);
+ Current = 0;
+ break;
+ }
+
+ // Some types skip the assembler phase (e.g., llvm-bc), but we
+ // can't encode this in the steps because the intermediate type
+ // depends on arguments. Just special case here.
+ if (Phase == phases::Assemble && Current->getType() != types::TY_PP_Asm)
+ continue;
+
+ // Otherwise construct the appropriate action.
+ Current = ConstructPhaseAction(Args, Phase, Current);
+ if (Current->getType() == types::TY_Nothing)
+ break;
+ }
+
+ // If we ended with something, add to the output list.
+ if (Current)
+ Actions.push_back(Current);
+ }
+
+ // Add a link action if necessary.
+ if (!LinkerInputs.empty())
+ Actions.push_back(new LinkJobAction(LinkerInputs, types::TY_Image));
+}
+
+Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
+ Action *Input) const {
+ llvm::PrettyStackTraceString CrashInfo("Constructing phase actions");
+ // Build the appropriate action.
+ switch (Phase) {
+ case phases::Link: assert(0 && "link action invalid here.");
+ case phases::Preprocess: {
+ types::ID OutputTy;
+ // -{M, MM} alter the output type.
+ if (Args.hasArg(options::OPT_M) || Args.hasArg(options::OPT_MM)) {
+ OutputTy = types::TY_Dependencies;
+ } else {
+ OutputTy = types::getPreprocessedType(Input->getType());
+ assert(OutputTy != types::TY_INVALID &&
+ "Cannot preprocess this input type!");
+ }
+ return new PreprocessJobAction(Input, OutputTy);
+ }
+ case phases::Precompile:
+ return new PrecompileJobAction(Input, types::TY_PCH);
+ case phases::Compile: {
+ if (Args.hasArg(options::OPT_fsyntax_only)) {
+ return new CompileJobAction(Input, types::TY_Nothing);
+ } else if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto)) {
+ return new AnalyzeJobAction(Input, types::TY_Plist);
+ } else if (Args.hasArg(options::OPT_emit_llvm) ||
+ Args.hasArg(options::OPT_flto) ||
+ Args.hasArg(options::OPT_O4)) {
+ types::ID Output =
+ Args.hasArg(options::OPT_S) ? types::TY_LLVMAsm : types::TY_LLVMBC;
+ return new CompileJobAction(Input, Output);
+ } else {
+ return new CompileJobAction(Input, types::TY_PP_Asm);
+ }
+ }
+ case phases::Assemble:
+ return new AssembleJobAction(Input, types::TY_Object);
+ }
+
+ assert(0 && "invalid phase in ConstructPhaseAction");
+ return 0;
+}
+
+void Driver::BuildJobs(Compilation &C) const {
+ llvm::PrettyStackTraceString CrashInfo("Building compilation jobs");
+ bool SaveTemps = C.getArgs().hasArg(options::OPT_save_temps);
+ bool UsePipes = C.getArgs().hasArg(options::OPT_pipe);
+
+ // FIXME: Pipes are forcibly disabled until we support executing
+ // them.
+ if (!CCCPrintBindings)
+ UsePipes = false;
+
+ // -save-temps inhibits pipes.
+ if (SaveTemps && UsePipes) {
+ Diag(clang::diag::warn_drv_pipe_ignored_with_save_temps);
+ UsePipes = true;
+ }
+
+ Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o);
+
+ // It is an error to provide a -o option if we are making multiple
+ // output files.
+ if (FinalOutput) {
+ unsigned NumOutputs = 0;
+ for (ActionList::const_iterator it = C.getActions().begin(),
+ ie = C.getActions().end(); it != ie; ++it)
+ if ((*it)->getType() != types::TY_Nothing)
+ ++NumOutputs;
+
+ if (NumOutputs > 1) {
+ Diag(clang::diag::err_drv_output_argument_with_multiple_files);
+ FinalOutput = 0;
+ }
+ }
+
+ for (ActionList::const_iterator it = C.getActions().begin(),
+ ie = C.getActions().end(); it != ie; ++it) {
+ Action *A = *it;
+
+ // If we are linking an image for multiple archs then the linker
+ // wants -arch_multiple and -final_output <final image
+ // name>. Unfortunately, this doesn't fit in cleanly because we
+ // have to pass this information down.
+ //
+ // FIXME: This is a hack; find a cleaner way to integrate this
+ // into the process.
+ const char *LinkingOutput = 0;
+ if (isa<LipoJobAction>(A)) {
+ if (FinalOutput)
+ LinkingOutput = FinalOutput->getValue(C.getArgs());
+ else
+ LinkingOutput = DefaultImageName.c_str();
+ }
+
+ InputInfo II;
+ BuildJobsForAction(C, A, &C.getDefaultToolChain(),
+ /*CanAcceptPipe*/ true,
+ /*AtTopLevel*/ true,
+ /*LinkingOutput*/ LinkingOutput,
+ II);
+ }
+
+ // If the user passed -Qunused-arguments or there were errors, don't
+ // warn about any unused arguments.
+ if (Diags.getNumErrors() ||
+ C.getArgs().hasArg(options::OPT_Qunused_arguments))
+ return;
+
+ // Claim -### here.
+ (void) C.getArgs().hasArg(options::OPT__HASH_HASH_HASH);
+
+ for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end();
+ it != ie; ++it) {
+ 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.
+ if (!A->isClaimed()) {
+ if (A->getOption().hasNoArgumentUnused())
+ continue;
+
+ // Suppress the warning automatically if this is just a flag,
+ // and it is an instance of an argument we already claimed.
+ const Option &Opt = A->getOption();
+ if (isa<FlagOption>(Opt)) {
+ bool DuplicateClaimed = false;
+
+ // FIXME: Use iterator.
+ for (ArgList::const_iterator it = C.getArgs().begin(),
+ ie = C.getArgs().end(); it != ie; ++it) {
+ if ((*it)->isClaimed() && (*it)->getOption().matches(Opt.getId())) {
+ DuplicateClaimed = true;
+ break;
+ }
+ }
+
+ if (DuplicateClaimed)
+ continue;
+ }
+
+ Diag(clang::diag::warn_drv_unused_argument)
+ << A->getAsString(C.getArgs());
+ }
+ }
+}
+
+void Driver::BuildJobsForAction(Compilation &C,
+ const Action *A,
+ const ToolChain *TC,
+ bool CanAcceptPipe,
+ bool AtTopLevel,
+ const char *LinkingOutput,
+ InputInfo &Result) const {
+ llvm::PrettyStackTraceString CrashInfo("Building compilation jobs for action");
+
+ bool UsePipes = C.getArgs().hasArg(options::OPT_pipe);
+ // FIXME: Pipes are forcibly disabled until we support executing
+ // them.
+ if (!CCCPrintBindings)
+ UsePipes = false;
+
+ if (const InputAction *IA = dyn_cast<InputAction>(A)) {
+ // FIXME: It would be nice to not claim this here; maybe the old
+ // scheme of just using Args was better?
+ const Arg &Input = IA->getInputArg();
+ Input.claim();
+ if (isa<PositionalArg>(Input)) {
+ const char *Name = Input.getValue(C.getArgs());
+ Result = InputInfo(Name, A->getType(), Name);
+ } else
+ Result = InputInfo(&Input, A->getType(), "");
+ return;
+ }
+
+ if (const BindArchAction *BAA = dyn_cast<BindArchAction>(A)) {
+ const char *ArchName = BAA->getArchName();
+ std::string Arch;
+ if (!ArchName) {
+ Arch = C.getDefaultToolChain().getArchName();
+ ArchName = Arch.c_str();
+ }
+ BuildJobsForAction(C,
+ *BAA->begin(),
+ Host->getToolChain(C.getArgs(), ArchName),
+ CanAcceptPipe,
+ AtTopLevel,
+ LinkingOutput,
+ Result);
+ return;
+ }
+
+ const JobAction *JA = cast<JobAction>(A);
+ const Tool &T = TC->SelectTool(C, *JA);
+
+ // See if we should use an integrated preprocessor. We do so when we
+ // have exactly one input, since this is the only use case we care
+ // about (irrelevant since we don't support combine yet).
+ bool UseIntegratedCPP = false;
+ const ActionList *Inputs = &A->getInputs();
+ if (Inputs->size() == 1 && isa<PreprocessJobAction>(*Inputs->begin())) {
+ if (!C.getArgs().hasArg(options::OPT_no_integrated_cpp) &&
+ !C.getArgs().hasArg(options::OPT_traditional_cpp) &&
+ !C.getArgs().hasArg(options::OPT_save_temps) &&
+ T.hasIntegratedCPP()) {
+ UseIntegratedCPP = true;
+ Inputs = &(*Inputs)[0]->getInputs();
+ }
+ }
+
+ // Only use pipes when there is exactly one input.
+ bool TryToUsePipeInput = Inputs->size() == 1 && T.acceptsPipedInput();
+ InputInfoList InputInfos;
+ for (ActionList::const_iterator it = Inputs->begin(), ie = Inputs->end();
+ it != ie; ++it) {
+ InputInfo II;
+ BuildJobsForAction(C, *it, TC, TryToUsePipeInput,
+ /*AtTopLevel*/false,
+ LinkingOutput,
+ II);
+ InputInfos.push_back(II);
+ }
+
+ // Determine if we should output to a pipe.
+ bool OutputToPipe = false;
+ if (CanAcceptPipe && T.canPipeOutput()) {
+ // Some actions default to writing to a pipe if they are the top
+ // level phase and there was no user override.
+ //
+ // FIXME: Is there a better way to handle this?
+ if (AtTopLevel) {
+ if (isa<PreprocessJobAction>(A) && !C.getArgs().hasArg(options::OPT_o))
+ OutputToPipe = true;
+ } else if (UsePipes)
+ OutputToPipe = true;
+ }
+
+ // Figure out where to put the job (pipes).
+ Job *Dest = &C.getJobs();
+ if (InputInfos[0].isPipe()) {
+ assert(TryToUsePipeInput && "Unrequested pipe!");
+ assert(InputInfos.size() == 1 && "Unexpected pipe with multiple inputs.");
+ Dest = &InputInfos[0].getPipe();
+ }
+
+ // Always use the first input as the base input.
+ const char *BaseInput = InputInfos[0].getBaseInput();
+
+ // Determine the place to write output to (nothing, pipe, or
+ // filename) and where to put the new job.
+ if (JA->getType() == types::TY_Nothing) {
+ Result = InputInfo(A->getType(), BaseInput);
+ } else if (OutputToPipe) {
+ // Append to current piped job or create a new one as appropriate.
+ PipedJob *PJ = dyn_cast<PipedJob>(Dest);
+ if (!PJ) {
+ PJ = new PipedJob();
+ // FIXME: Temporary hack so that -ccc-print-bindings work until
+ // we have pipe support. Please remove later.
+ if (!CCCPrintBindings)
+ cast<JobList>(Dest)->addJob(PJ);
+ Dest = PJ;
+ }
+ Result = InputInfo(PJ, A->getType(), BaseInput);
+ } else {
+ Result = InputInfo(GetNamedOutputPath(C, *JA, BaseInput, AtTopLevel),
+ A->getType(), BaseInput);
+ }
+
+ if (CCCPrintBindings) {
+ llvm::errs() << "# \"" << T.getToolChain().getTripleString() << '"'
+ << " - \"" << T.getName() << "\", inputs: [";
+ for (unsigned i = 0, e = InputInfos.size(); i != e; ++i) {
+ llvm::errs() << InputInfos[i].getAsString();
+ if (i + 1 != e)
+ llvm::errs() << ", ";
+ }
+ llvm::errs() << "], output: " << Result.getAsString() << "\n";
+ } else {
+ T.ConstructJob(C, *JA, *Dest, Result, InputInfos,
+ C.getArgsForToolChain(TC), LinkingOutput);
+ }
+}
+
+const char *Driver::GetNamedOutputPath(Compilation &C,
+ const JobAction &JA,
+ const char *BaseInput,
+ bool AtTopLevel) const {
+ llvm::PrettyStackTraceString CrashInfo("Computing output path");
+ // Output to a user requested destination?
+ if (AtTopLevel) {
+ if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
+ return C.addResultFile(FinalOutput->getValue(C.getArgs()));
+ }
+
+ // Output to a temporary file?
+ if (!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps)) {
+ std::string TmpName =
+ GetTemporaryPath(types::getTypeTempSuffix(JA.getType()));
+ return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str()));
+ }
+
+ llvm::sys::Path BasePath(BaseInput);
+ std::string BaseName(BasePath.getLast());
+
+ // Determine what the derived output name should be.
+ const char *NamedOutput;
+ if (JA.getType() == types::TY_Image) {
+ NamedOutput = DefaultImageName.c_str();
+ } else {
+ const char *Suffix = types::getTypeTempSuffix(JA.getType());
+ assert(Suffix && "All types used for output should have a suffix.");
+
+ std::string::size_type End = std::string::npos;
+ if (!types::appendSuffixForType(JA.getType()))
+ End = BaseName.rfind('.');
+ std::string Suffixed(BaseName.substr(0, End));
+ Suffixed += '.';
+ Suffixed += Suffix;
+ NamedOutput = C.getArgs().MakeArgString(Suffixed.c_str());
+ }
+
+ // As an annoying special case, PCH generation doesn't strip the
+ // pathname.
+ if (JA.getType() == types::TY_PCH) {
+ BasePath.eraseComponent();
+ if (BasePath.isEmpty())
+ BasePath = NamedOutput;
+ else
+ BasePath.appendComponent(NamedOutput);
+ return C.addResultFile(C.getArgs().MakeArgString(BasePath.c_str()));
+ } else {
+ return C.addResultFile(NamedOutput);
+ }
+}
+
+llvm::sys::Path Driver::GetFilePath(const char *Name,
+ const ToolChain &TC) const {
+ const ToolChain::path_list &List = TC.getFilePaths();
+ for (ToolChain::path_list::const_iterator
+ it = List.begin(), ie = List.end(); it != ie; ++it) {
+ llvm::sys::Path P(*it);
+ P.appendComponent(Name);
+ if (P.exists())
+ return P;
+ }
+
+ return llvm::sys::Path(Name);
+}
+
+llvm::sys::Path Driver::GetProgramPath(const char *Name,
+ const ToolChain &TC,
+ bool WantFile) const {
+ 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(Name);
+ if (WantFile ? P.exists() : P.canExecute())
+ return P;
+ }
+
+ // If all else failed, search the path.
+ llvm::sys::Path P(llvm::sys::Program::FindProgramByName(Name));
+ if (!P.empty())
+ return P;
+
+ return llvm::sys::Path(Name);
+}
+
+std::string Driver::GetTemporaryPath(const char *Suffix) const {
+ // FIXME: This is lame; sys::Path should provide this function (in
+ // particular, it should know how to find the temporary files dir).
+ std::string Error;
+ const char *TmpDir = ::getenv("TMPDIR");
+ if (!TmpDir)
+ TmpDir = ::getenv("TEMP");
+ if (!TmpDir)
+ TmpDir = ::getenv("TMP");
+ if (!TmpDir)
+ TmpDir = "/tmp";
+ llvm::sys::Path P(TmpDir);
+ P.appendComponent("cc");
+ if (P.makeUnique(false, &Error)) {
+ Diag(clang::diag::err_drv_unable_to_make_temp) << Error;
+ return "";
+ }
+
+ // FIXME: Grumble, makeUnique sometimes leaves the file around!?
+ // PR3837.
+ P.eraseFromDisk(false, 0);
+
+ P.appendSuffix(Suffix);
+ return P.toString();
+}
+
+const HostInfo *Driver::GetHostInfo(const char *TripleStr) const {
+ llvm::PrettyStackTraceString CrashInfo("Constructing host");
+ llvm::Triple Triple(TripleStr);
+
+ // Normalize Arch a bit.
+ //
+ // FIXME: We shouldn't need to do this once everything goes through the triple
+ // interface.
+ if (Triple.getArchName() == "i686")
+ Triple.setArchName("i386");
+ else if (Triple.getArchName() == "amd64")
+ Triple.setArchName("x86_64");
+ else if (Triple.getArchName() == "ppc" ||
+ Triple.getArchName() == "Power Macintosh")
+ Triple.setArchName("powerpc");
+ else if (Triple.getArchName() == "ppc64")
+ Triple.setArchName("powerpc64");
+
+ switch (Triple.getOS()) {
+ case llvm::Triple::Darwin:
+ return createDarwinHostInfo(*this, Triple);
+ case llvm::Triple::DragonFly:
+ return createDragonFlyHostInfo(*this, Triple);
+ case llvm::Triple::FreeBSD:
+ return createFreeBSDHostInfo(*this, Triple);
+ case llvm::Triple::Linux:
+ return createLinuxHostInfo(*this, Triple);
+ default:
+ return createUnknownHostInfo(*this, Triple);
+ }
+}
+
+bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA,
+ const std::string &ArchNameStr) const {
+ // FIXME: Remove this hack.
+ const char *ArchName = ArchNameStr.c_str();
+ if (ArchNameStr == "powerpc")
+ ArchName = "ppc";
+ else if (ArchNameStr == "powerpc64")
+ ArchName = "ppc64";
+
+ // Check if user requested no clang, or clang doesn't understand
+ // this type (we only handle single inputs for now).
+ if (!CCCUseClang || JA.size() != 1 ||
+ !types::isAcceptedByClang((*JA.begin())->getType()))
+ return false;
+
+ // Otherwise make sure this is an action clang understands.
+ if (isa<PreprocessJobAction>(JA)) {
+ if (!CCCUseClangCPP) {
+ Diag(clang::diag::warn_drv_not_using_clang_cpp);
+ return false;
+ }
+ } else if (!isa<PrecompileJobAction>(JA) && !isa<CompileJobAction>(JA))
+ return false;
+
+ // Use clang for C++?
+ if (!CCCUseClangCXX && types::isCXX((*JA.begin())->getType())) {
+ Diag(clang::diag::warn_drv_not_using_clang_cxx);
+ return false;
+ }
+
+ // Always use clang for precompiling, regardless of archs. PTH is
+ // platform independent, and this allows the use of the static
+ // analyzer on platforms we don't have full IRgen support for.
+ if (isa<PrecompileJobAction>(JA))
+ return true;
+
+ // Finally, don't use clang if this isn't one of the user specified
+ // archs to build.
+ if (!CCCClangArchs.empty() && !CCCClangArchs.count(ArchName)) {
+ Diag(clang::diag::warn_drv_not_using_clang_arch) << ArchName;
+ return false;
+ }
+
+ return true;
+}
+
+/// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and
+/// return the grouped values as integers. Numbers which are not
+/// provided are set to 0.
+///
+/// \return True if the entire string was parsed (9.2), or all groups
+/// were parsed (10.3.5extrastuff).
+bool Driver::GetReleaseVersion(const char *Str, unsigned &Major,
+ unsigned &Minor, unsigned &Micro,
+ bool &HadExtra) {
+ HadExtra = false;
+
+ Major = Minor = Micro = 0;
+ if (*Str == '\0')
+ return true;
+
+ char *End;
+ Major = (unsigned) strtol(Str, &End, 10);
+ if (*Str != '\0' && *End == '\0')
+ return true;
+ if (*End != '.')
+ return false;
+
+ Str = End+1;
+ Minor = (unsigned) strtol(Str, &End, 10);
+ if (*Str != '\0' && *End == '\0')
+ return true;
+ if (*End != '.')
+ return false;
+
+ Str = End+1;
+ Micro = (unsigned) strtol(Str, &End, 10);
+ if (*Str != '\0' && *End == '\0')
+ return true;
+ if (Str == End)
+ return false;
+ HadExtra = true;
+ return true;
+}
diff --git a/lib/Driver/HostInfo.cpp b/lib/Driver/HostInfo.cpp
new file mode 100644
index 000000000000..603b3ab230fa
--- /dev/null
+++ b/lib/Driver/HostInfo.cpp
@@ -0,0 +1,408 @@
+//===--- HostInfo.cpp - Host specific information -----------------------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/HostInfo.h"
+
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Option.h"
+#include "clang/Driver/Options.h"
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Compiler.h"
+
+#include "ToolChains.h"
+
+#include <cassert>
+
+using namespace clang::driver;
+
+HostInfo::HostInfo(const Driver &D, const llvm::Triple &_Triple)
+ : TheDriver(D), Triple(_Triple)
+{
+
+}
+
+HostInfo::~HostInfo() {
+}
+
+namespace {
+
+// Darwin Host Info
+
+/// DarwinHostInfo - Darwin host information implementation.
+class DarwinHostInfo : public HostInfo {
+ /// Darwin version of host.
+ unsigned DarwinVersion[3];
+
+ /// GCC version to use on this host.
+ unsigned GCCVersion[3];
+
+ /// Cache of tool chains we have created.
+ mutable llvm::StringMap<ToolChain *> ToolChains;
+
+public:
+ DarwinHostInfo(const Driver &D, const llvm::Triple &Triple);
+ ~DarwinHostInfo();
+
+ virtual bool useDriverDriver() const;
+
+ virtual types::ID lookupTypeForExtension(const char *Ext) const {
+ types::ID Ty = types::lookupTypeForExtension(Ext);
+
+ // Darwin always preprocesses assembly files (unless -x is used
+ // explicitly).
+ if (Ty == types::TY_PP_Asm)
+ return types::TY_Asm;
+
+ return Ty;
+ }
+
+ virtual ToolChain *getToolChain(const ArgList &Args,
+ const char *ArchName) const;
+};
+
+DarwinHostInfo::DarwinHostInfo(const Driver &D, const llvm::Triple& Triple)
+ : HostInfo(D, Triple) {
+
+ assert((getArchName() == "i386" || getArchName() == "x86_64" ||
+ getArchName() == "powerpc" || getArchName() == "powerpc64" ||
+ getArchName() == "arm") &&
+ "Unknown Darwin arch.");
+
+ assert(memcmp(&getOSName()[0], "darwin", 6) == 0 &&
+ "Unknown Darwin platform.");
+ bool HadExtra;
+ if (!Driver::GetReleaseVersion(&getOSName()[6],
+ DarwinVersion[0], DarwinVersion[1],
+ DarwinVersion[2], HadExtra)) {
+ D.Diag(clang::diag::err_drv_invalid_darwin_version)
+ << getOSName();
+ }
+
+ // We can only call 4.2.1 for now.
+ GCCVersion[0] = 4;
+ GCCVersion[1] = 2;
+ GCCVersion[2] = 1;
+}
+
+DarwinHostInfo::~DarwinHostInfo() {
+ for (llvm::StringMap<ToolChain*>::iterator
+ it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
+ delete it->second;
+}
+
+bool DarwinHostInfo::useDriverDriver() const {
+ return true;
+}
+
+ToolChain *DarwinHostInfo::getToolChain(const ArgList &Args,
+ const char *ArchName) const {
+ std::string Arch;
+ if (!ArchName) {
+ Arch = getArchName();
+ ArchName = Arch.c_str();
+
+ // If no arch name is specified, infer it from the host and
+ // -m32/-m64.
+ if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) {
+ if (getArchName() == "i386" || getArchName() == "x86_64") {
+ ArchName =
+ (A->getOption().getId() == options::OPT_m32) ? "i386" : "x86_64";
+ } else if (getArchName() == "powerpc" || getArchName() == "powerpc64") {
+ ArchName = (A->getOption().getId() == options::OPT_m32) ? "powerpc" :
+ "powerpc64";
+ }
+ }
+ } else {
+ // Normalize arch name; we shouldn't be doing this here.
+ //
+ // FIXME: This should be unnecessary once everything moves over to using the
+ // ID based Triple interface.
+ if (strcmp(ArchName, "ppc") == 0)
+ ArchName = "powerpc";
+ else if (strcmp(ArchName, "ppc64") == 0)
+ ArchName = "powerpc64";
+ }
+
+ ToolChain *&TC = ToolChains[ArchName];
+ if (!TC) {
+ llvm::Triple TCTriple(getTriple());
+ TCTriple.setArchName(ArchName);
+
+ if (strcmp(ArchName, "i386") == 0 || strcmp(ArchName, "x86_64") == 0)
+ TC = new toolchains::Darwin_X86(*this, TCTriple,
+ DarwinVersion,
+ GCCVersion);
+ else
+ TC = new toolchains::Darwin_GCC(*this, TCTriple);
+ }
+
+ return TC;
+}
+
+// Unknown Host Info
+
+/// UnknownHostInfo - Generic host information to use for unknown
+/// hosts.
+class UnknownHostInfo : public HostInfo {
+ /// Cache of tool chains we have created.
+ mutable llvm::StringMap<ToolChain*> ToolChains;
+
+public:
+ UnknownHostInfo(const Driver &D, const llvm::Triple& Triple);
+ ~UnknownHostInfo();
+
+ virtual bool useDriverDriver() const;
+
+ virtual types::ID lookupTypeForExtension(const char *Ext) const {
+ return types::lookupTypeForExtension(Ext);
+ }
+
+ virtual ToolChain *getToolChain(const ArgList &Args,
+ const char *ArchName) const;
+};
+
+UnknownHostInfo::UnknownHostInfo(const Driver &D, const llvm::Triple& Triple)
+ : HostInfo(D, Triple) {
+}
+
+UnknownHostInfo::~UnknownHostInfo() {
+ for (llvm::StringMap<ToolChain*>::iterator
+ it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
+ delete it->second;
+}
+
+bool UnknownHostInfo::useDriverDriver() const {
+ return false;
+}
+
+ToolChain *UnknownHostInfo::getToolChain(const ArgList &Args,
+ const char *ArchName) const {
+ assert(!ArchName &&
+ "Unexpected arch name on platform without driver driver support.");
+
+ // Automatically handle some instances of -m32/-m64 we know about.
+ std::string Arch = getArchName();
+ ArchName = Arch.c_str();
+ if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) {
+ if (getArchName() == "i386" || getArchName() == "x86_64") {
+ ArchName =
+ (A->getOption().getId() == options::OPT_m32) ? "i386" : "x86_64";
+ } else if (getArchName() == "powerpc" || getArchName() == "powerpc64") {
+ ArchName =
+ (A->getOption().getId() == options::OPT_m32) ? "powerpc" : "powerpc64";
+ }
+ }
+
+ ToolChain *&TC = ToolChains[ArchName];
+ if (!TC) {
+ llvm::Triple TCTriple(getTriple());
+ TCTriple.setArchName(ArchName);
+
+ TC = new toolchains::Generic_GCC(*this, TCTriple);
+ }
+
+ return TC;
+}
+
+// FreeBSD Host Info
+
+/// FreeBSDHostInfo - FreeBSD host information implementation.
+class FreeBSDHostInfo : public HostInfo {
+ /// Cache of tool chains we have created.
+ mutable llvm::StringMap<ToolChain*> ToolChains;
+
+public:
+ FreeBSDHostInfo(const Driver &D, const llvm::Triple& Triple)
+ : HostInfo(D, Triple) {}
+ ~FreeBSDHostInfo();
+
+ virtual bool useDriverDriver() const;
+
+ virtual types::ID lookupTypeForExtension(const char *Ext) const {
+ return types::lookupTypeForExtension(Ext);
+ }
+
+ virtual ToolChain *getToolChain(const ArgList &Args,
+ const char *ArchName) const;
+};
+
+FreeBSDHostInfo::~FreeBSDHostInfo() {
+ for (llvm::StringMap<ToolChain*>::iterator
+ it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
+ delete it->second;
+}
+
+bool FreeBSDHostInfo::useDriverDriver() const {
+ return false;
+}
+
+ToolChain *FreeBSDHostInfo::getToolChain(const ArgList &Args,
+ const char *ArchName) const {
+ bool Lib32 = false;
+
+ assert(!ArchName &&
+ "Unexpected arch name on platform without driver driver support.");
+
+ // On x86_64 we need to be able to compile 32-bits binaries as well.
+ // Compiling 64-bit binaries on i386 is not supported. We don't have a
+ // lib64.
+ std::string Arch = getArchName();
+ ArchName = Arch.c_str();
+ if (Args.hasArg(options::OPT_m32) && getArchName() == "x86_64") {
+ ArchName = "i386";
+ Lib32 = true;
+ }
+
+ ToolChain *&TC = ToolChains[ArchName];
+ if (!TC) {
+ llvm::Triple TCTriple(getTriple());
+ TCTriple.setArchName(ArchName);
+
+ TC = new toolchains::FreeBSD(*this, TCTriple, Lib32);
+ }
+
+ return TC;
+}
+
+// DragonFly Host Info
+
+/// DragonFlyHostInfo - DragonFly host information implementation.
+class DragonFlyHostInfo : public HostInfo {
+ /// Cache of tool chains we have created.
+ mutable llvm::StringMap<ToolChain*> ToolChains;
+
+public:
+ DragonFlyHostInfo(const Driver &D, const llvm::Triple& Triple)
+ : HostInfo(D, Triple) {}
+ ~DragonFlyHostInfo();
+
+ virtual bool useDriverDriver() const;
+
+ virtual types::ID lookupTypeForExtension(const char *Ext) const {
+ return types::lookupTypeForExtension(Ext);
+ }
+
+ virtual ToolChain *getToolChain(const ArgList &Args,
+ const char *ArchName) const;
+};
+
+DragonFlyHostInfo::~DragonFlyHostInfo() {
+ for (llvm::StringMap<ToolChain*>::iterator
+ it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
+ delete it->second;
+}
+
+bool DragonFlyHostInfo::useDriverDriver() const {
+ return false;
+}
+
+ToolChain *DragonFlyHostInfo::getToolChain(const ArgList &Args,
+ const char *ArchName) const {
+ assert(!ArchName &&
+ "Unexpected arch name on platform without driver driver support.");
+
+ ToolChain *&TC = ToolChains[getArchName()];
+
+ if (!TC) {
+ llvm::Triple TCTriple(getTriple());
+ TCTriple.setArchName(getArchName());
+
+ TC = new toolchains::DragonFly(*this, TCTriple);
+ }
+
+ return TC;
+}
+
+// Linux Host Info
+
+/// LinuxHostInfo - Linux host information implementation.
+class LinuxHostInfo : public HostInfo {
+ /// Cache of tool chains we have created.
+ mutable llvm::StringMap<ToolChain*> ToolChains;
+
+public:
+ LinuxHostInfo(const Driver &D, const llvm::Triple& Triple)
+ : HostInfo(D, Triple) {}
+ ~LinuxHostInfo();
+
+ virtual bool useDriverDriver() const;
+
+ virtual types::ID lookupTypeForExtension(const char *Ext) const {
+ return types::lookupTypeForExtension(Ext);
+ }
+
+ virtual ToolChain *getToolChain(const ArgList &Args,
+ const char *ArchName) const;
+};
+
+LinuxHostInfo::~LinuxHostInfo() {
+ for (llvm::StringMap<ToolChain*>::iterator
+ it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
+ delete it->second;
+}
+
+bool LinuxHostInfo::useDriverDriver() const {
+ return false;
+}
+
+ToolChain *LinuxHostInfo::getToolChain(const ArgList &Args,
+ const char *ArchName) const {
+
+ assert(!ArchName &&
+ "Unexpected arch name on platform without driver driver support.");
+
+ ArchName = getArchName().c_str();
+
+ ToolChain *&TC = ToolChains[ArchName];
+
+ if (!TC) {
+ llvm::Triple TCTriple(getTriple());
+ TCTriple.setArchName(getArchName());
+
+ TC = new toolchains::Linux(*this, TCTriple);
+ }
+
+ return TC;
+}
+
+}
+
+const HostInfo *
+clang::driver::createDarwinHostInfo(const Driver &D,
+ const llvm::Triple& Triple){
+ return new DarwinHostInfo(D, Triple);
+}
+
+const HostInfo *
+clang::driver::createFreeBSDHostInfo(const Driver &D,
+ const llvm::Triple& Triple) {
+ return new FreeBSDHostInfo(D, Triple);
+}
+
+const HostInfo *
+clang::driver::createDragonFlyHostInfo(const Driver &D,
+ const llvm::Triple& Triple) {
+ return new DragonFlyHostInfo(D, Triple);
+}
+
+const HostInfo *
+clang::driver::createLinuxHostInfo(const Driver &D,
+ const llvm::Triple& Triple) {
+ return new LinuxHostInfo(D, Triple);
+}
+
+const HostInfo *
+clang::driver::createUnknownHostInfo(const Driver &D,
+ const llvm::Triple& Triple) {
+ return new UnknownHostInfo(D, Triple);
+}
diff --git a/lib/Driver/InputInfo.h b/lib/Driver/InputInfo.h
new file mode 100644
index 000000000000..c657bef95af0
--- /dev/null
+++ b/lib/Driver/InputInfo.h
@@ -0,0 +1,101 @@
+//===--- InputInfo.h - Input Source & Type Information ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_LIB_DRIVER_INPUTINFO_H_
+#define CLANG_LIB_DRIVER_INPUTINFO_H_
+
+#include "clang/Driver/Types.h"
+
+#include <cassert>
+#include <string>
+
+namespace clang {
+namespace driver {
+ class PipedJob;
+
+/// InputInfo - Wrapper for information about an input source.
+class InputInfo {
+ // FIXME: The distinction between filenames and inputarg here is
+ // gross; we should probably drop the idea of a "linker
+ // input". Doing so means tweaking pipelining to still create link
+ // steps when it sees linker inputs (but not treat them as
+ // arguments), and making sure that arguments get rendered
+ // correctly.
+ enum Class {
+ Nothing,
+ Filename,
+ InputArg,
+ Pipe
+ };
+
+ union {
+ const char *Filename;
+ const Arg *InputArg;
+ PipedJob *Pipe;
+ } Data;
+ Class Kind;
+ types::ID Type;
+ const char *BaseInput;
+
+public:
+ InputInfo() {}
+ InputInfo(types::ID _Type, const char *_BaseInput)
+ : Kind(Nothing), Type(_Type), BaseInput(_BaseInput) {
+ }
+ InputInfo(const char *_Filename, types::ID _Type, const char *_BaseInput)
+ : Kind(Filename), Type(_Type), BaseInput(_BaseInput) {
+ Data.Filename = _Filename;
+ }
+ InputInfo(const Arg *_InputArg, types::ID _Type, const char *_BaseInput)
+ : Kind(InputArg), Type(_Type), BaseInput(_BaseInput) {
+ Data.InputArg = _InputArg;
+ }
+ InputInfo(PipedJob *_Pipe, types::ID _Type, const char *_BaseInput)
+ : Kind(Pipe), Type(_Type), BaseInput(_BaseInput) {
+ Data.Pipe = _Pipe;
+ }
+
+ bool isNothing() const { return Kind == Nothing; }
+ bool isFilename() const { return Kind == Filename; }
+ bool isInputArg() const { return Kind == InputArg; }
+ bool isPipe() const { return Kind == Pipe; }
+ types::ID getType() const { return Type; }
+ const char *getBaseInput() const { return BaseInput; }
+
+ const char *getFilename() const {
+ assert(isFilename() && "Invalid accessor.");
+ return Data.Filename;
+ }
+ const Arg &getInputArg() const {
+ assert(isInputArg() && "Invalid accessor.");
+ return *Data.InputArg;
+ }
+ PipedJob &getPipe() const {
+ assert(isPipe() && "Invalid accessor.");
+ return *Data.Pipe;
+ }
+
+ /// getAsString - Return a string name for this input, for
+ /// debugging.
+ std::string getAsString() const {
+ if (isPipe())
+ return "(pipe)";
+ else if (isFilename())
+ return std::string("\"") + getFilename() + '"';
+ else if (isInputArg())
+ return "(input arg)";
+ else
+ return "(nothing)";
+ }
+};
+
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
new file mode 100644
index 000000000000..222cf15db60f
--- /dev/null
+++ b/lib/Driver/Job.cpp
@@ -0,0 +1,31 @@
+//===--- Job.cpp - Command to Execute -----------------------------------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Job.h"
+
+#include <cassert>
+using namespace clang::driver;
+
+Job::~Job() {}
+
+Command::Command(const char *_Executable, const ArgStringList &_Arguments)
+ : Job(CommandClass), Executable(_Executable), Arguments(_Arguments) {
+}
+
+PipedJob::PipedJob() : Job(PipedJobClass) {}
+
+JobList::JobList() : Job(JobListClass) {}
+
+void Job::addCommand(Command *C) {
+ if (PipedJob *PJ = dyn_cast<PipedJob>(this))
+ PJ->addCommand(C);
+ else
+ cast<JobList>(this)->addJob(C);
+}
+
diff --git a/lib/Driver/Makefile b/lib/Driver/Makefile
new file mode 100644
index 000000000000..d163f0fe9efc
--- /dev/null
+++ b/lib/Driver/Makefile
@@ -0,0 +1,28 @@
+##===- clang/lib/Driver/Makefile ---------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+LIBRARYNAME := clangDriver
+BUILD_ARCHIVE = 1
+CXXFLAGS = -fno-rtti
+
+
+include $(LEVEL)/Makefile.common
+
+SVN_REVISION := $(shell cd $(PROJ_SRC_DIR)/../.. && svnversion)
+
+CPP.Defines += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include \
+ -DSVN_REVISION='"$(SVN_REVISION)"'
+
+$(ObjDir)/.ver-svn .ver: $(ObjDir)/.dir
+ @if [ '$(SVN_REVISION)' != '$(shell cat $(ObjDir)/.ver-svn 2>/dev/null)' ]; then\
+ echo '$(SVN_REVISION)' > $(ObjDir)/.ver-svn; \
+ fi
+$(ObjDir)/.ver-svn: .ver
+$(ObjDir)/Driver.o: $(ObjDir)/.ver-svn
diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp
new file mode 100644
index 000000000000..7ea6a8b0d9f4
--- /dev/null
+++ b/lib/Driver/OptTable.cpp
@@ -0,0 +1,265 @@
+//===--- Options.cpp - Option info table --------------------------------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Options.h"
+
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Option.h"
+#include <algorithm>
+#include <cassert>
+
+using namespace clang::driver;
+using namespace clang::driver::options;
+
+struct Info {
+ const char *Name;
+ const char *Flags;
+ const char *HelpText;
+ const char *MetaVar;
+
+ Option::OptionClass Kind;
+ unsigned GroupID;
+ unsigned AliasID;
+ unsigned Param;
+};
+
+// Ordering on Info. The ordering is *almost* lexicographic, with two
+// exceptions. First, '\0' comes at the end of the alphabet instead of
+// the beginning (thus options preceed any other options which prefix
+// them). Second, for options with the same name, the less permissive
+// version should come first; a Flag option should preceed a Joined
+// option, for example.
+
+static int StrCmpOptionName(const char *A, const char *B) {
+ char a = *A, b = *B;
+ while (a == b) {
+ if (a == '\0')
+ return 0;
+
+ a = *++A;
+ b = *++B;
+ }
+
+ if (a == '\0') // A is a prefix of B.
+ return 1;
+ if (b == '\0') // B is a prefix of A.
+ return -1;
+
+ // Otherwise lexicographic.
+ return (a < b) ? -1 : 1;
+}
+
+static inline bool operator<(const Info &A, const Info &B) {
+ if (&A == &B)
+ return false;
+
+ if (int N = StrCmpOptionName(A.Name, B.Name))
+ return N == -1;
+
+ // Names are the same, check that classes are in order; exactly one
+ // should be joined, and it should succeed the other.
+ assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) &&
+ "Unexpected classes for options with same name.");
+ return B.Kind == Option::JoinedClass;
+}
+
+//
+
+static Info OptionInfos[] = {
+ // The InputOption info
+ { "<input>", "d", 0, 0, Option::InputClass, OPT_INVALID, OPT_INVALID, 0 },
+ // The UnknownOption info
+ { "<unknown>", "", 0, 0, Option::UnknownClass, OPT_INVALID, OPT_INVALID, 0 },
+
+#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { NAME, FLAGS, HELPTEXT, METAVAR, \
+ Option::KIND##Class, OPT_##GROUP, OPT_##ALIAS, PARAM },
+#include "clang/Driver/Options.def"
+};
+static const unsigned numOptions = sizeof(OptionInfos) / sizeof(OptionInfos[0]);
+
+static Info &getInfo(unsigned id) {
+ assert(id > 0 && id - 1 < numOptions && "Invalid Option ID.");
+ return OptionInfos[id - 1];
+}
+
+OptTable::OptTable() : Options(new Option*[numOptions]()) {
+ // Find start of normal options.
+ FirstSearchableOption = 0;
+ for (unsigned i = OPT_UNKNOWN + 1; i < LastOption; ++i) {
+ if (getInfo(i).Kind != Option::GroupClass) {
+ FirstSearchableOption = i;
+ break;
+ }
+ }
+ assert(FirstSearchableOption != 0 && "No searchable options?");
+
+#ifndef NDEBUG
+ // Check that everything after the first searchable option is a
+ // regular option class.
+ for (unsigned i = FirstSearchableOption; i < LastOption; ++i) {
+ Option::OptionClass Kind = getInfo(i).Kind;
+ assert((Kind != Option::InputClass && Kind != Option::UnknownClass &&
+ Kind != Option::GroupClass) &&
+ "Special options should be defined first!");
+ }
+
+ // Check that options are in order.
+ for (unsigned i = FirstSearchableOption + 1; i < LastOption; ++i) {
+ if (!(getInfo(i - 1) < getInfo(i))) {
+ getOption((options::ID) (i - 1))->dump();
+ getOption((options::ID) i)->dump();
+ assert(0 && "Options are not in order!");
+ }
+ }
+#endif
+}
+
+OptTable::~OptTable() {
+ for (unsigned i = 0; i < numOptions; ++i)
+ delete Options[i];
+ delete[] Options;
+}
+
+unsigned OptTable::getNumOptions() const {
+ return numOptions;
+}
+
+const char *OptTable::getOptionName(options::ID id) const {
+ return getInfo(id).Name;
+}
+
+unsigned OptTable::getOptionKind(options::ID id) const {
+ return getInfo(id).Kind;
+}
+
+const char *OptTable::getOptionHelpText(options::ID id) const {
+ return getInfo(id).HelpText;
+}
+
+const char *OptTable::getOptionMetaVar(options::ID id) const {
+ return getInfo(id).MetaVar;
+}
+
+const Option *OptTable::getOption(options::ID id) const {
+ if (id == OPT_INVALID)
+ return 0;
+
+ assert((unsigned) (id - 1) < numOptions && "Invalid ID.");
+
+ Option *&Entry = Options[id - 1];
+ if (!Entry)
+ Entry = constructOption(id);
+
+ return Entry;
+}
+
+Option *OptTable::constructOption(options::ID id) const {
+ Info &info = getInfo(id);
+ const OptionGroup *Group =
+ cast_or_null<OptionGroup>(getOption((options::ID) info.GroupID));
+ const Option *Alias = getOption((options::ID) info.AliasID);
+
+ Option *Opt = 0;
+ switch (info.Kind) {
+ case Option::InputClass:
+ Opt = new InputOption(); break;
+ case Option::UnknownClass:
+ Opt = new UnknownOption(); break;
+ case Option::GroupClass:
+ Opt = new OptionGroup(id, info.Name, Group); break;
+ case Option::FlagClass:
+ Opt = new FlagOption(id, info.Name, Group, Alias); break;
+ case Option::JoinedClass:
+ Opt = new JoinedOption(id, info.Name, Group, Alias); break;
+ case Option::SeparateClass:
+ Opt = new SeparateOption(id, info.Name, Group, Alias); break;
+ case Option::CommaJoinedClass:
+ Opt = new CommaJoinedOption(id, info.Name, Group, Alias); break;
+ case Option::MultiArgClass:
+ Opt = new MultiArgOption(id, info.Name, Group, Alias, info.Param); break;
+ case Option::JoinedOrSeparateClass:
+ Opt = new JoinedOrSeparateOption(id, info.Name, Group, Alias); break;
+ case Option::JoinedAndSeparateClass:
+ Opt = new JoinedAndSeparateOption(id, info.Name, Group, Alias); break;
+ }
+
+ for (const char *s = info.Flags; *s; ++s) {
+ switch (*s) {
+ default: assert(0 && "Invalid option flag.");
+ case 'J':
+ assert(info.Kind == Option::SeparateClass && "Invalid option.");
+ Opt->setForceJoinedRender(true); break;
+ case 'S':
+ assert(info.Kind == Option::JoinedClass && "Invalid option.");
+ Opt->setForceSeparateRender(true); break;
+ case 'd': Opt->setDriverOption(true); break;
+ case 'i': Opt->setNoOptAsInput(true); break;
+ case 'l': Opt->setLinkerInput(true); break;
+ case 'q': Opt->setNoArgumentUnused(true); break;
+ case 'u': Opt->setUnsupported(true); break;
+ }
+ }
+
+ return Opt;
+}
+
+// Support lower_bound between info and an option name.
+static inline bool operator<(struct Info &I, const char *Name) {
+ return StrCmpOptionName(I.Name, Name) == -1;
+}
+static inline bool operator<(const char *Name, struct Info &I) {
+ return StrCmpOptionName(Name, I.Name) == -1;
+}
+
+Arg *OptTable::ParseOneArg(const InputArgList &Args, unsigned &Index) const {
+ unsigned Prev = Index;
+ const char *Str = Args.getArgString(Index);
+
+ // Anything that doesn't start with '-' is an input, as is '-' itself.
+ if (Str[0] != '-' || Str[1] == '\0')
+ return new PositionalArg(getOption(OPT_INPUT), Index++);
+
+ struct Info *Start = OptionInfos + FirstSearchableOption - 1;
+ struct Info *End = OptionInfos + LastOption - 1;
+
+ // Search for the first next option which could be a prefix.
+ Start = std::lower_bound(Start, End, Str);
+
+ // Options are stored in sorted order, with '\0' at the end of the
+ // alphabet. Since the only options which can accept a string must
+ // prefix it, we iteratively search for the next option which could
+ // be a prefix.
+ //
+ // FIXME: This is searching much more than necessary, but I am
+ // blanking on the simplest way to make it fast. We can solve this
+ // problem when we move to TableGen.
+ for (; Start != End; ++Start) {
+ // Scan for first option which is a proper prefix.
+ for (; Start != End; ++Start)
+ if (memcmp(Str, Start->Name, strlen(Start->Name)) == 0)
+ break;
+ if (Start == End)
+ break;
+
+ // See if this option matches.
+ options::ID id = (options::ID) (Start - OptionInfos + 1);
+ if (Arg *A = getOption(id)->accept(Args, Index))
+ return A;
+
+ // Otherwise, see if this argument was missing values.
+ if (Prev != Index)
+ return 0;
+ }
+
+ return new PositionalArg(getOption(OPT_UNKNOWN), Index++);
+}
+
diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp
new file mode 100644
index 000000000000..cad2bbf2b75e
--- /dev/null
+++ b/lib/Driver/Option.cpp
@@ -0,0 +1,250 @@
+//===--- Option.cpp - Abstract Driver Options ---------------------------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Option.h"
+
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <algorithm>
+using namespace clang::driver;
+
+Option::Option(OptionClass _Kind, options::ID _ID, const char *_Name,
+ const OptionGroup *_Group, const Option *_Alias)
+ : Kind(_Kind), ID(_ID), Name(_Name), Group(_Group), Alias(_Alias),
+ Unsupported(false), LinkerInput(false), NoOptAsInput(false),
+ ForceSeparateRender(false), ForceJoinedRender(false),
+ DriverOption(false), NoArgumentUnused(false)
+{
+
+ // Multi-level aliases are not supported, and alias options cannot
+ // have groups. This just simplifies option tracking, it is not an
+ // inherent limitation.
+ assert((!Alias || (!Alias->Alias && !Group)) &&
+ "Multi-level aliases and aliases with groups are unsupported.");
+}
+
+Option::~Option() {
+}
+
+void Option::dump() const {
+ llvm::errs() << "<";
+ switch (Kind) {
+ default:
+ assert(0 && "Invalid kind");
+#define P(N) case N: llvm::errs() << #N; break
+ P(GroupClass);
+ P(InputClass);
+ P(UnknownClass);
+ P(FlagClass);
+ P(JoinedClass);
+ P(SeparateClass);
+ P(CommaJoinedClass);
+ P(MultiArgClass);
+ P(JoinedOrSeparateClass);
+ P(JoinedAndSeparateClass);
+#undef P
+ }
+
+ llvm::errs() << " Name:\"" << Name << '"';
+
+ if (Group) {
+ llvm::errs() << " Group:";
+ Group->dump();
+ }
+
+ if (Alias) {
+ llvm::errs() << " Alias:";
+ Alias->dump();
+ }
+
+ if (const MultiArgOption *MOA = dyn_cast<MultiArgOption>(this))
+ llvm::errs() << " NumArgs:" << MOA->getNumArgs();
+
+ llvm::errs() << ">\n";
+}
+
+bool Option::matches(const Option *Opt) const {
+ // Aliases are never considered in matching.
+ if (Opt->getAlias())
+ return matches(Opt->getAlias());
+ if (Alias)
+ return Alias->matches(Opt);
+
+ if (this == Opt)
+ return true;
+
+ if (Group)
+ return Group->matches(Opt);
+ return false;
+}
+
+bool Option::matches(options::ID Id) const {
+ // FIXME: Decide what to do here; we should either pull out the
+ // handling of alias on the option for Id from the other matches, or
+ // find some other solution (which hopefully doesn't require using
+ // the option table).
+ if (Alias)
+ return Alias->matches(Id);
+
+ if (ID == Id)
+ return true;
+
+ if (Group)
+ return Group->matches(Id);
+ return false;
+}
+
+OptionGroup::OptionGroup(options::ID ID, const char *Name,
+ const OptionGroup *Group)
+ : Option(Option::GroupClass, ID, Name, Group, 0) {
+}
+
+Arg *OptionGroup::accept(const InputArgList &Args, unsigned &Index) const {
+ assert(0 && "accept() should never be called on an OptionGroup");
+ return 0;
+}
+
+InputOption::InputOption()
+ : Option(Option::InputClass, options::OPT_INPUT, "<input>", 0, 0) {
+}
+
+Arg *InputOption::accept(const InputArgList &Args, unsigned &Index) const {
+ assert(0 && "accept() should never be called on an InputOption");
+ return 0;
+}
+
+UnknownOption::UnknownOption()
+ : Option(Option::UnknownClass, options::OPT_UNKNOWN, "<unknown>", 0, 0) {
+}
+
+Arg *UnknownOption::accept(const InputArgList &Args, unsigned &Index) const {
+ assert(0 && "accept() should never be called on an UnknownOption");
+ return 0;
+}
+
+FlagOption::FlagOption(options::ID ID, const char *Name,
+ const OptionGroup *Group, const Option *Alias)
+ : Option(Option::FlagClass, ID, Name, Group, Alias) {
+}
+
+Arg *FlagOption::accept(const InputArgList &Args, unsigned &Index) const {
+ // Matches iff this is an exact match.
+ // FIXME: Avoid strlen.
+ if (strlen(getName()) != strlen(Args.getArgString(Index)))
+ return 0;
+
+ return new FlagArg(this, Index++);
+}
+
+JoinedOption::JoinedOption(options::ID ID, const char *Name,
+ const OptionGroup *Group, const Option *Alias)
+ : Option(Option::JoinedClass, ID, Name, Group, Alias) {
+}
+
+Arg *JoinedOption::accept(const InputArgList &Args, unsigned &Index) const {
+ // Always matches.
+ return new JoinedArg(this, Index++);
+}
+
+CommaJoinedOption::CommaJoinedOption(options::ID ID, const char *Name,
+ const OptionGroup *Group,
+ const Option *Alias)
+ : Option(Option::CommaJoinedClass, ID, Name, Group, Alias) {
+}
+
+Arg *CommaJoinedOption::accept(const InputArgList &Args,
+ unsigned &Index) const {
+ // Always matches. We count the commas now so we can answer
+ // getNumValues easily.
+
+ // Get the suffix string.
+ // FIXME: Avoid strlen, and move to helper method?
+ const char *Suffix = Args.getArgString(Index) + strlen(getName());
+ return new CommaJoinedArg(this, Index++, Suffix);
+}
+
+SeparateOption::SeparateOption(options::ID ID, const char *Name,
+ const OptionGroup *Group, const Option *Alias)
+ : Option(Option::SeparateClass, ID, Name, Group, Alias) {
+}
+
+Arg *SeparateOption::accept(const InputArgList &Args, unsigned &Index) const {
+ // Matches iff this is an exact match.
+ // FIXME: Avoid strlen.
+ if (strlen(getName()) != strlen(Args.getArgString(Index)))
+ return 0;
+
+ Index += 2;
+ if (Index > Args.getNumInputArgStrings())
+ return 0;
+
+ return new SeparateArg(this, Index - 2, 1);
+}
+
+MultiArgOption::MultiArgOption(options::ID ID, const char *Name,
+ const OptionGroup *Group, const Option *Alias,
+ unsigned _NumArgs)
+ : Option(Option::MultiArgClass, ID, Name, Group, Alias), NumArgs(_NumArgs) {
+ assert(NumArgs > 1 && "Invalid MultiArgOption!");
+}
+
+Arg *MultiArgOption::accept(const InputArgList &Args, unsigned &Index) const {
+ // Matches iff this is an exact match.
+ // FIXME: Avoid strlen.
+ if (strlen(getName()) != strlen(Args.getArgString(Index)))
+ return 0;
+
+ Index += 1 + NumArgs;
+ if (Index > Args.getNumInputArgStrings())
+ return 0;
+
+ return new SeparateArg(this, Index - 1 - NumArgs, NumArgs);
+}
+
+JoinedOrSeparateOption::JoinedOrSeparateOption(options::ID ID, const char *Name,
+ const OptionGroup *Group,
+ const Option *Alias)
+ : Option(Option::JoinedOrSeparateClass, ID, Name, Group, Alias) {
+}
+
+Arg *JoinedOrSeparateOption::accept(const InputArgList &Args,
+ unsigned &Index) const {
+ // If this is not an exact match, it is a joined arg.
+ // FIXME: Avoid strlen.
+ if (strlen(getName()) != strlen(Args.getArgString(Index)))
+ return new JoinedArg(this, Index++);
+
+ // Otherwise it must be separate.
+ Index += 2;
+ if (Index > Args.getNumInputArgStrings())
+ return 0;
+
+ return new SeparateArg(this, Index - 2, 1);
+}
+
+JoinedAndSeparateOption::JoinedAndSeparateOption(options::ID ID,
+ const char *Name,
+ const OptionGroup *Group,
+ const Option *Alias)
+ : Option(Option::JoinedAndSeparateClass, ID, Name, Group, Alias) {
+}
+
+Arg *JoinedAndSeparateOption::accept(const InputArgList &Args,
+ unsigned &Index) const {
+ // Always matches.
+
+ Index += 2;
+ if (Index > Args.getNumInputArgStrings())
+ return 0;
+
+ return new JoinedAndSeparateArg(this, Index - 2);
+}
+
diff --git a/lib/Driver/Phases.cpp b/lib/Driver/Phases.cpp
new file mode 100644
index 000000000000..df4cdee77500
--- /dev/null
+++ b/lib/Driver/Phases.cpp
@@ -0,0 +1,27 @@
+//===--- Phases.cpp - Transformations on Driver Types -------------------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Phases.h"
+
+#include <cassert>
+
+using namespace clang::driver;
+
+const char *phases::getPhaseName(ID Id) {
+ switch (Id) {
+ case Preprocess: return "preprocessor";
+ case Precompile: return "precompiler";
+ case Compile: return "compiler";
+ case Assemble: return "assembler";
+ case Link: return "linker";
+ }
+
+ assert(0 && "Invalid phase id.");
+ return 0;
+}
diff --git a/lib/Driver/Tool.cpp b/lib/Driver/Tool.cpp
new file mode 100644
index 000000000000..6f6589ab1327
--- /dev/null
+++ b/lib/Driver/Tool.cpp
@@ -0,0 +1,19 @@
+//===--- Tool.cpp - Compilation Tools -----------------------------------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Tool.h"
+
+using namespace clang::driver;
+
+Tool::Tool(const char *_Name, const ToolChain &TC) : Name(_Name),
+ TheToolChain(TC) {
+}
+
+Tool::~Tool() {
+}
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
new file mode 100644
index 000000000000..20ed31bd6e02
--- /dev/null
+++ b/lib/Driver/ToolChain.cpp
@@ -0,0 +1,35 @@
+//===--- ToolChain.cpp - Collections of tools for one platform ----------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/ToolChain.h"
+
+#include "clang/Driver/Action.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/HostInfo.h"
+
+using namespace clang::driver;
+
+ToolChain::ToolChain(const HostInfo &_Host, const llvm::Triple &_Triple)
+ : Host(_Host), Triple(_Triple) {
+}
+
+ToolChain::~ToolChain() {
+}
+
+llvm::sys::Path ToolChain::GetFilePath(const Compilation &C,
+ const char *Name) const {
+ return Host.getDriver().GetFilePath(Name, *this);
+
+}
+
+llvm::sys::Path ToolChain::GetProgramPath(const Compilation &C,
+ const char *Name,
+ bool WantFile) const {
+ return Host.getDriver().GetProgramPath(Name, *this, WantFile);
+}
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
new file mode 100644
index 000000000000..436d343dd021
--- /dev/null
+++ b/lib/Driver/ToolChains.cpp
@@ -0,0 +1,475 @@
+//===--- ToolChains.cpp - ToolChain Implementations ---------------------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ToolChains.h"
+
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/HostInfo.h"
+#include "clang/Driver/Option.h"
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+
+#include <cstdlib> // ::getenv
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+
+/// Darwin_X86 - Darwin tool chain for i386 and x86_64.
+
+Darwin_X86::Darwin_X86(const HostInfo &Host, const llvm::Triple& Triple,
+ const unsigned (&_DarwinVersion)[3],
+ const unsigned (&_GCCVersion)[3])
+ : ToolChain(Host, Triple) {
+ DarwinVersion[0] = _DarwinVersion[0];
+ DarwinVersion[1] = _DarwinVersion[1];
+ DarwinVersion[2] = _DarwinVersion[2];
+ GCCVersion[0] = _GCCVersion[0];
+ GCCVersion[1] = _GCCVersion[1];
+ GCCVersion[2] = _GCCVersion[2];
+
+ llvm::raw_string_ostream(MacosxVersionMin)
+ << "10." << DarwinVersion[0] - 4 << '.' << DarwinVersion[1];
+
+ ToolChainDir = "i686-apple-darwin";
+ ToolChainDir += llvm::utostr(DarwinVersion[0]);
+ ToolChainDir += "/";
+ ToolChainDir += llvm::utostr(GCCVersion[0]);
+ ToolChainDir += '.';
+ ToolChainDir += llvm::utostr(GCCVersion[1]);
+ ToolChainDir += '.';
+ ToolChainDir += llvm::utostr(GCCVersion[2]);
+
+ std::string Path;
+ if (getArchName() == "x86_64") {
+ Path = getHost().getDriver().Dir;
+ Path += "/../lib/gcc/";
+ Path += getToolChainDir();
+ Path += "/x86_64";
+ getFilePaths().push_back(Path);
+
+ Path = "/usr/lib/gcc/";
+ Path += getToolChainDir();
+ Path += "/x86_64";
+ getFilePaths().push_back(Path);
+ }
+
+ Path = getHost().getDriver().Dir;
+ Path += "/../lib/gcc/";
+ Path += getToolChainDir();
+ getFilePaths().push_back(Path);
+
+ Path = "/usr/lib/gcc/";
+ Path += getToolChainDir();
+ getFilePaths().push_back(Path);
+
+ Path = getHost().getDriver().Dir;
+ Path += "/../libexec/gcc/";
+ Path += getToolChainDir();
+ getProgramPaths().push_back(Path);
+
+ Path = "/usr/libexec/gcc/";
+ Path += getToolChainDir();
+ getProgramPaths().push_back(Path);
+
+ Path = getHost().getDriver().Dir;
+ Path += "/../libexec";
+ getProgramPaths().push_back(Path);
+
+ getProgramPaths().push_back(getHost().getDriver().Dir);
+}
+
+Darwin_X86::~Darwin_X86() {
+ // Free tool implementations.
+ for (llvm::DenseMap<unsigned, Tool*>::iterator
+ it = Tools.begin(), ie = Tools.end(); it != ie; ++it)
+ delete it->second;
+}
+
+Tool &Darwin_X86::SelectTool(const Compilation &C,
+ const JobAction &JA) const {
+ Action::ActionClass Key;
+ if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName()))
+ Key = Action::AnalyzeJobClass;
+ else
+ Key = JA.getKind();
+
+ Tool *&T = Tools[Key];
+ if (!T) {
+ switch (Key) {
+ case Action::InputClass:
+ case Action::BindArchClass:
+ assert(0 && "Invalid tool kind.");
+ case Action::PreprocessJobClass:
+ T = new tools::darwin::Preprocess(*this); break;
+ case Action::AnalyzeJobClass:
+ T = new tools::Clang(*this); break;
+ case Action::PrecompileJobClass:
+ case Action::CompileJobClass:
+ T = new tools::darwin::Compile(*this); break;
+ case Action::AssembleJobClass:
+ T = new tools::darwin::Assemble(*this); break;
+ case Action::LinkJobClass:
+ T = new tools::darwin::Link(*this, MacosxVersionMin.c_str()); break;
+ case Action::LipoJobClass:
+ T = new tools::darwin::Lipo(*this); break;
+ }
+ }
+
+ return *T;
+}
+
+DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const {
+ DerivedArgList *DAL = new DerivedArgList(Args, false);
+ const OptTable &Opts = getHost().getDriver().getOpts();
+
+ // FIXME: We really want to get out of the tool chain level argument
+ // translation business, as it makes the driver functionality much
+ // more opaque. For now, we follow gcc closely solely for the
+ // purpose of easily achieving feature parity & testability. Once we
+ // have something that works, we should reevaluate each translation
+ // and try to push it down into tool specific logic.
+
+ Arg *OSXVersion =
+ Args.getLastArg(options::OPT_mmacosx_version_min_EQ, false);
+ Arg *iPhoneVersion =
+ Args.getLastArg(options::OPT_miphoneos_version_min_EQ, false);
+ if (OSXVersion && iPhoneVersion) {
+ getHost().getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << OSXVersion->getAsString(Args)
+ << iPhoneVersion->getAsString(Args);
+ } else if (!OSXVersion && !iPhoneVersion) {
+ // Chose the default version based on the arch.
+ //
+ // FIXME: This will need to be fixed when we merge in arm support.
+
+ // Look for MACOSX_DEPLOYMENT_TARGET, otherwise use the version
+ // from the host.
+ const char *Version = ::getenv("MACOSX_DEPLOYMENT_TARGET");
+ if (!Version)
+ Version = MacosxVersionMin.c_str();
+ const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
+ DAL->append(DAL->MakeJoinedArg(0, O, Version));
+ }
+
+ for (ArgList::iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) {
+ Arg *A = *it;
+
+ if (A->getOption().matches(options::OPT_Xarch__)) {
+ // FIXME: Canonicalize name.
+ if (getArchName() != A->getValue(Args, 0))
+ continue;
+
+ // FIXME: The arg is leaked here, and we should have a nicer
+ // interface for this.
+ unsigned Prev, Index = Prev = A->getIndex() + 1;
+ Arg *XarchArg = Opts.ParseOneArg(Args, Index);
+
+ // If the argument parsing failed or more than one argument was
+ // consumed, the -Xarch_ argument's parameter tried to consume
+ // extra arguments. Emit an error and ignore.
+ //
+ // We also want to disallow any options which would alter the
+ // driver behavior; that isn't going to work in our model. We
+ // use isDriverOption() as an approximation, although things
+ // like -O4 are going to slip through.
+ if (!XarchArg || Index > Prev + 1 ||
+ XarchArg->getOption().isDriverOption()) {
+ getHost().getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument)
+ << A->getAsString(Args);
+ continue;
+ }
+
+ XarchArg->setBaseArg(A);
+ A = XarchArg;
+ }
+
+ // Sob. These is strictly gcc compatible for the time being. Apple
+ // gcc translates options twice, which means that self-expanding
+ // options add duplicates.
+ options::ID id = A->getOption().getId();
+ switch (id) {
+ default:
+ DAL->append(A);
+ break;
+
+ case options::OPT_mkernel:
+ case options::OPT_fapple_kext:
+ DAL->append(A);
+ DAL->append(DAL->MakeFlagArg(A, Opts.getOption(options::OPT_static)));
+ DAL->append(DAL->MakeFlagArg(A, Opts.getOption(options::OPT_static)));
+ break;
+
+ case options::OPT_dependency_file:
+ DAL->append(DAL->MakeSeparateArg(A, Opts.getOption(options::OPT_MF),
+ A->getValue(Args)));
+ break;
+
+ case options::OPT_gfull:
+ DAL->append(DAL->MakeFlagArg(A, Opts.getOption(options::OPT_g_Flag)));
+ DAL->append(DAL->MakeFlagArg(A,
+ Opts.getOption(options::OPT_fno_eliminate_unused_debug_symbols)));
+ break;
+
+ case options::OPT_gused:
+ DAL->append(DAL->MakeFlagArg(A, Opts.getOption(options::OPT_g_Flag)));
+ DAL->append(DAL->MakeFlagArg(A,
+ Opts.getOption(options::OPT_feliminate_unused_debug_symbols)));
+ break;
+
+ case options::OPT_fterminated_vtables:
+ case options::OPT_findirect_virtual_calls:
+ DAL->append(DAL->MakeFlagArg(A,
+ Opts.getOption(options::OPT_fapple_kext)));
+ DAL->append(DAL->MakeFlagArg(A, Opts.getOption(options::OPT_static)));
+ break;
+
+ case options::OPT_shared:
+ DAL->append(DAL->MakeFlagArg(A, Opts.getOption(options::OPT_dynamiclib)));
+ break;
+
+ case options::OPT_fconstant_cfstrings:
+ DAL->append(DAL->MakeFlagArg(A,
+ Opts.getOption(options::OPT_mconstant_cfstrings)));
+ break;
+
+ case options::OPT_fno_constant_cfstrings:
+ DAL->append(DAL->MakeFlagArg(A,
+ Opts.getOption(options::OPT_mno_constant_cfstrings)));
+ break;
+
+ case options::OPT_Wnonportable_cfstrings:
+ DAL->append(DAL->MakeFlagArg(A,
+ Opts.getOption(options::OPT_mwarn_nonportable_cfstrings)));
+ break;
+
+ case options::OPT_Wno_nonportable_cfstrings:
+ DAL->append(DAL->MakeFlagArg(A,
+ Opts.getOption(options::OPT_mno_warn_nonportable_cfstrings)));
+ break;
+
+ case options::OPT_fpascal_strings:
+ DAL->append(DAL->MakeFlagArg(A,
+ Opts.getOption(options::OPT_mpascal_strings)));
+ break;
+
+ case options::OPT_fno_pascal_strings:
+ DAL->append(DAL->MakeFlagArg(A,
+ Opts.getOption(options::OPT_mno_pascal_strings)));
+ break;
+ }
+ }
+
+ // FIXME: Actually, gcc always adds this, but it is filtered for
+ // duplicates somewhere. This also changes the order of things, so
+ // look it up.
+ if (getArchName() == "x86_64")
+ if (!Args.hasArg(options::OPT_m64, false))
+ DAL->append(DAL->MakeFlagArg(0, Opts.getOption(options::OPT_m64)));
+
+ if (!Args.hasArg(options::OPT_mtune_EQ, false))
+ DAL->append(DAL->MakeJoinedArg(0, Opts.getOption(options::OPT_mtune_EQ),
+ "core2"));
+
+ return DAL;
+}
+
+bool Darwin_X86::IsMathErrnoDefault() const {
+ return false;
+}
+
+bool Darwin_X86::IsUnwindTablesDefault() const {
+ // FIXME: Gross; we should probably have some separate target
+ // definition, possibly even reusing the one in clang.
+ return getArchName() == "x86_64";
+}
+
+const char *Darwin_X86::GetDefaultRelocationModel() const {
+ return "pic";
+}
+
+const char *Darwin_X86::GetForcedPicModel() const {
+ if (getArchName() == "x86_64")
+ return "pic";
+ return 0;
+}
+
+/// Generic_GCC - A tool chain using the 'gcc' command to perform
+/// all subcommands; this relies on gcc translating the majority of
+/// command line options.
+
+Generic_GCC::Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple)
+ : ToolChain(Host, Triple)
+{
+ std::string Path(getHost().getDriver().Dir);
+ Path += "/../libexec";
+ getProgramPaths().push_back(Path);
+
+ getProgramPaths().push_back(getHost().getDriver().Dir);
+}
+
+Generic_GCC::~Generic_GCC() {
+ // Free tool implementations.
+ for (llvm::DenseMap<unsigned, Tool*>::iterator
+ it = Tools.begin(), ie = Tools.end(); it != ie; ++it)
+ delete it->second;
+}
+
+Tool &Generic_GCC::SelectTool(const Compilation &C,
+ const JobAction &JA) const {
+ Action::ActionClass Key;
+ if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName()))
+ Key = Action::AnalyzeJobClass;
+ else
+ Key = JA.getKind();
+
+ Tool *&T = Tools[Key];
+ if (!T) {
+ switch (Key) {
+ case Action::InputClass:
+ case Action::BindArchClass:
+ assert(0 && "Invalid tool kind.");
+ case Action::PreprocessJobClass:
+ T = new tools::gcc::Preprocess(*this); break;
+ case Action::PrecompileJobClass:
+ T = new tools::gcc::Precompile(*this); break;
+ case Action::AnalyzeJobClass:
+ T = new tools::Clang(*this); break;
+ case Action::CompileJobClass:
+ T = new tools::gcc::Compile(*this); break;
+ case Action::AssembleJobClass:
+ T = new tools::gcc::Assemble(*this); break;
+ case Action::LinkJobClass:
+ T = new tools::gcc::Link(*this); break;
+
+ // This is a bit ungeneric, but the only platform using a driver
+ // driver is Darwin.
+ case Action::LipoJobClass:
+ T = new tools::darwin::Lipo(*this); break;
+ }
+ }
+
+ return *T;
+}
+
+bool Generic_GCC::IsMathErrnoDefault() const {
+ return true;
+}
+
+bool Generic_GCC::IsUnwindTablesDefault() const {
+ // FIXME: Gross; we should probably have some separate target
+ // definition, possibly even reusing the one in clang.
+ return getArchName() == "x86_64";
+}
+
+const char *Generic_GCC::GetDefaultRelocationModel() const {
+ return "static";
+}
+
+const char *Generic_GCC::GetForcedPicModel() const {
+ return 0;
+}
+
+DerivedArgList *Generic_GCC::TranslateArgs(InputArgList &Args) const {
+ return new DerivedArgList(Args, true);
+}
+
+/// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly.
+
+FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple, bool Lib32)
+ : Generic_GCC(Host, Triple) {
+ if (Lib32) {
+ getFilePaths().push_back(getHost().getDriver().Dir + "/../lib32");
+ getFilePaths().push_back("/usr/lib32");
+ } else {
+ getFilePaths().push_back(getHost().getDriver().Dir + "/../lib");
+ getFilePaths().push_back("/usr/lib");
+ }
+}
+
+Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const {
+ Action::ActionClass Key;
+ if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName()))
+ Key = Action::AnalyzeJobClass;
+ else
+ Key = JA.getKind();
+
+ Tool *&T = Tools[Key];
+ if (!T) {
+ switch (Key) {
+ case Action::AssembleJobClass:
+ T = new tools::freebsd::Assemble(*this); break;
+ case Action::LinkJobClass:
+ T = new tools::freebsd::Link(*this); break;
+ default:
+ T = &Generic_GCC::SelectTool(C, JA);
+ }
+ }
+
+ return *T;
+}
+
+/// Linux toolchain (very bare-bones at the moment).
+
+Linux::Linux(const HostInfo &Host, const llvm::Triple& Triple)
+ : Generic_GCC(Host, Triple) {
+ getFilePaths().push_back(getHost().getDriver().Dir + "/../lib/clang/1.0/");
+ getFilePaths().push_back("/lib/");
+ getFilePaths().push_back("/usr/lib/");
+ // FIXME: Figure out some way to get gcc's libdir
+ // (e.g. /usr/lib/gcc/i486-linux-gnu/4.3/ for Ubuntu 32-bit); we need
+ // crtbegin.o/crtend.o/etc., and want static versions of various
+ // libraries. If we had our own crtbegin.o/crtend.o/etc, we could probably
+ // get away with using shared versions in /usr/lib, though.
+ // We could fall back to the approach we used for includes (a massive
+ // list), but that's messy at best.
+}
+
+/// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly.
+
+DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple)
+ : Generic_GCC(Host, Triple) {
+
+ // Path mangling to find libexec
+ std::string Path(getHost().getDriver().Dir);
+
+ Path += "/../libexec";
+ getProgramPaths().push_back(Path);
+ getProgramPaths().push_back(getHost().getDriver().Dir);
+
+ getFilePaths().push_back(getHost().getDriver().Dir + "/../lib");
+ getFilePaths().push_back("/usr/lib");
+ getFilePaths().push_back("/usr/lib/gcc41");
+}
+
+Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA) const {
+ Action::ActionClass Key;
+ if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName()))
+ Key = Action::AnalyzeJobClass;
+ else
+ Key = JA.getKind();
+
+ Tool *&T = Tools[Key];
+ if (!T) {
+ switch (Key) {
+ case Action::AssembleJobClass:
+ T = new tools::dragonfly::Assemble(*this); break;
+ case Action::LinkJobClass:
+ T = new tools::dragonfly::Link(*this); break;
+ default:
+ T = &Generic_GCC::SelectTool(C, JA);
+ }
+ }
+
+ return *T;
+}
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
new file mode 100644
index 000000000000..3ecd1715da96
--- /dev/null
+++ b/lib/Driver/ToolChains.h
@@ -0,0 +1,134 @@
+//===--- ToolChains.h - ToolChain Implementations ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_LIB_DRIVER_TOOLCHAINS_H_
+#define CLANG_LIB_DRIVER_TOOLCHAINS_H_
+
+#include "clang/Driver/Action.h"
+#include "clang/Driver/ToolChain.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/Compiler.h"
+
+#include "Tools.h"
+
+namespace clang {
+namespace driver {
+namespace toolchains {
+
+ /// Generic_GCC - A tool chain using the 'gcc' command to perform
+ /// all subcommands; this relies on gcc translating the majority of
+ /// command line options.
+class VISIBILITY_HIDDEN Generic_GCC : public ToolChain {
+protected:
+ mutable llvm::DenseMap<unsigned, Tool*> Tools;
+
+public:
+ Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple);
+ ~Generic_GCC();
+
+ virtual DerivedArgList *TranslateArgs(InputArgList &Args) const;
+
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+
+ virtual bool IsMathErrnoDefault() const;
+ virtual bool IsUnwindTablesDefault() const;
+ virtual const char *GetDefaultRelocationModel() const;
+ virtual const char *GetForcedPicModel() const;
+};
+
+ /// Darwin_X86 - Darwin tool chain for i386 an x86_64.
+class VISIBILITY_HIDDEN Darwin_X86 : public ToolChain {
+ mutable llvm::DenseMap<unsigned, Tool*> Tools;
+
+ /// Darwin version of tool chain.
+ unsigned DarwinVersion[3];
+
+ /// GCC version to use.
+ unsigned GCCVersion[3];
+
+ /// The directory suffix for this tool chain.
+ std::string ToolChainDir;
+
+ /// The default macosx-version-min of this tool chain; empty until
+ /// initialized.
+ mutable std::string MacosxVersionMin;
+
+ const char *getMacosxVersionMin() const;
+
+public:
+ Darwin_X86(const HostInfo &Host, const llvm::Triple& Triple,
+ const unsigned (&DarwinVersion)[3],
+ const unsigned (&GCCVersion)[3]);
+ ~Darwin_X86();
+
+ void getDarwinVersion(unsigned (&Res)[3]) const {
+ Res[0] = DarwinVersion[0];
+ Res[1] = DarwinVersion[1];
+ Res[2] = DarwinVersion[2];
+ }
+
+ void getMacosxVersion(unsigned (&Res)[3]) const {
+ Res[0] = 10;
+ Res[1] = DarwinVersion[0] - 4;
+ Res[2] = DarwinVersion[1];
+ }
+
+ const char *getMacosxVersionStr() const {
+ return MacosxVersionMin.c_str();
+ }
+
+ const std::string &getToolChainDir() const {
+ return ToolChainDir;
+ }
+
+ virtual DerivedArgList *TranslateArgs(InputArgList &Args) const;
+
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+
+ virtual bool IsMathErrnoDefault() const;
+ virtual bool IsUnwindTablesDefault() const;
+ virtual const char *GetDefaultRelocationModel() const;
+ virtual const char *GetForcedPicModel() const;
+};
+
+ /// Darwin_GCC - Generic Darwin tool chain using gcc.
+class VISIBILITY_HIDDEN Darwin_GCC : public Generic_GCC {
+public:
+ Darwin_GCC(const HostInfo &Host, const llvm::Triple& Triple)
+ : Generic_GCC(Host, Triple) {}
+
+ virtual const char *GetDefaultRelocationModel() const { return "pic"; }
+};
+
+class VISIBILITY_HIDDEN FreeBSD : public Generic_GCC {
+public:
+ FreeBSD(const HostInfo &Host, const llvm::Triple& Triple, bool Lib32);
+
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+};
+
+class VISIBILITY_HIDDEN DragonFly : public Generic_GCC {
+public:
+ DragonFly(const HostInfo &Host, const llvm::Triple& Triple);
+
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+};
+
+class VISIBILITY_HIDDEN Linux : public Generic_GCC {
+public:
+ Linux(const HostInfo &Host, const llvm::Triple& Triple);
+};
+
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
new file mode 100644
index 000000000000..abfabbb721a1
--- /dev/null
+++ b/lib/Driver/Tools.cpp
@@ -0,0 +1,2033 @@
+//===--- Tools.cpp - Tools Implementations ------------------------------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Tools.h"
+
+#include "clang/Driver/Action.h"
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Driver.h" // FIXME: Remove?
+#include "clang/Driver/DriverDiagnostic.h" // FIXME: Remove?
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Job.h"
+#include "clang/Driver/HostInfo.h"
+#include "clang/Driver/Option.h"
+#include "clang/Driver/ToolChain.h"
+#include "clang/Driver/Util.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "InputInfo.h"
+#include "ToolChains.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+
+static const char *MakeFormattedString(const ArgList &Args,
+ const llvm::format_object_base &Fmt) {
+ std::string Str;
+ llvm::raw_string_ostream(Str) << Fmt;
+ return Args.MakeArgString(Str.c_str());
+}
+
+void Clang::AddPreprocessingOptions(const Driver &D,
+ const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs) const {
+ // Handle dependency file generation.
+ Arg *A;
+ if ((A = Args.getLastArg(options::OPT_M)) ||
+ (A = Args.getLastArg(options::OPT_MM)) ||
+ (A = Args.getLastArg(options::OPT_MD)) ||
+ (A = Args.getLastArg(options::OPT_MMD))) {
+ // Determine the output location.
+ const char *DepFile;
+ if (Output.getType() == types::TY_Dependencies) {
+ if (Output.isPipe())
+ DepFile = "-";
+ else
+ DepFile = Output.getFilename();
+ } else if (Arg *MF = Args.getLastArg(options::OPT_MF)) {
+ DepFile = MF->getValue(Args);
+ } else if (A->getOption().getId() == options::OPT_M ||
+ A->getOption().getId() == options::OPT_MM) {
+ DepFile = "-";
+ } else {
+ DepFile = darwin::CC1::getDependencyFileName(Args, Inputs);
+ }
+ CmdArgs.push_back("-dependency-file");
+ CmdArgs.push_back(DepFile);
+
+ // Add an -MT option if the user didn't specify their own.
+ // FIXME: This should use -MQ, when we support it.
+ if (!Args.hasArg(options::OPT_MT) && !Args.hasArg(options::OPT_MQ)) {
+ const char *DepTarget;
+
+ // If user provided -o, that is the dependency target, except
+ // when we are only generating a dependency file.
+ Arg *OutputOpt = Args.getLastArg(options::OPT_o);
+ if (OutputOpt && Output.getType() != types::TY_Dependencies) {
+ DepTarget = OutputOpt->getValue(Args);
+ } else {
+ // Otherwise derive from the base input.
+ //
+ // FIXME: This should use the computed output file location.
+ llvm::sys::Path P(Inputs[0].getBaseInput());
+
+ P.eraseSuffix();
+ P.appendSuffix("o");
+ DepTarget = Args.MakeArgString(P.getLast().c_str());
+ }
+
+ CmdArgs.push_back("-MT");
+ CmdArgs.push_back(DepTarget);
+ }
+
+ if (A->getOption().getId() == options::OPT_M ||
+ A->getOption().getId() == options::OPT_MD)
+ CmdArgs.push_back("-sys-header-deps");
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_MP);
+ Args.AddAllArgs(CmdArgs, options::OPT_MT);
+
+ // FIXME: Use iterator.
+
+ // Add -i* options, and automatically translate to
+ // -include-pch/-include-pth for transparent PCH support. It's
+ // wonky, but we include looking for .gch so we can support seamless
+ // replacement into a build system already set up to be generating
+ // .gch files.
+ for (ArgList::const_iterator
+ it = Args.begin(), ie = Args.end(); it != ie; ++it) {
+ const Arg *A = *it;
+ if (!A->getOption().matches(options::OPT_clang_i_Group))
+ continue;
+
+ if (A->getOption().matches(options::OPT_include)) {
+ bool FoundPTH = false;
+ bool FoundPCH = false;
+ llvm::sys::Path P(A->getValue(Args));
+ if (D.CCCUsePCH) {
+ P.appendSuffix("pch");
+ if (P.exists())
+ FoundPCH = true;
+ else
+ P.eraseSuffix();
+ }
+
+ if (!FoundPCH) {
+ P.appendSuffix("pth");
+ if (P.exists())
+ FoundPTH = true;
+ else
+ P.eraseSuffix();
+ }
+
+ if (!FoundPCH && !FoundPTH) {
+ P.appendSuffix("gch");
+ if (P.exists()) {
+ FoundPCH = D.CCCUsePCH;
+ FoundPTH = !D.CCCUsePCH;
+ }
+ else
+ P.eraseSuffix();
+ }
+
+ if (FoundPCH || FoundPTH) {
+ A->claim();
+ if (D.CCCUsePCH)
+ CmdArgs.push_back("-include-pch");
+ else
+ CmdArgs.push_back("-include-pth");
+ CmdArgs.push_back(Args.MakeArgString(P.c_str()));
+ continue;
+ }
+ }
+
+ // Not translated, render as usual.
+ A->claim();
+ A->render(Args, CmdArgs);
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U);
+ Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F);
+
+ // Add -Wp, and -Xassembler if using the preprocessor.
+
+ // FIXME: There is a very unfortunate problem here, some troubled
+ // souls abuse -Wp, to pass preprocessor options in gcc syntax. To
+ // really support that we would have to parse and then translate
+ // those options. :(
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA,
+ options::OPT_Xpreprocessor);
+}
+
+void Clang::ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getHost().getDriver();
+ ArgStringList CmdArgs;
+
+ assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
+
+ CmdArgs.push_back("-triple");
+ const char *TripleStr =
+ Args.MakeArgString(getToolChain().getTripleString().c_str());
+ CmdArgs.push_back(TripleStr);
+
+ if (isa<AnalyzeJobAction>(JA)) {
+ assert(JA.getType() == types::TY_Plist && "Invalid output type.");
+ CmdArgs.push_back("-analyze");
+ } else if (isa<PreprocessJobAction>(JA)) {
+ if (Output.getType() == types::TY_Dependencies)
+ CmdArgs.push_back("-Eonly");
+ else
+ CmdArgs.push_back("-E");
+ } else if (isa<PrecompileJobAction>(JA)) {
+ if (D.CCCUsePCH)
+ CmdArgs.push_back("-emit-pch");
+ else
+ CmdArgs.push_back("-emit-pth");
+ } else {
+ assert(isa<CompileJobAction>(JA) && "Invalid action for clang tool.");
+
+ if (JA.getType() == types::TY_Nothing) {
+ CmdArgs.push_back("-fsyntax-only");
+ } else if (JA.getType() == types::TY_LLVMAsm) {
+ CmdArgs.push_back("-emit-llvm");
+ } else if (JA.getType() == types::TY_LLVMBC) {
+ CmdArgs.push_back("-emit-llvm-bc");
+ } else if (JA.getType() == types::TY_PP_Asm) {
+ CmdArgs.push_back("-S");
+ }
+ }
+
+ // The make clang go fast button.
+ CmdArgs.push_back("-disable-free");
+
+ // Set the main file name, so that debug info works even with
+ // -save-temps.
+ CmdArgs.push_back("-main-file-name");
+ CmdArgs.push_back(darwin::CC1::getBaseInputName(Args, Inputs));
+
+ // Some flags which affect the language (via preprocessor
+ // defines). See darwin::CC1::AddCPPArgs.
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("-static-define");
+
+ if (isa<AnalyzeJobAction>(JA)) {
+ // Add default argument set.
+ if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
+ CmdArgs.push_back("-warn-dead-stores");
+ CmdArgs.push_back("-checker-cfref");
+ CmdArgs.push_back("-analyzer-eagerly-assume");
+ CmdArgs.push_back("-warn-objc-methodsigs");
+ // Do not enable the missing -dealloc check.
+ // '-warn-objc-missing-dealloc',
+ CmdArgs.push_back("-warn-objc-unused-ivars");
+ }
+
+ // Set the output format. The default is plist, for (lame) historical
+ // reasons.
+ CmdArgs.push_back("-analyzer-output");
+ if (Arg *A = Args.getLastArg(options::OPT__analyzer_output))
+ CmdArgs.push_back(A->getValue(Args));
+ else
+ CmdArgs.push_back("plist");
+
+ // Add -Xanalyzer arguments when running as analyzer.
+ Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer);
+ }
+
+ // Perform argument translation for LLVM backend. This
+ // takes some care in reconciling with llvm-gcc. The
+ // issue is that llvm-gcc translates these options based on
+ // the values in cc1, whereas we are processing based on
+ // the driver arguments.
+ //
+ // FIXME: This is currently broken for -f flags when -fno
+ // variants are present.
+
+ // This comes from the default translation the driver + cc1
+ // would do to enable flag_pic.
+ //
+ // FIXME: Centralize this code.
+ bool PICEnabled = (Args.hasArg(options::OPT_fPIC) ||
+ Args.hasArg(options::OPT_fpic) ||
+ Args.hasArg(options::OPT_fPIE) ||
+ Args.hasArg(options::OPT_fpie));
+ bool PICDisabled = (Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_static));
+ const char *Model = getToolChain().GetForcedPicModel();
+ if (!Model) {
+ if (Args.hasArg(options::OPT_mdynamic_no_pic))
+ Model = "dynamic-no-pic";
+ else if (PICDisabled)
+ Model = "static";
+ else if (PICEnabled)
+ Model = "pic";
+ else
+ Model = getToolChain().GetDefaultRelocationModel();
+ }
+ CmdArgs.push_back("--relocation-model");
+ CmdArgs.push_back(Model);
+
+ // Infer the __PIC__ value.
+ //
+ // FIXME: This isn't quite right on Darwin, which always sets
+ // __PIC__=2.
+ if (strcmp(Model, "pic") == 0 || strcmp(Model, "dynamic-no-pic") == 0) {
+ if (Args.hasArg(options::OPT_fPIC))
+ CmdArgs.push_back("-pic-level=2");
+ else
+ CmdArgs.push_back("-pic-level=1");
+ }
+
+ if (Args.hasArg(options::OPT_ftime_report))
+ CmdArgs.push_back("--time-passes");
+ // FIXME: Set --enable-unsafe-fp-math.
+ if (!Args.hasArg(options::OPT_fomit_frame_pointer))
+ CmdArgs.push_back("--disable-fp-elim");
+ if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss,
+ options::OPT_fno_zero_initialized_in_bss,
+ true))
+ CmdArgs.push_back("--nozero-initialized-in-bss");
+ if (Args.hasArg(options::OPT_dA) || Args.hasArg(options::OPT_fverbose_asm))
+ CmdArgs.push_back("--asm-verbose");
+ if (Args.hasArg(options::OPT_fdebug_pass_structure))
+ CmdArgs.push_back("--debug-pass=Structure");
+ if (Args.hasArg(options::OPT_fdebug_pass_arguments))
+ CmdArgs.push_back("--debug-pass=Arguments");
+ // FIXME: set --inline-threshhold=50 if (optimize_size || optimize
+ // < 3)
+ if (Args.hasFlag(options::OPT_funwind_tables,
+ options::OPT_fno_unwind_tables,
+ (getToolChain().IsUnwindTablesDefault() &&
+ !Args.hasArg(options::OPT_mkernel))))
+ CmdArgs.push_back("--unwind-tables=1");
+ else
+ CmdArgs.push_back("--unwind-tables=0");
+ if (!Args.hasFlag(options::OPT_mred_zone,
+ options::OPT_mno_red_zone,
+ true) ||
+ Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_fapple_kext))
+ CmdArgs.push_back("--disable-red-zone");
+ if (Args.hasFlag(options::OPT_msoft_float,
+ options::OPT_mno_soft_float,
+ false))
+ CmdArgs.push_back("--soft-float");
+
+ // FIXME: Handle -mtune=.
+ (void) Args.hasArg(options::OPT_mtune_EQ);
+
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+ // FIXME: We may need some translation here from the options gcc takes to
+ // names the LLVM backend understand?
+ CmdArgs.push_back("-mcpu");
+ CmdArgs.push_back(A->getValue(Args));
+ } else {
+ // Select default CPU.
+
+ // FIXME: Need target hooks.
+ if (memcmp(getToolChain().getOS().c_str(), "darwin", 6) == 0) {
+ if (getToolChain().getArchName() == "x86_64")
+ CmdArgs.push_back("--mcpu=core2");
+ else if (getToolChain().getArchName() == "i386")
+ CmdArgs.push_back("--mcpu=yonah");
+ } else {
+ if (getToolChain().getArchName() == "x86_64")
+ CmdArgs.push_back("--mcpu=x86-64");
+ else if (getToolChain().getArchName() == "i386")
+ CmdArgs.push_back("--mcpu=pentium4");
+ }
+ }
+
+ // FIXME: Use iterator.
+ for (ArgList::const_iterator
+ it = Args.begin(), ie = Args.end(); it != ie; ++it) {
+ const Arg *A = *it;
+ if (A->getOption().matches(options::OPT_m_x86_Features_Group)) {
+ const char *Name = A->getOption().getName();
+
+ // Skip over "-m".
+ assert(Name[0] == '-' && Name[1] == 'm' && "Invalid feature name.");
+ Name += 2;
+
+ bool IsNegative = memcmp(Name, "no-", 3) == 0;
+ if (IsNegative)
+ Name += 3;
+
+ A->claim();
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("%c%s",
+ IsNegative ? '-' : '+',
+ Name)));
+ }
+ }
+
+ if (Args.hasFlag(options::OPT_fmath_errno,
+ options::OPT_fno_math_errno,
+ getToolChain().IsMathErrnoDefault()))
+ CmdArgs.push_back("--fmath-errno=1");
+ else
+ CmdArgs.push_back("--fmath-errno=0");
+
+ if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
+ CmdArgs.push_back("--limit-float-precision");
+ CmdArgs.push_back(A->getValue(Args));
+ }
+
+ // FIXME: Add --stack-protector-buffer-size=<xxx> on
+ // -fstack-protect.
+
+ Arg *Unsupported;
+ if ((Unsupported = Args.getLastArg(options::OPT_MG)) ||
+ (Unsupported = Args.getLastArg(options::OPT_MQ)) ||
+ (Unsupported = Args.getLastArg(options::OPT_iframework)))
+ D.Diag(clang::diag::err_drv_clang_unsupported)
+ << Unsupported->getOption().getName();
+
+ Args.AddAllArgs(CmdArgs, options::OPT_v);
+ Args.AddLastArg(CmdArgs, options::OPT_P);
+ Args.AddLastArg(CmdArgs, options::OPT_mmacosx_version_min_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_miphoneos_version_min_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout);
+
+ // Special case debug options to only pass -g to clang. This is
+ // wrong.
+ if (Args.hasArg(options::OPT_g_Group))
+ CmdArgs.push_back("-g");
+
+ Args.AddLastArg(CmdArgs, options::OPT_nostdinc);
+
+ Args.AddLastArg(CmdArgs, options::OPT_isysroot);
+
+ // Add preprocessing options like -I, -D, etc. if we are using the
+ // preprocessor.
+ //
+ // FIXME: Support -fpreprocessed
+ types::ID InputType = Inputs[0].getType();
+ if (types::getPreprocessedType(InputType) != types::TY_INVALID)
+ AddPreprocessingOptions(D, Args, CmdArgs, Output, Inputs);
+
+ // Manually translate -O to -O1 and -O4 to -O3; let clang reject
+ // others.
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
+ if (A->getOption().getId() == options::OPT_O4)
+ CmdArgs.push_back("-O3");
+ else if (A->getValue(Args)[0] == '\0')
+ CmdArgs.push_back("-O1");
+ else
+ A->render(Args, CmdArgs);
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_W_Group, options::OPT_pedantic_Group);
+ Args.AddLastArg(CmdArgs, options::OPT_w);
+
+ // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi}
+ // (-ansi is equivalent to -std=c89).
+ //
+ // If a std is supplied, only add -trigraphs if it follows the
+ // option.
+ if (Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) {
+ if (Std->getOption().matches(options::OPT_ansi))
+ CmdArgs.push_back("-std=c89");
+ else
+ Std->render(Args, CmdArgs);
+
+ if (Arg *A = Args.getLastArg(options::OPT_trigraphs))
+ if (A->getIndex() > Std->getIndex())
+ A->render(Args, CmdArgs);
+ } else {
+ // Honor -std-default.
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
+ "-std=", /*Joined=*/true);
+ Args.AddLastArg(CmdArgs, options::OPT_trigraphs);
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_)) {
+ CmdArgs.push_back("-ftemplate-depth");
+ CmdArgs.push_back(A->getValue(Args));
+ }
+
+ // Forward -f options which we can pass directly.
+ Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
+ Args.AddLastArg(CmdArgs, options::OPT_fexceptions);
+ Args.AddLastArg(CmdArgs, options::OPT_ffreestanding);
+ Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
+ Args.AddLastArg(CmdArgs, options::OPT_fgnu_runtime);
+ Args.AddLastArg(CmdArgs, options::OPT_flax_vector_conversions);
+ Args.AddLastArg(CmdArgs, options::OPT_fmessage_length_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fms_extensions);
+ Args.AddLastArg(CmdArgs, options::OPT_fnext_runtime);
+ Args.AddLastArg(CmdArgs, options::OPT_fno_caret_diagnostics);
+ Args.AddLastArg(CmdArgs, options::OPT_fno_show_column);
+ Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc_only);
+ Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc);
+ Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
+ // FIXME: Should we remove this?
+ Args.AddLastArg(CmdArgs, options::OPT_fobjc_nonfragile_abi);
+ Args.AddLastArg(CmdArgs, options::OPT_fobjc_tight_layout);
+ Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
+ Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
+ Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
+ Args.AddLastArg(CmdArgs, options::OPT_fvisibility_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings);
+
+ // Forward -f options with positive and negative forms; we translate
+ // these by hand.
+
+ // -fbuiltin is default, only pass non-default.
+ if (!Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin))
+ CmdArgs.push_back("-fbuiltin=0");
+
+ // -fblocks default varies depending on platform and language; only
+ // pass if specified.
+ if (Arg *A = Args.getLastArg(options::OPT_fblocks, options::OPT_fno_blocks)) {
+ if (A->getOption().matches(options::OPT_fblocks))
+ CmdArgs.push_back("-fblocks");
+ else
+ CmdArgs.push_back("-fblocks=0");
+ }
+
+ // -fno-pascal-strings is default, only pass non-default. If the
+ // -tool chain happened to translate to -mpascal-strings, we want to
+ // -back translate here.
+ //
+ // FIXME: This is gross; that translation should be pulled from the
+ // tool chain.
+ if (Args.hasFlag(options::OPT_fpascal_strings,
+ options::OPT_fno_pascal_strings,
+ false) ||
+ Args.hasFlag(options::OPT_mpascal_strings,
+ options::OPT_mno_pascal_strings,
+ false))
+ CmdArgs.push_back("-fpascal-strings");
+
+ // -fcommon is default, only pass non-default.
+ if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common))
+ CmdArgs.push_back("-fno-common");
+
+ // -fsigned-bitfields is default, and clang doesn't yet support
+ // --funsigned-bitfields.
+ if (!Args.hasFlag(options::OPT_fsigned_bitfields,
+ options::OPT_funsigned_bitfields))
+ D.Diag(clang::diag::warn_drv_clang_unsupported)
+ << Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args);
+
+ // -fdiagnostics-fixit-info is default, only pass non-default.
+ if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info,
+ options::OPT_fno_diagnostics_fixit_info))
+ CmdArgs.push_back("-fno-diagnostics-fixit-info");
+
+ // Enable -fdiagnostics-show-option by default.
+ if (Args.hasFlag(options::OPT_fdiagnostics_show_option,
+ options::OPT_fno_diagnostics_show_option))
+ CmdArgs.push_back("-fdiagnostics-show-option");
+
+ // -fdollars-in-identifiers default varies depending on platform and
+ // language; only pass if specified.
+ if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers,
+ options::OPT_fno_dollars_in_identifiers)) {
+ if (A->getOption().matches(options::OPT_fdollars_in_identifiers))
+ CmdArgs.push_back("-fdollars-in-identifiers=1");
+ else
+ CmdArgs.push_back("-fdollars-in-identifiers=0");
+ }
+
+ // -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for
+ // practical purposes.
+ 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::err_drv_clang_unsupported) << A->getAsString(Args);
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_dM);
+ Args.AddLastArg(CmdArgs, options::OPT_dD);
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
+
+ if (Output.getType() == types::TY_Dependencies) {
+ // Handled with other dependency code.
+ } else if (Output.isPipe()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back("-");
+ } else if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+ const InputInfo &II = *it;
+ CmdArgs.push_back("-x");
+ CmdArgs.push_back(types::getTypeName(II.getType()));
+ if (II.isPipe())
+ CmdArgs.push_back("-");
+ else if (II.isFilename())
+ CmdArgs.push_back(II.getFilename());
+ else
+ II.getInputArg().renderAsInput(Args, CmdArgs);
+ }
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "clang-cc").c_str());
+ Dest.addCommand(new Command(Exec, CmdArgs));
+
+ // Explicitly warn that these options are unsupported, even though
+ // we are allowing compilation to continue.
+ // FIXME: Use iterator.
+ for (ArgList::const_iterator
+ it = Args.begin(), ie = Args.end(); it != ie; ++it) {
+ const Arg *A = *it;
+ if (A->getOption().matches(options::OPT_pg)) {
+ A->claim();
+ D.Diag(clang::diag::warn_drv_clang_unsupported)
+ << A->getAsString(Args);
+ }
+ }
+
+ // Claim some arguments which clang supports automatically.
+
+ // -fpch-preprocess is used with gcc to add a special marker in the
+ // -output to include the PCH file. Clang's PTH solution is
+ // -completely transparent, so we do not need to deal with it at
+ // -all.
+ Args.ClaimAllArgs(options::OPT_fpch_preprocess);
+
+ // Claim some arguments which clang doesn't support, but we don't
+ // care to warn the user about.
+
+ // FIXME: Use iterator.
+ for (ArgList::const_iterator
+ it = Args.begin(), ie = Args.end(); it != ie; ++it) {
+ const Arg *A = *it;
+ if (A->getOption().matches(options::OPT_clang_ignored_f_Group) ||
+ A->getOption().matches(options::OPT_clang_ignored_m_Group))
+ A->claim();
+ }
+}
+
+void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getHost().getDriver();
+ ArgStringList CmdArgs;
+
+ for (ArgList::const_iterator
+ it = Args.begin(), ie = Args.end(); it != ie; ++it) {
+ Arg *A = *it;
+ if (A->getOption().hasForwardToGCC()) {
+ // It is unfortunate that we have to claim here, as this means
+ // we will basically never report anything interesting for
+ // platforms using a generic gcc, even if we are just using gcc
+ // to get to the assembler.
+ A->claim();
+ A->render(Args, CmdArgs);
+ }
+ }
+
+ RenderExtraToolArgs(CmdArgs);
+
+ // If using a driver driver, force the arch.
+ const std::string &Arch = getToolChain().getArchName();
+ if (getToolChain().getHost().useDriverDriver()) {
+ CmdArgs.push_back("-arch");
+
+ // FIXME: Remove these special cases.
+ if (Arch == "powerpc")
+ CmdArgs.push_back("ppc");
+ else if (Arch == "powerpc64")
+ CmdArgs.push_back("ppc64");
+ else
+ CmdArgs.push_back(Args.MakeArgString(Arch.c_str()));
+ }
+
+ // Try to force gcc to match the tool chain we want, if we recognize
+ // the arch.
+ //
+ // FIXME: The triple class should directly provide the information we want
+ // here.
+ if (Arch == "i386" || Arch == "powerpc")
+ CmdArgs.push_back("-m32");
+ else if (Arch == "x86_64" || Arch == "powerpc64")
+ CmdArgs.push_back("-m64");
+
+ if (Output.isPipe()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back("-");
+ } else if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Unexpected output");
+ CmdArgs.push_back("-fsyntax-only");
+ }
+
+
+ // Only pass -x if gcc will understand it; otherwise hope gcc
+ // understands the suffix correctly. The main use case this would go
+ // wrong in is for linker inputs if they happened to have an odd
+ // suffix; really the only way to get this to happen is a command
+ // like '-x foobar a.c' which will treat a.c like a linker input.
+ //
+ // FIXME: For the linker case specifically, can we safely convert
+ // inputs into '-Wl,' options?
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+ const InputInfo &II = *it;
+
+ // Don't try to pass LLVM inputs to a generic gcc.
+ if (II.getType() == types::TY_LLVMBC)
+ D.Diag(clang::diag::err_drv_no_linker_llvm_support)
+ << getToolChain().getTripleString().c_str();
+
+ if (types::canTypeBeUserSpecified(II.getType())) {
+ CmdArgs.push_back("-x");
+ CmdArgs.push_back(types::getTypeName(II.getType()));
+ }
+
+ if (II.isPipe())
+ CmdArgs.push_back("-");
+ else if (II.isFilename())
+ CmdArgs.push_back(II.getFilename());
+ else
+ // Don't render as input, we need gcc to do the translations.
+ II.getInputArg().render(Args, CmdArgs);
+ }
+
+ const char *GCCName =
+ getToolChain().getHost().getDriver().CCCGenericGCCName.c_str();
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, GCCName).c_str());
+ Dest.addCommand(new Command(Exec, CmdArgs));
+}
+
+void gcc::Preprocess::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
+ CmdArgs.push_back("-E");
+}
+
+void gcc::Precompile::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
+ // The type is good enough.
+}
+
+void gcc::Compile::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
+ CmdArgs.push_back("-S");
+}
+
+void gcc::Assemble::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
+ CmdArgs.push_back("-c");
+}
+
+void gcc::Link::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
+ // The types are (hopefully) good enough.
+}
+
+const char *darwin::CC1::getCC1Name(types::ID Type) const {
+ switch (Type) {
+ default:
+ assert(0 && "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:
+ 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:
+ return "cc1objplus";
+ }
+}
+
+const char *darwin::CC1::getBaseInputName(const ArgList &Args,
+ const InputInfoList &Inputs) {
+ llvm::sys::Path P(Inputs[0].getBaseInput());
+ return Args.MakeArgString(P.getLast().c_str());
+}
+
+const char *darwin::CC1::getBaseInputStem(const ArgList &Args,
+ const InputInfoList &Inputs) {
+ const char *Str = getBaseInputName(Args, Inputs);
+
+ if (const char *End = strchr(Str, '.'))
+ return Args.MakeArgString(std::string(Str, End).c_str());
+
+ return Str;
+}
+
+const char *
+darwin::CC1::getDependencyFileName(const ArgList &Args,
+ const InputInfoList &Inputs) {
+ // FIXME: Think about this more.
+ std::string Res;
+
+ if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
+ std::string Str(OutputOpt->getValue(Args));
+
+ Res = Str.substr(0, Str.rfind('.'));
+ } else
+ Res = darwin::CC1::getBaseInputStem(Args, Inputs);
+
+ return Args.MakeArgString((Res + ".d").c_str());
+}
+
+void darwin::CC1::AddCC1Args(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Derived from cc1 spec.
+
+ // FIXME: -fapple-kext seems to disable this too. Investigate.
+ if (!Args.hasArg(options::OPT_mkernel) && !Args.hasArg(options::OPT_static) &&
+ !Args.hasArg(options::OPT_mdynamic_no_pic))
+ CmdArgs.push_back("-fPIC");
+
+ // gcc has some code here to deal with when no -mmacosx-version-min
+ // and no -miphoneos-version-min is present, but this never happens
+ // due to tool chain specific argument translation.
+
+ // FIXME: Remove mthumb
+ // FIXME: Remove mno-thumb
+ // FIXME: Remove faltivec
+ // FIXME: Remove mno-fused-madd
+ // FIXME: Remove mlong-branch
+ // FIXME: Remove mlongcall
+ // FIXME: Remove mcpu=G4
+ // FIXME: Remove mcpu=G5
+
+ if (Args.hasArg(options::OPT_g_Flag) &&
+ !Args.hasArg(options::OPT_fno_eliminate_unused_debug_symbols))
+ CmdArgs.push_back("-feliminate-unused-debug-symbols");
+}
+
+void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
+ const InputInfoList &Inputs,
+ const ArgStringList &OutputArgs) const {
+ const Driver &D = getToolChain().getHost().getDriver();
+
+ // Derived from cc1_options spec.
+ if (Args.hasArg(options::OPT_fast) ||
+ Args.hasArg(options::OPT_fastf) ||
+ Args.hasArg(options::OPT_fastcp))
+ CmdArgs.push_back("-O3");
+
+ if (Arg *A = Args.getLastArg(options::OPT_pg))
+ if (Args.hasArg(options::OPT_fomit_frame_pointer))
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "-fomit-frame-pointer";
+
+ AddCC1Args(Args, CmdArgs);
+
+ if (!Args.hasArg(options::OPT_Q))
+ CmdArgs.push_back("-quiet");
+
+ CmdArgs.push_back("-dumpbase");
+ CmdArgs.push_back(darwin::CC1::getBaseInputName(Args, Inputs));
+
+ Args.AddAllArgs(CmdArgs, options::OPT_d_Group);
+
+ Args.AddAllArgs(CmdArgs, options::OPT_m_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_a_Group);
+
+ // FIXME: The goal is to use the user provided -o if that is our
+ // final output, otherwise to drive from the original input
+ // name. Find a clean way to go about this.
+ if ((Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) &&
+ Args.hasArg(options::OPT_o)) {
+ Arg *OutputOpt = Args.getLastArg(options::OPT_o);
+ CmdArgs.push_back("-auxbase-strip");
+ CmdArgs.push_back(OutputOpt->getValue(Args));
+ } else {
+ CmdArgs.push_back("-auxbase");
+ CmdArgs.push_back(darwin::CC1::getBaseInputStem(Args, Inputs));
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_g_Group);
+
+ Args.AddAllArgs(CmdArgs, options::OPT_O);
+ // FIXME: -Wall is getting some special treatment. Investigate.
+ Args.AddAllArgs(CmdArgs, options::OPT_W_Group, options::OPT_pedantic_Group);
+ Args.AddLastArg(CmdArgs, options::OPT_w);
+ Args.AddAllArgs(CmdArgs, options::OPT_std_EQ, options::OPT_ansi,
+ options::OPT_trigraphs);
+ if (!Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) {
+ // Honor -std-default.
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
+ "-std=", /*Joined=*/true);
+ }
+
+ if (Args.hasArg(options::OPT_v))
+ CmdArgs.push_back("-version");
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-p");
+ Args.AddLastArg(CmdArgs, options::OPT_p);
+
+ // The driver treats -fsyntax-only specially.
+ Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only);
+
+ Args.AddAllArgs(CmdArgs, options::OPT_undef);
+ if (Args.hasArg(options::OPT_Qn))
+ CmdArgs.push_back("-fno-ident");
+
+ // FIXME: This isn't correct.
+ //Args.AddLastArg(CmdArgs, options::OPT__help)
+ //Args.AddLastArg(CmdArgs, options::OPT__targetHelp)
+
+ CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
+
+ // FIXME: Still don't get what is happening here. Investigate.
+ Args.AddAllArgs(CmdArgs, options::OPT__param);
+
+ if (Args.hasArg(options::OPT_fmudflap) ||
+ Args.hasArg(options::OPT_fmudflapth)) {
+ CmdArgs.push_back("-fno-builtin");
+ CmdArgs.push_back("-fno-merge-constants");
+ }
+
+ if (Args.hasArg(options::OPT_coverage)) {
+ CmdArgs.push_back("-fprofile-arcs");
+ CmdArgs.push_back("-ftest-coverage");
+ }
+
+ if (types::isCXX(Inputs[0].getType()))
+ CmdArgs.push_back("-D__private_extern__=extern");
+}
+
+void darwin::CC1::AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
+ const InputInfoList &Inputs,
+ const ArgStringList &OutputArgs) const {
+ // Derived from cpp_options
+ AddCPPUniqueOptionsArgs(Args, CmdArgs, Inputs);
+
+ CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
+
+ AddCC1Args(Args, CmdArgs);
+
+ // NOTE: The code below has some commonality with cpp_options, but
+ // in classic gcc style ends up sending things in different
+ // orders. This may be a good merge candidate once we drop pedantic
+ // compatibility.
+
+ Args.AddAllArgs(CmdArgs, options::OPT_m_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_std_EQ, options::OPT_ansi,
+ options::OPT_trigraphs);
+ if (!Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) {
+ // Honor -std-default.
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
+ "-std=", /*Joined=*/true);
+ }
+ Args.AddAllArgs(CmdArgs, options::OPT_W_Group, options::OPT_pedantic_Group);
+ Args.AddLastArg(CmdArgs, options::OPT_w);
+
+ // The driver treats -fsyntax-only specially.
+ Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only);
+
+ if (Args.hasArg(options::OPT_g_Group) && !Args.hasArg(options::OPT_g0) &&
+ !Args.hasArg(options::OPT_fno_working_directory))
+ CmdArgs.push_back("-fworking-directory");
+
+ Args.AddAllArgs(CmdArgs, options::OPT_O);
+ Args.AddAllArgs(CmdArgs, options::OPT_undef);
+ if (Args.hasArg(options::OPT_save_temps))
+ CmdArgs.push_back("-fpch-preprocess");
+}
+
+void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const InputInfoList &Inputs) const
+{
+ const Driver &D = getToolChain().getHost().getDriver();
+
+ // Derived from cpp_unique_options.
+ Arg *A;
+ if ((A = Args.getLastArg(options::OPT_C)) ||
+ (A = Args.getLastArg(options::OPT_CC))) {
+ if (!Args.hasArg(options::OPT_E))
+ D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ << A->getAsString(Args) << "-E";
+ }
+ if (!Args.hasArg(options::OPT_Q))
+ CmdArgs.push_back("-quiet");
+ Args.AddAllArgs(CmdArgs, options::OPT_nostdinc);
+ Args.AddLastArg(CmdArgs, options::OPT_v);
+ Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F);
+ Args.AddLastArg(CmdArgs, options::OPT_P);
+
+ // FIXME: Handle %I properly.
+ if (getToolChain().getArchName() == "x86_64") {
+ CmdArgs.push_back("-imultilib");
+ CmdArgs.push_back("x86_64");
+ }
+
+ if (Args.hasArg(options::OPT_MD)) {
+ CmdArgs.push_back("-MD");
+ CmdArgs.push_back(darwin::CC1::getDependencyFileName(Args, Inputs));
+ }
+
+ if (Args.hasArg(options::OPT_MMD)) {
+ CmdArgs.push_back("-MMD");
+ CmdArgs.push_back(darwin::CC1::getDependencyFileName(Args, Inputs));
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_M);
+ Args.AddLastArg(CmdArgs, options::OPT_MM);
+ Args.AddAllArgs(CmdArgs, options::OPT_MF);
+ Args.AddLastArg(CmdArgs, options::OPT_MG);
+ Args.AddLastArg(CmdArgs, options::OPT_MP);
+ Args.AddAllArgs(CmdArgs, options::OPT_MQ);
+ Args.AddAllArgs(CmdArgs, options::OPT_MT);
+ if (!Args.hasArg(options::OPT_M) && !Args.hasArg(options::OPT_MM) &&
+ (Args.hasArg(options::OPT_MD) || Args.hasArg(options::OPT_MMD))) {
+ if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
+ CmdArgs.push_back("-MQ");
+ CmdArgs.push_back(OutputOpt->getValue(Args));
+ }
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_remap);
+ if (Args.hasArg(options::OPT_g3))
+ CmdArgs.push_back("-dD");
+ Args.AddLastArg(CmdArgs, options::OPT_H);
+
+ AddCPPArgs(Args, CmdArgs);
+
+ Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U, options::OPT_A);
+ Args.AddAllArgs(CmdArgs, options::OPT_i_Group);
+
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+ const InputInfo &II = *it;
+
+ if (II.isPipe())
+ CmdArgs.push_back("-");
+ else
+ CmdArgs.push_back(II.getFilename());
+ }
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA,
+ options::OPT_Xpreprocessor);
+
+ if (Args.hasArg(options::OPT_fmudflap)) {
+ CmdArgs.push_back("-D_MUDFLAP");
+ CmdArgs.push_back("-include");
+ CmdArgs.push_back("mf-runtime.h");
+ }
+
+ if (Args.hasArg(options::OPT_fmudflapth)) {
+ CmdArgs.push_back("-D_MUDFLAP");
+ CmdArgs.push_back("-D_MUDFLAPTH");
+ CmdArgs.push_back("-include");
+ CmdArgs.push_back("mf-runtime.h");
+ }
+}
+
+void darwin::CC1::AddCPPArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Derived from cpp spec.
+
+ if (Args.hasArg(options::OPT_static)) {
+ // The gcc spec is broken here, it refers to dynamic but
+ // that has been translated. Start by being bug compatible.
+
+ // if (!Args.hasArg(arglist.parser.dynamicOption))
+ CmdArgs.push_back("-D__STATIC__");
+ } else
+ CmdArgs.push_back("-D__DYNAMIC__");
+
+ if (Args.hasArg(options::OPT_pthread))
+ CmdArgs.push_back("-D_REENTRANT");
+}
+
+void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest, const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ assert(Inputs.size() == 1 && "Unexpected number of inputs!");
+
+ CmdArgs.push_back("-E");
+
+ if (Args.hasArg(options::OPT_traditional) ||
+ Args.hasArg(options::OPT_ftraditional) ||
+ Args.hasArg(options::OPT_traditional_cpp))
+ CmdArgs.push_back("-traditional-cpp");
+
+ ArgStringList OutputArgs;
+ if (Output.isFilename()) {
+ OutputArgs.push_back("-o");
+ OutputArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isPipe() && "Unexpected CC1 output.");
+ }
+
+ if (Args.hasArg(options::OPT_E)) {
+ AddCPPOptionsArgs(Args, CmdArgs, Inputs, OutputArgs);
+ } else {
+ AddCPPOptionsArgs(Args, CmdArgs, Inputs, ArgStringList());
+ CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_d_Group);
+
+ const char *CC1Name = getCC1Name(Inputs[0].getType());
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name).c_str());
+ Dest.addCommand(new Command(Exec, CmdArgs));
+}
+
+void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest, const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getHost().getDriver();
+ ArgStringList CmdArgs;
+
+ assert(Inputs.size() == 1 && "Unexpected number of inputs!");
+
+ types::ID InputType = Inputs[0].getType();
+ const Arg *A;
+ if ((A = Args.getLastArg(options::OPT_traditional)) ||
+ (A = Args.getLastArg(options::OPT_ftraditional)))
+ D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ << A->getAsString(Args) << "-E";
+
+ if (Output.getType() == types::TY_LLVMAsm)
+ CmdArgs.push_back("-emit-llvm");
+ else if (Output.getType() == types::TY_LLVMBC)
+ CmdArgs.push_back("-emit-llvm-bc");
+
+ ArgStringList OutputArgs;
+ if (Output.getType() != types::TY_PCH) {
+ OutputArgs.push_back("-o");
+ if (Output.isPipe())
+ OutputArgs.push_back("-");
+ else if (Output.isNothing())
+ OutputArgs.push_back("/dev/null");
+ else
+ OutputArgs.push_back(Output.getFilename());
+ }
+
+ // There is no need for this level of compatibility, but it makes
+ // diffing easier.
+ bool OutputArgsEarly = (Args.hasArg(options::OPT_fsyntax_only) ||
+ Args.hasArg(options::OPT_S));
+
+ if (types::getPreprocessedType(InputType) != types::TY_INVALID) {
+ AddCPPUniqueOptionsArgs(Args, CmdArgs, Inputs);
+ if (OutputArgsEarly) {
+ AddCC1OptionsArgs(Args, CmdArgs, Inputs, OutputArgs);
+ } else {
+ AddCC1OptionsArgs(Args, CmdArgs, Inputs, ArgStringList());
+ CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
+ }
+ } else {
+ CmdArgs.push_back("-fpreprocessed");
+
+ // FIXME: There is a spec command to remove
+ // -fpredictive-compilation args here. Investigate.
+
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+ const InputInfo &II = *it;
+
+ if (II.isPipe())
+ CmdArgs.push_back("-");
+ else
+ CmdArgs.push_back(II.getFilename());
+ }
+
+ if (OutputArgsEarly) {
+ AddCC1OptionsArgs(Args, CmdArgs, Inputs, OutputArgs);
+ } else {
+ AddCC1OptionsArgs(Args, CmdArgs, Inputs, ArgStringList());
+ CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
+ }
+ }
+
+ if (Output.getType() == types::TY_PCH) {
+ assert(Output.isFilename() && "Invalid PCH output.");
+
+ CmdArgs.push_back("-o");
+ // NOTE: gcc uses a temp .s file for this, but there doesn't seem
+ // to be a good reason.
+ CmdArgs.push_back("/dev/null");
+
+ CmdArgs.push_back("--output-pch=");
+ CmdArgs.push_back(Output.getFilename());
+ }
+
+ const char *CC1Name = getCC1Name(Inputs[0].getType());
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name).c_str());
+ Dest.addCommand(new Command(Exec, CmdArgs));
+}
+
+void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest, const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ assert(Inputs.size() == 1 && "Unexpected number of inputs.");
+ const InputInfo &Input = Inputs[0];
+
+ // Bit of a hack, this is only used for original inputs.
+ //
+ // FIXME: This is broken for preprocessed .s inputs.
+ if (Input.isFilename() &&
+ strcmp(Input.getFilename(), Input.getBaseInput()) == 0) {
+ if (Args.hasArg(options::OPT_gstabs))
+ CmdArgs.push_back("--gstabs");
+ else if (Args.hasArg(options::OPT_g_Group))
+ CmdArgs.push_back("--gdwarf2");
+ }
+
+ // Derived from asm spec.
+ CmdArgs.push_back("-arch");
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName().c_str()));
+
+ CmdArgs.push_back("-force_cpusubtype_ALL");
+ if ((Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_fapple_kext)) &&
+ !Args.hasArg(options::OPT_dynamic))
+ CmdArgs.push_back("-static");
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
+ options::OPT_Xassembler);
+
+ assert(Output.isFilename() && "Unexpected lipo output.");
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ if (Input.isPipe()) {
+ CmdArgs.push_back("-");
+ } else {
+ assert(Input.isFilename() && "Invalid input.");
+ CmdArgs.push_back(Input.getFilename());
+ }
+
+ // asm_final spec is empty.
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "as").c_str());
+ Dest.addCommand(new Command(Exec, CmdArgs));
+}
+
+/// Helper routine for seeing if we should use dsymutil; this is a
+/// gcc compatible hack, we should remove it and use the input
+/// type information.
+static bool isSourceSuffix(const char *Str) {
+ // match: 'C', 'CPP', 'c', 'cc', 'cp', 'c++', 'cpp', 'cxx', 'm',
+ // 'mm'.
+ switch (strlen(Str)) {
+ default:
+ return false;
+ case 1:
+ return (memcmp(Str, "C", 1) == 0 ||
+ memcmp(Str, "c", 1) == 0 ||
+ memcmp(Str, "m", 1) == 0);
+ case 2:
+ return (memcmp(Str, "cc", 2) == 0 ||
+ memcmp(Str, "cp", 2) == 0 ||
+ memcmp(Str, "mm", 2) == 0);
+ case 3:
+ return (memcmp(Str, "CPP", 3) == 0 ||
+ memcmp(Str, "c++", 3) == 0 ||
+ memcmp(Str, "cpp", 3) == 0 ||
+ memcmp(Str, "cxx", 3) == 0);
+ }
+}
+
+static bool isMacosxVersionLT(unsigned (&A)[3], unsigned (&B)[3]) {
+ for (unsigned i=0; i < 3; ++i) {
+ if (A[i] > B[i]) return false;
+ if (A[i] < B[i]) return true;
+ }
+ return false;
+}
+
+static bool isMacosxVersionLT(unsigned (&A)[3],
+ unsigned V0, unsigned V1=0, unsigned V2=0) {
+ unsigned B[3] = { V0, V1, V2 };
+ return isMacosxVersionLT(A, B);
+}
+
+const toolchains::Darwin_X86 &darwin::Link::getDarwinToolChain() const {
+ return reinterpret_cast<const toolchains::Darwin_X86&>(getToolChain());
+}
+
+void darwin::Link::AddDarwinArch(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Derived from darwin_arch spec.
+ CmdArgs.push_back("-arch");
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName().c_str()));
+}
+
+void darwin::Link::AddDarwinSubArch(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Derived from darwin_subarch spec, not sure what the distinction
+ // exists for but at least for this chain it is the same.
+ AddDarwinArch(Args, CmdArgs);
+}
+
+void darwin::Link::AddLinkArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ const Driver &D = getToolChain().getHost().getDriver();
+
+ // Derived from the "link" spec.
+ Args.AddAllArgs(CmdArgs, options::OPT_static);
+ if (!Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("-dynamic");
+ if (Args.hasArg(options::OPT_fgnu_runtime)) {
+ // FIXME: gcc replaces -lobjc in forward args with -lobjc-gnu
+ // here. How do we wish to handle such things?
+ }
+
+ if (!Args.hasArg(options::OPT_dynamiclib)) {
+ if (Args.hasArg(options::OPT_force__cpusubtype__ALL)) {
+ AddDarwinArch(Args, CmdArgs);
+ CmdArgs.push_back("-force_cpusubtype_ALL");
+ } else
+ AddDarwinSubArch(Args, CmdArgs);
+
+ Args.AddLastArg(CmdArgs, options::OPT_bundle);
+ Args.AddAllArgs(CmdArgs, options::OPT_bundle__loader);
+ Args.AddAllArgs(CmdArgs, options::OPT_client__name);
+
+ Arg *A;
+ 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)
+ << A->getAsString(Args) << "-dynamiclib";
+
+ Args.AddLastArg(CmdArgs, options::OPT_force__flat__namespace);
+ Args.AddLastArg(CmdArgs, options::OPT_keep__private__externs);
+ Args.AddLastArg(CmdArgs, options::OPT_private__bundle);
+ } else {
+ CmdArgs.push_back("-dylib");
+
+ Arg *A;
+ if ((A = Args.getLastArg(options::OPT_bundle)) ||
+ (A = Args.getLastArg(options::OPT_bundle__loader)) ||
+ (A = Args.getLastArg(options::OPT_client__name)) ||
+ (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)
+ << A->getAsString(Args) << "-dynamiclib";
+
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_compatibility__version,
+ "-dylib_compatibility_version");
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_current__version,
+ "-dylib_current_version");
+
+ if (Args.hasArg(options::OPT_force__cpusubtype__ALL)) {
+ AddDarwinArch(Args, CmdArgs);
+ // NOTE: We don't add -force_cpusubtype_ALL on this path. Ok.
+ } else
+ AddDarwinSubArch(Args, CmdArgs);
+
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_install__name,
+ "-dylib_install_name");
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_all__load);
+ Args.AddAllArgs(CmdArgs, options::OPT_allowable__client);
+ Args.AddLastArg(CmdArgs, options::OPT_bind__at__load);
+ Args.AddLastArg(CmdArgs, options::OPT_dead__strip);
+ Args.AddLastArg(CmdArgs, options::OPT_no__dead__strip__inits__and__terms);
+ Args.AddAllArgs(CmdArgs, options::OPT_dylib__file);
+ Args.AddLastArg(CmdArgs, options::OPT_dynamic);
+ Args.AddAllArgs(CmdArgs, options::OPT_exported__symbols__list);
+ Args.AddLastArg(CmdArgs, options::OPT_flat__namespace);
+ Args.AddAllArgs(CmdArgs, options::OPT_headerpad__max__install__names);
+ Args.AddAllArgs(CmdArgs, options::OPT_image__base);
+ Args.AddAllArgs(CmdArgs, options::OPT_init);
+
+ if (!Args.hasArg(options::OPT_mmacosx_version_min_EQ)) {
+ if (!Args.hasArg(options::OPT_miphoneos_version_min_EQ)) {
+ // FIXME: I don't understand what is going on here. This is
+ // supposed to come from darwin_ld_minversion, but gcc doesn't
+ // seem to be following that; it must be getting overridden
+ // somewhere.
+ CmdArgs.push_back("-macosx_version_min");
+ CmdArgs.push_back(getDarwinToolChain().getMacosxVersionStr());
+ }
+ } else {
+ // Adding all arguments doesn't make sense here but this is what
+ // gcc does.
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_mmacosx_version_min_EQ,
+ "-macosx_version_min");
+ }
+
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_miphoneos_version_min_EQ,
+ "-iphoneos_version_min");
+ Args.AddLastArg(CmdArgs, options::OPT_nomultidefs);
+ Args.AddLastArg(CmdArgs, options::OPT_multi__module);
+ Args.AddLastArg(CmdArgs, options::OPT_single__module);
+ Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined);
+ Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined__unused);
+
+ if (Args.hasArg(options::OPT_fpie))
+ CmdArgs.push_back("-pie");
+
+ Args.AddLastArg(CmdArgs, options::OPT_prebind);
+ Args.AddLastArg(CmdArgs, options::OPT_noprebind);
+ Args.AddLastArg(CmdArgs, options::OPT_nofixprebinding);
+ Args.AddLastArg(CmdArgs, options::OPT_prebind__all__twolevel__modules);
+ Args.AddLastArg(CmdArgs, options::OPT_read__only__relocs);
+ Args.AddAllArgs(CmdArgs, options::OPT_sectcreate);
+ Args.AddAllArgs(CmdArgs, options::OPT_sectorder);
+ Args.AddAllArgs(CmdArgs, options::OPT_seg1addr);
+ Args.AddAllArgs(CmdArgs, options::OPT_segprot);
+ Args.AddAllArgs(CmdArgs, options::OPT_segaddr);
+ Args.AddAllArgs(CmdArgs, options::OPT_segs__read__only__addr);
+ Args.AddAllArgs(CmdArgs, options::OPT_segs__read__write__addr);
+ Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table);
+ Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table__filename);
+ Args.AddAllArgs(CmdArgs, options::OPT_sub__library);
+ Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella);
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_isysroot, "-syslibroot");
+ Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace);
+ Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace__hints);
+ Args.AddAllArgs(CmdArgs, options::OPT_umbrella);
+ Args.AddAllArgs(CmdArgs, options::OPT_undefined);
+ Args.AddAllArgs(CmdArgs, options::OPT_unexported__symbols__list);
+ Args.AddAllArgs(CmdArgs, options::OPT_weak__reference__mismatches);
+
+ if (!Args.hasArg(options::OPT_weak__reference__mismatches)) {
+ CmdArgs.push_back("-weak_reference_mismatches");
+ CmdArgs.push_back("non-weak");
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_X_Flag);
+ Args.AddAllArgs(CmdArgs, options::OPT_y);
+ Args.AddLastArg(CmdArgs, options::OPT_w);
+ Args.AddAllArgs(CmdArgs, options::OPT_pagezero__size);
+ Args.AddAllArgs(CmdArgs, options::OPT_segs__read__);
+ Args.AddLastArg(CmdArgs, options::OPT_seglinkedit);
+ Args.AddLastArg(CmdArgs, options::OPT_noseglinkedit);
+ Args.AddAllArgs(CmdArgs, options::OPT_sectalign);
+ Args.AddAllArgs(CmdArgs, options::OPT_sectobjectsymbols);
+ Args.AddAllArgs(CmdArgs, options::OPT_segcreate);
+ Args.AddLastArg(CmdArgs, options::OPT_whyload);
+ Args.AddLastArg(CmdArgs, options::OPT_whatsloaded);
+ Args.AddAllArgs(CmdArgs, options::OPT_dylinker__install__name);
+ Args.AddLastArg(CmdArgs, options::OPT_dylinker);
+ Args.AddLastArg(CmdArgs, options::OPT_Mach);
+}
+
+void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest, const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ assert(Output.getType() == types::TY_Image && "Invalid linker output type.");
+ // The logic here is derived from gcc's behavior; most of which
+ // comes from specs (starting with link_command). Consult gcc for
+ // more information.
+
+ // FIXME: The spec references -fdump= which seems to have
+ // disappeared?
+
+ ArgStringList CmdArgs;
+
+ // I'm not sure why this particular decomposition exists in gcc, but
+ // we follow suite for ease of comparison.
+ AddLinkArgs(Args, CmdArgs);
+
+ // FIXME: gcc has %{x} in here. How could this ever happen? Cruft?
+ Args.AddAllArgs(CmdArgs, options::OPT_d_Flag);
+ Args.AddAllArgs(CmdArgs, options::OPT_s);
+ Args.AddAllArgs(CmdArgs, options::OPT_t);
+ Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
+ Args.AddAllArgs(CmdArgs, options::OPT_u_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_A);
+ Args.AddLastArg(CmdArgs, options::OPT_e);
+ Args.AddAllArgs(CmdArgs, options::OPT_m_Separate);
+ Args.AddAllArgs(CmdArgs, options::OPT_r);
+
+ // FIXME: This is just being pedantically bug compatible, gcc
+ // doesn't *mean* to forward this, it just does (yay for pattern
+ // matching). It doesn't work, of course.
+ Args.AddAllArgs(CmdArgs, options::OPT_object);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ unsigned MacosxVersion[3];
+ if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ)) {
+ bool HadExtra;
+ if (!Driver::GetReleaseVersion(A->getValue(Args), MacosxVersion[0],
+ MacosxVersion[1], MacosxVersion[2],
+ HadExtra) ||
+ HadExtra) {
+ const Driver &D = getToolChain().getHost().getDriver();
+ D.Diag(clang::diag::err_drv_invalid_version_number)
+ << A->getAsString(Args);
+ }
+ } else {
+ getDarwinToolChain().getMacosxVersion(MacosxVersion);
+ }
+
+ if (!Args.hasArg(options::OPT_A) &&
+ !Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nostartfiles)) {
+ // Derived from startfile spec.
+ if (Args.hasArg(options::OPT_dynamiclib)) {
+ // Derived from darwin_dylib1 spec.
+ if (isMacosxVersionLT(MacosxVersion, 10, 5))
+ CmdArgs.push_back("-ldylib1.o");
+ else if (isMacosxVersionLT(MacosxVersion, 10, 6))
+ CmdArgs.push_back("-ldylib1.10.5.o");
+ } else {
+ if (Args.hasArg(options::OPT_bundle)) {
+ if (!Args.hasArg(options::OPT_static)) {
+ // Derived from darwin_bundle1 spec.
+ if (isMacosxVersionLT(MacosxVersion, 10, 6))
+ CmdArgs.push_back("-lbundle1.o");
+ }
+ } else {
+ if (Args.hasArg(options::OPT_pg)) {
+ if (Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_object) ||
+ Args.hasArg(options::OPT_preload)) {
+ CmdArgs.push_back("-lgcrt0.o");
+ } else {
+ CmdArgs.push_back("-lgcrt1.o");
+
+ // darwin_crt2 spec is empty.
+ }
+ } else {
+ if (Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_object) ||
+ Args.hasArg(options::OPT_preload)) {
+ CmdArgs.push_back("-lcrt0.o");
+ } else {
+ // Derived from darwin_crt1 spec.
+ if (isMacosxVersionLT(MacosxVersion, 10, 5))
+ CmdArgs.push_back("-lcrt1.o");
+ else if (isMacosxVersionLT(MacosxVersion, 10, 6))
+ CmdArgs.push_back("-lcrt1.10.5.o");
+ else
+ CmdArgs.push_back("-lcrt1.10.6.o");
+
+ // darwin_crt2 spec is empty.
+ }
+ }
+ }
+ }
+
+ if (Args.hasArg(options::OPT_shared_libgcc) &&
+ !Args.hasArg(options::OPT_miphoneos_version_min_EQ) &&
+ isMacosxVersionLT(MacosxVersion, 10, 5)) {
+ const char *Str = getToolChain().GetFilePath(C, "crt3.o").c_str();
+ CmdArgs.push_back(Args.MakeArgString(Str));
+ }
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+
+ if (Args.hasArg(options::OPT_fopenmp))
+ // This is more complicated in gcc...
+ CmdArgs.push_back("-lgomp");
+
+ // FIXME: Derive these correctly.
+ const char *TCDir = getDarwinToolChain().getToolChainDir().c_str();
+ if (getToolChain().getArchName() == "x86_64") {
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/usr/lib/gcc/%s/x86_64", TCDir)));
+ // Intentionally duplicated for (temporary) gcc bug compatibility.
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/usr/lib/gcc/%s/x86_64", TCDir)));
+ }
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/usr/lib/%s", TCDir)));
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/usr/lib/gcc/%s", TCDir)));
+ // Intentionally duplicated for (temporary) gcc bug compatibility.
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/usr/lib/gcc/%s", TCDir)));
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/usr/lib/gcc/%s/../../../%s", TCDir, TCDir)));
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/usr/lib/gcc/%s/../../..", TCDir)));
+
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+ const InputInfo &II = *it;
+ if (II.isFilename())
+ CmdArgs.push_back(II.getFilename());
+ else
+ II.getInputArg().renderAsInput(Args, CmdArgs);
+ }
+
+ if (LinkingOutput) {
+ CmdArgs.push_back("-arch_multiple");
+ CmdArgs.push_back("-final_output");
+ CmdArgs.push_back(LinkingOutput);
+ }
+
+ if (Args.hasArg(options::OPT_fprofile_arcs) ||
+ Args.hasArg(options::OPT_fprofile_generate) ||
+ Args.hasArg(options::OPT_fcreate_profile) ||
+ Args.hasArg(options::OPT_coverage))
+ CmdArgs.push_back("-lgcov");
+
+ if (Args.hasArg(options::OPT_fnested_functions))
+ CmdArgs.push_back("-allow_stack_execute");
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nodefaultlibs)) {
+ // FIXME: g++ is more complicated here, it tries to put -lstdc++
+ // before -lm, for example.
+ if (getToolChain().getHost().getDriver().CCCIsCXX)
+ CmdArgs.push_back("-lstdc++");
+
+ // link_ssp spec is empty.
+
+ // Derived from libgcc and lib specs but refactored.
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-lgcc_static");
+ } else {
+ if (Args.hasArg(options::OPT_static_libgcc)) {
+ CmdArgs.push_back("-lgcc_eh");
+ } else if (Args.hasArg(options::OPT_miphoneos_version_min_EQ)) {
+ // Derived from darwin_iphoneos_libgcc spec.
+ CmdArgs.push_back("-lgcc_s.10.5");
+ } else if (Args.hasArg(options::OPT_shared_libgcc) ||
+ Args.hasArg(options::OPT_fexceptions) ||
+ Args.hasArg(options::OPT_fgnu_runtime)) {
+ // FIXME: This is probably broken on 10.3?
+ if (isMacosxVersionLT(MacosxVersion, 10, 5))
+ CmdArgs.push_back("-lgcc_s.10.4");
+ else if (isMacosxVersionLT(MacosxVersion, 10, 6))
+ CmdArgs.push_back("-lgcc_s.10.5");
+ } else {
+ if (isMacosxVersionLT(MacosxVersion, 10, 3, 9))
+ ; // Do nothing.
+ else if (isMacosxVersionLT(MacosxVersion, 10, 5))
+ CmdArgs.push_back("-lgcc_s.10.4");
+ else if (isMacosxVersionLT(MacosxVersion, 10, 6))
+ CmdArgs.push_back("-lgcc_s.10.5");
+ }
+
+ if (isMacosxVersionLT(MacosxVersion, 10, 6)) {
+ CmdArgs.push_back("-lgcc");
+ CmdArgs.push_back("-lSystem");
+ } else {
+ CmdArgs.push_back("-lSystem");
+ CmdArgs.push_back("-lgcc");
+ }
+ }
+ }
+
+ if (!Args.hasArg(options::OPT_A) &&
+ !Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nostartfiles)) {
+ // endfile_spec is empty.
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_F);
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "ld").c_str());
+ Dest.addCommand(new Command(Exec, CmdArgs));
+
+ // Find the first non-empty base input (we want to ignore linker
+ // inputs).
+ const char *BaseInput = "";
+ for (unsigned i = 0, e = Inputs.size(); i != e; ++i) {
+ if (Inputs[i].getBaseInput()[0] != '\0') {
+ BaseInput = Inputs[i].getBaseInput();
+ break;
+ }
+ }
+
+ // Run dsymutil if we are making an executable in a single step.
+ //
+ // FIXME: Currently we don't want to do this when we are part of a
+ // universal build step, as this would end up creating stray temp
+ // files.
+ if (!LinkingOutput &&
+ Args.getLastArg(options::OPT_g_Group) &&
+ !Args.getLastArg(options::OPT_gstabs) &&
+ !Args.getLastArg(options::OPT_g0)) {
+ // FIXME: This is gross, but matches gcc. The test only considers
+ // the suffix (not the -x type), and then only of the first
+ // source input. Awesome.
+ const char *Suffix = strrchr(BaseInput, '.');
+ if (Suffix && isSourceSuffix(Suffix + 1)) {
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "dsymutil").c_str());
+ ArgStringList CmdArgs;
+ CmdArgs.push_back(Output.getFilename());
+ C.getJobs().addCommand(new Command(Exec, CmdArgs));
+ }
+ }
+}
+
+void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest, const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ CmdArgs.push_back("-create");
+ assert(Output.isFilename() && "Unexpected lipo output.");
+
+ CmdArgs.push_back("-output");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+ const InputInfo &II = *it;
+ assert(II.isFilename() && "Unexpected lipo input.");
+ CmdArgs.push_back(II.getFilename());
+ }
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "lipo").c_str());
+ Dest.addCommand(new Command(Exec, CmdArgs));
+}
+
+
+void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest, const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const
+{
+ ArgStringList CmdArgs;
+
+ // When building 32-bit code on FreeBSD/amd64, we have to explicitly
+ // instruct as in the base system to assemble 32-bit code.
+ if (getToolChain().getArchName() == "i386")
+ CmdArgs.push_back("--32");
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
+ options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ if (Output.isPipe())
+ CmdArgs.push_back("-");
+ else
+ CmdArgs.push_back(Output.getFilename());
+
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+ const InputInfo &II = *it;
+ if (II.isPipe())
+ CmdArgs.push_back("-");
+ else
+ CmdArgs.push_back(II.getFilename());
+ }
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "as").c_str());
+ Dest.addCommand(new Command(Exec, CmdArgs));
+}
+
+void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest, const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getHost().getDriver();
+ ArgStringList CmdArgs;
+
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-Bstatic");
+ } else {
+ CmdArgs.push_back("--eh-frame-hdr");
+ if (Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-Bshareable");
+ } else {
+ CmdArgs.push_back("-dynamic-linker");
+ CmdArgs.push_back("/libexec/ld-elf.so.1");
+ }
+ }
+
+ // When building 32-bit code on FreeBSD/amd64, we have to explicitly
+ // instruct ld in the base system to link 32-bit code.
+ if (getToolChain().getArchName() == "i386") {
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf_i386_fbsd");
+ }
+
+ if (Output.isPipe()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back("-");
+ } else if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt1.o").c_str()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o").c_str()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o").c_str()));
+ } else {
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o").c_str()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o").c_str()));
+ }
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_e);
+
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+ const InputInfo &II = *it;
+
+ // Don't try to pass LLVM inputs to a generic gcc.
+ if (II.getType() == types::TY_LLVMBC)
+ D.Diag(clang::diag::err_drv_no_linker_llvm_support)
+ << getToolChain().getTripleString().c_str();
+
+ if (II.isPipe())
+ CmdArgs.push_back("-");
+ else if (II.isFilename())
+ CmdArgs.push_back(II.getFilename());
+ else
+ II.getInputArg().renderAsInput(Args, CmdArgs);
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nodefaultlibs)) {
+ // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding
+ // the default system libraries. Just mimic this for now.
+ CmdArgs.push_back("-lgcc");
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-lgcc_eh");
+ } else {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lgcc_s");
+ CmdArgs.push_back("--no-as-needed");
+ }
+
+ if (Args.hasArg(options::OPT_pthread))
+ CmdArgs.push_back("-lpthread");
+ CmdArgs.push_back("-lc");
+
+ CmdArgs.push_back("-lgcc");
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-lgcc_eh");
+ } else {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lgcc_s");
+ CmdArgs.push_back("--no-as-needed");
+ }
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o").c_str()));
+ else
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o").c_str()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o").c_str()));
+ }
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "ld").c_str());
+ Dest.addCommand(new Command(Exec, CmdArgs));
+}
+
+/// DragonFly Tools
+
+// For now, DragonFly Assemble does just about the same as for
+// FreeBSD, but this may change soon.
+void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest, const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ // When building 32-bit code on DragonFly/pc64, we have to explicitly
+ // instruct as in the base system to assemble 32-bit code.
+ if (getToolChain().getArchName() == "i386")
+ CmdArgs.push_back("--32");
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
+ options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ if (Output.isPipe())
+ CmdArgs.push_back("-");
+ else
+ CmdArgs.push_back(Output.getFilename());
+
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+ const InputInfo &II = *it;
+ if (II.isPipe())
+ CmdArgs.push_back("-");
+ else
+ CmdArgs.push_back(II.getFilename());
+ }
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "as").c_str());
+ Dest.addCommand(new Command(Exec, CmdArgs));
+}
+
+void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest, const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getHost().getDriver();
+ ArgStringList CmdArgs;
+
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-Bstatic");
+ } else {
+ if (Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("-Bshareable");
+ else {
+ CmdArgs.push_back("-dynamic-linker");
+ CmdArgs.push_back("/usr/libexec/ld-elf.so.2");
+ }
+ }
+
+ // When building 32-bit code on DragonFly/pc64, we have to explicitly
+ // instruct ld in the base system to link 32-bit code.
+ if (getToolChain().getArchName() == "i386") {
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf_i386");
+ }
+
+ if (Output.isPipe()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back("-");
+ } else if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt1.o").c_str()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o").c_str()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o").c_str()));
+ } else {
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o").c_str()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o").c_str()));
+ }
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_e);
+
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+ const InputInfo &II = *it;
+
+ // Don't try to pass LLVM inputs to a generic gcc.
+ if (II.getType() == types::TY_LLVMBC)
+ D.Diag(clang::diag::err_drv_no_linker_llvm_support)
+ << getToolChain().getTripleString().c_str();
+
+ if (II.isPipe())
+ CmdArgs.push_back("-");
+ else if (II.isFilename())
+ CmdArgs.push_back(II.getFilename());
+ else
+ II.getInputArg().renderAsInput(Args, CmdArgs);
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nodefaultlibs)) {
+ // FIXME: GCC passes on -lgcc, -lgcc_pic and a whole lot of
+ // rpaths
+ CmdArgs.push_back("-L/usr/lib/gcc41");
+
+ if (!Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-rpath");
+ CmdArgs.push_back("/usr/lib/gcc41");
+
+ CmdArgs.push_back("-rpath-link");
+ CmdArgs.push_back("/usr/lib/gcc41");
+
+ CmdArgs.push_back("-rpath");
+ CmdArgs.push_back("/usr/lib");
+
+ CmdArgs.push_back("-rpath-link");
+ CmdArgs.push_back("/usr/lib");
+ }
+
+ if (Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-lgcc_pic");
+ } else {
+ CmdArgs.push_back("-lgcc");
+ }
+
+
+ if (Args.hasArg(options::OPT_pthread))
+ CmdArgs.push_back("-lthread_xu");
+
+ if (!Args.hasArg(options::OPT_nolibc)) {
+ CmdArgs.push_back("-lc");
+ }
+
+ if (Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-lgcc_pic");
+ } else {
+ CmdArgs.push_back("-lgcc");
+ }
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o").c_str()));
+ else
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o").c_str()));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o").c_str()));
+ }
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "ld").c_str());
+ Dest.addCommand(new Command(Exec, CmdArgs));
+}
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
new file mode 100644
index 000000000000..db108db2b4d7
--- /dev/null
+++ b/lib/Driver/Tools.h
@@ -0,0 +1,316 @@
+//===--- Tools.h - Tool Implementations -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_LIB_DRIVER_TOOLS_H_
+#define CLANG_LIB_DRIVER_TOOLS_H_
+
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/Types.h"
+#include "clang/Driver/Util.h"
+
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace driver {
+ class Driver;
+
+namespace toolchains {
+ class Darwin_X86;
+}
+
+namespace tools {
+
+ class VISIBILITY_HIDDEN Clang : public Tool {
+ void AddPreprocessingOptions(const Driver &D,
+ const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs) const;
+
+ public:
+ Clang(const ToolChain &TC) : Tool("clang", TC) {}
+
+ virtual bool acceptsPipedInput() const { return true; }
+ virtual bool canPipeOutput() const { return true; }
+ virtual bool hasIntegratedCPP() const { return true; }
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+
+ /// gcc - Generic GCC tool implementations.
+namespace gcc {
+ class VISIBILITY_HIDDEN Common : public Tool {
+ public:
+ Common(const char *Name, const ToolChain &TC) : Tool(Name, TC) {}
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+
+ /// RenderExtraToolArgs - Render any arguments necessary to force
+ /// the particular tool mode.
+ virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const = 0;
+ };
+
+
+ class VISIBILITY_HIDDEN Preprocess : public Common {
+ public:
+ Preprocess(const ToolChain &TC) : Common("gcc::Preprocess", TC) {}
+
+ virtual bool acceptsPipedInput() const { return true; }
+ virtual bool canPipeOutput() const { return true; }
+ virtual bool hasIntegratedCPP() const { return false; }
+
+ virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const;
+ };
+
+ class VISIBILITY_HIDDEN Precompile : public Common {
+ public:
+ Precompile(const ToolChain &TC) : Common("gcc::Precompile", TC) {}
+
+ virtual bool acceptsPipedInput() const { return true; }
+ virtual bool canPipeOutput() const { return false; }
+ virtual bool hasIntegratedCPP() const { return true; }
+
+ virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const;
+ };
+
+ class VISIBILITY_HIDDEN Compile : public Common {
+ public:
+ Compile(const ToolChain &TC) : Common("gcc::Compile", TC) {}
+
+ virtual bool acceptsPipedInput() const { return true; }
+ virtual bool canPipeOutput() const { return true; }
+ virtual bool hasIntegratedCPP() const { return true; }
+
+ virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const;
+ };
+
+ class VISIBILITY_HIDDEN Assemble : public Common {
+ public:
+ Assemble(const ToolChain &TC) : Common("gcc::Assemble", TC) {}
+
+ virtual bool acceptsPipedInput() const { return true; }
+ virtual bool canPipeOutput() const { return false; }
+ virtual bool hasIntegratedCPP() const { return false; }
+
+ virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const;
+ };
+
+ class VISIBILITY_HIDDEN Link : public Common {
+ public:
+ Link(const ToolChain &TC) : Common("gcc::Link", TC) {}
+
+ virtual bool acceptsPipedInput() const { return false; }
+ virtual bool canPipeOutput() const { return false; }
+ virtual bool hasIntegratedCPP() const { return false; }
+
+ virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const;
+ };
+} // end namespace gcc
+
+namespace darwin {
+ class VISIBILITY_HIDDEN CC1 : public Tool {
+ public:
+ static const char *getBaseInputName(const ArgList &Args,
+ const InputInfoList &Input);
+ static const char *getBaseInputStem(const ArgList &Args,
+ const InputInfoList &Input);
+ static const char *getDependencyFileName(const ArgList &Args,
+ const InputInfoList &Inputs);
+
+ protected:
+ const char *getCC1Name(types::ID Type) const;
+
+ void AddCC1Args(const ArgList &Args, ArgStringList &CmdArgs) const;
+ void AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
+ const InputInfoList &Inputs,
+ const ArgStringList &OutputArgs) const;
+ void AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
+ const InputInfoList &Inputs,
+ const ArgStringList &OutputArgs) const;
+ void AddCPPUniqueOptionsArgs(const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const InputInfoList &Inputs) const;
+ void AddCPPArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
+
+ public:
+ CC1(const char *Name, const ToolChain &TC) : Tool(Name, TC) {}
+
+ virtual bool acceptsPipedInput() const { return true; }
+ virtual bool canPipeOutput() const { return true; }
+ virtual bool hasIntegratedCPP() const { return true; }
+ };
+
+ class VISIBILITY_HIDDEN Preprocess : public CC1 {
+ public:
+ Preprocess(const ToolChain &TC) : CC1("darwin::Preprocess", TC) {}
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+
+ class VISIBILITY_HIDDEN Compile : public CC1 {
+ public:
+ Compile(const ToolChain &TC) : CC1("darwin::Compile", TC) {}
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+
+ class VISIBILITY_HIDDEN Assemble : public Tool {
+ public:
+ Assemble(const ToolChain &TC) : Tool("darwin::Assemble", TC) {}
+
+ virtual bool acceptsPipedInput() const { return true; }
+ virtual bool canPipeOutput() const { return false; }
+ virtual bool hasIntegratedCPP() const { return false; }
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+
+ class VISIBILITY_HIDDEN Link : public Tool {
+ void AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const;
+ void AddDarwinSubArch(const ArgList &Args, ArgStringList &CmdArgs) const;
+ void AddLinkArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
+
+ /// The default macosx-version-min.
+ const char *MacosxVersionMin;
+
+ const toolchains::Darwin_X86 &getDarwinToolChain() const;
+
+ public:
+ Link(const ToolChain &TC,
+ const char *_MacosxVersionMin)
+ : Tool("darwin::Link", TC), MacosxVersionMin(_MacosxVersionMin) {
+ }
+
+ virtual bool acceptsPipedInput() const { return false; }
+ virtual bool canPipeOutput() const { return false; }
+ virtual bool hasIntegratedCPP() const { return false; }
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+
+ class VISIBILITY_HIDDEN Lipo : public Tool {
+ public:
+ Lipo(const ToolChain &TC) : Tool("darwin::Lipo", TC) {}
+
+ virtual bool acceptsPipedInput() const { return false; }
+ virtual bool canPipeOutput() const { return false; }
+ virtual bool hasIntegratedCPP() const { return false; }
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+}
+
+ /// freebsd -- Directly call GNU Binutils assembler and linker
+namespace freebsd {
+ class VISIBILITY_HIDDEN Assemble : public Tool {
+ public:
+ Assemble(const ToolChain &TC) : Tool("freebsd::Assemble", TC) {}
+
+ virtual bool acceptsPipedInput() const { return true; }
+ virtual bool canPipeOutput() const { return true; }
+ virtual bool hasIntegratedCPP() const { return false; }
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+ class VISIBILITY_HIDDEN Link : public Tool {
+ public:
+ Link(const ToolChain &TC) : Tool("freebsd::Link", TC) {}
+
+ virtual bool acceptsPipedInput() const { return true; }
+ virtual bool canPipeOutput() const { return true; }
+ virtual bool hasIntegratedCPP() const { return false; }
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+}
+
+ /// dragonfly -- Directly call GNU Binutils assembler and linker
+namespace dragonfly {
+ class VISIBILITY_HIDDEN Assemble : public Tool {
+ public:
+ Assemble(const ToolChain &TC) : Tool("dragonfly::Assemble", TC) {}
+
+ virtual bool acceptsPipedInput() const { return true; }
+ virtual bool canPipeOutput() const { return true; }
+ virtual bool hasIntegratedCPP() const { return false; }
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+ class VISIBILITY_HIDDEN Link : public Tool {
+ public:
+ Link(const ToolChain &TC) : Tool("dragonfly::Link", TC) {}
+
+ virtual bool acceptsPipedInput() const { return true; }
+ virtual bool canPipeOutput() const { return true; }
+ virtual bool hasIntegratedCPP() const { return false; }
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+}
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
new file mode 100644
index 000000000000..e89e973f3f53
--- /dev/null
+++ b/lib/Driver/Types.cpp
@@ -0,0 +1,205 @@
+//===--- Types.cpp - Driver input & temporary type information ----------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Types.h"
+
+#include <string.h>
+#include <cassert>
+
+using namespace clang::driver;
+using namespace clang::driver::types;
+
+struct Info {
+ const char *Name;
+ const char *Flags;
+ const char *TempSuffix;
+ ID PreprocessedType;
+};
+
+static Info TypeInfos[] = {
+#define TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, FLAGS) \
+ { NAME, FLAGS, TEMP_SUFFIX, TY_##PP_TYPE, },
+#include "clang/Driver/Types.def"
+#undef TYPE
+};
+static const unsigned numTypes = sizeof(TypeInfos) / sizeof(TypeInfos[0]);
+
+static Info &getInfo(unsigned id) {
+ assert(id > 0 && id - 1 < numTypes && "Invalid Type ID.");
+ return TypeInfos[id - 1];
+}
+
+const char *types::getTypeName(ID Id) {
+ return getInfo(Id).Name;
+}
+
+types::ID types::getPreprocessedType(ID Id) {
+ return getInfo(Id).PreprocessedType;
+}
+
+const char *types::getTypeTempSuffix(ID Id) {
+ return getInfo(Id).TempSuffix;
+}
+
+bool types::onlyAssembleType(ID Id) {
+ return strchr(getInfo(Id).Flags, 'a');
+}
+
+bool types::onlyPrecompileType(ID Id) {
+ return strchr(getInfo(Id).Flags, 'p');
+}
+
+bool types::canTypeBeUserSpecified(ID Id) {
+ return strchr(getInfo(Id).Flags, 'u');
+}
+
+bool types::appendSuffixForType(ID Id) {
+ return strchr(getInfo(Id).Flags, 'A');
+}
+
+bool types::canLipoType(ID Id) {
+ return (Id == TY_Nothing ||
+ Id == TY_Image ||
+ Id == TY_Object);
+}
+
+bool types::isAcceptedByClang(ID Id) {
+ switch (Id) {
+ default:
+ return false;
+
+ case TY_Asm:
+ case TY_C: case TY_PP_C:
+ case TY_ObjC: case TY_PP_ObjC:
+ case TY_CXX: case TY_PP_CXX:
+ case TY_ObjCXX: case TY_PP_ObjCXX:
+ case TY_CHeader: case TY_PP_CHeader:
+ case TY_ObjCHeader: case TY_PP_ObjCHeader:
+ case TY_CXXHeader: case TY_PP_CXXHeader:
+ case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
+ return true;
+ }
+}
+
+bool types::isCXX(ID Id) {
+ switch (Id) {
+ default:
+ return false;
+
+ case TY_CXX: case TY_PP_CXX:
+ case TY_ObjCXX: case TY_PP_ObjCXX:
+ case TY_CXXHeader: case TY_PP_CXXHeader:
+ case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
+ return true;
+ }
+}
+
+types::ID types::lookupTypeForExtension(const char *Ext) {
+ unsigned N = strlen(Ext);
+
+ switch (N) {
+ case 1:
+ if (memcmp(Ext, "c", 1) == 0) return TY_C;
+ if (memcmp(Ext, "i", 1) == 0) return TY_PP_C;
+ if (memcmp(Ext, "m", 1) == 0) return TY_ObjC;
+ if (memcmp(Ext, "M", 1) == 0) return TY_ObjCXX;
+ if (memcmp(Ext, "h", 1) == 0) return TY_CHeader;
+ if (memcmp(Ext, "C", 1) == 0) return TY_CXX;
+ if (memcmp(Ext, "H", 1) == 0) return TY_CXXHeader;
+ if (memcmp(Ext, "f", 1) == 0) return TY_PP_Fortran;
+ if (memcmp(Ext, "F", 1) == 0) return TY_Fortran;
+ if (memcmp(Ext, "s", 1) == 0) return TY_PP_Asm;
+ if (memcmp(Ext, "S", 1) == 0) return TY_Asm;
+ case 2:
+ if (memcmp(Ext, "ii", 2) == 0) return TY_PP_CXX;
+ if (memcmp(Ext, "mi", 2) == 0) return TY_PP_ObjC;
+ if (memcmp(Ext, "mm", 2) == 0) return TY_ObjCXX;
+ if (memcmp(Ext, "cc", 2) == 0) return TY_CXX;
+ if (memcmp(Ext, "cc", 2) == 0) return TY_CXX;
+ if (memcmp(Ext, "cp", 2) == 0) return TY_CXX;
+ if (memcmp(Ext, "hh", 2) == 0) return TY_CXXHeader;
+ break;
+ case 3:
+ if (memcmp(Ext, "ads", 3) == 0) return TY_Ada;
+ if (memcmp(Ext, "adb", 3) == 0) return TY_Ada;
+ if (memcmp(Ext, "cxx", 3) == 0) return TY_CXX;
+ if (memcmp(Ext, "cpp", 3) == 0) return TY_CXX;
+ if (memcmp(Ext, "CPP", 3) == 0) return TY_CXX;
+ if (memcmp(Ext, "cXX", 3) == 0) return TY_CXX;
+ if (memcmp(Ext, "for", 3) == 0) return TY_PP_Fortran;
+ if (memcmp(Ext, "FOR", 3) == 0) return TY_PP_Fortran;
+ if (memcmp(Ext, "fpp", 3) == 0) return TY_Fortran;
+ if (memcmp(Ext, "FPP", 3) == 0) return TY_Fortran;
+ if (memcmp(Ext, "f90", 3) == 0) return TY_PP_Fortran;
+ if (memcmp(Ext, "f95", 3) == 0) return TY_PP_Fortran;
+ if (memcmp(Ext, "F90", 3) == 0) return TY_Fortran;
+ if (memcmp(Ext, "F95", 3) == 0) return TY_Fortran;
+ if (memcmp(Ext, "mii", 3) == 0) return TY_PP_ObjCXX;
+ break;
+ }
+
+ return TY_INVALID;
+}
+
+types::ID types::lookupTypeForTypeSpecifier(const char *Name) {
+ unsigned N = strlen(Name);
+
+ for (unsigned i=0; i<numTypes; ++i) {
+ types::ID Id = (types::ID) (i + 1);
+ if (canTypeBeUserSpecified(Id) &&
+ memcmp(Name, getInfo(Id).Name, N + 1) == 0)
+ return Id;
+ }
+
+ return TY_INVALID;
+}
+
+// FIXME: Why don't we just put this list in the defs file, eh.
+
+unsigned types::getNumCompilationPhases(ID Id) {
+ if (Id == TY_Object)
+ return 1;
+
+ unsigned N = 0;
+ if (getPreprocessedType(Id) != TY_INVALID)
+ N += 1;
+
+ if (onlyAssembleType(Id))
+ return N + 2; // assemble, link
+ if (onlyPrecompileType(Id))
+ return N + 1; // precompile
+
+ return N + 3; // compile, assemble, link
+}
+
+phases::ID types::getCompilationPhase(ID Id, unsigned N) {
+ assert(N < getNumCompilationPhases(Id) && "Invalid index.");
+
+ if (Id == TY_Object)
+ return phases::Link;
+
+ if (getPreprocessedType(Id) != TY_INVALID) {
+ if (N == 0)
+ return phases::Preprocess;
+ --N;
+ }
+
+ if (onlyAssembleType(Id))
+ return N == 0 ? phases::Assemble : phases::Link;
+
+ if (onlyPrecompileType(Id))
+ return phases::Precompile;
+
+ if (N == 0)
+ return phases::Compile;
+ if (N == 1)
+ return phases::Assemble;
+
+ return phases::Link;
+}
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
new file mode 100644
index 000000000000..11c9251ae987
--- /dev/null
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -0,0 +1,451 @@
+//===--- ASTConsumers.cpp - ASTConsumer implementations -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// AST Consumer Implementations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/DocumentXML.h"
+#include "clang/Frontend/PathDiagnosticClients.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "llvm/Module.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+/// ASTPrinter - Pretty-printer and dumper of ASTs
+
+namespace {
+ class ASTPrinter : public ASTConsumer {
+ llvm::raw_ostream &Out;
+ bool Dump;
+
+ public:
+ ASTPrinter(llvm::raw_ostream* o = NULL, bool Dump = false)
+ : Out(o? *o : llvm::errs()), Dump(Dump) { }
+
+ virtual void HandleTranslationUnit(ASTContext &Context) {
+ PrintingPolicy Policy = Context.PrintingPolicy;
+ Policy.Dump = Dump;
+ Context.getTranslationUnitDecl()->print(Out, Context, Policy);
+ }
+ };
+} // end anonymous namespace
+
+ASTConsumer *clang::CreateASTPrinter(llvm::raw_ostream* out) {
+ return new ASTPrinter(out);
+}
+
+//===----------------------------------------------------------------------===//
+/// ASTPrinterXML - XML-printer of ASTs
+
+namespace {
+ class ASTPrinterXML : public ASTConsumer {
+ DocumentXML Doc;
+
+ public:
+ ASTPrinterXML(llvm::raw_ostream& o) : Doc("CLANG_XML", o) {}
+
+ void Initialize(ASTContext &Context) {
+ Doc.initialize(Context);
+ }
+
+ virtual void HandleTranslationUnit(ASTContext &Ctx) {
+ Doc.addSubNode("TranslationUnit");
+ for (DeclContext::decl_iterator
+ D = Ctx.getTranslationUnitDecl()->decls_begin(Ctx),
+ DEnd = Ctx.getTranslationUnitDecl()->decls_end(Ctx);
+ D != DEnd;
+ ++D)
+ {
+ Doc.PrintDecl(*D);
+ }
+ Doc.toParent();
+ Doc.finalize();
+ }
+ };
+} // end anonymous namespace
+
+
+ASTConsumer *clang::CreateASTPrinterXML(llvm::raw_ostream* out) {
+ return new ASTPrinterXML(out ? *out : llvm::outs());
+}
+
+ASTConsumer *clang::CreateASTDumper() {
+ return new ASTPrinter(0, true);
+}
+
+//===----------------------------------------------------------------------===//
+/// ASTViewer - AST Visualization
+
+namespace {
+ class ASTViewer : public ASTConsumer {
+ ASTContext *Context;
+ public:
+ void Initialize(ASTContext &Context) {
+ this->Context = &Context;
+ }
+
+ virtual void HandleTopLevelDecl(DeclGroupRef D) {
+ for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
+ HandleTopLevelSingleDecl(*I);
+ }
+
+ void HandleTopLevelSingleDecl(Decl *D);
+ };
+}
+
+void ASTViewer::HandleTopLevelSingleDecl(Decl *D) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ FD->print(llvm::errs(), *Context);
+
+ if (FD->getBodyIfAvailable()) {
+ llvm::cerr << '\n';
+ FD->getBodyIfAvailable()->viewAST();
+ llvm::cerr << '\n';
+ }
+ return;
+ }
+
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ MD->print(llvm::errs(), *Context);
+
+ if (MD->getBody()) {
+ llvm::cerr << '\n';
+ MD->getBody()->viewAST();
+ llvm::cerr << '\n';
+ }
+ }
+}
+
+
+ASTConsumer *clang::CreateASTViewer() { return new ASTViewer(); }
+
+//===----------------------------------------------------------------------===//
+/// DeclContextPrinter - Decl and DeclContext Visualization
+
+namespace {
+
+class DeclContextPrinter : public ASTConsumer {
+ llvm::raw_ostream& Out;
+public:
+ DeclContextPrinter() : Out(llvm::errs()) {}
+
+ void HandleTranslationUnit(ASTContext &C) {
+ PrintDeclContext(C.getTranslationUnitDecl(), 4);
+ }
+
+ void PrintDeclContext(const DeclContext* DC, unsigned Indentation);
+};
+} // end anonymous namespace
+
+void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
+ unsigned Indentation) {
+ // Print DeclContext name.
+ switch (DC->getDeclKind()) {
+ case Decl::TranslationUnit:
+ Out << "[translation unit] " << DC;
+ break;
+ case Decl::Namespace: {
+ Out << "[namespace] ";
+ const NamespaceDecl* ND = cast<NamespaceDecl>(DC);
+ Out << ND->getNameAsString();
+ break;
+ }
+ case Decl::Enum: {
+ const EnumDecl* ED = cast<EnumDecl>(DC);
+ if (ED->isDefinition())
+ Out << "[enum] ";
+ else
+ Out << "<enum> ";
+ Out << ED->getNameAsString();
+ break;
+ }
+ case Decl::Record: {
+ const RecordDecl* RD = cast<RecordDecl>(DC);
+ if (RD->isDefinition())
+ Out << "[struct] ";
+ else
+ Out << "<struct> ";
+ Out << RD->getNameAsString();
+ break;
+ }
+ case Decl::CXXRecord: {
+ const CXXRecordDecl* RD = cast<CXXRecordDecl>(DC);
+ if (RD->isDefinition())
+ Out << "[class] ";
+ else
+ Out << "<class> ";
+ Out << RD->getNameAsString() << " " << DC;
+ break;
+ }
+ case Decl::ObjCMethod:
+ Out << "[objc method]";
+ break;
+ case Decl::ObjCInterface:
+ Out << "[objc interface]";
+ break;
+ case Decl::ObjCCategory:
+ Out << "[objc category]";
+ break;
+ case Decl::ObjCProtocol:
+ Out << "[objc protocol]";
+ break;
+ case Decl::ObjCImplementation:
+ Out << "[objc implementation]";
+ break;
+ case Decl::ObjCCategoryImpl:
+ Out << "[objc categoryimpl]";
+ break;
+ case Decl::LinkageSpec:
+ Out << "[linkage spec]";
+ break;
+ case Decl::Block:
+ Out << "[block]";
+ break;
+ case Decl::Function: {
+ const FunctionDecl* FD = cast<FunctionDecl>(DC);
+ if (FD->isThisDeclarationADefinition())
+ Out << "[function] ";
+ else
+ Out << "<function> ";
+ Out << FD->getNameAsString();
+ // Print the parameters.
+ Out << "(";
+ bool PrintComma = false;
+ for (FunctionDecl::param_const_iterator I = FD->param_begin(),
+ E = FD->param_end(); I != E; ++I) {
+ if (PrintComma)
+ Out << ", ";
+ else
+ PrintComma = true;
+ Out << (*I)->getNameAsString();
+ }
+ Out << ")";
+ break;
+ }
+ case Decl::CXXMethod: {
+ const CXXMethodDecl* D = cast<CXXMethodDecl>(DC);
+ if (D->isOutOfLineDefinition())
+ Out << "[c++ method] ";
+ else if (D->isImplicit())
+ Out << "(c++ method) ";
+ else
+ Out << "<c++ method> ";
+ Out << D->getNameAsString();
+ // Print the parameters.
+ Out << "(";
+ bool PrintComma = false;
+ for (FunctionDecl::param_const_iterator I = D->param_begin(),
+ E = D->param_end(); I != E; ++I) {
+ if (PrintComma)
+ Out << ", ";
+ else
+ PrintComma = true;
+ Out << (*I)->getNameAsString();
+ }
+ Out << ")";
+
+ // Check the semantic DeclContext.
+ const DeclContext* SemaDC = D->getDeclContext();
+ const DeclContext* LexicalDC = D->getLexicalDeclContext();
+ if (SemaDC != LexicalDC)
+ Out << " [[" << SemaDC << "]]";
+
+ break;
+ }
+ case Decl::CXXConstructor: {
+ const CXXConstructorDecl* D = cast<CXXConstructorDecl>(DC);
+ if (D->isOutOfLineDefinition())
+ Out << "[c++ ctor] ";
+ else if (D->isImplicit())
+ Out << "(c++ ctor) ";
+ else
+ Out << "<c++ ctor> ";
+ Out << D->getNameAsString();
+ // Print the parameters.
+ Out << "(";
+ bool PrintComma = false;
+ for (FunctionDecl::param_const_iterator I = D->param_begin(),
+ E = D->param_end(); I != E; ++I) {
+ if (PrintComma)
+ Out << ", ";
+ else
+ PrintComma = true;
+ Out << (*I)->getNameAsString();
+ }
+ Out << ")";
+
+ // Check the semantic DC.
+ const DeclContext* SemaDC = D->getDeclContext();
+ const DeclContext* LexicalDC = D->getLexicalDeclContext();
+ if (SemaDC != LexicalDC)
+ Out << " [[" << SemaDC << "]]";
+ break;
+ }
+ case Decl::CXXDestructor: {
+ const CXXDestructorDecl* D = cast<CXXDestructorDecl>(DC);
+ if (D->isOutOfLineDefinition())
+ Out << "[c++ dtor] ";
+ else if (D->isImplicit())
+ Out << "(c++ dtor) ";
+ else
+ Out << "<c++ dtor> ";
+ Out << D->getNameAsString();
+ // Check the semantic DC.
+ const DeclContext* SemaDC = D->getDeclContext();
+ const DeclContext* LexicalDC = D->getLexicalDeclContext();
+ if (SemaDC != LexicalDC)
+ Out << " [[" << SemaDC << "]]";
+ break;
+ }
+ case Decl::CXXConversion: {
+ const CXXConversionDecl* D = cast<CXXConversionDecl>(DC);
+ if (D->isOutOfLineDefinition())
+ Out << "[c++ conversion] ";
+ else if (D->isImplicit())
+ Out << "(c++ conversion) ";
+ else
+ Out << "<c++ conversion> ";
+ Out << D->getNameAsString();
+ // Check the semantic DC.
+ const DeclContext* SemaDC = D->getDeclContext();
+ const DeclContext* LexicalDC = D->getLexicalDeclContext();
+ if (SemaDC != LexicalDC)
+ Out << " [[" << SemaDC << "]]";
+ break;
+ }
+
+ default:
+ assert(0 && "a decl that inherits DeclContext isn't handled");
+ }
+
+ Out << "\n";
+
+ // Print decls in the DeclContext.
+ // FIXME: Should not use a NULL DeclContext!
+ ASTContext *Context = 0;
+ for (DeclContext::decl_iterator I = DC->decls_begin(*Context),
+ E = DC->decls_end(*Context);
+ I != E; ++I) {
+ for (unsigned i = 0; i < Indentation; ++i)
+ Out << " ";
+
+ Decl::Kind DK = I->getKind();
+ switch (DK) {
+ case Decl::Namespace:
+ case Decl::Enum:
+ case Decl::Record:
+ case Decl::CXXRecord:
+ case Decl::ObjCMethod:
+ case Decl::ObjCInterface:
+ case Decl::ObjCCategory:
+ case Decl::ObjCProtocol:
+ case Decl::ObjCImplementation:
+ case Decl::ObjCCategoryImpl:
+ case Decl::LinkageSpec:
+ case Decl::Block:
+ case Decl::Function:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ {
+ DeclContext* DC = cast<DeclContext>(*I);
+ PrintDeclContext(DC, Indentation+2);
+ break;
+ }
+ case Decl::Field: {
+ FieldDecl* FD = cast<FieldDecl>(*I);
+ Out << "<field> " << FD->getNameAsString() << "\n";
+ break;
+ }
+ case Decl::Typedef: {
+ TypedefDecl* TD = cast<TypedefDecl>(*I);
+ Out << "<typedef> " << TD->getNameAsString() << "\n";
+ break;
+ }
+ case Decl::EnumConstant: {
+ EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I);
+ Out << "<enum constant> " << ECD->getNameAsString() << "\n";
+ break;
+ }
+ case Decl::Var: {
+ VarDecl* VD = cast<VarDecl>(*I);
+ Out << "<var> " << VD->getNameAsString() << "\n";
+ break;
+ }
+ case Decl::ImplicitParam: {
+ ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I);
+ Out << "<implicit parameter> " << IPD->getNameAsString() << "\n";
+ break;
+ }
+ case Decl::ParmVar: {
+ ParmVarDecl* PVD = cast<ParmVarDecl>(*I);
+ Out << "<parameter> " << PVD->getNameAsString() << "\n";
+ break;
+ }
+ case Decl::OriginalParmVar: {
+ OriginalParmVarDecl* OPVD = cast<OriginalParmVarDecl>(*I);
+ Out << "<original parameter> " << OPVD->getNameAsString() << "\n";
+ break;
+ }
+ case Decl::ObjCProperty: {
+ ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I);
+ Out << "<objc property> " << OPD->getNameAsString() << "\n";
+ break;
+ }
+ default:
+ fprintf(stderr, "DeclKind: %d \"%s\"\n", DK, I->getDeclKindName());
+ assert(0 && "decl unhandled");
+ }
+ }
+}
+ASTConsumer *clang::CreateDeclContextPrinter() {
+ return new DeclContextPrinter();
+}
+
+//===----------------------------------------------------------------------===//
+/// InheritanceViewer - C++ Inheritance Visualization
+
+namespace {
+class InheritanceViewer : public ASTConsumer {
+ const std::string clsname;
+public:
+ InheritanceViewer(const std::string& cname) : clsname(cname) {}
+
+ void HandleTranslationUnit(ASTContext &C) {
+ for (ASTContext::type_iterator I=C.types_begin(),E=C.types_end(); I!=E; ++I)
+ if (RecordType *T = dyn_cast<RecordType>(*I)) {
+ if (CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(T->getDecl())) {
+ // FIXME: This lookup needs to be generalized to handle namespaces and
+ // (when we support them) templates.
+ if (D->getNameAsString() == clsname) {
+ D->viewInheritance(C);
+ }
+ }
+ }
+ }
+};
+}
+
+ASTConsumer *clang::CreateInheritanceViewer(const std::string& clsname) {
+ return new InheritanceViewer(clsname);
+}
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
new file mode 100644
index 000000000000..ae90594a4099
--- /dev/null
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -0,0 +1,659 @@
+//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// "Meta" ASTConsumer for running different source analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/AnalysisConsumer.h"
+#include "clang/Frontend/PathDiagnosticClients.h"
+#include "clang/Frontend/ManagerRegistry.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "clang/AST/CFG.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+#include "llvm/System/Program.h"
+
+using namespace clang;
+
+static ExplodedNodeImpl::Auditor* CreateUbiViz();
+
+//===----------------------------------------------------------------------===//
+// Basic type definitions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class AnalysisManager;
+ typedef void (*CodeAction)(AnalysisManager& Mgr);
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// AnalysisConsumer declaration.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+ class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
+ typedef std::vector<CodeAction> Actions;
+ Actions FunctionActions;
+ Actions ObjCMethodActions;
+ Actions ObjCImplementationActions;
+ Actions TranslationUnitActions;
+
+ public:
+ const LangOptions& LOpts;
+ Diagnostic &Diags;
+ ASTContext* Ctx;
+ Preprocessor* PP;
+ PreprocessorFactory* PPF;
+ const std::string OutDir;
+ AnalyzerOptions Opts;
+ llvm::OwningPtr<PathDiagnosticClient> PD;
+
+ AnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
+ PreprocessorFactory* ppf,
+ const LangOptions& lopts,
+ const std::string& outdir,
+ const AnalyzerOptions& opts)
+ : LOpts(lopts), Diags(diags),
+ Ctx(0), PP(pp), PPF(ppf),
+ OutDir(outdir), Opts(opts) {}
+
+ void addCodeAction(CodeAction action) {
+ FunctionActions.push_back(action);
+ ObjCMethodActions.push_back(action);
+ }
+
+ void addObjCImplementationAction(CodeAction action) {
+ ObjCImplementationActions.push_back(action);
+ }
+
+ void addTranslationUnitAction(CodeAction action) {
+ TranslationUnitActions.push_back(action);
+ }
+
+ virtual void Initialize(ASTContext &Context) {
+ Ctx = &Context;
+ }
+
+ virtual void HandleTopLevelDecl(DeclGroupRef D) {
+ for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
+ HandleTopLevelSingleDecl(*I);
+ }
+
+ void HandleTopLevelSingleDecl(Decl *D);
+ virtual void HandleTranslationUnit(ASTContext &C);
+
+ void HandleCode(Decl* D, Stmt* Body, Actions& actions);
+ };
+
+
+ class VISIBILITY_HIDDEN AnalysisManager : public BugReporterData {
+ Decl* D; Stmt* Body;
+
+ enum AnalysisScope { ScopeTU, ScopeDecl } AScope;
+
+ AnalysisConsumer& C;
+ bool DisplayedFunction;
+
+ llvm::OwningPtr<CFG> cfg;
+ llvm::OwningPtr<LiveVariables> liveness;
+ llvm::OwningPtr<ParentMap> PM;
+
+ // Configurable components creators.
+ StoreManagerCreator CreateStoreMgr;
+ ConstraintManagerCreator CreateConstraintMgr;
+
+ public:
+ AnalysisManager(AnalysisConsumer& c, Decl* d, Stmt* b, bool displayProgress)
+ : D(d), Body(b), AScope(ScopeDecl), C(c),
+ DisplayedFunction(!displayProgress) {
+ setManagerCreators();
+ }
+
+ AnalysisManager(AnalysisConsumer& c, bool displayProgress)
+ : D(0), Body(0), AScope(ScopeTU), C(c),
+ DisplayedFunction(!displayProgress) {
+ setManagerCreators();
+ }
+
+ Decl* getCodeDecl() const {
+ assert (AScope == ScopeDecl);
+ return D;
+ }
+
+ Stmt* getBody() const {
+ assert (AScope == ScopeDecl);
+ return Body;
+ }
+
+ StoreManagerCreator getStoreManagerCreator() {
+ return CreateStoreMgr;
+ };
+
+ ConstraintManagerCreator getConstraintManagerCreator() {
+ return CreateConstraintMgr;
+ }
+
+ virtual CFG* getCFG() {
+ if (!cfg) cfg.reset(CFG::buildCFG(getBody()));
+ return cfg.get();
+ }
+
+ virtual ParentMap& getParentMap() {
+ if (!PM)
+ PM.reset(new ParentMap(getBody()));
+ return *PM.get();
+ }
+
+ virtual ASTContext& getContext() {
+ return *C.Ctx;
+ }
+
+ virtual SourceManager& getSourceManager() {
+ return getContext().getSourceManager();
+ }
+
+ virtual Diagnostic& getDiagnostic() {
+ return C.Diags;
+ }
+
+ const LangOptions& getLangOptions() const {
+ return C.LOpts;
+ }
+
+ virtual PathDiagnosticClient* getPathDiagnosticClient() {
+ if (C.PD.get() == 0 && !C.OutDir.empty()) {
+ switch (C.Opts.AnalysisDiagOpt) {
+ default:
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE)\
+case PD_##NAME: C.PD.reset(CREATEFN(C.OutDir, C.PP, C.PPF)); break;
+#include "clang/Frontend/Analyses.def"
+ }
+ }
+ return C.PD.get();
+ }
+
+ virtual LiveVariables* getLiveVariables() {
+ if (!liveness) {
+ CFG* c = getCFG();
+ if (!c) return 0;
+
+ liveness.reset(new LiveVariables(getContext(), *c));
+ liveness->runOnCFG(*c);
+ liveness->runOnAllBlocks(*c, 0, true);
+ }
+
+ return liveness.get();
+ }
+
+ bool shouldVisualizeGraphviz() const { return C.Opts.VisualizeEGDot; }
+
+ bool shouldVisualizeUbigraph() const { return C.Opts.VisualizeEGUbi; }
+
+ bool shouldVisualize() const {
+ return C.Opts.VisualizeEGDot || C.Opts.VisualizeEGUbi;
+ }
+
+ bool shouldTrimGraph() const { return C.Opts.TrimGraph; }
+
+ bool shouldPurgeDead() const { return C.Opts.PurgeDead; }
+
+ bool shouldEagerlyAssume() const { return C.Opts.EagerlyAssume; }
+
+ void DisplayFunction() {
+
+ if (DisplayedFunction)
+ return;
+
+ DisplayedFunction = true;
+
+ // FIXME: Is getCodeDecl() always a named decl?
+ if (isa<FunctionDecl>(getCodeDecl()) ||
+ isa<ObjCMethodDecl>(getCodeDecl())) {
+ NamedDecl *ND = cast<NamedDecl>(getCodeDecl());
+ SourceManager &SM = getContext().getSourceManager();
+ llvm::cerr << "ANALYZE: "
+ << SM.getPresumedLoc(ND->getLocation()).getFilename()
+ << ' ' << ND->getNameAsString() << '\n';
+ }
+ }
+
+ private:
+ /// Set configurable analyzer components creators. First check if there are
+ /// components registered at runtime. Otherwise fall back to builtin
+ /// components.
+ void setManagerCreators() {
+ if (ManagerRegistry::StoreMgrCreator != 0) {
+ CreateStoreMgr = ManagerRegistry::StoreMgrCreator;
+ }
+ else {
+ switch (C.Opts.AnalysisStoreOpt) {
+ default:
+ assert(0 && "Unknown store manager.");
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \
+ case NAME##Model: CreateStoreMgr = CREATEFN; break;
+#include "clang/Frontend/Analyses.def"
+ }
+ }
+
+ if (ManagerRegistry::ConstraintMgrCreator != 0)
+ CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator;
+ else {
+ switch (C.Opts.AnalysisConstraintsOpt) {
+ default:
+ assert(0 && "Unknown store manager.");
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
+ case NAME##Model: CreateConstraintMgr = CREATEFN; break;
+#include "clang/Frontend/Analyses.def"
+ }
+ }
+
+
+ // Some DiagnosticClients should be created all the time instead of
+ // lazily. Create those now.
+ switch (C.Opts.AnalysisDiagOpt) {
+ default: break;
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE)\
+case PD_##NAME: if (AUTOCREATE) getPathDiagnosticClient(); break;
+#include "clang/Frontend/Analyses.def"
+ }
+ }
+
+ };
+
+} // end anonymous namespace
+
+namespace llvm {
+ template <> struct FoldingSetTrait<CodeAction> {
+ static inline void Profile(CodeAction X, FoldingSetNodeID& ID) {
+ ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
+ }
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// AnalysisConsumer implementation.
+//===----------------------------------------------------------------------===//
+
+void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) {
+ switch (D->getKind()) {
+ case Decl::Function: {
+ FunctionDecl* FD = cast<FunctionDecl>(D);
+
+ if (Opts.AnalyzeSpecificFunction.size() > 0 &&
+ Opts.AnalyzeSpecificFunction != FD->getIdentifier()->getName())
+ break;
+
+ Stmt* Body = FD->getBody(*Ctx);
+ if (Body) HandleCode(FD, Body, FunctionActions);
+ break;
+ }
+
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
+
+ if (Opts.AnalyzeSpecificFunction.size() > 0 &&
+ Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString())
+ return;
+
+ Stmt* Body = MD->getBody();
+ if (Body) HandleCode(MD, Body, ObjCMethodActions);
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
+
+ if(!TranslationUnitActions.empty()) {
+ AnalysisManager mgr(*this, Opts.AnalyzerDisplayProgress);
+ for (Actions::iterator I = TranslationUnitActions.begin(),
+ E = TranslationUnitActions.end(); I != E; ++I)
+ (*I)(mgr);
+ }
+
+ if (!ObjCImplementationActions.empty()) {
+ TranslationUnitDecl *TUD = C.getTranslationUnitDecl();
+
+ for (DeclContext::decl_iterator I = TUD->decls_begin(C),
+ E = TUD->decls_end(C);
+ I != E; ++I)
+ if (ObjCImplementationDecl* ID = dyn_cast<ObjCImplementationDecl>(*I))
+ HandleCode(ID, 0, ObjCImplementationActions);
+ }
+
+ // Delete the PathDiagnosticClient here just in case the AnalysisConsumer
+ // object doesn't get released. This will cause any side-effects in the
+ // destructor of the PathDiagnosticClient to get executed.
+ PD.reset();
+}
+
+void AnalysisConsumer::HandleCode(Decl* D, Stmt* Body, Actions& actions) {
+
+ // Don't run the actions if an error has occured with parsing the file.
+ if (Diags.hasErrorOccurred())
+ return;
+
+ // Don't run the actions on declarations in header files unless
+ // otherwise specified.
+ if (!Opts.AnalyzeAll &&
+ !Ctx->getSourceManager().isFromMainFile(D->getLocation()))
+ return;
+
+ // Create an AnalysisManager that will manage the state for analyzing
+ // this method/function.
+ AnalysisManager mgr(*this, D, Body, Opts.AnalyzerDisplayProgress);
+
+ // Dispatch on the actions.
+ for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
+ (*I)(mgr);
+}
+
+//===----------------------------------------------------------------------===//
+// Analyses
+//===----------------------------------------------------------------------===//
+
+static void ActionWarnDeadStores(AnalysisManager& mgr) {
+ if (LiveVariables* L = mgr.getLiveVariables()) {
+ BugReporter BR(mgr);
+ CheckDeadStores(*L, BR);
+ }
+}
+
+static void ActionWarnUninitVals(AnalysisManager& mgr) {
+ if (CFG* c = mgr.getCFG())
+ CheckUninitializedValues(*c, mgr.getContext(), mgr.getDiagnostic());
+}
+
+
+static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf,
+ bool StandardWarnings = true) {
+
+
+ llvm::OwningPtr<GRTransferFuncs> TF(tf);
+
+ // Display progress.
+ mgr.DisplayFunction();
+
+ // Construct the analysis engine.
+ LiveVariables* L = mgr.getLiveVariables();
+ if (!L) return;
+
+ GRExprEngine Eng(*mgr.getCFG(), *mgr.getCodeDecl(), mgr.getContext(), *L, mgr,
+ mgr.shouldPurgeDead(), mgr.shouldEagerlyAssume(),
+ mgr.getStoreManagerCreator(),
+ mgr.getConstraintManagerCreator());
+
+ Eng.setTransferFunctions(tf);
+
+ if (StandardWarnings) {
+ Eng.RegisterInternalChecks();
+ RegisterAppleChecks(Eng);
+ }
+
+ // Set the graph auditor.
+ llvm::OwningPtr<ExplodedNodeImpl::Auditor> Auditor;
+ if (mgr.shouldVisualizeUbigraph()) {
+ Auditor.reset(CreateUbiViz());
+ ExplodedNodeImpl::SetAuditor(Auditor.get());
+ }
+
+ // Execute the worklist algorithm.
+ Eng.ExecuteWorkList();
+
+ // Release the auditor (if any) so that it doesn't monitor the graph
+ // created BugReporter.
+ ExplodedNodeImpl::SetAuditor(0);
+
+ // Visualize the exploded graph.
+ if (mgr.shouldVisualizeGraphviz())
+ Eng.ViewGraph(mgr.shouldTrimGraph());
+
+ // Display warnings.
+ Eng.getBugReporter().FlushReports();
+}
+
+static void ActionCheckerCFRefAux(AnalysisManager& mgr, bool GCEnabled,
+ bool StandardWarnings) {
+
+ GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getContext(),
+ GCEnabled,
+ mgr.getLangOptions());
+
+ ActionGRExprEngine(mgr, TF, StandardWarnings);
+}
+
+static void ActionCheckerCFRef(AnalysisManager& mgr) {
+
+ switch (mgr.getLangOptions().getGCMode()) {
+ default:
+ assert (false && "Invalid GC mode.");
+ case LangOptions::NonGC:
+ ActionCheckerCFRefAux(mgr, false, true);
+ break;
+
+ case LangOptions::GCOnly:
+ ActionCheckerCFRefAux(mgr, true, true);
+ break;
+
+ case LangOptions::HybridGC:
+ ActionCheckerCFRefAux(mgr, false, true);
+ ActionCheckerCFRefAux(mgr, true, false);
+ break;
+ }
+}
+
+static void ActionCheckerSimple(AnalysisManager& mgr) {
+ ActionGRExprEngine(mgr, MakeGRSimpleValsTF());
+}
+
+static void ActionDisplayLiveVariables(AnalysisManager& mgr) {
+ if (LiveVariables* L = mgr.getLiveVariables()) {
+ mgr.DisplayFunction();
+ L->dumpBlockLiveness(mgr.getSourceManager());
+ }
+}
+
+static void ActionCFGDump(AnalysisManager& mgr) {
+ if (CFG* c = mgr.getCFG()) {
+ mgr.DisplayFunction();
+ c->dump();
+ }
+}
+
+static void ActionCFGView(AnalysisManager& mgr) {
+ if (CFG* c = mgr.getCFG()) {
+ mgr.DisplayFunction();
+ c->viewCFG();
+ }
+}
+
+static void ActionWarnObjCDealloc(AnalysisManager& mgr) {
+ if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
+ return;
+
+ BugReporter BR(mgr);
+
+ CheckObjCDealloc(cast<ObjCImplementationDecl>(mgr.getCodeDecl()),
+ mgr.getLangOptions(), BR);
+}
+
+static void ActionWarnObjCUnusedIvars(AnalysisManager& mgr) {
+ BugReporter BR(mgr);
+ CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(mgr.getCodeDecl()), BR);
+}
+
+static void ActionWarnObjCMethSigs(AnalysisManager& mgr) {
+ BugReporter BR(mgr);
+
+ CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(mgr.getCodeDecl()),
+ BR);
+}
+
+//===----------------------------------------------------------------------===//
+// AnalysisConsumer creation.
+//===----------------------------------------------------------------------===//
+
+ASTConsumer* clang::CreateAnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
+ PreprocessorFactory* ppf,
+ const LangOptions& lopts,
+ const std::string& OutDir,
+ const AnalyzerOptions& Opts) {
+
+ llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(diags, pp, ppf,
+ lopts, OutDir,
+ Opts));
+
+ for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i)
+ switch (Opts.AnalysisList[i]) {
+#define ANALYSIS(NAME, CMD, DESC, SCOPE)\
+ case NAME:\
+ C->add ## SCOPE ## Action(&Action ## NAME);\
+ break;
+#include "clang/Frontend/Analyses.def"
+ default: break;
+ }
+
+ // Last, disable the effects of '-Werror' when using the AnalysisConsumer.
+ diags.setWarningsAsErrors(false);
+
+ return C.take();
+}
+
+//===----------------------------------------------------------------------===//
+// Ubigraph Visualization. FIXME: Move to separate file.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class UbigraphViz : public ExplodedNodeImpl::Auditor {
+ llvm::OwningPtr<llvm::raw_ostream> Out;
+ llvm::sys::Path Dir, Filename;
+ unsigned Cntr;
+
+ typedef llvm::DenseMap<void*,unsigned> VMap;
+ VMap M;
+
+public:
+ UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
+ llvm::sys::Path& filename);
+
+ ~UbigraphViz();
+
+ virtual void AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst);
+};
+
+} // end anonymous namespace
+
+static ExplodedNodeImpl::Auditor* CreateUbiViz() {
+ std::string ErrMsg;
+
+ llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
+ if (!ErrMsg.empty())
+ return 0;
+
+ llvm::sys::Path Filename = Dir;
+ Filename.appendComponent("llvm_ubi");
+ Filename.makeUnique(true,&ErrMsg);
+
+ if (!ErrMsg.empty())
+ return 0;
+
+ llvm::cerr << "Writing '" << Filename << "'.\n";
+
+ llvm::OwningPtr<llvm::raw_fd_ostream> Stream;
+ std::string filename = Filename.toString();
+ Stream.reset(new llvm::raw_fd_ostream(filename.c_str(), false, ErrMsg));
+
+ if (!ErrMsg.empty())
+ return 0;
+
+ return new UbigraphViz(Stream.take(), Dir, Filename);
+}
+
+void UbigraphViz::AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst) {
+
+ assert (Src != Dst && "Self-edges are not allowed.");
+
+ // Lookup the Src. If it is a new node, it's a root.
+ VMap::iterator SrcI= M.find(Src);
+ unsigned SrcID;
+
+ if (SrcI == M.end()) {
+ M[Src] = SrcID = Cntr++;
+ *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n";
+ }
+ else
+ SrcID = SrcI->second;
+
+ // Lookup the Dst.
+ VMap::iterator DstI= M.find(Dst);
+ unsigned DstID;
+
+ if (DstI == M.end()) {
+ M[Dst] = DstID = Cntr++;
+ *Out << "('vertex', " << DstID << ")\n";
+ }
+ else {
+ // We have hit DstID before. Change its style to reflect a cache hit.
+ DstID = DstI->second;
+ *Out << "('change_vertex_style', " << DstID << ", 1)\n";
+ }
+
+ // Add the edge.
+ *Out << "('edge', " << SrcID << ", " << DstID
+ << ", ('arrow','true'), ('oriented', 'true'))\n";
+}
+
+UbigraphViz::UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
+ llvm::sys::Path& filename)
+ : Out(out), Dir(dir), Filename(filename), Cntr(0) {
+
+ *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
+ *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
+ " ('size', '1.5'))\n";
+}
+
+UbigraphViz::~UbigraphViz() {
+ Out.reset(0);
+ llvm::cerr << "Running 'ubiviz' program... ";
+ std::string ErrMsg;
+ llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz");
+ std::vector<const char*> args;
+ args.push_back(Ubiviz.c_str());
+ args.push_back(Filename.c_str());
+ args.push_back(0);
+
+ if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) {
+ llvm::cerr << "Error viewing graph: " << ErrMsg << "\n";
+ }
+
+ // Delete the directory.
+ Dir.eraseFromDisk(true);
+}
diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp
new file mode 100644
index 000000000000..44aa3a81a96e
--- /dev/null
+++ b/lib/Frontend/Backend.cpp
@@ -0,0 +1,415 @@
+//===--- Backend.cpp - Interface to LLVM backend technologies -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompileOptions.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/Module.h"
+#include "llvm/ModuleProvider.h"
+#include "llvm/PassManager.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Assembly/PrintModulePass.h"
+#include "llvm/Analysis/CallGraph.h"
+#include "llvm/Analysis/Verifier.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/CodeGen/RegAllocRegistry.h"
+#include "llvm/CodeGen/SchedulerRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/System/Path.h"
+#include "llvm/System/Program.h"
+#include "llvm/Target/SubtargetFeature.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetMachineRegistry.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/IPO.h"
+using namespace clang;
+using namespace llvm;
+
+namespace {
+ class VISIBILITY_HIDDEN BackendConsumer : public ASTConsumer {
+ BackendAction Action;
+ CompileOptions CompileOpts;
+ llvm::raw_ostream *AsmOutStream;
+ ASTContext *Context;
+
+ Timer LLVMIRGeneration;
+ Timer CodeGenerationTime;
+
+ llvm::OwningPtr<CodeGenerator> Gen;
+
+ llvm::Module *TheModule;
+ llvm::TargetData *TheTargetData;
+
+ mutable llvm::ModuleProvider *ModuleProvider;
+ mutable FunctionPassManager *CodeGenPasses;
+ mutable PassManager *PerModulePasses;
+ mutable FunctionPassManager *PerFunctionPasses;
+
+ FunctionPassManager *getCodeGenPasses() const;
+ PassManager *getPerModulePasses() const;
+ FunctionPassManager *getPerFunctionPasses() const;
+
+ void CreatePasses();
+
+ /// AddEmitPasses - Add passes necessary to emit assembly or LLVM
+ /// IR.
+ ///
+ /// \return True on success. On failure \arg Error will be set to
+ /// a user readable error message.
+ bool AddEmitPasses(std::string &Error);
+
+ void EmitAssembly();
+
+ public:
+ BackendConsumer(BackendAction action, Diagnostic &Diags,
+ const LangOptions &langopts, const CompileOptions &compopts,
+ const std::string &infile, llvm::raw_ostream* OS) :
+ Action(action),
+ CompileOpts(compopts),
+ AsmOutStream(OS),
+ LLVMIRGeneration("LLVM IR Generation Time"),
+ CodeGenerationTime("Code Generation Time"),
+ Gen(CreateLLVMCodeGen(Diags, infile, compopts)),
+ TheModule(0), TheTargetData(0), ModuleProvider(0),
+ CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) {
+
+ // Enable -time-passes if -ftime-report is enabled.
+ llvm::TimePassesIsEnabled = CompileOpts.TimePasses;
+ }
+
+ ~BackendConsumer() {
+ delete TheTargetData;
+ delete ModuleProvider;
+ delete CodeGenPasses;
+ delete PerModulePasses;
+ delete PerFunctionPasses;
+ }
+
+ virtual void Initialize(ASTContext &Ctx) {
+ Context = &Ctx;
+
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.startTimer();
+
+ Gen->Initialize(Ctx);
+
+ TheModule = Gen->GetModule();
+ ModuleProvider = new ExistingModuleProvider(TheModule);
+ TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription());
+
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.stopTimer();
+ }
+
+ virtual void HandleTopLevelDecl(DeclGroupRef D) {
+ PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(),
+ Context->getSourceManager(),
+ "LLVM IR generation of declaration");
+
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.startTimer();
+
+ Gen->HandleTopLevelDecl(D);
+
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.stopTimer();
+ }
+
+ virtual void HandleTranslationUnit(ASTContext &C) {
+ {
+ PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.startTimer();
+
+ Gen->HandleTranslationUnit(C);
+
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.stopTimer();
+ }
+
+ // EmitAssembly times and registers crash info itself.
+ EmitAssembly();
+
+ // Force a flush here in case we never get released.
+ if (AsmOutStream)
+ AsmOutStream->flush();
+ }
+
+ virtual void HandleTagDeclDefinition(TagDecl *D) {
+ PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
+ Context->getSourceManager(),
+ "LLVM IR generation of declaration");
+ Gen->HandleTagDeclDefinition(D);
+ }
+
+ virtual void CompleteTentativeDefinition(VarDecl *D) {
+ Gen->CompleteTentativeDefinition(D);
+ }
+ };
+}
+
+FunctionPassManager *BackendConsumer::getCodeGenPasses() const {
+ if (!CodeGenPasses) {
+ CodeGenPasses = new FunctionPassManager(ModuleProvider);
+ CodeGenPasses->add(new TargetData(*TheTargetData));
+ }
+
+ return CodeGenPasses;
+}
+
+PassManager *BackendConsumer::getPerModulePasses() const {
+ if (!PerModulePasses) {
+ PerModulePasses = new PassManager();
+ PerModulePasses->add(new TargetData(*TheTargetData));
+ }
+
+ return PerModulePasses;
+}
+
+FunctionPassManager *BackendConsumer::getPerFunctionPasses() const {
+ if (!PerFunctionPasses) {
+ PerFunctionPasses = new FunctionPassManager(ModuleProvider);
+ PerFunctionPasses->add(new TargetData(*TheTargetData));
+ }
+
+ return PerFunctionPasses;
+}
+
+bool BackendConsumer::AddEmitPasses(std::string &Error) {
+ if (Action == Backend_EmitNothing)
+ return true;
+
+ if (Action == Backend_EmitBC) {
+ getPerModulePasses()->add(createBitcodeWriterPass(*AsmOutStream));
+ } else if (Action == Backend_EmitLL) {
+ getPerModulePasses()->add(createPrintModulePass(AsmOutStream));
+ } else {
+ bool Fast = CompileOpts.OptimizationLevel == 0;
+
+ // Create the TargetMachine for generating code.
+ const TargetMachineRegistry::entry *TME =
+ TargetMachineRegistry::getClosestStaticTargetForModule(*TheModule, Error);
+ if (!TME) {
+ Error = std::string("Unable to get target machine: ") + Error;
+ return false;
+ }
+
+ std::string FeaturesStr;
+ if (CompileOpts.CPU.size() || CompileOpts.Features.size()) {
+ SubtargetFeatures Features;
+ Features.setCPU(CompileOpts.CPU);
+ for (std::vector<std::string>::iterator
+ it = CompileOpts.Features.begin(),
+ ie = CompileOpts.Features.end(); it != ie; ++it)
+ Features.AddFeature(*it);
+ FeaturesStr = Features.getString();
+ }
+ TargetMachine *TM = TME->CtorFn(*TheModule, FeaturesStr);
+
+ // Set register scheduler & allocation policy.
+ RegisterScheduler::setDefault(createDefaultScheduler);
+ RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator :
+ createLinearScanRegisterAllocator);
+
+ // From llvm-gcc:
+ // If there are passes we have to run on the entire module, we do codegen
+ // as a separate "pass" after that happens.
+ // FIXME: This is disabled right now until bugs can be worked out. Reenable
+ // this for fast -O0 compiles!
+ FunctionPassManager *PM = getCodeGenPasses();
+ CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
+
+ switch (CompileOpts.OptimizationLevel) {
+ default: break;
+ case 0: OptLevel = CodeGenOpt::None; break;
+ case 3: OptLevel = CodeGenOpt::Aggressive; break;
+ }
+
+ // Normal mode, emit a .s file by running the code generator.
+ // Note, this also adds codegenerator level optimization passes.
+ switch (TM->addPassesToEmitFile(*PM, *AsmOutStream,
+ TargetMachine::AssemblyFile, OptLevel)) {
+ default:
+ case FileModel::Error:
+ Error = "Unable to interface with target machine!\n";
+ return false;
+ case FileModel::AsmFile:
+ break;
+ }
+
+ if (TM->addPassesToEmitFileFinish(*CodeGenPasses, (MachineCodeEmitter *)0,
+ OptLevel)) {
+ Error = "Unable to interface with target machine!\n";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void BackendConsumer::CreatePasses() {
+ // In -O0 if checking is disabled, we don't even have per-function passes.
+ if (CompileOpts.VerifyModule)
+ getPerFunctionPasses()->add(createVerifierPass());
+
+ if (CompileOpts.OptimizationLevel > 0) {
+ FunctionPassManager *PM = getPerFunctionPasses();
+ PM->add(createCFGSimplificationPass());
+ if (CompileOpts.OptimizationLevel == 1)
+ PM->add(createPromoteMemoryToRegisterPass());
+ else
+ PM->add(createScalarReplAggregatesPass());
+ PM->add(createInstructionCombiningPass());
+ }
+
+ // For now we always create per module passes.
+ PassManager *PM = getPerModulePasses();
+ if (CompileOpts.OptimizationLevel > 0) {
+ if (CompileOpts.UnitAtATime)
+ PM->add(createRaiseAllocationsPass()); // call %malloc -> malloc inst
+ PM->add(createCFGSimplificationPass()); // Clean up disgusting code
+ PM->add(createPromoteMemoryToRegisterPass()); // Kill useless allocas
+ if (CompileOpts.UnitAtATime) {
+ PM->add(createGlobalOptimizerPass()); // Optimize out global vars
+ PM->add(createGlobalDCEPass()); // Remove unused fns and globs
+ PM->add(createIPConstantPropagationPass()); // IP Constant Propagation
+ PM->add(createDeadArgEliminationPass()); // Dead argument elimination
+ }
+ PM->add(createInstructionCombiningPass()); // Clean up after IPCP & DAE
+ PM->add(createCFGSimplificationPass()); // Clean up after IPCP & DAE
+ if (CompileOpts.UnitAtATime) {
+ PM->add(createPruneEHPass()); // Remove dead EH info
+ PM->add(createFunctionAttrsPass()); // Set readonly/readnone attrs
+ }
+ if (CompileOpts.InlineFunctions)
+ PM->add(createFunctionInliningPass()); // Inline small functions
+ else
+ PM->add(createAlwaysInlinerPass()); // Respect always_inline
+ if (CompileOpts.OptimizationLevel > 2)
+ PM->add(createArgumentPromotionPass()); // Scalarize uninlined fn args
+ if (CompileOpts.SimplifyLibCalls)
+ PM->add(createSimplifyLibCallsPass()); // Library Call Optimizations
+ PM->add(createInstructionCombiningPass()); // Cleanup for scalarrepl.
+ PM->add(createJumpThreadingPass()); // Thread jumps.
+ PM->add(createCFGSimplificationPass()); // Merge & remove BBs
+ PM->add(createScalarReplAggregatesPass()); // Break up aggregate allocas
+ PM->add(createInstructionCombiningPass()); // Combine silly seq's
+ PM->add(createCondPropagationPass()); // Propagate conditionals
+ PM->add(createTailCallEliminationPass()); // Eliminate tail calls
+ PM->add(createCFGSimplificationPass()); // Merge & remove BBs
+ PM->add(createReassociatePass()); // Reassociate expressions
+ PM->add(createLoopRotatePass()); // Rotate Loop
+ PM->add(createLICMPass()); // Hoist loop invariants
+ PM->add(createLoopUnswitchPass(CompileOpts.OptimizeSize ? true : false));
+// PM->add(createLoopIndexSplitPass()); // Split loop index
+ PM->add(createInstructionCombiningPass());
+ PM->add(createIndVarSimplifyPass()); // Canonicalize indvars
+ PM->add(createLoopDeletionPass()); // Delete dead loops
+ if (CompileOpts.UnrollLoops)
+ PM->add(createLoopUnrollPass()); // Unroll small loops
+ PM->add(createInstructionCombiningPass()); // Clean up after the unroller
+ PM->add(createGVNPass()); // Remove redundancies
+ PM->add(createMemCpyOptPass()); // Remove memcpy / form memset
+ PM->add(createSCCPPass()); // Constant prop with SCCP
+
+ // Run instcombine after redundancy elimination to exploit opportunities
+ // opened up by them.
+ PM->add(createInstructionCombiningPass());
+ PM->add(createCondPropagationPass()); // Propagate conditionals
+ PM->add(createDeadStoreEliminationPass()); // Delete dead stores
+ PM->add(createAggressiveDCEPass()); // Delete dead instructions
+ PM->add(createCFGSimplificationPass()); // Merge & remove BBs
+
+ if (CompileOpts.UnitAtATime) {
+ PM->add(createStripDeadPrototypesPass()); // Get rid of dead prototypes
+ PM->add(createDeadTypeEliminationPass()); // Eliminate dead types
+ }
+
+ if (CompileOpts.OptimizationLevel > 1 && CompileOpts.UnitAtATime)
+ PM->add(createConstantMergePass()); // Merge dup global constants
+ } else {
+ PM->add(createAlwaysInlinerPass());
+ }
+}
+
+/// EmitAssembly - Handle interaction with LLVM backend to generate
+/// actual machine code.
+void BackendConsumer::EmitAssembly() {
+ // Silently ignore if we weren't initialized for some reason.
+ if (!TheModule || !TheTargetData)
+ return;
+
+
+ TimeRegion Region(CompileOpts.TimePasses ? &CodeGenerationTime : 0);
+
+ // Make sure IR generation is happy with the module. This is
+ // released by the module provider.
+ Module *M = Gen->ReleaseModule();
+ if (!M) {
+ // The module has been released by IR gen on failures, do not
+ // double free.
+ ModuleProvider->releaseModule();
+ TheModule = 0;
+ return;
+ }
+
+ assert(TheModule == M && "Unexpected module change during IR generation");
+
+ CreatePasses();
+
+ std::string Error;
+ if (!AddEmitPasses(Error)) {
+ // FIXME: Don't fail this way.
+ llvm::cerr << "ERROR: " << Error << "\n";
+ ::exit(1);
+ }
+
+ // Run passes. For now we do all passes at once, but eventually we
+ // would like to have the option of streaming code generation.
+
+ if (PerFunctionPasses) {
+ PrettyStackTraceString CrashInfo("Per-function optimization");
+
+ PerFunctionPasses->doInitialization();
+ for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
+ if (!I->isDeclaration())
+ PerFunctionPasses->run(*I);
+ PerFunctionPasses->doFinalization();
+ }
+
+ if (PerModulePasses) {
+ PrettyStackTraceString CrashInfo("Per-module optimization passes");
+ PerModulePasses->run(*M);
+ }
+
+ if (CodeGenPasses) {
+ PrettyStackTraceString CrashInfo("Code generation");
+ CodeGenPasses->doInitialization();
+ for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
+ if (!I->isDeclaration())
+ CodeGenPasses->run(*I);
+ CodeGenPasses->doFinalization();
+ }
+}
+
+ASTConsumer *clang::CreateBackendConsumer(BackendAction Action,
+ Diagnostic &Diags,
+ const LangOptions &LangOpts,
+ const CompileOptions &CompileOpts,
+ const std::string& InFile,
+ llvm::raw_ostream* OS) {
+ return new BackendConsumer(Action, Diags, LangOpts, CompileOpts, InFile, OS);
+}
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
new file mode 100644
index 000000000000..649f9dae37bd
--- /dev/null
+++ b/lib/Frontend/CMakeLists.txt
@@ -0,0 +1,35 @@
+set(LLVM_NO_RTTI 1)
+
+add_clang_library(clangFrontend
+ AnalysisConsumer.cpp
+ ASTConsumers.cpp
+ Backend.cpp
+ CacheTokens.cpp
+ DependencyFile.cpp
+ DiagChecker.cpp
+ DocumentXML.cpp
+ FixItRewriter.cpp
+ GeneratePCH.cpp
+ HTMLDiagnostics.cpp
+ HTMLPrint.cpp
+ InitHeaderSearch.cpp
+ InitPreprocessor.cpp
+ ManagerRegistry.cpp
+ PCHReader.cpp
+ PCHReaderDecl.cpp
+ PCHReaderStmt.cpp
+ PCHWriter.cpp
+ PCHWriterDecl.cpp
+ PCHWriterStmt.cpp
+ PlistDiagnostics.cpp
+ PrintParserCallbacks.cpp
+ PrintPreprocessedOutput.cpp
+ RewriteBlocks.cpp
+ RewriteMacros.cpp
+ RewriteObjC.cpp
+ RewriteTest.cpp
+ StmtXML.cpp
+ TextDiagnosticBuffer.cpp
+ TextDiagnosticPrinter.cpp
+ Warnings.cpp
+ )
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
new file mode 100644
index 000000000000..0065828c6de8
--- /dev/null
+++ b/lib/Frontend/CacheTokens.cpp
@@ -0,0 +1,658 @@
+//===--- CacheTokens.cpp - Caching of lexer tokens for PTH support --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides a possible implementation of PTH support for Clang that is
+// based on caching lexed tokens and identifiers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Streams.h"
+
+// FIXME: put this somewhere else?
+#ifndef S_ISDIR
+#define S_ISDIR(x) (((x)&_S_IFDIR)!=0)
+#endif
+
+using namespace clang;
+using namespace clang::io;
+
+//===----------------------------------------------------------------------===//
+// PTH-specific stuff.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN PTHEntry {
+ Offset TokenData, PPCondData;
+
+public:
+ PTHEntry() {}
+
+ PTHEntry(Offset td, Offset ppcd)
+ : TokenData(td), PPCondData(ppcd) {}
+
+ Offset getTokenOffset() const { return TokenData; }
+ Offset getPPCondTableOffset() const { return PPCondData; }
+};
+
+
+class VISIBILITY_HIDDEN PTHEntryKeyVariant {
+ union { const FileEntry* FE; const char* Path; };
+ enum { IsFE = 0x1, IsDE = 0x2, IsNoExist = 0x0 } Kind;
+ struct stat *StatBuf;
+public:
+ PTHEntryKeyVariant(const FileEntry *fe)
+ : FE(fe), Kind(IsFE), StatBuf(0) {}
+
+ PTHEntryKeyVariant(struct stat* statbuf, const char* path)
+ : Path(path), Kind(IsDE), StatBuf(new struct stat(*statbuf)) {}
+
+ PTHEntryKeyVariant(const char* path)
+ : Path(path), Kind(IsNoExist), StatBuf(0) {}
+
+ bool isFile() const { return Kind == IsFE; }
+
+ const char* getCString() const {
+ return Kind == IsFE ? FE->getName() : Path;
+ }
+
+ unsigned getKind() const { return (unsigned) Kind; }
+
+ void EmitData(llvm::raw_ostream& Out) {
+ switch (Kind) {
+ case IsFE:
+ // Emit stat information.
+ ::Emit32(Out, FE->getInode());
+ ::Emit32(Out, FE->getDevice());
+ ::Emit16(Out, FE->getFileMode());
+ ::Emit64(Out, FE->getModificationTime());
+ ::Emit64(Out, FE->getSize());
+ break;
+ case IsDE:
+ // Emit stat information.
+ ::Emit32(Out, (uint32_t) StatBuf->st_ino);
+ ::Emit32(Out, (uint32_t) StatBuf->st_dev);
+ ::Emit16(Out, (uint16_t) StatBuf->st_mode);
+ ::Emit64(Out, (uint64_t) StatBuf->st_mtime);
+ ::Emit64(Out, (uint64_t) StatBuf->st_size);
+ delete StatBuf;
+ break;
+ default:
+ break;
+ }
+ }
+
+ unsigned getRepresentationLength() const {
+ return Kind == IsNoExist ? 0 : 4 + 4 + 2 + 8 + 8;
+ }
+};
+
+class VISIBILITY_HIDDEN FileEntryPTHEntryInfo {
+public:
+ typedef PTHEntryKeyVariant key_type;
+ typedef key_type key_type_ref;
+
+ typedef PTHEntry data_type;
+ typedef const PTHEntry& data_type_ref;
+
+ static unsigned ComputeHash(PTHEntryKeyVariant V) {
+ return BernsteinHash(V.getCString());
+ }
+
+ static std::pair<unsigned,unsigned>
+ EmitKeyDataLength(llvm::raw_ostream& Out, PTHEntryKeyVariant V,
+ const PTHEntry& E) {
+
+ unsigned n = strlen(V.getCString()) + 1 + 1;
+ ::Emit16(Out, n);
+
+ unsigned m = V.getRepresentationLength() + (V.isFile() ? 4 + 4 : 0);
+ ::Emit8(Out, m);
+
+ return std::make_pair(n, m);
+ }
+
+ static void EmitKey(llvm::raw_ostream& Out, PTHEntryKeyVariant V, unsigned n){
+ // Emit the entry kind.
+ ::Emit8(Out, (unsigned) V.getKind());
+ // Emit the string.
+ Out.write(V.getCString(), n - 1);
+ }
+
+ static void EmitData(llvm::raw_ostream& Out, PTHEntryKeyVariant V,
+ const PTHEntry& E, unsigned) {
+
+
+ // For file entries emit the offsets into the PTH file for token data
+ // and the preprocessor blocks table.
+ if (V.isFile()) {
+ ::Emit32(Out, E.getTokenOffset());
+ ::Emit32(Out, E.getPPCondTableOffset());
+ }
+
+ // Emit any other data associated with the key (i.e., stat information).
+ V.EmitData(Out);
+ }
+};
+
+class OffsetOpt {
+ bool valid;
+ Offset off;
+public:
+ OffsetOpt() : valid(false) {}
+ bool hasOffset() const { return valid; }
+ Offset getOffset() const { assert(valid); return off; }
+ void setOffset(Offset o) { off = o; valid = true; }
+};
+} // end anonymous namespace
+
+typedef OnDiskChainedHashTableGenerator<FileEntryPTHEntryInfo> PTHMap;
+typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap;
+typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy;
+
+namespace {
+class VISIBILITY_HIDDEN PTHWriter {
+ IDMap IM;
+ llvm::raw_fd_ostream& Out;
+ Preprocessor& PP;
+ uint32_t idcount;
+ PTHMap PM;
+ CachedStrsTy CachedStrs;
+ Offset CurStrOffset;
+ std::vector<llvm::StringMapEntry<OffsetOpt>*> StrEntries;
+
+ //// Get the persistent id for the given IdentifierInfo*.
+ uint32_t ResolveID(const IdentifierInfo* II);
+
+ /// Emit a token to the PTH file.
+ void EmitToken(const Token& T);
+
+ void Emit8(uint32_t V) {
+ Out << (unsigned char)(V);
+ }
+
+ void Emit16(uint32_t V) { ::Emit16(Out, V); }
+
+ void Emit24(uint32_t V) {
+ Out << (unsigned char)(V);
+ Out << (unsigned char)(V >> 8);
+ Out << (unsigned char)(V >> 16);
+ assert((V >> 24) == 0);
+ }
+
+ void Emit32(uint32_t V) { ::Emit32(Out, V); }
+
+ void EmitBuf(const char *Ptr, unsigned NumBytes) {
+ Out.write(Ptr, NumBytes);
+ }
+
+ /// EmitIdentifierTable - Emits two tables to the PTH file. The first is
+ /// a hashtable mapping from identifier strings to persistent IDs.
+ /// The second is a straight table mapping from persistent IDs to string data
+ /// (the keys of the first table).
+ std::pair<Offset, Offset> EmitIdentifierTable();
+
+ /// EmitFileTable - Emit a table mapping from file name strings to PTH
+ /// token data.
+ Offset EmitFileTable() { return PM.Emit(Out); }
+
+ PTHEntry LexTokens(Lexer& L);
+ Offset EmitCachedSpellings();
+
+public:
+ PTHWriter(llvm::raw_fd_ostream& out, Preprocessor& pp)
+ : Out(out), PP(pp), idcount(0), CurStrOffset(0) {}
+
+ PTHMap &getPM() { return PM; }
+ void GeneratePTH(const std::string *MainFile = 0);
+};
+} // end anonymous namespace
+
+uint32_t PTHWriter::ResolveID(const IdentifierInfo* II) {
+ // Null IdentifierInfo's map to the persistent ID 0.
+ if (!II)
+ return 0;
+
+ IDMap::iterator I = IM.find(II);
+ if (I != IM.end())
+ return I->second; // We've already added 1.
+
+ IM[II] = ++idcount; // Pre-increment since '0' is reserved for NULL.
+ return idcount;
+}
+
+void PTHWriter::EmitToken(const Token& T) {
+ // Emit the token kind, flags, and length.
+ Emit32(((uint32_t) T.getKind()) | ((((uint32_t) T.getFlags())) << 8)|
+ (((uint32_t) T.getLength()) << 16));
+
+ if (!T.isLiteral()) {
+ Emit32(ResolveID(T.getIdentifierInfo()));
+ } else {
+ // We cache *un-cleaned* spellings. This gives us 100% fidelity with the
+ // source code.
+ const char* s = T.getLiteralData();
+ unsigned len = T.getLength();
+
+ // Get the string entry.
+ llvm::StringMapEntry<OffsetOpt> *E = &CachedStrs.GetOrCreateValue(s, s+len);
+
+ // If this is a new string entry, bump the PTH offset.
+ if (!E->getValue().hasOffset()) {
+ E->getValue().setOffset(CurStrOffset);
+ StrEntries.push_back(E);
+ CurStrOffset += len + 1;
+ }
+
+ // Emit the relative offset into the PTH file for the spelling string.
+ Emit32(E->getValue().getOffset());
+ }
+
+ // Emit the offset into the original source file of this token so that we
+ // can reconstruct its SourceLocation.
+ Emit32(PP.getSourceManager().getFileOffset(T.getLocation()));
+}
+
+PTHEntry PTHWriter::LexTokens(Lexer& L) {
+ // Pad 0's so that we emit tokens to a 4-byte alignment.
+ // This speed up reading them back in.
+ Pad(Out, 4);
+ Offset off = (Offset) Out.tell();
+
+ // Keep track of matching '#if' ... '#endif'.
+ typedef std::vector<std::pair<Offset, unsigned> > PPCondTable;
+ PPCondTable PPCond;
+ std::vector<unsigned> PPStartCond;
+ bool ParsingPreprocessorDirective = false;
+ Token Tok;
+
+ do {
+ L.LexFromRawLexer(Tok);
+ NextToken:
+
+ if ((Tok.isAtStartOfLine() || Tok.is(tok::eof)) &&
+ ParsingPreprocessorDirective) {
+ // Insert an eom token into the token cache. It has the same
+ // position as the next token that is not on the same line as the
+ // preprocessor directive. Observe that we continue processing
+ // 'Tok' when we exit this branch.
+ Token Tmp = Tok;
+ Tmp.setKind(tok::eom);
+ Tmp.clearFlag(Token::StartOfLine);
+ Tmp.setIdentifierInfo(0);
+ EmitToken(Tmp);
+ ParsingPreprocessorDirective = false;
+ }
+
+ if (Tok.is(tok::identifier)) {
+ Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
+ EmitToken(Tok);
+ continue;
+ }
+
+ if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) {
+ // Special processing for #include. Store the '#' token and lex
+ // the next token.
+ assert(!ParsingPreprocessorDirective);
+ Offset HashOff = (Offset) Out.tell();
+ EmitToken(Tok);
+
+ // Get the next token.
+ L.LexFromRawLexer(Tok);
+
+ // If we see the start of line, then we had a null directive "#".
+ if (Tok.isAtStartOfLine())
+ goto NextToken;
+
+ // Did we see 'include'/'import'/'include_next'?
+ if (Tok.isNot(tok::identifier)) {
+ EmitToken(Tok);
+ continue;
+ }
+
+ IdentifierInfo* II = PP.LookUpIdentifierInfo(Tok);
+ Tok.setIdentifierInfo(II);
+ tok::PPKeywordKind K = II->getPPKeywordID();
+
+ ParsingPreprocessorDirective = true;
+
+ switch (K) {
+ case tok::pp_not_keyword:
+ // Invalid directives "#foo" can occur in #if 0 blocks etc, just pass
+ // them through.
+ default:
+ break;
+
+ case tok::pp_include:
+ case tok::pp_import:
+ case tok::pp_include_next: {
+ // Save the 'include' token.
+ EmitToken(Tok);
+ // Lex the next token as an include string.
+ L.setParsingPreprocessorDirective(true);
+ L.LexIncludeFilename(Tok);
+ L.setParsingPreprocessorDirective(false);
+ assert(!Tok.isAtStartOfLine());
+ if (Tok.is(tok::identifier))
+ Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
+
+ break;
+ }
+ case tok::pp_if:
+ case tok::pp_ifdef:
+ case tok::pp_ifndef: {
+ // Add an entry for '#if' and friends. We initially set the target
+ // index to 0. This will get backpatched when we hit #endif.
+ PPStartCond.push_back(PPCond.size());
+ PPCond.push_back(std::make_pair(HashOff, 0U));
+ break;
+ }
+ case tok::pp_endif: {
+ // Add an entry for '#endif'. We set the target table index to itself.
+ // This will later be set to zero when emitting to the PTH file. We
+ // use 0 for uninitialized indices because that is easier to debug.
+ unsigned index = PPCond.size();
+ // Backpatch the opening '#if' entry.
+ assert(!PPStartCond.empty());
+ assert(PPCond.size() > PPStartCond.back());
+ assert(PPCond[PPStartCond.back()].second == 0);
+ PPCond[PPStartCond.back()].second = index;
+ PPStartCond.pop_back();
+ // Add the new entry to PPCond.
+ PPCond.push_back(std::make_pair(HashOff, index));
+ EmitToken(Tok);
+
+ // Some files have gibberish on the same line as '#endif'.
+ // Discard these tokens.
+ do
+ L.LexFromRawLexer(Tok);
+ while (Tok.isNot(tok::eof) && !Tok.isAtStartOfLine());
+ // We have the next token in hand.
+ // Don't immediately lex the next one.
+ goto NextToken;
+ }
+ case tok::pp_elif:
+ case tok::pp_else: {
+ // Add an entry for #elif or #else.
+ // This serves as both a closing and opening of a conditional block.
+ // This means that its entry will get backpatched later.
+ unsigned index = PPCond.size();
+ // Backpatch the previous '#if' entry.
+ assert(!PPStartCond.empty());
+ assert(PPCond.size() > PPStartCond.back());
+ assert(PPCond[PPStartCond.back()].second == 0);
+ PPCond[PPStartCond.back()].second = index;
+ PPStartCond.pop_back();
+ // Now add '#elif' as a new block opening.
+ PPCond.push_back(std::make_pair(HashOff, 0U));
+ PPStartCond.push_back(index);
+ break;
+ }
+ }
+ }
+
+ EmitToken(Tok);
+ }
+ while (Tok.isNot(tok::eof));
+
+ assert(PPStartCond.empty() && "Error: imblanced preprocessor conditionals.");
+
+ // Next write out PPCond.
+ Offset PPCondOff = (Offset) Out.tell();
+
+ // Write out the size of PPCond so that clients can identifer empty tables.
+ Emit32(PPCond.size());
+
+ for (unsigned i = 0, e = PPCond.size(); i!=e; ++i) {
+ Emit32(PPCond[i].first - off);
+ uint32_t x = PPCond[i].second;
+ assert(x != 0 && "PPCond entry not backpatched.");
+ // Emit zero for #endifs. This allows us to do checking when
+ // we read the PTH file back in.
+ Emit32(x == i ? 0 : x);
+ }
+
+ return PTHEntry(off, PPCondOff);
+}
+
+Offset PTHWriter::EmitCachedSpellings() {
+ // Write each cached strings to the PTH file.
+ Offset SpellingsOff = Out.tell();
+
+ for (std::vector<llvm::StringMapEntry<OffsetOpt>*>::iterator
+ I = StrEntries.begin(), E = StrEntries.end(); I!=E; ++I)
+ EmitBuf((*I)->getKeyData(), (*I)->getKeyLength()+1 /*nul included*/);
+
+ return SpellingsOff;
+}
+
+void PTHWriter::GeneratePTH(const std::string *MainFile) {
+ // Generate the prologue.
+ Out << "cfe-pth";
+ Emit32(PTHManager::Version);
+
+ // Leave 4 words for the prologue.
+ Offset PrologueOffset = Out.tell();
+ for (unsigned i = 0; i < 4; ++i)
+ Emit32(0);
+
+ // Write the name of the MainFile.
+ if (MainFile && !MainFile->empty()) {
+ Emit16(MainFile->length());
+ EmitBuf(MainFile->data(), MainFile->length());
+ } else {
+ // String with 0 bytes.
+ Emit16(0);
+ }
+ Emit8(0);
+
+ // Iterate over all the files in SourceManager. Create a lexer
+ // for each file and cache the tokens.
+ SourceManager &SM = PP.getSourceManager();
+ const LangOptions &LOpts = PP.getLangOptions();
+
+ for (SourceManager::fileinfo_iterator I = SM.fileinfo_begin(),
+ E = SM.fileinfo_end(); I != E; ++I) {
+ const SrcMgr::ContentCache &C = *I->second;
+ const FileEntry *FE = C.Entry;
+
+ // FIXME: Handle files with non-absolute paths.
+ llvm::sys::Path P(FE->getName());
+ if (!P.isAbsolute())
+ continue;
+
+ const llvm::MemoryBuffer *B = C.getBuffer();
+ if (!B) continue;
+
+ FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
+ Lexer L(FID, SM, LOpts);
+ PM.insert(FE, LexTokens(L));
+ }
+
+ // Write out the identifier table.
+ const std::pair<Offset,Offset> &IdTableOff = EmitIdentifierTable();
+
+ // Write out the cached strings table.
+ Offset SpellingOff = EmitCachedSpellings();
+
+ // Write out the file table.
+ Offset FileTableOff = EmitFileTable();
+
+ // Finally, write the prologue.
+ Out.seek(PrologueOffset);
+ Emit32(IdTableOff.first);
+ Emit32(IdTableOff.second);
+ Emit32(FileTableOff);
+ Emit32(SpellingOff);
+}
+
+namespace {
+/// StatListener - A simple "interpose" object used to monitor stat calls
+/// invoked by FileManager while processing the original sources used
+/// as input to PTH generation. StatListener populates the PTHWriter's
+/// file map with stat information for directories as well as negative stats.
+/// Stat information for files are populated elsewhere.
+class StatListener : public StatSysCallCache {
+ PTHMap &PM;
+public:
+ StatListener(PTHMap &pm) : PM(pm) {}
+ ~StatListener() {}
+
+ int stat(const char *path, struct stat *buf) {
+ int result = ::stat(path, buf);
+
+ if (result != 0) // Failed 'stat'.
+ PM.insert(path, PTHEntry());
+ else if (S_ISDIR(buf->st_mode)) {
+ // Only cache directories with absolute paths.
+ if (!llvm::sys::Path(path).isAbsolute())
+ return result;
+
+ PM.insert(PTHEntryKeyVariant(buf, path), PTHEntry());
+ }
+
+ return result;
+ }
+};
+} // end anonymous namespace
+
+
+void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
+ // Get the name of the main file.
+ const SourceManager &SrcMgr = PP.getSourceManager();
+ const FileEntry *MainFile = SrcMgr.getFileEntryForID(SrcMgr.getMainFileID());
+ llvm::sys::Path MainFilePath(MainFile->getName());
+ std::string MainFileName;
+
+ if (!MainFilePath.isAbsolute()) {
+ llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
+ P.appendComponent(MainFilePath.toString());
+ MainFileName = P.toString();
+ } else {
+ MainFileName = MainFilePath.toString();
+ }
+
+ // Create the PTHWriter.
+ PTHWriter PW(*OS, PP);
+
+ // Install the 'stat' system call listener in the FileManager.
+ PP.getFileManager().setStatCache(new StatListener(PW.getPM()));
+
+ // Lex through the entire file. This will populate SourceManager with
+ // all of the header information.
+ Token Tok;
+ PP.EnterMainSourceFile();
+ do { PP.Lex(Tok); } while (Tok.isNot(tok::eof));
+
+ // Generate the PTH file.
+ PP.getFileManager().setStatCache(0);
+ PW.GeneratePTH(&MainFileName);
+}
+
+//===----------------------------------------------------------------------===//
+
+class PTHIdKey {
+public:
+ const IdentifierInfo* II;
+ uint32_t FileOffset;
+};
+
+namespace {
+class VISIBILITY_HIDDEN PTHIdentifierTableTrait {
+public:
+ typedef PTHIdKey* key_type;
+ typedef key_type key_type_ref;
+
+ typedef uint32_t data_type;
+ typedef data_type data_type_ref;
+
+ static unsigned ComputeHash(PTHIdKey* key) {
+ return BernsteinHash(key->II->getName());
+ }
+
+ static std::pair<unsigned,unsigned>
+ EmitKeyDataLength(llvm::raw_ostream& Out, const PTHIdKey* key, uint32_t) {
+ unsigned n = strlen(key->II->getName()) + 1;
+ ::Emit16(Out, n);
+ return std::make_pair(n, sizeof(uint32_t));
+ }
+
+ static void EmitKey(llvm::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->getName(), n);
+ }
+
+ static void EmitData(llvm::raw_ostream& Out, PTHIdKey*, uint32_t pID,
+ unsigned) {
+ ::Emit32(Out, pID);
+ }
+};
+} // end anonymous namespace
+
+/// EmitIdentifierTable - Emits two tables to the PTH file. The first is
+/// a hashtable mapping from identifier strings to persistent IDs. The second
+/// is a straight table mapping from persistent IDs to string data (the
+/// keys of the first table).
+///
+std::pair<Offset,Offset> PTHWriter::EmitIdentifierTable() {
+ // Build two maps:
+ // (1) an inverse map from persistent IDs -> (IdentifierInfo*,Offset)
+ // (2) a map from (IdentifierInfo*, Offset)* -> persistent IDs
+
+ // Note that we use 'calloc', so all the bytes are 0.
+ PTHIdKey *IIDMap = (PTHIdKey*)calloc(idcount, sizeof(PTHIdKey));
+
+ // Create the hashtable.
+ OnDiskChainedHashTableGenerator<PTHIdentifierTableTrait> IIOffMap;
+
+ // Generate mapping from persistent IDs -> IdentifierInfo*.
+ for (IDMap::iterator I = IM.begin(), E = IM.end(); I != E; ++I) {
+ // Decrement by 1 because we are using a vector for the lookup and
+ // 0 is reserved for NULL.
+ assert(I->second > 0);
+ assert(I->second-1 < idcount);
+ unsigned idx = I->second-1;
+
+ // Store the mapping from persistent ID to IdentifierInfo*
+ IIDMap[idx].II = I->first;
+
+ // Store the reverse mapping in a hashtable.
+ IIOffMap.insert(&IIDMap[idx], I->second);
+ }
+
+ // Write out the inverse map first. This causes the PCIDKey entries to
+ // record PTH file offsets for the string data. This is used to write
+ // the second table.
+ Offset StringTableOffset = IIOffMap.Emit(Out);
+
+ // Now emit the table mapping from persistent IDs to PTH file offsets.
+ Offset IDOff = Out.tell();
+ Emit32(idcount); // Emit the number of identifiers.
+ for (unsigned i = 0 ; i < idcount; ++i)
+ Emit32(IIDMap[i].FileOffset);
+
+ // Finally, release the inverse map.
+ free(IIDMap);
+
+ return std::make_pair(IDOff, StringTableOffset);
+}
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
new file mode 100644
index 000000000000..c8a654cff2c4
--- /dev/null
+++ b/lib/Frontend/DependencyFile.cpp
@@ -0,0 +1,169 @@
+//===--- DependencyFile.cpp - Generate dependency file --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This code generates dependency files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/DirectoryLookup.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN DependencyFileCallback : public PPCallbacks {
+ std::vector<std::string> Files;
+ llvm::StringSet<> FilesSet;
+ const Preprocessor *PP;
+ std::vector<std::string> Targets;
+ llvm::raw_ostream *OS;
+ bool IncludeSystemHeaders;
+ bool PhonyTarget;
+private:
+ bool FileMatchesDepCriteria(const char *Filename,
+ SrcMgr::CharacteristicKind FileType);
+ void OutputDependencyFile();
+
+public:
+ DependencyFileCallback(const Preprocessor *_PP,
+ llvm::raw_ostream *_OS,
+ const std::vector<std::string> &_Targets,
+ bool _IncludeSystemHeaders,
+ bool _PhonyTarget)
+ : PP(_PP), Targets(_Targets), OS(_OS),
+ IncludeSystemHeaders(_IncludeSystemHeaders), PhonyTarget(_PhonyTarget) {}
+
+ ~DependencyFileCallback() {
+ OutputDependencyFile();
+ OS->flush();
+ delete OS;
+ }
+
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType);
+};
+}
+
+
+
+void clang::AttachDependencyFileGen(Preprocessor *PP, llvm::raw_ostream *OS,
+ std::vector<std::string> &Targets,
+ bool IncludeSystemHeaders,
+ bool PhonyTarget) {
+ assert(!Targets.empty() && "Target required for dependency generation");
+
+ DependencyFileCallback *PPDep =
+ new DependencyFileCallback(PP, OS, Targets, IncludeSystemHeaders,
+ PhonyTarget);
+ PP->setPPCallbacks(PPDep);
+}
+
+/// FileMatchesDepCriteria - Determine whether the given Filename should be
+/// considered as a dependency.
+bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename,
+ SrcMgr::CharacteristicKind FileType) {
+ if (strcmp("<built-in>", Filename) == 0)
+ return false;
+
+ if (IncludeSystemHeaders)
+ return true;
+
+ return FileType == SrcMgr::C_User;
+}
+
+void DependencyFileCallback::FileChanged(SourceLocation Loc,
+ FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType) {
+ if (Reason != PPCallbacks::EnterFile)
+ return;
+
+ // Dependency generation really does want to go all the way to the
+ // file entry for a source location to find out what is depended on.
+ // We do not want #line markers to affect dependency generation!
+ SourceManager &SM = PP->getSourceManager();
+
+ const FileEntry *FE =
+ SM.getFileEntryForID(SM.getFileID(SM.getInstantiationLoc(Loc)));
+ if (FE == 0) return;
+
+ const char *Filename = FE->getName();
+ if (!FileMatchesDepCriteria(Filename, FileType))
+ return;
+
+ // Remove leading "./"
+ if (Filename[0] == '.' && Filename[1] == '/')
+ Filename = &Filename[2];
+
+ if (FilesSet.insert(Filename))
+ Files.push_back(Filename);
+}
+
+void DependencyFileCallback::OutputDependencyFile() {
+ // Write out the dependency targets, trying to avoid overly long
+ // lines when possible. We try our best to emit exactly the same
+ // dependency file as GCC (4.2), assuming the included files are the
+ // same.
+ const unsigned MaxColumns = 75;
+ unsigned Columns = 0;
+
+ for (std::vector<std::string>::iterator
+ I = Targets.begin(), E = Targets.end(); I != E; ++I) {
+ unsigned N = I->length();
+ if (Columns == 0) {
+ Columns += N;
+ *OS << *I;
+ } else if (Columns + N + 2 > MaxColumns) {
+ Columns = N + 2;
+ *OS << " \\\n " << *I;
+ } else {
+ Columns += N + 1;
+ *OS << ' ' << *I;
+ }
+ }
+
+ *OS << ':';
+ Columns += 1;
+
+ // Now add each dependency in the order it was seen, but avoiding
+ // duplicates.
+ for (std::vector<std::string>::iterator I = Files.begin(),
+ E = Files.end(); I != E; ++I) {
+ // Start a new line if this would exceed the column limit. Make
+ // sure to leave space for a trailing " \" in case we need to
+ // break the line on the next iteration.
+ unsigned N = I->length();
+ if (Columns + (N + 1) + 2 > MaxColumns) {
+ *OS << " \\\n ";
+ Columns = 2;
+ }
+ *OS << ' ' << *I;
+ Columns += N + 1;
+ }
+ *OS << '\n';
+
+ // Create phony targets if requested.
+ if (PhonyTarget) {
+ // Skip the first entry, this is always the input file itself.
+ for (std::vector<std::string>::iterator I = Files.begin() + 1,
+ E = Files.end(); I != E; ++I) {
+ *OS << '\n';
+ *OS << *I << ":\n";
+ }
+ }
+}
+
diff --git a/lib/Frontend/DiagChecker.cpp b/lib/Frontend/DiagChecker.cpp
new file mode 100644
index 000000000000..c0f5d141be06
--- /dev/null
+++ b/lib/Frontend/DiagChecker.cpp
@@ -0,0 +1,302 @@
+//===--- DiagChecker.cpp - Diagnostic Checking Functions ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Process the input files and check that the diagnostic messages are expected.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Sema/ParseAST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Preprocessor.h"
+#include <cstdio>
+using namespace clang;
+
+typedef TextDiagnosticBuffer::DiagList DiagList;
+typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
+
+static void EmitError(Preprocessor &PP, SourceLocation Pos, const char *String){
+ unsigned ID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error, String);
+ PP.Diag(Pos, ID);
+}
+
+
+// USING THE DIAGNOSTIC CHECKER:
+//
+// Indicating that a line expects an error or a warning is simple. Put a comment
+// on the line that has the diagnostic, use "expected-{error,warning}" to tag
+// if it's an expected error or warning, and place the expected text between {{
+// and }} markers. The full text doesn't have to be included, only enough to
+// ensure that the correct diagnostic was emitted.
+//
+// Here's an example:
+//
+// int A = B; // expected-error {{use of undeclared identifier 'B'}}
+//
+// You can place as many diagnostics on one line as you wish. To make the code
+// more readable, you can use slash-newline to separate out the diagnostics.
+//
+// The simple syntax above allows each specification to match exactly one error.
+// You can use the extended syntax to customize this. The extended syntax is
+// "expected-<type> <n> {{diag text}}", where <type> is one of "error",
+// "warning" or "note", and <n> is a positive integer. This allows the
+// diagnostic to appear as many times as specified. Example:
+//
+// void f(); // expected-note 2 {{previous declaration is here}}
+//
+
+/// FindDiagnostics - Go through the comment and see if it indicates expected
+/// diagnostics. If so, then put them in a diagnostic list.
+///
+static void FindDiagnostics(const char *CommentStart, unsigned CommentLen,
+ DiagList &ExpectedDiags,
+ Preprocessor &PP, SourceLocation Pos,
+ const char *ExpectedStr) {
+ const char *CommentEnd = CommentStart+CommentLen;
+ unsigned ExpectedStrLen = strlen(ExpectedStr);
+
+ // Find all expected-foo diagnostics in the string and add them to
+ // ExpectedDiags.
+ while (CommentStart != CommentEnd) {
+ CommentStart = std::find(CommentStart, CommentEnd, 'e');
+ if (unsigned(CommentEnd-CommentStart) < ExpectedStrLen) return;
+
+ // If this isn't expected-foo, ignore it.
+ if (memcmp(CommentStart, ExpectedStr, ExpectedStrLen)) {
+ ++CommentStart;
+ continue;
+ }
+
+ CommentStart += ExpectedStrLen;
+
+ // Skip whitespace.
+ while (CommentStart != CommentEnd &&
+ isspace(CommentStart[0]))
+ ++CommentStart;
+
+ // Default, if we find the '{' now, is 1 time.
+ int Times = 1;
+ int Temp = 0;
+ // In extended syntax, there could be a digit now.
+ while (CommentStart != CommentEnd &&
+ CommentStart[0] >= '0' && CommentStart[0] <= '9') {
+ Temp *= 10;
+ Temp += CommentStart[0] - '0';
+ ++CommentStart;
+ }
+ if (Temp > 0)
+ Times = Temp;
+
+ // Skip whitespace again.
+ while (CommentStart != CommentEnd &&
+ isspace(CommentStart[0]))
+ ++CommentStart;
+
+ // We should have a {{ now.
+ if (CommentEnd-CommentStart < 2 ||
+ CommentStart[0] != '{' || CommentStart[1] != '{') {
+ if (std::find(CommentStart, CommentEnd, '{') != CommentEnd)
+ EmitError(PP, Pos, "bogus characters before '{{' in expected string");
+ else
+ EmitError(PP, Pos, "cannot find start ('{{') of expected string");
+ return;
+ }
+ CommentStart += 2;
+
+ // Find the }}.
+ const char *ExpectedEnd = CommentStart;
+ while (1) {
+ ExpectedEnd = std::find(ExpectedEnd, CommentEnd, '}');
+ if (CommentEnd-ExpectedEnd < 2) {
+ EmitError(PP, Pos, "cannot find end ('}}') of expected string");
+ return;
+ }
+
+ if (ExpectedEnd[1] == '}')
+ break;
+
+ ++ExpectedEnd; // Skip over singular }'s
+ }
+
+ std::string Msg(CommentStart, ExpectedEnd);
+ std::string::size_type FindPos;
+ while ((FindPos = Msg.find("\\n")) != std::string::npos)
+ Msg.replace(FindPos, 2, "\n");
+ // Add is possibly multiple times.
+ for (int i = 0; i < Times; ++i)
+ ExpectedDiags.push_back(std::make_pair(Pos, Msg));
+
+ CommentStart = ExpectedEnd;
+ }
+}
+
+/// FindExpectedDiags - Lex the main source file to find all of the
+// expected errors and warnings.
+static void FindExpectedDiags(Preprocessor &PP,
+ DiagList &ExpectedErrors,
+ DiagList &ExpectedWarnings,
+ DiagList &ExpectedNotes) {
+ // 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.
+ FileID FID = PP.getSourceManager().getMainFileID();
+
+ // Create a lexer to lex all the tokens of the main file in raw mode.
+ Lexer RawLex(FID, PP.getSourceManager(), PP.getLangOptions());
+
+ // Return comments as tokens, this is how we find expected diagnostics.
+ RawLex.SetCommentRetentionState(true);
+
+ Token Tok;
+ Tok.setKind(tok::comment);
+ while (Tok.isNot(tok::eof)) {
+ RawLex.Lex(Tok);
+ if (!Tok.is(tok::comment)) continue;
+
+ std::string Comment = PP.getSpelling(Tok);
+ if (Comment.empty()) continue;
+
+
+ // Find all expected errors.
+ FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP,
+ Tok.getLocation(), "expected-error");
+
+ // Find all expected warnings.
+ FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP,
+ Tok.getLocation(), "expected-warning");
+
+ // Find all expected notes.
+ FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP,
+ Tok.getLocation(), "expected-note");
+ };
+}
+
+/// PrintProblem - This takes a diagnostic map of the delta between expected and
+/// seen diagnostics. If there's anything in it, then something unexpected
+/// 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 bool PrintProblem(SourceManager &SourceMgr,
+ const_diag_iterator diag_begin,
+ const_diag_iterator diag_end,
+ const char *Msg) {
+ if (diag_begin == diag_end) return false;
+
+ fprintf(stderr, "%s\n", Msg);
+
+ for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I)
+ fprintf(stderr, " Line %d: %s\n",
+ SourceMgr.getInstantiationLineNumber(I->first),
+ I->second.c_str());
+
+ return true;
+}
+
+/// CompareDiagLists - Compare two diagnostic lists and return the difference
+/// between them.
+///
+static bool CompareDiagLists(SourceManager &SourceMgr,
+ const_diag_iterator d1_begin,
+ const_diag_iterator d1_end,
+ const_diag_iterator d2_begin,
+ const_diag_iterator d2_end,
+ const char *MsgLeftOnly,
+ const char *MsgRightOnly) {
+ DiagList LeftOnly;
+ DiagList Left(d1_begin, d1_end);
+ DiagList Right(d2_begin, d2_end);
+
+ for (const_diag_iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
+ unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(I->first);
+ const std::string &Diag1 = I->second;
+
+ DiagList::iterator II, IE;
+ for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
+ unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first);
+ if (LineNo1 != LineNo2) continue;
+
+ const std::string &Diag2 = II->second;
+ if (Diag2.find(Diag1) != std::string::npos ||
+ Diag1.find(Diag2) != std::string::npos) {
+ break;
+ }
+ }
+ if (II == IE) {
+ // Not found.
+ LeftOnly.push_back(*I);
+ } else {
+ // Found. The same cannot be found twice.
+ Right.erase(II);
+ }
+ }
+ // Now all that's left in Right are those that were not matched.
+
+ return PrintProblem(SourceMgr, LeftOnly.begin(), LeftOnly.end(), MsgLeftOnly)
+ | PrintProblem(SourceMgr, Right.begin(), Right.end(), MsgRightOnly);
+}
+
+/// CheckResults - This compares the expected results to those that
+/// were actually reported. It emits any discrepencies. Return "true" if there
+/// were problems. Return "false" otherwise.
+///
+static bool CheckResults(Preprocessor &PP,
+ const DiagList &ExpectedErrors,
+ const DiagList &ExpectedWarnings,
+ const DiagList &ExpectedNotes) {
+ const DiagnosticClient *DiagClient = PP.getDiagnostics().getClient();
+ assert(DiagClient != 0 &&
+ "DiagChecker requires a valid TextDiagnosticBuffer");
+ const TextDiagnosticBuffer &Diags =
+ static_cast<const TextDiagnosticBuffer&>(*DiagClient);
+ SourceManager &SourceMgr = PP.getSourceManager();
+
+ // We want to capture the delta between what was expected and what was
+ // seen.
+ //
+ // Expected \ Seen - set expected but not seen
+ // Seen \ Expected - set seen but not expected
+ bool HadProblem = false;
+
+ // See if there are error mismatches.
+ HadProblem |= CompareDiagLists(SourceMgr,
+ ExpectedErrors.begin(), ExpectedErrors.end(),
+ Diags.err_begin(), Diags.err_end(),
+ "Errors expected but not seen:",
+ "Errors seen but not expected:");
+
+ // See if there are warning mismatches.
+ HadProblem |= CompareDiagLists(SourceMgr,
+ ExpectedWarnings.begin(),
+ ExpectedWarnings.end(),
+ Diags.warn_begin(), Diags.warn_end(),
+ "Warnings expected but not seen:",
+ "Warnings seen but not expected:");
+
+ // See if there are note mismatches.
+ HadProblem |= CompareDiagLists(SourceMgr,
+ ExpectedNotes.begin(),
+ ExpectedNotes.end(),
+ Diags.note_begin(), Diags.note_end(),
+ "Notes expected but not seen:",
+ "Notes seen but not expected:");
+
+ return HadProblem;
+}
+
+
+/// CheckDiagnostics - Gather the expected diagnostics and check them.
+bool clang::CheckDiagnostics(Preprocessor &PP) {
+ // Gather the set of expected diagnostics.
+ DiagList ExpectedErrors, ExpectedWarnings, ExpectedNotes;
+ FindExpectedDiags(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes);
+
+ // Check that the expected diagnostics occurred.
+ return CheckResults(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes);
+}
diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp
new file mode 100644
index 000000000000..7562d2ae8714
--- /dev/null
+++ b/lib/Frontend/DocumentXML.cpp
@@ -0,0 +1,579 @@
+//===--- DocumentXML.cpp - XML document for ASTs --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the XML document class, which provides the means to
+// dump out the AST in a XML form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/DocumentXML.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Expr.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/StringExtras.h"
+
+namespace clang {
+
+//---------------------------------------------------------
+struct DocumentXML::NodeXML
+{
+ std::string Name;
+ NodeXML* Parent;
+
+ NodeXML(const std::string& name, NodeXML* parent) :
+ Name(name),
+ Parent(parent)
+ {}
+};
+
+//---------------------------------------------------------
+DocumentXML::DocumentXML(const std::string& rootName, llvm::raw_ostream& out) :
+ Root(new NodeXML(rootName, 0)),
+ CurrentNode(Root),
+ Out(out),
+ Ctx(0),
+ CurrentIndent(0),
+ HasCurrentNodeSubNodes(false)
+{
+ Out << "<?xml version=\"1.0\"?>\n<" << rootName;
+}
+
+//---------------------------------------------------------
+DocumentXML::~DocumentXML()
+{
+ assert(CurrentNode == Root && "not completely backtracked");
+ delete Root;
+}
+
+//---------------------------------------------------------
+DocumentXML& DocumentXML::addSubNode(const std::string& name)
+{
+ if (!HasCurrentNodeSubNodes)
+ {
+ Out << ">\n";
+ }
+ CurrentNode = new NodeXML(name, CurrentNode);
+ HasCurrentNodeSubNodes = false;
+ CurrentIndent += 2;
+ Indent();
+ Out << "<" << CurrentNode->Name;
+ return *this;
+}
+
+//---------------------------------------------------------
+void DocumentXML::Indent()
+{
+ for (int i = 0; i < CurrentIndent; ++i)
+ Out << ' ';
+}
+
+//---------------------------------------------------------
+DocumentXML& DocumentXML::toParent()
+{
+ assert(CurrentNode != Root && "to much backtracking");
+
+ if (HasCurrentNodeSubNodes)
+ {
+ Indent();
+ Out << "</" << CurrentNode->Name << ">\n";
+ }
+ else
+ {
+ Out << "/>\n";
+ }
+ NodeXML* NodeToDelete = CurrentNode;
+ CurrentNode = CurrentNode->Parent;
+ delete NodeToDelete;
+ HasCurrentNodeSubNodes = true;
+ CurrentIndent -= 2;
+ return *this;
+}
+
+//---------------------------------------------------------
+namespace {
+
+enum tIdType { ID_NORMAL, ID_FILE, ID_LAST };
+
+unsigned getNewId(tIdType idType)
+{
+ static unsigned int idCounts[ID_LAST] = { 0 };
+ return ++idCounts[idType];
+}
+
+//---------------------------------------------------------
+inline std::string getPrefixedId(unsigned uId, tIdType idType)
+{
+ static const char idPrefix[ID_LAST] = { '_', 'f' };
+ char buffer[20];
+ char* BufPtr = llvm::utohex_buffer(uId, buffer + 20);
+ *--BufPtr = idPrefix[idType];
+ return BufPtr;
+}
+
+//---------------------------------------------------------
+template<class T, class V>
+bool addToMap(T& idMap, const V& value, tIdType idType = ID_NORMAL)
+{
+ typename T::iterator i = idMap.find(value);
+ bool toAdd = i == idMap.end();
+ if (toAdd)
+ {
+ idMap.insert(typename T::value_type(value, getNewId(idType)));
+ }
+ return toAdd;
+}
+
+} // anon NS
+
+//---------------------------------------------------------
+std::string DocumentXML::escapeString(const char* pStr, std::string::size_type len)
+{
+ std::string value;
+ value.reserve(len + 1);
+ char buffer[16];
+ for (unsigned i = 0; i < len; ++i) {
+ switch (char C = pStr[i]) {
+ default:
+ if (isprint(C))
+ value += C;
+ else
+ {
+ sprintf(buffer, "\\%03o", C);
+ value += buffer;
+ }
+ break;
+
+ case '\n': value += "\\n"; break;
+ case '\t': value += "\\t"; break;
+ case '\a': value += "\\a"; break;
+ case '\b': value += "\\b"; break;
+ case '\r': value += "\\r"; break;
+
+ case '&': value += "&amp;"; break;
+ case '<': value += "&lt;"; break;
+ case '>': value += "&gt;"; break;
+ case '"': value += "&quot;"; break;
+ case '\'': value += "&apos;"; break;
+
+ }
+ }
+ return value;
+}
+
+//---------------------------------------------------------
+void DocumentXML::finalize()
+{
+ assert(CurrentNode == Root && "not completely backtracked");
+
+ addSubNode("ReferenceSection");
+ addSubNode("Types");
+
+ for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end(); i != e; ++i)
+ {
+ if (i->first.getCVRQualifiers() != 0)
+ {
+ addSubNode("CvQualifiedType");
+ addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
+ addAttribute("type", getPrefixedId(BasicTypes[i->first.getTypePtr()], ID_NORMAL));
+ if (i->first.isConstQualified()) addAttribute("const", "1");
+ if (i->first.isVolatileQualified()) addAttribute("volatile", "1");
+ if (i->first.isRestrictQualified()) addAttribute("restrict", "1");
+ toParent();
+ }
+ }
+
+ for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(), e = BasicTypes.end(); i != e; ++i)
+ {
+ // don't use the get methods as they strip of typedef infos
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(i->first)) {
+ addSubNode("FundamentalType");
+ addAttribute("name", BT->getName(Ctx->getLangOptions().CPlusPlus));
+ }
+ else if (const PointerType *PT = dyn_cast<PointerType>(i->first)) {
+ addSubNode("PointerType");
+ addTypeAttribute(PT->getPointeeType());
+ }
+ else if (dyn_cast<FunctionType>(i->first) != 0) {
+ addSubNode("FunctionType");
+ }
+ else if (const ReferenceType *RT = dyn_cast<ReferenceType>(i->first)) {
+ addSubNode("ReferenceType");
+ addTypeAttribute(RT->getPointeeType());
+ }
+ else if (const TypedefType * TT = dyn_cast<TypedefType>(i->first)) {
+ addSubNode("Typedef");
+ addAttribute("name", TT->getDecl()->getNameAsString());
+ addTypeAttribute(TT->getDecl()->getUnderlyingType());
+ addContextAttribute(TT->getDecl()->getDeclContext());
+ }
+ else if (const QualifiedNameType *QT = dyn_cast<QualifiedNameType>(i->first)) {
+ addSubNode("QualifiedNameType");
+ addTypeAttribute(QT->getNamedType());
+ }
+ else if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(i->first)) {
+ addSubNode("ArrayType");
+ addAttribute("min", 0);
+ addAttribute("max", (CAT->getSize() - 1).toString(10, false));
+ addTypeAttribute(CAT->getElementType());
+ }
+ else if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(i->first)) {
+ addSubNode("VariableArrayType");
+ addTypeAttribute(VAT->getElementType());
+ }
+ else if (const TagType *RET = dyn_cast<TagType>(i->first)) {
+ const TagDecl *tagDecl = RET->getDecl();
+ std::string tagKind = tagDecl->getKindName();
+ tagKind[0] = std::toupper(tagKind[0]);
+ addSubNode(tagKind);
+ addAttribute("name", tagDecl->getNameAsString());
+ addContextAttribute(tagDecl->getDeclContext());
+ }
+ else if (const VectorType* VT = dyn_cast<VectorType>(i->first)) {
+ addSubNode("VectorType");
+ addTypeAttribute(VT->getElementType());
+ addAttribute("num_elements", VT->getNumElements());
+ }
+ else
+ {
+ addSubNode("FIXMEType");
+ }
+ addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
+ toParent();
+ }
+
+
+ toParent().addSubNode("Contexts");
+
+ for (XML::IdMap<const DeclContext*>::iterator i = Contexts.begin(), e = Contexts.end(); i != e; ++i)
+ {
+ addSubNode(i->first->getDeclKindName());
+ addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(i->first)) {
+ addAttribute("name", ND->getNameAsString());
+ }
+ if (const TagDecl *TD = dyn_cast<TagDecl>(i->first)) {
+ addAttribute("type", getPrefixedId(BasicTypes[TD->getTypeForDecl()], ID_NORMAL));
+ }
+ else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(i->first)) {
+ addAttribute("type", getPrefixedId(BasicTypes[FD->getType()->getAsFunctionType()], ID_NORMAL));
+ }
+
+ if (const DeclContext* parent = i->first->getParent())
+ {
+ addContextAttribute(parent);
+ }
+ toParent();
+ }
+
+ toParent().addSubNode("Files");
+
+ for (XML::IdMap<std::string>::iterator i = SourceFiles.begin(), e = SourceFiles.end(); i != e; ++i)
+ {
+ addSubNode("File");
+ addAttribute("id", getPrefixedId(i->second, ID_FILE));
+ addAttribute("name", escapeString(i->first.c_str(), i->first.size()));
+ toParent();
+ }
+
+ toParent().toParent();
+
+ // write the root closing node (which has always subnodes)
+ Out << "</" << CurrentNode->Name << ">\n";
+}
+
+//---------------------------------------------------------
+void DocumentXML::addTypeAttribute(const QualType& pType)
+{
+ addTypeRecursively(pType);
+ addAttribute("type", getPrefixedId(Types[pType], ID_NORMAL));
+}
+
+//---------------------------------------------------------
+void DocumentXML::addTypeIdAttribute(const Type* pType)
+{
+ addBasicTypeRecursively(pType);
+ addAttribute("id", getPrefixedId(BasicTypes[pType], ID_NORMAL));
+}
+
+//---------------------------------------------------------
+void DocumentXML::addTypeRecursively(const QualType& pType)
+{
+ if (addToMap(Types, pType))
+ {
+ addBasicTypeRecursively(pType.getTypePtr());
+ // beautifier: a non-qualified type shall be transparent
+ if (pType.getCVRQualifiers() == 0)
+ {
+ Types[pType] = BasicTypes[pType.getTypePtr()];
+ }
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addBasicTypeRecursively(const Type* pType)
+{
+ if (addToMap(BasicTypes, pType))
+ {
+ if (const PointerType *PT = dyn_cast<PointerType>(pType)) {
+ addTypeRecursively(PT->getPointeeType());
+ }
+ else if (const ReferenceType *RT = dyn_cast<ReferenceType>(pType)) {
+ addTypeRecursively(RT->getPointeeType());
+ }
+ else if (const TypedefType *TT = dyn_cast<TypedefType>(pType)) {
+ addTypeRecursively(TT->getDecl()->getUnderlyingType());
+ addContextsRecursively(TT->getDecl()->getDeclContext());
+ }
+ else if (const QualifiedNameType *QT = dyn_cast<QualifiedNameType>(pType)) {
+ addTypeRecursively(QT->getNamedType());
+ // FIXME: what to do with NestedNameSpecifier or shall this type be transparent?
+ }
+ else if (const ArrayType *AT = dyn_cast<ArrayType>(pType)) {
+ addTypeRecursively(AT->getElementType());
+ // FIXME: doesn't work in the immediate streaming approach
+ /*if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(AT))
+ {
+ addSubNode("VariableArraySizeExpression");
+ PrintStmt(VAT->getSizeExpr());
+ toParent();
+ }*/
+ }
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addContextAttribute(const DeclContext *DC, tContextUsage usage)
+{
+ addContextsRecursively(DC);
+ const char* pAttributeTags[2] = { "context", "id" };
+ addAttribute(pAttributeTags[usage], getPrefixedId(Contexts[DC], ID_NORMAL));
+}
+
+//---------------------------------------------------------
+void DocumentXML::addContextsRecursively(const DeclContext *DC)
+{
+ if (DC != 0 && addToMap(Contexts, DC))
+ {
+ addContextsRecursively(DC->getParent());
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addSourceFileAttribute(const std::string& fileName)
+{
+ addToMap(SourceFiles, fileName, ID_FILE);
+ addAttribute("file", getPrefixedId(SourceFiles[fileName], ID_FILE));
+}
+
+//---------------------------------------------------------
+PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc)
+{
+ SourceManager& SM = Ctx->getSourceManager();
+ SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
+ PresumedLoc PLoc;
+ if (!SpellingLoc.isInvalid())
+ {
+ PLoc = SM.getPresumedLoc(SpellingLoc);
+ addSourceFileAttribute(PLoc.getFilename());
+ addAttribute("line", PLoc.getLine());
+ addAttribute("col", PLoc.getColumn());
+ }
+ // else there is no error in some cases (eg. CXXThisExpr)
+ return PLoc;
+}
+
+//---------------------------------------------------------
+void DocumentXML::addLocationRange(const SourceRange& R)
+{
+ PresumedLoc PStartLoc = addLocation(R.getBegin());
+ if (R.getBegin() != R.getEnd())
+ {
+ SourceManager& SM = Ctx->getSourceManager();
+ SourceLocation SpellingLoc = SM.getSpellingLoc(R.getEnd());
+ if (!SpellingLoc.isInvalid())
+ {
+ PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc);
+ if (PStartLoc.isInvalid() ||
+ strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) {
+ addToMap(SourceFiles, PLoc.getFilename(), ID_FILE);
+ addAttribute("endfile", PLoc.getFilename());
+ addAttribute("endline", PLoc.getLine());
+ addAttribute("endcol", PLoc.getColumn());
+ } else if (PLoc.getLine() != PStartLoc.getLine()) {
+ addAttribute("endline", PLoc.getLine());
+ addAttribute("endcol", PLoc.getColumn());
+ } else {
+ addAttribute("endcol", PLoc.getColumn());
+ }
+ }
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::PrintFunctionDecl(FunctionDecl *FD)
+{
+ switch (FD->getStorageClass()) {
+ default: assert(0 && "Unknown storage class");
+ case FunctionDecl::None: break;
+ case FunctionDecl::Extern: addAttribute("storage_class", "extern"); break;
+ case FunctionDecl::Static: addAttribute("storage_class", "static"); break;
+ case FunctionDecl::PrivateExtern: addAttribute("storage_class", "__private_extern__"); break;
+ }
+
+ if (FD->isInline())
+ addAttribute("inline", "1");
+
+ const FunctionType *AFT = FD->getType()->getAsFunctionType();
+ addTypeAttribute(AFT->getResultType());
+ addBasicTypeRecursively(AFT);
+
+ if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(AFT)) {
+ addAttribute("num_args", FD->getNumParams());
+ for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
+ addSubNode("Argument");
+ ParmVarDecl *argDecl = FD->getParamDecl(i);
+ addAttribute("name", argDecl->getNameAsString());
+ addTypeAttribute(FT->getArgType(i));
+ addDeclIdAttribute(argDecl);
+ if (argDecl->getDefaultArg())
+ {
+ addAttribute("default_arg", "1");
+ PrintStmt(argDecl->getDefaultArg());
+ }
+ toParent();
+ }
+
+ if (FT->isVariadic()) {
+ addSubNode("Ellipsis").toParent();
+ }
+ } else {
+ assert(isa<FunctionNoProtoType>(AFT));
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addRefAttribute(const NamedDecl* D)
+{
+ // FIXME: in case of CXX inline member functions referring to a member defined
+ // after the function it needs to be tested, if the ids are already there
+ // (should work, but I couldn't test it)
+ if (const DeclContext* DC = dyn_cast<DeclContext>(D))
+ {
+ addAttribute("ref", getPrefixedId(Contexts[DC], ID_NORMAL));
+ }
+ else
+ {
+ addAttribute("ref", getPrefixedId(Decls[D], ID_NORMAL));
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addDeclIdAttribute(const NamedDecl* D)
+{
+ addToMap(Decls, D);
+ addAttribute("id", getPrefixedId(Decls[D], ID_NORMAL));
+}
+
+//---------------------------------------------------------
+void DocumentXML::PrintDecl(Decl *D)
+{
+ addSubNode(D->getDeclKindName());
+ addContextAttribute(D->getDeclContext());
+ addLocation(D->getLocation());
+ if (DeclContext* DC = dyn_cast<DeclContext>(D))
+ {
+ addContextAttribute(DC, CONTEXT_AS_ID);
+ }
+
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ addAttribute("name", ND->getNameAsString());
+
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ PrintFunctionDecl(FD);
+ if (Stmt *Body = FD->getBody(*Ctx)) {
+ addSubNode("Body");
+ PrintStmt(Body);
+ toParent();
+ }
+ } else if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
+ addBasicTypeRecursively(RD->getTypeForDecl());
+ addAttribute("type", getPrefixedId(BasicTypes[RD->getTypeForDecl()], ID_NORMAL));
+ if (!RD->isDefinition())
+ {
+ addAttribute("forward", "1");
+ }
+
+ for (RecordDecl::field_iterator i = RD->field_begin(*Ctx), e = RD->field_end(*Ctx); i != e; ++i)
+ {
+ PrintDecl(*i);
+ }
+ } else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
+ const QualType& enumType = ED->getIntegerType();
+ if (!enumType.isNull())
+ {
+ addTypeAttribute(enumType);
+ for (EnumDecl::enumerator_iterator i = ED->enumerator_begin(*Ctx), e = ED->enumerator_end(*Ctx); i != e; ++i)
+ {
+ PrintDecl(*i);
+ }
+ }
+ } else if (EnumConstantDecl* ECD = dyn_cast<EnumConstantDecl>(D)) {
+ addTypeAttribute(ECD->getType());
+ addAttribute("value", ECD->getInitVal().toString(10, true));
+ if (ECD->getInitExpr())
+ {
+ PrintStmt(ECD->getInitExpr());
+ }
+ } else if (FieldDecl *FdD = dyn_cast<FieldDecl>(D)) {
+ addTypeAttribute(FdD->getType());
+ addDeclIdAttribute(ND);
+ if (FdD->isMutable())
+ addAttribute("mutable", "1");
+ if (FdD->isBitField())
+ {
+ addAttribute("bitfield", "1");
+ PrintStmt(FdD->getBitWidth());
+ }
+ } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ addTypeIdAttribute(Ctx->getTypedefType(TD).getTypePtr());
+ addTypeAttribute(TD->getUnderlyingType());
+ } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
+ addTypeAttribute(VD->getType());
+ addDeclIdAttribute(ND);
+
+ VarDecl *V = dyn_cast<VarDecl>(VD);
+ if (V && V->getStorageClass() != VarDecl::None)
+ {
+ addAttribute("storage_class", VarDecl::getStorageClassSpecifierString(V->getStorageClass()));
+ }
+
+ if (V && V->getInit())
+ {
+ PrintStmt(V->getInit());
+ }
+ }
+ } else if (LinkageSpecDecl* LSD = dyn_cast<LinkageSpecDecl>(D)) {
+ switch (LSD->getLanguage())
+ {
+ case LinkageSpecDecl::lang_c: addAttribute("lang", "C"); break;
+ case LinkageSpecDecl::lang_cxx: addAttribute("lang", "CXX"); break;
+ default: assert(0 && "Unexpected lang id");
+ }
+ } else if (isa<FileScopeAsmDecl>(D)) {
+ // FIXME: Implement this
+ } else {
+ assert(0 && "Unexpected decl");
+ }
+ toParent();
+}
+
+//---------------------------------------------------------
+} // NS clang
+
diff --git a/lib/Frontend/FixItRewriter.cpp b/lib/Frontend/FixItRewriter.cpp
new file mode 100644
index 000000000000..1ed89d75a9c9
--- /dev/null
+++ b/lib/Frontend/FixItRewriter.cpp
@@ -0,0 +1,199 @@
+//===--- FixItRewriter.cpp - Fix-It Rewriter Diagnostic Client --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a diagnostic client adaptor that performs rewrites as
+// suggested by code modification hints attached to diagnostics. It
+// then forwards any diagnostics to the adapted diagnostic client.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/FixItRewriter.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+using namespace clang;
+
+FixItRewriter::FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr,
+ const LangOptions &LangOpts)
+ : Diags(Diags), Rewrite(SourceMgr, LangOpts), NumFailures(0) {
+ Client = Diags.getClient();
+ Diags.setClient(this);
+}
+
+FixItRewriter::~FixItRewriter() {
+ Diags.setClient(Client);
+}
+
+bool FixItRewriter::WriteFixedFile(const std::string &InFileName,
+ const std::string &OutFileName) {
+ if (NumFailures > 0) {
+ Diag(FullSourceLoc(), diag::warn_fixit_no_changes);
+ return true;
+ }
+
+ llvm::OwningPtr<llvm::raw_ostream> OwnedStream;
+ llvm::raw_ostream *OutFile;
+ if (!OutFileName.empty()) {
+ std::string Err;
+ OutFile = new llvm::raw_fd_ostream(OutFileName.c_str(),
+ // set binary mode (critical for Windoze)
+ true,
+ Err);
+ OwnedStream.reset(OutFile);
+ } else if (InFileName == "-") {
+ OutFile = &llvm::outs();
+ } else {
+ llvm::sys::Path Path(InFileName);
+ std::string Suffix = Path.getSuffix();
+ Path.eraseSuffix();
+ Path.appendSuffix("fixit." + Suffix);
+ std::string Err;
+ OutFile = new llvm::raw_fd_ostream(Path.toString().c_str(),
+ // set binary mode (critical for Windoze)
+ true,
+ Err);
+ OwnedStream.reset(OutFile);
+ }
+
+ FileID MainFileID = Rewrite.getSourceMgr().getMainFileID();
+ if (const RewriteBuffer *RewriteBuf =
+ Rewrite.getRewriteBufferFor(MainFileID)) {
+ *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
+ } else {
+ std::fprintf(stderr, "Main file is unchanged\n");
+ }
+ OutFile->flush();
+
+ return false;
+}
+
+bool FixItRewriter::IncludeInDiagnosticCounts() const {
+ return Client? Client->IncludeInDiagnosticCounts() : true;
+}
+
+void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info) {
+ Client->HandleDiagnostic(DiagLevel, Info);
+
+ // Skip over any diagnostics that are ignored.
+ if (DiagLevel == Diagnostic::Ignored)
+ return;
+
+ if (!FixItLocations.empty()) {
+ // The user has specified the locations where we should perform
+ // the various fix-it modifications.
+
+ // If this diagnostic does not have any code modifications,
+ // completely ignore it, even if it's an error: fix-it locations
+ // are meant to perform specific fix-ups even in the presence of
+ // other errors.
+ if (Info.getNumCodeModificationHints() == 0)
+ return;
+
+ // See if the location of the error is one that matches what the
+ // user requested.
+ bool AcceptableLocation = false;
+ const FileEntry *File
+ = Rewrite.getSourceMgr().getFileEntryForID(
+ Info.getLocation().getFileID());
+ unsigned Line = Info.getLocation().getSpellingLineNumber();
+ unsigned Column = Info.getLocation().getSpellingColumnNumber();
+ for (llvm::SmallVector<RequestedSourceLocation, 4>::iterator
+ Loc = FixItLocations.begin(), LocEnd = FixItLocations.end();
+ Loc != LocEnd; ++Loc) {
+ if (Loc->File == File && Loc->Line == Line && Loc->Column == Column) {
+ AcceptableLocation = true;
+ break;
+ }
+ }
+
+ if (!AcceptableLocation)
+ return;
+ }
+
+ // Make sure that we can perform all of the modifications we
+ // in this diagnostic.
+ bool CanRewrite = Info.getNumCodeModificationHints() > 0;
+ for (unsigned Idx = 0, Last = Info.getNumCodeModificationHints();
+ Idx < Last; ++Idx) {
+ const CodeModificationHint &Hint = Info.getCodeModificationHint(Idx);
+ if (Hint.RemoveRange.isValid() &&
+ Rewrite.getRangeSize(Hint.RemoveRange) == -1) {
+ CanRewrite = false;
+ break;
+ }
+
+ if (Hint.InsertionLoc.isValid() &&
+ !Rewrite.isRewritable(Hint.InsertionLoc)) {
+ CanRewrite = false;
+ break;
+ }
+ }
+
+ if (!CanRewrite) {
+ if (Info.getNumCodeModificationHints() > 0)
+ 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 (++NumFailures == 1)
+ Diag(Info.getLocation(), diag::note_fixit_unfixed_error);
+ }
+ return;
+ }
+
+ bool Failed = false;
+ for (unsigned Idx = 0, Last = Info.getNumCodeModificationHints();
+ Idx < Last; ++Idx) {
+ const CodeModificationHint &Hint = Info.getCodeModificationHint(Idx);
+ if (!Hint.RemoveRange.isValid()) {
+ // We're adding code.
+ if (Rewrite.InsertStrBefore(Hint.InsertionLoc, Hint.CodeToInsert))
+ Failed = true;
+ continue;
+ }
+
+ if (Hint.CodeToInsert.empty()) {
+ // We're removing code.
+ if (Rewrite.RemoveText(Hint.RemoveRange.getBegin(),
+ Rewrite.getRangeSize(Hint.RemoveRange)))
+ Failed = true;
+ continue;
+ }
+
+ // We're replacing code.
+ if (Rewrite.ReplaceText(Hint.RemoveRange.getBegin(),
+ Rewrite.getRangeSize(Hint.RemoveRange),
+ Hint.CodeToInsert.c_str(),
+ Hint.CodeToInsert.size()))
+ Failed = true;
+ }
+
+ if (Failed) {
+ ++NumFailures;
+ Diag(Info.getLocation(), diag::note_fixit_failed);
+ return;
+ }
+
+ Diag(Info.getLocation(), diag::note_fixit_applied);
+}
+
+/// \brief Emit a diagnostic via the adapted diagnostic client.
+void FixItRewriter::Diag(FullSourceLoc Loc, unsigned DiagID) {
+ // When producing this diagnostic, we temporarily bypass ourselves,
+ // clear out any current diagnostic, and let the downstream client
+ // format the diagnostic.
+ Diags.setClient(Client);
+ Diags.Clear();
+ Diags.Report(Loc, DiagID);
+ Diags.setClient(this);
+}
diff --git a/lib/Frontend/GeneratePCH.cpp b/lib/Frontend/GeneratePCH.cpp
new file mode 100644
index 000000000000..8be88ce38117
--- /dev/null
+++ b/lib/Frontend/GeneratePCH.cpp
@@ -0,0 +1,78 @@
+//===--- GeneratePCH.cpp - AST Consumer for PCH Generation ------*- 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 CreatePCHGenerate function, which creates an
+// ASTConsume that generates a PCH file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/PCHWriter.h"
+#include "clang/Sema/SemaConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/FileManager.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/System/Path.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Streams.h"
+#include <string>
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+ class VISIBILITY_HIDDEN PCHGenerator : public SemaConsumer {
+ const Preprocessor &PP;
+ llvm::raw_ostream *Out;
+ Sema *SemaPtr;
+ MemorizeStatCalls *StatCalls; // owned by the FileManager
+
+ public:
+ explicit PCHGenerator(const Preprocessor &PP, llvm::raw_ostream *Out);
+ virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
+ virtual void HandleTranslationUnit(ASTContext &Ctx);
+ };
+}
+
+PCHGenerator::PCHGenerator(const Preprocessor &PP, llvm::raw_ostream *OS)
+ : PP(PP), Out(OS), SemaPtr(0), StatCalls(0) {
+
+ // Install a stat() listener to keep track of all of the stat()
+ // calls.
+ StatCalls = new MemorizeStatCalls;
+ PP.getFileManager().setStatCache(StatCalls);
+}
+
+void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
+ if (PP.getDiagnostics().hasErrorOccurred())
+ return;
+
+ // Write the PCH contents into a buffer
+ std::vector<unsigned char> Buffer;
+ BitstreamWriter Stream(Buffer);
+ PCHWriter Writer(Stream);
+
+ // Emit the PCH file
+ assert(SemaPtr && "No Sema?");
+ Writer.WritePCH(*SemaPtr, StatCalls);
+
+ // Write the generated bitstream to "Out".
+ Out->write((char *)&Buffer.front(), Buffer.size());
+
+ // Make sure it hits disk now.
+ Out->flush();
+}
+
+ASTConsumer *clang::CreatePCHGenerator(const Preprocessor &PP,
+ llvm::raw_ostream *OS) {
+ return new PCHGenerator(PP, OS);
+}
diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp
new file mode 100644
index 000000000000..9cfe0b2a6124
--- /dev/null
+++ b/lib/Frontend/HTMLDiagnostics.cpp
@@ -0,0 +1,602 @@
+//===--- HTMLDiagnostics.cpp - HTML Diagnostics for Paths ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the HTMLDiagnostics object.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PathDiagnosticClients.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/HTMLRewrite.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+#include <fstream>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Boilerplate.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class VISIBILITY_HIDDEN HTMLDiagnostics : public PathDiagnosticClient {
+ llvm::sys::Path Directory, FilePrefix;
+ bool createdDir, noDir;
+ Preprocessor* PP;
+ std::vector<const PathDiagnostic*> BatchedDiags;
+public:
+ HTMLDiagnostics(const std::string& prefix, Preprocessor* pp);
+
+ virtual ~HTMLDiagnostics();
+
+ virtual void SetPreprocessor(Preprocessor *pp) { PP = pp; }
+
+ virtual void HandlePathDiagnostic(const PathDiagnostic* D);
+
+ unsigned ProcessMacroPiece(llvm::raw_ostream& os,
+ const PathDiagnosticMacroPiece& P,
+ unsigned num);
+
+ void HandlePiece(Rewriter& R, FileID BugFileID,
+ const PathDiagnosticPiece& P, unsigned num, unsigned max);
+
+ void HighlightRange(Rewriter& R, FileID BugFileID, SourceRange Range,
+ const char *HighlightStart = "<span class=\"mrange\">",
+ const char *HighlightEnd = "</span>");
+
+ void ReportDiag(const PathDiagnostic& D);
+};
+
+} // end anonymous namespace
+
+HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix, Preprocessor* pp)
+ : Directory(prefix), FilePrefix(prefix), createdDir(false), noDir(false),
+ PP(pp) {
+
+ // All html files begin with "report"
+ FilePrefix.appendComponent("report");
+}
+
+PathDiagnosticClient*
+clang::CreateHTMLDiagnosticClient(const std::string& prefix, Preprocessor* PP,
+ PreprocessorFactory*) {
+ return new HTMLDiagnostics(prefix, PP);
+}
+
+//===----------------------------------------------------------------------===//
+// Report processing.
+//===----------------------------------------------------------------------===//
+
+void HTMLDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
+ if (!D)
+ return;
+
+ if (D->empty()) {
+ delete D;
+ return;
+ }
+
+ const_cast<PathDiagnostic*>(D)->flattenLocations();
+ BatchedDiags.push_back(D);
+}
+
+HTMLDiagnostics::~HTMLDiagnostics() {
+ while (!BatchedDiags.empty()) {
+ const PathDiagnostic* D = BatchedDiags.back();
+ BatchedDiags.pop_back();
+ ReportDiag(*D);
+ delete D;
+ }
+}
+
+void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D) {
+ // Create the HTML directory if it is missing.
+ if (!createdDir) {
+ createdDir = true;
+ std::string ErrorMsg;
+ Directory.createDirectoryOnDisk(true, &ErrorMsg);
+
+ if (!Directory.isDirectory()) {
+ llvm::cerr << "warning: could not create directory '"
+ << Directory.toString() << "'\n"
+ << "reason: " << ErrorMsg << '\n';
+
+ noDir = true;
+
+ return;
+ }
+ }
+
+ if (noDir)
+ return;
+
+ const SourceManager &SMgr = D.begin()->getLocation().getManager();
+ FileID FID;
+
+ // 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();
+
+ if (FID.isInvalid()) {
+ FID = SMgr.getFileID(L);
+ } else if (SMgr.getFileID(L) != FID)
+ return; // FIXME: Emit a warning?
+
+ // Check the source ranges.
+ for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(),
+ RE=I->ranges_end(); RI!=RE; ++RI) {
+
+ SourceLocation L = SMgr.getInstantiationLoc(RI->getBegin());
+
+ if (!L.isFileID() || SMgr.getFileID(L) != FID)
+ return; // FIXME: Emit a warning?
+
+ L = SMgr.getInstantiationLoc(RI->getEnd());
+
+ if (!L.isFileID() || SMgr.getFileID(L) != FID)
+ return; // FIXME: Emit a warning?
+ }
+ }
+
+ if (FID.isInvalid())
+ return; // FIXME: Emit a warning?
+
+ // Create a new rewriter to generate HTML.
+ Rewriter R(const_cast<SourceManager&>(SMgr), PP->getLangOptions());
+
+ // Process the path.
+ unsigned n = D.size();
+ unsigned max = n;
+
+ for (PathDiagnostic::const_reverse_iterator I=D.rbegin(), E=D.rend();
+ I!=E; ++I, --n)
+ HandlePiece(R, FID, *I, n, max);
+
+ // Add line numbers, header, footer, etc.
+
+ // unsigned FID = R.getSourceMgr().getMainFileID();
+ html::EscapeText(R, FID);
+ html::AddLineNumbers(R, FID);
+
+ // If we have a preprocessor, relex the file and syntax highlight.
+ // We might not have a preprocessor if we come from a deserialized AST file,
+ // for example.
+
+ if (PP) html::SyntaxHighlight(R, FID, *PP);
+
+ // FIXME: We eventually want to use PPF to create a fresh Preprocessor,
+ // once we have worked out the bugs.
+ //
+ // if (PPF) html::HighlightMacros(R, FID, *PPF);
+ //
+ if (PP) html::HighlightMacros(R, FID, *PP);
+
+ // Get the full directory name of the analyzed file.
+
+ const FileEntry* Entry = SMgr.getFileEntryForID(FID);
+
+ // This is a cludge; basically we want to append either the full
+ // working directory if we have no directory information. This is
+ // a work in progress.
+
+ std::string DirName = "";
+
+ if (!llvm::sys::Path(Entry->getName()).isAbsolute()) {
+ llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
+ DirName = P.toString() + "/";
+ }
+
+ // Add the name of the file as an <h1> tag.
+
+ {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+
+ os << "<!-- REPORTHEADER -->\n"
+ << "<h3>Bug Summary</h3>\n<table class=\"simpletable\">\n"
+ "<tr><td class=\"rowname\">File:</td><td>"
+ << html::EscapeText(DirName)
+ << html::EscapeText(Entry->getName())
+ << "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>"
+ "<a href=\"#EndPath\">line "
+ << (*D.rbegin()).getLocation().asLocation().getInstantiationLineNumber()
+ << ", column "
+ << (*D.rbegin()).getLocation().asLocation().getInstantiationColumnNumber()
+ << "</a></td></tr>\n"
+ "<tr><td class=\"rowname\">Description:</td><td>"
+ << D.getDescription() << "</td></tr>\n";
+
+ // Output any other meta data.
+
+ for (PathDiagnostic::meta_iterator I=D.meta_begin(), E=D.meta_end();
+ I!=E; ++I) {
+ os << "<tr><td></td><td>" << html::EscapeText(*I) << "</td></tr>\n";
+ }
+
+ os << "</table>\n<!-- REPORTSUMMARYEXTRA -->\n"
+ "<h3>Annotated Source Code</h3>\n";
+
+ R.InsertStrBefore(SMgr.getLocForStartOfFile(FID), os.str());
+ }
+
+ // Embed meta-data tags.
+
+ const std::string& BugDesc = D.getDescription();
+
+ if (!BugDesc.empty()) {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+ os << "\n<!-- BUGDESC " << BugDesc << " -->\n";
+ R.InsertStrBefore(SMgr.getLocForStartOfFile(FID), os.str());
+ }
+
+ const std::string& BugType = D.getBugType();
+ if (!BugType.empty()) {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+ os << "\n<!-- BUGTYPE " << BugType << " -->\n";
+ R.InsertStrBefore(SMgr.getLocForStartOfFile(FID), os.str());
+ }
+
+ const std::string& BugCategory = D.getCategory();
+
+ if (!BugCategory.empty()) {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+ os << "\n<!-- BUGCATEGORY " << BugCategory << " -->\n";
+ R.InsertStrBefore(SMgr.getLocForStartOfFile(FID), os.str());
+ }
+
+ {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+ os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n";
+ R.InsertStrBefore(SMgr.getLocForStartOfFile(FID), os.str());
+ }
+
+ {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+ os << "\n<!-- BUGLINE "
+ << D.back()->getLocation().asLocation().getInstantiationLineNumber()
+ << " -->\n";
+ R.InsertStrBefore(SMgr.getLocForStartOfFile(FID), os.str());
+ }
+
+ {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+ os << "\n<!-- BUGPATHLENGTH " << D.size() << " -->\n";
+ R.InsertStrBefore(SMgr.getLocForStartOfFile(FID), os.str());
+ }
+
+ // Add CSS, header, and footer.
+
+ html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry->getName());
+
+ // Get the rewrite buffer.
+ const RewriteBuffer *Buf = R.getRewriteBufferFor(FID);
+
+ if (!Buf) {
+ llvm::cerr << "warning: no diagnostics generated for main file.\n";
+ return;
+ }
+
+ // Create the stream to write out the HTML.
+ std::ofstream os;
+
+ {
+ // Create a path for the target HTML file.
+ llvm::sys::Path F(FilePrefix);
+ F.makeUnique(false, NULL);
+
+ // Rename the file with an HTML extension.
+ llvm::sys::Path H(F);
+ H.appendSuffix("html");
+ F.renamePathOnDisk(H, NULL);
+
+ os.open(H.toString().c_str());
+
+ if (!os) {
+ llvm::cerr << "warning: could not create file '" << F.toString() << "'\n";
+ return;
+ }
+ }
+
+ // Emit the HTML to disk.
+
+ for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I)
+ os << *I;
+}
+
+void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
+ const PathDiagnosticPiece& P,
+ unsigned num, unsigned max) {
+
+ // For now, just draw a box above the line in question, and emit the
+ // warning.
+ FullSourceLoc Pos = P.getLocation().asLocation();
+
+ if (!Pos.isValid())
+ return;
+
+ SourceManager &SM = R.getSourceMgr();
+ assert(&Pos.getManager() == &SM && "SourceManagers are different!");
+ std::pair<FileID, unsigned> LPosInfo = SM.getDecomposedInstantiationLoc(Pos);
+
+ if (LPosInfo.first != BugFileID)
+ return;
+
+ const llvm::MemoryBuffer *Buf = SM.getBuffer(LPosInfo.first);
+ const char* FileStart = Buf->getBufferStart();
+
+ // 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 *LineStart = TokInstantiationPtr-ColNo;
+
+ // Compute LineEnd.
+ const char *LineEnd = TokInstantiationPtr;
+ const char* FileEnd = Buf->getBufferEnd();
+ while (*LineEnd != '\n' && LineEnd != FileEnd)
+ ++LineEnd;
+
+ // Compute the margin offset by counting tabs and non-tabs.
+ unsigned PosNo = 0;
+ for (const char* c = LineStart; c != TokInstantiationPtr; ++c)
+ PosNo += *c == '\t' ? 8 : 1;
+
+ // Create the html for the message.
+
+ const char *Kind = 0;
+ switch (P.getKind()) {
+ case PathDiagnosticPiece::Event: Kind = "Event"; break;
+ case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break;
+ // Setting Kind to "Control" is intentional.
+ case PathDiagnosticPiece::Macro: Kind = "Control"; break;
+ }
+
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+
+ os << "\n<tr><td class=\"num\"></td><td class=\"line\"><div id=\"";
+
+ if (num == max)
+ os << "EndPath";
+ else
+ os << "Path" << num;
+
+ os << "\" class=\"msg";
+ if (Kind)
+ os << " msg" << Kind;
+ os << "\" style=\"margin-left:" << PosNo << "ex";
+
+ // Output a maximum size.
+ if (!isa<PathDiagnosticMacroPiece>(P)) {
+ // Get the string and determining its maximum substring.
+ const std::string& Msg = P.getString();
+ unsigned max_token = 0;
+ unsigned cnt = 0;
+ unsigned len = Msg.size();
+
+ for (std::string::const_iterator I=Msg.begin(), E=Msg.end(); I!=E; ++I)
+ switch (*I) {
+ default:
+ ++cnt;
+ continue;
+ case ' ':
+ case '\t':
+ case '\n':
+ if (cnt > max_token) max_token = cnt;
+ cnt = 0;
+ }
+
+ if (cnt > max_token)
+ max_token = cnt;
+
+ // Determine the approximate size of the message bubble in em.
+ unsigned em;
+ const unsigned max_line = 120;
+
+ if (max_token >= max_line)
+ em = max_token / 2;
+ else {
+ unsigned characters = max_line;
+ unsigned lines = len / max_line;
+
+ if (lines > 0) {
+ for (; characters > max_token; --characters)
+ if (len / characters > lines) {
+ ++characters;
+ break;
+ }
+ }
+
+ em = characters / 2;
+ }
+
+ if (em < max_line/2)
+ os << "; max-width:" << em << "em";
+ }
+ else
+ os << "; max-width:100em";
+
+ os << "\">";
+
+ if (max > 1) {
+ os << "<table class=\"msgT\"><tr><td valign=\"top\">";
+ os << "<div class=\"PathIndex";
+ if (Kind) os << " PathIndex" << Kind;
+ os << "\">" << num << "</div>";
+ os << "</td><td>";
+ }
+
+ if (const PathDiagnosticMacroPiece *MP =
+ dyn_cast<PathDiagnosticMacroPiece>(&P)) {
+
+ os << "Within the expansion of the macro '";
+
+ // Get the name of the macro by relexing it.
+ {
+ FullSourceLoc L = MP->getLocation().asLocation().getInstantiationLoc();
+ assert(L.isFileID());
+ std::pair<const char*, const char*> BufferInfo = L.getBufferData();
+ const char* MacroName = L.getDecomposedLoc().second + BufferInfo.first;
+ Lexer rawLexer(L, PP->getLangOptions(), BufferInfo.first,
+ MacroName, BufferInfo.second);
+
+ Token TheTok;
+ rawLexer.LexFromRawLexer(TheTok);
+ for (unsigned i = 0, n = TheTok.getLength(); i < n; ++i)
+ os << MacroName[i];
+ }
+
+ os << "':\n";
+
+ if (max > 1)
+ os << "</td></tr></table>";
+
+ // Within a macro piece. Write out each event.
+ ProcessMacroPiece(os, *MP, 0);
+ }
+ else {
+ os << html::EscapeText(P.getString());
+
+ if (max > 1)
+ os << "</td></tr></table>";
+ }
+
+ os << "</div></td></tr>";
+
+ // Insert the new html.
+ unsigned DisplayPos = LineEnd - FileStart;
+ SourceLocation Loc =
+ SM.getLocForStartOfFile(LPosInfo.first).getFileLocWithOffset(DisplayPos);
+
+ R.InsertStrBefore(Loc, os.str());
+
+ // Now highlight the ranges.
+ for (const SourceRange *I = P.ranges_begin(), *E = P.ranges_end();
+ I != E; ++I)
+ HighlightRange(R, LPosInfo.first, *I);
+
+#if 0
+ // If there is a code insertion hint, insert that code.
+ // FIXME: This code is disabled because it seems to mangle the HTML
+ // output. I'm leaving it here because it's generally the right idea,
+ // but needs some help from someone more familiar with the rewriter.
+ for (const CodeModificationHint *Hint = P.code_modifications_begin(),
+ *HintEnd = P.code_modifications_end();
+ Hint != HintEnd; ++Hint) {
+ if (Hint->RemoveRange.isValid()) {
+ HighlightRange(R, LPosInfo.first, Hint->RemoveRange,
+ "<span class=\"CodeRemovalHint\">", "</span>");
+ }
+ if (Hint->InsertionLoc.isValid()) {
+ std::string EscapedCode = html::EscapeText(Hint->CodeToInsert, true);
+ EscapedCode = "<span class=\"CodeInsertionHint\">" + EscapedCode
+ + "</span>";
+ R.InsertStrBefore(Hint->InsertionLoc, EscapedCode);
+ }
+ }
+#endif
+}
+
+static void EmitAlphaCounter(llvm::raw_ostream& os, unsigned n) {
+ llvm::SmallVector<char, 10> buf;
+
+ do {
+ unsigned x = n % ('z' - 'a');
+ buf.push_back('a' + x);
+ n = n / ('z' - 'a');
+ } while (n);
+
+ assert(!buf.empty());
+
+ for (llvm::SmallVectorImpl<char>::reverse_iterator I=buf.rbegin(),
+ E=buf.rend(); I!=E; ++I)
+ os << *I;
+}
+
+unsigned HTMLDiagnostics::ProcessMacroPiece(llvm::raw_ostream& os,
+ const PathDiagnosticMacroPiece& P,
+ unsigned num) {
+
+ for (PathDiagnosticMacroPiece::const_iterator I=P.begin(), E=P.end();
+ I!=E; ++I) {
+
+ if (const PathDiagnosticMacroPiece *MP =
+ dyn_cast<PathDiagnosticMacroPiece>(*I)) {
+ num = ProcessMacroPiece(os, *MP, num);
+ continue;
+ }
+
+ if (PathDiagnosticEventPiece *EP = dyn_cast<PathDiagnosticEventPiece>(*I)) {
+ os << "<div class=\"msg msgEvent\" style=\"width:94%; "
+ "margin-left:5px\">"
+ "<table class=\"msgT\"><tr>"
+ "<td valign=\"top\"><div class=\"PathIndex PathIndexEvent\">";
+ EmitAlphaCounter(os, num++);
+ os << "</div></td><td valign=\"top\">"
+ << html::EscapeText(EP->getString())
+ << "</td></tr></table></div>\n";
+ }
+ }
+
+ return num;
+}
+
+void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID,
+ SourceRange Range,
+ const char *HighlightStart,
+ const char *HighlightEnd) {
+ SourceManager &SM = R.getSourceMgr();
+ const LangOptions &LangOpts = R.getLangOpts();
+
+ SourceLocation InstantiationStart = SM.getInstantiationLoc(Range.getBegin());
+ unsigned StartLineNo = SM.getInstantiationLineNumber(InstantiationStart);
+
+ SourceLocation InstantiationEnd = SM.getInstantiationLoc(Range.getEnd());
+ unsigned EndLineNo = SM.getInstantiationLineNumber(InstantiationEnd);
+
+ if (EndLineNo < StartLineNo)
+ return;
+
+ if (SM.getFileID(InstantiationStart) != BugFileID ||
+ SM.getFileID(InstantiationEnd) != BugFileID)
+ return;
+
+ // Compute the column number of the end.
+ unsigned EndColNo = SM.getInstantiationColumnNumber(InstantiationEnd);
+ unsigned OldEndColNo = EndColNo;
+
+ if (EndColNo) {
+ // Add in the length of the token, so that we cover multi-char tokens.
+ EndColNo += Lexer::MeasureTokenLength(Range.getEnd(), SM, LangOpts)-1;
+ }
+
+ // Highlight the range. Make the span tag the outermost tag for the
+ // selected range.
+
+ SourceLocation E =
+ InstantiationEnd.getFileLocWithOffset(EndColNo - OldEndColNo);
+
+ html::HighlightRange(R, InstantiationStart, E, HighlightStart, HighlightEnd);
+}
diff --git a/lib/Frontend/HTMLPrint.cpp b/lib/Frontend/HTMLPrint.cpp
new file mode 100644
index 000000000000..d5eb9fb5313d
--- /dev/null
+++ b/lib/Frontend/HTMLPrint.cpp
@@ -0,0 +1,92 @@
+//===--- HTMLPrint.cpp - Source code -> HTML pretty-printing --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Pretty-printing of source code to HTML.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/Decl.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/HTMLRewrite.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Functional HTML pretty-printing.
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class HTMLPrinter : public ASTConsumer {
+ Rewriter R;
+ llvm::raw_ostream *Out;
+ Diagnostic &Diags;
+ Preprocessor *PP;
+ PreprocessorFactory *PPF;
+ public:
+ HTMLPrinter(llvm::raw_ostream *OS, Diagnostic &D, Preprocessor *pp,
+ PreprocessorFactory* ppf)
+ : Out(OS), Diags(D), PP(pp), PPF(ppf) {}
+ virtual ~HTMLPrinter();
+
+ void Initialize(ASTContext &context);
+ };
+}
+
+ASTConsumer* clang::CreateHTMLPrinter(llvm::raw_ostream *OS,
+ Diagnostic &D, Preprocessor *PP,
+ PreprocessorFactory* PPF) {
+
+ return new HTMLPrinter(OS, D, PP, PPF);
+}
+
+void HTMLPrinter::Initialize(ASTContext &context) {
+ R.setSourceMgr(context.getSourceManager(), context.getLangOptions());
+}
+
+HTMLPrinter::~HTMLPrinter() {
+ if (Diags.hasErrorOccurred())
+ return;
+
+ // Format the file.
+ FileID FID = R.getSourceMgr().getMainFileID();
+ const FileEntry* Entry = R.getSourceMgr().getFileEntryForID(FID);
+ const char* Name;
+ // In some cases, in particular the case where the input is from stdin,
+ // there is no entry. Fall back to the memory buffer for a name in those
+ // cases.
+ if (Entry)
+ Name = Entry->getName();
+ else
+ Name = R.getSourceMgr().getBuffer(FID)->getBufferIdentifier();
+
+ html::AddLineNumbers(R, FID);
+ html::AddHeaderFooterInternalBuiltinCSS(R, FID, Name);
+
+ // If we have a preprocessor, relex the file and syntax highlight.
+ // We might not have a preprocessor if we come from a deserialized AST file,
+ // for example.
+
+ if (PP) html::SyntaxHighlight(R, FID, *PP);
+ if (PPF) html::HighlightMacros(R, FID, *PP);
+ html::EscapeText(R, FID, false, true);
+
+ // Emit the HTML.
+ const RewriteBuffer &RewriteBuf = R.getEditBuffer(FID);
+ char *Buffer = (char*)malloc(RewriteBuf.size());
+ std::copy(RewriteBuf.begin(), RewriteBuf.end(), Buffer);
+ Out->write(Buffer, RewriteBuf.size());
+ free(Buffer);
+}
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
new file mode 100644
index 000000000000..6383c2076ba4
--- /dev/null
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -0,0 +1,327 @@
+//===--- InitHeaderSearch.cpp - Initialize header search paths ----------*-===//
+//
+// 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 InitHeaderSearch class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/InitHeaderSearch.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/System/Path.h"
+#include "llvm/Config/config.h"
+#include <cstdio>
+#include <vector>
+using namespace clang;
+
+void InitHeaderSearch::AddPath(const std::string &Path, IncludeDirGroup Group,
+ bool isCXXAware, bool isUserSupplied,
+ bool isFramework, bool IgnoreSysRoot) {
+ assert(!Path.empty() && "can't handle empty path here");
+ FileManager &FM = Headers.getFileMgr();
+
+ // Compute the actual path, taking into consideration -isysroot.
+ llvm::SmallString<256> MappedPath;
+
+ // Handle isysroot.
+ if (Group == System && !IgnoreSysRoot) {
+ // FIXME: Portability. This should be a sys::Path interface, this doesn't
+ // handle things like C:\ right, nor win32 \\network\device\blah.
+ if (isysroot.size() != 1 || isysroot[0] != '/') // Add isysroot if present.
+ MappedPath.append(isysroot.begin(), isysroot.end());
+ }
+
+ MappedPath.append(Path.begin(), Path.end());
+
+ // Compute the DirectoryLookup type.
+ SrcMgr::CharacteristicKind Type;
+ if (Group == Quoted || Group == Angled)
+ Type = SrcMgr::C_User;
+ else if (isCXXAware)
+ Type = SrcMgr::C_System;
+ else
+ Type = SrcMgr::C_ExternCSystem;
+
+
+ // If the directory exists, add it.
+ if (const DirectoryEntry *DE = FM.getDirectory(&MappedPath[0],
+ &MappedPath[0]+
+ MappedPath.size())) {
+ IncludeGroup[Group].push_back(DirectoryLookup(DE, Type, isUserSupplied,
+ isFramework));
+ return;
+ }
+
+ // Check to see if this is an apple-style headermap (which are not allowed to
+ // be frameworks).
+ if (!isFramework) {
+ if (const FileEntry *FE = FM.getFile(&MappedPath[0],
+ &MappedPath[0]+MappedPath.size())) {
+ if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) {
+ // It is a headermap, add it to the search path.
+ IncludeGroup[Group].push_back(DirectoryLookup(HM, Type,isUserSupplied));
+ return;
+ }
+ }
+ }
+
+ if (Verbose)
+ fprintf(stderr, "ignoring nonexistent directory \"%s\"\n",
+ MappedPath.c_str());
+}
+
+
+void InitHeaderSearch::AddEnvVarPaths(const char *Name) {
+ const char* at = getenv(Name);
+ if (!at || *at == 0) // Empty string should not add '.' path.
+ return;
+
+ const char* delim = strchr(at, llvm::sys::PathSeparator);
+ while (delim != 0) {
+ if (delim-at == 0)
+ AddPath(".", Angled, false, true, false);
+ else
+ AddPath(std::string(at, std::string::size_type(delim-at)), Angled, false,
+ true, false);
+ at = delim + 1;
+ delim = strchr(at, llvm::sys::PathSeparator);
+ }
+ if (*at == 0)
+ AddPath(".", Angled, false, true, false);
+ else
+ AddPath(at, Angled, false, true, false);
+}
+
+
+void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang) {
+ // FIXME: temporary hack: hard-coded paths.
+ // FIXME: get these from the target?
+
+#ifdef LLVM_ON_WIN32
+ if (Lang.CPlusPlus) {
+ // Mingw32 GCC version 4
+ AddPath("c:/mingw/lib/gcc/mingw32/4.3.0/include/c++",
+ System, true, false, false);
+ AddPath("c:/mingw/lib/gcc/mingw32/4.3.0/include/c++/mingw32",
+ System, true, false, false);
+ AddPath("c:/mingw/lib/gcc/mingw32/4.3.0/include/c++/backward",
+ System, true, false, false);
+ }
+
+ // Mingw32 GCC version 4
+ AddPath("C:/mingw/include", System, false, false, false);
+#else
+
+ if (Lang.CPlusPlus) {
+ AddPath("/usr/include/c++/4.2.1", System, true, false, false);
+ AddPath("/usr/include/c++/4.2.1/i686-apple-darwin10", System, true, false,
+ false);
+ AddPath("/usr/include/c++/4.2.1/backward", System, true, false, false);
+
+ AddPath("/usr/include/c++/4.0.0", System, true, false, false);
+ AddPath("/usr/include/c++/4.0.0/i686-apple-darwin8", System, true, false,
+ false);
+ AddPath("/usr/include/c++/4.0.0/backward", System, true, false, false);
+
+ // Ubuntu 7.10 - Gutsy Gibbon
+ AddPath("/usr/include/c++/4.1.3", System, true, false, false);
+ AddPath("/usr/include/c++/4.1.3/i486-linux-gnu", System, true, false,
+ false);
+ AddPath("/usr/include/c++/4.1.3/backward", System, true, false, false);
+
+ // Fedora 8
+ AddPath("/usr/include/c++/4.1.2", System, true, false, false);
+ AddPath("/usr/include/c++/4.1.2/i386-redhat-linux", System, true, false,
+ false);
+ AddPath("/usr/include/c++/4.1.2/backward", System, true, false, false);
+
+ // Fedora 9
+ AddPath("/usr/include/c++/4.3.0", System, true, false, false);
+ AddPath("/usr/include/c++/4.3.0/i386-redhat-linux", System, true, false,
+ false);
+ AddPath("/usr/include/c++/4.3.0/backward", System, true, false, false);
+
+ // Fedora 10
+ AddPath("/usr/include/c++/4.3.2", System, true, false, false);
+ AddPath("/usr/include/c++/4.3.2/i386-redhat-linux", System, true, false,
+ false);
+ AddPath("/usr/include/c++/4.3.2/backward", System, true, false, false);
+
+ // Arch Linux 2008-06-24
+ AddPath("/usr/include/c++/4.3.1", System, true, false, false);
+ AddPath("/usr/include/c++/4.3.1/i686-pc-linux-gnu", System, true, false,
+ false);
+ AddPath("/usr/include/c++/4.3.1/backward", System, true, false, false);
+ AddPath("/usr/include/c++/4.3.1/x86_64-unknown-linux-gnu", System, true,
+ false, false);
+
+ // Gentoo x86 stable
+ AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", System,
+ true, false, false);
+ AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4/"
+ "i686-pc-linux-gnu", System, true, false, false);
+ AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4/backward",
+ System, true, false, false);
+
+ // DragonFly
+ AddPath("/usr/include/c++/4.1", System, true, false, false);
+
+ // FreeBSD
+ AddPath("/usr/include/c++/4.2", System, true, false, false);
+ }
+
+ AddPath("/usr/local/include", System, false, false, false);
+
+ AddPath("/usr/include", System, false, false, false);
+ AddPath("/System/Library/Frameworks", System, true, false, true);
+ AddPath("/Library/Frameworks", System, true, false, true);
+#endif
+}
+
+void InitHeaderSearch::AddDefaultEnvVarPaths(const LangOptions &Lang) {
+ AddEnvVarPaths("CPATH");
+ if (Lang.CPlusPlus && Lang.ObjC1)
+ AddEnvVarPaths("OBJCPLUS_INCLUDE_PATH");
+ else if (Lang.CPlusPlus)
+ AddEnvVarPaths("CPLUS_INCLUDE_PATH");
+ else if (Lang.ObjC1)
+ AddEnvVarPaths("OBJC_INCLUDE_PATH");
+ else
+ AddEnvVarPaths("C_INCLUDE_PATH");
+}
+
+
+/// RemoveDuplicates - If there are duplicate directory entries in the specified
+/// search list, remove the later (dead) ones.
+static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
+ bool Verbose) {
+ llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs;
+ llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs;
+ llvm::SmallPtrSet<const HeaderMap *, 8> SeenHeaderMaps;
+ for (unsigned i = 0; i != SearchList.size(); ++i) {
+ unsigned DirToRemove = i;
+
+ const DirectoryLookup &CurEntry = SearchList[i];
+
+ if (CurEntry.isNormalDir()) {
+ // If this isn't the first time we've seen this dir, remove it.
+ if (SeenDirs.insert(CurEntry.getDir()))
+ continue;
+ } else if (CurEntry.isFramework()) {
+ // If this isn't the first time we've seen this framework dir, remove it.
+ if (SeenFrameworkDirs.insert(CurEntry.getFrameworkDir()))
+ continue;
+ } else {
+ assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");
+ // If this isn't the first time we've seen this headermap, remove it.
+ if (SeenHeaderMaps.insert(CurEntry.getHeaderMap()))
+ continue;
+ }
+
+ // If we have a normal #include dir/framework/headermap that is shadowed
+ // later in the chain by a system include location, we actually want to
+ // ignore the user's request and drop the user dir... keeping the system
+ // dir. This is weird, but required to emulate GCC's search path correctly.
+ //
+ // Since dupes of system dirs are rare, just rescan to find the original
+ // that we're nuking instead of using a DenseMap.
+ if (CurEntry.getDirCharacteristic() != SrcMgr::C_User) {
+ // Find the dir that this is the same of.
+ unsigned FirstDir;
+ for (FirstDir = 0; ; ++FirstDir) {
+ assert(FirstDir != i && "Didn't find dupe?");
+
+ const DirectoryLookup &SearchEntry = SearchList[FirstDir];
+
+ // If these are different lookup types, then they can't be the dupe.
+ if (SearchEntry.getLookupType() != CurEntry.getLookupType())
+ continue;
+
+ bool isSame;
+ if (CurEntry.isNormalDir())
+ isSame = SearchEntry.getDir() == CurEntry.getDir();
+ else if (CurEntry.isFramework())
+ isSame = SearchEntry.getFrameworkDir() == CurEntry.getFrameworkDir();
+ else {
+ assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");
+ isSame = SearchEntry.getHeaderMap() == CurEntry.getHeaderMap();
+ }
+
+ if (isSame)
+ break;
+ }
+
+ // If the first dir in the search path is a non-system dir, zap it
+ // instead of the system one.
+ if (SearchList[FirstDir].getDirCharacteristic() == SrcMgr::C_User)
+ DirToRemove = FirstDir;
+ }
+
+ if (Verbose) {
+ fprintf(stderr, "ignoring duplicate directory \"%s\"\n",
+ CurEntry.getName());
+ if (DirToRemove != i)
+ fprintf(stderr, " as it is a non-system directory that duplicates"
+ " a system directory\n");
+ }
+
+ // This is reached if the current entry is a duplicate. Remove the
+ // DirToRemove (usually the current dir).
+ SearchList.erase(SearchList.begin()+DirToRemove);
+ --i;
+ }
+}
+
+
+void InitHeaderSearch::Realize() {
+ // Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList.
+ std::vector<DirectoryLookup> SearchList;
+ SearchList = IncludeGroup[Angled];
+ SearchList.insert(SearchList.end(), IncludeGroup[System].begin(),
+ IncludeGroup[System].end());
+ SearchList.insert(SearchList.end(), IncludeGroup[After].begin(),
+ IncludeGroup[After].end());
+ RemoveDuplicates(SearchList, Verbose);
+ RemoveDuplicates(IncludeGroup[Quoted], Verbose);
+
+ // Prepend QUOTED list on the search list.
+ SearchList.insert(SearchList.begin(), IncludeGroup[Quoted].begin(),
+ IncludeGroup[Quoted].end());
+
+
+ bool DontSearchCurDir = false; // TODO: set to true if -I- is set?
+ Headers.SetSearchPaths(SearchList, IncludeGroup[Quoted].size(),
+ DontSearchCurDir);
+
+ // If verbose, print the list of directories that will be searched.
+ if (Verbose) {
+ fprintf(stderr, "#include \"...\" search starts here:\n");
+ unsigned QuotedIdx = IncludeGroup[Quoted].size();
+ for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {
+ if (i == QuotedIdx)
+ fprintf(stderr, "#include <...> search starts here:\n");
+ const char *Name = SearchList[i].getName();
+ const char *Suffix;
+ if (SearchList[i].isNormalDir())
+ Suffix = "";
+ else if (SearchList[i].isFramework())
+ Suffix = " (framework directory)";
+ else {
+ assert(SearchList[i].isHeaderMap() && "Unknown DirectoryLookup");
+ Suffix = " (headermap)";
+ }
+ fprintf(stderr, " %s%s\n", Name, Suffix);
+ }
+ fprintf(stderr, "End of search list.\n");
+ }
+}
+
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
new file mode 100644
index 000000000000..09450377600e
--- /dev/null
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -0,0 +1,495 @@
+//===--- InitPreprocessor.cpp - PP initialization code. ---------*- 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 clang::InitializePreprocessor function.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/InitPreprocessor.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/System/Path.h"
+
+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(std::vector<char> &Buf, const char *Macro,
+ const char *Command = "#define ") {
+ Buf.insert(Buf.end(), Command, Command+strlen(Command));
+ if (const char *Equal = strchr(Macro, '=')) {
+ // Turn the = into ' '.
+ Buf.insert(Buf.end(), Macro, Equal);
+ Buf.push_back(' ');
+
+ // Per GCC -D semantics, the macro ends at \n if it exists.
+ const char *End = strpbrk(Equal, "\n\r");
+ if (End) {
+ fprintf(stderr, "warning: macro '%s' contains embedded newline, text "
+ "after the newline is ignored.\n",
+ std::string(Macro, Equal).c_str());
+ } else {
+ End = Equal+strlen(Equal);
+ }
+
+ Buf.insert(Buf.end(), Equal+1, End);
+ } else {
+ // Push "macroname 1".
+ Buf.insert(Buf.end(), Macro, Macro+strlen(Macro));
+ Buf.push_back(' ');
+ Buf.push_back('1');
+ }
+ Buf.push_back('\n');
+}
+
+// Append a #undef line to Buf for Macro. Macro should be of the form XXX
+// and we emit "#undef XXX".
+static void UndefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) {
+ // Push "macroname".
+ const char *Command = "#undef ";
+ Buf.insert(Buf.end(), Command, Command+strlen(Command));
+ Buf.insert(Buf.end(), Macro, Macro+strlen(Macro));
+ Buf.push_back('\n');
+}
+
+/// Add the quoted name of an implicit include file.
+static void AddQuotedIncludePath(std::vector<char> &Buf,
+ const std::string &File) {
+ // Implicit include paths should be resolved relative to the current
+ // working directory first, and then use the regular header search
+ // mechanism. The proper way to handle this is to have the
+ // predefines buffer located at the current working directory, but
+ // it has not file entry. For now, workaround this by using an
+ // absolute path if we find the file here, and otherwise letting
+ // header search handle it.
+ llvm::sys::Path Path(File);
+ Path.makeAbsolute();
+ if (!Path.exists())
+ Path = File;
+
+ // Escape double quotes etc.
+ Buf.push_back('"');
+ std::string EscapedFile = Lexer::Stringify(Path.toString());
+ Buf.insert(Buf.end(), EscapedFile.begin(), EscapedFile.end());
+ Buf.push_back('"');
+}
+
+/// AddImplicitInclude - Add an implicit #include of the specified file to the
+/// predefines buffer.
+static void AddImplicitInclude(std::vector<char> &Buf,
+ const std::string &File) {
+ const char *Inc = "#include ";
+ Buf.insert(Buf.end(), Inc, Inc+strlen(Inc));
+ AddQuotedIncludePath(Buf, File);
+ Buf.push_back('\n');
+}
+
+static void AddImplicitIncludeMacros(std::vector<char> &Buf,
+ const std::string &File) {
+ const char *Inc = "#__include_macros ";
+ Buf.insert(Buf.end(), Inc, Inc+strlen(Inc));
+ AddQuotedIncludePath(Buf, File);
+ Buf.push_back('\n');
+ // Marker token to stop the __include_macros fetch loop.
+ const char *Marker = "##\n"; // ##?
+ Buf.insert(Buf.end(), Marker, Marker+strlen(Marker));
+}
+
+/// AddImplicitIncludePTH - Add an implicit #include using the original file
+/// used to generate a PTH cache.
+static void AddImplicitIncludePTH(std::vector<char> &Buf, Preprocessor &PP,
+ const std::string& ImplicitIncludePTH) {
+ PTHManager *P = PP.getPTHManager();
+ assert(P && "No PTHManager.");
+ const char *OriginalFile = P->getOriginalSourceFile();
+
+ if (!OriginalFile) {
+ assert(!ImplicitIncludePTH.empty());
+ fprintf(stderr, "error: PTH file '%s' does not designate an original "
+ "source header file for -include-pth\n",
+ ImplicitIncludePTH.c_str());
+ exit (1);
+ }
+
+ AddImplicitInclude(Buf, OriginalFile);
+}
+
+/// PickFP - This is used to pick a value based on the FP semantics of the
+/// specified FP model.
+template <typename T>
+static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal,
+ T IEEEDoubleVal, T X87DoubleExtendedVal, T PPCDoubleDoubleVal,
+ T IEEEQuadVal) {
+ if (Sem == &llvm::APFloat::IEEEsingle)
+ return IEEESingleVal;
+ if (Sem == &llvm::APFloat::IEEEdouble)
+ return IEEEDoubleVal;
+ if (Sem == &llvm::APFloat::x87DoubleExtended)
+ return X87DoubleExtendedVal;
+ if (Sem == &llvm::APFloat::PPCDoubleDouble)
+ return PPCDoubleDoubleVal;
+ assert(Sem == &llvm::APFloat::IEEEquad);
+ return IEEEQuadVal;
+}
+
+static void DefineFloatMacros(std::vector<char> &Buf, const char *Prefix,
+ const llvm::fltSemantics *Sem) {
+ const char *DenormMin, *Epsilon, *Max, *Min;
+ DenormMin = PickFP(Sem, "1.40129846e-45F", "4.9406564584124654e-324",
+ "3.64519953188247460253e-4951L",
+ "4.94065645841246544176568792868221e-324L",
+ "6.47517511943802511092443895822764655e-4966L");
+ int Digits = PickFP(Sem, 6, 15, 18, 31, 33);
+ Epsilon = PickFP(Sem, "1.19209290e-7F", "2.2204460492503131e-16",
+ "1.08420217248550443401e-19L",
+ "4.94065645841246544176568792868221e-324L",
+ "1.92592994438723585305597794258492732e-34L");
+ int HasInifinity = 1, HasQuietNaN = 1;
+ int MantissaDigits = PickFP(Sem, 24, 53, 64, 106, 113);
+ int Min10Exp = PickFP(Sem, -37, -307, -4931, -291, -4931);
+ int Max10Exp = PickFP(Sem, 38, 308, 4932, 308, 4932);
+ int MinExp = PickFP(Sem, -125, -1021, -16381, -968, -16381);
+ int MaxExp = PickFP(Sem, 128, 1024, 16384, 1024, 16384);
+ Min = PickFP(Sem, "1.17549435e-38F", "2.2250738585072014e-308",
+ "3.36210314311209350626e-4932L",
+ "2.00416836000897277799610805135016e-292L",
+ "3.36210314311209350626267781732175260e-4932L");
+ Max = PickFP(Sem, "3.40282347e+38F", "1.7976931348623157e+308",
+ "1.18973149535723176502e+4932L",
+ "1.79769313486231580793728971405301e+308L",
+ "1.18973149535723176508575932662800702e+4932L");
+
+ char MacroBuf[100];
+ sprintf(MacroBuf, "__%s_DENORM_MIN__=%s", Prefix, DenormMin);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_DIG__=%d", Prefix, Digits);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_EPSILON__=%s", Prefix, Epsilon);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_HAS_INFINITY__=%d", Prefix, HasInifinity);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_HAS_QUIET_NAN__=%d", Prefix, HasQuietNaN);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_MANT_DIG__=%d", Prefix, MantissaDigits);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_MAX_10_EXP__=%d", Prefix, Max10Exp);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_MAX_EXP__=%d", Prefix, MaxExp);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_MAX__=%s", Prefix, Max);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_MIN_10_EXP__=(%d)", Prefix, Min10Exp);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_MIN_EXP__=(%d)", Prefix, MinExp);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_MIN__=%s", Prefix, Min);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_HAS_DENORM__=1", Prefix);
+ DefineBuiltinMacro(Buf, MacroBuf);
+}
+
+
+/// 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(const char *MacroName, unsigned TypeWidth,
+ const char *ValSuffix, bool isSigned,
+ std::vector<char> &Buf) {
+ char MacroBuf[60];
+ long long MaxVal;
+ if (isSigned)
+ MaxVal = (1LL << (TypeWidth - 1)) - 1;
+ else
+ MaxVal = ~0LL >> (64-TypeWidth);
+
+ sprintf(MacroBuf, "%s=%llu%s", MacroName, MaxVal, ValSuffix);
+ DefineBuiltinMacro(Buf, MacroBuf);
+}
+
+static void DefineType(const char *MacroName, TargetInfo::IntType Ty,
+ std::vector<char> &Buf) {
+ char MacroBuf[60];
+ sprintf(MacroBuf, "%s=%s", MacroName, TargetInfo::getTypeName(Ty));
+ DefineBuiltinMacro(Buf, MacroBuf);
+}
+
+
+static void InitializePredefinedMacros(const TargetInfo &TI,
+ const LangOptions &LangOpts,
+ std::vector<char> &Buf) {
+ char MacroBuf[60];
+ // Compiler version introspection macros.
+ DefineBuiltinMacro(Buf, "__llvm__=1"); // LLVM Backend
+ DefineBuiltinMacro(Buf, "__clang__=1"); // Clang Frontend
+
+ // Currently claim to be compatible with GCC 4.2.1-5621.
+ DefineBuiltinMacro(Buf, "__APPLE_CC__=5621");
+ DefineBuiltinMacro(Buf, "__GNUC_MINOR__=2");
+ DefineBuiltinMacro(Buf, "__GNUC_PATCHLEVEL__=1");
+ DefineBuiltinMacro(Buf, "__GNUC__=4");
+ DefineBuiltinMacro(Buf, "__GXX_ABI_VERSION=1002");
+ DefineBuiltinMacro(Buf, "__VERSION__=\"4.2.1 Compatible Clang Compiler\"");
+
+
+ // Initialize language-specific preprocessor defines.
+
+ // These should all be defined in the preprocessor according to the
+ // current language configuration.
+ if (!LangOpts.Microsoft)
+ DefineBuiltinMacro(Buf, "__STDC__=1");
+ if (LangOpts.AsmPreprocessor)
+ DefineBuiltinMacro(Buf, "__ASSEMBLER__=1");
+ if (LangOpts.C99 && !LangOpts.CPlusPlus)
+ DefineBuiltinMacro(Buf, "__STDC_VERSION__=199901L");
+ else if (0) // STDC94 ?
+ DefineBuiltinMacro(Buf, "__STDC_VERSION__=199409L");
+
+ // Standard conforming mode?
+ if (!LangOpts.GNUMode)
+ DefineBuiltinMacro(Buf, "__STRICT_ANSI__=1");
+
+ if (LangOpts.CPlusPlus0x)
+ DefineBuiltinMacro(Buf, "__GXX_EXPERIMENTAL_CXX0X__");
+
+ if (LangOpts.Freestanding)
+ DefineBuiltinMacro(Buf, "__STDC_HOSTED__=0");
+ else
+ DefineBuiltinMacro(Buf, "__STDC_HOSTED__=1");
+
+ if (LangOpts.ObjC1) {
+ DefineBuiltinMacro(Buf, "__OBJC__=1");
+ if (LangOpts.ObjCNonFragileABI) {
+ DefineBuiltinMacro(Buf, "__OBJC2__=1");
+ DefineBuiltinMacro(Buf, "OBJC_ZEROCOST_EXCEPTIONS=1");
+ DefineBuiltinMacro(Buf, "__EXCEPTIONS=1");
+ }
+
+ if (LangOpts.getGCMode() != LangOptions::NonGC)
+ DefineBuiltinMacro(Buf, "__OBJC_GC__=1");
+
+ if (LangOpts.NeXTRuntime)
+ DefineBuiltinMacro(Buf, "__NEXT_RUNTIME__=1");
+ }
+
+ // darwin_constant_cfstrings controls this. This is also dependent
+ // on other things like the runtime I believe. This is set even for C code.
+ DefineBuiltinMacro(Buf, "__CONSTANT_CFSTRINGS__=1");
+
+ if (LangOpts.ObjC2)
+ DefineBuiltinMacro(Buf, "OBJC_NEW_PROPERTIES");
+
+ if (LangOpts.ObjCSenderDispatch)
+ DefineBuiltinMacro(Buf, "__OBJC_SENDER_AWARE_DISPATCH__");
+
+ if (LangOpts.PascalStrings)
+ DefineBuiltinMacro(Buf, "__PASCAL_STRINGS__");
+
+ if (LangOpts.Blocks) {
+ DefineBuiltinMacro(Buf, "__block=__attribute__((__blocks__(byref)))");
+ DefineBuiltinMacro(Buf, "__BLOCKS__=1");
+ }
+
+ if (LangOpts.CPlusPlus) {
+ DefineBuiltinMacro(Buf, "__DEPRECATED=1");
+ DefineBuiltinMacro(Buf, "__EXCEPTIONS=1");
+ DefineBuiltinMacro(Buf, "__GNUG__=4");
+ DefineBuiltinMacro(Buf, "__GXX_WEAK__=1");
+ DefineBuiltinMacro(Buf, "__cplusplus=1");
+ DefineBuiltinMacro(Buf, "__private_extern__=extern");
+ }
+
+ // Filter out some microsoft extensions when trying to parse in ms-compat
+ // mode.
+ if (LangOpts.Microsoft) {
+ DefineBuiltinMacro(Buf, "_cdecl=__cdecl");
+ DefineBuiltinMacro(Buf, "__int8=__INT8_TYPE__");
+ DefineBuiltinMacro(Buf, "__int16=__INT16_TYPE__");
+ DefineBuiltinMacro(Buf, "__int32=__INT32_TYPE__");
+ DefineBuiltinMacro(Buf, "__int64=__INT64_TYPE__");
+ }
+
+ if (LangOpts.Optimize)
+ DefineBuiltinMacro(Buf, "__OPTIMIZE__=1");
+ if (LangOpts.OptimizeSize)
+ DefineBuiltinMacro(Buf, "__OPTIMIZE_SIZE__=1");
+
+ // Initialize target-specific preprocessor defines.
+
+ // Define type sizing macros based on the target properties.
+ assert(TI.getCharWidth() == 8 && "Only support 8-bit char so far");
+ DefineBuiltinMacro(Buf, "__CHAR_BIT__=8");
+
+ unsigned IntMaxWidth;
+ const char *IntMaxSuffix;
+ if (TI.getIntMaxType() == TargetInfo::SignedLongLong) {
+ IntMaxWidth = TI.getLongLongWidth();
+ IntMaxSuffix = "LL";
+ } else if (TI.getIntMaxType() == TargetInfo::SignedLong) {
+ IntMaxWidth = TI.getLongWidth();
+ IntMaxSuffix = "L";
+ } else {
+ assert(TI.getIntMaxType() == TargetInfo::SignedInt);
+ IntMaxWidth = TI.getIntWidth();
+ IntMaxSuffix = "";
+ }
+
+ DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Buf);
+ DefineTypeSize("__SHRT_MAX__", TI.getShortWidth(), "", true, Buf);
+ DefineTypeSize("__INT_MAX__", TI.getIntWidth(), "", true, Buf);
+ DefineTypeSize("__LONG_MAX__", TI.getLongWidth(), "L", true, Buf);
+ DefineTypeSize("__LONG_LONG_MAX__", TI.getLongLongWidth(), "LL", true, Buf);
+ DefineTypeSize("__WCHAR_MAX__", TI.getWCharWidth(), "", true, Buf);
+ DefineTypeSize("__INTMAX_MAX__", IntMaxWidth, IntMaxSuffix, true, Buf);
+
+ DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Buf);
+ DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Buf);
+ DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Buf);
+ DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Buf);
+ DefineType("__SIZE_TYPE__", TI.getSizeType(), Buf);
+ DefineType("__WCHAR_TYPE__", TI.getWCharType(), Buf);
+ // FIXME: TargetInfo hookize __WINT_TYPE__.
+ DefineBuiltinMacro(Buf, "__WINT_TYPE__=int");
+
+ DefineFloatMacros(Buf, "FLT", &TI.getFloatFormat());
+ DefineFloatMacros(Buf, "DBL", &TI.getDoubleFormat());
+ DefineFloatMacros(Buf, "LDBL", &TI.getLongDoubleFormat());
+
+ // Define a __POINTER_WIDTH__ macro for stdint.h.
+ sprintf(MacroBuf, "__POINTER_WIDTH__=%d", (int)TI.getPointerWidth(0));
+ DefineBuiltinMacro(Buf, MacroBuf);
+
+ if (!TI.isCharSigned())
+ DefineBuiltinMacro(Buf, "__CHAR_UNSIGNED__");
+
+ // Define fixed-sized integer types for stdint.h
+ assert(TI.getCharWidth() == 8 && "unsupported target types");
+ assert(TI.getShortWidth() == 16 && "unsupported target types");
+ DefineBuiltinMacro(Buf, "__INT8_TYPE__=char");
+ DefineBuiltinMacro(Buf, "__INT16_TYPE__=short");
+
+ if (TI.getIntWidth() == 32)
+ DefineBuiltinMacro(Buf, "__INT32_TYPE__=int");
+ else {
+ assert(TI.getLongLongWidth() == 32 && "unsupported target types");
+ DefineBuiltinMacro(Buf, "__INT32_TYPE__=long long");
+ }
+
+ // 16-bit targets doesn't necessarily have a 64-bit type.
+ if (TI.getLongLongWidth() == 64)
+ DefineBuiltinMacro(Buf, "__INT64_TYPE__=long long");
+
+ // Add __builtin_va_list typedef.
+ {
+ const char *VAList = TI.getVAListDeclaration();
+ Buf.insert(Buf.end(), VAList, VAList+strlen(VAList));
+ Buf.push_back('\n');
+ }
+
+ if (const char *Prefix = TI.getUserLabelPrefix()) {
+ sprintf(MacroBuf, "__USER_LABEL_PREFIX__=%s", Prefix);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ }
+
+ // Build configuration options. FIXME: these should be controlled by
+ // command line options or something.
+ DefineBuiltinMacro(Buf, "__FINITE_MATH_ONLY__=0");
+
+ if (LangOpts.Static)
+ DefineBuiltinMacro(Buf, "__STATIC__=1");
+ else
+ DefineBuiltinMacro(Buf, "__DYNAMIC__=1");
+
+ if (LangOpts.GNUInline)
+ DefineBuiltinMacro(Buf, "__GNUC_GNU_INLINE__=1");
+ else
+ DefineBuiltinMacro(Buf, "__GNUC_STDC_INLINE__=1");
+
+ if (LangOpts.NoInline)
+ DefineBuiltinMacro(Buf, "__NO_INLINE__=1");
+
+ if (unsigned PICLevel = LangOpts.PICLevel) {
+ sprintf(MacroBuf, "__PIC__=%d", PICLevel);
+ DefineBuiltinMacro(Buf, MacroBuf);
+
+ sprintf(MacroBuf, "__pic__=%d", PICLevel);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ }
+
+ // Macros to control C99 numerics and <float.h>
+ DefineBuiltinMacro(Buf, "__FLT_EVAL_METHOD__=0");
+ DefineBuiltinMacro(Buf, "__FLT_RADIX__=2");
+ sprintf(MacroBuf, "__DECIMAL_DIG__=%d",
+ PickFP(&TI.getLongDoubleFormat(), -1/*FIXME*/, 17, 21, 33, 36));
+ DefineBuiltinMacro(Buf, MacroBuf);
+
+ // Get other target #defines.
+ TI.getTargetDefines(LangOpts, Buf);
+}
+
+/// InitializePreprocessor - Initialize the preprocessor getting it and the
+/// environment ready to process a single file. This returns true on error.
+///
+bool InitializePreprocessor(Preprocessor &PP,
+ const PreprocessorInitOptions& InitOpts) {
+ std::vector<char> PredefineBuffer;
+
+ const char *LineDirective = "# 1 \"<built-in>\" 3\n";
+ PredefineBuffer.insert(PredefineBuffer.end(),
+ LineDirective, LineDirective+strlen(LineDirective));
+
+ // Install things like __POWERPC__, __GNUC__, etc into the macro table.
+ InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(),
+ PredefineBuffer);
+
+ // Add on the predefines from the driver. Wrap in a #line directive to report
+ // that they come from the command line.
+ LineDirective = "# 1 \"<command line>\" 1\n";
+ PredefineBuffer.insert(PredefineBuffer.end(),
+ LineDirective, LineDirective+strlen(LineDirective));
+
+ // Process #define's and #undef's in the order they are given.
+ for (PreprocessorInitOptions::macro_iterator I = InitOpts.macro_begin(),
+ E = InitOpts.macro_end(); I != E; ++I) {
+ if (I->second) // isUndef
+ UndefineBuiltinMacro(PredefineBuffer, I->first.c_str());
+ else
+ DefineBuiltinMacro(PredefineBuffer, I->first.c_str());
+ }
+
+ // If -imacros are specified, include them now. These are processed before
+ // any -include directives.
+ for (PreprocessorInitOptions::imacro_iterator I = InitOpts.imacro_begin(),
+ E = InitOpts.imacro_end(); I != E; ++I)
+ AddImplicitIncludeMacros(PredefineBuffer, *I);
+
+ // Process -include directives.
+ for (PreprocessorInitOptions::include_iterator I = InitOpts.include_begin(),
+ E = InitOpts.include_end(); I != E; ++I) {
+ if (I->second) // isPTH
+ AddImplicitIncludePTH(PredefineBuffer, PP, I->first);
+ else
+ AddImplicitInclude(PredefineBuffer, I->first);
+ }
+
+ LineDirective = "# 2 \"<built-in>\" 2 3\n";
+ PredefineBuffer.insert(PredefineBuffer.end(),
+ LineDirective, LineDirective+strlen(LineDirective));
+
+ // Null terminate PredefinedBuffer and add it.
+ PredefineBuffer.push_back(0);
+ PP.setPredefines(&PredefineBuffer[0]);
+
+ // Once we've read this, we're done.
+ return false;
+}
+
+} // namespace clang
diff --git a/lib/Frontend/Makefile b/lib/Frontend/Makefile
new file mode 100644
index 000000000000..8d708475783f
--- /dev/null
+++ b/lib/Frontend/Makefile
@@ -0,0 +1,18 @@
+##===- clang/lib/Frontend/Makefile -------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+LIBRARYNAME := clangFrontend
+BUILD_ARCHIVE = 1
+CXXFLAGS = -fno-rtti
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/Frontend/ManagerRegistry.cpp b/lib/Frontend/ManagerRegistry.cpp
new file mode 100644
index 000000000000..79f1e8178e10
--- /dev/null
+++ b/lib/Frontend/ManagerRegistry.cpp
@@ -0,0 +1,20 @@
+//===- ManagerRegistry.cpp - Pluggble Analyzer module creators --*- 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 pluggable analyzer module creators.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ManagerRegistry.h"
+
+using namespace clang;
+
+StoreManagerCreator ManagerRegistry::StoreMgrCreator = 0;
+
+ConstraintManagerCreator ManagerRegistry::ConstraintMgrCreator = 0;
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
new file mode 100644
index 000000000000..63e4337c8861
--- /dev/null
+++ b/lib/Frontend/PCHReader.cpp
@@ -0,0 +1,2260 @@
+//===--- PCHReader.cpp - Precompiled Headers Reader -------------*- 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 PCHReader class, which reads a precompiled header.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PCHReader.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "../Sema/Sema.h" // FIXME: move Sema headers elsewhere
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/SourceManagerInternals.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <algorithm>
+#include <iterator>
+#include <cstdio>
+#include <sys/stat.h>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// PCH reader implementation
+//===----------------------------------------------------------------------===//
+
+PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context)
+ : SemaObj(0), PP(PP), Context(Context), Consumer(0),
+ IdentifierTableData(0), IdentifierLookupTable(0),
+ IdentifierOffsets(0),
+ MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
+ TotalSelectorsInMethodPool(0), SelectorOffsets(0),
+ TotalNumSelectors(0), NumStatHits(0), NumStatMisses(0),
+ NumSLocEntriesRead(0), NumStatementsRead(0),
+ NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
+ NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0) { }
+
+PCHReader::~PCHReader() {}
+
+Expr *PCHReader::ReadDeclExpr() {
+ return dyn_cast_or_null<Expr>(ReadStmt(DeclsCursor));
+}
+
+Expr *PCHReader::ReadTypeExpr() {
+ return dyn_cast_or_null<Expr>(ReadStmt(Stream));
+}
+
+
+namespace {
+class VISIBILITY_HIDDEN PCHMethodPoolLookupTrait {
+ PCHReader &Reader;
+
+public:
+ typedef std::pair<ObjCMethodList, ObjCMethodList> data_type;
+
+ typedef Selector external_key_type;
+ typedef external_key_type internal_key_type;
+
+ explicit PCHMethodPoolLookupTrait(PCHReader &Reader) : Reader(Reader) { }
+
+ static bool EqualKey(const internal_key_type& a,
+ const internal_key_type& b) {
+ return a == b;
+ }
+
+ static unsigned ComputeHash(Selector Sel) {
+ unsigned N = Sel.getNumArgs();
+ if (N == 0)
+ ++N;
+ unsigned R = 5381;
+ for (unsigned I = 0; I != N; ++I)
+ if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I))
+ R = clang::BernsteinHashPartial(II->getName(), II->getLength(), R);
+ return R;
+ }
+
+ // This hopefully will just get inlined and removed by the optimizer.
+ static const internal_key_type&
+ GetInternalKey(const external_key_type& x) { return x; }
+
+ 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);
+ }
+
+ 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);
+
+ llvm::SmallVector<IdentifierInfo *, 16> Args;
+ Args.push_back(FirstII);
+ for (unsigned I = 1; I != N; ++I)
+ Args.push_back(Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d)));
+
+ return SelTable.getSelector(N, Args.data());
+ }
+
+ data_type ReadData(Selector, const unsigned char* d, unsigned DataLen) {
+ using namespace clang::io;
+ unsigned NumInstanceMethods = ReadUnalignedLE16(d);
+ unsigned NumFactoryMethods = ReadUnalignedLE16(d);
+
+ data_type Result;
+
+ // Load instance methods
+ ObjCMethodList *Prev = 0;
+ for (unsigned I = 0; I != NumInstanceMethods; ++I) {
+ ObjCMethodDecl *Method
+ = cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d)));
+ if (!Result.first.Method) {
+ // This is the first method, which is the easy case.
+ Result.first.Method = Method;
+ Prev = &Result.first;
+ continue;
+ }
+
+ Prev->Next = new 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.second.Method) {
+ // This is the first method, which is the easy case.
+ Result.second.Method = Method;
+ Prev = &Result.second;
+ continue;
+ }
+
+ Prev->Next = new ObjCMethodList(Method, 0);
+ Prev = Prev->Next;
+ }
+
+ return Result;
+ }
+};
+
+} // end anonymous namespace
+
+/// \brief The on-disk hash table used for the global method pool.
+typedef OnDiskChainedHashTable<PCHMethodPoolLookupTrait>
+ PCHMethodPoolLookupTable;
+
+namespace {
+class VISIBILITY_HIDDEN PCHIdentifierLookupTrait {
+ PCHReader &Reader;
+
+ // 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 PCH 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;
+
+ explicit PCHIdentifierLookupTrait(PCHReader &Reader, IdentifierInfo *II = 0)
+ : Reader(Reader), 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) {
+ return BernsteinHash(a.first, a.second);
+ }
+
+ // This hopefully will just get inlined and removed by the optimizer.
+ static const internal_key_type&
+ GetInternalKey(const external_key_type& x) { return x; }
+
+ 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);
+ }
+
+ 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;
+ pch::IdentID ID = ReadUnalignedLE32(d);
+ bool IsInteresting = ID & 0x01;
+
+ // Wipe out the "is interesting" bit.
+ ID = ID >> 1;
+
+ if (!IsInteresting) {
+ // For unintersting identifiers, just build the IdentifierInfo
+ // and associate it with the persistent ID.
+ IdentifierInfo *II = KnownII;
+ if (!II)
+ II = &Reader.getIdentifierTable().CreateIdentifierInfo(
+ k.first, k.first + k.second);
+ Reader.SetIdentifierInfo(ID, II);
+ return II;
+ }
+
+ unsigned Bits = ReadUnalignedLE16(d);
+ bool CPlusPlusOperatorKeyword = 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().CreateIdentifierInfo(
+ k.first, k.first + k.second);
+ Reader.SetIdentifierInfo(ID, II);
+
+ // Set or check the various bits in the IdentifierInfo structure.
+ // FIXME: Load token IDs lazily, too?
+ 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.ReadMacroRecord(Offset);
+ DataLen -= 4;
+ }
+
+ // Read all of the declarations visible at global scope with this
+ // name.
+ Sema *SemaObj = Reader.getSema();
+ if (Reader.getContext() == 0) return II;
+
+ while (DataLen > 0) {
+ NamedDecl *D = cast<NamedDecl>(Reader.GetDecl(ReadUnalignedLE32(d)));
+ if (SemaObj) {
+ // Introduce this declaration into the translation-unit scope
+ // and add it to the declaration chain for this identifier, so
+ // that (unqualified) name lookup will find it.
+ SemaObj->TUScope->AddDecl(Action::DeclPtrTy::make(D));
+ SemaObj->IdResolver.AddDeclToIdentifierChain(II, D);
+ } else {
+ // Queue this declaration so that it will be added to the
+ // translation unit scope and identifier's declaration chain
+ // once a Sema object is known.
+ Reader.PreloadedDecls.push_back(D);
+ }
+
+ DataLen -= 4;
+ }
+ 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<PCHIdentifierLookupTrait>
+ PCHIdentifierLookupTable;
+
+// FIXME: use the diagnostics machinery
+bool PCHReader::Error(const char *Msg) {
+ Diagnostic &Diags = PP.getDiagnostics();
+ unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Fatal, Msg);
+ Diag(DiagID);
+ return true;
+}
+
+/// \brief Split the given string into a vector of lines, eliminating
+/// any empty lines in the process.
+///
+/// \param Str the string to split.
+/// \param Len the length of Str.
+/// \param KeepEmptyLines true if empty lines should be included
+/// \returns a vector of lines, with the line endings removed
+std::vector<std::string> splitLines(const char *Str, unsigned Len,
+ bool KeepEmptyLines = false) {
+ std::vector<std::string> Lines;
+ for (unsigned LineStart = 0; LineStart < Len; ++LineStart) {
+ unsigned LineEnd = LineStart;
+ while (LineEnd < Len && Str[LineEnd] != '\n')
+ ++LineEnd;
+ if (LineStart != LineEnd || KeepEmptyLines)
+ Lines.push_back(std::string(&Str[LineStart], &Str[LineEnd]));
+ LineStart = LineEnd;
+ }
+ return Lines;
+}
+
+/// \brief Determine whether the string Haystack starts with the
+/// substring Needle.
+static bool startsWith(const std::string &Haystack, const char *Needle) {
+ for (unsigned I = 0, N = Haystack.size(); Needle[I] != 0; ++I) {
+ if (I == N)
+ return false;
+ if (Haystack[I] != Needle[I])
+ return false;
+ }
+
+ return true;
+}
+
+/// \brief Determine whether the string Haystack starts with the
+/// substring Needle.
+static inline bool startsWith(const std::string &Haystack,
+ const std::string &Needle) {
+ return startsWith(Haystack, Needle.c_str());
+}
+
+/// \brief Check the contents of the predefines buffer against the
+/// contents of the predefines buffer used to build the PCH file.
+///
+/// The contents of the two predefines buffers should be the same. If
+/// not, then some command-line option changed the preprocessor state
+/// and we must reject the PCH file.
+///
+/// \param PCHPredef The start of the predefines buffer in the PCH
+/// file.
+///
+/// \param PCHPredefLen The length of the predefines buffer in the PCH
+/// file.
+///
+/// \param PCHBufferID The FileID for the PCH predefines buffer.
+///
+/// \returns true if there was a mismatch (in which case the PCH file
+/// should be ignored), or false otherwise.
+bool PCHReader::CheckPredefinesBuffer(const char *PCHPredef,
+ unsigned PCHPredefLen,
+ FileID PCHBufferID) {
+ const char *Predef = PP.getPredefines().c_str();
+ unsigned PredefLen = PP.getPredefines().size();
+
+ // If the two predefines buffers compare equal, we're done!
+ if (PredefLen == PCHPredefLen &&
+ strncmp(Predef, PCHPredef, PCHPredefLen) == 0)
+ return false;
+
+ SourceManager &SourceMgr = PP.getSourceManager();
+
+ // The predefines buffers are different. Determine what the
+ // differences are, and whether they require us to reject the PCH
+ // file.
+ std::vector<std::string> CmdLineLines = splitLines(Predef, PredefLen);
+ std::vector<std::string> PCHLines = splitLines(PCHPredef, PCHPredefLen);
+
+ // Sort both sets of predefined buffer lines, since
+ std::sort(CmdLineLines.begin(), CmdLineLines.end());
+ std::sort(PCHLines.begin(), PCHLines.end());
+
+ // Determine which predefines that where used to build the PCH file
+ // are missing from the command line.
+ std::vector<std::string> MissingPredefines;
+ std::set_difference(PCHLines.begin(), PCHLines.end(),
+ CmdLineLines.begin(), CmdLineLines.end(),
+ std::back_inserter(MissingPredefines));
+
+ bool MissingDefines = false;
+ bool ConflictingDefines = false;
+ for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) {
+ const std::string &Missing = MissingPredefines[I];
+ if (!startsWith(Missing, "#define ") != 0) {
+ Diag(diag::warn_pch_compiler_options_mismatch);
+ return true;
+ }
+
+ // This is a macro definition. Determine the name of the macro
+ // we're defining.
+ std::string::size_type StartOfMacroName = strlen("#define ");
+ std::string::size_type EndOfMacroName
+ = Missing.find_first_of("( \n\r", StartOfMacroName);
+ assert(EndOfMacroName != std::string::npos &&
+ "Couldn't find the end of the macro name");
+ std::string MacroName = Missing.substr(StartOfMacroName,
+ EndOfMacroName - StartOfMacroName);
+
+ // Determine whether this macro was given a different definition
+ // on the command line.
+ std::string MacroDefStart = "#define " + MacroName;
+ std::string::size_type MacroDefLen = MacroDefStart.size();
+ std::vector<std::string>::iterator ConflictPos
+ = std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(),
+ MacroDefStart);
+ for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) {
+ if (!startsWith(*ConflictPos, MacroDefStart)) {
+ // Different macro; we're done.
+ ConflictPos = CmdLineLines.end();
+ break;
+ }
+
+ assert(ConflictPos->size() > MacroDefLen &&
+ "Invalid #define in predefines buffer?");
+ if ((*ConflictPos)[MacroDefLen] != ' ' &&
+ (*ConflictPos)[MacroDefLen] != '(')
+ continue; // Longer macro name; keep trying.
+
+ // We found a conflicting macro definition.
+ break;
+ }
+
+ if (ConflictPos != CmdLineLines.end()) {
+ Diag(diag::warn_cmdline_conflicting_macro_def)
+ << MacroName;
+
+ // Show the definition of this macro within the PCH file.
+ const char *MissingDef = strstr(PCHPredef, Missing.c_str());
+ unsigned Offset = MissingDef - PCHPredef;
+ SourceLocation PCHMissingLoc
+ = SourceMgr.getLocForStartOfFile(PCHBufferID)
+ .getFileLocWithOffset(Offset);
+ Diag(PCHMissingLoc, diag::note_pch_macro_defined_as)
+ << MacroName;
+
+ ConflictingDefines = true;
+ continue;
+ }
+
+ // If the macro doesn't conflict, then we'll just pick up the
+ // macro definition from the PCH file. Warn the user that they
+ // made a mistake.
+ if (ConflictingDefines)
+ continue; // Don't complain if there are already conflicting defs
+
+ if (!MissingDefines) {
+ Diag(diag::warn_cmdline_missing_macro_defs);
+ MissingDefines = true;
+ }
+
+ // Show the definition of this macro within the PCH file.
+ const char *MissingDef = strstr(PCHPredef, Missing.c_str());
+ unsigned Offset = MissingDef - PCHPredef;
+ SourceLocation PCHMissingLoc
+ = SourceMgr.getLocForStartOfFile(PCHBufferID)
+ .getFileLocWithOffset(Offset);
+ Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch);
+ }
+
+ if (ConflictingDefines)
+ return true;
+
+ // Determine what predefines were introduced based on command-line
+ // parameters that were not present when building the PCH
+ // file. Extra #defines are okay, so long as the identifiers being
+ // defined were not used within the precompiled header.
+ std::vector<std::string> 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) {
+ const std::string &Extra = ExtraPredefines[I];
+ if (!startsWith(Extra, "#define ") != 0) {
+ Diag(diag::warn_pch_compiler_options_mismatch);
+ return true;
+ }
+
+ // This is an extra macro definition. Determine the name of the
+ // macro we're defining.
+ std::string::size_type StartOfMacroName = strlen("#define ");
+ std::string::size_type EndOfMacroName
+ = Extra.find_first_of("( \n\r", StartOfMacroName);
+ assert(EndOfMacroName != std::string::npos &&
+ "Couldn't find the end of the macro name");
+ std::string MacroName = Extra.substr(StartOfMacroName,
+ EndOfMacroName - StartOfMacroName);
+
+ // Check whether this name was used somewhere in the PCH file. If
+ // so, defining it as a macro could change behavior, so we reject
+ // the PCH file.
+ if (IdentifierInfo *II = get(MacroName.c_str(),
+ MacroName.c_str() + MacroName.size())) {
+ Diag(diag::warn_macro_name_used_in_pch)
+ << II;
+ return true;
+ }
+
+ // Add this definition to the suggested predefines buffer.
+ SuggestedPredefines += Extra;
+ SuggestedPredefines += '\n';
+ }
+
+ // If we get here, it's because the predefines buffer had compatible
+ // contents. Accept the PCH file.
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Source Manager Deserialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Read the line table in the source manager block.
+/// \returns true if ther was an error.
+static bool ParseLineTable(SourceManager &SourceMgr,
+ llvm::SmallVectorImpl<uint64_t> &Record) {
+ unsigned Idx = 0;
+ LineTableInfo &LineTable = SourceMgr.getLineTable();
+
+ // Parse the file names
+ std::map<int, int> FileIDs;
+ for (int I = 0, N = Record[Idx++]; I != N; ++I) {
+ // Extract the file name
+ unsigned FilenameLen = Record[Idx++];
+ std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen);
+ Idx += FilenameLen;
+ FileIDs[I] = LineTable.getLineTableFilenameID(Filename.c_str(),
+ Filename.size());
+ }
+
+ // Parse the line entries
+ std::vector<LineEntry> Entries;
+ while (Idx < Record.size()) {
+ int FID = FileIDs[Record[Idx++]];
+
+ // Extract the line entries
+ unsigned NumEntries = Record[Idx++];
+ Entries.clear();
+ Entries.reserve(NumEntries);
+ for (unsigned I = 0; I != NumEntries; ++I) {
+ unsigned FileOffset = Record[Idx++];
+ unsigned LineNo = Record[Idx++];
+ int FilenameID = Record[Idx++];
+ SrcMgr::CharacteristicKind FileKind
+ = (SrcMgr::CharacteristicKind)Record[Idx++];
+ unsigned IncludeOffset = Record[Idx++];
+ Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID,
+ FileKind, IncludeOffset));
+ }
+ LineTable.AddEntry(FID, Entries);
+ }
+
+ return false;
+}
+
+namespace {
+
+class VISIBILITY_HIDDEN PCHStatData {
+public:
+ const bool hasStat;
+ const ino_t ino;
+ const dev_t dev;
+ const mode_t mode;
+ const time_t mtime;
+ const off_t size;
+
+ PCHStatData(ino_t i, dev_t d, mode_t mo, time_t m, off_t s)
+ : hasStat(true), ino(i), dev(d), mode(mo), mtime(m), size(s) {}
+
+ PCHStatData()
+ : hasStat(false), ino(0), dev(0), mode(0), mtime(0), size(0) {}
+};
+
+class VISIBILITY_HIDDEN PCHStatLookupTrait {
+ public:
+ typedef const char *external_key_type;
+ typedef const char *internal_key_type;
+
+ typedef PCHStatData data_type;
+
+ static unsigned ComputeHash(const char *path) {
+ return BernsteinHash(path);
+ }
+
+ static internal_key_type GetInternalKey(const char *path) { return path; }
+
+ static bool EqualKey(internal_key_type a, internal_key_type b) {
+ return strcmp(a, b) == 0;
+ }
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d) {
+ unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
+ unsigned DataLen = (unsigned) *d++;
+ return std::make_pair(KeyLen + 1, DataLen);
+ }
+
+ static internal_key_type ReadKey(const unsigned char *d, unsigned) {
+ return (const char *)d;
+ }
+
+ static data_type ReadData(const internal_key_type, const unsigned char *d,
+ unsigned /*DataLen*/) {
+ using namespace clang::io;
+
+ if (*d++ == 1)
+ return data_type();
+
+ ino_t ino = (ino_t) ReadUnalignedLE32(d);
+ dev_t dev = (dev_t) ReadUnalignedLE32(d);
+ mode_t mode = (mode_t) ReadUnalignedLE16(d);
+ time_t mtime = (time_t) ReadUnalignedLE64(d);
+ off_t size = (off_t) ReadUnalignedLE64(d);
+ return data_type(ino, dev, mode, mtime, size);
+ }
+};
+
+/// \brief stat() cache for precompiled headers.
+///
+/// This cache is very similar to the stat cache used by pretokenized
+/// headers.
+class VISIBILITY_HIDDEN PCHStatCache : public StatSysCallCache {
+ typedef OnDiskChainedHashTable<PCHStatLookupTrait> CacheTy;
+ CacheTy *Cache;
+
+ unsigned &NumStatHits, &NumStatMisses;
+public:
+ PCHStatCache(const unsigned char *Buckets,
+ const unsigned char *Base,
+ unsigned &NumStatHits,
+ unsigned &NumStatMisses)
+ : Cache(0), NumStatHits(NumStatHits), NumStatMisses(NumStatMisses) {
+ Cache = CacheTy::Create(Buckets, Base);
+ }
+
+ ~PCHStatCache() { delete Cache; }
+
+ int stat(const char *path, struct stat *buf) {
+ // Do the lookup for the file's data in the PCH file.
+ CacheTy::iterator I = Cache->find(path);
+
+ // If we don't get a hit in the PCH file just forward to 'stat'.
+ if (I == Cache->end()) {
+ ++NumStatMisses;
+ return ::stat(path, buf);
+ }
+
+ ++NumStatHits;
+ PCHStatData Data = *I;
+
+ if (!Data.hasStat)
+ return 1;
+
+ buf->st_ino = Data.ino;
+ buf->st_dev = Data.dev;
+ buf->st_mtime = Data.mtime;
+ buf->st_mode = Data.mode;
+ buf->st_size = Data.size;
+ return 0;
+ }
+};
+} // end anonymous namespace
+
+
+/// \brief Read the source manager block
+PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() {
+ using namespace SrcMgr;
+
+ // Set the source-location entry cursor to the current position in
+ // the stream. This cursor will be used to read the contents of the
+ // source manager block initially, and then lazily read
+ // source-location entries as needed.
+ SLocEntryCursor = Stream;
+
+ // The stream itself is going to skip over the source manager block.
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+
+ // Enter the source manager block.
+ if (SLocEntryCursor.EnterSubBlock(pch::SOURCE_MANAGER_BLOCK_ID)) {
+ Error("malformed source manager block record in PCH file");
+ return Failure;
+ }
+
+ SourceManager &SourceMgr = PP.getSourceManager();
+ RecordData Record;
+ unsigned NumHeaderInfos = 0;
+ while (true) {
+ unsigned Code = SLocEntryCursor.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (SLocEntryCursor.ReadBlockEnd()) {
+ Error("error at end of Source Manager block in PCH file");
+ return Failure;
+ }
+ return Success;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ SLocEntryCursor.ReadSubBlockID();
+ if (SLocEntryCursor.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ SLocEntryCursor.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ const char *BlobStart;
+ unsigned BlobLen;
+ Record.clear();
+ switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case pch::SM_LINE_TABLE:
+ if (ParseLineTable(SourceMgr, Record))
+ return Failure;
+ break;
+
+ case pch::SM_HEADER_FILE_INFO: {
+ HeaderFileInfo HFI;
+ HFI.isImport = Record[0];
+ HFI.DirInfo = Record[1];
+ HFI.NumIncludes = Record[2];
+ HFI.ControllingMacroID = Record[3];
+ PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
+ break;
+ }
+
+ case pch::SM_SLOC_FILE_ENTRY:
+ case pch::SM_SLOC_BUFFER_ENTRY:
+ case pch::SM_SLOC_INSTANTIATION_ENTRY:
+ // Once we hit one of the source location entries, we're done.
+ return Success;
+ }
+ }
+}
+
+/// \brief Read in the source location entry with the given ID.
+PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
+ if (ID == 0)
+ return Success;
+
+ if (ID > TotalNumSLocEntries) {
+ Error("source location entry ID out-of-range for PCH file");
+ return Failure;
+ }
+
+ ++NumSLocEntriesRead;
+ SLocEntryCursor.JumpToBit(SLocOffsets[ID - 1]);
+ 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 PCH file");
+ return Failure;
+ }
+
+ SourceManager &SourceMgr = PP.getSourceManager();
+ RecordData Record;
+ const char *BlobStart;
+ unsigned BlobLen;
+ switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default:
+ Error("incorrectly-formatted source location entry in PCH file");
+ return Failure;
+
+ case pch::SM_SLOC_FILE_ENTRY: {
+ const FileEntry *File
+ = PP.getFileManager().getFile(BlobStart, BlobStart + BlobLen);
+ // FIXME: Error recovery if file cannot be found.
+ FileID FID = SourceMgr.createFileID(File,
+ SourceLocation::getFromRawEncoding(Record[1]),
+ (SrcMgr::CharacteristicKind)Record[2],
+ ID, Record[0]);
+ if (Record[3])
+ const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile())
+ .setHasLineDirectives();
+
+ break;
+ }
+
+ case pch::SM_SLOC_BUFFER_ENTRY: {
+ const char *Name = BlobStart;
+ unsigned Offset = Record[0];
+ unsigned Code = SLocEntryCursor.ReadCode();
+ Record.clear();
+ unsigned RecCode
+ = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
+ assert(RecCode == pch::SM_SLOC_BUFFER_BLOB && "Ill-formed PCH file");
+ (void)RecCode;
+ llvm::MemoryBuffer *Buffer
+ = llvm::MemoryBuffer::getMemBuffer(BlobStart,
+ BlobStart + BlobLen - 1,
+ Name);
+ FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID, Offset);
+
+ if (strcmp(Name, "<built-in>") == 0) {
+ PCHPredefinesBufferID = BufferID;
+ PCHPredefines = BlobStart;
+ PCHPredefinesLen = BlobLen - 1;
+ }
+
+ break;
+ }
+
+ case pch::SM_SLOC_INSTANTIATION_ENTRY: {
+ SourceLocation SpellingLoc
+ = SourceLocation::getFromRawEncoding(Record[1]);
+ SourceMgr.createInstantiationLoc(SpellingLoc,
+ SourceLocation::getFromRawEncoding(Record[2]),
+ SourceLocation::getFromRawEncoding(Record[3]),
+ Record[4],
+ ID,
+ Record[0]);
+ break;
+ }
+ }
+
+ return Success;
+}
+
+/// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the
+/// specified cursor. Read the abbreviations that are at the top of the block
+/// and then leave the cursor pointing into the block.
+bool PCHReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
+ unsigned BlockID) {
+ if (Cursor.EnterSubBlock(BlockID)) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+
+ while (true) {
+ unsigned Code = Cursor.ReadCode();
+
+ // We expect all abbrevs to be at the start of the block.
+ if (Code != llvm::bitc::DEFINE_ABBREV)
+ return false;
+ Cursor.ReadAbbrevRecord();
+ }
+}
+
+void PCHReader::ReadMacroRecord(uint64_t Offset) {
+ // Keep track of where we are in the stream, then jump back there
+ // after reading this macro.
+ SavedStreamPosition SavedPosition(Stream);
+
+ Stream.JumpToBit(Offset);
+ RecordData Record;
+ llvm::SmallVector<IdentifierInfo*, 16> MacroArgs;
+ MacroInfo *Macro = 0;
+
+ while (true) {
+ unsigned Code = Stream.ReadCode();
+ switch (Code) {
+ case llvm::bitc::END_BLOCK:
+ return;
+
+ case llvm::bitc::ENTER_SUBBLOCK:
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return;
+ }
+ continue;
+
+ case llvm::bitc::DEFINE_ABBREV:
+ Stream.ReadAbbrevRecord();
+ continue;
+ default: break;
+ }
+
+ // Read a record.
+ Record.clear();
+ pch::PreprocessorRecordTypes RecType =
+ (pch::PreprocessorRecordTypes)Stream.ReadRecord(Code, Record);
+ switch (RecType) {
+ case pch::PP_MACRO_OBJECT_LIKE:
+ case pch::PP_MACRO_FUNCTION_LIKE: {
+ // If we already have a macro, that means that we've hit the end
+ // of the definition of the macro we were looking for. We're
+ // done.
+ if (Macro)
+ return;
+
+ IdentifierInfo *II = DecodeIdentifierInfo(Record[0]);
+ if (II == 0) {
+ Error("macro must have a name in PCH file");
+ return;
+ }
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(Record[1]);
+ bool isUsed = Record[2];
+
+ MacroInfo *MI = PP.AllocateMacroInfo(Loc);
+ MI->setIsUsed(isUsed);
+
+ if (RecType == pch::PP_MACRO_FUNCTION_LIKE) {
+ // Decode function-like macro info.
+ bool isC99VarArgs = Record[3];
+ bool isGNUVarArgs = Record[4];
+ MacroArgs.clear();
+ unsigned NumArgs = Record[5];
+ for (unsigned i = 0; i != NumArgs; ++i)
+ MacroArgs.push_back(DecodeIdentifierInfo(Record[6+i]));
+
+ // Install function-like macro info.
+ MI->setIsFunctionLike();
+ if (isC99VarArgs) MI->setIsC99Varargs();
+ if (isGNUVarArgs) MI->setIsGNUVarargs();
+ MI->setArgumentList(MacroArgs.data(), MacroArgs.size(),
+ PP.getPreprocessorAllocator());
+ }
+
+ // Finally, install the macro.
+ 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;
+ ++NumMacrosRead;
+ break;
+ }
+
+ case pch::PP_TOKEN: {
+ // If we see a TOKEN before a PP_MACRO_*, then the file is
+ // erroneous, just pretend we didn't see this.
+ if (Macro == 0) break;
+
+ Token Tok;
+ Tok.startToken();
+ Tok.setLocation(SourceLocation::getFromRawEncoding(Record[0]));
+ Tok.setLength(Record[1]);
+ if (IdentifierInfo *II = DecodeIdentifierInfo(Record[2]))
+ Tok.setIdentifierInfo(II);
+ Tok.setKind((tok::TokenKind)Record[3]);
+ Tok.setFlag((Token::TokenFlags)Record[4]);
+ Macro->AddTokenToBody(Tok);
+ break;
+ }
+ }
+ }
+}
+
+PCHReader::PCHReadResult
+PCHReader::ReadPCHBlock() {
+ if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+
+ // Read all of the records and blocks for the PCH file.
+ RecordData Record;
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd()) {
+ Error("error at end of module block in PCH file");
+ return Failure;
+ }
+
+ return Success;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ switch (Stream.ReadSubBlockID()) {
+ case pch::TYPES_BLOCK_ID: // Skip types block (lazily loaded)
+ default: // Skip unknown content.
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+ break;
+
+ case pch::DECLS_BLOCK_ID:
+ // We lazily load the decls block, but we want to set up the
+ // DeclsCursor cursor to point into it. Clone our current bitcode
+ // cursor to it, enter the block and read the abbrevs in that block.
+ // With the main cursor, we just skip over it.
+ DeclsCursor = Stream;
+ if (Stream.SkipBlock() || // Skip with the main cursor.
+ // Read the abbrevs.
+ ReadBlockAbbrevs(DeclsCursor, pch::DECLS_BLOCK_ID)) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+ break;
+
+ case pch::PREPROCESSOR_BLOCK_ID:
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+ break;
+
+ case pch::SOURCE_MANAGER_BLOCK_ID:
+ switch (ReadSourceManagerBlock()) {
+ case Success:
+ break;
+
+ case Failure:
+ Error("malformed source manager block in PCH file");
+ return Failure;
+
+ case IgnorePCH:
+ return IgnorePCH;
+ }
+ break;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read and process a record.
+ Record.clear();
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ switch ((pch::PCHRecordTypes)Stream.ReadRecord(Code, Record,
+ &BlobStart, &BlobLen)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case pch::TYPE_OFFSET:
+ if (!TypesLoaded.empty()) {
+ Error("duplicate TYPE_OFFSET record in PCH file");
+ return Failure;
+ }
+ TypeOffsets = (const uint32_t *)BlobStart;
+ TypesLoaded.resize(Record[0]);
+ break;
+
+ case pch::DECL_OFFSET:
+ if (!DeclsLoaded.empty()) {
+ Error("duplicate DECL_OFFSET record in PCH file");
+ return Failure;
+ }
+ DeclOffsets = (const uint32_t *)BlobStart;
+ DeclsLoaded.resize(Record[0]);
+ break;
+
+ case pch::LANGUAGE_OPTIONS:
+ if (ParseLanguageOptions(Record))
+ return IgnorePCH;
+ break;
+
+ case pch::METADATA: {
+ if (Record[0] != pch::VERSION_MAJOR) {
+ Diag(Record[0] < pch::VERSION_MAJOR? diag::warn_pch_version_too_old
+ : diag::warn_pch_version_too_new);
+ return IgnorePCH;
+ }
+
+ std::string TargetTriple(BlobStart, BlobLen);
+ if (TargetTriple != PP.getTargetInfo().getTargetTriple()) {
+ Diag(diag::warn_pch_target_triple)
+ << TargetTriple << PP.getTargetInfo().getTargetTriple();
+ return IgnorePCH;
+ }
+ break;
+ }
+
+ case pch::IDENTIFIER_TABLE:
+ IdentifierTableData = BlobStart;
+ if (Record[0]) {
+ IdentifierLookupTable
+ = PCHIdentifierLookupTable::Create(
+ (const unsigned char *)IdentifierTableData + Record[0],
+ (const unsigned char *)IdentifierTableData,
+ PCHIdentifierLookupTrait(*this));
+ PP.getIdentifierTable().setExternalIdentifierLookup(this);
+ }
+ break;
+
+ case pch::IDENTIFIER_OFFSET:
+ if (!IdentifiersLoaded.empty()) {
+ Error("duplicate IDENTIFIER_OFFSET record in PCH file");
+ return Failure;
+ }
+ IdentifierOffsets = (const uint32_t *)BlobStart;
+ IdentifiersLoaded.resize(Record[0]);
+ PP.getHeaderSearchInfo().SetExternalLookup(this);
+ break;
+
+ case pch::EXTERNAL_DEFINITIONS:
+ if (!ExternalDefinitions.empty()) {
+ Error("duplicate EXTERNAL_DEFINITIONS record in PCH file");
+ return Failure;
+ }
+ ExternalDefinitions.swap(Record);
+ break;
+
+ case pch::SPECIAL_TYPES:
+ SpecialTypes.swap(Record);
+ break;
+
+ case pch::STATISTICS:
+ TotalNumStatements = Record[0];
+ TotalNumMacros = Record[1];
+ TotalLexicalDeclContexts = Record[2];
+ TotalVisibleDeclContexts = Record[3];
+ break;
+
+ case pch::TENTATIVE_DEFINITIONS:
+ if (!TentativeDefinitions.empty()) {
+ Error("duplicate TENTATIVE_DEFINITIONS record in PCH file");
+ return Failure;
+ }
+ TentativeDefinitions.swap(Record);
+ break;
+
+ case pch::LOCALLY_SCOPED_EXTERNAL_DECLS:
+ if (!LocallyScopedExternalDecls.empty()) {
+ Error("duplicate LOCALLY_SCOPED_EXTERNAL_DECLS record in PCH file");
+ return Failure;
+ }
+ LocallyScopedExternalDecls.swap(Record);
+ break;
+
+ case pch::SELECTOR_OFFSETS:
+ SelectorOffsets = (const uint32_t *)BlobStart;
+ TotalNumSelectors = Record[0];
+ SelectorsLoaded.resize(TotalNumSelectors);
+ break;
+
+ case pch::METHOD_POOL:
+ MethodPoolLookupTableData = (const unsigned char *)BlobStart;
+ if (Record[0])
+ MethodPoolLookupTable
+ = PCHMethodPoolLookupTable::Create(
+ MethodPoolLookupTableData + Record[0],
+ MethodPoolLookupTableData,
+ PCHMethodPoolLookupTrait(*this));
+ TotalSelectorsInMethodPool = Record[1];
+ break;
+
+ case pch::PP_COUNTER_VALUE:
+ if (!Record.empty())
+ PP.setCounterValue(Record[0]);
+ break;
+
+ case pch::SOURCE_LOCATION_OFFSETS:
+ SLocOffsets = (const uint32_t *)BlobStart;
+ TotalNumSLocEntries = Record[0];
+ PP.getSourceManager().PreallocateSLocEntries(this,
+ TotalNumSLocEntries,
+ Record[1]);
+ break;
+
+ case pch::SOURCE_LOCATION_PRELOADS:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I) {
+ PCHReadResult Result = ReadSLocEntryRecord(Record[I]);
+ if (Result != Success)
+ return Result;
+ }
+ break;
+
+ case pch::STAT_CACHE:
+ PP.getFileManager().setStatCache(
+ new PCHStatCache((const unsigned char *)BlobStart + Record[0],
+ (const unsigned char *)BlobStart,
+ NumStatHits, NumStatMisses));
+ break;
+
+ case pch::EXT_VECTOR_DECLS:
+ if (!ExtVectorDecls.empty()) {
+ Error("duplicate EXT_VECTOR_DECLS record in PCH file");
+ return Failure;
+ }
+ ExtVectorDecls.swap(Record);
+ break;
+
+ case pch::OBJC_CATEGORY_IMPLEMENTATIONS:
+ if (!ObjCCategoryImpls.empty()) {
+ Error("duplicate OBJC_CATEGORY_IMPLEMENTATIONS record in PCH file");
+ return Failure;
+ }
+ ObjCCategoryImpls.swap(Record);
+ break;
+
+ case pch::ORIGINAL_FILE_NAME:
+ OriginalFileName.assign(BlobStart, BlobLen);
+ break;
+ }
+ }
+ Error("premature end of bitstream in PCH file");
+ return Failure;
+}
+
+PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
+ // Set the PCH file name.
+ this->FileName = FileName;
+
+ // Open the PCH file.
+ std::string ErrStr;
+ Buffer.reset(llvm::MemoryBuffer::getFile(FileName.c_str(), &ErrStr));
+ if (!Buffer) {
+ Error(ErrStr.c_str());
+ return IgnorePCH;
+ }
+
+ // Initialize the stream
+ StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+ Stream.init(StreamFile);
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'P' ||
+ Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'H') {
+ Diag(diag::err_not_a_pch_file) << FileName;
+ return Failure;
+ }
+
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+
+ if (Code != llvm::bitc::ENTER_SUBBLOCK) {
+ Error("invalid record at top-level of PCH file");
+ return Failure;
+ }
+
+ unsigned BlockID = Stream.ReadSubBlockID();
+
+ // We only know the PCH subblock ID.
+ switch (BlockID) {
+ case llvm::bitc::BLOCKINFO_BLOCK_ID:
+ if (Stream.ReadBlockInfoBlock()) {
+ Error("malformed BlockInfoBlock in PCH file");
+ return Failure;
+ }
+ break;
+ case pch::PCH_BLOCK_ID:
+ switch (ReadPCHBlock()) {
+ case Success:
+ break;
+
+ case Failure:
+ return Failure;
+
+ case IgnorePCH:
+ // FIXME: We could consider reading through to the end of this
+ // PCH block, skipping subblocks, to see if there are other
+ // PCH blocks elsewhere.
+
+ // Clear out any preallocated source location entries, so that
+ // the source manager does not try to resolve them later.
+ PP.getSourceManager().ClearPreallocatedSLocEntries();
+
+ // Remove the stat cache.
+ PP.getFileManager().setStatCache(0);
+
+ return IgnorePCH;
+ }
+ break;
+ default:
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+ break;
+ }
+ }
+
+ // Load the translation unit declaration
+ if (Context)
+ ReadDeclRecord(DeclOffsets[0], 0);
+
+ // Check the predefines buffer.
+ if (CheckPredefinesBuffer(PCHPredefines, PCHPredefinesLen,
+ PCHPredefinesBufferID))
+ return IgnorePCH;
+
+ // Initialization of builtins and library builtins occurs before the
+ // PCH 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);
+ PCHIdentifierLookupTable *IdTable
+ = (PCHIdentifierLookupTable *)IdentifierLookupTable;
+ for (unsigned I = 0, N = Identifiers.size(); I != N; ++I) {
+ IdentifierInfo *II = Identifiers[I];
+ // Look in the on-disk hash table for an entry for
+ PCHIdentifierLookupTrait Info(*this, II);
+ std::pair<const char*, unsigned> Key(II->getName(), II->getLength());
+ PCHIdentifierLookupTable::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;
+ }
+
+ // Load the special types.
+ if (Context) {
+ Context->setBuiltinVaListType(
+ GetType(SpecialTypes[pch::SPECIAL_TYPE_BUILTIN_VA_LIST]));
+ if (unsigned Id = SpecialTypes[pch::SPECIAL_TYPE_OBJC_ID])
+ Context->setObjCIdType(GetType(Id));
+ if (unsigned Sel = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SELECTOR])
+ Context->setObjCSelType(GetType(Sel));
+ if (unsigned Proto = SpecialTypes[pch::SPECIAL_TYPE_OBJC_PROTOCOL])
+ Context->setObjCProtoType(GetType(Proto));
+ if (unsigned Class = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS])
+ Context->setObjCClassType(GetType(Class));
+ if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_CF_CONSTANT_STRING])
+ Context->setCFConstantStringType(GetType(String));
+ if (unsigned FastEnum
+ = SpecialTypes[pch::SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE])
+ Context->setObjCFastEnumerationStateType(GetType(FastEnum));
+ }
+
+ return Success;
+}
+
+/// \brief Retrieve the name of the original source file name
+/// directly from the PCH file, without actually loading the PCH
+/// file.
+std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) {
+ // Open the PCH file.
+ std::string ErrStr;
+ llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
+ Buffer.reset(llvm::MemoryBuffer::getFile(PCHFileName.c_str(), &ErrStr));
+ if (!Buffer) {
+ fprintf(stderr, "error: %s\n", ErrStr.c_str());
+ return std::string();
+ }
+
+ // Initialize the stream
+ llvm::BitstreamReader StreamFile;
+ llvm::BitstreamCursor Stream;
+ StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+ Stream.init(StreamFile);
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'P' ||
+ Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'H') {
+ fprintf(stderr,
+ "error: '%s' does not appear to be a precompiled header file\n",
+ PCHFileName.c_str());
+ return std::string();
+ }
+
+ RecordData Record;
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ unsigned BlockID = Stream.ReadSubBlockID();
+
+ // We only know the PCH subblock ID.
+ switch (BlockID) {
+ case pch::PCH_BLOCK_ID:
+ if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
+ fprintf(stderr, "error: malformed block record in PCH file\n");
+ return std::string();
+ }
+ break;
+
+ default:
+ if (Stream.SkipBlock()) {
+ fprintf(stderr, "error: malformed block record in PCH file\n");
+ return std::string();
+ }
+ break;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd()) {
+ fprintf(stderr, "error: error at end of module block in PCH file\n");
+ return std::string();
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ Record.clear();
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)
+ == pch::ORIGINAL_FILE_NAME)
+ return std::string(BlobStart, BlobLen);
+ }
+
+ return std::string();
+}
+
+/// \brief Parse the record that corresponds to a LangOptions data
+/// structure.
+///
+/// This routine compares the language options used to generate the
+/// PCH file against the language options set for the current
+/// compilation. For each option, we classify differences between the
+/// two compiler states as either "benign" or "important". Benign
+/// differences don't matter, and we accept them without complaint
+/// (and without modifying the language options). Differences between
+/// the states for important options cause the PCH file to be
+/// unusable, so we emit a warning and return true to indicate that
+/// there was an error.
+///
+/// \returns true if the PCH file is unacceptable, false otherwise.
+bool PCHReader::ParseLanguageOptions(
+ const llvm::SmallVectorImpl<uint64_t> &Record) {
+ const LangOptions &LangOpts = PP.getLangOptions();
+#define PARSE_LANGOPT_BENIGN(Option) ++Idx
+#define PARSE_LANGOPT_IMPORTANT(Option, DiagID) \
+ if (Record[Idx] != LangOpts.Option) { \
+ Diag(DiagID) << (unsigned)Record[Idx] << LangOpts.Option; \
+ return true; \
+ } \
+ ++Idx
+
+ unsigned Idx = 0;
+ 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_BENIGN(ImplicitInt);
+ PARSE_LANGOPT_BENIGN(Digraphs);
+ PARSE_LANGOPT_BENIGN(HexFloats);
+ PARSE_LANGOPT_IMPORTANT(C99, diag::warn_pch_c99);
+ PARSE_LANGOPT_IMPORTANT(Microsoft, diag::warn_pch_microsoft_extensions);
+ 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_BENIGN(PascalStrings);
+ PARSE_LANGOPT_BENIGN(WritableStrings);
+ PARSE_LANGOPT_IMPORTANT(LaxVectorConversions,
+ diag::warn_pch_lax_vector_conversions);
+ PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions);
+ 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(Blocks, diag::warn_pch_blocks);
+ PARSE_LANGOPT_BENIGN(EmitAllDecls);
+ PARSE_LANGOPT_IMPORTANT(MathErrno, diag::warn_pch_math_errno);
+ PARSE_LANGOPT_IMPORTANT(OverflowChecking, diag::warn_pch_overflow_checking);
+ 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(AccessControl, diag::warn_pch_access_control);
+ if ((LangOpts.getGCMode() != 0) != (Record[Idx] != 0)) {
+ Diag(diag::warn_pch_gc_mode)
+ << (unsigned)Record[Idx] << LangOpts.getGCMode();
+ return true;
+ }
+ ++Idx;
+ PARSE_LANGOPT_BENIGN(getVisibilityMode());
+ PARSE_LANGOPT_BENIGN(InstantiationDepth);
+#undef PARSE_LANGOPT_IRRELEVANT
+#undef PARSE_LANGOPT_BENIGN
+
+ return false;
+}
+
+/// \brief Read and return the type at the given offset.
+///
+/// This routine actually reads the record corresponding to the type
+/// at the given offset in the bitstream. It is a helper routine for
+/// GetType, which deals with reading type IDs.
+QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
+ // Keep track of where we are in the stream, then jump back there
+ // after reading this type.
+ SavedStreamPosition SavedPosition(Stream);
+
+ Stream.JumpToBit(Offset);
+ RecordData Record;
+ unsigned Code = Stream.ReadCode();
+ switch ((pch::TypeCode)Stream.ReadRecord(Code, Record)) {
+ case pch::TYPE_EXT_QUAL: {
+ assert(Record.size() == 3 &&
+ "Incorrect encoding of extended qualifier type");
+ QualType Base = GetType(Record[0]);
+ QualType::GCAttrTypes GCAttr = (QualType::GCAttrTypes)Record[1];
+ unsigned AddressSpace = Record[2];
+
+ QualType T = Base;
+ if (GCAttr != QualType::GCNone)
+ T = Context->getObjCGCQualType(T, GCAttr);
+ if (AddressSpace)
+ T = Context->getAddrSpaceQualType(T, AddressSpace);
+ return T;
+ }
+
+ case pch::TYPE_FIXED_WIDTH_INT: {
+ assert(Record.size() == 2 && "Incorrect encoding of fixed-width int type");
+ return Context->getFixedWidthIntType(Record[0], Record[1]);
+ }
+
+ case pch::TYPE_COMPLEX: {
+ assert(Record.size() == 1 && "Incorrect encoding of complex type");
+ QualType ElemType = GetType(Record[0]);
+ return Context->getComplexType(ElemType);
+ }
+
+ case pch::TYPE_POINTER: {
+ assert(Record.size() == 1 && "Incorrect encoding of pointer type");
+ QualType PointeeType = GetType(Record[0]);
+ return Context->getPointerType(PointeeType);
+ }
+
+ case pch::TYPE_BLOCK_POINTER: {
+ assert(Record.size() == 1 && "Incorrect encoding of block pointer type");
+ QualType PointeeType = GetType(Record[0]);
+ return Context->getBlockPointerType(PointeeType);
+ }
+
+ case pch::TYPE_LVALUE_REFERENCE: {
+ assert(Record.size() == 1 && "Incorrect encoding of lvalue reference type");
+ QualType PointeeType = GetType(Record[0]);
+ return Context->getLValueReferenceType(PointeeType);
+ }
+
+ case pch::TYPE_RVALUE_REFERENCE: {
+ assert(Record.size() == 1 && "Incorrect encoding of rvalue reference type");
+ QualType PointeeType = GetType(Record[0]);
+ return Context->getRValueReferenceType(PointeeType);
+ }
+
+ case pch::TYPE_MEMBER_POINTER: {
+ assert(Record.size() == 1 && "Incorrect encoding of member pointer type");
+ QualType PointeeType = GetType(Record[0]);
+ QualType ClassType = GetType(Record[1]);
+ return Context->getMemberPointerType(PointeeType, ClassType.getTypePtr());
+ }
+
+ case pch::TYPE_CONSTANT_ARRAY: {
+ QualType ElementType = GetType(Record[0]);
+ 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, ASM,IndexTypeQuals);
+ }
+
+ case pch::TYPE_INCOMPLETE_ARRAY: {
+ QualType ElementType = GetType(Record[0]);
+ ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
+ unsigned IndexTypeQuals = Record[2];
+ return Context->getIncompleteArrayType(ElementType, ASM, IndexTypeQuals);
+ }
+
+ case pch::TYPE_VARIABLE_ARRAY: {
+ QualType ElementType = GetType(Record[0]);
+ ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
+ unsigned IndexTypeQuals = Record[2];
+ return Context->getVariableArrayType(ElementType, ReadTypeExpr(),
+ ASM, IndexTypeQuals);
+ }
+
+ case pch::TYPE_VECTOR: {
+ if (Record.size() != 2) {
+ Error("incorrect encoding of vector type in PCH file");
+ return QualType();
+ }
+
+ QualType ElementType = GetType(Record[0]);
+ unsigned NumElements = Record[1];
+ return Context->getVectorType(ElementType, NumElements);
+ }
+
+ case pch::TYPE_EXT_VECTOR: {
+ if (Record.size() != 2) {
+ Error("incorrect encoding of extended vector type in PCH file");
+ return QualType();
+ }
+
+ QualType ElementType = GetType(Record[0]);
+ unsigned NumElements = Record[1];
+ return Context->getExtVectorType(ElementType, NumElements);
+ }
+
+ case pch::TYPE_FUNCTION_NO_PROTO: {
+ if (Record.size() != 1) {
+ Error("incorrect encoding of no-proto function type");
+ return QualType();
+ }
+ QualType ResultType = GetType(Record[0]);
+ return Context->getFunctionNoProtoType(ResultType);
+ }
+
+ case pch::TYPE_FUNCTION_PROTO: {
+ QualType ResultType = GetType(Record[0]);
+ unsigned Idx = 1;
+ unsigned NumParams = Record[Idx++];
+ llvm::SmallVector<QualType, 16> ParamTypes;
+ for (unsigned I = 0; I != NumParams; ++I)
+ ParamTypes.push_back(GetType(Record[Idx++]));
+ bool isVariadic = Record[Idx++];
+ unsigned Quals = Record[Idx++];
+ bool hasExceptionSpec = Record[Idx++];
+ bool hasAnyExceptionSpec = Record[Idx++];
+ unsigned NumExceptions = Record[Idx++];
+ llvm::SmallVector<QualType, 2> Exceptions;
+ for (unsigned I = 0; I != NumExceptions; ++I)
+ Exceptions.push_back(GetType(Record[Idx++]));
+ return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams,
+ isVariadic, Quals, hasExceptionSpec,
+ hasAnyExceptionSpec, NumExceptions,
+ Exceptions.data());
+ }
+
+ case pch::TYPE_TYPEDEF:
+ assert(Record.size() == 1 && "incorrect encoding of typedef type");
+ return Context->getTypeDeclType(cast<TypedefDecl>(GetDecl(Record[0])));
+
+ case pch::TYPE_TYPEOF_EXPR:
+ return Context->getTypeOfExprType(ReadTypeExpr());
+
+ case pch::TYPE_TYPEOF: {
+ if (Record.size() != 1) {
+ Error("incorrect encoding of typeof(type) in PCH file");
+ return QualType();
+ }
+ QualType UnderlyingType = GetType(Record[0]);
+ return Context->getTypeOfType(UnderlyingType);
+ }
+
+ case pch::TYPE_RECORD:
+ assert(Record.size() == 1 && "incorrect encoding of record type");
+ return Context->getTypeDeclType(cast<RecordDecl>(GetDecl(Record[0])));
+
+ case pch::TYPE_ENUM:
+ assert(Record.size() == 1 && "incorrect encoding of enum type");
+ return Context->getTypeDeclType(cast<EnumDecl>(GetDecl(Record[0])));
+
+ case pch::TYPE_OBJC_INTERFACE:
+ assert(Record.size() == 1 && "incorrect encoding of objc interface type");
+ return Context->getObjCInterfaceType(
+ cast<ObjCInterfaceDecl>(GetDecl(Record[0])));
+
+ case pch::TYPE_OBJC_QUALIFIED_INTERFACE: {
+ unsigned Idx = 0;
+ ObjCInterfaceDecl *ItfD = cast<ObjCInterfaceDecl>(GetDecl(Record[Idx++]));
+ unsigned NumProtos = Record[Idx++];
+ llvm::SmallVector<ObjCProtocolDecl*, 4> Protos;
+ for (unsigned I = 0; I != NumProtos; ++I)
+ Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++])));
+ return Context->getObjCQualifiedInterfaceType(ItfD, Protos.data(), NumProtos);
+ }
+
+ case pch::TYPE_OBJC_QUALIFIED_ID: {
+ unsigned Idx = 0;
+ unsigned NumProtos = Record[Idx++];
+ llvm::SmallVector<ObjCProtocolDecl*, 4> Protos;
+ for (unsigned I = 0; I != NumProtos; ++I)
+ Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++])));
+ return Context->getObjCQualifiedIdType(Protos.data(), NumProtos);
+ }
+ }
+ // Suppress a GCC warning
+ return QualType();
+}
+
+
+QualType PCHReader::GetType(pch::TypeID ID) {
+ unsigned Quals = ID & 0x07;
+ unsigned Index = ID >> 3;
+
+ if (Index < pch::NUM_PREDEF_TYPE_IDS) {
+ QualType T;
+ switch ((pch::PredefinedTypeIDs)Index) {
+ case pch::PREDEF_TYPE_NULL_ID: return QualType();
+ case pch::PREDEF_TYPE_VOID_ID: T = Context->VoidTy; break;
+ case pch::PREDEF_TYPE_BOOL_ID: T = Context->BoolTy; break;
+
+ case pch::PREDEF_TYPE_CHAR_U_ID:
+ case pch::PREDEF_TYPE_CHAR_S_ID:
+ // FIXME: Check that the signedness of CharTy is correct!
+ T = Context->CharTy;
+ break;
+
+ case pch::PREDEF_TYPE_UCHAR_ID: T = Context->UnsignedCharTy; break;
+ case pch::PREDEF_TYPE_USHORT_ID: T = Context->UnsignedShortTy; break;
+ case pch::PREDEF_TYPE_UINT_ID: T = Context->UnsignedIntTy; break;
+ case pch::PREDEF_TYPE_ULONG_ID: T = Context->UnsignedLongTy; break;
+ case pch::PREDEF_TYPE_ULONGLONG_ID: T = Context->UnsignedLongLongTy; break;
+ case pch::PREDEF_TYPE_UINT128_ID: T = Context->UnsignedInt128Ty; break;
+ case pch::PREDEF_TYPE_SCHAR_ID: T = Context->SignedCharTy; break;
+ case pch::PREDEF_TYPE_WCHAR_ID: T = Context->WCharTy; break;
+ case pch::PREDEF_TYPE_SHORT_ID: T = Context->ShortTy; break;
+ case pch::PREDEF_TYPE_INT_ID: T = Context->IntTy; break;
+ case pch::PREDEF_TYPE_LONG_ID: T = Context->LongTy; break;
+ case pch::PREDEF_TYPE_LONGLONG_ID: T = Context->LongLongTy; break;
+ case pch::PREDEF_TYPE_INT128_ID: T = Context->Int128Ty; break;
+ case pch::PREDEF_TYPE_FLOAT_ID: T = Context->FloatTy; break;
+ case pch::PREDEF_TYPE_DOUBLE_ID: T = Context->DoubleTy; break;
+ case pch::PREDEF_TYPE_LONGDOUBLE_ID: T = Context->LongDoubleTy; break;
+ case pch::PREDEF_TYPE_OVERLOAD_ID: T = Context->OverloadTy; break;
+ case pch::PREDEF_TYPE_DEPENDENT_ID: T = Context->DependentTy; break;
+ case pch::PREDEF_TYPE_NULLPTR_ID: T = Context->NullPtrTy; break;
+ }
+
+ assert(!T.isNull() && "Unknown predefined type");
+ return T.getQualifiedType(Quals);
+ }
+
+ Index -= pch::NUM_PREDEF_TYPE_IDS;
+ assert(Index < TypesLoaded.size() && "Type index out-of-range");
+ if (!TypesLoaded[Index])
+ TypesLoaded[Index] = ReadTypeRecord(TypeOffsets[Index]).getTypePtr();
+
+ return QualType(TypesLoaded[Index], Quals);
+}
+
+Decl *PCHReader::GetDecl(pch::DeclID ID) {
+ if (ID == 0)
+ return 0;
+
+ if (ID > DeclsLoaded.size()) {
+ Error("declaration ID out-of-range for PCH file");
+ return 0;
+ }
+
+ unsigned Index = ID - 1;
+ if (!DeclsLoaded[Index])
+ ReadDeclRecord(DeclOffsets[Index], Index);
+
+ return DeclsLoaded[Index];
+}
+
+/// \brief Resolve the offset of a statement into a statement.
+///
+/// This operation will read a new statement from the external
+/// source each time it is called, and is meant to be used via a
+/// LazyOffsetPtr (which is used by Decls for the body of functions, etc).
+Stmt *PCHReader::GetDeclStmt(uint64_t Offset) {
+ // Since we know tha this statement is part of a decl, make sure to use the
+ // decl cursor to read it.
+ DeclsCursor.JumpToBit(Offset);
+ return ReadStmt(DeclsCursor);
+}
+
+bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC,
+ llvm::SmallVectorImpl<pch::DeclID> &Decls) {
+ assert(DC->hasExternalLexicalStorage() &&
+ "DeclContext has no lexical decls in storage");
+ uint64_t Offset = DeclContextOffsets[DC].first;
+ assert(Offset && "DeclContext has no lexical decls in storage");
+
+ // Keep track of where we are in the stream, then jump back there
+ // after reading this context.
+ SavedStreamPosition SavedPosition(DeclsCursor);
+
+ // Load the record containing all of the declarations lexically in
+ // this context.
+ DeclsCursor.JumpToBit(Offset);
+ RecordData Record;
+ unsigned Code = DeclsCursor.ReadCode();
+ unsigned RecCode = DeclsCursor.ReadRecord(Code, Record);
+ (void)RecCode;
+ assert(RecCode == pch::DECL_CONTEXT_LEXICAL && "Expected lexical block");
+
+ // Load all of the declaration IDs
+ Decls.clear();
+ Decls.insert(Decls.end(), Record.begin(), Record.end());
+ ++NumLexicalDeclContextsRead;
+ return false;
+}
+
+bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC,
+ llvm::SmallVectorImpl<VisibleDeclaration> &Decls) {
+ assert(DC->hasExternalVisibleStorage() &&
+ "DeclContext has no visible decls in storage");
+ uint64_t Offset = DeclContextOffsets[DC].second;
+ assert(Offset && "DeclContext has no visible decls in storage");
+
+ // Keep track of where we are in the stream, then jump back there
+ // after reading this context.
+ SavedStreamPosition SavedPosition(DeclsCursor);
+
+ // Load the record containing all of the declarations visible in
+ // this context.
+ DeclsCursor.JumpToBit(Offset);
+ RecordData Record;
+ unsigned Code = DeclsCursor.ReadCode();
+ unsigned RecCode = DeclsCursor.ReadRecord(Code, Record);
+ (void)RecCode;
+ assert(RecCode == pch::DECL_CONTEXT_VISIBLE && "Expected visible block");
+ if (Record.size() == 0)
+ return false;
+
+ Decls.clear();
+
+ unsigned Idx = 0;
+ while (Idx < Record.size()) {
+ Decls.push_back(VisibleDeclaration());
+ Decls.back().Name = ReadDeclarationName(Record, Idx);
+
+ unsigned Size = Record[Idx++];
+ llvm::SmallVector<unsigned, 4> &LoadedDecls = Decls.back().Declarations;
+ LoadedDecls.reserve(Size);
+ for (unsigned I = 0; I < Size; ++I)
+ LoadedDecls.push_back(Record[Idx++]);
+ }
+
+ ++NumVisibleDeclContextsRead;
+ return false;
+}
+
+void PCHReader::StartTranslationUnit(ASTConsumer *Consumer) {
+ this->Consumer = Consumer;
+
+ if (!Consumer)
+ return;
+
+ for (unsigned I = 0, N = ExternalDefinitions.size(); I != N; ++I) {
+ Decl *D = GetDecl(ExternalDefinitions[I]);
+ DeclGroupRef DG(D);
+ Consumer->HandleTopLevelDecl(DG);
+ }
+
+ for (unsigned I = 0, N = InterestingDecls.size(); I != N; ++I) {
+ DeclGroupRef DG(InterestingDecls[I]);
+ Consumer->HandleTopLevelDecl(DG);
+ }
+}
+
+void PCHReader::PrintStats() {
+ std::fprintf(stderr, "*** PCH Statistics:\n");
+
+ unsigned NumTypesLoaded
+ = TypesLoaded.size() - std::count(TypesLoaded.begin(), TypesLoaded.end(),
+ (Type *)0);
+ unsigned NumDeclsLoaded
+ = DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(),
+ (Decl *)0);
+ unsigned NumIdentifiersLoaded
+ = IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(),
+ IdentifiersLoaded.end(),
+ (IdentifierInfo *)0);
+ unsigned NumSelectorsLoaded
+ = SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(),
+ SelectorsLoaded.end(),
+ Selector());
+
+ std::fprintf(stderr, " %u stat cache hits\n", NumStatHits);
+ std::fprintf(stderr, " %u stat cache misses\n", NumStatMisses);
+ if (TotalNumSLocEntries)
+ std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n",
+ NumSLocEntriesRead, TotalNumSLocEntries,
+ ((float)NumSLocEntriesRead/TotalNumSLocEntries * 100));
+ if (!TypesLoaded.empty())
+ std::fprintf(stderr, " %u/%u types read (%f%%)\n",
+ NumTypesLoaded, (unsigned)TypesLoaded.size(),
+ ((float)NumTypesLoaded/TypesLoaded.size() * 100));
+ if (!DeclsLoaded.empty())
+ std::fprintf(stderr, " %u/%u declarations read (%f%%)\n",
+ NumDeclsLoaded, (unsigned)DeclsLoaded.size(),
+ ((float)NumDeclsLoaded/DeclsLoaded.size() * 100));
+ if (!IdentifiersLoaded.empty())
+ std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n",
+ NumIdentifiersLoaded, (unsigned)IdentifiersLoaded.size(),
+ ((float)NumIdentifiersLoaded/IdentifiersLoaded.size() * 100));
+ if (TotalNumSelectors)
+ std::fprintf(stderr, " %u/%u selectors read (%f%%)\n",
+ NumSelectorsLoaded, TotalNumSelectors,
+ ((float)NumSelectorsLoaded/TotalNumSelectors * 100));
+ if (TotalNumStatements)
+ std::fprintf(stderr, " %u/%u statements read (%f%%)\n",
+ NumStatementsRead, TotalNumStatements,
+ ((float)NumStatementsRead/TotalNumStatements * 100));
+ if (TotalNumMacros)
+ std::fprintf(stderr, " %u/%u macros read (%f%%)\n",
+ NumMacrosRead, TotalNumMacros,
+ ((float)NumMacrosRead/TotalNumMacros * 100));
+ if (TotalLexicalDeclContexts)
+ std::fprintf(stderr, " %u/%u lexical declcontexts read (%f%%)\n",
+ NumLexicalDeclContextsRead, TotalLexicalDeclContexts,
+ ((float)NumLexicalDeclContextsRead/TotalLexicalDeclContexts
+ * 100));
+ if (TotalVisibleDeclContexts)
+ std::fprintf(stderr, " %u/%u visible declcontexts read (%f%%)\n",
+ NumVisibleDeclContextsRead, TotalVisibleDeclContexts,
+ ((float)NumVisibleDeclContextsRead/TotalVisibleDeclContexts
+ * 100));
+ if (TotalSelectorsInMethodPool) {
+ std::fprintf(stderr, " %u/%u method pool entries read (%f%%)\n",
+ NumMethodPoolSelectorsRead, TotalSelectorsInMethodPool,
+ ((float)NumMethodPoolSelectorsRead/TotalSelectorsInMethodPool
+ * 100));
+ std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses);
+ }
+ std::fprintf(stderr, "\n");
+}
+
+void PCHReader::InitializeSema(Sema &S) {
+ SemaObj = &S;
+ S.ExternalSource = this;
+
+ // Makes sure any declarations that were deserialized "too early"
+ // still get added to the identifier's declaration chains.
+ for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) {
+ SemaObj->TUScope->AddDecl(Action::DeclPtrTy::make(PreloadedDecls[I]));
+ SemaObj->IdResolver.AddDecl(PreloadedDecls[I]);
+ }
+ PreloadedDecls.clear();
+
+ // If there were any tentative definitions, deserialize them and add
+ // them to Sema's table of tentative definitions.
+ for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
+ VarDecl *Var = cast<VarDecl>(GetDecl(TentativeDefinitions[I]));
+ SemaObj->TentativeDefinitions[Var->getDeclName()] = Var;
+ }
+
+ // 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<TypedefDecl>(GetDecl(ExtVectorDecls[I])));
+
+ // If there were any Objective-C category implementations,
+ // deserialize them and add them to Sema's vector of such
+ // definitions.
+ for (unsigned I = 0, N = ObjCCategoryImpls.size(); I != N; ++I)
+ SemaObj->ObjCCategoryImpls.push_back(
+ cast<ObjCCategoryImplDecl>(GetDecl(ObjCCategoryImpls[I])));
+}
+
+IdentifierInfo* PCHReader::get(const char *NameStart, const char *NameEnd) {
+ // Try to find this name within our on-disk hash table
+ PCHIdentifierLookupTable *IdTable
+ = (PCHIdentifierLookupTable *)IdentifierLookupTable;
+ std::pair<const char*, unsigned> Key(NameStart, NameEnd - NameStart);
+ PCHIdentifierLookupTable::iterator Pos = IdTable->find(Key);
+ if (Pos == IdTable->end())
+ return 0;
+
+ // Dereferencing the iterator has the effect of building the
+ // IdentifierInfo node and populating it with the various
+ // declarations it needs.
+ return *Pos;
+}
+
+std::pair<ObjCMethodList, ObjCMethodList>
+PCHReader::ReadMethodPool(Selector Sel) {
+ if (!MethodPoolLookupTable)
+ return std::pair<ObjCMethodList, ObjCMethodList>();
+
+ // Try to find this selector within our on-disk hash table.
+ PCHMethodPoolLookupTable *PoolTable
+ = (PCHMethodPoolLookupTable*)MethodPoolLookupTable;
+ PCHMethodPoolLookupTable::iterator Pos = PoolTable->find(Sel);
+ if (Pos == PoolTable->end()) {
+ ++NumMethodPoolMisses;
+ return std::pair<ObjCMethodList, ObjCMethodList>();;
+ }
+
+ ++NumMethodPoolSelectorsRead;
+ return *Pos;
+}
+
+void PCHReader::SetIdentifierInfo(unsigned ID, IdentifierInfo *II) {
+ assert(ID && "Non-zero identifier ID required");
+ assert(ID <= IdentifiersLoaded.size() && "identifier ID out of range");
+ IdentifiersLoaded[ID - 1] = II;
+}
+
+IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) {
+ if (ID == 0)
+ return 0;
+
+ if (!IdentifierTableData || IdentifiersLoaded.empty()) {
+ Error("no identifier table in PCH file");
+ return 0;
+ }
+
+ if (!IdentifiersLoaded[ID - 1]) {
+ uint32_t Offset = IdentifierOffsets[ID - 1];
+ const char *Str = IdentifierTableData + Offset;
+
+ // All of the strings in the PCH file are preceded by a 16-bit
+ // length. Extract that 16-bit length to avoid having to execute
+ // strlen().
+ const char *StrLenPtr = Str - 2;
+ unsigned StrLen = (((unsigned) StrLenPtr[0])
+ | (((unsigned) StrLenPtr[1]) << 8)) - 1;
+ IdentifiersLoaded[ID - 1]
+ = &PP.getIdentifierTable().get(Str, Str + StrLen);
+ }
+
+ return IdentifiersLoaded[ID - 1];
+}
+
+void PCHReader::ReadSLocEntry(unsigned ID) {
+ ReadSLocEntryRecord(ID);
+}
+
+Selector PCHReader::DecodeSelector(unsigned ID) {
+ if (ID == 0)
+ return Selector();
+
+ if (!MethodPoolLookupTableData)
+ return Selector();
+
+ if (ID > TotalNumSelectors) {
+ Error("selector ID out of range in PCH file");
+ return Selector();
+ }
+
+ unsigned Index = ID - 1;
+ if (SelectorsLoaded[Index].getAsOpaquePtr() == 0) {
+ // Load this selector from the selector table.
+ // FIXME: endianness portability issues with SelectorOffsets table
+ PCHMethodPoolLookupTrait Trait(*this);
+ SelectorsLoaded[Index]
+ = Trait.ReadKey(MethodPoolLookupTableData + SelectorOffsets[Index], 0);
+ }
+
+ return SelectorsLoaded[Index];
+}
+
+DeclarationName
+PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
+ DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
+ switch (Kind) {
+ case DeclarationName::Identifier:
+ return DeclarationName(GetIdentifierInfo(Record, Idx));
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ return DeclarationName(GetSelector(Record, Idx));
+
+ case DeclarationName::CXXConstructorName:
+ return Context->DeclarationNames.getCXXConstructorName(
+ GetType(Record[Idx++]));
+
+ case DeclarationName::CXXDestructorName:
+ return Context->DeclarationNames.getCXXDestructorName(
+ GetType(Record[Idx++]));
+
+ case DeclarationName::CXXConversionFunctionName:
+ return Context->DeclarationNames.getCXXConversionFunctionName(
+ GetType(Record[Idx++]));
+
+ case DeclarationName::CXXOperatorName:
+ return Context->DeclarationNames.getCXXOperatorName(
+ (OverloadedOperatorKind)Record[Idx++]);
+
+ case DeclarationName::CXXUsingDirective:
+ return DeclarationName::getUsingDirectiveName();
+ }
+
+ // Required to silence GCC warning
+ return DeclarationName();
+}
+
+/// \brief Read an integral value
+llvm::APInt PCHReader::ReadAPInt(const RecordData &Record, unsigned &Idx) {
+ unsigned BitWidth = Record[Idx++];
+ unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
+ llvm::APInt Result(BitWidth, NumWords, &Record[Idx]);
+ Idx += NumWords;
+ return Result;
+}
+
+/// \brief Read a signed integral value
+llvm::APSInt PCHReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) {
+ bool isUnsigned = Record[Idx++];
+ return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned);
+}
+
+/// \brief Read a floating-point value
+llvm::APFloat PCHReader::ReadAPFloat(const RecordData &Record, unsigned &Idx) {
+ return llvm::APFloat(ReadAPInt(Record, Idx));
+}
+
+// \brief Read a string
+std::string PCHReader::ReadString(const RecordData &Record, unsigned &Idx) {
+ unsigned Len = Record[Idx++];
+ std::string Result(Record.data() + Idx, Record.data() + Idx + Len);
+ Idx += Len;
+ return Result;
+}
+
+DiagnosticBuilder PCHReader::Diag(unsigned DiagID) {
+ return Diag(SourceLocation(), DiagID);
+}
+
+DiagnosticBuilder PCHReader::Diag(SourceLocation Loc, unsigned DiagID) {
+ return PP.getDiagnostics().Report(FullSourceLoc(Loc,
+ PP.getSourceManager()),
+ DiagID);
+}
+
+/// \brief Retrieve the identifier table associated with the
+/// preprocessor.
+IdentifierTable &PCHReader::getIdentifierTable() {
+ return PP.getIdentifierTable();
+}
+
+/// \brief Record that the given ID maps to the given switch-case
+/// statement.
+void PCHReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) {
+ assert(SwitchCaseStmts[ID] == 0 && "Already have a SwitchCase with this ID");
+ SwitchCaseStmts[ID] = SC;
+}
+
+/// \brief Retrieve the switch-case statement with the given ID.
+SwitchCase *PCHReader::getSwitchCaseWithID(unsigned ID) {
+ assert(SwitchCaseStmts[ID] != 0 && "No SwitchCase with this ID");
+ return SwitchCaseStmts[ID];
+}
+
+/// \brief Record that the given label statement has been
+/// deserialized and has the given ID.
+void PCHReader::RecordLabelStmt(LabelStmt *S, unsigned ID) {
+ assert(LabelStmts.find(ID) == LabelStmts.end() &&
+ "Deserialized label twice");
+ LabelStmts[ID] = S;
+
+ // If we've already seen any goto statements that point to this
+ // label, resolve them now.
+ typedef std::multimap<unsigned, GotoStmt *>::iterator GotoIter;
+ std::pair<GotoIter, GotoIter> Gotos = UnresolvedGotoStmts.equal_range(ID);
+ for (GotoIter Goto = Gotos.first; Goto != Gotos.second; ++Goto)
+ Goto->second->setLabel(S);
+ UnresolvedGotoStmts.erase(Gotos.first, Gotos.second);
+
+ // If we've already seen any address-label statements that point to
+ // this label, resolve them now.
+ typedef std::multimap<unsigned, AddrLabelExpr *>::iterator AddrLabelIter;
+ std::pair<AddrLabelIter, AddrLabelIter> AddrLabels
+ = UnresolvedAddrLabelExprs.equal_range(ID);
+ for (AddrLabelIter AddrLabel = AddrLabels.first;
+ AddrLabel != AddrLabels.second; ++AddrLabel)
+ AddrLabel->second->setLabel(S);
+ UnresolvedAddrLabelExprs.erase(AddrLabels.first, AddrLabels.second);
+}
+
+/// \brief Set the label of the given statement to the label
+/// identified by ID.
+///
+/// Depending on the order in which the label and other statements
+/// referencing that label occur, this operation may complete
+/// immediately (updating the statement) or it may queue the
+/// statement to be back-patched later.
+void PCHReader::SetLabelOf(GotoStmt *S, unsigned ID) {
+ std::map<unsigned, LabelStmt *>::iterator Label = LabelStmts.find(ID);
+ if (Label != LabelStmts.end()) {
+ // We've already seen this label, so set the label of the goto and
+ // we're done.
+ S->setLabel(Label->second);
+ } else {
+ // We haven't seen this label yet, so add this goto to the set of
+ // unresolved goto statements.
+ UnresolvedGotoStmts.insert(std::make_pair(ID, S));
+ }
+}
+
+/// \brief Set the label of the given expression to the label
+/// identified by ID.
+///
+/// Depending on the order in which the label and other statements
+/// referencing that label occur, this operation may complete
+/// immediately (updating the statement) or it may queue the
+/// statement to be back-patched later.
+void PCHReader::SetLabelOf(AddrLabelExpr *S, unsigned ID) {
+ std::map<unsigned, LabelStmt *>::iterator Label = LabelStmts.find(ID);
+ if (Label != LabelStmts.end()) {
+ // We've already seen this label, so set the label of the
+ // label-address expression and we're done.
+ S->setLabel(Label->second);
+ } else {
+ // We haven't seen this label yet, so add this label-address
+ // expression to the set of unresolved label-address expressions.
+ UnresolvedAddrLabelExprs.insert(std::make_pair(ID, S));
+ }
+}
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
new file mode 100644
index 000000000000..6856623e60c9
--- /dev/null
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -0,0 +1,712 @@
+//===--- PCHReaderDecl.cpp - Decl Deserialization ---------------*- 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 PCHReader::ReadDeclRecord method, which is the
+// entrypoint for loading a decl.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PCHReader.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/AST/Expr.h"
+using namespace clang;
+
+
+//===----------------------------------------------------------------------===//
+// Declaration deserialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class PCHDeclReader : public DeclVisitor<PCHDeclReader, void> {
+ PCHReader &Reader;
+ const PCHReader::RecordData &Record;
+ unsigned &Idx;
+
+ public:
+ PCHDeclReader(PCHReader &Reader, const PCHReader::RecordData &Record,
+ unsigned &Idx)
+ : Reader(Reader), Record(Record), Idx(Idx) { }
+
+ void VisitDecl(Decl *D);
+ void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
+ void VisitNamedDecl(NamedDecl *ND);
+ void VisitTypeDecl(TypeDecl *TD);
+ void VisitTypedefDecl(TypedefDecl *TD);
+ void VisitTagDecl(TagDecl *TD);
+ void VisitEnumDecl(EnumDecl *ED);
+ void VisitRecordDecl(RecordDecl *RD);
+ void VisitValueDecl(ValueDecl *VD);
+ void VisitEnumConstantDecl(EnumConstantDecl *ECD);
+ void VisitFunctionDecl(FunctionDecl *FD);
+ void VisitFieldDecl(FieldDecl *FD);
+ void VisitVarDecl(VarDecl *VD);
+ void VisitImplicitParamDecl(ImplicitParamDecl *PD);
+ void VisitParmVarDecl(ParmVarDecl *PD);
+ void VisitOriginalParmVarDecl(OriginalParmVarDecl *PD);
+ void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD);
+ void VisitBlockDecl(BlockDecl *BD);
+ std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
+ void VisitObjCMethodDecl(ObjCMethodDecl *D);
+ void VisitObjCContainerDecl(ObjCContainerDecl *D);
+ void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+ void VisitObjCIvarDecl(ObjCIvarDecl *D);
+ void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
+ void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D);
+ void VisitObjCClassDecl(ObjCClassDecl *D);
+ void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
+ void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
+ void VisitObjCImplDecl(ObjCImplDecl *D);
+ void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
+ void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
+ void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
+ void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
+ void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+ };
+}
+
+void PCHDeclReader::VisitDecl(Decl *D) {
+ D->setDeclContext(cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
+ D->setLexicalDeclContext(
+ cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
+ D->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ D->setInvalidDecl(Record[Idx++]);
+ if (Record[Idx++])
+ D->addAttr(Reader.ReadAttributes());
+ D->setImplicit(Record[Idx++]);
+ D->setAccess((AccessSpecifier)Record[Idx++]);
+}
+
+void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
+ VisitDecl(TU);
+}
+
+void PCHDeclReader::VisitNamedDecl(NamedDecl *ND) {
+ VisitDecl(ND);
+ ND->setDeclName(Reader.ReadDeclarationName(Record, Idx));
+}
+
+void PCHDeclReader::VisitTypeDecl(TypeDecl *TD) {
+ VisitNamedDecl(TD);
+ TD->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr());
+}
+
+void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
+ // Note that we cannot use VisitTypeDecl here, because we need to
+ // set the underlying type of the typedef *before* we try to read
+ // the type associated with the TypedefDecl.
+ VisitNamedDecl(TD);
+ TD->setUnderlyingType(Reader.GetType(Record[Idx + 1]));
+ TD->setTypeForDecl(Reader.GetType(Record[Idx]).getTypePtr());
+ Idx += 2;
+}
+
+void PCHDeclReader::VisitTagDecl(TagDecl *TD) {
+ VisitTypeDecl(TD);
+ TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
+ TD->setDefinition(Record[Idx++]);
+ TD->setTypedefForAnonDecl(
+ cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) {
+ VisitTagDecl(ED);
+ ED->setIntegerType(Reader.GetType(Record[Idx++]));
+ // FIXME: C++ InstantiatedFrom
+}
+
+void PCHDeclReader::VisitRecordDecl(RecordDecl *RD) {
+ VisitTagDecl(RD);
+ RD->setHasFlexibleArrayMember(Record[Idx++]);
+ RD->setAnonymousStructOrUnion(Record[Idx++]);
+}
+
+void PCHDeclReader::VisitValueDecl(ValueDecl *VD) {
+ VisitNamedDecl(VD);
+ VD->setType(Reader.GetType(Record[Idx++]));
+}
+
+void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) {
+ VisitValueDecl(ECD);
+ if (Record[Idx++])
+ ECD->setInitExpr(Reader.ReadDeclExpr());
+ ECD->setInitVal(Reader.ReadAPSInt(Record, Idx));
+}
+
+void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
+ VisitValueDecl(FD);
+ if (Record[Idx++])
+ FD->setLazyBody(Reader.getDeclsCursor().GetCurrentBitNo());
+ FD->setPreviousDeclaration(
+ cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
+ FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]);
+ FD->setInline(Record[Idx++]);
+ FD->setC99InlineDefinition(Record[Idx++]);
+ FD->setVirtualAsWritten(Record[Idx++]);
+ FD->setPure(Record[Idx++]);
+ FD->setHasInheritedPrototype(Record[Idx++]);
+ FD->setHasWrittenPrototype(Record[Idx++]);
+ FD->setDeleted(Record[Idx++]);
+ FD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ // FIXME: C++ TemplateOrInstantiation
+ unsigned NumParams = Record[Idx++];
+ llvm::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);
+}
+
+void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
+ VisitNamedDecl(MD);
+ if (Record[Idx++]) {
+ // In practice, this won't be executed (since method definitions
+ // don't occur in header files).
+ MD->setBody(Reader.ReadDeclStmt());
+ MD->setSelfDecl(cast<ImplicitParamDecl>(Reader.GetDecl(Record[Idx++])));
+ MD->setCmdDecl(cast<ImplicitParamDecl>(Reader.GetDecl(Record[Idx++])));
+ }
+ MD->setInstanceMethod(Record[Idx++]);
+ MD->setVariadic(Record[Idx++]);
+ MD->setSynthesized(Record[Idx++]);
+ MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]);
+ MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
+ MD->setResultType(Reader.GetType(Record[Idx++]));
+ MD->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ unsigned NumParams = Record[Idx++];
+ llvm::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);
+}
+
+void PCHDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
+ VisitNamedDecl(CD);
+ CD->setAtEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
+ VisitObjCContainerDecl(ID);
+ ID->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr());
+ ID->setSuperClass(cast_or_null<ObjCInterfaceDecl>
+ (Reader.GetDecl(Record[Idx++])));
+ unsigned NumProtocols = Record[Idx++];
+ llvm::SmallVector<ObjCProtocolDecl *, 16> Protocols;
+ Protocols.reserve(NumProtocols);
+ for (unsigned I = 0; I != NumProtocols; ++I)
+ Protocols.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
+ ID->setProtocolList(Protocols.data(), NumProtocols, *Reader.getContext());
+ unsigned NumIvars = Record[Idx++];
+ llvm::SmallVector<ObjCIvarDecl *, 16> IVars;
+ IVars.reserve(NumIvars);
+ for (unsigned I = 0; I != NumIvars; ++I)
+ IVars.push_back(cast<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++])));
+ ID->setIVarList(IVars.data(), NumIvars, *Reader.getContext());
+ ID->setCategoryList(
+ cast_or_null<ObjCCategoryDecl>(Reader.GetDecl(Record[Idx++])));
+ ID->setForwardDecl(Record[Idx++]);
+ ID->setImplicitInterfaceDecl(Record[Idx++]);
+ ID->setClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ ID->setSuperClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ ID->setAtEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHDeclReader::VisitObjCIvarDecl(ObjCIvarDecl *IVD) {
+ VisitFieldDecl(IVD);
+ IVD->setAccessControl((ObjCIvarDecl::AccessControl)Record[Idx++]);
+}
+
+void PCHDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
+ VisitObjCContainerDecl(PD);
+ PD->setForwardDecl(Record[Idx++]);
+ PD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ unsigned NumProtoRefs = Record[Idx++];
+ llvm::SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
+ ProtoRefs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
+ PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, *Reader.getContext());
+}
+
+void PCHDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) {
+ VisitFieldDecl(FD);
+}
+
+void PCHDeclReader::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++])));
+ CD->setClassList(*Reader.getContext(), ClassRefs.data(), NumClassRefs);
+}
+
+void PCHDeclReader::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *FPD) {
+ VisitDecl(FPD);
+ unsigned NumProtoRefs = Record[Idx++];
+ llvm::SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
+ ProtoRefs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
+ FPD->setProtocolList(ProtoRefs.data(), NumProtoRefs, *Reader.getContext());
+}
+
+void PCHDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) {
+ VisitObjCContainerDecl(CD);
+ CD->setClassInterface(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+ unsigned NumProtoRefs = Record[Idx++];
+ llvm::SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
+ ProtoRefs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
+ CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, *Reader.getContext());
+ CD->setNextClassCategory(cast_or_null<ObjCCategoryDecl>(Reader.GetDecl(Record[Idx++])));
+ CD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
+ VisitNamedDecl(CAD);
+ CAD->setClassInterface(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
+ VisitNamedDecl(D);
+ D->setType(Reader.GetType(Record[Idx++]));
+ // FIXME: stable encoding
+ D->setPropertyAttributes(
+ (ObjCPropertyDecl::PropertyAttributeKind)Record[Idx++]);
+ // 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++])));
+}
+
+void PCHDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) {
+ VisitNamedDecl(D);
+ D->setClassInterface(
+ cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+ D->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+void PCHDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ VisitObjCImplDecl(D);
+ D->setIdentifier(Reader.GetIdentifierInfo(Record, Idx));
+}
+
+void PCHDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+ VisitObjCImplDecl(D);
+ D->setSuperClass(
+ cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+
+void PCHDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+ VisitDecl(D);
+ D->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ D->setPropertyDecl(
+ cast_or_null<ObjCPropertyDecl>(Reader.GetDecl(Record[Idx++])));
+ D->setPropertyIvarDecl(
+ cast_or_null<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) {
+ VisitValueDecl(FD);
+ FD->setMutable(Record[Idx++]);
+ if (Record[Idx++])
+ FD->setBitWidth(Reader.ReadDeclExpr());
+}
+
+void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
+ VisitValueDecl(VD);
+ VD->setStorageClass((VarDecl::StorageClass)Record[Idx++]);
+ VD->setThreadSpecified(Record[Idx++]);
+ VD->setCXXDirectInitializer(Record[Idx++]);
+ VD->setDeclaredInCondition(Record[Idx++]);
+ VD->setPreviousDeclaration(
+ cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ VD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ if (Record[Idx++])
+ VD->setInit(*Reader.getContext(), Reader.ReadDeclExpr());
+}
+
+void PCHDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) {
+ VisitVarDecl(PD);
+}
+
+void PCHDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
+ VisitVarDecl(PD);
+ PD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
+ // FIXME: default argument (C++ only)
+}
+
+void PCHDeclReader::VisitOriginalParmVarDecl(OriginalParmVarDecl *PD) {
+ VisitParmVarDecl(PD);
+ PD->setOriginalType(Reader.GetType(Record[Idx++]));
+}
+
+void PCHDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) {
+ VisitDecl(AD);
+ AD->setAsmString(cast<StringLiteral>(Reader.ReadDeclExpr()));
+}
+
+void PCHDeclReader::VisitBlockDecl(BlockDecl *BD) {
+ VisitDecl(BD);
+ BD->setBody(cast_or_null<CompoundStmt>(Reader.ReadDeclStmt()));
+ unsigned NumParams = Record[Idx++];
+ llvm::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(*Reader.getContext(), Params.data(), NumParams);
+}
+
+std::pair<uint64_t, uint64_t>
+PCHDeclReader::VisitDeclContext(DeclContext *DC) {
+ uint64_t LexicalOffset = Record[Idx++];
+ uint64_t VisibleOffset = Record[Idx++];
+ return std::make_pair(LexicalOffset, VisibleOffset);
+}
+
+//===----------------------------------------------------------------------===//
+// Attribute Reading
+//===----------------------------------------------------------------------===//
+
+/// \brief Reads attributes from the current stream position.
+Attr *PCHReader::ReadAttributes() {
+ unsigned Code = DeclsCursor.ReadCode();
+ assert(Code == llvm::bitc::UNABBREV_RECORD &&
+ "Expected unabbreviated record"); (void)Code;
+
+ RecordData Record;
+ unsigned Idx = 0;
+ unsigned RecCode = DeclsCursor.ReadRecord(Code, Record);
+ assert(RecCode == pch::DECL_ATTR && "Expected attribute record");
+ (void)RecCode;
+
+#define SIMPLE_ATTR(Name) \
+ case Attr::Name: \
+ New = ::new (*Context) Name##Attr(); \
+ break
+
+#define STRING_ATTR(Name) \
+ case Attr::Name: \
+ New = ::new (*Context) Name##Attr(ReadString(Record, Idx)); \
+ break
+
+#define UNSIGNED_ATTR(Name) \
+ case Attr::Name: \
+ New = ::new (*Context) Name##Attr(Record[Idx++]); \
+ break
+
+ Attr *Attrs = 0;
+ while (Idx < Record.size()) {
+ Attr *New = 0;
+ Attr::Kind Kind = (Attr::Kind)Record[Idx++];
+ bool IsInherited = Record[Idx++];
+
+ switch (Kind) {
+ STRING_ATTR(Alias);
+ UNSIGNED_ATTR(Aligned);
+ SIMPLE_ATTR(AlwaysInline);
+ SIMPLE_ATTR(AnalyzerNoReturn);
+ STRING_ATTR(Annotate);
+ STRING_ATTR(AsmLabel);
+
+ case Attr::Blocks:
+ New = ::new (*Context) BlocksAttr(
+ (BlocksAttr::BlocksAttrTypes)Record[Idx++]);
+ break;
+
+ case Attr::Cleanup:
+ New = ::new (*Context) CleanupAttr(
+ cast<FunctionDecl>(GetDecl(Record[Idx++])));
+ break;
+
+ SIMPLE_ATTR(Const);
+ UNSIGNED_ATTR(Constructor);
+ SIMPLE_ATTR(DLLExport);
+ SIMPLE_ATTR(DLLImport);
+ SIMPLE_ATTR(Deprecated);
+ UNSIGNED_ATTR(Destructor);
+ SIMPLE_ATTR(FastCall);
+
+ case Attr::Format: {
+ std::string Type = ReadString(Record, Idx);
+ unsigned FormatIdx = Record[Idx++];
+ unsigned FirstArg = Record[Idx++];
+ New = ::new (*Context) FormatAttr(Type, FormatIdx, FirstArg);
+ break;
+ }
+
+ case Attr::FormatArg: {
+ unsigned FormatIdx = Record[Idx++];
+ New = ::new (*Context) FormatArgAttr(FormatIdx);
+ break;
+ }
+
+ case Attr::Sentinel: {
+ int sentinel = Record[Idx++];
+ int nullPos = Record[Idx++];
+ New = ::new (*Context) SentinelAttr(sentinel, nullPos);
+ break;
+ }
+
+ SIMPLE_ATTR(GNUInline);
+
+ case Attr::IBOutletKind:
+ New = ::new (*Context) IBOutletAttr();
+ break;
+
+ SIMPLE_ATTR(NoReturn);
+ SIMPLE_ATTR(NoThrow);
+ SIMPLE_ATTR(Nodebug);
+ SIMPLE_ATTR(Noinline);
+
+ case Attr::NonNull: {
+ unsigned Size = Record[Idx++];
+ llvm::SmallVector<unsigned, 16> ArgNums;
+ ArgNums.insert(ArgNums.end(), &Record[Idx], &Record[Idx] + Size);
+ Idx += Size;
+ New = ::new (*Context) NonNullAttr(ArgNums.data(), Size);
+ break;
+ }
+
+ SIMPLE_ATTR(ObjCException);
+ SIMPLE_ATTR(ObjCNSObject);
+ SIMPLE_ATTR(CFReturnsRetained);
+ SIMPLE_ATTR(NSReturnsRetained);
+ SIMPLE_ATTR(Overloadable);
+ UNSIGNED_ATTR(Packed);
+ SIMPLE_ATTR(Pure);
+ UNSIGNED_ATTR(Regparm);
+ STRING_ATTR(Section);
+ SIMPLE_ATTR(StdCall);
+ SIMPLE_ATTR(TransparentUnion);
+ SIMPLE_ATTR(Unavailable);
+ SIMPLE_ATTR(Unused);
+ SIMPLE_ATTR(Used);
+
+ case Attr::Visibility:
+ New = ::new (*Context) VisibilityAttr(
+ (VisibilityAttr::VisibilityTypes)Record[Idx++]);
+ break;
+
+ SIMPLE_ATTR(WarnUnusedResult);
+ SIMPLE_ATTR(Weak);
+ SIMPLE_ATTR(WeakImport);
+ }
+
+ assert(New && "Unable to decode attribute?");
+ New->setInherited(IsInherited);
+ New->setNext(Attrs);
+ Attrs = New;
+ }
+#undef UNSIGNED_ATTR
+#undef STRING_ATTR
+#undef SIMPLE_ATTR
+
+ // The list of attributes was built backwards. Reverse the list
+ // before returning it.
+ Attr *PrevAttr = 0, *NextAttr = 0;
+ while (Attrs) {
+ NextAttr = Attrs->getNext();
+ Attrs->setNext(PrevAttr);
+ PrevAttr = Attrs;
+ Attrs = NextAttr;
+ }
+
+ return PrevAttr;
+}
+
+//===----------------------------------------------------------------------===//
+// PCHReader Implementation
+//===----------------------------------------------------------------------===//
+
+/// \brief Note that we have loaded the declaration with the given
+/// Index.
+///
+/// This routine notes that this declaration has already been loaded,
+/// so that future GetDecl calls will return this declaration rather
+/// than trying to load a new declaration.
+inline void PCHReader::LoadedDecl(unsigned Index, Decl *D) {
+ assert(!DeclsLoaded[Index] && "Decl loaded twice?");
+ DeclsLoaded[Index] = D;
+}
+
+
+/// \brief Determine whether the consumer will be interested in seeing
+/// this declaration (via HandleTopLevelDecl).
+///
+/// This routine should return true for anything that might affect
+/// code generation, e.g., inline function definitions, Objective-C
+/// declarations with metadata, etc.
+static bool isConsumerInterestedIn(Decl *D) {
+ if (VarDecl *Var = dyn_cast<VarDecl>(D))
+ return Var->isFileVarDecl() && Var->getInit();
+ if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
+ return Func->isThisDeclarationADefinition();
+ return isa<ObjCProtocolDecl>(D);
+}
+
+/// \brief Read the declaration at the given offset from the PCH file.
+Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
+ // Keep track of where we are in the stream, then jump back there
+ // after reading this declaration.
+ SavedStreamPosition SavedPosition(DeclsCursor);
+
+ DeclsCursor.JumpToBit(Offset);
+ RecordData Record;
+ unsigned Code = DeclsCursor.ReadCode();
+ unsigned Idx = 0;
+ PCHDeclReader Reader(*this, Record, Idx);
+
+ Decl *D = 0;
+ switch ((pch::DeclCode)DeclsCursor.ReadRecord(Code, Record)) {
+ case pch::DECL_ATTR:
+ case pch::DECL_CONTEXT_LEXICAL:
+ case pch::DECL_CONTEXT_VISIBLE:
+ assert(false && "Record cannot be de-serialized with ReadDeclRecord");
+ break;
+ case pch::DECL_TRANSLATION_UNIT:
+ assert(Index == 0 && "Translation unit must be at index 0");
+ D = Context->getTranslationUnitDecl();
+ break;
+ case pch::DECL_TYPEDEF:
+ D = TypedefDecl::Create(*Context, 0, SourceLocation(), 0, QualType());
+ break;
+ case pch::DECL_ENUM:
+ D = EnumDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ break;
+ case pch::DECL_RECORD:
+ D = RecordDecl::Create(*Context, TagDecl::TK_struct, 0, SourceLocation(),
+ 0, 0);
+ break;
+ case pch::DECL_ENUM_CONSTANT:
+ D = EnumConstantDecl::Create(*Context, 0, SourceLocation(), 0, QualType(),
+ 0, llvm::APSInt());
+ break;
+ case pch::DECL_FUNCTION:
+ D = FunctionDecl::Create(*Context, 0, SourceLocation(), DeclarationName(),
+ QualType());
+ break;
+ case pch::DECL_OBJC_METHOD:
+ D = ObjCMethodDecl::Create(*Context, SourceLocation(), SourceLocation(),
+ Selector(), QualType(), 0);
+ break;
+ case pch::DECL_OBJC_INTERFACE:
+ D = ObjCInterfaceDecl::Create(*Context, 0, SourceLocation(), 0);
+ break;
+ case pch::DECL_OBJC_IVAR:
+ D = ObjCIvarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(),
+ ObjCIvarDecl::None);
+ break;
+ case pch::DECL_OBJC_PROTOCOL:
+ D = ObjCProtocolDecl::Create(*Context, 0, SourceLocation(), 0);
+ break;
+ case pch::DECL_OBJC_AT_DEFS_FIELD:
+ D = ObjCAtDefsFieldDecl::Create(*Context, 0, SourceLocation(), 0,
+ QualType(), 0);
+ break;
+ case pch::DECL_OBJC_CLASS:
+ D = ObjCClassDecl::Create(*Context, 0, SourceLocation());
+ break;
+ case pch::DECL_OBJC_FORWARD_PROTOCOL:
+ D = ObjCForwardProtocolDecl::Create(*Context, 0, SourceLocation());
+ break;
+ case pch::DECL_OBJC_CATEGORY:
+ D = ObjCCategoryDecl::Create(*Context, 0, SourceLocation(), 0);
+ break;
+ case pch::DECL_OBJC_CATEGORY_IMPL:
+ D = ObjCCategoryImplDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ break;
+ case pch::DECL_OBJC_IMPLEMENTATION:
+ D = ObjCImplementationDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ break;
+ case pch::DECL_OBJC_COMPATIBLE_ALIAS:
+ D = ObjCCompatibleAliasDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ break;
+ case pch::DECL_OBJC_PROPERTY:
+ D = ObjCPropertyDecl::Create(*Context, 0, SourceLocation(), 0, QualType());
+ break;
+ case pch::DECL_OBJC_PROPERTY_IMPL:
+ D = ObjCPropertyImplDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(), 0,
+ ObjCPropertyImplDecl::Dynamic, 0);
+ break;
+ case pch::DECL_FIELD:
+ D = FieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
+ false);
+ break;
+ case pch::DECL_VAR:
+ D = VarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(),
+ VarDecl::None, SourceLocation());
+ break;
+
+ case pch::DECL_IMPLICIT_PARAM:
+ D = ImplicitParamDecl::Create(*Context, 0, SourceLocation(), 0, QualType());
+ break;
+
+ case pch::DECL_PARM_VAR:
+ D = ParmVarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(),
+ VarDecl::None, 0);
+ break;
+ case pch::DECL_ORIGINAL_PARM_VAR:
+ D = OriginalParmVarDecl::Create(*Context, 0, SourceLocation(), 0,
+ QualType(), QualType(), VarDecl::None, 0);
+ break;
+ case pch::DECL_FILE_SCOPE_ASM:
+ D = FileScopeAsmDecl::Create(*Context, 0, SourceLocation(), 0);
+ break;
+ case pch::DECL_BLOCK:
+ D = BlockDecl::Create(*Context, 0, SourceLocation());
+ break;
+ }
+
+ assert(D && "Unknown declaration reading PCH file");
+ LoadedDecl(Index, D);
+ Reader.Visit(D);
+
+ // If this declaration is also a declaration context, get the
+ // offsets for its tables of lexical and visible declarations.
+ if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
+ 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);
+ DeclContextOffsets[DC] = Offsets;
+ }
+ }
+ assert(Idx == Record.size());
+
+ // If we have deserialized a declaration that has a definition the
+ // AST consumer might need to know about, notify the consumer
+ // about that definition now or queue it for later.
+ if (isConsumerInterestedIn(D)) {
+ if (Consumer) {
+ DeclGroupRef DG(D);
+ Consumer->HandleTopLevelDecl(DG);
+ } else {
+ InterestingDecls.push_back(D);
+ }
+ }
+
+ return D;
+}
+
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
new file mode 100644
index 000000000000..10059f609b10
--- /dev/null
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -0,0 +1,1136 @@
+//===--- PCHReaderStmt.cpp - Stmt/Expr Deserialization ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Statement/expression deserialization. This implements the
+// PCHReader::ReadStmt method.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PCHReader.h"
+#include "clang/AST/StmtVisitor.h"
+using namespace clang;
+
+namespace {
+ class PCHStmtReader : public StmtVisitor<PCHStmtReader, unsigned> {
+ PCHReader &Reader;
+ const PCHReader::RecordData &Record;
+ unsigned &Idx;
+ llvm::SmallVectorImpl<Stmt *> &StmtStack;
+
+ public:
+ PCHStmtReader(PCHReader &Reader, const PCHReader::RecordData &Record,
+ unsigned &Idx, llvm::SmallVectorImpl<Stmt *> &StmtStack)
+ : Reader(Reader), Record(Record), Idx(Idx), StmtStack(StmtStack) { }
+
+ /// \brief The number of record fields required for the Stmt class
+ /// itself.
+ static const unsigned NumStmtFields = 0;
+
+ /// \brief The number of record fields required for the Expr class
+ /// itself.
+ static const unsigned NumExprFields = NumStmtFields + 3;
+
+ // Each of the Visit* functions reads in part of the expression
+ // from the given record and the current expression stack, then
+ // return the total number of operands that it read from the
+ // expression stack.
+
+ unsigned VisitStmt(Stmt *S);
+ unsigned VisitNullStmt(NullStmt *S);
+ unsigned VisitCompoundStmt(CompoundStmt *S);
+ unsigned VisitSwitchCase(SwitchCase *S);
+ unsigned VisitCaseStmt(CaseStmt *S);
+ unsigned VisitDefaultStmt(DefaultStmt *S);
+ unsigned VisitLabelStmt(LabelStmt *S);
+ unsigned VisitIfStmt(IfStmt *S);
+ unsigned VisitSwitchStmt(SwitchStmt *S);
+ unsigned VisitWhileStmt(WhileStmt *S);
+ unsigned VisitDoStmt(DoStmt *S);
+ unsigned VisitForStmt(ForStmt *S);
+ unsigned VisitGotoStmt(GotoStmt *S);
+ unsigned VisitIndirectGotoStmt(IndirectGotoStmt *S);
+ unsigned VisitContinueStmt(ContinueStmt *S);
+ unsigned VisitBreakStmt(BreakStmt *S);
+ unsigned VisitReturnStmt(ReturnStmt *S);
+ unsigned VisitDeclStmt(DeclStmt *S);
+ unsigned VisitAsmStmt(AsmStmt *S);
+ unsigned VisitExpr(Expr *E);
+ unsigned VisitPredefinedExpr(PredefinedExpr *E);
+ unsigned VisitDeclRefExpr(DeclRefExpr *E);
+ unsigned VisitIntegerLiteral(IntegerLiteral *E);
+ unsigned VisitFloatingLiteral(FloatingLiteral *E);
+ unsigned VisitImaginaryLiteral(ImaginaryLiteral *E);
+ unsigned VisitStringLiteral(StringLiteral *E);
+ unsigned VisitCharacterLiteral(CharacterLiteral *E);
+ unsigned VisitParenExpr(ParenExpr *E);
+ unsigned VisitUnaryOperator(UnaryOperator *E);
+ unsigned VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+ unsigned VisitArraySubscriptExpr(ArraySubscriptExpr *E);
+ unsigned VisitCallExpr(CallExpr *E);
+ unsigned VisitMemberExpr(MemberExpr *E);
+ unsigned VisitCastExpr(CastExpr *E);
+ unsigned VisitBinaryOperator(BinaryOperator *E);
+ unsigned VisitCompoundAssignOperator(CompoundAssignOperator *E);
+ unsigned VisitConditionalOperator(ConditionalOperator *E);
+ unsigned VisitImplicitCastExpr(ImplicitCastExpr *E);
+ unsigned VisitExplicitCastExpr(ExplicitCastExpr *E);
+ unsigned VisitCStyleCastExpr(CStyleCastExpr *E);
+ unsigned VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
+ unsigned VisitExtVectorElementExpr(ExtVectorElementExpr *E);
+ unsigned VisitInitListExpr(InitListExpr *E);
+ unsigned VisitDesignatedInitExpr(DesignatedInitExpr *E);
+ unsigned VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
+ unsigned VisitVAArgExpr(VAArgExpr *E);
+ unsigned VisitAddrLabelExpr(AddrLabelExpr *E);
+ unsigned VisitStmtExpr(StmtExpr *E);
+ unsigned VisitTypesCompatibleExpr(TypesCompatibleExpr *E);
+ unsigned VisitChooseExpr(ChooseExpr *E);
+ unsigned VisitGNUNullExpr(GNUNullExpr *E);
+ unsigned VisitShuffleVectorExpr(ShuffleVectorExpr *E);
+ unsigned VisitBlockExpr(BlockExpr *E);
+ unsigned VisitBlockDeclRefExpr(BlockDeclRefExpr *E);
+ unsigned VisitObjCStringLiteral(ObjCStringLiteral *E);
+ unsigned VisitObjCEncodeExpr(ObjCEncodeExpr *E);
+ unsigned VisitObjCSelectorExpr(ObjCSelectorExpr *E);
+ unsigned VisitObjCProtocolExpr(ObjCProtocolExpr *E);
+ unsigned VisitObjCIvarRefExpr(ObjCIvarRefExpr *E);
+ unsigned VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
+ unsigned VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
+ unsigned VisitObjCMessageExpr(ObjCMessageExpr *E);
+ unsigned VisitObjCSuperExpr(ObjCSuperExpr *E);
+
+ unsigned VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
+ unsigned VisitObjCAtCatchStmt(ObjCAtCatchStmt *);
+ unsigned VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *);
+ unsigned VisitObjCAtTryStmt(ObjCAtTryStmt *);
+ unsigned VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *);
+ unsigned VisitObjCAtThrowStmt(ObjCAtThrowStmt *);
+ };
+}
+
+unsigned PCHStmtReader::VisitStmt(Stmt *S) {
+ assert(Idx == NumStmtFields && "Incorrect statement field count");
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitNullStmt(NullStmt *S) {
+ VisitStmt(S);
+ S->setSemiLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitCompoundStmt(CompoundStmt *S) {
+ VisitStmt(S);
+ unsigned NumStmts = Record[Idx++];
+ S->setStmts(*Reader.getContext(),
+ StmtStack.data() + StmtStack.size() - NumStmts, NumStmts);
+ S->setLBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setRBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return NumStmts;
+}
+
+unsigned PCHStmtReader::VisitSwitchCase(SwitchCase *S) {
+ VisitStmt(S);
+ Reader.RecordSwitchCaseID(S, Record[Idx++]);
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitCaseStmt(CaseStmt *S) {
+ VisitSwitchCase(S);
+ S->setLHS(cast<Expr>(StmtStack[StmtStack.size() - 3]));
+ S->setRHS(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2]));
+ S->setSubStmt(StmtStack.back());
+ S->setCaseLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setEllipsisLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 3;
+}
+
+unsigned PCHStmtReader::VisitDefaultStmt(DefaultStmt *S) {
+ VisitSwitchCase(S);
+ S->setSubStmt(StmtStack.back());
+ S->setDefaultLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitLabelStmt(LabelStmt *S) {
+ VisitStmt(S);
+ S->setID(Reader.GetIdentifierInfo(Record, Idx));
+ S->setSubStmt(StmtStack.back());
+ S->setIdentLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ Reader.RecordLabelStmt(S, Record[Idx++]);
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitIfStmt(IfStmt *S) {
+ VisitStmt(S);
+ S->setCond(cast<Expr>(StmtStack[StmtStack.size() - 3]));
+ S->setThen(StmtStack[StmtStack.size() - 2]);
+ S->setElse(StmtStack[StmtStack.size() - 1]);
+ S->setIfLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setElseLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 3;
+}
+
+unsigned PCHStmtReader::VisitSwitchStmt(SwitchStmt *S) {
+ VisitStmt(S);
+ S->setCond(cast<Expr>(StmtStack[StmtStack.size() - 2]));
+ S->setBody(StmtStack.back());
+ S->setSwitchLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ SwitchCase *PrevSC = 0;
+ for (unsigned N = Record.size(); Idx != N; ++Idx) {
+ SwitchCase *SC = Reader.getSwitchCaseWithID(Record[Idx]);
+ if (PrevSC)
+ PrevSC->setNextSwitchCase(SC);
+ else
+ S->setSwitchCaseList(SC);
+ PrevSC = SC;
+ }
+ return 2;
+}
+
+unsigned PCHStmtReader::VisitWhileStmt(WhileStmt *S) {
+ VisitStmt(S);
+ S->setCond(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2]));
+ S->setBody(StmtStack.back());
+ S->setWhileLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 2;
+}
+
+unsigned PCHStmtReader::VisitDoStmt(DoStmt *S) {
+ VisitStmt(S);
+ S->setCond(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2]));
+ S->setBody(StmtStack.back());
+ S->setDoLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setWhileLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 2;
+}
+
+unsigned PCHStmtReader::VisitForStmt(ForStmt *S) {
+ VisitStmt(S);
+ S->setInit(StmtStack[StmtStack.size() - 4]);
+ S->setCond(cast_or_null<Expr>(StmtStack[StmtStack.size() - 3]));
+ S->setInc(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2]));
+ S->setBody(StmtStack.back());
+ S->setForLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 4;
+}
+
+unsigned PCHStmtReader::VisitGotoStmt(GotoStmt *S) {
+ VisitStmt(S);
+ Reader.SetLabelOf(S, Record[Idx++]);
+ S->setGotoLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setLabelLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
+ VisitStmt(S);
+ S->setGotoLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setTarget(cast_or_null<Expr>(StmtStack.back()));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitContinueStmt(ContinueStmt *S) {
+ VisitStmt(S);
+ S->setContinueLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitBreakStmt(BreakStmt *S) {
+ VisitStmt(S);
+ S->setBreakLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitReturnStmt(ReturnStmt *S) {
+ VisitStmt(S);
+ S->setRetValue(cast_or_null<Expr>(StmtStack.back()));
+ S->setReturnLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitDeclStmt(DeclStmt *S) {
+ VisitStmt(S);
+ S->setStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+
+ if (Idx + 1 == Record.size()) {
+ // Single declaration
+ S->setDeclGroup(DeclGroupRef(Reader.GetDecl(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(),
+ Decls.data(),
+ Decls.size())));
+ }
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitAsmStmt(AsmStmt *S) {
+ VisitStmt(S);
+ unsigned NumOutputs = Record[Idx++];
+ unsigned NumInputs = Record[Idx++];
+ unsigned NumClobbers = Record[Idx++];
+ S->setAsmLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setVolatile(Record[Idx++]);
+ S->setSimple(Record[Idx++]);
+
+ unsigned StackIdx
+ = StmtStack.size() - (NumOutputs*2 + NumInputs*2 + NumClobbers + 1);
+ S->setAsmString(cast_or_null<StringLiteral>(StmtStack[StackIdx++]));
+
+ // Outputs and inputs
+ llvm::SmallVector<std::string, 16> Names;
+ llvm::SmallVector<StringLiteral*, 16> Constraints;
+ llvm::SmallVector<Stmt*, 16> Exprs;
+ for (unsigned I = 0, N = NumOutputs + NumInputs; I != N; ++I) {
+ Names.push_back(Reader.ReadString(Record, Idx));
+ Constraints.push_back(cast_or_null<StringLiteral>(StmtStack[StackIdx++]));
+ Exprs.push_back(StmtStack[StackIdx++]);
+ }
+ S->setOutputsAndInputs(NumOutputs, NumInputs,
+ Names.data(), Constraints.data(), Exprs.data());
+
+ // Constraints
+ llvm::SmallVector<StringLiteral*, 16> Clobbers;
+ for (unsigned I = 0; I != NumClobbers; ++I)
+ Clobbers.push_back(cast_or_null<StringLiteral>(StmtStack[StackIdx++]));
+ S->setClobbers(Clobbers.data(), NumClobbers);
+
+ assert(StackIdx == StmtStack.size() && "Error deserializing AsmStmt");
+ return NumOutputs*2 + NumInputs*2 + NumClobbers + 1;
+}
+
+unsigned PCHStmtReader::VisitExpr(Expr *E) {
+ VisitStmt(E);
+ E->setType(Reader.GetType(Record[Idx++]));
+ E->setTypeDependent(Record[Idx++]);
+ E->setValueDependent(Record[Idx++]);
+ assert(Idx == NumExprFields && "Incorrect expression field count");
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitPredefinedExpr(PredefinedExpr *E) {
+ VisitExpr(E);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setIdentType((PredefinedExpr::IdentType)Record[Idx++]);
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
+ VisitExpr(E);
+ E->setDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitIntegerLiteral(IntegerLiteral *E) {
+ VisitExpr(E);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setValue(Reader.ReadAPInt(Record, Idx));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitFloatingLiteral(FloatingLiteral *E) {
+ VisitExpr(E);
+ E->setValue(Reader.ReadAPFloat(Record, Idx));
+ E->setExact(Record[Idx++]);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitImaginaryLiteral(ImaginaryLiteral *E) {
+ VisitExpr(E);
+ E->setSubExpr(cast<Expr>(StmtStack.back()));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitStringLiteral(StringLiteral *E) {
+ VisitExpr(E);
+ unsigned Len = Record[Idx++];
+ assert(Record[Idx] == E->getNumConcatenated() &&
+ "Wrong number of concatenated tokens!");
+ ++Idx;
+ E->setWide(Record[Idx++]);
+
+ // Read string data
+ llvm::SmallVector<char, 16> Str(&Record[Idx], &Record[Idx] + Len);
+ E->setStrData(*Reader.getContext(), Str.data(), Len);
+ Idx += Len;
+
+ // Read source locations
+ for (unsigned I = 0, N = E->getNumConcatenated(); I != N; ++I)
+ E->setStrTokenLoc(I, SourceLocation::getFromRawEncoding(Record[Idx++]));
+
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitCharacterLiteral(CharacterLiteral *E) {
+ VisitExpr(E);
+ E->setValue(Record[Idx++]);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setWide(Record[Idx++]);
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitParenExpr(ParenExpr *E) {
+ VisitExpr(E);
+ E->setLParen(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParen(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setSubExpr(cast<Expr>(StmtStack.back()));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitUnaryOperator(UnaryOperator *E) {
+ VisitExpr(E);
+ E->setSubExpr(cast<Expr>(StmtStack.back()));
+ E->setOpcode((UnaryOperator::Opcode)Record[Idx++]);
+ E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+ VisitExpr(E);
+ E->setSizeof(Record[Idx++]);
+ if (Record[Idx] == 0) {
+ E->setArgument(cast<Expr>(StmtStack.back()));
+ ++Idx;
+ } else {
+ E->setArgument(Reader.GetType(Record[Idx++]));
+ }
+ E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return E->isArgumentType()? 0 : 1;
+}
+
+unsigned PCHStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+ VisitExpr(E);
+ E->setLHS(cast<Expr>(StmtStack[StmtStack.size() - 2]));
+ E->setRHS(cast<Expr>(StmtStack[StmtStack.size() - 1]));
+ E->setRBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 2;
+}
+
+unsigned PCHStmtReader::VisitCallExpr(CallExpr *E) {
+ VisitExpr(E);
+ E->setNumArgs(*Reader.getContext(), Record[Idx++]);
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setCallee(cast<Expr>(StmtStack[StmtStack.size() - E->getNumArgs() - 1]));
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I]));
+ return E->getNumArgs() + 1;
+}
+
+unsigned PCHStmtReader::VisitMemberExpr(MemberExpr *E) {
+ VisitExpr(E);
+ E->setBase(cast<Expr>(StmtStack.back()));
+ E->setMemberDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setMemberLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setArrow(Record[Idx++]);
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitCastExpr(CastExpr *E) {
+ VisitExpr(E);
+ E->setSubExpr(cast<Expr>(StmtStack.back()));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitBinaryOperator(BinaryOperator *E) {
+ VisitExpr(E);
+ E->setLHS(cast<Expr>(StmtStack.end()[-2]));
+ E->setRHS(cast<Expr>(StmtStack.end()[-1]));
+ E->setOpcode((BinaryOperator::Opcode)Record[Idx++]);
+ E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 2;
+}
+
+unsigned PCHStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
+ VisitBinaryOperator(E);
+ E->setComputationLHSType(Reader.GetType(Record[Idx++]));
+ E->setComputationResultType(Reader.GetType(Record[Idx++]));
+ return 2;
+}
+
+unsigned PCHStmtReader::VisitConditionalOperator(ConditionalOperator *E) {
+ VisitExpr(E);
+ E->setCond(cast<Expr>(StmtStack[StmtStack.size() - 3]));
+ E->setLHS(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2]));
+ E->setRHS(cast_or_null<Expr>(StmtStack[StmtStack.size() - 1]));
+ return 3;
+}
+
+unsigned PCHStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ VisitCastExpr(E);
+ E->setLvalueCast(Record[Idx++]);
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitExplicitCastExpr(ExplicitCastExpr *E) {
+ VisitCastExpr(E);
+ E->setTypeAsWritten(Reader.GetType(Record[Idx++]));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitCStyleCastExpr(CStyleCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ E->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ VisitExpr(E);
+ E->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setInitializer(cast<Expr>(StmtStack.back()));
+ E->setFileScope(Record[Idx++]);
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
+ VisitExpr(E);
+ E->setBase(cast<Expr>(StmtStack.back()));
+ E->setAccessor(Reader.GetIdentifierInfo(Record, Idx));
+ E->setAccessorLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitInitListExpr(InitListExpr *E) {
+ VisitExpr(E);
+ unsigned NumInits = Record[Idx++];
+ E->reserveInits(NumInits);
+ for (unsigned I = 0; I != NumInits; ++I)
+ E->updateInit(I,
+ cast<Expr>(StmtStack[StmtStack.size() - NumInits - 1 + I]));
+ E->setSyntacticForm(cast_or_null<InitListExpr>(StmtStack.back()));
+ E->setLBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setInitializedFieldInUnion(
+ cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])));
+ E->sawArrayRangeDesignator(Record[Idx++]);
+ return NumInits + 1;
+}
+
+unsigned PCHStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
+ typedef DesignatedInitExpr::Designator Designator;
+
+ VisitExpr(E);
+ unsigned NumSubExprs = Record[Idx++];
+ assert(NumSubExprs == E->getNumSubExprs() && "Wrong number of subexprs");
+ for (unsigned I = 0; I != NumSubExprs; ++I)
+ E->setSubExpr(I, cast<Expr>(StmtStack[StmtStack.size() - NumSubExprs + I]));
+ E->setEqualOrColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setGNUSyntax(Record[Idx++]);
+
+ llvm::SmallVector<Designator, 4> Designators;
+ while (Idx < Record.size()) {
+ switch ((pch::DesignatorTypes)Record[Idx++]) {
+ case pch::DESIG_FIELD_DECL: {
+ FieldDecl *Field = cast<FieldDecl>(Reader.GetDecl(Record[Idx++]));
+ SourceLocation DotLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation FieldLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ Designators.push_back(Designator(Field->getIdentifier(), DotLoc,
+ FieldLoc));
+ Designators.back().setField(Field);
+ break;
+ }
+
+ case pch::DESIG_FIELD_NAME: {
+ const IdentifierInfo *Name = Reader.GetIdentifierInfo(Record, Idx);
+ SourceLocation DotLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation FieldLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ Designators.push_back(Designator(Name, DotLoc, FieldLoc));
+ break;
+ }
+
+ case pch::DESIG_ARRAY: {
+ unsigned Index = Record[Idx++];
+ SourceLocation LBracketLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation RBracketLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ Designators.push_back(Designator(Index, LBracketLoc, RBracketLoc));
+ break;
+ }
+
+ case pch::DESIG_ARRAY_RANGE: {
+ unsigned Index = Record[Idx++];
+ SourceLocation LBracketLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation EllipsisLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation RBracketLoc
+ = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ Designators.push_back(Designator(Index, LBracketLoc, EllipsisLoc,
+ RBracketLoc));
+ break;
+ }
+ }
+ }
+ E->setDesignators(Designators.data(), Designators.size());
+
+ return NumSubExprs;
+}
+
+unsigned PCHStmtReader::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
+ VisitExpr(E);
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitVAArgExpr(VAArgExpr *E) {
+ VisitExpr(E);
+ E->setSubExpr(cast<Expr>(StmtStack.back()));
+ E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) {
+ VisitExpr(E);
+ E->setAmpAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setLabelLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ Reader.SetLabelOf(E, Record[Idx++]);
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitStmtExpr(StmtExpr *E) {
+ VisitExpr(E);
+ E->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setSubStmt(cast_or_null<CompoundStmt>(StmtStack.back()));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) {
+ VisitExpr(E);
+ E->setArgType1(Reader.GetType(Record[Idx++]));
+ E->setArgType2(Reader.GetType(Record[Idx++]));
+ E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitChooseExpr(ChooseExpr *E) {
+ VisitExpr(E);
+ E->setCond(cast<Expr>(StmtStack[StmtStack.size() - 3]));
+ E->setLHS(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2]));
+ E->setRHS(cast_or_null<Expr>(StmtStack[StmtStack.size() - 1]));
+ E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 3;
+}
+
+unsigned PCHStmtReader::VisitGNUNullExpr(GNUNullExpr *E) {
+ VisitExpr(E);
+ E->setTokenLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
+ VisitExpr(E);
+ unsigned NumExprs = Record[Idx++];
+ E->setExprs((Expr **)&StmtStack[StmtStack.size() - NumExprs], NumExprs);
+ E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return NumExprs;
+}
+
+unsigned PCHStmtReader::VisitBlockExpr(BlockExpr *E) {
+ VisitExpr(E);
+ E->setBlockDecl(cast_or_null<BlockDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setHasBlockDeclRefExprs(Record[Idx++]);
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
+ VisitExpr(E);
+ E->setDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setByRef(Record[Idx++]);
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// Objective-C Expressions and Statements
+
+unsigned PCHStmtReader::VisitObjCStringLiteral(ObjCStringLiteral *E) {
+ VisitExpr(E);
+ E->setString(cast<StringLiteral>(StmtStack.back()));
+ E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
+ VisitExpr(E);
+ E->setEncodedType(Reader.GetType(Record[Idx++]));
+ E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
+ VisitExpr(E);
+ E->setSelector(Reader.GetSelector(Record, Idx));
+ E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
+ VisitExpr(E);
+ E->setProtocol(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ VisitExpr(E);
+ E->setDecl(cast<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setBase(cast<Expr>(StmtStack.back()));
+ E->setIsArrow(Record[Idx++]);
+ E->setIsFreeIvar(Record[Idx++]);
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
+ VisitExpr(E);
+ E->setProperty(cast<ObjCPropertyDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setBase(cast<Expr>(StmtStack.back()));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
+ VisitExpr(E);
+ E->setGetterMethod(
+ cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setSetterMethod(
+ cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setClassProp(
+ cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setBase(cast_or_null<Expr>(StmtStack.back()));
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ VisitExpr(E);
+ E->setNumArgs(Record[Idx++]);
+ E->setLeftLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRightLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setSelector(Reader.GetSelector(Record, Idx));
+ E->setMethodDecl(cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
+
+ E->setReceiver(
+ cast_or_null<Expr>(StmtStack[StmtStack.size() - E->getNumArgs() - 1]));
+ if (!E->getReceiver()) {
+ ObjCMessageExpr::ClassInfo CI;
+ CI.first = cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]));
+ CI.second = Reader.GetIdentifierInfo(Record, Idx);
+ E->setClassInfo(CI);
+ }
+
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I]));
+ return E->getNumArgs() + 1;
+}
+
+unsigned PCHStmtReader::VisitObjCSuperExpr(ObjCSuperExpr *E) {
+ VisitExpr(E);
+ E->setLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
+ VisitStmt(S);
+ S->setElement(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 3]));
+ S->setCollection(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2]));
+ S->setBody(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1]));
+ S->setForLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 3;
+}
+
+unsigned PCHStmtReader::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
+ VisitStmt(S);
+ S->setCatchBody(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 2]));
+ S->setNextCatchStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1]));
+ S->setCatchParamDecl(cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setAtCatchLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 2;
+}
+
+unsigned PCHStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
+ VisitStmt(S);
+ S->setFinallyBody(StmtStack.back());
+ S->setAtFinallyLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
+ VisitStmt(S);
+ S->setTryBody(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 3]));
+ S->setCatchStmts(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 2]));
+ S->setFinallyStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1]));
+ S->setAtTryLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 3;
+}
+
+unsigned PCHStmtReader::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
+ VisitStmt(S);
+ S->setSynchExpr(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 2]));
+ S->setSynchBody(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1]));
+ S->setAtSynchronizedLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 2;
+}
+
+unsigned PCHStmtReader::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
+ VisitStmt(S);
+ S->setThrowExpr(StmtStack.back());
+ S->setThrowLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 1;
+}
+
+
+// Within the bitstream, expressions are stored in Reverse Polish
+// Notation, with each of the subexpressions preceding the
+// expression they are stored in. To evaluate expressions, we
+// continue reading expressions and placing them on 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 *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
+ RecordData Record;
+ unsigned Idx;
+ llvm::SmallVector<Stmt *, 16> StmtStack;
+ PCHStmtReader Reader(*this, Record, Idx, StmtStack);
+ Stmt::EmptyShell Empty;
+
+ while (true) {
+ unsigned Code = Cursor.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Cursor.ReadBlockEnd()) {
+ Error("error at end of block in PCH file");
+ return 0;
+ }
+ break;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Cursor.ReadSubBlockID();
+ if (Cursor.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return 0;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Cursor.ReadAbbrevRecord();
+ continue;
+ }
+
+ Stmt *S = 0;
+ Idx = 0;
+ Record.clear();
+ bool Finished = false;
+ switch ((pch::StmtCode)Cursor.ReadRecord(Code, Record)) {
+ case pch::STMT_STOP:
+ Finished = true;
+ break;
+
+ case pch::STMT_NULL_PTR:
+ S = 0;
+ break;
+
+ case pch::STMT_NULL:
+ S = new (Context) NullStmt(Empty);
+ break;
+
+ case pch::STMT_COMPOUND:
+ S = new (Context) CompoundStmt(Empty);
+ break;
+
+ case pch::STMT_CASE:
+ S = new (Context) CaseStmt(Empty);
+ break;
+
+ case pch::STMT_DEFAULT:
+ S = new (Context) DefaultStmt(Empty);
+ break;
+
+ case pch::STMT_LABEL:
+ S = new (Context) LabelStmt(Empty);
+ break;
+
+ case pch::STMT_IF:
+ S = new (Context) IfStmt(Empty);
+ break;
+
+ case pch::STMT_SWITCH:
+ S = new (Context) SwitchStmt(Empty);
+ break;
+
+ case pch::STMT_WHILE:
+ S = new (Context) WhileStmt(Empty);
+ break;
+
+ case pch::STMT_DO:
+ S = new (Context) DoStmt(Empty);
+ break;
+
+ case pch::STMT_FOR:
+ S = new (Context) ForStmt(Empty);
+ break;
+
+ case pch::STMT_GOTO:
+ S = new (Context) GotoStmt(Empty);
+ break;
+
+ case pch::STMT_INDIRECT_GOTO:
+ S = new (Context) IndirectGotoStmt(Empty);
+ break;
+
+ case pch::STMT_CONTINUE:
+ S = new (Context) ContinueStmt(Empty);
+ break;
+
+ case pch::STMT_BREAK:
+ S = new (Context) BreakStmt(Empty);
+ break;
+
+ case pch::STMT_RETURN:
+ S = new (Context) ReturnStmt(Empty);
+ break;
+
+ case pch::STMT_DECL:
+ S = new (Context) DeclStmt(Empty);
+ break;
+
+ case pch::STMT_ASM:
+ S = new (Context) AsmStmt(Empty);
+ break;
+
+ case pch::EXPR_PREDEFINED:
+ S = new (Context) PredefinedExpr(Empty);
+ break;
+
+ case pch::EXPR_DECL_REF:
+ S = new (Context) DeclRefExpr(Empty);
+ break;
+
+ case pch::EXPR_INTEGER_LITERAL:
+ S = new (Context) IntegerLiteral(Empty);
+ break;
+
+ case pch::EXPR_FLOATING_LITERAL:
+ S = new (Context) FloatingLiteral(Empty);
+ break;
+
+ case pch::EXPR_IMAGINARY_LITERAL:
+ S = new (Context) ImaginaryLiteral(Empty);
+ break;
+
+ case pch::EXPR_STRING_LITERAL:
+ S = StringLiteral::CreateEmpty(*Context,
+ Record[PCHStmtReader::NumExprFields + 1]);
+ break;
+
+ case pch::EXPR_CHARACTER_LITERAL:
+ S = new (Context) CharacterLiteral(Empty);
+ break;
+
+ case pch::EXPR_PAREN:
+ S = new (Context) ParenExpr(Empty);
+ break;
+
+ case pch::EXPR_UNARY_OPERATOR:
+ S = new (Context) UnaryOperator(Empty);
+ break;
+
+ case pch::EXPR_SIZEOF_ALIGN_OF:
+ S = new (Context) SizeOfAlignOfExpr(Empty);
+ break;
+
+ case pch::EXPR_ARRAY_SUBSCRIPT:
+ S = new (Context) ArraySubscriptExpr(Empty);
+ break;
+
+ case pch::EXPR_CALL:
+ S = new (Context) CallExpr(*Context, Empty);
+ break;
+
+ case pch::EXPR_MEMBER:
+ S = new (Context) MemberExpr(Empty);
+ break;
+
+ case pch::EXPR_BINARY_OPERATOR:
+ S = new (Context) BinaryOperator(Empty);
+ break;
+
+ case pch::EXPR_COMPOUND_ASSIGN_OPERATOR:
+ S = new (Context) CompoundAssignOperator(Empty);
+ break;
+
+ case pch::EXPR_CONDITIONAL_OPERATOR:
+ S = new (Context) ConditionalOperator(Empty);
+ break;
+
+ case pch::EXPR_IMPLICIT_CAST:
+ S = new (Context) ImplicitCastExpr(Empty);
+ break;
+
+ case pch::EXPR_CSTYLE_CAST:
+ S = new (Context) CStyleCastExpr(Empty);
+ break;
+
+ case pch::EXPR_COMPOUND_LITERAL:
+ S = new (Context) CompoundLiteralExpr(Empty);
+ break;
+
+ case pch::EXPR_EXT_VECTOR_ELEMENT:
+ S = new (Context) ExtVectorElementExpr(Empty);
+ break;
+
+ case pch::EXPR_INIT_LIST:
+ S = new (Context) InitListExpr(Empty);
+ break;
+
+ case pch::EXPR_DESIGNATED_INIT:
+ S = DesignatedInitExpr::CreateEmpty(*Context,
+ Record[PCHStmtReader::NumExprFields] - 1);
+
+ break;
+
+ case pch::EXPR_IMPLICIT_VALUE_INIT:
+ S = new (Context) ImplicitValueInitExpr(Empty);
+ break;
+
+ case pch::EXPR_VA_ARG:
+ S = new (Context) VAArgExpr(Empty);
+ break;
+
+ case pch::EXPR_ADDR_LABEL:
+ S = new (Context) AddrLabelExpr(Empty);
+ break;
+
+ case pch::EXPR_STMT:
+ S = new (Context) StmtExpr(Empty);
+ break;
+
+ case pch::EXPR_TYPES_COMPATIBLE:
+ S = new (Context) TypesCompatibleExpr(Empty);
+ break;
+
+ case pch::EXPR_CHOOSE:
+ S = new (Context) ChooseExpr(Empty);
+ break;
+
+ case pch::EXPR_GNU_NULL:
+ S = new (Context) GNUNullExpr(Empty);
+ break;
+
+ case pch::EXPR_SHUFFLE_VECTOR:
+ S = new (Context) ShuffleVectorExpr(Empty);
+ break;
+
+ case pch::EXPR_BLOCK:
+ S = new (Context) BlockExpr(Empty);
+ break;
+
+ case pch::EXPR_BLOCK_DECL_REF:
+ S = new (Context) BlockDeclRefExpr(Empty);
+ break;
+
+ case pch::EXPR_OBJC_STRING_LITERAL:
+ S = new (Context) ObjCStringLiteral(Empty);
+ break;
+ case pch::EXPR_OBJC_ENCODE:
+ S = new (Context) ObjCEncodeExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_SELECTOR_EXPR:
+ S = new (Context) ObjCSelectorExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_PROTOCOL_EXPR:
+ S = new (Context) ObjCProtocolExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_IVAR_REF_EXPR:
+ S = new (Context) ObjCIvarRefExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_PROPERTY_REF_EXPR:
+ S = new (Context) ObjCPropertyRefExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_KVC_REF_EXPR:
+ S = new (Context) ObjCKVCRefExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_MESSAGE_EXPR:
+ S = new (Context) ObjCMessageExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_SUPER_EXPR:
+ S = new (Context) ObjCSuperExpr(Empty);
+ break;
+ case pch::STMT_OBJC_FOR_COLLECTION:
+ S = new (Context) ObjCForCollectionStmt(Empty);
+ break;
+ case pch::STMT_OBJC_CATCH:
+ S = new (Context) ObjCAtCatchStmt(Empty);
+ break;
+ case pch::STMT_OBJC_FINALLY:
+ S = new (Context) ObjCAtFinallyStmt(Empty);
+ break;
+ case pch::STMT_OBJC_AT_TRY:
+ S = new (Context) ObjCAtTryStmt(Empty);
+ break;
+ case pch::STMT_OBJC_AT_SYNCHRONIZED:
+ S = new (Context) ObjCAtSynchronizedStmt(Empty);
+ break;
+ case pch::STMT_OBJC_AT_THROW:
+ S = new (Context) ObjCAtThrowStmt(Empty);
+ break;
+ }
+
+ // We hit a STMT_STOP, so we're done with this expression.
+ if (Finished)
+ break;
+
+ ++NumStatementsRead;
+
+ if (S) {
+ unsigned NumSubStmts = Reader.Visit(S);
+ while (NumSubStmts > 0) {
+ StmtStack.pop_back();
+ --NumSubStmts;
+ }
+ }
+
+ assert(Idx == Record.size() && "Invalid deserialization of statement");
+ StmtStack.push_back(S);
+ }
+ assert(StmtStack.size() == 1 && "Extra expressions on stack!");
+ SwitchCaseStmts.clear();
+ return StmtStack.back();
+}
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
new file mode 100644
index 000000000000..9f9b3b4e09c6
--- /dev/null
+++ b/lib/Frontend/PCHWriter.cpp
@@ -0,0 +1,1966 @@
+//===--- PCHWriter.h - Precompiled Headers Writer ---------------*- 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 PCHWriter class, which writes a precompiled header.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PCHWriter.h"
+#include "../Sema/Sema.h" // FIXME: move header into include/clang/Sema
+#include "../Sema/IdentifierResolver.h" // FIXME: move header
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclContextInternals.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/SourceManagerInternals.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Version.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/System/Path.h"
+#include <cstdio>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Type serialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class VISIBILITY_HIDDEN PCHTypeWriter {
+ PCHWriter &Writer;
+ PCHWriter::RecordData &Record;
+
+ public:
+ /// \brief Type code that corresponds to the record generated.
+ pch::TypeCode Code;
+
+ PCHTypeWriter(PCHWriter &Writer, PCHWriter::RecordData &Record)
+ : Writer(Writer), Record(Record), Code(pch::TYPE_EXT_QUAL) { }
+
+ void VisitArrayType(const ArrayType *T);
+ void VisitFunctionType(const FunctionType *T);
+ void VisitTagType(const TagType *T);
+
+#define TYPE(Class, Base) void Visit##Class##Type(const Class##Type *T);
+#define ABSTRACT_TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+ };
+}
+
+void PCHTypeWriter::VisitExtQualType(const ExtQualType *T) {
+ Writer.AddTypeRef(QualType(T->getBaseType(), 0), Record);
+ Record.push_back(T->getObjCGCAttr()); // FIXME: use stable values
+ Record.push_back(T->getAddressSpace());
+ Code = pch::TYPE_EXT_QUAL;
+}
+
+void PCHTypeWriter::VisitBuiltinType(const BuiltinType *T) {
+ assert(false && "Built-in types are never serialized");
+}
+
+void PCHTypeWriter::VisitFixedWidthIntType(const FixedWidthIntType *T) {
+ Record.push_back(T->getWidth());
+ Record.push_back(T->isSigned());
+ Code = pch::TYPE_FIXED_WIDTH_INT;
+}
+
+void PCHTypeWriter::VisitComplexType(const ComplexType *T) {
+ Writer.AddTypeRef(T->getElementType(), Record);
+ Code = pch::TYPE_COMPLEX;
+}
+
+void PCHTypeWriter::VisitPointerType(const PointerType *T) {
+ Writer.AddTypeRef(T->getPointeeType(), Record);
+ Code = pch::TYPE_POINTER;
+}
+
+void PCHTypeWriter::VisitBlockPointerType(const BlockPointerType *T) {
+ Writer.AddTypeRef(T->getPointeeType(), Record);
+ Code = pch::TYPE_BLOCK_POINTER;
+}
+
+void PCHTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) {
+ Writer.AddTypeRef(T->getPointeeType(), Record);
+ Code = pch::TYPE_LVALUE_REFERENCE;
+}
+
+void PCHTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) {
+ Writer.AddTypeRef(T->getPointeeType(), Record);
+ Code = pch::TYPE_RVALUE_REFERENCE;
+}
+
+void PCHTypeWriter::VisitMemberPointerType(const MemberPointerType *T) {
+ Writer.AddTypeRef(T->getPointeeType(), Record);
+ Writer.AddTypeRef(QualType(T->getClass(), 0), Record);
+ Code = pch::TYPE_MEMBER_POINTER;
+}
+
+void PCHTypeWriter::VisitArrayType(const ArrayType *T) {
+ Writer.AddTypeRef(T->getElementType(), Record);
+ Record.push_back(T->getSizeModifier()); // FIXME: stable values
+ Record.push_back(T->getIndexTypeQualifier()); // FIXME: stable values
+}
+
+void PCHTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) {
+ VisitArrayType(T);
+ Writer.AddAPInt(T->getSize(), Record);
+ Code = pch::TYPE_CONSTANT_ARRAY;
+}
+
+void PCHTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) {
+ VisitArrayType(T);
+ Code = pch::TYPE_INCOMPLETE_ARRAY;
+}
+
+void PCHTypeWriter::VisitVariableArrayType(const VariableArrayType *T) {
+ VisitArrayType(T);
+ Writer.AddStmt(T->getSizeExpr());
+ Code = pch::TYPE_VARIABLE_ARRAY;
+}
+
+void PCHTypeWriter::VisitVectorType(const VectorType *T) {
+ Writer.AddTypeRef(T->getElementType(), Record);
+ Record.push_back(T->getNumElements());
+ Code = pch::TYPE_VECTOR;
+}
+
+void PCHTypeWriter::VisitExtVectorType(const ExtVectorType *T) {
+ VisitVectorType(T);
+ Code = pch::TYPE_EXT_VECTOR;
+}
+
+void PCHTypeWriter::VisitFunctionType(const FunctionType *T) {
+ Writer.AddTypeRef(T->getResultType(), Record);
+}
+
+void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
+ VisitFunctionType(T);
+ Code = pch::TYPE_FUNCTION_NO_PROTO;
+}
+
+void PCHTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
+ VisitFunctionType(T);
+ Record.push_back(T->getNumArgs());
+ for (unsigned I = 0, N = T->getNumArgs(); I != N; ++I)
+ Writer.AddTypeRef(T->getArgType(I), Record);
+ Record.push_back(T->isVariadic());
+ Record.push_back(T->getTypeQuals());
+ Record.push_back(T->hasExceptionSpec());
+ Record.push_back(T->hasAnyExceptionSpec());
+ Record.push_back(T->getNumExceptions());
+ for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I)
+ Writer.AddTypeRef(T->getExceptionType(I), Record);
+ Code = pch::TYPE_FUNCTION_PROTO;
+}
+
+void PCHTypeWriter::VisitTypedefType(const TypedefType *T) {
+ Writer.AddDeclRef(T->getDecl(), Record);
+ Code = pch::TYPE_TYPEDEF;
+}
+
+void PCHTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) {
+ Writer.AddStmt(T->getUnderlyingExpr());
+ Code = pch::TYPE_TYPEOF_EXPR;
+}
+
+void PCHTypeWriter::VisitTypeOfType(const TypeOfType *T) {
+ Writer.AddTypeRef(T->getUnderlyingType(), Record);
+ Code = pch::TYPE_TYPEOF;
+}
+
+void PCHTypeWriter::VisitTagType(const TagType *T) {
+ Writer.AddDeclRef(T->getDecl(), Record);
+ assert(!T->isBeingDefined() &&
+ "Cannot serialize in the middle of a type definition");
+}
+
+void PCHTypeWriter::VisitRecordType(const RecordType *T) {
+ VisitTagType(T);
+ Code = pch::TYPE_RECORD;
+}
+
+void PCHTypeWriter::VisitEnumType(const EnumType *T) {
+ VisitTagType(T);
+ Code = pch::TYPE_ENUM;
+}
+
+void
+PCHTypeWriter::VisitTemplateSpecializationType(
+ const TemplateSpecializationType *T) {
+ // FIXME: Serialize this type (C++ only)
+ assert(false && "Cannot serialize template specialization types");
+}
+
+void PCHTypeWriter::VisitQualifiedNameType(const QualifiedNameType *T) {
+ // FIXME: Serialize this type (C++ only)
+ assert(false && "Cannot serialize qualified name types");
+}
+
+void PCHTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
+ Writer.AddDeclRef(T->getDecl(), Record);
+ Code = pch::TYPE_OBJC_INTERFACE;
+}
+
+void
+PCHTypeWriter::VisitObjCQualifiedInterfaceType(
+ const ObjCQualifiedInterfaceType *T) {
+ VisitObjCInterfaceType(T);
+ Record.push_back(T->getNumProtocols());
+ for (ObjCInterfaceType::qual_iterator I = T->qual_begin(),
+ E = T->qual_end(); I != E; ++I)
+ Writer.AddDeclRef(*I, Record);
+ Code = pch::TYPE_OBJC_QUALIFIED_INTERFACE;
+}
+
+void PCHTypeWriter::VisitObjCQualifiedIdType(const ObjCQualifiedIdType *T) {
+ Record.push_back(T->getNumProtocols());
+ for (ObjCQualifiedIdType::qual_iterator I = T->qual_begin(),
+ E = T->qual_end(); I != E; ++I)
+ Writer.AddDeclRef(*I, Record);
+ Code = pch::TYPE_OBJC_QUALIFIED_ID;
+}
+
+//===----------------------------------------------------------------------===//
+// PCHWriter Implementation
+//===----------------------------------------------------------------------===//
+
+static void EmitBlockID(unsigned ID, const char *Name,
+ llvm::BitstreamWriter &Stream,
+ PCHWriter::RecordData &Record) {
+ Record.clear();
+ Record.push_back(ID);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
+
+ // Emit the block name if present.
+ if (Name == 0 || Name[0] == 0) return;
+ Record.clear();
+ while (*Name)
+ Record.push_back(*Name++);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
+}
+
+static void EmitRecordID(unsigned ID, const char *Name,
+ llvm::BitstreamWriter &Stream,
+ PCHWriter::RecordData &Record) {
+ Record.clear();
+ Record.push_back(ID);
+ while (*Name)
+ Record.push_back(*Name++);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
+}
+
+static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
+ PCHWriter::RecordData &Record) {
+#define RECORD(X) EmitRecordID(pch::X, #X, Stream, Record)
+ RECORD(STMT_STOP);
+ RECORD(STMT_NULL_PTR);
+ RECORD(STMT_NULL);
+ RECORD(STMT_COMPOUND);
+ RECORD(STMT_CASE);
+ RECORD(STMT_DEFAULT);
+ RECORD(STMT_LABEL);
+ RECORD(STMT_IF);
+ RECORD(STMT_SWITCH);
+ RECORD(STMT_WHILE);
+ RECORD(STMT_DO);
+ RECORD(STMT_FOR);
+ RECORD(STMT_GOTO);
+ RECORD(STMT_INDIRECT_GOTO);
+ RECORD(STMT_CONTINUE);
+ RECORD(STMT_BREAK);
+ RECORD(STMT_RETURN);
+ RECORD(STMT_DECL);
+ RECORD(STMT_ASM);
+ RECORD(EXPR_PREDEFINED);
+ RECORD(EXPR_DECL_REF);
+ RECORD(EXPR_INTEGER_LITERAL);
+ RECORD(EXPR_FLOATING_LITERAL);
+ RECORD(EXPR_IMAGINARY_LITERAL);
+ RECORD(EXPR_STRING_LITERAL);
+ RECORD(EXPR_CHARACTER_LITERAL);
+ RECORD(EXPR_PAREN);
+ RECORD(EXPR_UNARY_OPERATOR);
+ RECORD(EXPR_SIZEOF_ALIGN_OF);
+ RECORD(EXPR_ARRAY_SUBSCRIPT);
+ RECORD(EXPR_CALL);
+ RECORD(EXPR_MEMBER);
+ RECORD(EXPR_BINARY_OPERATOR);
+ RECORD(EXPR_COMPOUND_ASSIGN_OPERATOR);
+ RECORD(EXPR_CONDITIONAL_OPERATOR);
+ RECORD(EXPR_IMPLICIT_CAST);
+ RECORD(EXPR_CSTYLE_CAST);
+ RECORD(EXPR_COMPOUND_LITERAL);
+ RECORD(EXPR_EXT_VECTOR_ELEMENT);
+ RECORD(EXPR_INIT_LIST);
+ RECORD(EXPR_DESIGNATED_INIT);
+ RECORD(EXPR_IMPLICIT_VALUE_INIT);
+ RECORD(EXPR_VA_ARG);
+ RECORD(EXPR_ADDR_LABEL);
+ RECORD(EXPR_STMT);
+ RECORD(EXPR_TYPES_COMPATIBLE);
+ RECORD(EXPR_CHOOSE);
+ RECORD(EXPR_GNU_NULL);
+ RECORD(EXPR_SHUFFLE_VECTOR);
+ RECORD(EXPR_BLOCK);
+ RECORD(EXPR_BLOCK_DECL_REF);
+ RECORD(EXPR_OBJC_STRING_LITERAL);
+ RECORD(EXPR_OBJC_ENCODE);
+ RECORD(EXPR_OBJC_SELECTOR_EXPR);
+ RECORD(EXPR_OBJC_PROTOCOL_EXPR);
+ RECORD(EXPR_OBJC_IVAR_REF_EXPR);
+ RECORD(EXPR_OBJC_PROPERTY_REF_EXPR);
+ RECORD(EXPR_OBJC_KVC_REF_EXPR);
+ RECORD(EXPR_OBJC_MESSAGE_EXPR);
+ RECORD(EXPR_OBJC_SUPER_EXPR);
+ RECORD(STMT_OBJC_FOR_COLLECTION);
+ RECORD(STMT_OBJC_CATCH);
+ RECORD(STMT_OBJC_FINALLY);
+ RECORD(STMT_OBJC_AT_TRY);
+ RECORD(STMT_OBJC_AT_SYNCHRONIZED);
+ RECORD(STMT_OBJC_AT_THROW);
+#undef RECORD
+}
+
+void PCHWriter::WriteBlockInfoBlock() {
+ RecordData Record;
+ Stream.EnterSubblock(llvm::bitc::BLOCKINFO_BLOCK_ID, 3);
+
+#define BLOCK(X) EmitBlockID(pch::X ## _ID, #X, Stream, Record)
+#define RECORD(X) EmitRecordID(pch::X, #X, Stream, Record)
+
+ // PCH Top-Level Block.
+ BLOCK(PCH_BLOCK);
+ RECORD(TYPE_OFFSET);
+ RECORD(DECL_OFFSET);
+ RECORD(LANGUAGE_OPTIONS);
+ RECORD(METADATA);
+ RECORD(IDENTIFIER_OFFSET);
+ RECORD(IDENTIFIER_TABLE);
+ RECORD(EXTERNAL_DEFINITIONS);
+ RECORD(SPECIAL_TYPES);
+ RECORD(STATISTICS);
+ RECORD(TENTATIVE_DEFINITIONS);
+ RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS);
+ RECORD(SELECTOR_OFFSETS);
+ RECORD(METHOD_POOL);
+ RECORD(PP_COUNTER_VALUE);
+ RECORD(SOURCE_LOCATION_OFFSETS);
+ RECORD(SOURCE_LOCATION_PRELOADS);
+ RECORD(STAT_CACHE);
+ RECORD(EXT_VECTOR_DECLS);
+ RECORD(OBJC_CATEGORY_IMPLEMENTATIONS);
+
+ // SourceManager Block.
+ BLOCK(SOURCE_MANAGER_BLOCK);
+ RECORD(SM_SLOC_FILE_ENTRY);
+ RECORD(SM_SLOC_BUFFER_ENTRY);
+ RECORD(SM_SLOC_BUFFER_BLOB);
+ RECORD(SM_SLOC_INSTANTIATION_ENTRY);
+ RECORD(SM_LINE_TABLE);
+ RECORD(SM_HEADER_FILE_INFO);
+
+ // Preprocessor Block.
+ BLOCK(PREPROCESSOR_BLOCK);
+ RECORD(PP_MACRO_OBJECT_LIKE);
+ RECORD(PP_MACRO_FUNCTION_LIKE);
+ RECORD(PP_TOKEN);
+
+ // Types block.
+ BLOCK(TYPES_BLOCK);
+ RECORD(TYPE_EXT_QUAL);
+ RECORD(TYPE_FIXED_WIDTH_INT);
+ RECORD(TYPE_COMPLEX);
+ RECORD(TYPE_POINTER);
+ RECORD(TYPE_BLOCK_POINTER);
+ RECORD(TYPE_LVALUE_REFERENCE);
+ RECORD(TYPE_RVALUE_REFERENCE);
+ RECORD(TYPE_MEMBER_POINTER);
+ RECORD(TYPE_CONSTANT_ARRAY);
+ RECORD(TYPE_INCOMPLETE_ARRAY);
+ RECORD(TYPE_VARIABLE_ARRAY);
+ RECORD(TYPE_VECTOR);
+ RECORD(TYPE_EXT_VECTOR);
+ RECORD(TYPE_FUNCTION_PROTO);
+ RECORD(TYPE_FUNCTION_NO_PROTO);
+ RECORD(TYPE_TYPEDEF);
+ RECORD(TYPE_TYPEOF_EXPR);
+ RECORD(TYPE_TYPEOF);
+ RECORD(TYPE_RECORD);
+ RECORD(TYPE_ENUM);
+ RECORD(TYPE_OBJC_INTERFACE);
+ RECORD(TYPE_OBJC_QUALIFIED_INTERFACE);
+ RECORD(TYPE_OBJC_QUALIFIED_ID);
+ // Statements and Exprs can occur in the Types block.
+ AddStmtsExprs(Stream, Record);
+
+ // Decls block.
+ BLOCK(DECLS_BLOCK);
+ RECORD(DECL_ATTR);
+ RECORD(DECL_TRANSLATION_UNIT);
+ RECORD(DECL_TYPEDEF);
+ RECORD(DECL_ENUM);
+ RECORD(DECL_RECORD);
+ RECORD(DECL_ENUM_CONSTANT);
+ RECORD(DECL_FUNCTION);
+ RECORD(DECL_OBJC_METHOD);
+ RECORD(DECL_OBJC_INTERFACE);
+ RECORD(DECL_OBJC_PROTOCOL);
+ RECORD(DECL_OBJC_IVAR);
+ RECORD(DECL_OBJC_AT_DEFS_FIELD);
+ RECORD(DECL_OBJC_CLASS);
+ RECORD(DECL_OBJC_FORWARD_PROTOCOL);
+ RECORD(DECL_OBJC_CATEGORY);
+ RECORD(DECL_OBJC_CATEGORY_IMPL);
+ RECORD(DECL_OBJC_IMPLEMENTATION);
+ RECORD(DECL_OBJC_COMPATIBLE_ALIAS);
+ RECORD(DECL_OBJC_PROPERTY);
+ RECORD(DECL_OBJC_PROPERTY_IMPL);
+ RECORD(DECL_FIELD);
+ RECORD(DECL_VAR);
+ RECORD(DECL_IMPLICIT_PARAM);
+ RECORD(DECL_PARM_VAR);
+ RECORD(DECL_ORIGINAL_PARM_VAR);
+ RECORD(DECL_FILE_SCOPE_ASM);
+ RECORD(DECL_BLOCK);
+ RECORD(DECL_CONTEXT_LEXICAL);
+ RECORD(DECL_CONTEXT_VISIBLE);
+ // Statements and Exprs can occur in the Decls block.
+ AddStmtsExprs(Stream, Record);
+#undef RECORD
+#undef BLOCK
+ Stream.ExitBlock();
+}
+
+
+/// \brief Write the PCH metadata (e.g., i686-apple-darwin9).
+void PCHWriter::WriteMetadata(ASTContext &Context) {
+ using namespace llvm;
+
+ // Original file name
+ SourceManager &SM = Context.getSourceManager();
+ if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
+ BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev();
+ FileAbbrev->Add(BitCodeAbbrevOp(pch::ORIGINAL_FILE_NAME));
+ FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
+ unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev);
+
+ llvm::sys::Path MainFilePath(MainFile->getName());
+ std::string MainFileName;
+
+ if (!MainFilePath.isAbsolute()) {
+ llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
+ P.appendComponent(MainFilePath.toString());
+ MainFileName = P.toString();
+ } else {
+ MainFileName = MainFilePath.toString();
+ }
+
+ RecordData Record;
+ Record.push_back(pch::ORIGINAL_FILE_NAME);
+ Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileName.c_str(),
+ MainFileName.size());
+ }
+
+ // Metadata
+ const TargetInfo &Target = Context.Target;
+ BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev();
+ MetaAbbrev->Add(BitCodeAbbrevOp(pch::METADATA));
+ MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH major
+ MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH minor
+ MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major
+ MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor
+ MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple
+ unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev);
+
+ RecordData Record;
+ Record.push_back(pch::METADATA);
+ Record.push_back(pch::VERSION_MAJOR);
+ Record.push_back(pch::VERSION_MINOR);
+ Record.push_back(CLANG_VERSION_MAJOR);
+ Record.push_back(CLANG_VERSION_MINOR);
+ const char *Triple = Target.getTargetTriple();
+ Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, Triple, strlen(Triple));
+}
+
+/// \brief Write the LangOptions structure.
+void PCHWriter::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.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.Microsoft); // Microsoft extensions.
+ 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.PascalStrings); // Allow Pascal strings
+ Record.push_back(LangOpts.WritableStrings); // Allow writable strings
+ Record.push_back(LangOpts.LaxVectorConversions);
+ Record.push_back(LangOpts.Exceptions); // Support exception handling.
+
+ 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.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.OverflowChecking); // Extension to call a handler function when
+ // signed integer arithmetic overflows.
+
+ Record.push_back(LangOpts.HeinousExtensions); // Extensions that we really don't like and
+ // may be ripped out at any time.
+
+ 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.AccessControl); // Whether C++ access control should
+ // be enabled.
+ Record.push_back(LangOpts.getGCMode());
+ Record.push_back(LangOpts.getVisibilityMode());
+ Record.push_back(LangOpts.InstantiationDepth);
+ Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record);
+}
+
+//===----------------------------------------------------------------------===//
+// stat cache Serialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+// Trait used for the on-disk hash table of stat cache results.
+class VISIBILITY_HIDDEN PCHStatCacheTrait {
+public:
+ typedef const char * key_type;
+ typedef key_type key_type_ref;
+
+ typedef std::pair<int, struct stat> data_type;
+ typedef const data_type& data_type_ref;
+
+ static unsigned ComputeHash(const char *path) {
+ return BernsteinHash(path);
+ }
+
+ std::pair<unsigned,unsigned>
+ EmitKeyDataLength(llvm::raw_ostream& Out, const char *path,
+ data_type_ref Data) {
+ unsigned StrLen = strlen(path);
+ clang::io::Emit16(Out, StrLen);
+ unsigned DataLen = 1; // result value
+ if (Data.first == 0)
+ DataLen += 4 + 4 + 2 + 8 + 8;
+ clang::io::Emit8(Out, DataLen);
+ return std::make_pair(StrLen + 1, DataLen);
+ }
+
+ void EmitKey(llvm::raw_ostream& Out, const char *path, unsigned KeyLen) {
+ Out.write(path, KeyLen);
+ }
+
+ void EmitData(llvm::raw_ostream& Out, key_type_ref,
+ data_type_ref Data, unsigned DataLen) {
+ using namespace clang::io;
+ uint64_t Start = Out.tell(); (void)Start;
+
+ // Result of stat()
+ Emit8(Out, Data.first? 1 : 0);
+
+ if (Data.first == 0) {
+ Emit32(Out, (uint32_t) Data.second.st_ino);
+ Emit32(Out, (uint32_t) Data.second.st_dev);
+ Emit16(Out, (uint16_t) Data.second.st_mode);
+ Emit64(Out, (uint64_t) Data.second.st_mtime);
+ Emit64(Out, (uint64_t) Data.second.st_size);
+ }
+
+ assert(Out.tell() - Start == DataLen && "Wrong data length");
+ }
+};
+} // end anonymous namespace
+
+/// \brief Write the stat() system call cache to the PCH file.
+void PCHWriter::WriteStatCache(MemorizeStatCalls &StatCalls) {
+ // Build the on-disk hash table containing information about every
+ // stat() call.
+ OnDiskChainedHashTableGenerator<PCHStatCacheTrait> Generator;
+ unsigned NumStatEntries = 0;
+ for (MemorizeStatCalls::iterator Stat = StatCalls.begin(),
+ StatEnd = StatCalls.end();
+ Stat != StatEnd; ++Stat, ++NumStatEntries)
+ Generator.insert(Stat->first(), Stat->second);
+
+ // Create the on-disk hash table in a buffer.
+ llvm::SmallVector<char, 4096> StatCacheData;
+ uint32_t BucketOffset;
+ {
+ llvm::raw_svector_ostream Out(StatCacheData);
+ // Make sure that no bucket is at offset 0
+ clang::io::Emit32(Out, 0);
+ BucketOffset = Generator.Emit(Out);
+ }
+
+ // Create a blob abbreviation
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::STAT_CACHE));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned StatCacheAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the stat cache
+ RecordData Record;
+ Record.push_back(pch::STAT_CACHE);
+ Record.push_back(BucketOffset);
+ Record.push_back(NumStatEntries);
+ Stream.EmitRecordWithBlob(StatCacheAbbrev, Record,
+ &StatCacheData.front(),
+ StatCacheData.size());
+}
+
+//===----------------------------------------------------------------------===//
+// Source Manager Serialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Create an abbreviation for the SLocEntry that refers to a
+/// file.
+static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_FILE_ENTRY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
+ return Stream.EmitAbbrev(Abbrev);
+}
+
+/// \brief Create an abbreviation for the SLocEntry that refers to a
+/// buffer.
+static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) {
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_BUFFER_ENTRY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Buffer name blob
+ return Stream.EmitAbbrev(Abbrev);
+}
+
+/// \brief Create an abbreviation for the SLocEntry that refers to a
+/// buffer's blob.
+static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream) {
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_BUFFER_BLOB));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Blob
+ return Stream.EmitAbbrev(Abbrev);
+}
+
+/// \brief Create an abbreviation for the SLocEntry that refers to an
+/// buffer.
+static unsigned CreateSLocInstantiationAbbrev(llvm::BitstreamWriter &Stream) {
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_INSTANTIATION_ENTRY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Spelling location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Start location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // End location
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Token length
+ return Stream.EmitAbbrev(Abbrev);
+}
+
+/// \brief Writes the block containing the serialized form of the
+/// source manager.
+///
+/// TODO: We should probably use an on-disk hash table (stored in a
+/// blob), indexed based on the file name, so that we only create
+/// entries for files that we actually need. In the common case (no
+/// errors), we probably won't have to create file entries for any of
+/// the files in the AST.
+void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
+ const Preprocessor &PP) {
+ RecordData Record;
+
+ // Enter the source manager block.
+ Stream.EnterSubblock(pch::SOURCE_MANAGER_BLOCK_ID, 3);
+
+ // Abbreviations for the various kinds of source-location entries.
+ unsigned SLocFileAbbrv = CreateSLocFileAbbrev(Stream);
+ unsigned SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream);
+ unsigned SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream);
+ unsigned SLocInstantiationAbbrv = CreateSLocInstantiationAbbrev(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);
+ 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(pch::SM_LINE_TABLE, Record);
+ }
+
+ // Write out entries for all of the header files we know about.
+ HeaderSearch &HS = PP.getHeaderSearchInfo();
+ Record.clear();
+ for (HeaderSearch::header_file_iterator I = HS.header_file_begin(),
+ E = HS.header_file_end();
+ I != E; ++I) {
+ Record.push_back(I->isImport);
+ Record.push_back(I->DirInfo);
+ Record.push_back(I->NumIncludes);
+ AddIdentifierRef(I->ControllingMacro, Record);
+ Stream.EmitRecord(pch::SM_HEADER_FILE_INFO, Record);
+ Record.clear();
+ }
+
+ // Write out the source location entry table. We skip the first
+ // entry, which is always the same dummy entry.
+ std::vector<uint32_t> SLocEntryOffsets;
+ RecordData PreloadSLocs;
+ SLocEntryOffsets.reserve(SourceMgr.sloc_entry_size() - 1);
+ for (SourceManager::sloc_entry_iterator
+ SLoc = SourceMgr.sloc_entry_begin() + 1,
+ SLocEnd = SourceMgr.sloc_entry_end();
+ SLoc != SLocEnd; ++SLoc) {
+ // Record the offset of this source-location entry.
+ SLocEntryOffsets.push_back(Stream.GetCurrentBitNo());
+
+ // Figure out which record code to use.
+ unsigned Code;
+ if (SLoc->isFile()) {
+ if (SLoc->getFile().getContentCache()->Entry)
+ Code = pch::SM_SLOC_FILE_ENTRY;
+ else
+ Code = pch::SM_SLOC_BUFFER_ENTRY;
+ } else
+ Code = pch::SM_SLOC_INSTANTIATION_ENTRY;
+ Record.clear();
+ Record.push_back(Code);
+
+ Record.push_back(SLoc->getOffset());
+ if (SLoc->isFile()) {
+ const SrcMgr::FileInfo &File = SLoc->getFile();
+ Record.push_back(File.getIncludeLoc().getRawEncoding());
+ Record.push_back(File.getFileCharacteristic()); // FIXME: stable encoding
+ Record.push_back(File.hasLineDirectives());
+
+ const SrcMgr::ContentCache *Content = File.getContentCache();
+ if (Content->Entry) {
+ // The source location entry is a file. The blob associated
+ // with this entry is the file name.
+ Stream.EmitRecordWithBlob(SLocFileAbbrv, Record,
+ Content->Entry->getName(),
+ strlen(Content->Entry->getName()));
+
+ // FIXME: For now, preload all file source locations, so that
+ // we get the appropriate File entries in the reader. This is
+ // a temporary measure.
+ PreloadSLocs.push_back(SLocEntryOffsets.size());
+ } else {
+ // The source location entry is a buffer. The blob associated
+ // with this entry contains the contents of the buffer.
+
+ // We add one to the size so that we capture the trailing NULL
+ // that is required by llvm::MemoryBuffer::getMemBuffer (on
+ // the reader side).
+ const llvm::MemoryBuffer *Buffer = Content->getBuffer();
+ const char *Name = Buffer->getBufferIdentifier();
+ Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record, Name, strlen(Name) + 1);
+ Record.clear();
+ Record.push_back(pch::SM_SLOC_BUFFER_BLOB);
+ Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
+ Buffer->getBufferStart(),
+ Buffer->getBufferSize() + 1);
+
+ if (strcmp(Name, "<built-in>") == 0)
+ PreloadSLocs.push_back(SLocEntryOffsets.size());
+ }
+ } else {
+ // The source location entry is an instantiation.
+ const SrcMgr::InstantiationInfo &Inst = SLoc->getInstantiation();
+ Record.push_back(Inst.getSpellingLoc().getRawEncoding());
+ Record.push_back(Inst.getInstantiationLocStart().getRawEncoding());
+ Record.push_back(Inst.getInstantiationLocEnd().getRawEncoding());
+
+ // Compute the token length for this macro expansion.
+ unsigned NextOffset = SourceMgr.getNextOffset();
+ SourceManager::sloc_entry_iterator NextSLoc = SLoc;
+ if (++NextSLoc != SLocEnd)
+ NextOffset = NextSLoc->getOffset();
+ Record.push_back(NextOffset - SLoc->getOffset() - 1);
+ Stream.EmitRecordWithAbbrev(SLocInstantiationAbbrv, Record);
+ }
+ }
+
+ Stream.ExitBlock();
+
+ if (SLocEntryOffsets.empty())
+ return;
+
+ // Write the source-location offsets table into the PCH block. This
+ // table is used for lazily loading source-location information.
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::SOURCE_LOCATION_OFFSETS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // next offset
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets
+ unsigned SLocOffsetsAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Record.clear();
+ Record.push_back(pch::SOURCE_LOCATION_OFFSETS);
+ Record.push_back(SLocEntryOffsets.size());
+ Record.push_back(SourceMgr.getNextOffset());
+ Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record,
+ (const char *)&SLocEntryOffsets.front(),
+ SLocEntryOffsets.size()*sizeof(SLocEntryOffsets[0]));
+
+ // Write the source location entry preloads array, telling the PCH
+ // reader which source locations entries it should load eagerly.
+ Stream.EmitRecord(pch::SOURCE_LOCATION_PRELOADS, PreloadSLocs);
+}
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Serialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Writes the block containing the serialized form of the
+/// preprocessor.
+///
+void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
+ RecordData Record;
+
+ // If the preprocessor __COUNTER__ value has been bumped, remember it.
+ if (PP.getCounterValue() != 0) {
+ Record.push_back(PP.getCounterValue());
+ Stream.EmitRecord(pch::PP_COUNTER_VALUE, Record);
+ Record.clear();
+ }
+
+ // Enter the preprocessor block.
+ Stream.EnterSubblock(pch::PREPROCESSOR_BLOCK_ID, 2);
+
+ // If the PCH file contains __DATE__ or __TIME__ emit a warning about this.
+ // FIXME: use diagnostics subsystem for localization etc.
+ if (PP.SawDateOrTime())
+ fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n");
+
+ // Loop over all the macro definitions that are live at the end of the file,
+ // emitting each to the PP section.
+ for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
+ I != E; ++I) {
+ // FIXME: This emits macros in hash table order, we should do it in a stable
+ // order so that output is reproducible.
+ MacroInfo *MI = I->second;
+
+ // Don't emit builtin macros like __LINE__ to the PCH file unless they have
+ // been redefined by the header (in which case they are not isBuiltinMacro).
+ if (MI->isBuiltinMacro())
+ continue;
+
+ // FIXME: Remove this identifier reference?
+ AddIdentifierRef(I->first, Record);
+ MacroOffsets[I->first] = Stream.GetCurrentBitNo();
+ Record.push_back(MI->getDefinitionLoc().getRawEncoding());
+ Record.push_back(MI->isUsed());
+
+ unsigned Code;
+ if (MI->isObjectLike()) {
+ Code = pch::PP_MACRO_OBJECT_LIKE;
+ } else {
+ Code = pch::PP_MACRO_FUNCTION_LIKE;
+
+ Record.push_back(MI->isC99Varargs());
+ Record.push_back(MI->isGNUVarargs());
+ Record.push_back(MI->getNumArgs());
+ for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end();
+ I != E; ++I)
+ AddIdentifierRef(*I, Record);
+ }
+ Stream.EmitRecord(Code, Record);
+ Record.clear();
+
+ // Emit the tokens array.
+ for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) {
+ // Note that we know that the preprocessor does not have any annotation
+ // tokens in it because they are created by the parser, and thus can't be
+ // in a macro definition.
+ const Token &Tok = MI->getReplacementToken(TokNo);
+
+ Record.push_back(Tok.getLocation().getRawEncoding());
+ Record.push_back(Tok.getLength());
+
+ // FIXME: When reading literal tokens, reconstruct the literal pointer if
+ // it is needed.
+ AddIdentifierRef(Tok.getIdentifierInfo(), Record);
+
+ // FIXME: Should translate token kind to a stable encoding.
+ Record.push_back(Tok.getKind());
+ // FIXME: Should translate token flags to a stable encoding.
+ Record.push_back(Tok.getFlags());
+
+ Stream.EmitRecord(pch::PP_TOKEN, Record);
+ Record.clear();
+ }
+ ++NumMacros;
+ }
+ Stream.ExitBlock();
+}
+
+//===----------------------------------------------------------------------===//
+// Type Serialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Write the representation of a type to the PCH stream.
+void PCHWriter::WriteType(const Type *T) {
+ pch::TypeID &ID = TypeIDs[T];
+ if (ID == 0) // we haven't seen this type before.
+ ID = NextTypeID++;
+
+ // Record the offset for this type.
+ if (TypeOffsets.size() == ID - pch::NUM_PREDEF_TYPE_IDS)
+ TypeOffsets.push_back(Stream.GetCurrentBitNo());
+ else if (TypeOffsets.size() < ID - pch::NUM_PREDEF_TYPE_IDS) {
+ TypeOffsets.resize(ID + 1 - pch::NUM_PREDEF_TYPE_IDS);
+ TypeOffsets[ID - pch::NUM_PREDEF_TYPE_IDS] = Stream.GetCurrentBitNo();
+ }
+
+ RecordData Record;
+
+ // Emit the type's representation.
+ PCHTypeWriter W(*this, Record);
+ switch (T->getTypeClass()) {
+ // For all of the concrete, non-dependent types, call the
+ // appropriate visitor function.
+#define TYPE(Class, Base) \
+ case Type::Class: W.Visit##Class##Type(cast<Class##Type>(T)); break;
+#define ABSTRACT_TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+
+ // For all of the dependent type nodes (which only occur in C++
+ // templates), produce an error.
+#define TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ assert(false && "Cannot serialize dependent type nodes");
+ break;
+ }
+
+ // Emit the serialized record.
+ Stream.EmitRecord(W.Code, Record);
+
+ // Flush any expressions that were written as part of this type.
+ FlushStmts();
+}
+
+/// \brief Write a block containing all of the types.
+void PCHWriter::WriteTypesBlock(ASTContext &Context) {
+ // Enter the types block.
+ Stream.EnterSubblock(pch::TYPES_BLOCK_ID, 2);
+
+ // Emit all of the types that need to be emitted (so far).
+ while (!TypesToEmit.empty()) {
+ const Type *T = TypesToEmit.front();
+ TypesToEmit.pop();
+ assert(!isa<BuiltinType>(T) && "Built-in types are not serialized");
+ WriteType(T);
+ }
+
+ // Exit the types block
+ Stream.ExitBlock();
+}
+
+//===----------------------------------------------------------------------===//
+// Declaration Serialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Write the block containing all of the declaration IDs
+/// lexically declared within the given DeclContext.
+///
+/// \returns the offset of the DECL_CONTEXT_LEXICAL block within the
+/// bistream, or 0 if no block was written.
+uint64_t PCHWriter::WriteDeclContextLexicalBlock(ASTContext &Context,
+ DeclContext *DC) {
+ if (DC->decls_empty(Context))
+ return 0;
+
+ uint64_t Offset = Stream.GetCurrentBitNo();
+ RecordData Record;
+ for (DeclContext::decl_iterator D = DC->decls_begin(Context),
+ DEnd = DC->decls_end(Context);
+ D != DEnd; ++D)
+ AddDeclRef(*D, Record);
+
+ ++NumLexicalDeclContexts;
+ Stream.EmitRecord(pch::DECL_CONTEXT_LEXICAL, Record);
+ return Offset;
+}
+
+/// \brief Write the block containing all of the declaration IDs
+/// visible from the given DeclContext.
+///
+/// \returns the offset of the DECL_CONTEXT_VISIBLE block within the
+/// bistream, or 0 if no block was written.
+uint64_t PCHWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
+ DeclContext *DC) {
+ if (DC->getPrimaryContext() != DC)
+ return 0;
+
+ // Since there is no name lookup into functions or methods, and we
+ // perform name lookup for the translation unit via the
+ // IdentifierInfo chains, don't bother to build a
+ // visible-declarations table for these entities.
+ if (DC->isFunctionOrMethod() || DC->isTranslationUnit())
+ return 0;
+
+ // Force the DeclContext to build a its name-lookup table.
+ DC->lookup(Context, DeclarationName());
+
+ // Serialize the contents of the mapping used for lookup. Note that,
+ // although we have two very different code paths, the serialized
+ // representation is the same for both cases: a declaration name,
+ // followed by a size, followed by references to the visible
+ // declarations that have that name.
+ uint64_t Offset = Stream.GetCurrentBitNo();
+ RecordData Record;
+ StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(DC->getLookupPtr());
+ if (!Map)
+ return 0;
+
+ for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end();
+ D != DEnd; ++D) {
+ AddDeclarationName(D->first, Record);
+ DeclContext::lookup_result Result = D->second.getLookupResult(Context);
+ Record.push_back(Result.second - Result.first);
+ for(; Result.first != Result.second; ++Result.first)
+ AddDeclRef(*Result.first, Record);
+ }
+
+ if (Record.size() == 0)
+ return 0;
+
+ Stream.EmitRecord(pch::DECL_CONTEXT_VISIBLE, Record);
+ ++NumVisibleDeclContexts;
+ return Offset;
+}
+
+//===----------------------------------------------------------------------===//
+// Global Method Pool and Selector Serialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+// Trait used for the on-disk hash table used in the method pool.
+class VISIBILITY_HIDDEN PCHMethodPoolTrait {
+ PCHWriter &Writer;
+
+public:
+ typedef Selector key_type;
+ typedef key_type key_type_ref;
+
+ typedef std::pair<ObjCMethodList, ObjCMethodList> data_type;
+ typedef const data_type& data_type_ref;
+
+ explicit PCHMethodPoolTrait(PCHWriter &Writer) : Writer(Writer) { }
+
+ static unsigned ComputeHash(Selector Sel) {
+ unsigned N = Sel.getNumArgs();
+ if (N == 0)
+ ++N;
+ unsigned R = 5381;
+ for (unsigned I = 0; I != N; ++I)
+ if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I))
+ R = clang::BernsteinHashPartial(II->getName(), II->getLength(), R);
+ return R;
+ }
+
+ std::pair<unsigned,unsigned>
+ EmitKeyDataLength(llvm::raw_ostream& Out, Selector Sel,
+ data_type_ref Methods) {
+ unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4);
+ clang::io::Emit16(Out, KeyLen);
+ unsigned DataLen = 2 + 2; // 2 bytes for each of the method counts
+ for (const ObjCMethodList *Method = &Methods.first; Method;
+ Method = Method->Next)
+ if (Method->Method)
+ DataLen += 4;
+ for (const ObjCMethodList *Method = &Methods.second; Method;
+ Method = Method->Next)
+ if (Method->Method)
+ DataLen += 4;
+ clang::io::Emit16(Out, DataLen);
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ void EmitKey(llvm::raw_ostream& Out, Selector Sel, unsigned) {
+ uint64_t Start = Out.tell();
+ assert((Start >> 32) == 0 && "Selector key offset too large");
+ Writer.SetSelectorOffset(Sel, Start);
+ unsigned N = Sel.getNumArgs();
+ clang::io::Emit16(Out, N);
+ if (N == 0)
+ N = 1;
+ for (unsigned I = 0; I != N; ++I)
+ clang::io::Emit32(Out,
+ Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I)));
+ }
+
+ void EmitData(llvm::raw_ostream& Out, key_type_ref,
+ data_type_ref Methods, unsigned DataLen) {
+ uint64_t Start = Out.tell(); (void)Start;
+ unsigned NumInstanceMethods = 0;
+ for (const ObjCMethodList *Method = &Methods.first; Method;
+ Method = Method->Next)
+ if (Method->Method)
+ ++NumInstanceMethods;
+
+ unsigned NumFactoryMethods = 0;
+ for (const ObjCMethodList *Method = &Methods.second; Method;
+ Method = Method->Next)
+ if (Method->Method)
+ ++NumFactoryMethods;
+
+ clang::io::Emit16(Out, NumInstanceMethods);
+ clang::io::Emit16(Out, NumFactoryMethods);
+ for (const ObjCMethodList *Method = &Methods.first; Method;
+ Method = Method->Next)
+ if (Method->Method)
+ clang::io::Emit32(Out, Writer.getDeclID(Method->Method));
+ for (const ObjCMethodList *Method = &Methods.second; Method;
+ Method = Method->Next)
+ if (Method->Method)
+ clang::io::Emit32(Out, Writer.getDeclID(Method->Method));
+
+ assert(Out.tell() - Start == DataLen && "Data length is wrong");
+ }
+};
+} // end anonymous namespace
+
+/// \brief Write the method pool into the PCH file.
+///
+/// The method pool contains both instance and factory methods, stored
+/// in an on-disk hash table indexed by the selector.
+void PCHWriter::WriteMethodPool(Sema &SemaRef) {
+ using namespace llvm;
+
+ // Create and write out the blob that contains the instance and
+ // factor method pools.
+ bool Empty = true;
+ {
+ OnDiskChainedHashTableGenerator<PCHMethodPoolTrait> Generator;
+
+ // Create the on-disk hash table representation. Start by
+ // iterating through the instance method pool.
+ PCHMethodPoolTrait::key_type Key;
+ unsigned NumSelectorsInMethodPool = 0;
+ for (llvm::DenseMap<Selector, ObjCMethodList>::iterator
+ Instance = SemaRef.InstanceMethodPool.begin(),
+ InstanceEnd = SemaRef.InstanceMethodPool.end();
+ Instance != InstanceEnd; ++Instance) {
+ // Check whether there is a factory method with the same
+ // selector.
+ llvm::DenseMap<Selector, ObjCMethodList>::iterator Factory
+ = SemaRef.FactoryMethodPool.find(Instance->first);
+
+ if (Factory == SemaRef.FactoryMethodPool.end())
+ Generator.insert(Instance->first,
+ std::make_pair(Instance->second,
+ ObjCMethodList()));
+ else
+ Generator.insert(Instance->first,
+ std::make_pair(Instance->second, Factory->second));
+
+ ++NumSelectorsInMethodPool;
+ Empty = false;
+ }
+
+ // Now iterate through the factory method pool, to pick up any
+ // selectors that weren't already in the instance method pool.
+ for (llvm::DenseMap<Selector, ObjCMethodList>::iterator
+ Factory = SemaRef.FactoryMethodPool.begin(),
+ FactoryEnd = SemaRef.FactoryMethodPool.end();
+ Factory != FactoryEnd; ++Factory) {
+ // Check whether there is an instance method with the same
+ // selector. If so, there is no work to do here.
+ llvm::DenseMap<Selector, ObjCMethodList>::iterator Instance
+ = SemaRef.InstanceMethodPool.find(Factory->first);
+
+ if (Instance == SemaRef.InstanceMethodPool.end()) {
+ Generator.insert(Factory->first,
+ std::make_pair(ObjCMethodList(), Factory->second));
+ ++NumSelectorsInMethodPool;
+ }
+
+ Empty = false;
+ }
+
+ if (Empty && SelectorOffsets.empty())
+ return;
+
+ // Create the on-disk hash table in a buffer.
+ llvm::SmallVector<char, 4096> MethodPool;
+ uint32_t BucketOffset;
+ SelectorOffsets.resize(SelVector.size());
+ {
+ PCHMethodPoolTrait Trait(*this);
+ llvm::raw_svector_ostream Out(MethodPool);
+ // Make sure that no bucket is at offset 0
+ clang::io::Emit32(Out, 0);
+ BucketOffset = Generator.Emit(Out, Trait);
+
+ // For every selector that we have seen but which was not
+ // written into the hash table, write the selector itself and
+ // record it's offset.
+ for (unsigned I = 0, N = SelVector.size(); I != N; ++I)
+ if (SelectorOffsets[I] == 0)
+ Trait.EmitKey(Out, SelVector[I], 0);
+ }
+
+ // Create a blob abbreviation
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::METHOD_POOL));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the method pool
+ RecordData Record;
+ Record.push_back(pch::METHOD_POOL);
+ Record.push_back(BucketOffset);
+ Record.push_back(NumSelectorsInMethodPool);
+ Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record,
+ &MethodPool.front(),
+ MethodPool.size());
+
+ // Create a blob abbreviation for the selector table offsets.
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::SELECTOR_OFFSETS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // index
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the selector offsets table.
+ Record.clear();
+ Record.push_back(pch::SELECTOR_OFFSETS);
+ Record.push_back(SelectorOffsets.size());
+ Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record,
+ (const char *)&SelectorOffsets.front(),
+ SelectorOffsets.size() * 4);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Identifier Table Serialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN PCHIdentifierTableTrait {
+ PCHWriter &Writer;
+ Preprocessor &PP;
+
+ /// \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>();
+ }
+
+public:
+ typedef const IdentifierInfo* key_type;
+ typedef key_type key_type_ref;
+
+ typedef pch::IdentID data_type;
+ typedef data_type data_type_ref;
+
+ PCHIdentifierTableTrait(PCHWriter &Writer, Preprocessor &PP)
+ : Writer(Writer), PP(PP) { }
+
+ static unsigned ComputeHash(const IdentifierInfo* II) {
+ return clang::BernsteinHash(II->getName());
+ }
+
+ std::pair<unsigned,unsigned>
+ EmitKeyDataLength(llvm::raw_ostream& Out, const IdentifierInfo* II,
+ pch::IdentID ID) {
+ unsigned KeyLen = strlen(II->getName()) + 1;
+ unsigned DataLen = 4; // 4 bytes for the persistent ID << 1
+ if (isInterestingIdentifier(II)) {
+ DataLen += 2; // 2 bytes for builtin ID, flags
+ if (II->hasMacroDefinition() &&
+ !PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro())
+ DataLen += 4;
+ for (IdentifierResolver::iterator D = IdentifierResolver::begin(II),
+ DEnd = IdentifierResolver::end();
+ D != DEnd; ++D)
+ DataLen += sizeof(pch::DeclID);
+ }
+ clang::io::Emit16(Out, DataLen);
+ // We emit the key length after the data length so that every
+ // string is preceded by a 16-bit length. This matches the PTH
+ // format for storing identifiers.
+ clang::io::Emit16(Out, KeyLen);
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ void EmitKey(llvm::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.
+ Writer.SetIdentifierOffset(II, Out.tell());
+ Out.write(II->getName(), KeyLen);
+ }
+
+ void EmitData(llvm::raw_ostream& Out, const IdentifierInfo* II,
+ pch::IdentID ID, unsigned) {
+ if (!isInterestingIdentifier(II)) {
+ 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();
+ Bits = (uint32_t)II->getObjCOrBuiltinID();
+ Bits = (Bits << 1) | hasMacroDefinition;
+ Bits = (Bits << 1) | II->isExtensionToken();
+ Bits = (Bits << 1) | II->isPoisoned();
+ Bits = (Bits << 1) | II->isCPlusPlusOperatorKeyword();
+ clang::io::Emit16(Out, Bits);
+
+ if (hasMacroDefinition)
+ clang::io::Emit32(Out, Writer.getMacroOffset(II));
+
+ // Emit the declaration IDs in reverse order, because the
+ // IdentifierResolver provides the declarations as they would be
+ // visible (e.g., the function "stat" would come before the struct
+ // "stat"), but IdentifierResolver::AddDeclToIdentifierChain()
+ // adds declarations to the end of the list (so we need to see the
+ // struct "status" before the function "status").
+ llvm::SmallVector<Decl *, 16> Decls(IdentifierResolver::begin(II),
+ IdentifierResolver::end());
+ for (llvm::SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(),
+ DEnd = Decls.rend();
+ D != DEnd; ++D)
+ clang::io::Emit32(Out, Writer.getDeclID(*D));
+ }
+};
+} // end anonymous namespace
+
+/// \brief Write the identifier table into the PCH file.
+///
+/// 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 PCHWriter::WriteIdentifierTable(Preprocessor &PP) {
+ using namespace llvm;
+
+ // Create and write out the blob that contains the identifier
+ // strings.
+ {
+ OnDiskChainedHashTableGenerator<PCHIdentifierTableTrait> Generator;
+
+ // Look for any identifiers that were named while processing the
+ // headers, but are otherwise not needed. We add these to the hash
+ // table to enable checking of the predefines buffer in the case
+ // where the user adds new macro definitions when building the PCH
+ // file.
+ for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
+ IDEnd = PP.getIdentifierTable().end();
+ ID != IDEnd; ++ID)
+ getIdentifierRef(ID->second);
+
+ // Create the on-disk hash table representation.
+ IdentifierOffsets.resize(IdentifierIDs.size());
+ for (llvm::DenseMap<const IdentifierInfo *, pch::IdentID>::iterator
+ ID = IdentifierIDs.begin(), IDEnd = IdentifierIDs.end();
+ ID != IDEnd; ++ID) {
+ assert(ID->first && "NULL identifier in identifier table");
+ Generator.insert(ID->first, ID->second);
+ }
+
+ // Create the on-disk hash table in a buffer.
+ llvm::SmallVector<char, 4096> IdentifierTable;
+ uint32_t BucketOffset;
+ {
+ PCHIdentifierTableTrait Trait(*this, PP);
+ llvm::raw_svector_ostream Out(IdentifierTable);
+ // Make sure that no bucket is at offset 0
+ clang::io::Emit32(Out, 0);
+ BucketOffset = Generator.Emit(Out, Trait);
+ }
+
+ // Create a blob abbreviation
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::IDENTIFIER_TABLE));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the identifier table
+ RecordData Record;
+ Record.push_back(pch::IDENTIFIER_TABLE);
+ Record.push_back(BucketOffset);
+ Stream.EmitRecordWithBlob(IDTableAbbrev, Record,
+ &IdentifierTable.front(),
+ IdentifierTable.size());
+ }
+
+ // Write the offsets table for identifier IDs.
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::IDENTIFIER_OFFSET));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of identifiers
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ RecordData Record;
+ Record.push_back(pch::IDENTIFIER_OFFSET);
+ Record.push_back(IdentifierOffsets.size());
+ Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record,
+ (const char *)&IdentifierOffsets.front(),
+ IdentifierOffsets.size() * sizeof(uint32_t));
+}
+
+//===----------------------------------------------------------------------===//
+// General Serialization Routines
+//===----------------------------------------------------------------------===//
+
+/// \brief Write a record containing the given attributes.
+void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
+ RecordData Record;
+ for (; Attr; Attr = Attr->getNext()) {
+ Record.push_back(Attr->getKind()); // FIXME: stable encoding
+ Record.push_back(Attr->isInherited());
+ switch (Attr->getKind()) {
+ case Attr::Alias:
+ AddString(cast<AliasAttr>(Attr)->getAliasee(), Record);
+ break;
+
+ case Attr::Aligned:
+ Record.push_back(cast<AlignedAttr>(Attr)->getAlignment());
+ break;
+
+ case Attr::AlwaysInline:
+ break;
+
+ case Attr::AnalyzerNoReturn:
+ break;
+
+ case Attr::Annotate:
+ AddString(cast<AnnotateAttr>(Attr)->getAnnotation(), Record);
+ break;
+
+ case Attr::AsmLabel:
+ AddString(cast<AsmLabelAttr>(Attr)->getLabel(), Record);
+ break;
+
+ case Attr::Blocks:
+ Record.push_back(cast<BlocksAttr>(Attr)->getType()); // FIXME: stable
+ break;
+
+ case Attr::Cleanup:
+ AddDeclRef(cast<CleanupAttr>(Attr)->getFunctionDecl(), Record);
+ break;
+
+ case Attr::Const:
+ break;
+
+ case Attr::Constructor:
+ Record.push_back(cast<ConstructorAttr>(Attr)->getPriority());
+ break;
+
+ case Attr::DLLExport:
+ case Attr::DLLImport:
+ case Attr::Deprecated:
+ break;
+
+ case Attr::Destructor:
+ Record.push_back(cast<DestructorAttr>(Attr)->getPriority());
+ break;
+
+ case Attr::FastCall:
+ break;
+
+ case Attr::Format: {
+ const FormatAttr *Format = cast<FormatAttr>(Attr);
+ AddString(Format->getType(), Record);
+ Record.push_back(Format->getFormatIdx());
+ Record.push_back(Format->getFirstArg());
+ break;
+ }
+
+ case Attr::FormatArg: {
+ const FormatArgAttr *Format = cast<FormatArgAttr>(Attr);
+ Record.push_back(Format->getFormatIdx());
+ break;
+ }
+
+ case Attr::Sentinel : {
+ const SentinelAttr *Sentinel = cast<SentinelAttr>(Attr);
+ Record.push_back(Sentinel->getSentinel());
+ Record.push_back(Sentinel->getNullPos());
+ break;
+ }
+
+ case Attr::GNUInline:
+ case Attr::IBOutletKind:
+ case Attr::NoReturn:
+ case Attr::NoThrow:
+ case Attr::Nodebug:
+ case Attr::Noinline:
+ break;
+
+ case Attr::NonNull: {
+ const NonNullAttr *NonNull = cast<NonNullAttr>(Attr);
+ Record.push_back(NonNull->size());
+ Record.insert(Record.end(), NonNull->begin(), NonNull->end());
+ break;
+ }
+
+ case Attr::ObjCException:
+ case Attr::ObjCNSObject:
+ case Attr::CFReturnsRetained:
+ case Attr::NSReturnsRetained:
+ case Attr::Overloadable:
+ break;
+
+ case Attr::Packed:
+ Record.push_back(cast<PackedAttr>(Attr)->getAlignment());
+ break;
+
+ case Attr::Pure:
+ break;
+
+ case Attr::Regparm:
+ Record.push_back(cast<RegparmAttr>(Attr)->getNumParams());
+ break;
+
+ case Attr::Section:
+ AddString(cast<SectionAttr>(Attr)->getName(), Record);
+ break;
+
+ case Attr::StdCall:
+ case Attr::TransparentUnion:
+ case Attr::Unavailable:
+ case Attr::Unused:
+ case Attr::Used:
+ break;
+
+ case Attr::Visibility:
+ // FIXME: stable encoding
+ Record.push_back(cast<VisibilityAttr>(Attr)->getVisibility());
+ break;
+
+ case Attr::WarnUnusedResult:
+ case Attr::Weak:
+ case Attr::WeakImport:
+ break;
+ }
+ }
+
+ Stream.EmitRecord(pch::DECL_ATTR, Record);
+}
+
+void PCHWriter::AddString(const std::string &Str, RecordData &Record) {
+ Record.push_back(Str.size());
+ Record.insert(Record.end(), Str.begin(), Str.end());
+}
+
+/// \brief Note that the identifier II occurs at the given offset
+/// within the identifier table.
+void PCHWriter::SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset) {
+ IdentifierOffsets[IdentifierIDs[II] - 1] = Offset;
+}
+
+/// \brief Note that the selector Sel occurs at the given offset
+/// within the method pool/selector table.
+void PCHWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
+ unsigned ID = SelectorIDs[Sel];
+ assert(ID && "Unknown selector");
+ SelectorOffsets[ID - 1] = Offset;
+}
+
+PCHWriter::PCHWriter(llvm::BitstreamWriter &Stream)
+ : Stream(Stream), NextTypeID(pch::NUM_PREDEF_TYPE_IDS),
+ NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0),
+ NumVisibleDeclContexts(0) { }
+
+void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls) {
+ using namespace llvm;
+
+ ASTContext &Context = SemaRef.Context;
+ Preprocessor &PP = SemaRef.PP;
+
+ // Emit the file header.
+ Stream.Emit((unsigned)'C', 8);
+ Stream.Emit((unsigned)'P', 8);
+ Stream.Emit((unsigned)'C', 8);
+ Stream.Emit((unsigned)'H', 8);
+
+ WriteBlockInfoBlock();
+
+ // The translation unit is the first declaration we'll emit.
+ DeclIDs[Context.getTranslationUnitDecl()] = 1;
+ DeclsToEmit.push(Context.getTranslationUnitDecl());
+
+ // Make sure that we emit IdentifierInfos (and any attached
+ // declarations) for builtins.
+ {
+ IdentifierTable &Table = PP.getIdentifierTable();
+ llvm::SmallVector<const char *, 32> BuiltinNames;
+ Context.BuiltinInfo.GetBuiltinNames(BuiltinNames,
+ Context.getLangOptions().NoBuiltin);
+ for (unsigned I = 0, N = BuiltinNames.size(); I != N; ++I)
+ getIdentifierRef(&Table.get(BuiltinNames[I]));
+ }
+
+ // Build a record containing all of the tentative definitions in
+ // this header file. Generally, this record will be empty.
+ RecordData TentativeDefinitions;
+ for (llvm::DenseMap<DeclarationName, VarDecl *>::iterator
+ TD = SemaRef.TentativeDefinitions.begin(),
+ TDEnd = SemaRef.TentativeDefinitions.end();
+ TD != TDEnd; ++TD)
+ AddDeclRef(TD->second, TentativeDefinitions);
+
+ // Build a record containing all of the locally-scoped external
+ // declarations in this header file. Generally, this record will be
+ // empty.
+ RecordData LocallyScopedExternalDecls;
+ for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
+ TD = SemaRef.LocallyScopedExternalDecls.begin(),
+ TDEnd = SemaRef.LocallyScopedExternalDecls.end();
+ TD != TDEnd; ++TD)
+ 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);
+
+ // Build a record containing all of the Objective-C category
+ // implementations.
+ RecordData ObjCCategoryImpls;
+ for (unsigned I = 0, N = SemaRef.ObjCCategoryImpls.size(); I != N; ++I)
+ AddDeclRef(SemaRef.ObjCCategoryImpls[I], ObjCCategoryImpls);
+
+ // Write the remaining PCH contents.
+ RecordData Record;
+ Stream.EnterSubblock(pch::PCH_BLOCK_ID, 4);
+ WriteMetadata(Context);
+ WriteLanguageOptions(Context.getLangOptions());
+ if (StatCalls)
+ WriteStatCache(*StatCalls);
+ WriteSourceManagerBlock(Context.getSourceManager(), PP);
+ WritePreprocessor(PP);
+
+ // Keep writing types and declarations until all types and
+ // declarations have been written.
+ do {
+ if (!DeclsToEmit.empty())
+ WriteDeclsBlock(Context);
+ if (!TypesToEmit.empty())
+ WriteTypesBlock(Context);
+ } while (!(DeclsToEmit.empty() && TypesToEmit.empty()));
+
+ WriteMethodPool(SemaRef);
+ WriteIdentifierTable(PP);
+
+ // Write the type offsets array
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::TYPE_OFFSET));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block
+ unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+ Record.clear();
+ Record.push_back(pch::TYPE_OFFSET);
+ Record.push_back(TypeOffsets.size());
+ Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record,
+ (const char *)&TypeOffsets.front(),
+ TypeOffsets.size() * sizeof(TypeOffsets[0]));
+
+ // Write the declaration offsets array
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(pch::DECL_OFFSET));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of declarations
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // declarations block
+ unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+ Record.clear();
+ Record.push_back(pch::DECL_OFFSET);
+ Record.push_back(DeclOffsets.size());
+ Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record,
+ (const char *)&DeclOffsets.front(),
+ DeclOffsets.size() * sizeof(DeclOffsets[0]));
+
+ // 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);
+ Stream.EmitRecord(pch::SPECIAL_TYPES, Record);
+
+ // Write the record containing external, unnamed definitions.
+ if (!ExternalDefinitions.empty())
+ Stream.EmitRecord(pch::EXTERNAL_DEFINITIONS, ExternalDefinitions);
+
+ // Write the record containing tentative definitions.
+ if (!TentativeDefinitions.empty())
+ Stream.EmitRecord(pch::TENTATIVE_DEFINITIONS, TentativeDefinitions);
+
+ // Write the record containing locally-scoped external definitions.
+ if (!LocallyScopedExternalDecls.empty())
+ Stream.EmitRecord(pch::LOCALLY_SCOPED_EXTERNAL_DECLS,
+ LocallyScopedExternalDecls);
+
+ // Write the record containing ext_vector type names.
+ if (!ExtVectorDecls.empty())
+ Stream.EmitRecord(pch::EXT_VECTOR_DECLS, ExtVectorDecls);
+
+ // Write the record containing Objective-C category implementations.
+ if (!ObjCCategoryImpls.empty())
+ Stream.EmitRecord(pch::OBJC_CATEGORY_IMPLEMENTATIONS, ObjCCategoryImpls);
+
+ // Some simple statistics
+ Record.clear();
+ Record.push_back(NumStatements);
+ Record.push_back(NumMacros);
+ Record.push_back(NumLexicalDeclContexts);
+ Record.push_back(NumVisibleDeclContexts);
+ Stream.EmitRecord(pch::STATISTICS, Record);
+ Stream.ExitBlock();
+}
+
+void PCHWriter::AddSourceLocation(SourceLocation Loc, RecordData &Record) {
+ Record.push_back(Loc.getRawEncoding());
+}
+
+void PCHWriter::AddAPInt(const llvm::APInt &Value, RecordData &Record) {
+ Record.push_back(Value.getBitWidth());
+ unsigned N = Value.getNumWords();
+ const uint64_t* Words = Value.getRawData();
+ for (unsigned I = 0; I != N; ++I)
+ Record.push_back(Words[I]);
+}
+
+void PCHWriter::AddAPSInt(const llvm::APSInt &Value, RecordData &Record) {
+ Record.push_back(Value.isUnsigned());
+ AddAPInt(Value, Record);
+}
+
+void PCHWriter::AddAPFloat(const llvm::APFloat &Value, RecordData &Record) {
+ AddAPInt(Value.bitcastToAPInt(), Record);
+}
+
+void PCHWriter::AddIdentifierRef(const IdentifierInfo *II, RecordData &Record) {
+ Record.push_back(getIdentifierRef(II));
+}
+
+pch::IdentID PCHWriter::getIdentifierRef(const IdentifierInfo *II) {
+ if (II == 0)
+ return 0;
+
+ pch::IdentID &ID = IdentifierIDs[II];
+ if (ID == 0)
+ ID = IdentifierIDs.size();
+ return ID;
+}
+
+void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) {
+ if (SelRef.getAsOpaquePtr() == 0) {
+ Record.push_back(0);
+ return;
+ }
+
+ pch::SelectorID &SID = SelectorIDs[SelRef];
+ if (SID == 0) {
+ SID = SelectorIDs.size();
+ SelVector.push_back(SelRef);
+ }
+ Record.push_back(SID);
+}
+
+void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
+ if (T.isNull()) {
+ Record.push_back(pch::PREDEF_TYPE_NULL_ID);
+ return;
+ }
+
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr())) {
+ pch::TypeID ID = 0;
+ switch (BT->getKind()) {
+ case BuiltinType::Void: ID = pch::PREDEF_TYPE_VOID_ID; break;
+ case BuiltinType::Bool: ID = pch::PREDEF_TYPE_BOOL_ID; break;
+ case BuiltinType::Char_U: ID = pch::PREDEF_TYPE_CHAR_U_ID; break;
+ case BuiltinType::UChar: ID = pch::PREDEF_TYPE_UCHAR_ID; break;
+ case BuiltinType::UShort: ID = pch::PREDEF_TYPE_USHORT_ID; break;
+ case BuiltinType::UInt: ID = pch::PREDEF_TYPE_UINT_ID; break;
+ case BuiltinType::ULong: ID = pch::PREDEF_TYPE_ULONG_ID; break;
+ case BuiltinType::ULongLong: ID = pch::PREDEF_TYPE_ULONGLONG_ID; break;
+ case BuiltinType::UInt128: ID = pch::PREDEF_TYPE_UINT128_ID; break;
+ case BuiltinType::Char_S: ID = pch::PREDEF_TYPE_CHAR_S_ID; break;
+ case BuiltinType::SChar: ID = pch::PREDEF_TYPE_SCHAR_ID; break;
+ case BuiltinType::WChar: ID = pch::PREDEF_TYPE_WCHAR_ID; break;
+ case BuiltinType::Short: ID = pch::PREDEF_TYPE_SHORT_ID; break;
+ case BuiltinType::Int: ID = pch::PREDEF_TYPE_INT_ID; break;
+ case BuiltinType::Long: ID = pch::PREDEF_TYPE_LONG_ID; break;
+ case BuiltinType::LongLong: ID = pch::PREDEF_TYPE_LONGLONG_ID; break;
+ case BuiltinType::Int128: ID = pch::PREDEF_TYPE_INT128_ID; break;
+ case BuiltinType::Float: ID = pch::PREDEF_TYPE_FLOAT_ID; break;
+ case BuiltinType::Double: ID = pch::PREDEF_TYPE_DOUBLE_ID; break;
+ case BuiltinType::LongDouble: ID = pch::PREDEF_TYPE_LONGDOUBLE_ID; break;
+ case BuiltinType::NullPtr: ID = pch::PREDEF_TYPE_NULLPTR_ID; break;
+ case BuiltinType::Overload: ID = pch::PREDEF_TYPE_OVERLOAD_ID; break;
+ case BuiltinType::Dependent: ID = pch::PREDEF_TYPE_DEPENDENT_ID; break;
+ }
+
+ Record.push_back((ID << 3) | T.getCVRQualifiers());
+ return;
+ }
+
+ pch::TypeID &ID = TypeIDs[T.getTypePtr()];
+ if (ID == 0) {
+ // We haven't seen this type before. Assign it a new ID and put it
+ // into the queu of types to emit.
+ ID = NextTypeID++;
+ TypesToEmit.push(T.getTypePtr());
+ }
+
+ // Encode the type qualifiers in the type reference.
+ Record.push_back((ID << 3) | T.getCVRQualifiers());
+}
+
+void PCHWriter::AddDeclRef(const Decl *D, RecordData &Record) {
+ if (D == 0) {
+ Record.push_back(0);
+ return;
+ }
+
+ pch::DeclID &ID = DeclIDs[D];
+ if (ID == 0) {
+ // We haven't seen this declaration before. Give it a new ID and
+ // enqueue it in the list of declarations to emit.
+ ID = DeclIDs.size();
+ DeclsToEmit.push(const_cast<Decl *>(D));
+ }
+
+ Record.push_back(ID);
+}
+
+pch::DeclID PCHWriter::getDeclID(const Decl *D) {
+ if (D == 0)
+ return 0;
+
+ assert(DeclIDs.find(D) != DeclIDs.end() && "Declaration not emitted!");
+ return DeclIDs[D];
+}
+
+void PCHWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) {
+ // FIXME: Emit a stable enum for NameKind. 0 = Identifier etc.
+ Record.push_back(Name.getNameKind());
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier:
+ AddIdentifierRef(Name.getAsIdentifierInfo(), Record);
+ break;
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ AddSelectorRef(Name.getObjCSelector(), Record);
+ break;
+
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ AddTypeRef(Name.getCXXNameType(), Record);
+ break;
+
+ case DeclarationName::CXXOperatorName:
+ Record.push_back(Name.getCXXOverloadedOperator());
+ break;
+
+ case DeclarationName::CXXUsingDirective:
+ // No extra data to emit
+ break;
+ }
+}
+
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
new file mode 100644
index 000000000000..67346619978e
--- /dev/null
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -0,0 +1,532 @@
+//===--- PCHWriterDecl.cpp - Declaration Serialization --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements serialization for Declarations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PCHWriter.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/Expr.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Declaration serialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class PCHDeclWriter : public DeclVisitor<PCHDeclWriter, void> {
+
+ PCHWriter &Writer;
+ ASTContext &Context;
+ PCHWriter::RecordData &Record;
+
+ public:
+ pch::DeclCode Code;
+ unsigned AbbrevToUse;
+
+ PCHDeclWriter(PCHWriter &Writer, ASTContext &Context,
+ PCHWriter::RecordData &Record)
+ : Writer(Writer), Context(Context), Record(Record) {
+ }
+
+ void VisitDecl(Decl *D);
+ void VisitTranslationUnitDecl(TranslationUnitDecl *D);
+ void VisitNamedDecl(NamedDecl *D);
+ void VisitTypeDecl(TypeDecl *D);
+ void VisitTypedefDecl(TypedefDecl *D);
+ void VisitTagDecl(TagDecl *D);
+ void VisitEnumDecl(EnumDecl *D);
+ void VisitRecordDecl(RecordDecl *D);
+ void VisitValueDecl(ValueDecl *D);
+ void VisitEnumConstantDecl(EnumConstantDecl *D);
+ void VisitFunctionDecl(FunctionDecl *D);
+ void VisitFieldDecl(FieldDecl *D);
+ void VisitVarDecl(VarDecl *D);
+ void VisitImplicitParamDecl(ImplicitParamDecl *D);
+ void VisitParmVarDecl(ParmVarDecl *D);
+ void VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
+ void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
+ void VisitBlockDecl(BlockDecl *D);
+ void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
+ uint64_t VisibleOffset);
+ void VisitObjCMethodDecl(ObjCMethodDecl *D);
+ void VisitObjCContainerDecl(ObjCContainerDecl *D);
+ void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+ void VisitObjCIvarDecl(ObjCIvarDecl *D);
+ void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
+ void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D);
+ void VisitObjCClassDecl(ObjCClassDecl *D);
+ void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
+ void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
+ void VisitObjCImplDecl(ObjCImplDecl *D);
+ void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
+ void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
+ void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
+ void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
+ void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+ };
+}
+
+void PCHDeclWriter::VisitDecl(Decl *D) {
+ Writer.AddDeclRef(cast_or_null<Decl>(D->getDeclContext()), Record);
+ Writer.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()), Record);
+ Writer.AddSourceLocation(D->getLocation(), Record);
+ Record.push_back(D->isInvalidDecl());
+ Record.push_back(D->hasAttrs());
+ Record.push_back(D->isImplicit());
+ Record.push_back(D->getAccess());
+}
+
+void PCHDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
+ VisitDecl(D);
+ Code = pch::DECL_TRANSLATION_UNIT;
+}
+
+void PCHDeclWriter::VisitNamedDecl(NamedDecl *D) {
+ VisitDecl(D);
+ Writer.AddDeclarationName(D->getDeclName(), Record);
+}
+
+void PCHDeclWriter::VisitTypeDecl(TypeDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
+}
+
+void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
+ VisitTypeDecl(D);
+ Writer.AddTypeRef(D->getUnderlyingType(), Record);
+ Code = pch::DECL_TYPEDEF;
+}
+
+void PCHDeclWriter::VisitTagDecl(TagDecl *D) {
+ VisitTypeDecl(D);
+ Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
+ Record.push_back(D->isDefinition());
+ Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record);
+}
+
+void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) {
+ VisitTagDecl(D);
+ Writer.AddTypeRef(D->getIntegerType(), Record);
+ // FIXME: C++ InstantiatedFrom
+ Code = pch::DECL_ENUM;
+}
+
+void PCHDeclWriter::VisitRecordDecl(RecordDecl *D) {
+ VisitTagDecl(D);
+ Record.push_back(D->hasFlexibleArrayMember());
+ Record.push_back(D->isAnonymousStructOrUnion());
+ Code = pch::DECL_RECORD;
+}
+
+void PCHDeclWriter::VisitValueDecl(ValueDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddTypeRef(D->getType(), Record);
+}
+
+void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) {
+ VisitValueDecl(D);
+ Record.push_back(D->getInitExpr()? 1 : 0);
+ if (D->getInitExpr())
+ Writer.AddStmt(D->getInitExpr());
+ Writer.AddAPSInt(D->getInitVal(), Record);
+ Code = pch::DECL_ENUM_CONSTANT;
+}
+
+void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
+ VisitValueDecl(D);
+ Record.push_back(D->isThisDeclarationADefinition());
+ if (D->isThisDeclarationADefinition())
+ Writer.AddStmt(D->getBody(Context));
+ Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+ Record.push_back(D->getStorageClass()); // FIXME: stable encoding
+ Record.push_back(D->isInline());
+ Record.push_back(D->isC99InlineDefinition());
+ Record.push_back(D->isVirtualAsWritten());
+ Record.push_back(D->isPure());
+ Record.push_back(D->hasInheritedPrototype());
+ Record.push_back(D->hasWrittenPrototype());
+ Record.push_back(D->isDeleted());
+ Writer.AddSourceLocation(D->getTypeSpecStartLoc(), Record);
+ // FIXME: C++ TemplateOrInstantiation
+ Record.push_back(D->param_size());
+ for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
+ P != PEnd; ++P)
+ Writer.AddDeclRef(*P, Record);
+ Code = pch::DECL_FUNCTION;
+}
+
+void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
+ VisitNamedDecl(D);
+ // FIXME: convert to LazyStmtPtr?
+ // Unlike C/C++, method bodies will never be in header files.
+ Record.push_back(D->getBody() != 0);
+ if (D->getBody() != 0) {
+ Writer.AddStmt(D->getBody(Context));
+ Writer.AddDeclRef(D->getSelfDecl(), Record);
+ Writer.AddDeclRef(D->getCmdDecl(), Record);
+ }
+ Record.push_back(D->isInstanceMethod());
+ Record.push_back(D->isVariadic());
+ Record.push_back(D->isSynthesized());
+ // 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());
+ Writer.AddTypeRef(D->getResultType(), Record);
+ Writer.AddSourceLocation(D->getLocEnd(), Record);
+ Record.push_back(D->param_size());
+ for (ObjCMethodDecl::param_iterator P = D->param_begin(),
+ PEnd = D->param_end(); P != PEnd; ++P)
+ Writer.AddDeclRef(*P, Record);
+ Code = pch::DECL_OBJC_METHOD;
+}
+
+void PCHDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getAtEndLoc(), Record);
+ // Abstract class (no need to define a stable pch::DECL code).
+}
+
+void PCHDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ VisitObjCContainerDecl(D);
+ Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
+ Writer.AddDeclRef(D->getSuperClass(), Record);
+ Record.push_back(D->protocol_size());
+ for (ObjCInterfaceDecl::protocol_iterator P = D->protocol_begin(),
+ PEnd = D->protocol_end();
+ P != PEnd; ++P)
+ Writer.AddDeclRef(*P, Record);
+ Record.push_back(D->ivar_size());
+ for (ObjCInterfaceDecl::ivar_iterator I = D->ivar_begin(),
+ IEnd = D->ivar_end(); I != IEnd; ++I)
+ Writer.AddDeclRef(*I, Record);
+ 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 = pch::DECL_OBJC_INTERFACE;
+}
+
+void PCHDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
+ VisitFieldDecl(D);
+ // FIXME: stable encoding for @public/@private/@protected/@package
+ Record.push_back(D->getAccessControl());
+ Code = pch::DECL_OBJC_IVAR;
+}
+
+void PCHDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
+ VisitObjCContainerDecl(D);
+ Record.push_back(D->isForwardDecl());
+ Writer.AddSourceLocation(D->getLocEnd(), Record);
+ Record.push_back(D->protocol_size());
+ for (ObjCProtocolDecl::protocol_iterator
+ I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
+ Writer.AddDeclRef(*I, Record);
+ Code = pch::DECL_OBJC_PROTOCOL;
+}
+
+void PCHDeclWriter::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) {
+ VisitFieldDecl(D);
+ Code = pch::DECL_OBJC_AT_DEFS_FIELD;
+}
+
+void PCHDeclWriter::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, Record);
+ Code = pch::DECL_OBJC_CLASS;
+}
+
+void PCHDeclWriter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
+ VisitDecl(D);
+ Record.push_back(D->protocol_size());
+ for (ObjCProtocolDecl::protocol_iterator
+ I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
+ Writer.AddDeclRef(*I, Record);
+ Code = pch::DECL_OBJC_FORWARD_PROTOCOL;
+}
+
+void PCHDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
+ VisitObjCContainerDecl(D);
+ Writer.AddDeclRef(D->getClassInterface(), Record);
+ Record.push_back(D->protocol_size());
+ for (ObjCProtocolDecl::protocol_iterator
+ I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
+ Writer.AddDeclRef(*I, Record);
+ Writer.AddDeclRef(D->getNextClassCategory(), Record);
+ Writer.AddSourceLocation(D->getLocEnd(), Record);
+ Code = pch::DECL_OBJC_CATEGORY;
+}
+
+void PCHDeclWriter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddDeclRef(D->getClassInterface(), Record);
+ Code = pch::DECL_OBJC_COMPATIBLE_ALIAS;
+}
+
+void PCHDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddTypeRef(D->getType(), Record);
+ // FIXME: stable encoding
+ Record.push_back((unsigned)D->getPropertyAttributes());
+ // FIXME: stable encoding
+ Record.push_back((unsigned)D->getPropertyImplementation());
+ Writer.AddDeclarationName(D->getGetterName(), Record);
+ Writer.AddDeclarationName(D->getSetterName(), Record);
+ Writer.AddDeclRef(D->getGetterMethodDecl(), Record);
+ Writer.AddDeclRef(D->getSetterMethodDecl(), Record);
+ Writer.AddDeclRef(D->getPropertyIvarDecl(), Record);
+ Code = pch::DECL_OBJC_PROPERTY;
+}
+
+void PCHDeclWriter::VisitObjCImplDecl(ObjCImplDecl *D) {
+ VisitNamedDecl(D);
+ Writer.AddDeclRef(D->getClassInterface(), Record);
+ Writer.AddSourceLocation(D->getLocEnd(), Record);
+ // Abstract class (no need to define a stable pch::DECL code).
+}
+
+void PCHDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ VisitObjCImplDecl(D);
+ Writer.AddIdentifierRef(D->getIdentifier(), Record);
+ Code = pch::DECL_OBJC_CATEGORY_IMPL;
+}
+
+void PCHDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+ VisitObjCImplDecl(D);
+ Writer.AddDeclRef(D->getSuperClass(), Record);
+ Code = pch::DECL_OBJC_IMPLEMENTATION;
+}
+
+void PCHDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+ VisitDecl(D);
+ Writer.AddSourceLocation(D->getLocStart(), Record);
+ Writer.AddDeclRef(D->getPropertyDecl(), Record);
+ Writer.AddDeclRef(D->getPropertyIvarDecl(), Record);
+ Code = pch::DECL_OBJC_PROPERTY_IMPL;
+}
+
+void PCHDeclWriter::VisitFieldDecl(FieldDecl *D) {
+ VisitValueDecl(D);
+ Record.push_back(D->isMutable());
+ Record.push_back(D->getBitWidth()? 1 : 0);
+ if (D->getBitWidth())
+ Writer.AddStmt(D->getBitWidth());
+ Code = pch::DECL_FIELD;
+}
+
+void PCHDeclWriter::VisitVarDecl(VarDecl *D) {
+ VisitValueDecl(D);
+ Record.push_back(D->getStorageClass()); // FIXME: stable encoding
+ Record.push_back(D->isThreadSpecified());
+ Record.push_back(D->hasCXXDirectInitializer());
+ Record.push_back(D->isDeclaredInCondition());
+ Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+ Writer.AddSourceLocation(D->getTypeSpecStartLoc(), Record);
+ Record.push_back(D->getInit()? 1 : 0);
+ if (D->getInit())
+ Writer.AddStmt(D->getInit());
+ Code = pch::DECL_VAR;
+}
+
+void PCHDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) {
+ VisitVarDecl(D);
+ Code = pch::DECL_IMPLICIT_PARAM;
+}
+
+void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
+ VisitVarDecl(D);
+ Record.push_back(D->getObjCDeclQualifier()); // FIXME: stable encoding
+ // FIXME: emit default argument (C++)
+ // FIXME: why isn't the "default argument" just stored as the initializer
+ // in VarDecl?
+ Code = pch::DECL_PARM_VAR;
+
+
+ // If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here
+ // we dynamically check for the properties that we optimize for, but don't
+ // know are true of all PARM_VAR_DECLs.
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ D->getAccess() == AS_none &&
+ D->getStorageClass() == 0 &&
+ !D->hasCXXDirectInitializer() && // Can params have this ever?
+ D->getObjCDeclQualifier() == 0)
+ AbbrevToUse = Writer.getParmVarDeclAbbrev();
+
+ // Check things we know are true of *every* PARM_VAR_DECL, which is more than
+ // just us assuming it.
+ assert(!D->isInvalidDecl() && "Shouldn't emit invalid decls");
+ assert(!D->isThreadSpecified() && "PARM_VAR_DECL can't be __thread");
+ assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private");
+ assert(!D->isDeclaredInCondition() && "PARM_VAR_DECL can't be in condition");
+ assert(D->getPreviousDeclaration() == 0 && "PARM_VAR_DECL can't be redecl");
+ assert(D->getInit() == 0 && "PARM_VAR_DECL never has init");
+}
+
+void PCHDeclWriter::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) {
+ VisitParmVarDecl(D);
+ Writer.AddTypeRef(D->getOriginalType(), Record);
+ Code = pch::DECL_ORIGINAL_PARM_VAR;
+ AbbrevToUse = 0;
+}
+
+void PCHDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
+ VisitDecl(D);
+ Writer.AddStmt(D->getAsmString());
+ Code = pch::DECL_FILE_SCOPE_ASM;
+}
+
+void PCHDeclWriter::VisitBlockDecl(BlockDecl *D) {
+ VisitDecl(D);
+ Writer.AddStmt(D->getBody());
+ Record.push_back(D->param_size());
+ for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
+ P != PEnd; ++P)
+ Writer.AddDeclRef(*P, Record);
+ Code = pch::DECL_BLOCK;
+}
+
+/// \brief Emit the DeclContext part of a declaration context decl.
+///
+/// \param LexicalOffset the offset at which the DECL_CONTEXT_LEXICAL
+/// block for this declaration context is stored. May be 0 to indicate
+/// that there are no declarations stored within this context.
+///
+/// \param VisibleOffset the offset at which the DECL_CONTEXT_VISIBLE
+/// block for this declaration context is stored. May be 0 to indicate
+/// that there are no declarations visible from this context. Note
+/// that this value will not be emitted for non-primary declaration
+/// contexts.
+void PCHDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
+ uint64_t VisibleOffset) {
+ Record.push_back(LexicalOffset);
+ Record.push_back(VisibleOffset);
+}
+
+
+//===----------------------------------------------------------------------===//
+// PCHWriter Implementation
+//===----------------------------------------------------------------------===//
+
+void PCHWriter::WriteDeclsBlockAbbrevs() {
+ using namespace llvm;
+ // Abbreviation for DECL_PARM_VAR.
+ BitCodeAbbrev *Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(pch::DECL_PARM_VAR));
+
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
+
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ // ValueDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ // VarDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // StorageClass
+ Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified
+ Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer
+ Abv->Add(BitCodeAbbrevOp(0)); // isDeclaredInCondition
+ Abv->Add(BitCodeAbbrevOp(0)); // PrevDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeSpecStartLoc
+ Abv->Add(BitCodeAbbrevOp(0)); // HasInit
+ // ParmVarDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier
+
+ ParmVarDeclAbbrev = Stream.EmitAbbrev(Abv);
+}
+
+/// \brief Write a block containing all of the declarations.
+void PCHWriter::WriteDeclsBlock(ASTContext &Context) {
+ // Enter the declarations block.
+ Stream.EnterSubblock(pch::DECLS_BLOCK_ID, 3);
+
+ // Output the abbreviations that we will use in this block.
+ WriteDeclsBlockAbbrevs();
+
+ // Emit all of the declarations.
+ RecordData Record;
+ PCHDeclWriter W(*this, Context, Record);
+ while (!DeclsToEmit.empty()) {
+ // Pull the next declaration off the queue
+ Decl *D = DeclsToEmit.front();
+ DeclsToEmit.pop();
+
+ // If this declaration is also a DeclContext, write blocks for the
+ // declarations that lexically stored inside its context and those
+ // declarations that are visible from its context. These blocks
+ // are written before the declaration itself so that we can put
+ // their offsets into the record for the declaration.
+ uint64_t LexicalOffset = 0;
+ uint64_t VisibleOffset = 0;
+ DeclContext *DC = dyn_cast<DeclContext>(D);
+ if (DC) {
+ LexicalOffset = WriteDeclContextLexicalBlock(Context, DC);
+ VisibleOffset = WriteDeclContextVisibleBlock(Context, DC);
+ }
+
+ // Determine the ID for this declaration
+ pch::DeclID &ID = DeclIDs[D];
+ if (ID == 0)
+ ID = DeclIDs.size();
+
+ unsigned Index = ID - 1;
+
+ // Record the offset for this declaration
+ if (DeclOffsets.size() == Index)
+ DeclOffsets.push_back(Stream.GetCurrentBitNo());
+ else if (DeclOffsets.size() < Index) {
+ DeclOffsets.resize(Index+1);
+ DeclOffsets[Index] = Stream.GetCurrentBitNo();
+ }
+
+ // Build and emit a record for this declaration
+ Record.clear();
+ W.Code = (pch::DeclCode)0;
+ W.AbbrevToUse = 0;
+ W.Visit(D);
+ if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset);
+
+ if (!W.Code) {
+ fprintf(stderr, "Cannot serialize declaration of kind %s\n",
+ D->getDeclKindName());
+ assert(false && "Unhandled declaration kind while generating PCH");
+ exit(-1);
+ }
+ Stream.EmitRecord(W.Code, Record, W.AbbrevToUse);
+
+ // If the declaration had any attributes, write them now.
+ if (D->hasAttrs())
+ WriteAttributeRecord(D->getAttrs());
+
+ // Flush any expressions that were written as part of this declaration.
+ FlushStmts();
+
+ // Note external declarations so that we can add them to a record
+ // in the PCH file later.
+ if (isa<FileScopeAsmDecl>(D))
+ ExternalDefinitions.push_back(ID);
+ }
+
+ // Exit the declarations block
+ Stream.ExitBlock();
+}
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
new file mode 100644
index 000000000000..b7caee5e5510
--- /dev/null
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -0,0 +1,829 @@
+//===--- PCHWriterStmt.cpp - Statement and Expression Serialization -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements serialization for Statements and Expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PCHWriter.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Statement/expression serialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class PCHStmtWriter : public StmtVisitor<PCHStmtWriter, void> {
+
+ PCHWriter &Writer;
+ PCHWriter::RecordData &Record;
+
+ public:
+ pch::StmtCode Code;
+
+ PCHStmtWriter(PCHWriter &Writer, PCHWriter::RecordData &Record)
+ : Writer(Writer), Record(Record) { }
+
+ void VisitStmt(Stmt *S);
+ void VisitNullStmt(NullStmt *S);
+ void VisitCompoundStmt(CompoundStmt *S);
+ void VisitSwitchCase(SwitchCase *S);
+ void VisitCaseStmt(CaseStmt *S);
+ void VisitDefaultStmt(DefaultStmt *S);
+ void VisitLabelStmt(LabelStmt *S);
+ void VisitIfStmt(IfStmt *S);
+ void VisitSwitchStmt(SwitchStmt *S);
+ void VisitWhileStmt(WhileStmt *S);
+ void VisitDoStmt(DoStmt *S);
+ void VisitForStmt(ForStmt *S);
+ void VisitGotoStmt(GotoStmt *S);
+ void VisitIndirectGotoStmt(IndirectGotoStmt *S);
+ void VisitContinueStmt(ContinueStmt *S);
+ void VisitBreakStmt(BreakStmt *S);
+ void VisitReturnStmt(ReturnStmt *S);
+ void VisitDeclStmt(DeclStmt *S);
+ void VisitAsmStmt(AsmStmt *S);
+ void VisitExpr(Expr *E);
+ void VisitPredefinedExpr(PredefinedExpr *E);
+ void VisitDeclRefExpr(DeclRefExpr *E);
+ void VisitIntegerLiteral(IntegerLiteral *E);
+ void VisitFloatingLiteral(FloatingLiteral *E);
+ void VisitImaginaryLiteral(ImaginaryLiteral *E);
+ void VisitStringLiteral(StringLiteral *E);
+ void VisitCharacterLiteral(CharacterLiteral *E);
+ void VisitParenExpr(ParenExpr *E);
+ void VisitUnaryOperator(UnaryOperator *E);
+ void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+ void VisitArraySubscriptExpr(ArraySubscriptExpr *E);
+ void VisitCallExpr(CallExpr *E);
+ void VisitMemberExpr(MemberExpr *E);
+ void VisitCastExpr(CastExpr *E);
+ void VisitBinaryOperator(BinaryOperator *E);
+ void VisitCompoundAssignOperator(CompoundAssignOperator *E);
+ void VisitConditionalOperator(ConditionalOperator *E);
+ void VisitImplicitCastExpr(ImplicitCastExpr *E);
+ void VisitExplicitCastExpr(ExplicitCastExpr *E);
+ void VisitCStyleCastExpr(CStyleCastExpr *E);
+ void VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
+ void VisitExtVectorElementExpr(ExtVectorElementExpr *E);
+ void VisitInitListExpr(InitListExpr *E);
+ void VisitDesignatedInitExpr(DesignatedInitExpr *E);
+ void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
+ void VisitVAArgExpr(VAArgExpr *E);
+ void VisitAddrLabelExpr(AddrLabelExpr *E);
+ void VisitStmtExpr(StmtExpr *E);
+ void VisitTypesCompatibleExpr(TypesCompatibleExpr *E);
+ void VisitChooseExpr(ChooseExpr *E);
+ void VisitGNUNullExpr(GNUNullExpr *E);
+ void VisitShuffleVectorExpr(ShuffleVectorExpr *E);
+ void VisitBlockExpr(BlockExpr *E);
+ void VisitBlockDeclRefExpr(BlockDeclRefExpr *E);
+
+ // Objective-C Expressions
+ void VisitObjCStringLiteral(ObjCStringLiteral *E);
+ void VisitObjCEncodeExpr(ObjCEncodeExpr *E);
+ void VisitObjCSelectorExpr(ObjCSelectorExpr *E);
+ void VisitObjCProtocolExpr(ObjCProtocolExpr *E);
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E);
+ void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
+ void VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
+ void VisitObjCMessageExpr(ObjCMessageExpr *E);
+ void VisitObjCSuperExpr(ObjCSuperExpr *E);
+
+ // Objective-C Statements
+ void VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
+ void VisitObjCAtCatchStmt(ObjCAtCatchStmt *);
+ void VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *);
+ void VisitObjCAtTryStmt(ObjCAtTryStmt *);
+ void VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *);
+ void VisitObjCAtThrowStmt(ObjCAtThrowStmt *);
+ };
+}
+
+void PCHStmtWriter::VisitStmt(Stmt *S) {
+}
+
+void PCHStmtWriter::VisitNullStmt(NullStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getSemiLoc(), Record);
+ Code = pch::STMT_NULL;
+}
+
+void PCHStmtWriter::VisitCompoundStmt(CompoundStmt *S) {
+ VisitStmt(S);
+ Record.push_back(S->size());
+ for (CompoundStmt::body_iterator CS = S->body_begin(), CSEnd = S->body_end();
+ CS != CSEnd; ++CS)
+ Writer.WriteSubStmt(*CS);
+ Writer.AddSourceLocation(S->getLBracLoc(), Record);
+ Writer.AddSourceLocation(S->getRBracLoc(), Record);
+ Code = pch::STMT_COMPOUND;
+}
+
+void PCHStmtWriter::VisitSwitchCase(SwitchCase *S) {
+ VisitStmt(S);
+ Record.push_back(Writer.RecordSwitchCaseID(S));
+}
+
+void PCHStmtWriter::VisitCaseStmt(CaseStmt *S) {
+ VisitSwitchCase(S);
+ Writer.WriteSubStmt(S->getLHS());
+ Writer.WriteSubStmt(S->getRHS());
+ Writer.WriteSubStmt(S->getSubStmt());
+ Writer.AddSourceLocation(S->getCaseLoc(), Record);
+ Writer.AddSourceLocation(S->getEllipsisLoc(), Record);
+ Writer.AddSourceLocation(S->getColonLoc(), Record);
+ Code = pch::STMT_CASE;
+}
+
+void PCHStmtWriter::VisitDefaultStmt(DefaultStmt *S) {
+ VisitSwitchCase(S);
+ Writer.WriteSubStmt(S->getSubStmt());
+ Writer.AddSourceLocation(S->getDefaultLoc(), Record);
+ Writer.AddSourceLocation(S->getColonLoc(), Record);
+ Code = pch::STMT_DEFAULT;
+}
+
+void PCHStmtWriter::VisitLabelStmt(LabelStmt *S) {
+ VisitStmt(S);
+ Writer.AddIdentifierRef(S->getID(), Record);
+ Writer.WriteSubStmt(S->getSubStmt());
+ Writer.AddSourceLocation(S->getIdentLoc(), Record);
+ Record.push_back(Writer.GetLabelID(S));
+ Code = pch::STMT_LABEL;
+}
+
+void PCHStmtWriter::VisitIfStmt(IfStmt *S) {
+ VisitStmt(S);
+ Writer.WriteSubStmt(S->getCond());
+ Writer.WriteSubStmt(S->getThen());
+ Writer.WriteSubStmt(S->getElse());
+ Writer.AddSourceLocation(S->getIfLoc(), Record);
+ Writer.AddSourceLocation(S->getElseLoc(), Record);
+ Code = pch::STMT_IF;
+}
+
+void PCHStmtWriter::VisitSwitchStmt(SwitchStmt *S) {
+ VisitStmt(S);
+ Writer.WriteSubStmt(S->getCond());
+ Writer.WriteSubStmt(S->getBody());
+ Writer.AddSourceLocation(S->getSwitchLoc(), Record);
+ for (SwitchCase *SC = S->getSwitchCaseList(); SC;
+ SC = SC->getNextSwitchCase())
+ Record.push_back(Writer.getSwitchCaseID(SC));
+ Code = pch::STMT_SWITCH;
+}
+
+void PCHStmtWriter::VisitWhileStmt(WhileStmt *S) {
+ VisitStmt(S);
+ Writer.WriteSubStmt(S->getCond());
+ Writer.WriteSubStmt(S->getBody());
+ Writer.AddSourceLocation(S->getWhileLoc(), Record);
+ Code = pch::STMT_WHILE;
+}
+
+void PCHStmtWriter::VisitDoStmt(DoStmt *S) {
+ VisitStmt(S);
+ Writer.WriteSubStmt(S->getCond());
+ Writer.WriteSubStmt(S->getBody());
+ Writer.AddSourceLocation(S->getDoLoc(), Record);
+ Writer.AddSourceLocation(S->getWhileLoc(), Record);
+ Code = pch::STMT_DO;
+}
+
+void PCHStmtWriter::VisitForStmt(ForStmt *S) {
+ VisitStmt(S);
+ Writer.WriteSubStmt(S->getInit());
+ Writer.WriteSubStmt(S->getCond());
+ Writer.WriteSubStmt(S->getInc());
+ Writer.WriteSubStmt(S->getBody());
+ Writer.AddSourceLocation(S->getForLoc(), Record);
+ Writer.AddSourceLocation(S->getLParenLoc(), Record);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Code = pch::STMT_FOR;
+}
+
+void PCHStmtWriter::VisitGotoStmt(GotoStmt *S) {
+ VisitStmt(S);
+ Record.push_back(Writer.GetLabelID(S->getLabel()));
+ Writer.AddSourceLocation(S->getGotoLoc(), Record);
+ Writer.AddSourceLocation(S->getLabelLoc(), Record);
+ Code = pch::STMT_GOTO;
+}
+
+void PCHStmtWriter::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getGotoLoc(), Record);
+ Writer.AddSourceLocation(S->getStarLoc(), Record);
+ Writer.WriteSubStmt(S->getTarget());
+ Code = pch::STMT_INDIRECT_GOTO;
+}
+
+void PCHStmtWriter::VisitContinueStmt(ContinueStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getContinueLoc(), Record);
+ Code = pch::STMT_CONTINUE;
+}
+
+void PCHStmtWriter::VisitBreakStmt(BreakStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getBreakLoc(), Record);
+ Code = pch::STMT_BREAK;
+}
+
+void PCHStmtWriter::VisitReturnStmt(ReturnStmt *S) {
+ VisitStmt(S);
+ Writer.WriteSubStmt(S->getRetValue());
+ Writer.AddSourceLocation(S->getReturnLoc(), Record);
+ Code = pch::STMT_RETURN;
+}
+
+void PCHStmtWriter::VisitDeclStmt(DeclStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getStartLoc(), Record);
+ Writer.AddSourceLocation(S->getEndLoc(), Record);
+ DeclGroupRef DG = S->getDeclGroup();
+ for (DeclGroupRef::iterator D = DG.begin(), DEnd = DG.end(); D != DEnd; ++D)
+ Writer.AddDeclRef(*D, Record);
+ Code = pch::STMT_DECL;
+}
+
+void PCHStmtWriter::VisitAsmStmt(AsmStmt *S) {
+ VisitStmt(S);
+ Record.push_back(S->getNumOutputs());
+ Record.push_back(S->getNumInputs());
+ Record.push_back(S->getNumClobbers());
+ Writer.AddSourceLocation(S->getAsmLoc(), Record);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Record.push_back(S->isVolatile());
+ Record.push_back(S->isSimple());
+ Writer.WriteSubStmt(S->getAsmString());
+
+ // Outputs
+ for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
+ Writer.AddString(S->getOutputName(I), Record);
+ Writer.WriteSubStmt(S->getOutputConstraintLiteral(I));
+ Writer.WriteSubStmt(S->getOutputExpr(I));
+ }
+
+ // Inputs
+ for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) {
+ Writer.AddString(S->getInputName(I), Record);
+ Writer.WriteSubStmt(S->getInputConstraintLiteral(I));
+ Writer.WriteSubStmt(S->getInputExpr(I));
+ }
+
+ // Clobbers
+ for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
+ Writer.WriteSubStmt(S->getClobber(I));
+
+ Code = pch::STMT_ASM;
+}
+
+void PCHStmtWriter::VisitExpr(Expr *E) {
+ VisitStmt(E);
+ Writer.AddTypeRef(E->getType(), Record);
+ Record.push_back(E->isTypeDependent());
+ Record.push_back(E->isValueDependent());
+}
+
+void PCHStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Record.push_back(E->getIdentType()); // FIXME: stable encoding
+ Code = pch::EXPR_PREDEFINED;
+}
+
+void PCHStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getDecl(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = pch::EXPR_DECL_REF;
+}
+
+void PCHStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Writer.AddAPInt(E->getValue(), Record);
+ Code = pch::EXPR_INTEGER_LITERAL;
+}
+
+void PCHStmtWriter::VisitFloatingLiteral(FloatingLiteral *E) {
+ VisitExpr(E);
+ Writer.AddAPFloat(E->getValue(), Record);
+ Record.push_back(E->isExact());
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = pch::EXPR_FLOATING_LITERAL;
+}
+
+void PCHStmtWriter::VisitImaginaryLiteral(ImaginaryLiteral *E) {
+ VisitExpr(E);
+ Writer.WriteSubStmt(E->getSubExpr());
+ Code = pch::EXPR_IMAGINARY_LITERAL;
+}
+
+void PCHStmtWriter::VisitStringLiteral(StringLiteral *E) {
+ VisitExpr(E);
+ Record.push_back(E->getByteLength());
+ Record.push_back(E->getNumConcatenated());
+ Record.push_back(E->isWide());
+ // 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
+ // provision for coping with abbreviations when we're jumping around
+ // the PCH file during deserialization.
+ Record.insert(Record.end(),
+ E->getStrData(), E->getStrData() + E->getByteLength());
+ for (unsigned I = 0, N = E->getNumConcatenated(); I != N; ++I)
+ Writer.AddSourceLocation(E->getStrTokenLoc(I), Record);
+ Code = pch::EXPR_STRING_LITERAL;
+}
+
+void PCHStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) {
+ VisitExpr(E);
+ Record.push_back(E->getValue());
+ Writer.AddSourceLocation(E->getLoc(), Record);
+ Record.push_back(E->isWide());
+ Code = pch::EXPR_CHARACTER_LITERAL;
+}
+
+void PCHStmtWriter::VisitParenExpr(ParenExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLParen(), Record);
+ Writer.AddSourceLocation(E->getRParen(), Record);
+ Writer.WriteSubStmt(E->getSubExpr());
+ Code = pch::EXPR_PAREN;
+}
+
+void PCHStmtWriter::VisitUnaryOperator(UnaryOperator *E) {
+ VisitExpr(E);
+ Writer.WriteSubStmt(E->getSubExpr());
+ Record.push_back(E->getOpcode()); // FIXME: stable encoding
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Code = pch::EXPR_UNARY_OPERATOR;
+}
+
+void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->isSizeOf());
+ if (E->isArgumentType())
+ Writer.AddTypeRef(E->getArgumentType(), Record);
+ else {
+ Record.push_back(0);
+ Writer.WriteSubStmt(E->getArgumentExpr());
+ }
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_SIZEOF_ALIGN_OF;
+}
+
+void PCHStmtWriter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+ VisitExpr(E);
+ Writer.WriteSubStmt(E->getLHS());
+ Writer.WriteSubStmt(E->getRHS());
+ Writer.AddSourceLocation(E->getRBracketLoc(), Record);
+ Code = pch::EXPR_ARRAY_SUBSCRIPT;
+}
+
+void PCHStmtWriter::VisitCallExpr(CallExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumArgs());
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Writer.WriteSubStmt(E->getCallee());
+ for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end();
+ Arg != ArgEnd; ++Arg)
+ Writer.WriteSubStmt(*Arg);
+ Code = pch::EXPR_CALL;
+}
+
+void PCHStmtWriter::VisitMemberExpr(MemberExpr *E) {
+ VisitExpr(E);
+ Writer.WriteSubStmt(E->getBase());
+ Writer.AddDeclRef(E->getMemberDecl(), Record);
+ Writer.AddSourceLocation(E->getMemberLoc(), Record);
+ Record.push_back(E->isArrow());
+ Code = pch::EXPR_MEMBER;
+}
+
+void PCHStmtWriter::VisitCastExpr(CastExpr *E) {
+ VisitExpr(E);
+ Writer.WriteSubStmt(E->getSubExpr());
+}
+
+void PCHStmtWriter::VisitBinaryOperator(BinaryOperator *E) {
+ VisitExpr(E);
+ Writer.WriteSubStmt(E->getLHS());
+ Writer.WriteSubStmt(E->getRHS());
+ Record.push_back(E->getOpcode()); // FIXME: stable encoding
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Code = pch::EXPR_BINARY_OPERATOR;
+}
+
+void PCHStmtWriter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
+ VisitBinaryOperator(E);
+ Writer.AddTypeRef(E->getComputationLHSType(), Record);
+ Writer.AddTypeRef(E->getComputationResultType(), Record);
+ Code = pch::EXPR_COMPOUND_ASSIGN_OPERATOR;
+}
+
+void PCHStmtWriter::VisitConditionalOperator(ConditionalOperator *E) {
+ VisitExpr(E);
+ Writer.WriteSubStmt(E->getCond());
+ Writer.WriteSubStmt(E->getLHS());
+ Writer.WriteSubStmt(E->getRHS());
+ Code = pch::EXPR_CONDITIONAL_OPERATOR;
+}
+
+void PCHStmtWriter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ VisitCastExpr(E);
+ Record.push_back(E->isLvalueCast());
+ Code = pch::EXPR_IMPLICIT_CAST;
+}
+
+void PCHStmtWriter::VisitExplicitCastExpr(ExplicitCastExpr *E) {
+ VisitCastExpr(E);
+ Writer.AddTypeRef(E->getTypeAsWritten(), Record);
+}
+
+void PCHStmtWriter::VisitCStyleCastExpr(CStyleCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ Writer.AddSourceLocation(E->getLParenLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_CSTYLE_CAST;
+}
+
+void PCHStmtWriter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLParenLoc(), Record);
+ Writer.WriteSubStmt(E->getInitializer());
+ Record.push_back(E->isFileScope());
+ Code = pch::EXPR_COMPOUND_LITERAL;
+}
+
+void PCHStmtWriter::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
+ VisitExpr(E);
+ Writer.WriteSubStmt(E->getBase());
+ Writer.AddIdentifierRef(&E->getAccessor(), Record);
+ Writer.AddSourceLocation(E->getAccessorLoc(), Record);
+ Code = pch::EXPR_EXT_VECTOR_ELEMENT;
+}
+
+void PCHStmtWriter::VisitInitListExpr(InitListExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumInits());
+ for (unsigned I = 0, N = E->getNumInits(); I != N; ++I)
+ Writer.WriteSubStmt(E->getInit(I));
+ Writer.WriteSubStmt(E->getSyntacticForm());
+ Writer.AddSourceLocation(E->getLBraceLoc(), Record);
+ Writer.AddSourceLocation(E->getRBraceLoc(), Record);
+ Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record);
+ Record.push_back(E->hadArrayRangeDesignator());
+ Code = pch::EXPR_INIT_LIST;
+}
+
+void PCHStmtWriter::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumSubExprs());
+ for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I)
+ Writer.WriteSubStmt(E->getSubExpr(I));
+ Writer.AddSourceLocation(E->getEqualOrColonLoc(), Record);
+ Record.push_back(E->usesGNUSyntax());
+ for (DesignatedInitExpr::designators_iterator D = E->designators_begin(),
+ DEnd = E->designators_end();
+ D != DEnd; ++D) {
+ if (D->isFieldDesignator()) {
+ if (FieldDecl *Field = D->getField()) {
+ Record.push_back(pch::DESIG_FIELD_DECL);
+ Writer.AddDeclRef(Field, Record);
+ } else {
+ Record.push_back(pch::DESIG_FIELD_NAME);
+ Writer.AddIdentifierRef(D->getFieldName(), Record);
+ }
+ Writer.AddSourceLocation(D->getDotLoc(), Record);
+ Writer.AddSourceLocation(D->getFieldLoc(), Record);
+ } else if (D->isArrayDesignator()) {
+ Record.push_back(pch::DESIG_ARRAY);
+ Record.push_back(D->getFirstExprIndex());
+ Writer.AddSourceLocation(D->getLBracketLoc(), Record);
+ Writer.AddSourceLocation(D->getRBracketLoc(), Record);
+ } else {
+ assert(D->isArrayRangeDesignator() && "Unknown designator");
+ Record.push_back(pch::DESIG_ARRAY_RANGE);
+ Record.push_back(D->getFirstExprIndex());
+ Writer.AddSourceLocation(D->getLBracketLoc(), Record);
+ Writer.AddSourceLocation(D->getEllipsisLoc(), Record);
+ Writer.AddSourceLocation(D->getRBracketLoc(), Record);
+ }
+ }
+ Code = pch::EXPR_DESIGNATED_INIT;
+}
+
+void PCHStmtWriter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
+ VisitExpr(E);
+ Code = pch::EXPR_IMPLICIT_VALUE_INIT;
+}
+
+void PCHStmtWriter::VisitVAArgExpr(VAArgExpr *E) {
+ VisitExpr(E);
+ Writer.WriteSubStmt(E->getSubExpr());
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_VA_ARG;
+}
+
+void PCHStmtWriter::VisitAddrLabelExpr(AddrLabelExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getAmpAmpLoc(), Record);
+ Writer.AddSourceLocation(E->getLabelLoc(), Record);
+ Record.push_back(Writer.GetLabelID(E->getLabel()));
+ Code = pch::EXPR_ADDR_LABEL;
+}
+
+void PCHStmtWriter::VisitStmtExpr(StmtExpr *E) {
+ VisitExpr(E);
+ Writer.WriteSubStmt(E->getSubStmt());
+ Writer.AddSourceLocation(E->getLParenLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_STMT;
+}
+
+void PCHStmtWriter::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) {
+ VisitExpr(E);
+ Writer.AddTypeRef(E->getArgType1(), Record);
+ Writer.AddTypeRef(E->getArgType2(), Record);
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_TYPES_COMPATIBLE;
+}
+
+void PCHStmtWriter::VisitChooseExpr(ChooseExpr *E) {
+ VisitExpr(E);
+ Writer.WriteSubStmt(E->getCond());
+ Writer.WriteSubStmt(E->getLHS());
+ Writer.WriteSubStmt(E->getRHS());
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_CHOOSE;
+}
+
+void PCHStmtWriter::VisitGNUNullExpr(GNUNullExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getTokenLocation(), Record);
+ Code = pch::EXPR_GNU_NULL;
+}
+
+void PCHStmtWriter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumSubExprs());
+ for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I)
+ Writer.WriteSubStmt(E->getExpr(I));
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_SHUFFLE_VECTOR;
+}
+
+void PCHStmtWriter::VisitBlockExpr(BlockExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getBlockDecl(), Record);
+ Record.push_back(E->hasBlockDeclRefExprs());
+ Code = pch::EXPR_BLOCK;
+}
+
+void PCHStmtWriter::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getDecl(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Record.push_back(E->isByRef());
+ Code = pch::EXPR_BLOCK_DECL_REF;
+}
+
+//===----------------------------------------------------------------------===//
+// Objective-C Expressions and Statements.
+//===----------------------------------------------------------------------===//
+
+void PCHStmtWriter::VisitObjCStringLiteral(ObjCStringLiteral *E) {
+ VisitExpr(E);
+ Writer.WriteSubStmt(E->getString());
+ Writer.AddSourceLocation(E->getAtLoc(), Record);
+ Code = pch::EXPR_OBJC_STRING_LITERAL;
+}
+
+void PCHStmtWriter::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
+ VisitExpr(E);
+ Writer.AddTypeRef(E->getEncodedType(), Record);
+ Writer.AddSourceLocation(E->getAtLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_OBJC_ENCODE;
+}
+
+void PCHStmtWriter::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
+ VisitExpr(E);
+ Writer.AddSelectorRef(E->getSelector(), Record);
+ Writer.AddSourceLocation(E->getAtLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_OBJC_SELECTOR_EXPR;
+}
+
+void PCHStmtWriter::VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getProtocol(), Record);
+ Writer.AddSourceLocation(E->getAtLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_OBJC_PROTOCOL_EXPR;
+}
+
+void PCHStmtWriter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getDecl(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Writer.WriteSubStmt(E->getBase());
+ Record.push_back(E->isArrow());
+ Record.push_back(E->isFreeIvar());
+ Code = pch::EXPR_OBJC_IVAR_REF_EXPR;
+}
+
+void PCHStmtWriter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getProperty(), Record);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Writer.WriteSubStmt(E->getBase());
+ Code = pch::EXPR_OBJC_PROPERTY_REF_EXPR;
+}
+
+void PCHStmtWriter::VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getGetterMethod(), Record);
+ Writer.AddDeclRef(E->getSetterMethod(), Record);
+
+ // NOTE: ClassProp and Base are mutually exclusive.
+ Writer.AddDeclRef(E->getClassProp(), Record);
+ Writer.WriteSubStmt(E->getBase());
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Writer.AddSourceLocation(E->getClassLoc(), Record);
+ Code = pch::EXPR_OBJC_KVC_REF_EXPR;
+}
+
+void PCHStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumArgs());
+ Writer.AddSourceLocation(E->getLeftLoc(), Record);
+ Writer.AddSourceLocation(E->getRightLoc(), Record);
+ Writer.AddSelectorRef(E->getSelector(), Record);
+ Writer.AddDeclRef(E->getMethodDecl(), Record); // optional
+ Writer.WriteSubStmt(E->getReceiver());
+
+ if (!E->getReceiver()) {
+ ObjCMessageExpr::ClassInfo CI = E->getClassInfo();
+ Writer.AddDeclRef(CI.first, Record);
+ Writer.AddIdentifierRef(CI.second, Record);
+ }
+
+ for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end();
+ Arg != ArgEnd; ++Arg)
+ Writer.WriteSubStmt(*Arg);
+ Code = pch::EXPR_OBJC_MESSAGE_EXPR;
+}
+
+void PCHStmtWriter::VisitObjCSuperExpr(ObjCSuperExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLoc(), Record);
+ Code = pch::EXPR_OBJC_SUPER_EXPR;
+}
+
+void PCHStmtWriter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
+ VisitStmt(S);
+ Writer.WriteSubStmt(S->getElement());
+ Writer.WriteSubStmt(S->getCollection());
+ Writer.WriteSubStmt(S->getBody());
+ Writer.AddSourceLocation(S->getForLoc(), Record);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Code = pch::STMT_OBJC_FOR_COLLECTION;
+}
+
+void PCHStmtWriter::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
+ Writer.WriteSubStmt(S->getCatchBody());
+ Writer.WriteSubStmt(S->getNextCatchStmt());
+ Writer.AddDeclRef(S->getCatchParamDecl(), Record);
+ Writer.AddSourceLocation(S->getAtCatchLoc(), Record);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Code = pch::STMT_OBJC_CATCH;
+}
+
+void PCHStmtWriter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
+ Writer.WriteSubStmt(S->getFinallyBody());
+ Writer.AddSourceLocation(S->getAtFinallyLoc(), Record);
+ Code = pch::STMT_OBJC_FINALLY;
+}
+
+void PCHStmtWriter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
+ Writer.WriteSubStmt(S->getTryBody());
+ Writer.WriteSubStmt(S->getCatchStmts());
+ Writer.WriteSubStmt(S->getFinallyStmt());
+ Writer.AddSourceLocation(S->getAtTryLoc(), Record);
+ Code = pch::STMT_OBJC_AT_TRY;
+}
+
+void PCHStmtWriter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
+ Writer.WriteSubStmt(S->getSynchExpr());
+ Writer.WriteSubStmt(S->getSynchBody());
+ Writer.AddSourceLocation(S->getAtSynchronizedLoc(), Record);
+ Code = pch::STMT_OBJC_AT_SYNCHRONIZED;
+}
+
+void PCHStmtWriter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
+ Writer.WriteSubStmt(S->getThrowExpr());
+ Writer.AddSourceLocation(S->getThrowLoc(), Record);
+ Code = pch::STMT_OBJC_AT_THROW;
+}
+
+//===----------------------------------------------------------------------===//
+// PCHWriter Implementation
+//===----------------------------------------------------------------------===//
+
+unsigned PCHWriter::RecordSwitchCaseID(SwitchCase *S) {
+ assert(SwitchCaseIDs.find(S) == SwitchCaseIDs.end() &&
+ "SwitchCase recorded twice");
+ unsigned NextID = SwitchCaseIDs.size();
+ SwitchCaseIDs[S] = NextID;
+ return NextID;
+}
+
+unsigned PCHWriter::getSwitchCaseID(SwitchCase *S) {
+ assert(SwitchCaseIDs.find(S) != SwitchCaseIDs.end() &&
+ "SwitchCase hasn't been seen yet");
+ return SwitchCaseIDs[S];
+}
+
+/// \brief Retrieve the ID for the given label statement, which may
+/// or may not have been emitted yet.
+unsigned PCHWriter::GetLabelID(LabelStmt *S) {
+ std::map<LabelStmt *, unsigned>::iterator Pos = LabelIDs.find(S);
+ if (Pos != LabelIDs.end())
+ return Pos->second;
+
+ unsigned NextID = LabelIDs.size();
+ LabelIDs[S] = NextID;
+ return NextID;
+}
+
+/// \brief Write the given substatement or subexpression to the
+/// bitstream.
+void PCHWriter::WriteSubStmt(Stmt *S) {
+ RecordData Record;
+ PCHStmtWriter Writer(*this, Record);
+ ++NumStatements;
+
+ if (!S) {
+ Stream.EmitRecord(pch::STMT_NULL_PTR, Record);
+ return;
+ }
+
+ Writer.Code = pch::STMT_NULL_PTR;
+ Writer.Visit(S);
+ assert(Writer.Code != pch::STMT_NULL_PTR &&
+ "Unhandled expression writing PCH file");
+ Stream.EmitRecord(Writer.Code, Record);
+}
+
+/// \brief Flush all of the statements that have been added to the
+/// queue via AddStmt().
+void PCHWriter::FlushStmts() {
+ RecordData Record;
+ PCHStmtWriter Writer(*this, Record);
+
+ for (unsigned I = 0, N = StmtsToEmit.size(); I != N; ++I) {
+ ++NumStatements;
+ Stmt *S = StmtsToEmit[I];
+
+ if (!S) {
+ Stream.EmitRecord(pch::STMT_NULL_PTR, Record);
+ continue;
+ }
+
+ Writer.Code = pch::STMT_NULL_PTR;
+ Writer.Visit(S);
+ assert(Writer.Code != pch::STMT_NULL_PTR &&
+ "Unhandled expression writing PCH file");
+ Stream.EmitRecord(Writer.Code, Record);
+
+ assert(N == StmtsToEmit.size() &&
+ "Substatement writen via AddStmt rather than WriteSubStmt!");
+
+ // Note that we are at the end of a full expression. Any
+ // expression records that follow this one are part of a different
+ // expression.
+ Record.clear();
+ Stream.EmitRecord(pch::STMT_STOP, Record);
+ }
+
+ StmtsToEmit.clear();
+ SwitchCaseIDs.clear();
+}
diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp
new file mode 100644
index 000000000000..387ed45a9c71
--- /dev/null
+++ b/lib/Frontend/PlistDiagnostics.cpp
@@ -0,0 +1,389 @@
+//===--- PlistDiagnostics.cpp - Plist Diagnostics for Paths -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the PlistDiagnostics object.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PathDiagnosticClients.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/System/Path.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+using namespace clang;
+using llvm::cast;
+
+typedef llvm::DenseMap<FileID, unsigned> FIDMap;
+
+namespace clang {
+ class Preprocessor;
+ class PreprocessorFactory;
+}
+
+namespace {
+ class VISIBILITY_HIDDEN PlistDiagnostics : public PathDiagnosticClient {
+ std::vector<const PathDiagnostic*> BatchedDiags;
+ const std::string OutputFile;
+ const LangOptions &LangOpts;
+ public:
+ PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts);
+ ~PlistDiagnostics();
+ void HandlePathDiagnostic(const PathDiagnostic* D);
+
+ PathGenerationScheme getGenerationScheme() const { return Extensive; }
+ bool supportsLogicalOpControlFlow() const { return true; }
+ bool supportsAllBlockEdges() const { return true; }
+ virtual bool useVerboseDescription() const { return false; }
+ };
+} // end anonymous namespace
+
+PlistDiagnostics::PlistDiagnostics(const std::string& output,
+ const LangOptions &LO)
+ : OutputFile(output), LangOpts(LO) {}
+
+PathDiagnosticClient*
+clang::CreatePlistDiagnosticClient(const std::string& s,
+ Preprocessor *PP, PreprocessorFactory*) {
+ return new PlistDiagnostics(s, PP->getLangOptions());
+}
+
+static void AddFID(FIDMap &FIDs, llvm::SmallVectorImpl<FileID> &V,
+ const SourceManager* SM, SourceLocation L) {
+
+ FileID FID = SM->getFileID(SM->getInstantiationLoc(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.getInstantiationLoc(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) {
+ for (unsigned i = 0; i < indent; ++i) o << ' ';
+ return o;
+}
+
+static void EmitLocation(llvm::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));
+
+ // 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.getInstantiationLineNumber() << "</integer>\n";
+ Indent(o, indent) << " <key>col</key><integer>"
+ << Loc.getInstantiationColumnNumber() + 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,
+ 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,
+ const LangOptions &LangOpts,
+ PathDiagnosticRange 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.isPoint);
+ Indent(o, indent) << "</array>\n";
+}
+
+static llvm::raw_ostream& EmitString(llvm::raw_ostream& o,
+ const std::string& s) {
+ o << "<string>";
+ for (std::string::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;
+}
+
+static void ReportControlFlow(llvm::raw_ostream& o,
+ const PathDiagnosticControlFlowPiece& P,
+ const FIDMap& FM,
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ unsigned indent) {
+
+ Indent(o, indent) << "<dict>\n";
+ ++indent;
+
+ Indent(o, indent) << "<key>kind</key><string>control</string>\n";
+
+ // Emit edges.
+ Indent(o, indent) << "<key>edges</key>\n";
+ ++indent;
+ Indent(o, indent) << "<array>\n";
+ ++indent;
+ for (PathDiagnosticControlFlowPiece::const_iterator I=P.begin(), E=P.end();
+ I!=E; ++I) {
+ Indent(o, indent) << "<dict>\n";
+ ++indent;
+ Indent(o, indent) << "<key>start</key>\n";
+ EmitRange(o, SM, LangOpts, I->getStart().asRange(), FM, indent+1);
+ Indent(o, indent) << "<key>end</key>\n";
+ EmitRange(o, SM, LangOpts, I->getEnd().asRange(), FM, indent+1);
+ --indent;
+ Indent(o, indent) << "</dict>\n";
+ }
+ --indent;
+ Indent(o, indent) << "</array>\n";
+ --indent;
+
+ // Output any helper text.
+ const std::string& s = P.getString();
+ if (!s.empty()) {
+ Indent(o, indent) << "<key>alternate</key>";
+ EmitString(o, s) << '\n';
+ }
+
+ --indent;
+ Indent(o, indent) << "</dict>\n";
+}
+
+static void ReportEvent(llvm::raw_ostream& o, const PathDiagnosticPiece& P,
+ const FIDMap& FM,
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ unsigned indent) {
+
+ Indent(o, indent) << "<dict>\n";
+ ++indent;
+
+ Indent(o, indent) << "<key>kind</key><string>event</string>\n";
+
+ // Output the location.
+ FullSourceLoc L = P.getLocation().asLocation();
+
+ Indent(o, indent) << "<key>location</key>\n";
+ EmitLocation(o, SM, LangOpts, L, FM, indent);
+
+ // Output the ranges (if any).
+ PathDiagnosticPiece::range_iterator RI = P.ranges_begin(),
+ RE = P.ranges_end();
+
+ if (RI != RE) {
+ Indent(o, indent) << "<key>ranges</key>\n";
+ Indent(o, indent) << "<array>\n";
+ ++indent;
+ for (; RI != RE; ++RI)
+ EmitRange(o, SM, LangOpts, *RI, FM, indent+1);
+ --indent;
+ Indent(o, indent) << "</array>\n";
+ }
+
+ // Output the text.
+ assert(!P.getString().empty());
+ Indent(o, indent) << "<key>extended_message</key>\n";
+ Indent(o, indent);
+ EmitString(o, P.getString()) << '\n';
+
+ // Output the short text.
+ // FIXME: Really use a short string.
+ Indent(o, indent) << "<key>message</key>\n";
+ EmitString(o, P.getString()) << '\n';
+
+ // Finish up.
+ --indent;
+ Indent(o, indent); o << "</dict>\n";
+}
+
+static void ReportMacro(llvm::raw_ostream& o,
+ const PathDiagnosticMacroPiece& P,
+ const FIDMap& FM, const SourceManager &SM,
+ const LangOptions &LangOpts,
+ unsigned indent) {
+
+ for (PathDiagnosticMacroPiece::const_iterator I=P.begin(), E=P.end();
+ I!=E; ++I) {
+
+ switch ((*I)->getKind()) {
+ default:
+ break;
+ case PathDiagnosticPiece::Event:
+ ReportEvent(o, cast<PathDiagnosticEventPiece>(**I), FM, SM, LangOpts,
+ indent);
+ break;
+ case PathDiagnosticPiece::Macro:
+ ReportMacro(o, cast<PathDiagnosticMacroPiece>(**I), FM, SM, LangOpts,
+ indent);
+ break;
+ }
+ }
+}
+
+static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P,
+ const FIDMap& FM, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+
+ unsigned indent = 4;
+
+ switch (P.getKind()) {
+ case PathDiagnosticPiece::ControlFlow:
+ ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, SM,
+ LangOpts, indent);
+ break;
+ case PathDiagnosticPiece::Event:
+ ReportEvent(o, cast<PathDiagnosticEventPiece>(P), FM, SM, LangOpts,
+ indent);
+ break;
+ case PathDiagnosticPiece::Macro:
+ ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts,
+ indent);
+ break;
+ }
+}
+
+void PlistDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
+ if (!D)
+ return;
+
+ if (D->empty()) {
+ delete D;
+ return;
+ }
+
+ // We need to flatten the locations (convert Stmt* to locations) because
+ // the referenced statements may be freed by the time the diagnostics
+ // are emitted.
+ const_cast<PathDiagnostic*>(D)->flattenLocations();
+ BatchedDiags.push_back(D);
+}
+
+PlistDiagnostics::~PlistDiagnostics() {
+
+ // 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;
+ const SourceManager* SM = 0;
+
+ if (!BatchedDiags.empty())
+ SM = &(*BatchedDiags.begin())->begin()->getLocation().getManager();
+
+ for (std::vector<const PathDiagnostic*>::iterator DI = BatchedDiags.begin(),
+ DE = BatchedDiags.end(); DI != DE; ++DI) {
+
+ const PathDiagnostic *D = *DI;
+
+ for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I!=E; ++I) {
+ AddFID(FM, Fids, SM, I->getLocation().asLocation());
+
+ for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(),
+ RE=I->ranges_end(); RI!=RE; ++RI) {
+ AddFID(FM, Fids, SM, RI->getBegin());
+ AddFID(FM, Fids, SM, RI->getEnd());
+ }
+ }
+ }
+
+ // Open the file.
+ std::string ErrMsg;
+ llvm::raw_fd_ostream o(OutputFile.c_str(), false, ErrMsg);
+ if (!ErrMsg.empty()) {
+ llvm::errs() << "warning: could not creat file: " << OutputFile << '\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 path diagnostics
+ o << "<dict>\n"
+ " <key>files</key>\n"
+ " <array>\n";
+
+ for (llvm::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 (std::vector<const PathDiagnostic*>::iterator DI=BatchedDiags.begin(),
+ DE = BatchedDiags.end(); DI!=DE; ++DI) {
+
+ o << " <dict>\n"
+ " <key>path</key>\n";
+
+ const PathDiagnostic *D = *DI;
+ // Create an owning smart pointer for 'D' just so that we auto-free it
+ // when we exit this method.
+ llvm::OwningPtr<PathDiagnostic> OwnedD(const_cast<PathDiagnostic*>(D));
+
+ o << " <array>\n";
+
+ for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I)
+ ReportDiag(o, *I, FM, *SM, LangOpts);
+
+ o << " </array>\n";
+
+ // Output the bug type and bug category.
+ o << " <key>description</key>";
+ EmitString(o, D->getDescription()) << '\n';
+ o << " <key>category</key>";
+ EmitString(o, D->getCategory()) << '\n';
+ o << " <key>type</key>";
+ EmitString(o, D->getBugType()) << '\n';
+
+ // Output the location of the bug.
+ o << " <key>location</key>\n";
+ EmitLocation(o, *SM, LangOpts, D->getLocation(), FM, 2);
+
+ // Close up the entry.
+ o << " </dict>\n";
+ }
+
+ o << " </array>\n";
+
+ // Finish.
+ o << "</dict>\n</plist>";
+}
diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp
new file mode 100644
index 000000000000..f02d5d469c64
--- /dev/null
+++ b/lib/Frontend/PrintParserCallbacks.cpp
@@ -0,0 +1,831 @@
+//===--- PrintParserActions.cpp - Implement -parse-print-callbacks mode ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This code simply runs the preprocessor on the input file and prints out the
+// result. This is the traditional behavior of the -E option.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Parse/Action.h"
+#include "clang/Parse/DeclSpec.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+namespace {
+ class ParserPrintActions : public MinimalAction {
+ llvm::raw_ostream& Out;
+
+ public:
+ ParserPrintActions(Preprocessor &PP, llvm::raw_ostream& OS)
+ : MinimalAction(PP), Out(OS) {}
+
+ // Printing Functions which also must call MinimalAction
+
+ /// ActOnDeclarator - This callback is invoked when a declarator is parsed
+ /// and 'Init' specifies the initializer if any. This is for things like:
+ /// "int X = 4" or "typedef int foo".
+ virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) {
+ Out << __FUNCTION__ << " ";
+ if (IdentifierInfo *II = D.getIdentifier()) {
+ Out << "'" << II->getName() << "'";
+ } else {
+ Out << "<anon>";
+ }
+ Out << "\n";
+
+ // Pass up to EmptyActions so that the symbol table is maintained right.
+ return MinimalAction::ActOnDeclarator(S, D);
+ }
+ /// ActOnPopScope - This callback is called immediately before the specified
+ /// scope is popped and deleted.
+ virtual void ActOnPopScope(SourceLocation Loc, Scope *S) {
+ Out << __FUNCTION__ << "\n";
+ return MinimalAction::ActOnPopScope(Loc, S);
+ }
+
+ /// ActOnTranslationUnitScope - This callback is called once, immediately
+ /// after creating the translation unit scope (in Parser::Initialize).
+ virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
+ Out << __FUNCTION__ << "\n";
+ MinimalAction::ActOnTranslationUnitScope(Loc, S);
+ }
+
+
+ Action::DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLoc,
+ IdentifierInfo *SuperName,
+ SourceLocation SuperLoc,
+ const DeclPtrTy *ProtoRefs,
+ unsigned NumProtocols,
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList) {
+ Out << __FUNCTION__ << "\n";
+ return MinimalAction::ActOnStartClassInterface(AtInterfaceLoc,
+ ClassName, ClassLoc,
+ SuperName, SuperLoc,
+ ProtoRefs, NumProtocols,
+ EndProtoLoc, AttrList);
+ }
+
+ /// ActOnForwardClassDeclaration -
+ /// Scope will always be top level file scope.
+ Action::DeclPtrTy ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
+ IdentifierInfo **IdentList,
+ unsigned NumElts) {
+ Out << __FUNCTION__ << "\n";
+ return MinimalAction::ActOnForwardClassDeclaration(AtClassLoc, IdentList,
+ NumElts);
+ }
+
+ // Pure Printing
+
+ /// ActOnParamDeclarator - This callback is invoked when a parameter
+ /// declarator is parsed. This callback only occurs for functions
+ /// with prototypes. S is the function prototype scope for the
+ /// parameters (C++ [basic.scope.proto]).
+ virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D) {
+ Out << __FUNCTION__ << " ";
+ if (IdentifierInfo *II = D.getIdentifier()) {
+ Out << "'" << II->getName() << "'";
+ } else {
+ Out << "<anon>";
+ }
+ Out << "\n";
+ return DeclPtrTy();
+ }
+
+ /// AddInitializerToDecl - This action is called immediately after
+ /// ParseDeclarator (when an initializer is present). The code is factored
+ /// this way to make sure we are able to handle the following:
+ /// void func() { int xx = xx; }
+ /// This allows ActOnDeclarator to register "xx" prior to parsing the
+ /// initializer. The declaration above should still result in a warning,
+ /// since the reference to "xx" is uninitialized.
+ virtual void AddInitializerToDecl(DeclPtrTy Dcl, FullExprArg Init) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ /// FinalizeDeclaratorGroup - After a sequence of declarators are parsed,
+ /// this gives the actions implementation a chance to process the group as
+ /// a whole.
+ virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec& DS,
+ DeclPtrTy *Group,
+ unsigned NumDecls) {
+ Out << __FUNCTION__ << "\n";
+ return DeclGroupPtrTy();
+ }
+
+ /// ActOnStartOfFunctionDef - This is called at the start of a function
+ /// definition, instead of calling ActOnDeclarator. The Declarator includes
+ /// information about formal arguments that are part of this function.
+ virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *FnBodyScope,
+ Declarator &D){
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ /// ActOnStartOfFunctionDef - This is called at the start of a function
+ /// definition, after the FunctionDecl has already been created.
+ virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual void ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ /// ActOnFunctionDefBody - This is called when a function body has completed
+ /// parsing. Decl is the DeclTy returned by ParseStartOfFunctionDef.
+ virtual DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual DeclPtrTy ActOnFileScopeAsmDecl(SourceLocation Loc,
+ ExprArg AsmString) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
+ /// no declarator (e.g. "struct foo;") is parsed.
+ virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ /// ActOnLinkageSpec - Parsed a C++ linkage-specification that
+ /// contained braces. Lang/StrSize contains the language string that
+ /// was parsed at location Loc. Decls/NumDecls provides the
+ /// declarations parsed inside the linkage specification.
+ virtual DeclPtrTy ActOnLinkageSpec(SourceLocation Loc,
+ SourceLocation LBrace,
+ SourceLocation RBrace, const char *Lang,
+ unsigned StrSize,
+ DeclPtrTy *Decls, unsigned NumDecls) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ /// ActOnLinkageSpec - Parsed a C++ linkage-specification without
+ /// braces. Lang/StrSize contains the language string that was
+ /// parsed at location Loc. D is the declaration parsed.
+ virtual DeclPtrTy ActOnLinkageSpec(SourceLocation Loc, const char *Lang,
+ unsigned StrSize, DeclPtrTy D) {
+ return DeclPtrTy();
+ }
+
+ //===------------------------------------------------------------------===//
+ // Type Parsing Callbacks.
+ //===------------------------------------------------------------------===//
+
+ virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) {
+ Out << __FUNCTION__ << "\n";
+ return TypeResult();
+ }
+
+ virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagType, TagKind TK,
+ SourceLocation KWLoc, const CXXScopeSpec &SS,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ AttributeList *Attr, AccessSpecifier AS,
+ bool &Owned) {
+ // TagType is an instance of DeclSpec::TST, indicating what kind of tag this
+ // is (struct/union/enum/class).
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ /// Act on @defs() element found when parsing a structure. ClassName is the
+ /// name of the referenced class.
+ virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
+ IdentifierInfo *ClassName,
+ llvm::SmallVectorImpl<DeclPtrTy> &Decls) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual DeclPtrTy ActOnField(Scope *S, DeclPtrTy TagD,
+ SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth,
+ tok::ObjCKeywordKind visibility) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual void ActOnFields(Scope* S, SourceLocation RecLoc, DeclPtrTy TagDecl,
+ DeclPtrTy *Fields, unsigned NumFields,
+ SourceLocation LBrac, SourceLocation RBrac,
+ AttributeList *AttrList) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual DeclPtrTy ActOnEnumConstant(Scope *S, DeclPtrTy EnumDecl,
+ DeclPtrTy LastEnumConstant,
+ SourceLocation IdLoc,IdentifierInfo *Id,
+ SourceLocation EqualLoc, ExprTy *Val) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
+ SourceLocation RBraceLoc, DeclPtrTy EnumDecl,
+ DeclPtrTy *Elements, unsigned NumElements) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ //===------------------------------------------------------------------===//
+ // Statement Parsing Callbacks.
+ //===------------------------------------------------------------------===//
+
+ virtual OwningStmtResult ActOnNullStmt(SourceLocation SemiLoc) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnCompoundStmt(SourceLocation L,
+ SourceLocation R,
+ MultiStmtArg Elts,
+ bool isStmtExpr) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnDeclStmt(DeclGroupPtrTy Decl,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnExprStmt(FullExprArg Expr) {
+ Out << __FUNCTION__ << "\n";
+ return OwningStmtResult(*this, Expr->release());
+ }
+
+ /// ActOnCaseStmt - Note that this handles the GNU 'case 1 ... 4' extension,
+ /// which can specify an RHS value.
+ virtual OwningStmtResult ActOnCaseStmt(SourceLocation CaseLoc,
+ ExprArg LHSVal,
+ SourceLocation DotDotDotLoc,
+ ExprArg RHSVal,
+ SourceLocation ColonLoc) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt, Scope *CurScope){
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnLabelStmt(SourceLocation IdentLoc,
+ IdentifierInfo *II,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc,
+ FullExprArg CondVal, StmtArg ThenVal,
+ SourceLocation ElseLoc,
+ StmtArg ElseVal) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
+ StmtArg Switch,
+ StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
+ FullExprArg Cond, StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
+ SourceLocation WhileLoc, ExprArg Cond){
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc,
+ StmtArg First, ExprArg Second,
+ ExprArg Third, SourceLocation RParenLoc,
+ StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnObjCForCollectionStmt(
+ SourceLocation ForColLoc,
+ SourceLocation LParenLoc,
+ StmtArg First, ExprArg Second,
+ SourceLocation RParenLoc, StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnGotoStmt(SourceLocation GotoLoc,
+ SourceLocation LabelLoc,
+ IdentifierInfo *LabelII) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc,
+ SourceLocation StarLoc,
+ ExprArg DestExp) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnContinueStmt(SourceLocation ContinueLoc,
+ Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnBreakStmt(SourceLocation GotoLoc,
+ Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc,
+ FullExprArg RetValExp) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnAsmStmt(SourceLocation AsmLoc,
+ bool IsSimple,
+ bool IsVolatile,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ std::string *Names,
+ MultiExprArg Constraints,
+ MultiExprArg Exprs,
+ ExprArg AsmString,
+ MultiExprArg Clobbers,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ // Objective-c statements
+ virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
+ SourceLocation RParen,
+ DeclPtrTy Parm, StmtArg Body,
+ StmtArg CatchList) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc,
+ StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
+ StmtArg Try, StmtArg Catch,
+ StmtArg Finally) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
+ ExprArg Throw,
+ Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc,
+ ExprArg SynchExpr,
+ StmtArg SynchBody) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ // C++ Statements
+ virtual DeclPtrTy ActOnExceptionDeclarator(Scope *S, Declarator &D) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
+ DeclPtrTy ExceptionDecl,
+ StmtArg HandlerBlock) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc,
+ StmtArg TryBlock,
+ MultiStmtArg Handlers) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ //===------------------------------------------------------------------===//
+ // Expression Parsing Callbacks.
+ //===------------------------------------------------------------------===//
+
+ // Primary Expressions.
+
+ /// ActOnIdentifierExpr - Parse an identifier in expression context.
+ /// 'HasTrailingLParen' indicates whether or not the identifier has a '('
+ /// token immediately after it.
+ virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
+ IdentifierInfo &II,
+ bool HasTrailingLParen,
+ const CXXScopeSpec *SS,
+ bool isAddressOfOperand) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(
+ Scope *S, SourceLocation OperatorLoc,
+ OverloadedOperatorKind Op,
+ bool HasTrailingLParen, const CXXScopeSpec &SS,
+ bool isAddressOfOperand) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXConversionFunctionExpr(
+ Scope *S, SourceLocation OperatorLoc,
+ TypeTy *Type, bool HasTrailingLParen,
+ const CXXScopeSpec &SS,bool isAddressOfOperand) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc,
+ tok::TokenKind Kind) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCharacterConstant(const Token &) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnNumericConstant(const Token &) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ /// ActOnStringLiteral - The specified tokens were lexed as pasted string
+ /// fragments (e.g. "foo" "bar" L"baz").
+ virtual OwningExprResult ActOnStringLiteral(const Token *Toks,
+ unsigned NumToks) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R,
+ ExprArg Val) {
+ Out << __FUNCTION__ << "\n";
+ return move(Val); // Default impl returns operand.
+ }
+
+ // Postfix Expressions.
+ virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
+ tok::TokenKind Kind,
+ ExprArg Input) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnArraySubscriptExpr(Scope *S, ExprArg Base,
+ SourceLocation LLoc,
+ ExprArg Idx,
+ SourceLocation RLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation MemberLoc,
+ IdentifierInfo &Member,
+ DeclPtrTy ImplDecl) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCallExpr(Scope *S, ExprArg Fn,
+ SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ // Unary Operators. 'Tok' is the token for the operator.
+ virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
+ tok::TokenKind Op, ExprArg Input) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult
+ ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
+ void *TyOrEx, const SourceRange &ArgRange) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParen,
+ TypeTy *Ty,
+ SourceLocation RParen,
+ ExprArg Op) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc,
+ MultiExprArg InitList,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
+ SourceLocation RParenLoc,ExprArg Op){
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc,
+ tok::TokenKind Kind,
+ ExprArg LHS, ExprArg RHS) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
+ /// in the case of a the GNU conditional expr extension.
+ virtual OwningExprResult ActOnConditionalOp(SourceLocation QuestionLoc,
+ SourceLocation ColonLoc,
+ ExprArg Cond, ExprArg LHS,
+ ExprArg RHS) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ //===--------------------- GNU Extension Expressions ------------------===//
+
+ virtual OwningExprResult ActOnAddrLabel(SourceLocation OpLoc,
+ SourceLocation LabLoc,
+ IdentifierInfo *LabelII) {// "&&foo"
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnStmtExpr(SourceLocation LPLoc,
+ StmtArg SubStmt,
+ SourceLocation RPLoc) { // "({..})"
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S,
+ SourceLocation BuiltinLoc,
+ SourceLocation TypeLoc,
+ TypeTy *Arg1,
+ OffsetOfComponent *CompPtr,
+ unsigned NumComponents,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ // __builtin_types_compatible_p(type1, type2)
+ virtual OwningExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
+ TypeTy *arg1,TypeTy *arg2,
+ SourceLocation RPLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ // __builtin_choose_expr(constExpr, expr1, expr2)
+ virtual OwningExprResult ActOnChooseExpr(SourceLocation BuiltinLoc,
+ ExprArg cond, ExprArg expr1,
+ ExprArg expr2,
+ SourceLocation RPLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ // __builtin_va_arg(expr, type)
+ virtual OwningExprResult ActOnVAArg(SourceLocation BuiltinLoc,
+ ExprArg expr, TypeTy *type,
+ SourceLocation RPLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnGNUNullExpr(SourceLocation TokenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual OwningExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc,
+ StmtArg Body,
+ Scope *CurScope) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc,
+ IdentifierInfo *Ident,
+ SourceLocation LBrace) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual void ActOnFinishNamespaceDef(DeclPtrTy Dcl, SourceLocation RBrace) {
+ Out << __FUNCTION__ << "\n";
+ return;
+ }
+
+#if 0
+ // FIXME: AttrList should be deleted by this function, but the definition
+ // would have to be available.
+ virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope,
+ SourceLocation UsingLoc,
+ SourceLocation NamespcLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *NamespcName,
+ AttributeList *AttrList) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+#endif
+
+ virtual void ActOnParamDefaultArgument(DeclPtrTy param,
+ SourceLocation EqualLoc,
+ ExprArg defarg) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
+ SourceLocation EqualLoc) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnParamDefaultArgumentError(DeclPtrTy param) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
+ SourceLocation LParenLoc,
+ MultiExprArg Exprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return;
+ }
+
+ virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S,
+ DeclPtrTy Method)
+ {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy Param) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S,
+ DeclPtrTy Method) {
+ Out << __FUNCTION__ << "\n";
+ }
+
+ virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
+ ExprArg AssertExpr,
+ ExprArg AssertMessageExpr) {
+ Out << __FUNCTION__ << "\n";
+ return DeclPtrTy();
+ }
+
+ virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
+ tok::TokenKind Kind,
+ SourceLocation LAngleBracketLoc,
+ TypeTy *Ty,
+ SourceLocation RAngleBracketLoc,
+ SourceLocation LParenLoc,
+ ExprArg Op,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc,
+ SourceLocation LParenLoc,
+ bool isType, void *TyOrExpr,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXThis(SourceLocation ThisLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc,
+ tok::TokenKind Kind) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXThrow(SourceLocation OpLoc, ExprArg Op) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXTypeConstructExpr(SourceRange TypeRange,
+ TypeTy *TypeRep,
+ SourceLocation LParenLoc,
+ MultiExprArg Exprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXConditionDeclarationExpr(Scope *S,
+ SourceLocation StartLoc,
+ Declarator &D,
+ SourceLocation EqualLoc,
+ ExprArg AssignExprVal) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXNew(SourceLocation StartLoc,
+ bool UseGlobal,
+ SourceLocation PlacementLParen,
+ MultiExprArg PlacementArgs,
+ SourceLocation PlacementRParen,
+ bool ParenTypeId, Declarator &D,
+ SourceLocation ConstructorLParen,
+ MultiExprArg ConstructorArgs,
+ SourceLocation ConstructorRParen) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc,
+ bool UseGlobal, bool ArrayForm,
+ ExprArg Operand) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
+ SourceLocation KWLoc,
+ SourceLocation LParen,
+ TypeTy *Ty,
+ SourceLocation RParen) {
+ Out << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ };
+}
+
+MinimalAction *clang::CreatePrintParserActionsAction(Preprocessor &PP,
+ llvm::raw_ostream* OS) {
+ return new ParserPrintActions(PP, *OS);
+}
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
new file mode 100644
index 000000000000..89d099caf8a9
--- /dev/null
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -0,0 +1,470 @@
+//===--- PrintPreprocessedOutput.cpp - Implement the -E mode --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This code simply runs the preprocessor on the input file and prints out the
+// result. This is the traditional behavior of the -E option.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/Pragma.h"
+#include "clang/Lex/TokenConcatenation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdio>
+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) {
+ OS << "#define " << II.getName();
+
+ if (MI.isFunctionLike()) {
+ OS << '(';
+ if (MI.arg_empty())
+ ;
+ else if (MI.getNumArgs() == 1)
+ OS << (*MI.arg_begin())->getName();
+ else {
+ MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end();
+ OS << (*AI++)->getName();
+ while (AI != E)
+ OS << ',' << (*AI++)->getName();
+ }
+
+ if (MI.isVariadic()) {
+ if (!MI.arg_empty())
+ OS << ',';
+ OS << "...";
+ }
+ OS << ')';
+ }
+
+ // GCC always emits a space, even if the macro body is empty. However, do not
+ // want to emit two spaces if the first token has a leading space.
+ if (MI.tokens_empty() || !MI.tokens_begin()->hasLeadingSpace())
+ OS << ' ';
+
+ llvm::SmallVector<char, 128> SpellingBuffer;
+ for (MacroInfo::tokens_iterator I = MI.tokens_begin(), E = MI.tokens_end();
+ I != E; ++I) {
+ if (I->hasLeadingSpace())
+ OS << ' ';
+
+ // Make sure we have enough space in the spelling buffer.
+ if (I->getLength() < SpellingBuffer.size())
+ SpellingBuffer.resize(I->getLength());
+ const char *Buffer = SpellingBuffer.data();
+ unsigned SpellingLen = PP.getSpelling(*I, Buffer);
+ OS.write(Buffer, SpellingLen);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Preprocessed token printer
+//===----------------------------------------------------------------------===//
+
+namespace {
+class PrintPPOutputPPCallbacks : public PPCallbacks {
+ Preprocessor &PP;
+ TokenConcatenation ConcatInfo;
+public:
+ llvm::raw_ostream &OS;
+private:
+ unsigned CurLine;
+ bool EmittedTokensOnThisLine;
+ bool EmittedMacroOnThisLine;
+ SrcMgr::CharacteristicKind FileType;
+ llvm::SmallString<512> CurFilename;
+ bool Initialized;
+ bool DisableLineMarkers;
+ bool DumpDefines;
+public:
+ PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os,
+ bool lineMarkers, bool defines)
+ : PP(pp), ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers),
+ DumpDefines(defines) {
+ CurLine = 0;
+ CurFilename += "<uninit>";
+ EmittedTokensOnThisLine = false;
+ EmittedMacroOnThisLine = false;
+ FileType = SrcMgr::C_User;
+ Initialized = false;
+ }
+
+ void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
+ bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; }
+
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType);
+ virtual void Ident(SourceLocation Loc, const std::string &str);
+ virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
+ const std::string &Str);
+
+
+ bool HandleFirstTokOnLine(Token &Tok);
+ bool MoveToLine(SourceLocation Loc);
+ bool AvoidConcat(const Token &PrevTok, const Token &Tok) {
+ return ConcatInfo.AvoidConcat(PrevTok, Tok);
+ }
+ void WriteLineInfo(unsigned LineNo, const char *Extra=0, unsigned ExtraLen=0);
+
+ /// MacroDefined - This hook is called whenever a macro definition is seen.
+ void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI);
+
+};
+} // end anonymous namespace
+
+void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
+ const char *Extra,
+ unsigned ExtraLen) {
+ if (EmittedTokensOnThisLine || EmittedMacroOnThisLine) {
+ OS << '\n';
+ EmittedTokensOnThisLine = false;
+ EmittedMacroOnThisLine = false;
+ }
+
+ OS << '#' << ' ' << LineNo << ' ' << '"';
+ OS.write(&CurFilename[0], CurFilename.size());
+ OS << '"';
+
+ if (ExtraLen)
+ OS.write(Extra, ExtraLen);
+
+ if (FileType == SrcMgr::C_System)
+ OS.write(" 3", 2);
+ else if (FileType == SrcMgr::C_ExternCSystem)
+ OS.write(" 3 4", 4);
+ OS << '\n';
+}
+
+/// MoveToLine - Move the output to the source line specified by the location
+/// object. We can do this by emitting some number of \n's, or be emitting a
+/// #line directive. This returns false if already at the specified line, true
+/// if some newlines were emitted.
+bool PrintPPOutputPPCallbacks::MoveToLine(SourceLocation Loc) {
+ unsigned LineNo = PP.getSourceManager().getInstantiationLineNumber(Loc);
+
+ if (DisableLineMarkers) {
+ if (LineNo == CurLine) return false;
+
+ CurLine = LineNo;
+
+ if (!EmittedTokensOnThisLine && !EmittedMacroOnThisLine)
+ return true;
+
+ OS << '\n';
+ EmittedTokensOnThisLine = false;
+ EmittedMacroOnThisLine = false;
+ return true;
+ }
+
+ // If this line is "close enough" to the original line, just print newlines,
+ // otherwise print a #line directive.
+ if (LineNo-CurLine <= 8) {
+ if (LineNo-CurLine == 1)
+ OS << '\n';
+ else if (LineNo == CurLine)
+ return false; // Spelling line moved, but instantiation line didn't.
+ else {
+ const char *NewLines = "\n\n\n\n\n\n\n\n";
+ OS.write(NewLines, LineNo-CurLine);
+ }
+ } else {
+ WriteLineInfo(LineNo, 0, 0);
+ }
+
+ CurLine = LineNo;
+ return true;
+}
+
+
+/// FileChanged - Whenever the preprocessor enters or exits a #include file
+/// it invokes this handler. Update our conception of the current source
+/// position.
+void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
+ FileChangeReason Reason,
+ SrcMgr::CharacteristicKind NewFileType) {
+ // Unless we are exiting a #include, make sure to skip ahead to the line the
+ // #include directive was at.
+ SourceManager &SourceMgr = PP.getSourceManager();
+ if (Reason == PPCallbacks::EnterFile) {
+ SourceLocation IncludeLoc = SourceMgr.getPresumedLoc(Loc).getIncludeLoc();
+ if (IncludeLoc.isValid())
+ MoveToLine(IncludeLoc);
+ } else if (Reason == PPCallbacks::SystemHeaderPragma) {
+ MoveToLine(Loc);
+
+ // TODO GCC emits the # directive for this directive on the line AFTER the
+ // directive and emits a bunch of spaces that aren't needed. Emulate this
+ // strange behavior.
+ }
+
+ Loc = SourceMgr.getInstantiationLoc(Loc);
+ // FIXME: Should use presumed line #!
+ CurLine = SourceMgr.getInstantiationLineNumber(Loc);
+
+ if (DisableLineMarkers) return;
+
+ CurFilename.clear();
+ CurFilename += SourceMgr.getPresumedLoc(Loc).getFilename();
+ Lexer::Stringify(CurFilename);
+ FileType = NewFileType;
+
+ if (!Initialized) {
+ WriteLineInfo(CurLine);
+ Initialized = true;
+ }
+
+ switch (Reason) {
+ case PPCallbacks::EnterFile:
+ WriteLineInfo(CurLine, " 1", 2);
+ break;
+ case PPCallbacks::ExitFile:
+ WriteLineInfo(CurLine, " 2", 2);
+ break;
+ case PPCallbacks::SystemHeaderPragma:
+ case PPCallbacks::RenameFile:
+ WriteLineInfo(CurLine);
+ break;
+ }
+}
+
+/// Ident - Handle #ident directives when read by the preprocessor.
+///
+void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) {
+ MoveToLine(Loc);
+
+ OS.write("#ident ", strlen("#ident "));
+ OS.write(&S[0], S.size());
+ EmittedTokensOnThisLine = true;
+}
+
+/// MacroDefined - This hook is called whenever a macro definition is seen.
+void PrintPPOutputPPCallbacks::MacroDefined(const IdentifierInfo *II,
+ const MacroInfo *MI) {
+ // Only print out macro definitions in -dD mode.
+ if (!DumpDefines ||
+ // Ignore __FILE__ etc.
+ MI->isBuiltinMacro()) return;
+
+ MoveToLine(MI->getDefinitionLoc());
+ PrintMacroDefinition(*II, *MI, PP, OS);
+ EmittedMacroOnThisLine = true;
+}
+
+
+void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
+ const IdentifierInfo *Kind,
+ const std::string &Str) {
+ MoveToLine(Loc);
+ OS << "#pragma comment(" << Kind->getName();
+
+ if (!Str.empty()) {
+ OS << ", \"";
+
+ for (unsigned i = 0, e = Str.size(); i != e; ++i) {
+ unsigned char Char = Str[i];
+ if (isprint(Char) && Char != '\\' && Char != '"')
+ OS << (char)Char;
+ else // Output anything hard as an octal escape.
+ OS << '\\'
+ << (char)('0'+ ((Char >> 6) & 7))
+ << (char)('0'+ ((Char >> 3) & 7))
+ << (char)('0'+ ((Char >> 0) & 7));
+ }
+ OS << '"';
+ }
+
+ OS << ')';
+ EmittedTokensOnThisLine = true;
+}
+
+
+/// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this
+/// is called for the first token on each new line. If this really is the start
+/// of a new logical line, handle it and return true, otherwise return false.
+/// This may not be the start of a logical line because the "start of line"
+/// marker is set for spelling lines, not instantiation ones.
+bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) {
+ // Figure out what line we went to and insert the appropriate number of
+ // newline characters.
+ if (!MoveToLine(Tok.getLocation()))
+ return false;
+
+ // Print out space characters so that the first token on a line is
+ // indented for easy reading.
+ const SourceManager &SourceMgr = PP.getSourceManager();
+ unsigned ColNo = SourceMgr.getInstantiationColumnNumber(Tok.getLocation());
+
+ // This hack prevents stuff like:
+ // #define HASH #
+ // HASH define foo bar
+ // From having the # character end up at column 1, which makes it so it
+ // is not handled as a #define next time through the preprocessor if in
+ // -fpreprocessed mode.
+ if (ColNo <= 1 && Tok.is(tok::hash))
+ OS << ' ';
+
+ // Otherwise, indent the appropriate number of spaces.
+ for (; ColNo > 1; --ColNo)
+ OS << ' ';
+
+ return true;
+}
+
+namespace {
+struct UnknownPragmaHandler : public PragmaHandler {
+ const char *Prefix;
+ PrintPPOutputPPCallbacks *Callbacks;
+
+ UnknownPragmaHandler(const char *prefix, PrintPPOutputPPCallbacks *callbacks)
+ : PragmaHandler(0), Prefix(prefix), Callbacks(callbacks) {}
+ virtual void HandlePragma(Preprocessor &PP, Token &PragmaTok) {
+ // Figure out what line we went to and insert the appropriate number of
+ // newline characters.
+ Callbacks->MoveToLine(PragmaTok.getLocation());
+ Callbacks->OS.write(Prefix, strlen(Prefix));
+
+ // Read and print all of the pragma tokens.
+ while (PragmaTok.isNot(tok::eom)) {
+ if (PragmaTok.hasLeadingSpace())
+ Callbacks->OS << ' ';
+ std::string TokSpell = PP.getSpelling(PragmaTok);
+ Callbacks->OS.write(&TokSpell[0], TokSpell.size());
+ PP.LexUnexpandedToken(PragmaTok);
+ }
+ Callbacks->OS << '\n';
+ }
+};
+} // end anonymous namespace
+
+
+static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
+ PrintPPOutputPPCallbacks *Callbacks,
+ llvm::raw_ostream &OS) {
+ char Buffer[256];
+ Token PrevTok;
+ while (1) {
+
+ // If this token is at the start of a line, emit newlines if needed.
+ if (Tok.isAtStartOfLine() && Callbacks->HandleFirstTokOnLine(Tok)) {
+ // done.
+ } else if (Tok.hasLeadingSpace() ||
+ // If we haven't emitted a token on this line yet, PrevTok isn't
+ // useful to look at and no concatenation could happen anyway.
+ (Callbacks->hasEmittedTokensOnThisLine() &&
+ // Don't print "-" next to "-", it would form "--".
+ Callbacks->AvoidConcat(PrevTok, Tok))) {
+ OS << ' ';
+ }
+
+ if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
+ OS.write(II->getName(), II->getLength());
+ } else if (Tok.isLiteral() && !Tok.needsCleaning() &&
+ Tok.getLiteralData()) {
+ OS.write(Tok.getLiteralData(), Tok.getLength());
+ } else if (Tok.getLength() < 256) {
+ const char *TokPtr = Buffer;
+ unsigned Len = PP.getSpelling(Tok, TokPtr);
+ OS.write(TokPtr, Len);
+ } else {
+ std::string S = PP.getSpelling(Tok);
+ OS.write(&S[0], S.size());
+ }
+ Callbacks->SetEmittedTokensOnThisLine();
+
+ if (Tok.is(tok::eof)) break;
+
+ PrevTok = Tok;
+ PP.Lex(Tok);
+ }
+}
+
+namespace {
+ struct SortMacrosByID {
+ typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair;
+ bool operator()(const id_macro_pair &LHS, const id_macro_pair &RHS) const {
+ return strcmp(LHS.first->getName(), RHS.first->getName()) < 0;
+ }
+ };
+}
+
+void clang::DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
+ // -dM mode just scans and ignores all tokens in the files, then dumps out
+ // the macro table at the end.
+ PP.EnterMainSourceFile();
+
+ Token Tok;
+ do PP.Lex(Tok);
+ while (Tok.isNot(tok::eof));
+
+ std::vector<std::pair<IdentifierInfo*, MacroInfo*> > MacrosByID;
+ for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
+ I != E; ++I)
+ MacrosByID.push_back(*I);
+ std::sort(MacrosByID.begin(), MacrosByID.end(), SortMacrosByID());
+
+ for (unsigned i = 0, e = MacrosByID.size(); i != e; ++i) {
+ MacroInfo &MI = *MacrosByID[i].second;
+ // Ignore computed macros like __LINE__ and friends.
+ if (MI.isBuiltinMacro()) continue;
+
+ PrintMacroDefinition(*MacrosByID[i].first, MI, PP, *OS);
+ *OS << "\n";
+ }
+}
+
+/// DoPrintPreprocessedInput - This implements -E mode.
+///
+void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS,
+ bool EnableCommentOutput,
+ bool EnableMacroCommentOutput,
+ bool DisableLineMarkers,
+ bool DumpDefines) {
+ // Inform the preprocessor whether we want it to retain comments or not, due
+ // to -C or -CC.
+ PP.SetCommentRetentionState(EnableCommentOutput, EnableMacroCommentOutput);
+
+ OS->SetBufferSize(64*1024);
+
+ PrintPPOutputPPCallbacks *Callbacks =
+ new PrintPPOutputPPCallbacks(PP, *OS, DisableLineMarkers, DumpDefines);
+ PP.AddPragmaHandler(0, new UnknownPragmaHandler("#pragma", Callbacks));
+ PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",
+ Callbacks));
+
+ PP.setPPCallbacks(Callbacks);
+
+ // After we have configured the preprocessor, enter the main file.
+ PP.EnterMainSourceFile();
+
+ // Consume all of the tokens that come from the predefines buffer. Those
+ // should not be emitted into the output and are guaranteed to be at the
+ // start.
+ const SourceManager &SourceMgr = PP.getSourceManager();
+ Token Tok;
+ do PP.Lex(Tok);
+ while (Tok.isNot(tok::eof) && Tok.getLocation().isFileID() &&
+ !strcmp(SourceMgr.getPresumedLoc(Tok.getLocation()).getFilename(),
+ "<built-in>"));
+
+ // Read all the preprocessed tokens, printing them out to the stream.
+ PrintPreprocessedTokens(PP, Tok, Callbacks, *OS);
+ *OS << '\n';
+}
+
diff --git a/lib/Frontend/RewriteBlocks.cpp b/lib/Frontend/RewriteBlocks.cpp
new file mode 100644
index 000000000000..9d73d90554ce
--- /dev/null
+++ b/lib/Frontend/RewriteBlocks.cpp
@@ -0,0 +1,1162 @@
+//===--- RewriteBlocks.cpp ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Hacks and fun related to the closure rewriter.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include <sstream>
+
+using namespace clang;
+using llvm::utostr;
+
+namespace {
+
+class RewriteBlocks : public ASTConsumer {
+ Rewriter Rewrite;
+ Diagnostic &Diags;
+ const LangOptions &LangOpts;
+ unsigned RewriteFailedDiag;
+
+ ASTContext *Context;
+ SourceManager *SM;
+ FileID MainFileID;
+ const char *MainFileStart, *MainFileEnd;
+
+ // Block expressions.
+ llvm::SmallVector<BlockExpr *, 32> Blocks;
+ llvm::SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs;
+ llvm::DenseMap<BlockDeclRefExpr *, CallExpr *> BlockCallExprs;
+
+ // Block related declarations.
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
+
+ llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
+
+ // The function/method we are rewriting.
+ FunctionDecl *CurFunctionDef;
+ ObjCMethodDecl *CurMethodDef;
+
+ bool IsHeader;
+
+ std::string Preamble;
+public:
+ RewriteBlocks(std::string inFile, Diagnostic &D,
+ const LangOptions &LOpts);
+ ~RewriteBlocks() {
+ // Get the buffer corresponding to MainFileID.
+ // If we haven't changed it, then we are done.
+ if (const RewriteBuffer *RewriteBuf =
+ Rewrite.getRewriteBufferFor(MainFileID)) {
+ std::string S(RewriteBuf->begin(), RewriteBuf->end());
+ printf("%s\n", S.c_str());
+ } else {
+ printf("No changes\n");
+ }
+ }
+
+ void Initialize(ASTContext &context);
+
+ void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen);
+ void ReplaceText(SourceLocation Start, unsigned OrigLength,
+ const char *NewStr, unsigned NewLength);
+
+ // Top Level Driver code.
+ virtual void HandleTopLevelDecl(DeclGroupRef D) {
+ for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
+ HandleTopLevelSingleDecl(*I);
+ }
+ void HandleTopLevelSingleDecl(Decl *D);
+ void HandleDeclInMainFile(Decl *D);
+
+ // Top level
+ Stmt *RewriteFunctionBody(Stmt *S);
+ void InsertBlockLiteralsWithinFunction(FunctionDecl *FD);
+ void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD);
+
+ // Block specific rewrite rules.
+ std::string SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD=0);
+
+ void RewriteBlockCall(CallExpr *Exp);
+ void RewriteBlockPointerDecl(NamedDecl *VD);
+ void RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD);
+ void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
+
+ std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
+ const char *funcName, std::string Tag);
+ std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
+ const char *funcName, std::string Tag);
+ std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
+ bool hasCopyDisposeHelpers);
+ std::string SynthesizeBlockCall(CallExpr *Exp);
+ void SynthesizeBlockLiterals(SourceLocation FunLocStart,
+ const char *FunName);
+
+ void CollectBlockDeclRefInfo(BlockExpr *Exp);
+ void GetBlockCallExprs(Stmt *S);
+ void GetBlockDeclRefExprs(Stmt *S);
+
+ // We avoid calling Type::isBlockPointerType(), since it operates on the
+ // canonical type. We only care if the top-level type is a closure pointer.
+ bool isBlockPointerType(QualType T) { return isa<BlockPointerType>(T); }
+
+ // FIXME: This predicate seems like it would be useful to add to ASTContext.
+ bool isObjCType(QualType T) {
+ if (!LangOpts.ObjC1 && !LangOpts.ObjC2)
+ return false;
+
+ QualType OCT = Context->getCanonicalType(T).getUnqualifiedType();
+
+ if (OCT == Context->getCanonicalType(Context->getObjCIdType()) ||
+ OCT == Context->getCanonicalType(Context->getObjCClassType()))
+ return true;
+
+ if (const PointerType *PT = OCT->getAsPointerType()) {
+ if (isa<ObjCInterfaceType>(PT->getPointeeType()) ||
+ isa<ObjCQualifiedIdType>(PT->getPointeeType()))
+ return true;
+ }
+ return false;
+ }
+ // ObjC rewrite methods.
+ void RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl);
+ void RewriteCategoryDecl(ObjCCategoryDecl *CatDecl);
+ void RewriteProtocolDecl(ObjCProtocolDecl *PDecl);
+ void RewriteMethodDecl(ObjCMethodDecl *MDecl);
+
+ void RewriteFunctionProtoType(QualType funcType, NamedDecl *D);
+ void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND);
+ void RewriteCastExpr(CastExpr *CE);
+
+ bool PointerTypeTakesAnyBlockArguments(QualType QT);
+ void GetExtentOfArgList(const char *Name, const char *&LParen, const char *&RParen);
+};
+
+}
+
+static bool IsHeaderFile(const std::string &Filename) {
+ std::string::size_type DotPos = Filename.rfind('.');
+
+ if (DotPos == std::string::npos) {
+ // no file extension
+ return false;
+ }
+
+ std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end());
+ // C header: .h
+ // C++ header: .hh or .H;
+ return Ext == "h" || Ext == "hh" || Ext == "H";
+}
+
+RewriteBlocks::RewriteBlocks(std::string inFile,
+ Diagnostic &D, const LangOptions &LOpts) :
+ Diags(D), LangOpts(LOpts) {
+ IsHeader = IsHeaderFile(inFile);
+ CurFunctionDef = 0;
+ CurMethodDef = 0;
+ RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
+ "rewriting failed");
+}
+
+ASTConsumer *clang::CreateBlockRewriter(const std::string& InFile,
+ Diagnostic &Diags,
+ const LangOptions &LangOpts) {
+ return new RewriteBlocks(InFile, Diags, LangOpts);
+}
+
+void RewriteBlocks::Initialize(ASTContext &context) {
+ Context = &context;
+ SM = &Context->getSourceManager();
+
+ // Get the ID and start/end of the main file.
+ MainFileID = SM->getMainFileID();
+ const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID);
+ MainFileStart = MainBuf->getBufferStart();
+ MainFileEnd = MainBuf->getBufferEnd();
+
+ Rewrite.setSourceMgr(Context->getSourceManager(), LangOpts);
+
+ if (IsHeader)
+ Preamble = "#pragma once\n";
+ Preamble += "#ifndef BLOCK_IMPL\n";
+ Preamble += "#define BLOCK_IMPL\n";
+ Preamble += "struct __block_impl {\n";
+ Preamble += " void *isa;\n";
+ Preamble += " int Flags;\n";
+ Preamble += " int Size;\n";
+ Preamble += " void *FuncPtr;\n";
+ Preamble += "};\n";
+ Preamble += "enum {\n";
+ Preamble += " BLOCK_HAS_COPY_DISPOSE = (1<<25),\n";
+ Preamble += " BLOCK_IS_GLOBAL = (1<<28)\n";
+ Preamble += "};\n";
+ if (LangOpts.Microsoft)
+ Preamble += "#define __OBJC_RW_EXTERN extern \"C\" __declspec(dllimport)\n";
+ else
+ Preamble += "#define __OBJC_RW_EXTERN extern\n";
+ Preamble += "// Runtime copy/destroy helper functions\n";
+ Preamble += "__OBJC_RW_EXTERN void _Block_copy_assign(void *, void *);\n";
+ Preamble += "__OBJC_RW_EXTERN void _Block_byref_assign_copy(void *, void *);\n";
+ Preamble += "__OBJC_RW_EXTERN void _Block_destroy(void *);\n";
+ Preamble += "__OBJC_RW_EXTERN void _Block_byref_release(void *);\n";
+ Preamble += "__OBJC_RW_EXTERN void *_NSConcreteGlobalBlock;\n";
+ Preamble += "__OBJC_RW_EXTERN void *_NSConcreteStackBlock;\n";
+ Preamble += "#endif\n";
+
+ InsertText(SM->getLocForStartOfFile(MainFileID),
+ Preamble.c_str(), Preamble.size());
+}
+
+void RewriteBlocks::InsertText(SourceLocation Loc, const char *StrData,
+ unsigned StrLen)
+{
+ if (!Rewrite.InsertText(Loc, StrData, StrLen))
+ return;
+ Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);
+}
+
+void RewriteBlocks::ReplaceText(SourceLocation Start, unsigned OrigLength,
+ const char *NewStr, unsigned NewLength) {
+ if (!Rewrite.ReplaceText(Start, OrigLength, NewStr, NewLength))
+ return;
+ Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag);
+}
+
+void RewriteBlocks::RewriteMethodDecl(ObjCMethodDecl *Method) {
+ bool haveBlockPtrs = false;
+ for (ObjCMethodDecl::param_iterator I = Method->param_begin(),
+ E = Method->param_end(); I != E; ++I)
+ if (isBlockPointerType((*I)->getType()))
+ haveBlockPtrs = true;
+
+ if (!haveBlockPtrs)
+ return;
+
+ // Do a fuzzy rewrite.
+ // We have 1 or more arguments that have closure pointers.
+ SourceLocation Loc = Method->getLocStart();
+ SourceLocation LocEnd = Method->getLocEnd();
+ const char *startBuf = SM->getCharacterData(Loc);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+
+ const char *methodPtr = startBuf;
+ std::string Tag = "struct __block_impl *";
+
+ while (*methodPtr++ && (methodPtr != endBuf)) {
+ switch (*methodPtr) {
+ case ':':
+ methodPtr++;
+ if (*methodPtr == '(') {
+ const char *scanType = ++methodPtr;
+ bool foundBlockPointer = false;
+ unsigned parenCount = 1;
+
+ while (parenCount) {
+ switch (*scanType) {
+ case '(':
+ parenCount++;
+ break;
+ case ')':
+ parenCount--;
+ break;
+ case '^':
+ foundBlockPointer = true;
+ break;
+ }
+ scanType++;
+ }
+ if (foundBlockPointer) {
+ // advance the location to startArgList.
+ Loc = Loc.getFileLocWithOffset(methodPtr-startBuf);
+ assert((Loc.isValid()) && "Invalid Loc");
+ ReplaceText(Loc, scanType-methodPtr-1, Tag.c_str(), Tag.size());
+
+ // Advance startBuf. Since the underlying buffer has changed,
+ // it's very important to advance startBuf (so we can correctly
+ // compute a relative Loc the next time around).
+ startBuf = methodPtr;
+ }
+ // Advance the method ptr to the end of the type.
+ methodPtr = scanType;
+ }
+ break;
+ }
+ }
+ return;
+}
+
+void RewriteBlocks::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
+ for (ObjCInterfaceDecl::instmeth_iterator
+ I = ClassDecl->instmeth_begin(*Context),
+ E = ClassDecl->instmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDecl(*I);
+ for (ObjCInterfaceDecl::classmeth_iterator
+ I = ClassDecl->classmeth_begin(*Context),
+ E = ClassDecl->classmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDecl(*I);
+}
+
+void RewriteBlocks::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
+ for (ObjCCategoryDecl::instmeth_iterator
+ I = CatDecl->instmeth_begin(*Context),
+ E = CatDecl->instmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDecl(*I);
+ for (ObjCCategoryDecl::classmeth_iterator
+ I = CatDecl->classmeth_begin(*Context),
+ E = CatDecl->classmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDecl(*I);
+}
+
+void RewriteBlocks::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
+ for (ObjCProtocolDecl::instmeth_iterator
+ I = PDecl->instmeth_begin(*Context),
+ E = PDecl->instmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDecl(*I);
+ for (ObjCProtocolDecl::classmeth_iterator
+ I = PDecl->classmeth_begin(*Context),
+ E = PDecl->classmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDecl(*I);
+}
+
+//===----------------------------------------------------------------------===//
+// Top Level Driver Code
+//===----------------------------------------------------------------------===//
+
+void RewriteBlocks::HandleTopLevelSingleDecl(Decl *D) {
+ // Two cases: either the decl could be in the main file, or it could be in a
+ // #included file. If the former, rewrite it now. If the later, check to see
+ // if we rewrote the #include/#import.
+ SourceLocation Loc = D->getLocation();
+ Loc = SM->getInstantiationLoc(Loc);
+
+ // If this is for a builtin, ignore it.
+ if (Loc.isInvalid()) return;
+
+ if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D))
+ RewriteInterfaceDecl(MD);
+ else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D))
+ RewriteCategoryDecl(CD);
+ else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
+ RewriteProtocolDecl(PD);
+
+ // If we have a decl in the main file, see if we should rewrite it.
+ if (SM->isFromMainFile(Loc))
+ HandleDeclInMainFile(D);
+ return;
+}
+
+std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i,
+ const char *funcName,
+ std::string Tag) {
+ const FunctionType *AFT = CE->getFunctionType();
+ QualType RT = AFT->getResultType();
+ std::string StructRef = "struct " + Tag;
+ std::string S = "static " + RT.getAsString() + " __" +
+ funcName + "_" + "block_func_" + utostr(i);
+
+ BlockDecl *BD = CE->getBlockDecl();
+
+ if (isa<FunctionNoProtoType>(AFT)) {
+ S += "()";
+ } else if (BD->param_empty()) {
+ S += "(" + StructRef + " *__cself)";
+ } else {
+ const FunctionProtoType *FT = cast<FunctionProtoType>(AFT);
+ assert(FT && "SynthesizeBlockFunc: No function proto");
+ S += '(';
+ // first add the implicit argument.
+ S += StructRef + " *__cself, ";
+ std::string ParamStr;
+ for (BlockDecl::param_iterator AI = BD->param_begin(),
+ E = BD->param_end(); AI != E; ++AI) {
+ if (AI != BD->param_begin()) S += ", ";
+ ParamStr = (*AI)->getNameAsString();
+ (*AI)->getType().getAsStringInternal(ParamStr, Context->PrintingPolicy);
+ S += ParamStr;
+ }
+ if (FT->isVariadic()) {
+ if (!BD->param_empty()) S += ", ";
+ S += "...";
+ }
+ S += ')';
+ }
+ S += " {\n";
+
+ // Create local declarations to avoid rewriting all closure decl ref exprs.
+ // First, emit a declaration for all "by ref" decls.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string Name = (*I)->getNameAsString();
+ Context->getPointerType((*I)->getType()).getAsStringInternal(Name,
+ Context->PrintingPolicy);
+ S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
+ }
+ // Next, emit a declaration for all "by copy" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string Name = (*I)->getNameAsString();
+ // Handle nested closure invocation. For example:
+ //
+ // void (^myImportedClosure)(void);
+ // myImportedClosure = ^(void) { setGlobalInt(x + y); };
+ //
+ // void (^anotherClosure)(void);
+ // anotherClosure = ^(void) {
+ // myImportedClosure(); // import and invoke the closure
+ // };
+ //
+ if (isBlockPointerType((*I)->getType()))
+ S += "struct __block_impl *";
+ else
+ (*I)->getType().getAsStringInternal(Name, Context->PrintingPolicy);
+ S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by copy\n";
+ }
+ std::string RewrittenStr = RewrittenBlockExprs[CE];
+ const char *cstr = RewrittenStr.c_str();
+ while (*cstr++ != '{') ;
+ S += cstr;
+ S += "\n";
+ return S;
+}
+
+std::string RewriteBlocks::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
+ const char *funcName,
+ std::string Tag) {
+ std::string StructRef = "struct " + Tag;
+ std::string S = "static void __";
+
+ S += funcName;
+ S += "_block_copy_" + utostr(i);
+ S += "(" + StructRef;
+ S += "*dst, " + StructRef;
+ S += "*src) {";
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
+ E = ImportedBlockDecls.end(); I != E; ++I) {
+ S += "_Block_copy_assign(&dst->";
+ S += (*I)->getNameAsString();
+ S += ", src->";
+ S += (*I)->getNameAsString();
+ S += ");}";
+ }
+ S += "\nstatic void __";
+ S += funcName;
+ S += "_block_dispose_" + utostr(i);
+ S += "(" + StructRef;
+ S += "*src) {";
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
+ E = ImportedBlockDecls.end(); I != E; ++I) {
+ S += "_Block_destroy(src->";
+ S += (*I)->getNameAsString();
+ S += ");";
+ }
+ S += "}\n";
+ return S;
+}
+
+std::string RewriteBlocks::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
+ bool hasCopyDisposeHelpers) {
+ std::string S = "struct " + Tag;
+ std::string Constructor = " " + Tag;
+
+ S += " {\n struct __block_impl impl;\n";
+
+ if (hasCopyDisposeHelpers)
+ S += " void *copy;\n void *dispose;\n";
+
+ Constructor += "(void *fp";
+
+ if (hasCopyDisposeHelpers)
+ Constructor += ", void *copyHelp, void *disposeHelp";
+
+ if (BlockDeclRefs.size()) {
+ // Output all "by copy" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string FieldName = (*I)->getNameAsString();
+ std::string ArgName = "_" + FieldName;
+ // Handle nested closure invocation. For example:
+ //
+ // void (^myImportedBlock)(void);
+ // myImportedBlock = ^(void) { setGlobalInt(x + y); };
+ //
+ // void (^anotherBlock)(void);
+ // anotherBlock = ^(void) {
+ // myImportedBlock(); // import and invoke the closure
+ // };
+ //
+ if (isBlockPointerType((*I)->getType())) {
+ S += "struct __block_impl *";
+ Constructor += ", void *" + ArgName;
+ } else {
+ (*I)->getType().getAsStringInternal(FieldName, Context->PrintingPolicy);
+ (*I)->getType().getAsStringInternal(ArgName, Context->PrintingPolicy);
+ Constructor += ", " + ArgName;
+ }
+ S += FieldName + ";\n";
+ }
+ // Output all "by ref" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string FieldName = (*I)->getNameAsString();
+ std::string ArgName = "_" + FieldName;
+ // Handle nested closure invocation. For example:
+ //
+ // void (^myImportedBlock)(void);
+ // myImportedBlock = ^(void) { setGlobalInt(x + y); };
+ //
+ // void (^anotherBlock)(void);
+ // anotherBlock = ^(void) {
+ // myImportedBlock(); // import and invoke the closure
+ // };
+ //
+ if (isBlockPointerType((*I)->getType())) {
+ S += "struct __block_impl *";
+ Constructor += ", void *" + ArgName;
+ } else {
+ Context->getPointerType((*I)->getType()).getAsStringInternal(FieldName,
+ Context->PrintingPolicy);
+ Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName,
+ Context->PrintingPolicy);
+ Constructor += ", " + ArgName;
+ }
+ S += FieldName + "; // by ref\n";
+ }
+ // Finish writing the constructor.
+ // FIXME: handle NSConcreteGlobalBlock.
+ Constructor += ", int flags=0) {\n";
+ Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof(";
+ Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
+
+ if (hasCopyDisposeHelpers)
+ Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
+
+ // Initialize all "by copy" arguments.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ std::string Name = (*I)->getNameAsString();
+ Constructor += " ";
+ if (isBlockPointerType((*I)->getType()))
+ Constructor += Name + " = (struct __block_impl *)_";
+ else
+ Constructor += Name + " = _";
+ Constructor += Name + ";\n";
+ }
+ // Initialize all "by ref" arguments.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ std::string Name = (*I)->getNameAsString();
+ Constructor += " ";
+ if (isBlockPointerType((*I)->getType()))
+ Constructor += Name + " = (struct __block_impl *)_";
+ else
+ Constructor += Name + " = _";
+ Constructor += Name + ";\n";
+ }
+ } else {
+ // Finish writing the constructor.
+ // FIXME: handle NSConcreteGlobalBlock.
+ Constructor += ", int flags=0) {\n";
+ Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof(";
+ Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
+ if (hasCopyDisposeHelpers)
+ Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
+ }
+ Constructor += " ";
+ Constructor += "}\n";
+ S += Constructor;
+ S += "};\n";
+ return S;
+}
+
+void RewriteBlocks::SynthesizeBlockLiterals(SourceLocation FunLocStart,
+ const char *FunName) {
+ // Insert closures that were part of the function.
+ for (unsigned i = 0; i < Blocks.size(); i++) {
+
+ CollectBlockDeclRefInfo(Blocks[i]);
+
+ std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i);
+
+ std::string CI = SynthesizeBlockImpl(Blocks[i], Tag,
+ ImportedBlockDecls.size() > 0);
+
+ InsertText(FunLocStart, CI.c_str(), CI.size());
+
+ std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag);
+
+ InsertText(FunLocStart, CF.c_str(), CF.size());
+
+ if (ImportedBlockDecls.size()) {
+ std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, Tag);
+ InsertText(FunLocStart, HF.c_str(), HF.size());
+ }
+
+ BlockDeclRefs.clear();
+ BlockByRefDecls.clear();
+ BlockByCopyDecls.clear();
+ BlockCallExprs.clear();
+ ImportedBlockDecls.clear();
+ }
+ Blocks.clear();
+ RewrittenBlockExprs.clear();
+}
+
+void RewriteBlocks::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
+ SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
+ const char *FuncName = FD->getNameAsCString();
+
+ SynthesizeBlockLiterals(FunLocStart, FuncName);
+}
+
+void RewriteBlocks::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
+ SourceLocation FunLocStart = MD->getLocStart();
+ std::string FuncName = MD->getSelector().getAsString();
+ // Convert colons to underscores.
+ std::string::size_type loc = 0;
+ while ((loc = FuncName.find(":", loc)) != std::string::npos)
+ FuncName.replace(loc, 1, "_");
+
+ SynthesizeBlockLiterals(FunLocStart, FuncName.c_str());
+}
+
+void RewriteBlocks::GetBlockDeclRefExprs(Stmt *S) {
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++CI)
+ if (*CI) {
+ if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI))
+ GetBlockDeclRefExprs(CBE->getBody());
+ else
+ GetBlockDeclRefExprs(*CI);
+ }
+ // Handle specific things.
+ if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S))
+ // FIXME: Handle enums.
+ if (!isa<FunctionDecl>(CDRE->getDecl()))
+ BlockDeclRefs.push_back(CDRE);
+ return;
+}
+
+void RewriteBlocks::GetBlockCallExprs(Stmt *S) {
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++CI)
+ if (*CI) {
+ if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI))
+ GetBlockCallExprs(CBE->getBody());
+ else
+ GetBlockCallExprs(*CI);
+ }
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ if (CE->getCallee()->getType()->isBlockPointerType()) {
+ BlockCallExprs[dyn_cast<BlockDeclRefExpr>(CE->getCallee())] = CE;
+ }
+ }
+ return;
+}
+
+std::string RewriteBlocks::SynthesizeBlockCall(CallExpr *Exp) {
+ // Navigate to relevant type information.
+ const char *closureName = 0;
+ const BlockPointerType *CPT = 0;
+
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp->getCallee())) {
+ closureName = DRE->getDecl()->getNameAsCString();
+ CPT = DRE->getType()->getAsBlockPointerType();
+ } else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) {
+ closureName = CDRE->getDecl()->getNameAsCString();
+ CPT = CDRE->getType()->getAsBlockPointerType();
+ } else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) {
+ closureName = MExpr->getMemberDecl()->getNameAsCString();
+ CPT = MExpr->getType()->getAsBlockPointerType();
+ } else {
+ assert(1 && "RewriteBlockClass: Bad type");
+ }
+ assert(CPT && "RewriteBlockClass: Bad type");
+ const FunctionType *FT = CPT->getPointeeType()->getAsFunctionType();
+ assert(FT && "RewriteBlockClass: Bad type");
+ const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
+ // FTP will be null for closures that don't take arguments.
+
+ // Build a closure call - start with a paren expr to enforce precedence.
+ std::string BlockCall = "(";
+
+ // Synthesize the cast.
+ BlockCall += "(" + Exp->getType().getAsString() + "(*)";
+ BlockCall += "(struct __block_impl *";
+ if (FTP) {
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I && (I != E); ++I)
+ BlockCall += ", " + (*I).getAsString();
+ }
+ BlockCall += "))"; // close the argument list and paren expression.
+
+ // Invoke the closure. We need to cast it since the declaration type is
+ // bogus (it's a function pointer type)
+ BlockCall += "((struct __block_impl *)";
+ std::string closureExprBufStr;
+ llvm::raw_string_ostream closureExprBuf(closureExprBufStr);
+ Exp->getCallee()->printPretty(closureExprBuf, *Context);
+ BlockCall += closureExprBuf.str();
+ BlockCall += ")->FuncPtr)";
+
+ // Add the arguments.
+ BlockCall += "((struct __block_impl *)";
+ BlockCall += closureExprBuf.str();
+ for (CallExpr::arg_iterator I = Exp->arg_begin(),
+ E = Exp->arg_end(); I != E; ++I) {
+ std::string syncExprBufS;
+ llvm::raw_string_ostream Buf(syncExprBufS);
+ (*I)->printPretty(Buf, *Context);
+ BlockCall += ", " + Buf.str();
+ }
+ return BlockCall;
+}
+
+void RewriteBlocks::RewriteBlockCall(CallExpr *Exp) {
+ std::string BlockCall = SynthesizeBlockCall(Exp);
+
+ const char *startBuf = SM->getCharacterData(Exp->getLocStart());
+ const char *endBuf = SM->getCharacterData(Exp->getLocEnd());
+
+ ReplaceText(Exp->getLocStart(), endBuf-startBuf,
+ BlockCall.c_str(), BlockCall.size());
+}
+
+void RewriteBlocks::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) {
+ // FIXME: Add more elaborate code generation required by the ABI.
+ InsertText(BDRE->getLocStart(), "*", 1);
+}
+
+void RewriteBlocks::RewriteCastExpr(CastExpr *CE) {
+ SourceLocation LocStart = CE->getLocStart();
+ SourceLocation LocEnd = CE->getLocEnd();
+
+ if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd))
+ return;
+
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+
+ // advance the location to startArgList.
+ const char *argPtr = startBuf;
+
+ while (*argPtr++ && (argPtr < endBuf)) {
+ switch (*argPtr) {
+ case '^':
+ // Replace the '^' with '*'.
+ LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf);
+ ReplaceText(LocStart, 1, "*", 1);
+ break;
+ }
+ }
+ return;
+}
+
+void RewriteBlocks::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
+ SourceLocation DeclLoc = FD->getLocation();
+ unsigned parenCount = 0;
+
+ // We have 1 or more arguments that have closure pointers.
+ const char *startBuf = SM->getCharacterData(DeclLoc);
+ const char *startArgList = strchr(startBuf, '(');
+
+ assert((*startArgList == '(') && "Rewriter fuzzy parser confused");
+
+ parenCount++;
+ // advance the location to startArgList.
+ DeclLoc = DeclLoc.getFileLocWithOffset(startArgList-startBuf);
+ assert((DeclLoc.isValid()) && "Invalid DeclLoc");
+
+ const char *argPtr = startArgList;
+
+ while (*argPtr++ && parenCount) {
+ switch (*argPtr) {
+ case '^':
+ // Replace the '^' with '*'.
+ DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList);
+ ReplaceText(DeclLoc, 1, "*", 1);
+ break;
+ case '(':
+ parenCount++;
+ break;
+ case ')':
+ parenCount--;
+ break;
+ }
+ }
+ return;
+}
+
+bool RewriteBlocks::PointerTypeTakesAnyBlockArguments(QualType QT) {
+ const FunctionProtoType *FTP;
+ const PointerType *PT = QT->getAsPointerType();
+ if (PT) {
+ FTP = PT->getPointeeType()->getAsFunctionProtoType();
+ } else {
+ const BlockPointerType *BPT = QT->getAsBlockPointerType();
+ assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
+ FTP = BPT->getPointeeType()->getAsFunctionProtoType();
+ }
+ if (FTP) {
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I != E; ++I)
+ if (isBlockPointerType(*I))
+ return true;
+ }
+ return false;
+}
+
+void RewriteBlocks::GetExtentOfArgList(const char *Name,
+ const char *&LParen, const char *&RParen) {
+ const char *argPtr = strchr(Name, '(');
+ assert((*argPtr == '(') && "Rewriter fuzzy parser confused");
+
+ LParen = argPtr; // output the start.
+ argPtr++; // skip past the left paren.
+ unsigned parenCount = 1;
+
+ while (*argPtr && parenCount) {
+ switch (*argPtr) {
+ case '(': parenCount++; break;
+ case ')': parenCount--; break;
+ default: break;
+ }
+ if (parenCount) argPtr++;
+ }
+ assert((*argPtr == ')') && "Rewriter fuzzy parser confused");
+ RParen = argPtr; // output the end
+}
+
+void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
+ RewriteBlockPointerFunctionArgs(FD);
+ return;
+ }
+ // Handle Variables and Typedefs.
+ SourceLocation DeclLoc = ND->getLocation();
+ QualType DeclT;
+ if (VarDecl *VD = dyn_cast<VarDecl>(ND))
+ DeclT = VD->getType();
+ else if (TypedefDecl *TDD = dyn_cast<TypedefDecl>(ND))
+ DeclT = TDD->getUnderlyingType();
+ else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND))
+ DeclT = FD->getType();
+ else
+ assert(0 && "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--;
+
+ // *startBuf != '^' if we are dealing with a pointer to function that
+ // may take block argument types (which will be handled below).
+ if (*startBuf == '^') {
+ // Replace the '^' with '*', computing a negative offset.
+ DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf);
+ ReplaceText(DeclLoc, 1, "*", 1);
+ }
+ if (PointerTypeTakesAnyBlockArguments(DeclT)) {
+ // Replace the '^' with '*' for arguments.
+ DeclLoc = ND->getLocation();
+ startBuf = SM->getCharacterData(DeclLoc);
+ const char *argListBegin, *argListEnd;
+ GetExtentOfArgList(startBuf, argListBegin, argListEnd);
+ while (argListBegin < argListEnd) {
+ if (*argListBegin == '^') {
+ SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf);
+ ReplaceText(CaretLoc, 1, "*", 1);
+ }
+ argListBegin++;
+ }
+ }
+ return;
+}
+
+void RewriteBlocks::CollectBlockDeclRefInfo(BlockExpr *Exp) {
+ // Add initializers for any closure decl refs.
+ GetBlockDeclRefExprs(Exp->getBody());
+ if (BlockDeclRefs.size()) {
+ // Unique all "by copy" declarations.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (!BlockDeclRefs[i]->isByRef())
+ BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl());
+ // Unique all "by ref" declarations.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (BlockDeclRefs[i]->isByRef()) {
+ BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl());
+ }
+ // Find any imported blocks...they will need special attention.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (isBlockPointerType(BlockDeclRefs[i]->getType())) {
+ GetBlockCallExprs(Blocks[i]);
+ ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl());
+ }
+ }
+}
+
+std::string RewriteBlocks::SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD) {
+ Blocks.push_back(Exp);
+
+ CollectBlockDeclRefInfo(Exp);
+ std::string FuncName;
+
+ if (CurFunctionDef)
+ FuncName = std::string(CurFunctionDef->getNameAsString());
+ else if (CurMethodDef) {
+ FuncName = CurMethodDef->getSelector().getAsString();
+ // Convert colons to underscores.
+ std::string::size_type loc = 0;
+ while ((loc = FuncName.find(":", loc)) != std::string::npos)
+ FuncName.replace(loc, 1, "_");
+ } else if (VD)
+ FuncName = std::string(VD->getNameAsString());
+
+ std::string BlockNumber = utostr(Blocks.size()-1);
+
+ std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber;
+ std::string Func = "__" + FuncName + "_block_func_" + BlockNumber;
+
+ std::string FunkTypeStr;
+
+ // Get a pointer to the function type so we can cast appropriately.
+ Context->getPointerType(QualType(Exp->getFunctionType(),0))
+ .getAsStringInternal(FunkTypeStr, Context->PrintingPolicy);
+
+ // Rewrite the closure block with a compound literal. The first cast is
+ // to prevent warnings from the C compiler.
+ std::string Init = "(" + FunkTypeStr;
+
+ Init += ")&" + Tag;
+
+ // Initialize the block function.
+ Init += "((void*)" + Func;
+
+ if (ImportedBlockDecls.size()) {
+ std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber;
+ Init += ",(void*)" + Buf;
+ Buf = "__" + FuncName + "_block_dispose_" + BlockNumber;
+ Init += ",(void*)" + Buf;
+ }
+ // Add initializers for any closure decl refs.
+ if (BlockDeclRefs.size()) {
+ // Output all "by copy" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ Init += ",";
+ if (isObjCType((*I)->getType())) {
+ Init += "[[";
+ Init += (*I)->getNameAsString();
+ Init += " retain] autorelease]";
+ } else if (isBlockPointerType((*I)->getType())) {
+ Init += "(void *)";
+ Init += (*I)->getNameAsString();
+ } else {
+ Init += (*I)->getNameAsString();
+ }
+ }
+ // Output all "by ref" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ Init += ",&";
+ Init += (*I)->getNameAsString();
+ }
+ }
+ Init += ")";
+ BlockDeclRefs.clear();
+ BlockByRefDecls.clear();
+ BlockByCopyDecls.clear();
+ ImportedBlockDecls.clear();
+
+ return Init;
+}
+
+//===----------------------------------------------------------------------===//
+// Function Body / Expression rewriting
+//===----------------------------------------------------------------------===//
+
+Stmt *RewriteBlocks::RewriteFunctionBody(Stmt *S) {
+ // Start by rewriting all children.
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++CI)
+ if (*CI) {
+ if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) {
+ Stmt *newStmt = RewriteFunctionBody(CBE->getBody());
+ if (newStmt)
+ *CI = newStmt;
+
+ // We've just rewritten the block body in place.
+ // Now we snarf the rewritten text and stash it away for later use.
+ std::string S = Rewrite.getRewritenText(CBE->getSourceRange());
+ RewrittenBlockExprs[CBE] = S;
+ std::string Init = SynthesizeBlockInitExpr(CBE);
+ // Do the rewrite, using S.size() which contains the rewritten size.
+ ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size());
+ } else {
+ Stmt *newStmt = RewriteFunctionBody(*CI);
+ if (newStmt)
+ *CI = newStmt;
+ }
+ }
+ // Handle specific things.
+ if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ if (CE->getCallee()->getType()->isBlockPointerType())
+ RewriteBlockCall(CE);
+ }
+ if (CastExpr *CE = dyn_cast<CastExpr>(S)) {
+ RewriteCastExpr(CE);
+ }
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+ for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
+ DI != DE; ++DI) {
+
+ Decl *SD = *DI;
+ if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {
+ if (isBlockPointerType(ND->getType()))
+ RewriteBlockPointerDecl(ND);
+ else if (ND->getType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(ND->getType(), ND);
+ }
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+ if (isBlockPointerType(TD->getUnderlyingType()))
+ RewriteBlockPointerDecl(TD);
+ else if (TD->getUnderlyingType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ }
+ }
+ }
+ // Handle specific things.
+ if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
+ if (BDRE->isByRef())
+ RewriteBlockDeclRefExpr(BDRE);
+ }
+ // Return this stmt unmodified.
+ return S;
+}
+
+void RewriteBlocks::RewriteFunctionProtoType(QualType funcType, NamedDecl *D) {
+ if (FunctionProtoType *fproto = dyn_cast<FunctionProtoType>(funcType)) {
+ for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(),
+ E = fproto->arg_type_end(); I && (I != E); ++I)
+ if (isBlockPointerType(*I)) {
+ // All the args are checked/rewritten. Don't call twice!
+ RewriteBlockPointerDecl(D);
+ break;
+ }
+ }
+}
+
+void RewriteBlocks::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) {
+ const PointerType *PT = funcType->getAsPointerType();
+ if (PT && PointerTypeTakesAnyBlockArguments(funcType))
+ RewriteFunctionProtoType(PT->getPointeeType(), ND);
+}
+
+/// HandleDeclInMainFile - This is called for each top-level decl defined in the
+/// main file of the input.
+void RewriteBlocks::HandleDeclInMainFile(Decl *D) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // Since function prototypes don't have ParmDecl's, we check the function
+ // prototype. This enables us to rewrite function declarations and
+ // definitions using the same code.
+ RewriteFunctionProtoType(FD->getType(), FD);
+
+ // FIXME: Handle CXXTryStmt
+ if (CompoundStmt *Body = FD->getCompoundBody(*Context)) {
+ CurFunctionDef = FD;
+ FD->setBody(cast_or_null<CompoundStmt>(RewriteFunctionBody(Body)));
+ // This synthesizes and inserts the block "impl" struct, invoke function,
+ // and any copy/dispose helper functions.
+ InsertBlockLiteralsWithinFunction(FD);
+ CurFunctionDef = 0;
+ }
+ return;
+ }
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ RewriteMethodDecl(MD);
+ if (Stmt *Body = MD->getBody(*Context)) {
+ CurMethodDef = MD;
+ RewriteFunctionBody(Body);
+ InsertBlockLiteralsWithinMethod(MD);
+ CurMethodDef = 0;
+ }
+ }
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (isBlockPointerType(VD->getType())) {
+ RewriteBlockPointerDecl(VD);
+ if (VD->getInit()) {
+ if (BlockExpr *CBE = dyn_cast<BlockExpr>(VD->getInit())) {
+ RewriteFunctionBody(CBE->getBody(*Context));
+
+ // We've just rewritten the block body in place.
+ // Now we snarf the rewritten text and stash it away for later use.
+ std::string S = Rewrite.getRewritenText(CBE->getSourceRange());
+ RewrittenBlockExprs[CBE] = S;
+ std::string Init = SynthesizeBlockInitExpr(CBE, VD);
+ // Do the rewrite, using S.size() which contains the rewritten size.
+ ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size());
+ SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(),
+ VD->getNameAsCString());
+ } else if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
+ RewriteCastExpr(CE);
+ }
+ }
+ } else if (VD->getType()->isFunctionPointerType()) {
+ CheckFunctionPointerDecl(VD->getType(), VD);
+ if (VD->getInit()) {
+ if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
+ RewriteCastExpr(CE);
+ }
+ }
+ }
+ return;
+ }
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ if (isBlockPointerType(TD->getUnderlyingType()))
+ RewriteBlockPointerDecl(TD);
+ else if (TD->getUnderlyingType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ return;
+ }
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
+ if (RD->isDefinition()) {
+ for (RecordDecl::field_iterator i = RD->field_begin(*Context),
+ e = RD->field_end(*Context); i != e; ++i) {
+ FieldDecl *FD = *i;
+ if (isBlockPointerType(FD->getType()))
+ RewriteBlockPointerDecl(FD);
+ }
+ }
+ return;
+ }
+}
diff --git a/lib/Frontend/RewriteMacros.cpp b/lib/Frontend/RewriteMacros.cpp
new file mode 100644
index 000000000000..5ef4892e5bc1
--- /dev/null
+++ b/lib/Frontend/RewriteMacros.cpp
@@ -0,0 +1,215 @@
+//===--- RewriteMacros.cpp - Rewrite macros into their expansions ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This code rewrites macro invocations into their expansions. This gives you
+// a macro expanded file that retains comments and #includes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+#include "llvm/ADT/OwningPtr.h"
+using namespace clang;
+
+/// isSameToken - Return true if the two specified tokens start have the same
+/// content.
+static bool isSameToken(Token &RawTok, Token &PPTok) {
+ // If two tokens have the same kind and the same identifier info, they are
+ // obviously the same.
+ if (PPTok.getKind() == RawTok.getKind() &&
+ PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo())
+ return true;
+
+ // Otherwise, if they are different but have the same identifier info, they
+ // are also considered to be the same. This allows keywords and raw lexed
+ // identifiers with the same name to be treated the same.
+ if (PPTok.getIdentifierInfo() &&
+ PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo())
+ return true;
+
+ return false;
+}
+
+
+/// GetNextRawTok - Return the next raw token in the stream, skipping over
+/// comments if ReturnComment is false.
+static const Token &GetNextRawTok(const std::vector<Token> &RawTokens,
+ unsigned &CurTok, bool ReturnComment) {
+ assert(CurTok < RawTokens.size() && "Overran eof!");
+
+ // If the client doesn't want comments and we have one, skip it.
+ if (!ReturnComment && RawTokens[CurTok].is(tok::comment))
+ ++CurTok;
+
+ return RawTokens[CurTok++];
+}
+
+
+/// LexRawTokensFromMainFile - Lets all the raw tokens from the main file into
+/// the specified vector.
+static void LexRawTokensFromMainFile(Preprocessor &PP,
+ std::vector<Token> &RawTokens) {
+ SourceManager &SM = PP.getSourceManager();
+
+ // Create a lexer to lex all the tokens of the main file in raw mode. Even
+ // though it is in raw mode, it will not return comments.
+ Lexer RawLex(SM.getMainFileID(), SM, PP.getLangOptions());
+
+ // Switch on comment lexing because we really do want them.
+ RawLex.SetCommentRetentionState(true);
+
+ Token RawTok;
+ do {
+ RawLex.LexFromRawLexer(RawTok);
+
+ // If we have an identifier with no identifier info for our raw token, look
+ // up the indentifier info. This is important for equality comparison of
+ // identifier tokens.
+ if (RawTok.is(tok::identifier) && !RawTok.getIdentifierInfo())
+ RawTok.setIdentifierInfo(PP.LookUpIdentifierInfo(RawTok));
+
+ RawTokens.push_back(RawTok);
+ } while (RawTok.isNot(tok::eof));
+}
+
+
+/// RewriteMacrosInInput - Implement -rewrite-macros mode.
+void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
+ SourceManager &SM = PP.getSourceManager();
+
+ Rewriter Rewrite;
+ Rewrite.setSourceMgr(SM, PP.getLangOptions());
+ RewriteBuffer &RB = Rewrite.getEditBuffer(SM.getMainFileID());
+
+ std::vector<Token> RawTokens;
+ LexRawTokensFromMainFile(PP, RawTokens);
+ unsigned CurRawTok = 0;
+ Token RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
+
+
+ // Get the first preprocessing token.
+ PP.EnterMainSourceFile();
+ Token PPTok;
+ PP.Lex(PPTok);
+
+ // Preprocess the input file in parallel with raw lexing the main file. Ignore
+ // all tokens that are preprocessed from a file other than the main file (e.g.
+ // a header). If we see tokens that are in the preprocessed file but not the
+ // lexed file, we have a macro expansion. If we see tokens in the lexed file
+ // that aren't in the preprocessed view, we have macros that expand to no
+ // tokens, or macro arguments etc.
+ while (RawTok.isNot(tok::eof) || PPTok.isNot(tok::eof)) {
+ SourceLocation PPLoc = SM.getInstantiationLoc(PPTok.getLocation());
+
+ // If PPTok is from a different source file, ignore it.
+ if (!SM.isFromMainFile(PPLoc)) {
+ PP.Lex(PPTok);
+ continue;
+ }
+
+ // If the raw file hits a preprocessor directive, they will be extra tokens
+ // in the raw file that don't exist in the preprocsesed file. However, we
+ // choose to preserve them in the output file and otherwise handle them
+ // specially.
+ if (RawTok.is(tok::hash) && RawTok.isAtStartOfLine()) {
+ // If this is a #warning directive or #pragma mark (GNU extensions),
+ // comment the line out.
+ if (RawTokens[CurRawTok].is(tok::identifier)) {
+ const IdentifierInfo *II = RawTokens[CurRawTok].getIdentifierInfo();
+ if (!strcmp(II->getName(), "warning")) {
+ // Comment out #warning.
+ RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//", 2);
+ } else if (!strcmp(II->getName(), "pragma") &&
+ RawTokens[CurRawTok+1].is(tok::identifier) &&
+ !strcmp(RawTokens[CurRawTok+1].getIdentifierInfo()->getName(),
+ "mark")){
+ // Comment out #pragma mark.
+ RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//", 2);
+ }
+ }
+
+ // Otherwise, if this is a #include or some other directive, just leave it
+ // in the file by skipping over the line.
+ RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
+ while (!RawTok.isAtStartOfLine() && RawTok.isNot(tok::eof))
+ RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
+ continue;
+ }
+
+ // Okay, both tokens are from the same file. Get their offsets from the
+ // start of the file.
+ unsigned PPOffs = SM.getFileOffset(PPLoc);
+ unsigned RawOffs = SM.getFileOffset(RawTok.getLocation());
+
+ // If the offsets are the same and the token kind is the same, ignore them.
+ if (PPOffs == RawOffs && isSameToken(RawTok, PPTok)) {
+ RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
+ PP.Lex(PPTok);
+ continue;
+ }
+
+ // If the PP token is farther along than the raw token, something was
+ // deleted. Comment out the raw token.
+ if (RawOffs <= PPOffs) {
+ // Comment out a whole run of tokens instead of bracketing each one with
+ // comments. Add a leading space if RawTok didn't have one.
+ bool HasSpace = RawTok.hasLeadingSpace();
+ RB.InsertTextAfter(RawOffs, " /*"+HasSpace, 2+!HasSpace);
+ unsigned EndPos;
+
+ do {
+ EndPos = RawOffs+RawTok.getLength();
+
+ RawTok = GetNextRawTok(RawTokens, CurRawTok, true);
+ RawOffs = SM.getFileOffset(RawTok.getLocation());
+
+ if (RawTok.is(tok::comment)) {
+ // Skip past the comment.
+ RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
+ break;
+ }
+
+ } while (RawOffs <= PPOffs && !RawTok.isAtStartOfLine() &&
+ (PPOffs != RawOffs || !isSameToken(RawTok, PPTok)));
+
+ RB.InsertTextBefore(EndPos, "*/", 2);
+ continue;
+ }
+
+ // Otherwise, there was a replacement an expansion. Insert the new token
+ // in the output buffer. Insert the whole run of new tokens at once to get
+ // them in the right order.
+ unsigned InsertPos = PPOffs;
+ std::string Expansion;
+ while (PPOffs < RawOffs) {
+ Expansion += ' ' + PP.getSpelling(PPTok);
+ PP.Lex(PPTok);
+ PPLoc = SM.getInstantiationLoc(PPTok.getLocation());
+ PPOffs = SM.getFileOffset(PPLoc);
+ }
+ Expansion += ' ';
+ RB.InsertTextBefore(InsertPos, &Expansion[0], Expansion.size());
+ }
+
+ // Get the buffer corresponding to MainFileID. If we haven't changed it, then
+ // we are done.
+ if (const RewriteBuffer *RewriteBuf =
+ Rewrite.getRewriteBufferFor(SM.getMainFileID())) {
+ //printf("Changed:\n");
+ *OS << std::string(RewriteBuf->begin(), RewriteBuf->end());
+ } else {
+ fprintf(stderr, "No changes\n");
+ }
+ OS->flush();
+}
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
new file mode 100644
index 000000000000..f382704014f7
--- /dev/null
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -0,0 +1,4693 @@
+//===--- RewriteObjC.cpp - Playground for the code rewriter ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Hacks and fun related to the code rewriter.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+using llvm::utostr;
+
+namespace {
+ class RewriteObjC : public ASTConsumer {
+ Rewriter Rewrite;
+ Diagnostic &Diags;
+ const LangOptions &LangOpts;
+ unsigned RewriteFailedDiag;
+ unsigned TryFinallyContainsReturnDiag;
+
+ ASTContext *Context;
+ SourceManager *SM;
+ TranslationUnitDecl *TUDecl;
+ FileID MainFileID;
+ const char *MainFileStart, *MainFileEnd;
+ SourceLocation LastIncLoc;
+
+ llvm::SmallVector<ObjCImplementationDecl *, 8> ClassImplementation;
+ llvm::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;
+ // Remember all the @protocol(<expr>) expressions.
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ProtocolExprDecls;
+
+ unsigned NumObjCStringLiterals;
+
+ FunctionDecl *MsgSendFunctionDecl;
+ FunctionDecl *MsgSendSuperFunctionDecl;
+ FunctionDecl *MsgSendStretFunctionDecl;
+ FunctionDecl *MsgSendSuperStretFunctionDecl;
+ FunctionDecl *MsgSendFpretFunctionDecl;
+ FunctionDecl *GetClassFunctionDecl;
+ FunctionDecl *GetMetaClassFunctionDecl;
+ FunctionDecl *SelGetUidFunctionDecl;
+ FunctionDecl *CFStringFunctionDecl;
+ FunctionDecl *SuperContructorFunctionDecl;
+
+ // ObjC string constant support.
+ VarDecl *ConstantStringClassReference;
+ RecordDecl *NSStringRecord;
+
+ // ObjC foreach break/continue generation support.
+ int BcLabelCount;
+
+ // Needed for super.
+ ObjCMethodDecl *CurMethodDef;
+ RecordDecl *SuperStructDecl;
+ RecordDecl *ConstantStringDecl;
+
+ TypeDecl *ProtocolTypeDecl;
+ QualType getProtocolType();
+
+ // Needed for header files being rewritten
+ bool IsHeader;
+
+ std::string InFileName;
+ llvm::raw_ostream* OutFile;
+
+ bool SilenceRewriteMacroWarning;
+
+ std::string Preamble;
+
+ // Block expressions.
+ llvm::SmallVector<BlockExpr *, 32> Blocks;
+ llvm::SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs;
+ llvm::DenseMap<BlockDeclRefExpr *, CallExpr *> BlockCallExprs;
+
+ // Block related declarations.
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
+
+ llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
+
+ // This maps a property to it's assignment statement.
+ llvm::DenseMap<ObjCPropertyRefExpr *, BinaryOperator *> PropSetters;
+ // This maps a property to it's synthesied message expression.
+ // This allows us to rewrite chained getters (e.g. o.a.b.c).
+ llvm::DenseMap<ObjCPropertyRefExpr *, Stmt *> PropGetters;
+
+ // This maps an original source AST to it's rewritten form. This allows
+ // us to avoid rewriting the same node twice (which is very uncommon).
+ // This is needed to support some of the exotic property rewriting.
+ llvm::DenseMap<Stmt *, Stmt *> ReplacedNodes;
+
+ FunctionDecl *CurFunctionDef;
+ VarDecl *GlobalVarDecl;
+
+ bool DisableReplaceStmt;
+
+ static const int OBJC_ABI_VERSION =7 ;
+ public:
+ virtual void Initialize(ASTContext &context);
+
+ // Top Level Driver code.
+ virtual void HandleTopLevelDecl(DeclGroupRef D) {
+ for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
+ HandleTopLevelSingleDecl(*I);
+ }
+ void HandleTopLevelSingleDecl(Decl *D);
+ void HandleDeclInMainFile(Decl *D);
+ RewriteObjC(std::string inFile, llvm::raw_ostream *OS,
+ Diagnostic &D, const LangOptions &LOpts,
+ bool silenceMacroWarn);
+
+ ~RewriteObjC() {}
+
+ virtual void HandleTranslationUnit(ASTContext &C);
+
+ void ReplaceStmt(Stmt *Old, Stmt *New) {
+ Stmt *ReplacingStmt = ReplacedNodes[Old];
+
+ if (ReplacingStmt)
+ return; // We can't rewrite the same node twice.
+
+ if (DisableReplaceStmt)
+ return; // Used when rewriting the assignment of a property setter.
+
+ // If replacement succeeded or warning disabled return with no warning.
+ if (!Rewrite.ReplaceStmt(Old, New)) {
+ ReplacedNodes[Old] = New;
+ return;
+ }
+ if (SilenceRewriteMacroWarning)
+ return;
+ Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag)
+ << Old->getSourceRange();
+ }
+
+ void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) {
+ // Measaure the old text.
+ int Size = Rewrite.getRangeSize(SrcRange);
+ if (Size == -1) {
+ Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag)
+ << Old->getSourceRange();
+ return;
+ }
+ // Get the new text.
+ std::string SStr;
+ llvm::raw_string_ostream S(SStr);
+ New->printPretty(S, *Context);
+ const std::string &Str = S.str();
+
+ // If replacement succeeded or warning disabled return with no warning.
+ if (!Rewrite.ReplaceText(SrcRange.getBegin(), Size, &Str[0], Str.size())) {
+ ReplacedNodes[Old] = New;
+ return;
+ }
+ if (SilenceRewriteMacroWarning)
+ return;
+ Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag)
+ << Old->getSourceRange();
+ }
+
+ void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen,
+ bool InsertAfter = true) {
+ // If insertion succeeded or warning disabled return with no warning.
+ if (!Rewrite.InsertText(Loc, StrData, StrLen, InsertAfter) ||
+ SilenceRewriteMacroWarning)
+ return;
+
+ Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);
+ }
+
+ void RemoveText(SourceLocation Loc, unsigned StrLen) {
+ // If removal succeeded or warning disabled return with no warning.
+ if (!Rewrite.RemoveText(Loc, StrLen) || SilenceRewriteMacroWarning)
+ return;
+
+ Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);
+ }
+
+ void ReplaceText(SourceLocation Start, unsigned OrigLength,
+ const char *NewStr, unsigned NewLength) {
+ // If removal succeeded or warning disabled return with no warning.
+ if (!Rewrite.ReplaceText(Start, OrigLength, NewStr, NewLength) ||
+ SilenceRewriteMacroWarning)
+ return;
+
+ Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag);
+ }
+
+ // Syntactic Rewriting.
+ void RewritePrologue(SourceLocation Loc);
+ void RewriteInclude();
+ void RewriteTabs();
+ void RewriteForwardClassDecl(ObjCClassDecl *Dcl);
+ void RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
+ ObjCImplementationDecl *IMD,
+ ObjCCategoryImplDecl *CID);
+ void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl);
+ void RewriteImplementationDecl(Decl *Dcl);
+ void RewriteObjCMethodDecl(ObjCMethodDecl *MDecl, std::string &ResultStr);
+ void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
+ void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
+ void RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *Dcl);
+ void RewriteMethodDeclaration(ObjCMethodDecl *Method);
+ void RewriteProperty(ObjCPropertyDecl *prop);
+ void RewriteFunctionDecl(FunctionDecl *FD);
+ void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl);
+ void RewriteObjCQualifiedInterfaceTypes(Expr *E);
+ bool needToScanForQualifiers(QualType T);
+ ObjCInterfaceDecl *isSuperReceiver(Expr *recExpr);
+ QualType getSuperStructType();
+ QualType getConstantStringStructType();
+ bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf);
+
+ // Expression Rewriting.
+ Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S);
+ void CollectPropertySetters(Stmt *S);
+
+ Stmt *CurrentBody;
+ ParentMap *PropParentMap; // created lazily.
+
+ Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
+ Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation OrigStart);
+ Stmt *RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr);
+ Stmt *RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
+ SourceRange SrcRange);
+ Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);
+ Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
+ Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
+ Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp);
+ void WarnAboutReturnGotoContinueOrBreakStmts(Stmt *S);
+ Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S);
+ Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S);
+ Stmt *RewriteObjCCatchStmt(ObjCAtCatchStmt *S);
+ Stmt *RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S);
+ Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S);
+ Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
+ SourceLocation OrigEnd);
+ CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
+ Expr **args, unsigned nargs);
+ Stmt *SynthMessageExpr(ObjCMessageExpr *Exp);
+ Stmt *RewriteBreakStmt(BreakStmt *S);
+ Stmt *RewriteContinueStmt(ContinueStmt *S);
+ void SynthCountByEnumWithState(std::string &buf);
+
+ void SynthMsgSendFunctionDecl();
+ void SynthMsgSendSuperFunctionDecl();
+ void SynthMsgSendStretFunctionDecl();
+ void SynthMsgSendFpretFunctionDecl();
+ void SynthMsgSendSuperStretFunctionDecl();
+ void SynthGetClassFunctionDecl();
+ void SynthGetMetaClassFunctionDecl();
+ void SynthSelGetUidFunctionDecl();
+ void SynthSuperContructorFunctionDecl();
+
+ // Metadata emission.
+ void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
+ std::string &Result);
+
+ void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,
+ std::string &Result);
+
+ template<typename MethodIterator>
+ void RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
+ MethodIterator MethodEnd,
+ bool IsInstanceMethod,
+ const char *prefix,
+ const char *ClassName,
+ std::string &Result);
+
+ void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol,
+ const char *prefix,
+ const char *ClassName,
+ std::string &Result);
+ void RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Prots,
+ const char *prefix,
+ const char *ClassName,
+ std::string &Result);
+ void SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
+ std::string &Result);
+ void SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl,
+ ObjCIvarDecl *ivar,
+ std::string &Result);
+ void RewriteImplementations();
+ void SynthesizeMetaDataIntoBuffer(std::string &Result);
+
+ // Block rewriting.
+ void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D);
+ void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND);
+
+ void InsertBlockLiteralsWithinFunction(FunctionDecl *FD);
+ void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD);
+
+ // Block specific rewrite rules.
+ void RewriteBlockCall(CallExpr *Exp);
+ void RewriteBlockPointerDecl(NamedDecl *VD);
+ Stmt *RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD);
+ void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
+
+ std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
+ const char *funcName, std::string Tag);
+ std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
+ const char *funcName, std::string Tag);
+ std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
+ bool hasCopyDisposeHelpers);
+ Stmt *SynthesizeBlockCall(CallExpr *Exp);
+ void SynthesizeBlockLiterals(SourceLocation FunLocStart,
+ const char *FunName);
+
+ void CollectBlockDeclRefInfo(BlockExpr *Exp);
+ void GetBlockCallExprs(Stmt *S);
+ void GetBlockDeclRefExprs(Stmt *S);
+
+ // We avoid calling Type::isBlockPointerType(), since it operates on the
+ // canonical type. We only care if the top-level type is a closure pointer.
+ bool isTopLevelBlockPointerType(QualType T) {
+ return isa<BlockPointerType>(T);
+ }
+
+ // FIXME: This predicate seems like it would be useful to add to ASTContext.
+ bool isObjCType(QualType T) {
+ if (!LangOpts.ObjC1 && !LangOpts.ObjC2)
+ return false;
+
+ QualType OCT = Context->getCanonicalType(T).getUnqualifiedType();
+
+ if (OCT == Context->getCanonicalType(Context->getObjCIdType()) ||
+ OCT == Context->getCanonicalType(Context->getObjCClassType()))
+ return true;
+
+ if (const PointerType *PT = OCT->getAsPointerType()) {
+ if (isa<ObjCInterfaceType>(PT->getPointeeType()) ||
+ isa<ObjCQualifiedIdType>(PT->getPointeeType()))
+ return true;
+ }
+ return false;
+ }
+ bool PointerTypeTakesAnyBlockArguments(QualType QT);
+ void GetExtentOfArgList(const char *Name, const char *&LParen,
+ const char *&RParen);
+ void RewriteCastExpr(CStyleCastExpr *CE);
+
+ FunctionDecl *SynthBlockInitFunctionDecl(const char *name);
+ Stmt *SynthBlockInitExpr(BlockExpr *Exp);
+
+ void QuoteDoublequotes(std::string &From, std::string &To) {
+ for(unsigned i = 0; i < From.length(); i++) {
+ if (From[i] == '"')
+ To += "\\\"";
+ else
+ To += From[i];
+ }
+ }
+ };
+}
+
+void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType,
+ NamedDecl *D) {
+ if (FunctionProtoType *fproto = dyn_cast<FunctionProtoType>(funcType)) {
+ for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(),
+ E = fproto->arg_type_end(); I && (I != E); ++I)
+ if (isTopLevelBlockPointerType(*I)) {
+ // All the args are checked/rewritten. Don't call twice!
+ RewriteBlockPointerDecl(D);
+ break;
+ }
+ }
+}
+
+void RewriteObjC::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) {
+ const PointerType *PT = funcType->getAsPointerType();
+ if (PT && PointerTypeTakesAnyBlockArguments(funcType))
+ RewriteBlocksInFunctionProtoType(PT->getPointeeType(), ND);
+}
+
+static bool IsHeaderFile(const std::string &Filename) {
+ std::string::size_type DotPos = Filename.rfind('.');
+
+ if (DotPos == std::string::npos) {
+ // no file extension
+ return false;
+ }
+
+ std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end());
+ // C header: .h
+ // C++ header: .hh or .H;
+ return Ext == "h" || Ext == "hh" || Ext == "H";
+}
+
+RewriteObjC::RewriteObjC(std::string inFile, llvm::raw_ostream* OS,
+ Diagnostic &D, const LangOptions &LOpts,
+ bool silenceMacroWarn)
+ : Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS),
+ SilenceRewriteMacroWarning(silenceMacroWarn) {
+ IsHeader = IsHeaderFile(inFile);
+ RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
+ "rewriting sub-expression within a macro (may not be correct)");
+ TryFinallyContainsReturnDiag = Diags.getCustomDiagID(Diagnostic::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,
+ const LangOptions &LOpts,
+ bool SilenceRewriteMacroWarning) {
+ return new RewriteObjC(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning);
+}
+
+void RewriteObjC::Initialize(ASTContext &context) {
+ Context = &context;
+ SM = &Context->getSourceManager();
+ TUDecl = Context->getTranslationUnitDecl();
+ MsgSendFunctionDecl = 0;
+ MsgSendSuperFunctionDecl = 0;
+ MsgSendStretFunctionDecl = 0;
+ MsgSendSuperStretFunctionDecl = 0;
+ MsgSendFpretFunctionDecl = 0;
+ GetClassFunctionDecl = 0;
+ GetMetaClassFunctionDecl = 0;
+ SelGetUidFunctionDecl = 0;
+ CFStringFunctionDecl = 0;
+ ConstantStringClassReference = 0;
+ NSStringRecord = 0;
+ CurMethodDef = 0;
+ CurFunctionDef = 0;
+ GlobalVarDecl = 0;
+ SuperStructDecl = 0;
+ ProtocolTypeDecl = 0;
+ ConstantStringDecl = 0;
+ BcLabelCount = 0;
+ SuperContructorFunctionDecl = 0;
+ NumObjCStringLiterals = 0;
+ PropParentMap = 0;
+ CurrentBody = 0;
+ DisableReplaceStmt = false;
+
+ // Get the ID and start/end of the main file.
+ MainFileID = SM->getMainFileID();
+ const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID);
+ MainFileStart = MainBuf->getBufferStart();
+ MainFileEnd = MainBuf->getBufferEnd();
+
+ Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOptions());
+
+ // declaring objc_selector outside the parameter list removes a silly
+ // scope related warning...
+ if (IsHeader)
+ Preamble = "#pragma once\n";
+ Preamble += "struct objc_selector; struct objc_class;\n";
+ Preamble += "struct __rw_objc_super { struct objc_object *object; ";
+ Preamble += "struct objc_object *superClass; ";
+ if (LangOpts.Microsoft) {
+ // Add a constructor for creating temporary objects.
+ Preamble += "__rw_objc_super(struct objc_object *o, struct objc_object *s) "
+ ": ";
+ Preamble += "object(o), superClass(s) {} ";
+ }
+ Preamble += "};\n";
+ Preamble += "#ifndef _REWRITER_typedef_Protocol\n";
+ Preamble += "typedef struct objc_object Protocol;\n";
+ Preamble += "#define _REWRITER_typedef_Protocol\n";
+ Preamble += "#endif\n";
+ if (LangOpts.Microsoft) {
+ Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n";
+ Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n";
+ } else
+ Preamble += "#define __OBJC_RW_DLLIMPORT extern\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend";
+ Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper";
+ Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend_stret";
+ Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper_stret";
+ Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT double objc_msgSend_fpret";
+ Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass";
+ Preamble += "(const char *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass";
+ Preamble += "(const char *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw(struct objc_object *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_enter(void *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_exit(void *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_exception_extract(void *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT int objc_exception_match";
+ Preamble += "(struct objc_class *, struct objc_object *);\n";
+ // @synchronized hooks.
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_enter(struct objc_object *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_exit(struct objc_object *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n";
+ Preamble += "#ifndef __FASTENUMERATIONSTATE\n";
+ Preamble += "struct __objcFastEnumerationState {\n\t";
+ Preamble += "unsigned long state;\n\t";
+ Preamble += "void **itemsPtr;\n\t";
+ Preamble += "unsigned long *mutationsPtr;\n\t";
+ Preamble += "unsigned long extra[5];\n};\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n";
+ Preamble += "#define __FASTENUMERATIONSTATE\n";
+ Preamble += "#endif\n";
+ Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n";
+ Preamble += "struct __NSConstantStringImpl {\n";
+ Preamble += " int *isa;\n";
+ Preamble += " int flags;\n";
+ Preamble += " char *str;\n";
+ Preamble += " long length;\n";
+ Preamble += "};\n";
+ Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n";
+ Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n";
+ Preamble += "#else\n";
+ Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n";
+ Preamble += "#endif\n";
+ Preamble += "#define __NSCONSTANTSTRINGIMPL\n";
+ Preamble += "#endif\n";
+ // Blocks preamble.
+ Preamble += "#ifndef BLOCK_IMPL\n";
+ Preamble += "#define BLOCK_IMPL\n";
+ Preamble += "struct __block_impl {\n";
+ Preamble += " void *isa;\n";
+ Preamble += " int Flags;\n";
+ Preamble += " int Size;\n";
+ Preamble += " void *FuncPtr;\n";
+ Preamble += "};\n";
+ Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n";
+ Preamble += "__OBJC_RW_STATICIMPORT void _Block_object_assign(void *, const void *, const int);\n";
+ Preamble += "__OBJC_RW_STATICIMPORT void _Block_object_dispose(const void *, const int);\n";
+ Preamble += "__OBJC_RW_STATICIMPORT void *_NSConcreteGlobalBlock[32];\n";
+ Preamble += "__OBJC_RW_STATICIMPORT void *_NSConcreteStackBlock[32];\n";
+ Preamble += "#endif\n";
+ if (LangOpts.Microsoft) {
+ Preamble += "#undef __OBJC_RW_DLLIMPORT\n";
+ Preamble += "#undef __OBJC_RW_STATICIMPORT\n";
+ Preamble += "#define __attribute__(X)\n";
+ }
+}
+
+
+//===----------------------------------------------------------------------===//
+// Top Level Driver Code
+//===----------------------------------------------------------------------===//
+
+void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
+ // Two cases: either the decl could be in the main file, or it could be in a
+ // #included file. If the former, rewrite it now. If the later, check to see
+ // if we rewrote the #include/#import.
+ SourceLocation Loc = D->getLocation();
+ Loc = SM->getInstantiationLoc(Loc);
+
+ // If this is for a builtin, ignore it.
+ if (Loc.isInvalid()) return;
+
+ // Look for built-in declarations that we need to refer during the rewrite.
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ RewriteFunctionDecl(FD);
+ } else if (VarDecl *FVD = dyn_cast<VarDecl>(D)) {
+ // declared in <Foundation/NSString.h>
+ if (strcmp(FVD->getNameAsCString(), "_NSConstantStringClassReference") == 0) {
+ ConstantStringClassReference = FVD;
+ return;
+ }
+ } else if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D)) {
+ RewriteInterfaceDecl(MD);
+ } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) {
+ RewriteCategoryDecl(CD);
+ } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
+ RewriteProtocolDecl(PD);
+ } else if (ObjCForwardProtocolDecl *FP =
+ dyn_cast<ObjCForwardProtocolDecl>(D)){
+ RewriteForwardProtocolDecl(FP);
+ } else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
+ // Recurse into linkage specifications
+ for (DeclContext::decl_iterator DI = LSD->decls_begin(*Context),
+ DIEnd = LSD->decls_end(*Context);
+ DI != DIEnd; ++DI)
+ HandleTopLevelSingleDecl(*DI);
+ }
+ // If we have a decl in the main file, see if we should rewrite it.
+ if (SM->isFromMainFile(Loc))
+ return HandleDeclInMainFile(D);
+}
+
+//===----------------------------------------------------------------------===//
+// Syntactic (non-AST) Rewriting Code
+//===----------------------------------------------------------------------===//
+
+void RewriteObjC::RewriteInclude() {
+ SourceLocation LocStart = SM->getLocForStartOfFile(MainFileID);
+ std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
+ const char *MainBufStart = MainBuf.first;
+ const char *MainBufEnd = MainBuf.second;
+ size_t ImportLen = strlen("import");
+ size_t IncludeLen = strlen("include");
+
+ // Loop over the whole file, looking for includes.
+ for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) {
+ if (*BufPtr == '#') {
+ if (++BufPtr == MainBufEnd)
+ return;
+ while (*BufPtr == ' ' || *BufPtr == '\t')
+ if (++BufPtr == MainBufEnd)
+ return;
+ if (!strncmp(BufPtr, "import", ImportLen)) {
+ // replace import with include
+ SourceLocation ImportLoc =
+ LocStart.getFileLocWithOffset(BufPtr-MainBufStart);
+ ReplaceText(ImportLoc, ImportLen, "include", IncludeLen);
+ BufPtr += ImportLen;
+ }
+ }
+ }
+}
+
+void RewriteObjC::RewriteTabs() {
+ std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
+ const char *MainBufStart = MainBuf.first;
+ const char *MainBufEnd = MainBuf.second;
+
+ // Loop over the whole file, looking for tabs.
+ for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) {
+ if (*BufPtr != '\t')
+ continue;
+
+ // Okay, we found a tab. This tab will turn into at least one character,
+ // but it depends on which 'virtual column' it is in. Compute that now.
+ unsigned VCol = 0;
+ while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' &&
+ BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r')
+ ++VCol;
+
+ // Okay, now that we know the virtual column, we know how many spaces to
+ // insert. We assume 8-character tab-stops.
+ unsigned Spaces = 8-(VCol & 7);
+
+ // Get the location of the tab.
+ SourceLocation TabLoc = SM->getLocForStartOfFile(MainFileID);
+ TabLoc = TabLoc.getFileLocWithOffset(BufPtr-MainBufStart);
+
+ // Rewrite the single tab character into a sequence of spaces.
+ ReplaceText(TabLoc, 1, " ", Spaces);
+ }
+}
+
+static std::string getIvarAccessString(ObjCInterfaceDecl *ClassDecl,
+ ObjCIvarDecl *OID) {
+ std::string S;
+ S = "((struct ";
+ S += ClassDecl->getIdentifier()->getName();
+ S += "_IMPL *)self)->";
+ S += OID->getNameAsCString();
+ return S;
+}
+
+void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
+ ObjCImplementationDecl *IMD,
+ ObjCCategoryImplDecl *CID) {
+ SourceLocation startLoc = PID->getLocStart();
+ InsertText(startLoc, "// ", 3);
+ const char *startBuf = SM->getCharacterData(startLoc);
+ assert((*startBuf == '@') && "bogus @synthesize location");
+ const char *semiBuf = strchr(startBuf, ';');
+ assert((*semiBuf == ';') && "@synthesize: can't find ';'");
+ SourceLocation onePastSemiLoc =
+ startLoc.getFileLocWithOffset(semiBuf-startBuf+1);
+
+ if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ return; // FIXME: is this correct?
+
+ // Generate the 'getter' function.
+ ObjCPropertyDecl *PD = PID->getPropertyDecl();
+ ObjCInterfaceDecl *ClassDecl = PD->getGetterMethodDecl()->getClassInterface();
+ ObjCIvarDecl *OID = PID->getPropertyIvarDecl();
+
+ if (!OID)
+ return;
+
+ std::string Getr;
+ RewriteObjCMethodDecl(PD->getGetterMethodDecl(), Getr);
+ Getr += "{ ";
+ // Synthesize an explicit cast to gain access to the ivar.
+ // FIXME: deal with code generation implications for various property
+ // attributes (copy, retain, nonatomic).
+ // See objc-act.c:objc_synthesize_new_getter() for details.
+ Getr += "return " + getIvarAccessString(ClassDecl, OID);
+ Getr += "; }";
+ InsertText(onePastSemiLoc, Getr.c_str(), Getr.size());
+ if (PD->isReadOnly())
+ return;
+
+ // Generate the 'setter' function.
+ std::string Setr;
+ RewriteObjCMethodDecl(PD->getSetterMethodDecl(), Setr);
+ Setr += "{ ";
+ // Synthesize an explicit cast to initialize the ivar.
+ // FIXME: deal with code generation implications for various property
+ // attributes (copy, retain, nonatomic).
+ // See objc-act.c:objc_synthesize_new_setter() for details.
+ Setr += getIvarAccessString(ClassDecl, OID) + " = ";
+ Setr += PD->getNameAsCString();
+ Setr += "; }";
+ InsertText(onePastSemiLoc, Setr.c_str(), Setr.size());
+}
+
+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, ';');
+
+ // 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.
+ std::string typedefString;
+ typedefString += "// ";
+ typedefString.append(startBuf, semiPtr-startBuf+1);
+ typedefString += "\n";
+ for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end();
+ I != E; ++I) {
+ ObjCInterfaceDecl *ForwardDecl = *I;
+ 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.c_str(), typedefString.size());
+}
+
+void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
+ SourceLocation LocStart = Method->getLocStart();
+ SourceLocation LocEnd = Method->getLocEnd();
+
+ if (SM->getInstantiationLineNumber(LocEnd) >
+ SM->getInstantiationLineNumber(LocStart)) {
+ InsertText(LocStart, "#if 0\n", 6);
+ ReplaceText(LocEnd, 1, ";\n#endif\n", 9);
+ } else {
+ InsertText(LocStart, "// ", 3);
+ }
+}
+
+void RewriteObjC::RewriteProperty(ObjCPropertyDecl *prop)
+{
+ SourceLocation Loc = prop->getLocation();
+
+ ReplaceText(Loc, 0, "// ", 3);
+
+ // FIXME: handle properties that are declared across multiple lines.
+}
+
+void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
+ SourceLocation LocStart = CatDecl->getLocStart();
+
+ // FIXME: handle category headers that are declared across multiple lines.
+ ReplaceText(LocStart, 0, "// ", 3);
+
+ for (ObjCCategoryDecl::instmeth_iterator
+ I = CatDecl->instmeth_begin(*Context),
+ E = CatDecl->instmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+ for (ObjCCategoryDecl::classmeth_iterator
+ I = CatDecl->classmeth_begin(*Context),
+ E = CatDecl->classmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+
+ // Lastly, comment out the @end.
+ ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3);
+}
+
+void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
+ std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
+
+ SourceLocation LocStart = PDecl->getLocStart();
+
+ // FIXME: handle protocol headers that are declared across multiple lines.
+ ReplaceText(LocStart, 0, "// ", 3);
+
+ for (ObjCProtocolDecl::instmeth_iterator
+ I = PDecl->instmeth_begin(*Context),
+ E = PDecl->instmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+ for (ObjCProtocolDecl::classmeth_iterator
+ I = PDecl->classmeth_begin(*Context),
+ E = PDecl->classmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+
+ // Lastly, comment out the @end.
+ SourceLocation LocEnd = PDecl->getAtEndLoc();
+ ReplaceText(LocEnd, 0, "// ", 3);
+
+ // Must comment out @optional/@required
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+ for (const char *p = startBuf; p < endBuf; p++) {
+ if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) {
+ std::string CommentedOptional = "/* @optional */";
+ SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
+ ReplaceText(OptionalLoc, strlen("@optional"),
+ CommentedOptional.c_str(), CommentedOptional.size());
+
+ }
+ else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) {
+ std::string CommentedRequired = "/* @required */";
+ SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
+ ReplaceText(OptionalLoc, strlen("@required"),
+ CommentedRequired.c_str(), CommentedRequired.size());
+
+ }
+ }
+}
+
+void RewriteObjC::RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *PDecl) {
+ SourceLocation LocStart = PDecl->getLocation();
+ if (LocStart.isInvalid())
+ assert(false && "Invalid SourceLocation");
+ // FIXME: handle forward protocol that are declared across multiple lines.
+ ReplaceText(LocStart, 0, "// ", 3);
+}
+
+void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
+ std::string &ResultStr) {
+ //fprintf(stderr,"In RewriteObjCMethodDecl\n");
+ const FunctionType *FPRetType = 0;
+ ResultStr += "\nstatic ";
+ if (OMD->getResultType()->isObjCQualifiedIdType())
+ ResultStr += "id";
+ else if (OMD->getResultType()->isFunctionPointerType() ||
+ OMD->getResultType()->isBlockPointerType()) {
+ // needs special handling, since pointer-to-functions have special
+ // syntax (where a decaration models use).
+ QualType retType = OMD->getResultType();
+ QualType PointeeTy;
+ if (const PointerType* PT = retType->getAsPointerType())
+ PointeeTy = PT->getPointeeType();
+ else if (const BlockPointerType *BPT = retType->getAsBlockPointerType())
+ PointeeTy = BPT->getPointeeType();
+ if ((FPRetType = PointeeTy->getAsFunctionType())) {
+ ResultStr += FPRetType->getResultType().getAsString();
+ ResultStr += "(*";
+ }
+ } else
+ ResultStr += OMD->getResultType().getAsString();
+ ResultStr += " ";
+
+ // Unique method name
+ std::string NameStr;
+
+ if (OMD->isInstanceMethod())
+ NameStr += "_I_";
+ else
+ NameStr += "_C_";
+
+ NameStr += OMD->getClassInterface()->getNameAsString();
+ NameStr += "_";
+
+ if (ObjCCategoryImplDecl *CID =
+ dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) {
+ NameStr += CID->getNameAsString();
+ NameStr += "_";
+ }
+ // Append selector names, replacing ':' with '_'
+ {
+ std::string selString = OMD->getSelector().getAsString();
+ int len = selString.size();
+ for (int i = 0; i < len; i++)
+ if (selString[i] == ':')
+ selString[i] = '_';
+ NameStr += selString;
+ }
+ // Remember this name for metadata emission
+ MethodInternalNames[OMD] = NameStr;
+ ResultStr += NameStr;
+
+ // Rewrite arguments
+ ResultStr += "(";
+
+ // invisible arguments
+ if (OMD->isInstanceMethod()) {
+ QualType selfTy = Context->getObjCInterfaceType(OMD->getClassInterface());
+ selfTy = Context->getPointerType(selfTy);
+ if (!LangOpts.Microsoft) {
+ if (ObjCSynthesizedStructs.count(OMD->getClassInterface()))
+ ResultStr += "struct ";
+ }
+ // When rewriting for Microsoft, explicitly omit the structure name.
+ ResultStr += OMD->getClassInterface()->getNameAsString();
+ ResultStr += " *";
+ }
+ else
+ ResultStr += Context->getObjCClassType().getAsString();
+
+ ResultStr += " self, ";
+ ResultStr += Context->getObjCSelType().getAsString();
+ ResultStr += " _cmd";
+
+ // Method arguments.
+ for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
+ E = OMD->param_end(); PI != E; ++PI) {
+ ParmVarDecl *PDecl = *PI;
+ ResultStr += ", ";
+ if (PDecl->getType()->isObjCQualifiedIdType()) {
+ ResultStr += "id ";
+ ResultStr += PDecl->getNameAsString();
+ } else {
+ std::string Name = PDecl->getNameAsString();
+ if (isTopLevelBlockPointerType(PDecl->getType())) {
+ // Make sure we convert "t (^)(...)" to "t (*)(...)".
+ const BlockPointerType *BPT = PDecl->getType()->getAsBlockPointerType();
+ Context->getPointerType(BPT->getPointeeType()).getAsStringInternal(Name,
+ Context->PrintingPolicy);
+ } else
+ PDecl->getType().getAsStringInternal(Name, Context->PrintingPolicy);
+ ResultStr += Name;
+ }
+ }
+ if (OMD->isVariadic())
+ ResultStr += ", ...";
+ ResultStr += ") ";
+
+ if (FPRetType) {
+ ResultStr += ")"; // close the precedence "scope" for "*".
+
+ // Now, emit the argument types (if any).
+ if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FPRetType)) {
+ ResultStr += "(";
+ for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) {
+ if (i) ResultStr += ", ";
+ std::string ParamStr = FT->getArgType(i).getAsString();
+ ResultStr += ParamStr;
+ }
+ if (FT->isVariadic()) {
+ if (FT->getNumArgs()) ResultStr += ", ";
+ ResultStr += "...";
+ }
+ ResultStr += ")";
+ } else {
+ ResultStr += "()";
+ }
+ }
+}
+void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
+ ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID);
+ ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID);
+
+ if (IMD)
+ InsertText(IMD->getLocStart(), "// ", 3);
+ else
+ InsertText(CID->getLocStart(), "// ", 3);
+
+ for (ObjCCategoryImplDecl::instmeth_iterator
+ I = IMD ? IMD->instmeth_begin(*Context) : CID->instmeth_begin(*Context),
+ E = IMD ? IMD->instmeth_end(*Context) : CID->instmeth_end(*Context);
+ I != E; ++I) {
+ std::string ResultStr;
+ ObjCMethodDecl *OMD = *I;
+ RewriteObjCMethodDecl(OMD, ResultStr);
+ SourceLocation LocStart = OMD->getLocStart();
+ SourceLocation LocEnd = OMD->getCompoundBody(*Context)->getLocStart();
+
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+ ReplaceText(LocStart, endBuf-startBuf,
+ ResultStr.c_str(), ResultStr.size());
+ }
+
+ for (ObjCCategoryImplDecl::classmeth_iterator
+ I = IMD ? IMD->classmeth_begin(*Context) : CID->classmeth_begin(*Context),
+ E = IMD ? IMD->classmeth_end(*Context) : CID->classmeth_end(*Context);
+ I != E; ++I) {
+ std::string ResultStr;
+ ObjCMethodDecl *OMD = *I;
+ RewriteObjCMethodDecl(OMD, ResultStr);
+ SourceLocation LocStart = OMD->getLocStart();
+ SourceLocation LocEnd = OMD->getCompoundBody(*Context)->getLocStart();
+
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+ ReplaceText(LocStart, endBuf-startBuf,
+ ResultStr.c_str(), ResultStr.size());
+ }
+ for (ObjCCategoryImplDecl::propimpl_iterator
+ I = IMD ? IMD->propimpl_begin(*Context) : CID->propimpl_begin(*Context),
+ E = IMD ? IMD->propimpl_end(*Context) : CID->propimpl_end(*Context);
+ I != E; ++I) {
+ RewritePropertyImplDecl(*I, IMD, CID);
+ }
+
+ if (IMD)
+ InsertText(IMD->getLocEnd(), "// ", 3);
+ else
+ InsertText(CID->getLocEnd(), "// ", 3);
+}
+
+void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
+ std::string ResultStr;
+ if (!ObjCForwardDecls.count(ClassDecl)) {
+ // we haven't seen a forward decl - generate a typedef.
+ ResultStr = "#ifndef _REWRITER_typedef_";
+ ResultStr += ClassDecl->getNameAsString();
+ ResultStr += "\n";
+ ResultStr += "#define _REWRITER_typedef_";
+ ResultStr += ClassDecl->getNameAsString();
+ ResultStr += "\n";
+ ResultStr += "typedef struct objc_object ";
+ ResultStr += ClassDecl->getNameAsString();
+ ResultStr += ";\n#endif\n";
+ // Mark this typedef as having been generated.
+ ObjCForwardDecls.insert(ClassDecl);
+ }
+ SynthesizeObjCInternalStruct(ClassDecl, ResultStr);
+
+ for (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(*Context),
+ E = ClassDecl->prop_end(*Context); I != E; ++I)
+ RewriteProperty(*I);
+ for (ObjCInterfaceDecl::instmeth_iterator
+ I = ClassDecl->instmeth_begin(*Context),
+ E = ClassDecl->instmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+ for (ObjCInterfaceDecl::classmeth_iterator
+ I = ClassDecl->classmeth_begin(*Context),
+ E = ClassDecl->classmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+
+ // Lastly, comment out the @end.
+ ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3);
+}
+
+Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
+ SourceRange SrcRange) {
+ // Synthesize a ObjCMessageExpr from a ObjCPropertyRefExpr.
+ // This allows us to reuse all the fun and games in SynthMessageExpr().
+ ObjCPropertyRefExpr *PropRefExpr = dyn_cast<ObjCPropertyRefExpr>(BinOp->getLHS());
+ ObjCMessageExpr *MsgExpr;
+ ObjCPropertyDecl *PDecl = PropRefExpr->getProperty();
+ llvm::SmallVector<Expr *, 1> ExprVec;
+ ExprVec.push_back(newStmt);
+
+ Stmt *Receiver = PropRefExpr->getBase();
+ ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(Receiver);
+ if (PRE && PropGetters[PRE]) {
+ // This allows us to handle chain/nested property getters.
+ Receiver = PropGetters[PRE];
+ }
+ MsgExpr = new (Context) ObjCMessageExpr(dyn_cast<Expr>(Receiver),
+ PDecl->getSetterName(), PDecl->getType(),
+ PDecl->getSetterMethodDecl(),
+ SourceLocation(), SourceLocation(),
+ &ExprVec[0], 1);
+ Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr);
+
+ // Now do the actual rewrite.
+ ReplaceStmtWithRange(BinOp, ReplacingStmt, SrcRange);
+ //delete BinOp;
+ // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references
+ // to things that stay around.
+ Context->Deallocate(MsgExpr);
+ return ReplacingStmt;
+}
+
+Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) {
+ // Synthesize a ObjCMessageExpr from a ObjCPropertyRefExpr.
+ // This allows us to reuse all the fun and games in SynthMessageExpr().
+ ObjCMessageExpr *MsgExpr;
+ ObjCPropertyDecl *PDecl = PropRefExpr->getProperty();
+
+ Stmt *Receiver = PropRefExpr->getBase();
+
+ ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(Receiver);
+ if (PRE && PropGetters[PRE]) {
+ // This allows us to handle chain/nested property getters.
+ Receiver = PropGetters[PRE];
+ }
+ MsgExpr = new (Context) ObjCMessageExpr(dyn_cast<Expr>(Receiver),
+ PDecl->getGetterName(), PDecl->getType(),
+ PDecl->getGetterMethodDecl(),
+ SourceLocation(), SourceLocation(),
+ 0, 0);
+
+ Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr);
+
+ if (!PropParentMap)
+ PropParentMap = new ParentMap(CurrentBody);
+
+ Stmt *Parent = PropParentMap->getParent(PropRefExpr);
+ if (Parent && isa<ObjCPropertyRefExpr>(Parent)) {
+ // We stash away the ReplacingStmt since actually doing the
+ // replacement/rewrite won't work for nested getters (e.g. obj.p.i)
+ PropGetters[PropRefExpr] = ReplacingStmt;
+ // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references
+ // to things that stay around.
+ Context->Deallocate(MsgExpr);
+ return PropRefExpr; // return the original...
+ } else {
+ ReplaceStmt(PropRefExpr, ReplacingStmt);
+ // delete PropRefExpr; elsewhere...
+ // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references
+ // to things that stay around.
+ Context->Deallocate(MsgExpr);
+ return ReplacingStmt;
+ }
+}
+
+Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
+ SourceLocation OrigStart) {
+ ObjCIvarDecl *D = IV->getDecl();
+ if (CurMethodDef) {
+ if (const PointerType *pType = IV->getBase()->getType()->getAsPointerType()) {
+ ObjCInterfaceType *iFaceDecl =
+ dyn_cast<ObjCInterfaceType>(pType->getPointeeType());
+ // lookup which class implements the instance variable.
+ ObjCInterfaceDecl *clsDeclared = 0;
+ iFaceDecl->getDecl()->lookupInstanceVariable(*Context,
+ D->getIdentifier(),
+ clsDeclared);
+ assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
+
+ // Synthesize an explicit cast to gain access to the ivar.
+ std::string RecName = clsDeclared->getIdentifier()->getName();
+ RecName += "_IMPL";
+ IdentifierInfo *II = &Context->Idents.get(RecName.c_str());
+ RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ SourceLocation(), II);
+ assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
+ QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
+ CastExpr *castExpr = new (Context) CStyleCastExpr(castT, IV->getBase(),
+ castT,SourceLocation(),
+ SourceLocation());
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
+ IV->getBase()->getLocEnd(),
+ castExpr);
+ if (IV->isFreeIvar() &&
+ CurMethodDef->getClassInterface() == iFaceDecl->getDecl()) {
+ MemberExpr *ME = new (Context) MemberExpr(PE, true, D,
+ IV->getLocation(),
+ D->getType());
+ ReplaceStmt(IV, ME);
+ // delete IV; leak for now, see RewritePropertySetter() usage for more info.
+ return ME;
+ }
+
+ ReplaceStmt(IV->getBase(), PE);
+ // Cannot delete IV->getBase(), since PE points to it.
+ // Replace the old base with the cast. This is important when doing
+ // embedded rewrites. For example, [newInv->_container addObject:0].
+ IV->setBase(PE);
+ return IV;
+ }
+ } else { // we are outside a method.
+ assert(!IV->isFreeIvar() && "Cannot have a free standing ivar outside a method");
+
+ // Explicit ivar refs need to have a cast inserted.
+ // FIXME: consider sharing some of this code with the code above.
+ if (const PointerType *pType = IV->getBase()->getType()->getAsPointerType()) {
+ ObjCInterfaceType *iFaceDecl = dyn_cast<ObjCInterfaceType>(pType->getPointeeType());
+ // lookup which class implements the instance variable.
+ ObjCInterfaceDecl *clsDeclared = 0;
+ iFaceDecl->getDecl()->lookupInstanceVariable(*Context,
+ D->getIdentifier(),
+ clsDeclared);
+ assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
+
+ // Synthesize an explicit cast to gain access to the ivar.
+ std::string RecName = clsDeclared->getIdentifier()->getName();
+ RecName += "_IMPL";
+ IdentifierInfo *II = &Context->Idents.get(RecName.c_str());
+ RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ SourceLocation(), II);
+ assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
+ QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
+ CastExpr *castExpr = new (Context) CStyleCastExpr(castT, IV->getBase(),
+ castT, SourceLocation(),
+ SourceLocation());
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
+ IV->getBase()->getLocEnd(), castExpr);
+ ReplaceStmt(IV->getBase(), PE);
+ // Cannot delete IV->getBase(), since PE points to it.
+ // Replace the old base with the cast. This is important when doing
+ // embedded rewrites. For example, [newInv->_container addObject:0].
+ IV->setBase(PE);
+ return IV;
+ }
+ }
+ return IV;
+}
+
+/// SynthCountByEnumWithState - To print:
+/// ((unsigned int (*)
+/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
+/// (void *)objc_msgSend)((id)l_collection,
+/// sel_registerName(
+/// "countByEnumeratingWithState:objects:count:"),
+/// &enumState,
+/// (id *)items, (unsigned int)16)
+///
+void RewriteObjC::SynthCountByEnumWithState(std::string &buf) {
+ buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, "
+ "id *, unsigned int))(void *)objc_msgSend)";
+ buf += "\n\t\t";
+ buf += "((id)l_collection,\n\t\t";
+ buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),";
+ buf += "\n\t\t";
+ buf += "&enumState, "
+ "(id *)items, (unsigned int)16)";
+}
+
+/// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach
+/// statement to exit to its outer synthesized loop.
+///
+Stmt *RewriteObjC::RewriteBreakStmt(BreakStmt *S) {
+ if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))
+ return S;
+ // replace break with goto __break_label
+ std::string buf;
+
+ SourceLocation startLoc = S->getLocStart();
+ buf = "goto __break_label_";
+ buf += utostr(ObjCBcLabelNo.back());
+ ReplaceText(startLoc, strlen("break"), buf.c_str(), buf.size());
+
+ return 0;
+}
+
+/// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach
+/// statement to continue with its inner synthesized loop.
+///
+Stmt *RewriteObjC::RewriteContinueStmt(ContinueStmt *S) {
+ if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))
+ return S;
+ // replace continue with goto __continue_label
+ std::string buf;
+
+ SourceLocation startLoc = S->getLocStart();
+ buf = "goto __continue_label_";
+ buf += utostr(ObjCBcLabelNo.back());
+ ReplaceText(startLoc, strlen("continue"), buf.c_str(), buf.size());
+
+ return 0;
+}
+
+/// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement.
+/// It rewrites:
+/// for ( type elem in collection) { stmts; }
+
+/// Into:
+/// {
+/// type elem;
+/// struct __objcFastEnumerationState enumState = { 0 };
+/// id items[16];
+/// id l_collection = (id)collection;
+/// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
+/// objects:items count:16];
+/// if (limit) {
+/// unsigned long startMutations = *enumState.mutationsPtr;
+/// do {
+/// unsigned long counter = 0;
+/// do {
+/// if (startMutations != *enumState.mutationsPtr)
+/// objc_enumerationMutation(l_collection);
+/// elem = (type)enumState.itemsPtr[counter++];
+/// stmts;
+/// __continue_label: ;
+/// } while (counter < limit);
+/// } while (limit = [l_collection countByEnumeratingWithState:&enumState
+/// objects:items count:16]);
+/// elem = nil;
+/// __break_label: ;
+/// }
+/// else
+/// elem = nil;
+/// }
+///
+Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
+ SourceLocation OrigEnd) {
+ assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty");
+ assert(isa<ObjCForCollectionStmt>(Stmts.back()) &&
+ "ObjCForCollectionStmt Statement stack mismatch");
+ assert(!ObjCBcLabelNo.empty() &&
+ "ObjCForCollectionStmt - Label No stack empty");
+
+ SourceLocation startLoc = S->getLocStart();
+ const char *startBuf = SM->getCharacterData(startLoc);
+ const char *elementName;
+ std::string elementTypeAsString;
+ std::string buf;
+ buf = "\n{\n\t";
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(S->getElement())) {
+ // type elem;
+ NamedDecl* D = cast<NamedDecl>(DS->getSingleDecl());
+ QualType ElementType = cast<ValueDecl>(D)->getType();
+ elementTypeAsString = ElementType.getAsString();
+ buf += elementTypeAsString;
+ buf += " ";
+ elementName = D->getNameAsCString();
+ buf += elementName;
+ buf += ";\n\t";
+ }
+ else {
+ DeclRefExpr *DR = cast<DeclRefExpr>(S->getElement());
+ elementName = DR->getDecl()->getNameAsCString();
+ elementTypeAsString
+ = cast<ValueDecl>(DR->getDecl())->getType().getAsString();
+ }
+
+ // struct __objcFastEnumerationState enumState = { 0 };
+ buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t";
+ // id items[16];
+ buf += "id items[16];\n\t";
+ // id l_collection = (id)
+ buf += "id l_collection = (id)";
+ // Find start location of 'collection' the hard way!
+ const char *startCollectionBuf = startBuf;
+ startCollectionBuf += 3; // skip 'for'
+ startCollectionBuf = strchr(startCollectionBuf, '(');
+ startCollectionBuf++; // skip '('
+ // find 'in' and skip it.
+ while (*startCollectionBuf != ' ' ||
+ *(startCollectionBuf+1) != 'i' || *(startCollectionBuf+2) != 'n' ||
+ (*(startCollectionBuf+3) != ' ' &&
+ *(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '('))
+ startCollectionBuf++;
+ startCollectionBuf += 3;
+
+ // Replace: "for (type element in" with string constructed thus far.
+ ReplaceText(startLoc, startCollectionBuf - startBuf,
+ buf.c_str(), buf.size());
+ // Replace ')' in for '(' type elem in collection ')' with ';'
+ SourceLocation rightParenLoc = S->getRParenLoc();
+ const char *rparenBuf = SM->getCharacterData(rightParenLoc);
+ SourceLocation lparenLoc = startLoc.getFileLocWithOffset(rparenBuf-startBuf);
+ buf = ";\n\t";
+
+ // unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
+ // objects:items count:16];
+ // which is synthesized into:
+ // unsigned int limit =
+ // ((unsigned int (*)
+ // (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
+ // (void *)objc_msgSend)((id)l_collection,
+ // sel_registerName(
+ // "countByEnumeratingWithState:objects:count:"),
+ // (struct __objcFastEnumerationState *)&state,
+ // (id *)items, (unsigned int)16);
+ buf += "unsigned long limit =\n\t\t";
+ SynthCountByEnumWithState(buf);
+ buf += ";\n\t";
+ /// if (limit) {
+ /// unsigned long startMutations = *enumState.mutationsPtr;
+ /// do {
+ /// unsigned long counter = 0;
+ /// do {
+ /// if (startMutations != *enumState.mutationsPtr)
+ /// objc_enumerationMutation(l_collection);
+ /// elem = (type)enumState.itemsPtr[counter++];
+ buf += "if (limit) {\n\t";
+ buf += "unsigned long startMutations = *enumState.mutationsPtr;\n\t";
+ buf += "do {\n\t\t";
+ buf += "unsigned long counter = 0;\n\t\t";
+ buf += "do {\n\t\t\t";
+ buf += "if (startMutations != *enumState.mutationsPtr)\n\t\t\t\t";
+ buf += "objc_enumerationMutation(l_collection);\n\t\t\t";
+ buf += elementName;
+ buf += " = (";
+ buf += elementTypeAsString;
+ buf += ")enumState.itemsPtr[counter++];";
+ // Replace ')' in for '(' type elem in collection ')' with all of these.
+ ReplaceText(lparenLoc, 1, buf.c_str(), buf.size());
+
+ /// __continue_label: ;
+ /// } while (counter < limit);
+ /// } while (limit = [l_collection countByEnumeratingWithState:&enumState
+ /// objects:items count:16]);
+ /// elem = nil;
+ /// __break_label: ;
+ /// }
+ /// else
+ /// elem = nil;
+ /// }
+ ///
+ buf = ";\n\t";
+ buf += "__continue_label_";
+ buf += utostr(ObjCBcLabelNo.back());
+ buf += ": ;";
+ buf += "\n\t\t";
+ buf += "} while (counter < limit);\n\t";
+ buf += "} while (limit = ";
+ SynthCountByEnumWithState(buf);
+ buf += ");\n\t";
+ buf += elementName;
+ buf += " = ((id)0);\n\t";
+ buf += "__break_label_";
+ buf += utostr(ObjCBcLabelNo.back());
+ buf += ": ;\n\t";
+ buf += "}\n\t";
+ buf += "else\n\t\t";
+ buf += elementName;
+ buf += " = ((id)0);\n";
+ buf += "}\n";
+
+ // 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);
+ InsertText(endBodyLoc, buf.c_str(), buf.size());
+ } else {
+ /* Need to treat single statements specially. For example:
+ *
+ * for (A *a in b) if (stuff()) break;
+ * for (A *a in b) xxxyy;
+ *
+ * The following code simply scans ahead to the semi to find the actual end.
+ */
+ const char *stmtBuf = SM->getCharacterData(OrigEnd);
+ const char *semiBuf = strchr(stmtBuf, ';');
+ assert(semiBuf && "Can't find ';'");
+ SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(semiBuf-stmtBuf+1);
+ InsertText(endBodyLoc, buf.c_str(), buf.size());
+ }
+ Stmts.pop_back();
+ ObjCBcLabelNo.pop_back();
+ return 0;
+}
+
+/// RewriteObjCSynchronizedStmt -
+/// This routine rewrites @synchronized(expr) stmt;
+/// into:
+/// objc_sync_enter(expr);
+/// @try stmt @finally { objc_sync_exit(expr); }
+///
+Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
+ // Get the start location and compute the semi location.
+ SourceLocation startLoc = S->getLocStart();
+ const char *startBuf = SM->getCharacterData(startLoc);
+
+ assert((*startBuf == '@') && "bogus @synchronized location");
+
+ std::string buf;
+ buf = "objc_sync_enter((id)";
+ const char *lparenBuf = startBuf;
+ while (*lparenBuf != '(') lparenBuf++;
+ ReplaceText(startLoc, lparenBuf-startBuf+1, buf.c_str(), buf.size());
+ // We can't use S->getSynchExpr()->getLocEnd() to find the end location, since
+ // the sync expression is typically a message expression that's already
+ // been rewritten! (which implies the SourceLocation's are invalid).
+ SourceLocation endLoc = S->getSynchBody()->getLocStart();
+ const char *endBuf = SM->getCharacterData(endLoc);
+ while (*endBuf != ')') endBuf--;
+ SourceLocation rparenLoc = startLoc.getFileLocWithOffset(endBuf-startBuf);
+ buf = ");\n";
+ // declare a new scope with two variables, _stack and _rethrow.
+ buf += "/* @try scope begin */ \n{ struct _objc_exception_data {\n";
+ buf += "int buf[18/*32-bit i386*/];\n";
+ buf += "char *pointers[4];} _stack;\n";
+ buf += "id volatile _rethrow = 0;\n";
+ buf += "objc_exception_try_enter(&_stack);\n";
+ buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
+ ReplaceText(rparenLoc, 1, buf.c_str(), buf.size());
+ startLoc = S->getSynchBody()->getLocEnd();
+ startBuf = SM->getCharacterData(startLoc);
+
+ assert((*startBuf == '}') && "bogus @synchronized block");
+ SourceLocation lastCurlyLoc = startLoc;
+ buf = "}\nelse {\n";
+ buf += " _rethrow = objc_exception_extract(&_stack);\n";
+ buf += "}\n";
+ buf += "{ /* implicit finally clause */\n";
+ buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
+ buf += " objc_sync_exit(";
+ Expr *syncExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ S->getSynchExpr(),
+ Context->getObjCIdType(),
+ SourceLocation(),
+ SourceLocation());
+ std::string syncExprBufS;
+ llvm::raw_string_ostream syncExprBuf(syncExprBufS);
+ syncExpr->printPretty(syncExprBuf, *Context);
+ buf += syncExprBuf.str();
+ buf += ");\n";
+ buf += " if (_rethrow) objc_exception_throw(_rethrow);\n";
+ buf += "}\n";
+ buf += "}";
+
+ ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
+ return 0;
+}
+
+void RewriteObjC::WarnAboutReturnGotoContinueOrBreakStmts(Stmt *S) {
+ // Perform a bottom up traversal of all children.
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++CI)
+ if (*CI)
+ WarnAboutReturnGotoContinueOrBreakStmts(*CI);
+
+ if (isa<ReturnStmt>(S) || isa<ContinueStmt>(S) ||
+ isa<BreakStmt>(S) || isa<GotoStmt>(S)) {
+ Diags.Report(Context->getFullLoc(S->getLocStart()),
+ TryFinallyContainsReturnDiag);
+ }
+ return;
+}
+
+Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
+ // Get the start location and compute the semi location.
+ SourceLocation startLoc = S->getLocStart();
+ const char *startBuf = SM->getCharacterData(startLoc);
+
+ assert((*startBuf == '@') && "bogus @try location");
+
+ std::string buf;
+ // declare a new scope with two variables, _stack and _rethrow.
+ buf = "/* @try scope begin */ { struct _objc_exception_data {\n";
+ buf += "int buf[18/*32-bit i386*/];\n";
+ buf += "char *pointers[4];} _stack;\n";
+ buf += "id volatile _rethrow = 0;\n";
+ buf += "objc_exception_try_enter(&_stack);\n";
+ buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
+
+ ReplaceText(startLoc, 4, buf.c_str(), buf.size());
+
+ startLoc = S->getTryBody()->getLocEnd();
+ startBuf = SM->getCharacterData(startLoc);
+
+ assert((*startBuf == '}') && "bogus @try block");
+
+ SourceLocation lastCurlyLoc = startLoc;
+ ObjCAtCatchStmt *catchList = S->getCatchStmts();
+ if (catchList) {
+ startLoc = startLoc.getFileLocWithOffset(1);
+ buf = " /* @catch begin */ else {\n";
+ buf += " id _caught = objc_exception_extract(&_stack);\n";
+ buf += " objc_exception_try_enter (&_stack);\n";
+ buf += " if (_setjmp(_stack.buf))\n";
+ buf += " _rethrow = objc_exception_extract(&_stack);\n";
+ buf += " else { /* @catch continue */";
+
+ InsertText(startLoc, buf.c_str(), buf.size());
+ } else { /* no catch list */
+ buf = "}\nelse {\n";
+ buf += " _rethrow = objc_exception_extract(&_stack);\n";
+ buf += "}";
+ ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
+ }
+ bool sawIdTypedCatch = false;
+ Stmt *lastCatchBody = 0;
+ while (catchList) {
+ ParmVarDecl *catchDecl = catchList->getCatchParamDecl();
+
+ if (catchList == S->getCatchStmts())
+ buf = "if ("; // we are generating code for the first catch clause
+ else
+ buf = "else if (";
+ startLoc = catchList->getLocStart();
+ startBuf = SM->getCharacterData(startLoc);
+
+ assert((*startBuf == '@') && "bogus @catch location");
+
+ const char *lParenLoc = strchr(startBuf, '(');
+
+ if (catchList->hasEllipsis()) {
+ // Now rewrite the body...
+ lastCatchBody = catchList->getCatchBody();
+ SourceLocation bodyLoc = lastCatchBody->getLocStart();
+ const char *bodyBuf = SM->getCharacterData(bodyLoc);
+ assert(*SM->getCharacterData(catchList->getRParenLoc()) == ')' &&
+ "bogus @catch paren location");
+ assert((*bodyBuf == '{') && "bogus @catch body location");
+
+ buf += "1) { id _tmp = _caught;";
+ Rewrite.ReplaceText(startLoc, bodyBuf-startBuf+1,
+ buf.c_str(), buf.size());
+ } else if (catchDecl) {
+ QualType t = catchDecl->getType();
+ if (t == Context->getObjCIdType()) {
+ buf += "1) { ";
+ ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size());
+ sawIdTypedCatch = true;
+ } else if (const PointerType *pType = t->getAsPointerType()) {
+ ObjCInterfaceType *cls; // Should be a pointer to a class.
+
+ cls = dyn_cast<ObjCInterfaceType>(pType->getPointeeType().getTypePtr());
+ if (cls) {
+ buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";
+ buf += cls->getDecl()->getNameAsString();
+ buf += "\"), (struct objc_object *)_caught)) { ";
+ ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size());
+ }
+ }
+ // Now rewrite the body...
+ lastCatchBody = catchList->getCatchBody();
+ SourceLocation rParenLoc = catchList->getRParenLoc();
+ SourceLocation bodyLoc = lastCatchBody->getLocStart();
+ const char *bodyBuf = SM->getCharacterData(bodyLoc);
+ const char *rParenBuf = SM->getCharacterData(rParenLoc);
+ assert((*rParenBuf == ')') && "bogus @catch paren location");
+ assert((*bodyBuf == '{') && "bogus @catch body location");
+
+ buf = " = _caught;";
+ // Here we replace ") {" with "= _caught;" (which initializes and
+ // declares the @catch parameter).
+ ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, buf.c_str(), buf.size());
+ } else {
+ assert(false && "@catch rewrite bug");
+ }
+ // make sure all the catch bodies get rewritten!
+ catchList = catchList->getNextCatchStmt();
+ }
+ // Complete the catch list...
+ if (lastCatchBody) {
+ SourceLocation bodyLoc = lastCatchBody->getLocEnd();
+ assert(*SM->getCharacterData(bodyLoc) == '}' &&
+ "bogus @catch body location");
+
+ // Insert the last (implicit) else clause *before* the right curly brace.
+ bodyLoc = bodyLoc.getFileLocWithOffset(-1);
+ buf = "} /* last catch end */\n";
+ buf += "else {\n";
+ buf += " _rethrow = _caught;\n";
+ buf += " objc_exception_try_exit(&_stack);\n";
+ buf += "} } /* @catch end */\n";
+ if (!S->getFinallyStmt())
+ buf += "}\n";
+ InsertText(bodyLoc, buf.c_str(), buf.size());
+
+ // Set lastCurlyLoc
+ lastCurlyLoc = lastCatchBody->getLocEnd();
+ }
+ if (ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt()) {
+ startLoc = finalStmt->getLocStart();
+ startBuf = SM->getCharacterData(startLoc);
+ assert((*startBuf == '@') && "bogus @finally start");
+
+ buf = "/* @finally */";
+ ReplaceText(startLoc, 8, buf.c_str(), buf.size());
+
+ Stmt *body = finalStmt->getFinallyBody();
+ SourceLocation startLoc = body->getLocStart();
+ SourceLocation endLoc = body->getLocEnd();
+ assert(*SM->getCharacterData(startLoc) == '{' &&
+ "bogus @finally body location");
+ assert(*SM->getCharacterData(endLoc) == '}' &&
+ "bogus @finally body location");
+
+ startLoc = startLoc.getFileLocWithOffset(1);
+ buf = " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
+ InsertText(startLoc, buf.c_str(), buf.size());
+ endLoc = endLoc.getFileLocWithOffset(-1);
+ buf = " if (_rethrow) objc_exception_throw(_rethrow);\n";
+ InsertText(endLoc, buf.c_str(), buf.size());
+
+ // Set lastCurlyLoc
+ lastCurlyLoc = body->getLocEnd();
+
+ // Now check for any return/continue/go statements within the @try.
+ WarnAboutReturnGotoContinueOrBreakStmts(S->getTryBody());
+ } else { /* no finally clause - make sure we synthesize an implicit one */
+ buf = "{ /* implicit finally clause */\n";
+ buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
+ buf += " if (_rethrow) objc_exception_throw(_rethrow);\n";
+ buf += "}";
+ ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
+ }
+ // Now emit the final closing curly brace...
+ lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1);
+ buf = " } /* @try scope end */\n";
+ InsertText(lastCurlyLoc, buf.c_str(), buf.size());
+ return 0;
+}
+
+Stmt *RewriteObjC::RewriteObjCCatchStmt(ObjCAtCatchStmt *S) {
+ return 0;
+}
+
+Stmt *RewriteObjC::RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S) {
+ return 0;
+}
+
+// This can't be done with ReplaceStmt(S, ThrowExpr), since
+// the throw expression is typically a message expression that's already
+// been rewritten! (which implies the SourceLocation's are invalid).
+Stmt *RewriteObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) {
+ // Get the start location and compute the semi location.
+ SourceLocation startLoc = S->getLocStart();
+ const char *startBuf = SM->getCharacterData(startLoc);
+
+ assert((*startBuf == '@') && "bogus @throw location");
+
+ std::string buf;
+ /* void objc_exception_throw(id) __attribute__((noreturn)); */
+ if (S->getThrowExpr())
+ buf = "objc_exception_throw(";
+ else // add an implicit argument
+ buf = "objc_exception_throw(_caught";
+
+ // handle "@ throw" correctly.
+ const char *wBuf = strchr(startBuf, 'w');
+ assert((*wBuf == 'w') && "@throw: can't find 'w'");
+ ReplaceText(startLoc, wBuf-startBuf+1, buf.c_str(), buf.size());
+
+ const char *semiBuf = strchr(startBuf, ';');
+ assert((*semiBuf == ';') && "@throw: can't find ';'");
+ SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf);
+ buf = ");";
+ ReplaceText(semiLoc, 1, buf.c_str(), buf.size());
+ return 0;
+}
+
+Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) {
+ // Create a new string expression.
+ QualType StrType = Context->getPointerType(Context->CharTy);
+ std::string StrEncoding;
+ Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding);
+ Expr *Replacement = StringLiteral::Create(*Context,StrEncoding.c_str(),
+ StrEncoding.length(), false,StrType,
+ SourceLocation());
+ ReplaceStmt(Exp, Replacement);
+
+ // Replace this subexpr in the parent.
+ // delete Exp; leak for now, see RewritePropertySetter() usage for more info.
+ return Replacement;
+}
+
+Stmt *RewriteObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) {
+ if (!SelGetUidFunctionDecl)
+ SynthSelGetUidFunctionDecl();
+ assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
+ // Create a call to sel_registerName("selName").
+ llvm::SmallVector<Expr*, 8> SelExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ SelExprs.push_back(StringLiteral::Create(*Context,
+ Exp->getSelector().getAsString().c_str(),
+ Exp->getSelector().getAsString().size(),
+ false, argType, SourceLocation()));
+ CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
+ &SelExprs[0], SelExprs.size());
+ ReplaceStmt(Exp, SelExp);
+ // delete Exp; leak for now, see RewritePropertySetter() usage for more info.
+ return SelExp;
+}
+
+CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl(
+ FunctionDecl *FD, Expr **args, unsigned nargs) {
+ // Get the type, we will need to reference it in a couple spots.
+ QualType msgSendType = FD->getType();
+
+ // Create a reference to the objc_msgSend() declaration.
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, msgSendType, SourceLocation());
+
+ // Now, we cast the reference to a pointer to the objc_msgSend type.
+ QualType pToFunc = Context->getPointerType(msgSendType);
+ ImplicitCastExpr *ICE = new (Context) ImplicitCastExpr(pToFunc, DRE,
+ /*isLvalue=*/false);
+
+ const FunctionType *FT = msgSendType->getAsFunctionType();
+
+ return new (Context) CallExpr(*Context, ICE, args, nargs, FT->getResultType(),
+ SourceLocation());
+}
+
+static bool scanForProtocolRefs(const char *startBuf, const char *endBuf,
+ const char *&startRef, const char *&endRef) {
+ while (startBuf < endBuf) {
+ if (*startBuf == '<')
+ startRef = startBuf; // mark the start.
+ if (*startBuf == '>') {
+ if (startRef && *startRef == '<') {
+ endRef = startBuf; // mark the end.
+ return true;
+ }
+ return false;
+ }
+ startBuf++;
+ }
+ return false;
+}
+
+static void scanToNextArgument(const char *&argRef) {
+ int angle = 0;
+ while (*argRef != ')' && (*argRef != ',' || angle > 0)) {
+ if (*argRef == '<')
+ angle++;
+ else if (*argRef == '>')
+ angle--;
+ argRef++;
+ }
+ assert(angle == 0 && "scanToNextArgument - bad protocol type syntax");
+}
+
+bool RewriteObjC::needToScanForQualifiers(QualType T) {
+
+ if (T->isObjCQualifiedIdType())
+ return true;
+
+ if (const PointerType *pType = T->getAsPointerType()) {
+ Type *pointeeType = pType->getPointeeType().getTypePtr();
+ if (isa<ObjCQualifiedInterfaceType>(pointeeType))
+ return true; // we have "Class <Protocol> *".
+ }
+ return false;
+}
+
+void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) {
+ QualType Type = E->getType();
+ if (needToScanForQualifiers(Type)) {
+ SourceLocation Loc, EndLoc;
+
+ if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E)) {
+ Loc = ECE->getLParenLoc();
+ EndLoc = ECE->getRParenLoc();
+ } else {
+ Loc = E->getLocStart();
+ EndLoc = E->getLocEnd();
+ }
+ // This will defend against trying to rewrite synthesized expressions.
+ if (Loc.isInvalid() || EndLoc.isInvalid())
+ return;
+
+ const char *startBuf = SM->getCharacterData(Loc);
+ const char *endBuf = SM->getCharacterData(EndLoc);
+ const char *startRef = 0, *endRef = 0;
+ if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
+ // Get the locations of the startRef, endRef.
+ SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-startBuf);
+ SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-startBuf+1);
+ // Comment out the protocol references.
+ InsertText(LessLoc, "/*", 2);
+ InsertText(GreaterLoc, "*/", 2);
+ }
+ }
+}
+
+void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
+ SourceLocation Loc;
+ QualType Type;
+ const FunctionProtoType *proto = 0;
+ if (VarDecl *VD = dyn_cast<VarDecl>(Dcl)) {
+ Loc = VD->getLocation();
+ Type = VD->getType();
+ }
+ else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Dcl)) {
+ Loc = FD->getLocation();
+ // Check for ObjC 'id' and class types that have been adorned with protocol
+ // information (id<p>, C<p>*). The protocol references need to be rewritten!
+ const FunctionType *funcType = FD->getType()->getAsFunctionType();
+ assert(funcType && "missing function type");
+ proto = dyn_cast<FunctionProtoType>(funcType);
+ if (!proto)
+ return;
+ Type = proto->getResultType();
+ }
+ else
+ return;
+
+ if (needToScanForQualifiers(Type)) {
+ // Since types are unique, we need to scan the buffer.
+
+ const char *endBuf = SM->getCharacterData(Loc);
+ const char *startBuf = endBuf;
+ while (*startBuf != ';' && *startBuf != '<' && startBuf != MainFileStart)
+ startBuf--; // scan backward (from the decl location) for return type.
+ const char *startRef = 0, *endRef = 0;
+ if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
+ // Get the locations of the startRef, endRef.
+ SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf);
+ SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1);
+ // Comment out the protocol references.
+ InsertText(LessLoc, "/*", 2);
+ InsertText(GreaterLoc, "*/", 2);
+ }
+ }
+ if (!proto)
+ return; // most likely, was a variable
+ // Now check arguments.
+ const char *startBuf = SM->getCharacterData(Loc);
+ const char *startFuncBuf = startBuf;
+ for (unsigned i = 0; i < proto->getNumArgs(); i++) {
+ if (needToScanForQualifiers(proto->getArgType(i))) {
+ // Since types are unique, we need to scan the buffer.
+
+ const char *endBuf = startBuf;
+ // scan forward (from the decl location) for argument types.
+ scanToNextArgument(endBuf);
+ const char *startRef = 0, *endRef = 0;
+ if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
+ // Get the locations of the startRef, endRef.
+ SourceLocation LessLoc =
+ Loc.getFileLocWithOffset(startRef-startFuncBuf);
+ SourceLocation GreaterLoc =
+ Loc.getFileLocWithOffset(endRef-startFuncBuf+1);
+ // Comment out the protocol references.
+ InsertText(LessLoc, "/*", 2);
+ InsertText(GreaterLoc, "*/", 2);
+ }
+ startBuf = ++endBuf;
+ }
+ else {
+ // If the function name is derived from a macro expansion, then the
+ // argument buffer will not follow the name. Need to speak with Chris.
+ while (*startBuf && *startBuf != ')' && *startBuf != ',')
+ startBuf++; // scan forward (from the decl location) for argument types.
+ startBuf++;
+ }
+ }
+}
+
+// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str);
+void RewriteObjC::SynthSelGetUidFunctionDecl() {
+ IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName");
+ llvm::SmallVector<QualType, 16> ArgTys;
+ ArgTys.push_back(Context->getPointerType(
+ Context->CharTy.getQualifiedType(QualType::Const)));
+ QualType getFuncType = Context->getFunctionType(Context->getObjCSelType(),
+ &ArgTys[0], ArgTys.size(),
+ false /*isVariadic*/, 0);
+ SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ SelGetUidIdent, getFuncType,
+ FunctionDecl::Extern, false);
+}
+
+void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) {
+ // declared in <objc/objc.h>
+ if (FD->getIdentifier() &&
+ strcmp(FD->getNameAsCString(), "sel_registerName") == 0) {
+ SelGetUidFunctionDecl = FD;
+ return;
+ }
+ RewriteObjCQualifiedInterfaceTypes(FD);
+}
+
+// SynthSuperContructorFunctionDecl - id objc_super(id obj, id super);
+void RewriteObjC::SynthSuperContructorFunctionDecl() {
+ if (SuperContructorFunctionDecl)
+ return;
+ IdentifierInfo *msgSendIdent = &Context->Idents.get("__rw_objc_super");
+ llvm::SmallVector<QualType, 16> ArgTys;
+ QualType argT = Context->getObjCIdType();
+ assert(!argT.isNull() && "Can't find 'id' type");
+ ArgTys.push_back(argT);
+ ArgTys.push_back(argT);
+ QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size(),
+ false, 0);
+ SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ FunctionDecl::Extern, false);
+}
+
+// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
+void RewriteObjC::SynthMsgSendFunctionDecl() {
+ IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend");
+ llvm::SmallVector<QualType, 16> ArgTys;
+ QualType argT = Context->getObjCIdType();
+ assert(!argT.isNull() && "Can't find 'id' type");
+ ArgTys.push_back(argT);
+ argT = Context->getObjCSelType();
+ assert(!argT.isNull() && "Can't find 'SEL' type");
+ ArgTys.push_back(argT);
+ QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size(),
+ true /*isVariadic*/, 0);
+ MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ FunctionDecl::Extern, false);
+}
+
+// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...);
+void RewriteObjC::SynthMsgSendSuperFunctionDecl() {
+ IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper");
+ llvm::SmallVector<QualType, 16> ArgTys;
+ RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ SourceLocation(),
+ &Context->Idents.get("objc_super"));
+ QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
+ assert(!argT.isNull() && "Can't build 'struct objc_super *' type");
+ ArgTys.push_back(argT);
+ argT = Context->getObjCSelType();
+ assert(!argT.isNull() && "Can't find 'SEL' type");
+ ArgTys.push_back(argT);
+ QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size(),
+ true /*isVariadic*/, 0);
+ MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ FunctionDecl::Extern, false);
+}
+
+// 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;
+ QualType argT = Context->getObjCIdType();
+ assert(!argT.isNull() && "Can't find 'id' type");
+ ArgTys.push_back(argT);
+ argT = Context->getObjCSelType();
+ assert(!argT.isNull() && "Can't find 'SEL' type");
+ ArgTys.push_back(argT);
+ QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size(),
+ true /*isVariadic*/, 0);
+ MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ FunctionDecl::Extern, false);
+}
+
+// SynthMsgSendSuperStretFunctionDecl -
+// id objc_msgSendSuper_stret(struct objc_super *, SEL op, ...);
+void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {
+ IdentifierInfo *msgSendIdent =
+ &Context->Idents.get("objc_msgSendSuper_stret");
+ llvm::SmallVector<QualType, 16> ArgTys;
+ RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ SourceLocation(),
+ &Context->Idents.get("objc_super"));
+ QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
+ assert(!argT.isNull() && "Can't build 'struct objc_super *' type");
+ ArgTys.push_back(argT);
+ argT = Context->getObjCSelType();
+ assert(!argT.isNull() && "Can't find 'SEL' type");
+ ArgTys.push_back(argT);
+ QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size(),
+ true /*isVariadic*/, 0);
+ MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ FunctionDecl::Extern, false);
+}
+
+// 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;
+ QualType argT = Context->getObjCIdType();
+ assert(!argT.isNull() && "Can't find 'id' type");
+ ArgTys.push_back(argT);
+ argT = Context->getObjCSelType();
+ assert(!argT.isNull() && "Can't find 'SEL' type");
+ ArgTys.push_back(argT);
+ QualType msgSendType = Context->getFunctionType(Context->DoubleTy,
+ &ArgTys[0], ArgTys.size(),
+ true /*isVariadic*/, 0);
+ MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ FunctionDecl::Extern, false);
+}
+
+// SynthGetClassFunctionDecl - id objc_getClass(const char *name);
+void RewriteObjC::SynthGetClassFunctionDecl() {
+ IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass");
+ llvm::SmallVector<QualType, 16> ArgTys;
+ ArgTys.push_back(Context->getPointerType(
+ Context->CharTy.getQualifiedType(QualType::Const)));
+ QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size(),
+ false /*isVariadic*/, 0);
+ GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ getClassIdent, getClassType,
+ FunctionDecl::Extern, false);
+}
+
+// SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name);
+void RewriteObjC::SynthGetMetaClassFunctionDecl() {
+ IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass");
+ llvm::SmallVector<QualType, 16> ArgTys;
+ ArgTys.push_back(Context->getPointerType(
+ Context->CharTy.getQualifiedType(QualType::Const)));
+ QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size(),
+ false /*isVariadic*/, 0);
+ GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ getClassIdent, getClassType,
+ FunctionDecl::Extern, false);
+}
+
+Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
+ QualType strType = getConstantStringStructType();
+
+ std::string S = "__NSConstantStringImpl_";
+
+ std::string tmpName = InFileName;
+ unsigned i;
+ for (i=0; i < tmpName.length(); i++) {
+ char c = tmpName.at(i);
+ // replace any non alphanumeric characters with '_'.
+ if (!isalpha(c) && (c < '0' || c > '9'))
+ tmpName[i] = '_';
+ }
+ S += tmpName;
+ S += "_";
+ S += utostr(NumObjCStringLiterals++);
+
+ Preamble += "static __NSConstantStringImpl " + S;
+ Preamble += " __attribute__ ((section (\"__DATA, __cfstring\"))) = {__CFConstantStringClassReference,";
+ Preamble += "0x000007c8,"; // utf8_str
+ // The pretty printer for StringLiteral handles escape characters properly.
+ std::string prettyBufS;
+ llvm::raw_string_ostream prettyBuf(prettyBufS);
+ Exp->getString()->printPretty(prettyBuf, *Context);
+ Preamble += prettyBuf.str();
+ Preamble += ",";
+ // The minus 2 removes the begin/end double quotes.
+ Preamble += utostr(prettyBuf.str().size()-2) + "};\n";
+
+ VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
+ &Context->Idents.get(S.c_str()), strType,
+ VarDecl::Static);
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, strType, SourceLocation());
+ Expr *Unop = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf,
+ Context->getPointerType(DRE->getType()),
+ SourceLocation());
+ // cast to NSConstantString *
+ CastExpr *cast = new (Context) CStyleCastExpr(Exp->getType(), Unop,
+ Exp->getType(), SourceLocation(), SourceLocation());
+ ReplaceStmt(Exp, cast);
+ // delete Exp; leak for now, see RewritePropertySetter() usage for more info.
+ return cast;
+}
+
+ObjCInterfaceDecl *RewriteObjC::isSuperReceiver(Expr *recExpr) {
+ // check if we are sending a message to 'super'
+ if (!CurMethodDef || !CurMethodDef->isInstanceMethod()) return 0;
+
+ if (ObjCSuperExpr *Super = dyn_cast<ObjCSuperExpr>(recExpr)) {
+ const PointerType *PT = Super->getType()->getAsPointerType();
+ assert(PT);
+ ObjCInterfaceType *IT = cast<ObjCInterfaceType>(PT->getPointeeType());
+ return IT->getDecl();
+ }
+ return 0;
+}
+
+// struct objc_super { struct objc_object *receiver; struct objc_class *super; };
+QualType RewriteObjC::getSuperStructType() {
+ if (!SuperStructDecl) {
+ SuperStructDecl = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ SourceLocation(),
+ &Context->Idents.get("objc_super"));
+ QualType FieldTypes[2];
+
+ // struct objc_object *receiver;
+ FieldTypes[0] = Context->getObjCIdType();
+ // struct objc_class *super;
+ FieldTypes[1] = Context->getObjCClassType();
+
+ // Create fields
+ for (unsigned i = 0; i < 2; ++i) {
+ SuperStructDecl->addDecl(*Context,
+ FieldDecl::Create(*Context, SuperStructDecl,
+ SourceLocation(), 0,
+ FieldTypes[i], /*BitWidth=*/0,
+ /*Mutable=*/false));
+ }
+
+ SuperStructDecl->completeDefinition(*Context);
+ }
+ return Context->getTagDeclType(SuperStructDecl);
+}
+
+QualType RewriteObjC::getConstantStringStructType() {
+ if (!ConstantStringDecl) {
+ ConstantStringDecl = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ SourceLocation(),
+ &Context->Idents.get("__NSConstantStringImpl"));
+ QualType FieldTypes[4];
+
+ // struct objc_object *receiver;
+ FieldTypes[0] = Context->getObjCIdType();
+ // int flags;
+ FieldTypes[1] = Context->IntTy;
+ // char *str;
+ FieldTypes[2] = Context->getPointerType(Context->CharTy);
+ // long length;
+ FieldTypes[3] = Context->LongTy;
+
+ // Create fields
+ for (unsigned i = 0; i < 4; ++i) {
+ ConstantStringDecl->addDecl(*Context,
+ FieldDecl::Create(*Context,
+ ConstantStringDecl,
+ SourceLocation(), 0,
+ FieldTypes[i],
+ /*BitWidth=*/0,
+ /*Mutable=*/true));
+ }
+
+ ConstantStringDecl->completeDefinition(*Context);
+ }
+ return Context->getTagDeclType(ConstantStringDecl);
+}
+
+Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
+ if (!SelGetUidFunctionDecl)
+ SynthSelGetUidFunctionDecl();
+ if (!MsgSendFunctionDecl)
+ SynthMsgSendFunctionDecl();
+ if (!MsgSendSuperFunctionDecl)
+ SynthMsgSendSuperFunctionDecl();
+ if (!MsgSendStretFunctionDecl)
+ SynthMsgSendStretFunctionDecl();
+ if (!MsgSendSuperStretFunctionDecl)
+ SynthMsgSendSuperStretFunctionDecl();
+ if (!MsgSendFpretFunctionDecl)
+ SynthMsgSendFpretFunctionDecl();
+ if (!GetClassFunctionDecl)
+ SynthGetClassFunctionDecl();
+ if (!GetMetaClassFunctionDecl)
+ SynthGetMetaClassFunctionDecl();
+
+ // default to objc_msgSend().
+ FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl;
+ // May need to use objc_msgSend_stret() as well.
+ FunctionDecl *MsgSendStretFlavor = 0;
+ if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) {
+ QualType resultType = mDecl->getResultType();
+ if (resultType->isStructureType() || resultType->isUnionType())
+ MsgSendStretFlavor = MsgSendStretFunctionDecl;
+ else if (resultType->isRealFloatingType())
+ MsgSendFlavor = MsgSendFpretFunctionDecl;
+ }
+
+ // Synthesize a call to objc_msgSend().
+ llvm::SmallVector<Expr*, 8> MsgExprs;
+ IdentifierInfo *clsName = Exp->getClassName();
+
+ // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
+ if (clsName) { // class message.
+ // FIXME: We need to fix Sema (and the AST for ObjCMessageExpr) to handle
+ // the 'super' idiom within a class method.
+ if (!strcmp(clsName->getName(), "super")) {
+ MsgSendFlavor = MsgSendSuperFunctionDecl;
+ if (MsgSendStretFlavor)
+ MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
+ assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
+
+ ObjCInterfaceDecl *SuperDecl =
+ CurMethodDef->getClassInterface()->getSuperClass();
+
+ llvm::SmallVector<Expr*, 4> InitExprs;
+
+ // set the receiver to self, the first argument to all methods.
+ InitExprs.push_back(
+ new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
+ Context->getObjCIdType(),
+ SourceLocation()),
+ Context->getObjCIdType(),
+ SourceLocation(), SourceLocation())); // set the 'receiver'.
+
+ llvm::SmallVector<Expr*, 8> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ SuperDecl->getIdentifier()->getName(),
+ SuperDecl->getIdentifier()->getLength(),
+ false, argType, SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size());
+ // To turn off a warning, type-cast to 'id'
+ InitExprs.push_back( // set 'super class', using objc_getClass().
+ new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ Cls, Context->getObjCIdType(),
+ SourceLocation(), SourceLocation()));
+ // struct objc_super
+ QualType superType = getSuperStructType();
+ Expr *SuperRep;
+
+ if (LangOpts.Microsoft) {
+ SynthSuperContructorFunctionDecl();
+ // Simulate a contructor call...
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
+ superType, SourceLocation());
+ SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
+ InitExprs.size(),
+ superType, SourceLocation());
+ // The code for super is a little tricky to prevent collision with
+ // the structure definition in the header. The rewriter has it's own
+ // internal definition (__rw_objc_super) that is uses. This is why
+ // we need the cast below. For example:
+ // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
+ //
+ SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
+ Context->getPointerType(SuperRep->getType()),
+ SourceLocation());
+ SuperRep = new (Context) CStyleCastExpr(Context->getPointerType(superType),
+ SuperRep, Context->getPointerType(superType),
+ SourceLocation(), SourceLocation());
+ } else {
+ // (struct objc_super) { <exprs from above> }
+ InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(),
+ &InitExprs[0], InitExprs.size(),
+ SourceLocation());
+ SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superType, ILE,
+ false);
+ // struct objc_super *
+ SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
+ Context->getPointerType(SuperRep->getType()),
+ SourceLocation());
+ }
+ MsgExprs.push_back(SuperRep);
+ } else {
+ llvm::SmallVector<Expr*, 8> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ clsName->getName(),
+ clsName->getLength(),
+ false, argType,
+ SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size());
+ MsgExprs.push_back(Cls);
+ }
+ } else { // instance message.
+ Expr *recExpr = Exp->getReceiver();
+
+ if (ObjCInterfaceDecl *SuperDecl = isSuperReceiver(recExpr)) {
+ MsgSendFlavor = MsgSendSuperFunctionDecl;
+ if (MsgSendStretFlavor)
+ MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
+ assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
+
+ llvm::SmallVector<Expr*, 4> InitExprs;
+
+ InitExprs.push_back(
+ new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
+ Context->getObjCIdType(),
+ SourceLocation()),
+ Context->getObjCIdType(),
+ SourceLocation(), SourceLocation())); // set the 'receiver'.
+
+ llvm::SmallVector<Expr*, 8> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ SuperDecl->getIdentifier()->getName(),
+ SuperDecl->getIdentifier()->getLength(),
+ false, argType, SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size());
+ // To turn off a warning, type-cast to 'id'
+ InitExprs.push_back(
+ // set 'super class', using objc_getClass().
+ new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ Cls, Context->getObjCIdType(), SourceLocation(), SourceLocation()));
+ // struct objc_super
+ QualType superType = getSuperStructType();
+ Expr *SuperRep;
+
+ if (LangOpts.Microsoft) {
+ SynthSuperContructorFunctionDecl();
+ // Simulate a contructor call...
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
+ superType, SourceLocation());
+ SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
+ InitExprs.size(),
+ superType, SourceLocation());
+ // The code for super is a little tricky to prevent collision with
+ // the structure definition in the header. The rewriter has it's own
+ // internal definition (__rw_objc_super) that is uses. This is why
+ // we need the cast below. For example:
+ // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
+ //
+ SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
+ Context->getPointerType(SuperRep->getType()),
+ SourceLocation());
+ SuperRep = new (Context) CStyleCastExpr(Context->getPointerType(superType),
+ SuperRep, Context->getPointerType(superType),
+ SourceLocation(), SourceLocation());
+ } else {
+ // (struct objc_super) { <exprs from above> }
+ InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(),
+ &InitExprs[0], InitExprs.size(),
+ SourceLocation());
+ SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superType, ILE, false);
+ }
+ MsgExprs.push_back(SuperRep);
+ } else {
+ // Remove all type-casts because it may contain objc-style types; e.g.
+ // Foo<Proto> *.
+ while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr))
+ recExpr = CE->getSubExpr();
+ recExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(), recExpr,
+ Context->getObjCIdType(),
+ SourceLocation(), SourceLocation());
+ MsgExprs.push_back(recExpr);
+ }
+ }
+ // Create a call to sel_registerName("selName"), it will be the 2nd argument.
+ llvm::SmallVector<Expr*, 8> SelExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ SelExprs.push_back(StringLiteral::Create(*Context,
+ Exp->getSelector().getAsString().c_str(),
+ Exp->getSelector().getAsString().size(),
+ false, argType, SourceLocation()));
+ CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
+ &SelExprs[0], SelExprs.size());
+ MsgExprs.push_back(SelExp);
+
+ // Now push any user supplied arguments.
+ for (unsigned i = 0; i < Exp->getNumArgs(); i++) {
+ Expr *userExpr = Exp->getArg(i);
+ // Make all implicit casts explicit...ICE comes in handy:-)
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) {
+ // Reuse the ICE type, it is exactly what the doctor ordered.
+ QualType type = ICE->getType()->isObjCQualifiedIdType()
+ ? Context->getObjCIdType()
+ : ICE->getType();
+ userExpr = new (Context) CStyleCastExpr(type, userExpr, type, SourceLocation(), SourceLocation());
+ }
+ // 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();
+ userExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ userExpr, Context->getObjCIdType(),
+ SourceLocation(), SourceLocation());
+ }
+ }
+ MsgExprs.push_back(userExpr);
+ // We've transferred the ownership to MsgExprs. For now, we *don't* null
+ // out the argument in the original expression (since we aren't deleting
+ // the ObjCMessageExpr). See RewritePropertySetter() usage for more info.
+ //Exp->setArg(i, 0);
+ }
+ // Generate the funky cast.
+ CastExpr *cast;
+ llvm::SmallVector<QualType, 8> ArgTypes;
+ QualType returnType;
+
+ // Push 'id' and 'SEL', the 2 implicit arguments.
+ if (MsgSendFlavor == MsgSendSuperFunctionDecl)
+ ArgTypes.push_back(Context->getPointerType(getSuperStructType()));
+ else
+ ArgTypes.push_back(Context->getObjCIdType());
+ ArgTypes.push_back(Context->getObjCSelType());
+ if (ObjCMethodDecl *OMD = Exp->getMethodDecl()) {
+ // Push any user argument types.
+ for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
+ E = OMD->param_end(); PI != E; ++PI) {
+ QualType t = (*PI)->getType()->isObjCQualifiedIdType()
+ ? Context->getObjCIdType()
+ : (*PI)->getType();
+ // Make sure we convert "t (^)(...)" to "t (*)(...)".
+ if (isTopLevelBlockPointerType(t)) {
+ const BlockPointerType *BPT = t->getAsBlockPointerType();
+ t = Context->getPointerType(BPT->getPointeeType());
+ }
+ ArgTypes.push_back(t);
+ }
+ returnType = OMD->getResultType()->isObjCQualifiedIdType()
+ ? Context->getObjCIdType() : OMD->getResultType();
+ } else {
+ returnType = Context->getObjCIdType();
+ }
+ // Get the type, we will need to reference it in a couple spots.
+ QualType msgSendType = MsgSendFlavor->getType();
+
+ // Create a reference to the objc_msgSend() declaration.
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, msgSendType,
+ SourceLocation());
+
+ // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid).
+ // If we don't do this cast, we get the following bizarre warning/note:
+ // xx.m:13: warning: function called through a non-compatible type
+ // xx.m:13: note: if this code is reached, the program will abort
+ cast = new (Context) CStyleCastExpr(Context->getPointerType(Context->VoidTy), DRE,
+ Context->getPointerType(Context->VoidTy),
+ SourceLocation(), SourceLocation());
+
+ // Now do the "normal" pointer to function cast.
+ QualType castType = Context->getFunctionType(returnType,
+ &ArgTypes[0], ArgTypes.size(),
+ // If we don't have a method decl, force a variadic cast.
+ Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true, 0);
+ castType = Context->getPointerType(castType);
+ cast = new (Context) CStyleCastExpr(castType, cast, castType, SourceLocation(), SourceLocation());
+
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast);
+
+ const FunctionType *FT = msgSendType->getAsFunctionType();
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
+ MsgExprs.size(),
+ FT->getResultType(), SourceLocation());
+ Stmt *ReplacingStmt = CE;
+ if (MsgSendStretFlavor) {
+ // We have the method which returns a struct/union. Must also generate
+ // call to objc_msgSend_stret and hang both varieties on a conditional
+ // expression which dictate which one to envoke depending on size of
+ // method's return type.
+
+ // Create a reference to the objc_msgSend_stret() declaration.
+ DeclRefExpr *STDRE = new (Context) DeclRefExpr(MsgSendStretFlavor, msgSendType,
+ SourceLocation());
+ // Need to cast objc_msgSend_stret to "void *" (see above comment).
+ cast = new (Context) CStyleCastExpr(Context->getPointerType(Context->VoidTy), STDRE,
+ Context->getPointerType(Context->VoidTy),
+ SourceLocation(), SourceLocation());
+ // Now do the "normal" pointer to function cast.
+ castType = Context->getFunctionType(returnType,
+ &ArgTypes[0], ArgTypes.size(),
+ Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false, 0);
+ castType = Context->getPointerType(castType);
+ cast = new (Context) CStyleCastExpr(castType, cast, castType, SourceLocation(), SourceLocation());
+
+ // Don't forget the parens to enforce the proper binding.
+ PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast);
+
+ FT = msgSendType->getAsFunctionType();
+ CallExpr *STCE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
+ MsgExprs.size(),
+ FT->getResultType(), SourceLocation());
+
+ // Build sizeof(returnType)
+ SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true,
+ returnType,
+ Context->getSizeType(),
+ SourceLocation(), SourceLocation());
+ // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
+ // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases.
+ // For X86 it is more complicated and some kind of target specific routine
+ // is needed to decide what to do.
+ unsigned IntSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
+ IntegerLiteral *limit = new (Context) IntegerLiteral(llvm::APInt(IntSize, 8),
+ Context->IntTy,
+ SourceLocation());
+ BinaryOperator *lessThanExpr = new (Context) BinaryOperator(sizeofExpr, limit,
+ BinaryOperator::LE,
+ Context->IntTy,
+ SourceLocation());
+ // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
+ ConditionalOperator *CondExpr =
+ new (Context) ConditionalOperator(lessThanExpr, CE, STCE, returnType);
+ ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(), CondExpr);
+ }
+ // delete Exp; leak for now, see RewritePropertySetter() usage for more info.
+ return ReplacingStmt;
+}
+
+Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) {
+ Stmt *ReplacingStmt = SynthMessageExpr(Exp);
+
+ // Now do the actual rewrite.
+ ReplaceStmt(Exp, ReplacingStmt);
+
+ // delete Exp; leak for now, see RewritePropertySetter() usage for more info.
+ return ReplacingStmt;
+}
+
+// typedef struct objc_object Protocol;
+QualType RewriteObjC::getProtocolType() {
+ if (!ProtocolTypeDecl) {
+ ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ &Context->Idents.get("Protocol"),
+ Context->getObjCIdType());
+ }
+ return Context->getTypeDeclType(ProtocolTypeDecl);
+}
+
+/// RewriteObjCProtocolExpr - Rewrite a protocol expression into
+/// a synthesized/forward data reference (to the protocol's metadata).
+/// The forward references (and metadata) are generated in
+/// RewriteObjC::HandleTranslationUnit().
+Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
+ std::string Name = "_OBJC_PROTOCOL_" + Exp->getProtocol()->getNameAsString();
+ IdentifierInfo *ID = &Context->Idents.get(Name);
+ VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
+ ID, QualType()/*UNUSED*/, VarDecl::Extern);
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, getProtocolType(), SourceLocation());
+ Expr *DerefExpr = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf,
+ Context->getPointerType(DRE->getType()),
+ SourceLocation());
+ CastExpr *castExpr = new (Context) CStyleCastExpr(DerefExpr->getType(), DerefExpr,
+ DerefExpr->getType(),
+ SourceLocation(), SourceLocation());
+ ReplaceStmt(Exp, castExpr);
+ ProtocolExprDecls.insert(Exp->getProtocol());
+ // delete Exp; leak for now, see RewritePropertySetter() usage for more info.
+ return castExpr;
+
+}
+
+bool RewriteObjC::BufferContainsPPDirectives(const char *startBuf,
+ const char *endBuf) {
+ while (startBuf < endBuf) {
+ if (*startBuf == '#') {
+ // Skip whitespace.
+ for (++startBuf; startBuf[0] == ' ' || startBuf[0] == '\t'; ++startBuf)
+ ;
+ if (!strncmp(startBuf, "if", strlen("if")) ||
+ !strncmp(startBuf, "ifdef", strlen("ifdef")) ||
+ !strncmp(startBuf, "ifndef", strlen("ifndef")) ||
+ !strncmp(startBuf, "define", strlen("define")) ||
+ !strncmp(startBuf, "undef", strlen("undef")) ||
+ !strncmp(startBuf, "else", strlen("else")) ||
+ !strncmp(startBuf, "elif", strlen("elif")) ||
+ !strncmp(startBuf, "endif", strlen("endif")) ||
+ !strncmp(startBuf, "pragma", strlen("pragma")) ||
+ !strncmp(startBuf, "include", strlen("include")) ||
+ !strncmp(startBuf, "import", strlen("import")) ||
+ !strncmp(startBuf, "include_next", strlen("include_next")))
+ return true;
+ }
+ startBuf++;
+ }
+ return false;
+}
+
+/// SynthesizeObjCInternalStruct - Rewrite one internal struct corresponding to
+/// an objective-c class with ivars.
+void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
+ std::string &Result) {
+ assert(CDecl && "Class missing in SynthesizeObjCInternalStruct");
+ assert(CDecl->getNameAsCString() &&
+ "Name missing in SynthesizeObjCInternalStruct");
+ // Do not synthesize more than once.
+ if (ObjCSynthesizedStructs.count(CDecl))
+ return;
+ ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass();
+ int NumIvars = CDecl->ivar_size();
+ SourceLocation LocStart = CDecl->getLocStart();
+ SourceLocation LocEnd = CDecl->getLocEnd();
+
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+
+ // If no ivars and no root or if its root, directly or indirectly,
+ // have no ivars (thus not synthesized) then no need to synthesize this class.
+ if ((CDecl->isForwardDecl() || NumIvars == 0) &&
+ (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) {
+ endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
+ ReplaceText(LocStart, endBuf-startBuf, Result.c_str(), Result.size());
+ return;
+ }
+
+ // FIXME: This has potential of causing problem. If
+ // SynthesizeObjCInternalStruct is ever called recursively.
+ Result += "\nstruct ";
+ Result += CDecl->getNameAsString();
+ if (LangOpts.Microsoft)
+ Result += "_IMPL";
+
+ if (NumIvars > 0) {
+ const char *cursor = strchr(startBuf, '{');
+ assert((cursor && endBuf)
+ && "SynthesizeObjCInternalStruct - malformed @interface");
+ // If the buffer contains preprocessor directives, we do more fine-grained
+ // rewrites. This is intended to fix code that looks like (which occurs in
+ // NSURL.h, for example):
+ //
+ // #ifdef XYZ
+ // @interface Foo : NSObject
+ // #else
+ // @interface FooBar : NSObject
+ // #endif
+ // {
+ // int i;
+ // }
+ // @end
+ //
+ // This clause is segregated to avoid breaking the common case.
+ if (BufferContainsPPDirectives(startBuf, cursor)) {
+ SourceLocation L = RCDecl ? CDecl->getSuperClassLoc() :
+ CDecl->getClassLoc();
+ const char *endHeader = SM->getCharacterData(L);
+ endHeader += Lexer::MeasureTokenLength(L, *SM, LangOpts);
+
+ if (CDecl->protocol_begin() != CDecl->protocol_end()) {
+ // advance to the end of the referenced protocols.
+ while (endHeader < cursor && *endHeader != '>') endHeader++;
+ endHeader++;
+ }
+ // rewrite the original header
+ ReplaceText(LocStart, endHeader-startBuf, Result.c_str(), Result.size());
+ } else {
+ // rewrite the original header *without* disturbing the '{'
+ ReplaceText(LocStart, cursor-startBuf-1, Result.c_str(), Result.size());
+ }
+ if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) {
+ Result = "\n struct ";
+ Result += RCDecl->getNameAsString();
+ Result += "_IMPL ";
+ Result += RCDecl->getNameAsString();
+ Result += "_IVARS;\n";
+
+ // insert the super class structure definition.
+ SourceLocation OnePastCurly =
+ LocStart.getFileLocWithOffset(cursor-startBuf+1);
+ InsertText(OnePastCurly, Result.c_str(), Result.size());
+ }
+ cursor++; // past '{'
+
+ // Now comment out any visibility specifiers.
+ while (cursor < endBuf) {
+ if (*cursor == '@') {
+ SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
+ // Skip whitespace.
+ for (++cursor; cursor[0] == ' ' || cursor[0] == '\t'; ++cursor)
+ /*scan*/;
+
+ // FIXME: presence of @public, etc. inside comment results in
+ // this transformation as well, which is still correct c-code.
+ if (!strncmp(cursor, "public", strlen("public")) ||
+ !strncmp(cursor, "private", strlen("private")) ||
+ !strncmp(cursor, "package", strlen("package")) ||
+ !strncmp(cursor, "protected", strlen("protected")))
+ InsertText(atLoc, "// ", 3);
+ }
+ // FIXME: If there are cases where '<' is used in ivar declaration part
+ // of user code, then scan the ivar list and use needToScanForQualifiers
+ // for type checking.
+ else if (*cursor == '<') {
+ SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
+ InsertText(atLoc, "/* ", 3);
+ cursor = strchr(cursor, '>');
+ cursor++;
+ atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
+ InsertText(atLoc, " */", 3);
+ } else if (*cursor == '^') { // rewrite block specifier.
+ SourceLocation caretLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
+ ReplaceText(caretLoc, 1, "*", 1);
+ }
+ cursor++;
+ }
+ // Don't forget to add a ';'!!
+ InsertText(LocEnd.getFileLocWithOffset(1), ";", 1);
+ } else { // we don't have any instance variables - insert super struct.
+ endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
+ Result += " {\n struct ";
+ Result += RCDecl->getNameAsString();
+ Result += "_IMPL ";
+ Result += RCDecl->getNameAsString();
+ Result += "_IVARS;\n};\n";
+ ReplaceText(LocStart, endBuf-startBuf, Result.c_str(), Result.size());
+ }
+ // Mark this struct as having been generated.
+ if (!ObjCSynthesizedStructs.insert(CDecl))
+ assert(false && "struct already synthesize- SynthesizeObjCInternalStruct");
+}
+
+// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or
+/// class methods.
+template<typename MethodIterator>
+void RewriteObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
+ MethodIterator MethodEnd,
+ bool IsInstanceMethod,
+ const char *prefix,
+ const char *ClassName,
+ std::string &Result) {
+ if (MethodBegin == MethodEnd) return;
+
+ static bool objc_impl_method = false;
+ if (!objc_impl_method) {
+ /* struct _objc_method {
+ SEL _cmd;
+ char *method_types;
+ void *_imp;
+ }
+ */
+ Result += "\nstruct _objc_method {\n";
+ Result += "\tSEL _cmd;\n";
+ Result += "\tchar *method_types;\n";
+ Result += "\tvoid *_imp;\n";
+ Result += "};\n";
+
+ objc_impl_method = true;
+ }
+
+ // Build _objc_method_list for class's methods if needed
+
+ /* struct {
+ struct _objc_method_list *next_method;
+ int method_count;
+ struct _objc_method method_list[];
+ }
+ */
+ unsigned NumMethods = std::distance(MethodBegin, MethodEnd);
+ Result += "\nstatic struct {\n";
+ Result += "\tstruct _objc_method_list *next_method;\n";
+ Result += "\tint method_count;\n";
+ Result += "\tstruct _objc_method method_list[";
+ Result += utostr(NumMethods);
+ Result += "];\n} _OBJC_";
+ Result += prefix;
+ Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
+ Result += "_METHODS_";
+ Result += ClassName;
+ Result += " __attribute__ ((used, section (\"__OBJC, __";
+ Result += IsInstanceMethod ? "inst" : "cls";
+ Result += "_meth\")))= ";
+ Result += "{\n\t0, " + utostr(NumMethods) + "\n";
+
+ Result += "\t,{{(SEL)\"";
+ Result += (*MethodBegin)->getSelector().getAsString().c_str();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\", (void *)";
+ Result += MethodInternalNames[*MethodBegin];
+ Result += "}\n";
+ for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) {
+ Result += "\t ,{(SEL)\"";
+ Result += (*MethodBegin)->getSelector().getAsString().c_str();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\", (void *)";
+ Result += MethodInternalNames[*MethodBegin];
+ Result += "}\n";
+ }
+ Result += "\t }\n};\n";
+}
+
+/// RewriteObjCProtocolMetaData - Rewrite protocols meta-data.
+void RewriteObjC::
+RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, const char *prefix,
+ const char *ClassName, std::string &Result) {
+ static bool objc_protocol_methods = false;
+
+ // Output struct protocol_methods holder of method selector and type.
+ if (!objc_protocol_methods && !PDecl->isForwardDecl()) {
+ /* struct protocol_methods {
+ SEL _cmd;
+ char *method_types;
+ }
+ */
+ Result += "\nstruct _protocol_methods {\n";
+ Result += "\tstruct objc_selector *_cmd;\n";
+ Result += "\tchar *method_types;\n";
+ Result += "};\n";
+
+ objc_protocol_methods = true;
+ }
+ // Do not synthesize the protocol more than once.
+ if (ObjCSynthesizedProtocols.count(PDecl))
+ return;
+
+ if (PDecl->instmeth_begin(*Context) != PDecl->instmeth_end(*Context)) {
+ unsigned NumMethods = std::distance(PDecl->instmeth_begin(*Context),
+ PDecl->instmeth_end(*Context));
+ /* struct _objc_protocol_method_list {
+ int protocol_method_count;
+ struct protocol_methods protocols[];
+ }
+ */
+ Result += "\nstatic struct {\n";
+ Result += "\tint protocol_method_count;\n";
+ Result += "\tstruct _protocol_methods protocol_methods[";
+ Result += utostr(NumMethods);
+ Result += "];\n} _OBJC_PROTOCOL_INSTANCE_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __cat_inst_meth\")))= "
+ "{\n\t" + utostr(NumMethods) + "\n";
+
+ // Output instance methods declared in this protocol.
+ for (ObjCProtocolDecl::instmeth_iterator
+ I = PDecl->instmeth_begin(*Context),
+ E = PDecl->instmeth_end(*Context);
+ I != E; ++I) {
+ if (I == PDecl->instmeth_begin(*Context))
+ Result += "\t ,{{(struct objc_selector *)\"";
+ else
+ Result += "\t ,{(struct objc_selector *)\"";
+ Result += (*I)->getSelector().getAsString().c_str();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\"}\n";
+ }
+ Result += "\t }\n};\n";
+ }
+
+ // Output class methods declared in this protocol.
+ unsigned NumMethods = std::distance(PDecl->classmeth_begin(*Context),
+ PDecl->classmeth_end(*Context));
+ if (NumMethods > 0) {
+ /* struct _objc_protocol_method_list {
+ int protocol_method_count;
+ struct protocol_methods protocols[];
+ }
+ */
+ Result += "\nstatic struct {\n";
+ Result += "\tint protocol_method_count;\n";
+ Result += "\tstruct _protocol_methods protocol_methods[";
+ Result += utostr(NumMethods);
+ Result += "];\n} _OBJC_PROTOCOL_CLASS_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= "
+ "{\n\t";
+ Result += utostr(NumMethods);
+ Result += "\n";
+
+ // Output instance methods declared in this protocol.
+ for (ObjCProtocolDecl::classmeth_iterator
+ I = PDecl->classmeth_begin(*Context),
+ E = PDecl->classmeth_end(*Context);
+ I != E; ++I) {
+ if (I == PDecl->classmeth_begin(*Context))
+ Result += "\t ,{{(struct objc_selector *)\"";
+ else
+ Result += "\t ,{(struct objc_selector *)\"";
+ Result += (*I)->getSelector().getAsString().c_str();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\"}\n";
+ }
+ Result += "\t }\n};\n";
+ }
+
+ // Output:
+ /* struct _objc_protocol {
+ // Objective-C 1.0 extensions
+ struct _objc_protocol_extension *isa;
+ char *protocol_name;
+ struct _objc_protocol **protocol_list;
+ struct _objc_protocol_method_list *instance_methods;
+ struct _objc_protocol_method_list *class_methods;
+ };
+ */
+ static bool objc_protocol = false;
+ if (!objc_protocol) {
+ Result += "\nstruct _objc_protocol {\n";
+ Result += "\tstruct _objc_protocol_extension *isa;\n";
+ Result += "\tchar *protocol_name;\n";
+ Result += "\tstruct _objc_protocol **protocol_list;\n";
+ Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
+ Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
+ Result += "};\n";
+
+ objc_protocol = true;
+ }
+
+ Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
+ Result += PDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __protocol\")))= "
+ "{\n\t0, \"";
+ Result += PDecl->getNameAsString();
+ Result += "\", 0, ";
+ if (PDecl->instmeth_begin(*Context) != PDecl->instmeth_end(*Context)) {
+ Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_INSTANCE_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += ", ";
+ }
+ else
+ Result += "0, ";
+ if (PDecl->classmeth_begin(*Context) != PDecl->classmeth_end(*Context)) {
+ Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_CLASS_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += "\n";
+ }
+ else
+ Result += "0\n";
+ Result += "};\n";
+
+ // Mark this protocol as having been generated.
+ if (!ObjCSynthesizedProtocols.insert(PDecl))
+ assert(false && "protocol already synthesized");
+
+}
+
+void RewriteObjC::
+RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Protocols,
+ const char *prefix, const char *ClassName,
+ std::string &Result) {
+ if (Protocols.empty()) return;
+
+ for (unsigned i = 0; i != Protocols.size(); i++)
+ RewriteObjCProtocolMetaData(Protocols[i], prefix, ClassName, Result);
+
+ // Output the top lovel protocol meta-data for the class.
+ /* struct _objc_protocol_list {
+ struct _objc_protocol_list *next;
+ int protocol_count;
+ struct _objc_protocol *class_protocols[];
+ }
+ */
+ Result += "\nstatic struct {\n";
+ Result += "\tstruct _objc_protocol_list *next;\n";
+ Result += "\tint protocol_count;\n";
+ Result += "\tstruct _objc_protocol *class_protocols[";
+ Result += utostr(Protocols.size());
+ Result += "];\n} _OBJC_";
+ Result += prefix;
+ Result += "_PROTOCOLS_";
+ Result += ClassName;
+ Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= "
+ "{\n\t0, ";
+ Result += utostr(Protocols.size());
+ Result += "\n";
+
+ Result += "\t,{&_OBJC_PROTOCOL_";
+ Result += Protocols[0]->getNameAsString();
+ Result += " \n";
+
+ for (unsigned i = 1; i != Protocols.size(); i++) {
+ Result += "\t ,&_OBJC_PROTOCOL_";
+ Result += Protocols[i]->getNameAsString();
+ Result += "\n";
+ }
+ Result += "\t }\n};\n";
+}
+
+
+/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category
+/// implementation.
+void RewriteObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
+ std::string &Result) {
+ ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface();
+ // Find category declaration for this implementation.
+ ObjCCategoryDecl *CDecl;
+ for (CDecl = ClassDecl->getCategoryList(); CDecl;
+ CDecl = CDecl->getNextClassCategory())
+ if (CDecl->getIdentifier() == IDecl->getIdentifier())
+ break;
+
+ std::string FullCategoryName = ClassDecl->getNameAsString();
+ FullCategoryName += '_';
+ FullCategoryName += IDecl->getNameAsString();
+
+ // Build _objc_method_list for class's instance methods if needed
+ llvm::SmallVector<ObjCMethodDecl *, 32>
+ InstanceMethods(IDecl->instmeth_begin(*Context),
+ IDecl->instmeth_end(*Context));
+
+ // If any of our property implementations have associated getters or
+ // setters, produce metadata for them as well.
+ for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(*Context),
+ PropEnd = IDecl->propimpl_end(*Context);
+ Prop != PropEnd; ++Prop) {
+ if ((*Prop)->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ continue;
+ if (!(*Prop)->getPropertyIvarDecl())
+ continue;
+ ObjCPropertyDecl *PD = (*Prop)->getPropertyDecl();
+ if (!PD)
+ continue;
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ InstanceMethods.push_back(Getter);
+ if (PD->isReadOnly())
+ continue;
+ if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
+ InstanceMethods.push_back(Setter);
+ }
+ RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),
+ true, "CATEGORY_", FullCategoryName.c_str(),
+ Result);
+
+ // Build _objc_method_list for class's class methods if needed
+ RewriteObjCMethodsMetaData(IDecl->classmeth_begin(*Context),
+ IDecl->classmeth_end(*Context),
+ false, "CATEGORY_", FullCategoryName.c_str(),
+ Result);
+
+ // Protocols referenced in class declaration?
+ // Null CDecl is case of a category implementation with no category interface
+ if (CDecl)
+ RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), "CATEGORY",
+ FullCategoryName.c_str(), Result);
+ /* struct _objc_category {
+ char *category_name;
+ char *class_name;
+ struct _objc_method_list *instance_methods;
+ struct _objc_method_list *class_methods;
+ struct _objc_protocol_list *protocols;
+ // Objective-C 1.0 extensions
+ uint32_t size; // sizeof (struct _objc_category)
+ struct _objc_property_list *instance_properties; // category's own
+ // @property decl.
+ };
+ */
+
+ static bool objc_category = false;
+ if (!objc_category) {
+ Result += "\nstruct _objc_category {\n";
+ Result += "\tchar *category_name;\n";
+ Result += "\tchar *class_name;\n";
+ Result += "\tstruct _objc_method_list *instance_methods;\n";
+ Result += "\tstruct _objc_method_list *class_methods;\n";
+ Result += "\tstruct _objc_protocol_list *protocols;\n";
+ Result += "\tunsigned int size;\n";
+ Result += "\tstruct _objc_property_list *instance_properties;\n";
+ Result += "};\n";
+ objc_category = true;
+ }
+ Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
+ Result += FullCategoryName;
+ Result += " __attribute__ ((used, section (\"__OBJC, __category\")))= {\n\t\"";
+ Result += IDecl->getNameAsString();
+ Result += "\"\n\t, \"";
+ Result += ClassDecl->getNameAsString();
+ Result += "\"\n";
+
+ if (IDecl->instmeth_begin(*Context) != IDecl->instmeth_end(*Context)) {
+ Result += "\t, (struct _objc_method_list *)"
+ "&_OBJC_CATEGORY_INSTANCE_METHODS_";
+ Result += FullCategoryName;
+ Result += "\n";
+ }
+ else
+ Result += "\t, 0\n";
+ if (IDecl->classmeth_begin(*Context) != IDecl->classmeth_end(*Context)) {
+ Result += "\t, (struct _objc_method_list *)"
+ "&_OBJC_CATEGORY_CLASS_METHODS_";
+ Result += FullCategoryName;
+ Result += "\n";
+ }
+ else
+ Result += "\t, 0\n";
+
+ if (CDecl && CDecl->protocol_begin() != CDecl->protocol_end()) {
+ Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
+ Result += FullCategoryName;
+ Result += "\n";
+ }
+ else
+ Result += "\t, 0\n";
+ Result += "\t, sizeof(struct _objc_category), 0\n};\n";
+}
+
+/// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of
+/// ivar offset.
+void RewriteObjC::SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl,
+ ObjCIvarDecl *ivar,
+ std::string &Result) {
+ if (ivar->isBitField()) {
+ // FIXME: The hack below doesn't work for bitfields. For now, we simply
+ // place all bitfields at offset 0.
+ Result += "0";
+ } else {
+ Result += "__OFFSETOFIVAR__(struct ";
+ Result += IDecl->getNameAsString();
+ if (LangOpts.Microsoft)
+ Result += "_IMPL";
+ Result += ", ";
+ Result += ivar->getNameAsString();
+ Result += ")";
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Meta Data Emission
+//===----------------------------------------------------------------------===//
+
+void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
+ std::string &Result) {
+ ObjCInterfaceDecl *CDecl = IDecl->getClassInterface();
+
+ // Explictly declared @interface's are already synthesized.
+ if (CDecl->isImplicitInterfaceDecl()) {
+ // FIXME: Implementation of a class with no @interface (legacy) doese not
+ // produce correct synthesis as yet.
+ SynthesizeObjCInternalStruct(CDecl, Result);
+ }
+
+ // Build _objc_ivar_list metadata for classes ivars if needed
+ unsigned NumIvars = !IDecl->ivar_empty(*Context)
+ ? IDecl->ivar_size(*Context)
+ : (CDecl ? CDecl->ivar_size() : 0);
+ if (NumIvars > 0) {
+ static bool objc_ivar = false;
+ if (!objc_ivar) {
+ /* struct _objc_ivar {
+ char *ivar_name;
+ char *ivar_type;
+ int ivar_offset;
+ };
+ */
+ Result += "\nstruct _objc_ivar {\n";
+ Result += "\tchar *ivar_name;\n";
+ Result += "\tchar *ivar_type;\n";
+ Result += "\tint ivar_offset;\n";
+ Result += "};\n";
+
+ objc_ivar = true;
+ }
+
+ /* struct {
+ int ivar_count;
+ struct _objc_ivar ivar_list[nIvars];
+ };
+ */
+ Result += "\nstatic struct {\n";
+ Result += "\tint ivar_count;\n";
+ Result += "\tstruct _objc_ivar ivar_list[";
+ Result += utostr(NumIvars);
+ Result += "];\n} _OBJC_INSTANCE_VARIABLES_";
+ Result += IDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __instance_vars\")))= "
+ "{\n\t";
+ Result += utostr(NumIvars);
+ Result += "\n";
+
+ ObjCInterfaceDecl::ivar_iterator IVI, IVE;
+ llvm::SmallVector<ObjCIvarDecl *, 8> IVars;
+ if (!IDecl->ivar_empty(*Context)) {
+ for (ObjCImplementationDecl::ivar_iterator
+ IV = IDecl->ivar_begin(*Context),
+ IVEnd = IDecl->ivar_end(*Context);
+ IV != IVEnd; ++IV)
+ IVars.push_back(*IV);
+ IVI = IVars.begin();
+ IVE = IVars.end();
+ } else {
+ IVI = CDecl->ivar_begin();
+ IVE = CDecl->ivar_end();
+ }
+ Result += "\t,{{\"";
+ Result += (*IVI)->getNameAsString();
+ Result += "\", \"";
+ std::string TmpString, StrEncoding;
+ Context->getObjCEncodingForType((*IVI)->getType(), TmpString, *IVI);
+ QuoteDoublequotes(TmpString, StrEncoding);
+ Result += StrEncoding;
+ Result += "\", ";
+ SynthesizeIvarOffsetComputation(IDecl, *IVI, Result);
+ Result += "}\n";
+ for (++IVI; IVI != IVE; ++IVI) {
+ Result += "\t ,{\"";
+ Result += (*IVI)->getNameAsString();
+ Result += "\", \"";
+ std::string TmpString, StrEncoding;
+ Context->getObjCEncodingForType((*IVI)->getType(), TmpString, *IVI);
+ QuoteDoublequotes(TmpString, StrEncoding);
+ Result += StrEncoding;
+ Result += "\", ";
+ SynthesizeIvarOffsetComputation(IDecl, (*IVI), Result);
+ Result += "}\n";
+ }
+
+ Result += "\t }\n};\n";
+ }
+
+ // Build _objc_method_list for class's instance methods if needed
+ llvm::SmallVector<ObjCMethodDecl *, 32>
+ InstanceMethods(IDecl->instmeth_begin(*Context),
+ IDecl->instmeth_end(*Context));
+
+ // If any of our property implementations have associated getters or
+ // setters, produce metadata for them as well.
+ for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(*Context),
+ PropEnd = IDecl->propimpl_end(*Context);
+ Prop != PropEnd; ++Prop) {
+ if ((*Prop)->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ continue;
+ if (!(*Prop)->getPropertyIvarDecl())
+ continue;
+ ObjCPropertyDecl *PD = (*Prop)->getPropertyDecl();
+ if (!PD)
+ continue;
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ InstanceMethods.push_back(Getter);
+ if (PD->isReadOnly())
+ continue;
+ if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
+ InstanceMethods.push_back(Setter);
+ }
+ RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),
+ true, "", IDecl->getNameAsCString(), Result);
+
+ // Build _objc_method_list for class's class methods if needed
+ RewriteObjCMethodsMetaData(IDecl->classmeth_begin(*Context),
+ IDecl->classmeth_end(*Context),
+ false, "", IDecl->getNameAsCString(), Result);
+
+ // Protocols referenced in class declaration?
+ RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(),
+ "CLASS", CDecl->getNameAsCString(), Result);
+
+ // Declaration of class/meta-class metadata
+ /* struct _objc_class {
+ struct _objc_class *isa; // or const char *root_class_name when metadata
+ const char *super_class_name;
+ char *name;
+ long version;
+ long info;
+ long instance_size;
+ struct _objc_ivar_list *ivars;
+ struct _objc_method_list *methods;
+ struct objc_cache *cache;
+ struct objc_protocol_list *protocols;
+ const char *ivar_layout;
+ struct _objc_class_ext *ext;
+ };
+ */
+ static bool objc_class = false;
+ if (!objc_class) {
+ Result += "\nstruct _objc_class {\n";
+ Result += "\tstruct _objc_class *isa;\n";
+ Result += "\tconst char *super_class_name;\n";
+ Result += "\tchar *name;\n";
+ Result += "\tlong version;\n";
+ Result += "\tlong info;\n";
+ Result += "\tlong instance_size;\n";
+ Result += "\tstruct _objc_ivar_list *ivars;\n";
+ Result += "\tstruct _objc_method_list *methods;\n";
+ Result += "\tstruct objc_cache *cache;\n";
+ Result += "\tstruct _objc_protocol_list *protocols;\n";
+ Result += "\tconst char *ivar_layout;\n";
+ Result += "\tstruct _objc_class_ext *ext;\n";
+ Result += "};\n";
+ objc_class = true;
+ }
+
+ // Meta-class metadata generation.
+ ObjCInterfaceDecl *RootClass = 0;
+ ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass();
+ while (SuperClass) {
+ RootClass = SuperClass;
+ SuperClass = SuperClass->getSuperClass();
+ }
+ SuperClass = CDecl->getSuperClass();
+
+ Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
+ Result += CDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __meta_class\")))= "
+ "{\n\t(struct _objc_class *)\"";
+ Result += (RootClass ? RootClass->getNameAsString() : CDecl->getNameAsString());
+ Result += "\"";
+
+ if (SuperClass) {
+ Result += ", \"";
+ Result += SuperClass->getNameAsString();
+ Result += "\", \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
+ }
+ else {
+ Result += ", 0, \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
+ }
+ // Set 'ivars' field for root class to 0. ObjC1 runtime does not use it.
+ // 'info' field is initialized to CLS_META(2) for metaclass
+ Result += ", 0,2, sizeof(struct _objc_class), 0";
+ if (IDecl->classmeth_begin(*Context) != IDecl->classmeth_end(*Context)) {
+ Result += "\n\t, (struct _objc_method_list *)&_OBJC_CLASS_METHODS_";
+ Result += IDecl->getNameAsString();
+ Result += "\n";
+ }
+ else
+ Result += ", 0\n";
+ if (CDecl->protocol_begin() != CDecl->protocol_end()) {
+ Result += "\t,0, (struct _objc_protocol_list *)&_OBJC_CLASS_PROTOCOLS_";
+ Result += CDecl->getNameAsString();
+ Result += ",0,0\n";
+ }
+ else
+ Result += "\t,0,0,0,0\n";
+ Result += "};\n";
+
+ // class metadata generation.
+ Result += "\nstatic struct _objc_class _OBJC_CLASS_";
+ Result += CDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __class\")))= "
+ "{\n\t&_OBJC_METACLASS_";
+ Result += CDecl->getNameAsString();
+ if (SuperClass) {
+ Result += ", \"";
+ Result += SuperClass->getNameAsString();
+ Result += "\", \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
+ }
+ else {
+ Result += ", 0, \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
+ }
+ // 'info' field is initialized to CLS_CLASS(1) for class
+ Result += ", 0,1";
+ if (!ObjCSynthesizedStructs.count(CDecl))
+ Result += ",0";
+ else {
+ // class has size. Must synthesize its size.
+ Result += ",sizeof(struct ";
+ Result += CDecl->getNameAsString();
+ if (LangOpts.Microsoft)
+ Result += "_IMPL";
+ Result += ")";
+ }
+ if (NumIvars > 0) {
+ Result += ", (struct _objc_ivar_list *)&_OBJC_INSTANCE_VARIABLES_";
+ Result += CDecl->getNameAsString();
+ Result += "\n\t";
+ }
+ else
+ Result += ",0";
+ if (IDecl->instmeth_begin(*Context) != IDecl->instmeth_end(*Context)) {
+ Result += ", (struct _objc_method_list *)&_OBJC_INSTANCE_METHODS_";
+ Result += CDecl->getNameAsString();
+ Result += ", 0\n\t";
+ }
+ else
+ Result += ",0,0";
+ if (CDecl->protocol_begin() != CDecl->protocol_end()) {
+ Result += ", (struct _objc_protocol_list*)&_OBJC_CLASS_PROTOCOLS_";
+ Result += CDecl->getNameAsString();
+ Result += ", 0,0\n";
+ }
+ else
+ Result += ",0,0,0\n";
+ Result += "};\n";
+}
+
+/// RewriteImplementations - This routine rewrites all method implementations
+/// and emits meta-data.
+
+void RewriteObjC::RewriteImplementations() {
+ int ClsDefCount = ClassImplementation.size();
+ int CatDefCount = CategoryImplementation.size();
+
+ // Rewrite implemented methods
+ for (int i = 0; i < ClsDefCount; i++)
+ RewriteImplementationDecl(ClassImplementation[i]);
+
+ for (int i = 0; i < CatDefCount; i++)
+ RewriteImplementationDecl(CategoryImplementation[i]);
+}
+
+void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) {
+ int ClsDefCount = ClassImplementation.size();
+ int CatDefCount = CategoryImplementation.size();
+
+ // This is needed for determining instance variable offsets.
+ Result += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)\n";
+ // For each implemented class, write out all its meta data.
+ for (int i = 0; i < ClsDefCount; i++)
+ RewriteObjCClassMetaData(ClassImplementation[i], Result);
+
+ // For each implemented category, write out all its meta data.
+ for (int i = 0; i < CatDefCount; i++)
+ RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result);
+
+ // Write objc_symtab metadata
+ /*
+ struct _objc_symtab
+ {
+ long sel_ref_cnt;
+ SEL *refs;
+ short cls_def_cnt;
+ short cat_def_cnt;
+ void *defs[cls_def_cnt + cat_def_cnt];
+ };
+ */
+
+ Result += "\nstruct _objc_symtab {\n";
+ Result += "\tlong sel_ref_cnt;\n";
+ Result += "\tSEL *refs;\n";
+ Result += "\tshort cls_def_cnt;\n";
+ Result += "\tshort cat_def_cnt;\n";
+ Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
+ Result += "};\n\n";
+
+ Result += "static struct _objc_symtab "
+ "_OBJC_SYMBOLS __attribute__((used, section (\"__OBJC, __symbols\")))= {\n";
+ Result += "\t0, 0, " + utostr(ClsDefCount)
+ + ", " + utostr(CatDefCount) + "\n";
+ for (int i = 0; i < ClsDefCount; i++) {
+ Result += "\t,&_OBJC_CLASS_";
+ Result += ClassImplementation[i]->getNameAsString();
+ Result += "\n";
+ }
+
+ for (int i = 0; i < CatDefCount; i++) {
+ Result += "\t,&_OBJC_CATEGORY_";
+ Result += CategoryImplementation[i]->getClassInterface()->getNameAsString();
+ Result += "_";
+ Result += CategoryImplementation[i]->getNameAsString();
+ Result += "\n";
+ }
+
+ Result += "};\n\n";
+
+ // Write objc_module metadata
+
+ /*
+ struct _objc_module {
+ long version;
+ long size;
+ const char *name;
+ struct _objc_symtab *symtab;
+ }
+ */
+
+ Result += "\nstruct _objc_module {\n";
+ Result += "\tlong version;\n";
+ Result += "\tlong size;\n";
+ Result += "\tconst char *name;\n";
+ Result += "\tstruct _objc_symtab *symtab;\n";
+ Result += "};\n\n";
+ Result += "static struct _objc_module "
+ "_OBJC_MODULES __attribute__ ((used, section (\"__OBJC, __module_info\")))= {\n";
+ Result += "\t" + utostr(OBJC_ABI_VERSION) +
+ ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
+ Result += "};\n\n";
+
+ if (LangOpts.Microsoft) {
+ if (ProtocolExprDecls.size()) {
+ Result += "#pragma section(\".objc_protocol$B\",long,read,write)\n";
+ Result += "#pragma data_seg(push, \".objc_protocol$B\")\n";
+ for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
+ E = ProtocolExprDecls.end(); I != E; ++I) {
+ Result += "static struct _objc_protocol *_POINTER_OBJC_PROTOCOL_";
+ Result += (*I)->getNameAsString();
+ Result += " = &_OBJC_PROTOCOL_";
+ Result += (*I)->getNameAsString();
+ Result += ";\n";
+ }
+ Result += "#pragma data_seg(pop)\n\n";
+ }
+ Result += "#pragma section(\".objc_module_info$B\",long,read,write)\n";
+ Result += "#pragma data_seg(push, \".objc_module_info$B\")\n";
+ Result += "static struct _objc_module *_POINTER_OBJC_MODULES = ";
+ Result += "&_OBJC_MODULES;\n";
+ Result += "#pragma data_seg(pop)\n\n";
+ }
+}
+
+std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
+ const char *funcName,
+ std::string Tag) {
+ const FunctionType *AFT = CE->getFunctionType();
+ QualType RT = AFT->getResultType();
+ std::string StructRef = "struct " + Tag;
+ std::string S = "static " + RT.getAsString() + " __" +
+ funcName + "_" + "block_func_" + utostr(i);
+
+ BlockDecl *BD = CE->getBlockDecl();
+
+ if (isa<FunctionNoProtoType>(AFT)) {
+ // No user-supplied arguments. Still need to pass in a pointer to the
+ // block (to reference imported block decl refs).
+ S += "(" + StructRef + " *__cself)";
+ } else if (BD->param_empty()) {
+ S += "(" + StructRef + " *__cself)";
+ } else {
+ const FunctionProtoType *FT = cast<FunctionProtoType>(AFT);
+ assert(FT && "SynthesizeBlockFunc: No function proto");
+ S += '(';
+ // first add the implicit argument.
+ S += StructRef + " *__cself, ";
+ std::string ParamStr;
+ for (BlockDecl::param_iterator AI = BD->param_begin(),
+ E = BD->param_end(); AI != E; ++AI) {
+ if (AI != BD->param_begin()) S += ", ";
+ ParamStr = (*AI)->getNameAsString();
+ (*AI)->getType().getAsStringInternal(ParamStr, Context->PrintingPolicy);
+ S += ParamStr;
+ }
+ if (FT->isVariadic()) {
+ if (!BD->param_empty()) S += ", ";
+ S += "...";
+ }
+ S += ')';
+ }
+ S += " {\n";
+
+ // Create local declarations to avoid rewriting all closure decl ref exprs.
+ // First, emit a declaration for all "by ref" decls.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string Name = (*I)->getNameAsString();
+ Context->getPointerType((*I)->getType()).getAsStringInternal(Name,
+ Context->PrintingPolicy);
+ S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
+ }
+ // Next, emit a declaration for all "by copy" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string Name = (*I)->getNameAsString();
+ // Handle nested closure invocation. For example:
+ //
+ // void (^myImportedClosure)(void);
+ // myImportedClosure = ^(void) { setGlobalInt(x + y); };
+ //
+ // void (^anotherClosure)(void);
+ // anotherClosure = ^(void) {
+ // myImportedClosure(); // import and invoke the closure
+ // };
+ //
+ if (isTopLevelBlockPointerType((*I)->getType()))
+ S += "struct __block_impl *";
+ else
+ (*I)->getType().getAsStringInternal(Name, Context->PrintingPolicy);
+ S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by copy\n";
+ }
+ std::string RewrittenStr = RewrittenBlockExprs[CE];
+ const char *cstr = RewrittenStr.c_str();
+ while (*cstr++ != '{') ;
+ S += cstr;
+ S += "\n";
+ return S;
+}
+
+std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
+ const char *funcName,
+ std::string Tag) {
+ std::string StructRef = "struct " + Tag;
+ std::string S = "static void __";
+
+ S += funcName;
+ S += "_block_copy_" + utostr(i);
+ S += "(" + StructRef;
+ S += "*dst, " + StructRef;
+ S += "*src) {";
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
+ E = ImportedBlockDecls.end(); I != E; ++I) {
+ S += "_Block_object_assign((void*)&dst->";
+ S += (*I)->getNameAsString();
+ S += ", (void*)src->";
+ S += (*I)->getNameAsString();
+ S += ", 3/*BLOCK_FIELD_IS_OBJECT*/);}";
+ }
+ S += "\nstatic void __";
+ S += funcName;
+ S += "_block_dispose_" + utostr(i);
+ S += "(" + StructRef;
+ S += "*src) {";
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
+ E = ImportedBlockDecls.end(); I != E; ++I) {
+ S += "_Block_object_dispose((void*)src->";
+ S += (*I)->getNameAsString();
+ S += ", 3/*BLOCK_FIELD_IS_OBJECT*/);";
+ }
+ S += "}\n";
+ return S;
+}
+
+std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
+ bool hasCopyDisposeHelpers) {
+ std::string S = "\nstruct " + Tag;
+ std::string Constructor = " " + Tag;
+
+ S += " {\n struct __block_impl impl;\n";
+
+ if (hasCopyDisposeHelpers)
+ S += " void *copy;\n void *dispose;\n";
+
+ Constructor += "(void *fp";
+
+ if (hasCopyDisposeHelpers)
+ Constructor += ", void *copyHelp, void *disposeHelp";
+
+ if (BlockDeclRefs.size()) {
+ // Output all "by copy" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string FieldName = (*I)->getNameAsString();
+ std::string ArgName = "_" + FieldName;
+ // Handle nested closure invocation. For example:
+ //
+ // void (^myImportedBlock)(void);
+ // myImportedBlock = ^(void) { setGlobalInt(x + y); };
+ //
+ // void (^anotherBlock)(void);
+ // anotherBlock = ^(void) {
+ // myImportedBlock(); // import and invoke the closure
+ // };
+ //
+ if (isTopLevelBlockPointerType((*I)->getType())) {
+ S += "struct __block_impl *";
+ Constructor += ", void *" + ArgName;
+ } else {
+ (*I)->getType().getAsStringInternal(FieldName, Context->PrintingPolicy);
+ (*I)->getType().getAsStringInternal(ArgName, Context->PrintingPolicy);
+ Constructor += ", " + ArgName;
+ }
+ S += FieldName + ";\n";
+ }
+ // Output all "by ref" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string FieldName = (*I)->getNameAsString();
+ std::string ArgName = "_" + FieldName;
+ // Handle nested closure invocation. For example:
+ //
+ // void (^myImportedBlock)(void);
+ // myImportedBlock = ^(void) { setGlobalInt(x + y); };
+ //
+ // void (^anotherBlock)(void);
+ // anotherBlock = ^(void) {
+ // myImportedBlock(); // import and invoke the closure
+ // };
+ //
+ if (isTopLevelBlockPointerType((*I)->getType())) {
+ S += "struct __block_impl *";
+ Constructor += ", void *" + ArgName;
+ } else {
+ Context->getPointerType((*I)->getType()).getAsStringInternal(FieldName,
+ Context->PrintingPolicy);
+ Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName,
+ Context->PrintingPolicy);
+ Constructor += ", " + ArgName;
+ }
+ S += FieldName + "; // by ref\n";
+ }
+ // Finish writing the constructor.
+ Constructor += ", int flags=0) {\n";
+ if (GlobalVarDecl)
+ Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n";
+ else
+ Constructor += " impl.isa = &_NSConcreteStackBlock;\n";
+ Constructor += " impl.Size = sizeof(";
+ Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
+
+ if (hasCopyDisposeHelpers)
+ Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
+
+ // Initialize all "by copy" arguments.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ std::string Name = (*I)->getNameAsString();
+ Constructor += " ";
+ if (isTopLevelBlockPointerType((*I)->getType()))
+ Constructor += Name + " = (struct __block_impl *)_";
+ else
+ Constructor += Name + " = _";
+ Constructor += Name + ";\n";
+ }
+ // Initialize all "by ref" arguments.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ std::string Name = (*I)->getNameAsString();
+ Constructor += " ";
+ if (isTopLevelBlockPointerType((*I)->getType()))
+ Constructor += Name + " = (struct __block_impl *)_";
+ else
+ Constructor += Name + " = _";
+ Constructor += Name + ";\n";
+ }
+ } else {
+ // Finish writing the constructor.
+ Constructor += ", int flags=0) {\n";
+ if (GlobalVarDecl)
+ Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n";
+ else
+ Constructor += " impl.isa = &_NSConcreteStackBlock;\n";
+ Constructor += " impl.Size = sizeof(";
+ Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
+ if (hasCopyDisposeHelpers)
+ Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
+ }
+ Constructor += " ";
+ Constructor += "}\n";
+ S += Constructor;
+ S += "};\n";
+ return S;
+}
+
+void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
+ const char *FunName) {
+ // Insert closures that were part of the function.
+ for (unsigned i = 0; i < Blocks.size(); i++) {
+
+ CollectBlockDeclRefInfo(Blocks[i]);
+
+ std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i);
+
+ std::string CI = SynthesizeBlockImpl(Blocks[i], Tag,
+ ImportedBlockDecls.size() > 0);
+
+ InsertText(FunLocStart, CI.c_str(), CI.size());
+
+ std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag);
+
+ InsertText(FunLocStart, CF.c_str(), CF.size());
+
+ if (ImportedBlockDecls.size()) {
+ std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, Tag);
+ InsertText(FunLocStart, HF.c_str(), HF.size());
+ }
+
+ BlockDeclRefs.clear();
+ BlockByRefDecls.clear();
+ BlockByCopyDecls.clear();
+ BlockCallExprs.clear();
+ ImportedBlockDecls.clear();
+ }
+ Blocks.clear();
+ RewrittenBlockExprs.clear();
+}
+
+void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
+ SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
+ const char *FuncName = FD->getNameAsCString();
+
+ SynthesizeBlockLiterals(FunLocStart, FuncName);
+}
+
+void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
+ //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n");
+ //SourceLocation FunLocStart = MD->getLocStart();
+ // FIXME: This hack works around a bug in Rewrite.InsertText().
+ SourceLocation FunLocStart = MD->getLocStart().getFileLocWithOffset(-1);
+ std::string FuncName = MD->getSelector().getAsString();
+ // Convert colons to underscores.
+ std::string::size_type loc = 0;
+ while ((loc = FuncName.find(":", loc)) != std::string::npos)
+ FuncName.replace(loc, 1, "_");
+
+ SynthesizeBlockLiterals(FunLocStart, FuncName.c_str());
+}
+
+void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) {
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++CI)
+ if (*CI) {
+ if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI))
+ GetBlockDeclRefExprs(CBE->getBody());
+ else
+ GetBlockDeclRefExprs(*CI);
+ }
+ // Handle specific things.
+ if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S))
+ // FIXME: Handle enums.
+ if (!isa<FunctionDecl>(CDRE->getDecl()))
+ BlockDeclRefs.push_back(CDRE);
+ return;
+}
+
+void RewriteObjC::GetBlockCallExprs(Stmt *S) {
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++CI)
+ if (*CI) {
+ if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI))
+ GetBlockCallExprs(CBE->getBody());
+ else
+ GetBlockCallExprs(*CI);
+ }
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ if (CE->getCallee()->getType()->isBlockPointerType()) {
+ BlockCallExprs[dyn_cast<BlockDeclRefExpr>(CE->getCallee())] = CE;
+ }
+ }
+ return;
+}
+
+Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp) {
+ // Navigate to relevant type information.
+ const char *closureName = 0;
+ const BlockPointerType *CPT = 0;
+
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp->getCallee())) {
+ closureName = DRE->getDecl()->getNameAsCString();
+ CPT = DRE->getType()->getAsBlockPointerType();
+ } else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) {
+ closureName = CDRE->getDecl()->getNameAsCString();
+ CPT = CDRE->getType()->getAsBlockPointerType();
+ } else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) {
+ closureName = MExpr->getMemberDecl()->getNameAsCString();
+ CPT = MExpr->getType()->getAsBlockPointerType();
+ } else {
+ assert(1 && "RewriteBlockClass: Bad type");
+ }
+ assert(CPT && "RewriteBlockClass: Bad type");
+ const FunctionType *FT = CPT->getPointeeType()->getAsFunctionType();
+ assert(FT && "RewriteBlockClass: Bad type");
+ const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
+ // FTP will be null for closures that don't take arguments.
+
+ RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ SourceLocation(),
+ &Context->Idents.get("__block_impl"));
+ QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD));
+
+ // Generate a funky cast.
+ llvm::SmallVector<QualType, 8> ArgTypes;
+
+ // Push the block argument type.
+ ArgTypes.push_back(PtrBlock);
+ if (FTP) {
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I && (I != E); ++I) {
+ QualType t = *I;
+ // Make sure we convert "t (^)(...)" to "t (*)(...)".
+ if (isTopLevelBlockPointerType(t)) {
+ const BlockPointerType *BPT = t->getAsBlockPointerType();
+ t = Context->getPointerType(BPT->getPointeeType());
+ }
+ ArgTypes.push_back(t);
+ }
+ }
+ // Now do the pointer to function cast.
+ QualType PtrToFuncCastType = Context->getFunctionType(Exp->getType(),
+ &ArgTypes[0], ArgTypes.size(), false/*no variadic*/, 0);
+
+ PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType);
+
+ CastExpr *BlkCast = new (Context) CStyleCastExpr(PtrBlock, Exp->getCallee(),
+ PtrBlock, SourceLocation(),
+ SourceLocation());
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
+ BlkCast);
+ //PE->dump();
+
+ FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ &Context->Idents.get("FuncPtr"), Context->VoidPtrTy,
+ /*BitWidth=*/0, /*Mutable=*/true);
+ MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
+ FD->getType());
+
+ CastExpr *FunkCast = new (Context) CStyleCastExpr(PtrToFuncCastType, ME,
+ PtrToFuncCastType,
+ SourceLocation(),
+ SourceLocation());
+ PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast);
+
+ llvm::SmallVector<Expr*, 8> BlkExprs;
+ // Add the implicit argument.
+ BlkExprs.push_back(BlkCast);
+ // Add the user arguments.
+ for (CallExpr::arg_iterator I = Exp->arg_begin(),
+ E = Exp->arg_end(); I != E; ++I) {
+ BlkExprs.push_back(*I);
+ }
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, &BlkExprs[0],
+ BlkExprs.size(),
+ Exp->getType(), SourceLocation());
+ return CE;
+}
+
+void RewriteObjC::RewriteBlockCall(CallExpr *Exp) {
+ Stmt *BlockCall = SynthesizeBlockCall(Exp);
+ ReplaceStmt(Exp, BlockCall);
+}
+
+// We need to return the rewritten expression to handle cases where the
+// BlockDeclRefExpr is embedded in another expression being rewritten.
+// For example:
+//
+// int main() {
+// __block Foo *f;
+// __block int i;
+//
+// void (^myblock)() = ^() {
+// [f test]; // f is a BlockDeclRefExpr embedded in a message (which is being rewritten).
+// i = 77;
+// };
+//}
+Stmt *RewriteObjC::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) {
+ // FIXME: Add more elaborate code generation required by the ABI.
+ Expr *DerefExpr = new (Context) UnaryOperator(BDRE, UnaryOperator::Deref,
+ Context->getPointerType(BDRE->getType()),
+ SourceLocation());
+ // Need parens to enforce precedence.
+ ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), DerefExpr);
+ ReplaceStmt(BDRE, PE);
+ return PE;
+}
+
+void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) {
+ SourceLocation LocStart = CE->getLParenLoc();
+ SourceLocation LocEnd = CE->getRParenLoc();
+
+ // Need to avoid trying to rewrite synthesized casts.
+ if (LocStart.isInvalid())
+ return;
+ // Need to avoid trying to rewrite casts contained in macros.
+ if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd))
+ return;
+
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+
+ // advance the location to startArgList.
+ const char *argPtr = startBuf;
+
+ while (*argPtr++ && (argPtr < endBuf)) {
+ switch (*argPtr) {
+ case '^':
+ // Replace the '^' with '*'.
+ LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf);
+ ReplaceText(LocStart, 1, "*", 1);
+ break;
+ }
+ }
+ return;
+}
+
+void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
+ SourceLocation DeclLoc = FD->getLocation();
+ unsigned parenCount = 0;
+
+ // We have 1 or more arguments that have closure pointers.
+ const char *startBuf = SM->getCharacterData(DeclLoc);
+ const char *startArgList = strchr(startBuf, '(');
+
+ assert((*startArgList == '(') && "Rewriter fuzzy parser confused");
+
+ parenCount++;
+ // advance the location to startArgList.
+ DeclLoc = DeclLoc.getFileLocWithOffset(startArgList-startBuf);
+ assert((DeclLoc.isValid()) && "Invalid DeclLoc");
+
+ const char *argPtr = startArgList;
+
+ while (*argPtr++ && parenCount) {
+ switch (*argPtr) {
+ case '^':
+ // Replace the '^' with '*'.
+ DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList);
+ ReplaceText(DeclLoc, 1, "*", 1);
+ break;
+ case '(':
+ parenCount++;
+ break;
+ case ')':
+ parenCount--;
+ break;
+ }
+ }
+ return;
+}
+
+bool RewriteObjC::PointerTypeTakesAnyBlockArguments(QualType QT) {
+ const FunctionProtoType *FTP;
+ const PointerType *PT = QT->getAsPointerType();
+ if (PT) {
+ FTP = PT->getPointeeType()->getAsFunctionProtoType();
+ } else {
+ const BlockPointerType *BPT = QT->getAsBlockPointerType();
+ assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
+ FTP = BPT->getPointeeType()->getAsFunctionProtoType();
+ }
+ if (FTP) {
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I != E; ++I)
+ if (isTopLevelBlockPointerType(*I))
+ return true;
+ }
+ return false;
+}
+
+void RewriteObjC::GetExtentOfArgList(const char *Name, const char *&LParen,
+ const char *&RParen) {
+ const char *argPtr = strchr(Name, '(');
+ assert((*argPtr == '(') && "Rewriter fuzzy parser confused");
+
+ LParen = argPtr; // output the start.
+ argPtr++; // skip past the left paren.
+ unsigned parenCount = 1;
+
+ while (*argPtr && parenCount) {
+ switch (*argPtr) {
+ case '(': parenCount++; break;
+ case ')': parenCount--; break;
+ default: break;
+ }
+ if (parenCount) argPtr++;
+ }
+ assert((*argPtr == ')') && "Rewriter fuzzy parser confused");
+ RParen = argPtr; // output the end
+}
+
+void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
+ RewriteBlockPointerFunctionArgs(FD);
+ return;
+ }
+ // Handle Variables and Typedefs.
+ SourceLocation DeclLoc = ND->getLocation();
+ QualType DeclT;
+ if (VarDecl *VD = dyn_cast<VarDecl>(ND))
+ DeclT = VD->getType();
+ else if (TypedefDecl *TDD = dyn_cast<TypedefDecl>(ND))
+ DeclT = TDD->getUnderlyingType();
+ else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND))
+ DeclT = FD->getType();
+ else
+ assert(0 && "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--;
+
+ // *startBuf != '^' if we are dealing with a pointer to function that
+ // may take block argument types (which will be handled below).
+ if (*startBuf == '^') {
+ // Replace the '^' with '*', computing a negative offset.
+ DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf);
+ ReplaceText(DeclLoc, 1, "*", 1);
+ }
+ if (PointerTypeTakesAnyBlockArguments(DeclT)) {
+ // Replace the '^' with '*' for arguments.
+ DeclLoc = ND->getLocation();
+ startBuf = SM->getCharacterData(DeclLoc);
+ const char *argListBegin, *argListEnd;
+ GetExtentOfArgList(startBuf, argListBegin, argListEnd);
+ while (argListBegin < argListEnd) {
+ if (*argListBegin == '^') {
+ SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf);
+ ReplaceText(CaretLoc, 1, "*", 1);
+ }
+ argListBegin++;
+ }
+ }
+ return;
+}
+
+void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
+ // Add initializers for any closure decl refs.
+ GetBlockDeclRefExprs(Exp->getBody());
+ if (BlockDeclRefs.size()) {
+ // Unique all "by copy" declarations.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (!BlockDeclRefs[i]->isByRef())
+ BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl());
+ // Unique all "by ref" declarations.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (BlockDeclRefs[i]->isByRef()) {
+ BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl());
+ }
+ // Find any imported blocks...they will need special attention.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (BlockDeclRefs[i]->getType()->isBlockPointerType()) {
+ GetBlockCallExprs(BlockDeclRefs[i]);
+ ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl());
+ }
+ }
+}
+
+FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(const char *name) {
+ IdentifierInfo *ID = &Context->Idents.get(name);
+ QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy);
+ return FunctionDecl::Create(*Context, TUDecl,SourceLocation(),
+ ID, FType, FunctionDecl::Extern, false,
+ false);
+}
+
+Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
+ Blocks.push_back(Exp);
+
+ CollectBlockDeclRefInfo(Exp);
+ std::string FuncName;
+
+ if (CurFunctionDef)
+ FuncName = CurFunctionDef->getNameAsString();
+ else if (CurMethodDef) {
+ FuncName = CurMethodDef->getSelector().getAsString();
+ // Convert colons to underscores.
+ std::string::size_type loc = 0;
+ while ((loc = FuncName.find(":", loc)) != std::string::npos)
+ FuncName.replace(loc, 1, "_");
+ } else if (GlobalVarDecl)
+ FuncName = std::string(GlobalVarDecl->getNameAsString());
+
+ std::string BlockNumber = utostr(Blocks.size()-1);
+
+ std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber;
+ std::string Func = "__" + FuncName + "_block_func_" + BlockNumber;
+
+ // Get a pointer to the function type so we can cast appropriately.
+ QualType FType = Context->getPointerType(QualType(Exp->getFunctionType(),0));
+
+ FunctionDecl *FD;
+ Expr *NewRep;
+
+ // Simulate a contructor call...
+ FD = SynthBlockInitFunctionDecl(Tag.c_str());
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, FType, SourceLocation());
+
+ llvm::SmallVector<Expr*, 4> InitExprs;
+
+ // Initialize the block function.
+ FD = SynthBlockInitFunctionDecl(Func.c_str());
+ DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, FD->getType(),
+ SourceLocation());
+ CastExpr *castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy, Arg,
+ Context->VoidPtrTy, SourceLocation(),
+ SourceLocation());
+ InitExprs.push_back(castExpr);
+
+ if (ImportedBlockDecls.size()) {
+ std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber;
+ FD = SynthBlockInitFunctionDecl(Buf.c_str());
+ Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
+ castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy, Arg,
+ Context->VoidPtrTy, SourceLocation(),
+ SourceLocation());
+ InitExprs.push_back(castExpr);
+
+ Buf = "__" + FuncName + "_block_dispose_" + BlockNumber;
+ FD = SynthBlockInitFunctionDecl(Buf.c_str());
+ Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
+ castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy, Arg,
+ Context->VoidPtrTy, SourceLocation(),
+ SourceLocation());
+ InitExprs.push_back(castExpr);
+ }
+ // Add initializers for any closure decl refs.
+ if (BlockDeclRefs.size()) {
+ Expr *Exp;
+ // Output all "by copy" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ if (isObjCType((*I)->getType())) {
+ // FIXME: Conform to ABI ([[obj retain] autorelease]).
+ FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
+ Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
+ } else if (isTopLevelBlockPointerType((*I)->getType())) {
+ FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
+ Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
+ Exp = new (Context) CStyleCastExpr(Context->VoidPtrTy, Arg,
+ Context->VoidPtrTy, SourceLocation(),
+ SourceLocation());
+ } else {
+ FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
+ Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
+ }
+ InitExprs.push_back(Exp);
+ }
+ // Output all "by ref" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
+ Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
+ Exp = new (Context) UnaryOperator(Exp, UnaryOperator::AddrOf,
+ Context->getPointerType(Exp->getType()),
+ SourceLocation());
+ InitExprs.push_back(Exp);
+ }
+ }
+ NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(),
+ FType, SourceLocation());
+ NewRep = new (Context) UnaryOperator(NewRep, UnaryOperator::AddrOf,
+ Context->getPointerType(NewRep->getType()),
+ SourceLocation());
+ NewRep = new (Context) CStyleCastExpr(FType, NewRep, FType, SourceLocation(),
+ SourceLocation());
+ BlockDeclRefs.clear();
+ BlockByRefDecls.clear();
+ BlockByCopyDecls.clear();
+ ImportedBlockDecls.clear();
+ return NewRep;
+}
+
+//===----------------------------------------------------------------------===//
+// Function Body / Expression rewriting
+//===----------------------------------------------------------------------===//
+
+// This is run as a first "pass" prior to RewriteFunctionBodyOrGlobalInitializer().
+// The allows the main rewrite loop to associate all ObjCPropertyRefExprs with
+// their respective BinaryOperator. Without this knowledge, we'd need to rewrite
+// the ObjCPropertyRefExpr twice (once as a getter, and later as a setter).
+// Since the rewriter isn't capable of rewriting rewritten code, it's important
+// we get this right.
+void RewriteObjC::CollectPropertySetters(Stmt *S) {
+ // Perform a bottom up traversal of all children.
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++CI)
+ if (*CI)
+ CollectPropertySetters(*CI);
+
+ if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
+ if (BinOp->isAssignmentOp()) {
+ if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(BinOp->getLHS()))
+ PropSetters[PRE] = BinOp;
+ }
+ }
+}
+
+Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
+ if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
+ isa<DoStmt>(S) || isa<ForStmt>(S))
+ Stmts.push_back(S);
+ else if (isa<ObjCForCollectionStmt>(S)) {
+ Stmts.push_back(S);
+ ObjCBcLabelNo.push_back(++BcLabelCount);
+ }
+
+ SourceRange OrigStmtRange = S->getSourceRange();
+
+ // Perform a bottom up rewrite of all children.
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++CI)
+ if (*CI) {
+ Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(*CI);
+ if (newStmt)
+ *CI = newStmt;
+ }
+
+ if (BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
+ // Rewrite the block body in place.
+ RewriteFunctionBodyOrGlobalInitializer(BE->getBody());
+
+ // Now we snarf the rewritten text and stash it away for later use.
+ std::string Str = Rewrite.getRewritenText(BE->getSourceRange());
+ RewrittenBlockExprs[BE] = Str;
+
+ Stmt *blockTranscribed = SynthBlockInitExpr(BE);
+ //blockTranscribed->dump();
+ ReplaceStmt(S, blockTranscribed);
+ return blockTranscribed;
+ }
+ // Handle specific things.
+ if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
+ return RewriteAtEncode(AtEncode);
+
+ if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S))
+ return RewriteObjCIvarRefExpr(IvarRefExpr, OrigStmtRange.getBegin());
+
+ if (ObjCPropertyRefExpr *PropRefExpr = dyn_cast<ObjCPropertyRefExpr>(S)) {
+ BinaryOperator *BinOp = PropSetters[PropRefExpr];
+ if (BinOp) {
+ // Because the rewriter doesn't allow us to rewrite rewritten code,
+ // we need to rewrite the right hand side prior to rewriting the setter.
+ DisableReplaceStmt = true;
+ // Save the source range. Even if we disable the replacement, the
+ // rewritten node will have been inserted into the tree. If the synthesized
+ // node is at the 'end', the rewriter will fail. Consider this:
+ // self.errorHandler = handler ? handler :
+ // ^(NSURL *errorURL, NSError *error) { return (BOOL)1; };
+ SourceRange SrcRange = BinOp->getSourceRange();
+ Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(BinOp->getRHS());
+ DisableReplaceStmt = false;
+ //
+ // Unlike the main iterator, we explicily avoid changing 'BinOp'. If
+ // we changed the RHS of BinOp, the rewriter would fail (since it needs
+ // to see the original expression). Consider this example:
+ //
+ // Foo *obj1, *obj2;
+ //
+ // obj1.i = [obj2 rrrr];
+ //
+ // 'BinOp' for the previous expression looks like:
+ //
+ // (BinaryOperator 0x231ccf0 'int' '='
+ // (ObjCPropertyRefExpr 0x231cc70 'int' Kind=PropertyRef Property="i"
+ // (DeclRefExpr 0x231cc50 'Foo *' Var='obj1' 0x231cbb0))
+ // (ObjCMessageExpr 0x231ccb0 'int' selector=rrrr
+ // (DeclRefExpr 0x231cc90 'Foo *' Var='obj2' 0x231cbe0)))
+ //
+ // 'newStmt' represents the rewritten message expression. For example:
+ //
+ // (CallExpr 0x231d300 'id':'struct objc_object *'
+ // (ParenExpr 0x231d2e0 'int (*)(id, SEL)'
+ // (CStyleCastExpr 0x231d2c0 'int (*)(id, SEL)'
+ // (CStyleCastExpr 0x231d220 'void *'
+ // (DeclRefExpr 0x231d200 'id (id, SEL, ...)' FunctionDecl='objc_msgSend' 0x231cdc0))))
+ //
+ // Note that 'newStmt' is passed to RewritePropertySetter so that it
+ // can be used as the setter argument. ReplaceStmt() will still 'see'
+ // the original RHS (since we haven't altered BinOp).
+ //
+ // This implies the Rewrite* routines can no longer delete the original
+ // node. As a result, we now leak the original AST nodes.
+ //
+ return RewritePropertySetter(BinOp, dyn_cast<Expr>(newStmt), SrcRange);
+ } else {
+ return RewritePropertyGetter(PropRefExpr);
+ }
+ }
+ if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
+ return RewriteAtSelector(AtSelector);
+
+ if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))
+ return RewriteObjCStringLiteral(AtString);
+
+ if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
+#if 0
+ // Before we rewrite it, put the original message expression in a comment.
+ SourceLocation startLoc = MessExpr->getLocStart();
+ SourceLocation endLoc = MessExpr->getLocEnd();
+
+ const char *startBuf = SM->getCharacterData(startLoc);
+ const char *endBuf = SM->getCharacterData(endLoc);
+
+ std::string messString;
+ messString += "// ";
+ messString.append(startBuf, endBuf-startBuf+1);
+ messString += "\n";
+
+ // FIXME: Missing definition of
+ // InsertText(clang::SourceLocation, char const*, unsigned int).
+ // InsertText(startLoc, messString.c_str(), messString.size());
+ // Tried this, but it didn't work either...
+ // ReplaceText(startLoc, 0, messString.c_str(), messString.size());
+#endif
+ return RewriteMessageExpr(MessExpr);
+ }
+
+ if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S))
+ return RewriteObjCTryStmt(StmtTry);
+
+ if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast<ObjCAtSynchronizedStmt>(S))
+ return RewriteObjCSynchronizedStmt(StmtTry);
+
+ if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S))
+ return RewriteObjCThrowStmt(StmtThrow);
+
+ if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S))
+ return RewriteObjCProtocolExpr(ProtocolExp);
+
+ if (ObjCForCollectionStmt *StmtForCollection =
+ dyn_cast<ObjCForCollectionStmt>(S))
+ return RewriteObjCForCollectionStmt(StmtForCollection,
+ OrigStmtRange.getEnd());
+ if (BreakStmt *StmtBreakStmt =
+ dyn_cast<BreakStmt>(S))
+ return RewriteBreakStmt(StmtBreakStmt);
+ if (ContinueStmt *StmtContinueStmt =
+ dyn_cast<ContinueStmt>(S))
+ return RewriteContinueStmt(StmtContinueStmt);
+
+ // Need to check for protocol refs (id <P>, Foo <P> *) in variable decls
+ // and cast exprs.
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+ // FIXME: What we're doing here is modifying the type-specifier that
+ // precedes the first Decl. In the future the DeclGroup should have
+ // a separate type-specifier that we can rewrite.
+ RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin());
+
+ // Blocks rewrite rules.
+ for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
+ DI != DE; ++DI) {
+ Decl *SD = *DI;
+ if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {
+ if (isTopLevelBlockPointerType(ND->getType()))
+ RewriteBlockPointerDecl(ND);
+ else if (ND->getType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(ND->getType(), ND);
+ }
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+ if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
+ RewriteBlockPointerDecl(TD);
+ else if (TD->getUnderlyingType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ }
+ }
+ }
+
+ if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S))
+ RewriteObjCQualifiedInterfaceTypes(CE);
+
+ if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
+ isa<DoStmt>(S) || isa<ForStmt>(S)) {
+ assert(!Stmts.empty() && "Statement stack is empty");
+ assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) ||
+ isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back()))
+ && "Statement stack mismatch");
+ Stmts.pop_back();
+ }
+ // Handle blocks rewriting.
+ if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
+ if (BDRE->isByRef())
+ return RewriteBlockDeclRefExpr(BDRE);
+ }
+ if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ if (CE->getCallee()->getType()->isBlockPointerType()) {
+ Stmt *BlockCall = SynthesizeBlockCall(CE);
+ ReplaceStmt(S, BlockCall);
+ return BlockCall;
+ }
+ }
+ if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S)) {
+ RewriteCastExpr(CE);
+ }
+#if 0
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) {
+ CastExpr *Replacement = new (Context) CastExpr(ICE->getType(), ICE->getSubExpr(), SourceLocation());
+ // Get the new text.
+ std::string SStr;
+ llvm::raw_string_ostream Buf(SStr);
+ Replacement->printPretty(Buf, *Context);
+ const std::string &Str = Buf.str();
+
+ printf("CAST = %s\n", &Str[0]);
+ InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size());
+ delete S;
+ return Replacement;
+ }
+#endif
+ // Return this stmt unmodified.
+ return S;
+}
+
+/// HandleDeclInMainFile - This is called for each top-level decl defined in the
+/// main file of the input.
+void RewriteObjC::HandleDeclInMainFile(Decl *D) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->isOverloadedOperator())
+ return;
+
+ // Since function prototypes don't have ParmDecl's, we check the function
+ // prototype. This enables us to rewrite function declarations and
+ // definitions using the same code.
+ RewriteBlocksInFunctionProtoType(FD->getType(), FD);
+
+ // FIXME: If this should support Obj-C++, support CXXTryStmt
+ if (CompoundStmt *Body = FD->getCompoundBody(*Context)) {
+ CurFunctionDef = FD;
+ CollectPropertySetters(Body);
+ CurrentBody = Body;
+ Body =
+ cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
+ FD->setBody(Body);
+ CurrentBody = 0;
+ if (PropParentMap) {
+ delete PropParentMap;
+ PropParentMap = 0;
+ }
+ // This synthesizes and inserts the block "impl" struct, invoke function,
+ // and any copy/dispose helper functions.
+ InsertBlockLiteralsWithinFunction(FD);
+ CurFunctionDef = 0;
+ }
+ return;
+ }
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (CompoundStmt *Body = MD->getBody()) {
+ CurMethodDef = MD;
+ CollectPropertySetters(Body);
+ CurrentBody = Body;
+ Body =
+ cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
+ MD->setBody(Body);
+ CurrentBody = 0;
+ if (PropParentMap) {
+ delete PropParentMap;
+ PropParentMap = 0;
+ }
+ InsertBlockLiteralsWithinMethod(MD);
+ CurMethodDef = 0;
+ }
+ }
+ if (ObjCImplementationDecl *CI = dyn_cast<ObjCImplementationDecl>(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 (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ RewriteObjCQualifiedInterfaceTypes(VD);
+ if (isTopLevelBlockPointerType(VD->getType()))
+ RewriteBlockPointerDecl(VD);
+ else if (VD->getType()->isFunctionPointerType()) {
+ CheckFunctionPointerDecl(VD->getType(), VD);
+ if (VD->getInit()) {
+ if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) {
+ RewriteCastExpr(CE);
+ }
+ }
+ }
+ if (VD->getInit()) {
+ GlobalVarDecl = VD;
+ CollectPropertySetters(VD->getInit());
+ CurrentBody = VD->getInit();
+ RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
+ CurrentBody = 0;
+ if (PropParentMap) {
+ delete PropParentMap;
+ PropParentMap = 0;
+ }
+ SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(),
+ VD->getNameAsCString());
+ GlobalVarDecl = 0;
+
+ // This is needed for blocks.
+ if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) {
+ RewriteCastExpr(CE);
+ }
+ }
+ return;
+ }
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
+ RewriteBlockPointerDecl(TD);
+ else if (TD->getUnderlyingType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ return;
+ }
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
+ if (RD->isDefinition()) {
+ for (RecordDecl::field_iterator i = RD->field_begin(*Context),
+ e = RD->field_end(*Context); i != e; ++i) {
+ FieldDecl *FD = *i;
+ if (isTopLevelBlockPointerType(FD->getType()))
+ RewriteBlockPointerDecl(FD);
+ }
+ }
+ return;
+ }
+ // Nothing yet.
+}
+
+void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
+ // Get the top-level buffer that this corresponds to.
+
+ // Rewrite tabs if we care.
+ //RewriteTabs();
+
+ if (Diags.hasErrorOccurred())
+ return;
+
+ RewriteInclude();
+
+ // Here's a great place to add any extra declarations that may be needed.
+ // Write out meta data for each @protocol(<expr>).
+ for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
+ E = ProtocolExprDecls.end(); I != E; ++I)
+ RewriteObjCProtocolMetaData(*I, "", "", Preamble);
+
+ InsertText(SM->getLocForStartOfFile(MainFileID),
+ Preamble.c_str(), Preamble.size(), false);
+ if (ClassImplementation.size() || CategoryImplementation.size())
+ RewriteImplementations();
+
+ // Get the buffer corresponding to MainFileID. If we haven't changed it, then
+ // we are done.
+ if (const RewriteBuffer *RewriteBuf =
+ Rewrite.getRewriteBufferFor(MainFileID)) {
+ //printf("Changed:\n");
+ *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
+ } else {
+ fprintf(stderr, "No changes\n");
+ }
+
+ if (ClassImplementation.size() || CategoryImplementation.size() ||
+ ProtocolExprDecls.size()) {
+ // Rewrite Objective-c meta data*
+ std::string ResultStr;
+ SynthesizeMetaDataIntoBuffer(ResultStr);
+ // Emit metadata.
+ *OutFile << ResultStr;
+ }
+ OutFile->flush();
+}
+
diff --git a/lib/Frontend/RewriteTest.cpp b/lib/Frontend/RewriteTest.cpp
new file mode 100644
index 000000000000..f9eb58f86740
--- /dev/null
+++ b/lib/Frontend/RewriteTest.cpp
@@ -0,0 +1,39 @@
+//===--- RewriteTest.cpp - Rewriter playground ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a testbed.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Rewrite/TokenRewriter.h"
+#include "llvm/Support/raw_ostream.h"
+
+void clang::DoRewriteTest(Preprocessor &PP, llvm::raw_ostream* OS) {
+ SourceManager &SM = PP.getSourceManager();
+ const LangOptions &LangOpts = PP.getLangOptions();
+
+ TokenRewriter Rewriter(SM.getMainFileID(), SM, LangOpts);
+
+ // Throw <i> </i> tags around comments.
+ for (TokenRewriter::token_iterator I = Rewriter.token_begin(),
+ E = Rewriter.token_end(); I != E; ++I) {
+ if (I->isNot(tok::comment)) continue;
+
+ Rewriter.AddTokenBefore(I, "<i>");
+ Rewriter.AddTokenAfter(I, "</i>");
+ }
+
+
+ // Print out the output.
+ for (TokenRewriter::token_iterator I = Rewriter.token_begin(),
+ E = Rewriter.token_end(); I != E; ++I)
+ *OS << PP.getSpelling(*I);
+}
diff --git a/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp
new file mode 100644
index 000000000000..c861881486b3
--- /dev/null
+++ b/lib/Frontend/StmtXML.cpp
@@ -0,0 +1,409 @@
+//===--- StmtXML.cpp - XML implementation for Stmt ASTs ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Stmt::dumpXML methods, which dump out the
+// AST to an XML document.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/DocumentXML.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/Compiler.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// StmtXML Visitor
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class VISIBILITY_HIDDEN StmtXML : public StmtVisitor<StmtXML> {
+ DocumentXML& Doc;
+
+ static const char *getOpcodeStr(UnaryOperator::Opcode Op);
+ static const char *getOpcodeStr(BinaryOperator::Opcode Op);
+
+ public:
+ StmtXML(DocumentXML& doc)
+ : Doc(doc) {
+ }
+
+ void DumpSubTree(Stmt *S) {
+ if (S)
+ {
+ Doc.addSubNode(S->getStmtClassName());
+ Doc.addLocationRange(S->getSourceRange());
+ if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
+ VisitDeclStmt(DS);
+ } else {
+ Visit(S);
+ for (Stmt::child_iterator i = S->child_begin(), e = S->child_end(); i != e; ++i)
+ {
+ DumpSubTree(*i);
+ }
+ }
+ Doc.toParent();
+ } else {
+ Doc.addSubNode("NULL").toParent();
+ }
+ }
+
+ void DumpTypeExpr(const QualType& T)
+ {
+ Doc.addSubNode("TypeExpr");
+ Doc.addTypeAttribute(T);
+ Doc.toParent();
+ }
+
+ void DumpExpr(const Expr *Node) {
+ Doc.addTypeAttribute(Node->getType());
+ }
+
+ // Stmts.
+ void VisitStmt(Stmt *Node);
+ void VisitDeclStmt(DeclStmt *Node);
+ void VisitLabelStmt(LabelStmt *Node);
+ void VisitGotoStmt(GotoStmt *Node);
+
+ // Exprs
+ void VisitExpr(Expr *Node);
+ void VisitDeclRefExpr(DeclRefExpr *Node);
+ void VisitPredefinedExpr(PredefinedExpr *Node);
+ void VisitCharacterLiteral(CharacterLiteral *Node);
+ void VisitIntegerLiteral(IntegerLiteral *Node);
+ void VisitFloatingLiteral(FloatingLiteral *Node);
+ void VisitStringLiteral(StringLiteral *Str);
+ void VisitUnaryOperator(UnaryOperator *Node);
+ void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node);
+ void VisitMemberExpr(MemberExpr *Node);
+ void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
+ void VisitBinaryOperator(BinaryOperator *Node);
+ void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
+ void VisitAddrLabelExpr(AddrLabelExpr *Node);
+ void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node);
+
+ // C++
+ void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
+ void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node);
+ void VisitCXXThisExpr(CXXThisExpr *Node);
+ void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node);
+
+ // ObjC
+ void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
+ void VisitObjCMessageExpr(ObjCMessageExpr* Node);
+ void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
+ void VisitObjCProtocolExpr(ObjCProtocolExpr *Node);
+ void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node);
+ void VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node);
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
+ void VisitObjCSuperExpr(ObjCSuperExpr *Node);
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// Stmt printing methods.
+//===----------------------------------------------------------------------===//
+
+void StmtXML::VisitStmt(Stmt *Node)
+{
+ // nothing special to do
+}
+
+void StmtXML::VisitDeclStmt(DeclStmt *Node)
+{
+ for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
+ DI != DE; ++DI)
+ {
+ Doc.PrintDecl(*DI);
+ }
+}
+
+void StmtXML::VisitLabelStmt(LabelStmt *Node)
+{
+ Doc.addAttribute("name", Node->getName());
+}
+
+void StmtXML::VisitGotoStmt(GotoStmt *Node)
+{
+ Doc.addAttribute("name", Node->getLabel()->getName());
+}
+
+//===----------------------------------------------------------------------===//
+// Expr printing methods.
+//===----------------------------------------------------------------------===//
+
+void StmtXML::VisitExpr(Expr *Node) {
+ DumpExpr(Node);
+}
+
+void StmtXML::VisitDeclRefExpr(DeclRefExpr *Node) {
+ DumpExpr(Node);
+
+ const char* pKind;
+ switch (Node->getDecl()->getKind()) {
+ case Decl::Function: pKind = "FunctionDecl"; break;
+ case Decl::Var: pKind = "Var"; break;
+ case Decl::ParmVar: pKind = "ParmVar"; break;
+ case Decl::EnumConstant: pKind = "EnumConstant"; break;
+ case Decl::Typedef: pKind = "Typedef"; break;
+ case Decl::Record: pKind = "Record"; break;
+ case Decl::Enum: pKind = "Enum"; break;
+ case Decl::CXXRecord: pKind = "CXXRecord"; break;
+ case Decl::ObjCInterface: pKind = "ObjCInterface"; break;
+ case Decl::ObjCClass: pKind = "ObjCClass"; break;
+ default: pKind = "Decl"; break;
+ }
+
+ Doc.addAttribute("kind", pKind);
+ Doc.addAttribute("name", Node->getDecl()->getNameAsString());
+ Doc.addRefAttribute(Node->getDecl());
+}
+
+void StmtXML::VisitPredefinedExpr(PredefinedExpr *Node) {
+ DumpExpr(Node);
+ switch (Node->getIdentType()) {
+ default: assert(0 && "unknown case");
+ case PredefinedExpr::Func: Doc.addAttribute("predefined", " __func__"); break;
+ case PredefinedExpr::Function: Doc.addAttribute("predefined", " __FUNCTION__"); break;
+ case PredefinedExpr::PrettyFunction: Doc.addAttribute("predefined", " __PRETTY_FUNCTION__");break;
+ }
+}
+
+void StmtXML::VisitCharacterLiteral(CharacterLiteral *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("value", Node->getValue());
+}
+
+void StmtXML::VisitIntegerLiteral(IntegerLiteral *Node) {
+ DumpExpr(Node);
+ bool isSigned = Node->getType()->isSignedIntegerType();
+ Doc.addAttribute("value", Node->getValue().toString(10, isSigned));
+}
+
+void StmtXML::VisitFloatingLiteral(FloatingLiteral *Node) {
+ DumpExpr(Node);
+ // FIXME: output float as written in source (no approximation or the like)
+ //Doc.addAttribute("value", Node->getValueAsApproximateDouble()));
+ Doc.addAttribute("value", "FIXME");
+}
+
+void StmtXML::VisitStringLiteral(StringLiteral *Str) {
+ DumpExpr(Str);
+ if (Str->isWide())
+ Doc.addAttribute("is_wide", "1");
+
+ Doc.addAttribute("value", Doc.escapeString(Str->getStrData(), Str->getByteLength()));
+}
+
+
+const char *StmtXML::getOpcodeStr(UnaryOperator::Opcode Op) {
+ switch (Op) {
+ default: assert(0 && "Unknown unary operator");
+ case UnaryOperator::PostInc: return "postinc";
+ case UnaryOperator::PostDec: return "postdec";
+ case UnaryOperator::PreInc: return "preinc";
+ case UnaryOperator::PreDec: return "predec";
+ case UnaryOperator::AddrOf: return "addrof";
+ case UnaryOperator::Deref: return "deref";
+ case UnaryOperator::Plus: return "plus";
+ case UnaryOperator::Minus: return "minus";
+ case UnaryOperator::Not: return "not";
+ case UnaryOperator::LNot: return "lnot";
+ case UnaryOperator::Real: return "__real";
+ case UnaryOperator::Imag: return "__imag";
+ case UnaryOperator::Extension: return "__extension__";
+ case UnaryOperator::OffsetOf: return "__builtin_offsetof";
+ }
+}
+
+
+const char *StmtXML::getOpcodeStr(BinaryOperator::Opcode Op) {
+ switch (Op) {
+ default: assert(0 && "Unknown binary operator");
+ case BinaryOperator::PtrMemD: return "ptrmemd";
+ case BinaryOperator::PtrMemI: return "ptrmemi";
+ case BinaryOperator::Mul: return "mul";
+ case BinaryOperator::Div: return "div";
+ case BinaryOperator::Rem: return "rem";
+ case BinaryOperator::Add: return "add";
+ case BinaryOperator::Sub: return "sub";
+ case BinaryOperator::Shl: return "shl";
+ case BinaryOperator::Shr: return "shr";
+ case BinaryOperator::LT: return "lt";
+ case BinaryOperator::GT: return "gt";
+ case BinaryOperator::LE: return "le";
+ case BinaryOperator::GE: return "ge";
+ case BinaryOperator::EQ: return "eq";
+ case BinaryOperator::NE: return "ne";
+ case BinaryOperator::And: return "and";
+ case BinaryOperator::Xor: return "xor";
+ case BinaryOperator::Or: return "or";
+ case BinaryOperator::LAnd: return "land";
+ case BinaryOperator::LOr: return "lor";
+ case BinaryOperator::Assign: return "assign";
+ case BinaryOperator::MulAssign: return "mulassign";
+ case BinaryOperator::DivAssign: return "divassign";
+ case BinaryOperator::RemAssign: return "remassign";
+ case BinaryOperator::AddAssign: return "addassign";
+ case BinaryOperator::SubAssign: return "subassign";
+ case BinaryOperator::ShlAssign: return "shlassign";
+ case BinaryOperator::ShrAssign: return "shrassign";
+ case BinaryOperator::AndAssign: return "andassign";
+ case BinaryOperator::XorAssign: return "xorassign";
+ case BinaryOperator::OrAssign: return "orassign";
+ case BinaryOperator::Comma: return "comma";
+ }
+}
+
+void StmtXML::VisitUnaryOperator(UnaryOperator *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode()));
+}
+
+void StmtXML::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("is_sizeof", Node->isSizeOf() ? "sizeof" : "alignof");
+ Doc.addAttribute("is_type", Node->isArgumentType() ? "1" : "0");
+ if (Node->isArgumentType())
+ {
+ DumpTypeExpr(Node->getArgumentType());
+ }
+}
+
+void StmtXML::VisitMemberExpr(MemberExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("is_deref", Node->isArrow() ? "1" : "0");
+ Doc.addAttribute("name", Node->getMemberDecl()->getNameAsString());
+ Doc.addRefAttribute(Node->getMemberDecl());
+}
+
+void StmtXML::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("name", Node->getAccessor().getName());
+}
+
+void StmtXML::VisitBinaryOperator(BinaryOperator *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode()));
+}
+
+void StmtXML::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
+ VisitBinaryOperator(Node);
+/* FIXME: is this needed in the AST?
+ DumpExpr(Node);
+ CurrentNode = CurrentNode->addSubNode("ComputeLHSTy");
+ DumpType(Node->getComputationLHSType());
+ CurrentNode = CurrentNode->Parent->addSubNode("ComputeResultTy");
+ DumpType(Node->getComputationResultType());
+ Doc.toParent();
+*/
+}
+
+// GNU extensions.
+
+void StmtXML::VisitAddrLabelExpr(AddrLabelExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("name", Node->getLabel()->getName());
+}
+
+void StmtXML::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
+ DumpExpr(Node);
+ DumpTypeExpr(Node->getArgType1());
+ DumpTypeExpr(Node->getArgType2());
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Expressions
+//===----------------------------------------------------------------------===//
+
+void StmtXML::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("kind", Node->getCastName());
+ DumpTypeExpr(Node->getTypeAsWritten());
+}
+
+void StmtXML::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("value", Node->getValue() ? "true" : "false");
+}
+
+void StmtXML::VisitCXXThisExpr(CXXThisExpr *Node) {
+ DumpExpr(Node);
+}
+
+void StmtXML::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
+ DumpExpr(Node);
+ DumpTypeExpr(Node->getTypeAsWritten());
+}
+
+//===----------------------------------------------------------------------===//
+// Obj-C Expressions
+//===----------------------------------------------------------------------===//
+
+void StmtXML::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("selector", Node->getSelector().getAsString());
+ IdentifierInfo* clsName = Node->getClassName();
+ if (clsName)
+ Doc.addAttribute("class", clsName->getName());
+}
+
+void StmtXML::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
+ DumpExpr(Node);
+ DumpTypeExpr(Node->getEncodedType());
+}
+
+void StmtXML::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("selector", Node->getSelector().getAsString());
+}
+
+void StmtXML::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("protocol", Node->getProtocol()->getNameAsString());
+}
+
+void StmtXML::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("property", Node->getProperty()->getNameAsString());
+}
+
+void StmtXML::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) {
+ DumpExpr(Node);
+ ObjCMethodDecl *Getter = Node->getGetterMethod();
+ ObjCMethodDecl *Setter = Node->getSetterMethod();
+ Doc.addAttribute("Getter", Getter->getSelector().getAsString());
+ Doc.addAttribute("Setter", Setter ? Setter->getSelector().getAsString().c_str() : "(null)");
+}
+
+void StmtXML::VisitObjCSuperExpr(ObjCSuperExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("super", "1");
+}
+
+void StmtXML::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
+ DumpExpr(Node);
+ Doc.addAttribute("kind", Node->getDecl()->getDeclKindName());
+ Doc.addAttribute("decl", Node->getDecl()->getNameAsString());
+ if (Node->isFreeIvar())
+ Doc.addAttribute("isFreeIvar", "1");
+}
+
+//===----------------------------------------------------------------------===//
+// Stmt method implementations
+//===----------------------------------------------------------------------===//
+
+/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
+void DocumentXML::PrintStmt(const Stmt *S) {
+ StmtXML P(*this);
+ P.DumpSubTree(const_cast<Stmt*>(S));
+}
+
diff --git a/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp
new file mode 100644
index 000000000000..a4518ee7e689
--- /dev/null
+++ b/lib/Frontend/TextDiagnosticBuffer.cpp
@@ -0,0 +1,39 @@
+//===--- TextDiagnosticBuffer.cpp - Buffer Text Diagnostics ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a concrete diagnostic client, which buffers the diagnostic messages.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "llvm/ADT/SmallString.h"
+using namespace clang;
+
+/// HandleDiagnostic - Store the errors, warnings, and notes that are
+/// reported.
+///
+void TextDiagnosticBuffer::HandleDiagnostic(Diagnostic::Level Level,
+ const DiagnosticInfo &Info) {
+ llvm::SmallString<100> StrC;
+ Info.FormatDiagnostic(StrC);
+ std::string Str(StrC.begin(), StrC.end());
+ switch (Level) {
+ default: assert(0 && "Diagnostic not handled during diagnostic buffering!");
+ case Diagnostic::Note:
+ Notes.push_back(std::make_pair(Info.getLocation(), Str));
+ break;
+ case Diagnostic::Warning:
+ Warnings.push_back(std::make_pair(Info.getLocation(), Str));
+ break;
+ case Diagnostic::Error:
+ case Diagnostic::Fatal:
+ Errors.push_back(std::make_pair(Info.getLocation(), Str));
+ break;
+ }
+}
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
new file mode 100644
index 000000000000..b1c05336c239
--- /dev/null
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -0,0 +1,710 @@
+//===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This diagnostic client prints out their diagnostic messages.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/SmallString.h"
+#include <algorithm>
+using namespace clang;
+
+/// \brief Number of spaces to indent when word-wrapping.
+const unsigned WordWrapIndentation = 6;
+
+void TextDiagnosticPrinter::
+PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) {
+ if (Loc.isInvalid()) return;
+
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+
+ // Print out the other include frames first.
+ PrintIncludeStack(PLoc.getIncludeLoc(), SM);
+
+ 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 SourceRange &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 #.
+ }
+
+ // Pick the first non-whitespace column.
+ while (StartColNo < SourceLine.size() &&
+ (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
+ ++StartColNo;
+
+ // 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.
+ EndColNo += Lexer::MeasureTokenLength(End, SM, *LangOpts);
+ } else {
+ EndColNo = CaretLine.size();
+ }
+ }
+
+ // Pick the last non-whitespace column.
+ if (EndColNo <= SourceLine.size())
+ while (EndColNo-1 &&
+ (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
+ --EndColNo;
+ else
+ EndColNo = SourceLine.size();
+
+ // Fill the range with ~'s.
+ assert(StartColNo <= EndColNo && "Invalid range!");
+ for (unsigned i = StartColNo; i < EndColNo; ++i)
+ CaretLine[i] = '~';
+}
+
+/// \brief When the source code line we want to print is too long for
+/// the terminal, select the "interesting" region.
+static void SelectInterestingSourceRegion(std::string &SourceLine,
+ std::string &CaretLine,
+ std::string &FixItInsertionLine,
+ unsigned EndOfCaretToken,
+ unsigned Columns) {
+ if (CaretLine.size() > SourceLine.size())
+ SourceLine.resize(CaretLine.size(), ' ');
+
+ // Find the slice that we need to display the full caret line
+ // correctly.
+ unsigned CaretStart = 0, CaretEnd = CaretLine.size();
+ for (; CaretStart != CaretEnd; ++CaretStart)
+ if (!isspace(CaretLine[CaretStart]))
+ break;
+
+ for (; CaretEnd != CaretStart; --CaretEnd)
+ if (!isspace(CaretLine[CaretEnd - 1]))
+ break;
+
+ // Make sure we don't chop the string shorter than the caret token
+ // itself.
+ if (CaretEnd < EndOfCaretToken)
+ CaretEnd = EndOfCaretToken;
+
+ // If we have a fix-it line, make sure the slice includes all of the
+ // fix-it information.
+ if (!FixItInsertionLine.empty()) {
+ unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size();
+ for (; FixItStart != FixItEnd; ++FixItStart)
+ if (!isspace(FixItInsertionLine[FixItStart]))
+ break;
+
+ for (; FixItEnd != FixItStart; --FixItEnd)
+ if (!isspace(FixItInsertionLine[FixItEnd - 1]))
+ break;
+
+ if (FixItStart < CaretStart)
+ CaretStart = FixItStart;
+ if (FixItEnd > CaretEnd)
+ CaretEnd = FixItEnd;
+ }
+
+ // CaretLine[CaretStart, CaretEnd) contains all of the interesting
+ // parts of the caret line. While this slice is smaller than the
+ // number of columns we have, try to grow the slice to encompass
+ // more context.
+
+ // If the end of the interesting region comes before we run out of
+ // space in the terminal, start at the beginning of the line.
+ if (Columns > 3 && CaretEnd < Columns - 3)
+ CaretStart = 0;
+
+ unsigned TargetColumns = Columns;
+ if (TargetColumns > 8)
+ TargetColumns -= 8; // Give us extra room for the ellipses.
+ unsigned SourceLength = SourceLine.size();
+ while ((CaretEnd - CaretStart) < TargetColumns) {
+ bool ExpandedRegion = false;
+ // Move the start of the interesting region left until we've
+ // pulled in something else interesting.
+ if (CaretStart == 1)
+ CaretStart = 0;
+ else if (CaretStart > 1) {
+ unsigned NewStart = CaretStart - 1;
+
+ // Skip over any whitespace we see here; we're looking for
+ // another bit of interesting text.
+ while (NewStart && isspace(SourceLine[NewStart]))
+ --NewStart;
+
+ // Skip over this bit of "interesting" text.
+ while (NewStart && !isspace(SourceLine[NewStart]))
+ --NewStart;
+
+ // Move up to the non-whitespace character we just saw.
+ if (NewStart)
+ ++NewStart;
+
+ // If we're still within our limit, update the starting
+ // position within the source/caret line.
+ if (CaretEnd - NewStart <= TargetColumns) {
+ CaretStart = NewStart;
+ ExpandedRegion = true;
+ }
+ }
+
+ // Move the end of the interesting region right until we've
+ // pulled in something else interesting.
+ if (CaretEnd != SourceLength) {
+ unsigned NewEnd = CaretEnd;
+
+ // Skip over any whitespace we see here; we're looking for
+ // another bit of interesting text.
+ while (NewEnd != SourceLength && isspace(SourceLine[NewEnd - 1]))
+ ++NewEnd;
+
+ // Skip over this bit of "interesting" text.
+ while (NewEnd != SourceLength && !isspace(SourceLine[NewEnd - 1]))
+ ++NewEnd;
+
+ if (NewEnd - CaretStart <= TargetColumns) {
+ CaretEnd = NewEnd;
+ ExpandedRegion = true;
+ }
+ }
+
+ if (!ExpandedRegion)
+ break;
+ }
+
+ // [CaretStart, CaretEnd) is the slice we want. Update the various
+ // output lines to show only this slice, with two-space padding
+ // before the lines so that it looks nicer.
+ if (CaretEnd < SourceLine.size())
+ SourceLine.replace(CaretEnd, std::string::npos, "...");
+ if (CaretEnd < CaretLine.size())
+ CaretLine.erase(CaretEnd, std::string::npos);
+ if (FixItInsertionLine.size() > CaretEnd)
+ FixItInsertionLine.erase(CaretEnd, std::string::npos);
+
+ if (CaretStart > 2) {
+ SourceLine.replace(0, CaretStart, " ...");
+ CaretLine.replace(0, CaretStart, " ");
+ if (FixItInsertionLine.size() >= CaretStart)
+ FixItInsertionLine.replace(0, CaretStart, " ");
+ }
+}
+
+void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
+ SourceRange *Ranges,
+ unsigned NumRanges,
+ SourceManager &SM,
+ const CodeModificationHint *Hints,
+ unsigned NumHints,
+ unsigned Columns) {
+ assert(!Loc.isInvalid() && "must have a valid source location here");
+
+ // If this is a macro ID, first emit information about where this was
+ // instantiated (recursively) then emit information about where. the token was
+ // spelled from.
+ if (!Loc.isFileID()) {
+ SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first;
+ // FIXME: Map ranges?
+ EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns);
+
+ Loc = SM.getImmediateSpellingLoc(Loc);
+
+ // Map the ranges.
+ for (unsigned i = 0; i != NumRanges; ++i) {
+ SourceLocation S = Ranges[i].getBegin(), E = Ranges[i].getEnd();
+ if (S.isMacroID()) S = SM.getImmediateSpellingLoc(S);
+ if (E.isMacroID()) E = SM.getImmediateSpellingLoc(E);
+ Ranges[i] = SourceRange(S, E);
+ }
+
+ if (ShowLocation) {
+ std::pair<FileID, unsigned> IInfo = SM.getDecomposedInstantiationLoc(Loc);
+
+ // Emit the file/line/column that this expansion came from.
+ OS << SM.getBuffer(IInfo.first)->getBufferIdentifier() << ':'
+ << SM.getLineNumber(IInfo.first, IInfo.second) << ':';
+ if (ShowColumn)
+ OS << SM.getColumnNumber(IInfo.first, IInfo.second) << ':';
+ OS << ' ';
+ }
+ OS << "note: instantiated from:\n";
+
+ EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, Hints, NumHints, Columns);
+ 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.
+ std::pair<const char*, const char*> BufferInfo = SM.getBufferData(FID);
+ const char *BufStart = BufferInfo.first;
+
+ 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;
+
+ // 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.
+ if (NumRanges) {
+ unsigned LineNo = SM.getLineNumber(FID, FileOffset);
+
+ for (unsigned i = 0, e = NumRanges; i != e; ++i)
+ HighlightRange(Ranges[i], SM, LineNo, FID, CaretLine, SourceLine);
+ }
+
+ // 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 8 characters 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 NumSpaces = ((i+8)&~7) - (i+1);
+ assert(NumSpaces < 8 && "Invalid computation of space amt");
+
+ // Insert spaces into the SourceLine.
+ SourceLine.insert(i+1, NumSpaces, ' ');
+
+ // Insert spaces or ~'s into CaretLine.
+ CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' ');
+ }
+
+ // 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 (PrintRangeInfo) {
+ SourceLine = ' ' + SourceLine;
+ CaretLine = ' ' + CaretLine;
+ }
+
+ std::string FixItInsertionLine;
+ if (NumHints && PrintFixItInfo) {
+ for (const CodeModificationHint *Hint = Hints, *LastHint = Hints + NumHints;
+ Hint != LastHint; ++Hint) {
+ if (Hint->InsertionLoc.isValid()) {
+ // 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->InsertionLoc);
+ if (SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) ==
+ SM.getLineNumber(FID, FileOffset)) {
+ // 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();
+ if (LastColumnModified > FixItInsertionLine.size())
+ FixItInsertionLine.resize(LastColumnModified, ' ');
+ std::copy(Hint->CodeToInsert.begin(), Hint->CodeToInsert.end(),
+ FixItInsertionLine.begin() + HintColNo - 1);
+ } else {
+ FixItInsertionLine.clear();
+ break;
+ }
+ }
+ }
+ }
+
+ // 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);
+
+ // Finally, remove any blank spaces from the end of CaretLine.
+ while (CaretLine[CaretLine.size()-1] == ' ')
+ CaretLine.erase(CaretLine.end()-1);
+
+ // Emit what we have computed.
+ OS << SourceLine << '\n';
+ OS << CaretLine << '\n';
+
+ if (!FixItInsertionLine.empty()) {
+ if (PrintRangeInfo)
+ OS << ' ';
+ OS << FixItInsertionLine << '\n';
+ }
+}
+
+/// \brief Skip over whitespace in the string, starting at the given
+/// index.
+///
+/// \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) {
+ while (Idx < Length && isspace(Str[Idx]))
+ ++Idx;
+ return Idx;
+}
+
+/// \brief If the given character is the start of some kind of
+/// balanced punctuation (e.g., quotes or parentheses), return the
+/// character that will terminate the punctuation.
+///
+/// \returns The ending punctuation character, if any, or the NULL
+/// character if the input character does not start any punctuation.
+static inline char findMatchingPunctuation(char c) {
+ switch (c) {
+ case '\'': return '\'';
+ case '`': return '\'';
+ case '"': return '"';
+ case '(': return ')';
+ case '[': return ']';
+ case '{': return '}';
+ default: break;
+ }
+
+ return 0;
+}
+
+/// \brief Find the end of the word starting at the given offset
+/// within a string.
+///
+/// \returns the index pointing one character past the end of the
+/// word.
+unsigned findEndOfWord(unsigned Start,
+ const llvm::SmallVectorImpl<char> &Str,
+ unsigned Length, unsigned Column,
+ unsigned Columns) {
+ unsigned End = Start + 1;
+
+ // Determine if the start of the string is actually opening
+ // punctuation, e.g., a quote or parentheses.
+ char EndPunct = findMatchingPunctuation(Str[Start]);
+ if (!EndPunct) {
+ // This is a normal word. Just find the first space character.
+ while (End < Length && !isspace(Str[End]))
+ ++End;
+ return End;
+ }
+
+ // We have the start of a balanced punctuation sequence (quotes,
+ // parentheses, etc.). Determine the full sequence is.
+ llvm::SmallVector<char, 16> PunctuationEndStack;
+ PunctuationEndStack.push_back(EndPunct);
+ while (End < Length && !PunctuationEndStack.empty()) {
+ if (Str[End] == PunctuationEndStack.back())
+ PunctuationEndStack.pop_back();
+ else if (char SubEndPunct = findMatchingPunctuation(Str[End]))
+ PunctuationEndStack.push_back(SubEndPunct);
+
+ ++End;
+ }
+
+ // Find the first space character after the punctuation ended.
+ while (End < Length && !isspace(Str[End]))
+ ++End;
+
+ unsigned PunctWordLength = End - Start;
+ if (// If the word fits on this line
+ Column + PunctWordLength <= Columns ||
+ // ... or the word is "short enough" to take up the next line
+ // without too much ugly white space
+ PunctWordLength < Columns/3)
+ return End; // Take the whole thing as a single "word".
+
+ // The whole quoted/parenthesized string is too long to print as a
+ // single "word". Instead, find the "word" that starts just after
+ // the punctuation and use that end-point instead. This will recurse
+ // until it finds something small enough to consider a word.
+ return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns);
+}
+
+/// \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
+/// 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
+/// 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
+/// 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,
+ 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;
+ }
+
+ // The string used to indent each line.
+ llvm::SmallString<16> IndentStr;
+ IndentStr.assign(Indentation, ' ');
+ bool Wrapped = false;
+ for (unsigned WordStart = 0, WordEnd; WordStart < Length;
+ WordStart = WordEnd) {
+ // Find the beginning of the next word.
+ WordStart = skipWhitespace(WordStart, Str, Length);
+ if (WordStart == Length)
+ break;
+
+ // Find the end of this word.
+ WordEnd = findEndOfWord(WordStart, Str, Length, Column, Columns);
+
+ // Does this word fit on the current line?
+ unsigned WordLength = WordEnd - WordStart;
+ if (Column + WordLength < Columns) {
+ // This word fits on the current line; print it there.
+ if (WordStart) {
+ OS << ' ';
+ Column += 1;
+ }
+ OS.write(&Str[WordStart], WordLength);
+ Column += WordLength;
+ continue;
+ }
+
+ // This word does not fit on the current line, so wrap to the next
+ // line.
+ OS << '\n';
+ OS.write(&IndentStr[0], Indentation);
+ OS.write(&Str[WordStart], WordLength);
+ Column = Indentation + WordLength;
+ Wrapped = true;
+ }
+
+ if (Length == Str.size())
+ return Wrapped; // We're done.
+
+ // 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;
+}
+
+void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
+ const DiagnosticInfo &Info) {
+ // Keeps track of the the starting position of the location
+ // information (e.g., "foo.c:10:4:") that precedes the error
+ // message. We use this information to determine how long the
+ // file+line+column number prefix is.
+ uint64_t StartOfLocationInfo = OS.tell();
+
+ // If the location is specified, print out a file/line/col and include trace
+ // if enabled.
+ if (Info.getLocation().isValid()) {
+ const SourceManager &SM = Info.getLocation().getManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
+ 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(LastWarningLoc, SM);
+ StartOfLocationInfo = OS.tell();
+ }
+
+ // Compute the column number.
+ if (ShowLocation) {
+ OS << PLoc.getFilename() << ':' << LineNo << ':';
+ if (ShowColumn)
+ if (unsigned ColNo = PLoc.getColumn())
+ OS << ColNo << ':';
+
+ if (PrintRangeInfo && 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();
+ std::pair<FileID, unsigned> BInfo=SM.getDecomposedInstantiationLoc(B);
+
+ E = SM.getInstantiationLoc(E);
+ 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 = 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 << ' ';
+ }
+ }
+
+ 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;
+ }
+
+ llvm::SmallString<100> OutStr;
+ Info.FormatDiagnostic(OutStr);
+
+ if (PrintDiagnosticOption)
+ if (const char *Opt = Diagnostic::getWarningOptionForDiag(Info.getID())) {
+ OutStr += " [-W";
+ OutStr += Opt;
+ OutStr += ']';
+ }
+
+ if (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, MessageLength, Column);
+ } else {
+ OS.write(OutStr.begin(), OutStr.size());
+ }
+ OS << '\n';
+
+ // 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 (CaretDiagnostics && Info.getLocation().isValid() &&
+ ((LastLoc != Info.getLocation()) || Info.getNumRanges() ||
+ (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) ||
+ Info.getNumCodeModificationHints())) {
+ // Cache the LastLoc, it allows us to omit duplicate source/caret spewage.
+ LastLoc = Info.getLocation();
+ LastCaretDiagnosticWasNote = (Level == Diagnostic::Note);
+
+ // Get the ranges into a local array we can hack on.
+ SourceRange 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.getNumCodeModificationHints();
+ for (unsigned idx = 0; idx < NumHints; ++idx) {
+ const CodeModificationHint &Hint = Info.getCodeModificationHint(idx);
+ if (Hint.RemoveRange.isValid()) {
+ assert(NumRanges < 20 && "Out of space");
+ Ranges[NumRanges++] = Hint.RemoveRange;
+ }
+ }
+
+ EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(),
+ Info.getCodeModificationHints(),
+ Info.getNumCodeModificationHints(),
+ MessageLength);
+ }
+
+ OS.flush();
+}
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
new file mode 100644
index 000000000000..81f75bdf755c
--- /dev/null
+++ b/lib/Frontend/Warnings.cpp
@@ -0,0 +1,106 @@
+//===--- Warnings.cpp - C-Language Front-end ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Command line warning options handler.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is responsible for handling all warning options. This includes
+// a number of -Wfoo options and their variants, which are driven by TableGen-
+// generated data, and the special cases -pedantic, -pedantic-errors, -w and
+// -Werror.
+//
+// Each warning option controls any number of actual warnings.
+// Given a warning option 'foo', the following are valid:
+// -Wfoo, -Wno-foo, -Werror=foo
+//
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include <cstdio>
+#include <cstring>
+#include <utility>
+#include <algorithm>
+using namespace clang;
+
+bool clang::ProcessWarningOptions(Diagnostic &Diags,
+ std::vector<std::string> &Warnings,
+ bool Pedantic, bool PedanticErrors,
+ bool NoWarnings) {
+ Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
+ Diags.setIgnoreAllWarnings(NoWarnings);
+
+ // If -pedantic or -pedantic-errors was specified, then we want to map all
+ // extension diagnostics onto WARNING or ERROR unless the user has futz'd
+ // around with them explicitly.
+ if (PedanticErrors)
+ Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Error);
+ else if (Pedantic)
+ Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Warn);
+ else
+ Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore);
+
+ // FIXME: -Wfatal-errors / -Wfatal-errors=foo
+
+ for (unsigned i = 0, e = Warnings.size(); i != e; ++i) {
+ const std::string &Opt = Warnings[i];
+ const char *OptStart = &Opt[0];
+ const char *OptEnd = OptStart+Opt.size();
+ assert(*OptEnd == 0 && "Expect null termination for lower-bound search");
+
+ // Check to see if this warning starts with "no-", if so, this is a negative
+ // form of the option.
+ bool isPositive = true;
+ if (OptEnd-OptStart > 3 && memcmp(OptStart, "no-", 3) == 0) {
+ isPositive = false;
+ OptStart += 3;
+ }
+
+ // Figure out how this option affects the warning. If -Wfoo, map the
+ // diagnostic to a warning, if -Wno-foo, map it to ignore.
+ diag::Mapping Mapping = isPositive ? diag::MAP_WARNING : diag::MAP_IGNORE;
+
+ // -Wsystem-headers is a special case, not driven by the option table. It
+ // cannot be controlled with -Werror.
+ if (OptEnd-OptStart == 14 && memcmp(OptStart, "system-headers", 14) == 0) {
+ Diags.setSuppressSystemWarnings(!isPositive);
+ 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 (OptEnd-OptStart >= 5 && memcmp(OptStart, "error", 5) == 0) {
+ const char *Specifier = 0;
+ if (OptEnd-OptStart != 5) { // Specifier must be present.
+ if ((OptStart[5] != '=' && OptStart[5] != '-') ||
+ OptEnd-OptStart == 6) {
+ fprintf(stderr, "warning: unknown -Werror warning specifier: -W%s\n",
+ Opt.c_str());
+ continue;
+ }
+ Specifier = OptStart+6;
+ }
+
+ if (Specifier == 0) {
+ Diags.setWarningsAsErrors(true);
+ continue;
+ }
+
+ // -Werror=foo maps foo to Error, -Wno-error=foo maps it to Warning.
+ Mapping = isPositive ? diag::MAP_ERROR : diag::MAP_WARNING_NO_WERROR;
+ OptStart = Specifier;
+ }
+
+ if (Diags.setDiagnosticGroupMapping(OptStart, Mapping))
+ fprintf(stderr, "warning: unknown warning option: -W%s\n", Opt.c_str());
+ }
+
+ return false;
+}
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
new file mode 100644
index 000000000000..3c42167e5a18
--- /dev/null
+++ b/lib/Headers/CMakeLists.txt
@@ -0,0 +1,25 @@
+set(files
+ iso646.h
+ mmintrin.h
+ stdarg.h
+ stdbool.h
+ stddef.h
+ )
+
+set(output_dir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/../Headers)
+
+foreach( f ${files} )
+ set( src ${CMAKE_CURRENT_SOURCE_DIR}/${f} )
+ set( dst ${output_dir}/${f} )
+ add_custom_command(OUTPUT ${dst}
+ DEPENDS ${src}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
+ COMMENT "Copying clang's ${f}...")
+endforeach( f )
+
+add_custom_target(clang_headers ALL
+ DEPENDS ${files})
+
+install(FILES ${files}
+ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
+ DESTINATION Headers)
diff --git a/lib/Headers/Makefile b/lib/Headers/Makefile
new file mode 100644
index 000000000000..77eb96dc4dc4
--- /dev/null
+++ b/lib/Headers/Makefile
@@ -0,0 +1,40 @@
+##===- clang/lib/Headers/Makefile --------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+include $(LEVEL)/Makefile.common
+
+# FIXME: Get version from a common place.
+HeaderDir := $(PROJ_OBJ_ROOT)/$(BuildMode)/lib/clang/1.0/include
+
+HEADERS := $(notdir $(wildcard $(PROJ_SRC_DIR)/*.h))
+
+OBJHEADERS := $(addprefix $(HeaderDir)/, $(HEADERS))
+
+
+$(OBJHEADERS): $(HeaderDir)/%.h: $(PROJ_SRC_DIR)/%.h $(HeaderDir)/.dir
+ $(Verb) cp $< $@
+ $(Echo) Copying $(notdir $<) to build dir
+
+# Hook into the standard Makefile rules.
+all-local:: $(OBJHEADERS)
+
+PROJ_headers := $(DESTDIR)$(PROJ_prefix)/lib/clang/1.0/include
+
+INSTHEADERS := $(addprefix $(PROJ_headers)/, $(HEADERS))
+
+$(PROJ_headers):
+ $(Verb) $(MKDIR) $@
+
+$(INSTHEADERS): $(PROJ_headers)/%.h: $(HeaderDir)/%.h | $(PROJ_headers)
+ $(Verb) $(DataInstall) $< $(PROJ_headers)
+ $(Echo) Installing compiler include file: $(notdir $<)
+
+install-local:: $(INSTHEADERS)
+
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
new file mode 100644
index 000000000000..c96000aa1b76
--- /dev/null
+++ b/lib/Headers/emmintrin.h
@@ -0,0 +1,1329 @@
+/*===---- xmmintrin.h - SSE intrinsics -------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __EMMINTRIN_H
+#define __EMMINTRIN_H
+
+#ifndef __SSE2__
+#error "SSE2 instruction set not enabled"
+#else
+
+#include <xmmintrin.h>
+
+typedef double __m128d __attribute__((__vector_size__(16)));
+typedef long long __m128i __attribute__((__vector_size__(16)));
+
+typedef int __v4si __attribute__((__vector_size__(16)));
+typedef short __v8hi __attribute__((__vector_size__(16)));
+typedef char __v16qi __attribute__((__vector_size__(16)));
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_add_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_addsd(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_add_pd(__m128d a, __m128d b)
+{
+ return a + b;
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_sub_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_subsd(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_sub_pd(__m128d a, __m128d b)
+{
+ return a - b;
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_mul_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_mulsd(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_mul_pd(__m128d a, __m128d b)
+{
+ return a * b;
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_div_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_divsd(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_div_pd(__m128d a, __m128d b)
+{
+ return a / b;
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_sqrt_sd(__m128d a, __m128d b)
+{
+ __m128d c = __builtin_ia32_sqrtsd(b);
+ return (__m128d) { c[0], a[1] };
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_sqrt_pd(__m128d a)
+{
+ return __builtin_ia32_sqrtpd(a);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_min_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_minsd(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_min_pd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_minpd(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_max_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_maxsd(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_max_pd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_maxpd(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_and_pd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_andpd(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_andnot_pd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_andnpd(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_or_pd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_orpd(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_xor_pd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_xorpd(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpeq_pd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmppd(a, b, 0);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmplt_pd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmppd(a, b, 1);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmple_pd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmppd(a, b, 2);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpgt_pd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmppd(b, a, 1);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpge_pd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmppd(b, a, 2);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpord_pd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmppd(a, b, 7);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpunord_pd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmppd(a, b, 3);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpneq_pd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmppd(a, b, 4);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpnlt_pd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmppd(a, b, 5);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpnle_pd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmppd(a, b, 6);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpngt_pd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmppd(b, a, 5);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpnge_pd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmppd(b, a, 6);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpeq_sd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmpsd(a, b, 0);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmplt_sd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmpsd(a, b, 1);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmple_sd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmpsd(a, b, 2);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpgt_sd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmpsd(b, a, 1);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpge_sd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmpsd(b, a, 2);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpord_sd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmpsd(a, b, 7);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpunord_sd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmpsd(a, b, 3);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpneq_sd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmpsd(a, b, 4);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpnlt_sd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmpsd(a, b, 5);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpnle_sd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmpsd(a, b, 6);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpngt_sd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmpsd(b, a, 5);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cmpnge_sd(__m128d a, __m128d b)
+{
+ return (__m128d)__builtin_ia32_cmpsd(b, a, 6);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_comieq_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_comisdeq(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_comilt_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_comisdlt(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_comile_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_comisdle(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_comigt_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_comisdgt(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_comineq_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_comisdneq(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_ucomieq_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_ucomisdeq(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_ucomilt_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_ucomisdlt(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_ucomile_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_ucomisdle(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_ucomigt_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_ucomisdgt(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_ucomineq_sd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_ucomisdneq(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtpd_ps(__m128d a)
+{
+ return __builtin_ia32_cvtpd2ps(a);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cvtps_pd(__m128 a)
+{
+ return __builtin_ia32_cvtps2pd(a);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cvtepi32_pd(__m128i a)
+{
+ return __builtin_ia32_cvtdq2pd((__v4si)a);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtpd_epi32(__m128d a)
+{
+ return __builtin_ia32_cvtpd2dq(a);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_cvtsd_si32(__m128d a)
+{
+ return __builtin_ia32_cvtsd2si(a);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtsd_ss(__m128 a, __m128d b)
+{
+ return __builtin_ia32_cvtsd2ss(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cvtsi32_sd(__m128d a, int b)
+{
+ return __builtin_ia32_cvtsi2sd(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cvtss_sd(__m128d a, __m128 b)
+{
+ return __builtin_ia32_cvtss2sd(a, b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvttpd_epi32(__m128d a)
+{
+ return (__m128i)__builtin_ia32_cvttpd2dq(a);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_cvttsd_si32(__m128d a)
+{
+ return __builtin_ia32_cvttsd2si(a);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtpd_pi32(__m128d a)
+{
+ return (__m64)__builtin_ia32_cvtpd2pi(a);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_cvttpd_pi32(__m128d a)
+{
+ return (__m64)__builtin_ia32_cvttpd2pi(a);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cvtpi32_pd(__m64 a)
+{
+ return __builtin_ia32_cvtpi2pd((__v2si)a);
+}
+
+static inline double __attribute__((__always_inline__, __nodebug__))
+_mm_cvtsd_f64(__m128d a)
+{
+ return a[0];
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_load_pd(double const *dp)
+{
+ return *(__m128d*)dp;
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_load1_pd(double const *dp)
+{
+ return (__m128d){ dp[0], dp[0] };
+}
+
+#define _mm_load_pd1(dp) _mm_load1_pd(dp)
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_loadr_pd(double const *dp)
+{
+ return (__m128d){ dp[1], dp[0] };
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_loadu_pd(double const *dp)
+{
+ return __builtin_ia32_loadupd(dp);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_load_sd(double const *dp)
+{
+ return (__m128d){ *dp, 0.0 };
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_loadh_pd(__m128d a, double const *dp)
+{
+ return __builtin_shufflevector(a, *(__m128d *)dp, 0, 2);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_loadl_pd(__m128d a, double const *dp)
+{
+ return __builtin_shufflevector(a, *(__m128d *)dp, 2, 1);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_set_sd(double w)
+{
+ return (__m128d){ w, 0 };
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_set1_pd(double w)
+{
+ return (__m128d){ w, w };
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_set_pd(double w, double x)
+{
+ return (__m128d){ w, x };
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_setr_pd(double w, double x)
+{
+ return (__m128d){ x, w };
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_setzero_pd(void)
+{
+ return (__m128d){ 0, 0 };
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_move_sd(__m128d a, __m128d b)
+{
+ return (__m128d){ b[0], a[1] };
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_store_sd(double *dp, __m128d a)
+{
+ dp[0] = a[0];
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_store1_pd(double *dp, __m128d a)
+{
+ dp[0] = a[0];
+ dp[1] = a[0];
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_store_pd(double *dp, __m128d a)
+{
+ *(__m128d *)dp = a;
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_storeu_pd(double *dp, __m128d a)
+{
+ __builtin_ia32_storeupd(dp, a);
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_storer_pd(double *dp, __m128d a)
+{
+ dp[0] = a[1];
+ dp[1] = a[0];
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_storeh_pd(double *dp, __m128d a)
+{
+ dp[0] = a[1];
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_storel_pd(double *dp, __m128d a)
+{
+ dp[0] = a[0];
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_add_epi8(__m128i a, __m128i b)
+{
+ return (__m128i)((__v16qi)a + (__v16qi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_add_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)((__v8hi)a + (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_add_epi32(__m128i a, __m128i b)
+{
+ return (__m128i)((__v4si)a + (__v4si)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_add_si64(__m64 a, __m64 b)
+{
+ return a + b;
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_add_epi64(__m128i a, __m128i b)
+{
+ return a + b;
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_adds_epi8(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_paddsb128((__v16qi)a, (__v16qi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_adds_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_paddsw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_adds_epu8(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_paddusb128((__v16qi)a, (__v16qi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_adds_epu16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_paddusw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_avg_epu8(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pavgb128((__v16qi)a, (__v16qi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_avg_epu16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pavgw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_madd_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pmaddwd128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_max_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pmaxsw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_max_epu8(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pmaxub128((__v16qi)a, (__v16qi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_min_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pminsw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_min_epu8(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pminub128((__v16qi)a, (__v16qi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_mulhi_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pmulhw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_mulhi_epu16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pmulhuw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_mullo_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pmullw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_mul_su32(__m64 a, __m64 b)
+{
+ return __builtin_ia32_pmuludq((__v2si)a, (__v2si)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_mul_epu32(__m128i a, __m128i b)
+{
+ return __builtin_ia32_pmuludq128((__v4si)a, (__v4si)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sad_epu8(__m128i a, __m128i b)
+{
+ return __builtin_ia32_psadbw128((__v16qi)a, (__v16qi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sub_epi8(__m128i a, __m128i b)
+{
+ return (__m128i)((__v16qi)a - (__v16qi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sub_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)((__v8hi)a - (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sub_epi32(__m128i a, __m128i b)
+{
+ return (__m128i)((__v4si)a - (__v4si)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_sub_si64(__m64 a, __m64 b)
+{
+ return a - b;
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sub_epi64(__m128i a, __m128i b)
+{
+ return a - b;
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_subs_epi8(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_psubsb128((__v16qi)a, (__v16qi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_subs_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_psubsw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_subs_epu8(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_psubusb128((__v16qi)a, (__v16qi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_subs_epu16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_psubusw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_and_si128(__m128i a, __m128i b)
+{
+ return __builtin_ia32_pand128(a, b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_andnot_si128(__m128i a, __m128i b)
+{
+ return __builtin_ia32_pandn128(a, b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_or_si128(__m128i a, __m128i b)
+{
+ return __builtin_ia32_por128(a, b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_xor_si128(__m128i a, __m128i b)
+{
+ return __builtin_ia32_pxor128(a, b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_slli_si128(__m128i a, int imm)
+{
+ return __builtin_ia32_pslldqi128(a, imm * 8);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_slli_epi16(__m128i a, int count)
+{
+ return (__m128i)__builtin_ia32_psllwi128((__v8hi)a, count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sll_epi16(__m128i a, __m128i count)
+{
+ return (__m128i)__builtin_ia32_psllw128((__v8hi)a, (__v8hi)count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_slli_epi32(__m128i a, int count)
+{
+ return (__m128i)__builtin_ia32_pslldi128((__v4si)a, count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sll_epi32(__m128i a, __m128i count)
+{
+ return (__m128i)__builtin_ia32_pslld128((__v4si)a, (__v4si)count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_slli_epi64(__m128i a, int count)
+{
+ return __builtin_ia32_psllqi128(a, count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sll_epi64(__m128i a, __m128i count)
+{
+ return __builtin_ia32_psllq128(a, count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_srai_epi16(__m128i a, int count)
+{
+ return (__m128i)__builtin_ia32_psrawi128((__v8hi)a, count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sra_epi16(__m128i a, __m128i count)
+{
+ return (__m128i)__builtin_ia32_psraw128((__v8hi)a, (__v8hi)count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_srai_epi32(__m128i a, int count)
+{
+ return (__m128i)__builtin_ia32_psradi128((__v4si)a, count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sra_epi32(__m128i a, __m128i count)
+{
+ return (__m128i)__builtin_ia32_psrad128((__v4si)a, (__v4si)count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_srli_si128(__m128i a, int imm)
+{
+ return __builtin_ia32_psrldqi128(a, imm * 8);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_srli_epi16(__m128i a, int count)
+{
+ return (__m128i)__builtin_ia32_psrlwi128((__v8hi)a, count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_srl_epi16(__m128i a, __m128i count)
+{
+ return (__m128i)__builtin_ia32_psrlw128((__v8hi)a, (__v8hi)count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_srli_epi32(__m128i a, int count)
+{
+ return (__m128i)__builtin_ia32_psrldi128((__v4si)a, count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_srl_epi32(__m128i a, __m128i count)
+{
+ return (__m128i)__builtin_ia32_psrld128((__v4si)a, (__v4si)count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_srli_epi64(__m128i a, int count)
+{
+ return __builtin_ia32_psrlqi128(a, count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_srl_epi64(__m128i a, __m128i count)
+{
+ return __builtin_ia32_psrlq128(a, count);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cmpeq_epi8(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pcmpeqb128((__v16qi)a, (__v16qi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cmpeq_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pcmpeqw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cmpeq_epi32(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pcmpeqd128((__v4si)a, (__v4si)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cmpgt_epi8(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pcmpgtb128((__v16qi)a, (__v16qi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cmpgt_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pcmpgtw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cmpgt_epi32(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pcmpgtd128((__v4si)a, (__v4si)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cmplt_epi8(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pcmpgtb128((__v16qi)b, (__v16qi)a);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cmplt_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pcmpgtw128((__v8hi)b, (__v8hi)a);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cmplt_epi32(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pcmpgtd128((__v4si)b, (__v4si)a);
+}
+
+#ifdef __x86_64__
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_cvtsi64_sd(__m128d a, long long b)
+{
+ return __builtin_ia32_cvtsi642sd(a, b);
+}
+
+static inline long long __attribute__((__always_inline__, __nodebug__))
+_mm_cvtsd_si64(__m128d a)
+{
+ return __builtin_ia32_cvtsd2si64(a);
+}
+
+static inline long long __attribute__((__always_inline__, __nodebug__))
+_mm_cvttsd_si64(__m128d a)
+{
+ return __builtin_ia32_cvttsd2si64(a);
+}
+#endif
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtepi32_ps(__m128i a)
+{
+ return __builtin_ia32_cvtdq2ps((__v4si)a);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtps_epi32(__m128 a)
+{
+ return (__m128i)__builtin_ia32_cvtps2dq(a);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvttps_epi32(__m128 a)
+{
+ return (__m128i)__builtin_ia32_cvttps2dq(a);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtsi32_si128(int a)
+{
+ return (__m128i)(__v4si){ a, 0, 0, 0 };
+}
+
+#ifdef __x86_64__
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_cvtsi64_si128(long long a)
+{
+ return (__m128i){ a, 0 };
+}
+#endif
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_cvtsi128_si32(__m128i a)
+{
+ __v4si b = (__v4si)a;
+ return b[0];
+}
+
+#ifdef __x86_64__
+static inline long long __attribute__((__always_inline__, __nodebug__))
+_mm_cvtsi128_si64(__m128i a)
+{
+ return a[0];
+}
+#endif
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_load_si128(__m128i const *p)
+{
+ return *p;
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_loadu_si128(__m128i const *p)
+{
+ return (__m128i)__builtin_ia32_loaddqu((char const *)p);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_loadl_epi64(__m128i const *p)
+{
+ return (__m128i)__builtin_ia32_loadlv4si((__v2si *)p);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_set_epi64(__m64 q1, __m64 q0)
+{
+ return (__m128i){ (long long)q0, (long long)q1 };
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_set_epi32(int i3, int i2, int i1, int i0)
+{
+ return (__m128i)(__v4si){ i0, i1, i2, i3};
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_set_epi16(short w7, short w6, short w5, short w4, short w3, short w2, short w1, short w0)
+{
+ return (__m128i)(__v8hi){ w0, w1, w2, w3, w4, w5, w6, w7 };
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_set_epi8(char b15, char b14, char b13, char b12, char b11, char b10, char b9, char b8, char b7, char b6, char b5, char b4, char b3, char b2, char b1, char b0)
+{
+ return (__m128i)(__v16qi){ b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 };
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_set1_epi64(__m64 q)
+{
+ return (__m128i){ (long long)q, (long long)q };
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_set1_epi32(int i)
+{
+ return (__m128i)(__v4si){ i, i, i, i };
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_set1_epi16(short w)
+{
+ return (__m128i)(__v8hi){ w, w, w, w, w, w, w, w };
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_set1_epi8(char b)
+{
+ return (__m128i)(__v16qi){ b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b };
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_setr_epi64(__m64 q0, __m64 q1)
+{
+ return (__m128i){ (long long)q0, (long long)q1 };
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_setr_epi32(int i0, int i1, int i2, int i3)
+{
+ return (__m128i)(__v4si){ i0, i1, i2, i3};
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_setr_epi16(short w0, short w1, short w2, short w3, short w4, short w5, short w6, short w7)
+{
+ return (__m128i)(__v8hi){ w0, w1, w2, w3, w4, w5, w6, w7 };
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_setr_epi8(char b0, char b1, char b2, char b3, char b4, char b5, char b6, char b7, char b8, char b9, char b10, char b11, char b12, char b13, char b14, char b15)
+{
+ return (__m128i)(__v16qi){ b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 };
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_setzero_si128(void)
+{
+ return (__m128i){ 0LL, 0LL };
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_store_si128(__m128i *p, __m128i b)
+{
+ *p = b;
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_storeu_si128(__m128i *p, __m128i b)
+{
+ __builtin_ia32_storedqu((char *)p, (__v16qi)b);
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_maskmoveu_si128(__m128i d, __m128i n, char *p)
+{
+ __builtin_ia32_maskmovdqu((__v16qi)d, (__v16qi)n, p);
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_storel_epi64(__m128i *p, __m128i a)
+{
+ __builtin_ia32_storelv4si((__v2si *)p, a);
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_stream_pd(double *p, __m128d a)
+{
+ __builtin_ia32_movntpd(p, a);
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_stream_si128(__m128i *p, __m128i a)
+{
+ __builtin_ia32_movntdq(p, a);
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_stream_si32(int *p, int a)
+{
+ __builtin_ia32_movnti(p, a);
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_clflush(void const *p)
+{
+ __builtin_ia32_clflush(p);
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_lfence(void)
+{
+ __builtin_ia32_lfence();
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_mfence(void)
+{
+ __builtin_ia32_mfence();
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_packs_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_packsswb128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_packs_epi32(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_packssdw128((__v4si)a, (__v4si)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_packus_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_packuswb128((__v8hi)a, (__v8hi)b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_extract_epi16(__m128i a, int imm)
+{
+ __v8hi b = (__v8hi)a;
+ return b[imm];
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_insert_epi16(__m128i a, int b, int imm)
+{
+ return (__m128i)__builtin_ia32_vec_set_v8hi((__v8hi)a, b, imm);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_movemask_epi8(__m128i a)
+{
+ return __builtin_ia32_pmovmskb128((__v16qi)a);
+}
+
+#define _mm_shuffle_epi32(a, imm) ((__m128i)__builtin_ia32_pshufd((__v4si)(a), (imm)))
+#define _mm_shufflehi_epi16(a, imm) ((__m128i)__builtin_ia32_pshufhw((__v8hi)(a), (imm)))
+#define _mm_shufflelo_epi16(a, imm) ((__m128i)__builtin_ia32_pshuflw((__v8hi)(a), (imm)))
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_unpackhi_epi8(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_shufflevector((__v16qi)a, (__v16qi)b, 8, 16+8, 9, 16+9, 10, 16+10, 11, 16+11, 12, 16+12, 13, 16+13, 14, 16+14, 15, 16+15);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_unpackhi_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_shufflevector((__v8hi)a, (__v8hi)b, 4, 8+4, 5, 8+5, 6, 8+6, 7, 8+7);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_unpackhi_epi32(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_shufflevector((__v4si)a, (__v4si)b, 2, 4+2, 3, 4+3);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_unpackhi_epi64(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_shufflevector(a, b, 1, 2+1);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_unpacklo_epi8(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_shufflevector((__v16qi)a, (__v16qi)b, 0, 16+0, 1, 16+1, 2, 16+2, 3, 16+3, 4, 16+4, 5, 16+5, 6, 16+6, 7, 16+7);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_unpacklo_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_shufflevector((__v8hi)a, (__v8hi)b, 0, 8+0, 1, 8+1, 2, 8+2, 3, 8+3);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_unpacklo_epi32(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_shufflevector((__v4si)a, (__v4si)b, 0, 4+0, 1, 4+1);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_unpacklo_epi64(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_shufflevector(a, b, 0, 2+0);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_movepi64_pi64(__m128i a)
+{
+ return (__m64)a[0];
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_movpi64_pi64(__m64 a)
+{
+ return (__m128i){ (long long)a, 0 };
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_move_epi64(__m128i a)
+{
+ return (__m128i){ a[0], 0 };
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_unpackhi_pd(__m128d a, __m128d b)
+{
+ return __builtin_shufflevector(a, b, 1, 2+1);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_unpacklo_pd(__m128d a, __m128d b)
+{
+ return __builtin_shufflevector(a, b, 0, 2+0);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_movemask_pd(__m128d a)
+{
+ return __builtin_ia32_movmskpd(a);
+}
+
+#define _mm_shuffle_pd(a, b, i) (__builtin_ia32_shufpd((a), (b), (i)))
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_castpd_ps(__m128d in)
+{
+ return (__m128)in;
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_castpd_si128(__m128d in)
+{
+ return (__m128i)in;
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_castps_pd(__m128 in)
+{
+ return (__m128d)in;
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_castps_si128(__m128 in)
+{
+ return (__m128i)in;
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_castsi128_ps(__m128i in)
+{
+ return (__m128)in;
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_castsi128_pd(__m128i in)
+{
+ return (__m128d)in;
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_pause(void)
+{
+ __asm__ volatile ("pause");
+}
+
+#define _MM_SHUFFLE2(x, y) (((x) << 1) | (y))
+
+#endif /* __SSE2__ */
+
+#endif /* __EMMINTRIN_H */
diff --git a/lib/Headers/float.h b/lib/Headers/float.h
new file mode 100644
index 000000000000..28fb882bd24a
--- /dev/null
+++ b/lib/Headers/float.h
@@ -0,0 +1,71 @@
+/*===---- float.h - Characteristics of floating point types ----------------===
+ *
+ * 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 __FLOAT_H
+#define __FLOAT_H
+
+/* Characteristics of floating point types, C99 5.2.4.2.2 */
+
+#define FLT_EVAL_METHOD __FLT_EVAL_METHOD__
+#define FLT_ROUNDS (__builtin_flt_rounds())
+#define FLT_RADIX __FLT_RADIX__
+
+#define FLT_MANT_DIG __FLT_MANT_DIG__
+#define DBL_MANT_DIG __DBL_MANT_DIG__
+#define LDBL_MANT_DIG __LDBL_MANT_DIG__
+
+#define DECIMAL_DIG __DECIMAL_DIG__
+
+#define FLT_DIG __FLT_DIG__
+#define DBL_DIG __DBL_DIG__
+#define LDBL_DIG __LDBL_DIG__
+
+#define FLT_MIN_EXP __FLT_MIN_EXP__
+#define DBL_MIN_EXP __DBL_MIN_EXP__
+#define LDBL_MIN_EXP __LDBL_MIN_EXP__
+
+#define FLT_MIN_10_EXP __FLT_MIN_10_EXP__
+#define DBL_MIN_10_EXP __DBL_MIN_10_EXP__
+#define LDBL_MIN_10_EXP __LDBL_MIN_10_EXP__
+
+#define FLT_MAX_EXP __FLT_MAX_EXP__
+#define DBL_MAX_EXP __DBL_MAX_EXP__
+#define LDBL_MAX_EXP __LDBL_MAX_EXP__
+
+#define FLT_MAX_10_EXP __FLT_MAX_10_EXP__
+#define DBL_MAX_10_EXP __DBL_MAX_10_EXP__
+#define LDBL_MAX_10_EXP __LDBL_MAX_10_EXP__
+
+#define FLT_MAX __FLT_MAX__
+#define DBL_MAX __DBL_MAX__
+#define LDBL_MAX __LDBL_MAX__
+
+#define FLT_EPSILON __FLT_EPSILON__
+#define DBL_EPSILON __DBL_EPSILON__
+#define LDBL_EPSILON __LDBL_EPSILON__
+
+#define FLT_MIN __FLT_MIN__
+#define DBL_MIN __DBL_MIN__
+#define LDBL_MIN __LDBL_MIN__
+
+#endif /* __FLOAT_H */
diff --git a/lib/Headers/iso646.h b/lib/Headers/iso646.h
new file mode 100644
index 000000000000..dca13c5babe5
--- /dev/null
+++ b/lib/Headers/iso646.h
@@ -0,0 +1,43 @@
+/*===---- iso646.h - Standard header for alternate spellings of operators---===
+ *
+ * Copyright (c) 2008 Eli Friedman
+ *
+ * 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 __ISO646_H
+#define __ISO646_H
+
+#ifndef __cplusplus
+#define and &&
+#define and_eq &=
+#define bitand &
+#define bitor |
+#define compl ~
+#define not !
+#define not_eq !=
+#define or ||
+#define or_eq |=
+#define xor ^
+#define xor_eq ^=
+#endif
+
+#endif /* __ISO646_H */
diff --git a/lib/Headers/limits.h b/lib/Headers/limits.h
new file mode 100644
index 000000000000..e4909ab034e6
--- /dev/null
+++ b/lib/Headers/limits.h
@@ -0,0 +1,114 @@
+/*===---- limits.h - Standard header for integer sizes --------------------===*\
+ *
+ * Copyright (c) 2009 Chris Lattner
+ *
+ * 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 __CLANG_LIMITS_H
+#define __CLANG_LIMITS_H
+
+/* The system's limits.h may, in turn, try to #include_next GCC's limits.h.
+ Avert this #include_next madness. */
+#if defined __GNUC__ && !defined _GCC_LIMITS_H_
+#define _GCC_LIMITS_H_
+#endif
+
+/* System headers include a number of constants from POSIX in <limits.h>. */
+#include_next <limits.h>
+
+/* Many system headers try to "help us out" by defining these. No really, we
+ know how big each datatype is. */
+#undef SCHAR_MIN
+#undef SCHAR_MAX
+#undef UCHAR_MAX
+#undef SHRT_MIN
+#undef SHRT_MAX
+#undef USHRT_MAX
+#undef INT_MIN
+#undef INT_MAX
+#undef UINT_MAX
+#undef LONG_MIN
+#undef LONG_MAX
+#undef ULONG_MAX
+
+#undef MB_LEN_MAX
+#undef CHAR_BIT
+#undef CHAR_MIN
+#undef CHAR_MAX
+
+/* C90/99 5.2.4.2.1 */
+#define SCHAR_MAX __SCHAR_MAX__
+#define SHRT_MAX __SHRT_MAX__
+#define INT_MAX __INT_MAX__
+#define LONG_MAX __LONG_MAX__
+
+#define SCHAR_MIN (-__SCHAR_MAX__-1)
+#define SHRT_MIN (-__SHRT_MAX__ -1)
+#define INT_MIN (-__INT_MAX__ -1)
+#define LONG_MIN (-__LONG_MAX__ -1L)
+
+#define UCHAR_MAX (__SCHAR_MAX__*2 +1)
+#define USHRT_MAX (__SHRT_MAX__ *2 +1)
+#define UINT_MAX (__INT_MAX__ *2U +1U)
+#define ULONG_MAX (__LONG_MAX__ *2UL+1UL)
+
+#ifndef MB_LEN_MAX
+#define MB_LEN_MAX 1
+#endif
+
+#define CHAR_BIT __CHAR_BIT__
+
+#ifdef __CHAR_UNSIGNED__ /* -funsigned-char */
+#define CHAR_MIN 0
+#define CHAR_MAX UCHAR_MAX
+#else
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX __SCHAR_MAX__
+#endif
+
+/* C99 5.2.4.2.1: Added long long. */
+#if __STDC_VERSION__ >= 199901
+
+#undef LLONG_MIN
+#undef LLONG_MAX
+#undef ULLONG_MAX
+
+#define LLONG_MAX __LONG_LONG_MAX__
+#define LLONG_MIN (-__LONG_LONG_MAX__-1LL)
+#define ULLONG_MAX (__LONG_LONG_MAX__*2ULL+1ULL)
+#endif
+
+/* LONG_LONG_MIN/LONG_LONG_MAX/ULONG_LONG_MAX are a GNU extension. It's too bad
+ that we don't have something like #pragma poison that could be used to
+ deprecate a macro - the code should just use LLONG_MAX and friends.
+ */
+#if defined(__GNU_LIBRARY__) ? defined(__USE_GNU) : !defined(__STRICT_ANSI__)
+
+#undef LONG_LONG_MIN
+#undef LONG_LONG_MAX
+#undef ULONG_LONG_MAX
+
+#define LONG_LONG_MAX __LONG_LONG_MAX__
+#define LONG_LONG_MIN (-__LONG_LONG_MAX__-1LL)
+#define ULONG_LONG_MAX (__LONG_LONG_MAX__*2ULL+1ULL)
+#endif
+
+#endif /* __CLANG_LIMITS_H */
diff --git a/lib/Headers/mm_malloc.h b/lib/Headers/mm_malloc.h
new file mode 100644
index 000000000000..a680c47a4a90
--- /dev/null
+++ b/lib/Headers/mm_malloc.h
@@ -0,0 +1,59 @@
+/*===---- mm_malloc.h - Allocating and Freeing Aligned Memory Blocks -------===
+ *
+ * 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 __MM_MALLOC_H
+#define __MM_MALLOC_H
+
+#include <errno.h>
+#include <stdlib.h>
+
+static inline void *__attribute__((__always_inline__, __nodebug__)) _mm_malloc(size_t size, size_t align)
+{
+ if (align & (align - 1)) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ if (!size)
+ return 0;
+
+ if (align < 2 * sizeof(void *))
+ align = 2 * sizeof(void *);
+
+ void *mallocedMemory = malloc(size + align);
+ if (!mallocedMemory)
+ return 0;
+
+ void *alignedMemory = (void *)(((size_t)mallocedMemory + align) & ~((size_t)align - 1));
+ ((void **)alignedMemory)[-1] = mallocedMemory;
+
+ return alignedMemory;
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__)) _mm_free(void *p)
+{
+ if (p)
+ free(((void **)p)[-1]);
+}
+
+#endif /* __MM_MALLOC_H */
diff --git a/lib/Headers/mmintrin.h b/lib/Headers/mmintrin.h
new file mode 100644
index 000000000000..339d21288b4e
--- /dev/null
+++ b/lib/Headers/mmintrin.h
@@ -0,0 +1,449 @@
+/*===---- mmintrin.h - MMX intrinsics --------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __MMINTRIN_H
+#define __MMINTRIN_H
+
+#ifndef __MMX__
+#error "MMX instruction set not enabled"
+#else
+
+typedef long long __m64 __attribute__((__vector_size__(8)));
+
+typedef int __v2si __attribute__((__vector_size__(8)));
+typedef short __v4hi __attribute__((__vector_size__(8)));
+typedef char __v8qi __attribute__((__vector_size__(8)));
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_empty(void)
+{
+ __builtin_ia32_emms();
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtsi32_si64(int __i)
+{
+ return (__m64)(__v2si){__i, 0};
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_cvtsi64_si32(__m64 __m)
+{
+ __v2si __mmx_var2 = (__v2si)__m;
+ return __mmx_var2[0];
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtsi64_m64(long long __i)
+{
+ return (__m64)__i;
+}
+
+static inline long long __attribute__((__always_inline__, __nodebug__))
+_mm_cvtm64_si64(__m64 __m)
+{
+ return (long long)__m;
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_packs_pi16(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_packsswb((__v4hi)__m1, (__v4hi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_packs_pi32(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_packssdw((__v2si)__m1, (__v2si)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_packs_pu16(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_packuswb((__v4hi)__m1, (__v4hi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_unpackhi_pi8(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_shufflevector((__v8qi)__m1, (__v8qi)__m2, 4, 8+4, 5,
+ 8+5, 6, 8+6, 7, 8+7);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_unpackhi_pi16(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_shufflevector((__v4hi)__m1, (__v4hi)__m2, 2, 4+2, 3,
+ 4+3);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_unpackhi_pi32(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_shufflevector((__v2si)__m1, (__v2si)__m2, 1, 2+1);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_unpacklo_pi8(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_shufflevector((__v8qi)__m1, (__v8qi)__m2, 0, 8+0, 1,
+ 8+1, 2, 8+2, 3, 8+3);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_unpacklo_pi16(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_shufflevector((__v4hi)__m1, (__v4hi)__m2, 0, 4+0, 1,
+ 4+1);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_unpacklo_pi32(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_shufflevector((__v2si)__m1, (__v2si)__m2, 0, 2+0);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_add_pi8(__m64 __m1, __m64 __m2)
+{
+ return (__m64)((__v8qi)__m1 + (__v8qi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_add_pi16(__m64 __m1, __m64 __m2)
+{
+ return (__m64)((__v4hi)__m1 + (__v4hi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_add_pi32(__m64 __m1, __m64 __m2)
+{
+ return (__m64)((__v2si)__m1 + (__v2si)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_adds_pi8(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_paddsb((__v8qi)__m1, (__v8qi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_adds_pi16(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_paddsw((__v4hi)__m1, (__v4hi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_adds_pu8(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_paddusb((__v8qi)__m1, (__v8qi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_adds_pu16(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_paddusw((__v4hi)__m1, (__v4hi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_sub_pi8(__m64 __m1, __m64 __m2)
+{
+ return (__m64)((__v8qi)__m1 - (__v8qi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_sub_pi16(__m64 __m1, __m64 __m2)
+{
+ return (__m64)((__v4hi)__m1 - (__v4hi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_sub_pi32(__m64 __m1, __m64 __m2)
+{
+ return (__m64)((__v2si)__m1 - (__v2si)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_subs_pi8(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_psubsb((__v8qi)__m1, (__v8qi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_subs_pi16(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_psubsw((__v4hi)__m1, (__v4hi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_subs_pu8(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_psubusb((__v8qi)__m1, (__v8qi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_subs_pu16(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_psubusw((__v4hi)__m1, (__v4hi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_madd_pi16(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_pmaddwd((__v4hi)__m1, (__v4hi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_mulhi_pi16(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_pmulhw((__v4hi)__m1, (__v4hi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_mullo_pi16(__m64 __m1, __m64 __m2)
+{
+ return (__m64)((__v4hi)__m1 * (__v4hi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_sll_pi16(__m64 __m, __m64 __count)
+{
+ return (__m64)__builtin_ia32_psllw((__v4hi)__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_slli_pi16(__m64 __m, int __count)
+{
+ return (__m64)__builtin_ia32_psllwi((__v4hi)__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_sll_pi32(__m64 __m, __m64 __count)
+{
+ return (__m64)__builtin_ia32_pslld((__v2si)__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_slli_pi32(__m64 __m, int __count)
+{
+ return (__m64)__builtin_ia32_pslldi((__v2si)__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_sll_si64(__m64 __m, __m64 __count)
+{
+ return __builtin_ia32_psllq(__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_slli_si64(__m64 __m, int __count)
+{
+ return __builtin_ia32_psllqi(__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_sra_pi16(__m64 __m, __m64 __count)
+{
+ return (__m64)__builtin_ia32_psraw((__v4hi)__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_srai_pi16(__m64 __m, int __count)
+{
+ return (__m64)__builtin_ia32_psrawi((__v4hi)__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_sra_pi32(__m64 __m, __m64 __count)
+{
+ return (__m64)__builtin_ia32_psrad((__v2si)__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_srai_pi32(__m64 __m, int __count)
+{
+ return (__m64)__builtin_ia32_psradi((__v2si)__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_srl_pi16(__m64 __m, __m64 __count)
+{
+ return (__m64)__builtin_ia32_psrlw((__v4hi)__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_srli_pi16(__m64 __m, int __count)
+{
+ return (__m64)__builtin_ia32_psrlwi((__v4hi)__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_srl_pi32(__m64 __m, __m64 __count)
+{
+ return (__m64)__builtin_ia32_psrld((__v2si)__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_srli_pi32(__m64 __m, int __count)
+{
+ return (__m64)__builtin_ia32_psrldi((__v2si)__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_srl_si64(__m64 __m, __m64 __count)
+{
+ return (__m64)__builtin_ia32_psrlq(__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_srli_si64(__m64 __m, int __count)
+{
+ return __builtin_ia32_psrlqi(__m, __count);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_and_si64(__m64 __m1, __m64 __m2)
+{
+ return __m1 & __m2;
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_andnot_si64(__m64 __m1, __m64 __m2)
+{
+ return ~__m1 & __m2;
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_or_si64(__m64 __m1, __m64 __m2)
+{
+ return __m1 | __m2;
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_xor_si64(__m64 __m1, __m64 __m2)
+{
+ return __m1 ^ __m2;
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpeq_pi8(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_pcmpeqb((__v8qi)__m1, (__v8qi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpeq_pi16(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_pcmpeqw((__v4hi)__m1, (__v4hi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpeq_pi32(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_pcmpeqd((__v2si)__m1, (__v2si)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpgt_pi8(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_pcmpgtb((__v8qi)__m1, (__v8qi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpgt_pi16(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_pcmpgtw((__v4hi)__m1, (__v4hi)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpgt_pi32(__m64 __m1, __m64 __m2)
+{
+ return (__m64)__builtin_ia32_pcmpgtd((__v2si)__m1, (__v2si)__m2);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_setzero_si64(void)
+{
+ return (__m64){ 0LL };
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_set_pi32(int __i1, int __i0)
+{
+ return (__m64)(__v2si){ __i0, __i1 };
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_set_pi16(short __s3, short __s2, short __s1, short __s0)
+{
+ return (__m64)(__v4hi){ __s0, __s1, __s2, __s3 };
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_set_pi8(char __b7, char __b6, char __b5, char __b4, char __b3, char __b2,
+ char __b1, char __b0)
+{
+ return (__m64)(__v8qi){ __b0, __b1, __b2, __b3, __b4, __b5, __b6, __b7 };
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_set1_pi32(int __i)
+{
+ return (__m64)(__v2si){ __i, __i };
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_set1_pi16(short __s)
+{
+ return (__m64)(__v4hi){ __s };
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_set1_pi8(char __b)
+{
+ return (__m64)(__v8qi){ __b };
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_setr_pi32(int __i1, int __i0)
+{
+ return (__m64)(__v2si){ __i1, __i0 };
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_setr_pi16(short __s3, short __s2, short __s1, short __s0)
+{
+ return (__m64)(__v4hi){ __s3, __s2, __s1, __s0 };
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_setr_pi8(char __b7, char __b6, char __b5, char __b4, char __b3, char __b2,
+ char __b1, char __b0)
+{
+ return (__m64)(__v8qi){ __b7, __b6, __b5, __b4, __b3, __b2, __b1, __b0 };
+}
+
+#endif /* __MMX__ */
+
+#endif /* __MMINTRIN_H */
+
diff --git a/lib/Headers/pmmintrin.h b/lib/Headers/pmmintrin.h
new file mode 100644
index 000000000000..cd901662d68b
--- /dev/null
+++ b/lib/Headers/pmmintrin.h
@@ -0,0 +1,121 @@
+/*===---- pmmintrin.h - SSE3 intrinsics ------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __PMMINTRIN_H
+#define __PMMINTRIN_H
+
+#ifndef __SSE3__
+#error "SSE3 instruction set not enabled"
+#else
+
+#include <emmintrin.h>
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_lddqu_si128(__m128i const *p)
+{
+ return (__m128i)__builtin_ia32_lddqu((char const *)p);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_addsub_ps(__m128 a, __m128 b)
+{
+ return __builtin_ia32_addsubps(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_hadd_ps(__m128 a, __m128 b)
+{
+ return __builtin_ia32_haddps(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_hsub_ps(__m128 a, __m128 b)
+{
+ return __builtin_ia32_hsubps(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_movehdup_ps(__m128 a)
+{
+ return __builtin_shufflevector(a, a, 1, 1, 3, 3);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_moveldup_ps(__m128 a)
+{
+ return __builtin_shufflevector(a, a, 0, 0, 2, 2);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_addsub_pd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_addsubpd(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_hadd_pd(__m128d a, __m128d b)
+{
+ return __builtin_ia32_haddpd(a, b);
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_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 };
+}
+
+static inline __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_movedup_pd(__m128d a)
+{
+ return __builtin_shufflevector(a, a, 0, 0);
+}
+
+#define _MM_DENORMALS_ZERO_ON (0x0040)
+#define _MM_DENORMALS_ZERO_OFF (0x0000)
+
+#define _MM_DENORMALS_ZERO_MASK (0x0040)
+
+#define _MM_GET_DENORMALS_ZERO_MODE() (_mm_getcsr() & _MM_DENORMALS_ZERO_MASK)
+#define _MM_SET_DENORMALS_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (x)))
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_monitor(void const *p, unsigned extensions, unsigned hints)
+{
+ __builtin_ia32_monitor((void *)p, extensions, hints);
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_mwait(unsigned extensions, unsigned hints)
+{
+ __builtin_ia32_mwait(extensions, hints);
+}
+
+#endif /* __SSE3__ */
+
+#endif /* __PMMINTRIN_H */
diff --git a/lib/Headers/stdarg.h b/lib/Headers/stdarg.h
new file mode 100644
index 000000000000..c436ced97c5f
--- /dev/null
+++ b/lib/Headers/stdarg.h
@@ -0,0 +1,47 @@
+/*===---- stdarg.h - Variable argument handling ----------------------------===
+ *
+ * Copyright (c) 2008 Eli Friedman
+ *
+ * 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 __STDARG_H
+#define __STDARG_H
+
+typedef __builtin_va_list va_list;
+#define va_start(ap, param) __builtin_va_start(ap, param)
+#define va_end(ap) __builtin_va_end(ap)
+#define va_arg(ap, type) __builtin_va_arg(ap, type)
+
+/* GCC always defines __va_copy, but does not define va_copy unless in c99 mode
+ * or -ansi is not specified, since it was not part of C90.
+ */
+#define __va_copy(d,s) __builtin_va_copy(d,s)
+
+#if __STDC_VERSION__ >= 199900L || !defined(__STRICT_ANSI__)
+#define va_copy(dest, src) __builtin_va_copy(dest, src)
+#endif
+
+/* Hack required to make standard headers work, at least on Ubuntu */
+#define __GNUC_VA_LIST 1
+typedef __builtin_va_list __gnuc_va_list;
+
+#endif /* __STDARG_H */
diff --git a/lib/Headers/stdbool.h b/lib/Headers/stdbool.h
new file mode 100644
index 000000000000..e44a1f9a979f
--- /dev/null
+++ b/lib/Headers/stdbool.h
@@ -0,0 +1,38 @@
+/*===---- stdbool.h - Standard header for booleans -------------------------===
+ *
+ * Copyright (c) 2008 Eli Friedman
+ *
+ * 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 __STDBOOL_H
+#define __STDBOOL_H
+
+/* Don't define bool, true, and false in C++ */
+#ifndef __cplusplus
+#define bool _Bool
+#define true 1
+#define false 0
+#endif
+
+#define __bool_true_false_are_defined 1
+
+#endif /* __STDBOOL_H */
diff --git a/lib/Headers/stddef.h b/lib/Headers/stddef.h
new file mode 100644
index 000000000000..2c84b4b066c9
--- /dev/null
+++ b/lib/Headers/stddef.h
@@ -0,0 +1,43 @@
+/*===---- stddef.h - Basic type definitions --------------------------------===
+ *
+ * Copyright (c) 2008 Eli Friedman
+ *
+ * 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 __STDDEF_H
+#define __STDDEF_H
+
+typedef __typeof__(((int*)0)-((int*)0)) ptrdiff_t;
+typedef __typeof__(sizeof(int)) size_t;
+#ifndef __cplusplus
+typedef __typeof__(*L"") wchar_t;
+#endif
+
+#ifdef __cplusplus
+#define NULL __null
+#else
+#define NULL ((void*)0)
+#endif
+
+#define offsetof(t, d) __builtin_offsetof(t, d)
+
+#endif /* __STDDEF_H */
diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h
new file mode 100644
index 000000000000..a7020d838ec9
--- /dev/null
+++ b/lib/Headers/stdint.h
@@ -0,0 +1,232 @@
+/*===---- stdint.h - Standard header for sized integer types --------------===*\
+ *
+ * Copyright (c) 2009 Chris Lattner
+ *
+ * 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 __CLANG_STDINT_H
+#define __CLANG_STDINT_H
+
+/* If we're hosted, fall back to the system's stdint.h, which might have
+ * additional definitions.
+ */
+#if __STDC_HOSTED__
+# include_next <stdint.h>
+#else
+
+/* We currently only support targets with power of two, 2s complement integers.
+ */
+
+/* C99 7.18.1.1 Exact-width integer types.
+ * C99 7.18.1.2 Minimum-width integer types.
+ * C99 7.18.1.3 Fastest minimum-width integer types.
+ * Since we only support pow-2 targets, these map directly to exact width types.
+ */
+
+#ifndef __int8_t_defined /* glibc does weird things with sys/types.h */
+#define __int8_t_defined
+typedef signed __INT8_TYPE__ int8_t;
+typedef __INT16_TYPE__ int16_t;
+typedef __INT32_TYPE__ int32_t;
+#ifdef __INT64_TYPE__
+typedef __INT64_TYPE__ int64_t;
+#endif
+#endif
+
+typedef unsigned __INT8_TYPE__ uint8_t;
+typedef int8_t int_least8_t;
+typedef uint8_t uint_least8_t;
+typedef int8_t int_fast8_t;
+typedef uint8_t uint_fast8_t;
+
+typedef unsigned __INT16_TYPE__ uint16_t;
+typedef int16_t int_least16_t;
+typedef uint16_t uint_least16_t;
+typedef int16_t int_fast16_t;
+typedef uint16_t uint_fast16_t;
+
+#ifndef __uint32_t_defined /* more glibc compatibility */
+#define __uint32_t_defined
+typedef unsigned __INT32_TYPE__ uint32_t;
+#endif
+typedef int32_t int_least32_t;
+typedef uint32_t uint_least32_t;
+typedef int32_t int_fast32_t;
+typedef uint32_t uint_fast32_t;
+
+/* Some 16-bit targets do not have a 64-bit datatype. Only define the 64-bit
+ * typedefs if there is something to typedef them to.
+ */
+#ifdef __INT64_TYPE__
+typedef unsigned __INT64_TYPE__ uint64_t;
+typedef int64_t int_least64_t;
+typedef uint64_t uint_least64_t;
+typedef int64_t int_fast64_t;
+typedef uint64_t uint_fast64_t;
+#endif
+
+
+/* C99 7.18.1.4 Integer types capable of holding object pointers.
+ */
+#ifndef __intptr_t_defined
+typedef __INTPTR_TYPE__ intptr_t;
+#define __intptr_t_defined
+#endif
+typedef unsigned __INTPTR_TYPE__ uintptr_t;
+
+/* C99 7.18.1.5 Greatest-width integer types.
+ */
+typedef __INTMAX_TYPE__ intmax_t;
+typedef __UINTMAX_TYPE__ uintmax_t;
+
+/* C99 7.18.2.1 Limits of exact-width integer types.
+ * Fixed sized values have fixed size max/min.
+ * C99 7.18.2.2 Limits of minimum-width integer types.
+ * Since we map these directly onto fixed-sized types, these values the same.
+ * C99 7.18.2.3 Limits of fastest minimum-width integer types.
+ *
+ * Note that C++ should not check __STDC_LIMIT_MACROS here, contrary to the
+ * claims of the C standard (see C++ 18.3.1p2, [cstdint.syn]).
+ */
+
+#define INT8_MAX 127
+#define INT8_MIN (-128)
+#define UINT8_MAX 255
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+
+#define INT16_MAX 32767
+#define INT16_MIN (-32768)
+#define UINT16_MAX 65535
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+
+#define INT32_MAX 2147483647
+#define INT32_MIN (-2147483647-1)
+#define UINT32_MAX 4294967295U
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+
+/* If we do not have 64-bit support, don't define the 64-bit size macros. */
+#ifdef __INT64_TYPE__
+#define INT64_MAX 9223372036854775807LL
+#define INT64_MIN (-9223372036854775807LL-1)
+#define UINT64_MAX 18446744073709551615ULL
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+#endif
+
+/* C99 7.18.2.4 Limits of integer types capable of holding object pointers. */
+/* C99 7.18.3 Limits of other integer types. */
+
+#if __POINTER_WIDTH__ == 64
+
+#define INTPTR_MIN INT64_MIN
+#define INTPTR_MAX INT64_MAX
+#define UINTPTR_MAX UINT64_MAX
+#define PTRDIFF_MIN INT64_MIN
+#define PTRDIFF_MAX INT64_MAX
+#define SIZE_MAX UINT64_MAX
+
+#elif __POINTER_WIDTH__ == 32
+
+#define INTPTR_MIN INT32_MIN
+#define INTPTR_MAX INT32_MAX
+#define UINTPTR_MAX UINT32_MAX
+#define PTRDIFF_MIN INT32_MIN
+#define PTRDIFF_MAX INT32_MAX
+#define SIZE_MAX UINT32_MAX
+
+#elif __POINTER_WIDTH__ == 16
+
+#define INTPTR_MIN INT16_MIN
+#define INTPTR_MAX INT16_MAX
+#define UINTPTR_MAX UINT16_MAX
+#define PTRDIFF_MIN INT16_MIN
+#define PTRDIFF_MAX INT16_MAX
+#define SIZE_MAX UINT16_MAX
+
+#else
+#error "unknown or unset pointer width!"
+#endif
+
+/* C99 7.18.2.5 Limits of greatest-width integer types. */
+#define INTMAX_MIN (-__INTMAX_MAX__-1)
+#define INTMAX_MAX __INTMAX_MAX__
+#define UINTMAX_MAX (__INTMAX_MAX__*2ULL+1ULL)
+
+/* C99 7.18.3 Limits of other integer types. */
+#define SIG_ATOMIC_MIN INT32_MIN
+#define SIG_ATOMIC_MAX INT32_MAX
+#define WINT_MIN INT32_MIN
+#define WINT_MAX INT32_MAX
+
+/* FIXME: if we ever support a target with unsigned wchar_t, this should be
+ * 0 .. Max.
+ */
+#ifndef WCHAR_MAX
+#define WCHAR_MAX __WCHAR_MAX__
+#endif
+#ifndef WCHAR_MIN
+#define WCHAR_MIN (-__WCHAR_MAX__-1)
+#endif
+
+/* C99 7.18.4 Macros for minimum-width integer constants.
+ *
+ * Note that C++ should not check __STDC_CONSTANT_MACROS here, contrary to the
+ * claims of the C standard (see C++ 18.3.1p2, [cstdint.syn]).
+ */
+
+#define INT8_C(v) (v)
+#define UINT8_C(v) (v##U)
+#define INT16_C(v) (v)
+#define UINT16_C(v) (v##U)
+#define INT32_C(v) (v)
+#define UINT32_C(v) (v##U)
+
+/* Only define the 64-bit size macros if we have 64-bit support. */
+#ifdef __INT64_TYPE__
+#define INT64_C(v) (v##LL)
+#define UINT64_C(v) (v##ULL)
+#endif
+
+/* 7.18.4.2 Macros for greatest-width integer constants. */
+#define INTMAX_C(v) (v##LL)
+#define UINTMAX_C(v) (v##ULL)
+
+#endif /* __STDC_HOSTED__ */
+#endif /* __CLANG_STDINT_H */
diff --git a/lib/Headers/tgmath.h b/lib/Headers/tgmath.h
new file mode 100644
index 000000000000..e1a00236781a
--- /dev/null
+++ b/lib/Headers/tgmath.h
@@ -0,0 +1,1358 @@
+/*===---- tgmath.h - Standard header for type generic math ----------------===*\
+ *
+ * Copyright (c) 2009 Howard Hinnant
+ *
+ * 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 __TGMATH_H
+#define __TGMATH_H
+
+/* C99 7.22 Type-generic math <tgmath.h>. */
+#include <math.h>
+
+/* C++ handles type genericity with overloading in math.h. */
+#ifndef __cplusplus
+#include <complex.h>
+
+#define _TG_ATTRSp __attribute__((__overloadable__))
+#define _TG_ATTRS __attribute__((__overloadable__, __always_inline__))
+
+// promotion
+
+typedef void _Argument_type_is_not_arithmetic;
+static _Argument_type_is_not_arithmetic __tg_promote(...)
+ __attribute__((__unavailable__,__overloadable__));
+static double _TG_ATTRSp __tg_promote(int);
+static double _TG_ATTRSp __tg_promote(unsigned int);
+static double _TG_ATTRSp __tg_promote(long);
+static double _TG_ATTRSp __tg_promote(unsigned long);
+static double _TG_ATTRSp __tg_promote(long long);
+static double _TG_ATTRSp __tg_promote(unsigned long long);
+static float _TG_ATTRSp __tg_promote(float);
+static double _TG_ATTRSp __tg_promote(double);
+static long double _TG_ATTRSp __tg_promote(long double);
+static float _Complex _TG_ATTRSp __tg_promote(float _Complex);
+static double _Complex _TG_ATTRSp __tg_promote(double _Complex);
+static long double _Complex _TG_ATTRSp __tg_promote(long double _Complex);
+
+#define __tg_promote1(__x) (__typeof__(__tg_promote(__x)))
+#define __tg_promote2(__x, __y) (__typeof__(__tg_promote(__x) + \
+ __tg_promote(__y)))
+#define __tg_promote3(__x, __y, __z) (__typeof__(__tg_promote(__x) + \
+ __tg_promote(__y) + \
+ __tg_promote(__z)))
+
+// acos
+
+static float
+ _TG_ATTRS
+ __tg_acos(float __x) {return acosf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_acos(double __x) {return acos(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_acos(long double __x) {return acosl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_acos(float _Complex __x) {return cacosf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_acos(double _Complex __x) {return cacos(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_acos(long double _Complex __x) {return cacosl(__x);}
+
+#undef acos
+#define acos(__x) __tg_acos(__tg_promote1((__x))(__x))
+
+// asin
+
+static float
+ _TG_ATTRS
+ __tg_asin(float __x) {return asinf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_asin(double __x) {return asin(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_asin(long double __x) {return asinl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_asin(float _Complex __x) {return casinf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_asin(double _Complex __x) {return casin(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_asin(long double _Complex __x) {return casinl(__x);}
+
+#undef asin
+#define asin(__x) __tg_asin(__tg_promote1((__x))(__x))
+
+// atan
+
+static float
+ _TG_ATTRS
+ __tg_atan(float __x) {return atanf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_atan(double __x) {return atan(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_atan(long double __x) {return atanl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_atan(float _Complex __x) {return catanf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_atan(double _Complex __x) {return catan(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_atan(long double _Complex __x) {return catanl(__x);}
+
+#undef atan
+#define atan(__x) __tg_atan(__tg_promote1((__x))(__x))
+
+// acosh
+
+static float
+ _TG_ATTRS
+ __tg_acosh(float __x) {return acoshf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_acosh(double __x) {return acosh(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_acosh(long double __x) {return acoshl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_acosh(float _Complex __x) {return cacoshf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_acosh(double _Complex __x) {return cacosh(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_acosh(long double _Complex __x) {return cacoshl(__x);}
+
+#undef acosh
+#define acosh(__x) __tg_acosh(__tg_promote1((__x))(__x))
+
+// asinh
+
+static float
+ _TG_ATTRS
+ __tg_asinh(float __x) {return asinhf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_asinh(double __x) {return asinh(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_asinh(long double __x) {return asinhl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_asinh(float _Complex __x) {return casinhf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_asinh(double _Complex __x) {return casinh(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_asinh(long double _Complex __x) {return casinhl(__x);}
+
+#undef asinh
+#define asinh(__x) __tg_asinh(__tg_promote1((__x))(__x))
+
+// atanh
+
+static float
+ _TG_ATTRS
+ __tg_atanh(float __x) {return atanhf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_atanh(double __x) {return atanh(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_atanh(long double __x) {return atanhl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_atanh(float _Complex __x) {return catanhf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_atanh(double _Complex __x) {return catanh(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_atanh(long double _Complex __x) {return catanhl(__x);}
+
+#undef atanh
+#define atanh(__x) __tg_atanh(__tg_promote1((__x))(__x))
+
+// cos
+
+static float
+ _TG_ATTRS
+ __tg_cos(float __x) {return cosf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_cos(double __x) {return cos(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_cos(long double __x) {return cosl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_cos(float _Complex __x) {return ccosf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_cos(double _Complex __x) {return ccos(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_cos(long double _Complex __x) {return ccosl(__x);}
+
+#undef cos
+#define cos(__x) __tg_cos(__tg_promote1((__x))(__x))
+
+// sin
+
+static float
+ _TG_ATTRS
+ __tg_sin(float __x) {return sinf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_sin(double __x) {return sin(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_sin(long double __x) {return sinl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_sin(float _Complex __x) {return csinf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_sin(double _Complex __x) {return csin(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_sin(long double _Complex __x) {return csinl(__x);}
+
+#undef sin
+#define sin(__x) __tg_sin(__tg_promote1((__x))(__x))
+
+// tan
+
+static float
+ _TG_ATTRS
+ __tg_tan(float __x) {return tanf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_tan(double __x) {return tan(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_tan(long double __x) {return tanl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_tan(float _Complex __x) {return ctanf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_tan(double _Complex __x) {return ctan(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_tan(long double _Complex __x) {return ctanl(__x);}
+
+#undef tan
+#define tan(__x) __tg_tan(__tg_promote1((__x))(__x))
+
+// cosh
+
+static float
+ _TG_ATTRS
+ __tg_cosh(float __x) {return coshf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_cosh(double __x) {return cosh(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_cosh(long double __x) {return coshl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_cosh(float _Complex __x) {return ccoshf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_cosh(double _Complex __x) {return ccosh(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_cosh(long double _Complex __x) {return ccoshl(__x);}
+
+#undef cosh
+#define cosh(__x) __tg_cosh(__tg_promote1((__x))(__x))
+
+// sinh
+
+static float
+ _TG_ATTRS
+ __tg_sinh(float __x) {return sinhf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_sinh(double __x) {return sinh(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_sinh(long double __x) {return sinhl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_sinh(float _Complex __x) {return csinhf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_sinh(double _Complex __x) {return csinh(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_sinh(long double _Complex __x) {return csinhl(__x);}
+
+#undef sinh
+#define sinh(__x) __tg_sinh(__tg_promote1((__x))(__x))
+
+// tanh
+
+static float
+ _TG_ATTRS
+ __tg_tanh(float __x) {return tanhf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_tanh(double __x) {return tanh(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_tanh(long double __x) {return tanhl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_tanh(float _Complex __x) {return ctanhf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_tanh(double _Complex __x) {return ctanh(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_tanh(long double _Complex __x) {return ctanhl(__x);}
+
+#undef tanh
+#define tanh(__x) __tg_tanh(__tg_promote1((__x))(__x))
+
+// exp
+
+static float
+ _TG_ATTRS
+ __tg_exp(float __x) {return expf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_exp(double __x) {return exp(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_exp(long double __x) {return expl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_exp(float _Complex __x) {return cexpf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_exp(double _Complex __x) {return cexp(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_exp(long double _Complex __x) {return cexpl(__x);}
+
+#undef exp
+#define exp(__x) __tg_exp(__tg_promote1((__x))(__x))
+
+// log
+
+static float
+ _TG_ATTRS
+ __tg_log(float __x) {return logf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_log(double __x) {return log(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_log(long double __x) {return logl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_log(float _Complex __x) {return clogf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_log(double _Complex __x) {return clog(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_log(long double _Complex __x) {return clogl(__x);}
+
+#undef log
+#define log(__x) __tg_log(__tg_promote1((__x))(__x))
+
+// pow
+
+static float
+ _TG_ATTRS
+ __tg_pow(float __x, float __y) {return powf(__x, __y);}
+
+static double
+ _TG_ATTRS
+ __tg_pow(double __x, double __y) {return pow(__x, __y);}
+
+static long double
+ _TG_ATTRS
+ __tg_pow(long double __x, long double __y) {return powl(__x, __y);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_pow(float _Complex __x, float _Complex __y) {return cpowf(__x, __y);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_pow(double _Complex __x, double _Complex __y) {return cpow(__x, __y);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_pow(long double _Complex __x, long double _Complex __y)
+ {return cpowl(__x, __y);}
+
+#undef pow
+#define pow(__x, __y) __tg_pow(__tg_promote2((__x), (__y))(__x), \
+ __tg_promote2((__x), (__y))(__y))
+
+// sqrt
+
+static float
+ _TG_ATTRS
+ __tg_sqrt(float __x) {return sqrtf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_sqrt(double __x) {return sqrt(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_sqrt(long double __x) {return sqrtl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_sqrt(float _Complex __x) {return csqrtf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_sqrt(double _Complex __x) {return csqrt(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_sqrt(long double _Complex __x) {return csqrtl(__x);}
+
+#undef sqrt
+#define sqrt(__x) __tg_sqrt(__tg_promote1((__x))(__x))
+
+// fabs
+
+static float
+ _TG_ATTRS
+ __tg_fabs(float __x) {return fabsf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_fabs(double __x) {return fabs(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_fabs(long double __x) {return fabsl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_fabs(float _Complex __x) {return cabsf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_fabs(double _Complex __x) {return cabs(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_fabs(long double _Complex __x) {return cabsl(__x);}
+
+#undef fabs
+#define fabs(__x) __tg_fabs(__tg_promote1((__x))(__x))
+
+// atan2
+
+static float
+ _TG_ATTRS
+ __tg_atan2(float __x, float __y) {return atan2f(__x, __y);}
+
+static double
+ _TG_ATTRS
+ __tg_atan2(double __x, double __y) {return atan2(__x, __y);}
+
+static long double
+ _TG_ATTRS
+ __tg_atan2(long double __x, long double __y) {return atan2l(__x, __y);}
+
+#undef atan2
+#define atan2(__x, __y) __tg_atan2(__tg_promote2((__x), (__y))(__x), \
+ __tg_promote2((__x), (__y))(__y))
+
+// cbrt
+
+static float
+ _TG_ATTRS
+ __tg_cbrt(float __x) {return cbrtf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_cbrt(double __x) {return cbrt(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_cbrt(long double __x) {return cbrtl(__x);}
+
+#undef cbrt
+#define cbrt(__x) __tg_cbrt(__tg_promote1((__x))(__x))
+
+// ceil
+
+static float
+ _TG_ATTRS
+ __tg_ceil(float __x) {return ceilf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_ceil(double __x) {return ceil(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_ceil(long double __x) {return ceill(__x);}
+
+#undef ceil
+#define ceil(__x) __tg_ceil(__tg_promote1((__x))(__x))
+
+// copysign
+
+static float
+ _TG_ATTRS
+ __tg_copysign(float __x, float __y) {return copysignf(__x, __y);}
+
+static double
+ _TG_ATTRS
+ __tg_copysign(double __x, double __y) {return copysign(__x, __y);}
+
+static long double
+ _TG_ATTRS
+ __tg_copysign(long double __x, long double __y) {return copysignl(__x, __y);}
+
+#undef copysign
+#define copysign(__x, __y) __tg_copysign(__tg_promote2((__x), (__y))(__x), \
+ __tg_promote2((__x), (__y))(__y))
+
+// erf
+
+static float
+ _TG_ATTRS
+ __tg_erf(float __x) {return erff(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_erf(double __x) {return erf(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_erf(long double __x) {return erfl(__x);}
+
+#undef erf
+#define erf(__x) __tg_erf(__tg_promote1((__x))(__x))
+
+// erfc
+
+static float
+ _TG_ATTRS
+ __tg_erfc(float __x) {return erfcf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_erfc(double __x) {return erfc(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_erfc(long double __x) {return erfcl(__x);}
+
+#undef erfc
+#define erfc(__x) __tg_erfc(__tg_promote1((__x))(__x))
+
+// exp2
+
+static float
+ _TG_ATTRS
+ __tg_exp2(float __x) {return exp2f(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_exp2(double __x) {return exp2(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_exp2(long double __x) {return exp2l(__x);}
+
+#undef exp2
+#define exp2(__x) __tg_exp2(__tg_promote1((__x))(__x))
+
+// expm1
+
+static float
+ _TG_ATTRS
+ __tg_expm1(float __x) {return expm1f(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_expm1(double __x) {return expm1(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_expm1(long double __x) {return expm1l(__x);}
+
+#undef expm1
+#define expm1(__x) __tg_expm1(__tg_promote1((__x))(__x))
+
+// fdim
+
+static float
+ _TG_ATTRS
+ __tg_fdim(float __x, float __y) {return fdimf(__x, __y);}
+
+static double
+ _TG_ATTRS
+ __tg_fdim(double __x, double __y) {return fdim(__x, __y);}
+
+static long double
+ _TG_ATTRS
+ __tg_fdim(long double __x, long double __y) {return fdiml(__x, __y);}
+
+#undef fdim
+#define fdim(__x, __y) __tg_fdim(__tg_promote2((__x), (__y))(__x), \
+ __tg_promote2((__x), (__y))(__y))
+
+// floor
+
+static float
+ _TG_ATTRS
+ __tg_floor(float __x) {return floorf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_floor(double __x) {return floor(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_floor(long double __x) {return floorl(__x);}
+
+#undef floor
+#define floor(__x) __tg_floor(__tg_promote1((__x))(__x))
+
+// fma
+
+static float
+ _TG_ATTRS
+ __tg_fma(float __x, float __y, float __z)
+ {return fmaf(__x, __y, __z);}
+
+static double
+ _TG_ATTRS
+ __tg_fma(double __x, double __y, double __z)
+ {return fma(__x, __y, __z);}
+
+static long double
+ _TG_ATTRS
+ __tg_fma(long double __x,long double __y, long double __z)
+ {return fmal(__x, __y, __z);}
+
+#undef fma
+#define fma(__x, __y, __z) \
+ __tg_fma(__tg_promote3((__x), (__y), (__z))(__x), \
+ __tg_promote3((__x), (__y), (__z))(__y), \
+ __tg_promote3((__x), (__y), (__z))(__z))
+
+// fmax
+
+static float
+ _TG_ATTRS
+ __tg_fmax(float __x, float __y) {return fmaxf(__x, __y);}
+
+static double
+ _TG_ATTRS
+ __tg_fmax(double __x, double __y) {return fmax(__x, __y);}
+
+static long double
+ _TG_ATTRS
+ __tg_fmax(long double __x, long double __y) {return fmaxl(__x, __y);}
+
+#undef fmax
+#define fmax(__x, __y) __tg_fmax(__tg_promote2((__x), (__y))(__x), \
+ __tg_promote2((__x), (__y))(__y))
+
+// fmin
+
+static float
+ _TG_ATTRS
+ __tg_fmin(float __x, float __y) {return fminf(__x, __y);}
+
+static double
+ _TG_ATTRS
+ __tg_fmin(double __x, double __y) {return fmin(__x, __y);}
+
+static long double
+ _TG_ATTRS
+ __tg_fmin(long double __x, long double __y) {return fminl(__x, __y);}
+
+#undef fmin
+#define fmin(__x, __y) __tg_fmin(__tg_promote2((__x), (__y))(__x), \
+ __tg_promote2((__x), (__y))(__y))
+
+// fmod
+
+static float
+ _TG_ATTRS
+ __tg_fmod(float __x, float __y) {return fmodf(__x, __y);}
+
+static double
+ _TG_ATTRS
+ __tg_fmod(double __x, double __y) {return fmod(__x, __y);}
+
+static long double
+ _TG_ATTRS
+ __tg_fmod(long double __x, long double __y) {return fmodl(__x, __y);}
+
+#undef fmod
+#define fmod(__x, __y) __tg_fmod(__tg_promote2((__x), (__y))(__x), \
+ __tg_promote2((__x), (__y))(__y))
+
+// frexp
+
+static float
+ _TG_ATTRS
+ __tg_frexp(float __x, int* __y) {return frexpf(__x, __y);}
+
+static double
+ _TG_ATTRS
+ __tg_frexp(double __x, int* __y) {return frexp(__x, __y);}
+
+static long double
+ _TG_ATTRS
+ __tg_frexp(long double __x, int* __y) {return frexpl(__x, __y);}
+
+#undef frexp
+#define frexp(__x, __y) __tg_frexp(__tg_promote1((__x))(__x), __y)
+
+// hypot
+
+static float
+ _TG_ATTRS
+ __tg_hypot(float __x, float __y) {return hypotf(__x, __y);}
+
+static double
+ _TG_ATTRS
+ __tg_hypot(double __x, double __y) {return hypot(__x, __y);}
+
+static long double
+ _TG_ATTRS
+ __tg_hypot(long double __x, long double __y) {return hypotl(__x, __y);}
+
+#undef hypot
+#define hypot(__x, __y) __tg_hypot(__tg_promote2((__x), (__y))(__x), \
+ __tg_promote2((__x), (__y))(__y))
+
+// ilogb
+
+static int
+ _TG_ATTRS
+ __tg_ilogb(float __x) {return ilogbf(__x);}
+
+static int
+ _TG_ATTRS
+ __tg_ilogb(double __x) {return ilogb(__x);}
+
+static int
+ _TG_ATTRS
+ __tg_ilogb(long double __x) {return ilogbl(__x);}
+
+#undef ilogb
+#define ilogb(__x) __tg_ilogb(__tg_promote1((__x))(__x))
+
+// ldexp
+
+static float
+ _TG_ATTRS
+ __tg_ldexp(float __x, int __y) {return ldexpf(__x, __y);}
+
+static double
+ _TG_ATTRS
+ __tg_ldexp(double __x, int __y) {return ldexp(__x, __y);}
+
+static long double
+ _TG_ATTRS
+ __tg_ldexp(long double __x, int __y) {return ldexpl(__x, __y);}
+
+#undef ldexp
+#define ldexp(__x, __y) __tg_ldexp(__tg_promote1((__x))(__x), __y)
+
+// lgamma
+
+static float
+ _TG_ATTRS
+ __tg_lgamma(float __x) {return lgammaf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_lgamma(double __x) {return lgamma(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_lgamma(long double __x) {return lgammal(__x);}
+
+#undef lgamma
+#define lgamma(__x) __tg_lgamma(__tg_promote1((__x))(__x))
+
+// llrint
+
+static long long
+ _TG_ATTRS
+ __tg_llrint(float __x) {return llrintf(__x);}
+
+static long long
+ _TG_ATTRS
+ __tg_llrint(double __x) {return llrint(__x);}
+
+static long long
+ _TG_ATTRS
+ __tg_llrint(long double __x) {return llrintl(__x);}
+
+#undef llrint
+#define llrint(__x) __tg_llrint(__tg_promote1((__x))(__x))
+
+// llround
+
+static long long
+ _TG_ATTRS
+ __tg_llround(float __x) {return llroundf(__x);}
+
+static long long
+ _TG_ATTRS
+ __tg_llround(double __x) {return llround(__x);}
+
+static long long
+ _TG_ATTRS
+ __tg_llround(long double __x) {return llroundl(__x);}
+
+#undef llround
+#define llround(__x) __tg_llround(__tg_promote1((__x))(__x))
+
+// log10
+
+static float
+ _TG_ATTRS
+ __tg_log10(float __x) {return log10f(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_log10(double __x) {return log10(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_log10(long double __x) {return log10l(__x);}
+
+#undef log10
+#define log10(__x) __tg_log10(__tg_promote1((__x))(__x))
+
+// log1p
+
+static float
+ _TG_ATTRS
+ __tg_log1p(float __x) {return log1pf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_log1p(double __x) {return log1p(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_log1p(long double __x) {return log1pl(__x);}
+
+#undef log1p
+#define log1p(__x) __tg_log1p(__tg_promote1((__x))(__x))
+
+// log2
+
+static float
+ _TG_ATTRS
+ __tg_log2(float __x) {return log2f(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_log2(double __x) {return log2(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_log2(long double __x) {return log2l(__x);}
+
+#undef log2
+#define log2(__x) __tg_log2(__tg_promote1((__x))(__x))
+
+// lrint
+
+static long
+ _TG_ATTRS
+ __tg_lrint(float __x) {return lrintf(__x);}
+
+static long
+ _TG_ATTRS
+ __tg_lrint(double __x) {return lrint(__x);}
+
+static long
+ _TG_ATTRS
+ __tg_lrint(long double __x) {return lrintl(__x);}
+
+#undef lrint
+#define lrint(__x) __tg_lrint(__tg_promote1((__x))(__x))
+
+// lround
+
+static long
+ _TG_ATTRS
+ __tg_lround(float __x) {return lroundf(__x);}
+
+static long
+ _TG_ATTRS
+ __tg_lround(double __x) {return lround(__x);}
+
+static long
+ _TG_ATTRS
+ __tg_lround(long double __x) {return lroundl(__x);}
+
+#undef lround
+#define lround(__x) __tg_lround(__tg_promote1((__x))(__x))
+
+// nearbyint
+
+static float
+ _TG_ATTRS
+ __tg_nearbyint(float __x) {return nearbyintf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_nearbyint(double __x) {return nearbyint(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_nearbyint(long double __x) {return nearbyintl(__x);}
+
+#undef nearbyint
+#define nearbyint(__x) __tg_nearbyint(__tg_promote1((__x))(__x))
+
+// nextafter
+
+static float
+ _TG_ATTRS
+ __tg_nextafter(float __x, float __y) {return nextafterf(__x, __y);}
+
+static double
+ _TG_ATTRS
+ __tg_nextafter(double __x, double __y) {return nextafter(__x, __y);}
+
+static long double
+ _TG_ATTRS
+ __tg_nextafter(long double __x, long double __y) {return nextafterl(__x, __y);}
+
+#undef nextafter
+#define nextafter(__x, __y) __tg_nextafter(__tg_promote2((__x), (__y))(__x), \
+ __tg_promote2((__x), (__y))(__y))
+
+// nexttoward
+
+static float
+ _TG_ATTRS
+ __tg_nexttoward(float __x, float __y) {return nexttowardf(__x, __y);}
+
+static double
+ _TG_ATTRS
+ __tg_nexttoward(double __x, 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))
+
+// remainder
+
+static float
+ _TG_ATTRS
+ __tg_remainder(float __x, float __y) {return remainderf(__x, __y);}
+
+static double
+ _TG_ATTRS
+ __tg_remainder(double __x, double __y) {return remainder(__x, __y);}
+
+static long double
+ _TG_ATTRS
+ __tg_remainder(long double __x, long double __y) {return remainderl(__x, __y);}
+
+#undef remainder
+#define remainder(__x, __y) __tg_remainder(__tg_promote2((__x), (__y))(__x), \
+ __tg_promote2((__x), (__y))(__y))
+
+// remquo
+
+static float
+ _TG_ATTRS
+ __tg_remquo(float __x, float __y, int* __z)
+ {return remquof(__x, __y, __z);}
+
+static double
+ _TG_ATTRS
+ __tg_remquo(double __x, double __y, int* __z)
+ {return remquo(__x, __y, __z);}
+
+static long double
+ _TG_ATTRS
+ __tg_remquo(long double __x,long double __y, int* __z)
+ {return remquol(__x, __y, __z);}
+
+#undef remquo
+#define remquo(__x, __y, __z) \
+ __tg_remquo(__tg_promote2((__x), (__y))(__x), \
+ __tg_promote2((__x), (__y))(__y), \
+ (__z))
+
+// rint
+
+static float
+ _TG_ATTRS
+ __tg_rint(float __x) {return rintf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_rint(double __x) {return rint(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_rint(long double __x) {return rintl(__x);}
+
+#undef rint
+#define rint(__x) __tg_rint(__tg_promote1((__x))(__x))
+
+// round
+
+static float
+ _TG_ATTRS
+ __tg_round(float __x) {return roundf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_round(double __x) {return round(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_round(long double __x) {return roundl(__x);}
+
+#undef round
+#define round(__x) __tg_round(__tg_promote1((__x))(__x))
+
+// scalbn
+
+static float
+ _TG_ATTRS
+ __tg_scalbn(float __x, int __y) {return scalbnf(__x, __y);}
+
+static double
+ _TG_ATTRS
+ __tg_scalbn(double __x, int __y) {return scalbn(__x, __y);}
+
+static long double
+ _TG_ATTRS
+ __tg_scalbn(long double __x, int __y) {return scalbnl(__x, __y);}
+
+#undef scalbn
+#define scalbn(__x, __y) __tg_scalbn(__tg_promote1((__x))(__x), __y)
+
+// scalbln
+
+static float
+ _TG_ATTRS
+ __tg_scalbln(float __x, long __y) {return scalblnf(__x, __y);}
+
+static double
+ _TG_ATTRS
+ __tg_scalbln(double __x, long __y) {return scalbln(__x, __y);}
+
+static long double
+ _TG_ATTRS
+ __tg_scalbln(long double __x, long __y) {return scalblnl(__x, __y);}
+
+#undef scalbln
+#define scalbln(__x, __y) __tg_scalbln(__tg_promote1((__x))(__x), __y)
+
+// tgamma
+
+static float
+ _TG_ATTRS
+ __tg_tgamma(float __x) {return tgammaf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_tgamma(double __x) {return tgamma(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_tgamma(long double __x) {return tgammal(__x);}
+
+#undef tgamma
+#define tgamma(__x) __tg_tgamma(__tg_promote1((__x))(__x))
+
+// trunc
+
+static float
+ _TG_ATTRS
+ __tg_trunc(float __x) {return truncf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_trunc(double __x) {return trunc(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_trunc(long double __x) {return truncl(__x);}
+
+#undef trunc
+#define trunc(__x) __tg_trunc(__tg_promote1((__x))(__x))
+
+// carg
+
+static float
+ _TG_ATTRS
+ __tg_carg(float __x) {return atan2f(0.F, __x);}
+
+static double
+ _TG_ATTRS
+ __tg_carg(double __x) {return atan2(0., __x);}
+
+static long double
+ _TG_ATTRS
+ __tg_carg(long double __x) {return atan2l(0.L, __x);}
+
+static float
+ _TG_ATTRS
+ __tg_carg(float _Complex __x) {return cargf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_carg(double _Complex __x) {return carg(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_carg(long double _Complex __x) {return cargl(__x);}
+
+#undef carg
+#define carg(__x) __tg_carg(__tg_promote1((__x))(__x))
+
+// cimag
+
+static float
+ _TG_ATTRS
+ __tg_cimag(float __x) {return 0;}
+
+static double
+ _TG_ATTRS
+ __tg_cimag(double __x) {return 0;}
+
+static long double
+ _TG_ATTRS
+ __tg_cimag(long double __x) {return 0;}
+
+static float
+ _TG_ATTRS
+ __tg_cimag(float _Complex __x) {return cimagf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_cimag(double _Complex __x) {return cimag(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_cimag(long double _Complex __x) {return cimagl(__x);}
+
+#undef cimag
+#define cimag(__x) __tg_cimag(__tg_promote1((__x))(__x))
+
+// conj
+
+static float _Complex
+ _TG_ATTRS
+ __tg_conj(float __x) {return __x;}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_conj(double __x) {return __x;}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_conj(long double __x) {return __x;}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_conj(float _Complex __x) {return conjf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_conj(double _Complex __x) {return conj(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_conj(long double _Complex __x) {return conjl(__x);}
+
+#undef conj
+#define conj(__x) __tg_conj(__tg_promote1((__x))(__x))
+
+// cproj
+
+static float _Complex
+ _TG_ATTRS
+ __tg_cproj(float __x) {return cprojf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_cproj(double __x) {return cproj(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_cproj(long double __x) {return cprojl(__x);}
+
+static float _Complex
+ _TG_ATTRS
+ __tg_cproj(float _Complex __x) {return cprojf(__x);}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_cproj(double _Complex __x) {return cproj(__x);}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_cproj(long double _Complex __x) {return cprojl(__x);}
+
+#undef cproj
+#define cproj(__x) __tg_cproj(__tg_promote1((__x))(__x))
+
+// creal
+
+static float _Complex
+ _TG_ATTRS
+ __tg_creal(float __x) {return __x;}
+
+static double _Complex
+ _TG_ATTRS
+ __tg_creal(double __x) {return __x;}
+
+static long double _Complex
+ _TG_ATTRS
+ __tg_creal(long double __x) {return __x;}
+
+static float
+ _TG_ATTRS
+ __tg_creal(float _Complex __x) {return crealf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_creal(double _Complex __x) {return creal(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_creal(long double _Complex __x) {return creall(__x);}
+
+#undef creal
+#define creal(__x) __tg_creal(__tg_promote1((__x))(__x))
+
+#undef _TG_ATTRSp
+#undef _TG_ATTRS
+
+#endif /* __cplusplus */
+#endif /* __TGMATH_H */
diff --git a/lib/Headers/tmmintrin.h b/lib/Headers/tmmintrin.h
new file mode 100644
index 000000000000..e9715f13d755
--- /dev/null
+++ b/lib/Headers/tmmintrin.h
@@ -0,0 +1,218 @@
+/*===---- tmmintrin.h - SSSE3 intrinsics -----------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __TMMINTRIN_H
+#define __TMMINTRIN_H
+
+#ifndef __SSSE3__
+#error "SSSE3 instruction set not enabled"
+#else
+
+#include <pmmintrin.h>
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_abs_pi8(__m64 a)
+{
+ return (__m64)__builtin_ia32_pabsb((__v8qi)a);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_abs_epi8(__m128i a)
+{
+ return (__m128i)__builtin_ia32_pabsb128((__v16qi)a);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_abs_pi16(__m64 a)
+{
+ return (__m64)__builtin_ia32_pabsw((__v4hi)a);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_abs_epi16(__m128i a)
+{
+ return (__m128i)__builtin_ia32_pabsw128((__v8hi)a);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_abs_pi32(__m64 a)
+{
+ return (__m64)__builtin_ia32_pabsd((__v2si)a);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_abs_epi32(__m128i a)
+{
+ return (__m128i)__builtin_ia32_pabsd128((__v4si)a);
+}
+
+#define _mm_alignr_epi8(a, b, n) (__builtin_ia32_palignr128((a), (b), (n)))
+#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n)))
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_hadd_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_phaddw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_hadd_epi32(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_phaddd128((__v4si)a, (__v4si)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_hadd_pi16(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_phaddw((__v4hi)a, (__v4hi)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_hadd_pi32(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_phaddd((__v2si)a, (__v2si)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_hadds_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_phaddsw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_hadds_pi16(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_phaddsw((__v4hi)a, (__v4hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_hsub_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_phsubw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_hsub_epi32(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_psubd128((__v4si)a, (__v4si)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_hsub_pi16(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_psubw((__v4hi)a, (__v4hi)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_hsub_pi32(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_psubd((__v2si)a, (__v2si)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_hsubs_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_phsubsw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_hsubs_pi16(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_phsubsw((__v4hi)a, (__v4hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_maddubs_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pmaddubsw128((__v16qi)a, (__v16qi)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_maddubs_pi16(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_pmaddubsw((__v8qi)a, (__v8qi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_mulhrs_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pmulhrsw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_mulhrs_pi16(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_pmulhrsw((__v4hi)a, (__v4hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_shuffle_epi8(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_pshufb128((__v16qi)a, (__v16qi)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_shuffle_pi8(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_pshufb((__v8qi)a, (__v8qi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sign_epi8(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_psignb128((__v16qi)a, (__v16qi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sign_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_psignw128((__v8hi)a, (__v8hi)b);
+}
+
+static inline __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sign_epi32(__m128i a, __m128i b)
+{
+ return (__m128i)__builtin_ia32_psignd128((__v4si)a, (__v4si)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_sign_pi8(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_psignb((__v8qi)a, (__v8qi)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_sign_pi16(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_psignw((__v4hi)a, (__v4hi)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_sign_pi32(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_psignd((__v2si)a, (__v2si)b);
+}
+
+#endif /* __SSSE3__ */
+
+#endif /* __TMMINTRIN_H */
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
new file mode 100644
index 000000000000..c104f6301a0c
--- /dev/null
+++ b/lib/Headers/xmmintrin.h
@@ -0,0 +1,888 @@
+/*===---- xmmintrin.h - SSE intrinsics -------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __XMMINTRIN_H
+#define __XMMINTRIN_H
+
+#ifndef __SSE__
+#error "SSE instruction set not enabled"
+#else
+
+#include <mmintrin.h>
+
+typedef float __v4sf __attribute__((__vector_size__(16)));
+typedef float __m128 __attribute__((__vector_size__(16)));
+
+#include <mm_malloc.h>
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_add_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_addss(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_add_ps(__m128 a, __m128 b)
+{
+ return a + b;
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_sub_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_subss(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_sub_ps(__m128 a, __m128 b)
+{
+ return a - b;
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_mul_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_mulss(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_mul_ps(__m128 a, __m128 b)
+{
+ return a * b;
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_div_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_divss(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_div_ps(__m128 a, __m128 b)
+{
+ return a / b;
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_sqrt_ss(__m128 a)
+{
+ return __builtin_ia32_sqrtss(a);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_sqrt_ps(__m128 a)
+{
+ return __builtin_ia32_sqrtps(a);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_rcp_ss(__m128 a)
+{
+ return __builtin_ia32_rcpss(a);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_rcp_ps(__m128 a)
+{
+ return __builtin_ia32_rcpps(a);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_rsqrt_ss(__m128 a)
+{
+ return __builtin_ia32_rsqrtss(a);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_rsqrt_ps(__m128 a)
+{
+ return __builtin_ia32_rsqrtps(a);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_min_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_minss(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_min_ps(__m128 a, __m128 b)
+{
+ return __builtin_ia32_minps(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_max_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_maxss(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_max_ps(__m128 a, __m128 b)
+{
+ return __builtin_ia32_maxps(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_and_ps(__m128 a, __m128 b)
+{
+ return __builtin_ia32_andps(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_andnot_ps(__m128 a, __m128 b)
+{
+ return __builtin_ia32_andnps(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_or_ps(__m128 a, __m128 b)
+{
+ return __builtin_ia32_orps(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_xor_ps(__m128 a, __m128 b)
+{
+ return __builtin_ia32_xorps(a, b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpeq_ss(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpss(a, b, 0);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpeq_ps(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpps(a, b, 0);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmplt_ss(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpss(a, b, 1);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmplt_ps(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpps(a, b, 1);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmple_ss(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpss(a, b, 2);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmple_ps(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpps(a, b, 2);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpgt_ss(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpss(b, a, 1);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpgt_ps(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpps(b, a, 1);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpge_ss(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpss(b, a, 2);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpge_ps(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpps(b, a, 2);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpneq_ss(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpss(a, b, 4);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpneq_ps(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpps(a, b, 4);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpnlt_ss(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpss(a, b, 5);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpnlt_ps(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpps(a, b, 5);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpnle_ss(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpss(a, b, 6);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpnle_ps(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpps(a, b, 6);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpngt_ss(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpss(b, a, 5);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpngt_ps(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpps(b, a, 5);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpnge_ss(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpss(b, a, 6);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpnge_ps(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpps(b, a, 6);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpord_ss(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpss(a, b, 7);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpord_ps(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpps(a, b, 7);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpunord_ss(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpss(a, b, 3);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cmpunord_ps(__m128 a, __m128 b)
+{
+ return (__m128)__builtin_ia32_cmpps(a, b, 3);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_comieq_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_comieq(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_comilt_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_comilt(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_comile_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_comile(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_comigt_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_comigt(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_comige_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_comige(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_comineq_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_comineq(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_ucomieq_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_ucomieq(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_ucomilt_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_ucomilt(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_ucomile_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_ucomile(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_ucomigt_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_ucomigt(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_ucomige_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_ucomige(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_ucomineq_ss(__m128 a, __m128 b)
+{
+ return __builtin_ia32_ucomineq(a, b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_cvtss_si32(__m128 a)
+{
+ return __builtin_ia32_cvtss2si(a);
+}
+
+static inline long long __attribute__((__always_inline__, __nodebug__))
+_mm_cvtss_si64(__m128 a)
+{
+ return __builtin_ia32_cvtss2si64(a);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtps_pi32(__m128 a)
+{
+ return (__m64)__builtin_ia32_cvtps2pi(a);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_cvttss_si32(__m128 a)
+{
+ return __builtin_ia32_cvttss2si(a);
+}
+
+static inline long long __attribute__((__always_inline__, __nodebug__))
+_mm_cvttss_si64(__m128 a)
+{
+ return __builtin_ia32_cvttss2si64(a);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_cvttps_pi32(__m128 a)
+{
+ return (__m64)__builtin_ia32_cvttps2pi(a);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtsi32_ss(__m128 a, int b)
+{
+ return __builtin_ia32_cvtsi2ss(a, b);
+}
+
+#ifdef __x86_64__
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtsi64_ss(__m128 a, long long b)
+{
+ return __builtin_ia32_cvtsi642ss(a, b);
+}
+
+#endif
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtpi32_ps(__m128 a, __m64 b)
+{
+ return __builtin_ia32_cvtpi2ps(a, (__v2si)b);
+}
+
+static inline float __attribute__((__always_inline__, __nodebug__))
+_mm_cvtss_f32(__m128 a)
+{
+ return a[0];
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_loadh_pi(__m128 a, __m64 const *p)
+{
+ return __builtin_ia32_loadhps(a, (__v2si *)p);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_loadl_pi(__m128 a, __m64 const *p)
+{
+ return __builtin_ia32_loadlps(a, (__v2si *)p);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_load_ss(float *p)
+{
+ return (__m128){ *p, 0, 0, 0 };
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_load1_ps(float *p)
+{
+ return (__m128){ *p, *p, *p, *p };
+}
+
+#define _mm_load_ps1(p) _mm_load1_ps(p)
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_load_ps(float *p)
+{
+ return *(__m128*)p;
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_loadu_ps(float *p)
+{
+ return __builtin_ia32_loadups(p);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_loadr_ps(float *p)
+{
+ __m128 a = _mm_load_ps(p);
+ return __builtin_shufflevector(a, a, 3, 2, 1, 0);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_set_ss(float w)
+{
+ return (__m128){ w, 0, 0, 0 };
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_set1_ps(float w)
+{
+ return (__m128){ w, w, w, w };
+}
+
+// Microsoft specific.
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_set_ps1(float w)
+{
+ return _mm_set1_ps(w);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_set_ps(float z, float y, float x, float w)
+{
+ return (__m128){ w, x, y, z };
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_setr_ps(float z, float y, float x, float w)
+{
+ return (__m128){ z, y, x, w };
+}
+
+static inline __m128 __attribute__((__always_inline__))
+_mm_setzero_ps(void)
+{
+ return (__m128){ 0, 0, 0, 0 };
+}
+
+static inline void __attribute__((__always_inline__))
+_mm_storeh_pi(__m64 *p, __m128 a)
+{
+ __builtin_ia32_storehps((__v2si *)p, a);
+}
+
+static inline void __attribute__((__always_inline__))
+_mm_storel_pi(__m64 *p, __m128 a)
+{
+ __builtin_ia32_storelps((__v2si *)p, a);
+}
+
+static inline void __attribute__((__always_inline__))
+_mm_store_ss(float *p, __m128 a)
+{
+ *p = a[0];
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_storeu_ps(float *p, __m128 a)
+{
+ __builtin_ia32_storeups(p, a);
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_store1_ps(float *p, __m128 a)
+{
+ a = __builtin_shufflevector(a, a, 0, 0, 0, 0);
+ _mm_storeu_ps(p, a);
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_store_ps(float *p, __m128 a)
+{
+ *(__m128 *)p = a;
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_storer_ps(float *p, __m128 a)
+{
+ a = __builtin_shufflevector(a, a, 3, 2, 1, 0);
+ _mm_store_ps(p, a);
+}
+
+#define _MM_HINT_T0 1
+#define _MM_HINT_T1 2
+#define _MM_HINT_T2 3
+#define _MM_HINT_NTA 0
+
+/* FIXME: We have to #define this because "sel" must be a constant integer, and
+ Sema doesn't do any form of constant propagation yet. */
+
+#define _mm_prefetch(a, sel) (__builtin_prefetch((void *)a, 0, sel))
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_stream_pi(__m64 *p, __m64 a)
+{
+ __builtin_ia32_movntq(p, a);
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_stream_ps(float *p, __m128 a)
+{
+ __builtin_ia32_movntps(p, a);
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_sfence(void)
+{
+ __builtin_ia32_sfence();
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_extract_pi16(__m64 a, int n)
+{
+ /* FIXME:
+ * This should force n to be an immediate.
+ * This does not use the PEXTRW instruction. From looking at the LLVM source, the
+ instruction doesn't seem to be hooked up.
+ * The code could probably be made better :)
+ */
+ __v4hi b = (__v4hi)a;
+ return b[(n == 0) ? 0 : (n == 1 ? 1 : (n == 2 ? 2 : 3))];
+}
+
+/* FIXME: Implement this. We could add a __builtin_insertelement function that's similar to
+ the already existing __builtin_shufflevector.
+*/
+/*
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_insert_pi16(__m64 a, int d, int n)
+{
+ return (__m64){ 0LL };
+}
+*/
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_max_pi16(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_pmaxsw((__v4hi)a, (__v4hi)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_max_pu8(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_pmaxub((__v8qi)a, (__v8qi)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_min_pi16(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_pminsw((__v4hi)a, (__v4hi)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_min_pu8(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_pminub((__v8qi)a, (__v8qi)b);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_movemask_pi8(__m64 a)
+{
+ return __builtin_ia32_pmovmskb((__v8qi)a);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_mulhi_pu16(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_pmulhuw((__v4hi)a, (__v4hi)b);
+}
+
+#define _mm_shuffle_pi16(a, n) ((__m64)__builtin_ia32_pshufw((__v4hi)a, n))
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_maskmove_si64(__m64 d, __m64 n, char *p)
+{
+ __builtin_ia32_maskmovq((__v8qi)d, (__v8qi)n, p);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_avg_pu8(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_pavgb((__v8qi)a, (__v8qi)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_avg_pu16(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_pavgw((__v4hi)a, (__v4hi)b);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_sad_pu8(__m64 a, __m64 b)
+{
+ return (__m64)__builtin_ia32_psadbw((__v8qi)a, (__v8qi)b);
+}
+
+static inline unsigned int __attribute__((__always_inline__, __nodebug__))
+_mm_getcsr(void)
+{
+ return __builtin_ia32_stmxcsr();
+}
+
+static inline void __attribute__((__always_inline__, __nodebug__))
+_mm_setcsr(unsigned int i)
+{
+ __builtin_ia32_ldmxcsr(i);
+}
+
+#define _mm_shuffle_ps(a, b, mask) (__builtin_ia32_shufps(a, b, mask))
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_unpackhi_ps(__m128 a, __m128 b)
+{
+ return __builtin_shufflevector(a, b, 2, 6, 3, 7);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_unpacklo_ps(__m128 a, __m128 b)
+{
+ return __builtin_shufflevector(a, b, 0, 4, 1, 5);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_move_ss(__m128 a, __m128 b)
+{
+ return __builtin_shufflevector(a, b, 4, 1, 2, 3);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_movehl_ps(__m128 a, __m128 b)
+{
+ return __builtin_shufflevector(a, b, 6, 7, 2, 3);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_movelh_ps(__m128 a, __m128 b)
+{
+ return __builtin_shufflevector(a, b, 0, 1, 4, 5);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtpi16_ps(__m64 a)
+{
+ __m64 b, c;
+ __m128 r;
+
+ b = _mm_setzero_si64();
+ b = _mm_cmpgt_pi16(b, a);
+ c = _mm_unpackhi_pi16(a, b);
+ r = _mm_setzero_ps();
+ r = _mm_cvtpi32_ps(r, c);
+ r = _mm_movelh_ps(r, r);
+ c = _mm_unpacklo_pi16(a, b);
+ r = _mm_cvtpi32_ps(r, c);
+
+ return r;
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtpu16_ps(__m64 a)
+{
+ __m64 b, c;
+ __m128 r;
+
+ b = _mm_setzero_si64();
+ c = _mm_unpackhi_pi16(a, b);
+ r = _mm_setzero_ps();
+ r = _mm_cvtpi32_ps(r, c);
+ r = _mm_movelh_ps(r, r);
+ c = _mm_unpacklo_pi16(a, b);
+ r = _mm_cvtpi32_ps(r, c);
+
+ return r;
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtpi8_ps(__m64 a)
+{
+ __m64 b;
+
+ b = _mm_setzero_si64();
+ b = _mm_cmpgt_pi8(b, a);
+ b = _mm_unpacklo_pi8(a, b);
+
+ return _mm_cvtpi16_ps(b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtpu8_ps(__m64 a)
+{
+ __m64 b;
+
+ b = _mm_setzero_si64();
+ b = _mm_unpacklo_pi8(a, b);
+
+ return _mm_cvtpi16_ps(b);
+}
+
+static inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtpi32x2_ps(__m64 a, __m64 b)
+{
+ __m128 c;
+
+ c = _mm_setzero_ps();
+ c = _mm_cvtpi32_ps(c, b);
+ c = _mm_movelh_ps(c, c);
+
+ return _mm_cvtpi32_ps(c, a);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtps_pi16(__m128 a)
+{
+ __m64 b, c;
+
+ b = _mm_cvtps_pi32(a);
+ a = _mm_movehl_ps(a, a);
+ c = _mm_cvtps_pi32(a);
+
+ return _mm_packs_pi16(b, c);
+}
+
+static inline __m64 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtps_pi8(__m128 a)
+{
+ __m64 b, c;
+
+ b = _mm_cvtps_pi16(a);
+ c = _mm_setzero_si64();
+
+ return _mm_packs_pi16(b, c);
+}
+
+static inline int __attribute__((__always_inline__, __nodebug__))
+_mm_movemask_ps(__m128 a)
+{
+ return __builtin_ia32_movmskps(a);
+}
+
+#define _MM_SHUFFLE(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w))
+
+#define _MM_EXCEPT_INVALID (0x0001)
+#define _MM_EXCEPT_DENORM (0x0002)
+#define _MM_EXCEPT_DIV_ZERO (0x0004)
+#define _MM_EXCEPT_OVERFLOW (0x0008)
+#define _MM_EXCEPT_UNDERFLOW (0x0010)
+#define _MM_EXCEPT_INEXACT (0x0020)
+#define _MM_EXCEPT_MASK (0x003f)
+
+#define _MM_MASK_INVALID (0x0080)
+#define _MM_MASK_DENORM (0x0100)
+#define _MM_MASK_DIV_ZERO (0x0200)
+#define _MM_MASK_OVERFLOW (0x0400)
+#define _MM_MASK_UNDERFLOW (0x0800)
+#define _MM_MASK_INEXACT (0x1000)
+#define _MM_MASK_MASK (0x1f80)
+
+#define _MM_ROUND_NEAREST (0x0000)
+#define _MM_ROUND_DOWN (0x2000)
+#define _MM_ROUND_UP (0x4000)
+#define _MM_ROUND_TOWARD_ZERO (0x6000)
+#define _MM_ROUND_MASK (0x6000)
+
+#define _MM_FLUSH_ZERO_MASK (0x8000)
+#define _MM_FLUSH_ZERO_ON (0x8000)
+#define _MM_FLUSH_ZERO_OFF (0x8000)
+
+#define _MM_GET_EXCEPTION_MASK() (_mm_getcsr() & _MM_MASK_MASK)
+#define _MM_GET_EXCEPTION_STATE() (_mm_getcsr() & _MM_EXCEPT_MASK)
+#define _MM_GET_FLUSH_ZERO_MODE() (_mm_getcsr() & _MM_FLUSH_ZERO_MASK)
+#define _MM_GET_ROUNDING_MODE() (_mm_getcsr() & _MM_ROUND_MASK)
+
+#define _MM_SET_EXCEPTION_MASK(x) (_mm_setcsr((_mm_getcsr() & ~_MM_MASK_MASK) | (x)))
+#define _MM_SET_EXCEPTION_STATE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_EXCEPT_MASK) | (x)))
+#define _MM_SET_FLUSH_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_FLUSH_ZERO_MASK) | (x)))
+#define _MM_SET_ROUNDING_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_ROUND_MASK) | (x)))
+
+#define _MM_TRANSPOSE4_PS(row0, row1, row2, row3) \
+do { \
+ __m128 tmp3, tmp2, tmp1, tmp0; \
+ tmp0 = _mm_unpacklo_ps((row0), (row1)); \
+ tmp2 = _mm_unpacklo_ps((row2), (row3)); \
+ tmp1 = _mm_unpackhi_ps((row0), (row1)); \
+ tmp3 = _mm_unpackhi_ps((row2), (row3)); \
+ (row0) = _mm_movelh_ps(tmp0, tmp2); \
+ (row1) = _mm_movehl_ps(tmp2, tmp0); \
+ (row2) = _mm_movelh_ps(tmp1, tmp3); \
+ (row3) = _mm_movelh_ps(tmp3, tmp1); \
+} while (0)
+
+#include <emmintrin.h>
+
+#endif /* __SSE__ */
+
+#endif /* __XMMINTRIN_H */
diff --git a/lib/Lex/CMakeLists.txt b/lib/Lex/CMakeLists.txt
new file mode 100644
index 000000000000..a7237a7b76f6
--- /dev/null
+++ b/lib/Lex/CMakeLists.txt
@@ -0,0 +1,26 @@
+set(LLVM_NO_RTTI 1)
+
+# TODO: Add -maltivec when ARCH is PowerPC.
+
+add_clang_library(clangLex
+ HeaderMap.cpp
+ HeaderSearch.cpp
+ Lexer.cpp
+ LiteralSupport.cpp
+ MacroArgs.cpp
+ MacroInfo.cpp
+ PPCaching.cpp
+ PPDirectives.cpp
+ PPExpressions.cpp
+ PPLexerChange.cpp
+ PPMacroExpansion.cpp
+ Pragma.cpp
+ Preprocessor.cpp
+ PreprocessorLexer.cpp
+ PTHLexer.cpp
+ ScratchBuffer.cpp
+ TokenLexer.cpp
+ TokenConcatenation.cpp
+ )
+
+add_dependencies(clangLex ClangDiagnosticLex)
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
new file mode 100644
index 000000000000..4c8b70eb7821
--- /dev/null
+++ b/lib/Lex/HeaderMap.cpp
@@ -0,0 +1,245 @@
+//===--- HeaderMap.cpp - A file that acts like dir of symlinks ------------===//
+//
+// 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 HeaderMap interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/HeaderMap.h"
+#include "clang/Basic/FileManager.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <cstdio>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Data Structures and Manifest Constants
+//===----------------------------------------------------------------------===//
+
+enum {
+ HMAP_HeaderMagicNumber = ('h' << 24) | ('m' << 16) | ('a' << 8) | 'p',
+ HMAP_HeaderVersion = 1,
+
+ HMAP_EmptyBucketKey = 0
+};
+
+namespace clang {
+struct HMapBucket {
+ uint32_t Key; // Offset (into strings) of key.
+
+ uint32_t Prefix; // Offset (into strings) of value prefix.
+ uint32_t Suffix; // Offset (into strings) of value suffix.
+};
+
+struct HMapHeader {
+ uint32_t Magic; // Magic word, also indicates byte order.
+ uint16_t Version; // Version number -- currently 1.
+ uint16_t Reserved; // Reserved for future use - zero for now.
+ uint32_t StringsOffset; // Offset to start of string pool.
+ uint32_t NumEntries; // Number of entries in the string table.
+ uint32_t NumBuckets; // Number of buckets (always a power of 2).
+ uint32_t MaxValueLength; // Length of longest result path (excluding nul).
+ // An array of 'NumBuckets' HMapBucket objects follows this header.
+ // Strings follow the buckets, at StringsOffset.
+};
+} // end namespace clang.
+
+/// 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(const char *S, const char *End) {
+ unsigned Result = 0;
+
+ for (; S != End; S++)
+ Result += tolower(*S) * 13;
+ return Result;
+}
+
+
+
+//===----------------------------------------------------------------------===//
+// Verification and Construction
+//===----------------------------------------------------------------------===//
+
+/// HeaderMap::Create - This attempts to load the specified file as a header
+/// map. If it doesn't look like a HeaderMap, it gives up and returns null.
+/// If it looks like a HeaderMap but is obviously corrupted, it puts a reason
+/// into the string error argument and returns null.
+const HeaderMap *HeaderMap::Create(const FileEntry *FE) {
+ // If the file is too small to be a header map, ignore it.
+ unsigned FileSize = FE->getSize();
+ if (FileSize <= sizeof(HMapHeader)) return 0;
+
+ llvm::OwningPtr<const llvm::MemoryBuffer> FileBuffer(
+ llvm::MemoryBuffer::getFile(FE->getName(), 0, FE->getSize()));
+ if (FileBuffer == 0) return 0; // Unreadable file?
+ const char *FileStart = FileBuffer->getBufferStart();
+
+ // We know the file is at least as big as the header, check it now.
+ const HMapHeader *Header = reinterpret_cast<const HMapHeader*>(FileStart);
+
+ // Sniff it to see if it's a headermap by checking the magic number and
+ // version.
+ bool NeedsByteSwap;
+ if (Header->Magic == HMAP_HeaderMagicNumber &&
+ Header->Version == HMAP_HeaderVersion)
+ NeedsByteSwap = false;
+ else if (Header->Magic == llvm::ByteSwap_32(HMAP_HeaderMagicNumber) &&
+ Header->Version == llvm::ByteSwap_16(HMAP_HeaderVersion))
+ NeedsByteSwap = true; // Mixed endianness headermap.
+ else
+ return 0; // Not a header map.
+
+ if (Header->Reserved != 0) return 0;
+
+ // Okay, everything looks good, create the header map.
+ return new HeaderMap(FileBuffer.take(), NeedsByteSwap);
+}
+
+HeaderMap::~HeaderMap() {
+ delete FileBuffer;
+}
+
+//===----------------------------------------------------------------------===//
+// Utility Methods
+//===----------------------------------------------------------------------===//
+
+
+/// getFileName - Return the filename of the headermap.
+const char *HeaderMap::getFileName() const {
+ return FileBuffer->getBufferIdentifier();
+}
+
+unsigned HeaderMap::getEndianAdjustedWord(unsigned X) const {
+ if (!NeedsBSwap) return X;
+ return llvm::ByteSwap_32(X);
+}
+
+/// getHeader - Return a reference to the file header, in unbyte-swapped form.
+/// This method cannot fail.
+const HMapHeader &HeaderMap::getHeader() const {
+ // We know the file is at least as big as the header. Return it.
+ return *reinterpret_cast<const HMapHeader*>(FileBuffer->getBufferStart());
+}
+
+/// getBucket - Return the specified hash table bucket from the header map,
+/// bswap'ing its fields as appropriate. If the bucket number is not valid,
+/// this return a bucket with an empty key (0).
+HMapBucket HeaderMap::getBucket(unsigned BucketNo) const {
+ HMapBucket Result;
+ Result.Key = HMAP_EmptyBucketKey;
+
+ const HMapBucket *BucketArray =
+ reinterpret_cast<const HMapBucket*>(FileBuffer->getBufferStart() +
+ sizeof(HMapHeader));
+
+ const HMapBucket *BucketPtr = BucketArray+BucketNo;
+ if ((char*)(BucketPtr+1) > FileBuffer->getBufferEnd()) {
+ Result.Prefix = 0;
+ Result.Suffix = 0;
+ return Result; // Invalid buffer, corrupt hmap.
+ }
+
+ // Otherwise, the bucket is valid. Load the values, bswapping as needed.
+ Result.Key = getEndianAdjustedWord(BucketPtr->Key);
+ Result.Prefix = getEndianAdjustedWord(BucketPtr->Prefix);
+ Result.Suffix = getEndianAdjustedWord(BucketPtr->Suffix);
+ return Result;
+}
+
+/// getString - Look up the specified string in the string table. If the string
+/// index is not valid, it returns an empty string.
+const char *HeaderMap::getString(unsigned StrTabIdx) const {
+ // Add the start of the string table to the idx.
+ StrTabIdx += getEndianAdjustedWord(getHeader().StringsOffset);
+
+ // Check for invalid index.
+ if (StrTabIdx >= FileBuffer->getBufferSize())
+ return 0;
+
+ // Otherwise, we have a valid pointer into the file. Just return it. We know
+ // that the "string" can not overrun the end of the file, because the buffer
+ // is nul terminated by virtue of being a MemoryBuffer.
+ return FileBuffer->getBufferStart()+StrTabIdx;
+}
+
+/// StringsEqualWithoutCase - Compare the specified two strings for case-
+/// insensitive equality, returning true if they are equal. Both strings are
+/// known to have the same length.
+static bool StringsEqualWithoutCase(const char *S1, const char *S2,
+ unsigned Len) {
+ for (; Len; ++S1, ++S2, --Len)
+ if (tolower(*S1) != tolower(*S2))
+ return false;
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// The Main Drivers
+//===----------------------------------------------------------------------===//
+
+/// dump - Print the contents of this headermap to stderr.
+void HeaderMap::dump() const {
+ const HMapHeader &Hdr = getHeader();
+ unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);
+
+ fprintf(stderr, "Header Map %s:\n %d buckets, %d entries\n",
+ getFileName(), NumBuckets,
+ getEndianAdjustedWord(Hdr.NumEntries));
+
+ for (unsigned i = 0; i != NumBuckets; ++i) {
+ HMapBucket B = getBucket(i);
+ if (B.Key == HMAP_EmptyBucketKey) continue;
+
+ const char *Key = getString(B.Key);
+ const char *Prefix = getString(B.Prefix);
+ const char *Suffix = getString(B.Suffix);
+ fprintf(stderr, " %d. %s -> '%s' '%s'\n", i, Key, Prefix, Suffix);
+ }
+}
+
+/// 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(const char *FilenameStart,
+ const char *FilenameEnd,
+ FileManager &FM) const {
+ const HMapHeader &Hdr = getHeader();
+ unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);
+
+ // If the number of buckets is not a power of two, the headermap is corrupt.
+ // Don't probe infinitely.
+ if (NumBuckets & (NumBuckets-1))
+ return 0;
+
+ // Linearly probe the hash table.
+ for (unsigned Bucket = HashHMapKey(FilenameStart, FilenameEnd);; ++Bucket) {
+ HMapBucket B = getBucket(Bucket & (NumBuckets-1));
+ if (B.Key == HMAP_EmptyBucketKey) return 0; // Hash miss.
+
+ // See if the key matches. If not, probe on.
+ const char *Key = getString(B.Key);
+ unsigned BucketKeyLen = strlen(Key);
+ if (BucketKeyLen != unsigned(FilenameEnd-FilenameStart))
+ continue;
+
+ // See if the actual strings equal.
+ if (!StringsEqualWithoutCase(FilenameStart, Key, BucketKeyLen))
+ continue;
+
+ // If so, we have a match in the hash table. Construct the destination
+ // path.
+ llvm::SmallString<1024> DestPath;
+ DestPath += getString(B.Prefix);
+ DestPath += getString(B.Suffix);
+ return FM.getFile(DestPath.begin(), DestPath.end());
+ }
+}
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
new file mode 100644
index 000000000000..129fa1ae35fa
--- /dev/null
+++ b/lib/Lex/HeaderSearch.cpp
@@ -0,0 +1,446 @@
+//===--- HeaderSearch.cpp - Resolve Header File Locations ---===//
+//
+// 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 DirectoryLookup and HeaderSearch interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderMap.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "llvm/System/Path.h"
+#include "llvm/ADT/SmallString.h"
+#include <cstdio>
+using namespace clang;
+
+const IdentifierInfo *
+HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
+ if (ControllingMacro)
+ return ControllingMacro;
+
+ if (!ControllingMacroID || !External)
+ return 0;
+
+ ControllingMacro = External->GetIdentifier(ControllingMacroID);
+ return ControllingMacro;
+}
+
+HeaderSearch::HeaderSearch(FileManager &FM) : FileMgr(FM), FrameworkMap(64) {
+ SystemDirIdx = 0;
+ NoCurDirSearch = false;
+
+ ExternalLookup = 0;
+ NumIncluded = 0;
+ NumMultiIncludeFileOptzn = 0;
+ NumFrameworkLookups = NumSubFrameworkLookups = 0;
+}
+
+HeaderSearch::~HeaderSearch() {
+ // Delete headermaps.
+ for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i)
+ delete HeaderMaps[i].second;
+}
+
+void HeaderSearch::PrintStats() {
+ fprintf(stderr, "\n*** HeaderSearch Stats:\n");
+ fprintf(stderr, "%d files tracked.\n", (int)FileInfo.size());
+ unsigned NumOnceOnlyFiles = 0, MaxNumIncludes = 0, NumSingleIncludedFiles = 0;
+ for (unsigned i = 0, e = FileInfo.size(); i != e; ++i) {
+ NumOnceOnlyFiles += FileInfo[i].isImport;
+ if (MaxNumIncludes < FileInfo[i].NumIncludes)
+ MaxNumIncludes = FileInfo[i].NumIncludes;
+ NumSingleIncludedFiles += FileInfo[i].NumIncludes == 1;
+ }
+ fprintf(stderr, " %d #import/#pragma once files.\n", NumOnceOnlyFiles);
+ fprintf(stderr, " %d included exactly once.\n", NumSingleIncludedFiles);
+ fprintf(stderr, " %d max times a file is included.\n", MaxNumIncludes);
+
+ fprintf(stderr, " %d #include/#include_next/#import.\n", NumIncluded);
+ fprintf(stderr, " %d #includes skipped due to"
+ " the multi-include optimization.\n", NumMultiIncludeFileOptzn);
+
+ fprintf(stderr, "%d framework lookups.\n", NumFrameworkLookups);
+ fprintf(stderr, "%d subframework lookups.\n", NumSubFrameworkLookups);
+}
+
+/// CreateHeaderMap - This method returns a HeaderMap for the specified
+/// FileEntry, uniquing them through the the 'HeaderMaps' datastructure.
+const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) {
+ // We expect the number of headermaps to be small, and almost always empty.
+ // If it ever grows, use of a linear search should be re-evaluated.
+ if (!HeaderMaps.empty()) {
+ for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i)
+ // Pointer equality comparison of FileEntries works because they are
+ // already uniqued by inode.
+ if (HeaderMaps[i].first == FE)
+ return HeaderMaps[i].second;
+ }
+
+ if (const HeaderMap *HM = HeaderMap::Create(FE)) {
+ HeaderMaps.push_back(std::make_pair(FE, HM));
+ return HM;
+ }
+
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// File lookup within a DirectoryLookup scope
+//===----------------------------------------------------------------------===//
+
+/// getName - Return the directory or filename corresponding to this lookup
+/// object.
+const char *DirectoryLookup::getName() const {
+ if (isNormalDir())
+ return getDir()->getName();
+ if (isFramework())
+ return getFrameworkDir()->getName();
+ assert(isHeaderMap() && "Unknown DirectoryLookup");
+ return getHeaderMap()->getFileName();
+}
+
+
+/// LookupFile - Lookup the specified file in this search path, returning it
+/// if it exists or returning null if not.
+const FileEntry *DirectoryLookup::LookupFile(const char *FilenameStart,
+ const char *FilenameEnd,
+ HeaderSearch &HS) const {
+ llvm::SmallString<1024> TmpDir;
+ if (isNormalDir()) {
+ // Concatenate the requested file onto the directory.
+ // FIXME: Portability. Filename concatenation should be in sys::Path.
+ TmpDir += getDir()->getName();
+ TmpDir.push_back('/');
+ TmpDir.append(FilenameStart, FilenameEnd);
+ return HS.getFileMgr().getFile(TmpDir.begin(), TmpDir.end());
+ }
+
+ if (isFramework())
+ return DoFrameworkLookup(FilenameStart, FilenameEnd, HS);
+
+ assert(isHeaderMap() && "Unknown directory lookup");
+ return getHeaderMap()->LookupFile(FilenameStart, FilenameEnd,HS.getFileMgr());
+}
+
+
+/// DoFrameworkLookup - Do a lookup of the specified file in the current
+/// DirectoryLookup, which is a framework directory.
+const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart,
+ const char *FilenameEnd,
+ HeaderSearch &HS) const {
+ FileManager &FileMgr = HS.getFileMgr();
+
+ // Framework names must have a '/' in the filename.
+ const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/');
+ if (SlashPos == FilenameEnd) return 0;
+
+ // Find out if this is the home for the specified framework, by checking
+ // HeaderSearch. Possible answer are yes/no and unknown.
+ const DirectoryEntry *&FrameworkDirCache =
+ HS.LookupFrameworkCache(FilenameStart, SlashPos);
+
+ // If it is known and in some other directory, fail.
+ if (FrameworkDirCache && FrameworkDirCache != getFrameworkDir())
+ return 0;
+
+ // Otherwise, construct the path to this framework dir.
+
+ // FrameworkName = "/System/Library/Frameworks/"
+ llvm::SmallString<1024> FrameworkName;
+ FrameworkName += getFrameworkDir()->getName();
+ if (FrameworkName.empty() || FrameworkName.back() != '/')
+ FrameworkName.push_back('/');
+
+ // FrameworkName = "/System/Library/Frameworks/Cocoa"
+ FrameworkName.append(FilenameStart, SlashPos);
+
+ // FrameworkName = "/System/Library/Frameworks/Cocoa.framework/"
+ FrameworkName += ".framework/";
+
+ // If the cache entry is still unresolved, query to see if the cache entry is
+ // still unresolved. If so, check its existence now.
+ if (FrameworkDirCache == 0) {
+ HS.IncrementFrameworkLookupCount();
+
+ // If the framework dir doesn't exist, we fail.
+ // FIXME: It's probably more efficient to query this with FileMgr.getDir.
+ if (!llvm::sys::Path(std::string(FrameworkName.begin(),
+ FrameworkName.end())).exists())
+ return 0;
+
+ // Otherwise, if it does, remember that this is the right direntry for this
+ // framework.
+ FrameworkDirCache = getFrameworkDir();
+ }
+
+ // Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h"
+ unsigned OrigSize = FrameworkName.size();
+
+ FrameworkName += "Headers/";
+ FrameworkName.append(SlashPos+1, FilenameEnd);
+ if (const FileEntry *FE = FileMgr.getFile(FrameworkName.begin(),
+ FrameworkName.end())) {
+ return FE;
+ }
+
+ // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
+ const char *Private = "Private";
+ FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
+ Private+strlen(Private));
+ return FileMgr.getFile(FrameworkName.begin(), FrameworkName.end());
+}
+
+
+//===----------------------------------------------------------------------===//
+// Header File Location.
+//===----------------------------------------------------------------------===//
+
+
+/// 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 ""). CurFileEnt, if
+/// non-null, indicates where the #including file is, in case a relative search
+/// is needed.
+const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart,
+ const char *FilenameEnd,
+ bool isAngled,
+ const DirectoryLookup *FromDir,
+ const DirectoryLookup *&CurDir,
+ const FileEntry *CurFileEnt) {
+ // If 'Filename' is absolute, check to see if it exists and no searching.
+ // FIXME: Portability. This should be a sys::Path interface, this doesn't
+ // handle things like C:\foo.txt right, nor win32 \\network\device\blah.
+ if (FilenameStart[0] == '/') {
+ CurDir = 0;
+
+ // If this was an #include_next "/absolute/file", fail.
+ if (FromDir) return 0;
+
+ // Otherwise, just return the file.
+ return FileMgr.getFile(FilenameStart, FilenameEnd);
+ }
+
+ // Step #0, 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".
+ // This search is not done for <> headers.
+ if (CurFileEnt && !isAngled && !NoCurDirSearch) {
+ llvm::SmallString<1024> TmpDir;
+ // Concatenate the requested file onto the directory.
+ // FIXME: Portability. Filename concatenation should be in sys::Path.
+ TmpDir += CurFileEnt->getDir()->getName();
+ TmpDir.push_back('/');
+ TmpDir.append(FilenameStart, FilenameEnd);
+ if (const FileEntry *FE = FileMgr.getFile(TmpDir.begin(), TmpDir.end())) {
+ // Leave CurDir unset.
+ // This file is a system header or C++ unfriendly if the old file is.
+ //
+ // Note that the temporary 'DirInfo' is required here, as either call to
+ // getFileInfo could resize the vector and we don't want to rely on order
+ // of evaluation.
+ unsigned DirInfo = getFileInfo(CurFileEnt).DirInfo;
+ getFileInfo(FE).DirInfo = DirInfo;
+ return FE;
+ }
+ }
+
+ CurDir = 0;
+
+ // If this is a system #include, ignore the user #include locs.
+ unsigned i = isAngled ? SystemDirIdx : 0;
+
+ // If this is a #include_next request, start searching after the directory the
+ // file was found in.
+ if (FromDir)
+ i = FromDir-&SearchDirs[0];
+
+ // Cache all of the lookups performed by this method. Many headers are
+ // multiply included, and the "pragma once" optimization prevents them from
+ // being relex/pp'd, but they would still have to search through a
+ // (potentially huge) series of SearchDirs to find it.
+ std::pair<unsigned, unsigned> &CacheLookup =
+ LookupFileCache.GetOrCreateValue(FilenameStart, FilenameEnd).getValue();
+
+ // If the entry has been previously looked up, the first value will be
+ // non-zero. If the value is equal to i (the start point of our search), then
+ // this is a matching hit.
+ if (CacheLookup.first == i+1) {
+ // Skip querying potentially lots of directories for this lookup.
+ i = CacheLookup.second;
+ } else {
+ // Otherwise, this is the first query, or the previous query didn't match
+ // our search start. We will fill in our found location below, so prime the
+ // start point value.
+ CacheLookup.first = i+1;
+ }
+
+ // Check each directory in sequence to see if it contains this file.
+ for (; i != SearchDirs.size(); ++i) {
+ const FileEntry *FE =
+ SearchDirs[i].LookupFile(FilenameStart, FilenameEnd, *this);
+ if (!FE) continue;
+
+ CurDir = &SearchDirs[i];
+
+ // This file is a system header or C++ unfriendly if the dir is.
+ getFileInfo(FE).DirInfo = CurDir->getDirCharacteristic();
+
+ // Remember this location for the next lookup we do.
+ CacheLookup.second = i;
+ return FE;
+ }
+
+ // Otherwise, didn't find it. Remember we didn't find this.
+ CacheLookup.second = SearchDirs.size();
+ return 0;
+}
+
+/// LookupSubframeworkHeader - Look up a subframework for the specified
+/// #include file. For example, if #include'ing <HIToolbox/HIToolbox.h> from
+/// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
+/// is a subframework within Carbon.framework. If so, return the FileEntry
+/// for the designated file, otherwise return null.
+const FileEntry *HeaderSearch::
+LookupSubframeworkHeader(const char *FilenameStart,
+ const char *FilenameEnd,
+ const FileEntry *ContextFileEnt) {
+ assert(ContextFileEnt && "No context file?");
+
+ // Framework names must have a '/' in the filename. Find it.
+ const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/');
+ if (SlashPos == FilenameEnd) return 0;
+
+ // Look up the base framework name of the ContextFileEnt.
+ const char *ContextName = ContextFileEnt->getName();
+
+ // If the context info wasn't a framework, couldn't be a subframework.
+ const char *FrameworkPos = strstr(ContextName, ".framework/");
+ if (FrameworkPos == 0)
+ return 0;
+
+ llvm::SmallString<1024> FrameworkName(ContextName,
+ FrameworkPos+strlen(".framework/"));
+
+ // Append Frameworks/HIToolbox.framework/
+ FrameworkName += "Frameworks/";
+ FrameworkName.append(FilenameStart, SlashPos);
+ FrameworkName += ".framework/";
+
+ llvm::StringMapEntry<const DirectoryEntry *> &CacheLookup =
+ FrameworkMap.GetOrCreateValue(FilenameStart, SlashPos);
+
+ // Some other location?
+ if (CacheLookup.getValue() &&
+ CacheLookup.getKeyLength() == FrameworkName.size() &&
+ memcmp(CacheLookup.getKeyData(), &FrameworkName[0],
+ CacheLookup.getKeyLength()) != 0)
+ return 0;
+
+ // Cache subframework.
+ if (CacheLookup.getValue() == 0) {
+ ++NumSubFrameworkLookups;
+
+ // If the framework dir doesn't exist, we fail.
+ const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.begin(),
+ FrameworkName.end());
+ if (Dir == 0) return 0;
+
+ // Otherwise, if it does, remember that this is the right direntry for this
+ // framework.
+ CacheLookup.setValue(Dir);
+ }
+
+ const FileEntry *FE = 0;
+
+ // Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h"
+ llvm::SmallString<1024> HeadersFilename(FrameworkName);
+ HeadersFilename += "Headers/";
+ HeadersFilename.append(SlashPos+1, FilenameEnd);
+ if (!(FE = FileMgr.getFile(HeadersFilename.begin(),
+ HeadersFilename.end()))) {
+
+ // Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
+ HeadersFilename = FrameworkName;
+ HeadersFilename += "PrivateHeaders/";
+ HeadersFilename.append(SlashPos+1, FilenameEnd);
+ if (!(FE = FileMgr.getFile(HeadersFilename.begin(), HeadersFilename.end())))
+ return 0;
+ }
+
+ // This file is a system header or C++ unfriendly if the old file is.
+ //
+ // Note that the temporary 'DirInfo' is required here, as either call to
+ // getFileInfo could resize the vector and we don't want to rely on order
+ // of evaluation.
+ unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo;
+ getFileInfo(FE).DirInfo = DirInfo;
+ return FE;
+}
+
+//===----------------------------------------------------------------------===//
+// File Info Management.
+//===----------------------------------------------------------------------===//
+
+
+/// getFileInfo - Return the HeaderFileInfo structure for the specified
+/// FileEntry.
+HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
+ if (FE->getUID() >= FileInfo.size())
+ FileInfo.resize(FE->getUID()+1);
+ return FileInfo[FE->getUID()];
+}
+
+void HeaderSearch::setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID) {
+ if (UID >= FileInfo.size())
+ FileInfo.resize(UID+1);
+ FileInfo[UID] = HFI;
+}
+
+/// ShouldEnterIncludeFile - Mark the specified file as a target of of a
+/// #include, #include_next, or #import directive. Return false if #including
+/// the file will have no effect or true if we should include it.
+bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){
+ ++NumIncluded; // Count # of attempted #includes.
+
+ // Get information about this file.
+ HeaderFileInfo &FileInfo = getFileInfo(File);
+
+ // If this is a #import directive, check that we have not already imported
+ // this header.
+ if (isImport) {
+ // If this has already been imported, don't import it again.
+ FileInfo.isImport = true;
+
+ // Has this already been #import'ed or #include'd?
+ if (FileInfo.NumIncludes) return false;
+ } else {
+ // Otherwise, if this is a #include of a file that was previously #import'd
+ // or if this is the second #include of a #pragma once file, ignore it.
+ if (FileInfo.isImport)
+ return false;
+ }
+
+ // Next, check to see if the file is wrapped with #ifndef guards. If so, and
+ // if the macro that guards it is defined, we know the #include has no effect.
+ if (const IdentifierInfo *ControllingMacro
+ = FileInfo.getControllingMacro(ExternalLookup))
+ if (ControllingMacro->hasMacroDefinition()) {
+ ++NumMultiIncludeFileOptzn;
+ return false;
+ }
+
+ // Increment the number of times this file has been included.
+ ++FileInfo.NumIncludes;
+
+ return true;
+}
+
+
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
new file mode 100644
index 000000000000..c2ffd6d4339e
--- /dev/null
+++ b/lib/Lex/Lexer.cpp
@@ -0,0 +1,1809 @@
+//===--- Lexer.cpp - C Language Family Lexer ------------------------------===//
+//
+// 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 Lexer and Token interfaces.
+//
+//===----------------------------------------------------------------------===//
+//
+// TODO: GCC Diagnostics emitted by the lexer:
+// PEDWARN: (form feed|vertical tab) in preprocessing directive
+//
+// Universal characters, unicode, char mapping:
+// WARNING: `%.*s' is not in NFKC
+// WARNING: `%.*s' is not in NFC
+//
+// Other:
+// TODO: Options to support:
+// -fexec-charset,-fwide-exec-charset
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <cctype>
+using namespace clang;
+
+static void InitCharacterInfo();
+
+//===----------------------------------------------------------------------===//
+// Token Class Implementation
+//===----------------------------------------------------------------------===//
+
+/// isObjCAtKeyword - Return true if we have an ObjC keyword identifier.
+bool Token::isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const {
+ if (IdentifierInfo *II = getIdentifierInfo())
+ return II->getObjCKeywordID() == objcKey;
+ return false;
+}
+
+/// getObjCKeywordID - Return the ObjC keyword kind.
+tok::ObjCKeywordKind Token::getObjCKeywordID() const {
+ IdentifierInfo *specId = getIdentifierInfo();
+ return specId ? specId->getObjCKeywordID() : tok::objc_not_keyword;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Lexer Class Implementation
+//===----------------------------------------------------------------------===//
+
+void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
+ const char *BufEnd) {
+ InitCharacterInfo();
+
+ BufferStart = BufStart;
+ BufferPtr = BufPtr;
+ BufferEnd = BufEnd;
+
+ assert(BufEnd[0] == 0 &&
+ "We assume that the input buffer has a null character at the end"
+ " to simplify lexing!");
+
+ Is_PragmaLexer = false;
+
+ // Start of the file is a start of line.
+ IsAtStartOfLine = true;
+
+ // We are not after parsing a #.
+ ParsingPreprocessorDirective = false;
+
+ // We are not after parsing #include.
+ ParsingFilename = false;
+
+ // We are not in raw mode. Raw mode disables diagnostics and interpretation
+ // of tokens (e.g. identifiers, thus disabling macro expansion). It is used
+ // to quickly lex the tokens of the buffer, e.g. when handling a "#if 0" block
+ // or otherwise skipping over tokens.
+ LexingRawMode = false;
+
+ // Default to not keeping comments.
+ ExtendedTokenMode = 0;
+}
+
+/// Lexer constructor - Create a new lexer object for the specified buffer
+/// with the specified preprocessor managing the lexing process. This lexer
+/// assumes that the associated file buffer and Preprocessor objects will
+/// outlive it, so it doesn't take ownership of either of them.
+Lexer::Lexer(FileID FID, Preprocessor &PP)
+ : PreprocessorLexer(&PP, FID),
+ FileLoc(PP.getSourceManager().getLocForStartOfFile(FID)),
+ Features(PP.getLangOptions()) {
+
+ const llvm::MemoryBuffer *InputFile = PP.getSourceManager().getBuffer(FID);
+
+ InitLexer(InputFile->getBufferStart(), InputFile->getBufferStart(),
+ InputFile->getBufferEnd());
+
+ // Default to keeping comments if the preprocessor wants them.
+ SetCommentRetentionState(PP.getCommentRetentionState());
+}
+
+/// Lexer constructor - Create a new raw lexer object. This object is only
+/// suitable for calls to 'LexRawToken'. This lexer assumes that the text
+/// range will outlive it, so it doesn't take ownership of it.
+Lexer::Lexer(SourceLocation fileloc, const LangOptions &features,
+ const char *BufStart, const char *BufPtr, const char *BufEnd)
+ : FileLoc(fileloc), Features(features) {
+
+ InitLexer(BufStart, BufPtr, BufEnd);
+
+ // We *are* in raw mode.
+ LexingRawMode = true;
+}
+
+/// Lexer constructor - Create a new raw lexer object. This object is only
+/// suitable for calls to 'LexRawToken'. This lexer assumes that the text
+/// range will outlive it, so it doesn't take ownership of it.
+Lexer::Lexer(FileID FID, const SourceManager &SM, const LangOptions &features)
+ : FileLoc(SM.getLocForStartOfFile(FID)), Features(features) {
+ const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
+
+ InitLexer(FromFile->getBufferStart(), FromFile->getBufferStart(),
+ FromFile->getBufferEnd());
+
+ // We *are* in raw mode.
+ LexingRawMode = true;
+}
+
+/// Create_PragmaLexer: Lexer constructor - Create a new lexer object for
+/// _Pragma expansion. This has a variety of magic semantics that this method
+/// sets up. It returns a new'd Lexer that must be delete'd when done.
+///
+/// On entrance to this routine, TokStartLoc is a macro location which has a
+/// spelling loc that indicates the bytes to be lexed for the token and an
+/// instantiation location that indicates where all lexed tokens should be
+/// "expanded from".
+///
+/// FIXME: It would really be nice to make _Pragma just be a wrapper around a
+/// normal lexer that remaps tokens as they fly by. This would require making
+/// Preprocessor::Lex virtual. Given that, we could just dump in a magic lexer
+/// interface that could handle this stuff. This would pull GetMappedTokenLoc
+/// out of the critical path of the lexer!
+///
+Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc,
+ SourceLocation InstantiationLocStart,
+ SourceLocation InstantiationLocEnd,
+ unsigned TokLen, Preprocessor &PP) {
+ SourceManager &SM = PP.getSourceManager();
+
+ // Create the lexer as if we were going to lex the file normally.
+ FileID SpellingFID = SM.getFileID(SpellingLoc);
+ Lexer *L = new Lexer(SpellingFID, PP);
+
+ // Now that the lexer is created, change the start/end locations so that we
+ // just lex the subsection of the file that we want. This is lexing from a
+ // scratch buffer.
+ const char *StrData = SM.getCharacterData(SpellingLoc);
+
+ L->BufferPtr = StrData;
+ L->BufferEnd = StrData+TokLen;
+ assert(L->BufferEnd[0] == 0 && "Buffer is not nul terminated!");
+
+ // 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),
+ InstantiationLocStart,
+ InstantiationLocEnd, TokLen);
+
+ // Ensure that the lexer thinks it is inside a directive, so that end \n will
+ // return an EOM token.
+ L->ParsingPreprocessorDirective = true;
+
+ // This lexer really is for _Pragma.
+ L->Is_PragmaLexer = true;
+ return L;
+}
+
+
+/// Stringify - Convert the specified string into a C string, with surrounding
+/// ""'s, and with escaped \ and " characters.
+std::string Lexer::Stringify(const std::string &Str, bool Charify) {
+ std::string Result = Str;
+ char Quote = Charify ? '\'' : '"';
+ for (unsigned i = 0, e = Result.size(); i != e; ++i) {
+ if (Result[i] == '\\' || Result[i] == Quote) {
+ Result.insert(Result.begin()+i, '\\');
+ ++i; ++e;
+ }
+ }
+ return Result;
+}
+
+/// 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) {
+ for (unsigned i = 0, e = Str.size(); i != e; ++i) {
+ if (Str[i] == '\\' || Str[i] == '"') {
+ Str.insert(Str.begin()+i, '\\');
+ ++i; ++e;
+ }
+ }
+}
+
+
+/// MeasureTokenLength - Relex the token at the specified location and return
+/// its length in bytes in the input file. If the token needs cleaning (e.g.
+/// includes a trigraph or an escaped newline) then this count includes bytes
+/// that are part of that.
+unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ // TODO: this could be special cased for common tokens like identifiers, ')',
+ // etc to make this faster, if it mattered. Just look at StrData[0] to handle
+ // all obviously single-char tokens. This could use
+ // Lexer::isObviouslySimpleCharacter for example to handle identifiers or
+ // something.
+
+ // 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);
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ std::pair<const char *,const char *> Buffer = SM.getBufferData(LocInfo.first);
+ const char *StrData = Buffer.first+LocInfo.second;
+
+ // Create a lexer starting at the beginning of this token.
+ Lexer TheLexer(Loc, LangOpts, Buffer.first, StrData, Buffer.second);
+ Token TheTok;
+ TheLexer.LexFromRawLexer(TheTok);
+ return TheTok.getLength();
+}
+
+//===----------------------------------------------------------------------===//
+// Character information.
+//===----------------------------------------------------------------------===//
+
+static unsigned char CharInfo[256];
+
+enum {
+ CHAR_HORZ_WS = 0x01, // ' ', '\t', '\f', '\v'. Note, no '\0'
+ CHAR_VERT_WS = 0x02, // '\r', '\n'
+ CHAR_LETTER = 0x04, // a-z,A-Z
+ CHAR_NUMBER = 0x08, // 0-9
+ CHAR_UNDER = 0x10, // _
+ CHAR_PERIOD = 0x20 // .
+};
+
+static void InitCharacterInfo() {
+ static bool isInited = false;
+ if (isInited) return;
+ isInited = true;
+
+ // Intiialize the CharInfo table.
+ // TODO: statically initialize this.
+ CharInfo[(int)' '] = CharInfo[(int)'\t'] =
+ CharInfo[(int)'\f'] = CharInfo[(int)'\v'] = CHAR_HORZ_WS;
+ CharInfo[(int)'\n'] = CharInfo[(int)'\r'] = CHAR_VERT_WS;
+
+ CharInfo[(int)'_'] = CHAR_UNDER;
+ CharInfo[(int)'.'] = CHAR_PERIOD;
+ for (unsigned i = 'a'; i <= 'z'; ++i)
+ CharInfo[i] = CharInfo[i+'A'-'a'] = CHAR_LETTER;
+ for (unsigned i = '0'; i <= '9'; ++i)
+ CharInfo[i] = CHAR_NUMBER;
+}
+
+/// isIdentifierBody - Return true if this is the body character of an
+/// identifier, which is [a-zA-Z0-9_].
+static inline bool isIdentifierBody(unsigned char c) {
+ return (CharInfo[c] & (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER)) ? true : false;
+}
+
+/// isHorizontalWhitespace - Return true if this character is horizontal
+/// whitespace: ' ', '\t', '\f', '\v'. Note that this returns false for '\0'.
+static inline bool isHorizontalWhitespace(unsigned char c) {
+ return (CharInfo[c] & CHAR_HORZ_WS) ? true : false;
+}
+
+/// isWhitespace - Return true if this character is horizontal or vertical
+/// whitespace: ' ', '\t', '\f', '\v', '\n', '\r'. Note that this returns false
+/// for '\0'.
+static inline bool isWhitespace(unsigned char c) {
+ return (CharInfo[c] & (CHAR_HORZ_WS|CHAR_VERT_WS)) ? true : false;
+}
+
+/// isNumberBody - Return true if this is the body character of an
+/// preprocessing number, which is [a-zA-Z0-9_.].
+static inline bool isNumberBody(unsigned char c) {
+ return (CharInfo[c] & (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER|CHAR_PERIOD)) ?
+ true : false;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Diagnostics forwarding code.
+//===----------------------------------------------------------------------===//
+
+/// GetMappedTokenLoc - If lexing out of a 'mapped buffer', where we pretend the
+/// lexer buffer was all instantiated at a single point, perform the mapping.
+/// This is currently only used for _Pragma implementation, so it is the slow
+/// path of the hot getSourceLocation method. Do not allow it to be inlined.
+static SourceLocation GetMappedTokenLoc(Preprocessor &PP,
+ SourceLocation FileLoc,
+ unsigned CharNo,
+ unsigned TokLen) DISABLE_INLINE;
+static SourceLocation GetMappedTokenLoc(Preprocessor &PP,
+ SourceLocation FileLoc,
+ unsigned CharNo, unsigned TokLen) {
+ assert(FileLoc.isMacroID() && "Must be an instantiation");
+
+ // Otherwise, we're lexing "mapped tokens". This is used for things like
+ // _Pragma handling. Combine the instantiation location of FileLoc with the
+ // spelling location.
+ SourceManager &SM = PP.getSourceManager();
+
+ // Create a new SLoc which is expanded from Instantiation(FileLoc) but whose
+ // characters come from spelling(FileLoc)+Offset.
+ SourceLocation SpellingLoc = SM.getSpellingLoc(FileLoc);
+ SpellingLoc = SpellingLoc.getFileLocWithOffset(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);
+
+ return SM.createInstantiationLoc(SpellingLoc, II.first, II.second, TokLen);
+}
+
+/// getSourceLocation - Return a source location identifier for the specified
+/// offset in the current file.
+SourceLocation Lexer::getSourceLocation(const char *Loc,
+ unsigned TokLen) const {
+ assert(Loc >= BufferStart && Loc <= BufferEnd &&
+ "Location out of range for this buffer!");
+
+ // In the normal case, we're just lexing from a simple file buffer, return
+ // the file id from FileLoc with the offset specified.
+ unsigned CharNo = Loc-BufferStart;
+ if (FileLoc.isFileID())
+ return FileLoc.getFileLocWithOffset(CharNo);
+
+ // Otherwise, this is the _Pragma lexer case, which pretends that all of the
+ // tokens are lexed from where the _Pragma was defined.
+ assert(PP && "This doesn't work on raw lexers");
+ return GetMappedTokenLoc(*PP, FileLoc, CharNo, TokLen);
+}
+
+/// Diag - Forwarding function for diagnostics. This translate a source
+/// position in the current buffer into a SourceLocation object for rendering.
+DiagnosticBuilder Lexer::Diag(const char *Loc, unsigned DiagID) const {
+ return PP->Diag(getSourceLocation(Loc), DiagID);
+}
+
+//===----------------------------------------------------------------------===//
+// Trigraph and Escaped Newline Handling Code.
+//===----------------------------------------------------------------------===//
+
+/// GetTrigraphCharForLetter - Given a character that occurs after a ?? pair,
+/// return the decoded trigraph letter it corresponds to, or '\0' if nothing.
+static char GetTrigraphCharForLetter(char Letter) {
+ switch (Letter) {
+ default: return 0;
+ case '=': return '#';
+ case ')': return ']';
+ case '(': return '[';
+ case '!': return '|';
+ case '\'': return '^';
+ case '>': return '}';
+ case '/': return '\\';
+ case '<': return '{';
+ case '-': return '~';
+ }
+}
+
+/// DecodeTrigraphChar - If the specified character is a legal trigraph when
+/// prefixed with ??, emit a trigraph warning. If trigraphs are enabled,
+/// return the result character. Finally, emit a warning about trigraph use
+/// whether trigraphs are enabled or not.
+static char DecodeTrigraphChar(const char *CP, Lexer *L) {
+ char Res = GetTrigraphCharForLetter(*CP);
+ if (!Res || !L) return Res;
+
+ if (!L->getFeatures().Trigraphs) {
+ if (!L->isLexingRawMode())
+ L->Diag(CP-2, diag::trigraph_ignored);
+ return 0;
+ }
+
+ if (!L->isLexingRawMode())
+ L->Diag(CP-2, diag::trigraph_converted) << std::string()+Res;
+ return Res;
+}
+
+/// getEscapedNewLineSize - Return the size of the specified escaped newline,
+/// or 0 if it is not an escaped newline. P[-1] is known to be a "\" or a
+/// trigraph equivalent on entry to this function.
+unsigned Lexer::getEscapedNewLineSize(const char *Ptr) {
+ unsigned Size = 0;
+ while (isWhitespace(Ptr[Size])) {
+ ++Size;
+
+ if (Ptr[Size-1] != '\n' && Ptr[Size-1] != '\r')
+ continue;
+
+ // If this is a \r\n or \n\r, skip the other half.
+ if ((Ptr[Size] == '\r' || Ptr[Size] == '\n') &&
+ Ptr[Size-1] != Ptr[Size])
+ ++Size;
+
+ return Size;
+ }
+
+ // Not an escaped newline, must be a \t or something else.
+ return 0;
+}
+
+/// SkipEscapedNewLines - If P points to an escaped newline (or a series of
+/// them), skip over them and return the first non-escaped-newline found,
+/// otherwise return P.
+const char *Lexer::SkipEscapedNewLines(const char *P) {
+ while (1) {
+ const char *AfterEscape;
+ if (*P == '\\') {
+ AfterEscape = P+1;
+ } else if (*P == '?') {
+ // If not a trigraph for escape, bail out.
+ if (P[1] != '?' || P[2] != '/')
+ return P;
+ AfterEscape = P+3;
+ } else {
+ return P;
+ }
+
+ unsigned NewLineSize = Lexer::getEscapedNewLineSize(AfterEscape);
+ if (NewLineSize == 0) return P;
+ P = AfterEscape+NewLineSize;
+ }
+}
+
+
+/// getCharAndSizeSlow - Peek a single 'character' from the specified buffer,
+/// get its size, and return it. This is tricky in several cases:
+/// 1. If currently at the start of a trigraph, we warn about the trigraph,
+/// then either return the trigraph (skipping 3 chars) or the '?',
+/// depending on whether trigraphs are enabled or not.
+/// 2. If this is an escaped newline (potentially with whitespace between
+/// the backslash and newline), implicitly skip the newline and return
+/// the char after it.
+/// 3. If this is a UCN, return it. FIXME: C++ UCN's?
+///
+/// This handles the slow/uncommon case of the getCharAndSize method. Here we
+/// know that we can accumulate into Size, and that we have already incremented
+/// Ptr by Size bytes.
+///
+/// NOTE: When this method is updated, getCharAndSizeSlowNoWarn (below) should
+/// be updated to match.
+///
+char Lexer::getCharAndSizeSlow(const char *Ptr, unsigned &Size,
+ Token *Tok) {
+ // If we have a slash, look for an escaped newline.
+ if (Ptr[0] == '\\') {
+ ++Size;
+ ++Ptr;
+Slash:
+ // Common case, backslash-char where the char is not whitespace.
+ if (!isWhitespace(Ptr[0])) return '\\';
+
+ // See if we have optional whitespace characters followed by a newline.
+ if (unsigned EscapedNewLineSize = getEscapedNewLineSize(Ptr)) {
+ // Remember that this token needs to be cleaned.
+ if (Tok) Tok->setFlag(Token::NeedsCleaning);
+
+ // Warn if there was whitespace between the backslash and newline.
+ if (EscapedNewLineSize != 1 && Tok && !isLexingRawMode())
+ Diag(Ptr, diag::backslash_newline_space);
+
+ // Found backslash<whitespace><newline>. Parse the char after it.
+ Size += EscapedNewLineSize;
+ Ptr += EscapedNewLineSize;
+ // Use slow version to accumulate a correct size field.
+ return getCharAndSizeSlow(Ptr, Size, Tok);
+ }
+
+ // Otherwise, this is not an escaped newline, just return the slash.
+ return '\\';
+ }
+
+ // If this is a trigraph, process it.
+ if (Ptr[0] == '?' && Ptr[1] == '?') {
+ // If this is actually a legal trigraph (not something like "??x"), emit
+ // a trigraph warning. If so, and if trigraphs are enabled, return it.
+ if (char C = DecodeTrigraphChar(Ptr+2, Tok ? this : 0)) {
+ // Remember that this token needs to be cleaned.
+ if (Tok) Tok->setFlag(Token::NeedsCleaning);
+
+ Ptr += 3;
+ Size += 3;
+ if (C == '\\') goto Slash;
+ return C;
+ }
+ }
+
+ // If this is neither, return a single character.
+ ++Size;
+ return *Ptr;
+}
+
+
+/// getCharAndSizeSlowNoWarn - Handle the slow/uncommon case of the
+/// getCharAndSizeNoWarn method. Here we know that we can accumulate into Size,
+/// and that we have already incremented Ptr by Size bytes.
+///
+/// NOTE: When this method is updated, getCharAndSizeSlow (above) should
+/// be updated to match.
+char Lexer::getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size,
+ const LangOptions &Features) {
+ // If we have a slash, look for an escaped newline.
+ if (Ptr[0] == '\\') {
+ ++Size;
+ ++Ptr;
+Slash:
+ // Common case, backslash-char where the char is not whitespace.
+ if (!isWhitespace(Ptr[0])) return '\\';
+
+ // See if we have optional whitespace characters followed by a newline.
+ if (unsigned EscapedNewLineSize = getEscapedNewLineSize(Ptr)) {
+ // Found backslash<whitespace><newline>. Parse the char after it.
+ Size += EscapedNewLineSize;
+ Ptr += EscapedNewLineSize;
+
+ // Use slow version to accumulate a correct size field.
+ return getCharAndSizeSlowNoWarn(Ptr, Size, Features);
+ }
+
+ // Otherwise, this is not an escaped newline, just return the slash.
+ return '\\';
+ }
+
+ // If this is a trigraph, process it.
+ if (Features.Trigraphs && Ptr[0] == '?' && Ptr[1] == '?') {
+ // If this is actually a legal trigraph (not something like "??x"), return
+ // it.
+ if (char C = GetTrigraphCharForLetter(Ptr[2])) {
+ Ptr += 3;
+ Size += 3;
+ if (C == '\\') goto Slash;
+ return C;
+ }
+ }
+
+ // If this is neither, return a single character.
+ ++Size;
+ return *Ptr;
+}
+
+//===----------------------------------------------------------------------===//
+// Helper methods for lexing.
+//===----------------------------------------------------------------------===//
+
+void Lexer::LexIdentifier(Token &Result, const char *CurPtr) {
+ // Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$]
+ unsigned Size;
+ unsigned char C = *CurPtr++;
+ while (isIdentifierBody(C)) {
+ C = *CurPtr++;
+ }
+ --CurPtr; // Back up over the skipped character.
+
+ // Fast path, no $,\,? in identifier found. '\' might be an escaped newline
+ // or UCN, and ? might be a trigraph for '\', an escaped newline or UCN.
+ // FIXME: UCNs.
+ if (C != '\\' && C != '?' && (C != '$' || !Features.DollarIdents)) {
+FinishIdentifier:
+ const char *IdStart = BufferPtr;
+ FormTokenWithChars(Result, CurPtr, tok::identifier);
+
+ // If we are in raw mode, return this identifier raw. There is no need to
+ // look up identifier information or attempt to macro expand it.
+ if (LexingRawMode) return;
+
+ // Fill in Result.IdentifierInfo, looking up the identifier in the
+ // identifier table.
+ IdentifierInfo *II = PP->LookUpIdentifierInfo(Result, IdStart);
+
+ // Change the kind of this identifier to the appropriate token kind, e.g.
+ // turning "for" into a keyword.
+ Result.setKind(II->getTokenID());
+
+ // Finally, now that we know we have an identifier, pass this off to the
+ // preprocessor, which may macro expand it or something.
+ if (II->isHandleIdentifierCase())
+ PP->HandleIdentifier(Result);
+ return;
+ }
+
+ // Otherwise, $,\,? in identifier found. Enter slower path.
+
+ C = getCharAndSize(CurPtr, Size);
+ while (1) {
+ if (C == '$') {
+ // If we hit a $ and they are not supported in identifiers, we are done.
+ if (!Features.DollarIdents) goto FinishIdentifier;
+
+ // Otherwise, emit a diagnostic and continue.
+ if (!isLexingRawMode())
+ Diag(CurPtr, diag::ext_dollar_in_identifier);
+ CurPtr = ConsumeChar(CurPtr, Size, Result);
+ C = getCharAndSize(CurPtr, Size);
+ continue;
+ } else if (!isIdentifierBody(C)) { // FIXME: UCNs.
+ // Found end of identifier.
+ goto FinishIdentifier;
+ }
+
+ // Otherwise, this character is good, consume it.
+ CurPtr = ConsumeChar(CurPtr, Size, Result);
+
+ C = getCharAndSize(CurPtr, Size);
+ while (isIdentifierBody(C)) { // FIXME: UCNs.
+ CurPtr = ConsumeChar(CurPtr, Size, Result);
+ C = getCharAndSize(CurPtr, Size);
+ }
+ }
+}
+
+
+/// LexNumericConstant - Lex the remainder of a integer or floating point
+/// constant. From[-1] is the first character lexed. Return the end of the
+/// constant.
+void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
+ unsigned Size;
+ char C = getCharAndSize(CurPtr, Size);
+ char PrevCh = 0;
+ while (isNumberBody(C)) { // FIXME: UCNs?
+ CurPtr = ConsumeChar(CurPtr, Size, Result);
+ PrevCh = C;
+ C = getCharAndSize(CurPtr, Size);
+ }
+
+ // If we fell out, check for a sign, due to 1e+12. If we have one, continue.
+ if ((C == '-' || C == '+') && (PrevCh == 'E' || PrevCh == 'e'))
+ return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
+
+ // If we have a hex FP constant, continue.
+ if ((C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p'))
+ return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
+
+ // Update the location of token as well as BufferPtr.
+ const char *TokStart = BufferPtr;
+ FormTokenWithChars(Result, CurPtr, tok::numeric_constant);
+ Result.setLiteralData(TokStart);
+}
+
+/// LexStringLiteral - Lex the remainder of a string literal, after having lexed
+/// either " or L".
+void Lexer::LexStringLiteral(Token &Result, const char *CurPtr, bool Wide) {
+ const char *NulCharacter = 0; // Does this string contain the \0 character?
+
+ char C = getAndAdvanceChar(CurPtr, Result);
+ while (C != '"') {
+ // Skip escaped characters.
+ if (C == '\\') {
+ // Skip the escaped character.
+ C = getAndAdvanceChar(CurPtr, Result);
+ } else if (C == '\n' || C == '\r' || // Newline.
+ (C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
+ if (!isLexingRawMode() && !Features.AsmPreprocessor)
+ Diag(BufferPtr, diag::err_unterminated_string);
+ FormTokenWithChars(Result, CurPtr-1, tok::unknown);
+ return;
+ } else if (C == 0) {
+ NulCharacter = CurPtr-1;
+ }
+ C = getAndAdvanceChar(CurPtr, Result);
+ }
+
+ // If a nul character existed in the string, warn about it.
+ if (NulCharacter && !isLexingRawMode())
+ Diag(NulCharacter, diag::null_in_string);
+
+ // 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);
+ Result.setLiteralData(TokStart);
+}
+
+/// LexAngledStringLiteral - Lex the remainder of an angled string literal,
+/// after having lexed the '<' character. This is used for #include filenames.
+void Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) {
+ const char *NulCharacter = 0; // Does this string contain the \0 character?
+ const char *AfterLessPos = CurPtr;
+ char C = getAndAdvanceChar(CurPtr, Result);
+ while (C != '>') {
+ // Skip escaped characters.
+ if (C == '\\') {
+ // Skip the escaped character.
+ C = getAndAdvanceChar(CurPtr, Result);
+ } else if (C == '\n' || C == '\r' || // Newline.
+ (C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
+ // If the filename is unterminated, then it must just be a lone <
+ // character. Return this as such.
+ FormTokenWithChars(Result, AfterLessPos, tok::less);
+ return;
+ } else if (C == 0) {
+ NulCharacter = CurPtr-1;
+ }
+ C = getAndAdvanceChar(CurPtr, Result);
+ }
+
+ // If a nul character existed in the string, warn about it.
+ if (NulCharacter && !isLexingRawMode())
+ Diag(NulCharacter, diag::null_in_string);
+
+ // Update the location of token as well as BufferPtr.
+ const char *TokStart = BufferPtr;
+ FormTokenWithChars(Result, CurPtr, tok::angle_string_literal);
+ Result.setLiteralData(TokStart);
+}
+
+
+/// LexCharConstant - Lex the remainder of a character constant, after having
+/// lexed either ' or L'.
+void Lexer::LexCharConstant(Token &Result, const char *CurPtr) {
+ const char *NulCharacter = 0; // Does this character contain the \0 character?
+
+ // Handle the common case of 'x' and '\y' efficiently.
+ char C = getAndAdvanceChar(CurPtr, Result);
+ if (C == '\'') {
+ if (!isLexingRawMode() && !Features.AsmPreprocessor)
+ Diag(BufferPtr, diag::err_empty_character);
+ FormTokenWithChars(Result, CurPtr, tok::unknown);
+ return;
+ } else if (C == '\\') {
+ // Skip the escaped character.
+ // FIXME: UCN's.
+ C = getAndAdvanceChar(CurPtr, Result);
+ }
+
+ if (C && C != '\n' && C != '\r' && CurPtr[0] == '\'') {
+ ++CurPtr;
+ } else {
+ // Fall back on generic code for embedded nulls, newlines, wide chars.
+ do {
+ // Skip escaped characters.
+ if (C == '\\') {
+ // Skip the escaped character.
+ C = getAndAdvanceChar(CurPtr, Result);
+ } else if (C == '\n' || C == '\r' || // Newline.
+ (C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
+ if (!isLexingRawMode() && !Features.AsmPreprocessor)
+ Diag(BufferPtr, diag::err_unterminated_char);
+ FormTokenWithChars(Result, CurPtr-1, tok::unknown);
+ return;
+ } else if (C == 0) {
+ NulCharacter = CurPtr-1;
+ }
+ C = getAndAdvanceChar(CurPtr, Result);
+ } while (C != '\'');
+ }
+
+ if (NulCharacter && !isLexingRawMode())
+ Diag(NulCharacter, diag::null_in_char);
+
+ // Update the location of token as well as BufferPtr.
+ const char *TokStart = BufferPtr;
+ FormTokenWithChars(Result, CurPtr, tok::char_constant);
+ Result.setLiteralData(TokStart);
+}
+
+/// SkipWhitespace - Efficiently skip over a series of whitespace characters.
+/// Update BufferPtr to point to the next non-whitespace character and return.
+///
+/// This method forms a token and returns true if KeepWhitespaceMode is enabled.
+///
+bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
+ // Whitespace - Skip it, then return the token after the whitespace.
+ unsigned char Char = *CurPtr; // Skip consequtive spaces efficiently.
+ while (1) {
+ // Skip horizontal whitespace very aggressively.
+ while (isHorizontalWhitespace(Char))
+ Char = *++CurPtr;
+
+ // Otherwise if we have something other than whitespace, we're done.
+ if (Char != '\n' && Char != '\r')
+ break;
+
+ if (ParsingPreprocessorDirective) {
+ // End of preprocessor directive line, let LexTokenInternal handle this.
+ BufferPtr = CurPtr;
+ return false;
+ }
+
+ // ok, but handle newline.
+ // The returned token is at the start of the line.
+ Result.setFlag(Token::StartOfLine);
+ // No leading whitespace seen so far.
+ Result.clearFlag(Token::LeadingSpace);
+ Char = *++CurPtr;
+ }
+
+ // If this isn't immediately after a newline, there is leading space.
+ char PrevChar = CurPtr[-1];
+ if (PrevChar != '\n' && PrevChar != '\r')
+ Result.setFlag(Token::LeadingSpace);
+
+ // If the client wants us to return whitespace, return it now.
+ if (isKeepWhitespaceMode()) {
+ FormTokenWithChars(Result, CurPtr, tok::unknown);
+ return true;
+ }
+
+ BufferPtr = CurPtr;
+ return false;
+}
+
+// SkipBCPLComment - We have just read the // characters from input. Skip until
+// we find the newline character thats terminate the comment. Then update
+/// BufferPtr and return. If we're in KeepCommentMode, this will form the token
+/// and return true.
+bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
+ // If BCPL comments aren't explicitly enabled for this language, emit an
+ // extension warning.
+ if (!Features.BCPLComment && !isLexingRawMode()) {
+ Diag(BufferPtr, diag::ext_bcpl_comment);
+
+ // Mark them enabled so we only emit one warning for this translation
+ // unit.
+ Features.BCPLComment = true;
+ }
+
+ // Scan over the body of the comment. The common case, when scanning, is that
+ // the comment contains normal ascii characters with nothing interesting in
+ // them. As such, optimize for this case with the inner loop.
+ 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!
+
+ // Otherwise, this is a hard case. Fall back on getAndAdvanceChar to
+ // properly decode the character. Read it in raw mode to avoid emitting
+ // diagnostics about things like trigraphs. If we see an escaped newline,
+ // we'll handle it below.
+ const char *OldPtr = CurPtr;
+ bool OldRawMode = isLexingRawMode();
+ LexingRawMode = true;
+ C = getAndAdvanceChar(CurPtr, Result);
+ LexingRawMode = OldRawMode;
+
+ // 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.
+ if (C == '\n' || C == '\r') {
+ --CurPtr;
+ C = 'x'; // doesn't matter what this is.
+ }
+
+ // If we read multiple characters, and one of those characters was a \r or
+ // \n, then we had an escaped newline within the comment. Emit diagnostic
+ // unless the next line is also a // comment.
+ if (CurPtr != OldPtr+1 && C != '/' && CurPtr[0] != '/') {
+ for (; OldPtr != CurPtr; ++OldPtr)
+ 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)) {
+ const char *ForwardPtr = CurPtr;
+ while (isspace(*ForwardPtr)) // Skip whitespace.
+ ++ForwardPtr;
+ if (ForwardPtr[0] == '/' && ForwardPtr[1] == '/')
+ break;
+ }
+
+ if (!isLexingRawMode())
+ Diag(OldPtr-1, diag::ext_multi_line_bcpl_comment);
+ break;
+ }
+ }
+
+ if (CurPtr == BufferEnd+1) { --CurPtr; break; }
+ } while (C != '\n' && C != '\r');
+
+ // Found but did not consume the newline.
+
+ // If we are returning comments as tokens, return this comment as a token.
+ if (inKeepCommentMode())
+ return SaveBCPLComment(Result, CurPtr);
+
+ // If we are inside a preprocessor directive and we see the end of line,
+ // return immediately, so that the lexer can return this as an EOM token.
+ if (ParsingPreprocessorDirective || CurPtr == BufferEnd) {
+ BufferPtr = CurPtr;
+ return false;
+ }
+
+ // Otherwise, eat the \n character. We don't care if this is a \n\r or
+ // \r\n sequence. This is an efficiency hack (because we know the \n can't
+ // contribute to another token), it isn't needed for correctness. Note that
+ // this is ok even in KeepWhitespaceMode, because we would have returned the
+ /// comment above in that mode.
+ ++CurPtr;
+
+ // The next returned token is at the start of the line.
+ Result.setFlag(Token::StartOfLine);
+ // No leading whitespace seen so far.
+ Result.clearFlag(Token::LeadingSpace);
+ BufferPtr = CurPtr;
+ return false;
+}
+
+/// SaveBCPLComment - If in save-comment mode, package up this BCPL comment in
+/// an appropriate way and return it.
+bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) {
+ // If we're not in a preprocessor directive, just return the // comment
+ // directly.
+ FormTokenWithChars(Result, CurPtr, tok::comment);
+
+ if (!ParsingPreprocessorDirective)
+ return true;
+
+ // If this BCPL-style comment is in a macro definition, transmogrify it into
+ // a C-style block comment.
+ std::string Spelling = PP->getSpelling(Result);
+ assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not bcpl comment?");
+ Spelling[1] = '*'; // Change prefix to "/*".
+ Spelling += "*/"; // add suffix.
+
+ Result.setKind(tok::comment);
+ PP->CreateString(&Spelling[0], Spelling.size(), Result,
+ Result.getLocation());
+ return true;
+}
+
+/// isBlockCommentEndOfEscapedNewLine - Return true if the specified newline
+/// character (either \n or \r) is part of an escaped newline sequence. Issue a
+/// diagnostic if so. We know that the newline is inside of a block comment.
+static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr,
+ Lexer *L) {
+ assert(CurPtr[0] == '\n' || CurPtr[0] == '\r');
+
+ // Back up off the newline.
+ --CurPtr;
+
+ // If this is a two-character newline sequence, skip the other character.
+ if (CurPtr[0] == '\n' || CurPtr[0] == '\r') {
+ // \n\n or \r\r -> not escaped newline.
+ if (CurPtr[0] == CurPtr[1])
+ return false;
+ // \n\r or \r\n -> skip the newline.
+ --CurPtr;
+ }
+
+ // If we have horizontal whitespace, skip over it. We allow whitespace
+ // between the slash and newline.
+ bool HasSpace = false;
+ while (isHorizontalWhitespace(*CurPtr) || *CurPtr == 0) {
+ --CurPtr;
+ HasSpace = true;
+ }
+
+ // If we have a slash, we know this is an escaped newline.
+ if (*CurPtr == '\\') {
+ if (CurPtr[-1] != '*') return false;
+ } else {
+ // It isn't a slash, is it the ?? / trigraph?
+ if (CurPtr[0] != '/' || CurPtr[-1] != '?' || CurPtr[-2] != '?' ||
+ CurPtr[-3] != '*')
+ return false;
+
+ // This is the trigraph ending the comment. Emit a stern warning!
+ CurPtr -= 2;
+
+ // If no trigraphs are enabled, warn that we ignored this trigraph and
+ // ignore this * character.
+ if (!L->getFeatures().Trigraphs) {
+ if (!L->isLexingRawMode())
+ L->Diag(CurPtr, diag::trigraph_ignored_block_comment);
+ return false;
+ }
+ if (!L->isLexingRawMode())
+ L->Diag(CurPtr, diag::trigraph_ends_block_comment);
+ }
+
+ // Warn about having an escaped newline between the */ characters.
+ if (!L->isLexingRawMode())
+ L->Diag(CurPtr, diag::escaped_newline_block_comment_end);
+
+ // If there was space between the backslash and newline, warn about it.
+ if (HasSpace && !L->isLexingRawMode())
+ L->Diag(CurPtr, diag::backslash_newline_space);
+
+ return true;
+}
+
+#ifdef __SSE2__
+#include <emmintrin.h>
+#elif __ALTIVEC__
+#include <altivec.h>
+#undef bool
+#endif
+
+/// SkipBlockComment - We have just read the /* characters from input. Read
+/// until we find the */ characters that terminate the comment. Note that we
+/// don't bother decoding trigraphs or escaped newlines in block comments,
+/// because they cannot cause the comment to end. The only thing that can
+/// happen is the comment could end with an escaped newline between the */ end
+/// of comment.
+///
+/// If KeepCommentMode is enabled, this forms a token from the comment and
+/// returns true.
+bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
+ // Scan one character past where we should, looking for a '/' character. Once
+ // we find it, check to see if it was preceeded by a *. This common
+ // optimization helps people who like to put a lot of * characters in their
+ // comments.
+
+ // The first character we get with newlines and trigraphs skipped to handle
+ // the degenerate /*/ case below correctly if the * has an escaped newline
+ // after it.
+ unsigned CharSize;
+ unsigned char C = getCharAndSize(CurPtr, CharSize);
+ CurPtr += CharSize;
+ if (C == 0 && CurPtr == BufferEnd+1) {
+ if (!isLexingRawMode())
+ Diag(BufferPtr, diag::err_unterminated_block_comment);
+ --CurPtr;
+
+ // KeepWhitespaceMode should return this broken comment as a token. Since
+ // it isn't a well formed comment, just return it as an 'unknown' token.
+ if (isKeepWhitespaceMode()) {
+ FormTokenWithChars(Result, CurPtr, tok::unknown);
+ return true;
+ }
+
+ BufferPtr = CurPtr;
+ return false;
+ }
+
+ // Check to see if the first character after the '/*' is another /. If so,
+ // then this slash does not end the block comment, it is part of it.
+ if (C == '/')
+ C = *CurPtr++;
+
+ while (1) {
+ // Skip over all non-interesting characters until we find end of buffer or a
+ // (probably ending) '/' character.
+ if (CurPtr + 24 < BufferEnd) {
+ // While not aligned to a 16-byte boundary.
+ while (C != '/' && ((intptr_t)CurPtr & 0x0F) != 0)
+ C = *CurPtr++;
+
+ if (C == '/') goto FoundSlash;
+
+#ifdef __SSE2__
+ __m128i Slashes = _mm_set_epi8('/', '/', '/', '/', '/', '/', '/', '/',
+ '/', '/', '/', '/', '/', '/', '/', '/');
+ while (CurPtr+16 <= BufferEnd &&
+ _mm_movemask_epi8(_mm_cmpeq_epi8(*(__m128i*)CurPtr, Slashes)) == 0)
+ CurPtr += 16;
+#elif __ALTIVEC__
+ __vector unsigned char Slashes = {
+ '/', '/', '/', '/', '/', '/', '/', '/',
+ '/', '/', '/', '/', '/', '/', '/', '/'
+ };
+ while (CurPtr+16 <= BufferEnd &&
+ !vec_any_eq(*(vector unsigned char*)CurPtr, Slashes))
+ CurPtr += 16;
+#else
+ // Scan for '/' quickly. Many block comments are very large.
+ while (CurPtr[0] != '/' &&
+ CurPtr[1] != '/' &&
+ CurPtr[2] != '/' &&
+ CurPtr[3] != '/' &&
+ CurPtr+4 < BufferEnd) {
+ CurPtr += 4;
+ }
+#endif
+
+ // It has to be one of the bytes scanned, increment to it and read one.
+ C = *CurPtr++;
+ }
+
+ // Loop to scan the remainder.
+ while (C != '/' && C != '\0')
+ C = *CurPtr++;
+
+ FoundSlash:
+ if (C == '/') {
+ if (CurPtr[-2] == '*') // We found the final */. We're done!
+ break;
+
+ if ((CurPtr[-2] == '\n' || CurPtr[-2] == '\r')) {
+ if (isEndOfBlockCommentWithEscapedNewLine(CurPtr-2, this)) {
+ // We found the final */, though it had an escaped newline between the
+ // * and /. We're done!
+ break;
+ }
+ }
+ if (CurPtr[0] == '*' && CurPtr[1] != '/') {
+ // If this is a /* inside of the comment, emit a warning. Don't do this
+ // if this is a /*/, which will end the comment. This misses cases with
+ // embedded escaped newlines, but oh well.
+ if (!isLexingRawMode())
+ Diag(CurPtr-1, diag::warn_nested_block_comment);
+ }
+ } else if (C == 0 && CurPtr == BufferEnd+1) {
+ 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
+ // comment, which surely would confuse the parser.
+ --CurPtr;
+
+ // KeepWhitespaceMode should return this broken comment as a token. Since
+ // it isn't a well formed comment, just return it as an 'unknown' token.
+ if (isKeepWhitespaceMode()) {
+ FormTokenWithChars(Result, CurPtr, tok::unknown);
+ return true;
+ }
+
+ BufferPtr = CurPtr;
+ return false;
+ }
+ C = *CurPtr++;
+ }
+
+ // If we are returning comments as tokens, return this comment as a token.
+ if (inKeepCommentMode()) {
+ FormTokenWithChars(Result, CurPtr, tok::comment);
+ return true;
+ }
+
+ // It is common for the tokens immediately after a /**/ comment to be
+ // whitespace. Instead of going through the big switch, handle it
+ // efficiently now. This is safe even in KeepWhitespaceMode because we would
+ // have already returned above with the comment as a token.
+ if (isHorizontalWhitespace(*CurPtr)) {
+ Result.setFlag(Token::LeadingSpace);
+ SkipWhitespace(Result, CurPtr+1);
+ return false;
+ }
+
+ // Otherwise, just return so that the next character will be lexed as a token.
+ BufferPtr = CurPtr;
+ Result.setFlag(Token::LeadingSpace);
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Primary Lexing Entry Points
+//===----------------------------------------------------------------------===//
+
+/// ReadToEndOfLine - Read the rest of the current preprocessor line as an
+/// uninterpreted string. This switches the lexer out of directive mode.
+std::string Lexer::ReadToEndOfLine() {
+ assert(ParsingPreprocessorDirective && ParsingFilename == false &&
+ "Must be in a preprocessing directive!");
+ std::string Result;
+ Token Tmp;
+
+ // CurPtr - Cache BufferPtr in an automatic variable.
+ const char *CurPtr = BufferPtr;
+ while (1) {
+ char Char = getAndAdvanceChar(CurPtr, Tmp);
+ switch (Char) {
+ default:
+ Result += Char;
+ break;
+ case 0: // Null.
+ // Found end of file?
+ if (CurPtr-1 != BufferEnd) {
+ // Nope, normal character, continue.
+ Result += Char;
+ break;
+ }
+ // FALL THROUGH.
+ case '\r':
+ case '\n':
+ // Okay, we found the end of the line. First, back up past the \0, \r, \n.
+ assert(CurPtr[-1] == Char && "Trigraphs for newline?");
+ BufferPtr = CurPtr-1;
+
+ // Next, lex the character, which should handle the EOM transition.
+ Lex(Tmp);
+ assert(Tmp.is(tok::eom) && "Unexpected token!");
+
+ // Finally, we're done, return the string we found.
+ return Result;
+ }
+ }
+}
+
+/// LexEndOfFile - CurPtr points to the end of this file. Handle this
+/// condition, reporting diagnostics and handling other edge cases as required.
+/// This returns true if Result contains a token, false if PP.Lex should be
+/// called again.
+bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
+ // 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.
+ if (ParsingPreprocessorDirective) {
+ // Done parsing the "line".
+ ParsingPreprocessorDirective = false;
+ // Update the location of token as well as BufferPtr.
+ FormTokenWithChars(Result, CurPtr, tok::eom);
+
+ // Restore comment saving mode, in case it was disabled for directive.
+ SetCommentRetentionState(PP->getCommentRetentionState());
+ return true; // Have a token.
+ }
+
+ // If we are in raw mode, return this event as an EOF token. Let the caller
+ // that put us in raw mode handle the event.
+ if (isLexingRawMode()) {
+ Result.startToken();
+ BufferPtr = BufferEnd;
+ FormTokenWithChars(Result, BufferEnd, tok::eof);
+ return true;
+ }
+
+ // Otherwise, issue diagnostics for unterminated #if and missing newline.
+
+ // If we are in a #if directive, emit an error.
+ while (!ConditionalStack.empty()) {
+ PP->Diag(ConditionalStack.back().IfLoc,
+ diag::err_pp_unterminated_conditional);
+ ConditionalStack.pop_back();
+ }
+
+ // C99 5.1.1.2p2: If the file is non-empty and didn't end in a newline, issue
+ // a pedwarn.
+ if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r'))
+ Diag(BufferEnd, diag::ext_no_newline_eof)
+ << CodeModificationHint::CreateInsertion(getSourceLocation(BufferEnd),
+ "\n");
+
+ BufferPtr = CurPtr;
+
+ // Finally, let the preprocessor handle this.
+ return PP->HandleEndOfFile(Result);
+}
+
+/// isNextPPTokenLParen - Return 1 if the next unexpanded token lexed from
+/// the specified lexer will return a tok::l_paren token, 0 if it is something
+/// else and 2 if there are no more tokens in the buffer controlled by the
+/// lexer.
+unsigned Lexer::isNextPPTokenLParen() {
+ assert(!LexingRawMode && "How can we expand a macro from a skipping buffer?");
+
+ // Switch to 'skipping' mode. This will ensure that we can lex a token
+ // without emitting diagnostics, disables macro expansion, and will cause EOF
+ // to return an EOF token instead of popping the include stack.
+ LexingRawMode = true;
+
+ // Save state that can be changed while lexing so that we can restore it.
+ const char *TmpBufferPtr = BufferPtr;
+ bool inPPDirectiveMode = ParsingPreprocessorDirective;
+
+ Token Tok;
+ Tok.startToken();
+ LexTokenInternal(Tok);
+
+ // Restore state that may have changed.
+ BufferPtr = TmpBufferPtr;
+ ParsingPreprocessorDirective = inPPDirectiveMode;
+
+ // Restore the lexer back to non-skipping mode.
+ LexingRawMode = false;
+
+ if (Tok.is(tok::eof))
+ return 2;
+ return Tok.is(tok::l_paren);
+}
+
+
+/// LexTokenInternal - This implements a simple C family lexer. It is an
+/// extremely performance critical piece of code. This assumes that the buffer
+/// has a null character at the end of the file. Return true if an error
+/// occurred and compilation should terminate, false if normal. This returns a
+/// preprocessing token, not a normal token, as such, it is an internal
+/// interface. It assumes that the Flags of result have been cleared before
+/// calling this.
+void Lexer::LexTokenInternal(Token &Result) {
+LexNextToken:
+ // New token, can't need cleaning yet.
+ Result.clearFlag(Token::NeedsCleaning);
+ Result.setIdentifierInfo(0);
+
+ // CurPtr - Cache BufferPtr in an automatic variable.
+ const char *CurPtr = BufferPtr;
+
+ // Small amounts of horizontal whitespace is very common between tokens.
+ if ((*CurPtr == ' ') || (*CurPtr == '\t')) {
+ ++CurPtr;
+ while ((*CurPtr == ' ') || (*CurPtr == '\t'))
+ ++CurPtr;
+
+ // If we are keeping whitespace and other tokens, just return what we just
+ // skipped. The next lexer invocation will return the token after the
+ // whitespace.
+ if (isKeepWhitespaceMode()) {
+ FormTokenWithChars(Result, CurPtr, tok::unknown);
+ return;
+ }
+
+ BufferPtr = CurPtr;
+ Result.setFlag(Token::LeadingSpace);
+ }
+
+ unsigned SizeTmp, SizeTmp2; // Temporaries for use in cases below.
+
+ // Read a character, advancing over it.
+ char Char = getAndAdvanceChar(CurPtr, Result);
+ tok::TokenKind Kind;
+
+ switch (Char) {
+ case 0: // Null.
+ // Found end of file?
+ if (CurPtr-1 == BufferEnd) {
+ // Read the PP instance variable into an automatic variable, because
+ // LexEndOfFile will often delete 'this'.
+ Preprocessor *PPCache = PP;
+ if (LexEndOfFile(Result, CurPtr-1)) // Retreat back into the file.
+ return; // Got a token to return.
+ assert(PPCache && "Raw buffer::LexEndOfFile should return a token");
+ return PPCache->Lex(Result);
+ }
+
+ if (!isLexingRawMode())
+ Diag(CurPtr-1, diag::null_in_file);
+ Result.setFlag(Token::LeadingSpace);
+ if (SkipWhitespace(Result, CurPtr))
+ return; // KeepWhitespaceMode
+
+ goto LexNextToken; // GCC isn't tail call eliminating.
+ case '\n':
+ case '\r':
+ // If we are inside a preprocessor directive and we see the end of line,
+ // we know we are done with the directive, so return an EOM token.
+ if (ParsingPreprocessorDirective) {
+ // Done parsing the "line".
+ ParsingPreprocessorDirective = false;
+
+ // Restore comment saving mode, in case it was disabled for directive.
+ SetCommentRetentionState(PP->getCommentRetentionState());
+
+ // Since we consumed a newline, we are back at the start of a line.
+ IsAtStartOfLine = true;
+
+ Kind = tok::eom;
+ break;
+ }
+ // The returned token is at the start of the line.
+ Result.setFlag(Token::StartOfLine);
+ // No leading whitespace seen so far.
+ Result.clearFlag(Token::LeadingSpace);
+
+ if (SkipWhitespace(Result, CurPtr))
+ return; // KeepWhitespaceMode
+ goto LexNextToken; // GCC isn't tail call eliminating.
+ case ' ':
+ case '\t':
+ case '\f':
+ case '\v':
+ SkipHorizontalWhitespace:
+ Result.setFlag(Token::LeadingSpace);
+ if (SkipWhitespace(Result, CurPtr))
+ return; // KeepWhitespaceMode
+
+ SkipIgnoredUnits:
+ CurPtr = BufferPtr;
+
+ // If the next token is obviously a // or /* */ comment, skip it efficiently
+ // too (without going through the big switch stmt).
+ if (CurPtr[0] == '/' && CurPtr[1] == '/' && !inKeepCommentMode() &&
+ Features.BCPLComment) {
+ SkipBCPLComment(Result, CurPtr+2);
+ goto SkipIgnoredUnits;
+ } else if (CurPtr[0] == '/' && CurPtr[1] == '*' && !inKeepCommentMode()) {
+ SkipBlockComment(Result, CurPtr+2);
+ goto SkipIgnoredUnits;
+ } else if (isHorizontalWhitespace(*CurPtr)) {
+ goto SkipHorizontalWhitespace;
+ }
+ goto LexNextToken; // GCC isn't tail call eliminating.
+
+ // C99 6.4.4.1: Integer Constants.
+ // C99 6.4.4.2: Floating Constants.
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ // Notify MIOpt that we read a non-whitespace/non-comment token.
+ MIOpt.ReadToken();
+ return LexNumericConstant(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();
+ Char = getCharAndSize(CurPtr, SizeTmp);
+
+ // Wide string literal.
+ if (Char == '"')
+ return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result),
+ true);
+
+ // Wide character constant.
+ if (Char == '\'')
+ return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result));
+ // 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 '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 'v': case 'w': case 'x': case 'y': case 'z':
+ case '_':
+ // Notify MIOpt that we read a non-whitespace/non-comment token.
+ MIOpt.ReadToken();
+ return LexIdentifier(Result, CurPtr);
+
+ case '$': // $ in identifiers.
+ if (Features.DollarIdents) {
+ if (!isLexingRawMode())
+ Diag(CurPtr-1, diag::ext_dollar_in_identifier);
+ // Notify MIOpt that we read a non-whitespace/non-comment token.
+ MIOpt.ReadToken();
+ return LexIdentifier(Result, CurPtr);
+ }
+
+ Kind = tok::unknown;
+ break;
+
+ // C99 6.4.4: Character Constants.
+ case '\'':
+ // Notify MIOpt that we read a non-whitespace/non-comment token.
+ MIOpt.ReadToken();
+ return LexCharConstant(Result, CurPtr);
+
+ // 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);
+
+ // C99 6.4.6: Punctuators.
+ case '?':
+ Kind = tok::question;
+ break;
+ case '[':
+ Kind = tok::l_square;
+ break;
+ case ']':
+ Kind = tok::r_square;
+ break;
+ case '(':
+ Kind = tok::l_paren;
+ break;
+ case ')':
+ Kind = tok::r_paren;
+ break;
+ case '{':
+ Kind = tok::l_brace;
+ break;
+ case '}':
+ Kind = tok::r_brace;
+ break;
+ case '.':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char >= '0' && Char <= '9') {
+ // Notify MIOpt that we read a non-whitespace/non-comment token.
+ MIOpt.ReadToken();
+
+ return LexNumericConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result));
+ } else if (Features.CPlusPlus && Char == '*') {
+ Kind = tok::periodstar;
+ CurPtr += SizeTmp;
+ } else if (Char == '.' &&
+ getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '.') {
+ Kind = tok::ellipsis;
+ CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result);
+ } else {
+ Kind = tok::period;
+ }
+ break;
+ case '&':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '&') {
+ Kind = tok::ampamp;
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Char == '=') {
+ Kind = tok::ampequal;
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Kind = tok::amp;
+ }
+ break;
+ case '*':
+ if (getCharAndSize(CurPtr, SizeTmp) == '=') {
+ Kind = tok::starequal;
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Kind = tok::star;
+ }
+ break;
+ case '+':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '+') {
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Kind = tok::plusplus;
+ } else if (Char == '=') {
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Kind = tok::plusequal;
+ } else {
+ Kind = tok::plus;
+ }
+ break;
+ case '-':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '-') { // --
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Kind = tok::minusminus;
+ } else if (Char == '>' && Features.CPlusPlus &&
+ getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '*') { // C++ ->*
+ CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result);
+ Kind = tok::arrowstar;
+ } else if (Char == '>') { // ->
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Kind = tok::arrow;
+ } else if (Char == '=') { // -=
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Kind = tok::minusequal;
+ } else {
+ Kind = tok::minus;
+ }
+ break;
+ case '~':
+ Kind = tok::tilde;
+ break;
+ case '!':
+ if (getCharAndSize(CurPtr, SizeTmp) == '=') {
+ Kind = tok::exclaimequal;
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Kind = tok::exclaim;
+ }
+ break;
+ case '/':
+ // 6.4.9: Comments
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '/') { // BCPL comment.
+ // Even if BCPL comments are disabled (e.g. in C89 mode), we generally
+ // want to lex this as a comment. There is one problem with this though,
+ // that in one particular corner case, this can change the behavior of the
+ // resultant program. For example, In "foo //**/ bar", C89 would lex
+ // this as "foo / bar" and langauges with BCPL comments would lex it as
+ // "foo". Check to see if the character after the second slash is a '*'.
+ // If so, we will lex that as a "/" instead of the start of a comment.
+ if (Features.BCPLComment ||
+ getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') {
+ if (SkipBCPLComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
+ return; // KeepCommentMode
+
+ // It is common for the tokens immediately after a // comment to be
+ // whitespace (indentation for the next line). Instead of going through
+ // the big switch, handle it efficiently now.
+ goto SkipIgnoredUnits;
+ }
+ }
+
+ if (Char == '*') { // /**/ comment.
+ if (SkipBlockComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
+ return; // KeepCommentMode
+ goto LexNextToken; // GCC isn't tail call eliminating.
+ }
+
+ if (Char == '=') {
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Kind = tok::slashequal;
+ } else {
+ Kind = tok::slash;
+ }
+ break;
+ case '%':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '=') {
+ Kind = tok::percentequal;
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Features.Digraphs && Char == '>') {
+ Kind = tok::r_brace; // '%>' -> '}'
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Features.Digraphs && Char == ':') {
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '%' && getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == ':') {
+ Kind = tok::hashhash; // '%:%:' -> '##'
+ CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result);
+ } else if (Char == '@' && Features.Microsoft) { // %:@ -> #@ -> Charize
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ if (!isLexingRawMode())
+ Diag(BufferPtr, diag::charize_microsoft_ext);
+ Kind = tok::hashat;
+ } else { // '%:' -> '#'
+ // We parsed a # character. If this occurs at the start of the line,
+ // it's actually the start of a preprocessing directive. Callback to
+ // the preprocessor to handle it.
+ // FIXME: -fpreprocessed mode??
+ if (Result.isAtStartOfLine() && !LexingRawMode && !Is_PragmaLexer) {
+ FormTokenWithChars(Result, CurPtr, tok::hash);
+ PP->HandleDirective(Result);
+
+ // As an optimization, if the preprocessor didn't switch lexers, tail
+ // recurse.
+ if (PP->isCurrentLexer(this)) {
+ // Start a new token. If this is a #include or something, the PP may
+ // want us starting at the beginning of the line again. If so, set
+ // the StartOfLine flag.
+ if (IsAtStartOfLine) {
+ Result.setFlag(Token::StartOfLine);
+ IsAtStartOfLine = false;
+ }
+ goto LexNextToken; // GCC isn't tail call eliminating.
+ }
+
+ return PP->Lex(Result);
+ }
+
+ Kind = tok::hash;
+ }
+ } else {
+ Kind = tok::percent;
+ }
+ break;
+ case '<':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (ParsingFilename) {
+ return LexAngledStringLiteral(Result, CurPtr);
+ } else if (Char == '<' &&
+ getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '=') {
+ Kind = tok::lesslessequal;
+ CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result);
+ } else if (Char == '<') {
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Kind = tok::lessless;
+ } else if (Char == '=') {
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Kind = tok::lessequal;
+ } else if (Features.Digraphs && Char == ':') { // '<:' -> '['
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Kind = tok::l_square;
+ } else if (Features.Digraphs && Char == '%') { // '<%' -> '{'
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Kind = tok::l_brace;
+ } else {
+ Kind = tok::less;
+ }
+ break;
+ case '>':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '=') {
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Kind = tok::greaterequal;
+ } else if (Char == '>' &&
+ getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '=') {
+ CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result);
+ Kind = tok::greatergreaterequal;
+ } else if (Char == '>') {
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Kind = tok::greatergreater;
+ } else {
+ Kind = tok::greater;
+ }
+ break;
+ case '^':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '=') {
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ Kind = tok::caretequal;
+ } else {
+ Kind = tok::caret;
+ }
+ break;
+ case '|':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '=') {
+ Kind = tok::pipeequal;
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Char == '|') {
+ Kind = tok::pipepipe;
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Kind = tok::pipe;
+ }
+ break;
+ case ':':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Features.Digraphs && Char == '>') {
+ Kind = tok::r_square; // ':>' -> ']'
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Features.CPlusPlus && Char == ':') {
+ Kind = tok::coloncolon;
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Kind = tok::colon;
+ }
+ break;
+ case ';':
+ Kind = tok::semi;
+ break;
+ case '=':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '=') {
+ Kind = tok::equalequal;
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Kind = tok::equal;
+ }
+ break;
+ case ',':
+ Kind = tok::comma;
+ break;
+ case '#':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '#') {
+ Kind = tok::hashhash;
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Char == '@' && Features.Microsoft) { // #@ -> Charize
+ Kind = tok::hashat;
+ if (!isLexingRawMode())
+ Diag(BufferPtr, diag::charize_microsoft_ext);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ // We parsed a # character. If this occurs at the start of the line,
+ // it's actually the start of a preprocessing directive. Callback to
+ // the preprocessor to handle it.
+ // FIXME: -fpreprocessed mode??
+ if (Result.isAtStartOfLine() && !LexingRawMode && !Is_PragmaLexer) {
+ FormTokenWithChars(Result, CurPtr, tok::hash);
+ PP->HandleDirective(Result);
+
+ // As an optimization, if the preprocessor didn't switch lexers, tail
+ // recurse.
+ if (PP->isCurrentLexer(this)) {
+ // Start a new token. If this is a #include or something, the PP may
+ // want us starting at the beginning of the line again. If so, set
+ // the StartOfLine flag.
+ if (IsAtStartOfLine) {
+ Result.setFlag(Token::StartOfLine);
+ IsAtStartOfLine = false;
+ }
+ goto LexNextToken; // GCC isn't tail call eliminating.
+ }
+ return PP->Lex(Result);
+ }
+
+ Kind = tok::hash;
+ }
+ break;
+
+ case '@':
+ // Objective C support.
+ if (CurPtr[-1] == '@' && Features.ObjC1)
+ Kind = tok::at;
+ else
+ Kind = tok::unknown;
+ break;
+
+ case '\\':
+ // FIXME: UCN's.
+ // FALL THROUGH.
+ default:
+ Kind = tok::unknown;
+ break;
+ }
+
+ // Notify MIOpt that we read a non-whitespace/non-comment token.
+ MIOpt.ReadToken();
+
+ // Update the location of token as well as BufferPtr.
+ FormTokenWithChars(Result, CurPtr, Kind);
+}
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
new file mode 100644
index 000000000000..0324c0b01289
--- /dev/null
+++ b/lib/Lex/LiteralSupport.cpp
@@ -0,0 +1,929 @@
+//===--- LiteralSupport.cpp - Code to parse and process literals ----------===//
+//
+// 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 NumericLiteralParser, CharLiteralParser, and
+// StringLiteralParser interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/StringExtras.h"
+using namespace clang;
+
+/// HexDigitValue - Return the value of the specified hex digit, or -1 if it's
+/// not valid.
+static int HexDigitValue(char C) {
+ if (C >= '0' && C <= '9') return C-'0';
+ if (C >= 'a' && C <= 'f') return C-'a'+10;
+ if (C >= 'A' && C <= 'F') return C-'A'+10;
+ return -1;
+}
+
+/// 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,
+ SourceLocation Loc, bool IsWide,
+ Preprocessor &PP) {
+ // Skip the '\' char.
+ ++ThisTokBuf;
+
+ // We know that this character can't be off the end of the buffer, because
+ // that would have been \", which would not have been the end of string.
+ unsigned ResultChar = *ThisTokBuf++;
+ switch (ResultChar) {
+ // These map to themselves.
+ case '\\': case '\'': case '"': case '?': break;
+
+ // These have fixed mappings.
+ case 'a':
+ // TODO: K&R: the meaning of '\\a' is different in traditional C
+ ResultChar = 7;
+ break;
+ case 'b':
+ ResultChar = 8;
+ break;
+ case 'e':
+ PP.Diag(Loc, diag::ext_nonstandard_escape) << "e";
+ ResultChar = 27;
+ break;
+ case 'f':
+ ResultChar = 12;
+ break;
+ case 'n':
+ ResultChar = 10;
+ break;
+ case 'r':
+ ResultChar = 13;
+ break;
+ case 't':
+ ResultChar = 9;
+ break;
+ case 'v':
+ ResultChar = 11;
+ break;
+ case 'x': { // Hex escape.
+ ResultChar = 0;
+ if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
+ PP.Diag(Loc, diag::err_hex_escape_no_digits);
+ HadError = 1;
+ break;
+ }
+
+ // Hex escapes are a maximal series of hex digits.
+ bool Overflow = false;
+ for (; ThisTokBuf != ThisTokEnd; ++ThisTokBuf) {
+ int CharVal = HexDigitValue(ThisTokBuf[0]);
+ if (CharVal == -1) break;
+ // About to shift out a digit?
+ Overflow |= (ResultChar & 0xF0000000) ? true : false;
+ ResultChar <<= 4;
+ ResultChar |= CharVal;
+ }
+
+ // See if any bits will be truncated when evaluated as a character.
+ unsigned CharWidth = PP.getTargetInfo().getCharWidth(IsWide);
+
+ if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
+ Overflow = true;
+ ResultChar &= ~0U >> (32-CharWidth);
+ }
+
+ // Check for overflow.
+ if (Overflow) // Too many digits to fit in
+ PP.Diag(Loc, diag::warn_hex_escape_too_large);
+ break;
+ }
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7': {
+ // Octal escapes.
+ --ThisTokBuf;
+ ResultChar = 0;
+
+ // Octal escapes are a series of octal digits with maximum length 3.
+ // "\0123" is a two digit sequence equal to "\012" "3".
+ unsigned NumDigits = 0;
+ do {
+ ResultChar <<= 3;
+ ResultChar |= *ThisTokBuf++ - '0';
+ ++NumDigits;
+ } while (ThisTokBuf != ThisTokEnd && NumDigits < 3 &&
+ ThisTokBuf[0] >= '0' && ThisTokBuf[0] <= '7');
+
+ // Check for overflow. Reject '\777', but not L'\777'.
+ unsigned CharWidth = PP.getTargetInfo().getCharWidth(IsWide);
+
+ if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
+ PP.Diag(Loc, diag::warn_octal_escape_too_large);
+ ResultChar &= ~0U >> (32-CharWidth);
+ }
+ break;
+ }
+
+ // Otherwise, these are not valid escapes.
+ case '(': case '{': case '[': case '%':
+ // GCC accepts these as extensions. We warn about them as such though.
+ PP.Diag(Loc, diag::ext_nonstandard_escape)
+ << std::string()+(char)ResultChar;
+ break;
+ // FALL THROUGH.
+ default:
+ if (isgraph(ThisTokBuf[0]))
+ PP.Diag(Loc, diag::ext_unknown_escape) << std::string()+(char)ResultChar;
+ else
+ PP.Diag(Loc, diag::ext_unknown_escape) << "x"+llvm::utohexstr(ResultChar);
+ break;
+ }
+
+ return ResultChar;
+}
+
+/// ProcessUCNEscape - Read the Universal Character Name, check constraints and
+/// convert the UTF32 to UTF8. This is a subroutine of StringLiteralParser.
+/// When we decide to implement UCN's for character constants and identifiers,
+/// we will likely rework our support for UCN's.
+static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
+ char *&ResultBuf, bool &HadError,
+ SourceLocation Loc, bool IsWide, Preprocessor &PP)
+{
+ // FIXME: Add a warning - UCN's are only valid in C++ & C99.
+ // FIXME: Handle wide strings.
+
+ // Save the beginning of the string (for error diagnostics).
+ const char *ThisTokBegin = ThisTokBuf;
+
+ // Skip the '\u' char's.
+ ThisTokBuf += 2;
+
+ if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
+ PP.Diag(Loc, diag::err_ucn_escape_no_digits);
+ HadError = 1;
+ return;
+ }
+ typedef uint32_t UTF32;
+
+ UTF32 UcnVal = 0;
+ unsigned short UcnLen = (ThisTokBuf[-1] == 'u' ? 4 : 8);
+ for (; ThisTokBuf != ThisTokEnd && UcnLen; ++ThisTokBuf, UcnLen--) {
+ int CharVal = HexDigitValue(ThisTokBuf[0]);
+ if (CharVal == -1) break;
+ UcnVal <<= 4;
+ UcnVal |= CharVal;
+ }
+ // If we didn't consume the proper number of digits, there is a problem.
+ if (UcnLen) {
+ PP.Diag(PP.AdvanceToTokenCharacter(Loc, ThisTokBuf-ThisTokBegin),
+ diag::err_ucn_escape_incomplete);
+ HadError = 1;
+ return;
+ }
+ // Check UCN constraints (C99 6.4.3p2).
+ if ((UcnVal < 0xa0 &&
+ (UcnVal != 0x24 && UcnVal != 0x40 && UcnVal != 0x60 )) // $, @, `
+ || (UcnVal >= 0xD800 && UcnVal <= 0xDFFF)
+ || (UcnVal > 0x10FFFF)) /* the maximum legal UTF32 value */ {
+ PP.Diag(Loc, diag::err_ucn_escape_invalid);
+ HadError = 1;
+ return;
+ }
+ // 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
+ // First, we determine how many bytes the result will require.
+ typedef uint8_t UTF8;
+
+ unsigned short bytesToWrite = 0;
+ if (UcnVal < (UTF32)0x80)
+ bytesToWrite = 1;
+ else if (UcnVal < (UTF32)0x800)
+ bytesToWrite = 2;
+ else if (UcnVal < (UTF32)0x10000)
+ bytesToWrite = 3;
+ else
+ bytesToWrite = 4;
+
+ const unsigned byteMask = 0xBF;
+ const unsigned byteMark = 0x80;
+
+ // Once the bits are split out into bytes of UTF8, this is a mask OR-ed
+ // into the first byte, depending on how many bytes follow.
+ static const UTF8 firstByteMark[5] = {
+ 0x00, 0x00, 0xC0, 0xE0, 0xF0
+ };
+ // Finally, we write the bytes into ResultBuf.
+ ResultBuf += bytesToWrite;
+ switch (bytesToWrite) { // note: everything falls through.
+ case 4: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
+ case 3: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
+ case 2: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
+ case 1: *--ResultBuf = (UTF8) (UcnVal | firstByteMark[bytesToWrite]);
+ }
+ // Update the buffer.
+ ResultBuf += bytesToWrite;
+}
+
+
+/// integer-constant: [C99 6.4.4.1]
+/// decimal-constant integer-suffix
+/// octal-constant integer-suffix
+/// hexadecimal-constant integer-suffix
+/// decimal-constant:
+/// nonzero-digit
+/// decimal-constant digit
+/// octal-constant:
+/// 0
+/// octal-constant octal-digit
+/// hexadecimal-constant:
+/// hexadecimal-prefix hexadecimal-digit
+/// hexadecimal-constant hexadecimal-digit
+/// hexadecimal-prefix: one of
+/// 0x 0X
+/// integer-suffix:
+/// unsigned-suffix [long-suffix]
+/// unsigned-suffix [long-long-suffix]
+/// long-suffix [unsigned-suffix]
+/// long-long-suffix [unsigned-sufix]
+/// nonzero-digit:
+/// 1 2 3 4 5 6 7 8 9
+/// octal-digit:
+/// 0 1 2 3 4 5 6 7
+/// hexadecimal-digit:
+/// 0 1 2 3 4 5 6 7 8 9
+/// a b c d e f
+/// A B C D E F
+/// unsigned-suffix: one of
+/// u U
+/// long-suffix: one of
+/// l L
+/// long-long-suffix: one of
+/// ll LL
+///
+/// floating-constant: [C99 6.4.4.2]
+/// TODO: add rules...
+///
+NumericLiteralParser::
+NumericLiteralParser(const char *begin, const char *end,
+ SourceLocation TokLoc, Preprocessor &pp)
+ : PP(pp), ThisTokBegin(begin), ThisTokEnd(end) {
+
+ // This routine assumes that the range begin/end matches the regex for integer
+ // and FP constants (specifically, the 'pp-number' regex), and assumes that
+ // the byte at "*end" is both valid and not part of the regex. Because of
+ // this, it doesn't have to check for 'overscan' in various places.
+ assert(!isalnum(*end) && *end != '.' && *end != '_' &&
+ "Lexer didn't maximally munch?");
+
+ s = DigitsBegin = begin;
+ saw_exponent = false;
+ saw_period = false;
+ isLong = false;
+ isUnsigned = false;
+ isLongLong = false;
+ isFloat = false;
+ isImaginary = false;
+ hadError = false;
+
+ if (*s == '0') { // parse radix
+ ParseNumberStartingWithZero(TokLoc);
+ if (hadError)
+ return;
+ } else { // the first digit is non-zero
+ radix = 10;
+ s = SkipDigits(s);
+ if (s == ThisTokEnd) {
+ // Done.
+ } else if (isxdigit(*s) && !(*s == 'e' || *s == 'E')) {
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin),
+ diag::err_invalid_decimal_digit) << std::string(s, s+1);
+ hadError = true;
+ return;
+ } else if (*s == '.') {
+ s++;
+ saw_period = true;
+ s = SkipDigits(s);
+ }
+ if ((*s == 'e' || *s == 'E')) { // exponent
+ const char *Exponent = s;
+ s++;
+ saw_exponent = true;
+ if (*s == '+' || *s == '-') s++; // sign
+ const char *first_non_digit = SkipDigits(s);
+ if (first_non_digit != s) {
+ s = first_non_digit;
+ } else {
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Exponent-begin),
+ diag::err_exponent_has_no_digits);
+ hadError = true;
+ return;
+ }
+ }
+ }
+
+ SuffixBegin = s;
+
+ // Parse the suffix. At this point we can classify whether we have an FP or
+ // integer constant.
+ bool isFPConstant = isFloatingLiteral();
+
+ // Loop over all of the characters of the suffix. If we see something bad,
+ // we break out of the loop.
+ for (; s != ThisTokEnd; ++s) {
+ switch (*s) {
+ case 'f': // FP Suffix for "float"
+ case 'F':
+ if (!isFPConstant) break; // Error for integer constant.
+ if (isFloat || isLong) break; // FF, LF invalid.
+ isFloat = true;
+ continue; // Success.
+ case 'u':
+ case 'U':
+ if (isFPConstant) break; // Error for floating constant.
+ if (isUnsigned) break; // Cannot be repeated.
+ isUnsigned = true;
+ continue; // Success.
+ case 'l':
+ case 'L':
+ if (isLong || isLongLong) break; // Cannot be repeated.
+ if (isFloat) break; // LF invalid.
+
+ // Check for long long. The L's need to be adjacent and the same case.
+ if (s+1 != ThisTokEnd && s[1] == s[0]) {
+ if (isFPConstant) break; // long long invalid for floats.
+ isLongLong = true;
+ ++s; // Eat both of them.
+ } else {
+ isLong = true;
+ }
+ continue; // Success.
+ case 'i':
+ if (PP.getLangOptions().Microsoft) {
+ // Allow i8, i16, i32, i64, and i128.
+ if (++s == ThisTokEnd) break;
+ switch (*s) {
+ case '8':
+ s++; // i8 suffix
+ break;
+ case '1':
+ if (++s == ThisTokEnd) break;
+ if (*s == '6') s++; // i16 suffix
+ else if (*s == '2') {
+ if (++s == ThisTokEnd) break;
+ if (*s == '8') s++; // i128 suffix
+ }
+ break;
+ case '3':
+ if (++s == ThisTokEnd) break;
+ if (*s == '2') s++; // i32 suffix
+ break;
+ case '6':
+ if (++s == ThisTokEnd) break;
+ if (*s == '4') s++; // i64 suffix
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ // fall through.
+ case 'I':
+ case 'j':
+ case 'J':
+ if (isImaginary) break; // Cannot be repeated.
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin),
+ diag::ext_imaginary_constant);
+ isImaginary = true;
+ continue; // Success.
+ }
+ // If we reached here, there was an error.
+ break;
+ }
+
+ // Report an error if there are any.
+ if (s != ThisTokEnd) {
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin),
+ isFPConstant ? diag::err_invalid_suffix_float_constant :
+ diag::err_invalid_suffix_integer_constant)
+ << std::string(SuffixBegin, ThisTokEnd);
+ hadError = true;
+ return;
+ }
+}
+
+/// ParseNumberStartingWithZero - This method is called when the first character
+/// of the number is found to be a zero. This means it is either an octal
+/// number (like '04') or a hex number ('0x123a') a binary number ('0b1010') or
+/// a floating point number (01239.123e4). Eat the prefix, determining the
+/// radix etc.
+void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
+ assert(s[0] == '0' && "Invalid method call");
+ s++;
+
+ // Handle a hex number like 0x1234.
+ if ((*s == 'x' || *s == 'X') && (isxdigit(s[1]) || s[1] == '.')) {
+ s++;
+ radix = 16;
+ DigitsBegin = s;
+ s = SkipHexDigits(s);
+ if (s == ThisTokEnd) {
+ // Done.
+ } else if (*s == '.') {
+ s++;
+ saw_period = true;
+ s = SkipHexDigits(s);
+ }
+ // A binary exponent can appear with or with a '.'. If dotted, the
+ // binary exponent is required.
+ if (*s == 'p' || *s == 'P') {
+ const char *Exponent = s;
+ s++;
+ saw_exponent = true;
+ if (*s == '+' || *s == '-') s++; // sign
+ const char *first_non_digit = SkipDigits(s);
+ if (first_non_digit == s) {
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Exponent-ThisTokBegin),
+ diag::err_exponent_has_no_digits);
+ hadError = true;
+ return;
+ }
+ s = first_non_digit;
+
+ if (!PP.getLangOptions().HexFloats)
+ PP.Diag(TokLoc, diag::ext_hexconstant_invalid);
+ } else if (saw_period) {
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
+ diag::err_hexconstant_requires_exponent);
+ hadError = true;
+ }
+ return;
+ }
+
+ // Handle simple binary numbers 0b01010
+ if (*s == 'b' || *s == 'B') {
+ // 0b101010 is a GCC extension.
+ PP.Diag(TokLoc, diag::ext_binary_literal);
+ ++s;
+ radix = 2;
+ DigitsBegin = s;
+ s = SkipBinaryDigits(s);
+ if (s == ThisTokEnd) {
+ // Done.
+ } else if (isxdigit(*s)) {
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
+ diag::err_invalid_binary_digit) << std::string(s, s+1);
+ hadError = true;
+ }
+ // Other suffixes will be diagnosed by the caller.
+ return;
+ }
+
+ // For now, the radix is set to 8. If we discover that we have a
+ // floating point constant, the radix will change to 10. Octal floating
+ // point constants are not permitted (only decimal and hexadecimal).
+ radix = 8;
+ DigitsBegin = s;
+ s = SkipOctalDigits(s);
+ if (s == ThisTokEnd)
+ return; // Done, simple octal number like 01234
+
+ // If we have some other non-octal digit that *is* a decimal digit, see if
+ // this is part of a floating point number like 094.123 or 09e1.
+ if (isdigit(*s)) {
+ const char *EndDecimal = SkipDigits(s);
+ if (EndDecimal[0] == '.' || EndDecimal[0] == 'e' || EndDecimal[0] == 'E') {
+ s = EndDecimal;
+ radix = 10;
+ }
+ }
+
+ // If we have a hex digit other than 'e' (which denotes a FP exponent) then
+ // the code is using an incorrect base.
+ if (isxdigit(*s) && *s != 'e' && *s != 'E') {
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
+ diag::err_invalid_octal_digit) << std::string(s, s+1);
+ hadError = true;
+ return;
+ }
+
+ if (*s == '.') {
+ s++;
+ radix = 10;
+ saw_period = true;
+ s = SkipDigits(s); // Skip suffix.
+ }
+ if (*s == 'e' || *s == 'E') { // exponent
+ const char *Exponent = s;
+ s++;
+ radix = 10;
+ saw_exponent = true;
+ if (*s == '+' || *s == '-') s++; // sign
+ const char *first_non_digit = SkipDigits(s);
+ if (first_non_digit != s) {
+ s = first_non_digit;
+ } else {
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Exponent-ThisTokBegin),
+ diag::err_exponent_has_no_digits);
+ hadError = true;
+ return;
+ }
+ }
+}
+
+
+/// GetIntegerValue - Convert this numeric literal value to an APInt that
+/// matches Val's input width. If there is an overflow, set Val to the low bits
+/// of the result and return true. Otherwise, return false.
+bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
+ // Fast path: Compute a conservative bound on the maximum number of
+ // bits per digit in this radix. If we can't possibly overflow a
+ // uint64 based on that bound then do the simple conversion to
+ // integer. This avoids the expensive overflow checking below, and
+ // handles the common cases that matter (small decimal integers and
+ // hex/octal values which don't overflow).
+ unsigned MaxBitsPerDigit = 1;
+ while ((1U << MaxBitsPerDigit) < radix)
+ MaxBitsPerDigit += 1;
+ if ((SuffixBegin - DigitsBegin) * MaxBitsPerDigit <= 64) {
+ uint64_t N = 0;
+ for (s = DigitsBegin; s != SuffixBegin; ++s)
+ N = N*radix + HexDigitValue(*s);
+
+ // This will truncate the value to Val's input width. Simply check
+ // for overflow by comparing.
+ Val = N;
+ return Val.getZExtValue() != N;
+ }
+
+ Val = 0;
+ s = DigitsBegin;
+
+ llvm::APInt RadixVal(Val.getBitWidth(), radix);
+ llvm::APInt CharVal(Val.getBitWidth(), 0);
+ llvm::APInt OldVal = Val;
+
+ bool OverflowOccurred = false;
+ while (s < SuffixBegin) {
+ unsigned C = HexDigitValue(*s++);
+
+ // If this letter is out of bound for this radix, reject it.
+ assert(C < radix && "NumericLiteralParser ctor should have rejected this");
+
+ CharVal = C;
+
+ // Add the digit to the value in the appropriate radix. If adding in digits
+ // made the value smaller, then this overflowed.
+ OldVal = Val;
+
+ // Multiply by radix, did overflow occur on the multiply?
+ Val *= RadixVal;
+ OverflowOccurred |= Val.udiv(RadixVal) != OldVal;
+
+ // Add value, did overflow occur on the value?
+ // (a + b) ult b <=> overflow
+ Val += CharVal;
+ OverflowOccurred |= Val.ult(CharVal);
+ }
+ return OverflowOccurred;
+}
+
+llvm::APFloat NumericLiteralParser::
+GetFloatValue(const llvm::fltSemantics &Format, bool* isExact) {
+ using llvm::APFloat;
+
+ llvm::SmallVector<char,256> floatChars;
+ for (unsigned i = 0, n = ThisTokEnd-ThisTokBegin; i != n; ++i)
+ floatChars.push_back(ThisTokBegin[i]);
+
+ floatChars.push_back('\0');
+
+ APFloat V (Format, APFloat::fcZero, false);
+ APFloat::opStatus status;
+
+ status = V.convertFromString(&floatChars[0],APFloat::rmNearestTiesToEven);
+
+ if (isExact)
+ *isExact = status == APFloat::opOK;
+
+ return V;
+}
+
+
+CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
+ SourceLocation Loc, Preprocessor &PP) {
+ // 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;
+
+ // Skip over the entry quote.
+ assert(begin[0] == '\'' && "Invalid token lexed");
+ ++begin;
+
+ // FIXME: The "Value" is an uint64_t so we can handle char literals of
+ // upto 64-bits.
+ // FIXME: This extensively assumes that 'char' is 8-bits.
+ assert(PP.getTargetInfo().getCharWidth() == 8 &&
+ "Assumes char is 8 bits");
+ assert(PP.getTargetInfo().getIntWidth() <= 64 &&
+ (PP.getTargetInfo().getIntWidth() & 7) == 0 &&
+ "Assumes sizeof(int) on target is <= 64 and a multiple of char");
+ assert(PP.getTargetInfo().getWCharWidth() <= 64 &&
+ "Assumes sizeof(wchar) on target is <= 64");
+
+ // This is what we will use for overflow detection
+ llvm::APInt LitVal(PP.getTargetInfo().getIntWidth(), 0);
+
+ unsigned NumCharsSoFar = 0;
+ while (begin[0] != '\'') {
+ uint64_t ResultChar;
+ if (begin[0] != '\\') // If this is a normal character, consume it.
+ ResultChar = *begin++;
+ else // Otherwise, this is an escape character.
+ ResultChar = ProcessCharEscape(begin, end, HadError, Loc, IsWide, PP);
+
+ // 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) {
+ // Emulate GCC's (unintentional?) behavior: L'ab' -> L'b'.
+ LitVal = 0;
+ } else {
+ // Narrow character literals act as though their value is concatenated
+ // in this implementation, but warn on overflow.
+ if (LitVal.countLeadingZeros() < 8)
+ PP.Diag(Loc, diag::warn_char_constant_too_large);
+ LitVal <<= 8;
+ }
+ }
+
+ LitVal = LitVal + ResultChar;
+ ++NumCharsSoFar;
+ }
+
+ // If this is the second character being processed, do special handling.
+ 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);
+ else if (NumCharsSoFar != 4)
+ PP.Diag(Loc, diag::ext_multichar_character_literal);
+ else
+ PP.Diag(Loc, diag::ext_four_char_character_literal);
+ IsMultiChar = true;
+ }
+
+ // Transfer the value from APInt to uint64_t
+ Value = LitVal.getZExtValue();
+
+ // 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) &&
+ PP.getTargetInfo().isCharSigned())
+ Value = (signed char)Value;
+}
+
+
+/// string-literal: [C99 6.4.5]
+/// " [s-char-sequence] "
+/// L" [s-char-sequence] "
+/// 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
+/// 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
+/// universal-character-name:
+/// \u hex-quad
+/// \U hex-quad hex-quad
+/// hex-quad:
+/// hex-digit hex-digit hex-digit hex-digit
+///
+StringLiteralParser::
+StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
+ Preprocessor &pp) : PP(pp) {
+ // Scan all of the string portions, remember the max individual token length,
+ // computing a bound on the concatenated string length, and see whether any
+ // piece is a wide-string. If any of the string portions is a wide-string
+ // literal, the result is a wide-string literal [C99 6.4.5p4].
+ MaxTokenLength = StringToks[0].getLength();
+ SizeBound = StringToks[0].getLength()-2; // -2 for "".
+ AnyWide = StringToks[0].is(tok::wide_string_literal);
+
+ hadError = false;
+
+ // Implement Translation Phase #6: concatenation of string literals
+ /// (C99 5.1.1.2p1). The common case is only one string fragment.
+ for (unsigned i = 1; i != NumStringToks; ++i) {
+ // The string could be shorter than this if it needs cleaning, but this is a
+ // reasonable bound, which is all we need.
+ SizeBound += StringToks[i].getLength()-2; // -2 for "".
+
+ // Remember maximum string piece length.
+ if (StringToks[i].getLength() > MaxTokenLength)
+ MaxTokenLength = StringToks[i].getLength();
+
+ // Remember if we see any wide strings.
+ AnyWide |= StringToks[i].is(tok::wide_string_literal);
+ }
+
+ // Include space for the null terminator.
+ ++SizeBound;
+
+ // 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 = PP.getTargetInfo().getWCharWidth();
+ assert((wchar_tByteWidth & 7) == 0 && "Assumes wchar_t is byte multiple!");
+ wchar_tByteWidth /= 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;
+
+ // Size the temporary buffer to hold the result string data.
+ ResultBuf.resize(SizeBound);
+
+ // Likewise, but for each string piece.
+ llvm::SmallString<512> TokenBuf;
+ TokenBuf.resize(MaxTokenLength);
+
+ // Loop over all the strings, getting their spelling, and expanding them to
+ // wide strings as appropriate.
+ ResultPtr = &ResultBuf[0]; // Next byte to fill in.
+
+ Pascal = false;
+
+ for (unsigned i = 0, e = NumStringToks; i != e; ++i) {
+ const char *ThisTokBuf = &TokenBuf[0];
+ // Get the spelling of the token, which eliminates trigraphs, etc. We know
+ // that ThisTokBuf points to a buffer that is big enough for the whole token
+ // and 'spelled' tokens can only shrink.
+ unsigned ThisTokLen = PP.getSpelling(StringToks[i], ThisTokBuf);
+ const char *ThisTokEnd = ThisTokBuf+ThisTokLen-1; // Skip end quote.
+
+ // TODO: Input character set mapping support.
+
+ // Skip L marker for wide strings.
+ bool ThisIsWide = false;
+ if (ThisTokBuf[0] == 'L') {
+ ++ThisTokBuf;
+ ThisIsWide = true;
+ }
+
+ assert(ThisTokBuf[0] == '"' && "Expected quote, lexer broken?");
+ ++ThisTokBuf;
+
+ // Check if this is a pascal string
+ if (pp.getLangOptions().PascalStrings && ThisTokBuf + 1 != ThisTokEnd &&
+ ThisTokBuf[0] == '\\' && ThisTokBuf[1] == 'p') {
+
+ // 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;
+ Pascal = true;
+ } else if (Pascal)
+ ThisTokBuf += 2;
+ }
+
+ 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.
+ 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') {
+ ProcessUCNEscape(ThisTokBuf, ThisTokEnd, ResultPtr,
+ hadError, StringToks[i].getLocation(), ThisIsWide, PP);
+ continue;
+ }
+ // Otherwise, this is a non-UCN escape character. Process it.
+ unsigned ResultChar = ProcessCharEscape(ThisTokBuf, ThisTokEnd, hadError,
+ StringToks[i].getLocation(),
+ ThisIsWide, PP);
+
+ // 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)
+ *ResultPtr++ = ResultChar >> i*8;
+ }
+ }
+ }
+
+ if (Pascal) {
+ ResultBuf[0] = ResultPtr-&ResultBuf[0]-1;
+
+ // Verify that pascal strings aren't too large.
+ if (GetStringLength() > 256) {
+ PP.Diag(StringToks[0].getLocation(), diag::err_pascal_string_too_long)
+ << SourceRange(StringToks[0].getLocation(),
+ StringToks[NumStringToks-1].getLocation());
+ hadError = 1;
+ return;
+ }
+ }
+}
+
+
+/// 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.
+unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok,
+ unsigned ByteNo,
+ Preprocessor &PP) {
+ // Get the spelling of the token.
+ llvm::SmallString<16> SpellingBuffer;
+ SpellingBuffer.resize(Tok.getLength());
+
+ const char *SpellingPtr = &SpellingBuffer[0];
+ unsigned TokLen = PP.getSpelling(Tok, SpellingPtr);
+
+ assert(SpellingPtr[0] != 'L' && "Doesn't handle wide strings yet");
+
+
+ const char *SpellingStart = SpellingPtr;
+ const char *SpellingEnd = SpellingPtr+TokLen;
+
+ // Skip over the leading quote.
+ assert(SpellingPtr[0] == '"' && "Should be a string literal!");
+ ++SpellingPtr;
+
+ // Skip over bytes until we find the offset we're looking for.
+ while (ByteNo) {
+ assert(SpellingPtr < SpellingEnd && "Didn't find byte offset!");
+
+ // Step over non-escapes simply.
+ if (*SpellingPtr != '\\') {
+ ++SpellingPtr;
+ --ByteNo;
+ continue;
+ }
+
+ // Otherwise, this is an escape character. Advance over it.
+ bool HadError = false;
+ ProcessCharEscape(SpellingPtr, SpellingEnd, HadError,
+ Tok.getLocation(), false, PP);
+ assert(!HadError && "This method isn't valid on erroneous strings");
+ --ByteNo;
+ }
+
+ return SpellingPtr-SpellingStart;
+}
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
new file mode 100644
index 000000000000..cba69b7d7919
--- /dev/null
+++ b/lib/Lex/MacroArgs.cpp
@@ -0,0 +1,240 @@
+//===--- TokenLexer.cpp - Lex from a token stream -------------------------===//
+//
+// 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 TokenLexer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MacroArgs.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/LexDiagnostic.h"
+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) {
+ assert(MI->isFunctionLike() &&
+ "Can't have args for an object-like macro!");
+
+ // Allocate memory for the MacroArgs object with the lexer tokens at the end.
+ MacroArgs *Result = (MacroArgs*)malloc(sizeof(MacroArgs) +
+ NumToks*sizeof(Token));
+ // Construct the macroargs object.
+ new (Result) MacroArgs(NumToks, 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));
+
+ return Result;
+}
+
+/// destroy - Destroy and deallocate the memory for this object.
+///
+void MacroArgs::destroy() {
+ // Run the dtor to deallocate the vectors.
+ this->~MacroArgs();
+ // Release the memory for the object.
+ free(this);
+}
+
+
+/// getArgLength - Given a pointer to an expanded or unexpanded argument,
+/// return the number of tokens, not counting the EOF, that make up the
+/// argument.
+unsigned MacroArgs::getArgLength(const Token *ArgPtr) {
+ unsigned NumArgTokens = 0;
+ for (; ArgPtr->isNot(tok::eof); ++ArgPtr)
+ ++NumArgTokens;
+ return NumArgTokens;
+}
+
+
+/// getUnexpArgument - Return the unexpanded tokens for the specified formal.
+///
+const Token *MacroArgs::getUnexpArgument(unsigned Arg) const {
+ // The unexpanded argument tokens start immediately after the MacroArgs object
+ // in memory.
+ const Token *Start = (const Token *)(this+1);
+ const Token *Result = Start;
+ // Scan to find Arg.
+ for (; Arg; ++Result) {
+ assert(Result < Start+NumUnexpArgTokens && "Invalid arg #");
+ if (Result->is(tok::eof))
+ --Arg;
+ }
+ assert(Result < Start+NumUnexpArgTokens && "Invalid arg #");
+ return Result;
+}
+
+
+/// ArgNeedsPreexpansion - If we can prove that the argument won't be affected
+/// by pre-expansion, return false. Otherwise, conservatively return true.
+bool MacroArgs::ArgNeedsPreexpansion(const Token *ArgTok,
+ Preprocessor &PP) const {
+ // If there are no identifiers in the argument list, or if the identifiers are
+ // known to not be macros, pre-expansion won't modify it.
+ for (; ArgTok->isNot(tok::eof); ++ArgTok)
+ if (IdentifierInfo *II = ArgTok->getIdentifierInfo()) {
+ if (II->hasMacroDefinition() && PP.getMacroInfo(II)->isEnabled())
+ // Return true even though the macro could be a function-like macro
+ // without a following '(' token.
+ return true;
+ }
+ return false;
+}
+
+/// getPreExpArgument - Return the pre-expanded form of the specified
+/// argument.
+const std::vector<Token> &
+MacroArgs::getPreExpArgument(unsigned Arg, Preprocessor &PP) {
+ assert(Arg < NumUnexpArgTokens && "Invalid argument number!");
+
+ // If we have already computed this, return it.
+ if (PreExpArgTokens.empty())
+ PreExpArgTokens.resize(NumUnexpArgTokens);
+
+ std::vector<Token> &Result = PreExpArgTokens[Arg];
+ if (!Result.empty()) return Result;
+
+ const Token *AT = getUnexpArgument(Arg);
+ unsigned NumToks = getArgLength(AT)+1; // Include the EOF.
+
+ // Otherwise, we have to pre-expand this argument, populating Result. To do
+ // this, we set up a fake TokenLexer to lex from the unexpanded argument
+ // list. With this installed, we lex expanded tokens until we hit the EOF
+ // token at the end of the unexp list.
+ PP.EnterTokenStream(AT, NumToks, false /*disable expand*/,
+ false /*owns tokens*/);
+
+ // Lex all of the macro-expanded tokens into Result.
+ do {
+ Result.push_back(Token());
+ Token &Tok = Result.back();
+ PP.Lex(Tok);
+ } while (Result.back().isNot(tok::eof));
+
+ // Pop the token stream off the top of the stack. We know that the internal
+ // pointer inside of it is to the "end" of the token stream, but the stack
+ // will not otherwise be popped until the next token is lexed. The problem is
+ // that the token may be lexed sometime after the vector of tokens itself is
+ // destroyed, which would be badness.
+ PP.RemoveTopOfLexerStack();
+ return Result;
+}
+
+
+/// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of
+/// tokens into the literal string token that should be produced by the C #
+/// preprocessor operator. If Charify is true, then it should be turned into
+/// a character literal for the Microsoft charize (#@) extension.
+///
+Token MacroArgs::StringifyArgument(const Token *ArgToks,
+ Preprocessor &PP, bool Charify) {
+ Token Tok;
+ Tok.startToken();
+ Tok.setKind(tok::string_literal);
+
+ const Token *ArgTokStart = ArgToks;
+
+ // Stringify all the tokens.
+ llvm::SmallString<128> Result;
+ Result += "\"";
+
+ bool isFirst = true;
+ for (; ArgToks->isNot(tok::eof); ++ArgToks) {
+ const Token &Tok = *ArgToks;
+ if (!isFirst && (Tok.hasLeadingSpace() || Tok.isAtStartOfLine()))
+ Result += ' ';
+ isFirst = false;
+
+ // If this is a string or character constant, escape the token as specified
+ // by 6.10.3.2p2.
+ if (Tok.is(tok::string_literal) || // "foo"
+ Tok.is(tok::wide_string_literal) || // L"foo"
+ Tok.is(tok::char_constant)) { // 'x' and L'x'.
+ std::string Str = Lexer::Stringify(PP.getSpelling(Tok));
+ Result.append(Str.begin(), Str.end());
+ } else {
+ // Otherwise, just append the token. Do some gymnastics to get the token
+ // in place and avoid copies where possible.
+ unsigned CurStrLen = Result.size();
+ Result.resize(CurStrLen+Tok.getLength());
+ const char *BufPtr = &Result[CurStrLen];
+ unsigned ActualTokLen = PP.getSpelling(Tok, BufPtr);
+
+ // If getSpelling returned a pointer to an already uniqued version of the
+ // string instead of filling in BufPtr, memcpy it onto our string.
+ if (BufPtr != &Result[CurStrLen])
+ memcpy(&Result[CurStrLen], BufPtr, ActualTokLen);
+
+ // If the token was dirty, the spelling may be shorter than the token.
+ if (ActualTokLen != Tok.getLength())
+ Result.resize(CurStrLen+ActualTokLen);
+ }
+ }
+
+ // If the last character of the string is a \, and if it isn't escaped, this
+ // is an invalid string literal, diagnose it as specified in C99.
+ if (Result.back() == '\\') {
+ // Count the number of consequtive \ characters. If even, then they are
+ // just escaped backslashes, otherwise it's an error.
+ unsigned FirstNonSlash = Result.size()-2;
+ // Guaranteed to find the starting " if nothing else.
+ while (Result[FirstNonSlash] == '\\')
+ --FirstNonSlash;
+ if ((Result.size()-1-FirstNonSlash) & 1) {
+ // Diagnose errors for things like: #define F(X) #X / F(\)
+ PP.Diag(ArgToks[-1], diag::pp_invalid_string_literal);
+ Result.pop_back(); // remove one of the \'s.
+ }
+ }
+ Result += '"';
+
+ // If this is the charify operation and the result is not a legal character
+ // constant, diagnose it.
+ if (Charify) {
+ // First step, turn double quotes into single quotes:
+ Result[0] = '\'';
+ Result[Result.size()-1] = '\'';
+
+ // Check for bogus character.
+ bool isBad = false;
+ if (Result.size() == 3)
+ isBad = Result[1] == '\''; // ''' is not legal. '\' already fixed above.
+ else
+ isBad = (Result.size() != 4 || Result[1] != '\\'); // Not '\x'
+
+ if (isBad) {
+ PP.Diag(ArgTokStart[0], diag::err_invalid_character_to_charify);
+ Result = "' '"; // Use something arbitrary, but legal.
+ }
+ }
+
+ PP.CreateString(&Result[0], Result.size(), Tok);
+ return Tok;
+}
+
+/// getStringifiedArgument - Compute, cache, and return the specified argument
+/// that has been 'stringified' as required by the # operator.
+const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo,
+ Preprocessor &PP) {
+ assert(ArgNo < NumUnexpArgTokens && "Invalid argument number!");
+ if (StringifiedArgs.empty()) {
+ StringifiedArgs.resize(getNumArguments());
+ memset(&StringifiedArgs[0], 0,
+ sizeof(StringifiedArgs[0])*getNumArguments());
+ }
+ if (StringifiedArgs[ArgNo].isNot(tok::string_literal))
+ StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP);
+ return StringifiedArgs[ArgNo];
+}
diff --git a/lib/Lex/MacroArgs.h b/lib/Lex/MacroArgs.h
new file mode 100644
index 000000000000..4b22fa18aa8b
--- /dev/null
+++ b/lib/Lex/MacroArgs.h
@@ -0,0 +1,109 @@
+//===--- MacroArgs.h - Formal argument info for Macros ----------*- 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 MacroArgs interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_MACROARGS_H
+#define LLVM_CLANG_MACROARGS_H
+
+#include <vector>
+
+namespace clang {
+ class MacroInfo;
+ class Preprocessor;
+ class Token;
+
+/// MacroArgs - An instance of this class captures information about
+/// the formal arguments specified to a function-like macro invocation.
+class MacroArgs {
+ /// NumUnexpArgTokens - The number of raw, unexpanded tokens for the
+ /// arguments. All of the actual argument tokens are allocated immediately
+ /// after the MacroArgs object in memory. This is all of the arguments
+ /// concatenated together, with 'EOF' markers at the end of each argument.
+ unsigned NumUnexpArgTokens;
+
+ /// PreExpArgTokens - Pre-expanded tokens for arguments that need them. Empty
+ /// if not yet computed. This includes the EOF marker at the end of the
+ /// stream.
+ std::vector<std::vector<Token> > PreExpArgTokens;
+
+ /// StringifiedArgs - This contains arguments in 'stringified' form. If the
+ /// stringified form of an argument has not yet been computed, this is empty.
+ std::vector<Token> StringifiedArgs;
+
+ /// VarargsElided - True if this is a C99 style varargs macro invocation and
+ /// there was no argument specified for the "..." argument. If the argument
+ /// was specified (even empty) or this isn't a C99 style varargs function, or
+ /// if in strict mode and the C99 varargs macro had only a ... argument, this
+ /// is false.
+ bool VarargsElided;
+
+ MacroArgs(unsigned NumToks, bool varargsElided)
+ : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided) {}
+ ~MacroArgs() {}
+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);
+
+ /// destroy - Destroy and deallocate the memory for this object.
+ ///
+ void destroy();
+
+ /// ArgNeedsPreexpansion - If we can prove that the argument won't be affected
+ /// by pre-expansion, return false. Otherwise, conservatively return true.
+ bool ArgNeedsPreexpansion(const Token *ArgTok, Preprocessor &PP) const;
+
+ /// getUnexpArgument - Return a pointer to the first token of the unexpanded
+ /// token list for the specified formal.
+ ///
+ const Token *getUnexpArgument(unsigned Arg) const;
+
+ /// getArgLength - Given a pointer to an expanded or unexpanded argument,
+ /// return the number of tokens, not counting the EOF, that make up the
+ /// argument.
+ static unsigned getArgLength(const Token *ArgPtr);
+
+ /// getPreExpArgument - Return the pre-expanded form of the specified
+ /// argument.
+ const std::vector<Token> &
+ getPreExpArgument(unsigned Arg, Preprocessor &PP);
+
+ /// getStringifiedArgument - Compute, cache, and return the specified argument
+ /// that has been 'stringified' as required by the # operator.
+ const Token &getStringifiedArgument(unsigned ArgNo, Preprocessor &PP);
+
+ /// getNumArguments - Return the number of arguments passed into this macro
+ /// invocation.
+ unsigned getNumArguments() const { return NumUnexpArgTokens; }
+
+
+ /// isVarargsElidedUse - Return true if this is a C99 style varargs macro
+ /// invocation and there was no argument specified for the "..." argument. If
+ /// the argument was specified (even empty) or this isn't a C99 style varargs
+ /// function, or if in strict mode and the C99 varargs macro had only a ...
+ /// argument, this returns false.
+ bool isVarargsElidedUse() const { return VarargsElided; }
+
+ /// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of
+ /// tokens into the literal string token that should be produced by the C #
+ /// preprocessor operator. If Charify is true, then it should be turned into
+ /// a character literal for the Microsoft charize (#@) extension.
+ ///
+ static Token StringifyArgument(const Token *ArgToks,
+ Preprocessor &PP, bool Charify = false);
+};
+
+} // end namespace clang
+
+#endif
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
new file mode 100644
index 000000000000..df89450f5a55
--- /dev/null
+++ b/lib/Lex/MacroInfo.cpp
@@ -0,0 +1,75 @@
+//===--- MacroInfo.cpp - Information about #defined identifiers -----------===//
+//
+// 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 MacroInfo interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Preprocessor.h"
+using namespace clang;
+
+MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
+ IsFunctionLike = false;
+ IsC99Varargs = false;
+ IsGNUVarargs = false;
+ IsBuiltinMacro = false;
+ IsDisabled = false;
+ IsUsed = true;
+
+ ArgumentList = 0;
+ NumArguments = 0;
+}
+
+/// isIdenticalTo - Return true if the specified macro definition is equal to
+/// this macro in spelling, arguments, and whitespace. This is used to emit
+/// duplicate definition warnings. This implements the rules in C99 6.10.3.
+///
+bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
+ // Check # tokens in replacement, number of args, and various flags all match.
+ if (ReplacementTokens.size() != Other.ReplacementTokens.size() ||
+ getNumArgs() != Other.getNumArgs() ||
+ isFunctionLike() != Other.isFunctionLike() ||
+ isC99Varargs() != Other.isC99Varargs() ||
+ isGNUVarargs() != Other.isGNUVarargs())
+ return false;
+
+ // Check arguments.
+ for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end();
+ I != E; ++I, ++OI)
+ if (*I != *OI) return false;
+
+ // Check all the tokens.
+ for (unsigned i = 0, e = ReplacementTokens.size(); i != e; ++i) {
+ const Token &A = ReplacementTokens[i];
+ const Token &B = Other.ReplacementTokens[i];
+ if (A.getKind() != B.getKind())
+ return false;
+
+ // If this isn't the first first token, check that the whitespace and
+ // start-of-line characteristics match.
+ if (i != 0 &&
+ (A.isAtStartOfLine() != B.isAtStartOfLine() ||
+ A.hasLeadingSpace() != B.hasLeadingSpace()))
+ return false;
+
+ // If this is an identifier, it is easy.
+ if (A.getIdentifierInfo() || B.getIdentifierInfo()) {
+ if (A.getIdentifierInfo() != B.getIdentifierInfo())
+ return false;
+ continue;
+ }
+
+ // Otherwise, check the spelling.
+ if (PP.getSpelling(A) != PP.getSpelling(B))
+ return false;
+ }
+
+ return true;
+}
diff --git a/lib/Lex/Makefile b/lib/Lex/Makefile
new file mode 100644
index 000000000000..a2437da812bd
--- /dev/null
+++ b/lib/Lex/Makefile
@@ -0,0 +1,28 @@
+##===- clang/lib/Lex/Makefile ------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements the Lexer library for the C-Language front-end.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+include $(LEVEL)/Makefile.config
+
+LIBRARYNAME := clangLex
+BUILD_ARCHIVE = 1
+CXXFLAGS = -fno-rtti
+
+ifeq ($(ARCH),PowerPC)
+CXXFLAGS += -maltivec
+endif
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/Lex/PPCaching.cpp b/lib/Lex/PPCaching.cpp
new file mode 100644
index 000000000000..53aa09c13040
--- /dev/null
+++ b/lib/Lex/PPCaching.cpp
@@ -0,0 +1,113 @@
+//===--- PPCaching.cpp - Handle caching lexed tokens ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements pieces of the Preprocessor interface that manage the
+// caching of lexed tokens.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Preprocessor.h"
+using namespace clang;
+
+/// EnableBacktrackAtThisPos - From the point that this method is called, and
+/// until CommitBacktrackedTokens() or Backtrack() is called, the Preprocessor
+/// keeps track of the lexed tokens so that a subsequent Backtrack() call will
+/// make the Preprocessor re-lex the same tokens.
+///
+/// Nested backtracks are allowed, meaning that EnableBacktrackAtThisPos can
+/// be called multiple times and CommitBacktrackedTokens/Backtrack calls will
+/// be combined with the EnableBacktrackAtThisPos calls in reverse order.
+void Preprocessor::EnableBacktrackAtThisPos() {
+ BacktrackPositions.push_back(CachedLexPos);
+ EnterCachingLexMode();
+}
+
+/// CommitBacktrackedTokens - Disable the last EnableBacktrackAtThisPos call.
+void Preprocessor::CommitBacktrackedTokens() {
+ assert(!BacktrackPositions.empty()
+ && "EnableBacktrackAtThisPos was not called!");
+ BacktrackPositions.pop_back();
+}
+
+/// Backtrack - Make Preprocessor re-lex the tokens that were lexed since
+/// EnableBacktrackAtThisPos() was previously called.
+void Preprocessor::Backtrack() {
+ assert(!BacktrackPositions.empty()
+ && "EnableBacktrackAtThisPos was not called!");
+ CachedLexPos = BacktrackPositions.back();
+ BacktrackPositions.pop_back();
+}
+
+void Preprocessor::CachingLex(Token &Result) {
+ if (CachedLexPos < CachedTokens.size()) {
+ Result = CachedTokens[CachedLexPos++];
+ return;
+ }
+
+ ExitCachingLexMode();
+ Lex(Result);
+
+ if (!isBacktrackEnabled()) {
+ // All cached tokens were consumed.
+ CachedTokens.clear();
+ CachedLexPos = 0;
+ return;
+ }
+
+ // We should cache the lexed token.
+
+ EnterCachingLexMode();
+ if (Result.isNot(tok::eof)) {
+ CachedTokens.push_back(Result);
+ ++CachedLexPos;
+ }
+}
+
+void Preprocessor::EnterCachingLexMode() {
+ if (InCachingLexMode())
+ return;
+
+ PushIncludeMacroStack();
+}
+
+
+const Token &Preprocessor::PeekAhead(unsigned N) {
+ assert(CachedLexPos + N > CachedTokens.size() && "Confused caching.");
+ ExitCachingLexMode();
+ for (unsigned C = CachedLexPos + N - CachedTokens.size(); C > 0; --C) {
+ CachedTokens.push_back(Token());
+ Lex(CachedTokens.back());
+ }
+ EnterCachingLexMode();
+ return CachedTokens.back();
+}
+
+void Preprocessor::AnnotatePreviousCachedTokens(const Token &Tok) {
+ assert(Tok.isAnnotation() && "Expected annotation token");
+ assert(CachedLexPos != 0 && "Expected to have some cached tokens");
+ assert(CachedTokens[CachedLexPos-1].getLocation() == Tok.getAnnotationEndLoc()
+ && "The annotation should be until the most recent cached token");
+
+ // Start from the end of the cached tokens list and look for the token
+ // that is the beginning of the annotation token.
+ for (CachedTokensTy::size_type i = CachedLexPos; i != 0; --i) {
+ CachedTokensTy::iterator AnnotBegin = CachedTokens.begin() + i-1;
+ if (AnnotBegin->getLocation() == Tok.getLocation()) {
+ assert((BacktrackPositions.empty() || BacktrackPositions.back() < i) &&
+ "The backtrack pos points inside the annotated tokens!");
+ // Replace the cached tokens with the single annotation token.
+ CachedTokens.erase(AnnotBegin + 1, CachedTokens.begin() + CachedLexPos);
+ *AnnotBegin = Tok;
+ CachedLexPos = i;
+ return;
+ }
+ }
+
+ assert(0&&"Didn't find the first token represented by the annotation token!");
+}
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
new file mode 100644
index 000000000000..af59ded27544
--- /dev/null
+++ b/lib/Lex/PPDirectives.cpp
@@ -0,0 +1,1665 @@
+//===--- PPDirectives.cpp - Directive Handling for Preprocessor -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements # directive processing for the Preprocessor.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/APInt.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Utility Methods for Preprocessor Directive Handling.
+//===----------------------------------------------------------------------===//
+
+MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) {
+ MacroInfo *MI;
+
+ if (!MICache.empty()) {
+ MI = MICache.back();
+ MICache.pop_back();
+ } else
+ MI = (MacroInfo*) BP.Allocate<MacroInfo>();
+ new (MI) MacroInfo(L);
+ return MI;
+}
+
+/// ReleaseMacroInfo - Release the specified MacroInfo. This memory will
+/// be reused for allocating new MacroInfo objects.
+void Preprocessor::ReleaseMacroInfo(MacroInfo* MI) {
+ MICache.push_back(MI);
+ MI->FreeArgumentList(BP);
+}
+
+
+/// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the
+/// current line until the tok::eom token is found.
+void Preprocessor::DiscardUntilEndOfDirective() {
+ Token Tmp;
+ do {
+ LexUnexpandedToken(Tmp);
+ } while (Tmp.isNot(tok::eom));
+}
+
+/// ReadMacroName - Lex and validate a macro name, which occurs after a
+/// #define or #undef. This sets the token kind to eom and discards the rest
+/// of the macro line if the macro name is invalid. isDefineUndef is 1 if
+/// this is due to a a #define, 2 if #undef directive, 0 if it is something
+/// else (e.g. #ifdef).
+void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
+ // Read the token, don't allow macro expansion on it.
+ LexUnexpandedToken(MacroNameTok);
+
+ // Missing macro name?
+ if (MacroNameTok.is(tok::eom)) {
+ Diag(MacroNameTok, diag::err_pp_missing_macro_name);
+ return;
+ }
+
+ IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
+ if (II == 0) {
+ std::string Spelling = getSpelling(MacroNameTok);
+ const IdentifierInfo &Info = Identifiers.get(Spelling);
+ if (Info.isCPlusPlusOperatorKeyword())
+ // C++ 2.5p2: Alternative tokens behave the same as its primary token
+ // except for their spellings.
+ Diag(MacroNameTok, diag::err_pp_operator_used_as_macro_name) << Spelling;
+ else
+ Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
+ // Fall through on error.
+ } else if (isDefineUndef && II->getPPKeywordID() == tok::pp_defined) {
+ // Error if defining "defined": C99 6.10.8.4.
+ Diag(MacroNameTok, diag::err_defined_macro_name);
+ } else if (isDefineUndef && II->hasMacroDefinition() &&
+ getMacroInfo(II)->isBuiltinMacro()) {
+ // Error if defining "__LINE__" and other builtins: C99 6.10.8.4.
+ if (isDefineUndef == 1)
+ Diag(MacroNameTok, diag::pp_redef_builtin_macro);
+ else
+ Diag(MacroNameTok, diag::pp_undef_builtin_macro);
+ } else {
+ // Okay, we got a good identifier node. Return it.
+ return;
+ }
+
+ // Invalid macro name, read and discard the rest of the line. Then set the
+ // token kind to tok::eom.
+ MacroNameTok.setKind(tok::eom);
+ return DiscardUntilEndOfDirective();
+}
+
+/// CheckEndOfDirective - Ensure that the next token is a tok::eom token. If
+/// not, emit a diagnostic and consume up until the eom. If EnableMacros is
+/// true, then we consider macros that expand to zero tokens as being ok.
+void Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) {
+ Token Tmp;
+ // Lex unexpanded tokens for most directives: macros might expand to zero
+ // tokens, causing us to miss diagnosing invalid lines. Some directives (like
+ // #line) allow empty macros.
+ if (EnableMacros)
+ Lex(Tmp);
+ else
+ LexUnexpandedToken(Tmp);
+
+ // There should be no tokens after the directive, but we allow them as an
+ // extension.
+ while (Tmp.is(tok::comment)) // Skip comments in -C mode.
+ LexUnexpandedToken(Tmp);
+
+ if (Tmp.isNot(tok::eom)) {
+ // Add a fixit in GNU/C99/C++ mode. Don't offer a fixit for strict-C89,
+ // because it is more trouble than it is worth to insert /**/ and check that
+ // there is no /**/ in the range also.
+ CodeModificationHint FixItHint;
+ if (Features.GNUMode || Features.C99 || Features.CPlusPlus)
+ FixItHint = CodeModificationHint::CreateInsertion(Tmp.getLocation(),"//");
+ Diag(Tmp, diag::ext_pp_extra_tokens_at_eol) << DirType << FixItHint;
+ DiscardUntilEndOfDirective();
+ }
+}
+
+
+
+/// SkipExcludedConditionalBlock - We just read a #if or related directive and
+/// decided that the subsequent tokens are in the #if'd out portion of the
+/// file. Lex the rest of the file, until we see an #endif. If
+/// FoundNonSkipPortion is true, then we have already emitted code for part of
+/// this #if directive, so #else/#elif blocks should never be entered. If ElseOk
+/// is true, then #else directives are ok, if not, then we have already seen one
+/// so a #else directive is a duplicate. When this returns, the caller can lex
+/// the first valid token.
+void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
+ bool FoundNonSkipPortion,
+ bool FoundElse) {
+ ++NumSkipped;
+ assert(CurTokenLexer == 0 && CurPPLexer && "Lexing a macro, not a file?");
+
+ CurPPLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/false,
+ FoundNonSkipPortion, FoundElse);
+
+ if (CurPTHLexer) {
+ PTHSkipExcludedConditionalBlock();
+ return;
+ }
+
+ // Enter raw mode to disable identifier lookup (and thus macro expansion),
+ // disabling warnings, etc.
+ CurPPLexer->LexingRawMode = true;
+ Token Tok;
+ while (1) {
+ if (CurLexer)
+ CurLexer->Lex(Tok);
+ else
+ CurPTHLexer->Lex(Tok);
+
+ // If this is the end of the buffer, we have an error.
+ if (Tok.is(tok::eof)) {
+ // Emit errors for each unterminated conditional on the stack, including
+ // the current one.
+ while (!CurPPLexer->ConditionalStack.empty()) {
+ Diag(CurPPLexer->ConditionalStack.back().IfLoc,
+ diag::err_pp_unterminated_conditional);
+ CurPPLexer->ConditionalStack.pop_back();
+ }
+
+ // Just return and let the caller lex after this #include.
+ break;
+ }
+
+ // If this token is not a preprocessor directive, just skip it.
+ if (Tok.isNot(tok::hash) || !Tok.isAtStartOfLine())
+ continue;
+
+ // We just parsed a # character at the start of a line, so we're in
+ // directive mode. Tell the lexer this so any newlines we see will be
+ // converted into an EOM token (this terminates the macro).
+ CurPPLexer->ParsingPreprocessorDirective = true;
+ if (CurLexer) CurLexer->SetCommentRetentionState(false);
+
+
+ // Read the next token, the directive flavor.
+ LexUnexpandedToken(Tok);
+
+ // If this isn't an identifier directive (e.g. is "# 1\n" or "#\n", or
+ // something bogus), skip it.
+ if (Tok.isNot(tok::identifier)) {
+ CurPPLexer->ParsingPreprocessorDirective = false;
+ // Restore comment saving mode.
+ if (CurLexer) CurLexer->SetCommentRetentionState(KeepComments);
+ continue;
+ }
+
+ // If the first letter isn't i or e, it isn't intesting to us. We know that
+ // this is safe in the face of spelling differences, because there is no way
+ // to spell an i/e in a strange way that is another letter. Skipping this
+ // allows us to avoid looking up the identifier info for #define/#undef and
+ // other common directives.
+ const char *RawCharData = SourceMgr.getCharacterData(Tok.getLocation());
+ char FirstChar = RawCharData[0];
+ if (FirstChar >= 'a' && FirstChar <= 'z' &&
+ FirstChar != 'i' && FirstChar != 'e') {
+ CurPPLexer->ParsingPreprocessorDirective = false;
+ // Restore comment saving mode.
+ if (CurLexer) CurLexer->SetCommentRetentionState(KeepComments);
+ continue;
+ }
+
+ // Get the identifier name without trigraphs or embedded newlines. Note
+ // that we can't use Tok.getIdentifierInfo() because its lookup is disabled
+ // when skipping.
+ // TODO: could do this with zero copies in the no-clean case by using
+ // strncmp below.
+ char Directive[20];
+ unsigned IdLen;
+ if (!Tok.needsCleaning() && Tok.getLength() < 20) {
+ IdLen = Tok.getLength();
+ memcpy(Directive, RawCharData, IdLen);
+ Directive[IdLen] = 0;
+ } else {
+ std::string DirectiveStr = getSpelling(Tok);
+ IdLen = DirectiveStr.size();
+ if (IdLen >= 20) {
+ CurPPLexer->ParsingPreprocessorDirective = false;
+ // Restore comment saving mode.
+ if (CurLexer) CurLexer->SetCommentRetentionState(KeepComments);
+ continue;
+ }
+ memcpy(Directive, &DirectiveStr[0], IdLen);
+ Directive[IdLen] = 0;
+ FirstChar = Directive[0];
+ }
+
+ if (FirstChar == 'i' && Directive[1] == 'f') {
+ if ((IdLen == 2) || // "if"
+ (IdLen == 5 && !strcmp(Directive+2, "def")) || // "ifdef"
+ (IdLen == 6 && !strcmp(Directive+2, "ndef"))) { // "ifndef"
+ // We know the entire #if/#ifdef/#ifndef block will be skipped, don't
+ // bother parsing the condition.
+ DiscardUntilEndOfDirective();
+ CurPPLexer->pushConditionalLevel(Tok.getLocation(), /*wasskipping*/true,
+ /*foundnonskip*/false,
+ /*fnddelse*/false);
+ }
+ } else if (FirstChar == 'e') {
+ if (IdLen == 5 && !strcmp(Directive+1, "ndif")) { // "endif"
+ CheckEndOfDirective("endif");
+ PPConditionalInfo CondInfo;
+ CondInfo.WasSkipping = true; // Silence bogus warning.
+ bool InCond = CurPPLexer->popConditionalLevel(CondInfo);
+ InCond = InCond; // Silence warning in no-asserts mode.
+ assert(!InCond && "Can't be skipping if not in a conditional!");
+
+ // If we popped the outermost skipping block, we're done skipping!
+ if (!CondInfo.WasSkipping)
+ break;
+ } else if (IdLen == 4 && !strcmp(Directive+1, "lse")) { // "else".
+ // #else directive in a skipping conditional. If not in some other
+ // skipping conditional, and if #else hasn't already been seen, enter it
+ // as a non-skipping conditional.
+ DiscardUntilEndOfDirective(); // C99 6.10p4.
+ PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel();
+
+ // If this is a #else with a #else before it, report the error.
+ if (CondInfo.FoundElse) Diag(Tok, diag::pp_err_else_after_else);
+
+ // Note that we've seen a #else in this conditional.
+ CondInfo.FoundElse = true;
+
+ // If the conditional is at the top level, and the #if block wasn't
+ // entered, enter the #else block now.
+ if (!CondInfo.WasSkipping && !CondInfo.FoundNonSkip) {
+ CondInfo.FoundNonSkip = true;
+ break;
+ }
+ } else if (IdLen == 4 && !strcmp(Directive+1, "lif")) { // "elif".
+ PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel();
+
+ bool ShouldEnter;
+ // If this is in a skipping block or if we're already handled this #if
+ // block, don't bother parsing the condition.
+ if (CondInfo.WasSkipping || CondInfo.FoundNonSkip) {
+ DiscardUntilEndOfDirective();
+ ShouldEnter = false;
+ } else {
+ // Restore the value of LexingRawMode so that identifiers are
+ // looked up, etc, inside the #elif expression.
+ assert(CurPPLexer->LexingRawMode && "We have to be skipping here!");
+ CurPPLexer->LexingRawMode = false;
+ IdentifierInfo *IfNDefMacro = 0;
+ ShouldEnter = EvaluateDirectiveExpression(IfNDefMacro);
+ CurPPLexer->LexingRawMode = true;
+ }
+
+ // If this is a #elif with a #else before it, report the error.
+ if (CondInfo.FoundElse) Diag(Tok, diag::pp_err_elif_after_else);
+
+ // If this condition is true, enter it!
+ if (ShouldEnter) {
+ CondInfo.FoundNonSkip = true;
+ break;
+ }
+ }
+ }
+
+ CurPPLexer->ParsingPreprocessorDirective = false;
+ // Restore comment saving mode.
+ if (CurLexer) CurLexer->SetCommentRetentionState(KeepComments);
+ }
+
+ // Finally, if we are out of the conditional (saw an #endif or ran off the end
+ // of the file, just stop skipping and return to lexing whatever came after
+ // the #if block.
+ CurPPLexer->LexingRawMode = false;
+}
+
+void Preprocessor::PTHSkipExcludedConditionalBlock() {
+
+ while(1) {
+ assert(CurPTHLexer);
+ assert(CurPTHLexer->LexingRawMode == false);
+
+ // Skip to the next '#else', '#elif', or #endif.
+ if (CurPTHLexer->SkipBlock()) {
+ // We have reached an #endif. Both the '#' and 'endif' tokens
+ // have been consumed by the PTHLexer. Just pop off the condition level.
+ PPConditionalInfo CondInfo;
+ bool InCond = CurPTHLexer->popConditionalLevel(CondInfo);
+ InCond = InCond; // Silence warning in no-asserts mode.
+ assert(!InCond && "Can't be skipping if not in a conditional!");
+ break;
+ }
+
+ // We have reached a '#else' or '#elif'. Lex the next token to get
+ // the directive flavor.
+ Token Tok;
+ LexUnexpandedToken(Tok);
+
+ // We can actually look up the IdentifierInfo here since we aren't in
+ // raw mode.
+ tok::PPKeywordKind K = Tok.getIdentifierInfo()->getPPKeywordID();
+
+ if (K == tok::pp_else) {
+ // #else: Enter the else condition. We aren't in a nested condition
+ // since we skip those. We're always in the one matching the last
+ // blocked we skipped.
+ PPConditionalInfo &CondInfo = CurPTHLexer->peekConditionalLevel();
+ // Note that we've seen a #else in this conditional.
+ CondInfo.FoundElse = true;
+
+ // If the #if block wasn't entered then enter the #else block now.
+ if (!CondInfo.FoundNonSkip) {
+ CondInfo.FoundNonSkip = true;
+
+ // Scan until the eom token.
+ CurPTHLexer->ParsingPreprocessorDirective = true;
+ DiscardUntilEndOfDirective();
+ CurPTHLexer->ParsingPreprocessorDirective = false;
+
+ break;
+ }
+
+ // Otherwise skip this block.
+ continue;
+ }
+
+ assert(K == tok::pp_elif);
+ PPConditionalInfo &CondInfo = CurPTHLexer->peekConditionalLevel();
+
+ // If this is a #elif with a #else before it, report the error.
+ if (CondInfo.FoundElse)
+ Diag(Tok, diag::pp_err_elif_after_else);
+
+ // If this is in a skipping block or if we're already handled this #if
+ // block, don't bother parsing the condition. We just skip this block.
+ if (CondInfo.FoundNonSkip)
+ continue;
+
+ // Evaluate the condition of the #elif.
+ IdentifierInfo *IfNDefMacro = 0;
+ CurPTHLexer->ParsingPreprocessorDirective = true;
+ bool ShouldEnter = EvaluateDirectiveExpression(IfNDefMacro);
+ CurPTHLexer->ParsingPreprocessorDirective = false;
+
+ // If this condition is true, enter it!
+ if (ShouldEnter) {
+ CondInfo.FoundNonSkip = true;
+ break;
+ }
+
+ // Otherwise, skip this block and go to the next one.
+ continue;
+ }
+}
+
+/// 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 *Preprocessor::LookupFile(const char *FilenameStart,
+ const char *FilenameEnd,
+ bool isAngled,
+ const DirectoryLookup *FromDir,
+ const DirectoryLookup *&CurDir) {
+ // 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;
+ if (!FromDir) {
+ FileID FID = getCurrentFileLexer()->getFileID();
+ CurFileEnt = SourceMgr.getFileEntryForID(FID);
+
+ // If there is no file entry associated with this file, it must be the
+ // predefines buffer. Any other file is not lexed with a normal lexer, so
+ // it won't be scanned for preprocessor directives. If we have the
+ // predefines buffer, resolve #include references (which come from the
+ // -include command line argument) as if they came from the main file, this
+ // affects file lookup etc.
+ if (CurFileEnt == 0) {
+ FID = SourceMgr.getMainFileID();
+ CurFileEnt = SourceMgr.getFileEntryForID(FID);
+ }
+ }
+
+ // Do a standard file entry lookup.
+ CurDir = CurDirLookup;
+ const FileEntry *FE =
+ HeaderInfo.LookupFile(FilenameStart, FilenameEnd,
+ isAngled, FromDir, CurDir, CurFileEnt);
+ 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.
+ if (IsFileLexer()) {
+ if ((CurFileEnt = SourceMgr.getFileEntryForID(CurPPLexer->getFileID())))
+ if ((FE = HeaderInfo.LookupSubframeworkHeader(FilenameStart, FilenameEnd,
+ CurFileEnt)))
+ return FE;
+ }
+
+ for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) {
+ IncludeStackInfo &ISEntry = IncludeMacroStack[e-i-1];
+ if (IsFileLexer(ISEntry)) {
+ if ((CurFileEnt =
+ SourceMgr.getFileEntryForID(ISEntry.ThePPLexer->getFileID())))
+ if ((FE = HeaderInfo.LookupSubframeworkHeader(FilenameStart,
+ FilenameEnd, CurFileEnt)))
+ return FE;
+ }
+ }
+
+ // Otherwise, we really couldn't find the file.
+ return 0;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Directive Handling.
+//===----------------------------------------------------------------------===//
+
+/// HandleDirective - This callback is invoked when the lexer sees a # token
+/// at the start of a line. This consumes the directive, modifies the
+/// lexer/preprocessor state, and advances the lexer(s) so that the next token
+/// read is the correct one.
+void Preprocessor::HandleDirective(Token &Result) {
+ // FIXME: Traditional: # with whitespace before it not recognized by K&R?
+
+ // We just parsed a # character at the start of a line, so we're in directive
+ // mode. Tell the lexer this so any newlines we see will be converted into an
+ // EOM token (which terminates the directive).
+ CurPPLexer->ParsingPreprocessorDirective = true;
+
+ ++NumDirectives;
+
+ // We are about to read a token. For the multiple-include optimization FA to
+ // work, we have to remember if we had read any tokens *before* this
+ // pp-directive.
+ bool ReadAnyTokensBeforeDirective = CurPPLexer->MIOpt.getHasReadAnyTokensVal();
+
+ // Save the '#' token in case we need to return it later.
+ Token SavedHash = Result;
+
+ // Read the next token, the directive flavor. This isn't expanded due to
+ // C99 6.10.3p8.
+ LexUnexpandedToken(Result);
+
+ // C99 6.10.3p11: Is this preprocessor directive in macro invocation? e.g.:
+ // #define A(x) #x
+ // A(abc
+ // #warning blah
+ // def)
+ // If so, the user is relying on non-portable behavior, emit a diagnostic.
+ if (InMacroArgs)
+ Diag(Result, diag::ext_embedded_directive);
+
+TryAgain:
+ switch (Result.getKind()) {
+ case tok::eom:
+ return; // null directive.
+ case tok::comment:
+ // Handle stuff like "# /*foo*/ define X" in -E -C mode.
+ LexUnexpandedToken(Result);
+ goto TryAgain;
+
+ case tok::numeric_constant: // # 7 GNU line marker directive.
+ if (getLangOptions().AsmPreprocessor)
+ break; // # 4 is not a preprocessor directive in .S files.
+ return HandleDigitDirective(Result);
+ default:
+ IdentifierInfo *II = Result.getIdentifierInfo();
+ if (II == 0) break; // Not an identifier.
+
+ // Ask what the preprocessor keyword ID is.
+ switch (II->getPPKeywordID()) {
+ default: break;
+ // C99 6.10.1 - Conditional Inclusion.
+ case tok::pp_if:
+ return HandleIfDirective(Result, ReadAnyTokensBeforeDirective);
+ case tok::pp_ifdef:
+ return HandleIfdefDirective(Result, false, true/*not valid for miopt*/);
+ case tok::pp_ifndef:
+ return HandleIfdefDirective(Result, true, ReadAnyTokensBeforeDirective);
+ case tok::pp_elif:
+ return HandleElifDirective(Result);
+ case tok::pp_else:
+ return HandleElseDirective(Result);
+ case tok::pp_endif:
+ return HandleEndifDirective(Result);
+
+ // C99 6.10.2 - Source File Inclusion.
+ case tok::pp_include:
+ return HandleIncludeDirective(Result); // Handle #include.
+ case tok::pp___include_macros:
+ return HandleIncludeMacrosDirective(Result); // Handle -imacros.
+
+ // C99 6.10.3 - Macro Replacement.
+ case tok::pp_define:
+ return HandleDefineDirective(Result);
+ case tok::pp_undef:
+ return HandleUndefDirective(Result);
+
+ // C99 6.10.4 - Line Control.
+ case tok::pp_line:
+ return HandleLineDirective(Result);
+
+ // C99 6.10.5 - Error Directive.
+ case tok::pp_error:
+ return HandleUserDiagnosticDirective(Result, false);
+
+ // C99 6.10.6 - Pragma Directive.
+ case tok::pp_pragma:
+ return HandlePragmaDirective();
+
+ // GNU Extensions.
+ case tok::pp_import:
+ return HandleImportDirective(Result);
+ case tok::pp_include_next:
+ return HandleIncludeNextDirective(Result);
+
+ case tok::pp_warning:
+ Diag(Result, diag::ext_pp_warning_directive);
+ return HandleUserDiagnosticDirective(Result, true);
+ case tok::pp_ident:
+ return HandleIdentSCCSDirective(Result);
+ case tok::pp_sccs:
+ return HandleIdentSCCSDirective(Result);
+ case tok::pp_assert:
+ //isExtension = true; // FIXME: implement #assert
+ break;
+ case tok::pp_unassert:
+ //isExtension = true; // FIXME: implement #unassert
+ break;
+ }
+ break;
+ }
+
+ // If this is a .S file, treat unknown # directives as non-preprocessor
+ // directives. This is important because # may be a comment or introduce
+ // various pseudo-ops. Just return the # token and push back the following
+ // token to be lexed next time.
+ if (getLangOptions().AsmPreprocessor) {
+ Token *Toks = new Token[2]();
+ // Return the # and the token after it.
+ Toks[0] = SavedHash;
+ Toks[1] = Result;
+ // Enter this token stream so that we re-lex the tokens. Make sure to
+ // enable macro expansion, in case the token after the # is an identifier
+ // that is expanded.
+ EnterTokenStream(Toks, 2, false, true);
+ return;
+ }
+
+ // If we reached here, the preprocessing token is not valid!
+ Diag(Result, diag::err_pp_invalid_directive);
+
+ // Read the rest of the PP line.
+ DiscardUntilEndOfDirective();
+
+ // Okay, we're done parsing the directive.
+}
+
+/// GetLineValue - Convert a numeric token into an unsigned value, emitting
+/// Diagnostic DiagID if it is invalid, and returning the value in Val.
+static bool GetLineValue(Token &DigitTok, unsigned &Val,
+ unsigned DiagID, Preprocessor &PP) {
+ if (DigitTok.isNot(tok::numeric_constant)) {
+ PP.Diag(DigitTok, DiagID);
+
+ if (DigitTok.isNot(tok::eom))
+ PP.DiscardUntilEndOfDirective();
+ return true;
+ }
+
+ llvm::SmallString<64> IntegerBuffer;
+ IntegerBuffer.resize(DigitTok.getLength());
+ const char *DigitTokBegin = &IntegerBuffer[0];
+ unsigned ActualLength = PP.getSpelling(DigitTok, DigitTokBegin);
+
+ // Verify that we have a simple digit-sequence, and compute the value. This
+ // is always a simple digit string computed in decimal, so we do this manually
+ // here.
+ Val = 0;
+ for (unsigned i = 0; i != ActualLength; ++i) {
+ if (!isdigit(DigitTokBegin[i])) {
+ PP.Diag(PP.AdvanceToTokenCharacter(DigitTok.getLocation(), i),
+ diag::err_pp_line_digit_sequence);
+ PP.DiscardUntilEndOfDirective();
+ return true;
+ }
+
+ unsigned NextVal = Val*10+(DigitTokBegin[i]-'0');
+ if (NextVal < Val) { // overflow.
+ PP.Diag(DigitTok, DiagID);
+ PP.DiscardUntilEndOfDirective();
+ return true;
+ }
+ Val = NextVal;
+ }
+
+ // Reject 0, this is needed both by #line numbers and flags.
+ if (Val == 0) {
+ PP.Diag(DigitTok, DiagID);
+ PP.DiscardUntilEndOfDirective();
+ return true;
+ }
+
+ if (DigitTokBegin[0] == '0')
+ PP.Diag(DigitTok.getLocation(), diag::warn_pp_line_decimal);
+
+ return false;
+}
+
+/// HandleLineDirective - Handle #line directive: C99 6.10.4. The two
+/// acceptable forms are:
+/// # line digit-sequence
+/// # line digit-sequence "s-char-sequence"
+void Preprocessor::HandleLineDirective(Token &Tok) {
+ // Read the line # and string argument. Per C99 6.10.4p5, these tokens are
+ // expanded.
+ Token DigitTok;
+ Lex(DigitTok);
+
+ // Validate the number and convert it to an unsigned.
+ unsigned LineNo;
+ if (GetLineValue(DigitTok, LineNo, diag::err_pp_line_requires_integer,*this))
+ return;
+
+ // 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;
+ if (LineNo >= LineLimit)
+ Diag(DigitTok, diag::ext_pp_line_too_big) << LineLimit;
+
+ int FilenameID = -1;
+ Token StrTok;
+ Lex(StrTok);
+
+ // If the StrTok is "eom", then it wasn't present. Otherwise, it must be a
+ // string followed by eom.
+ if (StrTok.is(tok::eom))
+ ; // ok
+ else if (StrTok.isNot(tok::string_literal)) {
+ Diag(StrTok, diag::err_pp_line_invalid_filename);
+ DiscardUntilEndOfDirective();
+ return;
+ } 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");
+ if (Literal.hadError)
+ return DiscardUntilEndOfDirective();
+ if (Literal.Pascal) {
+ Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
+ return DiscardUntilEndOfDirective();
+ }
+ FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString(),
+ Literal.GetStringLength());
+
+ // Verify that there is nothing after the string, other than EOM. Because
+ // of C99 6.10.4p5, macros that expand to empty tokens are ok.
+ CheckEndOfDirective("line", true);
+ }
+
+ SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID);
+
+ if (Callbacks)
+ Callbacks->FileChanged(DigitTok.getLocation(), PPCallbacks::RenameFile,
+ SrcMgr::C_User);
+}
+
+/// ReadLineMarkerFlags - Parse and validate any flags at the end of a GNU line
+/// marker directive.
+static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
+ bool &IsSystemHeader, bool &IsExternCHeader,
+ Preprocessor &PP) {
+ unsigned FlagVal;
+ Token FlagTok;
+ PP.Lex(FlagTok);
+ if (FlagTok.is(tok::eom)) return false;
+ if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag, PP))
+ return true;
+
+ if (FlagVal == 1) {
+ IsFileEntry = true;
+
+ PP.Lex(FlagTok);
+ if (FlagTok.is(tok::eom)) return false;
+ if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag,PP))
+ return true;
+ } else if (FlagVal == 2) {
+ IsFileExit = true;
+
+ SourceManager &SM = PP.getSourceManager();
+ // 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;
+ PresumedLoc PLoc = SM.getPresumedLoc(FlagTok.getLocation());
+
+ // If there is no include loc (main file) or if the include loc is in a
+ // 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) {
+ PP.Diag(FlagTok, diag::err_pp_linemarker_invalid_pop);
+ PP.DiscardUntilEndOfDirective();
+ return true;
+ }
+
+ PP.Lex(FlagTok);
+ if (FlagTok.is(tok::eom)) return false;
+ if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag,PP))
+ return true;
+ }
+
+ // We must have 3 if there are still flags.
+ if (FlagVal != 3) {
+ PP.Diag(FlagTok, diag::err_pp_linemarker_invalid_flag);
+ PP.DiscardUntilEndOfDirective();
+ return true;
+ }
+
+ IsSystemHeader = true;
+
+ PP.Lex(FlagTok);
+ if (FlagTok.is(tok::eom)) return false;
+ if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag, PP))
+ return true;
+
+ // We must have 4 if there is yet another flag.
+ if (FlagVal != 4) {
+ PP.Diag(FlagTok, diag::err_pp_linemarker_invalid_flag);
+ PP.DiscardUntilEndOfDirective();
+ return true;
+ }
+
+ IsExternCHeader = true;
+
+ PP.Lex(FlagTok);
+ if (FlagTok.is(tok::eom)) return false;
+
+ // There are no more valid flags here.
+ PP.Diag(FlagTok, diag::err_pp_linemarker_invalid_flag);
+ PP.DiscardUntilEndOfDirective();
+ return true;
+}
+
+/// HandleDigitDirective - Handle a GNU line marker directive, whose syntax is
+/// one of the following forms:
+///
+/// # 42
+/// # 42 "file" ('1' | '2')?
+/// # 42 "file" ('1' | '2')? '3' '4'?
+///
+void Preprocessor::HandleDigitDirective(Token &DigitTok) {
+ // Validate the number and convert it to an unsigned. GNU does not have a
+ // line # limit other than it fit in 32-bits.
+ unsigned LineNo;
+ if (GetLineValue(DigitTok, LineNo, diag::err_pp_linemarker_requires_integer,
+ *this))
+ return;
+
+ Token StrTok;
+ Lex(StrTok);
+
+ bool IsFileEntry = false, IsFileExit = false;
+ bool IsSystemHeader = false, IsExternCHeader = false;
+ int FilenameID = -1;
+
+ // If the StrTok is "eom", then it wasn't present. Otherwise, it must be a
+ // string followed by eom.
+ if (StrTok.is(tok::eom))
+ ; // ok
+ else if (StrTok.isNot(tok::string_literal)) {
+ Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
+ return DiscardUntilEndOfDirective();
+ } 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");
+ if (Literal.hadError)
+ return DiscardUntilEndOfDirective();
+ if (Literal.Pascal) {
+ Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
+ return DiscardUntilEndOfDirective();
+ }
+ FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString(),
+ Literal.GetStringLength());
+
+ // If a filename was present, read any flags that are present.
+ if (ReadLineMarkerFlags(IsFileEntry, IsFileExit,
+ IsSystemHeader, IsExternCHeader, *this))
+ return;
+ }
+
+ // Create a line note with this information.
+ SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID,
+ IsFileEntry, IsFileExit,
+ IsSystemHeader, IsExternCHeader);
+
+ // If the preprocessor has callbacks installed, notify them of the #line
+ // change. This is used so that the line marker comes out in -E mode for
+ // example.
+ if (Callbacks) {
+ PPCallbacks::FileChangeReason Reason = PPCallbacks::RenameFile;
+ if (IsFileEntry)
+ Reason = PPCallbacks::EnterFile;
+ else if (IsFileExit)
+ Reason = PPCallbacks::ExitFile;
+ SrcMgr::CharacteristicKind FileKind = SrcMgr::C_User;
+ if (IsExternCHeader)
+ FileKind = SrcMgr::C_ExternCSystem;
+ else if (IsSystemHeader)
+ FileKind = SrcMgr::C_System;
+
+ Callbacks->FileChanged(DigitTok.getLocation(), Reason, FileKind);
+ }
+}
+
+
+/// HandleUserDiagnosticDirective - Handle a #warning or #error directive.
+///
+void Preprocessor::HandleUserDiagnosticDirective(Token &Tok,
+ bool isWarning) {
+ // PTH doesn't emit #warning or #error directives.
+ if (CurPTHLexer)
+ return CurPTHLexer->DiscardToEndOfLine();
+
+ // Read the rest of the line raw. We do this because we don't want macros
+ // to be expanded and we don't require that the tokens be valid preprocessing
+ // tokens. For example, this is allowed: "#warning ` 'foo". GCC does
+ // collapse multiple consequtive white space between tokens, but this isn't
+ // specified by the standard.
+ std::string Message = CurLexer->ReadToEndOfLine();
+ if (isWarning)
+ Diag(Tok, diag::pp_hash_warning) << Message;
+ else
+ Diag(Tok, diag::err_pp_hash_error) << Message;
+}
+
+/// HandleIdentSCCSDirective - Handle a #ident/#sccs directive.
+///
+void Preprocessor::HandleIdentSCCSDirective(Token &Tok) {
+ // Yes, this directive is an extension.
+ Diag(Tok, diag::ext_pp_ident_directive);
+
+ // Read the string argument.
+ Token StrTok;
+ Lex(StrTok);
+
+ // If the token kind isn't a string, it's a malformed directive.
+ if (StrTok.isNot(tok::string_literal) &&
+ StrTok.isNot(tok::wide_string_literal)) {
+ Diag(StrTok, diag::err_pp_malformed_ident);
+ if (StrTok.isNot(tok::eom))
+ DiscardUntilEndOfDirective();
+ return;
+ }
+
+ // Verify that there is nothing after the string, other than EOM.
+ CheckEndOfDirective("ident");
+
+ if (Callbacks)
+ Callbacks->Ident(Tok.getLocation(), getSpelling(StrTok));
+}
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Include Directive Handling.
+//===----------------------------------------------------------------------===//
+
+/// GetIncludeFilenameSpelling - Turn the specified lexer token into a fully
+/// checked and spelled filename, e.g. as an operand of #include. This returns
+/// true if the input filename was in <>'s or false if it were in ""'s. The
+/// 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 Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc,
+ const char *&BufStart,
+ const char *&BufEnd) {
+ // Get the text form of the filename.
+ assert(BufStart != BufEnd && "Can't have tokens with empty spellings!");
+
+ // Make sure the filename is <x> or "x".
+ bool isAngled;
+ if (BufStart[0] == '<') {
+ if (BufEnd[-1] != '>') {
+ Diag(Loc, diag::err_pp_expects_filename);
+ BufStart = 0;
+ return true;
+ }
+ isAngled = true;
+ } else if (BufStart[0] == '"') {
+ if (BufEnd[-1] != '"') {
+ Diag(Loc, diag::err_pp_expects_filename);
+ BufStart = 0;
+ return true;
+ }
+ isAngled = false;
+ } else {
+ Diag(Loc, diag::err_pp_expects_filename);
+ BufStart = 0;
+ return true;
+ }
+
+ // Diagnose #include "" as invalid.
+ if (BufEnd-BufStart <= 2) {
+ Diag(Loc, diag::err_pp_empty_filename);
+ BufStart = 0;
+ return "";
+ }
+
+ // Skip the brackets.
+ ++BufStart;
+ --BufEnd;
+ return isAngled;
+}
+
+/// ConcatenateIncludeName - Handle cases where the #include name is expanded
+/// from a macro as multiple tokens, which need to be glued together. This
+/// occurs for code like:
+/// #define FOO <a/b.h>
+/// #include FOO
+/// because in this case, "<a/b.h>" is returned as 7 tokens, not one.
+///
+/// This code concatenates and consumes tokens up to the '>' token. It returns
+/// false if the > was found, otherwise it returns true if it finds and consumes
+/// the EOM marker.
+static bool ConcatenateIncludeName(llvm::SmallVector<char, 128> &FilenameBuffer,
+ Preprocessor &PP) {
+ Token CurTok;
+
+ PP.Lex(CurTok);
+ while (CurTok.isNot(tok::eom)) {
+ // Append the spelling of this token to the buffer. If there was a space
+ // before it, add it now.
+ if (CurTok.hasLeadingSpace())
+ FilenameBuffer.push_back(' ');
+
+ // Get the spelling of the token, directly into FilenameBuffer if possible.
+ unsigned PreAppendSize = FilenameBuffer.size();
+ FilenameBuffer.resize(PreAppendSize+CurTok.getLength());
+
+ const char *BufPtr = &FilenameBuffer[PreAppendSize];
+ unsigned ActualLen = PP.getSpelling(CurTok, BufPtr);
+
+ // If the token was spelled somewhere else, copy it into FilenameBuffer.
+ if (BufPtr != &FilenameBuffer[PreAppendSize])
+ memcpy(&FilenameBuffer[PreAppendSize], BufPtr, ActualLen);
+
+ // Resize FilenameBuffer to the correct size.
+ if (CurTok.getLength() != ActualLen)
+ FilenameBuffer.resize(PreAppendSize+ActualLen);
+
+ // If we found the '>' marker, return success.
+ if (CurTok.is(tok::greater))
+ return false;
+
+ PP.Lex(CurTok);
+ }
+
+ // If we hit the eom marker, emit an error and return true so that the caller
+ // knows the EOM has been read.
+ PP.Diag(CurTok.getLocation(), diag::err_pp_expects_filename);
+ return true;
+}
+
+/// HandleIncludeDirective - The "#include" tokens have just been read, read the
+/// file to be included from the lexer, then include it! This is a common
+/// routine with functionality shared between #include, #include_next and
+/// #import. LookupFrom is set when this is a #include_next directive, it
+/// specifies the file to start searching from.
+void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
+ const DirectoryLookup *LookupFrom,
+ bool isImport) {
+
+ Token FilenameTok;
+ CurPPLexer->LexIncludeFilename(FilenameTok);
+
+ // Reserve a buffer to get the spelling.
+ llvm::SmallVector<char, 128> FilenameBuffer;
+ const char *FilenameStart, *FilenameEnd;
+
+ switch (FilenameTok.getKind()) {
+ case tok::eom:
+ // If the token kind is EOM, the error has already been diagnosed.
+ return;
+
+ case tok::angle_string_literal:
+ case tok::string_literal: {
+ FilenameBuffer.resize(FilenameTok.getLength());
+ FilenameStart = &FilenameBuffer[0];
+ unsigned Len = getSpelling(FilenameTok, FilenameStart);
+ FilenameEnd = FilenameStart+Len;
+ break;
+ }
+
+ case tok::less:
+ // This could be a <foo/bar.h> file coming from a macro expansion. In this
+ // case, glue the tokens together into FilenameBuffer and interpret those.
+ FilenameBuffer.push_back('<');
+ if (ConcatenateIncludeName(FilenameBuffer, *this))
+ return; // Found <eom> but no ">"? Diagnostic already emitted.
+ FilenameStart = FilenameBuffer.data();
+ FilenameEnd = FilenameStart + FilenameBuffer.size();
+ break;
+ default:
+ Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
+ DiscardUntilEndOfDirective();
+ return;
+ }
+
+ bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(),
+ FilenameStart, FilenameEnd);
+ // If GetIncludeFilenameSpelling set the start ptr to null, there was an
+ // error.
+ if (FilenameStart == 0) {
+ DiscardUntilEndOfDirective();
+ return;
+ }
+
+ // Verify that there is nothing after the filename, other than EOM. Note that
+ // we allow macros that expand to nothing after the filename, because this
+ // falls into the category of "#include pp-tokens new-line" specified in
+ // C99 6.10.2p4.
+ CheckEndOfDirective(IncludeTok.getIdentifierInfo()->getName(), true);
+
+ // Check that we don't have infinite #include recursion.
+ if (IncludeMacroStack.size() == MaxAllowedIncludeStackDepth-1) {
+ Diag(FilenameTok, diag::err_pp_include_too_deep);
+ return;
+ }
+
+ // Search include directories.
+ const DirectoryLookup *CurDir;
+ const FileEntry *File = LookupFile(FilenameStart, FilenameEnd,
+ isAngled, LookupFrom, CurDir);
+ if (File == 0) {
+ Diag(FilenameTok, diag::err_pp_file_not_found)
+ << std::string(FilenameStart, FilenameEnd);
+ return;
+ }
+
+ // Ask HeaderInfo if we should enter this #include file. If not, #including
+ // this file will have no effect.
+ if (!HeaderInfo.ShouldEnterIncludeFile(File, isImport))
+ return;
+
+ // The #included file will be considered to be a system header if either it is
+ // in a system include directory, or if the #includer is a system include
+ // header.
+ SrcMgr::CharacteristicKind FileCharacter =
+ std::max(HeaderInfo.getFileDirFlavor(File),
+ SourceMgr.getFileCharacteristic(FilenameTok.getLocation()));
+
+ // Look up the file, create a File ID for it.
+ FileID FID = SourceMgr.createFileID(File, FilenameTok.getLocation(),
+ FileCharacter);
+ if (FID.isInvalid()) {
+ Diag(FilenameTok, diag::err_pp_file_not_found)
+ << std::string(FilenameStart, FilenameEnd);
+ return;
+ }
+
+ // Finally, if all is good, enter the new file!
+ EnterSourceFile(FID, CurDir);
+}
+
+/// HandleIncludeNextDirective - Implements #include_next.
+///
+void Preprocessor::HandleIncludeNextDirective(Token &IncludeNextTok) {
+ Diag(IncludeNextTok, diag::ext_pp_include_next_directive);
+
+ // #include_next is like #include, except that we start searching after
+ // the current found directory. If we can't do this, issue a
+ // diagnostic.
+ const DirectoryLookup *Lookup = CurDirLookup;
+ if (isInPrimaryFile()) {
+ Lookup = 0;
+ Diag(IncludeNextTok, diag::pp_include_next_in_primary);
+ } else if (Lookup == 0) {
+ Diag(IncludeNextTok, diag::pp_include_next_absolute_path);
+ } else {
+ // Start looking up in the next directory.
+ ++Lookup;
+ }
+
+ return HandleIncludeDirective(IncludeNextTok, Lookup);
+}
+
+/// HandleImportDirective - Implements #import.
+///
+void Preprocessor::HandleImportDirective(Token &ImportTok) {
+ if (!Features.ObjC1) // #import is standard for ObjC.
+ Diag(ImportTok, diag::ext_pp_import_directive);
+
+ return HandleIncludeDirective(ImportTok, 0, true);
+}
+
+/// HandleIncludeMacrosDirective - The -imacros command line option turns into a
+/// pseudo directive in the predefines buffer. This handles it by sucking all
+/// tokens through the preprocessor and discarding them (only keeping the side
+/// effects on the preprocessor).
+void Preprocessor::HandleIncludeMacrosDirective(Token &IncludeMacrosTok) {
+ // This directive should only occur in the predefines buffer. If not, emit an
+ // error and reject it.
+ SourceLocation Loc = IncludeMacrosTok.getLocation();
+ if (strcmp(SourceMgr.getBufferName(Loc), "<built-in>") != 0) {
+ Diag(IncludeMacrosTok.getLocation(),
+ diag::pp_include_macros_out_of_predefines);
+ DiscardUntilEndOfDirective();
+ return;
+ }
+
+ // Treat this as a normal #include for checking purposes. If this is
+ // successful, it will push a new lexer onto the include stack.
+ HandleIncludeDirective(IncludeMacrosTok, 0, false);
+
+ Token TmpTok;
+ do {
+ Lex(TmpTok);
+ assert(TmpTok.isNot(tok::eof) && "Didn't find end of -imacros!");
+ } while (TmpTok.isNot(tok::hashhash));
+}
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Macro Directive Handling.
+//===----------------------------------------------------------------------===//
+
+/// ReadMacroDefinitionArgList - The ( starting an argument list of a macro
+/// definition has just been read. Lex the rest of the arguments and the
+/// 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;
+
+ Token Tok;
+ while (1) {
+ LexUnexpandedToken(Tok);
+ switch (Tok.getKind()) {
+ case tok::r_paren:
+ // Found the end of the argument list.
+ if (Arguments.empty()) // #define FOO()
+ return false;
+ // Otherwise we have #define FOO(A,)
+ 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);
+
+ // Lex the token after the identifier.
+ LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_pp_missing_rparen_in_macro_def);
+ return true;
+ }
+ // Add the __VA_ARGS__ identifier as an argument.
+ Arguments.push_back(Ident__VA_ARGS__);
+ MI->setIsC99Varargs();
+ MI->setArgumentList(&Arguments[0], Arguments.size(), BP);
+ return false;
+ case tok::eom: // #define X(
+ Diag(Tok, diag::err_pp_missing_rparen_in_macro_def);
+ return true;
+ default:
+ // Handle keywords and identifiers here to accept things like
+ // #define Foo(for) for.
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (II == 0) {
+ // #define X(1
+ Diag(Tok, diag::err_pp_invalid_tok_in_arg_list);
+ return true;
+ }
+
+ // If this is already used as an argument, it is used multiple times (e.g.
+ // #define X(A,A.
+ if (std::find(Arguments.begin(), Arguments.end(), II) !=
+ Arguments.end()) { // C99 6.10.3p6
+ Diag(Tok, diag::err_pp_duplicate_name_in_arg_list) << II;
+ return true;
+ }
+
+ // Add the argument to the macro info.
+ Arguments.push_back(II);
+
+ // Lex the token after the identifier.
+ LexUnexpandedToken(Tok);
+
+ switch (Tok.getKind()) {
+ default: // #define X(A B
+ Diag(Tok, diag::err_pp_expected_comma_in_arg_list);
+ return true;
+ case tok::r_paren: // #define X(A)
+ MI->setArgumentList(&Arguments[0], Arguments.size(), BP);
+ return false;
+ case tok::comma: // #define X(A,
+ break;
+ case tok::ellipsis: // #define X(A... -> GCC extension
+ // Diagnose extension.
+ Diag(Tok, diag::ext_named_variadic_macro);
+
+ // Lex the token after the identifier.
+ LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_pp_missing_rparen_in_macro_def);
+ return true;
+ }
+
+ MI->setIsGNUVarargs();
+ MI->setArgumentList(&Arguments[0], Arguments.size(), BP);
+ return false;
+ }
+ }
+ }
+}
+
+/// HandleDefineDirective - Implements #define. This consumes the entire macro
+/// line then lets the caller lex the next real token.
+void Preprocessor::HandleDefineDirective(Token &DefineTok) {
+ ++NumDefined;
+
+ Token MacroNameTok;
+ ReadMacroName(MacroNameTok, 1);
+
+ // Error reading macro name? If so, diagnostic already issued.
+ if (MacroNameTok.is(tok::eom))
+ return;
+
+ Token LastTok = MacroNameTok;
+
+ // If we are supposed to keep comments in #defines, reenable comment saving
+ // mode.
+ if (CurLexer) CurLexer->SetCommentRetentionState(KeepMacroComments);
+
+ // Create the new macro.
+ MacroInfo *MI = AllocateMacroInfo(MacroNameTok.getLocation());
+
+ Token Tok;
+ LexUnexpandedToken(Tok);
+
+ // If this is a function-like macro definition, parse the argument list,
+ // marking each of the identifiers as being used as macro arguments. Also,
+ // check other constraints on the first token of the macro body.
+ if (Tok.is(tok::eom)) {
+ // If there is no body to this macro, we have no special handling here.
+ } else if (Tok.hasLeadingSpace()) {
+ // This is a normal token with leading space. Clear the leading space
+ // marker on the first token to get proper expansion.
+ Tok.clearFlag(Token::LeadingSpace);
+ } else if (Tok.is(tok::l_paren)) {
+ // This is a function-like macro definition. Read the argument list.
+ MI->setIsFunctionLike();
+ if (ReadMacroDefinitionArgList(MI)) {
+ // Forget about MI.
+ ReleaseMacroInfo(MI);
+ // Throw away the rest of the line.
+ if (CurPPLexer->ParsingPreprocessorDirective)
+ DiscardUntilEndOfDirective();
+ return;
+ }
+
+ // If this is a definition of a variadic C99 function-like macro, not using
+ // the GNU named varargs extension, enabled __VA_ARGS__.
+
+ // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro.
+ // This gets unpoisoned where it is allowed.
+ assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned!");
+ if (MI->isC99Varargs())
+ Ident__VA_ARGS__->setIsPoisoned(false);
+
+ // Read the first token after the arg list for down below.
+ LexUnexpandedToken(Tok);
+ } else if (Features.C99) {
+ // 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);
+ } else {
+ // C90 6.8 TC1 says: "In the definition of an object-like macro, if the
+ // first character of a replacement list is not a character required by
+ // subclause 5.2.1, then there shall be white-space separation between the
+ // identifier and the replacement list.". 5.2.1 lists this set:
+ // "A-Za-z0-9!"#%&'()*+,_./:;<=>?[\]^_{|}~" as well as whitespace, which
+ // is irrelevant here.
+ bool isInvalid = false;
+ if (Tok.is(tok::at)) // @ is not in the list above.
+ isInvalid = true;
+ else if (Tok.is(tok::unknown)) {
+ // If we have an unknown token, it is something strange like "`". Since
+ // all of valid characters would have lexed into a single character
+ // token of some sort, we know this is not a valid case.
+ isInvalid = true;
+ }
+ if (isInvalid)
+ Diag(Tok, diag::ext_missing_whitespace_after_macro_name);
+ else
+ Diag(Tok, diag::warn_missing_whitespace_after_macro_name);
+ }
+
+ if (!Tok.is(tok::eom))
+ LastTok = Tok;
+
+ // Read the rest of the macro body.
+ if (MI->isObjectLike()) {
+ // Object-like macros are very simple, just read their body.
+ while (Tok.isNot(tok::eom)) {
+ LastTok = Tok;
+ MI->AddTokenToBody(Tok);
+ // Get the next token of the macro.
+ LexUnexpandedToken(Tok);
+ }
+
+ } else {
+ // Otherwise, read the body of a function-like macro. While we are at it,
+ // check C99 6.10.3.2p1: ensure that # operators are followed by macro
+ // parameters in function-like macro expansions.
+ while (Tok.isNot(tok::eom)) {
+ LastTok = Tok;
+
+ if (Tok.isNot(tok::hash)) {
+ MI->AddTokenToBody(Tok);
+
+ // Get the next token of the macro.
+ LexUnexpandedToken(Tok);
+ continue;
+ }
+
+ // Get the next token of the macro.
+ LexUnexpandedToken(Tok);
+
+ // Check for a valid macro arg identifier.
+ if (Tok.getIdentifierInfo() == 0 ||
+ MI->getArgumentNum(Tok.getIdentifierInfo()) == -1) {
+
+ // If this is assembler-with-cpp mode, we accept random gibberish after
+ // the '#' because '#' is often a comment character. However, change
+ // the kind of the token to tok::unknown so that the preprocessor isn't
+ // confused.
+ if (getLangOptions().AsmPreprocessor && Tok.isNot(tok::eom)) {
+ LastTok.setKind(tok::unknown);
+ } else {
+ Diag(Tok, diag::err_pp_stringize_not_parameter);
+ ReleaseMacroInfo(MI);
+
+ // Disable __VA_ARGS__ again.
+ Ident__VA_ARGS__->setIsPoisoned(true);
+ return;
+ }
+ }
+
+ // Things look ok, add the '#' and param name tokens to the macro.
+ MI->AddTokenToBody(LastTok);
+ MI->AddTokenToBody(Tok);
+ LastTok = Tok;
+
+ // Get the next token of the macro.
+ LexUnexpandedToken(Tok);
+ }
+ }
+
+
+ // Disable __VA_ARGS__ again.
+ Ident__VA_ARGS__->setIsPoisoned(true);
+
+ // Check that there is no paste (##) operator at the begining or end of the
+ // replacement list.
+ unsigned NumTokens = MI->getNumTokens();
+ if (NumTokens != 0) {
+ if (MI->getReplacementToken(0).is(tok::hashhash)) {
+ Diag(MI->getReplacementToken(0), diag::err_paste_at_start);
+ ReleaseMacroInfo(MI);
+ return;
+ }
+ if (MI->getReplacementToken(NumTokens-1).is(tok::hashhash)) {
+ Diag(MI->getReplacementToken(NumTokens-1), diag::err_paste_at_end);
+ ReleaseMacroInfo(MI);
+ return;
+ }
+ }
+
+ // If this is the primary source file, remember that this macro hasn't been
+ // used yet.
+ if (isInPrimaryFile())
+ MI->setIsUsed(false);
+
+ MI->setDefinitionEndLoc(LastTok.getLocation());
+
+ // Finally, if this identifier already had a macro defined for it, verify that
+ // the macro bodies are identical and free the old definition.
+ if (MacroInfo *OtherMI = getMacroInfo(MacroNameTok.getIdentifierInfo())) {
+ // It is very common for system headers to have tons of macro redefinitions
+ // and for warnings to be disabled in system headers. If this is the case,
+ // then don't bother calling MacroInfo::isIdenticalTo.
+ if (!getDiagnostics().getSuppressSystemWarnings() ||
+ !SourceMgr.isInSystemHeader(DefineTok.getLocation())) {
+ if (!OtherMI->isUsed())
+ Diag(OtherMI->getDefinitionLoc(), diag::pp_macro_not_used);
+
+ // Macros must be identical. This means all tokes and whitespace
+ // separation must be the same. C99 6.10.3.2.
+ if (!MI->isIdenticalTo(*OtherMI, *this)) {
+ Diag(MI->getDefinitionLoc(), diag::ext_pp_macro_redef)
+ << MacroNameTok.getIdentifierInfo();
+ Diag(OtherMI->getDefinitionLoc(), diag::note_previous_definition);
+ }
+ }
+
+ ReleaseMacroInfo(OtherMI);
+ }
+
+ setMacroInfo(MacroNameTok.getIdentifierInfo(), MI);
+
+ // If the callbacks want to know, tell them about the macro definition.
+ if (Callbacks)
+ Callbacks->MacroDefined(MacroNameTok.getIdentifierInfo(), MI);
+}
+
+/// HandleUndefDirective - Implements #undef.
+///
+void Preprocessor::HandleUndefDirective(Token &UndefTok) {
+ ++NumUndefined;
+
+ Token MacroNameTok;
+ ReadMacroName(MacroNameTok, 2);
+
+ // Error reading macro name? If so, diagnostic already issued.
+ if (MacroNameTok.is(tok::eom))
+ return;
+
+ // Check to see if this is the last token on the #undef line.
+ CheckEndOfDirective("undef");
+
+ // Okay, we finally have a valid identifier to undef.
+ MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo());
+
+ // If the macro is not defined, this is a noop undef, just return.
+ if (MI == 0) return;
+
+ if (!MI->isUsed())
+ Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used);
+
+ // If the callbacks want to know, tell them about the macro #undef.
+ if (Callbacks)
+ Callbacks->MacroUndefined(MacroNameTok.getIdentifierInfo(), MI);
+
+ // Free macro definition.
+ ReleaseMacroInfo(MI);
+ setMacroInfo(MacroNameTok.getIdentifierInfo(), 0);
+}
+
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Conditional Directive Handling.
+//===----------------------------------------------------------------------===//
+
+/// HandleIfdefDirective - Implements the #ifdef/#ifndef directive. isIfndef is
+/// true when this is a #ifndef directive. ReadAnyTokensBeforeDirective is true
+/// if any tokens have been returned or pp-directives activated before this
+/// #ifndef has been lexed.
+///
+void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
+ bool ReadAnyTokensBeforeDirective) {
+ ++NumIf;
+ Token DirectiveTok = Result;
+
+ Token MacroNameTok;
+ ReadMacroName(MacroNameTok);
+
+ // Error reading macro name? If so, diagnostic already issued.
+ if (MacroNameTok.is(tok::eom)) {
+ // Skip code until we get to #endif. This helps with recovery by not
+ // emitting an error when the #endif is reached.
+ SkipExcludedConditionalBlock(DirectiveTok.getLocation(),
+ /*Foundnonskip*/false, /*FoundElse*/false);
+ return;
+ }
+
+ // Check to see if this is the last token on the #if[n]def line.
+ CheckEndOfDirective(isIfndef ? "ifndef" : "ifdef");
+
+ if (CurPPLexer->getConditionalStackDepth() == 0) {
+ // If the start of a top-level #ifdef, inform MIOpt.
+ if (!ReadAnyTokensBeforeDirective) {
+ assert(isIfndef && "#ifdef shouldn't reach here");
+ CurPPLexer->MIOpt.EnterTopLevelIFNDEF(MacroNameTok.getIdentifierInfo());
+ } else
+ CurPPLexer->MIOpt.EnterTopLevelConditional();
+ }
+
+ IdentifierInfo *MII = MacroNameTok.getIdentifierInfo();
+ MacroInfo *MI = getMacroInfo(MII);
+
+ // If there is a macro, process it.
+ if (MI) // Mark it used.
+ MI->setIsUsed(true);
+
+ // Should we include the stuff contained by this directive?
+ if (!MI == isIfndef) {
+ // Yes, remember that we are inside a conditional, then lex the next token.
+ CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(), /*wasskip*/false,
+ /*foundnonskip*/true, /*foundelse*/false);
+ } else {
+ // No, skip the contents of this block and return the first token after it.
+ SkipExcludedConditionalBlock(DirectiveTok.getLocation(),
+ /*Foundnonskip*/false,
+ /*FoundElse*/false);
+ }
+}
+
+/// HandleIfDirective - Implements the #if directive.
+///
+void Preprocessor::HandleIfDirective(Token &IfToken,
+ bool ReadAnyTokensBeforeDirective) {
+ ++NumIf;
+
+ // Parse and evaluation the conditional expression.
+ IdentifierInfo *IfNDefMacro = 0;
+ bool ConditionalTrue = EvaluateDirectiveExpression(IfNDefMacro);
+
+
+ // If this condition is equivalent to #ifndef X, and if this is the first
+ // directive seen, handle it for the multiple-include optimization.
+ if (CurPPLexer->getConditionalStackDepth() == 0) {
+ if (!ReadAnyTokensBeforeDirective && IfNDefMacro)
+ CurPPLexer->MIOpt.EnterTopLevelIFNDEF(IfNDefMacro);
+ else
+ CurPPLexer->MIOpt.EnterTopLevelConditional();
+ }
+
+ // Should we include the stuff contained by this directive?
+ if (ConditionalTrue) {
+ // Yes, remember that we are inside a conditional, then lex the next token.
+ CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false,
+ /*foundnonskip*/true, /*foundelse*/false);
+ } else {
+ // No, skip the contents of this block and return the first token after it.
+ SkipExcludedConditionalBlock(IfToken.getLocation(), /*Foundnonskip*/false,
+ /*FoundElse*/false);
+ }
+}
+
+/// HandleEndifDirective - Implements the #endif directive.
+///
+void Preprocessor::HandleEndifDirective(Token &EndifToken) {
+ ++NumEndif;
+
+ // Check that this is the whole directive.
+ CheckEndOfDirective("endif");
+
+ PPConditionalInfo CondInfo;
+ if (CurPPLexer->popConditionalLevel(CondInfo)) {
+ // No conditionals on the stack: this is an #endif without an #if.
+ Diag(EndifToken, diag::err_pp_endif_without_if);
+ return;
+ }
+
+ // If this the end of a top-level #endif, inform MIOpt.
+ if (CurPPLexer->getConditionalStackDepth() == 0)
+ CurPPLexer->MIOpt.ExitTopLevelConditional();
+
+ assert(!CondInfo.WasSkipping && !CurPPLexer->LexingRawMode &&
+ "This code should only be reachable in the non-skipping case!");
+}
+
+
+void Preprocessor::HandleElseDirective(Token &Result) {
+ ++NumElse;
+
+ // #else directive in a non-skipping conditional... start skipping.
+ CheckEndOfDirective("else");
+
+ PPConditionalInfo CI;
+ if (CurPPLexer->popConditionalLevel(CI)) {
+ Diag(Result, diag::pp_err_else_without_if);
+ return;
+ }
+
+ // If this is a top-level #else, inform the MIOpt.
+ if (CurPPLexer->getConditionalStackDepth() == 0)
+ CurPPLexer->MIOpt.EnterTopLevelConditional();
+
+ // If this is a #else with a #else before it, report the error.
+ if (CI.FoundElse) Diag(Result, diag::pp_err_else_after_else);
+
+ // Finally, skip the rest of the contents of this block and return the first
+ // token after it.
+ return SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
+ /*FoundElse*/true);
+}
+
+void Preprocessor::HandleElifDirective(Token &ElifToken) {
+ ++NumElse;
+
+ // #elif directive in a non-skipping conditional... start skipping.
+ // We don't care what the condition is, because we will always skip it (since
+ // the block immediately before it was included).
+ DiscardUntilEndOfDirective();
+
+ PPConditionalInfo CI;
+ if (CurPPLexer->popConditionalLevel(CI)) {
+ Diag(ElifToken, diag::pp_err_elif_without_if);
+ return;
+ }
+
+ // If this is a top-level #elif, inform the MIOpt.
+ if (CurPPLexer->getConditionalStackDepth() == 0)
+ CurPPLexer->MIOpt.EnterTopLevelConditional();
+
+ // If this is a #elif with a #else before it, report the error.
+ if (CI.FoundElse) Diag(ElifToken, diag::pp_err_elif_after_else);
+
+ // Finally, skip the rest of the contents of this block and return the first
+ // token after it.
+ return SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
+ /*FoundElse*/CI.FoundElse);
+}
+
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
new file mode 100644
index 000000000000..709e316b8036
--- /dev/null
+++ b/lib/Lex/PPExpressions.cpp
@@ -0,0 +1,717 @@
+//===--- PPExpressions.cpp - Preprocessor Expression Evaluation -----------===//
+//
+// 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 Preprocessor::EvaluateDirectiveExpression method,
+// which parses and evaluates integer constant expressions for #if directives.
+//
+//===----------------------------------------------------------------------===//
+//
+// FIXME: implement testing for #assert's.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "llvm/ADT/APSInt.h"
+using namespace clang;
+
+/// PPValue - Represents the value of a subexpression of a preprocessor
+/// conditional and the source range covered by it.
+class PPValue {
+ SourceRange Range;
+public:
+ llvm::APSInt Val;
+
+ // Default ctor - Construct an 'invalid' PPValue.
+ PPValue(unsigned BitWidth) : Val(BitWidth) {}
+
+ unsigned getBitWidth() const { return Val.getBitWidth(); }
+ bool isUnsigned() const { return Val.isUnsigned(); }
+
+ const SourceRange &getRange() const { return Range; }
+
+ void setRange(SourceLocation L) { Range.setBegin(L); Range.setEnd(L); }
+ void setRange(SourceLocation B, SourceLocation E) {
+ Range.setBegin(B); Range.setEnd(E);
+ }
+ void setBegin(SourceLocation L) { Range.setBegin(L); }
+ void setEnd(SourceLocation L) { Range.setEnd(L); }
+};
+
+static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
+ Token &PeekTok, bool ValueLive,
+ Preprocessor &PP);
+
+/// DefinedTracker - This struct is used while parsing expressions to keep track
+/// of whether !defined(X) has been seen.
+///
+/// With this simple scheme, we handle the basic forms:
+/// !defined(X) and !defined X
+/// but we also trivially handle (silly) stuff like:
+/// !!!defined(X) and +!defined(X) and !+!+!defined(X) and !(defined(X)).
+struct DefinedTracker {
+ /// Each time a Value is evaluated, it returns information about whether the
+ /// parsed value is of the form defined(X), !defined(X) or is something else.
+ enum TrackerState {
+ DefinedMacro, // defined(X)
+ NotDefinedMacro, // !defined(X)
+ Unknown // Something else.
+ } State;
+ /// TheMacro - When the state is DefinedMacro or NotDefinedMacro, this
+ /// indicates the macro that was checked.
+ IdentifierInfo *TheMacro;
+};
+
+/// EvaluateValue - Evaluate the token PeekTok (and any others needed) and
+/// return the computed value in Result. Return true if there was an error
+/// parsing. This function also returns information about the form of the
+/// expression in DT. See above for information on what DT means.
+///
+/// If ValueLive is false, then this value is being evaluated in a context where
+/// the result is not used. As such, avoid diagnostics that relate to
+/// evaluation.
+static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
+ bool ValueLive, Preprocessor &PP) {
+ DT.State = DefinedTracker::Unknown;
+
+ // If this token's spelling is a pp-identifier, check to see if it is
+ // 'defined' or if it is a macro. Note that we check here because many
+ // keywords are pp-identifiers, so we can't check the kind.
+ if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) {
+ // If this identifier isn't 'defined' and it wasn't macro expanded, it turns
+ // into a simple 0, unless it is the C++ keyword "true", in which case it
+ // turns into "1".
+ if (!II->isStr("defined")) {
+ if (ValueLive)
+ PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II;
+ Result.Val = II->getTokenID() == tok::kw_true;
+ Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
+ Result.setRange(PeekTok.getLocation());
+ PP.LexNonComment(PeekTok);
+ return false;
+ }
+
+ // Handle "defined X" and "defined(X)".
+ Result.setBegin(PeekTok.getLocation());
+
+ // Get the next token, don't expand it.
+ PP.LexUnexpandedToken(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);
+ }
+
+ // If we don't have a pp-identifier now, this is an error.
+ if ((II = PeekTok.getIdentifierInfo()) == 0) {
+ PP.Diag(PeekTok, diag::err_pp_defined_requires_identifier);
+ return true;
+ }
+
+ // Otherwise, we got an identifier, is it defined to something?
+ Result.Val = II->hasMacroDefinition();
+ Result.Val.setIsUnsigned(false); // Result is signed intmax_t.
+
+ // If there is a macro, mark it used.
+ if (Result.Val != 0 && ValueLive) {
+ MacroInfo *Macro = PP.getMacroInfo(II);
+ Macro->setIsUsed(true);
+ }
+
+ // Consume identifier.
+ Result.setEnd(PeekTok.getLocation());
+ PP.LexNonComment(PeekTok);
+
+ // If we are in parens, ensure we have a trailing ).
+ if (LParenLoc.isValid()) {
+ if (PeekTok.isNot(tok::r_paren)) {
+ PP.Diag(PeekTok.getLocation(), diag::err_pp_missing_rparen);
+ PP.Diag(LParenLoc, diag::note_matching) << "(";
+ return true;
+ }
+ // Consume the ).
+ Result.setEnd(PeekTok.getLocation());
+ PP.LexNonComment(PeekTok);
+ }
+
+ // Success, remember that we saw defined(X).
+ DT.State = DefinedTracker::DefinedMacro;
+ DT.TheMacro = II;
+ return false;
+ }
+
+ switch (PeekTok.getKind()) {
+ default: // Non-value token.
+ PP.Diag(PeekTok, diag::err_pp_expr_bad_token_start_expr);
+ return true;
+ case tok::eom:
+ case tok::r_paren:
+ // If there is no expression, report and exit.
+ PP.Diag(PeekTok, diag::err_pp_expected_value_in_expr);
+ return true;
+ case tok::numeric_constant: {
+ llvm::SmallString<64> IntegerBuffer;
+ IntegerBuffer.resize(PeekTok.getLength());
+ const char *ThisTokBegin = &IntegerBuffer[0];
+ unsigned ActualLength = PP.getSpelling(PeekTok, ThisTokBegin);
+ NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
+ PeekTok.getLocation(), PP);
+ if (Literal.hadError)
+ return true; // a diagnostic was already reported.
+
+ if (Literal.isFloatingLiteral() || Literal.isImaginary) {
+ PP.Diag(PeekTok, diag::err_pp_illegal_floating_literal);
+ return true;
+ }
+ 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);
+
+ // Parse the integer literal into Result.
+ if (Literal.GetIntegerValue(Result.Val)) {
+ // Overflow parsing integer literal.
+ if (ValueLive) PP.Diag(PeekTok, diag::warn_integer_too_large);
+ Result.Val.setIsUnsigned(true);
+ } else {
+ // Set the signedness of the result to match whether there was a U suffix
+ // or not.
+ Result.Val.setIsUnsigned(Literal.isUnsigned);
+
+ // Detect overflow based on whether the value is signed. If signed
+ // and if the value is too large, emit a warning "integer constant is so
+ // large that it is unsigned" e.g. on 12345678901234567890 where intmax_t
+ // is 64-bits.
+ if (!Literal.isUnsigned && Result.Val.isNegative()) {
+ // Don't warn for a hex literal: 0x8000..0 shouldn't warn.
+ if (ValueLive && Literal.getRadix() != 16)
+ PP.Diag(PeekTok, diag::warn_integer_too_large_for_signed);
+ Result.Val.setIsUnsigned(true);
+ }
+ }
+
+ // Consume the token.
+ Result.setRange(PeekTok.getLocation());
+ PP.LexNonComment(PeekTok);
+ return false;
+ }
+ case tok::char_constant: { // 'x'
+ llvm::SmallString<32> CharBuffer;
+ CharBuffer.resize(PeekTok.getLength());
+ const char *ThisTokBegin = &CharBuffer[0];
+ unsigned ActualLength = PP.getSpelling(PeekTok, ThisTokBegin);
+ CharLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
+ PeekTok.getLocation(), PP);
+ if (Literal.hadError())
+ return true; // A diagnostic was already emitted.
+
+ // Character literals are always int or wchar_t, expand to intmax_t.
+ TargetInfo &TI = PP.getTargetInfo();
+ unsigned NumBits;
+ if (Literal.isMultiChar())
+ NumBits = TI.getIntWidth();
+ else
+ NumBits = TI.getCharWidth(Literal.isWide());
+
+ // Set the width.
+ llvm::APSInt Val(NumBits);
+ // Set the value.
+ Val = Literal.getValue();
+ // Set the signedness.
+ Val.setIsUnsigned(!TI.isCharSigned());
+
+ if (Result.Val.getBitWidth() > Val.getBitWidth()) {
+ Result.Val = Val.extend(Result.Val.getBitWidth());
+ } else {
+ assert(Result.Val.getBitWidth() == Val.getBitWidth() &&
+ "intmax_t smaller than char/wchar_t?");
+ Result.Val = Val;
+ }
+
+ // Consume the token.
+ Result.setRange(PeekTok.getLocation());
+ PP.LexNonComment(PeekTok);
+ return false;
+ }
+ case tok::l_paren: {
+ SourceLocation Start = PeekTok.getLocation();
+ PP.LexNonComment(PeekTok); // Eat the (.
+ // Parse the value and if there are any binary operators involved, parse
+ // them.
+ if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true;
+
+ // If this is a silly value like (X), which doesn't need parens, check for
+ // !(defined X).
+ if (PeekTok.is(tok::r_paren)) {
+ // Just use DT unmodified as our result.
+ } else {
+ // Otherwise, we have something like (x+y), and we consumed '(x'.
+ if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP))
+ return true;
+
+ if (PeekTok.isNot(tok::r_paren)) {
+ PP.Diag(PeekTok.getLocation(), diag::err_pp_expected_rparen)
+ << Result.getRange();
+ PP.Diag(Start, diag::note_matching) << "(";
+ return true;
+ }
+ DT.State = DefinedTracker::Unknown;
+ }
+ Result.setRange(Start, PeekTok.getLocation());
+ PP.LexNonComment(PeekTok); // Eat the ).
+ return false;
+ }
+ case tok::plus: {
+ SourceLocation Start = PeekTok.getLocation();
+ // Unary plus doesn't modify the value.
+ PP.LexNonComment(PeekTok);
+ if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true;
+ Result.setBegin(Start);
+ return false;
+ }
+ case tok::minus: {
+ SourceLocation Loc = PeekTok.getLocation();
+ PP.LexNonComment(PeekTok);
+ if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true;
+ Result.setBegin(Loc);
+
+ // C99 6.5.3.3p3: The sign of the result matches the sign of the operand.
+ Result.Val = -Result.Val;
+
+ // -MININT is the only thing that overflows. Unsigned never overflows.
+ bool Overflow = !Result.isUnsigned() && Result.Val.isMinSignedValue();
+
+ // If this operator is live and overflowed, report the issue.
+ if (Overflow && ValueLive)
+ PP.Diag(Loc, diag::warn_pp_expr_overflow) << Result.getRange();
+
+ DT.State = DefinedTracker::Unknown;
+ return false;
+ }
+
+ case tok::tilde: {
+ SourceLocation Start = PeekTok.getLocation();
+ PP.LexNonComment(PeekTok);
+ if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true;
+ Result.setBegin(Start);
+
+ // C99 6.5.3.3p4: The sign of the result matches the sign of the operand.
+ Result.Val = ~Result.Val;
+ DT.State = DefinedTracker::Unknown;
+ return false;
+ }
+
+ case tok::exclaim: {
+ SourceLocation Start = PeekTok.getLocation();
+ PP.LexNonComment(PeekTok);
+ if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true;
+ Result.setBegin(Start);
+ Result.Val = !Result.Val;
+ // C99 6.5.3.3p5: The sign of the result is 'int', aka it is signed.
+ Result.Val.setIsUnsigned(false);
+
+ if (DT.State == DefinedTracker::DefinedMacro)
+ DT.State = DefinedTracker::NotDefinedMacro;
+ else if (DT.State == DefinedTracker::NotDefinedMacro)
+ DT.State = DefinedTracker::DefinedMacro;
+ return false;
+ }
+
+ // FIXME: Handle #assert
+ }
+}
+
+
+
+/// getPrecedence - Return the precedence of the specified binary operator
+/// token. This returns:
+/// ~0 - Invalid token.
+/// 14 -> 3 - various operators.
+/// 0 - 'eom' or ')'
+static unsigned getPrecedence(tok::TokenKind Kind) {
+ switch (Kind) {
+ default: return ~0U;
+ case tok::percent:
+ case tok::slash:
+ case tok::star: return 14;
+ case tok::plus:
+ case tok::minus: return 13;
+ case tok::lessless:
+ case tok::greatergreater: return 12;
+ case tok::lessequal:
+ case tok::less:
+ case tok::greaterequal:
+ case tok::greater: return 11;
+ case tok::exclaimequal:
+ case tok::equalequal: return 10;
+ case tok::amp: return 9;
+ case tok::caret: return 8;
+ case tok::pipe: return 7;
+ case tok::ampamp: return 6;
+ case tok::pipepipe: return 5;
+ case tok::question: return 4;
+ case tok::comma: return 3;
+ case tok::colon: return 2;
+ case tok::r_paren: return 0; // Lowest priority, end of expr.
+ case tok::eom: return 0; // Lowest priority, end of macro.
+ }
+}
+
+
+/// EvaluateDirectiveSubExpr - Evaluate the subexpression whose first token is
+/// PeekTok, and whose precedence is PeekPrec. This returns the result in LHS.
+///
+/// If ValueLive is false, then this value is being evaluated in a context where
+/// the result is not used. As such, avoid diagnostics that relate to
+/// evaluation, such as division by zero warnings.
+static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
+ Token &PeekTok, bool ValueLive,
+ Preprocessor &PP) {
+ unsigned PeekPrec = getPrecedence(PeekTok.getKind());
+ // If this token isn't valid, report the error.
+ if (PeekPrec == ~0U) {
+ PP.Diag(PeekTok.getLocation(), diag::err_pp_expr_bad_token_binop)
+ << LHS.getRange();
+ return true;
+ }
+
+ while (1) {
+ // If this token has a lower precedence than we are allowed to parse, return
+ // it so that higher levels of the recursion can parse it.
+ if (PeekPrec < MinPrec)
+ return false;
+
+ tok::TokenKind Operator = PeekTok.getKind();
+
+ // If this is a short-circuiting operator, see if the RHS of the operator is
+ // dead. Note that this cannot just clobber ValueLive. Consider
+ // "0 && 1 ? 4 : 1 / 0", which is parsed as "(0 && 1) ? 4 : (1 / 0)". In
+ // this example, the RHS of the && being dead does not make the rest of the
+ // expr dead.
+ bool RHSIsLive;
+ if (Operator == tok::ampamp && LHS.Val == 0)
+ RHSIsLive = false; // RHS of "0 && x" is dead.
+ else if (Operator == tok::pipepipe && LHS.Val != 0)
+ RHSIsLive = false; // RHS of "1 || x" is dead.
+ else if (Operator == tok::question && LHS.Val == 0)
+ RHSIsLive = false; // RHS (x) of "0 ? x : y" is dead.
+ else
+ RHSIsLive = ValueLive;
+
+ // Consume the operator, remembering the operator's location for reporting.
+ SourceLocation OpLoc = PeekTok.getLocation();
+ PP.LexNonComment(PeekTok);
+
+ PPValue RHS(LHS.getBitWidth());
+ // Parse the RHS of the operator.
+ DefinedTracker DT;
+ if (EvaluateValue(RHS, PeekTok, DT, RHSIsLive, PP)) return true;
+
+ // Remember the precedence of this operator and get the precedence of the
+ // operator immediately to the right of the RHS.
+ unsigned ThisPrec = PeekPrec;
+ PeekPrec = getPrecedence(PeekTok.getKind());
+
+ // If this token isn't valid, report the error.
+ if (PeekPrec == ~0U) {
+ PP.Diag(PeekTok.getLocation(), diag::err_pp_expr_bad_token_binop)
+ << RHS.getRange();
+ return true;
+ }
+
+ // Decide whether to include the next binop in this subexpression. For
+ // example, when parsing x+y*z and looking at '*', we want to recursively
+ // handle y*z as a single subexpression. We do this because the precedence
+ // of * is higher than that of +. The only strange case we have to handle
+ // here is for the ?: operator, where the precedence is actually lower than
+ // the LHS of the '?'. The grammar rule is:
+ //
+ // conditional-expression ::=
+ // logical-OR-expression ? expression : conditional-expression
+ // where 'expression' is actually comma-expression.
+ unsigned RHSPrec;
+ if (Operator == tok::question)
+ // The RHS of "?" should be maximally consumed as an expression.
+ RHSPrec = getPrecedence(tok::comma);
+ else // All others should munch while higher precedence.
+ RHSPrec = ThisPrec+1;
+
+ if (PeekPrec >= RHSPrec) {
+ if (EvaluateDirectiveSubExpr(RHS, RHSPrec, PeekTok, RHSIsLive, PP))
+ return true;
+ PeekPrec = getPrecedence(PeekTok.getKind());
+ }
+ assert(PeekPrec <= ThisPrec && "Recursion didn't work!");
+
+ // Usual arithmetic conversions (C99 6.3.1.8p1): result is unsigned if
+ // either operand is unsigned.
+ llvm::APSInt Res(LHS.getBitWidth());
+ switch (Operator) {
+ case tok::question: // No UAC for x and y in "x ? y : z".
+ case tok::lessless: // Shift amount doesn't UAC with shift value.
+ case tok::greatergreater: // Shift amount doesn't UAC with shift value.
+ case tok::comma: // Comma operands are not subject to UACs.
+ case tok::pipepipe: // Logical || does not do UACs.
+ case tok::ampamp: // Logical && does not do UACs.
+ break; // No UAC
+ default:
+ Res.setIsUnsigned(LHS.isUnsigned()|RHS.isUnsigned());
+ // If this just promoted something from signed to unsigned, and if the
+ // value was negative, warn about it.
+ if (ValueLive && Res.isUnsigned()) {
+ if (!LHS.isUnsigned() && LHS.Val.isNegative())
+ PP.Diag(OpLoc, diag::warn_pp_convert_lhs_to_positive)
+ << LHS.Val.toString(10, true) + " to " +
+ LHS.Val.toString(10, false)
+ << LHS.getRange() << RHS.getRange();
+ if (!RHS.isUnsigned() && RHS.Val.isNegative())
+ PP.Diag(OpLoc, diag::warn_pp_convert_rhs_to_positive)
+ << RHS.Val.toString(10, true) + " to " +
+ RHS.Val.toString(10, false)
+ << LHS.getRange() << RHS.getRange();
+ }
+ LHS.Val.setIsUnsigned(Res.isUnsigned());
+ RHS.Val.setIsUnsigned(Res.isUnsigned());
+ }
+
+ // FIXME: All of these should detect and report overflow??
+ bool Overflow = false;
+ switch (Operator) {
+ default: assert(0 && "Unknown operator token!");
+ case tok::percent:
+ if (RHS.Val != 0)
+ Res = LHS.Val % RHS.Val;
+ else if (ValueLive) {
+ PP.Diag(OpLoc, diag::err_pp_remainder_by_zero)
+ << LHS.getRange() << RHS.getRange();
+ return true;
+ }
+ break;
+ case tok::slash:
+ if (RHS.Val != 0) {
+ Res = LHS.Val / RHS.Val;
+ if (LHS.Val.isSigned()) // MININT/-1 --> overflow.
+ Overflow = LHS.Val.isMinSignedValue() && RHS.Val.isAllOnesValue();
+ } else if (ValueLive) {
+ PP.Diag(OpLoc, diag::err_pp_division_by_zero)
+ << LHS.getRange() << RHS.getRange();
+ return true;
+ }
+ break;
+
+ case tok::star:
+ Res = LHS.Val * RHS.Val;
+ if (Res.isSigned() && LHS.Val != 0 && RHS.Val != 0)
+ Overflow = Res/RHS.Val != LHS.Val || Res/LHS.Val != RHS.Val;
+ break;
+ case tok::lessless: {
+ // Determine whether overflow is about to happen.
+ unsigned ShAmt = static_cast<unsigned>(RHS.Val.getLimitedValue());
+ if (ShAmt >= LHS.Val.getBitWidth())
+ Overflow = true, ShAmt = LHS.Val.getBitWidth()-1;
+ else if (LHS.isUnsigned())
+ Overflow = false;
+ else if (LHS.Val.isNonNegative()) // Don't allow sign change.
+ Overflow = ShAmt >= LHS.Val.countLeadingZeros();
+ else
+ Overflow = ShAmt >= LHS.Val.countLeadingOnes();
+
+ Res = LHS.Val << ShAmt;
+ break;
+ }
+ case tok::greatergreater: {
+ // Determine whether overflow is about to happen.
+ unsigned ShAmt = static_cast<unsigned>(RHS.Val.getLimitedValue());
+ if (ShAmt >= LHS.getBitWidth())
+ Overflow = true, ShAmt = LHS.getBitWidth()-1;
+ Res = LHS.Val >> ShAmt;
+ break;
+ }
+ case tok::plus:
+ Res = LHS.Val + RHS.Val;
+ if (LHS.isUnsigned())
+ Overflow = false;
+ else if (LHS.Val.isNonNegative() == RHS.Val.isNonNegative() &&
+ Res.isNonNegative() != LHS.Val.isNonNegative())
+ Overflow = true; // Overflow for signed addition.
+ break;
+ case tok::minus:
+ Res = LHS.Val - RHS.Val;
+ if (LHS.isUnsigned())
+ Overflow = false;
+ else if (LHS.Val.isNonNegative() != RHS.Val.isNonNegative() &&
+ Res.isNonNegative() != LHS.Val.isNonNegative())
+ Overflow = true; // Overflow for signed subtraction.
+ break;
+ case tok::lessequal:
+ Res = LHS.Val <= RHS.Val;
+ Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed)
+ break;
+ case tok::less:
+ Res = LHS.Val < RHS.Val;
+ Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed)
+ break;
+ case tok::greaterequal:
+ Res = LHS.Val >= RHS.Val;
+ Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed)
+ break;
+ case tok::greater:
+ Res = LHS.Val > RHS.Val;
+ Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed)
+ break;
+ case tok::exclaimequal:
+ Res = LHS.Val != RHS.Val;
+ Res.setIsUnsigned(false); // C99 6.5.9p3, result is always int (signed)
+ break;
+ case tok::equalequal:
+ Res = LHS.Val == RHS.Val;
+ Res.setIsUnsigned(false); // C99 6.5.9p3, result is always int (signed)
+ break;
+ case tok::amp:
+ Res = LHS.Val & RHS.Val;
+ break;
+ case tok::caret:
+ Res = LHS.Val ^ RHS.Val;
+ break;
+ case tok::pipe:
+ Res = LHS.Val | RHS.Val;
+ break;
+ case tok::ampamp:
+ Res = (LHS.Val != 0 && RHS.Val != 0);
+ Res.setIsUnsigned(false); // C99 6.5.13p3, result is always int (signed)
+ break;
+ case tok::pipepipe:
+ Res = (LHS.Val != 0 || RHS.Val != 0);
+ Res.setIsUnsigned(false); // C99 6.5.14p3, result is always int (signed)
+ break;
+ case tok::comma:
+ // Comma is invalid in pp expressions in c89/c++ mode, but is valid in C99
+ // if not being evaluated.
+ if (!PP.getLangOptions().C99 || ValueLive)
+ PP.Diag(OpLoc, diag::ext_pp_comma_expr)
+ << LHS.getRange() << RHS.getRange();
+ Res = RHS.Val; // LHS = LHS,RHS -> RHS.
+ break;
+ case tok::question: {
+ // Parse the : part of the expression.
+ if (PeekTok.isNot(tok::colon)) {
+ PP.Diag(PeekTok.getLocation(), diag::err_expected_colon)
+ << LHS.getRange(), RHS.getRange();
+ PP.Diag(OpLoc, diag::note_matching) << "?";
+ return true;
+ }
+ // Consume the :.
+ PP.LexNonComment(PeekTok);
+
+ // Evaluate the value after the :.
+ bool AfterColonLive = ValueLive && LHS.Val == 0;
+ PPValue AfterColonVal(LHS.getBitWidth());
+ DefinedTracker DT;
+ if (EvaluateValue(AfterColonVal, PeekTok, DT, AfterColonLive, PP))
+ return true;
+
+ // Parse anything after the : with the same precedence as ?. We allow
+ // things of equal precedence because ?: is right associative.
+ if (EvaluateDirectiveSubExpr(AfterColonVal, ThisPrec,
+ PeekTok, AfterColonLive, PP))
+ return true;
+
+ // Now that we have the condition, the LHS and the RHS of the :, evaluate.
+ Res = LHS.Val != 0 ? RHS.Val : AfterColonVal.Val;
+ RHS.setEnd(AfterColonVal.getRange().getEnd());
+
+ // Usual arithmetic conversions (C99 6.3.1.8p1): result is unsigned if
+ // either operand is unsigned.
+ Res.setIsUnsigned(RHS.isUnsigned() | AfterColonVal.isUnsigned());
+
+ // Figure out the precedence of the token after the : part.
+ PeekPrec = getPrecedence(PeekTok.getKind());
+ break;
+ }
+ case tok::colon:
+ // Don't allow :'s to float around without being part of ?: exprs.
+ PP.Diag(OpLoc, diag::err_pp_colon_without_question)
+ << LHS.getRange() << RHS.getRange();
+ return true;
+ }
+
+ // If this operator is live and overflowed, report the issue.
+ if (Overflow && ValueLive)
+ PP.Diag(OpLoc, diag::warn_pp_expr_overflow)
+ << LHS.getRange() << RHS.getRange();
+
+ // Put the result back into 'LHS' for our next iteration.
+ LHS.Val = Res;
+ LHS.setEnd(RHS.getRange().getEnd());
+ }
+
+ return false;
+}
+
+/// EvaluateDirectiveExpression - Evaluate an integer constant expression that
+/// may occur after a #if or #elif directive. If the expression is equivalent
+/// to "!defined(X)" return X in IfNDefMacro.
+bool Preprocessor::
+EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
+ // Peek ahead one token.
+ Token Tok;
+ Lex(Tok);
+
+ // C99 6.10.1p3 - All expressions are evaluated as intmax_t or uintmax_t.
+ unsigned BitWidth = getTargetInfo().getIntMaxTWidth();
+
+ PPValue ResVal(BitWidth);
+ DefinedTracker DT;
+ if (EvaluateValue(ResVal, Tok, DT, true, *this)) {
+ // Parse error, skip the rest of the macro line.
+ if (Tok.isNot(tok::eom))
+ DiscardUntilEndOfDirective();
+ return false;
+ }
+
+ // If we are at the end of the expression after just parsing a value, there
+ // must be no (unparenthesized) binary operators involved, so we can exit
+ // directly.
+ if (Tok.is(tok::eom)) {
+ // If the expression we parsed was of the form !defined(macro), return the
+ // macro in IfNDefMacro.
+ if (DT.State == DefinedTracker::NotDefinedMacro)
+ IfNDefMacro = DT.TheMacro;
+
+ return ResVal.Val != 0;
+ }
+
+ // Otherwise, we must have a binary operator (e.g. "#if 1 < 2"), so parse the
+ // operator and the stuff after it.
+ if (EvaluateDirectiveSubExpr(ResVal, getPrecedence(tok::question),
+ Tok, true, *this)) {
+ // Parse error, skip the rest of the macro line.
+ if (Tok.isNot(tok::eom))
+ DiscardUntilEndOfDirective();
+ return false;
+ }
+
+ // If we aren't at the tok::eom token, something bad happened, like an extra
+ // ')' token.
+ if (Tok.isNot(tok::eom)) {
+ Diag(Tok, diag::err_pp_expected_eol);
+ DiscardUntilEndOfDirective();
+ }
+
+ return ResVal.Val != 0;
+}
+
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
new file mode 100644
index 000000000000..2a05ba336fca
--- /dev/null
+++ b/lib/Lex/PPLexerChange.cpp
@@ -0,0 +1,345 @@
+//===--- PPLexerChange.cpp - Handle changing lexers in the preprocessor ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements pieces of the Preprocessor interface that manage the
+// current lexer stack.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/MemoryBuffer.h"
+using namespace clang;
+
+PPCallbacks::~PPCallbacks() {}
+
+//===----------------------------------------------------------------------===//
+// Miscellaneous Methods.
+//===----------------------------------------------------------------------===//
+
+/// isInPrimaryFile - Return true if we're in the top-level file, not in a
+/// #include. This looks through macro expansions and active _Pragma lexers.
+bool Preprocessor::isInPrimaryFile() const {
+ if (IsFileLexer())
+ return IncludeMacroStack.empty();
+
+ // If there are any stacked lexers, we're in a #include.
+ assert(IsFileLexer(IncludeMacroStack[0]) &&
+ "Top level include stack isn't our primary lexer?");
+ for (unsigned i = 1, e = IncludeMacroStack.size(); i != e; ++i)
+ if (IsFileLexer(IncludeMacroStack[i]))
+ return false;
+ return true;
+}
+
+/// getCurrentLexer - Return the current file lexer being lexed from. Note
+/// that this ignores any potentially active macro expansions and _Pragma
+/// expansions going on at the time.
+PreprocessorLexer *Preprocessor::getCurrentFileLexer() const {
+ if (IsFileLexer())
+ return CurPPLexer;
+
+ // Look for a stacked lexer.
+ for (unsigned i = IncludeMacroStack.size(); i != 0; --i) {
+ const IncludeStackInfo& ISI = IncludeMacroStack[i-1];
+ if (IsFileLexer(ISI))
+ return ISI.ThePPLexer;
+ }
+ return 0;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Methods for Entering and Callbacks for leaving various contexts
+//===----------------------------------------------------------------------===//
+
+/// EnterSourceFile - Add a source file to the top of the include stack and
+/// start lexing tokens from it instead of the current buffer. Return true
+/// on failure.
+void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir) {
+ assert(CurTokenLexer == 0 && "Cannot #include a file inside a macro!");
+ ++NumEnteredSourceFiles;
+
+ if (MaxIncludeStackDepth < IncludeMacroStack.size())
+ MaxIncludeStackDepth = IncludeMacroStack.size();
+
+ if (PTH) {
+ if (PTHLexer *PL = PTH->CreateLexer(FID))
+ return EnterSourceFileWithPTH(PL, CurDir);
+ }
+ EnterSourceFileWithLexer(new Lexer(FID, *this), CurDir);
+}
+
+/// EnterSourceFileWithLexer - Add a source file to the top of the include stack
+/// and start lexing tokens from it instead of the current buffer.
+void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer,
+ const DirectoryLookup *CurDir) {
+
+ // Add the current lexer to the include stack.
+ if (CurPPLexer || CurTokenLexer)
+ PushIncludeMacroStack();
+
+ CurLexer.reset(TheLexer);
+ CurPPLexer = TheLexer;
+ CurDirLookup = CurDir;
+
+ // Notify the client, if desired, that we are in a new source file.
+ if (Callbacks && !CurLexer->Is_PragmaLexer) {
+ SrcMgr::CharacteristicKind FileType =
+ SourceMgr.getFileCharacteristic(CurLexer->getFileLoc());
+
+ Callbacks->FileChanged(CurLexer->getFileLoc(),
+ PPCallbacks::EnterFile, FileType);
+ }
+}
+
+/// EnterSourceFileWithPTH - Add a source file to the top of the include stack
+/// and start getting tokens from it using the PTH cache.
+void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL,
+ const DirectoryLookup *CurDir) {
+
+ if (CurPPLexer || CurTokenLexer)
+ PushIncludeMacroStack();
+
+ CurDirLookup = CurDir;
+ CurPTHLexer.reset(PL);
+ CurPPLexer = CurPTHLexer.get();
+
+ // Notify the client, if desired, that we are in a new source file.
+ if (Callbacks) {
+ FileID FID = CurPPLexer->getFileID();
+ SourceLocation EnterLoc = SourceMgr.getLocForStartOfFile(FID);
+ SrcMgr::CharacteristicKind FileType =
+ SourceMgr.getFileCharacteristic(EnterLoc);
+ Callbacks->FileChanged(EnterLoc, PPCallbacks::EnterFile, FileType);
+ }
+}
+
+/// EnterMacro - Add a Macro to the top of the include stack and start lexing
+/// tokens from it instead of the current buffer.
+void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd,
+ MacroArgs *Args) {
+ PushIncludeMacroStack();
+ CurDirLookup = 0;
+
+ if (NumCachedTokenLexers == 0) {
+ CurTokenLexer.reset(new TokenLexer(Tok, ILEnd, Args, *this));
+ } else {
+ CurTokenLexer.reset(TokenLexerCache[--NumCachedTokenLexers]);
+ CurTokenLexer->Init(Tok, ILEnd, Args);
+ }
+}
+
+/// EnterTokenStream - Add a "macro" context to the top of the include stack,
+/// which will cause the lexer to start returning the specified tokens.
+///
+/// If DisableMacroExpansion is true, tokens lexed from the token stream will
+/// not be subject to further macro expansion. Otherwise, these tokens will
+/// be re-macro-expanded when/if expansion is enabled.
+///
+/// If OwnsTokens is false, this method assumes that the specified stream of
+/// tokens has a permanent owner somewhere, so they do not need to be copied.
+/// If it is true, it assumes the array of tokens is allocated with new[] and
+/// must be freed.
+///
+void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks,
+ bool DisableMacroExpansion,
+ bool OwnsTokens) {
+ // Save our current state.
+ PushIncludeMacroStack();
+ CurDirLookup = 0;
+
+ // Create a macro expander to expand from the specified token stream.
+ if (NumCachedTokenLexers == 0) {
+ CurTokenLexer.reset(new TokenLexer(Toks, NumToks, DisableMacroExpansion,
+ OwnsTokens, *this));
+ } else {
+ CurTokenLexer.reset(TokenLexerCache[--NumCachedTokenLexers]);
+ CurTokenLexer->Init(Toks, NumToks, DisableMacroExpansion, OwnsTokens);
+ }
+}
+
+/// HandleEndOfFile - This callback is invoked when the lexer hits the end of
+/// the current file. This either returns the EOF token or pops a level off
+/// the include stack and keeps going.
+bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
+ assert(!CurTokenLexer &&
+ "Ending a file when currently in a macro!");
+
+ // See if this file had a controlling macro.
+ if (CurPPLexer) { // Not ending a macro, ignore it.
+ if (const IdentifierInfo *ControllingMacro =
+ CurPPLexer->MIOpt.GetControllingMacroAtEndOfFile()) {
+ // Okay, this has a controlling macro, remember in HeaderFileInfo.
+ if (const FileEntry *FE =
+ SourceMgr.getFileEntryForID(CurPPLexer->getFileID()))
+ HeaderInfo.SetFileControllingMacro(FE, ControllingMacro);
+ }
+ }
+
+ // If this is a #include'd file, pop it off the include stack and continue
+ // lexing the #includer file.
+ if (!IncludeMacroStack.empty()) {
+ // We're done with the #included file.
+ RemoveTopOfLexerStack();
+
+ // Notify the client, if desired, that we are in a new source file.
+ if (Callbacks && !isEndOfMacro && CurPPLexer) {
+ SrcMgr::CharacteristicKind FileType =
+ SourceMgr.getFileCharacteristic(CurPPLexer->getSourceLocation());
+ Callbacks->FileChanged(CurPPLexer->getSourceLocation(),
+ PPCallbacks::ExitFile, FileType);
+ }
+
+ // Client should lex another token.
+ return false;
+ }
+
+ // If the file ends with a newline, form the EOF token on the newline itself,
+ // rather than "on the line following it", which doesn't exist. This makes
+ // diagnostics relating to the end of file include the last file that the user
+ // actually typed, which is goodness.
+ if (CurLexer) {
+ const char *EndPos = CurLexer->BufferEnd;
+ if (EndPos != CurLexer->BufferStart &&
+ (EndPos[-1] == '\n' || EndPos[-1] == '\r')) {
+ --EndPos;
+
+ // Handle \n\r and \r\n:
+ if (EndPos != CurLexer->BufferStart &&
+ (EndPos[-1] == '\n' || EndPos[-1] == '\r') &&
+ EndPos[-1] != EndPos[0])
+ --EndPos;
+ }
+
+ Result.startToken();
+ CurLexer->BufferPtr = EndPos;
+ CurLexer->FormTokenWithChars(Result, EndPos, tok::eof);
+
+ // We're done with the #included file.
+ CurLexer.reset();
+ } else {
+ assert(CurPTHLexer && "Got EOF but no current lexer set!");
+ CurPTHLexer->getEOF(Result);
+ CurPTHLexer.reset();
+ }
+
+ CurPPLexer = 0;
+
+ // This is the end of the top-level file. If the diag::pp_macro_not_used
+ // diagnostic is enabled, look for macros that have not been used.
+ if (getDiagnostics().getDiagnosticLevel(diag::pp_macro_not_used) !=
+ Diagnostic::Ignored) {
+ for (macro_iterator I = macro_begin(), E = macro_end(); I != E; ++I)
+ if (!I->second->isUsed())
+ Diag(I->second->getDefinitionLoc(), diag::pp_macro_not_used);
+ }
+ return true;
+}
+
+/// HandleEndOfTokenLexer - This callback is invoked when the current TokenLexer
+/// hits the end of its token stream.
+bool Preprocessor::HandleEndOfTokenLexer(Token &Result) {
+ assert(CurTokenLexer && !CurPPLexer &&
+ "Ending a macro when currently in a #include file!");
+
+ // Delete or cache the now-dead macro expander.
+ if (NumCachedTokenLexers == TokenLexerCacheSize)
+ CurTokenLexer.reset();
+ else
+ TokenLexerCache[NumCachedTokenLexers++] = CurTokenLexer.take();
+
+ // Handle this like a #include file being popped off the stack.
+ return HandleEndOfFile(Result, true);
+}
+
+/// RemoveTopOfLexerStack - Pop the current lexer/macro exp off the top of the
+/// lexer stack. This should only be used in situations where the current
+/// state of the top-of-stack lexer is unknown.
+void Preprocessor::RemoveTopOfLexerStack() {
+ assert(!IncludeMacroStack.empty() && "Ran out of stack entries to load");
+
+ if (CurTokenLexer) {
+ // Delete or cache the now-dead macro expander.
+ if (NumCachedTokenLexers == TokenLexerCacheSize)
+ CurTokenLexer.reset();
+ else
+ TokenLexerCache[NumCachedTokenLexers++] = CurTokenLexer.take();
+ }
+
+ PopIncludeMacroStack();
+}
+
+/// HandleMicrosoftCommentPaste - When the macro expander pastes together a
+/// comment (/##/) in microsoft mode, this method handles updating the current
+/// state, returning the token on the next source line.
+void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) {
+ assert(CurTokenLexer && !CurPPLexer &&
+ "Pasted comment can only be formed from macro");
+
+ // We handle this by scanning for the closest real lexer, switching it to
+ // raw mode and preprocessor mode. This will cause it to return \n as an
+ // explicit EOM token.
+ PreprocessorLexer *FoundLexer = 0;
+ bool LexerWasInPPMode = false;
+ for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) {
+ IncludeStackInfo &ISI = *(IncludeMacroStack.end()-i-1);
+ if (ISI.ThePPLexer == 0) continue; // Scan for a real lexer.
+
+ // Once we find a real lexer, mark it as raw mode (disabling macro
+ // expansions) and preprocessor mode (return EOM). We know that the lexer
+ // was *not* in raw mode before, because the macro that the comment came
+ // from was expanded. However, it could have already been in preprocessor
+ // mode (#if COMMENT) in which case we have to return it to that mode and
+ // return EOM.
+ FoundLexer = ISI.ThePPLexer;
+ FoundLexer->LexingRawMode = true;
+ LexerWasInPPMode = FoundLexer->ParsingPreprocessorDirective;
+ FoundLexer->ParsingPreprocessorDirective = true;
+ break;
+ }
+
+ // Okay, we either found and switched over the lexer, or we didn't find a
+ // lexer. In either case, finish off the macro the comment came from, getting
+ // the next token.
+ if (!HandleEndOfTokenLexer(Tok)) Lex(Tok);
+
+ // Discarding comments as long as we don't have EOF or EOM. This 'comments
+ // out' the rest of the line, including any tokens that came from other macros
+ // that were active, as in:
+ // #define submacro a COMMENT b
+ // submacro c
+ // which should lex to 'a' only: 'b' and 'c' should be removed.
+ while (Tok.isNot(tok::eom) && Tok.isNot(tok::eof))
+ Lex(Tok);
+
+ // If we got an eom token, then we successfully found the end of the line.
+ if (Tok.is(tok::eom)) {
+ assert(FoundLexer && "Can't get end of line without an active lexer");
+ // Restore the lexer back to normal mode instead of raw mode.
+ FoundLexer->LexingRawMode = false;
+
+ // If the lexer was already in preprocessor mode, just return the EOM token
+ // to finish the preprocessor line.
+ if (LexerWasInPPMode) return;
+
+ // Otherwise, switch out of PP mode and return the next lexed token.
+ FoundLexer->ParsingPreprocessorDirective = false;
+ return Lex(Tok);
+ }
+
+ // If we got an EOF token, then we reached the end of the token stream but
+ // didn't find an explicit \n. This can only happen if there was no lexer
+ // active (an active lexer would return EOM at EOF if there was no \n in
+ // preprocessor directive mode), so just return EOF as our token.
+ assert(!FoundLexer && "Lexer should return EOM before EOF in PP mode");
+}
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
new file mode 100644
index 000000000000..55222c944a2b
--- /dev/null
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -0,0 +1,605 @@
+//===--- MacroExpansion.cpp - Top level Macro Expansion -------------------===//
+//
+// 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 top level handling of macro expasion for the
+// preprocessor.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Preprocessor.h"
+#include "MacroArgs.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include <cstdio>
+#include <ctime>
+using namespace clang;
+
+/// setMacroInfo - Specify a macro for this identifier.
+///
+void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI) {
+ if (MI) {
+ Macros[II] = MI;
+ II->setHasMacroDefinition(true);
+ } else if (II->hasMacroDefinition()) {
+ Macros.erase(II);
+ II->setHasMacroDefinition(false);
+ }
+}
+
+/// RegisterBuiltinMacro - Register the specified identifier in the identifier
+/// table and mark it as a builtin macro to be expanded.
+IdentifierInfo *Preprocessor::RegisterBuiltinMacro(const char *Name) {
+ // Get the identifier.
+ IdentifierInfo *Id = getIdentifierInfo(Name);
+
+ // Mark it as being a macro that is builtin.
+ MacroInfo *MI = AllocateMacroInfo(SourceLocation());
+ MI->setIsBuiltinMacro();
+ setMacroInfo(Id, MI);
+ return Id;
+}
+
+
+/// RegisterBuiltinMacros - Register builtin macros, such as __LINE__ with the
+/// identifier table.
+void Preprocessor::RegisterBuiltinMacros() {
+ Ident__LINE__ = RegisterBuiltinMacro("__LINE__");
+ Ident__FILE__ = RegisterBuiltinMacro("__FILE__");
+ Ident__DATE__ = RegisterBuiltinMacro("__DATE__");
+ Ident__TIME__ = RegisterBuiltinMacro("__TIME__");
+ Ident__COUNTER__ = RegisterBuiltinMacro("__COUNTER__");
+ Ident_Pragma = RegisterBuiltinMacro("_Pragma");
+
+ // GCC Extensions.
+ Ident__BASE_FILE__ = RegisterBuiltinMacro("__BASE_FILE__");
+ Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro("__INCLUDE_LEVEL__");
+ Ident__TIMESTAMP__ = RegisterBuiltinMacro("__TIMESTAMP__");
+}
+
+/// isTrivialSingleTokenExpansion - Return true if MI, which has a single token
+/// in its expansion, currently expands to that token literally.
+static bool isTrivialSingleTokenExpansion(const MacroInfo *MI,
+ const IdentifierInfo *MacroIdent,
+ Preprocessor &PP) {
+ IdentifierInfo *II = MI->getReplacementToken(0).getIdentifierInfo();
+
+ // If the token isn't an identifier, it's always literally expanded.
+ if (II == 0) return true;
+
+ // If the identifier is a macro, and if that macro is enabled, it may be
+ // expanded so it's not a trivial expansion.
+ if (II->hasMacroDefinition() && PP.getMacroInfo(II)->isEnabled() &&
+ // Fast expanding "#define X X" is ok, because X would be disabled.
+ II != MacroIdent)
+ return false;
+
+ // If this is an object-like macro invocation, it is safe to trivially expand
+ // it.
+ if (MI->isObjectLike()) return true;
+
+ // If this is a function-like macro invocation, it's safe to trivially expand
+ // as long as the identifier is not a macro argument.
+ for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end();
+ I != E; ++I)
+ if (*I == II)
+ return false; // Identifier is a macro argument.
+
+ return true;
+}
+
+
+/// isNextPPTokenLParen - Determine whether the next preprocessor token to be
+/// lexed is a '('. If so, consume the token and return true, if not, this
+/// method should have no observable side-effect on the lexed tokens.
+bool Preprocessor::isNextPPTokenLParen() {
+ // Do some quick tests for rejection cases.
+ unsigned Val;
+ if (CurLexer)
+ Val = CurLexer->isNextPPTokenLParen();
+ else if (CurPTHLexer)
+ Val = CurPTHLexer->isNextPPTokenLParen();
+ else
+ Val = CurTokenLexer->isNextTokenLParen();
+
+ if (Val == 2) {
+ // We have run off the end. If it's a source file we don't
+ // examine enclosing ones (C99 5.1.1.2p4). Otherwise walk up the
+ // macro stack.
+ if (CurPPLexer)
+ return false;
+ for (unsigned i = IncludeMacroStack.size(); i != 0; --i) {
+ IncludeStackInfo &Entry = IncludeMacroStack[i-1];
+ if (Entry.TheLexer)
+ Val = Entry.TheLexer->isNextPPTokenLParen();
+ else if (Entry.ThePTHLexer)
+ Val = Entry.ThePTHLexer->isNextPPTokenLParen();
+ else
+ Val = Entry.TheTokenLexer->isNextTokenLParen();
+
+ if (Val != 2)
+ break;
+
+ // Ran off the end of a source file?
+ if (Entry.ThePPLexer)
+ return false;
+ }
+ }
+
+ // Okay, if we know that the token is a '(', lex it and return. Otherwise we
+ // have found something that isn't a '(' or we found the end of the
+ // translation unit. In either case, return false.
+ return Val == 1;
+}
+
+/// HandleMacroExpandedIdentifier - If an identifier token is read that is to be
+/// expanded as a macro, handle it and return the next token as 'Identifier'.
+bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
+ MacroInfo *MI) {
+ if (Callbacks) Callbacks->MacroExpands(Identifier, MI);
+
+ // If this is a macro exapnsion in the "#if !defined(x)" line for the file,
+ // then the macro could expand to different things in other contexts, we need
+ // to disable the optimization in this case.
+ if (CurPPLexer) CurPPLexer->MIOpt.ExpandedMacro();
+
+ // If this is a builtin macro, like __LINE__ or _Pragma, handle it specially.
+ if (MI->isBuiltinMacro()) {
+ ExpandBuiltinMacro(Identifier);
+ return false;
+ }
+
+ /// Args - If this is a function-like macro expansion, this contains,
+ /// for each macro argument, the list of tokens that were provided to the
+ /// invocation.
+ MacroArgs *Args = 0;
+
+ // Remember where the end of the instantiation occurred. For an object-like
+ // macro, this is the identifier. For a function-like macro, this is the ')'.
+ SourceLocation InstantiationEnd = Identifier.getLocation();
+
+ // If this is a function-like macro, read the arguments.
+ if (MI->isFunctionLike()) {
+ // C99 6.10.3p10: If the preprocessing token immediately after the the macro
+ // name isn't a '(', this macro should not be expanded.
+ if (!isNextPPTokenLParen())
+ return true;
+
+ // Remember that we are now parsing the arguments to a macro invocation.
+ // Preprocessor directives used inside macro arguments are not portable, and
+ // this enables the warning.
+ InMacroArgs = true;
+ Args = ReadFunctionLikeMacroArgs(Identifier, MI, InstantiationEnd);
+
+ // Finished parsing args.
+ InMacroArgs = false;
+
+ // If there was an error parsing the arguments, bail out.
+ if (Args == 0) return false;
+
+ ++NumFnMacroExpanded;
+ } else {
+ ++NumMacroExpanded;
+ }
+
+ // Notice that this macro has been used.
+ MI->setIsUsed(true);
+
+ // 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) {
+ // No need for arg info.
+ if (Args) Args->destroy();
+
+ // Ignore this macro use, just return the next token in the current
+ // buffer.
+ bool HadLeadingSpace = Identifier.hasLeadingSpace();
+ bool IsAtStartOfLine = Identifier.isAtStartOfLine();
+
+ Lex(Identifier);
+
+ // If the identifier isn't on some OTHER line, inherit the leading
+ // whitespace/first-on-a-line property of this token. This handles
+ // stuff like "! XX," -> "! ," and " XX," -> " ,", when XX is
+ // empty.
+ if (!Identifier.isAtStartOfLine()) {
+ if (IsAtStartOfLine) Identifier.setFlag(Token::StartOfLine);
+ if (HadLeadingSpace) Identifier.setFlag(Token::LeadingSpace);
+ }
+ ++NumFastMacroExpanded;
+ return false;
+
+ } else if (MI->getNumTokens() == 1 &&
+ isTrivialSingleTokenExpansion(MI, Identifier.getIdentifierInfo(),
+ *this)) {
+ // Otherwise, if this macro expands into a single trivially-expanded
+ // token: expand it now. This handles common cases like
+ // "#define VAL 42".
+
+ // No need for arg info.
+ if (Args) Args->destroy();
+
+ // Propagate the isAtStartOfLine/hasLeadingSpace markers of the macro
+ // identifier to the expanded token.
+ bool isAtStartOfLine = Identifier.isAtStartOfLine();
+ bool hasLeadingSpace = Identifier.hasLeadingSpace();
+
+ // Remember where the token is instantiated.
+ SourceLocation InstantiateLoc = Identifier.getLocation();
+
+ // Replace the result token.
+ Identifier = MI->getReplacementToken(0);
+
+ // Restore the StartOfLine/LeadingSpace markers.
+ Identifier.setFlagValue(Token::StartOfLine , isAtStartOfLine);
+ Identifier.setFlagValue(Token::LeadingSpace, hasLeadingSpace);
+
+ // Update the tokens location to include both its instantiation and physical
+ // locations.
+ SourceLocation Loc =
+ SourceMgr.createInstantiationLoc(Identifier.getLocation(), InstantiateLoc,
+ InstantiationEnd,Identifier.getLength());
+ Identifier.setLocation(Loc);
+
+ // If this is #define X X, we must mark the result as unexpandible.
+ if (IdentifierInfo *NewII = Identifier.getIdentifierInfo())
+ if (getMacroInfo(NewII) == MI)
+ Identifier.setFlag(Token::DisableExpand);
+
+ // Since this is not an identifier token, it can't be macro expanded, so
+ // we're done.
+ ++NumFastMacroExpanded;
+ return false;
+ }
+
+ // Start expanding the macro.
+ EnterMacro(Identifier, InstantiationEnd, Args);
+
+ // Now that the macro is at the top of the include stack, ask the
+ // preprocessor to read the next token from it.
+ Lex(Identifier);
+ return false;
+}
+
+/// ReadFunctionLikeMacroArgs - After reading "MACRO" and knowing that the next
+/// token is the '(' of the macro, this method is invoked to read all of the
+/// actual arguments specified for the macro invocation. This returns null on
+/// error.
+MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
+ MacroInfo *MI,
+ SourceLocation &MacroEnd) {
+ // The number of fixed arguments to parse.
+ unsigned NumFixedArgsLeft = MI->getNumArgs();
+ bool isVariadic = MI->isVariadic();
+
+ // Outer loop, while there are more arguments, keep reading them.
+ Token Tok;
+
+ // Read arguments as unexpanded tokens. This avoids issues, e.g., where
+ // an argument value in a macro could expand to ',' or '(' or ')'.
+ LexUnexpandedToken(Tok);
+ assert(Tok.is(tok::l_paren) && "Error computing l-paren-ness?");
+
+ // 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;
+
+ unsigned NumActuals = 0;
+ while (Tok.isNot(tok::r_paren)) {
+ assert((Tok.is(tok::l_paren) || Tok.is(tok::comma)) &&
+ "only expect argument separators here");
+
+ unsigned ArgTokenStart = ArgTokens.size();
+ SourceLocation ArgStartLoc = Tok.getLocation();
+
+ // C99 6.10.3p11: Keep track of the number of l_parens we have seen. Note
+ // that we already consumed the first one.
+ unsigned NumParens = 0;
+
+ while (1) {
+ // Read arguments as unexpanded tokens. This avoids issues, e.g., where
+ // an argument value in a macro could expand to ',' or '(' or ')'.
+ LexUnexpandedToken(Tok);
+
+ if (Tok.is(tok::eof) || Tok.is(tok::eom)) { // "#if f(<eof>" & "#if f(\n"
+ Diag(MacroName, diag::err_unterm_macro_invoc);
+ // Do not lose the EOF/EOM. Return it to the client.
+ MacroName = Tok;
+ return 0;
+ } else if (Tok.is(tok::r_paren)) {
+ // If we found the ) token, the macro arg list is done.
+ if (NumParens-- == 0) {
+ MacroEnd = Tok.getLocation();
+ break;
+ }
+ } else if (Tok.is(tok::l_paren)) {
+ ++NumParens;
+ } else if (Tok.is(tok::comma) && NumParens == 0) {
+ // Comma ends this argument if there are more fixed arguments expected.
+ // However, if this is a variadic macro, and this is part of the
+ // variadic part, then the comma is just an argument token.
+ if (!isVariadic) break;
+ if (NumFixedArgsLeft > 1)
+ break;
+ } else if (Tok.is(tok::comment) && !KeepMacroComments) {
+ // If this is a comment token in the argument list and we're just in
+ // -C mode (not -CC mode), discard the comment.
+ continue;
+ } else if (Tok.getIdentifierInfo() != 0) {
+ // Reading macro arguments can cause macros that we are currently
+ // expanding from to be popped off the expansion stack. Doing so causes
+ // them to be reenabled for expansion. Here we record whether any
+ // identifiers we lex as macro arguments correspond to disabled macros.
+ // If so, we mark the token as noexpand. This is a subtle aspect of
+ // C99 6.10.3.4p2.
+ if (MacroInfo *MI = getMacroInfo(Tok.getIdentifierInfo()))
+ if (!MI->isEnabled())
+ Tok.setFlag(Token::DisableExpand);
+ }
+ ArgTokens.push_back(Tok);
+ }
+
+ // If this was an empty argument list foo(), don't add this as an empty
+ // argument.
+ if (ArgTokens.empty() && Tok.getKind() == tok::r_paren)
+ break;
+
+ // If this is not a variadic macro, and too many args were specified, emit
+ // an error.
+ if (!isVariadic && NumFixedArgsLeft == 0) {
+ if (ArgTokens.size() != ArgTokenStart)
+ ArgStartLoc = ArgTokens[ArgTokenStart].getLocation();
+
+ // Emit the diagnostic at the macro name in case there is a missing ).
+ // Emitting it at the , could be far away from the macro name.
+ Diag(ArgStartLoc, diag::err_too_many_args_in_macro_invoc);
+ return 0;
+ }
+
+ // Empty arguments are standard in C99 and supported as an extension in
+ // other modes.
+ if (ArgTokens.size() == ArgTokenStart && !Features.C99)
+ Diag(Tok, diag::ext_empty_fnmacro_arg);
+
+ // Add a marker EOF token to the end of the token list for this argument.
+ Token EOFTok;
+ EOFTok.startToken();
+ EOFTok.setKind(tok::eof);
+ EOFTok.setLocation(Tok.getLocation());
+ EOFTok.setLength(0);
+ ArgTokens.push_back(EOFTok);
+ ++NumActuals;
+ assert(NumFixedArgsLeft != 0 && "Too many arguments parsed");
+ --NumFixedArgsLeft;
+ }
+
+ // Okay, we either found the r_paren. Check to see if we parsed too few
+ // arguments.
+ unsigned MinArgsExpected = MI->getNumArgs();
+
+ // See MacroArgs instance var for description of this.
+ bool isVarargsElided = false;
+
+ if (NumActuals < MinArgsExpected) {
+ // There are several cases where too few arguments is ok, handle them now.
+ if (NumActuals == 0 && MinArgsExpected == 1) {
+ // #define A(X) or #define A(...) ---> A()
+
+ // If there is exactly one argument, and that argument is missing,
+ // then we have an empty "()" argument empty list. This is fine, even if
+ // the macro expects one argument (the argument is just empty).
+ isVarargsElided = MI->isVariadic();
+ } else if (MI->isVariadic() &&
+ (NumActuals+1 == MinArgsExpected || // A(x, ...) -> A(X)
+ (NumActuals == 0 && MinArgsExpected == 2))) {// A(x,...) -> A()
+ // Varargs where the named vararg parameter is missing: ok as extension.
+ // #define A(x, ...)
+ // A("blah")
+ Diag(Tok, diag::ext_missing_varargs_arg);
+
+ // Remember this occurred, allowing us to elide the comma when used for
+ // cases like:
+ // #define A(x, foo...) blah(a, ## foo)
+ // #define B(x, ...) blah(a, ## __VA_ARGS__)
+ // #define C(...) blah(a, ## __VA_ARGS__)
+ // A(x) B(x) C()
+ isVarargsElided = true;
+ } else {
+ // Otherwise, emit the error.
+ Diag(Tok, diag::err_too_few_args_in_macro_invoc);
+ return 0;
+ }
+
+ // Add a marker EOF token to the end of the token list for this argument.
+ SourceLocation EndLoc = Tok.getLocation();
+ Tok.startToken();
+ Tok.setKind(tok::eof);
+ Tok.setLocation(EndLoc);
+ Tok.setLength(0);
+ ArgTokens.push_back(Tok);
+
+ // If we expect two arguments, add both as empty.
+ if (NumActuals == 0 && MinArgsExpected == 2)
+ ArgTokens.push_back(Tok);
+
+ } else if (NumActuals > MinArgsExpected && !MI->isVariadic()) {
+ // Emit the diagnostic at the macro name in case there is a missing ).
+ // Emitting it at the , could be far away from the macro name.
+ Diag(MacroName, diag::err_too_many_args_in_macro_invoc);
+ return 0;
+ }
+
+ return MacroArgs::create(MI, ArgTokens.data(), ArgTokens.size(),
+ isVarargsElided);
+}
+
+/// ComputeDATE_TIME - Compute the current time, enter it into the specified
+/// scratch buffer, then return DATELoc/TIMELoc locations with the position of
+/// the identifier tokens inserted.
+static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
+ Preprocessor &PP) {
+ time_t TT = time(0);
+ struct tm *TM = localtime(&TT);
+
+ static const char * const Months[] = {
+ "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
+ };
+
+ char TmpBuffer[100];
+ sprintf(TmpBuffer, "\"%s %2d %4d\"", Months[TM->tm_mon], TM->tm_mday,
+ TM->tm_year+1900);
+
+ Token TmpTok;
+ TmpTok.startToken();
+ PP.CreateString(TmpBuffer, strlen(TmpBuffer), TmpTok);
+ DATELoc = TmpTok.getLocation();
+
+ sprintf(TmpBuffer, "\"%02d:%02d:%02d\"", TM->tm_hour, TM->tm_min, TM->tm_sec);
+ PP.CreateString(TmpBuffer, strlen(TmpBuffer), TmpTok);
+ TIMELoc = TmpTok.getLocation();
+}
+
+/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded
+/// as a builtin macro, handle it and return the next token as 'Tok'.
+void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
+ // Figure out which token this is.
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ assert(II && "Can't be a macro without id info!");
+
+ // If this is an _Pragma directive, expand it, invoke the pragma handler, then
+ // lex the token after it.
+ if (II == Ident_Pragma)
+ return Handle_Pragma(Tok);
+
+ ++NumBuiltinMacroExpanded;
+
+ char TmpBuffer[100];
+
+ // Set up the return result.
+ Tok.setIdentifierInfo(0);
+ Tok.clearFlag(Token::NeedsCleaning);
+
+ if (II == Ident__LINE__) {
+ // C99 6.10.8: "__LINE__: The presumed line number (within the current
+ // source file) of the current source line (an integer constant)". This can
+ // be affected by #line.
+ SourceLocation Loc = Tok.getLocation();
+
+ // Advance to the location of the first _, this might not be the first byte
+ // of the token if it starts with an escaped newline.
+ Loc = AdvanceToTokenCharacter(Loc, 0);
+
+ // One wrinkle here is that GCC expands __LINE__ to location of the *end* of
+ // a macro instantiation. This doesn't matter for object-like macros, but
+ // can matter for a function-like macro that expands to contain __LINE__.
+ // Skip down through instantiation points until we find a file loc for the
+ // end of the instantiation history.
+ Loc = SourceMgr.getInstantiationRange(Loc).second;
+ PresumedLoc PLoc = SourceMgr.getPresumedLoc(Loc);
+
+ // __LINE__ expands to a simple numeric value.
+ sprintf(TmpBuffer, "%u", PLoc.getLine());
+ Tok.setKind(tok::numeric_constant);
+ CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
+ } else if (II == Ident__FILE__ || II == Ident__BASE_FILE__) {
+ // C99 6.10.8: "__FILE__: The presumed name of the current source file (a
+ // character string literal)". This can be affected by #line.
+ PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation());
+
+ // __BASE_FILE__ is a GNU extension that returns the top of the presumed
+ // #include stack instead of the current file.
+ if (II == Ident__BASE_FILE__) {
+ Diag(Tok, diag::ext_pp_base_file);
+ SourceLocation NextLoc = PLoc.getIncludeLoc();
+ while (NextLoc.isValid()) {
+ PLoc = SourceMgr.getPresumedLoc(NextLoc);
+ NextLoc = PLoc.getIncludeLoc();
+ }
+ }
+
+ // Escape this filename. Turn '\' -> '\\' '"' -> '\"'
+ std::string FN = PLoc.getFilename();
+ FN = '"' + Lexer::Stringify(FN) + '"';
+ Tok.setKind(tok::string_literal);
+ CreateString(&FN[0], FN.size(), Tok, Tok.getLocation());
+ } else if (II == Ident__DATE__) {
+ if (!DATELoc.isValid())
+ 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()));
+ } 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()));
+ } else if (II == Ident__INCLUDE_LEVEL__) {
+ Diag(Tok, diag::ext_pp_include_level);
+
+ // Compute the presumed include depth of this token. This can be affected
+ // by GNU line markers.
+ unsigned Depth = 0;
+
+ PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation());
+ PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc());
+ for (; PLoc.isValid(); ++Depth)
+ PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc());
+
+ // __INCLUDE_LEVEL__ expands to a simple numeric value.
+ sprintf(TmpBuffer, "%u", Depth);
+ Tok.setKind(tok::numeric_constant);
+ CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
+ } else if (II == Ident__TIMESTAMP__) {
+ // MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be
+ // of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime.
+ Diag(Tok, diag::ext_pp_timestamp);
+
+ // Get the file that we are lexing out of. If we're currently lexing from
+ // a macro, dig into the include stack.
+ const FileEntry *CurFile = 0;
+ PreprocessorLexer *TheLexer = getCurrentFileLexer();
+
+ if (TheLexer)
+ CurFile = SourceMgr.getFileEntryForID(TheLexer->getFileID());
+
+ // If this file is older than the file it depends on, emit a diagnostic.
+ const char *Result;
+ if (CurFile) {
+ time_t TT = CurFile->getModificationTime();
+ struct tm *TM = localtime(&TT);
+ Result = asctime(TM);
+ } else {
+ Result = "??? ??? ?? ??:??:?? ????\n";
+ }
+ TmpBuffer[0] = '"';
+ strcpy(TmpBuffer+1, Result);
+ unsigned Len = strlen(TmpBuffer);
+ TmpBuffer[Len] = '"'; // Replace the newline with a quote.
+ Tok.setKind(tok::string_literal);
+ CreateString(TmpBuffer, Len+1, Tok, Tok.getLocation());
+ } else if (II == Ident__COUNTER__) {
+ Diag(Tok, diag::ext_pp_counter);
+
+ // __COUNTER__ expands to a simple numeric value.
+ sprintf(TmpBuffer, "%u", CounterValue++);
+ Tok.setKind(tok::numeric_constant);
+ CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
+ } else {
+ assert(0 && "Unknown identifier!");
+ }
+}
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
new file mode 100644
index 000000000000..916bdefdf2ac
--- /dev/null
+++ b/lib/Lex/PTHLexer.cpp
@@ -0,0 +1,701 @@
+//===--- PTHLexer.cpp - Lex from a token stream ---------------------------===//
+//
+// 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 PTHLexer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/TokenKinds.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Lex/PTHLexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PTHManager.h"
+#include "clang/Lex/Token.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <sys/stat.h>
+using namespace clang;
+using namespace clang::io;
+
+#define DISK_TOKEN_SIZE (1+1+2+4+4)
+
+//===----------------------------------------------------------------------===//
+// PTHLexer methods.
+//===----------------------------------------------------------------------===//
+
+PTHLexer::PTHLexer(Preprocessor &PP, FileID FID, const unsigned char *D,
+ const unsigned char *ppcond, PTHManager &PM)
+ : PreprocessorLexer(&PP, FID), TokBuf(D), CurPtr(D), LastHashTokPtr(0),
+ PPCond(ppcond), CurPPCondPtr(ppcond), PTHMgr(PM) {
+
+ FileStartLoc = PP.getSourceManager().getLocForStartOfFile(FID);
+}
+
+void PTHLexer::Lex(Token& Tok) {
+LexNextToken:
+
+ //===--------------------------------------==//
+ // Read the raw token data.
+ //===--------------------------------------==//
+
+ // Shadow CurPtr into an automatic variable.
+ const unsigned char *CurPtrShadow = CurPtr;
+
+ // Read in the data for the token.
+ unsigned Word0 = ReadLE32(CurPtrShadow);
+ uint32_t IdentifierID = ReadLE32(CurPtrShadow);
+ uint32_t FileOffset = ReadLE32(CurPtrShadow);
+
+ tok::TokenKind TKind = (tok::TokenKind) (Word0 & 0xFF);
+ Token::TokenFlags TFlags = (Token::TokenFlags) ((Word0 >> 8) & 0xFF);
+ uint32_t Len = Word0 >> 16;
+
+ CurPtr = CurPtrShadow;
+
+ //===--------------------------------------==//
+ // Construct the token itself.
+ //===--------------------------------------==//
+
+ Tok.startToken();
+ Tok.setKind(TKind);
+ Tok.setFlag(TFlags);
+ assert(!LexingRawMode);
+ Tok.setLocation(FileStartLoc.getFileLocWithOffset(FileOffset));
+ Tok.setLength(Len);
+
+ // Handle identifiers.
+ if (Tok.isLiteral()) {
+ Tok.setLiteralData((const char*) (PTHMgr.SpellingBase + IdentifierID));
+ }
+ else if (IdentifierID) {
+ MIOpt.ReadToken();
+ IdentifierInfo *II = PTHMgr.GetIdentifierInfo(IdentifierID-1);
+
+ Tok.setIdentifierInfo(II);
+
+ // Change the kind of this identifier to the appropriate token kind, e.g.
+ // turning "for" into a keyword.
+ Tok.setKind(II->getTokenID());
+
+ if (II->isHandleIdentifierCase())
+ PP->HandleIdentifier(Tok);
+ return;
+ }
+
+ //===--------------------------------------==//
+ // Process the token.
+ //===--------------------------------------==//
+#if 0
+ SourceManager& SM = PP->getSourceManager();
+ llvm::cerr << SM.getFileEntryForID(FileID)->getName()
+ << ':' << SM.getLogicalLineNumber(Tok.getLocation())
+ << ':' << SM.getLogicalColumnNumber(Tok.getLocation())
+ << '\n';
+#endif
+
+ if (TKind == tok::eof) {
+ // Save the end-of-file token.
+ EofToken = Tok;
+
+ Preprocessor *PPCache = PP;
+
+ assert(!ParsingPreprocessorDirective);
+ assert(!LexingRawMode);
+
+ // FIXME: Issue diagnostics similar to Lexer.
+ if (PP->HandleEndOfFile(Tok, false))
+ return;
+
+ assert(PPCache && "Raw buffer::LexEndOfFile should return a token");
+ return PPCache->Lex(Tok);
+ }
+
+ if (TKind == tok::hash && Tok.isAtStartOfLine()) {
+ LastHashTokPtr = CurPtr - DISK_TOKEN_SIZE;
+ assert(!LexingRawMode);
+ PP->HandleDirective(Tok);
+
+ if (PP->isCurrentLexer(this))
+ goto LexNextToken;
+
+ return PP->Lex(Tok);
+ }
+
+ if (TKind == tok::eom) {
+ assert(ParsingPreprocessorDirective);
+ ParsingPreprocessorDirective = false;
+ return;
+ }
+
+ MIOpt.ReadToken();
+}
+
+// FIXME: We can just grab the last token instead of storing a copy
+// into EofToken.
+void PTHLexer::getEOF(Token& Tok) {
+ assert(EofToken.is(tok::eof));
+ Tok = EofToken;
+}
+
+void PTHLexer::DiscardToEndOfLine() {
+ assert(ParsingPreprocessorDirective && ParsingFilename == false &&
+ "Must be in a preprocessing directive!");
+
+ // We assume that if the preprocessor wishes to discard to the end of
+ // the line that it also means to end the current preprocessor directive.
+ ParsingPreprocessorDirective = false;
+
+ // Skip tokens by only peeking at their token kind and the flags.
+ // We don't need to actually reconstruct full tokens from the token buffer.
+ // This saves some copies and it also reduces IdentifierInfo* lookup.
+ const unsigned char* p = CurPtr;
+ while (1) {
+ // Read the token kind. Are we at the end of the file?
+ tok::TokenKind x = (tok::TokenKind) (uint8_t) *p;
+ if (x == tok::eof) break;
+
+ // Read the token flags. Are we at the start of the next line?
+ Token::TokenFlags y = (Token::TokenFlags) (uint8_t) p[1];
+ if (y & Token::StartOfLine) break;
+
+ // Skip to the next token.
+ p += DISK_TOKEN_SIZE;
+ }
+
+ CurPtr = p;
+}
+
+/// SkipBlock - Used by Preprocessor to skip the current conditional block.
+bool PTHLexer::SkipBlock() {
+ assert(CurPPCondPtr && "No cached PP conditional information.");
+ assert(LastHashTokPtr && "No known '#' token.");
+
+ const unsigned char* HashEntryI = 0;
+ uint32_t Offset;
+ uint32_t TableIdx;
+
+ do {
+ // Read the token offset from the side-table.
+ Offset = ReadLE32(CurPPCondPtr);
+
+ // Read the target table index from the side-table.
+ TableIdx = ReadLE32(CurPPCondPtr);
+
+ // Compute the actual memory address of the '#' token data for this entry.
+ HashEntryI = TokBuf + Offset;
+
+ // Optmization: "Sibling jumping". #if...#else...#endif blocks can
+ // contain nested blocks. In the side-table we can jump over these
+ // nested blocks instead of doing a linear search if the next "sibling"
+ // entry is not at a location greater than LastHashTokPtr.
+ if (HashEntryI < LastHashTokPtr && TableIdx) {
+ // In the side-table we are still at an entry for a '#' token that
+ // is earlier than the last one we saw. Check if the location we would
+ // stride gets us closer.
+ const unsigned char* NextPPCondPtr =
+ PPCond + TableIdx*(sizeof(uint32_t)*2);
+ assert(NextPPCondPtr >= CurPPCondPtr);
+ // Read where we should jump to.
+ uint32_t TmpOffset = ReadLE32(NextPPCondPtr);
+ const unsigned char* HashEntryJ = TokBuf + TmpOffset;
+
+ if (HashEntryJ <= LastHashTokPtr) {
+ // Jump directly to the next entry in the side table.
+ HashEntryI = HashEntryJ;
+ Offset = TmpOffset;
+ TableIdx = ReadLE32(NextPPCondPtr);
+ CurPPCondPtr = NextPPCondPtr;
+ }
+ }
+ }
+ while (HashEntryI < LastHashTokPtr);
+ assert(HashEntryI == LastHashTokPtr && "No PP-cond entry found for '#'");
+ assert(TableIdx && "No jumping from #endifs.");
+
+ // Update our side-table iterator.
+ const unsigned char* NextPPCondPtr = PPCond + TableIdx*(sizeof(uint32_t)*2);
+ assert(NextPPCondPtr >= CurPPCondPtr);
+ CurPPCondPtr = NextPPCondPtr;
+
+ // Read where we should jump to.
+ HashEntryI = TokBuf + ReadLE32(NextPPCondPtr);
+ uint32_t NextIdx = ReadLE32(NextPPCondPtr);
+
+ // By construction NextIdx will be zero if this is a #endif. This is useful
+ // to know to obviate lexing another token.
+ bool isEndif = NextIdx == 0;
+
+ // This case can occur when we see something like this:
+ //
+ // #if ...
+ // /* a comment or nothing */
+ // #elif
+ //
+ // If we are skipping the first #if block it will be the case that CurPtr
+ // already points 'elif'. Just return.
+
+ if (CurPtr > HashEntryI) {
+ assert(CurPtr == HashEntryI + DISK_TOKEN_SIZE);
+ // Did we reach a #endif? If so, go ahead and consume that token as well.
+ if (isEndif)
+ CurPtr += DISK_TOKEN_SIZE*2;
+ else
+ LastHashTokPtr = HashEntryI;
+
+ return isEndif;
+ }
+
+ // Otherwise, we need to advance. Update CurPtr to point to the '#' token.
+ CurPtr = HashEntryI;
+
+ // Update the location of the last observed '#'. This is useful if we
+ // are skipping multiple blocks.
+ LastHashTokPtr = CurPtr;
+
+ // Skip the '#' token.
+ assert(((tok::TokenKind)*CurPtr) == tok::hash);
+ CurPtr += DISK_TOKEN_SIZE;
+
+ // Did we reach a #endif? If so, go ahead and consume that token as well.
+ if (isEndif) { CurPtr += DISK_TOKEN_SIZE*2; }
+
+ return isEndif;
+}
+
+SourceLocation PTHLexer::getSourceLocation() {
+ // getSourceLocation is not on the hot path. It is used to get the location
+ // of the next token when transitioning back to this lexer when done
+ // handling a #included file. Just read the necessary data from the token
+ // data buffer to construct the SourceLocation object.
+ // 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);
+}
+
+//===----------------------------------------------------------------------===//
+// PTH file lookup: map from strings to file data.
+//===----------------------------------------------------------------------===//
+
+/// PTHFileLookup - This internal data structure is used by the PTHManager
+/// to map from FileEntry objects managed by FileManager to offsets within
+/// the PTH file.
+namespace {
+class VISIBILITY_HIDDEN PTHFileData {
+ const uint32_t TokenOff;
+ const uint32_t PPCondOff;
+public:
+ PTHFileData(uint32_t tokenOff, uint32_t ppCondOff)
+ : TokenOff(tokenOff), PPCondOff(ppCondOff) {}
+
+ uint32_t getTokenOffset() const { return TokenOff; }
+ uint32_t getPPCondOffset() const { return PPCondOff; }
+};
+
+
+class VISIBILITY_HIDDEN PTHFileLookupCommonTrait {
+public:
+ typedef std::pair<unsigned char, const char*> internal_key_type;
+
+ static unsigned ComputeHash(internal_key_type x) {
+ return BernsteinHash(x.second);
+ }
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d) {
+ unsigned keyLen = (unsigned) ReadUnalignedLE16(d);
+ unsigned dataLen = (unsigned) *(d++);
+ return std::make_pair(keyLen, dataLen);
+ }
+
+ static internal_key_type ReadKey(const unsigned char* d, unsigned) {
+ unsigned char k = *(d++); // Read the entry kind.
+ return std::make_pair(k, (const char*) d);
+ }
+};
+
+class VISIBILITY_HIDDEN PTHFileLookupTrait : public PTHFileLookupCommonTrait {
+public:
+ typedef const FileEntry* external_key_type;
+ typedef PTHFileData data_type;
+
+ static internal_key_type GetInternalKey(const FileEntry* FE) {
+ return std::make_pair((unsigned char) 0x1, FE->getName());
+ }
+
+ static bool EqualKey(internal_key_type a, internal_key_type b) {
+ return a.first == b.first && strcmp(a.second, b.second) == 0;
+ }
+
+ static PTHFileData ReadData(const internal_key_type& k,
+ const unsigned char* d, unsigned) {
+ assert(k.first == 0x1 && "Only file lookups can match!");
+ uint32_t x = ::ReadUnalignedLE32(d);
+ uint32_t y = ::ReadUnalignedLE32(d);
+ return PTHFileData(x, y);
+ }
+};
+
+class VISIBILITY_HIDDEN PTHStringLookupTrait {
+public:
+ typedef uint32_t
+ data_type;
+
+ typedef const std::pair<const char*, unsigned>
+ external_key_type;
+
+ typedef external_key_type internal_key_type;
+
+ 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) {
+ return BernsteinHash(a.first, a.second);
+ }
+
+ // This hopefully will just get inlined and removed by the optimizer.
+ static const internal_key_type&
+ GetInternalKey(const external_key_type& x) { return x; }
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d) {
+ return std::make_pair((unsigned) ReadUnalignedLE16(d), sizeof(uint32_t));
+ }
+
+ 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);
+ }
+
+ static uint32_t ReadData(const internal_key_type& k, const unsigned char* d,
+ unsigned) {
+ return ::ReadUnalignedLE32(d);
+ }
+};
+
+} // end anonymous namespace
+
+typedef OnDiskChainedHashTable<PTHFileLookupTrait> PTHFileLookup;
+typedef OnDiskChainedHashTable<PTHStringLookupTrait> PTHStringIdLookup;
+
+//===----------------------------------------------------------------------===//
+// PTHManager methods.
+//===----------------------------------------------------------------------===//
+
+PTHManager::PTHManager(const llvm::MemoryBuffer* buf, void* fileLookup,
+ const unsigned char* idDataTable,
+ IdentifierInfo** perIDCache,
+ void* stringIdLookup, unsigned numIds,
+ const unsigned char* spellingBase,
+ const char* originalSourceFile)
+: Buf(buf), PerIDCache(perIDCache), FileLookup(fileLookup),
+ IdDataTable(idDataTable), StringIdLookup(stringIdLookup),
+ NumIds(numIds), PP(0), SpellingBase(spellingBase),
+ OriginalSourceFile(originalSourceFile) {}
+
+PTHManager::~PTHManager() {
+ delete Buf;
+ delete (PTHFileLookup*) FileLookup;
+ delete (PTHStringIdLookup*) StringIdLookup;
+ free(PerIDCache);
+}
+
+static void InvalidPTH(Diagnostic *Diags, Diagnostic::Level level,
+ const char* Msg = 0) {
+ if (!Diags) return;
+ if (!Msg) Msg = "Invalid or corrupted PTH file";
+ unsigned DiagID = Diags->getCustomDiagID(level, Msg);
+ Diags->Report(FullSourceLoc(), DiagID);
+}
+
+PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags,
+ Diagnostic::Level level) {
+ // Memory map the PTH file.
+ llvm::OwningPtr<llvm::MemoryBuffer>
+ File(llvm::MemoryBuffer::getFile(file.c_str()));
+
+ if (!File) {
+ if (Diags) {
+ unsigned DiagID = Diags->getCustomDiagID(level,
+ "PTH file %0 could not be read");
+ Diags->Report(FullSourceLoc(), DiagID) << file;
+ }
+
+ return 0;
+ }
+
+ // Get the buffer ranges and check if there are at least three 32-bit
+ // words at the end of the file.
+ const unsigned char* BufBeg = (unsigned char*)File->getBufferStart();
+ const unsigned char* BufEnd = (unsigned char*)File->getBufferEnd();
+
+ // Check the prologue of the file.
+ if ((BufEnd - BufBeg) < (signed) (sizeof("cfe-pth") + 3 + 4) ||
+ memcmp(BufBeg, "cfe-pth", sizeof("cfe-pth") - 1) != 0) {
+ InvalidPTH(Diags, level);
+ return 0;
+ }
+
+ // Read the PTH version.
+ const unsigned char *p = BufBeg + (sizeof("cfe-pth") - 1);
+ unsigned Version = ReadLE32(p);
+
+ if (Version != PTHManager::Version) {
+ InvalidPTH(Diags, level,
+ Version < PTHManager::Version
+ ? "PTH file uses an older PTH format that is no longer supported"
+ : "PTH file uses a newer PTH format that cannot be read");
+ return 0;
+ }
+
+ // Compute the address of the index table at the end of the PTH file.
+ const unsigned char *PrologueOffset = p;
+
+ if (PrologueOffset >= BufEnd) {
+ InvalidPTH(Diags, level);
+ return 0;
+ }
+
+ // Construct the file lookup table. This will be used for mapping from
+ // FileEntry*'s to cached tokens.
+ const unsigned char* FileTableOffset = PrologueOffset + sizeof(uint32_t)*2;
+ const unsigned char* FileTable = BufBeg + ReadLE32(FileTableOffset);
+
+ if (!(FileTable > BufBeg && FileTable < BufEnd)) {
+ InvalidPTH(Diags, level);
+ return 0; // FIXME: Proper error diagnostic?
+ }
+
+ llvm::OwningPtr<PTHFileLookup> FL(PTHFileLookup::Create(FileTable, BufBeg));
+
+ // Warn if the PTH file is empty. We still want to create a PTHManager
+ // as the PTH could be used with -include-pth.
+ if (FL->isEmpty())
+ InvalidPTH(Diags, level, "PTH file contains no cached source data");
+
+ // Get the location of the table mapping from persistent ids to the
+ // data needed to reconstruct identifiers.
+ const unsigned char* IDTableOffset = PrologueOffset + sizeof(uint32_t)*0;
+ const unsigned char* IData = BufBeg + ReadLE32(IDTableOffset);
+
+ if (!(IData >= BufBeg && IData < BufEnd)) {
+ InvalidPTH(Diags, level);
+ return 0;
+ }
+
+ // Get the location of the hashtable mapping between strings and
+ // persistent IDs.
+ const unsigned char* StringIdTableOffset = PrologueOffset + sizeof(uint32_t)*1;
+ const unsigned char* StringIdTable = BufBeg + ReadLE32(StringIdTableOffset);
+ if (!(StringIdTable >= BufBeg && StringIdTable < BufEnd)) {
+ InvalidPTH(Diags, level);
+ return 0;
+ }
+
+ llvm::OwningPtr<PTHStringIdLookup> SL(PTHStringIdLookup::Create(StringIdTable,
+ BufBeg));
+
+ // Get the location of the spelling cache.
+ const unsigned char* spellingBaseOffset = PrologueOffset + sizeof(uint32_t)*3;
+ const unsigned char* spellingBase = BufBeg + ReadLE32(spellingBaseOffset);
+ if (!(spellingBase >= BufBeg && spellingBase < BufEnd)) {
+ InvalidPTH(Diags, level);
+ return 0;
+ }
+
+ // Get the number of IdentifierInfos and pre-allocate the identifier cache.
+ uint32_t NumIds = ReadLE32(IData);
+
+ // Pre-allocate the peristent ID -> IdentifierInfo* cache. We use calloc()
+ // so that we in the best case only zero out memory once when the OS returns
+ // us new pages.
+ IdentifierInfo** PerIDCache = 0;
+
+ if (NumIds) {
+ PerIDCache = (IdentifierInfo**)calloc(NumIds, sizeof(*PerIDCache));
+ if (!PerIDCache) {
+ InvalidPTH(Diags, level,
+ "Could not allocate memory for processing PTH file");
+ return 0;
+ }
+ }
+
+ // Compute the address of the original source file.
+ const unsigned char* originalSourceBase = PrologueOffset + sizeof(uint32_t)*4;
+ unsigned len = ReadUnalignedLE16(originalSourceBase);
+ if (!len) originalSourceBase = 0;
+
+ // Create the new PTHManager.
+ return new PTHManager(File.take(), FL.take(), IData, PerIDCache,
+ SL.take(), NumIds, spellingBase,
+ (const char*) originalSourceBase);
+}
+
+IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned PersistentID) {
+ // Look in the PTH file for the string data for the IdentifierInfo object.
+ const unsigned char* TableEntry = IdDataTable + sizeof(uint32_t)*PersistentID;
+ const unsigned char* IDData =
+ (const unsigned char*)Buf->getBufferStart() + ReadLE32(TableEntry);
+ assert(IDData < (const unsigned char*)Buf->getBufferEnd());
+
+ // Allocate the object.
+ std::pair<IdentifierInfo,const unsigned char*> *Mem =
+ Alloc.Allocate<std::pair<IdentifierInfo,const unsigned char*> >();
+
+ Mem->second = IDData;
+ assert(IDData[0] != '\0');
+ IdentifierInfo *II = new ((void*) Mem) IdentifierInfo();
+
+ // Store the new IdentifierInfo in the cache.
+ PerIDCache[PersistentID] = II;
+ assert(II->getName() && II->getName()[0] != '\0');
+ return II;
+}
+
+IdentifierInfo* PTHManager::get(const char *NameStart, const char *NameEnd) {
+ PTHStringIdLookup& SL = *((PTHStringIdLookup*)StringIdLookup);
+ // Double check our assumption that the last character isn't '\0'.
+ assert(NameEnd==NameStart || NameStart[NameEnd-NameStart-1] != '\0');
+ PTHStringIdLookup::iterator I = SL.find(std::make_pair(NameStart,
+ NameEnd - NameStart));
+ if (I == SL.end()) // No identifier found?
+ return 0;
+
+ // Match found. Return the identifier!
+ assert(*I > 0);
+ return GetIdentifierInfo(*I-1);
+}
+
+PTHLexer *PTHManager::CreateLexer(FileID FID) {
+ const FileEntry *FE = PP->getSourceManager().getFileEntryForID(FID);
+ if (!FE)
+ return 0;
+
+ // Lookup the FileEntry object in our file lookup data structure. It will
+ // return a variant that indicates whether or not there is an offset within
+ // the PTH file that contains cached tokens.
+ PTHFileLookup& PFL = *((PTHFileLookup*)FileLookup);
+ PTHFileLookup::iterator I = PFL.find(FE);
+
+ if (I == PFL.end()) // No tokens available?
+ return 0;
+
+ const PTHFileData& FileData = *I;
+
+ const unsigned char *BufStart = (const unsigned char *)Buf->getBufferStart();
+ // Compute the offset of the token data within the buffer.
+ const unsigned char* data = BufStart + FileData.getTokenOffset();
+
+ // Get the location of pp-conditional table.
+ const unsigned char* ppcond = BufStart + FileData.getPPCondOffset();
+ uint32_t Len = ReadLE32(ppcond);
+ if (Len == 0) ppcond = 0;
+
+ assert(PP && "No preprocessor set yet!");
+ return new PTHLexer(*PP, FID, data, ppcond, *this);
+}
+
+//===----------------------------------------------------------------------===//
+// 'stat' caching.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN PTHStatData {
+public:
+ const bool hasStat;
+ const ino_t ino;
+ const dev_t dev;
+ const mode_t mode;
+ const time_t mtime;
+ const off_t size;
+
+ PTHStatData(ino_t i, dev_t d, mode_t mo, time_t m, off_t s)
+ : hasStat(true), ino(i), dev(d), mode(mo), mtime(m), size(s) {}
+
+ PTHStatData()
+ : hasStat(false), ino(0), dev(0), mode(0), mtime(0), size(0) {}
+};
+
+class VISIBILITY_HIDDEN PTHStatLookupTrait : public PTHFileLookupCommonTrait {
+public:
+ typedef const char* external_key_type; // const char*
+ typedef PTHStatData data_type;
+
+ static internal_key_type GetInternalKey(const char *path) {
+ // The key 'kind' doesn't matter here because it is ignored in EqualKey.
+ return std::make_pair((unsigned char) 0x0, path);
+ }
+
+ static bool EqualKey(internal_key_type a, internal_key_type b) {
+ // When doing 'stat' lookups we don't care about the kind of 'a' and 'b',
+ // just the paths.
+ return strcmp(a.second, b.second) == 0;
+ }
+
+ static data_type ReadData(const internal_key_type& k, const unsigned char* d,
+ unsigned) {
+
+ if (k.first /* File or Directory */) {
+ if (k.first == 0x1 /* File */) d += 4 * 2; // Skip the first 2 words.
+ ino_t ino = (ino_t) ReadUnalignedLE32(d);
+ dev_t dev = (dev_t) ReadUnalignedLE32(d);
+ mode_t mode = (mode_t) ReadUnalignedLE16(d);
+ time_t mtime = (time_t) ReadUnalignedLE64(d);
+ return data_type(ino, dev, mode, mtime, (off_t) ReadUnalignedLE64(d));
+ }
+
+ // Negative stat. Don't read anything.
+ return data_type();
+ }
+};
+
+class VISIBILITY_HIDDEN PTHStatCache : public StatSysCallCache {
+ typedef OnDiskChainedHashTable<PTHStatLookupTrait> CacheTy;
+ CacheTy Cache;
+
+public:
+ PTHStatCache(PTHFileLookup &FL) :
+ Cache(FL.getNumBuckets(), FL.getNumEntries(), FL.getBuckets(),
+ FL.getBase()) {}
+
+ ~PTHStatCache() {}
+
+ int stat(const char *path, struct stat *buf) {
+ // Do the lookup for the file's data in the PTH file.
+ CacheTy::iterator I = Cache.find(path);
+
+ // If we don't get a hit in the PTH file just forward to 'stat'.
+ if (I == Cache.end()) return ::stat(path, buf);
+
+ const PTHStatData& Data = *I;
+
+ if (!Data.hasStat)
+ return 1;
+
+ buf->st_ino = Data.ino;
+ buf->st_dev = Data.dev;
+ buf->st_mtime = Data.mtime;
+ buf->st_mode = Data.mode;
+ buf->st_size = Data.size;
+ return 0;
+ }
+};
+} // end anonymous namespace
+
+StatSysCallCache *PTHManager::createStatCache() {
+ return new PTHStatCache(*((PTHFileLookup*) FileLookup));
+}
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
new file mode 100644
index 000000000000..ce5934134f42
--- /dev/null
+++ b/lib/Lex/Pragma.cpp
@@ -0,0 +1,699 @@
+//===--- Pragma.cpp - Pragma registration and handling --------------------===//
+//
+// 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 PragmaHandler/PragmaTable interfaces and implements
+// pragma related methods of the Preprocessor class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Pragma.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+using namespace clang;
+
+// Out-of-line destructor to provide a home for the class.
+PragmaHandler::~PragmaHandler() {
+}
+
+//===----------------------------------------------------------------------===//
+// PragmaNamespace Implementation.
+//===----------------------------------------------------------------------===//
+
+
+PragmaNamespace::~PragmaNamespace() {
+ for (unsigned i = 0, e = Handlers.size(); i != e; ++i)
+ delete Handlers[i];
+}
+
+/// FindHandler - Check to see if there is already a handler for the
+/// 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(const IdentifierInfo *Name,
+ bool IgnoreNull) const {
+ PragmaHandler *NullHandler = 0;
+ for (unsigned i = 0, e = Handlers.size(); i != e; ++i) {
+ if (Handlers[i]->getName() == Name)
+ return Handlers[i];
+
+ if (Handlers[i]->getName() == 0)
+ NullHandler = Handlers[i];
+ }
+ return IgnoreNull ? 0 : NullHandler;
+}
+
+void PragmaNamespace::RemovePragmaHandler(PragmaHandler *Handler) {
+ for (unsigned i = 0, e = Handlers.size(); i != e; ++i) {
+ if (Handlers[i] == Handler) {
+ Handlers[i] = Handlers.back();
+ Handlers.pop_back();
+ return;
+ }
+ }
+ assert(0 && "Handler not registered in this namespace");
+}
+
+void PragmaNamespace::HandlePragma(Preprocessor &PP, Token &Tok) {
+ // Read the 'namespace' that the directive is in, e.g. STDC. Do not macro
+ // expand it, the user can have a STDC #define, that should not affect this.
+ PP.LexUnexpandedToken(Tok);
+
+ // Get the handler for this token. If there is no handler, ignore the pragma.
+ PragmaHandler *Handler = FindHandler(Tok.getIdentifierInfo(), false);
+ if (Handler == 0) {
+ PP.Diag(Tok, diag::warn_pragma_ignored);
+ return;
+ }
+
+ // Otherwise, pass it down.
+ Handler->HandlePragma(PP, Tok);
+}
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Pragma Directive Handling.
+//===----------------------------------------------------------------------===//
+
+/// HandlePragmaDirective - The "#pragma" directive has been parsed. Lex the
+/// rest of the pragma, passing it to the registered pragma handlers.
+void Preprocessor::HandlePragmaDirective() {
+ ++NumPragma;
+
+ // Invoke the first level of pragma handlers which reads the namespace id.
+ Token Tok;
+ PragmaHandlers->HandlePragma(*this, Tok);
+
+ // If the pragma handler didn't read the rest of the line, consume it now.
+ if (CurPPLexer->ParsingPreprocessorDirective)
+ DiscardUntilEndOfDirective();
+}
+
+/// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then
+/// return the first token after the directive. The _Pragma token has just
+/// been read into 'Tok'.
+void Preprocessor::Handle_Pragma(Token &Tok) {
+ // Remember the pragma token location.
+ SourceLocation PragmaLoc = Tok.getLocation();
+
+ // Read the '('.
+ Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(PragmaLoc, diag::err__Pragma_malformed);
+ return;
+ }
+
+ // Read the '"..."'.
+ Lex(Tok);
+ if (Tok.isNot(tok::string_literal) && Tok.isNot(tok::wide_string_literal)) {
+ Diag(PragmaLoc, diag::err__Pragma_malformed);
+ return;
+ }
+
+ // Remember the string.
+ std::string StrVal = getSpelling(Tok);
+
+ // Read the ')'.
+ Lex(Tok);
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(PragmaLoc, diag::err__Pragma_malformed);
+ return;
+ }
+
+ SourceLocation RParenLoc = Tok.getLocation();
+
+ // The _Pragma is lexically sound. Destringize according to C99 6.10.9.1:
+ // "The string literal is destringized by deleting the L prefix, if present,
+ // deleting the leading and trailing double-quotes, replacing each escape
+ // sequence \" by a double-quote, and replacing each escape sequence \\ by a
+ // single backslash."
+ if (StrVal[0] == 'L') // Remove L prefix.
+ StrVal.erase(StrVal.begin());
+ assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' &&
+ "Invalid string token!");
+
+ // Remove the front quote, replacing it with a space, so that the pragma
+ // contents appear to have a space before them.
+ StrVal[0] = ' ';
+
+ // Replace the terminating quote with a \n.
+ StrVal[StrVal.size()-1] = '\n';
+
+ // Remove escaped quotes and escapes.
+ for (unsigned i = 0, e = StrVal.size(); i != e-1; ++i) {
+ if (StrVal[i] == '\\' &&
+ (StrVal[i+1] == '\\' || StrVal[i+1] == '"')) {
+ // \\ -> '\' and \" -> '"'.
+ StrVal.erase(StrVal.begin()+i);
+ --e;
+ }
+ }
+
+ // Plop the string (including the newline and trailing null) into a buffer
+ // where we can lex it.
+ Token TmpTok;
+ TmpTok.startToken();
+ CreateString(&StrVal[0], StrVal.size(), TmpTok);
+ SourceLocation TokLoc = TmpTok.getLocation();
+
+ // Make and enter a lexer object so that we lex and expand the tokens just
+ // like any others.
+ Lexer *TL = Lexer::Create_PragmaLexer(TokLoc, PragmaLoc, RParenLoc,
+ StrVal.size(), *this);
+
+ EnterSourceFileWithLexer(TL, 0);
+
+ // With everything set up, lex this as a #pragma directive.
+ HandlePragmaDirective();
+
+ // Finally, return whatever came after the pragma directive.
+ return Lex(Tok);
+}
+
+
+
+/// HandlePragmaOnce - Handle #pragma once. OnceTok is the 'once'.
+///
+void Preprocessor::HandlePragmaOnce(Token &OnceTok) {
+ if (isInPrimaryFile()) {
+ Diag(OnceTok, diag::pp_pragma_once_in_main_file);
+ return;
+ }
+
+ // Get the current file lexer we're looking at. Ignore _Pragma 'files' etc.
+ // Mark the file as a once-only file now.
+ HeaderInfo.MarkFileIncludeOnce(getCurrentFileLexer()->getFileEntry());
+}
+
+void Preprocessor::HandlePragmaMark() {
+ assert(CurPPLexer && "No current lexer?");
+ if (CurLexer) CurLexer->ReadToEndOfLine();
+ else CurPTHLexer->DiscardToEndOfLine();
+}
+
+
+/// HandlePragmaPoison - Handle #pragma GCC poison. PoisonTok is the 'poison'.
+///
+void Preprocessor::HandlePragmaPoison(Token &PoisonTok) {
+ Token Tok;
+
+ while (1) {
+ // Read the next token to poison. While doing this, pretend that we are
+ // skipping while reading the identifier to poison.
+ // This avoids errors on code like:
+ // #pragma GCC poison X
+ // #pragma GCC poison X
+ if (CurPPLexer) CurPPLexer->LexingRawMode = true;
+ LexUnexpandedToken(Tok);
+ if (CurPPLexer) CurPPLexer->LexingRawMode = false;
+
+ // If we reached the end of line, we're done.
+ if (Tok.is(tok::eom)) return;
+
+ // Can only poison identifiers.
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_pp_invalid_poison);
+ return;
+ }
+
+ // Look up the identifier info for the token. We disabled identifier lookup
+ // by saying we're skipping contents, so we need to do this manually.
+ IdentifierInfo *II = LookUpIdentifierInfo(Tok);
+
+ // Already poisoned.
+ if (II->isPoisoned()) continue;
+
+ // If this is a macro identifier, emit a warning.
+ if (II->hasMacroDefinition())
+ Diag(Tok, diag::pp_poisoning_existing_macro);
+
+ // Finally, poison it!
+ II->setIsPoisoned();
+ }
+}
+
+/// HandlePragmaSystemHeader - Implement #pragma GCC system_header. We know
+/// that the whole directive has been parsed.
+void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) {
+ if (isInPrimaryFile()) {
+ Diag(SysHeaderTok, diag::pp_pragma_sysheader_in_main_file);
+ return;
+ }
+
+ // Get the current file lexer we're looking at. Ignore _Pragma 'files' etc.
+ PreprocessorLexer *TheLexer = getCurrentFileLexer();
+
+ // Mark the file as a system header.
+ HeaderInfo.MarkFileSystemHeader(TheLexer->getFileEntry());
+
+ // Notify the client, if desired, that we are in a new source file.
+ if (Callbacks)
+ Callbacks->FileChanged(SysHeaderTok.getLocation(),
+ PPCallbacks::SystemHeaderPragma, SrcMgr::C_System);
+}
+
+/// HandlePragmaDependency - Handle #pragma GCC dependency "foo" blah.
+///
+void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
+ Token FilenameTok;
+ CurPPLexer->LexIncludeFilename(FilenameTok);
+
+ // If the token kind is EOM, the error has already been diagnosed.
+ if (FilenameTok.is(tok::eom))
+ return;
+
+ // Reserve a buffer to get the spelling.
+ llvm::SmallVector<char, 128> FilenameBuffer;
+ FilenameBuffer.resize(FilenameTok.getLength());
+
+ const char *FilenameStart = &FilenameBuffer[0];
+ unsigned Len = getSpelling(FilenameTok, FilenameStart);
+ const char *FilenameEnd = FilenameStart+Len;
+ bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(),
+ FilenameStart, FilenameEnd);
+ // If GetIncludeFilenameSpelling set the start ptr to null, there was an
+ // error.
+ if (FilenameStart == 0)
+ return;
+
+ // Search include directories for this file.
+ const DirectoryLookup *CurDir;
+ const FileEntry *File = LookupFile(FilenameStart, FilenameEnd,
+ isAngled, 0, CurDir);
+ if (File == 0) {
+ Diag(FilenameTok, diag::err_pp_file_not_found)
+ << std::string(FilenameStart, FilenameEnd);
+ return;
+ }
+
+ const FileEntry *CurFile = getCurrentFileLexer()->getFileEntry();
+
+ // If this file is older than the file it depends on, emit a diagnostic.
+ if (CurFile && CurFile->getModificationTime() < File->getModificationTime()) {
+ // Lex tokens at the end of the message and include them in the message.
+ std::string Message;
+ Lex(DependencyTok);
+ while (DependencyTok.isNot(tok::eom)) {
+ Message += getSpelling(DependencyTok) + " ";
+ Lex(DependencyTok);
+ }
+
+ Message.erase(Message.end()-1);
+ Diag(FilenameTok, diag::pp_out_of_date_dependency) << Message;
+ }
+}
+
+/// HandlePragmaComment - Handle the microsoft #pragma comment extension. The
+/// syntax is:
+/// #pragma comment(linker, "foo")
+/// 'linker' is one of five identifiers: compiler, exestr, lib, linker, user.
+/// "foo" is a string, which is fully macro expanded, and permits string
+/// concatenation, embedded escape characters etc. See MSDN for more details.
+void Preprocessor::HandlePragmaComment(Token &Tok) {
+ SourceLocation CommentLoc = Tok.getLocation();
+ Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(CommentLoc, diag::err_pragma_comment_malformed);
+ return;
+ }
+
+ // Read the identifier.
+ Lex(Tok);
+ if (Tok.isNot(tok::identifier)) {
+ Diag(CommentLoc, diag::err_pragma_comment_malformed);
+ return;
+ }
+
+ // Verify that this is one of the 5 whitelisted options.
+ // FIXME: warn that 'exestr' is deprecated.
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (!II->isStr("compiler") && !II->isStr("exestr") && !II->isStr("lib") &&
+ !II->isStr("linker") && !II->isStr("user")) {
+ Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind);
+ return;
+ }
+
+ // Read the optional string if present.
+ Lex(Tok);
+ std::string ArgumentString;
+ if (Tok.is(tok::comma)) {
+ Lex(Tok); // eat the comma.
+
+ // We need at least one string.
+ if (Tok.isNot(tok::string_literal)) {
+ Diag(Tok.getLocation(), diag::err_pragma_comment_malformed);
+ return;
+ }
+
+ // String concatenation allows multiple strings, which can even come from
+ // macro expansion.
+ // "foo " "bar" "Baz"
+ llvm::SmallVector<Token, 4> StrToks;
+ while (Tok.is(tok::string_literal)) {
+ StrToks.push_back(Tok);
+ Lex(Tok);
+ }
+
+ // Concatenate and parse the strings.
+ StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this);
+ assert(!Literal.AnyWide && "Didn't allow wide strings in");
+ if (Literal.hadError)
+ return;
+ if (Literal.Pascal) {
+ Diag(StrToks[0].getLocation(), diag::err_pragma_comment_malformed);
+ return;
+ }
+
+ ArgumentString = std::string(Literal.GetString(),
+ Literal.GetString()+Literal.GetStringLength());
+ }
+
+ // FIXME: If the kind is "compiler" warn if the string is present (it is
+ // ignored).
+ // FIXME: 'lib' requires a comment string.
+ // FIXME: 'linker' requires a comment string, and has a specific list of
+ // things that are allowable.
+
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok.getLocation(), diag::err_pragma_comment_malformed);
+ return;
+ }
+ Lex(Tok); // eat the r_paren.
+
+ if (Tok.isNot(tok::eom)) {
+ Diag(Tok.getLocation(), diag::err_pragma_comment_malformed);
+ return;
+ }
+
+ // If the pragma is lexically sound, notify any interested PPCallbacks.
+ if (Callbacks)
+ Callbacks->PragmaComment(CommentLoc, II, ArgumentString);
+}
+
+
+
+
+/// 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(const char *Namespace,
+ PragmaHandler *Handler) {
+ PragmaNamespace *InsertNS = PragmaHandlers;
+
+ // If this is specified to be in a namespace, step down into it.
+ if (Namespace) {
+ IdentifierInfo *NSID = getIdentifierInfo(Namespace);
+
+ // If there is already a pragma handler with the name of this namespace,
+ // we either have an error (directive with the same name as a namespace) or
+ // we already have the namespace to insert into.
+ if (PragmaHandler *Existing = PragmaHandlers->FindHandler(NSID)) {
+ InsertNS = Existing->getIfNamespace();
+ assert(InsertNS != 0 && "Cannot have a pragma namespace and pragma"
+ " handler with the same name!");
+ } else {
+ // Otherwise, this namespace doesn't exist yet, create and insert the
+ // handler for it.
+ InsertNS = new PragmaNamespace(NSID);
+ PragmaHandlers->AddPragma(InsertNS);
+ }
+ }
+
+ // Check to make sure we don't already have a pragma for this identifier.
+ assert(!InsertNS->FindHandler(Handler->getName()) &&
+ "Pragma handler already exists for this identifier!");
+ InsertNS->AddPragma(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 Preprocessor::RemovePragmaHandler(const char *Namespace,
+ PragmaHandler *Handler) {
+ PragmaNamespace *NS = PragmaHandlers;
+
+ // If this is specified to be in a namespace, step down into it.
+ if (Namespace) {
+ IdentifierInfo *NSID = getIdentifierInfo(Namespace);
+ PragmaHandler *Existing = PragmaHandlers->FindHandler(NSID);
+ assert(Existing && "Namespace containing handler does not exist!");
+
+ NS = Existing->getIfNamespace();
+ assert(NS && "Invalid namespace, registered as a regular pragma handler!");
+ }
+
+ NS->RemovePragmaHandler(Handler);
+
+ // If this is a non-default namespace and it is now empty, remove
+ // it.
+ if (NS != PragmaHandlers && NS->IsEmpty())
+ PragmaHandlers->RemovePragmaHandler(NS);
+}
+
+namespace {
+/// PragmaOnceHandler - "#pragma once" marks the file as atomically included.
+struct PragmaOnceHandler : public PragmaHandler {
+ PragmaOnceHandler(const IdentifierInfo *OnceID) : PragmaHandler(OnceID) {}
+ virtual void HandlePragma(Preprocessor &PP, Token &OnceTok) {
+ PP.CheckEndOfDirective("pragma once");
+ PP.HandlePragmaOnce(OnceTok);
+ }
+};
+
+/// PragmaMarkHandler - "#pragma mark ..." is ignored by the compiler, and the
+/// rest of the line is not lexed.
+struct PragmaMarkHandler : public PragmaHandler {
+ PragmaMarkHandler(const IdentifierInfo *MarkID) : PragmaHandler(MarkID) {}
+ virtual void HandlePragma(Preprocessor &PP, Token &MarkTok) {
+ PP.HandlePragmaMark();
+ }
+};
+
+/// PragmaPoisonHandler - "#pragma poison x" marks x as not usable.
+struct PragmaPoisonHandler : public PragmaHandler {
+ PragmaPoisonHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
+ virtual void HandlePragma(Preprocessor &PP, Token &PoisonTok) {
+ PP.HandlePragmaPoison(PoisonTok);
+ }
+};
+
+/// PragmaSystemHeaderHandler - "#pragma system_header" marks the current file
+/// as a system header, which silences warnings in it.
+struct PragmaSystemHeaderHandler : public PragmaHandler {
+ PragmaSystemHeaderHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
+ virtual void HandlePragma(Preprocessor &PP, Token &SHToken) {
+ PP.HandlePragmaSystemHeader(SHToken);
+ PP.CheckEndOfDirective("pragma");
+ }
+};
+struct PragmaDependencyHandler : public PragmaHandler {
+ PragmaDependencyHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
+ virtual void HandlePragma(Preprocessor &PP, Token &DepToken) {
+ PP.HandlePragmaDependency(DepToken);
+ }
+};
+
+/// PragmaDiagnosticHandler - e.g. '#pragma GCC diagnostic ignored "-Wformat"'
+struct PragmaDiagnosticHandler : public PragmaHandler {
+ PragmaDiagnosticHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
+ virtual void HandlePragma(Preprocessor &PP, Token &DiagToken) {
+ Token Tok;
+ PP.LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid);
+ return;
+ }
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+
+ diag::Mapping Map;
+ if (II->isStr("warning"))
+ Map = diag::MAP_WARNING;
+ else if (II->isStr("error"))
+ Map = diag::MAP_ERROR;
+ else if (II->isStr("ignored"))
+ Map = diag::MAP_IGNORE;
+ else if (II->isStr("fatal"))
+ Map = diag::MAP_FATAL;
+ else {
+ PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid);
+ return;
+ }
+
+ PP.LexUnexpandedToken(Tok);
+
+ // We need at least one string.
+ if (Tok.isNot(tok::string_literal)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_diagnostic_invalid_token);
+ return;
+ }
+
+ // String concatenation allows multiple strings, which can even come from
+ // macro expansion.
+ // "foo " "bar" "Baz"
+ llvm::SmallVector<Token, 4> StrToks;
+ while (Tok.is(tok::string_literal)) {
+ StrToks.push_back(Tok);
+ PP.LexUnexpandedToken(Tok);
+ }
+
+ if (Tok.isNot(tok::eom)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_diagnostic_invalid_token);
+ return;
+ }
+
+ // Concatenate and parse the strings.
+ StringLiteralParser Literal(&StrToks[0], StrToks.size(), PP);
+ assert(!Literal.AnyWide && "Didn't allow wide strings in");
+ if (Literal.hadError)
+ return;
+ if (Literal.Pascal) {
+ PP.Diag(StrToks[0].getLocation(), diag::warn_pragma_diagnostic_invalid);
+ return;
+ }
+
+ std::string WarningName(Literal.GetString(),
+ Literal.GetString()+Literal.GetStringLength());
+
+ if (WarningName.size() < 3 || WarningName[0] != '-' ||
+ WarningName[1] != 'W') {
+ PP.Diag(StrToks[0].getLocation(),
+ diag::warn_pragma_diagnostic_invalid_option);
+ return;
+ }
+
+ if (PP.getDiagnostics().setDiagnosticGroupMapping(WarningName.c_str()+2,
+ Map))
+ PP.Diag(StrToks[0].getLocation(),
+ diag::warn_pragma_diagnostic_unknown_warning) << WarningName;
+ }
+};
+
+/// PragmaCommentHandler - "#pragma comment ...".
+struct PragmaCommentHandler : public PragmaHandler {
+ PragmaCommentHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
+ virtual void HandlePragma(Preprocessor &PP, Token &CommentTok) {
+ PP.HandlePragmaComment(CommentTok);
+ }
+};
+
+// Pragma STDC implementations.
+
+enum STDCSetting {
+ STDC_ON, STDC_OFF, STDC_DEFAULT, STDC_INVALID
+};
+
+static STDCSetting LexOnOffSwitch(Preprocessor &PP) {
+ Token Tok;
+ PP.LexUnexpandedToken(Tok);
+
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok, diag::ext_stdc_pragma_syntax);
+ return STDC_INVALID;
+ }
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ STDCSetting Result;
+ if (II->isStr("ON"))
+ Result = STDC_ON;
+ else if (II->isStr("OFF"))
+ Result = STDC_OFF;
+ else if (II->isStr("DEFAULT"))
+ Result = STDC_DEFAULT;
+ else {
+ PP.Diag(Tok, diag::ext_stdc_pragma_syntax);
+ return STDC_INVALID;
+ }
+
+ // Verify that this is followed by EOM.
+ PP.LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::eom))
+ PP.Diag(Tok, diag::ext_stdc_pragma_syntax_eom);
+ return Result;
+}
+
+/// PragmaSTDC_FP_CONTRACTHandler - "#pragma STDC FP_CONTRACT ...".
+struct PragmaSTDC_FP_CONTRACTHandler : public PragmaHandler {
+ PragmaSTDC_FP_CONTRACTHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
+ virtual void HandlePragma(Preprocessor &PP, Token &Tok) {
+ // We just ignore the setting of FP_CONTRACT. Since we don't do contractions
+ // at all, our default is OFF and setting it to ON is an optimization hint
+ // we can safely ignore. When we support -ffma or something, we would need
+ // to diagnose that we are ignoring FMA.
+ LexOnOffSwitch(PP);
+ }
+};
+
+/// PragmaSTDC_FENV_ACCESSHandler - "#pragma STDC FENV_ACCESS ...".
+struct PragmaSTDC_FENV_ACCESSHandler : public PragmaHandler {
+ PragmaSTDC_FENV_ACCESSHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {}
+ virtual void HandlePragma(Preprocessor &PP, Token &Tok) {
+ if (LexOnOffSwitch(PP) == STDC_ON)
+ PP.Diag(Tok, diag::warn_stdc_fenv_access_not_supported);
+ }
+};
+
+/// PragmaSTDC_CX_LIMITED_RANGEHandler - "#pragma STDC CX_LIMITED_RANGE ...".
+struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler {
+ PragmaSTDC_CX_LIMITED_RANGEHandler(const IdentifierInfo *ID)
+ : PragmaHandler(ID) {}
+ virtual void HandlePragma(Preprocessor &PP, Token &Tok) {
+ LexOnOffSwitch(PP);
+ }
+};
+
+/// PragmaSTDC_UnknownHandler - "#pragma STDC ...".
+struct PragmaSTDC_UnknownHandler : public PragmaHandler {
+ PragmaSTDC_UnknownHandler() : PragmaHandler(0) {}
+ virtual void HandlePragma(Preprocessor &PP, Token &UnknownTok) {
+ // C99 6.10.6p2, unknown forms are not allowed.
+ PP.Diag(UnknownTok, diag::ext_stdc_pragma_ignored);
+ }
+};
+
+} // end anonymous namespace
+
+
+/// RegisterBuiltinPragmas - Install the standard preprocessor pragmas:
+/// #pragma GCC poison/system_header/dependency and #pragma once.
+void Preprocessor::RegisterBuiltinPragmas() {
+ AddPragmaHandler(0, new PragmaOnceHandler(getIdentifierInfo("once")));
+ AddPragmaHandler(0, new PragmaMarkHandler(getIdentifierInfo("mark")));
+
+ // #pragma GCC ...
+ AddPragmaHandler("GCC", new PragmaPoisonHandler(getIdentifierInfo("poison")));
+ AddPragmaHandler("GCC", new PragmaSystemHeaderHandler(
+ getIdentifierInfo("system_header")));
+ AddPragmaHandler("GCC", new PragmaDependencyHandler(
+ getIdentifierInfo("dependency")));
+ AddPragmaHandler("GCC", new PragmaDiagnosticHandler(
+ getIdentifierInfo("diagnostic")));
+ // #pragma clang ...
+ AddPragmaHandler("clang", new PragmaPoisonHandler(
+ getIdentifierInfo("poison")));
+ AddPragmaHandler("clang", new PragmaSystemHeaderHandler(
+ getIdentifierInfo("system_header")));
+ AddPragmaHandler("clang", new PragmaDependencyHandler(
+ getIdentifierInfo("dependency")));
+ AddPragmaHandler("clang", new PragmaDiagnosticHandler(
+ getIdentifierInfo("diagnostic")));
+
+ AddPragmaHandler("STDC", new PragmaSTDC_FP_CONTRACTHandler(
+ getIdentifierInfo("FP_CONTRACT")));
+ AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler(
+ getIdentifierInfo("FENV_ACCESS")));
+ AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler(
+ getIdentifierInfo("CX_LIMITED_RANGE")));
+ AddPragmaHandler("STDC", new PragmaSTDC_UnknownHandler());
+
+ // MS extensions.
+ if (Features.Microsoft)
+ AddPragmaHandler(0, new PragmaCommentHandler(getIdentifierInfo("comment")));
+}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
new file mode 100644
index 000000000000..0a7d92eb83cf
--- /dev/null
+++ b/lib/Lex/Preprocessor.cpp
@@ -0,0 +1,478 @@
+//===--- Preprocess.cpp - C Language Family Preprocessor Implementation ---===//
+//
+// 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 Preprocessor interface.
+//
+//===----------------------------------------------------------------------===//
+//
+// Options to support:
+// -H - Print the name of each header file used.
+// -d[DNI] - Dump various things.
+// -fworking-directory - #line's with preprocessor's working dir.
+// -fpreprocessed
+// -dependency-file,-M,-MM,-MF,-MG,-MP,-MT,-MQ,-MD,-MMD
+// -W*
+// -w
+//
+// Messages to emit:
+// "Multiple include guards may be useful for:\n"
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Pragma.h"
+#include "clang/Lex/ScratchBuffer.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Streams.h"
+#include <cstdio>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+
+PreprocessorFactory::~PreprocessorFactory() {}
+
+Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
+ TargetInfo &target, SourceManager &SM,
+ HeaderSearch &Headers,
+ IdentifierInfoLookup* IILookup)
+ : Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()),
+ SourceMgr(SM), HeaderInfo(Headers), Identifiers(opts, IILookup),
+ CurPPLexer(0), CurDirLookup(0), Callbacks(0) {
+ ScratchBuf = new ScratchBuffer(SourceMgr);
+ CounterValue = 0; // __COUNTER__ starts at 0.
+
+ // Clear stats.
+ NumDirectives = NumDefined = NumUndefined = NumPragma = 0;
+ NumIf = NumElse = NumEndif = 0;
+ NumEnteredSourceFiles = 0;
+ NumMacroExpanded = NumFnMacroExpanded = NumBuiltinMacroExpanded = 0;
+ NumFastMacroExpanded = NumTokenPaste = NumFastTokenPaste = 0;
+ MaxIncludeStackDepth = 0;
+ NumSkipped = 0;
+
+ // Default to discarding comments.
+ KeepComments = false;
+ KeepMacroComments = false;
+
+ // Macro expansion is enabled.
+ DisableMacroExpansion = false;
+ InMacroArgs = false;
+ NumCachedTokenLexers = 0;
+
+ CachedLexPos = 0;
+
+ // "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();
+
+ // Initialize the pragma handlers.
+ PragmaHandlers = new PragmaNamespace(0);
+ RegisterBuiltinPragmas();
+
+ // Initialize builtin macros like __LINE__ and friends.
+ RegisterBuiltinMacros();
+}
+
+Preprocessor::~Preprocessor() {
+ assert(BacktrackPositions.empty() && "EnableBacktrack/Backtrack imbalance!");
+
+ while (!IncludeMacroStack.empty()) {
+ delete IncludeMacroStack.back().TheLexer;
+ delete IncludeMacroStack.back().TheTokenLexer;
+ IncludeMacroStack.pop_back();
+ }
+
+ // Free any macro definitions.
+ for (llvm::DenseMap<IdentifierInfo*, MacroInfo*>::iterator I =
+ Macros.begin(), E = Macros.end(); I != E; ++I) {
+ // We don't need to free the MacroInfo objects directly. These
+ // will be released when the BumpPtrAllocator 'BP' object gets
+ // destroyed. We still need to run the dstor, however, to free
+ // memory alocated by MacroInfo.
+ I->second->Destroy(BP);
+ I->first->setHasMacroDefinition(false);
+ }
+
+ // Free any cached macro expanders.
+ for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i)
+ delete TokenLexerCache[i];
+
+ // Release pragma information.
+ delete PragmaHandlers;
+
+ // Delete the scratch buffer info.
+ delete ScratchBuf;
+
+ delete Callbacks;
+}
+
+void Preprocessor::setPTHManager(PTHManager* pm) {
+ PTH.reset(pm);
+ FileMgr.setStatCache(PTH->createStatCache());
+}
+
+void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const {
+ llvm::cerr << tok::getTokenName(Tok.getKind()) << " '"
+ << getSpelling(Tok) << "'";
+
+ if (!DumpFlags) return;
+
+ llvm::cerr << "\t";
+ if (Tok.isAtStartOfLine())
+ llvm::cerr << " [StartOfLine]";
+ if (Tok.hasLeadingSpace())
+ llvm::cerr << " [LeadingSpace]";
+ if (Tok.isExpandDisabled())
+ llvm::cerr << " [ExpandDisabled]";
+ if (Tok.needsCleaning()) {
+ const char *Start = SourceMgr.getCharacterData(Tok.getLocation());
+ llvm::cerr << " [UnClean='" << std::string(Start, Start+Tok.getLength())
+ << "']";
+ }
+
+ llvm::cerr << "\tLoc=<";
+ DumpLocation(Tok.getLocation());
+ llvm::cerr << ">";
+}
+
+void Preprocessor::DumpLocation(SourceLocation Loc) const {
+ Loc.dump(SourceMgr);
+}
+
+void Preprocessor::DumpMacro(const MacroInfo &MI) const {
+ llvm::cerr << "MACRO: ";
+ for (unsigned i = 0, e = MI.getNumTokens(); i != e; ++i) {
+ DumpToken(MI.getReplacementToken(i));
+ llvm::cerr << " ";
+ }
+ llvm::cerr << "\n";
+}
+
+void Preprocessor::PrintStats() {
+ llvm::cerr << "\n*** Preprocessor Stats:\n";
+ llvm::cerr << NumDirectives << " directives found:\n";
+ llvm::cerr << " " << NumDefined << " #define.\n";
+ llvm::cerr << " " << NumUndefined << " #undef.\n";
+ llvm::cerr << " #include/#include_next/#import:\n";
+ llvm::cerr << " " << NumEnteredSourceFiles << " source files entered.\n";
+ llvm::cerr << " " << MaxIncludeStackDepth << " max include stack depth\n";
+ llvm::cerr << " " << NumIf << " #if/#ifndef/#ifdef.\n";
+ llvm::cerr << " " << NumElse << " #else/#elif.\n";
+ llvm::cerr << " " << NumEndif << " #endif.\n";
+ llvm::cerr << " " << NumPragma << " #pragma.\n";
+ llvm::cerr << NumSkipped << " #if/#ifndef#ifdef regions skipped\n";
+
+ llvm::cerr << NumMacroExpanded << "/" << NumFnMacroExpanded << "/"
+ << NumBuiltinMacroExpanded << " obj/fn/builtin macros expanded, "
+ << NumFastMacroExpanded << " on the fast path.\n";
+ llvm::cerr << (NumFastTokenPaste+NumTokenPaste)
+ << " token paste (##) operations performed, "
+ << NumFastTokenPaste << " on the fast path.\n";
+}
+
+//===----------------------------------------------------------------------===//
+// Token Spelling
+//===----------------------------------------------------------------------===//
+
+
+/// getSpelling() - Return the 'spelling' of this token. The spelling of a
+/// token are the characters used to represent the token in the source file
+/// after trigraph expansion and escaped-newline folding. In particular, this
+/// wants to get the true, uncanonicalized, spelling of things like digraphs
+/// UCNs, etc.
+std::string Preprocessor::getSpelling(const Token &Tok) const {
+ assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
+
+ // If this token contains nothing interesting, return it directly.
+ const char* TokStart = SourceMgr.getCharacterData(Tok.getLocation());
+ if (!Tok.needsCleaning())
+ return std::string(TokStart, TokStart+Tok.getLength());
+
+ std::string Result;
+ Result.reserve(Tok.getLength());
+
+ // Otherwise, hard case, relex the characters into the string.
+ for (const char *Ptr = TokStart, *End = TokStart+Tok.getLength();
+ Ptr != End; ) {
+ unsigned CharSize;
+ Result.push_back(Lexer::getCharAndSizeNoWarn(Ptr, CharSize, Features));
+ Ptr += CharSize;
+ }
+ assert(Result.size() != unsigned(Tok.getLength()) &&
+ "NeedsCleaning flag set on something that didn't need cleaning!");
+ return Result;
+}
+
+/// getSpelling - This method is used to get the spelling of a token into a
+/// preallocated buffer, instead of as an std::string. The caller is required
+/// to allocate enough space for the token, which is guaranteed to be at least
+/// Tok.getLength() bytes long. The actual length of the token is returned.
+///
+/// Note that this method may do two possible things: it may either fill in
+/// the buffer specified with characters, or it may *change the input pointer*
+/// to point to a constant buffer with the data already in it (avoiding a
+/// copy). The caller is not allowed to modify the returned buffer pointer
+/// if an internal buffer is returned.
+unsigned Preprocessor::getSpelling(const Token &Tok,
+ const char *&Buffer) const {
+ assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
+
+ // If this token is an identifier, just return the string from the identifier
+ // table, which is very quick.
+ if (const IdentifierInfo *II = Tok.getIdentifierInfo()) {
+ Buffer = II->getName();
+ return II->getLength();
+ }
+
+ // Otherwise, compute the start of the token in the input lexer buffer.
+ const char *TokStart = 0;
+
+ if (Tok.isLiteral())
+ TokStart = Tok.getLiteralData();
+
+ if (TokStart == 0)
+ TokStart = SourceMgr.getCharacterData(Tok.getLocation());
+
+ // If this token contains nothing interesting, return it directly.
+ if (!Tok.needsCleaning()) {
+ Buffer = TokStart;
+ return Tok.getLength();
+ }
+
+ // Otherwise, hard case, relex the characters into the string.
+ char *OutBuf = const_cast<char*>(Buffer);
+ for (const char *Ptr = TokStart, *End = TokStart+Tok.getLength();
+ Ptr != End; ) {
+ unsigned CharSize;
+ *OutBuf++ = Lexer::getCharAndSizeNoWarn(Ptr, CharSize, Features);
+ Ptr += CharSize;
+ }
+ assert(unsigned(OutBuf-Buffer) != Tok.getLength() &&
+ "NeedsCleaning flag set on something that didn't need cleaning!");
+
+ return OutBuf-Buffer;
+}
+
+/// 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 InstantiationLoc) {
+ Tok.setLength(Len);
+
+ const char *DestPtr;
+ SourceLocation Loc = ScratchBuf->getToken(Buf, Len, DestPtr);
+
+ if (InstantiationLoc.isValid())
+ Loc = SourceMgr.createInstantiationLoc(Loc, InstantiationLoc,
+ InstantiationLoc, Len);
+ Tok.setLocation(Loc);
+
+ // If this is a literal token, set the pointer data.
+ if (Tok.isLiteral())
+ Tok.setLiteralData(DestPtr);
+}
+
+
+/// AdvanceToTokenCharacter - Given a location that specifies the start of a
+/// token, return a new location that specifies a character within the token.
+SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart,
+ unsigned CharNo) {
+ // Figure out how many physical characters away the specified instantiation
+ // character is. This needs to take into consideration newlines and
+ // trigraphs.
+ const char *TokPtr = SourceMgr.getCharacterData(TokStart);
+
+ // If they request the first char of the token, we're trivially done.
+ if (CharNo == 0 && Lexer::isObviouslySimpleCharacter(*TokPtr))
+ return TokStart;
+
+ unsigned PhysOffset = 0;
+
+ // The usual case is that tokens don't contain anything interesting. Skip
+ // over the uninteresting characters. If a token only consists of simple
+ // chars, this method is extremely fast.
+ while (Lexer::isObviouslySimpleCharacter(*TokPtr)) {
+ if (CharNo == 0)
+ return TokStart.getFileLocWithOffset(PhysOffset);
+ ++TokPtr, --CharNo, ++PhysOffset;
+ }
+
+ // If we have a character that may be a trigraph or escaped newline, use a
+ // lexer to parse it correctly.
+ for (; CharNo; --CharNo) {
+ unsigned Size;
+ Lexer::getCharAndSizeNoWarn(TokPtr, Size, Features);
+ TokPtr += Size;
+ PhysOffset += Size;
+ }
+
+ // Final detail: if we end up on an escaped newline, we want to return the
+ // location of the actual byte of the token. For example foo\<newline>bar
+ // advanced by 3 should return the location of b, not of \\. One compounding
+ // detail of this is that the escape may be made by a trigraph.
+ if (!Lexer::isObviouslySimpleCharacter(*TokPtr))
+ PhysOffset = Lexer::SkipEscapedNewLines(TokPtr)-TokPtr;
+
+ return TokStart.getFileLocWithOffset(PhysOffset);
+}
+
+/// \brief Computes the source location just past the end of the
+/// token at this source location.
+///
+/// This routine can be used to produce a source location that
+/// points just past the end of the token referenced by \p Loc, and
+/// is generally used when a diagnostic needs to point just after a
+/// token where it expected something different that it received. If
+/// the returned source location would not be meaningful (e.g., if
+/// it points into a macro), this routine returns an invalid
+/// source location.
+SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc) {
+ if (Loc.isInvalid() || !Loc.isFileID())
+ return SourceLocation();
+
+ unsigned Len = Lexer::MeasureTokenLength(Loc, getSourceManager(), Features);
+ return AdvanceToTokenCharacter(Loc, Len);
+}
+
+
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Initialization Methods
+//===----------------------------------------------------------------------===//
+
+
+/// EnterMainSourceFile - Enter the specified FileID as the main source file,
+/// which implicitly adds the builtin defines etc.
+void Preprocessor::EnterMainSourceFile() {
+ // We do not allow the preprocessor to reenter the main file. Doing so will
+ // cause FileID's to accumulate information from both runs (e.g. #line
+ // information) and predefined macros aren't guaranteed to be set properly.
+ assert(NumEnteredSourceFiles == 0 && "Cannot reenter the main file!");
+ FileID MainFileID = SourceMgr.getMainFileID();
+
+ // Enter the main file source buffer.
+ EnterSourceFile(MainFileID, 0);
+
+ // Tell the header info that the main file was entered. If the file is later
+ // #imported, it won't be re-entered.
+ if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID))
+ HeaderInfo.IncrementIncludeCount(FE);
+
+ std::vector<char> PrologFile;
+ PrologFile.reserve(4080);
+
+ // FIXME: Don't make a copy.
+ PrologFile.insert(PrologFile.end(), Predefines.begin(), Predefines.end());
+
+ // Memory buffer must end with a null byte!
+ PrologFile.push_back(0);
+
+ // Now that we have emitted the predefined macros, #includes, etc into
+ // PrologFile, preprocess it to populate the initial preprocessor state.
+ llvm::MemoryBuffer *SB =
+ llvm::MemoryBuffer::getMemBufferCopy(&PrologFile.front(),&PrologFile.back(),
+ "<built-in>");
+ assert(SB && "Cannot fail to create predefined source buffer");
+ FileID FID = SourceMgr.createFileIDForMemBuffer(SB);
+ assert(!FID.isInvalid() && "Could not create FileID for predefines?");
+
+ // Start parsing the predefines.
+ EnterSourceFile(FID, 0);
+}
+
+
+//===----------------------------------------------------------------------===//
+// Lexer Event Handling.
+//===----------------------------------------------------------------------===//
+
+/// LookUpIdentifierInfo - Given a tok::identifier token, look up the
+/// identifier information for the token and install it into the token.
+IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier,
+ const char *BufPtr) {
+ assert(Identifier.is(tok::identifier) && "Not an identifier!");
+ assert(Identifier.getIdentifierInfo() == 0 && "Identinfo already exists!");
+
+ // Look up this token, see if it is a macro, or if it is a language keyword.
+ IdentifierInfo *II;
+ if (BufPtr && !Identifier.needsCleaning()) {
+ // No cleaning needed, just use the characters from the lexed buffer.
+ II = getIdentifierInfo(BufPtr, BufPtr+Identifier.getLength());
+ } else {
+ // Cleaning needed, alloca a buffer, clean into it, then use the buffer.
+ llvm::SmallVector<char, 64> IdentifierBuffer;
+ IdentifierBuffer.resize(Identifier.getLength());
+ const char *TmpBuf = &IdentifierBuffer[0];
+ unsigned Size = getSpelling(Identifier, TmpBuf);
+ II = getIdentifierInfo(TmpBuf, TmpBuf+Size);
+ }
+ Identifier.setIdentifierInfo(II);
+ return II;
+}
+
+
+/// HandleIdentifier - This callback is invoked when the lexer reads an
+/// identifier. This callback looks up the identifier in the map and/or
+/// potentially macro expands it or turns it into a named token (like 'for').
+///
+/// Note that callers of this method are guarded by checking the
+/// IdentifierInfo's 'isHandleIdentifierCase' bit. If this method changes, the
+/// IdentifierInfo methods that compute these properties will need to change to
+/// match.
+void Preprocessor::HandleIdentifier(Token &Identifier) {
+ assert(Identifier.getIdentifierInfo() &&
+ "Can't handle identifiers without identifier info!");
+
+ IdentifierInfo &II = *Identifier.getIdentifierInfo();
+
+ // If this identifier was poisoned, and if it was not produced from a macro
+ // expansion, emit an error.
+ if (II.isPoisoned() && CurPPLexer) {
+ if (&II != Ident__VA_ARGS__) // We warn about __VA_ARGS__ with poisoning.
+ Diag(Identifier, diag::err_pp_used_poisoned_id);
+ else
+ Diag(Identifier, diag::ext_pp_bad_vaargs_use);
+ }
+
+ // If this is a macro to be expanded, do it.
+ if (MacroInfo *MI = getMacroInfo(&II)) {
+ if (!DisableMacroExpansion && !Identifier.isExpandDisabled()) {
+ if (MI->isEnabled()) {
+ if (!HandleMacroExpandedIdentifier(Identifier, MI))
+ return;
+ } else {
+ // C99 6.10.3.4p2 says that a disabled macro may never again be
+ // expanded, even if it's in a context where it could be expanded in the
+ // future.
+ Identifier.setFlag(Token::DisableExpand);
+ }
+ }
+ }
+
+ // 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.
+ if (II.isCPlusPlusOperatorKeyword())
+ Identifier.setIdentifierInfo(0);
+
+ // If this is an extension token, diagnose its use.
+ // We avoid diagnosing tokens that originate from macro definitions.
+ // FIXME: This warning is disabled in cases where it shouldn't be,
+ // like "#define TY typeof", "TY(1) x".
+ if (II.isExtensionToken() && !DisableMacroExpansion)
+ Diag(Identifier, diag::ext_token_used);
+}
diff --git a/lib/Lex/PreprocessorLexer.cpp b/lib/Lex/PreprocessorLexer.cpp
new file mode 100644
index 000000000000..f9dfad9c808e
--- /dev/null
+++ b/lib/Lex/PreprocessorLexer.cpp
@@ -0,0 +1,45 @@
+//===--- PreprocessorLexer.cpp - C Language Family Lexer ------------------===//
+//
+// 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 PreprocessorLexer and Token interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/PreprocessorLexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+using namespace clang;
+
+/// LexIncludeFilename - After the preprocessor has parsed a #include, lex and
+/// (potentially) macro expand the filename.
+void PreprocessorLexer::LexIncludeFilename(Token &FilenameTok) {
+ assert(ParsingPreprocessorDirective &&
+ ParsingFilename == false &&
+ "Must be in a preprocessing directive!");
+
+ // We are now parsing a filename!
+ ParsingFilename = true;
+
+ // Lex the filename.
+ IndirectLex(FilenameTok);
+
+ // We should have obtained the filename now.
+ ParsingFilename = false;
+
+ // No filename?
+ if (FilenameTok.is(tok::eom))
+ PP->Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
+}
+
+/// getFileEntry - Return the FileEntry corresponding to this FileID. Like
+/// getFileID(), this only works for lexers with attached preprocessors.
+const FileEntry *PreprocessorLexer::getFileEntry() const {
+ return PP->getSourceManager().getFileEntryForID(getFileID());
+}
diff --git a/lib/Lex/ScratchBuffer.cpp b/lib/Lex/ScratchBuffer.cpp
new file mode 100644
index 000000000000..28f3d7ff45b2
--- /dev/null
+++ b/lib/Lex/ScratchBuffer.cpp
@@ -0,0 +1,73 @@
+//===--- ScratchBuffer.cpp - Scratch space for forming tokens -------------===//
+//
+// 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 ScratchBuffer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/ScratchBuffer.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <cstring>
+using namespace clang;
+
+// ScratchBufSize - The size of each chunk of scratch memory. Slightly less
+//than a page, almost certainly enough for anything. :)
+static const unsigned ScratchBufSize = 4060;
+
+ScratchBuffer::ScratchBuffer(SourceManager &SM) : SourceMgr(SM), CurBuffer(0) {
+ // Set BytesUsed so that the first call to getToken will require an alloc.
+ BytesUsed = ScratchBufSize;
+}
+
+/// getToken - Splat the specified text into a temporary MemoryBuffer and
+/// return a SourceLocation that refers to the token. This is just like the
+/// method below, but returns a location that indicates the physloc of the
+/// token.
+SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len,
+ const char *&DestPtr) {
+ if (BytesUsed+Len+2 > ScratchBufSize)
+ AllocScratchBuffer(Len+2);
+
+ // Prefix the token with a \n, so that it looks like it is the first thing on
+ // its own virtual line in caret diagnostics.
+ CurBuffer[BytesUsed++] = '\n';
+
+ // Return a pointer to the character data.
+ DestPtr = CurBuffer+BytesUsed;
+
+ // Copy the token data into the buffer.
+ memcpy(CurBuffer+BytesUsed, Buf, Len);
+
+ // Remember that we used these bytes.
+ BytesUsed += Len+1;
+
+ // Add a NUL terminator to the token. This keeps the tokens separated, in
+ // case they get relexed, and puts them on their own virtual lines in case a
+ // diagnostic points to one.
+ CurBuffer[BytesUsed-1] = '\0';
+
+ return BufferStartLoc.getFileLocWithOffset(BytesUsed-Len-1);
+}
+
+void ScratchBuffer::AllocScratchBuffer(unsigned RequestLen) {
+ // Only pay attention to the requested length if it is larger than our default
+ // page size. If it is, we allocate an entire chunk for it. This is to
+ // support gigantic tokens, which almost certainly won't happen. :)
+ if (RequestLen < ScratchBufSize)
+ RequestLen = ScratchBufSize;
+
+ llvm::MemoryBuffer *Buf =
+ llvm::MemoryBuffer::getNewMemBuffer(RequestLen, "<scratch space>");
+ FileID FID = SourceMgr.createFileIDForMemBuffer(Buf);
+ BufferStartLoc = SourceMgr.getLocForStartOfFile(FID);
+ CurBuffer = const_cast<char*>(Buf->getBufferStart());
+ BytesUsed = 1;
+ CurBuffer[0] = '0'; // Start out with a \0 for cleanliness.
+}
diff --git a/lib/Lex/TokenConcatenation.cpp b/lib/Lex/TokenConcatenation.cpp
new file mode 100644
index 000000000000..ab989cafc156
--- /dev/null
+++ b/lib/Lex/TokenConcatenation.cpp
@@ -0,0 +1,219 @@
+//===--- TokenConcatenation.cpp - Token Concatenation Avoidance -----------===//
+//
+// 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 TokenConcatenation class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/TokenConcatenation.h"
+#include "clang/Lex/Preprocessor.h"
+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';
+ }
+
+ if (Tok.getLength() < 256) {
+ char Buffer[256];
+ const char *TokPtr = Buffer;
+ PP.getSpelling(Tok, TokPtr);
+ return TokPtr[0] == 'L';
+ }
+
+ return PP.getSpelling(Tok)[0] == 'L';
+}
+
+/// IsIdentifierL - Return true if the spelling of this token is literally
+/// 'L'.
+bool TokenConcatenation::IsIdentifierL(const Token &Tok) const {
+ if (!Tok.needsCleaning()) {
+ if (Tok.getLength() != 1)
+ return false;
+ SourceManager &SM = PP.getSourceManager();
+ return *SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation())) == 'L';
+ }
+
+ if (Tok.getLength() < 256) {
+ char Buffer[256];
+ const char *TokPtr = Buffer;
+ if (PP.getSpelling(Tok, TokPtr) != 1)
+ return false;
+ return TokPtr[0] == 'L';
+ }
+
+ return PP.getSpelling(Tok) == "L";
+}
+
+TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) {
+ memset(TokenInfo, 0, sizeof(TokenInfo));
+
+ // These tokens have custom code in AvoidConcat.
+ TokenInfo[tok::identifier ] |= aci_custom;
+ TokenInfo[tok::numeric_constant] |= aci_custom_firstchar;
+ TokenInfo[tok::period ] |= aci_custom_firstchar;
+ TokenInfo[tok::amp ] |= aci_custom_firstchar;
+ TokenInfo[tok::plus ] |= aci_custom_firstchar;
+ TokenInfo[tok::minus ] |= aci_custom_firstchar;
+ TokenInfo[tok::slash ] |= aci_custom_firstchar;
+ TokenInfo[tok::less ] |= aci_custom_firstchar;
+ TokenInfo[tok::greater ] |= aci_custom_firstchar;
+ TokenInfo[tok::pipe ] |= aci_custom_firstchar;
+ TokenInfo[tok::percent ] |= aci_custom_firstchar;
+ TokenInfo[tok::colon ] |= aci_custom_firstchar;
+ TokenInfo[tok::hash ] |= aci_custom_firstchar;
+ TokenInfo[tok::arrow ] |= aci_custom_firstchar;
+
+ // These tokens change behavior if followed by an '='.
+ TokenInfo[tok::amp ] |= aci_avoid_equal; // &=
+ TokenInfo[tok::plus ] |= aci_avoid_equal; // +=
+ TokenInfo[tok::minus ] |= aci_avoid_equal; // -=
+ TokenInfo[tok::slash ] |= aci_avoid_equal; // /=
+ TokenInfo[tok::less ] |= aci_avoid_equal; // <=
+ TokenInfo[tok::greater ] |= aci_avoid_equal; // >=
+ TokenInfo[tok::pipe ] |= aci_avoid_equal; // |=
+ TokenInfo[tok::percent ] |= aci_avoid_equal; // %=
+ TokenInfo[tok::star ] |= aci_avoid_equal; // *=
+ TokenInfo[tok::exclaim ] |= aci_avoid_equal; // !=
+ TokenInfo[tok::lessless ] |= aci_avoid_equal; // <<=
+ TokenInfo[tok::greaterequal] |= aci_avoid_equal; // >>=
+ TokenInfo[tok::caret ] |= aci_avoid_equal; // ^=
+ TokenInfo[tok::equal ] |= aci_avoid_equal; // ==
+}
+
+/// GetFirstChar - Get the first character of the token \arg Tok,
+/// avoiding calls to getSpelling where possible.
+static char GetFirstChar(Preprocessor &PP, const Token &Tok) {
+ if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
+ // Avoid spelling identifiers, the most common form of token.
+ return II->getName()[0];
+ } else if (!Tok.needsCleaning()) {
+ if (Tok.isLiteral() && Tok.getLiteralData()) {
+ return *Tok.getLiteralData();
+ } else {
+ SourceManager &SM = PP.getSourceManager();
+ return *SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation()));
+ }
+ } else if (Tok.getLength() < 256) {
+ char Buffer[256];
+ const char *TokPtr = Buffer;
+ PP.getSpelling(Tok, TokPtr);
+ return TokPtr[0];
+ } else {
+ return PP.getSpelling(Tok)[0];
+ }
+}
+
+/// AvoidConcat - If printing PrevTok immediately followed by Tok would cause
+/// the two individual tokens to be lexed as a single token, return true
+/// (which causes a space to be printed between them). This allows the output
+/// of -E mode to be lexed to the same token stream as lexing the input
+/// directly would.
+///
+/// This code must conservatively return true if it doesn't want to be 100%
+/// accurate. This will cause the output to include extra space characters,
+/// but the resulting output won't have incorrect concatenations going on.
+/// Examples include "..", which we print with a space between, because we
+/// don't want to track enough to tell "x.." from "...".
+bool TokenConcatenation::AvoidConcat(const Token &PrevTok,
+ const Token &Tok) const {
+ // First, check to see if the tokens were directly adjacent in the original
+ // source. If they were, it must be okay to stick them together: if there
+ // were an issue, the tokens would have been lexed differently.
+ if (PrevTok.getLocation().isFileID() && Tok.getLocation().isFileID() &&
+ PrevTok.getLocation().getFileLocWithOffset(PrevTok.getLength()) ==
+ Tok.getLocation())
+ return false;
+
+ tok::TokenKind PrevKind = PrevTok.getKind();
+ if (PrevTok.getIdentifierInfo()) // Language keyword or named operator.
+ PrevKind = tok::identifier;
+
+ // Look up information on when we should avoid concatenation with prevtok.
+ unsigned ConcatInfo = TokenInfo[PrevKind];
+
+ // If prevtok never causes a problem for anything after it, return quickly.
+ if (ConcatInfo == 0) return false;
+
+ if (ConcatInfo & aci_avoid_equal) {
+ // If the next token is '=' or '==', avoid concatenation.
+ if (Tok.is(tok::equal) || Tok.is(tok::equalequal))
+ return true;
+ ConcatInfo &= ~aci_avoid_equal;
+ }
+
+ if (ConcatInfo == 0) return false;
+
+ // Basic algorithm: we look at the first character of the second token, and
+ // determine whether it, if appended to the first token, would form (or
+ // would contribute) to a larger token if concatenated.
+ char FirstChar = 0;
+ if (ConcatInfo & aci_custom) {
+ // If the token does not need to know the first character, don't get it.
+ } else {
+ FirstChar = GetFirstChar(PP, Tok);
+ }
+
+ switch (PrevKind) {
+ default: assert(0 && "InitAvoidConcatTokenInfo built wrong");
+ case tok::identifier: // id+id or id+number or id+L"foo".
+ // id+'.'... will not append.
+ 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)*/)
+ 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);
+ case tok::numeric_constant:
+ return isalnum(FirstChar) || Tok.is(tok::numeric_constant) ||
+ FirstChar == '+' || FirstChar == '-' || FirstChar == '.';
+ case tok::period: // ..., .*, .1234
+ return FirstChar == '.' || isdigit(FirstChar) || FirstChar == '*';
+ case tok::amp: // &&
+ return FirstChar == '&';
+ case tok::plus: // ++
+ return FirstChar == '+';
+ case tok::minus: // --, ->, ->*
+ return FirstChar == '-' || FirstChar == '>';
+ case tok::slash: //, /*, //
+ return FirstChar == '*' || FirstChar == '/';
+ case tok::less: // <<, <<=, <:, <%
+ return FirstChar == '<' || FirstChar == ':' || FirstChar == '%';
+ case tok::greater: // >>, >>=
+ return FirstChar == '>';
+ case tok::pipe: // ||
+ return FirstChar == '|';
+ case tok::percent: // %>, %:
+ return FirstChar == '>' || FirstChar == ':';
+ case tok::colon: // ::, :>
+ return FirstChar == ':' ||FirstChar == '>';
+ case tok::hash: // ##, #@, %:%:
+ return FirstChar == '#' || FirstChar == '@' || FirstChar == '%';
+ case tok::arrow: // ->*
+ return FirstChar == '*';
+ }
+}
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
new file mode 100644
index 000000000000..f9f93867c853
--- /dev/null
+++ b/lib/Lex/TokenLexer.cpp
@@ -0,0 +1,542 @@
+//===--- TokenLexer.cpp - Lex from a token stream -------------------------===//
+//
+// 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 TokenLexer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/TokenLexer.h"
+#include "MacroArgs.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "llvm/ADT/SmallVector.h"
+using namespace clang;
+
+
+/// Create a TokenLexer for the specified macro with the specified actual
+/// arguments. Note that this ctor takes ownership of the ActualArgs pointer.
+void TokenLexer::Init(Token &Tok, SourceLocation ILEnd, MacroArgs *Actuals) {
+ // If the client is reusing a TokenLexer, make sure to free any memory
+ // associated with it.
+ destroy();
+
+ Macro = PP.getMacroInfo(Tok.getIdentifierInfo());
+ ActualArgs = Actuals;
+ CurToken = 0;
+
+ InstantiateLocStart = Tok.getLocation();
+ InstantiateLocEnd = ILEnd;
+ AtStartOfLine = Tok.isAtStartOfLine();
+ HasLeadingSpace = Tok.hasLeadingSpace();
+ Tokens = &*Macro->tokens_begin();
+ OwnsTokens = false;
+ DisableMacroExpansion = false;
+ NumTokens = Macro->tokens_end()-Macro->tokens_begin();
+
+ // If this is a function-like macro, expand the arguments and change
+ // Tokens to point to the expanded tokens.
+ if (Macro->isFunctionLike() && Macro->getNumArgs())
+ ExpandFunctionArguments();
+
+ // Mark the macro as currently disabled, so that it is not recursively
+ // expanded. The macro must be disabled only after argument pre-expansion of
+ // function-like macro arguments occurs.
+ Macro->DisableMacro();
+}
+
+
+
+/// Create a TokenLexer for the specified token stream. This does not
+/// take ownership of the specified token vector.
+void TokenLexer::Init(const Token *TokArray, unsigned NumToks,
+ bool disableMacroExpansion, bool ownsTokens) {
+ // If the client is reusing a TokenLexer, make sure to free any memory
+ // associated with it.
+ destroy();
+
+ Macro = 0;
+ ActualArgs = 0;
+ Tokens = TokArray;
+ OwnsTokens = ownsTokens;
+ DisableMacroExpansion = disableMacroExpansion;
+ NumTokens = NumToks;
+ CurToken = 0;
+ InstantiateLocStart = InstantiateLocEnd = SourceLocation();
+ AtStartOfLine = false;
+ HasLeadingSpace = false;
+
+ // Set HasLeadingSpace/AtStartOfLine so that the first token will be
+ // returned unmodified.
+ if (NumToks != 0) {
+ AtStartOfLine = TokArray[0].isAtStartOfLine();
+ HasLeadingSpace = TokArray[0].hasLeadingSpace();
+ }
+}
+
+
+void TokenLexer::destroy() {
+ // If this was a function-like macro that actually uses its arguments, delete
+ // the expanded tokens.
+ if (OwnsTokens) {
+ delete [] Tokens;
+ Tokens = 0;
+ OwnsTokens = false;
+ }
+
+ // TokenLexer owns its formal arguments.
+ if (ActualArgs) ActualArgs->destroy();
+}
+
+/// Expand the arguments of a function-like macro so that we can quickly
+/// return preexpanded tokens from Tokens.
+void TokenLexer::ExpandFunctionArguments() {
+ llvm::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,
+ // we install the newly expanded sequence as the new 'Tokens' list.
+ bool MadeChange = false;
+
+ // NextTokGetsSpace - When this is true, the next token appended to the
+ // output list will get a leading space, regardless of whether it had one to
+ // begin with or not. This is used for placemarker support.
+ bool NextTokGetsSpace = false;
+
+ for (unsigned i = 0, e = NumTokens; i != e; ++i) {
+ // If we found the stringify operator, get the argument stringified. The
+ // preprocessor already verified that the following token is a macro name
+ // when the #define was parsed.
+ const Token &CurTok = Tokens[i];
+ if (CurTok.is(tok::hash) || CurTok.is(tok::hashat)) {
+ int ArgNo = Macro->getArgumentNum(Tokens[i+1].getIdentifierInfo());
+ assert(ArgNo != -1 && "Token following # is not an argument?");
+
+ Token Res;
+ if (CurTok.is(tok::hash)) // Stringify
+ Res = ActualArgs->getStringifiedArgument(ArgNo, PP);
+ else {
+ // 'charify': don't bother caching these.
+ Res = MacroArgs::StringifyArgument(ActualArgs->getUnexpArgument(ArgNo),
+ PP, true);
+ }
+
+ // The stringified/charified string leading space flag gets set to match
+ // the #/#@ operator.
+ if (CurTok.hasLeadingSpace() || NextTokGetsSpace)
+ Res.setFlag(Token::LeadingSpace);
+
+ ResultToks.push_back(Res);
+ MadeChange = true;
+ ++i; // Skip arg name.
+ NextTokGetsSpace = false;
+ continue;
+ }
+
+ // Otherwise, if this is not an argument token, just add the token to the
+ // output buffer.
+ IdentifierInfo *II = CurTok.getIdentifierInfo();
+ int ArgNo = II ? Macro->getArgumentNum(II) : -1;
+ if (ArgNo == -1) {
+ // This isn't an argument, just add it.
+ ResultToks.push_back(CurTok);
+
+ if (NextTokGetsSpace) {
+ ResultToks.back().setFlag(Token::LeadingSpace);
+ NextTokGetsSpace = false;
+ }
+ continue;
+ }
+
+ // An argument is expanded somehow, the result is different than the
+ // input.
+ MadeChange = true;
+
+ // Otherwise, this is a use of the argument. Find out if there is a paste
+ // (##) operator before or after the argument.
+ bool PasteBefore =
+ !ResultToks.empty() && ResultToks.back().is(tok::hashhash);
+ bool PasteAfter = i+1 != e && Tokens[i+1].is(tok::hashhash);
+
+ // If it is not the LHS/RHS of a ## operator, we must pre-expand the
+ // argument and substitute the expanded tokens into the result. This is
+ // C99 6.10.3.1p1.
+ if (!PasteBefore && !PasteAfter) {
+ const Token *ResultArgToks;
+
+ // Only preexpand the argument if it could possibly need it. This
+ // avoids some work in common cases.
+ const Token *ArgTok = ActualArgs->getUnexpArgument(ArgNo);
+ if (ActualArgs->ArgNeedsPreexpansion(ArgTok, PP))
+ ResultArgToks = &ActualArgs->getPreExpArgument(ArgNo, PP)[0];
+ else
+ ResultArgToks = ArgTok; // Use non-preexpanded tokens.
+
+ // If the arg token expanded into anything, append it.
+ if (ResultArgToks->isNot(tok::eof)) {
+ unsigned FirstResult = ResultToks.size();
+ unsigned NumToks = MacroArgs::getArgLength(ResultArgToks);
+ ResultToks.append(ResultArgToks, ResultArgToks+NumToks);
+
+ // If any tokens were substituted from the argument, the whitespace
+ // before the first token should match the whitespace of the arg
+ // identifier.
+ ResultToks[FirstResult].setFlagValue(Token::LeadingSpace,
+ CurTok.hasLeadingSpace() ||
+ NextTokGetsSpace);
+ NextTokGetsSpace = false;
+ } else {
+ // If this is an empty argument, and if there was whitespace before the
+ // formal token, make sure the next token gets whitespace before it.
+ NextTokGetsSpace = CurTok.hasLeadingSpace();
+ }
+ continue;
+ }
+
+ // Okay, we have a token that is either the LHS or RHS of a paste (##)
+ // argument. It gets substituted as its non-pre-expanded tokens.
+ const Token *ArgToks = ActualArgs->getUnexpArgument(ArgNo);
+ unsigned NumToks = MacroArgs::getArgLength(ArgToks);
+ if (NumToks) { // Not an empty argument?
+ // If this is the GNU ", ## __VA_ARG__" extension, and we just learned
+ // that __VA_ARG__ expands to multiple tokens, avoid a pasting error when
+ // the expander trys to paste ',' with the first token of the __VA_ARG__
+ // expansion.
+ if (PasteBefore && ResultToks.size() >= 2 &&
+ ResultToks[ResultToks.size()-2].is(tok::comma) &&
+ (unsigned)ArgNo == Macro->getNumArgs()-1 &&
+ Macro->isVariadic()) {
+ // Remove the paste operator, report use of the extension.
+ PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma);
+ ResultToks.pop_back();
+ }
+
+ ResultToks.append(ArgToks, ArgToks+NumToks);
+
+ // If this token (the macro argument) was supposed to get leading
+ // whitespace, transfer this information onto the first token of the
+ // expansion.
+ //
+ // Do not do this if the paste operator occurs before the macro argument,
+ // as in "A ## MACROARG". In valid code, the first token will get
+ // smooshed onto the preceding one anyway (forming AMACROARG). In
+ // assembler-with-cpp mode, invalid pastes are allowed through: in this
+ // case, we do not want the extra whitespace to be added. For example,
+ // we want ". ## foo" -> ".foo" not ". foo".
+ if ((CurTok.hasLeadingSpace() || NextTokGetsSpace) &&
+ !PasteBefore)
+ ResultToks[ResultToks.size()-NumToks].setFlag(Token::LeadingSpace);
+
+ NextTokGetsSpace = false;
+ continue;
+ }
+
+ // If an empty argument is on the LHS or RHS of a paste, the standard (C99
+ // 6.10.3.3p2,3) calls for a bunch of placemarker stuff to occur. We
+ // implement this by eating ## operators when a LHS or RHS expands to
+ // empty.
+ NextTokGetsSpace |= CurTok.hasLeadingSpace();
+ if (PasteAfter) {
+ // Discard the argument token and skip (don't copy to the expansion
+ // buffer) the paste operator after it.
+ NextTokGetsSpace |= Tokens[i+1].hasLeadingSpace();
+ ++i;
+ continue;
+ }
+
+ // If this is on the RHS of a paste operator, we've already copied the
+ // paste operator to the ResultToks list. Remove it.
+ assert(PasteBefore && ResultToks.back().is(tok::hashhash));
+ NextTokGetsSpace |= ResultToks.back().hasLeadingSpace();
+ ResultToks.pop_back();
+
+ // If this is the __VA_ARGS__ token, and if the argument wasn't provided,
+ // and if the macro had at least one real argument, and if the token before
+ // the ## was a comma, remove the comma.
+ if ((unsigned)ArgNo == Macro->getNumArgs()-1 && // is __VA_ARGS__
+ ActualArgs->isVarargsElidedUse() && // Argument elided.
+ !ResultToks.empty() && ResultToks.back().is(tok::comma)) {
+ // Never add a space, even if the comma, ##, or arg had a space.
+ NextTokGetsSpace = false;
+ // Remove the paste operator, report use of the extension.
+ PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma);
+ ResultToks.pop_back();
+ }
+ continue;
+ }
+
+ // If anything changed, install this as the new Tokens list.
+ if (MadeChange) {
+ assert(!OwnsTokens && "This would leak if we already own the token list");
+ // This is deleted in the dtor.
+ NumTokens = ResultToks.size();
+ llvm::BumpPtrAllocator &Alloc = PP.getPreprocessorAllocator();
+ Token *Res =
+ static_cast<Token *>(Alloc.Allocate(sizeof(Token)*ResultToks.size(),
+ llvm::alignof<Token>()));
+ if (NumTokens)
+ memcpy(Res, &ResultToks[0], NumTokens*sizeof(Token));
+ Tokens = Res;
+
+ // The preprocessor bump pointer owns these tokens, not us.
+ OwnsTokens = false;
+ }
+}
+
+/// Lex - Lex and return a token from this macro stream.
+///
+void TokenLexer::Lex(Token &Tok) {
+ // Lexing off the end of the macro, pop this macro off the expansion stack.
+ if (isAtEnd()) {
+ // If this is a macro (not a token stream), mark the macro enabled now
+ // that it is no longer being expanded.
+ if (Macro) Macro->EnableMacro();
+
+ // Pop this context off the preprocessors lexer stack and get the next
+ // token. This will delete "this" so remember the PP instance var.
+ Preprocessor &PPCache = PP;
+ if (PP.HandleEndOfTokenLexer(Tok))
+ return;
+
+ // HandleEndOfTokenLexer may not return a token. If it doesn't, lex
+ // whatever is next.
+ return PPCache.Lex(Tok);
+ }
+
+ // If this is the first token of the expanded result, we inherit spacing
+ // properties later.
+ bool isFirstToken = CurToken == 0;
+
+ // Get the next token to return.
+ Tok = Tokens[CurToken++];
+
+ bool TokenIsFromPaste = false;
+
+ // If this token is followed by a token paste (##) operator, paste the tokens!
+ if (!isAtEnd() && Tokens[CurToken].is(tok::hashhash)) {
+ if (PasteTokens(Tok)) {
+ // When handling the microsoft /##/ extension, the final token is
+ // returned by PasteTokens, not the pasted token.
+ return;
+ } else {
+ TokenIsFromPaste = true;
+ }
+ }
+
+ // 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 they came from
+ // InstantiationLoc. Pull this information together into a new SourceLocation
+ // that captures all of this.
+ if (InstantiateLocStart.isValid()) { // Don't do this for token streams.
+ SourceManager &SM = PP.getSourceManager();
+ Tok.setLocation(SM.createInstantiationLoc(Tok.getLocation(),
+ InstantiateLocStart,
+ InstantiateLocEnd,
+ Tok.getLength()));
+ }
+
+ // If this is the first token, set the lexical properties of the token to
+ // match the lexical properties of the macro identifier.
+ if (isFirstToken) {
+ Tok.setFlagValue(Token::StartOfLine , AtStartOfLine);
+ Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace);
+ }
+
+ // Handle recursive expansion!
+ if (!Tok.isAnnotation() && Tok.getIdentifierInfo() != 0) {
+ // Change the kind of this identifier to the appropriate token kind, e.g.
+ // turning "for" into a keyword.
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ Tok.setKind(II->getTokenID());
+
+ // If this identifier was poisoned and from a paste, emit an error. This
+ // won't be handled by Preprocessor::HandleIdentifier because this is coming
+ // from a macro expansion.
+ if (II->isPoisoned() && TokenIsFromPaste) {
+ // We warn about __VA_ARGS__ with poisoning.
+ if (II->isStr("__VA_ARGS__"))
+ PP.Diag(Tok, diag::ext_pp_bad_vaargs_use);
+ else
+ PP.Diag(Tok, diag::err_pp_used_poisoned_id);
+ }
+
+ if (!DisableMacroExpansion && II->isHandleIdentifierCase())
+ PP.HandleIdentifier(Tok);
+ }
+
+ // Otherwise, return a normal token.
+}
+
+/// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ##
+/// operator. Read the ## and RHS, and paste the LHS/RHS together. If there
+/// are more ## after it, chomp them iteratively. Return the result as Tok.
+/// If this returns true, the caller should immediately return the token.
+bool TokenLexer::PasteTokens(Token &Tok) {
+ llvm::SmallVector<char, 128> Buffer;
+ const char *ResultTokStrPtr = 0;
+ do {
+ // Consume the ## operator.
+ SourceLocation PasteOpLoc = Tokens[CurToken].getLocation();
+ ++CurToken;
+ assert(!isAtEnd() && "No token on the RHS of a paste operator!");
+
+ // Get the RHS token.
+ const Token &RHS = Tokens[CurToken];
+
+ // Allocate space for the result token. This is guaranteed to be enough for
+ // the two tokens.
+ Buffer.resize(Tok.getLength() + RHS.getLength());
+
+ // Get the spelling of the LHS token in Buffer.
+ const char *BufPtr = &Buffer[0];
+ unsigned LHSLen = PP.getSpelling(Tok, BufPtr);
+ if (BufPtr != &Buffer[0]) // Really, we want the chars in Buffer!
+ memcpy(&Buffer[0], BufPtr, LHSLen);
+
+ BufPtr = &Buffer[LHSLen];
+ unsigned RHSLen = PP.getSpelling(RHS, BufPtr);
+ if (BufPtr != &Buffer[LHSLen]) // Really, we want the chars in Buffer!
+ memcpy(&Buffer[LHSLen], BufPtr, RHSLen);
+
+ // Trim excess space.
+ Buffer.resize(LHSLen+RHSLen);
+
+ // Plop the pasted result (including the trailing newline and null) into a
+ // scratch buffer where we can lex it.
+ Token ResultTokTmp;
+ ResultTokTmp.startToken();
+
+ // Claim that the tmp token is a string_literal so that we can get the
+ // character pointer back from CreateString.
+ ResultTokTmp.setKind(tok::string_literal);
+ PP.CreateString(&Buffer[0], Buffer.size(), ResultTokTmp);
+ SourceLocation ResultTokLoc = ResultTokTmp.getLocation();
+ ResultTokStrPtr = ResultTokTmp.getLiteralData();
+
+ // Lex the resultant pasted token into Result.
+ Token Result;
+
+ if (Tok.is(tok::identifier) && RHS.is(tok::identifier)) {
+ // Common paste case: identifier+identifier = identifier. Avoid creating
+ // a lexer and other overhead.
+ PP.IncrementPasteCounter(true);
+ Result.startToken();
+ Result.setKind(tok::identifier);
+ Result.setLocation(ResultTokLoc);
+ Result.setLength(LHSLen+RHSLen);
+ } else {
+ PP.IncrementPasteCounter(false);
+
+ assert(ResultTokLoc.isFileID() &&
+ "Should be a raw location into scratch buffer");
+ SourceManager &SourceMgr = PP.getSourceManager();
+ FileID LocFileID = SourceMgr.getFileID(ResultTokLoc);
+
+ const char *ScratchBufStart = SourceMgr.getBufferData(LocFileID).first;
+
+ // Make a lexer to lex this string from. Lex just this one token.
+ // Make a lexer object so that we lex and expand the paste result.
+ Lexer TL(SourceMgr.getLocForStartOfFile(LocFileID),
+ PP.getLangOptions(), ScratchBufStart,
+ ResultTokStrPtr, ResultTokStrPtr+LHSLen+RHSLen);
+
+ // Lex a token in raw mode. This way it won't look up identifiers
+ // automatically, lexing off the end will return an eof token, and
+ // warnings are disabled. This returns true if the result token is the
+ // entire buffer.
+ bool isInvalid = !TL.LexFromRawLexer(Result);
+
+ // If we got an EOF token, we didn't form even ONE token. For example, we
+ // did "/ ## /" to get "//".
+ isInvalid |= Result.is(tok::eof);
+
+ // If pasting the two tokens didn't form a full new token, this is an
+ // error. This occurs with "x ## +" and other stuff. Return with Tok
+ // unmodified and with RHS as the next token to lex.
+ if (isInvalid) {
+ // Test for the Microsoft extension of /##/ turning into // here on the
+ // error path.
+ if (PP.getLangOptions().Microsoft && Tok.is(tok::slash) &&
+ RHS.is(tok::slash)) {
+ HandleMicrosoftCommentPaste(Tok);
+ return true;
+ }
+
+ // Do not emit the warning when preprocessing assembler code.
+ if (!PP.getLangOptions().AsmPreprocessor) {
+ // Explicitly convert the token location to have proper instantiation
+ // information so that the user knows where it came from.
+ SourceManager &SM = PP.getSourceManager();
+ SourceLocation Loc =
+ SM.createInstantiationLoc(PasteOpLoc, InstantiateLocStart,
+ InstantiateLocEnd, 2);
+ PP.Diag(Loc, diag::err_pp_bad_paste)
+ << std::string(Buffer.begin(), Buffer.end());
+ }
+
+ // Do not consume the RHS.
+ --CurToken;
+ }
+
+ // Turn ## into 'unknown' to avoid # ## # from looking like a paste
+ // operator.
+ if (Result.is(tok::hashhash))
+ Result.setKind(tok::unknown);
+ }
+
+ // Transfer properties of the LHS over the the Result.
+ Result.setFlagValue(Token::StartOfLine , Tok.isAtStartOfLine());
+ Result.setFlagValue(Token::LeadingSpace, Tok.hasLeadingSpace());
+
+ // Finally, replace LHS with the result, consume the RHS, and iterate.
+ ++CurToken;
+ Tok = Result;
+ } while (!isAtEnd() && Tokens[CurToken].is(tok::hashhash));
+
+ // 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
+ // isn't looked up. As such, if the result is an identifier, look up id info.
+ if (Tok.is(tok::identifier)) {
+ // Look up the identifier info for the token. We disabled identifier lookup
+ // by saying we're skipping contents, so we need to do this manually.
+ IdentifierInfo *II = PP.LookUpIdentifierInfo(Tok, ResultTokStrPtr);
+ Tok.setIdentifierInfo(II);
+ }
+ return false;
+}
+
+/// isNextTokenLParen - If the next token lexed will pop this macro off the
+/// expansion stack, return 2. If the next unexpanded token is a '(', return
+/// 1, otherwise return 0.
+unsigned TokenLexer::isNextTokenLParen() const {
+ // Out of tokens?
+ if (isAtEnd())
+ return 2;
+ return Tokens[CurToken].is(tok::l_paren);
+}
+
+
+/// HandleMicrosoftCommentPaste - In microsoft compatibility mode, /##/ pastes
+/// together to form a comment that comments out everything in the current
+/// macro, other active macros, and anything left on the current physical
+/// source line of the instantiated buffer. Handle this by returning the
+/// first token on the next line.
+void TokenLexer::HandleMicrosoftCommentPaste(Token &Tok) {
+ // We 'comment out' the rest of this macro by just ignoring the rest of the
+ // tokens that have not been lexed yet, if any.
+
+ // Since this must be a macro, mark the macro enabled now that it is no longer
+ // being expanded.
+ assert(Macro && "Token streams can't paste comments");
+ Macro->EnableMacro();
+
+ PP.HandleMicrosoftCommentPaste(Tok);
+}
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100755
index 000000000000..50ed94a88d07
--- /dev/null
+++ b/lib/Makefile
@@ -0,0 +1,15 @@
+##===- lib/Makefile ----------------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+LEVEL = ../../..
+
+PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis Rewrite \
+ Frontend Driver
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
new file mode 100644
index 000000000000..0170a0671db7
--- /dev/null
+++ b/lib/Parse/AttributeList.cpp
@@ -0,0 +1,145 @@
+//===--- AttributeList.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the AttributeList class implementation
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/AttributeList.h"
+#include "clang/Basic/IdentifierTable.h"
+using namespace clang;
+
+AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc,
+ IdentifierInfo *pName, SourceLocation pLoc,
+ ActionBase::ExprTy **ExprList, unsigned numArgs,
+ AttributeList *n)
+ : AttrName(aName), AttrLoc(aLoc), ParmName(pName), ParmLoc(pLoc),
+ NumArgs(numArgs), Next(n) {
+
+ if (numArgs == 0)
+ Args = 0;
+ else {
+ Args = new ActionBase::ExprTy*[numArgs];
+ memcpy(Args, ExprList, numArgs*sizeof(Args[0]));
+ }
+}
+
+AttributeList::~AttributeList() {
+ if (Args) {
+ // FIXME: before we delete the vector, we need to make sure the Expr's
+ // have been deleted. Since ActionBase::ExprTy is "void", we are dependent
+ // on the actions module for actually freeing the memory. The specific
+ // hooks are ActOnDeclarator, ActOnTypeName, ActOnParamDeclaratorType,
+ // ParseField, ParseTag. Once these routines have freed the expression,
+ // they should zero out the Args slot (to indicate the memory has been
+ // freed). If any element of the vector is non-null, we should assert.
+ delete [] Args;
+ }
+ delete Next;
+}
+
+AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
+ const char *Str = Name->getName();
+ unsigned Len = Name->getLength();
+
+ // Normalize the attribute name, __foo__ becomes foo.
+ if (Len > 4 && Str[0] == '_' && Str[1] == '_' &&
+ Str[Len - 2] == '_' && Str[Len - 1] == '_') {
+ Str += 2;
+ Len -= 4;
+ }
+
+ // FIXME: Hand generating this is neither smart nor efficient.
+ switch (Len) {
+ case 4:
+ if (!memcmp(Str, "weak", 4)) return AT_weak;
+ if (!memcmp(Str, "pure", 4)) return AT_pure;
+ if (!memcmp(Str, "mode", 4)) return AT_mode;
+ if (!memcmp(Str, "used", 4)) return AT_used;
+ break;
+ case 5:
+ if (!memcmp(Str, "alias", 5)) return AT_alias;
+ if (!memcmp(Str, "const", 5)) return AT_const;
+ break;
+ case 6:
+ if (!memcmp(Str, "packed", 6)) return AT_packed;
+ if (!memcmp(Str, "malloc", 6)) return IgnoredAttribute; // FIXME: noalias.
+ if (!memcmp(Str, "format", 6)) return AT_format;
+ if (!memcmp(Str, "unused", 6)) return AT_unused;
+ if (!memcmp(Str, "blocks", 6)) return AT_blocks;
+ break;
+ case 7:
+ if (!memcmp(Str, "aligned", 7)) return AT_aligned;
+ if (!memcmp(Str, "cleanup", 7)) return AT_cleanup;
+ if (!memcmp(Str, "nodebug", 7)) return AT_nodebug;
+ if (!memcmp(Str, "nonnull", 7)) return AT_nonnull;
+ if (!memcmp(Str, "nothrow", 7)) return AT_nothrow;
+ if (!memcmp(Str, "objc_gc", 7)) return AT_objc_gc;
+ if (!memcmp(Str, "regparm", 7)) return AT_regparm;
+ if (!memcmp(Str, "section", 7)) return AT_section;
+ if (!memcmp(Str, "stdcall", 7)) return AT_stdcall;
+ break;
+ case 8:
+ if (!memcmp(Str, "annotate", 8)) return AT_annotate;
+ if (!memcmp(Str, "noreturn", 8)) return AT_noreturn;
+ if (!memcmp(Str, "noinline", 8)) return AT_noinline;
+ if (!memcmp(Str, "fastcall", 8)) return AT_fastcall;
+ if (!memcmp(Str, "iboutlet", 8)) return AT_IBOutlet;
+ if (!memcmp(Str, "sentinel", 8)) return AT_sentinel;
+ if (!memcmp(Str, "NSObject", 8)) return AT_nsobject;
+ break;
+ case 9:
+ if (!memcmp(Str, "dllimport", 9)) return AT_dllimport;
+ if (!memcmp(Str, "dllexport", 9)) return AT_dllexport;
+ if (!memcmp(Str, "may_alias", 9)) return IgnoredAttribute; // FIXME: TBAA
+ break;
+ case 10:
+ if (!memcmp(Str, "deprecated", 10)) return AT_deprecated;
+ if (!memcmp(Str, "visibility", 10)) return AT_visibility;
+ if (!memcmp(Str, "destructor", 10)) return AT_destructor;
+ if (!memcmp(Str, "format_arg", 10)) return AT_format_arg;
+ if (!memcmp(Str, "gnu_inline", 10)) return AT_gnu_inline;
+ break;
+ case 11:
+ if (!memcmp(Str, "weak_import", 11)) return AT_weak_import;
+ if (!memcmp(Str, "vector_size", 11)) return AT_vector_size;
+ if (!memcmp(Str, "constructor", 11)) return AT_constructor;
+ if (!memcmp(Str, "unavailable", 11)) return AT_unavailable;
+ break;
+ case 12:
+ if (!memcmp(Str, "overloadable", 12)) return AT_overloadable;
+ break;
+ case 13:
+ if (!memcmp(Str, "address_space", 13)) return AT_address_space;
+ if (!memcmp(Str, "always_inline", 13)) return AT_always_inline;
+ break;
+ case 14:
+ if (!memcmp(Str, "objc_exception", 14)) return AT_objc_exception;
+ break;
+ case 15:
+ if (!memcmp(Str, "ext_vector_type", 15)) return AT_ext_vector_type;
+ break;
+ case 17:
+ if (!memcmp(Str, "transparent_union", 17)) return AT_transparent_union;
+ if (!memcmp(Str, "analyzer_noreturn", 17)) return AT_analyzer_noreturn;
+ break;
+ case 18:
+ if (!memcmp(Str, "warn_unused_result", 18)) return AT_warn_unused_result;
+ break;
+ case 19:
+ if (!memcmp(Str, "ns_returns_retained", 19)) return AT_ns_returns_retained;
+ if (!memcmp(Str, "cf_returns_retained", 19)) return AT_cf_returns_retained;
+ break;
+ case 22:
+ if (!memcmp(Str, "no_instrument_function", 22))
+ return AT_no_instrument_function;
+ break;
+ }
+ return UnknownAttribute;
+}
diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt
new file mode 100644
index 000000000000..8fb7cd23b89a
--- /dev/null
+++ b/lib/Parse/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(LLVM_NO_RTTI 1)
+
+add_clang_library(clangParse
+ AttributeList.cpp
+ DeclSpec.cpp
+ MinimalAction.cpp
+ ParseCXXInlineMethods.cpp
+ ParseDecl.cpp
+ ParseDeclCXX.cpp
+ ParseExpr.cpp
+ ParseExprCXX.cpp
+ ParseInit.cpp
+ ParseObjc.cpp
+ ParsePragma.cpp
+ Parser.cpp
+ ParseStmt.cpp
+ ParseTentative.cpp
+ ParseTemplate.cpp
+ )
+
+add_dependencies(clangParse ClangDiagnosticParse)
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
new file mode 100644
index 000000000000..d8c6986f9ea6
--- /dev/null
+++ b/lib/Parse/DeclSpec.cpp
@@ -0,0 +1,395 @@
+//===--- SemaDeclSpec.cpp - Declaration Specifier Semantic Analysis -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for declaration specifiers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/STLExtras.h"
+#include <cstring>
+using namespace clang;
+
+
+static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc,
+ SourceManager &SrcMgr, unsigned DiagID) {
+ return D.Report(FullSourceLoc(Loc, SrcMgr), DiagID);
+}
+
+/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
+/// "TheDeclarator" is the declarator that this will be added to.
+DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
+ SourceLocation EllipsisLoc,
+ ParamInfo *ArgInfo,
+ unsigned NumArgs,
+ unsigned TypeQuals,
+ bool hasExceptionSpec,
+ SourceLocation ThrowLoc,
+ bool hasAnyExceptionSpec,
+ ActionBase::TypeTy **Exceptions,
+ SourceRange *ExceptionRanges,
+ unsigned NumExceptions,
+ SourceLocation Loc,
+ Declarator &TheDeclarator) {
+ DeclaratorChunk I;
+ I.Kind = Function;
+ I.Loc = Loc;
+ I.Fun.hasPrototype = hasProto;
+ I.Fun.isVariadic = isVariadic;
+ I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding();
+ I.Fun.DeleteArgInfo = false;
+ I.Fun.TypeQuals = TypeQuals;
+ I.Fun.NumArgs = NumArgs;
+ I.Fun.ArgInfo = 0;
+ I.Fun.hasExceptionSpec = hasExceptionSpec;
+ I.Fun.ThrowLoc = ThrowLoc.getRawEncoding();
+ I.Fun.hasAnyExceptionSpec = hasAnyExceptionSpec;
+ I.Fun.NumExceptions = NumExceptions;
+ I.Fun.Exceptions = 0;
+
+ // new[] an argument array if needed.
+ if (NumArgs) {
+ // If the 'InlineParams' in Declarator is unused and big enough, put our
+ // parameter list there (in an effort to avoid new/delete traffic). If it
+ // is already used (consider a function returning a function pointer) or too
+ // small (function taking too many arguments), go to the heap.
+ if (!TheDeclarator.InlineParamsUsed &&
+ NumArgs <= llvm::array_lengthof(TheDeclarator.InlineParams)) {
+ I.Fun.ArgInfo = TheDeclarator.InlineParams;
+ I.Fun.DeleteArgInfo = false;
+ TheDeclarator.InlineParamsUsed = true;
+ } else {
+ I.Fun.ArgInfo = new DeclaratorChunk::ParamInfo[NumArgs];
+ I.Fun.DeleteArgInfo = true;
+ }
+ memcpy(I.Fun.ArgInfo, ArgInfo, sizeof(ArgInfo[0])*NumArgs);
+ }
+ // new[] an exception array if needed
+ if (NumExceptions) {
+ I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions];
+ for (unsigned i = 0; i != NumExceptions; ++i) {
+ I.Fun.Exceptions[i].Ty = Exceptions[i];
+ I.Fun.Exceptions[i].Range = ExceptionRanges[i];
+ }
+ }
+ return I;
+}
+
+/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
+/// declaration specifier includes.
+///
+unsigned DeclSpec::getParsedSpecifiers() const {
+ unsigned Res = 0;
+ if (StorageClassSpec != SCS_unspecified ||
+ SCS_thread_specified)
+ Res |= PQ_StorageClassSpecifier;
+
+ if (TypeQualifiers != TQ_unspecified)
+ Res |= PQ_TypeQualifier;
+
+ if (hasTypeSpecifier())
+ Res |= PQ_TypeSpecifier;
+
+ if (FS_inline_specified || FS_virtual_specified || FS_explicit_specified)
+ Res |= PQ_FunctionSpecifier;
+ return Res;
+}
+
+const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) {
+ switch (S) {
+ default: assert(0 && "Unknown typespec!");
+ case DeclSpec::SCS_unspecified: return "unspecified";
+ case DeclSpec::SCS_typedef: return "typedef";
+ case DeclSpec::SCS_extern: return "extern";
+ case DeclSpec::SCS_static: return "static";
+ case DeclSpec::SCS_auto: return "auto";
+ case DeclSpec::SCS_register: return "register";
+ case DeclSpec::SCS_private_extern: return "__private_extern__";
+ case DeclSpec::SCS_mutable: return "mutable";
+ }
+}
+
+bool DeclSpec::BadSpecifier(SCS S, const char *&PrevSpec) {
+ PrevSpec = getSpecifierName(S);
+ return true;
+}
+
+bool DeclSpec::BadSpecifier(TSW W, const char *&PrevSpec) {
+ switch (W) {
+ case TSW_unspecified: PrevSpec = "unspecified"; break;
+ case TSW_short: PrevSpec = "short"; break;
+ case TSW_long: PrevSpec = "long"; break;
+ case TSW_longlong: PrevSpec = "long long"; break;
+ }
+ return true;
+}
+
+bool DeclSpec::BadSpecifier(TSC C, const char *&PrevSpec) {
+ switch (C) {
+ case TSC_unspecified: PrevSpec = "unspecified"; break;
+ case TSC_imaginary: PrevSpec = "imaginary"; break;
+ case TSC_complex: PrevSpec = "complex"; break;
+ }
+ return true;
+}
+
+
+bool DeclSpec::BadSpecifier(TSS S, const char *&PrevSpec) {
+ switch (S) {
+ case TSS_unspecified: PrevSpec = "unspecified"; break;
+ case TSS_signed: PrevSpec = "signed"; break;
+ case TSS_unsigned: PrevSpec = "unsigned"; break;
+ }
+ return true;
+}
+
+const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
+ switch (T) {
+ default: assert(0 && "Unknown typespec!");
+ case DeclSpec::TST_unspecified: return "unspecified";
+ case DeclSpec::TST_void: return "void";
+ case DeclSpec::TST_char: return "char";
+ case DeclSpec::TST_wchar: return "wchar_t";
+ case DeclSpec::TST_int: return "int";
+ case DeclSpec::TST_float: return "float";
+ case DeclSpec::TST_double: return "double";
+ case DeclSpec::TST_bool: return "_Bool";
+ case DeclSpec::TST_decimal32: return "_Decimal32";
+ case DeclSpec::TST_decimal64: return "_Decimal64";
+ case DeclSpec::TST_decimal128: return "_Decimal128";
+ case DeclSpec::TST_enum: return "enum";
+ case DeclSpec::TST_class: return "class";
+ case DeclSpec::TST_union: return "union";
+ case DeclSpec::TST_struct: return "struct";
+ case DeclSpec::TST_typename: return "type-name";
+ case DeclSpec::TST_typeofType:
+ case DeclSpec::TST_typeofExpr: return "typeof";
+ }
+}
+
+bool DeclSpec::BadSpecifier(TST T, const char *&PrevSpec) {
+ PrevSpec = getSpecifierName(T);
+ return true;
+}
+
+bool DeclSpec::BadSpecifier(TQ T, const char *&PrevSpec) {
+ switch (T) {
+ case DeclSpec::TQ_unspecified: PrevSpec = "unspecified"; break;
+ case DeclSpec::TQ_const: PrevSpec = "const"; break;
+ case DeclSpec::TQ_restrict: PrevSpec = "restrict"; break;
+ case DeclSpec::TQ_volatile: PrevSpec = "volatile"; break;
+ }
+ return true;
+}
+
+bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc,
+ const char *&PrevSpec) {
+ if (StorageClassSpec != SCS_unspecified)
+ return BadSpecifier((SCS)StorageClassSpec, PrevSpec);
+ StorageClassSpec = S;
+ StorageClassSpecLoc = Loc;
+ assert((unsigned)S == StorageClassSpec && "SCS constants overflow bitfield");
+ return false;
+}
+
+bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc,
+ const char *&PrevSpec) {
+ if (SCS_thread_specified) {
+ PrevSpec = "__thread";
+ return true;
+ }
+ SCS_thread_specified = true;
+ SCS_threadLoc = Loc;
+ return false;
+}
+
+
+/// These methods set the specified attribute of the DeclSpec, but return true
+/// and ignore the request if invalid (e.g. "extern" then "auto" is
+/// specified).
+bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc,
+ const char *&PrevSpec) {
+ if (TypeSpecWidth != TSW_unspecified &&
+ // Allow turning long -> long long.
+ (W != TSW_longlong || TypeSpecWidth != TSW_long))
+ return BadSpecifier((TSW)TypeSpecWidth, PrevSpec);
+ TypeSpecWidth = W;
+ TSWLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc,
+ const char *&PrevSpec) {
+ if (TypeSpecComplex != TSC_unspecified)
+ return BadSpecifier((TSC)TypeSpecComplex, PrevSpec);
+ TypeSpecComplex = C;
+ TSCLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc,
+ const char *&PrevSpec) {
+ if (TypeSpecSign != TSS_unspecified)
+ return BadSpecifier((TSS)TypeSpecSign, PrevSpec);
+ TypeSpecSign = S;
+ TSSLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
+ const char *&PrevSpec, void *Rep,
+ bool Owned) {
+ if (TypeSpecType != TST_unspecified)
+ return BadSpecifier((TST)TypeSpecType, PrevSpec);
+ TypeSpecType = T;
+ TypeRep = Rep;
+ TSTLoc = Loc;
+ TypeSpecOwned = Owned;
+ return false;
+}
+
+bool DeclSpec::SetTypeSpecError() {
+ TypeSpecType = TST_error;
+ TypeRep = 0;
+ TSTLoc = SourceLocation();
+ return false;
+}
+
+bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
+ const LangOptions &Lang) {
+ // Duplicates turn into warnings pre-C99.
+ if ((TypeQualifiers & T) && !Lang.C99)
+ return BadSpecifier(T, PrevSpec);
+ TypeQualifiers |= T;
+
+ switch (T) {
+ default: assert(0 && "Unknown type qualifier!");
+ case TQ_const: TQ_constLoc = Loc; break;
+ case TQ_restrict: TQ_restrictLoc = Loc; break;
+ case TQ_volatile: TQ_volatileLoc = Loc; break;
+ }
+ return false;
+}
+
+bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec){
+ // 'inline inline' is ok.
+ FS_inline_specified = true;
+ FS_inlineLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec){
+ // 'virtual virtual' is ok.
+ FS_virtual_specified = true;
+ FS_virtualLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec){
+ // 'explicit explicit' is ok.
+ FS_explicit_specified = true;
+ FS_explicitLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec) {
+ if (Friend_specified) {
+ PrevSpec = "friend";
+ return true;
+ }
+
+ Friend_specified = true;
+ FriendLoc = Loc;
+ return false;
+}
+
+/// Finish - This does final analysis of the declspec, rejecting things like
+/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
+/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
+/// DeclSpec is guaranteed self-consistent, even if an error occurred.
+void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
+ // Check the type specifier components first.
+ SourceManager &SrcMgr = PP.getSourceManager();
+
+ // signed/unsigned are only valid with int/char/wchar_t.
+ if (TypeSpecSign != TSS_unspecified) {
+ if (TypeSpecType == TST_unspecified)
+ TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int.
+ else if (TypeSpecType != TST_int &&
+ TypeSpecType != TST_char && TypeSpecType != TST_wchar) {
+ Diag(D, TSSLoc, SrcMgr, diag::err_invalid_sign_spec)
+ << getSpecifierName((TST)TypeSpecType);
+ // signed double -> double.
+ TypeSpecSign = TSS_unspecified;
+ }
+ }
+
+ // Validate the width of the type.
+ switch (TypeSpecWidth) {
+ case TSW_unspecified: break;
+ case TSW_short: // short int
+ case TSW_longlong: // long long int
+ if (TypeSpecType == TST_unspecified)
+ TypeSpecType = TST_int; // short -> short int, long long -> long long int.
+ else if (TypeSpecType != TST_int) {
+ Diag(D, TSWLoc, SrcMgr,
+ TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec
+ : diag::err_invalid_longlong_spec)
+ << getSpecifierName((TST)TypeSpecType);
+ TypeSpecType = TST_int;
+ }
+ break;
+ case TSW_long: // long double, long int
+ if (TypeSpecType == TST_unspecified)
+ TypeSpecType = TST_int; // long -> long int.
+ else if (TypeSpecType != TST_int && TypeSpecType != TST_double) {
+ Diag(D, TSWLoc, SrcMgr, diag::err_invalid_long_spec)
+ << getSpecifierName((TST)TypeSpecType);
+ TypeSpecType = TST_int;
+ }
+ break;
+ }
+
+ // TODO: if the implementation does not implement _Complex or _Imaginary,
+ // disallow their use. Need information about the backend.
+ if (TypeSpecComplex != TSC_unspecified) {
+ if (TypeSpecType == TST_unspecified) {
+ Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex)
+ << CodeModificationHint::CreateInsertion(
+ PP.getLocForEndOfToken(getTypeSpecComplexLoc()),
+ " double");
+ TypeSpecType = TST_double; // _Complex -> _Complex double.
+ } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) {
+ // Note that this intentionally doesn't include _Complex _Bool.
+ Diag(D, TSTLoc, SrcMgr, diag::ext_integer_complex);
+ } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) {
+ Diag(D, TSCLoc, SrcMgr, diag::err_invalid_complex_spec)
+ << getSpecifierName((TST)TypeSpecType);
+ TypeSpecComplex = TSC_unspecified;
+ }
+ }
+
+ // Okay, now we can infer the real type.
+
+ // TODO: return "auto function" and other bad things based on the real type.
+
+ // 'data definition has no type or storage class'?
+}
+
+bool DeclSpec::isMissingDeclaratorOk() {
+ TST tst = getTypeSpecType();
+ return (tst == TST_union
+ || tst == TST_struct
+ || tst == TST_class
+ || tst == TST_enum
+ ) && getTypeRep() != 0 && StorageClassSpec != DeclSpec::SCS_typedef;
+}
diff --git a/lib/Parse/ExtensionRAIIObject.h b/lib/Parse/ExtensionRAIIObject.h
new file mode 100644
index 000000000000..2b2bd3b21648
--- /dev/null
+++ b/lib/Parse/ExtensionRAIIObject.h
@@ -0,0 +1,40 @@
+//===--- ExtensionRAIIObject.h - Use RAII for __extension__ -----*- 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 and implements the ExtensionRAIIObject class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PARSE_EXTENSION_RAII_OBJECT_H
+#define LLVM_CLANG_PARSE_EXTENSION_RAII_OBJECT_H
+
+#include "clang/Parse/ParseDiagnostic.h"
+
+namespace clang {
+
+ /// ExtensionRAIIObject - This saves the state of extension warnings when
+ /// constructed and disables them. When destructed, it restores them back to
+ /// the way they used to be. This is used to handle __extension__ in the
+ /// parser.
+ class ExtensionRAIIObject {
+ void operator=(const ExtensionRAIIObject &); // DO NOT IMPLEMENT
+ ExtensionRAIIObject(const ExtensionRAIIObject&); // DO NOT IMPLEMENT
+ Diagnostic &Diags;
+ public:
+ ExtensionRAIIObject(Diagnostic &diags) : Diags(diags) {
+ Diags.IncrementAllExtensionsSilenced();
+ }
+
+ ~ExtensionRAIIObject() {
+ Diags.DecrementAllExtensionsSilenced();
+ }
+ };
+}
+
+#endif
diff --git a/lib/Parse/Makefile b/lib/Parse/Makefile
new file mode 100644
index 000000000000..5d69029edc1a
--- /dev/null
+++ b/lib/Parse/Makefile
@@ -0,0 +1,22 @@
+##===- clang/lib/Parse/Makefile ----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements the Parser library for the C-Language front-end.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+LIBRARYNAME := clangParse
+BUILD_ARCHIVE = 1
+CXXFLAGS = -fno-rtti
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
new file mode 100644
index 000000000000..b018e36519f3
--- /dev/null
+++ b/lib/Parse/MinimalAction.cpp
@@ -0,0 +1,225 @@
+//===--- MinimalAction.cpp - Implement the MinimalAction class ------------===//
+//
+// 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 MinimalAction interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/RecyclingAllocator.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+/// Out-of-line virtual destructor to provide home for ActionBase class.
+ActionBase::~ActionBase() {}
+
+/// Out-of-line virtual destructor to provide home for Action class.
+Action::~Action() {}
+
+// Defined out-of-line here because of dependecy on AttributeList
+Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope,
+ SourceLocation UsingLoc,
+ SourceLocation NamespcLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *NamespcName,
+ AttributeList *AttrList) {
+
+ // FIXME: Parser seems to assume that Action::ActOn* takes ownership over
+ // passed AttributeList, however other actions don't free it, is it
+ // temporary state or bug?
+ delete AttrList;
+ return DeclPtrTy();
+}
+
+
+void PrettyStackTraceActionsDecl::print(llvm::raw_ostream &OS) const {
+ if (Loc.isValid()) {
+ Loc.print(OS, SM);
+ OS << ": ";
+ }
+ OS << Message;
+
+ std::string Name = Actions.getDeclName(TheDecl);
+ if (!Name.empty())
+ OS << " '" << Name << '\'';
+
+ OS << '\n';
+}
+
+/// TypeNameInfo - A link exists here for each scope that an identifier is
+/// defined.
+namespace {
+ struct TypeNameInfo {
+ TypeNameInfo *Prev;
+ bool isTypeName;
+
+ TypeNameInfo(bool istypename, TypeNameInfo *prev) {
+ isTypeName = istypename;
+ Prev = prev;
+ }
+ };
+
+ struct TypeNameInfoTable {
+ llvm::RecyclingAllocator<llvm::BumpPtrAllocator, TypeNameInfo> Allocator;
+
+ void AddEntry(bool isTypename, IdentifierInfo *II) {
+ TypeNameInfo *TI = Allocator.Allocate<TypeNameInfo>();
+ new (TI) TypeNameInfo(isTypename, II->getFETokenInfo<TypeNameInfo>());
+ II->setFETokenInfo(TI);
+ }
+
+ void DeleteEntry(TypeNameInfo *Entry) {
+ Entry->~TypeNameInfo();
+ Allocator.Deallocate(Entry);
+ }
+ };
+}
+
+static TypeNameInfoTable *getTable(void *TP) {
+ return static_cast<TypeNameInfoTable*>(TP);
+}
+
+MinimalAction::MinimalAction(Preprocessor &pp)
+ : Idents(pp.getIdentifierTable()), PP(pp) {
+ TypeNameInfoTablePtr = new TypeNameInfoTable();
+}
+
+MinimalAction::~MinimalAction() {
+ delete getTable(TypeNameInfoTablePtr);
+}
+
+void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
+ TUScope = S;
+
+ TypeNameInfoTable &TNIT = *getTable(TypeNameInfoTablePtr);
+
+ if (PP.getTargetInfo().getPointerWidth(0) >= 64) {
+ // Install [u]int128_t for 64-bit targets.
+ TNIT.AddEntry(true, &Idents.get("__int128_t"));
+ TNIT.AddEntry(true, &Idents.get("__uint128_t"));
+ }
+
+ if (PP.getLangOptions().ObjC1) {
+ // Recognize the ObjC built-in type identifiers as types.
+ TNIT.AddEntry(true, &Idents.get("id"));
+ TNIT.AddEntry(true, &Idents.get("SEL"));
+ TNIT.AddEntry(true, &Idents.get("Class"));
+ TNIT.AddEntry(true, &Idents.get("Protocol"));
+ }
+}
+
+/// isTypeName - This looks at the IdentifierInfo::FETokenInfo field to
+/// determine whether the name is a type name (objc class name or typedef) or
+/// not in this scope.
+///
+/// FIXME: Use the passed CXXScopeSpec for accurate C++ type checking.
+Action::TypeTy *
+MinimalAction::getTypeName(IdentifierInfo &II, SourceLocation Loc,
+ Scope *S, const CXXScopeSpec *SS) {
+ if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>())
+ if (TI->isTypeName)
+ return TI;
+ return 0;
+}
+
+/// isCurrentClassName - Always returns false, because MinimalAction
+/// does not support C++ classes with constructors.
+bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *,
+ const CXXScopeSpec *) {
+ return false;
+}
+
+TemplateNameKind
+MinimalAction::isTemplateName(const IdentifierInfo &II, Scope *S,
+ TemplateTy &TemplateDecl,
+ const CXXScopeSpec *SS) {
+ return TNK_Non_template;
+}
+
+/// ActOnDeclarator - If this is a typedef declarator, we modify the
+/// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is
+/// popped.
+Action::DeclPtrTy
+MinimalAction::ActOnDeclarator(Scope *S, Declarator &D) {
+ IdentifierInfo *II = D.getIdentifier();
+
+ // If there is no identifier associated with this declarator, bail out.
+ if (II == 0) return DeclPtrTy();
+
+ TypeNameInfo *weCurrentlyHaveTypeInfo = II->getFETokenInfo<TypeNameInfo>();
+ bool isTypeName =
+ D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef;
+
+ // this check avoids creating TypeNameInfo objects for the common case.
+ // It does need to handle the uncommon case of shadowing a typedef name with a
+ // non-typedef name. e.g. { typedef int a; a xx; { int a; } }
+ if (weCurrentlyHaveTypeInfo || isTypeName) {
+ // Allocate and add the 'TypeNameInfo' "decl".
+ getTable(TypeNameInfoTablePtr)->AddEntry(isTypeName, II);
+
+ // Remember that this needs to be removed when the scope is popped.
+ S->AddDecl(DeclPtrTy::make(II));
+ }
+ return DeclPtrTy();
+}
+
+Action::DeclPtrTy
+MinimalAction::ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLoc,
+ IdentifierInfo *SuperName,
+ SourceLocation SuperLoc,
+ const DeclPtrTy *ProtoRefs,
+ unsigned NumProtocols,
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList) {
+ // Allocate and add the 'TypeNameInfo' "decl".
+ getTable(TypeNameInfoTablePtr)->AddEntry(true, ClassName);
+ return DeclPtrTy();
+}
+
+/// ActOnForwardClassDeclaration -
+/// Scope will always be top level file scope.
+Action::DeclPtrTy
+MinimalAction::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
+ IdentifierInfo **IdentList, unsigned NumElts) {
+ for (unsigned i = 0; i != NumElts; ++i) {
+ // Allocate and add the 'TypeNameInfo' "decl".
+ getTable(TypeNameInfoTablePtr)->AddEntry(true, IdentList[i]);
+
+ // Remember that this needs to be removed when the scope is popped.
+ TUScope->AddDecl(DeclPtrTy::make(IdentList[i]));
+ }
+ return DeclPtrTy();
+}
+
+/// ActOnPopScope - When a scope is popped, if any typedefs are now
+/// out-of-scope, they are removed from the IdentifierInfo::FETokenInfo field.
+void MinimalAction::ActOnPopScope(SourceLocation Loc, Scope *S) {
+ TypeNameInfoTable &Table = *getTable(TypeNameInfoTablePtr);
+
+ for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end();
+ I != E; ++I) {
+ IdentifierInfo &II = *(*I).getAs<IdentifierInfo>();
+ TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>();
+ assert(TI && "This decl didn't get pushed??");
+
+ if (TI) {
+ TypeNameInfo *Next = TI->Prev;
+ Table.DeleteEntry(TI);
+
+ II.setFETokenInfo(Next);
+ }
+ }
+}
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
new file mode 100644
index 000000000000..af6fab7cb188
--- /dev/null
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -0,0 +1,271 @@
+//===--- ParseCXXInlineMethods.cpp - C++ class inline methods parsing------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements parsing for C++ class inline methods.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+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.
+Parser::DeclPtrTy
+Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
+ assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
+ "This isn't a function declarator!");
+ assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) &&
+ "Current token not a '{', ':' or 'try'!");
+
+ DeclPtrTy FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 0, 0);
+
+ // Consume the tokens and store them for later parsing.
+
+ getCurrentClass().MethodDefs.push_back(LexedMethod(FnD));
+ CachedTokens &Toks = getCurrentClass().MethodDefs.back().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, tok::unknown, Toks, tok::semi)) {
+ // 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();
+ getCurrentClass().MethodDefs.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, tok::unknown, Toks);
+
+ // If we're in a function-try-block, we need to store all the catch blocks.
+ if (kind == tok::kw_try) {
+ while (Tok.is(tok::kw_catch)) {
+ ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks);
+ ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
+ }
+ }
+
+ return FnD;
+}
+
+/// ParseLexedMethodDeclarations - We finished parsing the member
+/// specification of a top (non-nested) C++ class. Now go over the
+/// stack of method declarations with some parts for which parsing was
+/// delayed (such as default arguments) and parse them.
+void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
+ bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
+ ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope);
+ if (HasTemplateScope)
+ Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate);
+
+ bool HasClassScope = !Class.TopLevelClass;
+ ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
+ HasClassScope);
+
+ for (; !Class.MethodDecls.empty(); Class.MethodDecls.pop_front()) {
+ LateParsedMethodDeclaration &LM = Class.MethodDecls.front();
+
+ // FIXME: For member function templates, we'll need to introduce a
+ // scope for the template parameters.
+
+ // Start the delayed C++ method declaration
+ Actions.ActOnStartDelayedCXXMethodDeclaration(CurScope, LM.Method);
+
+ // Introduce the parameters into scope and parse their default
+ // arguments.
+ ParseScope PrototypeScope(this,
+ Scope::FunctionPrototypeScope|Scope::DeclScope);
+ for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {
+ // Introduce the parameter into scope.
+ Actions.ActOnDelayedCXXMethodParameter(CurScope, LM.DefaultArgs[I].Param);
+
+ if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) {
+ // Parse the default argument from its saved token stream.
+ Toks->push_back(Tok); // So that the current token doesn't get lost
+ PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false);
+
+ // Consume the previously-pushed token.
+ ConsumeAnyToken();
+
+ // Consume the '='.
+ assert(Tok.is(tok::equal) && "Default argument not starting with '='");
+ SourceLocation EqualLoc = ConsumeToken();
+
+ OwningExprResult DefArgResult(ParseAssignmentExpression());
+ if (DefArgResult.isInvalid())
+ Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param);
+ else
+ Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc,
+ move(DefArgResult));
+ delete Toks;
+ LM.DefaultArgs[I].Toks = 0;
+ }
+ }
+ PrototypeScope.Exit();
+
+ // Finish the delayed C++ method declaration.
+ Actions.ActOnFinishDelayedCXXMethodDeclaration(CurScope, LM.Method);
+ }
+
+ for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I)
+ ParseLexedMethodDeclarations(*Class.NestedClasses[I]);
+}
+
+/// ParseLexedMethodDefs - We finished parsing the member specification of a top
+/// (non-nested) C++ class. Now go over the stack of lexed methods that were
+/// collected during its parsing and parse them all.
+void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
+ bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
+ ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope);
+ if (HasTemplateScope)
+ Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate);
+
+ bool HasClassScope = !Class.TopLevelClass;
+ ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
+ HasClassScope);
+
+ for (; !Class.MethodDefs.empty(); Class.MethodDefs.pop_front()) {
+ LexedMethod &LM = Class.MethodDefs.front();
+
+ assert(!LM.Toks.empty() && "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.front(), LM.Toks.size(), true, false);
+
+ // Consume the previously pushed token.
+ ConsumeAnyToken();
+ assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try))
+ && "Inline method not starting with '{', ':' or 'try'");
+
+ // Parse the method body. Function body parsing code is similar enough
+ // to be re-used for method bodies as well.
+ ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
+ Actions.ActOnStartOfFunctionDef(CurScope, LM.D);
+
+ if (Tok.is(tok::kw_try)) {
+ ParseFunctionTryBlock(LM.D);
+ continue;
+ }
+ if (Tok.is(tok::colon))
+ ParseConstructorInitializer(LM.D);
+ // FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'??
+ ParseFunctionStatementBody(LM.D);
+ }
+
+ for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I)
+ ParseLexedMethodDefs(*Class.NestedClasses[I]);
+}
+
+/// ConsumeAndStoreUntil - Consume and store the token at the passed token
+/// container until the token 'T' is reached (which gets
+/// consumed/stored too, if ConsumeFinalToken).
+/// If EarlyAbortIf is specified, then we will stop early if we find that
+/// token at the top level.
+/// Returns true if token 'T1' or 'T2' was found.
+/// NOTE: This is a specialized version of Parser::SkipUntil.
+bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
+ CachedTokens &Toks,
+ tok::TokenKind EarlyAbortIf,
+ bool ConsumeFinalToken) {
+ // We always want this function to consume at least one token if the first
+ // token isn't T and if not at EOF.
+ bool isFirstTokenConsumed = true;
+ while (1) {
+ // If we found one of the tokens, stop and return true.
+ if (Tok.is(T1) || Tok.is(T2)) {
+ if (ConsumeFinalToken) {
+ Toks.push_back(Tok);
+ ConsumeAnyToken();
+ }
+ return true;
+ }
+
+ // If we found the early-abort token, return.
+ if (Tok.is(EarlyAbortIf))
+ return false;
+
+ switch (Tok.getKind()) {
+ case tok::eof:
+ // Ran out of tokens.
+ return false;
+
+ case tok::l_paren:
+ // Recursively consume properly-nested parens.
+ Toks.push_back(Tok);
+ ConsumeParen();
+ ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks);
+ break;
+ case tok::l_square:
+ // Recursively consume properly-nested square brackets.
+ Toks.push_back(Tok);
+ ConsumeBracket();
+ ConsumeAndStoreUntil(tok::r_square, tok::unknown, Toks);
+ break;
+ case tok::l_brace:
+ // Recursively consume properly-nested braces.
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
+ break;
+
+ // Okay, we found a ']' or '}' or ')', which we think should be balanced.
+ // Since the user wasn't looking for this token (if they were, it would
+ // already be handled), this isn't balanced. If there is a LHS token at a
+ // higher level, we will assume that this matches the unbalanced token
+ // and return it. Otherwise, this is a spurious RHS token, which we skip.
+ case tok::r_paren:
+ if (ParenCount && !isFirstTokenConsumed)
+ return false; // Matches something.
+ Toks.push_back(Tok);
+ ConsumeParen();
+ break;
+ case tok::r_square:
+ if (BracketCount && !isFirstTokenConsumed)
+ return false; // Matches something.
+ Toks.push_back(Tok);
+ ConsumeBracket();
+ break;
+ case tok::r_brace:
+ if (BraceCount && !isFirstTokenConsumed)
+ return false; // Matches something.
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ break;
+
+ case tok::string_literal:
+ case tok::wide_string_literal:
+ Toks.push_back(Tok);
+ ConsumeStringToken();
+ break;
+ default:
+ // consume this token.
+ Toks.push_back(Tok);
+ ConsumeToken();
+ break;
+ }
+ isFirstTokenConsumed = false;
+ }
+}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
new file mode 100644
index 000000000000..39eaf36c9574
--- /dev/null
+++ b/lib/Parse/ParseDecl.cpp
@@ -0,0 +1,2707 @@
+//===--- ParseDecl.cpp - Declaration Parsing ------------------------------===//
+//
+// 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 Declaration portions of the Parser interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Scope.h"
+#include "ExtensionRAIIObject.h"
+#include "llvm/ADT/SmallSet.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// C99 6.7: Declarations.
+//===----------------------------------------------------------------------===//
+
+/// ParseTypeName
+/// type-name: [C99 6.7.6]
+/// specifier-qualifier-list abstract-declarator[opt]
+///
+/// Called type-id in C++.
+Action::TypeResult Parser::ParseTypeName(SourceRange *Range) {
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS;
+ ParseSpecifierQualifierList(DS);
+
+ // Parse the abstract-declarator, if present.
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ ParseDeclarator(DeclaratorInfo);
+ if (Range)
+ *Range = DeclaratorInfo.getSourceRange();
+
+ if (DeclaratorInfo.isInvalidType())
+ return true;
+
+ return Actions.ActOnTypeName(CurScope, DeclaratorInfo);
+}
+
+/// ParseAttributes - Parse a non-empty attributes list.
+///
+/// [GNU] attributes:
+/// attribute
+/// attributes attribute
+///
+/// [GNU] attribute:
+/// '__attribute__' '(' '(' attribute-list ')' ')'
+///
+/// [GNU] attribute-list:
+/// attrib
+/// attribute_list ',' attrib
+///
+/// [GNU] attrib:
+/// empty
+/// attrib-name
+/// attrib-name '(' identifier ')'
+/// attrib-name '(' identifier ',' nonempty-expr-list ')'
+/// attrib-name '(' argument-expression-list [C99 6.5.2] ')'
+///
+/// [GNU] attrib-name:
+/// identifier
+/// typespec
+/// typequal
+/// storageclass
+///
+/// FIXME: The GCC grammar/code for this construct implies we need two
+/// token lookahead. Comment from gcc: "If they start with an identifier
+/// which is followed by a comma or close parenthesis, then the arguments
+/// start with that identifier; otherwise they are an expression list."
+///
+/// At the moment, I am not doing 2 token lookahead. I am also unaware of
+/// any attributes that don't work (based on my limited testing). Most
+/// attributes are very simple in practice. Until we find a bug, I don't see
+/// a pressing need to implement the 2 token lookahead.
+
+AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
+ assert(Tok.is(tok::kw___attribute) && "Not an attribute list!");
+
+ AttributeList *CurrAttr = 0;
+
+ while (Tok.is(tok::kw___attribute)) {
+ ConsumeToken();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
+ "attribute")) {
+ SkipUntil(tok::r_paren, true); // skip until ) or ;
+ return CurrAttr;
+ }
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) {
+ SkipUntil(tok::r_paren, true); // skip until ) or ;
+ return CurrAttr;
+ }
+ // 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();
+ continue;
+ }
+ // we have an identifier or declaration specifier (const, int, etc.)
+ IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+ SourceLocation AttrNameLoc = ConsumeToken();
+
+ // check if we have a "paramterized" attribute
+ 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
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ ParmName, ParmLoc, 0, 0, CurrAttr);
+ } 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) {
+ OwningExprResult 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
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName,
+ ParmLoc, ArgExprs.take(), ArgExprs.size(), CurrAttr);
+ }
+ }
+ } else { // not an identifier
+ // parse a possibly empty comma separated list of expressions
+ if (Tok.is(tok::r_paren)) {
+ // __attribute__(( nonnull() ))
+ ConsumeParen(); // ignore the right paren loc for now
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ 0, SourceLocation(), 0, 0, CurrAttr);
+ } else {
+ // __attribute__(( aligned(16) ))
+ ExprVector ArgExprs(Actions);
+ bool ArgExprsOk = true;
+
+ // now parse the list of expressions
+ while (1) {
+ OwningExprResult 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
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
+ SourceLocation(), ArgExprs.take(), ArgExprs.size(),
+ CurrAttr);
+ }
+ }
+ }
+ } else {
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ 0, SourceLocation(), 0, 0, CurrAttr);
+ }
+ }
+ if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
+ SkipUntil(tok::r_paren, false);
+ SourceLocation Loc = Tok.getLocation();;
+ if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
+ SkipUntil(tok::r_paren, false);
+ }
+ if (EndLoc)
+ *EndLoc = Loc;
+ }
+ return CurrAttr;
+}
+
+/// FuzzyParseMicrosoftDeclSpec. When -fms-extensions is enabled, this
+/// routine is called to skip/ignore tokens that comprise the MS declspec.
+void Parser::FuzzyParseMicrosoftDeclSpec() {
+ assert(Tok.is(tok::kw___declspec) && "Not a declspec!");
+ ConsumeToken();
+ if (Tok.is(tok::l_paren)) {
+ unsigned short savedParenCount = ParenCount;
+ do {
+ ConsumeAnyToken();
+ } while (ParenCount > savedParenCount && Tok.isNot(tok::eof));
+ }
+ return;
+}
+
+/// ParseDeclaration - Parse a full 'declaration', which consists of
+/// declaration-specifiers, some number of declarators, and a semicolon.
+/// 'Context' should be a Declarator::TheContext value. This returns the
+/// location of the semicolon in DeclEnd.
+///
+/// declaration: [C99 6.7]
+/// block-declaration ->
+/// simple-declaration
+/// others [FIXME]
+/// [C++] template-declaration
+/// [C++] namespace-definition
+/// [C++] using-directive
+/// [C++] using-declaration [TODO]
+/// [C++0x] static_assert-declaration
+/// others... [FIXME]
+///
+Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
+ SourceLocation &DeclEnd) {
+ DeclPtrTy SingleDecl;
+ switch (Tok.getKind()) {
+ case tok::kw_template:
+ case tok::kw_export:
+ SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd);
+ break;
+ case tok::kw_namespace:
+ SingleDecl = ParseNamespace(Context, DeclEnd);
+ break;
+ case tok::kw_using:
+ SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd);
+ break;
+ case tok::kw_static_assert:
+ SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
+ break;
+ default:
+ return ParseSimpleDeclaration(Context, DeclEnd);
+ }
+
+ // This routine returns a DeclGroup, if the thing we parsed only contains a
+ // single decl, convert it now.
+ return Actions.ConvertDeclToDeclGroup(SingleDecl);
+}
+
+/// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl]
+/// declaration-specifiers init-declarator-list[opt] ';'
+///[C90/C++]init-declarator-list ';' [TODO]
+/// [OMP] threadprivate-directive [TODO]
+///
+/// If RequireSemi is false, this does not check for a ';' at the end of the
+/// declaration.
+Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
+ SourceLocation &DeclEnd,
+ bool RequireSemi) {
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS);
+
+ // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
+ // declaration-specifiers init-declarator-list[opt] ';'
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ return Actions.ConvertDeclToDeclGroup(TheDecl);
+ }
+
+ Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context);
+ ParseDeclarator(DeclaratorInfo);
+
+ DeclGroupPtrTy DG =
+ ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
+
+ DeclEnd = Tok.getLocation();
+
+ // If the client wants to check what comes after the declaration, just return
+ // immediately without checking anything!
+ if (!RequireSemi) return DG;
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ return DG;
+ }
+
+ Diag(Tok, diag::err_expected_semi_declation);
+ // Skip to end of block or statement
+ SkipUntil(tok::r_brace, true, true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ return DG;
+}
+
+/// \brief Parse 'declaration' after parsing 'declaration-specifiers
+/// declarator'. This method parses the remainder of the declaration
+/// (including any attributes or initializer, among other things) and
+/// finalizes the declaration.
+///
+/// init-declarator: [C99 6.7]
+/// declarator
+/// declarator '=' initializer
+/// [GNU] declarator simple-asm-expr[opt] attributes[opt]
+/// [GNU] declarator simple-asm-expr[opt] attributes[opt] '=' initializer
+/// [C++] declarator initializer[opt]
+///
+/// [C++] initializer:
+/// [C++] '=' initializer-clause
+/// [C++] '(' expression-list ')'
+/// [C++0x] '=' 'default' [TODO]
+/// [C++0x] '=' 'delete'
+///
+/// According to the standard grammar, =default and =delete are function
+/// definitions, but that definitely doesn't fit with the parser here.
+///
+Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D) {
+ // If a simple-asm-expr is present, parse it.
+ if (Tok.is(tok::kw_asm)) {
+ SourceLocation Loc;
+ OwningExprResult AsmLabel(ParseSimpleAsm(&Loc));
+ if (AsmLabel.isInvalid()) {
+ SkipUntil(tok::semi, true, true);
+ return DeclPtrTy();
+ }
+
+ D.setAsmLabel(AsmLabel.release());
+ D.SetRangeEnd(Loc);
+ }
+
+ // If attributes are present, parse them.
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ D.AddAttributes(AttrList, Loc);
+ }
+
+ // Inform the current actions module that we just parsed this declarator.
+ DeclPtrTy ThisDecl = Actions.ActOnDeclarator(CurScope, D);
+
+ // Parse declarator '=' initializer.
+ if (Tok.is(tok::equal)) {
+ ConsumeToken();
+ if (getLang().CPlusPlus0x && Tok.is(tok::kw_delete)) {
+ SourceLocation DelLoc = ConsumeToken();
+ Actions.SetDeclDeleted(ThisDecl, DelLoc);
+ } else {
+ OwningExprResult Init(ParseInitializer());
+ if (Init.isInvalid()) {
+ SkipUntil(tok::semi, true, true);
+ return DeclPtrTy();
+ }
+ Actions.AddInitializerToDecl(ThisDecl, Actions.FullExpr(Init));
+ }
+ } else if (Tok.is(tok::l_paren)) {
+ // Parse C++ direct initializer: '(' expression-list ')'
+ SourceLocation LParenLoc = ConsumeParen();
+ ExprVector Exprs(Actions);
+ CommaLocsTy CommaLocs;
+
+ if (ParseExpressionList(Exprs, CommaLocs)) {
+ SkipUntil(tok::r_paren);
+ } else {
+ // Match the ')'.
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() &&
+ "Unexpected number of commas!");
+ Actions.AddCXXDirectInitializerToDecl(ThisDecl, LParenLoc,
+ move_arg(Exprs),
+ CommaLocs.data(), RParenLoc);
+ }
+ } else {
+ Actions.ActOnUninitializedDecl(ThisDecl);
+ }
+
+ return ThisDecl;
+}
+
+/// ParseInitDeclaratorListAfterFirstDeclarator - Parse 'declaration' after
+/// parsing 'declaration-specifiers declarator'. This method is split out this
+/// way to handle the ambiguity between top-level function-definitions and
+/// declarations.
+///
+/// init-declarator-list: [C99 6.7]
+/// init-declarator
+/// init-declarator-list ',' init-declarator
+///
+/// According to the standard grammar, =default and =delete are function
+/// definitions, but that definitely doesn't fit with the parser here.
+///
+Parser::DeclGroupPtrTy Parser::
+ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
+ // Declarators may be grouped together ("int X, *Y, Z();"). Remember the decls
+ // that we parse together here.
+ llvm::SmallVector<DeclPtrTy, 8> DeclsInGroup;
+
+ // At this point, we know that it is not a function definition. Parse the
+ // rest of the init-declarator-list.
+ while (1) {
+ DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(D);
+ if (ThisDecl.get())
+ DeclsInGroup.push_back(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))
+ break;
+
+ // Consume the comma.
+ ConsumeToken();
+
+ // Parse the next declarator.
+ D.clear();
+
+ // Accept attributes in an init-declarator. In the first declarator in a
+ // declaration, these would be part of the declspec. In subsequent
+ // declarators, they become part of the declarator itself, so that they
+ // don't apply to declarators after *this* one. Examples:
+ // short __attribute__((common)) var; -> declspec
+ // short var __attribute__((common)); -> declarator
+ // short x, __attribute__((common)) var; -> declarator
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ D.AddAttributes(AttrList, Loc);
+ }
+
+ ParseDeclarator(D);
+ }
+
+ return Actions.FinalizeDeclaratorGroup(CurScope, D.getDeclSpec(),
+ DeclsInGroup.data(),
+ DeclsInGroup.size());
+}
+
+/// ParseSpecifierQualifierList
+/// specifier-qualifier-list:
+/// type-specifier specifier-qualifier-list[opt]
+/// type-qualifier specifier-qualifier-list[opt]
+/// [GNU] attributes specifier-qualifier-list[opt]
+///
+void Parser::ParseSpecifierQualifierList(DeclSpec &DS) {
+ /// specifier-qualifier-list is a subset of declaration-specifiers. Just
+ /// parse declaration-specifiers and complain about extra stuff.
+ ParseDeclarationSpecifiers(DS);
+
+ // Validate declspec for type-name.
+ unsigned Specs = DS.getParsedSpecifiers();
+ if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() &&
+ !DS.getAttributes())
+ Diag(Tok, diag::err_typename_requires_specqual);
+
+ // Issue diagnostic and remove storage class if present.
+ if (Specs & DeclSpec::PQ_StorageClassSpecifier) {
+ if (DS.getStorageClassSpecLoc().isValid())
+ Diag(DS.getStorageClassSpecLoc(),diag::err_typename_invalid_storageclass);
+ else
+ Diag(DS.getThreadSpecLoc(), diag::err_typename_invalid_storageclass);
+ DS.ClearStorageClassSpecs();
+ }
+
+ // Issue diagnostic and remove function specfier if present.
+ if (Specs & DeclSpec::PQ_FunctionSpecifier) {
+ if (DS.isInlineSpecified())
+ Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec);
+ if (DS.isVirtualSpecified())
+ Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec);
+ if (DS.isExplicitSpecified())
+ Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec);
+ DS.ClearFunctionSpecs();
+ }
+}
+
+/// isValidAfterIdentifierInDeclaratorAfterDeclSpec - Return true if the
+/// specified token is valid after the identifier in a declarator which
+/// immediately follows the declspec. For example, these things are valid:
+///
+/// int x [ 4]; // direct-declarator
+/// int x ( int y); // direct-declarator
+/// int(int x ) // direct-declarator
+/// int x ; // simple-declaration
+/// int x = 17; // init-declarator-list
+/// int x , y; // init-declarator-list
+/// int x __asm__ ("foo"); // init-declarator-list
+/// int x : 4; // struct-declarator
+/// int x { 5}; // C++'0x unified initializers
+///
+/// This is not, because 'x' does not immediately follow the declspec (though
+/// ')' happens to be valid anyway).
+/// int (x)
+///
+static bool isValidAfterIdentifierInDeclarator(const Token &T) {
+ return T.is(tok::l_square) || T.is(tok::l_paren) || T.is(tok::r_paren) ||
+ T.is(tok::semi) || T.is(tok::comma) || T.is(tok::equal) ||
+ T.is(tok::kw_asm) || T.is(tok::l_brace) || T.is(tok::colon);
+}
+
+
+/// ParseImplicitInt - This method is called when we have an non-typename
+/// identifier in a declspec (which normally terminates the decl spec) when
+/// the declspec has no type specifier. In this case, the declspec is either
+/// malformed or is "implicit int" (in K&R and C89).
+///
+/// This method handles diagnosing this prettily and returns false if the
+/// declspec is done being processed. If it recovers and thinks there may be
+/// other pieces of declspec after it, it returns true.
+///
+bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
+ const ParsedTemplateInfo &TemplateInfo,
+ AccessSpecifier AS) {
+ assert(Tok.is(tok::identifier) && "should have identifier");
+
+ SourceLocation Loc = Tok.getLocation();
+ // If we see an identifier that is not a type name, we normally would
+ // parse it as the identifer being declared. However, when a typename
+ // is typo'd or the definition is not included, this will incorrectly
+ // parse the typename as the identifier name and fall over misparsing
+ // later parts of the diagnostic.
+ //
+ // As such, we try to do some look-ahead in cases where this would
+ // otherwise be an "implicit-int" case to see if this is invalid. For
+ // example: "static foo_t x = 4;" In this case, if we parsed foo_t as
+ // an identifier with implicit int, we'd get a parse error because the
+ // next token is obviously invalid for a type. Parse these as a case
+ // with an invalid type specifier.
+ assert(!DS.hasTypeSpecifier() && "Type specifier checked above");
+
+ // Since we know that this either implicit int (which is rare) or an
+ // error, we'd do lookahead to try to do better recovery.
+ if (isValidAfterIdentifierInDeclarator(NextToken())) {
+ // If this token is valid for implicit int, e.g. "static x = 4", then
+ // we just avoid eating the identifier, so it will be parsed as the
+ // identifier in the declarator.
+ return false;
+ }
+
+ // Otherwise, if we don't consume this token, we are going to emit an
+ // error anyway. Try to recover from various common problems. Check
+ // to see if this was a reference to a tag name without a tag specified.
+ // This is a common problem in C (saying 'foo' instead of 'struct foo').
+ //
+ // C++ doesn't need this, and isTagName doesn't take SS.
+ if (SS == 0) {
+ const char *TagName = 0;
+ tok::TokenKind TagKind = tok::unknown;
+
+ switch (Actions.isTagName(*Tok.getIdentifierInfo(), CurScope)) {
+ default: break;
+ case DeclSpec::TST_enum: TagName="enum" ;TagKind=tok::kw_enum ;break;
+ case DeclSpec::TST_union: TagName="union" ;TagKind=tok::kw_union ;break;
+ case DeclSpec::TST_struct:TagName="struct";TagKind=tok::kw_struct;break;
+ case DeclSpec::TST_class: TagName="class" ;TagKind=tok::kw_class ;break;
+ }
+
+ if (TagName) {
+ Diag(Loc, diag::err_use_of_tag_name_without_tag)
+ << Tok.getIdentifierInfo() << TagName
+ << CodeModificationHint::CreateInsertion(Tok.getLocation(),TagName);
+
+ // Parse this as a tag as if the missing tag were present.
+ if (TagKind == tok::kw_enum)
+ ParseEnumSpecifier(Loc, DS, AS);
+ else
+ ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS);
+ return true;
+ }
+ }
+
+ // Since this is almost certainly an invalid type name, emit a
+ // diagnostic that says it, eat the token, and mark the declspec as
+ // invalid.
+ SourceRange R;
+ if (SS) R = SS->getRange();
+
+ Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo() << R;
+ const char *PrevSpec;
+ DS.SetTypeSpecType(DeclSpec::TST_error, Loc, PrevSpec);
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken();
+
+ // TODO: Could inject an invalid typedef decl in an enclosing scope to
+ // avoid rippling error messages on subsequent uses of the same type,
+ // could be useful if #include was forgotten.
+ return false;
+}
+
+/// ParseDeclarationSpecifiers
+/// declaration-specifiers: [C99 6.7]
+/// storage-class-specifier declaration-specifiers[opt]
+/// type-specifier declaration-specifiers[opt]
+/// [C99] function-specifier declaration-specifiers[opt]
+/// [GNU] attributes declaration-specifiers[opt]
+///
+/// storage-class-specifier: [C99 6.7.1]
+/// 'typedef'
+/// 'extern'
+/// 'static'
+/// 'auto'
+/// 'register'
+/// [C++] 'mutable'
+/// [GNU] '__thread'
+/// function-specifier: [C99 6.7.4]
+/// [C99] 'inline'
+/// [C++] 'virtual'
+/// [C++] 'explicit'
+/// 'friend': [C++ dcl.friend]
+
+///
+void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
+ const ParsedTemplateInfo &TemplateInfo,
+ AccessSpecifier AS) {
+ DS.SetRangeStart(Tok.getLocation());
+ while (1) {
+ int isInvalid = false;
+ const char *PrevSpec = 0;
+ SourceLocation Loc = Tok.getLocation();
+
+ switch (Tok.getKind()) {
+ default:
+ DoneWithDeclSpec:
+ // 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);
+ return;
+
+ case tok::coloncolon: // ::foo::bar
+ // Annotate C++ scope specifiers. If we get one, loop.
+ if (TryAnnotateCXXScopeToken())
+ continue;
+ goto DoneWithDeclSpec;
+
+ case tok::annot_cxxscope: {
+ if (DS.hasTypeSpecifier())
+ goto DoneWithDeclSpec;
+
+ // We are looking for a qualified typename.
+ Token Next = NextToken();
+ if (Next.is(tok::annot_template_id) &&
+ static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
+ ->Kind == TNK_Type_template) {
+ // We have a qualified template-id, e.g., N::A<int>
+ CXXScopeSpec SS;
+ ParseOptionalCXXScopeSpecifier(SS);
+ assert(Tok.is(tok::annot_template_id) &&
+ "ParseOptionalCXXScopeSpecifier not working");
+ AnnotateTemplateIdTokenAsType(&SS);
+ continue;
+ }
+
+ if (Next.isNot(tok::identifier))
+ goto DoneWithDeclSpec;
+
+ CXXScopeSpec SS;
+ SS.setScopeRep(Tok.getAnnotationValue());
+ SS.setRange(Tok.getAnnotationRange());
+
+ // If the next token is the name of the class type that the C++ scope
+ // denotes, followed by a '(', then this is a constructor declaration.
+ // We're done with the decl-specifiers.
+ if (Actions.isCurrentClassName(*Next.getIdentifierInfo(),
+ CurScope, &SS) &&
+ GetLookAheadToken(2).is(tok::l_paren))
+ goto DoneWithDeclSpec;
+
+ TypeTy *TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(),
+ Next.getLocation(), CurScope, &SS);
+
+ // If the referenced identifier is not a type, then this declspec is
+ // erroneous: We already checked about that it has no type specifier, and
+ // C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the
+ // typename.
+ if (TypeRep == 0) {
+ ConsumeToken(); // Eat the scope spec so the identifier is current.
+ if (ParseImplicitInt(DS, &SS, TemplateInfo, AS)) continue;
+ goto DoneWithDeclSpec;
+ }
+
+ ConsumeToken(); // The C++ scope.
+
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
+ TypeRep);
+ if (isInvalid)
+ break;
+
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken(); // The typename.
+
+ continue;
+ }
+
+ case tok::annot_typename: {
+ if (Tok.getAnnotationValue())
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
+ Tok.getAnnotationValue());
+ else
+ DS.SetTypeSpecError();
+ DS.SetRangeEnd(Tok.getAnnotationEndLoc());
+ ConsumeToken(); // The typename
+
+ // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
+ // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
+ // Objective-C interface. If we don't have Objective-C or a '<', this is
+ // just a normal reference to a typedef name.
+ if (!Tok.is(tok::less) || !getLang().ObjC1)
+ continue;
+
+ SourceLocation EndProtoLoc;
+ llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
+ ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
+ DS.setProtocolQualifiers(&ProtocolDecl[0], ProtocolDecl.size());
+
+ DS.SetRangeEnd(EndProtoLoc);
+ continue;
+ }
+
+ // typedef-name
+ case tok::identifier: {
+ // In C++, check to see if this is a scope specifier like foo::bar::, if
+ // so handle it as such. This is important for ctor parsing.
+ if (getLang().CPlusPlus && TryAnnotateCXXScopeToken())
+ continue;
+
+ // This identifier can only be a typedef name if we haven't already seen
+ // a type-specifier. Without this check we misparse:
+ // typedef int X; struct Y { short X; }; as 'short int'.
+ if (DS.hasTypeSpecifier())
+ goto DoneWithDeclSpec;
+
+ // It has to be available as a typedef too!
+ TypeTy *TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(),
+ Tok.getLocation(), CurScope);
+
+ // If this is not a typedef name, don't parse it as part of the declspec,
+ // it must be an implicit int or an error.
+ if (TypeRep == 0) {
+ if (ParseImplicitInt(DS, 0, TemplateInfo, AS)) continue;
+ goto DoneWithDeclSpec;
+ }
+
+ // C++: If the identifier is actually the name of the class type
+ // being defined and the next token is a '(', then this is a
+ // constructor declaration. We're done with the decl-specifiers
+ // and will treat this token as an identifier.
+ if (getLang().CPlusPlus && CurScope->isClassScope() &&
+ Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) &&
+ NextToken().getKind() == tok::l_paren)
+ goto DoneWithDeclSpec;
+
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
+ TypeRep);
+ if (isInvalid)
+ break;
+
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken(); // The identifier
+
+ // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
+ // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
+ // Objective-C interface. If we don't have Objective-C or a '<', this is
+ // just a normal reference to a typedef name.
+ if (!Tok.is(tok::less) || !getLang().ObjC1)
+ continue;
+
+ SourceLocation EndProtoLoc;
+ llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
+ ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
+ DS.setProtocolQualifiers(&ProtocolDecl[0], ProtocolDecl.size());
+
+ DS.SetRangeEnd(EndProtoLoc);
+
+ // Need to support trailing type qualifiers (e.g. "id<p> const").
+ // If a type specifier follows, it will be diagnosed elsewhere.
+ continue;
+ }
+
+ // type-name
+ case tok::annot_template_id: {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (TemplateId->Kind != TNK_Type_template) {
+ // This template-id does not refer to a type name, so we're
+ // done with the type-specifiers.
+ goto DoneWithDeclSpec;
+ }
+
+ // Turn the template-id annotation token into a type annotation
+ // token, then try again to parse it as a type-specifier.
+ AnnotateTemplateIdTokenAsType();
+ continue;
+ }
+
+ // GNU attributes support.
+ case tok::kw___attribute:
+ DS.AddAttributes(ParseAttributes());
+ continue;
+
+ // Microsoft declspec support.
+ case tok::kw___declspec:
+ if (!PP.getLangOptions().Microsoft)
+ goto DoneWithDeclSpec;
+ FuzzyParseMicrosoftDeclSpec();
+ continue;
+
+ // Microsoft single token adornments.
+ case tok::kw___forceinline:
+ case tok::kw___w64:
+ case tok::kw___cdecl:
+ case tok::kw___stdcall:
+ case tok::kw___fastcall:
+ if (!PP.getLangOptions().Microsoft)
+ goto DoneWithDeclSpec;
+ // Just ignore it.
+ break;
+
+ // storage-class-specifier
+ case tok::kw_typedef:
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec);
+ break;
+ case tok::kw_extern:
+ if (DS.isThreadSpecified())
+ Diag(Tok, diag::ext_thread_before) << "extern";
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec);
+ break;
+ case tok::kw___private_extern__:
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_private_extern, Loc,
+ PrevSpec);
+ break;
+ case tok::kw_static:
+ if (DS.isThreadSpecified())
+ Diag(Tok, diag::ext_thread_before) << "static";
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec);
+ break;
+ case tok::kw_auto:
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec);
+ break;
+ case tok::kw_register:
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec);
+ break;
+ case tok::kw_mutable:
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_mutable, Loc, PrevSpec);
+ break;
+ case tok::kw___thread:
+ isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec)*2;
+ break;
+
+ // function-specifier
+ case tok::kw_inline:
+ isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec);
+ break;
+ case tok::kw_virtual:
+ isInvalid = DS.SetFunctionSpecVirtual(Loc, PrevSpec);
+ break;
+ case tok::kw_explicit:
+ isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec);
+ break;
+
+ // friend
+ case tok::kw_friend:
+ isInvalid = DS.SetFriendSpec(Loc, PrevSpec);
+ break;
+
+ // type-specifier
+ case tok::kw_short:
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
+ break;
+ case tok::kw_long:
+ if (DS.getTypeSpecWidth() != DeclSpec::TSW_long)
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
+ else
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec);
+ break;
+ case tok::kw_signed:
+ isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
+ break;
+ case tok::kw_unsigned:
+ isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
+ break;
+ case tok::kw__Complex:
+ isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec);
+ break;
+ case tok::kw__Imaginary:
+ isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec);
+ break;
+ case tok::kw_void:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
+ break;
+ case tok::kw_char:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
+ break;
+ case tok::kw_int:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
+ break;
+ case tok::kw_float:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
+ break;
+ case tok::kw_double:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
+ break;
+ case tok::kw_wchar_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec);
+ break;
+ case tok::kw_bool:
+ case tok::kw__Bool:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
+ break;
+ case tok::kw__Decimal32:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec);
+ break;
+ case tok::kw__Decimal64:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec);
+ break;
+ case tok::kw__Decimal128:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec);
+ break;
+
+ // class-specifier:
+ case tok::kw_class:
+ case tok::kw_struct:
+ case tok::kw_union: {
+ tok::TokenKind Kind = Tok.getKind();
+ ConsumeToken();
+ ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS);
+ continue;
+ }
+
+ // enum-specifier:
+ case tok::kw_enum:
+ ConsumeToken();
+ ParseEnumSpecifier(Loc, DS, AS);
+ continue;
+
+ // cv-qualifier:
+ case tok::kw_const:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec,getLang())*2;
+ break;
+ case tok::kw_volatile:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw_restrict:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
+ getLang())*2;
+ break;
+
+ // C++ typename-specifier:
+ case tok::kw_typename:
+ if (TryAnnotateTypeOrScopeToken())
+ continue;
+ break;
+
+ // GNU typeof support.
+ case tok::kw_typeof:
+ ParseTypeofSpecifier(DS);
+ continue;
+
+ case tok::less:
+ // GCC ObjC supports types like "<SomeProtocol>" as a synonym for
+ // "id<SomeProtocol>". This is hopelessly old fashioned and dangerous,
+ // but we support it.
+ if (DS.hasTypeSpecifier() || !getLang().ObjC1)
+ goto DoneWithDeclSpec;
+
+ {
+ SourceLocation EndProtoLoc;
+ llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
+ ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
+ DS.setProtocolQualifiers(&ProtocolDecl[0], ProtocolDecl.size());
+ DS.SetRangeEnd(EndProtoLoc);
+
+ Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id)
+ << CodeModificationHint::CreateInsertion(Loc, "id")
+ << SourceRange(Loc, EndProtoLoc);
+ // Need to support trailing type qualifiers (e.g. "id<p> const").
+ // If a type specifier follows, it will be diagnosed elsewhere.
+ continue;
+ }
+ }
+ // If the specifier combination wasn't legal, issue a diagnostic.
+ if (isInvalid) {
+ assert(PrevSpec && "Method did not return previous specifier!");
+ // Pick between error or extwarn.
+ unsigned DiagID = isInvalid == 1 ? diag::err_invalid_decl_spec_combination
+ : diag::ext_duplicate_declspec;
+ Diag(Tok, DiagID) << PrevSpec;
+ }
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken();
+ }
+}
+
+/// ParseOptionalTypeSpecifier - Try to parse a single type-specifier. We
+/// primarily follow the C++ grammar with additions for C99 and GNU,
+/// which together subsume the C grammar. Note that the C++
+/// type-specifier also includes the C type-qualifier (for const,
+/// volatile, and C99 restrict). Returns true if a type-specifier was
+/// found (and parsed), false otherwise.
+///
+/// type-specifier: [C++ 7.1.5]
+/// simple-type-specifier
+/// class-specifier
+/// enum-specifier
+/// elaborated-type-specifier [TODO]
+/// cv-qualifier
+///
+/// cv-qualifier: [C++ 7.1.5.1]
+/// 'const'
+/// 'volatile'
+/// [C99] 'restrict'
+///
+/// simple-type-specifier: [ C++ 7.1.5.2]
+/// '::'[opt] nested-name-specifier[opt] type-name [TODO]
+/// '::'[opt] nested-name-specifier 'template' template-id [TODO]
+/// 'char'
+/// 'wchar_t'
+/// 'bool'
+/// 'short'
+/// 'int'
+/// 'long'
+/// 'signed'
+/// 'unsigned'
+/// 'float'
+/// 'double'
+/// 'void'
+/// [C99] '_Bool'
+/// [C99] '_Complex'
+/// [C99] '_Imaginary' // Removed in TC2?
+/// [GNU] '_Decimal32'
+/// [GNU] '_Decimal64'
+/// [GNU] '_Decimal128'
+/// [GNU] typeof-specifier
+/// [OBJC] class-name objc-protocol-refs[opt] [TODO]
+/// [OBJC] typedef-name objc-protocol-refs[opt] [TODO]
+bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid,
+ const char *&PrevSpec,
+ const ParsedTemplateInfo &TemplateInfo) {
+ SourceLocation Loc = Tok.getLocation();
+
+ switch (Tok.getKind()) {
+ case tok::identifier: // foo::bar
+ 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())
+ return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, TemplateInfo);
+ // Otherwise, not a type specifier.
+ return false;
+ case tok::coloncolon: // ::foo::bar
+ if (NextToken().is(tok::kw_new) || // ::new
+ NextToken().is(tok::kw_delete)) // ::delete
+ return false;
+
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, TemplateInfo);
+ // Otherwise, not a type specifier.
+ return false;
+
+ // simple-type-specifier:
+ case tok::annot_typename: {
+ if (Tok.getAnnotationValue())
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
+ Tok.getAnnotationValue());
+ else
+ DS.SetTypeSpecError();
+ DS.SetRangeEnd(Tok.getAnnotationEndLoc());
+ ConsumeToken(); // The typename
+
+ // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
+ // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
+ // Objective-C interface. If we don't have Objective-C or a '<', this is
+ // just a normal reference to a typedef name.
+ if (!Tok.is(tok::less) || !getLang().ObjC1)
+ return true;
+
+ SourceLocation EndProtoLoc;
+ llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
+ ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
+ DS.setProtocolQualifiers(&ProtocolDecl[0], ProtocolDecl.size());
+
+ DS.SetRangeEnd(EndProtoLoc);
+ return true;
+ }
+
+ case tok::kw_short:
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
+ break;
+ case tok::kw_long:
+ if (DS.getTypeSpecWidth() != DeclSpec::TSW_long)
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
+ else
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec);
+ break;
+ case tok::kw_signed:
+ isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
+ break;
+ case tok::kw_unsigned:
+ isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
+ break;
+ case tok::kw__Complex:
+ isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec);
+ break;
+ case tok::kw__Imaginary:
+ isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec);
+ break;
+ case tok::kw_void:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
+ break;
+ case tok::kw_char:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
+ break;
+ case tok::kw_int:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
+ break;
+ case tok::kw_float:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
+ break;
+ case tok::kw_double:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
+ break;
+ case tok::kw_wchar_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec);
+ break;
+ case tok::kw_bool:
+ case tok::kw__Bool:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
+ break;
+ case tok::kw__Decimal32:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec);
+ break;
+ case tok::kw__Decimal64:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec);
+ break;
+ case tok::kw__Decimal128:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec);
+ break;
+
+ // class-specifier:
+ case tok::kw_class:
+ case tok::kw_struct:
+ case tok::kw_union: {
+ tok::TokenKind Kind = Tok.getKind();
+ ConsumeToken();
+ ParseClassSpecifier(Kind, Loc, DS, TemplateInfo);
+ return true;
+ }
+
+ // enum-specifier:
+ case tok::kw_enum:
+ ConsumeToken();
+ ParseEnumSpecifier(Loc, DS);
+ return true;
+
+ // cv-qualifier:
+ case tok::kw_const:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw_volatile:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw_restrict:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
+ getLang())*2;
+ break;
+
+ // GNU typeof support.
+ case tok::kw_typeof:
+ ParseTypeofSpecifier(DS);
+ return true;
+
+ case tok::kw___cdecl:
+ case tok::kw___stdcall:
+ case tok::kw___fastcall:
+ if (!PP.getLangOptions().Microsoft) return false;
+ ConsumeToken();
+ return true;
+
+ default:
+ // Not a type-specifier; do nothing.
+ return false;
+ }
+
+ // If the specifier combination wasn't legal, issue a diagnostic.
+ if (isInvalid) {
+ assert(PrevSpec && "Method did not return previous specifier!");
+ // Pick between error or extwarn.
+ unsigned DiagID = isInvalid == 1 ? diag::err_invalid_decl_spec_combination
+ : diag::ext_duplicate_declspec;
+ Diag(Tok, DiagID) << PrevSpec;
+ }
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken(); // whatever we parsed above.
+ return true;
+}
+
+/// ParseStructDeclaration - Parse a struct declaration without the terminating
+/// semicolon.
+///
+/// struct-declaration:
+/// specifier-qualifier-list struct-declarator-list
+/// [GNU] __extension__ struct-declaration
+/// [GNU] specifier-qualifier-list
+/// struct-declarator-list:
+/// struct-declarator
+/// struct-declarator-list ',' struct-declarator
+/// [GNU] struct-declarator-list ',' attributes[opt] struct-declarator
+/// struct-declarator:
+/// declarator
+/// [GNU] declarator attributes[opt]
+/// declarator[opt] ':' constant-expression
+/// [GNU] declarator[opt] ':' constant-expression attributes[opt]
+///
+void Parser::
+ParseStructDeclaration(DeclSpec &DS,
+ llvm::SmallVectorImpl<FieldDeclarator> &Fields) {
+ if (Tok.is(tok::kw___extension__)) {
+ // __extension__ silences extension warnings in the subexpression.
+ ExtensionRAIIObject O(Diags); // Use RAII to do this.
+ ConsumeToken();
+ return ParseStructDeclaration(DS, Fields);
+ }
+
+ // Parse the common specifier-qualifiers-list piece.
+ SourceLocation DSStart = Tok.getLocation();
+ ParseSpecifierQualifierList(DS);
+
+ // If there are no declarators, this is a free-standing declaration
+ // specifier. Let the actions module cope with it.
+ if (Tok.is(tok::semi)) {
+ Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ return;
+ }
+
+ // Read struct-declarators until we find the semicolon.
+ Fields.push_back(FieldDeclarator(DS));
+ while (1) {
+ FieldDeclarator &DeclaratorInfo = Fields.back();
+
+ /// struct-declarator: declarator
+ /// struct-declarator: declarator[opt] ':' constant-expression
+ if (Tok.isNot(tok::colon))
+ ParseDeclarator(DeclaratorInfo.D);
+
+ if (Tok.is(tok::colon)) {
+ ConsumeToken();
+ OwningExprResult Res(ParseConstantExpression());
+ if (Res.isInvalid())
+ SkipUntil(tok::semi, true, true);
+ else
+ DeclaratorInfo.BitfieldSize = Res.release();
+ }
+
+ // If attributes exist after the declarator, parse them.
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ DeclaratorInfo.D.AddAttributes(AttrList, Loc);
+ }
+
+ // 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))
+ return;
+
+ // Consume the comma.
+ ConsumeToken();
+
+ // Parse the next declarator.
+ Fields.push_back(FieldDeclarator(DS));
+
+ // Attributes are only allowed on the second declarator.
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ Fields.back().D.AddAttributes(AttrList, Loc);
+ }
+ }
+}
+
+/// ParseStructUnionBody
+/// struct-contents:
+/// struct-declaration-list
+/// [EXT] empty
+/// [GNU] "struct-declaration-list" without terminatoring ';'
+/// struct-declaration-list:
+/// struct-declaration
+/// struct-declaration-list struct-declaration
+/// [OBC] '@' 'defs' '(' class-name ')'
+///
+void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
+ unsigned TagType, DeclPtrTy TagDecl) {
+ PrettyStackTraceActionsDecl CrashInfo(TagDecl, RecordLoc, Actions,
+ PP.getSourceManager(),
+ "parsing struct/union body");
+
+ SourceLocation LBraceLoc = ConsumeBrace();
+
+ ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
+ Actions.ActOnTagStartDefinition(CurScope, TagDecl);
+
+ // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in
+ // C++.
+ if (Tok.is(tok::r_brace) && !getLang().CPlusPlus)
+ Diag(Tok, diag::ext_empty_struct_union_enum)
+ << DeclSpec::getSpecifierName((DeclSpec::TST)TagType);
+
+ llvm::SmallVector<DeclPtrTy, 32> FieldDecls;
+ llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators;
+
+ // While we still have something to read, read the declarations in the struct.
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ // Each iteration of this loop reads one struct-declaration.
+
+ // Check for extraneous top-level semicolon.
+ if (Tok.is(tok::semi)) {
+ Diag(Tok, diag::ext_extra_struct_semi)
+ << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation()));
+ ConsumeToken();
+ continue;
+ }
+
+ // Parse all the comma separated declarators.
+ DeclSpec DS;
+ FieldDeclarators.clear();
+ if (!Tok.is(tok::at)) {
+ ParseStructDeclaration(DS, FieldDeclarators);
+
+ // Convert them all to fields.
+ for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) {
+ FieldDeclarator &FD = FieldDeclarators[i];
+ // Install the declarator into the current TagDecl.
+ DeclPtrTy Field = Actions.ActOnField(CurScope, TagDecl,
+ DS.getSourceRange().getBegin(),
+ FD.D, FD.BitfieldSize);
+ FieldDecls.push_back(Field);
+ }
+ } else { // Handle @defs
+ ConsumeToken();
+ if (!Tok.isObjCAtKeyword(tok::objc_defs)) {
+ Diag(Tok, diag::err_unexpected_at);
+ SkipUntil(tok::semi, true, true);
+ continue;
+ }
+ ConsumeToken();
+ ExpectAndConsume(tok::l_paren, diag::err_expected_lparen);
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::semi, true, true);
+ continue;
+ }
+ llvm::SmallVector<DeclPtrTy, 16> Fields;
+ Actions.ActOnDefs(CurScope, TagDecl, Tok.getLocation(),
+ Tok.getIdentifierInfo(), Fields);
+ FieldDecls.insert(FieldDecls.end(), Fields.begin(), Fields.end());
+ ConsumeToken();
+ ExpectAndConsume(tok::r_paren, diag::err_expected_rparen);
+ }
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ } else if (Tok.is(tok::r_brace)) {
+ Diag(Tok, diag::ext_expected_semi_decl_list);
+ break;
+ } else {
+ Diag(Tok, diag::err_expected_semi_decl_list);
+ // Skip to end of block or statement
+ SkipUntil(tok::r_brace, true, true);
+ }
+ }
+
+ SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+
+ AttributeList *AttrList = 0;
+ // If attributes exist after struct contents, parse them.
+ if (Tok.is(tok::kw___attribute))
+ AttrList = ParseAttributes();
+
+ Actions.ActOnFields(CurScope,
+ RecordLoc, TagDecl, FieldDecls.data(), FieldDecls.size(),
+ LBraceLoc, RBraceLoc,
+ AttrList);
+ StructScope.Exit();
+ Actions.ActOnTagFinishDefinition(CurScope, TagDecl);
+}
+
+
+/// ParseEnumSpecifier
+/// enum-specifier: [C99 6.7.2.2]
+/// 'enum' identifier[opt] '{' enumerator-list '}'
+///[C99/C++]'enum' identifier[opt] '{' enumerator-list ',' '}'
+/// [GNU] 'enum' attributes[opt] identifier[opt] '{' enumerator-list ',' [opt]
+/// '}' attributes[opt]
+/// 'enum' identifier
+/// [GNU] 'enum' attributes[opt] identifier
+///
+/// [C++] elaborated-type-specifier:
+/// [C++] 'enum' '::'[opt] nested-name-specifier[opt] identifier
+///
+void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
+ AccessSpecifier AS) {
+ // Parse the tag portion of this.
+
+ AttributeList *Attr = 0;
+ // If attributes exist after tag, parse them.
+ if (Tok.is(tok::kw___attribute))
+ Attr = ParseAttributes();
+
+ CXXScopeSpec SS;
+ if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS)) {
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ if (Tok.isNot(tok::l_brace)) {
+ // Has no name and is not a definition.
+ // Skip the rest of this declarator, up until the comma or semicolon.
+ SkipUntil(tok::comma, true);
+ return;
+ }
+ }
+ }
+
+ // Must have either 'enum name' or 'enum {...}'.
+ if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_ident_lbrace);
+
+ // Skip the rest of this declarator, up until the comma or semicolon.
+ SkipUntil(tok::comma, true);
+ return;
+ }
+
+ // If an identifier is present, consume and remember it.
+ IdentifierInfo *Name = 0;
+ SourceLocation NameLoc;
+ if (Tok.is(tok::identifier)) {
+ Name = Tok.getIdentifierInfo();
+ NameLoc = ConsumeToken();
+ }
+
+ // There are three options here. If we have 'enum foo;', then this is a
+ // forward declaration. If we have 'enum foo {...' then this is a
+ // definition. Otherwise we have something like 'enum foo xyz', a reference.
+ //
+ // This is needed to handle stuff like this right (C99 6.7.2.3p11):
+ // enum foo {..}; void bar() { enum foo; } <- new foo in bar.
+ // enum foo {..}; void bar() { enum foo x; } <- use of old foo.
+ //
+ Action::TagKind TK;
+ if (Tok.is(tok::l_brace))
+ TK = Action::TK_Definition;
+ else if (Tok.is(tok::semi))
+ TK = Action::TK_Declaration;
+ else
+ TK = Action::TK_Reference;
+ bool Owned = false;
+ DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TK,
+ StartLoc, SS, Name, NameLoc, Attr, AS,
+ Owned);
+
+ if (Tok.is(tok::l_brace))
+ ParseEnumBody(StartLoc, TagDecl);
+
+ // TODO: semantic analysis on the declspec for enums.
+ const char *PrevSpec = 0;
+ if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec,
+ TagDecl.getAs<void>(), Owned))
+ Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
+}
+
+/// ParseEnumBody - Parse a {} enclosed enumerator-list.
+/// enumerator-list:
+/// enumerator
+/// enumerator-list ',' enumerator
+/// enumerator:
+/// enumeration-constant
+/// enumeration-constant '=' constant-expression
+/// enumeration-constant:
+/// identifier
+///
+void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) {
+ // Enter the scope of the enum body and start the definition.
+ ParseScope EnumScope(this, Scope::DeclScope);
+ Actions.ActOnTagStartDefinition(CurScope, EnumDecl);
+
+ SourceLocation LBraceLoc = ConsumeBrace();
+
+ // C does not allow an empty enumerator-list, C++ does [dcl.enum].
+ if (Tok.is(tok::r_brace) && !getLang().CPlusPlus)
+ Diag(Tok, diag::ext_empty_struct_union_enum) << "enum";
+
+ llvm::SmallVector<DeclPtrTy, 32> EnumConstantDecls;
+
+ DeclPtrTy LastEnumConstDecl;
+
+ // Parse the enumerator-list.
+ while (Tok.is(tok::identifier)) {
+ IdentifierInfo *Ident = Tok.getIdentifierInfo();
+ SourceLocation IdentLoc = ConsumeToken();
+
+ SourceLocation EqualLoc;
+ OwningExprResult AssignedVal(Actions);
+ if (Tok.is(tok::equal)) {
+ EqualLoc = ConsumeToken();
+ AssignedVal = ParseConstantExpression();
+ if (AssignedVal.isInvalid())
+ SkipUntil(tok::comma, tok::r_brace, true, true);
+ }
+
+ // Install the enumerator constant into EnumDecl.
+ DeclPtrTy EnumConstDecl = Actions.ActOnEnumConstant(CurScope, EnumDecl,
+ LastEnumConstDecl,
+ IdentLoc, Ident,
+ EqualLoc,
+ AssignedVal.release());
+ EnumConstantDecls.push_back(EnumConstDecl);
+ LastEnumConstDecl = EnumConstDecl;
+
+ if (Tok.isNot(tok::comma))
+ break;
+ SourceLocation CommaLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::identifier) &&
+ !(getLang().C99 || getLang().CPlusPlus0x))
+ Diag(CommaLoc, diag::ext_enumerator_list_comma)
+ << getLang().CPlusPlus
+ << CodeModificationHint::CreateRemoval((SourceRange(CommaLoc)));
+ }
+
+ // Eat the }.
+ SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+
+ Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl,
+ EnumConstantDecls.data(), EnumConstantDecls.size());
+
+ Action::AttrTy *AttrList = 0;
+ // If attributes exist after the identifier list, parse them.
+ if (Tok.is(tok::kw___attribute))
+ AttrList = ParseAttributes(); // FIXME: where do they do?
+
+ EnumScope.Exit();
+ Actions.ActOnTagFinishDefinition(CurScope, EnumDecl);
+}
+
+/// isTypeSpecifierQualifier - Return true if the current token could be the
+/// start of a type-qualifier-list.
+bool Parser::isTypeQualifier() const {
+ switch (Tok.getKind()) {
+ default: return false;
+ // type-qualifier
+ case tok::kw_const:
+ case tok::kw_volatile:
+ case tok::kw_restrict:
+ return true;
+ }
+}
+
+/// isTypeSpecifierQualifier - Return true if the current token could be the
+/// start of a specifier-qualifier-list.
+bool Parser::isTypeSpecifierQualifier() {
+ switch (Tok.getKind()) {
+ default: return false;
+
+ case tok::identifier: // foo::bar
+ case tok::kw_typename: // typename T::type
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return isTypeSpecifierQualifier();
+ // Otherwise, not a type specifier.
+ return false;
+
+ case tok::coloncolon: // ::foo::bar
+ if (NextToken().is(tok::kw_new) || // ::new
+ NextToken().is(tok::kw_delete)) // ::delete
+ return false;
+
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return isTypeSpecifierQualifier();
+ // Otherwise, not a type specifier.
+ return false;
+
+ // GNU attributes support.
+ case tok::kw___attribute:
+ // GNU typeof support.
+ case tok::kw_typeof:
+
+ // type-specifiers
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw__Complex:
+ case tok::kw__Imaginary:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_wchar_t:
+ case tok::kw_int:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_bool:
+ case tok::kw__Bool:
+ case tok::kw__Decimal32:
+ case tok::kw__Decimal64:
+ case tok::kw__Decimal128:
+
+ // struct-or-union-specifier (C99) or class-specifier (C++)
+ case tok::kw_class:
+ case tok::kw_struct:
+ case tok::kw_union:
+ // enum-specifier
+ case tok::kw_enum:
+
+ // type-qualifier
+ case tok::kw_const:
+ case tok::kw_volatile:
+ case tok::kw_restrict:
+
+ // typedef-name
+ case tok::annot_typename:
+ return true;
+
+ // GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'.
+ case tok::less:
+ return getLang().ObjC1;
+
+ case tok::kw___cdecl:
+ case tok::kw___stdcall:
+ case tok::kw___fastcall:
+ return PP.getLangOptions().Microsoft;
+ }
+}
+
+/// isDeclarationSpecifier() - Return true if the current token is part of a
+/// declaration specifier.
+bool Parser::isDeclarationSpecifier() {
+ switch (Tok.getKind()) {
+ default: return false;
+
+ case tok::identifier: // foo::bar
+ // Unfortunate hack to support "Class.factoryMethod" notation.
+ if (getLang().ObjC1 && NextToken().is(tok::period))
+ return false;
+ // Fall through
+
+ case tok::kw_typename: // typename T::type
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return isDeclarationSpecifier();
+ // Otherwise, not a declaration specifier.
+ return false;
+ case tok::coloncolon: // ::foo::bar
+ if (NextToken().is(tok::kw_new) || // ::new
+ NextToken().is(tok::kw_delete)) // ::delete
+ return false;
+
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return isDeclarationSpecifier();
+ // Otherwise, not a declaration specifier.
+ return false;
+
+ // storage-class-specifier
+ case tok::kw_typedef:
+ case tok::kw_extern:
+ case tok::kw___private_extern__:
+ case tok::kw_static:
+ case tok::kw_auto:
+ case tok::kw_register:
+ case tok::kw___thread:
+
+ // type-specifiers
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw__Complex:
+ case tok::kw__Imaginary:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_wchar_t:
+ case tok::kw_int:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_bool:
+ case tok::kw__Bool:
+ case tok::kw__Decimal32:
+ case tok::kw__Decimal64:
+ case tok::kw__Decimal128:
+
+ // struct-or-union-specifier (C99) or class-specifier (C++)
+ case tok::kw_class:
+ case tok::kw_struct:
+ case tok::kw_union:
+ // enum-specifier
+ case tok::kw_enum:
+
+ // type-qualifier
+ case tok::kw_const:
+ case tok::kw_volatile:
+ case tok::kw_restrict:
+
+ // function-specifier
+ case tok::kw_inline:
+ case tok::kw_virtual:
+ case tok::kw_explicit:
+
+ // typedef-name
+ case tok::annot_typename:
+
+ // GNU typeof support.
+ case tok::kw_typeof:
+
+ // GNU attributes.
+ case tok::kw___attribute:
+ return true;
+
+ // GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'.
+ case tok::less:
+ return getLang().ObjC1;
+
+ case tok::kw___declspec:
+ case tok::kw___cdecl:
+ case tok::kw___stdcall:
+ case tok::kw___fastcall:
+ return PP.getLangOptions().Microsoft;
+ }
+}
+
+
+/// ParseTypeQualifierListOpt
+/// type-qualifier-list: [C99 6.7.5]
+/// type-qualifier
+/// [GNU] attributes [ only if AttributesAllowed=true ]
+/// type-qualifier-list type-qualifier
+/// [GNU] type-qualifier-list attributes [ only if AttributesAllowed=true ]
+///
+void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) {
+ while (1) {
+ int isInvalid = false;
+ const char *PrevSpec = 0;
+ SourceLocation Loc = Tok.getLocation();
+
+ switch (Tok.getKind()) {
+ case tok::kw_const:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw_volatile:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw_restrict:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw___ptr64:
+ case tok::kw___cdecl:
+ case tok::kw___stdcall:
+ case tok::kw___fastcall:
+ if (!PP.getLangOptions().Microsoft)
+ goto DoneWithTypeQuals;
+ // Just ignore it.
+ break;
+ case tok::kw___attribute:
+ if (AttributesAllowed) {
+ DS.AddAttributes(ParseAttributes());
+ continue; // do *not* consume the next token!
+ }
+ // otherwise, FALL THROUGH!
+ default:
+ DoneWithTypeQuals:
+ // If this is not a type-qualifier token, we're done reading type
+ // qualifiers. First verify that DeclSpec's are consistent.
+ DS.Finish(Diags, PP);
+ return;
+ }
+
+ // If the specifier combination wasn't legal, issue a diagnostic.
+ if (isInvalid) {
+ assert(PrevSpec && "Method did not return previous specifier!");
+ // Pick between error or extwarn.
+ unsigned DiagID = isInvalid == 1 ? diag::err_invalid_decl_spec_combination
+ : diag::ext_duplicate_declspec;
+ Diag(Tok, DiagID) << PrevSpec;
+ }
+ ConsumeToken();
+ }
+}
+
+
+/// ParseDeclarator - Parse and verify a newly-initialized declarator.
+///
+void Parser::ParseDeclarator(Declarator &D) {
+ /// This implements the 'declarator' production in the C grammar, then checks
+ /// for well-formedness and issues diagnostics.
+ ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
+}
+
+/// ParseDeclaratorInternal - Parse a C or C++ declarator. The direct-declarator
+/// is parsed by the function passed to it. Pass null, and the direct-declarator
+/// isn't parsed at all, making this function effectively parse the C++
+/// ptr-operator production.
+///
+/// declarator: [C99 6.7.5] [C++ 8p4, dcl.decl]
+/// [C] pointer[opt] direct-declarator
+/// [C++] direct-declarator
+/// [C++] ptr-operator declarator
+///
+/// pointer: [C99 6.7.5]
+/// '*' type-qualifier-list[opt]
+/// '*' type-qualifier-list[opt] pointer
+///
+/// ptr-operator:
+/// '*' cv-qualifier-seq[opt]
+/// '&'
+/// [C++0x] '&&'
+/// [GNU] '&' restrict[opt] attributes[opt]
+/// [GNU?] '&&' restrict[opt] attributes[opt]
+/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt]
+void Parser::ParseDeclaratorInternal(Declarator &D,
+ DirectDeclParseFunction DirectDeclParser) {
+
+ // C++ member pointers start with a '::' or a nested-name.
+ // Member pointers get special handling, since there's no place for the
+ // scope spec in the generic path below.
+ if (getLang().CPlusPlus &&
+ (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) ||
+ Tok.is(tok::annot_cxxscope))) {
+ CXXScopeSpec SS;
+ if (ParseOptionalCXXScopeSpecifier(SS)) {
+ if(Tok.isNot(tok::star)) {
+ // The scope spec really belongs to the direct-declarator.
+ D.getCXXScopeSpec() = SS;
+ if (DirectDeclParser)
+ (this->*DirectDeclParser)(D);
+ return;
+ }
+
+ SourceLocation Loc = ConsumeToken();
+ D.SetRangeEnd(Loc);
+ DeclSpec DS;
+ ParseTypeQualifierListOpt(DS);
+ D.ExtendWithDeclSpec(DS);
+
+ // Recurse to parse whatever is left.
+ ParseDeclaratorInternal(D, DirectDeclParser);
+
+ // Sema will have to catch (syntactically invalid) pointers into global
+ // scope. It has to catch pointers into namespace scope anyway.
+ D.AddTypeInfo(DeclaratorChunk::getMemberPointer(SS,DS.getTypeQualifiers(),
+ Loc, DS.TakeAttributes()),
+ /* Don't replace range end. */SourceLocation());
+ return;
+ }
+ }
+
+ tok::TokenKind Kind = Tok.getKind();
+ // Not a pointer, C++ reference, or block.
+ if (Kind != tok::star && Kind != tok::caret &&
+ (Kind != tok::amp || !getLang().CPlusPlus) &&
+ // We parse rvalue refs in C++03, because otherwise the errors are scary.
+ (Kind != tok::ampamp || !getLang().CPlusPlus)) {
+ if (DirectDeclParser)
+ (this->*DirectDeclParser)(D);
+ return;
+ }
+
+ // Otherwise, '*' -> pointer, '^' -> block, '&' -> lvalue reference,
+ // '&&' -> rvalue reference
+ SourceLocation Loc = ConsumeToken(); // Eat the *, ^, & or &&.
+ D.SetRangeEnd(Loc);
+
+ if (Kind == tok::star || Kind == tok::caret) {
+ // Is a pointer.
+ DeclSpec DS;
+
+ ParseTypeQualifierListOpt(DS);
+ D.ExtendWithDeclSpec(DS);
+
+ // Recursively parse the declarator.
+ ParseDeclaratorInternal(D, DirectDeclParser);
+ if (Kind == tok::star)
+ // Remember that we parsed a pointer type, and remember the type-quals.
+ D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc,
+ DS.TakeAttributes()),
+ SourceLocation());
+ else
+ // Remember that we parsed a Block type, and remember the type-quals.
+ D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(),
+ Loc, DS.TakeAttributes()),
+ SourceLocation());
+ } else {
+ // Is a reference
+ DeclSpec DS;
+
+ // Complain about rvalue references in C++03, but then go on and build
+ // the declarator.
+ if (Kind == tok::ampamp && !getLang().CPlusPlus0x)
+ Diag(Loc, diag::err_rvalue_reference);
+
+ // C++ 8.3.2p1: cv-qualified references are ill-formed except when the
+ // cv-qualifiers are introduced through the use of a typedef or of a
+ // template type argument, in which case the cv-qualifiers are ignored.
+ //
+ // [GNU] Retricted references are allowed.
+ // [GNU] Attributes on references are allowed.
+ ParseTypeQualifierListOpt(DS);
+ D.ExtendWithDeclSpec(DS);
+
+ if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) {
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
+ Diag(DS.getConstSpecLoc(),
+ diag::err_invalid_reference_qualifier_application) << "const";
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
+ Diag(DS.getVolatileSpecLoc(),
+ diag::err_invalid_reference_qualifier_application) << "volatile";
+ }
+
+ // Recursively parse the declarator.
+ ParseDeclaratorInternal(D, DirectDeclParser);
+
+ if (D.getNumTypeObjects() > 0) {
+ // C++ [dcl.ref]p4: There shall be no references to references.
+ DeclaratorChunk& InnerChunk = D.getTypeObject(D.getNumTypeObjects() - 1);
+ if (InnerChunk.Kind == DeclaratorChunk::Reference) {
+ if (const IdentifierInfo *II = D.getIdentifier())
+ Diag(InnerChunk.Loc, diag::err_illegal_decl_reference_to_reference)
+ << II;
+ else
+ Diag(InnerChunk.Loc, diag::err_illegal_decl_reference_to_reference)
+ << "type name";
+
+ // Once we've complained about the reference-to-reference, we
+ // can go ahead and build the (technically ill-formed)
+ // declarator: reference collapsing will take care of it.
+ }
+ }
+
+ // Remember that we parsed a reference type. It doesn't have type-quals.
+ D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc,
+ DS.TakeAttributes(),
+ Kind == tok::amp),
+ SourceLocation());
+ }
+}
+
+/// ParseDirectDeclarator
+/// direct-declarator: [C99 6.7.5]
+/// [C99] identifier
+/// '(' declarator ')'
+/// [GNU] '(' attributes declarator ')'
+/// [C90] direct-declarator '[' constant-expression[opt] ']'
+/// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']'
+/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
+/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']'
+/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
+/// direct-declarator '(' parameter-type-list ')'
+/// direct-declarator '(' identifier-list[opt] ')'
+/// [GNU] direct-declarator '(' parameter-forward-declarations
+/// parameter-type-list[opt] ')'
+/// [C++] direct-declarator '(' parameter-declaration-clause ')'
+/// cv-qualifier-seq[opt] exception-specification[opt]
+/// [C++] declarator-id
+///
+/// declarator-id: [C++ 8]
+/// id-expression
+/// '::'[opt] nested-name-specifier[opt] type-name
+///
+/// id-expression: [C++ 5.1]
+/// unqualified-id
+/// qualified-id [TODO]
+///
+/// unqualified-id: [C++ 5.1]
+/// identifier
+/// operator-function-id
+/// conversion-function-id [TODO]
+/// '~' class-name
+/// template-id
+///
+void Parser::ParseDirectDeclarator(Declarator &D) {
+ DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec());
+
+ if (getLang().CPlusPlus) {
+ if (D.mayHaveIdentifier()) {
+ // ParseDeclaratorInternal might already have parsed the scope.
+ bool afterCXXScope = D.getCXXScopeSpec().isSet() ||
+ ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec());
+ if (afterCXXScope) {
+ // Change the declaration context for name lookup, until this function
+ // is exited (and the declarator has been parsed).
+ DeclScopeObj.EnterDeclaratorScope();
+ }
+
+ if (Tok.is(tok::identifier)) {
+ assert(Tok.getIdentifierInfo() && "Not an identifier?");
+
+ // If this identifier is the name of the current class, it's a
+ // constructor name.
+ if (!D.getDeclSpec().hasTypeSpecifier() &&
+ Actions.isCurrentClassName(*Tok.getIdentifierInfo(),CurScope)) {
+ D.setConstructor(Actions.getTypeName(*Tok.getIdentifierInfo(),
+ Tok.getLocation(), CurScope),
+ Tok.getLocation());
+ // This is a normal identifier.
+ } else
+ D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
+ ConsumeToken();
+ goto PastIdentifier;
+ } else if (Tok.is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+
+ // FIXME: Could this template-id name a constructor?
+
+ // FIXME: This is an egregious hack, where we silently ignore
+ // the specialization (which should be a function template
+ // specialization name) and use the name instead. This hack
+ // will go away when we have support for function
+ // specializations.
+ D.SetIdentifier(TemplateId->Name, Tok.getLocation());
+ TemplateId->Destroy();
+ ConsumeToken();
+ goto PastIdentifier;
+ } else if (Tok.is(tok::kw_operator)) {
+ SourceLocation OperatorLoc = Tok.getLocation();
+ SourceLocation EndLoc;
+
+ // First try the name of an overloaded operator
+ if (OverloadedOperatorKind Op = TryParseOperatorFunctionId(&EndLoc)) {
+ D.setOverloadedOperator(Op, OperatorLoc, EndLoc);
+ } else {
+ // This must be a conversion function (C++ [class.conv.fct]).
+ if (TypeTy *ConvType = ParseConversionFunctionId(&EndLoc))
+ D.setConversionFunction(ConvType, OperatorLoc, EndLoc);
+ else {
+ D.SetIdentifier(0, Tok.getLocation());
+ }
+ }
+ goto PastIdentifier;
+ } else if (Tok.is(tok::tilde)) {
+ // This should be a C++ destructor.
+ SourceLocation TildeLoc = ConsumeToken();
+ if (Tok.is(tok::identifier)) {
+ // FIXME: Inaccurate.
+ SourceLocation NameLoc = Tok.getLocation();
+ SourceLocation EndLoc;
+ TypeResult Type = ParseClassName(EndLoc);
+ if (Type.isInvalid())
+ D.SetIdentifier(0, TildeLoc);
+ else
+ D.setDestructor(Type.get(), TildeLoc, NameLoc);
+ } else {
+ Diag(Tok, diag::err_expected_class_name);
+ D.SetIdentifier(0, TildeLoc);
+ }
+ goto PastIdentifier;
+ }
+
+ // If we reached this point, token is not identifier and not '~'.
+
+ if (afterCXXScope) {
+ Diag(Tok, diag::err_expected_unqualified_id);
+ D.SetIdentifier(0, Tok.getLocation());
+ D.setInvalidType(true);
+ goto PastIdentifier;
+ }
+ }
+ }
+
+ // If we reached this point, we are either in C/ObjC or the token didn't
+ // satisfy any of the C++-specific checks.
+ if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) {
+ assert(!getLang().CPlusPlus &&
+ "There's a C++-specific check for tok::identifier above");
+ assert(Tok.getIdentifierInfo() && "Not an identifier?");
+ D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
+ ConsumeToken();
+ } else if (Tok.is(tok::l_paren)) {
+ // direct-declarator: '(' declarator ')'
+ // direct-declarator: '(' attributes declarator ')'
+ // Example: 'char (*X)' or 'int (*XX)(void)'
+ ParseParenDeclarator(D);
+ } else if (D.mayOmitIdentifier()) {
+ // This could be something simple like "int" (in which case the declarator
+ // portion is empty), if an abstract-declarator is allowed.
+ D.SetIdentifier(0, Tok.getLocation());
+ } else {
+ if (D.getContext() == Declarator::MemberContext)
+ Diag(Tok, diag::err_expected_member_name_or_semi)
+ << D.getDeclSpec().getSourceRange();
+ else if (getLang().CPlusPlus)
+ Diag(Tok, diag::err_expected_unqualified_id);
+ else
+ Diag(Tok, diag::err_expected_ident_lparen);
+ D.SetIdentifier(0, Tok.getLocation());
+ D.setInvalidType(true);
+ }
+
+ PastIdentifier:
+ assert(D.isPastIdentifier() &&
+ "Haven't past the location of the identifier yet?");
+
+ while (1) {
+ if (Tok.is(tok::l_paren)) {
+ // The paren may be part of a C++ direct initializer, eg. "int x(1);".
+ // In such a case, check if we actually have a function declarator; if it
+ // is not, the declarator has been fully parsed.
+ if (getLang().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) {
+ // When not in file scope, warn for ambiguous function declarators, just
+ // in case the author intended it as a variable definition.
+ bool warnIfAmbiguous = D.getContext() != Declarator::FileContext;
+ if (!isCXXFunctionDeclarator(warnIfAmbiguous))
+ break;
+ }
+ ParseFunctionDeclarator(ConsumeParen(), D);
+ } else if (Tok.is(tok::l_square)) {
+ ParseBracketDeclarator(D);
+ } else {
+ break;
+ }
+ }
+}
+
+/// ParseParenDeclarator - We parsed the declarator D up to a paren. This is
+/// only called before the identifier, so these are most likely just grouping
+/// parens for precedence. If we find that these are actually function
+/// parameter parens in an abstract-declarator, we call ParseFunctionDeclarator.
+///
+/// direct-declarator:
+/// '(' declarator ')'
+/// [GNU] '(' attributes declarator ')'
+/// direct-declarator '(' parameter-type-list ')'
+/// direct-declarator '(' identifier-list[opt] ')'
+/// [GNU] direct-declarator '(' parameter-forward-declarations
+/// parameter-type-list[opt] ')'
+///
+void Parser::ParseParenDeclarator(Declarator &D) {
+ SourceLocation StartLoc = ConsumeParen();
+ assert(!D.isPastIdentifier() && "Should be called before passing identifier");
+
+ // Eat any attributes before we look at whether this is a grouping or function
+ // declarator paren. If this is a grouping paren, the attribute applies to
+ // the type being built up, for example:
+ // int (__attribute__(()) *x)(long y)
+ // If this ends up not being a grouping paren, the attribute applies to the
+ // first argument, for example:
+ // int (__attribute__(()) int x)
+ // In either case, we need to eat any attributes to be able to determine what
+ // sort of paren this is.
+ //
+ AttributeList *AttrList = 0;
+ bool RequiresArg = false;
+ if (Tok.is(tok::kw___attribute)) {
+ AttrList = ParseAttributes();
+
+ // We require that the argument list (if this is a non-grouping paren) be
+ // present even if the attribute list was empty.
+ RequiresArg = true;
+ }
+ // Eat any Microsoft extensions.
+ while ((Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) ||
+ (Tok.is(tok::kw___fastcall))) && PP.getLangOptions().Microsoft)
+ ConsumeToken();
+
+ // If we haven't past the identifier yet (or where the identifier would be
+ // stored, if this is an abstract declarator), then this is probably just
+ // grouping parens. However, if this could be an abstract-declarator, then
+ // this could also be the start of function arguments (consider 'void()').
+ bool isGrouping;
+
+ if (!D.mayOmitIdentifier()) {
+ // If this can't be an abstract-declarator, this *must* be a grouping
+ // paren, because we haven't seen the identifier yet.
+ isGrouping = true;
+ } else if (Tok.is(tok::r_paren) || // 'int()' is a function.
+ (getLang().CPlusPlus && Tok.is(tok::ellipsis)) || // C++ int(...)
+ isDeclarationSpecifier()) { // 'int(int)' is a function.
+ // This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is
+ // considered to be a type, not a K&R identifier-list.
+ isGrouping = false;
+ } else {
+ // Otherwise, this is a grouping paren, e.g. 'int (*X)' or 'int(X)'.
+ isGrouping = true;
+ }
+
+ // If this is a grouping paren, handle:
+ // direct-declarator: '(' declarator ')'
+ // direct-declarator: '(' attributes declarator ')'
+ if (isGrouping) {
+ bool hadGroupingParens = D.hasGroupingParens();
+ D.setGroupingParens(true);
+ if (AttrList)
+ D.AddAttributes(AttrList, SourceLocation());
+
+ ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
+ // Match the ')'.
+ SourceLocation Loc = MatchRHSPunctuation(tok::r_paren, StartLoc);
+
+ D.setGroupingParens(hadGroupingParens);
+ D.SetRangeEnd(Loc);
+ return;
+ }
+
+ // Okay, if this wasn't a grouping paren, it must be the start of a function
+ // argument list. Recognize that this declarator will never have an
+ // identifier (and remember where it would have been), then call into
+ // ParseFunctionDeclarator to handle of argument list.
+ D.SetIdentifier(0, Tok.getLocation());
+
+ ParseFunctionDeclarator(StartLoc, D, AttrList, RequiresArg);
+}
+
+/// ParseFunctionDeclarator - We are after the identifier and have parsed the
+/// declarator D up to a paren, which indicates that we are parsing function
+/// arguments.
+///
+/// If AttrList is non-null, then the caller parsed those arguments immediately
+/// after the open paren - they should be considered to be the first argument of
+/// a parameter. If RequiresArg is true, then the first argument of the
+/// function is required to be present and required to not be an identifier
+/// list.
+///
+/// This method also handles this portion of the grammar:
+/// parameter-type-list: [C99 6.7.5]
+/// parameter-list
+/// parameter-list ',' '...'
+///
+/// parameter-list: [C99 6.7.5]
+/// parameter-declaration
+/// parameter-list ',' parameter-declaration
+///
+/// parameter-declaration: [C99 6.7.5]
+/// declaration-specifiers declarator
+/// [C++] declaration-specifiers declarator '=' assignment-expression
+/// [GNU] declaration-specifiers declarator attributes
+/// declaration-specifiers abstract-declarator[opt]
+/// [C++] declaration-specifiers abstract-declarator[opt]
+/// '=' assignment-expression
+/// [GNU] declaration-specifiers abstract-declarator[opt] attributes
+///
+/// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]"
+/// and "exception-specification[opt]".
+///
+void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
+ AttributeList *AttrList,
+ bool RequiresArg) {
+ // lparen is already consumed!
+ assert(D.isPastIdentifier() && "Should not call before identifier!");
+
+ // This parameter list may be empty.
+ if (Tok.is(tok::r_paren)) {
+ if (RequiresArg) {
+ Diag(Tok, diag::err_argument_required_after_attribute);
+ delete AttrList;
+ }
+
+ SourceLocation Loc = ConsumeParen(); // Eat the closing ')'.
+
+ // cv-qualifier-seq[opt].
+ DeclSpec DS;
+ bool hasExceptionSpec = false;
+ SourceLocation ThrowLoc;
+ bool hasAnyExceptionSpec = false;
+ llvm::SmallVector<TypeTy*, 2> Exceptions;
+ llvm::SmallVector<SourceRange, 2> ExceptionRanges;
+ if (getLang().CPlusPlus) {
+ ParseTypeQualifierListOpt(DS, false /*no attributes*/);
+ if (!DS.getSourceRange().getEnd().isInvalid())
+ Loc = DS.getSourceRange().getEnd();
+
+ // Parse exception-specification[opt].
+ if (Tok.is(tok::kw_throw)) {
+ hasExceptionSpec = true;
+ ThrowLoc = Tok.getLocation();
+ ParseExceptionSpecification(Loc, Exceptions, ExceptionRanges,
+ hasAnyExceptionSpec);
+ assert(Exceptions.size() == ExceptionRanges.size() &&
+ "Produced different number of exception types and ranges.");
+ }
+ }
+
+ // Remember that we parsed a function type, and remember the attributes.
+ // int() -> no prototype, no '...'.
+ D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/getLang().CPlusPlus,
+ /*variadic*/ false,
+ SourceLocation(),
+ /*arglist*/ 0, 0,
+ DS.getTypeQualifiers(),
+ hasExceptionSpec, ThrowLoc,
+ hasAnyExceptionSpec,
+ Exceptions.data(),
+ ExceptionRanges.data(),
+ Exceptions.size(),
+ LParenLoc, D),
+ Loc);
+ return;
+ }
+
+ // Alternatively, this parameter list may be an identifier list form for a
+ // K&R-style function: void foo(a,b,c)
+ if (!getLang().CPlusPlus && Tok.is(tok::identifier)) {
+ if (!TryAnnotateTypeOrScopeToken()) {
+ // K&R identifier lists can't have typedefs as identifiers, per
+ // C99 6.7.5.3p11.
+ if (RequiresArg) {
+ Diag(Tok, diag::err_argument_required_after_attribute);
+ delete AttrList;
+ }
+ // Identifier list. Note that '(' identifier-list ')' is only allowed for
+ // normal declarators, not for abstract-declarators.
+ return ParseFunctionDeclaratorIdentifierList(LParenLoc, D);
+ }
+ }
+
+ // Finally, a normal, non-empty parameter type list.
+
+ // Build up an array of information about the parsed arguments.
+ llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
+
+ // Enter function-declaration scope, limiting any declarators to the
+ // function prototype scope, including parameter declarators.
+ ParseScope PrototypeScope(this,
+ Scope::FunctionPrototypeScope|Scope::DeclScope);
+
+ bool IsVariadic = false;
+ SourceLocation EllipsisLoc;
+ while (1) {
+ if (Tok.is(tok::ellipsis)) {
+ IsVariadic = true;
+ EllipsisLoc = ConsumeToken(); // Consume the ellipsis.
+ break;
+ }
+
+ SourceLocation DSStart = Tok.getLocation();
+
+ // Parse the declaration-specifiers.
+ DeclSpec DS;
+
+ // If the caller parsed attributes for the first argument, add them now.
+ if (AttrList) {
+ DS.AddAttributes(AttrList);
+ AttrList = 0; // Only apply the attributes to the first parameter.
+ }
+ ParseDeclarationSpecifiers(DS);
+
+ // Parse the declarator. This is "PrototypeContext", because we must
+ // accept either 'declarator' or 'abstract-declarator' here.
+ Declarator ParmDecl(DS, Declarator::PrototypeContext);
+ ParseDeclarator(ParmDecl);
+
+ // Parse GNU attributes, if present.
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ ParmDecl.AddAttributes(AttrList, Loc);
+ }
+
+ // Remember this parsed parameter in ParamInfo.
+ IdentifierInfo *ParmII = ParmDecl.getIdentifier();
+
+ // DefArgToks is used when the parsing of default arguments needs
+ // to be delayed.
+ CachedTokens *DefArgToks = 0;
+
+ // If no parameter was specified, verify that *something* was specified,
+ // otherwise we have a missing type and identifier.
+ if (DS.isEmpty() && ParmDecl.getIdentifier() == 0 &&
+ ParmDecl.getNumTypeObjects() == 0) {
+ // Completely missing, emit error.
+ Diag(DSStart, diag::err_missing_param);
+ } else {
+ // Otherwise, we have something. Add it and let semantic analysis try
+ // to grok it and add the result to the ParamInfo we are building.
+
+ // Inform the actions module about the parameter declarator, so it gets
+ // added to the current scope.
+ DeclPtrTy Param = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
+
+ // Parse the default argument, if any. We parse the default
+ // arguments in all dialects; the semantic analysis in
+ // ActOnParamDefaultArgument will reject the default argument in
+ // C.
+ if (Tok.is(tok::equal)) {
+ SourceLocation EqualLoc = Tok.getLocation();
+
+ // Parse the default argument
+ if (D.getContext() == Declarator::MemberContext) {
+ // If we're inside a class definition, cache the tokens
+ // corresponding to the default argument. We'll actually parse
+ // them when we see the end of the class definition.
+ // FIXME: Templates will require something similar.
+ // FIXME: Can we use a smart pointer for Toks?
+ DefArgToks = new CachedTokens;
+
+ if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks,
+ tok::semi, false)) {
+ delete DefArgToks;
+ DefArgToks = 0;
+ Actions.ActOnParamDefaultArgumentError(Param);
+ } else
+ Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc);
+ } else {
+ // Consume the '='.
+ ConsumeToken();
+
+ OwningExprResult DefArgResult(ParseAssignmentExpression());
+ if (DefArgResult.isInvalid()) {
+ Actions.ActOnParamDefaultArgumentError(Param);
+ SkipUntil(tok::comma, tok::r_paren, true, true);
+ } else {
+ // Inform the actions module about the default argument
+ Actions.ActOnParamDefaultArgument(Param, EqualLoc,
+ move(DefArgResult));
+ }
+ }
+ }
+
+ ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
+ ParmDecl.getIdentifierLoc(), Param,
+ DefArgToks));
+ }
+
+ // If the next token is a comma, consume it and keep reading arguments.
+ if (Tok.isNot(tok::comma)) break;
+
+ // Consume the comma.
+ ConsumeToken();
+ }
+
+ // Leave prototype scope.
+ PrototypeScope.Exit();
+
+ // If we have the closing ')', eat it.
+ SourceLocation Loc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ DeclSpec DS;
+ bool hasExceptionSpec = false;
+ SourceLocation ThrowLoc;
+ bool hasAnyExceptionSpec = false;
+ llvm::SmallVector<TypeTy*, 2> Exceptions;
+ llvm::SmallVector<SourceRange, 2> ExceptionRanges;
+ if (getLang().CPlusPlus) {
+ // Parse cv-qualifier-seq[opt].
+ ParseTypeQualifierListOpt(DS, false /*no attributes*/);
+ if (!DS.getSourceRange().getEnd().isInvalid())
+ Loc = DS.getSourceRange().getEnd();
+
+ // Parse exception-specification[opt].
+ if (Tok.is(tok::kw_throw)) {
+ hasExceptionSpec = true;
+ ThrowLoc = Tok.getLocation();
+ ParseExceptionSpecification(Loc, Exceptions, ExceptionRanges,
+ hasAnyExceptionSpec);
+ assert(Exceptions.size() == ExceptionRanges.size() &&
+ "Produced different number of exception types and ranges.");
+ }
+ }
+
+ // Remember that we parsed a function type, and remember the attributes.
+ D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic,
+ EllipsisLoc,
+ ParamInfo.data(), ParamInfo.size(),
+ DS.getTypeQualifiers(),
+ hasExceptionSpec, ThrowLoc,
+ hasAnyExceptionSpec,
+ Exceptions.data(),
+ ExceptionRanges.data(),
+ Exceptions.size(), LParenLoc, D),
+ Loc);
+}
+
+/// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator
+/// we found a K&R-style identifier list instead of a type argument list. The
+/// current token is known to be the first identifier in the list.
+///
+/// identifier-list: [C99 6.7.5]
+/// identifier
+/// identifier-list ',' identifier
+///
+void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
+ Declarator &D) {
+ // Build up an array of information about the parsed arguments.
+ llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
+ llvm::SmallSet<const IdentifierInfo*, 16> ParamsSoFar;
+
+ // 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:
+ // diagnose this.
+ if (!D.getIdentifier())
+ Diag(Tok, diag::ext_ident_list_in_param);
+
+ // Tok is known to be the first identifier in the list. Remember this
+ // identifier in ParamInfo.
+ ParamsSoFar.insert(Tok.getIdentifierInfo());
+ ParamInfo.push_back(DeclaratorChunk::ParamInfo(Tok.getIdentifierInfo(),
+ Tok.getLocation(),
+ DeclPtrTy()));
+
+ ConsumeToken(); // eat the first identifier.
+
+ while (Tok.is(tok::comma)) {
+ // Eat the comma.
+ ConsumeToken();
+
+ // If this isn't an identifier, report the error and skip until ')'.
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ IdentifierInfo *ParmII = Tok.getIdentifierInfo();
+
+ // Reject 'typedef int y; int test(x, y)', but continue parsing.
+ if (Actions.getTypeName(*ParmII, Tok.getLocation(), CurScope))
+ Diag(Tok, diag::err_unexpected_typedef_ident) << ParmII;
+
+ // Verify that the argument identifier has not already been mentioned.
+ if (!ParamsSoFar.insert(ParmII)) {
+ Diag(Tok, diag::err_param_redefinition) << ParmII;
+ } else {
+ // Remember this identifier in ParamInfo.
+ ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
+ Tok.getLocation(),
+ DeclPtrTy()));
+ }
+
+ // Eat the identifier.
+ ConsumeToken();
+ }
+
+ // If we have the closing ')', eat it and we're done.
+ SourceLocation RLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ // Remember that we parsed a function type, and remember the attributes. This
+ // function type is always a K&R style function type, which is not varargs and
+ // has no prototype.
+ D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/false, /*varargs*/false,
+ SourceLocation(),
+ &ParamInfo[0], ParamInfo.size(),
+ /*TypeQuals*/0,
+ /*exception*/false,
+ SourceLocation(), false, 0, 0, 0,
+ LParenLoc, D),
+ RLoc);
+}
+
+/// [C90] direct-declarator '[' constant-expression[opt] ']'
+/// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']'
+/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
+/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']'
+/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
+void Parser::ParseBracketDeclarator(Declarator &D) {
+ SourceLocation StartLoc = ConsumeBracket();
+
+ // 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);
+ // Remember that we parsed the empty array type.
+ OwningExprResult NumElements(Actions);
+ D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, StartLoc),
+ EndLoc);
+ return;
+ } else if (Tok.getKind() == tok::numeric_constant &&
+ GetLookAheadToken(1).is(tok::r_square)) {
+ // [4] is very common. Parse the numeric constant expression.
+ OwningExprResult ExprRes(Actions.ActOnNumericConstant(Tok));
+ ConsumeToken();
+
+ SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+
+ // If there was an error parsing the assignment-expression, recover.
+ if (ExprRes.isInvalid())
+ ExprRes.release(); // Deallocate expr, just use [].
+
+ // Remember that we parsed a array type, and remember its features.
+ D.AddTypeInfo(DeclaratorChunk::getArray(0, false, 0,
+ ExprRes.release(), StartLoc),
+ EndLoc);
+ return;
+ }
+
+ // If valid, this location is the position where we read the 'static' keyword.
+ SourceLocation StaticLoc;
+ if (Tok.is(tok::kw_static))
+ StaticLoc = ConsumeToken();
+
+ // If there is a type-qualifier-list, read it now.
+ // Type qualifiers in an array subscript are a C99 feature.
+ DeclSpec DS;
+ ParseTypeQualifierListOpt(DS, false /*no attributes*/);
+
+ // If we haven't already read 'static', check to see if there is one after the
+ // type-qualifier-list.
+ if (!StaticLoc.isValid() && Tok.is(tok::kw_static))
+ StaticLoc = ConsumeToken();
+
+ // Handle "direct-declarator [ type-qual-list[opt] * ]".
+ bool isStar = false;
+ OwningExprResult NumElements(Actions);
+
+ // Handle the case where we have '[*]' as the array size. However, a leading
+ // star could be the start of an expression, for example 'X[*p + 4]'. Verify
+ // the the token after the star is a ']'. Since stars in arrays are
+ // infrequent, use of lookahead is not costly here.
+ if (Tok.is(tok::star) && GetLookAheadToken(1).is(tok::r_square)) {
+ ConsumeToken(); // Eat the '*'.
+
+ if (StaticLoc.isValid()) {
+ Diag(StaticLoc, diag::err_unspecified_vla_size_with_static);
+ StaticLoc = SourceLocation(); // Drop the static.
+ }
+ isStar = true;
+ } else if (Tok.isNot(tok::r_square)) {
+ // Note, in C89, this production uses the constant-expr production instead
+ // of assignment-expr. The only difference is that assignment-expr allows
+ // things like '=' and '*='. Sema rejects these in C89 mode because they
+ // are not i-c-e's, so we don't need to distinguish between the two here.
+
+ // Parse the assignment-expression now.
+ NumElements = ParseAssignmentExpression();
+ }
+
+ // If there was an error parsing the assignment-expression, recover.
+ if (NumElements.isInvalid()) {
+ D.setInvalidType(true);
+ // If the expression was invalid, skip it.
+ SkipUntil(tok::r_square);
+ return;
+ }
+
+ SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+
+ // Remember that we parsed a array type, and remember its features.
+ D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(),
+ StaticLoc.isValid(), isStar,
+ NumElements.release(), StartLoc),
+ EndLoc);
+}
+
+/// [GNU] typeof-specifier:
+/// typeof ( expressions )
+/// typeof ( type-name )
+/// [GNU/C++] typeof unary-expression
+///
+void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
+ assert(Tok.is(tok::kw_typeof) && "Not a typeof specifier");
+ Token OpTok = Tok;
+ SourceLocation StartLoc = ConsumeToken();
+
+ bool isCastExpr;
+ TypeTy *CastTy;
+ SourceRange CastRange;
+ OwningExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok,
+ isCastExpr,
+ CastTy,
+ CastRange);
+
+ if (CastRange.getEnd().isInvalid())
+ // FIXME: Not accurate, the range gets one token more than it should.
+ DS.SetRangeEnd(Tok.getLocation());
+ else
+ DS.SetRangeEnd(CastRange.getEnd());
+
+ if (isCastExpr) {
+ if (!CastTy) {
+ DS.SetTypeSpecError();
+ return;
+ }
+
+ const char *PrevSpec = 0;
+ // Check for duplicate type specifiers (e.g. "int typeof(int)").
+ if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec,
+ CastTy))
+ Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
+ return;
+ }
+
+ // If we get here, the operand to the typeof was an expresion.
+ if (Operand.isInvalid()) {
+ DS.SetTypeSpecError();
+ return;
+ }
+
+ const char *PrevSpec = 0;
+ // Check for duplicate type specifiers (e.g. "int typeof(int)").
+ if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec,
+ Operand.release()))
+ Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
+}
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
new file mode 100644
index 000000000000..809dc10c3ab8
--- /dev/null
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -0,0 +1,1292 @@
+//===--- ParseDeclCXX.cpp - C++ Declaration Parsing -----------------------===//
+//
+// 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 C++ Declaration portions of the Parser interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+#include "ExtensionRAIIObject.h"
+using namespace clang;
+
+/// ParseNamespace - We know that the current token is a namespace keyword. This
+/// may either be a top level namespace or a block-level namespace alias.
+///
+/// namespace-definition: [C++ 7.3: basic.namespace]
+/// named-namespace-definition
+/// unnamed-namespace-definition
+///
+/// unnamed-namespace-definition:
+/// 'namespace' attributes[opt] '{' namespace-body '}'
+///
+/// named-namespace-definition:
+/// original-namespace-definition
+/// extension-namespace-definition
+///
+/// original-namespace-definition:
+/// 'namespace' identifier attributes[opt] '{' namespace-body '}'
+///
+/// extension-namespace-definition:
+/// 'namespace' original-namespace-name '{' namespace-body '}'
+///
+/// namespace-alias-definition: [C++ 7.3.2: namespace.alias]
+/// 'namespace' identifier '=' qualified-namespace-specifier ';'
+///
+Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
+ SourceLocation &DeclEnd) {
+ assert(Tok.is(tok::kw_namespace) && "Not a namespace!");
+ SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'.
+
+ SourceLocation IdentLoc;
+ IdentifierInfo *Ident = 0;
+
+ if (Tok.is(tok::identifier)) {
+ Ident = Tok.getIdentifierInfo();
+ IdentLoc = ConsumeToken(); // eat the identifier.
+ }
+
+ // Read label attributes, if present.
+ Action::AttrTy *AttrList = 0;
+ if (Tok.is(tok::kw___attribute))
+ // FIXME: save these somewhere.
+ AttrList = ParseAttributes();
+
+ if (Tok.is(tok::equal))
+ // FIXME: Verify no attributes were present.
+ return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd);
+
+ if (Tok.isNot(tok::l_brace)) {
+ Diag(Tok, Ident ? diag::err_expected_lbrace :
+ diag::err_expected_ident_lbrace);
+ return DeclPtrTy();
+ }
+
+ SourceLocation LBrace = ConsumeBrace();
+
+ // Enter a scope for the namespace.
+ ParseScope NamespaceScope(this, Scope::DeclScope);
+
+ DeclPtrTy NamespcDecl =
+ Actions.ActOnStartNamespaceDef(CurScope, IdentLoc, Ident, LBrace);
+
+ PrettyStackTraceActionsDecl CrashInfo(NamespcDecl, NamespaceLoc, Actions,
+ PP.getSourceManager(),
+ "parsing namespace");
+
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof))
+ ParseExternalDeclaration();
+
+ // Leave the namespace scope.
+ NamespaceScope.Exit();
+
+ SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace);
+ Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc);
+
+ DeclEnd = RBraceLoc;
+ return NamespcDecl;
+}
+
+/// ParseNamespaceAlias - Parse the part after the '=' in a namespace
+/// alias definition.
+///
+Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
+ SourceLocation AliasLoc,
+ IdentifierInfo *Alias,
+ SourceLocation &DeclEnd) {
+ assert(Tok.is(tok::equal) && "Not equal token");
+
+ ConsumeToken(); // eat the '='.
+
+ CXXScopeSpec SS;
+ // Parse (optional) nested-name-specifier.
+ ParseOptionalCXXScopeSpecifier(SS);
+
+ if (SS.isInvalid() || Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_namespace_name);
+ // Skip to end of the definition and eat the ';'.
+ SkipUntil(tok::semi);
+ return DeclPtrTy();
+ }
+
+ // Parse identifier.
+ IdentifierInfo *Ident = Tok.getIdentifierInfo();
+ SourceLocation IdentLoc = ConsumeToken();
+
+ // Eat the ';'.
+ DeclEnd = Tok.getLocation();
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
+ "namespace name", tok::semi);
+
+ return Actions.ActOnNamespaceAliasDef(CurScope, NamespaceLoc, AliasLoc, Alias,
+ SS, IdentLoc, Ident);
+}
+
+/// ParseLinkage - We know that the current token is a string_literal
+/// and just before that, that extern was seen.
+///
+/// linkage-specification: [C++ 7.5p2: dcl.link]
+/// 'extern' string-literal '{' declaration-seq[opt] '}'
+/// 'extern' string-literal declaration
+///
+Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) {
+ assert(Tok.is(tok::string_literal) && "Not a string literal!");
+ llvm::SmallVector<char, 8> LangBuffer;
+ // LangBuffer is guaranteed to be big enough.
+ LangBuffer.resize(Tok.getLength());
+ const char *LangBufPtr = &LangBuffer[0];
+ unsigned StrSize = PP.getSpelling(Tok, LangBufPtr);
+
+ SourceLocation Loc = ConsumeStringToken();
+
+ ParseScope LinkageScope(this, Scope::DeclScope);
+ DeclPtrTy LinkageSpec
+ = Actions.ActOnStartLinkageSpecification(CurScope,
+ /*FIXME: */SourceLocation(),
+ Loc, LangBufPtr, StrSize,
+ Tok.is(tok::l_brace)? Tok.getLocation()
+ : SourceLocation());
+
+ if (Tok.isNot(tok::l_brace)) {
+ ParseDeclarationOrFunctionDefinition();
+ return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec,
+ SourceLocation());
+ }
+
+ SourceLocation LBrace = ConsumeBrace();
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ ParseExternalDeclaration();
+ }
+
+ SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace);
+ return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec, RBrace);
+}
+
+/// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or
+/// using-directive. Assumes that current token is 'using'.
+Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
+ SourceLocation &DeclEnd) {
+ assert(Tok.is(tok::kw_using) && "Not using token");
+
+ // Eat 'using'.
+ SourceLocation UsingLoc = ConsumeToken();
+
+ if (Tok.is(tok::kw_namespace))
+ // Next token after 'using' is 'namespace' so it must be using-directive
+ return ParseUsingDirective(Context, UsingLoc, DeclEnd);
+
+ // Otherwise, it must be using-declaration.
+ return ParseUsingDeclaration(Context, UsingLoc, DeclEnd);
+}
+
+/// ParseUsingDirective - Parse C++ using-directive, assumes
+/// that current token is 'namespace' and 'using' was already parsed.
+///
+/// using-directive: [C++ 7.3.p4: namespace.udir]
+/// 'using' 'namespace' ::[opt] nested-name-specifier[opt]
+/// namespace-name ;
+/// [GNU] using-directive:
+/// 'using' 'namespace' ::[opt] nested-name-specifier[opt]
+/// namespace-name attributes[opt] ;
+///
+Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
+ SourceLocation UsingLoc,
+ SourceLocation &DeclEnd) {
+ assert(Tok.is(tok::kw_namespace) && "Not 'namespace' token");
+
+ // Eat 'namespace'.
+ SourceLocation NamespcLoc = ConsumeToken();
+
+ CXXScopeSpec SS;
+ // Parse (optional) nested-name-specifier.
+ ParseOptionalCXXScopeSpecifier(SS);
+
+ AttributeList *AttrList = 0;
+ IdentifierInfo *NamespcName = 0;
+ SourceLocation IdentLoc = SourceLocation();
+
+ // Parse namespace-name.
+ if (SS.isInvalid() || Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_namespace_name);
+ // If there was invalid namespace name, skip to end of decl, and eat ';'.
+ SkipUntil(tok::semi);
+ // FIXME: Are there cases, when we would like to call ActOnUsingDirective?
+ return DeclPtrTy();
+ }
+
+ // Parse identifier.
+ NamespcName = Tok.getIdentifierInfo();
+ IdentLoc = ConsumeToken();
+
+ // Parse (optional) attributes (most likely GNU strong-using extension).
+ if (Tok.is(tok::kw___attribute))
+ AttrList = ParseAttributes();
+
+ // Eat ';'.
+ DeclEnd = Tok.getLocation();
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
+ AttrList ? "attributes list" : "namespace name", tok::semi);
+
+ return Actions.ActOnUsingDirective(CurScope, UsingLoc, NamespcLoc, SS,
+ IdentLoc, NamespcName, AttrList);
+}
+
+/// ParseUsingDeclaration - Parse C++ using-declaration. Assumes that
+/// 'using' was already seen.
+///
+/// using-declaration: [C++ 7.3.p3: namespace.udecl]
+/// 'using' 'typename'[opt] ::[opt] nested-name-specifier
+/// unqualified-id [TODO]
+/// 'using' :: unqualified-id [TODO]
+///
+Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
+ SourceLocation UsingLoc,
+ SourceLocation &DeclEnd) {
+ assert(false && "Not implemented");
+ // FIXME: Implement parsing.
+ return DeclPtrTy();
+}
+
+/// ParseStaticAssertDeclaration - Parse C++0x static_assert-declaratoion.
+///
+/// static_assert-declaration:
+/// static_assert ( constant-expression , string-literal ) ;
+///
+Parser::DeclPtrTy Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
+ assert(Tok.is(tok::kw_static_assert) && "Not a static_assert declaration");
+ SourceLocation StaticAssertLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen);
+ return DeclPtrTy();
+ }
+
+ SourceLocation LParenLoc = ConsumeParen();
+
+ OwningExprResult AssertExpr(ParseConstantExpression());
+ if (AssertExpr.isInvalid()) {
+ SkipUntil(tok::semi);
+ return DeclPtrTy();
+ }
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::semi))
+ return DeclPtrTy();
+
+ if (Tok.isNot(tok::string_literal)) {
+ Diag(Tok, diag::err_expected_string_literal);
+ SkipUntil(tok::semi);
+ return DeclPtrTy();
+ }
+
+ OwningExprResult AssertMessage(ParseStringLiteralExpression());
+ if (AssertMessage.isInvalid())
+ return DeclPtrTy();
+
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ DeclEnd = Tok.getLocation();
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_static_assert);
+
+ return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc, move(AssertExpr),
+ move(AssertMessage));
+}
+
+/// ParseClassName - Parse a C++ class-name, which names a class. Note
+/// that we only check that the result names a type; semantic analysis
+/// will need to verify that the type names a class. The result is
+/// either a type or NULL, depending on whether a type name was
+/// found.
+///
+/// class-name: [C++ 9.1]
+/// identifier
+/// simple-template-id
+///
+Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
+ const CXXScopeSpec *SS) {
+ // Check whether we have a template-id that names a type.
+ if (Tok.is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (TemplateId->Kind == TNK_Type_template) {
+ AnnotateTemplateIdTokenAsType(SS);
+
+ assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
+ TypeTy *Type = Tok.getAnnotationValue();
+ EndLocation = Tok.getAnnotationEndLoc();
+ ConsumeToken();
+
+ if (Type)
+ return Type;
+ return true;
+ }
+
+ // Fall through to produce an error below.
+ }
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_class_name);
+ return true;
+ }
+
+ // We have an identifier; check whether it is actually a type.
+ TypeTy *Type = Actions.getTypeName(*Tok.getIdentifierInfo(),
+ Tok.getLocation(), CurScope, SS);
+ if (!Type) {
+ Diag(Tok, diag::err_expected_class_name);
+ return true;
+ }
+
+ // Consume the identifier.
+ EndLocation = ConsumeToken();
+ return Type;
+}
+
+/// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or
+/// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which
+/// until we reach the start of a definition or see a token that
+/// cannot start a definition.
+///
+/// class-specifier: [C++ class]
+/// class-head '{' member-specification[opt] '}'
+/// class-head '{' member-specification[opt] '}' attributes[opt]
+/// class-head:
+/// class-key identifier[opt] base-clause[opt]
+/// class-key nested-name-specifier identifier base-clause[opt]
+/// class-key nested-name-specifier[opt] simple-template-id
+/// base-clause[opt]
+/// [GNU] class-key attributes[opt] identifier[opt] base-clause[opt]
+/// [GNU] class-key attributes[opt] nested-name-specifier
+/// identifier base-clause[opt]
+/// [GNU] class-key attributes[opt] nested-name-specifier[opt]
+/// simple-template-id base-clause[opt]
+/// class-key:
+/// 'class'
+/// 'struct'
+/// 'union'
+///
+/// elaborated-type-specifier: [C++ dcl.type.elab]
+/// class-key ::[opt] nested-name-specifier[opt] identifier
+/// class-key ::[opt] nested-name-specifier[opt] 'template'[opt]
+/// simple-template-id
+///
+/// Note that the C++ class-specifier and elaborated-type-specifier,
+/// together, subsume the C99 struct-or-union-specifier:
+///
+/// struct-or-union-specifier: [C99 6.7.2.1]
+/// struct-or-union identifier[opt] '{' struct-contents '}'
+/// struct-or-union identifier
+/// [GNU] struct-or-union attributes[opt] identifier[opt] '{' struct-contents
+/// '}' attributes[opt]
+/// [GNU] struct-or-union attributes[opt] identifier
+/// struct-or-union:
+/// 'struct'
+/// 'union'
+void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
+ SourceLocation StartLoc, DeclSpec &DS,
+ const ParsedTemplateInfo &TemplateInfo,
+ AccessSpecifier AS) {
+ DeclSpec::TST TagType;
+ if (TagTokKind == tok::kw_struct)
+ TagType = DeclSpec::TST_struct;
+ else if (TagTokKind == tok::kw_class)
+ TagType = DeclSpec::TST_class;
+ else {
+ assert(TagTokKind == tok::kw_union && "Not a class specifier");
+ TagType = DeclSpec::TST_union;
+ }
+
+ AttributeList *Attr = 0;
+ // If attributes exist after tag, parse them.
+ if (Tok.is(tok::kw___attribute))
+ Attr = ParseAttributes();
+
+ // If declspecs exist after tag, parse them.
+ if (Tok.is(tok::kw___declspec) && PP.getLangOptions().Microsoft)
+ FuzzyParseMicrosoftDeclSpec();
+
+ // Parse the (optional) nested-name-specifier.
+ CXXScopeSpec SS;
+ if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS))
+ if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
+ Diag(Tok, diag::err_expected_ident);
+
+ // Parse the (optional) class name or simple-template-id.
+ IdentifierInfo *Name = 0;
+ SourceLocation NameLoc;
+ TemplateIdAnnotation *TemplateId = 0;
+ if (Tok.is(tok::identifier)) {
+ Name = Tok.getIdentifierInfo();
+ NameLoc = ConsumeToken();
+ } else if (Tok.is(tok::annot_template_id)) {
+ TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ NameLoc = ConsumeToken();
+
+ if (TemplateId->Kind != TNK_Type_template) {
+ // The template-name in the simple-template-id refers to
+ // something other than a class template. Give an appropriate
+ // error message and skip to the ';'.
+ SourceRange Range(NameLoc);
+ if (SS.isNotEmpty())
+ Range.setBegin(SS.getBeginLoc());
+
+ Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template)
+ << Name << static_cast<int>(TemplateId->Kind) << Range;
+
+ DS.SetTypeSpecError();
+ SkipUntil(tok::semi, false, true);
+ TemplateId->Destroy();
+ return;
+ }
+ }
+
+ // There are three options here. If we have 'struct foo;', then
+ // this is a forward declaration. If we have 'struct foo {...' or
+ // 'struct foo :...' then this is a definition. Otherwise we have
+ // something like 'struct foo xyz', a reference.
+ Action::TagKind TK;
+ if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon)))
+ TK = Action::TK_Definition;
+ else if (Tok.is(tok::semi) && !DS.isFriendSpecified())
+ TK = Action::TK_Declaration;
+ else
+ TK = Action::TK_Reference;
+
+ if (!Name && !TemplateId && TK != Action::TK_Definition) {
+ // We have a declaration or reference to an anonymous class.
+ Diag(StartLoc, diag::err_anon_type_definition)
+ << DeclSpec::getSpecifierName(TagType);
+
+ // Skip the rest of this declarator, up until the comma or semicolon.
+ SkipUntil(tok::comma, true);
+
+ if (TemplateId)
+ TemplateId->Destroy();
+ return;
+ }
+
+ // Create the tag portion of the class or class template.
+ Action::DeclResult TagOrTempResult;
+ TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
+
+ // FIXME: When TK == TK_Reference and we have a template-id, we need
+ // to turn that template-id into a type.
+
+ bool Owned = false;
+ if (TemplateId && TK != Action::TK_Reference) {
+ // Explicit specialization, class template partial specialization,
+ // or explicit instantiation.
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions,
+ TemplateId->getTemplateArgs(),
+ TemplateId->getTemplateArgIsType(),
+ TemplateId->NumArgs);
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
+ TK == Action::TK_Declaration) {
+ // This is an explicit instantiation of a class template.
+ TagOrTempResult
+ = Actions.ActOnExplicitInstantiation(CurScope,
+ TemplateInfo.TemplateLoc,
+ TagType,
+ StartLoc,
+ SS,
+ TemplateTy::make(TemplateId->Template),
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->getTemplateArgLocations(),
+ TemplateId->RAngleLoc,
+ Attr);
+ } else {
+ // This is an explicit specialization or a class template
+ // partial specialization.
+ TemplateParameterLists FakedParamLists;
+
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
+ // This looks like an explicit instantiation, because we have
+ // something like
+ //
+ // template class Foo<X>
+ //
+ // but it actually has a definition. Most likely, this was
+ // meant to be an explicit specialization, but the user forgot
+ // the '<>' after 'template'.
+ assert(TK == Action::TK_Definition && "Expected a definition here");
+
+ SourceLocation LAngleLoc
+ = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
+ Diag(TemplateId->TemplateNameLoc,
+ diag::err_explicit_instantiation_with_definition)
+ << SourceRange(TemplateInfo.TemplateLoc)
+ << CodeModificationHint::CreateInsertion(LAngleLoc, "<>");
+
+ // Create a fake template parameter list that contains only
+ // "template<>", so that we treat this construct as a class
+ // template specialization.
+ FakedParamLists.push_back(
+ Actions.ActOnTemplateParameterList(0, SourceLocation(),
+ TemplateInfo.TemplateLoc,
+ LAngleLoc,
+ 0, 0,
+ LAngleLoc));
+ TemplateParams = &FakedParamLists;
+ }
+
+ // Build the class template specialization.
+ TagOrTempResult
+ = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TK,
+ StartLoc, SS,
+ TemplateTy::make(TemplateId->Template),
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->getTemplateArgLocations(),
+ TemplateId->RAngleLoc,
+ Attr,
+ Action::MultiTemplateParamsArg(Actions,
+ TemplateParams? &(*TemplateParams)[0] : 0,
+ TemplateParams? TemplateParams->size() : 0));
+ }
+ TemplateId->Destroy();
+ } else if (TemplateParams && TK != Action::TK_Reference) {
+ // Class template declaration or definition.
+ TagOrTempResult = Actions.ActOnClassTemplate(CurScope, TagType, TK,
+ StartLoc, SS, Name, NameLoc,
+ Attr,
+ Action::MultiTemplateParamsArg(Actions,
+ &(*TemplateParams)[0],
+ TemplateParams->size()),
+ AS);
+ } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
+ TK == Action::TK_Declaration) {
+ // Explicit instantiation of a member of a class template
+ // specialization, e.g.,
+ //
+ // template struct Outer<int>::Inner;
+ //
+ TagOrTempResult
+ = Actions.ActOnExplicitInstantiation(CurScope,
+ TemplateInfo.TemplateLoc,
+ TagType, StartLoc, SS, Name,
+ NameLoc, Attr);
+ } else {
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
+ TK == Action::TK_Definition) {
+ // FIXME: Diagnose this particular error.
+ }
+
+ // Declaration or definition of a class type
+ TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS,
+ Name, NameLoc, Attr, AS, Owned);
+ }
+
+ // Parse the optional base clause (C++ only).
+ if (getLang().CPlusPlus && Tok.is(tok::colon))
+ ParseBaseClause(TagOrTempResult.get());
+
+ // If there is a body, parse it and inform the actions module.
+ if (Tok.is(tok::l_brace))
+ if (getLang().CPlusPlus)
+ ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get());
+ else
+ ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
+ else if (TK == Action::TK_Definition) {
+ // FIXME: Complain that we have a base-specifier list but no
+ // definition.
+ Diag(Tok, diag::err_expected_lbrace);
+ }
+
+ const char *PrevSpec = 0;
+ if (TagOrTempResult.isInvalid()) {
+ DS.SetTypeSpecError();
+ return;
+ }
+
+ if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec,
+ TagOrTempResult.get().getAs<void>(), Owned))
+ Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
+
+ if (DS.isFriendSpecified())
+ Actions.ActOnFriendDecl(CurScope, DS.getFriendSpecLoc(),
+ TagOrTempResult.get());
+}
+
+/// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived].
+///
+/// base-clause : [C++ class.derived]
+/// ':' base-specifier-list
+/// base-specifier-list:
+/// base-specifier '...'[opt]
+/// base-specifier-list ',' base-specifier '...'[opt]
+void Parser::ParseBaseClause(DeclPtrTy ClassDecl) {
+ assert(Tok.is(tok::colon) && "Not a base clause");
+ ConsumeToken();
+
+ // Build up an array of parsed base specifiers.
+ llvm::SmallVector<BaseTy *, 8> BaseInfo;
+
+ while (true) {
+ // Parse a base-specifier.
+ BaseResult Result = ParseBaseSpecifier(ClassDecl);
+ if (Result.isInvalid()) {
+ // Skip the rest of this base specifier, up until the comma or
+ // opening brace.
+ SkipUntil(tok::comma, tok::l_brace, true, true);
+ } else {
+ // Add this to our array of base specifiers.
+ BaseInfo.push_back(Result.get());
+ }
+
+ // If the next token is a comma, consume it and keep reading
+ // base-specifiers.
+ if (Tok.isNot(tok::comma)) break;
+
+ // Consume the comma.
+ ConsumeToken();
+ }
+
+ // Attach the base specifiers
+ Actions.ActOnBaseSpecifiers(ClassDecl, BaseInfo.data(), BaseInfo.size());
+}
+
+/// ParseBaseSpecifier - Parse a C++ base-specifier. A base-specifier is
+/// one entry in the base class list of a class specifier, for example:
+/// class foo : public bar, virtual private baz {
+/// 'public bar' and 'virtual private baz' are each base-specifiers.
+///
+/// base-specifier: [C++ class.derived]
+/// ::[opt] nested-name-specifier[opt] class-name
+/// 'virtual' access-specifier[opt] ::[opt] nested-name-specifier[opt]
+/// class-name
+/// access-specifier 'virtual'[opt] ::[opt] nested-name-specifier[opt]
+/// class-name
+Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) {
+ bool IsVirtual = false;
+ SourceLocation StartLoc = Tok.getLocation();
+
+ // Parse the 'virtual' keyword.
+ if (Tok.is(tok::kw_virtual)) {
+ ConsumeToken();
+ IsVirtual = true;
+ }
+
+ // Parse an (optional) access specifier.
+ AccessSpecifier Access = getAccessSpecifierIfPresent();
+ if (Access)
+ ConsumeToken();
+
+ // Parse the 'virtual' keyword (again!), in case it came after the
+ // access specifier.
+ if (Tok.is(tok::kw_virtual)) {
+ SourceLocation VirtualLoc = ConsumeToken();
+ if (IsVirtual) {
+ // Complain about duplicate 'virtual'
+ Diag(VirtualLoc, diag::err_dup_virtual)
+ << CodeModificationHint::CreateRemoval(SourceRange(VirtualLoc));
+ }
+
+ IsVirtual = true;
+ }
+
+ // Parse optional '::' and optional nested-name-specifier.
+ CXXScopeSpec SS;
+ ParseOptionalCXXScopeSpecifier(SS);
+
+ // The location of the base class itself.
+ SourceLocation BaseLoc = Tok.getLocation();
+
+ // Parse the class-name.
+ SourceLocation EndLocation;
+ TypeResult BaseType = ParseClassName(EndLocation, &SS);
+ if (BaseType.isInvalid())
+ return true;
+
+ // Find the complete source range for the base-specifier.
+ SourceRange Range(StartLoc, EndLocation);
+
+ // Notify semantic analysis that we have parsed a complete
+ // base-specifier.
+ return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access,
+ BaseType.get(), BaseLoc);
+}
+
+/// getAccessSpecifierIfPresent - Determine whether the next token is
+/// a C++ access-specifier.
+///
+/// access-specifier: [C++ class.derived]
+/// 'private'
+/// 'protected'
+/// 'public'
+AccessSpecifier Parser::getAccessSpecifierIfPresent() const
+{
+ switch (Tok.getKind()) {
+ default: return AS_none;
+ case tok::kw_private: return AS_private;
+ case tok::kw_protected: return AS_protected;
+ case tok::kw_public: return AS_public;
+ }
+}
+
+/// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration.
+///
+/// member-declaration:
+/// decl-specifier-seq[opt] member-declarator-list[opt] ';'
+/// function-definition ';'[opt]
+/// ::[opt] nested-name-specifier template[opt] unqualified-id ';'[TODO]
+/// using-declaration [TODO]
+/// [C++0x] static_assert-declaration
+/// template-declaration
+/// [GNU] '__extension__' member-declaration
+///
+/// member-declarator-list:
+/// member-declarator
+/// member-declarator-list ',' member-declarator
+///
+/// member-declarator:
+/// declarator pure-specifier[opt]
+/// declarator constant-initializer[opt]
+/// identifier[opt] ':' constant-expression
+///
+/// pure-specifier:
+/// '= 0'
+///
+/// constant-initializer:
+/// '=' constant-expression
+///
+void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
+ // static_assert-declaration
+ if (Tok.is(tok::kw_static_assert)) {
+ SourceLocation DeclEnd;
+ ParseStaticAssertDeclaration(DeclEnd);
+ return;
+ }
+
+ if (Tok.is(tok::kw_template)) {
+ SourceLocation DeclEnd;
+ ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd,
+ AS);
+ return;
+ }
+
+ // Handle: member-declaration ::= '__extension__' member-declaration
+ if (Tok.is(tok::kw___extension__)) {
+ // __extension__ silences extension warnings in the subexpression.
+ ExtensionRAIIObject O(Diags); // Use RAII to do this.
+ ConsumeToken();
+ return ParseCXXClassMemberDeclaration(AS);
+ }
+
+ SourceLocation DSStart = Tok.getLocation();
+ // decl-specifier-seq:
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ // C++ 9.2p7: The member-declarator-list can be omitted only after a
+ // class-specifier or an enum-specifier or in a friend declaration.
+ // FIXME: Friend declarations.
+ switch (DS.getTypeSpecType()) {
+ case DeclSpec::TST_struct:
+ case DeclSpec::TST_union:
+ case DeclSpec::TST_class:
+ case DeclSpec::TST_enum:
+ Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ return;
+ default:
+ Diag(DSStart, diag::err_no_declarators);
+ return;
+ }
+ }
+
+ Declarator DeclaratorInfo(DS, Declarator::MemberContext);
+
+ if (Tok.isNot(tok::colon)) {
+ // Parse the first declarator.
+ ParseDeclarator(DeclaratorInfo);
+ // Error parsing the declarator?
+ if (!DeclaratorInfo.hasName()) {
+ // If so, skip until the semi-colon or a }.
+ SkipUntil(tok::r_brace, true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ return;
+ }
+
+ // function-definition:
+ if (Tok.is(tok::l_brace)
+ || (DeclaratorInfo.isFunctionDeclarator() &&
+ (Tok.is(tok::colon) || Tok.is(tok::kw_try)))) {
+ if (!DeclaratorInfo.isFunctionDeclarator()) {
+ Diag(Tok, diag::err_func_def_no_params);
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, true);
+ return;
+ }
+
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ Diag(Tok, diag::err_function_declared_typedef);
+ // This recovery skips the entire function body. It would be nice
+ // to simply call ParseCXXInlineMethodDef() below, however Sema
+ // assumes the declarator represents a function, not a typedef.
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, true);
+ return;
+ }
+
+ ParseCXXInlineMethodDef(AS, DeclaratorInfo);
+ return;
+ }
+ }
+
+ // member-declarator-list:
+ // member-declarator
+ // member-declarator-list ',' member-declarator
+
+ llvm::SmallVector<DeclPtrTy, 8> DeclsInGroup;
+ OwningExprResult BitfieldSize(Actions);
+ OwningExprResult Init(Actions);
+ bool Deleted = false;
+
+ while (1) {
+
+ // member-declarator:
+ // declarator pure-specifier[opt]
+ // declarator constant-initializer[opt]
+ // identifier[opt] ':' constant-expression
+
+ if (Tok.is(tok::colon)) {
+ ConsumeToken();
+ BitfieldSize = ParseConstantExpression();
+ if (BitfieldSize.isInvalid())
+ SkipUntil(tok::comma, true, true);
+ }
+
+ // pure-specifier:
+ // '= 0'
+ //
+ // constant-initializer:
+ // '=' constant-expression
+ //
+ // defaulted/deleted function-definition:
+ // '=' 'default' [TODO]
+ // '=' 'delete'
+
+ if (Tok.is(tok::equal)) {
+ ConsumeToken();
+ if (getLang().CPlusPlus0x && Tok.is(tok::kw_delete)) {
+ ConsumeToken();
+ Deleted = true;
+ } else {
+ Init = ParseInitializer();
+ if (Init.isInvalid())
+ SkipUntil(tok::comma, true, true);
+ }
+ }
+
+ // If attributes exist after the declarator, parse them.
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ DeclaratorInfo.AddAttributes(AttrList, Loc);
+ }
+
+ // NOTE: If Sema is the Action module and declarator is an instance field,
+ // this call will *not* return the created decl; It will return null.
+ // See Sema::ActOnCXXMemberDeclarator for details.
+ DeclPtrTy ThisDecl = Actions.ActOnCXXMemberDeclarator(CurScope, AS,
+ DeclaratorInfo,
+ BitfieldSize.release(),
+ Init.release(),
+ Deleted);
+ if (ThisDecl)
+ DeclsInGroup.push_back(ThisDecl);
+
+ if (DeclaratorInfo.isFunctionDeclarator() &&
+ DeclaratorInfo.getDeclSpec().getStorageClassSpec()
+ != DeclSpec::SCS_typedef) {
+ // We just declared a member function. If this member function
+ // has any default arguments, we'll need to parse them later.
+ LateParsedMethodDeclaration *LateMethod = 0;
+ DeclaratorChunk::FunctionTypeInfo &FTI
+ = DeclaratorInfo.getTypeObject(0).Fun;
+ for (unsigned ParamIdx = 0; ParamIdx < FTI.NumArgs; ++ParamIdx) {
+ if (LateMethod || FTI.ArgInfo[ParamIdx].DefaultArgTokens) {
+ if (!LateMethod) {
+ // Push this method onto the stack of late-parsed method
+ // declarations.
+ getCurrentClass().MethodDecls.push_back(
+ LateParsedMethodDeclaration(ThisDecl));
+ LateMethod = &getCurrentClass().MethodDecls.back();
+
+ // Add all of the parameters prior to this one (they don't
+ // have default arguments).
+ LateMethod->DefaultArgs.reserve(FTI.NumArgs);
+ for (unsigned I = 0; I < ParamIdx; ++I)
+ LateMethod->DefaultArgs.push_back(
+ LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param));
+ }
+
+ // Add this parameter to the list of parameters (it or may
+ // not have a default argument).
+ LateMethod->DefaultArgs.push_back(
+ LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param,
+ FTI.ArgInfo[ParamIdx].DefaultArgTokens));
+ }
+ }
+ }
+
+ // 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))
+ break;
+
+ // Consume the comma.
+ ConsumeToken();
+
+ // Parse the next declarator.
+ DeclaratorInfo.clear();
+ BitfieldSize = 0;
+ Init = 0;
+ Deleted = false;
+
+ // Attributes are only allowed on the second declarator.
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ DeclaratorInfo.AddAttributes(AttrList, Loc);
+ }
+
+ if (Tok.isNot(tok::colon))
+ ParseDeclarator(DeclaratorInfo);
+ }
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ Actions.FinalizeDeclaratorGroup(CurScope, DS, DeclsInGroup.data(),
+ DeclsInGroup.size());
+ return;
+ }
+
+ Diag(Tok, diag::err_expected_semi_decl_list);
+ // Skip to end of block or statement
+ SkipUntil(tok::r_brace, true, true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ return;
+}
+
+/// ParseCXXMemberSpecification - Parse the class definition.
+///
+/// member-specification:
+/// member-declaration member-specification[opt]
+/// access-specifier ':' member-specification[opt]
+///
+void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
+ unsigned TagType, DeclPtrTy TagDecl) {
+ assert((TagType == DeclSpec::TST_struct ||
+ TagType == DeclSpec::TST_union ||
+ TagType == DeclSpec::TST_class) && "Invalid TagType!");
+
+ PrettyStackTraceActionsDecl CrashInfo(TagDecl, RecordLoc, Actions,
+ PP.getSourceManager(),
+ "parsing struct/union/class body");
+
+ SourceLocation LBraceLoc = ConsumeBrace();
+
+ // Determine whether this is a top-level (non-nested) class.
+ bool TopLevelClass = ClassStack.empty() ||
+ CurScope->isInCXXInlineMethodScope();
+
+ // Enter a scope for the class.
+ ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope);
+
+ // Note that we are parsing a new (potentially-nested) class definition.
+ ParsingClassDefinition ParsingDef(*this, TagDecl, TopLevelClass);
+
+ if (TagDecl)
+ Actions.ActOnTagStartDefinition(CurScope, TagDecl);
+ else {
+ SkipUntil(tok::r_brace, false, false);
+ return;
+ }
+
+ // 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
+ // are public by default.
+ AccessSpecifier CurAS;
+ if (TagType == DeclSpec::TST_class)
+ CurAS = AS_private;
+ else
+ CurAS = AS_public;
+
+ // 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.
+
+ // Check for extraneous top-level semicolon.
+ if (Tok.is(tok::semi)) {
+ Diag(Tok, diag::ext_extra_struct_semi);
+ ConsumeToken();
+ continue;
+ }
+
+ AccessSpecifier AS = getAccessSpecifierIfPresent();
+ if (AS != AS_none) {
+ // Current token is a C++ access specifier.
+ CurAS = AS;
+ ConsumeToken();
+ ExpectAndConsume(tok::colon, diag::err_expected_colon);
+ continue;
+ }
+
+ // Parse all the comma separated declarators.
+ ParseCXXClassMemberDeclaration(CurAS);
+ }
+
+ SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+
+ AttributeList *AttrList = 0;
+ // If attributes exist after class contents, parse them.
+ if (Tok.is(tok::kw___attribute))
+ AttrList = ParseAttributes(); // FIXME: where should I put them?
+
+ Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl,
+ LBraceLoc, RBraceLoc);
+
+ // C++ 9.2p2: Within the class member-specification, the class is regarded as
+ // complete within function bodies, default arguments,
+ // exception-specifications, and constructor ctor-initializers (including
+ // such things in nested classes).
+ //
+ // FIXME: Only function bodies and constructor ctor-initializers are
+ // parsed correctly, fix the rest.
+ if (TopLevelClass) {
+ // 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.
+ ParseLexedMethodDeclarations(getCurrentClass());
+ ParseLexedMethodDefs(getCurrentClass());
+ }
+
+ // Leave the class scope.
+ ParsingDef.Pop();
+ ClassScope.Exit();
+
+ Actions.ActOnTagFinishDefinition(CurScope, TagDecl);
+}
+
+/// ParseConstructorInitializer - Parse a C++ constructor initializer,
+/// which explicitly initializes the members or base classes of a
+/// class (C++ [class.base.init]). For example, the three initializers
+/// after the ':' in the Derived constructor below:
+///
+/// @code
+/// class Base { };
+/// class Derived : Base {
+/// int x;
+/// float f;
+/// public:
+/// Derived(float f) : Base(), x(17), f(f) { }
+/// };
+/// @endcode
+///
+/// [C++] ctor-initializer:
+/// ':' mem-initializer-list
+///
+/// [C++] mem-initializer-list:
+/// mem-initializer
+/// mem-initializer , mem-initializer-list
+void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) {
+ assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'");
+
+ SourceLocation ColonLoc = ConsumeToken();
+
+ llvm::SmallVector<MemInitTy*, 4> MemInitializers;
+
+ do {
+ MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
+ if (!MemInit.isInvalid())
+ MemInitializers.push_back(MemInit.get());
+
+ if (Tok.is(tok::comma))
+ ConsumeToken();
+ else if (Tok.is(tok::l_brace))
+ break;
+ else {
+ // Skip over garbage, until we get to '{'. Don't eat the '{'.
+ Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma);
+ SkipUntil(tok::l_brace, true, true);
+ break;
+ }
+ } while (true);
+
+ Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc,
+ MemInitializers.data(), MemInitializers.size());
+}
+
+/// ParseMemInitializer - Parse a C++ member initializer, which is
+/// part of a constructor initializer that explicitly initializes one
+/// member or base class (C++ [class.base.init]). See
+/// ParseConstructorInitializer for an example.
+///
+/// [C++] mem-initializer:
+/// mem-initializer-id '(' expression-list[opt] ')'
+///
+/// [C++] mem-initializer-id:
+/// '::'[opt] nested-name-specifier[opt] class-name
+/// identifier
+Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) {
+ // FIXME: parse '::'[opt] nested-name-specifier[opt]
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_member_or_base_name);
+ return true;
+ }
+
+ // Get the identifier. This may be a member name or a class name,
+ // but we'll let the semantic analysis determine which it is.
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ SourceLocation IdLoc = ConsumeToken();
+
+ // Parse the '('.
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen);
+ return true;
+ }
+ SourceLocation LParenLoc = ConsumeParen();
+
+ // Parse the optional expression-list.
+ ExprVector ArgExprs(Actions);
+ CommaLocsTy CommaLocs;
+ if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) {
+ SkipUntil(tok::r_paren);
+ return true;
+ }
+
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ return Actions.ActOnMemInitializer(ConstructorDecl, CurScope, II, IdLoc,
+ LParenLoc, ArgExprs.take(),
+ ArgExprs.size(), CommaLocs.data(),
+ RParenLoc);
+}
+
+/// ParseExceptionSpecification - Parse a C++ exception-specification
+/// (C++ [except.spec]).
+///
+/// exception-specification:
+/// 'throw' '(' type-id-list [opt] ')'
+/// [MS] 'throw' '(' '...' ')'
+///
+/// type-id-list:
+/// type-id
+/// type-id-list ',' type-id
+///
+bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
+ llvm::SmallVector<TypeTy*, 2>
+ &Exceptions,
+ llvm::SmallVector<SourceRange, 2>
+ &Ranges,
+ bool &hasAnyExceptionSpec) {
+ assert(Tok.is(tok::kw_throw) && "expected throw");
+
+ SourceLocation ThrowLoc = ConsumeToken();
+
+ if (!Tok.is(tok::l_paren)) {
+ return Diag(Tok, diag::err_expected_lparen_after) << "throw";
+ }
+ SourceLocation LParenLoc = ConsumeParen();
+
+ // Parse throw(...), a Microsoft extension that means "this function
+ // can throw anything".
+ if (Tok.is(tok::ellipsis)) {
+ hasAnyExceptionSpec = true;
+ SourceLocation EllipsisLoc = ConsumeToken();
+ if (!getLang().Microsoft)
+ Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec);
+ EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ return false;
+ }
+
+ // Parse the sequence of type-ids.
+ SourceRange Range;
+ while (Tok.isNot(tok::r_paren)) {
+ TypeResult Res(ParseTypeName(&Range));
+ if (!Res.isInvalid()) {
+ Exceptions.push_back(Res.get());
+ Ranges.push_back(Range);
+ }
+ if (Tok.is(tok::comma))
+ ConsumeToken();
+ else
+ break;
+ }
+
+ EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ return false;
+}
+
+/// \brief We have just started parsing the definition of a new class,
+/// so push that class onto our stack of classes that is currently
+/// being parsed.
+void Parser::PushParsingClass(DeclPtrTy ClassDecl, bool TopLevelClass) {
+ assert((TopLevelClass || !ClassStack.empty()) &&
+ "Nested class without outer class");
+ ClassStack.push(new ParsingClass(ClassDecl, TopLevelClass));
+}
+
+/// \brief Deallocate the given parsed class and all of its nested
+/// classes.
+void Parser::DeallocateParsedClasses(Parser::ParsingClass *Class) {
+ for (unsigned I = 0, N = Class->NestedClasses.size(); I != N; ++I)
+ DeallocateParsedClasses(Class->NestedClasses[I]);
+ delete Class;
+}
+
+/// \brief Pop the top class of the stack of classes that are
+/// currently being parsed.
+///
+/// This routine should be called when we have finished parsing the
+/// definition of a class, but have not yet popped the Scope
+/// associated with the class's definition.
+///
+/// \returns true if the class we've popped is a top-level class,
+/// false otherwise.
+void Parser::PopParsingClass() {
+ assert(!ClassStack.empty() && "Mismatched push/pop for class parsing");
+
+ ParsingClass *Victim = ClassStack.top();
+ ClassStack.pop();
+ if (Victim->TopLevelClass) {
+ // Deallocate all of the nested classes of this class,
+ // recursively: we don't need to keep any of this information.
+ DeallocateParsedClasses(Victim);
+ return;
+ }
+ assert(!ClassStack.empty() && "Missing top-level class?");
+
+ if (Victim->MethodDecls.empty() && Victim->MethodDefs.empty() &&
+ Victim->NestedClasses.empty()) {
+ // The victim is a nested class, but we will not need to perform
+ // any processing after the definition of this class since it has
+ // no members whose handling was delayed. Therefore, we can just
+ // remove this nested class.
+ delete Victim;
+ return;
+ }
+
+ // This nested class has some members that will need to be processed
+ // after the top-level class is completely defined. Therefore, add
+ // it to the list of nested classes within its parent.
+ assert(CurScope->isClassScope() && "Nested class outside of class scope?");
+ ClassStack.top()->NestedClasses.push_back(Victim);
+ Victim->TemplateScope = CurScope->getParent()->isTemplateParamScope();
+}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
new file mode 100644
index 000000000000..cd62c64276b3
--- /dev/null
+++ b/lib/Parse/ParseExpr.cpp
@@ -0,0 +1,1514 @@
+//===--- ParseExpr.cpp - Expression Parsing -------------------------------===//
+//
+// 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 Expression parsing implementation. Expressions in
+// C99 basically consist of a bunch of binary operators with unary operators and
+// other random stuff at the leaves.
+//
+// In the C99 grammar, these unary operators bind tightest and are represented
+// as the 'cast-expression' production. Everything else is either a binary
+// operator (e.g. '/') or a ternary operator ("?:"). The unary leaves are
+// handled by ParseCastExpression, the higher level pieces are handled by
+// ParseBinaryExpression.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+#include "clang/Basic/PrettyStackTrace.h"
+#include "ExtensionRAIIObject.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/SmallString.h"
+using namespace clang;
+
+/// PrecedenceLevels - These are precedences for the binary/ternary operators in
+/// the C99 grammar. These have been named to relate with the C99 grammar
+/// productions. Low precedences numbers bind more weakly than high numbers.
+namespace prec {
+ enum Level {
+ Unknown = 0, // Not binary operator.
+ Comma = 1, // ,
+ Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
+ Conditional = 3, // ?
+ LogicalOr = 4, // ||
+ LogicalAnd = 5, // &&
+ InclusiveOr = 6, // |
+ ExclusiveOr = 7, // ^
+ And = 8, // &
+ Equality = 9, // ==, !=
+ Relational = 10, // >=, <=, >, <
+ Shift = 11, // <<, >>
+ Additive = 12, // -, +
+ Multiplicative = 13, // *, /, %
+ PointerToMember = 14 // .*, ->*
+ };
+}
+
+
+/// getBinOpPrecedence - Return the precedence of the specified binary operator
+/// token. This returns:
+///
+static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
+ bool GreaterThanIsOperator,
+ bool CPlusPlus0x) {
+ switch (Kind) {
+ case tok::greater:
+ // C++ [temp.names]p3:
+ // [...] When parsing a template-argument-list, the first
+ // non-nested > is taken as the ending delimiter rather than a
+ // greater-than operator. [...]
+ if (GreaterThanIsOperator)
+ return prec::Relational;
+ return prec::Unknown;
+
+ case tok::greatergreater:
+ // C++0x [temp.names]p3:
+ //
+ // [...] Similarly, the first non-nested >> is treated as two
+ // consecutive but distinct > tokens, the first of which is
+ // taken as the end of the template-argument-list and completes
+ // the template-id. [...]
+ if (GreaterThanIsOperator || !CPlusPlus0x)
+ return prec::Shift;
+ return prec::Unknown;
+
+ default: return prec::Unknown;
+ case tok::comma: return prec::Comma;
+ case tok::equal:
+ case tok::starequal:
+ case tok::slashequal:
+ case tok::percentequal:
+ case tok::plusequal:
+ case tok::minusequal:
+ case tok::lesslessequal:
+ case tok::greatergreaterequal:
+ case tok::ampequal:
+ case tok::caretequal:
+ case tok::pipeequal: return prec::Assignment;
+ case tok::question: return prec::Conditional;
+ case tok::pipepipe: return prec::LogicalOr;
+ case tok::ampamp: return prec::LogicalAnd;
+ case tok::pipe: return prec::InclusiveOr;
+ case tok::caret: return prec::ExclusiveOr;
+ case tok::amp: return prec::And;
+ case tok::exclaimequal:
+ case tok::equalequal: return prec::Equality;
+ case tok::lessequal:
+ case tok::less:
+ case tok::greaterequal: return prec::Relational;
+ case tok::lessless: return prec::Shift;
+ case tok::plus:
+ case tok::minus: return prec::Additive;
+ case tok::percent:
+ case tok::slash:
+ case tok::star: return prec::Multiplicative;
+ case tok::periodstar:
+ case tok::arrowstar: return prec::PointerToMember;
+ }
+}
+
+
+/// ParseExpression - Simple precedence-based parser for binary/ternary
+/// operators.
+///
+/// Note: we diverge from the C99 grammar when parsing the assignment-expression
+/// production. C99 specifies that the LHS of an assignment operator should be
+/// parsed as a unary-expression, but consistency dictates that it be a
+/// conditional-expession. In practice, the important thing here is that the
+/// LHS of an assignment has to be an l-value, which productions between
+/// unary-expression and conditional-expression don't produce. Because we want
+/// consistency, we parse the LHS as a conditional-expression, then check for
+/// l-value-ness in semantic analysis stages.
+///
+/// pm-expression: [C++ 5.5]
+/// cast-expression
+/// pm-expression '.*' cast-expression
+/// pm-expression '->*' cast-expression
+///
+/// multiplicative-expression: [C99 6.5.5]
+/// Note: in C++, apply pm-expression instead of cast-expression
+/// cast-expression
+/// multiplicative-expression '*' cast-expression
+/// multiplicative-expression '/' cast-expression
+/// multiplicative-expression '%' cast-expression
+///
+/// additive-expression: [C99 6.5.6]
+/// multiplicative-expression
+/// additive-expression '+' multiplicative-expression
+/// additive-expression '-' multiplicative-expression
+///
+/// shift-expression: [C99 6.5.7]
+/// additive-expression
+/// shift-expression '<<' additive-expression
+/// shift-expression '>>' additive-expression
+///
+/// relational-expression: [C99 6.5.8]
+/// shift-expression
+/// relational-expression '<' shift-expression
+/// relational-expression '>' shift-expression
+/// relational-expression '<=' shift-expression
+/// relational-expression '>=' shift-expression
+///
+/// equality-expression: [C99 6.5.9]
+/// relational-expression
+/// equality-expression '==' relational-expression
+/// equality-expression '!=' relational-expression
+///
+/// AND-expression: [C99 6.5.10]
+/// equality-expression
+/// AND-expression '&' equality-expression
+///
+/// exclusive-OR-expression: [C99 6.5.11]
+/// AND-expression
+/// exclusive-OR-expression '^' AND-expression
+///
+/// inclusive-OR-expression: [C99 6.5.12]
+/// exclusive-OR-expression
+/// inclusive-OR-expression '|' exclusive-OR-expression
+///
+/// logical-AND-expression: [C99 6.5.13]
+/// inclusive-OR-expression
+/// logical-AND-expression '&&' inclusive-OR-expression
+///
+/// logical-OR-expression: [C99 6.5.14]
+/// logical-AND-expression
+/// logical-OR-expression '||' logical-AND-expression
+///
+/// conditional-expression: [C99 6.5.15]
+/// logical-OR-expression
+/// logical-OR-expression '?' expression ':' conditional-expression
+/// [GNU] logical-OR-expression '?' ':' conditional-expression
+/// [C++] the third operand is an assignment-expression
+///
+/// assignment-expression: [C99 6.5.16]
+/// conditional-expression
+/// unary-expression assignment-operator assignment-expression
+/// [C++] throw-expression [C++ 15]
+///
+/// assignment-operator: one of
+/// = *= /= %= += -= <<= >>= &= ^= |=
+///
+/// expression: [C99 6.5.17]
+/// assignment-expression
+/// expression ',' assignment-expression
+///
+Parser::OwningExprResult Parser::ParseExpression() {
+ OwningExprResult LHS(ParseAssignmentExpression());
+ if (LHS.isInvalid()) return move(LHS);
+
+ return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
+}
+
+/// This routine is called when the '@' is seen and consumed.
+/// Current token is an Identifier and is not a 'try'. This
+/// routine is necessary to disambiguate @try-statement from,
+/// for example, @encode-expression.
+///
+Parser::OwningExprResult
+Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) {
+ OwningExprResult LHS(ParseObjCAtExpression(AtLoc));
+ if (LHS.isInvalid()) return move(LHS);
+
+ return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
+}
+
+/// This routine is called when a leading '__extension__' is seen and
+/// consumed. This is necessary because the token gets consumed in the
+/// process of disambiguating between an expression and a declaration.
+Parser::OwningExprResult
+Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
+ OwningExprResult LHS(Actions, true);
+ {
+ // Silence extension warnings in the sub-expression
+ ExtensionRAIIObject O(Diags);
+
+ LHS = ParseCastExpression(false);
+ if (LHS.isInvalid()) return move(LHS);
+ }
+
+ LHS = Actions.ActOnUnaryOp(CurScope, ExtLoc, tok::kw___extension__,
+ move(LHS));
+ if (LHS.isInvalid()) return move(LHS);
+
+ return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
+}
+
+/// ParseAssignmentExpression - Parse an expr that doesn't include commas.
+///
+Parser::OwningExprResult Parser::ParseAssignmentExpression() {
+ if (Tok.is(tok::kw_throw))
+ return ParseThrowExpression();
+
+ OwningExprResult LHS(ParseCastExpression(false));
+ if (LHS.isInvalid()) return move(LHS);
+
+ return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment);
+}
+
+/// ParseAssignmentExprWithObjCMessageExprStart - Parse an assignment expression
+/// where part of an objc message send has already been parsed. In this case
+/// LBracLoc indicates the location of the '[' of the message send, and either
+/// ReceiverName or ReceiverExpr is non-null indicating the receiver of the
+/// message.
+///
+/// Since this handles full assignment-expression's, it handles postfix
+/// expressions and other binary operators for these expressions as well.
+Parser::OwningExprResult
+Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc,
+ SourceLocation NameLoc,
+ IdentifierInfo *ReceiverName,
+ ExprArg ReceiverExpr) {
+ OwningExprResult R(ParseObjCMessageExpressionBody(LBracLoc, NameLoc,
+ ReceiverName,
+ move(ReceiverExpr)));
+ if (R.isInvalid()) return move(R);
+ R = ParsePostfixExpressionSuffix(move(R));
+ if (R.isInvalid()) return move(R);
+ return ParseRHSOfBinaryExpression(move(R), prec::Assignment);
+}
+
+
+Parser::OwningExprResult Parser::ParseConstantExpression() {
+ OwningExprResult LHS(ParseCastExpression(false));
+ if (LHS.isInvalid()) return move(LHS);
+
+ return ParseRHSOfBinaryExpression(move(LHS), prec::Conditional);
+}
+
+/// ParseRHSOfBinaryExpression - Parse a binary expression that starts with
+/// LHS and has a precedence of at least MinPrec.
+Parser::OwningExprResult
+Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
+ unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(),
+ GreaterThanIsOperator,
+ getLang().CPlusPlus0x);
+ SourceLocation ColonLoc;
+
+ while (1) {
+ // If this token has a lower precedence than we are allowed to parse (e.g.
+ // because we are called recursively, or because the token is not a binop),
+ // then we are done!
+ if (NextTokPrec < MinPrec)
+ return move(LHS);
+
+ // Consume the operator, saving the operator token for error reporting.
+ Token OpToken = Tok;
+ ConsumeToken();
+
+ // Special case handling for the ternary operator.
+ OwningExprResult TernaryMiddle(Actions, true);
+ if (NextTokPrec == prec::Conditional) {
+ if (Tok.isNot(tok::colon)) {
+ // Handle this production specially:
+ // logical-OR-expression '?' expression ':' conditional-expression
+ // In particular, the RHS of the '?' is 'expression', not
+ // 'logical-OR-expression' as we might expect.
+ TernaryMiddle = ParseExpression();
+ if (TernaryMiddle.isInvalid())
+ return move(TernaryMiddle);
+ } else {
+ // Special case handling of "X ? Y : Z" where Y is empty:
+ // logical-OR-expression '?' ':' conditional-expression [GNU]
+ TernaryMiddle = 0;
+ Diag(Tok, diag::ext_gnu_conditional_expr);
+ }
+
+ if (Tok.isNot(tok::colon)) {
+ Diag(Tok, diag::err_expected_colon);
+ Diag(OpToken, diag::note_matching) << "?";
+ return ExprError();
+ }
+
+ // Eat the colon.
+ ColonLoc = ConsumeToken();
+ }
+
+ // Parse another leaf here for the RHS of the operator.
+ // ParseCastExpression works here because all RHS expressions in C have it
+ // as a prefix, at least. However, in C++, an assignment-expression could
+ // be a throw-expression, which is not a valid cast-expression.
+ // Therefore we need some special-casing here.
+ // Also note that the third operand of the conditional operator is
+ // an assignment-expression in C++.
+ OwningExprResult RHS(Actions);
+ if (getLang().CPlusPlus && NextTokPrec <= prec::Conditional)
+ RHS = ParseAssignmentExpression();
+ else
+ RHS = ParseCastExpression(false);
+ if (RHS.isInvalid())
+ return move(RHS);
+
+ // Remember the precedence of this operator and get the precedence of the
+ // operator immediately to the right of the RHS.
+ unsigned ThisPrec = NextTokPrec;
+ NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
+ getLang().CPlusPlus0x);
+
+ // Assignment and conditional expressions are right-associative.
+ bool isRightAssoc = ThisPrec == prec::Conditional ||
+ ThisPrec == prec::Assignment;
+
+ // Get the precedence of the operator to the right of the RHS. If it binds
+ // more tightly with RHS than we do, evaluate it completely first.
+ if (ThisPrec < NextTokPrec ||
+ (ThisPrec == NextTokPrec && isRightAssoc)) {
+ // If this is left-associative, only parse things on the RHS that bind
+ // more tightly than the current operator. If it is left-associative, it
+ // is okay, to bind exactly as tightly. For example, compile A=B=C=D as
+ // A=(B=(C=D)), where each paren is a level of recursion here.
+ // The function takes ownership of the RHS.
+ RHS = ParseRHSOfBinaryExpression(move(RHS), ThisPrec + !isRightAssoc);
+ if (RHS.isInvalid())
+ return move(RHS);
+
+ NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
+ getLang().CPlusPlus0x);
+ }
+ assert(NextTokPrec <= ThisPrec && "Recursion didn't work!");
+
+ if (!LHS.isInvalid()) {
+ // Combine the LHS and RHS into the LHS (e.g. build AST).
+ if (TernaryMiddle.isInvalid()) {
+ // If we're using '>>' as an operator within a template
+ // argument list (in C++98), suggest the addition of
+ // parentheses so that the code remains well-formed in C++0x.
+ if (!GreaterThanIsOperator && OpToken.is(tok::greatergreater))
+ SuggestParentheses(OpToken.getLocation(),
+ diag::warn_cxx0x_right_shift_in_template_arg,
+ SourceRange(Actions.getExprRange(LHS.get()).getBegin(),
+ Actions.getExprRange(RHS.get()).getEnd()));
+
+ LHS = Actions.ActOnBinOp(CurScope, OpToken.getLocation(),
+ OpToken.getKind(), move(LHS), move(RHS));
+ } else
+ LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc,
+ move(LHS), move(TernaryMiddle),
+ move(RHS));
+ }
+ }
+}
+
+/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is
+/// true, parse a unary-expression. isAddressOfOperand exists because an
+/// id-expression that is the operand of address-of gets special treatment
+/// due to member pointers.
+///
+Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
+ bool isAddressOfOperand) {
+ bool NotCastExpr;
+ OwningExprResult Res = ParseCastExpression(isUnaryExpression,
+ isAddressOfOperand,
+ NotCastExpr);
+ if (NotCastExpr)
+ Diag(Tok, diag::err_expected_expression);
+ return move(Res);
+}
+
+/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is
+/// true, parse a unary-expression. isAddressOfOperand exists because an
+/// id-expression that is the operand of address-of gets special treatment
+/// due to member pointers. NotCastExpr is set to true if the token is not the
+/// start of a cast-expression, and no diagnostic is emitted in this case.
+///
+/// cast-expression: [C99 6.5.4]
+/// unary-expression
+/// '(' type-name ')' cast-expression
+///
+/// unary-expression: [C99 6.5.3]
+/// postfix-expression
+/// '++' unary-expression
+/// '--' unary-expression
+/// unary-operator cast-expression
+/// 'sizeof' unary-expression
+/// 'sizeof' '(' type-name ')'
+/// [GNU] '__alignof' unary-expression
+/// [GNU] '__alignof' '(' type-name ')'
+/// [C++0x] 'alignof' '(' type-id ')'
+/// [GNU] '&&' identifier
+/// [C++] new-expression
+/// [C++] delete-expression
+///
+/// unary-operator: one of
+/// '&' '*' '+' '-' '~' '!'
+/// [GNU] '__extension__' '__real' '__imag'
+///
+/// primary-expression: [C99 6.5.1]
+/// [C99] identifier
+/// [C++] id-expression
+/// constant
+/// string-literal
+/// [C++] boolean-literal [C++ 2.13.5]
+/// [C++0x] 'nullptr' [C++0x 2.14.7]
+/// '(' expression ')'
+/// '__func__' [C99 6.4.2.2]
+/// [GNU] '__FUNCTION__'
+/// [GNU] '__PRETTY_FUNCTION__'
+/// [GNU] '(' compound-statement ')'
+/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')'
+/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')'
+/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
+/// assign-expr ')'
+/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
+/// [GNU] '__null'
+/// [OBJC] '[' objc-message-expr ']'
+/// [OBJC] '@selector' '(' objc-selector-arg ')'
+/// [OBJC] '@protocol' '(' identifier ')'
+/// [OBJC] '@encode' '(' type-name ')'
+/// [OBJC] objc-string-literal
+/// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
+/// [C++] typename-specifier '(' expression-list[opt] ')' [TODO]
+/// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
+/// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
+/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
+/// [C++] 'static_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
+/// [C++] 'typeid' '(' expression ')' [C++ 5.2p1]
+/// [C++] 'typeid' '(' type-id ')' [C++ 5.2p1]
+/// [C++] 'this' [C++ 9.3.2]
+/// [G++] unary-type-trait '(' type-id ')'
+/// [G++] binary-type-trait '(' type-id ',' type-id ')' [TODO]
+/// [clang] '^' block-literal
+///
+/// constant: [C99 6.4.4]
+/// integer-constant
+/// floating-constant
+/// enumeration-constant -> identifier
+/// character-constant
+///
+/// id-expression: [C++ 5.1]
+/// unqualified-id
+/// qualified-id [TODO]
+///
+/// unqualified-id: [C++ 5.1]
+/// identifier
+/// operator-function-id
+/// conversion-function-id [TODO]
+/// '~' class-name [TODO]
+/// template-id [TODO]
+///
+/// new-expression: [C++ 5.3.4]
+/// '::'[opt] 'new' new-placement[opt] new-type-id
+/// new-initializer[opt]
+/// '::'[opt] 'new' new-placement[opt] '(' type-id ')'
+/// new-initializer[opt]
+///
+/// delete-expression: [C++ 5.3.5]
+/// '::'[opt] 'delete' cast-expression
+/// '::'[opt] 'delete' '[' ']' cast-expression
+///
+/// [GNU] unary-type-trait:
+/// '__has_nothrow_assign' [TODO]
+/// '__has_nothrow_copy' [TODO]
+/// '__has_nothrow_constructor' [TODO]
+/// '__has_trivial_assign' [TODO]
+/// '__has_trivial_copy' [TODO]
+/// '__has_trivial_constructor'
+/// '__has_trivial_destructor'
+/// '__has_virtual_destructor' [TODO]
+/// '__is_abstract' [TODO]
+/// '__is_class'
+/// '__is_empty' [TODO]
+/// '__is_enum'
+/// '__is_pod'
+/// '__is_polymorphic'
+/// '__is_union'
+///
+/// [GNU] binary-type-trait:
+/// '__is_base_of' [TODO]
+///
+Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
+ bool isAddressOfOperand,
+ bool &NotCastExpr) {
+ OwningExprResult Res(Actions);
+ tok::TokenKind SavedKind = Tok.getKind();
+ NotCastExpr = false;
+
+ // This handles all of cast-expression, unary-expression, postfix-expression,
+ // and primary-expression. We handle them together like this for efficiency
+ // and to simplify handling of an expression starting with a '(' token: which
+ // may be one of a parenthesized expression, cast-expression, compound literal
+ // expression, or statement expression.
+ //
+ // If the parsed tokens consist of a primary-expression, the cases below
+ // call ParsePostfixExpressionSuffix to handle the postfix expression
+ // suffixes. Cases that cannot be followed by postfix exprs should
+ // return without invoking ParsePostfixExpressionSuffix.
+ switch (SavedKind) {
+ case tok::l_paren: {
+ // If this expression is limited to being a unary-expression, the parent can
+ // not start a cast expression.
+ ParenParseOption ParenExprType =
+ isUnaryExpression ? CompoundLiteral : CastExpr;
+ TypeTy *CastTy;
+ SourceLocation LParenLoc = Tok.getLocation();
+ SourceLocation RParenLoc;
+ Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
+ CastTy, RParenLoc);
+ if (Res.isInvalid()) return move(Res);
+
+ switch (ParenExprType) {
+ case SimpleExpr: break; // Nothing else to do.
+ case CompoundStmt: break; // Nothing else to do.
+ case CompoundLiteral:
+ // We parsed '(' type-name ')' '{' ... '}'. If any suffixes of
+ // postfix-expression exist, parse them now.
+ break;
+ case CastExpr:
+ // We have parsed the cast-expression and no postfix-expr pieces are
+ // following.
+ return move(Res);
+ }
+
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+ }
+
+ // primary-expression
+ case tok::numeric_constant:
+ // constant: integer-constant
+ // constant: floating-constant
+
+ Res = Actions.ActOnNumericConstant(Tok);
+ ConsumeToken();
+
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+
+ case tok::kw_true:
+ case tok::kw_false:
+ return ParseCXXBoolLiteral();
+
+ case tok::kw_nullptr:
+ return Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
+
+ case tok::identifier: { // primary-expression: identifier
+ // unqualified-id: identifier
+ // constant: enumeration-constant
+ // Turn a potentially qualified name into a annot_typename or
+ // annot_cxxscope if it would be valid. This handles things like x::y, etc.
+ if (getLang().CPlusPlus) {
+ // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
+ if (TryAnnotateTypeOrScopeToken())
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
+ }
+
+ // Support 'Class.property' notation.
+ // We don't use isTokObjCMessageIdentifierReceiver(), since it allows
+ // 'super' (which is inappropriate here).
+ if (getLang().ObjC1 &&
+ Actions.getTypeName(*Tok.getIdentifierInfo(),
+ Tok.getLocation(), CurScope) &&
+ NextToken().is(tok::period)) {
+ IdentifierInfo &ReceiverName = *Tok.getIdentifierInfo();
+ SourceLocation IdentLoc = ConsumeToken();
+ SourceLocation DotLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ return ExprError();
+ }
+ IdentifierInfo &PropertyName = *Tok.getIdentifierInfo();
+ SourceLocation PropertyLoc = ConsumeToken();
+
+ Res = Actions.ActOnClassPropertyRefExpr(ReceiverName, PropertyName,
+ IdentLoc, PropertyLoc);
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+ }
+ // Consume the identifier so that we can see if it is followed by a '('.
+ // Function designators are allowed to be undeclared (C99 6.5.1p2), so we
+ // need to know whether or not this identifier is a function designator or
+ // not.
+ IdentifierInfo &II = *Tok.getIdentifierInfo();
+ SourceLocation L = ConsumeToken();
+ Res = Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren));
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+ }
+ case tok::char_constant: // constant: character-constant
+ Res = Actions.ActOnCharacterConstant(Tok);
+ ConsumeToken();
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+ case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2]
+ case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU]
+ case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU]
+ Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind);
+ ConsumeToken();
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+ case tok::string_literal: // primary-expression: string-literal
+ case tok::wide_string_literal:
+ Res = ParseStringLiteralExpression();
+ if (Res.isInvalid()) return move(Res);
+ // This can be followed by postfix-expr pieces (e.g. "foo"[1]).
+ return ParsePostfixExpressionSuffix(move(Res));
+ case tok::kw___builtin_va_arg:
+ case tok::kw___builtin_offsetof:
+ case tok::kw___builtin_choose_expr:
+ case tok::kw___builtin_types_compatible_p:
+ return ParseBuiltinPrimaryExpression();
+ case tok::kw___null:
+ return Actions.ActOnGNUNullExpr(ConsumeToken());
+ break;
+ case tok::plusplus: // unary-expression: '++' unary-expression
+ case tok::minusminus: { // unary-expression: '--' unary-expression
+ SourceLocation SavedLoc = ConsumeToken();
+ Res = ParseCastExpression(true);
+ if (!Res.isInvalid())
+ Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res));
+ return move(Res);
+ }
+ case tok::amp: { // unary-expression: '&' cast-expression
+ // Special treatment because of member pointers
+ SourceLocation SavedLoc = ConsumeToken();
+ Res = ParseCastExpression(false, true);
+ if (!Res.isInvalid())
+ Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res));
+ return move(Res);
+ }
+
+ case tok::star: // unary-expression: '*' cast-expression
+ case tok::plus: // unary-expression: '+' cast-expression
+ case tok::minus: // unary-expression: '-' cast-expression
+ case tok::tilde: // unary-expression: '~' cast-expression
+ case tok::exclaim: // unary-expression: '!' cast-expression
+ case tok::kw___real: // unary-expression: '__real' cast-expression [GNU]
+ case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU]
+ SourceLocation SavedLoc = ConsumeToken();
+ Res = ParseCastExpression(false);
+ if (!Res.isInvalid())
+ Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res));
+ return move(Res);
+ }
+
+ case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU]
+ // __extension__ silences extension warnings in the subexpression.
+ ExtensionRAIIObject O(Diags); // Use RAII to do this.
+ SourceLocation SavedLoc = ConsumeToken();
+ Res = ParseCastExpression(false);
+ if (!Res.isInvalid())
+ Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res));
+ return move(Res);
+ }
+ case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression
+ // unary-expression: 'sizeof' '(' type-name ')'
+ case tok::kw_alignof:
+ case tok::kw___alignof: // unary-expression: '__alignof' unary-expression
+ // unary-expression: '__alignof' '(' type-name ')'
+ // unary-expression: 'alignof' '(' type-id ')'
+ return ParseSizeofAlignofExpression();
+ case tok::ampamp: { // unary-expression: '&&' identifier
+ SourceLocation AmpAmpLoc = ConsumeToken();
+ if (Tok.isNot(tok::identifier))
+ return ExprError(Diag(Tok, diag::err_expected_ident));
+
+ Diag(AmpAmpLoc, diag::ext_gnu_address_of_label);
+ Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(),
+ Tok.getIdentifierInfo());
+ ConsumeToken();
+ return move(Res);
+ }
+ case tok::kw_const_cast:
+ case tok::kw_dynamic_cast:
+ case tok::kw_reinterpret_cast:
+ case tok::kw_static_cast:
+ Res = ParseCXXCasts();
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+ case tok::kw_typeid:
+ Res = ParseCXXTypeid();
+ // This can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+ case tok::kw_this:
+ Res = ParseCXXThis();
+ // This can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+
+ case tok::kw_char:
+ case tok::kw_wchar_t:
+ case tok::kw_bool:
+ case tok::kw_short:
+ case tok::kw_int:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_void:
+ case tok::kw_typename:
+ case tok::kw_typeof:
+ case tok::annot_typename: {
+ if (!getLang().CPlusPlus) {
+ Diag(Tok, diag::err_expected_expression);
+ return ExprError();
+ }
+
+ // postfix-expression: simple-type-specifier '(' expression-list[opt] ')'
+ //
+ DeclSpec DS;
+ ParseCXXSimpleTypeSpecifier(DS);
+ if (Tok.isNot(tok::l_paren))
+ return ExprError(Diag(Tok, diag::err_expected_lparen_after_type)
+ << DS.getSourceRange());
+
+ Res = ParseCXXTypeConstructExpression(DS);
+ // This can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+ }
+
+ case tok::annot_cxxscope: // [C++] id-expression: qualified-id
+ case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id
+ // template-id
+ Res = ParseCXXIdExpression(isAddressOfOperand);
+ return ParsePostfixExpressionSuffix(move(Res));
+
+ case tok::coloncolon: {
+ // ::foo::bar -> global qualified name etc. If TryAnnotateTypeOrScopeToken
+ // annotates the token, tail recurse.
+ if (TryAnnotateTypeOrScopeToken())
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
+
+ // ::new -> [C++] new-expression
+ // ::delete -> [C++] delete-expression
+ SourceLocation CCLoc = ConsumeToken();
+ if (Tok.is(tok::kw_new))
+ return ParseCXXNewExpression(true, CCLoc);
+ if (Tok.is(tok::kw_delete))
+ return ParseCXXDeleteExpression(true, CCLoc);
+
+ // This is not a type name or scope specifier, it is an invalid expression.
+ Diag(CCLoc, diag::err_expected_expression);
+ return ExprError();
+ }
+
+ case tok::kw_new: // [C++] new-expression
+ return ParseCXXNewExpression(false, Tok.getLocation());
+
+ case tok::kw_delete: // [C++] delete-expression
+ return ParseCXXDeleteExpression(false, Tok.getLocation());
+
+ case tok::kw___is_pod: // [GNU] unary-type-trait
+ case tok::kw___is_class:
+ case tok::kw___is_enum:
+ case tok::kw___is_union:
+ case tok::kw___is_polymorphic:
+ case tok::kw___is_abstract:
+ case tok::kw___has_trivial_constructor:
+ case tok::kw___has_trivial_destructor:
+ return ParseUnaryTypeTrait();
+
+ case tok::at: {
+ SourceLocation AtLoc = ConsumeToken();
+ return ParseObjCAtExpression(AtLoc);
+ }
+ case tok::caret:
+ return ParsePostfixExpressionSuffix(ParseBlockLiteralExpression());
+ case tok::l_square:
+ // These can be followed by postfix-expr pieces.
+ if (getLang().ObjC1)
+ return ParsePostfixExpressionSuffix(ParseObjCMessageExpression());
+ // FALL THROUGH.
+ default:
+ NotCastExpr = true;
+ return ExprError();
+ }
+
+ // unreachable.
+ abort();
+}
+
+/// ParsePostfixExpressionSuffix - Once the leading part of a postfix-expression
+/// is parsed, this method parses any suffixes that apply.
+///
+/// postfix-expression: [C99 6.5.2]
+/// primary-expression
+/// postfix-expression '[' expression ']'
+/// postfix-expression '(' argument-expression-list[opt] ')'
+/// postfix-expression '.' identifier
+/// postfix-expression '->' identifier
+/// postfix-expression '++'
+/// postfix-expression '--'
+/// '(' type-name ')' '{' initializer-list '}'
+/// '(' type-name ')' '{' initializer-list ',' '}'
+///
+/// argument-expression-list: [C99 6.5.2]
+/// argument-expression
+/// argument-expression-list ',' assignment-expression
+///
+Parser::OwningExprResult
+Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
+ // Now that the primary-expression piece of the postfix-expression has been
+ // parsed, see if there are any postfix-expression pieces here.
+ SourceLocation Loc;
+ while (1) {
+ switch (Tok.getKind()) {
+ default: // Not a postfix-expression suffix.
+ return move(LHS);
+ case tok::l_square: { // postfix-expression: p-e '[' expression ']'
+ Loc = ConsumeBracket();
+ OwningExprResult Idx(ParseExpression());
+
+ SourceLocation RLoc = Tok.getLocation();
+
+ if (!LHS.isInvalid() && !Idx.isInvalid() && Tok.is(tok::r_square)) {
+ LHS = Actions.ActOnArraySubscriptExpr(CurScope, move(LHS), Loc,
+ move(Idx), RLoc);
+ } else
+ LHS = ExprError();
+
+ // Match the ']'.
+ MatchRHSPunctuation(tok::r_square, Loc);
+ break;
+ }
+
+ case tok::l_paren: { // p-e: p-e '(' argument-expression-list[opt] ')'
+ ExprVector ArgExprs(Actions);
+ CommaLocsTy CommaLocs;
+
+ Loc = ConsumeParen();
+
+ if (Tok.isNot(tok::r_paren)) {
+ if (ParseExpressionList(ArgExprs, CommaLocs)) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+ }
+
+ // Match the ')'.
+ if (Tok.isNot(tok::r_paren)) {
+ MatchRHSPunctuation(tok::r_paren, Loc);
+ return ExprError();
+ }
+
+ if (!LHS.isInvalid()) {
+ assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&&
+ "Unexpected number of commas!");
+ LHS = Actions.ActOnCallExpr(CurScope, move(LHS), Loc,
+ move_arg(ArgExprs), CommaLocs.data(),
+ Tok.getLocation());
+ }
+
+ ConsumeParen();
+ break;
+ }
+ case tok::arrow: // postfix-expression: p-e '->' identifier
+ case tok::period: { // postfix-expression: p-e '.' identifier
+ tok::TokenKind OpKind = Tok.getKind();
+ SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token.
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ return ExprError();
+ }
+
+ if (!LHS.isInvalid()) {
+ LHS = Actions.ActOnMemberReferenceExpr(CurScope, move(LHS), OpLoc,
+ OpKind, Tok.getLocation(),
+ *Tok.getIdentifierInfo(),
+ ObjCImpDecl);
+ }
+ ConsumeToken();
+ break;
+ }
+ case tok::plusplus: // postfix-expression: postfix-expression '++'
+ case tok::minusminus: // postfix-expression: postfix-expression '--'
+ if (!LHS.isInvalid()) {
+ LHS = Actions.ActOnPostfixUnaryOp(CurScope, Tok.getLocation(),
+ Tok.getKind(), move(LHS));
+ }
+ ConsumeToken();
+ break;
+ }
+ }
+}
+
+/// ParseExprAfterTypeofSizeofAlignof - We parsed a typeof/sizeof/alignof and
+/// we are at the start of an expression or a parenthesized type-id.
+/// OpTok is the operand token (typeof/sizeof/alignof). Returns the expression
+/// (isCastExpr == false) or the type (isCastExpr == true).
+///
+/// unary-expression: [C99 6.5.3]
+/// 'sizeof' unary-expression
+/// 'sizeof' '(' type-name ')'
+/// [GNU] '__alignof' unary-expression
+/// [GNU] '__alignof' '(' type-name ')'
+/// [C++0x] 'alignof' '(' type-id ')'
+///
+/// [GNU] typeof-specifier:
+/// typeof ( expressions )
+/// typeof ( type-name )
+/// [GNU/C++] typeof unary-expression
+///
+Parser::OwningExprResult
+Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
+ bool &isCastExpr,
+ TypeTy *&CastTy,
+ SourceRange &CastRange) {
+
+ assert((OpTok.is(tok::kw_typeof) || OpTok.is(tok::kw_sizeof) ||
+ OpTok.is(tok::kw___alignof) || OpTok.is(tok::kw_alignof)) &&
+ "Not a typeof/sizeof/alignof expression!");
+
+ OwningExprResult Operand(Actions);
+
+ // If the operand doesn't start with an '(', it must be an expression.
+ if (Tok.isNot(tok::l_paren)) {
+ isCastExpr = false;
+ if (OpTok.is(tok::kw_typeof) && !getLang().CPlusPlus) {
+ Diag(Tok,diag::err_expected_lparen_after_id) << OpTok.getIdentifierInfo();
+ return ExprError();
+ }
+ Operand = ParseCastExpression(true/*isUnaryExpression*/);
+
+ } else {
+ // If it starts with a '(', we know that it is either a parenthesized
+ // type-name, or it is a unary-expression that starts with a compound
+ // literal, or starts with a primary-expression that is a parenthesized
+ // expression.
+ ParenParseOption ExprType = CastExpr;
+ SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
+ Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/,
+ CastTy, RParenLoc);
+ CastRange = SourceRange(LParenLoc, RParenLoc);
+
+ // If ParseParenExpression parsed a '(typename)' sequence only, then this is
+ // a type.
+ if (ExprType == CastExpr) {
+ isCastExpr = true;
+ return ExprEmpty();
+ }
+
+ // If this is a parenthesized expression, it is the start of a
+ // unary-expression, but doesn't include any postfix pieces. Parse these
+ // now if present.
+ Operand = ParsePostfixExpressionSuffix(move(Operand));
+ }
+
+ // If we get here, the operand to the typeof/sizeof/alignof was an expresion.
+ isCastExpr = false;
+ return move(Operand);
+}
+
+
+/// ParseSizeofAlignofExpression - Parse a sizeof or alignof expression.
+/// unary-expression: [C99 6.5.3]
+/// 'sizeof' unary-expression
+/// 'sizeof' '(' type-name ')'
+/// [GNU] '__alignof' unary-expression
+/// [GNU] '__alignof' '(' type-name ')'
+/// [C++0x] 'alignof' '(' type-id ')'
+Parser::OwningExprResult Parser::ParseSizeofAlignofExpression() {
+ assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof)
+ || Tok.is(tok::kw_alignof)) &&
+ "Not a sizeof/alignof expression!");
+ Token OpTok = Tok;
+ ConsumeToken();
+
+ bool isCastExpr;
+ TypeTy *CastTy;
+ SourceRange CastRange;
+ OwningExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok,
+ isCastExpr,
+ CastTy,
+ CastRange);
+
+ if (isCastExpr)
+ return Actions.ActOnSizeOfAlignOfExpr(OpTok.getLocation(),
+ OpTok.is(tok::kw_sizeof),
+ /*isType=*/true, CastTy,
+ CastRange);
+
+ // If we get here, the operand to the sizeof/alignof was an expresion.
+ if (!Operand.isInvalid())
+ Operand = Actions.ActOnSizeOfAlignOfExpr(OpTok.getLocation(),
+ OpTok.is(tok::kw_sizeof),
+ /*isType=*/false,
+ Operand.release(), CastRange);
+ return move(Operand);
+}
+
+/// ParseBuiltinPrimaryExpression
+///
+/// primary-expression: [C99 6.5.1]
+/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')'
+/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')'
+/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
+/// assign-expr ')'
+/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
+///
+/// [GNU] offsetof-member-designator:
+/// [GNU] identifier
+/// [GNU] offsetof-member-designator '.' identifier
+/// [GNU] offsetof-member-designator '[' expression ']'
+///
+Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() {
+ OwningExprResult Res(Actions);
+ const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo();
+
+ tok::TokenKind T = Tok.getKind();
+ SourceLocation StartLoc = ConsumeToken(); // Eat the builtin identifier.
+
+ // All of these start with an open paren.
+ if (Tok.isNot(tok::l_paren))
+ return ExprError(Diag(Tok, diag::err_expected_lparen_after_id)
+ << BuiltinII);
+
+ SourceLocation LParenLoc = ConsumeParen();
+ // TODO: Build AST.
+
+ switch (T) {
+ default: assert(0 && "Not a builtin primary expression!");
+ case tok::kw___builtin_va_arg: {
+ OwningExprResult Expr(ParseAssignmentExpression());
+ if (Expr.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ return ExprError();
+
+ TypeResult Ty = ParseTypeName();
+
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected_rparen);
+ return ExprError();
+ }
+ if (Ty.isInvalid())
+ Res = ExprError();
+ else
+ Res = Actions.ActOnVAArg(StartLoc, move(Expr), Ty.get(), ConsumeParen());
+ break;
+ }
+ case tok::kw___builtin_offsetof: {
+ SourceLocation TypeLoc = Tok.getLocation();
+ TypeResult Ty = ParseTypeName();
+ if (Ty.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ return ExprError();
+
+ // We must have at least one identifier here.
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ // Keep track of the various subcomponents we see.
+ llvm::SmallVector<Action::OffsetOfComponent, 4> Comps;
+
+ Comps.push_back(Action::OffsetOfComponent());
+ Comps.back().isBrackets = false;
+ Comps.back().U.IdentInfo = Tok.getIdentifierInfo();
+ Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken();
+
+ // FIXME: This loop leaks the index expressions on error.
+ while (1) {
+ if (Tok.is(tok::period)) {
+ // offsetof-member-designator: offsetof-member-designator '.' identifier
+ Comps.push_back(Action::OffsetOfComponent());
+ Comps.back().isBrackets = false;
+ Comps.back().LocStart = ConsumeToken();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+ Comps.back().U.IdentInfo = Tok.getIdentifierInfo();
+ Comps.back().LocEnd = ConsumeToken();
+
+ } else if (Tok.is(tok::l_square)) {
+ // offsetof-member-designator: offsetof-member-design '[' expression ']'
+ Comps.push_back(Action::OffsetOfComponent());
+ Comps.back().isBrackets = true;
+ Comps.back().LocStart = ConsumeBracket();
+ Res = ParseExpression();
+ if (Res.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return move(Res);
+ }
+ Comps.back().U.E = Res.release();
+
+ Comps.back().LocEnd =
+ MatchRHSPunctuation(tok::r_square, Comps.back().LocStart);
+ } else if (Tok.is(tok::r_paren)) {
+ if (Ty.isInvalid())
+ Res = ExprError();
+ else
+ Res = Actions.ActOnBuiltinOffsetOf(CurScope, StartLoc, TypeLoc,
+ Ty.get(), &Comps[0],
+ Comps.size(), ConsumeParen());
+ break;
+ } else {
+ // Error occurred.
+ return ExprError();
+ }
+ }
+ break;
+ }
+ case tok::kw___builtin_choose_expr: {
+ OwningExprResult Cond(ParseAssignmentExpression());
+ if (Cond.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return move(Cond);
+ }
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ return ExprError();
+
+ OwningExprResult Expr1(ParseAssignmentExpression());
+ if (Expr1.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return move(Expr1);
+ }
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ return ExprError();
+
+ OwningExprResult Expr2(ParseAssignmentExpression());
+ if (Expr2.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return move(Expr2);
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected_rparen);
+ return ExprError();
+ }
+ Res = Actions.ActOnChooseExpr(StartLoc, move(Cond), move(Expr1),
+ move(Expr2), ConsumeParen());
+ break;
+ }
+ case tok::kw___builtin_types_compatible_p:
+ TypeResult Ty1 = ParseTypeName();
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ return ExprError();
+
+ TypeResult Ty2 = ParseTypeName();
+
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected_rparen);
+ return ExprError();
+ }
+
+ if (Ty1.isInvalid() || Ty2.isInvalid())
+ Res = ExprError();
+ else
+ Res = Actions.ActOnTypesCompatibleExpr(StartLoc, Ty1.get(), Ty2.get(),
+ ConsumeParen());
+ break;
+ }
+
+ // These can be followed by postfix-expr pieces because they are
+ // primary-expressions.
+ return ParsePostfixExpressionSuffix(move(Res));
+}
+
+/// ParseParenExpression - This parses the unit that starts with a '(' token,
+/// based on what is allowed by ExprType. The actual thing parsed is returned
+/// in ExprType. If stopIfCastExpr is true, it will only return the parsed type,
+/// not the parsed cast-expression.
+///
+/// primary-expression: [C99 6.5.1]
+/// '(' expression ')'
+/// [GNU] '(' compound-statement ')' (if !ParenExprOnly)
+/// postfix-expression: [C99 6.5.2]
+/// '(' type-name ')' '{' initializer-list '}'
+/// '(' type-name ')' '{' initializer-list ',' '}'
+/// cast-expression: [C99 6.5.4]
+/// '(' type-name ')' cast-expression
+///
+Parser::OwningExprResult
+Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
+ TypeTy *&CastTy, SourceLocation &RParenLoc) {
+ assert(Tok.is(tok::l_paren) && "Not a paren expr!");
+ GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
+ SourceLocation OpenLoc = ConsumeParen();
+ OwningExprResult Result(Actions, true);
+ bool isAmbiguousTypeId;
+ CastTy = 0;
+
+ if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) {
+ Diag(Tok, diag::ext_gnu_statement_expr);
+ OwningStmtResult Stmt(ParseCompoundStatement(true));
+ ExprType = CompoundStmt;
+
+ // If the substmt parsed correctly, build the AST node.
+ if (!Stmt.isInvalid() && Tok.is(tok::r_paren))
+ Result = Actions.ActOnStmtExpr(OpenLoc, move(Stmt), Tok.getLocation());
+
+ } else if (ExprType >= CompoundLiteral &&
+ isTypeIdInParens(isAmbiguousTypeId)) {
+
+ // Otherwise, this is a compound literal expression or cast expression.
+
+ // In C++, if the type-id is ambiguous we disambiguate based on context.
+ // If stopIfCastExpr is true the context is a typeof/sizeof/alignof
+ // 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);
+
+ TypeResult Ty = ParseTypeName();
+
+ // Match the ')'.
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, OpenLoc);
+
+ if (Tok.is(tok::l_brace)) {
+ ExprType = CompoundLiteral;
+ return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc);
+ }
+
+ if (ExprType == CastExpr) {
+ // We parsed '(' type-name ')' and the thing after it wasn't a '{'.
+
+ if (Ty.isInvalid())
+ return ExprError();
+
+ CastTy = Ty.get();
+
+ if (stopIfCastExpr) {
+ // Note that this doesn't parse the subsequent cast-expression, it just
+ // returns the parsed type to the callee.
+ return OwningExprResult(Actions);
+ }
+
+ // Parse the cast-expression that follows it next.
+ // TODO: For cast expression with CastTy.
+ Result = ParseCastExpression(false);
+ if (!Result.isInvalid())
+ Result = Actions.ActOnCastExpr(OpenLoc, CastTy, RParenLoc,move(Result));
+ return move(Result);
+ }
+
+ Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
+ return ExprError();
+ } else {
+ Result = ParseExpression();
+ ExprType = SimpleExpr;
+ if (!Result.isInvalid() && Tok.is(tok::r_paren))
+ Result = Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), move(Result));
+ }
+
+ // Match the ')'.
+ if (Result.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, OpenLoc);
+
+ return move(Result);
+}
+
+/// ParseCompoundLiteralExpression - We have parsed the parenthesized type-name
+/// and we are at the left brace.
+///
+/// postfix-expression: [C99 6.5.2]
+/// '(' type-name ')' '{' initializer-list '}'
+/// '(' type-name ')' '{' initializer-list ',' '}'
+///
+Parser::OwningExprResult
+Parser::ParseCompoundLiteralExpression(TypeTy *Ty,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ assert(Tok.is(tok::l_brace) && "Not a compound literal!");
+ if (!getLang().C99) // Compound literals don't exist in C90.
+ Diag(LParenLoc, diag::ext_c99_compound_literal);
+ OwningExprResult Result = ParseInitializer();
+ if (!Result.isInvalid() && Ty)
+ return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, move(Result));
+ return move(Result);
+}
+
+/// ParseStringLiteralExpression - This handles the various token types that
+/// form string literals, and also handles string concatenation [C99 5.1.1.2,
+/// translation phase #6].
+///
+/// primary-expression: [C99 6.5.1]
+/// string-literal
+Parser::OwningExprResult Parser::ParseStringLiteralExpression() {
+ assert(isTokenStringLiteral() && "Not a string literal!");
+
+ // String concat. Note that keywords like __func__ and __FUNCTION__ are not
+ // considered to be strings for concatenation purposes.
+ llvm::SmallVector<Token, 4> StringToks;
+
+ do {
+ StringToks.push_back(Tok);
+ ConsumeStringToken();
+ } while (isTokenStringLiteral());
+
+ // Pass the set of string tokens, ready for concatenation, to the actions.
+ return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size());
+}
+
+/// ParseExpressionList - Used for C/C++ (argument-)expression-list.
+///
+/// argument-expression-list:
+/// assignment-expression
+/// argument-expression-list , assignment-expression
+///
+/// [C++] expression-list:
+/// [C++] assignment-expression
+/// [C++] expression-list , assignment-expression
+///
+bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs) {
+ while (1) {
+ OwningExprResult Expr(ParseAssignmentExpression());
+ if (Expr.isInvalid())
+ return true;
+
+ Exprs.push_back(Expr.release());
+
+ if (Tok.isNot(tok::comma))
+ return false;
+ // Move to the next argument, remember where the comma was.
+ CommaLocs.push_back(ConsumeToken());
+ }
+}
+
+/// ParseBlockId - Parse a block-id, which roughly looks like int (int x).
+///
+/// [clang] block-id:
+/// [clang] specifier-qualifier-list block-declarator
+///
+void Parser::ParseBlockId() {
+ // Parse the specifier-qualifier-list piece.
+ DeclSpec DS;
+ ParseSpecifierQualifierList(DS);
+
+ // Parse the block-declarator.
+ Declarator DeclaratorInfo(DS, Declarator::BlockLiteralContext);
+ ParseDeclarator(DeclaratorInfo);
+
+ // We do this for: ^ __attribute__((noreturn)) {, as DS has the attributes.
+ DeclaratorInfo.AddAttributes(DS.TakeAttributes(),
+ SourceLocation());
+
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ DeclaratorInfo.AddAttributes(AttrList, Loc);
+ }
+
+ // Inform sema that we are starting a block.
+ Actions.ActOnBlockArguments(DeclaratorInfo, CurScope);
+}
+
+/// ParseBlockLiteralExpression - Parse a block literal, which roughly looks
+/// like ^(int x){ return x+1; }
+///
+/// block-literal:
+/// [clang] '^' block-args[opt] compound-statement
+/// [clang] '^' block-id compound-statement
+/// [clang] block-args:
+/// [clang] '(' parameter-list ')'
+///
+Parser::OwningExprResult Parser::ParseBlockLiteralExpression() {
+ assert(Tok.is(tok::caret) && "block literal starts with ^");
+ SourceLocation CaretLoc = ConsumeToken();
+
+ PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), CaretLoc,
+ "block literal parsing");
+
+ // Enter a scope to hold everything within the block. This includes the
+ // argument decls, decls within the compound expression, etc. This also
+ // allows determining whether a variable reference inside the block is
+ // within or outside of the block.
+ ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope |
+ Scope::BreakScope | Scope::ContinueScope |
+ Scope::DeclScope);
+
+ // Inform sema that we are starting a block.
+ Actions.ActOnBlockStart(CaretLoc, CurScope);
+
+ // Parse the return type if present.
+ DeclSpec DS;
+ Declarator ParamInfo(DS, Declarator::BlockLiteralContext);
+ // FIXME: Since the return type isn't actually parsed, it can't be used to
+ // fill ParamInfo with an initial valid range, so do it manually.
+ ParamInfo.SetSourceRange(SourceRange(Tok.getLocation(), Tok.getLocation()));
+
+ // If this block has arguments, parse them. There is no ambiguity here with
+ // the expression case, because the expression case requires a parameter list.
+ if (Tok.is(tok::l_paren)) {
+ ParseParenDeclarator(ParamInfo);
+ // Parse the pieces after the identifier as if we had "int(...)".
+ // SetIdentifier sets the source range end, but in this case we're past
+ // that location.
+ SourceLocation Tmp = ParamInfo.getSourceRange().getEnd();
+ ParamInfo.SetIdentifier(0, CaretLoc);
+ ParamInfo.SetRangeEnd(Tmp);
+ if (ParamInfo.isInvalidType()) {
+ // If there was an error parsing the arguments, they may have
+ // tried to use ^(x+y) which requires an argument list. Just
+ // skip the whole block literal.
+ Actions.ActOnBlockError(CaretLoc, CurScope);
+ return ExprError();
+ }
+
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ ParamInfo.AddAttributes(AttrList, Loc);
+ }
+
+ // Inform sema that we are starting a block.
+ Actions.ActOnBlockArguments(ParamInfo, CurScope);
+ } else if (!Tok.is(tok::l_brace)) {
+ ParseBlockId();
+ } else {
+ // Otherwise, pretend we saw (void).
+ ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
+ SourceLocation(),
+ 0, 0, 0,
+ false, SourceLocation(),
+ false, 0, 0, 0,
+ CaretLoc, ParamInfo),
+ CaretLoc);
+
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ ParamInfo.AddAttributes(AttrList, Loc);
+ }
+
+ // Inform sema that we are starting a block.
+ Actions.ActOnBlockArguments(ParamInfo, CurScope);
+ }
+
+
+ OwningExprResult Result(Actions, true);
+ if (!Tok.is(tok::l_brace)) {
+ // Saw something like: ^expr
+ Diag(Tok, diag::err_expected_expression);
+ Actions.ActOnBlockError(CaretLoc, CurScope);
+ return ExprError();
+ }
+
+ OwningStmtResult Stmt(ParseCompoundStatementBody());
+ if (!Stmt.isInvalid())
+ Result = Actions.ActOnBlockStmtExpr(CaretLoc, move(Stmt), CurScope);
+ else
+ Actions.ActOnBlockError(CaretLoc, CurScope);
+ return move(Result);
+}
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
new file mode 100644
index 000000000000..681c6adb2ea9
--- /dev/null
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -0,0 +1,1166 @@
+//===--- ParseExprCXX.cpp - C++ Expression Parsing ------------------------===//
+//
+// 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 Expression parsing implementation for C++.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/DeclSpec.h"
+using namespace clang;
+
+/// ParseOptionalCXXScopeSpecifier - Parse global scope or
+/// nested-name-specifier if present. Returns true if a nested-name-specifier
+/// was parsed from the token stream. Note that this routine will not parse
+/// ::new or ::delete, it will just leave them in the token stream.
+///
+/// '::'[opt] nested-name-specifier
+/// '::'
+///
+/// nested-name-specifier:
+/// type-name '::'
+/// namespace-name '::'
+/// nested-name-specifier identifier '::'
+/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
+///
+bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
+ assert(getLang().CPlusPlus &&
+ "Call sites of this function should be guarded by checking for C++");
+
+ if (Tok.is(tok::annot_cxxscope)) {
+ SS.setScopeRep(Tok.getAnnotationValue());
+ SS.setRange(Tok.getAnnotationRange());
+ ConsumeToken();
+ return true;
+ }
+
+ bool HasScopeSpecifier = false;
+
+ if (Tok.is(tok::coloncolon)) {
+ // ::new and ::delete aren't nested-name-specifiers.
+ tok::TokenKind NextKind = NextToken().getKind();
+ if (NextKind == tok::kw_new || NextKind == tok::kw_delete)
+ return false;
+
+ // '::' - Global scope qualifier.
+ SourceLocation CCLoc = ConsumeToken();
+ SS.setBeginLoc(CCLoc);
+ SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc));
+ SS.setEndLoc(CCLoc);
+ HasScopeSpecifier = true;
+ }
+
+ while (true) {
+ // nested-name-specifier:
+ // type-name '::'
+ // namespace-name '::'
+ // nested-name-specifier identifier '::'
+ if (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
+ // We have an identifier followed by a '::'. Lookup this name
+ // as the name in a nested-name-specifier.
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ SourceLocation IdLoc = ConsumeToken();
+ assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
+ SourceLocation CCLoc = ConsumeToken();
+
+ if (!HasScopeSpecifier) {
+ SS.setBeginLoc(IdLoc);
+ HasScopeSpecifier = true;
+ }
+
+ if (SS.isInvalid())
+ continue;
+
+ SS.setScopeRep(
+ Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II));
+ SS.setEndLoc(CCLoc);
+ continue;
+ }
+
+ // nested-name-specifier:
+ // type-name '::'
+ // nested-name-specifier 'template'[opt] simple-template-id '::'
+ if ((Tok.is(tok::identifier) && NextToken().is(tok::less)) ||
+ Tok.is(tok::kw_template)) {
+ // Parse the optional 'template' keyword, then make sure we have
+ // 'identifier <' after it.
+ if (Tok.is(tok::kw_template)) {
+ SourceLocation TemplateKWLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok.getLocation(),
+ diag::err_id_after_template_in_nested_name_spec)
+ << SourceRange(TemplateKWLoc);
+ break;
+ }
+
+ if (NextToken().isNot(tok::less)) {
+ Diag(NextToken().getLocation(),
+ diag::err_less_after_template_name_in_nested_name_spec)
+ << Tok.getIdentifierInfo()->getName()
+ << SourceRange(TemplateKWLoc, Tok.getLocation());
+ break;
+ }
+
+ TemplateTy Template
+ = Actions.ActOnDependentTemplateName(TemplateKWLoc,
+ *Tok.getIdentifierInfo(),
+ Tok.getLocation(),
+ SS);
+ AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
+ &SS, TemplateKWLoc, false);
+ continue;
+ }
+
+ TemplateTy Template;
+ TemplateNameKind TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(),
+ CurScope, Template, &SS);
+ if (TNK) {
+ // We have found a template name, so annotate this this token
+ // with a template-id annotation. We do not permit the
+ // template-id to be translated into a type annotation,
+ // because some clients (e.g., the parsing of class template
+ // specializations) still want to see the original template-id
+ // token.
+ AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(), false);
+ continue;
+ }
+ }
+
+ if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) {
+ // We have
+ //
+ // simple-template-id '::'
+ //
+ // So we need to check whether the simple-template-id is of the
+ // right kind (it should name a type or be dependent), and then
+ // convert it into a type within the nested-name-specifier.
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+
+ if (TemplateId->Kind == TNK_Type_template ||
+ TemplateId->Kind == TNK_Dependent_template_name) {
+ AnnotateTemplateIdTokenAsType(&SS);
+ SS.setScopeRep(0);
+
+ assert(Tok.is(tok::annot_typename) &&
+ "AnnotateTemplateIdTokenAsType isn't working");
+ Token TypeToken = Tok;
+ ConsumeToken();
+ assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
+ SourceLocation CCLoc = ConsumeToken();
+
+ if (!HasScopeSpecifier) {
+ SS.setBeginLoc(TypeToken.getLocation());
+ HasScopeSpecifier = true;
+ }
+
+ if (TypeToken.getAnnotationValue())
+ SS.setScopeRep(
+ Actions.ActOnCXXNestedNameSpecifier(CurScope, SS,
+ TypeToken.getAnnotationValue(),
+ TypeToken.getAnnotationRange(),
+ CCLoc));
+ else
+ SS.setScopeRep(0);
+ SS.setEndLoc(CCLoc);
+ continue;
+ } else
+ assert(false && "FIXME: Only type template names supported here");
+ }
+
+ // We don't have any tokens that form the beginning of a
+ // nested-name-specifier, so we're done.
+ break;
+ }
+
+ return HasScopeSpecifier;
+}
+
+/// ParseCXXIdExpression - Handle id-expression.
+///
+/// id-expression:
+/// unqualified-id
+/// qualified-id
+///
+/// unqualified-id:
+/// identifier
+/// operator-function-id
+/// conversion-function-id [TODO]
+/// '~' class-name [TODO]
+/// template-id [TODO]
+///
+/// qualified-id:
+/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
+/// '::' identifier
+/// '::' operator-function-id
+/// '::' template-id [TODO]
+///
+/// nested-name-specifier:
+/// type-name '::'
+/// namespace-name '::'
+/// nested-name-specifier identifier '::'
+/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
+///
+/// NOTE: The standard specifies that, for qualified-id, the parser does not
+/// expect:
+///
+/// '::' conversion-function-id
+/// '::' '~' class-name
+///
+/// This may cause a slight inconsistency on diagnostics:
+///
+/// class C {};
+/// namespace A {}
+/// void f() {
+/// :: A :: ~ C(); // Some Sema error about using destructor with a
+/// // namespace.
+/// :: ~ C(); // Some Parser error like 'unexpected ~'.
+/// }
+///
+/// We simplify the parser a bit and make it work like:
+///
+/// qualified-id:
+/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
+/// '::' unqualified-id
+///
+/// That way Sema can handle and report similar errors for namespaces and the
+/// global scope.
+///
+/// The isAddressOfOperand parameter indicates that this id-expression is a
+/// direct operand of the address-of operator. This is, besides member contexts,
+/// the only place where a qualified-id naming a non-static class member may
+/// appear.
+///
+Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
+ // qualified-id:
+ // '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
+ // '::' unqualified-id
+ //
+ CXXScopeSpec SS;
+ ParseOptionalCXXScopeSpecifier(SS);
+
+ // unqualified-id:
+ // identifier
+ // operator-function-id
+ // conversion-function-id
+ // '~' class-name [TODO]
+ // template-id [TODO]
+ //
+ switch (Tok.getKind()) {
+ default:
+ return ExprError(Diag(Tok, diag::err_expected_unqualified_id));
+
+ case tok::identifier: {
+ // Consume the identifier so that we can see if it is followed by a '('.
+ IdentifierInfo &II = *Tok.getIdentifierInfo();
+ SourceLocation L = ConsumeToken();
+ return Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren),
+ &SS, isAddressOfOperand);
+ }
+
+ case tok::kw_operator: {
+ SourceLocation OperatorLoc = Tok.getLocation();
+ if (OverloadedOperatorKind Op = TryParseOperatorFunctionId())
+ return Actions.ActOnCXXOperatorFunctionIdExpr(
+ CurScope, OperatorLoc, Op, Tok.is(tok::l_paren), SS,
+ isAddressOfOperand);
+ if (TypeTy *Type = ParseConversionFunctionId())
+ return Actions.ActOnCXXConversionFunctionExpr(CurScope, OperatorLoc, Type,
+ Tok.is(tok::l_paren), SS,
+ isAddressOfOperand);
+
+ // We already complained about a bad conversion-function-id,
+ // above.
+ return ExprError();
+ }
+
+ } // switch.
+
+ assert(0 && "The switch was supposed to take care everything.");
+}
+
+/// ParseCXXCasts - This handles the various ways to cast expressions to another
+/// type.
+///
+/// postfix-expression: [C++ 5.2p1]
+/// 'dynamic_cast' '<' type-name '>' '(' expression ')'
+/// 'static_cast' '<' type-name '>' '(' expression ')'
+/// 'reinterpret_cast' '<' type-name '>' '(' expression ')'
+/// 'const_cast' '<' type-name '>' '(' expression ')'
+///
+Parser::OwningExprResult Parser::ParseCXXCasts() {
+ tok::TokenKind Kind = Tok.getKind();
+ const char *CastName = 0; // For error messages
+
+ switch (Kind) {
+ default: assert(0 && "Unknown C++ cast!"); abort();
+ 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;
+ case tok::kw_static_cast: CastName = "static_cast"; break;
+ }
+
+ SourceLocation OpLoc = ConsumeToken();
+ SourceLocation LAngleBracketLoc = Tok.getLocation();
+
+ if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
+ return ExprError();
+
+ TypeResult CastTy = ParseTypeName();
+ SourceLocation RAngleBracketLoc = Tok.getLocation();
+
+ if (ExpectAndConsume(tok::greater, diag::err_expected_greater))
+ return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << "<");
+
+ SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
+
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, CastName))
+ return ExprError();
+
+ OwningExprResult Result = ParseExpression();
+
+ // Match the ')'.
+ if (Result.isInvalid())
+ SkipUntil(tok::r_paren);
+
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ if (!Result.isInvalid() && !CastTy.isInvalid())
+ Result = Actions.ActOnCXXNamedCast(OpLoc, Kind,
+ LAngleBracketLoc, CastTy.get(),
+ RAngleBracketLoc,
+ LParenLoc, move(Result), RParenLoc);
+
+ return move(Result);
+}
+
+/// ParseCXXTypeid - This handles the C++ typeid expression.
+///
+/// postfix-expression: [C++ 5.2p1]
+/// 'typeid' '(' expression ')'
+/// 'typeid' '(' type-id ')'
+///
+Parser::OwningExprResult Parser::ParseCXXTypeid() {
+ assert(Tok.is(tok::kw_typeid) && "Not 'typeid'!");
+
+ SourceLocation OpLoc = ConsumeToken();
+ SourceLocation LParenLoc = Tok.getLocation();
+ SourceLocation RParenLoc;
+
+ // typeid expressions are always parenthesized.
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
+ "typeid"))
+ return ExprError();
+
+ OwningExprResult Result(Actions);
+
+ if (isTypeIdInParens()) {
+ TypeResult Ty = ParseTypeName();
+
+ // Match the ')'.
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ if (Ty.isInvalid())
+ return ExprError();
+
+ Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true,
+ Ty.get(), RParenLoc);
+ } else {
+ Result = ParseExpression();
+
+ // Match the ')'.
+ if (Result.isInvalid())
+ SkipUntil(tok::r_paren);
+ else {
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false,
+ Result.release(), RParenLoc);
+ }
+ }
+
+ return move(Result);
+}
+
+/// ParseCXXBoolLiteral - This handles the C++ Boolean literals.
+///
+/// boolean-literal: [C++ 2.13.5]
+/// 'true'
+/// 'false'
+Parser::OwningExprResult Parser::ParseCXXBoolLiteral() {
+ tok::TokenKind Kind = Tok.getKind();
+ return Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind);
+}
+
+/// ParseThrowExpression - This handles the C++ throw expression.
+///
+/// throw-expression: [C++ 15]
+/// 'throw' assignment-expression[opt]
+Parser::OwningExprResult Parser::ParseThrowExpression() {
+ assert(Tok.is(tok::kw_throw) && "Not throw!");
+ SourceLocation ThrowLoc = ConsumeToken(); // Eat the throw token.
+
+ // If the current token isn't the start of an assignment-expression,
+ // then the expression is not present. This handles things like:
+ // "C ? throw : (void)42", which is crazy but legal.
+ switch (Tok.getKind()) { // FIXME: move this predicate somewhere common.
+ case tok::semi:
+ case tok::r_paren:
+ case tok::r_square:
+ case tok::r_brace:
+ case tok::colon:
+ case tok::comma:
+ return Actions.ActOnCXXThrow(ThrowLoc, ExprArg(Actions));
+
+ default:
+ OwningExprResult Expr(ParseAssignmentExpression());
+ if (Expr.isInvalid()) return move(Expr);
+ return Actions.ActOnCXXThrow(ThrowLoc, move(Expr));
+ }
+}
+
+/// ParseCXXThis - This handles the C++ 'this' pointer.
+///
+/// C++ 9.3.2: In the body of a non-static member function, the keyword this is
+/// a non-lvalue expression whose value is the address of the object for which
+/// the function is called.
+Parser::OwningExprResult Parser::ParseCXXThis() {
+ assert(Tok.is(tok::kw_this) && "Not 'this'!");
+ SourceLocation ThisLoc = ConsumeToken();
+ return Actions.ActOnCXXThis(ThisLoc);
+}
+
+/// ParseCXXTypeConstructExpression - Parse construction of a specified type.
+/// Can be interpreted either as function-style casting ("int(x)")
+/// or class type construction ("ClassType(x,y,z)")
+/// or creation of a value-initialized type ("int()").
+///
+/// postfix-expression: [C++ 5.2p1]
+/// simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
+/// typename-specifier '(' expression-list[opt] ')' [TODO]
+///
+Parser::OwningExprResult
+Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ TypeTy *TypeRep = Actions.ActOnTypeName(CurScope, DeclaratorInfo).get();
+
+ assert(Tok.is(tok::l_paren) && "Expected '('!");
+ SourceLocation LParenLoc = ConsumeParen();
+
+ ExprVector Exprs(Actions);
+ CommaLocsTy CommaLocs;
+
+ if (Tok.isNot(tok::r_paren)) {
+ if (ParseExpressionList(Exprs, CommaLocs)) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+ }
+
+ // Match the ')'.
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
+ "Unexpected number of commas!");
+ return Actions.ActOnCXXTypeConstructExpr(DS.getSourceRange(), TypeRep,
+ LParenLoc, move_arg(Exprs),
+ CommaLocs.data(), RParenLoc);
+}
+
+/// ParseCXXCondition - if/switch/while/for condition expression.
+///
+/// condition:
+/// expression
+/// type-specifier-seq declarator '=' assignment-expression
+/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
+/// '=' assignment-expression
+///
+Parser::OwningExprResult Parser::ParseCXXCondition() {
+ if (!isCXXConditionDeclaration())
+ return ParseExpression(); // expression
+
+ SourceLocation StartLoc = Tok.getLocation();
+
+ // type-specifier-seq
+ DeclSpec DS;
+ ParseSpecifierQualifierList(DS);
+
+ // declarator
+ Declarator DeclaratorInfo(DS, Declarator::ConditionContext);
+ ParseDeclarator(DeclaratorInfo);
+
+ // simple-asm-expr[opt]
+ if (Tok.is(tok::kw_asm)) {
+ SourceLocation Loc;
+ OwningExprResult AsmLabel(ParseSimpleAsm(&Loc));
+ if (AsmLabel.isInvalid()) {
+ SkipUntil(tok::semi);
+ return ExprError();
+ }
+ DeclaratorInfo.setAsmLabel(AsmLabel.release());
+ DeclaratorInfo.SetRangeEnd(Loc);
+ }
+
+ // If attributes are present, parse them.
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ DeclaratorInfo.AddAttributes(AttrList, Loc);
+ }
+
+ // '=' assignment-expression
+ if (Tok.isNot(tok::equal))
+ return ExprError(Diag(Tok, diag::err_expected_equal_after_declarator));
+ SourceLocation EqualLoc = ConsumeToken();
+ OwningExprResult AssignExpr(ParseAssignmentExpression());
+ if (AssignExpr.isInvalid())
+ return ExprError();
+
+ return Actions.ActOnCXXConditionDeclarationExpr(CurScope, StartLoc,
+ DeclaratorInfo,EqualLoc,
+ move(AssignExpr));
+}
+
+/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
+/// This should only be called when the current token is known to be part of
+/// simple-type-specifier.
+///
+/// simple-type-specifier:
+/// '::'[opt] nested-name-specifier[opt] type-name
+/// '::'[opt] nested-name-specifier 'template' simple-template-id [TODO]
+/// char
+/// wchar_t
+/// bool
+/// short
+/// int
+/// long
+/// signed
+/// unsigned
+/// float
+/// double
+/// void
+/// [GNU] typeof-specifier
+/// [C++0x] auto [TODO]
+///
+/// type-name:
+/// class-name
+/// enum-name
+/// typedef-name
+///
+void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
+ DS.SetRangeStart(Tok.getLocation());
+ const char *PrevSpec;
+ SourceLocation Loc = Tok.getLocation();
+
+ switch (Tok.getKind()) {
+ case tok::identifier: // foo::bar
+ case tok::coloncolon: // ::foo::bar
+ assert(0 && "Annotation token should already be formed!");
+ default:
+ assert(0 && "Not a simple-type-specifier token!");
+ abort();
+
+ // type-name
+ case tok::annot_typename: {
+ DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
+ Tok.getAnnotationValue());
+ break;
+ }
+
+ // builtin types
+ case tok::kw_short:
+ DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
+ break;
+ case tok::kw_long:
+ DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
+ break;
+ case tok::kw_signed:
+ DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
+ break;
+ case tok::kw_unsigned:
+ DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
+ break;
+ case tok::kw_void:
+ DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
+ break;
+ case tok::kw_char:
+ DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
+ break;
+ case tok::kw_int:
+ DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
+ break;
+ case tok::kw_float:
+ DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
+ break;
+ case tok::kw_double:
+ DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
+ break;
+ case tok::kw_wchar_t:
+ DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec);
+ break;
+ case tok::kw_bool:
+ DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
+ break;
+
+ // GNU typeof support.
+ case tok::kw_typeof:
+ ParseTypeofSpecifier(DS);
+ DS.Finish(Diags, PP);
+ return;
+ }
+ if (Tok.is(tok::annot_typename))
+ DS.SetRangeEnd(Tok.getAnnotationEndLoc());
+ else
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken();
+ DS.Finish(Diags, PP);
+}
+
+/// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++
+/// [dcl.name]), which is a non-empty sequence of type-specifiers,
+/// e.g., "const short int". Note that the DeclSpec is *not* finished
+/// by parsing the type-specifier-seq, because these sequences are
+/// typically followed by some form of declarator. Returns true and
+/// emits diagnostics if this is not a type-specifier-seq, false
+/// otherwise.
+///
+/// type-specifier-seq: [C++ 8.1]
+/// type-specifier type-specifier-seq[opt]
+///
+bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
+ DS.SetRangeStart(Tok.getLocation());
+ const char *PrevSpec = 0;
+ int isInvalid = 0;
+
+ // Parse one or more of the type specifiers.
+ if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec)) {
+ Diag(Tok, diag::err_operator_missing_type_specifier);
+ return true;
+ }
+
+ while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec)) ;
+
+ return false;
+}
+
+/// TryParseOperatorFunctionId - Attempts to parse a C++ overloaded
+/// operator name (C++ [over.oper]). If successful, returns the
+/// predefined identifier that corresponds to that overloaded
+/// operator. Otherwise, returns NULL and does not consume any tokens.
+///
+/// operator-function-id: [C++ 13.5]
+/// 'operator' operator
+///
+/// operator: one of
+/// new delete new[] delete[]
+/// + - * / % ^ & | ~
+/// ! = < > += -= *= /= %=
+/// ^= &= |= << >> >>= <<= == !=
+/// <= >= && || ++ -- , ->* ->
+/// () []
+OverloadedOperatorKind
+Parser::TryParseOperatorFunctionId(SourceLocation *EndLoc) {
+ assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
+ SourceLocation Loc;
+
+ OverloadedOperatorKind Op = OO_None;
+ switch (NextToken().getKind()) {
+ case tok::kw_new:
+ ConsumeToken(); // 'operator'
+ Loc = ConsumeToken(); // 'new'
+ if (Tok.is(tok::l_square)) {
+ ConsumeBracket(); // '['
+ Loc = Tok.getLocation();
+ ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
+ Op = OO_Array_New;
+ } else {
+ Op = OO_New;
+ }
+ if (EndLoc)
+ *EndLoc = Loc;
+ return Op;
+
+ case tok::kw_delete:
+ ConsumeToken(); // 'operator'
+ Loc = ConsumeToken(); // 'delete'
+ if (Tok.is(tok::l_square)) {
+ ConsumeBracket(); // '['
+ Loc = Tok.getLocation();
+ ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
+ Op = OO_Array_Delete;
+ } else {
+ Op = OO_Delete;
+ }
+ if (EndLoc)
+ *EndLoc = Loc;
+ return Op;
+
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ case tok::Token: Op = OO_##Name; break;
+#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
+#include "clang/Basic/OperatorKinds.def"
+
+ case tok::l_paren:
+ ConsumeToken(); // 'operator'
+ ConsumeParen(); // '('
+ Loc = Tok.getLocation();
+ ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); // ')'
+ if (EndLoc)
+ *EndLoc = Loc;
+ return OO_Call;
+
+ case tok::l_square:
+ ConsumeToken(); // 'operator'
+ ConsumeBracket(); // '['
+ Loc = Tok.getLocation();
+ ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
+ if (EndLoc)
+ *EndLoc = Loc;
+ return OO_Subscript;
+
+ default:
+ return OO_None;
+ }
+
+ ConsumeToken(); // 'operator'
+ Loc = ConsumeAnyToken(); // the operator itself
+ if (EndLoc)
+ *EndLoc = Loc;
+ return Op;
+}
+
+/// ParseConversionFunctionId - Parse a C++ conversion-function-id,
+/// which expresses the name of a user-defined conversion operator
+/// (C++ [class.conv.fct]p1). Returns the type that this operator is
+/// specifying a conversion for, or NULL if there was an error.
+///
+/// conversion-function-id: [C++ 12.3.2]
+/// operator conversion-type-id
+///
+/// conversion-type-id:
+/// type-specifier-seq conversion-declarator[opt]
+///
+/// conversion-declarator:
+/// ptr-operator conversion-declarator[opt]
+Parser::TypeTy *Parser::ParseConversionFunctionId(SourceLocation *EndLoc) {
+ assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
+ ConsumeToken(); // 'operator'
+
+ // Parse the type-specifier-seq.
+ DeclSpec DS;
+ if (ParseCXXTypeSpecifierSeq(DS))
+ return 0;
+
+ // Parse the conversion-declarator, which is merely a sequence of
+ // ptr-operators.
+ Declarator D(DS, Declarator::TypeNameContext);
+ ParseDeclaratorInternal(D, /*DirectDeclParser=*/0);
+ if (EndLoc)
+ *EndLoc = D.getSourceRange().getEnd();
+
+ // Finish up the type.
+ Action::TypeResult Result = Actions.ActOnTypeName(CurScope, D);
+ if (Result.isInvalid())
+ return 0;
+ else
+ return Result.get();
+}
+
+/// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate
+/// memory in a typesafe manner and call constructors.
+///
+/// This method is called to parse the new expression after the optional :: has
+/// been already parsed. If the :: was present, "UseGlobal" is true and "Start"
+/// is its location. Otherwise, "Start" is the location of the 'new' token.
+///
+/// new-expression:
+/// '::'[opt] 'new' new-placement[opt] new-type-id
+/// new-initializer[opt]
+/// '::'[opt] 'new' new-placement[opt] '(' type-id ')'
+/// new-initializer[opt]
+///
+/// new-placement:
+/// '(' expression-list ')'
+///
+/// new-type-id:
+/// type-specifier-seq new-declarator[opt]
+///
+/// new-declarator:
+/// ptr-operator new-declarator[opt]
+/// direct-new-declarator
+///
+/// new-initializer:
+/// '(' expression-list[opt] ')'
+/// [C++0x] braced-init-list [TODO]
+///
+Parser::OwningExprResult
+Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
+ assert(Tok.is(tok::kw_new) && "expected 'new' token");
+ ConsumeToken(); // Consume 'new'
+
+ // A '(' now can be a new-placement or the '(' wrapping the type-id in the
+ // second form of new-expression. It can't be a new-type-id.
+
+ ExprVector PlacementArgs(Actions);
+ SourceLocation PlacementLParen, PlacementRParen;
+
+ bool ParenTypeId;
+ DeclSpec DS;
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ if (Tok.is(tok::l_paren)) {
+ // If it turns out to be a placement, we change the type location.
+ PlacementLParen = ConsumeParen();
+ if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) {
+ SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ return ExprError();
+ }
+
+ PlacementRParen = MatchRHSPunctuation(tok::r_paren, PlacementLParen);
+ if (PlacementRParen.isInvalid()) {
+ SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ return ExprError();
+ }
+
+ if (PlacementArgs.empty()) {
+ // Reset the placement locations. There was no placement.
+ PlacementLParen = PlacementRParen = SourceLocation();
+ ParenTypeId = true;
+ } else {
+ // We still need the type.
+ if (Tok.is(tok::l_paren)) {
+ SourceLocation LParen = ConsumeParen();
+ ParseSpecifierQualifierList(DS);
+ DeclaratorInfo.SetSourceRange(DS.getSourceRange());
+ ParseDeclarator(DeclaratorInfo);
+ MatchRHSPunctuation(tok::r_paren, LParen);
+ ParenTypeId = true;
+ } else {
+ if (ParseCXXTypeSpecifierSeq(DS))
+ DeclaratorInfo.setInvalidType(true);
+ else {
+ DeclaratorInfo.SetSourceRange(DS.getSourceRange());
+ ParseDeclaratorInternal(DeclaratorInfo,
+ &Parser::ParseDirectNewDeclarator);
+ }
+ ParenTypeId = false;
+ }
+ }
+ } else {
+ // A new-type-id is a simplified type-id, where essentially the
+ // direct-declarator is replaced by a direct-new-declarator.
+ if (ParseCXXTypeSpecifierSeq(DS))
+ DeclaratorInfo.setInvalidType(true);
+ else {
+ DeclaratorInfo.SetSourceRange(DS.getSourceRange());
+ ParseDeclaratorInternal(DeclaratorInfo,
+ &Parser::ParseDirectNewDeclarator);
+ }
+ ParenTypeId = false;
+ }
+ if (DeclaratorInfo.isInvalidType()) {
+ SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ return ExprError();
+ }
+
+ ExprVector ConstructorArgs(Actions);
+ SourceLocation ConstructorLParen, ConstructorRParen;
+
+ if (Tok.is(tok::l_paren)) {
+ ConstructorLParen = ConsumeParen();
+ if (Tok.isNot(tok::r_paren)) {
+ CommaLocsTy CommaLocs;
+ if (ParseExpressionList(ConstructorArgs, CommaLocs)) {
+ SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ return ExprError();
+ }
+ }
+ ConstructorRParen = MatchRHSPunctuation(tok::r_paren, ConstructorLParen);
+ if (ConstructorRParen.isInvalid()) {
+ SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ return ExprError();
+ }
+ }
+
+ return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
+ move_arg(PlacementArgs), PlacementRParen,
+ ParenTypeId, DeclaratorInfo, ConstructorLParen,
+ move_arg(ConstructorArgs), ConstructorRParen);
+}
+
+/// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be
+/// passed to ParseDeclaratorInternal.
+///
+/// direct-new-declarator:
+/// '[' expression ']'
+/// direct-new-declarator '[' constant-expression ']'
+///
+void Parser::ParseDirectNewDeclarator(Declarator &D) {
+ // Parse the array dimensions.
+ bool first = true;
+ while (Tok.is(tok::l_square)) {
+ SourceLocation LLoc = ConsumeBracket();
+ OwningExprResult Size(first ? ParseExpression()
+ : ParseConstantExpression());
+ if (Size.isInvalid()) {
+ // Recover
+ SkipUntil(tok::r_square);
+ return;
+ }
+ first = false;
+
+ SourceLocation RLoc = MatchRHSPunctuation(tok::r_square, LLoc);
+ D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false,
+ Size.release(), LLoc),
+ RLoc);
+
+ if (RLoc.isInvalid())
+ return;
+ }
+}
+
+/// ParseExpressionListOrTypeId - Parse either an expression-list or a type-id.
+/// This ambiguity appears in the syntax of the C++ new operator.
+///
+/// new-expression:
+/// '::'[opt] 'new' new-placement[opt] '(' type-id ')'
+/// new-initializer[opt]
+///
+/// new-placement:
+/// '(' expression-list ')'
+///
+bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs,
+ Declarator &D) {
+ // The '(' was already consumed.
+ if (isTypeIdInParens()) {
+ ParseSpecifierQualifierList(D.getMutableDeclSpec());
+ D.SetSourceRange(D.getDeclSpec().getSourceRange());
+ ParseDeclarator(D);
+ return D.isInvalidType();
+ }
+
+ // It's not a type, it has to be an expression list.
+ // Discard the comma locations - ActOnCXXNew has enough parameters.
+ CommaLocsTy CommaLocs;
+ return ParseExpressionList(PlacementArgs, CommaLocs);
+}
+
+/// ParseCXXDeleteExpression - Parse a C++ delete-expression. Delete is used
+/// to free memory allocated by new.
+///
+/// This method is called to parse the 'delete' expression after the optional
+/// '::' has been already parsed. If the '::' was present, "UseGlobal" is true
+/// and "Start" is its location. Otherwise, "Start" is the location of the
+/// 'delete' token.
+///
+/// delete-expression:
+/// '::'[opt] 'delete' cast-expression
+/// '::'[opt] 'delete' '[' ']' cast-expression
+Parser::OwningExprResult
+Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
+ assert(Tok.is(tok::kw_delete) && "Expected 'delete' keyword");
+ ConsumeToken(); // Consume 'delete'
+
+ // Array delete?
+ bool ArrayDelete = false;
+ if (Tok.is(tok::l_square)) {
+ ArrayDelete = true;
+ SourceLocation LHS = ConsumeBracket();
+ SourceLocation RHS = MatchRHSPunctuation(tok::r_square, LHS);
+ if (RHS.isInvalid())
+ return ExprError();
+ }
+
+ OwningExprResult Operand(ParseCastExpression(false));
+ if (Operand.isInvalid())
+ return move(Operand);
+
+ return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, move(Operand));
+}
+
+static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind)
+{
+ switch(kind) {
+ default: assert(false && "Not a known unary type trait.");
+ case tok::kw___has_nothrow_assign: return UTT_HasNothrowAssign;
+ case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy;
+ case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor;
+ case tok::kw___has_trivial_assign: return UTT_HasTrivialAssign;
+ case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy;
+ case tok::kw___has_trivial_constructor: return UTT_HasTrivialConstructor;
+ case tok::kw___has_trivial_destructor: return UTT_HasTrivialDestructor;
+ case tok::kw___has_virtual_destructor: return UTT_HasVirtualDestructor;
+ case tok::kw___is_abstract: return UTT_IsAbstract;
+ case tok::kw___is_class: return UTT_IsClass;
+ case tok::kw___is_empty: return UTT_IsEmpty;
+ case tok::kw___is_enum: return UTT_IsEnum;
+ case tok::kw___is_pod: return UTT_IsPOD;
+ case tok::kw___is_polymorphic: return UTT_IsPolymorphic;
+ case tok::kw___is_union: return UTT_IsUnion;
+ }
+}
+
+/// ParseUnaryTypeTrait - Parse the built-in unary type-trait
+/// pseudo-functions that allow implementation of the TR1/C++0x type traits
+/// templates.
+///
+/// primary-expression:
+/// [GNU] unary-type-trait '(' type-id ')'
+///
+Parser::OwningExprResult Parser::ParseUnaryTypeTrait()
+{
+ UnaryTypeTrait UTT = UnaryTypeTraitFromTokKind(Tok.getKind());
+ SourceLocation Loc = ConsumeToken();
+
+ SourceLocation LParen = Tok.getLocation();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen))
+ return ExprError();
+
+ // FIXME: Error reporting absolutely sucks! If the this fails to parse a type
+ // there will be cryptic errors about mismatched parentheses and missing
+ // specifiers.
+ TypeResult Ty = ParseTypeName();
+
+ SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen);
+
+ if (Ty.isInvalid())
+ return ExprError();
+
+ return Actions.ActOnUnaryTypeTrait(UTT, Loc, LParen, Ty.get(), RParen);
+}
+
+/// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a
+/// parenthesized ambiguous type-id. This uses tentative parsing to disambiguate
+/// based on the context past the parens.
+Parser::OwningExprResult
+Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
+ TypeTy *&CastTy,
+ SourceLocation LParenLoc,
+ SourceLocation &RParenLoc) {
+ assert(getLang().CPlusPlus && "Should only be called for C++!");
+ assert(ExprType == CastExpr && "Compound literals are not ambiguous!");
+ assert(isTypeIdInParens() && "Not a type-id!");
+
+ OwningExprResult Result(Actions, true);
+ CastTy = 0;
+
+ // We need to disambiguate a very ugly part of the C++ syntax:
+ //
+ // (T())x; - type-id
+ // (T())*x; - type-id
+ // (T())/x; - expression
+ // (T()); - expression
+ //
+ // The bad news is that we cannot use the specialized tentative parser, since
+ // it can only verify that the thing inside the parens can be parsed as
+ // type-id, it is not useful for determining the context past the parens.
+ //
+ // The good news is that the parser can disambiguate this part without
+ // making any unnecessary Action calls.
+ //
+ // It uses a scheme similar to parsing inline methods. The parenthesized
+ // tokens are cached, the context that follows is determined (possibly by
+ // parsing a cast-expression), and then we re-introduce the cached tokens
+ // into the token stream and parse them appropriately.
+
+ ParenParseOption ParseAs;
+ CachedTokens Toks;
+
+ // Store the tokens of the parentheses. We will parse them after we determine
+ // the context that follows them.
+ if (!ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks, tok::semi)) {
+ // We didn't find the ')' we expected.
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ return ExprError();
+ }
+
+ if (Tok.is(tok::l_brace)) {
+ ParseAs = CompoundLiteral;
+ } else {
+ bool NotCastExpr;
+ // FIXME: Special-case ++ and --: "(S())++;" is not a cast-expression
+ if (Tok.is(tok::l_paren) && NextToken().is(tok::r_paren)) {
+ NotCastExpr = true;
+ } else {
+ // Try parsing the cast-expression that may follow.
+ // If it is not a cast-expression, NotCastExpr will be true and no token
+ // will be consumed.
+ Result = ParseCastExpression(false/*isUnaryExpression*/,
+ false/*isAddressofOperand*/,
+ NotCastExpr);
+ }
+
+ // If we parsed a cast-expression, it's really a type-id, otherwise it's
+ // an expression.
+ ParseAs = NotCastExpr ? SimpleExpr : CastExpr;
+ }
+
+ // The current token should go after the cached tokens.
+ Toks.push_back(Tok);
+ // Re-enter the stored parenthesized tokens into the token stream, so we may
+ // parse them now.
+ PP.EnterTokenStream(Toks.data(), Toks.size(),
+ true/*DisableMacroExpansion*/, false/*OwnsTokens*/);
+ // Drop the current token and bring the first cached one. It's the same token
+ // as when we entered this function.
+ ConsumeAnyToken();
+
+ if (ParseAs >= CompoundLiteral) {
+ TypeResult Ty = ParseTypeName();
+
+ // Match the ')'.
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ if (ParseAs == CompoundLiteral) {
+ ExprType = CompoundLiteral;
+ return ParseCompoundLiteralExpression(Ty.get(), LParenLoc, RParenLoc);
+ }
+
+ // We parsed '(' type-id ')' and the thing after it wasn't a '{'.
+ assert(ParseAs == CastExpr);
+
+ if (Ty.isInvalid())
+ return ExprError();
+
+ CastTy = Ty.get();
+
+ // Result is what ParseCastExpression returned earlier.
+ if (!Result.isInvalid())
+ Result = Actions.ActOnCastExpr(LParenLoc, CastTy, RParenLoc,move(Result));
+ return move(Result);
+ }
+
+ // Not a compound literal, and not followed by a cast-expression.
+ assert(ParseAs == SimpleExpr);
+
+ ExprType = SimpleExpr;
+ Result = ParseExpression();
+ if (!Result.isInvalid() && Tok.is(tok::r_paren))
+ Result = Actions.ActOnParenExpr(LParenLoc, Tok.getLocation(), move(Result));
+
+ // Match the ')'.
+ if (Result.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ return move(Result);
+}
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
new file mode 100644
index 000000000000..bbc2124e5986
--- /dev/null
+++ b/lib/Parse/ParseInit.cpp
@@ -0,0 +1,308 @@
+//===--- ParseInit.cpp - Initializer Parsing ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements initializer parsing as specified by C99 6.7.8.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Designator.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "llvm/ADT/SmallString.h"
+using namespace clang;
+
+
+/// MayBeDesignationStart - Return true if this token might be the start of a
+/// designator. If we can tell it is impossible that it is a designator, return
+/// false.
+static bool MayBeDesignationStart(tok::TokenKind K, Preprocessor &PP) {
+ switch (K) {
+ default: return false;
+ case tok::period: // designator: '.' identifier
+ case tok::l_square: // designator: array-designator
+ return true;
+ case tok::identifier: // designation: identifier ':'
+ return PP.LookAhead(0).is(tok::colon);
+ }
+}
+
+/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
+/// checking to see if the token stream starts with a designator.
+///
+/// designation:
+/// designator-list '='
+/// [GNU] array-designator
+/// [GNU] identifier ':'
+///
+/// designator-list:
+/// designator
+/// designator-list designator
+///
+/// designator:
+/// array-designator
+/// '.' identifier
+///
+/// array-designator:
+/// '[' constant-expression ']'
+/// [GNU] '[' constant-expression '...' constant-expression ']'
+///
+/// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an
+/// initializer (because it is an expression). We need to consider this case
+/// when parsing array designators.
+///
+Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
+
+ // If this is the old-style GNU extension:
+ // designation ::= identifier ':'
+ // Handle it as a field designator. Otherwise, this must be the start of a
+ // normal expression.
+ if (Tok.is(tok::identifier)) {
+ const IdentifierInfo *FieldName = Tok.getIdentifierInfo();
+
+ std::string NewSyntax(".");
+ NewSyntax += FieldName->getName();
+ NewSyntax += " = ";
+
+ SourceLocation NameLoc = ConsumeToken(); // Eat the identifier.
+
+ assert(Tok.is(tok::colon) && "MayBeDesignationStart not working properly!");
+ SourceLocation ColonLoc = ConsumeToken();
+
+ Diag(Tok, diag::ext_gnu_old_style_field_designator)
+ << CodeModificationHint::CreateReplacement(SourceRange(NameLoc,
+ ColonLoc),
+ NewSyntax);
+
+ Designation D;
+ D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc));
+ return Actions.ActOnDesignatedInitializer(D, ColonLoc, true,
+ ParseInitializer());
+ }
+
+ // Desig - This is initialized when we see our first designator. We may have
+ // an objc message send with no designator, so we don't want to create this
+ // eagerly.
+ Designation Desig;
+
+ // Parse each designator in the designator list until we find an initializer.
+ while (Tok.is(tok::period) || Tok.is(tok::l_square)) {
+ if (Tok.is(tok::period)) {
+ // designator: '.' identifier
+ SourceLocation DotLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_expected_field_designator);
+ return ExprError();
+ }
+
+ Desig.AddDesignator(Designator::getField(Tok.getIdentifierInfo(), DotLoc,
+ Tok.getLocation()));
+ ConsumeToken(); // Eat the identifier.
+ continue;
+ }
+
+ // We must have either an array designator now or an objc message send.
+ assert(Tok.is(tok::l_square) && "Unexpected token!");
+
+ // Handle the two forms of array designator:
+ // array-designator: '[' constant-expression ']'
+ // array-designator: '[' constant-expression '...' constant-expression ']'
+ //
+ // Also, we have to handle the case where the expression after the
+ // designator an an objc message send: '[' objc-message-expr ']'.
+ // Interesting cases are:
+ // [foo bar] -> objc message send
+ // [foo] -> array designator
+ // [foo ... bar] -> array designator
+ // [4][foo bar] -> obsolete GNU designation with objc message send.
+ //
+ SourceLocation StartLoc = ConsumeBracket();
+
+ // If Objective-C is enabled and this is a typename or other identifier
+ // receiver, parse this as a message send expression.
+ if (getLang().ObjC1 && isTokObjCMessageIdentifierReceiver()) {
+ // If we have exactly one array designator, this used the GNU
+ // 'designation: array-designator' extension, otherwise there should be no
+ // designators at all!
+ if (Desig.getNumDesignators() == 1 &&
+ (Desig.getDesignator(0).isArrayDesignator() ||
+ Desig.getDesignator(0).isArrayRangeDesignator()))
+ Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
+ else if (Desig.getNumDesignators() > 0)
+ Diag(Tok, diag::err_expected_equal_designator);
+
+ IdentifierInfo *Name = Tok.getIdentifierInfo();
+ SourceLocation NameLoc = ConsumeToken();
+ return ParseAssignmentExprWithObjCMessageExprStart(
+ StartLoc, NameLoc, Name, ExprArg(Actions));
+ }
+
+ // Note that we parse this as an assignment expression, not a constant
+ // expression (allowing *=, =, etc) to handle the objc case. Sema needs
+ // to validate that the expression is a constant.
+ OwningExprResult Idx(ParseAssignmentExpression());
+ if (Idx.isInvalid()) {
+ SkipUntil(tok::r_square);
+ return move(Idx);
+ }
+
+ // Given an expression, we could either have a designator (if the next
+ // tokens are '...' or ']' or an objc message send. If this is an objc
+ // message send, handle it now. An objc-message send is the start of
+ // an assignment-expression production.
+ if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) &&
+ Tok.isNot(tok::r_square)) {
+
+ // If we have exactly one array designator, this used the GNU
+ // 'designation: array-designator' extension, otherwise there should be no
+ // designators at all!
+ if (Desig.getNumDesignators() == 1 &&
+ (Desig.getDesignator(0).isArrayDesignator() ||
+ Desig.getDesignator(0).isArrayRangeDesignator()))
+ Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
+ else if (Desig.getNumDesignators() > 0)
+ Diag(Tok, diag::err_expected_equal_designator);
+
+ return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
+ SourceLocation(),
+ 0, move(Idx));
+ }
+
+ // If this is a normal array designator, remember it.
+ if (Tok.isNot(tok::ellipsis)) {
+ Desig.AddDesignator(Designator::getArray(Idx.release(), StartLoc));
+ } else {
+ // Handle the gnu array range extension.
+ Diag(Tok, diag::ext_gnu_array_range);
+ SourceLocation EllipsisLoc = ConsumeToken();
+
+ OwningExprResult RHS(ParseConstantExpression());
+ if (RHS.isInvalid()) {
+ SkipUntil(tok::r_square);
+ return move(RHS);
+ }
+ Desig.AddDesignator(Designator::getArrayRange(Idx.release(),
+ RHS.release(),
+ StartLoc, EllipsisLoc));
+ }
+
+ SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+ Desig.getDesignator(Desig.getNumDesignators() - 1).setRBracketLoc(EndLoc);
+ }
+
+ // Okay, we're done with the designator sequence. We know that there must be
+ // at least one designator, because the only case we can get into this method
+ // without a designator is when we have an objc message send. That case is
+ // handled and returned from above.
+ assert(!Desig.empty() && "Designator is empty?");
+
+ // Handle a normal designator sequence end, which is an equal.
+ if (Tok.is(tok::equal)) {
+ SourceLocation EqualLoc = ConsumeToken();
+ return Actions.ActOnDesignatedInitializer(Desig, EqualLoc, false,
+ ParseInitializer());
+ }
+
+ // We read some number of designators and found something that isn't an = or
+ // an initializer. If we have exactly one array designator, this
+ // is the GNU 'designation: array-designator' extension. Otherwise, it is a
+ // parse error.
+ if (Desig.getNumDesignators() == 1 &&
+ (Desig.getDesignator(0).isArrayDesignator() ||
+ Desig.getDesignator(0).isArrayRangeDesignator())) {
+ Diag(Tok, diag::ext_gnu_missing_equal_designator)
+ << CodeModificationHint::CreateInsertion(Tok.getLocation(), "= ");
+ return Actions.ActOnDesignatedInitializer(Desig, Tok.getLocation(),
+ true, ParseInitializer());
+ }
+
+ Diag(Tok, diag::err_expected_equal_designator);
+ return ExprError();
+}
+
+
+/// ParseBraceInitializer - Called when parsing an initializer that has a
+/// leading open brace.
+///
+/// initializer: [C99 6.7.8]
+/// '{' initializer-list '}'
+/// '{' initializer-list ',' '}'
+/// [GNU] '{' '}'
+///
+/// initializer-list:
+/// designation[opt] initializer
+/// initializer-list ',' designation[opt] initializer
+///
+Parser::OwningExprResult Parser::ParseBraceInitializer() {
+ SourceLocation LBraceLoc = ConsumeBrace();
+
+ /// InitExprs - This is the actual list of expressions contained in the
+ /// initializer.
+ ExprVector InitExprs(Actions);
+
+ if (Tok.is(tok::r_brace)) {
+ // Empty initializers are a C++ feature and a GNU extension to C.
+ if (!getLang().CPlusPlus)
+ Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
+ // Match the '}'.
+ return Actions.ActOnInitList(LBraceLoc, Action::MultiExprArg(Actions),
+ ConsumeBrace());
+ }
+
+ bool InitExprsOk = true;
+
+ while (1) {
+ // Parse: designation[opt] initializer
+
+ // If we know that this cannot be a designation, just parse the nested
+ // initializer directly.
+ OwningExprResult SubElt(Actions);
+ if (MayBeDesignationStart(Tok.getKind(), PP))
+ SubElt = ParseInitializerWithPotentialDesignator();
+ else
+ SubElt = ParseInitializer();
+
+ // If we couldn't parse the subelement, bail out.
+ if (!SubElt.isInvalid()) {
+ InitExprs.push_back(SubElt.release());
+ } else {
+ InitExprsOk = false;
+
+ // We have two ways to try to recover from this error: if the code looks
+ // gramatically ok (i.e. we have a comma coming up) try to continue
+ // parsing the rest of the initializer. This allows us to emit
+ // diagnostics for later elements that we find. If we don't see a comma,
+ // assume there is a parse error, and just skip to recover.
+ // FIXME: This comment doesn't sound right. If there is a r_brace
+ // immediately, it can't be an error, since there is no other way of
+ // leaving this loop except through this if.
+ if (Tok.isNot(tok::comma)) {
+ SkipUntil(tok::r_brace, false, true);
+ break;
+ }
+ }
+
+ // If we don't have a comma continued list, we're done.
+ if (Tok.isNot(tok::comma)) break;
+
+ // TODO: save comma locations if some client cares.
+ ConsumeToken();
+
+ // Handle trailing comma.
+ if (Tok.is(tok::r_brace)) break;
+ }
+ if (InitExprsOk && Tok.is(tok::r_brace))
+ return Actions.ActOnInitList(LBraceLoc, move_arg(InitExprs),
+ ConsumeBrace());
+
+ // Match the '}'.
+ MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+ return ExprError(); // an error occurred.
+}
+
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
new file mode 100644
index 000000000000..3014f95a8482
--- /dev/null
+++ b/lib/Parse/ParseObjc.cpp
@@ -0,0 +1,1708 @@
+//===--- ParseObjC.cpp - Objective C Parsing ------------------------------===//
+//
+// 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 Objective-C portions of the Parser interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "llvm/ADT/SmallVector.h"
+using namespace clang;
+
+
+/// ParseObjCAtDirectives - Handle parts of the external-declaration production:
+/// external-declaration: [C99 6.9]
+/// [OBJC] objc-class-definition
+/// [OBJC] objc-class-declaration
+/// [OBJC] objc-alias-declaration
+/// [OBJC] objc-protocol-definition
+/// [OBJC] objc-method-definition
+/// [OBJC] '@' 'end'
+Parser::DeclPtrTy Parser::ParseObjCAtDirectives() {
+ SourceLocation AtLoc = ConsumeToken(); // the "@"
+
+ switch (Tok.getObjCKeywordID()) {
+ case tok::objc_class:
+ return ParseObjCAtClassDeclaration(AtLoc);
+ case tok::objc_interface:
+ return ParseObjCAtInterfaceDeclaration(AtLoc);
+ case tok::objc_protocol:
+ return ParseObjCAtProtocolDeclaration(AtLoc);
+ case tok::objc_implementation:
+ return ParseObjCAtImplementationDeclaration(AtLoc);
+ case tok::objc_end:
+ return ParseObjCAtEndDeclaration(AtLoc);
+ case tok::objc_compatibility_alias:
+ return ParseObjCAtAliasDeclaration(AtLoc);
+ case tok::objc_synthesize:
+ return ParseObjCPropertySynthesize(AtLoc);
+ case tok::objc_dynamic:
+ return ParseObjCPropertyDynamic(AtLoc);
+ default:
+ Diag(AtLoc, diag::err_unexpected_at);
+ SkipUntil(tok::semi);
+ return DeclPtrTy();
+ }
+}
+
+///
+/// objc-class-declaration:
+/// '@' 'class' identifier-list ';'
+///
+Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
+ ConsumeToken(); // the identifier "class"
+ llvm::SmallVector<IdentifierInfo *, 8> ClassNames;
+
+ while (1) {
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::semi);
+ return DeclPtrTy();
+ }
+ ClassNames.push_back(Tok.getIdentifierInfo());
+ ConsumeToken();
+
+ if (Tok.isNot(tok::comma))
+ break;
+
+ ConsumeToken();
+ }
+
+ // Consume the ';'.
+ if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
+ return DeclPtrTy();
+
+ return Actions.ActOnForwardClassDeclaration(atLoc,
+ &ClassNames[0], ClassNames.size());
+}
+
+///
+/// objc-interface:
+/// objc-class-interface-attributes[opt] objc-class-interface
+/// objc-category-interface
+///
+/// objc-class-interface:
+/// '@' 'interface' identifier objc-superclass[opt]
+/// objc-protocol-refs[opt]
+/// objc-class-instance-variables[opt]
+/// objc-interface-decl-list
+/// @end
+///
+/// objc-category-interface:
+/// '@' 'interface' identifier '(' identifier[opt] ')'
+/// objc-protocol-refs[opt]
+/// objc-interface-decl-list
+/// @end
+///
+/// objc-superclass:
+/// ':' identifier
+///
+/// objc-class-interface-attributes:
+/// __attribute__((visibility("default")))
+/// __attribute__((visibility("hidden")))
+/// __attribute__((deprecated))
+/// __attribute__((unavailable))
+/// __attribute__((objc_exception)) - used by NSException on 64-bit
+///
+Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
+ SourceLocation atLoc, AttributeList *attrList) {
+ assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
+ "ParseObjCAtInterfaceDeclaration(): Expected @interface");
+ ConsumeToken(); // the "interface" identifier
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident); // missing class or category name.
+ return DeclPtrTy();
+ }
+ // We have a class or category name - consume it.
+ IdentifierInfo *nameId = Tok.getIdentifierInfo();
+ SourceLocation nameLoc = ConsumeToken();
+
+ if (Tok.is(tok::l_paren)) { // we have a category.
+ SourceLocation lparenLoc = ConsumeParen();
+ SourceLocation categoryLoc, rparenLoc;
+ IdentifierInfo *categoryId = 0;
+
+ // For ObjC2, the category name is optional (not an error).
+ if (Tok.is(tok::identifier)) {
+ categoryId = Tok.getIdentifierInfo();
+ categoryLoc = ConsumeToken();
+ } else if (!getLang().ObjC2) {
+ Diag(Tok, diag::err_expected_ident); // missing category name.
+ return DeclPtrTy();
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected_rparen);
+ SkipUntil(tok::r_paren, false); // don't stop at ';'
+ return DeclPtrTy();
+ }
+ rparenLoc = ConsumeParen();
+
+ // Next, we need to check for any protocol references.
+ SourceLocation EndProtoLoc;
+ llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs;
+ if (Tok.is(tok::less) &&
+ ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc))
+ return DeclPtrTy();
+
+ if (attrList) // categories don't support attributes.
+ Diag(Tok, diag::err_objc_no_attributes_on_category);
+
+ DeclPtrTy CategoryType =
+ Actions.ActOnStartCategoryInterface(atLoc,
+ nameId, nameLoc,
+ categoryId, categoryLoc,
+ ProtocolRefs.data(),
+ ProtocolRefs.size(),
+ EndProtoLoc);
+
+ ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword);
+ return CategoryType;
+ }
+ // Parse a class interface.
+ IdentifierInfo *superClassId = 0;
+ SourceLocation superClassLoc;
+
+ if (Tok.is(tok::colon)) { // a super class is specified.
+ ConsumeToken();
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident); // missing super class name.
+ return DeclPtrTy();
+ }
+ superClassId = Tok.getIdentifierInfo();
+ superClassLoc = ConsumeToken();
+ }
+ // Next, we need to check for any protocol references.
+ llvm::SmallVector<Action::DeclPtrTy, 8> ProtocolRefs;
+ SourceLocation EndProtoLoc;
+ if (Tok.is(tok::less) &&
+ ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc))
+ return DeclPtrTy();
+
+ DeclPtrTy ClsType =
+ Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc,
+ superClassId, superClassLoc,
+ ProtocolRefs.data(), ProtocolRefs.size(),
+ EndProtoLoc, attrList);
+
+ if (Tok.is(tok::l_brace))
+ ParseObjCClassInstanceVariables(ClsType, atLoc);
+
+ ParseObjCInterfaceDeclList(ClsType, tok::objc_interface);
+ return ClsType;
+}
+
+/// objc-interface-decl-list:
+/// empty
+/// objc-interface-decl-list objc-property-decl [OBJC2]
+/// objc-interface-decl-list objc-method-requirement [OBJC2]
+/// objc-interface-decl-list objc-method-proto ';'
+/// objc-interface-decl-list declaration
+/// objc-interface-decl-list ';'
+///
+/// objc-method-requirement: [OBJC2]
+/// @required
+/// @optional
+///
+void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
+ tok::ObjCKeywordKind contextKey) {
+ llvm::SmallVector<DeclPtrTy, 32> allMethods;
+ llvm::SmallVector<DeclPtrTy, 16> allProperties;
+ llvm::SmallVector<DeclGroupPtrTy, 8> allTUVariables;
+ tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
+
+ SourceLocation AtEndLoc;
+
+ while (1) {
+ // If this is a method prototype, parse it.
+ if (Tok.is(tok::minus) || Tok.is(tok::plus)) {
+ DeclPtrTy methodPrototype =
+ ParseObjCMethodPrototype(interfaceDecl, MethodImplKind);
+ allMethods.push_back(methodPrototype);
+ // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
+ // method definitions.
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_method_proto,
+ "", tok::semi);
+ continue;
+ }
+
+ // Ignore excess semicolons.
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ continue;
+ }
+
+ // If we got to the end of the file, exit the loop.
+ if (Tok.is(tok::eof))
+ break;
+
+ // If we don't have an @ directive, parse it as a function definition.
+ if (Tok.isNot(tok::at)) {
+ // The code below does not consume '}'s because it is afraid of eating the
+ // end of a namespace. Because of the way this code is structured, an
+ // 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.
+ allTUVariables.push_back(ParseDeclarationOrFunctionDefinition());
+ continue;
+ }
+
+ // Otherwise, we have an @ directive, eat the @.
+ SourceLocation AtLoc = ConsumeToken(); // the "@"
+ tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
+
+ if (DirectiveKind == tok::objc_end) { // @end -> terminate list
+ AtEndLoc = AtLoc;
+ break;
+ }
+
+ // Eat the identifier.
+ ConsumeToken();
+
+ switch (DirectiveKind) {
+ default:
+ // FIXME: If someone forgets an @end on a protocol, this loop will
+ // continue to eat up tons of stuff and spew lots of nonsense errors. It
+ // would probably be better to bail out if we saw an @class or @interface
+ // or something like that.
+ Diag(AtLoc, diag::err_objc_illegal_interface_qual);
+ // Skip until we see an '@' or '}' or ';'.
+ SkipUntil(tok::r_brace, tok::at);
+ break;
+
+ case tok::objc_required:
+ case tok::objc_optional:
+ // This is only valid on protocols.
+ // FIXME: Should this check for ObjC2 being enabled?
+ if (contextKey != tok::objc_protocol)
+ Diag(AtLoc, diag::err_objc_directive_only_in_protocol);
+ else
+ MethodImplKind = DirectiveKind;
+ break;
+
+ case tok::objc_property:
+ if (!getLang().ObjC2)
+ Diag(AtLoc, diag::err_objc_propertoes_require_objc2);
+
+ ObjCDeclSpec OCDS;
+ // Parse property attribute list, if any.
+ if (Tok.is(tok::l_paren))
+ ParseObjCPropertyAttribute(OCDS);
+
+ // Parse all the comma separated declarators.
+ DeclSpec DS;
+ llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators;
+ ParseStructDeclaration(DS, FieldDeclarators);
+
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list, "",
+ tok::at);
+
+ // Convert them all to property declarations.
+ for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) {
+ FieldDeclarator &FD = FieldDeclarators[i];
+ if (FD.D.getIdentifier() == 0) {
+ Diag(AtLoc, diag::err_objc_property_requires_field_name)
+ << FD.D.getSourceRange();
+ continue;
+ }
+ if (FD.BitfieldSize) {
+ Diag(AtLoc, diag::err_objc_property_bitfield)
+ << FD.D.getSourceRange();
+ continue;
+ }
+
+ // Install the property declarator into interfaceDecl.
+ IdentifierInfo *SelName =
+ OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
+
+ Selector GetterSel =
+ PP.getSelectorTable().getNullarySelector(SelName);
+ IdentifierInfo *SetterName = OCDS.getSetterName();
+ Selector SetterSel;
+ if (SetterName)
+ SetterSel = PP.getSelectorTable().getSelector(1, &SetterName);
+ else
+ SetterSel = SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(),
+ FD.D.getIdentifier());
+ bool isOverridingProperty = false;
+ DeclPtrTy Property = Actions.ActOnProperty(CurScope, AtLoc, FD, OCDS,
+ GetterSel, SetterSel,
+ interfaceDecl,
+ &isOverridingProperty,
+ MethodImplKind);
+ if (!isOverridingProperty)
+ allProperties.push_back(Property);
+ }
+ break;
+ }
+ }
+
+ // 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.isObjCAtKeyword(tok::objc_end))
+ ConsumeToken(); // the "end" identifier
+ else
+ Diag(Tok, diag::err_objc_missing_end);
+
+ // Insert collected methods declarations into the @interface object.
+ // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
+ Actions.ActOnAtEnd(AtEndLoc, interfaceDecl,
+ allMethods.data(), allMethods.size(),
+ allProperties.data(), allProperties.size(),
+ allTUVariables.data(), allTUVariables.size());
+}
+
+/// Parse property attribute declarations.
+///
+/// property-attr-decl: '(' property-attrlist ')'
+/// property-attrlist:
+/// property-attribute
+/// property-attrlist ',' property-attribute
+/// property-attribute:
+/// getter '=' identifier
+/// setter '=' identifier ':'
+/// readonly
+/// readwrite
+/// assign
+/// retain
+/// copy
+/// nonatomic
+///
+void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
+ assert(Tok.getKind() == tok::l_paren);
+ SourceLocation LHSLoc = ConsumeParen(); // consume '('
+
+ while (1) {
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+
+ // If this is not an identifier at all, bail out early.
+ if (II == 0) {
+ MatchRHSPunctuation(tok::r_paren, LHSLoc);
+ return;
+ }
+
+ SourceLocation AttrName = ConsumeToken(); // consume last attribute name
+
+ if (II->isStr("readonly"))
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readonly);
+ else if (II->isStr("assign"))
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_assign);
+ else if (II->isStr("readwrite"))
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readwrite);
+ else if (II->isStr("retain"))
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_retain);
+ else if (II->isStr("copy"))
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy);
+ else if (II->isStr("nonatomic"))
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic);
+ else if (II->isStr("getter") || II->isStr("setter")) {
+ // getter/setter require extra treatment.
+ if (ExpectAndConsume(tok::equal, diag::err_objc_expected_equal, "",
+ tok::r_paren))
+ return;
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ if (II->getName()[0] == 's') {
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter);
+ DS.setSetterName(Tok.getIdentifierInfo());
+ ConsumeToken(); // consume method name
+
+ if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "",
+ tok::r_paren))
+ return;
+ } else {
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter);
+ DS.setGetterName(Tok.getIdentifierInfo());
+ ConsumeToken(); // consume method name
+ }
+ } else {
+ Diag(AttrName, diag::err_objc_expected_property_attr) << II;
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ if (Tok.isNot(tok::comma))
+ break;
+
+ ConsumeToken();
+ }
+
+ MatchRHSPunctuation(tok::r_paren, LHSLoc);
+}
+
+/// objc-method-proto:
+/// objc-instance-method objc-method-decl objc-method-attributes[opt]
+/// objc-class-method objc-method-decl objc-method-attributes[opt]
+///
+/// objc-instance-method: '-'
+/// objc-class-method: '+'
+///
+/// objc-method-attributes: [OBJC2]
+/// __attribute__((deprecated))
+///
+Parser::DeclPtrTy Parser::ParseObjCMethodPrototype(DeclPtrTy IDecl,
+ tok::ObjCKeywordKind MethodImplKind) {
+ assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-");
+
+ tok::TokenKind methodType = Tok.getKind();
+ SourceLocation mLoc = ConsumeToken();
+
+ DeclPtrTy MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl,MethodImplKind);
+ // Since this rule is used for both method declarations and definitions,
+ // the caller is (optionally) responsible for consuming the ';'.
+ return MDecl;
+}
+
+/// objc-selector:
+/// identifier
+/// one of
+/// enum struct union if else while do for switch case default
+/// break continue return goto asm sizeof typeof __alignof
+/// unsigned long const short volatile signed restrict _Complex
+/// in out inout bycopy byref oneway int char float double void _Bool
+///
+IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
+ switch (Tok.getKind()) {
+ default:
+ return 0;
+ case tok::identifier:
+ case tok::kw_asm:
+ case tok::kw_auto:
+ case tok::kw_bool:
+ case tok::kw_break:
+ case tok::kw_case:
+ case tok::kw_catch:
+ case tok::kw_char:
+ case tok::kw_class:
+ case tok::kw_const:
+ case tok::kw_const_cast:
+ case tok::kw_continue:
+ case tok::kw_default:
+ case tok::kw_delete:
+ case tok::kw_do:
+ case tok::kw_double:
+ case tok::kw_dynamic_cast:
+ case tok::kw_else:
+ case tok::kw_enum:
+ case tok::kw_explicit:
+ case tok::kw_export:
+ case tok::kw_extern:
+ case tok::kw_false:
+ case tok::kw_float:
+ case tok::kw_for:
+ case tok::kw_friend:
+ case tok::kw_goto:
+ case tok::kw_if:
+ case tok::kw_inline:
+ case tok::kw_int:
+ case tok::kw_long:
+ case tok::kw_mutable:
+ case tok::kw_namespace:
+ case tok::kw_new:
+ case tok::kw_operator:
+ case tok::kw_private:
+ case tok::kw_protected:
+ case tok::kw_public:
+ case tok::kw_register:
+ case tok::kw_reinterpret_cast:
+ case tok::kw_restrict:
+ case tok::kw_return:
+ case tok::kw_short:
+ case tok::kw_signed:
+ case tok::kw_sizeof:
+ case tok::kw_static:
+ case tok::kw_static_cast:
+ case tok::kw_struct:
+ case tok::kw_switch:
+ case tok::kw_template:
+ case tok::kw_this:
+ case tok::kw_throw:
+ case tok::kw_true:
+ case tok::kw_try:
+ case tok::kw_typedef:
+ case tok::kw_typeid:
+ case tok::kw_typename:
+ case tok::kw_typeof:
+ case tok::kw_union:
+ case tok::kw_unsigned:
+ case tok::kw_using:
+ case tok::kw_virtual:
+ case tok::kw_void:
+ case tok::kw_volatile:
+ case tok::kw_wchar_t:
+ case tok::kw_while:
+ case tok::kw__Bool:
+ case tok::kw__Complex:
+ case tok::kw___alignof:
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ SelectorLoc = ConsumeToken();
+ return II;
+ }
+}
+
+/// objc-for-collection-in: 'in'
+///
+bool Parser::isTokIdentifier_in() const {
+ // FIXME: May have to do additional look-ahead to only allow for
+ // valid tokens following an 'in'; such as an identifier, unary operators,
+ // '[' etc.
+ return (getLang().ObjC2 && Tok.is(tok::identifier) &&
+ Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]);
+}
+
+/// ParseObjCTypeQualifierList - This routine parses the objective-c's type
+/// qualifier list and builds their bitmask representation in the input
+/// argument.
+///
+/// objc-type-qualifiers:
+/// objc-type-qualifier
+/// objc-type-qualifiers objc-type-qualifier
+///
+void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) {
+ while (1) {
+ if (Tok.isNot(tok::identifier))
+ return;
+
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ for (unsigned i = 0; i != objc_NumQuals; ++i) {
+ if (II != ObjCTypeQuals[i])
+ continue;
+
+ ObjCDeclSpec::ObjCDeclQualifier Qual;
+ switch (i) {
+ default: assert(0 && "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;
+ case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break;
+ case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break;
+ case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break;
+ }
+ DS.setObjCDeclQualifier(Qual);
+ ConsumeToken();
+ II = 0;
+ break;
+ }
+
+ // If this wasn't a recognized qualifier, bail out.
+ if (II) return;
+ }
+}
+
+/// objc-type-name:
+/// '(' objc-type-qualifiers[opt] type-name ')'
+/// '(' objc-type-qualifiers[opt] ')'
+///
+Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) {
+ assert(Tok.is(tok::l_paren) && "expected (");
+
+ SourceLocation LParenLoc = ConsumeParen();
+ SourceLocation TypeStartLoc = Tok.getLocation();
+
+ // Parse type qualifiers, in, inout, etc.
+ ParseObjCTypeQualifierList(DS);
+
+ TypeTy *Ty = 0;
+ if (isTypeSpecifierQualifier()) {
+ TypeResult TypeSpec = ParseTypeName();
+ if (!TypeSpec.isInvalid())
+ Ty = TypeSpec.get();
+ }
+
+ if (Tok.is(tok::r_paren))
+ ConsumeParen();
+ else if (Tok.getLocation() == TypeStartLoc) {
+ // If we didn't eat any tokens, then this isn't a type.
+ Diag(Tok, diag::err_expected_type);
+ SkipUntil(tok::r_paren);
+ } 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);
+ }
+ return Ty;
+}
+
+/// objc-method-decl:
+/// objc-selector
+/// objc-keyword-selector objc-parmlist[opt]
+/// objc-type-name objc-selector
+/// objc-type-name objc-keyword-selector objc-parmlist[opt]
+///
+/// objc-keyword-selector:
+/// objc-keyword-decl
+/// objc-keyword-selector objc-keyword-decl
+///
+/// objc-keyword-decl:
+/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
+/// objc-selector ':' objc-keyword-attributes[opt] identifier
+/// ':' objc-type-name objc-keyword-attributes[opt] identifier
+/// ':' objc-keyword-attributes[opt] identifier
+///
+/// objc-parmlist:
+/// objc-parms objc-ellipsis[opt]
+///
+/// objc-parms:
+/// objc-parms , parameter-declaration
+///
+/// objc-ellipsis:
+/// , ...
+///
+/// objc-keyword-attributes: [OBJC2]
+/// __attribute__((unused))
+///
+Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
+ tok::TokenKind mType,
+ DeclPtrTy IDecl,
+ tok::ObjCKeywordKind MethodImplKind) {
+ // Parse the return type if present.
+ TypeTy *ReturnType = 0;
+ ObjCDeclSpec DSRet;
+ if (Tok.is(tok::l_paren))
+ ReturnType = ParseObjCTypeName(DSRet);
+
+ SourceLocation selLoc;
+ IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);
+
+ // An unnamed colon is valid.
+ if (!SelIdent && Tok.isNot(tok::colon)) { // missing selector name.
+ Diag(Tok, diag::err_expected_selector_for_method)
+ << SourceRange(mLoc, Tok.getLocation());
+ // Skip until we get a ; or {}.
+ SkipUntil(tok::r_brace);
+ return DeclPtrTy();
+ }
+
+ llvm::SmallVector<Declarator, 8> CargNames;
+ if (Tok.isNot(tok::colon)) {
+ // If attributes exist after the method, parse them.
+ AttributeList *MethodAttrs = 0;
+ if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
+ MethodAttrs = ParseAttributes();
+
+ Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
+ return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
+ mType, IDecl, DSRet, ReturnType, Sel,
+ 0, CargNames, MethodAttrs,
+ MethodImplKind);
+ }
+
+ llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
+ llvm::SmallVector<Action::ObjCArgInfo, 12> ArgInfos;
+
+ while (1) {
+ Action::ObjCArgInfo ArgInfo;
+
+ // Each iteration parses a single keyword argument.
+ if (Tok.isNot(tok::colon)) {
+ Diag(Tok, diag::err_expected_colon);
+ break;
+ }
+ ConsumeToken(); // Eat the ':'.
+
+ ArgInfo.Type = 0;
+ if (Tok.is(tok::l_paren)) // Parse the argument type if present.
+ ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec);
+
+ // If attributes exist before the argument name, parse them.
+ ArgInfo.ArgAttrs = 0;
+ if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
+ ArgInfo.ArgAttrs = ParseAttributes();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident); // missing argument name.
+ break;
+ }
+
+ ArgInfo.Name = Tok.getIdentifierInfo();
+ ArgInfo.NameLoc = Tok.getLocation();
+ ConsumeToken(); // Eat the identifier.
+
+ ArgInfos.push_back(ArgInfo);
+ KeyIdents.push_back(SelIdent);
+
+ // Check for another keyword selector.
+ SourceLocation Loc;
+ SelIdent = ParseObjCSelectorPiece(Loc);
+ if (!SelIdent && Tok.isNot(tok::colon))
+ break;
+ // We have a selector or a colon, continue parsing.
+ }
+
+ bool isVariadic = false;
+
+ // Parse the (optional) parameter list.
+ while (Tok.is(tok::comma)) {
+ ConsumeToken();
+ if (Tok.is(tok::ellipsis)) {
+ isVariadic = true;
+ ConsumeToken();
+ break;
+ }
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS);
+ // Parse the declarator.
+ Declarator ParmDecl(DS, Declarator::PrototypeContext);
+ ParseDeclarator(ParmDecl);
+ CargNames.push_back(ParmDecl);
+ }
+
+ // FIXME: Add support for optional parmameter list...
+ // If attributes exist after the method, parse them.
+ AttributeList *MethodAttrs = 0;
+ if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
+ MethodAttrs = ParseAttributes();
+
+ Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
+ &KeyIdents[0]);
+ return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
+ mType, IDecl, DSRet, ReturnType, Sel,
+ &ArgInfos[0], CargNames, MethodAttrs,
+ MethodImplKind, isVariadic);
+}
+
+/// objc-protocol-refs:
+/// '<' identifier-list '>'
+///
+bool Parser::
+ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols,
+ bool WarnOnDeclarations, SourceLocation &EndLoc) {
+ assert(Tok.is(tok::less) && "expected <");
+
+ ConsumeToken(); // the "<"
+
+ llvm::SmallVector<IdentifierLocPair, 8> ProtocolIdents;
+
+ while (1) {
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::greater);
+ return true;
+ }
+ ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(),
+ Tok.getLocation()));
+ ConsumeToken();
+
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken();
+ }
+
+ // Consume the '>'.
+ if (Tok.isNot(tok::greater)) {
+ Diag(Tok, diag::err_expected_greater);
+ return true;
+ }
+
+ EndLoc = ConsumeAnyToken();
+
+ // Convert the list of protocols identifiers into a list of protocol decls.
+ Actions.FindProtocolDeclaration(WarnOnDeclarations,
+ &ProtocolIdents[0], ProtocolIdents.size(),
+ Protocols);
+ return false;
+}
+
+/// objc-class-instance-variables:
+/// '{' objc-instance-variable-decl-list[opt] '}'
+///
+/// objc-instance-variable-decl-list:
+/// objc-visibility-spec
+/// objc-instance-variable-decl ';'
+/// ';'
+/// objc-instance-variable-decl-list objc-visibility-spec
+/// objc-instance-variable-decl-list objc-instance-variable-decl ';'
+/// objc-instance-variable-decl-list ';'
+///
+/// objc-visibility-spec:
+/// @private
+/// @protected
+/// @public
+/// @package [OBJC2]
+///
+/// objc-instance-variable-decl:
+/// struct-declaration
+///
+void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
+ SourceLocation atLoc) {
+ assert(Tok.is(tok::l_brace) && "expected {");
+ llvm::SmallVector<DeclPtrTy, 32> AllIvarDecls;
+ llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators;
+
+ ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope);
+
+ SourceLocation LBraceLoc = ConsumeBrace(); // the "{"
+
+ tok::ObjCKeywordKind visibility = tok::objc_protected;
+ // While we still have something to read, read the instance variables.
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ // Each iteration of this loop reads one objc-instance-variable-decl.
+
+ // Check for extraneous top-level semicolon.
+ if (Tok.is(tok::semi)) {
+ Diag(Tok, diag::ext_extra_struct_semi);
+ ConsumeToken();
+ continue;
+ }
+
+ // Set the default visibility to private.
+ if (Tok.is(tok::at)) { // parse objc-visibility-spec
+ ConsumeToken(); // eat the @ sign
+ switch (Tok.getObjCKeywordID()) {
+ case tok::objc_private:
+ case tok::objc_public:
+ case tok::objc_protected:
+ case tok::objc_package:
+ visibility = Tok.getObjCKeywordID();
+ ConsumeToken();
+ continue;
+ default:
+ Diag(Tok, diag::err_objc_illegal_visibility_spec);
+ continue;
+ }
+ }
+
+ // Parse all the comma separated declarators.
+ DeclSpec DS;
+ FieldDeclarators.clear();
+ ParseStructDeclaration(DS, FieldDeclarators);
+
+ // Convert them all to fields.
+ for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) {
+ FieldDeclarator &FD = FieldDeclarators[i];
+ // Install the declarator into interfaceDecl.
+ DeclPtrTy Field = Actions.ActOnIvar(CurScope,
+ DS.getSourceRange().getBegin(),
+ FD.D, FD.BitfieldSize, visibility);
+ AllIvarDecls.push_back(Field);
+ }
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ } else {
+ Diag(Tok, diag::err_expected_semi_decl_list);
+ // Skip to end of block or statement
+ SkipUntil(tok::r_brace, true, true);
+ }
+ }
+ SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+ // 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(CurScope, atLoc, interfaceDecl,
+ AllIvarDecls.data(), AllIvarDecls.size(),
+ LBraceLoc, RBraceLoc, 0);
+ return;
+}
+
+/// objc-protocol-declaration:
+/// objc-protocol-definition
+/// objc-protocol-forward-reference
+///
+/// objc-protocol-definition:
+/// @protocol identifier
+/// objc-protocol-refs[opt]
+/// objc-interface-decl-list
+/// @end
+///
+/// objc-protocol-forward-reference:
+/// @protocol identifier-list ';'
+///
+/// "@protocol identifier ;" should be resolved as "@protocol
+/// identifier-list ;": objc-interface-decl-list may not start with a
+/// semicolon in the first alternative if objc-protocol-refs are omitted.
+Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
+ AttributeList *attrList) {
+ assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
+ "ParseObjCAtProtocolDeclaration(): Expected @protocol");
+ ConsumeToken(); // the "protocol" identifier
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident); // missing protocol name.
+ return DeclPtrTy();
+ }
+ // Save the protocol name, then consume it.
+ IdentifierInfo *protocolName = Tok.getIdentifierInfo();
+ SourceLocation nameLoc = ConsumeToken();
+
+ if (Tok.is(tok::semi)) { // forward declaration of one protocol.
+ IdentifierLocPair ProtoInfo(protocolName, nameLoc);
+ ConsumeToken();
+ return Actions.ActOnForwardProtocolDeclaration(AtLoc, &ProtoInfo, 1,
+ attrList);
+ }
+
+ if (Tok.is(tok::comma)) { // list of forward declarations.
+ llvm::SmallVector<IdentifierLocPair, 8> ProtocolRefs;
+ ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc));
+
+ // Parse the list of forward declarations.
+ while (1) {
+ ConsumeToken(); // the ','
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::semi);
+ return DeclPtrTy();
+ }
+ ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(),
+ Tok.getLocation()));
+ ConsumeToken(); // the identifier
+
+ if (Tok.isNot(tok::comma))
+ break;
+ }
+ // Consume the ';'.
+ if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
+ return DeclPtrTy();
+
+ return Actions.ActOnForwardProtocolDeclaration(AtLoc,
+ &ProtocolRefs[0],
+ ProtocolRefs.size(),
+ attrList);
+ }
+
+ // Last, and definitely not least, parse a protocol declaration.
+ SourceLocation EndProtoLoc;
+
+ llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs;
+ if (Tok.is(tok::less) &&
+ ParseObjCProtocolReferences(ProtocolRefs, false, EndProtoLoc))
+ return DeclPtrTy();
+
+ DeclPtrTy ProtoType =
+ Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc,
+ ProtocolRefs.data(),
+ ProtocolRefs.size(),
+ EndProtoLoc, attrList);
+ ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol);
+ return ProtoType;
+}
+
+/// objc-implementation:
+/// objc-class-implementation-prologue
+/// objc-category-implementation-prologue
+///
+/// objc-class-implementation-prologue:
+/// @implementation identifier objc-superclass[opt]
+/// objc-class-instance-variables[opt]
+///
+/// objc-category-implementation-prologue:
+/// @implementation identifier ( identifier )
+Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
+ SourceLocation atLoc) {
+ assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
+ "ParseObjCAtImplementationDeclaration(): Expected @implementation");
+ ConsumeToken(); // the "implementation" identifier
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident); // missing class or category name.
+ return DeclPtrTy();
+ }
+ // We have a class or category name - consume it.
+ IdentifierInfo *nameId = Tok.getIdentifierInfo();
+ SourceLocation nameLoc = ConsumeToken(); // consume class or category name
+
+ if (Tok.is(tok::l_paren)) {
+ // we have a category implementation.
+ SourceLocation lparenLoc = ConsumeParen();
+ SourceLocation categoryLoc, rparenLoc;
+ IdentifierInfo *categoryId = 0;
+
+ if (Tok.is(tok::identifier)) {
+ categoryId = Tok.getIdentifierInfo();
+ categoryLoc = ConsumeToken();
+ } else {
+ Diag(Tok, diag::err_expected_ident); // missing category name.
+ return DeclPtrTy();
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected_rparen);
+ SkipUntil(tok::r_paren, false); // don't stop at ';'
+ return DeclPtrTy();
+ }
+ rparenLoc = ConsumeParen();
+ DeclPtrTy ImplCatType = Actions.ActOnStartCategoryImplementation(
+ atLoc, nameId, nameLoc, categoryId,
+ categoryLoc);
+ ObjCImpDecl = ImplCatType;
+ return DeclPtrTy();
+ }
+ // We have a class implementation
+ SourceLocation superClassLoc;
+ IdentifierInfo *superClassId = 0;
+ if (Tok.is(tok::colon)) {
+ // We have a super class
+ ConsumeToken();
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident); // missing super class name.
+ return DeclPtrTy();
+ }
+ superClassId = Tok.getIdentifierInfo();
+ superClassLoc = ConsumeToken(); // Consume super class name
+ }
+ DeclPtrTy ImplClsType = Actions.ActOnStartClassImplementation(
+ atLoc, nameId, nameLoc,
+ superClassId, superClassLoc);
+
+ if (Tok.is(tok::l_brace)) // we have ivars
+ ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/, atLoc);
+ ObjCImpDecl = ImplClsType;
+
+ return DeclPtrTy();
+}
+
+Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) {
+ assert(Tok.isObjCAtKeyword(tok::objc_end) &&
+ "ParseObjCAtEndDeclaration(): Expected @end");
+ DeclPtrTy Result = ObjCImpDecl;
+ ConsumeToken(); // the "end" identifier
+ if (ObjCImpDecl) {
+ Actions.ActOnAtEnd(atLoc, ObjCImpDecl);
+ ObjCImpDecl = DeclPtrTy();
+ }
+ else
+ Diag(atLoc, diag::warn_expected_implementation); // missing @implementation
+ return Result;
+}
+
+/// compatibility-alias-decl:
+/// @compatibility_alias alias-name class-name ';'
+///
+Parser::DeclPtrTy Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
+ assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
+ "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
+ ConsumeToken(); // consume compatibility_alias
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ return DeclPtrTy();
+ }
+ IdentifierInfo *aliasId = Tok.getIdentifierInfo();
+ SourceLocation aliasLoc = ConsumeToken(); // consume alias-name
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ return DeclPtrTy();
+ }
+ IdentifierInfo *classId = Tok.getIdentifierInfo();
+ SourceLocation classLoc = ConsumeToken(); // consume class-name;
+ if (Tok.isNot(tok::semi)) {
+ Diag(Tok, diag::err_expected_semi_after) << "@compatibility_alias";
+ return DeclPtrTy();
+ }
+ return Actions.ActOnCompatiblityAlias(atLoc, aliasId, aliasLoc,
+ classId, classLoc);
+}
+
+/// property-synthesis:
+/// @synthesize property-ivar-list ';'
+///
+/// property-ivar-list:
+/// property-ivar
+/// property-ivar-list ',' property-ivar
+///
+/// property-ivar:
+/// identifier
+/// identifier '=' identifier
+///
+Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
+ assert(Tok.isObjCAtKeyword(tok::objc_synthesize) &&
+ "ParseObjCPropertyDynamic(): Expected '@synthesize'");
+ SourceLocation loc = ConsumeToken(); // consume synthesize
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ return DeclPtrTy();
+ }
+
+ while (Tok.is(tok::identifier)) {
+ IdentifierInfo *propertyIvar = 0;
+ IdentifierInfo *propertyId = Tok.getIdentifierInfo();
+ SourceLocation propertyLoc = ConsumeToken(); // consume property name
+ if (Tok.is(tok::equal)) {
+ // property '=' ivar-name
+ ConsumeToken(); // consume '='
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ break;
+ }
+ propertyIvar = Tok.getIdentifierInfo();
+ ConsumeToken(); // consume ivar-name
+ }
+ Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, true, ObjCImpDecl,
+ propertyId, propertyIvar);
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // consume ','
+ }
+ if (Tok.isNot(tok::semi))
+ Diag(Tok, diag::err_expected_semi_after) << "@synthesize";
+ return DeclPtrTy();
+}
+
+/// property-dynamic:
+/// @dynamic property-list
+///
+/// property-list:
+/// identifier
+/// property-list ',' identifier
+///
+Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
+ assert(Tok.isObjCAtKeyword(tok::objc_dynamic) &&
+ "ParseObjCPropertyDynamic(): Expected '@dynamic'");
+ SourceLocation loc = ConsumeToken(); // consume dynamic
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ return DeclPtrTy();
+ }
+ while (Tok.is(tok::identifier)) {
+ IdentifierInfo *propertyId = Tok.getIdentifierInfo();
+ SourceLocation propertyLoc = ConsumeToken(); // consume property name
+ Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, false, ObjCImpDecl,
+ propertyId, 0);
+
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // consume ','
+ }
+ if (Tok.isNot(tok::semi))
+ Diag(Tok, diag::err_expected_semi_after) << "@dynamic";
+ return DeclPtrTy();
+}
+
+/// objc-throw-statement:
+/// throw expression[opt];
+///
+Parser::OwningStmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
+ OwningExprResult Res(Actions);
+ ConsumeToken(); // consume throw
+ if (Tok.isNot(tok::semi)) {
+ Res = ParseExpression();
+ if (Res.isInvalid()) {
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+ }
+ ConsumeToken(); // consume ';'
+ return Actions.ActOnObjCAtThrowStmt(atLoc, move(Res), CurScope);
+}
+
+/// objc-synchronized-statement:
+/// @synchronized '(' expression ')' compound-statement
+///
+Parser::OwningStmtResult
+Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
+ ConsumeToken(); // consume synchronized
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "@synchronized";
+ return StmtError();
+ }
+ ConsumeParen(); // '('
+ OwningExprResult Res(ParseExpression());
+ if (Res.isInvalid()) {
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected_lbrace);
+ return StmtError();
+ }
+ ConsumeParen(); // ')'
+ if (Tok.isNot(tok::l_brace)) {
+ 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);
+
+ OwningStmtResult SynchBody(ParseCompoundStatementBody());
+
+ BodyScope.Exit();
+ if (SynchBody.isInvalid())
+ SynchBody = Actions.ActOnNullStmt(Tok.getLocation());
+ return Actions.ActOnObjCAtSynchronizedStmt(atLoc, move(Res), move(SynchBody));
+}
+
+/// objc-try-catch-statement:
+/// @try compound-statement objc-catch-list[opt]
+/// @try compound-statement objc-catch-list[opt] @finally compound-statement
+///
+/// objc-catch-list:
+/// @catch ( parameter-declaration ) compound-statement
+/// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement
+/// catch-parameter-declaration:
+/// parameter-declaration
+/// '...' [OBJC2]
+///
+Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
+ bool catch_or_finally_seen = false;
+
+ ConsumeToken(); // consume try
+ if (Tok.isNot(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_lbrace);
+ return StmtError();
+ }
+ OwningStmtResult CatchStmts(Actions);
+ OwningStmtResult FinallyStmt(Actions);
+ ParseScope TryScope(this, Scope::DeclScope);
+ OwningStmtResult TryBody(ParseCompoundStatementBody());
+ TryScope.Exit();
+ if (TryBody.isInvalid())
+ TryBody = Actions.ActOnNullStmt(Tok.getLocation());
+
+ while (Tok.is(tok::at)) {
+ // At this point, we need to lookahead to determine if this @ is the start
+ // of an @catch or @finally. We don't want to consume the @ token if this
+ // is an @try or @encode or something else.
+ Token AfterAt = GetLookAheadToken(1);
+ if (!AfterAt.isObjCAtKeyword(tok::objc_catch) &&
+ !AfterAt.isObjCAtKeyword(tok::objc_finally))
+ break;
+
+ SourceLocation AtCatchFinallyLoc = ConsumeToken();
+ if (Tok.isObjCAtKeyword(tok::objc_catch)) {
+ DeclPtrTy FirstPart;
+ ConsumeToken(); // consume catch
+ if (Tok.is(tok::l_paren)) {
+ ConsumeParen();
+ ParseScope CatchScope(this, Scope::DeclScope|Scope::AtCatchScope);
+ if (Tok.isNot(tok::ellipsis)) {
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS);
+ // For some odd reason, the name of the exception variable is
+ // optional. As a result, we need to use "PrototypeContext", because
+ // we must accept either 'declarator' or 'abstract-declarator' here.
+ Declarator ParmDecl(DS, Declarator::PrototypeContext);
+ ParseDeclarator(ParmDecl);
+
+ // Inform the actions module about the parameter declarator, so it
+ // gets added to the current scope.
+ FirstPart = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
+ } else
+ ConsumeToken(); // consume '...'
+
+ SourceLocation RParenLoc;
+
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else // Skip over garbage, until we get to ')'. Eat the ')'.
+ SkipUntil(tok::r_paren, true, false);
+
+ OwningStmtResult CatchBody(Actions, true);
+ if (Tok.is(tok::l_brace))
+ CatchBody = ParseCompoundStatementBody();
+ else
+ Diag(Tok, diag::err_expected_lbrace);
+ if (CatchBody.isInvalid())
+ CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
+ CatchStmts = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
+ RParenLoc, FirstPart, move(CatchBody),
+ move(CatchStmts));
+ } else {
+ Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
+ << "@catch clause";
+ return StmtError();
+ }
+ catch_or_finally_seen = true;
+ } else {
+ assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?");
+ ConsumeToken(); // consume finally
+ ParseScope FinallyScope(this, Scope::DeclScope);
+
+ OwningStmtResult FinallyBody(Actions, true);
+ if (Tok.is(tok::l_brace))
+ FinallyBody = ParseCompoundStatementBody();
+ else
+ Diag(Tok, diag::err_expected_lbrace);
+ if (FinallyBody.isInvalid())
+ FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());
+ FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc,
+ move(FinallyBody));
+ catch_or_finally_seen = true;
+ break;
+ }
+ }
+ if (!catch_or_finally_seen) {
+ Diag(atLoc, diag::err_missing_catch_finally);
+ return StmtError();
+ }
+ return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody), move(CatchStmts),
+ move(FinallyStmt));
+}
+
+/// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
+///
+Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() {
+ DeclPtrTy MDecl = ParseObjCMethodPrototype(ObjCImpDecl);
+
+ PrettyStackTraceActionsDecl CrashInfo(MDecl, Tok.getLocation(), Actions,
+ PP.getSourceManager(),
+ "parsing Objective-C method");
+
+ // parse optional ';'
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+
+ // We should have an opening brace now.
+ if (Tok.isNot(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_method_body);
+
+ // Skip over garbage, until we get to '{'. Don't eat the '{'.
+ SkipUntil(tok::l_brace, true, true);
+
+ // If we didn't find the '{', bail out.
+ if (Tok.isNot(tok::l_brace))
+ return DeclPtrTy();
+ }
+ SourceLocation BraceLoc = Tok.getLocation();
+
+ // Enter a scope for the method body.
+ ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
+
+ // Tell the actions module that we have entered a method definition with the
+ // specified Declarator for the method.
+ Actions.ActOnStartOfObjCMethodDef(CurScope, MDecl);
+
+ OwningStmtResult 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);
+
+ // TODO: Pass argument information.
+ Actions.ActOnFinishFunctionBody(MDecl, move(FnBody));
+
+ // Leave the function body scope.
+ BodyScope.Exit();
+
+ return MDecl;
+}
+
+Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
+ if (Tok.isObjCAtKeyword(tok::objc_try)) {
+ return ParseObjCTryStmt(AtLoc);
+ } else if (Tok.isObjCAtKeyword(tok::objc_throw))
+ return ParseObjCThrowStmt(AtLoc);
+ else if (Tok.isObjCAtKeyword(tok::objc_synchronized))
+ return ParseObjCSynchronizedStmt(AtLoc);
+ OwningExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
+ if (Res.isInvalid()) {
+ // If the expression is invalid, skip ahead to the next semicolon. Not
+ // doing this opens us up to the possibility of infinite loops if
+ // ParseExpression does not consume any tokens.
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+ // Otherwise, eat the semicolon.
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
+ return Actions.ActOnExprStmt(Actions.FullExpr(Res));
+}
+
+Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
+ switch (Tok.getKind()) {
+ case tok::string_literal: // primary-expression: string-literal
+ case tok::wide_string_literal:
+ return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
+ default:
+ if (Tok.getIdentifierInfo() == 0)
+ return ExprError(Diag(AtLoc, diag::err_unexpected_at));
+
+ switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
+ case tok::objc_encode:
+ return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc));
+ case tok::objc_protocol:
+ return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc));
+ case tok::objc_selector:
+ return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc));
+ default:
+ return ExprError(Diag(AtLoc, diag::err_unexpected_at));
+ }
+ }
+}
+
+/// objc-message-expr:
+/// '[' objc-receiver objc-message-args ']'
+///
+/// objc-receiver:
+/// expression
+/// class-name
+/// type-name
+Parser::OwningExprResult Parser::ParseObjCMessageExpression() {
+ assert(Tok.is(tok::l_square) && "'[' expected");
+ SourceLocation LBracLoc = ConsumeBracket(); // consume '['
+
+ // Parse receiver
+ if (isTokObjCMessageIdentifierReceiver()) {
+ IdentifierInfo *ReceiverName = Tok.getIdentifierInfo();
+ if (ReceiverName != Ident_super || GetLookAheadToken(1).isNot(tok::period)) {
+ SourceLocation NameLoc = ConsumeToken();
+ return ParseObjCMessageExpressionBody(LBracLoc, NameLoc, ReceiverName,
+ ExprArg(Actions));
+ }
+ }
+
+ OwningExprResult Res(ParseExpression());
+ if (Res.isInvalid()) {
+ SkipUntil(tok::r_square);
+ return move(Res);
+ }
+
+ return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
+ 0, move(Res));
+}
+
+/// ParseObjCMessageExpressionBody - Having parsed "'[' objc-receiver", parse
+/// the rest of a message expression.
+///
+/// objc-message-args:
+/// objc-selector
+/// objc-keywordarg-list
+///
+/// objc-keywordarg-list:
+/// objc-keywordarg
+/// objc-keywordarg-list objc-keywordarg
+///
+/// objc-keywordarg:
+/// selector-name[opt] ':' objc-keywordexpr
+///
+/// objc-keywordexpr:
+/// nonempty-expr-list
+///
+/// nonempty-expr-list:
+/// assignment-expression
+/// nonempty-expr-list , assignment-expression
+///
+Parser::OwningExprResult
+Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
+ SourceLocation NameLoc,
+ IdentifierInfo *ReceiverName,
+ ExprArg ReceiverExpr) {
+ // Parse objc-selector
+ SourceLocation Loc;
+ IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);
+
+ SourceLocation SelectorLoc = Loc;
+
+ llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
+ ExprVector KeyExprs(Actions);
+
+ if (Tok.is(tok::colon)) {
+ while (1) {
+ // Each iteration parses a single keyword argument.
+ KeyIdents.push_back(selIdent);
+
+ if (Tok.isNot(tok::colon)) {
+ Diag(Tok, diag::err_expected_colon);
+ // We must manually skip to a ']', otherwise the expression skipper will
+ // stop at the ']' when it skips to the ';'. We want it to skip beyond
+ // the enclosing expression.
+ SkipUntil(tok::r_square);
+ return ExprError();
+ }
+
+ ConsumeToken(); // Eat the ':'.
+ /// Parse the expression after ':'
+ OwningExprResult Res(ParseAssignmentExpression());
+ if (Res.isInvalid()) {
+ // We must manually skip to a ']', otherwise the expression skipper will
+ // stop at the ']' when it skips to the ';'. We want it to skip beyond
+ // the enclosing expression.
+ SkipUntil(tok::r_square);
+ return move(Res);
+ }
+
+ // We have a valid expression.
+ KeyExprs.push_back(Res.release());
+
+ // Check for another keyword selector.
+ selIdent = ParseObjCSelectorPiece(Loc);
+ if (!selIdent && Tok.isNot(tok::colon))
+ break;
+ // We have a selector or a colon, continue parsing.
+ }
+ // Parse the, optional, argument list, comma separated.
+ while (Tok.is(tok::comma)) {
+ ConsumeToken(); // Eat the ','.
+ /// Parse the expression after ','
+ OwningExprResult Res(ParseAssignmentExpression());
+ if (Res.isInvalid()) {
+ // We must manually skip to a ']', otherwise the expression skipper will
+ // stop at the ']' when it skips to the ';'. We want it to skip beyond
+ // the enclosing expression.
+ SkipUntil(tok::r_square);
+ return move(Res);
+ }
+
+ // We have a valid expression.
+ KeyExprs.push_back(Res.release());
+ }
+ } else if (!selIdent) {
+ Diag(Tok, diag::err_expected_ident); // missing selector name.
+
+ // We must manually skip to a ']', otherwise the expression skipper will
+ // stop at the ']' when it skips to the ';'. We want it to skip beyond
+ // the enclosing expression.
+ SkipUntil(tok::r_square);
+ return ExprError();
+ }
+
+ if (Tok.isNot(tok::r_square)) {
+ Diag(Tok, diag::err_expected_rsquare);
+ // We must manually skip to a ']', otherwise the expression skipper will
+ // stop at the ']' when it skips to the ';'. We want it to skip beyond
+ // the enclosing expression.
+ SkipUntil(tok::r_square);
+ return ExprError();
+ }
+
+ SourceLocation RBracLoc = ConsumeBracket(); // consume ']'
+
+ unsigned nKeys = KeyIdents.size();
+ if (nKeys == 0)
+ KeyIdents.push_back(selIdent);
+ Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]);
+
+ // We've just parsed a keyword message.
+ if (ReceiverName)
+ return Owned(Actions.ActOnClassMessage(CurScope, ReceiverName, Sel,
+ LBracLoc, NameLoc, SelectorLoc,
+ RBracLoc,
+ KeyExprs.take(), KeyExprs.size()));
+ return Owned(Actions.ActOnInstanceMessage(ReceiverExpr.release(), Sel,
+ LBracLoc, SelectorLoc, RBracLoc,
+ KeyExprs.take(), KeyExprs.size()));
+}
+
+Parser::OwningExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
+ OwningExprResult Res(ParseStringLiteralExpression());
+ if (Res.isInvalid()) return move(Res);
+
+ // @"foo" @"bar" is a valid concatenated string. Eat any subsequent string
+ // expressions. At this point, we know that the only valid thing that starts
+ // with '@' is an @"".
+ llvm::SmallVector<SourceLocation, 4> AtLocs;
+ ExprVector AtStrings(Actions);
+ AtLocs.push_back(AtLoc);
+ AtStrings.push_back(Res.release());
+
+ while (Tok.is(tok::at)) {
+ AtLocs.push_back(ConsumeToken()); // eat the @.
+
+ // Invalid unless there is a string literal.
+ if (!isTokenStringLiteral())
+ return ExprError(Diag(Tok, diag::err_objc_concat_string));
+
+ OwningExprResult Lit(ParseStringLiteralExpression());
+ if (Lit.isInvalid())
+ return move(Lit);
+
+ AtStrings.push_back(Lit.release());
+ }
+
+ return Owned(Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.take(),
+ AtStrings.size()));
+}
+
+/// objc-encode-expression:
+/// @encode ( type-name )
+Parser::OwningExprResult
+Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
+ assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
+
+ SourceLocation EncLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::l_paren))
+ return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@encode");
+
+ SourceLocation LParenLoc = ConsumeParen();
+
+ TypeResult Ty = ParseTypeName();
+
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ if (Ty.isInvalid())
+ return ExprError();
+
+ return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, LParenLoc,
+ Ty.get(), RParenLoc));
+}
+
+/// objc-protocol-expression
+/// @protocol ( protocol-name )
+Parser::OwningExprResult
+Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
+ SourceLocation ProtoLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::l_paren))
+ return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@protocol");
+
+ SourceLocation LParenLoc = ConsumeParen();
+
+ if (Tok.isNot(tok::identifier))
+ return ExprError(Diag(Tok, diag::err_expected_ident));
+
+ IdentifierInfo *protocolId = Tok.getIdentifierInfo();
+ ConsumeToken();
+
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ return Owned(Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
+ LParenLoc, RParenLoc));
+}
+
+/// objc-selector-expression
+/// @selector '(' objc-keyword-selector ')'
+Parser::OwningExprResult
+Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
+ SourceLocation SelectorLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::l_paren))
+ return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector");
+
+ llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
+ SourceLocation LParenLoc = ConsumeParen();
+ SourceLocation sLoc;
+ IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc);
+ if (!SelIdent && Tok.isNot(tok::colon)) // missing selector name.
+ return ExprError(Diag(Tok, diag::err_expected_ident));
+
+ KeyIdents.push_back(SelIdent);
+ unsigned nColons = 0;
+ if (Tok.isNot(tok::r_paren)) {
+ while (1) {
+ if (Tok.isNot(tok::colon))
+ return ExprError(Diag(Tok, diag::err_expected_colon));
+
+ nColons++;
+ ConsumeToken(); // Eat the ':'.
+ if (Tok.is(tok::r_paren))
+ break;
+ // Check for another keyword selector.
+ SourceLocation Loc;
+ SelIdent = ParseObjCSelectorPiece(Loc);
+ KeyIdents.push_back(SelIdent);
+ if (!SelIdent && Tok.isNot(tok::colon))
+ break;
+ }
+ }
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
+ return Owned(Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
+ LParenLoc, RParenLoc));
+ }
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
new file mode 100644
index 000000000000..94695e4d5694
--- /dev/null
+++ b/lib/Parse/ParsePragma.cpp
@@ -0,0 +1,182 @@
+//===--- ParsePragma.cpp - Language specific pragma parsing ---------------===//
+//
+// 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 language specific #pragma handlers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ParsePragma.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/Action.h"
+#include "clang/Parse/Parser.h"
+using namespace clang;
+
+// #pragma pack(...) comes in the following delicious flavors:
+// pack '(' [integer] ')'
+// pack '(' 'show' ')'
+// pack '(' ('push' | 'pop') [',' identifier] [, integer] ')'
+void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
+ // FIXME: Should we be expanding macros here? My guess is no.
+ SourceLocation PackLoc = PackTok.getLocation();
+
+ Token Tok;
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "pack";
+ return;
+ }
+
+ Action::PragmaPackKind Kind = Action::PPK_Default;
+ IdentifierInfo *Name = 0;
+ Action::OwningExprResult Alignment(Actions);
+ SourceLocation LParenLoc = Tok.getLocation();
+ PP.Lex(Tok);
+ if (Tok.is(tok::numeric_constant)) {
+ Alignment = Actions.ActOnNumericConstant(Tok);
+ if (Alignment.isInvalid())
+ return;
+
+ PP.Lex(Tok);
+ } else if (Tok.is(tok::identifier)) {
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (II->isStr("show")) {
+ Kind = Action::PPK_Show;
+ PP.Lex(Tok);
+ } else {
+ if (II->isStr("push")) {
+ Kind = Action::PPK_Push;
+ } else if (II->isStr("pop")) {
+ Kind = Action::PPK_Pop;
+ } else {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_invalid_action);
+ return;
+ }
+ PP.Lex(Tok);
+
+ if (Tok.is(tok::comma)) {
+ PP.Lex(Tok);
+
+ if (Tok.is(tok::numeric_constant)) {
+ Alignment = Actions.ActOnNumericConstant(Tok);
+ if (Alignment.isInvalid())
+ return;
+
+ PP.Lex(Tok);
+ } else if (Tok.is(tok::identifier)) {
+ Name = Tok.getIdentifierInfo();
+ PP.Lex(Tok);
+
+ if (Tok.is(tok::comma)) {
+ PP.Lex(Tok);
+
+ if (Tok.isNot(tok::numeric_constant)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
+ return;
+ }
+
+ Alignment = Actions.ActOnNumericConstant(Tok);
+ if (Alignment.isInvalid())
+ return;
+
+ PP.Lex(Tok);
+ }
+ } else {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
+ return;
+ }
+ }
+ }
+ }
+
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "pack";
+ return;
+ }
+
+ SourceLocation RParenLoc = Tok.getLocation();
+ Actions.ActOnPragmaPack(Kind, Name, Alignment.release(), PackLoc,
+ LParenLoc, RParenLoc);
+}
+
+// #pragma unused(identifier)
+void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) {
+ // FIXME: Should we be expanding macros here? My guess is no.
+ SourceLocation UnusedLoc = UnusedTok.getLocation();
+
+ // Lex the left '('.
+ Token Tok;
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused";
+ return;
+ }
+ SourceLocation LParenLoc = Tok.getLocation();
+
+ // Lex the declaration reference(s).
+ llvm::SmallVector<Action::ExprTy*, 5> Ex;
+ SourceLocation RParenLoc;
+ bool LexID = true;
+
+ while (true) {
+ PP.Lex(Tok);
+
+ if (LexID) {
+ if (Tok.is(tok::identifier)) {
+ Action::OwningExprResult Name =
+ Actions.ActOnIdentifierExpr(parser.CurScope, Tok.getLocation(),
+ *Tok.getIdentifierInfo(), false);
+
+ if (Name.isInvalid()) {
+ if (!Ex.empty())
+ Action::MultiExprArg Release(Actions, &Ex[0], Ex.size());
+ return;
+ }
+
+ Ex.push_back(Name.release());
+ LexID = false;
+ continue;
+ }
+
+ // Illegal token! Release the parsed expressions (if any) and emit
+ // a warning.
+ if (!Ex.empty())
+ Action::MultiExprArg Release(Actions, &Ex[0], Ex.size());
+
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_var);
+ return;
+ }
+
+ // We are execting a ')' or a ','.
+ if (Tok.is(tok::comma)) {
+ LexID = true;
+ continue;
+ }
+
+ if (Tok.is(tok::r_paren)) {
+ RParenLoc = Tok.getLocation();
+ break;
+ }
+
+ // Illegal token! Release the parsed expressions (if any) and emit
+ // a warning.
+ if (!Ex.empty())
+ Action::MultiExprArg Release(Actions, &Ex[0], Ex.size());
+
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc);
+ return;
+ }
+
+ // Verify that we have a location for the right parenthesis.
+ assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'");
+ assert(!Ex.empty() && "Valid '#pragma unused' must have arguments");
+
+ // Perform the action to handle the pragma.
+ Actions.ActOnPragmaUnused(&Ex[0], Ex.size(), UnusedLoc, LParenLoc, RParenLoc);
+}
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
new file mode 100644
index 000000000000..31b2a5f6851d
--- /dev/null
+++ b/lib/Parse/ParsePragma.h
@@ -0,0 +1,44 @@
+//===---- ParserPragmas.h - Language specific pragmas -----------*- 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 #pragma handlers for language specific pragmas.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PARSE_PARSEPRAGMA_H
+#define LLVM_CLANG_PARSE_PARSEPRAGMA_H
+
+#include "clang/Lex/Pragma.h"
+
+namespace clang {
+ class Action;
+ class Parser;
+
+class PragmaPackHandler : public PragmaHandler {
+ Action &Actions;
+public:
+ PragmaPackHandler(const IdentifierInfo *N, Action &A) : PragmaHandler(N),
+ Actions(A) {}
+
+ virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);
+};
+
+class PragmaUnusedHandler : public PragmaHandler {
+ Action &Actions;
+ Parser &parser;
+public:
+ PragmaUnusedHandler(const IdentifierInfo *N, Action &A, Parser& p)
+ : PragmaHandler(N), Actions(A), parser(p) {}
+
+ virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);
+};
+
+} // end namespace clang
+
+#endif
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
new file mode 100644
index 000000000000..758b662a2392
--- /dev/null
+++ b/lib/Parse/ParseStmt.cpp
@@ -0,0 +1,1435 @@
+//===--- ParseStmt.cpp - Statement and Block Parser -----------------------===//
+//
+// 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 Statement and Block portions of the Parser
+// interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "ExtensionRAIIObject.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Basic/SourceManager.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// C99 6.8: Statements and Blocks.
+//===----------------------------------------------------------------------===//
+
+/// ParseStatementOrDeclaration - Read 'statement' or 'declaration'.
+/// StatementOrDeclaration:
+/// statement
+/// declaration
+///
+/// statement:
+/// labeled-statement
+/// compound-statement
+/// expression-statement
+/// selection-statement
+/// iteration-statement
+/// jump-statement
+/// [C++] declaration-statement
+/// [C++] try-block
+/// [OBC] objc-throw-statement
+/// [OBC] objc-try-catch-statement
+/// [OBC] objc-synchronized-statement
+/// [GNU] asm-statement
+/// [OMP] openmp-construct [TODO]
+///
+/// labeled-statement:
+/// identifier ':' statement
+/// 'case' constant-expression ':' statement
+/// 'default' ':' statement
+///
+/// selection-statement:
+/// if-statement
+/// switch-statement
+///
+/// iteration-statement:
+/// while-statement
+/// do-statement
+/// for-statement
+///
+/// expression-statement:
+/// expression[opt] ';'
+///
+/// jump-statement:
+/// 'goto' identifier ';'
+/// 'continue' ';'
+/// 'break' ';'
+/// 'return' expression[opt] ';'
+/// [GNU] 'goto' '*' expression ';'
+///
+/// [OBC] objc-throw-statement:
+/// [OBC] '@' 'throw' expression ';'
+/// [OBC] '@' 'throw' ';'
+///
+Parser::OwningStmtResult
+Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
+ const char *SemiError = 0;
+ OwningStmtResult Res(Actions);
+
+ // Cases in this switch statement should fall through if the parser expects
+ // the token to end in a semicolon (in which case SemiError should be set),
+ // or they directly 'return;' if not.
+ tok::TokenKind Kind = Tok.getKind();
+ SourceLocation AtLoc;
+ switch (Kind) {
+ case tok::at: // May be a @try or @throw statement
+ {
+ AtLoc = ConsumeToken(); // consume @
+ return ParseObjCAtStatement(AtLoc);
+ }
+
+ case tok::identifier:
+ if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement
+ // identifier ':' statement
+ return ParseLabeledStatement();
+ }
+ // PASS THROUGH.
+
+ default: {
+ if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
+ SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
+ DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd);
+ return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
+ }
+
+ if (Tok.is(tok::r_brace)) {
+ Diag(Tok, diag::err_expected_statement);
+ return StmtError();
+ }
+
+ // expression[opt] ';'
+ OwningExprResult Expr(ParseExpression());
+ if (Expr.isInvalid()) {
+ // If the expression is invalid, skip ahead to the next semicolon. Not
+ // doing this opens us up to the possibility of infinite loops if
+ // ParseExpression does not consume any tokens.
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+ // Otherwise, eat the semicolon.
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
+ return Actions.ActOnExprStmt(Actions.FullExpr(Expr));
+ }
+
+ case tok::kw_case: // C99 6.8.1: labeled-statement
+ return ParseCaseStatement();
+ case tok::kw_default: // C99 6.8.1: labeled-statement
+ return ParseDefaultStatement();
+
+ case tok::l_brace: // C99 6.8.2: compound-statement
+ return ParseCompoundStatement();
+ case tok::semi: // C99 6.8.3p3: expression[opt] ';'
+ return Actions.ActOnNullStmt(ConsumeToken());
+
+ case tok::kw_if: // C99 6.8.4.1: if-statement
+ return ParseIfStatement();
+ case tok::kw_switch: // C99 6.8.4.2: switch-statement
+ return ParseSwitchStatement();
+
+ case tok::kw_while: // C99 6.8.5.1: while-statement
+ return ParseWhileStatement();
+ case tok::kw_do: // C99 6.8.5.2: do-statement
+ Res = ParseDoStatement();
+ SemiError = "do/while loop";
+ break;
+ case tok::kw_for: // C99 6.8.5.3: for-statement
+ return ParseForStatement();
+
+ case tok::kw_goto: // C99 6.8.6.1: goto-statement
+ Res = ParseGotoStatement();
+ SemiError = "goto statement";
+ break;
+ case tok::kw_continue: // C99 6.8.6.2: continue-statement
+ Res = ParseContinueStatement();
+ SemiError = "continue statement";
+ break;
+ case tok::kw_break: // C99 6.8.6.3: break-statement
+ Res = ParseBreakStatement();
+ SemiError = "break statement";
+ break;
+ case tok::kw_return: // C99 6.8.6.4: return-statement
+ Res = ParseReturnStatement();
+ SemiError = "return statement";
+ break;
+
+ case tok::kw_asm: {
+ bool msAsm = false;
+ Res = ParseAsmStatement(msAsm);
+ if (msAsm) return move(Res);
+ SemiError = "asm statement";
+ break;
+ }
+
+ case tok::kw_try: // C++ 15: try-block
+ return ParseCXXTryBlock();
+ }
+
+ // If we reached this code, the statement must end in a semicolon.
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ } else if (!Res.isInvalid()) {
+ Diag(Tok, diag::err_expected_semi_after) << SemiError;
+ // Skip until we see a } or ;, but don't eat it.
+ SkipUntil(tok::r_brace, true, true);
+ }
+ return move(Res);
+}
+
+/// ParseLabeledStatement - We have an identifier and a ':' after it.
+///
+/// labeled-statement:
+/// identifier ':' statement
+/// [GNU] identifier ':' attributes[opt] statement
+///
+Parser::OwningStmtResult Parser::ParseLabeledStatement() {
+ assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() &&
+ "Not an identifier!");
+
+ Token IdentTok = Tok; // Save the whole token.
+ ConsumeToken(); // eat the identifier.
+
+ assert(Tok.is(tok::colon) && "Not a label!");
+
+ // identifier ':' statement
+ SourceLocation ColonLoc = ConsumeToken();
+
+ // Read label attributes, if present.
+ Action::AttrTy *AttrList = 0;
+ if (Tok.is(tok::kw___attribute))
+ // TODO: save these somewhere.
+ AttrList = ParseAttributes();
+
+ OwningStmtResult SubStmt(ParseStatement());
+
+ // Broken substmt shouldn't prevent the label from being added to the AST.
+ if (SubStmt.isInvalid())
+ SubStmt = Actions.ActOnNullStmt(ColonLoc);
+
+ return Actions.ActOnLabelStmt(IdentTok.getLocation(),
+ IdentTok.getIdentifierInfo(),
+ ColonLoc, move(SubStmt));
+}
+
+/// ParseCaseStatement
+/// labeled-statement:
+/// 'case' constant-expression ':' statement
+/// [GNU] 'case' constant-expression '...' constant-expression ':' statement
+///
+Parser::OwningStmtResult Parser::ParseCaseStatement() {
+ assert(Tok.is(tok::kw_case) && "Not a case stmt!");
+
+ // It is very very common for code to contain many case statements recursively
+ // nested, as in (but usually without indentation):
+ // case 1:
+ // case 2:
+ // case 3:
+ // case 4:
+ // case 5: etc.
+ //
+ // Parsing this naively works, but is both inefficient and can cause us to run
+ // out of stack space in our recursive descent parser. As a special case,
+ // flatten this recursion into an iterative loop. This is complex and gross,
+ // but all the grossness is constrained to ParseCaseStatement (and some
+ // wierdness in the actions), so this is just local grossness :).
+
+ // TopLevelCase - This is the highest level we have parsed. 'case 1' in the
+ // example above.
+ OwningStmtResult TopLevelCase(Actions, true);
+
+ // 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;
+
+ // While we have case statements, eat and stack them.
+ do {
+ SourceLocation CaseLoc = ConsumeToken(); // eat the 'case'.
+
+ OwningExprResult LHS(ParseConstantExpression());
+ if (LHS.isInvalid()) {
+ SkipUntil(tok::colon);
+ return StmtError();
+ }
+
+ // GNU case range extension.
+ SourceLocation DotDotDotLoc;
+ OwningExprResult RHS(Actions);
+ if (Tok.is(tok::ellipsis)) {
+ Diag(Tok, diag::ext_gnu_case_range);
+ DotDotDotLoc = ConsumeToken();
+
+ RHS = ParseConstantExpression();
+ if (RHS.isInvalid()) {
+ SkipUntil(tok::colon);
+ return StmtError();
+ }
+ }
+
+ if (Tok.isNot(tok::colon)) {
+ Diag(Tok, diag::err_expected_colon_after) << "'case'";
+ SkipUntil(tok::colon);
+ return StmtError();
+ }
+
+ SourceLocation ColonLoc = ConsumeToken();
+
+ OwningStmtResult Case =
+ Actions.ActOnCaseStmt(CaseLoc, move(LHS), DotDotDotLoc,
+ move(RHS), ColonLoc);
+
+ // If we had a sema error parsing this case, then just ignore it and
+ // continue parsing the sub-stmt.
+ if (Case.isInvalid()) {
+ if (TopLevelCase.isInvalid()) // No parsed case stmts.
+ return ParseStatement();
+ // Otherwise, just don't add it as a nested case.
+ } else {
+ // If this is the first case statement we parsed, it becomes TopLevelCase.
+ // Otherwise we link it into the current chain.
+ StmtTy *NextDeepest = Case.get();
+ if (TopLevelCase.isInvalid())
+ TopLevelCase = move(Case);
+ else
+ Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, move(Case));
+ DeepestParsedCaseStmt = NextDeepest;
+ }
+
+ // Handle all case statements.
+ } while (Tok.is(tok::kw_case));
+
+ assert(!TopLevelCase.isInvalid() && "Should have parsed at least one case!");
+
+ // If we found a non-case statement, start by parsing it.
+ OwningStmtResult SubStmt(Actions);
+
+ if (Tok.isNot(tok::r_brace)) {
+ SubStmt = ParseStatement();
+ } else {
+ // Nicely diagnose the common error "switch (X) { case 4: }", which is
+ // not valid.
+ // FIXME: add insertion hint.
+ Diag(Tok, diag::err_label_end_of_compound_statement);
+ SubStmt = true;
+ }
+
+ // Broken sub-stmt shouldn't prevent forming the case statement properly.
+ if (SubStmt.isInvalid())
+ SubStmt = Actions.ActOnNullStmt(SourceLocation());
+
+ // Install the body into the most deeply-nested case.
+ Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, move(SubStmt));
+
+ // Return the top level parsed statement tree.
+ return move(TopLevelCase);
+}
+
+/// ParseDefaultStatement
+/// labeled-statement:
+/// 'default' ':' statement
+/// Note that this does not parse the 'statement' at the end.
+///
+Parser::OwningStmtResult Parser::ParseDefaultStatement() {
+ assert(Tok.is(tok::kw_default) && "Not a default stmt!");
+ SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'.
+
+ if (Tok.isNot(tok::colon)) {
+ Diag(Tok, diag::err_expected_colon_after) << "'default'";
+ SkipUntil(tok::colon);
+ return StmtError();
+ }
+
+ SourceLocation ColonLoc = ConsumeToken();
+
+ // Diagnose the common error "switch (X) {... default: }", which is not valid.
+ if (Tok.is(tok::r_brace)) {
+ Diag(Tok, diag::err_label_end_of_compound_statement);
+ return StmtError();
+ }
+
+ OwningStmtResult SubStmt(ParseStatement());
+ if (SubStmt.isInvalid())
+ return StmtError();
+
+ return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc,
+ move(SubStmt), CurScope);
+}
+
+
+/// ParseCompoundStatement - Parse a "{}" block.
+///
+/// compound-statement: [C99 6.8.2]
+/// { block-item-list[opt] }
+/// [GNU] { label-declarations block-item-list } [TODO]
+///
+/// block-item-list:
+/// block-item
+/// block-item-list block-item
+///
+/// block-item:
+/// declaration
+/// [GNU] '__extension__' declaration
+/// statement
+/// [OMP] openmp-directive [TODO]
+///
+/// [GNU] label-declarations:
+/// [GNU] label-declaration
+/// [GNU] label-declarations label-declaration
+///
+/// [GNU] label-declaration:
+/// [GNU] '__label__' identifier-list ';'
+///
+/// [OMP] openmp-directive: [TODO]
+/// [OMP] barrier-directive
+/// [OMP] flush-directive
+///
+Parser::OwningStmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
+ assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
+
+ // Enter a scope to hold everything within the compound stmt. Compound
+ // statements can always hold declarations.
+ ParseScope CompoundScope(this, Scope::DeclScope);
+
+ // Parse the statements in the body.
+ return ParseCompoundStatementBody(isStmtExpr);
+}
+
+
+/// ParseCompoundStatementBody - Parse a sequence of statements and invoke the
+/// ActOnCompoundStmt action. This expects the '{' to be the current token, and
+/// consume the '}' at the end of the block. It does not manipulate the scope
+/// stack.
+Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
+ PrettyStackTraceLoc CrashInfo(PP.getSourceManager(),
+ Tok.getLocation(),
+ "in compound statement ('{}')");
+
+ SourceLocation LBraceLoc = ConsumeBrace(); // eat the '{'.
+
+ // TODO: "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are
+ // only allowed at the start of a compound stmt regardless of the language.
+
+ typedef StmtVector StmtsTy;
+ StmtsTy Stmts(Actions);
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ OwningStmtResult R(Actions);
+ if (Tok.isNot(tok::kw___extension__)) {
+ R = ParseStatementOrDeclaration(false);
+ } else {
+ // __extension__ can start declarations and it can also be a unary
+ // operator for expressions. Consume multiple __extension__ markers here
+ // until we can determine which is which.
+ // FIXME: This loses extension expressions in the AST!
+ SourceLocation ExtLoc = ConsumeToken();
+ while (Tok.is(tok::kw___extension__))
+ ConsumeToken();
+
+ // If this is the start of a declaration, parse it as such.
+ if (isDeclarationStatement()) {
+ // __extension__ silences extension warnings in the subdeclaration.
+ // FIXME: Save the __extension__ on the decl as a node somehow?
+ ExtensionRAIIObject O(Diags);
+
+ SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
+ DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext,DeclEnd);
+ R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd);
+ } else {
+ // Otherwise this was a unary __extension__ marker.
+ OwningExprResult Res(ParseExpressionWithLeadingExtension(ExtLoc));
+
+ if (Res.isInvalid()) {
+ SkipUntil(tok::semi);
+ continue;
+ }
+
+ // Eat the semicolon at the end of stmt and convert the expr into a
+ // statement.
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
+ R = Actions.ActOnExprStmt(Actions.FullExpr(Res));
+ }
+ }
+
+ if (R.isUsable())
+ Stmts.push_back(R.release());
+ }
+
+ // 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);
+ return StmtError();
+ }
+
+ SourceLocation RBraceLoc = ConsumeBrace();
+ return Actions.ActOnCompoundStmt(LBraceLoc, RBraceLoc, move_arg(Stmts),
+ isStmtExpr);
+}
+
+/// ParseParenExprOrCondition:
+/// [C ] '(' expression ')'
+/// [C++] '(' condition ')' [not allowed if OnlyAllowCondition=true]
+///
+/// This function parses and performs error recovery on the specified condition
+/// or expression (depending on whether we're in C++ or C mode). This function
+/// goes out of its way to recover well. It returns true if there was a parser
+/// error (the right paren couldn't be found), which indicates that the caller
+/// should try to recover harder. It returns false if the condition is
+/// successfully parsed. Note that a successful parse can still have semantic
+/// errors in the condition.
+bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp,
+ bool OnlyAllowCondition) {
+ SourceLocation LParenLoc = ConsumeParen();
+
+ if (getLang().CPlusPlus)
+ CondExp = ParseCXXCondition();
+ else
+ CondExp = ParseExpression();
+
+ // If the parser was confused by the condition and we don't have a ')', try to
+ // recover by skipping ahead to a semi and bailing out. If condexp is
+ // semantically invalid but we have well formed code, keep going.
+ if (CondExp.isInvalid() && Tok.isNot(tok::r_paren)) {
+ SkipUntil(tok::semi);
+ // Skipping may have stopped if it found the containing ')'. If so, we can
+ // continue parsing the if statement.
+ if (Tok.isNot(tok::r_paren))
+ return true;
+ }
+
+ // Otherwise the condition is valid or the rparen is present.
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ return false;
+}
+
+
+/// ParseIfStatement
+/// if-statement: [C99 6.8.4.1]
+/// 'if' '(' expression ')' statement
+/// 'if' '(' expression ')' statement 'else' statement
+/// [C++] 'if' '(' condition ')' statement
+/// [C++] 'if' '(' condition ')' statement 'else' statement
+///
+Parser::OwningStmtResult Parser::ParseIfStatement() {
+ assert(Tok.is(tok::kw_if) && "Not an if stmt!");
+ SourceLocation IfLoc = ConsumeToken(); // eat the 'if'.
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "if";
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+
+ bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
+
+ // C99 6.8.4p3 - In C99, the if statement is a block. This is not
+ // the case for C90.
+ //
+ // C++ 6.4p3:
+ // A name introduced by a declaration in a condition is in scope from its
+ // point of declaration until the end of the substatements controlled by the
+ // condition.
+ // C++ 3.3.2p4:
+ // Names declared in the for-init-statement, and in the condition of if,
+ // while, for, and switch statements are local to the if, while, for, or
+ // switch statement (including the controlled statement).
+ //
+ ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX);
+
+ // Parse the condition.
+ OwningExprResult CondExp(Actions);
+ if (ParseParenExprOrCondition(CondExp))
+ return StmtError();
+
+ // C99 6.8.4p3 - 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
+ // if the body isn't a compound statement to avoid push/pop in common cases.
+ //
+ // C++ 6.4p1:
+ // The substatement in a selection-statement (each substatement, in the else
+ // form of the if statement) implicitly defines a local scope.
+ //
+ // For C++ we create a scope for the condition and a new scope for
+ // substatements because:
+ // -When the 'then' scope exits, we want the condition declaration to still be
+ // active for the 'else' scope too.
+ // -Sema will detect name clashes by considering declarations of a
+ // 'ControlScope' as part of its direct subscope.
+ // -If we wanted the condition and substatement to be in the same scope, we
+ // would have to notify ParseStatement not to create a new scope. It's
+ // simpler to let it create a new scope.
+ //
+ ParseScope InnerScope(this, Scope::DeclScope,
+ C99orCXX && Tok.isNot(tok::l_brace));
+
+ // Read the 'then' stmt.
+ SourceLocation ThenStmtLoc = Tok.getLocation();
+ OwningStmtResult ThenStmt(ParseStatement());
+
+ // Pop the 'if' scope if needed.
+ InnerScope.Exit();
+
+ // If it has an else, parse it.
+ SourceLocation ElseLoc;
+ SourceLocation ElseStmtLoc;
+ OwningStmtResult ElseStmt(Actions);
+
+ if (Tok.is(tok::kw_else)) {
+ ElseLoc = ConsumeToken();
+
+ // C99 6.8.4p3 - 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 if the body isn't a compound statement to avoid push/pop in common
+ // cases.
+ //
+ // C++ 6.4p1:
+ // The substatement in a selection-statement (each substatement, in the else
+ // form of the if statement) implicitly defines a local scope.
+ //
+ ParseScope InnerScope(this, Scope::DeclScope,
+ C99orCXX && Tok.isNot(tok::l_brace));
+
+ bool WithinElse = CurScope->isWithinElse();
+ CurScope->setWithinElse(true);
+ ElseStmtLoc = Tok.getLocation();
+ ElseStmt = ParseStatement();
+ CurScope->setWithinElse(WithinElse);
+
+ // Pop the 'else' scope if needed.
+ InnerScope.Exit();
+ }
+
+ IfScope.Exit();
+
+ // If the condition was invalid, discard the if statement. We could recover
+ // better by replacing it with a valid expr, but don't do that yet.
+ if (CondExp.isInvalid())
+ return StmtError();
+
+ // If the then or else stmt is invalid and the other is valid (and present),
+ // make turn the invalid one into a null stmt to avoid dropping the other
+ // part. If both are invalid, return error.
+ if ((ThenStmt.isInvalid() && ElseStmt.isInvalid()) ||
+ (ThenStmt.isInvalid() && ElseStmt.get() == 0) ||
+ (ThenStmt.get() == 0 && ElseStmt.isInvalid())) {
+ // Both invalid, or one is invalid and other is non-present: return error.
+ return StmtError();
+ }
+
+ // Now if either are invalid, replace with a ';'.
+ if (ThenStmt.isInvalid())
+ ThenStmt = Actions.ActOnNullStmt(ThenStmtLoc);
+ if (ElseStmt.isInvalid())
+ ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc);
+
+ return Actions.ActOnIfStmt(IfLoc, Actions.FullExpr(CondExp), move(ThenStmt),
+ ElseLoc, move(ElseStmt));
+}
+
+/// ParseSwitchStatement
+/// switch-statement:
+/// 'switch' '(' expression ')' statement
+/// [C++] 'switch' '(' condition ')' statement
+Parser::OwningStmtResult Parser::ParseSwitchStatement() {
+ assert(Tok.is(tok::kw_switch) && "Not a switch stmt!");
+ SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'.
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "switch";
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+
+ bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
+
+ // C99 6.8.4p3 - In C99, the switch statement is a block. This is
+ // not the case for C90. Start the switch scope.
+ //
+ // C++ 6.4p3:
+ // A name introduced by a declaration in a condition is in scope from its
+ // point of declaration until the end of the substatements controlled by the
+ // condition.
+ // C++ 3.3.2p4:
+ // Names declared in the for-init-statement, and in the condition of if,
+ // while, for, and switch statements are local to the if, while, for, or
+ // switch statement (including the controlled statement).
+ //
+ unsigned ScopeFlags = Scope::BreakScope;
+ if (C99orCXX)
+ ScopeFlags |= Scope::DeclScope | Scope::ControlScope;
+ ParseScope SwitchScope(this, ScopeFlags);
+
+ // Parse the condition.
+ OwningExprResult Cond(Actions);
+ if (ParseParenExprOrCondition(Cond))
+ return StmtError();
+
+ OwningStmtResult Switch(Actions);
+ if (!Cond.isInvalid())
+ Switch = Actions.ActOnStartOfSwitchStmt(move(Cond));
+
+ // 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.
+ //
+ // C++ 6.4p1:
+ // The substatement in a selection-statement (each substatement, in the else
+ // form of the if statement) implicitly defines a local scope.
+ //
+ // See comments in ParseIfStatement for why we create a scope for the
+ // condition and a new scope for substatement in C++.
+ //
+ ParseScope InnerScope(this, Scope::DeclScope,
+ C99orCXX && Tok.isNot(tok::l_brace));
+
+ // Read the body statement.
+ OwningStmtResult Body(ParseStatement());
+
+ // Pop the body scope if needed.
+ InnerScope.Exit();
+
+ if (Body.isInvalid()) {
+ Body = Actions.ActOnNullStmt(Tok.getLocation());
+ // FIXME: Remove the case statement list from the Switch statement.
+ }
+
+ SwitchScope.Exit();
+
+ if (Cond.isInvalid())
+ return StmtError();
+
+ return Actions.ActOnFinishSwitchStmt(SwitchLoc, move(Switch), move(Body));
+}
+
+/// ParseWhileStatement
+/// while-statement: [C99 6.8.5.1]
+/// 'while' '(' expression ')' statement
+/// [C++] 'while' '(' condition ')' statement
+Parser::OwningStmtResult Parser::ParseWhileStatement() {
+ assert(Tok.is(tok::kw_while) && "Not a while stmt!");
+ SourceLocation WhileLoc = Tok.getLocation();
+ ConsumeToken(); // eat the 'while'.
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "while";
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+
+ bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
+
+ // C99 6.8.5p5 - In C99, the while statement is a block. This is not
+ // the case for C90. Start the loop scope.
+ //
+ // C++ 6.4p3:
+ // A name introduced by a declaration in a condition is in scope from its
+ // point of declaration until the end of the substatements controlled by the
+ // condition.
+ // C++ 3.3.2p4:
+ // Names declared in the for-init-statement, and in the condition of if,
+ // while, for, and switch statements are local to the if, while, for, or
+ // switch statement (including the controlled statement).
+ //
+ unsigned ScopeFlags;
+ if (C99orCXX)
+ ScopeFlags = Scope::BreakScope | Scope::ContinueScope |
+ Scope::DeclScope | Scope::ControlScope;
+ else
+ ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
+ ParseScope WhileScope(this, ScopeFlags);
+
+ // Parse the condition.
+ OwningExprResult Cond(Actions);
+ if (ParseParenExprOrCondition(Cond))
+ return StmtError();
+
+ // 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
+ // if the body isn't a compound statement to avoid push/pop in common cases.
+ //
+ // C++ 6.5p2:
+ // The substatement in an iteration-statement implicitly defines a local scope
+ // which is entered and exited each time through the loop.
+ //
+ // See comments in ParseIfStatement for why we create a scope for the
+ // condition and a new scope for substatement in C++.
+ //
+ ParseScope InnerScope(this, Scope::DeclScope,
+ C99orCXX && Tok.isNot(tok::l_brace));
+
+ // Read the body statement.
+ OwningStmtResult Body(ParseStatement());
+
+ // Pop the body scope if needed.
+ InnerScope.Exit();
+ WhileScope.Exit();
+
+ if (Cond.isInvalid() || Body.isInvalid())
+ return StmtError();
+
+ return Actions.ActOnWhileStmt(WhileLoc, Actions.FullExpr(Cond), move(Body));
+}
+
+/// ParseDoStatement
+/// do-statement: [C99 6.8.5.2]
+/// 'do' statement 'while' '(' expression ')' ';'
+/// Note: this lets the caller parse the end ';'.
+Parser::OwningStmtResult Parser::ParseDoStatement() {
+ assert(Tok.is(tok::kw_do) && "Not a do stmt!");
+ SourceLocation DoLoc = ConsumeToken(); // eat the 'do'.
+
+ // C99 6.8.5p5 - In C99, the do statement is a block. This is not
+ // the case for C90. Start the loop scope.
+ unsigned ScopeFlags;
+ if (getLang().C99)
+ ScopeFlags = Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope;
+ else
+ ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
+
+ ParseScope DoScope(this, ScopeFlags);
+
+ // 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
+ // if the body isn't a compound statement to avoid push/pop in common cases.
+ //
+ // C++ 6.5p2:
+ // The substatement in an iteration-statement implicitly defines a local scope
+ // which is entered and exited each time through the loop.
+ //
+ ParseScope InnerScope(this, Scope::DeclScope,
+ (getLang().C99 || getLang().CPlusPlus) &&
+ Tok.isNot(tok::l_brace));
+
+ // Read the body statement.
+ OwningStmtResult Body(ParseStatement());
+
+ // Pop the body scope if needed.
+ InnerScope.Exit();
+
+ if (Tok.isNot(tok::kw_while)) {
+ if (!Body.isInvalid()) {
+ Diag(Tok, diag::err_expected_while);
+ Diag(DoLoc, diag::note_matching) << "do";
+ SkipUntil(tok::semi, false, true);
+ }
+ return StmtError();
+ }
+ SourceLocation WhileLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "do/while";
+ SkipUntil(tok::semi, false, true);
+ return StmtError();
+ }
+
+ // Parse the parenthesized condition.
+ OwningExprResult Cond(Actions);
+ ParseParenExprOrCondition(Cond, true);
+
+ DoScope.Exit();
+
+ if (Cond.isInvalid() || Body.isInvalid())
+ return StmtError();
+
+ return Actions.ActOnDoStmt(DoLoc, move(Body), WhileLoc, move(Cond));
+}
+
+/// ParseForStatement
+/// for-statement: [C99 6.8.5.3]
+/// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
+/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
+/// [C++] 'for' '(' for-init-statement condition[opt] ';' expression[opt] ')'
+/// [C++] statement
+/// [OBJC2] 'for' '(' declaration 'in' expr ')' statement
+/// [OBJC2] 'for' '(' expr 'in' expr ')' statement
+///
+/// [C++] for-init-statement:
+/// [C++] expression-statement
+/// [C++] simple-declaration
+///
+Parser::OwningStmtResult Parser::ParseForStatement() {
+ assert(Tok.is(tok::kw_for) && "Not a for stmt!");
+ SourceLocation ForLoc = ConsumeToken(); // eat the 'for'.
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "for";
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+
+ bool C99orCXXorObjC = getLang().C99 || getLang().CPlusPlus || getLang().ObjC1;
+
+ // C99 6.8.5p5 - In C99, the for statement is a block. This is not
+ // the case for C90. Start the loop scope.
+ //
+ // C++ 6.4p3:
+ // A name introduced by a declaration in a condition is in scope from its
+ // point of declaration until the end of the substatements controlled by the
+ // condition.
+ // C++ 3.3.2p4:
+ // Names declared in the for-init-statement, and in the condition of if,
+ // while, for, and switch statements are local to the if, while, for, or
+ // switch statement (including the controlled statement).
+ // C++ 6.5.3p1:
+ // Names declared in the for-init-statement are in the same declarative-region
+ // as those declared in the condition.
+ //
+ unsigned ScopeFlags;
+ if (C99orCXXorObjC)
+ ScopeFlags = Scope::BreakScope | Scope::ContinueScope |
+ Scope::DeclScope | Scope::ControlScope;
+ else
+ ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
+
+ ParseScope ForScope(this, ScopeFlags);
+
+ SourceLocation LParenLoc = ConsumeParen();
+ OwningExprResult Value(Actions);
+
+ bool ForEach = false;
+ OwningStmtResult FirstPart(Actions);
+ OwningExprResult SecondPart(Actions), ThirdPart(Actions);
+
+ // Parse the first part of the for specifier.
+ if (Tok.is(tok::semi)) { // for (;
+ // no first part, eat the ';'.
+ ConsumeToken();
+ } else if (isSimpleDeclaration()) { // for (int X = 4;
+ // Parse declaration, which eats the ';'.
+ if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode?
+ Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
+
+ SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
+ DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd,
+ false);
+ FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
+
+ if (Tok.is(tok::semi)) { // for (int x = 4;
+ ConsumeToken();
+ } else if ((ForEach = isTokIdentifier_in())) {
+ // ObjC: for (id x in expr)
+ ConsumeToken(); // consume 'in'
+ SecondPart = ParseExpression();
+ } else {
+ Diag(Tok, diag::err_expected_semi_for);
+ SkipUntil(tok::semi);
+ }
+ } else {
+ Value = ParseExpression();
+
+ // Turn the expression into a stmt.
+ if (!Value.isInvalid())
+ FirstPart = Actions.ActOnExprStmt(Actions.FullExpr(Value));
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ } else if ((ForEach = isTokIdentifier_in())) {
+ ConsumeToken(); // consume 'in'
+ SecondPart = ParseExpression();
+ } else {
+ if (!Value.isInvalid()) Diag(Tok, diag::err_expected_semi_for);
+ SkipUntil(tok::semi);
+ }
+ }
+ if (!ForEach) {
+ assert(!SecondPart.get() && "Shouldn't have a second expression yet.");
+ // Parse the second part of the for specifier.
+ if (Tok.is(tok::semi)) { // for (...;;
+ // no second part.
+ } else {
+ SecondPart =getLang().CPlusPlus ? ParseCXXCondition() : ParseExpression();
+ }
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ } else {
+ if (!SecondPart.isInvalid()) Diag(Tok, diag::err_expected_semi_for);
+ SkipUntil(tok::semi);
+ }
+
+ // Parse the third part of the for specifier.
+ if (Tok.isNot(tok::r_paren)) // for (...;...;)
+ ThirdPart = ParseExpression();
+ }
+ // Match the ')'.
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ // 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
+ // if the body isn't a compound statement to avoid push/pop in common cases.
+ //
+ // C++ 6.5p2:
+ // The substatement in an iteration-statement implicitly defines a local scope
+ // which is entered and exited each time through the loop.
+ //
+ // See comments in ParseIfStatement for why we create a scope for
+ // for-init-statement/condition and a new scope for substatement in C++.
+ //
+ ParseScope InnerScope(this, Scope::DeclScope,
+ C99orCXXorObjC && Tok.isNot(tok::l_brace));
+
+ // Read the body statement.
+ OwningStmtResult Body(ParseStatement());
+
+ // Pop the body scope if needed.
+ InnerScope.Exit();
+
+ // Leave the for-scope.
+ ForScope.Exit();
+
+ if (Body.isInvalid())
+ return StmtError();
+
+ if (!ForEach)
+ return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart),
+ move(SecondPart), move(ThirdPart),
+ RParenLoc, move(Body));
+
+ return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc,
+ move(FirstPart),
+ move(SecondPart),
+ RParenLoc, move(Body));
+}
+
+/// ParseGotoStatement
+/// jump-statement:
+/// 'goto' identifier ';'
+/// [GNU] 'goto' '*' expression ';'
+///
+/// Note: this lets the caller parse the end ';'.
+///
+Parser::OwningStmtResult Parser::ParseGotoStatement() {
+ assert(Tok.is(tok::kw_goto) && "Not a goto stmt!");
+ SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'.
+
+ OwningStmtResult Res(Actions);
+ if (Tok.is(tok::identifier)) {
+ Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(),
+ Tok.getIdentifierInfo());
+ ConsumeToken();
+ } else if (Tok.is(tok::star)) {
+ // GNU indirect goto extension.
+ Diag(Tok, diag::ext_gnu_indirect_goto);
+ SourceLocation StarLoc = ConsumeToken();
+ OwningExprResult R(ParseExpression());
+ if (R.isInvalid()) { // Skip to the semicolon, but don't consume it.
+ SkipUntil(tok::semi, false, true);
+ return StmtError();
+ }
+ Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, move(R));
+ } else {
+ Diag(Tok, diag::err_expected_ident);
+ return StmtError();
+ }
+
+ return move(Res);
+}
+
+/// ParseContinueStatement
+/// jump-statement:
+/// 'continue' ';'
+///
+/// Note: this lets the caller parse the end ';'.
+///
+Parser::OwningStmtResult Parser::ParseContinueStatement() {
+ SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'.
+ return Actions.ActOnContinueStmt(ContinueLoc, CurScope);
+}
+
+/// ParseBreakStatement
+/// jump-statement:
+/// 'break' ';'
+///
+/// Note: this lets the caller parse the end ';'.
+///
+Parser::OwningStmtResult Parser::ParseBreakStatement() {
+ SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'.
+ return Actions.ActOnBreakStmt(BreakLoc, CurScope);
+}
+
+/// ParseReturnStatement
+/// jump-statement:
+/// 'return' expression[opt] ';'
+Parser::OwningStmtResult Parser::ParseReturnStatement() {
+ assert(Tok.is(tok::kw_return) && "Not a return stmt!");
+ SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'.
+
+ OwningExprResult R(Actions);
+ if (Tok.isNot(tok::semi)) {
+ R = ParseExpression();
+ if (R.isInvalid()) { // Skip to the semicolon, but don't consume it.
+ SkipUntil(tok::semi, false, true);
+ return StmtError();
+ }
+ }
+ return Actions.ActOnReturnStmt(ReturnLoc, Actions.FullExpr(R));
+}
+
+/// FuzzyParseMicrosoftAsmStatement. When -fms-extensions is enabled, this
+/// routine is called to skip/ignore tokens that comprise the MS asm statement.
+Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() {
+ if (Tok.is(tok::l_brace)) {
+ unsigned short savedBraceCount = BraceCount;
+ do {
+ 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();
+ SourceLocation TokLoc = Tok.getLocation();
+ unsigned LineNo = SrcMgr.getInstantiationLineNumber(TokLoc);
+ do {
+ ConsumeAnyToken();
+ TokLoc = Tok.getLocation();
+ } while ((SrcMgr.getInstantiationLineNumber(TokLoc) == LineNo) &&
+ Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) &&
+ Tok.isNot(tok::eof));
+ }
+ return Actions.ActOnNullStmt(Tok.getLocation());
+}
+
+/// ParseAsmStatement - Parse a GNU extended asm statement.
+/// asm-statement:
+/// gnu-asm-statement
+/// ms-asm-statement
+///
+/// [GNU] gnu-asm-statement:
+/// 'asm' type-qualifier[opt] '(' asm-argument ')' ';'
+///
+/// [GNU] asm-argument:
+/// asm-string-literal
+/// asm-string-literal ':' asm-operands[opt]
+/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
+/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
+/// ':' asm-clobbers
+///
+/// [GNU] asm-clobbers:
+/// asm-string-literal
+/// asm-clobbers ',' asm-string-literal
+///
+/// [MS] ms-asm-statement:
+/// '__asm' assembly-instruction ';'[opt]
+/// '__asm' '{' assembly-instruction-list '}' ';'[opt]
+///
+/// [MS] assembly-instruction-list:
+/// assembly-instruction ';'[opt]
+/// assembly-instruction-list ';' assembly-instruction ';'[opt]
+///
+Parser::OwningStmtResult 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()) {
+ msAsm = true;
+ return FuzzyParseMicrosoftAsmStatement();
+ }
+ DeclSpec DS;
+ SourceLocation Loc = Tok.getLocation();
+ ParseTypeQualifierListOpt(DS);
+
+ // GNU asms accept, but warn, about type-qualifiers other than volatile.
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
+ Diag(Loc, diag::w_asm_qualifier_ignored) << "const";
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
+ Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict";
+
+ // Remember if this was a volatile asm.
+ bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;
+ bool isSimple = false;
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "asm";
+ SkipUntil(tok::r_paren);
+ return StmtError();
+ }
+ Loc = ConsumeParen();
+
+ OwningExprResult AsmString(ParseAsmStringLiteral());
+ if (AsmString.isInvalid())
+ return StmtError();
+
+ llvm::SmallVector<std::string, 4> Names;
+ ExprVector Constraints(Actions);
+ ExprVector Exprs(Actions);
+ ExprVector Clobbers(Actions);
+
+ unsigned NumInputs = 0, NumOutputs = 0;
+
+ SourceLocation RParenLoc;
+ if (Tok.is(tok::r_paren)) {
+ // We have a simple asm expression
+ isSimple = true;
+
+ RParenLoc = ConsumeParen();
+ } else {
+ // Parse Outputs, if present.
+ if (ParseAsmOperandsOpt(Names, Constraints, Exprs))
+ return StmtError();
+
+ NumOutputs = Names.size();
+
+ // Parse Inputs, if present.
+ if (ParseAsmOperandsOpt(Names, Constraints, Exprs))
+ return StmtError();
+
+ assert(Names.size() == Constraints.size() &&
+ Constraints.size() == Exprs.size()
+ && "Input operand size mismatch!");
+
+ NumInputs = Names.size() - NumOutputs;
+
+ // Parse the clobbers, if present.
+ if (Tok.is(tok::colon)) {
+ ConsumeToken();
+
+ // Parse the asm-string list for clobbers.
+ while (1) {
+ OwningExprResult Clobber(ParseAsmStringLiteral());
+
+ if (Clobber.isInvalid())
+ break;
+
+ Clobbers.push_back(Clobber.release());
+
+ if (Tok.isNot(tok::comma)) break;
+ ConsumeToken();
+ }
+ }
+
+ RParenLoc = MatchRHSPunctuation(tok::r_paren, Loc);
+ }
+
+ return Actions.ActOnAsmStmt(AsmLoc, isSimple, isVolatile,
+ NumOutputs, NumInputs, Names.data(),
+ move_arg(Constraints), move_arg(Exprs),
+ move(AsmString), move_arg(Clobbers),
+ RParenLoc);
+}
+
+/// ParseAsmOperands - Parse the asm-operands production as used by
+/// asm-statement. We also parse a leading ':' token. If the leading colon is
+/// not present, we do not parse anything.
+///
+/// [GNU] asm-operands:
+/// asm-operand
+/// asm-operands ',' asm-operand
+///
+/// [GNU] asm-operand:
+/// asm-string-literal '(' expression ')'
+/// '[' identifier ']' asm-string-literal '(' expression ')'
+///
+bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names,
+ llvm::SmallVectorImpl<ExprTy*> &Constraints,
+ llvm::SmallVectorImpl<ExprTy*> &Exprs) {
+ // Only do anything if this operand is present.
+ if (Tok.isNot(tok::colon)) return false;
+ ConsumeToken();
+
+ // 'asm-operands' isn't present?
+ if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
+ return false;
+
+ while (1) {
+ // Read the [id] if present.
+ if (Tok.is(tok::l_square)) {
+ SourceLocation Loc = ConsumeBracket();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::r_paren);
+ return true;
+ }
+
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ ConsumeToken();
+
+ Names.push_back(std::string(II->getName(), II->getLength()));
+ MatchRHSPunctuation(tok::r_square, Loc);
+ } else
+ Names.push_back(std::string());
+
+ OwningExprResult Constraint(ParseAsmStringLiteral());
+ if (Constraint.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return true;
+ }
+ Constraints.push_back(Constraint.release());
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "asm operand";
+ SkipUntil(tok::r_paren);
+ return true;
+ }
+
+ // Read the parenthesized expression.
+ SourceLocation OpenLoc = ConsumeParen();
+ OwningExprResult Res(ParseExpression());
+ MatchRHSPunctuation(tok::r_paren, OpenLoc);
+ if (Res.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return true;
+ }
+ Exprs.push_back(Res.release());
+ // Eat the comma and continue parsing if it exists.
+ if (Tok.isNot(tok::comma)) return false;
+ ConsumeToken();
+ }
+
+ return true;
+}
+
+Parser::DeclPtrTy Parser::ParseFunctionStatementBody(DeclPtrTy Decl) {
+ assert(Tok.is(tok::l_brace));
+ SourceLocation LBraceLoc = Tok.getLocation();
+
+ PrettyStackTraceActionsDecl CrashInfo(Decl, LBraceLoc, Actions,
+ PP.getSourceManager(),
+ "parsing function body");
+
+ // Do not enter a scope for the brace, as the arguments are in the same scope
+ // (the function body) as the body itself. Instead, just read the statement
+ // list and put it into a CompoundStmt for safe keeping.
+ OwningStmtResult FnBody(ParseCompoundStatementBody());
+
+ // If the function body could not be parsed, make a bogus compoundstmt.
+ if (FnBody.isInvalid())
+ FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
+ MultiStmtArg(Actions), false);
+
+ return Actions.ActOnFinishFunctionBody(Decl, move(FnBody));
+}
+
+/// ParseFunctionTryBlock - Parse a C++ function-try-block.
+///
+/// function-try-block:
+/// 'try' ctor-initializer[opt] compound-statement handler-seq
+///
+Parser::DeclPtrTy Parser::ParseFunctionTryBlock(DeclPtrTy Decl) {
+ assert(Tok.is(tok::kw_try) && "Expected 'try'");
+ SourceLocation TryLoc = ConsumeToken();
+
+ PrettyStackTraceActionsDecl CrashInfo(Decl, TryLoc, Actions,
+ PP.getSourceManager(),
+ "parsing function try block");
+
+ // Constructor initializer list?
+ if (Tok.is(tok::colon))
+ ParseConstructorInitializer(Decl);
+
+ SourceLocation LBraceLoc = Tok.getLocation();
+ OwningStmtResult FnBody(ParseCXXTryBlockCommon(TryLoc));
+ // If we failed to parse the try-catch, we just give the function an empty
+ // compound statement as the body.
+ if (FnBody.isInvalid())
+ FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
+ MultiStmtArg(Actions), false);
+
+ return Actions.ActOnFinishFunctionBody(Decl, move(FnBody));
+}
+
+/// ParseCXXTryBlock - Parse a C++ try-block.
+///
+/// try-block:
+/// 'try' compound-statement handler-seq
+///
+Parser::OwningStmtResult Parser::ParseCXXTryBlock() {
+ assert(Tok.is(tok::kw_try) && "Expected 'try'");
+
+ SourceLocation TryLoc = ConsumeToken();
+ return ParseCXXTryBlockCommon(TryLoc);
+}
+
+/// ParseCXXTryBlockCommon - Parse the common part of try-block and
+/// function-try-block.
+///
+/// try-block:
+/// 'try' compound-statement handler-seq
+///
+/// function-try-block:
+/// 'try' ctor-initializer[opt] compound-statement handler-seq
+///
+/// handler-seq:
+/// handler handler-seq[opt]
+///
+Parser::OwningStmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
+ if (Tok.isNot(tok::l_brace))
+ return StmtError(Diag(Tok, diag::err_expected_lbrace));
+ OwningStmtResult TryBlock(ParseCompoundStatement());
+ if (TryBlock.isInvalid())
+ return move(TryBlock);
+
+ StmtVector Handlers(Actions);
+ if (Tok.isNot(tok::kw_catch))
+ return StmtError(Diag(Tok, diag::err_expected_catch));
+ while (Tok.is(tok::kw_catch)) {
+ OwningStmtResult Handler(ParseCXXCatchBlock());
+ if (!Handler.isInvalid())
+ Handlers.push_back(Handler.release());
+ }
+ // Don't bother creating the full statement if we don't have any usable
+ // handlers.
+ if (Handlers.empty())
+ return StmtError();
+
+ return Actions.ActOnCXXTryBlock(TryLoc, move(TryBlock), move_arg(Handlers));
+}
+
+/// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard
+///
+/// handler:
+/// 'catch' '(' exception-declaration ')' compound-statement
+///
+/// exception-declaration:
+/// type-specifier-seq declarator
+/// type-specifier-seq abstract-declarator
+/// type-specifier-seq
+/// '...'
+///
+Parser::OwningStmtResult Parser::ParseCXXCatchBlock() {
+ assert(Tok.is(tok::kw_catch) && "Expected 'catch'");
+
+ SourceLocation CatchLoc = ConsumeToken();
+
+ SourceLocation LParenLoc = Tok.getLocation();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen))
+ return StmtError();
+
+ // C++ 3.3.2p3:
+ // The name in a catch exception-declaration is local to the handler and
+ // shall not be redeclared in the outermost block of the handler.
+ ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope);
+
+ // exception-declaration is equivalent to '...' or a parameter-declaration
+ // without default arguments.
+ DeclPtrTy ExceptionDecl;
+ if (Tok.isNot(tok::ellipsis)) {
+ DeclSpec DS;
+ if (ParseCXXTypeSpecifierSeq(DS))
+ return StmtError();
+ Declarator ExDecl(DS, Declarator::CXXCatchContext);
+ ParseDeclarator(ExDecl);
+ ExceptionDecl = Actions.ActOnExceptionDeclarator(CurScope, ExDecl);
+ } else
+ ConsumeToken();
+
+ if (MatchRHSPunctuation(tok::r_paren, LParenLoc).isInvalid())
+ return StmtError();
+
+ if (Tok.isNot(tok::l_brace))
+ return StmtError(Diag(Tok, diag::err_expected_lbrace));
+
+ OwningStmtResult Block(ParseCompoundStatement());
+ if (Block.isInvalid())
+ return move(Block);
+
+ return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, move(Block));
+}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
new file mode 100644
index 000000000000..2a79b99d29c9
--- /dev/null
+++ b/lib/Parse/ParseTemplate.cpp
@@ -0,0 +1,812 @@
+//===--- ParseTemplate.cpp - Template Parsing -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements parsing of C++ templates.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+using namespace clang;
+
+/// \brief Parse a template declaration, explicit instantiation, or
+/// explicit specialization.
+Parser::DeclPtrTy
+Parser::ParseDeclarationStartingWithTemplate(unsigned Context,
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS) {
+ if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less))
+ return ParseExplicitInstantiation(ConsumeToken(), DeclEnd);
+
+ return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS);
+}
+
+/// \brief Parse a template declaration or an explicit specialization.
+///
+/// Template declarations include one or more template parameter lists
+/// and either the function or class template declaration. Explicit
+/// specializations contain one or more 'template < >' prefixes
+/// followed by a (possibly templated) declaration. Since the
+/// syntactic form of both features is nearly identical, we parse all
+/// of the template headers together and let semantic analysis sort
+/// the declarations from the explicit specializations.
+///
+/// template-declaration: [C++ temp]
+/// 'export'[opt] 'template' '<' template-parameter-list '>' declaration
+///
+/// explicit-specialization: [ C++ temp.expl.spec]
+/// 'template' '<' '>' declaration
+Parser::DeclPtrTy
+Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS) {
+ assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) &&
+ "Token does not start a template declaration.");
+
+ // Enter template-parameter scope.
+ ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
+
+ // Parse multiple levels of template headers within this template
+ // parameter scope, e.g.,
+ //
+ // template<typename T>
+ // template<typename U>
+ // class A<T>::B { ... };
+ //
+ // We parse multiple levels non-recursively so that we can build a
+ // single data structure containing all of the template parameter
+ // lists to easily differentiate between the case above and:
+ //
+ // template<typename T>
+ // class A {
+ // template<typename U> class B;
+ // };
+ //
+ // In the first case, the action for declaring A<T>::B receives
+ // both template parameter lists. In the second case, the action for
+ // defining A<T>::B receives just the inner template parameter list
+ // (and retrieves the outer template parameter list from its
+ // context).
+ bool isSpecialiation = true;
+ TemplateParameterLists ParamLists;
+ do {
+ // Consume the 'export', if any.
+ SourceLocation ExportLoc;
+ if (Tok.is(tok::kw_export)) {
+ ExportLoc = ConsumeToken();
+ }
+
+ // Consume the 'template', which should be here.
+ SourceLocation TemplateLoc;
+ if (Tok.is(tok::kw_template)) {
+ TemplateLoc = ConsumeToken();
+ } else {
+ Diag(Tok.getLocation(), diag::err_expected_template);
+ return DeclPtrTy();
+ }
+
+ // Parse the '<' template-parameter-list '>'
+ SourceLocation LAngleLoc, RAngleLoc;
+ TemplateParameterList TemplateParams;
+ ParseTemplateParameters(ParamLists.size(), TemplateParams, LAngleLoc,
+ RAngleLoc);
+
+ if (!TemplateParams.empty())
+ isSpecialiation = false;
+
+ ParamLists.push_back(
+ Actions.ActOnTemplateParameterList(ParamLists.size(), ExportLoc,
+ TemplateLoc, LAngleLoc,
+ TemplateParams.data(),
+ TemplateParams.size(), RAngleLoc));
+ } while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template));
+
+ // Parse the actual template declaration.
+ return ParseSingleDeclarationAfterTemplate(Context,
+ ParsedTemplateInfo(&ParamLists,
+ isSpecialiation),
+ DeclEnd, AS);
+}
+
+/// \brief Parse a single declaration that declares a template,
+/// template specialization, or explicit instantiation of a template.
+///
+/// \param TemplateParams if non-NULL, the template parameter lists
+/// that preceded this declaration. In this case, the declaration is a
+/// template declaration, out-of-line definition of a template, or an
+/// explicit template specialization. When NULL, the declaration is an
+/// explicit template instantiation.
+///
+/// \param TemplateLoc when TemplateParams is NULL, the location of
+/// the 'template' keyword that indicates that we have an explicit
+/// template instantiation.
+///
+/// \param DeclEnd will receive the source location of the last token
+/// within this declaration.
+///
+/// \param AS the access specifier associated with this
+/// declaration. Will be AS_none for namespace-scope declarations.
+///
+/// \returns the new declaration.
+Parser::DeclPtrTy
+Parser::ParseSingleDeclarationAfterTemplate(
+ unsigned Context,
+ const ParsedTemplateInfo &TemplateInfo,
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS) {
+ assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
+ "Template information required");
+
+ // Parse the declaration specifiers.
+ DeclSpec DS;
+ // FIXME: Pass TemplateLoc through for explicit template instantiations
+ ParseDeclarationSpecifiers(DS, TemplateInfo, AS);
+
+ if (Tok.is(tok::semi)) {
+ DeclEnd = ConsumeToken();
+ return Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ }
+
+ // Parse the declarator.
+ Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context);
+ ParseDeclarator(DeclaratorInfo);
+ // Error parsing the declarator?
+ if (!DeclaratorInfo.hasName()) {
+ // If so, skip until the semi-colon or a }.
+ SkipUntil(tok::r_brace, true, true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ return DeclPtrTy();
+ }
+
+ // If we have a declaration or declarator list, handle it.
+ if (isDeclarationAfterDeclarator()) {
+ // Parse this declaration.
+ DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo);
+
+ if (Tok.is(tok::comma)) {
+ Diag(Tok, diag::err_multiple_template_declarators)
+ << (int)TemplateInfo.Kind;
+ SkipUntil(tok::semi, true, false);
+ return ThisDecl;
+ }
+
+ // Eat the semi colon after the declaration.
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_declation);
+ return ThisDecl;
+ }
+
+ if (DeclaratorInfo.isFunctionDeclarator() &&
+ isStartOfFunctionDefinition()) {
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ Diag(Tok, diag::err_function_declared_typedef);
+
+ if (Tok.is(tok::l_brace)) {
+ // This recovery skips the entire function body. It would be nice
+ // to simply call ParseFunctionDefinition() below, however Sema
+ // assumes the declarator represents a function, not a typedef.
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, true);
+ } else {
+ SkipUntil(tok::semi);
+ }
+ return DeclPtrTy();
+ }
+ return ParseFunctionDefinition(DeclaratorInfo);
+ }
+
+ if (DeclaratorInfo.isFunctionDeclarator())
+ Diag(Tok, diag::err_expected_fn_body);
+ else
+ Diag(Tok, diag::err_invalid_token_after_toplevel_declarator);
+ SkipUntil(tok::semi);
+ return DeclPtrTy();
+}
+
+/// ParseTemplateParameters - Parses a template-parameter-list enclosed in
+/// angle brackets. Depth is the depth of this template-parameter-list, which
+/// is the number of template headers directly enclosing this template header.
+/// TemplateParams is the current list of template parameters we're building.
+/// The template parameter we parse will be added to this list. LAngleLoc and
+/// RAngleLoc will receive the positions of the '<' and '>', respectively,
+/// that enclose this template parameter list.
+bool Parser::ParseTemplateParameters(unsigned Depth,
+ TemplateParameterList &TemplateParams,
+ SourceLocation &LAngleLoc,
+ SourceLocation &RAngleLoc) {
+ // Get the template parameter list.
+ if(!Tok.is(tok::less)) {
+ Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
+ return false;
+ }
+ LAngleLoc = ConsumeToken();
+
+ // Try to parse the template parameter list.
+ if (Tok.is(tok::greater))
+ RAngleLoc = ConsumeToken();
+ else if(ParseTemplateParameterList(Depth, TemplateParams)) {
+ if(!Tok.is(tok::greater)) {
+ Diag(Tok.getLocation(), diag::err_expected_greater);
+ return false;
+ }
+ RAngleLoc = ConsumeToken();
+ }
+ return true;
+}
+
+/// ParseTemplateParameterList - Parse a template parameter list. If
+/// the parsing fails badly (i.e., closing bracket was left out), this
+/// will try to put the token stream in a reasonable position (closing
+/// a statement, etc.) and return false.
+///
+/// template-parameter-list: [C++ temp]
+/// template-parameter
+/// template-parameter-list ',' template-parameter
+bool
+Parser::ParseTemplateParameterList(unsigned Depth,
+ TemplateParameterList &TemplateParams) {
+ while(1) {
+ if (DeclPtrTy TmpParam
+ = ParseTemplateParameter(Depth, TemplateParams.size())) {
+ TemplateParams.push_back(TmpParam);
+ } else {
+ // If we failed to parse a template parameter, skip until we find
+ // a comma or closing brace.
+ SkipUntil(tok::comma, tok::greater, true, true);
+ }
+
+ // Did we find a comma or the end of the template parmeter list?
+ if(Tok.is(tok::comma)) {
+ ConsumeToken();
+ } else if(Tok.is(tok::greater)) {
+ // Don't consume this... that's done by template parser.
+ break;
+ } else {
+ // Somebody probably forgot to close the template. Skip ahead and
+ // try to get out of the expression. This error is currently
+ // subsumed by whatever goes on in ParseTemplateParameter.
+ // TODO: This could match >>, and it would be nice to avoid those
+ // silly errors with template <vec<T>>.
+ // Diag(Tok.getLocation(), diag::err_expected_comma_greater);
+ SkipUntil(tok::greater, true, true);
+ return false;
+ }
+ }
+ return true;
+}
+
+/// ParseTemplateParameter - Parse a template-parameter (C++ [temp.param]).
+///
+/// template-parameter: [C++ temp.param]
+/// type-parameter
+/// parameter-declaration
+///
+/// type-parameter: (see below)
+/// 'class' identifier[opt]
+/// 'class' identifier[opt] '=' type-id
+/// 'typename' identifier[opt]
+/// 'typename' identifier[opt] '=' type-id
+/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
+/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression
+Parser::DeclPtrTy
+Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
+ if(Tok.is(tok::kw_class) ||
+ (Tok.is(tok::kw_typename) &&
+ // FIXME: Next token has not been annotated!
+ NextToken().isNot(tok::annot_typename))) {
+ return ParseTypeParameter(Depth, Position);
+ }
+
+ if(Tok.is(tok::kw_template))
+ return ParseTemplateTemplateParameter(Depth, Position);
+
+ // If it's none of the above, then it must be a parameter declaration.
+ // NOTE: This will pick up errors in the closure of the template parameter
+ // list (e.g., template < ; Check here to implement >> style closures.
+ return ParseNonTypeTemplateParameter(Depth, Position);
+}
+
+/// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]).
+/// Other kinds of template parameters are parsed in
+/// ParseTemplateTemplateParameter and ParseNonTypeTemplateParameter.
+///
+/// type-parameter: [C++ temp.param]
+/// 'class' identifier[opt]
+/// 'class' identifier[opt] '=' type-id
+/// 'typename' identifier[opt]
+/// 'typename' identifier[opt] '=' type-id
+Parser::DeclPtrTy Parser::ParseTypeParameter(unsigned Depth, unsigned Position){
+ assert((Tok.is(tok::kw_class) || Tok.is(tok::kw_typename)) &&
+ "A type-parameter starts with 'class' or 'typename'");
+
+ // Consume the 'class' or 'typename' keyword.
+ bool TypenameKeyword = Tok.is(tok::kw_typename);
+ SourceLocation KeyLoc = ConsumeToken();
+
+ // Grab the template parameter name (if given)
+ SourceLocation NameLoc;
+ IdentifierInfo* ParamName = 0;
+ if(Tok.is(tok::identifier)) {
+ ParamName = Tok.getIdentifierInfo();
+ NameLoc = ConsumeToken();
+ } else if(Tok.is(tok::equal) || Tok.is(tok::comma) ||
+ Tok.is(tok::greater)) {
+ // Unnamed template parameter. Don't have to do anything here, just
+ // don't consume this token.
+ } else {
+ Diag(Tok.getLocation(), diag::err_expected_ident);
+ return DeclPtrTy();
+ }
+
+ DeclPtrTy TypeParam = Actions.ActOnTypeParameter(CurScope, TypenameKeyword,
+ KeyLoc, ParamName, NameLoc,
+ Depth, Position);
+
+ // Grab a default type id (if given).
+ if(Tok.is(tok::equal)) {
+ SourceLocation EqualLoc = ConsumeToken();
+ SourceLocation DefaultLoc = Tok.getLocation();
+ TypeResult DefaultType = ParseTypeName();
+ if (!DefaultType.isInvalid())
+ Actions.ActOnTypeParameterDefault(TypeParam, EqualLoc, DefaultLoc,
+ DefaultType.get());
+ }
+
+ return TypeParam;
+}
+
+/// ParseTemplateTemplateParameter - Handle the parsing of template
+/// template parameters.
+///
+/// type-parameter: [C++ temp.param]
+/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
+/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression
+Parser::DeclPtrTy
+Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
+ assert(Tok.is(tok::kw_template) && "Expected 'template' keyword");
+
+ // Handle the template <...> part.
+ SourceLocation TemplateLoc = ConsumeToken();
+ TemplateParameterList TemplateParams;
+ SourceLocation LAngleLoc, RAngleLoc;
+ {
+ ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
+ if(!ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc,
+ RAngleLoc)) {
+ return DeclPtrTy();
+ }
+ }
+
+ // Generate a meaningful error if the user forgot to put class before the
+ // identifier, comma, or greater.
+ if(!Tok.is(tok::kw_class)) {
+ Diag(Tok.getLocation(), diag::err_expected_class_before)
+ << PP.getSpelling(Tok);
+ return DeclPtrTy();
+ }
+ SourceLocation ClassLoc = ConsumeToken();
+
+ // Get the identifier, if given.
+ SourceLocation NameLoc;
+ IdentifierInfo* ParamName = 0;
+ if(Tok.is(tok::identifier)) {
+ ParamName = Tok.getIdentifierInfo();
+ NameLoc = ConsumeToken();
+ } else if(Tok.is(tok::equal) || Tok.is(tok::comma) || Tok.is(tok::greater)) {
+ // Unnamed template parameter. Don't have to do anything here, just
+ // don't consume this token.
+ } else {
+ Diag(Tok.getLocation(), diag::err_expected_ident);
+ return DeclPtrTy();
+ }
+
+ TemplateParamsTy *ParamList =
+ Actions.ActOnTemplateParameterList(Depth, SourceLocation(),
+ TemplateLoc, LAngleLoc,
+ &TemplateParams[0],
+ TemplateParams.size(),
+ RAngleLoc);
+
+ Parser::DeclPtrTy Param
+ = Actions.ActOnTemplateTemplateParameter(CurScope, TemplateLoc,
+ ParamList, ParamName,
+ NameLoc, Depth, Position);
+
+ // Get the a default value, if given.
+ if (Tok.is(tok::equal)) {
+ SourceLocation EqualLoc = ConsumeToken();
+ OwningExprResult DefaultExpr = ParseCXXIdExpression();
+ if (DefaultExpr.isInvalid())
+ return Param;
+ else if (Param)
+ Actions.ActOnTemplateTemplateParameterDefault(Param, EqualLoc,
+ move(DefaultExpr));
+ }
+
+ return Param;
+}
+
+/// ParseNonTypeTemplateParameter - Handle the parsing of non-type
+/// template parameters (e.g., in "template<int Size> class array;").
+///
+/// template-parameter:
+/// ...
+/// parameter-declaration
+///
+/// NOTE: It would be ideal to simply call out to ParseParameterDeclaration(),
+/// but that didn't work out to well. Instead, this tries to recrate the basic
+/// parsing of parameter declarations, but tries to constrain it for template
+/// parameters.
+/// FIXME: We need to make a ParseParameterDeclaration that works for
+/// non-type template parameters and normal function parameters.
+Parser::DeclPtrTy
+Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
+ SourceLocation StartLoc = Tok.getLocation();
+
+ // Parse the declaration-specifiers (i.e., the type).
+ // FIXME: The type should probably be restricted in some way... Not all
+ // declarators (parts of declarators?) are accepted for parameters.
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS);
+
+ // Parse this as a typename.
+ Declarator ParamDecl(DS, Declarator::TemplateParamContext);
+ ParseDeclarator(ParamDecl);
+ if (DS.getTypeSpecType() == DeclSpec::TST_unspecified && !DS.getTypeRep()) {
+ // This probably shouldn't happen - and it's more of a Sema thing, but
+ // basically we didn't parse the type name because we couldn't associate
+ // it with an AST node. we should just skip to the comma or greater.
+ // TODO: This is currently a placeholder for some kind of Sema Error.
+ Diag(Tok.getLocation(), diag::err_parse_error);
+ SkipUntil(tok::comma, tok::greater, true, true);
+ return DeclPtrTy();
+ }
+
+ // Create the parameter.
+ DeclPtrTy Param = Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl,
+ Depth, Position);
+
+ // If there is a default value, parse it.
+ if (Tok.is(tok::equal)) {
+ SourceLocation EqualLoc = ConsumeToken();
+
+ // C++ [temp.param]p15:
+ // When parsing a default template-argument for a non-type
+ // template-parameter, the first non-nested > is taken as the
+ // end of the template-parameter-list rather than a greater-than
+ // operator.
+ GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
+
+ OwningExprResult DefaultArg = ParseAssignmentExpression();
+ if (DefaultArg.isInvalid())
+ SkipUntil(tok::comma, tok::greater, true, true);
+ else if (Param)
+ Actions.ActOnNonTypeTemplateParameterDefault(Param, EqualLoc,
+ move(DefaultArg));
+ }
+
+ return Param;
+}
+
+/// \brief Parses a template-id that after the template name has
+/// already been parsed.
+///
+/// This routine takes care of parsing the enclosed template argument
+/// list ('<' template-parameter-list [opt] '>') and placing the
+/// results into a form that can be transferred to semantic analysis.
+///
+/// \param Template the template declaration produced by isTemplateName
+///
+/// \param TemplateNameLoc the source location of the template name
+///
+/// \param SS if non-NULL, the nested-name-specifier preceding the
+/// template name.
+///
+/// \param ConsumeLastToken if true, then we will consume the last
+/// token that forms the template-id. Otherwise, we will leave the
+/// last token in the stream (e.g., so that it can be replaced with an
+/// annotation token).
+bool
+Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
+ SourceLocation TemplateNameLoc,
+ const CXXScopeSpec *SS,
+ bool ConsumeLastToken,
+ SourceLocation &LAngleLoc,
+ TemplateArgList &TemplateArgs,
+ TemplateArgIsTypeList &TemplateArgIsType,
+ TemplateArgLocationList &TemplateArgLocations,
+ SourceLocation &RAngleLoc) {
+ assert(Tok.is(tok::less) && "Must have already parsed the template-name");
+
+ // Consume the '<'.
+ LAngleLoc = ConsumeToken();
+
+ // Parse the optional template-argument-list.
+ bool Invalid = false;
+ {
+ GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
+ if (Tok.isNot(tok::greater))
+ Invalid = ParseTemplateArgumentList(TemplateArgs, TemplateArgIsType,
+ TemplateArgLocations);
+
+ if (Invalid) {
+ // Try to find the closing '>'.
+ SkipUntil(tok::greater, true, !ConsumeLastToken);
+
+ return true;
+ }
+ }
+
+ if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater))
+ return true;
+
+ // Determine the location of the '>' or '>>'. Only consume this
+ // token if the caller asked us to.
+ RAngleLoc = Tok.getLocation();
+
+ if (Tok.is(tok::greatergreater)) {
+ if (!getLang().CPlusPlus0x) {
+ const char *ReplaceStr = "> >";
+ if (NextToken().is(tok::greater) || NextToken().is(tok::greatergreater))
+ ReplaceStr = "> > ";
+
+ Diag(Tok.getLocation(), diag::err_two_right_angle_brackets_need_space)
+ << CodeModificationHint::CreateReplacement(
+ SourceRange(Tok.getLocation()), ReplaceStr);
+ }
+
+ Tok.setKind(tok::greater);
+ if (!ConsumeLastToken) {
+ // Since we're not supposed to consume the '>>' token, we need
+ // to insert a second '>' token after the first.
+ PP.EnterToken(Tok);
+ }
+ } else if (ConsumeLastToken)
+ ConsumeToken();
+
+ return false;
+}
+
+/// \brief Replace the tokens that form a simple-template-id with an
+/// annotation token containing the complete template-id.
+///
+/// The first token in the stream must be the name of a template that
+/// is followed by a '<'. This routine will parse the complete
+/// simple-template-id and replace the tokens with a single annotation
+/// token with one of two different kinds: if the template-id names a
+/// type (and \p AllowTypeAnnotation is true), the annotation token is
+/// a type annotation that includes the optional nested-name-specifier
+/// (\p SS). Otherwise, the annotation token is a template-id
+/// annotation that does not include the optional
+/// nested-name-specifier.
+///
+/// \param Template the declaration of the template named by the first
+/// token (an identifier), as returned from \c Action::isTemplateName().
+///
+/// \param TemplateNameKind the kind of template that \p Template
+/// refers to, as returned from \c Action::isTemplateName().
+///
+/// \param SS if non-NULL, the nested-name-specifier that precedes
+/// this template name.
+///
+/// \param TemplateKWLoc if valid, specifies that this template-id
+/// annotation was preceded by the 'template' keyword and gives the
+/// location of that keyword. If invalid (the default), then this
+/// template-id was not preceded by a 'template' keyword.
+///
+/// \param AllowTypeAnnotation if true (the default), then a
+/// simple-template-id that refers to a class template, template
+/// template parameter, or other template that produces a type will be
+/// replaced with a type annotation token. Otherwise, the
+/// simple-template-id is always replaced with a template-id
+/// annotation token.
+void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
+ const CXXScopeSpec *SS,
+ SourceLocation TemplateKWLoc,
+ bool AllowTypeAnnotation) {
+ assert(getLang().CPlusPlus && "Can only annotate template-ids in C++");
+ assert(Template && Tok.is(tok::identifier) && NextToken().is(tok::less) &&
+ "Parser isn't at the beginning of a template-id");
+
+ // Consume the template-name.
+ IdentifierInfo *Name = Tok.getIdentifierInfo();
+ SourceLocation TemplateNameLoc = ConsumeToken();
+
+ // Parse the enclosed template argument list.
+ SourceLocation LAngleLoc, RAngleLoc;
+ TemplateArgList TemplateArgs;
+ TemplateArgIsTypeList TemplateArgIsType;
+ TemplateArgLocationList TemplateArgLocations;
+ bool Invalid = ParseTemplateIdAfterTemplateName(Template, TemplateNameLoc,
+ SS, false, LAngleLoc,
+ TemplateArgs,
+ TemplateArgIsType,
+ TemplateArgLocations,
+ RAngleLoc);
+
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(),
+ TemplateArgIsType.data(),
+ TemplateArgs.size());
+
+ if (Invalid) // FIXME: How to recover from a broken template-id?
+ return;
+
+ // Build the annotation token.
+ if (TNK == TNK_Type_template && AllowTypeAnnotation) {
+ Action::TypeResult Type
+ = Actions.ActOnTemplateIdType(Template, TemplateNameLoc,
+ LAngleLoc, TemplateArgsPtr,
+ &TemplateArgLocations[0],
+ RAngleLoc);
+ if (Type.isInvalid()) // FIXME: better recovery?
+ return;
+
+ Tok.setKind(tok::annot_typename);
+ Tok.setAnnotationValue(Type.get());
+ if (SS && SS->isNotEmpty())
+ Tok.setLocation(SS->getBeginLoc());
+ else if (TemplateKWLoc.isValid())
+ Tok.setLocation(TemplateKWLoc);
+ else
+ Tok.setLocation(TemplateNameLoc);
+ } else {
+ // Build a template-id annotation token that can be processed
+ // later.
+ Tok.setKind(tok::annot_template_id);
+ TemplateIdAnnotation *TemplateId
+ = TemplateIdAnnotation::Allocate(TemplateArgs.size());
+ TemplateId->TemplateNameLoc = TemplateNameLoc;
+ TemplateId->Name = Name;
+ TemplateId->Template = Template.getAs<void*>();
+ TemplateId->Kind = TNK;
+ TemplateId->LAngleLoc = LAngleLoc;
+ TemplateId->RAngleLoc = RAngleLoc;
+ void **Args = TemplateId->getTemplateArgs();
+ bool *ArgIsType = TemplateId->getTemplateArgIsType();
+ SourceLocation *ArgLocs = TemplateId->getTemplateArgLocations();
+ for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) {
+ Args[Arg] = TemplateArgs[Arg];
+ ArgIsType[Arg] = TemplateArgIsType[Arg];
+ ArgLocs[Arg] = TemplateArgLocations[Arg];
+ }
+ Tok.setAnnotationValue(TemplateId);
+ if (TemplateKWLoc.isValid())
+ Tok.setLocation(TemplateKWLoc);
+ else
+ Tok.setLocation(TemplateNameLoc);
+
+ TemplateArgsPtr.release();
+ }
+
+ // Common fields for the annotation token
+ Tok.setAnnotationEndLoc(RAngleLoc);
+
+ // In case the tokens were cached, have Preprocessor replace them with the
+ // annotation token.
+ PP.AnnotateCachedTokens(Tok);
+}
+
+/// \brief Replaces a template-id annotation token with a type
+/// annotation token.
+///
+/// If there was a failure when forming the type from the template-id,
+/// a type annotation token will still be created, but will have a
+/// NULL type pointer to signify an error.
+void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
+ assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens");
+
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ assert((TemplateId->Kind == TNK_Type_template ||
+ TemplateId->Kind == TNK_Dependent_template_name) &&
+ "Only works for type and dependent templates");
+
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions,
+ TemplateId->getTemplateArgs(),
+ TemplateId->getTemplateArgIsType(),
+ TemplateId->NumArgs);
+
+ Action::TypeResult Type
+ = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->getTemplateArgLocations(),
+ TemplateId->RAngleLoc);
+ // Create the new "type" annotation token.
+ Tok.setKind(tok::annot_typename);
+ Tok.setAnnotationValue(Type.isInvalid()? 0 : Type.get());
+ if (SS && SS->isNotEmpty()) // it was a C++ qualified type name.
+ Tok.setLocation(SS->getBeginLoc());
+
+ // We might be backtracking, in which case we need to replace the
+ // template-id annotation token with the type annotation within the
+ // set of cached tokens. That way, we won't try to form the same
+ // class template specialization again.
+ PP.ReplaceLastTokenWithAnnotation(Tok);
+ TemplateId->Destroy();
+}
+
+/// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]).
+///
+/// template-argument: [C++ 14.2]
+/// assignment-expression
+/// type-id
+/// id-expression
+void *Parser::ParseTemplateArgument(bool &ArgIsType) {
+ // C++ [temp.arg]p2:
+ // In a template-argument, an ambiguity between a type-id and an
+ // expression is resolved to a type-id, regardless of the form of
+ // the corresponding template-parameter.
+ //
+ // Therefore, we initially try to parse a type-id.
+ if (isCXXTypeId(TypeIdAsTemplateArgument)) {
+ ArgIsType = true;
+ TypeResult TypeArg = ParseTypeName();
+ if (TypeArg.isInvalid())
+ return 0;
+ return TypeArg.get();
+ }
+
+ OwningExprResult ExprArg = ParseAssignmentExpression();
+ if (ExprArg.isInvalid() || !ExprArg.get())
+ return 0;
+
+ ArgIsType = false;
+ return ExprArg.release();
+}
+
+/// ParseTemplateArgumentList - Parse a C++ template-argument-list
+/// (C++ [temp.names]). Returns true if there was an error.
+///
+/// template-argument-list: [C++ 14.2]
+/// template-argument
+/// template-argument-list ',' template-argument
+bool
+Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
+ TemplateArgIsTypeList &TemplateArgIsType,
+ TemplateArgLocationList &TemplateArgLocations) {
+ while (true) {
+ bool IsType = false;
+ SourceLocation Loc = Tok.getLocation();
+ void *Arg = ParseTemplateArgument(IsType);
+ if (Arg) {
+ TemplateArgs.push_back(Arg);
+ TemplateArgIsType.push_back(IsType);
+ TemplateArgLocations.push_back(Loc);
+ } else {
+ SkipUntil(tok::comma, tok::greater, true, true);
+ return true;
+ }
+
+ // If the next token is a comma, consume it and keep reading
+ // arguments.
+ if (Tok.isNot(tok::comma)) break;
+
+ // Consume the comma.
+ ConsumeToken();
+ }
+
+ return Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater);
+}
+
+/// \brief Parse a C++ explicit template instantiation
+/// (C++ [temp.explicit]).
+///
+/// explicit-instantiation:
+/// 'template' declaration
+Parser::DeclPtrTy
+Parser::ParseExplicitInstantiation(SourceLocation TemplateLoc,
+ SourceLocation &DeclEnd) {
+ return ParseSingleDeclarationAfterTemplate(Declarator::FileContext,
+ ParsedTemplateInfo(TemplateLoc),
+ DeclEnd, AS_none);
+}
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
new file mode 100644
index 000000000000..81696d6a6101
--- /dev/null
+++ b/lib/Parse/ParseTentative.cpp
@@ -0,0 +1,920 @@
+//===--- ParseTentative.cpp - Ambiguity Resolution Parsing ----------------===//
+//
+// 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 tentative parsing portions of the Parser
+// interfaces, for ambiguity resolution.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+using namespace clang;
+
+/// isCXXDeclarationStatement - C++-specialized function that disambiguates
+/// between a declaration or an expression statement, when parsing function
+/// bodies. Returns true for declaration, false for expression.
+///
+/// declaration-statement:
+/// block-declaration
+///
+/// block-declaration:
+/// simple-declaration
+/// asm-definition
+/// namespace-alias-definition
+/// using-declaration
+/// using-directive
+/// [C++0x] static_assert-declaration
+///
+/// asm-definition:
+/// 'asm' '(' string-literal ')' ';'
+///
+/// namespace-alias-definition:
+/// 'namespace' identifier = qualified-namespace-specifier ';'
+///
+/// using-declaration:
+/// 'using' typename[opt] '::'[opt] nested-name-specifier
+/// unqualified-id ';'
+/// 'using' '::' unqualified-id ;
+///
+/// using-directive:
+/// 'using' 'namespace' '::'[opt] nested-name-specifier[opt]
+/// namespace-name ';'
+///
+bool Parser::isCXXDeclarationStatement() {
+ switch (Tok.getKind()) {
+ // asm-definition
+ case tok::kw_asm:
+ // namespace-alias-definition
+ case tok::kw_namespace:
+ // using-declaration
+ // using-directive
+ case tok::kw_using:
+ return true;
+ case tok::kw_static_assert:
+ // static_assert-declaration
+ return true;
+ default:
+ // simple-declaration
+ return isCXXSimpleDeclaration();
+ }
+}
+
+/// isCXXSimpleDeclaration - C++-specialized function that disambiguates
+/// between a simple-declaration or an expression-statement.
+/// If during the disambiguation process a parsing error is encountered,
+/// the function returns true to let the declaration parsing code handle it.
+/// Returns false if the statement is disambiguated as expression.
+///
+/// simple-declaration:
+/// decl-specifier-seq init-declarator-list[opt] ';'
+///
+bool Parser::isCXXSimpleDeclaration() {
+ // C++ 6.8p1:
+ // There is an ambiguity in the grammar involving expression-statements and
+ // declarations: An expression-statement with a function-style explicit type
+ // conversion (5.2.3) as its leftmost subexpression can be indistinguishable
+ // from a declaration where the first declarator starts with a '('. In those
+ // cases the statement is a declaration. [Note: To disambiguate, the whole
+ // statement might have to be examined to determine if it is an
+ // expression-statement or a declaration].
+
+ // C++ 6.8p3:
+ // The disambiguation is purely syntactic; that is, the meaning of the names
+ // occurring in such a statement, beyond whether they are type-names or not,
+ // is not generally used in or changed by the disambiguation. Class
+ // templates are instantiated as necessary to determine if a qualified name
+ // is a type-name. Disambiguation precedes parsing, and a statement
+ // disambiguated as a declaration may be an ill-formed declaration.
+
+ // We don't have to parse all of the decl-specifier-seq part. There's only
+ // an ambiguity if the first decl-specifier is
+ // simple-type-specifier/typename-specifier followed by a '(', which may
+ // indicate a function-style cast expression.
+ // isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such
+ // a case.
+
+ TPResult TPR = isCXXDeclarationSpecifier();
+ if (TPR != TPResult::Ambiguous())
+ return TPR != TPResult::False(); // Returns true for TPResult::True() or
+ // TPResult::Error().
+
+ // FIXME: Add statistics about the number of ambiguous statements encountered
+ // and how they were resolved (number of declarations+number of expressions).
+
+ // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
+ // We need tentative parsing...
+
+ TentativeParsingAction PA(*this);
+
+ TPR = TryParseSimpleDeclaration();
+ SourceLocation TentativeParseLoc = Tok.getLocation();
+
+ PA.Revert();
+
+ // In case of an error, let the declaration parsing code handle it.
+ if (TPR == TPResult::Error())
+ return true;
+
+ // Declarations take precedence over expressions.
+ if (TPR == TPResult::Ambiguous())
+ TPR = TPResult::True();
+
+ assert(TPR == TPResult::True() || TPR == TPResult::False());
+ return TPR == TPResult::True();
+}
+
+/// simple-declaration:
+/// decl-specifier-seq init-declarator-list[opt] ';'
+///
+Parser::TPResult Parser::TryParseSimpleDeclaration() {
+ // We know that we have a simple-type-specifier/typename-specifier followed
+ // by a '('.
+ assert(isCXXDeclarationSpecifier() == TPResult::Ambiguous());
+
+ if (Tok.is(tok::kw_typeof))
+ TryParseTypeofSpecifier();
+ else
+ ConsumeToken();
+
+ assert(Tok.is(tok::l_paren) && "Expected '('");
+
+ TPResult TPR = TryParseInitDeclaratorList();
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+
+ if (Tok.isNot(tok::semi))
+ return TPResult::False();
+
+ return TPResult::Ambiguous();
+}
+
+/// init-declarator-list:
+/// init-declarator
+/// init-declarator-list ',' init-declarator
+///
+/// init-declarator:
+/// declarator initializer[opt]
+/// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt]
+///
+/// initializer:
+/// '=' initializer-clause
+/// '(' expression-list ')'
+///
+/// initializer-clause:
+/// assignment-expression
+/// '{' initializer-list ','[opt] '}'
+/// '{' '}'
+///
+Parser::TPResult Parser::TryParseInitDeclaratorList() {
+ // GCC only examines the first declarator for disambiguation:
+ // i.e:
+ // int(x), ++x; // GCC regards it as ill-formed declaration.
+ //
+ // Comeau and MSVC will regard the above statement as correct expression.
+ // Clang examines all of the declarators and also regards the above statement
+ // as correct expression.
+
+ while (1) {
+ // declarator
+ TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/);
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+
+ // [GNU] simple-asm-expr[opt] attributes[opt]
+ if (Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
+ return TPResult::True();
+
+ // initializer[opt]
+ if (Tok.is(tok::l_paren)) {
+ // Parse through the parens.
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+ } else if (Tok.is(tok::equal)) {
+ // MSVC won't examine the rest of declarators if '=' is encountered, it
+ // will conclude that it is a declaration.
+ // Comeau and Clang will examine the rest of declarators.
+ // Note that "int(x) = {0}, ++x;" will be interpreted as ill-formed
+ // expression.
+ //
+ // Parse through the initializer-clause.
+ SkipUntil(tok::comma, true/*StopAtSemi*/, true/*DontConsume*/);
+ }
+
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // the comma.
+ }
+
+ return TPResult::Ambiguous();
+}
+
+/// isCXXConditionDeclaration - Disambiguates between a declaration or an
+/// expression for a condition of a if/switch/while/for statement.
+/// If during the disambiguation process a parsing error is encountered,
+/// the function returns true to let the declaration parsing code handle it.
+///
+/// condition:
+/// expression
+/// type-specifier-seq declarator '=' assignment-expression
+/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
+/// '=' assignment-expression
+///
+bool Parser::isCXXConditionDeclaration() {
+ TPResult TPR = isCXXDeclarationSpecifier();
+ if (TPR != TPResult::Ambiguous())
+ return TPR != TPResult::False(); // Returns true for TPResult::True() or
+ // TPResult::Error().
+
+ // FIXME: Add statistics about the number of ambiguous statements encountered
+ // and how they were resolved (number of declarations+number of expressions).
+
+ // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
+ // We need tentative parsing...
+
+ TentativeParsingAction PA(*this);
+
+ // type-specifier-seq
+ if (Tok.is(tok::kw_typeof))
+ TryParseTypeofSpecifier();
+ else
+ ConsumeToken();
+ assert(Tok.is(tok::l_paren) && "Expected '('");
+
+ // declarator
+ TPR = TryParseDeclarator(false/*mayBeAbstract*/);
+
+ // In case of an error, let the declaration parsing code handle it.
+ if (TPR == TPResult::Error())
+ TPR = TPResult::True();
+
+ if (TPR == TPResult::Ambiguous()) {
+ // '='
+ // [GNU] simple-asm-expr[opt] attributes[opt]
+ if (Tok.is(tok::equal) ||
+ Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
+ TPR = TPResult::True();
+ else
+ TPR = TPResult::False();
+ }
+
+ PA.Revert();
+
+ assert(TPR == TPResult::True() || TPR == TPResult::False());
+ return TPR == TPResult::True();
+}
+
+ /// \brief Determine whether the next set of tokens contains a type-id.
+ ///
+ /// The context parameter states what context we're parsing right
+ /// now, which affects how this routine copes with the token
+ /// following the type-id. If the context is TypeIdInParens, we have
+ /// already parsed the '(' and we will cease lookahead when we hit
+ /// the corresponding ')'. If the context is
+ /// TypeIdAsTemplateArgument, we've already parsed the '<' or ','
+ /// before this template argument, and will cease lookahead when we
+ /// hit a '>', '>>' (in C++0x), or ','. Returns true for a type-id
+ /// and false for an expression. If during the disambiguation
+ /// process a parsing error is encountered, the function returns
+ /// true to let the declaration parsing code handle it.
+ ///
+ /// type-id:
+ /// type-specifier-seq abstract-declarator[opt]
+ ///
+bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
+
+ isAmbiguous = false;
+
+ // C++ 8.2p2:
+ // The ambiguity arising from the similarity between a function-style cast and
+ // a type-id can occur in different contexts. The ambiguity appears as a
+ // choice between a function-style cast expression and a declaration of a
+ // type. The resolution is that any construct that could possibly be a type-id
+ // in its syntactic context shall be considered a type-id.
+
+ TPResult TPR = isCXXDeclarationSpecifier();
+ if (TPR != TPResult::Ambiguous())
+ return TPR != TPResult::False(); // Returns true for TPResult::True() or
+ // TPResult::Error().
+
+ // FIXME: Add statistics about the number of ambiguous statements encountered
+ // and how they were resolved (number of declarations+number of expressions).
+
+ // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
+ // We need tentative parsing...
+
+ TentativeParsingAction PA(*this);
+
+ // type-specifier-seq
+ if (Tok.is(tok::kw_typeof))
+ TryParseTypeofSpecifier();
+ else
+ ConsumeToken();
+ assert(Tok.is(tok::l_paren) && "Expected '('");
+
+ // declarator
+ TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/);
+
+ // In case of an error, let the declaration parsing code handle it.
+ if (TPR == TPResult::Error())
+ TPR = TPResult::True();
+
+ if (TPR == TPResult::Ambiguous()) {
+ // We are supposed to be inside parens, so if after the abstract declarator
+ // we encounter a ')' this is a type-id, otherwise it's an expression.
+ if (Context == TypeIdInParens && Tok.is(tok::r_paren)) {
+ TPR = TPResult::True();
+ isAmbiguous = true;
+
+ // We are supposed to be inside a template argument, so if after
+ // the abstract declarator we encounter a '>', '>>' (in C++0x), or
+ // ',', this is a type-id. Otherwise, it's an expression.
+ } else if (Context == TypeIdAsTemplateArgument &&
+ (Tok.is(tok::greater) || Tok.is(tok::comma) ||
+ (getLang().CPlusPlus0x && Tok.is(tok::greatergreater)))) {
+ TPR = TPResult::True();
+ isAmbiguous = true;
+
+ } else
+ TPR = TPResult::False();
+ }
+
+ PA.Revert();
+
+ assert(TPR == TPResult::True() || TPR == TPResult::False());
+ return TPR == TPResult::True();
+}
+
+/// declarator:
+/// direct-declarator
+/// ptr-operator declarator
+///
+/// direct-declarator:
+/// declarator-id
+/// direct-declarator '(' parameter-declaration-clause ')'
+/// cv-qualifier-seq[opt] exception-specification[opt]
+/// direct-declarator '[' constant-expression[opt] ']'
+/// '(' declarator ')'
+/// [GNU] '(' attributes declarator ')'
+///
+/// abstract-declarator:
+/// ptr-operator abstract-declarator[opt]
+/// direct-abstract-declarator
+///
+/// direct-abstract-declarator:
+/// direct-abstract-declarator[opt]
+/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+/// exception-specification[opt]
+/// direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
+/// '(' abstract-declarator ')'
+///
+/// ptr-operator:
+/// '*' cv-qualifier-seq[opt]
+/// '&'
+/// [C++0x] '&&' [TODO]
+/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt]
+///
+/// cv-qualifier-seq:
+/// cv-qualifier cv-qualifier-seq[opt]
+///
+/// cv-qualifier:
+/// 'const'
+/// 'volatile'
+///
+/// declarator-id:
+/// id-expression
+///
+/// id-expression:
+/// unqualified-id
+/// qualified-id [TODO]
+///
+/// unqualified-id:
+/// identifier
+/// operator-function-id [TODO]
+/// conversion-function-id [TODO]
+/// '~' class-name [TODO]
+/// template-id [TODO]
+///
+Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
+ bool mayHaveIdentifier) {
+ // declarator:
+ // direct-declarator
+ // ptr-operator declarator
+
+ while (1) {
+ if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier))
+ TryAnnotateCXXScopeToken();
+
+ if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) ||
+ (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) {
+ // ptr-operator
+ ConsumeToken();
+ while (Tok.is(tok::kw_const) ||
+ Tok.is(tok::kw_volatile) ||
+ Tok.is(tok::kw_restrict))
+ ConsumeToken();
+ } else {
+ break;
+ }
+ }
+
+ // direct-declarator:
+ // direct-abstract-declarator:
+
+ if (Tok.is(tok::identifier) && mayHaveIdentifier) {
+ // declarator-id
+ ConsumeToken();
+ } else if (Tok.is(tok::l_paren)) {
+ ConsumeParen();
+ if (mayBeAbstract &&
+ (Tok.is(tok::r_paren) || // 'int()' is a function.
+ Tok.is(tok::ellipsis) || // 'int(...)' is a function.
+ isDeclarationSpecifier())) { // 'int(int)' is a function.
+ // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+ // exception-specification[opt]
+ TPResult TPR = TryParseFunctionDeclarator();
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+ } else {
+ // '(' declarator ')'
+ // '(' attributes declarator ')'
+ // '(' abstract-declarator ')'
+ if (Tok.is(tok::kw___attribute))
+ return TPResult::True(); // attributes indicate declaration
+ TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier);
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+ if (Tok.isNot(tok::r_paren))
+ return TPResult::False();
+ ConsumeParen();
+ }
+ } else if (!mayBeAbstract) {
+ return TPResult::False();
+ }
+
+ while (1) {
+ TPResult TPR(TPResult::Ambiguous());
+
+ if (Tok.is(tok::l_paren)) {
+ // Check whether we have a function declarator or a possible ctor-style
+ // initializer that follows the declarator. Note that ctor-style
+ // initializers are not possible in contexts where abstract declarators
+ // are allowed.
+ if (!mayBeAbstract && !isCXXFunctionDeclarator(false/*warnIfAmbiguous*/))
+ break;
+
+ // direct-declarator '(' parameter-declaration-clause ')'
+ // cv-qualifier-seq[opt] exception-specification[opt]
+ ConsumeParen();
+ TPR = TryParseFunctionDeclarator();
+ } else if (Tok.is(tok::l_square)) {
+ // direct-declarator '[' constant-expression[opt] ']'
+ // direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
+ TPR = TryParseBracketDeclarator();
+ } else {
+ break;
+ }
+
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+ }
+
+ return TPResult::Ambiguous();
+}
+
+/// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration
+/// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could
+/// be either a decl-specifier or a function-style cast, and TPResult::Error()
+/// if a parsing error was found and reported.
+///
+/// decl-specifier:
+/// storage-class-specifier
+/// type-specifier
+/// function-specifier
+/// 'friend'
+/// 'typedef'
+/// [GNU] attributes declaration-specifiers[opt]
+///
+/// storage-class-specifier:
+/// 'register'
+/// 'static'
+/// 'extern'
+/// 'mutable'
+/// 'auto'
+/// [GNU] '__thread'
+///
+/// function-specifier:
+/// 'inline'
+/// 'virtual'
+/// 'explicit'
+///
+/// typedef-name:
+/// identifier
+///
+/// type-specifier:
+/// simple-type-specifier
+/// class-specifier
+/// enum-specifier
+/// elaborated-type-specifier
+/// typename-specifier
+/// cv-qualifier
+///
+/// simple-type-specifier:
+/// '::'[opt] nested-name-specifier[opt] type-name
+/// '::'[opt] nested-name-specifier 'template'
+/// simple-template-id [TODO]
+/// 'char'
+/// 'wchar_t'
+/// 'bool'
+/// 'short'
+/// 'int'
+/// 'long'
+/// 'signed'
+/// 'unsigned'
+/// 'float'
+/// 'double'
+/// 'void'
+/// [GNU] typeof-specifier
+/// [GNU] '_Complex'
+/// [C++0x] 'auto' [TODO]
+///
+/// type-name:
+/// class-name
+/// enum-name
+/// typedef-name
+///
+/// elaborated-type-specifier:
+/// class-key '::'[opt] nested-name-specifier[opt] identifier
+/// class-key '::'[opt] nested-name-specifier[opt] 'template'[opt]
+/// simple-template-id
+/// 'enum' '::'[opt] nested-name-specifier[opt] identifier
+///
+/// enum-name:
+/// identifier
+///
+/// enum-specifier:
+/// 'enum' identifier[opt] '{' enumerator-list[opt] '}'
+/// 'enum' identifier[opt] '{' enumerator-list ',' '}'
+///
+/// class-specifier:
+/// class-head '{' member-specification[opt] '}'
+///
+/// class-head:
+/// class-key identifier[opt] base-clause[opt]
+/// class-key nested-name-specifier identifier base-clause[opt]
+/// class-key nested-name-specifier[opt] simple-template-id
+/// base-clause[opt]
+///
+/// class-key:
+/// 'class'
+/// 'struct'
+/// 'union'
+///
+/// cv-qualifier:
+/// 'const'
+/// 'volatile'
+/// [GNU] restrict
+///
+Parser::TPResult Parser::isCXXDeclarationSpecifier() {
+ switch (Tok.getKind()) {
+ case tok::identifier: // foo::bar
+ case tok::kw_typename: // typename T::type
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return isCXXDeclarationSpecifier();
+ // Otherwise, not a typename.
+ return TPResult::False();
+
+ case tok::coloncolon: // ::foo::bar
+ if (NextToken().is(tok::kw_new) || // ::new
+ NextToken().is(tok::kw_delete)) // ::delete
+ return TPResult::False();
+
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return isCXXDeclarationSpecifier();
+ // Otherwise, not a typename.
+ return TPResult::False();
+
+ // decl-specifier:
+ // storage-class-specifier
+ // type-specifier
+ // function-specifier
+ // 'friend'
+ // 'typedef'
+
+ case tok::kw_friend:
+ case tok::kw_typedef:
+ // storage-class-specifier
+ case tok::kw_register:
+ case tok::kw_static:
+ case tok::kw_extern:
+ case tok::kw_mutable:
+ case tok::kw_auto:
+ case tok::kw___thread:
+ // function-specifier
+ case tok::kw_inline:
+ case tok::kw_virtual:
+ case tok::kw_explicit:
+
+ // type-specifier:
+ // simple-type-specifier
+ // class-specifier
+ // enum-specifier
+ // elaborated-type-specifier
+ // typename-specifier
+ // cv-qualifier
+
+ // class-specifier
+ // elaborated-type-specifier
+ case tok::kw_class:
+ case tok::kw_struct:
+ case tok::kw_union:
+ // enum-specifier
+ case tok::kw_enum:
+ // cv-qualifier
+ case tok::kw_const:
+ case tok::kw_volatile:
+
+ // GNU
+ case tok::kw_restrict:
+ case tok::kw__Complex:
+ case tok::kw___attribute:
+ return TPResult::True();
+
+ // Microsoft
+ case tok::kw___declspec:
+ case tok::kw___cdecl:
+ case tok::kw___stdcall:
+ case tok::kw___fastcall:
+ return PP.getLangOptions().Microsoft ? TPResult::True() : TPResult::False();
+
+ // The ambiguity resides in a simple-type-specifier/typename-specifier
+ // followed by a '('. The '(' could either be the start of:
+ //
+ // direct-declarator:
+ // '(' declarator ')'
+ //
+ // direct-abstract-declarator:
+ // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+ // exception-specification[opt]
+ // '(' abstract-declarator ')'
+ //
+ // or part of a function-style cast expression:
+ //
+ // simple-type-specifier '(' expression-list[opt] ')'
+ //
+
+ // simple-type-specifier:
+
+ case tok::kw_char:
+ case tok::kw_wchar_t:
+ case tok::kw_bool:
+ case tok::kw_short:
+ case tok::kw_int:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_void:
+ case tok::annot_typename:
+ if (NextToken().is(tok::l_paren))
+ return TPResult::Ambiguous();
+
+ return TPResult::True();
+
+ // GNU typeof support.
+ case tok::kw_typeof: {
+ if (NextToken().isNot(tok::l_paren))
+ return TPResult::True();
+
+ TentativeParsingAction PA(*this);
+
+ TPResult TPR = TryParseTypeofSpecifier();
+ bool isFollowedByParen = Tok.is(tok::l_paren);
+
+ PA.Revert();
+
+ if (TPR == TPResult::Error())
+ return TPResult::Error();
+
+ if (isFollowedByParen)
+ return TPResult::Ambiguous();
+
+ return TPResult::True();
+ }
+
+ default:
+ return TPResult::False();
+ }
+}
+
+/// [GNU] typeof-specifier:
+/// 'typeof' '(' expressions ')'
+/// 'typeof' '(' type-name ')'
+///
+Parser::TPResult Parser::TryParseTypeofSpecifier() {
+ assert(Tok.is(tok::kw_typeof) && "Expected 'typeof'!");
+ ConsumeToken();
+
+ assert(Tok.is(tok::l_paren) && "Expected '('");
+ // Parse through the parens after 'typeof'.
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+
+ return TPResult::Ambiguous();
+}
+
+Parser::TPResult Parser::TryParseDeclarationSpecifier() {
+ TPResult TPR = isCXXDeclarationSpecifier();
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+
+ if (Tok.is(tok::kw_typeof))
+ TryParseTypeofSpecifier();
+ else
+ ConsumeToken();
+
+ assert(Tok.is(tok::l_paren) && "Expected '('!");
+ return TPResult::Ambiguous();
+}
+
+/// isCXXFunctionDeclarator - Disambiguates between a function declarator or
+/// a constructor-style initializer, when parsing declaration statements.
+/// Returns true for function declarator and false for constructor-style
+/// initializer.
+/// If during the disambiguation process a parsing error is encountered,
+/// the function returns true to let the declaration parsing code handle it.
+///
+/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+/// exception-specification[opt]
+///
+bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) {
+
+ // C++ 8.2p1:
+ // The ambiguity arising from the similarity between a function-style cast and
+ // a declaration mentioned in 6.8 can also occur in the context of a
+ // declaration. In that context, the choice is between a function declaration
+ // with a redundant set of parentheses around a parameter name and an object
+ // declaration with a function-style cast as the initializer. Just as for the
+ // ambiguities mentioned in 6.8, the resolution is to consider any construct
+ // that could possibly be a declaration a declaration.
+
+ TentativeParsingAction PA(*this);
+
+ ConsumeParen();
+ TPResult TPR = TryParseParameterDeclarationClause();
+ if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren))
+ TPR = TPResult::False();
+
+ SourceLocation TPLoc = Tok.getLocation();
+ PA.Revert();
+
+ // In case of an error, let the declaration parsing code handle it.
+ if (TPR == TPResult::Error())
+ return true;
+
+ if (TPR == TPResult::Ambiguous()) {
+ // Function declarator has precedence over constructor-style initializer.
+ // Emit a warning just in case the author intended a variable definition.
+ if (warnIfAmbiguous)
+ Diag(Tok, diag::warn_parens_disambiguated_as_function_decl)
+ << SourceRange(Tok.getLocation(), TPLoc);
+ return true;
+ }
+
+ return TPR == TPResult::True();
+}
+
+/// parameter-declaration-clause:
+/// parameter-declaration-list[opt] '...'[opt]
+/// parameter-declaration-list ',' '...'
+///
+/// parameter-declaration-list:
+/// parameter-declaration
+/// parameter-declaration-list ',' parameter-declaration
+///
+/// parameter-declaration:
+/// decl-specifier-seq declarator
+/// decl-specifier-seq declarator '=' assignment-expression
+/// decl-specifier-seq abstract-declarator[opt]
+/// decl-specifier-seq abstract-declarator[opt] '=' assignment-expression
+///
+Parser::TPResult Parser::TryParseParameterDeclarationClause() {
+
+ if (Tok.is(tok::r_paren))
+ return TPResult::True();
+
+ // parameter-declaration-list[opt] '...'[opt]
+ // parameter-declaration-list ',' '...'
+ //
+ // parameter-declaration-list:
+ // parameter-declaration
+ // parameter-declaration-list ',' parameter-declaration
+ //
+ while (1) {
+ // '...'[opt]
+ if (Tok.is(tok::ellipsis)) {
+ ConsumeToken();
+ return TPResult::True(); // '...' is a sign of a function declarator.
+ }
+
+ // decl-specifier-seq
+ TPResult TPR = TryParseDeclarationSpecifier();
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+
+ // declarator
+ // abstract-declarator[opt]
+ TPR = TryParseDeclarator(true/*mayBeAbstract*/);
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+
+ if (Tok.is(tok::equal)) {
+ // '=' assignment-expression
+ // Parse through assignment-expression.
+ tok::TokenKind StopToks[3] ={ tok::comma, tok::ellipsis, tok::r_paren };
+ if (!SkipUntil(StopToks, 3, true/*StopAtSemi*/, true/*DontConsume*/))
+ return TPResult::Error();
+ }
+
+ if (Tok.is(tok::ellipsis)) {
+ ConsumeToken();
+ return TPResult::True(); // '...' is a sign of a function declarator.
+ }
+
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // the comma.
+ }
+
+ return TPResult::Ambiguous();
+}
+
+/// TryParseFunctionDeclarator - We parsed a '(' and we want to try to continue
+/// parsing as a function declarator.
+/// If TryParseFunctionDeclarator fully parsed the function declarator, it will
+/// return TPResult::Ambiguous(), otherwise it will return either False() or
+/// Error().
+///
+/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+/// exception-specification[opt]
+///
+/// exception-specification:
+/// 'throw' '(' type-id-list[opt] ')'
+///
+Parser::TPResult Parser::TryParseFunctionDeclarator() {
+
+ // The '(' is already parsed.
+
+ TPResult TPR = TryParseParameterDeclarationClause();
+ if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren))
+ TPR = TPResult::False();
+
+ if (TPR == TPResult::False() || TPR == TPResult::Error())
+ return TPR;
+
+ // Parse through the parens.
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+
+ // cv-qualifier-seq
+ while (Tok.is(tok::kw_const) ||
+ Tok.is(tok::kw_volatile) ||
+ Tok.is(tok::kw_restrict) )
+ ConsumeToken();
+
+ // exception-specification
+ if (Tok.is(tok::kw_throw)) {
+ ConsumeToken();
+ if (Tok.isNot(tok::l_paren))
+ return TPResult::Error();
+
+ // Parse through the parens after 'throw'.
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+ }
+
+ return TPResult::Ambiguous();
+}
+
+/// '[' constant-expression[opt] ']'
+///
+Parser::TPResult Parser::TryParseBracketDeclarator() {
+ ConsumeBracket();
+ if (!SkipUntil(tok::r_square))
+ return TPResult::Error();
+
+ return TPResult::Ambiguous();
+}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
new file mode 100644
index 000000000000..1c2e8a62e1f9
--- /dev/null
+++ b/lib/Parse/Parser.cpp
@@ -0,0 +1,996 @@
+//===--- Parser.cpp - C Language Family Parser ----------------------------===//
+//
+// 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 Parser interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+#include "llvm/Support/raw_ostream.h"
+#include "ExtensionRAIIObject.h"
+#include "ParsePragma.h"
+using namespace clang;
+
+Parser::Parser(Preprocessor &pp, Action &actions)
+ : CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
+ GreaterThanIsOperator(true) {
+ Tok.setKind(tok::eof);
+ CurScope = 0;
+ NumCachedScopes = 0;
+ ParenCount = BracketCount = BraceCount = 0;
+ ObjCImpDecl = DeclPtrTy();
+
+ // Add #pragma handlers. These are removed and destroyed in the
+ // destructor.
+ PackHandler.reset(new
+ PragmaPackHandler(&PP.getIdentifierTable().get("pack"), actions));
+ PP.AddPragmaHandler(0, PackHandler.get());
+
+ UnusedHandler.reset(new
+ PragmaUnusedHandler(&PP.getIdentifierTable().get("unused"), actions,
+ *this));
+ PP.AddPragmaHandler(0, UnusedHandler.get());
+}
+
+/// 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 {
+ const Token &Tok = P.getCurToken();
+ if (Tok.is(tok::eof)) {
+ OS << "<eof> parser at end of file\n";
+ return;
+ }
+
+ if (Tok.getLocation().isInvalid()) {
+ OS << "<unknown> parser at unknown location\n";
+ return;
+ }
+
+ const Preprocessor &PP = P.getPreprocessor();
+ Tok.getLocation().print(OS, PP.getSourceManager());
+ OS << ": current parser token '" << PP.getSpelling(Tok) << "'\n";
+}
+
+
+DiagnosticBuilder Parser::Diag(SourceLocation Loc, unsigned DiagID) {
+ return Diags.Report(FullSourceLoc(Loc, PP.getSourceManager()), DiagID);
+}
+
+DiagnosticBuilder Parser::Diag(const Token &Tok, unsigned DiagID) {
+ return Diag(Tok.getLocation(), DiagID);
+}
+
+/// \brief Emits a diagnostic suggesting parentheses surrounding a
+/// given range.
+///
+/// \param Loc The location where we'll emit the diagnostic.
+/// \param Loc The kind of diagnostic to emit.
+/// \param ParenRange Source range enclosing code that should be parenthesized.
+void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK,
+ SourceRange ParenRange) {
+ SourceLocation EndLoc = PP.getLocForEndOfToken(ParenRange.getEnd());
+ if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
+ // We can't display the parentheses, so just dig the
+ // warning/error and return.
+ Diag(Loc, DK);
+ return;
+ }
+
+ Diag(Loc, DK)
+ << CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(")
+ << CodeModificationHint::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 the specified diagnostic indicating
+/// that the parser failed to match the RHS of the token at LHSLoc. LHSName
+/// should be the name of the unmatched LHS token.
+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;
+ }
+ Diag(Tok, DID);
+ Diag(LHSLoc, diag::note_matching) << LHSName;
+ SkipUntil(RHSTok);
+ return R;
+}
+
+/// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the
+/// input. If so, it is consumed and false is returned.
+///
+/// If the input is malformed, this emits the specified diagnostic. Next, if
+/// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is
+/// returned.
+bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
+ const char *Msg, tok::TokenKind SkipToTok) {
+ if (Tok.is(ExpectedTok)) {
+ ConsumeAnyToken();
+ return false;
+ }
+
+ const char *Spelling = 0;
+ SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation);
+ if (EndLoc.isValid() &&
+ (Spelling = tok::getTokenSimpleSpelling(ExpectedTok))) {
+ // Show what code to insert to fix this problem.
+ Diag(EndLoc, DiagID)
+ << Msg
+ << CodeModificationHint::CreateInsertion(EndLoc, Spelling);
+ } else
+ Diag(Tok, DiagID) << Msg;
+
+ if (SkipToTok != tok::unknown)
+ SkipUntil(SkipToTok);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Error recovery.
+//===----------------------------------------------------------------------===//
+
+/// SkipUntil - Read tokens until we get to the specified token, then consume
+/// it (unless DontConsume is true). Because we cannot guarantee that the
+/// token will ever occur, this skips to the next token, or to some likely
+/// good stopping point. If StopAtSemi is true, skipping will stop at a ';'
+/// character.
+///
+/// If SkipUntil finds the specified token, it returns true, otherwise it
+/// returns false.
+bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
+ bool StopAtSemi, bool DontConsume) {
+ // We always want this function to skip at least one token if the first token
+ // isn't T and if not at EOF.
+ bool isFirstTokenSkipped = true;
+ while (1) {
+ // If we found one of the tokens, stop and return true.
+ for (unsigned i = 0; i != NumToks; ++i) {
+ if (Tok.is(Toks[i])) {
+ if (DontConsume) {
+ // Noop, don't consume the token.
+ } else {
+ ConsumeAnyToken();
+ }
+ return true;
+ }
+ }
+
+ switch (Tok.getKind()) {
+ case tok::eof:
+ // Ran out of tokens.
+ return false;
+
+ case tok::l_paren:
+ // Recursively skip properly-nested parens.
+ ConsumeParen();
+ SkipUntil(tok::r_paren, false);
+ break;
+ case tok::l_square:
+ // Recursively skip properly-nested square brackets.
+ ConsumeBracket();
+ SkipUntil(tok::r_square, false);
+ break;
+ case tok::l_brace:
+ // Recursively skip properly-nested braces.
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, false);
+ break;
+
+ // Okay, we found a ']' or '}' or ')', which we think should be balanced.
+ // Since the user wasn't looking for this token (if they were, it would
+ // already be handled), this isn't balanced. If there is a LHS token at a
+ // higher level, we will assume that this matches the unbalanced token
+ // and return it. Otherwise, this is a spurious RHS token, which we skip.
+ case tok::r_paren:
+ if (ParenCount && !isFirstTokenSkipped)
+ return false; // Matches something.
+ ConsumeParen();
+ break;
+ case tok::r_square:
+ if (BracketCount && !isFirstTokenSkipped)
+ return false; // Matches something.
+ ConsumeBracket();
+ break;
+ case tok::r_brace:
+ if (BraceCount && !isFirstTokenSkipped)
+ return false; // Matches something.
+ ConsumeBrace();
+ break;
+
+ case tok::string_literal:
+ case tok::wide_string_literal:
+ ConsumeStringToken();
+ break;
+ case tok::semi:
+ if (StopAtSemi)
+ return false;
+ // FALL THROUGH.
+ default:
+ // Skip this token.
+ ConsumeToken();
+ break;
+ }
+ isFirstTokenSkipped = false;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Scope manipulation
+//===----------------------------------------------------------------------===//
+
+/// EnterScope - Start a new scope.
+void Parser::EnterScope(unsigned ScopeFlags) {
+ if (NumCachedScopes) {
+ Scope *N = ScopeCache[--NumCachedScopes];
+ N->Init(CurScope, ScopeFlags);
+ CurScope = N;
+ } else {
+ CurScope = new Scope(CurScope, ScopeFlags);
+ }
+}
+
+/// ExitScope - Pop a scope off the scope stack.
+void Parser::ExitScope() {
+ assert(CurScope && "Scope imbalance!");
+
+ // Inform the actions module that this scope is going away if there are any
+ // decls in it.
+ if (!CurScope->decl_empty())
+ Actions.ActOnPopScope(Tok.getLocation(), CurScope);
+
+ Scope *OldScope = CurScope;
+ CurScope = OldScope->getParent();
+
+ if (NumCachedScopes == ScopeCacheSize)
+ delete OldScope;
+ else
+ ScopeCache[NumCachedScopes++] = OldScope;
+}
+
+
+
+
+//===----------------------------------------------------------------------===//
+// C99 6.9: External Definitions.
+//===----------------------------------------------------------------------===//
+
+Parser::~Parser() {
+ // If we still have scopes active, delete the scope tree.
+ delete CurScope;
+
+ // Free the scope cache.
+ for (unsigned i = 0, e = NumCachedScopes; i != e; ++i)
+ delete ScopeCache[i];
+
+ // Remove the pragma handlers we installed.
+ PP.RemovePragmaHandler(0, PackHandler.get());
+ PackHandler.reset();
+ PP.RemovePragmaHandler(0, UnusedHandler.get());
+ UnusedHandler.reset();
+}
+
+/// Initialize - Warm up the parser.
+///
+void Parser::Initialize() {
+ // Prime the lexer look-ahead.
+ ConsumeToken();
+
+ // Create the translation unit scope. Install it as the current scope.
+ assert(CurScope == 0 && "A scope is already active?");
+ EnterScope(Scope::DeclScope);
+ Actions.ActOnTranslationUnitScope(Tok.getLocation(), CurScope);
+
+ if (Tok.is(tok::eof) &&
+ !getLang().CPlusPlus) // Empty source file is an extension in C
+ Diag(Tok, diag::ext_empty_source_file);
+
+ // Initialization for Objective-C context sensitive keywords recognition.
+ // Referenced in Parser::ParseObjCTypeQualifierList.
+ if (getLang().ObjC1) {
+ ObjCTypeQuals[objc_in] = &PP.getIdentifierTable().get("in");
+ ObjCTypeQuals[objc_out] = &PP.getIdentifierTable().get("out");
+ ObjCTypeQuals[objc_inout] = &PP.getIdentifierTable().get("inout");
+ ObjCTypeQuals[objc_oneway] = &PP.getIdentifierTable().get("oneway");
+ ObjCTypeQuals[objc_bycopy] = &PP.getIdentifierTable().get("bycopy");
+ ObjCTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref");
+ }
+
+ Ident_super = &PP.getIdentifierTable().get("super");
+}
+
+/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
+/// action tells us to. This returns true if the EOF was encountered.
+bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
+ Result = DeclGroupPtrTy();
+ if (Tok.is(tok::eof)) {
+ Actions.ActOnEndOfTranslationUnit();
+ return true;
+ }
+
+ Result = ParseExternalDeclaration();
+ return false;
+}
+
+/// ParseTranslationUnit:
+/// translation-unit: [C99 6.9]
+/// external-declaration
+/// translation-unit external-declaration
+void Parser::ParseTranslationUnit() {
+ Initialize();
+
+ DeclGroupPtrTy Res;
+ while (!ParseTopLevelDecl(Res))
+ /*parse them all*/;
+
+ ExitScope();
+ assert(CurScope == 0 && "Scope imbalance!");
+}
+
+/// ParseExternalDeclaration:
+///
+/// external-declaration: [C99 6.9], declaration: [C++ dcl.dcl]
+/// function-definition
+/// declaration
+/// [EXT] ';'
+/// [GNU] asm-definition
+/// [GNU] __extension__ external-declaration
+/// [OBJC] objc-class-definition
+/// [OBJC] objc-class-declaration
+/// [OBJC] objc-alias-declaration
+/// [OBJC] objc-protocol-definition
+/// [OBJC] objc-method-definition
+/// [OBJC] @end
+/// [C++] linkage-specification
+/// [GNU] asm-definition:
+/// simple-asm-expr ';'
+///
+Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
+ DeclPtrTy SingleDecl;
+ switch (Tok.getKind()) {
+ case tok::semi:
+ Diag(Tok, diag::ext_top_level_semi)
+ << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation()));
+ ConsumeToken();
+ // TODO: Invoke action for top-level semicolon.
+ return DeclGroupPtrTy();
+ case tok::r_brace:
+ Diag(Tok, diag::err_expected_external_declaration);
+ ConsumeBrace();
+ return DeclGroupPtrTy();
+ case tok::eof:
+ Diag(Tok, diag::err_expected_external_declaration);
+ return DeclGroupPtrTy();
+ case tok::kw___extension__: {
+ // __extension__ silences extension warnings in the subexpression.
+ ExtensionRAIIObject O(Diags); // Use RAII to do this.
+ ConsumeToken();
+ return ParseExternalDeclaration();
+ }
+ case tok::kw_asm: {
+ OwningExprResult Result(ParseSimpleAsm());
+
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
+ "top-level asm block");
+
+ if (Result.isInvalid())
+ return DeclGroupPtrTy();
+ SingleDecl = Actions.ActOnFileScopeAsmDecl(Tok.getLocation(), move(Result));
+ 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();
+ break;
+ case tok::minus:
+ case tok::plus:
+ if (!getLang().ObjC1) {
+ Diag(Tok, diag::err_expected_external_declaration);
+ ConsumeToken();
+ return DeclGroupPtrTy();
+ }
+ SingleDecl = ParseObjCMethodDefinition();
+ break;
+ case tok::kw_using:
+ case tok::kw_namespace:
+ case tok::kw_typedef:
+ case tok::kw_template:
+ case tok::kw_export: // As in 'export template'
+ case tok::kw_static_assert:
+ // A function definition cannot start with a these keywords.
+ {
+ SourceLocation DeclEnd;
+ return ParseDeclaration(Declarator::FileContext, DeclEnd);
+ }
+ default:
+ // We can't tell whether this is a function-definition or declaration yet.
+ return ParseDeclarationOrFunctionDefinition();
+ }
+
+ // This routine returns a DeclGroup, if the thing we parsed only contains a
+ // single decl, convert it now.
+ return Actions.ConvertDeclToDeclGroup(SingleDecl);
+}
+
+/// \brief Determine whether the current token, if it occurs after a
+/// declarator, continues a declaration or declaration list.
+bool Parser::isDeclarationAfterDeclarator() {
+ return Tok.is(tok::equal) || // int X()= -> not a function def
+ Tok.is(tok::comma) || // int X(), -> not a function def
+ Tok.is(tok::semi) || // int X(); -> not a function def
+ Tok.is(tok::kw_asm) || // int X() __asm__ -> not a function def
+ Tok.is(tok::kw___attribute) || // int X() __attr__ -> not a function def
+ (getLang().CPlusPlus &&
+ Tok.is(tok::l_paren)); // int X(0) -> not a function def [C++]
+}
+
+/// \brief Determine whether the current token, if it occurs after a
+/// declarator, indicates the start of a function definition.
+bool Parser::isStartOfFunctionDefinition() {
+ return Tok.is(tok::l_brace) || // int X() {}
+ (!getLang().CPlusPlus &&
+ isDeclarationSpecifier()) || // int X(f) int f; {}
+ (getLang().CPlusPlus &&
+ (Tok.is(tok::colon) || // X() : Base() {} (used for ctors)
+ Tok.is(tok::kw_try))); // X() try { ... }
+}
+
+/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or
+/// a declaration. We can't tell which we have until we read up to the
+/// compound-statement in function-definition. TemplateParams, if
+/// non-NULL, provides the template parameters when we're parsing a
+/// C++ template-declaration.
+///
+/// function-definition: [C99 6.9.1]
+/// decl-specs declarator declaration-list[opt] compound-statement
+/// [C90] function-definition: [C99 6.7.1] - implicit int result
+/// [C90] decl-specs[opt] declarator declaration-list[opt] compound-statement
+///
+/// declaration: [C99 6.7]
+/// declaration-specifiers init-declarator-list[opt] ';'
+/// [!C99] init-declarator-list ';' [TODO: warn in c99 mode]
+/// [OMP] threadprivate-directive [TODO]
+///
+Parser::DeclGroupPtrTy
+Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
+
+ // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
+ // declaration-specifiers init-declarator-list[opt] ';'
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ return Actions.ConvertDeclToDeclGroup(TheDecl);
+ }
+
+ // ObjC2 allows prefix attributes on class interfaces and protocols.
+ // FIXME: This still needs better diagnostics. We should only accept
+ // attributes here, no types, etc.
+ if (getLang().ObjC2 && Tok.is(tok::at)) {
+ SourceLocation AtLoc = ConsumeToken(); // the "@"
+ if (!Tok.isObjCAtKeyword(tok::objc_interface) &&
+ !Tok.isObjCAtKeyword(tok::objc_protocol)) {
+ Diag(Tok, diag::err_objc_unexpected_attr);
+ SkipUntil(tok::semi); // FIXME: better skip?
+ return DeclGroupPtrTy();
+ }
+ const char *PrevSpec = 0;
+ if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec))
+ Diag(AtLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
+
+ DeclPtrTy TheDecl;
+ if (Tok.isObjCAtKeyword(tok::objc_protocol))
+ TheDecl = ParseObjCAtProtocolDeclaration(AtLoc, DS.getAttributes());
+ else
+ TheDecl = ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes());
+ return Actions.ConvertDeclToDeclGroup(TheDecl);
+ }
+
+ // If the declspec consisted only of 'extern' and we have a string
+ // literal following it, this must be a C++ linkage specifier like
+ // 'extern "C"'.
+ if (Tok.is(tok::string_literal) && getLang().CPlusPlus &&
+ DS.getStorageClassSpec() == DeclSpec::SCS_extern &&
+ DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) {
+ DeclPtrTy TheDecl = ParseLinkage(Declarator::FileContext);
+ return Actions.ConvertDeclToDeclGroup(TheDecl);
+ }
+
+ // Parse the first declarator.
+ Declarator DeclaratorInfo(DS, Declarator::FileContext);
+ ParseDeclarator(DeclaratorInfo);
+ // Error parsing the declarator?
+ if (!DeclaratorInfo.hasName()) {
+ // If so, skip until the semi-colon or a }.
+ SkipUntil(tok::r_brace, true, true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ return DeclGroupPtrTy();
+ }
+
+ // If we have a declaration or declarator list, handle it.
+ if (isDeclarationAfterDeclarator()) {
+ // Parse the init-declarator-list for a normal declaration.
+ DeclGroupPtrTy DG =
+ ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
+ // Eat the semi colon after the declaration.
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_declation);
+ return DG;
+ }
+
+ if (DeclaratorInfo.isFunctionDeclarator() &&
+ isStartOfFunctionDefinition()) {
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ Diag(Tok, diag::err_function_declared_typedef);
+
+ if (Tok.is(tok::l_brace)) {
+ // This recovery skips the entire function body. It would be nice
+ // to simply call ParseFunctionDefinition() below, however Sema
+ // assumes the declarator represents a function, not a typedef.
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, true);
+ } else {
+ SkipUntil(tok::semi);
+ }
+ return DeclGroupPtrTy();
+ }
+ DeclPtrTy TheDecl = ParseFunctionDefinition(DeclaratorInfo);
+ return Actions.ConvertDeclToDeclGroup(TheDecl);
+ }
+
+ if (DeclaratorInfo.isFunctionDeclarator())
+ Diag(Tok, diag::err_expected_fn_body);
+ else
+ Diag(Tok, diag::err_invalid_token_after_toplevel_declarator);
+ SkipUntil(tok::semi);
+ return DeclGroupPtrTy();
+}
+
+/// ParseFunctionDefinition - We parsed and verified that the specified
+/// Declarator is well formed. If this is a K&R-style function, read the
+/// parameters declaration-list, then start the compound-statement.
+///
+/// function-definition: [C99 6.9.1]
+/// decl-specs declarator declaration-list[opt] compound-statement
+/// [C90] function-definition: [C99 6.7.1] - implicit int result
+/// [C90] decl-specs[opt] declarator declaration-list[opt] compound-statement
+/// [C++] function-definition: [C++ 8.4]
+/// decl-specifier-seq[opt] declarator ctor-initializer[opt]
+/// function-body
+/// [C++] function-definition: [C++ 8.4]
+/// decl-specifier-seq[opt] declarator function-try-block
+///
+Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D) {
+ const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0);
+ assert(FnTypeInfo.Kind == DeclaratorChunk::Function &&
+ "This isn't a function declarator!");
+ const DeclaratorChunk::FunctionTypeInfo &FTI = FnTypeInfo.Fun;
+
+ // If this is C90 and the declspecs were completely missing, fudge in an
+ // implicit int. We do this here because this is the only place where
+ // declaration-specifiers are completely optional in the grammar.
+ if (getLang().ImplicitInt && D.getDeclSpec().isEmpty()) {
+ const char *PrevSpec;
+ D.getMutableDeclSpec().SetTypeSpecType(DeclSpec::TST_int,
+ D.getIdentifierLoc(),
+ PrevSpec);
+ D.SetRangeBegin(D.getDeclSpec().getSourceRange().getBegin());
+ }
+
+ // If this declaration was formed with a K&R-style identifier list for the
+ // arguments, parse declarations for all of the args next.
+ // int foo(a,b) int a; float b; {}
+ if (!FTI.hasPrototype && FTI.NumArgs != 0)
+ ParseKNRParamDeclarations(D);
+
+ // We should have either an opening brace or, in a C++ constructor,
+ // we may have a colon.
+ if (Tok.isNot(tok::l_brace) && Tok.isNot(tok::colon) &&
+ Tok.isNot(tok::kw_try)) {
+ Diag(Tok, diag::err_expected_fn_body);
+
+ // Skip over garbage, until we get to '{'. Don't eat the '{'.
+ SkipUntil(tok::l_brace, true, true);
+
+ // If we didn't find the '{', bail out.
+ if (Tok.isNot(tok::l_brace))
+ return DeclPtrTy();
+ }
+
+ // Enter a scope for the function body.
+ ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
+
+ // Tell the actions module that we have entered a function definition with the
+ // specified Declarator for the function.
+ DeclPtrTy Res = Actions.ActOnStartOfFunctionDef(CurScope, D);
+
+ if (Tok.is(tok::kw_try))
+ return ParseFunctionTryBlock(Res);
+
+ // If we have a colon, then we're probably parsing a C++
+ // ctor-initializer.
+ if (Tok.is(tok::colon))
+ ParseConstructorInitializer(Res);
+
+ return ParseFunctionStatementBody(Res);
+}
+
+/// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides
+/// types for a function with a K&R-style identifier list for arguments.
+void Parser::ParseKNRParamDeclarations(Declarator &D) {
+ // We know that the top-level of this declarator is a function.
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+
+ // Enter function-declaration scope, limiting any declarators to the
+ // function prototype scope, including parameter declarators.
+ ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope);
+
+ // Read all the argument declarations.
+ while (isDeclarationSpecifier()) {
+ SourceLocation DSStart = Tok.getLocation();
+
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS);
+
+ // C99 6.9.1p6: 'each declaration in the declaration list shall have at
+ // least one declarator'.
+ // NOTE: GCC just makes this an ext-warn. It's not clear what it does with
+ // the declarations though. It's trivial to ignore them, really hard to do
+ // anything else with them.
+ if (Tok.is(tok::semi)) {
+ Diag(DSStart, diag::err_declaration_does_not_declare_param);
+ ConsumeToken();
+ continue;
+ }
+
+ // C99 6.9.1p6: Declarations shall contain no storage-class specifiers other
+ // than register.
+ if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified &&
+ DS.getStorageClassSpec() != DeclSpec::SCS_register) {
+ Diag(DS.getStorageClassSpecLoc(),
+ diag::err_invalid_storage_class_in_func_decl);
+ DS.ClearStorageClassSpecs();
+ }
+ if (DS.isThreadSpecified()) {
+ Diag(DS.getThreadSpecLoc(),
+ diag::err_invalid_storage_class_in_func_decl);
+ DS.ClearStorageClassSpecs();
+ }
+
+ // Parse the first declarator attached to this declspec.
+ Declarator ParmDeclarator(DS, Declarator::KNRTypeListContext);
+ ParseDeclarator(ParmDeclarator);
+
+ // Handle the full declarator list.
+ while (1) {
+ Action::AttrTy *AttrList;
+ // If attributes are present, parse them.
+ if (Tok.is(tok::kw___attribute))
+ // FIXME: attach attributes too.
+ AttrList = ParseAttributes();
+
+ // Ask the actions module to compute the type for this declarator.
+ Action::DeclPtrTy Param =
+ Actions.ActOnParamDeclarator(CurScope, ParmDeclarator);
+
+ if (Param &&
+ // A missing identifier has already been diagnosed.
+ ParmDeclarator.getIdentifier()) {
+
+ // Scan the argument list looking for the correct param to apply this
+ // type.
+ for (unsigned i = 0; ; ++i) {
+ // C99 6.9.1p6: those declarators shall declare only identifiers from
+ // the identifier list.
+ if (i == FTI.NumArgs) {
+ Diag(ParmDeclarator.getIdentifierLoc(), diag::err_no_matching_param)
+ << ParmDeclarator.getIdentifier();
+ break;
+ }
+
+ if (FTI.ArgInfo[i].Ident == ParmDeclarator.getIdentifier()) {
+ // Reject redefinitions of parameters.
+ if (FTI.ArgInfo[i].Param) {
+ Diag(ParmDeclarator.getIdentifierLoc(),
+ diag::err_param_redefinition)
+ << ParmDeclarator.getIdentifier();
+ } else {
+ FTI.ArgInfo[i].Param = Param;
+ }
+ break;
+ }
+ }
+ }
+
+ // 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))
+ break;
+
+ // Consume the comma.
+ ConsumeToken();
+
+ // Parse the next declarator.
+ ParmDeclarator.clear();
+ ParseDeclarator(ParmDeclarator);
+ }
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ } else {
+ Diag(Tok, diag::err_parse_error);
+ // Skip to end of block or statement
+ SkipUntil(tok::semi, true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ }
+ }
+
+ // The actions module must verify that all arguments were declared.
+ Actions.ActOnFinishKNRParamDeclarations(CurScope, D, Tok.getLocation());
+}
+
+
+/// ParseAsmStringLiteral - This is just a normal string-literal, but is not
+/// allowed to be a wide string, and is not subject to character translation.
+///
+/// [GNU] asm-string-literal:
+/// string-literal
+///
+Parser::OwningExprResult Parser::ParseAsmStringLiteral() {
+ if (!isTokenStringLiteral()) {
+ Diag(Tok, diag::err_expected_string_literal);
+ return ExprError();
+ }
+
+ OwningExprResult Res(ParseStringLiteralExpression());
+ if (Res.isInvalid()) return move(Res);
+
+ // TODO: Diagnose: wide string literal in 'asm'
+
+ return move(Res);
+}
+
+/// ParseSimpleAsm
+///
+/// [GNU] simple-asm-expr:
+/// 'asm' '(' asm-string-literal ')'
+///
+Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
+ assert(Tok.is(tok::kw_asm) && "Not an asm!");
+ SourceLocation Loc = ConsumeToken();
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "asm";
+ return ExprError();
+ }
+
+ Loc = ConsumeParen();
+
+ OwningExprResult Result(ParseAsmStringLiteral());
+
+ if (Result.isInvalid()) {
+ SkipUntil(tok::r_paren, true, true);
+ if (EndLoc)
+ *EndLoc = Tok.getLocation();
+ ConsumeAnyToken();
+ } else {
+ Loc = MatchRHSPunctuation(tok::r_paren, Loc);
+ if (EndLoc)
+ *EndLoc = Loc;
+ }
+
+ return move(Result);
+}
+
+/// TryAnnotateTypeOrScopeToken - If the current token position is on a
+/// typename (possibly qualified in C++) or a C++ scope specifier not followed
+/// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens
+/// with a single annotation token representing the typename or C++ scope
+/// respectively.
+/// This simplifies handling of C++ scope specifiers and allows efficient
+/// backtracking without the need to re-parse and resolve nested-names and
+/// typenames.
+/// It will mainly be called when we expect to treat identifiers as typenames
+/// (if they are typenames). For example, in C we do not expect identifiers
+/// inside expressions to be treated as typenames so it will not be called
+/// for expressions in C.
+/// The benefit for C/ObjC is that a typename will be annotated and
+/// Actions.getTypeName will not be needed to be called again (e.g. getTypeName
+/// will not be called twice, once to check whether we have a declaration
+/// specifier, and another one to get the actual type inside
+/// ParseDeclarationSpecifiers).
+///
+/// This returns true if the token was annotated.
+///
+/// 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() {
+ assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon)
+ || Tok.is(tok::kw_typename)) &&
+ "Cannot be a type or scope token!");
+
+ if (Tok.is(tok::kw_typename)) {
+ // Parse a C++ typename-specifier, e.g., "typename T::type".
+ //
+ // typename-specifier:
+ // 'typename' '::' [opt] nested-name-specifier identifier
+ // 'typename' '::' [opt] nested-name-specifier template [opt]
+ // simple-template-id
+ SourceLocation TypenameLoc = ConsumeToken();
+ CXXScopeSpec SS;
+ bool HadNestedNameSpecifier = ParseOptionalCXXScopeSpecifier(SS);
+ if (!HadNestedNameSpecifier) {
+ Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
+ return false;
+ }
+
+ TypeResult Ty;
+ if (Tok.is(tok::identifier)) {
+ // FIXME: check whether the next token is '<', first!
+ Ty = Actions.ActOnTypenameType(TypenameLoc, SS, *Tok.getIdentifierInfo(),
+ Tok.getLocation());
+ } else if (Tok.is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (TemplateId->Kind == TNK_Function_template) {
+ Diag(Tok, diag::err_typename_refers_to_non_type_template)
+ << Tok.getAnnotationRange();
+ return false;
+ }
+
+ AnnotateTemplateIdTokenAsType(0);
+ assert(Tok.is(tok::annot_typename) &&
+ "AnnotateTemplateIdTokenAsType isn't working properly");
+ if (Tok.getAnnotationValue())
+ Ty = Actions.ActOnTypenameType(TypenameLoc, SS, SourceLocation(),
+ Tok.getAnnotationValue());
+ else
+ Ty = true;
+ } else {
+ Diag(Tok, diag::err_expected_type_name_after_typename)
+ << SS.getRange();
+ return false;
+ }
+
+ Tok.setKind(tok::annot_typename);
+ Tok.setAnnotationValue(Ty.isInvalid()? 0 : Ty.get());
+ Tok.setAnnotationEndLoc(Tok.getLocation());
+ Tok.setLocation(TypenameLoc);
+ PP.AnnotateCachedTokens(Tok);
+ return true;
+ }
+
+ CXXScopeSpec SS;
+ if (getLang().CPlusPlus)
+ ParseOptionalCXXScopeSpecifier(SS);
+
+ if (Tok.is(tok::identifier)) {
+ // Determine whether the identifier is a type name.
+ if (TypeTy *Ty = Actions.getTypeName(*Tok.getIdentifierInfo(),
+ Tok.getLocation(), CurScope, &SS)) {
+ // This is a typename. Replace the current token in-place with an
+ // annotation type token.
+ Tok.setKind(tok::annot_typename);
+ Tok.setAnnotationValue(Ty);
+ Tok.setAnnotationEndLoc(Tok.getLocation());
+ if (SS.isNotEmpty()) // it was a C++ qualified type name.
+ Tok.setLocation(SS.getBeginLoc());
+
+ // In case the tokens were cached, have Preprocessor replace
+ // them with the annotation token.
+ PP.AnnotateCachedTokens(Tok);
+ return true;
+ }
+
+ if (!getLang().CPlusPlus) {
+ // If we're in C, we can't have :: tokens at all (the lexer won't return
+ // them). If the identifier is not a type, then it can't be scope either,
+ // just early exit.
+ return false;
+ }
+
+ // If this is a template-id, annotate with a template-id or type token.
+ if (NextToken().is(tok::less)) {
+ TemplateTy Template;
+ if (TemplateNameKind TNK
+ = Actions.isTemplateName(*Tok.getIdentifierInfo(),
+ CurScope, Template, &SS))
+ AnnotateTemplateIdToken(Template, TNK, &SS);
+ }
+
+ // The current token, which is either an identifier or a
+ // template-id, is not part of the annotation. Fall through to
+ // push that token back into the stream and complete the C++ scope
+ // specifier annotation.
+ }
+
+ if (Tok.is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (TemplateId->Kind == TNK_Type_template) {
+ // A template-id that refers to a type was parsed into a
+ // template-id annotation in a context where we weren't allowed
+ // to produce a type annotation token. Update the template-id
+ // annotation token to a type annotation token now.
+ AnnotateTemplateIdTokenAsType(&SS);
+ return true;
+ }
+ }
+
+ if (SS.isEmpty())
+ return false;
+
+ // A C++ scope specifier that isn't followed by a typename.
+ // Push the current token back into the token stream (or revert it if it is
+ // cached) and use an annotation scope token for current token.
+ if (PP.isBacktrackEnabled())
+ PP.RevertCachedTokens(1);
+ else
+ PP.EnterToken(Tok);
+ Tok.setKind(tok::annot_cxxscope);
+ Tok.setAnnotationValue(SS.getScopeRep());
+ Tok.setAnnotationRange(SS.getRange());
+
+ // In case the tokens were cached, have Preprocessor replace them with the
+ // annotation token.
+ PP.AnnotateCachedTokens(Tok);
+ return true;
+}
+
+/// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only
+/// annotates C++ scope specifiers and template-ids. This returns
+/// true if the token was annotated.
+///
+/// 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::TryAnnotateCXXScopeToken() {
+ assert(getLang().CPlusPlus &&
+ "Call sites of this function should be guarded by checking for C++");
+ assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) &&
+ "Cannot be a type or scope token!");
+
+ CXXScopeSpec SS;
+ if (!ParseOptionalCXXScopeSpecifier(SS))
+ return Tok.is(tok::annot_template_id);
+
+ // Push the current token back into the token stream (or revert it if it is
+ // cached) and use an annotation scope token for current token.
+ if (PP.isBacktrackEnabled())
+ PP.RevertCachedTokens(1);
+ else
+ PP.EnterToken(Tok);
+ Tok.setKind(tok::annot_cxxscope);
+ Tok.setAnnotationValue(SS.getScopeRep());
+ Tok.setAnnotationRange(SS.getRange());
+
+ // In case the tokens were cached, have Preprocessor replace them with the
+ // annotation token.
+ PP.AnnotateCachedTokens(Tok);
+ return true;
+}
diff --git a/lib/Rewrite/CMakeLists.txt b/lib/Rewrite/CMakeLists.txt
new file mode 100644
index 000000000000..52670b82a295
--- /dev/null
+++ b/lib/Rewrite/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(LLVM_NO_RTTI 1)
+
+add_clang_library(clangRewrite
+ DeltaTree.cpp
+ HTMLRewrite.cpp
+ Rewriter.cpp
+ RewriteRope.cpp
+ TokenRewriter.cpp
+ )
diff --git a/lib/Rewrite/DeltaTree.cpp b/lib/Rewrite/DeltaTree.cpp
new file mode 100644
index 000000000000..5d51ddae0896
--- /dev/null
+++ b/lib/Rewrite/DeltaTree.cpp
@@ -0,0 +1,485 @@
+//===--- DeltaTree.cpp - B-Tree for Rewrite Delta tracking ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the DeltaTree and related classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Rewrite/DeltaTree.h"
+#include "llvm/Support/Casting.h"
+#include <cstring>
+#include <cstdio>
+using namespace clang;
+using llvm::cast;
+using llvm::dyn_cast;
+
+namespace {
+ struct SourceDelta;
+ class DeltaTreeNode;
+ class DeltaTreeInteriorNode;
+}
+
+/// The DeltaTree class is a multiway search tree (BTree) structure with some
+/// fancy features. B-Trees are are generally more memory and cache efficient
+/// than binary trees, because they store multiple keys/values in each node.
+///
+/// DeltaTree implements a key/value mapping from FileIndex to Delta, allowing
+/// fast lookup by FileIndex. However, an added (important) bonus is that it
+/// can also efficiently tell us the full accumulated delta for a specific
+/// file offset as well, without traversing the whole tree.
+///
+/// The nodes of the tree are made up of instances of two classes:
+/// DeltaTreeNode and DeltaTreeInteriorNode. The later subclasses the
+/// former and adds children pointers. Each node knows the full delta of all
+/// entries (recursively) contained inside of it, which allows us to get the
+/// full delta implied by a whole subtree in constant time.
+
+namespace {
+ /// SourceDelta - As code in the original input buffer is added and deleted,
+ /// SourceDelta records are used to keep track of how the input SourceLocation
+ /// object is mapped into the output buffer.
+ struct SourceDelta {
+ unsigned FileLoc;
+ int Delta;
+
+ static SourceDelta get(unsigned Loc, int D) {
+ SourceDelta Delta;
+ Delta.FileLoc = Loc;
+ Delta.Delta = D;
+ return Delta;
+ }
+ };
+} // end anonymous namespace
+
+
+namespace {
+ struct InsertResult {
+ DeltaTreeNode *LHS, *RHS;
+ SourceDelta Split;
+ };
+} // end anonymous namespace
+
+
+namespace {
+ /// DeltaTreeNode - The common part of all nodes.
+ ///
+ class DeltaTreeNode {
+ friend class DeltaTreeInteriorNode;
+
+ /// WidthFactor - This controls the number of K/V slots held in the BTree:
+ /// how wide it is. Each level of the BTree is guaranteed to have at least
+ /// WidthFactor-1 K/V pairs (except the root) and may have at most
+ /// 2*WidthFactor-1 K/V pairs.
+ enum { WidthFactor = 8 };
+
+ /// Values - This tracks the SourceDelta's currently in this node.
+ ///
+ SourceDelta Values[2*WidthFactor-1];
+
+ /// NumValuesUsed - This tracks the number of values this node currently
+ /// holds.
+ unsigned char NumValuesUsed;
+
+ /// IsLeaf - This is true if this is a leaf of the btree. If false, this is
+ /// an interior node, and is actually an instance of DeltaTreeInteriorNode.
+ bool IsLeaf;
+
+ /// FullDelta - This is the full delta of all the values in this node and
+ /// all children nodes.
+ int FullDelta;
+ public:
+ DeltaTreeNode(bool isLeaf = true)
+ : NumValuesUsed(0), IsLeaf(isLeaf), FullDelta(0) {}
+
+ bool isLeaf() const { return IsLeaf; }
+ int getFullDelta() const { return FullDelta; }
+ bool isFull() const { return NumValuesUsed == 2*WidthFactor-1; }
+
+ unsigned getNumValuesUsed() const { return NumValuesUsed; }
+ const SourceDelta &getValue(unsigned i) const {
+ assert(i < NumValuesUsed && "Invalid value #");
+ return Values[i];
+ }
+ SourceDelta &getValue(unsigned i) {
+ assert(i < NumValuesUsed && "Invalid value #");
+ return Values[i];
+ }
+
+ /// DoInsertion - Do an insertion of the specified FileIndex/Delta pair into
+ /// this node. If insertion is easy, do it and return false. Otherwise,
+ /// split the node, populate InsertRes with info about the split, and return
+ /// true.
+ bool DoInsertion(unsigned FileIndex, int Delta, InsertResult *InsertRes);
+
+ void DoSplit(InsertResult &InsertRes);
+
+
+ /// RecomputeFullDeltaLocally - Recompute the FullDelta field by doing a
+ /// local walk over our contained deltas.
+ void RecomputeFullDeltaLocally();
+
+ void Destroy();
+
+ static inline bool classof(const DeltaTreeNode *) { return true; }
+ };
+} // end anonymous namespace
+
+namespace {
+ /// DeltaTreeInteriorNode - When isLeaf = false, a node has child pointers.
+ /// This class tracks them.
+ class DeltaTreeInteriorNode : public DeltaTreeNode {
+ DeltaTreeNode *Children[2*WidthFactor];
+ ~DeltaTreeInteriorNode() {
+ for (unsigned i = 0, e = NumValuesUsed+1; i != e; ++i)
+ Children[i]->Destroy();
+ }
+ friend class DeltaTreeNode;
+ public:
+ DeltaTreeInteriorNode() : DeltaTreeNode(false /*nonleaf*/) {}
+
+ DeltaTreeInteriorNode(DeltaTreeNode *FirstChild)
+ : DeltaTreeNode(false /*nonleaf*/) {
+ FullDelta = FirstChild->FullDelta;
+ Children[0] = FirstChild;
+ }
+
+ DeltaTreeInteriorNode(const InsertResult &IR)
+ : DeltaTreeNode(false /*nonleaf*/) {
+ Children[0] = IR.LHS;
+ Children[1] = IR.RHS;
+ Values[0] = IR.Split;
+ FullDelta = IR.LHS->getFullDelta()+IR.RHS->getFullDelta()+IR.Split.Delta;
+ NumValuesUsed = 1;
+ }
+
+ const DeltaTreeNode *getChild(unsigned i) const {
+ assert(i < getNumValuesUsed()+1 && "Invalid child");
+ return Children[i];
+ }
+ DeltaTreeNode *getChild(unsigned i) {
+ assert(i < getNumValuesUsed()+1 && "Invalid child");
+ return Children[i];
+ }
+
+ static inline bool classof(const DeltaTreeInteriorNode *) { return true; }
+ static inline bool classof(const DeltaTreeNode *N) { return !N->isLeaf(); }
+ };
+}
+
+
+/// Destroy - A 'virtual' destructor.
+void DeltaTreeNode::Destroy() {
+ if (isLeaf())
+ delete this;
+ else
+ delete cast<DeltaTreeInteriorNode>(this);
+}
+
+/// RecomputeFullDeltaLocally - Recompute the FullDelta field by doing a
+/// local walk over our contained deltas.
+void DeltaTreeNode::RecomputeFullDeltaLocally() {
+ int NewFullDelta = 0;
+ for (unsigned i = 0, e = getNumValuesUsed(); i != e; ++i)
+ NewFullDelta += Values[i].Delta;
+ if (DeltaTreeInteriorNode *IN = dyn_cast<DeltaTreeInteriorNode>(this))
+ for (unsigned i = 0, e = getNumValuesUsed()+1; i != e; ++i)
+ NewFullDelta += IN->getChild(i)->getFullDelta();
+ FullDelta = NewFullDelta;
+}
+
+/// DoInsertion - Do an insertion of the specified FileIndex/Delta pair into
+/// this node. If insertion is easy, do it and return false. Otherwise,
+/// split the node, populate InsertRes with info about the split, and return
+/// true.
+bool DeltaTreeNode::DoInsertion(unsigned FileIndex, int Delta,
+ InsertResult *InsertRes) {
+ // Maintain full delta for this node.
+ FullDelta += Delta;
+
+ // Find the insertion point, the first delta whose index is >= FileIndex.
+ unsigned i = 0, e = getNumValuesUsed();
+ while (i != e && FileIndex > getValue(i).FileLoc)
+ ++i;
+
+ // If we found an a record for exactly this file index, just merge this
+ // value into the pre-existing record and finish early.
+ if (i != e && getValue(i).FileLoc == FileIndex) {
+ // NOTE: Delta could drop to zero here. This means that the delta entry is
+ // useless and could be removed. Supporting erases is more complex than
+ // leaving an entry with Delta=0, so we just leave an entry with Delta=0 in
+ // the tree.
+ Values[i].Delta += Delta;
+ return false;
+ }
+
+ // Otherwise, we found an insertion point, and we know that the value at the
+ // specified index is > FileIndex. Handle the leaf case first.
+ if (isLeaf()) {
+ if (!isFull()) {
+ // For an insertion into a non-full leaf node, just insert the value in
+ // its sorted position. This requires moving later values over.
+ if (i != e)
+ memmove(&Values[i+1], &Values[i], sizeof(Values[0])*(e-i));
+ Values[i] = SourceDelta::get(FileIndex, Delta);
+ ++NumValuesUsed;
+ return false;
+ }
+
+ // Otherwise, if this is leaf is full, split the node at its median, insert
+ // the value into one of the children, and return the result.
+ assert(InsertRes && "No result location specified");
+ DoSplit(*InsertRes);
+
+ if (InsertRes->Split.FileLoc > FileIndex)
+ InsertRes->LHS->DoInsertion(FileIndex, Delta, 0 /*can't fail*/);
+ else
+ InsertRes->RHS->DoInsertion(FileIndex, Delta, 0 /*can't fail*/);
+ return true;
+ }
+
+ // Otherwise, this is an interior node. Send the request down the tree.
+ DeltaTreeInteriorNode *IN = cast<DeltaTreeInteriorNode>(this);
+ if (!IN->Children[i]->DoInsertion(FileIndex, Delta, InsertRes))
+ return false; // If there was space in the child, just return.
+
+ // Okay, this split the subtree, producing a new value and two children to
+ // insert here. If this node is non-full, we can just insert it directly.
+ if (!isFull()) {
+ // Now that we have two nodes and a new element, insert the perclated value
+ // into ourself by moving all the later values/children down, then inserting
+ // the new one.
+ if (i != e)
+ memmove(&IN->Children[i+2], &IN->Children[i+1],
+ (e-i)*sizeof(IN->Children[0]));
+ IN->Children[i] = InsertRes->LHS;
+ IN->Children[i+1] = InsertRes->RHS;
+
+ if (e != i)
+ memmove(&Values[i+1], &Values[i], (e-i)*sizeof(Values[0]));
+ Values[i] = InsertRes->Split;
+ ++NumValuesUsed;
+ return false;
+ }
+
+ // Finally, if this interior node was full and a node is percolated up, split
+ // ourself and return that up the chain. Start by saving all our info to
+ // avoid having the split clobber it.
+ IN->Children[i] = InsertRes->LHS;
+ DeltaTreeNode *SubRHS = InsertRes->RHS;
+ SourceDelta SubSplit = InsertRes->Split;
+
+ // Do the split.
+ DoSplit(*InsertRes);
+
+ // Figure out where to insert SubRHS/NewSplit.
+ DeltaTreeInteriorNode *InsertSide;
+ if (SubSplit.FileLoc < InsertRes->Split.FileLoc)
+ InsertSide = cast<DeltaTreeInteriorNode>(InsertRes->LHS);
+ else
+ InsertSide = cast<DeltaTreeInteriorNode>(InsertRes->RHS);
+
+ // We now have a non-empty interior node 'InsertSide' to insert
+ // SubRHS/SubSplit into. Find out where to insert SubSplit.
+
+ // Find the insertion point, the first delta whose index is >SubSplit.FileLoc.
+ i = 0; e = InsertSide->getNumValuesUsed();
+ while (i != e && SubSplit.FileLoc > InsertSide->getValue(i).FileLoc)
+ ++i;
+
+ // Now we know that i is the place to insert the split value into. Insert it
+ // and the child right after it.
+ if (i != e)
+ memmove(&InsertSide->Children[i+2], &InsertSide->Children[i+1],
+ (e-i)*sizeof(IN->Children[0]));
+ InsertSide->Children[i+1] = SubRHS;
+
+ if (e != i)
+ memmove(&InsertSide->Values[i+1], &InsertSide->Values[i],
+ (e-i)*sizeof(Values[0]));
+ InsertSide->Values[i] = SubSplit;
+ ++InsertSide->NumValuesUsed;
+ InsertSide->FullDelta += SubSplit.Delta + SubRHS->getFullDelta();
+ return true;
+}
+
+/// DoSplit - Split the currently full node (which has 2*WidthFactor-1 values)
+/// into two subtrees each with "WidthFactor-1" values and a pivot value.
+/// Return the pieces in InsertRes.
+void DeltaTreeNode::DoSplit(InsertResult &InsertRes) {
+ assert(isFull() && "Why split a non-full node?");
+
+ // Since this node is full, it contains 2*WidthFactor-1 values. We move
+ // the first 'WidthFactor-1' values to the LHS child (which we leave in this
+ // node), propagate one value up, and move the last 'WidthFactor-1' values
+ // into the RHS child.
+
+ // Create the new child node.
+ DeltaTreeNode *NewNode;
+ if (DeltaTreeInteriorNode *IN = dyn_cast<DeltaTreeInteriorNode>(this)) {
+ // If this is an interior node, also move over 'WidthFactor' children
+ // into the new node.
+ DeltaTreeInteriorNode *New = new DeltaTreeInteriorNode();
+ memcpy(&New->Children[0], &IN->Children[WidthFactor],
+ WidthFactor*sizeof(IN->Children[0]));
+ NewNode = New;
+ } else {
+ // Just create the new leaf node.
+ NewNode = new DeltaTreeNode();
+ }
+
+ // Move over the last 'WidthFactor-1' values from here to NewNode.
+ memcpy(&NewNode->Values[0], &Values[WidthFactor],
+ (WidthFactor-1)*sizeof(Values[0]));
+
+ // Decrease the number of values in the two nodes.
+ NewNode->NumValuesUsed = NumValuesUsed = WidthFactor-1;
+
+ // Recompute the two nodes' full delta.
+ NewNode->RecomputeFullDeltaLocally();
+ RecomputeFullDeltaLocally();
+
+ InsertRes.LHS = this;
+ InsertRes.RHS = NewNode;
+ InsertRes.Split = Values[WidthFactor-1];
+}
+
+
+
+//===----------------------------------------------------------------------===//
+// DeltaTree Implementation
+//===----------------------------------------------------------------------===//
+
+//#define VERIFY_TREE
+
+#ifdef VERIFY_TREE
+/// VerifyTree - Walk the btree performing assertions on various properties to
+/// verify consistency. This is useful for debugging new changes to the tree.
+static void VerifyTree(const DeltaTreeNode *N) {
+ const DeltaTreeInteriorNode *IN = dyn_cast<DeltaTreeInteriorNode>(N);
+ if (IN == 0) {
+ // Verify leaves, just ensure that FullDelta matches up and the elements
+ // are in proper order.
+ int FullDelta = 0;
+ for (unsigned i = 0, e = N->getNumValuesUsed(); i != e; ++i) {
+ if (i)
+ assert(N->getValue(i-1).FileLoc < N->getValue(i).FileLoc);
+ FullDelta += N->getValue(i).Delta;
+ }
+ assert(FullDelta == N->getFullDelta());
+ return;
+ }
+
+ // Verify interior nodes: Ensure that FullDelta matches up and the
+ // elements are in proper order and the children are in proper order.
+ int FullDelta = 0;
+ for (unsigned i = 0, e = IN->getNumValuesUsed(); i != e; ++i) {
+ const SourceDelta &IVal = N->getValue(i);
+ const DeltaTreeNode *IChild = IN->getChild(i);
+ if (i)
+ assert(IN->getValue(i-1).FileLoc < IVal.FileLoc);
+ FullDelta += IVal.Delta;
+ FullDelta += IChild->getFullDelta();
+
+ // The largest value in child #i should be smaller than FileLoc.
+ assert(IChild->getValue(IChild->getNumValuesUsed()-1).FileLoc <
+ IVal.FileLoc);
+
+ // The smallest value in child #i+1 should be larger than FileLoc.
+ assert(IN->getChild(i+1)->getValue(0).FileLoc > IVal.FileLoc);
+ VerifyTree(IChild);
+ }
+
+ FullDelta += IN->getChild(IN->getNumValuesUsed())->getFullDelta();
+
+ assert(FullDelta == N->getFullDelta());
+}
+#endif // VERIFY_TREE
+
+static DeltaTreeNode *getRoot(void *Root) {
+ return (DeltaTreeNode*)Root;
+}
+
+DeltaTree::DeltaTree() {
+ Root = new DeltaTreeNode();
+}
+DeltaTree::DeltaTree(const DeltaTree &RHS) {
+ // Currently we only support copying when the RHS is empty.
+ assert(getRoot(RHS.Root)->getNumValuesUsed() == 0 &&
+ "Can only copy empty tree");
+ Root = new DeltaTreeNode();
+}
+
+DeltaTree::~DeltaTree() {
+ getRoot(Root)->Destroy();
+}
+
+/// getDeltaAt - Return the accumulated delta at the specified file offset.
+/// This includes all insertions or delections that occurred *before* the
+/// specified file index.
+int DeltaTree::getDeltaAt(unsigned FileIndex) const {
+ const DeltaTreeNode *Node = getRoot(Root);
+
+ int Result = 0;
+
+ // Walk down the tree.
+ while (1) {
+ // For all nodes, include any local deltas before the specified file
+ // index by summing them up directly. Keep track of how many were
+ // included.
+ unsigned NumValsGreater = 0;
+ for (unsigned e = Node->getNumValuesUsed(); NumValsGreater != e;
+ ++NumValsGreater) {
+ const SourceDelta &Val = Node->getValue(NumValsGreater);
+
+ if (Val.FileLoc >= FileIndex)
+ break;
+ Result += Val.Delta;
+ }
+
+ // If we have an interior node, include information about children and
+ // recurse. Otherwise, if we have a leaf, we're done.
+ const DeltaTreeInteriorNode *IN = dyn_cast<DeltaTreeInteriorNode>(Node);
+ if (!IN) return Result;
+
+ // Include any children to the left of the values we skipped, all of
+ // their deltas should be included as well.
+ for (unsigned i = 0; i != NumValsGreater; ++i)
+ Result += IN->getChild(i)->getFullDelta();
+
+ // If we found exactly the value we were looking for, break off the
+ // search early. There is no need to search the RHS of the value for
+ // partial results.
+ if (NumValsGreater != Node->getNumValuesUsed() &&
+ Node->getValue(NumValsGreater).FileLoc == FileIndex)
+ return Result+IN->getChild(NumValsGreater)->getFullDelta();
+
+ // Otherwise, traverse down the tree. The selected subtree may be
+ // partially included in the range.
+ Node = IN->getChild(NumValsGreater);
+ }
+ // NOT REACHED.
+}
+
+/// AddDelta - When a change is made that shifts around the text buffer,
+/// this method is used to record that info. It inserts a delta of 'Delta'
+/// into the current DeltaTree at offset FileIndex.
+void DeltaTree::AddDelta(unsigned FileIndex, int Delta) {
+ assert(Delta && "Adding a noop?");
+ DeltaTreeNode *MyRoot = getRoot(Root);
+
+ InsertResult InsertRes;
+ if (MyRoot->DoInsertion(FileIndex, Delta, &InsertRes)) {
+ Root = MyRoot = new DeltaTreeInteriorNode(InsertRes);
+ }
+
+#ifdef VERIFY_TREE
+ VerifyTree(MyRoot);
+#endif
+}
+
diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp
new file mode 100644
index 000000000000..69dd03ad3f1f
--- /dev/null
+++ b/lib/Rewrite/HTMLRewrite.cpp
@@ -0,0 +1,574 @@
+//== HTMLRewrite.cpp - Translate source code into prettified HTML --*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the HTMLRewriter clas, which is used to translate the
+// text of a source file into prettified HTML.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/HTMLRewrite.h"
+#include "clang/Lex/TokenConcatenation.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+
+/// HighlightRange - Highlight a range in the source code with the specified
+/// start/end tags. B/E must be in the same file. This ensures that
+/// start/end tags are placed at the start/end of each line if the range is
+/// multiline.
+void html::HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E,
+ const char *StartTag, const char *EndTag) {
+ SourceManager &SM = R.getSourceMgr();
+ B = SM.getInstantiationLoc(B);
+ E = SM.getInstantiationLoc(E);
+ FileID FID = SM.getFileID(B);
+ assert(SM.getFileID(E) == FID && "B/E not in the same file!");
+
+ unsigned BOffset = SM.getFileOffset(B);
+ unsigned EOffset = SM.getFileOffset(E);
+
+ // Include the whole end token in the range.
+ EOffset += Lexer::MeasureTokenLength(E, R.getSourceMgr(), R.getLangOpts());
+
+ HighlightRange(R.getEditBuffer(FID), BOffset, EOffset,
+ SM.getBufferData(FID).first, StartTag, EndTag);
+}
+
+/// HighlightRange - This is the same as the above method, but takes
+/// decomposed file locations.
+void html::HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E,
+ const char *BufferStart,
+ const char *StartTag, const char *EndTag) {
+ // Insert the tag at the absolute start/end of the range.
+ RB.InsertTextAfter(B, StartTag, strlen(StartTag));
+ RB.InsertTextBefore(E, EndTag, strlen(EndTag));
+
+ // Scan the range to see if there is a \r or \n. If so, and if the line is
+ // not blank, insert tags on that line as well.
+ bool HadOpenTag = true;
+
+ unsigned LastNonWhiteSpace = B;
+ for (unsigned i = B; i != E; ++i) {
+ switch (BufferStart[i]) {
+ case '\r':
+ case '\n':
+ // Okay, we found a newline in the range. If we have an open tag, we need
+ // to insert a close tag at the first non-whitespace before the newline.
+ if (HadOpenTag)
+ RB.InsertTextBefore(LastNonWhiteSpace+1, EndTag, strlen(EndTag));
+
+ // Instead of inserting an open tag immediately after the newline, we
+ // wait until we see a non-whitespace character. This prevents us from
+ // inserting tags around blank lines, and also allows the open tag to
+ // be put *after* whitespace on a non-blank line.
+ HadOpenTag = false;
+ break;
+ case '\0':
+ case ' ':
+ case '\t':
+ case '\f':
+ case '\v':
+ // Ignore whitespace.
+ break;
+
+ default:
+ // If there is no tag open, do it now.
+ if (!HadOpenTag) {
+ RB.InsertTextAfter(i, StartTag, strlen(StartTag));
+ HadOpenTag = true;
+ }
+
+ // Remember this character.
+ LastNonWhiteSpace = i;
+ break;
+ }
+ }
+}
+
+void html::EscapeText(Rewriter &R, FileID FID,
+ bool EscapeSpaces, bool ReplaceTabs) {
+
+ const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID);
+ const char* C = Buf->getBufferStart();
+ const char* FileEnd = Buf->getBufferEnd();
+
+ assert (C <= FileEnd);
+
+ RewriteBuffer &RB = R.getEditBuffer(FID);
+
+ unsigned ColNo = 0;
+ for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) {
+ switch (*C) {
+ default: ++ColNo; break;
+ case '\n':
+ case '\r':
+ ColNo = 0;
+ break;
+
+ case ' ':
+ if (EscapeSpaces)
+ RB.ReplaceText(FilePos, 1, "&nbsp;", 6);
+ ++ColNo;
+ break;
+ case '\f':
+ RB.ReplaceText(FilePos, 1, "<hr>", 4);
+ ColNo = 0;
+ break;
+
+ case '\t': {
+ if (!ReplaceTabs)
+ break;
+ unsigned NumSpaces = 8-(ColNo&7);
+ if (EscapeSpaces)
+ RB.ReplaceText(FilePos, 1, "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
+ "&nbsp;&nbsp;&nbsp;", 6*NumSpaces);
+ else
+ RB.ReplaceText(FilePos, 1, " ", NumSpaces);
+ ColNo += NumSpaces;
+ break;
+ }
+ case '<':
+ RB.ReplaceText(FilePos, 1, "&lt;", 4);
+ ++ColNo;
+ break;
+
+ case '>':
+ RB.ReplaceText(FilePos, 1, "&gt;", 4);
+ ++ColNo;
+ break;
+
+ case '&':
+ RB.ReplaceText(FilePos, 1, "&amp;", 5);
+ ++ColNo;
+ break;
+ }
+ }
+}
+
+std::string html::EscapeText(const std::string& s, bool EscapeSpaces,
+ bool ReplaceTabs) {
+
+ unsigned len = s.size();
+ std::string Str;
+ llvm::raw_string_ostream os(Str);
+
+ for (unsigned i = 0 ; i < len; ++i) {
+
+ char c = s[i];
+ switch (c) {
+ default:
+ os << c; break;
+
+ case ' ':
+ if (EscapeSpaces) os << "&nbsp;";
+ else os << ' ';
+ break;
+
+ case '\t':
+ if (ReplaceTabs) {
+ if (EscapeSpaces)
+ for (unsigned i = 0; i < 4; ++i)
+ os << "&nbsp;";
+ else
+ for (unsigned i = 0; i < 4; ++i)
+ os << " ";
+ }
+ else
+ os << c;
+
+ break;
+
+ case '<': os << "&lt;"; break;
+ case '>': os << "&gt;"; break;
+ case '&': os << "&amp;"; break;
+ }
+ }
+
+ return os.str();
+}
+
+static void AddLineNumber(RewriteBuffer &RB, unsigned LineNo,
+ unsigned B, unsigned E) {
+ llvm::SmallString<100> Str;
+ Str += "<tr><td class=\"num\" id=\"LN";
+ Str.append_uint(LineNo);
+ Str += "\">";
+ Str.append_uint(LineNo);
+ Str += "</td><td class=\"line\">";
+
+ if (B == E) { // Handle empty lines.
+ Str += " </td></tr>";
+ RB.InsertTextBefore(B, &Str[0], Str.size());
+ } else {
+ RB.InsertTextBefore(B, &Str[0], Str.size());
+ RB.InsertTextBefore(E, "</td></tr>", strlen("</td></tr>"));
+ }
+}
+
+void html::AddLineNumbers(Rewriter& R, FileID FID) {
+
+ const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID);
+ const char* FileBeg = Buf->getBufferStart();
+ const char* FileEnd = Buf->getBufferEnd();
+ const char* C = FileBeg;
+ RewriteBuffer &RB = R.getEditBuffer(FID);
+
+ assert (C <= FileEnd);
+
+ unsigned LineNo = 0;
+ unsigned FilePos = 0;
+
+ while (C != FileEnd) {
+
+ ++LineNo;
+ unsigned LineStartPos = FilePos;
+ unsigned LineEndPos = FileEnd - FileBeg;
+
+ assert (FilePos <= LineEndPos);
+ assert (C < FileEnd);
+
+ // Scan until the newline (or end-of-file).
+
+ while (C != FileEnd) {
+ char c = *C;
+ ++C;
+
+ if (c == '\n') {
+ LineEndPos = FilePos++;
+ break;
+ }
+
+ ++FilePos;
+ }
+
+ AddLineNumber(RB, LineNo, LineStartPos, LineEndPos);
+ }
+
+ // Add one big table tag that surrounds all of the code.
+ RB.InsertTextBefore(0, "<table class=\"code\">\n",
+ strlen("<table class=\"code\">\n"));
+
+ RB.InsertTextAfter(FileEnd - FileBeg, "</table>", strlen("</table>"));
+}
+
+void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID,
+ const char *title) {
+
+ const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID);
+ const char* FileStart = Buf->getBufferStart();
+ const char* FileEnd = Buf->getBufferEnd();
+
+ SourceLocation StartLoc = R.getSourceMgr().getLocForStartOfFile(FID);
+ SourceLocation EndLoc = StartLoc.getFileLocWithOffset(FileEnd-FileStart);
+
+ std::string s;
+ llvm::raw_string_ostream os(s);
+ os << "<!doctype html>\n" // Use HTML 5 doctype
+ "<html>\n<head>\n";
+
+ if (title)
+ os << "<title>" << html::EscapeText(title) << "</title>\n";
+
+ os << "<style type=\"text/css\">\n"
+ " body { color:#000000; background-color:#ffffff }\n"
+ " body { font-family:Helvetica, sans-serif; font-size:10pt }\n"
+ " h1 { font-size:14pt }\n"
+ " .code { border-collapse:collapse; width:100%; }\n"
+ " .code { font-family: \"Andale Mono\", monospace; font-size:10pt }\n"
+ " .code { line-height: 1.2em }\n"
+ " .comment { color: green; font-style: oblique }\n"
+ " .keyword { color: blue }\n"
+ " .string_literal { color: red }\n"
+ " .directive { color: darkmagenta }\n"
+ // Macro expansions.
+ " .expansion { display: none; }\n"
+ " .macro:hover .expansion { display: block; border: 2px solid #FF0000; "
+ "padding: 2px; background-color:#FFF0F0; font-weight: normal; "
+ " -webkit-border-radius:5px; -webkit-box-shadow:1px 1px 7px #000; "
+ "position: absolute; top: -1em; left:10em; z-index: 1 } \n"
+ " .macro { color: darkmagenta; background-color:LemonChiffon;"
+ // Macros are position: relative to provide base for expansions.
+ " position: relative }\n"
+ " .num { width:2.5em; padding-right:2ex; background-color:#eeeeee }\n"
+ " .num { text-align:right; font-size:8pt }\n"
+ " .num { color:#444444 }\n"
+ " .line { padding-left: 1ex; border-left: 3px solid #ccc }\n"
+ " .line { white-space: pre }\n"
+ " .msg { -webkit-box-shadow:1px 1px 7px #000 }\n"
+ " .msg { -webkit-border-radius:5px }\n"
+ " .msg { font-family:Helvetica, sans-serif; font-size:8pt }\n"
+ " .msg { float:left }\n"
+ " .msg { padding:0.25em 1ex 0.25em 1ex }\n"
+ " .msg { margin-top:10px; margin-bottom:10px }\n"
+ " .msg { font-weight:bold }\n"
+ " .msg { max-width:60em; word-wrap: break-word; white-space: pre-wrap }\n"
+ " .msgT { padding:0x; spacing:0x }\n"
+ " .msgEvent { background-color:#fff8b4; color:#000000 }\n"
+ " .msgControl { background-color:#bbbbbb; color:#000000 }\n"
+ " .mrange { background-color:#dfddf3 }\n"
+ " .mrange { border-bottom:1px solid #6F9DBE }\n"
+ " .PathIndex { font-weight: bold; padding:0px 5px 0px 5px; "
+ "margin-right:5px; }\n"
+ " .PathIndex { -webkit-border-radius:8px }\n"
+ " .PathIndexEvent { background-color:#bfba87 }\n"
+ " .PathIndexControl { background-color:#8c8c8c }\n"
+ " .CodeInsertionHint { font-weight: bold; background-color: #10dd10 }\n"
+ " .CodeRemovalHint { background-color:#de1010 }\n"
+ " .CodeRemovalHint { border-bottom:1px solid #6F9DBE }\n"
+ " table.simpletable {\n"
+ " padding: 5px;\n"
+ " font-size:12pt;\n"
+ " margin:20px;\n"
+ " border-collapse: collapse; border-spacing: 0px;\n"
+ " }\n"
+ " td.rowname {\n"
+ " text-align:right; font-weight:bold; color:#444444;\n"
+ " padding-right:2ex; }\n"
+ "</style>\n</head>\n<body>";
+
+ // Generate header
+ R.InsertStrBefore(StartLoc, os.str());
+ // Generate footer
+
+ R.InsertCStrAfter(EndLoc, "</body></html>\n");
+}
+
+/// SyntaxHighlight - Relex the specified FileID and annotate the HTML with
+/// information about keywords, macro expansions etc. This uses the macro
+/// table state from the end of the file, so it won't be perfectly perfect,
+/// but it will be reasonably close.
+void html::SyntaxHighlight(Rewriter &R, FileID FID, Preprocessor &PP) {
+ RewriteBuffer &RB = R.getEditBuffer(FID);
+
+ const SourceManager &SM = PP.getSourceManager();
+ Lexer L(FID, SM, PP.getLangOptions());
+ const char *BufferStart = L.getBufferStart();
+
+ // Inform the preprocessor that we want to retain comments as tokens, so we
+ // can highlight them.
+ L.SetCommentRetentionState(true);
+
+ // Lex all the tokens in raw mode, to avoid entering #includes or expanding
+ // macros.
+ Token Tok;
+ L.LexFromRawLexer(Tok);
+
+ while (Tok.isNot(tok::eof)) {
+ // Since we are lexing unexpanded tokens, all tokens are from the main
+ // FileID.
+ unsigned TokOffs = SM.getFileOffset(Tok.getLocation());
+ unsigned TokLen = Tok.getLength();
+ switch (Tok.getKind()) {
+ default: break;
+ case tok::identifier: {
+ // Fill in Result.IdentifierInfo, looking up the identifier in the
+ // identifier table.
+ IdentifierInfo *II = PP.LookUpIdentifierInfo(Tok, BufferStart+TokOffs);
+
+ // If this is a pp-identifier, for a keyword, highlight it as such.
+ if (II->getTokenID() != tok::identifier)
+ HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
+ "<span class='keyword'>", "</span>");
+ break;
+ }
+ case tok::comment:
+ HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
+ "<span class='comment'>", "</span>");
+ break;
+ case tok::wide_string_literal:
+ // Chop off the L prefix
+ ++TokOffs;
+ --TokLen;
+ // FALL THROUGH.
+ case tok::string_literal:
+ HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
+ "<span class='string_literal'>", "</span>");
+ break;
+ case tok::hash: {
+ // If this is a preprocessor directive, all tokens to end of line are too.
+ if (!Tok.isAtStartOfLine())
+ break;
+
+ // Eat all of the tokens until we get to the next one at the start of
+ // line.
+ unsigned TokEnd = TokOffs+TokLen;
+ L.LexFromRawLexer(Tok);
+ while (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof)) {
+ TokEnd = SM.getFileOffset(Tok.getLocation())+Tok.getLength();
+ L.LexFromRawLexer(Tok);
+ }
+
+ // Find end of line. This is a hack.
+ HighlightRange(RB, TokOffs, TokEnd, BufferStart,
+ "<span class='directive'>", "</span>");
+
+ // Don't skip the next token.
+ continue;
+ }
+ }
+
+ L.LexFromRawLexer(Tok);
+ }
+}
+
+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
+/// reasonably close.
+void html::HighlightMacros(Rewriter &R, FileID FID, Preprocessor& PP) {
+ // Re-lex the raw token stream into a token buffer.
+ const SourceManager &SM = PP.getSourceManager();
+ std::vector<Token> TokenStream;
+
+ Lexer L(FID, SM, PP.getLangOptions());
+
+ // Lex all the tokens in raw mode, to avoid entering #includes or expanding
+ // macros.
+ while (1) {
+ Token Tok;
+ L.LexFromRawLexer(Tok);
+
+ // If this is a # at the start of a line, discard it from the token stream.
+ // We don't want the re-preprocess step to see #defines, #includes or other
+ // preprocessor directives.
+ if (Tok.is(tok::hash) && Tok.isAtStartOfLine())
+ continue;
+
+ // If this is a ## token, change its kind to unknown so that repreprocessing
+ // it will not produce an error.
+ if (Tok.is(tok::hashhash))
+ Tok.setKind(tok::unknown);
+
+ // If this raw token is an identifier, the raw lexer won't have looked up
+ // the corresponding identifier info for it. Do this now so that it will be
+ // macro expanded when we re-preprocess it.
+ if (Tok.is(tok::identifier)) {
+ // Change the kind of this identifier to the appropriate token kind, e.g.
+ // turning "for" into a keyword.
+ Tok.setKind(PP.LookUpIdentifierInfo(Tok)->getTokenID());
+ }
+
+ TokenStream.push_back(Tok);
+
+ if (Tok.is(tok::eof)) break;
+ }
+
+ // Temporarily change the diagnostics object so that we ignore any generated
+ // diagnostics from this pass.
+ IgnoringDiagClient TmpDC;
+ Diagnostic TmpDiags(&TmpDC);
+
+ Diagnostic *OldDiags = &PP.getDiagnostics();
+ PP.setDiagnostics(TmpDiags);
+
+ // Inform the preprocessor that we don't want comments.
+ PP.SetCommentRetentionState(false, false);
+
+ // Enter the tokens we just lexed. This will cause them to be macro expanded
+ // but won't enter sub-files (because we removed #'s).
+ PP.EnterTokenStream(&TokenStream[0], TokenStream.size(), false, false);
+
+ TokenConcatenation ConcatInfo(PP);
+
+ // Lex all the tokens.
+ Token Tok;
+ PP.Lex(Tok);
+ while (Tok.isNot(tok::eof)) {
+ // Ignore non-macro tokens.
+ if (!Tok.getLocation().isMacroID()) {
+ PP.Lex(Tok);
+ continue;
+ }
+
+ // Okay, we have the first token of a macro expansion: highlight the
+ // instantiation by inserting a start tag before the macro instantiation and
+ // end tag after it.
+ std::pair<SourceLocation, SourceLocation> LLoc =
+ SM.getInstantiationRange(Tok.getLocation());
+
+ // Ignore tokens whose instantiation location was not the main file.
+ if (SM.getFileID(LLoc.first) != FID) {
+ PP.Lex(Tok);
+ continue;
+ }
+
+ assert(SM.getFileID(LLoc.second) == FID &&
+ "Start and end of expansion must be in the same ultimate file!");
+
+ std::string Expansion = PP.getSpelling(Tok);
+ unsigned LineLen = Expansion.size();
+
+ Token PrevTok = Tok;
+ // Okay, eat this token, getting the next one.
+ PP.Lex(Tok);
+
+ // Skip all the rest of the tokens that are part of this macro
+ // instantiation. It would be really nice to pop up a window with all the
+ // spelling of the tokens or something.
+ while (!Tok.is(tok::eof) &&
+ SM.getInstantiationLoc(Tok.getLocation()) == LLoc.first) {
+ // Insert a newline if the macro expansion is getting large.
+ if (LineLen > 60) {
+ Expansion += "<br>";
+ LineLen = 0;
+ }
+
+ LineLen -= Expansion.size();
+
+ // If the tokens were already space separated, or if they must be to avoid
+ // them being implicitly pasted, add a space between them.
+ if (Tok.hasLeadingSpace() ||
+ ConcatInfo.AvoidConcat(PrevTok, Tok))
+ Expansion += ' ';
+
+ // Escape any special characters in the token text.
+ Expansion += EscapeText(PP.getSpelling(Tok));
+ LineLen += Expansion.size();
+
+ PrevTok = Tok;
+ PP.Lex(Tok);
+ }
+
+
+ // Insert the expansion as the end tag, so that multi-line macros all get
+ // highlighted.
+ Expansion = "<span class='expansion'>" + Expansion + "</span></span>";
+
+ HighlightRange(R, LLoc.first, LLoc.second,
+ "<span class='macro'>", Expansion.c_str());
+ }
+
+ // Restore diagnostics object back to its own thing.
+ PP.setDiagnostics(*OldDiags);
+}
+
+void html::HighlightMacros(Rewriter &R, FileID FID,
+ PreprocessorFactory &PPF) {
+
+ llvm::OwningPtr<Preprocessor> PP(PPF.CreatePreprocessor());
+ HighlightMacros(R, FID, *PP);
+}
diff --git a/lib/Rewrite/Makefile b/lib/Rewrite/Makefile
new file mode 100644
index 000000000000..61fdf4006f86
--- /dev/null
+++ b/lib/Rewrite/Makefile
@@ -0,0 +1,22 @@
+##===- clang/lib/Rewrite/Makefile --------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements code transformation / rewriting facilities.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+LIBRARYNAME := clangRewrite
+BUILD_ARCHIVE = 1
+CXXFLAGS = -fno-rtti
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/Rewrite/RewriteRope.cpp b/lib/Rewrite/RewriteRope.cpp
new file mode 100644
index 000000000000..61cb02b9a591
--- /dev/null
+++ b/lib/Rewrite/RewriteRope.cpp
@@ -0,0 +1,807 @@
+//===--- RewriteRope.cpp - Rope specialized for rewriter --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the RewriteRope class, which is a powerful string.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Rewrite/RewriteRope.h"
+#include "llvm/Support/Casting.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
+/// O(log N), but with a very low constant factor).
+///
+/// The implementation of this datastructure is a conceptual linear sequence of
+/// RopePiece elements. Each RopePiece represents a view on a separately
+/// allocated and reference counted string. This means that splitting a very
+/// long string can be done in constant time by splitting a RopePiece that
+/// references the whole string into two rope pieces that reference each half.
+/// Once split, another string can be inserted in between the two halves by
+/// inserting a RopePiece in between the two others. All of this is very
+/// inexpensive: it takes time proportional to the number of RopePieces, not the
+/// length of the strings they represent.
+///
+/// While a linear sequences of RopePieces is the conceptual model, the actual
+/// implementation captures them in an adapted B+ Tree. Using a B+ tree (which
+/// is a tree that keeps the values in the leaves and has where each node
+/// contains a reasonable number of pointers to children/values) allows us to
+/// maintain efficient operation when the RewriteRope contains a *huge* number
+/// of RopePieces. The basic idea of the B+ Tree is that it allows us to find
+/// the RopePiece corresponding to some offset very efficiently, and it
+/// automatically balances itself on insertions of RopePieces (which can happen
+/// for both insertions and erases of string ranges).
+///
+/// The one wrinkle on the theory is that we don't attempt to keep the tree
+/// properly balanced when erases happen. Erases of string data can both insert
+/// new RopePieces (e.g. when the middle of some other rope piece is deleted,
+/// which results in two rope pieces, which is just like an insert) or it can
+/// reduce the number of RopePieces maintained by the B+Tree. In the case when
+/// the number of RopePieces is reduced, we don't attempt to maintain the
+/// standard 'invariant' that each node in the tree contains at least
+/// 'WidthFactor' children/values. For our use cases, this doesn't seem to
+/// matter.
+///
+/// The implementation below is primarily implemented in terms of three classes:
+/// RopePieceBTreeNode - Common base class for:
+///
+/// RopePieceBTreeLeaf - Directly manages up to '2*WidthFactor' RopePiece
+/// nodes. This directly represents a chunk of the string with those
+/// RopePieces contatenated.
+/// RopePieceBTreeInterior - An interior node in the B+ Tree, which manages
+/// up to '2*WidthFactor' other nodes in the tree.
+
+
+//===----------------------------------------------------------------------===//
+// RopePieceBTreeNode Class
+//===----------------------------------------------------------------------===//
+
+namespace {
+ /// RopePieceBTreeNode - Common base class of RopePieceBTreeLeaf and
+ /// RopePieceBTreeInterior. This provides some 'virtual' dispatching methods
+ /// and a flag that determines which subclass the instance is. Also
+ /// important, this node knows the full extend of the node, including any
+ /// children that it has. This allows efficient skipping over entire subtrees
+ /// when looking for an offset in the BTree.
+ class RopePieceBTreeNode {
+ protected:
+ /// WidthFactor - This controls the number of K/V slots held in the BTree:
+ /// how wide it is. Each level of the BTree is guaranteed to have at least
+ /// 'WidthFactor' elements in it (either ropepieces or children), (except
+ /// the root, which may have less) and may have at most 2*WidthFactor
+ /// elements.
+ enum { WidthFactor = 8 };
+
+ /// Size - This is the number of bytes of file this node (including any
+ /// potential children) covers.
+ unsigned Size;
+
+ /// IsLeaf - True if this is an instance of RopePieceBTreeLeaf, false if it
+ /// is an instance of RopePieceBTreeInterior.
+ bool IsLeaf;
+
+ RopePieceBTreeNode(bool isLeaf) : Size(0), IsLeaf(isLeaf) {}
+ ~RopePieceBTreeNode() {}
+ public:
+
+ bool isLeaf() const { return IsLeaf; }
+ unsigned size() const { return Size; }
+
+ void Destroy();
+
+ /// split - Split the range containing the specified offset so that we are
+ /// guaranteed that there is a place to do an insertion at the specified
+ /// offset. The offset is relative, so "0" is the start of the node.
+ ///
+ /// If there is no space in this subtree for the extra piece, the extra tree
+ /// node is returned and must be inserted into a parent.
+ RopePieceBTreeNode *split(unsigned Offset);
+
+ /// insert - Insert the specified ropepiece into this tree node at the
+ /// specified offset. The offset is relative, so "0" is the start of the
+ /// node.
+ ///
+ /// If there is no space in this subtree for the extra piece, the extra tree
+ /// node is returned and must be inserted into a parent.
+ RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R);
+
+ /// erase - Remove NumBytes from this node at the specified offset. We are
+ /// guaranteed that there is a split at Offset.
+ void erase(unsigned Offset, unsigned NumBytes);
+
+ static inline bool classof(const RopePieceBTreeNode *) { return true; }
+
+ };
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// RopePieceBTreeLeaf Class
+//===----------------------------------------------------------------------===//
+
+namespace {
+ /// RopePieceBTreeLeaf - Directly manages up to '2*WidthFactor' RopePiece
+ /// nodes. This directly represents a chunk of the string with those
+ /// RopePieces contatenated. Since this is a B+Tree, all values (in this case
+ /// instances of RopePiece) are stored in leaves like this. To make iteration
+ /// over the leaves efficient, they maintain a singly linked list through the
+ /// NextLeaf field. This allows the B+Tree forward iterator to be constant
+ /// time for all increments.
+ class RopePieceBTreeLeaf : public RopePieceBTreeNode {
+ /// NumPieces - This holds the number of rope pieces currently active in the
+ /// Pieces array.
+ unsigned char NumPieces;
+
+ /// Pieces - This tracks the file chunks currently in this leaf.
+ ///
+ RopePiece Pieces[2*WidthFactor];
+
+ /// NextLeaf - This is a pointer to the next leaf in the tree, allowing
+ /// efficient in-order forward iteration of the tree without traversal.
+ RopePieceBTreeLeaf **PrevLeaf, *NextLeaf;
+ public:
+ RopePieceBTreeLeaf() : RopePieceBTreeNode(true), NumPieces(0),
+ PrevLeaf(0), NextLeaf(0) {}
+ ~RopePieceBTreeLeaf() {
+ if (PrevLeaf || NextLeaf)
+ removeFromLeafInOrder();
+ }
+
+ bool isFull() const { return NumPieces == 2*WidthFactor; }
+
+ /// clear - Remove all rope pieces from this leaf.
+ void clear() {
+ while (NumPieces)
+ Pieces[--NumPieces] = RopePiece();
+ Size = 0;
+ }
+
+ unsigned getNumPieces() const { return NumPieces; }
+
+ const RopePiece &getPiece(unsigned i) const {
+ assert(i < getNumPieces() && "Invalid piece ID");
+ return Pieces[i];
+ }
+
+ const RopePieceBTreeLeaf *getNextLeafInOrder() const { return NextLeaf; }
+ void insertAfterLeafInOrder(RopePieceBTreeLeaf *Node) {
+ assert(PrevLeaf == 0 && NextLeaf == 0 && "Already in ordering");
+
+ NextLeaf = Node->NextLeaf;
+ if (NextLeaf)
+ NextLeaf->PrevLeaf = &NextLeaf;
+ PrevLeaf = &Node->NextLeaf;
+ Node->NextLeaf = this;
+ }
+
+ void removeFromLeafInOrder() {
+ if (PrevLeaf) {
+ *PrevLeaf = NextLeaf;
+ if (NextLeaf)
+ NextLeaf->PrevLeaf = PrevLeaf;
+ } else if (NextLeaf) {
+ NextLeaf->PrevLeaf = 0;
+ }
+ }
+
+ /// FullRecomputeSizeLocally - This method recomputes the 'Size' field by
+ /// summing the size of all RopePieces.
+ void FullRecomputeSizeLocally() {
+ Size = 0;
+ for (unsigned i = 0, e = getNumPieces(); i != e; ++i)
+ Size += getPiece(i).size();
+ }
+
+ /// split - Split the range containing the specified offset so that we are
+ /// guaranteed that there is a place to do an insertion at the specified
+ /// offset. The offset is relative, so "0" is the start of the node.
+ ///
+ /// If there is no space in this subtree for the extra piece, the extra tree
+ /// node is returned and must be inserted into a parent.
+ RopePieceBTreeNode *split(unsigned Offset);
+
+ /// insert - Insert the specified ropepiece into this tree node at the
+ /// specified offset. The offset is relative, so "0" is the start of the
+ /// node.
+ ///
+ /// If there is no space in this subtree for the extra piece, the extra tree
+ /// node is returned and must be inserted into a parent.
+ RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R);
+
+
+ /// erase - Remove NumBytes from this node at the specified offset. We are
+ /// guaranteed that there is a split at Offset.
+ void erase(unsigned Offset, unsigned NumBytes);
+
+ static inline bool classof(const RopePieceBTreeLeaf *) { return true; }
+ static inline bool classof(const RopePieceBTreeNode *N) {
+ return N->isLeaf();
+ }
+ };
+} // end anonymous namespace
+
+/// split - Split the range containing the specified offset so that we are
+/// guaranteed that there is a place to do an insertion at the specified
+/// offset. The offset is relative, so "0" is the start of the node.
+///
+/// If there is no space in this subtree for the extra piece, the extra tree
+/// node is returned and must be inserted into a parent.
+RopePieceBTreeNode *RopePieceBTreeLeaf::split(unsigned Offset) {
+ // Find the insertion point. We are guaranteed that there is a split at the
+ // specified offset so find it.
+ if (Offset == 0 || Offset == size()) {
+ // Fastpath for a common case. There is already a splitpoint at the end.
+ return 0;
+ }
+
+ // Find the piece that this offset lands in.
+ unsigned PieceOffs = 0;
+ unsigned i = 0;
+ while (Offset >= PieceOffs+Pieces[i].size()) {
+ PieceOffs += Pieces[i].size();
+ ++i;
+ }
+
+ // If there is already a split point at the specified offset, just return
+ // success.
+ if (PieceOffs == Offset)
+ return 0;
+
+ // Otherwise, we need to split piece 'i' at Offset-PieceOffs. Convert Offset
+ // to being Piece relative.
+ unsigned IntraPieceOffset = Offset-PieceOffs;
+
+ // We do this by shrinking the RopePiece and then doing an insert of the tail.
+ RopePiece Tail(Pieces[i].StrData, Pieces[i].StartOffs+IntraPieceOffset,
+ Pieces[i].EndOffs);
+ Size -= Pieces[i].size();
+ Pieces[i].EndOffs = Pieces[i].StartOffs+IntraPieceOffset;
+ Size += Pieces[i].size();
+
+ return insert(Offset, Tail);
+}
+
+
+/// insert - Insert the specified RopePiece into this tree node at the
+/// specified offset. The offset is relative, so "0" is the start of the node.
+///
+/// If there is no space in this subtree for the extra piece, the extra tree
+/// node is returned and must be inserted into a parent.
+RopePieceBTreeNode *RopePieceBTreeLeaf::insert(unsigned Offset,
+ const RopePiece &R) {
+ // If this node is not full, insert the piece.
+ if (!isFull()) {
+ // Find the insertion point. We are guaranteed that there is a split at the
+ // specified offset so find it.
+ unsigned i = 0, e = getNumPieces();
+ if (Offset == size()) {
+ // Fastpath for a common case.
+ i = e;
+ } else {
+ unsigned SlotOffs = 0;
+ for (; Offset > SlotOffs; ++i)
+ SlotOffs += getPiece(i).size();
+ assert(SlotOffs == Offset && "Split didn't occur before insertion!");
+ }
+
+ // For an insertion into a non-full leaf node, just insert the value in
+ // its sorted position. This requires moving later values over.
+ for (; i != e; --e)
+ Pieces[e] = Pieces[e-1];
+ Pieces[i] = R;
+ ++NumPieces;
+ Size += R.size();
+ return 0;
+ }
+
+ // Otherwise, if this is leaf is full, split it in two halves. Since this
+ // node is full, it contains 2*WidthFactor values. We move the first
+ // 'WidthFactor' values to the LHS child (which we leave in this node) and
+ // move the last 'WidthFactor' values into the RHS child.
+
+ // Create the new node.
+ RopePieceBTreeLeaf *NewNode = new RopePieceBTreeLeaf();
+
+ // Move over the last 'WidthFactor' values from here to NewNode.
+ std::copy(&Pieces[WidthFactor], &Pieces[2*WidthFactor],
+ &NewNode->Pieces[0]);
+ // Replace old pieces with null RopePieces to drop refcounts.
+ std::fill(&Pieces[WidthFactor], &Pieces[2*WidthFactor], RopePiece());
+
+ // Decrease the number of values in the two nodes.
+ NewNode->NumPieces = NumPieces = WidthFactor;
+
+ // Recompute the two nodes' size.
+ NewNode->FullRecomputeSizeLocally();
+ FullRecomputeSizeLocally();
+
+ // Update the list of leaves.
+ NewNode->insertAfterLeafInOrder(this);
+
+ // These insertions can't fail.
+ if (this->size() >= Offset)
+ this->insert(Offset, R);
+ else
+ NewNode->insert(Offset - this->size(), R);
+ return NewNode;
+}
+
+/// erase - Remove NumBytes from this node at the specified offset. We are
+/// guaranteed that there is a split at Offset.
+void RopePieceBTreeLeaf::erase(unsigned Offset, unsigned NumBytes) {
+ // Since we are guaranteed that there is a split at Offset, we start by
+ // finding the Piece that starts there.
+ unsigned PieceOffs = 0;
+ unsigned i = 0;
+ for (; Offset > PieceOffs; ++i)
+ PieceOffs += getPiece(i).size();
+ assert(PieceOffs == Offset && "Split didn't occur before erase!");
+
+ unsigned StartPiece = i;
+
+ // Figure out how many pieces completely cover 'NumBytes'. We want to remove
+ // all of them.
+ for (; Offset+NumBytes > PieceOffs+getPiece(i).size(); ++i)
+ PieceOffs += getPiece(i).size();
+
+ // If we exactly include the last one, include it in the region to delete.
+ if (Offset+NumBytes == PieceOffs+getPiece(i).size())
+ PieceOffs += getPiece(i).size(), ++i;
+
+ // If we completely cover some RopePieces, erase them now.
+ if (i != StartPiece) {
+ unsigned NumDeleted = i-StartPiece;
+ for (; i != getNumPieces(); ++i)
+ Pieces[i-NumDeleted] = Pieces[i];
+
+ // Drop references to dead rope pieces.
+ std::fill(&Pieces[getNumPieces()-NumDeleted], &Pieces[getNumPieces()],
+ RopePiece());
+ NumPieces -= NumDeleted;
+
+ unsigned CoverBytes = PieceOffs-Offset;
+ NumBytes -= CoverBytes;
+ Size -= CoverBytes;
+ }
+
+ // If we completely removed some stuff, we could be done.
+ if (NumBytes == 0) return;
+
+ // Okay, now might be erasing part of some Piece. If this is the case, then
+ // move the start point of the piece.
+ assert(getPiece(StartPiece).size() > NumBytes);
+ Pieces[StartPiece].StartOffs += NumBytes;
+
+ // The size of this node just shrunk by NumBytes.
+ Size -= NumBytes;
+}
+
+//===----------------------------------------------------------------------===//
+// RopePieceBTreeInterior Class
+//===----------------------------------------------------------------------===//
+
+namespace {
+ /// RopePieceBTreeInterior - This represents an interior node in the B+Tree,
+ /// which holds up to 2*WidthFactor pointers to child nodes.
+ class RopePieceBTreeInterior : public RopePieceBTreeNode {
+ /// NumChildren - This holds the number of children currently active in the
+ /// Children array.
+ unsigned char NumChildren;
+ RopePieceBTreeNode *Children[2*WidthFactor];
+ public:
+ RopePieceBTreeInterior() : RopePieceBTreeNode(false), NumChildren(0) {}
+
+ RopePieceBTreeInterior(RopePieceBTreeNode *LHS, RopePieceBTreeNode *RHS)
+ : RopePieceBTreeNode(false) {
+ Children[0] = LHS;
+ Children[1] = RHS;
+ NumChildren = 2;
+ Size = LHS->size() + RHS->size();
+ }
+
+ bool isFull() const { return NumChildren == 2*WidthFactor; }
+
+ unsigned getNumChildren() const { return NumChildren; }
+ const RopePieceBTreeNode *getChild(unsigned i) const {
+ assert(i < NumChildren && "invalid child #");
+ return Children[i];
+ }
+ RopePieceBTreeNode *getChild(unsigned i) {
+ assert(i < NumChildren && "invalid child #");
+ return Children[i];
+ }
+
+ /// FullRecomputeSizeLocally - Recompute the Size field of this node by
+ /// summing up the sizes of the child nodes.
+ void FullRecomputeSizeLocally() {
+ Size = 0;
+ for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
+ Size += getChild(i)->size();
+ }
+
+
+ /// split - Split the range containing the specified offset so that we are
+ /// guaranteed that there is a place to do an insertion at the specified
+ /// offset. The offset is relative, so "0" is the start of the node.
+ ///
+ /// If there is no space in this subtree for the extra piece, the extra tree
+ /// node is returned and must be inserted into a parent.
+ RopePieceBTreeNode *split(unsigned Offset);
+
+
+ /// insert - Insert the specified ropepiece into this tree node at the
+ /// specified offset. The offset is relative, so "0" is the start of the
+ /// node.
+ ///
+ /// If there is no space in this subtree for the extra piece, the extra tree
+ /// node is returned and must be inserted into a parent.
+ RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R);
+
+ /// HandleChildPiece - A child propagated an insertion result up to us.
+ /// Insert the new child, and/or propagate the result further up the tree.
+ RopePieceBTreeNode *HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS);
+
+ /// erase - Remove NumBytes from this node at the specified offset. We are
+ /// guaranteed that there is a split at Offset.
+ void erase(unsigned Offset, unsigned NumBytes);
+
+ static inline bool classof(const RopePieceBTreeInterior *) { return true; }
+ static inline bool classof(const RopePieceBTreeNode *N) {
+ return !N->isLeaf();
+ }
+ };
+} // end anonymous namespace
+
+/// split - Split the range containing the specified offset so that we are
+/// guaranteed that there is a place to do an insertion at the specified
+/// offset. The offset is relative, so "0" is the start of the node.
+///
+/// If there is no space in this subtree for the extra piece, the extra tree
+/// node is returned and must be inserted into a parent.
+RopePieceBTreeNode *RopePieceBTreeInterior::split(unsigned Offset) {
+ // Figure out which child to split.
+ if (Offset == 0 || Offset == size())
+ return 0; // If we have an exact offset, we're already split.
+
+ unsigned ChildOffset = 0;
+ unsigned i = 0;
+ for (; Offset >= ChildOffset+getChild(i)->size(); ++i)
+ ChildOffset += getChild(i)->size();
+
+ // If already split there, we're done.
+ if (ChildOffset == Offset)
+ return 0;
+
+ // Otherwise, recursively split the child.
+ if (RopePieceBTreeNode *RHS = getChild(i)->split(Offset-ChildOffset))
+ return HandleChildPiece(i, RHS);
+ return 0; // Done!
+}
+
+/// insert - Insert the specified ropepiece into this tree node at the
+/// specified offset. The offset is relative, so "0" is the start of the
+/// node.
+///
+/// If there is no space in this subtree for the extra piece, the extra tree
+/// node is returned and must be inserted into a parent.
+RopePieceBTreeNode *RopePieceBTreeInterior::insert(unsigned Offset,
+ const RopePiece &R) {
+ // Find the insertion point. We are guaranteed that there is a split at the
+ // specified offset so find it.
+ unsigned i = 0, e = getNumChildren();
+
+ unsigned ChildOffs = 0;
+ if (Offset == size()) {
+ // Fastpath for a common case. Insert at end of last child.
+ i = e-1;
+ ChildOffs = size()-getChild(i)->size();
+ } else {
+ for (; Offset > ChildOffs+getChild(i)->size(); ++i)
+ ChildOffs += getChild(i)->size();
+ }
+
+ Size += R.size();
+
+ // Insert at the end of this child.
+ if (RopePieceBTreeNode *RHS = getChild(i)->insert(Offset-ChildOffs, R))
+ return HandleChildPiece(i, RHS);
+
+ return 0;
+}
+
+/// HandleChildPiece - A child propagated an insertion result up to us.
+/// Insert the new child, and/or propagate the result further up the tree.
+RopePieceBTreeNode *
+RopePieceBTreeInterior::HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS) {
+ // Otherwise the child propagated a subtree up to us as a new child. See if
+ // we have space for it here.
+ if (!isFull()) {
+ // Insert RHS after child 'i'.
+ if (i + 1 != getNumChildren())
+ memmove(&Children[i+2], &Children[i+1],
+ (getNumChildren()-i-1)*sizeof(Children[0]));
+ Children[i+1] = RHS;
+ ++NumChildren;
+ return false;
+ }
+
+ // Okay, this node is full. Split it in half, moving WidthFactor children to
+ // a newly allocated interior node.
+
+ // Create the new node.
+ RopePieceBTreeInterior *NewNode = new RopePieceBTreeInterior();
+
+ // Move over the last 'WidthFactor' values from here to NewNode.
+ memcpy(&NewNode->Children[0], &Children[WidthFactor],
+ WidthFactor*sizeof(Children[0]));
+
+ // Decrease the number of values in the two nodes.
+ NewNode->NumChildren = NumChildren = WidthFactor;
+
+ // Finally, insert the two new children in the side the can (now) hold them.
+ // These insertions can't fail.
+ if (i < WidthFactor)
+ this->HandleChildPiece(i, RHS);
+ else
+ NewNode->HandleChildPiece(i-WidthFactor, RHS);
+
+ // Recompute the two nodes' size.
+ NewNode->FullRecomputeSizeLocally();
+ FullRecomputeSizeLocally();
+ return NewNode;
+}
+
+/// erase - Remove NumBytes from this node at the specified offset. We are
+/// guaranteed that there is a split at Offset.
+void RopePieceBTreeInterior::erase(unsigned Offset, unsigned NumBytes) {
+ // This will shrink this node by NumBytes.
+ Size -= NumBytes;
+
+ // Find the first child that overlaps with Offset.
+ unsigned i = 0;
+ for (; Offset >= getChild(i)->size(); ++i)
+ Offset -= getChild(i)->size();
+
+ // Propagate the delete request into overlapping children, or completely
+ // delete the children as appropriate.
+ while (NumBytes) {
+ RopePieceBTreeNode *CurChild = getChild(i);
+
+ // If we are deleting something contained entirely in the child, pass on the
+ // request.
+ if (Offset+NumBytes < CurChild->size()) {
+ CurChild->erase(Offset, NumBytes);
+ return;
+ }
+
+ // If this deletion request starts somewhere in the middle of the child, it
+ // must be deleting to the end of the child.
+ if (Offset) {
+ unsigned BytesFromChild = CurChild->size()-Offset;
+ CurChild->erase(Offset, BytesFromChild);
+ NumBytes -= BytesFromChild;
+ // Start at the beginning of the next child.
+ Offset = 0;
+ ++i;
+ continue;
+ }
+
+ // If the deletion request completely covers the child, delete it and move
+ // the rest down.
+ NumBytes -= CurChild->size();
+ CurChild->Destroy();
+ --NumChildren;
+ if (i != getNumChildren())
+ memmove(&Children[i], &Children[i+1],
+ (getNumChildren()-i)*sizeof(Children[0]));
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// RopePieceBTreeNode Implementation
+//===----------------------------------------------------------------------===//
+
+void RopePieceBTreeNode::Destroy() {
+ if (RopePieceBTreeLeaf *Leaf = dyn_cast<RopePieceBTreeLeaf>(this))
+ delete Leaf;
+ else
+ delete cast<RopePieceBTreeInterior>(this);
+}
+
+/// split - Split the range containing the specified offset so that we are
+/// guaranteed that there is a place to do an insertion at the specified
+/// offset. The offset is relative, so "0" is the start of the node.
+///
+/// If there is no space in this subtree for the extra piece, the extra tree
+/// node is returned and must be inserted into a parent.
+RopePieceBTreeNode *RopePieceBTreeNode::split(unsigned Offset) {
+ assert(Offset <= size() && "Invalid offset to split!");
+ if (RopePieceBTreeLeaf *Leaf = dyn_cast<RopePieceBTreeLeaf>(this))
+ return Leaf->split(Offset);
+ return cast<RopePieceBTreeInterior>(this)->split(Offset);
+}
+
+/// insert - Insert the specified ropepiece into this tree node at the
+/// specified offset. The offset is relative, so "0" is the start of the
+/// node.
+///
+/// If there is no space in this subtree for the extra piece, the extra tree
+/// node is returned and must be inserted into a parent.
+RopePieceBTreeNode *RopePieceBTreeNode::insert(unsigned Offset,
+ const RopePiece &R) {
+ assert(Offset <= size() && "Invalid offset to insert!");
+ if (RopePieceBTreeLeaf *Leaf = dyn_cast<RopePieceBTreeLeaf>(this))
+ return Leaf->insert(Offset, R);
+ return cast<RopePieceBTreeInterior>(this)->insert(Offset, R);
+}
+
+/// erase - Remove NumBytes from this node at the specified offset. We are
+/// guaranteed that there is a split at Offset.
+void RopePieceBTreeNode::erase(unsigned Offset, unsigned NumBytes) {
+ assert(Offset+NumBytes <= size() && "Invalid offset to erase!");
+ if (RopePieceBTreeLeaf *Leaf = dyn_cast<RopePieceBTreeLeaf>(this))
+ return Leaf->erase(Offset, NumBytes);
+ return cast<RopePieceBTreeInterior>(this)->erase(Offset, NumBytes);
+}
+
+
+//===----------------------------------------------------------------------===//
+// RopePieceBTreeIterator Implementation
+//===----------------------------------------------------------------------===//
+
+static const RopePieceBTreeLeaf *getCN(const void *P) {
+ return static_cast<const RopePieceBTreeLeaf*>(P);
+}
+
+// begin iterator.
+RopePieceBTreeIterator::RopePieceBTreeIterator(const void *n) {
+ const RopePieceBTreeNode *N = static_cast<const RopePieceBTreeNode*>(n);
+
+ // Walk down the left side of the tree until we get to a leaf.
+ while (const RopePieceBTreeInterior *IN = dyn_cast<RopePieceBTreeInterior>(N))
+ N = IN->getChild(0);
+
+ // We must have at least one leaf.
+ CurNode = cast<RopePieceBTreeLeaf>(N);
+
+ // If we found a leaf that happens to be empty, skip over it until we get
+ // to something full.
+ while (CurNode && getCN(CurNode)->getNumPieces() == 0)
+ CurNode = getCN(CurNode)->getNextLeafInOrder();
+
+ if (CurNode != 0)
+ CurPiece = &getCN(CurNode)->getPiece(0);
+ else // Empty tree, this is an end() iterator.
+ CurPiece = 0;
+ CurChar = 0;
+}
+
+void RopePieceBTreeIterator::MoveToNextPiece() {
+ if (CurPiece != &getCN(CurNode)->getPiece(getCN(CurNode)->getNumPieces()-1)) {
+ CurChar = 0;
+ ++CurPiece;
+ return;
+ }
+
+ // Find the next non-empty leaf node.
+ do
+ CurNode = getCN(CurNode)->getNextLeafInOrder();
+ while (CurNode && getCN(CurNode)->getNumPieces() == 0);
+
+ if (CurNode != 0)
+ CurPiece = &getCN(CurNode)->getPiece(0);
+ else // Hit end().
+ CurPiece = 0;
+ CurChar = 0;
+}
+
+//===----------------------------------------------------------------------===//
+// RopePieceBTree Implementation
+//===----------------------------------------------------------------------===//
+
+static RopePieceBTreeNode *getRoot(void *P) {
+ return static_cast<RopePieceBTreeNode*>(P);
+}
+
+RopePieceBTree::RopePieceBTree() {
+ Root = new RopePieceBTreeLeaf();
+}
+RopePieceBTree::RopePieceBTree(const RopePieceBTree &RHS) {
+ assert(RHS.empty() && "Can't copy non-empty tree yet");
+ Root = new RopePieceBTreeLeaf();
+}
+RopePieceBTree::~RopePieceBTree() {
+ getRoot(Root)->Destroy();
+}
+
+unsigned RopePieceBTree::size() const {
+ return getRoot(Root)->size();
+}
+
+void RopePieceBTree::clear() {
+ if (RopePieceBTreeLeaf *Leaf = dyn_cast<RopePieceBTreeLeaf>(getRoot(Root)))
+ Leaf->clear();
+ else {
+ getRoot(Root)->Destroy();
+ Root = new RopePieceBTreeLeaf();
+ }
+}
+
+void RopePieceBTree::insert(unsigned Offset, const RopePiece &R) {
+ // #1. Split at Offset.
+ if (RopePieceBTreeNode *RHS = getRoot(Root)->split(Offset))
+ Root = new RopePieceBTreeInterior(getRoot(Root), RHS);
+
+ // #2. Do the insertion.
+ if (RopePieceBTreeNode *RHS = getRoot(Root)->insert(Offset, R))
+ Root = new RopePieceBTreeInterior(getRoot(Root), RHS);
+}
+
+void RopePieceBTree::erase(unsigned Offset, unsigned NumBytes) {
+ // #1. Split at Offset.
+ if (RopePieceBTreeNode *RHS = getRoot(Root)->split(Offset))
+ Root = new RopePieceBTreeInterior(getRoot(Root), RHS);
+
+ // #2. Do the erasing.
+ getRoot(Root)->erase(Offset, NumBytes);
+}
+
+//===----------------------------------------------------------------------===//
+// RewriteRope Implementation
+//===----------------------------------------------------------------------===//
+
+/// MakeRopeString - This copies the specified byte range into some instance of
+/// RopeRefCountString, and return a RopePiece that represents it. This uses
+/// the AllocBuffer object to aggregate requests for small strings into one
+/// allocation instead of doing tons of tiny allocations.
+RopePiece RewriteRope::MakeRopeString(const char *Start, const char *End) {
+ unsigned Len = End-Start;
+ assert(Len && "Zero length RopePiece is invalid!");
+
+ // If we have space for this string in the current alloc buffer, use it.
+ if (AllocOffs+Len <= AllocChunkSize) {
+ memcpy(AllocBuffer->Data+AllocOffs, Start, Len);
+ AllocOffs += Len;
+ return RopePiece(AllocBuffer, AllocOffs-Len, AllocOffs);
+ }
+
+ // If we don't have enough room because this specific allocation is huge,
+ // just allocate a new rope piece for it alone.
+ if (Len > AllocChunkSize) {
+ unsigned Size = End-Start+sizeof(RopeRefCountString)-1;
+ RopeRefCountString *Res =
+ reinterpret_cast<RopeRefCountString *>(new char[Size]);
+ Res->RefCount = 0;
+ memcpy(Res->Data, Start, End-Start);
+ return RopePiece(Res, 0, End-Start);
+ }
+
+ // Otherwise, this was a small request but we just don't have space for it
+ // Make a new chunk and share it with later allocations.
+
+ // If we had an old allocation, drop our reference to it.
+ if (AllocBuffer && --AllocBuffer->RefCount == 0)
+ delete [] (char*)AllocBuffer;
+
+ unsigned AllocSize = offsetof(RopeRefCountString, Data) + AllocChunkSize;
+ AllocBuffer = reinterpret_cast<RopeRefCountString *>(new char[AllocSize]);
+ AllocBuffer->RefCount = 0;
+ memcpy(AllocBuffer->Data, Start, Len);
+ AllocOffs = Len;
+
+ // Start out the new allocation with a refcount of 1, since we have an
+ // internal reference to it.
+ AllocBuffer->addRef();
+ return RopePiece(AllocBuffer, 0, Len);
+}
+
+
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp
new file mode 100644
index 000000000000..d81c38d6a466
--- /dev/null
+++ b/lib/Rewrite/Rewriter.cpp
@@ -0,0 +1,228 @@
+//===--- Rewriter.cpp - Code rewriting interface --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Rewriter class, which is used for code
+// transformations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/Decl.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) {
+ // Nothing to remove, exit early.
+ if (Size == 0) return;
+
+ unsigned RealOffset = getMappedOffset(OrigOffset, true);
+ assert(RealOffset+Size < Buffer.size() && "Invalid location");
+
+ // Remove the dead characters.
+ Buffer.erase(RealOffset, Size);
+
+ // Add a delta so that future changes are offset correctly.
+ AddReplaceDelta(OrigOffset, -Size);
+}
+
+void RewriteBuffer::InsertText(unsigned OrigOffset,
+ const char *StrData, unsigned StrLen,
+ bool InsertAfter) {
+
+ // Nothing to insert, exit early.
+ if (StrLen == 0) return;
+
+ unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter);
+ Buffer.insert(RealOffset, StrData, StrData+StrLen);
+
+ // Add a delta so that future changes are offset correctly.
+ AddInsertDelta(OrigOffset, StrLen);
+}
+
+/// ReplaceText - This method replaces a range of characters in the input
+/// buffer with a new string. This is effectively a combined "remove+insert"
+/// operation.
+void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,
+ const char *NewStr, unsigned NewLength) {
+ unsigned RealOffset = getMappedOffset(OrigOffset, true);
+ Buffer.erase(RealOffset, OrigLength);
+ Buffer.insert(RealOffset, NewStr, NewStr+NewLength);
+ if (OrigLength != NewLength)
+ AddReplaceDelta(OrigOffset, NewLength-OrigLength);
+}
+
+
+//===----------------------------------------------------------------------===//
+// Rewriter class
+//===----------------------------------------------------------------------===//
+
+/// getRangeSize - Return the size in bytes of the specified range if they
+/// are in the same file. If not, this returns -1.
+int Rewriter::getRangeSize(SourceRange Range) const {
+ if (!isRewritable(Range.getBegin()) ||
+ !isRewritable(Range.getEnd())) return -1;
+
+ FileID StartFileID, EndFileID;
+ unsigned StartOff, EndOff;
+
+ StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID);
+ EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID);
+
+ if (StartFileID != EndFileID)
+ return -1;
+
+ // If edits have been made to this buffer, the delta between the range may
+ // have changed.
+ std::map<FileID, RewriteBuffer>::const_iterator I =
+ RewriteBuffers.find(StartFileID);
+ if (I != RewriteBuffers.end()) {
+ const RewriteBuffer &RB = I->second;
+ EndOff = RB.getMappedOffset(EndOff, true);
+ StartOff = RB.getMappedOffset(StartOff);
+ }
+
+
+ // Adjust the end offset to the end of the last token, instead of being the
+ // start of the last token.
+ EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
+
+ return EndOff-StartOff;
+}
+
+/// getRewritenText - Return the rewritten form of the text in the specified
+/// range. If the start or end of the range was unrewritable or if they are
+/// in different buffers, this returns an empty string.
+///
+/// Note that this method is not particularly efficient.
+///
+std::string Rewriter::getRewritenText(SourceRange Range) const {
+ if (!isRewritable(Range.getBegin()) ||
+ !isRewritable(Range.getEnd()))
+ return "";
+
+ FileID StartFileID, EndFileID;
+ unsigned StartOff, EndOff;
+ StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID);
+ EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID);
+
+ if (StartFileID != EndFileID)
+ return ""; // Start and end in different buffers.
+
+ // If edits have been made to this buffer, the delta between the range may
+ // have changed.
+ std::map<FileID, RewriteBuffer>::const_iterator I =
+ RewriteBuffers.find(StartFileID);
+ if (I == RewriteBuffers.end()) {
+ // If the buffer hasn't been rewritten, just return the text from the input.
+ const char *Ptr = SourceMgr->getCharacterData(Range.getBegin());
+
+ // Adjust the end offset to the end of the last token, instead of being the
+ // start of the last token.
+ EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
+ return std::string(Ptr, Ptr+EndOff-StartOff);
+ }
+
+ const RewriteBuffer &RB = I->second;
+ EndOff = RB.getMappedOffset(EndOff, true);
+ StartOff = RB.getMappedOffset(StartOff);
+
+ // Adjust the end offset to the end of the last token, instead of being the
+ // start of the last token.
+ EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
+
+ // Advance the iterators to the right spot, yay for linear time algorithms.
+ RewriteBuffer::iterator Start = RB.begin();
+ std::advance(Start, StartOff);
+ RewriteBuffer::iterator End = Start;
+ std::advance(End, EndOff-StartOff);
+
+ return std::string(Start, End);
+}
+
+unsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc,
+ FileID &FID) const {
+ assert(Loc.isValid() && "Invalid location");
+ std::pair<FileID,unsigned> V = SourceMgr->getDecomposedLoc(Loc);
+ FID = V.first;
+ return V.second;
+}
+
+
+/// getEditBuffer - Get or create a RewriteBuffer for the specified FileID.
+///
+RewriteBuffer &Rewriter::getEditBuffer(FileID FID) {
+ std::map<FileID, RewriteBuffer>::iterator I =
+ RewriteBuffers.lower_bound(FID);
+ if (I != RewriteBuffers.end() && I->first == FID)
+ return I->second;
+ I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer()));
+
+ std::pair<const char*, const char*> MB = SourceMgr->getBufferData(FID);
+ I->second.Initialize(MB.first, MB.second);
+
+ return I->second;
+}
+
+/// InsertText - Insert the specified string at the specified location in the
+/// original buffer.
+bool Rewriter::InsertText(SourceLocation Loc, const char *StrData,
+ unsigned StrLen, bool InsertAfter) {
+ if (!isRewritable(Loc)) return true;
+ FileID FID;
+ unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
+ getEditBuffer(FID).InsertText(StartOffs, StrData, StrLen, InsertAfter);
+ return false;
+}
+
+/// RemoveText - Remove the specified text region.
+bool Rewriter::RemoveText(SourceLocation Start, unsigned Length) {
+ if (!isRewritable(Start)) return true;
+ FileID FID;
+ unsigned StartOffs = getLocationOffsetAndFileID(Start, FID);
+ getEditBuffer(FID).RemoveText(StartOffs, Length);
+ return false;
+}
+
+/// ReplaceText - This method replaces a range of characters in the input
+/// buffer with a new string. This is effectively a combined "remove/insert"
+/// operation.
+bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength,
+ const char *NewStr, unsigned NewLength) {
+ if (!isRewritable(Start)) return true;
+ FileID StartFileID;
+ unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);
+
+ getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength,
+ NewStr, NewLength);
+ return false;
+}
+
+/// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty
+/// printer to generate the replacement code. This returns true if the input
+/// could not be rewritten, or false if successful.
+bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) {
+ // Measaure the old text.
+ int Size = getRangeSize(From->getSourceRange());
+ if (Size == -1)
+ return true;
+
+ // Get the new text.
+ std::string SStr;
+ llvm::raw_string_ostream S(SStr);
+ To->printPretty(S);
+ const std::string &Str = S.str();
+
+ ReplaceText(From->getLocStart(), Size, &Str[0], Str.size());
+ return false;
+}
+
+
diff --git a/lib/Rewrite/TokenRewriter.cpp b/lib/Rewrite/TokenRewriter.cpp
new file mode 100644
index 000000000000..e17e80133b11
--- /dev/null
+++ b/lib/Rewrite/TokenRewriter.cpp
@@ -0,0 +1,98 @@
+//===--- TokenRewriter.cpp - Token-based code rewriting interface ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the TokenRewriter class, which is used for code
+// transformations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Rewrite/TokenRewriter.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/ScratchBuffer.h"
+#include "clang/Basic/SourceManager.h"
+using namespace clang;
+
+TokenRewriter::TokenRewriter(FileID FID, SourceManager &SM,
+ const LangOptions &LangOpts) {
+ ScratchBuf.reset(new ScratchBuffer(SM));
+
+ // Create a lexer to lex all the tokens of the main file in raw mode.
+ Lexer RawLex(FID, SM, LangOpts);
+
+ // Return all comments and whitespace as tokens.
+ RawLex.SetKeepWhitespaceMode(true);
+
+ // Lex the file, populating our datastructures.
+ Token RawTok;
+ RawLex.LexFromRawLexer(RawTok);
+ while (RawTok.isNot(tok::eof)) {
+#if 0
+ if (Tok.is(tok::identifier)) {
+ // Look up the identifier info for the token. This should use
+ // IdentifierTable directly instead of PP.
+ Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
+ }
+#endif
+
+ AddToken(RawTok, TokenList.end());
+ RawLex.LexFromRawLexer(RawTok);
+ }
+}
+
+TokenRewriter::~TokenRewriter() {
+}
+
+
+/// RemapIterator - Convert from token_iterator (a const iterator) to
+/// TokenRefTy (a non-const iterator).
+TokenRewriter::TokenRefTy TokenRewriter::RemapIterator(token_iterator I) {
+ if (I == token_end()) return TokenList.end();
+
+ // FIXME: This is horrible, we should use our own list or something to avoid
+ // this.
+ std::map<SourceLocation, TokenRefTy>::iterator MapIt =
+ TokenAtLoc.find(I->getLocation());
+ assert(MapIt != TokenAtLoc.end() && "iterator not in rewriter?");
+ return MapIt->second;
+}
+
+
+/// AddToken - Add the specified token into the Rewriter before the other
+/// position.
+TokenRewriter::TokenRefTy
+TokenRewriter::AddToken(const Token &T, TokenRefTy Where) {
+ Where = TokenList.insert(Where, T);
+
+ bool InsertSuccess = TokenAtLoc.insert(std::make_pair(T.getLocation(),
+ Where)).second;
+ assert(InsertSuccess && "Token location already in rewriter!");
+ InsertSuccess = InsertSuccess;
+ return Where;
+}
+
+
+TokenRewriter::token_iterator
+TokenRewriter::AddTokenBefore(token_iterator I, const char *Val) {
+ unsigned Len = strlen(Val);
+
+ // Plop the string into the scratch buffer, then create a token for this
+ // string.
+ Token Tok;
+ Tok.startToken();
+ const char *Spelling;
+ Tok.setLocation(ScratchBuf->getToken(Val, Len, Spelling));
+ Tok.setLength(Len);
+
+ // TODO: Form a whole lexer around this and relex the token! For now, just
+ // set kind to tok::unknown.
+ Tok.setKind(tok::unknown);
+
+ return AddToken(Tok, RemapIterator(I));
+}
+
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
new file mode 100644
index 000000000000..321dac18b6a2
--- /dev/null
+++ b/lib/Sema/CMakeLists.txt
@@ -0,0 +1,33 @@
+set(LLVM_NO_RTTI 1)
+
+add_clang_library(clangSema
+ IdentifierResolver.cpp
+ JumpDiagnostics.cpp
+ ParseAST.cpp
+ Sema.cpp
+ SemaAccess.cpp
+ SemaAttr.cpp
+ SemaChecking.cpp
+ SemaCXXScopeSpec.cpp
+ SemaDeclAttr.cpp
+ SemaDecl.cpp
+ SemaDeclCXX.cpp
+ SemaDeclObjC.cpp
+ SemaExpr.cpp
+ SemaExprCXX.cpp
+ SemaExprObjC.cpp
+ SemaInherit.cpp
+ SemaInit.cpp
+ SemaLookup.cpp
+ SemaNamedCast.cpp
+ SemaOverload.cpp
+ SemaStmt.cpp
+ SemaTemplate.cpp
+ SemaTemplateInstantiate.cpp
+ SemaTemplateInstantiateDecl.cpp
+ SemaTemplateInstantiateExpr.cpp
+ SemaTemplateInstantiateStmt.cpp
+ SemaType.cpp
+ )
+
+add_dependencies(clangSema ClangDiagnosticSema)
diff --git a/lib/Sema/CXXFieldCollector.h b/lib/Sema/CXXFieldCollector.h
new file mode 100644
index 000000000000..69d13515fa65
--- /dev/null
+++ b/lib/Sema/CXXFieldCollector.h
@@ -0,0 +1,76 @@
+//===- CXXFieldCollector.h - Utility class for C++ class semantic analysis ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides CXXFieldCollector that is used during parsing & semantic
+// analysis of C++ classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H
+#define LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H
+
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+ class FieldDecl;
+
+/// CXXFieldCollector - Used to keep track of CXXFieldDecls during parsing of
+/// C++ classes.
+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;
+
+ /// 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;
+
+ // Example:
+ //
+ // class C {
+ // int x,y;
+ // class NC {
+ // int q;
+ // // At this point, Fields contains [x,y,q] decls and FieldCount contains
+ // // [2,1].
+ // };
+ // int z;
+ // // At this point, Fields contains [x,y,z] decls and FieldCount contains
+ // // [3].
+ // };
+
+public:
+ /// StartClass - Called by Sema::ActOnStartCXXClassDef.
+ void StartClass() { FieldCount.push_back(0); }
+
+ /// Add - Called by Sema::ActOnCXXMemberDeclarator.
+ void Add(FieldDecl *D) {
+ Fields.push_back(D);
+ ++FieldCount.back();
+ }
+
+ /// getCurNumField - The number of fields added to the currently parsed class.
+ size_t getCurNumFields() const { return FieldCount.back(); }
+
+ /// getCurFields - Pointer to array of fields added to the currently parsed
+ /// class.
+ FieldDecl **getCurFields() { return &*(Fields.end() - getCurNumFields()); }
+
+ /// FinishClass - Called by Sema::ActOnFinishCXXClassDef.
+ void FinishClass() {
+ Fields.resize(Fields.size() - getCurNumFields());
+ FieldCount.pop_back();
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
new file mode 100644
index 000000000000..ceab859c90aa
--- /dev/null
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -0,0 +1,293 @@
+//===- IdentifierResolver.cpp - Lexical Scope Name lookup -------*- 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 IdentifierResolver class, which is used for lexical
+// scoped lookup, based on declaration names.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IdentifierResolver.h"
+#include "clang/Basic/LangOptions.h"
+#include <list>
+#include <vector>
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// IdDeclInfoMap class
+//===----------------------------------------------------------------------===//
+
+/// IdDeclInfoMap - Associates IdDeclInfos with declaration names.
+/// Allocates 'pools' (vectors of IdDeclInfos) to avoid allocating each
+/// individual IdDeclInfo to heap.
+class IdentifierResolver::IdDeclInfoMap {
+ static const unsigned int VECTOR_SIZE = 512;
+ // Holds vectors of IdDeclInfos that serve as 'pools'.
+ // New vectors are added when the current one is full.
+ std::list< std::vector<IdDeclInfo> > IDIVecs;
+ unsigned int CurIndex;
+
+public:
+ IdDeclInfoMap() : CurIndex(VECTOR_SIZE) {}
+
+ /// Returns the IdDeclInfo associated to the DeclarationName.
+ /// It creates a new IdDeclInfo if one was not created before for this id.
+ IdDeclInfo &operator[](DeclarationName Name);
+};
+
+
+//===----------------------------------------------------------------------===//
+// IdDeclInfo Implementation
+//===----------------------------------------------------------------------===//
+
+/// AddShadowed - Add a decl by putting it directly above the 'Shadow' decl.
+/// Later lookups will find the 'Shadow' decl first. The 'Shadow' decl must
+/// be already added to the scope chain and must be in the same context as
+/// the decl that we want to add.
+void IdentifierResolver::IdDeclInfo::AddShadowed(NamedDecl *D,
+ NamedDecl *Shadow) {
+ for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) {
+ if (Shadow == *(I-1)) {
+ Decls.insert(I-1, D);
+ return;
+ }
+ }
+
+ assert(0 && "Shadow wasn't in scope chain!");
+}
+
+/// RemoveDecl - Remove the decl from the scope chain.
+/// The decl must already be part of the decl chain.
+void IdentifierResolver::IdDeclInfo::RemoveDecl(NamedDecl *D) {
+ for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) {
+ if (D == *(I-1)) {
+ Decls.erase(I-1);
+ return;
+ }
+ }
+
+ assert(0 && "Didn't find this decl on its identifier's chain!");
+}
+
+bool
+IdentifierResolver::IdDeclInfo::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {
+ for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) {
+ if (Old == *(I-1)) {
+ *(I - 1) = New;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+//===----------------------------------------------------------------------===//
+// IdentifierResolver Implementation
+//===----------------------------------------------------------------------===//
+
+IdentifierResolver::IdentifierResolver(const LangOptions &langOpt)
+ : LangOpt(langOpt), IdDeclInfos(new IdDeclInfoMap) {
+}
+IdentifierResolver::~IdentifierResolver() {
+ delete IdDeclInfos;
+}
+
+/// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
+/// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
+/// true if 'D' belongs to the given declaration context.
+bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
+ ASTContext &Context, Scope *S) const {
+ Ctx = Ctx->getLookupContext();
+
+ if (Ctx->isFunctionOrMethod()) {
+ // Ignore the scopes associated within transparent declaration contexts.
+ while (S->getEntity() &&
+ ((DeclContext *)S->getEntity())->isTransparentContext())
+ S = S->getParent();
+
+ if (S->isDeclScope(Action::DeclPtrTy::make(D)))
+ return true;
+ if (LangOpt.CPlusPlus) {
+ // C++ 3.3.2p3:
+ // The name declared in a catch exception-declaration is local to the
+ // handler and shall not be redeclared in the outermost block of the
+ // handler.
+ // C++ 3.3.2p4:
+ // Names declared in the for-init-statement, and in the condition of if,
+ // while, for, and switch statements are local to the if, while, for, or
+ // switch statement (including the controlled statement), and shall not be
+ // redeclared in a subsequent condition of that statement nor in the
+ // outermost block (or, for the if statement, any of the outermost blocks)
+ // of the controlled statement.
+ //
+ assert(S->getParent() && "No TUScope?");
+ if (S->getParent()->getFlags() & Scope::ControlScope)
+ return S->getParent()->isDeclScope(Action::DeclPtrTy::make(D));
+ }
+ return false;
+ }
+
+ return D->getDeclContext()->getLookupContext() == Ctx->getPrimaryContext();
+}
+
+/// AddDecl - Link the decl to its shadowed decl chain.
+void IdentifierResolver::AddDecl(NamedDecl *D) {
+ DeclarationName Name = D->getDeclName();
+ void *Ptr = Name.getFETokenInfo<void>();
+
+ if (!Ptr) {
+ Name.setFETokenInfo(D);
+ return;
+ }
+
+ IdDeclInfo *IDI;
+
+ if (isDeclPtr(Ptr)) {
+ Name.setFETokenInfo(NULL);
+ IDI = &(*IdDeclInfos)[Name];
+ NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr);
+ IDI->AddDecl(PrevD);
+ } else
+ IDI = toIdDeclInfo(Ptr);
+
+ IDI->AddDecl(D);
+}
+
+/// AddShadowedDecl - Link the decl to its shadowed decl chain putting it
+/// after the decl that the iterator points to, thus the 'Shadow' decl will be
+/// encountered before the 'D' decl.
+void IdentifierResolver::AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow) {
+ assert(D->getDeclName() == Shadow->getDeclName() && "Different ids!");
+
+ DeclarationName Name = D->getDeclName();
+ void *Ptr = Name.getFETokenInfo<void>();
+ assert(Ptr && "No decl from Ptr ?");
+
+ IdDeclInfo *IDI;
+
+ if (isDeclPtr(Ptr)) {
+ Name.setFETokenInfo(NULL);
+ IDI = &(*IdDeclInfos)[Name];
+ NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr);
+ assert(PrevD == Shadow && "Invalid shadow decl ?");
+ IDI->AddDecl(D);
+ IDI->AddDecl(PrevD);
+ return;
+ }
+
+ IDI = toIdDeclInfo(Ptr);
+ IDI->AddShadowed(D, Shadow);
+}
+
+/// RemoveDecl - Unlink the decl from its shadowed decl chain.
+/// The decl must already be part of the decl chain.
+void IdentifierResolver::RemoveDecl(NamedDecl *D) {
+ assert(D && "null param passed");
+ DeclarationName Name = D->getDeclName();
+ void *Ptr = Name.getFETokenInfo<void>();
+
+ assert(Ptr && "Didn't find this decl on its identifier's chain!");
+
+ if (isDeclPtr(Ptr)) {
+ assert(D == Ptr && "Didn't find this decl on its identifier's chain!");
+ Name.setFETokenInfo(NULL);
+ return;
+ }
+
+ return toIdDeclInfo(Ptr)->RemoveDecl(D);
+}
+
+bool IdentifierResolver::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {
+ assert(Old->getDeclName() == New->getDeclName() &&
+ "Cannot replace a decl with another decl of a different name");
+
+ DeclarationName Name = Old->getDeclName();
+ void *Ptr = Name.getFETokenInfo<void>();
+
+ if (!Ptr)
+ return false;
+
+ if (isDeclPtr(Ptr)) {
+ if (Ptr == Old) {
+ Name.setFETokenInfo(New);
+ return true;
+ }
+ return false;
+ }
+
+ return toIdDeclInfo(Ptr)->ReplaceDecl(Old, New);
+}
+
+/// begin - Returns an iterator for decls with name 'Name'.
+IdentifierResolver::iterator
+IdentifierResolver::begin(DeclarationName Name) {
+ void *Ptr = Name.getFETokenInfo<void>();
+ if (!Ptr) return end();
+
+ if (isDeclPtr(Ptr))
+ return iterator(static_cast<NamedDecl*>(Ptr));
+
+ IdDeclInfo *IDI = toIdDeclInfo(Ptr);
+
+ IdDeclInfo::DeclsTy::iterator I = IDI->decls_end();
+ if (I != IDI->decls_begin())
+ return iterator(I-1);
+ // No decls found.
+ return end();
+}
+
+void IdentifierResolver::AddDeclToIdentifierChain(IdentifierInfo *II,
+ NamedDecl *D) {
+ void *Ptr = II->getFETokenInfo<void>();
+
+ if (!Ptr) {
+ II->setFETokenInfo(D);
+ return;
+ }
+
+ IdDeclInfo *IDI;
+
+ if (isDeclPtr(Ptr)) {
+ II->setFETokenInfo(NULL);
+ IDI = &(*IdDeclInfos)[II];
+ NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr);
+ IDI->AddDecl(PrevD);
+ } else
+ IDI = toIdDeclInfo(Ptr);
+
+ IDI->AddDecl(D);
+}
+
+//===----------------------------------------------------------------------===//
+// IdDeclInfoMap Implementation
+//===----------------------------------------------------------------------===//
+
+/// Returns the IdDeclInfo associated to the DeclarationName.
+/// It creates a new IdDeclInfo if one was not created before for this id.
+IdentifierResolver::IdDeclInfo &
+IdentifierResolver::IdDeclInfoMap::operator[](DeclarationName Name) {
+ void *Ptr = Name.getFETokenInfo<void>();
+
+ if (Ptr) return *toIdDeclInfo(Ptr);
+
+ if (CurIndex == VECTOR_SIZE) {
+ // Add a IdDeclInfo vector 'pool'
+ IDIVecs.push_back(std::vector<IdDeclInfo>());
+ // Fill the vector
+ IDIVecs.back().resize(VECTOR_SIZE);
+ CurIndex = 0;
+ }
+ IdDeclInfo *IDI = &IDIVecs.back()[CurIndex];
+ Name.setFETokenInfo(reinterpret_cast<void*>(
+ reinterpret_cast<uintptr_t>(IDI) | 0x1)
+ );
+ ++CurIndex;
+ return *IDI;
+}
diff --git a/lib/Sema/IdentifierResolver.h b/lib/Sema/IdentifierResolver.h
new file mode 100644
index 000000000000..0b0e6b388dde
--- /dev/null
+++ b/lib/Sema/IdentifierResolver.h
@@ -0,0 +1,214 @@
+//===- IdentifierResolver.h - Lexical Scope Name lookup ---------*- 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 IdentifierResolver class, which is used for lexical
+// scoped lookup, based on declaration names.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_SEMA_IDENTIFIERRESOLVER_H
+#define LLVM_CLANG_AST_SEMA_IDENTIFIERRESOLVER_H
+
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Parse/Scope.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/DeclCXX.h"
+
+namespace clang {
+
+/// IdentifierResolver - Keeps track of shadowed decls on enclosing
+/// scopes. It manages the shadowing chains of declaration names and
+/// implements efficent decl lookup based on a declaration name.
+class IdentifierResolver {
+
+ /// IdDeclInfo - Keeps track of information about decls associated
+ /// to a particular declaration name. IdDeclInfos are lazily
+ /// constructed and assigned to a declaration name the first time a
+ /// decl with that declaration name is shadowed in some scope.
+ class IdDeclInfo {
+ public:
+ typedef llvm::SmallVector<NamedDecl*, 2> DeclsTy;
+
+ inline DeclsTy::iterator decls_begin() { return Decls.begin(); }
+ inline DeclsTy::iterator decls_end() { return Decls.end(); }
+
+ void AddDecl(NamedDecl *D) { Decls.push_back(D); }
+
+ /// AddShadowed - Add a decl by putting it directly above the 'Shadow' decl.
+ /// Later lookups will find the 'Shadow' decl first. The 'Shadow' decl must
+ /// be already added to the scope chain and must be in the same context as
+ /// the decl that we want to add.
+ void AddShadowed(NamedDecl *D, NamedDecl *Shadow);
+
+ /// RemoveDecl - Remove the decl from the scope chain.
+ /// The decl must already be part of the decl chain.
+ void RemoveDecl(NamedDecl *D);
+
+ /// Replaces the Old declaration with the New declaration. If the
+ /// replacement is successful, returns true. If the old
+ /// declaration was not found, returns false.
+ bool ReplaceDecl(NamedDecl *Old, NamedDecl *New);
+
+ private:
+ DeclsTy Decls;
+ };
+
+public:
+
+ /// iterator - Iterate over the decls of a specified declaration name.
+ /// It will walk or not the parent declaration contexts depending on how
+ /// it was instantiated.
+ class iterator {
+ public:
+ typedef NamedDecl * value_type;
+ typedef NamedDecl * reference;
+ typedef NamedDecl * pointer;
+ typedef std::input_iterator_tag iterator_category;
+ typedef std::ptrdiff_t difference_type;
+
+ /// Ptr - There are 3 forms that 'Ptr' represents:
+ /// 1) A single NamedDecl. (Ptr & 0x1 == 0)
+ /// 2) A IdDeclInfo::DeclsTy::iterator that traverses only the decls of the
+ /// same declaration context. (Ptr & 0x3 == 0x1)
+ /// 3) A IdDeclInfo::DeclsTy::iterator that traverses the decls of parent
+ /// declaration contexts too. (Ptr & 0x3 == 0x3)
+ uintptr_t Ptr;
+ typedef IdDeclInfo::DeclsTy::iterator BaseIter;
+
+ /// A single NamedDecl. (Ptr & 0x1 == 0)
+ iterator(NamedDecl *D) {
+ Ptr = reinterpret_cast<uintptr_t>(D);
+ assert((Ptr & 0x1) == 0 && "Invalid Ptr!");
+ }
+ /// A IdDeclInfo::DeclsTy::iterator that walks or not the parent declaration
+ /// contexts depending on 'LookInParentCtx'.
+ iterator(BaseIter I) {
+ Ptr = reinterpret_cast<uintptr_t>(I) | 0x1;
+ }
+
+ bool isIterator() const { return (Ptr & 0x1); }
+
+ BaseIter getIterator() const {
+ assert(isIterator() && "Ptr not an iterator!");
+ return reinterpret_cast<BaseIter>(Ptr & ~0x3);
+ }
+
+ friend class IdentifierResolver;
+ public:
+ iterator() : Ptr(0) {}
+
+ NamedDecl *operator*() const {
+ if (isIterator())
+ return *getIterator();
+ else
+ return reinterpret_cast<NamedDecl*>(Ptr);
+ }
+
+ bool operator==(const iterator &RHS) const {
+ return Ptr == RHS.Ptr;
+ }
+ bool operator!=(const iterator &RHS) const {
+ return Ptr != RHS.Ptr;
+ }
+
+ // Preincrement.
+ iterator& operator++() {
+ if (!isIterator()) // common case.
+ Ptr = 0;
+ else {
+ NamedDecl *D = **this;
+ void *InfoPtr = D->getDeclName().getFETokenInfo<void>();
+ assert(!isDeclPtr(InfoPtr) && "Decl with wrong id ?");
+ IdDeclInfo *Info = toIdDeclInfo(InfoPtr);
+
+ BaseIter I = getIterator();
+ if (I != Info->decls_begin())
+ *this = iterator(I-1);
+ else // No more decls.
+ *this = iterator();
+ }
+ return *this;
+ }
+
+ uintptr_t getAsOpaqueValue() const { return Ptr; }
+
+ static iterator getFromOpaqueValue(uintptr_t P) {
+ iterator Result;
+ Result.Ptr = P;
+ return Result;
+ }
+ };
+
+ /// begin - Returns an iterator for decls with the name 'Name'.
+ static iterator begin(DeclarationName Name);
+
+ /// end - Returns an iterator that has 'finished'.
+ static iterator end() {
+ return iterator();
+ }
+
+ /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
+ /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
+ /// true if 'D' belongs to the given declaration context.
+ bool isDeclInScope(Decl *D, DeclContext *Ctx, ASTContext &Context,
+ Scope *S = 0) const;
+
+ /// AddDecl - Link the decl to its shadowed decl chain.
+ void AddDecl(NamedDecl *D);
+
+ /// AddShadowedDecl - Link the decl to its shadowed decl chain putting it
+ /// after the decl that the iterator points to, thus the 'Shadow' decl will be
+ /// encountered before the 'D' decl.
+ void AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow);
+
+ /// RemoveDecl - Unlink the decl from its shadowed decl chain.
+ /// The decl must already be part of the decl chain.
+ void RemoveDecl(NamedDecl *D);
+
+ /// Replace the decl Old with the new declaration New on its
+ /// identifier chain. Returns true if the old declaration was found
+ /// (and, therefore, replaced).
+ bool ReplaceDecl(NamedDecl *Old, NamedDecl *New);
+
+ /// \brief Link the declaration into the chain of declarations for
+ /// the given identifier.
+ ///
+ /// This is a lower-level routine used by the PCH reader to link a
+ /// declaration into a specific IdentifierInfo before the
+ /// declaration actually has a name.
+ void AddDeclToIdentifierChain(IdentifierInfo *II, NamedDecl *D);
+
+ explicit IdentifierResolver(const LangOptions &LangOpt);
+ ~IdentifierResolver();
+
+private:
+ const LangOptions &LangOpt;
+
+ class IdDeclInfoMap;
+ IdDeclInfoMap *IdDeclInfos;
+
+ /// FETokenInfo contains a Decl pointer if lower bit == 0.
+ static inline bool isDeclPtr(void *Ptr) {
+ return (reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 0;
+ }
+
+ /// FETokenInfo contains a IdDeclInfo pointer if lower bit == 1.
+ static inline IdDeclInfo *toIdDeclInfo(void *Ptr) {
+ assert((reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 1
+ && "Ptr not a IdDeclInfo* !");
+ return reinterpret_cast<IdDeclInfo*>(
+ reinterpret_cast<uintptr_t>(Ptr) & ~0x1
+ );
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
new file mode 100644
index 000000000000..ae863f2df1ee
--- /dev/null
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -0,0 +1,327 @@
+//===--- JumpDiagnostics.cpp - Analyze Jump Targets for VLA issues --------===//
+//
+// 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 JumpScopeChecker class, which is used to diagnose
+// jumps that enter a VLA scope in an invalid way.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtCXX.h"
+using namespace clang;
+
+namespace {
+
+/// JumpScopeChecker - This object is used by Sema to diagnose invalid jumps
+/// into VLA and other protected scopes. For example, this rejects:
+/// goto L;
+/// int a[n];
+/// L:
+///
+class JumpScopeChecker {
+ Sema &S;
+
+ /// GotoScope - This is a record that we use to keep track of all of the
+ /// scopes that are introduced by VLAs and other things that scope jumps like
+ /// gotos. This scope tree has nothing to do with the source scope tree,
+ /// because you can have multiple VLA scopes per compound statement, and most
+ /// compound statements don't introduce any scopes.
+ struct GotoScope {
+ /// ParentScope - The index in ScopeMap of the parent scope. This is 0 for
+ /// the parent scope is the function body.
+ unsigned ParentScope;
+
+ /// Diag - The diagnostic to emit if there is a jump into this scope.
+ unsigned Diag;
+
+ /// Loc - Location to emit the diagnostic.
+ SourceLocation Loc;
+
+ GotoScope(unsigned parentScope, unsigned diag, SourceLocation L)
+ : ParentScope(parentScope), Diag(diag), Loc(L) {}
+ };
+
+ llvm::SmallVector<GotoScope, 48> Scopes;
+ llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes;
+ llvm::SmallVector<Stmt*, 16> Jumps;
+public:
+ JumpScopeChecker(Stmt *Body, Sema &S);
+private:
+ void BuildScopeInformation(Stmt *S, unsigned ParentScope);
+ void VerifyJumps();
+ void CheckJump(Stmt *From, Stmt *To,
+ SourceLocation DiagLoc, unsigned JumpDiag);
+};
+} // end anonymous namespace
+
+
+JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) {
+ // Add a scope entry for function scope.
+ Scopes.push_back(GotoScope(~0U, ~0U, SourceLocation()));
+
+ // Build information for the top level compound statement, so that we have a
+ // defined scope record for every "goto" and label.
+ BuildScopeInformation(Body, 0);
+
+ // Check that all jumps we saw are kosher.
+ VerifyJumps();
+}
+
+/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a
+/// diagnostic that should be emitted if control goes over it. If not, return 0.
+static unsigned GetDiagForGotoScopeDecl(const Decl *D) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (VD->getType()->isVariablyModifiedType())
+ return diag::note_protected_by_vla;
+ if (VD->hasAttr<CleanupAttr>())
+ return diag::note_protected_by_cleanup;
+ } else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ if (TD->getUnderlyingType()->isVariablyModifiedType())
+ return diag::note_protected_by_vla_typedef;
+ }
+
+ return 0;
+}
+
+
+/// BuildScopeInformation - The statements from CI to CE are known to form a
+/// coherent VLA scope with a specified parent node. Walk through the
+/// statements, adding any labels or gotos to LabelAndGotoScopes and recursively
+/// walking the AST as needed.
+void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
+
+ // If we found a label, remember that it is in ParentScope scope.
+ if (isa<LabelStmt>(S) || isa<DefaultStmt>(S) || isa<CaseStmt>(S)) {
+ LabelAndGotoScopes[S] = ParentScope;
+ } else if (isa<GotoStmt>(S) || isa<SwitchStmt>(S) ||
+ isa<IndirectGotoStmt>(S) || isa<AddrLabelExpr>(S)) {
+ // Remember both what scope a goto is in as well as the fact that we have
+ // it. This makes the second scan not have to walk the AST again.
+ LabelAndGotoScopes[S] = ParentScope;
+ Jumps.push_back(S);
+ }
+
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E;
+ ++CI) {
+ Stmt *SubStmt = *CI;
+ if (SubStmt == 0) continue;
+
+ // FIXME: diagnose jumps past initialization: required in C++, warning in C.
+ // goto L; int X = 4; L: ;
+
+ // If this is a declstmt with a VLA definition, it defines a scope from here
+ // to the end of the containing context.
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(SubStmt)) {
+ // The decl statement creates a scope if any of the decls in it are VLAs or
+ // have the cleanup attribute.
+ for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
+ I != E; ++I) {
+ // If this decl causes a new scope, push and switch to it.
+ if (unsigned Diag = GetDiagForGotoScopeDecl(*I)) {
+ Scopes.push_back(GotoScope(ParentScope, Diag, (*I)->getLocation()));
+ ParentScope = Scopes.size()-1;
+ }
+
+ // If the decl has an initializer, walk it with the potentially new
+ // scope we just installed.
+ if (VarDecl *VD = dyn_cast<VarDecl>(*I))
+ if (Expr *Init = VD->getInit())
+ BuildScopeInformation(Init, ParentScope);
+ }
+ continue;
+ }
+
+ // Disallow jumps into any part of an @try statement by pushing a scope and
+ // walking all sub-stmts in that scope.
+ if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) {
+ // Recursively walk the AST for the @try part.
+ Scopes.push_back(GotoScope(ParentScope,diag::note_protected_by_objc_try,
+ AT->getAtTryLoc()));
+ if (Stmt *TryPart = AT->getTryBody())
+ BuildScopeInformation(TryPart, Scopes.size()-1);
+
+ // Jump from the catch to the finally or try is not valid.
+ for (ObjCAtCatchStmt *AC = AT->getCatchStmts(); AC;
+ AC = AC->getNextCatchStmt()) {
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_objc_catch,
+ AC->getAtCatchLoc()));
+ // @catches are nested and it isn't
+ BuildScopeInformation(AC->getCatchBody(), Scopes.size()-1);
+ }
+
+ // Jump from the finally to the try or catch is not valid.
+ if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) {
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_objc_finally,
+ AF->getAtFinallyLoc()));
+ BuildScopeInformation(AF, Scopes.size()-1);
+ }
+
+ continue;
+ }
+
+ // Disallow jumps into the protected statement of an @synchronized, but
+ // allow jumps into the object expression it protects.
+ if (ObjCAtSynchronizedStmt *AS = dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)){
+ // Recursively walk the AST for the @synchronized object expr, it is
+ // evaluated in the normal scope.
+ BuildScopeInformation(AS->getSynchExpr(), ParentScope);
+
+ // Recursively walk the AST for the @synchronized part, protected by a new
+ // scope.
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_objc_synchronized,
+ AS->getAtSynchronizedLoc()));
+ BuildScopeInformation(AS->getSynchBody(), Scopes.size()-1);
+ continue;
+ }
+
+ // Disallow jumps into any part of a C++ try statement. This is pretty
+ // much the same as for Obj-C.
+ if (CXXTryStmt *TS = dyn_cast<CXXTryStmt>(SubStmt)) {
+ Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_cxx_try,
+ TS->getSourceRange().getBegin()));
+ if (Stmt *TryBlock = TS->getTryBlock())
+ BuildScopeInformation(TryBlock, Scopes.size()-1);
+
+ // Jump from the catch into the try is not allowed either.
+ for(unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) {
+ CXXCatchStmt *CS = TS->getHandler(I);
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_cxx_catch,
+ CS->getSourceRange().getBegin()));
+ BuildScopeInformation(CS->getHandlerBlock(), Scopes.size()-1);
+ }
+
+ continue;
+ }
+
+ // Recursively walk the AST.
+ BuildScopeInformation(SubStmt, ParentScope);
+ }
+}
+
+/// VerifyJumps - Verify each element of the Jumps array to see if they are
+/// valid, emitting diagnostics if not.
+void JumpScopeChecker::VerifyJumps() {
+ while (!Jumps.empty()) {
+ Stmt *Jump = Jumps.pop_back_val();
+
+ // With a goto,
+ if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) {
+ CheckJump(GS, GS->getLabel(), GS->getGotoLoc(),
+ diag::err_goto_into_protected_scope);
+ continue;
+ }
+
+ if (SwitchStmt *SS = dyn_cast<SwitchStmt>(Jump)) {
+ for (SwitchCase *SC = SS->getSwitchCaseList(); SC;
+ SC = SC->getNextSwitchCase()) {
+ assert(LabelAndGotoScopes.count(SC) && "Case not visited?");
+ CheckJump(SS, SC, SC->getLocStart(),
+ diag::err_switch_into_protected_scope);
+ }
+ continue;
+ }
+
+ unsigned DiagnosticScope;
+
+ // We don't know where an indirect goto goes, require that it be at the
+ // top level of scoping.
+ if (IndirectGotoStmt *IG = dyn_cast<IndirectGotoStmt>(Jump)) {
+ assert(LabelAndGotoScopes.count(Jump) &&
+ "Jump didn't get added to scopes?");
+ unsigned GotoScope = LabelAndGotoScopes[IG];
+ if (GotoScope == 0) continue; // indirect jump is ok.
+ S.Diag(IG->getGotoLoc(), diag::err_indirect_goto_in_protected_scope);
+ DiagnosticScope = GotoScope;
+ } else {
+ // We model &&Label as a jump for purposes of scope tracking. We actually
+ // don't care *where* the address of label is, but we require the *label
+ // itself* to be in scope 0. If it is nested inside of a VLA scope, then
+ // it is possible for an indirect goto to illegally enter the VLA scope by
+ // indirectly jumping to the label.
+ assert(isa<AddrLabelExpr>(Jump) && "Unknown jump type");
+ LabelStmt *TheLabel = cast<AddrLabelExpr>(Jump)->getLabel();
+
+ assert(LabelAndGotoScopes.count(TheLabel) &&
+ "Referenced label didn't get added to scopes?");
+ unsigned LabelScope = LabelAndGotoScopes[TheLabel];
+ if (LabelScope == 0) continue; // Addr of label is ok.
+
+ S.Diag(Jump->getLocStart(), diag::err_addr_of_label_in_protected_scope);
+ DiagnosticScope = LabelScope;
+ }
+
+ // Report all the things that would be skipped over by this &&label or
+ // indirect goto.
+ while (DiagnosticScope != 0) {
+ S.Diag(Scopes[DiagnosticScope].Loc, Scopes[DiagnosticScope].Diag);
+ DiagnosticScope = Scopes[DiagnosticScope].ParentScope;
+ }
+ }
+}
+
+/// 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) {
+ assert(LabelAndGotoScopes.count(From) && "Jump didn't get added to scopes?");
+ unsigned FromScope = LabelAndGotoScopes[From];
+
+ assert(LabelAndGotoScopes.count(To) && "Jump didn't get added to scopes?");
+ unsigned ToScope = LabelAndGotoScopes[To];
+
+ // Common case: exactly the same scope, which is fine.
+ if (FromScope == ToScope) return;
+
+ // The only valid mismatch jump case happens when the jump is more deeply
+ // nested inside the jump target. Do a quick scan to see if the jump is valid
+ // because valid code is more common than invalid code.
+ unsigned TestScope = Scopes[FromScope].ParentScope;
+ while (TestScope != ~0U) {
+ // If we found the jump target, then we're jumping out of our current scope,
+ // which is perfectly fine.
+ if (TestScope == ToScope) return;
+
+ // Otherwise, scan up the hierarchy.
+ TestScope = Scopes[TestScope].ParentScope;
+ }
+
+ // If we get here, then we know we have invalid code. Diagnose the bad jump,
+ // and then emit a note at each VLA being jumped out of.
+ S.Diag(DiagLoc, JumpDiag);
+
+ // Eliminate the common prefix of the jump and the target. Start by
+ // linearizing both scopes, reversing them as we go.
+ std::vector<unsigned> FromScopes, ToScopes;
+ for (TestScope = FromScope; TestScope != ~0U;
+ TestScope = Scopes[TestScope].ParentScope)
+ FromScopes.push_back(TestScope);
+ for (TestScope = ToScope; TestScope != ~0U;
+ TestScope = Scopes[TestScope].ParentScope)
+ ToScopes.push_back(TestScope);
+
+ // Remove any common entries (such as the top-level function scope).
+ while (!FromScopes.empty() && FromScopes.back() == ToScopes.back()) {
+ FromScopes.pop_back();
+ ToScopes.pop_back();
+ }
+
+ // 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]].Diag);
+}
+
+void Sema::DiagnoseInvalidJumps(Stmt *Body) {
+ JumpScopeChecker(Body, *this);
+}
diff --git a/lib/Sema/Makefile b/lib/Sema/Makefile
new file mode 100644
index 000000000000..0f4c7965dca2
--- /dev/null
+++ b/lib/Sema/Makefile
@@ -0,0 +1,23 @@
+##===- clang/lib/Sema/Makefile -----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements the semantic analyzer and AST builder library for the
+# C-Language front-end.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+LIBRARYNAME := clangSema
+BUILD_ARCHIVE = 1
+CXXFLAGS = -fno-rtti
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp
new file mode 100644
index 000000000000..e2ee88ac86bc
--- /dev/null
+++ b/lib/Sema/ParseAST.cpp
@@ -0,0 +1,85 @@
+//===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===//
+//
+// 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 clang::ParseAST method.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/ParseAST.h"
+#include "Sema.h"
+#include "clang/Sema/SemaConsumer.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Parse/Parser.h"
+#include "llvm/ADT/OwningPtr.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Public interface to the file
+//===----------------------------------------------------------------------===//
+
+/// ParseAST - Parse the entire file specified, notifying the ASTConsumer as
+/// the file is parsed. This inserts the parsed decls into the translation unit
+/// held by Ctx.
+///
+void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
+ ASTContext &Ctx, bool PrintStats,
+ bool CompleteTranslationUnit) {
+ // Collect global stats on Decls/Stmts (until we have a module streamer).
+ if (PrintStats) {
+ Decl::CollectingStats(true);
+ Stmt::CollectingStats(true);
+ }
+
+ Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit);
+ Parser P(PP, S);
+ PP.EnterMainSourceFile();
+
+ // Initialize the parser.
+ P.Initialize();
+
+ Consumer->Initialize(Ctx);
+
+ if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumer))
+ SC->InitializeSema(S);
+
+ if (ExternalASTSource *External = Ctx.getExternalSource()) {
+ if (ExternalSemaSource *ExternalSema =
+ dyn_cast<ExternalSemaSource>(External))
+ ExternalSema->InitializeSema(S);
+
+ External->StartTranslationUnit(Consumer);
+ }
+
+ Parser::DeclGroupPtrTy ADecl;
+
+ while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file.
+ // If we got a null return and something *was* parsed, ignore it. This
+ // is due to a top-level semicolon, an action override, or a parse error
+ // skipping something.
+ if (ADecl)
+ Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>());
+ };
+
+ Consumer->HandleTranslationUnit(Ctx);
+
+ if (PrintStats) {
+ fprintf(stderr, "\nSTATISTICS:\n");
+ P.getActions().PrintStats();
+ Ctx.PrintStats();
+ Decl::PrintStats();
+ Stmt::PrintStats();
+ Consumer->PrintStats();
+
+ Decl::CollectingStats(false);
+ Stmt::CollectingStats(false);
+ }
+}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
new file mode 100644
index 000000000000..1212d070f699
--- /dev/null
+++ b/lib/Sema/Sema.cpp
@@ -0,0 +1,333 @@
+//===--- Sema.cpp - AST Builder and Semantic Analysis Implementation ------===//
+//
+// 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 actions class which performs semantic analysis and
+// builds an AST out of a parse stream.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/TargetInfo.h"
+using namespace clang;
+
+/// ConvertQualTypeToStringFn - This function is used to pretty print the
+/// specified QualType as a string in diagnostics.
+static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
+ const char *Modifier, unsigned ModLen,
+ const char *Argument, unsigned ArgLen,
+ llvm::SmallVectorImpl<char> &Output,
+ void *Cookie) {
+ ASTContext &Context = *static_cast<ASTContext*>(Cookie);
+
+ std::string S;
+ if (Kind == Diagnostic::ak_qualtype) {
+ assert(ModLen == 0 && ArgLen == 0 &&
+ "Invalid modifier for QualType argument");
+
+ QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
+
+ // FIXME: Playing with std::string is really slow.
+ S = Ty.getAsString(Context.PrintingPolicy);
+
+ // If this is a sugared type (like a typedef, typeof, etc), then unwrap one
+ // level of the sugar so that the type is more obvious to the user.
+ QualType DesugaredTy = Ty->getDesugaredType(true);
+ DesugaredTy.setCVRQualifiers(DesugaredTy.getCVRQualifiers() |
+ Ty.getCVRQualifiers());
+
+ if (Ty != DesugaredTy &&
+ // If the desugared type is a vector type, we don't want to expand it,
+ // it will turn into an attribute mess. People want their "vec4".
+ !isa<VectorType>(DesugaredTy) &&
+
+ // Don't desugar magic Objective-C types.
+ Ty.getUnqualifiedType() != Context.getObjCIdType() &&
+ Ty.getUnqualifiedType() != Context.getObjCSelType() &&
+ Ty.getUnqualifiedType() != Context.getObjCProtoType() &&
+ Ty.getUnqualifiedType() != Context.getObjCClassType() &&
+
+ // Not va_list.
+ Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) {
+ S = "'"+S+"' (aka '";
+ S += DesugaredTy.getAsString();
+ S += "')";
+ Output.append(S.begin(), S.end());
+ return;
+ }
+
+ } else if (Kind == Diagnostic::ak_declarationname) {
+
+ DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
+ S = N.getAsString();
+
+ if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
+ S = '+' + S;
+ else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) && ArgLen==0)
+ S = '-' + S;
+ else
+ assert(ModLen == 0 && ArgLen == 0 &&
+ "Invalid modifier for DeclarationName argument");
+ } else {
+ assert(Kind == Diagnostic::ak_nameddecl);
+ if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
+ S = reinterpret_cast<NamedDecl*>(Val)->getQualifiedNameAsString();
+ else {
+ assert(ModLen == 0 && ArgLen == 0 &&
+ "Invalid modifier for NamedDecl* argument");
+ S = reinterpret_cast<NamedDecl*>(Val)->getNameAsString();
+ }
+ }
+
+ Output.push_back('\'');
+ Output.append(S.begin(), S.end());
+ Output.push_back('\'');
+}
+
+
+static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
+ if (C.getLangOptions().CPlusPlus)
+ return CXXRecordDecl::Create(C, TagDecl::TK_struct,
+ C.getTranslationUnitDecl(),
+ SourceLocation(), &C.Idents.get(Name));
+
+ return RecordDecl::Create(C, TagDecl::TK_struct,
+ C.getTranslationUnitDecl(),
+ SourceLocation(), &C.Idents.get(Name));
+}
+
+void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
+ TUScope = S;
+ PushDeclContext(S, Context.getTranslationUnitDecl());
+
+ if (PP.getTargetInfo().getPointerWidth(0) >= 64) {
+ // Install [u]int128_t for 64-bit targets.
+ PushOnScopeChains(TypedefDecl::Create(Context, CurContext,
+ SourceLocation(),
+ &Context.Idents.get("__int128_t"),
+ Context.Int128Ty), TUScope);
+ PushOnScopeChains(TypedefDecl::Create(Context, CurContext,
+ SourceLocation(),
+ &Context.Idents.get("__uint128_t"),
+ Context.UnsignedInt128Ty), TUScope);
+ }
+
+
+ if (!PP.getLangOptions().ObjC1) return;
+
+ if (Context.getObjCSelType().isNull()) {
+ // Synthesize "typedef struct objc_selector *SEL;"
+ RecordDecl *SelTag = CreateStructDecl(Context, "objc_selector");
+ PushOnScopeChains(SelTag, TUScope);
+
+ QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag));
+ TypedefDecl *SelTypedef = TypedefDecl::Create(Context, CurContext,
+ SourceLocation(),
+ &Context.Idents.get("SEL"),
+ SelT);
+ PushOnScopeChains(SelTypedef, TUScope);
+ Context.setObjCSelType(Context.getTypeDeclType(SelTypedef));
+ }
+
+ if (Context.getObjCClassType().isNull()) {
+ RecordDecl *ClassTag = CreateStructDecl(Context, "objc_class");
+ QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag));
+ TypedefDecl *ClassTypedef =
+ TypedefDecl::Create(Context, CurContext, SourceLocation(),
+ &Context.Idents.get("Class"), ClassT);
+ PushOnScopeChains(ClassTag, TUScope);
+ PushOnScopeChains(ClassTypedef, TUScope);
+ Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef));
+ }
+
+ // 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);
+ }
+
+ // Synthesize "typedef struct objc_object { Class isa; } *id;"
+ if (Context.getObjCIdType().isNull()) {
+ RecordDecl *ObjectTag = CreateStructDecl(Context, "objc_object");
+
+ QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag));
+ PushOnScopeChains(ObjectTag, TUScope);
+ TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext,
+ SourceLocation(),
+ &Context.Idents.get("id"),
+ ObjT);
+ PushOnScopeChains(IdTypedef, TUScope);
+ Context.setObjCIdType(Context.getTypeDeclType(IdTypedef));
+ }
+}
+
+Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
+ bool CompleteTranslationUnit)
+ : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
+ Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
+ ExternalSource(0), CurContext(0), PreDeclaratorDC(0),
+ CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()),
+ GlobalNewDeleteDeclared(false),
+ CompleteTranslationUnit(CompleteTranslationUnit),
+ CurrentInstantiationScope(0) {
+
+ StdNamespace = 0;
+ TUScope = 0;
+ if (getLangOptions().CPlusPlus)
+ FieldCollector.reset(new CXXFieldCollector());
+
+ // Tell diagnostics how to render things from the AST library.
+ PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context);
+}
+
+/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
+/// If there is already an implicit cast, merge into the existing one.
+/// If isLvalue, the result of the cast is an lvalue.
+void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, bool isLvalue) {
+ QualType ExprTy = Context.getCanonicalType(Expr->getType());
+ QualType TypeTy = Context.getCanonicalType(Ty);
+
+ if (ExprTy == TypeTy)
+ return;
+
+ if (Expr->getType().getTypePtr()->isPointerType() &&
+ Ty.getTypePtr()->isPointerType()) {
+ QualType ExprBaseType =
+ cast<PointerType>(ExprTy.getUnqualifiedType())->getPointeeType();
+ QualType BaseType =
+ cast<PointerType>(TypeTy.getUnqualifiedType())->getPointeeType();
+ if (ExprBaseType.getAddressSpace() != BaseType.getAddressSpace()) {
+ Diag(Expr->getExprLoc(), diag::err_implicit_pointer_address_space_cast)
+ << Expr->getSourceRange();
+ }
+ }
+
+ if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
+ ImpCast->setType(Ty);
+ ImpCast->setLvalueCast(isLvalue);
+ } else
+ Expr = new (Context) ImplicitCastExpr(Ty, Expr, isLvalue);
+}
+
+void Sema::DeleteExpr(ExprTy *E) {
+ if (E) static_cast<Expr*>(E)->Destroy(Context);
+}
+void Sema::DeleteStmt(StmtTy *S) {
+ if (S) static_cast<Stmt*>(S)->Destroy(Context);
+}
+
+/// 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() {
+ if (!CompleteTranslationUnit)
+ 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
+ // specifier or with the storage-class specifier static,
+ // constitutes a tentative definition. If a translation unit
+ // contains one or more tentative definitions for an identifier,
+ // and the translation unit contains no external definition for
+ // that identifier, then the behavior is exactly as if the
+ // translation unit contains a file scope declaration of that
+ // identifier, with the composite type as of the end of the
+ // translation unit, with an initializer equal to 0.
+ for (llvm::DenseMap<DeclarationName, VarDecl *>::iterator
+ D = TentativeDefinitions.begin(),
+ DEnd = TentativeDefinitions.end();
+ D != DEnd; ++D) {
+ VarDecl *VD = D->second;
+
+ if (VD->isInvalidDecl() || !VD->isTentativeDefinition(Context))
+ continue;
+
+ if (const IncompleteArrayType *ArrayT
+ = Context.getAsIncompleteArrayType(VD->getType())) {
+ if (RequireCompleteType(VD->getLocation(),
+ ArrayT->getElementType(),
+ diag::err_tentative_def_incomplete_type_arr))
+ VD->setInvalidDecl();
+ else {
+ // Set the length of the array to 1 (C99 6.9.2p5).
+ Diag(VD->getLocation(), diag::warn_tentative_incomplete_array);
+ llvm::APInt One(Context.getTypeSize(Context.getSizeType()),
+ true);
+ QualType T
+ = Context.getConstantArrayType(ArrayT->getElementType(),
+ One, ArrayType::Normal, 0);
+ VD->setType(T);
+ }
+ } else if (RequireCompleteType(VD->getLocation(), VD->getType(),
+ diag::err_tentative_def_incomplete_type))
+ VD->setInvalidDecl();
+
+ // Notify the consumer that we've completed a tentative definition.
+ if (!VD->isInvalidDecl())
+ Consumer.CompleteTentativeDefinition(VD);
+
+ }
+}
+
+
+//===----------------------------------------------------------------------===//
+// Helper functions.
+//===----------------------------------------------------------------------===//
+
+/// getCurFunctionDecl - If inside of a function body, this returns a pointer
+/// to the function decl for the function being parsed. If we're currently
+/// in a 'block', this returns the containing context.
+FunctionDecl *Sema::getCurFunctionDecl() {
+ DeclContext *DC = CurContext;
+ while (isa<BlockDecl>(DC))
+ DC = DC->getParent();
+ return dyn_cast<FunctionDecl>(DC);
+}
+
+ObjCMethodDecl *Sema::getCurMethodDecl() {
+ DeclContext *DC = CurContext;
+ while (isa<BlockDecl>(DC))
+ DC = DC->getParent();
+ return dyn_cast<ObjCMethodDecl>(DC);
+}
+
+NamedDecl *Sema::getCurFunctionOrMethodDecl() {
+ DeclContext *DC = CurContext;
+ while (isa<BlockDecl>(DC))
+ DC = DC->getParent();
+ if (isa<ObjCMethodDecl>(DC) || isa<FunctionDecl>(DC))
+ return cast<NamedDecl>(DC);
+ return 0;
+}
+
+Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
+ this->Emit();
+
+ // If this is not a note, and we're in a template instantiation
+ // that is different from the last template instantiation where
+ // we emitted an error, print a template instantiation
+ // backtrace.
+ if (!SemaRef.Diags.isBuiltinNote(DiagID) &&
+ !SemaRef.ActiveTemplateInstantiations.empty() &&
+ SemaRef.ActiveTemplateInstantiations.back()
+ != SemaRef.LastTemplateInstantiationErrorContext) {
+ SemaRef.PrintInstantiationStack();
+ SemaRef.LastTemplateInstantiationErrorContext
+ = SemaRef.ActiveTemplateInstantiations.back();
+ }
+}
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
new file mode 100644
index 000000000000..c428d29367de
--- /dev/null
+++ b/lib/Sema/Sema.h
@@ -0,0 +1,2814 @@
+//===--- Sema.h - Semantic Analysis & AST Building --------------*- 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 Sema class, which performs semantic analysis and
+// builds ASTs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_SEMA_H
+#define LLVM_CLANG_AST_SEMA_H
+
+#include "IdentifierResolver.h"
+#include "CXXFieldCollector.h"
+#include "SemaOverload.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Parse/Action.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/OwningPtr.h"
+#include <string>
+#include <vector>
+
+namespace llvm {
+ class APSInt;
+}
+
+namespace clang {
+ class ASTContext;
+ class ASTConsumer;
+ class Preprocessor;
+ class Decl;
+ class DeclContext;
+ class DeclSpec;
+ class ExternalSemaSource;
+ class NamedDecl;
+ class Stmt;
+ class Expr;
+ class InitListExpr;
+ class DesignatedInitExpr;
+ class CallExpr;
+ class DeclRefExpr;
+ class VarDecl;
+ class ParmVarDecl;
+ class TypedefDecl;
+ class FunctionDecl;
+ class QualType;
+ class LangOptions;
+ class Token;
+ class IntegerLiteral;
+ class StringLiteral;
+ class ArrayType;
+ class LabelStmt;
+ class SwitchStmt;
+ class CXXTryStmt;
+ class ExtVectorType;
+ class TypedefDecl;
+ class TemplateDecl;
+ class TemplateArgument;
+ class TemplateArgumentList;
+ class TemplateParameterList;
+ class TemplateTemplateParmDecl;
+ class ClassTemplatePartialSpecializationDecl;
+ class ClassTemplateDecl;
+ class ObjCInterfaceDecl;
+ class ObjCCompatibleAliasDecl;
+ class ObjCProtocolDecl;
+ class ObjCImplDecl;
+ class ObjCImplementationDecl;
+ class ObjCCategoryImplDecl;
+ class ObjCCategoryDecl;
+ class ObjCIvarDecl;
+ class ObjCMethodDecl;
+ class ObjCPropertyDecl;
+ class ObjCContainerDecl;
+ class BasePaths;
+ struct MemberLookupCriteria;
+ class CXXTemporary;
+
+/// BlockSemaInfo - When a block is being parsed, this contains information
+/// about the block. It is pointed to from Sema::CurBlock.
+struct BlockSemaInfo {
+ llvm::SmallVector<ParmVarDecl*, 8> Params;
+ bool hasPrototype;
+ bool isVariadic;
+ bool hasBlockDeclRefExprs;
+
+ BlockDecl *TheDecl;
+
+ /// TheScope - This is the scope for the block itself, which contains
+ /// arguments etc.
+ Scope *TheScope;
+
+ /// ReturnType - This will get set to block result type, by looking at
+ /// return types, if any, in the block body.
+ Type *ReturnType;
+
+ /// LabelMap - This is a mapping from label identifiers to the LabelStmt for
+ /// it (which acts like the label decl in some ways). Forward referenced
+ /// labels have a LabelStmt created for them with a null location & SubStmt.
+ llvm::DenseMap<IdentifierInfo*, LabelStmt*> LabelMap;
+
+ /// SwitchStack - This is the current set of active switch statements in the
+ /// block.
+ llvm::SmallVector<SwitchStmt*, 8> SwitchStack;
+
+ /// SavedFunctionNeedsScopeChecking - This is the value of
+ /// CurFunctionNeedsScopeChecking at the point when the block started.
+ bool SavedFunctionNeedsScopeChecking;
+
+ /// PrevBlockInfo - If this is nested inside another block, this points
+ /// to the outer block.
+ BlockSemaInfo *PrevBlockInfo;
+};
+
+/// Sema - This implements semantic analysis and AST building for C.
+class Sema : public Action {
+ Sema(const Sema&); // DO NOT IMPLEMENT
+ void operator=(const Sema&); // DO NOT IMPLEMENT
+public:
+ const LangOptions &LangOpts;
+ Preprocessor &PP;
+ ASTContext &Context;
+ ASTConsumer &Consumer;
+ Diagnostic &Diags;
+ SourceManager &SourceMgr;
+
+ /// \brief Source of additional semantic information.
+ ExternalSemaSource *ExternalSource;
+
+ /// CurContext - This is the current declaration context of parsing.
+ DeclContext *CurContext;
+
+ /// PreDeclaratorDC - Keeps the declaration context before switching to the
+ /// context of a declarator's nested-name-specifier.
+ DeclContext *PreDeclaratorDC;
+
+ /// CurBlock - If inside of a block definition, this contains a pointer to
+ /// the active block object that represents it.
+ BlockSemaInfo *CurBlock;
+
+ /// PackContext - Manages the stack for #pragma pack. An alignment
+ /// of 0 indicates default alignment.
+ void *PackContext; // Really a "PragmaPackStack*"
+
+ /// FunctionLabelMap - This is a mapping from label identifiers to the
+ /// LabelStmt for it (which acts like the label decl in some ways). Forward
+ /// referenced labels have a LabelStmt created for them with a null location &
+ /// SubStmt.
+ ///
+ /// Note that this should always be accessed through getLabelMap() in order
+ /// to handle blocks properly.
+ llvm::DenseMap<IdentifierInfo*, LabelStmt*> FunctionLabelMap;
+
+ /// FunctionSwitchStack - This is the current set of active switch statements
+ /// in the top level function. Clients should always use getSwitchStack() to
+ /// handle the case when they are in a block.
+ llvm::SmallVector<SwitchStmt*, 8> FunctionSwitchStack;
+
+ /// ExprTemporaries - This is the stack of temporaries that are created by
+ /// the current full expression.
+ llvm::SmallVector<CXXTemporary*, 8> ExprTemporaries;
+
+ /// CurFunctionNeedsScopeChecking - This is set to true when a function or
+ /// ObjC method body contains a VLA or an ObjC try block, which introduce
+ /// scopes that need to be checked for goto conditions. If a function does
+ /// not contain this, then it need not have the jump checker run on it.
+ bool CurFunctionNeedsScopeChecking;
+
+ /// 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<TypedefDecl*, 24> ExtVectorDecls;
+
+ /// ObjCCategoryImpls - Maintain a list of category implementations so
+ /// we can check for duplicates and find local method declarations.
+ llvm::SmallVector<ObjCCategoryImplDecl*, 8> ObjCCategoryImpls;
+
+ /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes.
+ llvm::OwningPtr<CXXFieldCollector> FieldCollector;
+
+ typedef llvm::SmallPtrSet<const CXXRecordDecl*, 8> RecordDeclSetTy;
+
+ /// PureVirtualClassDiagSet - a set of class declarations which we have
+ /// emitted a list of pure virtual functions. Used to prevent emitting the
+ /// same list more than once.
+ llvm::OwningPtr<RecordDeclSetTy> PureVirtualClassDiagSet;
+
+ /// \brief A mapping from external names to the most recent
+ /// locally-scoped external declaration with that name.
+ ///
+ /// This map contains external declarations introduced in local
+ /// scoped, e.g.,
+ ///
+ /// \code
+ /// void f() {
+ /// void foo(int, int);
+ /// }
+ /// \endcode
+ ///
+ /// Here, the name "foo" will be associated with the declaration on
+ /// "foo" within f. This name is not visible outside of
+ /// "f". However, we still find it in two cases:
+ ///
+ /// - If we are declaring another external with the name "foo", we
+ /// can find "foo" as a previous declaration, so that the types
+ /// of this external declaration can be checked for
+ /// compatibility.
+ ///
+ /// - If we would implicitly declare "foo" (e.g., due to a call to
+ /// "foo" in C when no prototype or definition is visible), then
+ /// we find this declaration of "foo" and complain that it is
+ /// not visible.
+ llvm::DenseMap<DeclarationName, NamedDecl *> LocallyScopedExternalDecls;
+
+ /// \brief The set of tentative declarations seen so far in this
+ /// translation unit for which no definition has been seen.
+ ///
+ /// The tentative declarations are indexed by the name of the
+ /// declaration, and only the most recent tentative declaration for
+ /// a given variable will be recorded here.
+ llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions;
+
+ IdentifierResolver IdResolver;
+
+ /// Translation Unit Scope - useful to Objective-C actions that need
+ /// to lookup file scope declarations in the "ordinary" C decl namespace.
+ /// For example, user-defined classes, built-in "id" type, etc.
+ Scope *TUScope;
+
+ /// The C++ "std" namespace, where the standard library resides. Cached here
+ /// by GetStdNamespace
+ NamespaceDecl *StdNamespace;
+
+ /// A flag to remember whether the implicit forms of operator new and delete
+ /// have been declared.
+ bool GlobalNewDeleteDeclared;
+
+ /// \brief Whether the code handled by Sema should be considered a
+ /// complete translation unit or not.
+ ///
+ /// When true (which is generally the case), 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;
+
+ typedef llvm::DenseMap<Selector, ObjCMethodList> MethodPool;
+
+ /// Instance/Factory Method Pools - allows efficient lookup when typechecking
+ /// messages to "id". We need to maintain a list, since selectors can have
+ /// differing signatures across classes. In Cocoa, this happens to be
+ /// extremely uncommon (only 1% of selectors are "overloaded").
+ MethodPool InstanceMethodPool;
+ MethodPool FactoryMethodPool;
+
+ MethodPool::iterator ReadMethodPool(Selector Sel, bool isInstance);
+
+ /// Private Helper predicate to check for 'self'.
+ bool isSelfExpr(Expr *RExpr);
+public:
+ Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
+ bool CompleteTranslationUnit = true);
+ ~Sema() {
+ if (PackContext) FreePackedContext();
+ }
+
+ const LangOptions &getLangOptions() const { return LangOpts; }
+ Diagnostic &getDiagnostics() const { return Diags; }
+ SourceManager &getSourceManager() const { return SourceMgr; }
+
+ /// \brief Helper class that creates diagnostics with optional
+ /// template instantiation stacks.
+ ///
+ /// This class provides a wrapper around the basic DiagnosticBuilder
+ /// class that emits diagnostics. SemaDiagnosticBuilder is
+ /// responsible for emitting the diagnostic (as DiagnosticBuilder
+ /// does) and, if the diagnostic comes from inside a template
+ /// instantiation, printing the template instantiation stack as
+ /// well.
+ class SemaDiagnosticBuilder : public DiagnosticBuilder {
+ Sema &SemaRef;
+ unsigned DiagID;
+
+ public:
+ SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID)
+ : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { }
+
+ ~SemaDiagnosticBuilder();
+ };
+
+ /// \brief Emit a diagnostic.
+ SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
+ DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID);
+ return SemaDiagnosticBuilder(DB, *this, DiagID);
+ }
+
+ virtual void DeleteExpr(ExprTy *E);
+ virtual void DeleteStmt(StmtTy *S);
+
+ OwningExprResult Owned(Expr* E) { return OwningExprResult(*this, E); }
+ OwningExprResult Owned(ExprResult R) {
+ if (R.isInvalid())
+ return ExprError();
+ return OwningExprResult(*this, R.get());
+ }
+ OwningStmtResult Owned(Stmt* S) { return OwningStmtResult(*this, S); }
+
+ virtual void ActOnEndOfTranslationUnit();
+
+ /// getLabelMap() - Return the current label map. If we're in a block, we
+ /// return it.
+ llvm::DenseMap<IdentifierInfo*, LabelStmt*> &getLabelMap() {
+ return CurBlock ? CurBlock->LabelMap : FunctionLabelMap;
+ }
+
+ /// getSwitchStack - This is returns the switch stack for the current block or
+ /// function.
+ llvm::SmallVector<SwitchStmt*,8> &getSwitchStack() {
+ return CurBlock ? CurBlock->SwitchStack : FunctionSwitchStack;
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Type Analysis / Processing: SemaType.cpp.
+ //
+ QualType adjustParameterType(QualType T);
+ QualType ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc,
+ bool &IsInvalid);
+ void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
+ QualType BuildPointerType(QualType T, unsigned Quals,
+ SourceLocation Loc, DeclarationName Entity);
+ QualType BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
+ SourceLocation Loc, DeclarationName Entity);
+ QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
+ Expr *ArraySize, unsigned Quals,
+ SourceLocation Loc, DeclarationName Entity);
+ QualType BuildFunctionType(QualType T,
+ QualType *ParamTypes, unsigned NumParamTypes,
+ bool Variadic, unsigned Quals,
+ SourceLocation Loc, DeclarationName Entity);
+ QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0,
+ TagDecl **OwnedDecl = 0);
+ DeclarationName GetNameForDeclarator(Declarator &D);
+ bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
+ bool CheckDistantExceptionSpec(QualType T);
+
+ QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D);
+
+ bool UnwrapSimilarPointerTypes(QualType& T1, QualType& T2);
+
+ virtual TypeResult ActOnTypeName(Scope *S, Declarator &D);
+
+ bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
+ SourceRange Range1 = SourceRange(),
+ SourceRange Range2 = SourceRange(),
+ QualType PrintType = QualType());
+
+ QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T);
+
+ //===--------------------------------------------------------------------===//
+ // Symbol table / Decl tracking callbacks: SemaDecl.cpp.
+ //
+
+ /// getDeclName - Return a pretty name for the specified decl if possible, or
+ /// an empty string if not. This is used for pretty crash reporting.
+ virtual std::string getDeclName(DeclPtrTy D);
+
+ DeclGroupPtrTy ConvertDeclToDeclGroup(DeclPtrTy Ptr);
+
+ virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
+ Scope *S, const CXXScopeSpec *SS);
+ virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S);
+
+ virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) {
+ return ActOnDeclarator(S, D, false);
+ }
+ DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition);
+ void RegisterLocallyScopedExternCDecl(NamedDecl *ND, NamedDecl *PrevDecl,
+ Scope *S);
+ void DiagnoseFunctionSpecifiers(Declarator& D);
+ NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
+ QualType R, Decl* PrevDecl,
+ bool &Redeclaration);
+ NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
+ QualType R, NamedDecl* PrevDecl,
+ bool &Redeclaration);
+ void CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
+ bool &Redeclaration);
+ NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
+ QualType R, NamedDecl* PrevDecl,
+ bool IsFunctionDefinition,
+ bool &Redeclaration);
+ void CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
+ bool &Redeclaration,
+ bool &OverloadableAttrRequired);
+ virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D);
+ virtual void ActOnParamDefaultArgument(DeclPtrTy param,
+ SourceLocation EqualLoc,
+ ExprArg defarg);
+ virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
+ SourceLocation EqualLoc);
+ virtual void ActOnParamDefaultArgumentError(DeclPtrTy param);
+ virtual void AddInitializerToDecl(DeclPtrTy dcl, FullExprArg init);
+ void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit);
+ void ActOnUninitializedDecl(DeclPtrTy dcl);
+ virtual void SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc);
+ virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
+ DeclPtrTy *Group,
+ unsigned NumDecls);
+ virtual void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
+ SourceLocation LocAfterDecls);
+ virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *S, Declarator &D);
+ virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *S, DeclPtrTy D);
+ virtual void ActOnStartOfObjCMethodDef(Scope *S, DeclPtrTy D);
+
+ virtual DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body);
+ DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body,
+ bool IsInstantiation);
+ void DiagnoseInvalidJumps(Stmt *Body);
+ virtual DeclPtrTy ActOnFileScopeAsmDecl(SourceLocation Loc, ExprArg expr);
+
+ /// Scope actions.
+ virtual void ActOnPopScope(SourceLocation Loc, Scope *S);
+ virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S);
+
+ /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
+ /// no declarator (e.g. "struct foo;") is parsed.
+ virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS);
+
+ bool InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
+ RecordDecl *AnonRecord);
+ virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
+ RecordDecl *Record);
+
+ bool isAcceptableTagRedeclaration(const TagDecl *Previous,
+ TagDecl::TagKind NewTag,
+ SourceLocation NewTagLoc,
+ const IdentifierInfo &Name);
+
+ virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
+ SourceLocation KWLoc, const CXXScopeSpec &SS,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ AttributeList *Attr, AccessSpecifier AS,
+ bool &OwnedDecl);
+
+ virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
+ IdentifierInfo *ClassName,
+ llvm::SmallVectorImpl<DeclPtrTy> &Decls);
+ virtual DeclPtrTy ActOnField(Scope *S, DeclPtrTy TagD,
+ SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth);
+
+ FieldDecl *HandleField(Scope *S, RecordDecl *TagD, SourceLocation DeclStart,
+ Declarator &D, Expr *BitfieldWidth,
+ AccessSpecifier AS);
+
+ FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T,
+ RecordDecl *Record, SourceLocation Loc,
+ bool Mutable, Expr *BitfieldWidth,
+ AccessSpecifier AS, NamedDecl *PrevDecl,
+ Declarator *D = 0);
+
+ virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth,
+ tok::ObjCKeywordKind visibility);
+
+ // This is used for both record definitions and ObjC interface declarations.
+ virtual void ActOnFields(Scope* S,
+ SourceLocation RecLoc, DeclPtrTy TagDecl,
+ DeclPtrTy *Fields, unsigned NumFields,
+ SourceLocation LBrac, SourceLocation RBrac,
+ AttributeList *AttrList);
+
+ /// ActOnTagStartDefinition - Invoked when we have entered the
+ /// scope of a tag's definition (e.g., for an enumeration, class,
+ /// struct, or union).
+ virtual void ActOnTagStartDefinition(Scope *S, DeclPtrTy TagDecl);
+
+ /// ActOnTagFinishDefinition - Invoked once we have finished parsing
+ /// the definition of a tag (enumeration, class, struct, or union).
+ virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl);
+
+ EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum,
+ EnumConstantDecl *LastEnumConst,
+ SourceLocation IdLoc,
+ IdentifierInfo *Id,
+ ExprArg val);
+
+ virtual DeclPtrTy ActOnEnumConstant(Scope *S, DeclPtrTy EnumDecl,
+ DeclPtrTy LastEnumConstant,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ SourceLocation EqualLoc, ExprTy *Val);
+ virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
+ SourceLocation RBraceLoc, DeclPtrTy EnumDecl,
+ DeclPtrTy *Elements, unsigned NumElements);
+
+ DeclContext *getContainingDC(DeclContext *DC);
+
+ /// Set the current declaration context until it gets popped.
+ void PushDeclContext(Scope *S, DeclContext *DC);
+ void PopDeclContext();
+
+ /// getCurFunctionDecl - If inside of a function body, this returns a pointer
+ /// to the function decl for the function being parsed. If we're currently
+ /// in a 'block', this returns the containing context.
+ FunctionDecl *getCurFunctionDecl();
+
+ /// getCurMethodDecl - If inside of a method body, this returns a pointer to
+ /// the method decl for the method being parsed. If we're currently
+ /// in a 'block', this returns the containing context.
+ ObjCMethodDecl *getCurMethodDecl();
+
+ /// getCurFunctionOrMethodDecl - Return the Decl for the current ObjC method
+ /// or C function we're in, otherwise return null. If we're currently
+ /// in a 'block', this returns the containing context.
+ NamedDecl *getCurFunctionOrMethodDecl();
+
+ /// Add this decl to the scope shadowed decl chains.
+ void PushOnScopeChains(NamedDecl *D, Scope *S);
+
+ /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
+ /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
+ /// true if 'D' belongs to the given declaration context.
+ bool isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S = 0) {
+ return IdResolver.isDeclInScope(D, Ctx, Context, S);
+ }
+
+
+ /// Subroutines of ActOnDeclarator().
+ TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T);
+ void MergeTypeDefDecl(TypedefDecl *New, Decl *Old);
+ bool MergeFunctionDecl(FunctionDecl *New, Decl *Old);
+ bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old);
+ void MergeVarDecl(VarDecl *New, Decl *Old);
+ bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old);
+
+ /// C++ Overloading.
+ bool IsOverload(FunctionDecl *New, Decl* OldD,
+ OverloadedFunctionDecl::function_iterator &MatchedDecl);
+ ImplicitConversionSequence
+ TryImplicitConversion(Expr* From, QualType ToType,
+ bool SuppressUserConversions = false,
+ bool AllowExplicit = false,
+ bool ForceRValue = false);
+ bool IsStandardConversion(Expr *From, QualType ToType,
+ StandardConversionSequence& SCS);
+ bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType);
+ bool IsFloatingPointPromotion(QualType FromType, QualType ToType);
+ bool IsComplexPromotion(QualType FromType, QualType ToType);
+ bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
+ QualType& ConvertedType, bool &IncompatibleObjC);
+ bool isObjCPointerConversion(QualType FromType, QualType ToType,
+ QualType& ConvertedType, bool &IncompatibleObjC);
+ bool CheckPointerConversion(Expr *From, QualType ToType);
+ bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType,
+ QualType &ConvertedType);
+ bool CheckMemberPointerConversion(Expr *From, QualType ToType);
+ bool IsQualificationConversion(QualType FromType, QualType ToType);
+ bool IsUserDefinedConversion(Expr *From, QualType ToType,
+ UserDefinedConversionSequence& User,
+ bool AllowConversionFunctions,
+ bool AllowExplicit, bool ForceRValue);
+
+ ImplicitConversionSequence::CompareKind
+ CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
+ const ImplicitConversionSequence& ICS2);
+
+ ImplicitConversionSequence::CompareKind
+ CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
+ const StandardConversionSequence& SCS2);
+
+ ImplicitConversionSequence::CompareKind
+ CompareQualificationConversions(const StandardConversionSequence& SCS1,
+ const StandardConversionSequence& SCS2);
+
+ ImplicitConversionSequence::CompareKind
+ CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
+ const StandardConversionSequence& SCS2);
+
+ ImplicitConversionSequence
+ TryCopyInitialization(Expr* From, QualType ToType,
+ bool SuppressUserConversions = false,
+ bool ForceRValue = false);
+ bool PerformCopyInitialization(Expr *&From, QualType ToType,
+ const char *Flavor, bool Elidable = false);
+
+ ImplicitConversionSequence
+ TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method);
+ bool PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method);
+
+ ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From);
+ bool PerformContextuallyConvertToBool(Expr *&From);
+
+ /// OverloadingResult - Capture the result of performing overload
+ /// resolution.
+ enum OverloadingResult {
+ OR_Success, ///< Overload resolution succeeded.
+ OR_No_Viable_Function, ///< No viable function found.
+ OR_Ambiguous, ///< Ambiguous candidates found.
+ OR_Deleted ///< Overload resoltuion refers to a deleted function.
+ };
+
+ typedef llvm::SmallPtrSet<FunctionDecl *, 16> FunctionSet;
+ typedef llvm::SmallPtrSet<NamespaceDecl *, 16> AssociatedNamespaceSet;
+ typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet;
+
+ void AddOverloadCandidate(FunctionDecl *Function,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversions = false,
+ bool ForceRValue = false);
+ void AddFunctionCandidates(const FunctionSet &Functions,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversions = false);
+ void AddMethodCandidate(CXXMethodDecl *Method,
+ Expr *Object, Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversions = false,
+ bool ForceRValue = false);
+ void AddConversionCandidate(CXXConversionDecl *Conversion,
+ Expr *From, QualType ToType,
+ OverloadCandidateSet& CandidateSet);
+ void AddSurrogateCandidate(CXXConversionDecl *Conversion,
+ const FunctionProtoType *Proto,
+ Expr *Object, Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet);
+ void AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
+ SourceLocation OpLoc,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ SourceRange OpRange = SourceRange());
+ void AddMemberOperatorCandidates(OverloadedOperatorKind Op,
+ SourceLocation OpLoc,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ SourceRange OpRange = SourceRange());
+ void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool IsAssignmentOperator = false,
+ unsigned NumContextualBoolArguments = 0);
+ void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet);
+ void AddArgumentDependentLookupCandidates(DeclarationName Name,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet);
+ bool isBetterOverloadCandidate(const OverloadCandidate& Cand1,
+ const OverloadCandidate& Cand2);
+ OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet,
+ OverloadCandidateSet::iterator& Best);
+ void PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
+ bool OnlyViable);
+
+ FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
+ bool Complain);
+ void FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
+
+ FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
+ DeclarationName UnqualifiedName,
+ SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc,
+ bool &ArgumentDependentLookup);
+
+ OwningExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc,
+ unsigned Opc,
+ FunctionSet &Functions,
+ ExprArg input);
+
+ OwningExprResult CreateOverloadedBinOp(SourceLocation OpLoc,
+ unsigned Opc,
+ FunctionSet &Functions,
+ Expr *LHS, Expr *RHS);
+
+ ExprResult
+ BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
+ SourceLocation LParenLoc, Expr **Args,
+ unsigned NumArgs, SourceLocation *CommaLocs,
+ SourceLocation RParenLoc);
+ ExprResult
+ BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc);
+
+ ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
+ SourceLocation MemberLoc,
+ IdentifierInfo &Member);
+
+ /// Helpers for dealing with function parameters.
+ bool CheckParmsForFunctionDef(FunctionDecl *FD);
+ void CheckCXXDefaultArguments(FunctionDecl *FD);
+ void CheckExtraCXXDefaultArguments(Declarator &D);
+
+ Scope *getNonFieldDeclScope(Scope *S);
+
+ /// \name Name lookup
+ ///
+ /// These routines provide name lookup that is used during semantic
+ /// analysis to resolve the various kinds of names (identifiers,
+ /// overloaded operator names, constructor names, etc.) into zero or
+ /// more declarations within a particular scope. The major entry
+ /// points are LookupName, which performs unqualified name lookup,
+ /// and LookupQualifiedName, which performs qualified name lookup.
+ ///
+ /// All name lookup is performed based on some specific criteria,
+ /// which specify what names will be visible to name lookup and how
+ /// far name lookup should work. These criteria are important both
+ /// for capturing language semantics (certain lookups will ignore
+ /// certain names, for example) and for performance, since name
+ /// lookup is often a bottleneck in the compilation of C++. Name
+ /// lookup criteria is specified via the LookupCriteria enumeration.
+ ///
+ /// The results of name lookup can vary based on the kind of name
+ /// lookup performed, the current language, and the translation
+ /// unit. In C, for example, name lookup will either return nothing
+ /// (no entity found) or a single declaration. In C++, name lookup
+ /// can additionally refer to a set of overloaded functions or
+ /// result in an ambiguity. All of the possible results of name
+ /// lookup are captured by the LookupResult class, which provides
+ /// the ability to distinguish among them.
+ //@{
+
+ /// @brief Describes the kind of name lookup to perform.
+ enum LookupNameKind {
+ /// Ordinary name lookup, which finds ordinary names (functions,
+ /// variables, typedefs, etc.) in C and most kinds of names
+ /// (functions, variables, members, types, etc.) in C++.
+ LookupOrdinaryName = 0,
+ /// Tag name lookup, which finds the names of enums, classes,
+ /// structs, and unions.
+ LookupTagName,
+ /// Member name lookup, which finds the names of
+ /// class/struct/union members.
+ LookupMemberName,
+ // Look up of an operator name (e.g., operator+) for use with
+ // operator overloading. This lookup is similar to ordinary name
+ // lookup, but will ignore any declarations that are class
+ // members.
+ LookupOperatorName,
+ /// Look up of a name that precedes the '::' scope resolution
+ /// operator in C++. This lookup completely ignores operator,
+ /// function, and enumerator names (C++ [basic.lookup.qual]p1).
+ LookupNestedNameSpecifierName,
+ /// Look up a namespace name within a C++ using directive or
+ /// namespace alias definition, ignoring non-namespace names (C++
+ /// [basic.lookup.udir]p1).
+ LookupNamespaceName,
+ /// Look up an ordinary name that is going to be redeclared as a
+ /// name with linkage. This lookup ignores any declarations that
+ /// are outside of the current scope unless they have linkage. See
+ /// C99 6.2.2p4-5 and C++ [basic.link]p6.
+ LookupRedeclarationWithLinkage,
+ /// Look up the name of an Objective-C protocol.
+ LookupObjCProtocolName,
+ /// Look up the name of an Objective-C implementation
+ LookupObjCImplementationName,
+ /// Look up the name of an Objective-C category implementation
+ LookupObjCCategoryImplName
+ };
+
+ /// @brief Represents the results of name lookup.
+ ///
+ /// An instance of the LookupResult class captures the results of a
+ /// single name lookup, which can return no result (nothing found),
+ /// a single declaration, a set of overloaded functions, or an
+ /// ambiguity. Use the getKind() method to determine which of these
+ /// results occurred for a given lookup.
+ ///
+ /// Any non-ambiguous lookup can be converted into a single
+ /// (possibly NULL) @c NamedDecl* via a conversion function or the
+ /// getAsDecl() method. This conversion permits the common-case
+ /// usage in C and Objective-C where name lookup will always return
+ /// a single declaration.
+ struct LookupResult {
+ /// The kind of entity that is actually stored within the
+ /// LookupResult object.
+ enum {
+ /// First is a single declaration (a NamedDecl*), which may be NULL.
+ SingleDecl,
+
+ /// First is a single declaration (an OverloadedFunctionDecl*).
+ OverloadedDeclSingleDecl,
+
+ /// [First, Last) is an iterator range represented as opaque
+ /// pointers used to reconstruct IdentifierResolver::iterators.
+ OverloadedDeclFromIdResolver,
+
+ /// [First, Last) is an iterator range represented as opaque
+ /// pointers used to reconstruct DeclContext::lookup_iterators.
+ OverloadedDeclFromDeclContext,
+
+ /// First is a pointer to a BasePaths structure, which is owned
+ /// by the LookupResult. Last is non-zero to indicate that the
+ /// ambiguity is caused by two names found in base class
+ /// subobjects of different types.
+ AmbiguousLookupStoresBasePaths,
+
+ /// [First, Last) is an iterator range represented as opaque
+ /// pointers used to reconstruct new'ed Decl*[] array containing
+ /// found ambiguous decls. LookupResult is owner of this array.
+ AmbiguousLookupStoresDecls
+ } StoredKind;
+
+ /// The first lookup result, whose contents depend on the kind of
+ /// lookup result. This may be a NamedDecl* (if StoredKind ==
+ /// SingleDecl), OverloadedFunctionDecl* (if StoredKind ==
+ /// OverloadedDeclSingleDecl), the opaque pointer from an
+ /// IdentifierResolver::iterator (if StoredKind ==
+ /// OverloadedDeclFromIdResolver), a DeclContext::lookup_iterator
+ /// (if StoredKind == OverloadedDeclFromDeclContext), or a
+ /// BasePaths pointer (if StoredKind == AmbiguousLookupStoresBasePaths).
+ mutable uintptr_t First;
+
+ /// The last lookup result, whose contents depend on the kind of
+ /// lookup result. This may be unused (if StoredKind ==
+ /// SingleDecl), it may have the same type as First (for
+ /// overloaded function declarations), or is may be used as a
+ /// Boolean value (if StoredKind == AmbiguousLookupStoresBasePaths).
+ mutable uintptr_t Last;
+
+ /// Context - The context in which we will build any
+ /// OverloadedFunctionDecl nodes needed by the conversion to
+ /// Decl*.
+ ASTContext *Context;
+
+ /// @brief The kind of entity found by name lookup.
+ enum LookupKind {
+ /// @brief No entity found met the criteria.
+ NotFound = 0,
+
+ /// @brief Name lookup found a single declaration that met the
+ /// criteria. getAsDecl will return this declaration.
+ Found,
+
+ /// @brief Name lookup found a set of overloaded functions that
+ /// met the criteria. getAsDecl will turn this set of overloaded
+ /// functions into an OverloadedFunctionDecl.
+ FoundOverloaded,
+
+ /// Name lookup results in an ambiguity because multiple
+ /// entities that meet the lookup criteria were found in
+ /// subobjects of different types. For example:
+ /// @code
+ /// struct A { void f(int); }
+ /// struct B { void f(double); }
+ /// struct C : A, B { };
+ /// void test(C c) {
+ /// c.f(0); // error: A::f and B::f come from subobjects of different
+ /// // types. overload resolution is not performed.
+ /// }
+ /// @endcode
+ AmbiguousBaseSubobjectTypes,
+
+ /// Name lookup results in an ambiguity because multiple
+ /// nonstatic entities that meet the lookup criteria were found
+ /// in different subobjects of the same type. For example:
+ /// @code
+ /// struct A { int x; };
+ /// struct B : A { };
+ /// struct C : A { };
+ /// struct D : B, C { };
+ /// int test(D d) {
+ /// return d.x; // error: 'x' is found in two A subobjects (of B and C)
+ /// }
+ /// @endcode
+ AmbiguousBaseSubobjects,
+
+ /// Name lookup results in an ambiguity because multiple definitions
+ /// of entity that meet the lookup criteria were found in different
+ /// declaration contexts.
+ /// @code
+ /// namespace A {
+ /// int i;
+ /// namespace B { int i; }
+ /// int test() {
+ /// using namespace B;
+ /// return i; // error 'i' is found in namespace A and A::B
+ /// }
+ /// }
+ /// @endcode
+ AmbiguousReference
+ };
+
+ static LookupResult CreateLookupResult(ASTContext &Context, NamedDecl *D);
+
+ static LookupResult CreateLookupResult(ASTContext &Context,
+ IdentifierResolver::iterator F,
+ IdentifierResolver::iterator L);
+
+ static LookupResult CreateLookupResult(ASTContext &Context,
+ DeclContext::lookup_iterator F,
+ DeclContext::lookup_iterator L);
+
+ static LookupResult CreateLookupResult(ASTContext &Context, BasePaths *Paths,
+ bool DifferentSubobjectTypes) {
+ LookupResult Result;
+ Result.StoredKind = AmbiguousLookupStoresBasePaths;
+ Result.First = reinterpret_cast<uintptr_t>(Paths);
+ Result.Last = DifferentSubobjectTypes? 1 : 0;
+ Result.Context = &Context;
+ return Result;
+ }
+
+ template <typename Iterator>
+ static LookupResult CreateLookupResult(ASTContext &Context,
+ Iterator B, std::size_t Len) {
+ NamedDecl ** Array = new NamedDecl*[Len];
+ for (std::size_t Idx = 0; Idx < Len; ++Idx, ++B)
+ Array[Idx] = *B;
+ LookupResult Result;
+ Result.StoredKind = AmbiguousLookupStoresDecls;
+ Result.First = reinterpret_cast<uintptr_t>(Array);
+ Result.Last = reinterpret_cast<uintptr_t>(Array + Len);
+ Result.Context = &Context;
+ return Result;
+ }
+
+ LookupKind getKind() const;
+
+ /// @brief Determine whether name look found something.
+ operator bool() const { return getKind() != NotFound; }
+
+ /// @brief Determines whether the lookup resulted in an ambiguity.
+ bool isAmbiguous() const {
+ return StoredKind == AmbiguousLookupStoresBasePaths ||
+ StoredKind == AmbiguousLookupStoresDecls;
+ }
+
+ /// @brief Allows conversion of a lookup result into a
+ /// declaration, with the same behavior as getAsDecl.
+ operator NamedDecl*() const { return getAsDecl(); }
+
+ NamedDecl* getAsDecl() const;
+
+ BasePaths *getBasePaths() const;
+
+ /// \brief Iterate over the results of name lookup.
+ ///
+ /// The @c iterator class provides iteration over the results of a
+ /// non-ambiguous name lookup.
+ class iterator {
+ /// The LookupResult structure we're iterating through.
+ LookupResult *Result;
+
+ /// The current position of this iterator within the sequence of
+ /// results. This value will have the same representation as the
+ /// @c First field in the LookupResult structure.
+ mutable uintptr_t Current;
+
+ public:
+ typedef NamedDecl * value_type;
+ typedef NamedDecl * reference;
+ typedef NamedDecl * pointer;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::forward_iterator_tag iterator_category;
+
+ iterator() : Result(0), Current(0) { }
+
+ iterator(LookupResult *Res, uintptr_t Cur) : Result(Res), Current(Cur) { }
+
+ reference operator*() const;
+
+ pointer operator->() const { return **this; }
+
+ iterator &operator++();
+
+ iterator operator++(int) {
+ iterator tmp(*this);
+ ++(*this);
+ return tmp;
+ }
+
+ friend inline bool operator==(iterator const& x, iterator const& y) {
+ return x.Current == y.Current;
+ }
+
+ friend inline bool operator!=(iterator const& x, iterator const& y) {
+ return x.Current != y.Current;
+ }
+ };
+ friend class iterator;
+
+ iterator begin();
+ iterator end();
+
+ /// \brief Free the memory associated with this lookup.
+ void Destroy();
+ };
+
+private:
+ typedef llvm::SmallVector<LookupResult, 3> LookupResultsVecTy;
+
+ std::pair<bool, LookupResult> CppLookupName(Scope *S, DeclarationName Name,
+ LookupNameKind NameKind,
+ bool RedeclarationOnly);
+ ObjCMethodDecl *FindMethodInNestedImplementations(
+ const ObjCInterfaceDecl *IFace,
+ const Selector &Sel);
+
+public:
+ /// Determines whether D is a suitable lookup result according to the
+ /// lookup criteria.
+ static bool isAcceptableLookupResult(NamedDecl *D, LookupNameKind NameKind,
+ unsigned IDNS) {
+ switch (NameKind) {
+ case Sema::LookupOrdinaryName:
+ case Sema::LookupTagName:
+ case Sema::LookupMemberName:
+ case Sema::LookupRedeclarationWithLinkage: // FIXME: check linkage, scoping
+ case Sema::LookupObjCProtocolName:
+ case Sema::LookupObjCImplementationName:
+ case Sema::LookupObjCCategoryImplName:
+ return D->isInIdentifierNamespace(IDNS);
+
+ case Sema::LookupOperatorName:
+ return D->isInIdentifierNamespace(IDNS) &&
+ !D->getDeclContext()->isRecord();
+
+ case Sema::LookupNestedNameSpecifierName:
+ return isa<TypedefDecl>(D) || D->isInIdentifierNamespace(Decl::IDNS_Tag);
+
+ case Sema::LookupNamespaceName:
+ return isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D);
+ }
+
+ assert(false &&
+ "isAcceptableLookupResult always returns before this point");
+ return false;
+ }
+
+ LookupResult LookupName(Scope *S, DeclarationName Name,
+ LookupNameKind NameKind,
+ bool RedeclarationOnly = false,
+ bool AllowBuiltinCreation = true,
+ SourceLocation Loc = SourceLocation());
+ LookupResult LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
+ LookupNameKind NameKind,
+ bool RedeclarationOnly = false);
+ LookupResult LookupParsedName(Scope *S, const CXXScopeSpec *SS,
+ DeclarationName Name,
+ LookupNameKind NameKind,
+ bool RedeclarationOnly = false,
+ bool AllowBuiltinCreation = true,
+ SourceLocation Loc = SourceLocation());
+
+ ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II);
+ ObjCImplementationDecl *LookupObjCImplementation(IdentifierInfo *II);
+ ObjCCategoryImplDecl *LookupObjCCategoryImpl(IdentifierInfo *II);
+
+ void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
+ QualType T1, QualType T2,
+ FunctionSet &Functions);
+
+ void ArgumentDependentLookup(DeclarationName Name,
+ Expr **Args, unsigned NumArgs,
+ FunctionSet &Functions);
+
+ void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
+ AssociatedNamespaceSet &AssociatedNamespaces,
+ AssociatedClassSet &AssociatedClasses);
+
+ bool DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
+ SourceLocation NameLoc,
+ SourceRange LookupRange = SourceRange());
+ //@}
+
+ ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id);
+ NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
+ Scope *S, bool ForRedeclaration,
+ SourceLocation Loc);
+ NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
+ Scope *S);
+ void AddKnownFunctionAttributes(FunctionDecl *FD);
+
+ // More parsing and symbol table subroutines.
+
+ // Decl attributes - this routine is the top level dispatcher.
+ void ProcessDeclAttributes(Decl *D, const Declarator &PD);
+ void ProcessDeclAttributeList(Decl *D, const AttributeList *AttrList);
+
+ void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
+ bool &IncompleteImpl);
+ void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod,
+ ObjCMethodDecl *IntfMethod);
+ bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS);
+
+ NamespaceDecl *GetStdNamespace();
+
+ bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl,
+ ObjCInterfaceDecl *IDecl);
+
+ /// 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
+ /// inherited.
+ void CheckProtocolMethodDefs(SourceLocation ImpLoc,
+ ObjCProtocolDecl *PDecl,
+ bool& IncompleteImpl,
+ const llvm::DenseSet<Selector> &InsMap,
+ const llvm::DenseSet<Selector> &ClsMap,
+ ObjCInterfaceDecl *IDecl);
+
+ /// CheckImplementationIvars - This routine checks if the instance variables
+ /// listed in the implelementation match those listed in the interface.
+ void CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
+ ObjCIvarDecl **Fields, unsigned nIvars,
+ SourceLocation Loc);
+
+ /// ImplMethodsVsClassMethods - This is main routine to warn if any method
+ /// remains unimplemented in the class or category @implementation.
+ void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl* IDecl,
+ bool IncompleteImpl = false);
+
+ /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns
+ /// true, or false, accordingly.
+ bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
+ const ObjCMethodDecl *PrevMethod,
+ bool matchBasedOnSizeAndAlignment = false);
+
+ /// MatchAllMethodDeclarations - Check methods declaraed in interface or
+ /// or protocol against those declared in their implementations.
+ void MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
+ const llvm::DenseSet<Selector> &ClsMap,
+ llvm::DenseSet<Selector> &InsMapSeen,
+ llvm::DenseSet<Selector> &ClsMapSeen,
+ ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl* IDecl,
+ bool &IncompleteImpl,
+ bool ImmediateClass);
+
+ /// AddInstanceMethodToGlobalPool - All instance methods in a translation
+ /// unit are added to a global pool. This allows us to efficiently associate
+ /// a selector with a method declaraation for purposes of typechecking
+ /// messages sent to "id" (where the class of the object is unknown).
+ void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method);
+
+ /// LookupInstanceMethodInGlobalPool - Returns the method and warns if
+ /// there are multiple signatures.
+ ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R);
+
+ /// LookupFactoryMethodInGlobalPool - Returns the method and warns if
+ /// there are multiple signatures.
+ ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R);
+
+ /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods.
+ void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method);
+ //===--------------------------------------------------------------------===//
+ // Statement Parsing Callbacks: SemaStmt.cpp.
+public:
+ virtual OwningStmtResult ActOnExprStmt(FullExprArg Expr);
+
+ virtual OwningStmtResult ActOnNullStmt(SourceLocation SemiLoc);
+ virtual OwningStmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R,
+ MultiStmtArg Elts,
+ bool isStmtExpr);
+ virtual OwningStmtResult ActOnDeclStmt(DeclGroupPtrTy Decl,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc);
+ virtual OwningStmtResult ActOnCaseStmt(SourceLocation CaseLoc, ExprArg LHSVal,
+ SourceLocation DotDotDotLoc, ExprArg RHSVal,
+ SourceLocation ColonLoc);
+ virtual void ActOnCaseStmtBody(StmtTy *CaseStmt, StmtArg SubStmt);
+
+ virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt, Scope *CurScope);
+ virtual OwningStmtResult ActOnLabelStmt(SourceLocation IdentLoc,
+ IdentifierInfo *II,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt);
+ virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc,
+ FullExprArg CondVal, StmtArg ThenVal,
+ SourceLocation ElseLoc, StmtArg ElseVal);
+ virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond);
+ virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
+ StmtArg Switch, StmtArg Body);
+ virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
+ FullExprArg Cond, StmtArg Body);
+ virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
+ SourceLocation WhileLoc, ExprArg Cond);
+
+ virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc,
+ StmtArg First, ExprArg Second,
+ ExprArg Third, SourceLocation RParenLoc,
+ StmtArg Body);
+ virtual OwningStmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc,
+ SourceLocation LParenLoc,
+ StmtArg First, ExprArg Second,
+ SourceLocation RParenLoc, StmtArg Body);
+
+ virtual OwningStmtResult ActOnGotoStmt(SourceLocation GotoLoc,
+ SourceLocation LabelLoc,
+ IdentifierInfo *LabelII);
+ virtual OwningStmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc,
+ SourceLocation StarLoc,
+ ExprArg DestExp);
+ virtual OwningStmtResult ActOnContinueStmt(SourceLocation ContinueLoc,
+ Scope *CurScope);
+ virtual OwningStmtResult ActOnBreakStmt(SourceLocation GotoLoc,
+ Scope *CurScope);
+
+ virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc,
+ FullExprArg RetValExp);
+ OwningStmtResult ActOnBlockReturnStmt(SourceLocation ReturnLoc,
+ Expr *RetValExp);
+
+ virtual OwningStmtResult ActOnAsmStmt(SourceLocation AsmLoc,
+ bool IsSimple,
+ bool IsVolatile,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ std::string *Names,
+ MultiExprArg Constraints,
+ MultiExprArg Exprs,
+ ExprArg AsmString,
+ MultiExprArg Clobbers,
+ SourceLocation RParenLoc);
+
+ virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
+ SourceLocation RParen,
+ DeclPtrTy Parm, StmtArg Body,
+ StmtArg CatchList);
+
+ virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc,
+ StmtArg Body);
+
+ virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
+ StmtArg Try,
+ StmtArg Catch, StmtArg Finally);
+
+ virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
+ ExprArg Throw,
+ Scope *CurScope);
+ virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc,
+ ExprArg SynchExpr,
+ StmtArg SynchBody);
+
+ VarDecl *BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
+ IdentifierInfo *Name,
+ SourceLocation Loc,
+ SourceRange Range);
+ virtual DeclPtrTy ActOnExceptionDeclarator(Scope *S, Declarator &D);
+
+ virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
+ DeclPtrTy ExDecl,
+ StmtArg HandlerBlock);
+ virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc,
+ StmtArg TryBlock,
+ MultiStmtArg Handlers);
+ void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock);
+
+ //===--------------------------------------------------------------------===//
+ // Expression Parsing Callbacks: SemaExpr.cpp.
+
+ bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc);
+ bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD,
+ ObjCMethodDecl *Getter,
+ SourceLocation Loc);
+ void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
+ Expr **Args, unsigned NumArgs);
+
+ // Primary Expressions.
+ virtual SourceRange getExprRange(ExprTy *E) const;
+
+ virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
+ IdentifierInfo &II,
+ bool HasTrailingLParen,
+ const CXXScopeSpec *SS = 0,
+ bool isAddressOfOperand = false);
+ virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(Scope *S,
+ SourceLocation OperatorLoc,
+ OverloadedOperatorKind Op,
+ bool HasTrailingLParen,
+ const CXXScopeSpec &SS,
+ bool isAddressOfOperand);
+ virtual OwningExprResult ActOnCXXConversionFunctionExpr(Scope *S,
+ SourceLocation OperatorLoc,
+ TypeTy *Ty,
+ bool HasTrailingLParen,
+ const CXXScopeSpec &SS,
+ bool isAddressOfOperand);
+ DeclRefExpr *BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
+ bool TypeDependent, bool ValueDependent,
+ const CXXScopeSpec *SS = 0);
+ VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
+ llvm::SmallVectorImpl<FieldDecl *> &Path);
+ OwningExprResult
+ BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
+ FieldDecl *Field,
+ Expr *BaseObjectExpr = 0,
+ SourceLocation OpLoc = SourceLocation());
+ OwningExprResult ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
+ DeclarationName Name,
+ bool HasTrailingLParen,
+ const CXXScopeSpec *SS,
+ bool isAddressOfOperand = false);
+
+ virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc,
+ tok::TokenKind Kind);
+ virtual OwningExprResult ActOnNumericConstant(const Token &);
+ virtual OwningExprResult ActOnCharacterConstant(const Token &);
+ virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R,
+ ExprArg Val);
+
+ /// ActOnStringLiteral - The specified tokens were lexed as pasted string
+ /// fragments (e.g. "foo" "bar" L"baz").
+ virtual OwningExprResult ActOnStringLiteral(const Token *Toks,
+ unsigned NumToks);
+
+ // Binary/Unary Operators. 'Tok' is the token for the operator.
+ OwningExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc,
+ unsigned OpcIn,
+ ExprArg InputArg);
+ virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
+ tok::TokenKind Op, ExprArg Input);
+
+ OwningExprResult CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
+ bool isSizeOf, SourceRange R);
+ OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
+ bool isSizeOf, SourceRange R);
+ virtual OwningExprResult
+ ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
+ void *TyOrEx, const SourceRange &ArgRange);
+
+ bool CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, const SourceRange &R);
+ bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc,
+ const SourceRange &R, bool isSizeof);
+
+ virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
+ tok::TokenKind Kind,
+ ExprArg Input);
+
+ virtual OwningExprResult ActOnArraySubscriptExpr(Scope *S, ExprArg Base,
+ SourceLocation LLoc,
+ ExprArg Idx,
+ SourceLocation RLoc);
+ virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation MemberLoc,
+ IdentifierInfo &Member,
+ DeclPtrTy ImplDecl);
+ bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
+ FunctionDecl *FDecl,
+ const FunctionProtoType *Proto,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RParenLoc);
+
+ /// 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.
+ virtual OwningExprResult ActOnCallExpr(Scope *S, ExprArg Fn,
+ SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc);
+
+ virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
+ SourceLocation RParenLoc, ExprArg Op);
+
+ virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParenLoc,
+ TypeTy *Ty,
+ SourceLocation RParenLoc,
+ ExprArg Op);
+
+ virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc,
+ MultiExprArg InitList,
+ SourceLocation RParenLoc);
+
+ virtual OwningExprResult ActOnDesignatedInitializer(Designation &Desig,
+ SourceLocation Loc,
+ bool GNUSyntax,
+ OwningExprResult Init);
+
+ virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc,
+ tok::TokenKind Kind,
+ ExprArg LHS, ExprArg RHS);
+ OwningExprResult CreateBuiltinBinOp(SourceLocation TokLoc,
+ unsigned Opc, Expr *lhs, Expr *rhs);
+
+ /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
+ /// in the case of a the GNU conditional expr extension.
+ virtual OwningExprResult ActOnConditionalOp(SourceLocation QuestionLoc,
+ SourceLocation ColonLoc,
+ ExprArg Cond, ExprArg LHS,
+ ExprArg RHS);
+
+ /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
+ virtual OwningExprResult ActOnAddrLabel(SourceLocation OpLoc,
+ SourceLocation LabLoc,
+ IdentifierInfo *LabelII);
+
+ virtual OwningExprResult ActOnStmtExpr(SourceLocation LPLoc, StmtArg SubStmt,
+ SourceLocation RPLoc); // "({..})"
+
+ /// __builtin_offsetof(type, a.b[123][456].c)
+ virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S,
+ SourceLocation BuiltinLoc,
+ SourceLocation TypeLoc,
+ TypeTy *Arg1,
+ OffsetOfComponent *CompPtr,
+ unsigned NumComponents,
+ SourceLocation RParenLoc);
+
+ // __builtin_types_compatible_p(type1, type2)
+ virtual OwningExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
+ TypeTy *arg1, TypeTy *arg2,
+ SourceLocation RPLoc);
+
+ // __builtin_choose_expr(constExpr, expr1, expr2)
+ virtual OwningExprResult ActOnChooseExpr(SourceLocation BuiltinLoc,
+ ExprArg cond, ExprArg expr1,
+ ExprArg expr2, SourceLocation RPLoc);
+
+ // __builtin_va_arg(expr, type)
+ virtual OwningExprResult ActOnVAArg(SourceLocation BuiltinLoc,
+ ExprArg expr, TypeTy *type,
+ SourceLocation RPLoc);
+
+ // __null
+ virtual OwningExprResult ActOnGNUNullExpr(SourceLocation TokenLoc);
+
+ //===------------------------- "Block" Extension ------------------------===//
+
+ /// ActOnBlockStart - This callback is invoked when a block literal is
+ /// started.
+ virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope);
+
+ /// ActOnBlockArguments - This callback allows processing of block arguments.
+ /// If there are no arguments, this is still invoked.
+ virtual void ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope);
+
+ /// ActOnBlockError - If there is an error parsing a block, this callback
+ /// is invoked to pop the information about the block from the action impl.
+ virtual void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope);
+
+ /// ActOnBlockStmtExpr - This is called when the body of a block statement
+ /// literal was successfully completed. ^(int x){...}
+ virtual OwningExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc,
+ StmtArg Body, Scope *CurScope);
+
+ //===---------------------------- C++ Features --------------------------===//
+
+ // Act on C++ namespaces
+ virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc,
+ IdentifierInfo *Ident,
+ SourceLocation LBrace);
+ virtual void ActOnFinishNamespaceDef(DeclPtrTy Dcl, SourceLocation RBrace);
+
+ virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope,
+ SourceLocation UsingLoc,
+ SourceLocation NamespcLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *NamespcName,
+ AttributeList *AttrList);
+
+ void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir);
+
+ virtual DeclPtrTy ActOnNamespaceAliasDef(Scope *CurScope,
+ SourceLocation NamespaceLoc,
+ SourceLocation AliasLoc,
+ IdentifierInfo *Alias,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *Ident);
+
+ /// AddCXXDirectInitializerToDecl - This action is called immediately after
+ /// ActOnDeclarator, when a C++ direct initializer is present.
+ /// e.g: "int x(1);"
+ virtual void AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
+ SourceLocation LParenLoc,
+ MultiExprArg Exprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc);
+
+ /// InitializeVarWithConstructor - Creates an CXXConstructExpr
+ /// and sets it as the initializer for the the passed in VarDecl.
+ void InitializeVarWithConstructor(VarDecl *VD,
+ CXXConstructorDecl *Constructor,
+ QualType DeclInitType,
+ Expr **Exprs, unsigned NumExprs);
+
+ /// MaybeBindToTemporary - If the passed in expression has a record type with
+ /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise
+ /// it simply returns the passed in expression.
+ OwningExprResult MaybeBindToTemporary(Expr *E);
+
+ /// RemoveOutermostTemporaryBinding - Remove and destroy the outermost
+ /// CXXBindToTemporaryExpr if necessary. This is used when we want to not
+ /// destroy a temporary when a full expression has been evaluated.
+ /// For example:
+ ///
+ /// const T& t = T(10, T());
+ ///
+ /// Here the outermost T needs to be destroyed when t goes out of scope, but
+ /// the innermost T needs to be destroyed when the expr has been evaluated.
+ Expr *RemoveOutermostTemporaryBinding(Expr *E);
+
+ /// InitializationKind - Represents which kind of C++ initialization
+ /// [dcl.init] a routine is to perform.
+ enum InitializationKind {
+ IK_Direct, ///< Direct initialization
+ IK_Copy, ///< Copy initialization
+ IK_Default ///< Default initialization
+ };
+
+ CXXConstructorDecl *
+ PerformInitializationByConstructor(QualType ClassType,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation Loc, SourceRange Range,
+ DeclarationName InitEntity,
+ InitializationKind Kind);
+
+ /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
+ virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
+ tok::TokenKind Kind,
+ SourceLocation LAngleBracketLoc,
+ TypeTy *Ty,
+ SourceLocation RAngleBracketLoc,
+ SourceLocation LParenLoc,
+ ExprArg E,
+ SourceLocation RParenLoc);
+
+ /// ActOnCXXTypeid - Parse typeid( something ).
+ virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc,
+ SourceLocation LParenLoc, bool isType,
+ void *TyOrExpr,
+ SourceLocation RParenLoc);
+
+ //// ActOnCXXThis - Parse 'this' pointer.
+ virtual OwningExprResult ActOnCXXThis(SourceLocation ThisLoc);
+
+ /// ActOnCXXBoolLiteral - Parse {true,false} literals.
+ virtual OwningExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc,
+ tok::TokenKind Kind);
+
+ /// ActOnCXXNullPtrLiteral - Parse 'nullptr'.
+ virtual OwningExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc);
+
+ //// ActOnCXXThrow - Parse throw expressions.
+ virtual OwningExprResult ActOnCXXThrow(SourceLocation OpLoc,
+ ExprArg expr);
+ bool CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E);
+
+ /// ActOnCXXTypeConstructExpr - Parse construction of a specified type.
+ /// Can be interpreted either as function-style casting ("int(x)")
+ /// or class type construction ("ClassType(x,y,z)")
+ /// or creation of a value-initialized type ("int()").
+ virtual OwningExprResult ActOnCXXTypeConstructExpr(SourceRange TypeRange,
+ TypeTy *TypeRep,
+ SourceLocation LParenLoc,
+ MultiExprArg Exprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc);
+
+ /// ActOnCXXNew - Parsed a C++ 'new' expression.
+ virtual OwningExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
+ SourceLocation PlacementLParen,
+ MultiExprArg PlacementArgs,
+ SourceLocation PlacementRParen,
+ bool ParenTypeId, Declarator &D,
+ SourceLocation ConstructorLParen,
+ MultiExprArg ConstructorArgs,
+ SourceLocation ConstructorRParen);
+ OwningExprResult BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
+ SourceLocation PlacementLParen,
+ MultiExprArg PlacementArgs,
+ SourceLocation PlacementRParen,
+ bool ParenTypeId,
+ QualType AllocType,
+ SourceLocation TypeLoc,
+ SourceRange TypeRange,
+ ExprArg ArraySize,
+ SourceLocation ConstructorLParen,
+ MultiExprArg ConstructorArgs,
+ SourceLocation ConstructorRParen);
+
+ bool CheckAllocatedType(QualType AllocType, SourceLocation Loc,
+ SourceRange R);
+ bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
+ bool UseGlobal, QualType AllocType, bool IsArray,
+ Expr **PlaceArgs, unsigned NumPlaceArgs,
+ FunctionDecl *&OperatorNew,
+ FunctionDecl *&OperatorDelete);
+ bool FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
+ DeclarationName Name, Expr** Args,
+ unsigned NumArgs, DeclContext *Ctx,
+ bool AllowMissing, FunctionDecl *&Operator);
+ void DeclareGlobalNewDelete();
+ void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return,
+ QualType Argument);
+
+ /// ActOnCXXDelete - Parsed a C++ 'delete' expression
+ virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc,
+ bool UseGlobal, bool ArrayForm,
+ ExprArg Operand);
+
+ /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
+ /// C++ if/switch/while/for statement.
+ /// e.g: "if (int x = f()) {...}"
+ virtual OwningExprResult ActOnCXXConditionDeclarationExpr(Scope *S,
+ SourceLocation StartLoc,
+ Declarator &D,
+ SourceLocation EqualLoc,
+ ExprArg AssignExprVal);
+
+ /// ActOnUnaryTypeTrait - Parsed one of the unary type trait support
+ /// pseudo-functions.
+ virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
+ SourceLocation KWLoc,
+ SourceLocation LParen,
+ TypeTy *Ty,
+ SourceLocation RParen);
+
+ virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr);
+
+ bool RequireCompleteDeclContext(const CXXScopeSpec &SS);
+
+ DeclContext *computeDeclContext(const CXXScopeSpec &SS);
+ bool isDependentScopeSpecifier(const CXXScopeSpec &SS);
+ CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS);
+ bool isUnknownSpecialization(const CXXScopeSpec &SS);
+
+ /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
+ /// global scope ('::').
+ virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
+ SourceLocation CCLoc);
+
+ /// ActOnCXXNestedNameSpecifier - Called during parsing of a
+ /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
+ /// we want to resolve "bar::". 'SS' is empty or the previously parsed
+ /// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
+ /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
+ /// Returns a CXXScopeTy* object representing the C++ scope.
+ virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
+ const CXXScopeSpec &SS,
+ SourceLocation IdLoc,
+ SourceLocation CCLoc,
+ IdentifierInfo &II);
+
+ /// ActOnCXXNestedNameSpecifier - Called during parsing of a
+ /// nested-name-specifier that involves a template-id, e.g.,
+ /// "foo::bar<int, float>::", and now we need to build a scope
+ /// specifier. \p SS is empty or the previously parsed nested-name
+ /// part ("foo::"), \p Type is the already-parsed class template
+ /// specialization (or other template-id that names a type), \p
+ /// TypeRange is the source range where the type is located, and \p
+ /// CCLoc is the location of the trailing '::'.
+ virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
+ const CXXScopeSpec &SS,
+ TypeTy *Type,
+ SourceRange TypeRange,
+ SourceLocation CCLoc);
+
+ /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
+ /// scope or nested-name-specifier) is parsed, part of a declarator-id.
+ /// After this method is called, according to [C++ 3.4.3p3], names should be
+ /// looked up in the declarator-id's scope, until the declarator is parsed and
+ /// ActOnCXXExitDeclaratorScope is called.
+ /// The 'SS' should be a non-empty valid CXXScopeSpec.
+ virtual void ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS);
+
+ /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
+ /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same
+ /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well.
+ /// Used to indicate that names should revert to being looked up in the
+ /// defining scope.
+ virtual void ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS);
+
+ // ParseObjCStringLiteral - Parse Objective-C string literals.
+ virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
+ ExprTy **Strings,
+ unsigned NumStrings);
+ virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc,
+ SourceLocation EncodeLoc,
+ SourceLocation LParenLoc,
+ TypeTy *Ty,
+ SourceLocation RParenLoc);
+
+ // ParseObjCSelectorExpression - Build selector expression for @selector
+ virtual ExprResult ParseObjCSelectorExpression(Selector Sel,
+ SourceLocation AtLoc,
+ SourceLocation SelLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc);
+
+ // ParseObjCProtocolExpression - Build protocol expression for @protocol
+ virtual ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName,
+ SourceLocation AtLoc,
+ SourceLocation ProtoLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc);
+
+ //===--------------------------------------------------------------------===//
+ // C++ Declarations
+ //
+ virtual DeclPtrTy ActOnStartLinkageSpecification(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation LangLoc,
+ const char *Lang,
+ unsigned StrSize,
+ SourceLocation LBraceLoc);
+ virtual DeclPtrTy ActOnFinishLinkageSpecification(Scope *S,
+ DeclPtrTy LinkageSpec,
+ SourceLocation RBraceLoc);
+
+
+ //===--------------------------------------------------------------------===//
+ // C++ Classes
+ //
+ virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S,
+ const CXXScopeSpec *SS);
+
+ virtual DeclPtrTy ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS,
+ Declarator &D,
+ ExprTy *BitfieldWidth,
+ ExprTy *Init,
+ bool Deleted = false);
+
+ virtual MemInitResult ActOnMemInitializer(DeclPtrTy ConstructorD,
+ Scope *S,
+ IdentifierInfo *MemberOrBase,
+ SourceLocation IdLoc,
+ SourceLocation LParenLoc,
+ ExprTy **Args, unsigned NumArgs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc);
+
+ void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
+
+ virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
+ SourceLocation ColonLoc,
+ MemInitTy **MemInits, unsigned NumMemInits);
+
+ virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
+ DeclPtrTy TagDecl,
+ SourceLocation LBrac,
+ SourceLocation RBrac);
+
+ virtual void ActOnReenterTemplateScope(Scope *S, DeclPtrTy Template);
+ virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S,
+ DeclPtrTy Method);
+ virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy Param);
+ virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S,
+ DeclPtrTy Method);
+
+ virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
+ ExprArg AssertExpr,
+ ExprArg AssertMessageExpr);
+
+ virtual bool ActOnFriendDecl(Scope *S, SourceLocation FriendLoc,
+ DeclPtrTy Dcl);
+
+ QualType CheckConstructorDeclarator(Declarator &D, QualType R,
+ FunctionDecl::StorageClass& SC);
+ void CheckConstructor(CXXConstructorDecl *Constructor);
+ QualType CheckDestructorDeclarator(Declarator &D,
+ FunctionDecl::StorageClass& SC);
+ void CheckConversionDeclarator(Declarator &D, QualType &R,
+ FunctionDecl::StorageClass& SC);
+ DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion);
+
+ //===--------------------------------------------------------------------===//
+ // C++ Derived Classes
+ //
+
+ /// ActOnBaseSpecifier - Parsed a base specifier
+ CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class,
+ SourceRange SpecifierRange,
+ bool Virtual, AccessSpecifier Access,
+ QualType BaseType,
+ SourceLocation BaseLoc);
+ virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl,
+ SourceRange SpecifierRange,
+ bool Virtual, AccessSpecifier Access,
+ TypeTy *basetype, SourceLocation
+ BaseLoc);
+
+ bool AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
+ unsigned NumBases);
+ virtual void ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
+ unsigned NumBases);
+
+ bool IsDerivedFrom(QualType Derived, QualType Base);
+ bool IsDerivedFrom(QualType Derived, QualType Base, BasePaths &Paths);
+ bool LookupInBases(CXXRecordDecl *Class, const MemberLookupCriteria& Criteria,
+ BasePaths &Paths);
+ bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
+ SourceLocation Loc, SourceRange Range);
+ bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
+ unsigned InaccessibleBaseID,
+ unsigned AmbigiousBaseConvID,
+ SourceLocation Loc, SourceRange Range,
+ DeclarationName Name);
+
+ std::string getAmbiguousPathsDisplayString(BasePaths &Paths);
+
+ /// CheckReturnTypeCovariance - Checks whether two types are covariant,
+ /// according to C++ [class.virtual]p5.
+ bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old);
+
+
+ //===--------------------------------------------------------------------===//
+ // C++ Access Control
+ //
+
+ bool SetMemberAccessSpecifier(NamedDecl *MemberDecl,
+ NamedDecl *PrevMemberDecl,
+ AccessSpecifier LexicalAS);
+
+ bool CheckBaseClassAccess(QualType Derived, QualType Base,
+ unsigned InaccessibleBaseID,
+ BasePaths& Paths, SourceLocation AccessLoc,
+ DeclarationName Name);
+
+
+ enum AbstractDiagSelID {
+ AbstractNone = -1,
+ AbstractReturnType,
+ AbstractParamType,
+ AbstractVariableType,
+ AbstractFieldType
+ };
+
+ bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID,
+ AbstractDiagSelID SelID = AbstractNone,
+ const CXXRecordDecl *CurrentRD = 0);
+
+ //===--------------------------------------------------------------------===//
+ // C++ Overloaded Operators [C++ 13.5]
+ //
+
+ bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl);
+
+ //===--------------------------------------------------------------------===//
+ // C++ Templates [C++ 14]
+ //
+ virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
+ TemplateTy &Template,
+ const CXXScopeSpec *SS = 0);
+ bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
+ TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl);
+
+ virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename,
+ SourceLocation KeyLoc,
+ IdentifierInfo *ParamName,
+ SourceLocation ParamNameLoc,
+ unsigned Depth, unsigned Position);
+ virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam,
+ SourceLocation EqualLoc,
+ SourceLocation DefaultLoc,
+ TypeTy *Default);
+
+ QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc);
+ virtual DeclPtrTy ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
+ unsigned Depth,
+ unsigned Position);
+ virtual void ActOnNonTypeTemplateParameterDefault(DeclPtrTy TemplateParam,
+ SourceLocation EqualLoc,
+ ExprArg Default);
+ virtual DeclPtrTy ActOnTemplateTemplateParameter(Scope *S,
+ SourceLocation TmpLoc,
+ TemplateParamsTy *Params,
+ IdentifierInfo *ParamName,
+ SourceLocation ParamNameLoc,
+ unsigned Depth,
+ unsigned Position);
+ virtual void ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParam,
+ SourceLocation EqualLoc,
+ ExprArg Default);
+
+ virtual TemplateParamsTy *
+ ActOnTemplateParameterList(unsigned Depth,
+ SourceLocation ExportLoc,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ DeclPtrTy *Params, unsigned NumParams,
+ SourceLocation RAngleLoc);
+ bool CheckTemplateParameterList(TemplateParameterList *NewParams,
+ TemplateParameterList *OldParams);
+
+ virtual DeclResult
+ ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
+ SourceLocation KWLoc, const CXXScopeSpec &SS,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ AttributeList *Attr,
+ MultiTemplateParamsArg TemplateParameterLists,
+ AccessSpecifier AS);
+
+ QualType CheckTemplateIdType(TemplateName Template,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceLocation RAngleLoc);
+
+ virtual TypeResult
+ ActOnTemplateIdType(TemplateTy Template, SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgs,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc);
+
+ virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
+ const IdentifierInfo &Name,
+ SourceLocation NameLoc,
+ const CXXScopeSpec &SS);
+
+ bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
+ ClassTemplateSpecializationDecl *PrevDecl,
+ SourceLocation TemplateNameLoc,
+ SourceRange ScopeSpecifierRange,
+ bool ExplicitInstantiation);
+
+ virtual DeclResult
+ ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
+ SourceLocation KWLoc,
+ const CXXScopeSpec &SS,
+ TemplateTy Template,
+ SourceLocation TemplateNameLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgs,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc,
+ AttributeList *Attr,
+ MultiTemplateParamsArg TemplateParameterLists);
+
+ virtual DeclResult
+ ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
+ unsigned TagSpec,
+ SourceLocation KWLoc,
+ const CXXScopeSpec &SS,
+ TemplateTy Template,
+ SourceLocation TemplateNameLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgs,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc,
+ AttributeList *Attr);
+
+ virtual DeclResult
+ ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
+ unsigned TagSpec,
+ SourceLocation KWLoc,
+ const CXXScopeSpec &SS,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ AttributeList *Attr);
+
+ bool CheckTemplateArgumentList(TemplateDecl *Template,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceLocation RAngleLoc,
+ llvm::SmallVectorImpl<TemplateArgument> &Converted);
+
+ bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg,
+ SourceLocation ArgLoc);
+ bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
+ NamedDecl *&Entity);
+ bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member);
+ bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
+ QualType InstantiatedParamType, Expr *&Arg,
+ llvm::SmallVectorImpl<TemplateArgument> *Converted = 0);
+ bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg);
+ bool TemplateParameterListsAreEqual(TemplateParameterList *New,
+ TemplateParameterList *Old,
+ bool Complain,
+ bool IsTemplateTemplateParm = false,
+ SourceLocation TemplateArgLoc
+ = SourceLocation());
+
+ bool CheckTemplateDeclScope(Scope *S,
+ MultiTemplateParamsArg &TemplateParameterLists);
+
+ /// \brief Called when the parser has parsed a C++ typename
+ /// specifier, e.g., "typename T::type".
+ ///
+ /// \param TypenameLoc the location of the 'typename' keyword
+ /// \param SS the nested-name-specifier following the typename (e.g., 'T::').
+ /// \param II the identifier we're retrieving (e.g., 'type' in the example).
+ /// \param IdLoc the location of the identifier.
+ virtual TypeResult
+ ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
+ const IdentifierInfo &II, SourceLocation IdLoc);
+
+ /// \brief Called when the parser has parsed a C++ typename
+ /// specifier that ends in a template-id, e.g.,
+ /// "typename MetaFun::template apply<T1, T2>".
+ ///
+ /// \param TypenameLoc the location of the 'typename' keyword
+ /// \param SS the nested-name-specifier following the typename (e.g., 'T::').
+ /// \param TemplateLoc the location of the 'template' keyword, if any.
+ /// \param Ty the type that the typename specifier refers to.
+ virtual TypeResult
+ ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
+ SourceLocation TemplateLoc, TypeTy *Ty);
+
+ QualType CheckTypenameType(NestedNameSpecifier *NNS,
+ const IdentifierInfo &II,
+ SourceRange Range);
+
+ bool DeduceTemplateArguments(QualType Param, QualType Arg,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced);
+ bool DeduceTemplateArguments(const TemplateArgument &Param,
+ const TemplateArgument &Arg,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced);
+ bool DeduceTemplateArguments(const TemplateArgumentList &ParamList,
+ const TemplateArgumentList &ArgList,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced);
+ bool DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
+ const TemplateArgumentList &TemplateArgs);
+
+ //===--------------------------------------------------------------------===//
+ // C++ Template Instantiation
+ //
+
+ const TemplateArgumentList &getTemplateInstantiationArgs(NamedDecl *D);
+
+ /// \brief A template instantiation that is currently in progress.
+ struct ActiveTemplateInstantiation {
+ /// \brief The kind of template instantiation we are performing
+ enum {
+ /// We are instantiating a template declaration. The entity is
+ /// the declaration we're instantiating (e.g., a CXXRecordDecl).
+ TemplateInstantiation,
+
+ /// We are instantiating a default argument for a template
+ /// parameter. The Entity is the template, and
+ /// TemplateArgs/NumTemplateArguments provides the template
+ /// arguments as specified.
+ DefaultTemplateArgumentInstantiation
+ } Kind;
+
+ /// \brief The point of instantiation within the source code.
+ SourceLocation PointOfInstantiation;
+
+ /// \brief The entity that is being instantiated.
+ uintptr_t Entity;
+
+ // \brief If this the instantiation of a default template
+ // argument, the list of template arguments.
+ const TemplateArgument *TemplateArgs;
+
+ /// \brief The number of template arguments in TemplateArgs.
+ unsigned NumTemplateArgs;
+
+ /// \brief The source range that covers the construct that cause
+ /// the instantiation, e.g., the template-id that causes a class
+ /// template instantiation.
+ SourceRange InstantiationRange;
+
+ friend bool operator==(const ActiveTemplateInstantiation &X,
+ const ActiveTemplateInstantiation &Y) {
+ if (X.Kind != Y.Kind)
+ return false;
+
+ if (X.Entity != Y.Entity)
+ return false;
+
+ switch (X.Kind) {
+ case TemplateInstantiation:
+ return true;
+
+ case DefaultTemplateArgumentInstantiation:
+ return X.TemplateArgs == Y.TemplateArgs;
+ }
+
+ return true;
+ }
+
+ friend bool operator!=(const ActiveTemplateInstantiation &X,
+ const ActiveTemplateInstantiation &Y) {
+ return !(X == Y);
+ }
+ };
+
+ /// \brief List of active template instantiations.
+ ///
+ /// This vector is treated as a stack. As one template instantiation
+ /// requires another template instantiation, additional
+ /// instantiations are pushed onto the stack up to a
+ /// user-configurable limit LangOptions::InstantiationDepth.
+ llvm::SmallVector<ActiveTemplateInstantiation, 16>
+ ActiveTemplateInstantiations;
+
+ /// \brief The last template from which a template instantiation
+ /// error or warning was produced.
+ ///
+ /// This value is used to suppress printing of redundant template
+ /// instantiation backtraces when there are multiple errors in the
+ /// same instantiation. FIXME: Does this belong in Sema? It's tough
+ /// to implement it anywhere else.
+ ActiveTemplateInstantiation LastTemplateInstantiationErrorContext;
+
+ /// \brief A stack object to be created when performing template
+ /// instantiation.
+ ///
+ /// Construction of an object of type \c InstantiatingTemplate
+ /// pushes the current instantiation onto the stack of active
+ /// instantiations. If the size of this stack exceeds the maximum
+ /// number of recursive template instantiations, construction
+ /// produces an error and evaluates true.
+ ///
+ /// Destruction of this object will pop the named instantiation off
+ /// the stack.
+ struct InstantiatingTemplate {
+ /// \brief Note that we are instantiating a class template,
+ /// function template, or a member thereof.
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ Decl *Entity,
+ SourceRange InstantiationRange = SourceRange());
+
+ /// \brief Note that we are instantiating a default argument in a
+ /// template-id.
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange = SourceRange());
+
+ /// \brief Note that we have finished instantiating this template.
+ void Clear();
+
+ ~InstantiatingTemplate() { Clear(); }
+
+ /// \brief Determines whether we have exceeded the maximum
+ /// recursive template instantiations.
+ operator bool() const { return Invalid; }
+
+ private:
+ Sema &SemaRef;
+ bool Invalid;
+
+ bool CheckInstantiationDepth(SourceLocation PointOfInstantiation,
+ SourceRange InstantiationRange);
+
+ InstantiatingTemplate(const InstantiatingTemplate&); // not implemented
+
+ InstantiatingTemplate&
+ operator=(const InstantiatingTemplate&); // not implemented
+ };
+
+ void PrintInstantiationStack();
+
+ /// \brief A stack-allocated class that identifies which local
+ /// variable declaration instantiations are present in this scope.
+ ///
+ /// A new instance of this class type will be created whenever we
+ /// instantiate a new function declaration, which will have its own
+ /// set of parameter declarations.
+ class LocalInstantiationScope {
+ /// \brief Reference to the semantic analysis that is performing
+ /// this template instantiation.
+ Sema &SemaRef;
+
+ /// \brief A mapping from local declarations that occur
+ /// within a template to their instantiations.
+ ///
+ /// This mapping is used during instantiation to keep track of,
+ /// e.g., function parameter and variable declarations. For example,
+ /// given:
+ ///
+ /// \code
+ /// template<typename T> T add(T x, T y) { return x + y; }
+ /// \endcode
+ ///
+ /// when we instantiate add<int>, we will introduce a mapping from
+ /// the ParmVarDecl for 'x' that occurs in the template to the
+ /// instantiated ParmVarDecl for 'x'.
+ llvm::DenseMap<const Decl *, Decl *> LocalDecls;
+
+ /// \brief The outer scope, in which contains local variable
+ /// definitions from some other instantiation (that is not
+ /// relevant to this particular scope).
+ LocalInstantiationScope *Outer;
+
+ // This class is non-copyable
+ LocalInstantiationScope(const LocalInstantiationScope &);
+ LocalInstantiationScope &operator=(const LocalInstantiationScope &);
+
+ public:
+ LocalInstantiationScope(Sema &SemaRef)
+ : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) {
+ SemaRef.CurrentInstantiationScope = this;
+ }
+
+ ~LocalInstantiationScope() {
+ SemaRef.CurrentInstantiationScope = Outer;
+ }
+
+ Decl *getInstantiationOf(const Decl *D) {
+ Decl *Result = LocalDecls[D];
+ assert(Result && "declaration was not instantiated in this scope!");
+ return Result;
+ }
+
+ VarDecl *getInstantiationOf(const VarDecl *Var) {
+ return cast<VarDecl>(getInstantiationOf(cast<Decl>(Var)));
+ }
+
+ ParmVarDecl *getInstantiationOf(const ParmVarDecl *Var) {
+ return cast<ParmVarDecl>(getInstantiationOf(cast<Decl>(Var)));
+ }
+
+ void InstantiatedLocal(const Decl *D, Decl *Inst) {
+ Decl *&Stored = LocalDecls[D];
+ assert(!Stored && "Already instantiated this local");
+ Stored = Inst;
+ }
+ };
+
+ /// \brief The current instantiation scope used to store local
+ /// variables.
+ LocalInstantiationScope *CurrentInstantiationScope;
+
+ QualType InstantiateType(QualType T, const TemplateArgumentList &TemplateArgs,
+ SourceLocation Loc, DeclarationName Entity);
+
+ OwningExprResult InstantiateExpr(Expr *E,
+ const TemplateArgumentList &TemplateArgs);
+
+ OwningStmtResult InstantiateStmt(Stmt *S,
+ const TemplateArgumentList &TemplateArgs);
+ OwningStmtResult InstantiateCompoundStmt(CompoundStmt *S,
+ const TemplateArgumentList &TemplateArgs,
+ bool isStmtExpr);
+
+ Decl *InstantiateDecl(Decl *D, DeclContext *Owner,
+ const TemplateArgumentList &TemplateArgs);
+
+ bool
+ InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation,
+ CXXRecordDecl *Pattern,
+ const TemplateArgumentList &TemplateArgs);
+
+ bool
+ InstantiateClass(SourceLocation PointOfInstantiation,
+ CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
+ const TemplateArgumentList &TemplateArgs,
+ bool ExplicitInstantiation);
+
+ bool
+ InstantiateClassTemplateSpecialization(
+ ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ bool ExplicitInstantiation);
+
+ void InstantiateClassMembers(SourceLocation PointOfInstantiation,
+ CXXRecordDecl *Instantiation,
+ const TemplateArgumentList &TemplateArgs);
+
+ void InstantiateClassTemplateSpecializationMembers(
+ SourceLocation PointOfInstantiation,
+ ClassTemplateSpecializationDecl *ClassTemplateSpec);
+
+ NestedNameSpecifier *
+ InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,
+ SourceRange Range,
+ const TemplateArgumentList &TemplateArgs);
+
+ TemplateName
+ InstantiateTemplateName(TemplateName Name, SourceLocation Loc,
+ const TemplateArgumentList &TemplateArgs);
+
+ void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
+ FunctionDecl *Function);
+ void InstantiateVariableDefinition(VarDecl *Var);
+
+ NamedDecl *InstantiateCurrentDeclRef(NamedDecl *D);
+
+ // Simple function for cloning expressions.
+ template<typename T>
+ OwningExprResult Clone(T *E) {
+ assert(!E->isValueDependent() && !E->isTypeDependent() &&
+ "expression is value or type dependent!");
+ return Owned(E->Clone(Context));
+ }
+
+ // Objective-C declarations.
+ virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLoc,
+ IdentifierInfo *SuperName,
+ SourceLocation SuperLoc,
+ const DeclPtrTy *ProtoRefs,
+ unsigned NumProtoRefs,
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList);
+
+ virtual DeclPtrTy ActOnCompatiblityAlias(
+ SourceLocation AtCompatibilityAliasLoc,
+ IdentifierInfo *AliasName, SourceLocation AliasLocation,
+ IdentifierInfo *ClassName, SourceLocation ClassLocation);
+
+ void CheckForwardProtocolDeclarationForCircularDependency(
+ IdentifierInfo *PName,
+ SourceLocation &PLoc, SourceLocation PrevLoc,
+ const ObjCList<ObjCProtocolDecl> &PList);
+
+ virtual DeclPtrTy ActOnStartProtocolInterface(
+ SourceLocation AtProtoInterfaceLoc,
+ IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc,
+ const DeclPtrTy *ProtoRefNames, unsigned NumProtoRefs,
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList);
+
+ virtual DeclPtrTy ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLoc,
+ IdentifierInfo *CategoryName,
+ SourceLocation CategoryLoc,
+ const DeclPtrTy *ProtoRefs,
+ unsigned NumProtoRefs,
+ SourceLocation EndProtoLoc);
+
+ virtual DeclPtrTy ActOnStartClassImplementation(
+ SourceLocation AtClassImplLoc,
+ IdentifierInfo *ClassName, SourceLocation ClassLoc,
+ IdentifierInfo *SuperClassname,
+ SourceLocation SuperClassLoc);
+
+ virtual DeclPtrTy ActOnStartCategoryImplementation(
+ SourceLocation AtCatImplLoc,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLoc,
+ IdentifierInfo *CatName,
+ SourceLocation CatLoc);
+
+ virtual DeclPtrTy ActOnForwardClassDeclaration(SourceLocation Loc,
+ IdentifierInfo **IdentList,
+ unsigned NumElts);
+
+ virtual DeclPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
+ const IdentifierLocPair *IdentList,
+ unsigned NumElts,
+ AttributeList *attrList);
+
+ virtual void FindProtocolDeclaration(bool WarnOnDeclarations,
+ const IdentifierLocPair *ProtocolId,
+ unsigned NumProtocols,
+ llvm::SmallVectorImpl<DeclPtrTy> &Protocols);
+
+ /// Ensure attributes are consistent with type.
+ /// \param [in, out] Attributes The attributes to check; they will
+ /// be modified to be consistent with \arg PropertyTy.
+ void CheckObjCPropertyAttributes(QualType PropertyTy,
+ SourceLocation Loc,
+ unsigned &Attributes);
+ void ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCContainerDecl *DC);
+ void DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
+ ObjCPropertyDecl *SuperProperty,
+ const IdentifierInfo *Name);
+ void ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl);
+
+ void MergeProtocolPropertiesIntoClass(Decl *CDecl,
+ DeclPtrTy MergeProtocols);
+
+ void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
+ ObjCInterfaceDecl *ID);
+
+ void MergeOneProtocolPropertiesIntoClass(Decl *CDecl,
+ ObjCProtocolDecl *PDecl);
+
+ virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
+ DeclPtrTy *allMethods = 0, unsigned allNum = 0,
+ DeclPtrTy *allProperties = 0, unsigned pNum = 0,
+ DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0);
+
+ virtual DeclPtrTy ActOnProperty(Scope *S, SourceLocation AtLoc,
+ FieldDeclarator &FD, ObjCDeclSpec &ODS,
+ Selector GetterSel, Selector SetterSel,
+ DeclPtrTy ClassCategory,
+ bool *OverridingProperty,
+ tok::ObjCKeywordKind MethodImplKind);
+
+ virtual DeclPtrTy ActOnPropertyImplDecl(SourceLocation AtLoc,
+ SourceLocation PropertyLoc,
+ bool ImplKind,DeclPtrTy ClassImplDecl,
+ IdentifierInfo *PropertyId,
+ IdentifierInfo *PropertyIvar);
+
+ virtual DeclPtrTy ActOnMethodDeclaration(
+ SourceLocation BeginLoc, // location of the + or -.
+ SourceLocation EndLoc, // location of the ; or {.
+ tok::TokenKind MethodType,
+ DeclPtrTy ClassDecl, ObjCDeclSpec &ReturnQT, TypeTy *ReturnType,
+ Selector Sel,
+ // optional arguments. The number of types/arguments is obtained
+ // from the Sel.getNumArgs().
+ ObjCArgInfo *ArgInfo,
+ llvm::SmallVectorImpl<Declarator> &Cdecls,
+ AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind,
+ bool isVariadic = false);
+
+ // Helper method for ActOnClassMethod/ActOnInstanceMethod.
+ // Will search "local" class/category implementations for a method decl.
+ // Will also search in class's root looking for instance method.
+ // Returns 0 if no method is found.
+ ObjCMethodDecl *LookupPrivateClassMethod(Selector Sel,
+ ObjCInterfaceDecl *CDecl);
+ ObjCMethodDecl *LookupPrivateInstanceMethod(Selector Sel,
+ ObjCInterfaceDecl *ClassDecl);
+
+ virtual OwningExprResult ActOnClassPropertyRefExpr(
+ IdentifierInfo &receiverName,
+ IdentifierInfo &propertyName,
+ SourceLocation &receiverNameLoc,
+ SourceLocation &propertyNameLoc);
+
+ // ActOnClassMessage - used for both unary and keyword messages.
+ // ArgExprs is optional - if it is present, the number of expressions
+ // is obtained from NumArgs.
+ virtual ExprResult ActOnClassMessage(
+ Scope *S,
+ IdentifierInfo *receivingClassName, Selector Sel, SourceLocation lbrac,
+ SourceLocation receiverLoc, SourceLocation selectorLoc,SourceLocation rbrac,
+ ExprTy **ArgExprs, unsigned NumArgs);
+
+ // ActOnInstanceMessage - used for both unary and keyword messages.
+ // ArgExprs is optional - if it is present, the number of expressions
+ // is obtained from NumArgs.
+ virtual ExprResult ActOnInstanceMessage(
+ ExprTy *receiver, Selector Sel,
+ SourceLocation lbrac, SourceLocation receiverLoc, SourceLocation rbrac,
+ ExprTy **ArgExprs, unsigned NumArgs);
+
+ /// ActOnPragmaPack - Called on well formed #pragma pack(...).
+ virtual void ActOnPragmaPack(PragmaPackKind Kind,
+ IdentifierInfo *Name,
+ ExprTy *Alignment,
+ SourceLocation PragmaLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc);
+
+ /// ActOnPragmaUnused - Called on well-formed '#pragma unused'.
+ virtual void ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs,
+ SourceLocation PragmaLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc);
+
+ /// getPragmaPackAlignment() - Return the current alignment as specified by
+ /// the current #pragma pack directive, or 0 if none is currently active.
+ unsigned getPragmaPackAlignment() const;
+
+ /// FreePackedContext - Deallocate and null out PackContext.
+ void FreePackedContext();
+
+ /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit
+ /// cast. If there is already an implicit cast, merge into the existing one.
+ /// If isLvalue, the result of the cast is an lvalue.
+ void ImpCastExprToType(Expr *&Expr, QualType Type, bool isLvalue = false);
+
+ // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts
+ // functions and arrays to their respective pointers (C99 6.3.2.1).
+ Expr *UsualUnaryConversions(Expr *&expr);
+
+ // DefaultFunctionArrayConversion - converts functions and arrays
+ // to their respective pointers (C99 6.3.2.1).
+ void DefaultFunctionArrayConversion(Expr *&expr);
+
+ // DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
+ // do not have a prototype. Integer promotions are performed on each
+ // argument, and arguments that have type float are promoted to double.
+ void DefaultArgumentPromotion(Expr *&Expr);
+
+ // Used for emitting the right warning by DefaultVariadicArgumentPromotion
+ enum VariadicCallType {
+ VariadicFunction,
+ VariadicBlock,
+ VariadicMethod
+ };
+
+ // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
+ // will warn if the resulting type is not a POD type.
+ bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT);
+
+ // UsualArithmeticConversions - performs the UsualUnaryConversions on it's
+ // operands and then handles various conversions that are common to binary
+ // operators (C99 6.3.1.8). If both operands aren't arithmetic, this
+ // routine returns the first non-arithmetic type found. The client is
+ // responsible for emitting appropriate error diagnostics.
+ QualType UsualArithmeticConversions(Expr *&lExpr, Expr *&rExpr,
+ bool isCompAssign = false);
+
+ /// UsualArithmeticConversionsType - handles the various conversions
+ /// that are common to binary operators (C99 6.3.1.8, C++ [expr]p9)
+ /// and returns the result type of that conversion.
+ QualType UsualArithmeticConversionsType(QualType lhs, QualType rhs);
+
+
+ /// AssignConvertType - All of the 'assignment' semantic checks return this
+ /// enum to indicate whether the assignment was allowed. These checks are
+ /// done for simple assignments, as well as initialization, return from
+ /// function, argument passing, etc. The query is phrased in terms of a
+ /// source and destination type.
+ enum AssignConvertType {
+ /// Compatible - the types are compatible according to the standard.
+ Compatible,
+
+ /// PointerToInt - The assignment converts a pointer to an int, which we
+ /// accept as an extension.
+ PointerToInt,
+
+ /// IntToPointer - The assignment converts an int to a pointer, which we
+ /// accept as an extension.
+ IntToPointer,
+
+ /// FunctionVoidPointer - The assignment is between a function pointer and
+ /// void*, which the standard doesn't allow, but we accept as an extension.
+ FunctionVoidPointer,
+
+ /// IncompatiblePointer - The assignment is between two pointers types that
+ /// are not compatible, but we accept them as an extension.
+ IncompatiblePointer,
+
+ /// IncompatiblePointer - The assignment is between two pointers types which
+ /// point to integers which have a different sign, but are otherwise identical.
+ /// This is a subset of the above, but broken out because it's by far the most
+ /// common case of incompatible pointers.
+ IncompatiblePointerSign,
+
+ /// CompatiblePointerDiscardsQualifiers - The assignment discards
+ /// c/v/r qualifiers, which we accept as an extension.
+ CompatiblePointerDiscardsQualifiers,
+
+ /// IncompatibleVectors - The assignment is between two vector types that
+ /// have the same size, which we accept as an extension.
+ IncompatibleVectors,
+
+ /// IntToBlockPointer - The assignment converts an int to a block
+ /// pointer. We disallow this.
+ IntToBlockPointer,
+
+ /// IncompatibleBlockPointer - The assignment is between two block
+ /// pointers types that are not compatible.
+ IncompatibleBlockPointer,
+
+ /// IncompatibleObjCQualifiedId - The assignment is between a qualified
+ /// id type and something else (that is incompatible with it). For example,
+ /// "id <XXX>" = "Foo *", where "Foo *" doesn't implement the XXX protocol.
+ IncompatibleObjCQualifiedId,
+
+ /// Incompatible - We reject this conversion outright, it is invalid to
+ /// represent it in the AST.
+ Incompatible
+ };
+
+ /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the
+ /// assignment conversion type specified by ConvTy. This returns true if the
+ /// conversion was invalid or false if the conversion was accepted.
+ bool DiagnoseAssignmentResult(AssignConvertType ConvTy,
+ SourceLocation Loc,
+ QualType DstType, QualType SrcType,
+ Expr *SrcExpr, const char *Flavor);
+
+ /// CheckAssignmentConstraints - Perform type checking for assignment,
+ /// argument passing, variable initialization, and function return values.
+ /// This routine is only used by the following two methods. C99 6.5.16.
+ AssignConvertType CheckAssignmentConstraints(QualType lhs, QualType rhs);
+
+ // CheckSingleAssignmentConstraints - Currently used by
+ // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking,
+ // this routine performs the default function/array converions.
+ AssignConvertType CheckSingleAssignmentConstraints(QualType lhs,
+ Expr *&rExpr);
+
+ // \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,
+ Expr *&rExpr);
+
+ // Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1)
+ AssignConvertType CheckPointerTypesForAssignment(QualType lhsType,
+ QualType rhsType);
+
+ // Helper function for CheckAssignmentConstraints involving two
+ // block pointer types.
+ AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType,
+ QualType rhsType);
+
+ bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType);
+
+ bool PerformImplicitConversion(Expr *&From, QualType ToType,
+ const char *Flavor,
+ bool AllowExplicit = false,
+ bool Elidable = false);
+ bool PerformImplicitConversion(Expr *&From, QualType ToType,
+ const ImplicitConversionSequence& ICS,
+ const char *Flavor);
+ bool PerformImplicitConversion(Expr *&From, QualType ToType,
+ const StandardConversionSequence& SCS,
+ const char *Flavor);
+
+ /// the following "Check" methods will return a valid/converted QualType
+ /// or a null QualType (indicating an error diagnostic was issued).
+
+ /// type checking binary operators (subroutines of CreateBuiltinBinOp).
+ QualType InvalidOperands(SourceLocation l, Expr *&lex, Expr *&rex);
+ QualType CheckPointerToMemberOperands( // C++ 5.5
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isIndirect);
+ QualType CheckMultiplyDivideOperands( // C99 6.5.5
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ QualType CheckRemainderOperands( // C99 6.5.5
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ QualType CheckAdditionOperands( // C99 6.5.6
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, QualType* CompLHSTy = 0);
+ QualType CheckSubtractionOperands( // C99 6.5.6
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, QualType* CompLHSTy = 0);
+ QualType CheckShiftOperands( // C99 6.5.7
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ QualType CheckCompareOperands( // C99 6.5.8/9
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, unsigned Opc, bool isRelational);
+ QualType CheckBitwiseOperands( // C99 6.5.[10...12]
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ QualType CheckLogicalOperands( // C99 6.5.[13,14]
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc);
+ // 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, Expr *&rex, SourceLocation OpLoc, QualType convertedType);
+ QualType CheckCommaOperands( // C99 6.5.17
+ Expr *lex, Expr *&rex, SourceLocation OpLoc);
+ QualType CheckConditionalOperands( // C99 6.5.15
+ Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
+ QualType CXXCheckConditionalOperands( // C++ 5.16
+ Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
+ QualType FindCompositePointerType(Expr *&E1, Expr *&E2); // C++ 5.9
+
+ /// type checking for vector binary operators.
+ inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex);
+ inline QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx,
+ SourceLocation l, bool isRel);
+
+ /// type checking unary operators (subroutines of ActOnUnaryOp).
+ /// C99 6.5.3.1, 6.5.3.2, 6.5.3.4
+ QualType CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc,
+ bool isInc);
+ QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc);
+ QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc);
+ QualType CheckRealImagOperand(Expr *&Op, SourceLocation OpLoc, bool isReal);
+
+ /// type checking primary expressions.
+ QualType CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
+ IdentifierInfo &Comp, SourceLocation CmpLoc);
+
+ /// type checking declaration initializers (C99 6.7.8)
+
+ bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType,
+ SourceLocation InitLoc,DeclarationName InitEntity,
+ bool DirectInit);
+ bool CheckInitList(InitListExpr *&InitList, QualType &DeclType);
+ bool CheckForConstantInitializer(Expr *e, QualType t);
+
+ bool CheckValueInitialization(QualType Type, SourceLocation Loc);
+
+ // type checking C++ declaration initializers (C++ [dcl.init]).
+
+ /// ReferenceCompareResult - Expresses the result of comparing two
+ /// types (cv1 T1 and cv2 T2) to determine their compatibility for the
+ /// purposes of initialization by reference (C++ [dcl.init.ref]p4).
+ enum ReferenceCompareResult {
+ /// Ref_Incompatible - The two types are incompatible, so direct
+ /// reference binding is not possible.
+ Ref_Incompatible = 0,
+ /// Ref_Related - The two types are reference-related, which means
+ /// that their unqualified forms (T1 and T2) are either the same
+ /// or T1 is a base class of T2.
+ Ref_Related,
+ /// Ref_Compatible_With_Added_Qualification - The two types are
+ /// reference-compatible with added qualification, meaning that
+ /// they are reference-compatible and the qualifiers on T1 (cv1)
+ /// are greater than the qualifiers on T2 (cv2).
+ Ref_Compatible_With_Added_Qualification,
+ /// Ref_Compatible - The two types are reference-compatible and
+ /// have equivalent qualifiers (cv1 == cv2).
+ Ref_Compatible
+ };
+
+ ReferenceCompareResult CompareReferenceRelationship(QualType T1, QualType T2,
+ bool& DerivedToBase);
+
+ bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType declType,
+ ImplicitConversionSequence *ICS = 0,
+ bool SuppressUserConversions = false,
+ bool AllowExplicit = false,
+ bool ForceRValue = false);
+
+ /// CheckCastTypes - Check type constraints for casting between types.
+ bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr);
+
+ // CheckVectorCast - check type constraints for vectors.
+ // Since vectors are an extension, there are no C standard reference for this.
+ // We allow casting between vectors and integer datatypes of the same size.
+ // returns true if the cast is invalid
+ bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty);
+
+ /// CheckMessageArgumentTypes - Check types in an Obj-C message send.
+ /// \param Method - May be null.
+ /// \param [out] ReturnType - The return type of the send.
+ /// \return true iff there were any incompatible types.
+ bool CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, Selector Sel,
+ ObjCMethodDecl *Method, bool isClassMessage,
+ SourceLocation lbrac, SourceLocation rbrac,
+ QualType &ReturnType);
+
+ /// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid.
+ bool CheckCXXBooleanCondition(Expr *&CondExpr);
+
+ /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
+ /// the specified width and sign. If an overflow occurs, detect it and emit
+ /// the specified diagnostic.
+ void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal,
+ unsigned NewWidth, bool NewSign,
+ SourceLocation Loc, unsigned DiagID);
+
+ bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS,
+ bool ForCompare);
+
+ /// Checks that the Objective-C declaration is declared in the global scope.
+ /// Emits an error and marks the declaration as invalid if it's not declared
+ /// in the global scope.
+ bool CheckObjCDeclScope(Decl *D);
+
+ void InitBuiltinVaListType();
+
+ /// VerifyIntegerConstantExpression - verifies that an expression is an ICE,
+ /// and reports the appropriate diagnostics. Returns false on success.
+ /// Can optionally return the value of the expression.
+ bool VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result = 0);
+
+ /// VerifyBitField - verifies that a bit field expression is an ICE and has
+ /// the correct width, and that the field type is valid.
+ /// Returns false on success.
+ bool VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
+ QualType FieldTy, const Expr *BitWidth);
+
+ //===--------------------------------------------------------------------===//
+ // Extra semantic analysis beyond the C type system
+private:
+ Action::OwningExprResult CheckFunctionCall(FunctionDecl *FDecl,
+ CallExpr *TheCall);
+
+ Action::OwningExprResult CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall);
+ SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL,
+ unsigned ByteNo) const;
+ bool CheckObjCString(Expr *Arg);
+ bool SemaBuiltinVAStart(CallExpr *TheCall);
+ bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
+ bool SemaBuiltinStackAddress(CallExpr *TheCall);
+
+public:
+ // Used by C++ template instantiation.
+ Action::OwningExprResult SemaBuiltinShuffleVector(CallExpr *TheCall);
+
+private:
+ bool SemaBuiltinPrefetch(CallExpr *TheCall);
+ bool SemaBuiltinObjectSize(CallExpr *TheCall);
+ bool SemaBuiltinLongjmp(CallExpr *TheCall);
+ bool SemaBuiltinAtomicOverloaded(CallExpr *TheCall);
+ bool SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
+ bool HasVAListArg, unsigned format_idx,
+ unsigned firstDataArg);
+ void CheckPrintfString(const StringLiteral *FExpr, const Expr *OrigFormatExpr,
+ const CallExpr *TheCall, bool HasVAListArg,
+ unsigned format_idx, unsigned firstDataArg);
+ void CheckNonNullArguments(const NonNullAttr *NonNull,
+ const CallExpr *TheCall);
+ void CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
+ unsigned format_idx, unsigned firstDataArg);
+ void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
+ SourceLocation ReturnLoc);
+ void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
+};
+
+
+//===--------------------------------------------------------------------===//
+// Typed version of Parser::ExprArg (smart pointer for wrapping Expr pointers).
+template <typename T>
+class ExprOwningPtr : public Action::ExprArg {
+public:
+ ExprOwningPtr(Sema *S, T *expr) : Action::ExprArg(*S, expr) {}
+
+ void reset(T* p) { Action::ExprArg::operator=(p); }
+ T* get() const { return static_cast<T*>(Action::ExprArg::get()); }
+ T* take() { return static_cast<T*>(Action::ExprArg::take()); }
+ T* release() { return take(); }
+
+ T& operator*() const { return *get(); }
+ T* operator->() const { return get(); }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
new file mode 100644
index 000000000000..bae69ac6dc74
--- /dev/null
+++ b/lib/Sema/SemaAccess.cpp
@@ -0,0 +1,124 @@
+//===---- SemaAccess.cpp - C++ Access Control -------------------*- 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 Sema routines for C++ access control semantics.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SemaInherit.h"
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+using namespace clang;
+
+/// SetMemberAccessSpecifier - Set the access specifier of a member.
+/// Returns true on error (when the previous member decl access specifier
+/// is different from the new member decl access specifier).
+bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
+ NamedDecl *PrevMemberDecl,
+ AccessSpecifier LexicalAS) {
+ if (!PrevMemberDecl) {
+ // Use the lexical access specifier.
+ MemberDecl->setAccess(LexicalAS);
+ return false;
+ }
+
+ // C++ [class.access.spec]p3: When a member is redeclared its access
+ // specifier must be same as its initial declaration.
+ if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) {
+ Diag(MemberDecl->getLocation(),
+ diag::err_class_redeclared_with_different_access)
+ << MemberDecl << LexicalAS;
+ Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
+ << PrevMemberDecl << PrevMemberDecl->getAccess();
+ return true;
+ }
+
+ MemberDecl->setAccess(PrevMemberDecl->getAccess());
+ return false;
+}
+
+/// CheckBaseClassAccess - Check that a derived class can access its base class
+/// and report an error if it can't. [class.access.base]
+bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
+ unsigned InaccessibleBaseID,
+ BasePaths& Paths, SourceLocation AccessLoc,
+ DeclarationName Name) {
+ Base = Context.getCanonicalType(Base).getUnqualifiedType();
+ assert(!Paths.isAmbiguous(Base) &&
+ "Can't check base class access if set of paths is ambiguous");
+ assert(Paths.isRecordingPaths() &&
+ "Can't check base class access without recorded paths");
+
+ if (!getLangOptions().AccessControl)
+ return false;
+
+ const CXXBaseSpecifier *InacessibleBase = 0;
+
+ const CXXRecordDecl* CurrentClassDecl = 0;
+ if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl()))
+ CurrentClassDecl = MD->getParent();
+
+ for (BasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end();
+ Path != PathsEnd; ++Path) {
+
+ bool FoundInaccessibleBase = false;
+
+ for (BasePath::const_iterator Element = Path->begin(),
+ ElementEnd = Path->end(); Element != ElementEnd; ++Element) {
+ const CXXBaseSpecifier *Base = Element->Base;
+
+ switch (Base->getAccessSpecifier()) {
+ default:
+ assert(0 && "invalid access specifier");
+ case AS_public:
+ // Nothing to do.
+ break;
+ case AS_private:
+ // FIXME: Check if the current function/class is a friend.
+ if (CurrentClassDecl != Element->Class)
+ FoundInaccessibleBase = true;
+ break;
+ case AS_protected:
+ // FIXME: Implement
+ break;
+ }
+
+ if (FoundInaccessibleBase) {
+ InacessibleBase = Base;
+ break;
+ }
+ }
+
+ if (!FoundInaccessibleBase) {
+ // We found a path to the base, our work here is done.
+ InacessibleBase = 0;
+ break;
+ }
+ }
+
+ if (InacessibleBase) {
+ Diag(AccessLoc, InaccessibleBaseID)
+ << Derived << Base << Name;
+
+ AccessSpecifier AS = InacessibleBase->getAccessSpecifierAsWritten();
+
+ // If there's no written access specifier, then the inheritance specifier
+ // is implicitly private.
+ if (AS == AS_none)
+ Diag(InacessibleBase->getSourceRange().getBegin(),
+ diag::note_inheritance_implicitly_private_here);
+ else
+ Diag(InacessibleBase->getSourceRange().getBegin(),
+ diag::note_inheritance_specifier_here) << AS;
+
+ return true;
+ }
+
+ return false;
+}
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
new file mode 100644
index 000000000000..1bf8444c42b7
--- /dev/null
+++ b/lib/Sema/SemaAttr.cpp
@@ -0,0 +1,211 @@
+//===--- SemaAttr.cpp - Semantic Analysis for Attributes ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for non-trivial attributes and
+// pragmas.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/Expr.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Pragma Packed
+//===----------------------------------------------------------------------===//
+
+namespace {
+ /// PragmaPackStack - Simple class to wrap the stack used by #pragma
+ /// pack.
+ class PragmaPackStack {
+ typedef std::vector< std::pair<unsigned, IdentifierInfo*> > stack_ty;
+
+ /// Alignment - The current user specified alignment.
+ unsigned Alignment;
+
+ /// Stack - Entries in the #pragma pack stack, consisting of saved
+ /// alignments and optional names.
+ stack_ty Stack;
+
+ public:
+ PragmaPackStack() : Alignment(0) {}
+
+ void setAlignment(unsigned A) { Alignment = A; }
+ unsigned getAlignment() { return Alignment; }
+
+ /// push - Push the current alignment onto the stack, optionally
+ /// using the given \arg Name for the record, if non-zero.
+ void push(IdentifierInfo *Name) {
+ Stack.push_back(std::make_pair(Alignment, Name));
+ }
+
+ /// pop - Pop a record from the stack and restore the current
+ /// alignment to the previous value. If \arg Name is non-zero then
+ /// the first such named record is popped, otherwise the top record
+ /// is popped. Returns true if the pop succeeded.
+ bool pop(IdentifierInfo *Name);
+ };
+} // end anonymous namespace.
+
+bool PragmaPackStack::pop(IdentifierInfo *Name) {
+ if (Stack.empty())
+ return false;
+
+ // If name is empty just pop top.
+ if (!Name) {
+ Alignment = Stack.back().first;
+ Stack.pop_back();
+ return true;
+ }
+
+ // Otherwise, find the named record.
+ for (unsigned i = Stack.size(); i != 0; ) {
+ --i;
+ if (Stack[i].second == Name) {
+ // Found it, pop up to and including this record.
+ Alignment = Stack[i].first;
+ Stack.erase(Stack.begin() + i, Stack.end());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/// FreePackedContext - Deallocate and null out PackContext.
+void Sema::FreePackedContext() {
+ delete static_cast<PragmaPackStack*>(PackContext);
+ PackContext = 0;
+}
+
+/// getPragmaPackAlignment() - Return the current alignment as specified by
+/// the current #pragma pack directive, or 0 if none is currently active.
+unsigned Sema::getPragmaPackAlignment() const {
+ if (PackContext)
+ return static_cast<PragmaPackStack*>(PackContext)->getAlignment();
+ return 0;
+}
+
+void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
+ ExprTy *alignment, SourceLocation PragmaLoc,
+ SourceLocation LParenLoc, SourceLocation RParenLoc) {
+ Expr *Alignment = static_cast<Expr *>(alignment);
+
+ // If specified then alignment must be a "small" power of two.
+ unsigned AlignmentVal = 0;
+ if (Alignment) {
+ llvm::APSInt Val;
+
+ // pack(0) is like pack(), which just works out since that is what
+ // we use 0 for in PackAttr.
+ if (!Alignment->isIntegerConstantExpr(Val, Context) ||
+ !(Val == 0 || Val.isPowerOf2()) ||
+ Val.getZExtValue() > 16) {
+ Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment);
+ Alignment->Destroy(Context);
+ return; // Ignore
+ }
+
+ AlignmentVal = (unsigned) Val.getZExtValue();
+ }
+
+ if (PackContext == 0)
+ PackContext = new PragmaPackStack();
+
+ PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
+
+ switch (Kind) {
+ case Action::PPK_Default: // pack([n])
+ Context->setAlignment(AlignmentVal);
+ break;
+
+ case Action::PPK_Show: // pack(show)
+ // Show the current alignment, making sure to show the right value
+ // for the default.
+ AlignmentVal = Context->getAlignment();
+ // FIXME: This should come from the target.
+ if (AlignmentVal == 0)
+ AlignmentVal = 8;
+ Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal;
+ break;
+
+ case Action::PPK_Push: // pack(push [, id] [, [n])
+ Context->push(Name);
+ // Set the new alignment if specified.
+ if (Alignment)
+ Context->setAlignment(AlignmentVal);
+ break;
+
+ case Action::PPK_Pop: // pack(pop [, id] [, n])
+ // MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack:
+ // "#pragma pack(pop, identifier, n) is undefined"
+ if (Alignment && Name)
+ Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifer_and_alignment);
+
+ // Do the pop.
+ if (!Context->pop(Name)) {
+ // If a name was specified then failure indicates the name
+ // wasn't found. Otherwise failure indicates the stack was
+ // empty.
+ Diag(PragmaLoc, diag::warn_pragma_pack_pop_failed)
+ << (Name ? "no record matching name" : "stack empty");
+
+ // FIXME: Warn about popping named records as MSVC does.
+ } else {
+ // Pop succeeded, set the new alignment if specified.
+ if (Alignment)
+ Context->setAlignment(AlignmentVal);
+ }
+ break;
+
+ default:
+ assert(0 && "Invalid #pragma pack kind.");
+ }
+}
+
+void Sema::ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs,
+ SourceLocation PragmaLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+
+ // Verify that all of the expressions are valid before
+ // modifying the attributes of any referenced decl.
+ Expr *ErrorExpr = 0;
+
+ for (unsigned i = 0; i < NumExprs; ++i) {
+ Expr *Ex = (Expr*) Exprs[i];
+ if (!isa<DeclRefExpr>(Ex)) {
+ ErrorExpr = Ex;
+ break;
+ }
+
+ Decl *d = cast<DeclRefExpr>(Ex)->getDecl();;
+
+ if (!isa<VarDecl>(d) || !cast<VarDecl>(d)->hasLocalStorage()) {
+ ErrorExpr = Ex;
+ break;
+ }
+ }
+
+ // Delete the expressions if we encountered any error.
+ if (ErrorExpr) {
+ Diag(ErrorExpr->getLocStart(), diag::warn_pragma_unused_expected_localvar);
+ for (unsigned i = 0; i < NumExprs; ++i)
+ ((Expr*) Exprs[i])->Destroy(Context);
+ return;
+ }
+
+ // Otherwise, add the 'unused' attribute to each referenced declaration.
+ for (unsigned i = 0; i < NumExprs; ++i) {
+ DeclRefExpr *DR = (DeclRefExpr*) Exprs[i];
+ DR->getDecl()->addAttr(::new (Context) UnusedAttr());
+ DR->Destroy(Context);
+ }
+}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
new file mode 100644
index 000000000000..11ac0bd30056
--- /dev/null
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -0,0 +1,312 @@
+//===--- SemaCXXScopeSpec.cpp - Semantic Analysis for C++ scope specifiers-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements C++ semantic analysis for scope specifiers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/Parse/DeclSpec.h"
+#include "llvm/ADT/STLExtras.h"
+using namespace clang;
+
+/// \brief Compute the DeclContext that is associated with the given
+/// scope specifier.
+DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) {
+ if (!SS.isSet() || SS.isInvalid())
+ return 0;
+
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ if (NNS->isDependent()) {
+ // If this nested-name-specifier refers to the current
+ // instantiation, return its DeclContext.
+ if (CXXRecordDecl *Record = getCurrentInstantiationOf(NNS))
+ return Record;
+ else
+ return 0;
+ }
+
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ assert(false && "Dependent nested-name-specifier has no DeclContext");
+ break;
+
+ case NestedNameSpecifier::Namespace:
+ return NNS->getAsNamespace();
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ const TagType *Tag = NNS->getAsType()->getAsTagType();
+ assert(Tag && "Non-tag type in nested-name-specifier");
+ return Tag->getDecl();
+ } break;
+
+ case NestedNameSpecifier::Global:
+ return Context.getTranslationUnitDecl();
+ }
+
+ // Required to silence a GCC warning.
+ return 0;
+}
+
+bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) {
+ if (!SS.isSet() || SS.isInvalid())
+ return false;
+
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ return NNS->isDependent();
+}
+
+// \brief Determine whether this C++ scope specifier refers to an
+// unknown specialization, i.e., a dependent type that is not the
+// current instantiation.
+bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) {
+ if (!isDependentScopeSpecifier(SS))
+ return false;
+
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ return getCurrentInstantiationOf(NNS) == 0;
+}
+
+/// \brief If the given nested name specifier refers to the current
+/// instantiation, return the declaration that corresponds to that
+/// current instantiation (C++0x [temp.dep.type]p1).
+///
+/// \param NNS a dependent nested name specifier.
+CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
+ assert(getLangOptions().CPlusPlus && "Only callable in C++");
+ assert(NNS->isDependent() && "Only dependent nested-name-specifier allowed");
+
+ QualType T = QualType(NNS->getAsType(), 0);
+ // If the nested name specifier does not refer to a type, then it
+ // does not refer to the current instantiation.
+ if (T.isNull())
+ return 0;
+
+ T = Context.getCanonicalType(T);
+
+ for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) {
+ // If we've hit a namespace or the global scope, then the
+ // nested-name-specifier can't refer to the current instantiation.
+ if (Ctx->isFileContext())
+ return 0;
+
+ // Skip non-class contexts.
+ CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx);
+ if (!Record)
+ continue;
+
+ // If this record type is not dependent,
+ if (!Record->isDependentType())
+ return 0;
+
+ // C++ [temp.dep.type]p1:
+ //
+ // In the definition of a class template, a nested class of a
+ // class template, a member of a class template, or a member of a
+ // nested class of a class template, a name refers to the current
+ // instantiation if it is
+ // -- the injected-class-name (9) of the class template or
+ // nested class,
+ // -- in the definition of a primary class template, the name
+ // of the class template followed by the template argument
+ // list of the primary template (as described below)
+ // enclosed in <>,
+ // -- in the definition of a nested class of a class template,
+ // the name of the nested class referenced as a member of
+ // the current instantiation, or
+ // -- in the definition of a partial specialization, the name
+ // of the class template followed by the template argument
+ // list of the partial specialization enclosed in <>. If
+ // the nth template parameter is a parameter pack, the nth
+ // template argument is a pack expansion (14.6.3) whose
+ // pattern is the name of the parameter pack. (FIXME)
+ //
+ // All of these options come down to having the
+ // nested-name-specifier type that is equivalent to the
+ // injected-class-name of one of the types that is currently in
+ // our context.
+ if (Context.getTypeDeclType(Record) == T)
+ return Record;
+
+ if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) {
+ QualType InjectedClassName
+ = Template->getInjectedClassNameType(Context);
+ if (T == Context.getCanonicalType(InjectedClassName))
+ return Template->getTemplatedDecl();
+ }
+ }
+
+ return 0;
+}
+
+/// \brief Require that the context specified by SS be complete.
+///
+/// If SS refers to a type, this routine checks whether the type is
+/// complete enough (or can be made complete enough) for name lookup
+/// into the DeclContext. A type that is not yet completed can be
+/// considered "complete enough" if it is a class/struct/union/enum
+/// that is currently being defined. Or, if we have a type that names
+/// a class template specialization that is not a complete type, we
+/// will attempt to instantiate that class template.
+bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
+ if (!SS.isSet() || SS.isInvalid())
+ return false;
+
+ DeclContext *DC = computeDeclContext(SS);
+ if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
+ // If we're currently defining this type, then lookup into the
+ // type is okay: don't complain that it isn't complete yet.
+ const TagType *TagT = Context.getTypeDeclType(Tag)->getAsTagType();
+ if (TagT->isBeingDefined())
+ return false;
+
+ // The type must be complete.
+ return RequireCompleteType(SS.getRange().getBegin(),
+ Context.getTypeDeclType(Tag),
+ diag::err_incomplete_nested_name_spec,
+ SS.getRange());
+ }
+
+ return false;
+}
+
+/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
+/// global scope ('::').
+Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S,
+ SourceLocation CCLoc) {
+ return NestedNameSpecifier::GlobalSpecifier(Context);
+}
+
+/// ActOnCXXNestedNameSpecifier - Called during parsing of a
+/// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
+/// we want to resolve "bar::". 'SS' is empty or the previously parsed
+/// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
+/// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
+/// Returns a CXXScopeTy* object representing the C++ scope.
+Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
+ const CXXScopeSpec &SS,
+ SourceLocation IdLoc,
+ SourceLocation CCLoc,
+ IdentifierInfo &II) {
+ NestedNameSpecifier *Prefix
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+
+ // If the prefix already refers to an unknown specialization, there
+ // is no name lookup to perform. Just build the resulting
+ // nested-name-specifier.
+ if (Prefix && isUnknownSpecialization(SS))
+ return NestedNameSpecifier::Create(Context, Prefix, &II);
+
+ NamedDecl *SD = LookupParsedName(S, &SS, &II, LookupNestedNameSpecifierName);
+
+ if (SD) {
+ if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD))
+ return NestedNameSpecifier::Create(Context, Prefix, Namespace);
+
+ if (TypeDecl *Type = dyn_cast<TypeDecl>(SD)) {
+ // Determine whether we have a class (or, in C++0x, an enum) or
+ // a typedef thereof. If so, build the nested-name-specifier.
+ QualType T = Context.getTypeDeclType(Type);
+ bool AcceptableType = false;
+ if (T->isDependentType())
+ AcceptableType = true;
+ else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+ if (TD->getUnderlyingType()->isRecordType() ||
+ (getLangOptions().CPlusPlus0x &&
+ TD->getUnderlyingType()->isEnumeralType()))
+ AcceptableType = true;
+ } else if (isa<RecordDecl>(Type) ||
+ (getLangOptions().CPlusPlus0x && isa<EnumDecl>(Type)))
+ AcceptableType = true;
+
+ if (AcceptableType)
+ return NestedNameSpecifier::Create(Context, Prefix, false,
+ T.getTypePtr());
+ }
+
+ if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD))
+ return NestedNameSpecifier::Create(Context, Prefix,
+ Alias->getNamespace());
+
+ // Fall through to produce an error: we found something that isn't
+ // a class or a namespace.
+ }
+
+ // If we didn't find anything during our lookup, try again with
+ // ordinary name lookup, which can help us produce better error
+ // messages.
+ if (!SD)
+ SD = LookupParsedName(S, &SS, &II, LookupOrdinaryName);
+ unsigned DiagID;
+ if (SD)
+ DiagID = diag::err_expected_class_or_namespace;
+ else if (SS.isSet())
+ DiagID = diag::err_typecheck_no_member;
+ else
+ DiagID = diag::err_undeclared_var_use;
+
+ if (SS.isSet())
+ Diag(IdLoc, DiagID) << &II << SS.getRange();
+ else
+ Diag(IdLoc, DiagID) << &II;
+
+ return 0;
+}
+
+Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
+ const CXXScopeSpec &SS,
+ TypeTy *Ty,
+ SourceRange TypeRange,
+ SourceLocation CCLoc) {
+ NestedNameSpecifier *Prefix
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ QualType T = QualType::getFromOpaquePtr(Ty);
+ return NestedNameSpecifier::Create(Context, Prefix, /*FIXME:*/false,
+ T.getTypePtr());
+}
+
+/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
+/// scope or nested-name-specifier) is parsed, part of a declarator-id.
+/// After this method is called, according to [C++ 3.4.3p3], names should be
+/// looked up in the declarator-id's scope, until the declarator is parsed and
+/// ActOnCXXExitDeclaratorScope is called.
+/// The 'SS' should be a non-empty valid CXXScopeSpec.
+void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
+ assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
+ assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?");
+ PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity());
+ CurContext = computeDeclContext(SS);
+ assert(CurContext && "No context?");
+ S->setEntity(CurContext);
+}
+
+/// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
+/// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same
+/// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well.
+/// Used to indicate that names should revert to being looked up in the
+/// defining scope.
+void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
+ assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
+ assert(S->getEntity() == computeDeclContext(SS) && "Context imbalance!");
+ S->setEntity(PreDeclaratorDC);
+ PreDeclaratorDC = 0;
+
+ // Reset CurContext to the nearest enclosing context.
+ while (!S->getEntity() && S->getParent())
+ S = S->getParent();
+ CurContext = static_cast<DeclContext*>(S->getEntity());
+ assert(CurContext && "No context?");
+}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
new file mode 100644
index 000000000000..4856e7fd2164
--- /dev/null
+++ b/lib/Sema/SemaChecking.cpp
@@ -0,0 +1,1449 @@
+//===--- SemaChecking.cpp - Extra Semantic Checking -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements extra semantic analysis beyond what is enforced
+// by the C type system.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Lex/Preprocessor.h"
+#include <limits>
+using namespace clang;
+
+/// getLocationOfStringLiteralByte - Return a source location that points to the
+/// specified byte of the specified string literal.
+///
+/// Strings are amazingly complex. They can be formed from multiple tokens and
+/// can have escape sequences in them in addition to the usual trigraph and
+/// escaped newline business. This routine handles this complexity.
+///
+SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
+ unsigned ByteNo) const {
+ assert(!SL->isWide() && "This doesn't work for wide strings yet");
+
+ // 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;
+ while (1) {
+ assert(TokNo < SL->getNumConcatenated() && "Invalid byte number!");
+ SourceLocation StrTokLoc = SL->getStrTokenLoc(TokNo);
+
+ // Get the spelling of the string so that we can get the data that makes up
+ // the string literal, not the identifier for the macro it is potentially
+ // expanded through.
+ SourceLocation StrTokSpellingLoc = SourceMgr.getSpellingLoc(StrTokLoc);
+
+ // Re-lex the token to get its length and original spelling.
+ std::pair<FileID, unsigned> LocInfo =
+ SourceMgr.getDecomposedLoc(StrTokSpellingLoc);
+ std::pair<const char *,const char *> Buffer =
+ SourceMgr.getBufferData(LocInfo.first);
+ const char *StrData = Buffer.first+LocInfo.second;
+
+ // Create a langops struct and enable trigraphs. This is sufficient for
+ // relexing tokens.
+ LangOptions LangOpts;
+ LangOpts.Trigraphs = true;
+
+ // Create a lexer starting at the beginning of this token.
+ Lexer TheLexer(StrTokSpellingLoc, LangOpts, Buffer.first, StrData,
+ Buffer.second);
+ Token TheTok;
+ TheLexer.LexFromRawLexer(TheTok);
+
+ // Use the StringLiteralParser to compute the length of the string in bytes.
+ StringLiteralParser SLP(&TheTok, 1, PP);
+ unsigned TokNumBytes = SLP.GetStringLength();
+
+ // If the byte is in this token, return the location of the byte.
+ if (ByteNo < TokNumBytes ||
+ (ByteNo == TokNumBytes && TokNo == SL->getNumConcatenated())) {
+ unsigned Offset =
+ StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP);
+
+ // Now that we know the offset of the token in the spelling, use the
+ // preprocessor to get the offset in the original source.
+ return PP.AdvanceToTokenCharacter(StrTokLoc, Offset);
+ }
+
+ // Move to the next string token.
+ ++TokNo;
+ ByteNo -= TokNumBytes;
+ }
+}
+
+
+/// CheckFunctionCall - Check a direct function call for various correctness
+/// and safety properties not strictly enforced by the C type system.
+Action::OwningExprResult
+Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
+ OwningExprResult TheCallResult(Owned(TheCall));
+ // Get the IdentifierInfo* for the called function.
+ IdentifierInfo *FnInfo = FDecl->getIdentifier();
+
+ // None of the checks below are needed for functions that don't have
+ // simple names (e.g., C++ conversion functions).
+ if (!FnInfo)
+ return move(TheCallResult);
+
+ switch (FDecl->getBuiltinID(Context)) {
+ case Builtin::BI__builtin___CFStringMakeConstantString:
+ assert(TheCall->getNumArgs() == 1 &&
+ "Wrong # arguments to builtin CFStringMakeConstantString");
+ if (CheckObjCString(TheCall->getArg(0)))
+ return ExprError();
+ return move(TheCallResult);
+ case Builtin::BI__builtin_stdarg_start:
+ case Builtin::BI__builtin_va_start:
+ if (SemaBuiltinVAStart(TheCall))
+ return ExprError();
+ return move(TheCallResult);
+ case Builtin::BI__builtin_isgreater:
+ case Builtin::BI__builtin_isgreaterequal:
+ case Builtin::BI__builtin_isless:
+ case Builtin::BI__builtin_islessequal:
+ case Builtin::BI__builtin_islessgreater:
+ case Builtin::BI__builtin_isunordered:
+ if (SemaBuiltinUnorderedCompare(TheCall))
+ return ExprError();
+ return move(TheCallResult);
+ case Builtin::BI__builtin_return_address:
+ case Builtin::BI__builtin_frame_address:
+ if (SemaBuiltinStackAddress(TheCall))
+ return ExprError();
+ return move(TheCallResult);
+ case Builtin::BI__builtin_shufflevector:
+ return SemaBuiltinShuffleVector(TheCall);
+ // TheCall will be freed by the smart pointer here, but that's fine, since
+ // SemaBuiltinShuffleVector guts it, but then doesn't release it.
+ case Builtin::BI__builtin_prefetch:
+ if (SemaBuiltinPrefetch(TheCall))
+ return ExprError();
+ return move(TheCallResult);
+ case Builtin::BI__builtin_object_size:
+ if (SemaBuiltinObjectSize(TheCall))
+ return ExprError();
+ return move(TheCallResult);
+ case Builtin::BI__builtin_longjmp:
+ if (SemaBuiltinLongjmp(TheCall))
+ return ExprError();
+ return move(TheCallResult);
+ case Builtin::BI__sync_fetch_and_add:
+ case Builtin::BI__sync_fetch_and_sub:
+ case Builtin::BI__sync_fetch_and_or:
+ case Builtin::BI__sync_fetch_and_and:
+ case Builtin::BI__sync_fetch_and_xor:
+ case Builtin::BI__sync_fetch_and_nand:
+ case Builtin::BI__sync_add_and_fetch:
+ case Builtin::BI__sync_sub_and_fetch:
+ case Builtin::BI__sync_and_and_fetch:
+ case Builtin::BI__sync_or_and_fetch:
+ case Builtin::BI__sync_xor_and_fetch:
+ case Builtin::BI__sync_nand_and_fetch:
+ case Builtin::BI__sync_val_compare_and_swap:
+ case Builtin::BI__sync_bool_compare_and_swap:
+ case Builtin::BI__sync_lock_test_and_set:
+ case Builtin::BI__sync_lock_release:
+ if (SemaBuiltinAtomicOverloaded(TheCall))
+ return ExprError();
+ return move(TheCallResult);
+ }
+
+ // FIXME: This mechanism should be abstracted to be less fragile and
+ // more efficient. For example, just map function ids to custom
+ // handlers.
+
+ // Printf checking.
+ if (const FormatAttr *Format = FDecl->getAttr<FormatAttr>()) {
+ if (Format->getType() == "printf") {
+ bool HasVAListArg = Format->getFirstArg() == 0;
+ if (!HasVAListArg) {
+ if (const FunctionProtoType *Proto
+ = FDecl->getType()->getAsFunctionProtoType())
+ HasVAListArg = !Proto->isVariadic();
+ }
+ CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1,
+ HasVAListArg ? 0 : Format->getFirstArg() - 1);
+ }
+ }
+ for (const Attr *attr = FDecl->getAttrs(); attr; attr = attr->getNext()) {
+ if (const NonNullAttr *NonNull = dyn_cast<NonNullAttr>(attr))
+ CheckNonNullArguments(NonNull, TheCall);
+ }
+
+ return move(TheCallResult);
+}
+
+Action::OwningExprResult
+Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
+
+ OwningExprResult TheCallResult(Owned(TheCall));
+ // Printf checking.
+ const FormatAttr *Format = NDecl->getAttr<FormatAttr>();
+ if (!Format)
+ return move(TheCallResult);
+ const VarDecl *V = dyn_cast<VarDecl>(NDecl);
+ if (!V)
+ return move(TheCallResult);
+ QualType Ty = V->getType();
+ if (!Ty->isBlockPointerType())
+ return move(TheCallResult);
+ if (Format->getType() == "printf") {
+ bool HasVAListArg = Format->getFirstArg() == 0;
+ if (!HasVAListArg) {
+ const FunctionType *FT =
+ Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType();
+ if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
+ HasVAListArg = !Proto->isVariadic();
+ }
+ CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1,
+ HasVAListArg ? 0 : Format->getFirstArg() - 1);
+ }
+ return move(TheCallResult);
+}
+
+/// 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
+/// promoted the types of arguments because all of these calls are prototyped as
+/// void(...).
+///
+/// This function goes through and does final semantic checking for these
+/// builtins,
+bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
+ DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+ FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl());
+
+ // Ensure that we have at least one argument to do type inference from.
+ if (TheCall->getNumArgs() < 1)
+ return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
+ << 0 << TheCall->getCallee()->getSourceRange();
+
+ // Inspect the first argument of the atomic builtin. This should always be
+ // a pointer type, whose element is an integral scalar or pointer type.
+ // Because it is a pointer type, we don't have to worry about any implicit
+ // casts here.
+ Expr *FirstArg = TheCall->getArg(0);
+ if (!FirstArg->getType()->isPointerType())
+ return Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer)
+ << FirstArg->getType() << FirstArg->getSourceRange();
+
+ QualType ValType = FirstArg->getType()->getAsPointerType()->getPointeeType();
+ if (!ValType->isIntegerType() && !ValType->isPointerType() &&
+ !ValType->isBlockPointerType())
+ return Diag(DRE->getLocStart(),
+ diag::err_atomic_builtin_must_be_pointer_intptr)
+ << FirstArg->getType() << FirstArg->getSourceRange();
+
+ // We need to figure out which concrete builtin this maps onto. For example,
+ // __sync_fetch_and_add with a 2 byte object turns into
+ // __sync_fetch_and_add_2.
+#define BUILTIN_ROW(x) \
+ { Builtin::BI##x##_1, Builtin::BI##x##_2, Builtin::BI##x##_4, \
+ Builtin::BI##x##_8, Builtin::BI##x##_16 }
+
+ static const unsigned BuiltinIndices[][5] = {
+ BUILTIN_ROW(__sync_fetch_and_add),
+ BUILTIN_ROW(__sync_fetch_and_sub),
+ BUILTIN_ROW(__sync_fetch_and_or),
+ BUILTIN_ROW(__sync_fetch_and_and),
+ BUILTIN_ROW(__sync_fetch_and_xor),
+ BUILTIN_ROW(__sync_fetch_and_nand),
+
+ BUILTIN_ROW(__sync_add_and_fetch),
+ BUILTIN_ROW(__sync_sub_and_fetch),
+ BUILTIN_ROW(__sync_and_and_fetch),
+ BUILTIN_ROW(__sync_or_and_fetch),
+ BUILTIN_ROW(__sync_xor_and_fetch),
+ BUILTIN_ROW(__sync_nand_and_fetch),
+
+ BUILTIN_ROW(__sync_val_compare_and_swap),
+ BUILTIN_ROW(__sync_bool_compare_and_swap),
+ BUILTIN_ROW(__sync_lock_test_and_set),
+ BUILTIN_ROW(__sync_lock_release)
+ };
+#undef BUILTIN_ROW
+
+ // Determine the index of the size.
+ unsigned SizeIndex;
+ switch (Context.getTypeSize(ValType)/8) {
+ case 1: SizeIndex = 0; break;
+ case 2: SizeIndex = 1; break;
+ case 4: SizeIndex = 2; break;
+ case 8: SizeIndex = 3; break;
+ case 16: SizeIndex = 4; break;
+ default:
+ return Diag(DRE->getLocStart(), diag::err_atomic_builtin_pointer_size)
+ << FirstArg->getType() << FirstArg->getSourceRange();
+ }
+
+ // Each of these builtins has one pointer argument, followed by some number of
+ // values (0, 1 or 2) followed by a potentially empty varags list of stuff
+ // that we ignore. Find out which row of BuiltinIndices to read from as well
+ // as the number of fixed args.
+ unsigned BuiltinID = FDecl->getBuiltinID(Context);
+ unsigned BuiltinIndex, NumFixed = 1;
+ switch (BuiltinID) {
+ default: assert(0 && "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;
+ case Builtin::BI__sync_fetch_and_and: BuiltinIndex = 3; break;
+ case Builtin::BI__sync_fetch_and_xor: BuiltinIndex = 4; break;
+ case Builtin::BI__sync_fetch_and_nand:BuiltinIndex = 5; break;
+
+ case Builtin::BI__sync_add_and_fetch: BuiltinIndex = 6; break;
+ case Builtin::BI__sync_sub_and_fetch: BuiltinIndex = 7; break;
+ case Builtin::BI__sync_and_and_fetch: BuiltinIndex = 8; break;
+ case Builtin::BI__sync_or_and_fetch: BuiltinIndex = 9; break;
+ case Builtin::BI__sync_xor_and_fetch: BuiltinIndex =10; break;
+ case Builtin::BI__sync_nand_and_fetch:BuiltinIndex =11; break;
+
+ case Builtin::BI__sync_val_compare_and_swap:
+ BuiltinIndex = 12;
+ NumFixed = 2;
+ break;
+ case Builtin::BI__sync_bool_compare_and_swap:
+ BuiltinIndex = 13;
+ NumFixed = 2;
+ break;
+ case Builtin::BI__sync_lock_test_and_set: BuiltinIndex = 14; break;
+ case Builtin::BI__sync_lock_release:
+ BuiltinIndex = 15;
+ NumFixed = 0;
+ break;
+ }
+
+ // Now that we know how many fixed arguments we expect, first check that we
+ // have at least that many.
+ if (TheCall->getNumArgs() < 1+NumFixed)
+ return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
+ << 0 << TheCall->getCallee()->getSourceRange();
+
+
+ // Get the decl for the concrete builtin from this, we can tell what the
+ // concrete integer type we should convert to is.
+ unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex];
+ const char *NewBuiltinName = Context.BuiltinInfo.GetName(NewBuiltinID);
+ IdentifierInfo *NewBuiltinII = PP.getIdentifierInfo(NewBuiltinName);
+ FunctionDecl *NewBuiltinDecl =
+ cast<FunctionDecl>(LazilyCreateBuiltin(NewBuiltinII, NewBuiltinID,
+ TUScope, false, DRE->getLocStart()));
+ const FunctionProtoType *BuiltinFT =
+ NewBuiltinDecl->getType()->getAsFunctionProtoType();
+ ValType = BuiltinFT->getArgType(0)->getAsPointerType()->getPointeeType();
+
+ // If the first type needs to be converted (e.g. void** -> int*), do it now.
+ if (BuiltinFT->getArgType(0) != FirstArg->getType()) {
+ ImpCastExprToType(FirstArg, BuiltinFT->getArgType(0), false);
+ TheCall->setArg(0, FirstArg);
+ }
+
+ // Next, walk the valid ones promoting to the right type.
+ for (unsigned i = 0; i != NumFixed; ++i) {
+ Expr *Arg = TheCall->getArg(i+1);
+
+ // If the argument is an implicit cast, then there was a promotion due to
+ // "...", just remove it now.
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
+ Arg = ICE->getSubExpr();
+ ICE->setSubExpr(0);
+ ICE->Destroy(Context);
+ TheCall->setArg(i+1, Arg);
+ }
+
+ // 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.
+ if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg))
+ return true;
+
+ // Okay, we have something that *can* be converted to the right type. Check
+ // to see if there is a potentially weird extension going on here. This can
+ // happen when you do an atomic operation on something like an char* and
+ // 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.
+ ImpCastExprToType(Arg, ValType, false);
+ TheCall->setArg(i+1, Arg);
+ }
+
+ // Switch the DeclRefExpr to refer to the new decl.
+ DRE->setDecl(NewBuiltinDecl);
+ DRE->setType(NewBuiltinDecl->getType());
+
+ // Set the callee in the CallExpr.
+ // FIXME: This leaks the original parens and implicit casts.
+ Expr *PromotedCall = DRE;
+ UsualUnaryConversions(PromotedCall);
+ TheCall->setCallee(PromotedCall);
+
+
+ // Change the result type of the call to match the result type of the decl.
+ TheCall->setType(NewBuiltinDecl->getResultType());
+ return false;
+}
+
+
+/// CheckObjCString - Checks that the argument to the builtin
+/// CFString constructor is correct
+/// FIXME: GCC currently emits the following warning:
+/// "warning: input conversion stopped due to an input byte that does not
+/// belong to the input codeset UTF-8"
+/// Note: It might also make sense to do the UTF-16 conversion here (would
+/// simplify the backend).
+bool Sema::CheckObjCString(Expr *Arg) {
+ Arg = Arg->IgnoreParenCasts();
+ StringLiteral *Literal = dyn_cast<StringLiteral>(Arg);
+
+ if (!Literal || Literal->isWide()) {
+ Diag(Arg->getLocStart(), diag::err_cfstring_literal_not_string_constant)
+ << Arg->getSourceRange();
+ return true;
+ }
+
+ const char *Data = Literal->getStrData();
+ unsigned Length = Literal->getByteLength();
+
+ for (unsigned i = 0; i < Length; ++i) {
+ if (!Data[i]) {
+ Diag(getLocationOfStringLiteralByte(Literal, i),
+ diag::warn_cfstring_literal_contains_nul_character)
+ << Arg->getSourceRange();
+ break;
+ }
+ }
+
+ return false;
+}
+
+/// SemaBuiltinVAStart - Check the arguments to __builtin_va_start for validity.
+/// Emit an error and return true on failure, return false on success.
+bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
+ Expr *Fn = TheCall->getCallee();
+ if (TheCall->getNumArgs() > 2) {
+ Diag(TheCall->getArg(2)->getLocStart(),
+ diag::err_typecheck_call_too_many_args)
+ << 0 /*function call*/ << Fn->getSourceRange()
+ << SourceRange(TheCall->getArg(2)->getLocStart(),
+ (*(TheCall->arg_end()-1))->getLocEnd());
+ return true;
+ }
+
+ if (TheCall->getNumArgs() < 2) {
+ return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
+ << 0 /*function call*/;
+ }
+
+ // Determine whether the current function is variadic or not.
+ bool isVariadic;
+ if (CurBlock)
+ isVariadic = CurBlock->isVariadic;
+ else if (getCurFunctionDecl()) {
+ if (FunctionProtoType* FTP =
+ dyn_cast<FunctionProtoType>(getCurFunctionDecl()->getType()))
+ isVariadic = FTP->isVariadic();
+ else
+ isVariadic = false;
+ } else {
+ isVariadic = getCurMethodDecl()->isVariadic();
+ }
+
+ if (!isVariadic) {
+ Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function);
+ return true;
+ }
+
+ // Verify that the second argument to the builtin is the last argument of the
+ // current function or method.
+ bool SecondArgIsLastNamedArgument = false;
+ const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts();
+
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) {
+ if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) {
+ // FIXME: This isn't correct for methods (results in bogus warning).
+ // Get the last formal in the current function.
+ const ParmVarDecl *LastArg;
+ if (CurBlock)
+ LastArg = *(CurBlock->TheDecl->param_end()-1);
+ else if (FunctionDecl *FD = getCurFunctionDecl())
+ LastArg = *(FD->param_end()-1);
+ else
+ LastArg = *(getCurMethodDecl()->param_end()-1);
+ SecondArgIsLastNamedArgument = PV == LastArg;
+ }
+ }
+
+ if (!SecondArgIsLastNamedArgument)
+ Diag(TheCall->getArg(1)->getLocStart(),
+ diag::warn_second_parameter_of_va_start_not_last_named_argument);
+ return false;
+}
+
+/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isgreater and
+/// friends. This is declared to take (...), so we have to check everything.
+bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
+ if (TheCall->getNumArgs() < 2)
+ return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
+ << 0 /*function call*/;
+ if (TheCall->getNumArgs() > 2)
+ return Diag(TheCall->getArg(2)->getLocStart(),
+ diag::err_typecheck_call_too_many_args)
+ << 0 /*function call*/
+ << SourceRange(TheCall->getArg(2)->getLocStart(),
+ (*(TheCall->arg_end()-1))->getLocEnd());
+
+ Expr *OrigArg0 = TheCall->getArg(0);
+ Expr *OrigArg1 = TheCall->getArg(1);
+
+ // Do standard promotions between the two arguments, returning their common
+ // type.
+ QualType Res = UsualArithmeticConversions(OrigArg0, OrigArg1, false);
+
+ // Make sure any conversions are pushed back into the call; this is
+ // type safe since unordered compare builtins are declared as "_Bool
+ // foo(...)".
+ TheCall->setArg(0, OrigArg0);
+ TheCall->setArg(1, OrigArg1);
+
+ if (OrigArg0->isTypeDependent() || OrigArg1->isTypeDependent())
+ return false;
+
+ // If the common type isn't a real floating type, then the arguments were
+ // invalid for this operation.
+ if (!Res->isRealFloatingType())
+ return Diag(OrigArg0->getLocStart(),
+ diag::err_typecheck_call_invalid_ordered_compare)
+ << OrigArg0->getType() << OrigArg1->getType()
+ << SourceRange(OrigArg0->getLocStart(), OrigArg1->getLocEnd());
+
+ return false;
+}
+
+bool Sema::SemaBuiltinStackAddress(CallExpr *TheCall) {
+ // The signature for these builtins is exact; the only thing we need
+ // to check is that the argument is a constant.
+ SourceLocation Loc;
+ if (!TheCall->getArg(0)->isTypeDependent() &&
+ !TheCall->getArg(0)->isValueDependent() &&
+ !TheCall->getArg(0)->isIntegerConstantExpr(Context, &Loc))
+ return Diag(Loc, diag::err_stack_const_level) << TheCall->getSourceRange();
+
+ return false;
+}
+
+/// SemaBuiltinShuffleVector - Handle __builtin_shufflevector.
+// This is declared to take (...), so we have to check everything.
+Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
+ if (TheCall->getNumArgs() < 3)
+ return ExprError(Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_few_args)
+ << 0 /*function call*/ << TheCall->getSourceRange());
+
+ unsigned numElements = std::numeric_limits<unsigned>::max();
+ if (!TheCall->getArg(0)->isTypeDependent() &&
+ !TheCall->getArg(1)->isTypeDependent()) {
+ QualType FAType = TheCall->getArg(0)->getType();
+ QualType SAType = TheCall->getArg(1)->getType();
+
+ if (!FAType->isVectorType() || !SAType->isVectorType()) {
+ Diag(TheCall->getLocStart(), diag::err_shufflevector_non_vector)
+ << SourceRange(TheCall->getArg(0)->getLocStart(),
+ TheCall->getArg(1)->getLocEnd());
+ return ExprError();
+ }
+
+ if (Context.getCanonicalType(FAType).getUnqualifiedType() !=
+ Context.getCanonicalType(SAType).getUnqualifiedType()) {
+ Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector)
+ << SourceRange(TheCall->getArg(0)->getLocStart(),
+ TheCall->getArg(1)->getLocEnd());
+ return ExprError();
+ }
+
+ numElements = FAType->getAsVectorType()->getNumElements();
+ if (TheCall->getNumArgs() != numElements+2) {
+ if (TheCall->getNumArgs() < numElements+2)
+ return ExprError(Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_few_args)
+ << 0 /*function call*/ << TheCall->getSourceRange());
+ return ExprError(Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_many_args)
+ << 0 /*function call*/ << TheCall->getSourceRange());
+ }
+ }
+
+ for (unsigned i = 2; i < TheCall->getNumArgs(); i++) {
+ if (TheCall->getArg(i)->isTypeDependent() ||
+ TheCall->getArg(i)->isValueDependent())
+ continue;
+
+ llvm::APSInt Result(32);
+ if (!TheCall->getArg(i)->isIntegerConstantExpr(Result, Context))
+ return ExprError(Diag(TheCall->getLocStart(),
+ diag::err_shufflevector_nonconstant_argument)
+ << TheCall->getArg(i)->getSourceRange());
+
+ if (Result.getActiveBits() > 64 || Result.getZExtValue() >= numElements*2)
+ return ExprError(Diag(TheCall->getLocStart(),
+ diag::err_shufflevector_argument_too_large)
+ << TheCall->getArg(i)->getSourceRange());
+ }
+
+ llvm::SmallVector<Expr*, 32> exprs;
+
+ for (unsigned i = 0, e = TheCall->getNumArgs(); i != e; i++) {
+ exprs.push_back(TheCall->getArg(i));
+ TheCall->setArg(i, 0);
+ }
+
+ return Owned(new (Context) ShuffleVectorExpr(exprs.begin(), exprs.size(),
+ exprs[0]->getType(),
+ TheCall->getCallee()->getLocStart(),
+ TheCall->getRParenLoc()));
+}
+
+/// SemaBuiltinPrefetch - Handle __builtin_prefetch.
+// This is declared to take (const void*, ...) and can take two
+// optional constant int args.
+bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
+ unsigned NumArgs = TheCall->getNumArgs();
+
+ if (NumArgs > 3)
+ return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_many_args)
+ << 0 /*function call*/ << TheCall->getSourceRange();
+
+ // Argument 0 is checked for us and the remaining arguments must be
+ // constant integers.
+ for (unsigned i = 1; i != NumArgs; ++i) {
+ Expr *Arg = TheCall->getArg(i);
+ if (Arg->isTypeDependent())
+ continue;
+
+ QualType RWType = Arg->getType();
+
+ const BuiltinType *BT = RWType->getAsBuiltinType();
+ llvm::APSInt Result;
+ if (!BT || BT->getKind() != BuiltinType::Int)
+ return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_argument)
+ << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
+
+ if (Arg->isValueDependent())
+ continue;
+
+ if (!Arg->isIntegerConstantExpr(Result, Context))
+ return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_argument)
+ << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
+
+ // FIXME: gcc issues a warning and rewrites these to 0. These
+ // seems especially odd for the third argument since the default
+ // is 3.
+ if (i == 1) {
+ if (Result.getSExtValue() < 0 || Result.getSExtValue() > 1)
+ return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
+ << "0" << "1" << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
+ } else {
+ if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3)
+ return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
+ << "0" << "3" << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
+ }
+ }
+
+ return false;
+}
+
+/// SemaBuiltinObjectSize - Handle __builtin_object_size(void *ptr,
+/// int type). This simply type checks that type is one of the defined
+/// constants (0-3).
+bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
+ Expr *Arg = TheCall->getArg(1);
+ if (Arg->isTypeDependent())
+ return false;
+
+ QualType ArgType = Arg->getType();
+ const BuiltinType *BT = ArgType->getAsBuiltinType();
+ llvm::APSInt Result(32);
+ if (!BT || BT->getKind() != BuiltinType::Int)
+ return Diag(TheCall->getLocStart(), diag::err_object_size_invalid_argument)
+ << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
+
+ if (Arg->isValueDependent())
+ return false;
+
+ if (!Arg->isIntegerConstantExpr(Result, Context)) {
+ return Diag(TheCall->getLocStart(), diag::err_object_size_invalid_argument)
+ << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
+ }
+
+ if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3) {
+ return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
+ << "0" << "3" << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
+ }
+
+ return false;
+}
+
+/// SemaBuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val).
+/// This checks that val is a constant 1.
+bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
+ Expr *Arg = TheCall->getArg(1);
+ if (Arg->isTypeDependent() || Arg->isValueDependent())
+ return false;
+
+ llvm::APSInt Result(32);
+ if (!Arg->isIntegerConstantExpr(Result, Context) || Result != 1)
+ return Diag(TheCall->getLocStart(), diag::err_builtin_longjmp_invalid_val)
+ << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
+
+ return false;
+}
+
+// Handle i > 1 ? "x" : "y", recursivelly
+bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
+ bool HasVAListArg,
+ unsigned format_idx, unsigned firstDataArg) {
+ if (E->isTypeDependent() || E->isValueDependent())
+ return false;
+
+ switch (E->getStmtClass()) {
+ case Stmt::ConditionalOperatorClass: {
+ const ConditionalOperator *C = cast<ConditionalOperator>(E);
+ return SemaCheckStringLiteral(C->getLHS(), TheCall,
+ HasVAListArg, format_idx, firstDataArg)
+ && SemaCheckStringLiteral(C->getRHS(), TheCall,
+ HasVAListArg, format_idx, firstDataArg);
+ }
+
+ case Stmt::ImplicitCastExprClass: {
+ const ImplicitCastExpr *Expr = cast<ImplicitCastExpr>(E);
+ return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg,
+ format_idx, firstDataArg);
+ }
+
+ case Stmt::ParenExprClass: {
+ const ParenExpr *Expr = cast<ParenExpr>(E);
+ return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg,
+ format_idx, firstDataArg);
+ }
+
+ case Stmt::DeclRefExprClass: {
+ const DeclRefExpr *DR = cast<DeclRefExpr>(E);
+
+ // As an exception, do not flag errors for variables binding to
+ // const string literals.
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ bool isConstant = false;
+ QualType T = DR->getType();
+
+ if (const ArrayType *AT = Context.getAsArrayType(T)) {
+ isConstant = AT->getElementType().isConstant(Context);
+ }
+ else if (const PointerType *PT = T->getAsPointerType()) {
+ isConstant = T.isConstant(Context) &&
+ PT->getPointeeType().isConstant(Context);
+ }
+
+ if (isConstant) {
+ const VarDecl *Def = 0;
+ if (const Expr *Init = VD->getDefinition(Def))
+ return SemaCheckStringLiteral(Init, TheCall,
+ HasVAListArg, format_idx, firstDataArg);
+ }
+ }
+
+ return false;
+ }
+
+ case Stmt::ObjCStringLiteralClass:
+ case Stmt::StringLiteralClass: {
+ const StringLiteral *StrE = NULL;
+
+ if (const ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(E))
+ StrE = ObjCFExpr->getString();
+ else
+ StrE = cast<StringLiteral>(E);
+
+ if (StrE) {
+ CheckPrintfString(StrE, E, TheCall, HasVAListArg, format_idx,
+ firstDataArg);
+ return true;
+ }
+
+ return false;
+ }
+
+ default:
+ return false;
+ }
+}
+
+void
+Sema::CheckNonNullArguments(const NonNullAttr *NonNull, const CallExpr *TheCall)
+{
+ for (NonNullAttr::iterator i = NonNull->begin(), e = NonNull->end();
+ i != e; ++i) {
+ const Expr *ArgExpr = TheCall->getArg(*i);
+ if (ArgExpr->isNullPointerConstant(Context))
+ Diag(TheCall->getCallee()->getLocStart(), diag::warn_null_arg)
+ << ArgExpr->getSourceRange();
+ }
+}
+
+/// CheckPrintfArguments - Check calls to printf (and similar functions) for
+/// correct use of format strings.
+///
+/// HasVAListArg - A predicate indicating whether the printf-like
+/// function is passed an explicit va_arg argument (e.g., vprintf)
+///
+/// format_idx - The index into Args for the format string.
+///
+/// Improper format strings to functions in the printf family can be
+/// the source of bizarre bugs and very serious security holes. A
+/// good source of information is available in the following paper
+/// (which includes additional references):
+///
+/// FormatGuard: Automatic Protection From printf Format String
+/// Vulnerabilities, Proceedings of the 10th USENIX Security Symposium, 2001.
+///
+/// Functionality implemented:
+///
+/// We can statically check the following properties for string
+/// literal format strings for non v.*printf functions (where the
+/// arguments are passed directly):
+//
+/// (1) Are the number of format conversions equal to the number of
+/// data arguments?
+///
+/// (2) Does each format conversion correctly match the type of the
+/// corresponding data argument? (TODO)
+///
+/// Moreover, for all printf functions we can:
+///
+/// (3) Check for a missing format string (when not caught by type checking).
+///
+/// (4) Check for no-operation flags; e.g. using "#" with format
+/// conversion 'c' (TODO)
+///
+/// (5) Check the use of '%n', a major source of security holes.
+///
+/// (6) Check for malformed format conversions that don't specify anything.
+///
+/// (7) Check for empty format strings. e.g: printf("");
+///
+/// (8) Check that the format string is a wide literal.
+///
+/// (9) Also check the arguments of functions with the __format__ attribute.
+/// (TODO).
+///
+/// All of these checks can be done by parsing the format string.
+///
+/// For now, we ONLY do (1), (3), (5), (6), (7), and (8).
+void
+Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
+ unsigned format_idx, unsigned firstDataArg) {
+ const Expr *Fn = TheCall->getCallee();
+
+ // CHECK: printf-like function is called with no format string.
+ if (format_idx >= TheCall->getNumArgs()) {
+ Diag(TheCall->getRParenLoc(), diag::warn_printf_missing_format_string)
+ << Fn->getSourceRange();
+ return;
+ }
+
+ const Expr *OrigFormatExpr = TheCall->getArg(format_idx)->IgnoreParenCasts();
+
+ // CHECK: format string is not a string literal.
+ //
+ // Dynamically generated format strings are difficult to
+ // automatically vet at compile time. Requiring that format strings
+ // are string literals: (1) permits the checking of format strings by
+ // the compiler and thereby (2) can practically remove the source of
+ // many format string exploits.
+
+ // Format string can be either ObjC string (e.g. @"%d") or
+ // C string (e.g. "%d")
+ // ObjC string uses the same format specifiers as C string, so we can use
+ // the same format string checking logic for both ObjC and C strings.
+ if (SemaCheckStringLiteral(OrigFormatExpr, TheCall, HasVAListArg, format_idx,
+ firstDataArg))
+ return; // Literal format string found, check done!
+
+ // For vprintf* functions (i.e., HasVAListArg==true), we add a
+ // special check to see if the format string is a function parameter
+ // of the function calling the printf function. If the function
+ // has an attribute indicating it is a printf-like function, then we
+ // should suppress warnings concerning non-literals being used in a call
+ // to a vprintf function. For example:
+ //
+ // void
+ // logmessage(char const *fmt __attribute__ (format (printf, 1, 2)), ...) {
+ // va_list ap;
+ // va_start(ap, fmt);
+ // vprintf(fmt, ap); // Do NOT emit a warning about "fmt".
+ // ...
+ //
+ //
+ // FIXME: We don't have full attribute support yet, so just check to see
+ // if the argument is a DeclRefExpr that references a parameter. We'll
+ // add proper support for checking the attribute later.
+ if (HasVAListArg)
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OrigFormatExpr))
+ if (isa<ParmVarDecl>(DR->getDecl()))
+ return;
+
+ // If there are no arguments specified, warn with -Wformat-security, otherwise
+ // warn only with -Wformat-nonliteral.
+ if (TheCall->getNumArgs() == format_idx+1)
+ Diag(TheCall->getArg(format_idx)->getLocStart(),
+ diag::warn_printf_nonliteral_noargs)
+ << OrigFormatExpr->getSourceRange();
+ else
+ Diag(TheCall->getArg(format_idx)->getLocStart(),
+ diag::warn_printf_nonliteral)
+ << OrigFormatExpr->getSourceRange();
+}
+
+void Sema::CheckPrintfString(const StringLiteral *FExpr,
+ const Expr *OrigFormatExpr,
+ const CallExpr *TheCall, bool HasVAListArg,
+ unsigned format_idx, unsigned firstDataArg) {
+
+ const ObjCStringLiteral *ObjCFExpr =
+ dyn_cast<ObjCStringLiteral>(OrigFormatExpr);
+
+ // CHECK: is the format string a wide literal?
+ if (FExpr->isWide()) {
+ Diag(FExpr->getLocStart(),
+ diag::warn_printf_format_string_is_wide_literal)
+ << OrigFormatExpr->getSourceRange();
+ return;
+ }
+
+ // Str - The format string. NOTE: this is NOT null-terminated!
+ const char *Str = FExpr->getStrData();
+
+ // CHECK: empty format string?
+ unsigned StrLen = FExpr->getByteLength();
+
+ if (StrLen == 0) {
+ Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string)
+ << OrigFormatExpr->getSourceRange();
+ return;
+ }
+
+ // We process the format string using a binary state machine. The
+ // current state is stored in CurrentState.
+ enum {
+ state_OrdChr,
+ state_Conversion
+ } CurrentState = state_OrdChr;
+
+ // numConversions - The number of conversions seen so far. This is
+ // incremented as we traverse the format string.
+ unsigned numConversions = 0;
+
+ // numDataArgs - The number of data arguments after the format
+ // string. This can only be determined for non vprintf-like
+ // functions. For those functions, this value is 1 (the sole
+ // va_arg argument).
+ unsigned numDataArgs = TheCall->getNumArgs()-firstDataArg;
+
+ // Inspect the format string.
+ unsigned StrIdx = 0;
+
+ // LastConversionIdx - Index within the format string where we last saw
+ // a '%' character that starts a new format conversion.
+ unsigned LastConversionIdx = 0;
+
+ for (; StrIdx < StrLen; ++StrIdx) {
+
+ // Is the number of detected conversion conversions greater than
+ // the number of matching data arguments? If so, stop.
+ if (!HasVAListArg && numConversions > numDataArgs) break;
+
+ // Handle "\0"
+ if (Str[StrIdx] == '\0') {
+ // The string returned by getStrData() is not null-terminated,
+ // so the presence of a null character is likely an error.
+ Diag(getLocationOfStringLiteralByte(FExpr, StrIdx),
+ diag::warn_printf_format_string_contains_null_char)
+ << OrigFormatExpr->getSourceRange();
+ return;
+ }
+
+ // Ordinary characters (not processing a format conversion).
+ if (CurrentState == state_OrdChr) {
+ if (Str[StrIdx] == '%') {
+ CurrentState = state_Conversion;
+ LastConversionIdx = StrIdx;
+ }
+ continue;
+ }
+
+ // Seen '%'. Now processing a format conversion.
+ switch (Str[StrIdx]) {
+ // Handle dynamic precision or width specifier.
+ case '*': {
+ ++numConversions;
+
+ if (!HasVAListArg) {
+ if (numConversions > numDataArgs) {
+ SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, StrIdx);
+
+ if (Str[StrIdx-1] == '.')
+ Diag(Loc, diag::warn_printf_asterisk_precision_missing_arg)
+ << OrigFormatExpr->getSourceRange();
+ else
+ Diag(Loc, diag::warn_printf_asterisk_width_missing_arg)
+ << OrigFormatExpr->getSourceRange();
+
+ // Don't do any more checking. We'll just emit spurious errors.
+ return;
+ }
+
+ // Perform type checking on width/precision specifier.
+ const Expr *E = TheCall->getArg(format_idx+numConversions);
+ if (const BuiltinType *BT = E->getType()->getAsBuiltinType())
+ if (BT->getKind() == BuiltinType::Int)
+ break;
+
+ SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, StrIdx);
+
+ if (Str[StrIdx-1] == '.')
+ Diag(Loc, diag::warn_printf_asterisk_precision_wrong_type)
+ << E->getType() << E->getSourceRange();
+ else
+ Diag(Loc, diag::warn_printf_asterisk_width_wrong_type)
+ << E->getType() << E->getSourceRange();
+
+ break;
+ }
+ }
+
+ // Characters which can terminate a format conversion
+ // (e.g. "%d"). Characters that specify length modifiers or
+ // other flags are handled by the default case below.
+ //
+ // FIXME: additional checks will go into the following cases.
+ case 'i':
+ case 'd':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ case 'D':
+ case 'O':
+ case 'U':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ case 'a':
+ case 'A':
+ case 'c':
+ case 'C':
+ case 'S':
+ case 's':
+ case 'p':
+ ++numConversions;
+ CurrentState = state_OrdChr;
+ break;
+
+ case 'm':
+ // FIXME: Warn in situations where this isn't supported!
+ CurrentState = state_OrdChr;
+ break;
+
+ // CHECK: Are we using "%n"? Issue a warning.
+ case 'n': {
+ ++numConversions;
+ CurrentState = state_OrdChr;
+ SourceLocation Loc = getLocationOfStringLiteralByte(FExpr,
+ LastConversionIdx);
+
+ Diag(Loc, diag::warn_printf_write_back)<<OrigFormatExpr->getSourceRange();
+ break;
+ }
+
+ // Handle "%@"
+ case '@':
+ // %@ is allowed in ObjC format strings only.
+ if(ObjCFExpr != NULL)
+ CurrentState = state_OrdChr;
+ else {
+ // Issue a warning: invalid format conversion.
+ SourceLocation Loc =
+ getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
+
+ Diag(Loc, diag::warn_printf_invalid_conversion)
+ << std::string(Str+LastConversionIdx,
+ Str+std::min(LastConversionIdx+2, StrLen))
+ << OrigFormatExpr->getSourceRange();
+ }
+ ++numConversions;
+ break;
+
+ // Handle "%%"
+ case '%':
+ // Sanity check: Was the first "%" character the previous one?
+ // If not, we will assume that we have a malformed format
+ // conversion, and that the current "%" character is the start
+ // of a new conversion.
+ if (StrIdx - LastConversionIdx == 1)
+ CurrentState = state_OrdChr;
+ else {
+ // Issue a warning: invalid format conversion.
+ SourceLocation Loc =
+ getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
+
+ Diag(Loc, diag::warn_printf_invalid_conversion)
+ << std::string(Str+LastConversionIdx, Str+StrIdx)
+ << OrigFormatExpr->getSourceRange();
+
+ // This conversion is broken. Advance to the next format
+ // conversion.
+ LastConversionIdx = StrIdx;
+ ++numConversions;
+ }
+ break;
+
+ default:
+ // This case catches all other characters: flags, widths, etc.
+ // We should eventually process those as well.
+ break;
+ }
+ }
+
+ if (CurrentState == state_Conversion) {
+ // Issue a warning: invalid format conversion.
+ SourceLocation Loc =
+ getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
+
+ Diag(Loc, diag::warn_printf_invalid_conversion)
+ << std::string(Str+LastConversionIdx,
+ Str+std::min(LastConversionIdx+2, StrLen))
+ << OrigFormatExpr->getSourceRange();
+ return;
+ }
+
+ if (!HasVAListArg) {
+ // CHECK: Does the number of format conversions exceed the number
+ // of data arguments?
+ if (numConversions > numDataArgs) {
+ SourceLocation Loc =
+ getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
+
+ Diag(Loc, diag::warn_printf_insufficient_data_args)
+ << OrigFormatExpr->getSourceRange();
+ }
+ // CHECK: Does the number of data arguments exceed the number of
+ // format conversions in the format string?
+ else if (numConversions < numDataArgs)
+ Diag(TheCall->getArg(format_idx+numConversions+1)->getLocStart(),
+ diag::warn_printf_too_many_data_args)
+ << OrigFormatExpr->getSourceRange();
+ }
+}
+
+//===--- CHECK: Return Address of Stack Variable --------------------------===//
+
+static DeclRefExpr* EvalVal(Expr *E);
+static DeclRefExpr* EvalAddr(Expr* E);
+
+/// CheckReturnStackAddr - Check if a return statement returns the address
+/// of a stack variable.
+void
+Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
+ SourceLocation ReturnLoc) {
+
+ // Perform checking for returned stack addresses.
+ if (lhsType->isPointerType() || lhsType->isBlockPointerType()) {
+ if (DeclRefExpr *DR = EvalAddr(RetValExp))
+ Diag(DR->getLocStart(), diag::warn_ret_stack_addr)
+ << DR->getDecl()->getDeclName() << RetValExp->getSourceRange();
+
+ // Skip over implicit cast expressions when checking for block expressions.
+ if (ImplicitCastExpr *IcExpr =
+ dyn_cast_or_null<ImplicitCastExpr>(RetValExp))
+ RetValExp = IcExpr->getSubExpr();
+
+ if (BlockExpr *C = dyn_cast_or_null<BlockExpr>(RetValExp))
+ if (C->hasBlockDeclRefExprs())
+ Diag(C->getLocStart(), diag::err_ret_local_block)
+ << C->getSourceRange();
+ }
+ // Perform checking for stack values returned by reference.
+ else if (lhsType->isReferenceType()) {
+ // Check for a reference to the stack
+ if (DeclRefExpr *DR = EvalVal(RetValExp))
+ Diag(DR->getLocStart(), diag::warn_ret_stack_ref)
+ << DR->getDecl()->getDeclName() << RetValExp->getSourceRange();
+ }
+}
+
+/// EvalAddr - EvalAddr and EvalVal are mutually recursive functions that
+/// check if the expression in a return statement evaluates to an address
+/// to a location on the stack. The recursion is used to traverse the
+/// AST of the return expression, with recursion backtracking when we
+/// encounter a subexpression that (1) clearly does not lead to the address
+/// of a stack variable or (2) is something we cannot determine leads to
+/// the address of a stack variable based on such local checking.
+///
+/// EvalAddr processes expressions that are pointers that are used as
+/// references (and not L-values). EvalVal handles all other values.
+/// At the base case of the recursion is a check for a DeclRefExpr* in
+/// the refers to a stack variable.
+///
+/// This implementation handles:
+///
+/// * pointer-to-pointer casts
+/// * implicit conversions from array references to pointers
+/// * taking the address of fields
+/// * 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 DeclRefExpr* EvalAddr(Expr *E) {
+ // We should only be called for evaluating pointer expressions.
+ assert((E->getType()->isPointerType() ||
+ E->getType()->isBlockPointerType() ||
+ E->getType()->isObjCQualifiedIdType()) &&
+ "EvalAddr only works on pointers");
+
+ // Our "symbolic interpreter" is just a dispatch off the currently
+ // viewed AST node. We then recursively traverse the AST by calling
+ // EvalAddr and EvalVal appropriately.
+ switch (E->getStmtClass()) {
+ case Stmt::ParenExprClass:
+ // Ignore parentheses.
+ return EvalAddr(cast<ParenExpr>(E)->getSubExpr());
+
+ case Stmt::UnaryOperatorClass: {
+ // The only unary operator that make sense to handle here
+ // is AddrOf. All others don't make sense as pointers.
+ UnaryOperator *U = cast<UnaryOperator>(E);
+
+ if (U->getOpcode() == UnaryOperator::AddrOf)
+ return EvalVal(U->getSubExpr());
+ else
+ return NULL;
+ }
+
+ case Stmt::BinaryOperatorClass: {
+ // Handle pointer arithmetic. All other binary operators are not valid
+ // in this context.
+ BinaryOperator *B = cast<BinaryOperator>(E);
+ BinaryOperator::Opcode op = B->getOpcode();
+
+ if (op != BinaryOperator::Add && op != BinaryOperator::Sub)
+ return NULL;
+
+ Expr *Base = B->getLHS();
+
+ // Determine which argument is the real pointer base. It could be
+ // the RHS argument instead of the LHS.
+ if (!Base->getType()->isPointerType()) Base = B->getRHS();
+
+ assert (Base->getType()->isPointerType());
+ return EvalAddr(Base);
+ }
+
+ // For conditional operators we need to see if either the LHS or RHS are
+ // valid DeclRefExpr*s. If one of them is valid, we return it.
+ case Stmt::ConditionalOperatorClass: {
+ ConditionalOperator *C = cast<ConditionalOperator>(E);
+
+ // Handle the GNU extension for missing LHS.
+ if (Expr *lhsExpr = C->getLHS())
+ if (DeclRefExpr* LHS = EvalAddr(lhsExpr))
+ return LHS;
+
+ return EvalAddr(C->getRHS());
+ }
+
+ // For casts, we need to handle conversions from arrays to
+ // pointer values, and pointer-to-pointer conversions.
+ case Stmt::ImplicitCastExprClass:
+ case Stmt::CStyleCastExprClass:
+ case Stmt::CXXFunctionalCastExprClass: {
+ Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
+ QualType T = SubExpr->getType();
+
+ if (SubExpr->getType()->isPointerType() ||
+ SubExpr->getType()->isBlockPointerType() ||
+ SubExpr->getType()->isObjCQualifiedIdType())
+ return EvalAddr(SubExpr);
+ else if (T->isArrayType())
+ return EvalVal(SubExpr);
+ else
+ return 0;
+ }
+
+ // C++ casts. For dynamic casts, static casts, and const casts, we
+ // are always converting from a pointer-to-pointer, so we just blow
+ // through the cast. In the case the dynamic cast doesn't fail (and
+ // return NULL), we take the conservative route and report cases
+ // where we return the address of a stack variable. For Reinterpre
+ // FIXME: The comment about is wrong; we're not always converting
+ // from pointer to pointer. I'm guessing that this code should also
+ // handle references to objects.
+ case Stmt::CXXStaticCastExprClass:
+ case Stmt::CXXDynamicCastExprClass:
+ case Stmt::CXXConstCastExprClass:
+ case Stmt::CXXReinterpretCastExprClass: {
+ Expr *S = cast<CXXNamedCastExpr>(E)->getSubExpr();
+ if (S->getType()->isPointerType() || S->getType()->isBlockPointerType())
+ return EvalAddr(S);
+ else
+ return NULL;
+ }
+
+ // Everything else: we simply don't reason about them.
+ default:
+ return NULL;
+ }
+}
+
+
+/// EvalVal - This function is complements EvalAddr in the mutual recursion.
+/// See the comments for EvalAddr for more details.
+static DeclRefExpr* EvalVal(Expr *E) {
+
+ // We should only be called for evaluating non-pointer expressions, or
+ // expressions with a pointer type that are not used as references but instead
+ // are l-values (e.g., DeclRefExpr with a pointer type).
+
+ // Our "symbolic interpreter" is just a dispatch off the currently
+ // viewed AST node. We then recursively traverse the AST by calling
+ // EvalAddr and EvalVal appropriately.
+ switch (E->getStmtClass()) {
+ case Stmt::DeclRefExprClass:
+ case Stmt::QualifiedDeclRefExprClass: {
+ // DeclRefExpr: the base case. When we hit a DeclRefExpr we are looking
+ // at code that refers to a variable's name. We check if it has local
+ // storage within the function, and if so, return the expression.
+ DeclRefExpr *DR = cast<DeclRefExpr>(E);
+
+ if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl()))
+ if(V->hasLocalStorage() && !V->getType()->isReferenceType()) return DR;
+
+ return NULL;
+ }
+
+ case Stmt::ParenExprClass:
+ // Ignore parentheses.
+ return EvalVal(cast<ParenExpr>(E)->getSubExpr());
+
+ case Stmt::UnaryOperatorClass: {
+ // The only unary operator that make sense to handle here
+ // is Deref. All others don't resolve to a "name." This includes
+ // handling all sorts of rvalues passed to a unary operator.
+ UnaryOperator *U = cast<UnaryOperator>(E);
+
+ if (U->getOpcode() == UnaryOperator::Deref)
+ return EvalAddr(U->getSubExpr());
+
+ return NULL;
+ }
+
+ case Stmt::ArraySubscriptExprClass: {
+ // Array subscripts are potential references to data on the stack. We
+ // retrieve the DeclRefExpr* for the array variable if it indeed
+ // has local storage.
+ return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase());
+ }
+
+ case Stmt::ConditionalOperatorClass: {
+ // For conditional operators we need to see if either the LHS or RHS are
+ // non-NULL DeclRefExpr's. If one is non-NULL, we return it.
+ ConditionalOperator *C = cast<ConditionalOperator>(E);
+
+ // Handle the GNU extension for missing LHS.
+ if (Expr *lhsExpr = C->getLHS())
+ if (DeclRefExpr *LHS = EvalVal(lhsExpr))
+ return LHS;
+
+ return EvalVal(C->getRHS());
+ }
+
+ // Accesses to members are potential references to data on the stack.
+ case Stmt::MemberExprClass: {
+ MemberExpr *M = cast<MemberExpr>(E);
+
+ // Check for indirect access. We only want direct field accesses.
+ if (!M->isArrow())
+ return EvalVal(M->getBase());
+ else
+ return NULL;
+ }
+
+ // Everything else: we simply don't reason about them.
+ default:
+ return NULL;
+ }
+}
+
+//===--- CHECK: Floating-Point comparisons (-Wfloat-equal) ---------------===//
+
+/// 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) {
+ bool EmitWarning = true;
+
+ Expr* LeftExprSansParen = lex->IgnoreParens();
+ Expr* RightExprSansParen = rex->IgnoreParens();
+
+ // Special case: check for x == x (which is OK).
+ // Do not emit warnings for such cases.
+ if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LeftExprSansParen))
+ if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RightExprSansParen))
+ if (DRL->getDecl() == DRR->getDecl())
+ EmitWarning = false;
+
+
+ // Special case: check for comparisons against literals that can be exactly
+ // represented by APFloat. In such cases, do not emit a warning. This
+ // is a heuristic: often comparison against such literals are used to
+ // detect if a value in a variable has not changed. This clearly can
+ // lead to false negatives.
+ if (EmitWarning) {
+ if (FloatingLiteral* FLL = dyn_cast<FloatingLiteral>(LeftExprSansParen)) {
+ if (FLL->isExact())
+ EmitWarning = false;
+ }
+ else
+ if (FloatingLiteral* FLR = dyn_cast<FloatingLiteral>(RightExprSansParen)){
+ if (FLR->isExact())
+ EmitWarning = false;
+ }
+ }
+
+ // Check for comparisons with builtin types.
+ if (EmitWarning)
+ if (CallExpr* CL = dyn_cast<CallExpr>(LeftExprSansParen))
+ if (CL->isBuiltinCall(Context))
+ EmitWarning = false;
+
+ if (EmitWarning)
+ if (CallExpr* CR = dyn_cast<CallExpr>(RightExprSansParen))
+ if (CR->isBuiltinCall(Context))
+ EmitWarning = false;
+
+ // Emit the diagnostic.
+ if (EmitWarning)
+ Diag(loc, diag::warn_floatingpoint_eq)
+ << lex->getSourceRange() << rex->getSourceRange();
+}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
new file mode 100644
index 000000000000..959154c4ec1b
--- /dev/null
+++ b/lib/Sema/SemaDecl.cpp
@@ -0,0 +1,4415 @@
+//===--- SemaDecl.cpp - Semantic Analysis for Declarations ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for declarations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "SemaInherit.h"
+#include "clang/AST/APValue.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/SourceManager.h"
+// FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's)
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include <algorithm>
+#include <functional>
+using namespace clang;
+
+/// getDeclName - Return a pretty name for the specified decl if possible, or
+/// an empty string if not. This is used for pretty crash reporting.
+std::string Sema::getDeclName(DeclPtrTy d) {
+ Decl *D = d.getAs<Decl>();
+ if (NamedDecl *DN = dyn_cast_or_null<NamedDecl>(D))
+ return DN->getQualifiedNameAsString();
+ return "";
+}
+
+Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(DeclPtrTy Ptr) {
+ return DeclGroupPtrTy::make(DeclGroupRef(Ptr.getAs<Decl>()));
+}
+
+/// \brief If the identifier refers to a type name within this scope,
+/// return the declaration of that type.
+///
+/// This routine performs ordinary name lookup of the identifier II
+/// within the given scope, with optional C++ scope specifier SS, to
+/// determine whether the name refers to a type. If so, returns an
+/// opaque pointer (actually a QualType) corresponding to that
+/// type. Otherwise, returns NULL.
+///
+/// If name lookup results in an ambiguity, this routine will complain
+/// and then return NULL.
+Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
+ Scope *S, const CXXScopeSpec *SS) {
+ // C++ [temp.res]p3:
+ // A qualified-id that refers to a type and in which the
+ // nested-name-specifier depends on a template-parameter (14.6.2)
+ // shall be prefixed by the keyword typename to indicate that the
+ // qualified-id denotes a type, forming an
+ // elaborated-type-specifier (7.1.5.3).
+ //
+ // We therefore do not perform any name lookup if the result would
+ // refer to a member of an unknown specialization.
+ if (SS && isUnknownSpecialization(*SS))
+ return 0;
+
+ LookupResult Result
+ = LookupParsedName(S, SS, &II, LookupOrdinaryName, false, false);
+
+ NamedDecl *IIDecl = 0;
+ switch (Result.getKind()) {
+ case LookupResult::NotFound:
+ case LookupResult::FoundOverloaded:
+ return 0;
+
+ case LookupResult::AmbiguousBaseSubobjectTypes:
+ case LookupResult::AmbiguousBaseSubobjects:
+ case LookupResult::AmbiguousReference: {
+ // Look to see if we have a type anywhere in the list of results.
+ for (LookupResult::iterator Res = Result.begin(), ResEnd = Result.end();
+ Res != ResEnd; ++Res) {
+ if (isa<TypeDecl>(*Res) || isa<ObjCInterfaceDecl>(*Res)) {
+ if (!IIDecl ||
+ (*Res)->getLocation().getRawEncoding() <
+ IIDecl->getLocation().getRawEncoding())
+ IIDecl = *Res;
+ }
+ }
+
+ if (!IIDecl) {
+ // None of the entities we found is a type, so there is no way
+ // to even assume that the result is a type. In this case, don't
+ // complain about the ambiguity. The parser will either try to
+ // perform this lookup again (e.g., as an object name), which
+ // will produce the ambiguity, or will complain that it expected
+ // a type name.
+ Result.Destroy();
+ return 0;
+ }
+
+ // We found a type within the ambiguous lookup; diagnose the
+ // ambiguity and then return that type. This might be the right
+ // answer, or it might not be, but it suppresses any attempt to
+ // perform the name lookup again.
+ DiagnoseAmbiguousLookup(Result, DeclarationName(&II), NameLoc);
+ break;
+ }
+
+ case LookupResult::Found:
+ IIDecl = Result.getAsDecl();
+ break;
+ }
+
+ if (IIDecl) {
+ QualType T;
+
+ if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) {
+ // Check whether we can use this type
+ (void)DiagnoseUseOfDecl(IIDecl, NameLoc);
+
+ if (getLangOptions().CPlusPlus) {
+ // C++ [temp.local]p2:
+ // Within the scope of a class template specialization or
+ // partial specialization, when the injected-class-name is
+ // not followed by a <, it is equivalent to the
+ // injected-class-name followed by the template-argument s
+ // of the class template specialization or partial
+ // specialization enclosed in <>.
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD))
+ if (RD->isInjectedClassName())
+ if (ClassTemplateDecl *Template = RD->getDescribedClassTemplate())
+ T = Template->getInjectedClassNameType(Context);
+ }
+
+ if (T.isNull())
+ T = Context.getTypeDeclType(TD);
+ } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
+ // Check whether we can use this interface.
+ (void)DiagnoseUseOfDecl(IIDecl, NameLoc);
+
+ T = Context.getObjCInterfaceType(IDecl);
+ } else
+ return 0;
+
+ if (SS)
+ T = getQualifiedNameType(*SS, T);
+
+ return T.getAsOpaquePtr();
+ }
+
+ return 0;
+}
+
+/// isTagName() - This method is called *for error recovery purposes only*
+/// to determine if the specified name is a valid tag name ("struct foo"). If
+/// so, this returns the TST for the tag corresponding to it (TST_enum,
+/// TST_union, TST_struct, TST_class). This is used to diagnose cases in C
+/// where the user forgot to specify the tag.
+DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
+ // Do a tag name lookup in this scope.
+ LookupResult R = LookupName(S, &II, LookupTagName, false, false);
+ if (R.getKind() == LookupResult::Found)
+ if (const TagDecl *TD = dyn_cast<TagDecl>(R.getAsDecl())) {
+ switch (TD->getTagKind()) {
+ case TagDecl::TK_struct: return DeclSpec::TST_struct;
+ case TagDecl::TK_union: return DeclSpec::TST_union;
+ case TagDecl::TK_class: return DeclSpec::TST_class;
+ case TagDecl::TK_enum: return DeclSpec::TST_enum;
+ }
+ }
+
+ return DeclSpec::TST_unspecified;
+}
+
+
+
+DeclContext *Sema::getContainingDC(DeclContext *DC) {
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) {
+ // A C++ out-of-line method will return to the file declaration context.
+ if (MD->isOutOfLineDefinition())
+ return MD->getLexicalDeclContext();
+
+ // A C++ inline method is parsed *after* the topmost class it was declared
+ // in is fully parsed (it's "complete").
+ // The parsing of a C++ inline method happens at the declaration context of
+ // the topmost (non-nested) class it is lexically declared in.
+ assert(isa<CXXRecordDecl>(MD->getParent()) && "C++ method not in Record.");
+ DC = MD->getParent();
+ while (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC->getLexicalParent()))
+ DC = RD;
+
+ // Return the declaration context of the topmost class the inline method is
+ // declared in.
+ return DC;
+ }
+
+ if (isa<ObjCMethodDecl>(DC))
+ return Context.getTranslationUnitDecl();
+
+ return DC->getLexicalParent();
+}
+
+void Sema::PushDeclContext(Scope *S, DeclContext *DC) {
+ assert(getContainingDC(DC) == CurContext &&
+ "The next DeclContext should be lexically contained in the current one.");
+ CurContext = DC;
+ S->setEntity(DC);
+}
+
+void Sema::PopDeclContext() {
+ assert(CurContext && "DeclContext imbalance!");
+
+ CurContext = getContainingDC(CurContext);
+}
+
+/// \brief Determine whether we allow overloading of the function
+/// PrevDecl with another declaration.
+///
+/// This routine determines whether overloading is possible, not
+/// whether some new function is actually an overload. It will return
+/// true in C++ (where we can always provide overloads) or, as an
+/// extension, in C when the previous function is already an
+/// overloaded function declaration or has the "overloadable"
+/// attribute.
+static bool AllowOverloadingOfFunction(Decl *PrevDecl, ASTContext &Context) {
+ if (Context.getLangOptions().CPlusPlus)
+ return true;
+
+ if (isa<OverloadedFunctionDecl>(PrevDecl))
+ return true;
+
+ return PrevDecl->getAttr<OverloadableAttr>() != 0;
+}
+
+/// Add this decl to the scope shadowed decl chains.
+void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
+ // Move up the scope chain until we find the nearest enclosing
+ // non-transparent context. The declaration will be introduced into this
+ // scope.
+ while (S->getEntity() &&
+ ((DeclContext *)S->getEntity())->isTransparentContext())
+ S = S->getParent();
+
+ S->AddDecl(DeclPtrTy::make(D));
+
+ // Add scoped declarations into their context, so that they can be
+ // found later. Declarations without a context won't be inserted
+ // into any context.
+ CurContext->addDecl(Context, D);
+
+ // C++ [basic.scope]p4:
+ // -- exactly one declaration shall declare a class name or
+ // enumeration name that is not a typedef name and the other
+ // declarations shall all refer to the same object or
+ // enumerator, or all refer to functions and function templates;
+ // in this case the class name or enumeration name is hidden.
+ if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ // We are pushing the name of a tag (enum or class).
+ if (CurContext->getLookupContext()
+ == TD->getDeclContext()->getLookupContext()) {
+ // We're pushing the tag into the current context, which might
+ // require some reshuffling in the identifier resolver.
+ IdentifierResolver::iterator
+ I = IdResolver.begin(TD->getDeclName()),
+ IEnd = IdResolver.end();
+ if (I != IEnd && isDeclInScope(*I, CurContext, S)) {
+ NamedDecl *PrevDecl = *I;
+ for (; I != IEnd && isDeclInScope(*I, CurContext, S);
+ PrevDecl = *I, ++I) {
+ if (TD->declarationReplaces(*I)) {
+ // This is a redeclaration. Remove it from the chain and
+ // break out, so that we'll add in the shadowed
+ // declaration.
+ S->RemoveDecl(DeclPtrTy::make(*I));
+ if (PrevDecl == *I) {
+ IdResolver.RemoveDecl(*I);
+ IdResolver.AddDecl(TD);
+ return;
+ } else {
+ IdResolver.RemoveDecl(*I);
+ break;
+ }
+ }
+ }
+
+ // There is already a declaration with the same name in the same
+ // scope, which is not a tag declaration. It must be found
+ // before we find the new declaration, so insert the new
+ // declaration at the end of the chain.
+ IdResolver.AddShadowedDecl(TD, PrevDecl);
+
+ return;
+ }
+ }
+ } else if (isa<FunctionDecl>(D) &&
+ AllowOverloadingOfFunction(D, Context)) {
+ // We are pushing the name of a function, which might be an
+ // overloaded name.
+ FunctionDecl *FD = cast<FunctionDecl>(D);
+ IdentifierResolver::iterator Redecl
+ = std::find_if(IdResolver.begin(FD->getDeclName()),
+ IdResolver.end(),
+ std::bind1st(std::mem_fun(&NamedDecl::declarationReplaces),
+ FD));
+ if (Redecl != IdResolver.end() &&
+ S->isDeclScope(DeclPtrTy::make(*Redecl))) {
+ // There is already a declaration of a function on our
+ // IdResolver chain. Replace it with this declaration.
+ S->RemoveDecl(DeclPtrTy::make(*Redecl));
+ IdResolver.RemoveDecl(*Redecl);
+ }
+ } else if (isa<ObjCInterfaceDecl>(D)) {
+ // We're pushing an Objective-C interface into the current
+ // context. If there is already an alias declaration, remove it first.
+ for (IdentifierResolver::iterator
+ I = IdResolver.begin(D->getDeclName()), IEnd = IdResolver.end();
+ I != IEnd; ++I) {
+ if (isa<ObjCCompatibleAliasDecl>(*I)) {
+ S->RemoveDecl(DeclPtrTy::make(*I));
+ IdResolver.RemoveDecl(*I);
+ break;
+ }
+ }
+ }
+
+ IdResolver.AddDecl(D);
+}
+
+void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
+ if (S->decl_empty()) return;
+ assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
+ "Scope shouldn't contain decls!");
+
+ for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end();
+ I != E; ++I) {
+ Decl *TmpD = (*I).getAs<Decl>();
+ assert(TmpD && "This decl didn't get pushed??");
+
+ assert(isa<NamedDecl>(TmpD) && "Decl isn't NamedDecl?");
+ NamedDecl *D = cast<NamedDecl>(TmpD);
+
+ if (!D->getDeclName()) continue;
+
+ // Remove this name from our lexical scope.
+ IdResolver.RemoveDecl(D);
+ }
+}
+
+/// getObjCInterfaceDecl - Look up a for a class declaration in the scope.
+/// return 0 if one not found.
+ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
+ // The third "scope" argument is 0 since we aren't enabling lazy built-in
+ // creation from this context.
+ NamedDecl *IDecl = LookupName(TUScope, Id, LookupOrdinaryName);
+
+ return dyn_cast_or_null<ObjCInterfaceDecl>(IDecl);
+}
+
+/// getNonFieldDeclScope - Retrieves the innermost scope, starting
+/// from S, where a non-field would be declared. This routine copes
+/// with the difference between C and C++ scoping rules in structs and
+/// unions. For example, the following code is well-formed in C but
+/// ill-formed in C++:
+/// @code
+/// struct S6 {
+/// enum { BAR } e;
+/// };
+///
+/// void test_S6() {
+/// struct S6 a;
+/// a.e = BAR;
+/// }
+/// @endcode
+/// For the declaration of BAR, this routine will return a different
+/// scope. The scope S will be the scope of the unnamed enumeration
+/// within S6. In C++, this routine will return the scope associated
+/// with S6, because the enumeration's scope is a transparent
+/// context but structures can contain non-field names. In C, this
+/// routine will return the translation unit scope, since the
+/// enumeration's scope is a transparent context and structures cannot
+/// contain non-field names.
+Scope *Sema::getNonFieldDeclScope(Scope *S) {
+ while (((S->getFlags() & Scope::DeclScope) == 0) ||
+ (S->getEntity() &&
+ ((DeclContext *)S->getEntity())->isTransparentContext()) ||
+ (S->isClassScope() && !getLangOptions().CPlusPlus))
+ S = S->getParent();
+ return S;
+}
+
+void Sema::InitBuiltinVaListType() {
+ if (!Context.getBuiltinVaListType().isNull())
+ return;
+
+ IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list");
+ NamedDecl *VaDecl = LookupName(TUScope, VaIdent, LookupOrdinaryName);
+ TypedefDecl *VaTypedef = cast<TypedefDecl>(VaDecl);
+ Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef));
+}
+
+/// LazilyCreateBuiltin - The specified Builtin-ID was first used at
+/// file scope. lazily create a decl for it. ForRedeclaration is true
+/// if we're creating this built-in in anticipation of redeclaring the
+/// built-in.
+NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
+ Scope *S, bool ForRedeclaration,
+ SourceLocation Loc) {
+ Builtin::ID BID = (Builtin::ID)bid;
+
+ if (Context.BuiltinInfo.hasVAListUse(BID))
+ InitBuiltinVaListType();
+
+ Builtin::Context::GetBuiltinTypeError Error;
+ QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context, Error);
+ switch (Error) {
+ case Builtin::Context::GE_None:
+ // Okay
+ break;
+
+ case Builtin::Context::GE_Missing_FILE:
+ if (ForRedeclaration)
+ Diag(Loc, diag::err_implicit_decl_requires_stdio)
+ << Context.BuiltinInfo.GetName(BID);
+ return 0;
+ }
+
+ if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(BID)) {
+ Diag(Loc, diag::ext_implicit_lib_function_decl)
+ << Context.BuiltinInfo.GetName(BID)
+ << R;
+ if (Context.BuiltinInfo.getHeaderName(BID) &&
+ Diags.getDiagnosticLevel(diag::ext_implicit_lib_function_decl)
+ != Diagnostic::Ignored)
+ Diag(Loc, diag::note_please_include_header)
+ << Context.BuiltinInfo.getHeaderName(BID)
+ << Context.BuiltinInfo.GetName(BID);
+ }
+
+ FunctionDecl *New = FunctionDecl::Create(Context,
+ Context.getTranslationUnitDecl(),
+ Loc, II, R,
+ FunctionDecl::Extern, false,
+ /*hasPrototype=*/true);
+ New->setImplicit();
+
+ // Create Decl objects for each parameter, adding them to the
+ // FunctionDecl.
+ if (FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) {
+ llvm::SmallVector<ParmVarDecl*, 16> Params;
+ for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i)
+ Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0,
+ FT->getArgType(i), VarDecl::None, 0));
+ New->setParams(Context, Params.data(), Params.size());
+ }
+
+ AddKnownFunctionAttributes(New);
+
+ // TUScope is the translation-unit scope to insert this function into.
+ // FIXME: This is hideous. We need to teach PushOnScopeChains to
+ // relate Scopes to DeclContexts, and probably eliminate CurContext
+ // entirely, but we're not there yet.
+ DeclContext *SavedContext = CurContext;
+ CurContext = Context.getTranslationUnitDecl();
+ PushOnScopeChains(New, TUScope);
+ CurContext = SavedContext;
+ return New;
+}
+
+/// GetStdNamespace - This method gets the C++ "std" namespace. This is where
+/// everything from the standard library is defined.
+NamespaceDecl *Sema::GetStdNamespace() {
+ if (!StdNamespace) {
+ IdentifierInfo *StdIdent = &PP.getIdentifierTable().get("std");
+ DeclContext *Global = Context.getTranslationUnitDecl();
+ Decl *Std = LookupQualifiedName(Global, StdIdent, LookupNamespaceName);
+ StdNamespace = dyn_cast_or_null<NamespaceDecl>(Std);
+ }
+ return StdNamespace;
+}
+
+/// MergeTypeDefDecl - We just parsed a typedef 'New' which has the
+/// same name and scope as a previous declaration 'Old'. Figure out
+/// how to resolve this situation, merging decls or emitting
+/// diagnostics as appropriate. If there was an error, set New to be invalid.
+///
+void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
+ // If either decl is known invalid already, set the new one to be invalid and
+ // don't bother doing any merging checks.
+ if (New->isInvalidDecl() || OldD->isInvalidDecl())
+ return New->setInvalidDecl();
+
+ bool objc_types = false;
+
+ // Allow multiple definitions for ObjC built-in typedefs.
+ // FIXME: Verify the underlying types are equivalent!
+ if (getLangOptions().ObjC1) {
+ const IdentifierInfo *TypeID = New->getIdentifier();
+ switch (TypeID->getLength()) {
+ default: break;
+ case 2:
+ if (!TypeID->isStr("id"))
+ break;
+ Context.setObjCIdType(Context.getTypeDeclType(New));
+ objc_types = true;
+ break;
+ case 5:
+ if (!TypeID->isStr("Class"))
+ break;
+ Context.setObjCClassType(Context.getTypeDeclType(New));
+ return;
+ case 3:
+ if (!TypeID->isStr("SEL"))
+ break;
+ Context.setObjCSelType(Context.getTypeDeclType(New));
+ return;
+ case 8:
+ if (!TypeID->isStr("Protocol"))
+ break;
+ Context.setObjCProtoType(New->getUnderlyingType());
+ return;
+ }
+ // Fall through - the typedef name was not a builtin type.
+ }
+ // Verify the old decl was also a type.
+ TypeDecl *Old = dyn_cast<TypeDecl>(OldD);
+ if (!Old) {
+ Diag(New->getLocation(), diag::err_redefinition_different_kind)
+ << New->getDeclName();
+ if (OldD->getLocation().isValid())
+ Diag(OldD->getLocation(), diag::note_previous_definition);
+ return New->setInvalidDecl();
+ }
+
+ // Determine the "old" type we'll use for checking and diagnostics.
+ QualType OldType;
+ if (TypedefDecl *OldTypedef = dyn_cast<TypedefDecl>(Old))
+ OldType = OldTypedef->getUnderlyingType();
+ else
+ OldType = Context.getTypeDeclType(Old);
+
+ // If the typedef types are not identical, reject them in all languages and
+ // with any extensions enabled.
+
+ if (OldType != New->getUnderlyingType() &&
+ Context.getCanonicalType(OldType) !=
+ Context.getCanonicalType(New->getUnderlyingType())) {
+ Diag(New->getLocation(), diag::err_redefinition_different_typedef)
+ << New->getUnderlyingType() << OldType;
+ if (Old->getLocation().isValid())
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ return New->setInvalidDecl();
+ }
+
+ if (objc_types || getLangOptions().Microsoft)
+ return;
+
+ // C++ [dcl.typedef]p2:
+ // In a given non-class scope, a typedef specifier can be used to
+ // redefine the name of any type declared in that scope to refer
+ // to the type to which it already refers.
+ if (getLangOptions().CPlusPlus) {
+ if (!isa<CXXRecordDecl>(CurContext))
+ return;
+ Diag(New->getLocation(), diag::err_redefinition)
+ << New->getDeclName();
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ return New->setInvalidDecl();
+ }
+
+ // If we have a redefinition of a typedef in C, emit a warning. This warning
+ // is normally mapped to an error, but can be controlled with
+ // -Wtypedef-redefinition. If either the original was in a system header,
+ // don't emit this for compatibility with GCC.
+ if (PP.getDiagnostics().getSuppressSystemWarnings() &&
+ Context.getSourceManager().isInSystemHeader(Old->getLocation()))
+ return;
+
+ Diag(New->getLocation(), diag::warn_redefinition_of_typedef)
+ << New->getDeclName();
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ return;
+}
+
+/// DeclhasAttr - returns true if decl Declaration already has the target
+/// attribute.
+static bool DeclHasAttr(const Decl *decl, const Attr *target) {
+ for (const Attr *attr = decl->getAttrs(); attr; attr = attr->getNext())
+ if (attr->getKind() == target->getKind())
+ return true;
+
+ return false;
+}
+
+/// MergeAttributes - append attributes from the Old decl to the New one.
+static void MergeAttributes(Decl *New, Decl *Old, ASTContext &C) {
+ for (const Attr *attr = Old->getAttrs(); attr; attr = attr->getNext()) {
+ if (!DeclHasAttr(New, attr) && attr->isMerged()) {
+ Attr *NewAttr = attr->clone(C);
+ NewAttr->setInherited(true);
+ New->addAttr(NewAttr);
+ }
+ }
+}
+
+/// Used in MergeFunctionDecl to keep track of function parameters in
+/// C.
+struct GNUCompatibleParamWarning {
+ ParmVarDecl *OldParm;
+ ParmVarDecl *NewParm;
+ QualType PromotedType;
+};
+
+/// MergeFunctionDecl - We just parsed a function 'New' from
+/// declarator D which has the same name and scope as a previous
+/// declaration 'Old'. Figure out how to resolve this situation,
+/// merging decls or emitting diagnostics as appropriate.
+///
+/// In C++, New and Old must be declarations that are not
+/// overloaded. Use IsOverload to determine whether New and Old are
+/// overloaded, and to select the Old declaration that New should be
+/// merged with.
+///
+/// Returns true if there was an error, false otherwise.
+bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
+ assert(!isa<OverloadedFunctionDecl>(OldD) &&
+ "Cannot merge with an overloaded function declaration");
+
+ // Verify the old decl was also a function.
+ FunctionDecl *Old = dyn_cast<FunctionDecl>(OldD);
+ if (!Old) {
+ Diag(New->getLocation(), diag::err_redefinition_different_kind)
+ << New->getDeclName();
+ Diag(OldD->getLocation(), diag::note_previous_definition);
+ return true;
+ }
+
+ // Determine whether the previous declaration was a definition,
+ // implicit declaration, or a declaration.
+ diag::kind PrevDiag;
+ if (Old->isThisDeclarationADefinition())
+ PrevDiag = diag::note_previous_definition;
+ else if (Old->isImplicit())
+ PrevDiag = diag::note_previous_implicit_declaration;
+ else
+ PrevDiag = diag::note_previous_declaration;
+
+ QualType OldQType = Context.getCanonicalType(Old->getType());
+ QualType NewQType = Context.getCanonicalType(New->getType());
+
+ if (!isa<CXXMethodDecl>(New) && !isa<CXXMethodDecl>(Old) &&
+ New->getStorageClass() == FunctionDecl::Static &&
+ Old->getStorageClass() != FunctionDecl::Static) {
+ Diag(New->getLocation(), diag::err_static_non_static)
+ << New;
+ Diag(Old->getLocation(), PrevDiag);
+ return true;
+ }
+
+ if (getLangOptions().CPlusPlus) {
+ // (C++98 13.1p2):
+ // Certain function declarations cannot be overloaded:
+ // -- Function declarations that differ only in the return type
+ // cannot be overloaded.
+ QualType OldReturnType
+ = cast<FunctionType>(OldQType.getTypePtr())->getResultType();
+ QualType NewReturnType
+ = cast<FunctionType>(NewQType.getTypePtr())->getResultType();
+ if (OldReturnType != NewReturnType) {
+ Diag(New->getLocation(), diag::err_ovl_diff_return_type);
+ Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
+ return true;
+ }
+
+ const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
+ const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
+ if (OldMethod && NewMethod &&
+ OldMethod->getLexicalDeclContext() ==
+ NewMethod->getLexicalDeclContext()) {
+ // -- Member function declarations with the same name and the
+ // same parameter types cannot be overloaded if any of them
+ // is a static member function declaration.
+ if (OldMethod->isStatic() || NewMethod->isStatic()) {
+ Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member);
+ Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
+ return true;
+ }
+
+ // C++ [class.mem]p1:
+ // [...] A member shall not be declared twice in the
+ // member-specification, except that a nested class or member
+ // class template can be declared and then later defined.
+ unsigned NewDiag;
+ if (isa<CXXConstructorDecl>(OldMethod))
+ NewDiag = diag::err_constructor_redeclared;
+ else if (isa<CXXDestructorDecl>(NewMethod))
+ NewDiag = diag::err_destructor_redeclared;
+ else if (isa<CXXConversionDecl>(NewMethod))
+ NewDiag = diag::err_conv_function_redeclared;
+ else
+ NewDiag = diag::err_member_redeclared;
+
+ Diag(New->getLocation(), NewDiag);
+ Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
+ }
+
+ // (C++98 8.3.5p3):
+ // All declarations for a function shall agree exactly in both the
+ // return type and the parameter-type-list.
+ if (OldQType == NewQType)
+ return MergeCompatibleFunctionDecls(New, Old);
+
+ // Fall through for conflicting redeclarations and redefinitions.
+ }
+
+ // C: Function types need to be compatible, not identical. This handles
+ // duplicate function decls like "void f(int); void f(enum X);" properly.
+ if (!getLangOptions().CPlusPlus &&
+ Context.typesAreCompatible(OldQType, NewQType)) {
+ const FunctionType *OldFuncType = OldQType->getAsFunctionType();
+ const FunctionType *NewFuncType = NewQType->getAsFunctionType();
+ const FunctionProtoType *OldProto = 0;
+ if (isa<FunctionNoProtoType>(NewFuncType) &&
+ (OldProto = dyn_cast<FunctionProtoType>(OldFuncType))) {
+ // The old declaration provided a function prototype, but the
+ // new declaration does not. Merge in the prototype.
+ assert(!OldProto->hasExceptionSpec() && "Exception spec in C");
+ llvm::SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(),
+ OldProto->arg_type_end());
+ NewQType = Context.getFunctionType(NewFuncType->getResultType(),
+ ParamTypes.data(), ParamTypes.size(),
+ OldProto->isVariadic(),
+ OldProto->getTypeQuals());
+ New->setType(NewQType);
+ New->setHasInheritedPrototype();
+
+ // Synthesize a parameter for each argument type.
+ llvm::SmallVector<ParmVarDecl*, 16> Params;
+ for (FunctionProtoType::arg_type_iterator
+ ParamType = OldProto->arg_type_begin(),
+ ParamEnd = OldProto->arg_type_end();
+ ParamType != ParamEnd; ++ParamType) {
+ ParmVarDecl *Param = ParmVarDecl::Create(Context, New,
+ SourceLocation(), 0,
+ *ParamType, VarDecl::None,
+ 0);
+ Param->setImplicit();
+ Params.push_back(Param);
+ }
+
+ New->setParams(Context, Params.data(), Params.size());
+ }
+
+ return MergeCompatibleFunctionDecls(New, Old);
+ }
+
+ // GNU C permits a K&R definition to follow a prototype declaration
+ // if the declared types of the parameters in the K&R definition
+ // match the types in the prototype declaration, even when the
+ // promoted types of the parameters from the K&R definition differ
+ // from the types in the prototype. GCC then keeps the types from
+ // the prototype.
+ //
+ // If a variadic prototype is followed by a non-variadic K&R definition,
+ // the K&R definition becomes variadic. This is sort of an edge case, but
+ // it's legal per the standard depending on how you read C99 6.7.5.3p15 and
+ // C99 6.9.1p8.
+ if (!getLangOptions().CPlusPlus &&
+ Old->hasPrototype() && !New->hasPrototype() &&
+ New->getType()->getAsFunctionProtoType() &&
+ Old->getNumParams() == New->getNumParams()) {
+ llvm::SmallVector<QualType, 16> ArgTypes;
+ llvm::SmallVector<GNUCompatibleParamWarning, 16> Warnings;
+ const FunctionProtoType *OldProto
+ = Old->getType()->getAsFunctionProtoType();
+ const FunctionProtoType *NewProto
+ = New->getType()->getAsFunctionProtoType();
+
+ // Determine whether this is the GNU C extension.
+ QualType MergedReturn = Context.mergeTypes(OldProto->getResultType(),
+ NewProto->getResultType());
+ bool LooseCompatible = !MergedReturn.isNull();
+ for (unsigned Idx = 0, End = Old->getNumParams();
+ LooseCompatible && Idx != End; ++Idx) {
+ ParmVarDecl *OldParm = Old->getParamDecl(Idx);
+ ParmVarDecl *NewParm = New->getParamDecl(Idx);
+ if (Context.typesAreCompatible(OldParm->getType(),
+ NewProto->getArgType(Idx))) {
+ ArgTypes.push_back(NewParm->getType());
+ } else if (Context.typesAreCompatible(OldParm->getType(),
+ NewParm->getType())) {
+ GNUCompatibleParamWarning Warn
+ = { OldParm, NewParm, NewProto->getArgType(Idx) };
+ Warnings.push_back(Warn);
+ ArgTypes.push_back(NewParm->getType());
+ } else
+ LooseCompatible = false;
+ }
+
+ if (LooseCompatible) {
+ for (unsigned Warn = 0; Warn < Warnings.size(); ++Warn) {
+ Diag(Warnings[Warn].NewParm->getLocation(),
+ diag::ext_param_promoted_not_compatible_with_prototype)
+ << Warnings[Warn].PromotedType
+ << Warnings[Warn].OldParm->getType();
+ Diag(Warnings[Warn].OldParm->getLocation(),
+ diag::note_previous_declaration);
+ }
+
+ New->setType(Context.getFunctionType(MergedReturn, &ArgTypes[0],
+ ArgTypes.size(),
+ OldProto->isVariadic(), 0));
+ return MergeCompatibleFunctionDecls(New, Old);
+ }
+
+ // Fall through to diagnose conflicting types.
+ }
+
+ // A function that has already been declared has been redeclared or defined
+ // with a different type- show appropriate diagnostic
+ if (unsigned BuiltinID = Old->getBuiltinID(Context)) {
+ // The user has declared a builtin function with an incompatible
+ // signature.
+ if (Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) {
+ // The function the user is redeclaring is a library-defined
+ // function like 'malloc' or 'printf'. Warn about the
+ // redeclaration, then pretend that we don't know about this
+ // library built-in.
+ Diag(New->getLocation(), diag::warn_redecl_library_builtin) << New;
+ Diag(Old->getLocation(), diag::note_previous_builtin_declaration)
+ << Old << Old->getType();
+ New->getIdentifier()->setBuiltinID(Builtin::NotBuiltin);
+ Old->setInvalidDecl();
+ return false;
+ }
+
+ PrevDiag = diag::note_previous_builtin_declaration;
+ }
+
+ Diag(New->getLocation(), diag::err_conflicting_types) << New->getDeclName();
+ Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
+ return true;
+}
+
+/// \brief Completes the merge of two function declarations that are
+/// known to be compatible.
+///
+/// This routine handles the merging of attributes and other
+/// properties of function declarations form the old declaration to
+/// the new declaration, once we know that New is in fact a
+/// redeclaration of Old.
+///
+/// \returns false
+bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
+ // Merge the attributes
+ MergeAttributes(New, Old, Context);
+
+ // Merge the storage class.
+ if (Old->getStorageClass() != FunctionDecl::Extern)
+ New->setStorageClass(Old->getStorageClass());
+
+ // Merge "inline"
+ if (Old->isInline())
+ New->setInline(true);
+
+ // If this function declaration by itself qualifies as a C99 inline
+ // definition (C99 6.7.4p6), but the previous definition did not,
+ // then the function is not a C99 inline definition.
+ if (New->isC99InlineDefinition() && !Old->isC99InlineDefinition())
+ New->setC99InlineDefinition(false);
+ else if (Old->isC99InlineDefinition() && !New->isC99InlineDefinition()) {
+ // Mark all preceding definitions as not being C99 inline definitions.
+ for (const FunctionDecl *Prev = Old; Prev;
+ Prev = Prev->getPreviousDeclaration())
+ const_cast<FunctionDecl *>(Prev)->setC99InlineDefinition(false);
+ }
+
+ // Merge "pure" flag.
+ if (Old->isPure())
+ New->setPure();
+
+ // Merge the "deleted" flag.
+ if (Old->isDeleted())
+ New->setDeleted();
+
+ if (getLangOptions().CPlusPlus)
+ return MergeCXXFunctionDecl(New, Old);
+
+ return false;
+}
+
+/// MergeVarDecl - We just parsed a variable 'New' which has the same name
+/// and scope as a previous declaration 'Old'. Figure out how to resolve this
+/// situation, merging decls or emitting diagnostics as appropriate.
+///
+/// Tentative definition rules (C99 6.9.2p2) are checked by
+/// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative
+/// definitions here, since the initializer hasn't been attached.
+///
+void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) {
+ // If either decl is invalid, make sure the new one is marked invalid and
+ // don't do any other checking.
+ if (New->isInvalidDecl() || OldD->isInvalidDecl())
+ return New->setInvalidDecl();
+
+ // Verify the old decl was also a variable.
+ VarDecl *Old = dyn_cast<VarDecl>(OldD);
+ if (!Old) {
+ Diag(New->getLocation(), diag::err_redefinition_different_kind)
+ << New->getDeclName();
+ Diag(OldD->getLocation(), diag::note_previous_definition);
+ return New->setInvalidDecl();
+ }
+
+ MergeAttributes(New, Old, Context);
+
+ // Merge the types
+ QualType MergedT;
+ if (getLangOptions().CPlusPlus) {
+ if (Context.hasSameType(New->getType(), Old->getType()))
+ MergedT = New->getType();
+ } else {
+ MergedT = Context.mergeTypes(New->getType(), Old->getType());
+ }
+ if (MergedT.isNull()) {
+ Diag(New->getLocation(), diag::err_redefinition_different_type)
+ << New->getDeclName();
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ return New->setInvalidDecl();
+ }
+ New->setType(MergedT);
+
+ // C99 6.2.2p4: Check if we have a static decl followed by a non-static.
+ if (New->getStorageClass() == VarDecl::Static &&
+ (Old->getStorageClass() == VarDecl::None || Old->hasExternalStorage())) {
+ Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName();
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ return New->setInvalidDecl();
+ }
+ // C99 6.2.2p4:
+ // For an identifier declared with the storage-class specifier
+ // extern in a scope in which a prior declaration of that
+ // identifier is visible,23) if the prior declaration specifies
+ // internal or external linkage, the linkage of the identifier at
+ // the later declaration is the same as the linkage specified at
+ // the prior declaration. If no prior declaration is visible, or
+ // if the prior declaration specifies no linkage, then the
+ // identifier has external linkage.
+ if (New->hasExternalStorage() && Old->hasLinkage())
+ /* Okay */;
+ else if (New->getStorageClass() != VarDecl::Static &&
+ Old->getStorageClass() == VarDecl::Static) {
+ Diag(New->getLocation(), diag::err_non_static_static) << New->getDeclName();
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ return New->setInvalidDecl();
+ }
+
+ // Variables with external linkage are analyzed in FinalizeDeclaratorGroup.
+
+ // FIXME: The test for external storage here seems wrong? We still
+ // need to check for mismatches.
+ if (!New->hasExternalStorage() && !New->isFileVarDecl() &&
+ // Don't complain about out-of-line definitions of static members.
+ !(Old->getLexicalDeclContext()->isRecord() &&
+ !New->getLexicalDeclContext()->isRecord())) {
+ Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName();
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ return New->setInvalidDecl();
+ }
+
+ if (New->isThreadSpecified() && !Old->isThreadSpecified()) {
+ Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName();
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ } else if (!New->isThreadSpecified() && Old->isThreadSpecified()) {
+ Diag(New->getLocation(), diag::err_non_thread_thread) << New->getDeclName();
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ }
+
+ // Keep a chain of previous declarations.
+ New->setPreviousDeclaration(Old);
+}
+
+/// CheckParmsForFunctionDef - Check that the parameters of the given
+/// function are appropriate for the definition of a function. This
+/// takes care of any checks that cannot be performed on the
+/// declaration itself, e.g., that the types of each of the function
+/// parameters are complete.
+bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
+ bool HasInvalidParm = false;
+ for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
+ ParmVarDecl *Param = FD->getParamDecl(p);
+
+ // C99 6.7.5.3p4: the parameters in a parameter type list in a
+ // function declarator that is part of a function definition of
+ // that function shall not have incomplete type.
+ //
+ // This is also C++ [dcl.fct]p6.
+ if (!Param->isInvalidDecl() &&
+ RequireCompleteType(Param->getLocation(), Param->getType(),
+ diag::err_typecheck_decl_incomplete_type)) {
+ Param->setInvalidDecl();
+ HasInvalidParm = true;
+ }
+
+ // C99 6.9.1p5: If the declarator includes a parameter type list, the
+ // declaration of each parameter shall include an identifier.
+ if (Param->getIdentifier() == 0 &&
+ !Param->isImplicit() &&
+ !getLangOptions().CPlusPlus)
+ Diag(Param->getLocation(), diag::err_parameter_name_omitted);
+ }
+
+ return HasInvalidParm;
+}
+
+/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
+/// no declarator (e.g. "struct foo;") is parsed.
+Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
+ // FIXME: Error on auto/register at file scope
+ // FIXME: Error on inline/virtual/explicit
+ // FIXME: Error on invalid restrict
+ // FIXME: Warn on useless __thread
+ // FIXME: Warn on useless const/volatile
+ // FIXME: Warn on useless static/extern/typedef/private_extern/mutable
+ // FIXME: Warn on useless attributes
+ TagDecl *Tag = 0;
+ if (DS.getTypeSpecType() == DeclSpec::TST_class ||
+ DS.getTypeSpecType() == DeclSpec::TST_struct ||
+ DS.getTypeSpecType() == DeclSpec::TST_union ||
+ DS.getTypeSpecType() == DeclSpec::TST_enum) {
+ if (!DS.getTypeRep()) // We probably had an error
+ return DeclPtrTy();
+
+ Tag = dyn_cast<TagDecl>(static_cast<Decl *>(DS.getTypeRep()));
+ }
+
+ if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
+ if (!Record->getDeclName() && Record->isDefinition() &&
+ DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
+ if (getLangOptions().CPlusPlus ||
+ Record->getDeclContext()->isRecord())
+ return BuildAnonymousStructOrUnion(S, DS, Record);
+
+ Diag(DS.getSourceRange().getBegin(), diag::err_no_declarators)
+ << DS.getSourceRange();
+ }
+
+ // Microsoft allows unnamed struct/union fields. Don't complain
+ // about them.
+ // FIXME: Should we support Microsoft's extensions in this area?
+ if (Record->getDeclName() && getLangOptions().Microsoft)
+ return DeclPtrTy::make(Tag);
+ }
+
+ if (!DS.isMissingDeclaratorOk() &&
+ DS.getTypeSpecType() != DeclSpec::TST_error) {
+ // Warn about typedefs of enums without names, since this is an
+ // extension in both Microsoft an GNU.
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef &&
+ Tag && isa<EnumDecl>(Tag)) {
+ Diag(DS.getSourceRange().getBegin(), diag::ext_typedef_without_a_name)
+ << DS.getSourceRange();
+ return DeclPtrTy::make(Tag);
+ }
+
+ Diag(DS.getSourceRange().getBegin(), diag::err_no_declarators)
+ << DS.getSourceRange();
+ return DeclPtrTy();
+ }
+
+ return DeclPtrTy::make(Tag);
+}
+
+/// InjectAnonymousStructOrUnionMembers - Inject the members of the
+/// anonymous struct or union AnonRecord into the owning context Owner
+/// and scope S. This routine will be invoked just after we realize
+/// that an unnamed union or struct is actually an anonymous union or
+/// struct, e.g.,
+///
+/// @code
+/// union {
+/// int i;
+/// float f;
+/// }; // InjectAnonymousStructOrUnionMembers called here to inject i and
+/// // f into the surrounding scope.x
+/// @endcode
+///
+/// This routine is recursive, injecting the names of nested anonymous
+/// structs/unions into the owning context and scope as well.
+bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
+ RecordDecl *AnonRecord) {
+ bool Invalid = false;
+ for (RecordDecl::field_iterator F = AnonRecord->field_begin(Context),
+ FEnd = AnonRecord->field_end(Context);
+ F != FEnd; ++F) {
+ if ((*F)->getDeclName()) {
+ NamedDecl *PrevDecl = LookupQualifiedName(Owner, (*F)->getDeclName(),
+ LookupOrdinaryName, true);
+ if (PrevDecl && !isa<TagDecl>(PrevDecl)) {
+ // C++ [class.union]p2:
+ // The names of the members of an anonymous union shall be
+ // distinct from the names of any other entity in the
+ // scope in which the anonymous union is declared.
+ unsigned diagKind
+ = AnonRecord->isUnion()? diag::err_anonymous_union_member_redecl
+ : diag::err_anonymous_struct_member_redecl;
+ Diag((*F)->getLocation(), diagKind)
+ << (*F)->getDeclName();
+ Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
+ Invalid = true;
+ } else {
+ // C++ [class.union]p2:
+ // For the purpose of name lookup, after the anonymous union
+ // definition, the members of the anonymous union are
+ // considered to have been defined in the scope in which the
+ // anonymous union is declared.
+ Owner->makeDeclVisibleInContext(Context, *F);
+ S->AddDecl(DeclPtrTy::make(*F));
+ IdResolver.AddDecl(*F);
+ }
+ } else if (const RecordType *InnerRecordType
+ = (*F)->getType()->getAsRecordType()) {
+ RecordDecl *InnerRecord = InnerRecordType->getDecl();
+ if (InnerRecord->isAnonymousStructOrUnion())
+ Invalid = Invalid ||
+ InjectAnonymousStructOrUnionMembers(S, Owner, InnerRecord);
+ }
+ }
+
+ return Invalid;
+}
+
+/// ActOnAnonymousStructOrUnion - Handle the declaration of an
+/// anonymous structure or union. Anonymous unions are a C++ feature
+/// (C++ [class.union]) and a GNU C extension; anonymous structures
+/// are a GNU C and GNU C++ extension.
+Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
+ RecordDecl *Record) {
+ DeclContext *Owner = Record->getDeclContext();
+
+ // Diagnose whether this anonymous struct/union is an extension.
+ if (Record->isUnion() && !getLangOptions().CPlusPlus)
+ Diag(Record->getLocation(), diag::ext_anonymous_union);
+ else if (!Record->isUnion())
+ Diag(Record->getLocation(), diag::ext_anonymous_struct);
+
+ // C and C++ require different kinds of checks for anonymous
+ // structs/unions.
+ bool Invalid = false;
+ if (getLangOptions().CPlusPlus) {
+ const char* PrevSpec = 0;
+ // C++ [class.union]p3:
+ // Anonymous unions declared in a named namespace or in the
+ // global namespace shall be declared static.
+ if (DS.getStorageClassSpec() != DeclSpec::SCS_static &&
+ (isa<TranslationUnitDecl>(Owner) ||
+ (isa<NamespaceDecl>(Owner) &&
+ cast<NamespaceDecl>(Owner)->getDeclName()))) {
+ Diag(Record->getLocation(), diag::err_anonymous_union_not_static);
+ Invalid = true;
+
+ // Recover by adding 'static'.
+ DS.SetStorageClassSpec(DeclSpec::SCS_static, SourceLocation(), PrevSpec);
+ }
+ // C++ [class.union]p3:
+ // A storage class is not allowed in a declaration of an
+ // anonymous union in a class scope.
+ else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified &&
+ isa<RecordDecl>(Owner)) {
+ Diag(DS.getStorageClassSpecLoc(),
+ diag::err_anonymous_union_with_storage_spec);
+ Invalid = true;
+
+ // Recover by removing the storage specifier.
+ DS.SetStorageClassSpec(DeclSpec::SCS_unspecified, SourceLocation(),
+ PrevSpec);
+ }
+
+ // C++ [class.union]p2:
+ // The member-specification of an anonymous union shall only
+ // define non-static data members. [Note: nested types and
+ // functions cannot be declared within an anonymous union. ]
+ for (DeclContext::decl_iterator Mem = Record->decls_begin(Context),
+ MemEnd = Record->decls_end(Context);
+ Mem != MemEnd; ++Mem) {
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(*Mem)) {
+ // C++ [class.union]p3:
+ // An anonymous union shall not have private or protected
+ // members (clause 11).
+ if (FD->getAccess() == AS_protected || FD->getAccess() == AS_private) {
+ Diag(FD->getLocation(), diag::err_anonymous_record_nonpublic_member)
+ << (int)Record->isUnion() << (int)(FD->getAccess() == AS_protected);
+ Invalid = true;
+ }
+ } else if ((*Mem)->isImplicit()) {
+ // Any implicit members are fine.
+ } else if (isa<TagDecl>(*Mem) && (*Mem)->getDeclContext() != Record) {
+ // This is a type that showed up in an
+ // elaborated-type-specifier inside the anonymous struct or
+ // union, but which actually declares a type outside of the
+ // anonymous struct or union. It's okay.
+ } else if (RecordDecl *MemRecord = dyn_cast<RecordDecl>(*Mem)) {
+ if (!MemRecord->isAnonymousStructOrUnion() &&
+ MemRecord->getDeclName()) {
+ // This is a nested type declaration.
+ Diag(MemRecord->getLocation(), diag::err_anonymous_record_with_type)
+ << (int)Record->isUnion();
+ Invalid = true;
+ }
+ } else {
+ // We have something that isn't a non-static data
+ // member. Complain about it.
+ unsigned DK = diag::err_anonymous_record_bad_member;
+ if (isa<TypeDecl>(*Mem))
+ DK = diag::err_anonymous_record_with_type;
+ else if (isa<FunctionDecl>(*Mem))
+ DK = diag::err_anonymous_record_with_function;
+ else if (isa<VarDecl>(*Mem))
+ DK = diag::err_anonymous_record_with_static;
+ Diag((*Mem)->getLocation(), DK)
+ << (int)Record->isUnion();
+ Invalid = true;
+ }
+ }
+ }
+
+ if (!Record->isUnion() && !Owner->isRecord()) {
+ Diag(Record->getLocation(), diag::err_anonymous_struct_not_member)
+ << (int)getLangOptions().CPlusPlus;
+ Invalid = true;
+ }
+
+ // Create a declaration for this anonymous struct/union.
+ NamedDecl *Anon = 0;
+ if (RecordDecl *OwningClass = dyn_cast<RecordDecl>(Owner)) {
+ Anon = FieldDecl::Create(Context, OwningClass, Record->getLocation(),
+ /*IdentifierInfo=*/0,
+ Context.getTypeDeclType(Record),
+ /*BitWidth=*/0, /*Mutable=*/false);
+ Anon->setAccess(AS_public);
+ if (getLangOptions().CPlusPlus)
+ FieldCollector->Add(cast<FieldDecl>(Anon));
+ } else {
+ VarDecl::StorageClass SC;
+ switch (DS.getStorageClassSpec()) {
+ default: assert(0 && "Unknown storage class!");
+ case DeclSpec::SCS_unspecified: SC = VarDecl::None; break;
+ case DeclSpec::SCS_extern: SC = VarDecl::Extern; break;
+ case DeclSpec::SCS_static: SC = VarDecl::Static; break;
+ case DeclSpec::SCS_auto: SC = VarDecl::Auto; break;
+ case DeclSpec::SCS_register: SC = VarDecl::Register; break;
+ case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break;
+ case DeclSpec::SCS_mutable:
+ // mutable can only appear on non-static class members, so it's always
+ // an error here
+ Diag(Record->getLocation(), diag::err_mutable_nonmember);
+ Invalid = true;
+ SC = VarDecl::None;
+ break;
+ }
+
+ Anon = VarDecl::Create(Context, Owner, Record->getLocation(),
+ /*IdentifierInfo=*/0,
+ Context.getTypeDeclType(Record),
+ SC, DS.getSourceRange().getBegin());
+ }
+ Anon->setImplicit();
+
+ // Add the anonymous struct/union object to the current
+ // context. We'll be referencing this object when we refer to one of
+ // its members.
+ Owner->addDecl(Context, Anon);
+
+ // Inject the members of the anonymous struct/union into the owning
+ // context and into the identifier resolver chain for name lookup
+ // purposes.
+ if (InjectAnonymousStructOrUnionMembers(S, Owner, Record))
+ Invalid = true;
+
+ // Mark this as an anonymous struct/union type. Note that we do not
+ // do this until after we have already checked and injected the
+ // members of this anonymous struct/union type, because otherwise
+ // the members could be injected twice: once by DeclContext when it
+ // builds its lookup table, and once by
+ // InjectAnonymousStructOrUnionMembers.
+ Record->setAnonymousStructOrUnion(true);
+
+ if (Invalid)
+ Anon->setInvalidDecl();
+
+ return DeclPtrTy::make(Anon);
+}
+
+
+/// GetNameForDeclarator - Determine the full declaration name for the
+/// given Declarator.
+DeclarationName Sema::GetNameForDeclarator(Declarator &D) {
+ switch (D.getKind()) {
+ case Declarator::DK_Abstract:
+ assert(D.getIdentifier() == 0 && "abstract declarators have no name");
+ return DeclarationName();
+
+ case Declarator::DK_Normal:
+ assert (D.getIdentifier() != 0 && "normal declarators have an identifier");
+ return DeclarationName(D.getIdentifier());
+
+ case Declarator::DK_Constructor: {
+ QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
+ Ty = Context.getCanonicalType(Ty);
+ return Context.DeclarationNames.getCXXConstructorName(Ty);
+ }
+
+ case Declarator::DK_Destructor: {
+ QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
+ Ty = Context.getCanonicalType(Ty);
+ return Context.DeclarationNames.getCXXDestructorName(Ty);
+ }
+
+ case Declarator::DK_Conversion: {
+ // FIXME: We'd like to keep the non-canonical type for diagnostics!
+ QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
+ Ty = Context.getCanonicalType(Ty);
+ return Context.DeclarationNames.getCXXConversionFunctionName(Ty);
+ }
+
+ case Declarator::DK_Operator:
+ assert(D.getIdentifier() == 0 && "operator names have no identifier");
+ return Context.DeclarationNames.getCXXOperatorName(
+ D.getOverloadedOperator());
+ }
+
+ assert(false && "Unknown name kind");
+ return DeclarationName();
+}
+
+/// 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,
+ FunctionDecl *Declaration,
+ FunctionDecl *Definition) {
+ 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();
+
+ DeclParamTy = Context.getCanonicalType(DeclParamTy.getNonReferenceType());
+ DefParamTy = Context.getCanonicalType(DefParamTy.getNonReferenceType());
+ if (DeclParamTy.getUnqualifiedType() != DefParamTy.getUnqualifiedType())
+ return false;
+ }
+
+ return true;
+}
+
+Sema::DeclPtrTy
+Sema::ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition) {
+ DeclarationName Name = GetNameForDeclarator(D);
+
+ // All of these full declarators require an identifier. If it doesn't have
+ // one, the ParsedFreeStandingDeclSpec action should be used.
+ if (!Name) {
+ if (!D.isInvalidType()) // Reject this if we think it is valid.
+ Diag(D.getDeclSpec().getSourceRange().getBegin(),
+ diag::err_declarator_need_ident)
+ << D.getDeclSpec().getSourceRange() << D.getSourceRange();
+ return DeclPtrTy();
+ }
+
+ // The scope passed in may not be a decl scope. Zip up the scope tree until
+ // we find one that is.
+ while ((S->getFlags() & Scope::DeclScope) == 0 ||
+ (S->getFlags() & Scope::TemplateParamScope) != 0)
+ S = S->getParent();
+
+ DeclContext *DC;
+ NamedDecl *PrevDecl;
+ NamedDecl *New;
+
+ QualType R = GetTypeForDeclarator(D, S);
+
+ // See if this is a redefinition of a variable in the same scope.
+ if (D.getCXXScopeSpec().isInvalid()) {
+ DC = CurContext;
+ PrevDecl = 0;
+ D.setInvalidType();
+ } else if (!D.getCXXScopeSpec().isSet()) {
+ LookupNameKind NameKind = LookupOrdinaryName;
+
+ // If the declaration we're planning to build will be a function
+ // or object with linkage, then look for another declaration with
+ // linkage (C99 6.2.2p4-5 and C++ [basic.link]p6).
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
+ /* Do nothing*/;
+ else if (R->isFunctionType()) {
+ if (CurContext->isFunctionOrMethod())
+ NameKind = LookupRedeclarationWithLinkage;
+ } else if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern)
+ NameKind = LookupRedeclarationWithLinkage;
+
+ DC = CurContext;
+ PrevDecl = LookupName(S, Name, NameKind, true,
+ D.getDeclSpec().getStorageClassSpec() !=
+ DeclSpec::SCS_static,
+ D.getIdentifierLoc());
+ } else { // Something like "int foo::x;"
+ DC = computeDeclContext(D.getCXXScopeSpec());
+ // FIXME: RequireCompleteDeclContext(D.getCXXScopeSpec()); ?
+ PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true);
+
+ // C++ 7.3.1.2p2:
+ // Members (including explicit specializations of templates) of a named
+ // namespace can also be defined outside that namespace by explicit
+ // qualification of the name being defined, provided that the entity being
+ // defined was already declared in the namespace and the definition appears
+ // after the point of declaration in a namespace that encloses the
+ // declarations namespace.
+ //
+ // Note that we only check the context at this point. We don't yet
+ // have enough information to make sure that PrevDecl is actually
+ // the declaration we want to match. For example, given:
+ //
+ // class X {
+ // void f();
+ // void f(float);
+ // };
+ //
+ // void X::f(int) { } // ill-formed
+ //
+ // In this case, PrevDecl will point to the overload set
+ // containing the two f's declared in X, but neither of them
+ // matches.
+
+ // First check whether we named the global scope.
+ if (isa<TranslationUnitDecl>(DC)) {
+ Diag(D.getIdentifierLoc(), diag::err_invalid_declarator_global_scope)
+ << Name << D.getCXXScopeSpec().getRange();
+ } else if (!CurContext->Encloses(DC)) {
+ // The qualifying scope doesn't enclose the original declaration.
+ // Emit diagnostic based on current scope.
+ SourceLocation L = D.getIdentifierLoc();
+ SourceRange R = D.getCXXScopeSpec().getRange();
+ if (isa<FunctionDecl>(CurContext))
+ Diag(L, diag::err_invalid_declarator_in_function) << Name << R;
+ else
+ Diag(L, diag::err_invalid_declarator_scope)
+ << Name << cast<NamedDecl>(DC) << R;
+ D.setInvalidType();
+ }
+ }
+
+ if (PrevDecl && PrevDecl->isTemplateParameter()) {
+ // Maybe we will complain about the shadowed template parameter.
+ if (!D.isInvalidType())
+ if (DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl))
+ D.setInvalidType();
+
+ // Just pretend that we didn't see the previous declaration.
+ PrevDecl = 0;
+ }
+
+ // 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
+ // typedef (C++ [dcl.typedef]p4).
+ if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag &&
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef)
+ PrevDecl = 0;
+
+ bool Redeclaration = false;
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ New = ActOnTypedefDeclarator(S, D, DC, R, PrevDecl, Redeclaration);
+ } else if (R->isFunctionType()) {
+ New = ActOnFunctionDeclarator(S, D, DC, R, PrevDecl,
+ IsFunctionDefinition, Redeclaration);
+ } else {
+ New = ActOnVariableDeclarator(S, D, DC, R, PrevDecl, Redeclaration);
+ }
+
+ if (New == 0)
+ return DeclPtrTy();
+
+ // If this has an identifier and is not an invalid redeclaration,
+ // add it to the scope stack.
+ if (Name && !(Redeclaration && New->isInvalidDecl()))
+ PushOnScopeChains(New, S);
+
+ return DeclPtrTy::make(New);
+}
+
+/// TryToFixInvalidVariablyModifiedType - Helper method to turn variable array
+/// types into constant array types in certain situations which would otherwise
+/// be errors (for GCC compatibility).
+static QualType TryToFixInvalidVariablyModifiedType(QualType T,
+ ASTContext &Context,
+ bool &SizeIsNegative) {
+ // This method tries to turn a variable array into a constant
+ // array even when the size isn't an ICE. This is necessary
+ // for compatibility with code that depends on gcc's buggy
+ // constant expression folding, like struct {char x[(int)(char*)2];}
+ SizeIsNegative = false;
+
+ if (const PointerType* PTy = dyn_cast<PointerType>(T)) {
+ QualType Pointee = PTy->getPointeeType();
+ QualType FixedType =
+ TryToFixInvalidVariablyModifiedType(Pointee, Context, SizeIsNegative);
+ if (FixedType.isNull()) return FixedType;
+ FixedType = Context.getPointerType(FixedType);
+ FixedType.setCVRQualifiers(T.getCVRQualifiers());
+ return FixedType;
+ }
+
+ const VariableArrayType* VLATy = dyn_cast<VariableArrayType>(T);
+ if (!VLATy)
+ return QualType();
+ // FIXME: We should probably handle this case
+ if (VLATy->getElementType()->isVariablyModifiedType())
+ return QualType();
+
+ Expr::EvalResult EvalResult;
+ if (!VLATy->getSizeExpr() ||
+ !VLATy->getSizeExpr()->Evaluate(EvalResult, Context) ||
+ !EvalResult.Val.isInt())
+ return QualType();
+
+ llvm::APSInt &Res = EvalResult.Val.getInt();
+ if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned()))
+ return Context.getConstantArrayType(VLATy->getElementType(),
+ Res, ArrayType::Normal, 0);
+
+ SizeIsNegative = true;
+ return QualType();
+}
+
+/// \brief Register the given locally-scoped external C declaration so
+/// that it can be found later for redeclarations
+void
+Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, NamedDecl *PrevDecl,
+ Scope *S) {
+ assert(ND->getLexicalDeclContext()->isFunctionOrMethod() &&
+ "Decl is not a locally-scoped decl!");
+ // Note that we have a locally-scoped external with this name.
+ LocallyScopedExternalDecls[ND->getDeclName()] = ND;
+
+ if (!PrevDecl)
+ return;
+
+ // If there was a previous declaration of this variable, it may be
+ // in our identifier chain. Update the identifier chain with the new
+ // declaration.
+ if (S && IdResolver.ReplaceDecl(PrevDecl, ND)) {
+ // The previous declaration was found on the identifer resolver
+ // chain, so remove it from its scope.
+ while (S && !S->isDeclScope(DeclPtrTy::make(PrevDecl)))
+ S = S->getParent();
+
+ if (S)
+ S->RemoveDecl(DeclPtrTy::make(PrevDecl));
+ }
+}
+
+/// \brief Diagnose function specifiers on a declaration of an identifier that
+/// does not identify a function.
+void Sema::DiagnoseFunctionSpecifiers(Declarator& D) {
+ // FIXME: We should probably indicate the identifier in question to avoid
+ // confusion for constructs like "inline int a(), b;"
+ if (D.getDeclSpec().isInlineSpecified())
+ Diag(D.getDeclSpec().getInlineSpecLoc(),
+ diag::err_inline_non_function);
+
+ if (D.getDeclSpec().isVirtualSpecified())
+ Diag(D.getDeclSpec().getVirtualSpecLoc(),
+ diag::err_virtual_non_function);
+
+ if (D.getDeclSpec().isExplicitSpecified())
+ Diag(D.getDeclSpec().getExplicitSpecLoc(),
+ diag::err_explicit_non_function);
+}
+
+NamedDecl*
+Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
+ QualType R, Decl* PrevDecl, bool &Redeclaration) {
+ // Typedef declarators cannot be qualified (C++ [dcl.meaning]p1).
+ if (D.getCXXScopeSpec().isSet()) {
+ Diag(D.getIdentifierLoc(), diag::err_qualified_typedef_declarator)
+ << D.getCXXScopeSpec().getRange();
+ D.setInvalidType();
+ // Pretend we didn't see the scope specifier.
+ DC = 0;
+ }
+
+ if (getLangOptions().CPlusPlus) {
+ // Check that there are no default arguments (C++ only).
+ CheckExtraCXXDefaultArguments(D);
+ }
+
+ DiagnoseFunctionSpecifiers(D);
+
+ if (D.getDeclSpec().isThreadSpecified())
+ Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+
+ TypedefDecl *NewTD = ParseTypedefDecl(S, D, R);
+ if (!NewTD) return 0;
+
+ if (D.isInvalidType())
+ NewTD->setInvalidDecl();
+
+ // Handle attributes prior to checking for duplicates in MergeVarDecl
+ ProcessDeclAttributes(NewTD, D);
+ // Merge the decl with the existing one if appropriate. If the decl is
+ // in an outer scope, it isn't the same thing.
+ if (PrevDecl && isDeclInScope(PrevDecl, DC, S)) {
+ Redeclaration = true;
+ MergeTypeDefDecl(NewTD, PrevDecl);
+ }
+
+ // C99 6.7.7p2: If a typedef name specifies a variably modified type
+ // then it shall have block scope.
+ QualType T = NewTD->getUnderlyingType();
+ if (T->isVariablyModifiedType()) {
+ CurFunctionNeedsScopeChecking = true;
+
+ if (S->getFnParent() == 0) {
+ bool SizeIsNegative;
+ QualType FixedTy =
+ TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative);
+ if (!FixedTy.isNull()) {
+ Diag(D.getIdentifierLoc(), diag::warn_illegal_constant_array_size);
+ NewTD->setUnderlyingType(FixedTy);
+ } else {
+ if (SizeIsNegative)
+ Diag(D.getIdentifierLoc(), diag::err_typecheck_negative_array_size);
+ else if (T->isVariableArrayType())
+ Diag(D.getIdentifierLoc(), diag::err_vla_decl_in_file_scope);
+ else
+ Diag(D.getIdentifierLoc(), diag::err_vm_decl_in_file_scope);
+ NewTD->setInvalidDecl();
+ }
+ }
+ }
+ return NewTD;
+}
+
+/// \brief Determines whether the given declaration is an out-of-scope
+/// previous declaration.
+///
+/// This routine should be invoked when name lookup has found a
+/// previous declaration (PrevDecl) that is not in the scope where a
+/// new declaration by the same name is being introduced. If the new
+/// declaration occurs in a local scope, previous declarations with
+/// linkage may still be considered previous declarations (C99
+/// 6.2.2p4-5, C++ [basic.link]p6).
+///
+/// \param PrevDecl the previous declaration found by name
+/// lookup
+///
+/// \param DC the context in which the new declaration is being
+/// declared.
+///
+/// \returns true if PrevDecl is an out-of-scope previous declaration
+/// for a new delcaration with the same name.
+static bool
+isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
+ ASTContext &Context) {
+ if (!PrevDecl)
+ return 0;
+
+ // FIXME: PrevDecl could be an OverloadedFunctionDecl, in which
+ // case we need to check each of the overloaded functions.
+ if (!PrevDecl->hasLinkage())
+ return false;
+
+ if (Context.getLangOptions().CPlusPlus) {
+ // C++ [basic.link]p6:
+ // If there is a visible declaration of an entity with linkage
+ // having the same name and type, ignoring entities declared
+ // outside the innermost enclosing namespace scope, the block
+ // scope declaration declares that same entity and receives the
+ // linkage of the previous declaration.
+ DeclContext *OuterContext = DC->getLookupContext();
+ if (!OuterContext->isFunctionOrMethod())
+ // This rule only applies to block-scope declarations.
+ return false;
+ else {
+ DeclContext *PrevOuterContext = PrevDecl->getDeclContext();
+ if (PrevOuterContext->isRecord())
+ // We found a member function: ignore it.
+ return false;
+ else {
+ // Find the innermost enclosing namespace for the new and
+ // previous declarations.
+ while (!OuterContext->isFileContext())
+ OuterContext = OuterContext->getParent();
+ while (!PrevOuterContext->isFileContext())
+ PrevOuterContext = PrevOuterContext->getParent();
+
+ // The previous declaration is in a different namespace, so it
+ // isn't the same function.
+ if (OuterContext->getPrimaryContext() !=
+ PrevOuterContext->getPrimaryContext())
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+NamedDecl*
+Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
+ QualType R,NamedDecl* PrevDecl,
+ bool &Redeclaration) {
+ DeclarationName Name = GetNameForDeclarator(D);
+
+ // Check that there are no default arguments (C++ only).
+ if (getLangOptions().CPlusPlus)
+ CheckExtraCXXDefaultArguments(D);
+
+ VarDecl *NewVD;
+ VarDecl::StorageClass SC;
+ switch (D.getDeclSpec().getStorageClassSpec()) {
+ default: assert(0 && "Unknown storage class!");
+ case DeclSpec::SCS_unspecified: SC = VarDecl::None; break;
+ case DeclSpec::SCS_extern: SC = VarDecl::Extern; break;
+ case DeclSpec::SCS_static: SC = VarDecl::Static; break;
+ case DeclSpec::SCS_auto: SC = VarDecl::Auto; break;
+ case DeclSpec::SCS_register: SC = VarDecl::Register; break;
+ case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break;
+ case DeclSpec::SCS_mutable:
+ // mutable can only appear on non-static class members, so it's always
+ // an error here
+ Diag(D.getIdentifierLoc(), diag::err_mutable_nonmember);
+ D.setInvalidType();
+ SC = VarDecl::None;
+ break;
+ }
+
+ IdentifierInfo *II = Name.getAsIdentifierInfo();
+ if (!II) {
+ Diag(D.getIdentifierLoc(), diag::err_bad_variable_name)
+ << Name.getAsString();
+ return 0;
+ }
+
+ DiagnoseFunctionSpecifiers(D);
+
+ if (!DC->isRecord() && S->getFnParent() == 0) {
+ // C99 6.9p2: The storage-class specifiers auto and register shall not
+ // appear in the declaration specifiers in an external declaration.
+ if (SC == VarDecl::Auto || SC == VarDecl::Register) {
+
+ // If this is a register variable with an asm label specified, then this
+ // is a GNU extension.
+ if (SC == VarDecl::Register && D.getAsmLabel())
+ Diag(D.getIdentifierLoc(), diag::err_unsupported_global_register);
+ else
+ Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope);
+ D.setInvalidType();
+ }
+ }
+ if (DC->isRecord() && !CurContext->isRecord()) {
+ // This is an out-of-line definition of a static data member.
+ if (SC == VarDecl::Static) {
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ diag::err_static_out_of_line)
+ << CodeModificationHint::CreateRemoval(
+ SourceRange(D.getDeclSpec().getStorageClassSpecLoc()));
+ } else if (SC == VarDecl::None)
+ SC = VarDecl::Static;
+ }
+
+ // The variable can not
+ NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
+ II, R, SC,
+ // FIXME: Move to DeclGroup...
+ D.getDeclSpec().getSourceRange().getBegin());
+
+ if (D.isInvalidType())
+ NewVD->setInvalidDecl();
+
+ if (D.getDeclSpec().isThreadSpecified()) {
+ if (NewVD->hasLocalStorage())
+ Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global);
+ else if (!Context.Target.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);
+
+ // Handle attributes prior to checking for duplicates in MergeVarDecl
+ ProcessDeclAttributes(NewVD, D);
+
+ // Handle GNU asm-label extension (encoded as an attribute).
+ if (Expr *E = (Expr*) D.getAsmLabel()) {
+ // The parser guarantees this is a string.
+ StringLiteral *SE = cast<StringLiteral>(E);
+ NewVD->addAttr(::new (Context) AsmLabelAttr(std::string(SE->getStrData(),
+ SE->getByteLength())));
+ }
+
+ // If name lookup finds a previous declaration that is not in the
+ // same scope as the new declaration, this may still be an
+ // acceptable redeclaration.
+ if (PrevDecl && !isDeclInScope(PrevDecl, DC, S) &&
+ !(NewVD->hasLinkage() &&
+ isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
+ PrevDecl = 0;
+
+ // Merge the decl with the existing one if appropriate.
+ if (PrevDecl) {
+ if (isa<FieldDecl>(PrevDecl) && D.getCXXScopeSpec().isSet()) {
+ // The user tried to define a non-static data member
+ // out-of-line (C++ [dcl.meaning]p1).
+ Diag(NewVD->getLocation(), diag::err_nonstatic_member_out_of_line)
+ << D.getCXXScopeSpec().getRange();
+ PrevDecl = 0;
+ NewVD->setInvalidDecl();
+ }
+ } else if (D.getCXXScopeSpec().isSet()) {
+ // No previous declaration in the qualifying scope.
+ Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member)
+ << Name << D.getCXXScopeSpec().getRange();
+ NewVD->setInvalidDecl();
+ }
+
+ CheckVariableDeclaration(NewVD, PrevDecl, Redeclaration);
+
+ // If this is a locally-scoped extern C variable, update the map of
+ // such variables.
+ if (CurContext->isFunctionOrMethod() && NewVD->isExternC(Context) &&
+ !NewVD->isInvalidDecl())
+ RegisterLocallyScopedExternCDecl(NewVD, PrevDecl, S);
+
+ return NewVD;
+}
+
+/// \brief Perform semantic checking on a newly-created variable
+/// declaration.
+///
+/// This routine performs all of the type-checking required for a
+/// variable declaration once it has been built. It is used both to
+/// check variables after they have been parsed and their declarators
+/// have been translated into a declaration, and to check variables
+/// that have been instantiated from a template.
+///
+/// Sets NewVD->isInvalidDecl() if an error was encountered.
+void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl,
+ bool &Redeclaration) {
+ // If the decl is already known invalid, don't check it.
+ if (NewVD->isInvalidDecl())
+ return;
+
+ QualType T = NewVD->getType();
+
+ if (T->isObjCInterfaceType()) {
+ Diag(NewVD->getLocation(), diag::err_statically_allocated_object);
+ return NewVD->setInvalidDecl();
+ }
+
+ // The variable can not have an abstract class type.
+ if (RequireNonAbstractType(NewVD->getLocation(), T,
+ diag::err_abstract_type_in_decl,
+ AbstractVariableType))
+ return NewVD->setInvalidDecl();
+
+ // Emit an error if an address space was applied to decl with local storage.
+ // This includes arrays of objects with address space qualifiers, but not
+ // automatic variables that point to other address spaces.
+ // 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();
+ }
+
+ if (NewVD->hasLocalStorage() && T.isObjCGCWeak()
+ && !NewVD->hasAttr<BlocksAttr>())
+ Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local);
+
+ bool isVM = T->isVariablyModifiedType();
+ if (isVM || NewVD->hasAttr<CleanupAttr>())
+ CurFunctionNeedsScopeChecking = true;
+
+ if ((isVM && NewVD->hasLinkage()) ||
+ (T->isVariableArrayType() && NewVD->hasGlobalStorage())) {
+ bool SizeIsNegative;
+ QualType FixedTy =
+ TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative);
+
+ if (FixedTy.isNull() && T->isVariableArrayType()) {
+ const VariableArrayType *VAT = Context.getAsVariableArrayType(T);
+ // FIXME: This won't give the correct result for
+ // int a[10][n];
+ SourceRange SizeRange = VAT->getSizeExpr()->getSourceRange();
+
+ if (NewVD->isFileVarDecl())
+ Diag(NewVD->getLocation(), diag::err_vla_decl_in_file_scope)
+ << SizeRange;
+ else if (NewVD->getStorageClass() == VarDecl::Static)
+ Diag(NewVD->getLocation(), diag::err_vla_decl_has_static_storage)
+ << SizeRange;
+ else
+ Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage)
+ << SizeRange;
+ return NewVD->setInvalidDecl();
+ }
+
+ if (FixedTy.isNull()) {
+ if (NewVD->isFileVarDecl())
+ Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope);
+ else
+ Diag(NewVD->getLocation(), diag::err_vm_decl_has_extern_linkage);
+ return NewVD->setInvalidDecl();
+ }
+
+ Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size);
+ NewVD->setType(FixedTy);
+ }
+
+ if (!PrevDecl && NewVD->isExternC(Context)) {
+ // Since we did not find anything by this name and we're declaring
+ // an extern "C" variable, look for a non-visible extern "C"
+ // declaration with the same name.
+ llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
+ = LocallyScopedExternalDecls.find(NewVD->getDeclName());
+ if (Pos != LocallyScopedExternalDecls.end())
+ PrevDecl = Pos->second;
+ }
+
+ if (T->isVoidType() && !NewVD->hasExternalStorage()) {
+ Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type)
+ << T;
+ return NewVD->setInvalidDecl();
+ }
+
+ if (!NewVD->hasLocalStorage() && NewVD->hasAttr<BlocksAttr>()) {
+ Diag(NewVD->getLocation(), diag::err_block_on_nonlocal);
+ return NewVD->setInvalidDecl();
+ }
+
+ if (isVM && NewVD->hasAttr<BlocksAttr>()) {
+ Diag(NewVD->getLocation(), diag::err_block_on_vm);
+ return NewVD->setInvalidDecl();
+ }
+
+ if (PrevDecl) {
+ Redeclaration = true;
+ MergeVarDecl(NewVD, PrevDecl);
+ }
+}
+
+NamedDecl*
+Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
+ QualType R, NamedDecl* PrevDecl,
+ bool IsFunctionDefinition, bool &Redeclaration) {
+ assert(R.getTypePtr()->isFunctionType());
+
+ DeclarationName Name = GetNameForDeclarator(D);
+ FunctionDecl::StorageClass SC = FunctionDecl::None;
+ switch (D.getDeclSpec().getStorageClassSpec()) {
+ default: assert(0 && "Unknown storage class!");
+ case DeclSpec::SCS_auto:
+ case DeclSpec::SCS_register:
+ case DeclSpec::SCS_mutable:
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ diag::err_typecheck_sclass_func);
+ D.setInvalidType();
+ break;
+ case DeclSpec::SCS_unspecified: SC = FunctionDecl::None; break;
+ case DeclSpec::SCS_extern: SC = FunctionDecl::Extern; break;
+ case DeclSpec::SCS_static: {
+ if (CurContext->getLookupContext()->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 = FunctionDecl::None;
+ } else
+ SC = FunctionDecl::Static;
+ break;
+ }
+ case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break;
+ }
+
+ if (D.getDeclSpec().isThreadSpecified())
+ Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+
+ bool isInline = D.getDeclSpec().isInlineSpecified();
+ bool isVirtual = D.getDeclSpec().isVirtualSpecified();
+ bool isExplicit = D.getDeclSpec().isExplicitSpecified();
+
+ // 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->getAsFunctionType()->getResultType(),
+ diag::err_abstract_type_in_decl,
+ AbstractReturnType))
+ D.setInvalidType();
+
+ // Do not allow returning a objc interface by-value.
+ if (R->getAsFunctionType()->getResultType()->isObjCInterfaceType()) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_object_cannot_be_passed_returned_by_value) << 0
+ << R->getAsFunctionType()->getResultType();
+ D.setInvalidType();
+ }
+
+ bool isVirtualOkay = false;
+ FunctionDecl *NewFD;
+ if (D.getKind() == Declarator::DK_Constructor) {
+ // 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
+ NewFD = CXXConstructorDecl::Create(Context,
+ cast<CXXRecordDecl>(DC),
+ D.getIdentifierLoc(), Name, R,
+ isExplicit, isInline,
+ /*isImplicitlyDeclared=*/false);
+ } else if (D.getKind() == Declarator::DK_Destructor) {
+ // This is a C++ destructor declaration.
+ if (DC->isRecord()) {
+ R = CheckDestructorDeclarator(D, SC);
+
+ NewFD = CXXDestructorDecl::Create(Context,
+ cast<CXXRecordDecl>(DC),
+ D.getIdentifierLoc(), Name, R,
+ isInline,
+ /*isImplicitlyDeclared=*/false);
+
+ isVirtualOkay = true;
+ } 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.getIdentifierLoc(),
+ Name, R, SC, isInline,
+ /*hasPrototype=*/true,
+ // FIXME: Move to DeclGroup...
+ D.getDeclSpec().getSourceRange().getBegin());
+ D.setInvalidType();
+ }
+ } else if (D.getKind() == Declarator::DK_Conversion) {
+ if (!DC->isRecord()) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_conv_function_not_member);
+ return 0;
+ }
+
+ CheckConversionDeclarator(D, R, SC);
+ NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC),
+ D.getIdentifierLoc(), Name, R,
+ isInline, isExplicit);
+
+ 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() == cast<CXXRecordDecl>(DC)->getIdentifier()){
+ Diag(D.getIdentifierLoc(), diag::err_constructor_return_type)
+ << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
+ << SourceRange(D.getIdentifierLoc());
+ return 0;
+ }
+
+ // This is a C++ method declaration.
+ NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
+ D.getIdentifierLoc(), Name, R,
+ (SC == FunctionDecl::Static), isInline);
+
+ isVirtualOkay = (SC != FunctionDecl::Static);
+ } else {
+ // Determine whether the function was written with a
+ // prototype. This true when:
+ // - we're in C++ (where every function has a prototype),
+ // - 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 =
+ getLangOptions().CPlusPlus ||
+ (D.getNumTypeObjects() && D.getTypeObject(0).Fun.hasPrototype) ||
+ (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType());
+
+ NewFD = FunctionDecl::Create(Context, DC,
+ D.getIdentifierLoc(),
+ Name, R, SC, isInline, HasPrototype,
+ // FIXME: Move to DeclGroup...
+ D.getDeclSpec().getSourceRange().getBegin());
+ }
+
+ if (D.isInvalidType())
+ NewFD->setInvalidDecl();
+
+ // Set the lexical context. If the declarator has a C++
+ // scope specifier, the lexical context will be different
+ // from the semantic context.
+ NewFD->setLexicalDeclContext(CurContext);
+
+ // C++ [dcl.fct.spec]p5:
+ // The virtual specifier shall only be used in declarations of
+ // nonstatic class member functions that appear within a
+ // member-specification of a class declaration; see 10.3.
+ //
+ if (isVirtual && !NewFD->isInvalidDecl()) {
+ if (!isVirtualOkay) {
+ Diag(D.getDeclSpec().getVirtualSpecLoc(),
+ diag::err_virtual_non_function);
+ } else if (!CurContext->isRecord()) {
+ // 'virtual' was specified outside of the class.
+ Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class)
+ << CodeModificationHint::CreateRemoval(
+ SourceRange(D.getDeclSpec().getVirtualSpecLoc()));
+ } else {
+ // Okay: Add virtual to the method.
+ cast<CXXMethodDecl>(NewFD)->setVirtualAsWritten(true);
+ CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC);
+ CurClass->setAggregate(false);
+ CurClass->setPOD(false);
+ CurClass->setPolymorphic(true);
+ CurClass->setHasTrivialConstructor(false);
+ }
+ }
+
+ if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD)) {
+ // Look for virtual methods in base classes that this method might override.
+
+ BasePaths Paths;
+ if (LookupInBases(cast<CXXRecordDecl>(DC),
+ MemberLookupCriteria(NewMD), Paths)) {
+ for (BasePaths::decl_iterator I = Paths.found_decls_begin(),
+ E = Paths.found_decls_end(); I != E; ++I) {
+ if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
+ if (!CheckOverridingFunctionReturnType(NewMD, OldMD))
+ NewMD->addOverriddenMethod(OldMD);
+ }
+ }
+ }
+ }
+
+ if (SC == FunctionDecl::Static && isa<CXXMethodDecl>(NewFD) &&
+ !CurContext->isRecord()) {
+ // C++ [class.static]p1:
+ // A data or function member of a class may be declared static
+ // in a class definition, in which case it is a static member of
+ // the class.
+
+ // Complain about the 'static' specifier if it's on an out-of-line
+ // member function definition.
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ diag::err_static_out_of_line)
+ << CodeModificationHint::CreateRemoval(
+ SourceRange(D.getDeclSpec().getStorageClassSpecLoc()));
+ }
+
+ // Handle GNU asm-label extension (encoded as an attribute).
+ if (Expr *E = (Expr*) D.getAsmLabel()) {
+ // The parser guarantees this is a string.
+ StringLiteral *SE = cast<StringLiteral>(E);
+ NewFD->addAttr(::new (Context) AsmLabelAttr(std::string(SE->getStrData(),
+ SE->getByteLength())));
+ }
+
+ // 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;
+ if (D.getNumTypeObjects() > 0) {
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+
+ // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs
+ // function that takes no arguments, not a function that takes a
+ // single void argument.
+ // We let through "const void" here because Sema::GetTypeForDeclarator
+ // already checks for that case.
+ if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
+ FTI.ArgInfo[0].Param &&
+ FTI.ArgInfo[0].Param.getAs<ParmVarDecl>()->getType()->isVoidType()) {
+ // Empty arg list, don't push any params.
+ ParmVarDecl *Param = FTI.ArgInfo[0].Param.getAs<ParmVarDecl>();
+
+ // In C++, the empty parameter-type-list must be spelled "void"; a
+ // typedef of void is not permitted.
+ if (getLangOptions().CPlusPlus &&
+ Param->getType().getUnqualifiedType() != Context.VoidTy)
+ Diag(Param->getLocation(), diag::err_param_typedef_of_void);
+ // FIXME: Leaks decl?
+ } else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) {
+ for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
+ Params.push_back(FTI.ArgInfo[i].Param.getAs<ParmVarDecl>());
+ }
+
+ } else if (const FunctionProtoType *FT = R->getAsFunctionProtoType()) {
+ // When we're declaring a function with a typedef, typeof, etc as in the
+ // following example, we'll need to synthesize (unnamed)
+ // parameters for use in the declaration.
+ //
+ // @code
+ // typedef void fn(int);
+ // fn f;
+ // @endcode
+
+ // Synthesize a parameter for each argument type.
+ for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(),
+ AE = FT->arg_type_end(); AI != AE; ++AI) {
+ ParmVarDecl *Param = ParmVarDecl::Create(Context, DC,
+ SourceLocation(), 0,
+ *AI, VarDecl::None, 0);
+ Param->setImplicit();
+ Params.push_back(Param);
+ }
+ } else {
+ 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(Context, Params.data(), Params.size());
+
+
+
+ // If name lookup finds a previous declaration that is not in the
+ // same scope as the new declaration, this may still be an
+ // acceptable redeclaration.
+ if (PrevDecl && !isDeclInScope(PrevDecl, DC, S) &&
+ !(NewFD->hasLinkage() &&
+ isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
+ PrevDecl = 0;
+
+ // Perform semantic checking on the function declaration.
+ bool OverloadableAttrRequired = false; // FIXME: HACK!
+ CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration,
+ /*FIXME:*/OverloadableAttrRequired);
+
+ if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
+ // An out-of-line member function declaration must also be a
+ // definition (C++ [dcl.meaning]p1).
+ if (!IsFunctionDefinition) {
+ Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
+ << D.getCXXScopeSpec().getRange();
+ NewFD->setInvalidDecl();
+ } else if (!Redeclaration) {
+ // 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)
+ << cast<NamedDecl>(DC) << D.getCXXScopeSpec().getRange();
+ NewFD->setInvalidDecl();
+
+ LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName,
+ true);
+ 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(Context, cast<FunctionDecl>(*Func), NewFD))
+ Diag((*Func)->getLocation(), diag::note_member_def_close_match);
+ }
+
+ PrevDecl = 0;
+ }
+ }
+
+ // Handle attributes. We need to have merged decls when handling attributes
+ // (for example to check for conflicts, etc).
+ // FIXME: This needs to happen before we merge declarations. Then,
+ // let attribute merging cope with attribute conflicts.
+ ProcessDeclAttributes(NewFD, D);
+ AddKnownFunctionAttributes(NewFD);
+
+ if (OverloadableAttrRequired && !NewFD->getAttr<OverloadableAttr>()) {
+ // If a function name is overloadable in C, then every function
+ // with that name must be marked "overloadable".
+ Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
+ << Redeclaration << NewFD;
+ if (PrevDecl)
+ Diag(PrevDecl->getLocation(),
+ diag::note_attribute_overloadable_prev_overload);
+ NewFD->addAttr(::new (Context) OverloadableAttr());
+ }
+
+ // If this is a locally-scoped extern C function, update the
+ // map of such names.
+ if (CurContext->isFunctionOrMethod() && NewFD->isExternC(Context)
+ && !NewFD->isInvalidDecl())
+ RegisterLocallyScopedExternCDecl(NewFD, PrevDecl, S);
+
+ return NewFD;
+}
+
+/// \brief Perform semantic checking of a new function declaration.
+///
+/// Performs semantic analysis of the new function declaration
+/// NewFD. This routine performs all semantic checking that does not
+/// require the actual declarator involved in the declaration, and is
+/// used both for the declaration of functions as they are parsed
+/// (called via ActOnDeclarator) and for the declaration of functions
+/// that have been instantiated via C++ template instantiation (called
+/// via InstantiateDecl).
+///
+/// This sets NewFD->isInvalidDecl() to true if there was an error.
+void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
+ bool &Redeclaration,
+ bool &OverloadableAttrRequired) {
+ // If NewFD is already known erroneous, don't do any of this checking.
+ if (NewFD->isInvalidDecl())
+ 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();
+ }
+
+ // Semantic checking for this function declaration (in isolation).
+ if (getLangOptions().CPlusPlus) {
+ // C++-specific checks.
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {
+ CheckConstructor(Constructor);
+ } else if (isa<CXXDestructorDecl>(NewFD)) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent());
+ Record->setUserDeclaredDestructor(true);
+ // C++ [class]p4: A POD-struct is an aggregate class that has [...] no
+ // user-defined destructor.
+ Record->setPOD(false);
+
+ // C++ [class.dtor]p3: A destructor is trivial if it is an implicitly-
+ // declared destructor.
+ Record->setHasTrivialDestructor(false);
+ } else if (CXXConversionDecl *Conversion
+ = dyn_cast<CXXConversionDecl>(NewFD))
+ ActOnConversionDeclarator(Conversion);
+
+ // Extra checking for C++ overloaded operators (C++ [over.oper]).
+ if (NewFD->isOverloadedOperator() &&
+ CheckOverloadedOperatorDeclaration(NewFD))
+ return NewFD->setInvalidDecl();
+ }
+
+ // C99 6.7.4p6:
+ // [... ] For a function with external linkage, the following
+ // restrictions apply: [...] If all of the file scope declarations
+ // for a function in a translation unit include the inline
+ // function specifier without extern, then the definition in that
+ // translation unit is an inline definition. An inline definition
+ // does not provide an external definition for the function, and
+ // does not forbid an external definition in another translation
+ // unit.
+ //
+ // Here we determine whether this function, in isolation, would be a
+ // C99 inline definition. MergeCompatibleFunctionDecls looks at
+ // previous declarations.
+ if (NewFD->isInline() && getLangOptions().C99 &&
+ NewFD->getStorageClass() == FunctionDecl::None &&
+ NewFD->getDeclContext()->getLookupContext()->isTranslationUnit())
+ NewFD->setC99InlineDefinition(true);
+
+ // Check for a previous declaration of this name.
+ if (!PrevDecl && NewFD->isExternC(Context)) {
+ // Since we did not find anything by this name and we're declaring
+ // an extern "C" function, look for a non-visible extern "C"
+ // declaration with the same name.
+ llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
+ = LocallyScopedExternalDecls.find(NewFD->getDeclName());
+ if (Pos != LocallyScopedExternalDecls.end())
+ PrevDecl = Pos->second;
+ }
+
+ // Merge or overload the declaration with an existing declaration of
+ // the same name, if appropriate.
+ if (PrevDecl) {
+ // Determine whether NewFD is an overload of PrevDecl or
+ // a declaration that requires merging. If it's an overload,
+ // there's no more work to do here; we'll just add the new
+ // function to the scope.
+ OverloadedFunctionDecl::function_iterator MatchedDecl;
+
+ if (!getLangOptions().CPlusPlus &&
+ AllowOverloadingOfFunction(PrevDecl, Context)) {
+ OverloadableAttrRequired = true;
+
+ // Functions marked "overloadable" must have a prototype (that
+ // we can't get through declaration merging).
+ if (!NewFD->getType()->getAsFunctionProtoType()) {
+ Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype)
+ << NewFD;
+ Redeclaration = true;
+
+ // Turn this into a variadic function with no parameters.
+ QualType R = Context.getFunctionType(
+ NewFD->getType()->getAsFunctionType()->getResultType(),
+ 0, 0, true, 0);
+ NewFD->setType(R);
+ return NewFD->setInvalidDecl();
+ }
+ }
+
+ if (PrevDecl &&
+ (!AllowOverloadingOfFunction(PrevDecl, Context) ||
+ !IsOverload(NewFD, PrevDecl, MatchedDecl))) {
+ Redeclaration = true;
+ Decl *OldDecl = PrevDecl;
+
+ // If PrevDecl was an overloaded function, extract the
+ // FunctionDecl that matched.
+ if (isa<OverloadedFunctionDecl>(PrevDecl))
+ OldDecl = *MatchedDecl;
+
+ // NewFD and OldDecl represent declarations that need to be
+ // merged.
+ if (MergeFunctionDecl(NewFD, OldDecl))
+ return NewFD->setInvalidDecl();
+
+ NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
+ }
+ }
+
+ // 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
+ // during delayed parsing anyway.
+ if (getLangOptions().CPlusPlus && !CurContext->isRecord())
+ CheckCXXDefaultArguments(NewFD);
+}
+
+bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
+ // FIXME: Need strict checking. In C89, we need to check for
+ // any assignment, increment, decrement, function-calls, or
+ // commas outside of a sizeof. In C99, it's the same list,
+ // except that the aforementioned are allowed in unevaluated
+ // expressions. Everything else falls under the
+ // "may accept other forms of constant expressions" exception.
+ // (We never end up here for C++, so the constant expression
+ // rules there don't matter.)
+ if (Init->isConstantInitializer(Context))
+ return false;
+ Diag(Init->getExprLoc(), diag::err_init_element_not_constant)
+ << Init->getSourceRange();
+ return true;
+}
+
+void Sema::AddInitializerToDecl(DeclPtrTy dcl, FullExprArg init) {
+ AddInitializerToDecl(dcl, init.release(), /*DirectInit=*/false);
+}
+
+/// AddInitializerToDecl - Adds the initializer Init to the
+/// declaration dcl. If DirectInit is true, this is C++ direct
+/// initialization rather than copy initialization.
+void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
+ Decl *RealDecl = dcl.getAs<Decl>();
+ // If there is no declaration, there was an error parsing it. Just ignore
+ // the initializer.
+ if (RealDecl == 0)
+ return;
+
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
+ // With declarators parsed the way they are, the parser cannot
+ // distinguish between a normal initializer and a pure-specifier.
+ // Thus this grotesque test.
+ IntegerLiteral *IL;
+ Expr *Init = static_cast<Expr *>(init.get());
+ if ((IL = dyn_cast<IntegerLiteral>(Init)) && IL->getValue() == 0 &&
+ Context.getCanonicalType(IL->getType()) == Context.IntTy) {
+ if (Method->isVirtualAsWritten()) {
+ Method->setPure();
+
+ // A class is abstract if at least one function is pure virtual.
+ cast<CXXRecordDecl>(CurContext)->setAbstract(true);
+ } else if (!Method->isInvalidDecl()) {
+ Diag(Method->getLocation(), diag::err_non_virtual_pure)
+ << Method->getDeclName() << Init->getSourceRange();
+ Method->setInvalidDecl();
+ }
+ } else {
+ Diag(Method->getLocation(), diag::err_member_function_initialization)
+ << Method->getDeclName() << Init->getSourceRange();
+ Method->setInvalidDecl();
+ }
+ return;
+ }
+
+ VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl);
+ if (!VDecl) {
+ if (getLangOptions().CPlusPlus &&
+ RealDecl->getLexicalDeclContext()->isRecord() &&
+ isa<NamedDecl>(RealDecl))
+ Diag(RealDecl->getLocation(), diag::err_member_initialization)
+ << cast<NamedDecl>(RealDecl)->getDeclName();
+ else
+ Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
+ RealDecl->setInvalidDecl();
+ return;
+ }
+
+ if (!VDecl->getType()->isArrayType() &&
+ RequireCompleteType(VDecl->getLocation(), VDecl->getType(),
+ diag::err_typecheck_decl_incomplete_type)) {
+ RealDecl->setInvalidDecl();
+ return;
+ }
+
+ const VarDecl *Def = 0;
+ if (VDecl->getDefinition(Def)) {
+ Diag(VDecl->getLocation(), diag::err_redefinition)
+ << VDecl->getDeclName();
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ VDecl->setInvalidDecl();
+ return;
+ }
+
+ // Take ownership of the expression, now that we're sure we have somewhere
+ // to put it.
+ Expr *Init = init.takeAs<Expr>();
+ assert(Init && "missing initializer");
+
+ // Get the decls type and save a reference for later, since
+ // CheckInitializerTypes may change it.
+ QualType DclT = VDecl->getType(), SavT = DclT;
+ if (VDecl->isBlockVarDecl()) {
+ if (VDecl->hasExternalStorage()) { // C99 6.7.8p5
+ Diag(VDecl->getLocation(), diag::err_block_extern_cant_init);
+ VDecl->setInvalidDecl();
+ } else if (!VDecl->isInvalidDecl()) {
+ if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
+ VDecl->getDeclName(), DirectInit))
+ VDecl->setInvalidDecl();
+
+ // C++ 3.6.2p2, allow dynamic initialization of static initializers.
+ // Don't check invalid declarations to avoid emitting useless diagnostics.
+ if (!getLangOptions().CPlusPlus && !VDecl->isInvalidDecl()) {
+ if (VDecl->getStorageClass() == VarDecl::Static) // C99 6.7.8p4.
+ CheckForConstantInitializer(Init, DclT);
+ }
+ }
+ } else if (VDecl->isStaticDataMember() &&
+ VDecl->getLexicalDeclContext()->isRecord()) {
+ // This is an in-class initialization for a static data member, e.g.,
+ //
+ // struct S {
+ // static const int value = 17;
+ // };
+
+ // Attach the initializer
+ VDecl->setInit(Context, Init);
+
+ // C++ [class.mem]p4:
+ // 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.
+ QualType T = VDecl->getType();
+ if (!T->isDependentType() &&
+ (!Context.getCanonicalType(T).isConstQualified() ||
+ !T->isIntegralType())) {
+ Diag(VDecl->getLocation(), diag::err_member_initialization)
+ << VDecl->getDeclName() << Init->getSourceRange();
+ VDecl->setInvalidDecl();
+ } else {
+ // C++ [class.static.data]p4:
+ // If a static data member is of const integral or const
+ // enumeration type, its declaration in the class definition
+ // can specify a constant-initializer which shall be an
+ // integral constant expression (5.19).
+ if (!Init->isTypeDependent() &&
+ !Init->getType()->isIntegralType()) {
+ // We have a non-dependent, non-integral or enumeration type.
+ Diag(Init->getSourceRange().getBegin(),
+ diag::err_in_class_initializer_non_integral_type)
+ << Init->getType() << Init->getSourceRange();
+ VDecl->setInvalidDecl();
+ } else if (!Init->isTypeDependent() && !Init->isValueDependent()) {
+ // Check whether the expression is a constant expression.
+ llvm::APSInt Value;
+ SourceLocation Loc;
+ if (!Init->isIntegerConstantExpr(Value, Context, &Loc)) {
+ Diag(Loc, diag::err_in_class_initializer_non_constant)
+ << Init->getSourceRange();
+ VDecl->setInvalidDecl();
+ } else if (!VDecl->getType()->isDependentType())
+ ImpCastExprToType(Init, VDecl->getType());
+ }
+ }
+ } else if (VDecl->isFileVarDecl()) {
+ if (VDecl->getStorageClass() == VarDecl::Extern)
+ Diag(VDecl->getLocation(), diag::warn_extern_init);
+ if (!VDecl->isInvalidDecl())
+ if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
+ VDecl->getDeclName(), DirectInit))
+ VDecl->setInvalidDecl();
+
+ // C++ 3.6.2p2, allow dynamic initialization of static initializers.
+ // Don't check invalid declarations to avoid emitting useless diagnostics.
+ if (!getLangOptions().CPlusPlus && !VDecl->isInvalidDecl()) {
+ // C99 6.7.8p4. All file scoped initializers need to be constant.
+ CheckForConstantInitializer(Init, DclT);
+ }
+ }
+ // If the type changed, it means we had an incomplete type that was
+ // completed by the initializer. For example:
+ // int ary[] = { 1, 3, 5 };
+ // "ary" transitions from a VariableArrayType to a ConstantArrayType.
+ if (!VDecl->isInvalidDecl() && (DclT != SavT)) {
+ VDecl->setType(DclT);
+ Init->setType(DclT);
+ }
+
+ // Attach the initializer to the decl.
+ VDecl->setInit(Context, Init);
+
+ // If the previous declaration of VDecl was a tentative definition,
+ // remove it from the set of tentative definitions.
+ if (VDecl->getPreviousDeclaration() &&
+ VDecl->getPreviousDeclaration()->isTentativeDefinition(Context)) {
+ llvm::DenseMap<DeclarationName, VarDecl *>::iterator Pos
+ = TentativeDefinitions.find(VDecl->getDeclName());
+ assert(Pos != TentativeDefinitions.end() &&
+ "Unrecorded tentative definition?");
+ TentativeDefinitions.erase(Pos);
+ }
+
+ return;
+}
+
+void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) {
+ Decl *RealDecl = dcl.getAs<Decl>();
+
+ // If there is no declaration, there was an error parsing it. Just ignore it.
+ if (RealDecl == 0)
+ return;
+
+ if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) {
+ QualType Type = Var->getType();
+
+ // Record tentative definitions.
+ if (Var->isTentativeDefinition(Context))
+ TentativeDefinitions[Var->getDeclName()] = Var;
+
+ // C++ [dcl.init.ref]p3:
+ // The initializer can be omitted for a reference only in a
+ // parameter declaration (8.3.5), in the declaration of a
+ // function return type, in the declaration of a class member
+ // within its class declaration (9.2), and where the extern
+ // specifier is explicitly used.
+ if (Type->isReferenceType() && !Var->hasExternalStorage()) {
+ Diag(Var->getLocation(), diag::err_reference_var_requires_init)
+ << Var->getDeclName()
+ << SourceRange(Var->getLocation(), Var->getLocation());
+ Var->setInvalidDecl();
+ return;
+ }
+
+ // C++ [dcl.init]p9:
+ //
+ // If no initializer is specified for an object, and the object
+ // is of (possibly cv-qualified) non-POD class type (or array
+ // thereof), the object shall be default-initialized; if the
+ // object is of const-qualified type, the underlying class type
+ // shall have a user-declared default constructor.
+ if (getLangOptions().CPlusPlus) {
+ QualType InitType = Type;
+ if (const ArrayType *Array = Context.getAsArrayType(Type))
+ InitType = Array->getElementType();
+ if ((!Var->hasExternalStorage() && !Var->isExternC(Context)) &&
+ InitType->isRecordType() && !InitType->isDependentType()) {
+ CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(InitType->getAsRecordType()->getDecl());
+ CXXConstructorDecl *Constructor = 0;
+ if (!RequireCompleteType(Var->getLocation(), InitType,
+ diag::err_invalid_incomplete_type_use))
+ Constructor
+ = PerformInitializationByConstructor(InitType, 0, 0,
+ Var->getLocation(),
+ SourceRange(Var->getLocation(),
+ Var->getLocation()),
+ Var->getDeclName(),
+ IK_Default);
+ if (!Constructor)
+ Var->setInvalidDecl();
+ else if (!RD->hasTrivialConstructor())
+ InitializeVarWithConstructor(Var, Constructor, InitType, 0, 0);
+ }
+ }
+
+#if 0
+ // FIXME: Temporarily disabled because we are not properly parsing
+ // linkage specifications on declarations, e.g.,
+ //
+ // extern "C" const CGPoint CGPointerZero;
+ //
+ // C++ [dcl.init]p9:
+ //
+ // If no initializer is specified for an object, and the
+ // object is of (possibly cv-qualified) non-POD class type (or
+ // array thereof), the object shall be default-initialized; if
+ // the object is of const-qualified type, the underlying class
+ // type shall have a user-declared default
+ // constructor. Otherwise, if no initializer is specified for
+ // an object, the object and its subobjects, if any, have an
+ // indeterminate initial value; if the object or any of its
+ // subobjects are of const-qualified type, the program is
+ // ill-formed.
+ //
+ // This isn't technically an error in C, so we don't diagnose it.
+ //
+ // FIXME: Actually perform the POD/user-defined default
+ // constructor check.
+ if (getLangOptions().CPlusPlus &&
+ Context.getCanonicalType(Type).isConstQualified() &&
+ !Var->hasExternalStorage())
+ Diag(Var->getLocation(), diag::err_const_var_requires_init)
+ << Var->getName()
+ << SourceRange(Var->getLocation(), Var->getLocation());
+#endif
+ }
+}
+
+Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
+ DeclPtrTy *Group,
+ unsigned NumDecls) {
+ llvm::SmallVector<Decl*, 8> Decls;
+
+ if (DS.isTypeSpecOwned())
+ Decls.push_back((Decl*)DS.getTypeRep());
+
+ for (unsigned i = 0; i != NumDecls; ++i)
+ if (Decl *D = Group[i].getAs<Decl>())
+ Decls.push_back(D);
+
+ // Perform semantic analysis that depends on having fully processed both
+ // the declarator and initializer.
+ for (unsigned i = 0, e = Decls.size(); i != e; ++i) {
+ VarDecl *IDecl = dyn_cast<VarDecl>(Decls[i]);
+ if (!IDecl)
+ continue;
+ QualType T = IDecl->getType();
+
+ // Block scope. C99 6.7p7: If an identifier for an object is declared with
+ // no linkage (C99 6.2.2p6), the type for the object shall be complete...
+ if (IDecl->isBlockVarDecl() && !IDecl->hasExternalStorage()) {
+ if (!IDecl->isInvalidDecl() &&
+ RequireCompleteType(IDecl->getLocation(), T,
+ diag::err_typecheck_decl_incomplete_type))
+ IDecl->setInvalidDecl();
+ }
+ // File scope. C99 6.9.2p2: A declaration of an identifier for and
+ // object that has file scope without an initializer, and without a
+ // storage-class specifier or with the storage-class specifier "static",
+ // constitutes a tentative definition. Note: A tentative definition with
+ // external linkage is valid (C99 6.2.2p5).
+ if (IDecl->isTentativeDefinition(Context)) {
+ QualType CheckType = T;
+ unsigned DiagID = diag::err_typecheck_decl_incomplete_type;
+
+ const IncompleteArrayType *ArrayT = Context.getAsIncompleteArrayType(T);
+ if (ArrayT) {
+ CheckType = ArrayT->getElementType();
+ DiagID = diag::err_illegal_decl_array_incomplete_type;
+ }
+
+ if (IDecl->isInvalidDecl()) {
+ // Do nothing with invalid declarations
+ } else if ((ArrayT || IDecl->getStorageClass() == VarDecl::Static) &&
+ RequireCompleteType(IDecl->getLocation(), CheckType, DiagID)) {
+ // C99 6.9.2p3: If the declaration of an identifier for an object is
+ // a tentative definition and has internal linkage (C99 6.2.2p3), the
+ // declared type shall not be an incomplete type.
+ IDecl->setInvalidDecl();
+ }
+ }
+ }
+ return DeclGroupPtrTy::make(DeclGroupRef::Create(Context,
+ Decls.data(), Decls.size()));
+}
+
+
+/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator()
+/// to introduce parameters into function prototype scope.
+Sema::DeclPtrTy
+Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
+ const DeclSpec &DS = D.getDeclSpec();
+
+ // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
+ VarDecl::StorageClass StorageClass = VarDecl::None;
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
+ StorageClass = VarDecl::Register;
+ } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) {
+ Diag(DS.getStorageClassSpecLoc(),
+ diag::err_invalid_storage_class_in_func_decl);
+ D.getMutableDeclSpec().ClearStorageClassSpecs();
+ }
+
+ if (D.getDeclSpec().isThreadSpecified())
+ Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+
+ DiagnoseFunctionSpecifiers(D);
+
+ // Check that there are no default arguments inside the type of this
+ // parameter (C++ only).
+ if (getLangOptions().CPlusPlus)
+ CheckExtraCXXDefaultArguments(D);
+
+ TagDecl *OwnedDecl = 0;
+ QualType parmDeclType = GetTypeForDeclarator(D, S, /*Skip=*/0, &OwnedDecl);
+
+ if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) {
+ // C++ [dcl.fct]p6:
+ // Types shall not be defined in return or parameter types.
+ Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type)
+ << Context.getTypeDeclType(OwnedDecl);
+ }
+
+ // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope.
+ // Can this happen for params? We already checked that they don't conflict
+ // among each other. Here they can only shadow globals, which is ok.
+ IdentifierInfo *II = D.getIdentifier();
+ if (II) {
+ if (NamedDecl *PrevDecl = LookupName(S, II, LookupOrdinaryName)) {
+ if (PrevDecl->isTemplateParameter()) {
+ // Maybe we will complain about the shadowed template parameter.
+ DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
+ // Just pretend that we didn't see the previous declaration.
+ PrevDecl = 0;
+ } else if (S->isDeclScope(DeclPtrTy::make(PrevDecl))) {
+ Diag(D.getIdentifierLoc(), diag::err_param_redefinition) << II;
+
+ // Recover by removing the name
+ II = 0;
+ D.SetIdentifier(0, D.getIdentifierLoc());
+ }
+ }
+ }
+
+ // Parameters can not be abstract class types.
+ // For record types, this is done by the AbstractClassUsageDiagnoser once
+ // the class has been completely parsed.
+ if (!CurContext->isRecord() &&
+ RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType,
+ diag::err_abstract_type_in_decl,
+ AbstractParamType))
+ D.setInvalidType(true);
+
+ QualType T = adjustParameterType(parmDeclType);
+
+ ParmVarDecl *New;
+ if (T == parmDeclType) // parameter type did not need adjustment
+ New = ParmVarDecl::Create(Context, CurContext,
+ D.getIdentifierLoc(), II,
+ parmDeclType, StorageClass,
+ 0);
+ else // keep track of both the adjusted and unadjusted types
+ New = OriginalParmVarDecl::Create(Context, CurContext,
+ D.getIdentifierLoc(), II, T,
+ parmDeclType, StorageClass, 0);
+
+ if (D.isInvalidType())
+ New->setInvalidDecl();
+
+ // Parameter declarators cannot be interface types. All ObjC objects are
+ // passed by reference.
+ if (T->isObjCInterfaceType()) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_object_cannot_be_passed_returned_by_value) << 1 << T;
+ New->setInvalidDecl();
+ }
+
+ // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
+ if (D.getCXXScopeSpec().isSet()) {
+ Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator)
+ << D.getCXXScopeSpec().getRange();
+ New->setInvalidDecl();
+ }
+
+ // Add the parameter declaration into this scope.
+ S->AddDecl(DeclPtrTy::make(New));
+ if (II)
+ IdResolver.AddDecl(New);
+
+ ProcessDeclAttributes(New, D);
+
+ if (New->hasAttr<BlocksAttr>()) {
+ Diag(New->getLocation(), diag::err_block_on_nonlocal);
+ }
+ return DeclPtrTy::make(New);
+}
+
+void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
+ SourceLocation LocAfterDecls) {
+ assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
+ "Not a function declarator!");
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+
+ // Verify 6.9.1p6: 'every identifier in the identifier list shall be declared'
+ // for a K&R function.
+ if (!FTI.hasPrototype) {
+ for (int i = FTI.NumArgs; i != 0; /* decrement in loop */) {
+ --i;
+ if (FTI.ArgInfo[i].Param == 0) {
+ std::string Code = " int ";
+ Code += FTI.ArgInfo[i].Ident->getName();
+ Code += ";\n";
+ Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared)
+ << FTI.ArgInfo[i].Ident
+ << CodeModificationHint::CreateInsertion(LocAfterDecls, Code);
+
+ // Implicitly declare the argument as type 'int' for lack of a better
+ // type.
+ DeclSpec DS;
+ const char* PrevSpec; // unused
+ DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc,
+ PrevSpec);
+ Declarator ParamD(DS, Declarator::KNRTypeListContext);
+ ParamD.SetIdentifier(FTI.ArgInfo[i].Ident, FTI.ArgInfo[i].IdentLoc);
+ FTI.ArgInfo[i].Param = ActOnParamDeclarator(S, ParamD);
+ }
+ }
+ }
+}
+
+Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope,
+ Declarator &D) {
+ assert(getCurFunctionDecl() == 0 && "Function parsing confused");
+ assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
+ "Not a function declarator!");
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+
+ if (FTI.hasPrototype) {
+ // FIXME: Diagnose arguments without names in C.
+ }
+
+ Scope *ParentScope = FnBodyScope->getParent();
+
+ DeclPtrTy DP = ActOnDeclarator(ParentScope, D, /*IsFunctionDefinition=*/true);
+ return ActOnStartOfFunctionDef(FnBodyScope, DP);
+}
+
+Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
+ FunctionDecl *FD = cast<FunctionDecl>(D.getAs<Decl>());
+
+ CurFunctionNeedsScopeChecking = false;
+
+ // See if this is a redefinition.
+ const FunctionDecl *Definition;
+ if (FD->getBody(Context, Definition)) {
+ Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName();
+ Diag(Definition->getLocation(), diag::note_previous_definition);
+ }
+
+ // Builtin functions cannot be defined.
+ if (unsigned BuiltinID = FD->getBuiltinID(Context)) {
+ if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) {
+ Diag(FD->getLocation(), diag::err_builtin_definition) << FD;
+ FD->setInvalidDecl();
+ }
+ }
+
+ // The return type of a function definition must be complete
+ // (C99 6.9.1p3, C++ [dcl.fct]p6).
+ QualType ResultType = FD->getResultType();
+ if (!ResultType->isDependentType() && !ResultType->isVoidType() &&
+ !FD->isInvalidDecl() &&
+ RequireCompleteType(FD->getLocation(), ResultType,
+ diag::err_func_def_incomplete_result))
+ FD->setInvalidDecl();
+
+ // GNU warning -Wmissing-prototypes:
+ // Warn if a global function is defined without a previous
+ // prototype declaration. This warning is issued even if the
+ // definition itself provides a prototype. The aim is to detect
+ // global functions that fail to be declared in header files.
+ if (!FD->isInvalidDecl() && FD->isGlobal() && !isa<CXXMethodDecl>(FD) &&
+ !FD->isMain()) {
+ bool MissingPrototype = true;
+ for (const FunctionDecl *Prev = FD->getPreviousDeclaration();
+ Prev; Prev = Prev->getPreviousDeclaration()) {
+ // Ignore any declarations that occur in function or method
+ // scope, because they aren't visible from the header.
+ if (Prev->getDeclContext()->isFunctionOrMethod())
+ continue;
+
+ MissingPrototype = !Prev->getType()->isFunctionProtoType();
+ break;
+ }
+
+ if (MissingPrototype)
+ Diag(FD->getLocation(), diag::warn_missing_prototype) << FD;
+ }
+
+ if (FnBodyScope)
+ PushDeclContext(FnBodyScope, FD);
+
+ // Check the validity of our function parameters
+ CheckParmsForFunctionDef(FD);
+
+ // Introduce our parameters into the function scope
+ for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
+ ParmVarDecl *Param = FD->getParamDecl(p);
+ Param->setOwningFunction(FD);
+
+ // If this has an identifier, add it to the scope stack.
+ if (Param->getIdentifier() && FnBodyScope)
+ PushOnScopeChains(Param, FnBodyScope);
+ }
+
+ // Checking attributes of current function definition
+ // dllimport attribute.
+ if (FD->getAttr<DLLImportAttr>() && (!FD->getAttr<DLLExportAttr>())) {
+ // dllimport attribute cannot be applied to definition.
+ if (!(FD->getAttr<DLLImportAttr>())->isInherited()) {
+ Diag(FD->getLocation(),
+ diag::err_attribute_can_be_applied_only_to_symbol_declaration)
+ << "dllimport";
+ FD->setInvalidDecl();
+ return DeclPtrTy::make(FD);
+ } else {
+ // If a symbol previously declared dllimport is later defined, the
+ // attribute is ignored in subsequent references, and a warning is
+ // emitted.
+ Diag(FD->getLocation(),
+ diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
+ << FD->getNameAsCString() << "dllimport";
+ }
+ }
+ return DeclPtrTy::make(FD);
+}
+
+Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg) {
+ return ActOnFinishFunctionBody(D, move(BodyArg), false);
+}
+
+Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
+ bool IsInstantiation) {
+ Decl *dcl = D.getAs<Decl>();
+ Stmt *Body = BodyArg.takeAs<Stmt>();
+ if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(dcl)) {
+ FD->setBody(Body);
+ assert(FD == getCurFunctionDecl() && "Function parsing confused");
+ } else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
+ assert(MD == getCurMethodDecl() && "Method parsing confused");
+ MD->setBody(Body);
+ } else {
+ Body->Destroy(Context);
+ return DeclPtrTy();
+ }
+ if (!IsInstantiation)
+ PopDeclContext();
+
+ // Verify and clean out per-function state.
+
+ assert(&getLabelMap() == &FunctionLabelMap && "Didn't pop block right?");
+
+ // Check goto/label use.
+ for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator
+ I = FunctionLabelMap.begin(), E = FunctionLabelMap.end(); I != E; ++I) {
+ LabelStmt *L = I->second;
+
+ // Verify that we have no forward references left. If so, there was a goto
+ // or address of a label taken, but no definition of it. Label fwd
+ // definitions are indicated with a null substmt.
+ if (L->getSubStmt() != 0)
+ continue;
+
+ // Emit error.
+ Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName();
+
+ // At this point, we have gotos that use the bogus label. Stitch it into
+ // the function body so that they aren't leaked and that the AST is well
+ // formed.
+ if (Body == 0) {
+ // The whole function wasn't parsed correctly, just delete this.
+ L->Destroy(Context);
+ continue;
+ }
+
+ // Otherwise, the body is valid: we want to stitch the label decl into the
+ // function somewhere so that it is properly owned and so that the goto
+ // has a valid target. Do this by creating a new compound stmt with the
+ // label in it.
+
+ // Give the label a sub-statement.
+ L->setSubStmt(new (Context) NullStmt(L->getIdentLoc()));
+
+ CompoundStmt *Compound = isa<CXXTryStmt>(Body) ?
+ cast<CXXTryStmt>(Body)->getTryBlock() :
+ cast<CompoundStmt>(Body);
+ std::vector<Stmt*> Elements(Compound->body_begin(), Compound->body_end());
+ Elements.push_back(L);
+ Compound->setStmts(Context, &Elements[0], Elements.size());
+ }
+ FunctionLabelMap.clear();
+
+ if (!Body) return D;
+
+ // Verify that that gotos and switch cases don't jump into scopes illegally.
+ if (CurFunctionNeedsScopeChecking)
+ DiagnoseInvalidJumps(Body);
+
+ // C++ constructors that have function-try-blocks can't have return statements
+ // in the handlers of that block. (C++ [except.handle]p14) Verify this.
+ if (isa<CXXConstructorDecl>(dcl) && isa<CXXTryStmt>(Body))
+ DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
+
+ return D;
+}
+
+/// 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,
+ IdentifierInfo &II, Scope *S) {
+ // Before we produce a declaration for an implicitly defined
+ // function, see whether there was a locally-scoped declaration of
+ // this name as a function or variable. If so, use that
+ // (non-visible) declaration, and complain about it.
+ llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
+ = LocallyScopedExternalDecls.find(&II);
+ if (Pos != LocallyScopedExternalDecls.end()) {
+ Diag(Loc, diag::warn_use_out_of_scope_declaration) << Pos->second;
+ Diag(Pos->second->getLocation(), diag::note_previous_declaration);
+ return Pos->second;
+ }
+
+ // Extension in C99. Legal in C90, but warn about it.
+ if (getLangOptions().C99)
+ Diag(Loc, diag::ext_implicit_function_decl) << &II;
+ else
+ Diag(Loc, diag::warn_implicit_function_decl) << &II;
+
+ // FIXME: handle stuff like:
+ // void foo() { extern float X(); }
+ // void bar() { X(); } <-- implicit decl for X in another scope.
+
+ // Set a Declarator for the implicit definition: int foo();
+ const char *Dummy;
+ DeclSpec DS;
+ bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy);
+ Error = Error; // Silence warning.
+ assert(!Error && "Error setting up implicit decl!");
+ Declarator D(DS, Declarator::BlockContext);
+ D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0,
+ 0, 0, false, SourceLocation(),
+ false, 0,0,0, Loc, D),
+ SourceLocation());
+ D.SetIdentifier(&II, Loc);
+
+ // Insert this function into translation-unit scope.
+
+ DeclContext *PrevDC = CurContext;
+ CurContext = Context.getTranslationUnitDecl();
+
+ FunctionDecl *FD =
+ dyn_cast<FunctionDecl>(ActOnDeclarator(TUScope, D, DeclPtrTy()).getAs<Decl>());
+ FD->setImplicit();
+
+ CurContext = PrevDC;
+
+ AddKnownFunctionAttributes(FD);
+
+ return FD;
+}
+
+/// \brief Adds any function attributes that we know a priori based on
+/// the declaration of this function.
+///
+/// These attributes can apply both to implicitly-declared builtins
+/// (like __builtin___printf_chk) or to library-declared functions
+/// like NSLog or printf.
+void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
+ if (FD->isInvalidDecl())
+ return;
+
+ // If this is a built-in function, map its builtin attributes to
+ // actual attributes.
+ if (unsigned BuiltinID = FD->getBuiltinID(Context)) {
+ // Handle printf-formatting attributes.
+ unsigned FormatIdx;
+ bool HasVAListArg;
+ if (Context.BuiltinInfo.isPrintfLike(BuiltinID, FormatIdx, HasVAListArg)) {
+ if (!FD->getAttr<FormatAttr>())
+ FD->addAttr(::new (Context) FormatAttr("printf", FormatIdx + 1,
+ FormatIdx + 2));
+ }
+
+ // Mark const if we don't care about errno and that is the only
+ // thing preventing the function from being const. This allows
+ // IRgen to use LLVM intrinsics for such functions.
+ if (!getLangOptions().MathErrno &&
+ Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) {
+ if (!FD->getAttr<ConstAttr>())
+ FD->addAttr(::new (Context) ConstAttr());
+ }
+ }
+
+ IdentifierInfo *Name = FD->getIdentifier();
+ if (!Name)
+ return;
+ if ((!getLangOptions().CPlusPlus &&
+ FD->getDeclContext()->isTranslationUnit()) ||
+ (isa<LinkageSpecDecl>(FD->getDeclContext()) &&
+ cast<LinkageSpecDecl>(FD->getDeclContext())->getLanguage() ==
+ LinkageSpecDecl::lang_c)) {
+ // Okay: this could be a libc/libm/Objective-C function we know
+ // about.
+ } else
+ return;
+
+ if (Name->isStr("NSLog") || Name->isStr("NSLogv")) {
+ if (const FormatAttr *Format = FD->getAttr<FormatAttr>()) {
+ // FIXME: We known better than our headers.
+ const_cast<FormatAttr *>(Format)->setType("printf");
+ } else
+ FD->addAttr(::new (Context) FormatAttr("printf", 1, 2));
+ } else if (Name->isStr("asprintf") || Name->isStr("vasprintf")) {
+ if (!FD->getAttr<FormatAttr>())
+ FD->addAttr(::new (Context) FormatAttr("printf", 2, 3));
+ }
+}
+
+TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T) {
+ assert(D.getIdentifier() && "Wrong callback for declspec without declarator");
+ assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
+
+ // Scope manipulation handled by caller.
+ TypedefDecl *NewTD = TypedefDecl::Create(Context, CurContext,
+ D.getIdentifierLoc(),
+ D.getIdentifier(),
+ T);
+
+ if (TagType *TT = dyn_cast<TagType>(T)) {
+ TagDecl *TD = TT->getDecl();
+
+ // If the TagDecl that the TypedefDecl points to is an anonymous decl
+ // keep track of the TypedefDecl.
+ if (!TD->getIdentifier() && !TD->getTypedefForAnonDecl())
+ TD->setTypedefForAnonDecl(NewTD);
+ }
+
+ if (D.isInvalidType())
+ NewTD->setInvalidDecl();
+ return NewTD;
+}
+
+
+/// \brief Determine whether a tag with a given kind is acceptable
+/// as a redeclaration of the given tag declaration.
+///
+/// \returns true if the new tag kind is acceptable, false otherwise.
+bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
+ TagDecl::TagKind NewTag,
+ SourceLocation NewTagLoc,
+ const IdentifierInfo &Name) {
+ // C++ [dcl.type.elab]p3:
+ // The class-key or enum keyword present in the
+ // elaborated-type-specifier shall agree in kind with the
+ // declaration to which the name in theelaborated-type-specifier
+ // refers. This rule also applies to the form of
+ // elaborated-type-specifier that declares a class-name or
+ // friend class since it can be construed as referring to the
+ // definition of the class. Thus, in any
+ // elaborated-type-specifier, the enum keyword shall be used to
+ // refer to an enumeration (7.2), the union class-keyshall be
+ // used to refer to a union (clause 9), and either the class or
+ // struct class-key shall be used to refer to a class (clause 9)
+ // declared using the class or struct class-key.
+ TagDecl::TagKind OldTag = Previous->getTagKind();
+ if (OldTag == NewTag)
+ return true;
+
+ if ((OldTag == TagDecl::TK_struct || OldTag == TagDecl::TK_class) &&
+ (NewTag == TagDecl::TK_struct || NewTag == TagDecl::TK_class)) {
+ // Warn about the struct/class tag mismatch.
+ bool isTemplate = false;
+ if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous))
+ isTemplate = Record->getDescribedClassTemplate();
+
+ Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
+ << (NewTag == TagDecl::TK_class)
+ << isTemplate << &Name
+ << CodeModificationHint::CreateReplacement(SourceRange(NewTagLoc),
+ OldTag == TagDecl::TK_class? "class" : "struct");
+ Diag(Previous->getLocation(), diag::note_previous_use);
+ return true;
+ }
+ return false;
+}
+
+/// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the
+/// former case, Name will be non-null. In the later case, Name will be null.
+/// TagSpec indicates what kind of tag this is. TK indicates whether this is a
+/// reference/declaration/definition of a tag.
+Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
+ SourceLocation KWLoc, const CXXScopeSpec &SS,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ AttributeList *Attr, AccessSpecifier AS,
+ bool &OwnedDecl) {
+ // If this is not a definition, it must have a name.
+ assert((Name != 0 || TK == TK_Definition) &&
+ "Nameless record must be a definition!");
+
+ OwnedDecl = false;
+ TagDecl::TagKind Kind;
+ switch (TagSpec) {
+ default: assert(0 && "Unknown tag type!");
+ case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
+ case DeclSpec::TST_union: Kind = TagDecl::TK_union; break;
+ case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
+ case DeclSpec::TST_enum: Kind = TagDecl::TK_enum; break;
+ }
+
+ DeclContext *SearchDC = CurContext;
+ DeclContext *DC = CurContext;
+ NamedDecl *PrevDecl = 0;
+
+ bool Invalid = false;
+
+ if (Name && SS.isNotEmpty()) {
+ // We have a nested-name tag ('struct foo::bar').
+
+ // Check for invalid 'foo::'.
+ if (SS.isInvalid()) {
+ Name = 0;
+ goto CreateNewDecl;
+ }
+
+ if (RequireCompleteDeclContext(SS))
+ return DeclPtrTy::make((Decl *)0);
+
+ DC = computeDeclContext(SS);
+ SearchDC = DC;
+ // Look-up name inside 'foo::'.
+ PrevDecl
+ = dyn_cast_or_null<TagDecl>(
+ LookupQualifiedName(DC, Name, LookupTagName, true).getAsDecl());
+
+ // A tag 'foo::bar' must already exist.
+ if (PrevDecl == 0) {
+ Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange();
+ Name = 0;
+ Invalid = true;
+ goto CreateNewDecl;
+ }
+ } else if (Name) {
+ // If this is a named struct, check to see if there was a previous forward
+ // declaration or definition.
+ // FIXME: We're looking into outer scopes here, even when we
+ // shouldn't be. Doing so can result in ambiguities that we
+ // shouldn't be diagnosing.
+ LookupResult R = LookupName(S, Name, LookupTagName,
+ /*RedeclarationOnly=*/(TK != TK_Reference));
+ if (R.isAmbiguous()) {
+ DiagnoseAmbiguousLookup(R, Name, NameLoc);
+ // FIXME: This is not best way to recover from case like:
+ //
+ // struct S s;
+ //
+ // causes needless "incomplete type" error later.
+ Name = 0;
+ PrevDecl = 0;
+ Invalid = true;
+ }
+ else
+ PrevDecl = R;
+
+ if (!getLangOptions().CPlusPlus && TK != TK_Reference) {
+ // FIXME: This makes sure that we ignore the contexts associated
+ // with C structs, unions, and enums when looking for a matching
+ // tag declaration or definition. See the similar lookup tweak
+ // in Sema::LookupName; is there a better way to deal with this?
+ while (isa<RecordDecl>(SearchDC) || isa<EnumDecl>(SearchDC))
+ SearchDC = SearchDC->getParent();
+ }
+ }
+
+ if (PrevDecl && PrevDecl->isTemplateParameter()) {
+ // Maybe we will complain about the shadowed template parameter.
+ DiagnoseTemplateParameterShadow(NameLoc, PrevDecl);
+ // Just pretend that we didn't see the previous declaration.
+ PrevDecl = 0;
+ }
+
+ if (PrevDecl) {
+ // Check whether the previous declaration is usable.
+ (void)DiagnoseUseOfDecl(PrevDecl, NameLoc);
+
+ if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
+ // If this is a use of a previous tag, or if the tag is already declared
+ // in the same scope (so that the definition/declaration completes or
+ // rementions the tag), reuse the decl.
+ if (TK == TK_Reference || isDeclInScope(PrevDecl, SearchDC, S)) {
+ // Make sure that this wasn't declared as an enum and now used as a
+ // struct or something similar.
+ if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) {
+ bool SafeToContinue
+ = (PrevTagDecl->getTagKind() != TagDecl::TK_enum &&
+ Kind != TagDecl::TK_enum);
+ if (SafeToContinue)
+ Diag(KWLoc, diag::err_use_with_wrong_tag)
+ << Name
+ << CodeModificationHint::CreateReplacement(SourceRange(KWLoc),
+ PrevTagDecl->getKindName());
+ else
+ Diag(KWLoc, diag::err_use_with_wrong_tag) << Name;
+ Diag(PrevDecl->getLocation(), diag::note_previous_use);
+
+ if (SafeToContinue)
+ Kind = PrevTagDecl->getTagKind();
+ else {
+ // Recover by making this an anonymous redefinition.
+ Name = 0;
+ PrevDecl = 0;
+ Invalid = true;
+ }
+ }
+
+ if (!Invalid) {
+ // If this is a use, just return the declaration we found.
+
+ // FIXME: In the future, return a variant or some other clue
+ // for the consumer of this Decl to know it doesn't own it.
+ // For our current ASTs this shouldn't be a problem, but will
+ // need to be changed with DeclGroups.
+ if (TK == TK_Reference)
+ return DeclPtrTy::make(PrevDecl);
+
+ // Diagnose attempts to redefine a tag.
+ if (TK == TK_Definition) {
+ if (TagDecl *Def = PrevTagDecl->getDefinition(Context)) {
+ Diag(NameLoc, diag::err_redefinition) << Name;
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ // If this is a redefinition, recover by making this
+ // struct be anonymous, which will make any later
+ // references get the previous definition.
+ Name = 0;
+ PrevDecl = 0;
+ Invalid = true;
+ } else {
+ // If the type is currently being defined, complain
+ // about a nested redefinition.
+ TagType *Tag = cast<TagType>(Context.getTagDeclType(PrevTagDecl));
+ if (Tag->isBeingDefined()) {
+ Diag(NameLoc, diag::err_nested_redefinition) << Name;
+ Diag(PrevTagDecl->getLocation(),
+ diag::note_previous_definition);
+ Name = 0;
+ PrevDecl = 0;
+ Invalid = true;
+ }
+ }
+
+ // Okay, this is definition of a previously declared or referenced
+ // tag PrevDecl. We're going to create a new Decl for it.
+ }
+ }
+ // If we get here we have (another) forward declaration or we
+ // have a definition. Just create a new decl.
+ } else {
+ // If we get here, this is a definition of a new tag type in a nested
+ // scope, e.g. "struct foo; void bar() { struct foo; }", just create a
+ // new decl/type. We set PrevDecl to NULL so that the entities
+ // have distinct types.
+ PrevDecl = 0;
+ }
+ // If we get here, we're going to create a new Decl. If PrevDecl
+ // is non-NULL, it's a definition of the tag declared by
+ // PrevDecl. If it's NULL, we have a new definition.
+ } else {
+ // PrevDecl is a namespace, template, or anything else
+ // that lives in the IDNS_Tag identifier namespace.
+ if (isDeclInScope(PrevDecl, SearchDC, S)) {
+ // The tag name clashes with a namespace name, issue an error and
+ // recover by making this tag be anonymous.
+ Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ Name = 0;
+ PrevDecl = 0;
+ Invalid = true;
+ } else {
+ // The existing declaration isn't relevant to us; we're in a
+ // new scope, so clear out the previous declaration.
+ PrevDecl = 0;
+ }
+ }
+ } else if (TK == TK_Reference && SS.isEmpty() && Name &&
+ (Kind != TagDecl::TK_enum || !getLangOptions().CPlusPlus)) {
+ // C++ [basic.scope.pdecl]p5:
+ // -- for an elaborated-type-specifier of the form
+ //
+ // class-key identifier
+ //
+ // if the elaborated-type-specifier is used in the
+ // decl-specifier-seq or parameter-declaration-clause of a
+ // function defined in namespace scope, the identifier is
+ // declared as a class-name in the namespace that contains
+ // the declaration; otherwise, except as a friend
+ // declaration, the identifier is declared in the smallest
+ // non-class, non-function-prototype scope that contains the
+ // declaration.
+ //
+ // C99 6.7.2.3p8 has a similar (but not identical!) provision for
+ // C structs and unions.
+ //
+ // GNU C also supports this behavior as part of its incomplete
+ // enum types extension, while GNU C++ does not.
+ //
+ // Find the context where we'll be declaring the tag.
+ // FIXME: We would like to maintain the current DeclContext as the
+ // lexical context,
+ while (SearchDC->isRecord())
+ SearchDC = SearchDC->getParent();
+
+ // Find the scope where we'll be declaring the tag.
+ while (S->isClassScope() ||
+ (getLangOptions().CPlusPlus && S->isFunctionPrototypeScope()) ||
+ ((S->getFlags() & Scope::DeclScope) == 0) ||
+ (S->getEntity() &&
+ ((DeclContext *)S->getEntity())->isTransparentContext()))
+ S = S->getParent();
+ }
+
+CreateNewDecl:
+
+ // If there is an identifier, use the location of the identifier as the
+ // location of the decl, otherwise use the location of the struct/union
+ // keyword.
+ SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc;
+
+ // Otherwise, create a new declaration. If there is a previous
+ // declaration of the same entity, the two will be linked via
+ // PrevDecl.
+ TagDecl *New;
+
+ if (Kind == TagDecl::TK_enum) {
+ // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
+ // enum X { A, B, C } D; D should chain to X.
+ New = EnumDecl::Create(Context, SearchDC, Loc, Name,
+ cast_or_null<EnumDecl>(PrevDecl));
+ // If this is an undefined enum, warn.
+ if (TK != TK_Definition && !Invalid) {
+ unsigned DK = getLangOptions().CPlusPlus? diag::err_forward_ref_enum
+ : diag::ext_forward_ref_enum;
+ Diag(Loc, DK);
+ }
+ } else {
+ // struct/union/class
+
+ // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
+ // struct X { int A; } D; D should chain to X.
+ if (getLangOptions().CPlusPlus)
+ // FIXME: Look for a way to use RecordDecl for simple structs.
+ New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name,
+ cast_or_null<CXXRecordDecl>(PrevDecl));
+ else
+ New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name,
+ cast_or_null<RecordDecl>(PrevDecl));
+ }
+
+ if (Kind != TagDecl::TK_enum) {
+ // Handle #pragma pack: if the #pragma pack stack has non-default
+ // alignment, make up a packed attribute for this decl. These
+ // attributes are checked when the ASTContext lays out the
+ // structure.
+ //
+ // It is important for implementing the correct semantics that this
+ // happen here (in act on tag decl). The #pragma pack stack is
+ // maintained as a result of parser callbacks which can occur at
+ // many points during the parsing of a struct declaration (because
+ // the #pragma tokens are effectively skipped over during the
+ // parsing of the struct).
+ if (unsigned Alignment = getPragmaPackAlignment())
+ New->addAttr(::new (Context) PackedAttr(Alignment * 8));
+ }
+
+ if (getLangOptions().CPlusPlus && SS.isEmpty() && Name && !Invalid) {
+ // C++ [dcl.typedef]p3:
+ // [...] Similarly, in a given scope, a class or enumeration
+ // shall not be declared with the same name as a typedef-name
+ // that is declared in that scope and refers to a type other
+ // than the class or enumeration itself.
+ LookupResult Lookup = LookupName(S, Name, LookupOrdinaryName, true);
+ TypedefDecl *PrevTypedef = 0;
+ if (Lookup.getKind() == LookupResult::Found)
+ PrevTypedef = dyn_cast<TypedefDecl>(Lookup.getAsDecl());
+
+ if (PrevTypedef && isDeclInScope(PrevTypedef, SearchDC, S) &&
+ Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) !=
+ Context.getCanonicalType(Context.getTypeDeclType(New))) {
+ Diag(Loc, diag::err_tag_definition_of_typedef)
+ << Context.getTypeDeclType(New)
+ << PrevTypedef->getUnderlyingType();
+ Diag(PrevTypedef->getLocation(), diag::note_previous_definition);
+ Invalid = true;
+ }
+ }
+
+ if (Invalid)
+ New->setInvalidDecl();
+
+ if (Attr)
+ ProcessDeclAttributeList(New, Attr);
+
+ // If we're declaring or defining a tag in function prototype scope
+ // in C, note that this type can only be used within the function.
+ if (Name && S->isFunctionPrototypeScope() && !getLangOptions().CPlusPlus)
+ Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New);
+
+ // Set the lexical context. If the tag has a C++ scope specifier, the
+ // lexical context will be different from the semantic context.
+ New->setLexicalDeclContext(CurContext);
+
+ // Set the access specifier.
+ if (!Invalid)
+ SetMemberAccessSpecifier(New, PrevDecl, AS);
+
+ if (TK == TK_Definition)
+ New->startDefinition();
+
+ // If this has an identifier, add it to the scope stack.
+ if (Name) {
+ S = getNonFieldDeclScope(S);
+ PushOnScopeChains(New, S);
+ } else {
+ CurContext->addDecl(Context, New);
+ }
+
+ OwnedDecl = true;
+ return DeclPtrTy::make(New);
+}
+
+void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) {
+ AdjustDeclIfTemplate(TagD);
+ TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>());
+
+ // Enter the tag context.
+ PushDeclContext(S, Tag);
+
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Tag)) {
+ FieldCollector->StartClass();
+
+ if (Record->getIdentifier()) {
+ // C++ [class]p2:
+ // [...] The class-name is also inserted into the scope of the
+ // class itself; this is known as the injected-class-name. For
+ // purposes of access checking, the injected-class-name is treated
+ // as if it were a public member name.
+ CXXRecordDecl *InjectedClassName
+ = CXXRecordDecl::Create(Context, Record->getTagKind(),
+ CurContext, Record->getLocation(),
+ Record->getIdentifier(), Record);
+ InjectedClassName->setImplicit();
+ InjectedClassName->setAccess(AS_public);
+ if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate())
+ InjectedClassName->setDescribedClassTemplate(Template);
+ PushOnScopeChains(InjectedClassName, S);
+ assert(InjectedClassName->isInjectedClassName() &&
+ "Broken injected-class-name");
+ }
+ }
+}
+
+void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD) {
+ AdjustDeclIfTemplate(TagD);
+ TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>());
+
+ if (isa<CXXRecordDecl>(Tag))
+ FieldCollector->FinishClass();
+
+ // Exit this scope of this tag's definition.
+ PopDeclContext();
+
+ // Notify the consumer that we've defined a tag.
+ Consumer.HandleTagDeclDefinition(Tag);
+}
+
+// Note that FieldName may be null for anonymous bitfields.
+bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
+ QualType FieldTy, const Expr *BitWidth) {
+
+ // C99 6.7.2.1p4 - verify the field type.
+ // C++ 9.6p3: A bit-field shall have integral or enumeration type.
+ if (!FieldTy->isDependentType() && !FieldTy->isIntegralType()) {
+ // Handle incomplete types with specific error.
+ if (RequireCompleteType(FieldLoc, FieldTy, diag::err_field_incomplete))
+ return true;
+ if (FieldName)
+ return Diag(FieldLoc, diag::err_not_integral_type_bitfield)
+ << FieldName << FieldTy << BitWidth->getSourceRange();
+ return Diag(FieldLoc, diag::err_not_integral_type_anon_bitfield)
+ << FieldTy << BitWidth->getSourceRange();
+ }
+
+ // If the bit-width is type- or value-dependent, don't try to check
+ // it now.
+ if (BitWidth->isValueDependent() || BitWidth->isTypeDependent())
+ return false;
+
+ llvm::APSInt Value;
+ if (VerifyIntegerConstantExpression(BitWidth, &Value))
+ return true;
+
+ // Zero-width bitfield is ok for anonymous field.
+ if (Value == 0 && FieldName)
+ return Diag(FieldLoc, diag::err_bitfield_has_zero_width) << FieldName;
+
+ if (Value.isSigned() && Value.isNegative()) {
+ if (FieldName)
+ return Diag(FieldLoc, diag::err_bitfield_has_negative_width)
+ << FieldName << Value.toString(10);
+ return Diag(FieldLoc, diag::err_anon_bitfield_has_negative_width)
+ << Value.toString(10);
+ }
+
+ if (!FieldTy->isDependentType()) {
+ uint64_t TypeSize = Context.getTypeSize(FieldTy);
+ if (Value.getZExtValue() > TypeSize) {
+ if (FieldName)
+ return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size)
+ << FieldName << (unsigned)TypeSize;
+ return Diag(FieldLoc, diag::err_anon_bitfield_width_exceeds_type_size)
+ << (unsigned)TypeSize;
+ }
+ }
+
+ return false;
+}
+
+/// ActOnField - Each field of a struct/union/class is passed into this in order
+/// to create a FieldDecl object for it.
+Sema::DeclPtrTy Sema::ActOnField(Scope *S, DeclPtrTy TagD,
+ SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth) {
+ FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD.getAs<Decl>()),
+ DeclStart, D, static_cast<Expr*>(BitfieldWidth),
+ AS_public);
+ return DeclPtrTy::make(Res);
+}
+
+/// HandleField - Analyze a field of a C struct or a C++ data member.
+///
+FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
+ SourceLocation DeclStart,
+ Declarator &D, Expr *BitWidth,
+ AccessSpecifier AS) {
+ IdentifierInfo *II = D.getIdentifier();
+ SourceLocation Loc = DeclStart;
+ if (II) Loc = D.getIdentifierLoc();
+
+ QualType T = GetTypeForDeclarator(D, S);
+ if (getLangOptions().CPlusPlus)
+ CheckExtraCXXDefaultArguments(D);
+
+ DiagnoseFunctionSpecifiers(D);
+
+ if (D.getDeclSpec().isThreadSpecified())
+ Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+
+ NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true);
+ if (PrevDecl && !isDeclInScope(PrevDecl, Record, S))
+ PrevDecl = 0;
+
+ FieldDecl *NewFD
+ = CheckFieldDecl(II, T, Record, Loc,
+ D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable,
+ BitWidth, AS, PrevDecl, &D);
+ if (NewFD->isInvalidDecl() && PrevDecl) {
+ // Don't introduce NewFD into scope; there's already something
+ // with the same name in the same scope.
+ } else if (II) {
+ PushOnScopeChains(NewFD, S);
+ } else
+ Record->addDecl(Context, NewFD);
+
+ return NewFD;
+}
+
+/// \brief Build a new FieldDecl and check its well-formedness.
+///
+/// This routine builds a new FieldDecl given the fields name, type,
+/// record, etc. \p PrevDecl should refer to any previous declaration
+/// with the same name and in the same scope as the field to be
+/// created.
+///
+/// \returns a new FieldDecl.
+///
+/// \todo The Declarator argument is a hack. It will be removed once
+FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
+ RecordDecl *Record, SourceLocation Loc,
+ bool Mutable, Expr *BitWidth,
+ AccessSpecifier AS, NamedDecl *PrevDecl,
+ Declarator *D) {
+ IdentifierInfo *II = Name.getAsIdentifierInfo();
+ bool InvalidDecl = false;
+ if (D) InvalidDecl = D->isInvalidType();
+
+ // If we receive a broken type, recover by assuming 'int' and
+ // marking this declaration as invalid.
+ if (T.isNull()) {
+ InvalidDecl = true;
+ T = Context.IntTy;
+ }
+
+ // C99 6.7.2.1p8: A member of a structure or union may have any type other
+ // than a variably modified type.
+ if (T->isVariablyModifiedType()) {
+ bool SizeIsNegative;
+ QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context,
+ SizeIsNegative);
+ if (!FixedTy.isNull()) {
+ Diag(Loc, diag::warn_illegal_constant_array_size);
+ T = FixedTy;
+ } else {
+ if (SizeIsNegative)
+ Diag(Loc, diag::err_typecheck_negative_array_size);
+ else
+ Diag(Loc, diag::err_typecheck_field_variable_size);
+ T = Context.IntTy;
+ InvalidDecl = true;
+ }
+ }
+
+ // Fields can not have abstract class types
+ if (RequireNonAbstractType(Loc, T, diag::err_abstract_type_in_decl,
+ AbstractFieldType))
+ InvalidDecl = true;
+
+ // If this is declared as a bit-field, check the bit-field.
+ if (BitWidth && VerifyBitField(Loc, II, T, BitWidth)) {
+ InvalidDecl = true;
+ DeleteExpr(BitWidth);
+ BitWidth = 0;
+ }
+
+ FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, BitWidth,
+ Mutable);
+ if (InvalidDecl)
+ NewFD->setInvalidDecl();
+
+ if (PrevDecl && !isa<TagDecl>(PrevDecl)) {
+ Diag(Loc, diag::err_duplicate_member) << II;
+ Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
+ NewFD->setInvalidDecl();
+ }
+
+ if (getLangOptions().CPlusPlus && !T->isPODType())
+ cast<CXXRecordDecl>(Record)->setPOD(false);
+
+ // FIXME: We need to pass in the attributes given an AST
+ // representation, not a parser representation.
+ if (D)
+ ProcessDeclAttributes(NewFD, *D);
+
+ if (T.isObjCGCWeak())
+ Diag(Loc, diag::warn_attribute_weak_on_field);
+
+ NewFD->setAccess(AS);
+
+ // 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).
+ // A POD must be an aggregate.
+ if (getLangOptions().CPlusPlus &&
+ (AS == AS_private || AS == AS_protected)) {
+ CXXRecordDecl *CXXRecord = cast<CXXRecordDecl>(Record);
+ CXXRecord->setAggregate(false);
+ CXXRecord->setPOD(false);
+ }
+
+ return NewFD;
+}
+
+/// TranslateIvarVisibility - Translate visibility from a token ID to an
+/// AST enum value.
+static ObjCIvarDecl::AccessControl
+TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) {
+ switch (ivarVisibility) {
+ default: assert(0 && "Unknown visitibility kind");
+ case tok::objc_private: return ObjCIvarDecl::Private;
+ case tok::objc_public: return ObjCIvarDecl::Public;
+ case tok::objc_protected: return ObjCIvarDecl::Protected;
+ case tok::objc_package: return ObjCIvarDecl::Package;
+ }
+}
+
+/// ActOnIvar - Each ivar field of an objective-c class is passed into this
+/// in order to create an IvarDecl object for it.
+Sema::DeclPtrTy Sema::ActOnIvar(Scope *S,
+ SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth,
+ tok::ObjCKeywordKind Visibility) {
+
+ IdentifierInfo *II = D.getIdentifier();
+ Expr *BitWidth = (Expr*)BitfieldWidth;
+ SourceLocation Loc = DeclStart;
+ if (II) Loc = D.getIdentifierLoc();
+
+ // FIXME: Unnamed fields can be handled in various different ways, for
+ // example, unnamed unions inject all members into the struct namespace!
+
+ QualType T = GetTypeForDeclarator(D, S);
+
+ if (BitWidth) {
+ // 6.7.2.1p3, 6.7.2.1p4
+ if (VerifyBitField(Loc, II, T, BitWidth)) {
+ D.setInvalidType();
+ DeleteExpr(BitWidth);
+ BitWidth = 0;
+ }
+ } else {
+ // Not a bitfield.
+
+ // validate II.
+
+ }
+
+ // C99 6.7.2.1p8: A member of a structure or union may have any type other
+ // than a variably modified type.
+ if (T->isVariablyModifiedType()) {
+ Diag(Loc, diag::err_typecheck_ivar_variable_size);
+ D.setInvalidType();
+ }
+
+ // Get the visibility (access control) for this ivar.
+ ObjCIvarDecl::AccessControl ac =
+ Visibility != tok::objc_not_keyword ? TranslateIvarVisibility(Visibility)
+ : ObjCIvarDecl::None;
+
+ // Construct the decl.
+ ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, CurContext, Loc, II, T,ac,
+ (Expr *)BitfieldWidth);
+
+ if (II) {
+ NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true);
+ if (PrevDecl && isDeclInScope(PrevDecl, CurContext, S)
+ && !isa<TagDecl>(PrevDecl)) {
+ Diag(Loc, diag::err_duplicate_member) << II;
+ Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
+ NewID->setInvalidDecl();
+ }
+ }
+
+ // Process attributes attached to the ivar.
+ ProcessDeclAttributes(NewID, D);
+
+ if (D.isInvalidType())
+ NewID->setInvalidDecl();
+
+ if (II) {
+ // FIXME: When interfaces are DeclContexts, we'll need to add
+ // these to the interface.
+ S->AddDecl(DeclPtrTy::make(NewID));
+ IdResolver.AddDecl(NewID);
+ }
+
+ return DeclPtrTy::make(NewID);
+}
+
+void Sema::ActOnFields(Scope* S,
+ SourceLocation RecLoc, DeclPtrTy RecDecl,
+ DeclPtrTy *Fields, unsigned NumFields,
+ SourceLocation LBrac, SourceLocation RBrac,
+ AttributeList *Attr) {
+ Decl *EnclosingDecl = RecDecl.getAs<Decl>();
+ 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?
+ return;
+ }
+
+
+ // Verify that all the fields are okay.
+ unsigned NumNamedMembers = 0;
+ llvm::SmallVector<FieldDecl*, 32> RecFields;
+
+ RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
+ for (unsigned i = 0; i != NumFields; ++i) {
+ FieldDecl *FD = cast<FieldDecl>(Fields[i].getAs<Decl>());
+
+ // Get the type for the field.
+ Type *FDTy = FD->getType().getTypePtr();
+
+ if (!FD->isAnonymousStructOrUnion()) {
+ // Remember all fields written by the user.
+ RecFields.push_back(FD);
+ }
+
+ // If the field is already invalid for some reason, don't emit more
+ // diagnostics about it.
+ if (FD->isInvalidDecl())
+ continue;
+
+ // C99 6.7.2.1p2:
+ // A structure or union shall not contain a member with
+ // incomplete or function type (hence, a structure shall not
+ // contain an instance of itself, but may contain a pointer to
+ // an instance of itself), except that the last member of a
+ // structure with more than one named member may have incomplete
+ // array type; such a structure (and any union containing,
+ // possibly recursively, a member that is such a structure)
+ // shall not be a member of a structure or an element of an
+ // array.
+ if (FDTy->isFunctionType()) {
+ // Field declared as a function.
+ Diag(FD->getLocation(), diag::err_field_declared_as_function)
+ << FD->getDeclName();
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ } else if (FDTy->isIncompleteArrayType() && i == NumFields - 1 &&
+ Record && Record->isStruct()) {
+ // Flexible array member.
+ if (NumNamedMembers < 1) {
+ Diag(FD->getLocation(), diag::err_flexible_array_empty_struct)
+ << FD->getDeclName();
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ }
+ // Okay, we have a legal flexible array member at the end of the struct.
+ if (Record)
+ Record->setHasFlexibleArrayMember(true);
+ } else if (!FDTy->isDependentType() &&
+ RequireCompleteType(FD->getLocation(), FD->getType(),
+ diag::err_field_incomplete)) {
+ // Incomplete type
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ } else if (const RecordType *FDTTy = FDTy->getAsRecordType()) {
+ if (FDTTy->getDecl()->hasFlexibleArrayMember()) {
+ // If this is a member of a union, then entire union becomes "flexible".
+ if (Record && Record->isUnion()) {
+ Record->setHasFlexibleArrayMember(true);
+ } else {
+ // 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)
+ Diag(FD->getLocation(), diag::ext_variable_sized_type_in_struct)
+ << FD->getDeclName() << FD->getType();
+ else {
+ // We support flexible arrays at the end of structs in
+ // other structs as an extension.
+ Diag(FD->getLocation(), diag::ext_flexible_array_in_struct)
+ << FD->getDeclName();
+ if (Record)
+ Record->setHasFlexibleArrayMember(true);
+ }
+ }
+ }
+ } else if (FDTy->isObjCInterfaceType()) {
+ /// A field cannot be an Objective-c object
+ Diag(FD->getLocation(), diag::err_statically_allocated_object);
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ }
+ // Keep track of the number of named members.
+ if (FD->getIdentifier())
+ ++NumNamedMembers;
+ }
+
+ // Okay, we successfully defined 'Record'.
+ if (Record) {
+ Record->completeDefinition(Context);
+ } else {
+ ObjCIvarDecl **ClsFields =
+ reinterpret_cast<ObjCIvarDecl**>(RecFields.data());
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(EnclosingDecl)) {
+ ID->setIVarList(ClsFields, RecFields.size(), Context);
+ ID->setLocEnd(RBrac);
+
+ // Must enforce the rule that ivars in the base classes may not be
+ // duplicates.
+ if (ID->getSuperClass()) {
+ for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(),
+ IVE = ID->ivar_end(); IVI != IVE; ++IVI) {
+ ObjCIvarDecl* Ivar = (*IVI);
+
+ if (IdentifierInfo *II = Ivar->getIdentifier()) {
+ ObjCIvarDecl* prevIvar =
+ ID->getSuperClass()->lookupInstanceVariable(Context, II);
+ if (prevIvar) {
+ Diag(Ivar->getLocation(), diag::err_duplicate_member) << II;
+ Diag(prevIvar->getLocation(), diag::note_previous_declaration);
+ }
+ }
+ }
+ }
+ } else if (ObjCImplementationDecl *IMPDecl =
+ dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) {
+ assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl");
+ for (unsigned I = 0, N = RecFields.size(); I != N; ++I) {
+ // FIXME: Set the DeclContext correctly when we build the
+ // declarations.
+ ClsFields[I]->setLexicalDeclContext(IMPDecl);
+ IMPDecl->addDecl(Context, ClsFields[I]);
+ }
+ CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac);
+ }
+ }
+
+ if (Attr)
+ ProcessDeclAttributeList(Record, Attr);
+}
+
+EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
+ EnumConstantDecl *LastEnumConst,
+ SourceLocation IdLoc,
+ IdentifierInfo *Id,
+ ExprArg val) {
+ Expr *Val = (Expr *)val.get();
+
+ llvm::APSInt EnumVal(32);
+ QualType EltTy;
+ if (Val && !Val->isTypeDependent()) {
+ // Make sure to promote the operand type to int.
+ UsualUnaryConversions(Val);
+ if (Val != val.get()) {
+ val.release();
+ val = Val;
+ }
+
+ // C99 6.7.2.2p2: Make sure we have an integer constant expression.
+ SourceLocation ExpLoc;
+ if (!Val->isValueDependent() &&
+ VerifyIntegerConstantExpression(Val, &EnumVal)) {
+ Val = 0;
+ } else {
+ EltTy = Val->getType();
+ }
+ }
+
+ if (!Val) {
+ if (LastEnumConst) {
+ // Assign the last value + 1.
+ EnumVal = LastEnumConst->getInitVal();
+ ++EnumVal;
+
+ // Check for overflow on increment.
+ if (EnumVal < LastEnumConst->getInitVal())
+ Diag(IdLoc, diag::warn_enum_value_overflow);
+
+ EltTy = LastEnumConst->getType();
+ } else {
+ // First value, set to zero.
+ EltTy = Context.IntTy;
+ EnumVal.zextOrTrunc(static_cast<uint32_t>(Context.getTypeSize(EltTy)));
+ }
+ }
+
+ val.release();
+ return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy,
+ Val, EnumVal);
+}
+
+
+Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl,
+ DeclPtrTy lastEnumConst,
+ SourceLocation IdLoc,
+ IdentifierInfo *Id,
+ SourceLocation EqualLoc, ExprTy *val) {
+ EnumDecl *TheEnumDecl = cast<EnumDecl>(theEnumDecl.getAs<Decl>());
+ EnumConstantDecl *LastEnumConst =
+ cast_or_null<EnumConstantDecl>(lastEnumConst.getAs<Decl>());
+ Expr *Val = static_cast<Expr*>(val);
+
+ // The scope passed in may not be a decl scope. Zip up the scope tree until
+ // we find one that is.
+ S = getNonFieldDeclScope(S);
+
+ // Verify that there isn't already something declared with this name in this
+ // scope.
+ NamedDecl *PrevDecl = LookupName(S, Id, LookupOrdinaryName);
+ if (PrevDecl && PrevDecl->isTemplateParameter()) {
+ // Maybe we will complain about the shadowed template parameter.
+ DiagnoseTemplateParameterShadow(IdLoc, PrevDecl);
+ // Just pretend that we didn't see the previous declaration.
+ PrevDecl = 0;
+ }
+
+ if (PrevDecl) {
+ // When in C++, we may get a TagDecl with the same name; in this case the
+ // enum constant will 'hide' the tag.
+ assert((getLangOptions().CPlusPlus || !isa<TagDecl>(PrevDecl)) &&
+ "Received TagDecl when not in C++!");
+ if (!isa<TagDecl>(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S)) {
+ if (isa<EnumConstantDecl>(PrevDecl))
+ Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id;
+ else
+ Diag(IdLoc, diag::err_redefinition) << Id;
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ if (Val) Val->Destroy(Context);
+ return DeclPtrTy();
+ }
+ }
+
+ EnumConstantDecl *New = CheckEnumConstant(TheEnumDecl, LastEnumConst,
+ IdLoc, Id, Owned(Val));
+
+ // Register this decl in the current scope stack.
+ if (New)
+ PushOnScopeChains(New, S);
+
+ return DeclPtrTy::make(New);
+}
+
+void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
+ SourceLocation RBraceLoc, DeclPtrTy EnumDeclX,
+ DeclPtrTy *Elements, unsigned NumElements) {
+ EnumDecl *Enum = cast<EnumDecl>(EnumDeclX.getAs<Decl>());
+ QualType EnumType = Context.getTypeDeclType(Enum);
+
+ // 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();
+
+ // Verify that all the values are okay, compute the size of the values, and
+ // reverse the list.
+ unsigned NumNegativeBits = 0;
+ unsigned NumPositiveBits = 0;
+
+ // Keep track of whether all elements have type int.
+ bool AllElementsInt = true;
+
+ for (unsigned i = 0; i != NumElements; ++i) {
+ EnumConstantDecl *ECD =
+ cast_or_null<EnumConstantDecl>(Elements[i].getAs<Decl>());
+ if (!ECD) continue; // Already issued a diagnostic.
+
+ // If the enum value doesn't fit in an int, emit an extension warning.
+ const llvm::APSInt &InitVal = ECD->getInitVal();
+ assert(InitVal.getBitWidth() >= IntWidth &&
+ "Should have promoted value to int");
+ if (InitVal.getBitWidth() > IntWidth) {
+ llvm::APSInt V(InitVal);
+ V.trunc(IntWidth);
+ V.extend(InitVal.getBitWidth());
+ if (V != InitVal)
+ Diag(ECD->getLocation(), diag::ext_enum_value_not_int)
+ << InitVal.toString(10);
+ }
+
+ // Keep track of the size of positive and negative values.
+ if (InitVal.isUnsigned() || InitVal.isNonNegative())
+ NumPositiveBits = std::max(NumPositiveBits,
+ (unsigned)InitVal.getActiveBits());
+ else
+ NumNegativeBits = std::max(NumNegativeBits,
+ (unsigned)InitVal.getMinSignedBits());
+
+ // Keep track of whether every enum element has type int (very commmon).
+ if (AllElementsInt)
+ AllElementsInt = ECD->getType() == Context.IntTy;
+ }
+
+ // Figure out the type that should be used for this enum.
+ // FIXME: Support attribute(packed) on enums and -fshort-enums.
+ QualType BestType;
+ unsigned BestWidth;
+
+ if (NumNegativeBits) {
+ // If there is a negative value, figure out the smallest integer type (of
+ // int/long/longlong) that fits.
+ if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
+ BestType = Context.IntTy;
+ BestWidth = IntWidth;
+ } else {
+ BestWidth = Context.Target.getLongWidth();
+
+ if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth)
+ BestType = Context.LongTy;
+ else {
+ BestWidth = Context.Target.getLongLongWidth();
+
+ if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth)
+ Diag(Enum->getLocation(), diag::warn_enum_too_large);
+ BestType = Context.LongLongTy;
+ }
+ }
+ } else {
+ // If there is no negative value, figure out which of uint, ulong, ulonglong
+ // fits.
+ if (NumPositiveBits <= IntWidth) {
+ BestType = Context.UnsignedIntTy;
+ BestWidth = IntWidth;
+ } else if (NumPositiveBits <=
+ (BestWidth = Context.Target.getLongWidth())) {
+ BestType = Context.UnsignedLongTy;
+ } else {
+ BestWidth = Context.Target.getLongLongWidth();
+ assert(NumPositiveBits <= BestWidth &&
+ "How could an initializer get larger than ULL?");
+ BestType = Context.UnsignedLongLongTy;
+ }
+ }
+
+ // Loop over all of the enumerator constants, changing their types to match
+ // the type of the enum if needed.
+ for (unsigned i = 0; i != NumElements; ++i) {
+ EnumConstantDecl *ECD =
+ cast_or_null<EnumConstantDecl>(Elements[i].getAs<Decl>());
+ if (!ECD) continue; // Already issued a diagnostic.
+
+ // Standard C says the enumerators have int type, but we allow, as an
+ // extension, the enumerators to be larger than int size. If each
+ // enumerator value fits in an int, type it as an int, otherwise type it the
+ // same as the enumerator decl itself. This means that in "enum { X = 1U }"
+ // that X has type 'int', not 'unsigned'.
+ if (ECD->getType() == Context.IntTy) {
+ // Make sure the init value is signed.
+ llvm::APSInt IV = ECD->getInitVal();
+ IV.setIsSigned(true);
+ ECD->setInitVal(IV);
+
+ if (getLangOptions().CPlusPlus)
+ // C++ [dcl.enum]p4: Following the closing brace of an
+ // enum-specifier, each enumerator has the type of its
+ // enumeration.
+ ECD->setType(EnumType);
+ continue; // Already int type.
+ }
+
+ // Determine whether the value fits into an int.
+ llvm::APSInt InitVal = ECD->getInitVal();
+ bool FitsInInt;
+ if (InitVal.isUnsigned() || !InitVal.isNegative())
+ FitsInInt = InitVal.getActiveBits() < IntWidth;
+ else
+ FitsInInt = InitVal.getMinSignedBits() <= IntWidth;
+
+ // If it fits into an integer type, force it. Otherwise force it to match
+ // the enum decl type.
+ QualType NewTy;
+ unsigned NewWidth;
+ bool NewSign;
+ if (FitsInInt) {
+ NewTy = Context.IntTy;
+ NewWidth = IntWidth;
+ NewSign = true;
+ } else if (ECD->getType() == BestType) {
+ // Already the right type!
+ if (getLangOptions().CPlusPlus)
+ // C++ [dcl.enum]p4: Following the closing brace of an
+ // enum-specifier, each enumerator has the type of its
+ // enumeration.
+ ECD->setType(EnumType);
+ continue;
+ } else {
+ NewTy = BestType;
+ NewWidth = BestWidth;
+ NewSign = BestType->isSignedIntegerType();
+ }
+
+ // Adjust the APSInt value.
+ InitVal.extOrTrunc(NewWidth);
+ InitVal.setIsSigned(NewSign);
+ ECD->setInitVal(InitVal);
+
+ // Adjust the Expr initializer and type.
+ if (ECD->getInitExpr())
+ ECD->setInitExpr(new (Context) ImplicitCastExpr(NewTy, ECD->getInitExpr(),
+ /*isLvalue=*/false));
+ if (getLangOptions().CPlusPlus)
+ // C++ [dcl.enum]p4: Following the closing brace of an
+ // enum-specifier, each enumerator has the type of its
+ // enumeration.
+ ECD->setType(EnumType);
+ else
+ ECD->setType(NewTy);
+ }
+
+ Enum->completeDefinition(Context, BestType);
+}
+
+Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc,
+ ExprArg expr) {
+ StringLiteral *AsmString = cast<StringLiteral>(expr.takeAs<Expr>());
+
+ FileScopeAsmDecl *New = FileScopeAsmDecl::Create(Context, CurContext,
+ Loc, AsmString);
+ CurContext->addDecl(Context, New);
+ return DeclPtrTy::make(New);
+}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
new file mode 100644
index 000000000000..99b4d77fad42
--- /dev/null
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -0,0 +1,1803 @@
+//===--- SemaDeclAttr.cpp - Declaration Attribute Handling ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements decl-related attribute processing.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Parse/DeclSpec.h"
+#include <llvm/ADT/StringExtras.h>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Helper functions
+//===----------------------------------------------------------------------===//
+
+static const FunctionType *getFunctionType(Decl *d, bool blocksToo = true) {
+ QualType Ty;
+ if (ValueDecl *decl = dyn_cast<ValueDecl>(d))
+ Ty = decl->getType();
+ else if (FieldDecl *decl = dyn_cast<FieldDecl>(d))
+ Ty = decl->getType();
+ else if (TypedefDecl* decl = dyn_cast<TypedefDecl>(d))
+ Ty = decl->getUnderlyingType();
+ else
+ return 0;
+
+ if (Ty->isFunctionPointerType())
+ Ty = Ty->getAsPointerType()->getPointeeType();
+ else if (blocksToo && Ty->isBlockPointerType())
+ Ty = Ty->getAsBlockPointerType()->getPointeeType();
+
+ return Ty->getAsFunctionType();
+}
+
+// FIXME: We should provide an abstraction around a method or function
+// to provide the following bits of information.
+
+/// isFunctionOrMethod - Return true if the given decl has function
+/// type (function or function-typed variable) or an Objective-C
+/// method.
+static bool isFunctionOrMethod(Decl *d) {
+ return getFunctionType(d, false) || isa<ObjCMethodDecl>(d);
+}
+
+/// isFunctionOrMethodOrBlock - Return true if the given decl has function
+/// type (function or function-typed variable) or an Objective-C
+/// method or a block.
+static bool isFunctionOrMethodOrBlock(Decl *d) {
+ if (isFunctionOrMethod(d))
+ return true;
+ // check for block is more involved.
+ if (const VarDecl *V = dyn_cast<VarDecl>(d)) {
+ QualType Ty = V->getType();
+ return Ty->isBlockPointerType();
+ }
+ return isa<BlockDecl>(d);
+}
+
+/// hasFunctionProto - Return true if the given decl has a argument
+/// information. This decl should have already passed
+/// isFunctionOrMethod or isFunctionOrMethodOrBlock.
+static bool hasFunctionProto(Decl *d) {
+ if (const FunctionType *FnTy = getFunctionType(d))
+ return isa<FunctionProtoType>(FnTy);
+ else {
+ assert(isa<ObjCMethodDecl>(d) || isa<BlockDecl>(d));
+ return true;
+ }
+}
+
+/// getFunctionOrMethodNumArgs - Return number of function or method
+/// arguments. It is an error to call this on a K&R function (use
+/// hasFunctionProto first).
+static unsigned getFunctionOrMethodNumArgs(Decl *d) {
+ if (const FunctionType *FnTy = getFunctionType(d))
+ return cast<FunctionProtoType>(FnTy)->getNumArgs();
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
+ return BD->getNumParams();
+ return cast<ObjCMethodDecl>(d)->param_size();
+}
+
+static QualType getFunctionOrMethodArgType(Decl *d, unsigned Idx) {
+ if (const FunctionType *FnTy = getFunctionType(d))
+ return cast<FunctionProtoType>(FnTy)->getArgType(Idx);
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
+ return BD->getParamDecl(Idx)->getType();
+
+ return cast<ObjCMethodDecl>(d)->param_begin()[Idx]->getType();
+}
+
+static QualType getFunctionOrMethodResultType(Decl *d) {
+ if (const FunctionType *FnTy = getFunctionType(d))
+ return cast<FunctionProtoType>(FnTy)->getResultType();
+ return cast<ObjCMethodDecl>(d)->getResultType();
+}
+
+static bool isFunctionOrMethodVariadic(Decl *d) {
+ if (const FunctionType *FnTy = getFunctionType(d)) {
+ const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy);
+ return proto->isVariadic();
+ } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
+ return BD->IsVariadic();
+ else {
+ return cast<ObjCMethodDecl>(d)->isVariadic();
+ }
+}
+
+static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
+ const PointerType *PT = T->getAsPointerType();
+ if (!PT)
+ return false;
+
+ const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAsObjCInterfaceType();
+ if (!ClsT)
+ return false;
+
+ IdentifierInfo* ClsName = ClsT->getDecl()->getIdentifier();
+
+ // FIXME: Should we walk the chain of classes?
+ return ClsName == &Ctx.Idents.get("NSString") ||
+ ClsName == &Ctx.Idents.get("NSMutableString");
+}
+
+static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
+ const PointerType *PT = T->getAsPointerType();
+ if (!PT)
+ return false;
+
+ const RecordType *RT = PT->getPointeeType()->getAsRecordType();
+ if (!RT)
+ return false;
+
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->getTagKind() != TagDecl::TK_struct)
+ return false;
+
+ return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
+}
+
+//===----------------------------------------------------------------------===//
+// Attribute Implementations
+//===----------------------------------------------------------------------===//
+
+// FIXME: All this manual attribute parsing code is gross. At the
+// least add some helper functions to check most argument patterns (#
+// and types of args).
+
+static void HandleExtVectorTypeAttr(Decl *d, const AttributeList &Attr,
+ Sema &S) {
+ TypedefDecl *tDecl = dyn_cast<TypedefDecl>(d);
+ if (tDecl == 0) {
+ S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef);
+ return;
+ }
+
+ QualType curType = tDecl->getUnderlyingType();
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+ Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt vecSize(32);
+ if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << "ext_vector_type" << sizeExpr->getSourceRange();
+ return;
+ }
+ // unlike gcc's vector_size attribute, we do not allow vectors to be defined
+ // in conjunction with complex types (pointers, arrays, functions, etc.).
+ if (!curType->isIntegerType() && !curType->isRealFloatingType()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << curType;
+ return;
+ }
+ // unlike gcc's vector_size attribute, the size is specified as the
+ // number of elements, not the number of bytes.
+ unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue());
+
+ if (vectorSize == 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_zero_size)
+ << sizeExpr->getSourceRange();
+ return;
+ }
+ // Instantiate/Install the vector type, the number of elements is > 0.
+ tDecl->setUnderlyingType(S.Context.getExtVectorType(curType, vectorSize));
+ // Remember this typedef decl, we will need it later for diagnostics.
+ S.ExtVectorDecls.push_back(tDecl);
+}
+
+
+/// HandleVectorSizeAttribute - this attribute is only applicable to
+/// integral and float scalars, although arrays, pointers, and function
+/// return values are allowed in conjunction with this construct. Aggregates
+/// with this attribute are invalid, even if they are of the same size as a
+/// corresponding scalar.
+/// The raw attribute should contain precisely 1 argument, the vector size
+/// for the variable, measured in bytes. If curType and rawAttr are well
+/// formed, this routine will return a new vector type.
+static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+ QualType CurType;
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
+ CurType = VD->getType();
+ else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D))
+ CurType = TD->getUnderlyingType();
+ else {
+ S.Diag(D->getLocation(), diag::err_attr_wrong_decl)
+ << "vector_size" << SourceRange(Attr.getLoc(), Attr.getLoc());
+ return;
+ }
+
+ // Check the attribute arugments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+ Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt vecSize(32);
+ if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << "vector_size" << sizeExpr->getSourceRange();
+ return;
+ }
+ // navigate to the base type - we need to provide for vector pointers,
+ // vector arrays, and functions returning vectors.
+ if (CurType->isPointerType() || CurType->isArrayType() ||
+ CurType->isFunctionType()) {
+ S.Diag(Attr.getLoc(), diag::err_unsupported_vector_size) << CurType;
+ return;
+ /* FIXME: rebuild the type from the inside out, vectorizing the inner type.
+ do {
+ if (PointerType *PT = dyn_cast<PointerType>(canonType))
+ canonType = PT->getPointeeType().getTypePtr();
+ else if (ArrayType *AT = dyn_cast<ArrayType>(canonType))
+ canonType = AT->getElementType().getTypePtr();
+ else if (FunctionType *FT = dyn_cast<FunctionType>(canonType))
+ canonType = FT->getResultType().getTypePtr();
+ } while (canonType->isPointerType() || canonType->isArrayType() ||
+ canonType->isFunctionType());
+ */
+ }
+ // the base type must be integer or float, and can't already be a vector.
+ if (CurType->isVectorType() ||
+ (!CurType->isIntegerType() && !CurType->isRealFloatingType())) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType;
+ return;
+ }
+ unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType));
+ // vecSize is specified in bytes - convert to bits.
+ unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8);
+
+ // the vector size needs to be an integral multiple of the type size.
+ if (vectorSize % typeSize) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size)
+ << sizeExpr->getSourceRange();
+ return;
+ }
+ if (vectorSize == 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_zero_size)
+ << sizeExpr->getSourceRange();
+ return;
+ }
+
+ // Success! Instantiate the vector type, the number of elements is > 0, and
+ // not required to be a power of 2, unlike GCC.
+ CurType = S.Context.getVectorType(CurType, vectorSize/typeSize);
+
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
+ VD->setType(CurType);
+ else
+ cast<TypedefDecl>(D)->setUnderlyingType(CurType);
+}
+
+static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() > 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (TagDecl *TD = dyn_cast<TagDecl>(d))
+ TD->addAttr(::new (S.Context) PackedAttr(1));
+ else if (FieldDecl *FD = dyn_cast<FieldDecl>(d)) {
+ // If the alignment is less than or equal to 8 bits, the packed attribute
+ // has no effect.
+ if (!FD->getType()->isIncompleteType() &&
+ S.Context.getTypeAlign(FD->getType()) <= 8)
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
+ << Attr.getName() << FD->getType();
+ else
+ FD->addAttr(::new (S.Context) PackedAttr(1));
+ } else
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+}
+
+static void HandleIBOutletAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() > 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ // The IBOutlet attribute only applies to instance variables of Objective-C
+ // classes.
+ if (isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))
+ d->addAttr(::new (S.Context) IBOutletAttr());
+ else
+ S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet);
+}
+
+static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // GCC ignores the nonnull attribute on K&R style function
+ // prototypes, so we ignore it as well
+ if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ unsigned NumArgs = getFunctionOrMethodNumArgs(d);
+
+ // The nonnull attribute only applies to pointers.
+ llvm::SmallVector<unsigned, 10> NonNullArgs;
+
+ for (AttributeList::arg_iterator I=Attr.arg_begin(),
+ E=Attr.arg_end(); I!=E; ++I) {
+
+
+ // The argument must be an integer constant expression.
+ Expr *Ex = static_cast<Expr *>(*I);
+ llvm::APSInt ArgNum(32);
+ if (!Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << "nonnull" << Ex->getSourceRange();
+ return;
+ }
+
+ unsigned x = (unsigned) ArgNum.getZExtValue();
+
+ if (x < 1 || x > NumArgs) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << "nonnull" << I.getArgNum() << Ex->getSourceRange();
+ return;
+ }
+
+ --x;
+
+ // Is the function argument a pointer type?
+ QualType T = getFunctionOrMethodArgType(d, x);
+ if (!T->isPointerType() && !T->isBlockPointerType()) {
+ // FIXME: Should also highlight argument in decl.
+ S.Diag(Attr.getLoc(), diag::err_nonnull_pointers_only)
+ << "nonnull" << Ex->getSourceRange();
+ continue;
+ }
+
+ NonNullArgs.push_back(x);
+ }
+
+ // If no arguments were specified to __attribute__((nonnull)) then all
+ // pointer arguments have a nonnull attribute.
+ if (NonNullArgs.empty()) {
+ for (unsigned I = 0, E = getFunctionOrMethodNumArgs(d); I != E; ++I) {
+ QualType T = getFunctionOrMethodArgType(d, I);
+ if (T->isPointerType() || T->isBlockPointerType())
+ NonNullArgs.push_back(I);
+ }
+
+ if (NonNullArgs.empty()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers);
+ return;
+ }
+ }
+
+ unsigned* start = &NonNullArgs[0];
+ unsigned size = NonNullArgs.size();
+ std::sort(start, start + size);
+ d->addAttr(::new (S.Context) NonNullAttr(start, size));
+}
+
+static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ Expr *Arg = static_cast<Expr*>(Attr.getArg(0));
+ Arg = Arg->IgnoreParenCasts();
+ StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
+
+ if (Str == 0 || Str->isWide()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ << "alias" << 1;
+ return;
+ }
+
+ const char *Alias = Str->getStrData();
+ unsigned AliasLen = Str->getByteLength();
+
+ // FIXME: check if target symbol exists in current file
+
+ d->addAttr(::new (S.Context) AliasAttr(std::string(Alias, AliasLen)));
+}
+
+static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
+ Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isa<FunctionDecl>(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) AlwaysInlineAttr());
+}
+
+static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
+ Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return false;
+ }
+
+ if (!isFunctionOrMethod(d) && !isa<BlockDecl>(d)) {
+ ValueDecl *VD = dyn_cast<ValueDecl>(d);
+ if (VD == 0 || !VD->getType()->isBlockPointerType()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ if (HandleCommonNoReturnAttr(d, Attr, S))
+ d->addAttr(::new (S.Context) NoReturnAttr());
+}
+
+static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
+ Sema &S) {
+ if (HandleCommonNoReturnAttr(d, Attr, S))
+ d->addAttr(::new (S.Context) AnalyzerNoReturnAttr());
+}
+
+static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isa<VarDecl>(d) && !isFunctionOrMethod(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 2 /*variable and function*/;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) UnusedAttr());
+}
+
+static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (const VarDecl *VD = dyn_cast<VarDecl>(d)) {
+ if (VD->hasLocalStorage() || VD->hasExternalStorage()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used";
+ return;
+ }
+ } else if (!isFunctionOrMethod(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 2 /*variable and function*/;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) UsedAttr());
+}
+
+static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0 && Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << "0 or 1";
+ return;
+ }
+
+ int priority = 65535; // FIXME: Do not hardcode such constants.
+ if (Attr.getNumArgs() > 0) {
+ Expr *E = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt Idx(32);
+ if (!E->isIntegerConstantExpr(Idx, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
+ << "constructor" << 1 << E->getSourceRange();
+ return;
+ }
+ priority = Idx.getZExtValue();
+ }
+
+ if (!isa<FunctionDecl>(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) ConstructorAttr(priority));
+}
+
+static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0 && Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << "0 or 1";
+ return;
+ }
+
+ int priority = 65535; // FIXME: Do not hardcode such constants.
+ if (Attr.getNumArgs() > 0) {
+ Expr *E = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt Idx(32);
+ if (!E->isIntegerConstantExpr(Idx, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
+ << "destructor" << 1 << E->getSourceRange();
+ return;
+ }
+ priority = Idx.getZExtValue();
+ }
+
+ if (!isa<FunctionDecl>(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) DestructorAttr(priority));
+}
+
+static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) DeprecatedAttr());
+}
+
+static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) UnavailableAttr());
+}
+
+static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ Expr *Arg = static_cast<Expr*>(Attr.getArg(0));
+ Arg = Arg->IgnoreParenCasts();
+ StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
+
+ if (Str == 0 || Str->isWide()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ << "visibility" << 1;
+ return;
+ }
+
+ const char *TypeStr = Str->getStrData();
+ unsigned TypeLen = Str->getByteLength();
+ VisibilityAttr::VisibilityTypes type;
+
+ if (TypeLen == 7 && !memcmp(TypeStr, "default", 7))
+ type = VisibilityAttr::DefaultVisibility;
+ else if (TypeLen == 6 && !memcmp(TypeStr, "hidden", 6))
+ type = VisibilityAttr::HiddenVisibility;
+ else if (TypeLen == 8 && !memcmp(TypeStr, "internal", 8))
+ type = VisibilityAttr::HiddenVisibility; // FIXME
+ else if (TypeLen == 9 && !memcmp(TypeStr, "protected", 9))
+ type = VisibilityAttr::ProtectedVisibility;
+ else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << TypeStr;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) VisibilityAttr(type));
+}
+
+static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr,
+ Sema &S) {
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D);
+ if (OCI == 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_requires_objc_interface);
+ return;
+ }
+
+ D->addAttr(::new (S.Context) ObjCExceptionAttr());
+}
+
+static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) {
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ QualType T = TD->getUnderlyingType();
+ if (!T->isPointerType() ||
+ !T->getAsPointerType()->getPointeeType()->isRecordType()) {
+ S.Diag(TD->getLocation(), diag::err_nsobject_attribute);
+ return;
+ }
+ }
+ D->addAttr(::new (S.Context) ObjCNSObjectAttr());
+}
+
+static void
+HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ if (!isa<FunctionDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_overloadable_not_function);
+ return;
+ }
+
+ D->addAttr(::new (S.Context) OverloadableAttr());
+}
+
+static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ if (!Attr.getParameterName()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ << "blocks" << 1;
+ return;
+ }
+
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ BlocksAttr::BlocksAttrTypes type;
+ if (Attr.getParameterName()->isStr("byref"))
+ type = BlocksAttr::ByRef;
+ else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
+ << "blocks" << Attr.getParameterName();
+ return;
+ }
+
+ d->addAttr(::new (S.Context) BlocksAttr(type));
+}
+
+static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() > 2) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << "0, 1 or 2";
+ return;
+ }
+
+ int sentinel = 0;
+ if (Attr.getNumArgs() > 0) {
+ Expr *E = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt Idx(32);
+ if (!E->isIntegerConstantExpr(Idx, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
+ << "sentinel" << 1 << E->getSourceRange();
+ return;
+ }
+ sentinel = Idx.getZExtValue();
+
+ if (sentinel < 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_less_than_zero)
+ << E->getSourceRange();
+ return;
+ }
+ }
+
+ int nullPos = 0;
+ if (Attr.getNumArgs() > 1) {
+ Expr *E = static_cast<Expr *>(Attr.getArg(1));
+ llvm::APSInt Idx(32);
+ if (!E->isIntegerConstantExpr(Idx, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
+ << "sentinel" << 2 << E->getSourceRange();
+ return;
+ }
+ nullPos = Idx.getZExtValue();
+
+ if (nullPos > 1 || nullPos < 0) {
+ // 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)
+ << E->getSourceRange();
+ return;
+ }
+ }
+
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
+ const FunctionType *FT = FD->getType()->getAsFunctionType();
+ assert(FT && "FunctionDecl has non-function type?");
+
+ if (isa<FunctionNoProtoType>(FT)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_named_arguments);
+ return;
+ }
+
+ if (!cast<FunctionProtoType>(FT)->isVariadic()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
+ return;
+ }
+ } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) {
+ if (!MD->isVariadic()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
+ return;
+ }
+ } else if (isa<BlockDecl>(d)) {
+ // Note! BlockDecl is typeless. Variadic diagnostics
+ // will be issued by the caller.
+ ;
+ } else if (const VarDecl *V = dyn_cast<VarDecl>(d)) {
+ QualType Ty = V->getType();
+ if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
+ const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d)
+ : Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType();
+ if (!cast<FunctionProtoType>(FT)->isVariadic()) {
+ int m = Ty->isFunctionPointerType() ? 0 : 1;
+ S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m;
+ return;
+ }
+ }
+ else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 6 /*function, method or block */;
+ return;
+ }
+ } else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 6 /*function, method or block */;
+ return;
+ }
+ d->addAttr(::new (S.Context) SentinelAttr(sentinel, nullPos));
+}
+
+static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ // TODO: could also be applied to methods?
+ FunctionDecl *Fn = dyn_cast<FunctionDecl>(D);
+ if (!Fn) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ Fn->addAttr(::new (S.Context) WarnUnusedResultAttr());
+}
+
+static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ // TODO: could also be applied to methods?
+ if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 2 /*variable and function*/;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) WeakAttr());
+}
+
+static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ // weak_import only applies to variable & function declarations.
+ bool isDef = false;
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ isDef = (!VD->hasExternalStorage() || VD->getInit());
+ } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ isDef = FD->getBody(S.Context);
+ } else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D)) {
+ // We ignore weak import on properties and methods
+ return;
+ } else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 2 /*variable and function*/;
+ return;
+ }
+
+ // Merge should handle any subsequent violations.
+ if (isDef) {
+ S.Diag(Attr.getLoc(),
+ diag::warn_attribute_weak_import_invalid_on_definition)
+ << "weak_import" << 2 /*variable and function*/;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) WeakImportAttr());
+}
+
+static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ // Attribute can be applied only to functions or variables.
+ if (isa<VarDecl>(D)) {
+ D->addAttr(::new (S.Context) DLLImportAttr());
+ return;
+ }
+
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (!FD) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 2 /*variable and function*/;
+ return;
+ }
+
+ // Currently, the dllimport attribute is ignored for inlined functions.
+ // Warning is emitted.
+ if (FD->isInline()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
+ return;
+ }
+
+ // The attribute is also overridden by a subsequent declaration as dllexport.
+ // Warning is emitted.
+ for (AttributeList *nextAttr = Attr.getNext(); nextAttr;
+ nextAttr = nextAttr->getNext()) {
+ if (nextAttr->getKind() == AttributeList::AT_dllexport) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
+ return;
+ }
+ }
+
+ if (D->getAttr<DLLExportAttr>()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
+ return;
+ }
+
+ D->addAttr(::new (S.Context) DLLImportAttr());
+}
+
+static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ // Attribute can be applied only to functions or variables.
+ if (isa<VarDecl>(D)) {
+ D->addAttr(::new (S.Context) DLLExportAttr());
+ return;
+ }
+
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (!FD) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 2 /*variable and function*/;
+ return;
+ }
+
+ // Currently, the dllexport attribute is ignored for inlined functions,
+ // unless the -fkeep-inline-functions flag has been used. Warning is emitted;
+ if (FD->isInline()) {
+ // FIXME: ... unless the -fkeep-inline-functions flag has been used.
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport";
+ return;
+ }
+
+ D->addAttr(::new (S.Context) DLLExportAttr());
+}
+
+static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+ // Attribute has no arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ // Make sure that there is a string literal as the sections's single
+ // argument.
+ StringLiteral *SE =
+ dyn_cast<StringLiteral>(static_cast<Expr *>(Attr.getArg(0)));
+ if (!SE) {
+ // FIXME
+ S.Diag(Attr.getLoc(), diag::err_attribute_annotate_no_string);
+ return;
+ }
+ D->addAttr(::new (S.Context) SectionAttr(std::string(SE->getStrData(),
+ SE->getByteLength())));
+}
+
+static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // Attribute has no arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ // Attribute can be applied only to functions.
+ if (!isa<FunctionDecl>(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ // stdcall and fastcall attributes are mutually incompatible.
+ if (d->getAttr<FastCallAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << "stdcall" << "fastcall";
+ return;
+ }
+
+ d->addAttr(::new (S.Context) StdCallAttr());
+}
+
+static void HandleFastCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // Attribute has no arguments.
+ if (Attr.getNumArgs() != 0) {
+ 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() << 0 /*function*/;
+ return;
+ }
+
+ // stdcall and fastcall attributes are mutually incompatible.
+ if (d->getAttr<StdCallAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << "fastcall" << "stdcall";
+ return;
+ }
+
+ d->addAttr(::new (S.Context) FastCallAttr());
+}
+
+static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) NoThrowAttr());
+}
+
+static void HandleConstAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) ConstAttr());
+}
+
+static void HandlePureAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) PureAttr());
+}
+
+static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // Match gcc which ignores cleanup attrs when compiling C++.
+ if (S.getLangOptions().CPlusPlus)
+ return;
+
+ if (!Attr.getParameterName()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ VarDecl *VD = dyn_cast<VarDecl>(d);
+
+ if (!VD || !VD->hasLocalStorage()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "cleanup";
+ return;
+ }
+
+ // Look up the function
+ NamedDecl *CleanupDecl = S.LookupName(S.TUScope, Attr.getParameterName(),
+ Sema::LookupOrdinaryName);
+ if (!CleanupDecl) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_found) <<
+ Attr.getParameterName();
+ return;
+ }
+
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(CleanupDecl);
+ if (!FD) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_function) <<
+ Attr.getParameterName();
+ return;
+ }
+
+ if (FD->getNumParams() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_func_must_take_one_arg) <<
+ Attr.getParameterName();
+ return;
+ }
+
+ // We're currently more strict than GCC about what function types we accept.
+ // If this ever proves to be a problem it should be easy to fix.
+ QualType Ty = S.Context.getPointerType(VD->getType());
+ QualType ParamTy = FD->getParamDecl(0)->getType();
+ if (S.CheckAssignmentConstraints(ParamTy, Ty) != Sema::Compatible) {
+ S.Diag(Attr.getLoc(),
+ diag::err_attribute_cleanup_func_arg_incompatible_type) <<
+ Attr.getParameterName() << ParamTy << Ty;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) CleanupAttr(FD));
+}
+
+/// Handle __attribute__((format_arg((idx)))) attribute
+/// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
+static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+ if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+ // FIXME: in C++ the implicit 'this' function parameter also counts.
+ // this is needed in order to be compatible with GCC
+ // the index must start with 1.
+ unsigned NumArgs = getFunctionOrMethodNumArgs(d);
+ unsigned FirstIdx = 1;
+ // checks for the 2nd argument
+ Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt Idx(32);
+ if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
+ << "format" << 2 << IdxExpr->getSourceRange();
+ return;
+ }
+
+ if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << "format" << 2 << IdxExpr->getSourceRange();
+ return;
+ }
+
+ unsigned ArgIdx = Idx.getZExtValue() - 1;
+
+ // make sure the format string is really a string
+ QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
+
+ bool not_nsstring_type = !isNSStringType(Ty, S.Context);
+ if (not_nsstring_type &&
+ !isCFStringType(Ty, S.Context) &&
+ (!Ty->isPointerType() ||
+ !Ty->getAsPointerType()->getPointeeType()->isCharType())) {
+ // FIXME: Should highlight the actual expression that has the wrong type.
+ S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
+ << (not_nsstring_type ? "a string type" : "an NSString")
+ << IdxExpr->getSourceRange();
+ return;
+ }
+ Ty = getFunctionOrMethodResultType(d);
+ if (!isNSStringType(Ty, S.Context) &&
+ !isCFStringType(Ty, S.Context) &&
+ (!Ty->isPointerType() ||
+ !Ty->getAsPointerType()->getPointeeType()->isCharType())) {
+ // FIXME: Should highlight the actual expression that has the wrong type.
+ S.Diag(Attr.getLoc(), diag::err_format_attribute_result_not)
+ << (not_nsstring_type ? "string type" : "NSString")
+ << IdxExpr->getSourceRange();
+ return;
+ }
+
+ d->addAttr(::new (S.Context) FormatArgAttr(Idx.getZExtValue()));
+}
+
+/// Handle __attribute__((format(type,idx,firstarg))) attributes
+/// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
+static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+
+ if (!Attr.getParameterName()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ << "format" << 1;
+ return;
+ }
+
+ if (Attr.getNumArgs() != 2) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 3;
+ return;
+ }
+
+ if (!isFunctionOrMethodOrBlock(d) || !hasFunctionProto(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ // FIXME: in C++ the implicit 'this' function parameter also counts.
+ // this is needed in order to be compatible with GCC
+ // the index must start in 1 and the limit is numargs+1
+ unsigned NumArgs = getFunctionOrMethodNumArgs(d);
+ unsigned FirstIdx = 1;
+
+ const char *Format = Attr.getParameterName()->getName();
+ unsigned FormatLen = Attr.getParameterName()->getLength();
+
+ // Normalize the argument, __foo__ becomes foo.
+ if (FormatLen > 4 && Format[0] == '_' && Format[1] == '_' &&
+ Format[FormatLen - 2] == '_' && Format[FormatLen - 1] == '_') {
+ Format += 2;
+ FormatLen -= 4;
+ }
+
+ bool Supported = false;
+ bool is_NSString = false;
+ bool is_strftime = false;
+ bool is_CFString = false;
+
+ switch (FormatLen) {
+ default: break;
+ case 5: Supported = !memcmp(Format, "scanf", 5); break;
+ case 6: Supported = !memcmp(Format, "printf", 6); break;
+ case 7: Supported = !memcmp(Format, "strfmon", 7); break;
+ case 8:
+ Supported = (is_strftime = !memcmp(Format, "strftime", 8)) ||
+ (is_NSString = !memcmp(Format, "NSString", 8)) ||
+ (is_CFString = !memcmp(Format, "CFString", 8));
+ break;
+ }
+
+ if (!Supported) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
+ << "format" << Attr.getParameterName()->getName();
+ return;
+ }
+
+ // checks for the 2nd argument
+ Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt Idx(32);
+ if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
+ << "format" << 2 << IdxExpr->getSourceRange();
+ return;
+ }
+
+ if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << "format" << 2 << IdxExpr->getSourceRange();
+ return;
+ }
+
+ // FIXME: Do we need to bounds check?
+ unsigned ArgIdx = Idx.getZExtValue() - 1;
+
+ // make sure the format string is really a string
+ QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
+
+ if (is_CFString) {
+ if (!isCFStringType(Ty, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
+ << "a CFString" << IdxExpr->getSourceRange();
+ return;
+ }
+ } else if (is_NSString) {
+ // FIXME: do we need to check if the type is NSString*? What are the
+ // semantics?
+ if (!isNSStringType(Ty, S.Context)) {
+ // FIXME: Should highlight the actual expression that has the wrong type.
+ S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
+ << "an NSString" << IdxExpr->getSourceRange();
+ return;
+ }
+ } else if (!Ty->isPointerType() ||
+ !Ty->getAsPointerType()->getPointeeType()->isCharType()) {
+ // FIXME: Should highlight the actual expression that has the wrong type.
+ S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
+ << "a string type" << IdxExpr->getSourceRange();
+ return;
+ }
+
+ // check the 3rd argument
+ Expr *FirstArgExpr = static_cast<Expr *>(Attr.getArg(1));
+ llvm::APSInt FirstArg(32);
+ if (!FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
+ << "format" << 3 << FirstArgExpr->getSourceRange();
+ return;
+ }
+
+ // check if the function is variadic if the 3rd argument non-zero
+ if (FirstArg != 0) {
+ if (isFunctionOrMethodVariadic(d)) {
+ ++NumArgs; // +1 for ...
+ } else {
+ S.Diag(d->getLocation(), diag::err_format_attribute_requires_variadic);
+ return;
+ }
+ }
+
+ // strftime requires FirstArg to be 0 because it doesn't read from any
+ // variable the input is just the current time + the format string.
+ if (is_strftime) {
+ if (FirstArg != 0) {
+ S.Diag(Attr.getLoc(), diag::err_format_strftime_third_parameter)
+ << FirstArgExpr->getSourceRange();
+ return;
+ }
+ // if 0 it disables parameter checking (to use with e.g. va_list)
+ } else if (FirstArg != 0 && FirstArg != NumArgs) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << "format" << 3 << FirstArgExpr->getSourceRange();
+ return;
+ }
+
+ d->addAttr(::new (S.Context) FormatAttr(std::string(Format, FormatLen),
+ Idx.getZExtValue(), FirstArg.getZExtValue()));
+}
+
+static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
+ Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ // Try to find the underlying union declaration.
+ RecordDecl *RD = 0;
+ TypedefDecl *TD = dyn_cast<TypedefDecl>(d);
+ if (TD && TD->getUnderlyingType()->isUnionType())
+ RD = TD->getUnderlyingType()->getAsUnionType()->getDecl();
+ else
+ RD = dyn_cast<RecordDecl>(d);
+
+ if (!RD || !RD->isUnion()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 1 /*union*/;
+ return;
+ }
+
+ if (!RD->isDefinition()) {
+ S.Diag(Attr.getLoc(),
+ diag::warn_transparent_union_attribute_not_definition);
+ return;
+ }
+
+ RecordDecl::field_iterator Field = RD->field_begin(S.Context),
+ FieldEnd = RD->field_end(S.Context);
+ if (Field == FieldEnd) {
+ S.Diag(Attr.getLoc(), diag::warn_transparent_union_attribute_zero_fields);
+ return;
+ }
+
+ FieldDecl *FirstField = *Field;
+ QualType FirstType = FirstField->getType();
+ if (FirstType->isFloatingType() || FirstType->isVectorType()) {
+ S.Diag(FirstField->getLocation(),
+ diag::warn_transparent_union_attribute_floating);
+ return;
+ }
+
+ uint64_t FirstSize = S.Context.getTypeSize(FirstType);
+ uint64_t FirstAlign = S.Context.getTypeAlign(FirstType);
+ for (; Field != FieldEnd; ++Field) {
+ QualType FieldType = Field->getType();
+ if (S.Context.getTypeSize(FieldType) != FirstSize ||
+ S.Context.getTypeAlign(FieldType) != FirstAlign) {
+ // Warn if we drop the attribute.
+ bool isSize = S.Context.getTypeSize(FieldType) != FirstSize;
+ unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType)
+ : S.Context.getTypeAlign(FieldType);
+ S.Diag(Field->getLocation(),
+ diag::warn_transparent_union_attribute_field_size_align)
+ << isSize << Field->getDeclName() << FieldBits;
+ unsigned FirstBits = isSize? FirstSize : FirstAlign;
+ S.Diag(FirstField->getLocation(),
+ diag::note_transparent_union_first_field_size_align)
+ << isSize << FirstBits;
+ return;
+ }
+ }
+
+ RD->addAttr(::new (S.Context) TransparentUnionAttr());
+}
+
+static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+ Expr *argExpr = static_cast<Expr *>(Attr.getArg(0));
+ StringLiteral *SE = dyn_cast<StringLiteral>(argExpr);
+
+ // Make sure that there is a string literal as the annotation's single
+ // argument.
+ if (!SE) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_annotate_no_string);
+ return;
+ }
+ d->addAttr(::new (S.Context) AnnotateAttr(std::string(SE->getStrData(),
+ SE->getByteLength())));
+}
+
+static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() > 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ unsigned Align = 0;
+ if (Attr.getNumArgs() == 0) {
+ // FIXME: This should be the target specific maximum alignment.
+ // (For now we just use 128 bits which is the maximum on X86).
+ Align = 128;
+ d->addAttr(::new (S.Context) AlignedAttr(Align));
+ return;
+ }
+
+ Expr *alignmentExpr = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt Alignment(32);
+ if (!alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << "aligned" << alignmentExpr->getSourceRange();
+ return;
+ }
+ if (!llvm::isPowerOf2_64(Alignment.getZExtValue())) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_aligned_not_power_of_two)
+ << alignmentExpr->getSourceRange();
+ return;
+ }
+
+ d->addAttr(::new (S.Context) AlignedAttr(Alignment.getZExtValue() * 8));
+}
+
+/// HandleModeAttr - This attribute modifies the width of a decl with
+/// primitive type.
+///
+/// Despite what would be logical, the mode attribute is a decl attribute,
+/// not a type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make
+/// 'G' be HImode, not an intermediate pointer.
+///
+static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+ // This attribute isn't documented, but glibc uses it. It changes
+ // the width of an int or unsigned int to the specified size.
+
+ // Check that there aren't any arguments
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ IdentifierInfo *Name = Attr.getParameterName();
+ if (!Name) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_missing_parameter_name);
+ return;
+ }
+ const char *Str = Name->getName();
+ unsigned Len = Name->getLength();
+
+ // Normalize the attribute name, __foo__ becomes foo.
+ if (Len > 4 && Str[0] == '_' && Str[1] == '_' &&
+ Str[Len - 2] == '_' && Str[Len - 1] == '_') {
+ Str += 2;
+ Len -= 4;
+ }
+
+ unsigned DestWidth = 0;
+ bool IntegerMode = true;
+ bool ComplexMode = false;
+ switch (Len) {
+ case 2:
+ switch (Str[0]) {
+ case 'Q': DestWidth = 8; break;
+ case 'H': DestWidth = 16; break;
+ case 'S': DestWidth = 32; break;
+ case 'D': DestWidth = 64; break;
+ case 'X': DestWidth = 96; break;
+ case 'T': DestWidth = 128; break;
+ }
+ if (Str[1] == 'F') {
+ IntegerMode = false;
+ } else if (Str[1] == 'C') {
+ IntegerMode = false;
+ ComplexMode = true;
+ } else if (Str[1] != 'I') {
+ DestWidth = 0;
+ }
+ break;
+ case 4:
+ // FIXME: glibc uses 'word' to define register_t; this is narrower than a
+ // pointer on PIC16 and other embedded platforms.
+ if (!memcmp(Str, "word", 4))
+ DestWidth = S.Context.Target.getPointerWidth(0);
+ if (!memcmp(Str, "byte", 4))
+ DestWidth = S.Context.Target.getCharWidth();
+ break;
+ case 7:
+ if (!memcmp(Str, "pointer", 7))
+ DestWidth = S.Context.Target.getPointerWidth(0);
+ break;
+ }
+
+ QualType OldTy;
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D))
+ OldTy = TD->getUnderlyingType();
+ else if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
+ OldTy = VD->getType();
+ else {
+ S.Diag(D->getLocation(), diag::err_attr_wrong_decl)
+ << "mode" << SourceRange(Attr.getLoc(), Attr.getLoc());
+ return;
+ }
+
+ if (!OldTy->getAsBuiltinType() && !OldTy->isComplexType())
+ S.Diag(Attr.getLoc(), diag::err_mode_not_primitive);
+ else if (IntegerMode) {
+ if (!OldTy->isIntegralType())
+ S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
+ } else if (ComplexMode) {
+ if (!OldTy->isComplexType())
+ S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
+ } else {
+ if (!OldTy->isFloatingType())
+ S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
+ }
+
+ // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t
+ // and friends, at least with glibc.
+ // FIXME: Make sure 32/64-bit integers don't get defined to types of the wrong
+ // width on unusual platforms.
+ // FIXME: Make sure floating-point mappings are accurate
+ // FIXME: Support XF and TF types
+ QualType NewTy;
+ switch (DestWidth) {
+ case 0:
+ S.Diag(Attr.getLoc(), diag::err_unknown_machine_mode) << Name;
+ return;
+ default:
+ S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
+ return;
+ case 8:
+ if (!IntegerMode) {
+ S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
+ return;
+ }
+ if (OldTy->isSignedIntegerType())
+ NewTy = S.Context.SignedCharTy;
+ else
+ NewTy = S.Context.UnsignedCharTy;
+ break;
+ case 16:
+ if (!IntegerMode) {
+ S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
+ return;
+ }
+ if (OldTy->isSignedIntegerType())
+ NewTy = S.Context.ShortTy;
+ else
+ NewTy = S.Context.UnsignedShortTy;
+ break;
+ case 32:
+ if (!IntegerMode)
+ NewTy = S.Context.FloatTy;
+ else if (OldTy->isSignedIntegerType())
+ NewTy = S.Context.IntTy;
+ else
+ NewTy = S.Context.UnsignedIntTy;
+ break;
+ case 64:
+ if (!IntegerMode)
+ NewTy = S.Context.DoubleTy;
+ else if (OldTy->isSignedIntegerType())
+ NewTy = S.Context.LongLongTy;
+ else
+ NewTy = S.Context.UnsignedLongLongTy;
+ break;
+ case 96:
+ NewTy = S.Context.LongDoubleTy;
+ break;
+ case 128:
+ if (!IntegerMode) {
+ S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
+ return;
+ }
+ NewTy = S.Context.getFixedWidthIntType(128, OldTy->isSignedIntegerType());
+ break;
+ }
+
+ if (ComplexMode) {
+ NewTy = S.Context.getComplexType(NewTy);
+ }
+
+ // Install the new type.
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D))
+ TD->setUnderlyingType(NewTy);
+ else
+ cast<ValueDecl>(D)->setType(NewTy);
+}
+
+static void HandleNodebugAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() > 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isFunctionOrMethod(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) NodebugAttr());
+}
+
+static void HandleNoinlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isa<FunctionDecl>(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) NoinlineAttr());
+}
+
+static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ FunctionDecl *Fn = dyn_cast<FunctionDecl>(d);
+ if (Fn == 0) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ if (!Fn->isInline()) {
+ S.Diag(Attr.getLoc(), diag::warn_gnu_inline_attribute_requires_inline);
+ return;
+ }
+
+ d->addAttr(::new (S.Context) GNUInlineAttr());
+}
+
+static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ if (!isFunctionOrMethod(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt NumParams(32);
+ if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << "regparm" << NumParamsExpr->getSourceRange();
+ return;
+ }
+
+ if (S.Context.Target.getRegParmMax() == 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform)
+ << NumParamsExpr->getSourceRange();
+ return;
+ }
+
+ if (NumParams.getLimitedValue(255) > S.Context.Target.getRegParmMax()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number)
+ << S.Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange();
+ return;
+ }
+
+ d->addAttr(::new (S.Context) RegparmAttr(NumParams.getZExtValue()));
+}
+
+//===----------------------------------------------------------------------===//
+// Checker-specific attribute handlers.
+//===----------------------------------------------------------------------===//
+
+static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
+ Sema &S) {
+
+ QualType RetTy;
+
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d))
+ RetTy = MD->getResultType();
+ else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d))
+ RetTy = FD->getResultType();
+ else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 3 /* function or method */;
+ return;
+ }
+
+ if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAsPointerType())) {
+ S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type)
+ << Attr.getName();
+ return;
+ }
+
+ switch (Attr.getKind()) {
+ default:
+ assert(0 && "invalid ownership attribute");
+ return;
+ case AttributeList::AT_cf_returns_retained:
+ d->addAttr(::new (S.Context) CFReturnsRetainedAttr());
+ return;
+ case AttributeList::AT_ns_returns_retained:
+ d->addAttr(::new (S.Context) NSReturnsRetainedAttr());
+ return;
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// Top Level Sema Entry Points
+//===----------------------------------------------------------------------===//
+
+/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
+/// the attribute applies to decls. If the attribute is a type attribute, just
+/// silently ignore it.
+static void ProcessDeclAttribute(Decl *D, const AttributeList &Attr, Sema &S) {
+ switch (Attr.getKind()) {
+ case AttributeList::AT_IBOutlet: HandleIBOutletAttr (D, Attr, S); break;
+ case AttributeList::AT_address_space:
+ case AttributeList::AT_objc_gc:
+ // Ignore these, these are type attributes, handled by ProcessTypeAttributes.
+ break;
+ case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break;
+ case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break;
+ case AttributeList::AT_always_inline:
+ HandleAlwaysInlineAttr (D, Attr, S); break;
+ case AttributeList::AT_analyzer_noreturn:
+ HandleAnalyzerNoReturnAttr (D, Attr, S); break;
+ case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break;
+ case AttributeList::AT_constructor: HandleConstructorAttr(D, Attr, S); break;
+ case AttributeList::AT_deprecated: HandleDeprecatedAttr(D, Attr, S); break;
+ case AttributeList::AT_destructor: HandleDestructorAttr(D, Attr, S); break;
+ case AttributeList::AT_dllexport: HandleDLLExportAttr (D, Attr, S); break;
+ case AttributeList::AT_dllimport: HandleDLLImportAttr (D, Attr, S); break;
+ case AttributeList::AT_ext_vector_type:
+ HandleExtVectorTypeAttr(D, Attr, S);
+ break;
+ case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break;
+ case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break;
+ case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break;
+ case AttributeList::AT_gnu_inline: HandleGNUInlineAttr(D, Attr, S); break;
+ case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break;
+ case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break;
+ case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break;
+ case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break;
+
+ // Checker-specific.
+ case AttributeList::AT_ns_returns_retained:
+ case AttributeList::AT_cf_returns_retained:
+ HandleNSReturnsRetainedAttr(D, Attr, S); break;
+
+ case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break;
+ case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break;
+ case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break;
+ case AttributeList::AT_unavailable: HandleUnavailableAttr(D, Attr, S); break;
+ case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break;
+ case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break;
+ case AttributeList::AT_vector_size: HandleVectorSizeAttr(D, Attr, S); break;
+ case AttributeList::AT_visibility: HandleVisibilityAttr(D, Attr, S); break;
+ case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S);
+ break;
+ case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break;
+ case AttributeList::AT_weak_import: HandleWeakImportAttr(D, Attr, S); break;
+ case AttributeList::AT_transparent_union:
+ HandleTransparentUnionAttr(D, Attr, S);
+ break;
+ case AttributeList::AT_objc_exception:
+ HandleObjCExceptionAttr(D, Attr, S);
+ break;
+ case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break;
+ case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break;
+ case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break;
+ case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break;
+ case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break;
+ case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break;
+ case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break;
+ case AttributeList::AT_nodebug: HandleNodebugAttr (D, Attr, S); break;
+ case AttributeList::AT_noinline: HandleNoinlineAttr (D, Attr, S); break;
+ case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break;
+ case AttributeList::IgnoredAttribute:
+ case AttributeList::AT_no_instrument_function: // Interacts with -pg.
+ // Just ignore
+ break;
+ default:
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+ break;
+ }
+}
+
+/// ProcessDeclAttributeList - Apply all the decl attributes in the specified
+/// attribute list to the specified decl, ignoring any type attributes.
+void Sema::ProcessDeclAttributeList(Decl *D, const AttributeList *AttrList) {
+ while (AttrList) {
+ ProcessDeclAttribute(D, *AttrList, *this);
+ AttrList = AttrList->getNext();
+ }
+}
+
+/// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
+/// it, apply them to D. This is a bit tricky because PD can have attributes
+/// specified in many different places, and we need to find and apply them all.
+void Sema::ProcessDeclAttributes(Decl *D, const Declarator &PD) {
+ // Apply decl attributes from the DeclSpec if present.
+ if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes())
+ ProcessDeclAttributeList(D, Attrs);
+
+ // Walk the declarator structure, applying decl attributes that were in a type
+ // position to the decl itself. This handles cases like:
+ // int *__attr__(x)** D;
+ // when X is a decl attribute.
+ for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i)
+ if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs())
+ ProcessDeclAttributeList(D, Attrs);
+
+ // Finally, apply any attributes on the decl itself.
+ if (const AttributeList *Attrs = PD.getAttributes())
+ ProcessDeclAttributeList(D, Attrs);
+}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
new file mode 100644
index 000000000000..f13179f0438f
--- /dev/null
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -0,0 +1,2823 @@
+//===------ SemaDeclCXX.cpp - Semantic Analysis for C++ Declarations ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for C++ declarations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "SemaInherit.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/TypeOrdering.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/DeclSpec.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+#include <algorithm> // for std::equal
+#include <map>
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// CheckDefaultArgumentVisitor
+//===----------------------------------------------------------------------===//
+
+namespace {
+ /// CheckDefaultArgumentVisitor - C++ [dcl.fct.default] Traverses
+ /// the default argument of a parameter to determine whether it
+ /// contains any ill-formed subexpressions. For example, this will
+ /// diagnose the use of local variables or parameters within the
+ /// default argument expression.
+ class VISIBILITY_HIDDEN CheckDefaultArgumentVisitor
+ : public StmtVisitor<CheckDefaultArgumentVisitor, bool> {
+ Expr *DefaultArg;
+ Sema *S;
+
+ public:
+ CheckDefaultArgumentVisitor(Expr *defarg, Sema *s)
+ : DefaultArg(defarg), S(s) {}
+
+ bool VisitExpr(Expr *Node);
+ bool VisitDeclRefExpr(DeclRefExpr *DRE);
+ bool VisitCXXThisExpr(CXXThisExpr *ThisE);
+ };
+
+ /// VisitExpr - Visit all of the children of this expression.
+ bool CheckDefaultArgumentVisitor::VisitExpr(Expr *Node) {
+ bool IsInvalid = false;
+ for (Stmt::child_iterator I = Node->child_begin(),
+ E = Node->child_end(); I != E; ++I)
+ IsInvalid |= Visit(*I);
+ return IsInvalid;
+ }
+
+ /// VisitDeclRefExpr - Visit a reference to a declaration, to
+ /// determine whether this declaration can be used in the default
+ /// argument expression.
+ bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) {
+ NamedDecl *Decl = DRE->getDecl();
+ if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(Decl)) {
+ // C++ [dcl.fct.default]p9
+ // Default arguments are evaluated each time the function is
+ // called. The order of evaluation of function arguments is
+ // unspecified. Consequently, parameters of a function shall not
+ // be used in default argument expressions, even if they are not
+ // evaluated. Parameters of a function declared before a default
+ // argument expression are in scope and can hide namespace and
+ // class member names.
+ return S->Diag(DRE->getSourceRange().getBegin(),
+ diag::err_param_default_argument_references_param)
+ << Param->getDeclName() << DefaultArg->getSourceRange();
+ } else if (VarDecl *VDecl = dyn_cast<VarDecl>(Decl)) {
+ // C++ [dcl.fct.default]p7
+ // Local variables shall not be used in default argument
+ // expressions.
+ if (VDecl->isBlockVarDecl())
+ return S->Diag(DRE->getSourceRange().getBegin(),
+ diag::err_param_default_argument_references_local)
+ << VDecl->getDeclName() << DefaultArg->getSourceRange();
+ }
+
+ return false;
+ }
+
+ /// VisitCXXThisExpr - Visit a C++ "this" expression.
+ bool CheckDefaultArgumentVisitor::VisitCXXThisExpr(CXXThisExpr *ThisE) {
+ // C++ [dcl.fct.default]p8:
+ // The keyword this shall not be used in a default argument of a
+ // member function.
+ return S->Diag(ThisE->getSourceRange().getBegin(),
+ diag::err_param_default_argument_references_this)
+ << ThisE->getSourceRange();
+ }
+}
+
+/// ActOnParamDefaultArgument - Check whether the default argument
+/// provided for a function parameter is well-formed. If so, attach it
+/// to the parameter declaration.
+void
+Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc,
+ ExprArg defarg) {
+ ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>());
+ ExprOwningPtr<Expr> DefaultArg(this, defarg.takeAs<Expr>());
+ QualType ParamType = Param->getType();
+
+ // Default arguments are only permitted in C++
+ if (!getLangOptions().CPlusPlus) {
+ Diag(EqualLoc, diag::err_param_default_argument)
+ << DefaultArg->getSourceRange();
+ Param->setInvalidDecl();
+ return;
+ }
+
+ // C++ [dcl.fct.default]p5
+ // A default argument expression is implicitly converted (clause
+ // 4) to the parameter type. The default argument expression has
+ // the same semantic constraints as the initializer expression in
+ // a declaration of a variable of the parameter type, using the
+ // copy-initialization semantics (8.5).
+ Expr *DefaultArgPtr = DefaultArg.get();
+ bool DefaultInitFailed = CheckInitializerTypes(DefaultArgPtr, ParamType,
+ EqualLoc,
+ Param->getDeclName(),
+ /*DirectInit=*/false);
+ if (DefaultArgPtr != DefaultArg.get()) {
+ DefaultArg.take();
+ DefaultArg.reset(DefaultArgPtr);
+ }
+ if (DefaultInitFailed) {
+ return;
+ }
+
+ // Check that the default argument is well-formed
+ CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg.get(), this);
+ if (DefaultArgChecker.Visit(DefaultArg.get())) {
+ Param->setInvalidDecl();
+ return;
+ }
+
+ // Okay: add the default argument to the parameter
+ Param->setDefaultArg(DefaultArg.take());
+}
+
+/// ActOnParamUnparsedDefaultArgument - We've seen a default
+/// argument for a function parameter, but we can't parse it yet
+/// because we're inside a class definition. Note that this default
+/// argument will be parsed later.
+void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param,
+ SourceLocation EqualLoc) {
+ ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>());
+ if (Param)
+ Param->setUnparsedDefaultArg();
+}
+
+/// ActOnParamDefaultArgumentError - Parsing or semantic analysis of
+/// the default argument for the parameter param failed.
+void Sema::ActOnParamDefaultArgumentError(DeclPtrTy param) {
+ cast<ParmVarDecl>(param.getAs<Decl>())->setInvalidDecl();
+}
+
+/// CheckExtraCXXDefaultArguments - Check for any extra default
+/// arguments in the declarator, which is not a function declaration
+/// or definition and therefore is not permitted to have default
+/// arguments. This routine should be invoked for every declarator
+/// that is not a function declaration or definition.
+void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
+ // C++ [dcl.fct.default]p3
+ // A default argument expression shall be specified only in the
+ // parameter-declaration-clause of a function declaration or in a
+ // template-parameter (14.1). It shall not be specified for a
+ // parameter pack. If it is specified in a
+ // parameter-declaration-clause, it shall not occur within a
+ // declarator or abstract-declarator of a parameter-declaration.
+ for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
+ DeclaratorChunk &chunk = D.getTypeObject(i);
+ if (chunk.Kind == DeclaratorChunk::Function) {
+ for (unsigned argIdx = 0, e = chunk.Fun.NumArgs; argIdx != e; ++argIdx) {
+ ParmVarDecl *Param =
+ cast<ParmVarDecl>(chunk.Fun.ArgInfo[argIdx].Param.getAs<Decl>());
+ if (Param->hasUnparsedDefaultArg()) {
+ CachedTokens *Toks = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens;
+ Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
+ << SourceRange((*Toks)[1].getLocation(), Toks->back().getLocation());
+ delete Toks;
+ chunk.Fun.ArgInfo[argIdx].DefaultArgTokens = 0;
+ } else if (Param->getDefaultArg()) {
+ Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
+ << Param->getDefaultArg()->getSourceRange();
+ Param->setDefaultArg(0);
+ }
+ }
+ }
+ }
+}
+
+// MergeCXXFunctionDecl - Merge two declarations of the same C++
+// function, once we already know that they have the same
+// type. Subroutine of MergeFunctionDecl. Returns true if there was an
+// error, false otherwise.
+bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
+ bool Invalid = false;
+
+ // C++ [dcl.fct.default]p4:
+ //
+ // For non-template functions, default arguments can be added in
+ // later declarations of a function in the same
+ // scope. Declarations in different scopes have completely
+ // distinct sets of default arguments. That is, declarations in
+ // inner scopes do not acquire default arguments from
+ // declarations in outer scopes, and vice versa. In a given
+ // function declaration, all parameters subsequent to a
+ // parameter with a default argument shall have default
+ // arguments supplied in this or previous declarations. A
+ // default argument shall not be redefined by a later
+ // declaration (not even to the same value).
+ for (unsigned p = 0, NumParams = Old->getNumParams(); p < NumParams; ++p) {
+ ParmVarDecl *OldParam = Old->getParamDecl(p);
+ ParmVarDecl *NewParam = New->getParamDecl(p);
+
+ if(OldParam->getDefaultArg() && NewParam->getDefaultArg()) {
+ Diag(NewParam->getLocation(),
+ diag::err_param_default_argument_redefinition)
+ << NewParam->getDefaultArg()->getSourceRange();
+ Diag(OldParam->getLocation(), diag::note_previous_definition);
+ Invalid = true;
+ } else if (OldParam->getDefaultArg()) {
+ // Merge the old default argument into the new parameter
+ NewParam->setDefaultArg(OldParam->getDefaultArg());
+ }
+ }
+
+ return Invalid;
+}
+
+/// CheckCXXDefaultArguments - Verify that the default arguments for a
+/// function declaration are well-formed according to C++
+/// [dcl.fct.default].
+void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
+ unsigned NumParams = FD->getNumParams();
+ unsigned p;
+
+ // Find first parameter with a default argument
+ for (p = 0; p < NumParams; ++p) {
+ ParmVarDecl *Param = FD->getParamDecl(p);
+ if (Param->getDefaultArg())
+ break;
+ }
+
+ // C++ [dcl.fct.default]p4:
+ // In a given function declaration, all parameters
+ // subsequent to a parameter with a default argument shall
+ // have default arguments supplied in this or previous
+ // declarations. A default argument shall not be redefined
+ // by a later declaration (not even to the same value).
+ unsigned LastMissingDefaultArg = 0;
+ for(; p < NumParams; ++p) {
+ ParmVarDecl *Param = FD->getParamDecl(p);
+ if (!Param->getDefaultArg()) {
+ if (Param->isInvalidDecl())
+ /* We already complained about this parameter. */;
+ else if (Param->getIdentifier())
+ Diag(Param->getLocation(),
+ diag::err_param_default_argument_missing_name)
+ << Param->getIdentifier();
+ else
+ Diag(Param->getLocation(),
+ diag::err_param_default_argument_missing);
+
+ LastMissingDefaultArg = p;
+ }
+ }
+
+ if (LastMissingDefaultArg > 0) {
+ // Some default arguments were missing. Clear out all of the
+ // default arguments up to (and including) the last missing
+ // default argument, so that we leave the function parameters
+ // in a semantically valid state.
+ for (p = 0; p <= LastMissingDefaultArg; ++p) {
+ ParmVarDecl *Param = FD->getParamDecl(p);
+ if (Param->getDefaultArg()) {
+ if (!Param->hasUnparsedDefaultArg())
+ Param->getDefaultArg()->Destroy(Context);
+ Param->setDefaultArg(0);
+ }
+ }
+ }
+}
+
+/// 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
+/// the innermost class.
+bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
+ const CXXScopeSpec *SS) {
+ CXXRecordDecl *CurDecl;
+ if (SS && SS->isSet() && !SS->isInvalid()) {
+ DeclContext *DC = computeDeclContext(*SS);
+ CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC);
+ } else
+ CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext);
+
+ if (CurDecl)
+ return &II == CurDecl->getIdentifier();
+ else
+ return false;
+}
+
+/// \brief Check the validity of a C++ base class specifier.
+///
+/// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics
+/// and returns NULL otherwise.
+CXXBaseSpecifier *
+Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
+ SourceRange SpecifierRange,
+ bool Virtual, AccessSpecifier Access,
+ QualType BaseType,
+ SourceLocation BaseLoc) {
+ // C++ [class.union]p1:
+ // A union shall not have base classes.
+ if (Class->isUnion()) {
+ Diag(Class->getLocation(), diag::err_base_clause_on_union)
+ << SpecifierRange;
+ return 0;
+ }
+
+ if (BaseType->isDependentType())
+ return new CXXBaseSpecifier(SpecifierRange, Virtual,
+ Class->getTagKind() == RecordDecl::TK_class,
+ Access, BaseType);
+
+ // Base specifiers must be record types.
+ if (!BaseType->isRecordType()) {
+ Diag(BaseLoc, diag::err_base_must_be_class) << SpecifierRange;
+ return 0;
+ }
+
+ // C++ [class.union]p1:
+ // A union shall not be used as a base class.
+ if (BaseType->isUnionType()) {
+ Diag(BaseLoc, diag::err_union_as_base_class) << SpecifierRange;
+ return 0;
+ }
+
+ // C++ [class.derived]p2:
+ // The class-name in a base-specifier shall not be an incompletely
+ // defined class.
+ if (RequireCompleteType(BaseLoc, BaseType, diag::err_incomplete_base_class,
+ SpecifierRange))
+ return 0;
+
+ // If the base class is polymorphic, the new one is, too.
+ RecordDecl *BaseDecl = BaseType->getAsRecordType()->getDecl();
+ assert(BaseDecl && "Record type has no declaration");
+ BaseDecl = BaseDecl->getDefinition(Context);
+ assert(BaseDecl && "Base type is not incomplete, but has no definition");
+ if (cast<CXXRecordDecl>(BaseDecl)->isPolymorphic())
+ Class->setPolymorphic(true);
+
+ // C++ [dcl.init.aggr]p1:
+ // An aggregate is [...] a class with [...] no base classes [...].
+ Class->setAggregate(false);
+ Class->setPOD(false);
+
+ if (Virtual) {
+ // C++ [class.ctor]p5:
+ // A constructor is trivial if its class has no virtual base classes.
+ Class->setHasTrivialConstructor(false);
+ } else {
+ // C++ [class.ctor]p5:
+ // A constructor is trivial if all the direct base classes of its
+ // class have trivial constructors.
+ Class->setHasTrivialConstructor(cast<CXXRecordDecl>(BaseDecl)->
+ hasTrivialConstructor());
+ }
+
+ // C++ [class.ctor]p3:
+ // A destructor is trivial if all the direct base classes of its class
+ // have trivial destructors.
+ Class->setHasTrivialDestructor(cast<CXXRecordDecl>(BaseDecl)->
+ hasTrivialDestructor());
+
+ // Create the base specifier.
+ // FIXME: Allocate via ASTContext?
+ return new CXXBaseSpecifier(SpecifierRange, Virtual,
+ Class->getTagKind() == RecordDecl::TK_class,
+ Access, BaseType);
+}
+
+/// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is
+/// one entry in the base class list of a class specifier, for
+/// example:
+/// class foo : public bar, virtual private baz {
+/// 'public bar' and 'virtual private baz' are each base-specifiers.
+Sema::BaseResult
+Sema::ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange,
+ bool Virtual, AccessSpecifier Access,
+ TypeTy *basetype, SourceLocation BaseLoc) {
+ AdjustDeclIfTemplate(classdecl);
+ CXXRecordDecl *Class = cast<CXXRecordDecl>(classdecl.getAs<Decl>());
+ QualType BaseType = QualType::getFromOpaquePtr(basetype);
+ if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange,
+ Virtual, Access,
+ BaseType, BaseLoc))
+ return BaseSpec;
+
+ return true;
+}
+
+/// \brief Performs the actual work of attaching the given base class
+/// specifiers to a C++ class.
+bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
+ unsigned NumBases) {
+ if (NumBases == 0)
+ return false;
+
+ // Used to keep track of which base types we have already seen, so
+ // that we can properly diagnose redundant direct base types. Note
+ // that the key is always the unqualified canonical type of the base
+ // class.
+ std::map<QualType, CXXBaseSpecifier*, QualTypeOrdering> KnownBaseTypes;
+
+ // Copy non-redundant base specifiers into permanent storage.
+ unsigned NumGoodBases = 0;
+ bool Invalid = false;
+ for (unsigned idx = 0; idx < NumBases; ++idx) {
+ QualType NewBaseType
+ = Context.getCanonicalType(Bases[idx]->getType());
+ NewBaseType = NewBaseType.getUnqualifiedType();
+
+ if (KnownBaseTypes[NewBaseType]) {
+ // C++ [class.mi]p3:
+ // A class shall not be specified as a direct base class of a
+ // derived class more than once.
+ Diag(Bases[idx]->getSourceRange().getBegin(),
+ diag::err_duplicate_base_class)
+ << KnownBaseTypes[NewBaseType]->getType()
+ << Bases[idx]->getSourceRange();
+
+ // Delete the duplicate base class specifier; we're going to
+ // overwrite its pointer later.
+ delete Bases[idx];
+
+ Invalid = true;
+ } else {
+ // Okay, add this new base class.
+ KnownBaseTypes[NewBaseType] = Bases[idx];
+ Bases[NumGoodBases++] = Bases[idx];
+ }
+ }
+
+ // Attach the remaining base class specifiers to the derived class.
+ Class->setBases(Bases, NumGoodBases);
+
+ // Delete the remaining (good) base class specifiers, since their
+ // data has been copied into the CXXRecordDecl.
+ for (unsigned idx = 0; idx < NumGoodBases; ++idx)
+ delete Bases[idx];
+
+ return Invalid;
+}
+
+/// ActOnBaseSpecifiers - Attach the given base specifiers to the
+/// class, after checking whether there are any duplicate base
+/// classes.
+void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases,
+ unsigned NumBases) {
+ if (!ClassDecl || !Bases || !NumBases)
+ return;
+
+ AdjustDeclIfTemplate(ClassDecl);
+ AttachBaseSpecifiers(cast<CXXRecordDecl>(ClassDecl.getAs<Decl>()),
+ (CXXBaseSpecifier**)(Bases), NumBases);
+}
+
+//===----------------------------------------------------------------------===//
+// C++ class member Handling
+//===----------------------------------------------------------------------===//
+
+/// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
+/// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the
+/// bitfield width if there is one and 'InitExpr' specifies the initializer if
+/// any.
+Sema::DeclPtrTy
+Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
+ ExprTy *BW, ExprTy *InitExpr, bool Deleted) {
+ const DeclSpec &DS = D.getDeclSpec();
+ DeclarationName Name = GetNameForDeclarator(D);
+ Expr *BitWidth = static_cast<Expr*>(BW);
+ Expr *Init = static_cast<Expr*>(InitExpr);
+ SourceLocation Loc = D.getIdentifierLoc();
+
+ bool isFunc = D.isFunctionDeclarator();
+
+ // C++ 9.2p6: A member shall not be declared to have automatic storage
+ // duration (auto, register) or with the extern storage-class-specifier.
+ // C++ 7.1.1p8: The mutable specifier can be applied only to names of class
+ // data members and cannot be applied to names declared const or static,
+ // and cannot be applied to reference members.
+ switch (DS.getStorageClassSpec()) {
+ case DeclSpec::SCS_unspecified:
+ case DeclSpec::SCS_typedef:
+ case DeclSpec::SCS_static:
+ // FALL THROUGH.
+ break;
+ case DeclSpec::SCS_mutable:
+ if (isFunc) {
+ if (DS.getStorageClassSpecLoc().isValid())
+ Diag(DS.getStorageClassSpecLoc(), diag::err_mutable_function);
+ else
+ Diag(DS.getThreadSpecLoc(), diag::err_mutable_function);
+
+ // FIXME: It would be nicer if the keyword was ignored only for this
+ // declarator. Otherwise we could get follow-up errors.
+ D.getMutableDeclSpec().ClearStorageClassSpecs();
+ } else {
+ QualType T = GetTypeForDeclarator(D, S);
+ diag::kind err = static_cast<diag::kind>(0);
+ if (T->isReferenceType())
+ err = diag::err_mutable_reference;
+ else if (T.isConstQualified())
+ err = diag::err_mutable_const;
+ if (err != 0) {
+ if (DS.getStorageClassSpecLoc().isValid())
+ Diag(DS.getStorageClassSpecLoc(), err);
+ else
+ Diag(DS.getThreadSpecLoc(), err);
+ // FIXME: It would be nicer if the keyword was ignored only for this
+ // declarator. Otherwise we could get follow-up errors.
+ D.getMutableDeclSpec().ClearStorageClassSpecs();
+ }
+ }
+ break;
+ default:
+ if (DS.getStorageClassSpecLoc().isValid())
+ Diag(DS.getStorageClassSpecLoc(),
+ diag::err_storageclass_invalid_for_member);
+ else
+ Diag(DS.getThreadSpecLoc(), diag::err_storageclass_invalid_for_member);
+ D.getMutableDeclSpec().ClearStorageClassSpecs();
+ }
+
+ if (!isFunc &&
+ D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_typename &&
+ D.getNumTypeObjects() == 0) {
+ // Check also for this case:
+ //
+ // typedef int f();
+ // f a;
+ //
+ QualType TDType = QualType::getFromOpaquePtr(DS.getTypeRep());
+ isFunc = TDType->isFunctionType();
+ }
+
+ bool isInstField = ((DS.getStorageClassSpec() == DeclSpec::SCS_unspecified ||
+ DS.getStorageClassSpec() == DeclSpec::SCS_mutable) &&
+ !isFunc);
+
+ Decl *Member;
+ if (isInstField) {
+ Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth,
+ AS);
+ assert(Member && "HandleField never returns null");
+ } else {
+ Member = ActOnDeclarator(S, D).getAs<Decl>();
+ if (!Member) {
+ if (BitWidth) DeleteExpr(BitWidth);
+ return DeclPtrTy();
+ }
+
+ // Non-instance-fields can't have a bitfield.
+ if (BitWidth) {
+ if (Member->isInvalidDecl()) {
+ // don't emit another diagnostic.
+ } else if (isa<VarDecl>(Member)) {
+ // C++ 9.6p3: A bit-field shall not be a static member.
+ // "static member 'A' cannot be a bit-field"
+ Diag(Loc, diag::err_static_not_bitfield)
+ << Name << BitWidth->getSourceRange();
+ } else if (isa<TypedefDecl>(Member)) {
+ // "typedef member 'x' cannot be a bit-field"
+ Diag(Loc, diag::err_typedef_not_bitfield)
+ << Name << BitWidth->getSourceRange();
+ } else {
+ // A function typedef ("typedef int f(); f a;").
+ // C++ 9.6p3: A bit-field shall have integral or enumeration type.
+ Diag(Loc, diag::err_not_integral_type_bitfield)
+ << Name << cast<ValueDecl>(Member)->getType()
+ << BitWidth->getSourceRange();
+ }
+
+ DeleteExpr(BitWidth);
+ BitWidth = 0;
+ Member->setInvalidDecl();
+ }
+
+ Member->setAccess(AS);
+ }
+
+ assert((Name || isInstField) && "No identifier for non-field ?");
+
+ if (Init)
+ AddInitializerToDecl(DeclPtrTy::make(Member), ExprArg(*this, Init), false);
+ if (Deleted) // FIXME: Source location is not very good.
+ SetDeclDeleted(DeclPtrTy::make(Member), D.getSourceRange().getBegin());
+
+ if (isInstField) {
+ FieldCollector->Add(cast<FieldDecl>(Member));
+ return DeclPtrTy();
+ }
+ return DeclPtrTy::make(Member);
+}
+
+/// ActOnMemInitializer - Handle a C++ member initializer.
+Sema::MemInitResult
+Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
+ Scope *S,
+ IdentifierInfo *MemberOrBase,
+ SourceLocation IdLoc,
+ SourceLocation LParenLoc,
+ ExprTy **Args, unsigned NumArgs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(ConstructorD.getAs<Decl>());
+ if (!Constructor) {
+ // The user wrote a constructor initializer on a function that is
+ // not a C++ constructor. Ignore the error for now, because we may
+ // have more member initializers coming; we'll diagnose it just
+ // once in ActOnMemInitializers.
+ return true;
+ }
+
+ CXXRecordDecl *ClassDecl = Constructor->getParent();
+
+ // C++ [class.base.init]p2:
+ // Names in a mem-initializer-id are looked up in the scope of the
+ // constructor’s class and, if not found in that scope, are looked
+ // up in the scope containing the constructor’s
+ // definition. [Note: if the constructor’s class contains a member
+ // with the same name as a direct or virtual base class of the
+ // class, a mem-initializer-id naming the member or base class and
+ // composed of a single identifier refers to the class member. A
+ // mem-initializer-id for the hidden base class may be specified
+ // using a qualified name. ]
+ // Look for a member, first.
+ FieldDecl *Member = 0;
+ DeclContext::lookup_result Result
+ = ClassDecl->lookup(Context, MemberOrBase);
+ if (Result.first != Result.second)
+ Member = dyn_cast<FieldDecl>(*Result.first);
+
+ // FIXME: Handle members of an anonymous union.
+
+ if (Member) {
+ // FIXME: Perform direct initialization of the member.
+ return new CXXBaseOrMemberInitializer(Member, (Expr **)Args, NumArgs);
+ }
+
+ // It didn't name a member, so see if it names a class.
+ TypeTy *BaseTy = getTypeName(*MemberOrBase, IdLoc, S, 0/*SS*/);
+ if (!BaseTy)
+ return Diag(IdLoc, diag::err_mem_init_not_member_or_class)
+ << MemberOrBase << SourceRange(IdLoc, RParenLoc);
+
+ QualType BaseType = QualType::getFromOpaquePtr(BaseTy);
+ if (!BaseType->isRecordType())
+ return Diag(IdLoc, diag::err_base_init_does_not_name_class)
+ << BaseType << SourceRange(IdLoc, RParenLoc);
+
+ // C++ [class.base.init]p2:
+ // [...] Unless the mem-initializer-id names a nonstatic data
+ // member of the constructor’s class or a direct or virtual base
+ // of that class, the mem-initializer is ill-formed. A
+ // mem-initializer-list can initialize a base class using any
+ // name that denotes that base class type.
+
+ // First, check for a direct base class.
+ const CXXBaseSpecifier *DirectBaseSpec = 0;
+ for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ if (Context.getCanonicalType(BaseType).getUnqualifiedType() ==
+ Context.getCanonicalType(Base->getType()).getUnqualifiedType()) {
+ // We found a direct base of this type. That's what we're
+ // initializing.
+ DirectBaseSpec = &*Base;
+ break;
+ }
+ }
+
+ // Check for a virtual base class.
+ // FIXME: We might be able to short-circuit this if we know in advance that
+ // there are no virtual bases.
+ const CXXBaseSpecifier *VirtualBaseSpec = 0;
+ if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) {
+ // We haven't found a base yet; search the class hierarchy for a
+ // virtual base class.
+ BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (IsDerivedFrom(Context.getTypeDeclType(ClassDecl), BaseType, Paths)) {
+ for (BasePaths::paths_iterator Path = Paths.begin();
+ Path != Paths.end(); ++Path) {
+ if (Path->back().Base->isVirtual()) {
+ VirtualBaseSpec = Path->back().Base;
+ break;
+ }
+ }
+ }
+ }
+
+ // C++ [base.class.init]p2:
+ // If a mem-initializer-id is ambiguous because it designates both
+ // a direct non-virtual base class and an inherited virtual base
+ // class, the mem-initializer is ill-formed.
+ if (DirectBaseSpec && VirtualBaseSpec)
+ return Diag(IdLoc, diag::err_base_init_direct_and_virtual)
+ << MemberOrBase << SourceRange(IdLoc, RParenLoc);
+
+ return new CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, NumArgs);
+}
+
+void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
+ SourceLocation ColonLoc,
+ MemInitTy **MemInits, unsigned NumMemInits) {
+ CXXConstructorDecl *Constructor =
+ dyn_cast<CXXConstructorDecl>(ConstructorDecl.getAs<Decl>());
+
+ if (!Constructor) {
+ Diag(ColonLoc, diag::err_only_constructors_take_base_inits);
+ return;
+ }
+}
+
+namespace {
+ /// PureVirtualMethodCollector - traverses a class and its superclasses
+ /// and determines if it has any pure virtual methods.
+ class VISIBILITY_HIDDEN PureVirtualMethodCollector {
+ ASTContext &Context;
+
+ public:
+ typedef llvm::SmallVector<const CXXMethodDecl*, 8> MethodList;
+
+ private:
+ MethodList Methods;
+
+ void Collect(const CXXRecordDecl* RD, MethodList& Methods);
+
+ public:
+ PureVirtualMethodCollector(ASTContext &Ctx, const CXXRecordDecl* RD)
+ : Context(Ctx) {
+
+ MethodList List;
+ Collect(RD, List);
+
+ // Copy the temporary list to methods, and make sure to ignore any
+ // null entries.
+ for (size_t i = 0, e = List.size(); i != e; ++i) {
+ if (List[i])
+ Methods.push_back(List[i]);
+ }
+ }
+
+ bool empty() const { return Methods.empty(); }
+
+ MethodList::const_iterator methods_begin() { return Methods.begin(); }
+ MethodList::const_iterator methods_end() { return Methods.end(); }
+ };
+
+ void PureVirtualMethodCollector::Collect(const CXXRecordDecl* RD,
+ MethodList& Methods) {
+ // First, collect the pure virtual methods for the base classes.
+ for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(),
+ BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) {
+ if (const RecordType *RT = Base->getType()->getAsRecordType()) {
+ const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (BaseDecl && BaseDecl->isAbstract())
+ Collect(BaseDecl, Methods);
+ }
+ }
+
+ // Next, zero out any pure virtual methods that this class overrides.
+ typedef llvm::SmallPtrSet<const CXXMethodDecl*, 4> MethodSetTy;
+
+ MethodSetTy OverriddenMethods;
+ size_t MethodsSize = Methods.size();
+
+ for (RecordDecl::decl_iterator i = RD->decls_begin(Context),
+ e = RD->decls_end(Context);
+ i != e; ++i) {
+ // Traverse the record, looking for methods.
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*i)) {
+ // If the method is pre virtual, add it to the methods vector.
+ if (MD->isPure()) {
+ Methods.push_back(MD);
+ continue;
+ }
+
+ // Otherwise, record all the overridden methods in our set.
+ for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+ E = MD->end_overridden_methods(); I != E; ++I) {
+ // Keep track of the overridden methods.
+ OverriddenMethods.insert(*I);
+ }
+ }
+ }
+
+ // Now go through the methods and zero out all the ones we know are
+ // overridden.
+ for (size_t i = 0, e = MethodsSize; i != e; ++i) {
+ if (OverriddenMethods.count(Methods[i]))
+ Methods[i] = 0;
+ }
+
+ }
+}
+
+bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
+ unsigned DiagID, AbstractDiagSelID SelID,
+ const CXXRecordDecl *CurrentRD) {
+
+ if (!getLangOptions().CPlusPlus)
+ return false;
+
+ if (const ArrayType *AT = Context.getAsArrayType(T))
+ return RequireNonAbstractType(Loc, AT->getElementType(), DiagID, SelID,
+ CurrentRD);
+
+ if (const PointerType *PT = T->getAsPointerType()) {
+ // Find the innermost pointer type.
+ while (const PointerType *T = PT->getPointeeType()->getAsPointerType())
+ PT = T;
+
+ if (const ArrayType *AT = Context.getAsArrayType(PT->getPointeeType()))
+ return RequireNonAbstractType(Loc, AT->getElementType(), DiagID, SelID,
+ CurrentRD);
+ }
+
+ const RecordType *RT = T->getAsRecordType();
+ if (!RT)
+ return false;
+
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD)
+ return false;
+
+ if (CurrentRD && CurrentRD != RD)
+ return false;
+
+ if (!RD->isAbstract())
+ return false;
+
+ Diag(Loc, DiagID) << RD->getDeclName() << SelID;
+
+ // Check if we've already emitted the list of pure virtual functions for this
+ // class.
+ if (PureVirtualClassDiagSet && PureVirtualClassDiagSet->count(RD))
+ return true;
+
+ PureVirtualMethodCollector Collector(Context, RD);
+
+ for (PureVirtualMethodCollector::MethodList::const_iterator I =
+ Collector.methods_begin(), E = Collector.methods_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ Diag(MD->getLocation(), diag::note_pure_virtual_function) <<
+ MD->getDeclName();
+ }
+
+ if (!PureVirtualClassDiagSet)
+ PureVirtualClassDiagSet.reset(new RecordDeclSetTy);
+ PureVirtualClassDiagSet->insert(RD);
+
+ return true;
+}
+
+namespace {
+ class VISIBILITY_HIDDEN AbstractClassUsageDiagnoser
+ : public DeclVisitor<AbstractClassUsageDiagnoser, bool> {
+ Sema &SemaRef;
+ CXXRecordDecl *AbstractClass;
+
+ bool VisitDeclContext(const DeclContext *DC) {
+ bool Invalid = false;
+
+ for (CXXRecordDecl::decl_iterator I = DC->decls_begin(SemaRef.Context),
+ E = DC->decls_end(SemaRef.Context); I != E; ++I)
+ Invalid |= Visit(*I);
+
+ return Invalid;
+ }
+
+ public:
+ AbstractClassUsageDiagnoser(Sema& SemaRef, CXXRecordDecl *ac)
+ : SemaRef(SemaRef), AbstractClass(ac) {
+ Visit(SemaRef.Context.getTranslationUnitDecl());
+ }
+
+ bool VisitFunctionDecl(const FunctionDecl *FD) {
+ if (FD->isThisDeclarationADefinition()) {
+ // No need to do the check if we're in a definition, because it requires
+ // that the return/param types are complete.
+ // because that requires
+ return VisitDeclContext(FD);
+ }
+
+ // Check the return type.
+ QualType RTy = FD->getType()->getAsFunctionType()->getResultType();
+ bool Invalid =
+ SemaRef.RequireNonAbstractType(FD->getLocation(), RTy,
+ diag::err_abstract_type_in_decl,
+ Sema::AbstractReturnType,
+ AbstractClass);
+
+ for (FunctionDecl::param_const_iterator I = FD->param_begin(),
+ E = FD->param_end(); I != E; ++I) {
+ const ParmVarDecl *VD = *I;
+ Invalid |=
+ SemaRef.RequireNonAbstractType(VD->getLocation(),
+ VD->getOriginalType(),
+ diag::err_abstract_type_in_decl,
+ Sema::AbstractParamType,
+ AbstractClass);
+ }
+
+ return Invalid;
+ }
+
+ bool VisitDecl(const Decl* D) {
+ if (const DeclContext *DC = dyn_cast<DeclContext>(D))
+ return VisitDeclContext(DC);
+
+ return false;
+ }
+ };
+}
+
+void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
+ DeclPtrTy TagDecl,
+ SourceLocation LBrac,
+ SourceLocation RBrac) {
+ AdjustDeclIfTemplate(TagDecl);
+ ActOnFields(S, RLoc, TagDecl,
+ (DeclPtrTy*)FieldCollector->getCurFields(),
+ FieldCollector->getCurNumFields(), LBrac, RBrac, 0);
+
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(TagDecl.getAs<Decl>());
+ if (!RD->isAbstract()) {
+ // Collect all the pure virtual methods and see if this is an abstract
+ // class after all.
+ PureVirtualMethodCollector Collector(Context, RD);
+ if (!Collector.empty())
+ RD->setAbstract(true);
+ }
+
+ if (RD->isAbstract())
+ AbstractClassUsageDiagnoser(*this, RD);
+
+ if (RD->hasTrivialConstructor() || RD->hasTrivialDestructor()) {
+ for (RecordDecl::field_iterator i = RD->field_begin(Context),
+ e = RD->field_end(Context); i != e; ++i) {
+ // All the nonstatic data members must have trivial constructors.
+ QualType FTy = i->getType();
+ while (const ArrayType *AT = Context.getAsArrayType(FTy))
+ FTy = AT->getElementType();
+
+ if (const RecordType *RT = FTy->getAsRecordType()) {
+ CXXRecordDecl *FieldRD = cast<CXXRecordDecl>(RT->getDecl());
+
+ if (!FieldRD->hasTrivialConstructor())
+ RD->setHasTrivialConstructor(false);
+ if (!FieldRD->hasTrivialDestructor())
+ RD->setHasTrivialDestructor(false);
+
+ // If RD has neither a trivial constructor nor a trivial destructor
+ // we don't need to continue checking.
+ if (!RD->hasTrivialConstructor() && !RD->hasTrivialDestructor())
+ break;
+ }
+ }
+ }
+
+ if (!RD->isDependentType())
+ AddImplicitlyDeclaredMembersToClass(RD);
+}
+
+/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
+/// special functions, such as the default constructor, copy
+/// constructor, or destructor, to the given C++ class (C++
+/// [special]p1). This routine can only be executed just before the
+/// definition of the class is complete.
+void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
+ QualType ClassType = Context.getTypeDeclType(ClassDecl);
+ ClassType = Context.getCanonicalType(ClassType);
+
+ // FIXME: Implicit declarations have exception specifications, which are
+ // the union of the specifications of the implicitly called functions.
+
+ if (!ClassDecl->hasUserDeclaredConstructor()) {
+ // C++ [class.ctor]p5:
+ // A default constructor for a class X is a constructor of class X
+ // that can be called without an argument. If there is no
+ // user-declared constructor for class X, a default constructor is
+ // implicitly declared. An implicitly-declared default constructor
+ // is an inline public member of its class.
+ DeclarationName Name
+ = Context.DeclarationNames.getCXXConstructorName(ClassType);
+ CXXConstructorDecl *DefaultCon =
+ CXXConstructorDecl::Create(Context, ClassDecl,
+ ClassDecl->getLocation(), Name,
+ Context.getFunctionType(Context.VoidTy,
+ 0, 0, false, 0),
+ /*isExplicit=*/false,
+ /*isInline=*/true,
+ /*isImplicitlyDeclared=*/true);
+ DefaultCon->setAccess(AS_public);
+ DefaultCon->setImplicit();
+ ClassDecl->addDecl(Context, DefaultCon);
+
+ // Notify the class that we've added a constructor.
+ ClassDecl->addedConstructor(Context, DefaultCon);
+ }
+
+ if (!ClassDecl->hasUserDeclaredCopyConstructor()) {
+ // C++ [class.copy]p4:
+ // If the class definition does not explicitly declare a copy
+ // constructor, one is declared implicitly.
+
+ // C++ [class.copy]p5:
+ // The implicitly-declared copy constructor for a class X will
+ // have the form
+ //
+ // X::X(const X&)
+ //
+ // if
+ bool HasConstCopyConstructor = true;
+
+ // -- each direct or virtual base class B of X has a copy
+ // constructor whose first parameter is of type const B& or
+ // const volatile B&, and
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
+ HasConstCopyConstructor && Base != ClassDecl->bases_end(); ++Base) {
+ const CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
+ HasConstCopyConstructor
+ = BaseClassDecl->hasConstCopyConstructor(Context);
+ }
+
+ // -- for all the nonstatic data members of X that are of a
+ // class type M (or array thereof), each such class type
+ // has a copy constructor whose first parameter is of type
+ // const M& or const volatile M&.
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(Context);
+ HasConstCopyConstructor && Field != ClassDecl->field_end(Context);
+ ++Field) {
+ QualType FieldType = (*Field)->getType();
+ if (const ArrayType *Array = Context.getAsArrayType(FieldType))
+ FieldType = Array->getElementType();
+ if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+ const CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ HasConstCopyConstructor
+ = FieldClassDecl->hasConstCopyConstructor(Context);
+ }
+ }
+
+ // Otherwise, the implicitly declared copy constructor will have
+ // the form
+ //
+ // X::X(X&)
+ QualType ArgType = ClassType;
+ if (HasConstCopyConstructor)
+ ArgType = ArgType.withConst();
+ ArgType = Context.getLValueReferenceType(ArgType);
+
+ // An implicitly-declared copy constructor is an inline public
+ // member of its class.
+ DeclarationName Name
+ = Context.DeclarationNames.getCXXConstructorName(ClassType);
+ CXXConstructorDecl *CopyConstructor
+ = CXXConstructorDecl::Create(Context, ClassDecl,
+ ClassDecl->getLocation(), Name,
+ Context.getFunctionType(Context.VoidTy,
+ &ArgType, 1,
+ false, 0),
+ /*isExplicit=*/false,
+ /*isInline=*/true,
+ /*isImplicitlyDeclared=*/true);
+ CopyConstructor->setAccess(AS_public);
+ CopyConstructor->setImplicit();
+
+ // Add the parameter to the constructor.
+ ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
+ ClassDecl->getLocation(),
+ /*IdentifierInfo=*/0,
+ ArgType, VarDecl::None, 0);
+ CopyConstructor->setParams(Context, &FromParam, 1);
+
+ ClassDecl->addedConstructor(Context, CopyConstructor);
+ ClassDecl->addDecl(Context, CopyConstructor);
+ }
+
+ if (!ClassDecl->hasUserDeclaredCopyAssignment()) {
+ // Note: The following rules are largely analoguous to the copy
+ // constructor rules. Note that virtual bases are not taken into account
+ // for determining the argument type of the operator. Note also that
+ // operators taking an object instead of a reference are allowed.
+ //
+ // C++ [class.copy]p10:
+ // If the class definition does not explicitly declare a copy
+ // assignment operator, one is declared implicitly.
+ // The implicitly-defined copy assignment operator for a class X
+ // will have the form
+ //
+ // X& X::operator=(const X&)
+ //
+ // if
+ bool HasConstCopyAssignment = true;
+
+ // -- each direct base class B of X has a copy assignment operator
+ // whose parameter is of type const B&, const volatile B& or B,
+ // and
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
+ HasConstCopyAssignment && Base != ClassDecl->bases_end(); ++Base) {
+ const CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
+ HasConstCopyAssignment = BaseClassDecl->hasConstCopyAssignment(Context);
+ }
+
+ // -- for all the nonstatic data members of X that are of a class
+ // type M (or array thereof), each such class type has a copy
+ // assignment operator whose parameter is of type const M&,
+ // const volatile M& or M.
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(Context);
+ HasConstCopyAssignment && Field != ClassDecl->field_end(Context);
+ ++Field) {
+ QualType FieldType = (*Field)->getType();
+ if (const ArrayType *Array = Context.getAsArrayType(FieldType))
+ FieldType = Array->getElementType();
+ if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
+ const CXXRecordDecl *FieldClassDecl
+ = cast<CXXRecordDecl>(FieldClassType->getDecl());
+ HasConstCopyAssignment
+ = FieldClassDecl->hasConstCopyAssignment(Context);
+ }
+ }
+
+ // Otherwise, the implicitly declared copy assignment operator will
+ // have the form
+ //
+ // X& X::operator=(X&)
+ QualType ArgType = ClassType;
+ QualType RetType = Context.getLValueReferenceType(ArgType);
+ if (HasConstCopyAssignment)
+ ArgType = ArgType.withConst();
+ ArgType = Context.getLValueReferenceType(ArgType);
+
+ // An implicitly-declared copy assignment operator is an inline public
+ // member of its class.
+ DeclarationName Name =
+ Context.DeclarationNames.getCXXOperatorName(OO_Equal);
+ CXXMethodDecl *CopyAssignment =
+ CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name,
+ Context.getFunctionType(RetType, &ArgType, 1,
+ false, 0),
+ /*isStatic=*/false, /*isInline=*/true);
+ CopyAssignment->setAccess(AS_public);
+ CopyAssignment->setImplicit();
+
+ // Add the parameter to the operator.
+ ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
+ ClassDecl->getLocation(),
+ /*IdentifierInfo=*/0,
+ ArgType, VarDecl::None, 0);
+ CopyAssignment->setParams(Context, &FromParam, 1);
+
+ // Don't call addedAssignmentOperator. There is no way to distinguish an
+ // implicit from an explicit assignment operator.
+ ClassDecl->addDecl(Context, CopyAssignment);
+ }
+
+ if (!ClassDecl->hasUserDeclaredDestructor()) {
+ // C++ [class.dtor]p2:
+ // If a class has no user-declared destructor, a destructor is
+ // declared implicitly. An implicitly-declared destructor is an
+ // inline public member of its class.
+ DeclarationName Name
+ = Context.DeclarationNames.getCXXDestructorName(ClassType);
+ CXXDestructorDecl *Destructor
+ = CXXDestructorDecl::Create(Context, ClassDecl,
+ ClassDecl->getLocation(), Name,
+ Context.getFunctionType(Context.VoidTy,
+ 0, 0, false, 0),
+ /*isInline=*/true,
+ /*isImplicitlyDeclared=*/true);
+ Destructor->setAccess(AS_public);
+ Destructor->setImplicit();
+ ClassDecl->addDecl(Context, Destructor);
+ }
+}
+
+void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) {
+ TemplateDecl *Template = TemplateD.getAs<TemplateDecl>();
+ if (!Template)
+ return;
+
+ TemplateParameterList *Params = Template->getTemplateParameters();
+ for (TemplateParameterList::iterator Param = Params->begin(),
+ ParamEnd = Params->end();
+ Param != ParamEnd; ++Param) {
+ NamedDecl *Named = cast<NamedDecl>(*Param);
+ if (Named->getDeclName()) {
+ S->AddDecl(DeclPtrTy::make(Named));
+ IdResolver.AddDecl(Named);
+ }
+ }
+}
+
+/// ActOnStartDelayedCXXMethodDeclaration - We have completed
+/// parsing a top-level (non-nested) C++ class, and we are now
+/// parsing those parts of the given Method declaration that could
+/// not be parsed earlier (C++ [class.mem]p2), such as default
+/// arguments. This action should enter the scope of the given
+/// Method declaration as if we had just parsed the qualified method
+/// name. However, it should not bring the parameters into scope;
+/// that will be performed by ActOnDelayedCXXMethodParameter.
+void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) {
+ CXXScopeSpec SS;
+ FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>());
+ QualType ClassTy
+ = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
+ SS.setScopeRep(
+ NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr()));
+ ActOnCXXEnterDeclaratorScope(S, SS);
+}
+
+/// ActOnDelayedCXXMethodParameter - We've already started a delayed
+/// C++ method declaration. We're (re-)introducing the given
+/// function parameter into scope for use in parsing later parts of
+/// the method declaration. For example, we could see an
+/// ActOnParamDefaultArgument event for this parameter.
+void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy ParamD) {
+ ParmVarDecl *Param = cast<ParmVarDecl>(ParamD.getAs<Decl>());
+
+ // If this parameter has an unparsed default argument, clear it out
+ // to make way for the parsed default argument.
+ if (Param->hasUnparsedDefaultArg())
+ Param->setDefaultArg(0);
+
+ S->AddDecl(DeclPtrTy::make(Param));
+ if (Param->getDeclName())
+ IdResolver.AddDecl(Param);
+}
+
+/// ActOnFinishDelayedCXXMethodDeclaration - We have finished
+/// processing the delayed method declaration for Method. The method
+/// declaration is now considered finished. There may be a separate
+/// ActOnStartOfFunctionDef action later (not necessarily
+/// immediately!) for this method, if it was also defined inside the
+/// class body.
+void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) {
+ FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>());
+ CXXScopeSpec SS;
+ QualType ClassTy
+ = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
+ SS.setScopeRep(
+ NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr()));
+ ActOnCXXExitDeclaratorScope(S, SS);
+
+ // Now that we have our default arguments, check the constructor
+ // again. It could produce additional diagnostics or affect whether
+ // the class has implicitly-declared destructors, among other
+ // things.
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Method))
+ CheckConstructor(Constructor);
+
+ // Check the default arguments, which we may have added.
+ if (!Method->isInvalidDecl())
+ CheckCXXDefaultArguments(Method);
+}
+
+/// CheckConstructorDeclarator - Called by ActOnDeclarator to check
+/// the well-formedness of the constructor declarator @p D with type @p
+/// R. If there are any errors in the declarator, this routine will
+/// emit diagnostics and set the invalid bit to true. In any case, the type
+/// will be updated to reflect a well-formed type for the constructor and
+/// returned.
+QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
+ FunctionDecl::StorageClass &SC) {
+ bool isVirtual = D.getDeclSpec().isVirtualSpecified();
+
+ // C++ [class.ctor]p3:
+ // A constructor shall not be virtual (10.3) or static (9.4). A
+ // constructor can be invoked for a const, volatile or const
+ // volatile object. A constructor shall not be declared const,
+ // volatile, or const volatile (9.3.2).
+ if (isVirtual) {
+ if (!D.isInvalidType())
+ Diag(D.getIdentifierLoc(), diag::err_constructor_cannot_be)
+ << "virtual" << SourceRange(D.getDeclSpec().getVirtualSpecLoc())
+ << SourceRange(D.getIdentifierLoc());
+ D.setInvalidType();
+ }
+ if (SC == FunctionDecl::Static) {
+ if (!D.isInvalidType())
+ Diag(D.getIdentifierLoc(), diag::err_constructor_cannot_be)
+ << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc())
+ << SourceRange(D.getIdentifierLoc());
+ D.setInvalidType();
+ SC = FunctionDecl::None;
+ }
+
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+ if (FTI.TypeQuals != 0) {
+ if (FTI.TypeQuals & QualType::Const)
+ Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor)
+ << "const" << SourceRange(D.getIdentifierLoc());
+ if (FTI.TypeQuals & QualType::Volatile)
+ Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor)
+ << "volatile" << SourceRange(D.getIdentifierLoc());
+ if (FTI.TypeQuals & QualType::Restrict)
+ Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor)
+ << "restrict" << SourceRange(D.getIdentifierLoc());
+ }
+
+ // Rebuild the function type "R" without any type qualifiers (in
+ // case any of the errors above fired) and with "void" as the
+ // return type, since constructors don't have return types. We
+ // *always* have to do this, because GetTypeForDeclarator will
+ // put in a result type of "int" when none was specified.
+ const FunctionProtoType *Proto = R->getAsFunctionProtoType();
+ return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(),
+ Proto->getNumArgs(),
+ Proto->isVariadic(), 0);
+}
+
+/// CheckConstructor - Checks a fully-formed constructor for
+/// well-formedness, issuing any diagnostics required. Returns true if
+/// the constructor declarator is invalid.
+void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
+ CXXRecordDecl *ClassDecl
+ = dyn_cast<CXXRecordDecl>(Constructor->getDeclContext());
+ if (!ClassDecl)
+ return Constructor->setInvalidDecl();
+
+ // C++ [class.copy]p3:
+ // A declaration of a constructor for a class X is ill-formed if
+ // its first parameter is of type (optionally cv-qualified) X and
+ // either there are no other parameters or else all other
+ // parameters have default arguments.
+ if (!Constructor->isInvalidDecl() &&
+ ((Constructor->getNumParams() == 1) ||
+ (Constructor->getNumParams() > 1 &&
+ Constructor->getParamDecl(1)->getDefaultArg() != 0))) {
+ QualType ParamType = Constructor->getParamDecl(0)->getType();
+ QualType ClassTy = Context.getTagDeclType(ClassDecl);
+ if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {
+ SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation();
+ Diag(ParamLoc, diag::err_constructor_byvalue_arg)
+ << CodeModificationHint::CreateInsertion(ParamLoc, " const &");
+ Constructor->setInvalidDecl();
+ }
+ }
+
+ // Notify the class that we've added a constructor.
+ ClassDecl->addedConstructor(Context, Constructor);
+}
+
+static inline bool
+FTIHasSingleVoidArgument(DeclaratorChunk::FunctionTypeInfo &FTI) {
+ return (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
+ FTI.ArgInfo[0].Param &&
+ FTI.ArgInfo[0].Param.getAs<ParmVarDecl>()->getType()->isVoidType());
+}
+
+/// CheckDestructorDeclarator - Called by ActOnDeclarator to check
+/// the well-formednes of the destructor declarator @p D with type @p
+/// R. If there are any errors in the declarator, this routine will
+/// emit diagnostics and set the declarator to invalid. Even if this happens,
+/// will be updated to reflect a well-formed type for the destructor and
+/// returned.
+QualType Sema::CheckDestructorDeclarator(Declarator &D,
+ FunctionDecl::StorageClass& SC) {
+ // C++ [class.dtor]p1:
+ // [...] A typedef-name that names a class is a class-name
+ // (7.1.3); however, a typedef-name that names a class shall not
+ // be used as the identifier in the declarator for a destructor
+ // declaration.
+ QualType DeclaratorType = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
+ if (isa<TypedefType>(DeclaratorType)) {
+ Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name)
+ << DeclaratorType;
+ D.setInvalidType();
+ }
+
+ // C++ [class.dtor]p2:
+ // A destructor is used to destroy objects of its class type. A
+ // destructor takes no parameters, and no return type can be
+ // specified for it (not even void). The address of a destructor
+ // shall not be taken. A destructor shall not be static. A
+ // destructor can be invoked for a const, volatile or const
+ // volatile object. A destructor shall not be declared const,
+ // volatile or const volatile (9.3.2).
+ if (SC == FunctionDecl::Static) {
+ if (!D.isInvalidType())
+ Diag(D.getIdentifierLoc(), diag::err_destructor_cannot_be)
+ << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc())
+ << SourceRange(D.getIdentifierLoc());
+ SC = FunctionDecl::None;
+ D.setInvalidType();
+ }
+ if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) {
+ // Destructors don't have return types, but the parser will
+ // happily parse something like:
+ //
+ // class X {
+ // float ~X();
+ // };
+ //
+ // The return type will be eliminated later.
+ Diag(D.getIdentifierLoc(), diag::err_destructor_return_type)
+ << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
+ << SourceRange(D.getIdentifierLoc());
+ }
+
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+ if (FTI.TypeQuals != 0 && !D.isInvalidType()) {
+ if (FTI.TypeQuals & QualType::Const)
+ Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor)
+ << "const" << SourceRange(D.getIdentifierLoc());
+ if (FTI.TypeQuals & QualType::Volatile)
+ Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor)
+ << "volatile" << SourceRange(D.getIdentifierLoc());
+ if (FTI.TypeQuals & QualType::Restrict)
+ Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor)
+ << "restrict" << SourceRange(D.getIdentifierLoc());
+ D.setInvalidType();
+ }
+
+ // Make sure we don't have any parameters.
+ if (FTI.NumArgs > 0 && !FTIHasSingleVoidArgument(FTI)) {
+ Diag(D.getIdentifierLoc(), diag::err_destructor_with_params);
+
+ // Delete the parameters.
+ FTI.freeArgs();
+ D.setInvalidType();
+ }
+
+ // Make sure the destructor isn't variadic.
+ if (FTI.isVariadic) {
+ Diag(D.getIdentifierLoc(), diag::err_destructor_variadic);
+ D.setInvalidType();
+ }
+
+ // Rebuild the function type "R" without any type qualifiers or
+ // parameters (in case any of the errors above fired) and with
+ // "void" as the return type, since destructors don't have return
+ // types. We *always* have to do this, because GetTypeForDeclarator
+ // will put in a result type of "int" when none was specified.
+ return Context.getFunctionType(Context.VoidTy, 0, 0, false, 0);
+}
+
+/// CheckConversionDeclarator - Called by ActOnDeclarator to check the
+/// well-formednes of the conversion function declarator @p D with
+/// type @p R. If there are any errors in the declarator, this routine
+/// will emit diagnostics and return true. Otherwise, it will return
+/// false. Either way, the type @p R will be updated to reflect a
+/// well-formed type for the conversion operator.
+void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
+ FunctionDecl::StorageClass& SC) {
+ // C++ [class.conv.fct]p1:
+ // Neither parameter types nor return type can be specified. The
+ // type of a conversion function (8.3.5) is “function taking no
+ // parameter returning conversion-type-id.â€
+ if (SC == FunctionDecl::Static) {
+ if (!D.isInvalidType())
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_not_member)
+ << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc())
+ << SourceRange(D.getIdentifierLoc());
+ D.setInvalidType();
+ SC = FunctionDecl::None;
+ }
+ if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) {
+ // Conversion functions don't have return types, but the parser will
+ // happily parse something like:
+ //
+ // class X {
+ // float operator bool();
+ // };
+ //
+ // The return type will be changed later anyway.
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_return_type)
+ << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
+ << SourceRange(D.getIdentifierLoc());
+ }
+
+ // Make sure we don't have any parameters.
+ if (R->getAsFunctionProtoType()->getNumArgs() > 0) {
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params);
+
+ // Delete the parameters.
+ D.getTypeObject(0).Fun.freeArgs();
+ D.setInvalidType();
+ }
+
+ // Make sure the conversion function isn't variadic.
+ if (R->getAsFunctionProtoType()->isVariadic() && !D.isInvalidType()) {
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic);
+ D.setInvalidType();
+ }
+
+ // C++ [class.conv.fct]p4:
+ // The conversion-type-id shall not represent a function type nor
+ // an array type.
+ QualType ConvType = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
+ if (ConvType->isArrayType()) {
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array);
+ ConvType = Context.getPointerType(ConvType);
+ D.setInvalidType();
+ } else if (ConvType->isFunctionType()) {
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_to_function);
+ ConvType = Context.getPointerType(ConvType);
+ D.setInvalidType();
+ }
+
+ // Rebuild the function type "R" without any parameters (in case any
+ // of the errors above fired) and with the conversion type as the
+ // return type.
+ R = Context.getFunctionType(ConvType, 0, 0, false,
+ R->getAsFunctionProtoType()->getTypeQuals());
+
+ // C++0x explicit conversion operators.
+ if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x)
+ Diag(D.getDeclSpec().getExplicitSpecLoc(),
+ diag::warn_explicit_conversion_functions)
+ << SourceRange(D.getDeclSpec().getExplicitSpecLoc());
+}
+
+/// ActOnConversionDeclarator - Called by ActOnDeclarator to complete
+/// the declaration of the given C++ conversion function. This routine
+/// is responsible for recording the conversion function in the C++
+/// class, if possible.
+Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
+ assert(Conversion && "Expected to receive a conversion function declaration");
+
+ // Set the lexical context of this conversion function
+ Conversion->setLexicalDeclContext(CurContext);
+
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Conversion->getDeclContext());
+
+ // Make sure we aren't redeclaring the conversion function.
+ QualType ConvType = Context.getCanonicalType(Conversion->getConversionType());
+
+ // C++ [class.conv.fct]p1:
+ // [...] A conversion function is never used to convert a
+ // (possibly cv-qualified) object to the (possibly cv-qualified)
+ // same object type (or a reference to it), to a (possibly
+ // cv-qualified) base class of that type (or a reference to it),
+ // or to (possibly cv-qualified) void.
+ // FIXME: Suppress this warning if the conversion function ends up being a
+ // virtual function that overrides a virtual function in a base class.
+ QualType ClassType
+ = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
+ if (const ReferenceType *ConvTypeRef = ConvType->getAsReferenceType())
+ ConvType = ConvTypeRef->getPointeeType();
+ if (ConvType->isRecordType()) {
+ ConvType = Context.getCanonicalType(ConvType).getUnqualifiedType();
+ if (ConvType == ClassType)
+ Diag(Conversion->getLocation(), diag::warn_conv_to_self_not_used)
+ << ClassType;
+ else if (IsDerivedFrom(ClassType, ConvType))
+ Diag(Conversion->getLocation(), diag::warn_conv_to_base_not_used)
+ << ClassType << ConvType;
+ } else if (ConvType->isVoidType()) {
+ Diag(Conversion->getLocation(), diag::warn_conv_to_void_not_used)
+ << ClassType << ConvType;
+ }
+
+ if (Conversion->getPreviousDeclaration()) {
+ OverloadedFunctionDecl *Conversions = ClassDecl->getConversionFunctions();
+ for (OverloadedFunctionDecl::function_iterator
+ Conv = Conversions->function_begin(),
+ ConvEnd = Conversions->function_end();
+ Conv != ConvEnd; ++Conv) {
+ if (*Conv == Conversion->getPreviousDeclaration()) {
+ *Conv = Conversion;
+ return DeclPtrTy::make(Conversion);
+ }
+ }
+ assert(Conversion->isInvalidDecl() && "Conversion should not get here.");
+ } else
+ ClassDecl->addConversionFunction(Context, Conversion);
+
+ return DeclPtrTy::make(Conversion);
+}
+
+//===----------------------------------------------------------------------===//
+// Namespace Handling
+//===----------------------------------------------------------------------===//
+
+/// ActOnStartNamespaceDef - This is called at the start of a namespace
+/// definition.
+Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
+ SourceLocation IdentLoc,
+ IdentifierInfo *II,
+ SourceLocation LBrace) {
+ NamespaceDecl *Namespc =
+ NamespaceDecl::Create(Context, CurContext, IdentLoc, II);
+ Namespc->setLBracLoc(LBrace);
+
+ Scope *DeclRegionScope = NamespcScope->getParent();
+
+ if (II) {
+ // C++ [namespace.def]p2:
+ // The identifier in an original-namespace-definition shall not have been
+ // previously defined in the declarative region in which the
+ // original-namespace-definition appears. The identifier in an
+ // original-namespace-definition is the name of the namespace. Subsequently
+ // in that declarative region, it is treated as an original-namespace-name.
+
+ NamedDecl *PrevDecl = LookupName(DeclRegionScope, II, LookupOrdinaryName,
+ true);
+
+ if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) {
+ // This is an extended namespace definition.
+ // Attach this namespace decl to the chain of extended namespace
+ // definitions.
+ OrigNS->setNextNamespace(Namespc);
+ Namespc->setOriginalNamespace(OrigNS->getOriginalNamespace());
+
+ // Remove the previous declaration from the scope.
+ if (DeclRegionScope->isDeclScope(DeclPtrTy::make(OrigNS))) {
+ IdResolver.RemoveDecl(OrigNS);
+ DeclRegionScope->RemoveDecl(DeclPtrTy::make(OrigNS));
+ }
+ } else if (PrevDecl) {
+ // This is an invalid name redefinition.
+ Diag(Namespc->getLocation(), diag::err_redefinition_different_kind)
+ << Namespc->getDeclName();
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ Namespc->setInvalidDecl();
+ // Continue on to push Namespc as current DeclContext and return it.
+ }
+
+ PushOnScopeChains(Namespc, DeclRegionScope);
+ } else {
+ // FIXME: Handle anonymous namespaces
+ }
+
+ // Although we could have an invalid decl (i.e. the namespace name is a
+ // redefinition), push it as current DeclContext and try to continue parsing.
+ // FIXME: We should be able to push Namespc here, so that the each DeclContext
+ // for the namespace has the declarations that showed up in that particular
+ // namespace definition.
+ PushDeclContext(NamespcScope, Namespc);
+ return DeclPtrTy::make(Namespc);
+}
+
+/// ActOnFinishNamespaceDef - This callback is called after a namespace is
+/// exited. Decl is the DeclTy returned by ActOnStartNamespaceDef.
+void Sema::ActOnFinishNamespaceDef(DeclPtrTy D, SourceLocation RBrace) {
+ Decl *Dcl = D.getAs<Decl>();
+ NamespaceDecl *Namespc = dyn_cast_or_null<NamespaceDecl>(Dcl);
+ assert(Namespc && "Invalid parameter, expected NamespaceDecl");
+ Namespc->setRBracLoc(RBrace);
+ PopDeclContext();
+}
+
+Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S,
+ SourceLocation UsingLoc,
+ SourceLocation NamespcLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *NamespcName,
+ AttributeList *AttrList) {
+ assert(!SS.isInvalid() && "Invalid CXXScopeSpec.");
+ assert(NamespcName && "Invalid NamespcName.");
+ assert(IdentLoc.isValid() && "Invalid NamespceName location.");
+ assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
+
+ UsingDirectiveDecl *UDir = 0;
+
+ // Lookup namespace name.
+ LookupResult R = LookupParsedName(S, &SS, NamespcName,
+ LookupNamespaceName, false);
+ if (R.isAmbiguous()) {
+ DiagnoseAmbiguousLookup(R, NamespcName, IdentLoc);
+ return DeclPtrTy();
+ }
+ if (NamedDecl *NS = R) {
+ assert(isa<NamespaceDecl>(NS) && "expected namespace decl");
+ // C++ [namespace.udir]p1:
+ // A using-directive specifies that the names in the nominated
+ // namespace can be used in the scope in which the
+ // using-directive appears after the using-directive. During
+ // unqualified name lookup (3.4.1), the names appear as if they
+ // were declared in the nearest enclosing namespace which
+ // contains both the using-directive and the nominated
+ // namespace. [Note: in this context, “contains†means “contains
+ // directly or indirectlyâ€. ]
+
+ // Find enclosing context containing both using-directive and
+ // nominated namespace.
+ DeclContext *CommonAncestor = cast<DeclContext>(NS);
+ while (CommonAncestor && !CommonAncestor->Encloses(CurContext))
+ CommonAncestor = CommonAncestor->getParent();
+
+ UDir = UsingDirectiveDecl::Create(Context,
+ CurContext, UsingLoc,
+ NamespcLoc,
+ SS.getRange(),
+ (NestedNameSpecifier *)SS.getScopeRep(),
+ IdentLoc,
+ cast<NamespaceDecl>(NS),
+ CommonAncestor);
+ PushUsingDirective(S, UDir);
+ } else {
+ Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
+ }
+
+ // FIXME: We ignore attributes for now.
+ delete AttrList;
+ return DeclPtrTy::make(UDir);
+}
+
+void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) {
+ // If scope has associated entity, then using directive is at namespace
+ // or translation unit scope. We add UsingDirectiveDecls, into
+ // it's lookup structure.
+ if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()))
+ Ctx->addDecl(Context, UDir);
+ else
+ // Otherwise it is block-sope. using-directives will affect lookup
+ // only to the end of scope.
+ S->PushUsingDirective(DeclPtrTy::make(UDir));
+}
+
+/// getNamespaceDecl - Returns the namespace a decl represents. If the decl
+/// is a namespace alias, returns the namespace it points to.
+static inline NamespaceDecl *getNamespaceDecl(NamedDecl *D) {
+ if (NamespaceAliasDecl *AD = dyn_cast_or_null<NamespaceAliasDecl>(D))
+ return AD->getNamespace();
+ return dyn_cast_or_null<NamespaceDecl>(D);
+}
+
+Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
+ SourceLocation NamespaceLoc,
+ SourceLocation AliasLoc,
+ IdentifierInfo *Alias,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *Ident) {
+
+ // Lookup the namespace name.
+ LookupResult R = LookupParsedName(S, &SS, Ident, LookupNamespaceName, false);
+
+ // Check if we have a previous declaration with the same name.
+ if (NamedDecl *PrevDecl = LookupName(S, Alias, LookupOrdinaryName, true)) {
+ if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
+ // We already have an alias with the same name that points to the same
+ // namespace, so don't create a new one.
+ if (!R.isAmbiguous() && AD->getNamespace() == getNamespaceDecl(R))
+ return DeclPtrTy();
+ }
+
+ unsigned DiagID = isa<NamespaceDecl>(PrevDecl) ? diag::err_redefinition :
+ diag::err_redefinition_different_kind;
+ Diag(AliasLoc, DiagID) << Alias;
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ return DeclPtrTy();
+ }
+
+ if (R.isAmbiguous()) {
+ DiagnoseAmbiguousLookup(R, Ident, IdentLoc);
+ return DeclPtrTy();
+ }
+
+ if (!R) {
+ Diag(NamespaceLoc, diag::err_expected_namespace_name) << SS.getRange();
+ return DeclPtrTy();
+ }
+
+ NamespaceAliasDecl *AliasDecl =
+ NamespaceAliasDecl::Create(Context, CurContext, NamespaceLoc, AliasLoc,
+ Alias, SS.getRange(),
+ (NestedNameSpecifier *)SS.getScopeRep(),
+ IdentLoc, R);
+
+ CurContext->addDecl(Context, AliasDecl);
+ return DeclPtrTy::make(AliasDecl);
+}
+
+void Sema::InitializeVarWithConstructor(VarDecl *VD,
+ CXXConstructorDecl *Constructor,
+ QualType DeclInitType,
+ Expr **Exprs, unsigned NumExprs) {
+ Expr *Temp = CXXConstructExpr::Create(Context, DeclInitType, Constructor,
+ false, Exprs, NumExprs);
+ VD->setInit(Context, Temp);
+}
+
+/// AddCXXDirectInitializerToDecl - This action is called immediately after
+/// ActOnDeclarator, when a C++ direct initializer is present.
+/// e.g: "int x(1);"
+void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
+ SourceLocation LParenLoc,
+ MultiExprArg Exprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ unsigned NumExprs = Exprs.size();
+ assert(NumExprs != 0 && Exprs.get() && "missing expressions");
+ Decl *RealDecl = Dcl.getAs<Decl>();
+
+ // If there is no declaration, there was an error parsing it. Just ignore
+ // the initializer.
+ if (RealDecl == 0)
+ return;
+
+ VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl);
+ if (!VDecl) {
+ Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
+ RealDecl->setInvalidDecl();
+ return;
+ }
+
+ // FIXME: Need to handle dependent types and expressions here.
+
+ // We will treat direct-initialization as a copy-initialization:
+ // int x(1); -as-> int x = 1;
+ // ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c);
+ //
+ // Clients that want to distinguish between the two forms, can check for
+ // direct initializer using VarDecl::hasCXXDirectInitializer().
+ // A major benefit is that clients that don't particularly care about which
+ // exactly form was it (like the CodeGen) can handle both cases without
+ // special case code.
+
+ // C++ 8.5p11:
+ // The form of initialization (using parentheses or '=') is generally
+ // insignificant, but does matter when the entity being initialized has a
+ // class type.
+ QualType DeclInitType = VDecl->getType();
+ if (const ArrayType *Array = Context.getAsArrayType(DeclInitType))
+ DeclInitType = Array->getElementType();
+
+ // FIXME: This isn't the right place to complete the type.
+ if (RequireCompleteType(VDecl->getLocation(), VDecl->getType(),
+ diag::err_typecheck_decl_incomplete_type)) {
+ VDecl->setInvalidDecl();
+ return;
+ }
+
+ if (VDecl->getType()->isRecordType()) {
+ CXXConstructorDecl *Constructor
+ = PerformInitializationByConstructor(DeclInitType,
+ (Expr **)Exprs.get(), NumExprs,
+ VDecl->getLocation(),
+ SourceRange(VDecl->getLocation(),
+ RParenLoc),
+ VDecl->getDeclName(),
+ IK_Direct);
+ if (!Constructor)
+ RealDecl->setInvalidDecl();
+ else {
+ VDecl->setCXXDirectInitializer(true);
+ InitializeVarWithConstructor(VDecl, Constructor, DeclInitType,
+ (Expr**)Exprs.release(), NumExprs);
+ }
+ return;
+ }
+
+ if (NumExprs > 1) {
+ Diag(CommaLocs[0], diag::err_builtin_direct_init_more_than_one_arg)
+ << SourceRange(VDecl->getLocation(), RParenLoc);
+ RealDecl->setInvalidDecl();
+ return;
+ }
+
+ // Let clients know that initialization was done with a direct initializer.
+ VDecl->setCXXDirectInitializer(true);
+
+ assert(NumExprs == 1 && "Expected 1 expression");
+ // Set the init expression, handles conversions.
+ AddInitializerToDecl(Dcl, ExprArg(*this, Exprs.release()[0]),
+ /*DirectInit=*/true);
+}
+
+/// PerformInitializationByConstructor - Perform initialization by
+/// constructor (C++ [dcl.init]p14), which may occur as part of
+/// direct-initialization or copy-initialization. We are initializing
+/// an object of type @p ClassType with the given arguments @p
+/// Args. @p Loc is the location in the source code where the
+/// initializer occurs (e.g., a declaration, member initializer,
+/// functional cast, etc.) while @p Range covers the whole
+/// initialization. @p InitEntity is the entity being initialized,
+/// which may by the name of a declaration or a type. @p Kind is the
+/// kind of initialization we're performing, which affects whether
+/// explicit constructors will be considered. When successful, returns
+/// the constructor that will be used to perform the initialization;
+/// when the initialization fails, emits a diagnostic and returns
+/// null.
+CXXConstructorDecl *
+Sema::PerformInitializationByConstructor(QualType ClassType,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation Loc, SourceRange Range,
+ DeclarationName InitEntity,
+ InitializationKind Kind) {
+ const RecordType *ClassRec = ClassType->getAsRecordType();
+ assert(ClassRec && "Can only initialize a class type here");
+
+ // C++ [dcl.init]p14:
+ //
+ // If the initialization is direct-initialization, or if it is
+ // copy-initialization where the cv-unqualified version of the
+ // source type is the same class as, or a derived class of, the
+ // class of the destination, constructors are considered. The
+ // applicable constructors are enumerated (13.3.1.3), and the
+ // best one is chosen through overload resolution (13.3). The
+ // constructor so selected is called to initialize the object,
+ // with the initializer expression(s) as its argument(s). If no
+ // constructor applies, or the overload resolution is ambiguous,
+ // the initialization is ill-formed.
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl());
+ OverloadCandidateSet CandidateSet;
+
+ // Add constructors to the overload set.
+ DeclarationName ConstructorName
+ = Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(ClassType.getUnqualifiedType()));
+ DeclContext::lookup_const_iterator Con, ConEnd;
+ for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(Context, ConstructorName);
+ Con != ConEnd; ++Con) {
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
+ if ((Kind == IK_Direct) ||
+ (Kind == IK_Copy && Constructor->isConvertingConstructor()) ||
+ (Kind == IK_Default && Constructor->isDefaultConstructor()))
+ AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+ }
+
+ // FIXME: When we decide not to synthesize the implicitly-declared
+ // constructors, we'll need to make them appear here.
+
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(CandidateSet, Best)) {
+ case OR_Success:
+ // We found a constructor. Return it.
+ return cast<CXXConstructorDecl>(Best->Function);
+
+ case OR_No_Viable_Function:
+ if (InitEntity)
+ Diag(Loc, diag::err_ovl_no_viable_function_in_init)
+ << InitEntity << Range;
+ else
+ Diag(Loc, diag::err_ovl_no_viable_function_in_init)
+ << ClassType << Range;
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ return 0;
+
+ case OR_Ambiguous:
+ if (InitEntity)
+ Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range;
+ else
+ Diag(Loc, diag::err_ovl_ambiguous_init) << ClassType << Range;
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ return 0;
+
+ case OR_Deleted:
+ if (InitEntity)
+ Diag(Loc, diag::err_ovl_deleted_init)
+ << Best->Function->isDeleted()
+ << InitEntity << Range;
+ else
+ Diag(Loc, diag::err_ovl_deleted_init)
+ << Best->Function->isDeleted()
+ << InitEntity << Range;
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ return 0;
+ }
+
+ return 0;
+}
+
+/// CompareReferenceRelationship - Compare the two types T1 and T2 to
+/// determine whether they are reference-related,
+/// reference-compatible, reference-compatible with added
+/// qualification, or incompatible, for use in C++ initialization by
+/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference
+/// type, and the first type (T1) is the pointee type of the reference
+/// type being initialized.
+Sema::ReferenceCompareResult
+Sema::CompareReferenceRelationship(QualType T1, QualType T2,
+ bool& DerivedToBase) {
+ assert(!T1->isReferenceType() &&
+ "T1 must be the pointee type of the reference type");
+ assert(!T2->isReferenceType() && "T2 cannot be a reference type");
+
+ T1 = Context.getCanonicalType(T1);
+ T2 = Context.getCanonicalType(T2);
+ QualType UnqualT1 = T1.getUnqualifiedType();
+ QualType UnqualT2 = T2.getUnqualifiedType();
+
+ // C++ [dcl.init.ref]p4:
+ // Given types “cv1 T1†and “cv2 T2,†“cv1 T1†is
+ // reference-related to “cv2 T2†if T1 is the same type as T2, or
+ // T1 is a base class of T2.
+ if (UnqualT1 == UnqualT2)
+ DerivedToBase = false;
+ else if (IsDerivedFrom(UnqualT2, UnqualT1))
+ DerivedToBase = true;
+ else
+ return Ref_Incompatible;
+
+ // At this point, we know that T1 and T2 are reference-related (at
+ // least).
+
+ // C++ [dcl.init.ref]p4:
+ // "cv1 T1†is reference-compatible with “cv2 T2†if T1 is
+ // reference-related to T2 and cv1 is the same cv-qualification
+ // as, or greater cv-qualification than, cv2. For purposes of
+ // overload resolution, cases for which cv1 is greater
+ // cv-qualification than cv2 are identified as
+ // reference-compatible with added qualification (see 13.3.3.2).
+ if (T1.getCVRQualifiers() == T2.getCVRQualifiers())
+ return Ref_Compatible;
+ else if (T1.isMoreQualifiedThan(T2))
+ return Ref_Compatible_With_Added_Qualification;
+ else
+ return Ref_Related;
+}
+
+/// CheckReferenceInit - Check the initialization of a reference
+/// variable with the given initializer (C++ [dcl.init.ref]). Init is
+/// the initializer (either a simple initializer or an initializer
+/// list), and DeclType is the type of the declaration. When ICS is
+/// non-null, this routine will compute the implicit conversion
+/// sequence according to C++ [over.ics.ref] and will not produce any
+/// diagnostics; when ICS is null, it will emit diagnostics when any
+/// errors are found. Either way, a return value of true indicates
+/// that there was a failure, a return value of false indicates that
+/// the reference initialization succeeded.
+///
+/// When @p SuppressUserConversions, user-defined conversions are
+/// suppressed.
+/// When @p AllowExplicit, we also permit explicit user-defined
+/// conversion functions.
+/// When @p ForceRValue, we unconditionally treat the initializer as an rvalue.
+bool
+Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
+ ImplicitConversionSequence *ICS,
+ bool SuppressUserConversions,
+ bool AllowExplicit, bool ForceRValue) {
+ assert(DeclType->isReferenceType() && "Reference init needs a reference");
+
+ QualType T1 = DeclType->getAsReferenceType()->getPointeeType();
+ QualType T2 = Init->getType();
+
+ // If the initializer is the address of an overloaded function, try
+ // to resolve the overloaded function. If all goes well, T2 is the
+ // type of the resulting function.
+ if (Context.getCanonicalType(T2) == Context.OverloadTy) {
+ FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType,
+ ICS != 0);
+ if (Fn) {
+ // Since we're performing this reference-initialization for
+ // real, update the initializer with the resulting function.
+ if (!ICS) {
+ if (DiagnoseUseOfDecl(Fn, Init->getSourceRange().getBegin()))
+ return true;
+
+ FixOverloadedFunctionReference(Init, Fn);
+ }
+
+ T2 = Fn->getType();
+ }
+ }
+
+ // Compute some basic properties of the types and the initializer.
+ bool isRValRef = DeclType->isRValueReferenceType();
+ bool DerivedToBase = false;
+ Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression :
+ Init->isLvalue(Context);
+ ReferenceCompareResult RefRelationship
+ = CompareReferenceRelationship(T1, T2, DerivedToBase);
+
+ // Most paths end in a failed conversion.
+ if (ICS)
+ ICS->ConversionKind = ImplicitConversionSequence::BadConversion;
+
+ // C++ [dcl.init.ref]p5:
+ // A reference to type “cv1 T1†is initialized by an expression
+ // of type “cv2 T2†as follows:
+
+ // -- If the initializer expression
+
+ // Rvalue references cannot bind to lvalues (N2812).
+ // There is absolutely no situation where they can. In particular, note that
+ // this is ill-formed, even if B has a user-defined conversion to A&&:
+ // B b;
+ // A&& r = b;
+ if (isRValRef && InitLvalue == Expr::LV_Valid) {
+ if (!ICS)
+ Diag(Init->getSourceRange().getBegin(), diag::err_lvalue_to_rvalue_ref)
+ << Init->getSourceRange();
+ return true;
+ }
+
+ bool BindsDirectly = false;
+ // -- is an lvalue (but is not a bit-field), and “cv1 T1†is
+ // reference-compatible with “cv2 T2,†or
+ //
+ // Note that the bit-field check is skipped if we are just computing
+ // the implicit conversion sequence (C++ [over.best.ics]p2).
+ if (InitLvalue == Expr::LV_Valid && (ICS || !Init->getBitField()) &&
+ RefRelationship >= Ref_Compatible_With_Added_Qualification) {
+ BindsDirectly = true;
+
+ if (ICS) {
+ // C++ [over.ics.ref]p1:
+ // When a parameter of reference type binds directly (8.5.3)
+ // to an argument expression, the implicit conversion sequence
+ // is the identity conversion, unless the argument expression
+ // has a type that is a derived class of the parameter type,
+ // in which case the implicit conversion sequence is a
+ // derived-to-base Conversion (13.3.3.1).
+ ICS->ConversionKind = ImplicitConversionSequence::StandardConversion;
+ ICS->Standard.First = ICK_Identity;
+ ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
+ ICS->Standard.Third = ICK_Identity;
+ ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
+ ICS->Standard.ToTypePtr = T1.getAsOpaquePtr();
+ ICS->Standard.ReferenceBinding = true;
+ ICS->Standard.DirectBinding = true;
+ ICS->Standard.RRefBinding = false;
+ ICS->Standard.CopyConstructor = 0;
+
+ // Nothing more to do: the inaccessibility/ambiguity check for
+ // derived-to-base conversions is suppressed when we're
+ // computing the implicit conversion sequence (C++
+ // [over.best.ics]p2).
+ return false;
+ } else {
+ // Perform the conversion.
+ // FIXME: Binding to a subobject of the lvalue is going to require more
+ // AST annotation than this.
+ ImpCastExprToType(Init, T1, /*isLvalue=*/true);
+ }
+ }
+
+ // -- has a class type (i.e., T2 is a class type) and can be
+ // implicitly converted to an lvalue of type “cv3 T3,â€
+ // where “cv1 T1†is reference-compatible with “cv3 T3â€
+ // 92) (this conversion is selected by enumerating the
+ // applicable conversion functions (13.3.1.6) and choosing
+ // the best one through overload resolution (13.3)),
+ if (!isRValRef && !SuppressUserConversions && T2->isRecordType()) {
+ // FIXME: Look for conversions in base classes!
+ CXXRecordDecl *T2RecordDecl
+ = dyn_cast<CXXRecordDecl>(T2->getAsRecordType()->getDecl());
+
+ OverloadCandidateSet CandidateSet;
+ OverloadedFunctionDecl *Conversions
+ = T2RecordDecl->getConversionFunctions();
+ for (OverloadedFunctionDecl::function_iterator Func
+ = Conversions->function_begin();
+ Func != Conversions->function_end(); ++Func) {
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+
+ // If the conversion function doesn't return a reference type,
+ // it can't be considered for this conversion.
+ if (Conv->getConversionType()->isLValueReferenceType() &&
+ (AllowExplicit || !Conv->isExplicit()))
+ AddConversionCandidate(Conv, Init, DeclType, CandidateSet);
+ }
+
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(CandidateSet, Best)) {
+ case OR_Success:
+ // This is a direct binding.
+ BindsDirectly = true;
+
+ if (ICS) {
+ // C++ [over.ics.ref]p1:
+ //
+ // [...] If the parameter binds directly to the result of
+ // applying a conversion function to the argument
+ // expression, the implicit conversion sequence is a
+ // user-defined conversion sequence (13.3.3.1.2), with the
+ // second standard conversion sequence either an identity
+ // conversion or, if the conversion function returns an
+ // entity of a type that is a derived class of the parameter
+ // type, a derived-to-base Conversion.
+ ICS->ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
+ ICS->UserDefined.Before = Best->Conversions[0].Standard;
+ ICS->UserDefined.After = Best->FinalConversion;
+ ICS->UserDefined.ConversionFunction = Best->Function;
+ assert(ICS->UserDefined.After.ReferenceBinding &&
+ ICS->UserDefined.After.DirectBinding &&
+ "Expected a direct reference binding!");
+ return false;
+ } else {
+ // Perform the conversion.
+ // FIXME: Binding to a subobject of the lvalue is going to require more
+ // AST annotation than this.
+ ImpCastExprToType(Init, T1, /*isLvalue=*/true);
+ }
+ break;
+
+ case OR_Ambiguous:
+ assert(false && "Ambiguous reference binding conversions not implemented.");
+ return true;
+
+ case OR_No_Viable_Function:
+ case OR_Deleted:
+ // There was no suitable conversion, or we found a deleted
+ // conversion; continue with other checks.
+ break;
+ }
+ }
+
+ if (BindsDirectly) {
+ // C++ [dcl.init.ref]p4:
+ // [...] In all cases where the reference-related or
+ // reference-compatible relationship of two types is used to
+ // establish the validity of a reference binding, and T1 is a
+ // base class of T2, a program that necessitates such a binding
+ // is ill-formed if T1 is an inaccessible (clause 11) or
+ // ambiguous (10.2) base class of T2.
+ //
+ // Note that we only check this condition when we're allowed to
+ // complain about errors, because we should not be checking for
+ // ambiguity (or inaccessibility) unless the reference binding
+ // actually happens.
+ if (DerivedToBase)
+ return CheckDerivedToBaseConversion(T2, T1,
+ Init->getSourceRange().getBegin(),
+ Init->getSourceRange());
+ else
+ return false;
+ }
+
+ // -- Otherwise, the reference shall be to a non-volatile const
+ // type (i.e., cv1 shall be const), or the reference shall be an
+ // rvalue reference and the initializer expression shall be an rvalue.
+ if (!isRValRef && T1.getCVRQualifiers() != QualType::Const) {
+ if (!ICS)
+ Diag(Init->getSourceRange().getBegin(),
+ diag::err_not_reference_to_const_init)
+ << T1 << (InitLvalue != Expr::LV_Valid? "temporary" : "value")
+ << T2 << Init->getSourceRange();
+ return true;
+ }
+
+ // -- If the initializer expression is an rvalue, with T2 a
+ // class type, and “cv1 T1†is reference-compatible with
+ // “cv2 T2,†the reference is bound in one of the
+ // following ways (the choice is implementation-defined):
+ //
+ // -- The reference is bound to the object represented by
+ // the rvalue (see 3.10) or to a sub-object within that
+ // object.
+ //
+ // -- A temporary of type “cv1 T2†[sic] is created, and
+ // a constructor is called to copy the entire rvalue
+ // object into the temporary. The reference is bound to
+ // the temporary or to a sub-object within the
+ // temporary.
+ //
+ // The constructor that would be used to make the copy
+ // shall be callable whether or not the copy is actually
+ // done.
+ //
+ // Note that C++0x [dcl.init.ref]p5 takes away this implementation
+ // freedom, so we will always take the first option and never build
+ // a temporary in this case. FIXME: We will, however, have to check
+ // for the presence of a copy constructor in C++98/03 mode.
+ if (InitLvalue != Expr::LV_Valid && T2->isRecordType() &&
+ RefRelationship >= Ref_Compatible_With_Added_Qualification) {
+ if (ICS) {
+ ICS->ConversionKind = ImplicitConversionSequence::StandardConversion;
+ ICS->Standard.First = ICK_Identity;
+ ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
+ ICS->Standard.Third = ICK_Identity;
+ ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
+ ICS->Standard.ToTypePtr = T1.getAsOpaquePtr();
+ ICS->Standard.ReferenceBinding = true;
+ ICS->Standard.DirectBinding = false;
+ ICS->Standard.RRefBinding = isRValRef;
+ ICS->Standard.CopyConstructor = 0;
+ } else {
+ // FIXME: Binding to a subobject of the rvalue is going to require more
+ // AST annotation than this.
+ ImpCastExprToType(Init, T1, /*isLvalue=*/false);
+ }
+ return false;
+ }
+
+ // -- Otherwise, a temporary of type “cv1 T1†is created and
+ // initialized from the initializer expression using the
+ // rules for a non-reference copy initialization (8.5). The
+ // reference is then bound to the temporary. If T1 is
+ // reference-related to T2, cv1 must be the same
+ // cv-qualification as, or greater cv-qualification than,
+ // cv2; otherwise, the program is ill-formed.
+ if (RefRelationship == Ref_Related) {
+ // If cv1 == cv2 or cv1 is a greater cv-qualified than cv2, then
+ // we would be reference-compatible or reference-compatible with
+ // added qualification. But that wasn't the case, so the reference
+ // initialization fails.
+ if (!ICS)
+ Diag(Init->getSourceRange().getBegin(),
+ diag::err_reference_init_drops_quals)
+ << T1 << (InitLvalue != Expr::LV_Valid? "temporary" : "value")
+ << T2 << Init->getSourceRange();
+ return true;
+ }
+
+ // If at least one of the types is a class type, the types are not
+ // related, and we aren't allowed any user conversions, the
+ // reference binding fails. This case is important for breaking
+ // recursion, since TryImplicitConversion below will attempt to
+ // create a temporary through the use of a copy constructor.
+ if (SuppressUserConversions && RefRelationship == Ref_Incompatible &&
+ (T1->isRecordType() || T2->isRecordType())) {
+ if (!ICS)
+ Diag(Init->getSourceRange().getBegin(),
+ diag::err_typecheck_convert_incompatible)
+ << DeclType << Init->getType() << "initializing" << Init->getSourceRange();
+ return true;
+ }
+
+ // Actually try to convert the initializer to T1.
+ if (ICS) {
+ // C++ [over.ics.ref]p2:
+ //
+ // When a parameter of reference type is not bound directly to
+ // an argument expression, the conversion sequence is the one
+ // required to convert the argument expression to the
+ // underlying type of the reference according to
+ // 13.3.3.1. Conceptually, this conversion sequence corresponds
+ // to copy-initializing a temporary of the underlying type with
+ // the argument expression. Any difference in top-level
+ // cv-qualification is subsumed by the initialization itself
+ // and does not constitute a conversion.
+ *ICS = TryImplicitConversion(Init, T1, SuppressUserConversions);
+ // Of course, that's still a reference binding.
+ if (ICS->ConversionKind == ImplicitConversionSequence::StandardConversion) {
+ ICS->Standard.ReferenceBinding = true;
+ ICS->Standard.RRefBinding = isRValRef;
+ } else if(ICS->ConversionKind ==
+ ImplicitConversionSequence::UserDefinedConversion) {
+ ICS->UserDefined.After.ReferenceBinding = true;
+ ICS->UserDefined.After.RRefBinding = isRValRef;
+ }
+ return ICS->ConversionKind == ImplicitConversionSequence::BadConversion;
+ } else {
+ return PerformImplicitConversion(Init, T1, "initializing");
+ }
+}
+
+/// CheckOverloadedOperatorDeclaration - Check whether the declaration
+/// of this overloaded operator is well-formed. If so, returns false;
+/// otherwise, emits appropriate diagnostics and returns true.
+bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
+ assert(FnDecl && FnDecl->isOverloadedOperator() &&
+ "Expected an overloaded operator declaration");
+
+ OverloadedOperatorKind Op = FnDecl->getOverloadedOperator();
+
+ // C++ [over.oper]p5:
+ // The allocation and deallocation functions, operator new,
+ // operator new[], operator delete and operator delete[], are
+ // described completely in 3.7.3. The attributes and restrictions
+ // found in the rest of this subclause do not apply to them unless
+ // explicitly stated in 3.7.3.
+ // FIXME: Write a separate routine for checking this. For now, just allow it.
+ if (Op == OO_New || Op == OO_Array_New ||
+ Op == OO_Delete || Op == OO_Array_Delete)
+ return false;
+
+ // C++ [over.oper]p6:
+ // An operator function shall either be a non-static member
+ // function or be a non-member function and have at least one
+ // parameter whose type is a class, a reference to a class, an
+ // enumeration, or a reference to an enumeration.
+ if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(FnDecl)) {
+ if (MethodDecl->isStatic())
+ return Diag(FnDecl->getLocation(),
+ diag::err_operator_overload_static) << FnDecl->getDeclName();
+ } else {
+ bool ClassOrEnumParam = false;
+ for (FunctionDecl::param_iterator Param = FnDecl->param_begin(),
+ ParamEnd = FnDecl->param_end();
+ Param != ParamEnd; ++Param) {
+ QualType ParamType = (*Param)->getType().getNonReferenceType();
+ if (ParamType->isRecordType() || ParamType->isEnumeralType()) {
+ ClassOrEnumParam = true;
+ break;
+ }
+ }
+
+ if (!ClassOrEnumParam)
+ return Diag(FnDecl->getLocation(),
+ diag::err_operator_overload_needs_class_or_enum)
+ << FnDecl->getDeclName();
+ }
+
+ // C++ [over.oper]p8:
+ // An operator function cannot have default arguments (8.3.6),
+ // except where explicitly stated below.
+ //
+ // Only the function-call operator allows default arguments
+ // (C++ [over.call]p1).
+ if (Op != OO_Call) {
+ for (FunctionDecl::param_iterator Param = FnDecl->param_begin();
+ Param != FnDecl->param_end(); ++Param) {
+ if ((*Param)->hasUnparsedDefaultArg())
+ return Diag((*Param)->getLocation(),
+ diag::err_operator_overload_default_arg)
+ << FnDecl->getDeclName();
+ else if (Expr *DefArg = (*Param)->getDefaultArg())
+ return Diag((*Param)->getLocation(),
+ diag::err_operator_overload_default_arg)
+ << FnDecl->getDeclName() << DefArg->getSourceRange();
+ }
+ }
+
+ static const bool OperatorUses[NUM_OVERLOADED_OPERATORS][3] = {
+ { false, false, false }
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ , { Unary, Binary, MemberOnly }
+#include "clang/Basic/OperatorKinds.def"
+ };
+
+ bool CanBeUnaryOperator = OperatorUses[Op][0];
+ bool CanBeBinaryOperator = OperatorUses[Op][1];
+ bool MustBeMemberOperator = OperatorUses[Op][2];
+
+ // C++ [over.oper]p8:
+ // [...] Operator functions cannot have more or fewer parameters
+ // than the number required for the corresponding operator, as
+ // described in the rest of this subclause.
+ unsigned NumParams = FnDecl->getNumParams()
+ + (isa<CXXMethodDecl>(FnDecl)? 1 : 0);
+ if (Op != OO_Call &&
+ ((NumParams == 1 && !CanBeUnaryOperator) ||
+ (NumParams == 2 && !CanBeBinaryOperator) ||
+ (NumParams < 1) || (NumParams > 2))) {
+ // We have the wrong number of parameters.
+ unsigned ErrorKind;
+ if (CanBeUnaryOperator && CanBeBinaryOperator) {
+ ErrorKind = 2; // 2 -> unary or binary.
+ } else if (CanBeUnaryOperator) {
+ ErrorKind = 0; // 0 -> unary
+ } else {
+ assert(CanBeBinaryOperator &&
+ "All non-call overloaded operators are unary or binary!");
+ ErrorKind = 1; // 1 -> binary
+ }
+
+ return Diag(FnDecl->getLocation(), diag::err_operator_overload_must_be)
+ << FnDecl->getDeclName() << NumParams << ErrorKind;
+ }
+
+ // Overloaded operators other than operator() cannot be variadic.
+ if (Op != OO_Call &&
+ FnDecl->getType()->getAsFunctionProtoType()->isVariadic()) {
+ return Diag(FnDecl->getLocation(), diag::err_operator_overload_variadic)
+ << FnDecl->getDeclName();
+ }
+
+ // Some operators must be non-static member functions.
+ if (MustBeMemberOperator && !isa<CXXMethodDecl>(FnDecl)) {
+ return Diag(FnDecl->getLocation(),
+ diag::err_operator_overload_must_be_member)
+ << FnDecl->getDeclName();
+ }
+
+ // C++ [over.inc]p1:
+ // The user-defined function called operator++ implements the
+ // prefix and postfix ++ operator. If this function is a member
+ // function with no parameters, or a non-member function with one
+ // parameter of class or enumeration type, it defines the prefix
+ // increment operator ++ for objects of that type. If the function
+ // is a member function with one parameter (which shall be of type
+ // int) or a non-member function with two parameters (the second
+ // of which shall be of type int), it defines the postfix
+ // increment operator ++ for objects of that type.
+ if ((Op == OO_PlusPlus || Op == OO_MinusMinus) && NumParams == 2) {
+ ParmVarDecl *LastParam = FnDecl->getParamDecl(FnDecl->getNumParams() - 1);
+ bool ParamIsInt = false;
+ if (const BuiltinType *BT = LastParam->getType()->getAsBuiltinType())
+ ParamIsInt = BT->getKind() == BuiltinType::Int;
+
+ if (!ParamIsInt)
+ return Diag(LastParam->getLocation(),
+ diag::err_operator_overload_post_incdec_must_be_int)
+ << LastParam->getType() << (Op == OO_MinusMinus);
+ }
+
+ // Notify the class if it got an assignment operator.
+ if (Op == OO_Equal) {
+ // Would have returned earlier otherwise.
+ assert(isa<CXXMethodDecl>(FnDecl) &&
+ "Overloaded = not member, but not filtered.");
+ CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
+ Method->getParent()->addedAssignmentOperator(Context, Method);
+ }
+
+ return false;
+}
+
+/// ActOnStartLinkageSpecification - Parsed the beginning of a C++
+/// linkage specification, including the language and (if present)
+/// the '{'. ExternLoc is the location of the 'extern', LangLoc is
+/// the location of the language string literal, which is provided
+/// by Lang/StrSize. LBraceLoc, if valid, provides the location of
+/// the '{' brace. Otherwise, this linkage specification does not
+/// have any braces.
+Sema::DeclPtrTy Sema::ActOnStartLinkageSpecification(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation LangLoc,
+ const char *Lang,
+ unsigned StrSize,
+ SourceLocation LBraceLoc) {
+ LinkageSpecDecl::LanguageIDs Language;
+ if (strncmp(Lang, "\"C\"", StrSize) == 0)
+ Language = LinkageSpecDecl::lang_c;
+ else if (strncmp(Lang, "\"C++\"", StrSize) == 0)
+ Language = LinkageSpecDecl::lang_cxx;
+ else {
+ Diag(LangLoc, diag::err_bad_language);
+ return DeclPtrTy();
+ }
+
+ // FIXME: Add all the various semantics of linkage specifications
+
+ LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext,
+ LangLoc, Language,
+ LBraceLoc.isValid());
+ CurContext->addDecl(Context, D);
+ PushDeclContext(S, D);
+ return DeclPtrTy::make(D);
+}
+
+/// ActOnFinishLinkageSpecification - Completely the definition of
+/// the C++ linkage specification LinkageSpec. If RBraceLoc is
+/// valid, it's the position of the closing '}' brace in a linkage
+/// specification that uses braces.
+Sema::DeclPtrTy Sema::ActOnFinishLinkageSpecification(Scope *S,
+ DeclPtrTy LinkageSpec,
+ SourceLocation RBraceLoc) {
+ if (LinkageSpec)
+ PopDeclContext();
+ return LinkageSpec;
+}
+
+/// \brief Perform semantic analysis for the variable declaration that
+/// occurs within a C++ catch clause, returning the newly-created
+/// variable.
+VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
+ IdentifierInfo *Name,
+ SourceLocation Loc,
+ SourceRange Range) {
+ bool Invalid = false;
+
+ // Arrays and functions decay.
+ if (ExDeclType->isArrayType())
+ ExDeclType = Context.getArrayDecayedType(ExDeclType);
+ else if (ExDeclType->isFunctionType())
+ ExDeclType = Context.getPointerType(ExDeclType);
+
+ // C++ 15.3p1: The exception-declaration shall not denote an incomplete type.
+ // The exception-declaration shall not denote a pointer or reference to an
+ // incomplete type, other than [cv] void*.
+ // N2844 forbids rvalue references.
+ if(!ExDeclType->isDependentType() && ExDeclType->isRValueReferenceType()) {
+ Diag(Loc, diag::err_catch_rvalue_ref) << Range;
+ Invalid = true;
+ }
+
+ QualType BaseType = ExDeclType;
+ int Mode = 0; // 0 for direct type, 1 for pointer, 2 for reference
+ unsigned DK = diag::err_catch_incomplete;
+ if (const PointerType *Ptr = BaseType->getAsPointerType()) {
+ BaseType = Ptr->getPointeeType();
+ Mode = 1;
+ DK = diag::err_catch_incomplete_ptr;
+ } else if(const ReferenceType *Ref = BaseType->getAsReferenceType()) {
+ // For the purpose of error recovery, we treat rvalue refs like lvalue refs.
+ BaseType = Ref->getPointeeType();
+ Mode = 2;
+ DK = diag::err_catch_incomplete_ref;
+ }
+ if (!Invalid && (Mode == 0 || !BaseType->isVoidType()) &&
+ !BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK))
+ Invalid = true;
+
+ if (!Invalid && !ExDeclType->isDependentType() &&
+ RequireNonAbstractType(Loc, ExDeclType,
+ diag::err_abstract_type_in_decl,
+ AbstractVariableType))
+ Invalid = true;
+
+ // FIXME: Need to test for ability to copy-construct and destroy the
+ // exception variable.
+
+ // FIXME: Need to check for abstract classes.
+
+ VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc,
+ Name, ExDeclType, VarDecl::None,
+ Range.getBegin());
+
+ if (Invalid)
+ ExDecl->setInvalidDecl();
+
+ return ExDecl;
+}
+
+/// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch
+/// handler.
+Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
+ QualType ExDeclType = GetTypeForDeclarator(D, S);
+
+ bool Invalid = D.isInvalidType();
+ IdentifierInfo *II = D.getIdentifier();
+ if (NamedDecl *PrevDecl = LookupName(S, II, LookupOrdinaryName)) {
+ // The scope should be freshly made just for us. There is just no way
+ // it contains any previous declaration.
+ assert(!S->isDeclScope(DeclPtrTy::make(PrevDecl)));
+ if (PrevDecl->isTemplateParameter()) {
+ // Maybe we will complain about the shadowed template parameter.
+ DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
+ }
+ }
+
+ if (D.getCXXScopeSpec().isSet() && !Invalid) {
+ Diag(D.getIdentifierLoc(), diag::err_qualified_catch_declarator)
+ << D.getCXXScopeSpec().getRange();
+ Invalid = true;
+ }
+
+ VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType,
+ D.getIdentifier(),
+ D.getIdentifierLoc(),
+ D.getDeclSpec().getSourceRange());
+
+ if (Invalid)
+ ExDecl->setInvalidDecl();
+
+ // Add the exception declaration into this scope.
+ if (II)
+ PushOnScopeChains(ExDecl, S);
+ else
+ CurContext->addDecl(Context, ExDecl);
+
+ ProcessDeclAttributes(ExDecl, D);
+ return DeclPtrTy::make(ExDecl);
+}
+
+Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
+ ExprArg assertexpr,
+ ExprArg assertmessageexpr) {
+ Expr *AssertExpr = (Expr *)assertexpr.get();
+ StringLiteral *AssertMessage =
+ cast<StringLiteral>((Expr *)assertmessageexpr.get());
+
+ if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent()) {
+ llvm::APSInt Value(32);
+ if (!AssertExpr->isIntegerConstantExpr(Value, Context)) {
+ Diag(AssertLoc, diag::err_static_assert_expression_is_not_constant) <<
+ AssertExpr->getSourceRange();
+ return DeclPtrTy();
+ }
+
+ if (Value == 0) {
+ std::string str(AssertMessage->getStrData(),
+ AssertMessage->getByteLength());
+ Diag(AssertLoc, diag::err_static_assert_failed)
+ << str << AssertExpr->getSourceRange();
+ }
+ }
+
+ assertexpr.release();
+ assertmessageexpr.release();
+ Decl *Decl = StaticAssertDecl::Create(Context, CurContext, AssertLoc,
+ AssertExpr, AssertMessage);
+
+ CurContext->addDecl(Context, Decl);
+ return DeclPtrTy::make(Decl);
+}
+
+bool Sema::ActOnFriendDecl(Scope *S, SourceLocation FriendLoc, DeclPtrTy Dcl) {
+ if (!(S->getFlags() & Scope::ClassScope)) {
+ Diag(FriendLoc, diag::err_friend_decl_outside_class);
+ return true;
+ }
+
+ return false;
+}
+
+void Sema::SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc) {
+ Decl *Dcl = dcl.getAs<Decl>();
+ FunctionDecl *Fn = dyn_cast<FunctionDecl>(Dcl);
+ if (!Fn) {
+ Diag(DelLoc, diag::err_deleted_non_function);
+ return;
+ }
+ if (const FunctionDecl *Prev = Fn->getPreviousDeclaration()) {
+ Diag(DelLoc, diag::err_deleted_decl_not_first);
+ Diag(Prev->getLocation(), diag::note_previous_declaration);
+ // If the declaration wasn't the first, we delete the function anyway for
+ // recovery.
+ }
+ Fn->setDeleted();
+}
+
+static void SearchForReturnInStmt(Sema &Self, Stmt *S) {
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E;
+ ++CI) {
+ Stmt *SubStmt = *CI;
+ if (!SubStmt)
+ continue;
+ if (isa<ReturnStmt>(SubStmt))
+ Self.Diag(SubStmt->getSourceRange().getBegin(),
+ diag::err_return_in_constructor_handler);
+ if (!isa<Expr>(SubStmt))
+ SearchForReturnInStmt(Self, SubStmt);
+ }
+}
+
+void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) {
+ for (unsigned I = 0, E = TryBlock->getNumHandlers(); I != E; ++I) {
+ CXXCatchStmt *Handler = TryBlock->getHandler(I);
+ SearchForReturnInStmt(*this, Handler);
+ }
+}
+
+bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old) {
+ QualType NewTy = New->getType()->getAsFunctionType()->getResultType();
+ QualType OldTy = Old->getType()->getAsFunctionType()->getResultType();
+
+ QualType CNewTy = Context.getCanonicalType(NewTy);
+ QualType COldTy = Context.getCanonicalType(OldTy);
+
+ if (CNewTy == COldTy &&
+ CNewTy.getCVRQualifiers() == COldTy.getCVRQualifiers())
+ return false;
+
+ // Check if the return types are covariant
+ QualType NewClassTy, OldClassTy;
+
+ /// Both types must be pointers or references to classes.
+ if (PointerType *NewPT = dyn_cast<PointerType>(NewTy)) {
+ if (PointerType *OldPT = dyn_cast<PointerType>(OldTy)) {
+ NewClassTy = NewPT->getPointeeType();
+ OldClassTy = OldPT->getPointeeType();
+ }
+ } else if (ReferenceType *NewRT = dyn_cast<ReferenceType>(NewTy)) {
+ if (ReferenceType *OldRT = dyn_cast<ReferenceType>(OldTy)) {
+ NewClassTy = NewRT->getPointeeType();
+ OldClassTy = OldRT->getPointeeType();
+ }
+ }
+
+ // The return types aren't either both pointers or references to a class type.
+ if (NewClassTy.isNull()) {
+ Diag(New->getLocation(),
+ diag::err_different_return_type_for_overriding_virtual_function)
+ << New->getDeclName() << NewTy << OldTy;
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+
+ return true;
+ }
+
+ if (NewClassTy.getUnqualifiedType() != OldClassTy.getUnqualifiedType()) {
+ // Check if the new class derives from the old class.
+ if (!IsDerivedFrom(NewClassTy, OldClassTy)) {
+ Diag(New->getLocation(),
+ diag::err_covariant_return_not_derived)
+ << New->getDeclName() << NewTy << OldTy;
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ return true;
+ }
+
+ // Check if we the conversion from derived to base is valid.
+ if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy,
+ diag::err_covariant_return_inaccessible_base,
+ diag::err_covariant_return_ambiguous_derived_to_base_conv,
+ // FIXME: Should this point to the return type?
+ New->getLocation(), SourceRange(), New->getDeclName())) {
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ return true;
+ }
+ }
+
+ // The qualifiers of the return types must be the same.
+ if (CNewTy.getCVRQualifiers() != COldTy.getCVRQualifiers()) {
+ Diag(New->getLocation(),
+ diag::err_covariant_return_type_different_qualifications)
+ << New->getDeclName() << NewTy << OldTy;
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ return true;
+ };
+
+
+ // The new class type must have the same or less qualifiers as the old type.
+ if (NewClassTy.isMoreQualifiedThan(OldClassTy)) {
+ Diag(New->getLocation(),
+ diag::err_covariant_return_type_class_type_more_qualified)
+ << New->getDeclName() << NewTy << OldTy;
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ return true;
+ };
+
+ return false;
+}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
new file mode 100644
index 000000000000..8f580341bdc6
--- /dev/null
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -0,0 +1,2166 @@
+//===--- SemaDeclObjC.cpp - Semantic Analysis for ObjC Declarations -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for Objective C declarations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Parse/DeclSpec.h"
+using namespace clang;
+
+bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
+ ObjCMethodDecl *GetterMethod,
+ SourceLocation Loc) {
+ if (GetterMethod &&
+ GetterMethod->getResultType() != property->getType()) {
+ AssignConvertType result = Incompatible;
+ if (Context.isObjCObjectPointerType(property->getType()))
+ result = CheckAssignmentConstraints(GetterMethod->getResultType(), property->getType());
+ if (result != Compatible) {
+ Diag(Loc, diag::warn_accessor_property_type_mismatch)
+ << property->getDeclName()
+ << GetterMethod->getSelector();
+ Diag(GetterMethod->getLocation(), diag::note_declared_at);
+ return true;
+ }
+ }
+ return false;
+}
+
+/// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible
+/// and user declared, in the method definition's AST.
+void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
+ assert(getCurMethodDecl() == 0 && "Method parsing confused");
+ ObjCMethodDecl *MDecl = dyn_cast_or_null<ObjCMethodDecl>(D.getAs<Decl>());
+
+ // If we don't have a valid method decl, simply return.
+ if (!MDecl)
+ return;
+
+ CurFunctionNeedsScopeChecking = false;
+
+ // Allow the rest of sema to find private method decl implementations.
+ if (MDecl->isInstanceMethod())
+ AddInstanceMethodToGlobalPool(MDecl);
+ else
+ AddFactoryMethodToGlobalPool(MDecl);
+
+ // Allow all of Sema to see that we are entering a method definition.
+ PushDeclContext(FnBodyScope, MDecl);
+
+ // Create Decl objects for each parameter, entrring them in the scope for
+ // binding to their use.
+
+ // Insert the invisible arguments, self and _cmd!
+ MDecl->createImplicitParams(Context, MDecl->getClassInterface());
+
+ PushOnScopeChains(MDecl->getSelfDecl(), FnBodyScope);
+ PushOnScopeChains(MDecl->getCmdDecl(), FnBodyScope);
+
+ // Introduce all of the other parameters into this scope.
+ for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(),
+ E = MDecl->param_end(); PI != E; ++PI)
+ if ((*PI)->getIdentifier())
+ PushOnScopeChains(*PI, FnBodyScope);
+}
+
+Sema::DeclPtrTy Sema::
+ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
+ IdentifierInfo *ClassName, SourceLocation ClassLoc,
+ IdentifierInfo *SuperName, SourceLocation SuperLoc,
+ const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs,
+ SourceLocation EndProtoLoc, AttributeList *AttrList) {
+ assert(ClassName && "Missing class identifier");
+
+ // Check for another declaration kind with the same name.
+ NamedDecl *PrevDecl = LookupName(TUScope, ClassName, LookupOrdinaryName);
+ if (PrevDecl && PrevDecl->isTemplateParameter()) {
+ // Maybe we will complain about the shadowed template parameter.
+ DiagnoseTemplateParameterShadow(ClassLoc, PrevDecl);
+ // Just pretend that we didn't see the previous declaration.
+ PrevDecl = 0;
+ }
+
+ if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
+ Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ }
+
+ ObjCInterfaceDecl* IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+ if (IDecl) {
+ // Class already seen. Is it a forward declaration?
+ if (!IDecl->isForwardDecl()) {
+ IDecl->setInvalidDecl();
+ Diag(AtInterfaceLoc, diag::err_duplicate_class_def)<<IDecl->getDeclName();
+ Diag(IDecl->getLocation(), diag::note_previous_definition);
+
+ // Return the previous class interface.
+ // FIXME: don't leak the objects passed in!
+ return DeclPtrTy::make(IDecl);
+ } else {
+ IDecl->setLocation(AtInterfaceLoc);
+ IDecl->setForwardDecl(false);
+ }
+ } else {
+ IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc,
+ ClassName, ClassLoc);
+ if (AttrList)
+ ProcessDeclAttributeList(IDecl, AttrList);
+
+ PushOnScopeChains(IDecl, TUScope);
+ }
+
+ if (SuperName) {
+ // Check if a different kind of symbol declared in this scope.
+ PrevDecl = LookupName(TUScope, SuperName, LookupOrdinaryName);
+
+ ObjCInterfaceDecl *SuperClassDecl =
+ dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+
+ // Diagnose classes that inherit from deprecated classes.
+ if (SuperClassDecl)
+ (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc);
+
+ if (PrevDecl && SuperClassDecl == 0) {
+ // The previous declaration was not a class decl. Check if we have a
+ // typedef. If we do, get the underlying class type.
+ if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(PrevDecl)) {
+ QualType T = TDecl->getUnderlyingType();
+ if (T->isObjCInterfaceType()) {
+ if (NamedDecl *IDecl = T->getAsObjCInterfaceType()->getDecl())
+ SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl);
+ }
+ }
+
+ // This handles the following case:
+ //
+ // typedef int SuperClass;
+ // @interface MyClass : SuperClass {} @end
+ //
+ if (!SuperClassDecl) {
+ Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName;
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ }
+ }
+
+ if (!dyn_cast_or_null<TypedefDecl>(PrevDecl)) {
+ if (!SuperClassDecl)
+ Diag(SuperLoc, diag::err_undef_superclass)
+ << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
+ else if (SuperClassDecl->isForwardDecl())
+ Diag(SuperLoc, diag::err_undef_superclass)
+ << SuperClassDecl->getDeclName() << ClassName
+ << SourceRange(AtInterfaceLoc, ClassLoc);
+ }
+ IDecl->setSuperClass(SuperClassDecl);
+ IDecl->setSuperClassLoc(SuperLoc);
+ IDecl->setLocEnd(SuperLoc);
+ } else { // we have a root class.
+ IDecl->setLocEnd(ClassLoc);
+ }
+
+ /// Check then save referenced protocols.
+ if (NumProtoRefs) {
+ IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
+ Context);
+ IDecl->setLocEnd(EndProtoLoc);
+ }
+
+ CheckObjCDeclScope(IDecl);
+ return DeclPtrTy::make(IDecl);
+}
+
+/// ActOnCompatiblityAlias - this action is called after complete parsing of
+/// @compatibility_alias declaration. It sets up the alias relationships.
+Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
+ IdentifierInfo *AliasName,
+ SourceLocation AliasLocation,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLocation) {
+ // Look for previous declaration of alias name
+ NamedDecl *ADecl = LookupName(TUScope, AliasName, LookupOrdinaryName);
+ if (ADecl) {
+ if (isa<ObjCCompatibleAliasDecl>(ADecl))
+ Diag(AliasLocation, diag::warn_previous_alias_decl);
+ else
+ Diag(AliasLocation, diag::err_conflicting_aliasing_type) << AliasName;
+ Diag(ADecl->getLocation(), diag::note_previous_declaration);
+ return DeclPtrTy();
+ }
+ // Check for class declaration
+ NamedDecl *CDeclU = LookupName(TUScope, ClassName, LookupOrdinaryName);
+ if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(CDeclU)) {
+ QualType T = TDecl->getUnderlyingType();
+ if (T->isObjCInterfaceType()) {
+ if (NamedDecl *IDecl = T->getAsObjCInterfaceType()->getDecl()) {
+ ClassName = IDecl->getIdentifier();
+ CDeclU = LookupName(TUScope, ClassName, LookupOrdinaryName);
+ }
+ }
+ }
+ ObjCInterfaceDecl *CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDeclU);
+ if (CDecl == 0) {
+ Diag(ClassLocation, diag::warn_undef_interface) << ClassName;
+ if (CDeclU)
+ Diag(CDeclU->getLocation(), diag::note_previous_declaration);
+ return DeclPtrTy();
+ }
+
+ // Everything checked out, instantiate a new alias declaration AST.
+ ObjCCompatibleAliasDecl *AliasDecl =
+ ObjCCompatibleAliasDecl::Create(Context, CurContext, AtLoc, AliasName, CDecl);
+
+ if (!CheckObjCDeclScope(AliasDecl))
+ PushOnScopeChains(AliasDecl, TUScope);
+
+ return DeclPtrTy::make(AliasDecl);
+}
+
+void Sema::CheckForwardProtocolDeclarationForCircularDependency(
+ IdentifierInfo *PName,
+ SourceLocation &Ploc, SourceLocation PrevLoc,
+ const ObjCList<ObjCProtocolDecl> &PList)
+{
+ for (ObjCList<ObjCProtocolDecl>::iterator I = PList.begin(),
+ E = PList.end(); I != E; ++I) {
+
+ if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier())) {
+ if (PDecl->getIdentifier() == PName) {
+ Diag(Ploc, diag::err_protocol_has_circular_dependency);
+ Diag(PrevLoc, diag::note_previous_definition);
+ }
+ CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc,
+ PDecl->getLocation(), PDecl->getReferencedProtocols());
+ }
+ }
+}
+
+Sema::DeclPtrTy
+Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
+ IdentifierInfo *ProtocolName,
+ SourceLocation ProtocolLoc,
+ const DeclPtrTy *ProtoRefs,
+ unsigned NumProtoRefs,
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList) {
+ // FIXME: Deal with AttrList.
+ assert(ProtocolName && "Missing protocol identifier");
+ ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName);
+ if (PDecl) {
+ // Protocol already seen. Better be a forward protocol declaration
+ if (!PDecl->isForwardDecl()) {
+ Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName;
+ Diag(PDecl->getLocation(), diag::note_previous_definition);
+ // Just return the protocol we already had.
+ // FIXME: don't leak the objects passed in!
+ return DeclPtrTy::make(PDecl);
+ }
+ ObjCList<ObjCProtocolDecl> PList;
+ PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context);
+ CheckForwardProtocolDeclarationForCircularDependency(
+ ProtocolName, ProtocolLoc, PDecl->getLocation(), PList);
+ PList.Destroy(Context);
+
+ // Make sure the cached decl gets a valid start location.
+ PDecl->setLocation(AtProtoInterfaceLoc);
+ PDecl->setForwardDecl(false);
+ } else {
+ PDecl = ObjCProtocolDecl::Create(Context, CurContext,
+ AtProtoInterfaceLoc,ProtocolName);
+ PushOnScopeChains(PDecl, TUScope);
+ PDecl->setForwardDecl(false);
+ }
+ if (AttrList)
+ ProcessDeclAttributeList(PDecl, AttrList);
+ if (NumProtoRefs) {
+ /// Check then save referenced protocols.
+ PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context);
+ PDecl->setLocEnd(EndProtoLoc);
+ }
+
+ CheckObjCDeclScope(PDecl);
+ return DeclPtrTy::make(PDecl);
+}
+
+/// FindProtocolDeclaration - This routine looks up protocols and
+/// issues an error if they are not declared. It returns list of
+/// protocol declarations in its 'Protocols' argument.
+void
+Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
+ const IdentifierLocPair *ProtocolId,
+ unsigned NumProtocols,
+ llvm::SmallVectorImpl<DeclPtrTy> &Protocols) {
+ for (unsigned i = 0; i != NumProtocols; ++i) {
+ ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first);
+ if (!PDecl) {
+ Diag(ProtocolId[i].second, diag::err_undeclared_protocol)
+ << ProtocolId[i].first;
+ continue;
+ }
+
+ (void)DiagnoseUseOfDecl(PDecl, ProtocolId[i].second);
+
+ // If this is a forward declaration and we are supposed to warn in this
+ // case, do it.
+ if (WarnOnDeclarations && PDecl->isForwardDecl())
+ Diag(ProtocolId[i].second, diag::warn_undef_protocolref)
+ << ProtocolId[i].first;
+ Protocols.push_back(DeclPtrTy::make(PDecl));
+ }
+}
+
+/// DiagnosePropertyMismatch - Compares two properties for their
+/// attributes and types and warns on a variety of inconsistencies.
+///
+void
+Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
+ ObjCPropertyDecl *SuperProperty,
+ const IdentifierInfo *inheritedName) {
+ ObjCPropertyDecl::PropertyAttributeKind CAttr =
+ Property->getPropertyAttributes();
+ ObjCPropertyDecl::PropertyAttributeKind SAttr =
+ SuperProperty->getPropertyAttributes();
+ if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly)
+ && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite))
+ Diag(Property->getLocation(), diag::warn_readonly_property)
+ << Property->getDeclName() << inheritedName;
+ if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy)
+ != (SAttr & ObjCPropertyDecl::OBJC_PR_copy))
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "copy" << inheritedName;
+ else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain)
+ != (SAttr & ObjCPropertyDecl::OBJC_PR_retain))
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "retain" << inheritedName;
+
+ if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)
+ != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic))
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "atomic" << inheritedName;
+ if (Property->getSetterName() != SuperProperty->getSetterName())
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "setter" << inheritedName;
+ if (Property->getGetterName() != SuperProperty->getGetterName())
+ Diag(Property->getLocation(), diag::warn_property_attribute)
+ << Property->getDeclName() << "getter" << inheritedName;
+
+ QualType LHSType =
+ Context.getCanonicalType(SuperProperty->getType());
+ QualType RHSType =
+ Context.getCanonicalType(Property->getType());
+
+ if (!Context.typesAreCompatible(LHSType, RHSType)) {
+ // FIXME: Incorporate this test with typesAreCompatible.
+ if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType())
+ if (ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false))
+ return;
+ Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
+ << Property->getType() << SuperProperty->getType() << inheritedName;
+ }
+}
+
+/// ComparePropertiesInBaseAndSuper - This routine compares property
+/// declarations in base and its super class, if any, and issues
+/// diagnostics in a variety of inconsistant situations.
+///
+void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) {
+ ObjCInterfaceDecl *SDecl = IDecl->getSuperClass();
+ if (!SDecl)
+ return;
+ // FIXME: O(N^2)
+ for (ObjCInterfaceDecl::prop_iterator S = SDecl->prop_begin(Context),
+ E = SDecl->prop_end(Context); S != E; ++S) {
+ ObjCPropertyDecl *SuperPDecl = (*S);
+ // Does property in super class has declaration in current class?
+ for (ObjCInterfaceDecl::prop_iterator I = IDecl->prop_begin(Context),
+ E = IDecl->prop_end(Context); I != E; ++I) {
+ ObjCPropertyDecl *PDecl = (*I);
+ if (SuperPDecl->getIdentifier() == PDecl->getIdentifier())
+ DiagnosePropertyMismatch(PDecl, SuperPDecl,
+ SDecl->getIdentifier());
+ }
+ }
+}
+
+/// MergeOneProtocolPropertiesIntoClass - This routine goes thru the list
+/// of properties declared in a protocol and adds them to the list
+/// of properties for current class/category if it is not there already.
+void
+Sema::MergeOneProtocolPropertiesIntoClass(Decl *CDecl,
+ ObjCProtocolDecl *PDecl) {
+ ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
+ if (!IDecl) {
+ // Category
+ ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
+ assert (CatDecl && "MergeOneProtocolPropertiesIntoClass");
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(Context),
+ E = PDecl->prop_end(Context); P != E; ++P) {
+ ObjCPropertyDecl *Pr = (*P);
+ ObjCCategoryDecl::prop_iterator CP, CE;
+ // Is this property already in category's list of properties?
+ for (CP = CatDecl->prop_begin(Context), CE = CatDecl->prop_end(Context);
+ CP != CE; ++CP)
+ if ((*CP)->getIdentifier() == Pr->getIdentifier())
+ break;
+ if (CP != CE)
+ // Property protocol already exist in class. Diagnose any mismatch.
+ DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
+ }
+ return;
+ }
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(Context),
+ E = PDecl->prop_end(Context); P != E; ++P) {
+ ObjCPropertyDecl *Pr = (*P);
+ ObjCInterfaceDecl::prop_iterator CP, CE;
+ // Is this property already in class's list of properties?
+ for (CP = IDecl->prop_begin(Context), CE = IDecl->prop_end(Context);
+ CP != CE; ++CP)
+ if ((*CP)->getIdentifier() == Pr->getIdentifier())
+ break;
+ if (CP != CE)
+ // Property protocol already exist in class. Diagnose any mismatch.
+ DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
+ }
+}
+
+/// MergeProtocolPropertiesIntoClass - This routine merges properties
+/// declared in 'MergeItsProtocols' objects (which can be a class or an
+/// inherited protocol into the list of properties for class/category 'CDecl'
+///
+void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl,
+ DeclPtrTy MergeItsProtocols) {
+ Decl *ClassDecl = MergeItsProtocols.getAs<Decl>();
+ ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
+
+ if (!IDecl) {
+ // Category
+ ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
+ assert (CatDecl && "MergeProtocolPropertiesIntoClass");
+ if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
+ for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(),
+ E = MDecl->protocol_end(); P != E; ++P)
+ // Merge properties of category (*P) into IDECL's
+ MergeOneProtocolPropertiesIntoClass(CatDecl, *P);
+
+ // Go thru the list of protocols for this category and recursively merge
+ // their properties into this class as well.
+ for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(),
+ E = CatDecl->protocol_end(); P != E; ++P)
+ MergeProtocolPropertiesIntoClass(CatDecl, DeclPtrTy::make(*P));
+ } else {
+ ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
+ for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(),
+ E = MD->protocol_end(); P != E; ++P)
+ MergeOneProtocolPropertiesIntoClass(CatDecl, *P);
+ }
+ return;
+ }
+
+ if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
+ for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(),
+ E = MDecl->protocol_end(); P != E; ++P)
+ // Merge properties of class (*P) into IDECL's
+ MergeOneProtocolPropertiesIntoClass(IDecl, *P);
+
+ // Go thru the list of protocols for this class and recursively merge
+ // their properties into this class as well.
+ for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(),
+ E = IDecl->protocol_end(); P != E; ++P)
+ MergeProtocolPropertiesIntoClass(IDecl, DeclPtrTy::make(*P));
+ } else {
+ ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
+ for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(),
+ E = MD->protocol_end(); P != E; ++P)
+ MergeOneProtocolPropertiesIntoClass(IDecl, *P);
+ }
+}
+
+/// DiagnoseClassExtensionDupMethods - Check for duplicate declaration of
+/// a class method in its extension.
+///
+void Sema::DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
+ ObjCInterfaceDecl *ID) {
+ if (!ID)
+ return; // Possibly due to previous error
+
+ llvm::DenseMap<Selector, const ObjCMethodDecl*> MethodMap;
+ for (ObjCInterfaceDecl::method_iterator i = ID->meth_begin(Context),
+ e = ID->meth_end(Context); i != e; ++i) {
+ ObjCMethodDecl *MD = *i;
+ MethodMap[MD->getSelector()] = MD;
+ }
+
+ if (MethodMap.empty())
+ return;
+ for (ObjCCategoryDecl::method_iterator i = CAT->meth_begin(Context),
+ e = CAT->meth_end(Context); i != e; ++i) {
+ ObjCMethodDecl *Method = *i;
+ const ObjCMethodDecl *&PrevMethod = MethodMap[Method->getSelector()];
+ if (PrevMethod && !MatchTwoMethodDeclarations(Method, PrevMethod)) {
+ Diag(Method->getLocation(), diag::err_duplicate_method_decl)
+ << Method->getDeclName();
+ Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
+ }
+ }
+}
+
+/// ActOnForwardProtocolDeclaration - Handle @protocol foo;
+Action::DeclPtrTy
+Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
+ const IdentifierLocPair *IdentList,
+ unsigned NumElts,
+ AttributeList *attrList) {
+ llvm::SmallVector<ObjCProtocolDecl*, 32> Protocols;
+
+ for (unsigned i = 0; i != NumElts; ++i) {
+ IdentifierInfo *Ident = IdentList[i].first;
+ ObjCProtocolDecl *PDecl = LookupProtocol(Ident);
+ if (PDecl == 0) { // Not already seen?
+ PDecl = ObjCProtocolDecl::Create(Context, CurContext,
+ IdentList[i].second, Ident);
+ PushOnScopeChains(PDecl, TUScope);
+ }
+ if (attrList)
+ ProcessDeclAttributeList(PDecl, attrList);
+ Protocols.push_back(PDecl);
+ }
+
+ ObjCForwardProtocolDecl *PDecl =
+ ObjCForwardProtocolDecl::Create(Context, CurContext, AtProtocolLoc,
+ &Protocols[0], Protocols.size());
+ CurContext->addDecl(Context, PDecl);
+ CheckObjCDeclScope(PDecl);
+ return DeclPtrTy::make(PDecl);
+}
+
+Sema::DeclPtrTy Sema::
+ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
+ IdentifierInfo *ClassName, SourceLocation ClassLoc,
+ IdentifierInfo *CategoryName,
+ SourceLocation CategoryLoc,
+ const DeclPtrTy *ProtoRefs,
+ unsigned NumProtoRefs,
+ SourceLocation EndProtoLoc) {
+ ObjCCategoryDecl *CDecl =
+ ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, CategoryName);
+ // FIXME: PushOnScopeChains?
+ CurContext->addDecl(Context, CDecl);
+
+ ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName);
+ /// Check that class of this category is already completely declared.
+ if (!IDecl || IDecl->isForwardDecl()) {
+ CDecl->setInvalidDecl();
+ Diag(ClassLoc, diag::err_undef_interface) << ClassName;
+ return DeclPtrTy::make(CDecl);
+ }
+
+ CDecl->setClassInterface(IDecl);
+
+ // If the interface is deprecated, warn about it.
+ (void)DiagnoseUseOfDecl(IDecl, ClassLoc);
+
+ /// Check for duplicate interface declaration for this category
+ ObjCCategoryDecl *CDeclChain;
+ for (CDeclChain = IDecl->getCategoryList(); CDeclChain;
+ CDeclChain = CDeclChain->getNextClassCategory()) {
+ if (CategoryName && CDeclChain->getIdentifier() == CategoryName) {
+ Diag(CategoryLoc, diag::warn_dup_category_def)
+ << ClassName << CategoryName;
+ Diag(CDeclChain->getLocation(), diag::note_previous_definition);
+ break;
+ }
+ }
+ if (!CDeclChain)
+ CDecl->insertNextClassCategory();
+
+ if (NumProtoRefs) {
+ CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context);
+ CDecl->setLocEnd(EndProtoLoc);
+ }
+
+ CheckObjCDeclScope(CDecl);
+ return DeclPtrTy::make(CDecl);
+}
+
+/// ActOnStartCategoryImplementation - Perform semantic checks on the
+/// category implementation declaration and build an ObjCCategoryImplDecl
+/// object.
+Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation(
+ SourceLocation AtCatImplLoc,
+ IdentifierInfo *ClassName, SourceLocation ClassLoc,
+ IdentifierInfo *CatName, SourceLocation CatLoc) {
+ ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName);
+ ObjCCategoryImplDecl *CDecl =
+ ObjCCategoryImplDecl::Create(Context, CurContext, AtCatImplLoc, CatName,
+ IDecl);
+ /// Check that class of this category is already completely declared.
+ if (!IDecl || IDecl->isForwardDecl())
+ Diag(ClassLoc, diag::err_undef_interface) << ClassName;
+
+ // FIXME: PushOnScopeChains?
+ CurContext->addDecl(Context, CDecl);
+
+ /// TODO: Check that CatName, category name, is not used in another
+ // implementation.
+ ObjCCategoryImpls.push_back(CDecl);
+
+ CheckObjCDeclScope(CDecl);
+ return DeclPtrTy::make(CDecl);
+}
+
+Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
+ SourceLocation AtClassImplLoc,
+ IdentifierInfo *ClassName, SourceLocation ClassLoc,
+ IdentifierInfo *SuperClassname,
+ SourceLocation SuperClassLoc) {
+ ObjCInterfaceDecl* IDecl = 0;
+ // Check for another declaration kind with the same name.
+ NamedDecl *PrevDecl = LookupName(TUScope, ClassName, LookupOrdinaryName);
+ if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
+ Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ } else {
+ // Is there an interface declaration of this class; if not, warn!
+ IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+ if (!IDecl || IDecl->isForwardDecl()) {
+ Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
+ IDecl = 0;
+ }
+ }
+
+ // Check that super class name is valid class name
+ ObjCInterfaceDecl* SDecl = 0;
+ if (SuperClassname) {
+ // Check if a different kind of symbol declared in this scope.
+ PrevDecl = LookupName(TUScope, SuperClassname, LookupOrdinaryName);
+ if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
+ Diag(SuperClassLoc, diag::err_redefinition_different_kind)
+ << SuperClassname;
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ } else {
+ SDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+ if (!SDecl)
+ Diag(SuperClassLoc, diag::err_undef_superclass)
+ << SuperClassname << ClassName;
+ else if (IDecl && IDecl->getSuperClass() != SDecl) {
+ // This implementation and its interface do not have the same
+ // super class.
+ Diag(SuperClassLoc, diag::err_conflicting_super_class)
+ << SDecl->getDeclName();
+ Diag(SDecl->getLocation(), diag::note_previous_definition);
+ }
+ }
+ }
+
+ if (!IDecl) {
+ // Legacy case of @implementation with no corresponding @interface.
+ // Build, chain & install the interface decl into the identifier.
+
+ // FIXME: Do we support attributes on the @implementation? If so we should
+ // copy them over.
+ IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc,
+ ClassName, ClassLoc, false, true);
+ IDecl->setSuperClass(SDecl);
+ IDecl->setLocEnd(ClassLoc);
+
+ PushOnScopeChains(IDecl, TUScope);
+ } else {
+ // Mark the interface as being completed, even if it was just as
+ // @class ....;
+ // declaration; the user cannot reopen it.
+ IDecl->setForwardDecl(false);
+ }
+
+ ObjCImplementationDecl* IMPDecl =
+ ObjCImplementationDecl::Create(Context, CurContext, AtClassImplLoc,
+ IDecl, SDecl);
+
+ if (CheckObjCDeclScope(IMPDecl))
+ return DeclPtrTy::make(IMPDecl);
+
+ // Check that there is no duplicate implementation of this class.
+ if (LookupObjCImplementation(ClassName))
+ // FIXME: Don't leak everything!
+ Diag(ClassLoc, diag::err_dup_implementation_class) << ClassName;
+ else // add it to the list.
+ PushOnScopeChains(IMPDecl, TUScope);
+ return DeclPtrTy::make(IMPDecl);
+}
+
+void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
+ ObjCIvarDecl **ivars, unsigned numIvars,
+ SourceLocation RBrace) {
+ assert(ImpDecl && "missing implementation decl");
+ ObjCInterfaceDecl* IDecl = ImpDecl->getClassInterface();
+ if (!IDecl)
+ return;
+ /// Check case of non-existing @interface decl.
+ /// (legacy objective-c @implementation decl without an @interface decl).
+ /// Add implementations's ivar to the synthesize class's ivar list.
+ if (IDecl->isImplicitInterfaceDecl()) {
+ IDecl->setIVarList(ivars, numIvars, Context);
+ IDecl->setLocEnd(RBrace);
+ return;
+ }
+ // If implementation has empty ivar list, just return.
+ if (numIvars == 0)
+ return;
+
+ assert(ivars && "missing @implementation ivars");
+
+ // Check interface's Ivar list against those in the implementation.
+ // names and types must match.
+ //
+ unsigned j = 0;
+ ObjCInterfaceDecl::ivar_iterator
+ IVI = IDecl->ivar_begin(), IVE = IDecl->ivar_end();
+ for (; numIvars > 0 && IVI != IVE; ++IVI) {
+ ObjCIvarDecl* ImplIvar = ivars[j++];
+ ObjCIvarDecl* ClsIvar = *IVI;
+ assert (ImplIvar && "missing implementation ivar");
+ assert (ClsIvar && "missing class ivar");
+
+ // First, make sure the types match.
+ if (Context.getCanonicalType(ImplIvar->getType()) !=
+ Context.getCanonicalType(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);
+ }
+ }
+ // Make sure the names are identical.
+ if (ImplIvar->getIdentifier() != ClsIvar->getIdentifier()) {
+ Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_name)
+ << ImplIvar->getIdentifier() << ClsIvar->getIdentifier();
+ Diag(ClsIvar->getLocation(), diag::note_previous_definition);
+ }
+ --numIvars;
+ }
+
+ if (numIvars > 0)
+ Diag(ivars[j]->getLocation(), diag::err_inconsistant_ivar_count);
+ else if (IVI != IVE)
+ Diag((*IVI)->getLocation(), diag::err_inconsistant_ivar_count);
+}
+
+void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
+ bool &IncompleteImpl) {
+ if (!IncompleteImpl) {
+ Diag(ImpLoc, diag::warn_incomplete_impl);
+ IncompleteImpl = true;
+ }
+ Diag(ImpLoc, diag::warn_undef_method_impl) << method->getDeclName();
+}
+
+void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
+ ObjCMethodDecl *IntfMethodDecl) {
+ if (!Context.typesAreCompatible(IntfMethodDecl->getResultType(),
+ ImpMethodDecl->getResultType()) &&
+ !QualifiedIdConformsQualifiedId(IntfMethodDecl->getResultType(),
+ ImpMethodDecl->getResultType())) {
+ Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_ret_types)
+ << ImpMethodDecl->getDeclName() << IntfMethodDecl->getResultType()
+ << ImpMethodDecl->getResultType();
+ Diag(IntfMethodDecl->getLocation(), diag::note_previous_definition);
+ }
+
+ for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(),
+ IF = IntfMethodDecl->param_begin(), EM = ImpMethodDecl->param_end();
+ IM != EM; ++IM, ++IF) {
+ if (Context.typesAreCompatible((*IF)->getType(), (*IM)->getType()) ||
+ QualifiedIdConformsQualifiedId((*IF)->getType(), (*IM)->getType()))
+ continue;
+
+ Diag((*IM)->getLocation(), diag::warn_conflicting_param_types)
+ << ImpMethodDecl->getDeclName() << (*IF)->getType()
+ << (*IM)->getType();
+ Diag((*IF)->getLocation(), diag::note_previous_definition);
+ }
+}
+
+/// isPropertyReadonly - Return true if property is readonly, by searching
+/// for the property in the class and in its categories and implementations
+///
+bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl,
+ ObjCInterfaceDecl *IDecl) {
+ // by far the most common case.
+ if (!PDecl->isReadOnly())
+ return false;
+ // Even if property is ready only, if interface has a user defined setter,
+ // it is not considered read only.
+ if (IDecl->getInstanceMethod(Context, PDecl->getSetterName()))
+ return false;
+
+ // Main class has the property as 'readonly'. Must search
+ // through the category list to see if the property's
+ // attribute has been over-ridden to 'readwrite'.
+ for (ObjCCategoryDecl *Category = IDecl->getCategoryList();
+ Category; Category = Category->getNextClassCategory()) {
+ // Even if property is ready only, if a category has a user defined setter,
+ // it is not considered read only.
+ if (Category->getInstanceMethod(Context, PDecl->getSetterName()))
+ return false;
+ ObjCPropertyDecl *P =
+ Category->FindPropertyDeclaration(Context, PDecl->getIdentifier());
+ if (P && !P->isReadOnly())
+ return false;
+ }
+
+ // Also, check for definition of a setter method in the implementation if
+ // all else failed.
+ if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurContext)) {
+ if (ObjCImplementationDecl *IMD =
+ dyn_cast<ObjCImplementationDecl>(OMD->getDeclContext())) {
+ if (IMD->getInstanceMethod(Context, PDecl->getSetterName()))
+ return false;
+ }
+ else if (ObjCCategoryImplDecl *CIMD =
+ dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) {
+ if (CIMD->getInstanceMethod(Context, PDecl->getSetterName()))
+ return false;
+ }
+ }
+ // Lastly, look through the implementation (if one is in scope).
+ if (ObjCImplementationDecl *ImpDecl
+ = LookupObjCImplementation(IDecl->getIdentifier()))
+ if (ImpDecl->getInstanceMethod(Context, PDecl->getSetterName()))
+ return false;
+ // If all fails, look at the super class.
+ if (ObjCInterfaceDecl *SIDecl = IDecl->getSuperClass())
+ return isPropertyReadonly(PDecl, SIDecl);
+ return true;
+}
+
+/// 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
+/// we used an immutable set to keep the table then it wouldn't add significant
+/// memory cost and it would be handy for lookups.
+
+/// CheckProtocolMethodDefs - This routine checks unimplemented methods
+/// Declared in protocol, and those referenced by it.
+void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
+ ObjCProtocolDecl *PDecl,
+ bool& IncompleteImpl,
+ const llvm::DenseSet<Selector> &InsMap,
+ const llvm::DenseSet<Selector> &ClsMap,
+ ObjCInterfaceDecl *IDecl) {
+ ObjCInterfaceDecl *Super = IDecl->getSuperClass();
+ ObjCInterfaceDecl *NSIDecl = 0;
+ if (getLangOptions().NeXTRuntime) {
+ // check to see if class implements forwardInvocation method and objects
+ // of this class are derived from 'NSProxy' so that to forward requests
+ // from one object to another.
+ // Under such conditions, which means that every method possible is
+ // implemented in the class, we should not issue "Method definition not
+ // found" warnings.
+ // FIXME: Use a general GetUnarySelector method for this.
+ IdentifierInfo* II = &Context.Idents.get("forwardInvocation");
+ Selector fISelector = Context.Selectors.getSelector(1, &II);
+ if (InsMap.count(fISelector))
+ // Is IDecl derived from 'NSProxy'? If so, no instance methods
+ // need be implemented in the implementation.
+ NSIDecl = IDecl->lookupInheritedClass(&Context.Idents.get("NSProxy"));
+ }
+
+ // If a method lookup fails locally we still need to look and see if
+ // the method was implemented by a base class or an inherited
+ // protocol. This lookup is slow, but occurs rarely in correct code
+ // and otherwise would terminate in a warning.
+
+ // check unimplemented instance methods.
+ if (!NSIDecl)
+ for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(Context),
+ E = PDecl->instmeth_end(Context); I != E; ++I) {
+ ObjCMethodDecl *method = *I;
+ if (method->getImplementationControl() != ObjCMethodDecl::Optional &&
+ !method->isSynthesized() && !InsMap.count(method->getSelector()) &&
+ (!Super ||
+ !Super->lookupInstanceMethod(Context, method->getSelector()))) {
+ // Ugly, but necessary. Method declared in protcol might have
+ // have been synthesized due to a property declared in the class which
+ // uses the protocol.
+ ObjCMethodDecl *MethodInClass =
+ IDecl->lookupInstanceMethod(Context, method->getSelector());
+ if (!MethodInClass || !MethodInClass->isSynthesized())
+ WarnUndefinedMethod(ImpLoc, method, IncompleteImpl);
+ }
+ }
+ // check unimplemented class methods
+ for (ObjCProtocolDecl::classmeth_iterator
+ I = PDecl->classmeth_begin(Context),
+ E = PDecl->classmeth_end(Context);
+ I != E; ++I) {
+ ObjCMethodDecl *method = *I;
+ if (method->getImplementationControl() != ObjCMethodDecl::Optional &&
+ !ClsMap.count(method->getSelector()) &&
+ (!Super || !Super->lookupClassMethod(Context, method->getSelector())))
+ WarnUndefinedMethod(ImpLoc, method, IncompleteImpl);
+ }
+ // Check on this protocols's referenced protocols, recursively.
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI)
+ CheckProtocolMethodDefs(ImpLoc, *PI, IncompleteImpl, InsMap, ClsMap, IDecl);
+}
+
+/// MatchAllMethodDeclarations - Check methods declaraed in interface or
+/// or protocol against those declared in their implementations.
+///
+void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
+ const llvm::DenseSet<Selector> &ClsMap,
+ llvm::DenseSet<Selector> &InsMapSeen,
+ llvm::DenseSet<Selector> &ClsMapSeen,
+ ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl* CDecl,
+ bool &IncompleteImpl,
+ bool ImmediateClass)
+{
+ // 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(Context),
+ E = CDecl->instmeth_end(Context); I != E; ++I) {
+ if (InsMapSeen.count((*I)->getSelector()))
+ continue;
+ InsMapSeen.insert((*I)->getSelector());
+ if (!(*I)->isSynthesized() &&
+ !InsMap.count((*I)->getSelector())) {
+ if (ImmediateClass)
+ WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl);
+ continue;
+ }
+ else {
+ ObjCMethodDecl *ImpMethodDecl =
+ IMPDecl->getInstanceMethod(Context, (*I)->getSelector());
+ ObjCMethodDecl *IntfMethodDecl =
+ CDecl->getInstanceMethod(Context, (*I)->getSelector());
+ assert(IntfMethodDecl &&
+ "IntfMethodDecl is null in ImplMethodsVsClassMethods");
+ // ImpMethodDecl may be null as in a @dynamic property.
+ if (ImpMethodDecl)
+ WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl);
+ }
+ }
+
+ // Check and see if class methods in class interface have been
+ // implemented in the implementation class. If so, their types match.
+ for (ObjCInterfaceDecl::classmeth_iterator
+ I = CDecl->classmeth_begin(Context),
+ E = CDecl->classmeth_end(Context);
+ I != E; ++I) {
+ if (ClsMapSeen.count((*I)->getSelector()))
+ continue;
+ ClsMapSeen.insert((*I)->getSelector());
+ if (!ClsMap.count((*I)->getSelector())) {
+ if (ImmediateClass)
+ WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl);
+ }
+ else {
+ ObjCMethodDecl *ImpMethodDecl =
+ IMPDecl->getClassMethod(Context, (*I)->getSelector());
+ ObjCMethodDecl *IntfMethodDecl =
+ CDecl->getClassMethod(Context, (*I)->getSelector());
+ WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl);
+ }
+ }
+ if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) {
+ // Check for any implementation of a methods declared in protocol.
+ for (ObjCInterfaceDecl::protocol_iterator PI = I->protocol_begin(),
+ E = I->protocol_end(); PI != E; ++PI)
+ MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
+ IMPDecl,
+ (*PI), IncompleteImpl, false);
+ if (I->getSuperClass())
+ MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
+ IMPDecl,
+ I->getSuperClass(), IncompleteImpl, false);
+ }
+}
+
+void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl* CDecl,
+ bool IncompleteImpl) {
+ llvm::DenseSet<Selector> InsMap;
+ // Check and see if instance methods in class interface have been
+ // implemented in the implementation class.
+ for (ObjCImplementationDecl::instmeth_iterator
+ I = IMPDecl->instmeth_begin(Context),
+ E = IMPDecl->instmeth_end(Context); I != E; ++I)
+ InsMap.insert((*I)->getSelector());
+
+ // Check and see if properties declared in the interface have either 1)
+ // an implementation or 2) there is a @synthesize/@dynamic implementation
+ // of the property in the @implementation.
+ if (isa<ObjCInterfaceDecl>(CDecl))
+ for (ObjCContainerDecl::prop_iterator P = CDecl->prop_begin(Context),
+ E = CDecl->prop_end(Context); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ if (Prop->isInvalidDecl())
+ continue;
+ ObjCPropertyImplDecl *PI = 0;
+ // Is there a matching propery synthesize/dynamic?
+ for (ObjCImplDecl::propimpl_iterator
+ I = IMPDecl->propimpl_begin(Context),
+ EI = IMPDecl->propimpl_end(Context); I != EI; ++I)
+ if ((*I)->getPropertyDecl() == Prop) {
+ PI = (*I);
+ break;
+ }
+ if (PI)
+ continue;
+ if (!InsMap.count(Prop->getGetterName())) {
+ Diag(Prop->getLocation(),
+ diag::warn_setter_getter_impl_required)
+ << Prop->getDeclName() << Prop->getGetterName();
+ Diag(IMPDecl->getLocation(),
+ diag::note_property_impl_required);
+ }
+
+ if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) {
+ Diag(Prop->getLocation(),
+ diag::warn_setter_getter_impl_required)
+ << Prop->getDeclName() << Prop->getSetterName();
+ Diag(IMPDecl->getLocation(),
+ diag::note_property_impl_required);
+ }
+ }
+
+ llvm::DenseSet<Selector> ClsMap;
+ for (ObjCImplementationDecl::classmeth_iterator
+ I = IMPDecl->classmeth_begin(Context),
+ E = IMPDecl->classmeth_end(Context); I != E; ++I)
+ ClsMap.insert((*I)->getSelector());
+
+ // Check for type conflict of methods declared in a class/protocol and
+ // its implementation; if any.
+ llvm::DenseSet<Selector> InsMapSeen, ClsMapSeen;
+ MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
+ IMPDecl, CDecl,
+ IncompleteImpl, true);
+
+ // Check the protocol list for unimplemented methods in the @implementation
+ // class.
+ // Check and see if class methods in class interface have been
+ // implemented in the implementation class.
+
+ if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) {
+ for (ObjCInterfaceDecl::protocol_iterator PI = I->protocol_begin(),
+ E = I->protocol_end(); PI != E; ++PI)
+ CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
+ InsMap, ClsMap, I);
+ // Check class extensions (unnamed categories)
+ for (ObjCCategoryDecl *Categories = I->getCategoryList();
+ Categories; Categories = Categories->getNextClassCategory()) {
+ if (!Categories->getIdentifier()) {
+ ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl);
+ break;
+ }
+ }
+ } else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
+ for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(),
+ E = C->protocol_end(); PI != E; ++PI)
+ CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
+ InsMap, ClsMap, C->getClassInterface());
+ } else
+ assert(false && "invalid ObjCContainerDecl type.");
+}
+
+/// ActOnForwardClassDeclaration -
+Action::DeclPtrTy
+Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
+ IdentifierInfo **IdentList,
+ unsigned NumElts) {
+ llvm::SmallVector<ObjCInterfaceDecl*, 32> Interfaces;
+
+ for (unsigned i = 0; i != NumElts; ++i) {
+ // Check for another declaration kind with the same name.
+ NamedDecl *PrevDecl = LookupName(TUScope, IdentList[i], LookupOrdinaryName);
+ if (PrevDecl && PrevDecl->isTemplateParameter()) {
+ // Maybe we will complain about the shadowed template parameter.
+ DiagnoseTemplateParameterShadow(AtClassLoc, PrevDecl);
+ // Just pretend that we didn't see the previous declaration.
+ PrevDecl = 0;
+ }
+
+ if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
+ // GCC apparently allows the following idiom:
+ //
+ // typedef NSObject < XCElementTogglerP > XCElementToggler;
+ // @class XCElementToggler;
+ //
+ // FIXME: Make an extension?
+ TypedefDecl *TDD = dyn_cast<TypedefDecl>(PrevDecl);
+ if (!TDD || !isa<ObjCInterfaceType>(TDD->getUnderlyingType())) {
+ Diag(AtClassLoc, diag::err_redefinition_different_kind) << IdentList[i];
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ }
+ else if (TDD) {
+ // a forward class declaration matching a typedef name of a class
+ // refers to the underlying class.
+ if (ObjCInterfaceType * OI =
+ dyn_cast<ObjCInterfaceType>(TDD->getUnderlyingType()))
+ PrevDecl = OI->getDecl();
+ }
+ }
+ ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+ if (!IDecl) { // Not already seen? Make a forward decl.
+ IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
+ IdentList[i], SourceLocation(), true);
+ PushOnScopeChains(IDecl, TUScope);
+ }
+
+ Interfaces.push_back(IDecl);
+ }
+
+ ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc,
+ &Interfaces[0],
+ Interfaces.size());
+ CurContext->addDecl(Context, CDecl);
+ CheckObjCDeclScope(CDecl);
+ return DeclPtrTy::make(CDecl);
+}
+
+
+/// MatchTwoMethodDeclarations - Checks that two methods have matching type and
+/// returns true, or false, accordingly.
+/// TODO: Handle protocol list; such as id<p1,p2> in type comparisons
+bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
+ const ObjCMethodDecl *PrevMethod,
+ bool matchBasedOnSizeAndAlignment) {
+ QualType T1 = Context.getCanonicalType(Method->getResultType());
+ QualType T2 = Context.getCanonicalType(PrevMethod->getResultType());
+
+ if (T1 != T2) {
+ // The result types are different.
+ if (!matchBasedOnSizeAndAlignment)
+ return false;
+ // Incomplete types don't have a size and alignment.
+ if (T1->isIncompleteType() || T2->isIncompleteType())
+ return false;
+ // Check is based on size and alignment.
+ if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2))
+ return false;
+ }
+
+ ObjCMethodDecl::param_iterator ParamI = Method->param_begin(),
+ E = Method->param_end();
+ ObjCMethodDecl::param_iterator PrevI = PrevMethod->param_begin();
+
+ for (; ParamI != E; ++ParamI, ++PrevI) {
+ assert(PrevI != PrevMethod->param_end() && "Param mismatch");
+ T1 = Context.getCanonicalType((*ParamI)->getType());
+ T2 = Context.getCanonicalType((*PrevI)->getType());
+ if (T1 != T2) {
+ // The result types are different.
+ if (!matchBasedOnSizeAndAlignment)
+ return false;
+ // Incomplete types don't have a size and alignment.
+ if (T1->isIncompleteType() || T2->isIncompleteType())
+ return false;
+ // Check is based on size and alignment.
+ if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2))
+ return false;
+ }
+ }
+ return true;
+}
+
+/// \brief Read the contents of the instance and factory method pools
+/// for a given selector from external storage.
+///
+/// This routine should only be called once, when neither the instance
+/// nor the factory method pool has an entry for this selector.
+Sema::MethodPool::iterator Sema::ReadMethodPool(Selector Sel,
+ bool isInstance) {
+ assert(ExternalSource && "We need an external AST source");
+ assert(InstanceMethodPool.find(Sel) == InstanceMethodPool.end() &&
+ "Selector data already loaded into the instance method pool");
+ assert(FactoryMethodPool.find(Sel) == FactoryMethodPool.end() &&
+ "Selector data already loaded into the factory method pool");
+
+ // Read the method list from the external source.
+ std::pair<ObjCMethodList, ObjCMethodList> Methods
+ = ExternalSource->ReadMethodPool(Sel);
+
+ if (isInstance) {
+ if (Methods.second.Method)
+ FactoryMethodPool[Sel] = Methods.second;
+ return InstanceMethodPool.insert(std::make_pair(Sel, Methods.first)).first;
+ }
+
+ if (Methods.first.Method)
+ InstanceMethodPool[Sel] = Methods.first;
+
+ return FactoryMethodPool.insert(std::make_pair(Sel, Methods.second)).first;
+}
+
+void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) {
+ llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
+ = InstanceMethodPool.find(Method->getSelector());
+ if (Pos == InstanceMethodPool.end()) {
+ if (ExternalSource && !FactoryMethodPool.count(Method->getSelector()))
+ Pos = ReadMethodPool(Method->getSelector(), /*isInstance=*/true);
+ else
+ Pos = InstanceMethodPool.insert(std::make_pair(Method->getSelector(),
+ ObjCMethodList())).first;
+ }
+
+ ObjCMethodList &Entry = Pos->second;
+ if (Entry.Method == 0) {
+ // Haven't seen a method with this selector name yet - add it.
+ Entry.Method = Method;
+ Entry.Next = 0;
+ return;
+ }
+
+ // We've seen a method with this name, see if we have already seen this type
+ // signature.
+ for (ObjCMethodList *List = &Entry; List; List = List->Next)
+ if (MatchTwoMethodDeclarations(Method, List->Method))
+ return;
+
+ // We have a new signature for an existing method - add it.
+ // This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
+ Entry.Next = new ObjCMethodList(Method, Entry.Next);
+}
+
+// FIXME: Finish implementing -Wno-strict-selector-match.
+ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel,
+ SourceRange R) {
+ llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
+ = InstanceMethodPool.find(Sel);
+ if (Pos == InstanceMethodPool.end()) {
+ if (ExternalSource && !FactoryMethodPool.count(Sel))
+ Pos = ReadMethodPool(Sel, /*isInstance=*/true);
+ else
+ return 0;
+ }
+
+ ObjCMethodList &MethList = Pos->second;
+ bool issueWarning = false;
+
+ if (MethList.Method && MethList.Next) {
+ for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
+ // This checks if the methods differ by size & alignment.
+ if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true))
+ issueWarning = true;
+ }
+ if (issueWarning && (MethList.Method && MethList.Next)) {
+ Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
+ Diag(MethList.Method->getLocStart(), diag::note_using_decl)
+ << MethList.Method->getSourceRange();
+ for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
+ Diag(Next->Method->getLocStart(), diag::note_also_found_decl)
+ << Next->Method->getSourceRange();
+ }
+ return MethList.Method;
+}
+
+void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) {
+ llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
+ = FactoryMethodPool.find(Method->getSelector());
+ if (Pos == FactoryMethodPool.end()) {
+ if (ExternalSource && !InstanceMethodPool.count(Method->getSelector()))
+ Pos = ReadMethodPool(Method->getSelector(), /*isInstance=*/false);
+ else
+ Pos = FactoryMethodPool.insert(std::make_pair(Method->getSelector(),
+ ObjCMethodList())).first;
+ }
+
+ ObjCMethodList &FirstMethod = Pos->second;
+ if (!FirstMethod.Method) {
+ // Haven't seen a method with this selector name yet - add it.
+ FirstMethod.Method = Method;
+ FirstMethod.Next = 0;
+ } else {
+ // We've seen a method with this name, now check the type signature(s).
+ bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method);
+
+ for (ObjCMethodList *Next = FirstMethod.Next; !match && Next;
+ Next = Next->Next)
+ match = MatchTwoMethodDeclarations(Method, Next->Method);
+
+ if (!match) {
+ // We have a new signature for an existing method - add it.
+ // This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
+ struct ObjCMethodList *OMI = new ObjCMethodList(Method, FirstMethod.Next);
+ FirstMethod.Next = OMI;
+ }
+ }
+}
+
+ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel,
+ SourceRange R) {
+ llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
+ = FactoryMethodPool.find(Sel);
+ if (Pos == FactoryMethodPool.end()) {
+ if (ExternalSource && !InstanceMethodPool.count(Sel))
+ Pos = ReadMethodPool(Sel, /*isInstance=*/false);
+ else
+ return 0;
+ }
+
+ ObjCMethodList &MethList = Pos->second;
+ bool issueWarning = false;
+
+ if (MethList.Method && MethList.Next) {
+ for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
+ // This checks if the methods differ by size & alignment.
+ if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true))
+ issueWarning = true;
+ }
+ if (issueWarning && (MethList.Method && MethList.Next)) {
+ Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
+ Diag(MethList.Method->getLocStart(), diag::note_using_decl)
+ << MethList.Method->getSourceRange();
+ for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
+ Diag(Next->Method->getLocStart(), diag::note_also_found_decl)
+ << Next->Method->getSourceRange();
+ }
+ return MethList.Method;
+}
+
+/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods
+/// have the property type and issue diagnostics if they don't.
+/// Also synthesize a getter/setter method if none exist (and update the
+/// appropriate lookup tables. FIXME: Should reconsider if adding synthesized
+/// methods is the "right" thing to do.
+void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
+ ObjCContainerDecl *CD) {
+ ObjCMethodDecl *GetterMethod, *SetterMethod;
+
+ GetterMethod = CD->getInstanceMethod(Context, property->getGetterName());
+ SetterMethod = CD->getInstanceMethod(Context, property->getSetterName());
+ DiagnosePropertyAccessorMismatch(property, GetterMethod,
+ property->getLocation());
+
+ if (SetterMethod) {
+ if (Context.getCanonicalType(SetterMethod->getResultType())
+ != Context.VoidTy)
+ Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
+ if (SetterMethod->param_size() != 1 ||
+ ((*SetterMethod->param_begin())->getType() != property->getType())) {
+ Diag(property->getLocation(),
+ diag::warn_accessor_property_type_mismatch)
+ << property->getDeclName()
+ << SetterMethod->getSelector();
+ Diag(SetterMethod->getLocation(), diag::note_declared_at);
+ }
+ }
+
+ // Synthesize getter/setter methods if none exist.
+ // Find the default getter and if one not found, add one.
+ // FIXME: The synthesized property we set here is misleading. We almost always
+ // synthesize these methods unless the user explicitly provided prototypes
+ // (which is odd, but allowed). Sema should be typechecking that the
+ // declarations jive in that situation (which it is not currently).
+ if (!GetterMethod) {
+ // No instance method of same name as property getter name was found.
+ // Declare a getter method and add it to the list of methods
+ // for this class.
+ GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
+ property->getLocation(), property->getGetterName(),
+ property->getType(), CD, true, false, true,
+ (property->getPropertyImplementation() ==
+ ObjCPropertyDecl::Optional) ?
+ ObjCMethodDecl::Optional :
+ ObjCMethodDecl::Required);
+ CD->addDecl(Context, GetterMethod);
+ } else
+ // A user declared getter will be synthesize when @synthesize of
+ // the property with the same name is seen in the @implementation
+ GetterMethod->setSynthesized(true);
+ property->setGetterMethodDecl(GetterMethod);
+
+ // Skip setter if property is read-only.
+ if (!property->isReadOnly()) {
+ // Find the default setter and if one not found, add one.
+ if (!SetterMethod) {
+ // No instance method of same name as property setter name was found.
+ // Declare a setter method and add it to the list of methods
+ // for this class.
+ SetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
+ property->getLocation(),
+ property->getSetterName(),
+ Context.VoidTy, CD, true, false, true,
+ (property->getPropertyImplementation() ==
+ ObjCPropertyDecl::Optional) ?
+ ObjCMethodDecl::Optional :
+ ObjCMethodDecl::Required);
+ // Invent the arguments for the setter. We don't bother making a
+ // nice name for the argument.
+ ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,
+ property->getLocation(),
+ property->getIdentifier(),
+ property->getType(),
+ VarDecl::None,
+ 0);
+ SetterMethod->setMethodParams(Context, &Argument, 1);
+ CD->addDecl(Context, SetterMethod);
+ } else
+ // A user declared setter will be synthesize when @synthesize of
+ // the property with the same name is seen in the @implementation
+ SetterMethod->setSynthesized(true);
+ property->setSetterMethodDecl(SetterMethod);
+ }
+ // Add any synthesized methods to the global pool. This allows us to
+ // handle the following, which is supported by GCC (and part of the design).
+ //
+ // @interface Foo
+ // @property double bar;
+ // @end
+ //
+ // void thisIsUnfortunate() {
+ // id foo;
+ // double bar = [foo bar];
+ // }
+ //
+ if (GetterMethod)
+ AddInstanceMethodToGlobalPool(GetterMethod);
+ if (SetterMethod)
+ AddInstanceMethodToGlobalPool(SetterMethod);
+}
+
+// Note: For class/category implemenations, allMethods/allProperties is
+// always null.
+void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
+ DeclPtrTy *allMethods, unsigned allNum,
+ DeclPtrTy *allProperties, unsigned pNum,
+ DeclGroupPtrTy *allTUVars, unsigned tuvNum) {
+ Decl *ClassDecl = classDecl.getAs<Decl>();
+
+ // 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)
+ return;
+
+ bool isInterfaceDeclKind =
+ isa<ObjCInterfaceDecl>(ClassDecl) || isa<ObjCCategoryDecl>(ClassDecl)
+ || isa<ObjCProtocolDecl>(ClassDecl);
+ bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl);
+
+ DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
+
+ // FIXME: Remove these and use the ObjCContainerDecl/DeclContext.
+ llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap;
+ llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap;
+
+ for (unsigned i = 0; i < allNum; i++ ) {
+ ObjCMethodDecl *Method =
+ cast_or_null<ObjCMethodDecl>(allMethods[i].getAs<Decl>());
+
+ if (!Method) continue; // Already issued a diagnostic.
+ if (Method->isInstanceMethod()) {
+ /// Check for instance method of the same name with incompatible types
+ const ObjCMethodDecl *&PrevMethod = InsMap[Method->getSelector()];
+ bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod)
+ : false;
+ if ((isInterfaceDeclKind && PrevMethod && !match)
+ || (checkIdenticalMethods && match)) {
+ Diag(Method->getLocation(), diag::err_duplicate_method_decl)
+ << Method->getDeclName();
+ Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
+ } else {
+ DC->addDecl(Context, Method);
+ InsMap[Method->getSelector()] = Method;
+ /// The following allows us to typecheck messages to "id".
+ AddInstanceMethodToGlobalPool(Method);
+ }
+ }
+ else {
+ /// Check for class method of the same name with incompatible types
+ const ObjCMethodDecl *&PrevMethod = ClsMap[Method->getSelector()];
+ bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod)
+ : false;
+ if ((isInterfaceDeclKind && PrevMethod && !match)
+ || (checkIdenticalMethods && match)) {
+ Diag(Method->getLocation(), diag::err_duplicate_method_decl)
+ << Method->getDeclName();
+ Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
+ } else {
+ DC->addDecl(Context, Method);
+ ClsMap[Method->getSelector()] = Method;
+ /// The following allows us to typecheck messages to "Class".
+ AddFactoryMethodToGlobalPool(Method);
+ }
+ }
+ }
+ if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
+ // Compares properties declared in this class to those of its
+ // super class.
+ ComparePropertiesInBaseAndSuper(I);
+ MergeProtocolPropertiesIntoClass(I, DeclPtrTy::make(I));
+ } else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
+ // Categories are used to extend the class by declaring new methods.
+ // By the same token, they are also used to add new properties. No
+ // need to compare the added property to those in the class.
+
+ // Merge protocol properties into category
+ MergeProtocolPropertiesIntoClass(C, DeclPtrTy::make(C));
+ if (C->getIdentifier() == 0)
+ DiagnoseClassExtensionDupMethods(C, C->getClassInterface());
+ }
+ if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(ClassDecl)) {
+ // ProcessPropertyDecl is responsible for diagnosing conflicts with any
+ // user-defined setter/getter. It also synthesizes setter/getter methods
+ // and adds them to the DeclContext and global method pools.
+ for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(Context),
+ E = CDecl->prop_end(Context);
+ I != E; ++I)
+ ProcessPropertyDecl(*I, CDecl);
+ CDecl->setAtEndLoc(AtEndLoc);
+ }
+ if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
+ IC->setLocEnd(AtEndLoc);
+ if (ObjCInterfaceDecl* IDecl = IC->getClassInterface())
+ ImplMethodsVsClassMethods(IC, IDecl);
+ } else if (ObjCCategoryImplDecl* CatImplClass =
+ dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
+ CatImplClass->setLocEnd(AtEndLoc);
+
+ // Find category interface decl and then check that all methods declared
+ // in this interface are implemented in the category @implementation.
+ if (ObjCInterfaceDecl* IDecl = CatImplClass->getClassInterface()) {
+ for (ObjCCategoryDecl *Categories = IDecl->getCategoryList();
+ Categories; Categories = Categories->getNextClassCategory()) {
+ if (Categories->getIdentifier() == CatImplClass->getIdentifier()) {
+ ImplMethodsVsClassMethods(CatImplClass, Categories);
+ break;
+ }
+ }
+ }
+ }
+ if (isInterfaceDeclKind) {
+ // Reject invalid vardecls.
+ for (unsigned i = 0; i != tuvNum; i++) {
+ DeclGroupRef DG = allTUVars[i].getAsVal<DeclGroupRef>();
+ for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
+ if (VarDecl *VDecl = dyn_cast<VarDecl>(*I)) {
+ if (!VDecl->hasExternalStorage())
+ Diag(VDecl->getLocation(), diag::err_objc_var_decl_inclass);
+ }
+ }
+ }
+}
+
+
+/// CvtQTToAstBitMask - utility routine to produce an AST bitmask for
+/// objective-c's type qualifier from the parser version of the same info.
+static Decl::ObjCDeclQualifier
+CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) {
+ Decl::ObjCDeclQualifier ret = Decl::OBJC_TQ_None;
+ if (PQTVal & ObjCDeclSpec::DQ_In)
+ ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_In);
+ if (PQTVal & ObjCDeclSpec::DQ_Inout)
+ ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Inout);
+ if (PQTVal & ObjCDeclSpec::DQ_Out)
+ ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Out);
+ if (PQTVal & ObjCDeclSpec::DQ_Bycopy)
+ ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Bycopy);
+ if (PQTVal & ObjCDeclSpec::DQ_Byref)
+ ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Byref);
+ if (PQTVal & ObjCDeclSpec::DQ_Oneway)
+ ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Oneway);
+
+ return ret;
+}
+
+Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
+ SourceLocation MethodLoc, SourceLocation EndLoc,
+ tok::TokenKind MethodType, DeclPtrTy classDecl,
+ ObjCDeclSpec &ReturnQT, TypeTy *ReturnType,
+ Selector Sel,
+ // optional arguments. The number of types/arguments is obtained
+ // from the Sel.getNumArgs().
+ ObjCArgInfo *ArgInfo,
+ llvm::SmallVectorImpl<Declarator> &Cdecls,
+ AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind,
+ bool isVariadic) {
+ Decl *ClassDecl = classDecl.getAs<Decl>();
+
+ // Make sure we can establish a context for the method.
+ if (!ClassDecl) {
+ Diag(MethodLoc, diag::error_missing_method_context);
+ return DeclPtrTy();
+ }
+ QualType resultDeclType;
+
+ if (ReturnType) {
+ resultDeclType = QualType::getFromOpaquePtr(ReturnType);
+
+ // Methods cannot return interface types. All ObjC objects are
+ // passed by reference.
+ if (resultDeclType->isObjCInterfaceType()) {
+ Diag(MethodLoc, diag::err_object_cannot_be_passed_returned_by_value)
+ << 0 << resultDeclType;
+ return DeclPtrTy();
+ }
+ } else // get the type for "id".
+ resultDeclType = Context.getObjCIdType();
+
+ ObjCMethodDecl* ObjCMethod =
+ ObjCMethodDecl::Create(Context, MethodLoc, EndLoc, Sel, resultDeclType,
+ cast<DeclContext>(ClassDecl),
+ MethodType == tok::minus, isVariadic,
+ false,
+ MethodDeclKind == tok::objc_optional ?
+ ObjCMethodDecl::Optional :
+ ObjCMethodDecl::Required);
+
+ llvm::SmallVector<ParmVarDecl*, 16> Params;
+
+ for (unsigned i = 0, e = Sel.getNumArgs(); i != e; ++i) {
+ QualType ArgType, UnpromotedArgType;
+
+ if (ArgInfo[i].Type == 0) {
+ UnpromotedArgType = ArgType = Context.getObjCIdType();
+ } else {
+ UnpromotedArgType = ArgType = QualType::getFromOpaquePtr(ArgInfo[i].Type);
+ // Perform the default array/function conversions (C99 6.7.5.3p[7,8]).
+ ArgType = adjustParameterType(ArgType);
+ }
+
+ ParmVarDecl* Param;
+ if (ArgType == UnpromotedArgType)
+ Param = ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc,
+ ArgInfo[i].Name, ArgType,
+ VarDecl::None, 0);
+ else
+ Param = OriginalParmVarDecl::Create(Context, ObjCMethod,
+ ArgInfo[i].NameLoc,
+ ArgInfo[i].Name, ArgType,
+ UnpromotedArgType,
+ VarDecl::None, 0);
+
+ if (ArgType->isObjCInterfaceType()) {
+ Diag(ArgInfo[i].NameLoc,
+ diag::err_object_cannot_be_passed_returned_by_value)
+ << 1 << ArgType;
+ Param->setInvalidDecl();
+ }
+
+ Param->setObjCDeclQualifier(
+ CvtQTToAstBitMask(ArgInfo[i].DeclSpec.getObjCDeclQualifier()));
+
+ // Apply the attributes to the parameter.
+ ProcessDeclAttributeList(Param, ArgInfo[i].ArgAttrs);
+
+ Params.push_back(Param);
+ }
+
+ ObjCMethod->setMethodParams(Context, Params.data(), Sel.getNumArgs());
+ ObjCMethod->setObjCDeclQualifier(
+ CvtQTToAstBitMask(ReturnQT.getObjCDeclQualifier()));
+ const ObjCMethodDecl *PrevMethod = 0;
+
+ if (AttrList)
+ ProcessDeclAttributeList(ObjCMethod, AttrList);
+
+ // For implementations (which can be very "coarse grain"), we add the
+ // method now. This allows the AST to implement lookup methods that work
+ // incrementally (without waiting until we parse the @end). It also allows
+ // us to flag multiple declaration errors as they occur.
+ if (ObjCImplementationDecl *ImpDecl =
+ dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
+ if (MethodType == tok::minus) {
+ PrevMethod = ImpDecl->getInstanceMethod(Context, Sel);
+ ImpDecl->addInstanceMethod(Context, ObjCMethod);
+ } else {
+ PrevMethod = ImpDecl->getClassMethod(Context, Sel);
+ ImpDecl->addClassMethod(Context, ObjCMethod);
+ }
+ if (AttrList)
+ Diag(EndLoc, diag::warn_attribute_method_def);
+ }
+ else if (ObjCCategoryImplDecl *CatImpDecl =
+ dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
+ if (MethodType == tok::minus) {
+ PrevMethod = CatImpDecl->getInstanceMethod(Context, Sel);
+ CatImpDecl->addInstanceMethod(Context, ObjCMethod);
+ } else {
+ PrevMethod = CatImpDecl->getClassMethod(Context, Sel);
+ CatImpDecl->addClassMethod(Context, ObjCMethod);
+ }
+ if (AttrList)
+ Diag(EndLoc, diag::warn_attribute_method_def);
+ }
+ if (PrevMethod) {
+ // You can never have two method definitions with the same name.
+ Diag(ObjCMethod->getLocation(), diag::err_duplicate_method_decl)
+ << ObjCMethod->getDeclName();
+ Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
+ }
+ return DeclPtrTy::make(ObjCMethod);
+}
+
+void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
+ SourceLocation Loc,
+ unsigned &Attributes) {
+ // FIXME: Improve the reported location.
+
+ // readonly and readwrite/assign/retain/copy conflict.
+ if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+ (Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
+ ObjCDeclSpec::DQ_PR_assign |
+ ObjCDeclSpec::DQ_PR_copy |
+ ObjCDeclSpec::DQ_PR_retain))) {
+ const char * which = (Attributes & ObjCDeclSpec::DQ_PR_readwrite) ?
+ "readwrite" :
+ (Attributes & ObjCDeclSpec::DQ_PR_assign) ?
+ "assign" :
+ (Attributes & ObjCDeclSpec::DQ_PR_copy) ?
+ "copy" : "retain";
+
+ Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ?
+ diag::err_objc_property_attr_mutually_exclusive :
+ diag::warn_objc_property_attr_mutually_exclusive)
+ << "readonly" << which;
+ }
+
+ // Check for copy or retain on non-object types.
+ if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) &&
+ !Context.isObjCObjectPointerType(PropertyTy)) {
+ Diag(Loc, diag::err_objc_property_requires_object)
+ << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain");
+ Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain);
+ }
+
+ // Check for more than one of { assign, copy, retain }.
+ if (Attributes & ObjCDeclSpec::DQ_PR_assign) {
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "assign" << "copy";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_copy;
+ }
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "assign" << "retain";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
+ }
+ } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+ << "copy" << "retain";
+ Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
+ }
+ }
+
+ // 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 |
+ ObjCDeclSpec::DQ_PR_retain)) &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+ Context.isObjCObjectPointerType(PropertyTy)) {
+ // Skip this warning in gc-only mode.
+ if (getLangOptions().getGCMode() != 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);
+
+ // FIXME: Implement warning dependent on NSCopying being
+ // implemented. See also:
+ // <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496>
+ // (please trim this list while you are at it).
+ }
+
+ if (!(Attributes & ObjCDeclSpec::DQ_PR_copy)
+ && getLangOptions().getGCMode() == LangOptions::GCOnly
+ && PropertyTy->isBlockPointerType())
+ Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
+}
+
+Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
+ FieldDeclarator &FD,
+ ObjCDeclSpec &ODS,
+ Selector GetterSel,
+ Selector SetterSel,
+ DeclPtrTy ClassCategory,
+ bool *isOverridingProperty,
+ tok::ObjCKeywordKind MethodImplKind) {
+ unsigned Attributes = ODS.getPropertyAttributes();
+ bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||
+ // default is readwrite!
+ !(Attributes & ObjCDeclSpec::DQ_PR_readonly));
+ // property is defaulted to 'assign' if it is readwrite and is
+ // not retain or copy
+ bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) ||
+ (isReadWrite &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_retain) &&
+ !(Attributes & ObjCDeclSpec::DQ_PR_copy)));
+ QualType T = GetTypeForDeclarator(FD.D, S);
+ Decl *ClassDecl = ClassCategory.getAs<Decl>();
+ ObjCInterfaceDecl *CCPrimary = 0; // continuation class's primary class
+ // May modify Attributes.
+ CheckObjCPropertyAttributes(T, AtLoc, Attributes);
+ if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
+ if (!CDecl->getIdentifier()) {
+ // This is a continuation class. property requires special
+ // handling.
+ if ((CCPrimary = CDecl->getClassInterface())) {
+ // Find the property in continuation class's primary class only.
+ ObjCPropertyDecl *PIDecl = 0;
+ IdentifierInfo *PropertyId = FD.D.getIdentifier();
+ for (ObjCInterfaceDecl::prop_iterator
+ I = CCPrimary->prop_begin(Context),
+ E = CCPrimary->prop_end(Context);
+ I != E; ++I)
+ if ((*I)->getIdentifier() == PropertyId) {
+ PIDecl = *I;
+ break;
+ }
+
+ if (PIDecl) {
+ // property 'PIDecl's readonly attribute will be over-ridden
+ // with continuation class's readwrite property attribute!
+ unsigned PIkind = PIDecl->getPropertyAttributes();
+ if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) {
+ if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) !=
+ (PIkind & ObjCPropertyDecl::OBJC_PR_nonatomic))
+ Diag(AtLoc, diag::warn_property_attr_mismatch);
+ PIDecl->makeitReadWriteAttribute();
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain)
+ PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy)
+ PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
+ PIDecl->setSetterName(SetterSel);
+ }
+ else
+ Diag(AtLoc, diag::err_use_continuation_class)
+ << CCPrimary->getDeclName();
+ *isOverridingProperty = true;
+ // Make sure setter decl is synthesized, and added to primary
+ // class's list.
+ ProcessPropertyDecl(PIDecl, CCPrimary);
+ return DeclPtrTy();
+ }
+ // No matching property found in the primary class. Just fall thru
+ // and add property to continuation class's primary class.
+ ClassDecl = CCPrimary;
+ } else {
+ Diag(CDecl->getLocation(), diag::err_continuation_class);
+ *isOverridingProperty = true;
+ return DeclPtrTy();
+ }
+ }
+
+ DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
+ assert(DC && "ClassDecl is not a DeclContext");
+ ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
+ FD.D.getIdentifierLoc(),
+ FD.D.getIdentifier(), T);
+ DC->addDecl(Context, PDecl);
+
+ if (T->isArrayType() || T->isFunctionType()) {
+ Diag(AtLoc, diag::err_property_type) << T;
+ PDecl->setInvalidDecl();
+ }
+
+ ProcessDeclAttributes(PDecl, FD.D);
+
+ // Regardless of setter/getter attribute, we save the default getter/setter
+ // selector names in anticipation of declaration of setter/getter methods.
+ PDecl->setGetterName(GetterSel);
+ PDecl->setSetterName(SetterSel);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_getter)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_setter)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter);
+
+ if (isReadWrite)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
+
+ if (isAssign)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
+
+ if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
+
+ if (MethodImplKind == tok::objc_required)
+ PDecl->setPropertyImplementation(ObjCPropertyDecl::Required);
+ else if (MethodImplKind == tok::objc_optional)
+ PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional);
+ // A case of continuation class adding a new property in the class. This
+ // is not what it was meant for. However, gcc supports it and so should we.
+ // Make sure setter/getters are declared here.
+ if (CCPrimary)
+ ProcessPropertyDecl(PDecl, CCPrimary);
+
+ return DeclPtrTy::make(PDecl);
+}
+
+/// ActOnPropertyImplDecl - This routine performs semantic checks and
+/// builds the AST node for a property implementation declaration; declared
+/// as @synthesize or @dynamic.
+///
+Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
+ SourceLocation PropertyLoc,
+ bool Synthesize,
+ DeclPtrTy ClassCatImpDecl,
+ IdentifierInfo *PropertyId,
+ IdentifierInfo *PropertyIvar) {
+ Decl *ClassImpDecl = ClassCatImpDecl.getAs<Decl>();
+ // Make sure we have a context for the property implementation declaration.
+ if (!ClassImpDecl) {
+ Diag(AtLoc, diag::error_missing_property_context);
+ return DeclPtrTy();
+ }
+ ObjCPropertyDecl *property = 0;
+ ObjCInterfaceDecl* IDecl = 0;
+ // Find the class or category class where this property must have
+ // a declaration.
+ ObjCImplementationDecl *IC = 0;
+ ObjCCategoryImplDecl* CatImplClass = 0;
+ if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) {
+ IDecl = IC->getClassInterface();
+ // We always synthesize an interface for an implementation
+ // without an interface decl. So, IDecl is always non-zero.
+ assert(IDecl &&
+ "ActOnPropertyImplDecl - @implementation without @interface");
+
+ // Look for this property declaration in the @implementation's @interface
+ property = IDecl->FindPropertyDeclaration(Context, PropertyId);
+ if (!property) {
+ Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName();
+ return DeclPtrTy();
+ }
+ }
+ else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
+ if (Synthesize) {
+ Diag(AtLoc, diag::error_synthesize_category_decl);
+ return DeclPtrTy();
+ }
+ IDecl = CatImplClass->getClassInterface();
+ if (!IDecl) {
+ Diag(AtLoc, diag::error_missing_property_interface);
+ return DeclPtrTy();
+ }
+ ObjCCategoryDecl *Category =
+ IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier());
+
+ // If category for this implementation not found, it is an error which
+ // has already been reported eralier.
+ if (!Category)
+ return DeclPtrTy();
+ // Look for this property declaration in @implementation's category
+ property = Category->FindPropertyDeclaration(Context, PropertyId);
+ if (!property) {
+ Diag(PropertyLoc, diag::error_bad_category_property_decl)
+ << Category->getDeclName();
+ return DeclPtrTy();
+ }
+ } else {
+ Diag(AtLoc, diag::error_bad_property_context);
+ return DeclPtrTy();
+ }
+ ObjCIvarDecl *Ivar = 0;
+ // Check that we have a valid, previously declared ivar for @synthesize
+ if (Synthesize) {
+ // @synthesize
+ if (!PropertyIvar)
+ PropertyIvar = PropertyId;
+ QualType PropType = Context.getCanonicalType(property->getType());
+ // Check that this is a previously declared 'ivar' in 'IDecl' interface
+ ObjCInterfaceDecl *ClassDeclared;
+ Ivar = IDecl->lookupInstanceVariable(Context, PropertyIvar, ClassDeclared);
+ if (!Ivar) {
+ Ivar = ObjCIvarDecl::Create(Context, CurContext, PropertyLoc,
+ PropertyIvar, PropType,
+ ObjCIvarDecl::Public,
+ (Expr *)0);
+ property->setPropertyIvarDecl(Ivar);
+ if (!getLangOptions().ObjCNonFragileABI)
+ Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId;
+ // Note! I deliberately want it to fall thru so, we have a
+ // a property implementation and to avoid future warnings.
+ }
+ else if (getLangOptions().ObjCNonFragileABI &&
+ ClassDeclared != IDecl) {
+ Diag(PropertyLoc, diag::error_ivar_in_superclass_use)
+ << property->getDeclName() << Ivar->getDeclName()
+ << ClassDeclared->getDeclName();
+ Diag(Ivar->getLocation(), diag::note_previous_access_declaration)
+ << Ivar << Ivar->getNameAsCString();
+ // Note! I deliberately want it to fall thru so more errors are caught.
+ }
+ QualType IvarType = Context.getCanonicalType(Ivar->getType());
+
+ // Check that type of property and its ivar are type compatible.
+ if (PropType != IvarType) {
+ if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) {
+ Diag(PropertyLoc, diag::error_property_ivar_type)
+ << property->getDeclName() << Ivar->getDeclName();
+ // Note! I deliberately want it to fall thru so, we have a
+ // a property implementation and to avoid future warnings.
+ }
+
+ // FIXME! Rules for properties are somewhat different that those
+ // for assignments. Use a new routine to consolidate all cases;
+ // specifically for property redeclarations as well as for ivars.
+ QualType lhsType =Context.getCanonicalType(PropType).getUnqualifiedType();
+ QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType();
+ if (lhsType != rhsType &&
+ lhsType->isArithmeticType()) {
+ Diag(PropertyLoc, diag::error_property_ivar_type)
+ << property->getDeclName() << Ivar->getDeclName();
+ // Fall thru - see previous comment
+ }
+ // __weak is explicit. So it works on Canonical type.
+ if (PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
+ getLangOptions().getGCMode() != LangOptions::NonGC) {
+ Diag(PropertyLoc, diag::error_weak_property)
+ << property->getDeclName() << Ivar->getDeclName();
+ // Fall thru - see previous comment
+ }
+ if ((Context.isObjCObjectPointerType(property->getType()) ||
+ PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
+ getLangOptions().getGCMode() != LangOptions::NonGC) {
+ Diag(PropertyLoc, diag::error_strong_property)
+ << property->getDeclName() << Ivar->getDeclName();
+ // Fall thru - see previous comment
+ }
+ }
+ } else if (PropertyIvar)
+ // @dynamic
+ Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl);
+ assert (property && "ActOnPropertyImplDecl - property declaration missing");
+ ObjCPropertyImplDecl *PIDecl =
+ ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc,
+ property,
+ (Synthesize ?
+ ObjCPropertyImplDecl::Synthesize
+ : ObjCPropertyImplDecl::Dynamic),
+ Ivar);
+ if (IC) {
+ if (Synthesize)
+ if (ObjCPropertyImplDecl *PPIDecl =
+ IC->FindPropertyImplIvarDecl(Context, PropertyIvar)) {
+ Diag(PropertyLoc, diag::error_duplicate_ivar_use)
+ << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
+ << PropertyIvar;
+ Diag(PPIDecl->getLocation(), diag::note_previous_use);
+ }
+
+ if (ObjCPropertyImplDecl *PPIDecl
+ = IC->FindPropertyImplDecl(Context, PropertyId)) {
+ Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
+ Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
+ return DeclPtrTy();
+ }
+ IC->addPropertyImplementation(Context, PIDecl);
+ }
+ else {
+ if (Synthesize)
+ if (ObjCPropertyImplDecl *PPIDecl =
+ CatImplClass->FindPropertyImplIvarDecl(Context, PropertyIvar)) {
+ Diag(PropertyLoc, diag::error_duplicate_ivar_use)
+ << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
+ << PropertyIvar;
+ Diag(PPIDecl->getLocation(), diag::note_previous_use);
+ }
+
+ if (ObjCPropertyImplDecl *PPIDecl =
+ CatImplClass->FindPropertyImplDecl(Context, PropertyId)) {
+ Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
+ Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
+ return DeclPtrTy();
+ }
+ CatImplClass->addPropertyImplementation(Context, PIDecl);
+ }
+
+ return DeclPtrTy::make(PIDecl);
+}
+
+bool Sema::CheckObjCDeclScope(Decl *D) {
+ if (isa<TranslationUnitDecl>(CurContext->getLookupContext()))
+ return false;
+
+ Diag(D->getLocation(), diag::err_objc_decls_may_only_appear_in_global_scope);
+ D->setInvalidDecl();
+
+ return true;
+}
+
+/// Collect the instance variables declared in an Objective-C object. Used in
+/// the creation of structures from objects using the @defs directive.
+/// FIXME: This should be consolidated with CollectObjCIvars as it is also
+/// part of the AST generation logic of @defs.
+static void CollectIvars(ObjCInterfaceDecl *Class, RecordDecl *Record,
+ ASTContext& Ctx,
+ llvm::SmallVectorImpl<Sema::DeclPtrTy> &ivars) {
+ if (Class->getSuperClass())
+ CollectIvars(Class->getSuperClass(), Record, Ctx, ivars);
+
+ // For each ivar, create a fresh ObjCAtDefsFieldDecl.
+ for (ObjCInterfaceDecl::ivar_iterator I = Class->ivar_begin(),
+ E = Class->ivar_end(); I != E; ++I) {
+ ObjCIvarDecl* ID = *I;
+ Decl *FD = ObjCAtDefsFieldDecl::Create(Ctx, Record, ID->getLocation(),
+ ID->getIdentifier(), ID->getType(),
+ ID->getBitWidth());
+ ivars.push_back(Sema::DeclPtrTy::make(FD));
+ }
+}
+
+/// Called whenever @defs(ClassName) is encountered in the source. Inserts the
+/// instance variables of ClassName into Decls.
+void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
+ IdentifierInfo *ClassName,
+ llvm::SmallVectorImpl<DeclPtrTy> &Decls) {
+ // Check that ClassName is a valid class
+ ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName);
+ if (!Class) {
+ Diag(DeclStart, diag::err_undef_interface) << ClassName;
+ return;
+ }
+ if (LangOpts.ObjCNonFragileABI) {
+ Diag(DeclStart, diag::err_atdef_nonfragile_interface);
+ return;
+ }
+
+ // Collect the instance variables
+ CollectIvars(Class, dyn_cast<RecordDecl>(TagD.getAs<Decl>()), Context, Decls);
+
+ // Introduce all of these fields into the appropriate scope.
+ for (llvm::SmallVectorImpl<DeclPtrTy>::iterator D = Decls.begin();
+ D != Decls.end(); ++D) {
+ FieldDecl *FD = cast<FieldDecl>(D->getAs<Decl>());
+ if (getLangOptions().CPlusPlus)
+ PushOnScopeChains(cast<FieldDecl>(FD), S);
+ else if (RecordDecl *Record = dyn_cast<RecordDecl>(TagD.getAs<Decl>()))
+ Record->addDecl(Context, FD);
+ }
+}
+
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
new file mode 100644
index 000000000000..ee5132a7d8e0
--- /dev/null
+++ b/lib/Sema/SemaExpr.cpp
@@ -0,0 +1,5395 @@
+//===--- SemaExpr.cpp - Semantic Analysis for Expressions -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Designator.h"
+#include "clang/Parse/Scope.h"
+using namespace clang;
+
+/// \brief Determine whether the use of this declaration is valid, and
+/// emit any corresponding diagnostics.
+///
+/// This routine diagnoses various problems with referencing
+/// declarations that can occur when using a declaration. For example,
+/// it might warn if a deprecated or unavailable declaration is being
+/// used, or produce an error (and return true) if a C++0x deleted
+/// function is being used.
+///
+/// \returns true if there was an error (this declaration cannot be
+/// referenced), false otherwise.
+bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
+ // See if the decl is deprecated.
+ if (D->getAttr<DeprecatedAttr>()) {
+ // Implementing deprecated stuff requires referencing deprecated
+ // stuff. Don't warn if we are implementing a deprecated
+ // construct.
+ bool isSilenced = false;
+
+ if (NamedDecl *ND = getCurFunctionOrMethodDecl()) {
+ // If this reference happens *in* a deprecated function or method, don't
+ // warn.
+ isSilenced = ND->getAttr<DeprecatedAttr>();
+
+ // If this is an Objective-C method implementation, check to see if the
+ // method was deprecated on the declaration, not the definition.
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND)) {
+ // The semantic decl context of a ObjCMethodDecl is the
+ // ObjCImplementationDecl.
+ if (ObjCImplementationDecl *Impl
+ = dyn_cast<ObjCImplementationDecl>(MD->getParent())) {
+
+ MD = Impl->getClassInterface()->getMethod(Context,
+ MD->getSelector(),
+ MD->isInstanceMethod());
+ isSilenced |= MD && MD->getAttr<DeprecatedAttr>();
+ }
+ }
+ }
+
+ if (!isSilenced)
+ Diag(Loc, diag::warn_deprecated) << D->getDeclName();
+ }
+
+ // See if this is a deleted function.
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->isDeleted()) {
+ Diag(Loc, diag::err_deleted_function_use);
+ Diag(D->getLocation(), diag::note_unavailable_here) << true;
+ return true;
+ }
+ }
+
+ // See if the decl is unavailable
+ if (D->getAttr<UnavailableAttr>()) {
+ Diag(Loc, diag::warn_unavailable) << D->getDeclName();
+ Diag(D->getLocation(), diag::note_unavailable_here) << 0;
+ }
+
+ return false;
+}
+
+/// 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.
+///
+void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
+ Expr **Args, unsigned NumArgs)
+{
+ const SentinelAttr *attr = D->getAttr<SentinelAttr>();
+ if (!attr)
+ return;
+ int sentinelPos = attr->getSentinel();
+ int nullPos = attr->getNullPos();
+
+ // 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;
+ }
+ 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->getAsPointerType()->getPointeeType()->getAsFunctionType()
+ : Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType();
+ 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
+ return;
+ }
+ else
+ return;
+
+ if (warnNotEnoughArgs) {
+ Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName();
+ Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
+ return;
+ }
+ int sentinel = i;
+ while (sentinelPos > 0 && i < NumArgs-1) {
+ --sentinelPos;
+ ++i;
+ }
+ if (sentinelPos > 0) {
+ Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName();
+ Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
+ return;
+ }
+ while (i < NumArgs-1) {
+ ++i;
+ ++sentinel;
+ }
+ Expr *sentinelExpr = Args[sentinel];
+ if (sentinelExpr && (!sentinelExpr->getType()->isPointerType() ||
+ !sentinelExpr->isNullPointerConstant(Context))) {
+ Diag(Loc, diag::warn_missing_sentinel) << isMethod;
+ Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
+ }
+ return;
+}
+
+SourceRange Sema::getExprRange(ExprTy *E) const {
+ Expr *Ex = (Expr *)E;
+ return Ex? Ex->getSourceRange() : SourceRange();
+}
+
+//===----------------------------------------------------------------------===//
+// Standard Promotions and Conversions
+//===----------------------------------------------------------------------===//
+
+/// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4).
+void Sema::DefaultFunctionArrayConversion(Expr *&E) {
+ QualType Ty = E->getType();
+ assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type");
+
+ if (Ty->isFunctionType())
+ ImpCastExprToType(E, Context.getPointerType(Ty));
+ else if (Ty->isArrayType()) {
+ // In C90 mode, arrays only promote to pointers if the array expression is
+ // an lvalue. The relevant legalese is C90 6.2.2.1p3: "an lvalue that has
+ // type 'array of type' is converted to an expression that has type 'pointer
+ // to type'...". In C99 this was changed to: C99 6.3.2.1p3: "an expression
+ // that has type 'array of type' ...". The relevant change is "an lvalue"
+ // (C90) to "an expression" (C99).
+ //
+ // C++ 4.2p1:
+ // An lvalue or rvalue of type "array of N T" or "array of unknown bound of
+ // T" can be converted to an rvalue of type "pointer to T".
+ //
+ if (getLangOptions().C99 || getLangOptions().CPlusPlus ||
+ E->isLvalue(Context) == Expr::LV_Valid)
+ ImpCastExprToType(E, Context.getArrayDecayedType(Ty));
+ }
+}
+
+/// \brief Whether this is a promotable bitfield reference according
+/// to C99 6.3.1.1p2, bullet 2.
+///
+/// \returns the type this bit-field will promote to, or NULL if no
+/// promotion occurs.
+static QualType isPromotableBitField(Expr *E, ASTContext &Context) {
+ FieldDecl *Field = E->getBitField();
+ if (!Field)
+ return QualType();
+
+ const BuiltinType *BT = Field->getType()->getAsBuiltinType();
+ if (!BT)
+ return QualType();
+
+ if (BT->getKind() != BuiltinType::Bool &&
+ BT->getKind() != BuiltinType::Int &&
+ BT->getKind() != BuiltinType::UInt)
+ return QualType();
+
+ llvm::APSInt BitWidthAP;
+ if (!Field->getBitWidth()->isIntegerConstantExpr(BitWidthAP, Context))
+ return QualType();
+
+ uint64_t BitWidth = BitWidthAP.getZExtValue();
+ uint64_t IntSize = Context.getTypeSize(Context.IntTy);
+ if (BitWidth < IntSize ||
+ (Field->getType()->isSignedIntegerType() && BitWidth == IntSize))
+ return Context.IntTy;
+
+ if (BitWidth == IntSize && Field->getType()->isUnsignedIntegerType())
+ return Context.UnsignedIntTy;
+
+ return QualType();
+}
+
+/// UsualUnaryConversions - Performs various conversions that are common to most
+/// operators (C99 6.3). The conversions of array and function types are
+/// sometimes surpressed. For example, the array->pointer conversion doesn't
+/// apply if the array is an argument to the sizeof or address (&) operators.
+/// In these instances, this routine should *not* be called.
+Expr *Sema::UsualUnaryConversions(Expr *&Expr) {
+ QualType Ty = Expr->getType();
+ assert(!Ty.isNull() && "UsualUnaryConversions - missing type");
+
+ // C99 6.3.1.1p2:
+ //
+ // The following may be used in an expression wherever an int or
+ // unsigned int may be used:
+ // - an object or expression with an integer type whose integer
+ // conversion rank is less than or equal to the rank of int
+ // and unsigned int.
+ // - A bit-field of type _Bool, int, signed int, or unsigned int.
+ //
+ // If an int can represent all values of the original type, the
+ // 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.
+ if (Ty->isPromotableIntegerType()) {
+ ImpCastExprToType(Expr, Context.IntTy);
+ return Expr;
+ } else {
+ QualType T = isPromotableBitField(Expr, Context);
+ if (!T.isNull()) {
+ ImpCastExprToType(Expr, T);
+ return Expr;
+ }
+ }
+
+ DefaultFunctionArrayConversion(Expr);
+ return Expr;
+}
+
+/// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
+/// do not have a prototype. Arguments that have type float are promoted to
+/// double. All other argument types are converted by UsualUnaryConversions().
+void Sema::DefaultArgumentPromotion(Expr *&Expr) {
+ QualType Ty = Expr->getType();
+ assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type");
+
+ // If this is a 'float' (CVR qualified or typedef) promote to double.
+ if (const BuiltinType *BT = Ty->getAsBuiltinType())
+ if (BT->getKind() == BuiltinType::Float)
+ return ImpCastExprToType(Expr, Context.DoubleTy);
+
+ UsualUnaryConversions(Expr);
+}
+
+/// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
+/// will warn if the resulting type is not a POD type, and rejects ObjC
+/// interfaces passed by value. This returns true if the argument type is
+/// completely illegal.
+bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) {
+ DefaultArgumentPromotion(Expr);
+
+ if (Expr->getType()->isObjCInterfaceType()) {
+ Diag(Expr->getLocStart(),
+ diag::err_cannot_pass_objc_interface_to_vararg)
+ << Expr->getType() << CT;
+ return true;
+ }
+
+ if (!Expr->getType()->isPODType())
+ Diag(Expr->getLocStart(), diag::warn_cannot_pass_non_pod_arg_to_vararg)
+ << Expr->getType() << CT;
+
+ return false;
+}
+
+
+/// 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(Expr *&lhsExpr, Expr *&rhsExpr,
+ bool isCompAssign) {
+ if (!isCompAssign)
+ UsualUnaryConversions(lhsExpr);
+
+ UsualUnaryConversions(rhsExpr);
+
+ // For conversion purposes, we ignore any qualifiers.
+ // For example, "const float" and "float" are equivalent.
+ QualType lhs =
+ Context.getCanonicalType(lhsExpr->getType()).getUnqualifiedType();
+ QualType rhs =
+ Context.getCanonicalType(rhsExpr->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;
+
+ // Perform bitfield promotions.
+ QualType LHSBitfieldPromoteTy = isPromotableBitField(lhsExpr, Context);
+ if (!LHSBitfieldPromoteTy.isNull())
+ lhs = LHSBitfieldPromoteTy;
+ QualType RHSBitfieldPromoteTy = isPromotableBitField(rhsExpr, Context);
+ if (!RHSBitfieldPromoteTy.isNull())
+ rhs = RHSBitfieldPromoteTy;
+
+ QualType destType = UsualArithmeticConversionsType(lhs, rhs);
+ if (!isCompAssign)
+ ImpCastExprToType(lhsExpr, destType);
+ ImpCastExprToType(rhsExpr, destType);
+ return destType;
+}
+
+QualType Sema::UsualArithmeticConversionsType(QualType lhs, QualType rhs) {
+ // Perform the usual unary conversions. We do this early so that
+ // integral promotions to "int" can allow us to exit early, in the
+ // lhs == rhs check. Also, for conversion purposes, we ignore any
+ // qualifiers. For example, "const float" and "float" are
+ // equivalent.
+ if (lhs->isPromotableIntegerType())
+ lhs = Context.IntTy;
+ else
+ lhs = lhs.getUnqualifiedType();
+ if (rhs->isPromotableIntegerType())
+ rhs = Context.IntTy;
+ else
+ rhs = rhs.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;
+
+ // At this point, we have two different arithmetic types.
+
+ // Handle complex types first (C99 6.3.1.8p1).
+ if (lhs->isComplexType() || rhs->isComplexType()) {
+ // if we have an integer operand, the result is the complex type.
+ if (rhs->isIntegerType() || rhs->isComplexIntegerType()) {
+ // convert the rhs to the lhs complex type.
+ return lhs;
+ }
+ if (lhs->isIntegerType() || lhs->isComplexIntegerType()) {
+ // convert the lhs to the rhs complex type.
+ 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 result = Context.getFloatingTypeOrder(lhs, rhs);
+
+ if (result > 0) { // The left side is bigger, convert rhs.
+ rhs = Context.getFloatingTypeOfSizeWithinDomain(lhs, rhs);
+ } else if (result < 0) { // The right side is bigger, convert lhs.
+ lhs = Context.getFloatingTypeOfSizeWithinDomain(rhs, lhs);
+ }
+ // At this point, lhs and rhs have the same rank/size. Now, make sure the
+ // domains match. This is a requirement for our implementation, C99
+ // does not require this promotion.
+ if (lhs != rhs) { // Domains don't match, we have complex/float mix.
+ if (lhs->isRealFloatingType()) { // handle "double, _Complex double".
+ return rhs;
+ } else { // handle "_Complex double, double".
+ return lhs;
+ }
+ }
+ return lhs; // The domain/size match exactly.
+ }
+ // Now handle "real" floating types (i.e. float, double, long double).
+ if (lhs->isRealFloatingType() || rhs->isRealFloatingType()) {
+ // if we have an integer operand, the result is the real floating type.
+ if (rhs->isIntegerType()) {
+ // convert rhs to the lhs floating point type.
+ return lhs;
+ }
+ if (rhs->isComplexIntegerType()) {
+ // convert rhs to the complex floating point type.
+ return Context.getComplexType(lhs);
+ }
+ if (lhs->isIntegerType()) {
+ // convert lhs to the rhs floating point type.
+ return rhs;
+ }
+ if (lhs->isComplexIntegerType()) {
+ // convert lhs to the complex floating point type.
+ return Context.getComplexType(rhs);
+ }
+ // We have two real floating types, float/complex combos were handled above.
+ // Convert the smaller operand to the bigger result.
+ int result = Context.getFloatingTypeOrder(lhs, rhs);
+ if (result > 0) // convert the rhs
+ return lhs;
+ assert(result < 0 && "illegal float comparison");
+ return rhs; // convert the lhs
+ }
+ if (lhs->isComplexIntegerType() || rhs->isComplexIntegerType()) {
+ // Handle GCC complex int extension.
+ const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType();
+ const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType();
+
+ if (lhsComplexInt && rhsComplexInt) {
+ if (Context.getIntegerTypeOrder(lhsComplexInt->getElementType(),
+ rhsComplexInt->getElementType()) >= 0)
+ return lhs; // convert the rhs
+ return rhs;
+ } else if (lhsComplexInt && rhs->isIntegerType()) {
+ // convert the rhs to the lhs complex type.
+ return lhs;
+ } else if (rhsComplexInt && lhs->isIntegerType()) {
+ // convert the lhs to the rhs complex type.
+ return rhs;
+ }
+ }
+ // Finally, we have two differing integer types.
+ // The rules for this case are in C99 6.3.1.8
+ int compare = Context.getIntegerTypeOrder(lhs, rhs);
+ bool lhsSigned = lhs->isSignedIntegerType(),
+ rhsSigned = rhs->isSignedIntegerType();
+ QualType destType;
+ if (lhsSigned == rhsSigned) {
+ // Same signedness; use the higher-ranked type
+ destType = compare >= 0 ? lhs : rhs;
+ } else if (compare != (lhsSigned ? 1 : -1)) {
+ // The unsigned type has greater than or equal rank to the
+ // signed type, so use the unsigned type
+ destType = lhsSigned ? rhs : lhs;
+ } else if (Context.getIntWidth(lhs) != Context.getIntWidth(rhs)) {
+ // 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.
+ destType = lhsSigned ? lhs : rhs;
+ } 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.
+ destType = Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs);
+ }
+ return destType;
+}
+
+//===----------------------------------------------------------------------===//
+// Semantic Analysis for various Expression Types
+//===----------------------------------------------------------------------===//
+
+
+/// ActOnStringLiteral - The specified tokens were lexed as pasted string
+/// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string
+/// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from
+/// multiple tokens. However, the common case is that StringToks points to one
+/// string.
+///
+Action::OwningExprResult
+Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
+ assert(NumStringToks && "Must have at least one string!");
+
+ StringLiteralParser Literal(StringToks, NumStringToks, PP);
+ if (Literal.hadError)
+ return ExprError();
+
+ llvm::SmallVector<SourceLocation, 4> StringTokLocs;
+ for (unsigned i = 0; i != NumStringToks; ++i)
+ StringTokLocs.push_back(StringToks[i].getLocation());
+
+ QualType StrTy = Context.CharTy;
+ if (Literal.AnyWide) StrTy = Context.getWCharType();
+ if (Literal.Pascal) StrTy = Context.UnsignedCharTy;
+
+ // A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
+ if (getLangOptions().CPlusPlus)
+ StrTy.addConst();
+
+ // Get an array type for the string, according to C99 6.4.5. This includes
+ // the nul terminator character as well as the string length for pascal
+ // strings.
+ StrTy = Context.getConstantArrayType(StrTy,
+ llvm::APInt(32, Literal.GetNumStringChars()+1),
+ ArrayType::Normal, 0);
+
+ // Pass &StringTokLocs[0], StringTokLocs.size() to factory!
+ return Owned(StringLiteral::Create(Context, Literal.GetString(),
+ Literal.GetStringLength(),
+ Literal.AnyWide, StrTy,
+ &StringTokLocs[0],
+ StringTokLocs.size()));
+}
+
+/// ShouldSnapshotBlockValueReference - Return true if a reference inside of
+/// CurBlock to VD should cause it to be snapshotted (as we do for auto
+/// variables defined outside the block) or false if this is not needed (e.g.
+/// for values inside the block or for globals).
+///
+/// This also keeps the 'hasBlockDeclRefExprs' in the BlockSemaInfo records
+/// up-to-date.
+///
+static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
+ ValueDecl *VD) {
+ // If the value is defined inside the block, we couldn't snapshot it even if
+ // we wanted to.
+ if (CurBlock->TheDecl == VD->getDeclContext())
+ return false;
+
+ // If this is an enum constant or function, it is constant, don't snapshot.
+ if (isa<EnumConstantDecl>(VD) || isa<FunctionDecl>(VD))
+ return false;
+
+ // If this is a reference to an extern, static, or global variable, no need to
+ // snapshot it.
+ // FIXME: What about 'const' variables in C++?
+ if (const VarDecl *Var = dyn_cast<VarDecl>(VD))
+ if (!Var->hasLocalStorage())
+ return false;
+
+ // Blocks that have these can't be constant.
+ CurBlock->hasBlockDeclRefExprs = true;
+
+ // If we have nested blocks, the decl may be declared in an outer block (in
+ // which case that outer block doesn't get "hasBlockDeclRefExprs") or it may
+ // be defined outside all of the current blocks (in which case the blocks do
+ // all get the bit). Walk the nesting chain.
+ for (BlockSemaInfo *NextBlock = CurBlock->PrevBlockInfo; NextBlock;
+ NextBlock = NextBlock->PrevBlockInfo) {
+ // If we found the defining block for the variable, don't mark the block as
+ // having a reference outside it.
+ if (NextBlock->TheDecl == VD->getDeclContext())
+ break;
+
+ // Otherwise, the DeclRef from the inner block causes the outer one to need
+ // a snapshot as well.
+ NextBlock->hasBlockDeclRefExprs = true;
+ }
+
+ return true;
+}
+
+
+
+/// ActOnIdentifierExpr - The parser read an identifier in expression context,
+/// validate it per-C99 6.5.1. HasTrailingLParen indicates whether this
+/// identifier is used in a function call context.
+/// SS is only used for a C++ qualified-id (foo::bar) to indicate the
+/// class or namespace that the identifier must be a member of.
+Sema::OwningExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
+ IdentifierInfo &II,
+ bool HasTrailingLParen,
+ const CXXScopeSpec *SS,
+ bool isAddressOfOperand) {
+ return ActOnDeclarationNameExpr(S, Loc, &II, HasTrailingLParen, SS,
+ isAddressOfOperand);
+}
+
+/// BuildDeclRefExpr - Build either a DeclRefExpr or a
+/// QualifiedDeclRefExpr based on whether or not SS is a
+/// nested-name-specifier.
+DeclRefExpr *
+Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
+ bool TypeDependent, bool ValueDependent,
+ const CXXScopeSpec *SS) {
+ if (SS && !SS->isEmpty()) {
+ return new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent,
+ ValueDependent, SS->getRange(),
+ static_cast<NestedNameSpecifier *>(SS->getScopeRep()));
+ } else
+ return new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent);
+}
+
+/// getObjectForAnonymousRecordDecl - Retrieve the (unnamed) field or
+/// variable corresponding to the anonymous union or struct whose type
+/// is Record.
+static Decl *getObjectForAnonymousRecordDecl(ASTContext &Context,
+ RecordDecl *Record) {
+ assert(Record->isAnonymousStructOrUnion() &&
+ "Record must be an anonymous struct or union!");
+
+ // FIXME: Once Decls are directly linked together, this will be an O(1)
+ // operation rather than a slow walk through DeclContext's vector (which
+ // itself will be eliminated). DeclGroups might make this even better.
+ DeclContext *Ctx = Record->getDeclContext();
+ for (DeclContext::decl_iterator D = Ctx->decls_begin(Context),
+ DEnd = Ctx->decls_end(Context);
+ D != DEnd; ++D) {
+ if (*D == Record) {
+ // The object for the anonymous struct/union directly
+ // follows its type in the list of declarations.
+ ++D;
+ assert(D != DEnd && "Missing object for anonymous record");
+ assert(!cast<NamedDecl>(*D)->getDeclName() && "Decl should be unnamed");
+ return *D;
+ }
+ }
+
+ assert(false && "Missing object for anonymous record");
+ return 0;
+}
+
+/// \brief Given a field that represents a member of an anonymous
+/// struct/union, build the path from that field's context to the
+/// actual member.
+///
+/// Construct the sequence of field member references we'll have to
+/// perform to get to the field in the anonymous union/struct. The
+/// list of members is built from the field outward, so traverse it
+/// backwards to go from an object in the current context to the field
+/// we found.
+///
+/// \returns The variable from which the field access should begin,
+/// for an anonymous struct/union that is not a member of another
+/// class. Otherwise, returns NULL.
+VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
+ llvm::SmallVectorImpl<FieldDecl *> &Path) {
+ assert(Field->getDeclContext()->isRecord() &&
+ cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion()
+ && "Field must be stored inside an anonymous struct or union");
+
+ Path.push_back(Field);
+ VarDecl *BaseObject = 0;
+ DeclContext *Ctx = Field->getDeclContext();
+ do {
+ RecordDecl *Record = cast<RecordDecl>(Ctx);
+ Decl *AnonObject = getObjectForAnonymousRecordDecl(Context, Record);
+ if (FieldDecl *AnonField = dyn_cast<FieldDecl>(AnonObject))
+ Path.push_back(AnonField);
+ else {
+ BaseObject = cast<VarDecl>(AnonObject);
+ break;
+ }
+ Ctx = Ctx->getParent();
+ } while (Ctx->isRecord() &&
+ cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion());
+
+ return BaseObject;
+}
+
+Sema::OwningExprResult
+Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
+ FieldDecl *Field,
+ Expr *BaseObjectExpr,
+ SourceLocation OpLoc) {
+ llvm::SmallVector<FieldDecl *, 4> AnonFields;
+ VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field,
+ AnonFields);
+
+ // Build the expression that refers to the base object, from
+ // which we will build a sequence of member references to each
+ // of the anonymous union objects and, eventually, the field we
+ // found via name lookup.
+ bool BaseObjectIsPointer = false;
+ unsigned ExtraQuals = 0;
+ if (BaseObject) {
+ // BaseObject is an anonymous struct/union variable (and is,
+ // therefore, not part of another non-anonymous record).
+ if (BaseObjectExpr) BaseObjectExpr->Destroy(Context);
+ BaseObjectExpr = new (Context) DeclRefExpr(BaseObject,BaseObject->getType(),
+ SourceLocation());
+ ExtraQuals
+ = Context.getCanonicalType(BaseObject->getType()).getCVRQualifiers();
+ } else if (BaseObjectExpr) {
+ // The caller provided the base object expression. Determine
+ // whether its a pointer and whether it adds any qualifiers to the
+ // anonymous struct/union fields we're looking into.
+ QualType ObjectType = BaseObjectExpr->getType();
+ if (const PointerType *ObjectPtr = ObjectType->getAsPointerType()) {
+ BaseObjectIsPointer = true;
+ ObjectType = ObjectPtr->getPointeeType();
+ }
+ ExtraQuals = Context.getCanonicalType(ObjectType).getCVRQualifiers();
+ } else {
+ // We've found a member of an anonymous struct/union that is
+ // inside a non-anonymous struct/union, so in a well-formed
+ // program our base object expression is "this".
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
+ if (!MD->isStatic()) {
+ QualType AnonFieldType
+ = Context.getTagDeclType(
+ cast<RecordDecl>(AnonFields.back()->getDeclContext()));
+ QualType ThisType = Context.getTagDeclType(MD->getParent());
+ if ((Context.getCanonicalType(AnonFieldType)
+ == Context.getCanonicalType(ThisType)) ||
+ IsDerivedFrom(ThisType, AnonFieldType)) {
+ // Our base object expression is "this".
+ BaseObjectExpr = new (Context) CXXThisExpr(SourceLocation(),
+ MD->getThisType(Context));
+ BaseObjectIsPointer = true;
+ }
+ } else {
+ return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method)
+ << Field->getDeclName());
+ }
+ ExtraQuals = MD->getTypeQualifiers();
+ }
+
+ if (!BaseObjectExpr)
+ return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use)
+ << Field->getDeclName());
+ }
+
+ // Build the implicit member references to the field of the
+ // anonymous struct/union.
+ Expr *Result = BaseObjectExpr;
+ for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator
+ FI = AnonFields.rbegin(), FIEnd = AnonFields.rend();
+ FI != FIEnd; ++FI) {
+ QualType MemberType = (*FI)->getType();
+ if (!(*FI)->isMutable()) {
+ unsigned combinedQualifiers
+ = MemberType.getCVRQualifiers() | ExtraQuals;
+ MemberType = MemberType.getQualifiedType(combinedQualifiers);
+ }
+ Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI,
+ OpLoc, MemberType);
+ BaseObjectIsPointer = false;
+ ExtraQuals = Context.getCanonicalType(MemberType).getCVRQualifiers();
+ }
+
+ return Owned(Result);
+}
+
+/// ActOnDeclarationNameExpr - The parser has read some kind of name
+/// (e.g., a C++ id-expression (C++ [expr.prim]p1)). This routine
+/// performs lookup on that name and returns an expression that refers
+/// to that name. This routine isn't directly called from the parser,
+/// because the parser doesn't know about DeclarationName. Rather,
+/// this routine is called by ActOnIdentifierExpr,
+/// ActOnOperatorFunctionIdExpr, and ActOnConversionFunctionExpr,
+/// which form the DeclarationName from the corresponding syntactic
+/// forms.
+///
+/// HasTrailingLParen indicates whether this identifier is used in a
+/// function call context. LookupCtx is only used for a C++
+/// qualified-id (foo::bar) to indicate the class or namespace that
+/// the identifier must be a member of.
+///
+/// isAddressOfOperand means that this expression is the direct operand
+/// of an address-of operator. This matters because this is the only
+/// situation where a qualified name referencing a non-static member may
+/// appear outside a member function of this class.
+Sema::OwningExprResult
+Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
+ DeclarationName Name, bool HasTrailingLParen,
+ const CXXScopeSpec *SS,
+ bool isAddressOfOperand) {
+ // Could be enum-constant, value decl, instance variable, etc.
+ if (SS && SS->isInvalid())
+ return ExprError();
+
+ // C++ [temp.dep.expr]p3:
+ // An id-expression is type-dependent if it contains:
+ // -- a nested-name-specifier that contains a class-name that
+ // names a dependent type.
+ // FIXME: Member of the current instantiation.
+ if (SS && isDependentScopeSpecifier(*SS)) {
+ return Owned(new (Context) UnresolvedDeclRefExpr(Name, Context.DependentTy,
+ Loc, SS->getRange(),
+ static_cast<NestedNameSpecifier *>(SS->getScopeRep())));
+ }
+
+ LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName,
+ false, true, Loc);
+
+ if (Lookup.isAmbiguous()) {
+ DiagnoseAmbiguousLookup(Lookup, Name, Loc,
+ SS && SS->isSet() ? SS->getRange()
+ : SourceRange());
+ return ExprError();
+ }
+
+ NamedDecl *D = Lookup.getAsDecl();
+
+ // If this reference is in an Objective-C method, then ivar lookup happens as
+ // well.
+ IdentifierInfo *II = Name.getAsIdentifierInfo();
+ if (II && getCurMethodDecl()) {
+ // There are two cases to handle here. 1) scoped lookup could have failed,
+ // in which case we should look for an ivar. 2) scoped lookup could have
+ // found a decl, but that decl is outside the current instance method (i.e.
+ // a global variable). In these two cases, we do a lookup for an ivar with
+ // this name, if the lookup sucedes, we replace it our current decl.
+ if (D == 0 || D->isDefinedOutsideFunctionOrMethod()) {
+ ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
+ ObjCInterfaceDecl *ClassDeclared;
+ if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(Context, II,
+ ClassDeclared)) {
+ // Check if referencing a field with __attribute__((deprecated)).
+ if (DiagnoseUseOfDecl(IV, Loc))
+ return ExprError();
+
+ // If we're referencing an invalid decl, just return this as a silent
+ // error node. The error diagnostic was already emitted on the decl.
+ if (IV->isInvalidDecl())
+ return ExprError();
+
+ bool IsClsMethod = getCurMethodDecl()->isClassMethod();
+ // If a class method attemps to use a free standing ivar, this is
+ // an error.
+ if (IsClsMethod && D && !D->isDefinedOutsideFunctionOrMethod())
+ return ExprError(Diag(Loc, diag::error_ivar_use_in_class_method)
+ << IV->getDeclName());
+ // If a class method uses a global variable, even if an ivar with
+ // same name exists, use the global.
+ if (!IsClsMethod) {
+ if (IV->getAccessControl() == ObjCIvarDecl::Private &&
+ ClassDeclared != IFace)
+ Diag(Loc, diag::error_private_ivar_access) << IV->getDeclName();
+ // FIXME: This should use a new expr for a direct reference, don't
+ // turn this into Self->ivar, just return a BareIVarExpr or something.
+ IdentifierInfo &II = Context.Idents.get("self");
+ OwningExprResult SelfExpr = ActOnIdentifierExpr(S, Loc, II, false);
+ return Owned(new (Context)
+ ObjCIvarRefExpr(IV, IV->getType(), Loc,
+ SelfExpr.takeAs<Expr>(), true, true));
+ }
+ }
+ }
+ else if (getCurMethodDecl()->isInstanceMethod()) {
+ // We should warn if a local variable hides an ivar.
+ ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
+ ObjCInterfaceDecl *ClassDeclared;
+ if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(Context, II,
+ ClassDeclared)) {
+ if (IV->getAccessControl() != ObjCIvarDecl::Private ||
+ IFace == ClassDeclared)
+ Diag(Loc, diag::warn_ivar_use_hidden) << IV->getDeclName();
+ }
+ }
+ // Needed to implement property "super.method" notation.
+ if (D == 0 && II->isStr("super")) {
+ QualType T;
+
+ if (getCurMethodDecl()->isInstanceMethod())
+ T = Context.getPointerType(Context.getObjCInterfaceType(
+ getCurMethodDecl()->getClassInterface()));
+ else
+ T = Context.getObjCClassType();
+ return Owned(new (Context) ObjCSuperExpr(Loc, T));
+ }
+ }
+
+ // Determine whether this name might be a candidate for
+ // argument-dependent lookup.
+ bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
+ HasTrailingLParen;
+
+ if (ADL && D == 0) {
+ // We've seen something of the form
+ //
+ // identifier(
+ //
+ // and we did not find any entity by the name
+ // "identifier". However, this identifier is still subject to
+ // argument-dependent lookup, so keep track of the name.
+ return Owned(new (Context) UnresolvedFunctionNameExpr(Name,
+ Context.OverloadTy,
+ Loc));
+ }
+
+ if (D == 0) {
+ // Otherwise, this could be an implicitly declared function reference (legal
+ // in C90, extension in C99).
+ if (HasTrailingLParen && II &&
+ !getLangOptions().CPlusPlus) // Not in C++.
+ D = ImplicitlyDefineFunction(Loc, *II, S);
+ else {
+ // If this name wasn't predeclared and if this is not a function call,
+ // diagnose the problem.
+ if (SS && !SS->isEmpty())
+ return ExprError(Diag(Loc, diag::err_typecheck_no_member)
+ << Name << SS->getRange());
+ else if (Name.getNameKind() == DeclarationName::CXXOperatorName ||
+ Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
+ return ExprError(Diag(Loc, diag::err_undeclared_use)
+ << Name.getAsString());
+ else
+ return ExprError(Diag(Loc, diag::err_undeclared_var_use) << Name);
+ }
+ }
+
+ // If this is an expression of the form &Class::member, don't build an
+ // implicit member ref, because we want a pointer to the member in general,
+ // not any specific instance's member.
+ if (isAddressOfOperand && SS && !SS->isEmpty() && !HasTrailingLParen) {
+ DeclContext *DC = computeDeclContext(*SS);
+ if (D && isa<CXXRecordDecl>(DC)) {
+ QualType DType;
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+ DType = FD->getType().getNonReferenceType();
+ } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
+ DType = Method->getType();
+ } else if (isa<OverloadedFunctionDecl>(D)) {
+ DType = Context.OverloadTy;
+ }
+ // Could be an inner type. That's diagnosed below, so ignore it here.
+ if (!DType.isNull()) {
+ // The pointer is type- and value-dependent if it points into something
+ // dependent.
+ bool Dependent = DC->isDependentContext();
+ return Owned(BuildDeclRefExpr(D, DType, Loc, Dependent, Dependent, SS));
+ }
+ }
+ }
+
+ // We may have found a field within an anonymous union or struct
+ // (C++ [class.union]).
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(D))
+ if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion())
+ return BuildAnonymousStructUnionMemberReference(Loc, FD);
+
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
+ if (!MD->isStatic()) {
+ // C++ [class.mfct.nonstatic]p2:
+ // [...] if name lookup (3.4.1) resolves the name in the
+ // id-expression to a nonstatic nontype member of class X or of
+ // a base class of X, the id-expression is transformed into a
+ // class member access expression (5.2.5) using (*this) (9.3.2)
+ // as the postfix-expression to the left of the '.' operator.
+ DeclContext *Ctx = 0;
+ QualType MemberType;
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+ Ctx = FD->getDeclContext();
+ MemberType = FD->getType();
+
+ if (const ReferenceType *RefType = MemberType->getAsReferenceType())
+ MemberType = RefType->getPointeeType();
+ else if (!FD->isMutable()) {
+ unsigned combinedQualifiers
+ = MemberType.getCVRQualifiers() | MD->getTypeQualifiers();
+ MemberType = MemberType.getQualifiedType(combinedQualifiers);
+ }
+ } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
+ if (!Method->isStatic()) {
+ Ctx = Method->getParent();
+ MemberType = Method->getType();
+ }
+ } else if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(D)) {
+ for (OverloadedFunctionDecl::function_iterator
+ Func = Ovl->function_begin(),
+ FuncEnd = Ovl->function_end();
+ Func != FuncEnd; ++Func) {
+ if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(*Func))
+ if (!DMethod->isStatic()) {
+ Ctx = Ovl->getDeclContext();
+ MemberType = Context.OverloadTy;
+ break;
+ }
+ }
+ }
+
+ if (Ctx && Ctx->isRecord()) {
+ QualType CtxType = Context.getTagDeclType(cast<CXXRecordDecl>(Ctx));
+ QualType ThisType = Context.getTagDeclType(MD->getParent());
+ if ((Context.getCanonicalType(CtxType)
+ == Context.getCanonicalType(ThisType)) ||
+ IsDerivedFrom(ThisType, CtxType)) {
+ // Build the implicit member access expression.
+ Expr *This = new (Context) CXXThisExpr(SourceLocation(),
+ MD->getThisType(Context));
+ return Owned(new (Context) MemberExpr(This, true, D,
+ Loc, MemberType));
+ }
+ }
+ }
+ }
+
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
+ if (MD->isStatic())
+ // "invalid use of member 'x' in static member function"
+ return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method)
+ << FD->getDeclName());
+ }
+
+ // Any other ways we could have found the field in a well-formed
+ // program would have been turned into implicit member expressions
+ // above.
+ return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use)
+ << FD->getDeclName());
+ }
+
+ if (isa<TypedefDecl>(D))
+ return ExprError(Diag(Loc, diag::err_unexpected_typedef) << Name);
+ if (isa<ObjCInterfaceDecl>(D))
+ return ExprError(Diag(Loc, diag::err_unexpected_interface) << Name);
+ if (isa<NamespaceDecl>(D))
+ return ExprError(Diag(Loc, diag::err_unexpected_namespace) << Name);
+
+ // Make the DeclRefExpr or BlockDeclRefExpr for the decl.
+ if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D))
+ return Owned(BuildDeclRefExpr(Ovl, Context.OverloadTy, Loc,
+ false, false, SS));
+ else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
+ return Owned(BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
+ false, false, SS));
+ ValueDecl *VD = cast<ValueDecl>(D);
+
+ // Check whether this declaration can be used. Note that we suppress
+ // this check when we're going to perform argument-dependent lookup
+ // on this function name, because this might not be the function
+ // that overload resolution actually selects.
+ if (!(ADL && isa<FunctionDecl>(VD)) && DiagnoseUseOfDecl(VD, Loc))
+ return ExprError();
+
+ if (VarDecl *Var = dyn_cast<VarDecl>(VD)) {
+ // Warn about constructs like:
+ // if (void *X = foo()) { ... } else { X }.
+ // In the else block, the pointer is always false.
+
+ // FIXME: In a template instantiation, we don't have scope
+ // information to check this property.
+ if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) {
+ Scope *CheckS = S;
+ while (CheckS) {
+ if (CheckS->isWithinElse() &&
+ CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) {
+ if (Var->getType()->isBooleanType())
+ ExprError(Diag(Loc, diag::warn_value_always_false)
+ << Var->getDeclName());
+ else
+ ExprError(Diag(Loc, diag::warn_value_always_zero)
+ << Var->getDeclName());
+ break;
+ }
+
+ // Move up one more control parent to check again.
+ CheckS = CheckS->getControlParent();
+ if (CheckS)
+ CheckS = CheckS->getParent();
+ }
+ }
+ } else if (FunctionDecl *Func = dyn_cast<FunctionDecl>(VD)) {
+ if (!getLangOptions().CPlusPlus && !Func->hasPrototype()) {
+ // C99 DR 316 says that, if a function type comes from a
+ // function definition (without a prototype), that type is only
+ // used for checking compatibility. Therefore, when referencing
+ // the function, we pretend that we don't have the full function
+ // type.
+ QualType T = Func->getType();
+ QualType NoProtoType = T;
+ if (const FunctionProtoType *Proto = T->getAsFunctionProtoType())
+ NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType());
+ return Owned(BuildDeclRefExpr(VD, NoProtoType, Loc, false, false, SS));
+ }
+ }
+
+ // Only create DeclRefExpr's for valid Decl's.
+ if (VD->isInvalidDecl())
+ return ExprError();
+
+ // If the identifier reference is inside a block, and it refers to a value
+ // that is outside the block, create a BlockDeclRefExpr instead of a
+ // DeclRefExpr. This ensures the value is treated as a copy-in snapshot when
+ // the block is formed.
+ //
+ // We do not do this for things like enum constants, global variables, etc,
+ // as they do not get snapshotted.
+ //
+ if (CurBlock && ShouldSnapshotBlockValueReference(CurBlock, VD)) {
+ QualType ExprTy = VD->getType().getNonReferenceType();
+ // The BlocksAttr indicates the variable is bound by-reference.
+ if (VD->getAttr<BlocksAttr>())
+ return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, true));
+
+ // Variable will be bound by-copy, make it const within the closure.
+ ExprTy.addConst();
+ return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, false));
+ }
+ // If this reference is not in a block or if the referenced variable is
+ // within the block, create a normal DeclRefExpr.
+
+ bool TypeDependent = false;
+ bool ValueDependent = false;
+ if (getLangOptions().CPlusPlus) {
+ // C++ [temp.dep.expr]p3:
+ // An id-expression is type-dependent if it contains:
+ // - an identifier that was declared with a dependent type,
+ if (VD->getType()->isDependentType())
+ TypeDependent = true;
+ // - FIXME: a template-id that is dependent,
+ // - a conversion-function-id that specifies a dependent type,
+ else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
+ Name.getCXXNameType()->isDependentType())
+ TypeDependent = true;
+ // - a nested-name-specifier that contains a class-name that
+ // names a dependent type.
+ else if (SS && !SS->isEmpty()) {
+ for (DeclContext *DC = computeDeclContext(*SS);
+ DC; DC = DC->getParent()) {
+ // FIXME: could stop early at namespace scope.
+ if (DC->isRecord()) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+ if (Context.getTypeDeclType(Record)->isDependentType()) {
+ TypeDependent = true;
+ break;
+ }
+ }
+ }
+ }
+
+ // C++ [temp.dep.constexpr]p2:
+ //
+ // An identifier is value-dependent if it is:
+ // - a name declared with a dependent type,
+ if (TypeDependent)
+ ValueDependent = true;
+ // - the name of a non-type template parameter,
+ else if (isa<NonTypeTemplateParmDecl>(VD))
+ ValueDependent = true;
+ // - a constant with integral or enumeration type and is
+ // initialized with an expression that is value-dependent
+ // (FIXME!).
+ }
+
+ return Owned(BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc,
+ TypeDependent, ValueDependent, SS));
+}
+
+Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
+ tok::TokenKind Kind) {
+ PredefinedExpr::IdentType IT;
+
+ switch (Kind) {
+ default: assert(0 && "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;
+ }
+
+ // Pre-defined identifiers are of type char[x], where x is the length of the
+ // string.
+ unsigned Length;
+ if (FunctionDecl *FD = getCurFunctionDecl())
+ Length = FD->getIdentifier()->getLength();
+ else if (ObjCMethodDecl *MD = getCurMethodDecl())
+ Length = MD->getSynthesizedMethodSize();
+ else {
+ Diag(Loc, diag::ext_predef_outside_function);
+ // __PRETTY_FUNCTION__ -> "top level", the others produce an empty string.
+ Length = IT == PredefinedExpr::PrettyFunction ? strlen("top level") : 0;
+ }
+
+
+ llvm::APInt LengthI(32, Length + 1);
+ QualType ResTy = Context.CharTy.getQualifiedType(QualType::Const);
+ ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
+ return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT));
+}
+
+Sema::OwningExprResult Sema::ActOnCharacterConstant(const Token &Tok) {
+ llvm::SmallString<16> CharBuffer;
+ CharBuffer.resize(Tok.getLength());
+ const char *ThisTokBegin = &CharBuffer[0];
+ unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin);
+
+ CharLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
+ Tok.getLocation(), PP);
+ if (Literal.hadError())
+ return ExprError();
+
+ QualType type = getLangOptions().CPlusPlus ? Context.CharTy : Context.IntTy;
+
+ return Owned(new (Context) CharacterLiteral(Literal.getValue(),
+ Literal.isWide(),
+ type, Tok.getLocation()));
+}
+
+Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) {
+ // Fast path for a single digit (which is quite common). A single digit
+ // 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();
+ return Owned(new (Context) IntegerLiteral(llvm::APInt(IntSize, Val-'0'),
+ Context.IntTy, Tok.getLocation()));
+ }
+
+ llvm::SmallString<512> IntegerBuffer;
+ // Add padding so that NumericLiteralParser can overread by one character.
+ IntegerBuffer.resize(Tok.getLength()+1);
+ const char *ThisTokBegin = &IntegerBuffer[0];
+
+ // Get the spelling of the token, which eliminates trigraphs, etc.
+ unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin);
+
+ NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
+ Tok.getLocation(), PP);
+ if (Literal.hadError)
+ return ExprError();
+
+ Expr *Res;
+
+ if (Literal.isFloatingLiteral()) {
+ QualType Ty;
+ if (Literal.isFloat)
+ Ty = Context.FloatTy;
+ else if (!Literal.isLong)
+ Ty = Context.DoubleTy;
+ else
+ Ty = Context.LongDoubleTy;
+
+ const llvm::fltSemantics &Format = Context.getFloatTypeSemantics(Ty);
+
+ // isExact will be set by GetFloatValue().
+ bool isExact = false;
+ Res = new (Context) FloatingLiteral(Literal.GetFloatValue(Format, &isExact),
+ &isExact, Ty, Tok.getLocation());
+
+ } else if (!Literal.isIntegerLiteral()) {
+ return ExprError();
+ } else {
+ QualType Ty;
+
+ // long long is a C99 feature.
+ if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x &&
+ Literal.isLongLong)
+ Diag(Tok.getLocation(), diag::ext_longlong);
+
+ // Get the value in the widest-possible width.
+ llvm::APInt ResultVal(Context.Target.getIntMaxTWidth(), 0);
+
+ if (Literal.GetIntegerValue(ResultVal)) {
+ // If this value didn't fit into uintmax_t, warn and force to ull.
+ Diag(Tok.getLocation(), diag::warn_integer_too_large);
+ Ty = Context.UnsignedLongLongTy;
+ assert(Context.getTypeSize(Ty) == ResultVal.getBitWidth() &&
+ "long long is not intmax_t?");
+ } else {
+ // If this value fits into a ULL, try to figure out what else it fits into
+ // according to the rules of C99 6.4.4.1p5.
+
+ // Octal, Hexadecimal, and integers with a U suffix are allowed to
+ // be an unsigned int.
+ bool AllowUnsigned = Literal.isUnsigned || Literal.getRadix() != 10;
+
+ // Check from smallest to largest, picking the smallest type we can.
+ unsigned Width = 0;
+ if (!Literal.isLong && !Literal.isLongLong) {
+ // Are int/unsigned possibilities?
+ unsigned IntSize = Context.Target.getIntWidth();
+
+ // Does it fit in a unsigned int?
+ if (ResultVal.isIntN(IntSize)) {
+ // Does it fit in a signed int?
+ if (!Literal.isUnsigned && ResultVal[IntSize-1] == 0)
+ Ty = Context.IntTy;
+ else if (AllowUnsigned)
+ Ty = Context.UnsignedIntTy;
+ Width = IntSize;
+ }
+ }
+
+ // Are long/unsigned long possibilities?
+ if (Ty.isNull() && !Literal.isLongLong) {
+ unsigned LongSize = Context.Target.getLongWidth();
+
+ // Does it fit in a unsigned long?
+ if (ResultVal.isIntN(LongSize)) {
+ // Does it fit in a signed long?
+ if (!Literal.isUnsigned && ResultVal[LongSize-1] == 0)
+ Ty = Context.LongTy;
+ else if (AllowUnsigned)
+ Ty = Context.UnsignedLongTy;
+ Width = LongSize;
+ }
+ }
+
+ // Finally, check long long if needed.
+ if (Ty.isNull()) {
+ unsigned LongLongSize = Context.Target.getLongLongWidth();
+
+ // Does it fit in a unsigned long long?
+ if (ResultVal.isIntN(LongLongSize)) {
+ // Does it fit in a signed long long?
+ if (!Literal.isUnsigned && ResultVal[LongLongSize-1] == 0)
+ Ty = Context.LongLongTy;
+ else if (AllowUnsigned)
+ Ty = Context.UnsignedLongLongTy;
+ Width = LongLongSize;
+ }
+ }
+
+ // If we still couldn't decide a type, we probably have something that
+ // does not fit in a signed long long, but has no U suffix.
+ if (Ty.isNull()) {
+ Diag(Tok.getLocation(), diag::warn_integer_too_large_for_signed);
+ Ty = Context.UnsignedLongLongTy;
+ Width = Context.Target.getLongLongWidth();
+ }
+
+ if (ResultVal.getBitWidth() != Width)
+ ResultVal.trunc(Width);
+ }
+ Res = new (Context) IntegerLiteral(ResultVal, Ty, Tok.getLocation());
+ }
+
+ // If this is an imaginary literal, create the ImaginaryLiteral wrapper.
+ if (Literal.isImaginary)
+ Res = new (Context) ImaginaryLiteral(Res,
+ Context.getComplexType(Res->getType()));
+
+ return Owned(Res);
+}
+
+Action::OwningExprResult Sema::ActOnParenExpr(SourceLocation L,
+ SourceLocation R, ExprArg Val) {
+ Expr *E = Val.takeAs<Expr>();
+ assert((E != 0) && "ActOnParenExpr() missing expr");
+ return Owned(new (Context) ParenExpr(L, R, E));
+}
+
+/// The UsualUnaryConversions() function is *not* called by this routine.
+/// See C99 6.3.2.1p[2-4] for more details.
+bool Sema::CheckSizeOfAlignOfOperand(QualType exprType,
+ SourceLocation OpLoc,
+ const SourceRange &ExprRange,
+ bool isSizeof) {
+ if (exprType->isDependentType())
+ return false;
+
+ // C99 6.5.3.4p1:
+ if (isa<FunctionType>(exprType)) {
+ // alignof(function) is allowed as an extension.
+ if (isSizeof)
+ Diag(OpLoc, diag::ext_sizeof_function_type) << ExprRange;
+ return false;
+ }
+
+ // Allow sizeof(void)/alignof(void) as an extension.
+ if (exprType->isVoidType()) {
+ Diag(OpLoc, diag::ext_sizeof_void_type)
+ << (isSizeof ? "sizeof" : "__alignof") << ExprRange;
+ return false;
+ }
+
+ if (RequireCompleteType(OpLoc, exprType,
+ isSizeof ? diag::err_sizeof_incomplete_type :
+ diag::err_alignof_incomplete_type,
+ ExprRange))
+ return true;
+
+ // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
+ if (LangOpts.ObjCNonFragileABI && exprType->isObjCInterfaceType()) {
+ Diag(OpLoc, diag::err_sizeof_nonfragile_interface)
+ << exprType << isSizeof << ExprRange;
+ return true;
+ }
+
+ return false;
+}
+
+bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc,
+ const SourceRange &ExprRange) {
+ E = E->IgnoreParens();
+
+ // alignof decl is always ok.
+ if (isa<DeclRefExpr>(E))
+ return false;
+
+ // Cannot know anything else if the expression is dependent.
+ if (E->isTypeDependent())
+ return false;
+
+ if (E->getBitField()) {
+ Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 1 << ExprRange;
+ return true;
+ }
+
+ // Alignment of a field access is always okay, so long as it isn't a
+ // bit-field.
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
+ if (dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ return false;
+
+ return CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false);
+}
+
+/// \brief Build a sizeof or alignof expression given a type operand.
+Action::OwningExprResult
+Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
+ bool isSizeOf, SourceRange R) {
+ if (T.isNull())
+ return ExprError();
+
+ if (!T->isDependentType() &&
+ CheckSizeOfAlignOfOperand(T, OpLoc, R, isSizeOf))
+ return ExprError();
+
+ // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
+ return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, T,
+ Context.getSizeType(), OpLoc,
+ R.getEnd()));
+}
+
+/// \brief Build a sizeof or alignof expression given an expression
+/// operand.
+Action::OwningExprResult
+Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
+ bool isSizeOf, SourceRange R) {
+ // Verify that the operand is valid.
+ bool isInvalid = false;
+ if (E->isTypeDependent()) {
+ // Delay type-checking for type-dependent expressions.
+ } else if (!isSizeOf) {
+ isInvalid = CheckAlignOfExpr(E, OpLoc, R);
+ } else if (E->getBitField()) { // C99 6.5.3.4p1.
+ Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0;
+ isInvalid = true;
+ } else {
+ isInvalid = CheckSizeOfAlignOfOperand(E->getType(), OpLoc, R, true);
+ }
+
+ if (isInvalid)
+ return ExprError();
+
+ // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
+ return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, E,
+ Context.getSizeType(), OpLoc,
+ R.getEnd()));
+}
+
+/// ActOnSizeOfAlignOfExpr - Handle @c sizeof(type) and @c sizeof @c expr and
+/// the same for @c alignof and @c __alignof
+/// Note that the ArgRange is invalid if isType is false.
+Action::OwningExprResult
+Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
+ void *TyOrEx, const SourceRange &ArgRange) {
+ // If error parsing type, ignore.
+ if (TyOrEx == 0) return ExprError();
+
+ if (isType) {
+ QualType ArgTy = QualType::getFromOpaquePtr(TyOrEx);
+ return CreateSizeOfAlignOfExpr(ArgTy, OpLoc, isSizeof, ArgRange);
+ }
+
+ // Get the end location.
+ Expr *ArgEx = (Expr *)TyOrEx;
+ Action::OwningExprResult Result
+ = CreateSizeOfAlignOfExpr(ArgEx, OpLoc, isSizeof, ArgEx->getSourceRange());
+
+ if (Result.isInvalid())
+ DeleteExpr(ArgEx);
+
+ return move(Result);
+}
+
+QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) {
+ if (V->isTypeDependent())
+ return Context.DependentTy;
+
+ // These operators return the element type of a complex type.
+ if (const ComplexType *CT = V->getType()->getAsComplexType())
+ return CT->getElementType();
+
+ // Otherwise they pass through real integer and floating point types here.
+ if (V->getType()->isArithmeticType())
+ return V->getType();
+
+ // Reject anything else.
+ Diag(Loc, diag::err_realimag_invalid_type) << V->getType()
+ << (isReal ? "__real" : "__imag");
+ return QualType();
+}
+
+
+
+Action::OwningExprResult
+Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
+ tok::TokenKind Kind, ExprArg Input) {
+ Expr *Arg = (Expr *)Input.get();
+
+ UnaryOperator::Opcode Opc;
+ switch (Kind) {
+ default: assert(0 && "Unknown unary op!");
+ case tok::plusplus: Opc = UnaryOperator::PostInc; break;
+ case tok::minusminus: Opc = UnaryOperator::PostDec; break;
+ }
+
+ if (getLangOptions().CPlusPlus &&
+ (Arg->getType()->isRecordType() || Arg->getType()->isEnumeralType())) {
+ // Which overloaded operator?
+ OverloadedOperatorKind OverOp =
+ (Opc == UnaryOperator::PostInc)? OO_PlusPlus : OO_MinusMinus;
+
+ // C++ [over.inc]p1:
+ //
+ // [...] If the function is a member function with one
+ // parameter (which shall be of type int) or a non-member
+ // function with two parameters (the second of which shall be
+ // of type int), it defines the postfix increment operator ++
+ // for objects of that type. When the postfix increment is
+ // called as a result of using the ++ operator, the int
+ // argument will have value zero.
+ Expr *Args[2] = {
+ Arg,
+ new (Context) IntegerLiteral(llvm::APInt(Context.Target.getIntWidth(), 0,
+ /*isSigned=*/true), Context.IntTy, SourceLocation())
+ };
+
+ // Build the candidate set for overloading
+ OverloadCandidateSet CandidateSet;
+ AddOperatorCandidates(OverOp, S, OpLoc, Args, 2, CandidateSet);
+
+ // Perform overload resolution.
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(CandidateSet, Best)) {
+ case OR_Success: {
+ // We found a built-in operator or an overloaded operator.
+ FunctionDecl *FnDecl = Best->Function;
+
+ if (FnDecl) {
+ // We matched an overloaded operator. Build a call to that
+ // operator.
+
+ // Convert the arguments.
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
+ if (PerformObjectArgumentInitialization(Arg, Method))
+ return ExprError();
+ } else {
+ // Convert the arguments.
+ if (PerformCopyInitialization(Arg,
+ FnDecl->getParamDecl(0)->getType(),
+ "passing"))
+ return ExprError();
+ }
+
+ // Determine the result type
+ QualType ResultTy
+ = FnDecl->getType()->getAsFunctionType()->getResultType();
+ ResultTy = ResultTy.getNonReferenceType();
+
+ // Build the actual expression node.
+ Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
+ SourceLocation());
+ UsualUnaryConversions(FnExpr);
+
+ Input.release();
+ Args[0] = Arg;
+ return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, FnExpr,
+ Args, 2, ResultTy,
+ OpLoc));
+ } else {
+ // We matched a built-in operator. Convert the arguments, then
+ // break out so that we will build the appropriate built-in
+ // operator node.
+ if (PerformCopyInitialization(Arg, Best->BuiltinTypes.ParamTypes[0],
+ "passing"))
+ return ExprError();
+
+ break;
+ }
+ }
+
+ case OR_No_Viable_Function:
+ // No viable function; fall through to handling this as a
+ // built-in operator, which will produce an error message for us.
+ break;
+
+ case OR_Ambiguous:
+ Diag(OpLoc, diag::err_ovl_ambiguous_oper)
+ << UnaryOperator::getOpcodeStr(Opc)
+ << Arg->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ return ExprError();
+
+ case OR_Deleted:
+ Diag(OpLoc, diag::err_ovl_deleted_oper)
+ << Best->Function->isDeleted()
+ << UnaryOperator::getOpcodeStr(Opc)
+ << Arg->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ return ExprError();
+ }
+
+ // Either we found no viable overloaded operator or we matched a
+ // built-in operator. In either case, fall through to trying to
+ // build a built-in operation.
+ }
+
+ QualType result = CheckIncrementDecrementOperand(Arg, OpLoc,
+ Opc == UnaryOperator::PostInc);
+ if (result.isNull())
+ return ExprError();
+ Input.release();
+ return Owned(new (Context) UnaryOperator(Arg, Opc, result, OpLoc));
+}
+
+Action::OwningExprResult
+Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
+ ExprArg Idx, SourceLocation RLoc) {
+ Expr *LHSExp = static_cast<Expr*>(Base.get()),
+ *RHSExp = static_cast<Expr*>(Idx.get());
+
+ if (getLangOptions().CPlusPlus &&
+ (LHSExp->isTypeDependent() || RHSExp->isTypeDependent())) {
+ Base.release();
+ Idx.release();
+ return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
+ Context.DependentTy, RLoc));
+ }
+
+ if (getLangOptions().CPlusPlus &&
+ (LHSExp->getType()->isRecordType() ||
+ LHSExp->getType()->isEnumeralType() ||
+ RHSExp->getType()->isRecordType() ||
+ RHSExp->getType()->isEnumeralType())) {
+ // Add the appropriate overloaded operators (C++ [over.match.oper])
+ // to the candidate set.
+ OverloadCandidateSet CandidateSet;
+ Expr *Args[2] = { LHSExp, RHSExp };
+ AddOperatorCandidates(OO_Subscript, S, LLoc, Args, 2, CandidateSet,
+ SourceRange(LLoc, RLoc));
+
+ // Perform overload resolution.
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(CandidateSet, Best)) {
+ case OR_Success: {
+ // We found a built-in operator or an overloaded operator.
+ FunctionDecl *FnDecl = Best->Function;
+
+ if (FnDecl) {
+ // We matched an overloaded operator. Build a call to that
+ // operator.
+
+ // Convert the arguments.
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
+ if (PerformObjectArgumentInitialization(LHSExp, Method) ||
+ PerformCopyInitialization(RHSExp,
+ FnDecl->getParamDecl(0)->getType(),
+ "passing"))
+ return ExprError();
+ } else {
+ // Convert the arguments.
+ if (PerformCopyInitialization(LHSExp,
+ FnDecl->getParamDecl(0)->getType(),
+ "passing") ||
+ PerformCopyInitialization(RHSExp,
+ FnDecl->getParamDecl(1)->getType(),
+ "passing"))
+ return ExprError();
+ }
+
+ // Determine the result type
+ QualType ResultTy
+ = FnDecl->getType()->getAsFunctionType()->getResultType();
+ ResultTy = ResultTy.getNonReferenceType();
+
+ // Build the actual expression node.
+ Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
+ SourceLocation());
+ UsualUnaryConversions(FnExpr);
+
+ Base.release();
+ Idx.release();
+ Args[0] = LHSExp;
+ Args[1] = RHSExp;
+ return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
+ FnExpr, Args, 2,
+ ResultTy, LLoc));
+ } else {
+ // We matched a built-in operator. Convert the arguments, then
+ // break out so that we will build the appropriate built-in
+ // operator node.
+ if (PerformCopyInitialization(LHSExp, Best->BuiltinTypes.ParamTypes[0],
+ "passing") ||
+ PerformCopyInitialization(RHSExp, Best->BuiltinTypes.ParamTypes[1],
+ "passing"))
+ return ExprError();
+
+ break;
+ }
+ }
+
+ case OR_No_Viable_Function:
+ // No viable function; fall through to handling this as a
+ // built-in operator, which will produce an error message for us.
+ break;
+
+ case OR_Ambiguous:
+ Diag(LLoc, diag::err_ovl_ambiguous_oper)
+ << "[]"
+ << LHSExp->getSourceRange() << RHSExp->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ return ExprError();
+
+ case OR_Deleted:
+ Diag(LLoc, diag::err_ovl_deleted_oper)
+ << Best->Function->isDeleted()
+ << "[]"
+ << LHSExp->getSourceRange() << RHSExp->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ return ExprError();
+ }
+
+ // Either we found no viable overloaded operator or we matched a
+ // built-in operator. In either case, fall through to trying to
+ // build a built-in operation.
+ }
+
+ // Perform default conversions.
+ DefaultFunctionArrayConversion(LHSExp);
+ DefaultFunctionArrayConversion(RHSExp);
+
+ QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType();
+
+ // C99 6.5.2.1p2: the expression e1[e2] is by definition precisely equivalent
+ // to the expression *((e1)+(e2)). This means the array "Base" may actually be
+ // in the subscript position. As a result, we need to derive the array base
+ // and index from the expression types.
+ Expr *BaseExpr, *IndexExpr;
+ QualType ResultType;
+ if (LHSTy->isDependentType() || RHSTy->isDependentType()) {
+ BaseExpr = LHSExp;
+ IndexExpr = RHSExp;
+ ResultType = Context.DependentTy;
+ } else if (const PointerType *PTy = LHSTy->getAsPointerType()) {
+ BaseExpr = LHSExp;
+ IndexExpr = RHSExp;
+ ResultType = PTy->getPointeeType();
+ } else if (const PointerType *PTy = RHSTy->getAsPointerType()) {
+ // Handle the uncommon case of "123[Ptr]".
+ BaseExpr = RHSExp;
+ IndexExpr = LHSExp;
+ ResultType = PTy->getPointeeType();
+ } else if (const VectorType *VTy = LHSTy->getAsVectorType()) {
+ BaseExpr = LHSExp; // vectors: V[123]
+ IndexExpr = RHSExp;
+
+ // FIXME: need to deal with const...
+ ResultType = VTy->getElementType();
+ } else if (LHSTy->isArrayType()) {
+ // If we see an array that wasn't promoted by
+ // DefaultFunctionArrayConversion, it must be an array that
+ // wasn't promoted because of the C90 rule that doesn't
+ // allow promoting non-lvalue arrays. Warn, then
+ // force the promotion here.
+ Diag(LHSExp->getLocStart(), diag::ext_subscript_non_lvalue) <<
+ LHSExp->getSourceRange();
+ ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy));
+ LHSTy = LHSExp->getType();
+
+ BaseExpr = LHSExp;
+ IndexExpr = RHSExp;
+ ResultType = LHSTy->getAsPointerType()->getPointeeType();
+ } else if (RHSTy->isArrayType()) {
+ // Same as previous, except for 123[f().a] case
+ Diag(RHSExp->getLocStart(), diag::ext_subscript_non_lvalue) <<
+ RHSExp->getSourceRange();
+ ImpCastExprToType(RHSExp, Context.getArrayDecayedType(RHSTy));
+ RHSTy = RHSExp->getType();
+
+ BaseExpr = RHSExp;
+ IndexExpr = LHSExp;
+ ResultType = RHSTy->getAsPointerType()->getPointeeType();
+ } else {
+ return ExprError(Diag(LLoc, diag::err_typecheck_subscript_value)
+ << LHSExp->getSourceRange() << RHSExp->getSourceRange());
+ }
+ // C99 6.5.2.1p1
+ if (!IndexExpr->getType()->isIntegerType() && !IndexExpr->isTypeDependent())
+ return ExprError(Diag(LLoc, diag::err_typecheck_subscript_not_integer)
+ << IndexExpr->getSourceRange());
+
+ // C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly,
+ // C++ [expr.sub]p1: The type "T" shall be a completely-defined object
+ // type. Note that Functions are not objects, and that (in C99 parlance)
+ // incomplete types are not object types.
+ if (ResultType->isFunctionType()) {
+ Diag(BaseExpr->getLocStart(), diag::err_subscript_function_type)
+ << ResultType << BaseExpr->getSourceRange();
+ return ExprError();
+ }
+
+ if (!ResultType->isDependentType() &&
+ RequireCompleteType(LLoc, ResultType, diag::err_subscript_incomplete_type,
+ BaseExpr->getSourceRange()))
+ return ExprError();
+
+ // Diagnose bad cases where we step over interface counts.
+ if (ResultType->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
+ Diag(LLoc, diag::err_subscript_nonfragile_interface)
+ << ResultType << BaseExpr->getSourceRange();
+ return ExprError();
+ }
+
+ Base.release();
+ Idx.release();
+ return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
+ ResultType, RLoc));
+}
+
+QualType Sema::
+CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
+ IdentifierInfo &CompName, SourceLocation CompLoc) {
+ const ExtVectorType *vecType = baseType->getAsExtVectorType();
+
+ // The vector accessor can't exceed the number of elements.
+ const char *compStr = CompName.getName();
+
+ // This flag determines whether or not the component is one of the four
+ // special names that indicate a subset of exactly half the elements are
+ // to be selected.
+ bool HalvingSwizzle = false;
+
+ // This flag determines whether or not CompName has an 's' char prefix,
+ // indicating that it is a string of hex values to be used as vector indices.
+ bool HexSwizzle = *compStr == 's';
+
+ // Check that we've found one of the special components, or that the component
+ // names must come from the same set.
+ if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") ||
+ !strcmp(compStr, "even") || !strcmp(compStr, "odd")) {
+ HalvingSwizzle = true;
+ } else if (vecType->getPointAccessorIdx(*compStr) != -1) {
+ do
+ compStr++;
+ while (*compStr && vecType->getPointAccessorIdx(*compStr) != -1);
+ } else if (HexSwizzle || vecType->getNumericAccessorIdx(*compStr) != -1) {
+ do
+ compStr++;
+ while (*compStr && vecType->getNumericAccessorIdx(*compStr) != -1);
+ }
+
+ if (!HalvingSwizzle && *compStr) {
+ // 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.
+ Diag(OpLoc, diag::err_ext_vector_component_name_illegal)
+ << std::string(compStr,compStr+1) << SourceRange(CompLoc);
+ return QualType();
+ }
+
+ // Ensure no component accessor exceeds the width of the vector type it
+ // operates on.
+ if (!HalvingSwizzle) {
+ compStr = CompName.getName();
+
+ if (HexSwizzle)
+ compStr++;
+
+ while (*compStr) {
+ if (!vecType->isAccessorWithinNumElements(*compStr++)) {
+ Diag(OpLoc, diag::err_ext_vector_component_exceeds_length)
+ << baseType << SourceRange(CompLoc);
+ return QualType();
+ }
+ }
+ }
+
+ // If this is a halving swizzle, verify that the base type has an even
+ // number of elements.
+ if (HalvingSwizzle && (vecType->getNumElements() & 1U)) {
+ Diag(OpLoc, diag::err_ext_vector_component_requires_even)
+ << baseType << SourceRange(CompLoc);
+ return QualType();
+ }
+
+ // The component accessor looks fine - now we need to compute the actual type.
+ // The vector type is implied by the component accessor. For example,
+ // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc.
+ // vec4.s0 is a float, vec4.s23 is a vec3, etc.
+ // vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2.
+ unsigned CompSize = HalvingSwizzle ? vecType->getNumElements() / 2
+ : CompName.getLength();
+ if (HexSwizzle)
+ CompSize--;
+
+ if (CompSize == 1)
+ return vecType->getElementType();
+
+ QualType VT = 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 = ExtVectorDecls.size(); i != E; ++i) {
+ if (ExtVectorDecls[i]->getUnderlyingType() == VT)
+ return Context.getTypedefType(ExtVectorDecls[i]);
+ }
+ return VT; // should never get here (a typedef type should always be found).
+}
+
+static Decl *FindGetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
+ IdentifierInfo &Member,
+ const Selector &Sel,
+ ASTContext &Context) {
+
+ if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Context, &Member))
+ return PD;
+ if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Context, Sel))
+ return OMD;
+
+ for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); I != E; ++I) {
+ if (Decl *D = FindGetterNameDeclFromProtocolList(*I, Member, Sel,
+ Context))
+ return D;
+ }
+ return 0;
+}
+
+static Decl *FindGetterNameDecl(const ObjCQualifiedIdType *QIdTy,
+ IdentifierInfo &Member,
+ const Selector &Sel,
+ ASTContext &Context) {
+ // Check protocols on qualified interfaces.
+ Decl *GDecl = 0;
+ for (ObjCQualifiedIdType::qual_iterator I = QIdTy->qual_begin(),
+ E = QIdTy->qual_end(); I != E; ++I) {
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Context, &Member)) {
+ GDecl = PD;
+ break;
+ }
+ // Also must look for a getter name which uses property syntax.
+ if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Context, Sel)) {
+ GDecl = OMD;
+ break;
+ }
+ }
+ if (!GDecl) {
+ for (ObjCQualifiedIdType::qual_iterator I = QIdTy->qual_begin(),
+ E = QIdTy->qual_end(); I != E; ++I) {
+ // Search in the protocol-qualifier list of current protocol.
+ GDecl = FindGetterNameDeclFromProtocolList(*I, Member, Sel, Context);
+ if (GDecl)
+ return GDecl;
+ }
+ }
+ return GDecl;
+}
+
+/// FindMethodInNestedImplementations - Look up a method in current and
+/// all base class implementations.
+///
+ObjCMethodDecl *Sema::FindMethodInNestedImplementations(
+ const ObjCInterfaceDecl *IFace,
+ const Selector &Sel) {
+ ObjCMethodDecl *Method = 0;
+ if (ObjCImplementationDecl *ImpDecl
+ = LookupObjCImplementation(IFace->getIdentifier()))
+ Method = ImpDecl->getInstanceMethod(Context, Sel);
+
+ if (!Method && IFace->getSuperClass())
+ return FindMethodInNestedImplementations(IFace->getSuperClass(), Sel);
+ return Method;
+}
+
+Action::OwningExprResult
+Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
+ tok::TokenKind OpKind, SourceLocation MemberLoc,
+ IdentifierInfo &Member,
+ DeclPtrTy ObjCImpDecl) {
+ Expr *BaseExpr = Base.takeAs<Expr>();
+ assert(BaseExpr && "no record expression");
+
+ // Perform default conversions.
+ DefaultFunctionArrayConversion(BaseExpr);
+
+ QualType BaseType = BaseExpr->getType();
+ assert(!BaseType.isNull() && "no type for member expression");
+
+ // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
+ // must have pointer type, and the accessed type is the pointee.
+ if (OpKind == tok::arrow) {
+ if (BaseType->isDependentType())
+ return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
+ BaseExpr, true,
+ OpLoc,
+ DeclarationName(&Member),
+ MemberLoc));
+ else if (const PointerType *PT = BaseType->getAsPointerType())
+ BaseType = PT->getPointeeType();
+ else if (getLangOptions().CPlusPlus && BaseType->isRecordType())
+ return Owned(BuildOverloadedArrowExpr(S, BaseExpr, OpLoc,
+ MemberLoc, Member));
+ else
+ return ExprError(Diag(MemberLoc,
+ diag::err_typecheck_member_reference_arrow)
+ << BaseType << BaseExpr->getSourceRange());
+ } else {
+ if (BaseType->isDependentType()) {
+ // Require that the base type isn't a pointer type
+ // (so we'll report an error for)
+ // T* t;
+ // t.f;
+ //
+ // In Obj-C++, however, the above expression is valid, since it could be
+ // accessing the 'f' property if T is an Obj-C interface. The extra check
+ // allows this, while still reporting an error if T is a struct pointer.
+ const PointerType *PT = BaseType->getAsPointerType();
+
+ if (!PT || (getLangOptions().ObjC1 &&
+ !PT->getPointeeType()->isRecordType()))
+ return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
+ BaseExpr, false,
+ OpLoc,
+ DeclarationName(&Member),
+ MemberLoc));
+ }
+ }
+
+ // Handle field access to simple records. This also handles access to fields
+ // of the ObjC 'id' struct.
+ if (const RecordType *RTy = BaseType->getAsRecordType()) {
+ RecordDecl *RDecl = RTy->getDecl();
+ if (RequireCompleteType(OpLoc, BaseType,
+ diag::err_typecheck_incomplete_tag,
+ BaseExpr->getSourceRange()))
+ return ExprError();
+
+ // The record definition is complete, now make sure the member is valid.
+ // FIXME: Qualified name lookup for C++ is a bit more complicated than this.
+ LookupResult Result
+ = LookupQualifiedName(RDecl, DeclarationName(&Member),
+ LookupMemberName, false);
+
+ if (!Result)
+ return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member)
+ << &Member << BaseExpr->getSourceRange());
+ if (Result.isAmbiguous()) {
+ DiagnoseAmbiguousLookup(Result, DeclarationName(&Member),
+ MemberLoc, BaseExpr->getSourceRange());
+ return ExprError();
+ }
+
+ NamedDecl *MemberDecl = Result;
+
+ // If the decl being referenced had an error, return an error for this
+ // sub-expr without emitting another error, in order to avoid cascading
+ // error cases.
+ if (MemberDecl->isInvalidDecl())
+ return ExprError();
+
+ // Check the use of this field
+ if (DiagnoseUseOfDecl(MemberDecl, MemberLoc))
+ return ExprError();
+
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) {
+ // We may have found a field within an anonymous union or struct
+ // (C++ [class.union]).
+ if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion())
+ return BuildAnonymousStructUnionMemberReference(MemberLoc, FD,
+ BaseExpr, OpLoc);
+
+ // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
+ // FIXME: Handle address space modifiers
+ QualType MemberType = FD->getType();
+ if (const ReferenceType *Ref = MemberType->getAsReferenceType())
+ MemberType = Ref->getPointeeType();
+ else {
+ unsigned combinedQualifiers =
+ MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers();
+ if (FD->isMutable())
+ combinedQualifiers &= ~QualType::Const;
+ MemberType = MemberType.getQualifiedType(combinedQualifiers);
+ }
+
+ return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, FD,
+ MemberLoc, MemberType));
+ }
+
+ if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl))
+ return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
+ Var, MemberLoc,
+ Var->getType().getNonReferenceType()));
+ if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl))
+ return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
+ MemberFn, MemberLoc,
+ MemberFn->getType()));
+ if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(MemberDecl))
+ return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, Ovl,
+ MemberLoc, Context.OverloadTy));
+ if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl))
+ return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
+ Enum, MemberLoc, Enum->getType()));
+ if (isa<TypeDecl>(MemberDecl))
+ return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type)
+ << DeclarationName(&Member) << int(OpKind == tok::arrow));
+
+ // We found a declaration kind that we didn't expect. This is a
+ // generic error message that tells the user that she can't refer
+ // to this member with '.' or '->'.
+ return ExprError(Diag(MemberLoc,
+ diag::err_typecheck_member_reference_unknown)
+ << DeclarationName(&Member) << int(OpKind == tok::arrow));
+ }
+
+ // Handle access to Objective-C instance variables, such as "Obj->ivar" and
+ // (*Obj).ivar.
+ if (const ObjCInterfaceType *IFTy = BaseType->getAsObjCInterfaceType()) {
+ ObjCInterfaceDecl *ClassDeclared;
+ if (ObjCIvarDecl *IV = IFTy->getDecl()->lookupInstanceVariable(Context,
+ &Member,
+ ClassDeclared)) {
+ // If the decl being referenced had an error, return an error for this
+ // sub-expr without emitting another error, in order to avoid cascading
+ // error cases.
+ if (IV->isInvalidDecl())
+ return ExprError();
+
+ // Check whether we can reference this field.
+ if (DiagnoseUseOfDecl(IV, MemberLoc))
+ return ExprError();
+ if (IV->getAccessControl() != ObjCIvarDecl::Public &&
+ IV->getAccessControl() != ObjCIvarDecl::Package) {
+ ObjCInterfaceDecl *ClassOfMethodDecl = 0;
+ if (ObjCMethodDecl *MD = getCurMethodDecl())
+ ClassOfMethodDecl = MD->getClassInterface();
+ else if (ObjCImpDecl && getCurFunctionDecl()) {
+ // Case of a c-function declared inside an objc implementation.
+ // FIXME: For a c-style function nested inside an objc implementation
+ // class, there is no implementation context available, so we pass
+ // down the context as argument to this routine. Ideally, this context
+ // need be passed down in the AST node and somehow calculated from the
+ // AST for a function decl.
+ Decl *ImplDecl = ObjCImpDecl.getAs<Decl>();
+ if (ObjCImplementationDecl *IMPD =
+ dyn_cast<ObjCImplementationDecl>(ImplDecl))
+ ClassOfMethodDecl = IMPD->getClassInterface();
+ else if (ObjCCategoryImplDecl* CatImplClass =
+ dyn_cast<ObjCCategoryImplDecl>(ImplDecl))
+ ClassOfMethodDecl = CatImplClass->getClassInterface();
+ }
+
+ if (IV->getAccessControl() == ObjCIvarDecl::Private) {
+ if (ClassDeclared != IFTy->getDecl() ||
+ ClassOfMethodDecl != ClassDeclared)
+ Diag(MemberLoc, diag::error_private_ivar_access) << IV->getDeclName();
+ }
+ // @protected
+ else if (!IFTy->getDecl()->isSuperClassOf(ClassOfMethodDecl))
+ Diag(MemberLoc, diag::error_protected_ivar_access) << IV->getDeclName();
+ }
+
+ return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
+ MemberLoc, BaseExpr,
+ OpKind == tok::arrow));
+ }
+ return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
+ << IFTy->getDecl()->getDeclName() << &Member
+ << BaseExpr->getSourceRange());
+ }
+
+ // Handle Objective-C property access, which is "Obj.property" where Obj is a
+ // pointer to a (potentially qualified) interface type.
+ const PointerType *PTy;
+ const ObjCInterfaceType *IFTy;
+ if (OpKind == tok::period && (PTy = BaseType->getAsPointerType()) &&
+ (IFTy = PTy->getPointeeType()->getAsObjCInterfaceType())) {
+ ObjCInterfaceDecl *IFace = IFTy->getDecl();
+
+ // Search for a declared property first.
+ if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Context,
+ &Member)) {
+ // Check whether we can reference this property.
+ if (DiagnoseUseOfDecl(PD, MemberLoc))
+ return ExprError();
+ QualType ResTy = PD->getType();
+ Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
+ ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Context, Sel);
+ if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))
+ ResTy = Getter->getResultType();
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
+ MemberLoc, BaseExpr));
+ }
+
+ // Check protocols on qualified interfaces.
+ for (ObjCInterfaceType::qual_iterator I = IFTy->qual_begin(),
+ E = IFTy->qual_end(); I != E; ++I)
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Context,
+ &Member)) {
+ // Check whether we can reference this property.
+ if (DiagnoseUseOfDecl(PD, MemberLoc))
+ return ExprError();
+
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+ MemberLoc, BaseExpr));
+ }
+
+ // If that failed, look for an "implicit" property by seeing if the nullary
+ // selector is implemented.
+
+ // FIXME: The logic for looking up nullary and unary selectors should be
+ // shared with the code in ActOnInstanceMessage.
+
+ Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
+ ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Context, Sel);
+
+ // If this reference is in an @implementation, check for 'private' methods.
+ if (!Getter)
+ Getter = FindMethodInNestedImplementations(IFace, Sel);
+
+ // Look through local category implementations associated with the class.
+ if (!Getter) {
+ for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Getter; i++) {
+ if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
+ Getter = ObjCCategoryImpls[i]->getInstanceMethod(Context, Sel);
+ }
+ }
+ if (Getter) {
+ // Check if we can reference this property.
+ if (DiagnoseUseOfDecl(Getter, MemberLoc))
+ return ExprError();
+ }
+ // If we found a getter then this may be a valid dot-reference, we
+ // will look for the matching setter, in case it is needed.
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(), &Member);
+ ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(Context, SetterSel);
+ if (!Setter) {
+ // If this reference is in an @implementation, also check for 'private'
+ // methods.
+ Setter = FindMethodInNestedImplementations(IFace, SetterSel);
+ }
+ // Look through local category implementations associated with the class.
+ if (!Setter) {
+ for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) {
+ if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
+ Setter = ObjCCategoryImpls[i]->getInstanceMethod(Context, SetterSel);
+ }
+ }
+
+ if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
+ return ExprError();
+
+ if (Getter || Setter) {
+ QualType PType;
+
+ if (Getter)
+ PType = Getter->getResultType();
+ else {
+ for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
+ E = Setter->param_end(); PI != E; ++PI)
+ PType = (*PI)->getType();
+ }
+ // FIXME: we must check that the setter has property type.
+ return Owned(new (Context) ObjCKVCRefExpr(Getter, PType,
+ Setter, MemberLoc, BaseExpr));
+ }
+ return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+ << &Member << BaseType);
+ }
+ // Handle properties on qualified "id" protocols.
+ const ObjCQualifiedIdType *QIdTy;
+ if (OpKind == tok::period && (QIdTy = BaseType->getAsObjCQualifiedIdType())) {
+ // Check protocols on qualified interfaces.
+ Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
+ if (Decl *PMDecl = FindGetterNameDecl(QIdTy, Member, Sel, Context)) {
+ if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
+ // Check the use of this declaration
+ if (DiagnoseUseOfDecl(PD, MemberLoc))
+ return ExprError();
+
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+ MemberLoc, BaseExpr));
+ }
+ if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
+ // Check the use of this method.
+ if (DiagnoseUseOfDecl(OMD, MemberLoc))
+ return ExprError();
+
+ return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel,
+ OMD->getResultType(),
+ OMD, OpLoc, MemberLoc,
+ NULL, 0));
+ }
+ }
+
+ return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+ << &Member << BaseType);
+ }
+ // Handle properties on ObjC 'Class' types.
+ if (OpKind == tok::period && (BaseType == Context.getObjCClassType())) {
+ // Also must look for a getter name which uses property syntax.
+ Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
+ if (ObjCMethodDecl *MD = getCurMethodDecl()) {
+ ObjCInterfaceDecl *IFace = MD->getClassInterface();
+ ObjCMethodDecl *Getter;
+ // FIXME: need to also look locally in the implementation.
+ if ((Getter = IFace->lookupClassMethod(Context, Sel))) {
+ // Check the use of this method.
+ if (DiagnoseUseOfDecl(Getter, MemberLoc))
+ return ExprError();
+ }
+ // If we found a getter then this may be a valid dot-reference, we
+ // will look for the matching setter, in case it is needed.
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(), &Member);
+ ObjCMethodDecl *Setter = IFace->lookupClassMethod(Context, SetterSel);
+ if (!Setter) {
+ // If this reference is in an @implementation, also check for 'private'
+ // methods.
+ Setter = FindMethodInNestedImplementations(IFace, SetterSel);
+ }
+ // Look through local category implementations associated with the class.
+ if (!Setter) {
+ for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) {
+ if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
+ Setter = ObjCCategoryImpls[i]->getClassMethod(Context, SetterSel);
+ }
+ }
+
+ if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
+ return ExprError();
+
+ if (Getter || Setter) {
+ QualType PType;
+
+ if (Getter)
+ PType = Getter->getResultType();
+ else {
+ for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
+ E = Setter->param_end(); PI != E; ++PI)
+ PType = (*PI)->getType();
+ }
+ // FIXME: we must check that the setter has property type.
+ return Owned(new (Context) ObjCKVCRefExpr(Getter, PType,
+ Setter, MemberLoc, BaseExpr));
+ }
+ return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+ << &Member << BaseType);
+ }
+ }
+
+ // Handle 'field access' to vectors, such as 'V.xx'.
+ if (BaseType->isExtVectorType()) {
+ QualType ret = CheckExtVectorComponent(BaseType, OpLoc, Member, MemberLoc);
+ if (ret.isNull())
+ return ExprError();
+ return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, Member,
+ MemberLoc));
+ }
+
+ Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
+ << BaseType << BaseExpr->getSourceRange();
+
+ // If the user is trying to apply -> or . to a function or function
+ // pointer, it's probably because they forgot parentheses to call
+ // the function. Suggest the addition of those parentheses.
+ if (BaseType == Context.OverloadTy ||
+ BaseType->isFunctionType() ||
+ (BaseType->isPointerType() &&
+ BaseType->getAsPointerType()->isFunctionType())) {
+ SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd());
+ Diag(Loc, diag::note_member_reference_needs_call)
+ << CodeModificationHint::CreateInsertion(Loc, "()");
+ }
+
+ return ExprError();
+}
+
+/// ConvertArgumentsForCall - Converts the arguments specified in
+/// Args/NumArgs to the parameter types of the function FDecl with
+/// function prototype Proto. Call is the call expression itself, and
+/// Fn is the function expression. For a C++ member function, this
+/// routine does not attempt to convert the object argument. Returns
+/// true if the call is ill-formed.
+bool
+Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
+ FunctionDecl *FDecl,
+ const FunctionProtoType *Proto,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RParenLoc) {
+ // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by
+ // assignment, to the types of the corresponding parameter, ...
+ unsigned NumArgsInProto = Proto->getNumArgs();
+ unsigned NumArgsToCheck = NumArgs;
+ bool Invalid = false;
+
+ // 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() << Fn->getSourceRange();
+ // Use default arguments for missing arguments
+ NumArgsToCheck = NumArgsInProto;
+ Call->setNumArgs(Context, NumArgsInProto);
+ }
+
+ // If too many are passed and not variadic, error on the extras and drop
+ // them.
+ if (NumArgs > NumArgsInProto) {
+ if (!Proto->isVariadic()) {
+ Diag(Args[NumArgsInProto]->getLocStart(),
+ diag::err_typecheck_call_too_many_args)
+ << Fn->getType()->isBlockPointerType() << Fn->getSourceRange()
+ << SourceRange(Args[NumArgsInProto]->getLocStart(),
+ Args[NumArgs-1]->getLocEnd());
+ // This deletes the extra arguments.
+ Call->setNumArgs(Context, NumArgsInProto);
+ Invalid = true;
+ }
+ NumArgsToCheck = NumArgsInProto;
+ }
+
+ // Continue to check argument types (even if we have too few/many args).
+ for (unsigned i = 0; i != NumArgsToCheck; i++) {
+ QualType ProtoArgType = Proto->getArgType(i);
+
+ Expr *Arg;
+ if (i < NumArgs) {
+ Arg = Args[i];
+
+ if (RequireCompleteType(Arg->getSourceRange().getBegin(),
+ ProtoArgType,
+ diag::err_call_incomplete_argument,
+ Arg->getSourceRange()))
+ return true;
+
+ // Pass the argument.
+ if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
+ return true;
+ } else
+ // We already type-checked the argument, so we know it works.
+ Arg = new (Context) CXXDefaultArgExpr(FDecl->getParamDecl(i));
+ QualType ArgType = Arg->getType();
+
+ Call->setArg(i, Arg);
+ }
+
+ // If this is a variadic call, handle args passed through "...".
+ if (Proto->isVariadic()) {
+ VariadicCallType CallType = VariadicFunction;
+ if (Fn->getType()->isBlockPointerType())
+ CallType = VariadicBlock; // Block
+ else if (isa<MemberExpr>(Fn))
+ CallType = VariadicMethod;
+
+ // Promote the arguments (C99 6.5.2.2p7).
+ for (unsigned i = NumArgsInProto; i != NumArgs; i++) {
+ Expr *Arg = Args[i];
+ Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType);
+ Call->setArg(i, Arg);
+ }
+ }
+
+ return Invalid;
+}
+
+/// 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.
+Action::OwningExprResult
+Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
+ MultiExprArg args,
+ SourceLocation *CommaLocs, SourceLocation RParenLoc) {
+ unsigned NumArgs = args.size();
+ Expr *Fn = fn.takeAs<Expr>();
+ Expr **Args = reinterpret_cast<Expr**>(args.release());
+ assert(Fn && "no function call expression");
+ FunctionDecl *FDecl = NULL;
+ NamedDecl *NDecl = NULL;
+ DeclarationName UnqualifiedName;
+
+ if (getLangOptions().CPlusPlus) {
+ // Determine whether this is a dependent call inside a C++ template,
+ // in which case we won't do any semantic analysis now.
+ // FIXME: Will need to cache the results of name lookup (including ADL) in
+ // Fn.
+ bool Dependent = false;
+ if (Fn->isTypeDependent())
+ Dependent = true;
+ else if (Expr::hasAnyTypeDependentArguments(Args, NumArgs))
+ Dependent = true;
+
+ if (Dependent)
+ return Owned(new (Context) CallExpr(Context, Fn, Args, NumArgs,
+ Context.DependentTy, RParenLoc));
+
+ // Determine whether this is a call to an object (C++ [over.call.object]).
+ if (Fn->getType()->isRecordType())
+ return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs,
+ CommaLocs, RParenLoc));
+
+ // Determine whether this is a call to a member function.
+ if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(Fn->IgnoreParens()))
+ if (isa<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) ||
+ isa<CXXMethodDecl>(MemExpr->getMemberDecl()))
+ return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
+ CommaLocs, RParenLoc));
+ }
+
+ // If we're directly calling a function, get the appropriate declaration.
+ DeclRefExpr *DRExpr = NULL;
+ Expr *FnExpr = Fn;
+ bool ADL = true;
+ while (true) {
+ if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(FnExpr))
+ FnExpr = IcExpr->getSubExpr();
+ else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) {
+ // Parentheses around a function disable ADL
+ // (C++0x [basic.lookup.argdep]p1).
+ ADL = false;
+ FnExpr = PExpr->getSubExpr();
+ } else if (isa<UnaryOperator>(FnExpr) &&
+ cast<UnaryOperator>(FnExpr)->getOpcode()
+ == UnaryOperator::AddrOf) {
+ FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr();
+ } else if ((DRExpr = dyn_cast<DeclRefExpr>(FnExpr))) {
+ // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1).
+ ADL &= !isa<QualifiedDeclRefExpr>(DRExpr);
+ break;
+ } else if (UnresolvedFunctionNameExpr *DepName
+ = dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) {
+ UnqualifiedName = DepName->getName();
+ break;
+ } else {
+ // Any kind of name that does not refer to a declaration (or
+ // set of declarations) disables ADL (C++0x [basic.lookup.argdep]p3).
+ ADL = false;
+ break;
+ }
+ }
+
+ OverloadedFunctionDecl *Ovl = 0;
+ if (DRExpr) {
+ FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
+ Ovl = dyn_cast<OverloadedFunctionDecl>(DRExpr->getDecl());
+ NDecl = dyn_cast<NamedDecl>(DRExpr->getDecl());
+ }
+
+ if (Ovl || (getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
+ // We don't perform ADL for implicit declarations of builtins.
+ if (FDecl && FDecl->getBuiltinID(Context) && FDecl->isImplicit())
+ ADL = false;
+
+ // We don't perform ADL in C.
+ if (!getLangOptions().CPlusPlus)
+ ADL = false;
+
+ if (Ovl || ADL) {
+ FDecl = ResolveOverloadedCallFn(Fn, DRExpr? DRExpr->getDecl() : 0,
+ UnqualifiedName, LParenLoc, Args,
+ NumArgs, CommaLocs, RParenLoc, ADL);
+ if (!FDecl)
+ return ExprError();
+
+ // Update Fn to refer to the actual function selected.
+ Expr *NewFn = 0;
+ if (QualifiedDeclRefExpr *QDRExpr
+ = dyn_cast_or_null<QualifiedDeclRefExpr>(DRExpr))
+ NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(),
+ QDRExpr->getLocation(),
+ false, false,
+ QDRExpr->getQualifierRange(),
+ QDRExpr->getQualifier());
+ else
+ NewFn = new (Context) DeclRefExpr(FDecl, FDecl->getType(),
+ Fn->getSourceRange().getBegin());
+ Fn->Destroy(Context);
+ Fn = NewFn;
+ }
+ }
+
+ // Promote the function operand.
+ UsualUnaryConversions(Fn);
+
+ // Make the call expr early, before semantic checks. This guarantees cleanup
+ // of arguments and function on error.
+ ExprOwningPtr<CallExpr> TheCall(this, new (Context) CallExpr(Context, Fn,
+ Args, NumArgs,
+ Context.BoolTy,
+ RParenLoc));
+
+ const FunctionType *FuncT;
+ if (!Fn->getType()->isBlockPointerType()) {
+ // C99 6.5.2.2p1 - "The expression that denotes the called function shall
+ // have type pointer to function".
+ const PointerType *PT = Fn->getType()->getAsPointerType();
+ if (PT == 0)
+ return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
+ << Fn->getType() << Fn->getSourceRange());
+ FuncT = PT->getPointeeType()->getAsFunctionType();
+ } else { // This is a block call.
+ FuncT = Fn->getType()->getAsBlockPointerType()->getPointeeType()->
+ getAsFunctionType();
+ }
+ if (FuncT == 0)
+ return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
+ << Fn->getType() << Fn->getSourceRange());
+
+ // Check for a valid return type
+ if (!FuncT->getResultType()->isVoidType() &&
+ RequireCompleteType(Fn->getSourceRange().getBegin(),
+ FuncT->getResultType(),
+ diag::err_call_incomplete_return,
+ TheCall->getSourceRange()))
+ return ExprError();
+
+ // We know the result type of the call, set it.
+ TheCall->setType(FuncT->getResultType().getNonReferenceType());
+
+ if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT)) {
+ if (ConvertArgumentsForCall(&*TheCall, Fn, FDecl, Proto, Args, NumArgs,
+ RParenLoc))
+ return ExprError();
+ } else {
+ assert(isa<FunctionNoProtoType>(FuncT) && "Unknown FunctionType!");
+
+ if (FDecl) {
+ // Check if we have too few/too many template arguments, based
+ // on our knowledge of the function definition.
+ const FunctionDecl *Def = 0;
+ if (FDecl->getBody(Context, Def) && NumArgs != Def->param_size()) {
+ const FunctionProtoType *Proto =
+ Def->getType()->getAsFunctionProtoType();
+ if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size())) {
+ Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments)
+ << (NumArgs > Def->param_size()) << FDecl << Fn->getSourceRange();
+ }
+ }
+ }
+
+ // Promote the arguments (C99 6.5.2.2p6).
+ for (unsigned i = 0; i != NumArgs; i++) {
+ Expr *Arg = Args[i];
+ DefaultArgumentPromotion(Arg);
+ if (RequireCompleteType(Arg->getSourceRange().getBegin(),
+ Arg->getType(),
+ diag::err_call_incomplete_argument,
+ Arg->getSourceRange()))
+ return ExprError();
+ TheCall->setArg(i, Arg);
+ }
+ }
+
+ if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(FDecl))
+ if (!Method->isStatic())
+ return ExprError(Diag(LParenLoc, diag::err_member_call_without_object)
+ << Fn->getSourceRange());
+
+ // Check for sentinels
+ if (NDecl)
+ DiagnoseSentinelCalls(NDecl, LParenLoc, Args, NumArgs);
+ // Do special checking on direct calls to functions.
+ if (FDecl)
+ return CheckFunctionCall(FDecl, TheCall.take());
+ if (NDecl)
+ return CheckBlockCall(NDecl, TheCall.take());
+
+ return Owned(TheCall.take());
+}
+
+Action::OwningExprResult
+Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
+ SourceLocation RParenLoc, ExprArg InitExpr) {
+ assert((Ty != 0) && "ActOnCompoundLiteral(): missing type");
+ QualType literalType = QualType::getFromOpaquePtr(Ty);
+ // FIXME: put back this assert when initializers are worked out.
+ //assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression");
+ Expr *literalExpr = static_cast<Expr*>(InitExpr.get());
+
+ if (literalType->isArrayType()) {
+ if (literalType->isVariableArrayType())
+ return ExprError(Diag(LParenLoc, diag::err_variable_object_no_init)
+ << SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd()));
+ } else if (!literalType->isDependentType() &&
+ RequireCompleteType(LParenLoc, literalType,
+ diag::err_typecheck_decl_incomplete_type,
+ SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd())))
+ return ExprError();
+
+ if (CheckInitializerTypes(literalExpr, literalType, LParenLoc,
+ DeclarationName(), /*FIXME:DirectInit=*/false))
+ return ExprError();
+
+ bool isFileScope = getCurFunctionOrMethodDecl() == 0;
+ if (isFileScope) { // 6.5.2.5p3
+ if (CheckForConstantInitializer(literalExpr, literalType))
+ return ExprError();
+ }
+ InitExpr.release();
+ return Owned(new (Context) CompoundLiteralExpr(LParenLoc, literalType,
+ literalExpr, isFileScope));
+}
+
+Action::OwningExprResult
+Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist,
+ SourceLocation RBraceLoc) {
+ unsigned NumInit = initlist.size();
+ Expr **InitList = reinterpret_cast<Expr**>(initlist.release());
+
+ // Semantic analysis for initializers is done by ActOnDeclarator() and
+ // CheckInitializer() - it requires knowledge of the object being intialized.
+
+ InitListExpr *E = new (Context) InitListExpr(LBraceLoc, InitList, NumInit,
+ RBraceLoc);
+ E->setType(Context.VoidTy); // FIXME: just a place holder for now.
+ return Owned(E);
+}
+
+/// CheckCastTypes - Check type constraints for casting between types.
+bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) {
+ UsualUnaryConversions(castExpr);
+
+ // C99 6.5.4p2: the cast type needs to be void or scalar and the expression
+ // type needs to be scalar.
+ if (castType->isVoidType()) {
+ // Cast to void allows any expr type.
+ } else if (castType->isDependentType() || castExpr->isTypeDependent()) {
+ // We can't check any more until template instantiation time.
+ } else if (!castType->isScalarType() && !castType->isVectorType()) {
+ if (Context.getCanonicalType(castType).getUnqualifiedType() ==
+ Context.getCanonicalType(castExpr->getType().getUnqualifiedType()) &&
+ (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();
+ } else if (castType->isUnionType()) {
+ // GCC cast to union extension
+ RecordDecl *RD = castType->getAsRecordType()->getDecl();
+ RecordDecl::field_iterator Field, FieldEnd;
+ for (Field = RD->field_begin(Context), FieldEnd = RD->field_end(Context);
+ Field != FieldEnd; ++Field) {
+ if (Context.getCanonicalType(Field->getType()).getUnqualifiedType() ==
+ Context.getCanonicalType(castExpr->getType()).getUnqualifiedType()) {
+ Diag(TyR.getBegin(), diag::ext_typecheck_cast_to_union)
+ << castExpr->getSourceRange();
+ break;
+ }
+ }
+ if (Field == FieldEnd)
+ return Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type)
+ << castExpr->getType() << castExpr->getSourceRange();
+ } else {
+ // Reject any other conversions to non-scalar types.
+ return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar)
+ << castType << castExpr->getSourceRange();
+ }
+ } else if (!castExpr->getType()->isScalarType() &&
+ !castExpr->getType()->isVectorType()) {
+ return Diag(castExpr->getLocStart(),
+ diag::err_typecheck_expect_scalar_operand)
+ << castExpr->getType() << castExpr->getSourceRange();
+ } else if (castExpr->getType()->isVectorType()) {
+ if (CheckVectorCast(TyR, castExpr->getType(), castType))
+ return true;
+ } else if (castType->isVectorType()) {
+ if (CheckVectorCast(TyR, castType, castExpr->getType()))
+ return true;
+ } else if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr)) {
+ return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR;
+ } else if (!castType->isArithmeticType()) {
+ QualType castExprType = castExpr->getType();
+ if (!castExprType->isIntegralType() && castExprType->isArithmeticType())
+ return Diag(castExpr->getLocStart(),
+ diag::err_cast_pointer_from_non_pointer_int)
+ << castExprType << castExpr->getSourceRange();
+ } else if (!castExpr->getType()->isArithmeticType()) {
+ if (!castType->isIntegralType() && castType->isArithmeticType())
+ return Diag(castExpr->getLocStart(),
+ diag::err_cast_pointer_to_non_pointer_int)
+ << castType << castExpr->getSourceRange();
+ }
+ if (isa<ObjCSelectorExpr>(castExpr))
+ return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr);
+ return false;
+}
+
+bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty) {
+ assert(VectorTy->isVectorType() && "Not a vector type!");
+
+ if (Ty->isVectorType() || Ty->isIntegerType()) {
+ if (Context.getTypeSize(VectorTy) != Context.getTypeSize(Ty))
+ return Diag(R.getBegin(),
+ Ty->isVectorType() ?
+ diag::err_invalid_conversion_between_vectors :
+ diag::err_invalid_conversion_between_vector_and_integer)
+ << VectorTy << Ty << R;
+ } else
+ return Diag(R.getBegin(),
+ diag::err_invalid_conversion_between_vector_and_scalar)
+ << VectorTy << Ty << R;
+
+ return false;
+}
+
+Action::OwningExprResult
+Sema::ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
+ SourceLocation RParenLoc, ExprArg Op) {
+ assert((Ty != 0) && (Op.get() != 0) &&
+ "ActOnCastExpr(): missing type or expr");
+
+ Expr *castExpr = Op.takeAs<Expr>();
+ QualType castType = QualType::getFromOpaquePtr(Ty);
+
+ if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr))
+ return ExprError();
+ return Owned(new (Context) CStyleCastExpr(castType, castExpr, castType,
+ LParenLoc, RParenLoc));
+}
+
+/// 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(Expr *&Cond, Expr *&LHS, Expr *&RHS,
+ SourceLocation QuestionLoc) {
+ // C++ is sufficiently different to merit its own checker.
+ if (getLangOptions().CPlusPlus)
+ return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc);
+
+ UsualUnaryConversions(Cond);
+ UsualUnaryConversions(LHS);
+ UsualUnaryConversions(RHS);
+ QualType CondTy = Cond->getType();
+ QualType LHSTy = LHS->getType();
+ QualType RHSTy = RHS->getType();
+
+ // first, check the condition.
+ if (!CondTy->isScalarType()) { // C99 6.5.15p2
+ Diag(Cond->getLocStart(), diag::err_typecheck_cond_expect_scalar)
+ << CondTy;
+ return QualType();
+ }
+
+ // Now check the two expressions.
+
+ // If both operands have arithmetic type, do the usual arithmetic conversions
+ // to find a common type: C99 6.5.15p3,5.
+ if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) {
+ UsualArithmeticConversions(LHS, RHS);
+ return LHS->getType();
+ }
+
+ // If both operands are the same structure or union type, the result is that
+ // type.
+ if (const RecordType *LHSRT = LHSTy->getAsRecordType()) { // C99 6.5.15p3
+ if (const RecordType *RHSRT = RHSTy->getAsRecordType())
+ if (LHSRT->getDecl() == RHSRT->getDecl())
+ // "If both the operands have structure or union type, the result has
+ // that type." This implies that CV qualifiers are dropped.
+ return LHSTy.getUnqualifiedType();
+ // FIXME: Type of conditional expression must be complete in C mode.
+ }
+
+ // 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->getLocStart(), diag::ext_typecheck_cond_one_void)
+ << RHS->getSourceRange();
+ if (!RHSTy->isVoidType())
+ Diag(LHS->getLocStart(), diag::ext_typecheck_cond_one_void)
+ << LHS->getSourceRange();
+ ImpCastExprToType(LHS, Context.VoidTy);
+ ImpCastExprToType(RHS, Context.VoidTy);
+ return Context.VoidTy;
+ }
+ // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
+ // the type of the other operand."
+ if ((LHSTy->isPointerType() || LHSTy->isBlockPointerType() ||
+ Context.isObjCObjectPointerType(LHSTy)) &&
+ RHS->isNullPointerConstant(Context)) {
+ ImpCastExprToType(RHS, LHSTy); // promote the null to a pointer.
+ return LHSTy;
+ }
+ if ((RHSTy->isPointerType() || RHSTy->isBlockPointerType() ||
+ Context.isObjCObjectPointerType(RHSTy)) &&
+ LHS->isNullPointerConstant(Context)) {
+ ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer.
+ return RHSTy;
+ }
+
+ const PointerType *LHSPT = LHSTy->getAsPointerType();
+ const PointerType *RHSPT = RHSTy->getAsPointerType();
+ const BlockPointerType *LHSBPT = LHSTy->getAsBlockPointerType();
+ const BlockPointerType *RHSBPT = RHSTy->getAsBlockPointerType();
+
+ // Handle the case where both operands are pointers before we handle null
+ // pointer constants in case both operands are null pointer constants.
+ if ((LHSPT || LHSBPT) && (RHSPT || RHSBPT)) { // C99 6.5.15p3,6
+ // get the "pointed to" types
+ QualType lhptee = (LHSPT ? LHSPT->getPointeeType()
+ : LHSBPT->getPointeeType());
+ QualType rhptee = (RHSPT ? RHSPT->getPointeeType()
+ : RHSBPT->getPointeeType());
+
+ // ignore qualifiers on void (C99 6.5.15p3, clause 6)
+ if (lhptee->isVoidType()
+ && (RHSBPT || rhptee->isIncompleteOrObjectType())) {
+ // Figure out necessary qualifiers (C99 6.5.15p6)
+ QualType destPointee=lhptee.getQualifiedType(rhptee.getCVRQualifiers());
+ QualType destType = Context.getPointerType(destPointee);
+ ImpCastExprToType(LHS, destType); // add qualifiers if necessary
+ ImpCastExprToType(RHS, destType); // promote to void*
+ return destType;
+ }
+ if (rhptee->isVoidType()
+ && (LHSBPT || lhptee->isIncompleteOrObjectType())) {
+ QualType destPointee=rhptee.getQualifiedType(lhptee.getCVRQualifiers());
+ QualType destType = Context.getPointerType(destPointee);
+ ImpCastExprToType(LHS, destType); // add qualifiers if necessary
+ ImpCastExprToType(RHS, destType); // promote to void*
+ return destType;
+ }
+
+ bool sameKind = (LHSPT && RHSPT) || (LHSBPT && RHSBPT);
+ if (sameKind
+ && Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
+ // Two identical pointer types are always compatible.
+ return LHSTy;
+ }
+
+ QualType compositeType = LHSTy;
+
+ // If either type is an Objective-C object type then check
+ // compatibility according to Objective-C.
+ if (Context.isObjCObjectPointerType(LHSTy) ||
+ Context.isObjCObjectPointerType(RHSTy)) {
+ // If both operands are interfaces and either operand can be
+ // assigned to the other, use that type as the composite
+ // type. This allows
+ // xxx ? (A*) a : (B*) b
+ // where B is a subclass of A.
+ //
+ // Additionally, as for assignment, if either type is 'id'
+ // allow silent coercion. Finally, if the types are
+ // incompatible then make sure to use 'id' as the composite
+ // type so the result is acceptable for sending messages to.
+
+ // FIXME: Consider unifying with 'areComparableObjCPointerTypes'.
+ // It could return the composite type.
+ const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType();
+ const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType();
+ if (LHSIface && RHSIface &&
+ Context.canAssignObjCInterfaces(LHSIface, RHSIface)) {
+ compositeType = LHSTy;
+ } else if (LHSIface && RHSIface &&
+ Context.canAssignObjCInterfaces(RHSIface, LHSIface)) {
+ compositeType = RHSTy;
+ } else if (Context.isObjCIdStructType(lhptee) ||
+ Context.isObjCIdStructType(rhptee)) {
+ compositeType = Context.getObjCIdType();
+ } else if (LHSBPT || RHSBPT) {
+ if (!sameKind
+ || !Context.typesAreBlockCompatible(lhptee.getUnqualifiedType(),
+ rhptee.getUnqualifiedType()))
+ Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
+ << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
+ return QualType();
+ } else {
+ Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands)
+ << LHSTy << RHSTy
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ QualType incompatTy = Context.getObjCIdType();
+ ImpCastExprToType(LHS, incompatTy);
+ ImpCastExprToType(RHS, incompatTy);
+ return incompatTy;
+ }
+ } else if (!sameKind
+ || !Context.typesAreCompatible(lhptee.getUnqualifiedType(),
+ rhptee.getUnqualifiedType())) {
+ Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers)
+ << LHSTy << RHSTy << LHS->getSourceRange() << RHS->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);
+ ImpCastExprToType(LHS, incompatTy);
+ ImpCastExprToType(RHS, incompatTy);
+ 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
+ ImpCastExprToType(LHS, compositeType);
+ ImpCastExprToType(RHS, compositeType);
+ return compositeType;
+ }
+
+ // GCC compatibility: soften pointer/integer mismatch.
+ if (RHSTy->isPointerType() && LHSTy->isIntegerType()) {
+ Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch)
+ << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
+ ImpCastExprToType(LHS, RHSTy); // promote the integer to a pointer.
+ return RHSTy;
+ }
+ if (LHSTy->isPointerType() && RHSTy->isIntegerType()) {
+ Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch)
+ << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
+ ImpCastExprToType(RHS, LHSTy); // promote the integer to a pointer.
+ return LHSTy;
+ }
+
+ // Need to handle "id<xx>" explicitly. Unlike "id", whose canonical type
+ // evaluates to "struct objc_object *" (and is handled above when comparing
+ // id with statically typed objects).
+ if (LHSTy->isObjCQualifiedIdType() || RHSTy->isObjCQualifiedIdType()) {
+ // GCC allows qualified id and any Objective-C type to devolve to
+ // id. Currently localizing to here until clear this should be
+ // part of ObjCQualifiedIdTypesAreCompatible.
+ if (ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true) ||
+ (LHSTy->isObjCQualifiedIdType() &&
+ Context.isObjCObjectPointerType(RHSTy)) ||
+ (RHSTy->isObjCQualifiedIdType() &&
+ Context.isObjCObjectPointerType(LHSTy))) {
+ // FIXME: This is not the correct composite type. This only happens to
+ // work because id can more or less be used anywhere, however this may
+ // change the type of method sends.
+
+ // FIXME: gcc adds some type-checking of the arguments and emits
+ // (confusing) incompatible comparison warnings in some
+ // cases. Investigate.
+ QualType compositeType = Context.getObjCIdType();
+ ImpCastExprToType(LHS, compositeType);
+ ImpCastExprToType(RHS, compositeType);
+ return compositeType;
+ }
+ }
+
+ // Otherwise, the operands are not compatible.
+ Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
+ << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
+ return QualType();
+}
+
+/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
+/// in the case of a the GNU conditional expr extension.
+Action::OwningExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
+ SourceLocation ColonLoc,
+ ExprArg Cond, ExprArg LHS,
+ ExprArg RHS) {
+ Expr *CondExpr = (Expr *) Cond.get();
+ Expr *LHSExpr = (Expr *) LHS.get(), *RHSExpr = (Expr *) RHS.get();
+
+ // If this is the gnu "x ?: y" extension, analyze the types as though the LHS
+ // was the condition.
+ bool isLHSNull = LHSExpr == 0;
+ if (isLHSNull)
+ LHSExpr = CondExpr;
+
+ QualType result = CheckConditionalOperands(CondExpr, LHSExpr,
+ RHSExpr, QuestionLoc);
+ if (result.isNull())
+ return ExprError();
+
+ Cond.release();
+ LHS.release();
+ RHS.release();
+ return Owned(new (Context) ConditionalOperator(CondExpr,
+ isLHSNull ? 0 : LHSExpr,
+ RHSExpr, result));
+}
+
+
+// CheckPointerTypesForAssignment - This is a very tricky routine (despite
+// being closely modeled after the C99 spec:-). The odd characteristic of this
+// routine is it effectively iqnores the qualifiers on the top level pointee.
+// This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3].
+// FIXME: add a couple examples in this comment.
+Sema::AssignConvertType
+Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
+ QualType lhptee, rhptee;
+
+ // get the "pointed to" type (ignoring qualifiers at the top level)
+ lhptee = lhsType->getAsPointerType()->getPointeeType();
+ rhptee = rhsType->getAsPointerType()->getPointeeType();
+
+ // make sure we operate on the canonical type
+ lhptee = Context.getCanonicalType(lhptee);
+ rhptee = Context.getCanonicalType(rhptee);
+
+ AssignConvertType ConvTy = Compatible;
+
+ // C99 6.5.16.1p1: This following citation is common to constraints
+ // 3 & 4 (below). ...and the type *pointed to* by the left has all the
+ // qualifiers of the type *pointed to* by the right;
+ // FIXME: Handle ExtQualType
+ if (!lhptee.isAtLeastAsQualifiedAs(rhptee))
+ ConvTy = CompatiblePointerDiscardsQualifiers;
+
+ // C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or
+ // incomplete type and the other is a pointer to a qualified or unqualified
+ // version of void...
+ if (lhptee->isVoidType()) {
+ if (rhptee->isIncompleteOrObjectType())
+ return ConvTy;
+
+ // As an extension, we allow cast to/from void* to function pointer.
+ assert(rhptee->isFunctionType());
+ return FunctionVoidPointer;
+ }
+
+ if (rhptee->isVoidType()) {
+ if (lhptee->isIncompleteOrObjectType())
+ return ConvTy;
+
+ // As an extension, we allow cast to/from void* to function pointer.
+ assert(lhptee->isFunctionType());
+ return FunctionVoidPointer;
+ }
+ // C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or
+ // unqualified versions of compatible types, ...
+ lhptee = lhptee.getUnqualifiedType();
+ rhptee = rhptee.getUnqualifiedType();
+ if (!Context.typesAreCompatible(lhptee, rhptee)) {
+ // Check if the pointee types are compatible ignoring the sign.
+ // We explicitly check for char so that we catch "char" vs
+ // "unsigned char" on systems where "char" is unsigned.
+ if (lhptee->isCharType()) {
+ lhptee = Context.UnsignedCharTy;
+ } else if (lhptee->isSignedIntegerType()) {
+ lhptee = Context.getCorrespondingUnsignedType(lhptee);
+ }
+ if (rhptee->isCharType()) {
+ rhptee = Context.UnsignedCharTy;
+ } else if (rhptee->isSignedIntegerType()) {
+ rhptee = Context.getCorrespondingUnsignedType(rhptee);
+ }
+ if (lhptee == rhptee) {
+ // Types are compatible ignoring the sign. Qualifier incompatibility
+ // takes priority over sign incompatibility because the sign
+ // warning can be disabled.
+ if (ConvTy != Compatible)
+ return ConvTy;
+ return IncompatiblePointerSign;
+ }
+ // General pointer incompatibility takes priority over qualifiers.
+ return IncompatiblePointer;
+ }
+ return ConvTy;
+}
+
+/// CheckBlockPointerTypesForAssignment - This routine determines whether two
+/// block pointer types are compatible or whether a block and normal pointer
+/// are compatible. It is more restrict than comparing two function pointer
+// types.
+Sema::AssignConvertType
+Sema::CheckBlockPointerTypesForAssignment(QualType lhsType,
+ QualType rhsType) {
+ QualType lhptee, rhptee;
+
+ // get the "pointed to" type (ignoring qualifiers at the top level)
+ lhptee = lhsType->getAsBlockPointerType()->getPointeeType();
+ rhptee = rhsType->getAsBlockPointerType()->getPointeeType();
+
+ // make sure we operate on the canonical type
+ lhptee = Context.getCanonicalType(lhptee);
+ rhptee = Context.getCanonicalType(rhptee);
+
+ AssignConvertType ConvTy = Compatible;
+
+ // For blocks we enforce that qualifiers are identical.
+ if (lhptee.getCVRQualifiers() != rhptee.getCVRQualifiers())
+ ConvTy = CompatiblePointerDiscardsQualifiers;
+
+ if (!Context.typesAreBlockCompatible(lhptee, rhptee))
+ return IncompatibleBlockPointer;
+ return ConvTy;
+}
+
+/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
+/// has code to accommodate several GCC extensions when type checking
+/// pointers. Here are some objectionable examples that GCC considers warnings:
+///
+/// int a, *pint;
+/// short *pshort;
+/// struct foo *pfoo;
+///
+/// pint = pshort; // warning: assignment from incompatible pointer type
+/// a = pint; // warning: assignment makes integer from pointer without a cast
+/// pint = a; // warning: assignment makes pointer from integer without a cast
+/// pint = pfoo; // warning: assignment from incompatible pointer type
+///
+/// As a result, the code for dealing with pointers is more complex than the
+/// C99 spec dictates.
+///
+Sema::AssignConvertType
+Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
+ // Get canonical types. We're not formatting these types, just comparing
+ // them.
+ lhsType = Context.getCanonicalType(lhsType).getUnqualifiedType();
+ rhsType = Context.getCanonicalType(rhsType).getUnqualifiedType();
+
+ if (lhsType == rhsType)
+ return Compatible; // Common case: fast path an exact match.
+
+ // If the left-hand side is a reference type, then we are in a
+ // (rare!) case where we've allowed the use of references in C,
+ // 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
+ // type.
+ if (const ReferenceType *lhsTypeRef = lhsType->getAsReferenceType()) {
+ if (Context.typesAreCompatible(lhsTypeRef->getPointeeType(), rhsType))
+ return Compatible;
+ return Incompatible;
+ }
+
+ if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) {
+ if (ObjCQualifiedIdTypesAreCompatible(lhsType, rhsType, false))
+ return Compatible;
+ // Relax integer conversions like we do for pointers below.
+ if (rhsType->isIntegerType())
+ return IntToPointer;
+ if (lhsType->isIntegerType())
+ return PointerToInt;
+ return IncompatibleObjCQualifiedId;
+ }
+
+ if (lhsType->isVectorType() || rhsType->isVectorType()) {
+ // For ExtVector, allow vector splats; float -> <n x float>
+ if (const ExtVectorType *LV = lhsType->getAsExtVectorType())
+ if (LV->getElementType() == rhsType)
+ return Compatible;
+
+ // 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.
+ if (getLangOptions().LaxVectorConversions &&
+ lhsType->isVectorType() && rhsType->isVectorType()) {
+ if (Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType))
+ return IncompatibleVectors;
+ }
+ return Incompatible;
+ }
+
+ if (lhsType->isArithmeticType() && rhsType->isArithmeticType())
+ return Compatible;
+
+ if (isa<PointerType>(lhsType)) {
+ if (rhsType->isIntegerType())
+ return IntToPointer;
+
+ if (isa<PointerType>(rhsType))
+ return CheckPointerTypesForAssignment(lhsType, rhsType);
+
+ if (rhsType->getAsBlockPointerType()) {
+ if (lhsType->getAsPointerType()->getPointeeType()->isVoidType())
+ return Compatible;
+
+ // Treat block pointers as objects.
+ if (getLangOptions().ObjC1 &&
+ lhsType == Context.getCanonicalType(Context.getObjCIdType()))
+ return Compatible;
+ }
+ return Incompatible;
+ }
+
+ if (isa<BlockPointerType>(lhsType)) {
+ if (rhsType->isIntegerType())
+ return IntToBlockPointer;
+
+ // Treat block pointers as objects.
+ if (getLangOptions().ObjC1 &&
+ rhsType == Context.getCanonicalType(Context.getObjCIdType()))
+ return Compatible;
+
+ if (rhsType->isBlockPointerType())
+ return CheckBlockPointerTypesForAssignment(lhsType, rhsType);
+
+ if (const PointerType *RHSPT = rhsType->getAsPointerType()) {
+ if (RHSPT->getPointeeType()->isVoidType())
+ return Compatible;
+ }
+ return Incompatible;
+ }
+
+ if (isa<PointerType>(rhsType)) {
+ // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
+ if (lhsType == Context.BoolTy)
+ return Compatible;
+
+ if (lhsType->isIntegerType())
+ return PointerToInt;
+
+ if (isa<PointerType>(lhsType))
+ return CheckPointerTypesForAssignment(lhsType, rhsType);
+
+ if (isa<BlockPointerType>(lhsType) &&
+ rhsType->getAsPointerType()->getPointeeType()->isVoidType())
+ return Compatible;
+ return Incompatible;
+ }
+
+ if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) {
+ if (Context.typesAreCompatible(lhsType, rhsType))
+ return Compatible;
+ }
+ return Incompatible;
+}
+
+/// \brief Constructs a transparent union from an expression that is
+/// used to initialize the transparent union.
+static void ConstructTransparentUnion(ASTContext &C, Expr *&E,
+ QualType UnionType, FieldDecl *Field) {
+ // Build an initializer list that designates the appropriate member
+ // of the transparent union.
+ InitListExpr *Initializer = new (C) InitListExpr(SourceLocation(),
+ &E, 1,
+ SourceLocation());
+ Initializer->setType(UnionType);
+ Initializer->setInitializedFieldInUnion(Field);
+
+ // Build a compound literal constructing a value of the transparent
+ // union type from this initializer list.
+ E = new (C) CompoundLiteralExpr(SourceLocation(), UnionType, Initializer,
+ false);
+}
+
+Sema::AssignConvertType
+Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) {
+ QualType FromType = rExpr->getType();
+
+ // If the ArgType is a Union type, we want to handle a potential
+ // transparent_union GCC extension.
+ const RecordType *UT = ArgType->getAsUnionType();
+ if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
+ return Incompatible;
+
+ // The field to initialize within the transparent union.
+ RecordDecl *UD = UT->getDecl();
+ FieldDecl *InitField = 0;
+ // It's compatible if the expression matches any of the fields.
+ for (RecordDecl::field_iterator it = UD->field_begin(Context),
+ itend = UD->field_end(Context);
+ it != itend; ++it) {
+ if (it->getType()->isPointerType()) {
+ // If the transparent union contains a pointer type, we allow:
+ // 1) void pointer
+ // 2) null pointer constant
+ if (FromType->isPointerType())
+ if (FromType->getAsPointerType()->getPointeeType()->isVoidType()) {
+ ImpCastExprToType(rExpr, it->getType());
+ InitField = *it;
+ break;
+ }
+
+ if (rExpr->isNullPointerConstant(Context)) {
+ ImpCastExprToType(rExpr, it->getType());
+ InitField = *it;
+ break;
+ }
+ }
+
+ if (CheckAssignmentConstraints(it->getType(), rExpr->getType())
+ == Compatible) {
+ InitField = *it;
+ break;
+ }
+ }
+
+ if (!InitField)
+ return Incompatible;
+
+ ConstructTransparentUnion(Context, rExpr, ArgType, InitField);
+ return Compatible;
+}
+
+Sema::AssignConvertType
+Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
+ if (getLangOptions().CPlusPlus) {
+ if (!lhsType->isRecordType()) {
+ // 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.
+ if (PerformImplicitConversion(rExpr, lhsType.getUnqualifiedType(),
+ "assigning"))
+ return Incompatible;
+ return Compatible;
+ }
+
+ // FIXME: Currently, we fall through and treat C++ classes like C
+ // structures.
+ }
+
+ // C99 6.5.16.1p1: the left operand is a pointer and the right is
+ // a null pointer constant.
+ if ((lhsType->isPointerType() ||
+ lhsType->isObjCQualifiedIdType() ||
+ lhsType->isBlockPointerType())
+ && rExpr->isNullPointerConstant(Context)) {
+ ImpCastExprToType(rExpr, lhsType);
+ return Compatible;
+ }
+
+ // This check seems unnatural, however it is necessary to ensure the proper
+ // conversion of functions/arrays. If the conversion were done for all
+ // DeclExpr's (created by ActOnIdentifierExpr), it would mess up the unary
+ // expressions that surpress this implicit conversion (&, sizeof).
+ //
+ // Suppress this for references: C++ 8.5.3p5.
+ if (!lhsType->isReferenceType())
+ DefaultFunctionArrayConversion(rExpr);
+
+ Sema::AssignConvertType result =
+ CheckAssignmentConstraints(lhsType, rExpr->getType());
+
+ // C99 6.5.16.1p2: The value of the right operand is converted to the
+ // type of the assignment expression.
+ // CheckAssignmentConstraints allows the left-hand side to be a reference,
+ // 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->getType() != lhsType)
+ ImpCastExprToType(rExpr, lhsType.getNonReferenceType());
+ return result;
+}
+
+QualType Sema::InvalidOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
+ Diag(Loc, diag::err_typecheck_invalid_operands)
+ << lex->getType() << rex->getType()
+ << lex->getSourceRange() << rex->getSourceRange();
+ return QualType();
+}
+
+inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
+ Expr *&rex) {
+ // For conversion purposes, we ignore any qualifiers.
+ // For example, "const float" and "float" are equivalent.
+ QualType lhsType =
+ Context.getCanonicalType(lex->getType()).getUnqualifiedType();
+ QualType rhsType =
+ Context.getCanonicalType(rex->getType()).getUnqualifiedType();
+
+ // If the vector types are identical, return.
+ if (lhsType == rhsType)
+ return lhsType;
+
+ // Handle the case of a vector & extvector type of the same size and element
+ // type. It would be nice if we only had one vector type someday.
+ if (getLangOptions().LaxVectorConversions) {
+ // FIXME: Should we warn here?
+ if (const VectorType *LV = lhsType->getAsVectorType()) {
+ if (const VectorType *RV = rhsType->getAsVectorType())
+ if (LV->getElementType() == RV->getElementType() &&
+ LV->getNumElements() == RV->getNumElements()) {
+ return lhsType->isExtVectorType() ? lhsType : rhsType;
+ }
+ }
+ }
+
+ // If the lhs is an extended vector and the rhs is a scalar of the same type
+ // or a literal, promote the rhs to the vector type.
+ if (const ExtVectorType *V = lhsType->getAsExtVectorType()) {
+ QualType eltType = V->getElementType();
+
+ if ((eltType->getAsBuiltinType() == rhsType->getAsBuiltinType()) ||
+ (eltType->isIntegerType() && isa<IntegerLiteral>(rex)) ||
+ (eltType->isFloatingType() && isa<FloatingLiteral>(rex))) {
+ ImpCastExprToType(rex, lhsType);
+ return lhsType;
+ }
+ }
+
+ // If the rhs is an extended vector and the lhs is a scalar of the same type,
+ // promote the lhs to the vector type.
+ if (const ExtVectorType *V = rhsType->getAsExtVectorType()) {
+ QualType eltType = V->getElementType();
+
+ if ((eltType->getAsBuiltinType() == lhsType->getAsBuiltinType()) ||
+ (eltType->isIntegerType() && isa<IntegerLiteral>(lex)) ||
+ (eltType->isFloatingType() && isa<FloatingLiteral>(lex))) {
+ ImpCastExprToType(lex, rhsType);
+ return rhsType;
+ }
+ }
+
+ // You cannot convert between vector values of different size.
+ Diag(Loc, diag::err_typecheck_vector_not_convertable)
+ << lex->getType() << rex->getType()
+ << lex->getSourceRange() << rex->getSourceRange();
+ return QualType();
+}
+
+inline QualType Sema::CheckMultiplyDivideOperands(
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
+{
+ if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
+ return CheckVectorOperands(Loc, lex, rex);
+
+ QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
+
+ if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
+ return compType;
+ return InvalidOperands(Loc, lex, rex);
+}
+
+inline QualType Sema::CheckRemainderOperands(
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
+{
+ if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
+ if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType())
+ return CheckVectorOperands(Loc, lex, rex);
+ return InvalidOperands(Loc, lex, rex);
+ }
+
+ QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
+
+ if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType())
+ return compType;
+ return InvalidOperands(Loc, lex, rex);
+}
+
+inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
+ Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy)
+{
+ if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
+ QualType compType = CheckVectorOperands(Loc, lex, rex);
+ if (CompLHSTy) *CompLHSTy = compType;
+ return compType;
+ }
+
+ QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy);
+
+ // handle the common case first (both operands are arithmetic).
+ if (lex->getType()->isArithmeticType() &&
+ rex->getType()->isArithmeticType()) {
+ if (CompLHSTy) *CompLHSTy = compType;
+ return compType;
+ }
+
+ // Put any potential pointer into PExp
+ Expr* PExp = lex, *IExp = rex;
+ if (IExp->getType()->isPointerType())
+ std::swap(PExp, IExp);
+
+ if (const PointerType *PTy = PExp->getType()->getAsPointerType()) {
+ if (IExp->getType()->isIntegerType()) {
+ QualType PointeeTy = PTy->getPointeeType();
+ // Check for arithmetic on pointers to incomplete types.
+ if (PointeeTy->isVoidType()) {
+ if (getLangOptions().CPlusPlus) {
+ Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
+ << lex->getSourceRange() << rex->getSourceRange();
+ return QualType();
+ }
+
+ // GNU extension: arithmetic on pointer to void
+ Diag(Loc, diag::ext_gnu_void_ptr)
+ << lex->getSourceRange() << rex->getSourceRange();
+ } else if (PointeeTy->isFunctionType()) {
+ if (getLangOptions().CPlusPlus) {
+ Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
+ << lex->getType() << lex->getSourceRange();
+ return QualType();
+ }
+
+ // GNU extension: arithmetic on pointer to function
+ Diag(Loc, diag::ext_gnu_ptr_func_arith)
+ << lex->getType() << lex->getSourceRange();
+ } else if (!PTy->isDependentType() &&
+ RequireCompleteType(Loc, PointeeTy,
+ diag::err_typecheck_arithmetic_incomplete_type,
+ PExp->getSourceRange(), SourceRange(),
+ PExp->getType()))
+ return QualType();
+
+ // Diagnose bad cases where we step over interface counts.
+ if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
+ Diag(Loc, diag::err_arithmetic_nonfragile_interface)
+ << PointeeTy << PExp->getSourceRange();
+ return QualType();
+ }
+
+ if (CompLHSTy) {
+ QualType LHSTy = lex->getType();
+ if (LHSTy->isPromotableIntegerType())
+ LHSTy = Context.IntTy;
+ else {
+ QualType T = isPromotableBitField(lex, Context);
+ if (!T.isNull())
+ LHSTy = T;
+ }
+
+ *CompLHSTy = LHSTy;
+ }
+ return PExp->getType();
+ }
+ }
+
+ return InvalidOperands(Loc, lex, rex);
+}
+
+// C99 6.5.6
+QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
+ SourceLocation Loc, QualType* CompLHSTy) {
+ if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
+ QualType compType = CheckVectorOperands(Loc, lex, rex);
+ if (CompLHSTy) *CompLHSTy = compType;
+ return compType;
+ }
+
+ QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy);
+
+ // Enforce type constraints: C99 6.5.6p3.
+
+ // Handle the common case first (both operands are arithmetic).
+ if (lex->getType()->isArithmeticType()
+ && rex->getType()->isArithmeticType()) {
+ if (CompLHSTy) *CompLHSTy = compType;
+ return compType;
+ }
+
+ // Either ptr - int or ptr - ptr.
+ if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) {
+ QualType lpointee = LHSPTy->getPointeeType();
+
+ // The LHS must be an completely-defined object type.
+
+ bool ComplainAboutVoid = false;
+ Expr *ComplainAboutFunc = 0;
+ if (lpointee->isVoidType()) {
+ if (getLangOptions().CPlusPlus) {
+ Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
+ << lex->getSourceRange() << rex->getSourceRange();
+ return QualType();
+ }
+
+ // GNU C extension: arithmetic on pointer to void
+ ComplainAboutVoid = true;
+ } else if (lpointee->isFunctionType()) {
+ if (getLangOptions().CPlusPlus) {
+ Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
+ << lex->getType() << lex->getSourceRange();
+ return QualType();
+ }
+
+ // GNU C extension: arithmetic on pointer to function
+ ComplainAboutFunc = lex;
+ } else if (!lpointee->isDependentType() &&
+ RequireCompleteType(Loc, lpointee,
+ diag::err_typecheck_sub_ptr_object,
+ lex->getSourceRange(),
+ SourceRange(),
+ lex->getType()))
+ return QualType();
+
+ // Diagnose bad cases where we step over interface counts.
+ if (lpointee->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
+ Diag(Loc, diag::err_arithmetic_nonfragile_interface)
+ << lpointee << lex->getSourceRange();
+ return QualType();
+ }
+
+ // The result type of a pointer-int computation is the pointer type.
+ if (rex->getType()->isIntegerType()) {
+ if (ComplainAboutVoid)
+ Diag(Loc, diag::ext_gnu_void_ptr)
+ << lex->getSourceRange() << rex->getSourceRange();
+ if (ComplainAboutFunc)
+ Diag(Loc, diag::ext_gnu_ptr_func_arith)
+ << ComplainAboutFunc->getType()
+ << ComplainAboutFunc->getSourceRange();
+
+ if (CompLHSTy) *CompLHSTy = lex->getType();
+ return lex->getType();
+ }
+
+ // Handle pointer-pointer subtractions.
+ if (const PointerType *RHSPTy = rex->getType()->getAsPointerType()) {
+ QualType rpointee = RHSPTy->getPointeeType();
+
+ // RHS must be a completely-type object type.
+ // Handle the GNU void* extension.
+ if (rpointee->isVoidType()) {
+ if (getLangOptions().CPlusPlus) {
+ Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
+ << lex->getSourceRange() << rex->getSourceRange();
+ return QualType();
+ }
+
+ ComplainAboutVoid = true;
+ } else if (rpointee->isFunctionType()) {
+ if (getLangOptions().CPlusPlus) {
+ Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
+ << rex->getType() << rex->getSourceRange();
+ return QualType();
+ }
+
+ // GNU extension: arithmetic on pointer to function
+ if (!ComplainAboutFunc)
+ ComplainAboutFunc = rex;
+ } else if (!rpointee->isDependentType() &&
+ RequireCompleteType(Loc, rpointee,
+ diag::err_typecheck_sub_ptr_object,
+ rex->getSourceRange(),
+ SourceRange(),
+ rex->getType()))
+ return QualType();
+
+ 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->getType() << rex->getType()
+ << lex->getSourceRange() << rex->getSourceRange();
+ return QualType();
+ }
+ } 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->getType() << rex->getType()
+ << lex->getSourceRange() << rex->getSourceRange();
+ return QualType();
+ }
+ }
+
+ if (ComplainAboutVoid)
+ Diag(Loc, diag::ext_gnu_void_ptr)
+ << lex->getSourceRange() << rex->getSourceRange();
+ if (ComplainAboutFunc)
+ Diag(Loc, diag::ext_gnu_ptr_func_arith)
+ << ComplainAboutFunc->getType()
+ << ComplainAboutFunc->getSourceRange();
+
+ if (CompLHSTy) *CompLHSTy = lex->getType();
+ return Context.getPointerDiffType();
+ }
+ }
+
+ return InvalidOperands(Loc, lex, rex);
+}
+
+// C99 6.5.7
+QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
+ bool isCompAssign) {
+ // C99 6.5.7p2: Each of the operands shall have integer type.
+ if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType())
+ return InvalidOperands(Loc, lex, rex);
+
+ // Shifts don't perform usual arithmetic conversions, they just do integer
+ // promotions on each operand. C99 6.5.7p3
+ QualType LHSTy;
+ if (lex->getType()->isPromotableIntegerType())
+ LHSTy = Context.IntTy;
+ else {
+ LHSTy = isPromotableBitField(lex, Context);
+ if (LHSTy.isNull())
+ LHSTy = lex->getType();
+ }
+ if (!isCompAssign)
+ ImpCastExprToType(lex, LHSTy);
+
+ UsualUnaryConversions(rex);
+
+ // "The type of the result is that of the promoted left operand."
+ return LHSTy;
+}
+
+// C99 6.5.8, C++ [expr.rel]
+QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
+ unsigned OpaqueOpc, bool isRelational) {
+ BinaryOperator::Opcode Opc = (BinaryOperator::Opcode)OpaqueOpc;
+
+ if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
+ return CheckVectorCompareOperands(lex, rex, Loc, isRelational);
+
+ // C99 6.5.8p3 / C99 6.5.9p4
+ if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
+ UsualArithmeticConversions(lex, rex);
+ else {
+ UsualUnaryConversions(lex);
+ UsualUnaryConversions(rex);
+ }
+ QualType lType = lex->getType();
+ QualType rType = rex->getType();
+
+ if (!lType->isFloatingType()
+ && !(lType->isBlockPointerType() && isRelational)) {
+ // 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.
+ // NOTE: Don't warn about comparisons of enum constants. These can arise
+ // from macro expansions, and are usually quite deliberate.
+ Expr *LHSStripped = lex->IgnoreParens();
+ Expr *RHSStripped = rex->IgnoreParens();
+ if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHSStripped))
+ if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped))
+ if (DRL->getDecl() == DRR->getDecl() &&
+ !isa<EnumConstantDecl>(DRL->getDecl()))
+ Diag(Loc, diag::warn_selfcomparison);
+
+ if (isa<CastExpr>(LHSStripped))
+ LHSStripped = LHSStripped->IgnoreParenCasts();
+ if (isa<CastExpr>(RHSStripped))
+ RHSStripped = RHSStripped->IgnoreParenCasts();
+
+ // Warn about comparisons against a string constant (unless the other
+ // operand is null), the user probably wants strcmp.
+ Expr *literalString = 0;
+ Expr *literalStringStripped = 0;
+ if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) &&
+ !RHSStripped->isNullPointerConstant(Context)) {
+ literalString = lex;
+ literalStringStripped = LHSStripped;
+ }
+ else if ((isa<StringLiteral>(RHSStripped) ||
+ isa<ObjCEncodeExpr>(RHSStripped)) &&
+ !LHSStripped->isNullPointerConstant(Context)) {
+ literalString = rex;
+ literalStringStripped = RHSStripped;
+ }
+
+ if (literalString) {
+ std::string resultComparison;
+ switch (Opc) {
+ case BinaryOperator::LT: resultComparison = ") < 0"; break;
+ case BinaryOperator::GT: resultComparison = ") > 0"; break;
+ case BinaryOperator::LE: resultComparison = ") <= 0"; break;
+ case BinaryOperator::GE: resultComparison = ") >= 0"; break;
+ case BinaryOperator::EQ: resultComparison = ") == 0"; break;
+ case BinaryOperator::NE: resultComparison = ") != 0"; break;
+ default: assert(false && "Invalid comparison operator");
+ }
+ Diag(Loc, diag::warn_stringcompare)
+ << isa<ObjCEncodeExpr>(literalStringStripped)
+ << literalString->getSourceRange()
+ << CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ")
+ << CodeModificationHint::CreateInsertion(lex->getLocStart(),
+ "strcmp(")
+ << CodeModificationHint::CreateInsertion(
+ PP.getLocForEndOfToken(rex->getLocEnd()),
+ resultComparison);
+ }
+ }
+
+ // The result of comparisons is 'bool' in C++, 'int' in C.
+ QualType ResultTy = getLangOptions().CPlusPlus? Context.BoolTy :Context.IntTy;
+
+ if (isRelational) {
+ if (lType->isRealType() && rType->isRealType())
+ return ResultTy;
+ } else {
+ // Check for comparisons of floating point operands using != and ==.
+ if (lType->isFloatingType()) {
+ assert(rType->isFloatingType());
+ CheckFloatComparison(Loc,lex,rex);
+ }
+
+ if (lType->isArithmeticType() && rType->isArithmeticType())
+ return ResultTy;
+ }
+
+ bool LHSIsNull = lex->isNullPointerConstant(Context);
+ bool RHSIsNull = rex->isNullPointerConstant(Context);
+
+ // All of the following pointer related warnings are GCC extensions, except
+ // when handling null pointer constants. One day, we can consider making them
+ // errors (when -pedantic-errors is enabled).
+ if (lType->isPointerType() && rType->isPointerType()) { // C99 6.5.8p2
+ QualType LCanPointeeTy =
+ Context.getCanonicalType(lType->getAsPointerType()->getPointeeType());
+ QualType RCanPointeeTy =
+ Context.getCanonicalType(rType->getAsPointerType()->getPointeeType());
+
+ // Simple check: if the pointee types are identical, we're done.
+ if (LCanPointeeTy == RCanPointeeTy)
+ return ResultTy;
+
+ if (getLangOptions().CPlusPlus) {
+ // 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]p2 uses the same notion for (in)equality
+ // comparisons of pointers.
+ QualType T = FindCompositePointerType(lex, rex);
+ if (T.isNull()) {
+ Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ return QualType();
+ }
+
+ ImpCastExprToType(lex, T);
+ ImpCastExprToType(rex, T);
+ return ResultTy;
+ }
+
+ if (!LHSIsNull && !RHSIsNull && // C99 6.5.9p2
+ !LCanPointeeTy->isVoidType() && !RCanPointeeTy->isVoidType() &&
+ !Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
+ RCanPointeeTy.getUnqualifiedType()) &&
+ !Context.areComparableObjCPointerTypes(lType, rType)) {
+ Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ }
+ ImpCastExprToType(rex, lType); // promote the pointer to pointer
+ return ResultTy;
+ }
+ // C++ allows comparison of pointers with null pointer constants.
+ if (getLangOptions().CPlusPlus) {
+ if (lType->isPointerType() && RHSIsNull) {
+ ImpCastExprToType(rex, lType);
+ return ResultTy;
+ }
+ if (rType->isPointerType() && LHSIsNull) {
+ ImpCastExprToType(lex, rType);
+ return ResultTy;
+ }
+ // And comparison of nullptr_t with itself.
+ if (lType->isNullPtrType() && rType->isNullPtrType())
+ return ResultTy;
+ }
+ // Handle block pointer types.
+ if (!isRelational && lType->isBlockPointerType() && rType->isBlockPointerType()) {
+ QualType lpointee = lType->getAsBlockPointerType()->getPointeeType();
+ QualType rpointee = rType->getAsBlockPointerType()->getPointeeType();
+
+ if (!LHSIsNull && !RHSIsNull &&
+ !Context.typesAreBlockCompatible(lpointee, rpointee)) {
+ Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ }
+ ImpCastExprToType(rex, lType); // promote the pointer to pointer
+ return ResultTy;
+ }
+ // Allow block pointers to be compared with null pointer constants.
+ if (!isRelational
+ && ((lType->isBlockPointerType() && rType->isPointerType())
+ || (lType->isPointerType() && rType->isBlockPointerType()))) {
+ if (!LHSIsNull && !RHSIsNull) {
+ if (!((rType->isPointerType() && rType->getAsPointerType()
+ ->getPointeeType()->isVoidType())
+ || (lType->isPointerType() && lType->getAsPointerType()
+ ->getPointeeType()->isVoidType())))
+ Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ }
+ ImpCastExprToType(rex, lType); // promote the pointer to pointer
+ return ResultTy;
+ }
+
+ if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())) {
+ if (lType->isPointerType() || rType->isPointerType()) {
+ const PointerType *LPT = lType->getAsPointerType();
+ const PointerType *RPT = rType->getAsPointerType();
+ bool LPtrToVoid = LPT ?
+ Context.getCanonicalType(LPT->getPointeeType())->isVoidType() : false;
+ bool RPtrToVoid = RPT ?
+ Context.getCanonicalType(RPT->getPointeeType())->isVoidType() : false;
+
+ if (!LPtrToVoid && !RPtrToVoid &&
+ !Context.typesAreCompatible(lType, rType)) {
+ Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ ImpCastExprToType(rex, lType);
+ return ResultTy;
+ }
+ ImpCastExprToType(rex, lType);
+ return ResultTy;
+ }
+ if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
+ ImpCastExprToType(rex, lType);
+ return ResultTy;
+ } else {
+ if ((lType->isObjCQualifiedIdType() && rType->isObjCQualifiedIdType())) {
+ Diag(Loc, diag::warn_incompatible_qualified_id_operands)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ ImpCastExprToType(rex, lType);
+ return ResultTy;
+ }
+ }
+ }
+ if ((lType->isPointerType() || lType->isObjCQualifiedIdType()) &&
+ rType->isIntegerType()) {
+ if (!RHSIsNull)
+ Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ ImpCastExprToType(rex, lType); // promote the integer to pointer
+ return ResultTy;
+ }
+ if (lType->isIntegerType() &&
+ (rType->isPointerType() || rType->isObjCQualifiedIdType())) {
+ if (!LHSIsNull)
+ Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ ImpCastExprToType(lex, rType); // promote the integer to pointer
+ return ResultTy;
+ }
+ // Handle block pointers.
+ if (!isRelational && RHSIsNull
+ && lType->isBlockPointerType() && rType->isIntegerType()) {
+ ImpCastExprToType(rex, lType); // promote the integer to pointer
+ return ResultTy;
+ }
+ if (!isRelational && LHSIsNull
+ && lType->isIntegerType() && rType->isBlockPointerType()) {
+ ImpCastExprToType(lex, rType); // promote the integer to pointer
+ return ResultTy;
+ }
+ return InvalidOperands(Loc, lex, rex);
+}
+
+/// 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(Expr *&lex, Expr *&rex,
+ SourceLocation Loc,
+ 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(Loc, lex, rex);
+ if (vType.isNull())
+ return vType;
+
+ QualType lType = lex->getType();
+ QualType rType = rex->getType();
+
+ // 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->isFloatingType()) {
+ if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex->IgnoreParens()))
+ if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex->IgnoreParens()))
+ if (DRL->getDecl() == DRR->getDecl())
+ Diag(Loc, diag::warn_selfcomparison);
+ }
+
+ // Check for comparisons of floating point operands using != and ==.
+ if (!isRelational && lType->isFloatingType()) {
+ assert (rType->isFloatingType());
+ CheckFloatComparison(Loc,lex,rex);
+ }
+
+ // FIXME: Vector compare support in the LLVM backend is not fully reliable,
+ // just reject all vector comparisons for now.
+ if (1) {
+ Diag(Loc, diag::err_typecheck_vector_comparison)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ return QualType();
+ }
+
+ // 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->isIntegerType())
+ return lType;
+
+ const VectorType *VTy = lType->getAsVectorType();
+ unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
+ if (TypeSize == Context.getTypeSize(Context.IntTy))
+ return Context.getExtVectorType(Context.IntTy, VTy->getNumElements());
+ if (TypeSize == Context.getTypeSize(Context.LongTy))
+ return Context.getExtVectorType(Context.LongTy, VTy->getNumElements());
+
+ assert(TypeSize == Context.getTypeSize(Context.LongLongTy) &&
+ "Unhandled vector element size in vector compare");
+ return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements());
+}
+
+inline QualType Sema::CheckBitwiseOperands(
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
+{
+ if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
+ return CheckVectorOperands(Loc, lex, rex);
+
+ QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
+
+ if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType())
+ return compType;
+ return InvalidOperands(Loc, lex, rex);
+}
+
+inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
+ Expr *&lex, Expr *&rex, SourceLocation Loc)
+{
+ UsualUnaryConversions(lex);
+ UsualUnaryConversions(rex);
+
+ if (lex->getType()->isScalarType() && rex->getType()->isScalarType())
+ return Context.IntTy;
+ return InvalidOperands(Loc, lex, rex);
+}
+
+/// IsReadonlyProperty - Verify that otherwise a valid l-value expression
+/// is a read-only property; return true if so. A readonly property expression
+/// depends on various declarations and thus must be treated specially.
+///
+static bool IsReadonlyProperty(Expr *E, Sema &S)
+{
+ if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) {
+ const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E);
+ if (ObjCPropertyDecl *PDecl = PropExpr->getProperty()) {
+ QualType BaseType = PropExpr->getBase()->getType();
+ if (const PointerType *PTy = BaseType->getAsPointerType())
+ if (const ObjCInterfaceType *IFTy =
+ PTy->getPointeeType()->getAsObjCInterfaceType())
+ if (ObjCInterfaceDecl *IFace = IFTy->getDecl())
+ if (S.isPropertyReadonly(PDecl, IFace))
+ return true;
+ }
+ }
+ return false;
+}
+
+/// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not,
+/// emit an error and return true. If so, return false.
+static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
+ SourceLocation OrigLoc = Loc;
+ Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context,
+ &Loc);
+ if (IsLV == Expr::MLV_Valid && IsReadonlyProperty(E, S))
+ IsLV = Expr::MLV_ReadonlyProperty;
+ if (IsLV == Expr::MLV_Valid)
+ return false;
+
+ unsigned Diag = 0;
+ bool NeedType = false;
+ switch (IsLV) { // C99 6.5.16p2
+ default: assert(0 && "Unknown result from isModifiableLvalue!");
+ case Expr::MLV_ConstQualified: Diag = diag::err_typecheck_assign_const; break;
+ case Expr::MLV_ArrayType:
+ Diag = diag::err_typecheck_array_not_modifiable_lvalue;
+ NeedType = true;
+ break;
+ case Expr::MLV_NotObjectType:
+ Diag = diag::err_typecheck_non_object_not_modifiable_lvalue;
+ NeedType = true;
+ break;
+ case Expr::MLV_LValueCast:
+ Diag = diag::err_typecheck_lvalue_casts_not_supported;
+ break;
+ case Expr::MLV_InvalidExpression:
+ Diag = diag::err_typecheck_expression_not_modifiable_lvalue;
+ break;
+ case Expr::MLV_IncompleteType:
+ case Expr::MLV_IncompleteVoidType:
+ return S.RequireCompleteType(Loc, E->getType(),
+ diag::err_typecheck_incomplete_type_not_modifiable_lvalue,
+ E->getSourceRange());
+ case Expr::MLV_DuplicateVectorComponents:
+ Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue;
+ break;
+ case Expr::MLV_NotBlockQualified:
+ Diag = diag::err_block_decl_ref_not_modifiable_lvalue;
+ break;
+ case Expr::MLV_ReadonlyProperty:
+ Diag = diag::error_readonly_property_assignment;
+ break;
+ case Expr::MLV_NoSetterProperty:
+ Diag = diag::error_nosetter_property_assignment;
+ break;
+ }
+
+ SourceRange Assign;
+ if (Loc != OrigLoc)
+ Assign = SourceRange(OrigLoc, OrigLoc);
+ if (NeedType)
+ S.Diag(Loc, Diag) << E->getType() << E->getSourceRange() << Assign;
+ else
+ S.Diag(Loc, Diag) << E->getSourceRange() << Assign;
+ return true;
+}
+
+
+
+// C99 6.5.16.1
+QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
+ SourceLocation Loc,
+ QualType CompoundType) {
+ // Verify that LHS is a modifiable lvalue, and emit error if not.
+ if (CheckForModifiableLvalue(LHS, Loc, *this))
+ return QualType();
+
+ QualType LHSType = LHS->getType();
+ QualType RHSType = CompoundType.isNull() ? RHS->getType() : CompoundType;
+
+ AssignConvertType ConvTy;
+ if (CompoundType.isNull()) {
+ // Simple assignment "x = y".
+ ConvTy = CheckSingleAssignmentConstraints(LHSType, RHS);
+ // Special case of NSObject attributes on c-style pointer types.
+ if (ConvTy == IncompatiblePointer &&
+ ((Context.isObjCNSObjectType(LHSType) &&
+ Context.isObjCObjectPointerType(RHSType)) ||
+ (Context.isObjCNSObjectType(RHSType) &&
+ Context.isObjCObjectPointerType(LHSType))))
+ ConvTy = Compatible;
+
+ // If the RHS is a unary plus or minus, check to see if they = and + are
+ // right next to each other. If so, the user may have typo'd "x =+ 4"
+ // instead of "x += 4".
+ Expr *RHSCheck = RHS;
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(RHSCheck))
+ RHSCheck = ICE->getSubExpr();
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(RHSCheck)) {
+ if ((UO->getOpcode() == UnaryOperator::Plus ||
+ UO->getOpcode() == UnaryOperator::Minus) &&
+ Loc.isFileID() && UO->getOperatorLoc().isFileID() &&
+ // Only if the two operators are exactly adjacent.
+ Loc.getFileLocWithOffset(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() &&
+ UO->getSubExpr()->getLocStart().isFileID()) {
+ Diag(Loc, diag::warn_not_compound_assign)
+ << (UO->getOpcode() == UnaryOperator::Plus ? "+" : "-")
+ << SourceRange(UO->getOperatorLoc(), UO->getOperatorLoc());
+ }
+ }
+ } else {
+ // Compound assignment "x += y"
+ ConvTy = CheckAssignmentConstraints(LHSType, RHSType);
+ }
+
+ if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType,
+ RHS, "assigning"))
+ return QualType();
+
+ // 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.
+ // C99 6.5.16.1p2: In simple assignment, the value of the right operand
+ // is converted to the type of the assignment expression (above).
+ // C++ 5.17p1: the type of the assignment expression is that of its left
+ // operand.
+ return LHSType.getUnqualifiedType();
+}
+
+// C99 6.5.17
+QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) {
+ // Comma performs lvalue conversion (C99 6.3.2.1), but not unary conversions.
+ DefaultFunctionArrayConversion(RHS);
+
+ // FIXME: Check that RHS type is complete in C mode (it's legal for it to be
+ // incomplete in C++).
+
+ return RHS->getType();
+}
+
+/// CheckIncrementDecrementOperand - unlike most "Check" methods, this routine
+/// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions.
+QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
+ bool isInc) {
+ if (Op->isTypeDependent())
+ return Context.DependentTy;
+
+ QualType ResType = Op->getType();
+ assert(!ResType.isNull() && "no type for increment/decrement expression");
+
+ if (getLangOptions().CPlusPlus && ResType->isBooleanType()) {
+ // Decrement of bool is not allowed.
+ if (!isInc) {
+ Diag(OpLoc, diag::err_decrement_bool) << Op->getSourceRange();
+ return QualType();
+ }
+ // Increment of bool sets it to true, but is deprecated.
+ Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange();
+ } else if (ResType->isRealType()) {
+ // OK!
+ } else if (const PointerType *PT = ResType->getAsPointerType()) {
+ // C99 6.5.2.4p2, 6.5.6p2
+ if (PT->getPointeeType()->isVoidType()) {
+ if (getLangOptions().CPlusPlus) {
+ Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type)
+ << Op->getSourceRange();
+ return QualType();
+ }
+
+ // Pointer to void is a GNU extension in C.
+ Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange();
+ } else if (PT->getPointeeType()->isFunctionType()) {
+ if (getLangOptions().CPlusPlus) {
+ Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type)
+ << Op->getType() << Op->getSourceRange();
+ return QualType();
+ }
+
+ Diag(OpLoc, diag::ext_gnu_ptr_func_arith)
+ << ResType << Op->getSourceRange();
+ } else if (RequireCompleteType(OpLoc, PT->getPointeeType(),
+ diag::err_typecheck_arithmetic_incomplete_type,
+ Op->getSourceRange(), SourceRange(),
+ ResType))
+ return QualType();
+ } else if (ResType->isComplexType()) {
+ // C99 does not support ++/-- on complex types, we allow as an extension.
+ Diag(OpLoc, diag::ext_integer_increment_complex)
+ << ResType << Op->getSourceRange();
+ } else {
+ Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement)
+ << ResType << Op->getSourceRange();
+ return QualType();
+ }
+ // At this point, we know we have a real, complex or pointer type.
+ // Now make sure the operand is a modifiable lvalue.
+ if (CheckForModifiableLvalue(Op, OpLoc, *this))
+ return QualType();
+ return ResType;
+}
+
+/// getPrimaryDecl - Helper function for CheckAddressOfOperand().
+/// This routine allows us to typecheck complex/recursive expressions
+/// where the declaration is needed for type checking. We only need to
+/// handle cases when the expression references a function designator
+/// or is an lvalue. Here are some examples:
+/// - &(x) => x
+/// - &*****f => f for f a function designator.
+/// - &s.xx => s
+/// - &s.zz[1].yy -> s, if zz is an array
+/// - *(x + 1) -> x, if x is an array
+/// - &"123"[2] -> 0
+/// - & __real__ x -> x
+static NamedDecl *getPrimaryDecl(Expr *E) {
+ switch (E->getStmtClass()) {
+ case Stmt::DeclRefExprClass:
+ case Stmt::QualifiedDeclRefExprClass:
+ return cast<DeclRefExpr>(E)->getDecl();
+ case Stmt::MemberExprClass:
+ // If this is an arrow operator, the address is an offset from
+ // the base's value, so the object the base refers to is
+ // irrelevant.
+ if (cast<MemberExpr>(E)->isArrow())
+ return 0;
+ // Otherwise, the expression refers to a part of the base
+ return getPrimaryDecl(cast<MemberExpr>(E)->getBase());
+ case Stmt::ArraySubscriptExprClass: {
+ // FIXME: This code shouldn't be necessary! We should catch the implicit
+ // promotion of register arrays earlier.
+ Expr* Base = cast<ArraySubscriptExpr>(E)->getBase();
+ if (ImplicitCastExpr* ICE = dyn_cast<ImplicitCastExpr>(Base)) {
+ if (ICE->getSubExpr()->getType()->isArrayType())
+ return getPrimaryDecl(ICE->getSubExpr());
+ }
+ return 0;
+ }
+ case Stmt::UnaryOperatorClass: {
+ UnaryOperator *UO = cast<UnaryOperator>(E);
+
+ switch(UO->getOpcode()) {
+ case UnaryOperator::Real:
+ case UnaryOperator::Imag:
+ case UnaryOperator::Extension:
+ return getPrimaryDecl(UO->getSubExpr());
+ default:
+ return 0;
+ }
+ }
+ case Stmt::ParenExprClass:
+ return getPrimaryDecl(cast<ParenExpr>(E)->getSubExpr());
+ case Stmt::ImplicitCastExprClass:
+ // If the result of an implicit cast is an l-value, we care about
+ // the sub-expression; otherwise, the result here doesn't matter.
+ return getPrimaryDecl(cast<ImplicitCastExpr>(E)->getSubExpr());
+ default:
+ return 0;
+ }
+}
+
+/// 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.
+/// Note: The usual conversions are *not* applied to the operand of the &
+/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue.
+/// In C++, the operand might be an overloaded function name, in which case
+/// we allow the '&' but retain the overloaded-function type.
+QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
+ // Make sure to ignore parentheses in subsequent checks
+ op = op->IgnoreParens();
+
+ if (op->isTypeDependent())
+ return Context.DependentTy;
+
+ if (getLangOptions().C99) {
+ // Implement C99-only parts of addressof rules.
+ if (UnaryOperator* uOp = dyn_cast<UnaryOperator>(op)) {
+ if (uOp->getOpcode() == UnaryOperator::Deref)
+ // Per C99 6.5.3.2, the address of a deref always returns a valid result
+ // (assuming the deref expression is valid).
+ return uOp->getSubExpr()->getType();
+ }
+ // Technically, there should be a check for array subscript
+ // expressions here, but the result of one is always an lvalue anyway.
+ }
+ NamedDecl *dcl = getPrimaryDecl(op);
+ Expr::isLvalueResult lval = op->isLvalue(Context);
+
+ if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) {
+ // C99 6.5.3.2p1
+ // The operand must be either an l-value or a function designator
+ if (!op->getType()->isFunctionType()) {
+ // FIXME: emit more specific diag...
+ Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
+ << op->getSourceRange();
+ return QualType();
+ }
+ } else if (op->getBitField()) { // C99 6.5.3.2p1
+ // The operand cannot be a bit-field
+ Diag(OpLoc, diag::err_typecheck_address_of)
+ << "bit-field" << op->getSourceRange();
+ return QualType();
+ } else if (isa<ExtVectorElementExpr>(op) || (isa<ArraySubscriptExpr>(op) &&
+ cast<ArraySubscriptExpr>(op)->getBase()->getType()->isVectorType())){
+ // The operand cannot be an element of a vector
+ Diag(OpLoc, diag::err_typecheck_address_of)
+ << "vector element" << op->getSourceRange();
+ return QualType();
+ } 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.
+ if (const VarDecl *vd = dyn_cast<VarDecl>(dcl)) {
+ if (vd->getStorageClass() == VarDecl::Register) {
+ Diag(OpLoc, diag::err_typecheck_address_of)
+ << "register variable" << op->getSourceRange();
+ return QualType();
+ }
+ } else if (isa<OverloadedFunctionDecl>(dcl)) {
+ return Context.OverloadTy;
+ } else if (isa<FieldDecl>(dcl)) {
+ // Okay: we can take the address of a field.
+ // Could be a pointer to member, though, if there is an explicit
+ // scope qualifier for the class.
+ if (isa<QualifiedDeclRefExpr>(op)) {
+ DeclContext *Ctx = dcl->getDeclContext();
+ if (Ctx && Ctx->isRecord())
+ return Context.getMemberPointerType(op->getType(),
+ Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr());
+ }
+ } else if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(dcl)) {
+ // Okay: we can take the address of a function.
+ // As above.
+ if (isa<QualifiedDeclRefExpr>(op) && MD->isInstance())
+ return Context.getMemberPointerType(op->getType(),
+ Context.getTypeDeclType(MD->getParent()).getTypePtr());
+ } else if (!isa<FunctionDecl>(dcl))
+ assert(0 && "Unknown/unexpected decl type");
+ }
+
+ if (lval == Expr::LV_IncompleteVoidType) {
+ // Taking the address of a void variable is technically illegal, but we
+ // allow it in cases which are otherwise valid.
+ // Example: "extern void x; void* y = &x;".
+ Diag(OpLoc, diag::ext_typecheck_addrof_void) << op->getSourceRange();
+ }
+
+ // If the operand has type "type", the result has type "pointer to type".
+ return Context.getPointerType(op->getType());
+}
+
+QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) {
+ if (Op->isTypeDependent())
+ return Context.DependentTy;
+
+ UsualUnaryConversions(Op);
+ QualType Ty = Op->getType();
+
+ // Note that per both C89 and C99, this is always legal, even if ptype is an
+ // incomplete type or void. It would be possible to warn about dereferencing
+ // a void pointer, but it's completely well-defined, and such a warning is
+ // unlikely to catch any mistakes.
+ if (const PointerType *PT = Ty->getAsPointerType())
+ return PT->getPointeeType();
+
+ Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer)
+ << Ty << Op->getSourceRange();
+ return QualType();
+}
+
+static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode(
+ tok::TokenKind Kind) {
+ BinaryOperator::Opcode Opc;
+ switch (Kind) {
+ default: assert(0 && "Unknown binop!");
+ case tok::periodstar: Opc = BinaryOperator::PtrMemD; break;
+ case tok::arrowstar: Opc = BinaryOperator::PtrMemI; break;
+ case tok::star: Opc = BinaryOperator::Mul; break;
+ case tok::slash: Opc = BinaryOperator::Div; break;
+ case tok::percent: Opc = BinaryOperator::Rem; break;
+ case tok::plus: Opc = BinaryOperator::Add; break;
+ case tok::minus: Opc = BinaryOperator::Sub; break;
+ case tok::lessless: Opc = BinaryOperator::Shl; break;
+ case tok::greatergreater: Opc = BinaryOperator::Shr; break;
+ case tok::lessequal: Opc = BinaryOperator::LE; break;
+ case tok::less: Opc = BinaryOperator::LT; break;
+ case tok::greaterequal: Opc = BinaryOperator::GE; break;
+ case tok::greater: Opc = BinaryOperator::GT; break;
+ case tok::exclaimequal: Opc = BinaryOperator::NE; break;
+ case tok::equalequal: Opc = BinaryOperator::EQ; break;
+ case tok::amp: Opc = BinaryOperator::And; break;
+ case tok::caret: Opc = BinaryOperator::Xor; break;
+ case tok::pipe: Opc = BinaryOperator::Or; break;
+ case tok::ampamp: Opc = BinaryOperator::LAnd; break;
+ case tok::pipepipe: Opc = BinaryOperator::LOr; break;
+ case tok::equal: Opc = BinaryOperator::Assign; break;
+ case tok::starequal: Opc = BinaryOperator::MulAssign; break;
+ case tok::slashequal: Opc = BinaryOperator::DivAssign; break;
+ case tok::percentequal: Opc = BinaryOperator::RemAssign; break;
+ case tok::plusequal: Opc = BinaryOperator::AddAssign; break;
+ case tok::minusequal: Opc = BinaryOperator::SubAssign; break;
+ case tok::lesslessequal: Opc = BinaryOperator::ShlAssign; break;
+ case tok::greatergreaterequal: Opc = BinaryOperator::ShrAssign; break;
+ case tok::ampequal: Opc = BinaryOperator::AndAssign; break;
+ case tok::caretequal: Opc = BinaryOperator::XorAssign; break;
+ case tok::pipeequal: Opc = BinaryOperator::OrAssign; break;
+ case tok::comma: Opc = BinaryOperator::Comma; break;
+ }
+ return Opc;
+}
+
+static inline UnaryOperator::Opcode ConvertTokenKindToUnaryOpcode(
+ tok::TokenKind Kind) {
+ UnaryOperator::Opcode Opc;
+ switch (Kind) {
+ default: assert(0 && "Unknown unary op!");
+ case tok::plusplus: Opc = UnaryOperator::PreInc; break;
+ case tok::minusminus: Opc = UnaryOperator::PreDec; break;
+ case tok::amp: Opc = UnaryOperator::AddrOf; break;
+ case tok::star: Opc = UnaryOperator::Deref; break;
+ case tok::plus: Opc = UnaryOperator::Plus; break;
+ case tok::minus: Opc = UnaryOperator::Minus; break;
+ case tok::tilde: Opc = UnaryOperator::Not; break;
+ case tok::exclaim: Opc = UnaryOperator::LNot; break;
+ case tok::kw___real: Opc = UnaryOperator::Real; break;
+ case tok::kw___imag: Opc = UnaryOperator::Imag; break;
+ case tok::kw___extension__: Opc = UnaryOperator::Extension; break;
+ }
+ return Opc;
+}
+
+/// CreateBuiltinBinOp - Creates a new built-in binary operation with
+/// operator @p Opc at location @c TokLoc. This routine only supports
+/// built-in operations; ActOnBinOp handles overloaded operators.
+Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
+ unsigned Op,
+ Expr *lhs, Expr *rhs) {
+ QualType ResultTy; // Result type of the binary operator.
+ BinaryOperator::Opcode Opc = (BinaryOperator::Opcode)Op;
+ // The following two variables are used for compound assignment operators
+ QualType CompLHSTy; // Type of LHS after promotions for computation
+ QualType CompResultTy; // Type of computation result
+
+ switch (Opc) {
+ case BinaryOperator::Assign:
+ ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, QualType());
+ break;
+ case BinaryOperator::PtrMemD:
+ case BinaryOperator::PtrMemI:
+ ResultTy = CheckPointerToMemberOperands(lhs, rhs, OpLoc,
+ Opc == BinaryOperator::PtrMemI);
+ break;
+ case BinaryOperator::Mul:
+ case BinaryOperator::Div:
+ ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc);
+ break;
+ case BinaryOperator::Rem:
+ ResultTy = CheckRemainderOperands(lhs, rhs, OpLoc);
+ break;
+ case BinaryOperator::Add:
+ ResultTy = CheckAdditionOperands(lhs, rhs, OpLoc);
+ break;
+ case BinaryOperator::Sub:
+ ResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc);
+ break;
+ case BinaryOperator::Shl:
+ case BinaryOperator::Shr:
+ ResultTy = CheckShiftOperands(lhs, rhs, OpLoc);
+ break;
+ case BinaryOperator::LE:
+ case BinaryOperator::LT:
+ case BinaryOperator::GE:
+ case BinaryOperator::GT:
+ ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, Opc, true);
+ break;
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, Opc, false);
+ break;
+ case BinaryOperator::And:
+ case BinaryOperator::Xor:
+ case BinaryOperator::Or:
+ ResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc);
+ break;
+ case BinaryOperator::LAnd:
+ case BinaryOperator::LOr:
+ ResultTy = CheckLogicalOperands(lhs, rhs, OpLoc);
+ break;
+ case BinaryOperator::MulAssign:
+ case BinaryOperator::DivAssign:
+ CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true);
+ CompLHSTy = CompResultTy;
+ if (!CompResultTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
+ break;
+ case BinaryOperator::RemAssign:
+ CompResultTy = CheckRemainderOperands(lhs, rhs, OpLoc, true);
+ CompLHSTy = CompResultTy;
+ if (!CompResultTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
+ break;
+ case BinaryOperator::AddAssign:
+ CompResultTy = CheckAdditionOperands(lhs, rhs, OpLoc, &CompLHSTy);
+ if (!CompResultTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
+ break;
+ case BinaryOperator::SubAssign:
+ CompResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc, &CompLHSTy);
+ if (!CompResultTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
+ break;
+ case BinaryOperator::ShlAssign:
+ case BinaryOperator::ShrAssign:
+ CompResultTy = CheckShiftOperands(lhs, rhs, OpLoc, true);
+ CompLHSTy = CompResultTy;
+ if (!CompResultTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
+ break;
+ case BinaryOperator::AndAssign:
+ case BinaryOperator::XorAssign:
+ case BinaryOperator::OrAssign:
+ CompResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc, true);
+ CompLHSTy = CompResultTy;
+ if (!CompResultTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
+ break;
+ case BinaryOperator::Comma:
+ ResultTy = CheckCommaOperands(lhs, rhs, OpLoc);
+ break;
+ }
+ if (ResultTy.isNull())
+ return ExprError();
+ if (CompResultTy.isNull())
+ return Owned(new (Context) BinaryOperator(lhs, rhs, Opc, ResultTy, OpLoc));
+ else
+ return Owned(new (Context) CompoundAssignOperator(lhs, rhs, Opc, ResultTy,
+ CompLHSTy, CompResultTy,
+ OpLoc));
+}
+
+// Binary Operators. 'Tok' is the token for the operator.
+Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
+ tok::TokenKind Kind,
+ ExprArg LHS, ExprArg RHS) {
+ BinaryOperator::Opcode Opc = ConvertTokenKindToBinaryOpcode(Kind);
+ Expr *lhs = LHS.takeAs<Expr>(), *rhs = RHS.takeAs<Expr>();
+
+ assert((lhs != 0) && "ActOnBinOp(): missing left expression");
+ assert((rhs != 0) && "ActOnBinOp(): missing right expression");
+
+ if (getLangOptions().CPlusPlus &&
+ (lhs->getType()->isOverloadableType() ||
+ rhs->getType()->isOverloadableType())) {
+ // Find all of the overloaded operators visible from this
+ // point. We perform both an operator-name lookup from the local
+ // scope and an argument-dependent lookup based on the types of
+ // the arguments.
+ FunctionSet Functions;
+ OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc);
+ if (OverOp != OO_None) {
+ LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
+ Functions);
+ Expr *Args[2] = { lhs, rhs };
+ DeclarationName OpName
+ = Context.DeclarationNames.getCXXOperatorName(OverOp);
+ ArgumentDependentLookup(OpName, Args, 2, Functions);
+ }
+
+ // Build the (potentially-overloaded, potentially-dependent)
+ // binary operation.
+ return CreateOverloadedBinOp(TokLoc, Opc, Functions, lhs, rhs);
+ }
+
+ // Build a built-in binary operation.
+ return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);
+}
+
+Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
+ unsigned OpcIn,
+ ExprArg InputArg) {
+ UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn);
+
+ // FIXME: Input is modified below, but InputArg is not updated appropriately.
+ Expr *Input = (Expr *)InputArg.get();
+ QualType resultType;
+ switch (Opc) {
+ case UnaryOperator::PostInc:
+ case UnaryOperator::PostDec:
+ case UnaryOperator::OffsetOf:
+ assert(false && "Invalid unary operator");
+ break;
+
+ case UnaryOperator::PreInc:
+ case UnaryOperator::PreDec:
+ resultType = CheckIncrementDecrementOperand(Input, OpLoc,
+ Opc == UnaryOperator::PreInc);
+ break;
+ case UnaryOperator::AddrOf:
+ resultType = CheckAddressOfOperand(Input, OpLoc);
+ break;
+ case UnaryOperator::Deref:
+ DefaultFunctionArrayConversion(Input);
+ resultType = CheckIndirectionOperand(Input, OpLoc);
+ break;
+ case UnaryOperator::Plus:
+ case UnaryOperator::Minus:
+ UsualUnaryConversions(Input);
+ resultType = Input->getType();
+ if (resultType->isDependentType())
+ break;
+ if (resultType->isArithmeticType()) // C99 6.5.3.3p1
+ break;
+ else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6-7
+ resultType->isEnumeralType())
+ break;
+ else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6
+ Opc == UnaryOperator::Plus &&
+ resultType->isPointerType())
+ break;
+
+ return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+ << resultType << Input->getSourceRange());
+ case UnaryOperator::Not: // bitwise complement
+ UsualUnaryConversions(Input);
+ resultType = Input->getType();
+ if (resultType->isDependentType())
+ break;
+ // C99 6.5.3.3p1. We allow complex int and float as a GCC extension.
+ if (resultType->isComplexType() || resultType->isComplexIntegerType())
+ // C99 does not support '~' for complex conjugation.
+ Diag(OpLoc, diag::ext_integer_complement_complex)
+ << resultType << Input->getSourceRange();
+ else if (!resultType->isIntegerType())
+ return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+ << resultType << Input->getSourceRange());
+ break;
+ case UnaryOperator::LNot: // logical negation
+ // Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5).
+ DefaultFunctionArrayConversion(Input);
+ resultType = Input->getType();
+ if (resultType->isDependentType())
+ break;
+ if (!resultType->isScalarType()) // C99 6.5.3.3p1
+ return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+ << resultType << Input->getSourceRange());
+ // LNot always has type int. C99 6.5.3.3p5.
+ // In C++, it's bool. C++ 5.3.1p8
+ resultType = getLangOptions().CPlusPlus ? Context.BoolTy : Context.IntTy;
+ break;
+ case UnaryOperator::Real:
+ case UnaryOperator::Imag:
+ resultType = CheckRealImagOperand(Input, OpLoc, Opc == UnaryOperator::Real);
+ break;
+ case UnaryOperator::Extension:
+ resultType = Input->getType();
+ break;
+ }
+ if (resultType.isNull())
+ return ExprError();
+
+ InputArg.release();
+ return Owned(new (Context) UnaryOperator(Input, Opc, resultType, OpLoc));
+}
+
+// Unary Operators. 'Tok' is the token for the operator.
+Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
+ tok::TokenKind Op, ExprArg input) {
+ Expr *Input = (Expr*)input.get();
+ UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op);
+
+ if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType()) {
+ // Find all of the overloaded operators visible from this
+ // point. We perform both an operator-name lookup from the local
+ // scope and an argument-dependent lookup based on the types of
+ // the arguments.
+ FunctionSet Functions;
+ OverloadedOperatorKind OverOp = UnaryOperator::getOverloadedOperator(Opc);
+ if (OverOp != OO_None) {
+ LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
+ Functions);
+ DeclarationName OpName
+ = Context.DeclarationNames.getCXXOperatorName(OverOp);
+ ArgumentDependentLookup(OpName, &Input, 1, Functions);
+ }
+
+ return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input));
+ }
+
+ return CreateBuiltinUnaryOp(OpLoc, Opc, move(input));
+}
+
+/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
+Sema::OwningExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc,
+ SourceLocation LabLoc,
+ IdentifierInfo *LabelII) {
+ // Look up the record for this label identifier.
+ LabelStmt *&LabelDecl = getLabelMap()[LabelII];
+
+ // If we haven't seen this label yet, create a forward reference. It
+ // will be validated and/or cleaned up in ActOnFinishFunctionBody.
+ if (LabelDecl == 0)
+ LabelDecl = new (Context) LabelStmt(LabLoc, LabelII, 0);
+
+ // Create the AST node. The address of a label always has type 'void*'.
+ return Owned(new (Context) AddrLabelExpr(OpLoc, LabLoc, LabelDecl,
+ Context.getPointerType(Context.VoidTy)));
+}
+
+Sema::OwningExprResult
+Sema::ActOnStmtExpr(SourceLocation LPLoc, StmtArg substmt,
+ SourceLocation RPLoc) { // "({..})"
+ Stmt *SubStmt = static_cast<Stmt*>(substmt.get());
+ assert(SubStmt && isa<CompoundStmt>(SubStmt) && "Invalid action invocation!");
+ CompoundStmt *Compound = cast<CompoundStmt>(SubStmt);
+
+ bool isFileScope = getCurFunctionOrMethodDecl() == 0;
+ if (isFileScope)
+ return ExprError(Diag(LPLoc, diag::err_stmtexpr_file_scope));
+
+ // FIXME: there are a variety of strange constraints to enforce here, for
+ // example, it is not possible to goto into a stmt expression apparently.
+ // More semantic analysis is needed.
+
+ // If there are sub stmts in the compound stmt, take the type of the last one
+ // as the type of the stmtexpr.
+ QualType Ty = Context.VoidTy;
+
+ if (!Compound->body_empty()) {
+ Stmt *LastStmt = Compound->body_back();
+ // If LastStmt is a label, skip down through into the body.
+ while (LabelStmt *Label = dyn_cast<LabelStmt>(LastStmt))
+ LastStmt = Label->getSubStmt();
+
+ if (Expr *LastExpr = dyn_cast<Expr>(LastStmt))
+ Ty = LastExpr->getType();
+ }
+
+ // FIXME: Check that expression type is complete/non-abstract; statement
+ // expressions are not lvalues.
+
+ substmt.release();
+ return Owned(new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc));
+}
+
+Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
+ SourceLocation BuiltinLoc,
+ SourceLocation TypeLoc,
+ TypeTy *argty,
+ OffsetOfComponent *CompPtr,
+ unsigned NumComponents,
+ SourceLocation RPLoc) {
+ // FIXME: This function leaks all expressions in the offset components on
+ // error.
+ QualType ArgTy = QualType::getFromOpaquePtr(argty);
+ assert(!ArgTy.isNull() && "Missing type argument!");
+
+ bool Dependent = ArgTy->isDependentType();
+
+ // We must have at least one component that refers to the type, and the first
+ // one is known to be a field designator. Verify that the ArgTy represents
+ // a struct/union/class.
+ if (!Dependent && !ArgTy->isRecordType())
+ return ExprError(Diag(TypeLoc, diag::err_offsetof_record_type) << ArgTy);
+
+ // FIXME: Type must be complete per C99 7.17p3 because a declaring a variable
+ // with an incomplete type would be illegal.
+
+ // Otherwise, create a null pointer as the base, and iteratively process
+ // the offsetof designators.
+ QualType ArgTyPtr = Context.getPointerType(ArgTy);
+ Expr* Res = new (Context) ImplicitValueInitExpr(ArgTyPtr);
+ Res = new (Context) UnaryOperator(Res, UnaryOperator::Deref,
+ ArgTy, SourceLocation());
+
+ // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a
+ // GCC extension, diagnose them.
+ // FIXME: This diagnostic isn't actually visible because the location is in
+ // a system header!
+ if (NumComponents != 1)
+ Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator)
+ << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd);
+
+ if (!Dependent) {
+ bool DidWarnAboutNonPOD = false;
+
+ // FIXME: Dependent case loses a lot of information here. And probably
+ // leaks like a sieve.
+ for (unsigned i = 0; i != NumComponents; ++i) {
+ const OffsetOfComponent &OC = CompPtr[i];
+ if (OC.isBrackets) {
+ // Offset of an array sub-field. TODO: Should we allow vector elements?
+ const ArrayType *AT = Context.getAsArrayType(Res->getType());
+ if (!AT) {
+ Res->Destroy(Context);
+ return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type)
+ << Res->getType());
+ }
+
+ // FIXME: C++: Verify that operator[] isn't overloaded.
+
+ // Promote the array so it looks more like a normal array subscript
+ // expression.
+ DefaultFunctionArrayConversion(Res);
+
+ // C99 6.5.2.1p1
+ Expr *Idx = static_cast<Expr*>(OC.U.E);
+ // FIXME: Leaks Res
+ if (!Idx->isTypeDependent() && !Idx->getType()->isIntegerType())
+ return ExprError(Diag(Idx->getLocStart(),
+ diag::err_typecheck_subscript_not_integer)
+ << Idx->getSourceRange());
+
+ Res = new (Context) ArraySubscriptExpr(Res, Idx, AT->getElementType(),
+ OC.LocEnd);
+ continue;
+ }
+
+ const RecordType *RC = Res->getType()->getAsRecordType();
+ if (!RC) {
+ Res->Destroy(Context);
+ return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type)
+ << Res->getType());
+ }
+
+ // Get the decl corresponding to this.
+ RecordDecl *RD = RC->getDecl();
+ if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
+ if (!CRD->isPOD() && !DidWarnAboutNonPOD) {
+ ExprError(Diag(BuiltinLoc, diag::warn_offsetof_non_pod_type)
+ << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
+ << Res->getType());
+ DidWarnAboutNonPOD = true;
+ }
+ }
+
+ FieldDecl *MemberDecl
+ = dyn_cast_or_null<FieldDecl>(LookupQualifiedName(RD, OC.U.IdentInfo,
+ LookupMemberName)
+ .getAsDecl());
+ // FIXME: Leaks Res
+ if (!MemberDecl)
+ return ExprError(Diag(BuiltinLoc, diag::err_typecheck_no_member)
+ << OC.U.IdentInfo << SourceRange(OC.LocStart, OC.LocEnd));
+
+ // FIXME: C++: Verify that MemberDecl isn't a static field.
+ // FIXME: Verify that MemberDecl isn't a bitfield.
+ if (cast<RecordDecl>(MemberDecl->getDeclContext())->isAnonymousStructOrUnion()) {
+ Res = BuildAnonymousStructUnionMemberReference(
+ SourceLocation(), MemberDecl, Res, SourceLocation()).takeAs<Expr>();
+ } else {
+ // MemberDecl->getType() doesn't get the right qualifiers, but it
+ // doesn't matter here.
+ Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd,
+ MemberDecl->getType().getNonReferenceType());
+ }
+ }
+ }
+
+ return Owned(new (Context) UnaryOperator(Res, UnaryOperator::OffsetOf,
+ Context.getSizeType(), BuiltinLoc));
+}
+
+
+Sema::OwningExprResult Sema::ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
+ TypeTy *arg1,TypeTy *arg2,
+ SourceLocation RPLoc) {
+ QualType argT1 = QualType::getFromOpaquePtr(arg1);
+ QualType argT2 = QualType::getFromOpaquePtr(arg2);
+
+ assert((!argT1.isNull() && !argT2.isNull()) && "Missing type argument(s)");
+
+ if (getLangOptions().CPlusPlus) {
+ Diag(BuiltinLoc, diag::err_types_compatible_p_in_cplusplus)
+ << SourceRange(BuiltinLoc, RPLoc);
+ return ExprError();
+ }
+
+ return Owned(new (Context) TypesCompatibleExpr(Context.IntTy, BuiltinLoc,
+ argT1, argT2, RPLoc));
+}
+
+Sema::OwningExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
+ ExprArg cond,
+ ExprArg expr1, ExprArg expr2,
+ SourceLocation RPLoc) {
+ Expr *CondExpr = static_cast<Expr*>(cond.get());
+ Expr *LHSExpr = static_cast<Expr*>(expr1.get());
+ Expr *RHSExpr = static_cast<Expr*>(expr2.get());
+
+ assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)");
+
+ QualType resType;
+ if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) {
+ resType = Context.DependentTy;
+ } else {
+ // The conditional expression is required to be a constant expression.
+ llvm::APSInt condEval(32);
+ SourceLocation ExpLoc;
+ if (!CondExpr->isIntegerConstantExpr(condEval, Context, &ExpLoc))
+ return ExprError(Diag(ExpLoc,
+ diag::err_typecheck_choose_expr_requires_constant)
+ << CondExpr->getSourceRange());
+
+ // If the condition is > zero, then the AST type is the same as the LSHExpr.
+ resType = condEval.getZExtValue() ? LHSExpr->getType() : RHSExpr->getType();
+ }
+
+ cond.release(); expr1.release(); expr2.release();
+ return Owned(new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr,
+ resType, RPLoc));
+}
+
+//===----------------------------------------------------------------------===//
+// Clang Extensions.
+//===----------------------------------------------------------------------===//
+
+/// ActOnBlockStart - This callback is invoked when a block literal is started.
+void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) {
+ // Analyze block parameters.
+ BlockSemaInfo *BSI = new BlockSemaInfo();
+
+ // Add BSI to CurBlock.
+ BSI->PrevBlockInfo = CurBlock;
+ CurBlock = BSI;
+
+ BSI->ReturnType = 0;
+ BSI->TheScope = BlockScope;
+ BSI->hasBlockDeclRefExprs = false;
+ BSI->SavedFunctionNeedsScopeChecking = CurFunctionNeedsScopeChecking;
+ CurFunctionNeedsScopeChecking = false;
+
+ BSI->TheDecl = BlockDecl::Create(Context, CurContext, CaretLoc);
+ PushDeclContext(BlockScope, BSI->TheDecl);
+}
+
+void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
+ assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!");
+
+ if (ParamInfo.getNumTypeObjects() == 0
+ || ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) {
+ ProcessDeclAttributes(CurBlock->TheDecl, ParamInfo);
+ QualType T = GetTypeForDeclarator(ParamInfo, CurScope);
+
+ if (T->isArrayType()) {
+ Diag(ParamInfo.getSourceRange().getBegin(),
+ diag::err_block_returns_array);
+ return;
+ }
+
+ // The parameter list is optional, if there was none, assume ().
+ if (!T->isFunctionType())
+ T = Context.getFunctionType(T, NULL, 0, 0, 0);
+
+ CurBlock->hasPrototype = true;
+ CurBlock->isVariadic = false;
+ // Check for a valid sentinel attribute on this block.
+ if (CurBlock->TheDecl->getAttr<SentinelAttr>()) {
+ Diag(ParamInfo.getAttributes()->getLoc(),
+ diag::warn_attribute_sentinel_not_variadic) << 1;
+ // FIXME: remove the attribute.
+ }
+ QualType RetTy = T.getTypePtr()->getAsFunctionType()->getResultType();
+
+ // Do not allow returning a objc interface by-value.
+ if (RetTy->isObjCInterfaceType()) {
+ Diag(ParamInfo.getSourceRange().getBegin(),
+ diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
+ return;
+ }
+ return;
+ }
+
+ // Analyze arguments to block.
+ assert(ParamInfo.getTypeObject(0).Kind == DeclaratorChunk::Function &&
+ "Not a function declarator!");
+ DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getTypeObject(0).Fun;
+
+ CurBlock->hasPrototype = FTI.hasPrototype;
+ CurBlock->isVariadic = true;
+
+ // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs function that takes
+ // no arguments, not a function that takes a single void argument.
+ if (FTI.hasPrototype &&
+ FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
+ (!FTI.ArgInfo[0].Param.getAs<ParmVarDecl>()->getType().getCVRQualifiers()&&
+ FTI.ArgInfo[0].Param.getAs<ParmVarDecl>()->getType()->isVoidType())) {
+ // empty arg list, don't push any params.
+ CurBlock->isVariadic = false;
+ } else if (FTI.hasPrototype) {
+ for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
+ CurBlock->Params.push_back(FTI.ArgInfo[i].Param.getAs<ParmVarDecl>());
+ CurBlock->isVariadic = FTI.isVariadic;
+ }
+ CurBlock->TheDecl->setParams(Context, CurBlock->Params.data(),
+ CurBlock->Params.size());
+ CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic);
+ ProcessDeclAttributes(CurBlock->TheDecl, ParamInfo);
+ for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(),
+ E = CurBlock->TheDecl->param_end(); AI != E; ++AI)
+ // If this has an identifier, add it to the scope stack.
+ if ((*AI)->getIdentifier())
+ PushOnScopeChains(*AI, CurBlock->TheScope);
+
+ // Check for a valid sentinel attribute on this block.
+ if (!CurBlock->isVariadic && CurBlock->TheDecl->getAttr<SentinelAttr>()) {
+ Diag(ParamInfo.getAttributes()->getLoc(),
+ diag::warn_attribute_sentinel_not_variadic) << 1;
+ // FIXME: remove the attribute.
+ }
+
+ // Analyze the return type.
+ QualType T = GetTypeForDeclarator(ParamInfo, CurScope);
+ QualType RetTy = T->getAsFunctionType()->getResultType();
+
+ // Do not allow returning a objc interface by-value.
+ if (RetTy->isObjCInterfaceType()) {
+ Diag(ParamInfo.getSourceRange().getBegin(),
+ diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
+ } else if (!RetTy->isDependentType())
+ CurBlock->ReturnType = RetTy.getTypePtr();
+}
+
+/// ActOnBlockError - If there is an error parsing a block, this callback
+/// is invoked to pop the information about the block from the action impl.
+void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {
+ // Ensure that CurBlock is deleted.
+ llvm::OwningPtr<BlockSemaInfo> CC(CurBlock);
+
+ CurFunctionNeedsScopeChecking = CurBlock->SavedFunctionNeedsScopeChecking;
+
+ // Pop off CurBlock, handle nested blocks.
+ PopDeclContext();
+ CurBlock = CurBlock->PrevBlockInfo;
+ // FIXME: Delete the ParmVarDecl objects as well???
+}
+
+/// ActOnBlockStmtExpr - This is called when the body of a block statement
+/// literal was successfully completed. ^(int x){...}
+Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
+ StmtArg body, Scope *CurScope) {
+ // If blocks are disabled, emit an error.
+ if (!LangOpts.Blocks)
+ Diag(CaretLoc, diag::err_blocks_disable);
+
+ // Ensure that CurBlock is deleted.
+ llvm::OwningPtr<BlockSemaInfo> BSI(CurBlock);
+
+ PopDeclContext();
+
+ // Pop off CurBlock, handle nested blocks.
+ CurBlock = CurBlock->PrevBlockInfo;
+
+ QualType RetTy = Context.VoidTy;
+ if (BSI->ReturnType)
+ RetTy = QualType(BSI->ReturnType, 0);
+
+ llvm::SmallVector<QualType, 8> ArgTypes;
+ for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i)
+ ArgTypes.push_back(BSI->Params[i]->getType());
+
+ QualType BlockTy;
+ if (!BSI->hasPrototype)
+ BlockTy = Context.getFunctionNoProtoType(RetTy);
+ else
+ BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(),
+ BSI->isVariadic, 0);
+
+ // FIXME: Check that return/parameter types are complete/non-abstract
+
+ BlockTy = Context.getBlockPointerType(BlockTy);
+
+ // If needed, diagnose invalid gotos and switches in the block.
+ if (CurFunctionNeedsScopeChecking)
+ DiagnoseInvalidJumps(static_cast<CompoundStmt*>(body.get()));
+ CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking;
+
+ BSI->TheDecl->setBody(body.takeAs<CompoundStmt>());
+ return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy,
+ BSI->hasBlockDeclRefExprs));
+}
+
+Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
+ ExprArg expr, TypeTy *type,
+ SourceLocation RPLoc) {
+ QualType T = QualType::getFromOpaquePtr(type);
+ Expr *E = static_cast<Expr*>(expr.get());
+ Expr *OrigExpr = E;
+
+ InitBuiltinVaListType();
+
+ // Get the va_list type
+ QualType VaListType = Context.getBuiltinVaListType();
+ if (VaListType->isArrayType()) {
+ // Deal with implicit array decay; for example, on x86-64,
+ // va_list is an array, but it's supposed to decay to
+ // a pointer for va_arg.
+ VaListType = Context.getArrayDecayedType(VaListType);
+ // Make sure the input expression also decays appropriately.
+ UsualUnaryConversions(E);
+ } else {
+ // Otherwise, the va_list argument must be an l-value because
+ // it is modified by va_arg.
+ if (!E->isTypeDependent() &&
+ CheckForModifiableLvalue(E, BuiltinLoc, *this))
+ return ExprError();
+ }
+
+ if (!E->isTypeDependent() &&
+ !Context.hasSameType(VaListType, E->getType())) {
+ return ExprError(Diag(E->getLocStart(),
+ diag::err_first_argument_to_va_arg_not_of_type_va_list)
+ << OrigExpr->getType() << E->getSourceRange());
+ }
+
+ // FIXME: Check that type is complete/non-abstract
+ // FIXME: Warn if a non-POD type is passed in.
+
+ expr.release();
+ return Owned(new (Context) VAArgExpr(BuiltinLoc, E, T.getNonReferenceType(),
+ RPLoc));
+}
+
+Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
+ // The type of __null will be int or long, depending on the size of
+ // pointers on the target.
+ QualType Ty;
+ if (Context.Target.getPointerWidth(0) == Context.Target.getIntWidth())
+ Ty = Context.IntTy;
+ else
+ Ty = Context.LongTy;
+
+ return Owned(new (Context) GNUNullExpr(Ty, TokenLoc));
+}
+
+bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
+ SourceLocation Loc,
+ QualType DstType, QualType SrcType,
+ Expr *SrcExpr, const char *Flavor) {
+ // Decode the result (notice that AST's are still created for extensions).
+ bool isInvalid = false;
+ unsigned DiagKind;
+ switch (ConvTy) {
+ default: assert(0 && "Unknown conversion type");
+ case Compatible: return false;
+ case PointerToInt:
+ DiagKind = diag::ext_typecheck_convert_pointer_int;
+ break;
+ case IntToPointer:
+ DiagKind = diag::ext_typecheck_convert_int_pointer;
+ break;
+ case IncompatiblePointer:
+ DiagKind = diag::ext_typecheck_convert_incompatible_pointer;
+ break;
+ case IncompatiblePointerSign:
+ DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign;
+ break;
+ case FunctionVoidPointer:
+ DiagKind = diag::ext_typecheck_convert_pointer_void_func;
+ break;
+ case CompatiblePointerDiscardsQualifiers:
+ // If the qualifiers lost were because we were applying the
+ // (deprecated) C++ conversion from a string literal to a char*
+ // (or wchar_t*), then there was no error (C++ 4.2p2). FIXME:
+ // Ideally, this check would be performed in
+ // CheckPointerTypesForAssignment. However, that would require a
+ // bit of refactoring (so that the second argument is an
+ // expression, rather than a type), which should be done as part
+ // of a larger effort to fix CheckPointerTypesForAssignment for
+ // C++ semantics.
+ if (getLangOptions().CPlusPlus &&
+ IsStringLiteralToNonConstPointerConversion(SrcExpr, DstType))
+ return false;
+ DiagKind = diag::ext_typecheck_convert_discards_qualifiers;
+ break;
+ case IntToBlockPointer:
+ DiagKind = diag::err_int_to_block_pointer;
+ break;
+ case IncompatibleBlockPointer:
+ DiagKind = diag::err_typecheck_convert_incompatible_block_pointer;
+ break;
+ case IncompatibleObjCQualifiedId:
+ // FIXME: Diagnose the problem in ObjCQualifiedIdTypesAreCompatible, since
+ // it can give a more specific diagnostic.
+ DiagKind = diag::warn_incompatible_qualified_id;
+ break;
+ case IncompatibleVectors:
+ DiagKind = diag::warn_incompatible_vectors;
+ break;
+ case Incompatible:
+ DiagKind = diag::err_typecheck_convert_incompatible;
+ isInvalid = true;
+ break;
+ }
+
+ Diag(Loc, DiagKind) << DstType << SrcType << Flavor
+ << SrcExpr->getSourceRange();
+ return isInvalid;
+}
+
+bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){
+ llvm::APSInt ICEResult;
+ if (E->isIntegerConstantExpr(ICEResult, Context)) {
+ if (Result)
+ *Result = ICEResult;
+ return false;
+ }
+
+ Expr::EvalResult EvalResult;
+
+ if (!E->Evaluate(EvalResult, Context) || !EvalResult.Val.isInt() ||
+ EvalResult.HasSideEffects) {
+ Diag(E->getExprLoc(), diag::err_expr_not_ice) << E->getSourceRange();
+
+ if (EvalResult.Diag) {
+ // We only show the note if it's not the usual "invalid subexpression"
+ // or if it's actually in a subexpression.
+ if (EvalResult.Diag != diag::note_invalid_subexpr_in_ice ||
+ E->IgnoreParens() != EvalResult.DiagExpr->IgnoreParens())
+ Diag(EvalResult.DiagLoc, EvalResult.Diag);
+ }
+
+ return true;
+ }
+
+ Diag(E->getExprLoc(), diag::ext_expr_not_ice) <<
+ E->getSourceRange();
+
+ if (EvalResult.Diag &&
+ Diags.getDiagnosticLevel(diag::ext_expr_not_ice) != Diagnostic::Ignored)
+ Diag(EvalResult.DiagLoc, EvalResult.Diag);
+
+ if (Result)
+ *Result = EvalResult.Val.getInt();
+ return false;
+}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
new file mode 100644
index 000000000000..65018daff75b
--- /dev/null
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -0,0 +1,1603 @@
+//===--- SemaExprCXX.cpp - Semantic Analysis for Expressions --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for C++ expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SemaInherit.h"
+#include "Sema.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/STLExtras.h"
+using namespace clang;
+
+/// ActOnCXXConversionFunctionExpr - Parse a C++ conversion function
+/// name (e.g., operator void const *) as an expression. This is
+/// very similar to ActOnIdentifierExpr, except that instead of
+/// providing an identifier the parser provides the type of the
+/// conversion function.
+Sema::OwningExprResult
+Sema::ActOnCXXConversionFunctionExpr(Scope *S, SourceLocation OperatorLoc,
+ TypeTy *Ty, bool HasTrailingLParen,
+ const CXXScopeSpec &SS,
+ bool isAddressOfOperand) {
+ QualType ConvType = QualType::getFromOpaquePtr(Ty);
+ QualType ConvTypeCanon = Context.getCanonicalType(ConvType);
+ DeclarationName ConvName
+ = Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon);
+ return ActOnDeclarationNameExpr(S, OperatorLoc, ConvName, HasTrailingLParen,
+ &SS, isAddressOfOperand);
+}
+
+/// ActOnCXXOperatorFunctionIdExpr - Parse a C++ overloaded operator
+/// name (e.g., @c operator+ ) as an expression. This is very
+/// similar to ActOnIdentifierExpr, except that instead of providing
+/// an identifier the parser provides the kind of overloaded
+/// operator that was parsed.
+Sema::OwningExprResult
+Sema::ActOnCXXOperatorFunctionIdExpr(Scope *S, SourceLocation OperatorLoc,
+ OverloadedOperatorKind Op,
+ bool HasTrailingLParen,
+ const CXXScopeSpec &SS,
+ bool isAddressOfOperand) {
+ DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(Op);
+ return ActOnDeclarationNameExpr(S, OperatorLoc, Name, HasTrailingLParen, &SS,
+ isAddressOfOperand);
+}
+
+/// ActOnCXXTypeidOfType - Parse typeid( type-id ).
+Action::OwningExprResult
+Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
+ bool isType, void *TyOrExpr, SourceLocation RParenLoc) {
+ NamespaceDecl *StdNs = GetStdNamespace();
+ if (!StdNs)
+ return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
+
+ IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info");
+ Decl *TypeInfoDecl = LookupQualifiedName(StdNs, TypeInfoII, LookupTagName);
+ RecordDecl *TypeInfoRecordDecl = dyn_cast_or_null<RecordDecl>(TypeInfoDecl);
+ if (!TypeInfoRecordDecl)
+ return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
+
+ QualType TypeInfoType = Context.getTypeDeclType(TypeInfoRecordDecl);
+
+ return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr,
+ TypeInfoType.withConst(),
+ SourceRange(OpLoc, RParenLoc)));
+}
+
+/// ActOnCXXBoolLiteral - Parse {true,false} literals.
+Action::OwningExprResult
+Sema::ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) {
+ assert((Kind == tok::kw_true || Kind == tok::kw_false) &&
+ "Unknown C++ Boolean value!");
+ return Owned(new (Context) CXXBoolLiteralExpr(Kind == tok::kw_true,
+ Context.BoolTy, OpLoc));
+}
+
+/// ActOnCXXNullPtrLiteral - Parse 'nullptr'.
+Action::OwningExprResult
+Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) {
+ return Owned(new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc));
+}
+
+/// ActOnCXXThrow - Parse throw expressions.
+Action::OwningExprResult
+Sema::ActOnCXXThrow(SourceLocation OpLoc, ExprArg E) {
+ Expr *Ex = E.takeAs<Expr>();
+ if (Ex && !Ex->isTypeDependent() && CheckCXXThrowOperand(OpLoc, Ex))
+ return ExprError();
+ return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc));
+}
+
+/// CheckCXXThrowOperand - Validate the operand of a throw.
+bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
+ // C++ [except.throw]p3:
+ // [...] adjusting the type from "array of T" or "function returning T"
+ // to "pointer to T" or "pointer to function returning T", [...]
+ DefaultFunctionArrayConversion(E);
+
+ // If the type of the exception would be an incomplete type or a pointer
+ // to an incomplete type other than (cv) void the program is ill-formed.
+ QualType Ty = E->getType();
+ int isPointer = 0;
+ if (const PointerType* Ptr = Ty->getAsPointerType()) {
+ Ty = Ptr->getPointeeType();
+ isPointer = 1;
+ }
+ if (!isPointer || !Ty->isVoidType()) {
+ if (RequireCompleteType(ThrowLoc, Ty,
+ isPointer ? diag::err_throw_incomplete_ptr
+ : diag::err_throw_incomplete,
+ E->getSourceRange(), SourceRange(), QualType()))
+ return true;
+ }
+
+ // FIXME: Construct a temporary here.
+ return false;
+}
+
+Action::OwningExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) {
+ /// C++ 9.3.2: In the body of a non-static member function, the keyword this
+ /// is a non-lvalue expression whose value is the address of the object for
+ /// which the function is called.
+
+ if (!isa<FunctionDecl>(CurContext))
+ return ExprError(Diag(ThisLoc, diag::err_invalid_this_use));
+
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext))
+ if (MD->isInstance())
+ return Owned(new (Context) CXXThisExpr(ThisLoc,
+ MD->getThisType(Context)));
+
+ return ExprError(Diag(ThisLoc, diag::err_invalid_this_use));
+}
+
+/// ActOnCXXTypeConstructExpr - Parse construction of a specified type.
+/// Can be interpreted either as function-style casting ("int(x)")
+/// or class type construction ("ClassType(x,y,z)")
+/// or creation of a value-initialized type ("int()").
+Action::OwningExprResult
+Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
+ SourceLocation LParenLoc,
+ MultiExprArg exprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ assert(TypeRep && "Missing type!");
+ QualType Ty = QualType::getFromOpaquePtr(TypeRep);
+ unsigned NumExprs = exprs.size();
+ Expr **Exprs = (Expr**)exprs.get();
+ SourceLocation TyBeginLoc = TypeRange.getBegin();
+ SourceRange FullRange = SourceRange(TyBeginLoc, RParenLoc);
+
+ if (Ty->isDependentType() ||
+ CallExpr::hasAnyTypeDependentArguments(Exprs, NumExprs)) {
+ exprs.release();
+
+ return Owned(CXXUnresolvedConstructExpr::Create(Context,
+ TypeRange.getBegin(), Ty,
+ LParenLoc,
+ Exprs, NumExprs,
+ RParenLoc));
+ }
+
+
+ // C++ [expr.type.conv]p1:
+ // 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) {
+ if (CheckCastTypes(TypeRange, Ty, Exprs[0]))
+ return ExprError();
+ exprs.release();
+ return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(),
+ Ty, TyBeginLoc, Exprs[0],
+ RParenLoc));
+ }
+
+ if (const RecordType *RT = Ty->getAsRecordType()) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl());
+
+ // FIXME: We should always create a CXXTemporaryObjectExpr here unless
+ // both the ctor and dtor are trivial.
+ if (NumExprs > 1 || Record->hasUserDeclaredConstructor()) {
+ CXXConstructorDecl *Constructor
+ = PerformInitializationByConstructor(Ty, Exprs, NumExprs,
+ TypeRange.getBegin(),
+ SourceRange(TypeRange.getBegin(),
+ RParenLoc),
+ DeclarationName(),
+ IK_Direct);
+
+ if (!Constructor)
+ return ExprError();
+
+ exprs.release();
+ Expr *E = new (Context) CXXTemporaryObjectExpr(Context, Constructor,
+ Ty, TyBeginLoc, Exprs,
+ NumExprs, RParenLoc);
+ return MaybeBindToTemporary(E);
+ }
+
+ // Fall through to value-initialize an object of class type that
+ // doesn't have a user-declared default constructor.
+ }
+
+ // C++ [expr.type.conv]p1:
+ // If the expression list specifies more than a single value, the type shall
+ // be a class with a suitably declared constructor.
+ //
+ if (NumExprs > 1)
+ return ExprError(Diag(CommaLocs[0],
+ diag::err_builtin_func_cast_more_than_one_arg)
+ << FullRange);
+
+ assert(NumExprs == 0 && "Expected 0 expressions");
+
+ // C++ [expr.type.conv]p2:
+ // The expression T(), where T is a simple-type-specifier for a non-array
+ // complete object type or the (possibly cv-qualified) void type, creates an
+ // rvalue of the specified type, which is value-initialized.
+ //
+ if (Ty->isArrayType())
+ return ExprError(Diag(TyBeginLoc,
+ diag::err_value_init_for_array_type) << FullRange);
+ if (!Ty->isDependentType() && !Ty->isVoidType() &&
+ RequireCompleteType(TyBeginLoc, Ty,
+ diag::err_invalid_incomplete_type_use, FullRange))
+ return ExprError();
+
+ if (RequireNonAbstractType(TyBeginLoc, Ty,
+ diag::err_allocation_of_abstract_type))
+ return ExprError();
+
+ exprs.release();
+ return Owned(new (Context) CXXZeroInitValueExpr(Ty, TyBeginLoc, RParenLoc));
+}
+
+
+/// ActOnCXXNew - Parsed a C++ 'new' expression (C++ 5.3.4), as in e.g.:
+/// @code new (memory) int[size][4] @endcode
+/// or
+/// @code ::new Foo(23, "hello") @endcode
+/// For the interpretation of this heap of arguments, consult the base version.
+Action::OwningExprResult
+Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
+ SourceLocation PlacementLParen, MultiExprArg PlacementArgs,
+ SourceLocation PlacementRParen, bool ParenTypeId,
+ Declarator &D, SourceLocation ConstructorLParen,
+ MultiExprArg ConstructorArgs,
+ SourceLocation ConstructorRParen)
+{
+ Expr *ArraySize = 0;
+ unsigned Skip = 0;
+ // If the specified type is an array, unwrap it and save the expression.
+ if (D.getNumTypeObjects() > 0 &&
+ D.getTypeObject(0).Kind == DeclaratorChunk::Array) {
+ DeclaratorChunk &Chunk = D.getTypeObject(0);
+ if (Chunk.Arr.hasStatic)
+ return ExprError(Diag(Chunk.Loc, diag::err_static_illegal_in_new)
+ << D.getSourceRange());
+ if (!Chunk.Arr.NumElts)
+ return ExprError(Diag(Chunk.Loc, diag::err_array_new_needs_size)
+ << D.getSourceRange());
+ ArraySize = static_cast<Expr*>(Chunk.Arr.NumElts);
+ Skip = 1;
+ }
+
+ QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, Skip);
+ if (D.isInvalidType())
+ return ExprError();
+
+ // Every dimension shall be of constant size.
+ unsigned i = 1;
+ QualType ElementType = AllocType;
+ while (const ArrayType *Array = Context.getAsArrayType(ElementType)) {
+ if (!Array->isConstantArrayType()) {
+ Diag(D.getTypeObject(i).Loc, diag::err_new_array_nonconst)
+ << static_cast<Expr*>(D.getTypeObject(i).Arr.NumElts)->getSourceRange();
+ return ExprError();
+ }
+ ElementType = Array->getElementType();
+ ++i;
+ }
+
+ return BuildCXXNew(StartLoc, UseGlobal,
+ PlacementLParen,
+ move(PlacementArgs),
+ PlacementRParen,
+ ParenTypeId,
+ AllocType,
+ D.getSourceRange().getBegin(),
+ D.getSourceRange(),
+ Owned(ArraySize),
+ ConstructorLParen,
+ move(ConstructorArgs),
+ ConstructorRParen);
+}
+
+Sema::OwningExprResult
+Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
+ SourceLocation PlacementLParen,
+ MultiExprArg PlacementArgs,
+ SourceLocation PlacementRParen,
+ bool ParenTypeId,
+ QualType AllocType,
+ SourceLocation TypeLoc,
+ SourceRange TypeRange,
+ ExprArg ArraySizeE,
+ SourceLocation ConstructorLParen,
+ MultiExprArg ConstructorArgs,
+ SourceLocation ConstructorRParen) {
+ if (CheckAllocatedType(AllocType, TypeLoc, TypeRange))
+ return ExprError();
+
+ QualType ResultType = Context.getPointerType(AllocType);
+
+ // That every array dimension except the first is constant was already
+ // checked by the type check above.
+
+ // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral
+ // or enumeration type with a non-negative value."
+ Expr *ArraySize = (Expr *)ArraySizeE.get();
+ if (ArraySize && !ArraySize->isTypeDependent()) {
+ QualType SizeType = ArraySize->getType();
+ if (!SizeType->isIntegralType() && !SizeType->isEnumeralType())
+ return ExprError(Diag(ArraySize->getSourceRange().getBegin(),
+ diag::err_array_size_not_integral)
+ << SizeType << ArraySize->getSourceRange());
+ // Let's see if this is a constant < 0. If so, we reject it out of hand.
+ // We don't care about special rules, so we tell the machinery it's not
+ // evaluated - it gives us a result in more cases.
+ if (!ArraySize->isValueDependent()) {
+ llvm::APSInt Value;
+ if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) {
+ if (Value < llvm::APSInt(
+ llvm::APInt::getNullValue(Value.getBitWidth()), false))
+ return ExprError(Diag(ArraySize->getSourceRange().getBegin(),
+ diag::err_typecheck_negative_array_size)
+ << ArraySize->getSourceRange());
+ }
+ }
+ }
+
+ FunctionDecl *OperatorNew = 0;
+ FunctionDecl *OperatorDelete = 0;
+ Expr **PlaceArgs = (Expr**)PlacementArgs.get();
+ unsigned NumPlaceArgs = PlacementArgs.size();
+ if (!AllocType->isDependentType() &&
+ !Expr::hasAnyTypeDependentArguments(PlaceArgs, NumPlaceArgs) &&
+ FindAllocationFunctions(StartLoc,
+ SourceRange(PlacementLParen, PlacementRParen),
+ UseGlobal, AllocType, ArraySize, PlaceArgs,
+ NumPlaceArgs, OperatorNew, OperatorDelete))
+ return ExprError();
+
+ bool Init = ConstructorLParen.isValid();
+ // --- Choosing a constructor ---
+ // C++ 5.3.4p15
+ // 1) If T is a POD and there's no initializer (ConstructorLParen is invalid)
+ // the object is not initialized. If the object, or any part of it, is
+ // const-qualified, it's an error.
+ // 2) If T is a POD and there's an empty initializer, the object is value-
+ // initialized.
+ // 3) If T is a POD and there's one initializer argument, the object is copy-
+ // constructed.
+ // 4) If T is a POD and there's more initializer arguments, it's an error.
+ // 5) If T is not a POD, the initializer arguments are used as constructor
+ // arguments.
+ //
+ // Or by the C++0x formulation:
+ // 1) If there's no initializer, the object is default-initialized according
+ // to C++0x rules.
+ // 2) Otherwise, the object is direct-initialized.
+ CXXConstructorDecl *Constructor = 0;
+ Expr **ConsArgs = (Expr**)ConstructorArgs.get();
+ const RecordType *RT;
+ unsigned NumConsArgs = ConstructorArgs.size();
+ if (AllocType->isDependentType()) {
+ // Skip all the checks.
+ }
+ else if ((RT = AllocType->getAsRecordType()) &&
+ !AllocType->isAggregateType()) {
+ Constructor = PerformInitializationByConstructor(
+ AllocType, ConsArgs, NumConsArgs,
+ TypeLoc,
+ SourceRange(TypeLoc, ConstructorRParen),
+ RT->getDecl()->getDeclName(),
+ NumConsArgs != 0 ? IK_Direct : IK_Default);
+ if (!Constructor)
+ return ExprError();
+ } else {
+ if (!Init) {
+ // FIXME: Check that no subpart is const.
+ if (AllocType.isConstQualified())
+ return ExprError(Diag(StartLoc, diag::err_new_uninitialized_const)
+ << TypeRange);
+ } else if (NumConsArgs == 0) {
+ // Object is value-initialized. Do nothing.
+ } else if (NumConsArgs == 1) {
+ // Object is direct-initialized.
+ // FIXME: What DeclarationName do we pass in here?
+ if (CheckInitializerTypes(ConsArgs[0], AllocType, StartLoc,
+ DeclarationName() /*AllocType.getAsString()*/,
+ /*DirectInit=*/true))
+ return ExprError();
+ } else {
+ return ExprError(Diag(StartLoc,
+ diag::err_builtin_direct_init_more_than_one_arg)
+ << SourceRange(ConstructorLParen, ConstructorRParen));
+ }
+ }
+
+ // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16)
+
+ PlacementArgs.release();
+ ConstructorArgs.release();
+ ArraySizeE.release();
+ return Owned(new (Context) CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs,
+ NumPlaceArgs, ParenTypeId, ArraySize, Constructor, Init,
+ ConsArgs, NumConsArgs, OperatorDelete, ResultType,
+ StartLoc, Init ? ConstructorRParen : SourceLocation()));
+}
+
+/// CheckAllocatedType - Checks that a type is suitable as the allocated type
+/// in a new-expression.
+/// dimension off and stores the size expression in ArraySize.
+bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
+ SourceRange R)
+{
+ // C++ 5.3.4p1: "[The] type shall be a complete object type, but not an
+ // abstract class type or array thereof.
+ if (AllocType->isFunctionType())
+ return Diag(Loc, diag::err_bad_new_type)
+ << AllocType << 0 << R;
+ else if (AllocType->isReferenceType())
+ return Diag(Loc, diag::err_bad_new_type)
+ << AllocType << 1 << R;
+ else if (!AllocType->isDependentType() &&
+ RequireCompleteType(Loc, AllocType,
+ diag::err_new_incomplete_type,
+ R))
+ return true;
+ else if (RequireNonAbstractType(Loc, AllocType,
+ diag::err_allocation_of_abstract_type))
+ return true;
+
+ return false;
+}
+
+/// FindAllocationFunctions - Finds the overloads of operator new and delete
+/// that are appropriate for the allocation.
+bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
+ bool UseGlobal, QualType AllocType,
+ bool IsArray, Expr **PlaceArgs,
+ unsigned NumPlaceArgs,
+ FunctionDecl *&OperatorNew,
+ FunctionDecl *&OperatorDelete)
+{
+ // --- Choosing an allocation function ---
+ // C++ 5.3.4p8 - 14 & 18
+ // 1) If UseGlobal is true, only look in the global scope. Else, also look
+ // in the scope of the allocated class.
+ // 2) If an array size is given, look for operator new[], else look for
+ // operator new.
+ // 3) The first argument is always size_t. Append the arguments from the
+ // placement form.
+ // FIXME: Also find the appropriate delete operator.
+
+ llvm::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?
+ AllocArgs[0] = new (Context) IntegerLiteral(llvm::APInt::getNullValue(
+ Context.Target.getPointerWidth(0)),
+ Context.getSizeType(),
+ SourceLocation());
+ std::copy(PlaceArgs, PlaceArgs + NumPlaceArgs, AllocArgs.begin() + 1);
+
+ DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName(
+ IsArray ? OO_Array_New : OO_New);
+ if (AllocType->isRecordType() && !UseGlobal) {
+ CXXRecordDecl *Record
+ = cast<CXXRecordDecl>(AllocType->getAsRecordType()->getDecl());
+ // FIXME: We fail to find inherited overloads.
+ if (FindAllocationOverload(StartLoc, Range, NewName, &AllocArgs[0],
+ AllocArgs.size(), Record, /*AllowMissing=*/true,
+ OperatorNew))
+ return true;
+ }
+ if (!OperatorNew) {
+ // Didn't find a member overload. Look for a global one.
+ DeclareGlobalNewDelete();
+ DeclContext *TUDecl = Context.getTranslationUnitDecl();
+ if (FindAllocationOverload(StartLoc, Range, NewName, &AllocArgs[0],
+ AllocArgs.size(), TUDecl, /*AllowMissing=*/false,
+ OperatorNew))
+ return true;
+ }
+
+ // FindAllocationOverload can change the passed in arguments, so we need to
+ // copy them back.
+ if (NumPlaceArgs > 0)
+ std::copy(&AllocArgs[1], AllocArgs.end(), PlaceArgs);
+
+ // FIXME: This is leaked on error. But so much is currently in Sema that it's
+ // easier to clean it in one go.
+ AllocArgs[0]->Destroy(Context);
+ return false;
+}
+
+/// FindAllocationOverload - Find an fitting overload for the allocation
+/// function in the specified scope.
+bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
+ DeclarationName Name, Expr** Args,
+ unsigned NumArgs, DeclContext *Ctx,
+ bool AllowMissing, FunctionDecl *&Operator)
+{
+ DeclContext::lookup_iterator Alloc, AllocEnd;
+ llvm::tie(Alloc, AllocEnd) = Ctx->lookup(Context, Name);
+ if (Alloc == AllocEnd) {
+ if (AllowMissing)
+ return false;
+ return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
+ << Name << Range;
+ }
+
+ OverloadCandidateSet Candidates;
+ for (; Alloc != AllocEnd; ++Alloc) {
+ // Even member operator new/delete are implicitly treated as
+ // static, so don't use AddMemberCandidate.
+ if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*Alloc))
+ AddOverloadCandidate(Fn, Args, NumArgs, Candidates,
+ /*SuppressUserConversions=*/false);
+ }
+
+ // Do the resolution.
+ OverloadCandidateSet::iterator Best;
+ switch(BestViableFunction(Candidates, Best)) {
+ case OR_Success: {
+ // Got one!
+ FunctionDecl *FnDecl = Best->Function;
+ // The first argument is size_t, and the first parameter must be size_t,
+ // too. This is checked on declaration and can be assumed. (It can't be
+ // asserted on, though, since invalid decls are left in there.)
+ for (unsigned i = 1; i < NumArgs; ++i) {
+ // FIXME: Passing word to diagnostic.
+ if (PerformCopyInitialization(Args[i],
+ FnDecl->getParamDecl(i)->getType(),
+ "passing"))
+ return true;
+ }
+ Operator = FnDecl;
+ return false;
+ }
+
+ case OR_No_Viable_Function:
+ Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
+ << Name << Range;
+ PrintOverloadCandidates(Candidates, /*OnlyViable=*/false);
+ return true;
+
+ case OR_Ambiguous:
+ Diag(StartLoc, diag::err_ovl_ambiguous_call)
+ << Name << Range;
+ PrintOverloadCandidates(Candidates, /*OnlyViable=*/true);
+ return true;
+
+ case OR_Deleted:
+ Diag(StartLoc, diag::err_ovl_deleted_call)
+ << Best->Function->isDeleted()
+ << Name << Range;
+ PrintOverloadCandidates(Candidates, /*OnlyViable=*/true);
+ return true;
+ }
+ assert(false && "Unreachable, bad result from BestViableFunction");
+ return true;
+}
+
+
+/// DeclareGlobalNewDelete - Declare the global forms of operator new and
+/// delete. These are:
+/// @code
+/// void* operator new(std::size_t) throw(std::bad_alloc);
+/// void* operator new[](std::size_t) throw(std::bad_alloc);
+/// void operator delete(void *) throw();
+/// void operator delete[](void *) throw();
+/// @endcode
+/// Note that the placement and nothrow forms of new are *not* implicitly
+/// declared. Their use requires including \<new\>.
+void Sema::DeclareGlobalNewDelete()
+{
+ if (GlobalNewDeleteDeclared)
+ return;
+ GlobalNewDeleteDeclared = true;
+
+ QualType VoidPtr = Context.getPointerType(Context.VoidTy);
+ QualType SizeT = Context.getSizeType();
+
+ // FIXME: Exception specifications are not added.
+ DeclareGlobalAllocationFunction(
+ Context.DeclarationNames.getCXXOperatorName(OO_New),
+ VoidPtr, SizeT);
+ DeclareGlobalAllocationFunction(
+ Context.DeclarationNames.getCXXOperatorName(OO_Array_New),
+ VoidPtr, SizeT);
+ DeclareGlobalAllocationFunction(
+ Context.DeclarationNames.getCXXOperatorName(OO_Delete),
+ Context.VoidTy, VoidPtr);
+ DeclareGlobalAllocationFunction(
+ Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete),
+ Context.VoidTy, VoidPtr);
+}
+
+/// DeclareGlobalAllocationFunction - Declares a single implicit global
+/// allocation function if it doesn't already exist.
+void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
+ QualType Return, QualType Argument)
+{
+ DeclContext *GlobalCtx = Context.getTranslationUnitDecl();
+
+ // Check if this function is already declared.
+ {
+ DeclContext::lookup_iterator Alloc, AllocEnd;
+ for (llvm::tie(Alloc, AllocEnd) = GlobalCtx->lookup(Context, Name);
+ Alloc != AllocEnd; ++Alloc) {
+ // FIXME: Do we need to check for default arguments here?
+ FunctionDecl *Func = cast<FunctionDecl>(*Alloc);
+ if (Func->getNumParams() == 1 &&
+ Context.getCanonicalType(Func->getParamDecl(0)->getType())==Argument)
+ return;
+ }
+ }
+
+ QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0);
+ FunctionDecl *Alloc =
+ FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
+ FnType, FunctionDecl::None, false, true,
+ SourceLocation());
+ Alloc->setImplicit();
+ ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
+ 0, Argument, VarDecl::None, 0);
+ Alloc->setParams(Context, &Param, 1);
+
+ // FIXME: Also add this declaration to the IdentifierResolver, but
+ // make sure it is at the end of the chain to coincide with the
+ // global scope.
+ ((DeclContext *)TUScope->getEntity())->addDecl(Context, Alloc);
+}
+
+/// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in:
+/// @code ::delete ptr; @endcode
+/// or
+/// @code delete [] ptr; @endcode
+Action::OwningExprResult
+Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
+ bool ArrayForm, ExprArg Operand)
+{
+ // C++ 5.3.5p1: "The operand shall have a pointer type, or a class type
+ // having a single conversion function to a pointer type. The result has
+ // type void."
+ // DR599 amends "pointer type" to "pointer to object type" in both cases.
+
+ Expr *Ex = (Expr *)Operand.get();
+ if (!Ex->isTypeDependent()) {
+ QualType Type = Ex->getType();
+
+ if (Type->isRecordType()) {
+ // FIXME: Find that one conversion function and amend the type.
+ }
+
+ if (!Type->isPointerType())
+ return ExprError(Diag(StartLoc, diag::err_delete_operand)
+ << Type << Ex->getSourceRange());
+
+ QualType Pointee = Type->getAsPointerType()->getPointeeType();
+ if (Pointee->isFunctionType() || Pointee->isVoidType())
+ return ExprError(Diag(StartLoc, diag::err_delete_operand)
+ << Type << Ex->getSourceRange());
+ else if (!Pointee->isDependentType() &&
+ RequireCompleteType(StartLoc, Pointee,
+ diag::warn_delete_incomplete,
+ Ex->getSourceRange()))
+ return ExprError();
+
+ // FIXME: Look up the correct operator delete overload and pass a pointer
+ // along.
+ // FIXME: Check access and ambiguity of operator delete and destructor.
+ }
+
+ Operand.release();
+ return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm,
+ 0, Ex, StartLoc));
+}
+
+
+/// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
+/// C++ if/switch/while/for statement.
+/// e.g: "if (int x = f()) {...}"
+Action::OwningExprResult
+Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc,
+ Declarator &D,
+ SourceLocation EqualLoc,
+ ExprArg AssignExprVal) {
+ assert(AssignExprVal.get() && "Null assignment expression");
+
+ // C++ 6.4p2:
+ // The declarator shall not specify a function or an array.
+ // The type-specifier-seq shall not contain typedef and shall not declare a
+ // new class or enumeration.
+
+ assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
+ "Parser allowed 'typedef' as storage class of condition decl.");
+
+ QualType Ty = GetTypeForDeclarator(D, S);
+
+ if (Ty->isFunctionType()) { // The declarator shall not specify a function...
+ // We exit without creating a CXXConditionDeclExpr because a FunctionDecl
+ // would be created and CXXConditionDeclExpr wants a VarDecl.
+ return ExprError(Diag(StartLoc, diag::err_invalid_use_of_function_type)
+ << SourceRange(StartLoc, EqualLoc));
+ } else if (Ty->isArrayType()) { // ...or an array.
+ Diag(StartLoc, diag::err_invalid_use_of_array_type)
+ << SourceRange(StartLoc, EqualLoc);
+ } else if (const RecordType *RT = Ty->getAsRecordType()) {
+ RecordDecl *RD = RT->getDecl();
+ // The type-specifier-seq shall not declare a new class...
+ if (RD->isDefinition() &&
+ (RD->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(RD))))
+ Diag(RD->getLocation(), diag::err_type_defined_in_condition);
+ } else if (const EnumType *ET = Ty->getAsEnumType()) {
+ EnumDecl *ED = ET->getDecl();
+ // ...or enumeration.
+ if (ED->isDefinition() &&
+ (ED->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(ED))))
+ Diag(ED->getLocation(), diag::err_type_defined_in_condition);
+ }
+
+ DeclPtrTy Dcl = ActOnDeclarator(S, D, DeclPtrTy());
+ if (!Dcl)
+ return ExprError();
+ AddInitializerToDecl(Dcl, move(AssignExprVal), /*DirectInit=*/false);
+
+ // Mark this variable as one that is declared within a conditional.
+ // We know that the decl had to be a VarDecl because that is the only type of
+ // decl that can be assigned and the grammar requires an '='.
+ VarDecl *VD = cast<VarDecl>(Dcl.getAs<Decl>());
+ VD->setDeclaredInCondition(true);
+ return Owned(new (Context) CXXConditionDeclExpr(StartLoc, EqualLoc, VD));
+}
+
+/// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid.
+bool Sema::CheckCXXBooleanCondition(Expr *&CondExpr) {
+ // C++ 6.4p4:
+ // The value of a condition that is an initialized declaration in a statement
+ // other than a switch statement is the value of the declared variable
+ // implicitly converted to type bool. If that conversion is ill-formed, the
+ // program is ill-formed.
+ // The value of a condition that is an expression is the value of the
+ // expression, implicitly converted to bool.
+ //
+ return PerformContextuallyConvertToBool(CondExpr);
+}
+
+/// Helper function to determine whether this is the (deprecated) C++
+/// conversion from a string literal to a pointer to non-const char or
+/// non-const wchar_t (for narrow and wide string literals,
+/// respectively).
+bool
+Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
+ // Look inside the implicit cast, if it exists.
+ if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(From))
+ From = Cast->getSubExpr();
+
+ // A string literal (2.13.4) that is not a wide string literal can
+ // be converted to an rvalue of type "pointer to char"; a wide
+ // string literal can be converted to an rvalue of type "pointer
+ // to wchar_t" (C++ 4.2p2).
+ if (StringLiteral *StrLit = dyn_cast<StringLiteral>(From))
+ if (const PointerType *ToPtrType = ToType->getAsPointerType())
+ if (const BuiltinType *ToPointeeType
+ = ToPtrType->getPointeeType()->getAsBuiltinType()) {
+ // This conversion is considered only when there is an
+ // explicit appropriate pointer target type (C++ 4.2p2).
+ if (ToPtrType->getPointeeType().getCVRQualifiers() == 0 &&
+ ((StrLit->isWide() && ToPointeeType->isWideCharType()) ||
+ (!StrLit->isWide() &&
+ (ToPointeeType->getKind() == BuiltinType::Char_U ||
+ ToPointeeType->getKind() == BuiltinType::Char_S))))
+ return true;
+ }
+
+ return false;
+}
+
+/// PerformImplicitConversion - Perform an implicit conversion of the
+/// expression From to the type ToType. Returns true if there was an
+/// error, false otherwise. The expression From is replaced with the
+/// converted expression. Flavor is the kind of conversion we're
+/// performing, used in the error message. If @p AllowExplicit,
+/// explicit user-defined conversions are permitted. @p Elidable should be true
+/// when called for copies which may be elided (C++ 12.8p15). C++0x overload
+/// resolution works differently in that case.
+bool
+Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+ const char *Flavor, bool AllowExplicit,
+ bool Elidable)
+{
+ ImplicitConversionSequence ICS;
+ ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+ if (Elidable && getLangOptions().CPlusPlus0x) {
+ ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions*/false,
+ AllowExplicit, /*ForceRValue*/true);
+ }
+ if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) {
+ ICS = TryImplicitConversion(From, ToType, false, AllowExplicit);
+ }
+ return PerformImplicitConversion(From, ToType, ICS, Flavor);
+}
+
+/// PerformImplicitConversion - Perform an implicit conversion of the
+/// expression From to the type ToType using the pre-computed implicit
+/// conversion sequence ICS. Returns true if there was an error, false
+/// otherwise. The expression From is replaced with the converted
+/// expression. Flavor is the kind of conversion we're performing,
+/// used in the error message.
+bool
+Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+ const ImplicitConversionSequence &ICS,
+ const char* Flavor) {
+ switch (ICS.ConversionKind) {
+ case ImplicitConversionSequence::StandardConversion:
+ if (PerformImplicitConversion(From, ToType, ICS.Standard, Flavor))
+ return true;
+ break;
+
+ case ImplicitConversionSequence::UserDefinedConversion:
+ // FIXME: This is, of course, wrong. We'll need to actually call the
+ // constructor or conversion operator, and then cope with the standard
+ // conversions.
+ ImpCastExprToType(From, ToType.getNonReferenceType(),
+ ToType->isLValueReferenceType());
+ return false;
+
+ case ImplicitConversionSequence::EllipsisConversion:
+ assert(false && "Cannot perform an ellipsis conversion");
+ return false;
+
+ case ImplicitConversionSequence::BadConversion:
+ return true;
+ }
+
+ // Everything went well.
+ return false;
+}
+
+/// PerformImplicitConversion - Perform an implicit conversion of the
+/// expression From to the type ToType by following the standard
+/// conversion sequence SCS. Returns true if there was an error, false
+/// otherwise. The expression From is replaced with the converted
+/// expression. Flavor is the context in which we're performing this
+/// conversion, for use in error messages.
+bool
+Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+ const StandardConversionSequence& SCS,
+ const char *Flavor) {
+ // Overall FIXME: we are recomputing too many types here and doing far too
+ // much extra work. What this means is that we need to keep track of more
+ // information that is computed when we try the implicit conversion initially,
+ // so that we don't need to recompute anything here.
+ QualType FromType = From->getType();
+
+ if (SCS.CopyConstructor) {
+ // FIXME: When can ToType be a reference type?
+ assert(!ToType->isReferenceType());
+
+ // FIXME: Keep track of whether the copy constructor is elidable or not.
+ From = CXXConstructExpr::Create(Context, ToType,
+ SCS.CopyConstructor, false, &From, 1);
+ return false;
+ }
+
+ // Perform the first implicit conversion.
+ switch (SCS.First) {
+ case ICK_Identity:
+ case ICK_Lvalue_To_Rvalue:
+ // Nothing to do.
+ break;
+
+ case ICK_Array_To_Pointer:
+ FromType = Context.getArrayDecayedType(FromType);
+ ImpCastExprToType(From, FromType);
+ break;
+
+ case ICK_Function_To_Pointer:
+ if (Context.getCanonicalType(FromType) == Context.OverloadTy) {
+ FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true);
+ if (!Fn)
+ return true;
+
+ if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin()))
+ return true;
+
+ FixOverloadedFunctionReference(From, Fn);
+ FromType = From->getType();
+ }
+ FromType = Context.getPointerType(FromType);
+ ImpCastExprToType(From, FromType);
+ break;
+
+ default:
+ assert(false && "Improper first standard conversion");
+ break;
+ }
+
+ // Perform the second implicit conversion
+ switch (SCS.Second) {
+ case ICK_Identity:
+ // Nothing to do.
+ break;
+
+ case ICK_Integral_Promotion:
+ case ICK_Floating_Promotion:
+ case ICK_Complex_Promotion:
+ case ICK_Integral_Conversion:
+ case ICK_Floating_Conversion:
+ case ICK_Complex_Conversion:
+ case ICK_Floating_Integral:
+ case ICK_Complex_Real:
+ case ICK_Compatible_Conversion:
+ // FIXME: Go deeper to get the unqualified type!
+ FromType = ToType.getUnqualifiedType();
+ ImpCastExprToType(From, FromType);
+ break;
+
+ case ICK_Pointer_Conversion:
+ if (SCS.IncompatibleObjC) {
+ // Diagnose incompatible Objective-C conversions
+ Diag(From->getSourceRange().getBegin(),
+ diag::ext_typecheck_convert_incompatible_pointer)
+ << From->getType() << ToType << Flavor
+ << From->getSourceRange();
+ }
+
+ if (CheckPointerConversion(From, ToType))
+ return true;
+ ImpCastExprToType(From, ToType);
+ break;
+
+ case ICK_Pointer_Member:
+ if (CheckMemberPointerConversion(From, ToType))
+ return true;
+ ImpCastExprToType(From, ToType);
+ break;
+
+ case ICK_Boolean_Conversion:
+ FromType = Context.BoolTy;
+ ImpCastExprToType(From, FromType);
+ break;
+
+ default:
+ assert(false && "Improper second standard conversion");
+ break;
+ }
+
+ switch (SCS.Third) {
+ case ICK_Identity:
+ // Nothing to do.
+ break;
+
+ case ICK_Qualification:
+ // FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue
+ // references.
+ ImpCastExprToType(From, ToType.getNonReferenceType(),
+ ToType->isLValueReferenceType());
+ break;
+
+ default:
+ assert(false && "Improper second standard conversion");
+ break;
+ }
+
+ return false;
+}
+
+Sema::OwningExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
+ SourceLocation KWLoc,
+ SourceLocation LParen,
+ TypeTy *Ty,
+ SourceLocation RParen) {
+ // FIXME: Some of the type traits have requirements. Interestingly, only the
+ // __is_base_of requirement is explicitly stated to be diagnosed. Indeed, G++
+ // accepts __is_pod(Incomplete) without complaints, and claims that the type
+ // is indeed a POD.
+
+ // There is no point in eagerly computing the value. The traits are designed
+ // to be used from type trait templates, so Ty will be a template parameter
+ // 99% of the time.
+ return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, OTT,
+ QualType::getFromOpaquePtr(Ty),
+ RParen, Context.BoolTy));
+}
+
+QualType Sema::CheckPointerToMemberOperands(
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect)
+{
+ 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->getType();
+ const MemberPointerType *MemPtr = RType->getAsMemberPointerType();
+ if (!MemPtr) {
+ Diag(Loc, diag::err_bad_memptr_rhs)
+ << OpSpelling << RType << rex->getSourceRange();
+ return QualType();
+ }
+
+ QualType Class(MemPtr->getClass(), 0);
+
+ // C++ 5.5p2
+ // [...] 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->getType();
+ if (isIndirect) {
+ if (const PointerType *Ptr = LType->getAsPointerType())
+ LType = Ptr->getPointeeType().getNonReferenceType();
+ else {
+ Diag(Loc, diag::err_bad_memptr_lhs)
+ << OpSpelling << 1 << LType << lex->getSourceRange();
+ return QualType();
+ }
+ }
+
+ if (Context.getCanonicalType(Class).getUnqualifiedType() !=
+ Context.getCanonicalType(LType).getUnqualifiedType()) {
+ BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+ /*DetectVirtual=*/false);
+ // FIXME: Would it be useful to print full ambiguity paths, or is that
+ // overkill?
+ if (!IsDerivedFrom(LType, Class, Paths) ||
+ Paths.isAmbiguous(Context.getCanonicalType(Class))) {
+ Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling
+ << (int)isIndirect << lex->getType() << lex->getSourceRange();
+ return QualType();
+ }
+ }
+
+ // C++ 5.5p2
+ // The result is an object or a function of the type specified by the
+ // second operand.
+ // The cv qualifiers are the union of those in the pointer and the left side,
+ // in accordance with 5.5p5 and 5.2.5.
+ // FIXME: This returns a dereferenced member function pointer as a normal
+ // function type. However, the only operation valid on such functions is
+ // calling them. There's also a GCC extension to get a function pointer to the
+ // thing, which is another complication, because this type - unlike the type
+ // that is the result of this expression - takes the class as the first
+ // argument.
+ // We probably need a "MemberFunctionClosureType" or something like that.
+ QualType Result = MemPtr->getPointeeType();
+ if (LType.isConstQualified())
+ Result.addConst();
+ if (LType.isVolatileQualified())
+ Result.addVolatile();
+ return Result;
+}
+
+/// \brief Get the target type of a standard or user-defined conversion.
+static QualType TargetType(const ImplicitConversionSequence &ICS) {
+ assert((ICS.ConversionKind ==
+ ImplicitConversionSequence::StandardConversion ||
+ ICS.ConversionKind ==
+ ImplicitConversionSequence::UserDefinedConversion) &&
+ "function only valid for standard or user-defined conversions");
+ if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion)
+ return QualType::getFromOpaquePtr(ICS.Standard.ToTypePtr);
+ return QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr);
+}
+
+/// \brief Try to convert a type to another according to C++0x 5.16p3.
+///
+/// This is part of the parameter validation for the ? operator. If either
+/// value operand is a class type, the two operands are attempted to be
+/// converted to each other. This function does the conversion in one direction.
+/// It emits a diagnostic and returns true only if it finds an ambiguous
+/// conversion.
+static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
+ SourceLocation QuestionLoc,
+ ImplicitConversionSequence &ICS)
+{
+ // C++0x 5.16p3
+ // The process for determining whether an operand expression E1 of type T1
+ // can be converted to match an operand expression E2 of type T2 is defined
+ // as follows:
+ // -- If E2 is an lvalue:
+ if (To->isLvalue(Self.Context) == Expr::LV_Valid) {
+ // E1 can be converted to match E2 if E1 can be implicitly converted to
+ // type "lvalue reference to T2", subject to the constraint that in the
+ // conversion the reference must bind directly to E1.
+ if (!Self.CheckReferenceInit(From,
+ Self.Context.getLValueReferenceType(To->getType()),
+ &ICS))
+ {
+ assert((ICS.ConversionKind ==
+ ImplicitConversionSequence::StandardConversion ||
+ ICS.ConversionKind ==
+ ImplicitConversionSequence::UserDefinedConversion) &&
+ "expected a definite conversion");
+ bool DirectBinding =
+ ICS.ConversionKind == ImplicitConversionSequence::StandardConversion ?
+ ICS.Standard.DirectBinding : ICS.UserDefined.After.DirectBinding;
+ if (DirectBinding)
+ return false;
+ }
+ }
+ ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+ // -- If E2 is an rvalue, or if the conversion above cannot be done:
+ // -- if E1 and E2 have class type, and the underlying class types are
+ // the same or one is a base class of the other:
+ QualType FTy = From->getType();
+ QualType TTy = To->getType();
+ const RecordType *FRec = FTy->getAsRecordType();
+ const RecordType *TRec = TTy->getAsRecordType();
+ bool FDerivedFromT = FRec && TRec && Self.IsDerivedFrom(FTy, TTy);
+ if (FRec && TRec && (FRec == TRec ||
+ FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) {
+ // E1 can be converted to match E2 if the class of T2 is the
+ // same type as, or a base class of, the class of T1, and
+ // [cv2 > cv1].
+ if ((FRec == TRec || FDerivedFromT) && TTy.isAtLeastAsQualifiedAs(FTy)) {
+ // Could still fail if there's no copy constructor.
+ // FIXME: Is this a hard error then, or just a conversion failure? The
+ // standard doesn't say.
+ ICS = Self.TryCopyInitialization(From, TTy);
+ }
+ } else {
+ // -- Otherwise: E1 can be converted to match E2 if E1 can be
+ // implicitly converted to the type that expression E2 would have
+ // if E2 were converted to an rvalue.
+ // First find the decayed type.
+ if (TTy->isFunctionType())
+ TTy = Self.Context.getPointerType(TTy);
+ else if(TTy->isArrayType())
+ TTy = Self.Context.getArrayDecayedType(TTy);
+
+ // Now try the implicit conversion.
+ // FIXME: This doesn't detect ambiguities.
+ ICS = Self.TryImplicitConversion(From, TTy);
+ }
+ return false;
+}
+
+/// \brief Try to find a common type for two according to C++0x 5.16p5.
+///
+/// This is part of the parameter validation for the ? operator. If either
+/// value operand is a class type, overload resolution is used to find a
+/// conversion to a common type.
+static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
+ SourceLocation Loc) {
+ Expr *Args[2] = { LHS, RHS };
+ OverloadCandidateSet CandidateSet;
+ Self.AddBuiltinOperatorCandidates(OO_Conditional, Args, 2, CandidateSet);
+
+ OverloadCandidateSet::iterator Best;
+ switch (Self.BestViableFunction(CandidateSet, Best)) {
+ case Sema::OR_Success:
+ // We found a match. Perform the conversions on the arguments and move on.
+ if (Self.PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0],
+ Best->Conversions[0], "converting") ||
+ Self.PerformImplicitConversion(RHS, Best->BuiltinTypes.ParamTypes[1],
+ Best->Conversions[1], "converting"))
+ break;
+ return false;
+
+ case Sema::OR_No_Viable_Function:
+ Self.Diag(Loc, diag::err_typecheck_cond_incompatible_operands)
+ << LHS->getType() << RHS->getType()
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ return true;
+
+ case Sema::OR_Ambiguous:
+ Self.Diag(Loc, diag::err_conditional_ambiguous_ovl)
+ << LHS->getType() << RHS->getType()
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ // FIXME: Print the possible common types by printing the return types of
+ // the viable candidates.
+ break;
+
+ case Sema::OR_Deleted:
+ assert(false && "Conditional operator has only built-in overloads");
+ break;
+ }
+ return true;
+}
+
+/// \brief Perform an "extended" implicit conversion as returned by
+/// TryClassUnification.
+///
+/// TryClassUnification generates ICSs that include reference bindings.
+/// PerformImplicitConversion is not suitable for this; it chokes if the
+/// second part of a standard conversion is ICK_DerivedToBase. This function
+/// handles the reference binding specially.
+static bool ConvertForConditional(Sema &Self, Expr *&E,
+ const ImplicitConversionSequence &ICS)
+{
+ if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion &&
+ ICS.Standard.ReferenceBinding) {
+ assert(ICS.Standard.DirectBinding &&
+ "TryClassUnification should never generate indirect ref bindings");
+ // FIXME: CheckReferenceInit should be able to reuse the ICS instead of
+ // redoing all the work.
+ return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType(
+ TargetType(ICS)));
+ }
+ if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion &&
+ ICS.UserDefined.After.ReferenceBinding) {
+ assert(ICS.UserDefined.After.DirectBinding &&
+ "TryClassUnification should never generate indirect ref bindings");
+ return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType(
+ TargetType(ICS)));
+ }
+ if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, "converting"))
+ return true;
+ return false;
+}
+
+/// \brief Check the operands of ?: under C++ semantics.
+///
+/// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y
+/// extension. In this case, LHS == Cond. (But they're not aliases.)
+QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
+ SourceLocation QuestionLoc) {
+ // FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++
+ // interface pointers.
+
+ // C++0x 5.16p1
+ // The first expression is contextually converted to bool.
+ if (!Cond->isTypeDependent()) {
+ if (CheckCXXBooleanCondition(Cond))
+ return QualType();
+ }
+
+ // Either of the arguments dependent?
+ if (LHS->isTypeDependent() || RHS->isTypeDependent())
+ return Context.DependentTy;
+
+ // C++0x 5.16p2
+ // If either the second or the third operand has type (cv) void, ...
+ QualType LTy = LHS->getType();
+ QualType RTy = RHS->getType();
+ bool LVoid = LTy->isVoidType();
+ bool RVoid = RTy->isVoidType();
+ if (LVoid || RVoid) {
+ // ... then the [l2r] conversions are performed on the second and third
+ // operands ...
+ DefaultFunctionArrayConversion(LHS);
+ DefaultFunctionArrayConversion(RHS);
+ LTy = LHS->getType();
+ RTy = RHS->getType();
+
+ // ... and one of the following shall hold:
+ // -- The second or the third operand (but not both) is a throw-
+ // expression; the result is of the type of the other and is an rvalue.
+ bool LThrow = isa<CXXThrowExpr>(LHS);
+ bool RThrow = isa<CXXThrowExpr>(RHS);
+ if (LThrow && !RThrow)
+ return RTy;
+ if (RThrow && !LThrow)
+ return LTy;
+
+ // -- Both the second and third operands have type void; the result is of
+ // type void and is an rvalue.
+ if (LVoid && RVoid)
+ return Context.VoidTy;
+
+ // Neither holds, error.
+ Diag(QuestionLoc, diag::err_conditional_void_nonvoid)
+ << (LVoid ? RTy : LTy) << (LVoid ? 0 : 1)
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ return QualType();
+ }
+
+ // Neither is void.
+
+ // C++0x 5.16p3
+ // Otherwise, if the second and third operand have different types, and
+ // either has (cv) class type, and attempt is made to convert each of those
+ // operands to the other.
+ if (Context.getCanonicalType(LTy) != Context.getCanonicalType(RTy) &&
+ (LTy->isRecordType() || RTy->isRecordType())) {
+ ImplicitConversionSequence ICSLeftToRight, ICSRightToLeft;
+ // These return true if a single direction is already ambiguous.
+ if (TryClassUnification(*this, LHS, RHS, QuestionLoc, ICSLeftToRight))
+ return QualType();
+ if (TryClassUnification(*this, RHS, LHS, QuestionLoc, ICSRightToLeft))
+ return QualType();
+
+ bool HaveL2R = ICSLeftToRight.ConversionKind !=
+ ImplicitConversionSequence::BadConversion;
+ bool HaveR2L = ICSRightToLeft.ConversionKind !=
+ ImplicitConversionSequence::BadConversion;
+ // If both can be converted, [...] the program is ill-formed.
+ if (HaveL2R && HaveR2L) {
+ Diag(QuestionLoc, diag::err_conditional_ambiguous)
+ << LTy << RTy << LHS->getSourceRange() << RHS->getSourceRange();
+ return QualType();
+ }
+
+ // If exactly one conversion is possible, that conversion is applied to
+ // the chosen operand and the converted operands are used in place of the
+ // original operands for the remainder of this section.
+ if (HaveL2R) {
+ if (ConvertForConditional(*this, LHS, ICSLeftToRight))
+ return QualType();
+ LTy = LHS->getType();
+ } else if (HaveR2L) {
+ if (ConvertForConditional(*this, RHS, ICSRightToLeft))
+ return QualType();
+ RTy = RHS->getType();
+ }
+ }
+
+ // C++0x 5.16p4
+ // If the second and third operands are lvalues and have the same type,
+ // the result is of that type [...]
+ bool Same = Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy);
+ if (Same && LHS->isLvalue(Context) == Expr::LV_Valid &&
+ RHS->isLvalue(Context) == Expr::LV_Valid)
+ return LTy;
+
+ // C++0x 5.16p5
+ // Otherwise, the result is an rvalue. If the second and third operands
+ // do not have the same type, and either has (cv) class type, ...
+ if (!Same && (LTy->isRecordType() || RTy->isRecordType())) {
+ // ... overload resolution is used to determine the conversions (if any)
+ // to be applied to the operands. If the overload resolution fails, the
+ // program is ill-formed.
+ if (FindConditionalOverload(*this, LHS, RHS, QuestionLoc))
+ return QualType();
+ }
+
+ // C++0x 5.16p6
+ // LValue-to-rvalue, array-to-pointer, and function-to-pointer standard
+ // conversions are performed on the second and third operands.
+ DefaultFunctionArrayConversion(LHS);
+ DefaultFunctionArrayConversion(RHS);
+ LTy = LHS->getType();
+ RTy = RHS->getType();
+
+ // After those conversions, one of the following shall hold:
+ // -- The second and third operands have the same type; the result
+ // is of that type.
+ if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy))
+ return LTy;
+
+ // -- The second and third operands have arithmetic or enumeration type;
+ // the usual arithmetic conversions are performed to bring them to a
+ // common type, and the result is of that type.
+ if (LTy->isArithmeticType() && RTy->isArithmeticType()) {
+ UsualArithmeticConversions(LHS, RHS);
+ return LHS->getType();
+ }
+
+ // -- The second and third operands have pointer type, or one has pointer
+ // type and the other is a null pointer constant; pointer conversions
+ // and qualification conversions are performed to bring them to their
+ // composite pointer type. The result is of the composite pointer type.
+ QualType Composite = FindCompositePointerType(LHS, RHS);
+ if (!Composite.isNull())
+ return Composite;
+
+ // Fourth bullet is same for pointers-to-member. However, the possible
+ // conversions are far more limited: we have null-to-pointer, upcast of
+ // containing class, and second-level cv-ness.
+ // cv-ness is not a union, but must match one of the two operands. (Which,
+ // frankly, is stupid.)
+ const MemberPointerType *LMemPtr = LTy->getAsMemberPointerType();
+ const MemberPointerType *RMemPtr = RTy->getAsMemberPointerType();
+ if (LMemPtr && RHS->isNullPointerConstant(Context)) {
+ ImpCastExprToType(RHS, LTy);
+ return LTy;
+ }
+ if (RMemPtr && LHS->isNullPointerConstant(Context)) {
+ ImpCastExprToType(LHS, RTy);
+ return RTy;
+ }
+ if (LMemPtr && RMemPtr) {
+ QualType LPointee = LMemPtr->getPointeeType();
+ QualType RPointee = RMemPtr->getPointeeType();
+ // First, we check that the unqualified pointee type is the same. If it's
+ // not, there's no conversion that will unify the two pointers.
+ if (Context.getCanonicalType(LPointee).getUnqualifiedType() ==
+ Context.getCanonicalType(RPointee).getUnqualifiedType()) {
+ // Second, we take the greater of the two cv qualifications. If neither
+ // is greater than the other, the conversion is not possible.
+ unsigned Q = LPointee.getCVRQualifiers() | RPointee.getCVRQualifiers();
+ if (Q == LPointee.getCVRQualifiers() || Q == RPointee.getCVRQualifiers()){
+ // Third, we check if either of the container classes is derived from
+ // the other.
+ QualType LContainer(LMemPtr->getClass(), 0);
+ QualType RContainer(RMemPtr->getClass(), 0);
+ QualType MoreDerived;
+ if (Context.getCanonicalType(LContainer) ==
+ Context.getCanonicalType(RContainer))
+ MoreDerived = LContainer;
+ else if (IsDerivedFrom(LContainer, RContainer))
+ MoreDerived = LContainer;
+ else if (IsDerivedFrom(RContainer, LContainer))
+ MoreDerived = RContainer;
+
+ if (!MoreDerived.isNull()) {
+ // The type 'Q Pointee (MoreDerived::*)' is the common type.
+ // We don't use ImpCastExprToType here because this could still fail
+ // for ambiguous or inaccessible conversions.
+ QualType Common = Context.getMemberPointerType(
+ LPointee.getQualifiedType(Q), MoreDerived.getTypePtr());
+ if (PerformImplicitConversion(LHS, Common, "converting"))
+ return QualType();
+ if (PerformImplicitConversion(RHS, Common, "converting"))
+ return QualType();
+ return Common;
+ }
+ }
+ }
+ }
+
+ Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
+ << LHS->getType() << RHS->getType()
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ return QualType();
+}
+
+/// \brief Find a merged pointer type and convert the two expressions to it.
+///
+/// This finds the composite pointer type for @p E1 and @p E2 according to
+/// C++0x 5.9p2. It converts both expressions to this type and returns it.
+/// It does not emit diagnostics.
+QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
+ assert(getLangOptions().CPlusPlus && "This function assumes C++");
+ QualType T1 = E1->getType(), T2 = E2->getType();
+ if(!T1->isPointerType() && !T2->isPointerType())
+ return QualType();
+
+ // C++0x 5.9p2
+ // Pointer conversions and qualification conversions are performed on
+ // pointer operands to bring them to their composite pointer type. If
+ // one operand is a null pointer constant, the composite pointer type is
+ // the type of the other operand.
+ if (E1->isNullPointerConstant(Context)) {
+ ImpCastExprToType(E1, T2);
+ return T2;
+ }
+ if (E2->isNullPointerConstant(Context)) {
+ ImpCastExprToType(E2, T1);
+ return T1;
+ }
+ // Now both have to be pointers.
+ if(!T1->isPointerType() || !T2->isPointerType())
+ return QualType();
+
+ // Otherwise, of one of the operands has type "pointer to cv1 void," then
+ // the other has type "pointer to cv2 T" and the composite pointer type is
+ // "pointer to cv12 void," where cv12 is the union of cv1 and cv2.
+ // Otherwise, the composite pointer type is a pointer type similar to the
+ // type of one of the operands, with a cv-qualification signature that is
+ // the union of the cv-qualification signatures of the operand types.
+ // In practice, the first part here is redundant; it's subsumed by the second.
+ // What we do here is, we build the two possible composite types, and try the
+ // conversions in both directions. If only one works, or if the two composite
+ // types are the same, we have succeeded.
+ llvm::SmallVector<unsigned, 4> QualifierUnion;
+ QualType Composite1 = T1, Composite2 = T2;
+ const PointerType *Ptr1, *Ptr2;
+ while ((Ptr1 = Composite1->getAsPointerType()) &&
+ (Ptr2 = Composite2->getAsPointerType())) {
+ Composite1 = Ptr1->getPointeeType();
+ Composite2 = Ptr2->getPointeeType();
+ QualifierUnion.push_back(
+ Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
+ }
+ // Rewrap the composites as pointers with the union CVRs.
+ for (llvm::SmallVector<unsigned, 4>::iterator I = QualifierUnion.begin(),
+ E = QualifierUnion.end(); I != E; ++I) {
+ Composite1 = Context.getPointerType(Composite1.getQualifiedType(*I));
+ Composite2 = Context.getPointerType(Composite2.getQualifiedType(*I));
+ }
+
+ ImplicitConversionSequence E1ToC1 = TryImplicitConversion(E1, Composite1);
+ ImplicitConversionSequence E2ToC1 = TryImplicitConversion(E2, Composite1);
+ ImplicitConversionSequence E1ToC2, E2ToC2;
+ E1ToC2.ConversionKind = ImplicitConversionSequence::BadConversion;
+ E2ToC2.ConversionKind = ImplicitConversionSequence::BadConversion;
+ if (Context.getCanonicalType(Composite1) !=
+ Context.getCanonicalType(Composite2)) {
+ E1ToC2 = TryImplicitConversion(E1, Composite2);
+ E2ToC2 = TryImplicitConversion(E2, Composite2);
+ }
+
+ bool ToC1Viable = E1ToC1.ConversionKind !=
+ ImplicitConversionSequence::BadConversion
+ && E2ToC1.ConversionKind !=
+ ImplicitConversionSequence::BadConversion;
+ bool ToC2Viable = E1ToC2.ConversionKind !=
+ ImplicitConversionSequence::BadConversion
+ && E2ToC2.ConversionKind !=
+ ImplicitConversionSequence::BadConversion;
+ if (ToC1Viable && !ToC2Viable) {
+ if (!PerformImplicitConversion(E1, Composite1, E1ToC1, "converting") &&
+ !PerformImplicitConversion(E2, Composite1, E2ToC1, "converting"))
+ return Composite1;
+ }
+ if (ToC2Viable && !ToC1Viable) {
+ if (!PerformImplicitConversion(E1, Composite2, E1ToC2, "converting") &&
+ !PerformImplicitConversion(E2, Composite2, E2ToC2, "converting"))
+ return Composite2;
+ }
+ return QualType();
+}
+
+Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
+ const RecordType *RT = E->getType()->getAsRecordType();
+ if (!RT)
+ return Owned(E);
+
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (RD->hasTrivialDestructor())
+ return Owned(E);
+
+ CXXTemporary *Temp = CXXTemporary::Create(Context,
+ RD->getDestructor(Context));
+ ExprTemporaries.push_back(Temp);
+
+ // FIXME: Add the temporary to the temporaries vector.
+ return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E));
+}
+
+// FIXME: This doesn't handle casts yet.
+Expr *Sema::RemoveOutermostTemporaryBinding(Expr *E) {
+ const RecordType *RT = E->getType()->getAsRecordType();
+ if (!RT)
+ return E;
+
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (RD->hasTrivialDestructor())
+ return E;
+
+ /// The expr passed in must be a CXXExprWithTemporaries.
+ CXXExprWithTemporaries *TempExpr = dyn_cast<CXXExprWithTemporaries>(E);
+ if (!TempExpr)
+ return E;
+
+ Expr *SubExpr = TempExpr->getSubExpr();
+ if (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(SubExpr)) {
+ assert(BE->getTemporary() ==
+ TempExpr->getTemporary(TempExpr->getNumTemporaries() - 1) &&
+ "Found temporary is not last in list!");
+
+ Expr *BindSubExpr = BE->getSubExpr();
+ BE->setSubExpr(0);
+
+ if (TempExpr->getNumTemporaries() == 1) {
+ // There's just one temporary left, so we don't need the TempExpr node.
+ TempExpr->Destroy(Context);
+ return BindSubExpr;
+ } else {
+ TempExpr->removeLastTemporary();
+ TempExpr->setSubExpr(BindSubExpr);
+ BE->Destroy(Context);
+ }
+
+ return E;
+ }
+
+ // FIXME: We might need to handle other expressions here.
+ return E;
+}
+
+Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
+ Expr *FullExpr = Arg.takeAs<Expr>();
+
+ if (FullExpr && !ExprTemporaries.empty()) {
+ // Create a cleanup expr.
+ FullExpr = CXXExprWithTemporaries::Create(Context, FullExpr,
+ &ExprTemporaries[0],
+ ExprTemporaries.size());
+ ExprTemporaries.clear();
+ }
+
+ return Owned(FullExpr);
+}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
new file mode 100644
index 000000000000..eabc87d7f3b8
--- /dev/null
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -0,0 +1,860 @@
+//===--- SemaExprObjC.cpp - Semantic Analysis for ObjC Expressions --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for Objective-C expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExprObjC.h"
+#include "llvm/ADT/SmallString.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang;
+
+Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
+ ExprTy **strings,
+ unsigned NumStrings) {
+ StringLiteral **Strings = reinterpret_cast<StringLiteral**>(strings);
+
+ // Most ObjC strings are formed out of a single piece. However, we *can*
+ // have strings formed out of multiple @ strings with multiple pptokens in
+ // each one, e.g. @"foo" "bar" @"baz" "qux" which need to be turned into one
+ // StringLiteral for ObjCStringLiteral to hold onto.
+ StringLiteral *S = Strings[0];
+
+ // If we have a multi-part string, merge it all together.
+ if (NumStrings != 1) {
+ // Concatenate objc strings.
+ llvm::SmallString<128> StrBuf;
+ llvm::SmallVector<SourceLocation, 8> StrLocs;
+
+ for (unsigned i = 0; i != NumStrings; ++i) {
+ S = Strings[i];
+
+ // ObjC strings can't be wide.
+ if (S->isWide()) {
+ Diag(S->getLocStart(), diag::err_cfstring_literal_not_string_constant)
+ << S->getSourceRange();
+ return true;
+ }
+
+ // Get the string data.
+ StrBuf.append(S->getStrData(), S->getStrData()+S->getByteLength());
+
+ // Get the locations of the string tokens.
+ StrLocs.append(S->tokloc_begin(), S->tokloc_end());
+
+ // Free the temporary string.
+ S->Destroy(Context);
+ }
+
+ // Create the aggregate string with the appropriate content and location
+ // information.
+ S = StringLiteral::Create(Context, &StrBuf[0], StrBuf.size(), false,
+ Context.getPointerType(Context.CharTy),
+ &StrLocs[0], StrLocs.size());
+ }
+
+ // Verify that this composite string is acceptable for ObjC strings.
+ if (CheckObjCString(S))
+ return true;
+
+ // Initialize the constant string interface lazily. This assumes
+ // the NSString interface is seen in this translation unit. Note: We
+ // don't use NSConstantString, since the runtime team considers this
+ // interface private (even though it appears in the header files).
+ QualType Ty = Context.getObjCConstantStringInterface();
+ if (!Ty.isNull()) {
+ Ty = Context.getPointerType(Ty);
+ } else {
+ IdentifierInfo *NSIdent = &Context.Idents.get("NSString");
+ NamedDecl *IF = LookupName(TUScope, NSIdent, LookupOrdinaryName);
+ if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
+ Context.setObjCConstantStringInterface(StrIF);
+ Ty = Context.getObjCConstantStringInterface();
+ Ty = Context.getPointerType(Ty);
+ } else {
+ // If there is no NSString interface defined then treat constant
+ // strings as untyped objects and let the runtime figure it out later.
+ Ty = Context.getObjCIdType();
+ }
+ }
+
+ return new (Context) ObjCStringLiteral(S, Ty, AtLocs[0]);
+}
+
+Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,
+ SourceLocation EncodeLoc,
+ SourceLocation LParenLoc,
+ TypeTy *ty,
+ SourceLocation RParenLoc) {
+ QualType EncodedType = QualType::getFromOpaquePtr(ty);
+
+ std::string Str;
+ Context.getObjCEncodingForType(EncodedType, Str);
+
+ // The type of @encode is the same as the type of the corresponding string,
+ // which is an array type.
+ QualType StrTy = Context.CharTy;
+ // A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
+ if (getLangOptions().CPlusPlus)
+ StrTy.addConst();
+ StrTy = Context.getConstantArrayType(StrTy, llvm::APInt(32, Str.size()+1),
+ ArrayType::Normal, 0);
+
+ return new (Context) ObjCEncodeExpr(StrTy, EncodedType, AtLoc, RParenLoc);
+}
+
+Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
+ SourceLocation AtLoc,
+ SourceLocation SelLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ QualType Ty = Context.getObjCSelType();
+ return new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, RParenLoc);
+}
+
+Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
+ SourceLocation AtLoc,
+ SourceLocation ProtoLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId);
+ if (!PDecl) {
+ Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId;
+ return true;
+ }
+
+ QualType Ty = Context.getObjCProtoType();
+ if (Ty.isNull())
+ return true;
+ Ty = Context.getPointerType(Ty);
+ return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, RParenLoc);
+}
+
+bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
+ Selector Sel, ObjCMethodDecl *Method,
+ bool isClassMessage,
+ SourceLocation lbrac, SourceLocation rbrac,
+ QualType &ReturnType) {
+ if (!Method) {
+ // Apply default argument promotion as for (C99 6.5.2.2p6).
+ for (unsigned i = 0; i != NumArgs; i++)
+ DefaultArgumentPromotion(Args[i]);
+
+ unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found :
+ diag::warn_inst_method_not_found;
+ Diag(lbrac, DiagID)
+ << Sel << isClassMessage << SourceRange(lbrac, rbrac);
+ ReturnType = Context.getObjCIdType();
+ return false;
+ }
+
+ ReturnType = Method->getResultType();
+
+ unsigned NumNamedArgs = Sel.getNumArgs();
+ assert(NumArgs >= NumNamedArgs && "Too few arguments for selector!");
+
+ bool IsError = false;
+ for (unsigned i = 0; i < NumNamedArgs; i++) {
+ Expr *argExpr = Args[i];
+ assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
+
+ QualType lhsType = Method->param_begin()[i]->getType();
+ QualType rhsType = argExpr->getType();
+
+ // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8].
+ if (lhsType->isArrayType())
+ lhsType = Context.getArrayDecayedType(lhsType);
+ else if (lhsType->isFunctionType())
+ lhsType = Context.getPointerType(lhsType);
+
+ AssignConvertType Result =
+ CheckSingleAssignmentConstraints(lhsType, argExpr);
+ if (Args[i] != argExpr) // The expression was converted.
+ Args[i] = argExpr; // Make sure we store the converted expression.
+
+ IsError |=
+ DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType,
+ argExpr, "sending");
+ }
+
+ // Promote additional arguments to variadic methods.
+ if (Method->isVariadic()) {
+ for (unsigned i = NumNamedArgs; i < NumArgs; ++i)
+ IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod);
+ } else {
+ // Check for extra arguments to non-variadic methods.
+ if (NumArgs != NumNamedArgs) {
+ Diag(Args[NumNamedArgs]->getLocStart(),
+ diag::err_typecheck_call_too_many_args)
+ << 2 /*method*/ << Method->getSourceRange()
+ << SourceRange(Args[NumNamedArgs]->getLocStart(),
+ Args[NumArgs-1]->getLocEnd());
+ }
+ }
+
+ return IsError;
+}
+
+bool Sema::isSelfExpr(Expr *RExpr) {
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RExpr))
+ if (DRE->getDecl()->getIdentifier() == &Context.Idents.get("self"))
+ return true;
+ return false;
+}
+
+// Helper method for ActOnClassMethod/ActOnInstanceMethod.
+// Will search "local" class/category implementations for a method decl.
+// If failed, then we search in class's root for an instance method.
+// Returns 0 if no method is found.
+ObjCMethodDecl *Sema::LookupPrivateClassMethod(Selector Sel,
+ ObjCInterfaceDecl *ClassDecl) {
+ ObjCMethodDecl *Method = 0;
+ // lookup in class and all superclasses
+ while (ClassDecl && !Method) {
+ if (ObjCImplementationDecl *ImpDecl
+ = LookupObjCImplementation(ClassDecl->getIdentifier()))
+ Method = ImpDecl->getClassMethod(Context, Sel);
+
+ // Look through local category implementations associated with the class.
+ if (!Method) {
+ for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Method; i++) {
+ if (ObjCCategoryImpls[i]->getClassInterface() == ClassDecl)
+ Method = ObjCCategoryImpls[i]->getClassMethod(Context, Sel);
+ }
+ }
+
+ // Before we give up, check if the selector is an instance method.
+ // But only in the root. This matches gcc's behaviour and what the
+ // runtime expects.
+ if (!Method && !ClassDecl->getSuperClass()) {
+ Method = ClassDecl->lookupInstanceMethod(Context, Sel);
+ // Look through local category implementations associated
+ // with the root class.
+ if (!Method)
+ Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
+ }
+
+ ClassDecl = ClassDecl->getSuperClass();
+ }
+ return Method;
+}
+
+ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel,
+ ObjCInterfaceDecl *ClassDecl) {
+ ObjCMethodDecl *Method = 0;
+ while (ClassDecl && !Method) {
+ // If we have implementations in scope, check "private" methods.
+ if (ObjCImplementationDecl *ImpDecl
+ = LookupObjCImplementation(ClassDecl->getIdentifier()))
+ Method = ImpDecl->getInstanceMethod(Context, Sel);
+
+ // Look through local category implementations associated with the class.
+ if (!Method) {
+ for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Method; i++) {
+ if (ObjCCategoryImpls[i]->getClassInterface() == ClassDecl)
+ Method = ObjCCategoryImpls[i]->getInstanceMethod(Context, Sel);
+ }
+ }
+ ClassDecl = ClassDecl->getSuperClass();
+ }
+ return Method;
+}
+
+Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
+ IdentifierInfo &receiverName,
+ IdentifierInfo &propertyName,
+ SourceLocation &receiverNameLoc,
+ SourceLocation &propertyNameLoc) {
+
+ ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(&receiverName);
+
+ // Search for a declared property first.
+
+ Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName);
+ ObjCMethodDecl *Getter = IFace->lookupClassMethod(Context, Sel);
+
+ // If this reference is in an @implementation, check for 'private' methods.
+ if (!Getter)
+ if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
+ if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
+ if (ObjCImplementationDecl *ImpDecl
+ = LookupObjCImplementation(ClassDecl->getIdentifier()))
+ Getter = ImpDecl->getClassMethod(Context, Sel);
+
+ if (Getter) {
+ // FIXME: refactor/share with ActOnMemberReference().
+ // Check if we can reference this property.
+ if (DiagnoseUseOfDecl(Getter, propertyNameLoc))
+ return ExprError();
+ }
+
+ // Look for the matching setter, in case it is needed.
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(), &propertyName);
+
+ ObjCMethodDecl *Setter = IFace->lookupClassMethod(Context, SetterSel);
+ if (!Setter) {
+ // If this reference is in an @implementation, also check for 'private'
+ // methods.
+ if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
+ if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
+ if (ObjCImplementationDecl *ImpDecl
+ = LookupObjCImplementation(ClassDecl->getIdentifier()))
+ Setter = ImpDecl->getClassMethod(Context, SetterSel);
+ }
+ // Look through local category implementations associated with the class.
+ if (!Setter) {
+ for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) {
+ if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
+ Setter = ObjCCategoryImpls[i]->getClassMethod(Context, SetterSel);
+ }
+ }
+
+ if (Setter && DiagnoseUseOfDecl(Setter, propertyNameLoc))
+ return ExprError();
+
+ if (Getter || Setter) {
+ QualType PType;
+
+ if (Getter)
+ PType = Getter->getResultType();
+ else {
+ for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
+ E = Setter->param_end(); PI != E; ++PI)
+ PType = (*PI)->getType();
+ }
+ return Owned(new (Context) ObjCKVCRefExpr(Getter, PType, Setter,
+ propertyNameLoc, IFace, receiverNameLoc));
+ }
+ return ExprError(Diag(propertyNameLoc, diag::err_property_not_found)
+ << &propertyName << Context.getObjCInterfaceType(IFace));
+}
+
+
+// ActOnClassMessage - used for both unary and keyword messages.
+// ArgExprs is optional - if it is present, the number of expressions
+// is obtained from Sel.getNumArgs().
+Sema::ExprResult Sema::ActOnClassMessage(
+ Scope *S,
+ IdentifierInfo *receiverName, Selector Sel,
+ SourceLocation lbrac, SourceLocation receiverLoc,
+ SourceLocation selectorLoc, SourceLocation rbrac,
+ ExprTy **Args, unsigned NumArgs)
+{
+ assert(receiverName && "missing receiver class name");
+
+ Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
+ ObjCInterfaceDecl* ClassDecl = 0;
+ bool isSuper = false;
+
+ if (receiverName->isStr("super")) {
+ if (getCurMethodDecl()) {
+ isSuper = true;
+ ObjCInterfaceDecl *OID = getCurMethodDecl()->getClassInterface();
+ if (!OID)
+ return Diag(lbrac, diag::error_no_super_class_message)
+ << getCurMethodDecl()->getDeclName();
+ ClassDecl = OID->getSuperClass();
+ if (!ClassDecl)
+ return Diag(lbrac, diag::error_no_super_class) << OID->getDeclName();
+ if (getCurMethodDecl()->isInstanceMethod()) {
+ QualType superTy = Context.getObjCInterfaceType(ClassDecl);
+ superTy = Context.getPointerType(superTy);
+ ExprResult ReceiverExpr = new (Context) ObjCSuperExpr(SourceLocation(),
+ superTy);
+ // We are really in an instance method, redirect.
+ return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
+ selectorLoc, rbrac, Args, NumArgs);
+ }
+ // We are sending a message to 'super' within a class method. Do nothing,
+ // the receiver will pass through as 'super' (how convenient:-).
+ } else {
+ // 'super' has been used outside a method context. If a variable named
+ // 'super' has been declared, redirect. If not, produce a diagnostic.
+ NamedDecl *SuperDecl = LookupName(S, receiverName, LookupOrdinaryName);
+ ValueDecl *VD = dyn_cast_or_null<ValueDecl>(SuperDecl);
+ if (VD) {
+ ExprResult ReceiverExpr = new (Context) DeclRefExpr(VD, VD->getType(),
+ receiverLoc);
+ // We are really in an instance method, redirect.
+ return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
+ selectorLoc, rbrac, Args, NumArgs);
+ }
+ return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName;
+ }
+ } else
+ ClassDecl = getObjCInterfaceDecl(receiverName);
+
+ // The following code allows for the following GCC-ism:
+ //
+ // typedef XCElementDisplayRect XCElementGraphicsRect;
+ //
+ // @implementation XCRASlice
+ // - whatever { // Note that XCElementGraphicsRect is a typedef name.
+ // _sGraphicsDelegate =[[XCElementGraphicsRect alloc] init];
+ // }
+ //
+ // If necessary, the following lookup could move to getObjCInterfaceDecl().
+ if (!ClassDecl) {
+ NamedDecl *IDecl = LookupName(TUScope, receiverName, LookupOrdinaryName);
+ if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl)) {
+ const ObjCInterfaceType *OCIT;
+ OCIT = OCTD->getUnderlyingType()->getAsObjCInterfaceType();
+ if (!OCIT) {
+ Diag(receiverLoc, diag::err_invalid_receiver_to_message);
+ return true;
+ }
+ ClassDecl = OCIT->getDecl();
+ }
+ }
+ assert(ClassDecl && "missing interface declaration");
+ ObjCMethodDecl *Method = 0;
+ QualType returnType;
+ if (ClassDecl->isForwardDecl()) {
+ // A forward class used in messaging is tread as a 'Class'
+ Diag(lbrac, diag::warn_receiver_forward_class) << ClassDecl->getDeclName();
+ Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac));
+ if (Method)
+ Diag(Method->getLocation(), diag::note_method_sent_forward_class)
+ << Method->getDeclName();
+ }
+ if (!Method)
+ Method = ClassDecl->lookupClassMethod(Context, Sel);
+
+ // If we have an implementation in scope, check "private" methods.
+ if (!Method)
+ Method = LookupPrivateClassMethod(Sel, ClassDecl);
+
+ if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
+ return true;
+
+ if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, true,
+ lbrac, rbrac, returnType))
+ return true;
+
+ returnType = returnType.getNonReferenceType();
+
+ // If we have the ObjCInterfaceDecl* for the class that is receiving the
+ // message, use that to construct the ObjCMessageExpr. Otherwise pass on the
+ // IdentifierInfo* for the class.
+ // FIXME: need to do a better job handling 'super' usage within a class. For
+ // now, we simply pass the "super" identifier through (which isn't consistent
+ // with instance methods.
+ if (isSuper)
+ return new (Context) ObjCMessageExpr(receiverName, Sel, returnType, Method,
+ lbrac, rbrac, ArgExprs, NumArgs);
+ else
+ return new (Context) ObjCMessageExpr(ClassDecl, Sel, returnType, Method,
+ lbrac, rbrac, ArgExprs, NumArgs);
+}
+
+// ActOnInstanceMessage - used for both unary and keyword messages.
+// ArgExprs is optional - if it is present, the number of expressions
+// is obtained from Sel.getNumArgs().
+Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
+ SourceLocation lbrac,
+ SourceLocation receiverLoc,
+ SourceLocation rbrac,
+ ExprTy **Args, unsigned NumArgs) {
+ assert(receiver && "missing receiver expression");
+
+ Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
+ Expr *RExpr = static_cast<Expr *>(receiver);
+
+ // If necessary, apply function/array conversion to the receiver.
+ // C99 6.7.5.3p[7,8].
+ DefaultFunctionArrayConversion(RExpr);
+
+ QualType returnType;
+ QualType ReceiverCType =
+ Context.getCanonicalType(RExpr->getType()).getUnqualifiedType();
+
+ // Handle messages to 'super'.
+ if (isa<ObjCSuperExpr>(RExpr)) {
+ ObjCMethodDecl *Method = 0;
+ if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
+ // If we have an interface in scope, check 'super' methods.
+ if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
+ if (ObjCInterfaceDecl *SuperDecl = ClassDecl->getSuperClass()) {
+ Method = SuperDecl->lookupInstanceMethod(Context, Sel);
+
+ if (!Method)
+ // If we have implementations in scope, check "private" methods.
+ Method = LookupPrivateInstanceMethod(Sel, SuperDecl);
+ }
+ }
+
+ if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
+ return true;
+
+ if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
+ lbrac, rbrac, returnType))
+ return true;
+
+ returnType = returnType.getNonReferenceType();
+ return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac,
+ rbrac, ArgExprs, NumArgs);
+ }
+
+ // Handle messages to id.
+ if (ReceiverCType == Context.getCanonicalType(Context.getObjCIdType()) ||
+ ReceiverCType->isBlockPointerType() ||
+ Context.isObjCNSObjectType(RExpr->getType())) {
+ ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(
+ Sel, SourceRange(lbrac,rbrac));
+ if (!Method)
+ Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac, rbrac));
+ if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
+ lbrac, rbrac, returnType))
+ return true;
+ returnType = returnType.getNonReferenceType();
+ return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac,
+ rbrac, ArgExprs, NumArgs);
+ }
+
+ // Handle messages to Class.
+ if (ReceiverCType == Context.getCanonicalType(Context.getObjCClassType())) {
+ ObjCMethodDecl *Method = 0;
+
+ if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
+ if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) {
+ // First check the public methods in the class interface.
+ Method = ClassDecl->lookupClassMethod(Context, Sel);
+
+ if (!Method)
+ Method = LookupPrivateClassMethod(Sel, ClassDecl);
+ }
+ if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
+ return true;
+ }
+ if (!Method) {
+ // If not messaging 'self', look for any factory method named 'Sel'.
+ if (!isSelfExpr(RExpr)) {
+ Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac));
+ if (!Method) {
+ // If no class (factory) method was found, check if an _instance_
+ // method of the same name exists in the root class only.
+ Method = LookupInstanceMethodInGlobalPool(
+ Sel, SourceRange(lbrac,rbrac));
+ if (Method)
+ if (const ObjCInterfaceDecl *ID =
+ dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) {
+ if (ID->getSuperClass())
+ Diag(lbrac, diag::warn_root_inst_method_not_found)
+ << Sel << SourceRange(lbrac, rbrac);
+ }
+ }
+ }
+ }
+ if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
+ lbrac, rbrac, returnType))
+ return true;
+ returnType = returnType.getNonReferenceType();
+ return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac,
+ rbrac, ArgExprs, NumArgs);
+ }
+
+ ObjCMethodDecl *Method = 0;
+ ObjCInterfaceDecl* ClassDecl = 0;
+
+ // We allow sending a message to a qualified ID ("id<foo>"), which is ok as
+ // long as one of the protocols implements the selector (if not, warn).
+ if (ObjCQualifiedIdType *QIdTy = dyn_cast<ObjCQualifiedIdType>(ReceiverCType)) {
+ // Search protocols for instance methods.
+ for (ObjCQualifiedIdType::qual_iterator I = QIdTy->qual_begin(),
+ E = QIdTy->qual_end(); I != E; ++I) {
+ ObjCProtocolDecl *PDecl = *I;
+ if (PDecl && (Method = PDecl->lookupInstanceMethod(Context, Sel)))
+ break;
+ // Since we aren't supporting "Class<foo>", look for a class method.
+ if (PDecl && (Method = PDecl->lookupClassMethod(Context, Sel)))
+ break;
+ }
+ } else if (const ObjCInterfaceType *OCIType =
+ ReceiverCType->getAsPointerToObjCInterfaceType()) {
+ // We allow sending a message to a pointer to an interface (an object).
+
+ ClassDecl = OCIType->getDecl();
+ // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
+ // faster than the following method (which can do *many* linear searches).
+ // The idea is to add class info to InstanceMethodPool.
+ Method = ClassDecl->lookupInstanceMethod(Context, Sel);
+
+ if (!Method) {
+ // Search protocol qualifiers.
+ for (ObjCQualifiedInterfaceType::qual_iterator QI = OCIType->qual_begin(),
+ E = OCIType->qual_end(); QI != E; ++QI) {
+ if ((Method = (*QI)->lookupInstanceMethod(Context, Sel)))
+ break;
+ }
+ }
+ if (!Method) {
+ // If we have implementations in scope, check "private" methods.
+ Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
+
+ if (!Method && !isSelfExpr(RExpr)) {
+ // If we still haven't found a method, look in the global pool. This
+ // behavior isn't very desirable, however we need it for GCC
+ // compatibility. FIXME: should we deviate??
+ if (OCIType->qual_empty()) {
+ Method = LookupInstanceMethodInGlobalPool(
+ Sel, SourceRange(lbrac,rbrac));
+ if (Method && !OCIType->getDecl()->isForwardDecl())
+ Diag(lbrac, diag::warn_maynot_respond)
+ << OCIType->getDecl()->getIdentifier()->getName() << Sel;
+ }
+ }
+ }
+ if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
+ return true;
+ } else if (!Context.getObjCIdType().isNull() &&
+ (ReceiverCType->isPointerType() ||
+ (ReceiverCType->isIntegerType() &&
+ ReceiverCType->isScalarType()))) {
+ // Implicitly convert integers and pointers to 'id' but emit a warning.
+ Diag(lbrac, diag::warn_bad_receiver_type)
+ << RExpr->getType() << RExpr->getSourceRange();
+ ImpCastExprToType(RExpr, Context.getObjCIdType());
+ } else {
+ // Reject other random receiver types (e.g. structs).
+ Diag(lbrac, diag::err_bad_receiver_type)
+ << RExpr->getType() << RExpr->getSourceRange();
+ return true;
+ }
+
+ if (Method)
+ DiagnoseSentinelCalls(Method, receiverLoc, ArgExprs, NumArgs);
+ if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
+ lbrac, rbrac, returnType))
+ return true;
+ returnType = returnType.getNonReferenceType();
+ return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac,
+ rbrac, ArgExprs, NumArgs);
+}
+
+//===----------------------------------------------------------------------===//
+// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's.
+//===----------------------------------------------------------------------===//
+
+/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the
+/// inheritance hierarchy of 'rProto'.
+static bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
+ ObjCProtocolDecl *rProto) {
+ if (lProto == rProto)
+ return true;
+ for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(),
+ E = rProto->protocol_end(); PI != E; ++PI)
+ if (ProtocolCompatibleWithProtocol(lProto, *PI))
+ return true;
+ return false;
+}
+
+/// ClassImplementsProtocol - Checks that 'lProto' protocol
+/// has been implemented in IDecl class, its super class or categories (if
+/// lookupCategory is true).
+static bool ClassImplementsProtocol(ObjCProtocolDecl *lProto,
+ ObjCInterfaceDecl *IDecl,
+ bool lookupCategory,
+ bool RHSIsQualifiedID = false) {
+
+ // 1st, look up the class.
+ const ObjCList<ObjCProtocolDecl> &Protocols =
+ IDecl->getReferencedProtocols();
+
+ for (ObjCList<ObjCProtocolDecl>::iterator PI = Protocols.begin(),
+ E = Protocols.end(); PI != E; ++PI) {
+ if (ProtocolCompatibleWithProtocol(lProto, *PI))
+ return true;
+ // This is dubious and is added to be compatible with gcc. In gcc, it is
+ // also allowed assigning a protocol-qualified 'id' type to a LHS object
+ // when protocol in qualified LHS is in list of protocols in the rhs 'id'
+ // object. This IMO, should be a bug.
+ // FIXME: Treat this as an extension, and flag this as an error when GCC
+ // extensions are not enabled.
+ if (RHSIsQualifiedID && ProtocolCompatibleWithProtocol(*PI, lProto))
+ return true;
+ }
+
+ // 2nd, look up the category.
+ if (lookupCategory)
+ for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl;
+ CDecl = CDecl->getNextClassCategory()) {
+ for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(),
+ E = CDecl->protocol_end(); PI != E; ++PI)
+ if (ProtocolCompatibleWithProtocol(lProto, *PI))
+ return true;
+ }
+
+ // 3rd, look up the super class(s)
+ if (IDecl->getSuperClass())
+ return
+ ClassImplementsProtocol(lProto, IDecl->getSuperClass(), lookupCategory,
+ RHSIsQualifiedID);
+
+ return false;
+}
+
+/// QualifiedIdConformsQualifiedId - compare id<p,...> with id<p1,...>
+/// return true if lhs's protocols conform to rhs's protocol; false
+/// otherwise.
+bool Sema::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) {
+ if (lhs->isObjCQualifiedIdType() && rhs->isObjCQualifiedIdType())
+ return ObjCQualifiedIdTypesAreCompatible(lhs, rhs, false);
+ return false;
+}
+
+/// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an
+/// ObjCQualifiedIDType.
+/// FIXME: Move to ASTContext::typesAreCompatible() and friends.
+bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
+ bool compare) {
+ // Allow id<P..> and an 'id' or void* type in all cases.
+ if (const PointerType *PT = lhs->getAsPointerType()) {
+ QualType PointeeTy = PT->getPointeeType();
+ if (PointeeTy->isVoidType() ||
+ Context.isObjCIdStructType(PointeeTy) ||
+ Context.isObjCClassStructType(PointeeTy))
+ return true;
+ } else if (const PointerType *PT = rhs->getAsPointerType()) {
+ QualType PointeeTy = PT->getPointeeType();
+ if (PointeeTy->isVoidType() ||
+ Context.isObjCIdStructType(PointeeTy) ||
+ Context.isObjCClassStructType(PointeeTy))
+ return true;
+ }
+
+ if (const ObjCQualifiedIdType *lhsQID = lhs->getAsObjCQualifiedIdType()) {
+ const ObjCQualifiedIdType *rhsQID = rhs->getAsObjCQualifiedIdType();
+ const ObjCQualifiedInterfaceType *rhsQI = 0;
+ QualType rtype;
+
+ if (!rhsQID) {
+ // Not comparing two ObjCQualifiedIdType's?
+ if (!rhs->isPointerType()) return false;
+
+ rtype = rhs->getAsPointerType()->getPointeeType();
+ rhsQI = rtype->getAsObjCQualifiedInterfaceType();
+ if (rhsQI == 0) {
+ // If the RHS is a unqualified interface pointer "NSString*",
+ // make sure we check the class hierarchy.
+ if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) {
+ ObjCInterfaceDecl *rhsID = IT->getDecl();
+ for (ObjCQualifiedIdType::qual_iterator I = lhsQID->qual_begin(),
+ E = lhsQID->qual_end(); I != E; ++I) {
+ // when comparing an id<P> on lhs with a static type on rhs,
+ // see if static class implements all of id's protocols, directly or
+ // through its super class and categories.
+ if (!ClassImplementsProtocol(*I, rhsID, true))
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+
+ ObjCQualifiedIdType::qual_iterator RHSProtoI, RHSProtoE;
+ if (rhsQI) { // We have a qualified interface (e.g. "NSObject<Proto> *").
+ RHSProtoI = rhsQI->qual_begin();
+ RHSProtoE = rhsQI->qual_end();
+ } else if (rhsQID) { // We have a qualified id (e.g. "id<Proto> *").
+ RHSProtoI = rhsQID->qual_begin();
+ RHSProtoE = rhsQID->qual_end();
+ } else {
+ return false;
+ }
+
+ for (ObjCQualifiedIdType::qual_iterator I = lhsQID->qual_begin(),
+ E = lhsQID->qual_end(); I != E; ++I) {
+ ObjCProtocolDecl *lhsProto = *I;
+ bool match = false;
+
+ // when comparing an id<P> on lhs with a static type on rhs,
+ // see if static class implements all of id's protocols, directly or
+ // through its super class and categories.
+ for (; RHSProtoI != RHSProtoE; ++RHSProtoI) {
+ ObjCProtocolDecl *rhsProto = *RHSProtoI;
+ if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
+ (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
+ match = true;
+ break;
+ }
+ }
+ if (rhsQI) {
+ // If the RHS is a qualified interface pointer "NSString<P>*",
+ // make sure we check the class hierarchy.
+ if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) {
+ ObjCInterfaceDecl *rhsID = IT->getDecl();
+ for (ObjCQualifiedIdType::qual_iterator I = lhsQID->qual_begin(),
+ E = lhsQID->qual_end(); I != E; ++I) {
+ // when comparing an id<P> on lhs with a static type on rhs,
+ // see if static class implements all of id's protocols, directly or
+ // through its super class and categories.
+ if (ClassImplementsProtocol(*I, rhsID, true)) {
+ match = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!match)
+ return false;
+ }
+
+ return true;
+ }
+
+ const ObjCQualifiedIdType *rhsQID = rhs->getAsObjCQualifiedIdType();
+ assert(rhsQID && "One of the LHS/RHS should be id<x>");
+
+ if (!lhs->isPointerType())
+ return false;
+
+ QualType ltype = lhs->getAsPointerType()->getPointeeType();
+ if (const ObjCQualifiedInterfaceType *lhsQI =
+ ltype->getAsObjCQualifiedInterfaceType()) {
+ ObjCQualifiedIdType::qual_iterator LHSProtoI = lhsQI->qual_begin();
+ ObjCQualifiedIdType::qual_iterator LHSProtoE = lhsQI->qual_end();
+ for (; LHSProtoI != LHSProtoE; ++LHSProtoI) {
+ bool match = false;
+ ObjCProtocolDecl *lhsProto = *LHSProtoI;
+ for (ObjCQualifiedIdType::qual_iterator I = rhsQID->qual_begin(),
+ E = rhsQID->qual_end(); I != E; ++I) {
+ ObjCProtocolDecl *rhsProto = *I;
+ if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
+ (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
+ match = true;
+ break;
+ }
+ }
+ if (!match)
+ return false;
+ }
+ return true;
+ }
+
+ if (const ObjCInterfaceType *IT = ltype->getAsObjCInterfaceType()) {
+ // for static type vs. qualified 'id' type, check that class implements
+ // all of 'id's protocols.
+ ObjCInterfaceDecl *lhsID = IT->getDecl();
+ for (ObjCQualifiedIdType::qual_iterator I = rhsQID->qual_begin(),
+ E = rhsQID->qual_end(); I != E; ++I) {
+ if (!ClassImplementsProtocol(*I, lhsID, compare, true))
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
diff --git a/lib/Sema/SemaInherit.cpp b/lib/Sema/SemaInherit.cpp
new file mode 100644
index 000000000000..1b968f0fbcce
--- /dev/null
+++ b/lib/Sema/SemaInherit.cpp
@@ -0,0 +1,344 @@
+//===---- SemaInherit.cpp - C++ Inheritance ---------------------*- 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 Sema routines for C++ inheritance semantics,
+// including searching the inheritance hierarchy.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SemaInherit.h"
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeOrdering.h"
+#include <algorithm>
+#include <memory>
+#include <set>
+#include <string>
+
+using namespace clang;
+
+/// \brief Computes the set of declarations referenced by these base
+/// paths.
+void BasePaths::ComputeDeclsFound() {
+ assert(NumDeclsFound == 0 && !DeclsFound &&
+ "Already computed the set of declarations");
+
+ std::set<NamedDecl *> Decls;
+ for (BasePaths::paths_iterator Path = begin(), PathEnd = end();
+ Path != PathEnd; ++Path)
+ Decls.insert(*Path->Decls.first);
+
+ NumDeclsFound = Decls.size();
+ DeclsFound = new NamedDecl * [NumDeclsFound];
+ std::copy(Decls.begin(), Decls.end(), DeclsFound);
+}
+
+BasePaths::decl_iterator BasePaths::found_decls_begin() {
+ if (NumDeclsFound == 0)
+ ComputeDeclsFound();
+ return DeclsFound;
+}
+
+BasePaths::decl_iterator BasePaths::found_decls_end() {
+ if (NumDeclsFound == 0)
+ ComputeDeclsFound();
+ return DeclsFound + NumDeclsFound;
+}
+
+/// isAmbiguous - Determines whether the set of paths provided is
+/// ambiguous, i.e., there are two or more paths that refer to
+/// different base class subobjects of the same type. BaseType must be
+/// an unqualified, canonical class type.
+bool BasePaths::isAmbiguous(QualType BaseType) {
+ assert(BaseType->isCanonical() && "Base type must be the canonical type");
+ assert(BaseType.getCVRQualifiers() == 0 && "Base type must be unqualified");
+ std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType];
+ return Subobjects.second + (Subobjects.first? 1 : 0) > 1;
+}
+
+/// clear - Clear out all prior path information.
+void BasePaths::clear() {
+ Paths.clear();
+ ClassSubobjects.clear();
+ ScratchPath.clear();
+ DetectedVirtual = 0;
+}
+
+/// @brief Swaps the contents of this BasePaths structure with the
+/// contents of Other.
+void BasePaths::swap(BasePaths &Other) {
+ std::swap(Origin, Other.Origin);
+ Paths.swap(Other.Paths);
+ ClassSubobjects.swap(Other.ClassSubobjects);
+ std::swap(FindAmbiguities, Other.FindAmbiguities);
+ std::swap(RecordPaths, Other.RecordPaths);
+ std::swap(DetectVirtual, Other.DetectVirtual);
+ std::swap(DetectedVirtual, Other.DetectedVirtual);
+}
+
+/// IsDerivedFrom - Determine whether the type Derived is derived from
+/// the type Base, ignoring qualifiers on Base and Derived. This
+/// routine does not assess whether an actual conversion from a
+/// Derived* to a Base* is legal, because it does not account for
+/// ambiguous conversions or conversions to private/protected bases.
+bool Sema::IsDerivedFrom(QualType Derived, QualType Base) {
+ BasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false,
+ /*DetectVirtual=*/false);
+ return IsDerivedFrom(Derived, Base, Paths);
+}
+
+/// IsDerivedFrom - Determine whether the type Derived is derived from
+/// the type Base, ignoring qualifiers on Base and Derived. This
+/// routine does not assess whether an actual conversion from a
+/// Derived* to a Base* is legal, because it does not account for
+/// ambiguous conversions or conversions to private/protected
+/// bases. This routine will use Paths to determine if there are
+/// ambiguous paths (if @c Paths.isFindingAmbiguities()) and record
+/// information about all of the paths (if @c Paths.isRecordingPaths()).
+bool Sema::IsDerivedFrom(QualType Derived, QualType Base, BasePaths &Paths) {
+ Derived = Context.getCanonicalType(Derived).getUnqualifiedType();
+ Base = Context.getCanonicalType(Base).getUnqualifiedType();
+
+ if (!Derived->isRecordType() || !Base->isRecordType())
+ return false;
+
+ if (Derived == Base)
+ return false;
+
+ Paths.setOrigin(Derived);
+ return LookupInBases(cast<CXXRecordDecl>(Derived->getAsRecordType()->getDecl()),
+ MemberLookupCriteria(Base), Paths);
+}
+
+/// LookupInBases - Look for something that meets the specified
+/// Criteria within the base classes of Class (or any of its base
+/// classes, transitively). This routine populates BasePaths with the
+/// list of paths that one can take to find the entity that meets the
+/// search criteria, and returns true if any such entity is found. The
+/// various options passed to the BasePath constructor will affect the
+/// behavior of this lookup, e.g., whether it finds ambiguities,
+/// records paths, or attempts to detect the use of virtual base
+/// classes.
+bool Sema::LookupInBases(CXXRecordDecl *Class,
+ const MemberLookupCriteria& Criteria,
+ BasePaths &Paths) {
+ bool FoundPath = false;
+
+ for (CXXRecordDecl::base_class_const_iterator BaseSpec = Class->bases_begin(),
+ BaseSpecEnd = Class->bases_end();
+ BaseSpec != BaseSpecEnd; ++BaseSpec) {
+ // Find the record of the base class subobjects for this type.
+ QualType BaseType = Context.getCanonicalType(BaseSpec->getType());
+ BaseType = BaseType.getUnqualifiedType();
+
+ // Determine whether we need to visit this base class at all,
+ // updating the count of subobjects appropriately.
+ std::pair<bool, unsigned>& Subobjects = Paths.ClassSubobjects[BaseType];
+ bool VisitBase = true;
+ bool SetVirtual = false;
+ if (BaseSpec->isVirtual()) {
+ VisitBase = !Subobjects.first;
+ Subobjects.first = true;
+ if (Paths.isDetectingVirtual() && Paths.DetectedVirtual == 0) {
+ // If this is the first virtual we find, remember it. If it turns out
+ // there is no base path here, we'll reset it later.
+ Paths.DetectedVirtual = BaseType->getAsRecordType();
+ SetVirtual = true;
+ }
+ } else
+ ++Subobjects.second;
+
+ if (Paths.isRecordingPaths()) {
+ // Add this base specifier to the current path.
+ BasePathElement Element;
+ Element.Base = &*BaseSpec;
+ Element.Class = Class;
+ if (BaseSpec->isVirtual())
+ Element.SubobjectNumber = 0;
+ else
+ Element.SubobjectNumber = Subobjects.second;
+ Paths.ScratchPath.push_back(Element);
+ }
+
+ CXXRecordDecl *BaseRecord
+ = cast<CXXRecordDecl>(BaseSpec->getType()->getAsRecordType()->getDecl());
+
+ // Either look at the base class type or look into the base class
+ // type to see if we've found a member that meets the search
+ // criteria.
+ bool FoundPathToThisBase = false;
+ switch (Criteria.Kind) {
+ case MemberLookupCriteria::LK_Base:
+ FoundPathToThisBase
+ = (Context.getCanonicalType(BaseSpec->getType()) == Criteria.Base);
+ break;
+ case MemberLookupCriteria::LK_NamedMember:
+ Paths.ScratchPath.Decls = BaseRecord->lookup(Context, Criteria.Name);
+ while (Paths.ScratchPath.Decls.first != Paths.ScratchPath.Decls.second) {
+ if (isAcceptableLookupResult(*Paths.ScratchPath.Decls.first,
+ Criteria.NameKind, Criteria.IDNS)) {
+ FoundPathToThisBase = true;
+ break;
+ }
+ ++Paths.ScratchPath.Decls.first;
+ }
+ break;
+ case MemberLookupCriteria::LK_OverriddenMember:
+ Paths.ScratchPath.Decls =
+ BaseRecord->lookup(Context, Criteria.Method->getDeclName());
+ while (Paths.ScratchPath.Decls.first != Paths.ScratchPath.Decls.second) {
+ if (CXXMethodDecl *MD =
+ dyn_cast<CXXMethodDecl>(*Paths.ScratchPath.Decls.first)) {
+ OverloadedFunctionDecl::function_iterator MatchedDecl;
+ if (MD->isVirtual() &&
+ !IsOverload(Criteria.Method, MD, MatchedDecl)) {
+ FoundPathToThisBase = true;
+ break;
+ }
+ }
+
+ ++Paths.ScratchPath.Decls.first;
+ }
+ break;
+ }
+
+ if (FoundPathToThisBase) {
+ // We've found a path that terminates that this base.
+ FoundPath = true;
+ if (Paths.isRecordingPaths()) {
+ // We have a path. Make a copy of it before moving on.
+ Paths.Paths.push_back(Paths.ScratchPath);
+ } else if (!Paths.isFindingAmbiguities()) {
+ // We found a path and we don't care about ambiguities;
+ // return immediately.
+ return FoundPath;
+ }
+ }
+ // C++ [class.member.lookup]p2:
+ // A member name f in one sub-object B hides a member name f in
+ // a sub-object A if A is a base class sub-object of B. Any
+ // declarations that are so hidden are eliminated from
+ // consideration.
+ else if (VisitBase && LookupInBases(BaseRecord, Criteria, Paths)) {
+ // There is a path to a base class that meets the criteria. If we're not
+ // collecting paths or finding ambiguities, we're done.
+ FoundPath = true;
+ if (!Paths.isFindingAmbiguities())
+ return FoundPath;
+ }
+
+ // Pop this base specifier off the current path (if we're
+ // collecting paths).
+ if (Paths.isRecordingPaths())
+ Paths.ScratchPath.pop_back();
+ // If we set a virtual earlier, and this isn't a path, forget it again.
+ if (SetVirtual && !FoundPath) {
+ Paths.DetectedVirtual = 0;
+ }
+ }
+
+ return FoundPath;
+}
+
+/// CheckDerivedToBaseConversion - Check whether the Derived-to-Base
+/// conversion (where Derived and Base are class types) is
+/// well-formed, meaning that the conversion is unambiguous (and
+/// that all of the base classes are accessible). Returns true
+/// and emits a diagnostic if the code is ill-formed, returns false
+/// otherwise. Loc is the location where this routine should point to
+/// if there is an error, and Range is the source range to highlight
+/// if there is an error.
+bool
+Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
+ unsigned InaccessibleBaseID,
+ unsigned AmbigiousBaseConvID,
+ SourceLocation Loc, SourceRange Range,
+ DeclarationName Name) {
+ // First, determine whether the path from Derived to Base is
+ // ambiguous. This is slightly more expensive than checking whether
+ // the Derived to Base conversion exists, because here we need to
+ // explore multiple paths to determine if there is an ambiguity.
+ BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ bool DerivationOkay = IsDerivedFrom(Derived, Base, Paths);
+ assert(DerivationOkay &&
+ "Can only be used with a derived-to-base conversion");
+ (void)DerivationOkay;
+
+ if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
+ // Check that the base class can be accessed.
+ return CheckBaseClassAccess(Derived, Base, InaccessibleBaseID, Paths, Loc,
+ Name);
+ }
+
+ // We know that the derived-to-base conversion is ambiguous, and
+ // we're going to produce a diagnostic. Perform the derived-to-base
+ // search just one more time to compute all of the possible paths so
+ // that we can print them out. This is more expensive than any of
+ // the previous derived-to-base checks we've done, but at this point
+ // performance isn't as much of an issue.
+ Paths.clear();
+ Paths.setRecordingPaths(true);
+ bool StillOkay = IsDerivedFrom(Derived, Base, Paths);
+ assert(StillOkay && "Can only be used with a derived-to-base conversion");
+ (void)StillOkay;
+
+ // Build up a textual representation of the ambiguous paths, e.g.,
+ // D -> B -> A, that will be used to illustrate the ambiguous
+ // conversions in the diagnostic. We only print one of the paths
+ // to each base class subobject.
+ std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths);
+
+ Diag(Loc, AmbigiousBaseConvID)
+ << Derived << Base << PathDisplayStr << Range << Name;
+ return true;
+}
+
+bool
+Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
+ SourceLocation Loc, SourceRange Range) {
+ return CheckDerivedToBaseConversion(Derived, Base,
+ diag::err_conv_to_inaccessible_base,
+ diag::err_ambiguous_derived_to_base_conv,
+ Loc, Range, DeclarationName());
+}
+
+
+/// @brief Builds a string representing ambiguous paths from a
+/// specific derived class to different subobjects of the same base
+/// class.
+///
+/// This function builds a string that can be used in error messages
+/// to show the different paths that one can take through the
+/// inheritance hierarchy to go from the derived class to different
+/// subobjects of a base class. The result looks something like this:
+/// @code
+/// struct D -> struct B -> struct A
+/// struct D -> struct C -> struct A
+/// @endcode
+std::string Sema::getAmbiguousPathsDisplayString(BasePaths &Paths) {
+ std::string PathDisplayStr;
+ std::set<unsigned> DisplayedPaths;
+ for (BasePaths::paths_iterator Path = Paths.begin();
+ Path != Paths.end(); ++Path) {
+ if (DisplayedPaths.insert(Path->back().SubobjectNumber).second) {
+ // We haven't displayed a path to this particular base
+ // class subobject yet.
+ PathDisplayStr += "\n ";
+ PathDisplayStr += Paths.getOrigin().getAsString();
+ for (BasePath::const_iterator Element = Path->begin();
+ Element != Path->end(); ++Element)
+ PathDisplayStr += " -> " + Element->Base->getType().getAsString();
+ }
+ }
+
+ return PathDisplayStr;
+}
diff --git a/lib/Sema/SemaInherit.h b/lib/Sema/SemaInherit.h
new file mode 100644
index 000000000000..b1e791a17ba3
--- /dev/null
+++ b/lib/Sema/SemaInherit.h
@@ -0,0 +1,248 @@
+//===------ SemaInherit.h - C++ Inheritance ---------------------*- 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 Sema data structures that help analyse C++
+// inheritance semantics, including searching the inheritance
+// hierarchy.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_INHERIT_H
+#define LLVM_CLANG_SEMA_INHERIT_H
+
+#include "Sema.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeOrdering.h"
+#include "llvm/ADT/SmallVector.h"
+#include <list>
+#include <map>
+
+namespace clang {
+ class CXXBaseSpecifier;
+
+ /// BasePathElement - An element in a path from a derived class to a
+ /// base class. Each step in the path references the link from a
+ /// derived class to one of its direct base classes, along with a
+ /// base "number" that identifies which base subobject of the
+ /// original derived class we are referencing.
+ struct BasePathElement {
+ /// Base - The base specifier that states the link from a derived
+ /// class to a base class, which will be followed by this base
+ /// path element.
+ const CXXBaseSpecifier *Base;
+
+ /// Class - The record decl of the class that the base is a base of.
+ const CXXRecordDecl *Class;
+
+ /// SubobjectNumber - Identifies which base class subobject (of type
+ /// @c Base->getType()) this base path element refers to. This
+ /// value is only valid if @c !Base->isVirtual(), because there
+ /// is no base numbering for the zero or one virtual bases of a
+ /// given type.
+ int SubobjectNumber;
+ };
+
+ /// BasePath - Represents a path from a specific derived class
+ /// (which is not represented as part of the path) to a particular
+ /// (direct or indirect) base class subobject that contains some
+ /// number of declarations with the same name. Individual elements
+ /// in the path are described by the BasePathElement 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.
+ struct BasePath : public llvm::SmallVector<BasePathElement, 4> {
+ /// Decls - The set of declarations found inside this base class
+ /// subobject.
+ DeclContext::lookup_result Decls;
+ };
+
+ /// BasePaths - Represents the set of paths from a derived class to
+ /// one of its (direct or indirect) bases. For example, given the
+ /// following class hierachy:
+ ///
+ /// @code
+ /// class A { };
+ /// class B : public A { };
+ /// class C : public A { };
+ /// class D : public B, public C{ };
+ /// @endcode
+ ///
+ /// There are two potential BasePaths to represent paths from D to a
+ /// base subobject of type A. One path is (D,0) -> (B,0) -> (A,0)
+ /// and another is (D,0)->(C,0)->(A,1). These two paths actually
+ /// refer to two different base class subobjects of the same type,
+ /// so the BasePaths object refers to an ambiguous path. On the
+ /// other hand, consider the following class hierarchy:
+ ///
+ /// @code
+ /// class A { };
+ /// class B : public virtual A { };
+ /// class C : public virtual A { };
+ /// class D : public B, public C{ };
+ /// @endcode
+ ///
+ /// Here, there are two potential BasePaths again, (D, 0) -> (B, 0)
+ /// -> (A,v) and (D, 0) -> (C, 0) -> (A, v), but since both of them
+ /// refer to the same base class subobject of type A (the virtual
+ /// one), there is no ambiguity.
+ class BasePaths {
+ /// Origin - The type from which this search originated.
+ QualType Origin;
+
+ /// Paths - The actual set of paths that can be taken from the
+ /// derived class to the same base class.
+ std::list<BasePath> Paths;
+
+ /// ClassSubobjects - Records the class subobjects for each class
+ /// type that we've seen. The first element in the pair says
+ /// whether we found a path to a virtual base for that class type,
+ /// while the element contains the number of non-virtual base
+ /// class subobjects for that class type. The key of the map is
+ /// the cv-unqualified canonical type of the base class subobject.
+ std::map<QualType, std::pair<bool, unsigned>, QualTypeOrdering>
+ ClassSubobjects;
+
+ /// FindAmbiguities - Whether Sema::IsDerivedFrom should try find
+ /// ambiguous paths while it is looking for a path from a derived
+ /// type to a base type.
+ bool FindAmbiguities;
+
+ /// RecordPaths - Whether Sema::IsDerivedFrom should record paths
+ /// while it is determining whether there are paths from a derived
+ /// type to a base type.
+ bool RecordPaths;
+
+ /// DetectVirtual - Whether Sema::IsDerivedFrom should abort the search
+ /// if it finds a path that goes across a virtual base. The virtual class
+ /// is also recorded.
+ bool DetectVirtual;
+
+ /// ScratchPath - A BasePath that is used by Sema::IsDerivedFrom
+ /// to help build the set of paths.
+ BasePath ScratchPath;
+
+ /// DetectedVirtual - The base class that is virtual.
+ const RecordType *DetectedVirtual;
+
+ /// \brief Array of the declarations that have been found. This
+ /// array is constructed only if needed, e.g., to iterate over the
+ /// results within LookupResult.
+ NamedDecl **DeclsFound;
+ unsigned NumDeclsFound;
+
+ friend class Sema;
+
+ void ComputeDeclsFound();
+
+ public:
+ typedef std::list<BasePath>::const_iterator paths_iterator;
+ typedef NamedDecl **decl_iterator;
+
+ /// BasePaths - Construct a new BasePaths structure to record the
+ /// paths for a derived-to-base search.
+ explicit BasePaths(bool FindAmbiguities = true,
+ bool RecordPaths = true,
+ bool DetectVirtual = true)
+ : FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths),
+ DetectVirtual(DetectVirtual), DetectedVirtual(0), DeclsFound(0),
+ NumDeclsFound(0)
+ {}
+
+ ~BasePaths() { delete [] DeclsFound; }
+
+ paths_iterator begin() const { return Paths.begin(); }
+ paths_iterator end() const { return Paths.end(); }
+
+ BasePath& front() { return Paths.front(); }
+ const BasePath& front() const { return Paths.front(); }
+
+ decl_iterator found_decls_begin();
+ decl_iterator found_decls_end();
+
+ bool isAmbiguous(QualType BaseType);
+
+ /// isFindingAmbiguities - Whether we are finding multiple paths
+ /// to detect ambiguities.
+ bool isFindingAmbiguities() const { return FindAmbiguities; }
+
+ /// isRecordingPaths - Whether we are recording paths.
+ bool isRecordingPaths() const { return RecordPaths; }
+
+ /// setRecordingPaths - Specify whether we should be recording
+ /// paths or not.
+ void setRecordingPaths(bool RP) { RecordPaths = RP; }
+
+ /// isDetectingVirtual - Whether we are detecting virtual bases.
+ bool isDetectingVirtual() const { return DetectVirtual; }
+
+ /// getDetectedVirtual - The virtual base discovered on the path.
+ const RecordType* getDetectedVirtual() const {
+ return DetectedVirtual;
+ }
+
+ /// @brief Retrieve the type from which this base-paths search
+ /// began
+ QualType getOrigin() const { return Origin; }
+ void setOrigin(QualType Type) { Origin = Type; }
+
+ void clear();
+
+ void swap(BasePaths &Other);
+ };
+
+ /// MemberLookupCriteria - Criteria for performing lookup of a
+ /// member of a C++ class. Objects of this type are used to direct
+ /// Sema::LookupCXXClassMember.
+ struct MemberLookupCriteria {
+ /// LookupKind - the kind of lookup we're doing.
+ enum LookupKind {
+ LK_Base,
+ LK_NamedMember,
+ LK_OverriddenMember
+ };
+
+ /// MemberLookupCriteria - Constructs member lookup criteria to
+ /// search for a base class of type Base.
+ explicit MemberLookupCriteria(QualType Base)
+ : Kind(LK_Base), Base(Base) { }
+
+ /// MemberLookupCriteria - Constructs member lookup criteria to
+ /// search for a class member with the given Name.
+ explicit MemberLookupCriteria(DeclarationName Name,
+ Sema::LookupNameKind NameKind,
+ unsigned IDNS)
+ : Kind(LK_NamedMember), Name(Name), NameKind(NameKind), IDNS(IDNS) { }
+
+ explicit MemberLookupCriteria(CXXMethodDecl *MD)
+ : Kind(LK_OverriddenMember), Method(MD) { }
+
+ /// Kind - The kind of lookup we're doing.
+ /// LK_Base if we are looking for a base class (whose
+ /// type is Base). LK_NamedMember if we are looking for a named member of
+ /// the class (with the name Name).
+ LookupKind Kind;
+
+ /// Base - The type of the base class we're searching for, if
+ /// LookupBase is true.
+ QualType Base;
+
+ /// Name - The name of the member we're searching for, if
+ /// LookupBase is false.
+ DeclarationName Name;
+
+ Sema::LookupNameKind NameKind;
+ unsigned IDNS;
+
+ CXXMethodDecl *Method;
+ };
+}
+
+#endif
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
new file mode 100644
index 000000000000..4e0eb1d431fe
--- /dev/null
+++ b/lib/Sema/SemaInit.cpp
@@ -0,0 +1,1784 @@
+//===--- SemaInit.cpp - Semantic Analysis for Initializers ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for initializers. The main entry
+// point is Sema::CheckInitList(), but all of the work is performed
+// within the InitListChecker class.
+//
+// This file also implements Sema::CheckInitializerTypes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/Parse/Designator.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include <map>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Sema Initialization Checking
+//===----------------------------------------------------------------------===//
+
+static Expr *IsStringInit(Expr *Init, QualType DeclType, ASTContext &Context) {
+ const ArrayType *AT = Context.getAsArrayType(DeclType);
+ if (!AT) return 0;
+
+ if (!isa<ConstantArrayType>(AT) && !isa<IncompleteArrayType>(AT))
+ return 0;
+
+ // See if this is a string literal or @encode.
+ Init = Init->IgnoreParens();
+
+ // Handle @encode, which is a narrow string.
+ if (isa<ObjCEncodeExpr>(Init) && AT->getElementType()->isCharType())
+ return Init;
+
+ // Otherwise we can only handle string literals.
+ StringLiteral *SL = dyn_cast<StringLiteral>(Init);
+ 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())
+ return ElemTy->isCharType() ? Init : 0;
+
+ // 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;
+}
+
+static bool CheckSingleInitializer(Expr *&Init, QualType DeclType,
+ bool DirectInit, Sema &S) {
+ // Get the type before calling CheckSingleAssignmentConstraints(), since
+ // it can promote the expression.
+ QualType InitType = Init->getType();
+
+ if (S.getLangOptions().CPlusPlus) {
+ // FIXME: I dislike this error message. A lot.
+ if (S.PerformImplicitConversion(Init, DeclType, "initializing", DirectInit))
+ return S.Diag(Init->getSourceRange().getBegin(),
+ diag::err_typecheck_convert_incompatible)
+ << DeclType << Init->getType() << "initializing"
+ << Init->getSourceRange();
+ return false;
+ }
+
+ Sema::AssignConvertType ConvTy =
+ S.CheckSingleAssignmentConstraints(DeclType, Init);
+ return S.DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType,
+ InitType, Init, "initializing");
+}
+
+static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) {
+ // Get the length of the string as parsed.
+ uint64_t StrLength =
+ cast<ConstantArrayType>(Str->getType())->getSize().getZExtValue();
+
+
+ const ArrayType *AT = S.Context.getAsArrayType(DeclT);
+ if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) {
+ // C99 6.7.8p14. We have an array of character type with unknown size
+ // being initialized to a string literal.
+ llvm::APSInt ConstVal(32);
+ ConstVal = StrLength;
+ // Return a new array type (C99 6.7.8p22).
+ DeclT = S.Context.getConstantArrayType(IAT->getElementType(), ConstVal,
+ ArrayType::Normal, 0);
+ return;
+ }
+
+ const ConstantArrayType *CAT = cast<ConstantArrayType>(AT);
+
+ // C99 6.7.8p14. We have an array of character type with known size. However,
+ // the size may be smaller or larger than the string we are initializing.
+ // FIXME: Avoid truncation for 64-bit length strings.
+ if (StrLength-1 > CAT->getSize().getZExtValue())
+ S.Diag(Str->getSourceRange().getBegin(),
+ diag::warn_initializer_string_for_char_array_too_long)
+ << Str->getSourceRange();
+
+ // Set the type to the actual size that we are initializing. If we have
+ // something like:
+ // char x[1] = "foo";
+ // then this will set the string literal's type to char[1].
+ Str->setType(DeclT);
+}
+
+bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
+ SourceLocation InitLoc,
+ DeclarationName InitEntity, bool DirectInit) {
+ if (DeclType->isDependentType() ||
+ Init->isTypeDependent() || Init->isValueDependent())
+ return false;
+
+ // C++ [dcl.init.ref]p1:
+ // A variable declared to be a T& or T&&, that is "reference to type T"
+ // (8.3.2), shall be initialized by an object, or function, of
+ // type T or by an object that can be converted into a T.
+ if (DeclType->isReferenceType())
+ return CheckReferenceInit(Init, DeclType, 0, false, DirectInit);
+
+ // C99 6.7.8p3: The type of the entity to be initialized shall be an array
+ // of unknown size ("[]") or an object type that is not a variable array type.
+ if (const VariableArrayType *VAT = Context.getAsVariableArrayType(DeclType))
+ return Diag(InitLoc, diag::err_variable_object_no_init)
+ << VAT->getSizeExpr()->getSourceRange();
+
+ InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
+ if (!InitList) {
+ // FIXME: Handle wide strings
+ if (Expr *Str = IsStringInit(Init, DeclType, Context)) {
+ CheckStringInit(Str, DeclType, *this);
+ return false;
+ }
+
+ // C++ [dcl.init]p14:
+ // -- If the destination type is a (possibly cv-qualified) class
+ // type:
+ if (getLangOptions().CPlusPlus && DeclType->isRecordType()) {
+ QualType DeclTypeC = Context.getCanonicalType(DeclType);
+ QualType InitTypeC = Context.getCanonicalType(Init->getType());
+
+ // -- If the initialization is direct-initialization, or if it is
+ // copy-initialization where the cv-unqualified version of the
+ // source type is the same class as, or a derived class of, the
+ // class of the destination, constructors are considered.
+ if ((DeclTypeC.getUnqualifiedType() == InitTypeC.getUnqualifiedType()) ||
+ IsDerivedFrom(InitTypeC, DeclTypeC)) {
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(DeclType->getAsRecordType()->getDecl());
+
+ // No need to make a CXXConstructExpr if both the ctor and dtor are
+ // trivial.
+ if (RD->hasTrivialConstructor() && RD->hasTrivialDestructor())
+ return false;
+
+ CXXConstructorDecl *Constructor
+ = PerformInitializationByConstructor(DeclType, &Init, 1,
+ InitLoc, Init->getSourceRange(),
+ InitEntity,
+ DirectInit? IK_Direct : IK_Copy);
+ if (!Constructor)
+ return true;
+
+ Init = CXXConstructExpr::Create(Context, DeclType, Constructor, false,
+ &Init, 1);
+ return false;
+ }
+
+ // -- Otherwise (i.e., for the remaining copy-initialization
+ // cases), user-defined conversion sequences that can
+ // convert from the source type to the destination type or
+ // (when a conversion function is used) to a derived class
+ // thereof are enumerated as described in 13.3.1.4, and the
+ // best one is chosen through overload resolution
+ // (13.3). If the conversion cannot be done or is
+ // ambiguous, the initialization is ill-formed. The
+ // function selected is called with the initializer
+ // expression as its argument; if the function is a
+ // constructor, the call initializes a temporary of the
+ // destination type.
+ // FIXME: We're pretending to do copy elision here; return to this when we
+ // have ASTs for such things.
+ if (!PerformImplicitConversion(Init, DeclType, "initializing"))
+ return false;
+
+ if (InitEntity)
+ return Diag(InitLoc, diag::err_cannot_initialize_decl)
+ << InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
+ << Init->getType() << Init->getSourceRange();
+ else
+ return Diag(InitLoc, diag::err_cannot_initialize_decl_noname)
+ << DeclType << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
+ << Init->getType() << Init->getSourceRange();
+ }
+
+ // C99 6.7.8p16.
+ if (DeclType->isArrayType())
+ return Diag(Init->getLocStart(), diag::err_array_init_list_required)
+ << Init->getSourceRange();
+
+ return CheckSingleInitializer(Init, DeclType, DirectInit, *this);
+ }
+
+ bool hadError = CheckInitList(InitList, DeclType);
+ Init = InitList;
+ return hadError;
+}
+
+//===----------------------------------------------------------------------===//
+// Semantic checking for initializer lists.
+//===----------------------------------------------------------------------===//
+
+/// @brief Semantic checking for initializer lists.
+///
+/// The InitListChecker class contains a set of routines that each
+/// handle the initialization of a certain kind of entity, e.g.,
+/// arrays, vectors, struct/union types, scalars, etc. The
+/// InitListChecker itself performs a recursive walk of the subobject
+/// structure of the type to be initialized, while stepping through
+/// the initializer list one element at a time. The IList and Index
+/// parameters to each of the Check* routines contain the active
+/// (syntactic) initializer list and the index into that initializer
+/// list that represents the current initializer. Each routine is
+/// responsible for moving that Index forward as it consumes elements.
+///
+/// Each Check* routine also has a StructuredList/StructuredIndex
+/// arguments, which contains the current the "structured" (semantic)
+/// initializer list and the index into that initializer list where we
+/// are copying initializers as we map them over to the semantic
+/// list. Once we have completed our recursive walk of the subobject
+/// structure, we will have constructed a full semantic initializer
+/// list.
+///
+/// C99 designators cause changes in the initializer list traversal,
+/// because they make the initialization "jump" into a specific
+/// subobject and then continue the initialization from that
+/// point. CheckDesignatedInitializer() recursively steps into the
+/// designated subobject and manages backing out the recursion to
+/// initialize the subobjects after the one designated.
+namespace {
+class InitListChecker {
+ Sema &SemaRef;
+ bool hadError;
+ std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic;
+ InitListExpr *FullyStructuredList;
+
+ void CheckImplicitInitList(InitListExpr *ParentIList, QualType T,
+ unsigned &Index, InitListExpr *StructuredList,
+ unsigned &StructuredIndex,
+ bool TopLevelObject = false);
+ void CheckExplicitInitList(InitListExpr *IList, QualType &T,
+ unsigned &Index, InitListExpr *StructuredList,
+ unsigned &StructuredIndex,
+ bool TopLevelObject = false);
+ void CheckListElementTypes(InitListExpr *IList, QualType &DeclType,
+ bool SubobjectIsDesignatorContext,
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex,
+ bool TopLevelObject = false);
+ void CheckSubElementType(InitListExpr *IList, QualType ElemType,
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex);
+ void CheckScalarType(InitListExpr *IList, QualType DeclType,
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex);
+ void CheckReferenceType(InitListExpr *IList, QualType DeclType,
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex);
+ void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex);
+ void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType,
+ RecordDecl::field_iterator Field,
+ bool SubobjectIsDesignatorContext, unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex,
+ bool TopLevelObject = false);
+ void CheckArrayType(InitListExpr *IList, QualType &DeclType,
+ llvm::APSInt elementIndex,
+ bool SubobjectIsDesignatorContext, unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex);
+ bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE,
+ unsigned DesigIdx,
+ QualType &CurrentObjectType,
+ RecordDecl::field_iterator *NextField,
+ llvm::APSInt *NextElementIndex,
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex,
+ bool FinishSubobjectInit,
+ bool TopLevelObject);
+ InitListExpr *getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
+ QualType CurrentObjectType,
+ InitListExpr *StructuredList,
+ unsigned StructuredIndex,
+ SourceRange InitRange);
+ void UpdateStructuredListElement(InitListExpr *StructuredList,
+ unsigned &StructuredIndex,
+ Expr *expr);
+ int numArrayElements(QualType DeclType);
+ int numStructUnionElements(QualType DeclType);
+
+ void FillInValueInitializations(InitListExpr *ILE);
+public:
+ InitListChecker(Sema &S, InitListExpr *IL, QualType &T);
+ bool HadError() { return hadError; }
+
+ // @brief Retrieves the fully-structured initializer list used for
+ // semantic analysis and code generation.
+ InitListExpr *getFullyStructuredList() const { return FullyStructuredList; }
+};
+} // end anonymous namespace
+
+/// Recursively replaces NULL values within the given initializer list
+/// with expressions that perform value-initialization of the
+/// appropriate type.
+void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
+ assert((ILE->getType() != SemaRef.Context.VoidTy) &&
+ "Should not have void type");
+ SourceLocation Loc = ILE->getSourceRange().getBegin();
+ if (ILE->getSyntacticForm())
+ Loc = ILE->getSyntacticForm()->getSourceRange().getBegin();
+
+ if (const RecordType *RType = ILE->getType()->getAsRecordType()) {
+ unsigned Init = 0, NumInits = ILE->getNumInits();
+ for (RecordDecl::field_iterator
+ Field = RType->getDecl()->field_begin(SemaRef.Context),
+ FieldEnd = RType->getDecl()->field_end(SemaRef.Context);
+ Field != FieldEnd; ++Field) {
+ if (Field->isUnnamedBitfield())
+ continue;
+
+ if (Init >= NumInits || !ILE->getInit(Init)) {
+ if (Field->getType()->isReferenceType()) {
+ // C++ [dcl.init.aggr]p9:
+ // If an incomplete or empty initializer-list leaves a
+ // member of reference type uninitialized, the program is
+ // ill-formed.
+ SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized)
+ << Field->getType()
+ << ILE->getSyntacticForm()->getSourceRange();
+ SemaRef.Diag(Field->getLocation(),
+ diag::note_uninit_reference_member);
+ hadError = true;
+ return;
+ } else if (SemaRef.CheckValueInitialization(Field->getType(), Loc)) {
+ hadError = true;
+ return;
+ }
+
+ // FIXME: If value-initialization involves calling a constructor, should
+ // we make that call explicit in the representation (even when it means
+ // extending the initializer list)?
+ if (Init < NumInits && !hadError)
+ ILE->setInit(Init,
+ new (SemaRef.Context) ImplicitValueInitExpr(Field->getType()));
+ } else if (InitListExpr *InnerILE
+ = dyn_cast<InitListExpr>(ILE->getInit(Init)))
+ FillInValueInitializations(InnerILE);
+ ++Init;
+
+ // Only look at the first initialization of a union.
+ if (RType->getDecl()->isUnion())
+ break;
+ }
+
+ return;
+ }
+
+ QualType ElementType;
+
+ unsigned NumInits = ILE->getNumInits();
+ unsigned NumElements = NumInits;
+ if (const ArrayType *AType = SemaRef.Context.getAsArrayType(ILE->getType())) {
+ ElementType = AType->getElementType();
+ if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType))
+ NumElements = CAType->getSize().getZExtValue();
+ } else if (const VectorType *VType = ILE->getType()->getAsVectorType()) {
+ ElementType = VType->getElementType();
+ NumElements = VType->getNumElements();
+ } else
+ ElementType = ILE->getType();
+
+ for (unsigned Init = 0; Init != NumElements; ++Init) {
+ if (Init >= NumInits || !ILE->getInit(Init)) {
+ if (SemaRef.CheckValueInitialization(ElementType, Loc)) {
+ hadError = true;
+ return;
+ }
+
+ // FIXME: If value-initialization involves calling a constructor, should
+ // we make that call explicit in the representation (even when it means
+ // extending the initializer list)?
+ if (Init < NumInits && !hadError)
+ ILE->setInit(Init,
+ new (SemaRef.Context) ImplicitValueInitExpr(ElementType));
+ }
+ else if (InitListExpr *InnerILE =dyn_cast<InitListExpr>(ILE->getInit(Init)))
+ FillInValueInitializations(InnerILE);
+ }
+}
+
+
+InitListChecker::InitListChecker(Sema &S, InitListExpr *IL, QualType &T)
+ : SemaRef(S) {
+ hadError = false;
+
+ unsigned newIndex = 0;
+ unsigned newStructuredIndex = 0;
+ FullyStructuredList
+ = getStructuredSubobjectInit(IL, newIndex, T, 0, 0, IL->getSourceRange());
+ CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex,
+ /*TopLevelObject=*/true);
+
+ if (!hadError)
+ FillInValueInitializations(FullyStructuredList);
+}
+
+int InitListChecker::numArrayElements(QualType DeclType) {
+ // FIXME: use a proper constant
+ int maxElements = 0x7FFFFFFF;
+ if (const ConstantArrayType *CAT =
+ SemaRef.Context.getAsConstantArrayType(DeclType)) {
+ maxElements = static_cast<int>(CAT->getSize().getZExtValue());
+ }
+ return maxElements;
+}
+
+int InitListChecker::numStructUnionElements(QualType DeclType) {
+ RecordDecl *structDecl = DeclType->getAsRecordType()->getDecl();
+ int InitializableMembers = 0;
+ for (RecordDecl::field_iterator
+ Field = structDecl->field_begin(SemaRef.Context),
+ FieldEnd = structDecl->field_end(SemaRef.Context);
+ Field != FieldEnd; ++Field) {
+ if ((*Field)->getIdentifier() || !(*Field)->isBitField())
+ ++InitializableMembers;
+ }
+ if (structDecl->isUnion())
+ return std::min(InitializableMembers, 1);
+ return InitializableMembers - structDecl->hasFlexibleArrayMember();
+}
+
+void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
+ QualType T, unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex,
+ bool TopLevelObject) {
+ int maxElements = 0;
+
+ if (T->isArrayType())
+ maxElements = numArrayElements(T);
+ else if (T->isStructureType() || T->isUnionType())
+ maxElements = numStructUnionElements(T);
+ else if (T->isVectorType())
+ maxElements = T->getAsVectorType()->getNumElements();
+ else
+ assert(0 && "CheckImplicitInitList(): Illegal type");
+
+ if (maxElements == 0) {
+ SemaRef.Diag(ParentIList->getInit(Index)->getLocStart(),
+ diag::err_implicit_empty_initializer);
+ ++Index;
+ hadError = true;
+ return;
+ }
+
+ // Build a structured initializer list corresponding to this subobject.
+ InitListExpr *StructuredSubobjectInitList
+ = getStructuredSubobjectInit(ParentIList, Index, T, StructuredList,
+ StructuredIndex,
+ SourceRange(ParentIList->getInit(Index)->getSourceRange().getBegin(),
+ ParentIList->getSourceRange().getEnd()));
+ unsigned StructuredSubobjectInitIndex = 0;
+
+ // Check the element types and build the structural subobject.
+ unsigned StartIndex = Index;
+ CheckListElementTypes(ParentIList, T, false, Index,
+ StructuredSubobjectInitList,
+ StructuredSubobjectInitIndex,
+ TopLevelObject);
+ 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);
+ }
+}
+
+void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex,
+ bool TopLevelObject) {
+ assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
+ SyntacticToSemantic[IList] = StructuredList;
+ StructuredList->setSyntacticForm(IList);
+ CheckListElementTypes(IList, T, true, Index, StructuredList,
+ StructuredIndex, TopLevelObject);
+ IList->setType(T);
+ StructuredList->setType(T);
+ if (hadError)
+ return;
+
+ if (Index < IList->getNumInits()) {
+ // We have leftover initializers
+ if (StructuredIndex == 1 &&
+ IsStringInit(StructuredList->getInit(0), T, SemaRef.Context)) {
+ unsigned DK = diag::warn_excess_initializers_in_char_array_initializer;
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ DK = diag::err_excess_initializers_in_char_array_initializer;
+ hadError = true;
+ }
+ // Special-case
+ SemaRef.Diag(IList->getInit(Index)->getLocStart(), DK)
+ << IList->getInit(Index)->getSourceRange();
+ } else if (!T->isIncompleteType()) {
+ // Don't complain for incomplete types, since we'll get an error
+ // elsewhere
+ QualType CurrentObjectType = StructuredList->getType();
+ int initKind =
+ CurrentObjectType->isArrayType()? 0 :
+ CurrentObjectType->isVectorType()? 1 :
+ CurrentObjectType->isScalarType()? 2 :
+ CurrentObjectType->isUnionType()? 3 :
+ 4;
+
+ unsigned DK = diag::warn_excess_initializers;
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ DK = diag::err_excess_initializers;
+ hadError = true;
+ }
+
+ SemaRef.Diag(IList->getInit(Index)->getLocStart(), DK)
+ << initKind << IList->getInit(Index)->getSourceRange();
+ }
+ }
+
+ if (T->isScalarType() && !TopLevelObject)
+ SemaRef.Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init)
+ << IList->getSourceRange()
+ << CodeModificationHint::CreateRemoval(SourceRange(IList->getLocStart()))
+ << CodeModificationHint::CreateRemoval(SourceRange(IList->getLocEnd()));
+}
+
+void InitListChecker::CheckListElementTypes(InitListExpr *IList,
+ QualType &DeclType,
+ bool SubobjectIsDesignatorContext,
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex,
+ bool TopLevelObject) {
+ if (DeclType->isScalarType()) {
+ CheckScalarType(IList, DeclType, Index, StructuredList, StructuredIndex);
+ } else if (DeclType->isVectorType()) {
+ CheckVectorType(IList, DeclType, Index, StructuredList, StructuredIndex);
+ } else if (DeclType->isAggregateType()) {
+ if (DeclType->isRecordType()) {
+ RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
+ CheckStructUnionTypes(IList, DeclType, RD->field_begin(SemaRef.Context),
+ SubobjectIsDesignatorContext, Index,
+ StructuredList, StructuredIndex,
+ TopLevelObject);
+ } else if (DeclType->isArrayType()) {
+ llvm::APSInt Zero(
+ SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()),
+ false);
+ CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index,
+ StructuredList, StructuredIndex);
+ }
+ else
+ assert(0 && "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;
+ hadError = true;
+ } else if (DeclType->isRecordType()) {
+ // C++ [dcl.init]p14:
+ // [...] If the class is an aggregate (8.5.1), and the initializer
+ // is a brace-enclosed list, see 8.5.1.
+ //
+ // Note: 8.5.1 is handled below; here, we diagnose the case where
+ // 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();
+ hadError = true;
+ } else if (DeclType->isReferenceType()) {
+ CheckReferenceType(IList, DeclType, Index, StructuredList, StructuredIndex);
+ } else {
+ // In C, all types are either scalars or aggregates, but
+ // additional handling is needed here for C++ (and possibly others?).
+ assert(0 && "Unsupported initializer type");
+ }
+}
+
+void InitListChecker::CheckSubElementType(InitListExpr *IList,
+ QualType ElemType,
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex) {
+ Expr *expr = IList->getInit(Index);
+ if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
+ unsigned newIndex = 0;
+ unsigned newStructuredIndex = 0;
+ InitListExpr *newStructuredList
+ = getStructuredSubobjectInit(IList, Index, ElemType,
+ StructuredList, StructuredIndex,
+ SubInitList->getSourceRange());
+ CheckExplicitInitList(SubInitList, ElemType, newIndex,
+ newStructuredList, newStructuredIndex);
+ ++StructuredIndex;
+ ++Index;
+ } else if (Expr *Str = IsStringInit(expr, ElemType, SemaRef.Context)) {
+ CheckStringInit(Str, ElemType, SemaRef);
+ UpdateStructuredListElement(StructuredList, StructuredIndex, Str);
+ ++Index;
+ } else if (ElemType->isScalarType()) {
+ CheckScalarType(IList, ElemType, Index, StructuredList, StructuredIndex);
+ } else if (ElemType->isReferenceType()) {
+ CheckReferenceType(IList, ElemType, Index, StructuredList, StructuredIndex);
+ } 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
+ // an initializer-list. If the initializer can initialize a
+ // member, the member is initialized. [...]
+ ImplicitConversionSequence ICS
+ = SemaRef.TryCopyInitialization(expr, ElemType);
+ if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion) {
+ if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS,
+ "initializing"))
+ hadError = true;
+ UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+ ++Index;
+ return;
+ }
+
+ // Fall through for subaggregate initialization
+ } else {
+ // C99 6.7.8p13:
+ //
+ // The initializer for a structure or union object that has
+ // automatic storage duration shall be either an initializer
+ // list as described below, or a single expression that has
+ // compatible structure or union type. In the latter case, the
+ // initial value of the object, including unnamed members, is
+ // that of the expression.
+ if (ElemType->isRecordType() &&
+ SemaRef.Context.hasSameUnqualifiedType(expr->getType(), ElemType)) {
+ UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+ ++Index;
+ return;
+ }
+
+ // Fall through for subaggregate initialization
+ }
+
+ // C++ [dcl.init.aggr]p12:
+ //
+ // [...] Otherwise, if the member is itself a non-empty
+ // subaggregate, brace elision is assumed and the initializer is
+ // considered for the initialization of the first member of
+ // the subaggregate.
+ if (ElemType->isAggregateType() || ElemType->isVectorType()) {
+ CheckImplicitInitList(IList, ElemType, Index, StructuredList,
+ StructuredIndex);
+ ++StructuredIndex;
+ } else {
+ // We cannot initialize this element, so let
+ // PerformCopyInitialization produce the appropriate diagnostic.
+ SemaRef.PerformCopyInitialization(expr, ElemType, "initializing");
+ hadError = true;
+ ++Index;
+ ++StructuredIndex;
+ }
+ }
+}
+
+void InitListChecker::CheckScalarType(InitListExpr *IList, QualType DeclType,
+ 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_many_braces_around_scalar_init)
+ << IList->getSourceRange();
+ hadError = true;
+ ++Index;
+ ++StructuredIndex;
+ return;
+ } else if (isa<DesignatedInitExpr>(expr)) {
+ SemaRef.Diag(expr->getSourceRange().getBegin(),
+ diag::err_designator_for_scalar_init)
+ << DeclType << expr->getSourceRange();
+ hadError = true;
+ ++Index;
+ ++StructuredIndex;
+ return;
+ }
+
+ Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
+ if (CheckSingleInitializer(expr, DeclType, false, SemaRef))
+ hadError = true; // types weren't compatible.
+ else if (savExpr != expr) {
+ // The type was promoted, update initializer list.
+ IList->setInit(Index, expr);
+ }
+ if (hadError)
+ ++StructuredIndex;
+ else
+ UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+ ++Index;
+ } else {
+ SemaRef.Diag(IList->getLocStart(), diag::err_empty_scalar_initializer)
+ << IList->getSourceRange();
+ hadError = true;
+ ++Index;
+ ++StructuredIndex;
+ return;
+ }
+}
+
+void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType,
+ 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;
+ }
+
+ Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
+ if (SemaRef.CheckReferenceInit(expr, DeclType))
+ hadError = true;
+ else if (savExpr != expr) {
+ // The type was promoted, update initializer list.
+ IList->setInit(Index, expr);
+ }
+ if (hadError)
+ ++StructuredIndex;
+ else
+ UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+ ++Index;
+ } else {
+ // 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();
+ hadError = true;
+ ++Index;
+ ++StructuredIndex;
+ return;
+ }
+}
+
+void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex) {
+ if (Index < IList->getNumInits()) {
+ const VectorType *VT = DeclType->getAsVectorType();
+ int maxElements = VT->getNumElements();
+ QualType elementType = VT->getElementType();
+
+ for (int i = 0; i < maxElements; ++i) {
+ // Don't attempt to go past the end of the init list
+ if (Index >= IList->getNumInits())
+ break;
+ CheckSubElementType(IList, elementType, Index,
+ StructuredList, StructuredIndex);
+ }
+ }
+}
+
+void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
+ llvm::APSInt elementIndex,
+ bool SubobjectIsDesignatorContext,
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex) {
+ // Check for the special-case of initializing an array with a string.
+ if (Index < IList->getNumInits()) {
+ if (Expr *Str = IsStringInit(IList->getInit(Index), DeclType,
+ SemaRef.Context)) {
+ CheckStringInit(Str, DeclType, 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);
+ ++Index;
+ return;
+ }
+ }
+ if (const VariableArrayType *VAT =
+ SemaRef.Context.getAsVariableArrayType(DeclType)) {
+ // 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();
+ hadError = true;
+ ++Index;
+ ++StructuredIndex;
+ return;
+ }
+
+ // We might know the maximum number of elements in advance.
+ llvm::APSInt maxElements(elementIndex.getBitWidth(),
+ elementIndex.isUnsigned());
+ bool maxElementsKnown = false;
+ if (const ConstantArrayType *CAT =
+ SemaRef.Context.getAsConstantArrayType(DeclType)) {
+ maxElements = CAT->getSize();
+ elementIndex.extOrTrunc(maxElements.getBitWidth());
+ elementIndex.setIsUnsigned(maxElements.isUnsigned());
+ maxElementsKnown = true;
+ }
+
+ QualType elementType = SemaRef.Context.getAsArrayType(DeclType)
+ ->getElementType();
+ while (Index < IList->getNumInits()) {
+ Expr *Init = IList->getInit(Index);
+ if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) {
+ // If we're not the subobject that matches up with the '{' for
+ // the designator, we shouldn't be handling the
+ // designator. Return immediately.
+ if (!SubobjectIsDesignatorContext)
+ return;
+
+ // Handle this designated initializer. elementIndex will be
+ // updated to be the next array element we'll initialize.
+ if (CheckDesignatedInitializer(IList, DIE, 0,
+ DeclType, 0, &elementIndex, Index,
+ StructuredList, StructuredIndex, true,
+ false)) {
+ hadError = true;
+ continue;
+ }
+
+ if (elementIndex.getBitWidth() > maxElements.getBitWidth())
+ maxElements.extend(elementIndex.getBitWidth());
+ else if (elementIndex.getBitWidth() < maxElements.getBitWidth())
+ elementIndex.extend(maxElements.getBitWidth());
+ elementIndex.setIsUnsigned(maxElements.isUnsigned());
+
+ // If the array is of incomplete type, keep track of the number of
+ // elements in the initializer.
+ if (!maxElementsKnown && elementIndex > maxElements)
+ maxElements = elementIndex;
+
+ continue;
+ }
+
+ // If we know the maximum number of elements, and we've already
+ // hit it, stop consuming elements in the initializer list.
+ if (maxElementsKnown && elementIndex == maxElements)
+ break;
+
+ // Check this element.
+ CheckSubElementType(IList, elementType, Index,
+ StructuredList, StructuredIndex);
+ ++elementIndex;
+
+ // If the array is of incomplete type, keep track of the number of
+ // elements in the initializer.
+ if (!maxElementsKnown && elementIndex > maxElements)
+ maxElements = elementIndex;
+ }
+ if (!hadError && DeclType->isIncompleteArrayType()) {
+ // If this is an incomplete array type, the actual type needs to
+ // be calculated here.
+ llvm::APSInt Zero(maxElements.getBitWidth(), maxElements.isUnsigned());
+ if (maxElements == Zero) {
+ // Sizing an array implicitly to zero is not allowed by ISO C,
+ // but is supported by GNU.
+ SemaRef.Diag(IList->getLocStart(),
+ diag::ext_typecheck_zero_array_size);
+ }
+
+ DeclType = SemaRef.Context.getConstantArrayType(elementType, maxElements,
+ ArrayType::Normal, 0);
+ }
+}
+
+void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
+ QualType DeclType,
+ RecordDecl::field_iterator Field,
+ bool SubobjectIsDesignatorContext,
+ unsigned &Index,
+ InitListExpr *StructuredList,
+ unsigned &StructuredIndex,
+ bool TopLevelObject) {
+ RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl();
+
+ // If the record is invalid, some of it's members are invalid. To avoid
+ // confusion, we forgo checking the intializer for the entire record.
+ if (structDecl->isInvalidDecl()) {
+ hadError = true;
+ return;
+ }
+
+ if (DeclType->isUnionType() && IList->getNumInits() == 0) {
+ // Value-initialize the first named member of the union.
+ RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
+ for (RecordDecl::field_iterator FieldEnd = RD->field_end(SemaRef.Context);
+ Field != FieldEnd; ++Field) {
+ if (Field->getDeclName()) {
+ StructuredList->setInitializedFieldInUnion(*Field);
+ break;
+ }
+ }
+ return;
+ }
+
+ // If structDecl is a forward declaration, this loop won't do
+ // anything except look at designated initializers; That's okay,
+ // because an error should get printed out elsewhere. It might be
+ // worthwhile to skip over the rest of the initializer, though.
+ RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
+ RecordDecl::field_iterator FieldEnd = RD->field_end(SemaRef.Context);
+ bool InitializedSomething = false;
+ while (Index < IList->getNumInits()) {
+ Expr *Init = IList->getInit(Index);
+
+ if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) {
+ // If we're not the subobject that matches up with the '{' for
+ // the designator, we shouldn't be handling the
+ // designator. Return immediately.
+ if (!SubobjectIsDesignatorContext)
+ return;
+
+ // Handle this designated initializer. Field will be updated to
+ // the next field that we'll be initializing.
+ if (CheckDesignatedInitializer(IList, DIE, 0,
+ DeclType, &Field, 0, Index,
+ StructuredList, StructuredIndex,
+ true, TopLevelObject))
+ hadError = true;
+
+ InitializedSomething = true;
+ continue;
+ }
+
+ if (Field == FieldEnd) {
+ // We've run out of fields. We're done.
+ break;
+ }
+
+ // We've already initialized a member of a union. We're done.
+ if (InitializedSomething && DeclType->isUnionType())
+ break;
+
+ // If we've hit the flexible array member at the end, we're done.
+ if (Field->getType()->isIncompleteArrayType())
+ break;
+
+ if (Field->isUnnamedBitfield()) {
+ // Don't initialize unnamed bitfields, e.g. "int : 20;"
+ ++Field;
+ continue;
+ }
+
+ CheckSubElementType(IList, Field->getType(), Index,
+ StructuredList, StructuredIndex);
+ InitializedSomething = true;
+
+ if (DeclType->isUnionType()) {
+ // Initialize the first field within the union.
+ StructuredList->setInitializedFieldInUnion(*Field);
+ }
+
+ ++Field;
+ }
+
+ if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() ||
+ 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;
+ 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;
+ }
+
+ if (isa<InitListExpr>(IList->getInit(Index)))
+ CheckSubElementType(IList, Field->getType(), Index, StructuredList,
+ StructuredIndex);
+ else
+ CheckImplicitInitList(IList, Field->getType(), Index, StructuredList,
+ StructuredIndex);
+}
+
+/// \brief Expand a field designator that refers to a member of an
+/// anonymous struct or union into a series of field designators that
+/// refers to the field within the appropriate subobject.
+///
+/// Field/FieldIndex will be updated to point to the (new)
+/// currently-designated field.
+static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
+ DesignatedInitExpr *DIE,
+ unsigned DesigIdx,
+ FieldDecl *Field,
+ RecordDecl::field_iterator &FieldIter,
+ unsigned &FieldIndex) {
+ typedef DesignatedInitExpr::Designator Designator;
+
+ // Build the path from the current object to the member of the
+ // anonymous struct/union (backwards).
+ llvm::SmallVector<FieldDecl *, 4> Path;
+ SemaRef.BuildAnonymousStructUnionMemberPath(Field, Path);
+
+ // Build the replacement designators.
+ llvm::SmallVector<Designator, 4> Replacements;
+ for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator
+ FI = Path.rbegin(), FIEnd = Path.rend();
+ FI != FIEnd; ++FI) {
+ if (FI + 1 == FIEnd)
+ Replacements.push_back(Designator((IdentifierInfo *)0,
+ DIE->getDesignator(DesigIdx)->getDotLoc(),
+ DIE->getDesignator(DesigIdx)->getFieldLoc()));
+ else
+ Replacements.push_back(Designator((IdentifierInfo *)0, SourceLocation(),
+ SourceLocation()));
+ Replacements.back().setField(*FI);
+ }
+
+ // Expand the current designator into the set of replacement
+ // designators, so we have a full subobject path down to where the
+ // member of the anonymous struct/union is actually stored.
+ DIE->ExpandDesignator(DesigIdx, &Replacements[0],
+ &Replacements[0] + Replacements.size());
+
+ // Update FieldIter/FieldIndex;
+ RecordDecl *Record = cast<RecordDecl>(Path.back()->getDeclContext());
+ FieldIter = Record->field_begin(SemaRef.Context);
+ FieldIndex = 0;
+ for (RecordDecl::field_iterator FEnd = Record->field_end(SemaRef.Context);
+ FieldIter != FEnd; ++FieldIter) {
+ if (FieldIter->isUnnamedBitfield())
+ continue;
+
+ if (*FieldIter == Path.back())
+ return;
+
+ ++FieldIndex;
+ }
+
+ assert(false && "Unable to find anonymous struct/union field");
+}
+
+/// @brief Check the well-formedness of a C99 designated initializer.
+///
+/// Determines whether the designated initializer @p DIE, which
+/// resides at the given @p Index within the initializer list @p
+/// IList, is well-formed for a current object of type @p DeclType
+/// (C99 6.7.8). The actual subobject that this designator refers to
+/// within the current subobject is returned in either
+/// @p NextField or @p NextElementIndex (whichever is appropriate).
+///
+/// @param IList The initializer list in which this designated
+/// initializer occurs.
+///
+/// @param DIE The designated initializer expression.
+///
+/// @param DesigIdx The index of the current designator.
+///
+/// @param DeclType The type of the "current object" (C99 6.7.8p17),
+/// into which the designation in @p DIE should refer.
+///
+/// @param NextField If non-NULL and the first designator in @p DIE is
+/// a field, this will be set to the field declaration corresponding
+/// to the field named by the designator.
+///
+/// @param NextElementIndex If non-NULL and the first designator in @p
+/// DIE is an array designator or GNU array-range designator, this
+/// will be set to the last index initialized by this designator.
+///
+/// @param Index Index into @p IList where the designated initializer
+/// @p DIE occurs.
+///
+/// @param StructuredList The initializer list expression that
+/// describes all of the subobject initializers in the order they'll
+/// actually be initialized.
+///
+/// @returns true if there was an error, false otherwise.
+bool
+InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
+ 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()) {
+ // Check the actual initialization for the designated object type.
+ bool prevHadError = hadError;
+
+ // Temporarily remove the designator expression from the
+ // initializer list that the child calls see, so that we don't try
+ // to re-process the designator.
+ unsigned OldIndex = Index;
+ IList->setInit(OldIndex, DIE->getInit());
+
+ CheckSubElementType(IList, CurrentObjectType, Index,
+ StructuredList, StructuredIndex);
+
+ // Restore the designated initializer expression in the syntactic
+ // form of the initializer list.
+ if (IList->getInit(OldIndex) != DIE->getInit())
+ DIE->setInit(IList->getInit(OldIndex));
+ IList->setInit(OldIndex, DIE);
+
+ 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");
+
+ if (D->isFieldDesignator()) {
+ // C99 6.7.8p7:
+ //
+ // If a designator has the form
+ //
+ // . identifier
+ //
+ // then the current object (defined below) shall have
+ // structure or union type and the identifier shall be the
+ // name of a member of that type.
+ const RecordType *RT = CurrentObjectType->getAsRecordType();
+ if (!RT) {
+ SourceLocation Loc = D->getDotLoc();
+ if (Loc.isInvalid())
+ Loc = D->getFieldLoc();
+ SemaRef.Diag(Loc, diag::err_field_designator_non_aggr)
+ << SemaRef.getLangOptions().CPlusPlus << CurrentObjectType;
+ ++Index;
+ return true;
+ }
+
+ // Note: we perform a linear search of the fields here, despite
+ // the fact that we have a faster lookup method, because we always
+ // need to compute the field's index.
+ FieldDecl *KnownField = D->getField();
+ IdentifierInfo *FieldName = D->getFieldName();
+ unsigned FieldIndex = 0;
+ RecordDecl::field_iterator
+ Field = RT->getDecl()->field_begin(SemaRef.Context),
+ FieldEnd = RT->getDecl()->field_end(SemaRef.Context);
+ for (; Field != FieldEnd; ++Field) {
+ if (Field->isUnnamedBitfield())
+ continue;
+
+ if (KnownField == *Field || Field->getIdentifier() == FieldName)
+ break;
+
+ ++FieldIndex;
+ }
+
+ if (Field == FieldEnd) {
+ // 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),
+ // may find nothing, or may find a member of an anonymous
+ // struct/union.
+ DeclContext::lookup_result Lookup
+ = RT->getDecl()->lookup(SemaRef.Context, FieldName);
+ if (Lookup.first == Lookup.second) {
+ // Name lookup didn't find anything.
+ SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
+ << FieldName << CurrentObjectType;
+ ++Index;
+ return true;
+ } else if (!KnownField && isa<FieldDecl>(*Lookup.first) &&
+ cast<RecordDecl>((*Lookup.first)->getDeclContext())
+ ->isAnonymousStructOrUnion()) {
+ // Handle an field designator that refers to a member of an
+ // anonymous struct or union.
+ ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx,
+ cast<FieldDecl>(*Lookup.first),
+ Field, FieldIndex);
+ D = DIE->getDesignator(DesigIdx);
+ } else {
+ // Name lookup found something, but it wasn't a field.
+ SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
+ << FieldName;
+ SemaRef.Diag((*Lookup.first)->getLocation(),
+ diag::note_field_designator_found);
+ ++Index;
+ return true;
+ }
+ } else if (!KnownField &&
+ cast<RecordDecl>((*Field)->getDeclContext())
+ ->isAnonymousStructOrUnion()) {
+ ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, *Field,
+ Field, FieldIndex);
+ D = DIE->getDesignator(DesigIdx);
+ }
+
+ // All of the fields of a union are located at the same place in
+ // the initializer list.
+ if (RT->getDecl()->isUnion()) {
+ FieldIndex = 0;
+ StructuredList->setInitializedFieldInUnion(*Field);
+ }
+
+ // 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);
+
+ // This designator names a flexible array member.
+ if (Field->getType()->isIncompleteArrayType()) {
+ bool Invalid = false;
+ 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;
+ Invalid = true;
+ }
+
+ if (!hadError && !isa<InitListExpr>(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;
+ 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;
+ Invalid = true;
+ }
+
+ if (Invalid) {
+ ++Index;
+ return true;
+ }
+
+ // Initialize the array.
+ bool prevHadError = hadError;
+ unsigned newStructuredIndex = FieldIndex;
+ unsigned OldIndex = Index;
+ IList->setInit(Index, DIE->getInit());
+ CheckSubElementType(IList, Field->getType(), Index,
+ StructuredList, newStructuredIndex);
+ IList->setInit(OldIndex, DIE);
+ if (hadError && !prevHadError) {
+ ++Field;
+ ++FieldIndex;
+ if (NextField)
+ *NextField = Field;
+ StructuredIndex = FieldIndex;
+ return true;
+ }
+ } else {
+ // Recurse to check later designated subobjects.
+ QualType FieldType = (*Field)->getType();
+ unsigned newStructuredIndex = FieldIndex;
+ if (CheckDesignatedInitializer(IList, DIE, DesigIdx + 1, FieldType, 0, 0,
+ Index, StructuredList, newStructuredIndex,
+ true, false))
+ return true;
+ }
+
+ // Find the position of the next field to be initialized in this
+ // subobject.
+ ++Field;
+ ++FieldIndex;
+
+ // If this the first designator, our caller will continue checking
+ // the rest of this struct/class/union subobject.
+ if (IsFirstDesignator) {
+ if (NextField)
+ *NextField = Field;
+ StructuredIndex = FieldIndex;
+ return false;
+ }
+
+ if (!FinishSubobjectInit)
+ return false;
+
+ // We've already initialized something in the union; we're done.
+ if (RT->getDecl()->isUnion())
+ return hadError;
+
+ // Check the remaining fields within this class/struct/union subobject.
+ bool prevHadError = hadError;
+ CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index,
+ StructuredList, FieldIndex);
+ return hadError && !prevHadError;
+ }
+
+ // C99 6.7.8p6:
+ //
+ // If a designator has the form
+ //
+ // [ constant-expression ]
+ //
+ // then the current object (defined below) shall have array
+ // type and the expression shall be an integer constant
+ // expression. If the array is of unknown size, any
+ // nonnegative value is valid.
+ //
+ // Additionally, cope with the GNU extension that permits
+ // designators of the form
+ //
+ // [ constant-expression ... constant-expression ]
+ const ArrayType *AT = SemaRef.Context.getAsArrayType(CurrentObjectType);
+ if (!AT) {
+ SemaRef.Diag(D->getLBracketLoc(), diag::err_array_designator_non_array)
+ << CurrentObjectType;
+ ++Index;
+ return true;
+ }
+
+ Expr *IndexExpr = 0;
+ llvm::APSInt DesignatedStartIndex, DesignatedEndIndex;
+ if (D->isArrayDesignator()) {
+ IndexExpr = DIE->getArrayIndex(*D);
+ DesignatedStartIndex = IndexExpr->EvaluateAsInt(SemaRef.Context);
+ DesignatedEndIndex = DesignatedStartIndex;
+ } else {
+ assert(D->isArrayRangeDesignator() && "Need array-range designator");
+
+
+ DesignatedStartIndex =
+ DIE->getArrayRangeStart(*D)->EvaluateAsInt(SemaRef.Context);
+ DesignatedEndIndex =
+ DIE->getArrayRangeEnd(*D)->EvaluateAsInt(SemaRef.Context);
+ IndexExpr = DIE->getArrayRangeEnd(*D);
+
+ if (DesignatedStartIndex.getZExtValue() !=DesignatedEndIndex.getZExtValue())
+ FullyStructuredList->sawArrayRangeDesignator();
+ }
+
+ if (isa<ConstantArrayType>(AT)) {
+ llvm::APSInt MaxElements(cast<ConstantArrayType>(AT)->getSize(), false);
+ DesignatedStartIndex.extOrTrunc(MaxElements.getBitWidth());
+ DesignatedStartIndex.setIsUnsigned(MaxElements.isUnsigned());
+ 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();
+ ++Index;
+ return true;
+ }
+ } else {
+ // Make sure the bit-widths and signedness match.
+ if (DesignatedStartIndex.getBitWidth() > DesignatedEndIndex.getBitWidth())
+ DesignatedEndIndex.extend(DesignatedStartIndex.getBitWidth());
+ else if (DesignatedStartIndex.getBitWidth() <
+ DesignatedEndIndex.getBitWidth())
+ DesignatedStartIndex.extend(DesignatedEndIndex.getBitWidth());
+ DesignatedStartIndex.setIsUnsigned(true);
+ DesignatedEndIndex.setIsUnsigned(true);
+ }
+
+ // Make sure that our non-designated initializer list has space
+ // for a subobject corresponding to this array element.
+ if (DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits())
+ StructuredList->resizeInits(SemaRef.Context,
+ DesignatedEndIndex.getZExtValue() + 1);
+
+ // Repeatedly perform subobject initializations in the range
+ // [DesignatedStartIndex, DesignatedEndIndex].
+
+ // Move to the next designator
+ unsigned ElementIndex = DesignatedStartIndex.getZExtValue();
+ unsigned OldIndex = Index;
+ while (DesignatedStartIndex <= DesignatedEndIndex) {
+ // Recurse to check later designated subobjects.
+ QualType ElementType = AT->getElementType();
+ Index = OldIndex;
+ if (CheckDesignatedInitializer(IList, DIE, DesigIdx + 1, ElementType, 0, 0,
+ Index, StructuredList, ElementIndex,
+ (DesignatedStartIndex == DesignatedEndIndex),
+ false))
+ return true;
+
+ // Move to the next index in the array that we'll be initializing.
+ ++DesignatedStartIndex;
+ ElementIndex = DesignatedStartIndex.getZExtValue();
+ }
+
+ // If this the first designator, our caller will continue checking
+ // the rest of this array subobject.
+ if (IsFirstDesignator) {
+ if (NextElementIndex)
+ *NextElementIndex = DesignatedStartIndex;
+ StructuredIndex = ElementIndex;
+ return false;
+ }
+
+ if (!FinishSubobjectInit)
+ return false;
+
+ // Check the remaining elements within this array subobject.
+ bool prevHadError = hadError;
+ CheckArrayType(IList, CurrentObjectType, DesignatedStartIndex, false, Index,
+ StructuredList, ElementIndex);
+ return hadError && !prevHadError;
+}
+
+// Get the structured initializer list for a subobject of type
+// @p CurrentObjectType.
+InitListExpr *
+InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
+ QualType CurrentObjectType,
+ InitListExpr *StructuredList,
+ unsigned StructuredIndex,
+ SourceRange InitRange) {
+ Expr *ExistingInit = 0;
+ if (!StructuredList)
+ ExistingInit = SyntacticToSemantic[IList];
+ else if (StructuredIndex < StructuredList->getNumInits())
+ ExistingInit = StructuredList->getInit(StructuredIndex);
+
+ if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit))
+ return Result;
+
+ if (ExistingInit) {
+ // We are creating an initializer list that initializes the
+ // subobjects of the current object, but there was already an
+ // initialization that completely initialized the current
+ // subobject, e.g., by a compound literal:
+ //
+ // struct X { int a, b; };
+ // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
+ //
+ // Here, xs[0].a == 0 and xs[0].b == 3, since the second,
+ // designated initializer re-initializes the whole
+ // subobject [0], overwriting previous initializers.
+ SemaRef.Diag(InitRange.getBegin(),
+ diag::warn_subobject_initializer_overrides)
+ << InitRange;
+ SemaRef.Diag(ExistingInit->getSourceRange().getBegin(),
+ diag::note_previous_initializer)
+ << /*FIXME:has side effects=*/0
+ << ExistingInit->getSourceRange();
+ }
+
+ InitListExpr *Result
+ = new (SemaRef.Context) InitListExpr(InitRange.getBegin(), 0, 0,
+ InitRange.getEnd());
+
+ Result->setType(CurrentObjectType);
+
+ // Pre-allocate storage for the structured initializer list.
+ unsigned NumElements = 0;
+ unsigned NumInits = 0;
+ if (!StructuredList)
+ NumInits = IList->getNumInits();
+ else if (Index < IList->getNumInits()) {
+ if (InitListExpr *SubList = dyn_cast<InitListExpr>(IList->getInit(Index)))
+ NumInits = SubList->getNumInits();
+ }
+
+ if (const ArrayType *AType
+ = SemaRef.Context.getAsArrayType(CurrentObjectType)) {
+ if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType)) {
+ NumElements = CAType->getSize().getZExtValue();
+ // Simple heuristic so that we don't allocate a very large
+ // initializer with many empty entries at the end.
+ if (NumInits && NumElements > NumInits)
+ NumElements = 0;
+ }
+ } else if (const VectorType *VType = CurrentObjectType->getAsVectorType())
+ NumElements = VType->getNumElements();
+ else if (const RecordType *RType = CurrentObjectType->getAsRecordType()) {
+ RecordDecl *RDecl = RType->getDecl();
+ if (RDecl->isUnion())
+ NumElements = 1;
+ else
+ NumElements = std::distance(RDecl->field_begin(SemaRef.Context),
+ RDecl->field_end(SemaRef.Context));
+ }
+
+ if (NumElements < NumInits)
+ NumElements = IList->getNumInits();
+
+ Result->reserveInits(NumElements);
+
+ // Link this new initializer list into the structured initializer
+ // lists.
+ if (StructuredList)
+ StructuredList->updateInit(StructuredIndex, Result);
+ else {
+ Result->setSyntacticForm(IList);
+ SyntacticToSemantic[IList] = Result;
+ }
+
+ return Result;
+}
+
+/// Update the initializer at index @p StructuredIndex within the
+/// structured initializer list to the value @p expr.
+void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
+ unsigned &StructuredIndex,
+ Expr *expr) {
+ // No structured initializer list to update
+ if (!StructuredList)
+ return;
+
+ if (Expr *PrevInit = StructuredList->updateInit(StructuredIndex, expr)) {
+ // This initializer overwrites a previous initializer. Warn.
+ SemaRef.Diag(expr->getSourceRange().getBegin(),
+ diag::warn_initializer_overrides)
+ << expr->getSourceRange();
+ SemaRef.Diag(PrevInit->getSourceRange().getBegin(),
+ diag::note_previous_initializer)
+ << /*FIXME:has side effects=*/0
+ << PrevInit->getSourceRange();
+ }
+
+ ++StructuredIndex;
+}
+
+/// Check that the given Index expression is a valid array designator
+/// value. This is essentailly just a wrapper around
+/// VerifyIntegerConstantExpression that also checks for negative values
+/// and produces a reasonable diagnostic if there is a
+/// failure. Returns true if there was an error, false otherwise. If
+/// everything went okay, Value will receive the value of the constant
+/// expression.
+static bool
+CheckArrayDesignatorExpr(Sema &S, Expr *Index, llvm::APSInt &Value) {
+ SourceLocation Loc = Index->getSourceRange().getBegin();
+
+ // Make sure this is an integer constant expression.
+ if (S.VerifyIntegerConstantExpression(Index, &Value))
+ return true;
+
+ if (Value.isSigned() && Value.isNegative())
+ return S.Diag(Loc, diag::err_array_designator_negative)
+ << Value.toString(10) << Index->getSourceRange();
+
+ Value.setIsUnsigned(true);
+ return false;
+}
+
+Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
+ SourceLocation Loc,
+ bool GNUSyntax,
+ OwningExprResult Init) {
+ typedef DesignatedInitExpr::Designator ASTDesignator;
+
+ bool Invalid = false;
+ llvm::SmallVector<ASTDesignator, 32> Designators;
+ llvm::SmallVector<Expr *, 32> InitExpressions;
+
+ // Build designators and check array designator expressions.
+ for (unsigned Idx = 0; Idx < Desig.getNumDesignators(); ++Idx) {
+ const Designator &D = Desig.getDesignator(Idx);
+ switch (D.getKind()) {
+ case Designator::FieldDesignator:
+ Designators.push_back(ASTDesignator(D.getField(), D.getDotLoc(),
+ D.getFieldLoc()));
+ break;
+
+ case Designator::ArrayDesignator: {
+ Expr *Index = static_cast<Expr *>(D.getArrayIndex());
+ llvm::APSInt IndexValue;
+ if (!Index->isTypeDependent() &&
+ !Index->isValueDependent() &&
+ CheckArrayDesignatorExpr(*this, Index, IndexValue))
+ Invalid = true;
+ else {
+ Designators.push_back(ASTDesignator(InitExpressions.size(),
+ D.getLBracketLoc(),
+ D.getRBracketLoc()));
+ InitExpressions.push_back(Index);
+ }
+ break;
+ }
+
+ case Designator::ArrayRangeDesignator: {
+ Expr *StartIndex = static_cast<Expr *>(D.getArrayRangeStart());
+ Expr *EndIndex = static_cast<Expr *>(D.getArrayRangeEnd());
+ llvm::APSInt StartValue;
+ llvm::APSInt EndValue;
+ bool StartDependent = StartIndex->isTypeDependent() ||
+ StartIndex->isValueDependent();
+ bool EndDependent = EndIndex->isTypeDependent() ||
+ EndIndex->isValueDependent();
+ if ((!StartDependent &&
+ CheckArrayDesignatorExpr(*this, StartIndex, StartValue)) ||
+ (!EndDependent &&
+ CheckArrayDesignatorExpr(*this, EndIndex, EndValue)))
+ Invalid = true;
+ else {
+ // Make sure we're comparing values with the same bit width.
+ if (StartDependent || EndDependent) {
+ // Nothing to compute.
+ } else if (StartValue.getBitWidth() > EndValue.getBitWidth())
+ EndValue.extend(StartValue.getBitWidth());
+ else if (StartValue.getBitWidth() < EndValue.getBitWidth())
+ StartValue.extend(EndValue.getBitWidth());
+
+ if (!StartDependent && !EndDependent && EndValue < StartValue) {
+ Diag(D.getEllipsisLoc(), diag::err_array_designator_empty_range)
+ << StartValue.toString(10) << EndValue.toString(10)
+ << StartIndex->getSourceRange() << EndIndex->getSourceRange();
+ Invalid = true;
+ } else {
+ Designators.push_back(ASTDesignator(InitExpressions.size(),
+ D.getLBracketLoc(),
+ D.getEllipsisLoc(),
+ D.getRBracketLoc()));
+ InitExpressions.push_back(StartIndex);
+ InitExpressions.push_back(EndIndex);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (Invalid || Init.isInvalid())
+ return ExprError();
+
+ // Clear out the expressions within the designation.
+ Desig.ClearExprs(*this);
+
+ DesignatedInitExpr *DIE
+ = DesignatedInitExpr::Create(Context,
+ Designators.data(), Designators.size(),
+ InitExpressions.data(), InitExpressions.size(),
+ Loc, GNUSyntax, Init.takeAs<Expr>());
+ return Owned(DIE);
+}
+
+bool Sema::CheckInitList(InitListExpr *&InitList, QualType &DeclType) {
+ InitListChecker CheckInitList(*this, InitList, DeclType);
+ if (!CheckInitList.HadError())
+ InitList = CheckInitList.getFullyStructuredList();
+
+ return CheckInitList.HadError();
+}
+
+/// \brief Diagnose any semantic errors with value-initialization of
+/// the given type.
+///
+/// Value-initialization effectively zero-initializes any types
+/// without user-declared constructors, and calls the default
+/// constructor for a for any type that has a user-declared
+/// constructor (C++ [dcl.init]p5). Value-initialization can fail when
+/// a type with a user-declared constructor does not have an
+/// accessible, non-deleted default constructor. In C, everything can
+/// be value-initialized, which corresponds to C's notion of
+/// initializing objects with static storage duration when no
+/// initializer is provided for that object.
+///
+/// \returns true if there was an error, false otherwise.
+bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) {
+ // C++ [dcl.init]p5:
+ //
+ // To value-initialize an object of type T means:
+
+ // -- if T is an array type, then each element is value-initialized;
+ if (const ArrayType *AT = Context.getAsArrayType(Type))
+ return CheckValueInitialization(AT->getElementType(), Loc);
+
+ if (const RecordType *RT = Type->getAsRecordType()) {
+ if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ // -- if T is a class type (clause 9) with a user-declared
+ // constructor (12.1), then the default constructor for T is
+ // called (and the initialization is ill-formed if T has no
+ // accessible default constructor);
+ if (ClassDecl->hasUserDeclaredConstructor())
+ // FIXME: Eventually, we'll need to put the constructor decl into the
+ // AST.
+ return PerformInitializationByConstructor(Type, 0, 0, Loc,
+ SourceRange(Loc),
+ DeclarationName(),
+ IK_Direct);
+ }
+ }
+
+ if (Type->isReferenceType()) {
+ // C++ [dcl.init]p5:
+ // [...] A program that calls for default-initialization or
+ // value-initialization of an entity of reference type is
+ // ill-formed. [...]
+ // FIXME: Once we have code that goes through this path, add an actual
+ // diagnostic :)
+ }
+
+ return false;
+}
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
new file mode 100644
index 000000000000..6212449744ca
--- /dev/null
+++ b/lib/Sema/SemaLookup.cpp
@@ -0,0 +1,1626 @@
+//===--------------------- SemaLookup.cpp - Name Lookup ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements name lookup for C, C++, Objective-C, and
+// Objective-C++.
+//
+//===----------------------------------------------------------------------===//
+#include "Sema.h"
+#include "SemaInherit.h"
+#include "clang/AST/ASTContext.h"
+#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/Parse/DeclSpec.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include <set>
+#include <vector>
+#include <iterator>
+#include <utility>
+#include <algorithm>
+
+using namespace clang;
+
+typedef llvm::SmallVector<UsingDirectiveDecl*, 4> UsingDirectivesTy;
+typedef llvm::DenseSet<NamespaceDecl*> NamespaceSet;
+typedef llvm::SmallVector<Sema::LookupResult, 3> LookupResultsTy;
+
+/// UsingDirAncestorCompare - Implements strict weak ordering of
+/// UsingDirectives. It orders them by address of its common ancestor.
+struct UsingDirAncestorCompare {
+
+ /// @brief Compares UsingDirectiveDecl common ancestor with DeclContext.
+ bool operator () (UsingDirectiveDecl *U, const DeclContext *Ctx) const {
+ return U->getCommonAncestor() < Ctx;
+ }
+
+ /// @brief Compares UsingDirectiveDecl common ancestor with DeclContext.
+ bool operator () (const DeclContext *Ctx, UsingDirectiveDecl *U) const {
+ return Ctx < U->getCommonAncestor();
+ }
+
+ /// @brief Compares UsingDirectiveDecl common ancestors.
+ bool operator () (UsingDirectiveDecl *U1, UsingDirectiveDecl *U2) const {
+ return U1->getCommonAncestor() < U2->getCommonAncestor();
+ }
+};
+
+/// AddNamespaceUsingDirectives - Adds all UsingDirectiveDecl's to heap UDirs
+/// (ordered by common ancestors), found in namespace NS,
+/// including all found (recursively) in their nominated namespaces.
+void AddNamespaceUsingDirectives(ASTContext &Context,
+ DeclContext *NS,
+ UsingDirectivesTy &UDirs,
+ NamespaceSet &Visited) {
+ DeclContext::udir_iterator I, End;
+
+ for (llvm::tie(I, End) = NS->getUsingDirectives(Context); I !=End; ++I) {
+ UDirs.push_back(*I);
+ std::push_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare());
+ NamespaceDecl *Nominated = (*I)->getNominatedNamespace();
+ if (Visited.insert(Nominated).second)
+ AddNamespaceUsingDirectives(Context, Nominated, UDirs, /*ref*/ Visited);
+ }
+}
+
+/// AddScopeUsingDirectives - Adds all UsingDirectiveDecl's found in Scope S,
+/// including all found in the namespaces they nominate.
+static void AddScopeUsingDirectives(ASTContext &Context, Scope *S,
+ UsingDirectivesTy &UDirs) {
+ NamespaceSet VisitedNS;
+
+ if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) {
+
+ if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(Ctx))
+ VisitedNS.insert(NS);
+
+ AddNamespaceUsingDirectives(Context, Ctx, UDirs, /*ref*/ VisitedNS);
+
+ } else {
+ Scope::udir_iterator I = S->using_directives_begin(),
+ End = S->using_directives_end();
+
+ for (; I != End; ++I) {
+ UsingDirectiveDecl *UD = I->getAs<UsingDirectiveDecl>();
+ UDirs.push_back(UD);
+ std::push_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare());
+
+ NamespaceDecl *Nominated = UD->getNominatedNamespace();
+ if (!VisitedNS.count(Nominated)) {
+ VisitedNS.insert(Nominated);
+ AddNamespaceUsingDirectives(Context, Nominated, UDirs,
+ /*ref*/ VisitedNS);
+ }
+ }
+ }
+}
+
+/// MaybeConstructOverloadSet - Name lookup has determined that the
+/// elements in [I, IEnd) have the name that we are looking for, and
+/// *I is a match for the namespace. This routine returns an
+/// appropriate Decl for name lookup, which may either be *I or an
+/// OverloadedFunctionDecl that represents the overloaded functions in
+/// [I, IEnd).
+///
+/// The existance of this routine is temporary; users of LookupResult
+/// should be able to handle multiple results, to deal with cases of
+/// ambiguity and overloaded functions without needing to create a
+/// Decl node.
+template<typename DeclIterator>
+static NamedDecl *
+MaybeConstructOverloadSet(ASTContext &Context,
+ DeclIterator I, DeclIterator IEnd) {
+ assert(I != IEnd && "Iterator range cannot be empty");
+ assert(!isa<OverloadedFunctionDecl>(*I) &&
+ "Cannot have an overloaded function");
+
+ if (isa<FunctionDecl>(*I)) {
+ // If we found a function, there might be more functions. If
+ // so, collect them into an overload set.
+ DeclIterator Last = I;
+ OverloadedFunctionDecl *Ovl = 0;
+ for (++Last; Last != IEnd && isa<FunctionDecl>(*Last); ++Last) {
+ if (!Ovl) {
+ // FIXME: We leak this overload set. Eventually, we want to stop
+ // building the declarations for these overload sets, so there will be
+ // nothing to leak.
+ Ovl = OverloadedFunctionDecl::Create(Context, (*I)->getDeclContext(),
+ (*I)->getDeclName());
+ Ovl->addOverload(cast<FunctionDecl>(*I));
+ }
+ Ovl->addOverload(cast<FunctionDecl>(*Last));
+ }
+
+ // If we had more than one function, we built an overload
+ // set. Return it.
+ if (Ovl)
+ return Ovl;
+ }
+
+ return *I;
+}
+
+/// Merges together multiple LookupResults dealing with duplicated Decl's.
+static Sema::LookupResult
+MergeLookupResults(ASTContext &Context, LookupResultsTy &Results) {
+ typedef Sema::LookupResult LResult;
+ typedef llvm::SmallPtrSet<NamedDecl*, 4> DeclsSetTy;
+
+ // Remove duplicated Decl pointing at same Decl, by storing them in
+ // associative collection. This might be case for code like:
+ //
+ // namespace A { int i; }
+ // namespace B { using namespace A; }
+ // namespace C { using namespace A; }
+ //
+ // void foo() {
+ // using namespace B;
+ // using namespace C;
+ // ++i; // finds A::i, from both namespace B and C at global scope
+ // }
+ //
+ // C++ [namespace.qual].p3:
+ // The same declaration found more than once is not an ambiguity
+ // (because it is still a unique declaration).
+ DeclsSetTy FoundDecls;
+
+ // Counter of tag names, and functions for resolving ambiguity
+ // and name hiding.
+ std::size_t TagNames = 0, Functions = 0, OrdinaryNonFunc = 0;
+
+ LookupResultsTy::iterator I = Results.begin(), End = Results.end();
+
+ // No name lookup results, return early.
+ if (I == End) return LResult::CreateLookupResult(Context, 0);
+
+ // Keep track of the tag declaration we found. We only use this if
+ // we find a single tag declaration.
+ TagDecl *TagFound = 0;
+
+ for (; I != End; ++I) {
+ switch (I->getKind()) {
+ case LResult::NotFound:
+ assert(false &&
+ "Should be always successful name lookup result here.");
+ break;
+
+ case LResult::AmbiguousReference:
+ case LResult::AmbiguousBaseSubobjectTypes:
+ case LResult::AmbiguousBaseSubobjects:
+ assert(false && "Shouldn't get ambiguous lookup here.");
+ break;
+
+ case LResult::Found: {
+ NamedDecl *ND = I->getAsDecl();
+ if (TagDecl *TD = dyn_cast<TagDecl>(ND)) {
+ TagFound = Context.getCanonicalDecl(TD);
+ TagNames += FoundDecls.insert(TagFound)? 1 : 0;
+ } else if (isa<FunctionDecl>(ND))
+ Functions += FoundDecls.insert(ND)? 1 : 0;
+ else
+ FoundDecls.insert(ND);
+ break;
+ }
+
+ case LResult::FoundOverloaded:
+ for (LResult::iterator FI = I->begin(), FEnd = I->end(); FI != FEnd; ++FI)
+ Functions += FoundDecls.insert(*FI)? 1 : 0;
+ break;
+ }
+ }
+ OrdinaryNonFunc = FoundDecls.size() - TagNames - Functions;
+ bool Ambiguous = false, NameHidesTags = false;
+
+ if (FoundDecls.size() == 1) {
+ // 1) Exactly one result.
+ } else if (TagNames > 1) {
+ // 2) Multiple tag names (even though they may be hidden by an
+ // object name).
+ Ambiguous = true;
+ } else if (FoundDecls.size() - TagNames == 1) {
+ // 3) Ordinary name hides (optional) tag.
+ NameHidesTags = TagFound;
+ } else if (Functions) {
+ // C++ [basic.lookup].p1:
+ // ... Name lookup may associate more than one declaration with
+ // a name if it finds the name to be a function name; the declarations
+ // are said to form a set of overloaded functions (13.1).
+ // Overload resolution (13.3) takes place after name lookup has succeeded.
+ //
+ if (!OrdinaryNonFunc) {
+ // 4) Functions hide tag names.
+ NameHidesTags = TagFound;
+ } else {
+ // 5) Functions + ordinary names.
+ Ambiguous = true;
+ }
+ } else {
+ // 6) Multiple non-tag names
+ Ambiguous = true;
+ }
+
+ if (Ambiguous)
+ return LResult::CreateLookupResult(Context,
+ FoundDecls.begin(), FoundDecls.size());
+ if (NameHidesTags) {
+ // There's only one tag, TagFound. Remove it.
+ assert(TagFound && FoundDecls.count(TagFound) && "No tag name found?");
+ FoundDecls.erase(TagFound);
+ }
+
+ // Return successful name lookup result.
+ return LResult::CreateLookupResult(Context,
+ MaybeConstructOverloadSet(Context,
+ FoundDecls.begin(),
+ FoundDecls.end()));
+}
+
+// Retrieve the set of identifier namespaces that correspond to a
+// specific kind of name lookup.
+inline unsigned
+getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
+ bool CPlusPlus) {
+ unsigned IDNS = 0;
+ switch (NameKind) {
+ case Sema::LookupOrdinaryName:
+ case Sema::LookupOperatorName:
+ case Sema::LookupRedeclarationWithLinkage:
+ IDNS = Decl::IDNS_Ordinary;
+ if (CPlusPlus)
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member;
+ break;
+
+ case Sema::LookupTagName:
+ IDNS = Decl::IDNS_Tag;
+ break;
+
+ case Sema::LookupMemberName:
+ IDNS = Decl::IDNS_Member;
+ if (CPlusPlus)
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_Ordinary;
+ break;
+
+ case Sema::LookupNestedNameSpecifierName:
+ case Sema::LookupNamespaceName:
+ IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member;
+ break;
+
+ case Sema::LookupObjCProtocolName:
+ IDNS = Decl::IDNS_ObjCProtocol;
+ break;
+
+ case Sema::LookupObjCImplementationName:
+ IDNS = Decl::IDNS_ObjCImplementation;
+ break;
+
+ case Sema::LookupObjCCategoryImplName:
+ IDNS = Decl::IDNS_ObjCCategoryImpl;
+ break;
+ }
+ return IDNS;
+}
+
+Sema::LookupResult
+Sema::LookupResult::CreateLookupResult(ASTContext &Context, NamedDecl *D) {
+ if (ObjCCompatibleAliasDecl *Alias
+ = dyn_cast_or_null<ObjCCompatibleAliasDecl>(D))
+ D = Alias->getClassInterface();
+
+ LookupResult Result;
+ Result.StoredKind = (D && isa<OverloadedFunctionDecl>(D))?
+ OverloadedDeclSingleDecl : SingleDecl;
+ Result.First = reinterpret_cast<uintptr_t>(D);
+ Result.Last = 0;
+ Result.Context = &Context;
+ return Result;
+}
+
+/// @brief Moves the name-lookup results from Other to this LookupResult.
+Sema::LookupResult
+Sema::LookupResult::CreateLookupResult(ASTContext &Context,
+ IdentifierResolver::iterator F,
+ IdentifierResolver::iterator L) {
+ LookupResult Result;
+ Result.Context = &Context;
+
+ if (F != L && isa<FunctionDecl>(*F)) {
+ IdentifierResolver::iterator Next = F;
+ ++Next;
+ if (Next != L && isa<FunctionDecl>(*Next)) {
+ Result.StoredKind = OverloadedDeclFromIdResolver;
+ Result.First = F.getAsOpaqueValue();
+ Result.Last = L.getAsOpaqueValue();
+ return Result;
+ }
+ }
+
+ Decl *D = *F;
+ if (ObjCCompatibleAliasDecl *Alias
+ = dyn_cast_or_null<ObjCCompatibleAliasDecl>(D))
+ D = Alias->getClassInterface();
+
+ Result.StoredKind = SingleDecl;
+ Result.First = reinterpret_cast<uintptr_t>(D);
+ Result.Last = 0;
+ return Result;
+}
+
+Sema::LookupResult
+Sema::LookupResult::CreateLookupResult(ASTContext &Context,
+ DeclContext::lookup_iterator F,
+ DeclContext::lookup_iterator L) {
+ LookupResult Result;
+ Result.Context = &Context;
+
+ if (F != L && isa<FunctionDecl>(*F)) {
+ DeclContext::lookup_iterator Next = F;
+ ++Next;
+ if (Next != L && isa<FunctionDecl>(*Next)) {
+ Result.StoredKind = OverloadedDeclFromDeclContext;
+ Result.First = reinterpret_cast<uintptr_t>(F);
+ Result.Last = reinterpret_cast<uintptr_t>(L);
+ return Result;
+ }
+ }
+
+ Decl *D = *F;
+ if (ObjCCompatibleAliasDecl *Alias
+ = dyn_cast_or_null<ObjCCompatibleAliasDecl>(D))
+ D = Alias->getClassInterface();
+
+ Result.StoredKind = SingleDecl;
+ Result.First = reinterpret_cast<uintptr_t>(D);
+ Result.Last = 0;
+ return Result;
+}
+
+/// @brief Determine the result of name lookup.
+Sema::LookupResult::LookupKind Sema::LookupResult::getKind() const {
+ switch (StoredKind) {
+ case SingleDecl:
+ return (reinterpret_cast<Decl *>(First) != 0)? Found : NotFound;
+
+ case OverloadedDeclSingleDecl:
+ case OverloadedDeclFromIdResolver:
+ case OverloadedDeclFromDeclContext:
+ return FoundOverloaded;
+
+ case AmbiguousLookupStoresBasePaths:
+ return Last? AmbiguousBaseSubobjectTypes : AmbiguousBaseSubobjects;
+
+ case AmbiguousLookupStoresDecls:
+ return AmbiguousReference;
+ }
+
+ // We can't ever get here.
+ return NotFound;
+}
+
+/// @brief Converts the result of name lookup into a single (possible
+/// NULL) pointer to a declaration.
+///
+/// The resulting declaration will either be the declaration we found
+/// (if only a single declaration was found), an
+/// OverloadedFunctionDecl (if an overloaded function was found), or
+/// NULL (if no declaration was found). This conversion must not be
+/// used anywhere where name lookup could result in an ambiguity.
+///
+/// The OverloadedFunctionDecl conversion is meant as a stop-gap
+/// solution, since it causes the OverloadedFunctionDecl to be
+/// leaked. FIXME: Eventually, there will be a better way to iterate
+/// over the set of overloaded functions returned by name lookup.
+NamedDecl *Sema::LookupResult::getAsDecl() const {
+ switch (StoredKind) {
+ case SingleDecl:
+ return reinterpret_cast<NamedDecl *>(First);
+
+ case OverloadedDeclFromIdResolver:
+ return MaybeConstructOverloadSet(*Context,
+ IdentifierResolver::iterator::getFromOpaqueValue(First),
+ IdentifierResolver::iterator::getFromOpaqueValue(Last));
+
+ case OverloadedDeclFromDeclContext:
+ return MaybeConstructOverloadSet(*Context,
+ reinterpret_cast<DeclContext::lookup_iterator>(First),
+ reinterpret_cast<DeclContext::lookup_iterator>(Last));
+
+ case OverloadedDeclSingleDecl:
+ return reinterpret_cast<OverloadedFunctionDecl*>(First);
+
+ case AmbiguousLookupStoresDecls:
+ case AmbiguousLookupStoresBasePaths:
+ assert(false &&
+ "Name lookup returned an ambiguity that could not be handled");
+ break;
+ }
+
+ return 0;
+}
+
+/// @brief Retrieves the BasePaths structure describing an ambiguous
+/// name lookup, or null.
+BasePaths *Sema::LookupResult::getBasePaths() const {
+ if (StoredKind == AmbiguousLookupStoresBasePaths)
+ return reinterpret_cast<BasePaths *>(First);
+ return 0;
+}
+
+Sema::LookupResult::iterator::reference
+Sema::LookupResult::iterator::operator*() const {
+ switch (Result->StoredKind) {
+ case SingleDecl:
+ return reinterpret_cast<NamedDecl*>(Current);
+
+ case OverloadedDeclSingleDecl:
+ return *reinterpret_cast<NamedDecl**>(Current);
+
+ case OverloadedDeclFromIdResolver:
+ return *IdentifierResolver::iterator::getFromOpaqueValue(Current);
+
+ case AmbiguousLookupStoresBasePaths:
+ if (Result->Last)
+ return *reinterpret_cast<NamedDecl**>(Current);
+
+ // Fall through to handle the DeclContext::lookup_iterator we're
+ // storing.
+
+ case OverloadedDeclFromDeclContext:
+ case AmbiguousLookupStoresDecls:
+ return *reinterpret_cast<DeclContext::lookup_iterator>(Current);
+ }
+
+ return 0;
+}
+
+Sema::LookupResult::iterator& Sema::LookupResult::iterator::operator++() {
+ switch (Result->StoredKind) {
+ case SingleDecl:
+ Current = reinterpret_cast<uintptr_t>((NamedDecl*)0);
+ break;
+
+ case OverloadedDeclSingleDecl: {
+ NamedDecl ** I = reinterpret_cast<NamedDecl**>(Current);
+ ++I;
+ Current = reinterpret_cast<uintptr_t>(I);
+ break;
+ }
+
+ case OverloadedDeclFromIdResolver: {
+ IdentifierResolver::iterator I
+ = IdentifierResolver::iterator::getFromOpaqueValue(Current);
+ ++I;
+ Current = I.getAsOpaqueValue();
+ break;
+ }
+
+ case AmbiguousLookupStoresBasePaths:
+ if (Result->Last) {
+ NamedDecl ** I = reinterpret_cast<NamedDecl**>(Current);
+ ++I;
+ Current = reinterpret_cast<uintptr_t>(I);
+ break;
+ }
+ // Fall through to handle the DeclContext::lookup_iterator we're
+ // storing.
+
+ case OverloadedDeclFromDeclContext:
+ case AmbiguousLookupStoresDecls: {
+ DeclContext::lookup_iterator I
+ = reinterpret_cast<DeclContext::lookup_iterator>(Current);
+ ++I;
+ Current = reinterpret_cast<uintptr_t>(I);
+ break;
+ }
+ }
+
+ return *this;
+}
+
+Sema::LookupResult::iterator Sema::LookupResult::begin() {
+ switch (StoredKind) {
+ case SingleDecl:
+ case OverloadedDeclFromIdResolver:
+ case OverloadedDeclFromDeclContext:
+ case AmbiguousLookupStoresDecls:
+ return iterator(this, First);
+
+ case OverloadedDeclSingleDecl: {
+ OverloadedFunctionDecl * Ovl =
+ reinterpret_cast<OverloadedFunctionDecl*>(First);
+ return iterator(this,
+ reinterpret_cast<uintptr_t>(&(*Ovl->function_begin())));
+ }
+
+ case AmbiguousLookupStoresBasePaths:
+ if (Last)
+ return iterator(this,
+ reinterpret_cast<uintptr_t>(getBasePaths()->found_decls_begin()));
+ else
+ return iterator(this,
+ reinterpret_cast<uintptr_t>(getBasePaths()->front().Decls.first));
+ }
+
+ // Required to suppress GCC warning.
+ return iterator();
+}
+
+Sema::LookupResult::iterator Sema::LookupResult::end() {
+ switch (StoredKind) {
+ case SingleDecl:
+ case OverloadedDeclFromIdResolver:
+ case OverloadedDeclFromDeclContext:
+ case AmbiguousLookupStoresDecls:
+ return iterator(this, Last);
+
+ case OverloadedDeclSingleDecl: {
+ OverloadedFunctionDecl * Ovl =
+ reinterpret_cast<OverloadedFunctionDecl*>(First);
+ return iterator(this,
+ reinterpret_cast<uintptr_t>(&(*Ovl->function_end())));
+ }
+
+ case AmbiguousLookupStoresBasePaths:
+ if (Last)
+ return iterator(this,
+ reinterpret_cast<uintptr_t>(getBasePaths()->found_decls_end()));
+ else
+ return iterator(this, reinterpret_cast<uintptr_t>(
+ getBasePaths()->front().Decls.second));
+ }
+
+ // Required to suppress GCC warning.
+ return iterator();
+}
+
+void Sema::LookupResult::Destroy() {
+ if (BasePaths *Paths = getBasePaths())
+ delete Paths;
+ else if (getKind() == AmbiguousReference)
+ delete[] reinterpret_cast<NamedDecl **>(First);
+}
+
+static void
+CppNamespaceLookup(ASTContext &Context, DeclContext *NS,
+ DeclarationName Name, Sema::LookupNameKind NameKind,
+ unsigned IDNS, LookupResultsTy &Results,
+ UsingDirectivesTy *UDirs = 0) {
+
+ assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!");
+
+ // Perform qualified name lookup into the LookupCtx.
+ DeclContext::lookup_iterator I, E;
+ for (llvm::tie(I, E) = NS->lookup(Context, Name); I != E; ++I)
+ if (Sema::isAcceptableLookupResult(*I, NameKind, IDNS)) {
+ Results.push_back(Sema::LookupResult::CreateLookupResult(Context, I, E));
+ break;
+ }
+
+ if (UDirs) {
+ // For each UsingDirectiveDecl, which common ancestor is equal
+ // to NS, we preform qualified name lookup into namespace nominated by it.
+ UsingDirectivesTy::const_iterator UI, UEnd;
+ llvm::tie(UI, UEnd) =
+ std::equal_range(UDirs->begin(), UDirs->end(), NS,
+ UsingDirAncestorCompare());
+
+ for (; UI != UEnd; ++UI)
+ CppNamespaceLookup(Context, (*UI)->getNominatedNamespace(),
+ Name, NameKind, IDNS, Results);
+ }
+}
+
+static bool isNamespaceOrTranslationUnitScope(Scope *S) {
+ if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()))
+ return Ctx->isFileContext();
+ return false;
+}
+
+std::pair<bool, Sema::LookupResult>
+Sema::CppLookupName(Scope *S, DeclarationName Name,
+ LookupNameKind NameKind, bool RedeclarationOnly) {
+ assert(getLangOptions().CPlusPlus &&
+ "Can perform only C++ lookup");
+ unsigned IDNS
+ = getIdentifierNamespacesFromLookupNameKind(NameKind, /*CPlusPlus*/ true);
+ Scope *Initial = S;
+ DeclContext *OutOfLineCtx = 0;
+ IdentifierResolver::iterator
+ I = IdResolver.begin(Name),
+ IEnd = IdResolver.end();
+
+ // First we lookup local scope.
+ // We don't consider using-directives, as per 7.3.4.p1 [namespace.udir]
+ // ...During unqualified name lookup (3.4.1), the names appear as if
+ // they were declared in the nearest enclosing namespace which contains
+ // both the using-directive and the nominated namespace.
+ // [Note: in this context, “contains†means “contains directly or
+ // indirectlyâ€.
+ //
+ // For example:
+ // namespace A { int i; }
+ // void foo() {
+ // int i;
+ // {
+ // using namespace A;
+ // ++i; // finds local 'i', A::i appears at global scope
+ // }
+ // }
+ //
+ for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) {
+ // Check whether the IdResolver has anything in this scope.
+ for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) {
+ if (isAcceptableLookupResult(*I, NameKind, IDNS)) {
+ // We found something. Look for anything else in our scope
+ // with this same name and in an acceptable identifier
+ // namespace, so that we can construct an overload set if we
+ // need to.
+ IdentifierResolver::iterator LastI = I;
+ for (++LastI; LastI != IEnd; ++LastI) {
+ if (!S->isDeclScope(DeclPtrTy::make(*LastI)))
+ break;
+ }
+ LookupResult Result =
+ LookupResult::CreateLookupResult(Context, I, LastI);
+ return std::make_pair(true, Result);
+ }
+ }
+ if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) {
+ LookupResult R;
+ // Perform member lookup into struct.
+ // FIXME: In some cases, we know that every name that could be found by
+ // this qualified name lookup will also be on the identifier chain. For
+ // example, inside a class without any base classes, we never need to
+ // perform qualified lookup because all of the members are on top of the
+ // identifier chain.
+ if (isa<RecordDecl>(Ctx)) {
+ R = LookupQualifiedName(Ctx, Name, NameKind, RedeclarationOnly);
+ if (R || RedeclarationOnly)
+ return std::make_pair(true, R);
+ }
+ if (Ctx->getParent() != Ctx->getLexicalParent()
+ || isa<CXXMethodDecl>(Ctx)) {
+ // It is out of line defined C++ method or struct, we continue
+ // doing name lookup in parent context. Once we will find namespace
+ // or translation-unit we save it for possible checking
+ // using-directives later.
+ for (OutOfLineCtx = Ctx; OutOfLineCtx && !OutOfLineCtx->isFileContext();
+ OutOfLineCtx = OutOfLineCtx->getParent()) {
+ R = LookupQualifiedName(OutOfLineCtx, Name, NameKind, RedeclarationOnly);
+ if (R || RedeclarationOnly)
+ return std::make_pair(true, R);
+ }
+ }
+ }
+ }
+
+ // Collect UsingDirectiveDecls in all scopes, and recursively all
+ // nominated namespaces by those using-directives.
+ // UsingDirectives are pushed to heap, in common ancestor pointer value order.
+ // FIXME: Cache this sorted list in Scope structure, and DeclContext, so we
+ // don't build it for each lookup!
+ UsingDirectivesTy UDirs;
+ for (Scope *SC = Initial; SC; SC = SC->getParent())
+ if (SC->getFlags() & Scope::DeclScope)
+ AddScopeUsingDirectives(Context, SC, UDirs);
+
+ // Sort heapified UsingDirectiveDecls.
+ std::sort_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare());
+
+ // Lookup namespace scope, and global scope.
+ // Unqualified name lookup in C++ requires looking into scopes
+ // that aren't strictly lexical, and therefore we walk through the
+ // context as well as walking through the scopes.
+
+ LookupResultsTy LookupResults;
+ assert((!OutOfLineCtx || OutOfLineCtx->isFileContext()) &&
+ "We should have been looking only at file context here already.");
+ bool LookedInCtx = false;
+ LookupResult Result;
+ while (OutOfLineCtx &&
+ OutOfLineCtx != S->getEntity() &&
+ OutOfLineCtx->isNamespace()) {
+ LookedInCtx = true;
+
+ // Look into context considering using-directives.
+ CppNamespaceLookup(Context, OutOfLineCtx, Name, NameKind, IDNS,
+ LookupResults, &UDirs);
+
+ if ((Result = MergeLookupResults(Context, LookupResults)) ||
+ (RedeclarationOnly && !OutOfLineCtx->isTransparentContext()))
+ return std::make_pair(true, Result);
+
+ OutOfLineCtx = OutOfLineCtx->getParent();
+ }
+
+ for (; S; S = S->getParent()) {
+ DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
+ assert(Ctx && Ctx->isFileContext() &&
+ "We should have been looking only at file context here already.");
+
+ // Check whether the IdResolver has anything in this scope.
+ for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) {
+ if (isAcceptableLookupResult(*I, NameKind, IDNS)) {
+ // We found something. Look for anything else in our scope
+ // with this same name and in an acceptable identifier
+ // namespace, so that we can construct an overload set if we
+ // need to.
+ IdentifierResolver::iterator LastI = I;
+ for (++LastI; LastI != IEnd; ++LastI) {
+ if (!S->isDeclScope(DeclPtrTy::make(*LastI)))
+ break;
+ }
+
+ // We store name lookup result, and continue trying to look into
+ // associated context, and maybe namespaces nominated by
+ // using-directives.
+ LookupResults.push_back(
+ LookupResult::CreateLookupResult(Context, I, LastI));
+ break;
+ }
+ }
+
+ LookedInCtx = true;
+ // Look into context considering using-directives.
+ CppNamespaceLookup(Context, Ctx, Name, NameKind, IDNS,
+ LookupResults, &UDirs);
+
+ if ((Result = MergeLookupResults(Context, LookupResults)) ||
+ (RedeclarationOnly && !Ctx->isTransparentContext()))
+ return std::make_pair(true, Result);
+ }
+
+ if (!(LookedInCtx || LookupResults.empty())) {
+ // We didn't Performed lookup in Scope entity, so we return
+ // result form IdentifierResolver.
+ assert((LookupResults.size() == 1) && "Wrong size!");
+ return std::make_pair(true, LookupResults.front());
+ }
+ return std::make_pair(false, LookupResult());
+}
+
+/// @brief Perform unqualified name lookup starting from a given
+/// scope.
+///
+/// Unqualified name lookup (C++ [basic.lookup.unqual], C99 6.2.1) is
+/// used to find names within the current scope. For example, 'x' in
+/// @code
+/// int x;
+/// int f() {
+/// return x; // unqualified name look finds 'x' in the global scope
+/// }
+/// @endcode
+///
+/// Different lookup criteria can find different names. For example, a
+/// particular scope can have both a struct and a function of the same
+/// name, and each can be found by certain lookup criteria. For more
+/// information about lookup criteria, see the documentation for the
+/// class LookupCriteria.
+///
+/// @param S The scope from which unqualified name lookup will
+/// begin. If the lookup criteria permits, name lookup may also search
+/// in the parent scopes.
+///
+/// @param Name The name of the entity that we are searching for.
+///
+/// @param Loc If provided, the source location where we're performing
+/// name lookup. At present, this is only used to produce diagnostics when
+/// C library functions (like "malloc") are implicitly declared.
+///
+/// @returns The result of name lookup, which includes zero or more
+/// declarations and possibly additional information used to diagnose
+/// ambiguities.
+Sema::LookupResult
+Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
+ bool RedeclarationOnly, bool AllowBuiltinCreation,
+ SourceLocation Loc) {
+ if (!Name) return LookupResult::CreateLookupResult(Context, 0);
+
+ if (!getLangOptions().CPlusPlus) {
+ // Unqualified name lookup in C/Objective-C is purely lexical, so
+ // search in the declarations attached to the name.
+ unsigned IDNS = 0;
+ switch (NameKind) {
+ case Sema::LookupOrdinaryName:
+ IDNS = Decl::IDNS_Ordinary;
+ break;
+
+ case Sema::LookupTagName:
+ IDNS = Decl::IDNS_Tag;
+ break;
+
+ case Sema::LookupMemberName:
+ IDNS = Decl::IDNS_Member;
+ break;
+
+ case Sema::LookupOperatorName:
+ case Sema::LookupNestedNameSpecifierName:
+ case Sema::LookupNamespaceName:
+ assert(false && "C does not perform these kinds of name lookup");
+ break;
+
+ case Sema::LookupRedeclarationWithLinkage:
+ // Find the nearest non-transparent declaration scope.
+ while (!(S->getFlags() & Scope::DeclScope) ||
+ (S->getEntity() &&
+ static_cast<DeclContext *>(S->getEntity())
+ ->isTransparentContext()))
+ S = S->getParent();
+ IDNS = Decl::IDNS_Ordinary;
+ break;
+
+ case Sema::LookupObjCProtocolName:
+ IDNS = Decl::IDNS_ObjCProtocol;
+ break;
+
+ case Sema::LookupObjCImplementationName:
+ IDNS = Decl::IDNS_ObjCImplementation;
+ break;
+
+ case Sema::LookupObjCCategoryImplName:
+ IDNS = Decl::IDNS_ObjCCategoryImpl;
+ break;
+ }
+
+ // Scan up the scope chain looking for a decl that matches this
+ // identifier that is in the appropriate namespace. This search
+ // should not take long, as shadowing of names is uncommon, and
+ // deep shadowing is extremely uncommon.
+ bool LeftStartingScope = false;
+
+ for (IdentifierResolver::iterator I = IdResolver.begin(Name),
+ IEnd = IdResolver.end();
+ I != IEnd; ++I)
+ if ((*I)->isInIdentifierNamespace(IDNS)) {
+ if (NameKind == LookupRedeclarationWithLinkage) {
+ // Determine whether this (or a previous) declaration is
+ // out-of-scope.
+ if (!LeftStartingScope && !S->isDeclScope(DeclPtrTy::make(*I)))
+ LeftStartingScope = true;
+
+ // If we found something outside of our starting scope that
+ // does not have linkage, skip it.
+ if (LeftStartingScope && !((*I)->hasLinkage()))
+ continue;
+ }
+
+ if ((*I)->getAttr<OverloadableAttr>()) {
+ // If this declaration has the "overloadable" attribute, we
+ // might have a set of overloaded functions.
+
+ // Figure out what scope the identifier is in.
+ while (!(S->getFlags() & Scope::DeclScope) ||
+ !S->isDeclScope(DeclPtrTy::make(*I)))
+ S = S->getParent();
+
+ // Find the last declaration in this scope (with the same
+ // name, naturally).
+ IdentifierResolver::iterator LastI = I;
+ for (++LastI; LastI != IEnd; ++LastI) {
+ if (!S->isDeclScope(DeclPtrTy::make(*LastI)))
+ break;
+ }
+
+ return LookupResult::CreateLookupResult(Context, I, LastI);
+ }
+
+ // We have a single lookup result.
+ return LookupResult::CreateLookupResult(Context, *I);
+ }
+ } else {
+ // Perform C++ unqualified name lookup.
+ std::pair<bool, LookupResult> MaybeResult =
+ CppLookupName(S, Name, NameKind, RedeclarationOnly);
+ if (MaybeResult.first)
+ return MaybeResult.second;
+ }
+
+ // If we didn't find a use of this identifier, and if the identifier
+ // corresponds to a compiler builtin, create the decl object for the builtin
+ // now, injecting it into translation unit scope, and return it.
+ if (NameKind == LookupOrdinaryName ||
+ NameKind == LookupRedeclarationWithLinkage) {
+ IdentifierInfo *II = Name.getAsIdentifierInfo();
+ if (II && AllowBuiltinCreation) {
+ // If this is a builtin on this (or all) targets, create the decl.
+ if (unsigned BuiltinID = II->getBuiltinID()) {
+ // In C++, we don't have any predefined library functions like
+ // 'malloc'. Instead, we'll just error.
+ if (getLangOptions().CPlusPlus &&
+ Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
+ return LookupResult::CreateLookupResult(Context, 0);
+
+ return LookupResult::CreateLookupResult(Context,
+ LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
+ S, RedeclarationOnly, Loc));
+ }
+ }
+ }
+ return LookupResult::CreateLookupResult(Context, 0);
+}
+
+/// @brief Perform qualified name lookup into a given context.
+///
+/// Qualified name lookup (C++ [basic.lookup.qual]) is used to find
+/// names when the context of those names is explicit specified, e.g.,
+/// "std::vector" or "x->member".
+///
+/// Different lookup criteria can find different names. For example, a
+/// particular scope can have both a struct and a function of the same
+/// name, and each can be found by certain lookup criteria. For more
+/// information about lookup criteria, see the documentation for the
+/// class LookupCriteria.
+///
+/// @param LookupCtx The context in which qualified name lookup will
+/// search. If the lookup criteria permits, name lookup may also search
+/// in the parent contexts or (for C++ classes) base classes.
+///
+/// @param Name The name of the entity that we are searching for.
+///
+/// @param Criteria The criteria that this routine will use to
+/// determine which names are visible and which names will be
+/// found. Note that name lookup will find a name that is visible by
+/// the given criteria, but the entity itself may not be semantically
+/// correct or even the kind of entity expected based on the
+/// lookup. For example, searching for a nested-name-specifier name
+/// might result in an EnumDecl, which is visible but is not permitted
+/// as a nested-name-specifier in C++03.
+///
+/// @returns The result of name lookup, which includes zero or more
+/// declarations and possibly additional information used to diagnose
+/// ambiguities.
+Sema::LookupResult
+Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
+ LookupNameKind NameKind, bool RedeclarationOnly) {
+ assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context");
+
+ if (!Name) return LookupResult::CreateLookupResult(Context, 0);
+
+ // If we're performing qualified name lookup (e.g., lookup into a
+ // struct), find fields as part of ordinary name lookup.
+ unsigned IDNS
+ = getIdentifierNamespacesFromLookupNameKind(NameKind,
+ getLangOptions().CPlusPlus);
+ if (NameKind == LookupOrdinaryName)
+ IDNS |= Decl::IDNS_Member;
+
+ // Perform qualified name lookup into the LookupCtx.
+ DeclContext::lookup_iterator I, E;
+ for (llvm::tie(I, E) = LookupCtx->lookup(Context, Name); I != E; ++I)
+ if (isAcceptableLookupResult(*I, NameKind, IDNS))
+ return LookupResult::CreateLookupResult(Context, I, E);
+
+ // If this isn't a C++ class or we aren't allowed to look into base
+ // classes, we're done.
+ if (RedeclarationOnly || !isa<CXXRecordDecl>(LookupCtx))
+ return LookupResult::CreateLookupResult(Context, 0);
+
+ // Perform lookup into our base classes.
+ BasePaths Paths;
+ Paths.setOrigin(Context.getTypeDeclType(cast<RecordDecl>(LookupCtx)));
+
+ // Look for this member in our base classes
+ if (!LookupInBases(cast<CXXRecordDecl>(LookupCtx),
+ MemberLookupCriteria(Name, NameKind, IDNS), Paths))
+ return LookupResult::CreateLookupResult(Context, 0);
+
+ // C++ [class.member.lookup]p2:
+ // [...] If the resulting set of declarations are not all from
+ // sub-objects of the same type, or the set has a nonstatic member
+ // and includes members from distinct sub-objects, there is an
+ // ambiguity and the program is ill-formed. Otherwise that set is
+ // the result of the lookup.
+ // FIXME: support using declarations!
+ QualType SubobjectType;
+ int SubobjectNumber = 0;
+ for (BasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end();
+ Path != PathEnd; ++Path) {
+ const BasePathElement &PathElement = Path->back();
+
+ // Determine whether we're looking at a distinct sub-object or not.
+ if (SubobjectType.isNull()) {
+ // This is the first subobject we've looked at. Record it's type.
+ SubobjectType = Context.getCanonicalType(PathElement.Base->getType());
+ SubobjectNumber = PathElement.SubobjectNumber;
+ } else if (SubobjectType
+ != Context.getCanonicalType(PathElement.Base->getType())) {
+ // We found members of the given name in two subobjects of
+ // different types. This lookup is ambiguous.
+ BasePaths *PathsOnHeap = new BasePaths;
+ PathsOnHeap->swap(Paths);
+ return LookupResult::CreateLookupResult(Context, PathsOnHeap, true);
+ } else if (SubobjectNumber != PathElement.SubobjectNumber) {
+ // We have a different subobject of the same type.
+
+ // C++ [class.member.lookup]p5:
+ // A static member, a nested type or an enumerator defined in
+ // a base class T can unambiguously be found even if an object
+ // has more than one base class subobject of type T.
+ Decl *FirstDecl = *Path->Decls.first;
+ if (isa<VarDecl>(FirstDecl) ||
+ isa<TypeDecl>(FirstDecl) ||
+ isa<EnumConstantDecl>(FirstDecl))
+ continue;
+
+ if (isa<CXXMethodDecl>(FirstDecl)) {
+ // Determine whether all of the methods are static.
+ bool AllMethodsAreStatic = true;
+ for (DeclContext::lookup_iterator Func = Path->Decls.first;
+ Func != Path->Decls.second; ++Func) {
+ if (!isa<CXXMethodDecl>(*Func)) {
+ assert(isa<TagDecl>(*Func) && "Non-function must be a tag decl");
+ break;
+ }
+
+ if (!cast<CXXMethodDecl>(*Func)->isStatic()) {
+ AllMethodsAreStatic = false;
+ break;
+ }
+ }
+
+ if (AllMethodsAreStatic)
+ continue;
+ }
+
+ // We have found a nonstatic member name in multiple, distinct
+ // subobjects. Name lookup is ambiguous.
+ BasePaths *PathsOnHeap = new BasePaths;
+ PathsOnHeap->swap(Paths);
+ return LookupResult::CreateLookupResult(Context, PathsOnHeap, false);
+ }
+ }
+
+ // Lookup in a base class succeeded; return these results.
+
+ // If we found a function declaration, return an overload set.
+ if (isa<FunctionDecl>(*Paths.front().Decls.first))
+ return LookupResult::CreateLookupResult(Context,
+ Paths.front().Decls.first, Paths.front().Decls.second);
+
+ // We found a non-function declaration; return a single declaration.
+ return LookupResult::CreateLookupResult(Context, *Paths.front().Decls.first);
+}
+
+/// @brief Performs name lookup for a name that was parsed in the
+/// source code, and may contain a C++ scope specifier.
+///
+/// This routine is a convenience routine meant to be called from
+/// contexts that receive a name and an optional C++ scope specifier
+/// (e.g., "N::M::x"). It will then perform either qualified or
+/// unqualified name lookup (with LookupQualifiedName or LookupName,
+/// respectively) on the given name and return those results.
+///
+/// @param S The scope from which unqualified name lookup will
+/// begin.
+///
+/// @param SS An optional C++ scope-specified, e.g., "::N::M".
+///
+/// @param Name The name of the entity that name lookup will
+/// search for.
+///
+/// @param Loc If provided, the source location where we're performing
+/// name lookup. At present, this is only used to produce diagnostics when
+/// C library functions (like "malloc") are implicitly declared.
+///
+/// @returns The result of qualified or unqualified name lookup.
+Sema::LookupResult
+Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS,
+ DeclarationName Name, LookupNameKind NameKind,
+ bool RedeclarationOnly, bool AllowBuiltinCreation,
+ SourceLocation Loc) {
+ if (SS && (SS->isSet() || SS->isInvalid())) {
+ // If the scope specifier is invalid, don't even look for
+ // anything.
+ if (SS->isInvalid())
+ return LookupResult::CreateLookupResult(Context, 0);
+
+ assert(!isUnknownSpecialization(*SS) && "Can't lookup dependent types");
+
+ if (isDependentScopeSpecifier(*SS)) {
+ // Determine whether we are looking into the current
+ // instantiation.
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
+ CXXRecordDecl *Current = getCurrentInstantiationOf(NNS);
+ assert(Current && "Bad dependent scope specifier");
+
+ // We nested name specifier refers to the current instantiation,
+ // so now we will look for a member of the current instantiation
+ // (C++0x [temp.dep.type]).
+ unsigned IDNS = getIdentifierNamespacesFromLookupNameKind(NameKind, true);
+ DeclContext::lookup_iterator I, E;
+ for (llvm::tie(I, E) = Current->lookup(Context, Name); I != E; ++I)
+ if (isAcceptableLookupResult(*I, NameKind, IDNS))
+ return LookupResult::CreateLookupResult(Context, I, E);
+ }
+
+ if (RequireCompleteDeclContext(*SS))
+ return LookupResult::CreateLookupResult(Context, 0);
+
+ return LookupQualifiedName(computeDeclContext(*SS),
+ Name, NameKind, RedeclarationOnly);
+ }
+
+ return LookupName(S, Name, NameKind, RedeclarationOnly,
+ AllowBuiltinCreation, Loc);
+}
+
+
+/// @brief Produce a diagnostic describing the ambiguity that resulted
+/// from name lookup.
+///
+/// @param Result The ambiguous name lookup result.
+///
+/// @param Name The name of the entity that name lookup was
+/// searching for.
+///
+/// @param NameLoc The location of the name within the source code.
+///
+/// @param LookupRange A source range that provides more
+/// source-location information concerning the lookup itself. For
+/// example, this range might highlight a nested-name-specifier that
+/// precedes the name.
+///
+/// @returns true
+bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
+ SourceLocation NameLoc,
+ SourceRange LookupRange) {
+ assert(Result.isAmbiguous() && "Lookup result must be ambiguous");
+
+ if (BasePaths *Paths = Result.getBasePaths()) {
+ if (Result.getKind() == LookupResult::AmbiguousBaseSubobjects) {
+ QualType SubobjectType = Paths->front().back().Base->getType();
+ Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects)
+ << Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths)
+ << LookupRange;
+
+ DeclContext::lookup_iterator Found = Paths->front().Decls.first;
+ while (isa<CXXMethodDecl>(*Found) &&
+ cast<CXXMethodDecl>(*Found)->isStatic())
+ ++Found;
+
+ Diag((*Found)->getLocation(), diag::note_ambiguous_member_found);
+
+ Result.Destroy();
+ return true;
+ }
+
+ assert(Result.getKind() == LookupResult::AmbiguousBaseSubobjectTypes &&
+ "Unhandled form of name lookup ambiguity");
+
+ Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types)
+ << Name << LookupRange;
+
+ std::set<Decl *> DeclsPrinted;
+ for (BasePaths::paths_iterator Path = Paths->begin(), PathEnd = Paths->end();
+ Path != PathEnd; ++Path) {
+ Decl *D = *Path->Decls.first;
+ if (DeclsPrinted.insert(D).second)
+ Diag(D->getLocation(), diag::note_ambiguous_member_found);
+ }
+
+ Result.Destroy();
+ return true;
+ } else if (Result.getKind() == LookupResult::AmbiguousReference) {
+ Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange;
+
+ NamedDecl **DI = reinterpret_cast<NamedDecl **>(Result.First),
+ **DEnd = reinterpret_cast<NamedDecl **>(Result.Last);
+
+ for (; DI != DEnd; ++DI)
+ Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI;
+
+ Result.Destroy();
+ return true;
+ }
+
+ assert(false && "Unhandled form of name lookup ambiguity");
+
+ // We can't reach here.
+ return true;
+}
+
+// \brief Add the associated classes and namespaces for
+// argument-dependent lookup with an argument of class type
+// (C++ [basic.lookup.koenig]p2).
+static void
+addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
+ ASTContext &Context,
+ Sema::AssociatedNamespaceSet &AssociatedNamespaces,
+ Sema::AssociatedClassSet &AssociatedClasses) {
+ // C++ [basic.lookup.koenig]p2:
+ // [...]
+ // -- If T is a class type (including unions), its associated
+ // classes are: the class itself; the class of which it is a
+ // member, if any; and its direct and indirect base
+ // classes. Its associated namespaces are the namespaces in
+ // which its associated classes are defined.
+
+ // Add the class of which it is a member, if any.
+ DeclContext *Ctx = Class->getDeclContext();
+ if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
+ AssociatedClasses.insert(EnclosingClass);
+
+ // Add the associated namespace for this class.
+ while (Ctx->isRecord())
+ Ctx = Ctx->getParent();
+ if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
+ AssociatedNamespaces.insert(EnclosingNamespace);
+
+ // Add the class itself. If we've already seen this class, we don't
+ // need to visit base classes.
+ if (!AssociatedClasses.insert(Class))
+ return;
+
+ // FIXME: Handle class template specializations
+
+ // Add direct and indirect base classes along with their associated
+ // namespaces.
+ llvm::SmallVector<CXXRecordDecl *, 32> Bases;
+ Bases.push_back(Class);
+ while (!Bases.empty()) {
+ // Pop this class off the stack.
+ Class = Bases.back();
+ Bases.pop_back();
+
+ // Visit the base classes.
+ for (CXXRecordDecl::base_class_iterator Base = Class->bases_begin(),
+ BaseEnd = Class->bases_end();
+ Base != BaseEnd; ++Base) {
+ const RecordType *BaseType = Base->getType()->getAsRecordType();
+ CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl());
+ if (AssociatedClasses.insert(BaseDecl)) {
+ // Find the associated namespace for this base class.
+ DeclContext *BaseCtx = BaseDecl->getDeclContext();
+ while (BaseCtx->isRecord())
+ BaseCtx = BaseCtx->getParent();
+ if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(BaseCtx))
+ AssociatedNamespaces.insert(EnclosingNamespace);
+
+ // Make sure we visit the bases of this base class.
+ if (BaseDecl->bases_begin() != BaseDecl->bases_end())
+ Bases.push_back(BaseDecl);
+ }
+ }
+ }
+}
+
+// \brief Add the associated classes and namespaces for
+// argument-dependent lookup with an argument of type T
+// (C++ [basic.lookup.koenig]p2).
+static void
+addAssociatedClassesAndNamespaces(QualType T,
+ ASTContext &Context,
+ Sema::AssociatedNamespaceSet &AssociatedNamespaces,
+ Sema::AssociatedClassSet &AssociatedClasses) {
+ // C++ [basic.lookup.koenig]p2:
+ //
+ // For each argument type T in the function call, there is a set
+ // of zero or more associated namespaces and a set of zero or more
+ // associated classes to be considered. The sets of namespaces and
+ // classes is determined entirely by the types of the function
+ // arguments (and the namespace of any template template
+ // argument). Typedef names and using-declarations used to specify
+ // the types do not contribute to this set. The sets of namespaces
+ // and classes are determined in the following way:
+ T = Context.getCanonicalType(T).getUnqualifiedType();
+
+ // -- If T is a pointer to U or an array of U, its associated
+ // namespaces and classes are those associated with U.
+ //
+ // We handle this by unwrapping pointer and array types immediately,
+ // to avoid unnecessary recursion.
+ while (true) {
+ if (const PointerType *Ptr = T->getAsPointerType())
+ T = Ptr->getPointeeType();
+ else if (const ArrayType *Ptr = Context.getAsArrayType(T))
+ T = Ptr->getElementType();
+ else
+ break;
+ }
+
+ // -- If T is a fundamental type, its associated sets of
+ // namespaces and classes are both empty.
+ if (T->getAsBuiltinType())
+ return;
+
+ // -- If T is a class type (including unions), its associated
+ // classes are: the class itself; the class of which it is a
+ // member, if any; and its direct and indirect base
+ // classes. Its associated namespaces are the namespaces in
+ // which its associated classes are defined.
+ if (const RecordType *ClassType = T->getAsRecordType())
+ if (CXXRecordDecl *ClassDecl
+ = dyn_cast<CXXRecordDecl>(ClassType->getDecl())) {
+ addAssociatedClassesAndNamespaces(ClassDecl, Context,
+ AssociatedNamespaces,
+ AssociatedClasses);
+ return;
+ }
+
+ // -- If T is an enumeration type, its associated namespace is
+ // the namespace in which it is defined. If it is class
+ // member, its associated class is the member’s class; else
+ // it has no associated class.
+ if (const EnumType *EnumT = T->getAsEnumType()) {
+ EnumDecl *Enum = EnumT->getDecl();
+
+ DeclContext *Ctx = Enum->getDeclContext();
+ if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
+ AssociatedClasses.insert(EnclosingClass);
+
+ // Add the associated namespace for this class.
+ while (Ctx->isRecord())
+ Ctx = Ctx->getParent();
+ if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
+ AssociatedNamespaces.insert(EnclosingNamespace);
+
+ return;
+ }
+
+ // -- If T is a function type, its associated namespaces and
+ // classes are those associated with the function parameter
+ // types and those associated with the return type.
+ if (const FunctionType *FunctionType = T->getAsFunctionType()) {
+ // Return type
+ addAssociatedClassesAndNamespaces(FunctionType->getResultType(),
+ Context,
+ AssociatedNamespaces, AssociatedClasses);
+
+ const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FunctionType);
+ if (!Proto)
+ return;
+
+ // Argument types
+ for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
+ ArgEnd = Proto->arg_type_end();
+ Arg != ArgEnd; ++Arg)
+ addAssociatedClassesAndNamespaces(*Arg, Context,
+ AssociatedNamespaces, AssociatedClasses);
+
+ return;
+ }
+
+ // -- If T is a pointer to a member function of a class X, its
+ // associated namespaces and classes are those associated
+ // with the function parameter types and return type,
+ // together with those associated with X.
+ //
+ // -- If T is a pointer to a data member of class X, its
+ // associated namespaces and classes are those associated
+ // with the member type together with those associated with
+ // X.
+ if (const MemberPointerType *MemberPtr = T->getAsMemberPointerType()) {
+ // Handle the type that the pointer to member points to.
+ addAssociatedClassesAndNamespaces(MemberPtr->getPointeeType(),
+ Context,
+ AssociatedNamespaces, AssociatedClasses);
+
+ // Handle the class type into which this points.
+ if (const RecordType *Class = MemberPtr->getClass()->getAsRecordType())
+ addAssociatedClassesAndNamespaces(cast<CXXRecordDecl>(Class->getDecl()),
+ Context,
+ AssociatedNamespaces, AssociatedClasses);
+
+ return;
+ }
+
+ // FIXME: What about block pointers?
+ // FIXME: What about Objective-C message sends?
+}
+
+/// \brief Find the associated classes and namespaces for
+/// argument-dependent lookup for a call with the given set of
+/// arguments.
+///
+/// This routine computes the sets of associated classes and associated
+/// namespaces searched by argument-dependent lookup
+/// (C++ [basic.lookup.argdep]) for a given set of arguments.
+void
+Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
+ AssociatedNamespaceSet &AssociatedNamespaces,
+ AssociatedClassSet &AssociatedClasses) {
+ AssociatedNamespaces.clear();
+ AssociatedClasses.clear();
+
+ // C++ [basic.lookup.koenig]p2:
+ // For each argument type T in the function call, there is a set
+ // of zero or more associated namespaces and a set of zero or more
+ // associated classes to be considered. The sets of namespaces and
+ // classes is determined entirely by the types of the function
+ // arguments (and the namespace of any template template
+ // argument).
+ for (unsigned ArgIdx = 0; ArgIdx != NumArgs; ++ArgIdx) {
+ Expr *Arg = Args[ArgIdx];
+
+ if (Arg->getType() != Context.OverloadTy) {
+ addAssociatedClassesAndNamespaces(Arg->getType(), Context,
+ AssociatedNamespaces, AssociatedClasses);
+ continue;
+ }
+
+ // [...] In addition, if the argument is the name or address of a
+ // set of overloaded functions and/or function templates, its
+ // associated classes and namespaces are the union of those
+ // associated with each of the members of the set: the namespace
+ // in which the function or function template is defined and the
+ // classes and namespaces associated with its (non-dependent)
+ // parameter types and return type.
+ DeclRefExpr *DRE = 0;
+ if (UnaryOperator *unaryOp = dyn_cast<UnaryOperator>(Arg)) {
+ if (unaryOp->getOpcode() == UnaryOperator::AddrOf)
+ DRE = dyn_cast<DeclRefExpr>(unaryOp->getSubExpr());
+ } else
+ DRE = dyn_cast<DeclRefExpr>(Arg);
+ if (!DRE)
+ continue;
+
+ OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(DRE->getDecl());
+ if (!Ovl)
+ continue;
+
+ for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
+ FuncEnd = Ovl->function_end();
+ Func != FuncEnd; ++Func) {
+ FunctionDecl *FDecl = cast<FunctionDecl>(*Func);
+
+ // Add the namespace in which this function was defined. Note
+ // that, if this is a member function, we do *not* consider the
+ // enclosing namespace of its class.
+ DeclContext *Ctx = FDecl->getDeclContext();
+ if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
+ AssociatedNamespaces.insert(EnclosingNamespace);
+
+ // Add the classes and namespaces associated with the parameter
+ // types and return type of this function.
+ addAssociatedClassesAndNamespaces(FDecl->getType(), Context,
+ AssociatedNamespaces, AssociatedClasses);
+ }
+ }
+}
+
+/// IsAcceptableNonMemberOperatorCandidate - Determine whether Fn is
+/// an acceptable non-member overloaded operator for a call whose
+/// arguments have types T1 (and, if non-empty, T2). This routine
+/// implements the check in C++ [over.match.oper]p3b2 concerning
+/// enumeration types.
+static bool
+IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
+ QualType T1, QualType T2,
+ ASTContext &Context) {
+ if (T1->isDependentType() || (!T2.isNull() && T2->isDependentType()))
+ return true;
+
+ if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
+ return true;
+
+ const FunctionProtoType *Proto = Fn->getType()->getAsFunctionProtoType();
+ if (Proto->getNumArgs() < 1)
+ return false;
+
+ if (T1->isEnumeralType()) {
+ QualType ArgType = Proto->getArgType(0).getNonReferenceType();
+ if (Context.getCanonicalType(T1).getUnqualifiedType()
+ == Context.getCanonicalType(ArgType).getUnqualifiedType())
+ return true;
+ }
+
+ if (Proto->getNumArgs() < 2)
+ return false;
+
+ if (!T2.isNull() && T2->isEnumeralType()) {
+ QualType ArgType = Proto->getArgType(1).getNonReferenceType();
+ if (Context.getCanonicalType(T2).getUnqualifiedType()
+ == Context.getCanonicalType(ArgType).getUnqualifiedType())
+ return true;
+ }
+
+ return false;
+}
+
+/// \brief Find the protocol with the given name, if any.
+ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) {
+ Decl *D = LookupName(TUScope, II, LookupObjCProtocolName).getAsDecl();
+ return cast_or_null<ObjCProtocolDecl>(D);
+}
+
+/// \brief Find the Objective-C implementation with the given name, if
+/// any.
+ObjCImplementationDecl *Sema::LookupObjCImplementation(IdentifierInfo *II) {
+ Decl *D = LookupName(TUScope, II, LookupObjCImplementationName).getAsDecl();
+ return cast_or_null<ObjCImplementationDecl>(D);
+}
+
+/// \brief Find the Objective-C category implementation with the given
+/// name, if any.
+ObjCCategoryImplDecl *Sema::LookupObjCCategoryImpl(IdentifierInfo *II) {
+ Decl *D = LookupName(TUScope, II, LookupObjCCategoryImplName).getAsDecl();
+ return cast_or_null<ObjCCategoryImplDecl>(D);
+}
+
+void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
+ QualType T1, QualType T2,
+ FunctionSet &Functions) {
+ // C++ [over.match.oper]p3:
+ // -- The set of non-member candidates is the result of the
+ // unqualified lookup of operator@ in the context of the
+ // expression according to the usual rules for name lookup in
+ // unqualified function calls (3.4.2) except that all member
+ // functions are ignored. However, if no operand has a class
+ // type, only those non-member functions in the lookup set
+ // that have a first parameter of type T1 or “reference to
+ // (possibly cv-qualified) T1â€, when T1 is an enumeration
+ // type, or (if there is a right operand) a second parameter
+ // of type T2 or “reference to (possibly cv-qualified) T2â€,
+ // when T2 is an enumeration type, are candidate functions.
+ DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
+ LookupResult Operators = LookupName(S, OpName, LookupOperatorName);
+
+ assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous");
+
+ if (!Operators)
+ return;
+
+ for (LookupResult::iterator Op = Operators.begin(), OpEnd = Operators.end();
+ Op != OpEnd; ++Op) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Op))
+ if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
+ Functions.insert(FD); // FIXME: canonical FD
+ }
+}
+
+void Sema::ArgumentDependentLookup(DeclarationName Name,
+ Expr **Args, unsigned NumArgs,
+ FunctionSet &Functions) {
+ // Find all of the associated namespaces and classes based on the
+ // arguments we have.
+ AssociatedNamespaceSet AssociatedNamespaces;
+ AssociatedClassSet AssociatedClasses;
+ FindAssociatedClassesAndNamespaces(Args, NumArgs,
+ AssociatedNamespaces, AssociatedClasses);
+
+ // C++ [basic.lookup.argdep]p3:
+ // Let X be the lookup set produced by unqualified lookup (3.4.1)
+ // and let Y be the lookup set produced by argument dependent
+ // lookup (defined as follows). If X contains [...] then Y is
+ // empty. Otherwise Y is the set of declarations found in the
+ // namespaces associated with the argument types as described
+ // below. The set of declarations found by the lookup of the name
+ // is the union of X and Y.
+ //
+ // Here, we compute Y and add its members to the overloaded
+ // candidate set.
+ for (AssociatedNamespaceSet::iterator NS = AssociatedNamespaces.begin(),
+ NSEnd = AssociatedNamespaces.end();
+ NS != NSEnd; ++NS) {
+ // When considering an associated namespace, the lookup is the
+ // same as the lookup performed when the associated namespace is
+ // used as a qualifier (3.4.3.2) except that:
+ //
+ // -- Any using-directives in the associated namespace are
+ // ignored.
+ //
+ // -- FIXME: Any namespace-scope friend functions declared in
+ // associated classes are visible within their respective
+ // namespaces even if they are not visible during an ordinary
+ // lookup (11.4).
+ DeclContext::lookup_iterator I, E;
+ for (llvm::tie(I, E) = (*NS)->lookup(Context, Name); I != E; ++I) {
+ FunctionDecl *Func = dyn_cast<FunctionDecl>(*I);
+ if (!Func)
+ break;
+
+ Functions.insert(Func);
+ }
+ }
+}
diff --git a/lib/Sema/SemaNamedCast.cpp b/lib/Sema/SemaNamedCast.cpp
new file mode 100644
index 000000000000..daf6800ea0c0
--- /dev/null
+++ b/lib/Sema/SemaNamedCast.cpp
@@ -0,0 +1,932 @@
+//===--- SemaNamedCast.cpp - Semantic Analysis for Named Casts ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for C++ named casts.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "SemaInherit.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/ADT/SmallVector.h"
+#include <set>
+using namespace clang;
+
+enum TryStaticCastResult {
+ TSC_NotApplicable, ///< The cast method is not applicable.
+ TSC_Success, ///< The cast method is appropriate and successful.
+ TSC_Failed ///< The cast method is appropriate, but failed. A
+ ///< diagnostic has been emitted.
+};
+
+static void CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange,
+ const SourceRange &DestRange);
+static void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange,
+ const SourceRange &DestRange);
+static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange);
+static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange,
+ const SourceRange &DestRange);
+
+static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType);
+static TryStaticCastResult TryLValueToRValueCast(
+ Sema &Self, Expr *SrcExpr, QualType DestType, const SourceRange &OpRange);
+static TryStaticCastResult TryStaticReferenceDowncast(
+ Sema &Self, Expr *SrcExpr, QualType DestType, const SourceRange &OpRange);
+static TryStaticCastResult TryStaticPointerDowncast(
+ Sema &Self, QualType SrcType, QualType DestType, const SourceRange &OpRange);
+static TryStaticCastResult TryStaticMemberPointerUpcast(
+ Sema &Self, QualType SrcType, QualType DestType, const SourceRange &OpRange);
+static TryStaticCastResult TryStaticDowncast(Sema &Self, QualType SrcType,
+ QualType DestType,
+ const SourceRange &OpRange,
+ QualType OrigSrcType,
+ QualType OrigDestType);
+static TryStaticCastResult TryStaticImplicitCast(Sema &Self, Expr *SrcExpr,
+ QualType DestType,
+ const SourceRange &OpRange);
+
+/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
+Action::OwningExprResult
+Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
+ SourceLocation LAngleBracketLoc, TypeTy *Ty,
+ SourceLocation RAngleBracketLoc,
+ SourceLocation LParenLoc, ExprArg E,
+ SourceLocation RParenLoc) {
+ Expr *Ex = E.takeAs<Expr>();
+ QualType DestType = QualType::getFromOpaquePtr(Ty);
+ SourceRange OpRange(OpLoc, RParenLoc);
+ SourceRange DestRange(LAngleBracketLoc, RAngleBracketLoc);
+
+ // 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->isTypeDependent();
+
+ switch (Kind) {
+ default: assert(0 && "Unknown C++ cast!");
+
+ case tok::kw_const_cast:
+ if (!TypeDependent)
+ CheckConstCast(*this, Ex, DestType, OpRange, DestRange);
+ return Owned(new (Context) CXXConstCastExpr(DestType.getNonReferenceType(),
+ Ex, DestType, OpLoc));
+
+ case tok::kw_dynamic_cast:
+ if (!TypeDependent)
+ CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange);
+ return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(),
+ Ex, DestType, OpLoc));
+
+ case tok::kw_reinterpret_cast:
+ if (!TypeDependent)
+ CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange);
+ return Owned(new (Context) CXXReinterpretCastExpr(
+ DestType.getNonReferenceType(),
+ Ex, DestType, OpLoc));
+
+ case tok::kw_static_cast:
+ if (!TypeDependent)
+ CheckStaticCast(*this, Ex, DestType, OpRange);
+ return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(),
+ Ex, DestType, OpLoc));
+ }
+
+ return ExprError();
+}
+
+/// CheckConstCast - Check that a const_cast\<DestType\>(SrcExpr) is valid.
+/// Refer to C++ 5.2.11 for details. const_cast is typically used in code
+/// like this:
+/// const char *str = "literal";
+/// legacy_function(const_cast\<char*\>(str));
+void
+CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange, const SourceRange &DestRange)
+{
+ QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType();
+
+ DestType = Self.Context.getCanonicalType(DestType);
+ QualType SrcType = SrcExpr->getType();
+ if (const LValueReferenceType *DestTypeTmp =
+ DestType->getAsLValueReferenceType()) {
+ if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
+ // Cannot cast non-lvalue to lvalue reference type.
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue)
+ << "const_cast" << OrigDestType << SrcExpr->getSourceRange();
+ return;
+ }
+
+ // C++ 5.2.11p4: An lvalue of type T1 can be [cast] to an lvalue of type T2
+ // [...] if a pointer to T1 can be [cast] to the type pointer to T2.
+ DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
+ SrcType = Self.Context.getPointerType(SrcType);
+ } else {
+ // C++ 5.2.11p1: Otherwise, the result is an rvalue and the
+ // lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard
+ // conversions are performed on the expression.
+ Self.DefaultFunctionArrayConversion(SrcExpr);
+ SrcType = SrcExpr->getType();
+ }
+
+ // C++ 5.2.11p5: For a const_cast involving pointers to data members [...]
+ // the rules for const_cast are the same as those used for pointers.
+
+ if (!DestType->isPointerType() && !DestType->isMemberPointerType()) {
+ // Cannot cast to non-pointer, non-reference type. Note that, if DestType
+ // was a reference type, we converted it to a pointer above.
+ // The status of rvalue references isn't entirely clear, but it looks like
+ // conversion to them is simply invalid.
+ // C++ 5.2.11p3: For two pointer types [...]
+ Self.Diag(OpRange.getBegin(), diag::err_bad_const_cast_dest)
+ << OrigDestType << DestRange;
+ return;
+ }
+ if (DestType->isFunctionPointerType() ||
+ DestType->isMemberFunctionPointerType()) {
+ // Cannot cast direct function pointers.
+ // C++ 5.2.11p2: [...] where T is any object type or the void type [...]
+ // T is the ultimate pointee of source and target type.
+ Self.Diag(OpRange.getBegin(), diag::err_bad_const_cast_dest)
+ << OrigDestType << DestRange;
+ return;
+ }
+ SrcType = Self.Context.getCanonicalType(SrcType);
+
+ // Unwrap the pointers. Ignore qualifiers. Terminate early if the types are
+ // completely equal.
+ // FIXME: const_cast should probably not be able to convert between pointers
+ // to different address spaces.
+ // C++ 5.2.11p3 describes the core semantics of const_cast. All cv specifiers
+ // in multi-level pointers may change, but the level count must be the same,
+ // as must be the final pointee type.
+ while (SrcType != DestType &&
+ Self.UnwrapSimilarPointerTypes(SrcType, DestType)) {
+ SrcType = SrcType.getUnqualifiedType();
+ DestType = DestType.getUnqualifiedType();
+ }
+
+ // Doug Gregor said to disallow this until users complain.
+#if 0
+ // If we end up with constant arrays of equal size, unwrap those too. A cast
+ // from const int [N] to int (&)[N] is invalid by my reading of the
+ // standard, but g++ accepts it even with -ansi -pedantic.
+ // No more than one level, though, so don't embed this in the unwrap loop
+ // above.
+ const ConstantArrayType *SrcTypeArr, *DestTypeArr;
+ if ((SrcTypeArr = Self.Context.getAsConstantArrayType(SrcType)) &&
+ (DestTypeArr = Self.Context.getAsConstantArrayType(DestType)))
+ {
+ if (SrcTypeArr->getSize() != DestTypeArr->getSize()) {
+ // Different array sizes.
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
+ << "const_cast" << OrigDestType << OrigSrcType << OpRange;
+ return;
+ }
+ SrcType = SrcTypeArr->getElementType().getUnqualifiedType();
+ DestType = DestTypeArr->getElementType().getUnqualifiedType();
+ }
+#endif
+
+ // Since we're dealing in canonical types, the remainder must be the same.
+ if (SrcType != DestType) {
+ // Cast between unrelated types.
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
+ << "const_cast" << OrigDestType << OrigSrcType << OpRange;
+ return;
+ }
+}
+
+/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is
+/// valid.
+/// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code
+/// like this:
+/// char *bytes = reinterpret_cast\<char*\>(int_ptr);
+void
+CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange, const SourceRange &DestRange)
+{
+ QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType();
+
+ DestType = Self.Context.getCanonicalType(DestType);
+ QualType SrcType = SrcExpr->getType();
+ if (const LValueReferenceType *DestTypeTmp =
+ DestType->getAsLValueReferenceType()) {
+ if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
+ // Cannot cast non-lvalue to reference type.
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue)
+ << "reinterpret_cast" << OrigDestType << SrcExpr->getSourceRange();
+ return;
+ }
+
+ // C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the
+ // same effect as the conversion *reinterpret_cast<T*>(&x) with the
+ // built-in & and * operators.
+ // This code does this transformation for the checked types.
+ DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
+ SrcType = Self.Context.getPointerType(SrcType);
+ } else if (const RValueReferenceType *DestTypeTmp =
+ DestType->getAsRValueReferenceType()) {
+ // Both the reference conversion and the rvalue rules apply.
+ Self.DefaultFunctionArrayConversion(SrcExpr);
+ SrcType = SrcExpr->getType();
+
+ DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
+ SrcType = Self.Context.getPointerType(SrcType);
+ } else {
+ // C++ 5.2.10p1: [...] the lvalue-to-rvalue, array-to-pointer, and
+ // function-to-pointer standard conversions are performed on the
+ // expression v.
+ Self.DefaultFunctionArrayConversion(SrcExpr);
+ SrcType = SrcExpr->getType();
+ }
+
+ // Canonicalize source for comparison.
+ SrcType = Self.Context.getCanonicalType(SrcType);
+
+ const MemberPointerType *DestMemPtr = DestType->getAsMemberPointerType(),
+ *SrcMemPtr = SrcType->getAsMemberPointerType();
+ if (DestMemPtr && SrcMemPtr) {
+ // C++ 5.2.10p9: An rvalue of type "pointer to member of X of type T1"
+ // can be explicitly converted to an rvalue of type "pointer to member
+ // of Y of type T2" if T1 and T2 are both function types or both object
+ // types.
+ if (DestMemPtr->getPointeeType()->isFunctionType() !=
+ SrcMemPtr->getPointeeType()->isFunctionType()) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
+ << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
+ return;
+ }
+
+ // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away
+ // constness.
+ if (CastsAwayConstness(Self, SrcType, DestType)) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away)
+ << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
+ return;
+ }
+
+ // A valid member pointer cast.
+ return;
+ }
+
+ // See below for the enumeral issue.
+ if (SrcType->isNullPtrType() && DestType->isIntegralType() &&
+ !DestType->isEnumeralType()) {
+ // C++0x 5.2.10p4: A pointer can be explicitly converted to any integral
+ // type large enough to hold it. A value of std::nullptr_t can be
+ // converted to an integral type; the conversion has the same meaning
+ // and validity as a conversion of (void*)0 to the integral type.
+ if (Self.Context.getTypeSize(SrcType) >
+ Self.Context.getTypeSize(DestType)) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_small_int)
+ << OrigDestType << DestRange;
+ }
+ return;
+ }
+
+ bool destIsPtr = DestType->isPointerType();
+ bool srcIsPtr = SrcType->isPointerType();
+ if (!destIsPtr && !srcIsPtr) {
+ // Except for std::nullptr_t->integer and lvalue->reference, which are
+ // handled above, at least one of the two arguments must be a pointer.
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
+ << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
+ return;
+ }
+
+ if (SrcType == DestType) {
+ // C++ 5.2.10p2 has a note that mentions that, subject to all other
+ // restrictions, a cast to the same type is allowed. The intent is not
+ // entirely clear here, since all other paragraphs explicitly forbid casts
+ // to the same type. However, the behavior of compilers is pretty consistent
+ // on this point: allow same-type conversion if the involved types are
+ // pointers, disallow otherwise.
+ return;
+ }
+
+ // Note: Clang treats enumeration types as integral types. If this is ever
+ // changed for C++, the additional check here will be redundant.
+ if (DestType->isIntegralType() && !DestType->isEnumeralType()) {
+ assert(srcIsPtr && "One type must be a pointer");
+ // C++ 5.2.10p4: A pointer can be explicitly converted to any integral
+ // type large enough to hold it.
+ if (Self.Context.getTypeSize(SrcType) >
+ Self.Context.getTypeSize(DestType)) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_small_int)
+ << OrigDestType << DestRange;
+ }
+ return;
+ }
+
+ if (SrcType->isIntegralType() || SrcType->isEnumeralType()) {
+ assert(destIsPtr && "One type must be a pointer");
+ // C++ 5.2.10p5: A value of integral or enumeration type can be explicitly
+ // converted to a pointer.
+ return;
+ }
+
+ if (!destIsPtr || !srcIsPtr) {
+ // With the valid non-pointer conversions out of the way, we can be even
+ // more stringent.
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
+ << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
+ return;
+ }
+
+ // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness.
+ if (CastsAwayConstness(Self, SrcType, DestType)) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away)
+ << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
+ return;
+ }
+
+ // Not casting away constness, so the only remaining check is for compatible
+ // pointer categories.
+
+ if (SrcType->isFunctionPointerType()) {
+ if (DestType->isFunctionPointerType()) {
+ // C++ 5.2.10p6: A pointer to a function can be explicitly converted to
+ // a pointer to a function of a different type.
+ return;
+ }
+
+ // C++0x 5.2.10p8: Converting a pointer to a function into a pointer to
+ // an object type or vice versa is conditionally-supported.
+ // Compilers support it in C++03 too, though, because it's necessary for
+ // casting the return value of dlsym() and GetProcAddress().
+ // FIXME: Conditionally-supported behavior should be configurable in the
+ // TargetInfo or similar.
+ if (!Self.getLangOptions().CPlusPlus0x) {
+ Self.Diag(OpRange.getBegin(), diag::ext_reinterpret_cast_fn_obj)
+ << OpRange;
+ }
+ return;
+ }
+
+ if (DestType->isFunctionPointerType()) {
+ // See above.
+ if (!Self.getLangOptions().CPlusPlus0x) {
+ Self.Diag(OpRange.getBegin(), diag::ext_reinterpret_cast_fn_obj)
+ << OpRange;
+ }
+ return;
+ }
+
+ // C++ 5.2.10p7: A pointer to an object can be explicitly converted to
+ // a pointer to an object of different type.
+ // Void pointers are not specified, but supported by every compiler out there.
+ // So we finish by allowing everything that remains - it's got to be two
+ // object pointers.
+}
+
+/// CastsAwayConstness - Check if the pointer conversion from SrcType to
+/// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by
+/// the cast checkers. Both arguments must denote pointer (possibly to member)
+/// types.
+bool
+CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType)
+{
+ // Casting away constness is defined in C++ 5.2.11p8 with reference to
+ // C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since
+ // the rules are non-trivial. So first we construct Tcv *...cv* as described
+ // in C++ 5.2.11p8.
+ assert((SrcType->isPointerType() || SrcType->isMemberPointerType()) &&
+ "Source type is not pointer or pointer to member.");
+ assert((DestType->isPointerType() || DestType->isMemberPointerType()) &&
+ "Destination type is not pointer or pointer to member.");
+
+ QualType UnwrappedSrcType = SrcType, UnwrappedDestType = DestType;
+ llvm::SmallVector<unsigned, 8> cv1, cv2;
+
+ // Find the qualifications.
+ while (Self.UnwrapSimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) {
+ cv1.push_back(UnwrappedSrcType.getCVRQualifiers());
+ cv2.push_back(UnwrappedDestType.getCVRQualifiers());
+ }
+ assert(cv1.size() > 0 && "Must have at least one pointer level.");
+
+ // Construct void pointers with those qualifiers (in reverse order of
+ // unwrapping, of course).
+ QualType SrcConstruct = Self.Context.VoidTy;
+ QualType DestConstruct = Self.Context.VoidTy;
+ for (llvm::SmallVector<unsigned, 8>::reverse_iterator i1 = cv1.rbegin(),
+ i2 = cv2.rbegin();
+ i1 != cv1.rend(); ++i1, ++i2)
+ {
+ SrcConstruct = Self.Context.getPointerType(
+ SrcConstruct.getQualifiedType(*i1));
+ DestConstruct = Self.Context.getPointerType(
+ DestConstruct.getQualifiedType(*i2));
+ }
+
+ // Test if they're compatible.
+ return SrcConstruct != DestConstruct &&
+ !Self.IsQualificationConversion(SrcConstruct, DestConstruct);
+}
+
+/// 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, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange)
+{
+ // The order the tests is not entirely arbitrary. There is one conversion
+ // that can be handled in two different ways. Given:
+ // struct A {};
+ // struct B : public A {
+ // B(); B(const A&);
+ // };
+ // const A &a = B();
+ // the cast static_cast<const B&>(a) could be seen as either a static
+ // reference downcast, or an explicit invocation of the user-defined
+ // conversion using B's conversion constructor.
+ // DR 427 specifies that the downcast is to be applied here.
+
+ // FIXME: With N2812, casts to rvalue refs will change.
+
+ // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
+ if (DestType->isVoidType()) {
+ return;
+ }
+
+ // C++ 5.2.9p5, reference downcast.
+ // See the function for details.
+ // DR 427 specifies that this is to be applied before paragraph 2.
+ if (TryStaticReferenceDowncast(Self, SrcExpr, DestType, OpRange)
+ > TSC_NotApplicable) {
+ return;
+ }
+
+ // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue
+ // reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1".
+ if (TryLValueToRValueCast(Self, SrcExpr, DestType, OpRange) >
+ TSC_NotApplicable) {
+ return;
+ }
+
+ // C++ 5.2.9p2: An expression e can be explicitly converted to a type T
+ // [...] if the declaration "T t(e);" is well-formed, [...].
+ if (TryStaticImplicitCast(Self, SrcExpr, DestType, OpRange) >
+ TSC_NotApplicable) {
+ return;
+ }
+
+ // C++ 5.2.9p6: May apply the reverse of any standard conversion, except
+ // lvalue-to-rvalue, array-to-pointer, function-to-pointer, and boolean
+ // conversions, subject to further restrictions.
+ // Also, C++ 5.2.9p1 forbids casting away constness, which makes reversal
+ // of qualification conversions impossible.
+
+ // The lvalue-to-rvalue, array-to-pointer and function-to-pointer conversions
+ // are applied to the expression.
+ QualType OrigSrcType = SrcExpr->getType();
+ Self.DefaultFunctionArrayConversion(SrcExpr);
+
+ QualType SrcType = Self.Context.getCanonicalType(SrcExpr->getType());
+
+ // Reverse integral promotion/conversion. All such conversions are themselves
+ // again integral promotions or conversions and are thus already handled by
+ // p2 (TryDirectInitialization above).
+ // (Note: any data loss warnings should be suppressed.)
+ // The exception is the reverse of enum->integer, i.e. integer->enum (and
+ // enum->enum). See also C++ 5.2.9p7.
+ // 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()) {
+ return;
+ }
+ }
+
+ // Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast.
+ // C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance.
+ if (TryStaticPointerDowncast(Self, SrcType, DestType, OpRange)
+ > TSC_NotApplicable) {
+ return;
+ }
+
+ // Reverse member pointer conversion. C++ 4.11 specifies member pointer
+ // conversion. C++ 5.2.9p9 has additional information.
+ // DR54's access restrictions apply here also.
+ if (TryStaticMemberPointerUpcast(Self, SrcType, DestType, OpRange)
+ > TSC_NotApplicable) {
+ return;
+ }
+
+ // Reverse pointer conversion to void*. C++ 4.10.p2 specifies conversion to
+ // void*. C++ 5.2.9p10 specifies additional restrictions, which really is
+ // just the usual constness stuff.
+ if (const PointerType *SrcPointer = SrcType->getAsPointerType()) {
+ QualType SrcPointee = SrcPointer->getPointeeType();
+ if (SrcPointee->isVoidType()) {
+ if (const PointerType *DestPointer = DestType->getAsPointerType()) {
+ QualType DestPointee = DestPointer->getPointeeType();
+ if (DestPointee->isIncompleteOrObjectType()) {
+ // This is definitely the intended conversion, but it might fail due
+ // to a const violation.
+ if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away)
+ << "static_cast" << DestType << OrigSrcType << OpRange;
+ }
+ return;
+ }
+ }
+ }
+ }
+
+ // We tried everything. Everything! Nothing works! :-(
+ // FIXME: Error reporting could be a lot better. Should store the reason why
+ // every substep failed and, at the end, select the most specific and report
+ // that.
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
+ << "static_cast" << DestType << OrigSrcType
+ << OpRange;
+}
+
+/// Tests whether a conversion according to N2844 is valid.
+TryStaticCastResult
+TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
+ const SourceRange &OpRange)
+{
+ // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue
+ // reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1".
+ const RValueReferenceType *R = DestType->getAsRValueReferenceType();
+ if (!R)
+ return TSC_NotApplicable;
+
+ if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid)
+ return TSC_NotApplicable;
+
+ // Because we try the reference downcast before this function, from now on
+ // this is the only cast possibility, so we issue an error if we fail now.
+ bool DerivedToBase;
+ if (Self.CompareReferenceRelationship(SrcExpr->getType(), R->getPointeeType(),
+ DerivedToBase) <
+ Sema::Ref_Compatible_With_Added_Qualification) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_lvalue_to_rvalue_cast)
+ << SrcExpr->getType() << R->getPointeeType() << OpRange;
+ return TSC_Failed;
+ }
+
+ // FIXME: Similar to CheckReferenceInit, we actually need more AST annotation
+ // than nothing.
+ return TSC_Success;
+}
+
+/// Tests whether a conversion according to C++ 5.2.9p5 is valid.
+TryStaticCastResult
+TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
+ const SourceRange &OpRange)
+{
+ // C++ 5.2.9p5: An lvalue of type "cv1 B", where B is a class type, can be
+ // cast to type "reference to cv2 D", where D is a class derived from B,
+ // if a valid standard conversion from "pointer to D" to "pointer to B"
+ // exists, cv2 >= cv1, and B is not a virtual base class of D.
+ // In addition, DR54 clarifies that the base must be accessible in the
+ // current context. Although the wording of DR54 only applies to the pointer
+ // variant of this rule, the intent is clearly for it to apply to the this
+ // conversion as well.
+
+ if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
+ return TSC_NotApplicable;
+ }
+
+ const ReferenceType *DestReference = DestType->getAsReferenceType();
+ if (!DestReference) {
+ return TSC_NotApplicable;
+ }
+ QualType DestPointee = DestReference->getPointeeType();
+
+ return TryStaticDowncast(Self, SrcExpr->getType(), DestPointee, OpRange,
+ SrcExpr->getType(), DestType);
+}
+
+/// Tests whether a conversion according to C++ 5.2.9p8 is valid.
+TryStaticCastResult
+TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType,
+ const SourceRange &OpRange)
+{
+ // C++ 5.2.9p8: An rvalue of type "pointer to cv1 B", where B is a class
+ // type, can be converted to an rvalue of type "pointer to cv2 D", where D
+ // is a class derived from B, if a valid standard conversion from "pointer
+ // to D" to "pointer to B" exists, cv2 >= cv1, and B is not a virtual base
+ // class of D.
+ // In addition, DR54 clarifies that the base must be accessible in the
+ // current context.
+
+ const PointerType *SrcPointer = SrcType->getAsPointerType();
+ if (!SrcPointer) {
+ return TSC_NotApplicable;
+ }
+
+ const PointerType *DestPointer = DestType->getAsPointerType();
+ if (!DestPointer) {
+ return TSC_NotApplicable;
+ }
+
+ return TryStaticDowncast(Self, SrcPointer->getPointeeType(),
+ DestPointer->getPointeeType(),
+ OpRange, SrcType, DestType);
+}
+
+/// TryStaticDowncast - Common functionality of TryStaticReferenceDowncast and
+/// TryStaticPointerDowncast. Tests whether a static downcast from SrcType to
+/// DestType, both of which must be canonical, is possible and allowed.
+TryStaticCastResult
+TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType,
+ const SourceRange &OpRange, QualType OrigSrcType,
+ QualType OrigDestType)
+{
+ // Downcast can only happen in class hierarchies, so we need classes.
+ if (!DestType->isRecordType() || !SrcType->isRecordType()) {
+ return TSC_NotApplicable;
+ }
+
+ BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+ /*DetectVirtual=*/true);
+ if (!Self.IsDerivedFrom(DestType, SrcType, Paths)) {
+ return TSC_NotApplicable;
+ }
+
+ // Target type does derive from source type. Now we're serious. If an error
+ // appears now, it's not ignored.
+ // This may not be entirely in line with the standard. Take for example:
+ // struct A {};
+ // struct B : virtual A {
+ // B(A&);
+ // };
+ //
+ // void f()
+ // {
+ // (void)static_cast<const B&>(*((A*)0));
+ // }
+ // As far as the standard is concerned, p5 does not apply (A is virtual), so
+ // p2 should be used instead - "const B& t(*((A*)0));" is perfectly valid.
+ // However, both GCC and Comeau reject this example, and accepting it would
+ // mean more complex code if we're to preserve the nice error message.
+ // FIXME: Being 100% compliant here would be nice to have.
+
+ // Must preserve cv, as always.
+ if (!DestType.isAtLeastAsQualifiedAs(SrcType)) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away)
+ << "static_cast" << OrigDestType << OrigSrcType << OpRange;
+ return TSC_Failed;
+ }
+
+ if (Paths.isAmbiguous(SrcType.getUnqualifiedType())) {
+ // This code is analoguous to that in CheckDerivedToBaseConversion, except
+ // that it builds the paths in reverse order.
+ // To sum up: record all paths to the base and build a nice string from
+ // them. Use it to spice up the error message.
+ Paths.clear();
+ Paths.setRecordingPaths(true);
+ Self.IsDerivedFrom(DestType, SrcType, Paths);
+ std::string PathDisplayStr;
+ std::set<unsigned> DisplayedPaths;
+ for (BasePaths::paths_iterator Path = Paths.begin();
+ Path != Paths.end(); ++Path) {
+ if (DisplayedPaths.insert(Path->back().SubobjectNumber).second) {
+ // We haven't displayed a path to this particular base
+ // class subobject yet.
+ PathDisplayStr += "\n ";
+ for (BasePath::const_reverse_iterator Element = Path->rbegin();
+ Element != Path->rend(); ++Element)
+ PathDisplayStr += Element->Base->getType().getAsString() + " -> ";
+ PathDisplayStr += DestType.getAsString();
+ }
+ }
+
+ Self.Diag(OpRange.getBegin(), diag::err_ambiguous_base_to_derived_cast)
+ << SrcType.getUnqualifiedType() << DestType.getUnqualifiedType()
+ << PathDisplayStr << OpRange;
+ return TSC_Failed;
+ }
+
+ if (Paths.getDetectedVirtual() != 0) {
+ QualType VirtualBase(Paths.getDetectedVirtual(), 0);
+ Self.Diag(OpRange.getBegin(), diag::err_static_downcast_via_virtual)
+ << OrigSrcType << OrigDestType << VirtualBase << OpRange;
+ return TSC_Failed;
+ }
+
+ // FIXME: Test accessibility.
+
+ return TSC_Success;
+}
+
+/// TryStaticMemberPointerUpcast - Tests whether a conversion according to
+/// C++ 5.2.9p9 is valid:
+///
+/// An rvalue of type "pointer to member of D of type cv1 T" can be
+/// converted to an rvalue of type "pointer to member of B of type cv2 T",
+/// where B is a base class of D [...].
+///
+TryStaticCastResult
+TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType,
+ const SourceRange &OpRange)
+{
+ const MemberPointerType *SrcMemPtr = SrcType->getAsMemberPointerType();
+ if (!SrcMemPtr)
+ return TSC_NotApplicable;
+ const MemberPointerType *DestMemPtr = DestType->getAsMemberPointerType();
+ if (!DestMemPtr)
+ return TSC_NotApplicable;
+
+ // T == T, modulo cv
+ if (Self.Context.getCanonicalType(
+ SrcMemPtr->getPointeeType().getUnqualifiedType()) !=
+ Self.Context.getCanonicalType(DestMemPtr->getPointeeType().
+ getUnqualifiedType()))
+ return TSC_NotApplicable;
+
+ // B base of D
+ QualType SrcClass(SrcMemPtr->getClass(), 0);
+ QualType DestClass(DestMemPtr->getClass(), 0);
+ BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+ /*DetectVirtual=*/true);
+ if (!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) {
+ return TSC_NotApplicable;
+ }
+
+ // B is a base of D. But is it an allowed base? If not, it's a hard error.
+ if (Paths.isAmbiguous(DestClass)) {
+ Paths.clear();
+ Paths.setRecordingPaths(true);
+ bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths);
+ assert(StillOkay);
+ StillOkay = StillOkay;
+ std::string PathDisplayStr = Self.getAmbiguousPathsDisplayString(Paths);
+ Self.Diag(OpRange.getBegin(), diag::err_ambiguous_memptr_conv)
+ << 1 << SrcClass << DestClass << PathDisplayStr << OpRange;
+ return TSC_Failed;
+ }
+
+ if (const RecordType *VBase = Paths.getDetectedVirtual()) {
+ Self.Diag(OpRange.getBegin(), diag::err_memptr_conv_via_virtual)
+ << SrcClass << DestClass << QualType(VBase, 0) << OpRange;
+ return TSC_Failed;
+ }
+
+ // FIXME: Test accessibility.
+
+ return TSC_Success;
+}
+
+/// TryStaticImplicitCast - Tests whether a conversion according to C++ 5.2.9p2
+/// is valid:
+///
+/// An expression e can be explicitly converted to a type T using a
+/// @c static_cast if the declaration "T t(e);" is well-formed [...].
+TryStaticCastResult
+TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType,
+ const SourceRange &OpRange)
+{
+ if (DestType->isReferenceType()) {
+ // At this point of CheckStaticCast, if the destination is a reference,
+ // this has to work. There is no other way that works.
+ return Self.CheckReferenceInit(SrcExpr, DestType) ?
+ TSC_Failed : TSC_Success;
+ }
+ if (DestType->isRecordType()) {
+ // FIXME: Use an implementation of C++ [over.match.ctor] for this.
+ return TSC_NotApplicable;
+ }
+
+ // FIXME: To get a proper error from invalid conversions here, we need to
+ // reimplement more of this.
+ ImplicitConversionSequence ICS = Self.TryImplicitConversion(
+ SrcExpr, DestType);
+ return ICS.ConversionKind == ImplicitConversionSequence::BadConversion ?
+ TSC_NotApplicable : TSC_Success;
+}
+
+/// 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.
+void
+CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+ const SourceRange &OpRange,
+ const SourceRange &DestRange)
+{
+ QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType();
+ DestType = Self.Context.getCanonicalType(DestType);
+
+ // C++ 5.2.7p1: T shall be a pointer or reference to a complete class type,
+ // or "pointer to cv void".
+
+ QualType DestPointee;
+ const PointerType *DestPointer = DestType->getAsPointerType();
+ const ReferenceType *DestReference = DestType->getAsReferenceType();
+ if (DestPointer) {
+ DestPointee = DestPointer->getPointeeType();
+ } else if (DestReference) {
+ DestPointee = DestReference->getPointeeType();
+ } else {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr)
+ << OrigDestType << DestRange;
+ return;
+ }
+
+ const RecordType *DestRecord = DestPointee->getAsRecordType();
+ if (DestPointee->isVoidType()) {
+ assert(DestPointer && "Reference to void is not possible");
+ } else if (DestRecord) {
+ if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee,
+ diag::err_bad_dynamic_cast_incomplete,
+ DestRange))
+ return;
+ } else {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class)
+ << DestPointee.getUnqualifiedType() << DestRange;
+ return;
+ }
+
+ // C++0x 5.2.7p2: If T is a pointer type, v shall be an rvalue of a pointer to
+ // complete class type, [...]. If T is an lvalue reference type, v shall be
+ // an lvalue of a complete class type, [...]. If T is an rvalue reference
+ // type, v shall be an expression having a complete effective class type,
+ // [...]
+
+ QualType SrcType = Self.Context.getCanonicalType(OrigSrcType);
+ QualType SrcPointee;
+ if (DestPointer) {
+ if (const PointerType *SrcPointer = SrcType->getAsPointerType()) {
+ SrcPointee = SrcPointer->getPointeeType();
+ } else {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr)
+ << OrigSrcType << SrcExpr->getSourceRange();
+ return;
+ }
+ } else if (DestReference->isLValueReferenceType()) {
+ if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue)
+ << "dynamic_cast" << OrigDestType << OpRange;
+ }
+ SrcPointee = SrcType;
+ } else {
+ SrcPointee = SrcType;
+ }
+
+ const RecordType *SrcRecord = SrcPointee->getAsRecordType();
+ if (SrcRecord) {
+ if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee,
+ diag::err_bad_dynamic_cast_incomplete,
+ SrcExpr->getSourceRange()))
+ return;
+ } else {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class)
+ << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange();
+ return;
+ }
+
+ assert((DestPointer || DestReference) &&
+ "Bad destination non-ptr/ref slipped through.");
+ assert((DestRecord || DestPointee->isVoidType()) &&
+ "Bad destination pointee slipped through.");
+ assert(SrcRecord && "Bad source pointee slipped through.");
+
+ // 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_const_away)
+ << "dynamic_cast" << OrigDestType << OrigSrcType << OpRange;
+ return;
+ }
+
+ // C++ 5.2.7p3: If the type of v is the same as the required result type,
+ // [except for cv].
+ if (DestRecord == SrcRecord) {
+ return;
+ }
+
+ // C++ 5.2.7p5
+ // Upcasts are resolved statically.
+ if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) {
+ Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee,
+ OpRange.getBegin(), OpRange);
+ // Diagnostic already emitted on error.
+ return;
+ }
+
+ // C++ 5.2.7p6: Otherwise, v shall be [polymorphic].
+ const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition(Self.Context);
+ assert(SrcDecl && "Definition missing");
+ if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic)
+ << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange();
+ }
+
+ // Done. Everything else is run-time checks.
+}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
new file mode 100644
index 000000000000..98ee13af856a
--- /dev/null
+++ b/lib/Sema/SemaOverload.cpp
@@ -0,0 +1,4485 @@
+//===--- SemaOverload.cpp - C++ Overloading ---------------------*- 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 Sema routines for C++ overloading.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "SemaInherit.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/TypeOrdering.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+#include <algorithm>
+
+namespace clang {
+
+/// GetConversionCategory - Retrieve the implicit conversion
+/// category corresponding to the given implicit conversion kind.
+ImplicitConversionCategory
+GetConversionCategory(ImplicitConversionKind Kind) {
+ static const ImplicitConversionCategory
+ Category[(int)ICK_Num_Conversion_Kinds] = {
+ ICC_Identity,
+ ICC_Lvalue_Transformation,
+ ICC_Lvalue_Transformation,
+ ICC_Lvalue_Transformation,
+ ICC_Qualification_Adjustment,
+ ICC_Promotion,
+ ICC_Promotion,
+ ICC_Promotion,
+ ICC_Conversion,
+ ICC_Conversion,
+ ICC_Conversion,
+ ICC_Conversion,
+ ICC_Conversion,
+ ICC_Conversion,
+ ICC_Conversion,
+ ICC_Conversion,
+ ICC_Conversion,
+ ICC_Conversion
+ };
+ return Category[(int)Kind];
+}
+
+/// GetConversionRank - Retrieve the implicit conversion rank
+/// corresponding to the given implicit conversion kind.
+ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) {
+ static const ImplicitConversionRank
+ Rank[(int)ICK_Num_Conversion_Kinds] = {
+ ICR_Exact_Match,
+ ICR_Exact_Match,
+ ICR_Exact_Match,
+ ICR_Exact_Match,
+ ICR_Exact_Match,
+ ICR_Promotion,
+ ICR_Promotion,
+ ICR_Promotion,
+ ICR_Conversion,
+ ICR_Conversion,
+ ICR_Conversion,
+ ICR_Conversion,
+ ICR_Conversion,
+ ICR_Conversion,
+ ICR_Conversion,
+ ICR_Conversion,
+ ICR_Conversion,
+ ICR_Conversion
+ };
+ return Rank[(int)Kind];
+}
+
+/// GetImplicitConversionName - Return the name of this kind of
+/// implicit conversion.
+const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
+ static const char* Name[(int)ICK_Num_Conversion_Kinds] = {
+ "No conversion",
+ "Lvalue-to-rvalue",
+ "Array-to-pointer",
+ "Function-to-pointer",
+ "Qualification",
+ "Integral promotion",
+ "Floating point promotion",
+ "Complex promotion",
+ "Integral conversion",
+ "Floating conversion",
+ "Complex conversion",
+ "Floating-integral conversion",
+ "Complex-real conversion",
+ "Pointer conversion",
+ "Pointer-to-member conversion",
+ "Boolean conversion",
+ "Compatible-types conversion",
+ "Derived-to-base conversion"
+ };
+ return Name[Kind];
+}
+
+/// StandardConversionSequence - Set the standard conversion
+/// sequence to the identity conversion.
+void StandardConversionSequence::setAsIdentityConversion() {
+ First = ICK_Identity;
+ Second = ICK_Identity;
+ Third = ICK_Identity;
+ Deprecated = false;
+ ReferenceBinding = false;
+ DirectBinding = false;
+ RRefBinding = false;
+ CopyConstructor = 0;
+}
+
+/// getRank - Retrieve the rank of this standard conversion sequence
+/// (C++ 13.3.3.1.1p3). The rank is the largest rank of each of the
+/// implicit conversions.
+ImplicitConversionRank StandardConversionSequence::getRank() const {
+ ImplicitConversionRank Rank = ICR_Exact_Match;
+ if (GetConversionRank(First) > Rank)
+ Rank = GetConversionRank(First);
+ if (GetConversionRank(Second) > Rank)
+ Rank = GetConversionRank(Second);
+ if (GetConversionRank(Third) > Rank)
+ Rank = GetConversionRank(Third);
+ return Rank;
+}
+
+/// isPointerConversionToBool - Determines whether this conversion is
+/// a conversion of a pointer or pointer-to-member to bool. This is
+/// used as part of the ranking of standard conversion sequences
+/// (C++ 13.3.3.2p4).
+bool StandardConversionSequence::isPointerConversionToBool() const
+{
+ QualType FromType = QualType::getFromOpaquePtr(FromTypePtr);
+ QualType ToType = QualType::getFromOpaquePtr(ToTypePtr);
+
+ // Note that FromType has not necessarily been transformed by the
+ // array-to-pointer or function-to-pointer implicit conversions, so
+ // check for their presence as well as checking whether FromType is
+ // a pointer.
+ if (ToType->isBooleanType() &&
+ (FromType->isPointerType() || FromType->isBlockPointerType() ||
+ First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer))
+ return true;
+
+ return false;
+}
+
+/// isPointerConversionToVoidPointer - Determines whether this
+/// conversion is a conversion of a pointer to a void pointer. This is
+/// used as part of the ranking of standard conversion sequences (C++
+/// 13.3.3.2p4).
+bool
+StandardConversionSequence::
+isPointerConversionToVoidPointer(ASTContext& Context) const
+{
+ QualType FromType = QualType::getFromOpaquePtr(FromTypePtr);
+ QualType ToType = QualType::getFromOpaquePtr(ToTypePtr);
+
+ // Note that FromType has not necessarily been transformed by the
+ // array-to-pointer implicit conversion, so check for its presence
+ // and redo the conversion to get a pointer.
+ if (First == ICK_Array_To_Pointer)
+ FromType = Context.getArrayDecayedType(FromType);
+
+ if (Second == ICK_Pointer_Conversion)
+ if (const PointerType* ToPtrType = ToType->getAsPointerType())
+ return ToPtrType->getPointeeType()->isVoidType();
+
+ return false;
+}
+
+/// DebugPrint - Print this standard conversion sequence to standard
+/// error. Useful for debugging overloading issues.
+void StandardConversionSequence::DebugPrint() const {
+ bool PrintedSomething = false;
+ if (First != ICK_Identity) {
+ fprintf(stderr, "%s", GetImplicitConversionName(First));
+ PrintedSomething = true;
+ }
+
+ if (Second != ICK_Identity) {
+ if (PrintedSomething) {
+ fprintf(stderr, " -> ");
+ }
+ fprintf(stderr, "%s", GetImplicitConversionName(Second));
+
+ if (CopyConstructor) {
+ fprintf(stderr, " (by copy constructor)");
+ } else if (DirectBinding) {
+ fprintf(stderr, " (direct reference binding)");
+ } else if (ReferenceBinding) {
+ fprintf(stderr, " (reference binding)");
+ }
+ PrintedSomething = true;
+ }
+
+ if (Third != ICK_Identity) {
+ if (PrintedSomething) {
+ fprintf(stderr, " -> ");
+ }
+ fprintf(stderr, "%s", GetImplicitConversionName(Third));
+ PrintedSomething = true;
+ }
+
+ if (!PrintedSomething) {
+ fprintf(stderr, "No conversions required");
+ }
+}
+
+/// DebugPrint - Print this user-defined conversion sequence to standard
+/// error. Useful for debugging overloading issues.
+void UserDefinedConversionSequence::DebugPrint() const {
+ if (Before.First || Before.Second || Before.Third) {
+ Before.DebugPrint();
+ fprintf(stderr, " -> ");
+ }
+ fprintf(stderr, "'%s'", ConversionFunction->getNameAsString().c_str());
+ if (After.First || After.Second || After.Third) {
+ fprintf(stderr, " -> ");
+ After.DebugPrint();
+ }
+}
+
+/// DebugPrint - Print this implicit conversion sequence to standard
+/// error. Useful for debugging overloading issues.
+void ImplicitConversionSequence::DebugPrint() const {
+ switch (ConversionKind) {
+ case StandardConversion:
+ fprintf(stderr, "Standard conversion: ");
+ Standard.DebugPrint();
+ break;
+ case UserDefinedConversion:
+ fprintf(stderr, "User-defined conversion: ");
+ UserDefined.DebugPrint();
+ break;
+ case EllipsisConversion:
+ fprintf(stderr, "Ellipsis conversion");
+ break;
+ case BadConversion:
+ fprintf(stderr, "Bad conversion");
+ break;
+ }
+
+ fprintf(stderr, "\n");
+}
+
+// IsOverload - Determine whether the given New declaration is an
+// overload of the Old declaration. This routine returns false if New
+// and Old cannot be overloaded, e.g., if they are functions with the
+// same signature (C++ 1.3.10) or if the Old declaration isn't a
+// function (or overload set). When it does return false and Old is an
+// OverloadedFunctionDecl, MatchedDecl will be set to point to the
+// FunctionDecl that New cannot be overloaded with.
+//
+// Example: Given the following input:
+//
+// void f(int, float); // #1
+// void f(int, int); // #2
+// int f(int, int); // #3
+//
+// When we process #1, there is no previous declaration of "f",
+// so IsOverload will not be used.
+//
+// When we process #2, Old is a FunctionDecl for #1. By comparing the
+// parameter types, we see that #1 and #2 are overloaded (since they
+// have different signatures), so this routine returns false;
+// MatchedDecl is unchanged.
+//
+// When we process #3, Old is an OverloadedFunctionDecl containing #1
+// and #2. We compare the signatures of #3 to #1 (they're overloaded,
+// so we do nothing) and then #3 to #2. Since the signatures of #3 and
+// #2 are identical (return types of functions are not part of the
+// signature), IsOverload returns false and MatchedDecl will be set to
+// point to the FunctionDecl for #2.
+bool
+Sema::IsOverload(FunctionDecl *New, Decl* OldD,
+ OverloadedFunctionDecl::function_iterator& MatchedDecl)
+{
+ if (OverloadedFunctionDecl* Ovl = dyn_cast<OverloadedFunctionDecl>(OldD)) {
+ // Is this new function an overload of every function in the
+ // overload set?
+ OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
+ FuncEnd = Ovl->function_end();
+ for (; Func != FuncEnd; ++Func) {
+ if (!IsOverload(New, *Func, MatchedDecl)) {
+ MatchedDecl = Func;
+ return false;
+ }
+ }
+
+ // This function overloads every function in the overload set.
+ return true;
+ } else if (FunctionDecl* Old = dyn_cast<FunctionDecl>(OldD)) {
+ // Is the function New an overload of the function Old?
+ QualType OldQType = Context.getCanonicalType(Old->getType());
+ QualType NewQType = Context.getCanonicalType(New->getType());
+
+ // Compare the signatures (C++ 1.3.10) of the two functions to
+ // determine whether they are overloads. If we find any mismatch
+ // in the signature, they are overloads.
+
+ // If either of these functions is a K&R-style function (no
+ // prototype), then we consider them to have matching signatures.
+ if (isa<FunctionNoProtoType>(OldQType.getTypePtr()) ||
+ isa<FunctionNoProtoType>(NewQType.getTypePtr()))
+ return false;
+
+ FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType.getTypePtr());
+ FunctionProtoType* NewType = cast<FunctionProtoType>(NewQType.getTypePtr());
+
+ // The signature of a function includes the types of its
+ // parameters (C++ 1.3.10), which includes the presence or absence
+ // of the ellipsis; see C++ DR 357).
+ if (OldQType != NewQType &&
+ (OldType->getNumArgs() != NewType->getNumArgs() ||
+ OldType->isVariadic() != NewType->isVariadic() ||
+ !std::equal(OldType->arg_type_begin(), OldType->arg_type_end(),
+ NewType->arg_type_begin())))
+ return true;
+
+ // If the function is a class member, its signature includes the
+ // cv-qualifiers (if any) on the function itself.
+ //
+ // As part of this, also check whether one of the member functions
+ // is static, in which case they are not overloads (C++
+ // 13.1p2). While not part of the definition of the signature,
+ // this check is important to determine whether these functions
+ // can be overloaded.
+ CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
+ CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
+ if (OldMethod && NewMethod &&
+ !OldMethod->isStatic() && !NewMethod->isStatic() &&
+ OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers())
+ return true;
+
+ // The signatures match; this is not an overload.
+ return false;
+ } else {
+ // (C++ 13p1):
+ // Only function declarations can be overloaded; object and type
+ // declarations cannot be overloaded.
+ return false;
+ }
+}
+
+/// TryImplicitConversion - Attempt to perform an implicit conversion
+/// from the given expression (Expr) to the given type (ToType). This
+/// function returns an implicit conversion sequence that can be used
+/// to perform the initialization. Given
+///
+/// void f(float f);
+/// void g(int i) { f(i); }
+///
+/// this routine would produce an implicit conversion sequence to
+/// describe the initialization of f from i, which will be a standard
+/// conversion sequence containing an lvalue-to-rvalue conversion (C++
+/// 4.1) followed by a floating-integral conversion (C++ 4.9).
+//
+/// Note that this routine only determines how the conversion can be
+/// performed; it does not actually perform the conversion. As such,
+/// it will not produce any diagnostics if no conversion is available,
+/// but will instead return an implicit conversion sequence of kind
+/// "BadConversion".
+///
+/// If @p SuppressUserConversions, then user-defined conversions are
+/// not permitted.
+/// If @p AllowExplicit, then explicit user-defined conversions are
+/// permitted.
+/// If @p ForceRValue, then overloading is performed as if From was an rvalue,
+/// no matter its actual lvalueness.
+ImplicitConversionSequence
+Sema::TryImplicitConversion(Expr* From, QualType ToType,
+ bool SuppressUserConversions,
+ bool AllowExplicit, bool ForceRValue)
+{
+ ImplicitConversionSequence ICS;
+ if (IsStandardConversion(From, ToType, ICS.Standard))
+ ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
+ else if (getLangOptions().CPlusPlus &&
+ IsUserDefinedConversion(From, ToType, ICS.UserDefined,
+ !SuppressUserConversions, AllowExplicit,
+ ForceRValue)) {
+ ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
+ // C++ [over.ics.user]p4:
+ // A conversion of an expression of class type to the same class
+ // type is given Exact Match rank, and a conversion of an
+ // expression of class type to a base class of that type is
+ // given Conversion rank, in spite of the fact that a copy
+ // constructor (i.e., a user-defined conversion function) is
+ // called for those cases.
+ if (CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
+ QualType FromCanon
+ = Context.getCanonicalType(From->getType().getUnqualifiedType());
+ QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType();
+ if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) {
+ // Turn this into a "standard" conversion sequence, so that it
+ // gets ranked with standard conversion sequences.
+ ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
+ ICS.Standard.setAsIdentityConversion();
+ ICS.Standard.FromTypePtr = From->getType().getAsOpaquePtr();
+ ICS.Standard.ToTypePtr = ToType.getAsOpaquePtr();
+ ICS.Standard.CopyConstructor = Constructor;
+ if (ToCanon != FromCanon)
+ ICS.Standard.Second = ICK_Derived_To_Base;
+ }
+ }
+
+ // C++ [over.best.ics]p4:
+ // However, when considering the argument of a user-defined
+ // conversion function that is a candidate by 13.3.1.3 when
+ // invoked for the copying of the temporary in the second step
+ // of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or
+ // 13.3.1.6 in all cases, only standard conversion sequences and
+ // ellipsis conversion sequences are allowed.
+ if (SuppressUserConversions &&
+ ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion)
+ ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+ } else
+ ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+
+ return ICS;
+}
+
+/// IsStandardConversion - Determines whether there is a standard
+/// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the
+/// expression From to the type ToType. Standard conversion sequences
+/// only consider non-class types; for conversions that involve class
+/// types, use TryImplicitConversion. If a conversion exists, SCS will
+/// contain the standard conversion sequence required to perform this
+/// conversion and this routine will return true. Otherwise, this
+/// routine will return false and the value of SCS is unspecified.
+bool
+Sema::IsStandardConversion(Expr* From, QualType ToType,
+ StandardConversionSequence &SCS)
+{
+ QualType FromType = From->getType();
+
+ // Standard conversions (C++ [conv])
+ SCS.setAsIdentityConversion();
+ SCS.Deprecated = false;
+ SCS.IncompatibleObjC = false;
+ SCS.FromTypePtr = FromType.getAsOpaquePtr();
+ SCS.CopyConstructor = 0;
+
+ // There are no standard conversions for class types in C++, so
+ // abort early. When overloading in C, however, we do permit
+ if (FromType->isRecordType() || ToType->isRecordType()) {
+ if (getLangOptions().CPlusPlus)
+ return false;
+
+ // When we're overloading in C, we allow, as standard conversions,
+ }
+
+ // The first conversion can be an lvalue-to-rvalue conversion,
+ // array-to-pointer conversion, or function-to-pointer conversion
+ // (C++ 4p1).
+
+ // 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.
+ Expr::isLvalueResult argIsLvalue = From->isLvalue(Context);
+ if (argIsLvalue == Expr::LV_Valid &&
+ !FromType->isFunctionType() && !FromType->isArrayType() &&
+ Context.getCanonicalType(FromType) != Context.OverloadTy) {
+ SCS.First = ICK_Lvalue_To_Rvalue;
+
+ // If T is a non-class type, the type of the rvalue is the
+ // cv-unqualified version of T. Otherwise, the type of the rvalue
+ // is T (C++ 4.1p1). C++ can't get here with class types; in C, we
+ // just strip the qualifiers because they don't matter.
+
+ // FIXME: Doesn't see through to qualifiers behind a typedef!
+ FromType = FromType.getUnqualifiedType();
+ }
+ // Array-to-pointer conversion (C++ 4.2)
+ else if (FromType->isArrayType()) {
+ SCS.First = ICK_Array_To_Pointer;
+
+ // An lvalue or rvalue of type "array of N T" or "array of unknown
+ // bound of T" can be converted to an rvalue of type "pointer to
+ // T" (C++ 4.2p1).
+ FromType = Context.getArrayDecayedType(FromType);
+
+ if (IsStringLiteralToNonConstPointerConversion(From, ToType)) {
+ // This conversion is deprecated. (C++ D.4).
+ SCS.Deprecated = true;
+
+ // For the purpose of ranking in overload resolution
+ // (13.3.3.1.1), this conversion is considered an
+ // array-to-pointer conversion followed by a qualification
+ // conversion (4.4). (C++ 4.2p2)
+ SCS.Second = ICK_Identity;
+ SCS.Third = ICK_Qualification;
+ SCS.ToTypePtr = ToType.getAsOpaquePtr();
+ return true;
+ }
+ }
+ // Function-to-pointer conversion (C++ 4.3).
+ else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) {
+ SCS.First = ICK_Function_To_Pointer;
+
+ // An lvalue of function type T can be converted to an rvalue of
+ // type "pointer to T." The result is a pointer to the
+ // function. (C++ 4.3p1).
+ FromType = Context.getPointerType(FromType);
+ }
+ // Address of overloaded function (C++ [over.over]).
+ else if (FunctionDecl *Fn
+ = ResolveAddressOfOverloadedFunction(From, ToType, false)) {
+ SCS.First = ICK_Function_To_Pointer;
+
+ // We were able to resolve the address of the overloaded function,
+ // so we can convert to the type of that function.
+ FromType = Fn->getType();
+ if (ToType->isLValueReferenceType())
+ FromType = Context.getLValueReferenceType(FromType);
+ else if (ToType->isRValueReferenceType())
+ FromType = Context.getRValueReferenceType(FromType);
+ else if (ToType->isMemberPointerType()) {
+ // Resolve address only succeeds if both sides are member pointers,
+ // but it doesn't have to be the same class. See DR 247.
+ // Note that this means that the type of &Derived::fn can be
+ // Ret (Base::*)(Args) if the fn overload actually found is from the
+ // base class, even if it was brought into the derived class via a
+ // using declaration. The standard isn't clear on this issue at all.
+ CXXMethodDecl *M = cast<CXXMethodDecl>(Fn);
+ FromType = Context.getMemberPointerType(FromType,
+ Context.getTypeDeclType(M->getParent()).getTypePtr());
+ } else
+ FromType = Context.getPointerType(FromType);
+ }
+ // We don't require any conversions for the first step.
+ else {
+ SCS.First = ICK_Identity;
+ }
+
+ // The second conversion can be an integral promotion, floating
+ // point promotion, integral conversion, floating point conversion,
+ // floating-integral conversion, pointer conversion,
+ // pointer-to-member conversion, or boolean conversion (C++ 4p1).
+ // For overloading in C, this can also be a "compatible-type"
+ // conversion.
+ bool IncompatibleObjC = false;
+ if (Context.hasSameUnqualifiedType(FromType, ToType)) {
+ // The unqualified versions of the types are the same: there's no
+ // conversion to do.
+ SCS.Second = ICK_Identity;
+ }
+ // Integral promotion (C++ 4.5).
+ else if (IsIntegralPromotion(From, FromType, ToType)) {
+ SCS.Second = ICK_Integral_Promotion;
+ FromType = ToType.getUnqualifiedType();
+ }
+ // Floating point promotion (C++ 4.6).
+ else if (IsFloatingPointPromotion(FromType, ToType)) {
+ SCS.Second = ICK_Floating_Promotion;
+ FromType = ToType.getUnqualifiedType();
+ }
+ // Complex promotion (Clang extension)
+ else if (IsComplexPromotion(FromType, ToType)) {
+ SCS.Second = ICK_Complex_Promotion;
+ FromType = ToType.getUnqualifiedType();
+ }
+ // Integral conversions (C++ 4.7).
+ // FIXME: isIntegralType shouldn't be true for enums in C++.
+ else if ((FromType->isIntegralType() || FromType->isEnumeralType()) &&
+ (ToType->isIntegralType() && !ToType->isEnumeralType())) {
+ SCS.Second = ICK_Integral_Conversion;
+ FromType = ToType.getUnqualifiedType();
+ }
+ // Floating point conversions (C++ 4.8).
+ else if (FromType->isFloatingType() && ToType->isFloatingType()) {
+ SCS.Second = ICK_Floating_Conversion;
+ FromType = ToType.getUnqualifiedType();
+ }
+ // Complex conversions (C99 6.3.1.6)
+ else if (FromType->isComplexType() && ToType->isComplexType()) {
+ SCS.Second = ICK_Complex_Conversion;
+ FromType = ToType.getUnqualifiedType();
+ }
+ // Floating-integral conversions (C++ 4.9).
+ // FIXME: isIntegralType shouldn't be true for enums in C++.
+ else if ((FromType->isFloatingType() &&
+ ToType->isIntegralType() && !ToType->isBooleanType() &&
+ !ToType->isEnumeralType()) ||
+ ((FromType->isIntegralType() || FromType->isEnumeralType()) &&
+ ToType->isFloatingType())) {
+ SCS.Second = ICK_Floating_Integral;
+ FromType = ToType.getUnqualifiedType();
+ }
+ // Complex-real conversions (C99 6.3.1.7)
+ else if ((FromType->isComplexType() && ToType->isArithmeticType()) ||
+ (ToType->isComplexType() && FromType->isArithmeticType())) {
+ SCS.Second = ICK_Complex_Real;
+ FromType = ToType.getUnqualifiedType();
+ }
+ // Pointer conversions (C++ 4.10).
+ else if (IsPointerConversion(From, FromType, ToType, FromType,
+ IncompatibleObjC)) {
+ SCS.Second = ICK_Pointer_Conversion;
+ SCS.IncompatibleObjC = IncompatibleObjC;
+ }
+ // Pointer to member conversions (4.11).
+ else if (IsMemberPointerConversion(From, FromType, ToType, FromType)) {
+ SCS.Second = ICK_Pointer_Member;
+ }
+ // Boolean conversions (C++ 4.12).
+ else if (ToType->isBooleanType() &&
+ (FromType->isArithmeticType() ||
+ FromType->isEnumeralType() ||
+ FromType->isPointerType() ||
+ FromType->isBlockPointerType() ||
+ FromType->isMemberPointerType() ||
+ FromType->isNullPtrType())) {
+ SCS.Second = ICK_Boolean_Conversion;
+ FromType = Context.BoolTy;
+ }
+ // Compatible conversions (Clang extension for C function overloading)
+ else if (!getLangOptions().CPlusPlus &&
+ Context.typesAreCompatible(ToType, FromType)) {
+ SCS.Second = ICK_Compatible_Conversion;
+ } else {
+ // No second conversion required.
+ SCS.Second = ICK_Identity;
+ }
+
+ QualType CanonFrom;
+ QualType CanonTo;
+ // The third conversion can be a qualification conversion (C++ 4p1).
+ if (IsQualificationConversion(FromType, ToType)) {
+ SCS.Third = ICK_Qualification;
+ FromType = ToType;
+ CanonFrom = Context.getCanonicalType(FromType);
+ CanonTo = Context.getCanonicalType(ToType);
+ } else {
+ // No conversion required
+ SCS.Third = ICK_Identity;
+
+ // C++ [over.best.ics]p6:
+ // [...] Any difference in top-level cv-qualification is
+ // subsumed by the initialization itself and does not constitute
+ // a conversion. [...]
+ CanonFrom = Context.getCanonicalType(FromType);
+ CanonTo = Context.getCanonicalType(ToType);
+ if (CanonFrom.getUnqualifiedType() == CanonTo.getUnqualifiedType() &&
+ CanonFrom.getCVRQualifiers() != CanonTo.getCVRQualifiers()) {
+ FromType = ToType;
+ CanonFrom = CanonTo;
+ }
+ }
+
+ // If we have not converted the argument type to the parameter type,
+ // this is a bad conversion sequence.
+ if (CanonFrom != CanonTo)
+ return false;
+
+ SCS.ToTypePtr = FromType.getAsOpaquePtr();
+ return true;
+}
+
+/// IsIntegralPromotion - Determines whether the conversion from the
+/// expression From (whose potentially-adjusted type is FromType) to
+/// ToType is an integral promotion (C++ 4.5). If so, returns true and
+/// sets PromotedType to the promoted type.
+bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType)
+{
+ const BuiltinType *To = ToType->getAsBuiltinType();
+ // All integers are built-in.
+ if (!To) {
+ return false;
+ }
+
+ // An rvalue of type char, signed char, unsigned char, short int, or
+ // unsigned short int can be converted to an rvalue of type int if
+ // int can represent all the values of the source type; otherwise,
+ // the source rvalue can be converted to an rvalue of type unsigned
+ // int (C++ 4.5p1).
+ if (FromType->isPromotableIntegerType() && !FromType->isBooleanType()) {
+ if (// We can promote any signed, promotable integer type to an int
+ (FromType->isSignedIntegerType() ||
+ // We can promote any unsigned integer type whose size is
+ // less than int to an int.
+ (!FromType->isSignedIntegerType() &&
+ Context.getTypeSize(FromType) < Context.getTypeSize(ToType)))) {
+ return To->getKind() == BuiltinType::Int;
+ }
+
+ return To->getKind() == BuiltinType::UInt;
+ }
+
+ // An rvalue of type wchar_t (3.9.1) or an enumeration type (7.2)
+ // can be converted to an rvalue of the first of the following types
+ // that can represent all the values of its underlying type: int,
+ // unsigned int, long, or unsigned long (C++ 4.5p2).
+ if ((FromType->isEnumeralType() || FromType->isWideCharType())
+ && ToType->isIntegerType()) {
+ // Determine whether the type we're converting from is signed or
+ // unsigned.
+ bool FromIsSigned;
+ uint64_t FromSize = Context.getTypeSize(FromType);
+ if (const EnumType *FromEnumType = FromType->getAsEnumType()) {
+ QualType UnderlyingType = FromEnumType->getDecl()->getIntegerType();
+ FromIsSigned = UnderlyingType->isSignedIntegerType();
+ } else {
+ // 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] = {
+ Context.IntTy, Context.UnsignedIntTy,
+ Context.LongTy, Context.UnsignedLongTy ,
+ Context.LongLongTy, Context.UnsignedLongLongTy
+ };
+ for (int Idx = 0; Idx < 6; ++Idx) {
+ uint64_t ToSize = Context.getTypeSize(PromoteTypes[Idx]);
+ if (FromSize < ToSize ||
+ (FromSize == ToSize &&
+ FromIsSigned == PromoteTypes[Idx]->isSignedIntegerType())) {
+ // We found the type that we can promote to. If this is the
+ // type we wanted, we have a promotion. Otherwise, no
+ // promotion.
+ return Context.getCanonicalType(ToType).getUnqualifiedType()
+ == Context.getCanonicalType(PromoteTypes[Idx]).getUnqualifiedType();
+ }
+ }
+ }
+
+ // An rvalue for an integral bit-field (9.6) can be converted to an
+ // rvalue of type int if int can represent all the values of the
+ // bit-field; otherwise, it can be converted to unsigned int if
+ // unsigned int can represent all the values of the bit-field. If
+ // the bit-field is larger yet, no integral promotion applies to
+ // it. If the bit-field has an enumerated type, it is treated as any
+ // other value of that type for promotion purposes (C++ 4.5p3).
+ // FIXME: We should delay checking of bit-fields until we actually perform the
+ // conversion.
+ using llvm::APSInt;
+ if (From)
+ if (FieldDecl *MemberDecl = From->getBitField()) {
+ APSInt BitWidth;
+ if (FromType->isIntegralType() && !FromType->isEnumeralType() &&
+ MemberDecl->getBitWidth()->isIntegerConstantExpr(BitWidth, Context)) {
+ APSInt ToSize(BitWidth.getBitWidth(), BitWidth.isUnsigned());
+ ToSize = Context.getTypeSize(ToType);
+
+ // Are we promoting to an int from a bitfield that fits in an int?
+ if (BitWidth < ToSize ||
+ (FromType->isSignedIntegerType() && BitWidth <= ToSize)) {
+ return To->getKind() == BuiltinType::Int;
+ }
+
+ // Are we promoting to an unsigned int from an unsigned bitfield
+ // that fits into an unsigned int?
+ if (FromType->isUnsignedIntegerType() && BitWidth <= ToSize) {
+ return To->getKind() == BuiltinType::UInt;
+ }
+
+ return false;
+ }
+ }
+
+ // An rvalue of type bool can be converted to an rvalue of type int,
+ // with false becoming zero and true becoming one (C++ 4.5p4).
+ if (FromType->isBooleanType() && To->getKind() == BuiltinType::Int) {
+ return true;
+ }
+
+ return false;
+}
+
+/// IsFloatingPointPromotion - Determines whether the conversion from
+/// 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->getAsBuiltinType())
+ if (const BuiltinType *ToBuiltin = ToType->getAsBuiltinType()) {
+ if (FromBuiltin->getKind() == BuiltinType::Float &&
+ ToBuiltin->getKind() == BuiltinType::Double)
+ return true;
+
+ // C99 6.3.1.5p1:
+ // When a float is promoted to double or long double, or a
+ // double is promoted to long double [...].
+ if (!getLangOptions().CPlusPlus &&
+ (FromBuiltin->getKind() == BuiltinType::Float ||
+ FromBuiltin->getKind() == BuiltinType::Double) &&
+ (ToBuiltin->getKind() == BuiltinType::LongDouble))
+ return true;
+ }
+
+ return false;
+}
+
+/// \brief Determine if a conversion is a complex promotion.
+///
+/// A complex promotion is defined as a complex -> complex conversion
+/// where the conversion between the underlying real types is a
+/// floating-point or integral promotion.
+bool Sema::IsComplexPromotion(QualType FromType, QualType ToType) {
+ const ComplexType *FromComplex = FromType->getAsComplexType();
+ if (!FromComplex)
+ return false;
+
+ const ComplexType *ToComplex = ToType->getAsComplexType();
+ if (!ToComplex)
+ return false;
+
+ return IsFloatingPointPromotion(FromComplex->getElementType(),
+ ToComplex->getElementType()) ||
+ IsIntegralPromotion(0, FromComplex->getElementType(),
+ ToComplex->getElementType());
+}
+
+/// BuildSimilarlyQualifiedPointerType - In a pointer conversion from
+/// the pointer type FromPtr to a pointer to type ToPointee, with the
+/// same type qualifiers as FromPtr has on its pointee type. ToType,
+/// if non-empty, will be a pointer to ToType that may or may not have
+/// the right set of qualifiers on its pointee.
+static QualType
+BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr,
+ QualType ToPointee, QualType ToType,
+ ASTContext &Context) {
+ QualType CanonFromPointee = Context.getCanonicalType(FromPtr->getPointeeType());
+ QualType CanonToPointee = Context.getCanonicalType(ToPointee);
+ unsigned Quals = CanonFromPointee.getCVRQualifiers();
+
+ // Exact qualifier match -> return the pointer type we're converting to.
+ if (CanonToPointee.getCVRQualifiers() == Quals) {
+ // ToType is exactly what we need. Return it.
+ if (ToType.getTypePtr())
+ return ToType;
+
+ // Build a pointer to ToPointee. It has the right qualifiers
+ // already.
+ return Context.getPointerType(ToPointee);
+ }
+
+ // Just build a canonical type that has the right qualifiers.
+ return Context.getPointerType(CanonToPointee.getQualifiedType(Quals));
+}
+
+/// IsPointerConversion - Determines whether the conversion of the
+/// expression From, which has the (possibly adjusted) type FromType,
+/// can be converted to the type ToType via a pointer conversion (C++
+/// 4.10). If so, returns true and places the converted type (that
+/// might differ from ToType in its cv-qualifiers at some level) into
+/// ConvertedType.
+///
+/// This routine also supports conversions to and from block pointers
+/// and conversions with Objective-C's 'id', 'id<protocols...>', and
+/// pointers to interfaces. FIXME: Once we've determined the
+/// appropriate overloading rules for Objective-C, we may want to
+/// split the Objective-C checks into a different routine; however,
+/// GCC seems to consider all of these conversions to be pointer
+/// conversions, so for now they live here. IncompatibleObjC will be
+/// set if the conversion is an allowed Objective-C conversion that
+/// should result in a warning.
+bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
+ QualType& ConvertedType,
+ bool &IncompatibleObjC)
+{
+ IncompatibleObjC = false;
+ if (isObjCPointerConversion(FromType, ToType, ConvertedType, IncompatibleObjC))
+ return true;
+
+ // Conversion from a null pointer constant to any Objective-C pointer type.
+ if (Context.isObjCObjectPointerType(ToType) &&
+ From->isNullPointerConstant(Context)) {
+ ConvertedType = ToType;
+ return true;
+ }
+
+ // Blocks: Block pointers can be converted to void*.
+ if (FromType->isBlockPointerType() && ToType->isPointerType() &&
+ ToType->getAsPointerType()->getPointeeType()->isVoidType()) {
+ ConvertedType = ToType;
+ return true;
+ }
+ // Blocks: A null pointer constant can be converted to a block
+ // pointer type.
+ if (ToType->isBlockPointerType() && From->isNullPointerConstant(Context)) {
+ ConvertedType = ToType;
+ return true;
+ }
+
+ // If the left-hand-side is nullptr_t, the right side can be a null
+ // pointer constant.
+ if (ToType->isNullPtrType() && From->isNullPointerConstant(Context)) {
+ ConvertedType = ToType;
+ return true;
+ }
+
+ const PointerType* ToTypePtr = ToType->getAsPointerType();
+ if (!ToTypePtr)
+ return false;
+
+ // A null pointer constant can be converted to a pointer type (C++ 4.10p1).
+ if (From->isNullPointerConstant(Context)) {
+ ConvertedType = ToType;
+ return true;
+ }
+
+ // Beyond this point, both types need to be pointers.
+ const PointerType *FromTypePtr = FromType->getAsPointerType();
+ if (!FromTypePtr)
+ return false;
+
+ QualType FromPointeeType = FromTypePtr->getPointeeType();
+ QualType ToPointeeType = ToTypePtr->getPointeeType();
+
+ // An rvalue of type "pointer to cv T," where T is an object type,
+ // can be converted to an rvalue of type "pointer to cv void" (C++
+ // 4.10p2).
+ if (FromPointeeType->isObjectType() && ToPointeeType->isVoidType()) {
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ToPointeeType,
+ ToType, Context);
+ return true;
+ }
+
+ // When we're overloading in C, we allow a special kind of pointer
+ // conversion for compatible-but-not-identical pointee types.
+ if (!getLangOptions().CPlusPlus &&
+ Context.typesAreCompatible(FromPointeeType, ToPointeeType)) {
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ToPointeeType,
+ ToType, Context);
+ return true;
+ }
+
+ // C++ [conv.ptr]p3:
+ //
+ // An rvalue of type "pointer to cv D," where D is a class type,
+ // can be converted to an rvalue of type "pointer to cv B," where
+ // B is a base class (clause 10) of D. If B is an inaccessible
+ // (clause 11) or ambiguous (10.2) base class of D, a program that
+ // necessitates this conversion is ill-formed. The result of the
+ // conversion is a pointer to the base class sub-object of the
+ // derived class object. The null pointer value is converted to
+ // the null pointer value of the destination type.
+ //
+ // Note that we do not check for ambiguity or inaccessibility
+ // here. That is handled by CheckPointerConversion.
+ if (getLangOptions().CPlusPlus &&
+ FromPointeeType->isRecordType() && ToPointeeType->isRecordType() &&
+ IsDerivedFrom(FromPointeeType, ToPointeeType)) {
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ToPointeeType,
+ ToType, Context);
+ return true;
+ }
+
+ return false;
+}
+
+/// isObjCPointerConversion - Determines whether this is an
+/// Objective-C pointer conversion. Subroutine of IsPointerConversion,
+/// with the same arguments and return values.
+bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
+ QualType& ConvertedType,
+ bool &IncompatibleObjC) {
+ if (!getLangOptions().ObjC1)
+ return false;
+
+ // Conversions with Objective-C's id<...>.
+ if ((FromType->isObjCQualifiedIdType() || ToType->isObjCQualifiedIdType()) &&
+ ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) {
+ ConvertedType = ToType;
+ return true;
+ }
+
+ // Beyond this point, both types need to be pointers or block pointers.
+ QualType ToPointeeType;
+ const PointerType* ToTypePtr = ToType->getAsPointerType();
+ if (ToTypePtr)
+ ToPointeeType = ToTypePtr->getPointeeType();
+ else if (const BlockPointerType *ToBlockPtr = ToType->getAsBlockPointerType())
+ ToPointeeType = ToBlockPtr->getPointeeType();
+ else
+ return false;
+
+ QualType FromPointeeType;
+ const PointerType *FromTypePtr = FromType->getAsPointerType();
+ if (FromTypePtr)
+ FromPointeeType = FromTypePtr->getPointeeType();
+ else if (const BlockPointerType *FromBlockPtr
+ = FromType->getAsBlockPointerType())
+ FromPointeeType = FromBlockPtr->getPointeeType();
+ else
+ return false;
+
+ // Objective C++: We're able to convert from a pointer to an
+ // interface to a pointer to a different interface.
+ const ObjCInterfaceType* FromIface = FromPointeeType->getAsObjCInterfaceType();
+ const ObjCInterfaceType* ToIface = ToPointeeType->getAsObjCInterfaceType();
+ if (FromIface && ToIface &&
+ Context.canAssignObjCInterfaces(ToIface, FromIface)) {
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ToPointeeType,
+ ToType, Context);
+ return true;
+ }
+
+ if (FromIface && ToIface &&
+ Context.canAssignObjCInterfaces(FromIface, ToIface)) {
+ // Okay: this is some kind of implicit downcast of Objective-C
+ // interfaces, which is permitted. However, we're going to
+ // complain about it.
+ IncompatibleObjC = true;
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ToPointeeType,
+ ToType, Context);
+ return true;
+ }
+
+ // Objective C++: We're able to convert between "id" and a pointer
+ // to any interface (in both directions).
+ if ((FromIface && Context.isObjCIdStructType(ToPointeeType))
+ || (ToIface && Context.isObjCIdStructType(FromPointeeType))) {
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ToPointeeType,
+ ToType, Context);
+ return true;
+ }
+
+ // Objective C++: Allow conversions between the Objective-C "id" and
+ // "Class", in either direction.
+ if ((Context.isObjCIdStructType(FromPointeeType) &&
+ Context.isObjCClassStructType(ToPointeeType)) ||
+ (Context.isObjCClassStructType(FromPointeeType) &&
+ Context.isObjCIdStructType(ToPointeeType))) {
+ ConvertedType = ToType;
+ return true;
+ }
+
+ // If we have pointers to pointers, recursively check whether this
+ // is an Objective-C conversion.
+ if (FromPointeeType->isPointerType() && ToPointeeType->isPointerType() &&
+ isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType,
+ IncompatibleObjC)) {
+ // We always complain about this conversion.
+ IncompatibleObjC = true;
+ ConvertedType = ToType;
+ return true;
+ }
+
+ // If we have pointers to functions or blocks, check whether the only
+ // differences in the argument and result types are in Objective-C
+ // pointer conversions. If so, we permit the conversion (but
+ // complain about it).
+ const FunctionProtoType *FromFunctionType
+ = FromPointeeType->getAsFunctionProtoType();
+ const FunctionProtoType *ToFunctionType
+ = ToPointeeType->getAsFunctionProtoType();
+ if (FromFunctionType && ToFunctionType) {
+ // If the function types are exactly the same, this isn't an
+ // Objective-C pointer conversion.
+ if (Context.getCanonicalType(FromPointeeType)
+ == Context.getCanonicalType(ToPointeeType))
+ return false;
+
+ // Perform the quick checks that will tell us whether these
+ // function types are obviously different.
+ if (FromFunctionType->getNumArgs() != ToFunctionType->getNumArgs() ||
+ FromFunctionType->isVariadic() != ToFunctionType->isVariadic() ||
+ FromFunctionType->getTypeQuals() != ToFunctionType->getTypeQuals())
+ return false;
+
+ bool HasObjCConversion = false;
+ if (Context.getCanonicalType(FromFunctionType->getResultType())
+ == Context.getCanonicalType(ToFunctionType->getResultType())) {
+ // Okay, the types match exactly. Nothing to do.
+ } else if (isObjCPointerConversion(FromFunctionType->getResultType(),
+ ToFunctionType->getResultType(),
+ ConvertedType, IncompatibleObjC)) {
+ // Okay, we have an Objective-C pointer conversion.
+ HasObjCConversion = true;
+ } else {
+ // Function types are too different. Abort.
+ return false;
+ }
+
+ // Check argument types.
+ for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs();
+ ArgIdx != NumArgs; ++ArgIdx) {
+ QualType FromArgType = FromFunctionType->getArgType(ArgIdx);
+ QualType ToArgType = ToFunctionType->getArgType(ArgIdx);
+ if (Context.getCanonicalType(FromArgType)
+ == Context.getCanonicalType(ToArgType)) {
+ // Okay, the types match exactly. Nothing to do.
+ } else if (isObjCPointerConversion(FromArgType, ToArgType,
+ ConvertedType, IncompatibleObjC)) {
+ // Okay, we have an Objective-C pointer conversion.
+ HasObjCConversion = true;
+ } else {
+ // Argument types are too different. Abort.
+ return false;
+ }
+ }
+
+ if (HasObjCConversion) {
+ // We had an Objective-C conversion. Allow this pointer
+ // conversion, but complain about it.
+ ConvertedType = ToType;
+ IncompatibleObjC = true;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/// CheckPointerConversion - Check the pointer conversion from the
+/// expression From to the type ToType. This routine checks for
+/// ambiguous (FIXME: or inaccessible) derived-to-base pointer
+/// conversions for which IsPointerConversion has already returned
+/// true. It returns true and produces a diagnostic if there was an
+/// error, or returns false otherwise.
+bool Sema::CheckPointerConversion(Expr *From, QualType ToType) {
+ QualType FromType = From->getType();
+
+ if (const PointerType *FromPtrType = FromType->getAsPointerType())
+ if (const PointerType *ToPtrType = ToType->getAsPointerType()) {
+ QualType FromPointeeType = FromPtrType->getPointeeType(),
+ ToPointeeType = ToPtrType->getPointeeType();
+
+ // Objective-C++ conversions are always okay.
+ // FIXME: We should have a different class of conversions for the
+ // Objective-C++ implicit conversions.
+ if (Context.isObjCIdStructType(FromPointeeType) ||
+ Context.isObjCIdStructType(ToPointeeType) ||
+ Context.isObjCClassStructType(FromPointeeType) ||
+ Context.isObjCClassStructType(ToPointeeType))
+ return false;
+
+ if (FromPointeeType->isRecordType() &&
+ ToPointeeType->isRecordType()) {
+ // We must have a derived-to-base conversion. Check an
+ // ambiguous or inaccessible conversion.
+ return CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType,
+ From->getExprLoc(),
+ From->getSourceRange());
+ }
+ }
+
+ return false;
+}
+
+/// IsMemberPointerConversion - Determines whether the conversion of the
+/// expression From, which has the (possibly adjusted) type FromType, can be
+/// converted to the type ToType via a member pointer conversion (C++ 4.11).
+/// If so, returns true and places the converted type (that might differ from
+/// ToType in its cv-qualifiers at some level) into ConvertedType.
+bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType,
+ QualType ToType, QualType &ConvertedType)
+{
+ const MemberPointerType *ToTypePtr = ToType->getAsMemberPointerType();
+ if (!ToTypePtr)
+ return false;
+
+ // A null pointer constant can be converted to a member pointer (C++ 4.11p1)
+ if (From->isNullPointerConstant(Context)) {
+ ConvertedType = ToType;
+ return true;
+ }
+
+ // Otherwise, both types have to be member pointers.
+ const MemberPointerType *FromTypePtr = FromType->getAsMemberPointerType();
+ if (!FromTypePtr)
+ return false;
+
+ // A pointer to member of B can be converted to a pointer to member of D,
+ // where D is derived from B (C++ 4.11p2).
+ QualType FromClass(FromTypePtr->getClass(), 0);
+ QualType ToClass(ToTypePtr->getClass(), 0);
+ // FIXME: What happens when these are dependent? Is this function even called?
+
+ if (IsDerivedFrom(ToClass, FromClass)) {
+ ConvertedType = Context.getMemberPointerType(FromTypePtr->getPointeeType(),
+ ToClass.getTypePtr());
+ return true;
+ }
+
+ return false;
+}
+
+/// CheckMemberPointerConversion - Check the member pointer conversion from the
+/// expression From to the type ToType. This routine checks for ambiguous or
+/// virtual (FIXME: or inaccessible) base-to-derived member pointer conversions
+/// for which IsMemberPointerConversion has already returned true. It returns
+/// true and produces a diagnostic if there was an error, or returns false
+/// otherwise.
+bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType) {
+ QualType FromType = From->getType();
+ const MemberPointerType *FromPtrType = FromType->getAsMemberPointerType();
+ if (!FromPtrType)
+ return false;
+
+ const MemberPointerType *ToPtrType = ToType->getAsMemberPointerType();
+ assert(ToPtrType && "No member pointer cast has a target type "
+ "that is not a member pointer.");
+
+ QualType FromClass = QualType(FromPtrType->getClass(), 0);
+ QualType ToClass = QualType(ToPtrType->getClass(), 0);
+
+ // FIXME: What about dependent types?
+ assert(FromClass->isRecordType() && "Pointer into non-class.");
+ assert(ToClass->isRecordType() && "Pointer into non-class.");
+
+ BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+ /*DetectVirtual=*/true);
+ bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths);
+ assert(DerivationOkay &&
+ "Should not have been called if derivation isn't OK.");
+ (void)DerivationOkay;
+
+ if (Paths.isAmbiguous(Context.getCanonicalType(FromClass).
+ getUnqualifiedType())) {
+ // Derivation is ambiguous. Redo the check to find the exact paths.
+ Paths.clear();
+ Paths.setRecordingPaths(true);
+ bool StillOkay = IsDerivedFrom(ToClass, FromClass, Paths);
+ assert(StillOkay && "Derivation changed due to quantum fluctuation.");
+ (void)StillOkay;
+
+ std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths);
+ Diag(From->getExprLoc(), diag::err_ambiguous_memptr_conv)
+ << 0 << FromClass << ToClass << PathDisplayStr << From->getSourceRange();
+ return true;
+ }
+
+ if (const RecordType *VBase = Paths.getDetectedVirtual()) {
+ Diag(From->getExprLoc(), diag::err_memptr_conv_via_virtual)
+ << FromClass << ToClass << QualType(VBase, 0)
+ << From->getSourceRange();
+ return true;
+ }
+
+ return false;
+}
+
+/// IsQualificationConversion - Determines whether the conversion from
+/// an rvalue of type FromType to ToType is a qualification conversion
+/// (C++ 4.4).
+bool
+Sema::IsQualificationConversion(QualType FromType, QualType ToType)
+{
+ FromType = Context.getCanonicalType(FromType);
+ ToType = Context.getCanonicalType(ToType);
+
+ // If FromType and ToType are the same type, this is not a
+ // qualification conversion.
+ if (FromType == ToType)
+ return false;
+
+ // (C++ 4.4p4):
+ // A conversion can add cv-qualifiers at levels other than the first
+ // in multi-level pointers, subject to the following rules: [...]
+ bool PreviousToQualsIncludeConst = true;
+ bool UnwrappedAnyPointer = false;
+ while (UnwrapSimilarPointerTypes(FromType, ToType)) {
+ // Within each iteration of the loop, we check the qualifiers to
+ // determine if this still looks like a qualification
+ // conversion. Then, if all is well, we unwrap one more level of
+ // pointers or pointers-to-members and do it all again
+ // until there are no more pointers or pointers-to-members left to
+ // unwrap.
+ UnwrappedAnyPointer = true;
+
+ // -- for every j > 0, if const is in cv 1,j then const is in cv
+ // 2,j, and similarly for volatile.
+ if (!ToType.isAtLeastAsQualifiedAs(FromType))
+ return false;
+
+ // -- if the cv 1,j and cv 2,j are different, then const is in
+ // every cv for 0 < k < j.
+ if (FromType.getCVRQualifiers() != ToType.getCVRQualifiers()
+ && !PreviousToQualsIncludeConst)
+ return false;
+
+ // Keep track of whether all prior cv-qualifiers in the "to" type
+ // include const.
+ PreviousToQualsIncludeConst
+ = PreviousToQualsIncludeConst && ToType.isConstQualified();
+ }
+
+ // We are left with FromType and ToType being the pointee types
+ // after unwrapping the original FromType and ToType the same number
+ // of types. If we unwrapped any pointers, and if FromType and
+ // ToType have the same unqualified type (since we checked
+ // qualifiers above), then this is a qualification conversion.
+ return UnwrappedAnyPointer &&
+ FromType.getUnqualifiedType() == ToType.getUnqualifiedType();
+}
+
+/// Determines whether there is a user-defined conversion sequence
+/// (C++ [over.ics.user]) that converts expression From to the type
+/// ToType. If such a conversion exists, User will contain the
+/// user-defined conversion sequence that performs such a conversion
+/// and this routine will return true. Otherwise, this routine returns
+/// false and User is unspecified.
+///
+/// \param AllowConversionFunctions true if the conversion should
+/// consider conversion functions at all. If false, only constructors
+/// will be considered.
+///
+/// \param AllowExplicit true if the conversion should consider C++0x
+/// "explicit" conversion functions as well as non-explicit conversion
+/// functions (C++0x [class.conv.fct]p2).
+///
+/// \param ForceRValue true if the expression should be treated as an rvalue
+/// for overload resolution.
+bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
+ UserDefinedConversionSequence& User,
+ bool AllowConversionFunctions,
+ bool AllowExplicit, bool ForceRValue)
+{
+ OverloadCandidateSet CandidateSet;
+ if (const RecordType *ToRecordType = ToType->getAsRecordType()) {
+ if (CXXRecordDecl *ToRecordDecl
+ = dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) {
+ // C++ [over.match.ctor]p1:
+ // When objects of class type are direct-initialized (8.5), or
+ // copy-initialized from an expression of the same or a
+ // derived class type (8.5), overload resolution selects the
+ // constructor. [...] For copy-initialization, the candidate
+ // functions are all the converting constructors (12.3.1) of
+ // that class. The argument list is the expression-list within
+ // the parentheses of the initializer.
+ DeclarationName ConstructorName
+ = Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(ToType).getUnqualifiedType());
+ DeclContext::lookup_iterator Con, ConEnd;
+ for (llvm::tie(Con, ConEnd)
+ = ToRecordDecl->lookup(Context, ConstructorName);
+ Con != ConEnd; ++Con) {
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
+ if (Constructor->isConvertingConstructor())
+ AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
+ /*SuppressUserConversions=*/true, ForceRValue);
+ }
+ }
+ }
+
+ if (!AllowConversionFunctions) {
+ // Don't allow any conversion functions to enter the overload set.
+ } else if (const RecordType *FromRecordType
+ = From->getType()->getAsRecordType()) {
+ if (CXXRecordDecl *FromRecordDecl
+ = dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) {
+ // Add all of the conversion functions as candidates.
+ // FIXME: Look for conversions in base classes!
+ OverloadedFunctionDecl *Conversions
+ = FromRecordDecl->getConversionFunctions();
+ for (OverloadedFunctionDecl::function_iterator Func
+ = Conversions->function_begin();
+ Func != Conversions->function_end(); ++Func) {
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+ if (AllowExplicit || !Conv->isExplicit())
+ AddConversionCandidate(Conv, From, ToType, CandidateSet);
+ }
+ }
+ }
+
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(CandidateSet, Best)) {
+ case OR_Success:
+ // Record the standard conversion we used and the conversion function.
+ if (CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(Best->Function)) {
+ // C++ [over.ics.user]p1:
+ // If the user-defined conversion is specified by a
+ // constructor (12.3.1), the initial standard conversion
+ // sequence converts the source type to the type required by
+ // the argument of the constructor.
+ //
+ // FIXME: What about ellipsis conversions?
+ QualType ThisType = Constructor->getThisType(Context);
+ User.Before = Best->Conversions[0].Standard;
+ User.ConversionFunction = Constructor;
+ User.After.setAsIdentityConversion();
+ User.After.FromTypePtr
+ = ThisType->getAsPointerType()->getPointeeType().getAsOpaquePtr();
+ User.After.ToTypePtr = ToType.getAsOpaquePtr();
+ return true;
+ } else if (CXXConversionDecl *Conversion
+ = dyn_cast<CXXConversionDecl>(Best->Function)) {
+ // C++ [over.ics.user]p1:
+ //
+ // [...] If the user-defined conversion is specified by a
+ // conversion function (12.3.2), the initial standard
+ // conversion sequence converts the source type to the
+ // implicit object parameter of the conversion function.
+ User.Before = Best->Conversions[0].Standard;
+ User.ConversionFunction = Conversion;
+
+ // C++ [over.ics.user]p2:
+ // The second standard conversion sequence converts the
+ // result of the user-defined conversion to the target type
+ // for the sequence. Since an implicit conversion sequence
+ // is an initialization, the special rules for
+ // initialization by user-defined conversion apply when
+ // selecting the best user-defined conversion for a
+ // user-defined conversion sequence (see 13.3.3 and
+ // 13.3.3.1).
+ User.After = Best->FinalConversion;
+ return true;
+ } else {
+ assert(false && "Not a constructor or conversion function?");
+ return false;
+ }
+
+ case OR_No_Viable_Function:
+ case OR_Deleted:
+ // No conversion here! We're done.
+ return false;
+
+ case OR_Ambiguous:
+ // FIXME: See C++ [over.best.ics]p10 for the handling of
+ // ambiguous conversion sequences.
+ return false;
+ }
+
+ return false;
+}
+
+/// CompareImplicitConversionSequences - Compare two implicit
+/// conversion sequences to determine whether one is better than the
+/// other or if they are indistinguishable (C++ 13.3.3.2).
+ImplicitConversionSequence::CompareKind
+Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
+ const ImplicitConversionSequence& ICS2)
+{
+ // (C++ 13.3.3.2p2): When comparing the basic forms of implicit
+ // conversion sequences (as defined in 13.3.3.1)
+ // -- a standard conversion sequence (13.3.3.1.1) is a better
+ // conversion sequence than a user-defined conversion sequence or
+ // an ellipsis conversion sequence, and
+ // -- a user-defined conversion sequence (13.3.3.1.2) is a better
+ // conversion sequence than an ellipsis conversion sequence
+ // (13.3.3.1.3).
+ //
+ if (ICS1.ConversionKind < ICS2.ConversionKind)
+ return ImplicitConversionSequence::Better;
+ else if (ICS2.ConversionKind < ICS1.ConversionKind)
+ return ImplicitConversionSequence::Worse;
+
+ // Two implicit conversion sequences of the same form are
+ // indistinguishable conversion sequences unless one of the
+ // following rules apply: (C++ 13.3.3.2p3):
+ if (ICS1.ConversionKind == ImplicitConversionSequence::StandardConversion)
+ return CompareStandardConversionSequences(ICS1.Standard, ICS2.Standard);
+ else if (ICS1.ConversionKind ==
+ ImplicitConversionSequence::UserDefinedConversion) {
+ // User-defined conversion sequence U1 is a better conversion
+ // sequence than another user-defined conversion sequence U2 if
+ // they contain the same user-defined conversion function or
+ // constructor and if the second standard conversion sequence of
+ // U1 is better than the second standard conversion sequence of
+ // U2 (C++ 13.3.3.2p3).
+ if (ICS1.UserDefined.ConversionFunction ==
+ ICS2.UserDefined.ConversionFunction)
+ return CompareStandardConversionSequences(ICS1.UserDefined.After,
+ ICS2.UserDefined.After);
+ }
+
+ return ImplicitConversionSequence::Indistinguishable;
+}
+
+/// CompareStandardConversionSequences - Compare two standard
+/// conversion sequences to determine whether one is better than the
+/// other or if they are indistinguishable (C++ 13.3.3.2p3).
+ImplicitConversionSequence::CompareKind
+Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
+ const StandardConversionSequence& SCS2)
+{
+ // Standard conversion sequence S1 is a better conversion sequence
+ // than standard conversion sequence S2 if (C++ 13.3.3.2p3):
+
+ // -- S1 is a proper subsequence of S2 (comparing the conversion
+ // sequences in the canonical form defined by 13.3.3.1.1,
+ // excluding any Lvalue Transformation; the identity conversion
+ // sequence is considered to be a subsequence of any
+ // non-identity conversion sequence) or, if not that,
+ if (SCS1.Second == SCS2.Second && SCS1.Third == SCS2.Third)
+ // Neither is a proper subsequence of the other. Do nothing.
+ ;
+ else if ((SCS1.Second == ICK_Identity && SCS1.Third == SCS2.Third) ||
+ (SCS1.Third == ICK_Identity && SCS1.Second == SCS2.Second) ||
+ (SCS1.Second == ICK_Identity &&
+ SCS1.Third == ICK_Identity))
+ // SCS1 is a proper subsequence of SCS2.
+ return ImplicitConversionSequence::Better;
+ else if ((SCS2.Second == ICK_Identity && SCS2.Third == SCS1.Third) ||
+ (SCS2.Third == ICK_Identity && SCS2.Second == SCS1.Second) ||
+ (SCS2.Second == ICK_Identity &&
+ SCS2.Third == ICK_Identity))
+ // SCS2 is a proper subsequence of SCS1.
+ return ImplicitConversionSequence::Worse;
+
+ // -- the rank of S1 is better than the rank of S2 (by the rules
+ // defined below), or, if not that,
+ ImplicitConversionRank Rank1 = SCS1.getRank();
+ ImplicitConversionRank Rank2 = SCS2.getRank();
+ if (Rank1 < Rank2)
+ return ImplicitConversionSequence::Better;
+ else if (Rank2 < Rank1)
+ return ImplicitConversionSequence::Worse;
+
+ // (C++ 13.3.3.2p4): Two conversion sequences with the same rank
+ // are indistinguishable unless one of the following rules
+ // applies:
+
+ // A conversion that is not a conversion of a pointer, or
+ // pointer to member, to bool is better than another conversion
+ // that is such a conversion.
+ if (SCS1.isPointerConversionToBool() != SCS2.isPointerConversionToBool())
+ return SCS2.isPointerConversionToBool()
+ ? ImplicitConversionSequence::Better
+ : ImplicitConversionSequence::Worse;
+
+ // C++ [over.ics.rank]p4b2:
+ //
+ // If class B is derived directly or indirectly from class A,
+ // conversion of B* to A* is better than conversion of B* to
+ // void*, and conversion of A* to void* is better than conversion
+ // of B* to void*.
+ bool SCS1ConvertsToVoid
+ = SCS1.isPointerConversionToVoidPointer(Context);
+ bool SCS2ConvertsToVoid
+ = SCS2.isPointerConversionToVoidPointer(Context);
+ if (SCS1ConvertsToVoid != SCS2ConvertsToVoid) {
+ // Exactly one of the conversion sequences is a conversion to
+ // a void pointer; it's the worse conversion.
+ return SCS2ConvertsToVoid ? ImplicitConversionSequence::Better
+ : ImplicitConversionSequence::Worse;
+ } else if (!SCS1ConvertsToVoid && !SCS2ConvertsToVoid) {
+ // Neither conversion sequence converts to a void pointer; compare
+ // their derived-to-base conversions.
+ if (ImplicitConversionSequence::CompareKind DerivedCK
+ = CompareDerivedToBaseConversions(SCS1, SCS2))
+ return DerivedCK;
+ } else if (SCS1ConvertsToVoid && SCS2ConvertsToVoid) {
+ // Both conversion sequences are conversions to void
+ // pointers. Compare the source types to determine if there's an
+ // inheritance relationship in their sources.
+ QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr);
+ QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr);
+
+ // Adjust the types we're converting from via the array-to-pointer
+ // conversion, if we need to.
+ if (SCS1.First == ICK_Array_To_Pointer)
+ FromType1 = Context.getArrayDecayedType(FromType1);
+ if (SCS2.First == ICK_Array_To_Pointer)
+ FromType2 = Context.getArrayDecayedType(FromType2);
+
+ QualType FromPointee1
+ = FromType1->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ QualType FromPointee2
+ = FromType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
+
+ if (IsDerivedFrom(FromPointee2, FromPointee1))
+ return ImplicitConversionSequence::Better;
+ else if (IsDerivedFrom(FromPointee1, FromPointee2))
+ return ImplicitConversionSequence::Worse;
+
+ // Objective-C++: If one interface is more specific than the
+ // other, it is the better one.
+ const ObjCInterfaceType* FromIface1 = FromPointee1->getAsObjCInterfaceType();
+ const ObjCInterfaceType* FromIface2 = FromPointee2->getAsObjCInterfaceType();
+ if (FromIface1 && FromIface1) {
+ if (Context.canAssignObjCInterfaces(FromIface2, FromIface1))
+ return ImplicitConversionSequence::Better;
+ else if (Context.canAssignObjCInterfaces(FromIface1, FromIface2))
+ return ImplicitConversionSequence::Worse;
+ }
+ }
+
+ // Compare based on qualification conversions (C++ 13.3.3.2p3,
+ // bullet 3).
+ if (ImplicitConversionSequence::CompareKind QualCK
+ = CompareQualificationConversions(SCS1, SCS2))
+ return QualCK;
+
+ if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) {
+ // C++0x [over.ics.rank]p3b4:
+ // -- S1 and S2 are reference bindings (8.5.3) and neither refers to an
+ // implicit object parameter of a non-static member function declared
+ // without a ref-qualifier, and S1 binds an rvalue reference to an
+ // rvalue and S2 binds an lvalue reference.
+ // FIXME: We don't know if we're dealing with the implicit object parameter,
+ // or if the member function in this case has a ref qualifier.
+ // (Of course, we don't have ref qualifiers yet.)
+ if (SCS1.RRefBinding != SCS2.RRefBinding)
+ return SCS1.RRefBinding ? ImplicitConversionSequence::Better
+ : ImplicitConversionSequence::Worse;
+
+ // C++ [over.ics.rank]p3b4:
+ // -- S1 and S2 are reference bindings (8.5.3), and the types to
+ // which the references refer are the same type except for
+ // top-level cv-qualifiers, and the type to which the reference
+ // initialized by S2 refers is more cv-qualified than the type
+ // to which the reference initialized by S1 refers.
+ QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr);
+ QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
+ T1 = Context.getCanonicalType(T1);
+ T2 = Context.getCanonicalType(T2);
+ if (T1.getUnqualifiedType() == T2.getUnqualifiedType()) {
+ if (T2.isMoreQualifiedThan(T1))
+ return ImplicitConversionSequence::Better;
+ else if (T1.isMoreQualifiedThan(T2))
+ return ImplicitConversionSequence::Worse;
+ }
+ }
+
+ return ImplicitConversionSequence::Indistinguishable;
+}
+
+/// CompareQualificationConversions - Compares two standard conversion
+/// sequences to determine whether they can be ranked based on their
+/// qualification conversions (C++ 13.3.3.2p3 bullet 3).
+ImplicitConversionSequence::CompareKind
+Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
+ const StandardConversionSequence& SCS2)
+{
+ // C++ 13.3.3.2p3:
+ // -- S1 and S2 differ only in their qualification conversion and
+ // yield similar types T1 and T2 (C++ 4.4), respectively, and the
+ // cv-qualification signature of type T1 is a proper subset of
+ // the cv-qualification signature of type T2, and S1 is not the
+ // deprecated string literal array-to-pointer conversion (4.2).
+ if (SCS1.First != SCS2.First || SCS1.Second != SCS2.Second ||
+ SCS1.Third != SCS2.Third || SCS1.Third != ICK_Qualification)
+ return ImplicitConversionSequence::Indistinguishable;
+
+ // FIXME: the example in the standard doesn't use a qualification
+ // conversion (!)
+ QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr);
+ QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
+ T1 = Context.getCanonicalType(T1);
+ T2 = Context.getCanonicalType(T2);
+
+ // If the types are the same, we won't learn anything by unwrapped
+ // them.
+ if (T1.getUnqualifiedType() == T2.getUnqualifiedType())
+ return ImplicitConversionSequence::Indistinguishable;
+
+ ImplicitConversionSequence::CompareKind Result
+ = ImplicitConversionSequence::Indistinguishable;
+ while (UnwrapSimilarPointerTypes(T1, T2)) {
+ // Within each iteration of the loop, we check the qualifiers to
+ // determine if this still looks like a qualification
+ // conversion. Then, if all is well, we unwrap one more level of
+ // pointers or pointers-to-members and do it all again
+ // until there are no more pointers or pointers-to-members left
+ // to unwrap. This essentially mimics what
+ // IsQualificationConversion does, but here we're checking for a
+ // strict subset of qualifiers.
+ if (T1.getCVRQualifiers() == T2.getCVRQualifiers())
+ // The qualifiers are the same, so this doesn't tell us anything
+ // about how the sequences rank.
+ ;
+ else if (T2.isMoreQualifiedThan(T1)) {
+ // T1 has fewer qualifiers, so it could be the better sequence.
+ if (Result == ImplicitConversionSequence::Worse)
+ // Neither has qualifiers that are a subset of the other's
+ // qualifiers.
+ return ImplicitConversionSequence::Indistinguishable;
+
+ Result = ImplicitConversionSequence::Better;
+ } else if (T1.isMoreQualifiedThan(T2)) {
+ // T2 has fewer qualifiers, so it could be the better sequence.
+ if (Result == ImplicitConversionSequence::Better)
+ // Neither has qualifiers that are a subset of the other's
+ // qualifiers.
+ return ImplicitConversionSequence::Indistinguishable;
+
+ Result = ImplicitConversionSequence::Worse;
+ } else {
+ // Qualifiers are disjoint.
+ return ImplicitConversionSequence::Indistinguishable;
+ }
+
+ // If the types after this point are equivalent, we're done.
+ if (T1.getUnqualifiedType() == T2.getUnqualifiedType())
+ break;
+ }
+
+ // Check that the winning standard conversion sequence isn't using
+ // the deprecated string literal array to pointer conversion.
+ switch (Result) {
+ case ImplicitConversionSequence::Better:
+ if (SCS1.Deprecated)
+ Result = ImplicitConversionSequence::Indistinguishable;
+ break;
+
+ case ImplicitConversionSequence::Indistinguishable:
+ break;
+
+ case ImplicitConversionSequence::Worse:
+ if (SCS2.Deprecated)
+ Result = ImplicitConversionSequence::Indistinguishable;
+ break;
+ }
+
+ return Result;
+}
+
+/// CompareDerivedToBaseConversions - Compares two standard conversion
+/// sequences to determine whether they can be ranked based on their
+/// various kinds of derived-to-base conversions (C++
+/// [over.ics.rank]p4b3). As part of these checks, we also look at
+/// conversions between Objective-C interface types.
+ImplicitConversionSequence::CompareKind
+Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
+ const StandardConversionSequence& SCS2) {
+ QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr);
+ QualType ToType1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr);
+ QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr);
+ QualType ToType2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
+
+ // Adjust the types we're converting from via the array-to-pointer
+ // conversion, if we need to.
+ if (SCS1.First == ICK_Array_To_Pointer)
+ FromType1 = Context.getArrayDecayedType(FromType1);
+ if (SCS2.First == ICK_Array_To_Pointer)
+ FromType2 = Context.getArrayDecayedType(FromType2);
+
+ // Canonicalize all of the types.
+ FromType1 = Context.getCanonicalType(FromType1);
+ ToType1 = Context.getCanonicalType(ToType1);
+ FromType2 = Context.getCanonicalType(FromType2);
+ ToType2 = Context.getCanonicalType(ToType2);
+
+ // C++ [over.ics.rank]p4b3:
+ //
+ // If class B is derived directly or indirectly from class A and
+ // class C is derived directly or indirectly from B,
+ //
+ // For Objective-C, we let A, B, and C also be Objective-C
+ // interfaces.
+
+ // Compare based on pointer conversions.
+ if (SCS1.Second == ICK_Pointer_Conversion &&
+ SCS2.Second == ICK_Pointer_Conversion &&
+ /*FIXME: Remove if Objective-C id conversions get their own rank*/
+ FromType1->isPointerType() && FromType2->isPointerType() &&
+ ToType1->isPointerType() && ToType2->isPointerType()) {
+ QualType FromPointee1
+ = FromType1->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ QualType ToPointee1
+ = ToType1->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ QualType FromPointee2
+ = FromType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
+ QualType ToPointee2
+ = ToType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
+
+ const ObjCInterfaceType* FromIface1 = FromPointee1->getAsObjCInterfaceType();
+ const ObjCInterfaceType* FromIface2 = FromPointee2->getAsObjCInterfaceType();
+ const ObjCInterfaceType* ToIface1 = ToPointee1->getAsObjCInterfaceType();
+ const ObjCInterfaceType* ToIface2 = ToPointee2->getAsObjCInterfaceType();
+
+ // -- conversion of C* to B* is better than conversion of C* to A*,
+ if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) {
+ if (IsDerivedFrom(ToPointee1, ToPointee2))
+ return ImplicitConversionSequence::Better;
+ else if (IsDerivedFrom(ToPointee2, ToPointee1))
+ return ImplicitConversionSequence::Worse;
+
+ if (ToIface1 && ToIface2) {
+ if (Context.canAssignObjCInterfaces(ToIface2, ToIface1))
+ return ImplicitConversionSequence::Better;
+ else if (Context.canAssignObjCInterfaces(ToIface1, ToIface2))
+ return ImplicitConversionSequence::Worse;
+ }
+ }
+
+ // -- conversion of B* to A* is better than conversion of C* to A*,
+ if (FromPointee1 != FromPointee2 && ToPointee1 == ToPointee2) {
+ if (IsDerivedFrom(FromPointee2, FromPointee1))
+ return ImplicitConversionSequence::Better;
+ else if (IsDerivedFrom(FromPointee1, FromPointee2))
+ return ImplicitConversionSequence::Worse;
+
+ if (FromIface1 && FromIface2) {
+ if (Context.canAssignObjCInterfaces(FromIface1, FromIface2))
+ return ImplicitConversionSequence::Better;
+ else if (Context.canAssignObjCInterfaces(FromIface2, FromIface1))
+ return ImplicitConversionSequence::Worse;
+ }
+ }
+ }
+
+ // Compare based on reference bindings.
+ if (SCS1.ReferenceBinding && SCS2.ReferenceBinding &&
+ SCS1.Second == ICK_Derived_To_Base) {
+ // -- binding of an expression of type C to a reference of type
+ // B& is better than binding an expression of type C to a
+ // reference of type A&,
+ if (FromType1.getUnqualifiedType() == FromType2.getUnqualifiedType() &&
+ ToType1.getUnqualifiedType() != ToType2.getUnqualifiedType()) {
+ if (IsDerivedFrom(ToType1, ToType2))
+ return ImplicitConversionSequence::Better;
+ else if (IsDerivedFrom(ToType2, ToType1))
+ return ImplicitConversionSequence::Worse;
+ }
+
+ // -- binding of an expression of type B to a reference of type
+ // A& is better than binding an expression of type C to a
+ // reference of type A&,
+ if (FromType1.getUnqualifiedType() != FromType2.getUnqualifiedType() &&
+ ToType1.getUnqualifiedType() == ToType2.getUnqualifiedType()) {
+ if (IsDerivedFrom(FromType2, FromType1))
+ return ImplicitConversionSequence::Better;
+ else if (IsDerivedFrom(FromType1, FromType2))
+ return ImplicitConversionSequence::Worse;
+ }
+ }
+
+
+ // FIXME: conversion of A::* to B::* is better than conversion of
+ // A::* to C::*,
+
+ // FIXME: conversion of B::* to C::* is better than conversion of
+ // A::* to C::*, and
+
+ if (SCS1.CopyConstructor && SCS2.CopyConstructor &&
+ SCS1.Second == ICK_Derived_To_Base) {
+ // -- conversion of C to B is better than conversion of C to A,
+ if (FromType1.getUnqualifiedType() == FromType2.getUnqualifiedType() &&
+ ToType1.getUnqualifiedType() != ToType2.getUnqualifiedType()) {
+ if (IsDerivedFrom(ToType1, ToType2))
+ return ImplicitConversionSequence::Better;
+ else if (IsDerivedFrom(ToType2, ToType1))
+ return ImplicitConversionSequence::Worse;
+ }
+
+ // -- conversion of B to A is better than conversion of C to A.
+ if (FromType1.getUnqualifiedType() != FromType2.getUnqualifiedType() &&
+ ToType1.getUnqualifiedType() == ToType2.getUnqualifiedType()) {
+ if (IsDerivedFrom(FromType2, FromType1))
+ return ImplicitConversionSequence::Better;
+ else if (IsDerivedFrom(FromType1, FromType2))
+ return ImplicitConversionSequence::Worse;
+ }
+ }
+
+ return ImplicitConversionSequence::Indistinguishable;
+}
+
+/// TryCopyInitialization - Try to copy-initialize a value of type
+/// ToType from the expression From. Return the implicit conversion
+/// sequence required to pass this argument, which may be a bad
+/// conversion sequence (meaning that the argument cannot be passed to
+/// a parameter of this type). If @p SuppressUserConversions, then we
+/// do not permit any user-defined conversion sequences. If @p ForceRValue,
+/// then we treat @p From as an rvalue, even if it is an lvalue.
+ImplicitConversionSequence
+Sema::TryCopyInitialization(Expr *From, QualType ToType,
+ bool SuppressUserConversions, bool ForceRValue) {
+ if (ToType->isReferenceType()) {
+ ImplicitConversionSequence ICS;
+ CheckReferenceInit(From, ToType, &ICS, SuppressUserConversions,
+ /*AllowExplicit=*/false, ForceRValue);
+ return ICS;
+ } else {
+ return TryImplicitConversion(From, ToType, SuppressUserConversions,
+ ForceRValue);
+ }
+}
+
+/// PerformCopyInitialization - Copy-initialize an object of type @p ToType with
+/// the expression @p From. Returns true (and emits a diagnostic) if there was
+/// an error, returns false if the initialization succeeded. Elidable should
+/// be true when the copy may be elided (C++ 12.8p15). Overload resolution works
+/// differently in C++0x for this case.
+bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
+ const char* Flavor, bool Elidable) {
+ if (!getLangOptions().CPlusPlus) {
+ // In C, argument passing is the same as performing an assignment.
+ QualType FromType = From->getType();
+
+ AssignConvertType ConvTy =
+ CheckSingleAssignmentConstraints(ToType, From);
+ if (ConvTy != Compatible &&
+ CheckTransparentUnionArgumentConstraints(ToType, From) == Compatible)
+ ConvTy = Compatible;
+
+ return DiagnoseAssignmentResult(ConvTy, From->getLocStart(), ToType,
+ FromType, From, Flavor);
+ }
+
+ if (ToType->isReferenceType())
+ return CheckReferenceInit(From, ToType);
+
+ if (!PerformImplicitConversion(From, ToType, Flavor,
+ /*AllowExplicit=*/false, Elidable))
+ return false;
+
+ return Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_convert_incompatible)
+ << ToType << From->getType() << Flavor << From->getSourceRange();
+}
+
+/// TryObjectArgumentInitialization - Try to initialize the object
+/// parameter of the given member function (@c Method) from the
+/// expression @p From.
+ImplicitConversionSequence
+Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) {
+ QualType ClassType = Context.getTypeDeclType(Method->getParent());
+ unsigned MethodQuals = Method->getTypeQualifiers();
+ QualType ImplicitParamType = ClassType.getQualifiedType(MethodQuals);
+
+ // Set up the conversion sequence as a "bad" conversion, to allow us
+ // to exit early.
+ ImplicitConversionSequence ICS;
+ ICS.Standard.setAsIdentityConversion();
+ ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+
+ // We need to have an object of class type.
+ QualType FromType = From->getType();
+ if (const PointerType *PT = FromType->getAsPointerType())
+ FromType = PT->getPointeeType();
+
+ assert(FromType->isRecordType());
+
+ // The implicit object parmeter is has the type "reference to cv X",
+ // where X is the class of which the function is a member
+ // (C++ [over.match.funcs]p4). However, when finding an implicit
+ // conversion sequence for the argument, we are not allowed to
+ // create temporaries or perform user-defined conversions
+ // (C++ [over.match.funcs]p5). We perform a simplified version of
+ // reference binding here, that allows class rvalues to bind to
+ // non-constant references.
+
+ // First check the qualifiers. We don't care about lvalue-vs-rvalue
+ // with the implicit object parameter (C++ [over.match.funcs]p5).
+ QualType FromTypeCanon = Context.getCanonicalType(FromType);
+ if (ImplicitParamType.getCVRQualifiers() != FromType.getCVRQualifiers() &&
+ !ImplicitParamType.isAtLeastAsQualifiedAs(FromType))
+ return ICS;
+
+ // Check that we have either the same type or a derived type. It
+ // affects the conversion rank.
+ QualType ClassTypeCanon = Context.getCanonicalType(ClassType);
+ if (ClassTypeCanon == FromTypeCanon.getUnqualifiedType())
+ ICS.Standard.Second = ICK_Identity;
+ else if (IsDerivedFrom(FromType, ClassType))
+ ICS.Standard.Second = ICK_Derived_To_Base;
+ else
+ return ICS;
+
+ // Success. Mark this as a reference binding.
+ ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
+ ICS.Standard.FromTypePtr = FromType.getAsOpaquePtr();
+ ICS.Standard.ToTypePtr = ImplicitParamType.getAsOpaquePtr();
+ ICS.Standard.ReferenceBinding = true;
+ ICS.Standard.DirectBinding = true;
+ ICS.Standard.RRefBinding = false;
+ return ICS;
+}
+
+/// PerformObjectArgumentInitialization - Perform initialization of
+/// the implicit object parameter for the given Method with the given
+/// expression.
+bool
+Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) {
+ QualType FromRecordType, DestType;
+ QualType ImplicitParamRecordType =
+ Method->getThisType(Context)->getAsPointerType()->getPointeeType();
+
+ if (const PointerType *PT = From->getType()->getAsPointerType()) {
+ FromRecordType = PT->getPointeeType();
+ DestType = Method->getThisType(Context);
+ } else {
+ FromRecordType = From->getType();
+ DestType = ImplicitParamRecordType;
+ }
+
+ ImplicitConversionSequence ICS
+ = TryObjectArgumentInitialization(From, Method);
+ if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion)
+ return Diag(From->getSourceRange().getBegin(),
+ diag::err_implicit_object_parameter_init)
+ << ImplicitParamRecordType << FromRecordType << From->getSourceRange();
+
+ if (ICS.Standard.Second == ICK_Derived_To_Base &&
+ CheckDerivedToBaseConversion(FromRecordType,
+ ImplicitParamRecordType,
+ From->getSourceRange().getBegin(),
+ From->getSourceRange()))
+ return true;
+
+ ImpCastExprToType(From, DestType, /*isLvalue=*/true);
+ return false;
+}
+
+/// TryContextuallyConvertToBool - Attempt to contextually convert the
+/// expression From to bool (C++0x [conv]p3).
+ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) {
+ return TryImplicitConversion(From, Context.BoolTy, false, true);
+}
+
+/// PerformContextuallyConvertToBool - Perform a contextual conversion
+/// of the expression From to bool (C++0x [conv]p3).
+bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
+ ImplicitConversionSequence ICS = TryContextuallyConvertToBool(From);
+ if (!PerformImplicitConversion(From, Context.BoolTy, ICS, "converting"))
+ return false;
+
+ return Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_bool_condition)
+ << From->getType() << From->getSourceRange();
+}
+
+/// AddOverloadCandidate - Adds the given function to the set of
+/// candidate functions, using the given function call arguments. If
+/// @p SuppressUserConversions, then don't allow user-defined
+/// conversions via constructors or conversion operators.
+/// If @p ForceRValue, treat all arguments as rvalues. This is a slightly
+/// hacky way to implement the overloading rules for elidable copy
+/// initialization in C++0x (C++0x 12.8p15).
+void
+Sema::AddOverloadCandidate(FunctionDecl *Function,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversions,
+ bool ForceRValue)
+{
+ const FunctionProtoType* Proto
+ = dyn_cast<FunctionProtoType>(Function->getType()->getAsFunctionType());
+ assert(Proto && "Functions without a prototype cannot be overloaded");
+ assert(!isa<CXXConversionDecl>(Function) &&
+ "Use AddConversionCandidate for conversion functions");
+
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
+ if (!isa<CXXConstructorDecl>(Method)) {
+ // If we get here, it's because we're calling a member function
+ // that is named without a member access expression (e.g.,
+ // "this->f") that was either written explicitly or created
+ // implicitly. This can happen with a qualified call to a member
+ // function, e.g., X::f(). We use a NULL object as the implied
+ // object argument (C++ [over.call.func]p3).
+ AddMethodCandidate(Method, 0, Args, NumArgs, CandidateSet,
+ SuppressUserConversions, ForceRValue);
+ return;
+ }
+ // We treat a constructor like a non-member function, since its object
+ // argument doesn't participate in overload resolution.
+ }
+
+
+ // Add this candidate
+ CandidateSet.push_back(OverloadCandidate());
+ OverloadCandidate& Candidate = CandidateSet.back();
+ Candidate.Function = Function;
+ Candidate.Viable = true;
+ Candidate.IsSurrogate = false;
+ Candidate.IgnoreObjectArgument = false;
+
+ unsigned NumArgsInProto = Proto->getNumArgs();
+
+ // (C++ 13.3.2p2): A candidate function having fewer than m
+ // parameters is viable only if it has an ellipsis in its parameter
+ // list (8.3.5).
+ if (NumArgs > NumArgsInProto && !Proto->isVariadic()) {
+ Candidate.Viable = false;
+ return;
+ }
+
+ // (C++ 13.3.2p2): A candidate function having more than m parameters
+ // is viable only if the (m+1)st parameter has a default argument
+ // (8.3.6). For the purposes of overload resolution, the
+ // parameter list is truncated on the right, so that there are
+ // exactly m parameters.
+ unsigned MinRequiredArgs = Function->getMinRequiredArguments();
+ if (NumArgs < MinRequiredArgs) {
+ // Not enough arguments.
+ Candidate.Viable = false;
+ return;
+ }
+
+ // Determine the implicit conversion sequences for each of the
+ // arguments.
+ Candidate.Conversions.resize(NumArgs);
+ for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
+ if (ArgIdx < NumArgsInProto) {
+ // (C++ 13.3.2p3): for F to be a viable function, there shall
+ // exist for each argument an implicit conversion sequence
+ // (13.3.3.1) that converts that argument to the corresponding
+ // parameter of F.
+ QualType ParamType = Proto->getArgType(ArgIdx);
+ Candidate.Conversions[ArgIdx]
+ = TryCopyInitialization(Args[ArgIdx], ParamType,
+ SuppressUserConversions, ForceRValue);
+ if (Candidate.Conversions[ArgIdx].ConversionKind
+ == ImplicitConversionSequence::BadConversion) {
+ Candidate.Viable = false;
+ break;
+ }
+ } else {
+ // (C++ 13.3.2p2): For the purposes of overload resolution, any
+ // argument for which there is no corresponding parameter is
+ // considered to ""match the ellipsis" (C+ 13.3.3.1.3).
+ Candidate.Conversions[ArgIdx].ConversionKind
+ = ImplicitConversionSequence::EllipsisConversion;
+ }
+ }
+}
+
+/// \brief Add all of the function declarations in the given function set to
+/// the overload canddiate set.
+void Sema::AddFunctionCandidates(const FunctionSet &Functions,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversions) {
+ for (FunctionSet::const_iterator F = Functions.begin(),
+ FEnd = Functions.end();
+ F != FEnd; ++F)
+ AddOverloadCandidate(*F, Args, NumArgs, CandidateSet,
+ SuppressUserConversions);
+}
+
+/// AddMethodCandidate - Adds the given C++ member function to the set
+/// of candidate functions, using the given function call arguments
+/// and the object argument (@c Object). For example, in a call
+/// @c o.f(a1,a2), @c Object will contain @c o and @c Args will contain
+/// both @c a1 and @c a2. If @p SuppressUserConversions, then don't
+/// allow user-defined conversions via constructors or conversion
+/// operators. If @p ForceRValue, treat all arguments as rvalues. This is
+/// a slightly hacky way to implement the overloading rules for elidable copy
+/// initialization in C++0x (C++0x 12.8p15).
+void
+Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversions, bool ForceRValue)
+{
+ const FunctionProtoType* Proto
+ = dyn_cast<FunctionProtoType>(Method->getType()->getAsFunctionType());
+ assert(Proto && "Methods without a prototype cannot be overloaded");
+ assert(!isa<CXXConversionDecl>(Method) &&
+ "Use AddConversionCandidate for conversion functions");
+ assert(!isa<CXXConstructorDecl>(Method) &&
+ "Use AddOverloadCandidate for constructors");
+
+ // Add this candidate
+ CandidateSet.push_back(OverloadCandidate());
+ OverloadCandidate& Candidate = CandidateSet.back();
+ Candidate.Function = Method;
+ Candidate.IsSurrogate = false;
+ Candidate.IgnoreObjectArgument = false;
+
+ unsigned NumArgsInProto = Proto->getNumArgs();
+
+ // (C++ 13.3.2p2): A candidate function having fewer than m
+ // parameters is viable only if it has an ellipsis in its parameter
+ // list (8.3.5).
+ if (NumArgs > NumArgsInProto && !Proto->isVariadic()) {
+ Candidate.Viable = false;
+ return;
+ }
+
+ // (C++ 13.3.2p2): A candidate function having more than m parameters
+ // is viable only if the (m+1)st parameter has a default argument
+ // (8.3.6). For the purposes of overload resolution, the
+ // parameter list is truncated on the right, so that there are
+ // exactly m parameters.
+ unsigned MinRequiredArgs = Method->getMinRequiredArguments();
+ if (NumArgs < MinRequiredArgs) {
+ // Not enough arguments.
+ Candidate.Viable = false;
+ return;
+ }
+
+ Candidate.Viable = true;
+ Candidate.Conversions.resize(NumArgs + 1);
+
+ if (Method->isStatic() || !Object)
+ // The implicit object argument is ignored.
+ Candidate.IgnoreObjectArgument = true;
+ else {
+ // Determine the implicit conversion sequence for the object
+ // parameter.
+ Candidate.Conversions[0] = TryObjectArgumentInitialization(Object, Method);
+ if (Candidate.Conversions[0].ConversionKind
+ == ImplicitConversionSequence::BadConversion) {
+ Candidate.Viable = false;
+ return;
+ }
+ }
+
+ // Determine the implicit conversion sequences for each of the
+ // arguments.
+ for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
+ if (ArgIdx < NumArgsInProto) {
+ // (C++ 13.3.2p3): for F to be a viable function, there shall
+ // exist for each argument an implicit conversion sequence
+ // (13.3.3.1) that converts that argument to the corresponding
+ // parameter of F.
+ QualType ParamType = Proto->getArgType(ArgIdx);
+ Candidate.Conversions[ArgIdx + 1]
+ = TryCopyInitialization(Args[ArgIdx], ParamType,
+ SuppressUserConversions, ForceRValue);
+ if (Candidate.Conversions[ArgIdx + 1].ConversionKind
+ == ImplicitConversionSequence::BadConversion) {
+ Candidate.Viable = false;
+ break;
+ }
+ } else {
+ // (C++ 13.3.2p2): For the purposes of overload resolution, any
+ // argument for which there is no corresponding parameter is
+ // considered to ""match the ellipsis" (C+ 13.3.3.1.3).
+ Candidate.Conversions[ArgIdx + 1].ConversionKind
+ = ImplicitConversionSequence::EllipsisConversion;
+ }
+ }
+}
+
+/// AddConversionCandidate - Add a C++ conversion function as a
+/// candidate in the candidate set (C++ [over.match.conv],
+/// C++ [over.match.copy]). From is the expression we're converting from,
+/// and ToType is the type that we're eventually trying to convert to
+/// (which may or may not be the same type as the type that the
+/// conversion function produces).
+void
+Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
+ Expr *From, QualType ToType,
+ OverloadCandidateSet& CandidateSet) {
+ // Add this candidate
+ CandidateSet.push_back(OverloadCandidate());
+ OverloadCandidate& Candidate = CandidateSet.back();
+ Candidate.Function = Conversion;
+ Candidate.IsSurrogate = false;
+ Candidate.IgnoreObjectArgument = false;
+ Candidate.FinalConversion.setAsIdentityConversion();
+ Candidate.FinalConversion.FromTypePtr
+ = Conversion->getConversionType().getAsOpaquePtr();
+ Candidate.FinalConversion.ToTypePtr = ToType.getAsOpaquePtr();
+
+ // Determine the implicit conversion sequence for the implicit
+ // object parameter.
+ Candidate.Viable = true;
+ Candidate.Conversions.resize(1);
+ Candidate.Conversions[0] = TryObjectArgumentInitialization(From, Conversion);
+
+ if (Candidate.Conversions[0].ConversionKind
+ == ImplicitConversionSequence::BadConversion) {
+ Candidate.Viable = false;
+ return;
+ }
+
+ // To determine what the conversion from the result of calling the
+ // conversion function to the type we're eventually trying to
+ // convert to (ToType), we need to synthesize a call to the
+ // conversion function and attempt copy initialization from it. This
+ // makes sure that we get the right semantics with respect to
+ // lvalues/rvalues and the type. Fortunately, we can allocate this
+ // call on the stack and we don't need its arguments to be
+ // well-formed.
+ DeclRefExpr ConversionRef(Conversion, Conversion->getType(),
+ SourceLocation());
+ ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()),
+ &ConversionRef, false);
+
+ // Note that it is safe to allocate CallExpr on the stack here because
+ // there are 0 arguments (i.e., nothing is allocated using ASTContext's
+ // allocator).
+ CallExpr Call(Context, &ConversionFn, 0, 0,
+ Conversion->getConversionType().getNonReferenceType(),
+ SourceLocation());
+ ImplicitConversionSequence ICS = TryCopyInitialization(&Call, ToType, true);
+ switch (ICS.ConversionKind) {
+ case ImplicitConversionSequence::StandardConversion:
+ Candidate.FinalConversion = ICS.Standard;
+ break;
+
+ case ImplicitConversionSequence::BadConversion:
+ Candidate.Viable = false;
+ break;
+
+ default:
+ assert(false &&
+ "Can only end up with a standard conversion sequence or failure");
+ }
+}
+
+/// AddSurrogateCandidate - Adds a "surrogate" candidate function that
+/// converts the given @c Object to a function pointer via the
+/// conversion function @c Conversion, and then attempts to call it
+/// with the given arguments (C++ [over.call.object]p2-4). Proto is
+/// the type of function that we'll eventually be calling.
+void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
+ const FunctionProtoType *Proto,
+ Expr *Object, Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet) {
+ CandidateSet.push_back(OverloadCandidate());
+ OverloadCandidate& Candidate = CandidateSet.back();
+ Candidate.Function = 0;
+ Candidate.Surrogate = Conversion;
+ Candidate.Viable = true;
+ Candidate.IsSurrogate = true;
+ Candidate.IgnoreObjectArgument = false;
+ Candidate.Conversions.resize(NumArgs + 1);
+
+ // Determine the implicit conversion sequence for the implicit
+ // object parameter.
+ ImplicitConversionSequence ObjectInit
+ = TryObjectArgumentInitialization(Object, Conversion);
+ if (ObjectInit.ConversionKind == ImplicitConversionSequence::BadConversion) {
+ Candidate.Viable = false;
+ return;
+ }
+
+ // The first conversion is actually a user-defined conversion whose
+ // first conversion is ObjectInit's standard conversion (which is
+ // effectively a reference binding). Record it as such.
+ Candidate.Conversions[0].ConversionKind
+ = ImplicitConversionSequence::UserDefinedConversion;
+ Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard;
+ Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion;
+ Candidate.Conversions[0].UserDefined.After
+ = Candidate.Conversions[0].UserDefined.Before;
+ Candidate.Conversions[0].UserDefined.After.setAsIdentityConversion();
+
+ // Find the
+ unsigned NumArgsInProto = Proto->getNumArgs();
+
+ // (C++ 13.3.2p2): A candidate function having fewer than m
+ // parameters is viable only if it has an ellipsis in its parameter
+ // list (8.3.5).
+ if (NumArgs > NumArgsInProto && !Proto->isVariadic()) {
+ Candidate.Viable = false;
+ return;
+ }
+
+ // Function types don't have any default arguments, so just check if
+ // we have enough arguments.
+ if (NumArgs < NumArgsInProto) {
+ // Not enough arguments.
+ Candidate.Viable = false;
+ return;
+ }
+
+ // Determine the implicit conversion sequences for each of the
+ // arguments.
+ for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
+ if (ArgIdx < NumArgsInProto) {
+ // (C++ 13.3.2p3): for F to be a viable function, there shall
+ // exist for each argument an implicit conversion sequence
+ // (13.3.3.1) that converts that argument to the corresponding
+ // parameter of F.
+ QualType ParamType = Proto->getArgType(ArgIdx);
+ Candidate.Conversions[ArgIdx + 1]
+ = TryCopyInitialization(Args[ArgIdx], ParamType,
+ /*SuppressUserConversions=*/false);
+ if (Candidate.Conversions[ArgIdx + 1].ConversionKind
+ == ImplicitConversionSequence::BadConversion) {
+ Candidate.Viable = false;
+ break;
+ }
+ } else {
+ // (C++ 13.3.2p2): For the purposes of overload resolution, any
+ // argument for which there is no corresponding parameter is
+ // considered to ""match the ellipsis" (C+ 13.3.3.1.3).
+ Candidate.Conversions[ArgIdx + 1].ConversionKind
+ = ImplicitConversionSequence::EllipsisConversion;
+ }
+ }
+}
+
+// FIXME: This will eventually be removed, once we've migrated all of the
+// operator overloading logic over to the scheme used by binary operators, which
+// works for template instantiation.
+void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
+ SourceLocation OpLoc,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ SourceRange OpRange) {
+
+ FunctionSet Functions;
+
+ QualType T1 = Args[0]->getType();
+ QualType T2;
+ if (NumArgs > 1)
+ T2 = Args[1]->getType();
+
+ DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
+ if (S)
+ LookupOverloadedOperatorName(Op, S, T1, T2, Functions);
+ ArgumentDependentLookup(OpName, Args, NumArgs, Functions);
+ AddFunctionCandidates(Functions, Args, NumArgs, CandidateSet);
+ AddMemberOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet, OpRange);
+ AddBuiltinOperatorCandidates(Op, Args, NumArgs, CandidateSet);
+}
+
+/// \brief Add overload candidates for overloaded operators that are
+/// member functions.
+///
+/// Add the overloaded operator candidates that are member functions
+/// for the operator Op that was used in an operator expression such
+/// as "x Op y". , Args/NumArgs provides the operator arguments, and
+/// CandidateSet will store the added overload candidates. (C++
+/// [over.match.oper]).
+void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
+ SourceLocation OpLoc,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ SourceRange OpRange) {
+ DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
+
+ // C++ [over.match.oper]p3:
+ // For a unary operator @ with an operand of a type whose
+ // cv-unqualified version is T1, and for a binary operator @ with
+ // a left operand of a type whose cv-unqualified version is T1 and
+ // a right operand of a type whose cv-unqualified version is T2,
+ // three sets of candidate functions, designated member
+ // candidates, non-member candidates and built-in candidates, are
+ // constructed as follows:
+ QualType T1 = Args[0]->getType();
+ QualType T2;
+ if (NumArgs > 1)
+ T2 = Args[1]->getType();
+
+ // -- If T1 is a class type, the set of member candidates is the
+ // result of the qualified lookup of T1::operator@
+ // (13.3.1.1.1); otherwise, the set of member candidates is
+ // empty.
+ // FIXME: Lookup in base classes, too!
+ if (const RecordType *T1Rec = T1->getAsRecordType()) {
+ DeclContext::lookup_const_iterator Oper, OperEnd;
+ for (llvm::tie(Oper, OperEnd) = T1Rec->getDecl()->lookup(Context, OpName);
+ Oper != OperEnd; ++Oper)
+ AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Args[0],
+ Args+1, NumArgs - 1, CandidateSet,
+ /*SuppressUserConversions=*/false);
+ }
+}
+
+/// AddBuiltinCandidate - Add a candidate for a built-in
+/// operator. ResultTy and ParamTys are the result and parameter types
+/// of the built-in candidate, respectively. Args and NumArgs are the
+/// arguments being passed to the candidate. IsAssignmentOperator
+/// should be true when this built-in candidate is an assignment
+/// operator. NumContextualBoolArguments is the number of arguments
+/// (at the beginning of the argument list) that will be contextually
+/// converted to bool.
+void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool IsAssignmentOperator,
+ unsigned NumContextualBoolArguments) {
+ // Add this candidate
+ CandidateSet.push_back(OverloadCandidate());
+ OverloadCandidate& Candidate = CandidateSet.back();
+ Candidate.Function = 0;
+ Candidate.IsSurrogate = false;
+ Candidate.IgnoreObjectArgument = false;
+ Candidate.BuiltinTypes.ResultTy = ResultTy;
+ for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
+ Candidate.BuiltinTypes.ParamTypes[ArgIdx] = ParamTys[ArgIdx];
+
+ // Determine the implicit conversion sequences for each of the
+ // arguments.
+ Candidate.Viable = true;
+ Candidate.Conversions.resize(NumArgs);
+ for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
+ // C++ [over.match.oper]p4:
+ // For the built-in assignment operators, conversions of the
+ // left operand are restricted as follows:
+ // -- no temporaries are introduced to hold the left operand, and
+ // -- no user-defined conversions are applied to the left
+ // operand to achieve a type match with the left-most
+ // parameter of a built-in candidate.
+ //
+ // We block these conversions by turning off user-defined
+ // conversions, since that is the only way that initialization of
+ // a reference to a non-class type can occur from something that
+ // is not of the same type.
+ if (ArgIdx < NumContextualBoolArguments) {
+ assert(ParamTys[ArgIdx] == Context.BoolTy &&
+ "Contextual conversion to bool requires bool type");
+ Candidate.Conversions[ArgIdx] = TryContextuallyConvertToBool(Args[ArgIdx]);
+ } else {
+ Candidate.Conversions[ArgIdx]
+ = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx],
+ ArgIdx == 0 && IsAssignmentOperator);
+ }
+ if (Candidate.Conversions[ArgIdx].ConversionKind
+ == ImplicitConversionSequence::BadConversion) {
+ Candidate.Viable = false;
+ break;
+ }
+ }
+}
+
+/// BuiltinCandidateTypeSet - A set of types that will be used for the
+/// candidate operator functions for built-in operators (C++
+/// [over.built]). The types are separated into pointer types and
+/// enumeration types.
+class BuiltinCandidateTypeSet {
+ /// TypeSet - A set of types.
+ typedef llvm::SmallPtrSet<QualType, 8> TypeSet;
+
+ /// PointerTypes - The set of pointer types that will be used in the
+ /// built-in candidates.
+ TypeSet PointerTypes;
+
+ /// MemberPointerTypes - The set of member pointer types that will be
+ /// used in the built-in candidates.
+ TypeSet MemberPointerTypes;
+
+ /// EnumerationTypes - The set of enumeration types that will be
+ /// used in the built-in candidates.
+ TypeSet EnumerationTypes;
+
+ /// Context - The AST context in which we will build the type sets.
+ ASTContext &Context;
+
+ bool AddPointerWithMoreQualifiedTypeVariants(QualType Ty);
+ bool AddMemberPointerWithMoreQualifiedTypeVariants(QualType Ty);
+
+public:
+ /// iterator - Iterates through the types that are part of the set.
+ typedef TypeSet::iterator iterator;
+
+ BuiltinCandidateTypeSet(ASTContext &Context) : Context(Context) { }
+
+ void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions,
+ bool AllowExplicitConversions);
+
+ /// pointer_begin - First pointer type found;
+ iterator pointer_begin() { return PointerTypes.begin(); }
+
+ /// pointer_end - Past the last pointer type found;
+ iterator pointer_end() { return PointerTypes.end(); }
+
+ /// member_pointer_begin - First member pointer type found;
+ iterator member_pointer_begin() { return MemberPointerTypes.begin(); }
+
+ /// member_pointer_end - Past the last member pointer type found;
+ iterator member_pointer_end() { return MemberPointerTypes.end(); }
+
+ /// enumeration_begin - First enumeration type found;
+ iterator enumeration_begin() { return EnumerationTypes.begin(); }
+
+ /// enumeration_end - Past the last enumeration type found;
+ iterator enumeration_end() { return EnumerationTypes.end(); }
+};
+
+/// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to
+/// the set of pointer types along with any more-qualified variants of
+/// that type. For example, if @p Ty is "int const *", this routine
+/// will add "int const *", "int const volatile *", "int const
+/// restrict *", and "int const volatile restrict *" to the set of
+/// pointer types. Returns true if the add of @p Ty itself succeeded,
+/// false otherwise.
+bool
+BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty) {
+ // Insert this type.
+ if (!PointerTypes.insert(Ty))
+ return false;
+
+ if (const PointerType *PointerTy = Ty->getAsPointerType()) {
+ QualType PointeeTy = PointerTy->getPointeeType();
+ // FIXME: Optimize this so that we don't keep trying to add the same types.
+
+ // FIXME: Do we have to add CVR qualifiers at *all* levels to deal with all
+ // pointer conversions that don't cast away constness?
+ if (!PointeeTy.isConstQualified())
+ AddPointerWithMoreQualifiedTypeVariants
+ (Context.getPointerType(PointeeTy.withConst()));
+ if (!PointeeTy.isVolatileQualified())
+ AddPointerWithMoreQualifiedTypeVariants
+ (Context.getPointerType(PointeeTy.withVolatile()));
+ if (!PointeeTy.isRestrictQualified())
+ AddPointerWithMoreQualifiedTypeVariants
+ (Context.getPointerType(PointeeTy.withRestrict()));
+ }
+
+ return true;
+}
+
+/// AddMemberPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty
+/// to the set of pointer types along with any more-qualified variants of
+/// that type. For example, if @p Ty is "int const *", this routine
+/// will add "int const *", "int const volatile *", "int const
+/// restrict *", and "int const volatile restrict *" to the set of
+/// pointer types. Returns true if the add of @p Ty itself succeeded,
+/// false otherwise.
+bool
+BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants(
+ QualType Ty) {
+ // Insert this type.
+ if (!MemberPointerTypes.insert(Ty))
+ return false;
+
+ if (const MemberPointerType *PointerTy = Ty->getAsMemberPointerType()) {
+ QualType PointeeTy = PointerTy->getPointeeType();
+ const Type *ClassTy = PointerTy->getClass();
+ // FIXME: Optimize this so that we don't keep trying to add the same types.
+
+ if (!PointeeTy.isConstQualified())
+ AddMemberPointerWithMoreQualifiedTypeVariants
+ (Context.getMemberPointerType(PointeeTy.withConst(), ClassTy));
+ if (!PointeeTy.isVolatileQualified())
+ AddMemberPointerWithMoreQualifiedTypeVariants
+ (Context.getMemberPointerType(PointeeTy.withVolatile(), ClassTy));
+ if (!PointeeTy.isRestrictQualified())
+ AddMemberPointerWithMoreQualifiedTypeVariants
+ (Context.getMemberPointerType(PointeeTy.withRestrict(), ClassTy));
+ }
+
+ return true;
+}
+
+/// AddTypesConvertedFrom - Add each of the types to which the type @p
+/// Ty can be implicit converted to the given set of @p Types. We're
+/// primarily interested in pointer types and enumeration types. We also
+/// take member pointer types, for the conditional operator.
+/// AllowUserConversions is true if we should look at the conversion
+/// functions of a class type, and AllowExplicitConversions if we
+/// should also include the explicit conversion functions of a class
+/// type.
+void
+BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
+ bool AllowUserConversions,
+ bool AllowExplicitConversions) {
+ // Only deal with canonical types.
+ Ty = Context.getCanonicalType(Ty);
+
+ // Look through reference types; they aren't part of the type of an
+ // expression for the purposes of conversions.
+ if (const ReferenceType *RefTy = Ty->getAsReferenceType())
+ Ty = RefTy->getPointeeType();
+
+ // We don't care about qualifiers on the type.
+ Ty = Ty.getUnqualifiedType();
+
+ if (const PointerType *PointerTy = Ty->getAsPointerType()) {
+ QualType PointeeTy = PointerTy->getPointeeType();
+
+ // Insert our type, and its more-qualified variants, into the set
+ // of types.
+ if (!AddPointerWithMoreQualifiedTypeVariants(Ty))
+ return;
+
+ // Add 'cv void*' to our set of types.
+ if (!Ty->isVoidType()) {
+ QualType QualVoid
+ = Context.VoidTy.getQualifiedType(PointeeTy.getCVRQualifiers());
+ AddPointerWithMoreQualifiedTypeVariants(Context.getPointerType(QualVoid));
+ }
+
+ // If this is a pointer to a class type, add pointers to its bases
+ // (with the same level of cv-qualification as the original
+ // derived class, of course).
+ if (const RecordType *PointeeRec = PointeeTy->getAsRecordType()) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(PointeeRec->getDecl());
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ QualType BaseTy = Context.getCanonicalType(Base->getType());
+ BaseTy = BaseTy.getQualifiedType(PointeeTy.getCVRQualifiers());
+
+ // Add the pointer type, recursively, so that we get all of
+ // the indirect base classes, too.
+ AddTypesConvertedFrom(Context.getPointerType(BaseTy), false, false);
+ }
+ }
+ } else if (Ty->isMemberPointerType()) {
+ // Member pointers are far easier, since the pointee can't be converted.
+ if (!AddMemberPointerWithMoreQualifiedTypeVariants(Ty))
+ return;
+ } else if (Ty->isEnumeralType()) {
+ EnumerationTypes.insert(Ty);
+ } else if (AllowUserConversions) {
+ if (const RecordType *TyRec = Ty->getAsRecordType()) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
+ // FIXME: Visit conversion functions in the base classes, too.
+ OverloadedFunctionDecl *Conversions
+ = ClassDecl->getConversionFunctions();
+ for (OverloadedFunctionDecl::function_iterator Func
+ = Conversions->function_begin();
+ Func != Conversions->function_end(); ++Func) {
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+ if (AllowExplicitConversions || !Conv->isExplicit())
+ AddTypesConvertedFrom(Conv->getConversionType(), false, false);
+ }
+ }
+ }
+}
+
+/// AddBuiltinOperatorCandidates - Add the appropriate built-in
+/// operator overloads to the candidate set (C++ [over.built]), based
+/// on the operator @p Op and the arguments given. For example, if the
+/// operator is a binary '+', this routine might add "int
+/// operator+(int, int)" to cover integer addition.
+void
+Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet) {
+ // The set of "promoted arithmetic types", which are the arithmetic
+ // types are that preserved by promotion (C++ [over.built]p2). Note
+ // that the first few of these types are the promoted integral
+ // types; these types need to be first.
+ // FIXME: What about complex?
+ const unsigned FirstIntegralType = 0;
+ const unsigned LastIntegralType = 13;
+ const unsigned FirstPromotedIntegralType = 7,
+ LastPromotedIntegralType = 13;
+ const unsigned FirstPromotedArithmeticType = 7,
+ LastPromotedArithmeticType = 16;
+ const unsigned NumArithmeticTypes = 16;
+ QualType ArithmeticTypes[NumArithmeticTypes] = {
+ Context.BoolTy, Context.CharTy, Context.WCharTy,
+ Context.SignedCharTy, Context.ShortTy,
+ Context.UnsignedCharTy, Context.UnsignedShortTy,
+ Context.IntTy, Context.LongTy, Context.LongLongTy,
+ Context.UnsignedIntTy, Context.UnsignedLongTy, Context.UnsignedLongLongTy,
+ Context.FloatTy, Context.DoubleTy, Context.LongDoubleTy
+ };
+
+ // Find all of the types that the arguments can convert to, but only
+ // if the operator we're looking at has built-in operator candidates
+ // that make use of these types.
+ BuiltinCandidateTypeSet CandidateTypes(Context);
+ if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual ||
+ Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual ||
+ Op == OO_Plus || (Op == OO_Minus && NumArgs == 2) || Op == OO_Equal ||
+ Op == OO_PlusEqual || Op == OO_MinusEqual || Op == OO_Subscript ||
+ Op == OO_ArrowStar || Op == OO_PlusPlus || Op == OO_MinusMinus ||
+ (Op == OO_Star && NumArgs == 1) || Op == OO_Conditional) {
+ for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
+ CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(),
+ true,
+ (Op == OO_Exclaim ||
+ Op == OO_AmpAmp ||
+ Op == OO_PipePipe));
+ }
+
+ bool isComparison = false;
+ switch (Op) {
+ case OO_None:
+ case NUM_OVERLOADED_OPERATORS:
+ assert(false && "Expected an overloaded operator");
+ break;
+
+ case OO_Star: // '*' is either unary or binary
+ if (NumArgs == 1)
+ goto UnaryStar;
+ else
+ goto BinaryStar;
+ break;
+
+ case OO_Plus: // '+' is either unary or binary
+ if (NumArgs == 1)
+ goto UnaryPlus;
+ else
+ goto BinaryPlus;
+ break;
+
+ case OO_Minus: // '-' is either unary or binary
+ if (NumArgs == 1)
+ goto UnaryMinus;
+ else
+ goto BinaryMinus;
+ break;
+
+ case OO_Amp: // '&' is either unary or binary
+ if (NumArgs == 1)
+ goto UnaryAmp;
+ else
+ goto BinaryAmp;
+
+ case OO_PlusPlus:
+ case OO_MinusMinus:
+ // C++ [over.built]p3:
+ //
+ // For every pair (T, VQ), where T is an arithmetic type, and VQ
+ // is either volatile or empty, there exist candidate operator
+ // functions of the form
+ //
+ // VQ T& operator++(VQ T&);
+ // T operator++(VQ T&, int);
+ //
+ // C++ [over.built]p4:
+ //
+ // For every pair (T, VQ), where T is an arithmetic type other
+ // than bool, and VQ is either volatile or empty, there exist
+ // candidate operator functions of the form
+ //
+ // VQ T& operator--(VQ T&);
+ // T operator--(VQ T&, int);
+ for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1);
+ Arith < NumArithmeticTypes; ++Arith) {
+ QualType ArithTy = ArithmeticTypes[Arith];
+ QualType ParamTypes[2]
+ = { Context.getLValueReferenceType(ArithTy), Context.IntTy };
+
+ // Non-volatile version.
+ if (NumArgs == 1)
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
+ else
+ AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet);
+
+ // Volatile version
+ ParamTypes[0] = Context.getLValueReferenceType(ArithTy.withVolatile());
+ if (NumArgs == 1)
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
+ else
+ AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet);
+ }
+
+ // C++ [over.built]p5:
+ //
+ // For every pair (T, VQ), where T is a cv-qualified or
+ // cv-unqualified object type, and VQ is either volatile or
+ // empty, there exist candidate operator functions of the form
+ //
+ // T*VQ& operator++(T*VQ&);
+ // T*VQ& operator--(T*VQ&);
+ // T* operator++(T*VQ&, int);
+ // T* operator--(T*VQ&, int);
+ for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin();
+ Ptr != CandidateTypes.pointer_end(); ++Ptr) {
+ // Skip pointer types that aren't pointers to object types.
+ if (!(*Ptr)->getAsPointerType()->getPointeeType()->isObjectType())
+ continue;
+
+ QualType ParamTypes[2] = {
+ Context.getLValueReferenceType(*Ptr), Context.IntTy
+ };
+
+ // Without volatile
+ if (NumArgs == 1)
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
+ else
+ AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet);
+
+ if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) {
+ // With volatile
+ ParamTypes[0] = Context.getLValueReferenceType((*Ptr).withVolatile());
+ if (NumArgs == 1)
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
+ else
+ AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet);
+ }
+ }
+ break;
+
+ UnaryStar:
+ // C++ [over.built]p6:
+ // For every cv-qualified or cv-unqualified object type T, there
+ // exist candidate operator functions of the form
+ //
+ // T& operator*(T*);
+ //
+ // C++ [over.built]p7:
+ // For every function type T, there exist candidate operator
+ // functions of the form
+ // T& operator*(T*);
+ for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin();
+ Ptr != CandidateTypes.pointer_end(); ++Ptr) {
+ QualType ParamTy = *Ptr;
+ QualType PointeeTy = ParamTy->getAsPointerType()->getPointeeType();
+ AddBuiltinCandidate(Context.getLValueReferenceType(PointeeTy),
+ &ParamTy, Args, 1, CandidateSet);
+ }
+ break;
+
+ UnaryPlus:
+ // C++ [over.built]p8:
+ // For every type T, there exist candidate operator functions of
+ // the form
+ //
+ // T* operator+(T*);
+ for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin();
+ Ptr != CandidateTypes.pointer_end(); ++Ptr) {
+ QualType ParamTy = *Ptr;
+ AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet);
+ }
+
+ // Fall through
+
+ UnaryMinus:
+ // C++ [over.built]p9:
+ // For every promoted arithmetic type T, there exist candidate
+ // operator functions of the form
+ //
+ // T operator+(T);
+ // T operator-(T);
+ for (unsigned Arith = FirstPromotedArithmeticType;
+ Arith < LastPromotedArithmeticType; ++Arith) {
+ QualType ArithTy = ArithmeticTypes[Arith];
+ AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet);
+ }
+ break;
+
+ case OO_Tilde:
+ // C++ [over.built]p10:
+ // For every promoted integral type T, there exist candidate
+ // operator functions of the form
+ //
+ // T operator~(T);
+ for (unsigned Int = FirstPromotedIntegralType;
+ Int < LastPromotedIntegralType; ++Int) {
+ QualType IntTy = ArithmeticTypes[Int];
+ AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet);
+ }
+ break;
+
+ 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;
+
+ case OO_Comma:
+ UnaryAmp:
+ case OO_Arrow:
+ // C++ [over.match.oper]p3:
+ // -- For the operator ',', the unary operator '&', or the
+ // operator '->', the built-in candidates set is empty.
+ break;
+
+ case OO_Less:
+ case OO_Greater:
+ case OO_LessEqual:
+ case OO_GreaterEqual:
+ case OO_EqualEqual:
+ case OO_ExclaimEqual:
+ // C++ [over.built]p15:
+ //
+ // For every pointer or enumeration type T, there exist
+ // candidate operator functions of the form
+ //
+ // bool operator<(T, T);
+ // bool operator>(T, T);
+ // bool operator<=(T, T);
+ // bool operator>=(T, T);
+ // bool operator==(T, T);
+ // bool operator!=(T, T);
+ for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin();
+ Ptr != CandidateTypes.pointer_end(); ++Ptr) {
+ QualType ParamTypes[2] = { *Ptr, *Ptr };
+ AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet);
+ }
+ for (BuiltinCandidateTypeSet::iterator Enum
+ = CandidateTypes.enumeration_begin();
+ Enum != CandidateTypes.enumeration_end(); ++Enum) {
+ QualType ParamTypes[2] = { *Enum, *Enum };
+ AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet);
+ }
+
+ // Fall through.
+ isComparison = true;
+
+ BinaryPlus:
+ BinaryMinus:
+ if (!isComparison) {
+ // We didn't fall through, so we must have OO_Plus or OO_Minus.
+
+ // C++ [over.built]p13:
+ //
+ // For every cv-qualified or cv-unqualified object type T
+ // there exist candidate operator functions of the form
+ //
+ // T* operator+(T*, ptrdiff_t);
+ // T& operator[](T*, ptrdiff_t); [BELOW]
+ // T* operator-(T*, ptrdiff_t);
+ // T* operator+(ptrdiff_t, T*);
+ // T& operator[](ptrdiff_t, T*); [BELOW]
+ //
+ // C++ [over.built]p14:
+ //
+ // For every T, where T is a pointer to object type, there
+ // exist candidate operator functions of the form
+ //
+ // ptrdiff_t operator-(T, T);
+ for (BuiltinCandidateTypeSet::iterator Ptr
+ = CandidateTypes.pointer_begin();
+ Ptr != CandidateTypes.pointer_end(); ++Ptr) {
+ QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() };
+
+ // operator+(T*, ptrdiff_t) or operator-(T*, ptrdiff_t)
+ AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet);
+
+ if (Op == OO_Plus) {
+ // T* operator+(ptrdiff_t, T*);
+ ParamTypes[0] = ParamTypes[1];
+ ParamTypes[1] = *Ptr;
+ AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet);
+ } else {
+ // ptrdiff_t operator-(T, T);
+ ParamTypes[1] = *Ptr;
+ AddBuiltinCandidate(Context.getPointerDiffType(), ParamTypes,
+ Args, 2, CandidateSet);
+ }
+ }
+ }
+ // Fall through
+
+ case OO_Slash:
+ BinaryStar:
+ Conditional:
+ // C++ [over.built]p12:
+ //
+ // For every pair of promoted arithmetic types L and R, there
+ // exist candidate operator functions of the form
+ //
+ // LR operator*(L, R);
+ // LR operator/(L, R);
+ // LR operator+(L, R);
+ // LR operator-(L, R);
+ // bool operator<(L, R);
+ // bool operator>(L, R);
+ // bool operator<=(L, R);
+ // bool operator>=(L, R);
+ // bool operator==(L, R);
+ // bool operator!=(L, R);
+ //
+ // where LR is the result of the usual arithmetic conversions
+ // between types L and R.
+ //
+ // C++ [over.built]p24:
+ //
+ // For every pair of promoted arithmetic types L and R, there exist
+ // candidate operator functions of the form
+ //
+ // LR operator?(bool, L, R);
+ //
+ // where LR is the result of the usual arithmetic conversions
+ // between types L and R.
+ // Our candidates ignore the first parameter.
+ for (unsigned Left = FirstPromotedArithmeticType;
+ Left < LastPromotedArithmeticType; ++Left) {
+ for (unsigned Right = FirstPromotedArithmeticType;
+ Right < LastPromotedArithmeticType; ++Right) {
+ QualType LandR[2] = { ArithmeticTypes[Left], ArithmeticTypes[Right] };
+ QualType Result
+ = isComparison? Context.BoolTy
+ : UsualArithmeticConversionsType(LandR[0], LandR[1]);
+ AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
+ }
+ }
+ break;
+
+ case OO_Percent:
+ BinaryAmp:
+ case OO_Caret:
+ case OO_Pipe:
+ case OO_LessLess:
+ case OO_GreaterGreater:
+ // C++ [over.built]p17:
+ //
+ // For every pair of promoted integral types L and R, there
+ // exist candidate operator functions of the form
+ //
+ // LR operator%(L, R);
+ // LR operator&(L, R);
+ // LR operator^(L, R);
+ // LR operator|(L, R);
+ // L operator<<(L, R);
+ // L operator>>(L, R);
+ //
+ // where LR is the result of the usual arithmetic conversions
+ // between types L and R.
+ for (unsigned Left = FirstPromotedIntegralType;
+ Left < LastPromotedIntegralType; ++Left) {
+ for (unsigned Right = FirstPromotedIntegralType;
+ Right < LastPromotedIntegralType; ++Right) {
+ QualType LandR[2] = { ArithmeticTypes[Left], ArithmeticTypes[Right] };
+ QualType Result = (Op == OO_LessLess || Op == OO_GreaterGreater)
+ ? LandR[0]
+ : UsualArithmeticConversionsType(LandR[0], LandR[1]);
+ AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
+ }
+ }
+ break;
+
+ case OO_Equal:
+ // C++ [over.built]p20:
+ //
+ // For every pair (T, VQ), where T is an enumeration or
+ // (FIXME:) pointer to member type and VQ is either volatile or
+ // empty, there exist candidate operator functions of the form
+ //
+ // VQ T& operator=(VQ T&, T);
+ for (BuiltinCandidateTypeSet::iterator Enum
+ = CandidateTypes.enumeration_begin();
+ Enum != CandidateTypes.enumeration_end(); ++Enum) {
+ QualType ParamTypes[2];
+
+ // T& operator=(T&, T)
+ ParamTypes[0] = Context.getLValueReferenceType(*Enum);
+ ParamTypes[1] = *Enum;
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssignmentOperator=*/false);
+
+ if (!Context.getCanonicalType(*Enum).isVolatileQualified()) {
+ // volatile T& operator=(volatile T&, T)
+ ParamTypes[0] = Context.getLValueReferenceType((*Enum).withVolatile());
+ ParamTypes[1] = *Enum;
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssignmentOperator=*/false);
+ }
+ }
+ // Fall through.
+
+ case OO_PlusEqual:
+ case OO_MinusEqual:
+ // C++ [over.built]p19:
+ //
+ // For every pair (T, VQ), where T is any type and VQ is either
+ // volatile or empty, there exist candidate operator functions
+ // of the form
+ //
+ // T*VQ& operator=(T*VQ&, T*);
+ //
+ // C++ [over.built]p21:
+ //
+ // For every pair (T, VQ), where T is a cv-qualified or
+ // cv-unqualified object type and VQ is either volatile or
+ // empty, there exist candidate operator functions of the form
+ //
+ // T*VQ& operator+=(T*VQ&, ptrdiff_t);
+ // T*VQ& operator-=(T*VQ&, ptrdiff_t);
+ for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin();
+ Ptr != CandidateTypes.pointer_end(); ++Ptr) {
+ QualType ParamTypes[2];
+ ParamTypes[1] = (Op == OO_Equal)? *Ptr : Context.getPointerDiffType();
+
+ // non-volatile version
+ ParamTypes[0] = Context.getLValueReferenceType(*Ptr);
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/Op == OO_Equal);
+
+ if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) {
+ // volatile version
+ ParamTypes[0] = Context.getLValueReferenceType((*Ptr).withVolatile());
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/Op == OO_Equal);
+ }
+ }
+ // Fall through.
+
+ case OO_StarEqual:
+ case OO_SlashEqual:
+ // C++ [over.built]p18:
+ //
+ // For every triple (L, VQ, R), where L is an arithmetic type,
+ // VQ is either volatile or empty, and R is a promoted
+ // arithmetic type, there exist candidate operator functions of
+ // the form
+ //
+ // VQ L& operator=(VQ L&, R);
+ // VQ L& operator*=(VQ L&, R);
+ // VQ L& operator/=(VQ L&, R);
+ // VQ L& operator+=(VQ L&, R);
+ // VQ L& operator-=(VQ L&, R);
+ for (unsigned Left = 0; Left < NumArithmeticTypes; ++Left) {
+ for (unsigned Right = FirstPromotedArithmeticType;
+ Right < LastPromotedArithmeticType; ++Right) {
+ QualType ParamTypes[2];
+ ParamTypes[1] = ArithmeticTypes[Right];
+
+ // Add this built-in operator as a candidate (VQ is empty).
+ ParamTypes[0] = Context.getLValueReferenceType(ArithmeticTypes[Left]);
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/Op == OO_Equal);
+
+ // Add this built-in operator as a candidate (VQ is 'volatile').
+ ParamTypes[0] = ArithmeticTypes[Left].withVolatile();
+ ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]);
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/Op == OO_Equal);
+ }
+ }
+ break;
+
+ case OO_PercentEqual:
+ case OO_LessLessEqual:
+ case OO_GreaterGreaterEqual:
+ case OO_AmpEqual:
+ case OO_CaretEqual:
+ case OO_PipeEqual:
+ // C++ [over.built]p22:
+ //
+ // For every triple (L, VQ, R), where L is an integral type, VQ
+ // is either volatile or empty, and R is a promoted integral
+ // type, there exist candidate operator functions of the form
+ //
+ // VQ L& operator%=(VQ L&, R);
+ // VQ L& operator<<=(VQ L&, R);
+ // VQ L& operator>>=(VQ L&, R);
+ // VQ L& operator&=(VQ L&, R);
+ // VQ L& operator^=(VQ L&, R);
+ // VQ L& operator|=(VQ L&, R);
+ for (unsigned Left = FirstIntegralType; Left < LastIntegralType; ++Left) {
+ for (unsigned Right = FirstPromotedIntegralType;
+ Right < LastPromotedIntegralType; ++Right) {
+ QualType ParamTypes[2];
+ ParamTypes[1] = ArithmeticTypes[Right];
+
+ // Add this built-in operator as a candidate (VQ is empty).
+ ParamTypes[0] = Context.getLValueReferenceType(ArithmeticTypes[Left]);
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+
+ // Add this built-in operator as a candidate (VQ is 'volatile').
+ ParamTypes[0] = ArithmeticTypes[Left];
+ ParamTypes[0].addVolatile();
+ ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]);
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+ }
+ }
+ break;
+
+ case OO_Exclaim: {
+ // C++ [over.operator]p23:
+ //
+ // There also exist candidate operator functions of the form
+ //
+ // bool operator!(bool);
+ // bool operator&&(bool, bool); [BELOW]
+ // bool operator||(bool, bool); [BELOW]
+ QualType ParamTy = Context.BoolTy;
+ AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet,
+ /*IsAssignmentOperator=*/false,
+ /*NumContextualBoolArguments=*/1);
+ break;
+ }
+
+ case OO_AmpAmp:
+ case OO_PipePipe: {
+ // C++ [over.operator]p23:
+ //
+ // There also exist candidate operator functions of the form
+ //
+ // bool operator!(bool); [ABOVE]
+ // bool operator&&(bool, bool);
+ // bool operator||(bool, bool);
+ QualType ParamTypes[2] = { Context.BoolTy, Context.BoolTy };
+ AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet,
+ /*IsAssignmentOperator=*/false,
+ /*NumContextualBoolArguments=*/2);
+ break;
+ }
+
+ case OO_Subscript:
+ // C++ [over.built]p13:
+ //
+ // For every cv-qualified or cv-unqualified object type T there
+ // exist candidate operator functions of the form
+ //
+ // T* operator+(T*, ptrdiff_t); [ABOVE]
+ // T& operator[](T*, ptrdiff_t);
+ // T* operator-(T*, ptrdiff_t); [ABOVE]
+ // T* operator+(ptrdiff_t, T*); [ABOVE]
+ // T& operator[](ptrdiff_t, T*);
+ for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin();
+ Ptr != CandidateTypes.pointer_end(); ++Ptr) {
+ QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() };
+ QualType PointeeType = (*Ptr)->getAsPointerType()->getPointeeType();
+ QualType ResultTy = Context.getLValueReferenceType(PointeeType);
+
+ // T& operator[](T*, ptrdiff_t)
+ AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet);
+
+ // T& operator[](ptrdiff_t, T*);
+ ParamTypes[0] = ParamTypes[1];
+ ParamTypes[1] = *Ptr;
+ AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet);
+ }
+ break;
+
+ case OO_ArrowStar:
+ // FIXME: No support for pointer-to-members yet.
+ break;
+
+ case OO_Conditional:
+ // Note that we don't consider the first argument, since it has been
+ // contextually converted to bool long ago. The candidates below are
+ // therefore added as binary.
+ //
+ // C++ [over.built]p24:
+ // For every type T, where T is a pointer or pointer-to-member type,
+ // there exist candidate operator functions of the form
+ //
+ // T operator?(bool, T, T);
+ //
+ for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(),
+ E = CandidateTypes.pointer_end(); Ptr != E; ++Ptr) {
+ QualType ParamTypes[2] = { *Ptr, *Ptr };
+ AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet);
+ }
+ for (BuiltinCandidateTypeSet::iterator Ptr =
+ CandidateTypes.member_pointer_begin(),
+ E = CandidateTypes.member_pointer_end(); Ptr != E; ++Ptr) {
+ QualType ParamTypes[2] = { *Ptr, *Ptr };
+ AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet);
+ }
+ goto Conditional;
+ }
+}
+
+/// \brief Add function candidates found via argument-dependent lookup
+/// to the set of overloading candidates.
+///
+/// This routine performs argument-dependent name lookup based on the
+/// given function name (which may also be an operator name) and adds
+/// all of the overload candidates found by ADL to the overload
+/// candidate set (C++ [basic.lookup.argdep]).
+void
+Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet) {
+ FunctionSet Functions;
+
+ // Record all of the function candidates that we've already
+ // added to the overload set, so that we don't add those same
+ // candidates a second time.
+ for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
+ CandEnd = CandidateSet.end();
+ Cand != CandEnd; ++Cand)
+ if (Cand->Function)
+ Functions.insert(Cand->Function);
+
+ ArgumentDependentLookup(Name, Args, NumArgs, Functions);
+
+ // Erase all of the candidates we already knew about.
+ // FIXME: This is suboptimal. Is there a better way?
+ for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
+ CandEnd = CandidateSet.end();
+ Cand != CandEnd; ++Cand)
+ if (Cand->Function)
+ Functions.erase(Cand->Function);
+
+ // For each of the ADL candidates we found, add it to the overload
+ // set.
+ for (FunctionSet::iterator Func = Functions.begin(),
+ FuncEnd = Functions.end();
+ Func != FuncEnd; ++Func)
+ AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet);
+}
+
+/// isBetterOverloadCandidate - Determines whether the first overload
+/// candidate is a better candidate than the second (C++ 13.3.3p1).
+bool
+Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
+ const OverloadCandidate& Cand2)
+{
+ // Define viable functions to be better candidates than non-viable
+ // functions.
+ if (!Cand2.Viable)
+ return Cand1.Viable;
+ else if (!Cand1.Viable)
+ return false;
+
+ // C++ [over.match.best]p1:
+ //
+ // -- if F is a static member function, ICS1(F) is defined such
+ // that ICS1(F) is neither better nor worse than ICS1(G) for
+ // any function G, and, symmetrically, ICS1(G) is neither
+ // better nor worse than ICS1(F).
+ unsigned StartArg = 0;
+ if (Cand1.IgnoreObjectArgument || Cand2.IgnoreObjectArgument)
+ StartArg = 1;
+
+ // (C++ 13.3.3p1): a viable function F1 is defined to be a better
+ // function than another viable function F2 if for all arguments i,
+ // ICSi(F1) is not a worse conversion sequence than ICSi(F2), and
+ // then...
+ unsigned NumArgs = Cand1.Conversions.size();
+ assert(Cand2.Conversions.size() == NumArgs && "Overload candidate mismatch");
+ bool HasBetterConversion = false;
+ for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) {
+ switch (CompareImplicitConversionSequences(Cand1.Conversions[ArgIdx],
+ Cand2.Conversions[ArgIdx])) {
+ case ImplicitConversionSequence::Better:
+ // Cand1 has a better conversion sequence.
+ HasBetterConversion = true;
+ break;
+
+ case ImplicitConversionSequence::Worse:
+ // Cand1 can't be better than Cand2.
+ return false;
+
+ case ImplicitConversionSequence::Indistinguishable:
+ // Do nothing.
+ break;
+ }
+ }
+
+ if (HasBetterConversion)
+ return true;
+
+ // FIXME: Several other bullets in (C++ 13.3.3p1) need to be
+ // implemented, but they require template support.
+
+ // C++ [over.match.best]p1b4:
+ //
+ // -- the context is an initialization by user-defined conversion
+ // (see 8.5, 13.3.1.5) and the standard conversion sequence
+ // from the return type of F1 to the destination type (i.e.,
+ // the type of the entity being initialized) is a better
+ // conversion sequence than the standard conversion sequence
+ // from the return type of F2 to the destination type.
+ if (Cand1.Function && Cand2.Function &&
+ isa<CXXConversionDecl>(Cand1.Function) &&
+ isa<CXXConversionDecl>(Cand2.Function)) {
+ switch (CompareStandardConversionSequences(Cand1.FinalConversion,
+ Cand2.FinalConversion)) {
+ case ImplicitConversionSequence::Better:
+ // Cand1 has a better conversion sequence.
+ return true;
+
+ case ImplicitConversionSequence::Worse:
+ // Cand1 can't be better than Cand2.
+ return false;
+
+ case ImplicitConversionSequence::Indistinguishable:
+ // Do nothing
+ break;
+ }
+ }
+
+ return false;
+}
+
+/// BestViableFunction - Computes the best viable function (C++ 13.3.3)
+/// within an overload candidate set. If overloading is successful,
+/// the result will be OR_Success and Best will be set to point to the
+/// best viable function within the candidate set. Otherwise, one of
+/// several kinds of errors will be returned; see
+/// Sema::OverloadingResult.
+Sema::OverloadingResult
+Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
+ OverloadCandidateSet::iterator& Best)
+{
+ // Find the best viable function.
+ Best = CandidateSet.end();
+ for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
+ Cand != CandidateSet.end(); ++Cand) {
+ if (Cand->Viable) {
+ if (Best == CandidateSet.end() || isBetterOverloadCandidate(*Cand, *Best))
+ Best = Cand;
+ }
+ }
+
+ // If we didn't find any viable functions, abort.
+ if (Best == CandidateSet.end())
+ return OR_No_Viable_Function;
+
+ // Make sure that this function is better than every other viable
+ // function. If not, we have an ambiguity.
+ for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
+ Cand != CandidateSet.end(); ++Cand) {
+ if (Cand->Viable &&
+ Cand != Best &&
+ !isBetterOverloadCandidate(*Best, *Cand)) {
+ Best = CandidateSet.end();
+ return OR_Ambiguous;
+ }
+ }
+
+ // Best is the best viable function.
+ if (Best->Function &&
+ (Best->Function->isDeleted() ||
+ Best->Function->getAttr<UnavailableAttr>()))
+ return OR_Deleted;
+
+ // If Best refers to a function that is either deleted (C++0x) or
+ // unavailable (Clang extension) report an error.
+
+ return OR_Success;
+}
+
+/// PrintOverloadCandidates - When overload resolution fails, prints
+/// diagnostic messages containing the candidates in the candidate
+/// set. If OnlyViable is true, only viable candidates will be printed.
+void
+Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
+ bool OnlyViable)
+{
+ OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
+ LastCand = CandidateSet.end();
+ for (; Cand != LastCand; ++Cand) {
+ if (Cand->Viable || !OnlyViable) {
+ if (Cand->Function) {
+ if (Cand->Function->isDeleted() ||
+ Cand->Function->getAttr<UnavailableAttr>()) {
+ // Deleted or "unavailable" function.
+ Diag(Cand->Function->getLocation(), diag::err_ovl_candidate_deleted)
+ << Cand->Function->isDeleted();
+ } else {
+ // Normal function
+ // FIXME: Give a better reason!
+ Diag(Cand->Function->getLocation(), diag::err_ovl_candidate);
+ }
+ } else if (Cand->IsSurrogate) {
+ // Desugar the type of the surrogate down to a function type,
+ // retaining as many typedefs as possible while still showing
+ // the function type (and, therefore, its parameter types).
+ QualType FnType = Cand->Surrogate->getConversionType();
+ bool isLValueReference = false;
+ bool isRValueReference = false;
+ bool isPointer = false;
+ if (const LValueReferenceType *FnTypeRef =
+ FnType->getAsLValueReferenceType()) {
+ FnType = FnTypeRef->getPointeeType();
+ isLValueReference = true;
+ } else if (const RValueReferenceType *FnTypeRef =
+ FnType->getAsRValueReferenceType()) {
+ FnType = FnTypeRef->getPointeeType();
+ isRValueReference = true;
+ }
+ if (const PointerType *FnTypePtr = FnType->getAsPointerType()) {
+ FnType = FnTypePtr->getPointeeType();
+ isPointer = true;
+ }
+ // Desugar down to a function type.
+ FnType = QualType(FnType->getAsFunctionType(), 0);
+ // Reconstruct the pointer/reference as appropriate.
+ if (isPointer) FnType = Context.getPointerType(FnType);
+ if (isRValueReference) FnType = Context.getRValueReferenceType(FnType);
+ if (isLValueReference) FnType = Context.getLValueReferenceType(FnType);
+
+ Diag(Cand->Surrogate->getLocation(), diag::err_ovl_surrogate_cand)
+ << FnType;
+ } else {
+ // FIXME: We need to get the identifier in here
+ // FIXME: Do we want the error message to point at the operator?
+ // (built-ins won't have a location)
+ QualType FnType
+ = Context.getFunctionType(Cand->BuiltinTypes.ResultTy,
+ Cand->BuiltinTypes.ParamTypes,
+ Cand->Conversions.size(),
+ false, 0);
+
+ Diag(SourceLocation(), diag::err_ovl_builtin_candidate) << FnType;
+ }
+ }
+ }
+}
+
+/// ResolveAddressOfOverloadedFunction - Try to resolve the address of
+/// an overloaded function (C++ [over.over]), where @p From is an
+/// expression with overloaded function type and @p ToType is the type
+/// we're trying to resolve to. For example:
+///
+/// @code
+/// int f(double);
+/// int f(int);
+///
+/// int (*pfd)(double) = f; // selects f(double)
+/// @endcode
+///
+/// This routine returns the resulting FunctionDecl if it could be
+/// resolved, and NULL otherwise. When @p Complain is true, this
+/// routine will emit diagnostics if there is an error.
+FunctionDecl *
+Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
+ bool Complain) {
+ QualType FunctionType = ToType;
+ bool IsMember = false;
+ if (const PointerType *ToTypePtr = ToType->getAsPointerType())
+ FunctionType = ToTypePtr->getPointeeType();
+ else if (const ReferenceType *ToTypeRef = ToType->getAsReferenceType())
+ FunctionType = ToTypeRef->getPointeeType();
+ else if (const MemberPointerType *MemTypePtr =
+ ToType->getAsMemberPointerType()) {
+ FunctionType = MemTypePtr->getPointeeType();
+ IsMember = true;
+ }
+
+ // We only look at pointers or references to functions.
+ if (!FunctionType->isFunctionType())
+ return 0;
+
+ // Find the actual overloaded function declaration.
+ OverloadedFunctionDecl *Ovl = 0;
+
+ // C++ [over.over]p1:
+ // [...] [Note: any redundant set of parentheses surrounding the
+ // overloaded function name is ignored (5.1). ]
+ Expr *OvlExpr = From->IgnoreParens();
+
+ // C++ [over.over]p1:
+ // [...] The overloaded function name can be preceded by the &
+ // operator.
+ if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(OvlExpr)) {
+ if (UnOp->getOpcode() == UnaryOperator::AddrOf)
+ OvlExpr = UnOp->getSubExpr()->IgnoreParens();
+ }
+
+ // Try to dig out the overloaded function.
+ if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OvlExpr))
+ Ovl = dyn_cast<OverloadedFunctionDecl>(DR->getDecl());
+
+ // If there's no overloaded function declaration, we're done.
+ if (!Ovl)
+ return 0;
+
+ // Look through all of the overloaded functions, searching for one
+ // whose type matches exactly.
+ // FIXME: When templates or using declarations come along, we'll actually
+ // have to deal with duplicates, partial ordering, etc. For now, we
+ // can just do a simple search.
+ FunctionType = Context.getCanonicalType(FunctionType.getUnqualifiedType());
+ for (OverloadedFunctionDecl::function_iterator Fun = Ovl->function_begin();
+ Fun != Ovl->function_end(); ++Fun) {
+ // C++ [over.over]p3:
+ // Non-member functions and static member functions match
+ // targets of type "pointer-to-function" or "reference-to-function."
+ // Nonstatic member functions match targets of
+ // type "pointer-to-member-function."
+ // Note that according to DR 247, the containing class does not matter.
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Fun)) {
+ // Skip non-static functions when converting to pointer, and static
+ // when converting to member pointer.
+ if (Method->isStatic() == IsMember)
+ continue;
+ } else if (IsMember)
+ continue;
+
+ if (FunctionType == Context.getCanonicalType((*Fun)->getType()))
+ return *Fun;
+ }
+
+ return 0;
+}
+
+/// ResolveOverloadedCallFn - Given the call expression that calls Fn
+/// (which eventually refers to the declaration Func) and the call
+/// arguments Args/NumArgs, attempt to resolve the function call down
+/// to a specific function. If overload resolution succeeds, returns
+/// the function declaration produced by overload
+/// resolution. Otherwise, emits diagnostics, deletes all of the
+/// arguments and Fn, and returns NULL.
+FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
+ DeclarationName UnqualifiedName,
+ SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc,
+ bool &ArgumentDependentLookup) {
+ OverloadCandidateSet CandidateSet;
+
+ // Add the functions denoted by Callee to the set of candidate
+ // functions. While we're doing so, track whether argument-dependent
+ // lookup still applies, per:
+ //
+ // C++0x [basic.lookup.argdep]p3:
+ // Let X be the lookup set produced by unqualified lookup (3.4.1)
+ // and let Y be the lookup set produced by argument dependent
+ // lookup (defined as follows). If X contains
+ //
+ // -- a declaration of a class member, or
+ //
+ // -- a block-scope function declaration that is not a
+ // using-declaration, or
+ //
+ // -- a declaration that is neither a function or a function
+ // template
+ //
+ // then Y is empty.
+ if (OverloadedFunctionDecl *Ovl
+ = dyn_cast_or_null<OverloadedFunctionDecl>(Callee)) {
+ for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
+ FuncEnd = Ovl->function_end();
+ Func != FuncEnd; ++Func) {
+ AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet);
+
+ if ((*Func)->getDeclContext()->isRecord() ||
+ (*Func)->getDeclContext()->isFunctionOrMethod())
+ ArgumentDependentLookup = false;
+ }
+ } else if (FunctionDecl *Func = dyn_cast_or_null<FunctionDecl>(Callee)) {
+ AddOverloadCandidate(Func, Args, NumArgs, CandidateSet);
+
+ if (Func->getDeclContext()->isRecord() ||
+ Func->getDeclContext()->isFunctionOrMethod())
+ ArgumentDependentLookup = false;
+ }
+
+ if (Callee)
+ UnqualifiedName = Callee->getDeclName();
+
+ if (ArgumentDependentLookup)
+ AddArgumentDependentLookupCandidates(UnqualifiedName, Args, NumArgs,
+ CandidateSet);
+
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(CandidateSet, Best)) {
+ case OR_Success:
+ return Best->Function;
+
+ case OR_No_Viable_Function:
+ Diag(Fn->getSourceRange().getBegin(),
+ diag::err_ovl_no_viable_function_in_call)
+ << UnqualifiedName << Fn->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ break;
+
+ case OR_Ambiguous:
+ Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call)
+ << UnqualifiedName << Fn->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ break;
+
+ case OR_Deleted:
+ Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_deleted_call)
+ << Best->Function->isDeleted()
+ << UnqualifiedName
+ << Fn->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ break;
+ }
+
+ // Overload resolution failed. Destroy all of the subexpressions and
+ // return NULL.
+ Fn->Destroy(Context);
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
+ Args[Arg]->Destroy(Context);
+ return 0;
+}
+
+/// \brief Create a unary operation that may resolve to an overloaded
+/// operator.
+///
+/// \param OpLoc The location of the operator itself (e.g., '*').
+///
+/// \param OpcIn The UnaryOperator::Opcode that describes this
+/// operator.
+///
+/// \param Functions The set of non-member functions that will be
+/// considered by overload resolution. The caller needs to build this
+/// set based on the context using, e.g.,
+/// LookupOverloadedOperatorName() and ArgumentDependentLookup(). This
+/// set should not contain any member functions; those will be added
+/// by CreateOverloadedUnaryOp().
+///
+/// \param input The input argument.
+Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
+ unsigned OpcIn,
+ FunctionSet &Functions,
+ ExprArg input) {
+ UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn);
+ Expr *Input = (Expr *)input.get();
+
+ OverloadedOperatorKind Op = UnaryOperator::getOverloadedOperator(Opc);
+ assert(Op != OO_None && "Invalid opcode for overloaded unary operator");
+ DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
+
+ Expr *Args[2] = { Input, 0 };
+ unsigned NumArgs = 1;
+
+ // For post-increment and post-decrement, add the implicit '0' as
+ // the second argument, so that we know this is a post-increment or
+ // post-decrement.
+ if (Opc == UnaryOperator::PostInc || Opc == UnaryOperator::PostDec) {
+ llvm::APSInt Zero(Context.getTypeSize(Context.IntTy), false);
+ Args[1] = new (Context) IntegerLiteral(Zero, Context.IntTy,
+ SourceLocation());
+ NumArgs = 2;
+ }
+
+ if (Input->isTypeDependent()) {
+ OverloadedFunctionDecl *Overloads
+ = OverloadedFunctionDecl::Create(Context, CurContext, OpName);
+ for (FunctionSet::iterator Func = Functions.begin(),
+ FuncEnd = Functions.end();
+ Func != FuncEnd; ++Func)
+ Overloads->addOverload(*Func);
+
+ DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy,
+ OpLoc, false, false);
+
+ input.release();
+ return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
+ &Args[0], NumArgs,
+ Context.DependentTy,
+ OpLoc));
+ }
+
+ // Build an empty overload set.
+ OverloadCandidateSet CandidateSet;
+
+ // Add the candidates from the given function set.
+ AddFunctionCandidates(Functions, &Args[0], NumArgs, CandidateSet, false);
+
+ // Add operator candidates that are member functions.
+ AddMemberOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet);
+
+ // Add builtin operator candidates.
+ AddBuiltinOperatorCandidates(Op, &Args[0], NumArgs, CandidateSet);
+
+ // Perform overload resolution.
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(CandidateSet, Best)) {
+ case OR_Success: {
+ // We found a built-in operator or an overloaded operator.
+ FunctionDecl *FnDecl = Best->Function;
+
+ if (FnDecl) {
+ // We matched an overloaded operator. Build a call to that
+ // operator.
+
+ // Convert the arguments.
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
+ if (PerformObjectArgumentInitialization(Input, Method))
+ return ExprError();
+ } else {
+ // Convert the arguments.
+ if (PerformCopyInitialization(Input,
+ FnDecl->getParamDecl(0)->getType(),
+ "passing"))
+ return ExprError();
+ }
+
+ // Determine the result type
+ QualType ResultTy
+ = FnDecl->getType()->getAsFunctionType()->getResultType();
+ ResultTy = ResultTy.getNonReferenceType();
+
+ // Build the actual expression node.
+ Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
+ SourceLocation());
+ UsualUnaryConversions(FnExpr);
+
+ input.release();
+ return Owned(new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
+ &Input, 1, ResultTy,
+ OpLoc));
+ } else {
+ // We matched a built-in operator. Convert the arguments, then
+ // break out so that we will build the appropriate built-in
+ // operator node.
+ if (PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0],
+ Best->Conversions[0], "passing"))
+ return ExprError();
+
+ break;
+ }
+ }
+
+ case OR_No_Viable_Function:
+ // No viable function; fall through to handling this as a
+ // built-in operator, which will produce an error message for us.
+ break;
+
+ case OR_Ambiguous:
+ Diag(OpLoc, diag::err_ovl_ambiguous_oper)
+ << UnaryOperator::getOpcodeStr(Opc)
+ << Input->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ return ExprError();
+
+ case OR_Deleted:
+ Diag(OpLoc, diag::err_ovl_deleted_oper)
+ << Best->Function->isDeleted()
+ << UnaryOperator::getOpcodeStr(Opc)
+ << Input->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ return ExprError();
+ }
+
+ // Either we found no viable overloaded operator or we matched a
+ // built-in operator. In either case, fall through to trying to
+ // build a built-in operation.
+ input.release();
+ return CreateBuiltinUnaryOp(OpLoc, Opc, Owned(Input));
+}
+
+/// \brief Create a binary operation that may resolve to an overloaded
+/// operator.
+///
+/// \param OpLoc The location of the operator itself (e.g., '+').
+///
+/// \param OpcIn The BinaryOperator::Opcode that describes this
+/// operator.
+///
+/// \param Functions The set of non-member functions that will be
+/// considered by overload resolution. The caller needs to build this
+/// set based on the context using, e.g.,
+/// LookupOverloadedOperatorName() and ArgumentDependentLookup(). This
+/// set should not contain any member functions; those will be added
+/// by CreateOverloadedBinOp().
+///
+/// \param LHS Left-hand argument.
+/// \param RHS Right-hand argument.
+Sema::OwningExprResult
+Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
+ unsigned OpcIn,
+ FunctionSet &Functions,
+ Expr *LHS, Expr *RHS) {
+ Expr *Args[2] = { LHS, RHS };
+
+ BinaryOperator::Opcode Opc = static_cast<BinaryOperator::Opcode>(OpcIn);
+ OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc);
+ DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
+
+ // If either side is type-dependent, create an appropriate dependent
+ // expression.
+ if (LHS->isTypeDependent() || RHS->isTypeDependent()) {
+ // .* cannot be overloaded.
+ if (Opc == BinaryOperator::PtrMemD)
+ return Owned(new (Context) BinaryOperator(LHS, RHS, Opc,
+ Context.DependentTy, OpLoc));
+
+ OverloadedFunctionDecl *Overloads
+ = OverloadedFunctionDecl::Create(Context, CurContext, OpName);
+ for (FunctionSet::iterator Func = Functions.begin(),
+ FuncEnd = Functions.end();
+ Func != FuncEnd; ++Func)
+ Overloads->addOverload(*Func);
+
+ DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy,
+ OpLoc, false, false);
+
+ return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
+ Args, 2,
+ Context.DependentTy,
+ OpLoc));
+ }
+
+ // If this is the .* operator, which is not overloadable, just
+ // create a built-in binary operator.
+ if (Opc == BinaryOperator::PtrMemD)
+ return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS);
+
+ // If this is one of the assignment operators, we only perform
+ // overload resolution if the left-hand side is a class or
+ // enumeration type (C++ [expr.ass]p3).
+ if (Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign &&
+ !LHS->getType()->isOverloadableType())
+ return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS);
+
+ // Build an empty overload set.
+ OverloadCandidateSet CandidateSet;
+
+ // Add the candidates from the given function set.
+ AddFunctionCandidates(Functions, Args, 2, CandidateSet, false);
+
+ // Add operator candidates that are member functions.
+ AddMemberOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet);
+
+ // Add builtin operator candidates.
+ AddBuiltinOperatorCandidates(Op, Args, 2, CandidateSet);
+
+ // Perform overload resolution.
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(CandidateSet, Best)) {
+ case OR_Success: {
+ // We found a built-in operator or an overloaded operator.
+ FunctionDecl *FnDecl = Best->Function;
+
+ if (FnDecl) {
+ // We matched an overloaded operator. Build a call to that
+ // operator.
+
+ // Convert the arguments.
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
+ if (PerformObjectArgumentInitialization(LHS, Method) ||
+ PerformCopyInitialization(RHS, FnDecl->getParamDecl(0)->getType(),
+ "passing"))
+ return ExprError();
+ } else {
+ // Convert the arguments.
+ if (PerformCopyInitialization(LHS, FnDecl->getParamDecl(0)->getType(),
+ "passing") ||
+ PerformCopyInitialization(RHS, FnDecl->getParamDecl(1)->getType(),
+ "passing"))
+ return ExprError();
+ }
+
+ // Determine the result type
+ QualType ResultTy
+ = FnDecl->getType()->getAsFunctionType()->getResultType();
+ ResultTy = ResultTy.getNonReferenceType();
+
+ // Build the actual expression node.
+ Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
+ SourceLocation());
+ UsualUnaryConversions(FnExpr);
+
+ return Owned(new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
+ Args, 2, ResultTy,
+ OpLoc));
+ } else {
+ // We matched a built-in operator. Convert the arguments, then
+ // break out so that we will build the appropriate built-in
+ // operator node.
+ if (PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0],
+ Best->Conversions[0], "passing") ||
+ PerformImplicitConversion(RHS, Best->BuiltinTypes.ParamTypes[1],
+ Best->Conversions[1], "passing"))
+ return ExprError();
+
+ break;
+ }
+ }
+
+ case OR_No_Viable_Function:
+ // For class as left operand for assignment or compound assigment operator
+ // do not fall through to handling in built-in, but report that no overloaded
+ // assignment operator found
+ if (LHS->getType()->isRecordType() && Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign) {
+ Diag(OpLoc, diag::err_ovl_no_viable_oper)
+ << BinaryOperator::getOpcodeStr(Opc)
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ return ExprError();
+ }
+ // No viable function; fall through to handling this as a
+ // built-in operator, which will produce an error message for us.
+ break;
+
+ case OR_Ambiguous:
+ Diag(OpLoc, diag::err_ovl_ambiguous_oper)
+ << BinaryOperator::getOpcodeStr(Opc)
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ return ExprError();
+
+ case OR_Deleted:
+ Diag(OpLoc, diag::err_ovl_deleted_oper)
+ << Best->Function->isDeleted()
+ << BinaryOperator::getOpcodeStr(Opc)
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ return ExprError();
+ }
+
+ // Either we found no viable overloaded operator or we matched a
+ // built-in operator. In either case, try to build a built-in
+ // operation.
+ return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS);
+}
+
+/// BuildCallToMemberFunction - Build a call to a member
+/// function. MemExpr is the expression that refers to the member
+/// function (and includes the object parameter), Args/NumArgs are the
+/// arguments to the function call (not including the object
+/// parameter). The caller needs to validate that the member
+/// expression refers to a member function or an overloaded member
+/// function.
+Sema::ExprResult
+Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
+ SourceLocation LParenLoc, Expr **Args,
+ unsigned NumArgs, SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ // Dig out the member expression. This holds both the object
+ // argument and the member function we're referring to.
+ MemberExpr *MemExpr = 0;
+ if (ParenExpr *ParenE = dyn_cast<ParenExpr>(MemExprE))
+ MemExpr = dyn_cast<MemberExpr>(ParenE->getSubExpr());
+ else
+ MemExpr = dyn_cast<MemberExpr>(MemExprE);
+ assert(MemExpr && "Building member call without member expression");
+
+ // Extract the object argument.
+ Expr *ObjectArg = MemExpr->getBase();
+
+ CXXMethodDecl *Method = 0;
+ if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(MemExpr->getMemberDecl())) {
+ // Add overload candidates
+ OverloadCandidateSet CandidateSet;
+ for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
+ FuncEnd = Ovl->function_end();
+ Func != FuncEnd; ++Func) {
+ assert(isa<CXXMethodDecl>(*Func) && "Function is not a method");
+ Method = cast<CXXMethodDecl>(*Func);
+ AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet,
+ /*SuppressUserConversions=*/false);
+ }
+
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(CandidateSet, Best)) {
+ case OR_Success:
+ Method = cast<CXXMethodDecl>(Best->Function);
+ break;
+
+ case OR_No_Viable_Function:
+ Diag(MemExpr->getSourceRange().getBegin(),
+ diag::err_ovl_no_viable_member_function_in_call)
+ << Ovl->getDeclName() << MemExprE->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ // FIXME: Leaking incoming expressions!
+ return true;
+
+ case OR_Ambiguous:
+ Diag(MemExpr->getSourceRange().getBegin(),
+ diag::err_ovl_ambiguous_member_call)
+ << Ovl->getDeclName() << MemExprE->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ // FIXME: Leaking incoming expressions!
+ return true;
+
+ case OR_Deleted:
+ Diag(MemExpr->getSourceRange().getBegin(),
+ diag::err_ovl_deleted_member_call)
+ << Best->Function->isDeleted()
+ << Ovl->getDeclName() << MemExprE->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ // FIXME: Leaking incoming expressions!
+ return true;
+ }
+
+ FixOverloadedFunctionReference(MemExpr, Method);
+ } else {
+ Method = dyn_cast<CXXMethodDecl>(MemExpr->getMemberDecl());
+ }
+
+ assert(Method && "Member call to something that isn't a method?");
+ ExprOwningPtr<CXXMemberCallExpr>
+ TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExpr, Args,
+ NumArgs,
+ Method->getResultType().getNonReferenceType(),
+ RParenLoc));
+
+ // Convert the object argument (for a non-static member function call).
+ if (!Method->isStatic() &&
+ PerformObjectArgumentInitialization(ObjectArg, Method))
+ return true;
+ MemExpr->setBase(ObjectArg);
+
+ // Convert the rest of the arguments
+ const FunctionProtoType *Proto = cast<FunctionProtoType>(Method->getType());
+ if (ConvertArgumentsForCall(&*TheCall, MemExpr, Method, Proto, Args, NumArgs,
+ RParenLoc))
+ return true;
+
+ return CheckFunctionCall(Method, TheCall.take()).release();
+}
+
+/// BuildCallToObjectOfClassType - Build a call to an object of class
+/// type (C++ [over.call.object]), which can end up invoking an
+/// overloaded function call operator (@c operator()) or performing a
+/// user-defined conversion on the object argument.
+Sema::ExprResult
+Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
+ SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ assert(Object->getType()->isRecordType() && "Requires object type argument");
+ const RecordType *Record = Object->getType()->getAsRecordType();
+
+ // C++ [over.call.object]p1:
+ // If the primary-expression E in the function call syntax
+ // evaluates to a class object of type “cv Tâ€, then the set of
+ // candidate functions includes at least the function call
+ // operators of T. The function call operators of T are obtained by
+ // ordinary lookup of the name operator() in the context of
+ // (E).operator().
+ OverloadCandidateSet CandidateSet;
+ DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call);
+ DeclContext::lookup_const_iterator Oper, OperEnd;
+ for (llvm::tie(Oper, OperEnd) = Record->getDecl()->lookup(Context, OpName);
+ Oper != OperEnd; ++Oper)
+ AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Object, Args, NumArgs,
+ CandidateSet, /*SuppressUserConversions=*/false);
+
+ // C++ [over.call.object]p2:
+ // In addition, for each conversion function declared in T of the
+ // form
+ //
+ // operator conversion-type-id () cv-qualifier;
+ //
+ // where cv-qualifier is the same cv-qualification as, or a
+ // greater cv-qualification than, cv, and where conversion-type-id
+ // denotes the type "pointer to function of (P1,...,Pn) returning
+ // R", or the type "reference to pointer to function of
+ // (P1,...,Pn) returning R", or the type "reference to function
+ // of (P1,...,Pn) returning R", a surrogate call function [...]
+ // is also considered as a candidate function. Similarly,
+ // surrogate call functions are added to the set of candidate
+ // functions for each conversion function declared in an
+ // accessible base class provided the function is not hidden
+ // within T by another intervening declaration.
+ //
+ // FIXME: Look in base classes for more conversion operators!
+ OverloadedFunctionDecl *Conversions
+ = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
+ for (OverloadedFunctionDecl::function_iterator
+ Func = Conversions->function_begin(),
+ FuncEnd = Conversions->function_end();
+ Func != FuncEnd; ++Func) {
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+
+ // 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->getAsPointerType())
+ ConvType = ConvPtrType->getPointeeType();
+
+ if (const FunctionProtoType *Proto = ConvType->getAsFunctionProtoType())
+ AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet);
+ }
+
+ // Perform overload resolution.
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(CandidateSet, Best)) {
+ case OR_Success:
+ // Overload resolution succeeded; we'll build the appropriate call
+ // below.
+ break;
+
+ case OR_No_Viable_Function:
+ Diag(Object->getSourceRange().getBegin(),
+ diag::err_ovl_no_viable_object_call)
+ << Object->getType() << Object->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ break;
+
+ case OR_Ambiguous:
+ Diag(Object->getSourceRange().getBegin(),
+ diag::err_ovl_ambiguous_object_call)
+ << Object->getType() << Object->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ break;
+
+ case OR_Deleted:
+ Diag(Object->getSourceRange().getBegin(),
+ diag::err_ovl_deleted_object_call)
+ << Best->Function->isDeleted()
+ << Object->getType() << Object->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ break;
+ }
+
+ if (Best == CandidateSet.end()) {
+ // We had an error; delete all of the subexpressions and return
+ // the error.
+ Object->Destroy(Context);
+ for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
+ Args[ArgIdx]->Destroy(Context);
+ return true;
+ }
+
+ if (Best->Function == 0) {
+ // Since there is no function declaration, this is one of the
+ // surrogate candidates. Dig out the conversion function.
+ CXXConversionDecl *Conv
+ = cast<CXXConversionDecl>(
+ Best->Conversions[0].UserDefined.ConversionFunction);
+
+ // We selected one of the surrogate functions that converts the
+ // object parameter to a function pointer. Perform the conversion
+ // on the object argument, then let ActOnCallExpr finish the job.
+ // FIXME: Represent the user-defined conversion in the AST!
+ ImpCastExprToType(Object,
+ Conv->getConversionType().getNonReferenceType(),
+ Conv->getConversionType()->isLValueReferenceType());
+ return ActOnCallExpr(S, ExprArg(*this, Object), LParenLoc,
+ MultiExprArg(*this, (ExprTy**)Args, NumArgs),
+ CommaLocs, RParenLoc).release();
+ }
+
+ // We found an overloaded operator(). Build a CXXOperatorCallExpr
+ // that calls this method, using Object for the implicit object
+ // parameter and passing along the remaining arguments.
+ CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
+ const FunctionProtoType *Proto = Method->getType()->getAsFunctionProtoType();
+
+ unsigned NumArgsInProto = Proto->getNumArgs();
+ unsigned NumArgsToCheck = NumArgs;
+
+ // Build the full argument list for the method call (the
+ // implicit object parameter is placed at the beginning of the
+ // list).
+ Expr **MethodArgs;
+ if (NumArgs < NumArgsInProto) {
+ NumArgsToCheck = NumArgsInProto;
+ MethodArgs = new Expr*[NumArgsInProto + 1];
+ } else {
+ MethodArgs = new Expr*[NumArgs + 1];
+ }
+ MethodArgs[0] = Object;
+ for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
+ MethodArgs[ArgIdx + 1] = Args[ArgIdx];
+
+ Expr *NewFn = new (Context) DeclRefExpr(Method, Method->getType(),
+ SourceLocation());
+ UsualUnaryConversions(NewFn);
+
+ // Once we've built TheCall, all of the expressions are properly
+ // owned.
+ QualType ResultTy = Method->getResultType().getNonReferenceType();
+ ExprOwningPtr<CXXOperatorCallExpr>
+ TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn,
+ MethodArgs, NumArgs + 1,
+ ResultTy, RParenLoc));
+ delete [] MethodArgs;
+
+ // We may have default arguments. If so, we need to allocate more
+ // slots in the call for them.
+ if (NumArgs < NumArgsInProto)
+ TheCall->setNumArgs(Context, NumArgsInProto + 1);
+ else if (NumArgs > NumArgsInProto)
+ NumArgsToCheck = NumArgsInProto;
+
+ bool IsError = false;
+
+ // Initialize the implicit object parameter.
+ IsError |= PerformObjectArgumentInitialization(Object, Method);
+ TheCall->setArg(0, Object);
+
+
+ // Check the argument types.
+ for (unsigned i = 0; i != NumArgsToCheck; i++) {
+ Expr *Arg;
+ if (i < NumArgs) {
+ Arg = Args[i];
+
+ // Pass the argument.
+ QualType ProtoArgType = Proto->getArgType(i);
+ IsError |= PerformCopyInitialization(Arg, ProtoArgType, "passing");
+ } else {
+ Arg = new (Context) CXXDefaultArgExpr(Method->getParamDecl(i));
+ }
+
+ TheCall->setArg(i + 1, Arg);
+ }
+
+ // If this is a variadic call, handle args passed through "...".
+ if (Proto->isVariadic()) {
+ // Promote the arguments (C99 6.5.2.2p7).
+ for (unsigned i = NumArgsInProto; i != NumArgs; i++) {
+ Expr *Arg = Args[i];
+ IsError |= DefaultVariadicArgumentPromotion(Arg, VariadicMethod);
+ TheCall->setArg(i + 1, Arg);
+ }
+ }
+
+ if (IsError) return true;
+
+ return CheckFunctionCall(Method, TheCall.take()).release();
+}
+
+/// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator->
+/// (if one exists), where @c Base is an expression of class type and
+/// @c Member is the name of the member we're trying to find.
+Action::ExprResult
+Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
+ SourceLocation MemberLoc,
+ IdentifierInfo &Member) {
+ assert(Base->getType()->isRecordType() && "left-hand side must have class type");
+
+ // C++ [over.ref]p1:
+ //
+ // [...] An expression x->m is interpreted as (x.operator->())->m
+ // for a class object x of type T if T::operator->() exists and if
+ // the operator is selected as the best match function by the
+ // overload resolution mechanism (13.3).
+ // FIXME: look in base classes.
+ DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Arrow);
+ OverloadCandidateSet CandidateSet;
+ const RecordType *BaseRecord = Base->getType()->getAsRecordType();
+
+ DeclContext::lookup_const_iterator Oper, OperEnd;
+ for (llvm::tie(Oper, OperEnd)
+ = BaseRecord->getDecl()->lookup(Context, OpName);
+ Oper != OperEnd; ++Oper)
+ AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Base, 0, 0, CandidateSet,
+ /*SuppressUserConversions=*/false);
+
+ ExprOwningPtr<Expr> BasePtr(this, Base);
+
+ // Perform overload resolution.
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(CandidateSet, Best)) {
+ case OR_Success:
+ // Overload resolution succeeded; we'll build the call below.
+ break;
+
+ case OR_No_Viable_Function:
+ if (CandidateSet.empty())
+ Diag(OpLoc, diag::err_typecheck_member_reference_arrow)
+ << BasePtr->getType() << BasePtr->getSourceRange();
+ else
+ Diag(OpLoc, diag::err_ovl_no_viable_oper)
+ << "operator->" << BasePtr->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ return true;
+
+ case OR_Ambiguous:
+ Diag(OpLoc, diag::err_ovl_ambiguous_oper)
+ << "operator->" << BasePtr->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ return true;
+
+ case OR_Deleted:
+ Diag(OpLoc, diag::err_ovl_deleted_oper)
+ << Best->Function->isDeleted()
+ << "operator->" << BasePtr->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ return true;
+ }
+
+ // Convert the object parameter.
+ CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
+ if (PerformObjectArgumentInitialization(Base, Method))
+ return true;
+
+ // No concerns about early exits now.
+ BasePtr.take();
+
+ // Build the operator call.
+ Expr *FnExpr = new (Context) DeclRefExpr(Method, Method->getType(),
+ SourceLocation());
+ UsualUnaryConversions(FnExpr);
+ Base = new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, &Base, 1,
+ Method->getResultType().getNonReferenceType(),
+ OpLoc);
+ return ActOnMemberReferenceExpr(S, ExprArg(*this, Base), OpLoc, tok::arrow,
+ MemberLoc, Member, DeclPtrTy()).release();
+}
+
+/// FixOverloadedFunctionReference - E is an expression that refers to
+/// a C++ overloaded function (possibly with some parentheses and
+/// perhaps a '&' around it). We have resolved the overloaded function
+/// to the function declaration Fn, so patch up the expression E to
+/// refer (possibly indirectly) to Fn.
+void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
+ if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
+ FixOverloadedFunctionReference(PE->getSubExpr(), Fn);
+ E->setType(PE->getSubExpr()->getType());
+ } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) {
+ assert(UnOp->getOpcode() == UnaryOperator::AddrOf &&
+ "Can only take the address of an overloaded function");
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
+ if (Method->isStatic()) {
+ // Do nothing: static member functions aren't any different
+ // from non-member functions.
+ }
+ else if (QualifiedDeclRefExpr *DRE
+ = dyn_cast<QualifiedDeclRefExpr>(UnOp->getSubExpr())) {
+ // We have taken the address of a pointer to member
+ // function. Perform the computation here so that we get the
+ // appropriate pointer to member type.
+ DRE->setDecl(Fn);
+ DRE->setType(Fn->getType());
+ QualType ClassType
+ = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
+ E->setType(Context.getMemberPointerType(Fn->getType(),
+ ClassType.getTypePtr()));
+ return;
+ }
+ }
+ FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn);
+ E->setType(Context.getPointerType(UnOp->getSubExpr()->getType()));
+ } else if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) {
+ assert(isa<OverloadedFunctionDecl>(DR->getDecl()) &&
+ "Expected overloaded function");
+ DR->setDecl(Fn);
+ E->setType(Fn->getType());
+ } else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(E)) {
+ MemExpr->setMemberDecl(Fn);
+ E->setType(Fn->getType());
+ } else {
+ assert(false && "Invalid reference to overloaded function");
+ }
+}
+
+} // end namespace clang
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
new file mode 100644
index 000000000000..9de380657612
--- /dev/null
+++ b/lib/Sema/SemaOverload.h
@@ -0,0 +1,263 @@
+//===--- Overload.h - C++ Overloading ---------------------------*- 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 data structures and types used in C++
+// overload resolution.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_OVERLOAD_H
+#define LLVM_CLANG_SEMA_OVERLOAD_H
+
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+ class CXXConstructorDecl;
+ class FunctionDecl;
+
+ /// ImplicitConversionKind - The kind of implicit conversion used to
+ /// convert an argument to a parameter's type. The enumerator values
+ /// match with Table 9 of (C++ 13.3.3.1.1) and are listed such that
+ /// better conversion kinds have smaller values.
+ enum ImplicitConversionKind {
+ ICK_Identity = 0, ///< Identity conversion (no conversion)
+ ICK_Lvalue_To_Rvalue, ///< Lvalue-to-rvalue conversion (C++ 4.1)
+ ICK_Array_To_Pointer, ///< Array-to-pointer conversion (C++ 4.2)
+ ICK_Function_To_Pointer, ///< Function-to-pointer (C++ 4.3)
+ ICK_Qualification, ///< Qualification conversions (C++ 4.4)
+ ICK_Integral_Promotion, ///< Integral promotions (C++ 4.5)
+ ICK_Floating_Promotion, ///< Floating point promotions (C++ 4.6)
+ ICK_Complex_Promotion, ///< Complex promotions (Clang extension)
+ ICK_Integral_Conversion, ///< Integral conversions (C++ 4.7)
+ ICK_Floating_Conversion, ///< Floating point conversions (C++ 4.8)
+ ICK_Complex_Conversion, ///< Complex conversions (C99 6.3.1.6)
+ ICK_Floating_Integral, ///< Floating-integral conversions (C++ 4.9)
+ ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7)
+ ICK_Pointer_Conversion, ///< Pointer conversions (C++ 4.10)
+ ICK_Pointer_Member, ///< Pointer-to-member conversions (C++ 4.11)
+ ICK_Boolean_Conversion, ///< Boolean conversions (C++ 4.12)
+ ICK_Compatible_Conversion, ///< Conversions between compatible types in C99
+ ICK_Derived_To_Base, ///< Derived-to-base (C++ [over.best.ics])
+ ICK_Num_Conversion_Kinds ///< The number of conversion kinds
+ };
+
+ /// ImplicitConversionCategory - The category of an implicit
+ /// conversion kind. The enumerator values match with Table 9 of
+ /// (C++ 13.3.3.1.1) and are listed such that better conversion
+ /// categories have smaller values.
+ enum ImplicitConversionCategory {
+ ICC_Identity = 0, ///< Identity
+ ICC_Lvalue_Transformation, ///< Lvalue transformation
+ ICC_Qualification_Adjustment, ///< Qualification adjustment
+ ICC_Promotion, ///< Promotion
+ ICC_Conversion ///< Conversion
+ };
+
+ ImplicitConversionCategory
+ GetConversionCategory(ImplicitConversionKind Kind);
+
+ /// ImplicitConversionRank - The rank of an implicit conversion
+ /// kind. The enumerator values match with Table 9 of (C++
+ /// 13.3.3.1.1) and are listed such that better conversion ranks
+ /// have smaller values.
+ enum ImplicitConversionRank {
+ ICR_Exact_Match = 0, ///< Exact Match
+ ICR_Promotion, ///< Promotion
+ ICR_Conversion ///< Conversion
+ };
+
+ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind);
+
+ /// StandardConversionSequence - represents a standard conversion
+ /// sequence (C++ 13.3.3.1.1). A standard conversion sequence
+ /// contains between zero and three conversions. If a particular
+ /// conversion is not needed, it will be set to the identity conversion
+ /// (ICK_Identity). Note that the three conversions are
+ /// specified as separate members (rather than in an array) so that
+ /// we can keep the size of a standard conversion sequence to a
+ /// single word.
+ struct StandardConversionSequence {
+ /// First -- The first conversion can be an lvalue-to-rvalue
+ /// conversion, array-to-pointer conversion, or
+ /// function-to-pointer conversion.
+ ImplicitConversionKind First : 8;
+
+ /// Second - The second conversion can be an integral promotion,
+ /// floating point promotion, integral conversion, floating point
+ /// conversion, floating-integral conversion, pointer conversion,
+ /// pointer-to-member conversion, or boolean conversion.
+ ImplicitConversionKind Second : 8;
+
+ /// Third - The third conversion can be a qualification conversion.
+ ImplicitConversionKind Third : 8;
+
+ /// Deprecated - Whether this the deprecated conversion of a
+ /// string literal to a pointer to non-const character data
+ /// (C++ 4.2p2).
+ bool Deprecated : 1;
+
+ /// IncompatibleObjC - Whether this is an Objective-C conversion
+ /// that we should warn about (if we actually use it).
+ bool IncompatibleObjC : 1;
+
+ /// ReferenceBinding - True when this is a reference binding
+ /// (C++ [over.ics.ref]).
+ bool ReferenceBinding : 1;
+
+ /// DirectBinding - True when this is a reference binding that is a
+ /// direct binding (C++ [dcl.init.ref]).
+ bool DirectBinding : 1;
+
+ /// RRefBinding - True when this is a reference binding of an rvalue
+ /// reference to an rvalue (C++0x [over.ics.rank]p3b4).
+ bool RRefBinding : 1;
+
+ /// FromType - The type that this conversion is converting
+ /// from. This is an opaque pointer that can be translated into a
+ /// QualType.
+ void *FromTypePtr;
+
+ /// ToType - The type that this conversion is converting to. This
+ /// is an opaque pointer that can be translated into a QualType.
+ void *ToTypePtr;
+
+ /// CopyConstructor - The copy constructor that is used to perform
+ /// this conversion, when the conversion is actually just the
+ /// initialization of an object via copy constructor. Such
+ /// conversions are either identity conversions or derived-to-base
+ /// conversions.
+ CXXConstructorDecl *CopyConstructor;
+
+ void setAsIdentityConversion();
+ ImplicitConversionRank getRank() const;
+ bool isPointerConversionToBool() const;
+ bool isPointerConversionToVoidPointer(ASTContext& Context) const;
+ void DebugPrint() const;
+ };
+
+ /// UserDefinedConversionSequence - Represents a user-defined
+ /// conversion sequence (C++ 13.3.3.1.2).
+ struct UserDefinedConversionSequence {
+ /// Before - Represents the standard conversion that occurs before
+ /// the actual user-defined conversion. (C++ 13.3.3.1.2p1):
+ ///
+ /// If the user-defined conversion is specified by a constructor
+ /// (12.3.1), the initial standard conversion sequence converts
+ /// the source type to the type required by the argument of the
+ /// constructor. If the user-defined conversion is specified by
+ /// a conversion function (12.3.2), the initial standard
+ /// conversion sequence converts the source type to the implicit
+ /// object parameter of the conversion function.
+ StandardConversionSequence Before;
+
+ /// After - Represents the standard conversion that occurs after
+ /// the actual user-defined conversion.
+ StandardConversionSequence After;
+
+ /// ConversionFunction - The function that will perform the
+ /// user-defined conversion.
+ FunctionDecl* ConversionFunction;
+
+ void DebugPrint() const;
+ };
+
+ /// ImplicitConversionSequence - Represents an implicit conversion
+ /// sequence, which may be a standard conversion sequence
+ /// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2),
+ /// or an ellipsis conversion sequence (C++ 13.3.3.1.3).
+ struct ImplicitConversionSequence {
+ /// Kind - The kind of implicit conversion sequence. BadConversion
+ /// specifies that there is no conversion from the source type to
+ /// the target type. The enumerator values are ordered such that
+ /// better implicit conversions have smaller values.
+ enum Kind {
+ StandardConversion = 0,
+ UserDefinedConversion,
+ EllipsisConversion,
+ BadConversion
+ };
+
+ /// ConversionKind - The kind of implicit conversion sequence.
+ Kind ConversionKind;
+
+ union {
+ /// When ConversionKind == StandardConversion, provides the
+ /// details of the standard conversion sequence.
+ StandardConversionSequence Standard;
+
+ /// When ConversionKind == UserDefinedConversion, provides the
+ /// details of the user-defined conversion sequence.
+ UserDefinedConversionSequence UserDefined;
+ };
+
+ // The result of a comparison between implicit conversion
+ // sequences. Use Sema::CompareImplicitConversionSequences to
+ // actually perform the comparison.
+ enum CompareKind {
+ Better = -1,
+ Indistinguishable = 0,
+ Worse = 1
+ };
+
+ void DebugPrint() const;
+ };
+
+ /// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
+ struct OverloadCandidate {
+ /// Function - The actual function that this candidate
+ /// represents. When NULL, this is a built-in candidate
+ /// (C++ [over.oper]) or a surrogate for a conversion to a
+ /// function pointer or reference (C++ [over.call.object]).
+ FunctionDecl *Function;
+
+ // BuiltinTypes - Provides the return and parameter types of a
+ // built-in overload candidate. Only valid when Function is NULL.
+ struct {
+ QualType ResultTy;
+ QualType ParamTypes[3];
+ } BuiltinTypes;
+
+ /// Surrogate - The conversion function for which this candidate
+ /// is a surrogate, but only if IsSurrogate is true.
+ CXXConversionDecl *Surrogate;
+
+ /// Conversions - The conversion sequences used to convert the
+ /// function arguments to the function parameters.
+ llvm::SmallVector<ImplicitConversionSequence, 4> Conversions;
+
+ /// Viable - True to indicate that this overload candidate is viable.
+ bool Viable;
+
+ /// IsSurrogate - True to indicate that this candidate is a
+ /// surrogate for a conversion to a function pointer or reference
+ /// (C++ [over.call.object]).
+ bool IsSurrogate;
+
+ /// IgnoreObjectArgument - True to indicate that the first
+ /// argument's conversion, which for this function represents the
+ /// implicit object argument, should be ignored. This will be true
+ /// when the candidate is a static member function (where the
+ /// implicit object argument is just a placeholder) or a
+ /// non-static member function when the call doesn't have an
+ /// object argument.
+ bool IgnoreObjectArgument;
+
+ /// FinalConversion - For a conversion function (where Function is
+ /// a CXXConversionDecl), the standard conversion that occurs
+ /// after the call to the overload candidate to convert the result
+ /// of calling the conversion function to the required type.
+ StandardConversionSequence FinalConversion;
+ };
+
+ /// OverloadCandidateSet - A set of overload candidates, used in C++
+ /// overload resolution (C++ 13.3).
+ typedef llvm::SmallVector<OverloadCandidate, 16> OverloadCandidateSet;
+} // end namespace clang
+
+#endif // LLVM_CLANG_SEMA_OVERLOAD_H
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
new file mode 100644
index 000000000000..15262e9c3ac2
--- /dev/null
+++ b/lib/Sema/SemaStmt.cpp
@@ -0,0 +1,1266 @@
+//===--- SemaStmt.cpp - Semantic Analysis for Statements ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for statements.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/APValue.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Basic/TargetInfo.h"
+using namespace clang;
+
+Sema::OwningStmtResult Sema::ActOnExprStmt(FullExprArg expr) {
+ Expr *E = expr->takeAs<Expr>();
+ assert(E && "ActOnExprStmt(): missing expression");
+
+ // C99 6.8.3p2: The expression in an expression statement is evaluated as a
+ // void expression for its side effects. Conversion to void allows any
+ // operand, even incomplete types.
+
+ // Same thing in for stmt first clause (when expr) and third clause.
+ return Owned(static_cast<Stmt*>(E));
+}
+
+
+Sema::OwningStmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc) {
+ return Owned(new (Context) NullStmt(SemiLoc));
+}
+
+Sema::OwningStmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ DeclGroupRef DG = dg.getAsVal<DeclGroupRef>();
+
+ // If we have an invalid decl, just return an error.
+ if (DG.isNull()) return StmtError();
+
+ return Owned(new (Context) DeclStmt(DG, StartLoc, EndLoc));
+}
+
+Action::OwningStmtResult
+Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
+ MultiStmtArg elts, bool isStmtExpr) {
+ unsigned NumElts = elts.size();
+ Stmt **Elts = reinterpret_cast<Stmt**>(elts.release());
+ // If we're in C89 mode, check that we don't have any decls after stmts. If
+ // so, emit an extension diagnostic.
+ if (!getLangOptions().C99 && !getLangOptions().CPlusPlus) {
+ // Note that __extension__ can be around a decl.
+ unsigned i = 0;
+ // Skip over all declarations.
+ for (; i != NumElts && isa<DeclStmt>(Elts[i]); ++i)
+ /*empty*/;
+
+ // We found the end of the list or a statement. Scan for another declstmt.
+ for (; i != NumElts && !isa<DeclStmt>(Elts[i]); ++i)
+ /*empty*/;
+
+ if (i != NumElts) {
+ Decl *D = *cast<DeclStmt>(Elts[i])->decl_begin();
+ Diag(D->getLocation(), diag::ext_mixed_decls_code);
+ }
+ }
+ // Warn about unused expressions in statements.
+ for (unsigned i = 0; i != NumElts; ++i) {
+ Expr *E = dyn_cast<Expr>(Elts[i]);
+ if (!E) continue;
+
+ // Warn about expressions with unused results if they are non-void and if
+ // this not the last stmt in a stmt expr.
+ if (E->getType()->isVoidType() || (isStmtExpr && i == NumElts-1))
+ continue;
+
+ SourceLocation Loc;
+ SourceRange R1, R2;
+ if (!E->isUnusedResultAWarning(Loc, R1, R2))
+ continue;
+
+ Diag(Loc, diag::warn_unused_expr) << R1 << R2;
+ }
+
+ return Owned(new (Context) CompoundStmt(Context, Elts, NumElts, L, R));
+}
+
+Action::OwningStmtResult
+Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprArg lhsval,
+ SourceLocation DotDotDotLoc, ExprArg rhsval,
+ SourceLocation ColonLoc) {
+ assert((lhsval.get() != 0) && "missing expression in case statement");
+
+ // C99 6.8.4.2p3: The expression shall be an integer constant.
+ // However, GCC allows any evaluatable integer expression.
+ Expr *LHSVal = static_cast<Expr*>(lhsval.get());
+ if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() &&
+ VerifyIntegerConstantExpression(LHSVal))
+ return StmtError();
+
+ // GCC extension: The expression shall be an integer constant.
+
+ Expr *RHSVal = static_cast<Expr*>(rhsval.get());
+ if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent() &&
+ VerifyIntegerConstantExpression(RHSVal)) {
+ RHSVal = 0; // Recover by just forgetting about it.
+ rhsval = 0;
+ }
+
+ if (getSwitchStack().empty()) {
+ Diag(CaseLoc, diag::err_case_not_in_switch);
+ return StmtError();
+ }
+
+ // Only now release the smart pointers.
+ lhsval.release();
+ rhsval.release();
+ CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc,
+ ColonLoc);
+ getSwitchStack().back()->addSwitchCase(CS);
+ return Owned(CS);
+}
+
+/// ActOnCaseStmtBody - This installs a statement as the body of a case.
+void Sema::ActOnCaseStmtBody(StmtTy *caseStmt, StmtArg subStmt) {
+ CaseStmt *CS = static_cast<CaseStmt*>(caseStmt);
+ Stmt *SubStmt = subStmt.takeAs<Stmt>();
+ CS->setSubStmt(SubStmt);
+}
+
+Action::OwningStmtResult
+Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
+ StmtArg subStmt, Scope *CurScope) {
+ Stmt *SubStmt = subStmt.takeAs<Stmt>();
+
+ if (getSwitchStack().empty()) {
+ Diag(DefaultLoc, diag::err_default_not_in_switch);
+ return Owned(SubStmt);
+ }
+
+ DefaultStmt *DS = new (Context) DefaultStmt(DefaultLoc, ColonLoc, SubStmt);
+ getSwitchStack().back()->addSwitchCase(DS);
+ return Owned(DS);
+}
+
+Action::OwningStmtResult
+Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
+ SourceLocation ColonLoc, StmtArg subStmt) {
+ Stmt *SubStmt = subStmt.takeAs<Stmt>();
+ // Look up the record for this label identifier.
+ LabelStmt *&LabelDecl = getLabelMap()[II];
+
+ // If not forward referenced or defined already, just create a new LabelStmt.
+ if (LabelDecl == 0)
+ return Owned(LabelDecl = new (Context) LabelStmt(IdentLoc, II, SubStmt));
+
+ assert(LabelDecl->getID() == II && "Label mismatch!");
+
+ // Otherwise, this label was either forward reference or multiply defined. If
+ // multiply defined, reject it now.
+ if (LabelDecl->getSubStmt()) {
+ Diag(IdentLoc, diag::err_redefinition_of_label) << LabelDecl->getID();
+ Diag(LabelDecl->getIdentLoc(), diag::note_previous_definition);
+ return Owned(SubStmt);
+ }
+
+ // Otherwise, this label was forward declared, and we just found its real
+ // definition. Fill in the forward definition and return it.
+ LabelDecl->setIdentLoc(IdentLoc);
+ LabelDecl->setSubStmt(SubStmt);
+ return Owned(LabelDecl);
+}
+
+Action::OwningStmtResult
+Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal,
+ StmtArg ThenVal, SourceLocation ElseLoc,
+ StmtArg ElseVal) {
+ OwningExprResult CondResult(CondVal.release());
+
+ Expr *condExpr = CondResult.takeAs<Expr>();
+
+ assert(condExpr && "ActOnIfStmt(): missing expression");
+
+ if (!condExpr->isTypeDependent()) {
+ DefaultFunctionArrayConversion(condExpr);
+ // Take ownership again until we're past the error checking.
+ CondResult = condExpr;
+ QualType condType = condExpr->getType();
+
+ if (getLangOptions().CPlusPlus) {
+ if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4
+ return StmtError();
+ } else if (!condType->isScalarType()) // C99 6.8.4.1p1
+ return StmtError(Diag(IfLoc,
+ diag::err_typecheck_statement_requires_scalar)
+ << condType << condExpr->getSourceRange());
+ }
+
+ Stmt *thenStmt = ThenVal.takeAs<Stmt>();
+
+ // Warn if the if block has a null body without an else value.
+ // this helps prevent bugs due to typos, such as
+ // if (condition);
+ // do_stuff();
+ if (!ElseVal.get()) {
+ if (NullStmt* stmt = dyn_cast<NullStmt>(thenStmt))
+ Diag(stmt->getSemiLoc(), diag::warn_empty_if_body);
+ }
+
+ CondResult.release();
+ return Owned(new (Context) IfStmt(IfLoc, condExpr, thenStmt,
+ ElseLoc, ElseVal.takeAs<Stmt>()));
+}
+
+Action::OwningStmtResult
+Sema::ActOnStartOfSwitchStmt(ExprArg cond) {
+ Expr *Cond = cond.takeAs<Expr>();
+
+ if (getLangOptions().CPlusPlus) {
+ // C++ 6.4.2.p2:
+ // The condition shall be of integral type, enumeration type, or of a class
+ // type for which a single conversion function to integral or enumeration
+ // type exists (12.3). If the condition is of class type, the condition is
+ // converted by calling that conversion function, and the result of the
+ // conversion is used in place of the original condition for the remainder
+ // of this section. Integral promotions are performed.
+ if (!Cond->isTypeDependent()) {
+ QualType Ty = Cond->getType();
+
+ // FIXME: Handle class types.
+
+ // If the type is wrong a diagnostic will be emitted later at
+ // ActOnFinishSwitchStmt.
+ if (Ty->isIntegralType() || Ty->isEnumeralType()) {
+ // Integral promotions are performed.
+ // FIXME: Integral promotions for C++ are not complete.
+ UsualUnaryConversions(Cond);
+ }
+ }
+ } else {
+ // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
+ UsualUnaryConversions(Cond);
+ }
+
+ SwitchStmt *SS = new (Context) SwitchStmt(Cond);
+ getSwitchStack().push_back(SS);
+ return Owned(SS);
+}
+
+/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
+/// the specified width and sign. If an overflow occurs, detect it and emit
+/// the specified diagnostic.
+void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
+ unsigned NewWidth, bool NewSign,
+ SourceLocation Loc,
+ unsigned DiagID) {
+ // Perform a conversion to the promoted condition type if needed.
+ if (NewWidth > Val.getBitWidth()) {
+ // If this is an extension, just do it.
+ llvm::APSInt OldVal(Val);
+ Val.extend(NewWidth);
+
+ // If the input was signed and negative and the output is unsigned,
+ // warn.
+ if (!NewSign && OldVal.isSigned() && OldVal.isNegative())
+ Diag(Loc, DiagID) << OldVal.toString(10) << Val.toString(10);
+
+ Val.setIsSigned(NewSign);
+ } else if (NewWidth < Val.getBitWidth()) {
+ // If this is a truncation, check for overflow.
+ llvm::APSInt ConvVal(Val);
+ ConvVal.trunc(NewWidth);
+ ConvVal.setIsSigned(NewSign);
+ ConvVal.extend(Val.getBitWidth());
+ ConvVal.setIsSigned(Val.isSigned());
+ if (ConvVal != Val)
+ Diag(Loc, DiagID) << Val.toString(10) << ConvVal.toString(10);
+
+ // Regardless of whether a diagnostic was emitted, really do the
+ // truncation.
+ Val.trunc(NewWidth);
+ Val.setIsSigned(NewSign);
+ } else if (NewSign != Val.isSigned()) {
+ // Convert the sign to match the sign of the condition. This can cause
+ // overflow as well: unsigned(INTMIN)
+ llvm::APSInt OldVal(Val);
+ Val.setIsSigned(NewSign);
+
+ if (Val.isNegative()) // Sign bit changes meaning.
+ Diag(Loc, DiagID) << OldVal.toString(10) << Val.toString(10);
+ }
+}
+
+namespace {
+ struct CaseCompareFunctor {
+ bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS,
+ const llvm::APSInt &RHS) {
+ return LHS.first < RHS;
+ }
+ bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS,
+ const std::pair<llvm::APSInt, CaseStmt*> &RHS) {
+ return LHS.first < RHS.first;
+ }
+ bool operator()(const llvm::APSInt &LHS,
+ const std::pair<llvm::APSInt, CaseStmt*> &RHS) {
+ return LHS < RHS.first;
+ }
+ };
+}
+
+/// CmpCaseVals - Comparison predicate for sorting case values.
+///
+static bool CmpCaseVals(const std::pair<llvm::APSInt, CaseStmt*>& lhs,
+ const std::pair<llvm::APSInt, CaseStmt*>& rhs) {
+ if (lhs.first < rhs.first)
+ return true;
+
+ if (lhs.first == rhs.first &&
+ lhs.second->getCaseLoc().getRawEncoding()
+ < rhs.second->getCaseLoc().getRawEncoding())
+ return true;
+ return false;
+}
+
+Action::OwningStmtResult
+Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
+ StmtArg Body) {
+ Stmt *BodyStmt = Body.takeAs<Stmt>();
+
+ SwitchStmt *SS = getSwitchStack().back();
+ assert(SS == (SwitchStmt*)Switch.get() && "switch stack missing push/pop!");
+
+ SS->setBody(BodyStmt, SwitchLoc);
+ getSwitchStack().pop_back();
+
+ Expr *CondExpr = SS->getCond();
+ QualType CondType = CondExpr->getType();
+
+ if (!CondExpr->isTypeDependent() &&
+ !CondType->isIntegerType()) { // C99 6.8.4.2p1
+ Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer)
+ << CondType << CondExpr->getSourceRange();
+ return StmtError();
+ }
+
+ // Get the bitwidth of the switched-on value before promotions. We must
+ // convert the integer case values to this width before comparison.
+ bool HasDependentValue
+ = CondExpr->isTypeDependent() || CondExpr->isValueDependent();
+ unsigned CondWidth
+ = HasDependentValue? 0
+ : static_cast<unsigned>(Context.getTypeSize(CondType));
+ bool CondIsSigned = CondType->isSignedIntegerType();
+
+ // 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;
+ CaseValsTy CaseVals;
+
+ // Keep track of any GNU case ranges we see. The APSInt is the low value.
+ std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRanges;
+
+ DefaultStmt *TheDefaultStmt = 0;
+
+ bool CaseListIsErroneous = false;
+
+ for (SwitchCase *SC = SS->getSwitchCaseList(); SC && !HasDependentValue;
+ SC = SC->getNextSwitchCase()) {
+
+ if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC)) {
+ if (TheDefaultStmt) {
+ Diag(DS->getDefaultLoc(), diag::err_multiple_default_labels_defined);
+ Diag(TheDefaultStmt->getDefaultLoc(), diag::note_duplicate_case_prev);
+
+ // FIXME: Remove the default statement from the switch block so that
+ // we'll return a valid AST. This requires recursing down the AST and
+ // finding it, not something we are set up to do right now. For now,
+ // just lop the entire switch stmt out of the AST.
+ CaseListIsErroneous = true;
+ }
+ TheDefaultStmt = DS;
+
+ } else {
+ CaseStmt *CS = cast<CaseStmt>(SC);
+
+ // We already verified that the expression has a i-c-e value (C99
+ // 6.8.4.2p3) - get that value now.
+ Expr *Lo = CS->getLHS();
+
+ if (Lo->isTypeDependent() || Lo->isValueDependent()) {
+ HasDependentValue = true;
+ break;
+ }
+
+ llvm::APSInt LoVal = Lo->EvaluateAsInt(Context);
+
+ // Convert the value to the same width/sign as the condition.
+ ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned,
+ CS->getLHS()->getLocStart(),
+ diag::warn_case_value_overflow);
+
+ // If the LHS is not the same type as the condition, insert an implicit
+ // cast.
+ ImpCastExprToType(Lo, CondType);
+ CS->setLHS(Lo);
+
+ // If this is a case range, remember it in CaseRanges, otherwise CaseVals.
+ if (CS->getRHS()) {
+ if (CS->getRHS()->isTypeDependent() ||
+ CS->getRHS()->isValueDependent()) {
+ HasDependentValue = true;
+ break;
+ }
+ CaseRanges.push_back(std::make_pair(LoVal, CS));
+ } else
+ CaseVals.push_back(std::make_pair(LoVal, CS));
+ }
+ }
+
+ if (!HasDependentValue) {
+ // Sort all the scalar case values so we can easily detect duplicates.
+ std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals);
+
+ if (!CaseVals.empty()) {
+ for (unsigned i = 0, e = CaseVals.size()-1; i != e; ++i) {
+ if (CaseVals[i].first == CaseVals[i+1].first) {
+ // If we have a duplicate, report it.
+ Diag(CaseVals[i+1].second->getLHS()->getLocStart(),
+ diag::err_duplicate_case) << CaseVals[i].first.toString(10);
+ Diag(CaseVals[i].second->getLHS()->getLocStart(),
+ diag::note_duplicate_case_prev);
+ // FIXME: We really want to remove the bogus case stmt from the
+ // substmt, but we have no way to do this right now.
+ CaseListIsErroneous = true;
+ }
+ }
+ }
+
+ // Detect duplicate case ranges, which usually don't exist at all in
+ // the first place.
+ if (!CaseRanges.empty()) {
+ // Sort all the case ranges by their low value so we can easily detect
+ // overlaps between ranges.
+ std::stable_sort(CaseRanges.begin(), CaseRanges.end());
+
+ // Scan the ranges, computing the high values and removing empty ranges.
+ std::vector<llvm::APSInt> HiVals;
+ for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) {
+ CaseStmt *CR = CaseRanges[i].second;
+ Expr *Hi = CR->getRHS();
+ llvm::APSInt HiVal = Hi->EvaluateAsInt(Context);
+
+ // Convert the value to the same width/sign as the condition.
+ ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned,
+ CR->getRHS()->getLocStart(),
+ diag::warn_case_value_overflow);
+
+ // If the LHS is not the same type as the condition, insert an implicit
+ // cast.
+ ImpCastExprToType(Hi, CondType);
+ CR->setRHS(Hi);
+
+ // If the low value is bigger than the high value, the case is empty.
+ if (CaseRanges[i].first > HiVal) {
+ Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range)
+ << SourceRange(CR->getLHS()->getLocStart(),
+ CR->getRHS()->getLocEnd());
+ CaseRanges.erase(CaseRanges.begin()+i);
+ --i, --e;
+ continue;
+ }
+ HiVals.push_back(HiVal);
+ }
+
+ // Rescan the ranges, looking for overlap with singleton values and other
+ // ranges. Since the range list is sorted, we only need to compare case
+ // ranges with their neighbors.
+ for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) {
+ llvm::APSInt &CRLo = CaseRanges[i].first;
+ llvm::APSInt &CRHi = HiVals[i];
+ CaseStmt *CR = CaseRanges[i].second;
+
+ // Check to see whether the case range overlaps with any
+ // singleton cases.
+ CaseStmt *OverlapStmt = 0;
+ llvm::APSInt OverlapVal(32);
+
+ // Find the smallest value >= the lower bound. If I is in the
+ // case range, then we have overlap.
+ CaseValsTy::iterator I = std::lower_bound(CaseVals.begin(),
+ CaseVals.end(), CRLo,
+ CaseCompareFunctor());
+ if (I != CaseVals.end() && I->first < CRHi) {
+ OverlapVal = I->first; // Found overlap with scalar.
+ OverlapStmt = I->second;
+ }
+
+ // Find the smallest value bigger than the upper bound.
+ I = std::upper_bound(I, CaseVals.end(), CRHi, CaseCompareFunctor());
+ if (I != CaseVals.begin() && (I-1)->first >= CRLo) {
+ OverlapVal = (I-1)->first; // Found overlap with scalar.
+ OverlapStmt = (I-1)->second;
+ }
+
+ // Check to see if this case stmt overlaps with the subsequent
+ // case range.
+ if (i && CRLo <= HiVals[i-1]) {
+ OverlapVal = HiVals[i-1]; // Found overlap with range.
+ OverlapStmt = CaseRanges[i-1].second;
+ }
+
+ if (OverlapStmt) {
+ // If we have a duplicate, report it.
+ Diag(CR->getLHS()->getLocStart(), diag::err_duplicate_case)
+ << OverlapVal.toString(10);
+ Diag(OverlapStmt->getLHS()->getLocStart(),
+ diag::note_duplicate_case_prev);
+ // FIXME: We really want to remove the bogus case stmt from the
+ // substmt, but we have no way to do this right now.
+ CaseListIsErroneous = true;
+ }
+ }
+ }
+ }
+
+ // FIXME: If the case list was broken is some way, we don't have a good system
+ // to patch it up. Instead, just return the whole substmt as broken.
+ if (CaseListIsErroneous)
+ return StmtError();
+
+ Switch.release();
+ return Owned(SS);
+}
+
+Action::OwningStmtResult
+Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, StmtArg Body) {
+ ExprArg CondArg(Cond.release());
+ Expr *condExpr = CondArg.takeAs<Expr>();
+ assert(condExpr && "ActOnWhileStmt(): missing expression");
+
+ if (!condExpr->isTypeDependent()) {
+ DefaultFunctionArrayConversion(condExpr);
+ CondArg = condExpr;
+ QualType condType = condExpr->getType();
+
+ if (getLangOptions().CPlusPlus) {
+ if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4
+ return StmtError();
+ } else if (!condType->isScalarType()) // C99 6.8.5p2
+ return StmtError(Diag(WhileLoc,
+ diag::err_typecheck_statement_requires_scalar)
+ << condType << condExpr->getSourceRange());
+ }
+
+ CondArg.release();
+ return Owned(new (Context) WhileStmt(condExpr, Body.takeAs<Stmt>(),
+ WhileLoc));
+}
+
+Action::OwningStmtResult
+Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
+ SourceLocation WhileLoc, ExprArg Cond) {
+ Expr *condExpr = Cond.takeAs<Expr>();
+ assert(condExpr && "ActOnDoStmt(): missing expression");
+
+ if (!condExpr->isTypeDependent()) {
+ DefaultFunctionArrayConversion(condExpr);
+ Cond = condExpr;
+ QualType condType = condExpr->getType();
+
+ if (getLangOptions().CPlusPlus) {
+ if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4
+ return StmtError();
+ } else if (!condType->isScalarType()) // C99 6.8.5p2
+ return StmtError(Diag(DoLoc,
+ diag::err_typecheck_statement_requires_scalar)
+ << condType << condExpr->getSourceRange());
+ }
+
+ Cond.release();
+ return Owned(new (Context) DoStmt(Body.takeAs<Stmt>(), condExpr, DoLoc,
+ WhileLoc));
+}
+
+Action::OwningStmtResult
+Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
+ StmtArg first, ExprArg second, ExprArg third,
+ SourceLocation RParenLoc, StmtArg body) {
+ Stmt *First = static_cast<Stmt*>(first.get());
+ Expr *Second = static_cast<Expr*>(second.get());
+ Expr *Third = static_cast<Expr*>(third.get());
+ Stmt *Body = static_cast<Stmt*>(body.get());
+
+ if (!getLangOptions().CPlusPlus) {
+ if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) {
+ // C99 6.8.5p3: The declaration part of a 'for' statement shall only
+ // declare identifiers for objects having storage class 'auto' or
+ // 'register'.
+ for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end();
+ DI!=DE; ++DI) {
+ VarDecl *VD = dyn_cast<VarDecl>(*DI);
+ if (VD && VD->isBlockVarDecl() && !VD->hasLocalStorage())
+ VD = 0;
+ if (VD == 0)
+ Diag((*DI)->getLocation(), diag::err_non_variable_decl_in_for);
+ // FIXME: mark decl erroneous!
+ }
+ }
+ }
+ if (Second && !Second->isTypeDependent()) {
+ DefaultFunctionArrayConversion(Second);
+ QualType SecondType = Second->getType();
+
+ if (getLangOptions().CPlusPlus) {
+ if (CheckCXXBooleanCondition(Second)) // C++ 6.4p4
+ return StmtError();
+ } else if (!SecondType->isScalarType()) // C99 6.8.5p2
+ return StmtError(Diag(ForLoc,
+ diag::err_typecheck_statement_requires_scalar)
+ << SecondType << Second->getSourceRange());
+ }
+ first.release();
+ second.release();
+ third.release();
+ body.release();
+ return Owned(new (Context) ForStmt(First, Second, Third, Body, ForLoc,
+ LParenLoc, RParenLoc));
+}
+
+Action::OwningStmtResult
+Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc,
+ StmtArg first, ExprArg second,
+ SourceLocation RParenLoc, StmtArg body) {
+ Stmt *First = static_cast<Stmt*>(first.get());
+ Expr *Second = static_cast<Expr*>(second.get());
+ Stmt *Body = static_cast<Stmt*>(body.get());
+ if (First) {
+ QualType FirstType;
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(First)) {
+ if (!DS->isSingleDecl())
+ return StmtError(Diag((*DS->decl_begin())->getLocation(),
+ diag::err_toomany_element_decls));
+
+ Decl *D = DS->getSingleDecl();
+ FirstType = cast<ValueDecl>(D)->getType();
+ // C99 6.8.5p3: The declaration part of a 'for' statement shall only
+ // declare identifiers for objects having storage class 'auto' or
+ // 'register'.
+ VarDecl *VD = cast<VarDecl>(D);
+ if (VD->isBlockVarDecl() && !VD->hasLocalStorage())
+ return StmtError(Diag(VD->getLocation(),
+ diag::err_non_variable_decl_in_for));
+ } else {
+ if (cast<Expr>(First)->isLvalue(Context) != Expr::LV_Valid)
+ return StmtError(Diag(First->getLocStart(),
+ diag::err_selector_element_not_lvalue)
+ << First->getSourceRange());
+
+ FirstType = static_cast<Expr*>(First)->getType();
+ }
+ if (!Context.isObjCObjectPointerType(FirstType))
+ Diag(ForLoc, diag::err_selector_element_type)
+ << FirstType << First->getSourceRange();
+ }
+ if (Second) {
+ DefaultFunctionArrayConversion(Second);
+ QualType SecondType = Second->getType();
+ if (!Context.isObjCObjectPointerType(SecondType))
+ Diag(ForLoc, diag::err_collection_expr_type)
+ << SecondType << Second->getSourceRange();
+ }
+ first.release();
+ second.release();
+ body.release();
+ return Owned(new (Context) ObjCForCollectionStmt(First, Second, Body,
+ ForLoc, RParenLoc));
+}
+
+Action::OwningStmtResult
+Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
+ IdentifierInfo *LabelII) {
+ // If we are in a block, reject all gotos for now.
+ if (CurBlock)
+ return StmtError(Diag(GotoLoc, diag::err_goto_in_block));
+
+ // Look up the record for this label identifier.
+ LabelStmt *&LabelDecl = getLabelMap()[LabelII];
+
+ // If we haven't seen this label yet, create a forward reference.
+ if (LabelDecl == 0)
+ LabelDecl = new (Context) LabelStmt(LabelLoc, LabelII, 0);
+
+ return Owned(new (Context) GotoStmt(LabelDecl, GotoLoc, LabelLoc));
+}
+
+Action::OwningStmtResult
+Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc,
+ ExprArg DestExp) {
+ // Convert operand to void*
+ Expr* E = DestExp.takeAs<Expr>();
+ if (!E->isTypeDependent()) {
+ QualType ETy = E->getType();
+ AssignConvertType ConvTy =
+ CheckSingleAssignmentConstraints(Context.VoidPtrTy, E);
+ if (DiagnoseAssignmentResult(ConvTy, StarLoc, Context.VoidPtrTy, ETy,
+ E, "passing"))
+ return StmtError();
+ }
+ return Owned(new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E));
+}
+
+Action::OwningStmtResult
+Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
+ Scope *S = CurScope->getContinueParent();
+ if (!S) {
+ // C99 6.8.6.2p1: A break shall appear only in or as a loop body.
+ return StmtError(Diag(ContinueLoc, diag::err_continue_not_in_loop));
+ }
+
+ return Owned(new (Context) ContinueStmt(ContinueLoc));
+}
+
+Action::OwningStmtResult
+Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
+ Scope *S = CurScope->getBreakParent();
+ if (!S) {
+ // C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body.
+ return StmtError(Diag(BreakLoc, diag::err_break_not_in_loop_or_switch));
+ }
+
+ return Owned(new (Context) BreakStmt(BreakLoc));
+}
+
+/// ActOnBlockReturnStmt - Utility routine to figure out block's return type.
+///
+Action::OwningStmtResult
+Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
+ // If this is the first return we've seen in the block, infer the type of
+ // the block from it.
+ if (CurBlock->ReturnType == 0) {
+ if (RetValExp) {
+ // Don't call UsualUnaryConversions(), since we don't want to do
+ // integer promotions here.
+ DefaultFunctionArrayConversion(RetValExp);
+ CurBlock->ReturnType = RetValExp->getType().getTypePtr();
+ } else
+ CurBlock->ReturnType = Context.VoidTy.getTypePtr();
+ }
+ QualType FnRetType = QualType(CurBlock->ReturnType, 0);
+
+ if (CurBlock->TheDecl->hasAttr<NoReturnAttr>()) {
+ Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr)
+ << getCurFunctionOrMethodDecl()->getDeclName();
+ return StmtError();
+ }
+
+ // 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.
+ if (CurBlock->ReturnType->isVoidType()) {
+ if (RetValExp) {
+ Diag(ReturnLoc, diag::err_return_block_has_expr);
+ RetValExp->Destroy(Context);
+ RetValExp = 0;
+ }
+ return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
+ }
+
+ if (!RetValExp)
+ return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
+
+ if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
+ // we have a non-void block with an expression, continue checking
+ QualType RetValType = RetValExp->getType();
+
+ // 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.
+ // FIXME: Leaks RetValExp.
+ if (PerformCopyInitialization(RetValExp, FnRetType, "returning"))
+ return StmtError();
+
+ if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+ }
+
+ return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
+}
+
+/// IsReturnCopyElidable - Whether returning @p RetExpr from a function that
+/// returns a @p RetType fulfills the criteria for copy elision (C++0x 12.8p15).
+static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType,
+ Expr *RetExpr) {
+ QualType ExprType = RetExpr->getType();
+ // - in a return statement in a function with ...
+ // ... a class return type ...
+ if (!RetType->isRecordType())
+ return false;
+ // ... the same cv-unqualified type as the function return type ...
+ if (Ctx.getCanonicalType(RetType).getUnqualifiedType() !=
+ Ctx.getCanonicalType(ExprType).getUnqualifiedType())
+ return false;
+ // ... the expression is the name of a non-volatile automatic object ...
+ // We ignore parentheses here.
+ // FIXME: Is this compliant?
+ const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens());
+ if (!DR)
+ return false;
+ const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
+ if (!VD)
+ return false;
+ return VD->hasLocalStorage() && !VD->getType()->isReferenceType()
+ && !VD->getType().isVolatileQualified();
+}
+
+Action::OwningStmtResult
+Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) {
+ Expr *RetValExp = rex->takeAs<Expr>();
+ if (CurBlock)
+ return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
+
+ QualType FnRetType;
+ if (const FunctionDecl *FD = getCurFunctionDecl()) {
+ FnRetType = FD->getResultType();
+ if (FD->hasAttr<NoReturnAttr>())
+ Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
+ << getCurFunctionOrMethodDecl()->getDeclName();
+ } else if (ObjCMethodDecl *MD = getCurMethodDecl())
+ FnRetType = MD->getResultType();
+ else // If we don't have a function/method context, bail.
+ return StmtError();
+
+ if (FnRetType->isVoidType()) {
+ if (RetValExp) {// C99 6.8.6.4p1 (ext_ since GCC warns)
+ unsigned D = diag::ext_return_has_expr;
+ if (RetValExp->getType()->isVoidType())
+ D = diag::ext_return_has_void_expr;
+
+ // return (some void expression); is legal in C++.
+ if (D != diag::ext_return_has_void_expr ||
+ !getLangOptions().CPlusPlus) {
+ NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
+ Diag(ReturnLoc, D)
+ << CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl)
+ << RetValExp->getSourceRange();
+ }
+ }
+ return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
+ }
+
+ if (!RetValExp && !FnRetType->isDependentType()) {
+ unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4
+ // C99 6.8.6.4p1 (ext_ since GCC warns)
+ if (getLangOptions().C99) DiagID = diag::ext_return_missing_expr;
+
+ if (FunctionDecl *FD = getCurFunctionDecl())
+ Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/;
+ else
+ Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/;
+ return Owned(new (Context) ReturnStmt(ReturnLoc, (Expr*)0));
+ }
+
+ if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
+ // we have a non-void function 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.
+
+ // C++0x 12.8p15: When certain criteria are met, an implementation is
+ // allowed to omit the copy construction of a class object, [...]
+ // - in a return statement in a function with a class return type, when
+ // the expression is the name of a non-volatile automatic object with
+ // the same cv-unqualified type as the function return type, the copy
+ // operation can be omitted [...]
+ // C++0x 12.8p16: When the criteria for elision of a copy operation are met
+ // and the object to be copied is designated by an lvalue, overload
+ // resolution to select the constructor for the copy is first performed
+ // as if the object were designated by an rvalue.
+ // Note that we only compute Elidable if we're in C++0x, since we don't
+ // care otherwise.
+ bool Elidable = getLangOptions().CPlusPlus0x ?
+ IsReturnCopyElidable(Context, FnRetType, RetValExp) :
+ false;
+
+ // In C++ the return statement is handled via a copy initialization.
+ // the C version of which boils down to CheckSingleAssignmentConstraints.
+ // FIXME: Leaks RetValExp on error.
+ if (PerformCopyInitialization(RetValExp, FnRetType, "returning", Elidable))
+ return StmtError();
+
+ if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+ }
+
+ return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
+}
+
+/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently
+/// ignore "noop" casts in places where an lvalue is required by an inline asm.
+/// We emulate this behavior when -fheinous-gnu-extensions is specified, but
+/// provide a strong guidance to not use it.
+///
+/// This method checks to see if the argument is an acceptable l-value and
+/// returns false if it is a case we can handle.
+static bool CheckAsmLValue(const Expr *E, Sema &S) {
+ if (E->isLvalue(S.Context) == Expr::LV_Valid)
+ return false; // Cool, this is an lvalue.
+
+ // Okay, this is not an lvalue, but perhaps it is the result of a cast that we
+ // are supposed to allow.
+ const Expr *E2 = E->IgnoreParenNoopCasts(S.Context);
+ if (E != E2 && E2->isLvalue(S.Context) == Expr::LV_Valid) {
+ if (!S.getLangOptions().HeinousExtensions)
+ S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue)
+ << E->getSourceRange();
+ else
+ S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue)
+ << E->getSourceRange();
+ // Accept, even if we emitted an error diagnostic.
+ return false;
+ }
+
+ // None of the above, just randomly invalid non-lvalue.
+ return true;
+}
+
+
+Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
+ bool IsSimple,
+ bool IsVolatile,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ std::string *Names,
+ MultiExprArg constraints,
+ MultiExprArg exprs,
+ ExprArg asmString,
+ MultiExprArg clobbers,
+ SourceLocation RParenLoc) {
+ unsigned NumClobbers = clobbers.size();
+ StringLiteral **Constraints =
+ reinterpret_cast<StringLiteral**>(constraints.get());
+ Expr **Exprs = reinterpret_cast<Expr **>(exprs.get());
+ StringLiteral *AsmString = cast<StringLiteral>((Expr *)asmString.get());
+ StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.get());
+
+ llvm::SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
+
+ // The parser verifies that there is a string literal here.
+ if (AsmString->isWide())
+ 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())
+ return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
+ << Literal->getSourceRange());
+
+ TargetInfo::ConstraintInfo Info(Literal->getStrData(),
+ Literal->getByteLength(),
+ Names[i]);
+ if (!Context.Target.validateOutputConstraint(Info))
+ return StmtError(Diag(Literal->getLocStart(),
+ diag::err_asm_invalid_output_constraint)
+ << Info.getConstraintStr());
+
+ // Check that the output exprs are valid lvalues.
+ Expr *OutputExpr = Exprs[i];
+ if (CheckAsmLValue(OutputExpr, *this)) {
+ return StmtError(Diag(OutputExpr->getLocStart(),
+ diag::err_asm_invalid_lvalue_in_output)
+ << OutputExpr->getSourceRange());
+ }
+
+ OutputConstraintInfos.push_back(Info);
+ }
+
+ llvm::SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
+
+ for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
+ StringLiteral *Literal = Constraints[i];
+ if (Literal->isWide())
+ return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
+ << Literal->getSourceRange());
+
+ TargetInfo::ConstraintInfo Info(Literal->getStrData(),
+ Literal->getByteLength(),
+ Names[i]);
+ if (!Context.Target.validateInputConstraint(OutputConstraintInfos.data(),
+ NumOutputs, Info)) {
+ return StmtError(Diag(Literal->getLocStart(),
+ diag::err_asm_invalid_input_constraint)
+ << Info.getConstraintStr());
+ }
+
+ Expr *InputExpr = Exprs[i];
+
+ // Only allow void types for memory constraints.
+ if (Info.allowsMemory() && !Info.allowsRegister()) {
+ if (CheckAsmLValue(InputExpr, *this))
+ return StmtError(Diag(InputExpr->getLocStart(),
+ diag::err_asm_invalid_lvalue_in_input)
+ << Info.getConstraintStr()
+ << InputExpr->getSourceRange());
+ }
+
+ if (Info.allowsRegister()) {
+ if (InputExpr->getType()->isVoidType()) {
+ return StmtError(Diag(InputExpr->getLocStart(),
+ diag::err_asm_invalid_type_in_input)
+ << InputExpr->getType() << Info.getConstraintStr()
+ << InputExpr->getSourceRange());
+ }
+ }
+
+ DefaultFunctionArrayConversion(Exprs[i]);
+
+ InputConstraintInfos.push_back(Info);
+ }
+
+ // Check that the clobbers are valid.
+ for (unsigned i = 0; i != NumClobbers; i++) {
+ StringLiteral *Literal = Clobbers[i];
+ if (Literal->isWide())
+ return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
+ << Literal->getSourceRange());
+
+ llvm::SmallString<16> Clobber(Literal->getStrData(),
+ Literal->getStrData() +
+ Literal->getByteLength());
+
+ if (!Context.Target.isValidGCCRegisterName(Clobber.c_str()))
+ return StmtError(Diag(Literal->getLocStart(),
+ diag::err_asm_unknown_register_name) << Clobber.c_str());
+ }
+
+ constraints.release();
+ exprs.release();
+ asmString.release();
+ clobbers.release();
+ AsmStmt *NS =
+ new (Context) AsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs,
+ Names, Constraints, Exprs, AsmString, NumClobbers,
+ Clobbers, RParenLoc);
+ // Validate the asm string, ensuring it makes sense given the operands we
+ // have.
+ llvm::SmallVector<AsmStmt::AsmStringPiece, 8> Pieces;
+ unsigned DiagOffs;
+ if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) {
+ Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID)
+ << AsmString->getSourceRange();
+ DeleteStmt(NS);
+ return StmtError();
+ }
+
+ // Validate tied input operands for type mismatches.
+ for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) {
+ TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
+
+ // If this is a tied constraint, verify that the output and input have
+ // either exactly the same type, or that they are int/ptr operands with the
+ // same size (int/long, int*/long, are ok etc).
+ if (!Info.hasTiedOperand()) continue;
+
+ unsigned TiedTo = Info.getTiedOperand();
+ Expr *OutputExpr = Exprs[TiedTo];
+ Expr *InputExpr = Exprs[i+NumOutputs];
+ QualType InTy = InputExpr->getType();
+ QualType OutTy = OutputExpr->getType();
+ if (Context.hasSameType(InTy, OutTy))
+ continue; // All types can be tied to themselves.
+
+ // Int/ptr operands have some special cases that we allow.
+ if ((OutTy->isIntegerType() || OutTy->isPointerType()) &&
+ (InTy->isIntegerType() || InTy->isPointerType())) {
+
+ // They are ok if they are the same size. Tying void* to int is ok if
+ // they are the same size, for example. This also allows tying void* to
+ // int*.
+ uint64_t OutSize = Context.getTypeSize(OutTy);
+ uint64_t InSize = Context.getTypeSize(InTy);
+ if (OutSize == InSize)
+ continue;
+
+ // If the smaller input/output operand is not mentioned in the asm string,
+ // then we can promote it and the asm string won't notice. Check this
+ // case now.
+ bool SmallerValueMentioned = false;
+ for (unsigned p = 0, e = Pieces.size(); p != e; ++p) {
+ AsmStmt::AsmStringPiece &Piece = Pieces[p];
+ if (!Piece.isOperand()) continue;
+
+ // If this is a reference to the input and if the input was the smaller
+ // one, then we have to reject this asm.
+ if (Piece.getOperandNo() == i+NumOutputs) {
+ if (InSize < OutSize) {
+ SmallerValueMentioned = true;
+ break;
+ }
+ }
+
+ // If this is a reference to the input and if the input was the smaller
+ // one, then we have to reject this asm.
+ if (Piece.getOperandNo() == TiedTo) {
+ if (InSize > OutSize) {
+ SmallerValueMentioned = true;
+ break;
+ }
+ }
+ }
+
+ // If the smaller value wasn't mentioned in the asm string, and if the
+ // output was a register, just extend the shorter one to the size of the
+ // larger one.
+ if (!SmallerValueMentioned &&
+ OutputConstraintInfos[TiedTo].allowsRegister())
+ continue;
+ }
+
+ Diag(InputExpr->getLocStart(),
+ diag::err_asm_tying_incompatible_types)
+ << InTy << OutTy << OutputExpr->getSourceRange()
+ << InputExpr->getSourceRange();
+ DeleteStmt(NS);
+ return StmtError();
+ }
+
+ return Owned(NS);
+}
+
+Action::OwningStmtResult
+Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
+ SourceLocation RParen, DeclPtrTy Parm,
+ StmtArg Body, StmtArg catchList) {
+ Stmt *CatchList = catchList.takeAs<Stmt>();
+ ParmVarDecl *PVD = cast_or_null<ParmVarDecl>(Parm.getAs<Decl>());
+
+ // PVD == 0 implies @catch(...).
+ if (PVD) {
+ // If we already know the decl is invalid, reject it.
+ if (PVD->isInvalidDecl())
+ return StmtError();
+
+ if (!Context.isObjCObjectPointerType(PVD->getType()))
+ return StmtError(Diag(PVD->getLocation(),
+ diag::err_catch_param_not_objc_type));
+ if (PVD->getType()->isObjCQualifiedIdType())
+ return StmtError(Diag(PVD->getLocation(),
+ diag::err_illegal_qualifiers_on_catch_parm));
+ }
+
+ ObjCAtCatchStmt *CS = new (Context) ObjCAtCatchStmt(AtLoc, RParen,
+ PVD, Body.takeAs<Stmt>(), CatchList);
+ return Owned(CatchList ? CatchList : CS);
+}
+
+Action::OwningStmtResult
+Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body) {
+ return Owned(new (Context) ObjCAtFinallyStmt(AtLoc,
+ static_cast<Stmt*>(Body.release())));
+}
+
+Action::OwningStmtResult
+Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc,
+ StmtArg Try, StmtArg Catch, StmtArg Finally) {
+ CurFunctionNeedsScopeChecking = true;
+ return Owned(new (Context) ObjCAtTryStmt(AtLoc, Try.takeAs<Stmt>(),
+ Catch.takeAs<Stmt>(),
+ Finally.takeAs<Stmt>()));
+}
+
+Action::OwningStmtResult
+Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) {
+ Expr *ThrowExpr = expr.takeAs<Expr>();
+ if (!ThrowExpr) {
+ // @throw without an expression designates a rethrow (which much occur
+ // in the context of an @catch clause).
+ Scope *AtCatchParent = CurScope;
+ while (AtCatchParent && !AtCatchParent->isAtCatchScope())
+ AtCatchParent = AtCatchParent->getParent();
+ if (!AtCatchParent)
+ return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch));
+ } else {
+ QualType ThrowType = ThrowExpr->getType();
+ // Make sure the expression type is an ObjC pointer or "void *".
+ if (!Context.isObjCObjectPointerType(ThrowType)) {
+ const PointerType *PT = ThrowType->getAsPointerType();
+ if (!PT || !PT->getPointeeType()->isVoidType())
+ return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object)
+ << ThrowExpr->getType() << ThrowExpr->getSourceRange());
+ }
+ }
+ return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowExpr));
+}
+
+Action::OwningStmtResult
+Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr,
+ StmtArg SynchBody) {
+ CurFunctionNeedsScopeChecking = true;
+
+ // Make sure the expression type is an ObjC pointer or "void *".
+ Expr *SyncExpr = static_cast<Expr*>(SynchExpr.get());
+ if (!Context.isObjCObjectPointerType(SyncExpr->getType())) {
+ const PointerType *PT = SyncExpr->getType()->getAsPointerType();
+ if (!PT || !PT->getPointeeType()->isVoidType())
+ return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object)
+ << SyncExpr->getType() << SyncExpr->getSourceRange());
+ }
+
+ return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc,
+ SynchExpr.takeAs<Stmt>(),
+ SynchBody.takeAs<Stmt>()));
+}
+
+/// ActOnCXXCatchBlock - Takes an exception declaration and a handler block
+/// and creates a proper catch handler from them.
+Action::OwningStmtResult
+Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, DeclPtrTy ExDecl,
+ StmtArg HandlerBlock) {
+ // There's nothing to test that ActOnExceptionDecl didn't already test.
+ return Owned(new (Context) CXXCatchStmt(CatchLoc,
+ cast_or_null<VarDecl>(ExDecl.getAs<Decl>()),
+ HandlerBlock.takeAs<Stmt>()));
+}
+
+/// ActOnCXXTryBlock - Takes a try compound-statement and a number of
+/// handlers and creates a try statement from them.
+Action::OwningStmtResult
+Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock,
+ MultiStmtArg RawHandlers) {
+ unsigned NumHandlers = RawHandlers.size();
+ assert(NumHandlers > 0 &&
+ "The parser shouldn't call this if there are no handlers.");
+ Stmt **Handlers = reinterpret_cast<Stmt**>(RawHandlers.get());
+
+ for(unsigned i = 0; i < NumHandlers - 1; ++i) {
+ CXXCatchStmt *Handler = llvm::cast<CXXCatchStmt>(Handlers[i]);
+ if (!Handler->getExceptionDecl())
+ return StmtError(Diag(Handler->getLocStart(), diag::err_early_catch_all));
+ }
+ // FIXME: We should detect handlers for the same type as an earlier one.
+ // This one is rather easy.
+ // FIXME: We should detect handlers that cannot catch anything because an
+ // earlier handler catches a superclass. Need to find a method that is not
+ // quadratic for this.
+ // Neither of these are explicitly forbidden, but every compiler detects them
+ // and warns.
+
+ CurFunctionNeedsScopeChecking = true;
+ RawHandlers.release();
+ return Owned(new (Context) CXXTryStmt(TryLoc,
+ static_cast<Stmt*>(TryBlock.release()),
+ Handlers, NumHandlers));
+}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
new file mode 100644
index 000000000000..782a0d87d897
--- /dev/null
+++ b/lib/Sema/SemaTemplate.cpp
@@ -0,0 +1,2651 @@
+//===------- SemaTemplate.cpp - Semantic Analysis for C++ Templates -------===/
+
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===/
+
+//
+// This file implements semantic analysis for C++ templates.
+//===----------------------------------------------------------------------===/
+
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Basic/LangOptions.h"
+
+using namespace clang;
+
+/// isTemplateName - Determines whether the identifier II is a
+/// template name in the current scope, and returns the template
+/// declaration if II names a template. An optional CXXScope can be
+/// passed to indicate the C++ scope in which the identifier will be
+/// found.
+TemplateNameKind Sema::isTemplateName(const IdentifierInfo &II, Scope *S,
+ TemplateTy &TemplateResult,
+ const CXXScopeSpec *SS) {
+ NamedDecl *IIDecl = LookupParsedName(S, SS, &II, LookupOrdinaryName);
+
+ TemplateNameKind TNK = TNK_Non_template;
+ TemplateDecl *Template = 0;
+
+ if (IIDecl) {
+ if ((Template = dyn_cast<TemplateDecl>(IIDecl))) {
+ if (isa<FunctionTemplateDecl>(IIDecl))
+ TNK = TNK_Function_template;
+ else if (isa<ClassTemplateDecl>(IIDecl) ||
+ isa<TemplateTemplateParmDecl>(IIDecl))
+ TNK = TNK_Type_template;
+ else
+ assert(false && "Unknown template declaration kind");
+ } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(IIDecl)) {
+ // C++ [temp.local]p1:
+ // Like normal (non-template) classes, class templates have an
+ // injected-class-name (Clause 9). The injected-class-name
+ // can be used with or without a template-argument-list. When
+ // it is used without a template-argument-list, it is
+ // equivalent to the injected-class-name followed by the
+ // template-parameters of the class template enclosed in
+ // <>. When it is used with a template-argument-list, it
+ // refers to the specified class template specialization,
+ // which could be the current specialization or another
+ // specialization.
+ if (Record->isInjectedClassName()) {
+ Record = cast<CXXRecordDecl>(Context.getCanonicalDecl(Record));
+ if ((Template = Record->getDescribedClassTemplate()))
+ TNK = TNK_Type_template;
+ else if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
+ Template = Spec->getSpecializedTemplate();
+ TNK = TNK_Type_template;
+ }
+ }
+ }
+
+ // FIXME: What follows is a gross hack.
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(IIDecl)) {
+ if (FD->getType()->isDependentType()) {
+ TemplateResult = TemplateTy::make(FD);
+ return TNK_Function_template;
+ }
+ } else if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(IIDecl)) {
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F) {
+ if ((*F)->getType()->isDependentType()) {
+ TemplateResult = TemplateTy::make(Ovl);
+ return TNK_Function_template;
+ }
+ }
+ }
+
+ if (TNK != TNK_Non_template) {
+ if (SS && SS->isSet() && !SS->isInvalid()) {
+ NestedNameSpecifier *Qualifier
+ = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
+ TemplateResult
+ = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier,
+ false,
+ Template));
+ } else
+ TemplateResult = TemplateTy::make(TemplateName(Template));
+ }
+ }
+ return TNK;
+}
+
+/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
+/// that the template parameter 'PrevDecl' is being shadowed by a new
+/// declaration at location Loc. Returns true to indicate that this is
+/// an error, and false otherwise.
+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)
+ return false;
+
+ // C++ [temp.local]p4:
+ // A template-parameter shall not be redeclared within its
+ // scope (including nested scopes).
+ Diag(Loc, diag::err_template_param_shadow)
+ << cast<NamedDecl>(PrevDecl)->getDeclName();
+ Diag(PrevDecl->getLocation(), diag::note_template_param_here);
+ return true;
+}
+
+/// AdjustDeclIfTemplate - If the given decl happens to be a template, reset
+/// the parameter D to reference the templated declaration and return a pointer
+/// to the template declaration. Otherwise, do nothing to D and return null.
+TemplateDecl *Sema::AdjustDeclIfTemplate(DeclPtrTy &D) {
+ if (TemplateDecl *Temp = dyn_cast<TemplateDecl>(D.getAs<Decl>())) {
+ D = DeclPtrTy::make(Temp->getTemplatedDecl());
+ return Temp;
+ }
+ return 0;
+}
+
+/// ActOnTypeParameter - Called when a C++ template type parameter
+/// (e.g., "typename T") has been parsed. Typename specifies whether
+/// the keyword "typename" was used to declare the type parameter
+/// (otherwise, "class" was used), and KeyLoc is the location of the
+/// "class" or "typename" keyword. ParamName is the name of the
+/// parameter (NULL indicates an unnamed template parameter) and
+/// ParamName is the location of the parameter name (if any).
+/// If the type parameter has a default argument, it will be added
+/// later via ActOnTypeParameterDefault.
+Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename,
+ SourceLocation KeyLoc,
+ IdentifierInfo *ParamName,
+ SourceLocation ParamNameLoc,
+ unsigned Depth, unsigned Position) {
+ assert(S->isTemplateParamScope() &&
+ "Template type parameter not in template parameter scope!");
+ bool Invalid = false;
+
+ if (ParamName) {
+ NamedDecl *PrevDecl = LookupName(S, ParamName, LookupTagName);
+ if (PrevDecl && PrevDecl->isTemplateParameter())
+ Invalid = Invalid || DiagnoseTemplateParameterShadow(ParamNameLoc,
+ PrevDecl);
+ }
+
+ SourceLocation Loc = ParamNameLoc;
+ if (!ParamName)
+ Loc = KeyLoc;
+
+ TemplateTypeParmDecl *Param
+ = TemplateTypeParmDecl::Create(Context, CurContext, Loc,
+ Depth, Position, ParamName, Typename);
+ if (Invalid)
+ Param->setInvalidDecl();
+
+ if (ParamName) {
+ // Add the template parameter into the current scope.
+ S->AddDecl(DeclPtrTy::make(Param));
+ IdResolver.AddDecl(Param);
+ }
+
+ return DeclPtrTy::make(Param);
+}
+
+/// ActOnTypeParameterDefault - Adds a default argument (the type
+/// Default) to the given template type parameter (TypeParam).
+void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam,
+ SourceLocation EqualLoc,
+ SourceLocation DefaultLoc,
+ TypeTy *DefaultT) {
+ TemplateTypeParmDecl *Parm
+ = cast<TemplateTypeParmDecl>(TypeParam.getAs<Decl>());
+ QualType Default = QualType::getFromOpaquePtr(DefaultT);
+
+ // C++ [temp.param]p14:
+ // A template-parameter shall not be used in its own default argument.
+ // FIXME: Implement this check! Needs a recursive walk over the types.
+
+ // Check the template argument itself.
+ if (CheckTemplateArgument(Parm, Default, DefaultLoc)) {
+ Parm->setInvalidDecl();
+ return;
+ }
+
+ Parm->setDefaultArgument(Default, DefaultLoc, false);
+}
+
+/// \brief Check that the type of a non-type template parameter is
+/// well-formed.
+///
+/// \returns the (possibly-promoted) parameter type if valid;
+/// otherwise, produces a diagnostic and returns a NULL type.
+QualType
+Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
+ // C++ [temp.param]p4:
+ //
+ // A non-type template-parameter shall have one of the following
+ // (optionally cv-qualified) types:
+ //
+ // -- integral or enumeration type,
+ if (T->isIntegralType() || T->isEnumeralType() ||
+ // -- pointer to object or pointer to function,
+ (T->isPointerType() &&
+ (T->getAsPointerType()->getPointeeType()->isObjectType() ||
+ T->getAsPointerType()->getPointeeType()->isFunctionType())) ||
+ // -- reference to object or reference to function,
+ T->isReferenceType() ||
+ // -- pointer to member.
+ T->isMemberPointerType() ||
+ // If T is a dependent type, we can't do the check now, so we
+ // assume that it is well-formed.
+ T->isDependentType())
+ return T;
+ // C++ [temp.param]p8:
+ //
+ // A non-type template-parameter of type "array of T" or
+ // "function returning T" is adjusted to be of type "pointer to
+ // T" or "pointer to function returning T", respectively.
+ else if (T->isArrayType())
+ // FIXME: Keep the type prior to promotion?
+ return Context.getArrayDecayedType(T);
+ else if (T->isFunctionType())
+ // FIXME: Keep the type prior to promotion?
+ return Context.getPointerType(T);
+
+ Diag(Loc, diag::err_template_nontype_parm_bad_type)
+ << T;
+
+ return QualType();
+}
+
+/// ActOnNonTypeTemplateParameter - Called when a C++ non-type
+/// template parameter (e.g., "int Size" in "template<int Size>
+/// class Array") has been parsed. S is the current scope and D is
+/// the parsed declarator.
+Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
+ unsigned Depth,
+ unsigned Position) {
+ QualType T = GetTypeForDeclarator(D, S);
+
+ assert(S->isTemplateParamScope() &&
+ "Non-type template parameter not in template parameter scope!");
+ bool Invalid = false;
+
+ IdentifierInfo *ParamName = D.getIdentifier();
+ if (ParamName) {
+ NamedDecl *PrevDecl = LookupName(S, ParamName, LookupTagName);
+ if (PrevDecl && PrevDecl->isTemplateParameter())
+ Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
+ PrevDecl);
+ }
+
+ T = CheckNonTypeTemplateParameterType(T, D.getIdentifierLoc());
+ if (T.isNull()) {
+ T = Context.IntTy; // Recover with an 'int' type.
+ Invalid = true;
+ }
+
+ NonTypeTemplateParmDecl *Param
+ = NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(),
+ Depth, Position, ParamName, T);
+ if (Invalid)
+ Param->setInvalidDecl();
+
+ if (D.getIdentifier()) {
+ // Add the template parameter into the current scope.
+ S->AddDecl(DeclPtrTy::make(Param));
+ IdResolver.AddDecl(Param);
+ }
+ return DeclPtrTy::make(Param);
+}
+
+/// \brief Adds a default argument to the given non-type template
+/// parameter.
+void Sema::ActOnNonTypeTemplateParameterDefault(DeclPtrTy TemplateParamD,
+ SourceLocation EqualLoc,
+ ExprArg DefaultE) {
+ NonTypeTemplateParmDecl *TemplateParm
+ = cast<NonTypeTemplateParmDecl>(TemplateParamD.getAs<Decl>());
+ Expr *Default = static_cast<Expr *>(DefaultE.get());
+
+ // C++ [temp.param]p14:
+ // A template-parameter shall not be used in its own default argument.
+ // FIXME: Implement this check! Needs a recursive walk over the types.
+
+ // Check the well-formedness of the default template argument.
+ if (CheckTemplateArgument(TemplateParm, TemplateParm->getType(), Default)) {
+ TemplateParm->setInvalidDecl();
+ return;
+ }
+
+ TemplateParm->setDefaultArgument(DefaultE.takeAs<Expr>());
+}
+
+
+/// ActOnTemplateTemplateParameter - Called when a C++ template template
+/// parameter (e.g. T in template <template <typename> class T> class array)
+/// has been parsed. S is the current scope.
+Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S,
+ SourceLocation TmpLoc,
+ TemplateParamsTy *Params,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ unsigned Depth,
+ unsigned Position)
+{
+ assert(S->isTemplateParamScope() &&
+ "Template template parameter not in template parameter scope!");
+
+ // Construct the parameter object.
+ TemplateTemplateParmDecl *Param =
+ TemplateTemplateParmDecl::Create(Context, CurContext, TmpLoc, Depth,
+ Position, Name,
+ (TemplateParameterList*)Params);
+
+ // Make sure the parameter is valid.
+ // FIXME: Decl object is not currently invalidated anywhere so this doesn't
+ // do anything yet. However, if the template parameter list or (eventual)
+ // default value is ever invalidated, that will propagate here.
+ bool Invalid = false;
+ if (Invalid) {
+ Param->setInvalidDecl();
+ }
+
+ // If the tt-param has a name, then link the identifier into the scope
+ // and lookup mechanisms.
+ if (Name) {
+ S->AddDecl(DeclPtrTy::make(Param));
+ IdResolver.AddDecl(Param);
+ }
+
+ return DeclPtrTy::make(Param);
+}
+
+/// \brief Adds a default argument to the given template template
+/// parameter.
+void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD,
+ SourceLocation EqualLoc,
+ ExprArg DefaultE) {
+ TemplateTemplateParmDecl *TemplateParm
+ = cast<TemplateTemplateParmDecl>(TemplateParamD.getAs<Decl>());
+
+ // Since a template-template parameter's default argument is an
+ // id-expression, it must be a DeclRefExpr.
+ DeclRefExpr *Default
+ = cast<DeclRefExpr>(static_cast<Expr *>(DefaultE.get()));
+
+ // C++ [temp.param]p14:
+ // A template-parameter shall not be used in its own default argument.
+ // FIXME: Implement this check! Needs a recursive walk over the types.
+
+ // Check the well-formedness of the template argument.
+ if (!isa<TemplateDecl>(Default->getDecl())) {
+ Diag(Default->getSourceRange().getBegin(),
+ diag::err_template_arg_must_be_template)
+ << Default->getSourceRange();
+ TemplateParm->setInvalidDecl();
+ return;
+ }
+ if (CheckTemplateArgument(TemplateParm, Default)) {
+ TemplateParm->setInvalidDecl();
+ return;
+ }
+
+ DefaultE.release();
+ TemplateParm->setDefaultArgument(Default);
+}
+
+/// ActOnTemplateParameterList - Builds a TemplateParameterList that
+/// contains the template parameters in Params/NumParams.
+Sema::TemplateParamsTy *
+Sema::ActOnTemplateParameterList(unsigned Depth,
+ SourceLocation ExportLoc,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ DeclPtrTy *Params, unsigned NumParams,
+ SourceLocation RAngleLoc) {
+ if (ExportLoc.isValid())
+ Diag(ExportLoc, diag::note_template_export_unsupported);
+
+ return TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
+ (Decl**)Params, NumParams, RAngleLoc);
+}
+
+Sema::DeclResult
+Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
+ SourceLocation KWLoc, const CXXScopeSpec &SS,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ AttributeList *Attr,
+ MultiTemplateParamsArg TemplateParameterLists,
+ AccessSpecifier AS) {
+ assert(TemplateParameterLists.size() > 0 && "No template parameter lists?");
+ assert(TK != TK_Reference && "Can only declare or define class templates");
+ bool Invalid = false;
+
+ // Check that we can declare a template here.
+ if (CheckTemplateDeclScope(S, TemplateParameterLists))
+ return true;
+
+ TagDecl::TagKind Kind;
+ switch (TagSpec) {
+ default: assert(0 && "Unknown tag type!");
+ case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
+ case DeclSpec::TST_union: Kind = TagDecl::TK_union; break;
+ case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
+ }
+
+ // There is no such thing as an unnamed class template.
+ if (!Name) {
+ Diag(KWLoc, diag::err_template_unnamed_class);
+ return true;
+ }
+
+ // Find any previous declaration with this name.
+ LookupResult Previous = LookupParsedName(S, &SS, Name, LookupOrdinaryName,
+ true);
+ assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?");
+ NamedDecl *PrevDecl = 0;
+ if (Previous.begin() != Previous.end())
+ PrevDecl = *Previous.begin();
+
+ DeclContext *SemanticContext = CurContext;
+ if (SS.isNotEmpty() && !SS.isInvalid()) {
+ SemanticContext = computeDeclContext(SS);
+
+ // FIXME: need to match up several levels of template parameter lists here.
+ }
+
+ // FIXME: member templates!
+ TemplateParameterList *TemplateParams
+ = static_cast<TemplateParameterList *>(*TemplateParameterLists.release());
+
+ // If there is a previous declaration with the same name, check
+ // whether this is a valid redeclaration.
+ ClassTemplateDecl *PrevClassTemplate
+ = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl);
+ if (PrevClassTemplate) {
+ // Ensure that the template parameter lists are compatible.
+ if (!TemplateParameterListsAreEqual(TemplateParams,
+ PrevClassTemplate->getTemplateParameters(),
+ /*Complain=*/true))
+ return true;
+
+ // C++ [temp.class]p4:
+ // In a redeclaration, partial specialization, explicit
+ // specialization or explicit instantiation of a class template,
+ // the class-key shall agree in kind with the original class
+ // template declaration (7.1.5.3).
+ RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl();
+ if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, KWLoc, *Name)) {
+ Diag(KWLoc, diag::err_use_with_wrong_tag)
+ << Name
+ << CodeModificationHint::CreateReplacement(KWLoc,
+ PrevRecordDecl->getKindName());
+ Diag(PrevRecordDecl->getLocation(), diag::note_previous_use);
+ Kind = PrevRecordDecl->getTagKind();
+ }
+
+ // Check for redefinition of this class template.
+ if (TK == TK_Definition) {
+ if (TagDecl *Def = PrevRecordDecl->getDefinition(Context)) {
+ Diag(NameLoc, diag::err_redefinition) << Name;
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ // FIXME: Would it make sense to try to "forget" the previous
+ // 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);
+ // Just pretend that we didn't see the previous declaration.
+ PrevDecl = 0;
+ } else if (PrevDecl) {
+ // C++ [temp]p5:
+ // A class template shall not have the same name as any other
+ // template, class, function, object, enumeration, enumerator,
+ // namespace, or type in the same scope (3.3), except as specified
+ // in (14.5.4).
+ Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ return true;
+ }
+
+ // Check the template parameter list of this declaration, possibly
+ // merging in the template parameter list from the previous class
+ // template declaration.
+ if (CheckTemplateParameterList(TemplateParams,
+ PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0))
+ Invalid = true;
+
+ // FIXME: If we had a scope specifier, we better have a previous template
+ // declaration!
+
+ CXXRecordDecl *NewClass =
+ CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name,
+ PrevClassTemplate?
+ PrevClassTemplate->getTemplatedDecl() : 0,
+ /*DelayTypeCreation=*/true);
+
+ ClassTemplateDecl *NewTemplate
+ = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
+ DeclarationName(Name), TemplateParams,
+ NewClass, PrevClassTemplate);
+ NewClass->setDescribedClassTemplate(NewTemplate);
+
+ // Build the type for the class template declaration now.
+ QualType T =
+ Context.getTypeDeclType(NewClass,
+ PrevClassTemplate?
+ PrevClassTemplate->getTemplatedDecl() : 0);
+ assert(T->isDependentType() && "Class template type is not dependent?");
+ (void)T;
+
+ // Set the access specifier.
+ SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
+
+ // Set the lexical context of these templates
+ NewClass->setLexicalDeclContext(CurContext);
+ NewTemplate->setLexicalDeclContext(CurContext);
+
+ if (TK == TK_Definition)
+ NewClass->startDefinition();
+
+ if (Attr)
+ ProcessDeclAttributeList(NewClass, Attr);
+
+ PushOnScopeChains(NewTemplate, S);
+
+ if (Invalid) {
+ NewTemplate->setInvalidDecl();
+ NewClass->setInvalidDecl();
+ }
+ return DeclPtrTy::make(NewTemplate);
+}
+
+/// \brief Checks the validity of a template parameter list, possibly
+/// considering the template parameter list from a previous
+/// declaration.
+///
+/// If an "old" template parameter list is provided, it must be
+/// equivalent (per TemplateParameterListsAreEqual) to the "new"
+/// template parameter list.
+///
+/// \param NewParams Template parameter list for a new template
+/// declaration. This template parameter list will be updated with any
+/// default arguments that are carried through from the previous
+/// template parameter list.
+///
+/// \param OldParams If provided, template parameter list from a
+/// previous declaration of the same template. Default template
+/// arguments will be merged from the old template parameter list to
+/// the new template parameter list.
+///
+/// \returns true if an error occurred, false otherwise.
+bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
+ TemplateParameterList *OldParams) {
+ bool Invalid = false;
+
+ // C++ [temp.param]p10:
+ // The set of default template-arguments available for use with a
+ // template declaration or definition is obtained by merging the
+ // default arguments from the definition (if in scope) and all
+ // declarations in scope in the same way default function
+ // arguments are (8.3.6).
+ bool SawDefaultArgument = false;
+ SourceLocation PreviousDefaultArgLoc;
+
+ // Dummy initialization to avoid warnings.
+ TemplateParameterList::iterator OldParam = NewParams->end();
+ if (OldParams)
+ OldParam = OldParams->begin();
+
+ for (TemplateParameterList::iterator NewParam = NewParams->begin(),
+ NewParamEnd = NewParams->end();
+ NewParam != NewParamEnd; ++NewParam) {
+ // Variables used to diagnose redundant default arguments
+ bool RedundantDefaultArg = false;
+ SourceLocation OldDefaultLoc;
+ SourceLocation NewDefaultLoc;
+
+ // Variables used to diagnose missing default arguments
+ bool MissingDefaultArg = false;
+
+ // Merge default arguments for template type parameters.
+ if (TemplateTypeParmDecl *NewTypeParm
+ = dyn_cast<TemplateTypeParmDecl>(*NewParam)) {
+ TemplateTypeParmDecl *OldTypeParm
+ = OldParams? cast<TemplateTypeParmDecl>(*OldParam) : 0;
+
+ if (OldTypeParm && OldTypeParm->hasDefaultArgument() &&
+ NewTypeParm->hasDefaultArgument()) {
+ OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc();
+ NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc();
+ SawDefaultArgument = true;
+ RedundantDefaultArg = true;
+ PreviousDefaultArgLoc = NewDefaultLoc;
+ } else if (OldTypeParm && OldTypeParm->hasDefaultArgument()) {
+ // Merge the default argument from the old declaration to the
+ // new declaration.
+ SawDefaultArgument = true;
+ NewTypeParm->setDefaultArgument(OldTypeParm->getDefaultArgument(),
+ OldTypeParm->getDefaultArgumentLoc(),
+ true);
+ PreviousDefaultArgLoc = OldTypeParm->getDefaultArgumentLoc();
+ } else if (NewTypeParm->hasDefaultArgument()) {
+ SawDefaultArgument = true;
+ PreviousDefaultArgLoc = NewTypeParm->getDefaultArgumentLoc();
+ } else if (SawDefaultArgument)
+ MissingDefaultArg = true;
+ }
+ // Merge default arguments for non-type template parameters
+ else if (NonTypeTemplateParmDecl *NewNonTypeParm
+ = dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
+ NonTypeTemplateParmDecl *OldNonTypeParm
+ = OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : 0;
+ if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
+ NewNonTypeParm->hasDefaultArgument()) {
+ OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
+ NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc();
+ SawDefaultArgument = true;
+ RedundantDefaultArg = true;
+ PreviousDefaultArgLoc = NewDefaultLoc;
+ } else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument()) {
+ // Merge the default argument from the old declaration to the
+ // new declaration.
+ SawDefaultArgument = true;
+ // FIXME: We need to create a new kind of "default argument"
+ // expression that points to a previous template template
+ // parameter.
+ NewNonTypeParm->setDefaultArgument(
+ OldNonTypeParm->getDefaultArgument());
+ PreviousDefaultArgLoc = OldNonTypeParm->getDefaultArgumentLoc();
+ } else if (NewNonTypeParm->hasDefaultArgument()) {
+ SawDefaultArgument = true;
+ PreviousDefaultArgLoc = NewNonTypeParm->getDefaultArgumentLoc();
+ } else if (SawDefaultArgument)
+ MissingDefaultArg = true;
+ }
+ // Merge default arguments for template template parameters
+ else {
+ TemplateTemplateParmDecl *NewTemplateParm
+ = cast<TemplateTemplateParmDecl>(*NewParam);
+ TemplateTemplateParmDecl *OldTemplateParm
+ = OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0;
+ if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
+ NewTemplateParm->hasDefaultArgument()) {
+ OldDefaultLoc = OldTemplateParm->getDefaultArgumentLoc();
+ NewDefaultLoc = NewTemplateParm->getDefaultArgumentLoc();
+ SawDefaultArgument = true;
+ RedundantDefaultArg = true;
+ PreviousDefaultArgLoc = NewDefaultLoc;
+ } else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument()) {
+ // Merge the default argument from the old declaration to the
+ // new declaration.
+ SawDefaultArgument = true;
+ // FIXME: We need to create a new kind of "default argument" expression
+ // that points to a previous template template parameter.
+ NewTemplateParm->setDefaultArgument(
+ OldTemplateParm->getDefaultArgument());
+ PreviousDefaultArgLoc = OldTemplateParm->getDefaultArgumentLoc();
+ } else if (NewTemplateParm->hasDefaultArgument()) {
+ SawDefaultArgument = true;
+ PreviousDefaultArgLoc = NewTemplateParm->getDefaultArgumentLoc();
+ } else if (SawDefaultArgument)
+ MissingDefaultArg = true;
+ }
+
+ if (RedundantDefaultArg) {
+ // C++ [temp.param]p12:
+ // A template-parameter shall not be given default arguments
+ // by two different declarations in the same scope.
+ Diag(NewDefaultLoc, diag::err_template_param_default_arg_redefinition);
+ Diag(OldDefaultLoc, diag::note_template_param_prev_default_arg);
+ Invalid = true;
+ } else if (MissingDefaultArg) {
+ // C++ [temp.param]p11:
+ // If a template-parameter has a default template-argument,
+ // all subsequent template-parameters shall have a default
+ // template-argument supplied.
+ Diag((*NewParam)->getLocation(),
+ diag::err_template_param_default_arg_missing);
+ Diag(PreviousDefaultArgLoc, diag::note_template_param_prev_default_arg);
+ Invalid = true;
+ }
+
+ // If we have an old template parameter list that we're merging
+ // in, move on to the next parameter.
+ if (OldParams)
+ ++OldParam;
+ }
+
+ return Invalid;
+}
+
+/// \brief Translates template arguments as provided by the parser
+/// into template arguments used by semantic analysis.
+static void
+translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
+ SourceLocation *TemplateArgLocs,
+ llvm::SmallVector<TemplateArgument, 16> &TemplateArgs) {
+ TemplateArgs.reserve(TemplateArgsIn.size());
+
+ void **Args = TemplateArgsIn.getArgs();
+ bool *ArgIsType = TemplateArgsIn.getArgIsType();
+ for (unsigned Arg = 0, Last = TemplateArgsIn.size(); Arg != Last; ++Arg) {
+ TemplateArgs.push_back(
+ ArgIsType[Arg]? TemplateArgument(TemplateArgLocs[Arg],
+ QualType::getFromOpaquePtr(Args[Arg]))
+ : TemplateArgument(reinterpret_cast<Expr *>(Args[Arg])));
+ }
+}
+
+/// \brief Build a canonical version of a template argument list.
+///
+/// This function builds a canonical version of the given template
+/// argument list, where each of the template arguments has been
+/// converted into its canonical form. This routine is typically used
+/// to canonicalize a template argument list when the template name
+/// itself is dependent. When the template name refers to an actual
+/// template declaration, Sema::CheckTemplateArgumentList should be
+/// used to check and canonicalize the template arguments.
+///
+/// \param TemplateArgs The incoming template arguments.
+///
+/// \param NumTemplateArgs The number of template arguments in \p
+/// TemplateArgs.
+///
+/// \param Canonical A vector to be filled with the canonical versions
+/// of the template arguments.
+///
+/// \param Context The ASTContext in which the template arguments live.
+static void CanonicalizeTemplateArguments(const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ llvm::SmallVectorImpl<TemplateArgument> &Canonical,
+ ASTContext &Context) {
+ Canonical.reserve(NumTemplateArgs);
+ for (unsigned Idx = 0; Idx < NumTemplateArgs; ++Idx) {
+ switch (TemplateArgs[Idx].getKind()) {
+ case TemplateArgument::Expression:
+ // FIXME: Build canonical expression (!)
+ Canonical.push_back(TemplateArgs[Idx]);
+ break;
+
+ case TemplateArgument::Declaration:
+ Canonical.push_back(
+ TemplateArgument(SourceLocation(),
+ Context.getCanonicalDecl(TemplateArgs[Idx].getAsDecl())));
+ break;
+
+ case TemplateArgument::Integral:
+ Canonical.push_back(TemplateArgument(SourceLocation(),
+ *TemplateArgs[Idx].getAsIntegral(),
+ TemplateArgs[Idx].getIntegralType()));
+
+ case TemplateArgument::Type: {
+ QualType CanonType
+ = Context.getCanonicalType(TemplateArgs[Idx].getAsType());
+ Canonical.push_back(TemplateArgument(SourceLocation(), CanonType));
+ }
+ }
+ }
+}
+
+QualType Sema::CheckTemplateIdType(TemplateName Name,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceLocation RAngleLoc) {
+ TemplateDecl *Template = Name.getAsTemplateDecl();
+ if (!Template) {
+ // The template name does not resolve to a template, so we just
+ // build a dependent template-id type.
+
+ // Canonicalize the template arguments to build the canonical
+ // template-id type.
+ llvm::SmallVector<TemplateArgument, 16> CanonicalTemplateArgs;
+ CanonicalizeTemplateArguments(TemplateArgs, NumTemplateArgs,
+ CanonicalTemplateArgs, Context);
+
+ TemplateName CanonName = Context.getCanonicalTemplateName(Name);
+ QualType CanonType
+ = Context.getTemplateSpecializationType(CanonName,
+ &CanonicalTemplateArgs[0],
+ CanonicalTemplateArgs.size());
+
+ // Build the dependent template-id type.
+ return Context.getTemplateSpecializationType(Name, TemplateArgs,
+ NumTemplateArgs, CanonType);
+ }
+
+ // Check that the template argument list is well-formed for this
+ // template.
+ llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs;
+ if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc,
+ TemplateArgs, NumTemplateArgs, RAngleLoc,
+ ConvertedTemplateArgs))
+ return QualType();
+
+ assert((ConvertedTemplateArgs.size() ==
+ Template->getTemplateParameters()->size()) &&
+ "Converted template argument list is too short!");
+
+ QualType CanonType;
+
+ if (TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs,
+ NumTemplateArgs)) {
+ // This class template specialization is a dependent
+ // type. Therefore, its canonical type is another class template
+ // specialization type that contains all of the converted
+ // arguments in canonical form. This ensures that, e.g., A<T> and
+ // A<T, T> have identical types when A is declared as:
+ //
+ // template<typename T, typename U = T> struct A;
+ TemplateName CanonName = Context.getCanonicalTemplateName(Name);
+ CanonType = Context.getTemplateSpecializationType(CanonName,
+ &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size());
+ } else if (ClassTemplateDecl *ClassTemplate
+ = dyn_cast<ClassTemplateDecl>(Template)) {
+ // Find the class template specialization declaration that
+ // corresponds to these arguments.
+ llvm::FoldingSetNodeID ID;
+ ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size());
+ void *InsertPos = 0;
+ ClassTemplateSpecializationDecl *Decl
+ = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
+ if (!Decl) {
+ // This is the first time we have referenced this class template
+ // specialization. Create the canonical declaration and add it to
+ // the set of specializations.
+ Decl = ClassTemplateSpecializationDecl::Create(Context,
+ ClassTemplate->getDeclContext(),
+ TemplateLoc,
+ ClassTemplate,
+ &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size(),
+ 0);
+ ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos);
+ Decl->setLexicalDeclContext(CurContext);
+ }
+
+ CanonType = Context.getTypeDeclType(Decl);
+ }
+
+ // Build the fully-sugared type for this class template
+ // specialization, which refers back to the class template
+ // specialization we created or found.
+ return Context.getTemplateSpecializationType(Name, TemplateArgs,
+ NumTemplateArgs, CanonType);
+}
+
+Action::TypeResult
+Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgsIn,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc) {
+ TemplateName Template = TemplateD.getAsVal<TemplateName>();
+
+ // Translate the parser's template argument list in our AST format.
+ llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+ translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
+
+ QualType Result = CheckTemplateIdType(Template, TemplateLoc, LAngleLoc,
+ TemplateArgs.data(),
+ TemplateArgs.size(),
+ RAngleLoc);
+ TemplateArgsIn.release();
+
+ if (Result.isNull())
+ return true;
+
+ return Result.getAsOpaquePtr();
+}
+
+/// \brief Form a dependent template name.
+///
+/// This action forms a dependent template name given the template
+/// name and its (presumably dependent) scope specifier. For
+/// example, given "MetaFun::template apply", the scope specifier \p
+/// SS will be "MetaFun::", \p TemplateKWLoc contains the location
+/// of the "template" keyword, and "apply" is the \p Name.
+Sema::TemplateTy
+Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
+ const IdentifierInfo &Name,
+ SourceLocation NameLoc,
+ const CXXScopeSpec &SS) {
+ if (!SS.isSet() || SS.isInvalid())
+ return TemplateTy();
+
+ NestedNameSpecifier *Qualifier
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+
+ // FIXME: member of the current instantiation
+
+ if (!Qualifier->isDependent()) {
+ // C++0x [temp.names]p5:
+ // If a name prefixed by the keyword template is not the name of
+ // a template, the program is ill-formed. [Note: the keyword
+ // template may not be applied to non-template members of class
+ // templates. -end note ] [ Note: as is the case with the
+ // typename prefix, the template prefix is allowed in cases
+ // where it is not strictly necessary; i.e., when the
+ // nested-name-specifier or the expression on the left of the ->
+ // or . is not dependent on a template-parameter, or the use
+ // does not appear in the scope of a template. -end note]
+ //
+ // Note: C++03 was more strict here, because it banned the use of
+ // the "template" keyword prior to a template-name that was not a
+ // dependent name. C++ DR468 relaxed this requirement (the
+ // "template" keyword is now permitted). We follow the C++0x
+ // rules, even in C++03 mode, retroactively applying the DR.
+ TemplateTy Template;
+ TemplateNameKind TNK = isTemplateName(Name, 0, Template, &SS);
+ if (TNK == TNK_Non_template) {
+ Diag(NameLoc, diag::err_template_kw_refers_to_non_template)
+ << &Name;
+ return TemplateTy();
+ }
+
+ return Template;
+ }
+
+ return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name));
+}
+
+/// \brief Check that the given template argument list is well-formed
+/// for specializing the given template.
+bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceLocation RAngleLoc,
+ llvm::SmallVectorImpl<TemplateArgument> &Converted) {
+ TemplateParameterList *Params = Template->getTemplateParameters();
+ unsigned NumParams = Params->size();
+ unsigned NumArgs = NumTemplateArgs;
+ bool Invalid = false;
+
+ if (NumArgs > NumParams ||
+ NumArgs < Params->getMinRequiredArguments()) {
+ // FIXME: point at either the first arg beyond what we can handle,
+ // or the '>', depending on whether we have too many or too few
+ // arguments.
+ SourceRange Range;
+ if (NumArgs > NumParams)
+ Range = SourceRange(TemplateArgs[NumParams].getLocation(), RAngleLoc);
+ Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
+ << (NumArgs > NumParams)
+ << (isa<ClassTemplateDecl>(Template)? 0 :
+ isa<FunctionTemplateDecl>(Template)? 1 :
+ isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
+ << Template << Range;
+ Diag(Template->getLocation(), diag::note_template_decl_here)
+ << Params->getSourceRange();
+ Invalid = true;
+ }
+
+ // C++ [temp.arg]p1:
+ // [...] The type and form of each template-argument specified in
+ // a template-id shall match the type and form specified for the
+ // corresponding parameter declared by the template in its
+ // template-parameter-list.
+ unsigned ArgIdx = 0;
+ for (TemplateParameterList::iterator Param = Params->begin(),
+ ParamEnd = Params->end();
+ Param != ParamEnd; ++Param, ++ArgIdx) {
+ // Decode the template argument
+ TemplateArgument Arg;
+ if (ArgIdx >= NumArgs) {
+ // Retrieve the default template argument from the template
+ // parameter.
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+ if (!TTP->hasDefaultArgument())
+ break;
+
+ QualType ArgType = TTP->getDefaultArgument();
+
+ // If the argument type is dependent, instantiate it now based
+ // on the previously-computed template arguments.
+ if (ArgType->isDependentType()) {
+ InstantiatingTemplate Inst(*this, TemplateLoc,
+ Template, &Converted[0],
+ Converted.size(),
+ SourceRange(TemplateLoc, RAngleLoc));
+
+ TemplateArgumentList TemplateArgs(Context, &Converted[0],
+ Converted.size(),
+ /*CopyArgs=*/false);
+ ArgType = InstantiateType(ArgType, TemplateArgs,
+ TTP->getDefaultArgumentLoc(),
+ TTP->getDeclName());
+ }
+
+ if (ArgType.isNull())
+ return true;
+
+ Arg = TemplateArgument(TTP->getLocation(), ArgType);
+ } else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
+ if (!NTTP->hasDefaultArgument())
+ break;
+
+ // FIXME: Instantiate default argument
+ Arg = TemplateArgument(NTTP->getDefaultArgument());
+ } else {
+ TemplateTemplateParmDecl *TempParm
+ = cast<TemplateTemplateParmDecl>(*Param);
+
+ if (!TempParm->hasDefaultArgument())
+ break;
+
+ // FIXME: Instantiate default argument
+ Arg = TemplateArgument(TempParm->getDefaultArgument());
+ }
+ } else {
+ // Retrieve the template argument produced by the user.
+ Arg = TemplateArgs[ArgIdx];
+ }
+
+
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+ // Check template type parameters.
+ if (Arg.getKind() == TemplateArgument::Type) {
+ if (CheckTemplateArgument(TTP, Arg.getAsType(), Arg.getLocation()))
+ Invalid = true;
+
+ // Add the converted template type argument.
+ Converted.push_back(
+ TemplateArgument(Arg.getLocation(),
+ Context.getCanonicalType(Arg.getAsType())));
+ continue;
+ }
+
+ // C++ [temp.arg.type]p1:
+ // A template-argument for a template-parameter which is a
+ // type shall be a type-id.
+
+ // We have a template type parameter but the template argument
+ // is not a type.
+ Diag(Arg.getLocation(), diag::err_template_arg_must_be_type);
+ Diag((*Param)->getLocation(), diag::note_template_param_here);
+ Invalid = true;
+ } else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
+ // Check non-type template parameters.
+
+ // Instantiate the type of the non-type template parameter with
+ // the template arguments we've seen thus far.
+ QualType NTTPType = NTTP->getType();
+ if (NTTPType->isDependentType()) {
+ // Instantiate the type of the non-type template parameter.
+ InstantiatingTemplate Inst(*this, TemplateLoc,
+ Template, &Converted[0],
+ Converted.size(),
+ SourceRange(TemplateLoc, RAngleLoc));
+
+ TemplateArgumentList TemplateArgs(Context, &Converted[0],
+ Converted.size(),
+ /*CopyArgs=*/false);
+ NTTPType = InstantiateType(NTTPType, TemplateArgs,
+ NTTP->getLocation(),
+ NTTP->getDeclName());
+ // If that worked, check the non-type template parameter type
+ // for validity.
+ if (!NTTPType.isNull())
+ NTTPType = CheckNonTypeTemplateParameterType(NTTPType,
+ NTTP->getLocation());
+
+ if (NTTPType.isNull()) {
+ Invalid = true;
+ break;
+ }
+ }
+
+ switch (Arg.getKind()) {
+ case TemplateArgument::Expression: {
+ Expr *E = Arg.getAsExpr();
+ if (CheckTemplateArgument(NTTP, NTTPType, E, &Converted))
+ Invalid = true;
+ break;
+ }
+
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Integral:
+ // We've already checked this template argument, so just copy
+ // it to the list of converted arguments.
+ Converted.push_back(Arg);
+ break;
+
+ case TemplateArgument::Type:
+ // We have a non-type template parameter but the template
+ // argument is a type.
+
+ // C++ [temp.arg]p2:
+ // In a template-argument, an ambiguity between a type-id and
+ // an expression is resolved to a type-id, regardless of the
+ // form of the corresponding template-parameter.
+ //
+ // We warn specifically about this case, since it can be rather
+ // confusing for users.
+ if (Arg.getAsType()->isFunctionType())
+ Diag(Arg.getLocation(), diag::err_template_arg_nontype_ambig)
+ << Arg.getAsType();
+ else
+ Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr);
+ Diag((*Param)->getLocation(), diag::note_template_param_here);
+ Invalid = true;
+ }
+ } else {
+ // Check template template parameters.
+ TemplateTemplateParmDecl *TempParm
+ = cast<TemplateTemplateParmDecl>(*Param);
+
+ switch (Arg.getKind()) {
+ case TemplateArgument::Expression: {
+ Expr *ArgExpr = Arg.getAsExpr();
+ if (ArgExpr && isa<DeclRefExpr>(ArgExpr) &&
+ isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) {
+ if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr)))
+ Invalid = true;
+
+ // Add the converted template argument.
+ Decl *D
+ = Context.getCanonicalDecl(cast<DeclRefExpr>(ArgExpr)->getDecl());
+ Converted.push_back(TemplateArgument(Arg.getLocation(), D));
+ continue;
+ }
+ }
+ // fall through
+
+ case TemplateArgument::Type: {
+ // We have a template template parameter but the template
+ // argument does not refer to a template.
+ Diag(Arg.getLocation(), diag::err_template_arg_must_be_template);
+ Invalid = true;
+ break;
+ }
+
+ case TemplateArgument::Declaration:
+ // We've already checked this template argument, so just copy
+ // it to the list of converted arguments.
+ Converted.push_back(Arg);
+ break;
+
+ case TemplateArgument::Integral:
+ assert(false && "Integral argument with template template parameter");
+ break;
+ }
+ }
+ }
+
+ return Invalid;
+}
+
+/// \brief Check a template argument against its corresponding
+/// template type parameter.
+///
+/// This routine implements the semantics of C++ [temp.arg.type]. It
+/// returns true if an error occurred, and false otherwise.
+bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
+ QualType Arg, SourceLocation ArgLoc) {
+ // C++ [temp.arg.type]p2:
+ // A local type, a type with no linkage, an unnamed type or a type
+ // compounded from any of these types shall not be used as a
+ // template-argument for a template type-parameter.
+ //
+ // FIXME: Perform the recursive and no-linkage type checks.
+ const TagType *Tag = 0;
+ if (const EnumType *EnumT = Arg->getAsEnumType())
+ Tag = EnumT;
+ else if (const RecordType *RecordT = Arg->getAsRecordType())
+ Tag = RecordT;
+ if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod())
+ return Diag(ArgLoc, diag::err_template_arg_local_type)
+ << QualType(Tag, 0);
+ else if (Tag && !Tag->getDecl()->getDeclName() &&
+ !Tag->getDecl()->getTypedefForAnonDecl()) {
+ Diag(ArgLoc, diag::err_template_arg_unnamed_type);
+ Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here);
+ return true;
+ }
+
+ return false;
+}
+
+/// \brief Checks whether the given template argument is the address
+/// of an object or function according to C++ [temp.arg.nontype]p1.
+bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
+ NamedDecl *&Entity) {
+ bool Invalid = false;
+
+ // See through any implicit casts we added to fix the type.
+ if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
+ Arg = Cast->getSubExpr();
+
+ // C++0x allows nullptr, and there's no further checking to be done for that.
+ if (Arg->getType()->isNullPtrType())
+ return false;
+
+ // C++ [temp.arg.nontype]p1:
+ //
+ // A template-argument for a non-type, non-template
+ // template-parameter shall be one of: [...]
+ //
+ // -- the address of an object or function with external
+ // linkage, including function templates and function
+ // template-ids but excluding non-static class members,
+ // expressed as & id-expression where the & is optional if
+ // the name refers to a function or array, or if the
+ // corresponding template-parameter is a reference; or
+ DeclRefExpr *DRE = 0;
+
+ // Ignore (and complain about) any excess parentheses.
+ while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
+ if (!Invalid) {
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_extra_parens)
+ << Arg->getSourceRange();
+ Invalid = true;
+ }
+
+ Arg = Parens->getSubExpr();
+ }
+
+ if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
+ if (UnOp->getOpcode() == UnaryOperator::AddrOf)
+ DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr());
+ } else
+ DRE = dyn_cast<DeclRefExpr>(Arg);
+
+ if (!DRE || !isa<ValueDecl>(DRE->getDecl()))
+ return Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_object_or_func_form)
+ << Arg->getSourceRange();
+
+ // Cannot refer to non-static data members
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(DRE->getDecl()))
+ return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_field)
+ << Field << Arg->getSourceRange();
+
+ // Cannot refer to non-static member functions
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(DRE->getDecl()))
+ if (!Method->isStatic())
+ return Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_method)
+ << Method << Arg->getSourceRange();
+
+ // Functions must have external linkage.
+ if (FunctionDecl *Func = dyn_cast<FunctionDecl>(DRE->getDecl())) {
+ if (Func->getStorageClass() == FunctionDecl::Static) {
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_function_not_extern)
+ << Func << Arg->getSourceRange();
+ Diag(Func->getLocation(), diag::note_template_arg_internal_object)
+ << true;
+ return true;
+ }
+
+ // Okay: we've named a function with external linkage.
+ Entity = Func;
+ return Invalid;
+ }
+
+ if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (!Var->hasGlobalStorage()) {
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_object_not_extern)
+ << Var << Arg->getSourceRange();
+ Diag(Var->getLocation(), diag::note_template_arg_internal_object)
+ << true;
+ return true;
+ }
+
+ // Okay: we've named an object with external linkage
+ Entity = Var;
+ return Invalid;
+ }
+
+ // We found something else, but we don't know specifically what it is.
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_object_or_func)
+ << Arg->getSourceRange();
+ Diag(DRE->getDecl()->getLocation(),
+ diag::note_template_arg_refers_here);
+ return true;
+}
+
+/// \brief Checks whether the given template argument is a pointer to
+/// member constant according to C++ [temp.arg.nontype]p1.
+bool
+Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
+ bool Invalid = false;
+
+ // See through any implicit casts we added to fix the type.
+ if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
+ Arg = Cast->getSubExpr();
+
+ // C++0x allows nullptr, and there's no further checking to be done for that.
+ if (Arg->getType()->isNullPtrType())
+ return false;
+
+ // C++ [temp.arg.nontype]p1:
+ //
+ // A template-argument for a non-type, non-template
+ // template-parameter shall be one of: [...]
+ //
+ // -- a pointer to member expressed as described in 5.3.1.
+ QualifiedDeclRefExpr *DRE = 0;
+
+ // Ignore (and complain about) any excess parentheses.
+ while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
+ if (!Invalid) {
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_extra_parens)
+ << Arg->getSourceRange();
+ Invalid = true;
+ }
+
+ Arg = Parens->getSubExpr();
+ }
+
+ if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg))
+ if (UnOp->getOpcode() == UnaryOperator::AddrOf)
+ DRE = dyn_cast<QualifiedDeclRefExpr>(UnOp->getSubExpr());
+
+ if (!DRE)
+ return Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_pointer_to_member_form)
+ << Arg->getSourceRange();
+
+ if (isa<FieldDecl>(DRE->getDecl()) || isa<CXXMethodDecl>(DRE->getDecl())) {
+ assert((isa<FieldDecl>(DRE->getDecl()) ||
+ !cast<CXXMethodDecl>(DRE->getDecl())->isStatic()) &&
+ "Only non-static member pointers can make it here");
+
+ // Okay: this is the address of a non-static member, and therefore
+ // a member pointer constant.
+ Member = DRE->getDecl();
+ return Invalid;
+ }
+
+ // We found something else, but we don't know specifically what it is.
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_pointer_to_member_form)
+ << Arg->getSourceRange();
+ Diag(DRE->getDecl()->getLocation(),
+ diag::note_template_arg_refers_here);
+ return true;
+}
+
+/// \brief Check a template argument against its corresponding
+/// non-type template parameter.
+///
+/// This routine implements the semantics of C++ [temp.arg.nontype].
+/// It returns true if an error occurred, and false otherwise. \p
+/// InstantiatedParamType is the type of the non-type template
+/// parameter after it has been instantiated.
+///
+/// If Converted is non-NULL and no errors occur, the value
+/// of this argument will be added to the end of the Converted vector.
+bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
+ QualType InstantiatedParamType, Expr *&Arg,
+ llvm::SmallVectorImpl<TemplateArgument> *Converted) {
+ SourceLocation StartLoc = Arg->getSourceRange().getBegin();
+
+ // If either the parameter has a dependent type or the argument is
+ // type-dependent, there's nothing we can check now.
+ // FIXME: Add template argument to Converted!
+ if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) {
+ // FIXME: Produce a cloned, canonical expression?
+ Converted->push_back(TemplateArgument(Arg));
+ return false;
+ }
+
+ // C++ [temp.arg.nontype]p5:
+ // The following conversions are performed on each expression used
+ // as a non-type template-argument. If a non-type
+ // template-argument cannot be converted to the type of the
+ // corresponding template-parameter then the program is
+ // ill-formed.
+ //
+ // -- for a non-type template-parameter of integral or
+ // enumeration type, integral promotions (4.5) and integral
+ // conversions (4.7) are applied.
+ QualType ParamType = InstantiatedParamType;
+ QualType ArgType = Arg->getType();
+ if (ParamType->isIntegralType() || ParamType->isEnumeralType()) {
+ // C++ [temp.arg.nontype]p1:
+ // A template-argument for a non-type, non-template
+ // template-parameter shall be one of:
+ //
+ // -- an integral constant-expression of integral or enumeration
+ // type; or
+ // -- the name of a non-type template-parameter; or
+ SourceLocation NonConstantLoc;
+ llvm::APSInt Value;
+ if (!ArgType->isIntegralType() && !ArgType->isEnumeralType()) {
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_integral_or_enumeral)
+ << ArgType << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ } else if (!Arg->isValueDependent() &&
+ !Arg->isIntegerConstantExpr(Value, Context, &NonConstantLoc)) {
+ Diag(NonConstantLoc, diag::err_template_arg_not_ice)
+ << ArgType << Arg->getSourceRange();
+ return true;
+ }
+
+ // FIXME: We need some way to more easily get the unqualified form
+ // of the types without going all the way to the
+ // canonical type.
+ if (Context.getCanonicalType(ParamType).getCVRQualifiers())
+ ParamType = Context.getCanonicalType(ParamType).getUnqualifiedType();
+ if (Context.getCanonicalType(ArgType).getCVRQualifiers())
+ ArgType = Context.getCanonicalType(ArgType).getUnqualifiedType();
+
+ // Try to convert the argument to the parameter's type.
+ if (ParamType == ArgType) {
+ // Okay: no conversion necessary
+ } else if (IsIntegralPromotion(Arg, ArgType, ParamType) ||
+ !ParamType->isEnumeralType()) {
+ // This is an integral promotion or conversion.
+ ImpCastExprToType(Arg, ParamType);
+ } else {
+ // We can't perform this conversion.
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_convertible)
+ << Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ QualType IntegerType = Context.getCanonicalType(ParamType);
+ if (const EnumType *Enum = IntegerType->getAsEnumType())
+ IntegerType = Enum->getDecl()->getIntegerType();
+
+ if (!Arg->isValueDependent()) {
+ // Check that an unsigned parameter does not receive a negative
+ // value.
+ if (IntegerType->isUnsignedIntegerType()
+ && (Value.isSigned() && Value.isNegative())) {
+ Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_negative)
+ << Value.toString(10) << Param->getType()
+ << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ // Check that we don't overflow the template parameter type.
+ unsigned AllowedBits = Context.getTypeSize(IntegerType);
+ if (Value.getActiveBits() > AllowedBits) {
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_too_large)
+ << Value.toString(10) << Param->getType()
+ << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ if (Value.getBitWidth() != AllowedBits)
+ Value.extOrTrunc(AllowedBits);
+ Value.setIsSigned(IntegerType->isSignedIntegerType());
+ }
+
+ if (Converted) {
+ // Add the value of this argument to the list of converted
+ // arguments. We use the bitwidth and signedness of the template
+ // parameter.
+ if (Arg->isValueDependent()) {
+ // The argument is value-dependent. Create a new
+ // TemplateArgument with the converted expression.
+ Converted->push_back(TemplateArgument(Arg));
+ return false;
+ }
+
+ Converted->push_back(TemplateArgument(StartLoc, Value,
+ ParamType->isEnumeralType() ? ParamType : IntegerType));
+ }
+
+ return false;
+ }
+
+ // Handle pointer-to-function, reference-to-function, and
+ // pointer-to-member-function all in (roughly) the same way.
+ if (// -- For a non-type template-parameter of type pointer to
+ // function, only the function-to-pointer conversion (4.3) is
+ // applied. If the template-argument represents a set of
+ // overloaded functions (or a pointer to such), the matching
+ // function is selected from the set (13.4).
+ // In C++0x, any std::nullptr_t value can be converted.
+ (ParamType->isPointerType() &&
+ ParamType->getAsPointerType()->getPointeeType()->isFunctionType()) ||
+ // -- For a non-type template-parameter of type reference to
+ // function, no conversions apply. If the template-argument
+ // represents a set of overloaded functions, the matching
+ // function is selected from the set (13.4).
+ (ParamType->isReferenceType() &&
+ ParamType->getAsReferenceType()->getPointeeType()->isFunctionType()) ||
+ // -- For a non-type template-parameter of type pointer to
+ // member function, no conversions apply. If the
+ // template-argument represents a set of overloaded member
+ // functions, the matching member function is selected from
+ // the set (13.4).
+ // Again, C++0x allows a std::nullptr_t value.
+ (ParamType->isMemberPointerType() &&
+ ParamType->getAsMemberPointerType()->getPointeeType()
+ ->isFunctionType())) {
+ if (Context.hasSameUnqualifiedType(ArgType,
+ ParamType.getNonReferenceType())) {
+ // We don't have to do anything: the types already match.
+ } else if (ArgType->isNullPtrType() && (ParamType->isPointerType() ||
+ ParamType->isMemberPointerType())) {
+ ArgType = ParamType;
+ ImpCastExprToType(Arg, ParamType);
+ } else if (ArgType->isFunctionType() && ParamType->isPointerType()) {
+ ArgType = Context.getPointerType(ArgType);
+ ImpCastExprToType(Arg, ArgType);
+ } else if (FunctionDecl *Fn
+ = ResolveAddressOfOverloadedFunction(Arg, ParamType, true)) {
+ if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
+ return true;
+
+ FixOverloadedFunctionReference(Arg, Fn);
+ ArgType = Arg->getType();
+ if (ArgType->isFunctionType() && ParamType->isPointerType()) {
+ ArgType = Context.getPointerType(Arg->getType());
+ ImpCastExprToType(Arg, ArgType);
+ }
+ }
+
+ if (!Context.hasSameUnqualifiedType(ArgType,
+ ParamType.getNonReferenceType())) {
+ // We can't perform this conversion.
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_convertible)
+ << Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ if (ParamType->isMemberPointerType()) {
+ NamedDecl *Member = 0;
+ if (CheckTemplateArgumentPointerToMember(Arg, Member))
+ return true;
+
+ if (Converted) {
+ Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member));
+ Converted->push_back(TemplateArgument(StartLoc, Member));
+ }
+
+ return false;
+ }
+
+ NamedDecl *Entity = 0;
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
+ return true;
+
+ if (Converted) {
+ Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity));
+ Converted->push_back(TemplateArgument(StartLoc, Entity));
+ }
+ return false;
+ }
+
+ if (ParamType->isPointerType()) {
+ // -- for a non-type template-parameter of type pointer to
+ // object, qualification conversions (4.4) and the
+ // array-to-pointer conversion (4.2) are applied.
+ // C++0x also allows a value of std::nullptr_t.
+ assert(ParamType->getAsPointerType()->getPointeeType()->isObjectType() &&
+ "Only object pointers allowed here");
+
+ if (ArgType->isNullPtrType()) {
+ ArgType = ParamType;
+ ImpCastExprToType(Arg, ParamType);
+ } else if (ArgType->isArrayType()) {
+ ArgType = Context.getArrayDecayedType(ArgType);
+ ImpCastExprToType(Arg, ArgType);
+ }
+
+ if (IsQualificationConversion(ArgType, ParamType)) {
+ ArgType = ParamType;
+ ImpCastExprToType(Arg, ParamType);
+ }
+
+ if (!Context.hasSameUnqualifiedType(ArgType, ParamType)) {
+ // We can't perform this conversion.
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_convertible)
+ << Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ NamedDecl *Entity = 0;
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
+ return true;
+
+ if (Converted) {
+ Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity));
+ Converted->push_back(TemplateArgument(StartLoc, Entity));
+ }
+
+ return false;
+ }
+
+ if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) {
+ // -- For a non-type template-parameter of type reference to
+ // object, no conversions apply. The type referred to by the
+ // reference may be more cv-qualified than the (otherwise
+ // identical) type of the template-argument. The
+ // template-parameter is bound directly to the
+ // template-argument, which must be an lvalue.
+ assert(ParamRefType->getPointeeType()->isObjectType() &&
+ "Only object references allowed here");
+
+ if (!Context.hasSameUnqualifiedType(ParamRefType->getPointeeType(), ArgType)) {
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_no_ref_bind)
+ << InstantiatedParamType << Arg->getType()
+ << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ unsigned ParamQuals
+ = Context.getCanonicalType(ParamType).getCVRQualifiers();
+ unsigned ArgQuals = Context.getCanonicalType(ArgType).getCVRQualifiers();
+
+ if ((ParamQuals | ArgQuals) != ParamQuals) {
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_ref_bind_ignores_quals)
+ << InstantiatedParamType << Arg->getType()
+ << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ NamedDecl *Entity = 0;
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
+ return true;
+
+ if (Converted) {
+ Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity));
+ Converted->push_back(TemplateArgument(StartLoc, Entity));
+ }
+
+ return false;
+ }
+
+ // -- For a non-type template-parameter of type pointer to data
+ // member, qualification conversions (4.4) are applied.
+ // C++0x allows std::nullptr_t values.
+ assert(ParamType->isMemberPointerType() && "Only pointers to members remain");
+
+ if (Context.hasSameUnqualifiedType(ParamType, ArgType)) {
+ // Types match exactly: nothing more to do here.
+ } else if (ArgType->isNullPtrType()) {
+ ImpCastExprToType(Arg, ParamType);
+ } else if (IsQualificationConversion(ArgType, ParamType)) {
+ ImpCastExprToType(Arg, ParamType);
+ } else {
+ // We can't perform this conversion.
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_convertible)
+ << Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ NamedDecl *Member = 0;
+ if (CheckTemplateArgumentPointerToMember(Arg, Member))
+ return true;
+
+ if (Converted) {
+ Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member));
+ Converted->push_back(TemplateArgument(StartLoc, Member));
+ }
+
+ return false;
+}
+
+/// \brief Check a template argument against its corresponding
+/// template template parameter.
+///
+/// This routine implements the semantics of C++ [temp.arg.template].
+/// It returns true if an error occurred, and false otherwise.
+bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
+ DeclRefExpr *Arg) {
+ assert(isa<TemplateDecl>(Arg->getDecl()) && "Only template decls allowed");
+ TemplateDecl *Template = cast<TemplateDecl>(Arg->getDecl());
+
+ // C++ [temp.arg.template]p1:
+ // A template-argument for a template template-parameter shall be
+ // the name of a class template, expressed as id-expression. Only
+ // primary class templates are considered when matching the
+ // template template argument with the corresponding parameter;
+ // partial specializations are not considered even if their
+ // parameter lists match that of the template template parameter.
+ if (!isa<ClassTemplateDecl>(Template)) {
+ assert(isa<FunctionTemplateDecl>(Template) &&
+ "Only function templates are possible here");
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::note_template_arg_refers_here_func)
+ << Template;
+ }
+
+ return !TemplateParameterListsAreEqual(Template->getTemplateParameters(),
+ Param->getTemplateParameters(),
+ true, true,
+ Arg->getSourceRange().getBegin());
+}
+
+/// \brief Determine whether the given template parameter lists are
+/// equivalent.
+///
+/// \param New The new template parameter list, typically written in the
+/// source code as part of a new template declaration.
+///
+/// \param Old The old template parameter list, typically found via
+/// name lookup of the template declared with this template parameter
+/// list.
+///
+/// \param Complain If true, this routine will produce a diagnostic if
+/// the template parameter lists are not equivalent.
+///
+/// \param IsTemplateTemplateParm If true, this routine is being
+/// called to compare the template parameter lists of a template
+/// template parameter.
+///
+/// \param TemplateArgLoc If this source location is valid, then we
+/// are actually checking the template parameter list of a template
+/// argument (New) against the template parameter list of its
+/// corresponding template template parameter (Old). We produce
+/// slightly different diagnostics in this scenario.
+///
+/// \returns True if the template parameter lists are equal, false
+/// otherwise.
+bool
+Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
+ TemplateParameterList *Old,
+ bool Complain,
+ bool IsTemplateTemplateParm,
+ SourceLocation TemplateArgLoc) {
+ if (Old->size() != New->size()) {
+ if (Complain) {
+ unsigned NextDiag = diag::err_template_param_list_different_arity;
+ if (TemplateArgLoc.isValid()) {
+ Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch);
+ NextDiag = diag::note_template_param_list_different_arity;
+ }
+ Diag(New->getTemplateLoc(), NextDiag)
+ << (New->size() > Old->size())
+ << IsTemplateTemplateParm
+ << SourceRange(New->getTemplateLoc(), New->getRAngleLoc());
+ Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration)
+ << IsTemplateTemplateParm
+ << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc());
+ }
+
+ return false;
+ }
+
+ for (TemplateParameterList::iterator OldParm = Old->begin(),
+ OldParmEnd = Old->end(), NewParm = New->begin();
+ OldParm != OldParmEnd; ++OldParm, ++NewParm) {
+ if ((*OldParm)->getKind() != (*NewParm)->getKind()) {
+ unsigned NextDiag = diag::err_template_param_different_kind;
+ if (TemplateArgLoc.isValid()) {
+ Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch);
+ NextDiag = diag::note_template_param_different_kind;
+ }
+ Diag((*NewParm)->getLocation(), NextDiag)
+ << IsTemplateTemplateParm;
+ Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration)
+ << IsTemplateTemplateParm;
+ return false;
+ }
+
+ if (isa<TemplateTypeParmDecl>(*OldParm)) {
+ // Okay; all template type parameters are equivalent (since we
+ // know we're at the same index).
+#if 0
+ // FIXME: Enable this code in debug mode *after* we properly go through
+ // and "instantiate" the template parameter lists of template template
+ // parameters. It's only after this instantiation that (1) any dependent
+ // types within the template parameter list of the template template
+ // parameter can be checked, and (2) the template type parameter depths
+ // will match up.
+ QualType OldParmType
+ = Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*OldParm));
+ QualType NewParmType
+ = Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*NewParm));
+ assert(Context.getCanonicalType(OldParmType) ==
+ Context.getCanonicalType(NewParmType) &&
+ "type parameter mismatch?");
+#endif
+ } else if (NonTypeTemplateParmDecl *OldNTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(*OldParm)) {
+ // The types of non-type template parameters must agree.
+ NonTypeTemplateParmDecl *NewNTTP
+ = cast<NonTypeTemplateParmDecl>(*NewParm);
+ if (Context.getCanonicalType(OldNTTP->getType()) !=
+ Context.getCanonicalType(NewNTTP->getType())) {
+ if (Complain) {
+ unsigned NextDiag = diag::err_template_nontype_parm_different_type;
+ if (TemplateArgLoc.isValid()) {
+ Diag(TemplateArgLoc,
+ diag::err_template_arg_template_params_mismatch);
+ NextDiag = diag::note_template_nontype_parm_different_type;
+ }
+ Diag(NewNTTP->getLocation(), NextDiag)
+ << NewNTTP->getType()
+ << IsTemplateTemplateParm;
+ Diag(OldNTTP->getLocation(),
+ diag::note_template_nontype_parm_prev_declaration)
+ << OldNTTP->getType();
+ }
+ return false;
+ }
+ } else {
+ // The template parameter lists of template template
+ // parameters must agree.
+ // FIXME: Could we perform a faster "type" comparison here?
+ assert(isa<TemplateTemplateParmDecl>(*OldParm) &&
+ "Only template template parameters handled here");
+ TemplateTemplateParmDecl *OldTTP
+ = cast<TemplateTemplateParmDecl>(*OldParm);
+ TemplateTemplateParmDecl *NewTTP
+ = cast<TemplateTemplateParmDecl>(*NewParm);
+ if (!TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
+ OldTTP->getTemplateParameters(),
+ Complain,
+ /*IsTemplateTemplateParm=*/true,
+ TemplateArgLoc))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/// \brief Check whether a template can be declared within this scope.
+///
+/// If the template declaration is valid in this scope, returns
+/// false. Otherwise, issues a diagnostic and returns true.
+bool
+Sema::CheckTemplateDeclScope(Scope *S,
+ MultiTemplateParamsArg &TemplateParameterLists) {
+ assert(TemplateParameterLists.size() > 0 && "Not a template");
+
+ // Find the nearest enclosing declaration scope.
+ while ((S->getFlags() & Scope::DeclScope) == 0 ||
+ (S->getFlags() & Scope::TemplateParamScope) != 0)
+ S = S->getParent();
+
+ TemplateParameterList *TemplateParams =
+ static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
+ SourceLocation TemplateLoc = TemplateParams->getTemplateLoc();
+ SourceRange TemplateRange
+ = SourceRange(TemplateLoc, TemplateParams->getRAngleLoc());
+
+ // C++ [temp]p2:
+ // A template-declaration can appear only as a namespace scope or
+ // class scope declaration.
+ DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
+ while (Ctx && isa<LinkageSpecDecl>(Ctx)) {
+ if (cast<LinkageSpecDecl>(Ctx)->getLanguage() != LinkageSpecDecl::lang_cxx)
+ return Diag(TemplateLoc, diag::err_template_linkage)
+ << TemplateRange;
+
+ Ctx = Ctx->getParent();
+ }
+
+ if (Ctx && (Ctx->isFileContext() || Ctx->isRecord()))
+ return false;
+
+ return Diag(TemplateLoc, diag::err_template_outside_namespace_or_class_scope)
+ << TemplateRange;
+}
+
+/// \brief Check whether a class template specialization or explicit
+/// instantiation in the current context is well-formed.
+///
+/// This routine determines whether a class template specialization or
+/// explicit instantiation can be declared in the current context
+/// (C++ [temp.expl.spec]p2, C++0x [temp.explicit]p2) and emits
+/// appropriate diagnostics if there was an error. It returns true if
+// there was an error that we cannot recover from, and false otherwise.
+bool
+Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
+ ClassTemplateSpecializationDecl *PrevDecl,
+ SourceLocation TemplateNameLoc,
+ SourceRange ScopeSpecifierRange,
+ bool ExplicitInstantiation) {
+ // C++ [temp.expl.spec]p2:
+ // An explicit specialization shall be declared in the namespace
+ // of which the template is a member, or, for member templates, in
+ // the namespace of which the enclosing class or enclosing class
+ // template is a member. An explicit specialization of a member
+ // function, member class or static data member of a class
+ // template shall be declared in the namespace of which the class
+ // template is a member. Such a declaration may also be a
+ // definition. If the declaration is not a definition, the
+ // specialization may be defined later in the name- space in which
+ // the explicit specialization was declared, or in a namespace
+ // that encloses the one in which the explicit specialization was
+ // declared.
+ if (CurContext->getLookupContext()->isFunctionOrMethod()) {
+ Diag(TemplateNameLoc, diag::err_template_spec_decl_function_scope)
+ << ExplicitInstantiation << ClassTemplate;
+ return true;
+ }
+
+ DeclContext *DC = CurContext->getEnclosingNamespaceContext();
+ DeclContext *TemplateContext
+ = ClassTemplate->getDeclContext()->getEnclosingNamespaceContext();
+ if ((!PrevDecl || PrevDecl->getSpecializationKind() == TSK_Undeclared) &&
+ !ExplicitInstantiation) {
+ // There is no prior declaration of this entity, so this
+ // specialization must be in the same context as the template
+ // itself.
+ if (DC != TemplateContext) {
+ if (isa<TranslationUnitDecl>(TemplateContext))
+ Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope_global)
+ << ClassTemplate << ScopeSpecifierRange;
+ else if (isa<NamespaceDecl>(TemplateContext))
+ Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope)
+ << ClassTemplate << cast<NamedDecl>(TemplateContext)
+ << ScopeSpecifierRange;
+
+ Diag(ClassTemplate->getLocation(), diag::note_template_decl_here);
+ }
+
+ return false;
+ }
+
+ // We have a previous declaration of this entity. Make sure that
+ // this redeclaration (or definition) occurs in an enclosing namespace.
+ if (!CurContext->Encloses(TemplateContext)) {
+ // FIXME: In C++98, we would like to turn these errors into warnings,
+ // dependent on a -Wc++0x flag.
+ bool SuppressedDiag = false;
+ if (isa<TranslationUnitDecl>(TemplateContext)) {
+ if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x)
+ Diag(TemplateNameLoc, diag::err_template_spec_redecl_global_scope)
+ << ExplicitInstantiation << ClassTemplate << ScopeSpecifierRange;
+ else
+ SuppressedDiag = true;
+ } else if (isa<NamespaceDecl>(TemplateContext)) {
+ if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x)
+ Diag(TemplateNameLoc, diag::err_template_spec_redecl_out_of_scope)
+ << ExplicitInstantiation << ClassTemplate
+ << cast<NamedDecl>(TemplateContext) << ScopeSpecifierRange;
+ else
+ SuppressedDiag = true;
+ }
+
+ if (!SuppressedDiag)
+ Diag(ClassTemplate->getLocation(), diag::note_template_decl_here);
+ }
+
+ return false;
+}
+
+Sema::DeclResult
+Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
+ SourceLocation KWLoc,
+ const CXXScopeSpec &SS,
+ TemplateTy TemplateD,
+ SourceLocation TemplateNameLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgsIn,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc,
+ AttributeList *Attr,
+ MultiTemplateParamsArg TemplateParameterLists) {
+ // Find the class template we're specializing
+ TemplateName Name = TemplateD.getAsVal<TemplateName>();
+ ClassTemplateDecl *ClassTemplate
+ = cast<ClassTemplateDecl>(Name.getAsTemplateDecl());
+
+ bool isPartialSpecialization = false;
+
+ // Check the validity of the template headers that introduce this
+ // template.
+ // FIXME: Once we have member templates, we'll need to check
+ // C++ [temp.expl.spec]p17-18, where we could have multiple levels of
+ // template<> headers.
+ if (TemplateParameterLists.size() == 0)
+ Diag(KWLoc, diag::err_template_spec_needs_header)
+ << CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
+ else {
+ TemplateParameterList *TemplateParams
+ = static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
+ if (TemplateParameterLists.size() > 1) {
+ Diag(TemplateParams->getTemplateLoc(),
+ diag::err_template_spec_extra_headers);
+ return true;
+ }
+
+ // FIXME: We'll need more checks, here!
+ if (TemplateParams->size() > 0)
+ isPartialSpecialization = true;
+ }
+
+ // Check that the specialization uses the same tag kind as the
+ // original template.
+ TagDecl::TagKind Kind;
+ switch (TagSpec) {
+ default: assert(0 && "Unknown tag type!");
+ case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
+ case DeclSpec::TST_union: Kind = TagDecl::TK_union; break;
+ case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
+ }
+ if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
+ Kind, KWLoc,
+ *ClassTemplate->getIdentifier())) {
+ Diag(KWLoc, diag::err_use_with_wrong_tag)
+ << ClassTemplate
+ << CodeModificationHint::CreateReplacement(KWLoc,
+ ClassTemplate->getTemplatedDecl()->getKindName());
+ Diag(ClassTemplate->getTemplatedDecl()->getLocation(),
+ diag::note_previous_use);
+ Kind = ClassTemplate->getTemplatedDecl()->getTagKind();
+ }
+
+ // Translate the parser's template argument list in our AST format.
+ llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+ translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
+
+ // Check that the template argument list is well-formed for this
+ // template.
+ llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs;
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
+ &TemplateArgs[0], TemplateArgs.size(),
+ RAngleLoc, ConvertedTemplateArgs))
+ return true;
+
+ assert((ConvertedTemplateArgs.size() ==
+ ClassTemplate->getTemplateParameters()->size()) &&
+ "Converted template argument list is too short!");
+
+ // Find the class template (partial) specialization declaration that
+ // corresponds to these arguments.
+ llvm::FoldingSetNodeID ID;
+ if (isPartialSpecialization)
+ // FIXME: Template parameter list matters, too
+ ClassTemplatePartialSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size());
+ else
+ ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size());
+ void *InsertPos = 0;
+ ClassTemplateSpecializationDecl *PrevDecl = 0;
+
+ if (isPartialSpecialization)
+ PrevDecl
+ = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID,
+ InsertPos);
+ else
+ PrevDecl
+ = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
+
+ ClassTemplateSpecializationDecl *Specialization = 0;
+
+ // Check whether we can declare a class template specialization in
+ // the current scope.
+ if (CheckClassTemplateSpecializationScope(ClassTemplate, PrevDecl,
+ TemplateNameLoc,
+ SS.getRange(),
+ /*ExplicitInstantiation=*/false))
+ return true;
+
+ if (PrevDecl && PrevDecl->getSpecializationKind() == TSK_Undeclared) {
+ // Since the only prior class template specialization with these
+ // arguments was referenced but not declared, reuse that
+ // declaration node as our own, updating its source location to
+ // reflect our new declaration.
+ Specialization = PrevDecl;
+ Specialization->setLocation(TemplateNameLoc);
+ PrevDecl = 0;
+ } else if (isPartialSpecialization) {
+ // FIXME: extra checking for partial specializations
+
+ // Create a new class template partial specialization declaration node.
+ TemplateParameterList *TemplateParams
+ = static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
+ ClassTemplatePartialSpecializationDecl *PrevPartial
+ = cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl);
+ ClassTemplatePartialSpecializationDecl *Partial
+ = ClassTemplatePartialSpecializationDecl::Create(Context,
+ ClassTemplate->getDeclContext(),
+ TemplateNameLoc,
+ TemplateParams,
+ ClassTemplate,
+ &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size(),
+ PrevPartial);
+
+ if (PrevPartial) {
+ ClassTemplate->getPartialSpecializations().RemoveNode(PrevPartial);
+ ClassTemplate->getPartialSpecializations().GetOrInsertNode(Partial);
+ } else {
+ ClassTemplate->getPartialSpecializations().InsertNode(Partial, InsertPos);
+ }
+ Specialization = Partial;
+ } else {
+ // Create a new class template specialization declaration node for
+ // this explicit specialization.
+ Specialization
+ = ClassTemplateSpecializationDecl::Create(Context,
+ ClassTemplate->getDeclContext(),
+ TemplateNameLoc,
+ ClassTemplate,
+ &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size(),
+ PrevDecl);
+
+ if (PrevDecl) {
+ ClassTemplate->getSpecializations().RemoveNode(PrevDecl);
+ ClassTemplate->getSpecializations().GetOrInsertNode(Specialization);
+ } else {
+ ClassTemplate->getSpecializations().InsertNode(Specialization,
+ InsertPos);
+ }
+ }
+
+ // Note that this is an explicit specialization.
+ Specialization->setSpecializationKind(TSK_ExplicitSpecialization);
+
+ // Check that this isn't a redefinition of this specialization.
+ if (TK == TK_Definition) {
+ if (RecordDecl *Def = Specialization->getDefinition(Context)) {
+ // FIXME: Should also handle explicit specialization after implicit
+ // instantiation with a special diagnostic.
+ SourceRange Range(TemplateNameLoc, RAngleLoc);
+ Diag(TemplateNameLoc, diag::err_redefinition)
+ << Context.getTypeDeclType(Specialization) << Range;
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ Specialization->setInvalidDecl();
+ return true;
+ }
+ }
+
+ // Build the fully-sugared type for this class template
+ // specialization as the user wrote in the specialization
+ // itself. This means that we'll pretty-print the type retrieved
+ // from the specialization's declaration the way that the user
+ // actually wrote the specialization, rather than formatting the
+ // name based on the "canonical" representation used to store the
+ // template arguments in the specialization.
+ QualType WrittenTy
+ = Context.getTemplateSpecializationType(Name,
+ &TemplateArgs[0],
+ TemplateArgs.size(),
+ Context.getTypeDeclType(Specialization));
+ Specialization->setTypeAsWritten(WrittenTy);
+ TemplateArgsIn.release();
+
+ // C++ [temp.expl.spec]p9:
+ // A template explicit specialization is in the scope of the
+ // namespace in which the template was defined.
+ //
+ // We actually implement this paragraph where we set the semantic
+ // context (in the creation of the ClassTemplateSpecializationDecl),
+ // but we also maintain the lexical context where the actual
+ // definition occurs.
+ Specialization->setLexicalDeclContext(CurContext);
+
+ // We may be starting the definition of this specialization.
+ if (TK == TK_Definition)
+ Specialization->startDefinition();
+
+ // Add the specialization into its lexical context, so that it can
+ // be seen when iterating through the list of declarations in that
+ // context. However, specializations are not found by name lookup.
+ CurContext->addDecl(Context, Specialization);
+ return DeclPtrTy::make(Specialization);
+}
+
+// Explicit instantiation of a class template specialization
+Sema::DeclResult
+Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
+ unsigned TagSpec,
+ SourceLocation KWLoc,
+ const CXXScopeSpec &SS,
+ TemplateTy TemplateD,
+ SourceLocation TemplateNameLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgsIn,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc,
+ AttributeList *Attr) {
+ // Find the class template we're specializing
+ TemplateName Name = TemplateD.getAsVal<TemplateName>();
+ ClassTemplateDecl *ClassTemplate
+ = cast<ClassTemplateDecl>(Name.getAsTemplateDecl());
+
+ // Check that the specialization uses the same tag kind as the
+ // original template.
+ TagDecl::TagKind Kind;
+ switch (TagSpec) {
+ default: assert(0 && "Unknown tag type!");
+ case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
+ case DeclSpec::TST_union: Kind = TagDecl::TK_union; break;
+ case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
+ }
+ if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
+ Kind, KWLoc,
+ *ClassTemplate->getIdentifier())) {
+ Diag(KWLoc, diag::err_use_with_wrong_tag)
+ << ClassTemplate
+ << CodeModificationHint::CreateReplacement(KWLoc,
+ ClassTemplate->getTemplatedDecl()->getKindName());
+ Diag(ClassTemplate->getTemplatedDecl()->getLocation(),
+ diag::note_previous_use);
+ Kind = ClassTemplate->getTemplatedDecl()->getTagKind();
+ }
+
+ // C++0x [temp.explicit]p2:
+ // [...] An explicit instantiation shall appear in an enclosing
+ // namespace of its template. [...]
+ //
+ // This is C++ DR 275.
+ if (CheckClassTemplateSpecializationScope(ClassTemplate, 0,
+ TemplateNameLoc,
+ SS.getRange(),
+ /*ExplicitInstantiation=*/true))
+ return true;
+
+ // Translate the parser's template argument list in our AST format.
+ llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+ translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
+
+ // Check that the template argument list is well-formed for this
+ // template.
+ llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs;
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
+ &TemplateArgs[0], TemplateArgs.size(),
+ RAngleLoc, ConvertedTemplateArgs))
+ return true;
+
+ assert((ConvertedTemplateArgs.size() ==
+ ClassTemplate->getTemplateParameters()->size()) &&
+ "Converted template argument list is too short!");
+
+ // Find the class template specialization declaration that
+ // corresponds to these arguments.
+ llvm::FoldingSetNodeID ID;
+ ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size());
+ void *InsertPos = 0;
+ ClassTemplateSpecializationDecl *PrevDecl
+ = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
+
+ ClassTemplateSpecializationDecl *Specialization = 0;
+
+ bool SpecializationRequiresInstantiation = true;
+ if (PrevDecl) {
+ if (PrevDecl->getSpecializationKind() == TSK_ExplicitInstantiation) {
+ // This particular specialization has already been declared or
+ // instantiated. We cannot explicitly instantiate it.
+ Diag(TemplateNameLoc, diag::err_explicit_instantiation_duplicate)
+ << Context.getTypeDeclType(PrevDecl);
+ Diag(PrevDecl->getLocation(),
+ diag::note_previous_explicit_instantiation);
+ return DeclPtrTy::make(PrevDecl);
+ }
+
+ if (PrevDecl->getSpecializationKind() == TSK_ExplicitSpecialization) {
+ // C++ DR 259, C++0x [temp.explicit]p4:
+ // For a given set of template parameters, if an explicit
+ // instantiation of a template appears after a declaration of
+ // an explicit specialization for that template, the explicit
+ // instantiation has no effect.
+ if (!getLangOptions().CPlusPlus0x) {
+ Diag(TemplateNameLoc,
+ diag::ext_explicit_instantiation_after_specialization)
+ << Context.getTypeDeclType(PrevDecl);
+ Diag(PrevDecl->getLocation(),
+ diag::note_previous_template_specialization);
+ }
+
+ // Create a new class template specialization declaration node
+ // for this explicit specialization. This node is only used to
+ // record the existence of this explicit instantiation for
+ // accurate reproduction of the source code; we don't actually
+ // use it for anything, since it is semantically irrelevant.
+ Specialization
+ = ClassTemplateSpecializationDecl::Create(Context,
+ ClassTemplate->getDeclContext(),
+ TemplateNameLoc,
+ ClassTemplate,
+ &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size(),
+ 0);
+ Specialization->setLexicalDeclContext(CurContext);
+ CurContext->addDecl(Context, Specialization);
+ return DeclPtrTy::make(Specialization);
+ }
+
+ // If we have already (implicitly) instantiated this
+ // specialization, there is less work to do.
+ if (PrevDecl->getSpecializationKind() == TSK_ImplicitInstantiation)
+ SpecializationRequiresInstantiation = false;
+
+ // Since the only prior class template specialization with these
+ // arguments was referenced but not declared, reuse that
+ // declaration node as our own, updating its source location to
+ // reflect our new declaration.
+ Specialization = PrevDecl;
+ Specialization->setLocation(TemplateNameLoc);
+ PrevDecl = 0;
+ } else {
+ // Create a new class template specialization declaration node for
+ // this explicit specialization.
+ Specialization
+ = ClassTemplateSpecializationDecl::Create(Context,
+ ClassTemplate->getDeclContext(),
+ TemplateNameLoc,
+ ClassTemplate,
+ &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size(),
+ 0);
+
+ ClassTemplate->getSpecializations().InsertNode(Specialization,
+ InsertPos);
+ }
+
+ // Build the fully-sugared type for this explicit instantiation as
+ // the user wrote in the explicit instantiation itself. This means
+ // that we'll pretty-print the type retrieved from the
+ // specialization's declaration the way that the user actually wrote
+ // the explicit instantiation, rather than formatting the name based
+ // on the "canonical" representation used to store the template
+ // arguments in the specialization.
+ QualType WrittenTy
+ = Context.getTemplateSpecializationType(Name,
+ &TemplateArgs[0],
+ TemplateArgs.size(),
+ Context.getTypeDeclType(Specialization));
+ Specialization->setTypeAsWritten(WrittenTy);
+ TemplateArgsIn.release();
+
+ // Add the explicit instantiation into its lexical context. However,
+ // since explicit instantiations are never found by name lookup, we
+ // just put it into the declaration context directly.
+ Specialization->setLexicalDeclContext(CurContext);
+ CurContext->addDecl(Context, Specialization);
+
+ // C++ [temp.explicit]p3:
+ // A definition of a class template or class member template
+ // shall be in scope at the point of the explicit instantiation of
+ // the class template or class member template.
+ //
+ // This check comes when we actually try to perform the
+ // instantiation.
+ if (SpecializationRequiresInstantiation)
+ InstantiateClassTemplateSpecialization(Specialization, true);
+ else // Instantiate the members of this class template specialization.
+ InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization);
+
+ return DeclPtrTy::make(Specialization);
+}
+
+// Explicit instantiation of a member class of a class template.
+Sema::DeclResult
+Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
+ unsigned TagSpec,
+ SourceLocation KWLoc,
+ const CXXScopeSpec &SS,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ AttributeList *Attr) {
+
+ bool Owned = false;
+ DeclPtrTy TagD = ActOnTag(S, TagSpec, Action::TK_Reference,
+ KWLoc, SS, Name, NameLoc, Attr, AS_none, Owned);
+ if (!TagD)
+ return true;
+
+ TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>());
+ if (Tag->isEnum()) {
+ Diag(TemplateLoc, diag::err_explicit_instantiation_enum)
+ << Context.getTypeDeclType(Tag);
+ return true;
+ }
+
+ if (Tag->isInvalidDecl())
+ return true;
+
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(Tag);
+ CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass();
+ if (!Pattern) {
+ Diag(TemplateLoc, diag::err_explicit_instantiation_nontemplate_type)
+ << Context.getTypeDeclType(Record);
+ Diag(Record->getLocation(), diag::note_nontemplate_decl_here);
+ return true;
+ }
+
+ // C++0x [temp.explicit]p2:
+ // [...] An explicit instantiation shall appear in an enclosing
+ // namespace of its template. [...]
+ //
+ // This is C++ DR 275.
+ if (getLangOptions().CPlusPlus0x) {
+ // FIXME: In C++98, we would like to turn these errors into warnings,
+ // dependent on a -Wc++0x flag.
+ DeclContext *PatternContext
+ = Pattern->getDeclContext()->getEnclosingNamespaceContext();
+ if (!CurContext->Encloses(PatternContext)) {
+ Diag(TemplateLoc, diag::err_explicit_instantiation_out_of_scope)
+ << Record << cast<NamedDecl>(PatternContext) << SS.getRange();
+ Diag(Pattern->getLocation(), diag::note_previous_declaration);
+ }
+ }
+
+ if (!Record->getDefinition(Context)) {
+ // If the class has a definition, instantiate it (and all of its
+ // members, recursively).
+ Pattern = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
+ if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern,
+ getTemplateInstantiationArgs(Record),
+ /*ExplicitInstantiation=*/true))
+ return true;
+ } else // Instantiate all of the members of class.
+ InstantiateClassMembers(TemplateLoc, Record,
+ getTemplateInstantiationArgs(Record));
+
+ // FIXME: We don't have any representation for explicit instantiations of
+ // member classes. Such a representation is not needed for compilation, but it
+ // should be available for clients that want to see all of the declarations in
+ // the source code.
+ return TagD;
+}
+
+Sema::TypeResult
+Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
+ const IdentifierInfo &II, SourceLocation IdLoc) {
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ if (!NNS)
+ return true;
+
+ QualType T = CheckTypenameType(NNS, II, SourceRange(TypenameLoc, IdLoc));
+ if (T.isNull())
+ return true;
+ return T.getAsOpaquePtr();
+}
+
+Sema::TypeResult
+Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
+ SourceLocation TemplateLoc, TypeTy *Ty) {
+ QualType T = QualType::getFromOpaquePtr(Ty);
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ const TemplateSpecializationType *TemplateId
+ = T->getAsTemplateSpecializationType();
+ assert(TemplateId && "Expected a template specialization type");
+
+ if (NNS->isDependent())
+ return Context.getTypenameType(NNS, TemplateId).getAsOpaquePtr();
+
+ return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
+}
+
+/// \brief Build the type that describes a C++ typename specifier,
+/// e.g., "typename T::type".
+QualType
+Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
+ SourceRange Range) {
+ CXXRecordDecl *CurrentInstantiation = 0;
+ if (NNS->isDependent()) {
+ CurrentInstantiation = getCurrentInstantiationOf(NNS);
+
+ // If the nested-name-specifier does not refer to the current
+ // instantiation, then build a typename type.
+ if (!CurrentInstantiation)
+ return Context.getTypenameType(NNS, &II);
+ }
+
+ DeclContext *Ctx = 0;
+
+ if (CurrentInstantiation)
+ Ctx = CurrentInstantiation;
+ else {
+ CXXScopeSpec SS;
+ SS.setScopeRep(NNS);
+ SS.setRange(Range);
+ if (RequireCompleteDeclContext(SS))
+ return QualType();
+
+ Ctx = computeDeclContext(SS);
+ }
+ assert(Ctx && "No declaration context?");
+
+ DeclarationName Name(&II);
+ LookupResult Result = LookupQualifiedName(Ctx, Name, LookupOrdinaryName,
+ false);
+ unsigned DiagID = 0;
+ Decl *Referenced = 0;
+ switch (Result.getKind()) {
+ case LookupResult::NotFound:
+ if (Ctx->isTranslationUnit())
+ DiagID = diag::err_typename_nested_not_found_global;
+ else
+ DiagID = diag::err_typename_nested_not_found;
+ break;
+
+ case LookupResult::Found:
+ if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getAsDecl())) {
+ // We found a type. Build a QualifiedNameType, since the
+ // typename-specifier was just sugar. FIXME: Tell
+ // QualifiedNameType that it has a "typename" prefix.
+ return Context.getQualifiedNameType(NNS, Context.getTypeDeclType(Type));
+ }
+
+ DiagID = diag::err_typename_nested_not_type;
+ Referenced = Result.getAsDecl();
+ break;
+
+ case LookupResult::FoundOverloaded:
+ DiagID = diag::err_typename_nested_not_type;
+ Referenced = *Result.begin();
+ break;
+
+ case LookupResult::AmbiguousBaseSubobjectTypes:
+ case LookupResult::AmbiguousBaseSubobjects:
+ case LookupResult::AmbiguousReference:
+ DiagnoseAmbiguousLookup(Result, Name, Range.getEnd(), Range);
+ return QualType();
+ }
+
+ // If we get here, it's because name lookup did not find a
+ // type. Emit an appropriate diagnostic and return an error.
+ if (NamedDecl *NamedCtx = dyn_cast<NamedDecl>(Ctx))
+ Diag(Range.getEnd(), DiagID) << Range << Name << NamedCtx;
+ else
+ Diag(Range.getEnd(), DiagID) << Range << Name;
+ if (Referenced)
+ Diag(Referenced->getLocation(), diag::note_typename_refers_here)
+ << Name;
+ return QualType();
+}
+
+// FIXME: Move to SemaTemplateDeduction.cpp
+bool
+Sema::DeduceTemplateArguments(QualType Param, QualType Arg,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ // We only want to look at the canonical types, since typedefs and
+ // sugar are not part of template argument deduction.
+ Param = Context.getCanonicalType(Param);
+ Arg = Context.getCanonicalType(Arg);
+
+ // If the parameter type is not dependent, just compare the types
+ // directly.
+ if (!Param->isDependentType())
+ return Param == Arg;
+
+ // FIXME: Use a visitor or switch to handle all of the kinds of
+ // types that the parameter may be.
+ if (const TemplateTypeParmType *TemplateTypeParm
+ = Param->getAsTemplateTypeParmType()) {
+ (void)TemplateTypeParm; // FIXME: use this
+ // The argument type can not be less qualified than the parameter
+ // type.
+ if (Param.isMoreQualifiedThan(Arg))
+ return false;
+
+ unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
+ QualType DeducedType = Arg.getQualifiedType(Quals);
+ // FIXME: actually save the deduced type, and check that this
+ // deduction is consistent.
+ return true;
+ }
+
+ if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
+ return false;
+
+ if (const PointerType *PointerParam = Param->getAsPointerType()) {
+ const PointerType *PointerArg = Arg->getAsPointerType();
+ if (!PointerArg)
+ return false;
+
+ return DeduceTemplateArguments(PointerParam->getPointeeType(),
+ PointerArg->getPointeeType(),
+ Deduced);
+ }
+
+ // FIXME: Many more cases to go (to go).
+ return false;
+}
+
+bool
+Sema::DeduceTemplateArguments(const TemplateArgument &Param,
+ const TemplateArgument &Arg,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ assert(Param.getKind() == Arg.getKind() &&
+ "Template argument kind mismatch during deduction");
+ switch (Param.getKind()) {
+ case TemplateArgument::Type:
+ return DeduceTemplateArguments(Param.getAsType(), Arg.getAsType(),
+ Deduced);
+
+ default:
+ return false;
+ }
+}
+
+bool
+Sema::DeduceTemplateArguments(const TemplateArgumentList &ParamList,
+ const TemplateArgumentList &ArgList,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ assert(ParamList.size() == ArgList.size());
+ for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
+ if (!DeduceTemplateArguments(ParamList[I], ArgList[I], Deduced))
+ return false;
+ }
+ return true;
+}
+
+
+bool
+Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
+ const TemplateArgumentList &TemplateArgs) {
+ llvm::SmallVector<TemplateArgument, 4> Deduced;
+ Deduced.resize(Partial->getTemplateParameters()->size());
+ return DeduceTemplateArguments(Partial->getTemplateArgs(), TemplateArgs,
+ Deduced);
+}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
new file mode 100644
index 000000000000..d3d771b0ebb6
--- /dev/null
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -0,0 +1,1034 @@
+//===------- SemaTemplateInstantiate.cpp - C++ Template Instantiation ------===/
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===/
+//
+// This file implements C++ template instantiation.
+//
+//===----------------------------------------------------------------------===/
+
+#include "Sema.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===/
+// Template Instantiation Support
+//===----------------------------------------------------------------------===/
+
+/// \brief Retrieve the template argument list that should be used to
+/// instantiate the given declaration.
+const TemplateArgumentList &
+Sema::getTemplateInstantiationArgs(NamedDecl *D) {
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(D))
+ return Spec->getTemplateArgs();
+
+ DeclContext *EnclosingTemplateCtx = D->getDeclContext();
+ while (!isa<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx)) {
+ assert(!EnclosingTemplateCtx->isFileContext() &&
+ "Tried to get the instantiation arguments of a non-template");
+ EnclosingTemplateCtx = EnclosingTemplateCtx->getParent();
+ }
+
+ ClassTemplateSpecializationDecl *EnclosingTemplate
+ = cast<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx);
+ return EnclosingTemplate->getTemplateArgs();
+}
+
+Sema::InstantiatingTemplate::
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ Decl *Entity,
+ SourceRange InstantiationRange)
+ : SemaRef(SemaRef) {
+
+ Invalid = CheckInstantiationDepth(PointOfInstantiation,
+ InstantiationRange);
+ if (!Invalid) {
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind = ActiveTemplateInstantiation::TemplateInstantiation;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Entity = reinterpret_cast<uintptr_t>(Entity);
+ Inst.TemplateArgs = 0;
+ Inst.NumTemplateArgs = 0;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+ Invalid = false;
+ }
+}
+
+Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
+ SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange)
+ : SemaRef(SemaRef) {
+
+ Invalid = CheckInstantiationDepth(PointOfInstantiation,
+ InstantiationRange);
+ if (!Invalid) {
+ ActiveTemplateInstantiation Inst;
+ Inst.Kind
+ = ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation;
+ Inst.PointOfInstantiation = PointOfInstantiation;
+ Inst.Entity = reinterpret_cast<uintptr_t>(Template);
+ Inst.TemplateArgs = TemplateArgs;
+ Inst.NumTemplateArgs = NumTemplateArgs;
+ Inst.InstantiationRange = InstantiationRange;
+ SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+ Invalid = false;
+ }
+}
+
+void Sema::InstantiatingTemplate::Clear() {
+ if (!Invalid) {
+ SemaRef.ActiveTemplateInstantiations.pop_back();
+ Invalid = true;
+ }
+}
+
+bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
+ SourceLocation PointOfInstantiation,
+ SourceRange InstantiationRange) {
+ if (SemaRef.ActiveTemplateInstantiations.size()
+ <= SemaRef.getLangOptions().InstantiationDepth)
+ return false;
+
+ SemaRef.Diag(PointOfInstantiation,
+ diag::err_template_recursion_depth_exceeded)
+ << SemaRef.getLangOptions().InstantiationDepth
+ << InstantiationRange;
+ SemaRef.Diag(PointOfInstantiation, diag::note_template_recursion_depth)
+ << SemaRef.getLangOptions().InstantiationDepth;
+ return true;
+}
+
+/// \brief Prints the current instantiation stack through a series of
+/// notes.
+void Sema::PrintInstantiationStack() {
+ for (llvm::SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator
+ Active = ActiveTemplateInstantiations.rbegin(),
+ ActiveEnd = ActiveTemplateInstantiations.rend();
+ Active != ActiveEnd;
+ ++Active) {
+ switch (Active->Kind) {
+ case ActiveTemplateInstantiation::TemplateInstantiation: {
+ Decl *D = reinterpret_cast<Decl *>(Active->Entity);
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
+ unsigned DiagID = diag::note_template_member_class_here;
+ if (isa<ClassTemplateSpecializationDecl>(Record))
+ DiagID = diag::note_template_class_instantiation_here;
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ DiagID)
+ << Context.getTypeDeclType(Record)
+ << Active->InstantiationRange;
+ } else {
+ FunctionDecl *Function = cast<FunctionDecl>(D);
+ unsigned DiagID = diag::note_template_member_function_here;
+ // FIXME: check for a function template
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ DiagID)
+ << Function
+ << Active->InstantiationRange;
+ }
+ break;
+ }
+
+ case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: {
+ TemplateDecl *Template = cast<TemplateDecl>((Decl *)Active->Entity);
+ std::string TemplateArgsStr
+ = TemplateSpecializationType::PrintTemplateArgumentList(
+ Active->TemplateArgs,
+ Active->NumTemplateArgs,
+ Context.PrintingPolicy);
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ diag::note_default_arg_instantiation_here)
+ << (Template->getNameAsString() + TemplateArgsStr)
+ << Active->InstantiationRange;
+ break;
+ }
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===/
+// Template Instantiation for Types
+//===----------------------------------------------------------------------===/
+namespace {
+ class VISIBILITY_HIDDEN TemplateTypeInstantiator {
+ Sema &SemaRef;
+ const TemplateArgumentList &TemplateArgs;
+ SourceLocation Loc;
+ DeclarationName Entity;
+
+ public:
+ TemplateTypeInstantiator(Sema &SemaRef,
+ const TemplateArgumentList &TemplateArgs,
+ SourceLocation Loc,
+ DeclarationName Entity)
+ : SemaRef(SemaRef), TemplateArgs(TemplateArgs),
+ Loc(Loc), Entity(Entity) { }
+
+ QualType operator()(QualType T) const { return Instantiate(T); }
+
+ QualType Instantiate(QualType T) const;
+
+ // Declare instantiate functions for each type.
+#define TYPE(Class, Base) \
+ QualType Instantiate##Class##Type(const Class##Type *T, \
+ unsigned Quals) const;
+#define ABSTRACT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+ };
+}
+
+QualType
+TemplateTypeInstantiator::InstantiateExtQualType(const ExtQualType *T,
+ unsigned Quals) const {
+ // FIXME: Implement this
+ assert(false && "Cannot instantiate ExtQualType yet");
+ return QualType();
+}
+
+QualType
+TemplateTypeInstantiator::InstantiateBuiltinType(const BuiltinType *T,
+ unsigned Quals) const {
+ assert(false && "Builtin types are not dependent and cannot be instantiated");
+ return QualType(T, Quals);
+}
+
+QualType
+TemplateTypeInstantiator::
+InstantiateFixedWidthIntType(const FixedWidthIntType *T, unsigned Quals) const {
+ // FIXME: Implement this
+ assert(false && "Cannot instantiate FixedWidthIntType yet");
+ return QualType();
+}
+
+QualType
+TemplateTypeInstantiator::InstantiateComplexType(const ComplexType *T,
+ unsigned Quals) const {
+ // FIXME: Implement this
+ assert(false && "Cannot instantiate ComplexType yet");
+ return QualType();
+}
+
+QualType
+TemplateTypeInstantiator::InstantiatePointerType(const PointerType *T,
+ unsigned Quals) const {
+ QualType PointeeType = Instantiate(T->getPointeeType());
+ if (PointeeType.isNull())
+ return QualType();
+
+ return SemaRef.BuildPointerType(PointeeType, Quals, Loc, Entity);
+}
+
+QualType
+TemplateTypeInstantiator::InstantiateBlockPointerType(const BlockPointerType *T,
+ unsigned Quals) const {
+ // FIXME: Implement this
+ assert(false && "Cannot instantiate BlockPointerType yet");
+ return QualType();
+}
+
+QualType
+TemplateTypeInstantiator::InstantiateLValueReferenceType(
+ const LValueReferenceType *T, unsigned Quals) const {
+ QualType ReferentType = Instantiate(T->getPointeeType());
+ if (ReferentType.isNull())
+ return QualType();
+
+ return SemaRef.BuildReferenceType(ReferentType, true, Quals, Loc, Entity);
+}
+
+QualType
+TemplateTypeInstantiator::InstantiateRValueReferenceType(
+ const RValueReferenceType *T, unsigned Quals) const {
+ QualType ReferentType = Instantiate(T->getPointeeType());
+ if (ReferentType.isNull())
+ return QualType();
+
+ return SemaRef.BuildReferenceType(ReferentType, false, Quals, Loc, Entity);
+}
+
+QualType
+TemplateTypeInstantiator::
+InstantiateMemberPointerType(const MemberPointerType *T,
+ unsigned Quals) const {
+ // FIXME: Implement this
+ assert(false && "Cannot instantiate MemberPointerType yet");
+ return QualType();
+}
+
+QualType
+TemplateTypeInstantiator::
+InstantiateConstantArrayType(const ConstantArrayType *T,
+ unsigned Quals) const {
+ QualType ElementType = Instantiate(T->getElementType());
+ if (ElementType.isNull())
+ return ElementType;
+
+ // Build a temporary integer literal to specify the size for
+ // BuildArrayType. Since we have already checked the size as part of
+ // creating the dependent array type in the first place, we know
+ // there aren't any errors. However, we do need to determine what
+ // C++ type to give the size expression.
+ llvm::APInt Size = T->getSize();
+ QualType Types[] = {
+ SemaRef.Context.UnsignedCharTy, SemaRef.Context.UnsignedShortTy,
+ SemaRef.Context.UnsignedIntTy, SemaRef.Context.UnsignedLongTy,
+ SemaRef.Context.UnsignedLongLongTy, SemaRef.Context.UnsignedInt128Ty
+ };
+ const unsigned NumTypes = sizeof(Types) / sizeof(QualType);
+ QualType SizeType;
+ for (unsigned I = 0; I != NumTypes; ++I)
+ if (Size.getBitWidth() == SemaRef.Context.getIntWidth(Types[I])) {
+ SizeType = Types[I];
+ break;
+ }
+
+ if (SizeType.isNull())
+ SizeType = SemaRef.Context.getFixedWidthIntType(Size.getBitWidth(), false);
+
+ IntegerLiteral ArraySize(Size, SizeType, Loc);
+ return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(),
+ &ArraySize, T->getIndexTypeQualifier(),
+ Loc, Entity);
+}
+
+QualType
+TemplateTypeInstantiator::
+InstantiateIncompleteArrayType(const IncompleteArrayType *T,
+ unsigned Quals) const {
+ QualType ElementType = Instantiate(T->getElementType());
+ if (ElementType.isNull())
+ return ElementType;
+
+ return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(),
+ 0, T->getIndexTypeQualifier(),
+ Loc, Entity);
+}
+
+QualType
+TemplateTypeInstantiator::
+InstantiateVariableArrayType(const VariableArrayType *T,
+ unsigned Quals) const {
+ // FIXME: Implement this
+ assert(false && "Cannot instantiate VariableArrayType yet");
+ return QualType();
+}
+
+QualType
+TemplateTypeInstantiator::
+InstantiateDependentSizedArrayType(const DependentSizedArrayType *T,
+ unsigned Quals) const {
+ Expr *ArraySize = T->getSizeExpr();
+ assert(ArraySize->isValueDependent() &&
+ "dependent sized array types must have value dependent size expr");
+
+ // Instantiate the element type if needed
+ QualType ElementType = T->getElementType();
+ if (ElementType->isDependentType()) {
+ ElementType = Instantiate(ElementType);
+ if (ElementType.isNull())
+ return QualType();
+ }
+
+ // Instantiate the size expression
+ Sema::OwningExprResult InstantiatedArraySize =
+ SemaRef.InstantiateExpr(ArraySize, TemplateArgs);
+ if (InstantiatedArraySize.isInvalid())
+ return QualType();
+
+ return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(),
+ InstantiatedArraySize.takeAs<Expr>(),
+ T->getIndexTypeQualifier(), Loc, Entity);
+}
+
+QualType
+TemplateTypeInstantiator::InstantiateVectorType(const VectorType *T,
+ unsigned Quals) const {
+ // FIXME: Implement this
+ assert(false && "Cannot instantiate VectorType yet");
+ return QualType();
+}
+
+QualType
+TemplateTypeInstantiator::InstantiateExtVectorType(const ExtVectorType *T,
+ unsigned Quals) const {
+ // FIXME: Implement this
+ assert(false && "Cannot instantiate ExtVectorType yet");
+ return QualType();
+}
+
+QualType
+TemplateTypeInstantiator::
+InstantiateFunctionProtoType(const FunctionProtoType *T,
+ unsigned Quals) const {
+ QualType ResultType = Instantiate(T->getResultType());
+ if (ResultType.isNull())
+ return ResultType;
+
+ llvm::SmallVector<QualType, 4> ParamTypes;
+ for (FunctionProtoType::arg_type_iterator Param = T->arg_type_begin(),
+ ParamEnd = T->arg_type_end();
+ Param != ParamEnd; ++Param) {
+ QualType P = Instantiate(*Param);
+ if (P.isNull())
+ return P;
+
+ ParamTypes.push_back(P);
+ }
+
+ return SemaRef.BuildFunctionType(ResultType, &ParamTypes[0],
+ ParamTypes.size(),
+ T->isVariadic(), T->getTypeQuals(),
+ Loc, Entity);
+}
+
+QualType
+TemplateTypeInstantiator::
+InstantiateFunctionNoProtoType(const FunctionNoProtoType *T,
+ unsigned Quals) const {
+ assert(false && "Functions without prototypes cannot be dependent.");
+ return QualType();
+}
+
+QualType
+TemplateTypeInstantiator::InstantiateTypedefType(const TypedefType *T,
+ unsigned Quals) const {
+ TypedefDecl *Typedef
+ = cast_or_null<TypedefDecl>(
+ SemaRef.InstantiateCurrentDeclRef(T->getDecl()));
+ if (!Typedef)
+ return QualType();
+
+ return SemaRef.Context.getTypeDeclType(Typedef);
+}
+
+QualType
+TemplateTypeInstantiator::InstantiateTypeOfExprType(const TypeOfExprType *T,
+ unsigned Quals) const {
+ Sema::OwningExprResult E
+ = SemaRef.InstantiateExpr(T->getUnderlyingExpr(), TemplateArgs);
+ if (E.isInvalid())
+ return QualType();
+
+ return SemaRef.Context.getTypeOfExprType(E.takeAs<Expr>());
+}
+
+QualType
+TemplateTypeInstantiator::InstantiateTypeOfType(const TypeOfType *T,
+ unsigned Quals) const {
+ QualType Underlying = Instantiate(T->getUnderlyingType());
+ if (Underlying.isNull())
+ return QualType();
+
+ return SemaRef.Context.getTypeOfType(Underlying);
+}
+
+QualType
+TemplateTypeInstantiator::InstantiateRecordType(const RecordType *T,
+ unsigned Quals) const {
+ RecordDecl *Record
+ = cast_or_null<RecordDecl>(SemaRef.InstantiateCurrentDeclRef(T->getDecl()));
+ if (!Record)
+ return QualType();
+
+ return SemaRef.Context.getTypeDeclType(Record);
+}
+
+QualType
+TemplateTypeInstantiator::InstantiateEnumType(const EnumType *T,
+ unsigned Quals) const {
+ EnumDecl *Enum
+ = cast_or_null<EnumDecl>(SemaRef.InstantiateCurrentDeclRef(T->getDecl()));
+ if (!Enum)
+ return QualType();
+
+ return SemaRef.Context.getTypeDeclType(Enum);
+}
+
+QualType
+TemplateTypeInstantiator::
+InstantiateTemplateTypeParmType(const TemplateTypeParmType *T,
+ unsigned Quals) const {
+ if (T->getDepth() == 0) {
+ // Replace the template type parameter with its corresponding
+ // template argument.
+ assert(TemplateArgs[T->getIndex()].getKind() == TemplateArgument::Type &&
+ "Template argument kind mismatch");
+ QualType Result = TemplateArgs[T->getIndex()].getAsType();
+ if (Result.isNull() || !Quals)
+ return Result;
+
+ // C++ [dcl.ref]p1:
+ // [...] Cv-qualified references are ill-formed except when
+ // the cv-qualifiers are introduced through the use of a
+ // typedef (7.1.3) or of a template type argument (14.3), in
+ // which case the cv-qualifiers are ignored.
+ if (Quals && Result->isReferenceType())
+ Quals = 0;
+
+ return QualType(Result.getTypePtr(), Quals | Result.getCVRQualifiers());
+ }
+
+ // The template type parameter comes from an inner template (e.g.,
+ // the template parameter list of a member template inside the
+ // template we are instantiating). Create a new template type
+ // parameter with the template "level" reduced by one.
+ return SemaRef.Context.getTemplateTypeParmType(T->getDepth() - 1,
+ T->getIndex(),
+ T->getName())
+ .getQualifiedType(Quals);
+}
+
+QualType
+TemplateTypeInstantiator::
+InstantiateTemplateSpecializationType(
+ const TemplateSpecializationType *T,
+ unsigned Quals) const {
+ llvm::SmallVector<TemplateArgument, 4> InstantiatedTemplateArgs;
+ InstantiatedTemplateArgs.reserve(T->getNumArgs());
+ for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end();
+ Arg != ArgEnd; ++Arg) {
+ switch (Arg->getKind()) {
+ case TemplateArgument::Type: {
+ QualType T = SemaRef.InstantiateType(Arg->getAsType(),
+ TemplateArgs,
+ Arg->getLocation(),
+ DeclarationName());
+ if (T.isNull())
+ return QualType();
+
+ InstantiatedTemplateArgs.push_back(
+ TemplateArgument(Arg->getLocation(), T));
+ break;
+ }
+
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Integral:
+ InstantiatedTemplateArgs.push_back(*Arg);
+ break;
+
+ case TemplateArgument::Expression:
+ Sema::OwningExprResult E
+ = SemaRef.InstantiateExpr(Arg->getAsExpr(), TemplateArgs);
+ if (E.isInvalid())
+ return QualType();
+ InstantiatedTemplateArgs.push_back(E.takeAs<Expr>());
+ break;
+ }
+ }
+
+ // FIXME: We're missing the locations of the template name, '<', and '>'.
+
+ TemplateName Name = SemaRef.InstantiateTemplateName(T->getTemplateName(),
+ Loc,
+ TemplateArgs);
+
+ return SemaRef.CheckTemplateIdType(Name, Loc, SourceLocation(),
+ &InstantiatedTemplateArgs[0],
+ InstantiatedTemplateArgs.size(),
+ SourceLocation());
+}
+
+QualType
+TemplateTypeInstantiator::
+InstantiateQualifiedNameType(const QualifiedNameType *T,
+ unsigned Quals) const {
+ // When we instantiated a qualified name type, there's no point in
+ // keeping the qualification around in the instantiated result. So,
+ // just instantiate the named type.
+ return (*this)(T->getNamedType());
+}
+
+QualType
+TemplateTypeInstantiator::
+InstantiateTypenameType(const TypenameType *T, unsigned Quals) const {
+ if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) {
+ // When the typename type refers to a template-id, the template-id
+ // is dependent and has enough information to instantiate the
+ // result of the typename type. Since we don't care about keeping
+ // the spelling of the typename type in template instantiations,
+ // we just instantiate the template-id.
+ return InstantiateTemplateSpecializationType(TemplateId, Quals);
+ }
+
+ NestedNameSpecifier *NNS
+ = SemaRef.InstantiateNestedNameSpecifier(T->getQualifier(),
+ SourceRange(Loc),
+ TemplateArgs);
+ if (!NNS)
+ return QualType();
+
+ return SemaRef.CheckTypenameType(NNS, *T->getIdentifier(), SourceRange(Loc));
+}
+
+QualType
+TemplateTypeInstantiator::
+InstantiateObjCInterfaceType(const ObjCInterfaceType *T,
+ unsigned Quals) const {
+ assert(false && "Objective-C types cannot be dependent");
+ return QualType();
+}
+
+QualType
+TemplateTypeInstantiator::
+InstantiateObjCQualifiedInterfaceType(const ObjCQualifiedInterfaceType *T,
+ unsigned Quals) const {
+ assert(false && "Objective-C types cannot be dependent");
+ return QualType();
+}
+
+QualType
+TemplateTypeInstantiator::
+InstantiateObjCQualifiedIdType(const ObjCQualifiedIdType *T,
+ unsigned Quals) const {
+ assert(false && "Objective-C types cannot be dependent");
+ return QualType();
+}
+
+/// \brief The actual implementation of Sema::InstantiateType().
+QualType TemplateTypeInstantiator::Instantiate(QualType T) const {
+ // If T is not a dependent type, there is nothing to do.
+ if (!T->isDependentType())
+ return T;
+
+ switch (T->getTypeClass()) {
+#define TYPE(Class, Base) \
+ case Type::Class: \
+ return Instantiate##Class##Type(cast<Class##Type>(T.getTypePtr()), \
+ T.getCVRQualifiers());
+#define ABSTRACT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+ }
+
+ assert(false && "Not all types have been decoded for instantiation");
+ return QualType();
+}
+
+/// \brief Instantiate the type T with a given set of template arguments.
+///
+/// This routine substitutes the given template arguments into the
+/// type T and produces the instantiated type.
+///
+/// \param T the type into which the template arguments will be
+/// substituted. If this type is not dependent, it will be returned
+/// immediately.
+///
+/// \param TemplateArgs the template arguments that will be
+/// substituted for the top-level template parameters within T.
+///
+/// \param Loc the location in the source code where this substitution
+/// is being performed. It will typically be the location of the
+/// declarator (if we're instantiating the type of some declaration)
+/// or the location of the type in the source code (if, e.g., we're
+/// instantiating the type of a cast expression).
+///
+/// \param Entity the name of the entity associated with a declaration
+/// being instantiated (if any). May be empty to indicate that there
+/// is no such entity (if, e.g., this is a type that occurs as part of
+/// a cast expression) or that the entity has no name (e.g., an
+/// unnamed function parameter).
+///
+/// \returns If the instantiation succeeds, the instantiated
+/// type. Otherwise, produces diagnostics and returns a NULL type.
+QualType Sema::InstantiateType(QualType T,
+ const TemplateArgumentList &TemplateArgs,
+ SourceLocation Loc, DeclarationName Entity) {
+ assert(!ActiveTemplateInstantiations.empty() &&
+ "Cannot perform an instantiation without some context on the "
+ "instantiation stack");
+
+ // If T is not a dependent type, there is nothing to do.
+ if (!T->isDependentType())
+ return T;
+
+ TemplateTypeInstantiator Instantiator(*this, TemplateArgs, Loc, Entity);
+ return Instantiator(T);
+}
+
+/// \brief Instantiate the base class specifiers of the given class
+/// template specialization.
+///
+/// Produces a diagnostic and returns true on error, returns false and
+/// attaches the instantiated base classes to the class template
+/// specialization if successful.
+bool
+Sema::InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation,
+ CXXRecordDecl *Pattern,
+ const TemplateArgumentList &TemplateArgs) {
+ bool Invalid = false;
+ llvm::SmallVector<CXXBaseSpecifier*, 4> InstantiatedBases;
+ for (ClassTemplateSpecializationDecl::base_class_iterator
+ Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end();
+ Base != BaseEnd; ++Base) {
+ if (!Base->getType()->isDependentType()) {
+ // FIXME: Allocate via ASTContext
+ InstantiatedBases.push_back(new CXXBaseSpecifier(*Base));
+ continue;
+ }
+
+ QualType BaseType = InstantiateType(Base->getType(),
+ TemplateArgs,
+ Base->getSourceRange().getBegin(),
+ DeclarationName());
+ if (BaseType.isNull()) {
+ Invalid = true;
+ continue;
+ }
+
+ if (CXXBaseSpecifier *InstantiatedBase
+ = CheckBaseSpecifier(Instantiation,
+ Base->getSourceRange(),
+ Base->isVirtual(),
+ Base->getAccessSpecifierAsWritten(),
+ BaseType,
+ /*FIXME: Not totally accurate */
+ Base->getSourceRange().getBegin()))
+ InstantiatedBases.push_back(InstantiatedBase);
+ else
+ Invalid = true;
+ }
+
+ if (!Invalid &&
+ AttachBaseSpecifiers(Instantiation, InstantiatedBases.data(),
+ InstantiatedBases.size()))
+ Invalid = true;
+
+ return Invalid;
+}
+
+/// \brief Instantiate the definition of a class from a given pattern.
+///
+/// \param PointOfInstantiation The point of instantiation within the
+/// source code.
+///
+/// \param Instantiation is the declaration whose definition is being
+/// instantiated. This will be either a class template specialization
+/// or a member class of a class template specialization.
+///
+/// \param Pattern is the pattern from which the instantiation
+/// occurs. This will be either the declaration of a class template or
+/// the declaration of a member class of a class template.
+///
+/// \param TemplateArgs The template arguments to be substituted into
+/// the pattern.
+///
+/// \returns true if an error occurred, false otherwise.
+bool
+Sema::InstantiateClass(SourceLocation PointOfInstantiation,
+ CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
+ const TemplateArgumentList &TemplateArgs,
+ bool ExplicitInstantiation) {
+ bool Invalid = false;
+
+ CXXRecordDecl *PatternDef
+ = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
+ if (!PatternDef) {
+ if (Pattern == Instantiation->getInstantiatedFromMemberClass()) {
+ Diag(PointOfInstantiation,
+ diag::err_implicit_instantiate_member_undefined)
+ << Context.getTypeDeclType(Instantiation);
+ Diag(Pattern->getLocation(), diag::note_member_of_template_here);
+ } else {
+ Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
+ << ExplicitInstantiation
+ << Context.getTypeDeclType(Instantiation);
+ Diag(Pattern->getLocation(), diag::note_template_decl_here);
+ }
+ return true;
+ }
+ Pattern = PatternDef;
+
+ InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation);
+ if (Inst)
+ return true;
+
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ DeclContext *PreviousContext = CurContext;
+ CurContext = Instantiation;
+
+ // Start the definition of this instantiation.
+ Instantiation->startDefinition();
+
+ // Instantiate the base class specifiers.
+ if (InstantiateBaseSpecifiers(Instantiation, Pattern, TemplateArgs))
+ Invalid = true;
+
+ llvm::SmallVector<DeclPtrTy, 4> Fields;
+ for (RecordDecl::decl_iterator Member = Pattern->decls_begin(Context),
+ MemberEnd = Pattern->decls_end(Context);
+ Member != MemberEnd; ++Member) {
+ Decl *NewMember = InstantiateDecl(*Member, Instantiation, TemplateArgs);
+ if (NewMember) {
+ if (NewMember->isInvalidDecl())
+ Invalid = true;
+ else if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
+ Fields.push_back(DeclPtrTy::make(Field));
+ } else {
+ // FIXME: Eventually, a NULL return will mean that one of the
+ // instantiations was a semantic disaster, and we'll want to set Invalid =
+ // true. For now, we expect to skip some members that we can't yet handle.
+ }
+ }
+
+ // Finish checking fields.
+ ActOnFields(0, Instantiation->getLocation(), DeclPtrTy::make(Instantiation),
+ Fields.data(), Fields.size(), SourceLocation(), SourceLocation(),
+ 0);
+
+ // Add any implicitly-declared members that we might need.
+ AddImplicitlyDeclaredMembersToClass(Instantiation);
+
+ // Exit the scope of this instantiation.
+ CurContext = PreviousContext;
+
+ if (!Invalid)
+ Consumer.HandleTagDeclDefinition(Instantiation);
+
+ // If this is an explicit instantiation, instantiate our members, too.
+ if (!Invalid && ExplicitInstantiation) {
+ Inst.Clear();
+ InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs);
+ }
+
+ return Invalid;
+}
+
+bool
+Sema::InstantiateClassTemplateSpecialization(
+ ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ bool ExplicitInstantiation) {
+ // Perform the actual instantiation on the canonical declaration.
+ ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
+ Context.getCanonicalDecl(ClassTemplateSpec));
+
+ // We can only instantiate something that hasn't already been
+ // instantiated or specialized. Fail without any diagnostics: our
+ // caller will provide an error message.
+ if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared)
+ return true;
+
+ ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
+ CXXRecordDecl *Pattern = Template->getTemplatedDecl();
+ const TemplateArgumentList *TemplateArgs
+ = &ClassTemplateSpec->getTemplateArgs();
+
+ // Determine whether any class template partial specializations
+ // match the given template arguments.
+ llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> Matched;
+ for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+ Partial = Template->getPartialSpecializations().begin(),
+ PartialEnd = Template->getPartialSpecializations().end();
+ Partial != PartialEnd;
+ ++Partial) {
+ if (DeduceTemplateArguments(&*Partial, ClassTemplateSpec->getTemplateArgs()))
+ Matched.push_back(&*Partial);
+ }
+
+ if (Matched.size() == 1) {
+ Pattern = Matched[0];
+ // FIXME: set TemplateArgs to the template arguments of the
+ // partial specialization, instantiated with the deduced template
+ // arguments.
+ } else if (Matched.size() > 1) {
+ // FIXME: Implement partial ordering of class template partial
+ // specializations.
+ Diag(ClassTemplateSpec->getLocation(),
+ diag::unsup_template_partial_spec_ordering);
+ }
+
+ // Note that this is an instantiation.
+ ClassTemplateSpec->setSpecializationKind(
+ ExplicitInstantiation? TSK_ExplicitInstantiation
+ : TSK_ImplicitInstantiation);
+
+ return InstantiateClass(ClassTemplateSpec->getLocation(),
+ ClassTemplateSpec, Pattern, *TemplateArgs,
+ ExplicitInstantiation);
+}
+
+/// \brief Instantiate the definitions of all of the member of the
+/// given class, which is an instantiation of a class template or a
+/// member class of a template.
+void
+Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
+ CXXRecordDecl *Instantiation,
+ const TemplateArgumentList &TemplateArgs) {
+ for (DeclContext::decl_iterator D = Instantiation->decls_begin(Context),
+ DEnd = Instantiation->decls_end(Context);
+ D != DEnd; ++D) {
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) {
+ if (!Function->getBody(Context))
+ InstantiateFunctionDefinition(PointOfInstantiation, Function);
+ } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
+ const VarDecl *Def = 0;
+ if (!Var->getDefinition(Def))
+ InstantiateVariableDefinition(Var);
+ } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
+ if (!Record->isInjectedClassName() && !Record->getDefinition(Context)) {
+ assert(Record->getInstantiatedFromMemberClass() &&
+ "Missing instantiated-from-template information");
+ InstantiateClass(PointOfInstantiation, Record,
+ Record->getInstantiatedFromMemberClass(),
+ TemplateArgs, true);
+ }
+ }
+ }
+}
+
+/// \brief Instantiate the definitions of all of the members of the
+/// given class template specialization, which was named as part of an
+/// explicit instantiation.
+void Sema::InstantiateClassTemplateSpecializationMembers(
+ SourceLocation PointOfInstantiation,
+ ClassTemplateSpecializationDecl *ClassTemplateSpec) {
+ // C++0x [temp.explicit]p7:
+ // An explicit instantiation that names a class template
+ // specialization is an explicit instantion of the same kind
+ // (declaration or definition) of each of its members (not
+ // including members inherited from base classes) that has not
+ // been previously explicitly specialized in the translation unit
+ // containing the explicit instantiation, except as described
+ // below.
+ InstantiateClassMembers(PointOfInstantiation, ClassTemplateSpec,
+ ClassTemplateSpec->getTemplateArgs());
+}
+
+/// \brief Instantiate a nested-name-specifier.
+NestedNameSpecifier *
+Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,
+ SourceRange Range,
+ const TemplateArgumentList &TemplateArgs) {
+ // Instantiate the prefix of this nested name specifier.
+ NestedNameSpecifier *Prefix = NNS->getPrefix();
+ if (Prefix) {
+ Prefix = InstantiateNestedNameSpecifier(Prefix, Range, TemplateArgs);
+ if (!Prefix)
+ return 0;
+ }
+
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier: {
+ assert(Prefix &&
+ "Can't have an identifier nested-name-specifier with no prefix");
+ CXXScopeSpec SS;
+ // FIXME: The source location information is all wrong.
+ SS.setRange(Range);
+ SS.setScopeRep(Prefix);
+ return static_cast<NestedNameSpecifier *>(
+ ActOnCXXNestedNameSpecifier(0, SS,
+ Range.getEnd(),
+ Range.getEnd(),
+ *NNS->getAsIdentifier()));
+ break;
+ }
+
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::Global:
+ return NNS;
+
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ case NestedNameSpecifier::TypeSpec: {
+ QualType T = QualType(NNS->getAsType(), 0);
+ if (!T->isDependentType())
+ return NNS;
+
+ T = InstantiateType(T, TemplateArgs, Range.getBegin(), DeclarationName());
+ if (T.isNull())
+ return 0;
+
+ if (T->isRecordType() ||
+ (getLangOptions().CPlusPlus0x && T->isEnumeralType())) {
+ assert(T.getCVRQualifiers() == 0 && "Can't get cv-qualifiers here");
+ return NestedNameSpecifier::Create(Context, Prefix,
+ NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate,
+ T.getTypePtr());
+ }
+
+ Diag(Range.getBegin(), diag::err_nested_name_spec_non_tag) << T;
+ return 0;
+ }
+ }
+
+ // Required to silence a GCC warning
+ return 0;
+}
+
+TemplateName
+Sema::InstantiateTemplateName(TemplateName Name, SourceLocation Loc,
+ const TemplateArgumentList &TemplateArgs) {
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast_or_null<TemplateTemplateParmDecl>(
+ Name.getAsTemplateDecl())) {
+ assert(TTP->getDepth() == 0 &&
+ "Cannot reduce depth of a template template parameter");
+ assert(TemplateArgs[TTP->getPosition()].getAsDecl() &&
+ "Wrong kind of template template argument");
+ ClassTemplateDecl *ClassTemplate
+ = dyn_cast<ClassTemplateDecl>(
+ TemplateArgs[TTP->getPosition()].getAsDecl());
+ assert(ClassTemplate && "Expected a class template");
+ if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
+ NestedNameSpecifier *NNS
+ = InstantiateNestedNameSpecifier(QTN->getQualifier(),
+ /*FIXME=*/SourceRange(Loc),
+ TemplateArgs);
+ if (NNS)
+ return Context.getQualifiedTemplateName(NNS,
+ QTN->hasTemplateKeyword(),
+ ClassTemplate);
+ }
+
+ return TemplateName(ClassTemplate);
+ } else if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
+ NestedNameSpecifier *NNS
+ = InstantiateNestedNameSpecifier(DTN->getQualifier(),
+ /*FIXME=*/SourceRange(Loc),
+ TemplateArgs);
+
+ if (!NNS) // FIXME: Not the best recovery strategy.
+ return Name;
+
+ if (NNS->isDependent())
+ return Context.getDependentTemplateName(NNS, DTN->getName());
+
+ // Somewhat redundant with ActOnDependentTemplateName.
+ CXXScopeSpec SS;
+ SS.setRange(SourceRange(Loc));
+ SS.setScopeRep(NNS);
+ TemplateTy Template;
+ TemplateNameKind TNK = isTemplateName(*DTN->getName(), 0, Template, &SS);
+ if (TNK == TNK_Non_template) {
+ Diag(Loc, diag::err_template_kw_refers_to_non_template)
+ << DTN->getName();
+ return Name;
+ } else if (TNK == TNK_Function_template) {
+ Diag(Loc, diag::err_template_kw_refers_to_non_template)
+ << DTN->getName();
+ return Name;
+ }
+
+ return Template.getAsVal<TemplateName>();
+ }
+
+
+
+ // FIXME: Even if we're referring to a Decl that isn't a template template
+ // parameter, we may need to instantiate the outer contexts of that
+ // Decl. However, this won't be needed until we implement member templates.
+ return Name;
+}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
new file mode 100644
index 000000000000..6d7dc2e6d531
--- /dev/null
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -0,0 +1,767 @@
+//===--- SemaTemplateInstantiateDecl.cpp - C++ Template Decl Instantiation ===/
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===/
+//
+// This file implements C++ template instantiation for declarations.
+//
+//===----------------------------------------------------------------------===/
+#include "Sema.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/Expr.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace clang;
+
+namespace {
+ class VISIBILITY_HIDDEN TemplateDeclInstantiator
+ : public DeclVisitor<TemplateDeclInstantiator, Decl *> {
+ Sema &SemaRef;
+ DeclContext *Owner;
+ const TemplateArgumentList &TemplateArgs;
+
+ public:
+ typedef Sema::OwningExprResult OwningExprResult;
+
+ TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
+ const TemplateArgumentList &TemplateArgs)
+ : SemaRef(SemaRef), Owner(Owner), TemplateArgs(TemplateArgs) { }
+
+ // FIXME: Once we get closer to completion, replace these manually-written
+ // declarations with automatically-generated ones from
+ // clang/AST/DeclNodes.def.
+ Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
+ Decl *VisitNamespaceDecl(NamespaceDecl *D);
+ Decl *VisitTypedefDecl(TypedefDecl *D);
+ Decl *VisitVarDecl(VarDecl *D);
+ Decl *VisitFieldDecl(FieldDecl *D);
+ Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
+ Decl *VisitEnumDecl(EnumDecl *D);
+ Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
+ Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
+ Decl *VisitCXXMethodDecl(CXXMethodDecl *D);
+ Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
+ Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
+ Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
+ ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D);
+ Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
+
+ // Base case. FIXME: Remove once we can instantiate everything.
+ Decl *VisitDecl(Decl *) {
+ assert(false && "Template instantiation of unknown declaration kind!");
+ return 0;
+ }
+
+ // Helper functions for instantiating methods.
+ QualType InstantiateFunctionType(FunctionDecl *D,
+ llvm::SmallVectorImpl<ParmVarDecl *> &Params);
+ bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
+ };
+}
+
+Decl *
+TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
+ assert(false && "Translation units cannot be instantiated");
+ return D;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) {
+ assert(false && "Namespaces cannot be instantiated");
+ return D;
+}
+
+Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
+ bool Invalid = false;
+ QualType T = D->getUnderlyingType();
+ if (T->isDependentType()) {
+ T = SemaRef.InstantiateType(T, TemplateArgs,
+ D->getLocation(), D->getDeclName());
+ if (T.isNull()) {
+ Invalid = true;
+ T = SemaRef.Context.IntTy;
+ }
+ }
+
+ // Create the new typedef
+ TypedefDecl *Typedef
+ = TypedefDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ D->getIdentifier(), T);
+ if (Invalid)
+ Typedef->setInvalidDecl();
+
+ Owner->addDecl(SemaRef.Context, Typedef);
+
+ return Typedef;
+}
+
+Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
+ // Instantiate the type of the declaration
+ QualType T = SemaRef.InstantiateType(D->getType(), TemplateArgs,
+ D->getTypeSpecStartLoc(),
+ D->getDeclName());
+ if (T.isNull())
+ return 0;
+
+ // Build the instantiated declaration
+ VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner,
+ D->getLocation(), D->getIdentifier(),
+ T, D->getStorageClass(),
+ D->getTypeSpecStartLoc());
+ Var->setThreadSpecified(D->isThreadSpecified());
+ Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
+ Var->setDeclaredInCondition(D->isDeclaredInCondition());
+
+ // FIXME: In theory, we could have a previous declaration for variables that
+ // are not static data members.
+ bool Redeclaration = false;
+ SemaRef.CheckVariableDeclaration(Var, 0, Redeclaration);
+ Owner->addDecl(SemaRef.Context, Var);
+
+ if (D->getInit()) {
+ OwningExprResult Init
+ = SemaRef.InstantiateExpr(D->getInit(), TemplateArgs);
+ if (Init.isInvalid())
+ Var->setInvalidDecl();
+ else
+ SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init),
+ D->hasCXXDirectInitializer());
+ } else {
+ // FIXME: Call ActOnUninitializedDecl? (Not always)
+ }
+
+ return Var;
+}
+
+Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
+ bool Invalid = false;
+ QualType T = D->getType();
+ if (T->isDependentType()) {
+ T = SemaRef.InstantiateType(T, TemplateArgs,
+ D->getLocation(), D->getDeclName());
+ if (!T.isNull() && T->isFunctionType()) {
+ // C++ [temp.arg.type]p3:
+ // If a declaration acquires a function type through a type
+ // dependent on a template-parameter and this causes a
+ // declaration that does not use the syntactic form of a
+ // function declarator to have function type, the program is
+ // ill-formed.
+ SemaRef.Diag(D->getLocation(), diag::err_field_instantiates_to_function)
+ << T;
+ T = QualType();
+ Invalid = true;
+ }
+ }
+
+ Expr *BitWidth = D->getBitWidth();
+ if (Invalid)
+ BitWidth = 0;
+ else if (BitWidth) {
+ OwningExprResult InstantiatedBitWidth
+ = SemaRef.InstantiateExpr(BitWidth, TemplateArgs);
+ if (InstantiatedBitWidth.isInvalid()) {
+ Invalid = true;
+ BitWidth = 0;
+ } else
+ BitWidth = InstantiatedBitWidth.takeAs<Expr>();
+ }
+
+ FieldDecl *Field = SemaRef.CheckFieldDecl(D->getDeclName(), T,
+ cast<RecordDecl>(Owner),
+ D->getLocation(),
+ D->isMutable(),
+ BitWidth,
+ D->getAccess(),
+ 0);
+ if (Field) {
+ if (Invalid)
+ Field->setInvalidDecl();
+
+ Owner->addDecl(SemaRef.Context, Field);
+ }
+
+ return Field;
+}
+
+Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
+ Expr *AssertExpr = D->getAssertExpr();
+
+ OwningExprResult InstantiatedAssertExpr
+ = SemaRef.InstantiateExpr(AssertExpr, TemplateArgs);
+ if (InstantiatedAssertExpr.isInvalid())
+ return 0;
+
+ OwningExprResult Message = SemaRef.Clone(D->getMessage());
+ Decl *StaticAssert
+ = SemaRef.ActOnStaticAssertDeclaration(D->getLocation(),
+ move(InstantiatedAssertExpr),
+ move(Message)).getAs<Decl>();
+ return StaticAssert;
+}
+
+Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
+ EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner,
+ D->getLocation(), D->getIdentifier(),
+ /*PrevDecl=*/0);
+ Enum->setInstantiationOfMemberEnum(D);
+ Enum->setAccess(D->getAccess());
+ Owner->addDecl(SemaRef.Context, Enum);
+ Enum->startDefinition();
+
+ llvm::SmallVector<Sema::DeclPtrTy, 4> Enumerators;
+
+ EnumConstantDecl *LastEnumConst = 0;
+ for (EnumDecl::enumerator_iterator EC = D->enumerator_begin(SemaRef.Context),
+ ECEnd = D->enumerator_end(SemaRef.Context);
+ EC != ECEnd; ++EC) {
+ // The specified value for the enumerator.
+ OwningExprResult Value = SemaRef.Owned((Expr *)0);
+ if (Expr *UninstValue = EC->getInitExpr())
+ Value = SemaRef.InstantiateExpr(UninstValue, TemplateArgs);
+
+ // Drop the initial value and continue.
+ bool isInvalid = false;
+ if (Value.isInvalid()) {
+ Value = SemaRef.Owned((Expr *)0);
+ isInvalid = true;
+ }
+
+ EnumConstantDecl *EnumConst
+ = SemaRef.CheckEnumConstant(Enum, LastEnumConst,
+ EC->getLocation(), EC->getIdentifier(),
+ move(Value));
+
+ if (isInvalid) {
+ if (EnumConst)
+ EnumConst->setInvalidDecl();
+ Enum->setInvalidDecl();
+ }
+
+ if (EnumConst) {
+ Enum->addDecl(SemaRef.Context, EnumConst);
+ Enumerators.push_back(Sema::DeclPtrTy::make(EnumConst));
+ LastEnumConst = EnumConst;
+ }
+ }
+
+ // FIXME: Fixup LBraceLoc and RBraceLoc
+ SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), SourceLocation(),
+ Sema::DeclPtrTy::make(Enum),
+ &Enumerators[0], Enumerators.size());
+
+ return Enum;
+}
+
+Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
+ assert(false && "EnumConstantDecls can only occur within EnumDecls.");
+ return 0;
+}
+
+Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
+ CXXRecordDecl *PrevDecl = 0;
+ if (D->isInjectedClassName())
+ PrevDecl = cast<CXXRecordDecl>(Owner);
+
+ CXXRecordDecl *Record
+ = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner,
+ D->getLocation(), D->getIdentifier(), PrevDecl);
+ Record->setImplicit(D->isImplicit());
+ Record->setAccess(D->getAccess());
+ if (!D->isInjectedClassName())
+ Record->setInstantiationOfMemberClass(D);
+
+ Owner->addDecl(SemaRef.Context, Record);
+ return Record;
+}
+
+Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
+ // Only handle actual methods; we'll deal with constructors,
+ // destructors, etc. separately.
+ if (D->getKind() != Decl::CXXMethod)
+ return 0;
+
+ Sema::LocalInstantiationScope Scope(SemaRef);
+
+ llvm::SmallVector<ParmVarDecl *, 4> Params;
+ QualType T = InstantiateFunctionType(D, Params);
+ if (T.isNull())
+ return 0;
+
+ // Build the instantiated method declaration.
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
+ CXXMethodDecl *Method
+ = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
+ D->getDeclName(), T, D->isStatic(),
+ D->isInline());
+ Method->setInstantiationOfMemberFunction(D);
+
+ // Attach the parameters
+ for (unsigned P = 0; P < Params.size(); ++P)
+ Params[P]->setOwningFunction(Method);
+ Method->setParams(SemaRef.Context, Params.data(), Params.size());
+
+ if (InitMethodInstantiation(Method, D))
+ Method->setInvalidDecl();
+
+ NamedDecl *PrevDecl
+ = SemaRef.LookupQualifiedName(Owner, Method->getDeclName(),
+ Sema::LookupOrdinaryName, true);
+ // 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
+ // typedef (C++ [dcl.typedef]p4).
+ if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
+ PrevDecl = 0;
+ bool Redeclaration = false;
+ bool OverloadableAttrRequired = false;
+ SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
+ /*FIXME:*/OverloadableAttrRequired);
+
+ if (!Method->isInvalidDecl() || !PrevDecl)
+ Owner->addDecl(SemaRef.Context, Method);
+ return Method;
+}
+
+Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
+ Sema::LocalInstantiationScope Scope(SemaRef);
+
+ llvm::SmallVector<ParmVarDecl *, 4> Params;
+ QualType T = InstantiateFunctionType(D, Params);
+ if (T.isNull())
+ return 0;
+
+ // Build the instantiated method declaration.
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
+ QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
+ DeclarationName Name
+ = SemaRef.Context.DeclarationNames.getCXXConstructorName(
+ SemaRef.Context.getCanonicalType(ClassTy));
+ CXXConstructorDecl *Constructor
+ = CXXConstructorDecl::Create(SemaRef.Context, Record, D->getLocation(),
+ Name, T, D->isExplicit(), D->isInline(),
+ false);
+ Constructor->setInstantiationOfMemberFunction(D);
+
+ // Attach the parameters
+ for (unsigned P = 0; P < Params.size(); ++P)
+ Params[P]->setOwningFunction(Constructor);
+ Constructor->setParams(SemaRef.Context, Params.data(), Params.size());
+
+ if (InitMethodInstantiation(Constructor, D))
+ Constructor->setInvalidDecl();
+
+ NamedDecl *PrevDecl
+ = SemaRef.LookupQualifiedName(Owner, Name, Sema::LookupOrdinaryName, true);
+
+ // 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
+ // typedef (C++ [dcl.typedef]p4).
+ if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
+ PrevDecl = 0;
+ bool Redeclaration = false;
+ bool OverloadableAttrRequired = false;
+ SemaRef.CheckFunctionDeclaration(Constructor, PrevDecl, Redeclaration,
+ /*FIXME:*/OverloadableAttrRequired);
+
+ Record->addedConstructor(SemaRef.Context, Constructor);
+ Owner->addDecl(SemaRef.Context, Constructor);
+ return Constructor;
+}
+
+Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
+ Sema::LocalInstantiationScope Scope(SemaRef);
+
+ llvm::SmallVector<ParmVarDecl *, 4> Params;
+ QualType T = InstantiateFunctionType(D, Params);
+ if (T.isNull())
+ return 0;
+ assert(Params.size() == 0 && "Destructor with parameters?");
+
+ // Build the instantiated destructor declaration.
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
+ QualType ClassTy =
+ SemaRef.Context.getCanonicalType(SemaRef.Context.getTypeDeclType(Record));
+ CXXDestructorDecl *Destructor
+ = CXXDestructorDecl::Create(SemaRef.Context, Record,
+ D->getLocation(),
+ SemaRef.Context.DeclarationNames.getCXXDestructorName(ClassTy),
+ T, D->isInline(), false);
+ Destructor->setInstantiationOfMemberFunction(D);
+ if (InitMethodInstantiation(Destructor, D))
+ Destructor->setInvalidDecl();
+
+ bool Redeclaration = false;
+ bool OverloadableAttrRequired = false;
+ NamedDecl *PrevDecl = 0;
+ SemaRef.CheckFunctionDeclaration(Destructor, PrevDecl, Redeclaration,
+ /*FIXME:*/OverloadableAttrRequired);
+ Owner->addDecl(SemaRef.Context, Destructor);
+ return Destructor;
+}
+
+Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
+ Sema::LocalInstantiationScope Scope(SemaRef);
+
+ llvm::SmallVector<ParmVarDecl *, 4> Params;
+ QualType T = InstantiateFunctionType(D, Params);
+ if (T.isNull())
+ return 0;
+ assert(Params.size() == 0 && "Destructor with parameters?");
+
+ // Build the instantiated conversion declaration.
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
+ QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
+ QualType ConvTy
+ = SemaRef.Context.getCanonicalType(T->getAsFunctionType()->getResultType());
+ CXXConversionDecl *Conversion
+ = CXXConversionDecl::Create(SemaRef.Context, Record,
+ D->getLocation(),
+ SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(ConvTy),
+ T, D->isInline(), D->isExplicit());
+ Conversion->setInstantiationOfMemberFunction(D);
+ if (InitMethodInstantiation(Conversion, D))
+ Conversion->setInvalidDecl();
+
+ bool Redeclaration = false;
+ bool OverloadableAttrRequired = false;
+ NamedDecl *PrevDecl = 0;
+ SemaRef.CheckFunctionDeclaration(Conversion, PrevDecl, Redeclaration,
+ /*FIXME:*/OverloadableAttrRequired);
+ Owner->addDecl(SemaRef.Context, Conversion);
+ return Conversion;
+}
+
+ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
+ QualType OrigT = SemaRef.InstantiateType(D->getOriginalType(), TemplateArgs,
+ D->getLocation(), D->getDeclName());
+ if (OrigT.isNull())
+ return 0;
+
+ QualType T = SemaRef.adjustParameterType(OrigT);
+
+ if (D->getDefaultArg()) {
+ // FIXME: Leave a marker for "uninstantiated" default
+ // arguments. They only get instantiated on demand at the call
+ // site.
+ unsigned DiagID = SemaRef.Diags.getCustomDiagID(Diagnostic::Warning,
+ "sorry, dropping default argument during template instantiation");
+ SemaRef.Diag(D->getDefaultArg()->getSourceRange().getBegin(), DiagID)
+ << D->getDefaultArg()->getSourceRange();
+ }
+
+ // Allocate the parameter
+ ParmVarDecl *Param = 0;
+ if (T == OrigT)
+ Param = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ D->getIdentifier(), T, D->getStorageClass(),
+ 0);
+ else
+ Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner,
+ D->getLocation(), D->getIdentifier(),
+ T, OrigT, D->getStorageClass(), 0);
+
+ // Note: we don't try to instantiate function parameters until after
+ // we've instantiated the function's type. Therefore, we don't have
+ // to check for 'void' parameter types here.
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param);
+ return Param;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) {
+ // Since parameter types can decay either before or after
+ // instantiation, we simply treat OriginalParmVarDecls as
+ // ParmVarDecls the same way, and create one or the other depending
+ // on what happens after template instantiation.
+ return VisitParmVarDecl(D);
+}
+
+Decl *Sema::InstantiateDecl(Decl *D, DeclContext *Owner,
+ const TemplateArgumentList &TemplateArgs) {
+ TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
+ return Instantiator.Visit(D);
+}
+
+/// \brief Instantiates the type of the given function, including
+/// instantiating all of the function parameters.
+///
+/// \param D The function that we will be instantiated
+///
+/// \param Params the instantiated parameter declarations
+
+/// \returns the instantiated function's type if successfull, a NULL
+/// type if there was an error.
+QualType
+TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
+ llvm::SmallVectorImpl<ParmVarDecl *> &Params) {
+ bool InvalidDecl = false;
+
+ // Instantiate the function parameters
+ TemplateDeclInstantiator ParamInstantiator(SemaRef, 0, TemplateArgs);
+ llvm::SmallVector<QualType, 4> ParamTys;
+ for (FunctionDecl::param_iterator P = D->param_begin(),
+ PEnd = D->param_end();
+ P != PEnd; ++P) {
+ if (ParmVarDecl *PInst = ParamInstantiator.VisitParmVarDecl(*P)) {
+ if (PInst->getType()->isVoidType()) {
+ SemaRef.Diag(PInst->getLocation(), diag::err_param_with_void_type);
+ PInst->setInvalidDecl();
+ }
+ else if (SemaRef.RequireNonAbstractType(PInst->getLocation(),
+ PInst->getType(),
+ diag::err_abstract_type_in_decl,
+ Sema::AbstractParamType))
+ PInst->setInvalidDecl();
+
+ Params.push_back(PInst);
+ ParamTys.push_back(PInst->getType());
+
+ if (PInst->isInvalidDecl())
+ InvalidDecl = true;
+ } else
+ InvalidDecl = true;
+ }
+
+ // FIXME: Deallocate dead declarations.
+ if (InvalidDecl)
+ return QualType();
+
+ const FunctionProtoType *Proto = D->getType()->getAsFunctionProtoType();
+ assert(Proto && "Missing prototype?");
+ QualType ResultType
+ = SemaRef.InstantiateType(Proto->getResultType(), TemplateArgs,
+ D->getLocation(), D->getDeclName());
+ if (ResultType.isNull())
+ return QualType();
+
+ return SemaRef.BuildFunctionType(ResultType, ParamTys.data(), ParamTys.size(),
+ Proto->isVariadic(), Proto->getTypeQuals(),
+ D->getLocation(), D->getDeclName());
+}
+
+/// \brief Initializes common fields of an instantiated method
+/// declaration (New) from the corresponding fields of its template
+/// (Tmpl).
+///
+/// \returns true if there was an error
+bool
+TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
+ CXXMethodDecl *Tmpl) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
+ New->setAccess(Tmpl->getAccess());
+ if (Tmpl->isVirtualAsWritten()) {
+ New->setVirtualAsWritten(true);
+ Record->setAggregate(false);
+ Record->setPOD(false);
+ Record->setPolymorphic(true);
+ }
+ if (Tmpl->isDeleted())
+ New->setDeleted();
+ if (Tmpl->isPure()) {
+ New->setPure();
+ Record->setAbstract(true);
+ }
+
+ // FIXME: attributes
+ // FIXME: New needs a pointer to Tmpl
+ return false;
+}
+
+/// \brief Instantiate the definition of the given function from its
+/// template.
+///
+/// \param Function the already-instantiated declaration of a
+/// function.
+void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
+ FunctionDecl *Function) {
+ // FIXME: make this work for function template specializations, too.
+
+ if (Function->isInvalidDecl())
+ return;
+
+ // Find the function body that we'll be substituting.
+ const FunctionDecl *PatternDecl
+ = Function->getInstantiatedFromMemberFunction();
+ Stmt *Pattern = 0;
+ if (PatternDecl)
+ Pattern = PatternDecl->getBody(Context, PatternDecl);
+
+ if (!Pattern)
+ return;
+
+ InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
+ if (Inst)
+ return;
+
+ ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function));
+
+ // Introduce a new scope where local variable instantiations will be
+ // recorded.
+ LocalInstantiationScope Scope(*this);
+
+ // Introduce the instantiated function parameters into the local
+ // instantiation scope.
+ for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I)
+ Scope.InstantiatedLocal(PatternDecl->getParamDecl(I),
+ Function->getParamDecl(I));
+
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ DeclContext *PreviousContext = CurContext;
+ CurContext = Function;
+
+ // Instantiate the function body.
+ OwningStmtResult Body
+ = InstantiateStmt(Pattern, getTemplateInstantiationArgs(Function));
+
+ ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body),
+ /*IsInstantiation=*/true);
+
+ CurContext = PreviousContext;
+
+ DeclGroupRef DG(Function);
+ Consumer.HandleTopLevelDecl(DG);
+}
+
+/// \brief Instantiate the definition of the given variable from its
+/// template.
+///
+/// \param Var the already-instantiated declaration of a variable.
+void Sema::InstantiateVariableDefinition(VarDecl *Var) {
+ // FIXME: Implement this!
+}
+
+static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
+ if (D->getKind() != Other->getKind())
+ return false;
+
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Other))
+ return Ctx.getCanonicalDecl(Record->getInstantiatedFromMemberClass())
+ == Ctx.getCanonicalDecl(D);
+
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Other))
+ return Ctx.getCanonicalDecl(Function->getInstantiatedFromMemberFunction())
+ == Ctx.getCanonicalDecl(D);
+
+ if (EnumDecl *Enum = dyn_cast<EnumDecl>(Other))
+ return Ctx.getCanonicalDecl(Enum->getInstantiatedFromMemberEnum())
+ == Ctx.getCanonicalDecl(D);
+
+ // FIXME: How can we find instantiations of anonymous unions?
+
+ return D->getDeclName() && isa<NamedDecl>(Other) &&
+ D->getDeclName() == cast<NamedDecl>(Other)->getDeclName();
+}
+
+template<typename ForwardIterator>
+static NamedDecl *findInstantiationOf(ASTContext &Ctx,
+ NamedDecl *D,
+ ForwardIterator first,
+ ForwardIterator last) {
+ for (; first != last; ++first)
+ if (isInstantiationOf(Ctx, D, *first))
+ return cast<NamedDecl>(*first);
+
+ return 0;
+}
+
+/// \brief Find the instantiation of the given declaration within the
+/// current instantiation.
+///
+/// This routine is intended to be used when \p D is a declaration
+/// referenced from within a template, that needs to mapped into the
+/// corresponding declaration within an instantiation. For example,
+/// given:
+///
+/// \code
+/// template<typename T>
+/// struct X {
+/// enum Kind {
+/// KnownValue = sizeof(T)
+/// };
+///
+/// bool getKind() const { return KnownValue; }
+/// };
+///
+/// template struct X<int>;
+/// \endcode
+///
+/// In the instantiation of X<int>::getKind(), we need to map the
+/// EnumConstantDecl for KnownValue (which refers to
+/// X<T>::<Kind>::KnownValue) to its instantiation
+/// (X<int>::<Kind>::KnownValue). InstantiateCurrentDeclRef() performs
+/// this mapping from within the instantiation of X<int>.
+NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) {
+ DeclContext *ParentDC = D->getDeclContext();
+ if (isa<ParmVarDecl>(D) || ParentDC->isFunctionOrMethod()) {
+ // D is a local of some kind. Look into the map of local
+ // declarations to their instantiations.
+ return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D));
+ }
+
+ if (NamedDecl *ParentDecl = dyn_cast<NamedDecl>(ParentDC)) {
+ ParentDecl = InstantiateCurrentDeclRef(ParentDecl);
+ if (!ParentDecl)
+ return 0;
+
+ ParentDC = cast<DeclContext>(ParentDecl);
+ }
+
+ if (ParentDC != D->getDeclContext()) {
+ // We performed some kind of instantiation in the parent context,
+ // so now we need to look into the instantiated parent context to
+ // find the instantiation of the declaration D.
+ NamedDecl *Result = 0;
+ if (D->getDeclName()) {
+ DeclContext::lookup_result Found
+ = ParentDC->lookup(Context, D->getDeclName());
+ Result = findInstantiationOf(Context, D, Found.first, Found.second);
+ } else {
+ // Since we don't have a name for the entity we're looking for,
+ // our only option is to walk through all of the declarations to
+ // find that name. This will occur in a few cases:
+ //
+ // - anonymous struct/union within a template
+ // - unnamed class/struct/union/enum within a template
+ //
+ // FIXME: Find a better way to find these instantiations!
+ Result = findInstantiationOf(Context, D,
+ ParentDC->decls_begin(Context),
+ ParentDC->decls_end(Context));
+ }
+ assert(Result && "Unable to find instantiation of declaration!");
+ D = Result;
+ }
+
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D))
+ if (ClassTemplateDecl *ClassTemplate
+ = Record->getDescribedClassTemplate()) {
+ // When the declaration D was parsed, it referred to the current
+ // instantiation. Therefore, look through the current context,
+ // which contains actual instantiations, to find the
+ // instantiation of the "current instantiation" that D refers
+ // to. Alternatively, we could just instantiate the
+ // injected-class-name with the current template arguments, but
+ // such an instantiation is far more expensive.
+ for (DeclContext *DC = CurContext; !DC->isFileContext();
+ DC = DC->getParent()) {
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(DC))
+ if (Context.getCanonicalDecl(Spec->getSpecializedTemplate())
+ == Context.getCanonicalDecl(ClassTemplate))
+ return Spec;
+ }
+
+ assert(false &&
+ "Unable to find declaration for the current instantiation");
+ }
+
+ return D;
+}
diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp
new file mode 100644
index 000000000000..a6b9703cee0b
--- /dev/null
+++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp
@@ -0,0 +1,1278 @@
+//===--- SemaTemplateInstantiateExpr.cpp - C++ Template Expr Instantiation ===/
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===/
+//
+// This file implements C++ template instantiation for expressions.
+//
+//===----------------------------------------------------------------------===/
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Designator.h"
+#include "clang/Lex/Preprocessor.h" // for the identifier table
+#include "llvm/Support/Compiler.h"
+using namespace clang;
+
+namespace {
+ class VISIBILITY_HIDDEN TemplateExprInstantiator
+ : public StmtVisitor<TemplateExprInstantiator, Sema::OwningExprResult> {
+ Sema &SemaRef;
+ const TemplateArgumentList &TemplateArgs;
+
+ public:
+ typedef Sema::OwningExprResult OwningExprResult;
+
+ TemplateExprInstantiator(Sema &SemaRef,
+ const TemplateArgumentList &TemplateArgs)
+ : SemaRef(SemaRef), TemplateArgs(TemplateArgs) { }
+
+ // Declare VisitXXXStmt nodes for all of the expression kinds.
+#define EXPR(Type, Base) OwningExprResult Visit##Type(Type *S);
+#define STMT(Type, Base)
+#include "clang/AST/StmtNodes.def"
+
+ // Base case. We can't get here.
+ Sema::OwningExprResult VisitStmt(Stmt *S) {
+ S->dump();
+ assert(false && "Cannot instantiate this kind of expression");
+ return SemaRef.ExprError();
+ }
+ };
+}
+
+// Base case. We can't get here.
+Sema::OwningExprResult TemplateExprInstantiator::VisitExpr(Expr *E) {
+ E->dump();
+ assert(false && "Cannot instantiate this kind of expression");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitPredefinedExpr(PredefinedExpr *E) {
+ return SemaRef.Clone(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitIntegerLiteral(IntegerLiteral *E) {
+ return SemaRef.Clone(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitFloatingLiteral(FloatingLiteral *E) {
+ return SemaRef.Clone(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitStringLiteral(StringLiteral *E) {
+ return SemaRef.Clone(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCharacterLiteral(CharacterLiteral *E) {
+ return SemaRef.Clone(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitImaginaryLiteral(ImaginaryLiteral *E) {
+ return SemaRef.Clone(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
+ return SemaRef.Clone(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) {
+ return SemaRef.Clone(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitGNUNullExpr(GNUNullExpr *E) {
+ return SemaRef.Clone(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitUnresolvedFunctionNameExpr(
+ UnresolvedFunctionNameExpr *E) {
+ return SemaRef.Clone(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) {
+ NamedDecl *D = E->getDecl();
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
+ assert(NTTP->getDepth() == 0 && "No nested templates yet");
+ const TemplateArgument &Arg = TemplateArgs[NTTP->getPosition()];
+ QualType T = Arg.getIntegralType();
+ if (T->isCharType() || T->isWideCharType())
+ return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral(
+ Arg.getAsIntegral()->getZExtValue(),
+ T->isWideCharType(),
+ T,
+ E->getSourceRange().getBegin()));
+ else if (T->isBooleanType())
+ return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr(
+ Arg.getAsIntegral()->getBoolValue(),
+ T,
+ E->getSourceRange().getBegin()));
+
+ return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral(
+ *Arg.getAsIntegral(),
+ T,
+ E->getSourceRange().getBegin()));
+ }
+
+ if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) {
+ // FIXME: instantiate each decl in the overload set
+ return SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(Ovl,
+ SemaRef.Context.OverloadTy,
+ E->getLocation(),
+ false, false));
+ }
+
+ ValueDecl *NewD
+ = dyn_cast_or_null<ValueDecl>(SemaRef.InstantiateCurrentDeclRef(D));
+ if (!NewD)
+ return SemaRef.ExprError();
+
+ // FIXME: Build QualifiedDeclRefExpr?
+ QualType T = NewD->getType();
+ return SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(NewD,
+ T.getNonReferenceType(),
+ E->getLocation(),
+ T->isDependentType(),
+ T->isDependentType()));
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitParenExpr(ParenExpr *E) {
+ Sema::OwningExprResult SubExpr = Visit(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ return SemaRef.Owned(new (SemaRef.Context) ParenExpr(
+ E->getLParen(), E->getRParen(),
+ (Expr *)SubExpr.release()));
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitUnaryOperator(UnaryOperator *E) {
+ Sema::OwningExprResult Arg = Visit(E->getSubExpr());
+ if (Arg.isInvalid())
+ return SemaRef.ExprError();
+
+ return SemaRef.CreateBuiltinUnaryOp(E->getOperatorLoc(),
+ E->getOpcode(),
+ move(Arg));
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+ Sema::OwningExprResult LHS = Visit(E->getLHS());
+ if (LHS.isInvalid())
+ return SemaRef.ExprError();
+
+ Sema::OwningExprResult RHS = Visit(E->getRHS());
+ if (RHS.isInvalid())
+ return SemaRef.ExprError();
+
+ // Since the overloaded array-subscript operator (operator[]) can
+ // only be a member function, we can make several simplifying
+ // assumptions here:
+ // 1) Normal name lookup (from the current scope) will not ever
+ // find any declarations of operator[] that won't also be found be
+ // member operator lookup, so it is safe to pass a NULL Scope
+ // during the instantiation to avoid the lookup entirely.
+ //
+ // 2) Neither normal name lookup nor argument-dependent lookup at
+ // template definition time will find any operators that won't be
+ // found at template instantiation time, so we do not need to
+ // cache the results of name lookup as we do for the binary
+ // operators.
+ SourceLocation LLocFake = ((Expr*)LHS.get())->getSourceRange().getBegin();
+ return SemaRef.ActOnArraySubscriptExpr(/*Scope=*/0, move(LHS),
+ /*FIXME:*/LLocFake,
+ move(RHS),
+ E->getRBracketLoc());
+}
+
+Sema::OwningExprResult TemplateExprInstantiator::VisitCallExpr(CallExpr *E) {
+ // Instantiate callee
+ OwningExprResult Callee = Visit(E->getCallee());
+ if (Callee.isInvalid())
+ return SemaRef.ExprError();
+
+ // Instantiate arguments
+ ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
+ llvm::SmallVector<SourceLocation, 4> FakeCommaLocs;
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
+ OwningExprResult Arg = Visit(E->getArg(I));
+ if (Arg.isInvalid())
+ return SemaRef.ExprError();
+
+ FakeCommaLocs.push_back(
+ SemaRef.PP.getLocForEndOfToken(E->getArg(I)->getSourceRange().getEnd()));
+ Args.push_back(Arg.takeAs<Expr>());
+ }
+
+ SourceLocation FakeLParenLoc
+ = ((Expr *)Callee.get())->getSourceRange().getBegin();
+ return SemaRef.ActOnCallExpr(/*Scope=*/0, move(Callee),
+ /*FIXME:*/FakeLParenLoc,
+ move_arg(Args),
+ /*FIXME:*/&FakeCommaLocs.front(),
+ E->getRParenLoc());
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitMemberExpr(MemberExpr *E) {
+ // Instantiate the base of the expression.
+ OwningExprResult Base = Visit(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ // FIXME: Handle declaration names here
+ SourceLocation FakeOperatorLoc =
+ SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd());
+ return SemaRef.ActOnMemberReferenceExpr(/*Scope=*/0,
+ move(Base),
+ /*FIXME*/FakeOperatorLoc,
+ E->isArrow()? tok::arrow
+ : tok::period,
+ E->getMemberLoc(),
+ /*FIXME:*/*E->getMemberDecl()->getIdentifier(),
+ /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ SourceLocation FakeTypeLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc());
+ QualType T = SemaRef.InstantiateType(E->getType(), TemplateArgs,
+ FakeTypeLoc,
+ DeclarationName());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ OwningExprResult Init = Visit(E->getInitializer());
+ if (Init.isInvalid())
+ return SemaRef.ExprError();
+
+ return SemaRef.ActOnCompoundLiteral(E->getLParenLoc(),
+ T.getAsOpaquePtr(),
+ /*FIXME*/E->getLParenLoc(),
+ move(Init));
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitBinaryOperator(BinaryOperator *E) {
+ Sema::OwningExprResult LHS = Visit(E->getLHS());
+ if (LHS.isInvalid())
+ return SemaRef.ExprError();
+
+ Sema::OwningExprResult RHS = Visit(E->getRHS());
+ if (RHS.isInvalid())
+ return SemaRef.ExprError();
+
+ Sema::OwningExprResult Result
+ = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(),
+ E->getOpcode(),
+ (Expr *)LHS.get(),
+ (Expr *)RHS.get());
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ LHS.release();
+ RHS.release();
+ return move(Result);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCompoundAssignOperator(
+ CompoundAssignOperator *E) {
+ return VisitBinaryOperator(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ Sema::OwningExprResult First = Visit(E->getArg(0));
+ if (First.isInvalid())
+ return SemaRef.ExprError();
+
+ Expr *Args[2] = { (Expr *)First.get(), 0 };
+
+ Sema::OwningExprResult Second(SemaRef);
+ if (E->getNumArgs() == 2) {
+ Second = Visit(E->getArg(1));
+
+ if (Second.isInvalid())
+ return SemaRef.ExprError();
+
+ Args[1] = (Expr *)Second.get();
+ }
+
+ if (!E->isTypeDependent()) {
+ // Since our original expression was not type-dependent, we do not
+ // perform lookup again at instantiation time (C++ [temp.dep]p1).
+ // Instead, we just build the new overloaded operator call
+ // expression.
+ OwningExprResult Callee = Visit(E->getCallee());
+ if (Callee.isInvalid())
+ return SemaRef.ExprError();
+
+ First.release();
+ Second.release();
+
+ return SemaRef.Owned(new (SemaRef.Context) CXXOperatorCallExpr(
+ SemaRef.Context,
+ E->getOperator(),
+ Callee.takeAs<Expr>(),
+ Args, E->getNumArgs(),
+ E->getType(),
+ E->getOperatorLoc()));
+ }
+
+ bool isPostIncDec = E->getNumArgs() == 2 &&
+ (E->getOperator() == OO_PlusPlus || E->getOperator() == OO_MinusMinus);
+ if (E->getNumArgs() == 1 || isPostIncDec) {
+ if (!Args[0]->getType()->isOverloadableType()) {
+ // The argument is not of overloadable type, so try to create a
+ // built-in unary operation.
+ UnaryOperator::Opcode Opc
+ = UnaryOperator::getOverloadedOpcode(E->getOperator(), isPostIncDec);
+
+ return SemaRef.CreateBuiltinUnaryOp(E->getOperatorLoc(), Opc,
+ move(First));
+ }
+
+ // Fall through to perform overload resolution
+ } else {
+ assert(E->getNumArgs() == 2 && "Expected binary operation");
+
+ Sema::OwningExprResult Result(SemaRef);
+ if (!Args[0]->getType()->isOverloadableType() &&
+ !Args[1]->getType()->isOverloadableType()) {
+ // Neither of the arguments is an overloadable type, so try to
+ // create a built-in binary operation.
+ BinaryOperator::Opcode Opc =
+ BinaryOperator::getOverloadedOpcode(E->getOperator());
+ Result = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(), Opc,
+ Args[0], Args[1]);
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ First.release();
+ Second.release();
+ return move(Result);
+ }
+
+ // Fall through to perform overload resolution.
+ }
+
+ // Compute the set of functions that were found at template
+ // definition time.
+ Sema::FunctionSet Functions;
+ DeclRefExpr *DRE = cast<DeclRefExpr>(E->getCallee());
+ OverloadedFunctionDecl *Overloads
+ = cast<OverloadedFunctionDecl>(DRE->getDecl());
+
+ // FIXME: Do we have to check
+ // IsAcceptableNonMemberOperatorCandidate for each of these?
+ for (OverloadedFunctionDecl::function_iterator
+ F = Overloads->function_begin(),
+ FEnd = Overloads->function_end();
+ F != FEnd; ++F)
+ Functions.insert(*F);
+
+ // Add any functions found via argument-dependent lookup.
+ DeclarationName OpName
+ = SemaRef.Context.DeclarationNames.getCXXOperatorName(E->getOperator());
+ SemaRef.ArgumentDependentLookup(OpName, Args, E->getNumArgs(), Functions);
+
+ // Create the overloaded operator invocation.
+ if (E->getNumArgs() == 1 || isPostIncDec) {
+ UnaryOperator::Opcode Opc
+ = UnaryOperator::getOverloadedOpcode(E->getOperator(), isPostIncDec);
+ return SemaRef.CreateOverloadedUnaryOp(E->getOperatorLoc(), Opc,
+ Functions, move(First));
+ }
+
+ // FIXME: This would be far less ugly if CreateOverloadedBinOp took in ExprArg
+ // arguments!
+ BinaryOperator::Opcode Opc =
+ BinaryOperator::getOverloadedOpcode(E->getOperator());
+ OwningExprResult Result
+ = SemaRef.CreateOverloadedBinOp(E->getOperatorLoc(), Opc,
+ Functions, Args[0], Args[1]);
+
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ First.release();
+ Second.release();
+ return move(Result);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *E) {
+ VarDecl *Var
+ = cast_or_null<VarDecl>(SemaRef.InstantiateDecl(E->getVarDecl(),
+ SemaRef.CurContext,
+ TemplateArgs));
+ if (!Var)
+ return SemaRef.ExprError();
+
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(E->getVarDecl(), Var);
+ return SemaRef.Owned(new (SemaRef.Context) CXXConditionDeclExpr(
+ E->getStartLoc(),
+ SourceLocation(),
+ Var));
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitConditionalOperator(ConditionalOperator *E) {
+ Sema::OwningExprResult Cond = Visit(E->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.ExprError();
+
+ Sema::OwningExprResult LHS = SemaRef.InstantiateExpr(E->getLHS(),
+ TemplateArgs);
+ if (LHS.isInvalid())
+ return SemaRef.ExprError();
+
+ Sema::OwningExprResult RHS = Visit(E->getRHS());
+ if (RHS.isInvalid())
+ return SemaRef.ExprError();
+
+ if (!E->isTypeDependent()) {
+ // Since our original expression was not type-dependent, we do not
+ // perform lookup again at instantiation time (C++ [temp.dep]p1).
+ // Instead, we just build the new conditional operator call expression.
+ return SemaRef.Owned(new (SemaRef.Context) ConditionalOperator(
+ Cond.takeAs<Expr>(),
+ LHS.takeAs<Expr>(),
+ RHS.takeAs<Expr>(),
+ E->getType()));
+ }
+
+
+ return SemaRef.ActOnConditionalOp(/*FIXME*/E->getCond()->getLocEnd(),
+ /*FIXME*/E->getFalseExpr()->getLocStart(),
+ move(Cond), move(LHS), move(RHS));
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitAddrLabelExpr(AddrLabelExpr *E) {
+ return SemaRef.ActOnAddrLabel(E->getAmpAmpLoc(),
+ E->getLabelLoc(),
+ E->getLabel()->getID());
+}
+
+Sema::OwningExprResult TemplateExprInstantiator::VisitStmtExpr(StmtExpr *E) {
+ Sema::OwningStmtResult SubStmt
+ = SemaRef.InstantiateCompoundStmt(E->getSubStmt(), TemplateArgs, true);
+ if (SubStmt.isInvalid())
+ return SemaRef.ExprError();
+
+ return SemaRef.ActOnStmtExpr(E->getLParenLoc(), move(SubStmt),
+ E->getRParenLoc());
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) {
+ assert(false && "__builtin_types_compatible_p is not legal in C++");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
+ ASTOwningVector<&ActionBase::DeleteExpr> SubExprs(SemaRef);
+ for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) {
+ OwningExprResult SubExpr = Visit(E->getExpr(I));
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ SubExprs.push_back(SubExpr.takeAs<Expr>());
+ }
+
+ // Find the declaration for __builtin_shufflevector
+ const IdentifierInfo &Name
+ = SemaRef.Context.Idents.get("__builtin_shufflevector");
+ TranslationUnitDecl *TUDecl = SemaRef.Context.getTranslationUnitDecl();
+ DeclContext::lookup_result Lookup
+ = TUDecl->lookup(SemaRef.Context, DeclarationName(&Name));
+ assert(Lookup.first != Lookup.second && "No __builtin_shufflevector?");
+
+ // Build a reference to the __builtin_shufflevector builtin
+ FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first);
+ Expr *Callee = new (SemaRef.Context) DeclRefExpr(Builtin, Builtin->getType(),
+ E->getBuiltinLoc(),
+ false, false);
+ SemaRef.UsualUnaryConversions(Callee);
+
+ // Build the CallExpr
+ CallExpr *TheCall = new (SemaRef.Context) CallExpr(SemaRef.Context, Callee,
+ SubExprs.takeAs<Expr>(),
+ SubExprs.size(),
+ Builtin->getResultType(),
+ E->getRParenLoc());
+ OwningExprResult OwnedCall(SemaRef.Owned(TheCall));
+
+ // Type-check the __builtin_shufflevector expression.
+ OwningExprResult Result = SemaRef.SemaBuiltinShuffleVector(TheCall);
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ OwnedCall.release();
+ return move(Result);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitChooseExpr(ChooseExpr *E) {
+ OwningExprResult Cond = Visit(E->getCond());
+ if (Cond.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult LHS = SemaRef.InstantiateExpr(E->getLHS(), TemplateArgs);
+ if (LHS.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult RHS = Visit(E->getRHS());
+ if (RHS.isInvalid())
+ return SemaRef.ExprError();
+
+ return SemaRef.ActOnChooseExpr(E->getBuiltinLoc(),
+ move(Cond), move(LHS), move(RHS),
+ E->getRParenLoc());
+}
+
+Sema::OwningExprResult TemplateExprInstantiator::VisitVAArgExpr(VAArgExpr *E) {
+ OwningExprResult SubExpr = Visit(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ SourceLocation FakeTypeLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getSubExpr()->getSourceRange()
+ .getEnd());
+ QualType T = SemaRef.InstantiateType(E->getType(), TemplateArgs,
+ /*FIXME:*/FakeTypeLoc,
+ DeclarationName());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ return SemaRef.ActOnVAArg(E->getBuiltinLoc(), move(SubExpr),
+ T.getAsOpaquePtr(), E->getRParenLoc());
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitInitListExpr(InitListExpr *E) {
+ ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef);
+ for (unsigned I = 0, N = E->getNumInits(); I != N; ++I) {
+ OwningExprResult Init = Visit(E->getInit(I));
+ if (Init.isInvalid())
+ return SemaRef.ExprError();
+ Inits.push_back(Init.takeAs<Expr>());
+ }
+
+ return SemaRef.ActOnInitList(E->getLBraceLoc(), move_arg(Inits),
+ E->getRBraceLoc());
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
+ Designation Desig;
+
+ // Instantiate the initializer value
+ OwningExprResult Init = Visit(E->getInit());
+ if (Init.isInvalid())
+ return SemaRef.ExprError();
+
+ // Instantiate the designators.
+ ASTOwningVector<&ActionBase::DeleteExpr, 4> ArrayExprs(SemaRef);
+ for (DesignatedInitExpr::designators_iterator D = E->designators_begin(),
+ DEnd = E->designators_end();
+ D != DEnd; ++D) {
+ if (D->isFieldDesignator()) {
+ Desig.AddDesignator(Designator::getField(D->getFieldName(),
+ D->getDotLoc(),
+ D->getFieldLoc()));
+ continue;
+ }
+
+ if (D->isArrayDesignator()) {
+ OwningExprResult Index = Visit(E->getArrayIndex(*D));
+ if (Index.isInvalid())
+ return SemaRef.ExprError();
+
+ Desig.AddDesignator(Designator::getArray(Index.get(),
+ D->getLBracketLoc()));
+
+ ArrayExprs.push_back(Index.release());
+ continue;
+ }
+
+ assert(D->isArrayRangeDesignator() && "New kind of designator?");
+ OwningExprResult Start = Visit(E->getArrayRangeStart(*D));
+ if (Start.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult End = Visit(E->getArrayRangeEnd(*D));
+ if (End.isInvalid())
+ return SemaRef.ExprError();
+
+ Desig.AddDesignator(Designator::getArrayRange(Start.get(),
+ End.get(),
+ D->getLBracketLoc(),
+ D->getEllipsisLoc()));
+
+ ArrayExprs.push_back(Start.release());
+ ArrayExprs.push_back(End.release());
+ }
+
+ OwningExprResult Result =
+ SemaRef.ActOnDesignatedInitializer(Desig,
+ E->getEqualOrColonLoc(),
+ E->usesGNUSyntax(),
+ move(Init));
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ ArrayExprs.take();
+ return move(Result);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitImplicitValueInitExpr(
+ ImplicitValueInitExpr *E) {
+ assert(!E->isTypeDependent() && !E->isValueDependent() &&
+ "ImplicitValueInitExprs are never dependent");
+ return SemaRef.Clone(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
+ OwningExprResult Base = Visit(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ SourceLocation FakeOperatorLoc =
+ SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd());
+ return SemaRef.ActOnMemberReferenceExpr(/*Scope=*/0,
+ move(Base),
+ /*FIXME*/FakeOperatorLoc,
+ tok::period,
+ E->getAccessorLoc(),
+ E->getAccessor(),
+ /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitBlockExpr(BlockExpr *E) {
+ assert(false && "FIXME:Template instantiation for blocks is unimplemented");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
+ assert(false && "FIXME:Template instantiation for blocks is unimplemented");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+ bool isSizeOf = E->isSizeOf();
+
+ if (E->isArgumentType()) {
+ QualType T = E->getArgumentType();
+ if (T->isDependentType()) {
+ T = SemaRef.InstantiateType(T, TemplateArgs,
+ /*FIXME*/E->getOperatorLoc(),
+ &SemaRef.PP.getIdentifierTable().get("sizeof"));
+ if (T.isNull())
+ return SemaRef.ExprError();
+ }
+
+ return SemaRef.CreateSizeOfAlignOfExpr(T, E->getOperatorLoc(), isSizeOf,
+ E->getSourceRange());
+ }
+
+ Sema::OwningExprResult Arg = Visit(E->getArgumentExpr());
+ if (Arg.isInvalid())
+ return SemaRef.ExprError();
+
+ Sema::OwningExprResult Result
+ = SemaRef.CreateSizeOfAlignOfExpr((Expr *)Arg.get(), E->getOperatorLoc(),
+ isSizeOf, E->getSourceRange());
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ Arg.release();
+ return move(Result);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *E) {
+ NestedNameSpecifier *NNS
+ = SemaRef.InstantiateNestedNameSpecifier(E->getQualifier(),
+ E->getQualifierRange(),
+ TemplateArgs);
+ if (!NNS)
+ return SemaRef.ExprError();
+
+ CXXScopeSpec SS;
+ SS.setRange(E->getQualifierRange());
+ SS.setScopeRep(NNS);
+
+ // FIXME: We're passing in a NULL scope, because
+ // ActOnDeclarationNameExpr doesn't actually use the scope when we
+ // give it a non-empty scope specifier. Investigate whether it would
+ // be better to refactor ActOnDeclarationNameExpr.
+ return SemaRef.ActOnDeclarationNameExpr(/*Scope=*/0, E->getLocation(),
+ E->getDeclName(),
+ /*HasTrailingLParen=*/false,
+ &SS,
+ /*FIXME:isAddressOfOperand=*/false);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXTemporaryObjectExpr(
+ CXXTemporaryObjectExpr *E) {
+ QualType T = E->getType();
+ if (T->isDependentType()) {
+ T = SemaRef.InstantiateType(T, TemplateArgs,
+ E->getTypeBeginLoc(), DeclarationName());
+ if (T.isNull())
+ return SemaRef.ExprError();
+ }
+
+ ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
+ Args.reserve(E->getNumArgs());
+ for (CXXTemporaryObjectExpr::arg_iterator Arg = E->arg_begin(),
+ ArgEnd = E->arg_end();
+ Arg != ArgEnd; ++Arg) {
+ OwningExprResult InstantiatedArg = Visit(*Arg);
+ if (InstantiatedArg.isInvalid())
+ return SemaRef.ExprError();
+
+ Args.push_back((Expr *)InstantiatedArg.release());
+ }
+
+ SourceLocation CommaLoc;
+ // FIXME: HACK!
+ if (Args.size() > 1) {
+ Expr *First = (Expr *)Args[0];
+ CommaLoc
+ = SemaRef.PP.getLocForEndOfToken(First->getSourceRange().getEnd());
+ }
+ return SemaRef.ActOnCXXTypeConstructExpr(SourceRange(E->getTypeBeginLoc()
+ /*, FIXME*/),
+ T.getAsOpaquePtr(),
+ /*FIXME*/E->getTypeBeginLoc(),
+ move_arg(Args),
+ /*HACK*/&CommaLoc,
+ E->getSourceRange().getEnd());
+}
+
+Sema::OwningExprResult TemplateExprInstantiator::VisitCastExpr(CastExpr *E) {
+ assert(false && "Cannot instantiate abstract CastExpr");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult TemplateExprInstantiator::VisitImplicitCastExpr(
+ ImplicitCastExpr *E) {
+ assert(!E->isTypeDependent() && "Implicit casts must have known types");
+
+ Sema::OwningExprResult SubExpr = Visit(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ ImplicitCastExpr *ICE =
+ new (SemaRef.Context) ImplicitCastExpr(E->getType(),
+ (Expr *)SubExpr.release(),
+ E->isLvalueCast());
+ return SemaRef.Owned(ICE);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitExplicitCastExpr(ExplicitCastExpr *E) {
+ assert(false && "Cannot instantiate abstract ExplicitCastExpr");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCStyleCastExpr(CStyleCastExpr *E) {
+ // Instantiate the type that we're casting to.
+ SourceLocation TypeStartLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc());
+ QualType ExplicitTy = SemaRef.InstantiateType(E->getTypeAsWritten(),
+ TemplateArgs,
+ TypeStartLoc,
+ DeclarationName());
+ if (ExplicitTy.isNull())
+ return SemaRef.ExprError();
+
+ // Instantiate the subexpression.
+ OwningExprResult SubExpr = Visit(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ return SemaRef.ActOnCastExpr(E->getLParenLoc(),
+ ExplicitTy.getAsOpaquePtr(),
+ E->getRParenLoc(),
+ move(SubExpr));
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
+ return VisitCallExpr(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
+ // Figure out which cast operator we're dealing with.
+ tok::TokenKind Kind;
+ switch (E->getStmtClass()) {
+ case Stmt::CXXStaticCastExprClass:
+ Kind = tok::kw_static_cast;
+ break;
+
+ case Stmt::CXXDynamicCastExprClass:
+ Kind = tok::kw_dynamic_cast;
+ break;
+
+ case Stmt::CXXReinterpretCastExprClass:
+ Kind = tok::kw_reinterpret_cast;
+ break;
+
+ case Stmt::CXXConstCastExprClass:
+ Kind = tok::kw_const_cast;
+ break;
+
+ default:
+ assert(false && "Invalid C++ named cast");
+ return SemaRef.ExprError();
+ }
+
+ // Instantiate the type that we're casting to.
+ SourceLocation TypeStartLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc());
+ QualType ExplicitTy = SemaRef.InstantiateType(E->getTypeAsWritten(),
+ TemplateArgs,
+ TypeStartLoc,
+ DeclarationName());
+ if (ExplicitTy.isNull())
+ return SemaRef.ExprError();
+
+ // Instantiate the subexpression.
+ OwningExprResult SubExpr = Visit(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ SourceLocation FakeLAngleLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc());
+ SourceLocation FakeRAngleLoc = E->getSubExpr()->getSourceRange().getBegin();
+ SourceLocation FakeRParenLoc
+ = SemaRef.PP.getLocForEndOfToken(
+ E->getSubExpr()->getSourceRange().getEnd());
+ return SemaRef.ActOnCXXNamedCast(E->getOperatorLoc(), Kind,
+ /*FIXME:*/FakeLAngleLoc,
+ ExplicitTy.getAsOpaquePtr(),
+ /*FIXME:*/FakeRAngleLoc,
+ /*FIXME:*/FakeRAngleLoc,
+ move(SubExpr),
+ /*FIXME:*/FakeRParenLoc);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXReinterpretCastExpr(
+ CXXReinterpretCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXConstCastExpr(CXXConstCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXThisExpr(CXXThisExpr *E) {
+ QualType ThisType =
+ cast<CXXMethodDecl>(SemaRef.CurContext)->getThisType(SemaRef.Context);
+
+ CXXThisExpr *TE =
+ new (SemaRef.Context) CXXThisExpr(E->getLocStart(), ThisType);
+
+ return SemaRef.Owned(TE);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
+ if (E->isTypeOperand()) {
+ QualType T = SemaRef.InstantiateType(E->getTypeOperand(),
+ TemplateArgs,
+ /*FIXME*/E->getSourceRange().getBegin(),
+ DeclarationName());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ return SemaRef.ActOnCXXTypeid(E->getSourceRange().getBegin(),
+ /*FIXME*/E->getSourceRange().getBegin(),
+ true, T.getAsOpaquePtr(),
+ E->getSourceRange().getEnd());
+ }
+
+ OwningExprResult Operand = Visit(E->getExprOperand());
+ if (Operand.isInvalid())
+ return SemaRef.ExprError();
+
+ OwningExprResult Result
+ = SemaRef.ActOnCXXTypeid(E->getSourceRange().getBegin(),
+ /*FIXME*/E->getSourceRange().getBegin(),
+ false, Operand.get(),
+ E->getSourceRange().getEnd());
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ Operand.release(); // FIXME: since ActOnCXXTypeid silently took ownership
+ return move(Result);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXThrowExpr(CXXThrowExpr *E) {
+ OwningExprResult SubExpr(SemaRef, (void *)0);
+ if (E->getSubExpr()) {
+ SubExpr = Visit(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+ }
+
+ return SemaRef.ActOnCXXThrow(E->getThrowLoc(), move(SubExpr));
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
+ assert(false &&
+ "FIXME: Instantiation for default arguments is unimplemented");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXBindTemporaryExpr(
+ CXXBindTemporaryExpr *E) {
+ OwningExprResult SubExpr = Visit(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ return SemaRef.MaybeBindToTemporary(SubExpr.takeAs<Expr>());
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ assert(!cast<CXXRecordDecl>(E->getConstructor()->getDeclContext())
+ ->isDependentType() && "Dependent constructor shouldn't be here");
+
+ QualType T = SemaRef.InstantiateType(E->getType(), TemplateArgs,
+ /*FIXME*/E->getSourceRange().getBegin(),
+ DeclarationName());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
+ for (CXXConstructExpr::arg_iterator Arg = E->arg_begin(),
+ ArgEnd = E->arg_end();
+ Arg != ArgEnd; ++Arg) {
+ OwningExprResult ArgInst = Visit(*Arg);
+ if (ArgInst.isInvalid())
+ return SemaRef.ExprError();
+
+ Args.push_back(ArgInst.takeAs<Expr>());
+ }
+
+ return SemaRef.Owned(CXXConstructExpr::Create(SemaRef.Context, T,
+ E->getConstructor(),
+ E->isElidable(),
+ Args.takeAs<Expr>(),
+ Args.size()));
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXFunctionalCastExpr(
+ CXXFunctionalCastExpr *E) {
+ // Instantiate the type that we're casting to.
+ QualType ExplicitTy = SemaRef.InstantiateType(E->getTypeAsWritten(),
+ TemplateArgs,
+ E->getTypeBeginLoc(),
+ DeclarationName());
+ if (ExplicitTy.isNull())
+ return SemaRef.ExprError();
+
+ // Instantiate the subexpression.
+ OwningExprResult SubExpr = Visit(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ // FIXME: The end of the type's source range is wrong
+ Expr *Sub = SubExpr.takeAs<Expr>();
+ return SemaRef.ActOnCXXTypeConstructExpr(SourceRange(E->getTypeBeginLoc()),
+ ExplicitTy.getAsOpaquePtr(),
+ /*FIXME:*/E->getTypeBeginLoc(),
+ Sema::MultiExprArg(SemaRef,
+ (void **)&Sub,
+ 1),
+ 0,
+ E->getRParenLoc());
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
+ return SemaRef.Clone(E);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXNewExpr(CXXNewExpr *E) {
+ // Instantiate the type that we're allocating
+ QualType AllocType = SemaRef.InstantiateType(E->getAllocatedType(),
+ TemplateArgs,
+ /*FIXME:*/E->getSourceRange().getBegin(),
+ DeclarationName());
+ if (AllocType.isNull())
+ return SemaRef.ExprError();
+
+ // Instantiate the size of the array we're allocating (if any).
+ OwningExprResult ArraySize = SemaRef.InstantiateExpr(E->getArraySize(),
+ TemplateArgs);
+ if (ArraySize.isInvalid())
+ return SemaRef.ExprError();
+
+ // Instantiate the placement arguments (if any).
+ ASTOwningVector<&ActionBase::DeleteExpr> PlacementArgs(SemaRef);
+ for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) {
+ OwningExprResult Arg = Visit(E->getPlacementArg(I));
+ if (Arg.isInvalid())
+ return SemaRef.ExprError();
+
+ PlacementArgs.push_back(Arg.take());
+ }
+
+ // Instantiate the constructor arguments (if any).
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(SemaRef);
+ for (unsigned I = 0, N = E->getNumConstructorArgs(); I != N; ++I) {
+ OwningExprResult Arg = Visit(E->getConstructorArg(I));
+ if (Arg.isInvalid())
+ return SemaRef.ExprError();
+
+ ConstructorArgs.push_back(Arg.take());
+ }
+
+ return SemaRef.BuildCXXNew(E->getSourceRange().getBegin(),
+ E->isGlobalNew(),
+ /*FIXME*/SourceLocation(),
+ move_arg(PlacementArgs),
+ /*FIXME*/SourceLocation(),
+ E->isParenTypeId(),
+ AllocType,
+ /*FIXME*/E->getSourceRange().getBegin(),
+ SourceRange(),
+ move(ArraySize),
+ /*FIXME*/SourceLocation(),
+ Sema::MultiExprArg(SemaRef,
+ ConstructorArgs.take(),
+ ConstructorArgs.size()),
+ E->getSourceRange().getEnd());
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
+ OwningExprResult Operand = Visit(E->getArgument());
+ if (Operand.isInvalid())
+ return SemaRef.ExprError();
+
+ return SemaRef.ActOnCXXDelete(E->getSourceRange().getBegin(),
+ E->isGlobalDelete(),
+ E->isArrayForm(),
+ move(Operand));
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
+ QualType T = SemaRef.InstantiateType(E->getQueriedType(), TemplateArgs,
+ /*FIXME*/E->getSourceRange().getBegin(),
+ DeclarationName());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ SourceLocation FakeLParenLoc
+ = SemaRef.PP.getLocForEndOfToken(E->getSourceRange().getBegin());
+ return SemaRef.ActOnUnaryTypeTrait(E->getTrait(),
+ E->getSourceRange().getBegin(),
+ /*FIXME*/FakeLParenLoc,
+ T.getAsOpaquePtr(),
+ E->getSourceRange().getEnd());
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *E) {
+ NestedNameSpecifier *NNS
+ = SemaRef.InstantiateNestedNameSpecifier(E->getQualifier(),
+ E->getQualifierRange(),
+ TemplateArgs);
+ if (!NNS)
+ return SemaRef.ExprError();
+
+ CXXScopeSpec SS;
+ SS.setRange(E->getQualifierRange());
+ SS.setScopeRep(NNS);
+ return SemaRef.ActOnDeclarationNameExpr(/*Scope=*/0,
+ E->getLocation(),
+ E->getDecl()->getDeclName(),
+ /*Trailing lparen=*/false,
+ &SS,
+ /*FIXME:*/false);
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXExprWithTemporaries(
+ CXXExprWithTemporaries *E) {
+ OwningExprResult SubExpr = Visit(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ return SemaRef.ActOnFinishFullExpr(move(SubExpr));
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXUnresolvedConstructExpr(
+ CXXUnresolvedConstructExpr *E) {
+ QualType T = SemaRef.InstantiateType(E->getTypeAsWritten(), TemplateArgs,
+ E->getTypeBeginLoc(),
+ DeclarationName());
+ if (T.isNull())
+ return SemaRef.ExprError();
+
+ ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
+ llvm::SmallVector<SourceLocation, 8> FakeCommaLocs;
+ for (CXXUnresolvedConstructExpr::arg_iterator Arg = E->arg_begin(),
+ ArgEnd = E->arg_end();
+ Arg != ArgEnd; ++Arg) {
+ OwningExprResult InstArg = Visit(*Arg);
+ if (InstArg.isInvalid())
+ return SemaRef.ExprError();
+
+ FakeCommaLocs.push_back(
+ SemaRef.PP.getLocForEndOfToken((*Arg)->getSourceRange().getEnd()));
+ Args.push_back(InstArg.takeAs<Expr>());
+ }
+
+ // FIXME: The end of the type range isn't exactly correct.
+ // FIXME: we're faking the locations of the commas
+ return SemaRef.ActOnCXXTypeConstructExpr(SourceRange(E->getTypeBeginLoc(),
+ E->getLParenLoc()),
+ T.getAsOpaquePtr(),
+ E->getLParenLoc(),
+ move_arg(Args),
+ &FakeCommaLocs.front(),
+ E->getRParenLoc());
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitCXXUnresolvedMemberExpr(
+ CXXUnresolvedMemberExpr *E) {
+ // Instantiate the base of the expression.
+ OwningExprResult Base = Visit(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ // FIXME: Instantiate the declaration name.
+ return SemaRef.ActOnMemberReferenceExpr(/*Scope=*/0,
+ move(Base), E->getOperatorLoc(),
+ E->isArrow()? tok::arrow
+ : tok::period,
+ E->getMemberLoc(),
+ /*FIXME:*/*E->getMember().getAsIdentifierInfo(),
+ /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
+}
+
+//----------------------------------------------------------------------------
+// Objective-C Expressions
+//----------------------------------------------------------------------------
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitObjCStringLiteral(ObjCStringLiteral *E) {
+ assert(false && "FIXME: Template instantiations for ObjC expressions");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
+ assert(false && "FIXME: Template instantiations for ObjC expressions");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ assert(false && "FIXME: Template instantiations for ObjC expressions");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
+ assert(false && "FIXME: Template instantiations for ObjC expressions");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
+ assert(false && "FIXME: Template instantiations for ObjC expressions");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ assert(false && "FIXME: Template instantiations for ObjC expressions");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
+ assert(false && "FIXME: Template instantiations for ObjC expressions");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
+ assert(false && "FIXME: Template instantiations for ObjC expressions");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult
+TemplateExprInstantiator::VisitObjCSuperExpr(ObjCSuperExpr *E) {
+ assert(false && "FIXME: Template instantiations for ObjC expressions");
+ return SemaRef.ExprError();
+}
+
+Sema::OwningExprResult
+Sema::InstantiateExpr(Expr *E, const TemplateArgumentList &TemplateArgs) {
+ if (!E)
+ return Owned((Expr *)0);
+
+ TemplateExprInstantiator Instantiator(*this, TemplateArgs);
+ return Instantiator.Visit(E);
+}
diff --git a/lib/Sema/SemaTemplateInstantiateStmt.cpp b/lib/Sema/SemaTemplateInstantiateStmt.cpp
new file mode 100644
index 000000000000..1f69479a0e7c
--- /dev/null
+++ b/lib/Sema/SemaTemplateInstantiateStmt.cpp
@@ -0,0 +1,443 @@
+//===--- SemaTemplateInstantiateStmt.cpp - C++ Template Stmt Instantiation ===/
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===/
+//
+// This file implements C++ template instantiation for statements.
+//
+//===----------------------------------------------------------------------===/
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Parse/DeclSpec.h"
+#include "llvm/Support/Compiler.h"
+using namespace clang;
+
+namespace {
+ class VISIBILITY_HIDDEN TemplateStmtInstantiator
+ : public StmtVisitor<TemplateStmtInstantiator, Sema::OwningStmtResult> {
+ Sema &SemaRef;
+ const TemplateArgumentList &TemplateArgs;
+
+ template<typename T>
+ Sema::FullExprArg FullExpr(T &expr) {
+ return SemaRef.FullExpr(expr);
+ }
+
+ public:
+ typedef Sema::OwningExprResult OwningExprResult;
+ typedef Sema::OwningStmtResult OwningStmtResult;
+
+ TemplateStmtInstantiator(Sema &SemaRef,
+ const TemplateArgumentList &TemplateArgs)
+ : SemaRef(SemaRef), TemplateArgs(TemplateArgs) { }
+
+ // Declare VisitXXXStmt nodes for all of the statement kinds.
+#define STMT(Type, Base) OwningStmtResult Visit##Type(Type *S);
+#define EXPR(Type, Base)
+#include "clang/AST/StmtNodes.def"
+
+ // Visit an expression (which will use the expression
+ // instantiator).
+ OwningStmtResult VisitExpr(Expr *E);
+
+ // Base case. I'm supposed to ignore this.
+ OwningStmtResult VisitStmt(Stmt *S) {
+ S->dump();
+ assert(false && "Cannot instantiate this kind of statement");
+ return SemaRef.StmtError();
+ }
+ };
+}
+
+//===----------------------------------------------------------------------===/
+// Common/C statements
+//===----------------------------------------------------------------------===/
+Sema::OwningStmtResult TemplateStmtInstantiator::VisitDeclStmt(DeclStmt *S) {
+ llvm::SmallVector<Decl *, 4> Decls;
+ for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
+ D != DEnd; ++D) {
+ Decl *Instantiated = SemaRef.InstantiateDecl(*D, SemaRef.CurContext,
+ TemplateArgs);
+ if (!Instantiated)
+ return SemaRef.StmtError();
+
+ Decls.push_back(Instantiated);
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(*D, Instantiated);
+ }
+
+ return SemaRef.Owned(new (SemaRef.Context) DeclStmt(
+ DeclGroupRef::Create(SemaRef.Context,
+ &Decls[0],
+ Decls.size()),
+ S->getStartLoc(),
+ S->getEndLoc()));
+}
+
+Sema::OwningStmtResult TemplateStmtInstantiator::VisitNullStmt(NullStmt *S) {
+ return SemaRef.Owned(S->Clone(SemaRef.Context));
+}
+
+Sema::OwningStmtResult TemplateStmtInstantiator::VisitLabelStmt(LabelStmt *S) {
+ OwningStmtResult SubStmt = Visit(S->getSubStmt());
+
+ if (SubStmt.isInvalid())
+ return SemaRef.StmtError();
+
+ // FIXME: Pass the real colon loc in.
+ return SemaRef.ActOnLabelStmt(S->getIdentLoc(), S->getID(), SourceLocation(),
+ move(SubStmt));
+}
+
+Sema::OwningStmtResult TemplateStmtInstantiator::VisitGotoStmt(GotoStmt *S) {
+ return SemaRef.ActOnGotoStmt(S->getGotoLoc(), S->getLabelLoc(),
+ S->getLabel()->getID());
+}
+
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
+ OwningExprResult Target = SemaRef.InstantiateExpr(S->getTarget(),
+ TemplateArgs);
+ if (Target.isInvalid())
+ return SemaRef.StmtError();
+
+ return SemaRef.ActOnIndirectGotoStmt(S->getGotoLoc(), S->getStarLoc(),
+ move(Target));
+}
+
+Sema::OwningStmtResult TemplateStmtInstantiator::VisitBreakStmt(BreakStmt *S) {
+ return SemaRef.Owned(S->Clone(SemaRef.Context));
+}
+
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitContinueStmt(ContinueStmt *S) {
+ return SemaRef.Owned(S->Clone(SemaRef.Context));
+}
+
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitReturnStmt(ReturnStmt *S) {
+ Sema::OwningExprResult Result = SemaRef.ExprEmpty();
+ if (Expr *E = S->getRetValue()) {
+ Result = SemaRef.InstantiateExpr(E, TemplateArgs);
+
+ if (Result.isInvalid())
+ return SemaRef.StmtError();
+ }
+
+ return SemaRef.ActOnReturnStmt(S->getReturnLoc(), FullExpr(Result));
+}
+
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitCompoundStmt(CompoundStmt *S) {
+ return SemaRef.InstantiateCompoundStmt(S, TemplateArgs, false);
+}
+
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitSwitchCase(SwitchCase *S) {
+ assert(false && "SwitchCase statements are never directly instantiated");
+ return SemaRef.StmtError();
+}
+
+Sema::OwningStmtResult TemplateStmtInstantiator::VisitCaseStmt(CaseStmt *S) {
+ // Instantiate left-hand case value.
+ OwningExprResult LHS = SemaRef.InstantiateExpr(S->getLHS(), TemplateArgs);
+ if (LHS.isInvalid())
+ return SemaRef.StmtError();
+
+ // Instantiate right-hand case value (for the GNU case-range extension).
+ OwningExprResult RHS = SemaRef.InstantiateExpr(S->getRHS(), TemplateArgs);
+ if (RHS.isInvalid())
+ return SemaRef.StmtError();
+
+ // Build the case statement.
+ OwningStmtResult Case = SemaRef.ActOnCaseStmt(S->getCaseLoc(),
+ move(LHS),
+ S->getEllipsisLoc(),
+ move(RHS),
+ S->getColonLoc());
+ if (Case.isInvalid())
+ return SemaRef.StmtError();
+
+ // Instantiate the statement following the case
+ OwningStmtResult SubStmt = SemaRef.InstantiateStmt(S->getSubStmt(),
+ TemplateArgs);
+ if (SubStmt.isInvalid())
+ return SemaRef.StmtError();
+
+ SemaRef.ActOnCaseStmtBody(Case.get(), move(SubStmt));
+ return move(Case);
+}
+
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitDefaultStmt(DefaultStmt *S) {
+ // Instantiate the statement following the default case
+ OwningStmtResult SubStmt = SemaRef.InstantiateStmt(S->getSubStmt(),
+ TemplateArgs);
+ if (SubStmt.isInvalid())
+ return SemaRef.StmtError();
+
+ return SemaRef.ActOnDefaultStmt(S->getDefaultLoc(),
+ S->getColonLoc(),
+ move(SubStmt),
+ /*CurScope=*/0);
+}
+
+Sema::OwningStmtResult TemplateStmtInstantiator::VisitIfStmt(IfStmt *S) {
+ // Instantiate the condition
+ OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs);
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
+ // Instantiate the "then" branch.
+ OwningStmtResult Then = SemaRef.InstantiateStmt(S->getThen(), TemplateArgs);
+ if (Then.isInvalid())
+ return SemaRef.StmtError();
+
+ // Instantiate the "else" branch.
+ OwningStmtResult Else = SemaRef.InstantiateStmt(S->getElse(), TemplateArgs);
+ if (Else.isInvalid())
+ return SemaRef.StmtError();
+
+ return SemaRef.ActOnIfStmt(S->getIfLoc(), FullExpr(Cond), move(Then),
+ S->getElseLoc(), move(Else));
+}
+
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitSwitchStmt(SwitchStmt *S) {
+ // Instantiate the condition.
+ OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs);
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
+ // Start the switch statement itself.
+ OwningStmtResult Switch = SemaRef.ActOnStartOfSwitchStmt(move(Cond));
+ if (Switch.isInvalid())
+ return SemaRef.StmtError();
+
+ // Instantiate the body of the switch statement.
+ OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs);
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ // Complete the switch statement.
+ return SemaRef.ActOnFinishSwitchStmt(S->getSwitchLoc(), move(Switch),
+ move(Body));
+}
+
+Sema::OwningStmtResult TemplateStmtInstantiator::VisitWhileStmt(WhileStmt *S) {
+ // Instantiate the condition
+ OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs);
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
+ // Instantiate the body
+ OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs);
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ return SemaRef.ActOnWhileStmt(S->getWhileLoc(), FullExpr(Cond), move(Body));
+}
+
+Sema::OwningStmtResult TemplateStmtInstantiator::VisitDoStmt(DoStmt *S) {
+ // Instantiate the condition
+ OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs);
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
+ // Instantiate the body
+ OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs);
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ return SemaRef.ActOnDoStmt(S->getDoLoc(), move(Body), S->getWhileLoc(),
+ move(Cond));
+}
+
+Sema::OwningStmtResult TemplateStmtInstantiator::VisitForStmt(ForStmt *S) {
+ // Instantiate the initialization statement
+ OwningStmtResult Init = SemaRef.InstantiateStmt(S->getInit(), TemplateArgs);
+ if (Init.isInvalid())
+ return SemaRef.StmtError();
+
+ // Instantiate the condition
+ OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs);
+ if (Cond.isInvalid())
+ return SemaRef.StmtError();
+
+ // Instantiate the increment
+ OwningExprResult Inc = SemaRef.InstantiateExpr(S->getInc(), TemplateArgs);
+ if (Inc.isInvalid())
+ return SemaRef.StmtError();
+
+ // Instantiate the body
+ OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs);
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ return SemaRef.ActOnForStmt(S->getForLoc(), S->getLParenLoc(),
+ move(Init), move(Cond), move(Inc),
+ S->getRParenLoc(), move(Body));
+}
+
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitAsmStmt(AsmStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot instantiate an 'asm' statement");
+ return SemaRef.StmtError();
+}
+
+//===----------------------------------------------------------------------===/
+// C++ statements
+//===----------------------------------------------------------------------===/
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitCXXTryStmt(CXXTryStmt *S) {
+ // Instantiate the try block itself.
+ OwningStmtResult TryBlock = VisitCompoundStmt(S->getTryBlock());
+ if (TryBlock.isInvalid())
+ return SemaRef.StmtError();
+
+ // Instantiate the handlers.
+ ASTOwningVector<&ActionBase::DeleteStmt> Handlers(SemaRef);
+ for (unsigned I = 0, N = S->getNumHandlers(); I != N; ++I) {
+ OwningStmtResult Handler = VisitCXXCatchStmt(S->getHandler(I));
+ if (Handler.isInvalid())
+ return SemaRef.StmtError();
+
+ Handlers.push_back(Handler.takeAs<Stmt>());
+ }
+
+ return SemaRef.ActOnCXXTryBlock(S->getTryLoc(), move(TryBlock),
+ move_arg(Handlers));
+}
+
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitCXXCatchStmt(CXXCatchStmt *S) {
+ // Instantiate the exception declaration, if any.
+ VarDecl *Var = 0;
+ if (S->getExceptionDecl()) {
+ VarDecl *ExceptionDecl = S->getExceptionDecl();
+ QualType T = SemaRef.InstantiateType(ExceptionDecl->getType(),
+ TemplateArgs,
+ ExceptionDecl->getLocation(),
+ ExceptionDecl->getDeclName());
+ if (T.isNull())
+ return SemaRef.StmtError();
+
+ Var = SemaRef.BuildExceptionDeclaration(0, T,
+ ExceptionDecl->getIdentifier(),
+ ExceptionDecl->getLocation(),
+ /*FIXME: Inaccurate*/
+ SourceRange(ExceptionDecl->getLocation()));
+ if (Var->isInvalidDecl()) {
+ Var->Destroy(SemaRef.Context);
+ return SemaRef.StmtError();
+ }
+
+ // Introduce the exception declaration into scope.
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var);
+ }
+
+ // Instantiate the actual exception handler.
+ OwningStmtResult Handler = Visit(S->getHandlerBlock());
+ if (Handler.isInvalid()) {
+ if (Var)
+ Var->Destroy(SemaRef.Context);
+ return SemaRef.StmtError();
+ }
+
+ return SemaRef.Owned(new (SemaRef.Context) CXXCatchStmt(S->getCatchLoc(),
+ Var,
+ Handler.takeAs<Stmt>()));
+}
+
+//===----------------------------------------------------------------------===/
+// Objective-C statements
+//===----------------------------------------------------------------------===/
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot instantiate an Objective-C @finally statement");
+ return SemaRef.StmtError();
+}
+
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitObjCAtSynchronizedStmt(
+ ObjCAtSynchronizedStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot instantiate an Objective-C @synchronized statement");
+ return SemaRef.StmtError();
+}
+
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot instantiate an Objective-C @try statement");
+ return SemaRef.StmtError();
+}
+
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitObjCForCollectionStmt(
+ ObjCForCollectionStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot instantiate an Objective-C \"for\" statement");
+ return SemaRef.StmtError();
+}
+
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot instantiate an Objective-C @throw statement");
+ return SemaRef.StmtError();
+}
+
+Sema::OwningStmtResult
+TemplateStmtInstantiator::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
+ // FIXME: Implement this
+ assert(false && "Cannot instantiate an Objective-C @catch statement");
+ return SemaRef.StmtError();
+}
+
+Sema::OwningStmtResult TemplateStmtInstantiator::VisitExpr(Expr *E) {
+ Sema::OwningExprResult Result = SemaRef.InstantiateExpr(E, TemplateArgs);
+ if (Result.isInvalid())
+ return SemaRef.StmtError();
+
+ return SemaRef.Owned(Result.takeAs<Stmt>());
+}
+
+Sema::OwningStmtResult
+Sema::InstantiateStmt(Stmt *S, const TemplateArgumentList &TemplateArgs) {
+ if (!S)
+ return Owned((Stmt *)0);
+
+ TemplateStmtInstantiator Instantiator(*this, TemplateArgs);
+ return Instantiator.Visit(S);
+}
+
+Sema::OwningStmtResult
+Sema::InstantiateCompoundStmt(CompoundStmt *S,
+ const TemplateArgumentList &TemplateArgs,
+ bool isStmtExpr) {
+ if (!S)
+ return Owned((Stmt *)0);
+
+ TemplateStmtInstantiator Instantiator(*this, TemplateArgs);
+ ASTOwningVector<&ActionBase::DeleteStmt> Statements(*this);
+ for (CompoundStmt::body_iterator B = S->body_begin(), BEnd = S->body_end();
+ B != BEnd; ++B) {
+ OwningStmtResult Result = Instantiator.Visit(*B);
+ if (Result.isInvalid())
+ return StmtError();
+
+ Statements.push_back(Result.takeAs<Stmt>());
+ }
+
+ return ActOnCompoundStmt(S->getLBracLoc(), S->getRBracLoc(),
+ move_arg(Statements), isStmtExpr);
+}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
new file mode 100644
index 000000000000..81ac21123e91
--- /dev/null
+++ b/lib/Sema/SemaType.cpp
@@ -0,0 +1,1301 @@
+//===--- SemaType.cpp - Semantic Analysis for Types -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements type-related semantic analysis.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/Parse/DeclSpec.h"
+using namespace clang;
+
+/// \brief Perform adjustment on the parameter type of a function.
+///
+/// This routine adjusts the given parameter type @p T to the actual
+/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8],
+/// C++ [dcl.fct]p3). The adjusted parameter type is returned.
+QualType Sema::adjustParameterType(QualType T) {
+ // C99 6.7.5.3p7:
+ if (T->isArrayType()) {
+ // C99 6.7.5.3p7:
+ // A declaration of a parameter as "array of type" shall be
+ // adjusted to "qualified pointer to type", where the type
+ // qualifiers (if any) are those specified within the [ and ] of
+ // the array type derivation.
+ return Context.getArrayDecayedType(T);
+ } else if (T->isFunctionType())
+ // C99 6.7.5.3p8:
+ // A declaration of a parameter as "function returning type"
+ // shall be adjusted to "pointer to function returning type", as
+ // in 6.3.2.1.
+ return Context.getPointerType(T);
+
+ return T;
+}
+
+/// \brief Convert the specified declspec to the appropriate type
+/// object.
+/// \param DS the declaration specifiers
+/// \param DeclLoc The location of the declarator identifier or invalid if none.
+/// \returns The type described by the declaration specifiers. This function
+/// never returns null.
+QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
+ SourceLocation DeclLoc,
+ bool &isInvalid) {
+ // FIXME: Should move the logic from DeclSpec::Finish to here for validity
+ // checking.
+ QualType Result;
+
+ switch (DS.getTypeSpecType()) {
+ case DeclSpec::TST_void:
+ Result = Context.VoidTy;
+ break;
+ case DeclSpec::TST_char:
+ if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified)
+ Result = Context.CharTy;
+ else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed)
+ Result = Context.SignedCharTy;
+ else {
+ assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned &&
+ "Unknown TSS value");
+ Result = Context.UnsignedCharTy;
+ }
+ break;
+ case DeclSpec::TST_wchar:
+ if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified)
+ Result = Context.WCharTy;
+ else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) {
+ Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec)
+ << DS.getSpecifierName(DS.getTypeSpecType());
+ Result = Context.getSignedWCharType();
+ } else {
+ assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned &&
+ "Unknown TSS value");
+ Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec)
+ << DS.getSpecifierName(DS.getTypeSpecType());
+ Result = Context.getUnsignedWCharType();
+ }
+ break;
+ case DeclSpec::TST_unspecified:
+ // "<proto1,proto2>" is an objc qualified ID with a missing id.
+ if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
+ Result = Context.getObjCQualifiedIdType((ObjCProtocolDecl**)PQ,
+ DS.getNumProtocolQualifiers());
+ break;
+ }
+
+ // Unspecified typespec defaults to int in C90. However, the C90 grammar
+ // [C90 6.5] only allows a decl-spec if there was *some* type-specifier,
+ // type-qualifier, or storage-class-specifier. If not, emit an extwarn.
+ // Note that the one exception to this is function definitions, which are
+ // allowed to be completely missing a declspec. This is handled in the
+ // parser already though by it pretending to have seen an 'int' in this
+ // case.
+ if (getLangOptions().ImplicitInt) {
+ // In C89 mode, we only warn if there is a completely missing declspec
+ // when one is not allowed.
+ if (DS.isEmpty()) {
+ if (DeclLoc.isInvalid())
+ DeclLoc = DS.getSourceRange().getBegin();
+ Diag(DeclLoc, diag::warn_missing_declspec)
+ << DS.getSourceRange()
+ << CodeModificationHint::CreateInsertion(DS.getSourceRange().getBegin(),
+ "int");
+ }
+ } else if (!DS.hasTypeSpecifier()) {
+ // C99 and C++ require a type specifier. For example, C99 6.7.2p2 says:
+ // "At least one type specifier shall be given in the declaration
+ // specifiers in each declaration, and in the specifier-qualifier list in
+ // each struct declaration and type name."
+ // FIXME: Does Microsoft really have the implicit int extension in C++?
+ if (DeclLoc.isInvalid())
+ DeclLoc = DS.getSourceRange().getBegin();
+
+ if (getLangOptions().CPlusPlus && !getLangOptions().Microsoft)
+ Diag(DeclLoc, diag::err_missing_type_specifier)
+ << DS.getSourceRange();
+ else
+ Diag(DeclLoc, diag::warn_missing_type_specifier)
+ << DS.getSourceRange();
+
+ // FIXME: If we could guarantee that the result would be well-formed, it
+ // would be useful to have a code insertion hint here. However, after
+ // emitting this warning/error, we often emit other errors.
+ }
+
+ // FALL THROUGH.
+ case DeclSpec::TST_int: {
+ if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) {
+ switch (DS.getTypeSpecWidth()) {
+ case DeclSpec::TSW_unspecified: Result = Context.IntTy; break;
+ case DeclSpec::TSW_short: Result = Context.ShortTy; break;
+ case DeclSpec::TSW_long: Result = Context.LongTy; break;
+ case DeclSpec::TSW_longlong: Result = Context.LongLongTy; break;
+ }
+ } else {
+ switch (DS.getTypeSpecWidth()) {
+ case DeclSpec::TSW_unspecified: Result = Context.UnsignedIntTy; break;
+ case DeclSpec::TSW_short: Result = Context.UnsignedShortTy; break;
+ case DeclSpec::TSW_long: Result = Context.UnsignedLongTy; break;
+ case DeclSpec::TSW_longlong: Result =Context.UnsignedLongLongTy; break;
+ }
+ }
+ break;
+ }
+ case DeclSpec::TST_float: Result = Context.FloatTy; break;
+ case DeclSpec::TST_double:
+ if (DS.getTypeSpecWidth() == DeclSpec::TSW_long)
+ Result = Context.LongDoubleTy;
+ else
+ Result = Context.DoubleTy;
+ break;
+ case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool
+ case DeclSpec::TST_decimal32: // _Decimal32
+ case DeclSpec::TST_decimal64: // _Decimal64
+ case DeclSpec::TST_decimal128: // _Decimal128
+ Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported);
+ Result = Context.IntTy;
+ isInvalid = true;
+ break;
+ case DeclSpec::TST_class:
+ case DeclSpec::TST_enum:
+ case DeclSpec::TST_union:
+ case DeclSpec::TST_struct: {
+ Decl *D = static_cast<Decl *>(DS.getTypeRep());
+ assert(D && "Didn't get a decl for a class/enum/union/struct?");
+ assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 &&
+ DS.getTypeSpecSign() == 0 &&
+ "Can't handle qualifiers on typedef names yet!");
+ // TypeQuals handled by caller.
+ Result = Context.getTypeDeclType(cast<TypeDecl>(D));
+
+ if (D->isInvalidDecl())
+ isInvalid = true;
+ break;
+ }
+ case DeclSpec::TST_typename: {
+ assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 &&
+ DS.getTypeSpecSign() == 0 &&
+ "Can't handle qualifiers on typedef names yet!");
+ Result = QualType::getFromOpaquePtr(DS.getTypeRep());
+
+ if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
+ // FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so we have
+ // this "hack" for now...
+ if (const ObjCInterfaceType *Interface = Result->getAsObjCInterfaceType())
+ Result = Context.getObjCQualifiedInterfaceType(Interface->getDecl(),
+ (ObjCProtocolDecl**)PQ,
+ DS.getNumProtocolQualifiers());
+ else if (Result == Context.getObjCIdType())
+ // id<protocol-list>
+ Result = Context.getObjCQualifiedIdType((ObjCProtocolDecl**)PQ,
+ DS.getNumProtocolQualifiers());
+ else if (Result == Context.getObjCClassType()) {
+ if (DeclLoc.isInvalid())
+ DeclLoc = DS.getSourceRange().getBegin();
+ // Class<protocol-list>
+ Diag(DeclLoc, diag::err_qualified_class_unsupported)
+ << DS.getSourceRange();
+ } else {
+ if (DeclLoc.isInvalid())
+ DeclLoc = DS.getSourceRange().getBegin();
+ Diag(DeclLoc, diag::err_invalid_protocol_qualifiers)
+ << DS.getSourceRange();
+ isInvalid = true;
+ }
+ }
+
+ // If this is a reference to an invalid typedef, propagate the invalidity.
+ if (TypedefType *TDT = dyn_cast<TypedefType>(Result))
+ if (TDT->getDecl()->isInvalidDecl())
+ isInvalid = true;
+
+ // TypeQuals handled by caller.
+ break;
+ }
+ case DeclSpec::TST_typeofType:
+ Result = QualType::getFromOpaquePtr(DS.getTypeRep());
+ assert(!Result.isNull() && "Didn't get a type for typeof?");
+ // TypeQuals handled by caller.
+ Result = Context.getTypeOfType(Result);
+ break;
+ case DeclSpec::TST_typeofExpr: {
+ Expr *E = static_cast<Expr *>(DS.getTypeRep());
+ assert(E && "Didn't get an expression for typeof?");
+ // TypeQuals handled by caller.
+ Result = Context.getTypeOfExprType(E);
+ break;
+ }
+ case DeclSpec::TST_error:
+ Result = Context.IntTy;
+ isInvalid = true;
+ break;
+ }
+
+ // Handle complex types.
+ if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) {
+ if (getLangOptions().Freestanding)
+ Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex);
+ Result = Context.getComplexType(Result);
+ }
+
+ assert(DS.getTypeSpecComplex() != DeclSpec::TSC_imaginary &&
+ "FIXME: imaginary types not supported yet!");
+
+ // See if there are any attributes on the declspec that apply to the type (as
+ // opposed to the decl).
+ if (const AttributeList *AL = DS.getAttributes())
+ ProcessTypeAttributeList(Result, AL);
+
+ // Apply const/volatile/restrict qualifiers to T.
+ if (unsigned TypeQuals = DS.getTypeQualifiers()) {
+
+ // Enforce C99 6.7.3p2: "Types other than pointer types derived from object
+ // or incomplete types shall not be restrict-qualified." C++ also allows
+ // restrict-qualified references.
+ if (TypeQuals & QualType::Restrict) {
+ if (Result->isPointerType() || Result->isReferenceType()) {
+ QualType EltTy = Result->isPointerType() ?
+ Result->getAsPointerType()->getPointeeType() :
+ Result->getAsReferenceType()->getPointeeType();
+
+ // If we have a pointer or reference, the pointee must have an object
+ // incomplete type.
+ if (!EltTy->isIncompleteOrObjectType()) {
+ Diag(DS.getRestrictSpecLoc(),
+ diag::err_typecheck_invalid_restrict_invalid_pointee)
+ << EltTy << DS.getSourceRange();
+ TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier.
+ }
+ } else {
+ Diag(DS.getRestrictSpecLoc(),
+ diag::err_typecheck_invalid_restrict_not_pointer)
+ << Result << DS.getSourceRange();
+ TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier.
+ }
+ }
+
+ // Warn about CV qualifiers on functions: C99 6.7.3p8: "If the specification
+ // of a function type includes any type qualifiers, the behavior is
+ // undefined."
+ if (Result->isFunctionType() && TypeQuals) {
+ // Get some location to point at, either the C or V location.
+ SourceLocation Loc;
+ if (TypeQuals & QualType::Const)
+ Loc = DS.getConstSpecLoc();
+ else {
+ assert((TypeQuals & QualType::Volatile) &&
+ "Has CV quals but not C or V?");
+ Loc = DS.getVolatileSpecLoc();
+ }
+ Diag(Loc, diag::warn_typecheck_function_qualifiers)
+ << Result << DS.getSourceRange();
+ }
+
+ // C++ [dcl.ref]p1:
+ // Cv-qualified references are ill-formed except when the
+ // cv-qualifiers are introduced through the use of a typedef
+ // (7.1.3) or of a template type argument (14.3), in which
+ // case the cv-qualifiers are ignored.
+ // FIXME: Shouldn't we be checking SCS_typedef here?
+ if (DS.getTypeSpecType() == DeclSpec::TST_typename &&
+ TypeQuals && Result->isReferenceType()) {
+ TypeQuals &= ~QualType::Const;
+ TypeQuals &= ~QualType::Volatile;
+ }
+
+ Result = Result.getQualifiedType(TypeQuals);
+ }
+ return Result;
+}
+
+static std::string getPrintableNameForEntity(DeclarationName Entity) {
+ if (Entity)
+ return Entity.getAsString();
+
+ return "type name";
+}
+
+/// \brief Build a pointer type.
+///
+/// \param T The type to which we'll be building a pointer.
+///
+/// \param Quals The cvr-qualifiers to be applied to the pointer type.
+///
+/// \param Loc The location of the entity whose type involves this
+/// pointer type or, if there is no such entity, the location of the
+/// type that will have pointer type.
+///
+/// \param Entity The name of the entity that involves the pointer
+/// type, if known.
+///
+/// \returns A suitable pointer type, if there are no
+/// errors. Otherwise, returns a NULL type.
+QualType Sema::BuildPointerType(QualType T, unsigned Quals,
+ SourceLocation Loc, DeclarationName Entity) {
+ if (T->isReferenceType()) {
+ // C++ 8.3.2p4: There shall be no ... pointers to references ...
+ Diag(Loc, diag::err_illegal_decl_pointer_to_reference)
+ << getPrintableNameForEntity(Entity);
+ return QualType();
+ }
+
+ // Enforce C99 6.7.3p2: "Types other than pointer types derived from
+ // object or incomplete types shall not be restrict-qualified."
+ if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) {
+ Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
+ << T;
+ Quals &= ~QualType::Restrict;
+ }
+
+ // Build the pointer type.
+ return Context.getPointerType(T).getQualifiedType(Quals);
+}
+
+/// \brief Build a reference type.
+///
+/// \param T The type to which we'll be building a reference.
+///
+/// \param Quals The cvr-qualifiers to be applied to the reference type.
+///
+/// \param Loc The location of the entity whose type involves this
+/// reference type or, if there is no such entity, the location of the
+/// type that will have reference type.
+///
+/// \param Entity The name of the entity that involves the reference
+/// type, if known.
+///
+/// \returns A suitable reference type, if there are no
+/// errors. Otherwise, returns a NULL type.
+QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
+ SourceLocation Loc, DeclarationName Entity) {
+ if (LValueRef) {
+ if (const RValueReferenceType *R = T->getAsRValueReferenceType()) {
+ // C++0x [dcl.typedef]p9: If a typedef TD names a type that is a
+ // reference to a type T, and attempt to create the type "lvalue
+ // reference to cv TD" creates the type "lvalue reference to T".
+ // We use the qualifiers (restrict or none) of the original reference,
+ // not the new ones. This is consistent with GCC.
+ return Context.getLValueReferenceType(R->getPointeeType()).
+ getQualifiedType(T.getCVRQualifiers());
+ }
+ }
+ if (T->isReferenceType()) {
+ // C++ [dcl.ref]p4: There shall be no references to references.
+ //
+ // According to C++ DR 106, references to references are only
+ // diagnosed when they are written directly (e.g., "int & &"),
+ // but not when they happen via a typedef:
+ //
+ // typedef int& intref;
+ // typedef intref& intref2;
+ //
+ // Parser::ParserDeclaratorInternal diagnoses the case where
+ // references are written directly; here, we handle the
+ // collapsing of references-to-references as described in C++
+ // DR 106 and amended by C++ DR 540.
+ return T;
+ }
+
+ // C++ [dcl.ref]p1:
+ // A declarator that specifies the type “reference to cv voidâ€
+ // is ill-formed.
+ if (T->isVoidType()) {
+ Diag(Loc, diag::err_reference_to_void);
+ return QualType();
+ }
+
+ // Enforce C99 6.7.3p2: "Types other than pointer types derived from
+ // object or incomplete types shall not be restrict-qualified."
+ if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) {
+ Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
+ << T;
+ Quals &= ~QualType::Restrict;
+ }
+
+ // C++ [dcl.ref]p1:
+ // [...] Cv-qualified references are ill-formed except when the
+ // cv-qualifiers are introduced through the use of a typedef
+ // (7.1.3) or of a template type argument (14.3), in which case
+ // the cv-qualifiers are ignored.
+ //
+ // We diagnose extraneous cv-qualifiers for the non-typedef,
+ // non-template type argument case within the parser. Here, we just
+ // ignore any extraneous cv-qualifiers.
+ Quals &= ~QualType::Const;
+ Quals &= ~QualType::Volatile;
+
+ // Handle restrict on references.
+ if (LValueRef)
+ return Context.getLValueReferenceType(T).getQualifiedType(Quals);
+ return Context.getRValueReferenceType(T).getQualifiedType(Quals);
+}
+
+/// \brief Build an array type.
+///
+/// \param T The type of each element in the array.
+///
+/// \param ASM C99 array size modifier (e.g., '*', 'static').
+///
+/// \param ArraySize Expression describing the size of the array.
+///
+/// \param Quals The cvr-qualifiers to be applied to the array's
+/// element type.
+///
+/// \param Loc The location of the entity whose type involves this
+/// array type or, if there is no such entity, the location of the
+/// type that will have array type.
+///
+/// \param Entity The name of the entity that involves the array
+/// type, if known.
+///
+/// \returns A suitable array type, if there are no errors. Otherwise,
+/// returns a NULL type.
+QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
+ Expr *ArraySize, unsigned Quals,
+ SourceLocation Loc, DeclarationName Entity) {
+ // C99 6.7.5.2p1: If the element type is an incomplete or function type,
+ // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]())
+ if (RequireCompleteType(Loc, T,
+ diag::err_illegal_decl_array_incomplete_type))
+ return QualType();
+
+ if (T->isFunctionType()) {
+ Diag(Loc, diag::err_illegal_decl_array_of_functions)
+ << getPrintableNameForEntity(Entity);
+ return QualType();
+ }
+
+ // C++ 8.3.2p4: There shall be no ... arrays of references ...
+ if (T->isReferenceType()) {
+ Diag(Loc, diag::err_illegal_decl_array_of_references)
+ << getPrintableNameForEntity(Entity);
+ return QualType();
+ }
+
+ if (const RecordType *EltTy = T->getAsRecordType()) {
+ // If the element type is a struct or union that contains a variadic
+ // array, accept it as a GNU extension: C99 6.7.2.1p2.
+ if (EltTy->getDecl()->hasFlexibleArrayMember())
+ Diag(Loc, diag::ext_flexible_array_in_array) << T;
+ } else if (T->isObjCInterfaceType()) {
+ Diag(Loc, diag::err_objc_array_of_interfaces) << T;
+ return QualType();
+ }
+
+ // C99 6.7.5.2p1: The size expression shall have integer type.
+ if (ArraySize && !ArraySize->isTypeDependent() &&
+ !ArraySize->getType()->isIntegerType()) {
+ Diag(ArraySize->getLocStart(), diag::err_array_size_non_int)
+ << ArraySize->getType() << ArraySize->getSourceRange();
+ ArraySize->Destroy(Context);
+ return QualType();
+ }
+ llvm::APSInt ConstVal(32);
+ if (!ArraySize) {
+ if (ASM == ArrayType::Star)
+ T = Context.getVariableArrayType(T, 0, ASM, Quals);
+ else
+ T = Context.getIncompleteArrayType(T, ASM, Quals);
+ } else if (ArraySize->isValueDependent()) {
+ T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals);
+ } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) ||
+ (!T->isDependentType() && !T->isConstantSizeType())) {
+ // Per C99, a variable array is an array with either a non-constant
+ // size or an element type that has a non-constant-size
+ T = Context.getVariableArrayType(T, ArraySize, ASM, Quals);
+ } else {
+ // C99 6.7.5.2p1: If the expression is a constant expression, it shall
+ // have a value greater than zero.
+ if (ConstVal.isSigned()) {
+ if (ConstVal.isNegative()) {
+ Diag(ArraySize->getLocStart(),
+ diag::err_typecheck_negative_array_size)
+ << ArraySize->getSourceRange();
+ return QualType();
+ } else if (ConstVal == 0) {
+ // GCC accepts zero sized static arrays.
+ Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size)
+ << ArraySize->getSourceRange();
+ }
+ }
+ T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
+ }
+ // If this is not C99, extwarn about VLA's and C99 array size modifiers.
+ if (!getLangOptions().C99) {
+ if (ArraySize && !ArraySize->isTypeDependent() &&
+ !ArraySize->isValueDependent() &&
+ !ArraySize->isIntegerConstantExpr(Context))
+ Diag(Loc, diag::ext_vla);
+ else if (ASM != ArrayType::Normal || Quals != 0)
+ Diag(Loc, diag::ext_c99_array_usage);
+ }
+
+ return T;
+}
+
+/// \brief Build a function type.
+///
+/// This routine checks the function type according to C++ rules and
+/// under the assumption that the result type and parameter types have
+/// just been instantiated from a template. It therefore duplicates
+/// some of the behavior of GetTypeForDeclarator, but in a much
+/// simpler form that is only suitable for this narrow use case.
+///
+/// \param T The return type of the function.
+///
+/// \param ParamTypes The parameter types of the function. This array
+/// will be modified to account for adjustments to the types of the
+/// function parameters.
+///
+/// \param NumParamTypes The number of parameter types in ParamTypes.
+///
+/// \param Variadic Whether this is a variadic function type.
+///
+/// \param Quals The cvr-qualifiers to be applied to the function type.
+///
+/// \param Loc The location of the entity whose type involves this
+/// function type or, if there is no such entity, the location of the
+/// type that will have function type.
+///
+/// \param Entity The name of the entity that involves the function
+/// type, if known.
+///
+/// \returns A suitable function type, if there are no
+/// errors. Otherwise, returns a NULL type.
+QualType Sema::BuildFunctionType(QualType T,
+ QualType *ParamTypes,
+ unsigned NumParamTypes,
+ bool Variadic, unsigned Quals,
+ SourceLocation Loc, DeclarationName Entity) {
+ if (T->isArrayType() || T->isFunctionType()) {
+ Diag(Loc, diag::err_func_returning_array_function) << T;
+ return QualType();
+ }
+
+ bool Invalid = false;
+ for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) {
+ QualType ParamType = adjustParameterType(ParamTypes[Idx]);
+ if (ParamType->isVoidType()) {
+ Diag(Loc, diag::err_param_with_void_type);
+ Invalid = true;
+ }
+
+ ParamTypes[Idx] = ParamType;
+ }
+
+ if (Invalid)
+ return QualType();
+
+ return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic,
+ Quals);
+}
+
+/// GetTypeForDeclarator - Convert the type for the specified
+/// declarator to Type instances. Skip the outermost Skip type
+/// objects.
+///
+/// If OwnedDecl is non-NULL, and this declarator's decl-specifier-seq
+/// owns the declaration of a type (e.g., the definition of a struct
+/// type), then *OwnedDecl will receive the owned declaration.
+QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip,
+ TagDecl **OwnedDecl) {
+ bool OmittedReturnType = false;
+
+ if (D.getContext() == Declarator::BlockLiteralContext
+ && Skip == 0
+ && !D.getDeclSpec().hasTypeSpecifier()
+ && (D.getNumTypeObjects() == 0
+ || (D.getNumTypeObjects() == 1
+ && D.getTypeObject(0).Kind == DeclaratorChunk::Function)))
+ OmittedReturnType = true;
+
+ // long long is a C99 feature.
+ if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x &&
+ D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong)
+ Diag(D.getDeclSpec().getTypeSpecWidthLoc(), diag::ext_longlong);
+
+ // Determine the type of the declarator. Not all forms of declarator
+ // have a type.
+ QualType T;
+ switch (D.getKind()) {
+ case Declarator::DK_Abstract:
+ case Declarator::DK_Normal:
+ case Declarator::DK_Operator: {
+ const DeclSpec &DS = D.getDeclSpec();
+ if (OmittedReturnType) {
+ // We default to a dependent type initially. Can be modified by
+ // the first return statement.
+ T = Context.DependentTy;
+ } else {
+ bool isInvalid = false;
+ T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid);
+ if (isInvalid)
+ D.setInvalidType(true);
+ else if (OwnedDecl && DS.isTypeSpecOwned())
+ *OwnedDecl = cast<TagDecl>((Decl *)DS.getTypeRep());
+ }
+ break;
+ }
+
+ case Declarator::DK_Constructor:
+ case Declarator::DK_Destructor:
+ case Declarator::DK_Conversion:
+ // Constructors and destructors don't have return types. Use
+ // "void" instead. Conversion operators will check their return
+ // types separately.
+ T = Context.VoidTy;
+ break;
+ }
+
+ // The name we're declaring, if any.
+ DeclarationName Name;
+ if (D.getIdentifier())
+ Name = D.getIdentifier();
+
+ // Walk the DeclTypeInfo, building the recursive type as we go.
+ // DeclTypeInfos are ordered from the identifier out, which is
+ // opposite of what we want :).
+ for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) {
+ DeclaratorChunk &DeclType = D.getTypeObject(e-i-1+Skip);
+ switch (DeclType.Kind) {
+ default: assert(0 && "Unknown decltype!");
+ case DeclaratorChunk::BlockPointer:
+ // If blocks are disabled, emit an error.
+ if (!LangOpts.Blocks)
+ Diag(DeclType.Loc, diag::err_blocks_disable);
+
+ if (!T.getTypePtr()->isFunctionType())
+ Diag(D.getIdentifierLoc(), diag::err_nonfunction_block_type);
+ else
+ T = (Context.getBlockPointerType(T)
+ .getQualifiedType(DeclType.Cls.TypeQuals));
+ break;
+ case DeclaratorChunk::Pointer:
+ // Verify that we're not building a pointer to pointer to function with
+ // exception specification.
+ if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
+ Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
+ D.setInvalidType(true);
+ // Build the type anyway.
+ }
+ T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name);
+ break;
+ case DeclaratorChunk::Reference:
+ // Verify that we're not building a reference to pointer to function with
+ // exception specification.
+ if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
+ Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
+ D.setInvalidType(true);
+ // Build the type anyway.
+ }
+ T = BuildReferenceType(T, DeclType.Ref.LValueRef,
+ DeclType.Ref.HasRestrict ? QualType::Restrict : 0,
+ DeclType.Loc, Name);
+ break;
+ case DeclaratorChunk::Array: {
+ // Verify that we're not building an array of pointers to function with
+ // exception specification.
+ if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
+ Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
+ D.setInvalidType(true);
+ // Build the type anyway.
+ }
+ DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr;
+ Expr *ArraySize = static_cast<Expr*>(ATI.NumElts);
+ ArrayType::ArraySizeModifier ASM;
+ if (ATI.isStar)
+ ASM = ArrayType::Star;
+ else if (ATI.hasStatic)
+ ASM = ArrayType::Static;
+ else
+ ASM = ArrayType::Normal;
+ if (ASM == ArrayType::Star &&
+ D.getContext() != Declarator::PrototypeContext) {
+ // FIXME: This check isn't quite right: it allows star in prototypes
+ // for function definitions, and disallows some edge cases detailed
+ // in http://gcc.gnu.org/ml/gcc-patches/2009-02/msg00133.html
+ Diag(DeclType.Loc, diag::err_array_star_outside_prototype);
+ ASM = ArrayType::Normal;
+ D.setInvalidType(true);
+ }
+ T = BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, DeclType.Loc, Name);
+ break;
+ }
+ case DeclaratorChunk::Function: {
+ // If the function declarator has a prototype (i.e. it is not () and
+ // does not have a K&R-style identifier list), then the arguments are part
+ // of the type, otherwise the argument list is ().
+ const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+
+ // C99 6.7.5.3p1: The return type may not be a function or array type.
+ if (T->isArrayType() || T->isFunctionType()) {
+ Diag(DeclType.Loc, diag::err_func_returning_array_function) << T;
+ T = Context.IntTy;
+ D.setInvalidType(true);
+ }
+
+ if (getLangOptions().CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) {
+ // C++ [dcl.fct]p6:
+ // Types shall not be defined in return or parameter types.
+ TagDecl *Tag = cast<TagDecl>((Decl *)D.getDeclSpec().getTypeRep());
+ if (Tag->isDefinition())
+ Diag(Tag->getLocation(), diag::err_type_defined_in_result_type)
+ << Context.getTypeDeclType(Tag);
+ }
+
+ // Exception specs are not allowed in typedefs. Complain, but add it
+ // anyway.
+ if (FTI.hasExceptionSpec &&
+ D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
+ Diag(FTI.getThrowLoc(), diag::err_exception_spec_in_typedef);
+
+ if (FTI.NumArgs == 0) {
+ if (getLangOptions().CPlusPlus) {
+ // C++ 8.3.5p2: If the parameter-declaration-clause is empty, the
+ // function takes no arguments.
+ llvm::SmallVector<QualType, 4> Exceptions;
+ Exceptions.reserve(FTI.NumExceptions);
+ for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
+ QualType ET = QualType::getFromOpaquePtr(FTI.Exceptions[ei].Ty);
+ // Check that the type is valid for an exception spec, and drop it
+ // if not.
+ if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range))
+ Exceptions.push_back(ET);
+ }
+ T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, FTI.TypeQuals,
+ FTI.hasExceptionSpec,
+ FTI.hasAnyExceptionSpec,
+ Exceptions.size(), Exceptions.data());
+ } else if (FTI.isVariadic) {
+ // We allow a zero-parameter variadic function in C if the
+ // function is marked with the "overloadable"
+ // attribute. Scan for this attribute now.
+ bool Overloadable = false;
+ for (const AttributeList *Attrs = D.getAttributes();
+ Attrs; Attrs = Attrs->getNext()) {
+ if (Attrs->getKind() == AttributeList::AT_overloadable) {
+ Overloadable = true;
+ break;
+ }
+ }
+
+ if (!Overloadable)
+ Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg);
+ T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, 0);
+ } else {
+ // Simple void foo(), where the incoming T is the result type.
+ T = Context.getFunctionNoProtoType(T);
+ }
+ } else if (FTI.ArgInfo[0].Param == 0) {
+ // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function definition.
+ Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
+ } else {
+ // Otherwise, we have a function with an argument list that is
+ // potentially variadic.
+ llvm::SmallVector<QualType, 16> ArgTys;
+
+ for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
+ ParmVarDecl *Param =
+ cast<ParmVarDecl>(FTI.ArgInfo[i].Param.getAs<Decl>());
+ QualType ArgTy = Param->getType();
+ assert(!ArgTy.isNull() && "Couldn't parse type?");
+
+ // Adjust the parameter type.
+ assert((ArgTy == adjustParameterType(ArgTy)) && "Unadjusted type?");
+
+ // Look for 'void'. void is allowed only as a single argument to a
+ // function with no other parameters (C99 6.7.5.3p10). We record
+ // int(void) as a FunctionProtoType with an empty argument list.
+ if (ArgTy->isVoidType()) {
+ // If this is something like 'float(int, void)', reject it. 'void'
+ // is an incomplete type (C99 6.2.5p19) and function decls cannot
+ // have arguments of incomplete type.
+ if (FTI.NumArgs != 1 || FTI.isVariadic) {
+ Diag(DeclType.Loc, diag::err_void_only_param);
+ ArgTy = Context.IntTy;
+ Param->setType(ArgTy);
+ } else if (FTI.ArgInfo[i].Ident) {
+ // Reject, but continue to parse 'int(void abc)'.
+ Diag(FTI.ArgInfo[i].IdentLoc,
+ diag::err_param_with_void_type);
+ ArgTy = Context.IntTy;
+ Param->setType(ArgTy);
+ } else {
+ // Reject, but continue to parse 'float(const void)'.
+ if (ArgTy.getCVRQualifiers())
+ Diag(DeclType.Loc, diag::err_void_param_qualified);
+
+ // Do not add 'void' to the ArgTys list.
+ break;
+ }
+ } else if (!FTI.hasPrototype) {
+ if (ArgTy->isPromotableIntegerType()) {
+ ArgTy = Context.IntTy;
+ } else if (const BuiltinType* BTy = ArgTy->getAsBuiltinType()) {
+ if (BTy->getKind() == BuiltinType::Float)
+ ArgTy = Context.DoubleTy;
+ }
+ }
+
+ ArgTys.push_back(ArgTy);
+ }
+
+ llvm::SmallVector<QualType, 4> Exceptions;
+ Exceptions.reserve(FTI.NumExceptions);
+ for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
+ QualType ET = QualType::getFromOpaquePtr(FTI.Exceptions[ei].Ty);
+ // Check that the type is valid for an exception spec, and drop it if
+ // not.
+ if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range))
+ Exceptions.push_back(ET);
+ }
+
+ T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(),
+ FTI.isVariadic, FTI.TypeQuals,
+ FTI.hasExceptionSpec,
+ FTI.hasAnyExceptionSpec,
+ Exceptions.size(), Exceptions.data());
+ }
+ break;
+ }
+ case DeclaratorChunk::MemberPointer:
+ // Verify that we're not building a pointer to pointer to function with
+ // exception specification.
+ if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
+ Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
+ D.setInvalidType(true);
+ // Build the type anyway.
+ }
+ // The scope spec must refer to a class, or be dependent.
+ DeclContext *DC = computeDeclContext(DeclType.Mem.Scope());
+ QualType ClsType;
+ // FIXME: Extend for dependent types when it's actually supported.
+ // See ActOnCXXNestedNameSpecifier.
+ if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC)) {
+ ClsType = Context.getTagDeclType(RD);
+ } else {
+ if (DC) {
+ Diag(DeclType.Mem.Scope().getBeginLoc(),
+ diag::err_illegal_decl_mempointer_in_nonclass)
+ << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name")
+ << DeclType.Mem.Scope().getRange();
+ }
+ D.setInvalidType(true);
+ ClsType = Context.IntTy;
+ }
+
+ // C++ 8.3.3p3: A pointer to member shall not pointer to ... a member
+ // with reference type, or "cv void."
+ if (T->isReferenceType()) {
+ Diag(DeclType.Loc, diag::err_illegal_decl_pointer_to_reference)
+ << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
+ D.setInvalidType(true);
+ T = Context.IntTy;
+ }
+ if (T->isVoidType()) {
+ Diag(DeclType.Loc, diag::err_illegal_decl_mempointer_to_void)
+ << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
+ T = Context.IntTy;
+ }
+
+ // Enforce C99 6.7.3p2: "Types other than pointer types derived from
+ // object or incomplete types shall not be restrict-qualified."
+ if ((DeclType.Mem.TypeQuals & QualType::Restrict) &&
+ !T->isIncompleteOrObjectType()) {
+ Diag(DeclType.Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
+ << T;
+ DeclType.Mem.TypeQuals &= ~QualType::Restrict;
+ }
+
+ T = Context.getMemberPointerType(T, ClsType.getTypePtr()).
+ getQualifiedType(DeclType.Mem.TypeQuals);
+
+ break;
+ }
+
+ if (T.isNull()) {
+ D.setInvalidType(true);
+ T = Context.IntTy;
+ }
+
+ // See if there are any attributes on this declarator chunk.
+ if (const AttributeList *AL = DeclType.getAttrs())
+ ProcessTypeAttributeList(T, AL);
+ }
+
+ if (getLangOptions().CPlusPlus && T->isFunctionType()) {
+ const FunctionProtoType *FnTy = T->getAsFunctionProtoType();
+ assert(FnTy && "Why oh why is there not a FunctionProtoType here ?");
+
+ // C++ 8.3.5p4: A cv-qualifier-seq shall only be part of the function type
+ // for a nonstatic member function, the function type to which a pointer
+ // to member refers, or the top-level function type of a function typedef
+ // declaration.
+ if (FnTy->getTypeQuals() != 0 &&
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
+ ((D.getContext() != Declarator::MemberContext &&
+ (!D.getCXXScopeSpec().isSet() ||
+ !computeDeclContext(D.getCXXScopeSpec())->isRecord())) ||
+ D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) {
+ if (D.isFunctionDeclarator())
+ Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type);
+ else
+ Diag(D.getIdentifierLoc(),
+ diag::err_invalid_qualified_typedef_function_type_use);
+
+ // Strip the cv-quals from the type.
+ T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(),
+ FnTy->getNumArgs(), FnTy->isVariadic(), 0);
+ }
+ }
+
+ // If there were any type attributes applied to the decl itself (not the
+ // type, apply the type attribute to the type!)
+ if (const AttributeList *Attrs = D.getAttributes())
+ ProcessTypeAttributeList(T, Attrs);
+
+ return T;
+}
+
+/// CheckSpecifiedExceptionType - Check if the given type is valid in an
+/// exception specification. Incomplete types, or pointers to incomplete types
+/// other than void are not allowed.
+bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
+ // FIXME: This may not correctly work with the fix for core issue 437,
+ // where a class's own type is considered complete within its body.
+
+ // C++ 15.4p2: A type denoted in an exception-specification shall not denote
+ // an incomplete type.
+ if (T->isIncompleteType())
+ return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec)
+ << Range << T << /*direct*/0;
+
+ // C++ 15.4p2: A type denoted in an exception-specification shall not denote
+ // an incomplete type a pointer or reference to an incomplete type, other
+ // than (cv) void*.
+ int kind;
+ if (const PointerType* IT = T->getAsPointerType()) {
+ T = IT->getPointeeType();
+ kind = 1;
+ } else if (const ReferenceType* IT = T->getAsReferenceType()) {
+ T = IT->getPointeeType();
+ kind = 2;
+ } else
+ return false;
+
+ if (T->isIncompleteType() && !T->isVoidType())
+ return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec)
+ << Range << T << /*indirect*/kind;
+
+ return false;
+}
+
+/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
+/// to member to a function with an exception specification. This means that
+/// it is invalid to add another level of indirection.
+bool Sema::CheckDistantExceptionSpec(QualType T) {
+ if (const PointerType *PT = T->getAsPointerType())
+ T = PT->getPointeeType();
+ else if (const MemberPointerType *PT = T->getAsMemberPointerType())
+ T = PT->getPointeeType();
+ else
+ return false;
+
+ const FunctionProtoType *FnT = T->getAsFunctionProtoType();
+ if (!FnT)
+ return false;
+
+ return FnT->hasExceptionSpec();
+}
+
+/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition
+/// declarator
+QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) {
+ ObjCMethodDecl *MDecl = cast<ObjCMethodDecl>(D.getAs<Decl>());
+ QualType T = MDecl->getResultType();
+ llvm::SmallVector<QualType, 16> ArgTys;
+
+ // Add the first two invisible argument types for self and _cmd.
+ if (MDecl->isInstanceMethod()) {
+ QualType selfTy = Context.getObjCInterfaceType(MDecl->getClassInterface());
+ selfTy = Context.getPointerType(selfTy);
+ ArgTys.push_back(selfTy);
+ } else
+ ArgTys.push_back(Context.getObjCIdType());
+ ArgTys.push_back(Context.getObjCSelType());
+
+ for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(),
+ E = MDecl->param_end(); PI != E; ++PI) {
+ QualType ArgTy = (*PI)->getType();
+ assert(!ArgTy.isNull() && "Couldn't parse type?");
+ ArgTy = adjustParameterType(ArgTy);
+ ArgTys.push_back(ArgTy);
+ }
+ T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(),
+ MDecl->isVariadic(), 0);
+ return T;
+}
+
+/// UnwrapSimilarPointerTypes - If T1 and T2 are pointer types that
+/// may be similar (C++ 4.4), replaces T1 and T2 with the type that
+/// they point to and return true. If T1 and T2 aren't pointer types
+/// or pointer-to-member types, or if they are not similar at this
+/// level, returns false and leaves T1 and T2 unchanged. Top-level
+/// qualifiers on T1 and T2 are ignored. This function will typically
+/// be called in a loop that successively "unwraps" pointer and
+/// pointer-to-member types to compare them at each level.
+bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2) {
+ const PointerType *T1PtrType = T1->getAsPointerType(),
+ *T2PtrType = T2->getAsPointerType();
+ if (T1PtrType && T2PtrType) {
+ T1 = T1PtrType->getPointeeType();
+ T2 = T2PtrType->getPointeeType();
+ return true;
+ }
+
+ const MemberPointerType *T1MPType = T1->getAsMemberPointerType(),
+ *T2MPType = T2->getAsMemberPointerType();
+ if (T1MPType && T2MPType &&
+ Context.getCanonicalType(T1MPType->getClass()) ==
+ Context.getCanonicalType(T2MPType->getClass())) {
+ T1 = T1MPType->getPointeeType();
+ T2 = T2MPType->getPointeeType();
+ return true;
+ }
+ return false;
+}
+
+Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
+ // C99 6.7.6: Type names have no identifier. This is already validated by
+ // the parser.
+ assert(D.getIdentifier() == 0 && "Type name should have no identifier!");
+
+ TagDecl *OwnedTag = 0;
+ QualType T = GetTypeForDeclarator(D, S, /*Skip=*/0, &OwnedTag);
+ if (D.isInvalidType())
+ return true;
+
+ if (getLangOptions().CPlusPlus) {
+ // Check that there are no default arguments (C++ only).
+ CheckExtraCXXDefaultArguments(D);
+
+ // C++0x [dcl.type]p3:
+ // A type-specifier-seq shall not define a class or enumeration
+ // unless it appears in the type-id of an alias-declaration
+ // (7.1.3).
+ if (OwnedTag && OwnedTag->isDefinition())
+ Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier)
+ << Context.getTypeDeclType(OwnedTag);
+ }
+
+ return T.getAsOpaquePtr();
+}
+
+
+
+//===----------------------------------------------------------------------===//
+// Type Attribute Processing
+//===----------------------------------------------------------------------===//
+
+/// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the
+/// specified type. The attribute contains 1 argument, the id of the address
+/// space for the type.
+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."
+ if (Type.getAddressSpace()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers);
+ return;
+ }
+
+ // Check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+ Expr *ASArgExpr = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt addrSpace(32);
+ if (!ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_address_space_not_int)
+ << ASArgExpr->getSourceRange();
+ return;
+ }
+
+ unsigned ASIdx = static_cast<unsigned>(addrSpace.getZExtValue());
+ Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
+}
+
+/// HandleObjCGCTypeAttribute - Process an objc's gc attribute on the
+/// specified type. The attribute contains 1 argument, weak or strong.
+static void HandleObjCGCTypeAttribute(QualType &Type,
+ const AttributeList &Attr, Sema &S) {
+ if (Type.getObjCGCAttr() != QualType::GCNone) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_multiple_objc_gc);
+ return;
+ }
+
+ // Check the attribute arguments.
+ if (!Attr.getParameterName()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ << "objc_gc" << 1;
+ return;
+ }
+ QualType::GCAttrTypes GCAttr;
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+ if (Attr.getParameterName()->isStr("weak"))
+ GCAttr = QualType::Weak;
+ else if (Attr.getParameterName()->isStr("strong"))
+ GCAttr = QualType::Strong;
+ else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
+ << "objc_gc" << Attr.getParameterName();
+ return;
+ }
+
+ Type = S.Context.getObjCGCQualType(Type, GCAttr);
+}
+
+void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
+ // Scan through and apply attributes to this type where it makes sense. Some
+ // attributes (such as __address_space__, __vector_size__, etc) apply to the
+ // type, but others can be present in the type specifiers even though they
+ // apply to the decl. Here we apply type attributes and ignore the rest.
+ for (; AL; AL = AL->getNext()) {
+ // If this is an attribute we can handle, do so now, otherwise, add it to
+ // the LeftOverAttrs list for rechaining.
+ switch (AL->getKind()) {
+ default: break;
+ case AttributeList::AT_address_space:
+ HandleAddressSpaceTypeAttribute(Result, *AL, *this);
+ break;
+ case AttributeList::AT_objc_gc:
+ HandleObjCGCTypeAttribute(Result, *AL, *this);
+ break;
+ }
+ }
+}
+
+/// @brief Ensure that the type T is a complete type.
+///
+/// This routine checks whether the type @p T is complete in any
+/// context where a complete type is required. If @p T is a complete
+/// type, returns false. If @p T is a class template specialization,
+/// this routine then attempts to perform class template
+/// instantiation. If instantiation fails, or if @p T is incomplete
+/// and cannot be completed, issues the diagnostic @p diag (giving it
+/// the type @p T) and returns true.
+///
+/// @param Loc The location in the source that the incomplete type
+/// diagnostic should refer to.
+///
+/// @param T The type that this routine is examining for completeness.
+///
+/// @param diag The diagnostic value (e.g.,
+/// @c diag::err_typecheck_decl_incomplete_type) that will be used
+/// for the error message if @p T is incomplete.
+///
+/// @param Range1 An optional range in the source code that will be a
+/// part of the "incomplete type" error message.
+///
+/// @param Range2 An optional range in the source code that will be a
+/// part of the "incomplete type" error message.
+///
+/// @param PrintType If non-NULL, the type that should be printed
+/// instead of @p T. This parameter should be used when the type that
+/// we're checking for incompleteness isn't the type that should be
+/// displayed to the user, e.g., when T is a type and PrintType is a
+/// pointer to T.
+///
+/// @returns @c true if @p T is incomplete and a diagnostic was emitted,
+/// @c false otherwise.
+bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
+ SourceRange Range1, SourceRange Range2,
+ QualType PrintType) {
+ // FIXME: Add this assertion to help us flush out problems with
+ // checking for dependent types and type-dependent expressions.
+ //
+ // assert(!T->isDependentType() &&
+ // "Can't ask whether a dependent type is complete");
+
+ // If we have a complete type, we're done.
+ if (!T->isIncompleteType())
+ return false;
+
+ // If we have a class template specialization or a class member of a
+ // class template specialization, try to instantiate it.
+ if (const RecordType *Record = T->getAsRecordType()) {
+ if (ClassTemplateSpecializationDecl *ClassTemplateSpec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) {
+ if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) {
+ // Update the class template specialization's location to
+ // refer to the point of instantiation.
+ if (Loc.isValid())
+ ClassTemplateSpec->setLocation(Loc);
+ return InstantiateClassTemplateSpecialization(ClassTemplateSpec,
+ /*ExplicitInstantiation=*/false);
+ }
+ } else if (CXXRecordDecl *Rec
+ = dyn_cast<CXXRecordDecl>(Record->getDecl())) {
+ if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) {
+ // Find the class template specialization that surrounds this
+ // member class.
+ ClassTemplateSpecializationDecl *Spec = 0;
+ for (DeclContext *Parent = Rec->getDeclContext();
+ Parent && !Spec; Parent = Parent->getParent())
+ Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent);
+ assert(Spec && "Not a member of a class template specialization?");
+ return InstantiateClass(Loc, Rec, Pattern, Spec->getTemplateArgs(),
+ /*ExplicitInstantiation=*/false);
+ }
+ }
+ }
+
+ if (PrintType.isNull())
+ PrintType = T;
+
+ // We have an incomplete type. Produce a diagnostic.
+ Diag(Loc, diag) << PrintType << Range1 << Range2;
+
+ // If the type was a forward declaration of a class/struct/union
+ // type, produce
+ const TagType *Tag = 0;
+ if (const RecordType *Record = T->getAsRecordType())
+ Tag = Record;
+ else if (const EnumType *Enum = T->getAsEnumType())
+ Tag = Enum;
+
+ if (Tag && !Tag->getDecl()->isInvalidDecl())
+ Diag(Tag->getDecl()->getLocation(),
+ Tag->isBeingDefined() ? diag::note_type_being_defined
+ : diag::note_forward_declaration)
+ << QualType(Tag, 0);
+
+ return true;
+}
+
+/// \brief Retrieve a version of the type 'T' that is qualified by the
+/// nested-name-specifier contained in SS.
+QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) {
+ if (!SS.isSet() || SS.isInvalid() || T.isNull())
+ return T;
+
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ return Context.getQualifiedNameType(NNS, T);
+}
diff --git a/test/Analysis/CFDateGC.m b/test/Analysis/CFDateGC.m
new file mode 100644
index 000000000000..dfc736627bfc
--- /dev/null
+++ b/test/Analysis/CFDateGC.m
@@ -0,0 +1,87 @@
+// RUN: clang-cc -analyze -checker-cfref -verify -fobjc-gc -analyzer-constraints=basic %s &&
+// RUN: clang-cc -analyze -checker-cfref -verify -fobjc-gc -analyzer-constraints=range %s &&
+// RUN: clang-cc -analyze -checker-cfref -verify -fobjc-gc -disable-free %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fobjc-gc %s
+
+//===----------------------------------------------------------------------===//
+// The following code is reduced using delta-debugging from
+// Foundation.h and CoreFoundation.h (Mac OS X).
+//
+// It includes the basic definitions for the test cases below.
+// Not directly including [Core]Foundation.h directly makes this test case
+// both svelte and portable to non-Mac platforms.
+//===----------------------------------------------------------------------===//
+
+typedef const void * CFTypeRef;
+void CFRelease(CFTypeRef cf);
+CFTypeRef CFRetain(CFTypeRef cf);
+CFTypeRef CFMakeCollectable(CFTypeRef cf);
+typedef const struct __CFAllocator * CFAllocatorRef;
+typedef double CFTimeInterval;
+typedef CFTimeInterval CFAbsoluteTime;
+typedef const struct __CFDate * CFDateRef;
+extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at);
+extern CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate);
+typedef struct objc_object {} *id;
+typedef signed char BOOL;
+static __inline__ __attribute__((always_inline)) id NSMakeCollectable(CFTypeRef cf) {}
+@protocol NSObject - (BOOL)isEqual:(id)object;
+- (oneway void)release;
+- (id)retain;
+@end
+@class NSArray;
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+CFAbsoluteTime f1_use_after_release() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ CFRetain(date);
+ [NSMakeCollectable(date) release];
+ CFDateGetAbsoluteTime(date); // no-warning
+ CFRelease(date);
+ t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}}
+ return t;
+}
+
+// The following two test cases verifies that CFMakeCollectable is a no-op
+// in non-GC mode and a "release" in GC mode.
+CFAbsoluteTime f2_use_after_release() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ CFRetain(date);
+ [(id) CFMakeCollectable(date) release];
+ CFDateGetAbsoluteTime(date); // no-warning
+ CFRelease(date);
+ t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}}
+ return t;
+}
+
+CFAbsoluteTime f2_noleak() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ CFRetain(date);
+ [(id) CFMakeCollectable(date) release];
+ CFDateGetAbsoluteTime(date); // no-warning
+ t = CFDateGetAbsoluteTime(date); // no-warning
+ CFRelease(date); // no-warning
+ return t;
+}
+
+void f3_leak_with_gc() {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); // expected-warning 2 {{leak}}
+ [[(id) date retain] release];
+}
+
+// The following test case verifies that we "stop tracking" a retained object
+// when it is passed as an argument to an implicitly defined function.
+CFAbsoluteTime f4() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ CFRetain(date);
+ some_implicitly_defined_function_stop_tracking(date); // no-warning
+ return t;
+}
diff --git a/test/Analysis/CFNumber.c b/test/Analysis/CFNumber.c
new file mode 100644
index 000000000000..f62d2ab569d4
--- /dev/null
+++ b/test/Analysis/CFNumber.c
@@ -0,0 +1,31 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
+
+typedef signed long CFIndex;
+typedef const struct __CFAllocator * CFAllocatorRef;
+enum { kCFNumberSInt8Type = 1, kCFNumberSInt16Type = 2,
+ kCFNumberSInt32Type = 3, kCFNumberSInt64Type = 4,
+ kCFNumberFloat32Type = 5, kCFNumberFloat64Type = 6,
+ kCFNumberCharType = 7, kCFNumberShortType = 8,
+ kCFNumberIntType = 9, kCFNumberLongType = 10,
+ kCFNumberLongLongType = 11, kCFNumberFloatType = 12,
+ kCFNumberDoubleType = 13, kCFNumberCFIndexType = 14,
+ kCFNumberNSIntegerType = 15, kCFNumberCGFloatType = 16,
+ kCFNumberMaxType = 16 };
+typedef CFIndex CFNumberType;
+typedef const struct __CFNumber * CFNumberRef;
+extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr);
+
+CFNumberRef f1(unsigned char x) {
+ return CFNumberCreate(0, kCFNumberSInt16Type, &x); // expected-warning{{An 8 bit integer is used to initialize a CFNumber object that represents a 16 bit integer. 8 bits of the CFNumber value will be garbage.}}
+}
+
+CFNumberRef f2(unsigned short x) {
+ return CFNumberCreate(0, kCFNumberSInt8Type, &x); // expected-warning{{A 16 bit integer is used to initialize a CFNumber object that represents an 8 bit integer. 8 bits of the input integer will be lost.}}
+}
+
+CFNumberRef f3(unsigned i) {
+ return CFNumberCreate(0, kCFNumberLongType, &i); // expected-warning{{A 32 bit integer is used to initialize a CFNumber object that represents a 64 bit integer.}}
+}
diff --git a/test/Analysis/CFRetainRelease_NSAssertionHandler.m b/test/Analysis/CFRetainRelease_NSAssertionHandler.m
new file mode 100644
index 000000000000..1ff950725c02
--- /dev/null
+++ b/test/Analysis/CFRetainRelease_NSAssertionHandler.m
@@ -0,0 +1,67 @@
+// RUN: clang-cc -analyze -checker-cfref -verify %s -analyzer-constraints=basic -analyzer-store=basic &&
+// RUN: clang-cc -analyze -checker-cfref -verify %s -analyzer-constraints=range -analyzer-store=basic &&
+// RUN: clang-cc -analyze -checker-cfref -verify %s -analyzer-constraints=basic -analyzer-store=region &&
+// RUN: clang-cc -analyze -checker-cfref -verify %s -analyzer-constraints=range -analyzer-store=region
+
+typedef struct objc_selector *SEL;
+typedef signed char BOOL;
+typedef int NSInteger;
+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 NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
+@interface NSObject <NSObject> {} - (id)init; @end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
++ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
+@end extern NSString * const NSBundleDidLoadNotification;
+@interface NSAssertionHandler : NSObject {}
++ (NSAssertionHandler *)currentHandler;
+- (void)handleFailureInMethod:(SEL)selector object:(id)object file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format,...;
+@end
+extern NSString * const NSConnectionReplyMode;
+
+//----------------------------------------------------------------------------//
+// The following test case was filed in PR 2593:
+// http://llvm.org/bugs/show_bug.cgi?id=2593
+//
+// There should be no null dereference flagged by the checker because of
+// NSParameterAssert and NSAssert.
+
+
+@interface TestAssert : NSObject {}
+@end
+
+@implementation TestAssert
+
+- (id)initWithPointer: (int*)x
+{
+ // Expansion of: NSParameterAssert( x != 0 );
+ do { if (!((x != 0))) { [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd object:self file:[NSString stringWithUTF8String:"CFRetainRelease_NSAssertionHandler.m"] lineNumber:21 description:(@"Invalid parameter not satisfying: %s"), ("x != 0"), (0), (0), (0), (0)]; } } while(0);
+
+ if( (self = [super init]) != 0 )
+ {
+ *x = 1; // no-warning
+ }
+
+ return self;
+}
+
+- (id)initWithPointer2: (int*)x
+{
+ // Expansion of: NSAssert( x != 0, @"" );
+ do { if (!((x != 0))) { [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd object:self file:[NSString stringWithUTF8String:"CFRetainRelease_NSAssertionHandler.m"] lineNumber:33 description:((@"")), (0), (0), (0), (0), (0)]; } } while(0);
+
+ if( (self = [super init]) != 0 )
+ {
+ *x = 1; // no-warning
+ }
+
+ return self;
+}
+
+@end
diff --git a/test/Analysis/CGColorSpace.c b/test/Analysis/CGColorSpace.c
new file mode 100644
index 000000000000..2887d47c5118
--- /dev/null
+++ b/test/Analysis/CGColorSpace.c
@@ -0,0 +1,21 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+
+typedef struct CGColorSpace *CGColorSpaceRef;
+extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
+extern CGColorSpaceRef CGColorSpaceRetain(CGColorSpaceRef space);
+extern void CGColorSpaceRelease(CGColorSpaceRef space);
+
+void f() {
+ CGColorSpaceRef X = CGColorSpaceCreateDeviceRGB(); // expected-warning{{leak}}
+ CGColorSpaceRetain(X);
+}
+
+void fb() {
+ CGColorSpaceRef X = CGColorSpaceCreateDeviceRGB();
+ CGColorSpaceRetain(X);
+ CGColorSpaceRelease(X);
+ CGColorSpaceRelease(X); // no-warning
+}
diff --git a/test/Analysis/CheckNSError.m b/test/Analysis/CheckNSError.m
new file mode 100644
index 000000000000..779b865aff8c
--- /dev/null
+++ b/test/Analysis/CheckNSError.m
@@ -0,0 +1,59 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+
+
+typedef signed char BOOL;
+typedef int NSInteger;
+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
+@interface NSObject <NSObject> {} @end
+@class NSDictionary;
+@interface NSError : NSObject <NSCopying, NSCoding> {}
++ (id)errorWithDomain:(NSString *)domain code:(NSInteger)code userInfo:(NSDictionary *)dict;
+@end
+extern NSString * const NSXMLParserErrorDomain ;
+
+@interface A
+- (void)myMethodWhichMayFail:(NSError **)error;
+- (BOOL)myMethodWhichMayFail2:(NSError **)error;
+@end
+
+@implementation A
+- (void)myMethodWhichMayFail:(NSError **)error { // expected-warning {{Method accepting NSError** should have a non-void return value to indicate whether or not an error occured.}}
+ *error = [NSError errorWithDomain:@"domain" code:1 userInfo:0]; // expected-warning {{Potential null dereference.}}
+}
+
+- (BOOL)myMethodWhichMayFail2:(NSError **)error { // no-warning
+ if (error) *error = [NSError errorWithDomain:@"domain" code:1 userInfo:0]; // no-warning
+ return 0;
+}
+@end
+
+struct __CFError {};
+typedef struct __CFError* CFErrorRef;
+
+void foo(CFErrorRef* error) { // expected-warning {{Function accepting CFErrorRef* should have a non-void return value to indicate whether or not an error occured.}}
+ *error = 0; // expected-warning {{Potential null dereference.}}
+}
+
+int f1(CFErrorRef* error) {
+ if (error) *error = 0; // no-warning
+ return 0;
+}
+
+int f2(CFErrorRef* error) {
+ if (0 != error) *error = 0; // no-warning
+ return 0;
+}
+
+int f3(CFErrorRef* error) {
+ if (error != 0) *error = 0; // no-warning
+ return 0;
+}
+
+
diff --git a/test/Analysis/MissingDealloc.m b/test/Analysis/MissingDealloc.m
new file mode 100644
index 000000000000..41498e56ec1d
--- /dev/null
+++ b/test/Analysis/MissingDealloc.m
@@ -0,0 +1,117 @@
+// RUN: clang-cc -analyze -warn-objc-missing-dealloc '-DIBOutlet=__attribute__((iboutlet))' %s --verify
+typedef signed char BOOL;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (Class)class;
+@end
+
+@interface NSObject <NSObject> {}
+- (void)dealloc;
+- (id)init;
+@end
+
+typedef struct objc_selector *SEL;
+
+// <rdar://problem/6380411>: 'myproperty' has kind 'assign' and thus the
+// assignment through the setter does not perform a release.
+
+@interface MyObject : NSObject {
+ id _myproperty;
+}
+@property(assign) id myproperty;
+@end
+
+@implementation MyObject
+@synthesize myproperty=_myproperty; // no-warning
+- (void)dealloc {
+ self.myproperty = 0;
+ [super dealloc];
+}
+@end
+
+//===------------------------------------------------------------------------===
+// Don't warn about iVars that are selectors.
+
+@interface TestSELs : NSObject {
+ SEL a;
+ SEL b;
+}
+
+@end
+
+@implementation TestSELs // no-warning
+- (id)init {
+ if( (self = [super init]) ) {
+ a = @selector(a);
+ b = @selector(b);
+ }
+
+ return self;
+}
+@end
+
+//===------------------------------------------------------------------------===
+// Don't warn about iVars that are IBOutlets.
+
+#ifndef IBOutlet
+#define IBOutlet
+#endif
+
+@class NSWindow;
+
+@interface HasOutlet : NSObject {
+IBOutlet NSWindow *window;
+}
+@end
+
+@implementation HasOutlet // no-warning
+@end
+
+//===------------------------------------------------------------------------===
+// <rdar://problem/6380411>
+// Was bogus warning: "The '_myproperty' instance variable was not retained by a
+// synthesized property but was released in 'dealloc'"
+
+@interface MyObject_rdar6380411 : NSObject {
+ id _myproperty;
+}
+@property(assign) id myproperty;
+@end
+
+@implementation MyObject_rdar6380411
+@synthesize myproperty=_myproperty;
+- (void)dealloc {
+ // Don't claim that myproperty is released since it the property
+ // has the 'assign' attribute.
+ self.myproperty = 0; // no-warning
+ [super dealloc];
+}
+@end
+
+//===------------------------------------------------------------------------===
+// PR 3187: http://llvm.org/bugs/show_bug.cgi?id=3187
+// - Disable the missing -dealloc check for classes that subclass SenTestCase
+
+@class NSString;
+
+@interface SenTestCase : NSObject {}
+@end
+
+@interface MyClassTest : SenTestCase {
+ NSString *resourcePath;
+}
+@end
+
+@interface NSBundle : NSObject {}
++ (NSBundle *)bundleForClass:(Class)aClass;
+- (NSString *)resourcePath;
+@end
+
+@implementation MyClassTest
+- (void)setUp {
+ resourcePath = [[NSBundle bundleForClass:[self class]] resourcePath];
+}
+- (void)testXXX {
+ // do something which uses resourcepath
+}
+@end
diff --git a/test/Analysis/NSPanel.m b/test/Analysis/NSPanel.m
new file mode 100644
index 000000000000..c4d4c22540f2
--- /dev/null
+++ b/test/Analysis/NSPanel.m
@@ -0,0 +1,90 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+
+// BEGIN delta-debugging reduced header stuff
+
+typedef struct objc_selector *SEL;
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (oneway void)release;
+@end
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end
+@protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+@protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
++ (id)alloc;
+@end
+typedef float CGFloat;
+typedef struct _NSPoint {} NSRect;
+static __inline__ __attribute__((always_inline)) NSRect NSMakeRect(CGFloat x, CGFloat y, CGFloat w, CGFloat h) {}
+typedef struct {} NSFastEnumerationState;
+@protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end
+@class NSString;
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+@end
+@interface NSMutableArray : NSArray
+- (void)addObject:(id)anObject;
+@end @class NSAppleEventDescriptor;
+enum { NSBackingStoreRetained = 0, NSBackingStoreNonretained = 1, NSBackingStoreBuffered = 2 };
+typedef NSUInteger NSBackingStoreType;
+@interface NSResponder : NSObject <NSCoding> {} @end
+@protocol NSAnimatablePropertyContainer
+- (id)animator;
+@end
+@protocol NSValidatedUserInterfaceItem
+- (SEL)action;
+@end
+@protocol NSUserInterfaceValidations
+- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem;
+@end @class NSDate, NSDictionary, NSError, NSException, NSNotification;
+enum { NSBorderlessWindowMask = 0, NSTitledWindowMask = 1 << 0, NSClosableWindowMask = 1 << 1, NSMiniaturizableWindowMask = 1 << 2, NSResizableWindowMask = 1 << 3 };
+@interface NSWindow : NSResponder <NSAnimatablePropertyContainer, NSUserInterfaceValidations> {}
+- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag;
+@end
+extern NSString *NSWindowDidBecomeKeyNotification;
+@interface NSPanel : NSWindow {}
+@end
+@class NSTableHeaderView;
+
+// END delta-debugging reduced header stuff
+
+@interface MyClass
+{
+ NSMutableArray *panels;
+}
+- (void)myMethod;
+- (void)myMethod2;
+@end
+
+@implementation MyClass // no-warning
+- (void)myMethod
+{
+ NSPanel *panel = [[NSPanel alloc] initWithContentRect:NSMakeRect(0, 0, 200, 200) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:(BOOL)1];
+
+ [panels addObject:panel];
+
+ [panel release]; // no-warning
+}
+- (void)myMethod2
+{
+ NSPanel *panel = [[NSPanel alloc] initWithContentRect:NSMakeRect(0, 0, 200, 200) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:(BOOL)1]; // no-warning
+
+ [panels addObject:panel];
+}
+@end
+
diff --git a/test/Analysis/NSString.m b/test/Analysis/NSString.m
new file mode 100644
index 000000000000..b707071990f8
--- /dev/null
+++ b/test/Analysis/NSString.m
@@ -0,0 +1,335 @@
+// RUN: clang-cc -triple i386-pc-linux-gnu -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -triple i386-pc-linux-gnu -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s
+
+
+// NOTWORK: clang-cc -triple i386-pc-linux-gnu -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s &&
+// NOTWORK: clang-cc -triple i386-pc-linux-gnu -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -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 directly including Foundation.h directly makes this test case
+// both svelte and portable to non-Mac platforms.
+//===----------------------------------------------------------------------===//
+
+typedef int int32_t;
+typedef const void * CFTypeRef;
+typedef const struct __CFString * CFStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+void CFRelease(CFTypeRef cf);
+typedef const struct __CFDictionary * CFDictionaryRef;
+const void *CFDictionaryGetValue(CFDictionaryRef theDict, const void *key);
+extern CFStringRef CFStringCreateWithFormat(CFAllocatorRef alloc, CFDictionaryRef formatOptions, CFStringRef format, ...);
+typedef signed char BOOL;
+typedef int NSInteger;
+typedef unsigned int NSUInteger;
+@class NSString, Protocol;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+typedef NSInteger NSComparisonResult;
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (oneway void)release;
+- (id)retain;
+- (id)autorelease;
+@end
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end
+@protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+@protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
+- (id)init;
++ (id)alloc;
+@end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+typedef struct {} NSFastEnumerationState;
+@protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end
+@class NSString;
+typedef struct _NSRange {} NSRange;
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+@end
+@interface NSMutableArray : NSArray
+- (void)addObject:(id)anObject;
+- (id)initWithCapacity:(NSUInteger)numItems;
+@end
+typedef unsigned short unichar;
+@class NSData, NSArray, NSDictionary, NSCharacterSet, NSData, NSURL, NSError, NSLocale;
+typedef NSUInteger NSStringCompareOptions;
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
+- (NSComparisonResult)compare:(NSString *)string;
+- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask;
+- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange;
+- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange locale:(id)locale;
+- (NSComparisonResult)caseInsensitiveCompare:(NSString *)string;
+- (NSArray *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)separator;
++ (id)stringWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2)));
+@end
+@interface NSSimpleCString : NSString {} @end
+@interface NSConstantString : NSSimpleCString @end
+extern void *_NSConstantStringClassReference;
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+NSComparisonResult f1(NSString* s) {
+ NSString *aString = 0;
+ return [s compare:aString]; // expected-warning {{Argument to 'NSString' method 'compare:' cannot be nil.}}
+}
+
+NSComparisonResult f2(NSString* s) {
+ NSString *aString = 0;
+ return [s caseInsensitiveCompare:aString]; // expected-warning {{Argument to 'NSString' method 'caseInsensitiveCompare:' cannot be nil.}}
+}
+
+NSComparisonResult f3(NSString* s, NSStringCompareOptions op) {
+ NSString *aString = 0;
+ return [s compare:aString options:op]; // expected-warning {{Argument to 'NSString' method 'compare:options:' cannot be nil.}}
+}
+
+NSComparisonResult f4(NSString* s, NSStringCompareOptions op, NSRange R) {
+ NSString *aString = 0;
+ return [s compare:aString options:op range:R]; // expected-warning {{Argument to 'NSString' method 'compare:options:range:' cannot be nil.}}
+}
+
+NSComparisonResult f5(NSString* s, NSStringCompareOptions op, NSRange R) {
+ NSString *aString = 0;
+ return [s compare:aString options:op range:R locale:0]; // expected-warning {{Argument to 'NSString' method 'compare:options:range:locale:' cannot be nil.}}
+}
+
+NSArray *f6(NSString* s) {
+ return [s componentsSeparatedByCharactersInSet:0]; // expected-warning {{Argument to 'NSString' method 'componentsSeparatedByCharactersInSet:' cannot be nil.}}
+}
+
+NSString* f7(NSString* s1, NSString* s2, NSString* s3) {
+
+ NSString* s4 = (NSString*)
+ CFStringCreateWithFormat(kCFAllocatorDefault, 0, // expected-warning{{leak}}
+ (CFStringRef) __builtin___CFStringMakeConstantString("%@ %@ (%@)"),
+ s1, s2, s3);
+
+ CFRetain(s4);
+ return s4;
+}
+
+NSMutableArray* f8() {
+
+ NSString* s = [[NSString alloc] init];
+ NSMutableArray* a = [[NSMutableArray alloc] initWithCapacity:2];
+ [a addObject:s];
+ [s release]; // no-warning
+ return a;
+}
+
+void f9() {
+
+ NSString* s = [[NSString alloc] init];
+ NSString* q = s;
+ [s release];
+ [q release]; // expected-warning {{used after it is released}}
+}
+
+NSString* f10() {
+ static NSString* s = 0;
+ if (!s) s = [[NSString alloc] init];
+ return s; // no-warning
+}
+
+// Test case for regression reported in <rdar://problem/6452745>.
+// Essentially 's' should not be considered allocated on the false branch.
+// This exercises the 'EvalAssume' logic in GRTransferFuncs (CFRefCount.cpp).
+NSString* f11(CFDictionaryRef dict, const char* key) {
+ NSString* s = (NSString*) CFDictionaryGetValue(dict, key);
+ [s retain];
+ if (s) {
+ [s release];
+ }
+}
+
+// Test case for passing a tracked object by-reference to a function we
+// don't understand.
+void unknown_function_f12(NSString** s);
+void f12() {
+ NSString *string = [[NSString alloc] init];
+ unknown_function_f12(&string); // no-warning
+}
+
+// Test double release of CFString (PR 4014).
+void f13(void) {
+ CFStringRef ref = CFStringCreateWithFormat(kCFAllocatorDefault, ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "%d" "")), 100);
+ CFRelease(ref);
+ CFRelease(ref); // expected-warning{{Reference-counted object is used after it is released}}
+}
+
+// Test regular use of -autorelease
+@interface TestAutorelease
+-(NSString*) getString;
+@end
+@implementation TestAutorelease
+-(NSString*) getString {
+ NSString *str = [[NSString alloc] init];
+ return [str autorelease]; // no-warning
+}
+- (void)m1
+{
+ NSString *s = [[NSString alloc] init]; // expected-warning{{leak}}
+ [s retain];
+ [s autorelease];
+}
+- (void)m2
+{
+ NSString *s = [[[NSString alloc] init] autorelease]; // expected-warning{{leak}}
+ [s retain];
+}
+- (void)m3
+{
+ NSString *s = [[[NSString alloc] init] autorelease];
+ [s retain];
+ [s autorelease];
+}
+- (void)m4
+{
+ NSString *s = [[NSString alloc] init]; // expected-warning{{leak}}
+ [s retain];
+}
+- (void)m5
+{
+ NSString *s = [[NSString alloc] init];
+ [s autorelease];
+}
+@end
+
+@interface C1 : NSObject {}
+- (NSString*) getShared;
++ (C1*) sharedInstance;
+@end
+@implementation C1 : NSObject {}
+- (NSString*) getShared {
+ static NSString* s = 0;
+ if (!s) s = [[NSString alloc] init];
+ return s; // no-warning
+}
++ (C1 *)sharedInstance {
+ static C1 *sharedInstance = 0;
+ if (!sharedInstance) {
+ sharedInstance = [[C1 alloc] init];
+ }
+ return sharedInstance; // no-warning
+}
+@end
+
+@interface SharedClass : NSObject
++ (id)sharedInstance;
+- (id)notShared;
+@end
+
+@implementation SharedClass
+
+- (id)_init {
+ if ((self = [super init])) {
+ NSLog(@"Bar");
+ }
+ return self;
+}
+
+- (id)notShared {
+ return [[SharedClass alloc] _init]; // expected-warning{{leak}}
+}
+
++ (id)sharedInstance {
+ static SharedClass *_sharedInstance = 0;
+ if (!_sharedInstance) {
+ _sharedInstance = [[SharedClass alloc] _init];
+ }
+ return _sharedInstance; // no-warning
+}
+@end
+
+id testSharedClassFromFunction() {
+ return [[SharedClass alloc] _init]; // no-warning
+}
+
+// Test OSCompareAndSwap
+_Bool OSAtomicCompareAndSwapPtr( void *__oldValue, void *__newValue, void * volatile *__theValue );
+_Bool OSAtomicCompareAndSwap32Barrier( int32_t __oldValue, int32_t __newValue, volatile int32_t *__theValue );
+extern BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation);
+
+void testOSCompareAndSwap() {
+ NSString *old = 0;
+ NSString *s = [[NSString alloc] init]; // no-warning
+ if (!OSAtomicCompareAndSwapPtr(0, s, (void**) &old))
+ [s release];
+ else
+ [old release];
+}
+
+void testOSCompareAndSwap32Barrier() {
+ NSString *old = 0;
+ NSString *s = [[NSString alloc] init]; // no-warning
+ if (!OSAtomicCompareAndSwap32Barrier((int32_t) 0, (int32_t) s, (int32_t*) &old))
+ [s release];
+ else
+ [old release];
+}
+
+void test_objc_atomicCompareAndSwap() {
+ NSString *old = 0;
+ NSString *s = [[NSString alloc] init]; // no-warning
+ if (!objc_atomicCompareAndSwapPtr(0, s, &old))
+ [s release];
+ else
+ [old release];
+}
+
+// Test stringWithFormat (<rdar://problem/6815234>)
+void test_stringWithFormat() {
+ NSString *string = [[NSString stringWithFormat:@"%ld", (long) 100] retain];
+ [string release];
+ [string release]; // expected-warning{{Incorrect decrement of the reference count}}
+}
+
+// Test isTrackedObjectType().
+typedef NSString* WonkyTypedef;
+@interface TestIsTracked
++ (WonkyTypedef)newString;
+@end
+
+void test_isTrackedObjectType(void) {
+ NSString *str = [TestIsTracked newString]; // expected-warning{{Potential leak}}
+}
+
+// Test isTrackedCFObjectType().
+@interface TestIsCFTracked
++ (CFStringRef) badNewCFString;
++ (CFStringRef) newCFString;
+@end
+
+@implementation TestIsCFTracked
++ (CFStringRef) newCFString {
+ return CFStringCreateWithFormat(kCFAllocatorDefault, ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "%d" "")), 100); // no-warning
+}
++ (CFStringRef) badNewCFString {
+ return CFStringCreateWithFormat(kCFAllocatorDefault, ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "%d" "")), 100); // expected-warning{{leak}}
+}
+
+// Test @synchronized
+void test_synchronized(id x) {
+ @synchronized(x) {
+ NSString *string = [[NSString stringWithFormat:@"%ld", (long) 100] retain]; // expected-warning {{leak}}
+ }
+}
+
+
diff --git a/test/Analysis/NSWindow.m b/test/Analysis/NSWindow.m
new file mode 100644
index 000000000000..9609c5260f53
--- /dev/null
+++ b/test/Analysis/NSWindow.m
@@ -0,0 +1,89 @@
+// RUN: clang-cc -analyze -checker-cfref -warn-dead-stores -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -warn-dead-stores -analyzer-store=basic -analyzer-constraints=range -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -warn-dead-stores -analyzer-store=region -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -warn-dead-stores -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.
+
+typedef struct objc_selector *SEL;
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+@end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
+ + (id)alloc;
+@end
+typedef float CGFloat;
+typedef struct _NSPoint {} NSRect;
+NSRect NSMakeRect(CGFloat x, CGFloat y, CGFloat w, CGFloat h);
+enum { NSBackingStoreRetained = 0, NSBackingStoreNonretained = 1, NSBackingStoreBuffered = 2 };
+typedef NSUInteger NSBackingStoreType;
+@interface NSResponder : NSObject <NSCoding> {}
+@end
+@protocol NSAnimatablePropertyContainer
+- (id)animator;
+@end
+extern NSString *NSAnimationTriggerOrderIn ;
+@class CIFilter, CALayer, NSDictionary, NSScreen, NSShadow, NSTrackingArea;
+@interface NSView : NSResponder <NSAnimatablePropertyContainer> {} @end
+@protocol NSValidatedUserInterfaceItem - (SEL)action; @end
+@protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem; @end @class NSNotification, NSText, NSView, NSMutableSet, NSSet, NSDate;
+enum { NSBorderlessWindowMask = 0, NSTitledWindowMask = 1 << 0, NSClosableWindowMask = 1 << 1, NSMiniaturizableWindowMask = 1 << 2, NSResizableWindowMask = 1 << 3 };
+@interface NSWindow : NSResponder <NSAnimatablePropertyContainer, NSUserInterfaceValidations> {
+ struct __wFlags {} _wFlags;
+}
+- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag;
+- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag screen:(NSScreen *)screen;
+- (void)orderFrontRegardless;
+@end
+
+extern NSString *NSWindowDidBecomeKeyNotification;
+
+// Test cases.
+
+void f1() {
+ NSWindow *window = [[NSWindow alloc]
+ initWithContentRect:NSMakeRect(0,0,100,100)
+ styleMask:NSTitledWindowMask|NSClosableWindowMask
+ backing:NSBackingStoreBuffered
+ defer:0];
+
+ [window orderFrontRegardless]; // no-warning
+}
+
+void f2() {
+ NSWindow *window = [[NSWindow alloc]
+ initWithContentRect:NSMakeRect(0,0,100,100)
+ styleMask:NSTitledWindowMask|NSClosableWindowMask
+ backing:NSBackingStoreBuffered
+ defer:0
+ screen:0];
+
+ [window orderFrontRegardless]; // no-warning
+}
+
+void f2b() {
+ // FIXME: NSWindow doesn't own itself until it is displayed.
+ NSWindow *window = [[NSWindow alloc] // no-warning
+ initWithContentRect:NSMakeRect(0,0,100,100)
+ styleMask:NSTitledWindowMask|NSClosableWindowMask
+ backing:NSBackingStoreBuffered
+ defer:0
+ screen:0];
+
+ [window orderFrontRegardless];
+
+ [window retain];
+}
+
+
+void f3() {
+ // FIXME: For now we don't track NSWindow.
+ NSWindow *window = [NSWindow alloc]; // expected-warning{{never read}}
+}
diff --git a/test/Analysis/NoReturn.m b/test/Analysis/NoReturn.m
new file mode 100644
index 000000000000..a43f99bdd79b
--- /dev/null
+++ b/test/Analysis/NoReturn.m
@@ -0,0 +1,82 @@
+// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=range -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+
+#include <stdarg.h>
+
+//===----------------------------------------------------------------------===//
+// 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 directly including Foundation.h directly makes this test case
+// both svelte and portable to non-Mac platforms.
+//===----------------------------------------------------------------------===//
+
+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 NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
+@interface NSObject <NSObject> {} @end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
++ (id)stringWithFormat:(NSString *)format, ...;
+@end
+@interface NSSimpleCString : NSString {} @end
+@interface NSConstantString : NSSimpleCString @end
+extern void *_NSConstantStringClassReference;
+typedef double NSTimeInterval;
+@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate; @end
+@class NSString, NSDictionary, NSArray;
+@interface NSException : NSObject <NSCopying, NSCoding> {}
++ (NSException *)exceptionWithName:(NSString *)name reason:(NSString *)reason userInfo:(NSDictionary *)userInfo;
+- (void)raise;
+@end
+@interface NSException (NSExceptionRaisingConveniences)
++ (void)raise:(NSString *)name format:(NSString *)format, ...;
++ (void)raise:(NSString *)name format:(NSString *)format arguments:(va_list)argList;
+@end
+
+enum {NSPointerFunctionsStrongMemory = (0 << 0), NSPointerFunctionsZeroingWeakMemory = (1 << 0), NSPointerFunctionsOpaqueMemory = (2 << 0), NSPointerFunctionsMallocMemory = (3 << 0), NSPointerFunctionsMachVirtualMemory = (4 << 0), NSPointerFunctionsObjectPersonality = (0 << 8), NSPointerFunctionsOpaquePersonality = (1 << 8), NSPointerFunctionsObjectPointerPersonality = (2 << 8), NSPointerFunctionsCStringPersonality = (3 << 8), NSPointerFunctionsStructPersonality = (4 << 8), NSPointerFunctionsIntegerPersonality = (5 << 8), NSPointerFunctionsCopyIn = (1 << 16), };
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+int f1(int *x, NSString* s) {
+
+ if (x) ++x;
+
+ [NSException raise:@"Blah" format:[NSString stringWithFormat:@"Blah %@", s]];
+
+ return *x; // no-warning
+}
+
+int f2(int *x, ...) {
+
+ if (x) ++x;
+ va_list alist;
+ va_start(alist, x);
+
+ [NSException raise:@"Blah" format:@"Blah %@" arguments:alist];
+
+ return *x; // no-warning
+}
+
+int f3(int* x) {
+
+ if (x) ++x;
+
+ [[NSException exceptionWithName:@"My Exception" reason:@"Want to test exceptions." userInfo:0] raise];
+
+ return *x; // no-warning
+}
+
diff --git a/test/Analysis/ObjCProperties.m b/test/Analysis/ObjCProperties.m
new file mode 100644
index 000000000000..7787a1d6ecdc
--- /dev/null
+++ b/test/Analysis/ObjCProperties.m
@@ -0,0 +1,25 @@
+// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=basic %s -verify &&
+// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=range %s -verify &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic %s -verify &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range %s -verify &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic %s -verify &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range %s -verify
+
+// The point of this test cases is to exercise properties in the static
+// analyzer
+
+@interface MyClass {
+@private
+ id _X;
+}
+- (id)initWithY:(id)Y;
+@property(copy, readwrite) id X;
+@end
+
+@implementation MyClass
+@synthesize X = _X;
+- (id)initWithY:(id)Y {
+ self.X = Y;
+ return self;
+}
+@end
diff --git a/test/Analysis/ObjCRetSigs.m b/test/Analysis/ObjCRetSigs.m
new file mode 100644
index 000000000000..0d699168a551
--- /dev/null
+++ b/test/Analysis/ObjCRetSigs.m
@@ -0,0 +1,25 @@
+// RUN: clang-cc -analyze -warn-objc-methodsigs -verify %s
+
+#include <stdio.h>
+
+@interface MyBase
+-(long long)length;
+@end
+
+@interface MySub : MyBase{}
+-(double)length;
+@end
+
+@implementation MyBase
+-(long long)length{
+ printf("Called MyBase -length;\n");
+ return 3;
+}
+@end
+
+@implementation MySub
+-(double)length{ // expected-warning{{types are incompatible}}
+ printf("Called MySub -length;\n");
+ return 3.3;
+}
+@end
diff --git a/test/Analysis/PR2599.m b/test/Analysis/PR2599.m
new file mode 100644
index 000000000000..098bfe8e8539
--- /dev/null
+++ b/test/Analysis/PR2599.m
@@ -0,0 +1,64 @@
+// RUN: clang-cc -analyze -analyzer-constraints=basic -analyzer-store=basic -checker-cfref -fobjc-gc -verify %s &&
+// RUN: clang-cc -analyze -analyzer-constraints=range -analyzer-store=basic -checker-cfref -fobjc-gc -verify %s &&
+// RUN: clang-cc -analyze -analyzer-constraints=basic -analyzer-store=basic -checker-cfref -fobjc-gc -verify %s &&
+// RUN: clang-cc -analyze -analyzer-constraints=range -analyzer-store=region -checker-cfref -fobjc-gc -verify %s
+
+typedef const void * CFTypeRef;
+typedef const struct __CFString * CFStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+typedef const struct __CFDictionary * CFDictionaryRef;
+CFTypeRef CFMakeCollectable(CFTypeRef cf) ;
+extern CFStringRef CFStringCreateWithFormat(CFAllocatorRef alloc, CFDictionaryRef formatOptions, CFStringRef format, ...);
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)autorelease;
+@end
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end @protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+@protocol
+NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
+- (id)init;
++ (id)alloc;
+@end
+enum { NSASCIIStringEncoding = 1, NSNEXTSTEPStringEncoding = 2, NSJapaneseEUCStringEncoding = 3, NSUTF8StringEncoding = 4, NSISOLatin1StringEncoding = 5, NSSymbolStringEncoding = 6, NSNonLossyASCIIStringEncoding = 7, NSShiftJISStringEncoding = 8, NSISOLatin2StringEncoding = 9, NSUnicodeStringEncoding = 10, NSWindowsCP1251StringEncoding = 11, NSWindowsCP1252StringEncoding = 12, NSWindowsCP1253StringEncoding = 13, NSWindowsCP1254StringEncoding = 14, NSWindowsCP1250StringEncoding = 15, NSISO2022JPStringEncoding = 21, NSMacOSRomanStringEncoding = 30, NSUTF16StringEncoding = NSUnicodeStringEncoding, NSUTF16BigEndianStringEncoding = 0x90000100, NSUTF16LittleEndianStringEncoding = 0x94000100, NSUTF32StringEncoding = 0x8c000100, NSUTF32BigEndianStringEncoding = 0x98000100, NSUTF32LittleEndianStringEncoding = 0x9c000100 };
+typedef NSUInteger NSStringEncoding;
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
+- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding freeWhenDone:(BOOL)freeBuffer;
+@end
+@interface NSAutoreleasePool : NSObject {}
+- (void)drain;
+@end
+extern NSString * const NSXMLParserErrorDomain ;
+
+// The actual test case. UTIL_AUTORELEASE_CF_AS_ID is a macro that doesn't
+// actually do what it was intended to.
+
+#define NSSTRINGWRAPPER(bytes,len) \
+ [[[NSString alloc] initWithBytesNoCopy: (void*)(bytes) length: (len) encoding: NSUTF8StringEncoding freeWhenDone: (BOOL)0] autorelease]
+
+#define UTIL_AUTORELEASE_CF_AS_ID(cf) ( (((void*)0) == (cf)) ? ((void*)0) : [(id) CFMakeCollectable( (CFTypeRef) cf) autorelease] )
+
+#define UTIL_AUTORELEASE_CF_AS_ID_WITHOUT_TEST(cf) ( [(id) CFMakeCollectable( (CFTypeRef) cf) autorelease] )
+
+static char *lorem = "fooBarBaz";
+
+int main (int argc, const char * argv[]) {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ NSString *tmp1 = NSSTRINGWRAPPER(lorem, 6); // no-warning
+ NSString *tmp2 = UTIL_AUTORELEASE_CF_AS_ID( CFStringCreateWithFormat(((void*)0), ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "lorem: %@" "")), tmp1) ); // expected-warning 2 {{leak}}
+ NSString *tmp3 = UTIL_AUTORELEASE_CF_AS_ID_WITHOUT_TEST( CFStringCreateWithFormat(((void*)0), ((void*)0), ((CFStringRef) __builtin___CFStringMakeConstantString ("" "lorem: %@" "")), tmp1) );
+ NSLog(@"tmp2: %@ tmp3: %@", tmp2, tmp3);
+ [pool drain];
+ return 0;
+}
diff --git a/test/Analysis/PR2978.m b/test/Analysis/PR2978.m
new file mode 100644
index 000000000000..7bc90b8d03e0
--- /dev/null
+++ b/test/Analysis/PR2978.m
@@ -0,0 +1,61 @@
+// RUN: clang-cc -analyze -warn-objc-missing-dealloc %s -verify
+
+// Tests for the checker which checks missing/extra ivar 'release' calls
+// in dealloc.
+
+@interface NSObject
+- (void)release;
+- dealloc;
+@end
+
+@interface MyClass : NSObject {
+@private
+ id _X;
+ id _Y;
+ id _Z;
+ id _K;
+ id _N;
+ id _M;
+ id _V;
+ id _W;
+}
+@property(retain) id X;
+@property(retain) id Y;
+@property(assign) id Z;
+@property(assign) id K;
+@property(readonly) id N;
+@property(retain) id M;
+@property(retain) id V;
+@property(retain) id W;
+-(id) O;
+-(void) setO: (id) arg;
+@end
+
+@implementation MyClass
+@synthesize X = _X;
+@synthesize Y = _Y; // expected-warning{{The '_Y' instance variable was retained by a synthesized property but wasn't released in 'dealloc'}}
+@synthesize Z = _Z; // expected-warning{{The '_Z' instance variable was not retained by a synthesized property but was released in 'dealloc'}}
+@synthesize K = _K;
+@synthesize N = _N;
+@synthesize M = _M;
+@synthesize V = _V;
+@synthesize W = _W; // expected-warning{{The '_W' instance variable was retained by a synthesized property but wasn't released in 'dealloc'}}
+
+-(id) O{ return 0; }
+-(void) setO:(id)arg { }
+
+- (id)dealloc
+{
+ [_X release];
+ [_Z release];
+ [_N release];
+
+ self.M = 0; // This will release '_M'
+ [self setV:0]; // This will release '_V'
+ [self setW:@"newW"]; // This will release '_W', but retain the new value
+ self.O = 0; // no-warning
+ [super dealloc];
+}
+
+@end
+
diff --git a/test/Analysis/PR3991.m b/test/Analysis/PR3991.m
new file mode 100644
index 000000000000..20d4b5b96059
--- /dev/null
+++ b/test/Analysis/PR3991.m
@@ -0,0 +1,67 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
+
+//===----------------------------------------------------------------------===//
+// Delta-debugging produced forward declarations.
+//===----------------------------------------------------------------------===//
+
+typedef signed char BOOL;
+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 NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end @interface NSObject <NSObject> {
+}
+@end extern id <NSObject> NSAllocateObject(Class aClass, unsigned extraBytes, NSZone *zone);
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding> - (unsigned)count;
+@end @class NSTimer, NSPort, NSArray;
+@class NSURLHandle, NSMutableArray, NSMutableData, NSData, NSURL;
+@interface NSResponder : NSObject <NSCoding> {
+}
+@end @class NSBitmapImageRep, NSCursor, NSGraphicsContext, NSImage, NSPasteboard, NSScrollView, NSWindow, NSAttributedString;
+@interface NSView : NSResponder {
+ struct __VFlags2 {
+ }
+ _vFlags2;
+}
+@end @class NSTextField, NSPanel, NSArray, NSWindow, NSImage, NSButton, NSError;
+@interface NSBox : NSView {
+}
+@end @class GDataFeedDocList, GDataServiceTicket, GDataServiceTicket, IHGoogleDocsAdapter;
+@protocol IHGoogleDocsAdapterDelegate - (void)googleDocsAdapter:(IHGoogleDocsAdapter*)inGoogleDocsAdapter accountVerifyIsValid:(BOOL)inIsValid error:(NSError *)inError;
+@end @interface IHGoogleDocsAdapter : NSObject {
+}
+- (NSArray *)entries;
+@end extern Class const kGDataUseRegisteredClass ;
+@interface IHGoogleDocsAdapter () - (GDataFeedDocList *)feedDocList;
+- (NSArray *)directoryPathComponents;
+- (unsigned int)currentPathComponentIndex;
+- (void)setCurrentPathComponentIndex:(unsigned int)aCurrentPathComponentIndex;
+- (NSURL *)folderFeedURL;
+@end @implementation IHGoogleDocsAdapter - (id)initWithUsername:(NSString *)inUsername password:(NSString *)inPassword owner:(NSObject <IHGoogleDocsAdapterDelegate> *)owner {
+}
+
+//===----------------------------------------------------------------------===//
+// Actual test case:
+//
+// The analyzer currently doesn't reason about ObjCKVCRefExpr. Have both
+// GRExprEngine::Visit and GRExprEngine::VisitLValue have such expressions
+// evaluate to UnknownVal.
+//===----------------------------------------------------------------------===//
+
+- (void)docListListFetchTicket:(GDataServiceTicket *)ticket finishedWithFeed:(GDataFeedDocList *)feed {
+ BOOL doGetDir = self.directoryPathComponents != 0 && self.currentPathComponentIndex < [self.directoryPathComponents count];
+ if (doGetDir) {
+ BOOL isDirExisting = [[self.feedDocList entries] count] > 0;
+ if (isDirExisting) {
+ if (self.folderFeedURL != 0) {
+ if (++self.currentPathComponentIndex == [self.directoryPathComponents count]) {
+ }
+ }
+ }
+ }
+}
diff --git a/test/Analysis/array-struct.c b/test/Analysis/array-struct.c
new file mode 100644
index 000000000000..c0e1d8b7e39f
--- /dev/null
+++ b/test/Analysis/array-struct.c
@@ -0,0 +1,150 @@
+// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s
+
+// RegionStore now has an infinite recursion with this test case.
+// NOWORK: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s &&
+// NOWORK: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+
+struct s {
+ int data;
+ int data_array[10];
+};
+
+typedef struct {
+ int data;
+} STYPE;
+
+void g(char *p);
+void g1(struct s* p);
+
+// Array to pointer conversion. Array in the struct field.
+void f(void) {
+ int a[10];
+ int (*p)[10];
+ p = &a;
+ (*p)[3] = 1;
+
+ struct s d;
+ struct s *q;
+ q = &d;
+ q->data = 3;
+ d.data_array[9] = 17;
+}
+
+// StringLiteral in lvalue context and pointer to array type.
+// p: ElementRegion, q: StringRegion
+void f2() {
+ char *p = "/usr/local";
+ char (*q)[4];
+ q = &"abc";
+}
+
+// Typedef'ed struct definition.
+void f3() {
+ STYPE s;
+}
+
+// Initialize array with InitExprList.
+void f4() {
+ int a[] = { 1, 2, 3};
+ int b[3] = { 1, 2 };
+ struct s c[] = {{1,{1}}};
+}
+
+// Struct variable in lvalue context.
+// Assign UnknownVal to the whole struct.
+void f5() {
+ struct s data;
+ g1(&data);
+}
+
+// AllocaRegion test.
+void f6() {
+ char *p;
+ p = __builtin_alloca(10);
+ g(p);
+ char c = *p;
+ p[1] = 'a';
+ // Test if RegionStore::EvalBinOp converts the alloca region to element
+ // region.
+ p += 2;
+}
+
+struct s2;
+
+void g2(struct s2 *p);
+
+// Incomplete struct pointer used as function argument.
+void f7() {
+ struct s2 *p = __builtin_alloca(10);
+ g2(p);
+}
+
+// sizeof() is unsigned while -1 is signed in array index.
+void f8() {
+ int a[10];
+ a[sizeof(a)/sizeof(int) - 1] = 1; // no-warning
+}
+
+// Initialization of struct array elements.
+void f9() {
+ struct s a[10];
+}
+
+// Initializing array with string literal.
+void f10() {
+ char a1[4] = "abc";
+ char a3[6] = "abc";
+}
+
+// Retrieve the default value of element/field region.
+void f11() {
+ struct s a;
+ g1(&a);
+ if (a.data == 0) // no-warning
+ a.data = 1;
+}
+
+// Convert unsigned offset to signed when creating ElementRegion from
+// SymbolicRegion.
+void f12(int *list) {
+ unsigned i = 0;
+ list[i] = 1;
+}
+
+struct s1 {
+ struct s2 {
+ int d;
+ } e;
+};
+
+// The binding of a.e.d should not be removed. Test recursive subregion map
+// building: a->e, e->d. Only then 'a' could be added to live region roots.
+void f13(double timeout) {
+ struct s1 a;
+ a.e.d = (long) timeout;
+ if (a.e.d == 10)
+ a.e.d = 4;
+}
+
+struct s3 {
+ int a[2];
+};
+
+static struct s3 opt;
+
+// Test if the embedded array is retrieved correctly.
+void f14() {
+ struct s3 my_opt = opt;
+}
+
+void bar(int*);
+
+// Test if the array is correctly invalidated.
+void f15() {
+ int a[10];
+ bar(a);
+ if (a[1]) // no-warning
+ 1;
+}
diff --git a/test/Analysis/basicstore_wine_crash.c b/test/Analysis/basicstore_wine_crash.c
new file mode 100644
index 000000000000..cb5fac8d2919
--- /dev/null
+++ b/test/Analysis/basicstore_wine_crash.c
@@ -0,0 +1,11 @@
+// RUN: clang-cc -checker-cfref -analyze -analyzer-store=basic %s
+
+// Once xfail_regionstore_wine_crash.c passes, move this test case
+// into misc-ps.m.
+
+void foo() {
+ long x = 0;
+ char *y = (char *) &x;
+ if (!*y)
+ return;
+}
diff --git a/test/Analysis/casts.c b/test/Analysis/casts.c
new file mode 100644
index 000000000000..94a1eac0a316
--- /dev/null
+++ b/test/Analysis/casts.c
@@ -0,0 +1,16 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region --verify %s
+
+// Test if the 'storage' region gets properly initialized after it is cast to
+// 'struct sockaddr *'.
+
+#include <sys/socket.h>
+void f(int sock) {
+ struct sockaddr_storage storage;
+ struct sockaddr* sockaddr = (struct sockaddr*)&storage;
+ socklen_t addrlen = sizeof(storage);
+ getsockname(sock, sockaddr, &addrlen);
+ switch (sockaddr->sa_family) { // no-warning
+ default:
+ ;
+ }
+}
diff --git a/test/Analysis/casts.m b/test/Analysis/casts.m
new file mode 100644
index 000000000000..82c29fac904f
--- /dev/null
+++ b/test/Analysis/casts.m
@@ -0,0 +1,22 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic --verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -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
+// functions with regions?
+typedef void* (*MyFuncTest1)(void);
+
+MyFuncTest1 test1_aux(void);
+void test1(void) {
+ void *x;
+ void* (*p)(void);
+ p = ((void*) test1_aux());
+ if (p != ((void*) 0)) x = (*p)();
+}
+
+// Test casts from void* to function pointers. Same issue as above:
+// should we eventually model function pointers using regions?
+void* test2(void *p) {
+ MyFuncTest1 fp = (MyFuncTest1) p;
+ return (*fp)();
+}
diff --git a/test/Analysis/cfref_PR2519.c b/test/Analysis/cfref_PR2519.c
new file mode 100644
index 000000000000..695123b53345
--- /dev/null
+++ b/test/Analysis/cfref_PR2519.c
@@ -0,0 +1,48 @@
+// RUN: clang-cc -analyze -checker-cfref --analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref --analyzer-store=basic -analyzer-constraints=range -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=range -verify %s
+
+typedef unsigned char Boolean;
+typedef signed long CFIndex;
+typedef const void * CFTypeRef;
+typedef const struct __CFString * CFStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+typedef struct {} CFAllocatorContext;
+extern void CFRelease(CFTypeRef cf);
+typedef struct {}
+CFDictionaryKeyCallBacks;
+extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
+typedef struct {}
+CFDictionaryValueCallBacks;
+extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
+typedef const struct __CFDictionary * CFDictionaryRef;
+extern CFDictionaryRef CFDictionaryCreate(CFAllocatorRef allocator, const void **keys, const void **values, CFIndex numValues, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks);
+enum { kCFNumberSInt8Type = 1, kCFNumberSInt16Type = 2, kCFNumberSInt32Type = 3, kCFNumberSInt64Type = 4, kCFNumberFloat32Type = 5, kCFNumberFloat64Type = 6, kCFNumberCharType = 7, kCFNumberShortType = 8, kCFNumberIntType = 9, kCFNumberLongType = 10, kCFNumberLongLongType = 11, kCFNumberFloatType = 12, kCFNumberDoubleType = 13, kCFNumberCFIndexType = 14, kCFNumberNSIntegerType = 15, kCFNumberCGFloatType = 16, kCFNumberMaxType = 16 };
+typedef CFIndex CFNumberType;
+typedef const struct __CFNumber * CFNumberRef;
+extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr);
+typedef struct __CFNotificationCenter * CFNotificationCenterRef;
+extern CFNotificationCenterRef CFNotificationCenterGetDistributedCenter(void);
+extern void CFNotificationCenterPostNotification(CFNotificationCenterRef center, CFStringRef name, const void *object, CFDictionaryRef userInfo, Boolean deliverImmediately);
+
+// This test case was reported in PR2519 as a false positive (_value was
+// reported as being leaked).
+
+int main(int argc, char **argv) {
+ CFStringRef _key = ((CFStringRef) __builtin___CFStringMakeConstantString ("" "Process identifier" ""));
+ int pid = 42;
+
+ CFNumberRef _value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pid);
+ CFDictionaryRef userInfo = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&_key, (const void **)&_value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CFRelease(_value); // no-warning
+ CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(),
+ ((CFStringRef) __builtin___CFStringMakeConstantString ("" "GrowlPreferencesChanged" "")),
+ ((CFStringRef) __builtin___CFStringMakeConstantString ("" "GrowlUserDefaults" "")),
+ userInfo, 0);
+ CFRelease(userInfo); // no-warning
+
+ return 0;
+}
+
diff --git a/test/Analysis/cfref_rdar6080742.c b/test/Analysis/cfref_rdar6080742.c
new file mode 100644
index 000000000000..5d957615d0dd
--- /dev/null
+++ b/test/Analysis/cfref_rdar6080742.c
@@ -0,0 +1,58 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -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).
+
+int printf(const char *restrict,...);
+typedef unsigned long UInt32;
+typedef signed long SInt32;
+typedef SInt32 OSStatus;
+typedef unsigned char Boolean;
+enum { noErr = 0};
+typedef const void *CFTypeRef;
+typedef const struct __CFString *CFStringRef;
+typedef const struct __CFAllocator *CFAllocatorRef;
+extern void CFRelease(CFTypeRef cf);
+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);
+
+enum { memROZWarn = -99, memROZError = -99, memROZErr = -99, memFullErr = -108,
+ nilHandleErr = -109, memWZErr = -111, memPurErr = -112, memAdrErr = -110,
+ memAZErr = -113, memPCErr = -114, memBCErr = -115, memSCErr = -116, memLockedErr = -117};
+
+#define DEBUG1
+
+void DebugStop(const char *format,...);
+void DebugTraceIf(unsigned int condition, const char *format,...);
+Boolean DebugDisplayOSStatusMsg(OSStatus status, const char *statusStr, const char *fileName, unsigned long lineNumber);
+
+#define Assert(condition)if (!(condition)) { DebugStop("Assertion failure: %s [File: %s, Line: %lu]", #condition, __FILE__, __LINE__); }
+#define AssertMsg(condition, message)if (!(condition)) { DebugStop("Assertion failure: %s (%s) [File: %s, Line: %lu]", #condition, message, __FILE__, __LINE__); }
+#define Require(condition)if (!(condition)) { DebugStop("Assertion failure: %s [File: %s, Line: %lu]", #condition, __FILE__, __LINE__); }
+#define RequireAction(condition, action)if (!(condition)) { DebugStop("Assertion failure: %s [File: %s, Line: %lu]", #condition, __FILE__, __LINE__); action }
+#define RequireActionSilent(condition, action)if (!(condition)) { action }
+#define AssertNoErr(err){ DebugDisplayOSStatusMsg((err), #err, __FILE__, __LINE__); }
+#define RequireNoErr(err, action){ if( DebugDisplayOSStatusMsg((err), #err, __FILE__, __LINE__) ) { action }}
+
+void DebugStop(const char *format,...); /* Not an abort function. */
+
+int main(int argc, char *argv[]) {
+ CFStringRef cfString;
+ OSStatus status = noErr;
+ cfString = CFStringCreateWithCString(0, "hello", kCFStringEncodingUTF8);
+ RequireAction(cfString != 0, return memFullErr;) //no - warning
+ printf("cfstring %p\n", cfString);
+Exit:
+ CFRelease(cfString);
+ return 0;
+}
diff --git a/test/Analysis/complex.c b/test/Analysis/complex.c
new file mode 100644
index 000000000000..f29fc70c4944
--- /dev/null
+++ b/test/Analysis/complex.c
@@ -0,0 +1,21 @@
+// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+
+#include <stdint.h>
+
+int f1(int * p) {
+
+ // This branch should be infeasible
+ // because __imag__ p is 0.
+ if (!p && __imag__ (intptr_t) p)
+ *p = 1; // no-warning
+
+ // If p != 0 then this branch is feasible; otherwise it is not.
+ if (__real__ (intptr_t) p)
+ *p = 1; // no-warning
+
+ *p = 2; // expected-warning{{Dereference of null pointer}}
+}
diff --git a/test/Analysis/conditional-op-missing-lhs.c b/test/Analysis/conditional-op-missing-lhs.c
new file mode 100644
index 000000000000..bebf155f4640
--- /dev/null
+++ b/test/Analysis/conditional-op-missing-lhs.c
@@ -0,0 +1,26 @@
+// RUN: clang-cc -analyze -warn-dead-stores -warn-uninit-values -verify %s
+
+void f1()
+{
+ int i;
+
+ int j = i ? : 1; // expected-warning{{use of uninitialized variable}} //expected-warning{{Value stored to 'j' during its initialization is never read}}
+}
+
+void *f2(int *i)
+{
+ return i ? : 0;
+}
+
+void *f3(int *i)
+{
+ int a;
+
+ return &a ? : i;
+}
+
+void f4()
+{
+ char c[1 ? : 2];
+}
+
diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c
new file mode 100644
index 000000000000..c100344adf6d
--- /dev/null
+++ b/test/Analysis/dead-stores.c
@@ -0,0 +1,175 @@
+// RUN: clang-cc -analyze -warn-dead-stores -verify %s &&
+// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=basic -warn-dead-stores -verify %s &&
+// RUN: clang-cc -analyze -checker-simple -analyzer-store=basic -analyzer-constraints=range -warn-dead-stores -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -warn-dead-stores -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -analyzer-constraints=range -warn-dead-stores -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=basic -warn-dead-stores -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range -warn-dead-stores -verify %s
+
+void f1() {
+ int k, y;
+ int abc=1;
+ long idx=abc+3*5; // expected-warning {{never read}}
+}
+
+void f2(void *b) {
+ char *c = (char*)b; // no-warning
+ char *d = b+1; // expected-warning {{never read}}
+ printf("%s", c); // expected-warning{{implicitly declaring C library function 'printf' with type 'int (char const *, ...)'}} \
+ // expected-note{{please include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
+}
+
+void f3() {
+ int r;
+ if ((r = f()) != 0) { // no-warning
+ int y = r; // no-warning
+ printf("the error is: %d\n", y);
+ }
+}
+
+void f4(int k) {
+
+ k = 1;
+
+ if (k)
+ f1();
+
+ k = 2; // expected-warning {{never read}}
+}
+
+void f5() {
+
+ int x = 4; // no-warning
+ int *p = &x; // expected-warning{{never read}}
+
+}
+
+int f6() {
+
+ int x = 4;
+ ++x; // expected-warning{{never read}}
+ return 1;
+}
+
+int f7(int *p) {
+ // This is allowed for defensive programming.
+ p = 0; // no-warning
+ return 1;
+}
+
+int f8(int *p) {
+ extern int *baz();
+ if (p = baz()) // expected-warning{{Although the value}}
+ return 1;
+ return 0;
+}
+
+int f9() {
+ int x = 4;
+ x = x + 10; // expected-warning{{never read}}
+ return 1;
+}
+
+int f10() {
+ int x = 4;
+ x = 10 + x; // expected-warning{{never read}}
+ return 1;
+}
+
+int f11() {
+ int x = 4;
+ return x++; // expected-warning{{never read}}
+}
+
+int f11b() {
+ int x = 4;
+ return ((((++x)))); // no-warning
+}
+
+int f12a(int y) {
+ int x = y; // expected-warning{{never read}}
+ return 1;
+}
+int f12b(int y) {
+ int x __attribute__((unused)) = y; // no-warning
+ return 1;
+}
+
+// Filed with PR 2630. This code should produce no warnings.
+int f13(void)
+{
+ int a = 1;
+ int b, c = b = a + a;
+
+ if (b > 0)
+ return (0);
+
+ return (a + b + c);
+}
+
+// Filed with PR 2763.
+int f14(int count) {
+ int index, nextLineIndex;
+ for (index = 0; index < count; index = nextLineIndex+1) {
+ nextLineIndex = index+1; // no-warning
+ continue;
+ }
+ return index;
+}
+
+// Test case for <rdar://problem/6248086>
+void f15(unsigned x, unsigned y) {
+ int count = x * y; // no-warning
+ int z[count];
+}
+
+int f16(int x) {
+ x = x * 2;
+ x = sizeof(int [x = (x || x + 1) * 2]) // expected-warning{{Although the value stored to 'x' is used}}
+ ? 5 : 8;
+ return x;
+}
+
+// Self-assignments should not be flagged as dead stores.
+int f17() {
+ int x = 1;
+ x = x; // no-warning
+}
+
+// <rdar://problem/6506065>
+// The values of dead stores are only "consumed" in an enclosing expression
+// what that value is actually used. In other words, don't say "Although the value stored to 'x' is used...".
+int f18() {
+ int x = 0; // no-warning
+ if (1)
+ x = 10; // expected-warning{{Value stored to 'x' is never read}}
+ while (1)
+ x = 10; // expected-warning{{Value stored to 'x' is never read}}
+ do
+ x = 10; // expected-warning{{Value stored to 'x' is never read}}
+ while (1);
+
+ return (x = 10); // expected-warning{{Although the value stored to 'x' is used in the enclosing expression, the value is never actually read from 'x'}}
+}
+
+// PR 3514: false positive `dead initialization` warning for init to global
+// http://llvm.org/bugs/show_bug.cgi?id=3514
+extern const int MyConstant;
+int f19(void) {
+ int x = MyConstant; // no-warning
+ x = 1;
+ return x;
+}
+
+int f19b(void) { // This case is the same as f19.
+ const int MyConstant = 0;
+ int x = MyConstant; // no-warning
+ x = 1;
+ return x;
+}
+
+void f20(void) {
+ int x = 1; // no-warning
+#pragma unused(x)
+}
+
diff --git a/test/Analysis/dead-stores.m b/test/Analysis/dead-stores.m
new file mode 100644
index 000000000000..218cb4458580
--- /dev/null
+++ b/test/Analysis/dead-stores.m
@@ -0,0 +1,36 @@
+// RUN: clang-cc -analyze -warn-dead-stores -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
+@interface NSObject <NSObject> {} @end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value; @end
+typedef float CGFloat;
+typedef struct _NSPoint {} NSRange;
+@interface NSValue (NSValueRangeExtensions) + (NSValue *)valueWithRange:(NSRange)range;
+- (BOOL)containsObject:(id)anObject;
+@end
+@class NSURLAuthenticationChallenge;
+@interface NSResponder : NSObject <NSCoding> {} @end
+@class NSArray, NSDictionary, NSString;
+@interface NSObject (NSKeyValueBindingCreation)
++ (void)exposeBinding:(NSString *)binding;
+- (NSArray *)exposedBindings;
+@end
+extern NSString *NSAlignmentBinding;
+
+// This test case was reported as a false positive due to a bug in the
+// LiveVariables <-> DeadStores interplay. We should not flag a warning
+// here. The test case was reported in:
+// http://lists.cs.uiuc.edu/pipermail/cfe-dev/2008-July/002157.html
+void DeadStoreTest(NSObject *anObject) {
+ NSArray *keys;
+ if ((keys = [anObject exposedBindings]) && // no-warning
+ ([keys containsObject:@"name"] && [keys containsObject:@"icon"])) {}
+}
+
diff --git a/test/Analysis/delegates.m b/test/Analysis/delegates.m
new file mode 100644
index 000000000000..440f31113cff
--- /dev/null
+++ b/test/Analysis/delegates.m
@@ -0,0 +1,114 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -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 directly including Foundation.h directly makes this test case
+// both svelte and portable to non-Mac platforms.
+//===----------------------------------------------------------------------===//
+
+typedef const void * CFTypeRef;
+typedef const struct __CFString * CFStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+void CFRelease(CFTypeRef cf);
+typedef const struct __CFDictionary * CFDictionaryRef;
+const void *CFDictionaryGetValue(CFDictionaryRef theDict, const void *key);
+extern CFStringRef CFStringCreateWithFormat(CFAllocatorRef alloc, CFDictionaryRef formatOptions, CFStringRef format, ...);
+typedef signed char BOOL;
+typedef int NSInteger;
+typedef unsigned int NSUInteger;
+typedef struct objc_selector *SEL;
+@class NSString, Protocol;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+typedef NSInteger NSComparisonResult;
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (oneway void)release;
+- (Class)class;
+- (id)retain;
+@end
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end
+@protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+@protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
+- (id)init;
++ (id)alloc;
++ (Class)class;
+- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
+@end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+typedef struct {} NSFastEnumerationState;
+@protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end
+@class NSString;
+typedef struct _NSRange {} NSRange;
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+@end
+@interface NSMutableArray : NSArray
+- (void)addObject:(id)anObject;
+- (id)initWithCapacity:(NSUInteger)numItems;
+@end
+typedef unsigned short unichar;
+@class NSData, NSArray, NSDictionary, NSCharacterSet, NSData, NSURL, NSError, NSLocale;
+typedef NSUInteger NSStringCompareOptions;
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
+- (NSComparisonResult)compare:(NSString *)string;
+- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask;
+- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange;
+- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange locale:(id)locale;
+- (NSComparisonResult)caseInsensitiveCompare:(NSString *)string;
+- (NSArray *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)separator;
+@end
+@interface NSSimpleCString : NSString {} @end
+@interface NSConstantString : NSSimpleCString @end
+extern void *_NSConstantStringClassReference;
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+// <rdar://problem/6062730>
+// The analyzer doesn't perform any inter-procedural analysis, so delegates
+// involving [NSObject performSelector...] tend to lead to false positives.
+// For now the analyzer just stops tracking the reference count of the
+// receiver until we have better support for delegates.
+
+@interface test_6062730 : NSObject
++ (void)postNotification:(NSString *)str;
+- (void)foo;
+- (void)bar;
+@end
+
+@implementation test_6062730
+- (void) foo {
+ NSString *str = [[NSString alloc] init];
+ [test_6062730 performSelectorOnMainThread:@selector(postNotification:) withObject:str waitUntilDone:1];
+}
+
+- (void) bar {
+ NSString *str = [[NSString alloc] init]; // expected-warning{{leak}}
+ // FIXME: We need to resolve [self class] to 'test_6062730'.
+ [[self class] performSelectorOnMainThread:@selector(postNotification:) withObject:str waitUntilDone:1];
+}
+
++ (void) postNotification:(NSString *)str {
+ [str release]; // no-warning
+}
+@end
+
diff --git a/test/Analysis/exercise-ps.c b/test/Analysis/exercise-ps.c
new file mode 100644
index 000000000000..08842b1b8dbf
--- /dev/null
+++ b/test/Analysis/exercise-ps.c
@@ -0,0 +1,25 @@
+// RUN: clang-cc -analyze -checker-simple -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s
+//
+// Just exercise the analyzer on code that has at one point caused issues
+// (i.e., no assertions or crashes).
+
+
+static const char * f1(const char *x, char *y) {
+ while (*x != 0) {
+ *y++ = *x++;
+ }
+}
+
+// This following case checks that we properly handle typedefs when getting
+// the RvalueType of an ElementRegion.
+typedef struct F12_struct {} F12_typedef;
+typedef void* void_typedef;
+void_typedef f2_helper();
+static void f2(void *buf) {
+ F12_typedef* x;
+ x = f2_helper();
+ memcpy((&x[1]), (buf), 1); // expected-warning{{implicitly declaring C library function 'memcpy' with type 'void *(void *, void const *}} \
+ // expected-note{{please include the header <string.h> or explicitly provide a declaration for 'memcpy'}}
+}
diff --git a/test/Analysis/fields.c b/test/Analysis/fields.c
new file mode 100644
index 000000000000..c012a9da7b81
--- /dev/null
+++ b/test/Analysis/fields.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -analyze -checker-cfref %s --analyzer-store=basic -verify &&
+// RUN: clang-cc -analyze -checker-cfref %s --analyzer-store=region -verify
+
+unsigned foo();
+typedef struct bf { unsigned x:2; } bf;
+void bar() {
+ bf y;
+ *(unsigned*)&y = foo();
+ y.x = 1;
+}
diff --git a/test/Analysis/func.c b/test/Analysis/func.c
new file mode 100644
index 000000000000..ac067a98103c
--- /dev/null
+++ b/test/Analysis/func.c
@@ -0,0 +1,17 @@
+// RUN: clang-cc -analyze -checker-simple -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s
+
+void f(void) {
+ void (*p)(void);
+ p = f;
+ p = &f;
+ p();
+ (*p)();
+}
+
+void g(void (*fp)(void));
+
+void f2() {
+ g(f);
+}
diff --git a/test/Analysis/misc-ps-64.m b/test/Analysis/misc-ps-64.m
new file mode 100644
index 000000000000..163da4b4abeb
--- /dev/null
+++ b/test/Analysis/misc-ps-64.m
@@ -0,0 +1,49 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -checker-cfref --analyzer-store=basic -analyzer-constraints=basic --verify -fblocks %s &&
+// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -checker-cfref --analyzer-store=basic -analyzer-constraints=range --verify -fblocks %s &&
+// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=basic --verify -fblocks %s &&
+// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -checker-cfref --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
+// regressions.
+typedef long long int64_t;
+@class NSString, NSDictionary;
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+typedef unsigned char Boolean;
+typedef const struct __CFDictionary * CFDictionaryRef;
+
+extern Boolean CFDictionaryGetValueIfPresent(CFDictionaryRef theDict, const void *key, const void **value);
+static void shazam(NSUInteger i, unsigned char **out);
+
+void rdar_6440393_1(NSDictionary *dict) {
+ NSInteger x = 0;
+ unsigned char buf[10], *bufptr = buf;
+ if (!CFDictionaryGetValueIfPresent(0, dict, (void *)&x))
+ return;
+ shazam(x, &bufptr);
+}
+
+// <rdar://problem/6845148> - In this example we got a signedness
+// mismatch between the literal '0' and the value of 'scrooge'. The
+// trick is to have the evaluator convert the literal to an unsigned
+// integer when doing a comparison with the pointer. This happens
+// because of the transfer function logic of
+// OSAtomicCompareAndSwap64Barrier, which doesn't have special casts
+// in place to do this for us.
+_Bool OSAtomicCompareAndSwap64Barrier( int64_t __oldValue, int64_t __newValue, volatile int64_t *__theValue );
+extern id objc_lookUpClass(const char *name);
+void rdar_6845148(id debug_yourself) {
+ if (!debug_yourself) {
+ const char *wacky = ((void *)0);
+ Class scrooge = wacky ? (Class)objc_lookUpClass(wacky) : ((void *)0);
+ OSAtomicCompareAndSwap64Barrier(0, (int64_t)scrooge, (int64_t*)&debug_yourself);
+ }
+}
+void rdar_6845148_b(id debug_yourself) {
+ if (!debug_yourself) {
+ const char *wacky = ((void *)0);
+ Class scrooge = wacky ? (Class)objc_lookUpClass(wacky) : ((void *)0);
+ OSAtomicCompareAndSwap64Barrier((int64_t)scrooge, 0, (int64_t*)&debug_yourself);
+ }
+}
diff --git a/test/Analysis/misc-ps-basic-store.m b/test/Analysis/misc-ps-basic-store.m
new file mode 100644
index 000000000000..1207f8663e90
--- /dev/null
+++ b/test/Analysis/misc-ps-basic-store.m
@@ -0,0 +1,21 @@
+// RUN: clang-cc -analyze -checker-cfref --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;
+}
diff --git a/test/Analysis/misc-ps-eager-assume.m b/test/Analysis/misc-ps-eager-assume.m
new file mode 100644
index 000000000000..818922eba925
--- /dev/null
+++ b/test/Analysis/misc-ps-eager-assume.m
@@ -0,0 +1,79 @@
+// RUN: clang-cc -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=range --verify -fblocks %s -analyzer-eagerly-assume
+
+// Delta-reduced header stuff (needed for test cases).
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject - (BOOL)isEqual:(id)object;
+- (oneway void)release;
+@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
+@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end @interface NSObject <NSObject> {}
++ (id)alloc;
+@end typedef struct {}
+NSFastEnumerationState;
+@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end @interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+@end @interface NSMutableArray : NSArray - (void)addObject:(id)anObject;
+- (BOOL)isEqualToString:(NSString *)aString;
+@end @interface NSAutoreleasePool : NSObject {}
+- (void)drain;
+- (id)init;
+@end
+
+// This test case tests that (x != 0) is eagerly evaluated before stored to
+// 'y'. This test case complements recoverCastedSymbol (see below) because
+// the symbolic expression is stored to 'y' (which is a short instead of an
+// int). recoverCastedSymbol() only recovers path-sensitivity when the
+// symbolic expression is literally the branch condition.
+//
+void handle_assign_of_condition(int x) {
+ // The cast to 'short' causes us to lose symbolic constraint.
+ short y = (x != 0);
+ char *p = 0;
+ if (y) {
+ // This should be infeasible.
+ if (!(x != 0)) {
+ *p = 1; // no-warning
+ }
+ }
+}
+
+// From <rdar://problem/6619921>
+//
+// In this test case, 'needsAnArray' is a signed char. The analyzer tracks
+// a symbolic value for this variable, but in the branch condition it is
+// promoted to 'int'. Currently the analyzer doesn't reason well about
+// promotions of symbolic values, so this test case tests the logic in
+// 'recoverCastedSymbol()' (GRExprEngine.cpp) to test that we recover
+// path-sensitivity and use the symbol for 'needsAnArray' in the branch
+// condition.
+//
+void handle_symbolic_cast_in_condition(void) {
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+ BOOL needsAnArray = [@"aString" isEqualToString:@"anotherString"];
+ NSMutableArray* array = needsAnArray ? [[NSMutableArray alloc] init] : 0;
+ if(needsAnArray)
+ [array release];
+
+ [pool drain];
+}
+
+// From PR 3836 (http://llvm.org/bugs/show_bug.cgi?id=3836)
+//
+// In this test case, the double '!' works fine with our symbolic constraints,
+// but we don't support comparing SymConstraint != SymConstraint. By eagerly
+// assuming the truth of !!a or !!b, we can compare these values directly.
+//
+void pr3836(int *a, int *b) {
+ if (!!a != !!b) /* one of them is NULL */
+ return;
+ if (!a && !b) /* both are NULL */
+ return;
+
+ *a = 1; // no-warning
+ *b = 1; // no-warning
+}
diff --git a/test/Analysis/misc-ps-ranges.m b/test/Analysis/misc-ps-ranges.m
new file mode 100644
index 000000000000..a191bec3cfb1
--- /dev/null
+++ b/test/Analysis/misc-ps-ranges.m
@@ -0,0 +1,23 @@
+// RUN: clang-cc -analyze -checker-cfref --analyzer-store=basic -analyzer-constraints=range --verify -fblocks %s &&
+// RUN: clang-cc -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=range --verify -fblocks %s
+
+// <rdar://problem/6776949>
+// main's 'argc' argument is always > 0
+int main(int argc, char* argv[]) {
+ int *p = 0;
+
+ if (argc == 0)
+ *p = 1;
+
+ if (argc == 1)
+ return 1;
+
+ int x = 1;
+ int i;
+
+ for(i=1;i<argc;i++){
+ p = &x;
+ }
+
+ return *p; // no-warning
+} \ No newline at end of file
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
new file mode 100644
index 000000000000..8c8815ea63eb
--- /dev/null
+++ b/test/Analysis/misc-ps-region-store.m
@@ -0,0 +1,70 @@
+// RUN: clang-cc -analyze -checker-cfref --analyzer-store=region --verify -fblocks %s
+
+typedef struct objc_selector *SEL;
+typedef signed char BOOL;
+typedef int NSInteger;
+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 NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
+@interface NSObject <NSObject> {} - (id)init; @end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
++ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
+@end extern NSString * const NSBundleDidLoadNotification;
+@interface NSAssertionHandler : NSObject {}
++ (NSAssertionHandler *)currentHandler;
+- (void)handleFailureInMethod:(SEL)selector object:(id)object file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format,...;
+@end
+extern NSString * const NSConnectionReplyMode;
+
+
+//---------------------------------------------------------------------------
+// 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 { // expected-warning {{ Branch condition evaluates to an uninitialized value.}}
+ __typeof (status) __in; int __i;}
+ )
+ {
+ .__in = (status)}
+ ).__i))) & 0xff00) >> 8) == 1)
+ ret = 1;
+}
+
+
+// Check our handling of fields being invalidated by function calls.
+struct test2_struct { int x; int y; char* s; };
+void test2_helper(struct test2_struct* p);
+
+char test2() {
+ struct test2_struct s;
+ test2_help(&s);
+ char *p = 0;
+
+ if (s.x > 1) {
+ if (s.s != 0) {
+ p = "hello";
+ }
+ }
+
+ if (s.x > 1) {
+ if (s.s != 0) {
+ return *p;
+ }
+ }
+
+ return 'a';
+}
+
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
new file mode 100644
index 000000000000..205bac2c825f
--- /dev/null
+++ b/test/Analysis/misc-ps.m
@@ -0,0 +1,287 @@
+// RUN: clang-cc -analyze -checker-cfref --analyzer-store=basic -analyzer-constraints=basic --verify -fblocks %s &&
+// RUN: clang-cc -analyze -checker-cfref --analyzer-store=basic -analyzer-constraints=range --verify -fblocks %s
+
+// NOWORK: clang-cc -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=basic --verify -fblocks %s &&
+// NOWORK: clang-cc -analyze -checker-cfref --analyzer-store=region -analyzer-constraints=range --verify -fblocks %s
+
+typedef struct objc_selector *SEL;
+typedef signed char BOOL;
+typedef int NSInteger;
+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 NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
+@interface NSObject <NSObject> {} - (id)init; @end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
++ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
+@end extern NSString * const NSBundleDidLoadNotification;
+@interface NSAssertionHandler : NSObject {}
++ (NSAssertionHandler *)currentHandler;
+- (void)handleFailureInMethod:(SEL)selector object:(id)object file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format,...;
+@end
+extern NSString * const NSConnectionReplyMode;
+typedef float CGFloat;
+typedef struct _NSPoint {
+ CGFloat x;
+ CGFloat y;
+} NSPoint;
+typedef struct _NSSize {
+ CGFloat width;
+ CGFloat height;
+} NSSize;
+typedef struct _NSRect {
+ NSPoint origin;
+ NSSize size;
+} NSRect;
+
+// Reduced test case from crash in <rdar://problem/6253157>
+@interface A @end
+@implementation A
+- (void)foo:(void (^)(NSObject *x))block {
+ if (!((block != ((void *)0)))) {}
+}
+@end
+
+// Reduced test case from crash in PR 2796;
+// http://llvm.org/bugs/show_bug.cgi?id=2796
+
+unsigned foo(unsigned x) { return __alignof__((x)) + sizeof(x); }
+
+// Improvement to path-sensitivity involving compound assignments.
+// Addresses false positive in <rdar://problem/6268365>
+//
+
+unsigned r6268365Aux();
+
+void r6268365() {
+ unsigned x = 0;
+ x &= r6268365Aux();
+ unsigned j = 0;
+
+ if (x == 0) ++j;
+ if (x == 0) x = x / j; // no-warning
+}
+
+void divzeroassume(unsigned x, unsigned j) {
+ x /= j;
+ if (j == 0) x /= 0; // no-warning
+ if (j == 0) x /= j; // no-warning
+ if (j == 0) x = x / 0; // no-warning
+}
+
+void divzeroassumeB(unsigned x, unsigned j) {
+ x = x / j;
+ if (j == 0) x /= 0; // no-warning
+ if (j == 0) x /= j; // no-warning
+ if (j == 0) x = x / 0; // no-warning
+}
+
+// InitListExpr processing
+
+typedef float __m128 __attribute__((__vector_size__(16), __may_alias__));
+__m128 return128() {
+ // This compound literal has a Vector type. We currently just
+ // return UnknownVal.
+ return __extension__(__m128) { 0.0f, 0.0f, 0.0f, 0.0f };
+}
+
+typedef long long __v2di __attribute__ ((__vector_size__ (16)));
+typedef long long __m128i __attribute__ ((__vector_size__ (16), __may_alias__));
+__m128i vec128i(long long __q1, long long __q0) {
+ // This compound literal returns true for both isVectorType() and
+ // isIntegerType().
+ return __extension__ (__m128i)(__v2di){ __q0, __q1 };
+}
+
+// Zero-sized VLAs.
+void check_zero_sized_VLA(int x) {
+ if (x)
+ return;
+
+ int vla[x]; // expected-warning{{Variable-length array 'vla' has zero elements (undefined behavior)}}
+}
+
+void check_uninit_sized_VLA() {
+ int x;
+ int vla[x]; // expected-warning{{Variable-length array 'vla' garbage value for array size}}
+}
+
+// sizeof(void)
+// - Tests a regression reported in PR 3211: http://llvm.org/bugs/show_bug.cgi?id=3211
+void handle_sizeof_void(unsigned flag) {
+ int* p = 0;
+
+ if (flag) {
+ if (sizeof(void) == 1)
+ return;
+ // Infeasible.
+ *p = 1; // no-warning
+ }
+
+ void* q;
+
+ if (!flag) {
+ if (sizeof(*q) == 1)
+ return;
+ // Infeasibe.
+ *p = 1; // no-warning
+ }
+
+ // Infeasible.
+ *p = 1; // no-warning
+}
+
+// PR 3422
+void pr3422_helper(char *p);
+void pr3422() {
+ char buf[100];
+ char *q = &buf[10];
+ pr3422_helper(&q[1]);
+}
+
+// PR 3543 (handle empty statement expressions)
+int pr_3543(void) {
+ ({});
+}
+
+// <rdar://problem/6611677>
+// This test case test the use of a vector type within an array subscript
+// expression.
+typedef long long __a64vector __attribute__((__vector_size__(8)));
+typedef long long __a128vector __attribute__((__vector_size__(16)));
+static inline __a64vector __attribute__((__always_inline__, __nodebug__))
+my_test_mm_movepi64_pi64(__a128vector a) {
+ return (__a64vector)a[0];
+}
+
+// Test basic tracking of ivars associated with 'self'.
+@interface SelfIvarTest : NSObject {
+ int flag;
+}
+- (void)test_self_tracking;
+@end
+
+@implementation SelfIvarTest
+- (void)test_self_tracking {
+ char *p = 0;
+ char c;
+
+ if (flag)
+ p = "hello";
+
+ if (flag)
+ c = *p; // no-warning
+}
+@end
+
+// PR 3770
+char pr3770(int x) {
+ int y = x & 0x2;
+ char *p = 0;
+ if (y == 1)
+ p = "hello";
+
+ if (y == 1)
+ return p[0]; // no-warning
+
+ return 'a';
+}
+
+// PR 3772
+// - We just want to test that this doesn't crash the analyzer.
+typedef struct st ST;
+struct st { char *name; };
+extern ST *Cur_Pu;
+
+void pr3772(void)
+{
+ static ST *last_Cur_Pu;
+ if (last_Cur_Pu == Cur_Pu) {
+ return;
+ }
+}
+
+// PR 3780 - This tests that StmtIterator isn't broken for VLAs in DeclGroups.
+void pr3780(int sz) { typedef double MAT[sz][sz]; }
+
+// <rdar://problem/6695527> - Test that we don't symbolicate doubles before
+// we are ready to do something with them.
+int rdar6695527(double x) {
+ if (!x) { return 0; }
+ return 1;
+}
+
+// <rdar://problem/6708148> - Test that we properly invalidate structs
+// passed-by-reference to a function.
+void pr6708148_invalidate(NSRect *x);
+void pr6708148_use(NSRect x);
+void pr6708148_test(void) {
+ NSRect x;
+ pr6708148_invalidate(&x);
+ pr6708148_use(x); // no-warning
+}
+
+// Handle both kinds of noreturn attributes for pruning paths.
+void rdar_6777003_noret() __attribute__((noreturn));
+void rdar_6777003_analyzer_noret() __attribute__((analyzer_noreturn));
+
+void rdar_6777003(int x) {
+ int *p = 0;
+
+ if (x == 1) {
+ rdar_6777003_noret();
+ *p = 1; // no-warning;
+ }
+
+ if (x == 2) {
+ rdar_6777003_analyzer_noret();
+ *p = 1; // no-warning;
+ }
+
+ *p = 1; // expected-warning{{Dereference of null pointer}}
+}
+
+// For pointer arithmetic, --/++ should be treated as preserving non-nullness,
+// regardless of how well the underlying StoreManager reasons about pointer
+// arithmetic.
+// <rdar://problem/6777209>
+void rdar_6777209(char *p) {
+ if (p == 0)
+ return;
+
+ ++p;
+
+ // This branch should always be infeasible.
+ if (p == 0)
+ *p = 'c'; // no-warning
+}
+
+// PR 4033. A symbolic 'void *' pointer can be used as the address for a
+// computed goto.
+typedef void *Opcode;
+Opcode pr_4033_getOpcode();
+void pr_4033(void) {
+next_opcode:
+ {
+ Opcode op = pr_4033_getOpcode();
+ if (op) goto *op;
+ }
+}
+
+// Test invalidating pointers-to-pointers with slightly different types. This
+// example came from a recent false positive due to a regression where the
+// branch condition was falsely reported as being uninitialized.
+void invalidate_by_ref(char **x);
+int test_invalidate_by_ref() {
+ unsigned short y;
+ invalidate_by_ref((char**) &y);
+ if (y) // no-warning
+ return 1;
+ return 0;
+}
+
diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
new file mode 100644
index 000000000000..9a64b3001e16
--- /dev/null
+++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
@@ -0,0 +1,67 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s -verify
+
+@interface MyClass {}
+- (void *)voidPtrM;
+- (int)intM;
+- (long long)longlongM;
+- (double)doubleM;
+- (long double)longDoubleM;
+- (void)voidM;
+@end
+@implementation MyClass
+- (void *)voidPtrM { return (void *)0; }
+- (int)intM { return 0; }
+- (long long)longlongM { return 0; }
+- (double)doubleM { return 0.0; }
+- (long double)longDoubleM { return 0.0; }
+- (void)voidM {}
+@end
+
+void createFoo() {
+ MyClass *obj = 0;
+
+ void *v = [obj voidPtrM]; // no-warning
+ int i = [obj intM]; // no-warning
+}
+
+void createFoo2() {
+ MyClass *obj = 0;
+
+ long double ld = [obj longDoubleM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}}
+}
+
+void createFoo3() {
+ MyClass *obj;
+ obj = 0;
+
+ long long ll = [obj longlongM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}}
+}
+
+void createFoo4() {
+ MyClass *obj = 0;
+
+ double d = [obj doubleM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}}
+}
+
+void createFoo5() {
+ MyClass *obj = @"";
+
+ double d = [obj doubleM]; // no-warning
+}
+
+void handleNilPruneLoop(MyClass *obj) {
+ if (!!obj)
+ return;
+
+ // Test if [obj intM] evaluates to 0, thus pruning the entire loop.
+ for (int i = 0; i < [obj intM]; i++) {
+ long long j = [obj longlongM]; // no-warning
+ }
+
+ long long j = [obj longlongM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}}
+}
+
+int handleVoidInComma() {
+ MyClass *obj = 0;
+ return [obj voidM], 0;
+}
diff --git a/test/Analysis/no-exit-cfg.c b/test/Analysis/no-exit-cfg.c
new file mode 100644
index 000000000000..cad2127b2082
--- /dev/null
+++ b/test/Analysis/no-exit-cfg.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -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
+// The flow-sensitive dataflow solver should work even when no block in
+// the CFG reaches the exit block.
+
+int g(int x);
+void h(int x);
+
+int f(int x)
+{
+out_err:
+ if (g(x)) {
+ h(x);
+ }
+ goto out_err;
+}
diff --git a/test/Analysis/no-outofbounds-basicstore.c b/test/Analysis/no-outofbounds-basicstore.c
new file mode 100644
index 000000000000..9a0b35906d7c
--- /dev/null
+++ b/test/Analysis/no-outofbounds-basicstore.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -checker-cfref -analyze -analyzer-store=basic -verify %s
+
+void f() {
+ long x = 0;
+ char *y = (char*) &x;
+ char c = y[0] + y[1] + y[2]; // no-warning
+}
diff --git a/test/Analysis/null-deref-ps-region.c b/test/Analysis/null-deref-ps-region.c
new file mode 100644
index 000000000000..80a5f9212fac
--- /dev/null
+++ b/test/Analysis/null-deref-ps-region.c
@@ -0,0 +1,14 @@
+// RUN: clang-cc -analyze -std=gnu99 -checker-cfref -analyzer-store=region -verify %s
+
+
+// The store for 'a[1]' should not be removed mistakenly. SymbolicRegions may
+// also be live roots.
+void f14(int *a) {
+ int i;
+ a[1] = 1;
+ i = a[1];
+ if (i != 1) {
+ int *p = 0;
+ i = *p; // no-warning
+ }
+}
diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c
new file mode 100644
index 000000000000..09b9c2ffa3b7
--- /dev/null
+++ b/test/Analysis/null-deref-ps.c
@@ -0,0 +1,265 @@
+// RUN: clang-cc -analyze -std=gnu99 -checker-simple -verify %s &&
+// RUN: clang-cc -analyze -std=gnu99 -checker-simple -verify %s -analyzer-constraints=range &&
+// RUN: clang-cc -analyze -std=gnu99 -checker-simple -analyzer-store=region -analyzer-purge-dead=false -verify %s &&
+// RUN: clang-cc -analyze -std=gnu99 -checker-cfref -analyzer-store=region -verify %s
+
+#include<stdint.h>
+#include <assert.h>
+
+void f1(int *p) {
+ if (p) *p = 1;
+ else *p = 0; // expected-warning{{ereference}}
+}
+
+struct foo_struct {
+ int x;
+};
+
+int f2(struct foo_struct* p) {
+
+ if (p)
+ p->x = 1;
+
+ return p->x++; // expected-warning{{Dereference of null pointer.}}
+}
+
+int f3(char* x) {
+
+ int i = 2;
+
+ if (x)
+ return x[i - 1];
+
+ return x[i+1]; // expected-warning{{Dereference of null pointer.}}
+}
+
+int f3_b(char* x) {
+
+ int i = 2;
+
+ if (x)
+ return x[i - 1];
+
+ return x[i+1]++; // expected-warning{{Dereference of null pointer.}}
+}
+
+int f4(int *p) {
+
+ uintptr_t x = (uintptr_t) p;
+
+ if (x)
+ return 1;
+
+ int *q = (int*) x;
+ return *q; // expected-warning{{Dereference of null pointer.}}
+}
+
+int f4_b() {
+ short array[2];
+ uintptr_t x = array; // expected-warning{{incompatible pointer to integer conversion initializing}}
+ short *p = x; // expected-warning{{incompatible integer to pointer conversion initializing}}
+
+ // The following branch should be infeasible.
+ if (!(p = &array[0])) {
+ p = 0;
+ *p = 1; // no-warning
+ }
+
+ if (p) {
+ *p = 5; // no-warning
+ p = 0;
+ }
+ else return; // expected-warning {{non-void function 'f4_b' should return a value}}
+
+ *p += 10; // expected-warning{{Dereference of null pointer}}
+}
+
+
+int f5() {
+
+ char *s = "hello world";
+ return s[0]; // no-warning
+}
+
+int bar(int* p, int q) __attribute__((nonnull));
+
+int f6(int *p) {
+ return !p ? bar(p, 1) // expected-warning {{Null pointer passed as an argument to a 'nonnull' parameter}}
+ : bar(p, 0); // no-warning
+}
+
+int bar2(int* p, int q) __attribute__((nonnull(1)));
+
+int f6b(int *p) {
+ return !p ? bar2(p, 1) // expected-warning {{Null pointer passed as an argument to a 'nonnull' parameter}}
+ : bar2(p, 0); // no-warning
+}
+
+int bar3(int*p, int q, int *r) __attribute__((nonnull(1,3)));
+
+int f6c(int *p, int *q) {
+ return !p ? bar3(q, 2, p) // expected-warning {{Null pointer passed as an argument to a 'nonnull' parameter}}
+ : bar3(p, 2, q); // no-warning
+}
+
+int* qux();
+
+int f7(int x) {
+
+ int* p = 0;
+
+ if (0 == x)
+ p = qux();
+
+ if (0 == x)
+ *p = 1; // no-warning
+
+ return x;
+}
+
+int* f7b(int *x) {
+
+ int* p = 0;
+
+ if (((void*)0) == x)
+ p = qux();
+
+ if (((void*)0) == x)
+ *p = 1; // no-warning
+
+ return x;
+}
+
+int* f7c(int *x) {
+
+ int* p = 0;
+
+ if (((void*)0) == x)
+ p = qux();
+
+ if (((void*)0) != x)
+ return x;
+
+ // If we reach here then 'p' is not null.
+ *p = 1; // no-warning
+ return x;
+}
+
+int* f7c2(int *x) {
+
+ int* p = 0;
+
+ if (((void*)0) == x)
+ p = qux();
+
+ if (((void*)0) == x)
+ return x;
+
+ *p = 1; // expected-warning{{null}}
+ return x;
+}
+
+
+int f8(int *p, int *q) {
+ if (!p)
+ if (p)
+ *p = 1; // no-warning
+
+ if (q)
+ if (!q)
+ *q = 1; // no-warning
+}
+
+int* qux();
+
+int f9(unsigned len) {
+ assert (len != 0);
+ int *p = 0;
+ unsigned i;
+
+ for (i = 0; i < len; ++i)
+ p = qux(i);
+
+ return *p++; // no-warning
+}
+
+int f9b(unsigned len) {
+ assert (len > 0); // note use of '>'
+ int *p = 0;
+ unsigned i;
+
+ for (i = 0; i < len; ++i)
+ p = qux(i);
+
+ return *p++; // no-warning
+}
+
+int* f10(int* p, signed char x, int y) {
+ // This line tests symbolication with compound assignments where the
+ // LHS and RHS have different bitwidths. The new symbolic value
+ // for 'x' should have a bitwidth of 8.
+ x &= y;
+
+ // This tests that our symbolication worked, and that we correctly test
+ // x against 0 (with the same bitwidth).
+ if (!x) {
+ if (!p) return; // expected-warning {{non-void function 'f10' should return a value}}
+ *p = 10;
+ }
+ else p = 0;
+
+ if (!x)
+ *p = 5; // no-warning
+
+ return p;
+}
+
+// Test case from <rdar://problem/6407949>
+void f11(unsigned i) {
+ int *x = 0;
+ if (i >= 0) {
+ // always true
+ } else {
+ *x = 42; // no-warning
+ }
+}
+
+void f11b(unsigned i) {
+ int *x = 0;
+ if (i <= ~(unsigned)0) {
+ // always true
+ } else {
+ *x = 42; // no-warning
+ }
+}
+
+// Test case for switch statements with weird case arms.
+typedef int BOOL, *PBOOL, *LPBOOL;
+typedef long LONG_PTR, *PLONG_PTR;
+typedef unsigned long ULONG_PTR, *PULONG_PTR;
+typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
+typedef LONG_PTR LRESULT;
+typedef struct _F12ITEM *HF12ITEM;
+
+void f12(HF12ITEM i, char *q) {
+ char *p = 0;
+ switch ((DWORD_PTR) i) {
+ case 0 ... 10:
+ p = q;
+ break;
+ case (DWORD_PTR) ((HF12ITEM) - 65535):
+ return;
+ default:
+ return;
+ }
+
+ *p = 1; // no-warning
+}
+
+// Test handling of translating between integer "pointers" and back.
+void f13() {
+ int *x = 0;
+ if (((((int) x) << 2) + 1) >> 1) *x = 1; // no-warning
+}
+
+
diff --git a/test/Analysis/outofbound.c b/test/Analysis/outofbound.c
new file mode 100644
index 000000000000..953075fe03d7
--- /dev/null
+++ b/test/Analysis/outofbound.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -analyze -checker-simple -analyzer-store=region -verify %s
+
+char f1() {
+ char* s = "abcd";
+ char c = s[4]; // no-warning
+ return s[5] + c; // expected-warning{{Load or store into an out-of-bound memory position.}}
+}
diff --git a/test/Analysis/override-werror.c b/test/Analysis/override-werror.c
new file mode 100644
index 000000000000..f928ee031fe3
--- /dev/null
+++ b/test/Analysis/override-werror.c
@@ -0,0 +1,15 @@
+// RUN: clang-cc -analyze -checker-cfref -Werror %s -analyzer-store=basic -verify &&
+// RUN: clang-cc -analyze -checker-cfref -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
+// analyzer results.
+
+char* f(int *p) {
+ return p; // expected-warning{{incompatible pointer types returning 'int *', expected 'char *'}}
+}
+
+void g(int *p) {
+ if (!p) *p = 0; // expected-warning{{null}}
+}
+
diff --git a/test/Analysis/pr4209.m b/test/Analysis/pr4209.m
new file mode 100644
index 000000000000..7d7d8fc5a157
--- /dev/null
+++ b/test/Analysis/pr4209.m
@@ -0,0 +1,70 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -analyze -checker-cfref -verify %s &&
+// RUN: clang-cc -triple i386-apple-darwin9 -analyze -checker-cfref -analyzer-store=region -verify %s
+
+// This test case was crashing due to how CFRefCount.cpp resolved the
+// ObjCInterfaceDecl* and ClassName in EvalObjCMessageExpr.
+
+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 NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end @interface NSObject <NSObject> {
+}
+@end typedef float CGFloat;
+typedef struct _NSPoint {
+}
+NSFastEnumerationState;
+@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end @class NSString;
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+@end @interface NSMutableArray : NSArray - (void)addObject:(id)anObject;
+@end typedef unsigned short unichar;
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
+- (int)intValue;
+@end @interface NSSimpleCString : NSString {
+}
+@end @interface NSConstantString : NSSimpleCString @end extern void *_NSConstantStringClassReference;
+@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+@end @interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey;
+@end typedef struct {
+}
+CMProfileLocation;
+@interface NSResponder : NSObject <NSCoding> {
+}
+@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView;
+@interface NSCell : NSObject <NSCopying, NSCoding> {
+}
+@end extern NSString *NSControlTintDidChangeNotification;
+@interface NSActionCell : NSCell {
+}
+@end @class NSArray, NSDocument, NSWindow;
+@interface NSWindowController : NSResponder <NSCoding> {
+}
+@end @class EBayCategoryType, GSEbayCategory, GBSearchRequest;
+@interface GBCategoryChooserPanelController : NSWindowController {
+ GSEbayCategory *rootCategory;
+}
+- (NSMutableDictionary*)categoryDictionaryForCategoryID:(int)inID inRootTreeCategories:(NSMutableArray*)inRootTreeCategories;
+-(NSString*) categoryID;
+@end @interface GSEbayCategory : NSObject <NSCoding> {
+}
+- (int) categoryID;
+- (GSEbayCategory *) parent;
+- (GSEbayCategory*) subcategoryWithID:(int) inID;
+@end @implementation GBCategoryChooserPanelController + (int) chooseCategoryIDFromCategories:(NSArray*) inCategories searchRequest:(GBSearchRequest*)inRequest parentWindow:(NSWindow*) inParent {
+}
+- (void) addCategory:(EBayCategoryType*)inCategory toRootTreeCategory:(NSMutableArray*)inRootTreeCategories {
+ GSEbayCategory *category = [rootCategory subcategoryWithID:[[inCategory categoryID] intValue]];
+ if (rootCategory != category) {
+ GSEbayCategory *parent = category;
+ while ((((void*)0) != (parent = [parent parent])) && ([parent categoryID] != 0)) {
+ NSMutableDictionary *treeCategoryDict = [self categoryDictionaryForCategoryID:[parent categoryID] inRootTreeCategories:inRootTreeCategories];
+ if (((void*)0) == treeCategoryDict) {
+ }
+ }
+ }
+}
diff --git a/test/Analysis/pr_2542_rdar_6793404.m b/test/Analysis/pr_2542_rdar_6793404.m
new file mode 100644
index 000000000000..82a028d652d1
--- /dev/null
+++ b/test/Analysis/pr_2542_rdar_6793404.m
@@ -0,0 +1,68 @@
+// RUN: clang-cc -analyze -checker-cfref -pedantic -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -pedantic -analyzer-store=region -verify %s
+
+// BEGIN delta-debugging reduced header stuff
+
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+typedef struct _NSZone NSZone;
+@class NSCoder;
+@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> {}
+- (id)init;
++ (id)alloc;
+@end
+typedef double NSTimeInterval;
+enum { NSAnimationEaseInOut, NSAnimationEaseIn, NSAnimationEaseOut, NSAnimationLinear };
+typedef NSUInteger NSAnimationCurve;
+@interface NSAnimation : NSObject <NSCopying, NSCoding> {}
+- (id)initWithDuration:(NSTimeInterval)duration animationCurve:(NSAnimationCurve)animationCurve;
+- (void)startAnimation;
+- (void)setDelegate:(id)delegate;
+@end
+
+// END delta-debugging reduced header stuff
+
+// From NSAnimation Class Reference
+// -(void)startAnimation
+// The receiver retains itself and is then autoreleased at the end
+// of the animation or when it receives stopAnimation.
+
+@interface MyClass { }
+- (void)animationDidEnd:(NSAnimation *)animation;
+@end
+
+@implementation MyClass
+- (void)f1 {
+ // NOTE: The analyzer doesn't really handle this; it just stops tracking
+ // 'animation' when it is sent the message 'setDelegate:'.
+ NSAnimation *animation = [[NSAnimation alloc] // no-warning
+ initWithDuration:1.0
+ animationCurve:NSAnimationEaseInOut];
+
+ [animation setDelegate:self];
+ [animation startAnimation];
+}
+
+- (void)f2 {
+ NSAnimation *animation = [[NSAnimation alloc] // expected-warning{{leak}}
+ initWithDuration:1.0
+ animationCurve:NSAnimationEaseInOut];
+
+ [animation startAnimation];
+}
+
+- (void)animationDidEnd:(NSAnimation *)animation {
+ [animation release];
+}
+@end
diff --git a/test/Analysis/pr_4164.c b/test/Analysis/pr_4164.c
new file mode 100644
index 000000000000..cc2479c3e49c
--- /dev/null
+++ b/test/Analysis/pr_4164.c
@@ -0,0 +1,41 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -checker-cfref -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -checker-cfref -analyzer-store=region -verify %s
+
+// PR 4164: http://llvm.org/bugs/show_bug.cgi?id=4164
+//
+// Eventually this should be pulled into misc-ps.m. This is in a separate test
+// file for now to play around with the specific issues for BasicStoreManager
+// and StoreManager (i.e., we can make a copy of this file for either
+// StoreManager should one start to fail in the near future).
+//
+// The basic issue is that the VarRegion for 'size' is casted to (char*),
+// resulting in an ElementRegion. 'getsockopt' is an unknown function that
+// takes a void*, which means the ElementRegion should get stripped off.
+typedef unsigned int __uint32_t;
+typedef __uint32_t __darwin_socklen_t;
+typedef __darwin_socklen_t socklen_t;
+int getsockopt(int, int, int, void * restrict, socklen_t * restrict);
+
+int test1() {
+ int s = -1;
+ int size;
+ socklen_t size_len = sizeof(size);
+ if (getsockopt(s, 0xffff, 0x1001, (char *)&size, &size_len) < 0)
+ return -1;
+
+ return size; // no-warning
+}
+
+// Similar case: instead of passing a 'void*', we pass 'char*'. In this
+// case we pass an ElementRegion to the invalidation logic. Since it is
+// an ElementRegion that just layers on top of another typed region and the
+// ElementRegion itself has elements whose type are integral (essentially raw
+// data) we strip off the ElementRegion when doing the invalidation.
+int takes_charptr(char* p);
+int test2() {
+ int size;
+ if (takes_charptr((char*)&size))
+ return -1;
+ return size; // no-warning
+}
+
diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c
new file mode 100644
index 000000000000..ea8b7f566615
--- /dev/null
+++ b/test/Analysis/ptr-arith.c
@@ -0,0 +1,34 @@
+// RUN: clang-cc -analyze -checker-simple -analyzer-store=region -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify -triple i686-apple-darwin9 %s
+
+void f1() {
+ int a[10];
+ int *p = a;
+ ++p;
+}
+
+char* foo();
+
+void f2() {
+ char *p = foo();
+ ++p;
+}
+
+// This test case checks if we get the right rvalue type of a TypedViewRegion.
+// The ElementRegion's type depends on the array region's rvalue type. If it was
+// a pointer type, we would get a loc::SymbolVal for '*p'.
+char* memchr();
+static int
+domain_port (const char *domain_b, const char *domain_e,
+ const char **domain_e_ptr)
+{
+ int port = 0;
+
+ const char *p;
+ const char *colon = memchr (domain_b, ':', domain_e - domain_b);
+
+ for (p = colon + 1; p < domain_e ; p++)
+ port = 10 * port + (*p - '0');
+ return port;
+}
diff --git a/test/Analysis/rdar-6442306-1.m b/test/Analysis/rdar-6442306-1.m
new file mode 100644
index 000000000000..15d349884093
--- /dev/null
+++ b/test/Analysis/rdar-6442306-1.m
@@ -0,0 +1,31 @@
+// RUN: clang-cc -analyze -checker-cfref %s --analyzer-store=basic -verify &&
+// RUN: clang-cc -analyze -checker-cfref %s --analyzer-store=region -verify
+
+typedef int bar_return_t;
+typedef struct {
+ unsigned char int_rep;
+} Foo_record_t;
+extern Foo_record_t Foo_record;
+struct QuxSize {};
+typedef struct QuxSize QuxSize;
+typedef struct {
+ Foo_record_t Foo;
+ QuxSize size;
+} __Request__SetPortalSize_t;
+
+static __inline__ bar_return_t
+__Beeble_check__Request__SetPortalSize_t(__attribute__((__unused__)) __Request__SetPortalSize_t *In0P) {
+ if (In0P->Foo.int_rep != Foo_record.int_rep) {
+ do {
+ int __i__, __C__ = (2);
+ for (__i__ = 0;
+ __i__ < __C__;
+ __i__++) do {
+ *(&((double *)(&In0P->size))[__i__]) =
+ __Foo_READSWAP__double(&((double *)(&In0P->size))[__i__]);
+ }
+ while (0);
+ }
+ while (0);
+ }
+}
diff --git a/test/Analysis/rdar-6539791.c b/test/Analysis/rdar-6539791.c
new file mode 100644
index 000000000000..c1c989154337
--- /dev/null
+++ b/test/Analysis/rdar-6539791.c
@@ -0,0 +1,47 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s
+
+typedef const struct __CFAllocator * CFAllocatorRef;
+typedef struct __CFDictionary * CFMutableDictionaryRef;
+typedef signed long CFIndex;
+typedef CFIndex CFNumberType;
+typedef const void * CFTypeRef;
+typedef struct {} CFDictionaryKeyCallBacks, CFDictionaryValueCallBacks;
+typedef const struct __CFNumber * CFNumberRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
+extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
+enum { kCFNumberSInt32Type = 3 };
+CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks);
+void CFDictionaryAddValue(CFMutableDictionaryRef theDict, const void *key, const void *value);
+void CFRelease(CFTypeRef cf);
+CFTypeRef CFRetain(CFTypeRef cf);
+extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr);
+typedef const struct __CFArray * CFArrayRef;
+typedef struct __CFArray * CFMutableArrayRef;
+void CFArrayAppendValue(CFMutableArrayRef theArray, const void *value);
+
+void f(CFMutableDictionaryRef y, void* key, void* val_key) {
+ CFMutableDictionaryRef x = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CFDictionaryAddValue(y, key, x);
+ CFRelease(x); // the dictionary keeps a reference, so the object isn't deallocated yet
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z);
+ if (value) {
+ CFDictionaryAddValue(x, val_key, value); // no-warning
+ CFRelease(value);
+ CFDictionaryAddValue(y, val_key, value); // no-warning
+ }
+}
+
+// <rdar://problem/6560661>
+// Same issue, except with "AppendValue" functions.
+void f2(CFMutableArrayRef x) {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z);
+ // CFArrayAppendValue keeps a reference to value.
+ CFArrayAppendValue(x, value);
+ CFRelease(value);
+ CFRetain(value);
+ CFRelease(value); // no-warning
+}
diff --git a/test/Analysis/rdar-6540084.m b/test/Analysis/rdar-6540084.m
new file mode 100644
index 000000000000..18ab038f6e2e
--- /dev/null
+++ b/test/Analysis/rdar-6540084.m
@@ -0,0 +1,36 @@
+// RUN: clang-cc -analyze -warn-dead-stores -verify %s
+//
+// This test exercises the live variables analysis (LiveVariables.cpp).
+// The case originally identified a non-termination bug.
+//
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+typedef struct _NSZone NSZone;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@interface NSObject <NSObject> {} @end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+@class NSArray;
+@class NSMutableArray, NSIndexSet, NSView, NSPredicate, NSString, NSViewAnimation, NSTimer;
+@interface FooBazController : NSObject {}
+@end
+typedef struct {} TazVersion;
+@class TazNode;
+@interface TazGuttenberg : NSObject {} typedef NSUInteger BugsBunnyType; @end
+@interface FooBaz : NSObject {}
+@property (nonatomic) BugsBunnyType matchType;
+@property (nonatomic, retain) NSArray *papyrus; @end
+@implementation FooBazController
+- (NSArray *)excitingStuff:(FooBaz *)options {
+ BugsBunnyType matchType = options.matchType;
+ NSPredicate *isSearchablePredicate = [NSPredicate predicateWithFormat:@"isSearchable == YES"]; // expected-warning{{receiver 'NSPredicate' is a forward class and corresponding}} // expected-warning{{return type defaults to 'id'}}
+ for (TazGuttenberg *Guttenberg in options.papyrus) {
+ NSArray *GuttenbergNodes = [Guttenberg nodes]; // expected-warning{{return type defaults to 'id'}}
+ NSArray *searchableNodes = [GuttenbergNodes filteredArrayUsingPredicate:isSearchablePredicate]; // expected-warning{{return type defaults to 'id'}}
+ for (TazNode *node in searchableNodes) {
+ switch (matchType) {
+ default: break;
+ }
+ }
+ }
+}
+@end
diff --git a/test/Analysis/rdar-6541136-region.c b/test/Analysis/rdar-6541136-region.c
new file mode 100644
index 000000000000..1e7a2d974bc4
--- /dev/null
+++ b/test/Analysis/rdar-6541136-region.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc -verify -analyze -checker-cfref -analyzer-store=region %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.
+
+
+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; // expected-warning{{out-of-bound memory position}}
+}
diff --git a/test/Analysis/rdar-6541136.c b/test/Analysis/rdar-6541136.c
new file mode 100644
index 000000000000..6e6a479136b9
--- /dev/null
+++ b/test/Analysis/rdar-6541136.c
@@ -0,0 +1,20 @@
+// RUN: clang-cc -verify -analyze -checker-cfref -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
new file mode 100644
index 000000000000..581d6eacf085
--- /dev/null
+++ b/test/Analysis/rdar-6562655.m
@@ -0,0 +1,63 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=basic -verify %s
+//
+// This test case mainly checks that the retain/release checker doesn't crash
+// on this file.
+//
+typedef int int32_t;
+typedef signed char BOOL;
+typedef long NSInteger;
+typedef unsigned long 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 @interface NSObject <NSObject> {}
+@end extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+@interface NSResponder : NSObject <NSCoding> {}
+@end @protocol NSAnimatablePropertyContainer - (id)animator;
+@end extern NSString *NSAnimationTriggerOrderIn ;
+@interface NSView : NSResponder <NSAnimatablePropertyContainer> {
+}
+@end enum {
+NSNullCellType = 0, NSTextCellType = 1, NSImageCellType = 2 };
+typedef struct __CFlags {
+ unsigned int botnet:3;
+}
+ _CFlags;
+@interface Bar : NSObject <NSCopying, NSCoding> {
+ _CFlags _cFlags;
+@private id _support;
+}
+@end extern NSString *NSControlTintDidChangeNotification;
+typedef NSInteger NSBotnet;
+@interface NSControl : NSView {
+}
+@end @class NSAttributedString, NSFont, NSImage, NSSound;
+typedef int32_t Baz;
+@interface Bar(BarInternal) - (void)_setIsWhite:(BOOL)isWhite;
+@end
+@interface Bar (BarBotnetCompatibility)
+- (NSBotnet)_initialBotnetZorg;
+@end
+typedef struct _NSRunArrayItem {
+ unsigned int botnetIsSet:1;
+} BarAuxFlags;
+@interface BarAuxiliary : NSObject {
+@public
+ NSControl *controlView;
+ BarAuxFlags auxCFlags;
+}
+@end
+@implementation Bar
+static Baz Qux = 0;
+- (id)copyWithZone:(NSZone *)zone {}
+- (void)encodeWithCoder:(NSCoder *)coder {}
+@end
+@implementation Bar (BarBotnet)
+- (NSBotnet)botnet {
+ if (!(*(BarAuxiliary **)&self->_support)->auxCFlags.botnetIsSet) {
+ _cFlags.botnet = [self _initialBotnetZorg];
+ }
+}
+@end
diff --git a/test/Analysis/rdar-6582778-basic-store.c b/test/Analysis/rdar-6582778-basic-store.c
new file mode 100644
index 000000000000..9ec38ef7a5f0
--- /dev/null
+++ b/test/Analysis/rdar-6582778-basic-store.c
@@ -0,0 +1,22 @@
+// RUN: clang-cc -analyze -checker-cfref -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
new file mode 100644
index 000000000000..5d1fa37c46a8
--- /dev/null
+++ b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
@@ -0,0 +1,25 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s -verify
+
+typedef struct Foo { int x; } Bar;
+
+@interface MyClass {}
+- (Bar)foo;
+@end
+@implementation MyClass
+- (Bar)foo {
+ struct Foo f = { 0 };
+ return f;
+}
+@end
+
+void createFoo() {
+ MyClass *obj = 0;
+ Bar f = [obj foo]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value (of type 'Bar') to be garbage or otherwise undefined.}}
+}
+
+void createFoo2() {
+ MyClass *obj = 0;
+ [obj foo]; // no-warning
+ Bar f = [obj foo]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value (of type 'Bar') to be garbage or otherwise undefined.}}
+}
+
diff --git a/test/Analysis/refcnt_naming.m b/test/Analysis/refcnt_naming.m
new file mode 100644
index 000000000000..bea404799ba3
--- /dev/null
+++ b/test/Analysis/refcnt_naming.m
@@ -0,0 +1,62 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s
+
+typedef const struct __CFString * CFStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+typedef const struct __CFURL * CFURLRef;
+extern CFURLRef CFURLCreateWithString(CFAllocatorRef allocator, CFStringRef URLString, CFURLRef baseURL);
+typedef signed char BOOL;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@interface NSObject <NSObject> {} @end
+@class NSArray, NSString, NSURL;
+
+@interface NamingTest : NSObject {}
+-(NSObject*)photocopy; // read as "photocopy"
+-(NSObject*)photoCopy; // read as "photo Copy"
+-(NSObject*)__blebPRCopy; // read as "bleb PRCopy"
+-(NSObject*)__blebPRcopy; // read as "bleb P Rcopy"
+-(NSObject*)new_theprefixdoesnotcount; // read as "theprefixdoesnotcount"
+-(NSObject*)newestAwesomeStuff; // read as "newest awesome stuff"
+
+@end
+
+@interface MyClass : NSObject
+{
+ id myObject;
+}
+- (NSURL *)myMethod:(NSString *)inString;
+- (NSURL *)getMethod:(NSString*)inString;
+- (void)addObject:(id)X;
+@end
+
+@implementation MyClass
+
+- (NSURL *)myMethod:(NSString *)inString
+{
+ NSURL *url = (NSURL *)CFURLCreateWithString(0, (CFStringRef)inString, 0); // expected-warning{{leak}}
+ return url;
+}
+
+- (NSURL *)getMethod:(NSString *)inString
+{
+ NSURL *url = (NSURL *)CFURLCreateWithString(0, (CFStringRef)inString, 0);
+ [self addObject:url];
+ return url; // no-warning
+}
+
+void testNames(NamingTest* x) {
+ [x photocopy]; // no-warning
+ [x photoCopy]; // expected-warning{{leak}}
+ [x __blebPRCopy]; // expected-warning{{leak}}
+ [x __blebPRcopy]; // no-warning
+ [x new_theprefixdoesnotcount]; // no-warning
+ [x newestAwesomeStuff]; // no-warning
+}
+
+
+- (void)addObject:(id)X
+{
+ myObject = X;
+}
+
+@end
diff --git a/test/Analysis/region-1.m b/test/Analysis/region-1.m
new file mode 100644
index 000000000000..ed172e431e99
--- /dev/null
+++ b/test/Analysis/region-1.m
@@ -0,0 +1,90 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s
+//
+// This test case simply should not crash. It evaluates the logic of not
+// using MemRegion::getRValueType in incorrect places.
+
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject - (BOOL)isEqual:(id)object;
+- (Class)class;
+- (BOOL)isLegOfClass:(Class)aClass;
+@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end @interface NSObject <NSObject> {
+}
+@end @class NSArray;
+@interface NSResponder : NSObject <NSCoding> {
+}
+@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView;
+@class JabasectItem;
+@protocol EcoClassifier;
+@protocol EcoClassInterfaceCommons <EcoClassifier> @end @protocol EcoImplementation;
+@protocol EcoBehavioredClassifier <EcoClassInterfaceCommons> - (NSArray *) implementations;
+@end enum {
+CK_UNRESTRICTED= 0, CK_READ_ONLY, CK_ADD_ONLY, CK_REMOVE_ONLY };
+@protocol EcoClass <EcoBehavioredClassifier> - (NSArray *) ownedAttributes;
+@end @protocol EcoNamespace;
+@protocol EcoType;
+@protocol EcoClassifier <EcoNamespace,EcoType> - (NSArray *) features;
+@end @protocol EcoComment;
+@protocol EcoElement <NSObject> - (NSArray *) ownedElements;
+@end @protocol EcoDirectedRelationship;
+@protocol EcoNamedElement <EcoElement> - (NSString *) name;
+@end extern NSString *const JabaPathSeparator;
+@protocol EcoNamespace <EcoNamedElement> - (NSArray *) Legs;
+@end enum {
+PDK_IN=0, PDK_INOUT, PDK_OUT, PDK_RETURN };
+@interface EcoElementImp : NSObject <EcoElement, NSCoding> {
+}
+@end @class EcoNamespace;
+@interface EcoNamedElementImp : EcoElementImp <EcoNamedElement>{
+}
+@end @interface EcoNamespaceImp : EcoNamedElementImp <EcoNamespace> {
+}
+@end @class JabaSCDocController, JabaSCDisplaySpecification;
+@interface JabaSCSharedDiagramViewController : NSObject {
+}
+@end extern NSString *const JabaSCsectGraphicNamesectIdentifier;
+@interface EcoClassifierImp : EcoNamespaceImp <EcoClassifier> {
+}
+@end @class EcoOperationImp;
+@interface EcoClassImp : EcoClassifierImp <EcoClass> {
+}
+@end extern NSString *const JabaAddedUMLElements;
+@class JabaSCClass, JabaSCInterface, JabaSCOperation;
+@class DosLegVaseSymbol, DosProtocolSymbol, DosMethodSymbol, DosFileReference;
+@interface HancodeFett : NSObject {
+}
++ (DosLegVaseSymbol *) symbolFromClass: (JabaSCClass *) clz;
+@end enum _JabaSourceLanguage {
+JabaSourceUnknown=0, JabaSourcePrawn, JabaSourceC, JabaSourceCPP, JabaSourceObjectiveC };
+typedef NSUInteger JabaSourceLanguage;
+@protocol JabaSCClassifier <EcoClassInterfaceCommons> - (JabaSourceLanguage)language;
+@end @interface JabaSCClass : EcoClassImp <JabaSCClassifier> {
+}
+@end @class DosGlobalID, DosPQuLC, DosPQuUnLC;
+@protocol XCProxyObjectProtocol - (id) representedObject;
+@end typedef union _Dossymbollocation {
+}
+ DosRecordArrPrl;
+@interface DosIndexEntry : NSObject {
+}
+@end @class DosProjectIndex, DosTextPapyruswiggle, DosDocPapyruswiggle, DosLegVaseSymbol;
+@interface DosSymbol : DosIndexEntry {
+}
+@end @interface DosLegVaseSymbol : DosSymbol {
+}
+@end typedef enum _DosTextRangeType {
+Dos_CharacterRangeType = 0, Dos_LineRangeType = 1 }
+ DosTextRangeType;
+@implementation JabaSCSharedDiagramViewController + (NSImage *)findImageNamed:(NSString *)name {
+}
+- (void)revealSourceInEditor:(JabasectItem *)sectItem duperGesture:(BOOL)duperGesture {
+ id <EcoNamedElement> selectedElement = [sectItem representedObject];
+ id <EcoNamedElement> selectedClassifier = selectedElement;
+ DosSymbol *symbol=((void *)0);
+ if([selectedClassifier isLegOfClass:[JabaSCClass class]]) {
+ symbol = [HancodeFett symbolFromClass:(JabaSCClass *) selectedClassifier];
+ }
+}
diff --git a/test/Analysis/region-only-test.c b/test/Analysis/region-only-test.c
new file mode 100644
index 000000000000..fdc740488a2c
--- /dev/null
+++ b/test/Analysis/region-only-test.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -analyze -checker-simple -analyzer-store=region -verify %s
+
+// Region store must be enabled for tests in this file.
+
+// Exercise creating ElementRegion with symbolic super region.
+void foo(int* p) {
+ int *x;
+ int a;
+ if (p[0] == 1)
+ x = &a;
+ if (p[0] == 1)
+ *x; // no-warning
+}
diff --git a/test/Analysis/retain-release-basic-store.m b/test/Analysis/retain-release-basic-store.m
new file mode 100644
index 000000000000..b16c231ce23b
--- /dev/null
+++ b/test/Analysis/retain-release-basic-store.m
@@ -0,0 +1,102 @@
+// RUN: clang-cc -analyze -checker-cfref -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 = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3e)&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 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
new file mode 100644
index 000000000000..70ad54f8aa4a
--- /dev/null
+++ b/test/Analysis/retain-release-gc-only.m
@@ -0,0 +1,161 @@
+// RUN: clang-cc -analyze -checker-cfref -verify -fobjc-gc-only %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -fobjc-gc-only -verify %s
+
+//===----------------------------------------------------------------------===//
+// Header stuff.
+//===----------------------------------------------------------------------===//
+
+typedef unsigned int __darwin_natural_t;
+typedef struct {} div_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);
+extern void CFArrayAppendValue(CFMutableArrayRef theArray, const void *value);
+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;
+extern CFAbsoluteTime CFAbsoluteTimeGetCurrent(void);
+typedef const struct __CFDate * CFDateRef;
+extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at);
+extern CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate);
+typedef __darwin_natural_t natural_t;
+typedef natural_t mach_port_name_t;
+typedef mach_port_name_t mach_port_t;
+typedef struct {
+}
+CFRunLoopObserverContext;
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+@class NSString, Protocol;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject - (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+- (id)autorelease;
+@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
+@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
++ (id)alloc;
++ (id)allocWithZone:(NSZone *)zone;
+@end typedef float CGFloat;
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
+- (const char *)UTF8String;
+- (id)initWithUTF8String:(const char *)nullTerminatedCString;
++ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
+- (id)init;
+- (void)dealloc;
+@end extern NSString * const NSCurrentLocaleDidChangeNotification ;
+@protocol NSLocking - (void)lock;
+@end extern NSString * const NSUndoManagerCheckpointNotification;
+typedef enum {
+ACL_READ_DATA = (1<<1), ACL_LIST_DIRECTORY = (1<<1), ACL_WRITE_DATA = (1<<2), ACL_ADD_FILE = (1<<2), ACL_EXECUTE = (1<<3), ACL_SEARCH = (1<<3), ACL_DELETE = (1<<4), ACL_APPEND_DATA = (1<<5), ACL_ADD_SUBDIRECTORY = (1<<5), ACL_DELETE_CHILD = (1<<6), ACL_READ_ATTRIBUTES = (1<<7), ACL_WRITE_ATTRIBUTES = (1<<8), ACL_READ_EXTATTRIBUTES = (1<<9), ACL_WRITE_EXTATTRIBUTES = (1<<10), ACL_READ_SECURITY = (1<<11), ACL_WRITE_SECURITY = (1<<12), ACL_CHANGE_OWNER = (1<<13) }
+acl_entry_id_t;
+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 NSResponder : NSObject <NSCoding> {
+}
+@end @class NSColor, NSFont, NSNotification;
+typedef struct __CFlags {
+}
+_CFlags;
+@interface NSCell : NSObject <NSCopying, NSCoding> {
+}
+@end @class NSDate, NSDictionary, NSError, NSException, NSNotification;
+@interface NSManagedObjectContext : NSObject <NSCoding, NSLocking> {
+}
+@end enum {
+kDAReturnSuccess = 0, kDAReturnError = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3e)&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 );
+
+CFTypeRef CFMakeCollectable(CFTypeRef cf) ;
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+void f1() {
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+ id x = [(id) A autorelease];
+ CFRelease((CFMutableArrayRef) x);
+}
+
+void f2() {
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{leak}}
+ id x = [(id) A retain];
+ [x release];
+ [x release];
+}
+
+void f3() {
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{leak}}
+ CFMakeCollectable(A);
+ CFRetain(A);
+}
+
+// Test return of non-owned objects in contexts where an owned object
+// is expected.
+@interface TestReturnNotOwnedWhenExpectedOwned
+- (NSString*)newString;
+- (CFMutableArrayRef)newArray;
+@end
+
+@implementation TestReturnNotOwnedWhenExpectedOwned
+- (NSString*)newString {
+ NSString *s = [NSString stringWithUTF8String:"hello"]; // expected-warning{{Potential leak (when using garbage collection) of an object allocated on line 136 and stored into 's'}}
+ CFRetain(s);
+ return s;
+}
+- (CFMutableArrayRef)newArray{
+ return CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// Tests of ownership attributes.
+//===----------------------------------------------------------------------===//
+
+@interface TestOwnershipAttr : NSObject
+- (NSString*) returnsAnOwnedString __attribute__((ns_returns_retained));
+- (NSString*) returnsAnOwnedCFString __attribute__((cf_returns_retained));
+@end
+
+void test_attr_1(TestOwnershipAttr *X) {
+ NSString *str = [X returnsAnOwnedString]; // no-warning
+}
+
+void test_attr_1b(TestOwnershipAttr *X) {
+ NSString *str = [X returnsAnOwnedCFString]; // expected-warning{{leak}}
+}
+
diff --git a/test/Analysis/retain-release-region-store.m b/test/Analysis/retain-release-region-store.m
new file mode 100644
index 000000000000..66950e2190ed
--- /dev/null
+++ b/test/Analysis/retain-release-region-store.m
@@ -0,0 +1,118 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -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 = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3e)&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 *issue* an error when we store the pointer
+// to a struct. This differs from basic store.
+
+struct foo {
+ NSDate* f;
+};
+
+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); // expected-warning{{Reference-counted object is used after it is released.}}
+ return t;
+}
+
+// Test that assigning to an self.ivar loses track of an object.
+// This is a temporary hack to reduce false positives.
+@interface Test3 : NSObject {
+ id myObj;
+}
+- (void)test_self_assign_ivar;
+@end
+
+@implementation Test3
+- (void)test_self_assign_ivar {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t); // no-warning
+ myObj = (id) date;
+}
+@end
+
+
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
new file mode 100644
index 000000000000..3ff007ed8b3a
--- /dev/null
+++ b/test/Analysis/retain-release.m
@@ -0,0 +1,708 @@
+//>>SLICER
+// RUN: clang-cc -analyze -checker-cfref -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s
+
+//===----------------------------------------------------------------------===//
+// The following code is reduced using delta-debugging from Mac OS X headers:
+//
+// #include <Cocoa/Cocoa.h>
+// #include <CoreFoundation/CoreFoundation.h>
+// #include <DiskArbitration/DiskArbitration.h>
+// #include <QuartzCore/QuartzCore.h>
+// #include <Quartz/Quartz.h>
+//
+// It includes the basic definitions for the test cases below.
+//===----------------------------------------------------------------------===//
+
+typedef unsigned int __darwin_natural_t;
+typedef unsigned int UInt32;
+typedef signed long CFIndex;
+typedef const void * CFTypeRef;
+typedef const struct __CFString * CFStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+extern void CFRelease(CFTypeRef cf);
+extern const CFAllocatorRef kCFAllocatorDefault;
+typedef struct {
+}
+CFArrayCallBacks;
+extern const CFArrayCallBacks kCFTypeArrayCallBacks;
+typedef const struct __CFArray * CFArrayRef;
+typedef struct __CFArray * CFMutableArrayRef;
+extern CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks);
+extern const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx);
+extern void CFArrayAppendValue(CFMutableArrayRef theArray, const void *value);
+typedef 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;
+extern CFAbsoluteTime CFAbsoluteTimeGetCurrent(void);
+typedef const struct __CFDate * CFDateRef;
+extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at);
+CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate);
+enum {
+kCFCalendarComponentsWrap = (1UL << 0) };
+typedef __darwin_natural_t natural_t;
+typedef natural_t mach_port_name_t;
+typedef mach_port_name_t mach_port_t;
+typedef int kern_return_t;
+typedef kern_return_t mach_error_t;
+typedef signed char BOOL;
+typedef unsigned long NSUInteger;
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject - (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+- (id)autorelease;
+@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
+@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end @interface NSObject <NSObject> {
+}
++ (id)allocWithZone:(NSZone *)zone;
++ (id)alloc;
+- (void)dealloc;
+@end extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+typedef struct {
+}
+NSFastEnumerationState;
+@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end @interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+@end @interface NSArray (NSArrayCreation) + (id)array;
+@end @interface NSAutoreleasePool : NSObject {
+}
+- (void)drain;
+@end typedef double NSTimeInterval;
+@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate;
+@end enum {
+NSWrapCalendarComponents = kCFCalendarComponentsWrap, };
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
+- ( const char *)UTF8String;
+- (id)initWithUTF8String:(const char *)nullTerminatedCString;
++ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
+@end @interface NSData : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
+@end @interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+@end @interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey;
+- (void)setObject:(id)anObject forKey:(id)aKey;
+@end @interface NSMutableDictionary (NSMutableDictionaryCreation) + (id)dictionaryWithCapacity:(NSUInteger)numItems;
+struct CGRect {
+};
+typedef struct CGRect CGRect;
+- (id)init;
+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 );
+typedef struct CGColorSpace *CGColorSpaceRef;
+typedef struct CGImage *CGImageRef;
+@end @class CIContext;
+@class NSArray, NSError, NSEvent, NSMenu, NSUndoManager, NSWindow;
+@interface NSResponder : NSObject <NSCoding> {
+}
+@end @protocol NSAnimatablePropertyContainer - (id)animator;
+@end extern NSString *NSAnimationTriggerOrderIn ;
+@interface NSView : NSResponder <NSAnimatablePropertyContainer> {
+}
+@end @class NSColor, NSFont, NSNotification;
+@protocol NSValidatedUserInterfaceItem - (SEL)action;
+@end @protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem;
+@end typedef struct NSThreadPrivate _NSThreadPrivate;
+@interface NSApplication : NSResponder <NSUserInterfaceValidations> {
+}
+@end enum {
+NSTerminateCancel = 0, NSTerminateNow = 1, NSTerminateLater = 2 };
+typedef NSUInteger NSApplicationTerminateReply;
+@protocol NSApplicationDelegate <NSObject> @optional - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
+@end enum {
+NSUserInterfaceLayoutDirectionLeftToRight = 0, NSUserInterfaceLayoutDirectionRightToLeft = 1 };
+@interface CIImage : NSObject <NSCoding, NSCopying> {
+}
+typedef int CIFormat;
+typedef struct __SFlags {
+}
+_SFlags;
+@end extern NSString * const kCAGravityCenter __attribute__((visibility("default")));
+enum {
+kDAReturnSuccess = 0, kDAReturnError = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3e)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0C };
+typedef mach_error_t DAReturn;
+typedef const struct __DADissenter * DADissenterRef;
+extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string );
+@interface CIContext: NSObject {
+}
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r;
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs;
+@end @protocol QCCompositionRenderer @end @interface QCRenderer : NSObject <QCCompositionRenderer> {
+}
+- (id) createSnapshotImageOfType:(NSString*)type;
+@end @interface QCView : NSView <QCCompositionRenderer> {
+}
+- (id) createSnapshotImageOfType:(NSString*)type;
+@end
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+CFAbsoluteTime f1() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ CFRetain(date);
+ CFRelease(date);
+ CFDateGetAbsoluteTime(date); // no-warning
+ CFRelease(date);
+ t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}}
+ return t;
+}
+
+CFAbsoluteTime f2() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ [((NSDate*) date) retain];
+ CFRelease(date);
+ CFDateGetAbsoluteTime(date); // no-warning
+ [((NSDate*) date) release];
+ t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}}
+ return t;
+}
+
+
+NSDate* global_x;
+
+// Test to see if we supresss an error when we store the pointer
+// to a global.
+
+CFAbsoluteTime f3() {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t);
+ [((NSDate*) date) retain];
+ CFRelease(date);
+ CFDateGetAbsoluteTime(date); // no-warning
+ global_x = (NSDate*) date;
+ [((NSDate*) date) release];
+ t = CFDateGetAbsoluteTime(date); // no-warning
+ return t;
+}
+
+//---------------------------------------------------------------------------
+// Test case 'f4' differs for region store and basic store. See
+// retain-release-region-store.m and retain-release-basic-store.m.
+//---------------------------------------------------------------------------
+
+// Test a leak.
+
+CFAbsoluteTime f5(int x) {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ CFDateRef date = CFDateCreate(0, t); // expected-warning{{leak}}
+
+ if (x)
+ CFRelease(date);
+
+ return t;
+}
+
+// Test a leak involving the return.
+
+CFDateRef f6(int x) {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); // expected-warning{{leak}}
+ CFRetain(date);
+ return date;
+}
+
+// Test a leak involving an overwrite.
+
+CFDateRef f7() {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); //expected-warning{{leak}}
+ CFRetain(date);
+ date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+ return date;
+}
+
+// Generalization of Create rule. MyDateCreate returns a CFXXXTypeRef, and
+// has the word create.
+CFDateRef MyDateCreate();
+
+CFDateRef f8() {
+ CFDateRef date = MyDateCreate(); // expected-warning{{leak}}
+ CFRetain(date);
+ return date;
+}
+
+CFDateRef f9() {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+ int *p = 0;
+ // When allocations fail, CFDateCreate can return null.
+ if (!date) *p = 1; // expected-warning{{null}}
+ return date;
+}
+
+// Handle DiskArbitration API:
+//
+// http://developer.apple.com/DOCUMENTATION/DARWIN/Reference/DiscArbitrationFramework/
+//
+void f10(io_service_t media, DADiskRef d, CFStringRef s) {
+ DADiskRef disk = DADiskCreateFromBSDName(kCFAllocatorDefault, 0, "hello"); // expected-warning{{leak}}
+ if (disk) NSLog(@"ok");
+
+ disk = DADiskCreateFromIOMedia(kCFAllocatorDefault, 0, media); // expected-warning{{leak}}
+ if (disk) NSLog(@"ok");
+
+ CFDictionaryRef dict = DADiskCopyDescription(d); // expected-warning{{leak}}
+ if (dict) NSLog(@"ok");
+
+ disk = DADiskCopyWholeDisk(d); // expected-warning{{leak}}
+ if (disk) NSLog(@"ok");
+
+ DADissenterRef dissenter = DADissenterCreate(kCFAllocatorDefault, // expected-warning{{leak}}
+ kDAReturnSuccess, s);
+ if (dissenter) NSLog(@"ok");
+
+ DASessionRef session = DASessionCreate(kCFAllocatorDefault); // expected-warning{{leak}}
+ if (session) NSLog(@"ok");
+}
+
+// Test retain/release checker with CFString and CFMutableArray.
+void f11() {
+ // Create the array.
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+
+ // Create a string.
+ CFStringRef s1 = CFStringCreateWithCString(0, "hello world",
+ kCFStringEncodingUTF8);
+
+ // Add the string to the array.
+ CFArrayAppendValue(A, s1);
+
+ // Decrement the reference count.
+ CFRelease(s1); // no-warning
+
+ // Get the string. We don't own it.
+ s1 = (CFStringRef) CFArrayGetValueAtIndex(A, 0);
+
+ // Release the array.
+ CFRelease(A); // no-warning
+
+ // Release the string. This is a bug.
+ CFRelease(s1); // expected-warning{{Incorrect decrement of the reference count}}
+}
+
+// PR 3337: Handle functions declared using typedefs.
+typedef CFTypeRef CREATEFUN();
+CREATEFUN MyCreateFun;
+
+void f12() {
+ CFTypeRef o = MyCreateFun(); // expected-warning {{leak}}
+}
+
+void f13_autorelease() {
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+ [(id) A autorelease]; // no-warning
+}
+
+void f13_autorelease_b() {
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+ [(id) A autorelease];
+ [(id) A autorelease]; // expected-warning{{Object sent -autorelease too many times}}
+}
+
+CFMutableArrayRef f13_autorelease_c() {
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+ [(id) A autorelease];
+ [(id) A autorelease];
+ return A; // expected-warning{{Object sent -autorelease too many times}}
+}
+
+CFMutableArrayRef f13_autorelease_d() {
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+ [(id) A autorelease];
+ [(id) A autorelease];
+ CFMutableArrayRef B = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{Object sent -autorelease too many times}}
+ CFRelease(B); // no-warning
+}
+
+
+// This case exercises the logic where the leak site is the same as the allocation site.
+void f14_leakimmediately() {
+ CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{leak}}
+}
+
+// Test that we track an allocated object beyond the point where the *name*
+// of the variable storing the reference is no longer live.
+void f15() {
+ // Create the array.
+ CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
+ CFMutableArrayRef *B = &A;
+ // At this point, the name 'A' is no longer live.
+ CFRelease(*B); // no-warning
+}
+
+
+// Test basic tracking of ivars associated with 'self'. For the retain/release
+// checker we currently do not want to flag leaks associated with stores
+// of tracked objects to ivars.
+@interface SelfIvarTest : NSObject {
+ id myObj;
+}
+- (void)test_self_tracking;
+@end
+
+@implementation SelfIvarTest
+- (void)test_self_tracking {
+ myObj = (id) CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // no-warning
+}
+@end
+
+// Test return of non-owned objects in contexts where an owned object
+// is expected.
+@interface TestReturnNotOwnedWhenExpectedOwned
+- (NSString*)newString;
+@end
+
+@implementation TestReturnNotOwnedWhenExpectedOwned
+- (NSString*)newString {
+ NSString *s = [NSString stringWithUTF8String:"hello"];
+ return s; // expected-warning{{Object with +0 retain counts returned to caller where a +1 (owning) retain count is expected}}
+}
+@end
+
+// <rdar://problem/6659160>
+int isFoo(char c);
+
+static void rdar_6659160(char *inkind, char *inname)
+{
+ // We currently expect that [NSObject alloc] cannot fail. This
+ // will be a toggled flag in the future. It can indeed return null, but
+ // Cocoa programmers generally aren't expected to reason about out-of-memory
+ // conditions.
+ NSString *kind = [[NSString alloc] initWithUTF8String:inkind]; // expected-warning{{leak}}
+
+ // We do allow stringWithUTF8String to fail. This isn't really correct, as
+ // far as returning 0. In most error conditions it will throw an exception.
+ // If allocation fails it could return 0, but again this
+ // isn't expected.
+ NSString *name = [NSString stringWithUTF8String:inname];
+ if(!name)
+ return;
+
+ const char *kindC = 0;
+ const char *nameC = 0;
+
+ // In both cases, we cannot reach a point down below where we
+ // dereference kindC or nameC with either being null. This is because
+ // we assume that [NSObject alloc] doesn't fail and that we have the guard
+ // up above.
+
+ if(kind)
+ kindC = [kind UTF8String];
+ if(name)
+ nameC = [name UTF8String];
+ if(!isFoo(kindC[0])) // expected-warning{{null}}
+ return;
+ if(!isFoo(nameC[0])) // no-warning
+ return;
+
+ [kind release];
+ [name release]; // expected-warning{{Incorrect decrement of the reference count}}
+}
+
+// PR 3677 - 'allocWithZone' should be treated as following the Cocoa naming
+// conventions with respect to 'return'ing ownership.
+@interface PR3677: NSObject @end
+@implementation PR3677
++ (id)allocWithZone:(NSZone *)inZone {
+ return [super allocWithZone:inZone]; // no-warning
+}
+@end
+
+// PR 3820 - Reason about calls to -dealloc
+void pr3820_DeallocInsteadOfRelease(void)
+{
+ id foo = [[NSString alloc] init]; // no-warning
+ [foo dealloc];
+ // foo is not leaked, since it has been deallocated.
+}
+
+void pr3820_ReleaseAfterDealloc(void)
+{
+ id foo = [[NSString alloc] init];
+ [foo dealloc];
+ [foo release]; // expected-warning{{used after it is release}}
+ // NSInternalInconsistencyException: message sent to deallocated object
+}
+
+void pr3820_DeallocAfterRelease(void)
+{
+ NSLog(@"\n\n[%s]", __FUNCTION__);
+ id foo = [[NSString alloc] init];
+ [foo release];
+ [foo dealloc]; // expected-warning{{used after it is released}}
+ // message sent to released object
+}
+
+// From <rdar://problem/6704930>. The problem here is that 'length' binds to
+// '($0 - 1)' after '--length', but SimpleConstraintManager doesn't know how to
+// reason about '($0 - 1) > constant'. As a temporary hack, we drop the value
+// of '($0 - 1)' and conjure a new symbol.
+void rdar6704930(unsigned char *s, unsigned int length) {
+ NSString* name = 0;
+ if (s != 0) {
+ if (length > 0) {
+ while (length > 0) {
+ if (*s == ':') {
+ ++s;
+ --length;
+ name = [[NSString alloc] init]; // no-warning
+ break;
+ }
+ ++s;
+ --length;
+ }
+ if ((length == 0) && (name != 0)) {
+ [name release];
+ name = 0;
+ }
+ if (length == 0) { // no ':' found -> use it all as name
+ name = [[NSString alloc] init]; // no-warning
+ }
+ }
+ }
+
+ if (name != 0) {
+ [name release];
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6833332>
+// One build of the analyzer accidentally stopped tracking the allocated
+// object after the 'retain'.
+//===----------------------------------------------------------------------===//
+
+@interface rdar_6833332 : NSObject <NSApplicationDelegate> {
+ NSWindow *window;
+}
+@property (nonatomic, retain) NSWindow *window;
+@end
+
+@implementation rdar_6833332
+@synthesize window;
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
+ NSMutableDictionary *dict = [[NSMutableDictionary dictionaryWithCapacity:4] retain]; // expected-warning{{leak}}
+
+ [dict setObject:@"foo" forKey:@"bar"];
+
+ NSLog(@"%@", dict);
+}
+- (void)dealloc {
+ [window release];
+ [super dealloc];
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6257780> clang checker fails to catch use-after-release
+//===----------------------------------------------------------------------===//
+
+int rdar_6257780_Case1() {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ NSArray *array = [NSArray array];
+ [array release]; // expected-warning{{Incorrect decrement of the reference count of an object is not owned at this point by the caller}}
+ [pool drain];
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6866843> Checker should understand new/setObject:/release constructs
+//===----------------------------------------------------------------------===//
+
+void rdar_6866843() {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ NSMutableDictionary* dictionary = [[NSMutableDictionary alloc] init];
+ NSArray* array = [[NSArray alloc] init];
+ [dictionary setObject:array forKey:@"key"];
+ [array release];
+ // Using 'array' here should be fine
+ NSLog(@"array = %@\n", array); // no-warning
+ // Now the array is released
+ [dictionary release];
+ [pool drain];
+}
+
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6877235> Classes typedef-ed to CF objects should get the same treatment as CF objects
+//===----------------------------------------------------------------------===//
+
+typedef CFTypeRef OtherRef;
+
+@interface RDar6877235 : NSObject {}
+- (CFTypeRef)_copyCFTypeRef;
+- (OtherRef)_copyOtherRef;
+@end
+
+@implementation RDar6877235
+- (CFTypeRef)_copyCFTypeRef {
+ return [[NSString alloc] init]; // no-warning
+}
+- (OtherRef)_copyOtherRef {
+ return [[NSString alloc] init]; // no-warning
+}
+@end
+
+//===----------------------------------------------------------------------===//
+//<rdar://problem/6320065> false positive - init method returns an object owned by caller
+//===----------------------------------------------------------------------===//
+
+@interface RDar6320065 : NSObject {
+ NSString *_foo;
+}
+- (id)initReturningNewClass;
+- (id)initReturningNewClassBad;
+- (id)initReturningNewClassBad2;
+@end
+
+@interface RDar6320065Subclass : RDar6320065
+@end
+
+@implementation RDar6320065
+- (id)initReturningNewClass {
+ [self release];
+ self = [[RDar6320065Subclass alloc] init]; // no-warning
+ return self;
+}
+- (id)initReturningNewClassBad {
+ [self release];
+ [[RDar6320065Subclass alloc] init]; // expected-warning {{leak}}
+ return self;
+}
+- (id)initReturningNewClassBad2 {
+ [self release];
+ self = [[RDar6320065Subclass alloc] init];
+ return [self autorelease]; // expected-warning{{Object with +0 retain counts returned to caller where a +1 (owning) retain count is expected}}
+}
+
+@end
+
+@implementation RDar6320065Subclass
+@end
+
+int RDar6320065_test() {
+ RDar6320065 *test = [[RDar6320065 alloc] init]; // no-warning
+ [test release];
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6859457> [NSData dataWithBytesNoCopy] does not return a retained object
+//===----------------------------------------------------------------------===//
+
+@interface RDar6859457 : NSObject {}
+- (NSString*) NoCopyString;
+- (NSString*) noCopyString;
+@end
+
+@implementation RDar6859457
+- (NSString*) NoCopyString { return [[NSString alloc] init]; } // no-warning
+- (NSString*) noCopyString { return [[NSString alloc] init]; } // no-warning
+@end
+
+void test_RDar6859457(RDar6859457 *x, void *bytes, NSUInteger dataLength) {
+ [x NoCopyString]; // expected-warning{{leak}}
+ [x noCopyString]; // expected-warning{{leak}}
+ [NSData dataWithBytesNoCopy:bytes length:dataLength]; // no-warning
+ [NSData dataWithBytesNoCopy:bytes length:dataLength freeWhenDone:1]; // no-warning
+}
+
+//===----------------------------------------------------------------------===//
+// PR 4230 - an autorelease pool is not necessarily leaked during a premature
+// return
+//===----------------------------------------------------------------------===//
+
+static void PR4230(void)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // no-warning
+ NSString *object = [[[NSString alloc] init] autorelease]; // no-warning
+ return;
+}
+
+//===----------------------------------------------------------------------===//
+// Method name that has a null IdentifierInfo* for its first selector slot.
+// This test just makes sure that we handle it.
+//===----------------------------------------------------------------------===//
+
+@interface TestNullIdentifier
+@end
+
+@implementation TestNullIdentifier
++ (id):(int)x, ... {
+ return [[NSString alloc] init]; // expected-warning{{leak}}
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6893565> don't flag leaks for return types that cannot be
+// determined to be CF types
+//===----------------------------------------------------------------------===//
+
+// We don't know if 'struct s6893565' represents a Core Foundation type, so
+// we shouldn't emit an error here.
+typedef struct s6893565* TD6893565;
+
+@interface RDar6893565 {}
+-(TD6893565)newThing;
+@end
+
+@implementation RDar6893565
+-(TD6893565)newThing {
+ return (TD6893565) [[NSString alloc] init]; // no-warning
+}
+@end
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/6902710> clang: false positives w/QC and CoreImage methods
+//===----------------------------------------------------------------------===//
+
+void rdar6902710(QCView *view, QCRenderer *renderer, CIContext *context,
+ NSString *str, CIImage *img, CGRect rect,
+ CIFormat form, CGColorSpaceRef cs) {
+ [view createSnapshotImageOfType:str]; // expected-warning{{leak}}
+ [renderer createSnapshotImageOfType:str]; // expected-warning{{leak}}
+ [context createCGImage:img fromRect:rect]; // expected-warning{{leak}}
+ [context createCGImage:img fromRect:rect format:form colorSpace:cs]; // expected-warning{{leak}}
+}
+
+//===----------------------------------------------------------------------===//
+// Tests of ownership attributes.
+//===----------------------------------------------------------------------===//
+
+typedef NSString* MyStringTy;
+
+@interface TestOwnershipAttr : NSObject
+- (NSString*) returnsAnOwnedString __attribute__((ns_returns_retained)); // no-warning
+- (NSString*) returnsAnOwnedCFString __attribute__((cf_returns_retained)); // no-warning
+- (MyStringTy) returnsAnOwnedTypedString __attribute__((ns_returns_retained)); // no-warning
+- (int) returnsAnOwnedInt __attribute__((ns_returns_retained)); // expected-warning{{'ns_returns_retained' attribute only applies to functions or methods that return a pointer or Objective-C object}}
+@end
+
+static int ownership_attribute_doesnt_go_here __attribute__((ns_returns_retained)); // expected-warning{{'ns_returns_retained' attribute only applies to function or method types}}
+
+void test_attr_1(TestOwnershipAttr *X) {
+ NSString *str = [X returnsAnOwnedString]; // expected-warning{{leak}}
+}
+
+void test_attr_1b(TestOwnershipAttr *X) {
+ NSString *str = [X returnsAnOwnedCFString]; // expected-warning{{leak}}
+}
+//<<SLICER
+
diff --git a/test/Analysis/stack-addr-ps.c b/test/Analysis/stack-addr-ps.c
new file mode 100644
index 000000000000..4bc9a7def2c8
--- /dev/null
+++ b/test/Analysis/stack-addr-ps.c
@@ -0,0 +1,44 @@
+// RUN: clang-cc -analyze -checker-simple -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s
+
+#include <stdlib.h>
+
+int* f1() {
+ int x = 0;
+ return &x; // expected-warning{{Address of stack memory associated with local variable 'x' returned.}} expected-warning{{address of stack memory associated with local variable 'x' returned}}
+}
+
+int* f2(int y) {
+ return &y; // expected-warning{{Address of stack memory associated with local variable 'y' returned.}} expected-warning{{address of stack memory associated with local variable 'y' returned}}
+}
+
+int* f3(int x, int *y) {
+ int w = 0;
+
+ if (x)
+ y = &w;
+
+ return y; // expected-warning{{Address of stack memory associated with local variable 'w' returned.}}
+}
+
+void* compound_literal(int x, int y) {
+ if (x)
+ return &(unsigned short){((unsigned short)0x22EF)}; // expected-warning{{Address of stack memory}}
+
+ int* array[] = {};
+ struct s { int z; double y; int w; };
+
+ if (y)
+ return &((struct s){ 2, 0.4, 5 * 8 }); // expected-warning{{Address of stack memory}}
+
+
+ void* p = &((struct s){ 42, 0.4, x ? 42 : 0 });
+ return p; // expected-warning{{Address of stack memory}}
+}
+
+void* alloca_test() {
+ void* p = __builtin_alloca(10);
+ return p; // expected-warning{{Address of stack memory}}
+}
+
diff --git a/test/Analysis/uninit-msg-expr.m b/test/Analysis/uninit-msg-expr.m
new file mode 100644
index 000000000000..161ab8041de1
--- /dev/null
+++ b/test/Analysis/uninit-msg-expr.m
@@ -0,0 +1,58 @@
+// RUN: clang-cc -analyze -checker-simple -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -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 directly including Foundation.h directly makes this test case
+// both svelte and portable to non-Mac platforms.
+//===----------------------------------------------------------------------===//
+
+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 NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
+@interface NSObject <NSObject> {} @end
+@class NSString, NSData;
+@class NSString, NSData, NSMutableData, NSMutableDictionary, NSMutableArray;
+typedef struct {} NSFastEnumerationState;
+@protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end
+@class NSData, NSIndexSet, NSString, NSURL;
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+@end
+@interface NSArray (NSArrayCreation)
++ (id)array;
+- (NSUInteger)length;
+- (void)addObject:(id)object;
+@end
+extern NSString * const NSUndoManagerCheckpointNotification;
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+unsigned f1() {
+ NSString *aString;
+ return [aString length]; // expected-warning {{Receiver in message expression is an uninitialized value}}
+}
+
+unsigned f2() {
+ NSString *aString = 0;
+ return [aString length]; // no-warning
+}
+
+void f3() {
+ NSMutableArray *aArray = [NSArray array];
+ NSString *aString;
+ [aArray addObject:aString]; // expected-warning {{Pass-by-value argument in message expression is undefined.}}
+}
diff --git a/test/Analysis/uninit-ps-rdar6145427.m b/test/Analysis/uninit-ps-rdar6145427.m
new file mode 100644
index 000000000000..49eb26984a0b
--- /dev/null
+++ b/test/Analysis/uninit-ps-rdar6145427.m
@@ -0,0 +1,37 @@
+// RUN: clang-cc -analyze -verify -analyzer-store=basic -checker-cfref %s &&
+// RUN: clang-cc -analyze -verify -analyzer-store=region -checker-cfref %s
+
+// Delta-Debugging reduced preamble.
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+@class NSString, Protocol;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
+@interface NSObject <NSObject> {} + (id)alloc; @end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value; @end
+@class NSString, NSData;
+typedef struct _NSPoint {} NSRange;
+@interface NSValue (NSValueRangeExtensions)
++ (NSValue *)valueWithRange:(NSRange)range;
+- (id)objectAtIndex:(NSUInteger)index;
+@end
+@interface NSAutoreleasePool : NSObject {} - (void)drain; @end
+extern NSString * const NSBundleDidLoadNotification;
+typedef struct {} NSDecimal;
+@interface NSNetService : NSObject {} - (id)init; @end
+extern NSString * const NSUndoManagerCheckpointNotification;
+
+// Test case: <rdar://problem/6145427>
+
+int main (int argc, const char * argv[]) {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ id someUnintializedPointer = [someUnintializedPointer objectAtIndex:0]; // expected-warning{{Receiver in message expression is an uninitialized value.}}
+ NSLog(@"%@", someUnintializedPointer);
+ [pool drain];
+ return 0;
+}
diff --git a/test/Analysis/uninit-vals-ps-region.c b/test/Analysis/uninit-vals-ps-region.c
new file mode 100644
index 000000000000..6f3762ee10bf
--- /dev/null
+++ b/test/Analysis/uninit-vals-ps-region.c
@@ -0,0 +1,17 @@
+// RUN: clang-cc -analyze -checker-simple -analyzer-store=region -verify %s
+
+struct s {
+ int data;
+};
+
+struct s global;
+
+void g(int);
+
+void f4() {
+ int a;
+ if (global.data == 0)
+ a = 3;
+ if (global.data == 0) // When the true branch is feasible 'a = 3'.
+ g(a); // no-warning
+}
diff --git a/test/Analysis/uninit-vals-ps.c b/test/Analysis/uninit-vals-ps.c
new file mode 100644
index 000000000000..41771265367a
--- /dev/null
+++ b/test/Analysis/uninit-vals-ps.c
@@ -0,0 +1,85 @@
+// RUN: clang-cc -analyze -checker-cfref -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s
+
+struct FPRec {
+ void (*my_func)(int * x);
+};
+
+int bar(int x);
+
+int f1_a(struct FPRec* foo) {
+ int x;
+ (*foo->my_func)(&x);
+ return bar(x)+1; // no-warning
+}
+
+int f1_b() {
+ int x;
+ return bar(x)+1; // expected-warning{{Pass-by-value argument in function call is undefined.}}
+}
+
+int f2() {
+
+ int x;
+
+ if (x+1) // expected-warning{{Branch}}
+ return 1;
+
+ return 2;
+}
+
+int f2_b() {
+ int x;
+
+ return ((x+1)+2+((x))) + 1 ? 1 : 2; // expected-warning{{Branch}}
+}
+
+int f3(void) {
+ int i;
+ int *p = &i;
+ if (*p > 0) // expected-warning{{Branch condition evaluates to an uninitialized value}}
+ return 0;
+ else
+ return 1;
+}
+
+void f4_aux(float* x);
+float f4(void) {
+ float x;
+ f4_aux(&x);
+ return x; // no-warning
+}
+
+struct f5_struct { int x; };
+void f5_aux(struct f5_struct* s);
+int f5(void) {
+ struct f5_struct s;
+ f5_aux(&s);
+ return s.x; // no-warning
+}
+
+int ret_uninit() {
+ int i;
+ int *p = &i;
+ return *p; // expected-warning{{Uninitialized or undefined value returned to caller.}}
+}
+
+// <rdar://problem/6451816>
+typedef unsigned char Boolean;
+typedef const struct __CFNumber * CFNumberRef;
+typedef signed long CFIndex;
+typedef CFIndex CFNumberType;
+typedef unsigned long UInt32;
+typedef UInt32 CFStringEncoding;
+typedef const struct __CFString * CFStringRef;
+extern Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePtr);
+extern CFStringRef CFStringConvertEncodingToIANACharSetName(CFStringEncoding encoding);
+
+CFStringRef rdar_6451816(CFNumberRef nr) {
+ CFStringEncoding encoding;
+ // &encoding is casted to void*. This test case tests whether or not
+ // we properly invalidate the value of 'encoding'.
+ CFNumberGetValue(nr, 9, &encoding);
+ return CFStringConvertEncodingToIANACharSetName(encoding); // no-warning
+}
+
diff --git a/test/Analysis/uninit-vals.c b/test/Analysis/uninit-vals.c
new file mode 100644
index 000000000000..d69250b65c0b
--- /dev/null
+++ b/test/Analysis/uninit-vals.c
@@ -0,0 +1,53 @@
+// RUN: clang-cc -analyze -warn-uninit-values -verify %s
+
+int f1() {
+ int x;
+ return x; // expected-warning {{use of uninitialized variable}}
+}
+
+int f2(int x) {
+ int y;
+ int z = x + y; // expected-warning {{use of uninitialized variable}}
+ return z;
+}
+
+
+int f3(int x) {
+ int y;
+ return x ? 1 : y; // expected-warning {{use of uninitialized variable}}
+}
+
+int f4(int x) {
+ int y;
+ if (x) y = 1;
+ return y; // expected-warning {{use of uninitialized variable}}
+}
+
+int f5() {
+ int a;
+ a = 30; // no-warning
+}
+
+void f6(int i) {
+ int x;
+ for (i = 0 ; i < 10; i++)
+ printf("%d",x++); // expected-warning {{use of uninitialized variable}} \
+ // expected-warning{{implicitly declaring C library function 'printf' with type 'int (char const *, ...)'}} \
+ // expected-note{{please include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
+}
+
+void f7(int i) {
+ int x = i;
+ int y;
+ for (i = 0; i < 10; i++ ) {
+ printf("%d",x++); // no-warning
+ x += y; // expected-warning {{use of uninitialized variable}}
+ }
+}
+
+int f8(int j) {
+ int x = 1, y = x + 1;
+ if (y) // no-warning
+ return x;
+ return y;
+}
diff --git a/test/Analysis/uninit-vals.m b/test/Analysis/uninit-vals.m
new file mode 100644
index 000000000000..7be247e7ca9e
--- /dev/null
+++ b/test/Analysis/uninit-vals.m
@@ -0,0 +1,25 @@
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s &&
+// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s
+
+typedef unsigned int NSUInteger;
+
+@interface A
+- (NSUInteger)foo;
+@end
+
+NSUInteger f8(A* x){
+ const NSUInteger n = [x foo];
+ int* bogus;
+
+ if (n > 0) { // tests const cast transfer function logic
+ NSUInteger i;
+
+ for (i = 0; i < n; ++i)
+ bogus = 0;
+
+ if (bogus) // no-warning
+ return n+1;
+ }
+
+ return n;
+}
diff --git a/test/Analysis/unused-ivars.m b/test/Analysis/unused-ivars.m
new file mode 100644
index 000000000000..632b395c3e08
--- /dev/null
+++ b/test/Analysis/unused-ivars.m
@@ -0,0 +1,10 @@
+// RUN: clang-cc -analyze -warn-objc-unused-ivars %s -verify
+
+@interface A
+{
+ @private int x; // expected-warning {{Instance variable 'x' in class 'A' is never used}}
+}
+@end
+
+@implementation A @end
+
diff --git a/test/Analysis/xfail-no-outofbounds.c b/test/Analysis/xfail-no-outofbounds.c
new file mode 100644
index 000000000000..f2ee732c2570
--- /dev/null
+++ b/test/Analysis/xfail-no-outofbounds.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -checker-cfref -analyze -analyzer-store=region -verify %s
+
+void f() {
+ long x = 0;
+ char *y = (char*) &x;
+ char c = y[0] + y[1] + y[2]; // no-warning
+}
diff --git a/test/Analysis/xfail_regionstore_wine_crash.c b/test/Analysis/xfail_regionstore_wine_crash.c
new file mode 100644
index 000000000000..2628d0dacf6a
--- /dev/null
+++ b/test/Analysis/xfail_regionstore_wine_crash.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -checker-cfref -analyze -analyzer-store=region -verify %s
+// XFAIL
+
+// When this test passes we should put it in the misc-ps.m test file.
+// This test fails now because RegionStoreManager::Retrieve() does correctly
+// retrieve the first byte of 'x' when retrieving '*y'.
+void foo() {
+ long x = 0;
+ char *y = (char *) &x;
+ if (!*y)
+ return;
+}
diff --git a/test/CodeGen/2007-11-29-ArraySizeFromInitializer.c b/test/CodeGen/2007-11-29-ArraySizeFromInitializer.c
new file mode 100644
index 000000000000..3b158241c68e
--- /dev/null
+++ b/test/CodeGen/2007-11-29-ArraySizeFromInitializer.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+int array[] = {1, 2, 3, 4, 5};
+
diff --git a/test/CodeGen/2008-02-07-bitfield-bug.c b/test/CodeGen/2008-02-07-bitfield-bug.c
new file mode 100644
index 000000000000..dc2ebb75d598
--- /dev/null
+++ b/test/CodeGen/2008-02-07-bitfield-bug.c
@@ -0,0 +1,11 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+// PR1990
+
+struct test {
+ char a[3];
+ unsigned char b:1;
+};
+
+void f(struct test *t) {
+ t->b = 1;
+}
diff --git a/test/CodeGen/2008-02-08-bitfield-bug.c b/test/CodeGen/2008-02-08-bitfield-bug.c
new file mode 100644
index 000000000000..fc69e58ed3cf
--- /dev/null
+++ b/test/CodeGen/2008-02-08-bitfield-bug.c
@@ -0,0 +1,9 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+
+struct test {
+ unsigned a:1;
+ unsigned b:1;
+};
+
+struct test *t;
+
diff --git a/test/CodeGen/2008-02-26-inline-asm-bug.c b/test/CodeGen/2008-02-26-inline-asm-bug.c
new file mode 100644
index 000000000000..a6816f5de8ff
--- /dev/null
+++ b/test/CodeGen/2008-02-26-inline-asm-bug.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -emit-llvm < %s | grep "\$0,\$1"
+
+void f() {
+ int d1, d2;
+ asm("%0,%1": "=r" (d1) : "r" (d2));
+}
diff --git a/test/CodeGen/2008-07-17-no-emit-on-error.c b/test/CodeGen/2008-07-17-no-emit-on-error.c
new file mode 100644
index 000000000000..89aeb18d9d13
--- /dev/null
+++ b/test/CodeGen/2008-07-17-no-emit-on-error.c
@@ -0,0 +1,10 @@
+// RUN: rm -f %t1.bc
+// RUN: not clang-cc %s -emit-llvm-bc -o %t1.bc
+// RUN: not test -f %t1.bc
+
+void f() {
+}
+
+void g() {
+ *10;
+}
diff --git a/test/CodeGen/2008-07-21-mixed-var-fn-decl.c b/test/CodeGen/2008-07-21-mixed-var-fn-decl.c
new file mode 100644
index 000000000000..c55c86b2fc6c
--- /dev/null
+++ b/test/CodeGen/2008-07-21-mixed-var-fn-decl.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -emit-llvm -o - %s | grep -e "@g[0-9] " | count 2
+
+int g0, f0();
+int f1(), g1;
+
diff --git a/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c b/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c
new file mode 100644
index 000000000000..19bf9a2b078e
--- /dev/null
+++ b/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c
@@ -0,0 +1,11 @@
+// RUN: clang-cc --emit-llvm -o %t %s &&
+// RUN: grep "i8 52" %t | count 1
+
+struct et7 {
+ float lv7[0];
+ char mv7:6;
+} yv7 = {
+ {},
+ 52,
+};
+
diff --git a/test/CodeGen/2008-07-22-packed-bitfield-access.c b/test/CodeGen/2008-07-22-packed-bitfield-access.c
new file mode 100644
index 000000000000..437a4be156b7
--- /dev/null
+++ b/test/CodeGen/2008-07-22-packed-bitfield-access.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc %s -emit-llvm -o -
+
+int main () {
+ struct foo {
+ unsigned a:16;
+ unsigned b:32 __attribute__ ((packed));
+ } x;
+ x.b = 0x56789abcL;
+ return 0;
+}
diff --git a/test/CodeGen/2008-07-29-override-alias-decl.c b/test/CodeGen/2008-07-29-override-alias-decl.c
new file mode 100644
index 000000000000..43f4e3ecedae
--- /dev/null
+++ b/test/CodeGen/2008-07-29-override-alias-decl.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -emit-llvm -o - %s | grep -e "^@f" | count 1
+
+int x() {}
+
+int f() __attribute__((weak, alias("x")));
+
+/* Test that we link to the alias correctly instead of making a new
+ forward definition. */
+int f();
+int h() {
+ return f();
+}
diff --git a/test/CodeGen/2008-07-30-implicit-initialization.c b/test/CodeGen/2008-07-30-implicit-initialization.c
new file mode 100644
index 000000000000..2f4c14eb728b
--- /dev/null
+++ b/test/CodeGen/2008-07-30-implicit-initialization.c
@@ -0,0 +1,28 @@
+// RUN: clang-cc -triple i386-unknown-unknown --emit-llvm-bc -o - %s | opt --std-compile-opts | llvm-dis > %t &&
+// RUN: grep "ret i32" %t | count 2 &&
+// RUN: grep "ret i32 0" %t | count 2
+// <rdar://problem/6113085>
+
+struct s0 {
+ int x, y;
+};
+
+int f0() {
+ struct s0 x = {0};
+ return x.y;
+}
+
+#if 0
+/* Optimizer isn't smart enough to reduce this since we use
+ memset. Hrm. */
+int f1() {
+ struct s0 x[2] = { {0} };
+ return x[1].x;
+}
+#endif
+
+int f2() {
+ int x[2] = { 0 };
+ return x[1];
+}
+
diff --git a/test/CodeGen/2008-07-30-redef-of-bitcasted-decl.c b/test/CodeGen/2008-07-30-redef-of-bitcasted-decl.c
new file mode 100644
index 000000000000..c374f8d00843
--- /dev/null
+++ b/test/CodeGen/2008-07-30-redef-of-bitcasted-decl.c
@@ -0,0 +1,28 @@
+// RUN: clang-cc --emit-llvm -o - %s
+// <rdar://problem/6108358>
+
+/* For posterity, the issue here begins initial "char []" decl for
+ * s. This is a tentative definition and so a global was being
+ * emitted, however the mapping in GlobalDeclMap referred to a bitcast
+ * of this global.
+ *
+ * The problem was that later when the correct definition for s is
+ * emitted we were doing a RAUW on the old global which was destroying
+ * the bitcast in the GlobalDeclMap (since it cannot be replaced
+ * properly), leaving a dangling pointer.
+ *
+ * The purpose of bar is just to trigger a use of the old decl
+ * sometime after the dangling pointer has been introduced.
+ */
+
+char s[];
+
+static void bar(void *db) {
+ eek(s);
+}
+
+char s[5] = "hi";
+
+int foo() {
+ bar(0);
+}
diff --git a/test/CodeGen/2008-07-31-asm-labels.c b/test/CodeGen/2008-07-31-asm-labels.c
new file mode 100644
index 000000000000..f114f65eded2
--- /dev/null
+++ b/test/CodeGen/2008-07-31-asm-labels.c
@@ -0,0 +1,33 @@
+// RUN: clang-cc -emit-llvm -o %t %s &&
+// RUN: grep "@pipe()" %t | count 0 &&
+// RUN: grep '_thisIsNotAPipe' %t | count 3 &&
+// RUN: grep 'g0' %t | count 0 &&
+// RUN: grep '_renamed' %t | count 2 &&
+// RUN: clang-cc -DUSE_DEF -emit-llvm -o %t %s &&
+// RUN: grep "@pipe()" %t | count 0 &&
+// RUN: grep '_thisIsNotAPipe' %t | count 3
+// <rdr://6116729>
+
+void pipe() asm("_thisIsNotAPipe");
+
+void f0() {
+ pipe();
+}
+
+void pipe(int);
+
+void f1() {
+ pipe(1);
+}
+
+#ifdef USE_DEF
+void pipe(int arg) {
+ int x = 10;
+}
+#endif
+
+// PR3698
+extern int g0 asm("_renamed");
+int f2() {
+ return g0;
+}
diff --git a/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c b/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c
new file mode 100644
index 000000000000..0ce4ba66ca12
--- /dev/null
+++ b/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c
@@ -0,0 +1,25 @@
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis | grep "ret i32 1" | count 3
+// <rdr://6115726>
+
+int f0() {
+ int x;
+ unsigned short n = 1;
+ int *a = &x;
+ int *b = &x;
+ a = a - n;
+ b -= n;
+ return a == b;
+}
+
+int f1(int *a) {
+ long b = a - (int*) 1;
+ a -= (int*) 1;
+ return b == (long) a;
+}
+
+int f2(long n) {
+ int *b = n + (int*) 1;
+ n += (int*) 1;
+ return b == (int*) n;
+}
+
diff --git a/test/CodeGen/2008-08-04-void-pointer-arithmetic.c b/test/CodeGen/2008-08-04-void-pointer-arithmetic.c
new file mode 100644
index 000000000000..22815f32ccc4
--- /dev/null
+++ b/test/CodeGen/2008-08-04-void-pointer-arithmetic.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc --emit-llvm -o - %s
+// <rdar://problem/6122967>
+
+int f0(void *a, void *b) {
+ return a - b;
+}
diff --git a/test/CodeGen/2008-08-19-cast-of-typedef.c b/test/CodeGen/2008-08-19-cast-of-typedef.c
new file mode 100644
index 000000000000..3db5e903090a
--- /dev/null
+++ b/test/CodeGen/2008-08-19-cast-of-typedef.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc --emit-llvm -o %t %s
+
+typedef short T[4];
+struct s {
+ T f0;
+};
+
+void foo(struct s *x) {
+ bar((long) x->f0);
+}
diff --git a/test/CodeGen/2008-08-25-incompatible-cond-expr.m b/test/CodeGen/2008-08-25-incompatible-cond-expr.m
new file mode 100644
index 000000000000..3cc42d89f6fa
--- /dev/null
+++ b/test/CodeGen/2008-08-25-incompatible-cond-expr.m
@@ -0,0 +1,10 @@
+// RUN: clang-cc -emit-llvm -o %t %s
+
+@protocol P0
+@end
+@interface A <P0>
+@end
+
+id f0(int a, id<P0> x, A* p) {
+ return a ? x : p;
+}
diff --git a/test/CodeGen/2008-09-22-bad-switch-type.c b/test/CodeGen/2008-09-22-bad-switch-type.c
new file mode 100644
index 000000000000..2526dd9289c8
--- /dev/null
+++ b/test/CodeGen/2008-09-22-bad-switch-type.c
@@ -0,0 +1,34 @@
+// RUN: clang-cc -emit-llvm -o %t %s
+// PR2817
+
+void f0(void) {
+ switch (0) {
+ case (unsigned long long) 0 < 0:
+ break;
+ }
+
+ switch (0) {
+ case (unsigned long long) 0 > 0:
+ break;
+ }
+
+ switch (0) {
+ case (unsigned long long) 0 <= 0:
+ break;
+ }
+
+ switch (0) {
+ case (unsigned long long) 0 >= 0:
+ break;
+ }
+
+ switch (0) {
+ case (unsigned long long) 0 == 0:
+ break;
+ }
+
+ switch (0) {
+ case (unsigned long long) 0 != 0:
+ break;
+ }
+}
diff --git a/test/CodeGen/2008-12-02-logical-or-fold.c b/test/CodeGen/2008-12-02-logical-or-fold.c
new file mode 100644
index 000000000000..d54bf287d2e2
--- /dev/null
+++ b/test/CodeGen/2008-12-02-logical-or-fold.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -emit-llvm -o - %s | grep "store i32 1"
+// PR3150
+
+int a() {return 1||1;}
diff --git a/test/CodeGen/2009-01-21-invalid-debug-info.m b/test/CodeGen/2009-01-21-invalid-debug-info.m
new file mode 100644
index 000000000000..9a955a1c0d95
--- /dev/null
+++ b/test/CodeGen/2009-01-21-invalid-debug-info.m
@@ -0,0 +1,16 @@
+// RUN: clang-cc -S -g -o %t.s %s
+
+// FIXME: This test case can be removed at some point (since it will
+// no longer effectively test anything). The reason it was causing
+// trouble was the synthesized self decl in im1 was causing the debug
+// info for I1* to be generated, but referring to an invalid compile
+// unit. This was later referred to by f1 and created ill formed debug
+// information.
+
+@interface I1 @end
+
+@implementation I1
+-im0 {}
+@end
+
+I1 *f1(void) { return 0; }
diff --git a/test/CodeGen/2009-03-22-increment-bitfield.c b/test/CodeGen/2009-03-22-increment-bitfield.c
new file mode 100644
index 000000000000..f0aaafda60ea
--- /dev/null
+++ b/test/CodeGen/2009-03-22-increment-bitfield.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -emit-llvm -O1 < %s | grep "ret i32 0"
+
+int a(void) {
+ return ++(struct x {unsigned x : 2;}){3}.x;
+}
+
+
diff --git a/test/CodeGen/2009-04-23-dbg.c b/test/CodeGen/2009-04-23-dbg.c
new file mode 100644
index 000000000000..4be6dab7ea2b
--- /dev/null
+++ b/test/CodeGen/2009-04-23-dbg.c
@@ -0,0 +1,20 @@
+// RUN: clang-cc -g -o %t %s -emit-llvm-bc && llc %t -f -o %t.s
+# 1 "a.c"
+# 1 "a.c" 1
+# 1 "<built-in>" 1
+# 103 "<built-in>"
+# 103 "<command line>" 1
+
+# 1 "/private/tmp/a.h" 1
+int bar;
+# 105 "<command line>" 2
+# 105 "<built-in>" 2
+# 1 "a.c" 2
+# 1 "/private/tmp/a.h" 1
+int bar;
+# 2 "a.c" 2
+
+int main() {
+ bar = 0;
+ return 0;
+}
diff --git a/test/CodeGen/2009-05-22-callingconv.c b/test/CodeGen/2009-05-22-callingconv.c
new file mode 100644
index 000000000000..2b70d840c061
--- /dev/null
+++ b/test/CodeGen/2009-05-22-callingconv.c
@@ -0,0 +1,25 @@
+// RUN: clang-cc %s -emit-llvm -o - | grep call | grep x86_stdcallcc
+void abort(void) __attribute__((__noreturn__));
+typedef void re_string_t;
+typedef void re_dfa_t;
+typedef int reg_errcode_t;
+static reg_errcode_t re_string_construct (re_string_t *pstr, const char *str,
+ int len, char * trans,
+ int icase, const re_dfa_t *dfa)
+ __attribute__ ((regparm (3), stdcall));
+static reg_errcode_t
+re_string_construct (pstr, str, len, trans, icase, dfa)
+ re_string_t *pstr;
+ const char *str;
+ int len, icase;
+ char * trans;
+ const re_dfa_t *dfa;
+{
+ if (dfa != (void*)0x282020c0)
+ abort();
+return 0;
+}
+int main()
+{
+ return re_string_construct(0, 0, 0, 0, 0, (void*)0x282020c0);
+}
diff --git a/test/CodeGen/2009-05-28-const-typedef.c b/test/CodeGen/2009-05-28-const-typedef.c
new file mode 100644
index 000000000000..e46e83b9478c
--- /dev/null
+++ b/test/CodeGen/2009-05-28-const-typedef.c
@@ -0,0 +1,17 @@
+// RUN: clang-cc -emit-llvm %s -o -
+// PR4281
+
+typedef struct {
+ int i;
+} something;
+
+typedef const something const_something;
+
+something fail(void);
+
+int
+main(int argc, char *argv[])
+{
+ const_something R = fail();
+}
+
diff --git a/test/CodeGen/2009-06-01-addrofknr.c b/test/CodeGen/2009-06-01-addrofknr.c
new file mode 100644
index 000000000000..16a5bbffc3af
--- /dev/null
+++ b/test/CodeGen/2009-06-01-addrofknr.c
@@ -0,0 +1,21 @@
+// RUN: clang-cc %s -o %t -emit-llvm -verify
+// PR4289
+
+struct funcptr {
+ int (*func)();
+};
+
+static int func(f)
+ void *f;
+{
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct funcptr fp;
+
+ fp.func = &func;
+ fp.func = func;
+}
+
diff --git a/test/CodeGen/OpaqueStruct.c b/test/CodeGen/OpaqueStruct.c
new file mode 100644
index 000000000000..b994c3000246
--- /dev/null
+++ b/test/CodeGen/OpaqueStruct.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+typedef struct a b;
+
+b* x;
+
+struct a {
+ b* p;
+};
+
+void f() {
+ b* z = x->p;
+}
diff --git a/test/CodeGen/PR2001-bitfield-reload.c b/test/CodeGen/PR2001-bitfield-reload.c
new file mode 100644
index 000000000000..797b494cf823
--- /dev/null
+++ b/test/CodeGen/PR2001-bitfield-reload.c
@@ -0,0 +1,17 @@
+// RUN: clang-cc -triple i386-unknown-unknown --emit-llvm-bc -o - %s | opt --std-compile-opts | llvm-dis > %t &&
+// RUN: grep "ret i32" %t | count 1 &&
+// RUN: grep "ret i32 1" %t | count 1
+// PR2001
+
+/* Test that the result of the assignment properly uses the value *in
+ the bitfield* as opposed to the RHS. */
+static int foo(int i) {
+ struct {
+ int f0 : 2;
+ } x;
+ return (x.f0 = i);
+}
+
+int bar() {
+ return foo(-5) == -1;
+}
diff --git a/test/CodeGen/PR2413-void-address-cast-error.c b/test/CodeGen/PR2413-void-address-cast-error.c
new file mode 100644
index 000000000000..95a4c6d80fc3
--- /dev/null
+++ b/test/CodeGen/PR2413-void-address-cast-error.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -emit-llvm %s -o -
+void f()
+{
+ void *addr;
+ addr = (void *)( ((long int)addr + 7L) );
+}
diff --git a/test/CodeGen/PR2643-null-store-to-bitfield.c b/test/CodeGen/PR2643-null-store-to-bitfield.c
new file mode 100644
index 000000000000..6a5b0e92f660
--- /dev/null
+++ b/test/CodeGen/PR2643-null-store-to-bitfield.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -emit-llvm -o - %s
+// PR2643
+
+void foo() {
+ struct {
+ int a : 1;
+ int b : 1;
+ } entry = {0};
+}
+
diff --git a/test/CodeGen/PR2743-reference-missing-static.c b/test/CodeGen/PR2743-reference-missing-static.c
new file mode 100644
index 000000000000..e152c5258527
--- /dev/null
+++ b/test/CodeGen/PR2743-reference-missing-static.c
@@ -0,0 +1,16 @@
+// RUN: clang-cc -emit-llvm -o %t %s
+// PR2743
+// <rdr://6094512>
+
+/* CodeGen should handle this even if it makes it past
+ sema. Unfortunately this test will become useless once sema starts
+ rejecting this. */
+
+static void e0();
+void f0() { e0(); }
+
+inline void e1();
+void f1() { e1(); }
+
+void e2() __attribute__((weak));
+void f2() { e2(); }
diff --git a/test/CodeGen/PR3130-cond-constant.c b/test/CodeGen/PR3130-cond-constant.c
new file mode 100644
index 000000000000..e488eeb37f67
--- /dev/null
+++ b/test/CodeGen/PR3130-cond-constant.c
@@ -0,0 +1,3 @@
+// RUN: clang-cc -emit-llvm %s -o -
+
+int a = 2.0 ? 1 : 2;
diff --git a/test/CodeGen/PR3589-freestanding-libcalls.c b/test/CodeGen/PR3589-freestanding-libcalls.c
new file mode 100644
index 000000000000..90b5fff1620f
--- /dev/null
+++ b/test/CodeGen/PR3589-freestanding-libcalls.c
@@ -0,0 +1,9 @@
+// RUN: clang-cc -emit-llvm %s -o - | grep 'declare i32 @printf' | count 1 &&
+// RUN: clang-cc -O2 -emit-llvm %s -o - | grep 'declare i32 @puts' | count 1 &&
+// RUN: clang-cc -ffreestanding -O2 -emit-llvm %s -o - | grep 'declare i32 @puts' | count 0
+
+#include <stdio.h>
+
+void f0() {
+ printf("hello\n");
+}
diff --git a/test/CodeGen/PR3613-static-decl.c b/test/CodeGen/PR3613-static-decl.c
new file mode 100644
index 000000000000..365b9b2be05e
--- /dev/null
+++ b/test/CodeGen/PR3613-static-decl.c
@@ -0,0 +1,16 @@
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: grep '@g0 = internal global .struct.s0 <{ i32 3 }>' %t | count 1
+
+struct s0 {
+ int a;
+};
+
+static struct s0 g0;
+
+static int f0(void) {
+ return g0.a;
+}
+
+static struct s0 g0 = {3};
+
+void *g1 = f0;
diff --git a/test/CodeGen/PR3709-int-to-pointer-sign.c b/test/CodeGen/PR3709-int-to-pointer-sign.c
new file mode 100644
index 000000000000..24c42f649bbe
--- /dev/null
+++ b/test/CodeGen/PR3709-int-to-pointer-sign.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -emit-llvm %s -o - -O1 -triple=x86_64-gnu-linux | grep "i64 -1"
+
+// PR3709
+long long a() { return (long long)(int*)-1;}
+
diff --git a/test/CodeGen/PR3869-indirect-goto-long.c b/test/CodeGen/PR3869-indirect-goto-long.c
new file mode 100644
index 000000000000..140e4ec14a86
--- /dev/null
+++ b/test/CodeGen/PR3869-indirect-goto-long.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -emit-llvm-bc -o - %s
+// PR3869
+int a(long long b) { goto *b; }
+
diff --git a/test/CodeGen/address-space-cast.c b/test/CodeGen/address-space-cast.c
new file mode 100644
index 000000000000..2fba5ecd7dca
--- /dev/null
+++ b/test/CodeGen/address-space-cast.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -emit-llvm < %s
+
+volatile unsigned char* const __attribute__((address_space(1))) serial_ctrl = 0x02;
+
diff --git a/test/CodeGen/address-space.c b/test/CodeGen/address-space.c
new file mode 100644
index 000000000000..3b6a8e654167
--- /dev/null
+++ b/test/CodeGen/address-space.c
@@ -0,0 +1,20 @@
+// RUN: clang-cc -emit-llvm < %s | grep '@foo.*global.*addrspace(1)' &&
+// RUN: clang-cc -emit-llvm < %s | grep '@ban.*global.*addrspace(1)' &&
+// RUN: clang-cc -emit-llvm < %s | grep 'load.*addrspace(1)' | count 2 &&
+// RUN: clang-cc -emit-llvm < %s | grep 'load.*addrspace(2).. @A' &&
+// RUN: clang-cc -emit-llvm < %s | grep 'load.*addrspace(2).. @B'
+
+int foo __attribute__((address_space(1)));
+int ban[10] __attribute__((address_space(1)));
+
+int bar() { return foo; }
+
+int baz(int i) { return ban[i]; }
+
+// Both A and B point into addrspace(2).
+__attribute__((address_space(2))) int *A, *B;
+
+void test3() {
+ *A = *B;
+}
+
diff --git a/test/CodeGen/alias.c b/test/CodeGen/alias.c
new file mode 100644
index 000000000000..b0c71fbdfca4
--- /dev/null
+++ b/test/CodeGen/alias.c
@@ -0,0 +1,32 @@
+// RUN: clang-cc -triple i386-pc-linux-gnu -emit-llvm -o %t %s &&
+// RUN: grep '@g0 = common global i32 0' %t &&
+// RUN: grep '@f1 = alias void ()\* @f0' %t &&
+// RUN: grep '@g1 = alias i32\* @g0' %t &&
+// RUN: grep 'define void @f0() nounwind {' %t &&
+
+void f0(void) { }
+extern void f1(void);
+extern void f1(void) __attribute((alias("f0")));
+
+int g0;
+extern int g1;
+extern int g1 __attribute((alias("g0")));
+
+// Make sure that aliases cause referenced values to be emitted.
+// PR3200
+// RUN: grep 'define internal i32 @foo1()' %t &&
+static inline int foo1() { return 0; }
+int foo() __attribute__((alias("foo1")));
+
+
+// RUN: grep '@bar1 = internal global i32 42' %t
+static int bar1 = 42;
+int bar() __attribute__((alias("bar1")));
+
+
+extern int test6();
+void test7() { test6(); } // test6 is emitted as extern.
+
+// test6 changes to alias.
+int test6() __attribute__((alias("test7")));
+
diff --git a/test/CodeGen/align-local.c b/test/CodeGen/align-local.c
new file mode 100644
index 000000000000..afbe1d5dd0d0
--- /dev/null
+++ b/test/CodeGen/align-local.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -emit-llvm < %s | grep "align 16" | count 2
+
+typedef struct __attribute((aligned(16))) {int x[4];} ff;
+
+int a() {
+ ff a;
+ struct {int x[4];} b __attribute((aligned(16)));
+}
diff --git a/test/CodeGen/alignof.c b/test/CodeGen/alignof.c
new file mode 100644
index 000000000000..d39f4e418eb1
--- /dev/null
+++ b/test/CodeGen/alignof.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -triple i386-unknown-unknown -O1 -emit-llvm -o %t %s &&
+// RUN: grep 'ret i32 4' %t
+
+enum e0 { E0 };
+struct s0 {
+ enum e0 a:31;
+};
+
+struct s0 t1_tmp;
+int f0() {
+ return __alignof__(t1_tmp);
+}
diff --git a/test/CodeGen/array.c b/test/CodeGen/array.c
new file mode 100644
index 000000000000..5bcc26ecf38b
--- /dev/null
+++ b/test/CodeGen/array.c
@@ -0,0 +1,14 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+int f() {
+ int a[2];
+ a[0] = 0;
+}
+
+int f2() {
+ int x = 0;
+ int y = 1;
+ int a[10] = { y, x, 2, 3};
+ int b[10] = { 2,4,x,6,y,8};
+ int c[5] = { 0,1,2,3};
+}
diff --git a/test/CodeGen/asm-2.c b/test/CodeGen/asm-2.c
new file mode 100644
index 000000000000..f5b378eb1017
--- /dev/null
+++ b/test/CodeGen/asm-2.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -emit-llvm %s -o %t -triple i386-pc-linux-gnu -O2 &&
+// RUN: not grep "load" %t
+
+// <rdar://problem/6841383>
+int cpuid(unsigned data) {
+ int a, b;
+
+ asm("xyz" :"=a"(a), "=d"(b) : "a"(data));
+ return a + b;
+}
diff --git a/test/CodeGen/asm.c b/test/CodeGen/asm.c
new file mode 100644
index 000000000000..58373fc4c96e
--- /dev/null
+++ b/test/CodeGen/asm.c
@@ -0,0 +1,103 @@
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm %s -o %t &&
+void t1(int len) {
+ __asm__ volatile("" : "=&r"(len), "+&r"(len));
+}
+
+void t2(unsigned long long t) {
+ __asm__ volatile("" : "+m"(t));
+}
+
+void t3(unsigned char *src, unsigned long long temp) {
+ __asm__ volatile("" : "+m"(temp), "+r"(src));
+}
+
+void t4() {
+ unsigned long long a;
+ struct reg { unsigned long long a, b; } b;
+
+ __asm__ volatile ("":: "m"(a), "m"(b));
+}
+
+// PR3417
+void t5(int i) {
+ asm("nop" : "=r"(i) : "0"(t5));
+}
+
+// PR3641
+void t6(void) {
+ __asm__ volatile("" : : "i" (t6));
+}
+
+// RUN: grep "T7 NAMED: \$1" %t &&
+void t7(int a) {
+ __asm__ volatile("T7 NAMED: %[input]" : "+r"(a): [input] "i" (4));
+}
+
+// RUN: grep "T8 NAMED MODIFIER: \${0:c}" %t
+void t8() {
+ __asm__ volatile("T8 NAMED MODIFIER: %c[input]" :: [input] "i" (4));
+}
+
+// PR3682
+unsigned t9(unsigned int a) {
+ asm("bswap %0 %1" : "+r" (a));
+ return a;
+}
+
+// PR3908
+// RUN: grep "PR3908 \$1 \$3 \$2 \$0" %t
+void t10(int r) {
+ __asm__("PR3908 %[lf] %[xx] %[li] %[r]" : [r] "+r" (r) : [lf] "mx" (0), [li] "mr" (0), [xx] "x" ((double)(0)));
+}
+
+
+// PR3373
+unsigned t11(signed char input) {
+ unsigned output;
+ __asm__("xyz"
+ : "=a" (output)
+ : "0" (input));
+ return output;
+}
+
+// PR3373
+unsigned char t12(unsigned input) {
+ unsigned char output;
+ __asm__("xyz"
+ : "=a" (output)
+ : "0" (input));
+ return output;
+}
+
+unsigned char t13(unsigned input) {
+ unsigned char output;
+ __asm__("xyz %1"
+ : "=a" (output)
+ : "0" (input));
+ return output;
+}
+
+struct large {
+ int x[1000];
+};
+
+unsigned long t15(int x, struct large *P) {
+ __asm__("xyz "
+ : "=r" (x)
+ : "m" (*P), "0" (x));
+ return x;
+}
+
+
+
+
+// bitfield destination of an asm.
+struct S {
+ int a : 4;
+};
+
+void t14(struct S *P) {
+ __asm__("abc %0" : "=r"(P->a) );
+}
+
+
diff --git a/test/CodeGen/atomic.c b/test/CodeGen/atomic.c
new file mode 100644
index 000000000000..66dc702bfee9
--- /dev/null
+++ b/test/CodeGen/atomic.c
@@ -0,0 +1,53 @@
+// RUN: clang-cc %s -emit-llvm -o - -triple=i686-apple-darwin9 > %t1 &&
+// RUN: grep @llvm.atomic.load.add.i32 %t1 | count 3 &&
+// RUN: grep @llvm.atomic.load.sub.i8 %t1 | count 2 &&
+// RUN: grep @llvm.atomic.load.min.i32 %t1 &&
+// RUN: grep @llvm.atomic.load.max.i32 %t1 &&
+// RUN: grep @llvm.atomic.load.umin.i32 %t1 &&
+// RUN: grep @llvm.atomic.load.umax.i32 %t1 &&
+// RUN: grep @llvm.atomic.swap.i32 %t1 &&
+// RUN: grep @llvm.atomic.cmp.swap.i32 %t1 | count 4 &&
+// RUN: grep @llvm.atomic.load.and.i32 %t1 | count 2 &&
+// RUN: grep @llvm.atomic.load.or.i8 %t1 &&
+// RUN: grep @llvm.atomic.load.xor.i8 %t1
+
+
+int atomic(void)
+{
+ // non-sensical test for sync functions
+ int old;
+ int val = 1;
+ char valc = 1;
+ unsigned int uval = 1;
+ int cmp = 0;
+
+ old = __sync_fetch_and_add(&val, 1);
+ old = __sync_fetch_and_sub(&valc, 2);
+ old = __sync_fetch_and_min(&val, 3);
+ old = __sync_fetch_and_max(&val, 4);
+ old = __sync_fetch_and_umin(&uval, 5u);
+ old = __sync_fetch_and_umax(&uval, 6u);
+ old = __sync_lock_test_and_set(&val, 7);
+ old = __sync_val_compare_and_swap(&val, 4, 1976);
+ old = __sync_bool_compare_and_swap(&val, 4, 1976);
+ old = __sync_fetch_and_and(&val, 0x9);
+ old = __sync_fetch_and_or(&val, 0xa);
+ old = __sync_fetch_and_xor(&val, 0xb);
+ old = __sync_fetch_and_nand(&val, 0xb);
+
+ old = __sync_add_and_fetch(&val, 1);
+ old = __sync_sub_and_fetch(&val, 2);
+ old = __sync_and_and_fetch(&valc, 3);
+ old = __sync_or_and_fetch(&valc, 4);
+ old = __sync_xor_and_fetch(&valc, 5);
+ old = __sync_nand_and_fetch(&valc, 5);
+
+
+ __sync_val_compare_and_swap((void **)0, (void *)0, (void *)0);
+
+
+ __sync_lock_release(&val);
+ __sync_synchronize ();
+
+ return old;
+}
diff --git a/test/CodeGen/attr-cleanup.c b/test/CodeGen/attr-cleanup.c
new file mode 100644
index 000000000000..03dde3341e6c
--- /dev/null
+++ b/test/CodeGen/attr-cleanup.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+// <rdar://problem/6827047>
+void f(void* arg);
+void g() {
+ __attribute__((cleanup(f))) void *g;
+}
+
diff --git a/test/CodeGen/attr-nodebug.c b/test/CodeGen/attr-nodebug.c
new file mode 100644
index 000000000000..b96ad26d6d04
--- /dev/null
+++ b/test/CodeGen/attr-nodebug.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -g -emit-llvm -o %t %s &&
+// RUN: not grep 'call void @llvm.dbg.func.start' %t
+
+void t1() __attribute__((nodebug));
+
+void t1()
+{
+ int a = 10;
+
+ a++;
+}
+
diff --git a/test/CodeGen/attr-noinline.c b/test/CodeGen/attr-noinline.c
new file mode 100644
index 000000000000..199c2918d425
--- /dev/null
+++ b/test/CodeGen/attr-noinline.c
@@ -0,0 +1,9 @@
+// RUN: clang-cc -g -emit-llvm -o %t %s &&
+// RUN: grep 'noinline' %t
+
+void t1() __attribute__((noinline));
+
+void t1()
+{
+}
+
diff --git a/test/CodeGen/attr-used.c b/test/CodeGen/attr-used.c
new file mode 100644
index 000000000000..8521ffd2e4bb
--- /dev/null
+++ b/test/CodeGen/attr-used.c
@@ -0,0 +1,14 @@
+// RUN: clang-cc -emit-llvm -o %t %s &&
+// RUN: grep '@llvm.used = .*@g0' %t &&
+// RUN: grep '@llvm.used = .*@f0' %t &&
+// RUN: grep '@llvm.used = .*@f1.l0' %t
+
+
+int g0 __attribute__((used));
+
+static void __attribute__((used)) f0(void) {
+}
+
+void f1() {
+ static int l0 __attribute__((used)) = 5225;
+}
diff --git a/test/CodeGen/attributes.c b/test/CodeGen/attributes.c
new file mode 100644
index 000000000000..d45d5124b010
--- /dev/null
+++ b/test/CodeGen/attributes.c
@@ -0,0 +1,59 @@
+// RUN: clang-cc -emit-llvm -o %t %s &&
+// RUN: grep 't1.*noreturn' %t &&
+// RUN: grep 't2.*nounwind' %t &&
+// RUN: grep 'weak.*t3' %t &&
+// RUN: grep 'hidden.*t4' %t &&
+// RUN: grep 't5.*weak' %t &&
+// RUN: grep 't6.*protected' %t &&
+// RUN: grep 't7.*noreturn' %t &&
+// RUN: grep 't7.*nounwind' %t &&
+// RUN: grep 't9.*alias.*weak.*t8' %t &&
+// RUN: grep '@t10().*section "SECT"' %t &&
+// RUN: grep '@t11().*section "SECT"' %t &&
+// RUN: grep '@t12 =.*section "SECT"' %t &&
+// RUN: grep '@t13 =.*section "SECT"' %t &&
+// RUN: grep '@t14.x =.*section "SECT"' %t
+// RUN: grep 'declare extern_weak i32 @t15()' %t &&
+// RUN: grep '@t16 = extern_weak global i32' %t
+
+void t1() __attribute__((noreturn));
+void t1() {}
+
+void t2() __attribute__((nothrow));
+void t2() {}
+
+void t3() __attribute__((weak));
+void t3() {}
+
+void t4() __attribute__((visibility("hidden")));
+void t4() {}
+
+int t5 __attribute__((weak)) = 2;
+
+int t6 __attribute__((visibility("protected")));
+
+void t7() __attribute__((noreturn, nothrow));
+void t7() {}
+
+void __t8() {}
+void t9() __attribute__((weak, alias("__t8")));
+
+void t10(void) __attribute__((section("SECT")));
+void t10(void) {}
+void __attribute__((section("SECT"))) t11(void) {}
+
+int t12 __attribute__((section("SECT")));
+struct s0 { int x; };
+struct s0 t13 __attribute__((section("SECT"))) = { 0 };
+
+void t14(void) {
+ static int x __attribute__((section("SECT"))) = 0;
+}
+
+int __attribute__((weak_import)) t15(void);
+extern int t16 __attribute__((weak_import));
+int t17() {
+ return t15() + t16;
+}
+
+
diff --git a/test/CodeGen/bitfield-assign.c b/test/CodeGen/bitfield-assign.c
new file mode 100644
index 000000000000..05d4dda353c7
--- /dev/null
+++ b/test/CodeGen/bitfield-assign.c
@@ -0,0 +1,44 @@
+/* Check that the result of a bitfield assignment is properly
+ truncated and does not generate a redundant load. */
+
+/* Check that we get one load for each simple assign and two for the
+ compound assign (load the old value before the add then load again
+ to store back). Also check that our g0 pattern is good. */
+// RUN: clang-cc -triple i386-unknown-unknown -O0 -emit-llvm -o %t %s &&
+// RUN: grep 'load ' %t | count 5 &&
+// RUN: grep "@g0" %t | count 4 &&
+
+// Check that we got the right value.
+// RUN: clang-cc -triple i386-unknown-unknown -O3 -emit-llvm -o %t %s &&
+// RUN: grep 'load ' %t | count 0 &&
+// RUN: grep "@g0" %t | count 0
+
+struct s0 {
+ int f0 : 2;
+ _Bool f1 : 1;
+ unsigned f2 : 2;
+};
+
+int g0();
+
+void f0(void) {
+ struct s0 s;
+ if ((s.f0 = 3) != -1) g0();
+}
+
+void f1(void) {
+ struct s0 s;
+ if ((s.f1 = 3) != 1) g0();
+}
+
+void f2(void) {
+ struct s0 s;
+ if ((s.f2 = 3) != 3) g0();
+}
+
+void f3(void) {
+ struct s0 s;
+ // Just check this one for load counts.
+ s.f0 += 3;
+}
+
diff --git a/test/CodeGen/bitfield-init.c b/test/CodeGen/bitfield-init.c
new file mode 100644
index 000000000000..7459614a1254
--- /dev/null
+++ b/test/CodeGen/bitfield-init.c
@@ -0,0 +1,14 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+typedef struct { unsigned int i: 1; } c;
+const c d = { 1 };
+
+// PR2310
+struct Token {
+ unsigned n : 31;
+};
+void sqlite3CodeSubselect(){
+ struct Token one = { 1 };
+}
+
+typedef union T0 { char field0 : 2; } T0;
+T0 T0_values = { 0 };
diff --git a/test/CodeGen/bitfield-promote.c b/test/CodeGen/bitfield-promote.c
new file mode 100644
index 000000000000..5894e51626da
--- /dev/null
+++ b/test/CodeGen/bitfield-promote.c
@@ -0,0 +1,19 @@
+// RUN: clang -O3 -emit-llvm -S -o %t %s &&
+// RUN: grep 'ret i64 4294967292' %t | count 2 &&
+// RUN: grep 'ret i64 -4' %t | count 1 &&
+// RUN: true
+
+long long f0(void) {
+ struct { unsigned f0 : 32; } x = { 18 };
+ return (long long) (x.f0 - (int) 22);
+}
+
+long long f1(void) {
+ struct { unsigned f0 : 31; } x = { 18 };
+ return (long long) (x.f0 - (int) 22);
+}
+
+long long f2(void) {
+ struct { unsigned f0 ; } x = { 18 };
+ return (long long) (x.f0 - (int) 22);
+}
diff --git a/test/CodeGen/bitfield.c b/test/CodeGen/bitfield.c
new file mode 100644
index 000000000000..02f2de79f6bc
--- /dev/null
+++ b/test/CodeGen/bitfield.c
@@ -0,0 +1,74 @@
+// RUN: clang-cc -triple i386-unknown-unknown %s -emit-llvm -o %t -O3 &&
+// RUN: grep "ret i32" %t | count 4 &&
+// RUN: grep "ret i32 1" %t | count 4
+
+static int f0(int n) {
+ struct s0 {
+ int a : 30;
+ int b : 2;
+ long long c : 31;
+ } x = { 0xdeadbeef, 0xdeadbeef, 0xdeadbeef };
+
+ x.a += n;
+ x.b += n;
+ x.c += n;
+
+ return x.a + x.b + x.c;
+}
+
+int g0(void) {
+ return f0(-1) + 44335655;
+}
+
+static int f1(void) {
+ struct s1 {
+ int a:13;
+ char b;
+ unsigned short c:7;
+ } x;
+
+ x.a = -40;
+ x.b = 10;
+ x.c = 15;
+
+ return x.a + x.b + x.c;
+}
+
+int g1(void) {
+ return f1() + 16;
+}
+
+static int f2(void) {
+ struct s2 {
+ short a[3];
+ int b : 15;
+ } x;
+
+ x.a[0] = x.a[1] = x.a[2] = -40;
+ x.b = 10;
+
+ return x.b;
+}
+
+int g2(void) {
+ return f2() - 9;
+}
+
+static int f3(int n) {
+ struct s3 {
+ unsigned a:16;
+ unsigned b:28 __attribute__ ((packed));
+ } x = { 0xdeadbeef, 0xdeadbeef };
+ struct s4 {
+ signed a:16;
+ signed b:28 __attribute__ ((packed));
+ } y;
+ y.a = -0x56789abcL;
+ y.b = -0x56789abcL;
+ return ((y.a += x.a += n) +
+ (y.b += x.b += n));
+}
+
+int g3(void) {
+ return f3(20) + 130725747;
+}
diff --git a/test/CodeGen/blocks-1.c b/test/CodeGen/blocks-1.c
new file mode 100644
index 000000000000..10498cb00495
--- /dev/null
+++ b/test/CodeGen/blocks-1.c
@@ -0,0 +1,78 @@
+// RUN: clang-cc %s -emit-llvm -o %t -fblocks &&
+// RUN: grep "_Block_object_dispose" %t | count 17 &&
+// RUN: grep "__copy_helper_block_" %t | count 16 &&
+// RUN: grep "__destroy_helper_block_" %t | count 16 &&
+// RUN: grep "__Block_byref_id_object_copy_" %t | count 2 &&
+// RUN: grep "__Block_byref_id_object_dispose_" %t | count 2 &&
+// RUN: grep "i32 135)" %t | count 2 &&
+// RUN: grep "_Block_object_assign" %t | count 10
+
+#include <stdio.h>
+
+void test1() {
+ __block int a;
+ int b=2;
+ a=1;
+ printf("a is %d, b is %d\n", a, b);
+ ^{ a = 10; printf("a is %d, b is %d\n", a, b); }();
+ printf("a is %d, b is %d\n", a, b);
+ a = 1;
+ printf("a is %d, b is %d\n", a, b);
+}
+
+void test2() {
+ __block int a;
+ a=1;
+ printf("a is %d\n", a);
+ ^{
+ ^{
+ a = 10;
+ }();
+ }();
+ printf("a is %d\n", a);
+ a = 1;
+ printf("a is %d\n", a);
+}
+
+void test3() {
+ __block int k;
+ __block int (^j)(int);
+ ^{j=0; k=0;}();
+}
+
+int test4() {
+ extern int g;
+ static int i = 1;
+ ^(int j){ i = j; g = 0; }(0);
+ return i + g;
+}
+
+int g;
+
+void test5() {
+ __block struct { int i; } i;
+ ^{ (void)i; }();
+}
+
+void test6() {
+ __block int i;
+ ^{ i=1; }();
+ ^{}();
+}
+
+void test7() {
+ ^{
+ __block int i;
+ ^{ i = 1; }();
+ }();
+}
+
+int main() {
+ int rv = 0;
+ test1();
+ test2();
+ test3();
+ rv += test4();
+ test5();
+ return rv;
+}
diff --git a/test/CodeGen/blocks-2.c b/test/CodeGen/blocks-2.c
new file mode 100644
index 000000000000..5ee2a73a82c9
--- /dev/null
+++ b/test/CodeGen/blocks-2.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -g %s -emit-llvm -o %t -fblocks
+// RUN: grep "func.start" %t | count 4
+// 1 declaration, 1 bar, 1 test_block_dbg and 1 for the block.
+
+static __inline__ __attribute__((always_inline)) int bar(int va, int vb) { return (va == vb); }
+
+int test_block_dbg() {
+ extern int g;
+ static int i = 1;
+ ^(int j){ i = bar(3,4); }(0);
+ return i + g;
+}
+
diff --git a/test/CodeGen/blocks-seq.c b/test/CodeGen/blocks-seq.c
new file mode 100644
index 000000000000..f637fbc0782e
--- /dev/null
+++ b/test/CodeGen/blocks-seq.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fblocks -triple x86_64-apple-darwin10 -emit-llvm -o %t %s &&
+// RUN: grep '%call = call i32 (...)\* @rhs()' %t | count 1 &&
+// If this fails, see about sliding %4, %5, %6 and %7...
+// RUN: grep '%forwarding1 = getelementptr %0\* %i, i32 0, i32 1' %t | count 1 &&
+// RUN: grep '%4 = bitcast i8\*\* %forwarding1 to %0\*\*' %t | count 1 &&
+// RUN: grep '%5 = load %0\*\* %4' %t | count 1 &&
+// RUN: grep '%call2 = call i32 (...)\* @rhs()' %t | count 1 &&
+// RUN: grep '%forwarding3 = getelementptr %0\* %i, i32 0, i32 1' %t | count 1 &&
+// RUN: grep '%6 = bitcast i8\*\* %forwarding3 to %0\*\*' %t | count 1 &&
+// RUN: grep '%7 = load %0\*\* %6' %t | count 1
+
+int rhs();
+
+void foo() {
+ __block int i;
+ i = rhs();
+ i += rhs();
+}
diff --git a/test/CodeGen/blocks.c b/test/CodeGen/blocks.c
new file mode 100644
index 000000000000..39c5b06b1727
--- /dev/null
+++ b/test/CodeGen/blocks.c
@@ -0,0 +1,30 @@
+// RUN: clang-cc -triple i386-unknown-unknown %s -emit-llvm -o %t -fblocks &&
+void (^f)(void) = ^{};
+
+// rdar://6768379
+int f0(int (^a0)()) {
+ return a0(1, 2, 3);
+}
+
+// Verify that attributes on blocks are set correctly.
+typedef struct s0 T;
+struct s0 {
+ int a[64];
+};
+
+// RUN: grep 'internal void @__f2_block_invoke_(.struct.s0\* noalias sret .*, .*, .* byval .*)' %t &&
+struct s0 f2(struct s0 a0) {
+ return ^(struct s0 a1){ return a1; }(a0);
+}
+
+// This should not crash: rdar://6808051
+void *P = ^{
+ void *Q = __func__;
+};
+
+void (^test1)(void) = ^(void) {
+ __block int i;
+ ^ { i = 1; }();
+};
+
+// RUN: true
diff --git a/test/CodeGen/bool-bitfield.c b/test/CodeGen/bool-bitfield.c
new file mode 100644
index 000000000000..50990a47c285
--- /dev/null
+++ b/test/CodeGen/bool-bitfield.c
@@ -0,0 +1,54 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+// From GCC PR19331
+struct SysParams
+{
+ unsigned short tag;
+ unsigned short version;
+ unsigned int seqnum;
+ int contrast;
+ int igain_1, igain_2;
+ int oattn_1, oattn_2;
+ int max_out_vltg_1, max_out_vltg_2;
+ int max_mains_current;
+ int meters_mode;
+ int input_select;
+ _Bool input_parallelch2:1;
+ _Bool cliplmt_ch1:1;
+ _Bool cliplmt_ch2:1;
+ _Bool gate_ch1:1;
+ _Bool gate_ch2:1;
+ _Bool mute_ch1:1;
+ _Bool mute_ch2:1;
+ _Bool brownout:1;
+ _Bool power_on:1;
+ _Bool pwrup_mute:1;
+ _Bool keylock:1;
+ _Bool dsp_ch1:1;
+ _Bool dsp_ch2:1;
+ int dsp_preset;
+ long unlock_code;
+};
+extern struct SysParams params;
+
+void foo(void *);
+void kcmd_setParams(void)
+{
+ struct {
+ unsigned char igain_1;
+ unsigned char igain_2;
+ unsigned char max_out_vltg_1;
+ unsigned char max_out_vltg_2;
+ unsigned char max_imains;
+ unsigned char cliplmt_ch1:1;
+ unsigned char cliplmt_ch2:1;
+ unsigned char gate_ch1:1;
+ unsigned char gate_ch2:1;
+ } msg;
+ foo(&msg);
+ params.cliplmt_ch1 = msg.cliplmt_ch1;
+ params.cliplmt_ch2 = msg.cliplmt_ch2;
+ params.gate_ch1 = msg.gate_ch1;
+ params.gate_ch2 = msg.gate_ch2;
+}
+
diff --git a/test/CodeGen/bool-convert.c b/test/CodeGen/bool-convert.c
new file mode 100644
index 000000000000..4df81bb82d7c
--- /dev/null
+++ b/test/CodeGen/bool-convert.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -emit-llvm < %s | grep i1 | count 1
+// All of these should uses the memory representation of _Bool
+struct teststruct1 {_Bool a, b;} test1;
+_Bool* test2;
+_Bool test3[10];
+_Bool (*test4)[];
+void f(int x) {
+ _Bool test5;
+ _Bool test6[x];
+}
diff --git a/test/CodeGen/bool-init.c b/test/CodeGen/bool-init.c
new file mode 100644
index 000000000000..7d331ed07eb0
--- /dev/null
+++ b/test/CodeGen/bool-init.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -emit-llvm < %s | grep i1 | count 1
+
+// Check that the type of this global isn't i1
+_Bool test = &test;
diff --git a/test/CodeGen/boolassign.c b/test/CodeGen/boolassign.c
new file mode 100644
index 000000000000..2d14f8c1de19
--- /dev/null
+++ b/test/CodeGen/boolassign.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+
+int testBoolAssign(void) {
+int ss;
+if ((ss = ss && ss)) {}
+}
diff --git a/test/CodeGen/builtin-count-zeros.c b/test/CodeGen/builtin-count-zeros.c
new file mode 100644
index 000000000000..374acc43ae58
--- /dev/null
+++ b/test/CodeGen/builtin-count-zeros.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -emit-llvm %s -o - | grep 'cttz' | count 2 &&
+// RUN: clang-cc -emit-llvm %s -o - | grep 'ctlz' | count 2
+
+int a(int a) {return __builtin_ctz(a) + __builtin_clz(a);}
diff --git a/test/CodeGen/builtin-memfns.c b/test/CodeGen/builtin-memfns.c
new file mode 100644
index 000000000000..9ae380c5455b
--- /dev/null
+++ b/test/CodeGen/builtin-memfns.c
@@ -0,0 +1,15 @@
+// RUN: clang-cc -triple i386-pc-linux-gnu -emit-llvm -o %t %s &&
+// RUN: grep '@llvm.memset.i32' %t &&
+// RUN: grep '@llvm.memcpy.i32' %t &&
+// RUN: grep '@llvm.memmove.i32' %t &&
+// RUN: grep __builtin %t | count 0
+
+int main(int argc, char **argv) {
+ unsigned char a = 0x11223344;
+ unsigned char b = 0x11223344;
+ __builtin_bzero(&a, sizeof(a));
+ __builtin_memset(&a, 0, sizeof(a));
+ __builtin_memcpy(&a, &b, sizeof(a));
+ __builtin_memmove(&a, &b, sizeof(a));
+ return 0;
+}
diff --git a/test/CodeGen/builtin-nanf.c b/test/CodeGen/builtin-nanf.c
new file mode 100644
index 000000000000..e048c7a1aa5a
--- /dev/null
+++ b/test/CodeGen/builtin-nanf.c
@@ -0,0 +1,15 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm -o %t %s &&
+// RUN: grep 'float 0x7FF8000000000000, float 0x7FF8000000000000, float 0x7FF8000020000000, float 0x7FF8000000000000, float 0x7FF80001E0000000, float 0x7FF8001E00000000, float 0x7FF801E000000000, float 0x7FF81E0000000000, float 0x7FF9E00000000000, float 0x7FFFFFFFE0000000' %t
+
+float n[] = {
+ __builtin_nanf("0"),
+ __builtin_nanf(""),
+ __builtin_nanf("1"),
+ __builtin_nanf("0x7fc00000"),
+ __builtin_nanf("0x7fc0000f"),
+ __builtin_nanf("0x7fc000f0"),
+ __builtin_nanf("0x7fc00f00"),
+ __builtin_nanf("0x7fc0f000"),
+ __builtin_nanf("0x7fcf0000"),
+ __builtin_nanf("0xffffffff"),
+};
diff --git a/test/CodeGen/builtin-rename.c b/test/CodeGen/builtin-rename.c
new file mode 100644
index 000000000000..d0b5c2472de6
--- /dev/null
+++ b/test/CodeGen/builtin-rename.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc %s -emit-llvm -o - | grep 'declare.*printf' | count 1
+// PR3612
+
+int printf(const char *, ...);
+
+int foo(void) {
+ return printf(printf);
+}
diff --git a/test/CodeGen/builtin-stackaddress.c b/test/CodeGen/builtin-stackaddress.c
new file mode 100644
index 000000000000..5c6d540172a0
--- /dev/null
+++ b/test/CodeGen/builtin-stackaddress.c
@@ -0,0 +1,9 @@
+// RUN: clang-cc -emit-llvm < %s | grep "llvm.returnaddress" &&
+// RUN: clang-cc -emit-llvm < %s | grep "llvm.frameaddress"
+void* a(unsigned x) {
+return __builtin_return_address(0);
+}
+
+void* c(unsigned x) {
+return __builtin_frame_address(0);
+}
diff --git a/test/CodeGen/builtin-unwind-init.c b/test/CodeGen/builtin-unwind-init.c
new file mode 100644
index 000000000000..49a016a304f0
--- /dev/null
+++ b/test/CodeGen/builtin-unwind-init.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -emit-llvm < %s -o - | grep -F "llvm.eh.unwind.init"
+
+int a() { __builtin_unwind_init(); }
+
diff --git a/test/CodeGen/builtinmemcpy.c b/test/CodeGen/builtinmemcpy.c
new file mode 100644
index 000000000000..d1fdebbe8287
--- /dev/null
+++ b/test/CodeGen/builtinmemcpy.c
@@ -0,0 +1,3 @@
+// RUN: clang-cc -emit-llvm < %s -o - | grep "llvm.memcpy"
+
+char* x(char* a, char* b) {return __builtin_memcpy(a, b, 4);}
diff --git a/test/CodeGen/builtins-ffs_parity_popcount.c b/test/CodeGen/builtins-ffs_parity_popcount.c
new file mode 100644
index 000000000000..47469985eeda
--- /dev/null
+++ b/test/CodeGen/builtins-ffs_parity_popcount.c
@@ -0,0 +1,15 @@
+// RUN: clang-cc -emit-llvm -o - %s > %t
+// RUN: ! grep "__builtin" %t
+
+#include <stdio.h>
+
+void test(int M, long long N) {
+ printf("%d %lld: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ M, N,
+ __builtin_ffs(M), __builtin_ffsl(M), __builtin_ffsll(M),
+ __builtin_parity(M), __builtin_parityl(M), __builtin_parityll(M),
+ __builtin_popcount(M), __builtin_popcountl(M), __builtin_popcountll(M),
+ __builtin_ffs(N), __builtin_ffsl(N), __builtin_ffsll(N),
+ __builtin_parity(N), __builtin_parityl(N), __builtin_parityll(N),
+ __builtin_popcount(N), __builtin_popcountl(N), __builtin_popcountll(N));
+}
diff --git a/test/CodeGen/builtins-powi.c b/test/CodeGen/builtins-powi.c
new file mode 100644
index 000000000000..73f752f5e80e
--- /dev/null
+++ b/test/CodeGen/builtins-powi.c
@@ -0,0 +1,29 @@
+// RUN: clang-cc -emit-llvm -o - %s > %t
+// RUN: ! grep "__builtin" %t
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+void test(long double a, int b) {
+ printf("%Lf**%d: %08x %08x %016Lx\n",
+ a, b,
+ __builtin_powi(a, b),
+ __builtin_powif(a, b),
+ __builtin_powil(a, b)
+ );
+}
+
+int main() {
+ int i;
+
+ test(-1,-1LL);
+ test(0,0);
+ test(1,1);
+
+ for (i=0; i<3; i++) {
+ test(random(), i);
+ }
+
+ return 0;
+}
diff --git a/test/CodeGen/builtins-x86.c b/test/CodeGen/builtins-x86.c
new file mode 100644
index 000000000000..33ab36074fe0
--- /dev/null
+++ b/test/CodeGen/builtins-x86.c
@@ -0,0 +1,522 @@
+// RUN: clang-cc -DUSE_64 -triple x86_64-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: clang-cc -DUSE_ALL -triple x86_64-unknown-unknown -fsyntax-only -o %t %s
+
+#ifdef USE_ALL
+#define USE_3DNOW
+#define USE_64
+#define USE_SSE4
+#endif
+
+// 64-bit
+typedef char V8c __attribute__((vector_size(8 * sizeof(char))));
+typedef signed short V4s __attribute__((vector_size(8)));
+typedef signed int V2i __attribute__((vector_size(8)));
+typedef signed long long V1LLi __attribute__((vector_size(8)));
+
+typedef float V2f __attribute__((vector_size(8)));
+
+// 128-bit
+typedef char V16c __attribute__((vector_size(16)));
+typedef signed short V8s __attribute__((vector_size(16)));
+typedef signed int V4i __attribute__((vector_size(16)));
+typedef signed long long V2LLi __attribute__((vector_size(16)));
+
+typedef float V4f __attribute__((vector_size(16)));
+typedef double V2d __attribute__((vector_size(16)));
+
+void f0() {
+ signed char tmp_c;
+// unsigned char tmp_Uc;
+ signed short tmp_s;
+#ifdef USE_ALL
+ unsigned short tmp_Us;
+#endif
+ signed int tmp_i;
+ unsigned int tmp_Ui;
+ signed long long tmp_LLi;
+// unsigned long long tmp_ULLi;
+ float tmp_f;
+ double tmp_d;
+
+ void* tmp_vp;
+ const void* tmp_vCp;
+ char* tmp_cp;
+ const char* tmp_cCp;
+ int* tmp_ip;
+ float* tmp_fp;
+ const float* tmp_fCp;
+ double* tmp_dp;
+ const double* tmp_dCp;
+
+#define imm_i 32
+#define imm_i_0_2 0
+#define imm_i_0_4 3
+#define imm_i_0_8 7
+#define imm_i_0_16 15
+ // Check this.
+#define imm_i_0_256 0
+
+ V2i* tmp_V2ip;
+ V1LLi* tmp_V1LLip;
+ V2LLi* tmp_V2LLip;
+
+ // 64-bit
+ V8c tmp_V8c;
+ V4s tmp_V4s;
+ V2i tmp_V2i;
+ V1LLi tmp_V1LLi;
+#ifdef USE_3DNOW
+ V2f tmp_V2f;
+#endif
+
+ // 128-bit
+ V16c tmp_V16c;
+ V8s tmp_V8s;
+ V4i tmp_V4i;
+ V2LLi tmp_V2LLi;
+ V4f tmp_V4f;
+ V2d tmp_V2d;
+
+ tmp_i = __builtin_ia32_comieq(tmp_V4f, tmp_V4f);
+ tmp_i = __builtin_ia32_comilt(tmp_V4f, tmp_V4f);
+ tmp_i = __builtin_ia32_comile(tmp_V4f, tmp_V4f);
+ tmp_i = __builtin_ia32_comigt(tmp_V4f, tmp_V4f);
+ tmp_i = __builtin_ia32_comige(tmp_V4f, tmp_V4f);
+ tmp_i = __builtin_ia32_comineq(tmp_V4f, tmp_V4f);
+ tmp_i = __builtin_ia32_ucomieq(tmp_V4f, tmp_V4f);
+ tmp_i = __builtin_ia32_ucomilt(tmp_V4f, tmp_V4f);
+ tmp_i = __builtin_ia32_ucomile(tmp_V4f, tmp_V4f);
+ tmp_i = __builtin_ia32_ucomigt(tmp_V4f, tmp_V4f);
+ tmp_i = __builtin_ia32_ucomige(tmp_V4f, tmp_V4f);
+ tmp_i = __builtin_ia32_ucomineq(tmp_V4f, tmp_V4f);
+ tmp_i = __builtin_ia32_comisdeq(tmp_V2d, tmp_V2d);
+ tmp_i = __builtin_ia32_comisdlt(tmp_V2d, tmp_V2d);
+ tmp_i = __builtin_ia32_comisdle(tmp_V2d, tmp_V2d);
+ tmp_i = __builtin_ia32_comisdgt(tmp_V2d, tmp_V2d);
+ tmp_i = __builtin_ia32_comisdge(tmp_V2d, tmp_V2d);
+ tmp_i = __builtin_ia32_comisdneq(tmp_V2d, tmp_V2d);
+ tmp_i = __builtin_ia32_ucomisdeq(tmp_V2d, tmp_V2d);
+ tmp_i = __builtin_ia32_ucomisdlt(tmp_V2d, tmp_V2d);
+ tmp_i = __builtin_ia32_ucomisdle(tmp_V2d, tmp_V2d);
+ tmp_i = __builtin_ia32_ucomisdgt(tmp_V2d, tmp_V2d);
+ tmp_i = __builtin_ia32_ucomisdge(tmp_V2d, tmp_V2d);
+ tmp_i = __builtin_ia32_ucomisdneq(tmp_V2d, tmp_V2d);
+ tmp_V4f = __builtin_ia32_addps(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_subps(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_mulps(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_divps(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_addss(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_subss(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_mulss(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_divss(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_cmpps(tmp_V4f, tmp_V4f, 0);
+ tmp_V4f = __builtin_ia32_cmpps(tmp_V4f, tmp_V4f, 1);
+ tmp_V4f = __builtin_ia32_cmpps(tmp_V4f, tmp_V4f, 2);
+ tmp_V4f = __builtin_ia32_cmpps(tmp_V4f, tmp_V4f, 3);
+ tmp_V4f = __builtin_ia32_cmpps(tmp_V4f, tmp_V4f, 4);
+ tmp_V4f = __builtin_ia32_cmpps(tmp_V4f, tmp_V4f, 5);
+ tmp_V4f = __builtin_ia32_cmpps(tmp_V4f, tmp_V4f, 6);
+ tmp_V4f = __builtin_ia32_cmpps(tmp_V4f, tmp_V4f, 7);
+ tmp_V4f = __builtin_ia32_cmpss(tmp_V4f, tmp_V4f, 0);
+ tmp_V4f = __builtin_ia32_cmpss(tmp_V4f, tmp_V4f, 1);
+ tmp_V4f = __builtin_ia32_cmpss(tmp_V4f, tmp_V4f, 2);
+ tmp_V4f = __builtin_ia32_cmpss(tmp_V4f, tmp_V4f, 3);
+ tmp_V4f = __builtin_ia32_cmpss(tmp_V4f, tmp_V4f, 4);
+ tmp_V4f = __builtin_ia32_cmpss(tmp_V4f, tmp_V4f, 5);
+ tmp_V4f = __builtin_ia32_cmpss(tmp_V4f, tmp_V4f, 6);
+ tmp_V4f = __builtin_ia32_cmpss(tmp_V4f, tmp_V4f, 7);
+ tmp_V4f = __builtin_ia32_minps(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_maxps(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_minss(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_maxss(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_andps(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_andnps(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_orps(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_xorps(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_movss(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_movhlps(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_movlhps(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_unpckhps(tmp_V4f, tmp_V4f);
+ tmp_V4f = __builtin_ia32_unpcklps(tmp_V4f, tmp_V4f);
+ tmp_V8c = __builtin_ia32_paddb(tmp_V8c, tmp_V8c);
+ tmp_V4s = __builtin_ia32_paddw(tmp_V4s, tmp_V4s);
+ tmp_V2i = __builtin_ia32_paddd(tmp_V2i, tmp_V2i);
+
+ tmp_V1LLi = __builtin_ia32_paddq(tmp_V1LLi, tmp_V1LLi);
+ tmp_V8c = __builtin_ia32_psubb(tmp_V8c, tmp_V8c);
+ tmp_V4s = __builtin_ia32_psubw(tmp_V4s, tmp_V4s);
+ tmp_V2i = __builtin_ia32_psubd(tmp_V2i, tmp_V2i);
+ tmp_V1LLi = __builtin_ia32_psubq(tmp_V1LLi, tmp_V1LLi);
+ tmp_V8c = __builtin_ia32_paddsb(tmp_V8c, tmp_V8c);
+ tmp_V4s = __builtin_ia32_paddsw(tmp_V4s, tmp_V4s);
+ tmp_V8c = __builtin_ia32_psubsb(tmp_V8c, tmp_V8c);
+ tmp_V4s = __builtin_ia32_psubsw(tmp_V4s, tmp_V4s);
+ tmp_V8c = __builtin_ia32_paddusb(tmp_V8c, tmp_V8c);
+ tmp_V4s = __builtin_ia32_paddusw(tmp_V4s, tmp_V4s);
+ tmp_V8c = __builtin_ia32_psubusb(tmp_V8c, tmp_V8c);
+ tmp_V4s = __builtin_ia32_psubusw(tmp_V4s, tmp_V4s);
+ tmp_V4s = __builtin_ia32_pmullw(tmp_V4s, tmp_V4s);
+ tmp_V4s = __builtin_ia32_pmulhw(tmp_V4s, tmp_V4s);
+ tmp_V4s = __builtin_ia32_pmulhuw(tmp_V4s, tmp_V4s);
+ tmp_V1LLi = __builtin_ia32_pand(tmp_V1LLi, tmp_V1LLi);
+ tmp_V1LLi = __builtin_ia32_pandn(tmp_V1LLi, tmp_V1LLi);
+ tmp_V1LLi = __builtin_ia32_por(tmp_V1LLi, tmp_V1LLi);
+ tmp_V1LLi = __builtin_ia32_pxor(tmp_V1LLi, tmp_V1LLi);
+ tmp_V8c = __builtin_ia32_pavgb(tmp_V8c, tmp_V8c);
+ tmp_V4s = __builtin_ia32_pavgw(tmp_V4s, tmp_V4s);
+ tmp_V8c = __builtin_ia32_pcmpeqb(tmp_V8c, tmp_V8c);
+ tmp_V4s = __builtin_ia32_pcmpeqw(tmp_V4s, tmp_V4s);
+ tmp_V2i = __builtin_ia32_pcmpeqd(tmp_V2i, tmp_V2i);
+ tmp_V8c = __builtin_ia32_pcmpgtb(tmp_V8c, tmp_V8c);
+ tmp_V4s = __builtin_ia32_pcmpgtw(tmp_V4s, tmp_V4s);
+ tmp_V2i = __builtin_ia32_pcmpgtd(tmp_V2i, tmp_V2i);
+ tmp_V8c = __builtin_ia32_pmaxub(tmp_V8c, tmp_V8c);
+ tmp_V4s = __builtin_ia32_pmaxsw(tmp_V4s, tmp_V4s);
+ tmp_V8c = __builtin_ia32_pminub(tmp_V8c, tmp_V8c);
+ tmp_V4s = __builtin_ia32_pminsw(tmp_V4s, tmp_V4s);
+ tmp_V8c = __builtin_ia32_punpckhbw(tmp_V8c, tmp_V8c);
+ tmp_V4s = __builtin_ia32_punpckhwd(tmp_V4s, tmp_V4s);
+ tmp_V2i = __builtin_ia32_punpckhdq(tmp_V2i, tmp_V2i);
+ tmp_V8c = __builtin_ia32_punpcklbw(tmp_V8c, tmp_V8c);
+ tmp_V4s = __builtin_ia32_punpcklwd(tmp_V4s, tmp_V4s);
+ tmp_V2i = __builtin_ia32_punpckldq(tmp_V2i, tmp_V2i);
+ tmp_V2d = __builtin_ia32_addpd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_subpd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_mulpd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_divpd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_addsd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_subsd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_mulsd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_divsd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_cmppd(tmp_V2d, tmp_V2d, 0);
+ tmp_V2d = __builtin_ia32_cmppd(tmp_V2d, tmp_V2d, 1);
+ tmp_V2d = __builtin_ia32_cmppd(tmp_V2d, tmp_V2d, 2);
+ tmp_V2d = __builtin_ia32_cmppd(tmp_V2d, tmp_V2d, 3);
+ tmp_V2d = __builtin_ia32_cmppd(tmp_V2d, tmp_V2d, 4);
+ tmp_V2d = __builtin_ia32_cmppd(tmp_V2d, tmp_V2d, 5);
+ tmp_V2d = __builtin_ia32_cmppd(tmp_V2d, tmp_V2d, 6);
+ tmp_V2d = __builtin_ia32_cmppd(tmp_V2d, tmp_V2d, 7);
+ tmp_V2d = __builtin_ia32_cmpsd(tmp_V2d, tmp_V2d, 0);
+ tmp_V2d = __builtin_ia32_cmpsd(tmp_V2d, tmp_V2d, 1);
+ tmp_V2d = __builtin_ia32_cmpsd(tmp_V2d, tmp_V2d, 2);
+ tmp_V2d = __builtin_ia32_cmpsd(tmp_V2d, tmp_V2d, 3);
+ tmp_V2d = __builtin_ia32_cmpsd(tmp_V2d, tmp_V2d, 4);
+ tmp_V2d = __builtin_ia32_cmpsd(tmp_V2d, tmp_V2d, 5);
+ tmp_V2d = __builtin_ia32_cmpsd(tmp_V2d, tmp_V2d, 6);
+ tmp_V2d = __builtin_ia32_cmpsd(tmp_V2d, tmp_V2d, 7);
+ tmp_V2d = __builtin_ia32_minpd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_maxpd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_minsd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_maxsd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_andpd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_andnpd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_orpd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_xorpd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_movsd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_unpckhpd(tmp_V2d, tmp_V2d);
+ tmp_V2d = __builtin_ia32_unpcklpd(tmp_V2d, tmp_V2d);
+ tmp_V16c = __builtin_ia32_paddb128(tmp_V16c, tmp_V16c);
+ tmp_V8s = __builtin_ia32_paddw128(tmp_V8s, tmp_V8s);
+ tmp_V4i = __builtin_ia32_paddd128(tmp_V4i, tmp_V4i);
+ tmp_V2LLi = __builtin_ia32_paddq128(tmp_V2LLi, tmp_V2LLi);
+ tmp_V16c = __builtin_ia32_psubb128(tmp_V16c, tmp_V16c);
+ tmp_V8s = __builtin_ia32_psubw128(tmp_V8s, tmp_V8s);
+ tmp_V4i = __builtin_ia32_psubd128(tmp_V4i, tmp_V4i);
+ tmp_V2LLi = __builtin_ia32_psubq128(tmp_V2LLi, tmp_V2LLi);
+ tmp_V16c = __builtin_ia32_paddsb128(tmp_V16c, tmp_V16c);
+ tmp_V8s = __builtin_ia32_paddsw128(tmp_V8s, tmp_V8s);
+ tmp_V16c = __builtin_ia32_psubsb128(tmp_V16c, tmp_V16c);
+ tmp_V8s = __builtin_ia32_psubsw128(tmp_V8s, tmp_V8s);
+ tmp_V16c = __builtin_ia32_paddusb128(tmp_V16c, tmp_V16c);
+ tmp_V8s = __builtin_ia32_paddusw128(tmp_V8s, tmp_V8s);
+ tmp_V16c = __builtin_ia32_psubusb128(tmp_V16c, tmp_V16c);
+ tmp_V8s = __builtin_ia32_psubusw128(tmp_V8s, tmp_V8s);
+ tmp_V8s = __builtin_ia32_pmullw128(tmp_V8s, tmp_V8s);
+ tmp_V8s = __builtin_ia32_pmulhw128(tmp_V8s, tmp_V8s);
+ tmp_V2LLi = __builtin_ia32_pand128(tmp_V2LLi, tmp_V2LLi);
+ tmp_V2LLi = __builtin_ia32_pandn128(tmp_V2LLi, tmp_V2LLi);
+ tmp_V2LLi = __builtin_ia32_por128(tmp_V2LLi, tmp_V2LLi);
+ tmp_V2LLi = __builtin_ia32_pxor128(tmp_V2LLi, tmp_V2LLi);
+ tmp_V16c = __builtin_ia32_pavgb128(tmp_V16c, tmp_V16c);
+ tmp_V8s = __builtin_ia32_pavgw128(tmp_V8s, tmp_V8s);
+ tmp_V16c = __builtin_ia32_pcmpeqb128(tmp_V16c, tmp_V16c);
+ tmp_V8s = __builtin_ia32_pcmpeqw128(tmp_V8s, tmp_V8s);
+ tmp_V4i = __builtin_ia32_pcmpeqd128(tmp_V4i, tmp_V4i);
+ tmp_V16c = __builtin_ia32_pcmpgtb128(tmp_V16c, tmp_V16c);
+ tmp_V8s = __builtin_ia32_pcmpgtw128(tmp_V8s, tmp_V8s);
+ tmp_V4i = __builtin_ia32_pcmpgtd128(tmp_V4i, tmp_V4i);
+ tmp_V16c = __builtin_ia32_pmaxub128(tmp_V16c, tmp_V16c);
+ tmp_V8s = __builtin_ia32_pmaxsw128(tmp_V8s, tmp_V8s);
+ tmp_V16c = __builtin_ia32_pminub128(tmp_V16c, tmp_V16c);
+ tmp_V8s = __builtin_ia32_pminsw128(tmp_V8s, tmp_V8s);
+ tmp_V16c = __builtin_ia32_punpckhbw128(tmp_V16c, tmp_V16c);
+ tmp_V8s = __builtin_ia32_punpckhwd128(tmp_V8s, tmp_V8s);
+ tmp_V4i = __builtin_ia32_punpckhdq128(tmp_V4i, tmp_V4i);
+ tmp_V2LLi = __builtin_ia32_punpckhqdq128(tmp_V2LLi, tmp_V2LLi);
+ tmp_V16c = __builtin_ia32_punpcklbw128(tmp_V16c, tmp_V16c);
+ tmp_V8s = __builtin_ia32_punpcklwd128(tmp_V8s, tmp_V8s);
+ tmp_V4i = __builtin_ia32_punpckldq128(tmp_V4i, tmp_V4i);
+ tmp_V2LLi = __builtin_ia32_punpcklqdq128(tmp_V2LLi, tmp_V2LLi);
+ tmp_V8s = __builtin_ia32_packsswb128(tmp_V8s, tmp_V8s);
+ tmp_V4i = __builtin_ia32_packssdw128(tmp_V4i, tmp_V4i);
+ tmp_V8s = __builtin_ia32_packuswb128(tmp_V8s, tmp_V8s);
+ tmp_V8s = __builtin_ia32_pmulhuw128(tmp_V8s, tmp_V8s);
+ tmp_V4f = __builtin_ia32_addsubps(tmp_V4f, tmp_V4f);
+ tmp_V2d = __builtin_ia32_addsubpd(tmp_V2d, tmp_V2d);
+ tmp_V4f = __builtin_ia32_haddps(tmp_V4f, tmp_V4f);
+ tmp_V2d = __builtin_ia32_haddpd(tmp_V2d, tmp_V2d);
+ tmp_V4f = __builtin_ia32_hsubps(tmp_V4f, tmp_V4f);
+ tmp_V2d = __builtin_ia32_hsubpd(tmp_V2d, tmp_V2d);
+ tmp_V8s = __builtin_ia32_phaddw128(tmp_V8s, tmp_V8s);
+ tmp_V4s = __builtin_ia32_phaddw(tmp_V4s, tmp_V4s);
+ tmp_V4i = __builtin_ia32_phaddd128(tmp_V4i, tmp_V4i);
+ tmp_V2i = __builtin_ia32_phaddd(tmp_V2i, tmp_V2i);
+ tmp_V8s = __builtin_ia32_phaddsw128(tmp_V8s, tmp_V8s);
+ tmp_V4s = __builtin_ia32_phaddsw(tmp_V4s, tmp_V4s);
+ tmp_V8s = __builtin_ia32_phsubw128(tmp_V8s, tmp_V8s);
+ tmp_V4s = __builtin_ia32_phsubw(tmp_V4s, tmp_V4s);
+ tmp_V4i = __builtin_ia32_phsubd128(tmp_V4i, tmp_V4i);
+ tmp_V2i = __builtin_ia32_phsubd(tmp_V2i, tmp_V2i);
+ tmp_V8s = __builtin_ia32_phsubsw128(tmp_V8s, tmp_V8s);
+ tmp_V4s = __builtin_ia32_phsubsw(tmp_V4s, tmp_V4s);
+ tmp_V16c = __builtin_ia32_pmaddubsw128(tmp_V16c, tmp_V16c);
+ tmp_V8c = __builtin_ia32_pmaddubsw(tmp_V8c, tmp_V8c);
+ tmp_V8s = __builtin_ia32_pmulhrsw128(tmp_V8s, tmp_V8s);
+ tmp_V4s = __builtin_ia32_pmulhrsw(tmp_V4s, tmp_V4s);
+ tmp_V16c = __builtin_ia32_pshufb128(tmp_V16c, tmp_V16c);
+ tmp_V8c = __builtin_ia32_pshufb(tmp_V8c, tmp_V8c);
+ tmp_V16c = __builtin_ia32_psignb128(tmp_V16c, tmp_V16c);
+ tmp_V8c = __builtin_ia32_psignb(tmp_V8c, tmp_V8c);
+ tmp_V8s = __builtin_ia32_psignw128(tmp_V8s, tmp_V8s);
+ tmp_V4s = __builtin_ia32_psignw(tmp_V4s, tmp_V4s);
+ tmp_V4i = __builtin_ia32_psignd128(tmp_V4i, tmp_V4i);
+ tmp_V2i = __builtin_ia32_psignd(tmp_V2i, tmp_V2i);
+ tmp_V16c = __builtin_ia32_pabsb128(tmp_V16c);
+ tmp_V8c = __builtin_ia32_pabsb(tmp_V8c);
+ tmp_V8s = __builtin_ia32_pabsw128(tmp_V8s);
+ tmp_V4s = __builtin_ia32_pabsw(tmp_V4s);
+ tmp_V4i = __builtin_ia32_pabsd128(tmp_V4i);
+ tmp_V2i = __builtin_ia32_pabsd(tmp_V2i);
+ tmp_V4s = __builtin_ia32_psllw(tmp_V4s, tmp_V1LLi);
+ tmp_V2i = __builtin_ia32_pslld(tmp_V2i, tmp_V1LLi);
+ tmp_V1LLi = __builtin_ia32_psllq(tmp_V1LLi, tmp_V1LLi);
+ tmp_V4s = __builtin_ia32_psrlw(tmp_V4s, tmp_V1LLi);
+ tmp_V2i = __builtin_ia32_psrld(tmp_V2i, tmp_V1LLi);
+ tmp_V1LLi = __builtin_ia32_psrlq(tmp_V1LLi, tmp_V1LLi);
+ tmp_V4s = __builtin_ia32_psraw(tmp_V4s, tmp_V1LLi);
+ tmp_V2i = __builtin_ia32_psrad(tmp_V2i, tmp_V1LLi);
+#ifdef USE_ALL
+ tmp_V4s = __builtin_ia32_pshufw(tmp_V4s, imm_i);
+#endif
+ tmp_V2i = __builtin_ia32_pmaddwd(tmp_V4s, tmp_V4s);
+ tmp_V8c = __builtin_ia32_packsswb(tmp_V4s, tmp_V4s);
+ tmp_V4s = __builtin_ia32_packssdw(tmp_V2i, tmp_V2i);
+ tmp_V8c = __builtin_ia32_packuswb(tmp_V4s, tmp_V4s);
+
+ (void) __builtin_ia32_ldmxcsr(tmp_Ui);
+ tmp_Ui = __builtin_ia32_stmxcsr();
+ tmp_V4f = __builtin_ia32_cvtpi2ps(tmp_V4f, tmp_V2i);
+ tmp_V2i = __builtin_ia32_cvtps2pi(tmp_V4f);
+ tmp_V4f = __builtin_ia32_cvtsi2ss(tmp_V4f, tmp_i);
+#ifdef USE_64
+ tmp_V4f = __builtin_ia32_cvtsi642ss(tmp_V4f, tmp_LLi);
+#endif
+ tmp_i = __builtin_ia32_cvtss2si(tmp_V4f);
+#ifdef USE_64
+ tmp_LLi = __builtin_ia32_cvtss2si64(tmp_V4f);
+#endif
+ tmp_V2i = __builtin_ia32_cvttps2pi(tmp_V4f);
+ tmp_i = __builtin_ia32_cvttss2si(tmp_V4f);
+#ifdef USE_64
+ tmp_LLi = __builtin_ia32_cvttss2si64(tmp_V4f);
+#endif
+ (void) __builtin_ia32_maskmovq(tmp_V8c, tmp_V8c, tmp_cp);
+ tmp_V4f = __builtin_ia32_loadups(tmp_fCp);
+ (void) __builtin_ia32_storeups(tmp_fp, tmp_V4f);
+ tmp_V4f = __builtin_ia32_loadhps(tmp_V4f, tmp_V2ip);
+ tmp_V4f = __builtin_ia32_loadlps(tmp_V4f, tmp_V2ip);
+ (void) __builtin_ia32_storehps(tmp_V2ip, tmp_V4f);
+ (void) __builtin_ia32_storelps(tmp_V2ip, tmp_V4f);
+ tmp_i = __builtin_ia32_movmskps(tmp_V4f);
+ tmp_i = __builtin_ia32_pmovmskb(tmp_V8c);
+ (void) __builtin_ia32_movntps(tmp_fp, tmp_V4f);
+ (void) __builtin_ia32_movntq(tmp_V1LLip, tmp_V1LLi);
+ (void) __builtin_ia32_sfence();
+
+ tmp_V4s = __builtin_ia32_psadbw(tmp_V8c, tmp_V8c);
+ tmp_V4f = __builtin_ia32_rcpps(tmp_V4f);
+ tmp_V4f = __builtin_ia32_rcpss(tmp_V4f);
+ tmp_V4f = __builtin_ia32_rsqrtps(tmp_V4f);
+ tmp_V4f = __builtin_ia32_rsqrtss(tmp_V4f);
+ tmp_V4f = __builtin_ia32_sqrtps(tmp_V4f);
+ tmp_V4f = __builtin_ia32_sqrtss(tmp_V4f);
+ tmp_V4f = __builtin_ia32_shufps(tmp_V4f, tmp_V4f, imm_i);
+#ifdef USE_3DNOW
+ (void) __builtin_ia32_femms();
+ tmp_V8c = __builtin_ia32_pavgusb(tmp_V8c, tmp_V8c);
+ tmp_V2i = __builtin_ia32_pf2id(tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfacc(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfadd(tmp_V2f, tmp_V2f);
+ tmp_V2i = __builtin_ia32_pfcmpeq(tmp_V2f, tmp_V2f);
+ tmp_V2i = __builtin_ia32_pfcmpge(tmp_V2f, tmp_V2f);
+ tmp_V2i = __builtin_ia32_pfcmpgt(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfmax(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfmin(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfmul(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfrcp(tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfrcpit1(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfrcpit2(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfrsqrt(tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfrsqit1(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfsub(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfsubr(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pi2fd(tmp_V2i);
+ tmp_V4s = __builtin_ia32_pmulhrw(tmp_V4s, tmp_V4s);
+#endif
+#ifdef USE_3DNOWA
+ tmp_V2i = __builtin_ia32_pf2iw(tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfnacc(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfpnacc(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pi2fw(tmp_V2i);
+ tmp_V2f = __builtin_ia32_pswapdsf(tmp_V2f);
+ tmp_V2i = __builtin_ia32_pswapdsi(tmp_V2i);
+#endif
+ (void) __builtin_ia32_maskmovdqu(tmp_V16c, tmp_V16c, tmp_cp);
+ tmp_V2d = __builtin_ia32_loadupd(tmp_dCp);
+ (void) __builtin_ia32_storeupd(tmp_dp, tmp_V2d);
+ tmp_V2d = __builtin_ia32_loadhpd(tmp_V2d, tmp_dCp);
+ tmp_V2d = __builtin_ia32_loadlpd(tmp_V2d, tmp_dCp);
+ tmp_i = __builtin_ia32_movmskpd(tmp_V2d);
+ tmp_i = __builtin_ia32_pmovmskb128(tmp_V16c);
+ (void) __builtin_ia32_movnti(tmp_ip, tmp_i);
+ (void) __builtin_ia32_movntpd(tmp_dp, tmp_V2d);
+ (void) __builtin_ia32_movntdq(tmp_V2LLip, tmp_V2LLi);
+ tmp_V4i = __builtin_ia32_pshufd(tmp_V4i, imm_i);
+ tmp_V8s = __builtin_ia32_pshuflw(tmp_V8s, imm_i);
+ tmp_V8s = __builtin_ia32_pshufhw(tmp_V8s, imm_i);
+ tmp_V2LLi = __builtin_ia32_psadbw128(tmp_V16c, tmp_V16c);
+ tmp_V2d = __builtin_ia32_sqrtpd(tmp_V2d);
+ tmp_V2d = __builtin_ia32_sqrtsd(tmp_V2d);
+ tmp_V2d = __builtin_ia32_shufpd(tmp_V2d, tmp_V2d, imm_i);
+ tmp_V2d = __builtin_ia32_cvtdq2pd(tmp_V4i);
+ tmp_V4f = __builtin_ia32_cvtdq2ps(tmp_V4i);
+ tmp_V2LLi = __builtin_ia32_cvtpd2dq(tmp_V2d);
+ tmp_V2i = __builtin_ia32_cvtpd2pi(tmp_V2d);
+ tmp_V4f = __builtin_ia32_cvtpd2ps(tmp_V2d);
+ tmp_V4i = __builtin_ia32_cvttpd2dq(tmp_V2d);
+ tmp_V2i = __builtin_ia32_cvttpd2pi(tmp_V2d);
+ tmp_V2d = __builtin_ia32_cvtpi2pd(tmp_V2i);
+ tmp_i = __builtin_ia32_cvtsd2si(tmp_V2d);
+ tmp_i = __builtin_ia32_cvttsd2si(tmp_V2d);
+#ifdef USE_64
+ tmp_LLi = __builtin_ia32_cvtsd2si64(tmp_V2d);
+ tmp_LLi = __builtin_ia32_cvttsd2si64(tmp_V2d);
+#endif
+ tmp_V4i = __builtin_ia32_cvtps2dq(tmp_V4f);
+ tmp_V2d = __builtin_ia32_cvtps2pd(tmp_V4f);
+ tmp_V4i = __builtin_ia32_cvttps2dq(tmp_V4f);
+ tmp_V2d = __builtin_ia32_cvtsi2sd(tmp_V2d, tmp_i);
+#ifdef USE_64
+ tmp_V2d = __builtin_ia32_cvtsi642sd(tmp_V2d, tmp_LLi);
+#endif
+ tmp_V4f = __builtin_ia32_cvtsd2ss(tmp_V4f, tmp_V2d);
+ tmp_V2d = __builtin_ia32_cvtss2sd(tmp_V2d, tmp_V4f);
+ (void) __builtin_ia32_clflush(tmp_vCp);
+ (void) __builtin_ia32_lfence();
+ (void) __builtin_ia32_mfence();
+ tmp_V16c = __builtin_ia32_loaddqu(tmp_cCp);
+ (void) __builtin_ia32_storedqu(tmp_cp, tmp_V16c);
+ tmp_V4s = __builtin_ia32_psllwi(tmp_V4s, tmp_i);
+ tmp_V2i = __builtin_ia32_pslldi(tmp_V2i, tmp_i);
+ tmp_V1LLi = __builtin_ia32_psllqi(tmp_V1LLi, tmp_i);
+ tmp_V4s = __builtin_ia32_psrawi(tmp_V4s, tmp_i);
+ tmp_V2i = __builtin_ia32_psradi(tmp_V2i, tmp_i);
+ tmp_V4s = __builtin_ia32_psrlwi(tmp_V4s, tmp_i);
+ tmp_V2i = __builtin_ia32_psrldi(tmp_V2i, tmp_i);
+ tmp_V1LLi = __builtin_ia32_psrlqi(tmp_V1LLi, tmp_i);
+ tmp_V1LLi = __builtin_ia32_pmuludq(tmp_V2i, tmp_V2i);
+ tmp_V2LLi = __builtin_ia32_pmuludq128(tmp_V4i, tmp_V4i);
+ tmp_V8s = __builtin_ia32_psraw128(tmp_V8s, tmp_V8s);
+ tmp_V4i = __builtin_ia32_psrad128(tmp_V4i, tmp_V4i);
+ tmp_V8s = __builtin_ia32_psrlw128(tmp_V8s, tmp_V8s);
+ tmp_V4i = __builtin_ia32_psrld128(tmp_V4i, tmp_V4i);
+ tmp_V2LLi = __builtin_ia32_psrlq128(tmp_V2LLi, tmp_V2LLi);
+ tmp_V8s = __builtin_ia32_psllw128(tmp_V8s, tmp_V8s);
+ tmp_V4i = __builtin_ia32_pslld128(tmp_V4i, tmp_V4i);
+ tmp_V2LLi = __builtin_ia32_psllq128(tmp_V2LLi, tmp_V2LLi);
+ tmp_V8s = __builtin_ia32_psllwi128(tmp_V8s, tmp_i);
+ tmp_V4i = __builtin_ia32_pslldi128(tmp_V4i, tmp_i);
+ tmp_V2LLi = __builtin_ia32_psllqi128(tmp_V2LLi, tmp_i);
+ tmp_V8s = __builtin_ia32_psrlwi128(tmp_V8s, tmp_i);
+ tmp_V4i = __builtin_ia32_psrldi128(tmp_V4i, tmp_i);
+ tmp_V2LLi = __builtin_ia32_psrlqi128(tmp_V2LLi, tmp_i);
+ tmp_V8s = __builtin_ia32_psrawi128(tmp_V8s, tmp_i);
+ tmp_V4i = __builtin_ia32_psradi128(tmp_V4i, tmp_i);
+ tmp_V8s = __builtin_ia32_pmaddwd128(tmp_V8s, tmp_V8s);
+ (void) __builtin_ia32_monitor(tmp_vp, tmp_Ui, tmp_Ui);
+ (void) __builtin_ia32_mwait(tmp_Ui, tmp_Ui);
+#ifdef USE_ALL
+ tmp_V4f = __builtin_ia32_movshdup(tmp_V4f);
+ tmp_V4f = __builtin_ia32_movsldup(tmp_V4f);
+#endif
+ tmp_V16c = __builtin_ia32_lddqu(tmp_cCp);
+ tmp_V2LLi = __builtin_ia32_palignr128(tmp_V2LLi, tmp_V2LLi, imm_i);
+ tmp_V1LLi = __builtin_ia32_palignr(tmp_V1LLi, tmp_V1LLi, imm_i);
+ tmp_V2i = __builtin_ia32_vec_init_v2si(tmp_i, tmp_i);
+ tmp_V4s = __builtin_ia32_vec_init_v4hi(tmp_s, tmp_s, tmp_s, tmp_s);
+ tmp_V8c = __builtin_ia32_vec_init_v8qi(tmp_c, tmp_c, tmp_c, tmp_c, tmp_c, tmp_c, tmp_c, tmp_c);
+ tmp_d = __builtin_ia32_vec_ext_v2df(tmp_V2d, imm_i_0_2);
+ tmp_LLi = __builtin_ia32_vec_ext_v2di(tmp_V2LLi, imm_i_0_2);
+ tmp_f = __builtin_ia32_vec_ext_v4sf(tmp_V4f, imm_i_0_4);
+ tmp_i = __builtin_ia32_vec_ext_v4si(tmp_V4i, imm_i_0_4);
+#ifdef USE_ALL
+ tmp_Us = __builtin_ia32_vec_ext_v8hi(tmp_V8s, imm_i_0_8);
+ tmp_s = __builtin_ia32_vec_ext_v4hi(tmp_V4s, imm_i_0_4);
+#endif
+ tmp_i = __builtin_ia32_vec_ext_v2si(tmp_V2i, imm_i_0_2);
+ tmp_V8s = __builtin_ia32_vec_set_v8hi(tmp_V8s, tmp_s, imm_i_0_8);
+ tmp_V4s = __builtin_ia32_vec_set_v4hi(tmp_V4s, tmp_s, imm_i_0_4);
+ tmp_V4i = __builtin_ia32_loadlv4si(tmp_V2ip);
+ (void) __builtin_ia32_storelv4si(tmp_V2ip, tmp_V2LLi);
+#ifdef USE_SSE4
+ tmp_V16c = __builtin_ia32_pblendvb128(tmp_V16c, tmp_V16c, tmp_V16c);
+ tmp_V8s = __builtin_ia32_pblendw128(tmp_V8s, tmp_V8s, imm_i_0_256);
+ tmp_V2d = __builtin_ia32_blendpd(tmp_V2d, tmp_V2d, imm_i_0_256);
+ tmp_V4f = __builtin_ia32_blendps(tmp_V4f, tmp_V4f, imm_i_0_256);
+ tmp_V2d = __builtin_ia32_blendvpd(tmp_V2d, tmp_V2d, tmp_V2d);
+ tmp_V4f = __builtin_ia32_blendvps(tmp_V4f, tmp_V4f, tmp_V4f);
+ tmp_V8s = __builtin_ia32_packusdw128(tmp_V4i, tmp_V4i);
+ tmp_V16c = __builtin_ia32_pmaxsb128(tmp_V16c, tmp_V16c);
+ tmp_V4i = __builtin_ia32_pmaxsd128(tmp_V4i, tmp_V4i);
+ tmp_V4i = __builtin_ia32_pmaxud128(tmp_V4i, tmp_V4i);
+ tmp_V8s = __builtin_ia32_pmaxuw128(tmp_V8s, tmp_V8s);
+ tmp_V16c = __builtin_ia32_pminsb128(tmp_V16c, tmp_V16c);
+ tmp_V4i = __builtin_ia32_pminsd128(tmp_V4i, tmp_V4i);
+ tmp_V4i = __builtin_ia32_pminud128(tmp_V4i, tmp_V4i);
+ tmp_V8s = __builtin_ia32_pminuw128(tmp_V8s, tmp_V8s);
+ tmp_V4i = __builtin_ia32_pmovsxbd128(tmp_V16c);
+ tmp_V2LLi = __builtin_ia32_pmovsxbq128(tmp_V16c);
+ tmp_V8s = __builtin_ia32_pmovsxbw128(tmp_V16c);
+ tmp_V2LLi = __builtin_ia32_pmovsxdq128(tmp_V4i);
+ tmp_V4i = __builtin_ia32_pmovsxwd128(tmp_V8s);
+ tmp_V2LLi = __builtin_ia32_pmovsxwq128(tmp_V8s);
+ tmp_V4i = __builtin_ia32_pmovzxbd128(tmp_V16c);
+ tmp_V2LLi = __builtin_ia32_pmovzxbq128(tmp_V16c);
+ tmp_V8s = __builtin_ia32_pmovzxbw128(tmp_V16c);
+ tmp_V2LLi = __builtin_ia32_pmovzxdq128(tmp_V4i);
+ tmp_V4i = __builtin_ia32_pmovzxwd128(tmp_V8s);
+ tmp_V2LLi = __builtin_ia32_pmovzxwq128(tmp_V8s);
+ tmp_V2LLi = __builtin_ia32_pmuldq128(tmp_V4i, tmp_V4i);
+ tmp_V4i = __builtin_ia32_pmulld128(tmp_V4i, tmp_V4i);
+ tmp_V4f = __builtin_ia32_roundps(tmp_V4f, imm_i_0_16);
+ // tmp_V4f = __builtin_ia32_roundss(tmp_V4f, tmp_V4f, imm_i_0_16);
+ // tmp_V2d = __builtin_ia32_roundsd(tmp_V2d, tmp_V2d, imm_i_0_16);
+ tmp_V2d = __builtin_ia32_roundpd(tmp_V2d, imm_i_0_16);
+ tmp_V16c = __builtin_ia32_vec_set_v16qi(tmp_V16c, tmp_i, tmp_i);
+ tmp_V4i = __builtin_ia32_vec_set_v4si(tmp_V4i, tmp_i, tmp_i);
+ tmp_V4f = __builtin_ia32_insertps128(tmp_V4f, tmp_V4f, tmp_i);
+ tmp_V2LLi = __builtin_ia32_vec_set_v2di(tmp_V2LLi, tmp_LLi, tmp_i);
+#endif
+}
+
+
diff --git a/test/CodeGen/builtins.c b/test/CodeGen/builtins.c
new file mode 100644
index 000000000000..ce5cd74bd4c4
--- /dev/null
+++ b/test/CodeGen/builtins.c
@@ -0,0 +1,124 @@
+// RUN: clang-cc -emit-llvm -o %t %s &&
+// RUN: not grep __builtin %t
+
+#include <stdio.h>
+#include <math.h>
+
+void p(char *str, int x) {
+ printf("%s: %d\n", str, x);
+}
+void q(char *str, double x) {
+ printf("%s: %f\n", str, x);
+}
+
+int main() {
+ int N = random();
+#define P(n,args) p(#n #args, __builtin_##n args)
+#define Q(n,args) q(#n #args, __builtin_##n args)
+#define V(n,args) p(#n #args, (__builtin_##n args, 0))
+ P(types_compatible_p, (int, float));
+ P(choose_expr, (0, 10, 20));
+ P(constant_p, (sizeof(10)));
+ P(expect, (N == 12, 0));
+ V(prefetch, (&N));
+ V(prefetch, (&N, 1));
+ V(prefetch, (&N, 1, 0));
+
+ // Numeric Constants
+
+ Q(huge_val, ());
+ Q(huge_valf, ());
+ Q(huge_vall, ());
+ Q(inf, ());
+ Q(inff, ());
+ Q(infl, ());
+
+ // FIXME:
+ // XXX note funny semantics for the (last) argument
+ // P(fpclassify, (FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, 1.0));
+ // P(isinf_sign, (1.0));
+
+ Q(nan, (""));
+ Q(nanf, (""));
+ Q(nanl, (""));
+ Q(nans, (""));
+ Q(nan, ("10"));
+ Q(nanf, ("10"));
+ Q(nanl, ("10"));
+ Q(nans, ("10"));
+
+ P(isgreater, (1., 2.));
+ P(isgreaterequal, (1., 2.));
+ P(isless, (1., 2.));
+ P(islessequal, (1., 2.));
+ P(islessgreater, (1., 2.));
+ P(isunordered, (1., 2.));
+
+ // Bitwise & Numeric Functions
+
+ P(abs, (N));
+
+ P(clz, (N));
+ P(clzl, (N));
+ P(clzll, (N));
+ P(ctz, (N));
+ P(ctzl, (N));
+ P(ctzll, (N));
+ P(ffs, (N));
+ P(ffsl, (N));
+ P(ffsll, (N));
+ P(parity, (N));
+ P(parityl, (N));
+ P(parityll, (N));
+ P(popcount, (N));
+ P(popcountl, (N));
+ P(popcountll, (N));
+ Q(powi, (1.2f, N));
+ Q(powif, (1.2f, N));
+ Q(powil, (1.2f, N));
+
+ // Lib functions
+ int a, b, n = random(); // Avoid optimizing out.
+ char s0[10], s1[] = "Hello";
+ V(strcat, (s0, s1));
+ V(strcmp, (s0, s1));
+ V(strncat, (s0, s1, n));
+ V(strchr, (s0, s1[0]));
+ V(strrchr, (s0, s1[0]));
+ V(strcpy, (s0, s1));
+ V(strncpy, (s0, s1, n));
+
+ // Object size checking
+ V(__memset_chk, (s0, 0, sizeof s0, n));
+ V(__memcpy_chk, (s0, s1, sizeof s0, n));
+ V(__memmove_chk, (s0, s1, sizeof s0, n));
+ V(__mempcpy_chk, (s0, s1, sizeof s0, n));
+ V(__strncpy_chk, (s0, s1, sizeof s0, n));
+ V(__strcpy_chk, (s0, s1, n));
+ s0[0] = 0;
+ V(__strcat_chk, (s0, s1, n));
+ P(object_size, (s0, 0));
+ P(object_size, (s0, 1));
+ P(object_size, (s0, 2));
+ P(object_size, (s0, 3));
+
+ // Whatever
+
+ P(bswap32, (N));
+ P(bswap64, (N));
+ // FIXME
+ // V(clear_cache, (&N, &N+1));
+ V(trap, ());
+ P(extract_return_addr, (&N));
+
+ return 0;
+}
+
+
+
+void strcat() {}
+
+void foo() {
+ __builtin_strcat(0, 0);
+}
+
diff --git a/test/CodeGen/builtinshufflevector.c b/test/CodeGen/builtinshufflevector.c
new file mode 100644
index 000000000000..9a3ae610282e
--- /dev/null
+++ b/test/CodeGen/builtinshufflevector.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -emit-llvm < %s | grep 'shufflevector' | count 1
+typedef int v4si __attribute__ ((vector_size (16)));
+
+v4si a(v4si x, v4si y) {return __builtin_shufflevector(x, y, 3, 2, 5, 7);}
+
diff --git a/test/CodeGen/c-strings.c b/test/CodeGen/c-strings.c
new file mode 100644
index 000000000000..ee85f60ed15a
--- /dev/null
+++ b/test/CodeGen/c-strings.c
@@ -0,0 +1,36 @@
+// RUN: clang-cc -emit-llvm -o %t %s &&
+// RUN: grep "hello" %t | count 3 &&
+// RUN: grep 'c"hello\\00"' %t | count 2 &&
+// RUN: grep 'c"hello\\00\\00\\00"' %t | count 1 &&
+// RUN: grep 'c"ola"' %t | count 1
+
+/* Should be 3 hello string, two global (of different sizes), the rest
+ are shared. */
+
+void f0() {
+ bar("hello");
+}
+
+void f1() {
+ static char *x = "hello";
+ bar(x);
+}
+
+void f2() {
+ static char x[] = "hello";
+ bar(x);
+}
+
+void f3() {
+ static char x[8] = "hello";
+ bar(x);
+}
+
+void f4() {
+ static struct s {
+ char *name;
+ } x = { "hello" };
+ gaz(&x);
+}
+
+char x[3] = "ola";
diff --git a/test/CodeGen/cast-to-union.c b/test/CodeGen/cast-to-union.c
new file mode 100644
index 000000000000..03aee3e30c4f
--- /dev/null
+++ b/test/CodeGen/cast-to-union.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -emit-llvm < %s -o %t &&
+// RUN: grep "store i32 351, i32*" %t &&
+// RUN: grep "w = global %0 <{ i32 2, i8 0, i8 0, i8 0, i8 0 }>" %t &&
+// RUN: grep "y = global %1 <{ double 7.300000e+01 }>" %t
+
+union u { int i; double d; };
+
+void foo() {
+ union u ola = (union u) 351;
+}
+
+union u w = (union u)2;
+union u y = (union u)73.0;
diff --git a/test/CodeGen/cast.c b/test/CodeGen/cast.c
new file mode 100644
index 000000000000..6fb2b116d47b
--- /dev/null
+++ b/test/CodeGen/cast.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+
+extern void go(const void *p);
+float v[2] = { 0.0, 1.0 };
+void foo(void) { go(v); }
+
diff --git a/test/CodeGen/cfstring.c b/test/CodeGen/cfstring.c
new file mode 100644
index 000000000000..a78dfdaf6502
--- /dev/null
+++ b/test/CodeGen/cfstring.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+#define CFSTR __builtin___CFStringMakeConstantString
+
+void f() {
+ CFSTR("Hello, World!");
+}
+
+// rdar://6248329
+void *G = CFSTR("yo joe");
+
+void h() {
+ static void* h = CFSTR("Goodbye, World!");
+}
diff --git a/test/CodeGen/cfstring2.c b/test/CodeGen/cfstring2.c
new file mode 100644
index 000000000000..ceefeb9e832c
--- /dev/null
+++ b/test/CodeGen/cfstring2.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+typedef const struct __CFString * CFStringRef;
+
+#define CFSTR(x) (CFStringRef) __builtin___CFStringMakeConstantString (x)
+
+void f() {
+ CFSTR("Hello, World!");
+}
+
+// rdar://6151192
+void *G = CFSTR("yo joe");
+
diff --git a/test/CodeGen/cleanup-stack.c b/test/CodeGen/cleanup-stack.c
new file mode 100644
index 000000000000..b0c5e88d55ec
--- /dev/null
+++ b/test/CodeGen/cleanup-stack.c
@@ -0,0 +1,25 @@
+// RUN: clang-cc -triple i386-unknown-unknown -O3 -emit-llvm %s -o %t &&
+// RUN: grep "ret i32 9" %t
+
+struct s0 {
+ int *var;
+ int addend;
+};
+
+static void f0(struct s0 *p) {
+ *p->var += p->addend;
+}
+
+int f1(void) {
+ int var = 0;
+
+ {
+ struct s0 x __attribute__((cleanup(f0))) = { &var, 2 };
+ struct s0 y __attribute__((cleanup(f0))) = { &var, 3 };
+ {
+ struct s0 y __attribute__((cleanup(f0))) = { &var, 4 };
+ }
+ }
+
+ return var;
+}
diff --git a/test/CodeGen/complex.c b/test/CodeGen/complex.c
new file mode 100644
index 000000000000..6a0d3d628c54
--- /dev/null
+++ b/test/CodeGen/complex.c
@@ -0,0 +1,61 @@
+// RUN: clang-cc -emit-llvm < %s
+
+int main(void)
+{
+ double _Complex a = 5;
+ double _Complex b = 42;
+
+ return a * b != b * a;
+}
+
+_Complex double bar(int);
+void test(_Complex double*);
+void takecomplex(_Complex double);
+
+void test2(int c) {
+ _Complex double X;
+ X = bar(1);
+ test(&X);
+ takecomplex(X);
+}
+
+_Complex double g1, g2;
+_Complex float cf;
+double D;
+
+void test3() {
+ g1 = g1 + g2;
+ g1 = g1 - g2;
+ g1 = g1 * g2;
+ g1 = +-~g1;
+
+ double Gr = __real g1;
+
+ cf += D;
+ // FIXME: Currently unsupported!
+ //D += cf;
+ cf /= g1;
+ g1 = g1 + D;
+ g1 = D + g1;
+}
+
+void t1() {
+ (__real__ cf) = 4.0;
+}
+
+void t2() {
+ (__imag__ cf) = 4.0;
+}
+
+// PR1960
+void t3() {
+ __complex__ long long v = 2;
+}
+
+// PR3131
+float _Complex t4();
+
+void t5() {
+ float _Complex x = t4();
+}
+
diff --git a/test/CodeGen/compound-literal.c b/test/CodeGen/compound-literal.c
new file mode 100644
index 000000000000..ef0436744dae
--- /dev/null
+++ b/test/CodeGen/compound-literal.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc < %s -emit-llvm
+
+int* a = &(int){1};
+struct s {int a, b, c;} * b = &(struct s) {1, 2, 3};
+// Not working; complex constants are broken
+// _Complex double * x = &(_Complex double){1.0f};
+
+int xxx() {
+int* a = &(int){1};
+struct s {int a, b, c;} * b = &(struct s) {1, 2, 3};
+_Complex double * x = &(_Complex double){1.0f};
+}
diff --git a/test/CodeGen/compound-type.c b/test/CodeGen/compound-type.c
new file mode 100644
index 000000000000..352f6cc3ce65
--- /dev/null
+++ b/test/CodeGen/compound-type.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc < %s -emit-llvm -triple i686-pc-linux-gnu > %t &&
+// RUN: grep "div i32" %t &&
+// RUN: grep "shl i32" %t
+
+unsigned char a,b;
+void c(void) {a <<= b;}
+void d(void) {a /= b;}
diff --git a/test/CodeGen/compound.c b/test/CodeGen/compound.c
new file mode 100644
index 000000000000..c54600705330
--- /dev/null
+++ b/test/CodeGen/compound.c
@@ -0,0 +1,25 @@
+// RUN: clang-cc < %s -emit-llvm
+int A;
+long long B;
+int C;
+int *P;
+void test1() {
+ C = (A /= B);
+
+ P -= 4;
+
+ C = P - (P+10);
+}
+
+short x;
+void test2(char c) { x += c; }
+
+void foo(char *strbuf) {
+ int stufflen = 4;
+ strbuf += stufflen;
+}
+
+
+// Aggregate cast to void
+union uu { int a;}; void f(union uu p) { (void) p;}
+
diff --git a/test/CodeGen/conditional-gnu-ext.c b/test/CodeGen/conditional-gnu-ext.c
new file mode 100644
index 000000000000..1483d8af8592
--- /dev/null
+++ b/test/CodeGen/conditional-gnu-ext.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+// PR1824
+
+int foo(int x, short y) {
+ return x ?: y;
+}
+
+// rdar://6586493
+float test(float x, int Y) {
+ return Y != 0 ? : x;
+}
+
diff --git a/test/CodeGen/conditional.c b/test/CodeGen/conditional.c
new file mode 100644
index 000000000000..22286705c89c
--- /dev/null
+++ b/test/CodeGen/conditional.c
@@ -0,0 +1,44 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+float test1(int cond, float a, float b)
+{
+ return cond ? a : b;
+}
+double test2(int cond, float a, double b)
+{
+ return cond ? a : b;
+}
+
+void f();
+
+void test3(){
+ 1 ? f() : (void)0;
+}
+
+void test4() {
+int i; short j;
+float* k = 1 ? &i : &j;
+}
+
+void test5() {
+ const int* cip;
+ void* vp;
+ cip = 0 ? vp : cip;
+}
+
+void test6();
+void test7(int);
+void* test8() {return 1 ? test6 : test7;}
+
+
+void _efree(void *ptr);
+
+void _php_stream_free3()
+{
+ (1 ? free(0) : _efree(0));
+}
+
+void _php_stream_free4()
+{
+ 1 ? _efree(0) : free(0);
+}
diff --git a/test/CodeGen/const-init.c b/test/CodeGen/const-init.c
new file mode 100644
index 000000000000..0364cc153ff8
--- /dev/null
+++ b/test/CodeGen/const-init.c
@@ -0,0 +1,104 @@
+// RUN: clang-cc -triple i386-pc-linux-gnu -verify -emit-llvm -o %t %s &&
+
+#include <stdint.h>
+
+// Brace-enclosed string array initializers
+char a[] = { "asdf" };
+
+// Double-implicit-conversions of array/functions (not legal C, but
+// clang accepts it for gcc compat).
+intptr_t b = a; // expected-warning {{incompatible pointer to integer conversion}}
+int c();
+void *d = c;
+intptr_t e = c; // expected-warning {{incompatible pointer to integer conversion}}
+
+int f, *g = __extension__ &f, *h = (1 != 1) ? &f : &f;
+
+union s2 {
+ struct {
+ struct { } *f0;
+ } f0;
+};
+
+int g0 = (int)(&(((union s2 *) 0)->f0.f0) - 0);
+
+// RUN: grep '@g1x = global %. { double 1.000000e+00, double 0.000000e+00 }' %t &&
+_Complex double g1x = 1.0f;
+// RUN: grep '@g1y = global %. { double 0.000000e+00, double 1.000000e+00 }' %t &&
+_Complex double g1y = 1.0fi;
+// RUN: grep '@g1 = global %. { i8 1, i8 10 }' %t &&
+_Complex char g1 = (char) 1 + (char) 10 * 1i;
+// RUN: grep '@g2 = global %2 { i32 1, i32 10 }' %t &&
+_Complex int g2 = 1 + 10i;
+// RUN: grep '@g3 = global %. { float 1.000000e+00, float 1.000000e+01 }' %t &&
+_Complex float g3 = 1.0 + 10.0i;
+// RUN: grep '@g4 = global %. { double 1.000000e+00, double 1.000000e+01 }' %t &&
+_Complex double g4 = 1.0 + 10.0i;
+// RUN: grep '@g5 = global %2 zeroinitializer' %t &&
+_Complex int g5 = (2 + 3i) == (5 + 7i);
+// RUN: grep '@g6 = global %. { double -1.100000e+01, double 2.900000e+01 }' %t &&
+_Complex double g6 = (2.0 + 3.0i) * (5.0 + 7.0i);
+// RUN: grep '@g7 = global i32 1' %t &&
+int g7 = (2 + 3i) * (5 + 7i) == (-11 + 29i);
+// RUN: grep '@g8 = global i32 1' %t &&
+int g8 = (2.0 + 3.0i) * (5.0 + 7.0i) == (-11.0 + 29.0i);
+// RUN: grep '@g9 = global i32 0' %t &&
+int g9 = (2 + 3i) * (5 + 7i) != (-11 + 29i);
+// RUN: grep '@g10 = global i32 0' %t &&
+int g10 = (2.0 + 3.0i) * (5.0 + 7.0i) != (-11.0 + 29.0i);
+
+
+// Global references
+// RUN: grep '@g11.l0 = internal global i32 ptrtoint (i32 ()\* @g11 to i32)' %t &&
+long g11() {
+ static long l0 = (long) g11;
+ return l0;
+}
+
+// RUN: grep '@g12 = global i32 ptrtoint (i8\* @g12_tmp to i32)' %t &&
+static char g12_tmp;
+long g12 = (long) &g12_tmp;
+
+// RUN: grep '@g13 = global \[1 x .struct.g13_s0\] \[.struct.g13_s0 <{ i32 ptrtoint (i8\* @g12_tmp to i32) }>\]' %t &&
+struct g13_s0 {
+ long a;
+};
+struct g13_s0 g13[] = {
+ { (long) &g12_tmp }
+};
+
+// RUN: grep '@g14 = global i8\* inttoptr (i64 100 to i8\*)' %t &&
+void *g14 = (void*) 100;
+
+// RUN: grep '@g15 = global i32 -1' %t &&
+int g15 = (int) (char) ((void*) 0 + 255);
+
+// RUN: grep '@g16 = global i64 4294967295' %t &&
+long long g16 = (long long) ((void*) 0xFFFFFFFF);
+
+// RUN: grep '@g17 = global i32\* @g15' %t &&
+int *g17 = (int *) ((long) &g15);
+
+// RUN: grep '@g18.p = internal global \[1 x i32\*\] \[i32\* @g19\]' %t &&
+void g18(void) {
+ extern int g19;
+ static int *p[] = { &g19 };
+}
+
+// RUN: grep '@g20.l0 = internal global .struct.g20_s1 <{ .struct.g20_s0\* null, .struct.g20_s0\*\* getelementptr (.struct.g20_s1\* @g20.l0, i32 0, i32 0) }>' %t &&
+
+struct g20_s0;
+struct g20_s1 {
+ struct g20_s0 *f0, **f1;
+};
+void *g20(void) {
+ static struct g20_s1 l0 = { ((void*) 0), &l0.f0 };
+ return l0.f1;
+}
+
+// PR4108
+struct g21 {int g21;};
+const struct g21 g21 = (struct g21){1};
+
+// RUN: true
+
diff --git a/test/CodeGen/const-label-addr.c b/test/CodeGen/const-label-addr.c
new file mode 100644
index 000000000000..f8c35c676783
--- /dev/null
+++ b/test/CodeGen/const-label-addr.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+int a() {
+A:;static void* a = &&A;
+}
diff --git a/test/CodeGen/constant-comparison.c b/test/CodeGen/constant-comparison.c
new file mode 100644
index 000000000000..ea3e8962b333
--- /dev/null
+++ b/test/CodeGen/constant-comparison.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -emit-llvm %s -o - 2>&1 | not grep warning &&
+// RUN: clang-cc -emit-llvm %s -o - | grep @b | count 1
+
+int a, b;
+int *c1 = 1 < 2 ? &a : &b;
+int *c2 = 3 != 3LL ? &b : &a;
+int *c3 = !(3 <= 4.0) ? &b : &a;
+int *c4 = &a - (6 * 5 > 30);
+int *c5 = &a + (6 * 5 >= 30);
+int c6 = 44 < 33;
+
+
diff --git a/test/CodeGen/constructor-attribute.c b/test/CodeGen/constructor-attribute.c
new file mode 100644
index 000000000000..9a1fa76c622a
--- /dev/null
+++ b/test/CodeGen/constructor-attribute.c
@@ -0,0 +1,38 @@
+// RUN: clang-cc -emit-llvm -o %t %s &&
+// RUN: grep -e "global_ctors.*@A" %t &&
+// RUN: grep -e "global_dtors.*@B" %t &&
+// RUN: grep -e "global_ctors.*@C" %t &&
+// RUN: grep -e "global_dtors.*@D" %t
+
+#include <stdio.h>
+
+void A() __attribute__((constructor));
+void B() __attribute__((destructor));
+
+void A() {
+ printf("A\n");
+}
+
+void B() {
+ printf("B\n");
+}
+
+static void C() __attribute__((constructor));
+
+static void D() __attribute__((destructor));
+
+static int foo() {
+ return 10;
+}
+
+static void C() {
+ printf("A: %d\n", foo());
+}
+
+static void D() {
+ printf("B\n");
+}
+
+int main() {
+ return 0;
+}
diff --git a/test/CodeGen/cxx-condition.cpp b/test/CodeGen/cxx-condition.cpp
new file mode 100644
index 000000000000..330a17a10a43
--- /dev/null
+++ b/test/CodeGen/cxx-condition.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+void f() {
+ int a;
+ if (int x=a) ++a; else a=x;
+ while (int x=a) ++a;
+ for (; int x=a; --a) ;
+ switch (int x=0) { }
+}
diff --git a/test/CodeGen/cxx-default-arg.cpp b/test/CodeGen/cxx-default-arg.cpp
new file mode 100644
index 000000000000..8391b9ccae19
--- /dev/null
+++ b/test/CodeGen/cxx-default-arg.cpp
@@ -0,0 +1,25 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+// Note: define CLANG_GENERATE_KNOWN_GOOD and compile to generate code
+// that makes all of the defaulted arguments explicit. The resulting
+// byte code should be identical to the compilation without
+// CLANG_GENERATE_KNOWN_GOOD.
+#ifdef CLANG_GENERATE_KNOWN_GOOD
+# define DEFARG(...) __VA_ARGS__
+#else
+# define DEFARG(...)
+#endif
+
+extern int x;
+struct S { float x; float y; } s;
+double _Complex c;
+
+void f(int i = 0, int j = 1, int k = x, struct S t = s, double _Complex d = c);
+
+void g() {
+ f(0, 1, x, s DEFARG(, c));
+ f(0, 1, x DEFARG(, s, c));
+ f(0, 1 DEFARG(, x, s, c));
+ f(0 DEFARG(, 1, x, s, c));
+ f(DEFARG(0, 1, x, s, c));
+}
diff --git a/test/CodeGen/cxx-value-init.cpp b/test/CodeGen/cxx-value-init.cpp
new file mode 100644
index 000000000000..e23869879fbd
--- /dev/null
+++ b/test/CodeGen/cxx-value-init.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+enum E {};
+int v1 = E();
+float v2 = float();
+
+void f() {
+ int v3 = int();
+ _Complex int v4 = typeof(_Complex int)();
+ _Complex float v5 = typeof(_Complex float)();
+}
diff --git a/test/CodeGen/darwin-string-literals.c b/test/CodeGen/darwin-string-literals.c
new file mode 100644
index 000000000000..ff245fcc7a5c
--- /dev/null
+++ b/test/CodeGen/darwin-string-literals.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm %s -o %t &&
+
+// RUN: grep -F '@"\01LC" = internal constant [8 x i8] c"string0\00"' %t &&
+// RUN: grep -F '@"\01LC1" = internal constant [8 x i8] c"string1\00", section "__TEXT,__cstring,cstring_literals"' %t &&
+// RUN: grep -F '@__utf16_string_ = internal global [35 x i8] c"h\00e\00l\00l\00o\00 \00\92! \00\03& \00\90! \00w\00o\00r\00l\00d\00\00", section "__TEXT,__ustring", align 2' %t &&
+// RUN: true
+
+const char *g0 = "string0";
+const void *g1 = __builtin___CFStringMakeConstantString("string1");
+const void *g2 = __builtin___CFStringMakeConstantString("hello \u2192 \u2603 \u2190 world");
diff --git a/test/CodeGen/debug-info.c b/test/CodeGen/debug-info.c
new file mode 100644
index 000000000000..e0ec2c9027cf
--- /dev/null
+++ b/test/CodeGen/debug-info.c
@@ -0,0 +1,37 @@
+// RUN: clang-cc -o %t --emit-llvm -g %s
+
+// PR3023
+void convert(void) {
+ struct { typeof(0) f0; } v0;
+}
+
+// PR2784
+struct OPAQUE;
+typedef struct OPAQUE *PTR;
+PTR p;
+
+
+// PR2950
+struct s0;
+struct s0 { struct s0 *p; } g0;
+
+struct s0 *f0(struct s0 *a0) {
+ return a0->p;
+}
+
+// PR3134
+char xpto[];
+
+// PR3427
+struct foo {
+ int a;
+ void *ptrs[];
+};
+struct foo bar;
+
+// PR4143
+struct foo2 {
+ enum bar *bar;
+};
+
+struct foo2 foo2;
diff --git a/test/CodeGen/designated-initializers.c b/test/CodeGen/designated-initializers.c
new file mode 100644
index 000000000000..466933928665
--- /dev/null
+++ b/test/CodeGen/designated-initializers.c
@@ -0,0 +1,21 @@
+// RUN: clang-cc -triple i386-unknown-unknown %s -emit-llvm -o - | grep "<{ i8\* null, i32 1024 }>" &&
+// RUN: clang-cc -triple i386-unknown-unknown %s -emit-llvm -o - | grep "i32 0, i32 22"
+
+struct foo {
+ void *a;
+ int b;
+};
+
+union { int i; float f; } u = { };
+
+int main(int argc, char **argv)
+{
+ union { int i; float f; } u2 = { };
+ static struct foo foo = {
+ .b = 1024,
+ };
+}
+
+int b[2] = {
+ [1] 22
+};
diff --git a/test/CodeGen/dllimport-dllexport.c b/test/CodeGen/dllimport-dllexport.c
new file mode 100644
index 000000000000..fe49ae7a32af
--- /dev/null
+++ b/test/CodeGen/dllimport-dllexport.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -emit-llvm < %s -o %t &&
+// RUN: grep 'dllexport' %t | count 1 &&
+// RUN: not grep 'dllimport' %t
+
+void __attribute__((dllimport)) foo1();
+void __attribute__((dllexport)) foo1(){}
+void __attribute__((dllexport)) foo2();
diff --git a/test/CodeGen/dostmt.c b/test/CodeGen/dostmt.c
new file mode 100644
index 000000000000..4fb3dcdee9bc
--- /dev/null
+++ b/test/CodeGen/dostmt.c
@@ -0,0 +1,70 @@
+// RUN: clang-cc %s -emit-llvm -o -
+
+int bar();
+int test0() {
+ int i;
+ i = 1 + 2;
+ do {
+ i = bar();
+ i = bar();
+ } while(0);
+ return i;
+}
+
+
+int test1() {
+ int i;
+ i = 1 + 2;
+ do {
+ i = bar();
+ if (i == 42)
+ break;
+ i = bar();
+ } while(1);
+ return i;
+}
+
+
+int test2() {
+ int i;
+ i = 1 + 2;
+ do {
+ i = bar();
+ if (i == 42)
+ continue;
+ i = bar();
+ } while(1);
+ return i;
+}
+
+
+int test3() {
+ int i;
+ i = 1 + 2;
+ do {
+ i = bar();
+ if (i == 42)
+ break;
+ } while(0);
+ return i;
+}
+
+
+int test4() {
+ int i;
+ i = 1 + 2;
+ do {
+ i = bar();
+ if (i == 42)
+ continue;
+ } while(0);
+ return i;
+}
+
+// rdar://6103124
+void test5() {
+ do { break; } while(0);
+}
+
+
+
diff --git a/test/CodeGen/emit-all-decls.c b/test/CodeGen/emit-all-decls.c
new file mode 100644
index 000000000000..775cb6f118a8
--- /dev/null
+++ b/test/CodeGen/emit-all-decls.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -emit-llvm -o %t %s &&
+// RUN: not grep "@foo" %t &&
+// RUN: clang-cc -femit-all-decls -emit-llvm -o %t %s &&
+// RUN: grep "@foo" %t
+
+static void foo() {
+
+}
diff --git a/test/CodeGen/empty-union-init.c b/test/CodeGen/empty-union-init.c
new file mode 100644
index 000000000000..8448b3ded798
--- /dev/null
+++ b/test/CodeGen/empty-union-init.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -emit-llvm < %s -o -
+// PR2419
+
+struct Mem {
+ union {
+ } u;
+};
+
+struct Mem *columnMem(){
+ static const struct Mem nullMem = { {} };
+}
+
+
diff --git a/test/CodeGen/enum.c b/test/CodeGen/enum.c
new file mode 100644
index 000000000000..172d308c2b0b
--- /dev/null
+++ b/test/CodeGen/enum.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc -triple i386-unknown-unknown %s -emit-llvm-bc -o - | opt -std-compile-opts | llvm-dis | grep 'ret i32 6'
+
+static enum { foo, bar = 1U } z;
+
+int main (void)
+{
+ int r = 0;
+
+ if (bar - 2 < 0)
+ r += 4;
+ if (foo - 1 < 0)
+ r += 2;
+ if (z - 1 < 0)
+ r++;
+
+ return r;
+}
+
diff --git a/test/CodeGen/exprs.c b/test/CodeGen/exprs.c
new file mode 100644
index 000000000000..36cfff9e8a69
--- /dev/null
+++ b/test/CodeGen/exprs.c
@@ -0,0 +1,118 @@
+// RUN: clang-cc %s -emit-llvm -o -
+
+// PR1895
+// sizeof function
+int zxcv(void);
+int x=sizeof(zxcv);
+int y=__alignof__(zxcv);
+
+
+void *test(int *i) {
+ short a = 1;
+ i += a;
+ i + a;
+ a + i;
+}
+
+_Bool test2b;
+int test2() {if (test2b);}
+
+// PR1921
+int test3() {
+ const unsigned char *bp;
+ bp -= (short)1;
+}
+
+// PR2080 - sizeof void
+int t1 = sizeof(void);
+int t2 = __alignof__(void);
+void test4() {
+ t1 = sizeof(void);
+ t2 = __alignof__(void);
+
+ t1 = sizeof(test4());
+ t2 = __alignof__(test4());
+}
+
+// 'const float' promotes to double in varargs.
+int test5(const float x, float float_number) {
+ return __builtin_isless(x, float_number);
+}
+
+// this one shouldn't fold
+int ola() {
+ int a=2;
+ if ((0, (int)a) & 2) { return 1; }
+ return 2;
+}
+
+// this one shouldn't fold as well
+void eMaisUma() {
+ double t[1];
+ if (*t)
+ return;
+}
+
+// rdar://6520707
+void f0(void (*fp)(void), void (*fp2)(void)) {
+ int x = fp - fp2;
+}
+
+// noop casts as lvalues.
+struct X {
+ int Y;
+};
+struct X foo();
+int bar() {
+ return ((struct X)foo()).Y + 1;
+}
+
+// PR3809: INC/DEC of function pointers.
+void f2(void);
+unsigned f1(void) {
+ void (*fp)(void) = f2;
+
+ ++fp;
+ fp++;
+ --fp;
+ fp--;
+ return (unsigned) fp;
+}
+
+union f3_x {int x; float y;};
+int f3() {return ((union f3_x)2).x;}
+
+union f4_y {int x; _Complex float y;};
+_Complex float f4() {return ((union f4_y)(_Complex float)2.0).y;}
+
+struct f5_a { int a; } f5_a;
+union f5_z {int x; struct f5_a y;};
+struct f5_a f5() {return ((union f5_z)f5_a).y;}
+
+// ?: in "lvalue"
+struct s6 { int f0; };
+int f6(int a0, struct s6 a1, struct s6 a2) {
+ return (a0 ? a1 : a2).f0;
+}
+
+// PR4026
+void f7() {
+ __func__;
+}
+
+// PR4067
+int f8() {
+ return ({ foo(); }).Y;
+}
+
+// rdar://6880558
+struct S;
+struct C {
+ int i;
+ struct S *tab[];
+};
+struct S { struct C c; };
+void f9(struct S *x) {
+ foo(((void)1, x->c).tab[0]);
+}
+
diff --git a/test/CodeGen/ext-vector-shuffle.c b/test/CodeGen/ext-vector-shuffle.c
new file mode 100644
index 000000000000..37d3ed42d060
--- /dev/null
+++ b/test/CodeGen/ext-vector-shuffle.c
@@ -0,0 +1,15 @@
+// RUN: clang-cc %s -emit-llvm -o - | not grep 'extractelement'
+// RUN: clang-cc %s -emit-llvm -o - | not grep 'insertelement'
+// RUN: clang-cc %s -emit-llvm -o - | grep 'shufflevector'
+
+typedef __attribute__(( ext_vector_type(2) )) float float2;
+typedef __attribute__(( ext_vector_type(4) )) float float4;
+
+float2 test1(float4 V) {
+ return V.xy + V.wz;
+}
+
+float4 test2(float4 V) {
+ float2 W = V.ww;
+ return W.xyxy + W.yxyx;
+}
diff --git a/test/CodeGen/ext-vector.c b/test/CodeGen/ext-vector.c
new file mode 100644
index 000000000000..e3b6211ee991
--- /dev/null
+++ b/test/CodeGen/ext-vector.c
@@ -0,0 +1,129 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+typedef __attribute__(( ext_vector_type(4) )) float float4;
+typedef __attribute__(( ext_vector_type(2) )) float float2;
+typedef __attribute__(( ext_vector_type(4) )) int int4;
+
+float4 foo = (float4){ 1.0, 2.0, 3.0, 4.0 };
+
+const float4 bar = (float4){ 1.0, 2.0, 3.0, __builtin_inff() };
+
+float4 test1(float4 V) {
+ return V.wzyx+V;
+}
+
+float2 vec2, vec2_2;
+float4 vec4, vec4_2;
+float f;
+
+void test2() {
+ vec2 = vec4.xy; // shorten
+ f = vec2.x; // extract elt
+ vec4 = vec4.yyyy; // splat
+
+ vec2.x = f; // insert one.
+ vec2.yx = vec2; // reverse
+}
+
+void test3(float4 *out) {
+ *out = ((float4) {1.0f, 2.0f, 3.0f, 4.0f });
+}
+
+void test4(float4 *out) {
+ float a = 1.0f;
+ float b = 2.0f;
+ float c = 3.0f;
+ float d = 4.0f;
+ *out = ((float4) {a,b,c,d});
+}
+
+void test5(float4 *out) {
+ float a;
+ float4 b;
+
+ a = 1.0f;
+ b = a;
+ b = b * 5.0f;
+ b = 5.0f * b;
+ b *= a;
+
+ *out = b;
+}
+
+void test6(float4 *ap, float4 *bp, float c) {
+ float4 a = *ap;
+ float4 b = *bp;
+
+ a = a + b;
+ a = a - b;
+ a = a * b;
+ a = a / b;
+
+ a = a + c;
+ a = a - c;
+ a = a * c;
+ a = a / c;
+
+ a += b;
+ a -= b;
+ a *= b;
+ a /= b;
+
+ a += c;
+ a -= c;
+ a *= c;
+ a /= c;
+
+ // Vector comparisons can sometimes crash the x86 backend: rdar://6326239,
+ // reject them until the implementation is stable.
+#if 0
+ int4 cmp;
+ cmp = a < b;
+ cmp = a <= b;
+ cmp = a < b;
+ cmp = a >= b;
+ cmp = a == b;
+ cmp = a != b;
+#endif
+}
+
+void test7(int4 *ap, int4 *bp, int c) {
+ int4 a = *ap;
+ int4 b = *bp;
+
+ a = a + b;
+ a = a - b;
+ a = a * b;
+ a = a / b;
+ a = a % b;
+
+ a = a + c;
+ a = a - c;
+ a = a * c;
+ a = a / c;
+ a = a % c;
+
+ a += b;
+ a -= b;
+ a *= b;
+ a /= b;
+ a %= b;
+
+ a += c;
+ a -= c;
+ a *= c;
+ a /= c;
+ a %= c;
+
+ // Vector comparisons can sometimes crash the x86 backend: rdar://6326239,
+ // reject them until the implementation is stable.
+#if 0
+ int4 cmp;
+ cmp = a < b;
+ cmp = a <= b;
+ cmp = a < b;
+ cmp = a >= b;
+ cmp = a == b;
+ cmp = a != b;
+#endif
+}
diff --git a/test/CodeGen/extern-block-var.c b/test/CodeGen/extern-block-var.c
new file mode 100644
index 000000000000..e8de3e7f11fe
--- /dev/null
+++ b/test/CodeGen/extern-block-var.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+
+int f() {
+ extern int a;
+ return a;
+}
diff --git a/test/CodeGen/flexible-array-init.c b/test/CodeGen/flexible-array-init.c
new file mode 100644
index 000000000000..fb98a8ec07a6
--- /dev/null
+++ b/test/CodeGen/flexible-array-init.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -o - %s | grep 7 | count 1 &&
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -o - %s | grep 11 | count 1 &&
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -o - %s | grep 13 | count 1 &&
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -o - %s | grep 15 | count 1
+
+struct { int x; int y[]; } a = { 1, 7, 11 };
+
+struct { int x; int y[]; } b = { 1, { 13, 15 } };
diff --git a/test/CodeGen/func-decl-cleanup.c b/test/CodeGen/func-decl-cleanup.c
new file mode 100644
index 000000000000..4808e12fdfcc
--- /dev/null
+++ b/test/CodeGen/func-decl-cleanup.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc %s -emit-llvm -o -
+
+
+// PR2360
+typedef void fn_t();
+
+fn_t a,b;
+
+void b()
+{
+}
+
diff --git a/test/CodeGen/func-return-member.c b/test/CodeGen/func-return-member.c
new file mode 100644
index 000000000000..e6fc5623904b
--- /dev/null
+++ b/test/CodeGen/func-return-member.c
@@ -0,0 +1,23 @@
+// RUN: clang-cc -emit-llvm < %s 2>&1 | not grep 'cannot codegen this l-value expression yet'
+
+struct frk { float _Complex c; int x; };
+struct faz { struct frk f; };
+struct fuz { struct faz f; };
+
+extern struct fuz foo(void);
+
+int X;
+struct frk F;
+float _Complex C;
+
+void bar(void) {
+ X = foo().f.f.x;
+}
+
+void bun(void) {
+ F = foo().f.f;
+}
+
+void ban(void) {
+ C = foo().f.f.c;
+}
diff --git a/test/CodeGen/function-attributes.c b/test/CodeGen/function-attributes.c
new file mode 100644
index 000000000000..ba2e4e4d564d
--- /dev/null
+++ b/test/CodeGen/function-attributes.c
@@ -0,0 +1,69 @@
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: grep 'define signext i8 @f0(i32 %x) nounwind' %t &&
+// RUN: grep 'define zeroext i8 @f1(i32 %x) nounwind' %t &&
+// RUN: grep 'define void @f2(i8 signext %x) nounwind' %t &&
+// RUN: grep 'define void @f3(i8 zeroext %x) nounwind' %t &&
+// RUN: grep 'define signext i16 @f4(i32 %x) nounwind' %t &&
+// RUN: grep 'define zeroext i16 @f5(i32 %x) nounwind' %t &&
+// RUN: grep 'define void @f6(i16 signext %x) nounwind' %t &&
+// RUN: grep 'define void @f7(i16 zeroext %x) nounwind' %t &&
+
+signed char f0(int x) { return x; }
+
+unsigned char f1(int x) { return x; }
+
+void f2(signed char x) { }
+
+void f3(unsigned char x) { }
+
+signed short f4(int x) { return x; }
+
+unsigned short f5(int x) { return x; }
+
+void f6(signed short x) { }
+
+void f7(unsigned short x) { }
+
+// RUN: grep 'define void @f8() nounwind alwaysinline' %t &&
+void __attribute__((always_inline)) f8(void) { }
+
+// RUN: grep 'call void @f9_t() noreturn' %t &&
+void __attribute__((noreturn)) f9_t(void);
+void f9(void) { f9_t(); }
+
+// FIXME: We should be setting nounwind on calls.
+// RUN: grep 'call i32 @f10_t() readnone' %t &&
+int __attribute__((const)) f10_t(void);
+int f10(void) { return f10_t(); }
+int f11(void) {
+ exit:
+ return f10_t();
+}
+int f12(int arg) {
+ return arg ? 0 : f10_t();
+}
+
+// RUN: grep 'define void @f13() nounwind readnone' %t &&
+void f13(void) __attribute__((pure)) __attribute__((const));
+void f13(void){}
+
+
+// Ensure that these get inlined: rdar://6853279
+// RUN: not grep '@ai_' %t &&
+static __inline__ __attribute__((always_inline))
+int ai_1() { return 4; }
+
+static __inline__ __attribute__((always_inline))
+struct {
+ int a, b, c, d, e;
+} ai_2() { }
+
+
+int foo() {
+ ai_2();
+ return ai_1();
+}
+
+
+
+// RUN: true
diff --git a/test/CodeGen/function-decay.m b/test/CodeGen/function-decay.m
new file mode 100644
index 000000000000..5652fdbb21ea
--- /dev/null
+++ b/test/CodeGen/function-decay.m
@@ -0,0 +1,10 @@
+// RUN: clang-cc %s -emit-llvm -o -
+
+@interface I0 @end
+@implementation I0
+- (void) im0: (int (void)) a0 {
+}
+@end
+
+void func(int pf(void)) {
+}
diff --git a/test/CodeGen/functions.c b/test/CodeGen/functions.c
new file mode 100644
index 000000000000..985599216e1c
--- /dev/null
+++ b/test/CodeGen/functions.c
@@ -0,0 +1,35 @@
+// RUN: clang-cc %s -emit-llvm -o %t &&
+
+int g();
+
+int foo(int i) {
+ return g(i);
+}
+
+int g(int i) {
+ return g(i);
+}
+
+// rdar://6110827
+typedef void T(void);
+void test3(T f) {
+ f();
+}
+
+int a(int);
+int a() {return 1;}
+
+// RUN: grep 'define void @f0()' %t &&
+void f0() {}
+
+void f1();
+// RUN: grep 'call void @f1()' %t &&
+void f2(void) {
+ f1(1, 2, 3);
+}
+// RUN: grep 'define void @f1()' %t &&
+void f1() {}
+
+// RUN: grep 'define .* @f3' %t | not grep -F '...'
+struct foo { int X, Y, Z; } f3() {
+}
diff --git a/test/CodeGen/global-decls.c b/test/CodeGen/global-decls.c
new file mode 100644
index 000000000000..80222ea85ef1
--- /dev/null
+++ b/test/CodeGen/global-decls.c
@@ -0,0 +1,22 @@
+// RUN: clang-cc -triple i386-pc-linux-gnu -emit-llvm -o %t %s &&
+
+// RUN: grep '@g0_ext = extern_weak global i32' %t &&
+extern int g0_ext __attribute__((weak));
+// RUN: grep 'declare extern_weak i32 @g1_ext()' %t &&
+extern int __attribute__((weak)) g1_ext (void);
+
+// RUN: grep '@g0_common = weak global i32' %t &&
+int g0_common __attribute__((weak));
+
+// RUN: grep '@g0_def = weak global i32' %t &&
+int g0_def __attribute__((weak)) = 52;
+// RUN: grep 'define weak i32 @g1_def()' %t &&
+int __attribute__((weak)) g1_def (void) {}
+
+// Force _ext references
+void f0() {
+ int a = g0_ext;
+ int b = g1_ext();
+}
+
+// RUN: true
diff --git a/test/CodeGen/global-init.c b/test/CodeGen/global-init.c
new file mode 100644
index 000000000000..4b769f8ccbb0
--- /dev/null
+++ b/test/CodeGen/global-init.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -emit-llvm -o - %s | not grep "common"
+
+// This checks that the global won't be marked as common.
+// (It shouldn't because it's being initialized).
+
+int a;
+int a = 242;
diff --git a/test/CodeGen/global-with-initialiser.c b/test/CodeGen/global-with-initialiser.c
new file mode 100644
index 000000000000..29b4e21b9129
--- /dev/null
+++ b/test/CodeGen/global-with-initialiser.c
@@ -0,0 +1,25 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+const int globalInt = 1;
+int globalIntWithFloat = 1.5f;
+int globalIntArray[5] = { 1, 2 };
+int globalIntFromSizeOf = sizeof(globalIntArray);
+char globalChar = 'a';
+char globalCharArray[5] = { 'a', 'b' };
+float globalFloat = 1.0f;
+float globalFloatWithInt = 1;
+float globalFloatArray[5] = { 1.0f, 2.0f };
+double globalDouble = 1.0;
+double globalDoubleArray[5] = { 1.0, 2.0 };
+char *globalString = "abc";
+char *globalStringArray[5] = { "123", "abc" };
+long double globalLongDouble = 1;
+long double globalLongDoubleArray[5] = { 1.0, 2.0 };
+
+struct Struct {
+ int member1;
+ float member2;
+ char *member3;
+};
+
+struct Struct globalStruct = { 1, 2.0f, "foobar"};
diff --git a/test/CodeGen/globalinit.c b/test/CodeGen/globalinit.c
new file mode 100644
index 000000000000..2798cae712a2
--- /dev/null
+++ b/test/CodeGen/globalinit.c
@@ -0,0 +1,51 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+int A[10] = { 1,2,3,4,5 };
+
+
+extern int x[];
+void foo() { x[0] = 1; }
+int x[10];
+void bar() { x[0] = 1; }
+
+
+extern int y[];
+void *g = y;
+
+int latin_ptr2len (char *p);
+int (*mb_ptr2len) (char *p) = latin_ptr2len;
+
+
+char string[8] = "string"; // extend init
+char string2[4] = "string"; // truncate init
+
+char *test(int c) {
+ static char buf[10];
+ static char *bufptr = buf;
+
+ return c ? buf : bufptr;
+}
+
+
+_Bool booltest = 0;
+void booltest2() {
+ static _Bool booltest3 = 4;
+}
+
+// Scalars in braces.
+static int a = { 1 };
+
+// References to enums.
+enum {
+ EnumA, EnumB
+};
+
+int c[] = { EnumA, EnumB };
+
+// Binary operators
+int d[] = { EnumA | EnumB };
+
+// PR1968
+static int array[];
+static int array[4];
+
diff --git a/test/CodeGen/illegal-UTF8.m b/test/CodeGen/illegal-UTF8.m
new file mode 100644
index 000000000000..a9d5a37ac757
--- /dev/null
+++ b/test/CodeGen/illegal-UTF8.m
@@ -0,0 +1,8 @@
+// RUN: clang %s -S -m64 -o -
+
+@class NSString;
+
+// FIXME: GCC emits the following warning:
+// CodeGen/illegal-UTF8.m:4: warning: input conversion stopped due to an input byte that does not belong to the input codeset UTF-8
+
+NSString *S = @"\xff\xff___WAIT___";
diff --git a/test/CodeGen/incomplete-function-type.c b/test/CodeGen/incomplete-function-type.c
new file mode 100644
index 000000000000..a641268cf50f
--- /dev/null
+++ b/test/CodeGen/incomplete-function-type.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -emit-llvm %s -o - | not grep opaque
+
+enum teste1 test1f(void), (*test1)(void) = test1f;
+struct tests2 test2f(), (*test2)() = test2f;
+struct tests3;
+void test3f(struct tests3), (*test3)(struct tests3) = test3f;
+enum teste1 { TEST1 };
+struct tests2 { int x,y,z,a,b,c,d,e,f,g; };
+struct tests3 { float x; };
+
diff --git a/test/CodeGen/indirect-goto.c b/test/CodeGen/indirect-goto.c
new file mode 100644
index 000000000000..b9a601953877
--- /dev/null
+++ b/test/CodeGen/indirect-goto.c
@@ -0,0 +1,20 @@
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t &&
+// RUN: grep "ret i32" %t | count 1 &&
+// RUN: grep "ret i32 210" %t | count 1
+
+static int foo(unsigned i) {
+ const void *addrs[] = { &&L1, &&L2, &&L3, &&L4, &&L5 };
+ int res = 1;
+
+ goto *addrs[i];
+ L5: res *= 11;
+ L4: res *= 7;
+ L3: res *= 5;
+ L2: res *= 3;
+ L1: res *= 2;
+ return res;
+}
+
+int bar() {
+ return foo(3);
+}
diff --git a/test/CodeGen/init-with-member-expr.c b/test/CodeGen/init-with-member-expr.c
new file mode 100644
index 000000000000..7750dbf9869d
--- /dev/null
+++ b/test/CodeGen/init-with-member-expr.c
@@ -0,0 +1,21 @@
+// RUN: clang-cc < %s -emit-llvm
+struct test {
+ int a;
+};
+
+extern struct test t;
+
+int *b=&t.a;
+
+
+// PR2049
+typedef struct mark_header_tag {
+ unsigned char mark[7];
+} mark_header_t;
+int is_rar_archive(int fd) {
+ const mark_header_t rar_hdr[2] = {{0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00}, {'U', 'n', 'i', 'q', 'u', 'E', '!'}};
+ foo(rar_hdr);
+
+ return 0;
+}
+
diff --git a/test/CodeGen/init.c b/test/CodeGen/init.c
new file mode 100644
index 000000000000..2e239cf5438c
--- /dev/null
+++ b/test/CodeGen/init.c
@@ -0,0 +1,31 @@
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm %s -o %t &&
+
+void f1() {
+ // Scalars in braces.
+ int a = { 1 };
+}
+
+void f2() {
+ int a[2][2] = { { 1, 2 }, { 3, 4 } };
+ int b[3][3] = { { 1, 2 }, { 3, 4 } };
+ int *c[2] = { &a[1][1], &b[2][2] };
+ int *d[2][2] = { {&a[1][1], &b[2][2]}, {&a[0][0], &b[1][1]} };
+ int *e[3][3] = { {&a[1][1], &b[2][2]}, {&a[0][0], &b[1][1]} };
+ char ext[3][3] = {".Y",".U",".V"};
+}
+
+typedef void (* F)(void);
+extern void foo(void);
+struct S { F f; };
+void f3() {
+ struct S a[1] = { { foo } };
+}
+
+// Constants
+// RUN: grep '@g3 = constant i32 10' %t &&
+// RUN: grep '@f4.g4 = internal constant i32 12' %t
+const int g3 = 10;
+int f4() {
+ static const int g4 = 12;
+ return g4;
+}
diff --git a/test/CodeGen/inline.c b/test/CodeGen/inline.c
new file mode 100644
index 000000000000..234f1f8d93a8
--- /dev/null
+++ b/test/CodeGen/inline.c
@@ -0,0 +1,86 @@
+// RUN: echo "C89 tests:" &&
+// RUN: clang %s -emit-llvm -S -o %t -std=c89 &&
+// RUN: grep "define available_externally i32 @ei()" %t &&
+// RUN: grep "define i32 @foo()" %t &&
+// RUN: grep "define i32 @bar()" %t &&
+// RUN: grep "define void @unreferenced1()" %t &&
+// RUN: not grep unreferenced2 %t &&
+// RUN: grep "define void @gnu_inline()" %t &&
+// RUN: grep "define available_externally void @gnu_ei_inline()" %t &&
+// RUN: grep "define i32 @test1" %t &&
+// RUN: grep "define i32 @test2" %t &&
+// RUN: grep "define void @test3()" %t &&
+// RUN: grep "define available_externally i32 @test4" %t &&
+// RUN: grep "define available_externally i32 @test5" %t &&
+
+// RUN: echo "\nC99 tests:" &&
+// RUN: clang %s -emit-llvm -S -o %t -std=c99 &&
+// RUN: grep "define i32 @ei()" %t &&
+// RUN: grep "define available_externally i32 @foo()" %t &&
+// RUN: grep "define i32 @bar()" %t &&
+// RUN: not grep unreferenced1 %t &&
+// RUN: grep "define void @unreferenced2()" %t &&
+// RUN: grep "define void @gnu_inline()" %t &&
+// RUN: grep "define available_externally void @gnu_ei_inline()" %t &&
+// RUN: grep "define i32 @test1" %t &&
+// RUN: grep "define i32 @test2" %t &&
+// RUN: grep "define available_externally void @test3" %t &&
+// RUN: grep "define available_externally i32 @test4" %t &&
+// RUN: grep "define i32 @test5" %t &&
+
+// RUN: echo "\nC++ tests:" &&
+// RUN: clang %s -emit-llvm -S -o %t -std=c++98 &&
+// RUN: grep "define linkonce_odr i32 @_Z2eiv()" %t &&
+// RUN: grep "define linkonce_odr i32 @_Z3foov()" %t &&
+// RUN: grep "define i32 @_Z3barv()" %t &&
+// RUN: not grep unreferenced %t &&
+// RUN: grep "define void @_Z10gnu_inlinev()" %t &&
+// RUN: grep "define available_externally void @_Z13gnu_ei_inlinev()" %t
+
+extern __inline int ei() { return 123; }
+
+__inline int foo() {
+ return ei();
+}
+
+int bar() { return foo(); }
+
+
+__inline void unreferenced1() {}
+extern __inline void unreferenced2() {}
+
+__inline __attribute((__gnu_inline__)) void gnu_inline() {}
+
+// PR3988
+extern __inline __attribute__((gnu_inline)) void gnu_ei_inline() {}
+void (*P)() = gnu_ei_inline;
+
+// <rdar://problem/6818429>
+int test1();
+__inline int test1() { return 4; }
+__inline int test2() { return 5; }
+__inline int test2();
+int test2();
+
+void test_test1() { test1(); }
+void test_test2() { test2(); }
+
+// PR3989
+extern __inline void test3() __attribute__((gnu_inline));
+__inline void test3() {}
+
+void test_test3() { test3(); }
+
+extern int test4(void);
+extern __inline __attribute__ ((__gnu_inline__)) int test4(void)
+{
+}
+
+void test_test4() { test4(); }
+
+extern __inline int test5(void);
+extern __inline int __attribute__ ((__gnu_inline__)) test5(void)
+{
+}
+
+void test_test5() { test5(); }
diff --git a/test/CodeGen/int-to-pointer.c b/test/CodeGen/int-to-pointer.c
new file mode 100644
index 000000000000..7cefc3902ebc
--- /dev/null
+++ b/test/CodeGen/int-to-pointer.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+void *test(int i)
+{
+ return (void *)i;
+}
diff --git a/test/CodeGen/kr-func-promote.c b/test/CodeGen/kr-func-promote.c
new file mode 100644
index 000000000000..d4c3851909ab
--- /dev/null
+++ b/test/CodeGen/kr-func-promote.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -triple i386-unknown-unknown %s -emit-llvm -o - | grep "i32 @a(i32)"
+
+int a();
+int a(x) short x; {return x;}
+
diff --git a/test/CodeGen/kr-style-block.c b/test/CodeGen/kr-style-block.c
new file mode 100644
index 000000000000..ac788dc9ab9f
--- /dev/null
+++ b/test/CodeGen/kr-style-block.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -emit-llvm %s -o %t -fblocks
+
+void foo (void(^)());
+
+int main()
+{
+foo(
+ ^() { }
+);
+}
diff --git a/test/CodeGen/libcalls.c b/test/CodeGen/libcalls.c
new file mode 100644
index 000000000000..695321622fed
--- /dev/null
+++ b/test/CodeGen/libcalls.c
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fmath-errno=1 -emit-llvm -o %t %s &&
+// RUN: grep "declare " %t | count 6 &&
+// RUN: grep "declare " %t | grep "@llvm." | count 1 &&
+// RUN: clang-cc -fmath-errno=0 -emit-llvm -o %t %s &&
+// RUN: grep "declare " %t | count 6 &&
+// RUN: grep "declare " %t | grep -v "@llvm." | count 0
+
+// IRgen only pays attention to const; it should always call llvm for
+// this.
+float sqrtf(float) __attribute__((const));
+
+void test_sqrt(float a0, double a1, long double a2) {
+ float l0 = sqrtf(a0);
+ double l1 = sqrt(a1);
+ long double l2 = sqrtl(a2);
+}
+
+void test_pow(float a0, double a1, long double a2) {
+ float l0 = powf(a0, a0);
+ double l1 = pow(a1, a1);
+ long double l2 = powl(a2, a2);
+}
diff --git a/test/CodeGen/lineno-dbginfo.c b/test/CodeGen/lineno-dbginfo.c
new file mode 100644
index 000000000000..fe9e59ac2d70
--- /dev/null
+++ b/test/CodeGen/lineno-dbginfo.c
@@ -0,0 +1,5 @@
+// RUN: echo "#include <stdio.h>" > %t.h
+// RUN: clang -S -save-temps -g -include %t.h %s -emit-llvm -o %t.ll
+// RUN: grep "i32 5" %t.ll
+// outer is at line number 5.
+int outer = 42;
diff --git a/test/CodeGen/linkage-redecl.c b/test/CodeGen/linkage-redecl.c
new file mode 100644
index 000000000000..b015ca854737
--- /dev/null
+++ b/test/CodeGen/linkage-redecl.c
@@ -0,0 +1,11 @@
+// RUN: clang-cc -emit-llvm %s -o - |grep internal
+
+// C99 6.2.2p3
+// PR3425
+static void f(int x);
+
+void g0() {
+ f(5);
+}
+
+extern void f(int x) { } // still has internal linkage
diff --git a/test/CodeGen/long-double-x86.c b/test/CodeGen/long-double-x86.c
new file mode 100644
index 000000000000..b01ce0b93ec3
--- /dev/null
+++ b/test/CodeGen/long-double-x86.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc %s -emit-llvm -o - -triple=i686-apple-darwin9 | grep x86_fp80
+
+long double x = 0;
+int checksize[sizeof(x) == 16 ? 1 : -1];
diff --git a/test/CodeGen/mandel.c b/test/CodeGen/mandel.c
new file mode 100644
index 000000000000..6f46ee407f5c
--- /dev/null
+++ b/test/CodeGen/mandel.c
@@ -0,0 +1,67 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+/* Sparc is not C99-compliant */
+#if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
+
+int main() { return 0; }
+
+#else /* sparc */
+
+#define ESCAPE 2
+#define IMAGE_WIDTH 150
+#define IMAGE_HEIGHT 50
+#if 1
+#define IMAGE_SIZE 60
+#else
+#define IMAGE_SIZE 5000
+#endif
+#define START_X -2.1
+#define END_X 1.0
+#define START_Y -1.25
+#define MAX_ITER 100
+
+#define step_X ((END_X - START_X)/IMAGE_WIDTH)
+#define step_Y ((-START_Y - START_Y)/IMAGE_HEIGHT)
+
+#define I 1.0iF
+
+#include <math.h>
+
+#include <stdio.h>
+
+volatile double __complex__ accum;
+
+void mandel() {
+ int x, y, n;
+ for (y = 0; y < IMAGE_HEIGHT; ++y) {
+ for (x = 0; x < IMAGE_WIDTH; ++x) {
+ double __complex__ c = (START_X+x*step_X) + (START_Y+y*step_Y) * I;
+ double __complex__ z = 0.0;
+
+ for (n = 0; n < MAX_ITER; ++n) {
+ z = z * z + c;
+ if (hypot(__real__ z, __imag__ z) >= ESCAPE)
+ break;
+ }
+
+ if (n == MAX_ITER)
+ putchar(' ');
+ else if (n > 6)
+ putchar('.');
+ else if (n > 3)
+ putchar('+');
+ else if (n > 2)
+ putchar('x');
+ else
+ putchar('*');
+ }
+ putchar('\n');
+ }
+}
+
+int main() {
+ mandel();
+ return 0;
+}
+
+#endif /* sparc */
diff --git a/test/CodeGen/mangle.c b/test/CodeGen/mangle.c
new file mode 100644
index 000000000000..17d74ba71f0c
--- /dev/null
+++ b/test/CodeGen/mangle.c
@@ -0,0 +1,54 @@
+// RUN: clang-cc -triple i386-pc-linux-gnu -emit-llvm -o %t %s &&
+// RUN: grep '@_Z2f0i' %t &&
+// RUN: grep '@_Z2f0l' %t &&
+
+// Make sure we mangle overloadable, even in C system headers.
+
+# 1 "somesystemheader.h" 1 3 4
+void __attribute__((__overloadable__)) f0(int a) {}
+void __attribute__((__overloadable__)) f0(long b) {}
+
+
+
+// These should get merged.
+void foo() __asm__("bar");
+void foo2() __asm__("bar");
+
+// RUN: grep '@"\\01foo"' %t &&
+// RUN: grep '@"\\01bar"' %t
+
+int nux __asm__("foo");
+extern float nux2 __asm__("foo");
+
+int test() {
+ foo();
+ foo2();
+
+ return nux + nux2;
+}
+
+
+// Function becomes a variable.
+void foo3() __asm__("var");
+
+void test2() {
+ foo3();
+}
+int foo4 __asm__("var") = 4;
+
+
+// Variable becomes a function
+extern int foo5 __asm__("var2");
+
+void test3() {
+ foo5 = 1;
+}
+
+void foo6() __asm__("var2");
+void foo6() {
+}
+
+
+
+int foo7 __asm__("foo7") __attribute__((used));
+float foo8 __asm__("foo7") = 42;
diff --git a/test/CodeGen/merge-attrs.c b/test/CodeGen/merge-attrs.c
new file mode 100644
index 000000000000..1aab47a3a30c
--- /dev/null
+++ b/test/CodeGen/merge-attrs.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+
+void *malloc(__SIZE_TYPE__ size) __attribute__ ((__nothrow__));
+
+inline static void __zend_malloc() {
+ malloc(1);
+}
+
+void *malloc(__SIZE_TYPE__ size) __attribute__ ((__nothrow__));
+
+void fontFetch() {
+ __zend_malloc(1);
+}
diff --git a/test/CodeGen/merge-statics.c b/test/CodeGen/merge-statics.c
new file mode 100644
index 000000000000..c442669e6422
--- /dev/null
+++ b/test/CodeGen/merge-statics.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc < %s -emit-llvm | grep internal | count 1
+
+// The two decls for 'a' should merge into one llvm GlobalVariable.
+
+struct s { int x; };
+static struct s a;
+
+struct s *ap1 = &a;
+
+static struct s a = {
+ 10
+};
+
diff --git a/test/CodeGen/mmintrin-test.c b/test/CodeGen/mmintrin-test.c
new file mode 100644
index 000000000000..2a9ab5672330
--- /dev/null
+++ b/test/CodeGen/mmintrin-test.c
@@ -0,0 +1,26 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -mcpu=pentium4 -emit-llvm -o %t %s &&
+// RUN: grep define %t | count 1 &&
+// RUN: clang-cc -triple i386-apple-darwin9 -mcpu=pentium4 -g -emit-llvm -o %t %s &&
+// RUN: grep define %t | count 1
+
+#include <mmintrin.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+ int array[16] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
+ __m64 *p = (__m64 *)array;
+
+ __m64 accum = _mm_setzero_si64();
+
+ for (int i=0; i<8; ++i)
+ accum = _mm_add_pi32(p[i], accum);
+
+ __m64 accum2 = _mm_unpackhi_pi32(accum, accum);
+ accum = _mm_add_pi32(accum, accum2);
+
+ int result = _mm_cvtsi64_si32(accum);
+ _mm_empty();
+ printf("%d\n", result );
+
+ return 0;
+}
diff --git a/test/CodeGen/no-common.c b/test/CodeGen/no-common.c
new file mode 100644
index 000000000000..190873c745fe
--- /dev/null
+++ b/test/CodeGen/no-common.c
@@ -0,0 +1,6 @@
+// RUN: clang -emit-llvm -S -o %t %s &&
+// RUN: grep '@x = common global' %t &&
+// RUN: clang -fno-common -emit-llvm -S -o %t %s &&
+// RUN: grep '@x = global' %t
+
+int x;
diff --git a/test/CodeGen/offsetof.c b/test/CodeGen/offsetof.c
new file mode 100644
index 000000000000..b0f5727a92dc
--- /dev/null
+++ b/test/CodeGen/offsetof.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+
+// PR2910
+struct sockaddr_un {
+ unsigned char sun_len;
+ char sun_path[104];
+};
+
+int test(int len) {
+ return __builtin_offsetof(struct sockaddr_un, sun_path[len+1]);
+}
+
diff --git a/test/CodeGen/opaque-pointer.c b/test/CodeGen/opaque-pointer.c
new file mode 100644
index 000000000000..7f78b91fb17e
--- /dev/null
+++ b/test/CodeGen/opaque-pointer.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc %s -emit-llvm -o -
+struct test;
+
+typedef void (*my_func) (struct test *);
+my_func handler;
+
+struct test {
+ char a;
+};
+
+char f(struct test *t) {
+ return t->a;
+}
diff --git a/test/CodeGen/overloadable.c b/test/CodeGen/overloadable.c
new file mode 100644
index 000000000000..4b58c8254624
--- /dev/null
+++ b/test/CodeGen/overloadable.c
@@ -0,0 +1,26 @@
+// RUN: clang-cc -emit-llvm %s -o - | grep _Z1fPA10_1X
+int __attribute__((overloadable)) f(int x) { return x; }
+float __attribute__((overloadable)) f(float x) { return x; }
+double __attribute__((overloadable)) f(double x) { return x; }
+double _Complex __attribute__((overloadable)) f(double _Complex x) { return x; }
+typedef short v4hi __attribute__ ((__vector_size__ (8)));
+v4hi __attribute__((overloadable)) f(v4hi x) { return x; }
+
+struct X { };
+void __attribute__((overloadable)) f(struct X (*ptr)[10]) { }
+
+void __attribute__((overloadable)) f(int x, int y, ...) { }
+
+int main() {
+ int iv = 17;
+ float fv = 3.0f;
+ double dv = 4.0;
+ double _Complex cdv;
+ v4hi vv;
+
+ iv = f(iv);
+ fv = f(fv);
+ dv = f(dv);
+ cdv = f(cdv);
+ vv = f(vv);
+}
diff --git a/test/CodeGen/parameter-passing.c b/test/CodeGen/parameter-passing.c
new file mode 100644
index 000000000000..2ace299ef770
--- /dev/null
+++ b/test/CodeGen/parameter-passing.c
@@ -0,0 +1,57 @@
+// Check the various ways in which the three classes of values
+// (scalar, complex, aggregate) interact with parameter passing
+// (function entry, function return, call argument, call result).
+//
+// We also check _Bool and empty structures, as these can have annoying
+// corner cases.
+
+// RUN: clang-cc %s -triple i386-unknown-unknown -O3 -emit-llvm -o %t &&
+// RUN: not grep '@g0' %t &&
+
+// RUN: clang-cc %s -triple x86_64-unknown-unknown -O3 -emit-llvm -o %t &&
+// RUN: not grep '@g0' %t &&
+
+// RUN: clang-cc %s -triple ppc-unknown-unknown -O3 -emit-llvm -o %t &&
+// RUN: not grep '@g0' %t &&
+// RUN: true
+
+typedef _Bool BoolTy;
+typedef int ScalarTy;
+typedef _Complex int ComplexTy;
+typedef struct { int a, b, c; } AggrTy;
+typedef struct { int a[0]; } EmptyTy;
+
+static int result;
+
+static BoolTy bool_id(BoolTy a) { return a; }
+static AggrTy aggr_id(AggrTy a) { return a; }
+static EmptyTy empty_id(EmptyTy a) { return a; }
+static ScalarTy scalar_id(ScalarTy a) { return a; }
+static ComplexTy complex_id(ComplexTy a) { return a; }
+
+static void bool_mul(BoolTy a) { result *= a; }
+
+static void aggr_mul(AggrTy a) { result *= a.a * a.b * a.c; }
+
+static void empty_mul(EmptyTy a) { result *= 53; }
+
+static void scalar_mul(ScalarTy a) { result *= a; }
+
+static void complex_mul(ComplexTy a) { result *= __real a * __imag a; }
+
+extern void g0(void);
+
+void f0(void) {
+ result = 1;
+
+ bool_mul(bool_id(1));
+ aggr_mul(aggr_id((AggrTy) { 2, 3, 5}));
+ empty_mul(empty_id((EmptyTy) {}));
+ scalar_mul(scalar_id(7));
+ complex_mul(complex_id(11 + 13i));
+
+ // This call should be eliminated.
+ if (result != 2 * 3 * 5 * 7 * 11 * 13 * 53)
+ g0();
+}
+
diff --git a/test/CodeGen/pascal-string.c b/test/CodeGen/pascal-string.c
new file mode 100644
index 000000000000..fcd807cde7b1
--- /dev/null
+++ b/test/CodeGen/pascal-string.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -emit-llvm -o - %s -fpascal-strings | grep "05Hello"
+
+unsigned char * Foo( void )
+{
+ static unsigned char s[256] = "\pHello";
+ return s;
+}
+
diff --git a/test/CodeGen/pointer-arithmetic.c b/test/CodeGen/pointer-arithmetic.c
new file mode 100644
index 000000000000..5049875dd3ed
--- /dev/null
+++ b/test/CodeGen/pointer-arithmetic.c
@@ -0,0 +1,22 @@
+// RUN: clang-cc -S %s -o -
+
+typedef int Int;
+
+int f0(int *a, Int *b) { return a - b; }
+
+int f1(const char *a, char *b) { return b - a; }
+
+// GNU extensions
+typedef void (*FP)(void);
+void *f2(void *a, int b) { return a + b; }
+void *f2_1(void *a, int b) { return (a += b); }
+void *f3(int a, void *b) { return a + b; }
+void *f3_1(int a, void *b) { return (a += b); }
+void *f4(void *a, int b) { return a - b; }
+void *f4_1(void *a, int b) { return (a -= b); }
+FP f5(FP a, int b) { return a + b; }
+FP f5_1(FP a, int b) { return (a += b); }
+FP f6(int a, FP b) { return a + b; }
+FP f6_1(int a, FP b) { return (a += b); }
+FP f7(FP a, int b) { return a - b; }
+FP f7_1(FP a, int b) { return (a -= b); }
diff --git a/test/CodeGen/pointer-cmp-type.c b/test/CodeGen/pointer-cmp-type.c
new file mode 100644
index 000000000000..d88c0911ba48
--- /dev/null
+++ b/test/CodeGen/pointer-cmp-type.c
@@ -0,0 +1,3 @@
+// RUN: clang-cc -emit-llvm %s -o - | grep "icmp ult"
+
+int a(char* a, char* b) {return a<b;}
diff --git a/test/CodeGen/pointer-to-int.c b/test/CodeGen/pointer-to-int.c
new file mode 100644
index 000000000000..e40bd91d8f99
--- /dev/null
+++ b/test/CodeGen/pointer-to-int.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -emit-llvm %s -o -
+
+int test(void* i)
+{
+ return (int)i;
+}
+
+// rdar://6093986
+int test2(void) {
+ float x[2];
+ return x;
+}
+
diff --git a/test/CodeGen/private-extern.c b/test/CodeGen/private-extern.c
new file mode 100644
index 000000000000..f3ffe5461d06
--- /dev/null
+++ b/test/CodeGen/private-extern.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -emit-llvm -o %t %s &&
+// RUN: grep '@g0 = external hidden constant i32' %t &&
+// RUN: grep '@g1 = hidden constant i32 1' %t
+
+__private_extern__ const int g0;
+__private_extern__ const int g1 = 1;
+
+int f0(void) {
+ return g0;
+}
diff --git a/test/CodeGen/rdr-6098585-default-after-caserange.c b/test/CodeGen/rdr-6098585-default-after-caserange.c
new file mode 100644
index 000000000000..3a11ad64299c
--- /dev/null
+++ b/test/CodeGen/rdr-6098585-default-after-caserange.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc -triple i386-unknown-unknown --emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t &&
+// RUN: grep "ret i32" %t | count 1 &&
+// RUN: grep "ret i32 10" %t | count 1
+
+// Ensure that default after a case range is not ignored.
+
+static int f1(unsigned x) {
+ switch(x) {
+ case 10 ... 0xFFFFFFFF:
+ return 0;
+ default:
+ return 10;
+ }
+}
+
+int g() {
+ return f1(2);
+}
diff --git a/test/CodeGen/rdr-6098585-default-fallthrough-to-caserange.c b/test/CodeGen/rdr-6098585-default-fallthrough-to-caserange.c
new file mode 100644
index 000000000000..f1d15dcd4fd5
--- /dev/null
+++ b/test/CodeGen/rdr-6098585-default-fallthrough-to-caserange.c
@@ -0,0 +1,20 @@
+// RUN: clang-cc -triple i386-unknown-unknown --emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t &&
+// RUN: grep "ret i32 10" %t
+
+// Ensure that this doesn't compile to infinite loop in g() due to
+// miscompilation of fallthrough from default to a (tested) case
+// range.
+
+static int f0(unsigned x) {
+ switch(x) {
+ default:
+ x += 1;
+ case 10 ... 0xFFFFFFFF:
+ return 0;
+ }
+}
+
+int g() {
+ f0(1);
+ return 10;
+}
diff --git a/test/CodeGen/rdr-6098585-empty-case-range.c b/test/CodeGen/rdr-6098585-empty-case-range.c
new file mode 100644
index 000000000000..ca5ff1b71225
--- /dev/null
+++ b/test/CodeGen/rdr-6098585-empty-case-range.c
@@ -0,0 +1,23 @@
+// RUN: clang-cc -triple i386-unknown-unknown --emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t &&
+// RUN: grep "ret i32" %t | count 2 &&
+// RUN: grep "ret i32 3" %t | count 2
+
+// This generated incorrect code because of poor switch chaining.
+int f1(int x) {
+ switch(x) {
+ default:
+ return 3;
+ case 10 ... 0xFFFFFFFF:
+ return 0;
+ }
+}
+
+// This just asserted because of the way case ranges were calculated.
+int f2(int x) {
+ switch (x) {
+ default:
+ return 3;
+ case 10 ... -1:
+ return 0;
+ }
+}
diff --git a/test/CodeGen/rdr-6098585-fallthrough-to-empty-range.c b/test/CodeGen/rdr-6098585-fallthrough-to-empty-range.c
new file mode 100644
index 000000000000..b34744970610
--- /dev/null
+++ b/test/CodeGen/rdr-6098585-fallthrough-to-empty-range.c
@@ -0,0 +1,15 @@
+// RUN: clang-cc -triple i386-unknown-unknown --emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t &&
+// RUN: grep "ret i32 %" %t
+
+// Make sure return is not constant (if empty range is skipped or miscompiled)
+
+int f0(unsigned x) {
+ switch(x) {
+ case 2:
+ // fallthrough empty range
+ case 10 ... 9:
+ return 10;
+ default:
+ return 0;
+ }
+}
diff --git a/test/CodeGen/rdr-6098585-unsigned-caserange.c b/test/CodeGen/rdr-6098585-unsigned-caserange.c
new file mode 100644
index 000000000000..80035982e1f4
--- /dev/null
+++ b/test/CodeGen/rdr-6098585-unsigned-caserange.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -triple i386-unknown-unknown --emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t &&
+// RUN: grep "ret i32" %t | count 1 &&
+// RUN: grep "ret i32 3" %t | count 1
+
+int f2(unsigned x) {
+ switch(x) {
+ default:
+ return 3;
+ case 0xFFFFFFFF ... 1: // This range should be empty because x is unsigned.
+ return 0;
+ }
+}
diff --git a/test/CodeGen/rdr-6732143-dangling-block-reference.m b/test/CodeGen/rdr-6732143-dangling-block-reference.m
new file mode 100644
index 000000000000..2d1baa622009
--- /dev/null
+++ b/test/CodeGen/rdr-6732143-dangling-block-reference.m
@@ -0,0 +1,10 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm %s -o -
+
+void f0(id x) {
+ @synchronized (x) {
+ do { ; } while(0);
+ @try {
+ } @finally {
+ }
+ }
+}
diff --git a/test/CodeGen/regparm.c b/test/CodeGen/regparm.c
new file mode 100644
index 000000000000..fdf07ead6de7
--- /dev/null
+++ b/test/CodeGen/regparm.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc -triple i386-unknown-unknown %s -emit-llvm -o - | grep inreg | count 2
+
+#define FASTCALL __attribute__((regparm(2)))
+
+typedef struct {
+ int aaa;
+ double bbbb;
+ int ccc[200];
+} foo;
+
+static void FASTCALL
+reduced(char b, double c, foo* d, double e, int f)
+{
+}
+
+int
+main(void) {
+ reduced(0, 0.0, 0, 0.0, 0);
+}
diff --git a/test/CodeGen/shared-string-literals.c b/test/CodeGen/shared-string-literals.c
new file mode 100644
index 000000000000..a05975b4aeb7
--- /dev/null
+++ b/test/CodeGen/shared-string-literals.c
@@ -0,0 +1,9 @@
+// RUN: clang-cc -emit-llvm %s -o %t
+
+char *globalString = "abc";
+char *globalStringArray[5] = { "123", "abc" };
+char *anotherGlobalString = "123";
+
+int main() {
+ printf("123");
+}
diff --git a/test/CodeGen/sizeof-vla.c b/test/CodeGen/sizeof-vla.c
new file mode 100644
index 000000000000..af5088553e48
--- /dev/null
+++ b/test/CodeGen/sizeof-vla.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -triple x86_64-unknown-unknown -emit-llvm -o %t %s
+
+// PR3442
+
+static void *g(unsigned long len);
+
+void
+f(int n)
+{
+ unsigned begin_set[n];
+
+ g(sizeof(begin_set));
+}
diff --git a/test/CodeGen/statements.c b/test/CodeGen/statements.c
new file mode 100644
index 000000000000..1ff7601adf68
--- /dev/null
+++ b/test/CodeGen/statements.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc < %s -emit-llvm
+
+void test1(int x) {
+switch (x) {
+case 111111111111111111111111111111111111111:
+bar();
+}
+}
+
+// Mismatched type between return and function result.
+int test2() { return; }
+void test3() { return 4; }
+
diff --git a/test/CodeGen/static-forward-decl-fun.c b/test/CodeGen/static-forward-decl-fun.c
new file mode 100644
index 000000000000..a945df3d3b38
--- /dev/null
+++ b/test/CodeGen/static-forward-decl-fun.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+
+static int staticfun(void);
+int (*staticuse1)(void) = staticfun;
+static int staticfun() {return 1;}
+int (*staticuse2)(void) = staticfun;
diff --git a/test/CodeGen/static-forward-decl.c b/test/CodeGen/static-forward-decl.c
new file mode 100644
index 000000000000..f12c22fb41af
--- /dev/null
+++ b/test/CodeGen/static-forward-decl.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc %s -emit-llvm -o - -triple=i686-apple-darwin9 | grep "global i32 10"
+
+static int i;
+int*j=&i;
+static int i = 10;
diff --git a/test/CodeGen/static-local-union.c b/test/CodeGen/static-local-union.c
new file mode 100644
index 000000000000..f276b200eb10
--- /dev/null
+++ b/test/CodeGen/static-local-union.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -emit-llvm < %s
+
+int a() {static union{int a;} r[2] = {1,2};return r[1].a;}
+
diff --git a/test/CodeGen/static-order.c b/test/CodeGen/static-order.c
new file mode 100644
index 000000000000..243e96bf3e65
--- /dev/null
+++ b/test/CodeGen/static-order.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc -emit-llvm -o - %s | not grep "zeroinitializer"
+
+struct s {
+ int a;
+};
+
+static void *v;
+
+static struct s a;
+
+static struct s a = {
+ 10
+};
+
+void *f()
+{
+ if (a.a)
+ return v;
+}
diff --git a/test/CodeGen/staticinit.c b/test/CodeGen/staticinit.c
new file mode 100644
index 000000000000..91fcdcf69f00
--- /dev/null
+++ b/test/CodeGen/staticinit.c
@@ -0,0 +1,31 @@
+// RUN: clang-cc -triple i386-pc-linux-gnu -emit-llvm -o %t %s &&
+// RUN: grep "g.b = internal global i8. getelementptr" %t &&
+
+struct AStruct {
+ int i;
+ char *s;
+ double d;
+};
+
+void f() {
+ static int i = 42;
+ static int is[] = { 1, 2, 3, 4 };
+ static char* str = "forty-two";
+ static char* strs[] = { "one", "two", "three", "four" };
+ static struct AStruct myStruct = { 1, "two", 3.0 };
+}
+
+void g() {
+ static char a[10];
+ static char *b = a;
+}
+
+struct s { void *p; };
+
+void foo(void) {
+ static struct s var = {((void*)&((char*)0)[0])};
+}
+
+// RUN: grep "f1.l0 = internal global i32 ptrtoint (i32 ()\* @f1 to i32)" %t
+int f1(void) { static int l0 = (unsigned) f1; }
+
diff --git a/test/CodeGen/stdcall-fastcall.c b/test/CodeGen/stdcall-fastcall.c
new file mode 100644
index 000000000000..11b652178ca8
--- /dev/null
+++ b/test/CodeGen/stdcall-fastcall.c
@@ -0,0 +1,17 @@
+// RUN: clang-cc -emit-llvm < %s | grep 'fastcallcc' | count 4
+// RUN: clang-cc -emit-llvm < %s | grep 'stdcallcc' | count 4
+
+void __attribute__((fastcall)) f1(void);
+void __attribute__((stdcall)) f2(void);
+void __attribute__((fastcall)) f3(void) {
+ f1();
+}
+void __attribute__((stdcall)) f4(void) {
+ f2();
+}
+
+int main(void) {
+ f3(); f4();
+ return 0;
+}
+
diff --git a/test/CodeGen/string-init.c b/test/CodeGen/string-init.c
new file mode 100644
index 000000000000..38c7ec057597
--- /dev/null
+++ b/test/CodeGen/string-init.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -emit-llvm %s -o %t &&
+// RUN: grep 'internal constant \[10 x i8\]' %t &&
+// RUN: not grep -F "[5 x i8]" %t &&
+// RUN: not grep "store " %t
+
+void test(void) {
+ char a[10] = "asdf";
+ char b[10] = { "asdf" };
+}
+
diff --git a/test/CodeGen/string-literal.c b/test/CodeGen/string-literal.c
new file mode 100644
index 000000000000..a4011938c106
--- /dev/null
+++ b/test/CodeGen/string-literal.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -emit-llvm %s -o -
+
+int main() {
+ char a[10] = "abc";
+
+ void *foo = L"AB";
+}
diff --git a/test/CodeGen/struct-comma.c b/test/CodeGen/struct-comma.c
new file mode 100644
index 000000000000..d7f50da13122
--- /dev/null
+++ b/test/CodeGen/struct-comma.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc %s -emit-llvm -o -
+
+struct S {int a, b;} x;
+void a(struct S* b) {*b = (r(), x);}
diff --git a/test/CodeGen/struct-copy.c b/test/CodeGen/struct-copy.c
new file mode 100644
index 000000000000..62c29aba6c9c
--- /dev/null
+++ b/test/CodeGen/struct-copy.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -emit-llvm %s -o - | grep 'call.*llvm.memcpy'
+struct x { int a[100]; };
+
+
+void foo(struct x *P, struct x *Q) {
+ *P = *Q;
+}
diff --git a/test/CodeGen/struct-init.c b/test/CodeGen/struct-init.c
new file mode 100644
index 000000000000..a38442b1a88f
--- /dev/null
+++ b/test/CodeGen/struct-init.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc %s -emit-llvm -o -
+
+typedef struct _zend_ini_entry zend_ini_entry;
+struct _zend_ini_entry {
+ void *mh_arg1;
+};
+
+char a;
+
+const zend_ini_entry ini_entries[] = {
+ { ((char*)&((zend_ini_entry*)0)->mh_arg1 - (char*)(void*)0)},
+};
diff --git a/test/CodeGen/struct-passing.c b/test/CodeGen/struct-passing.c
new file mode 100644
index 000000000000..9a4f47651b74
--- /dev/null
+++ b/test/CodeGen/struct-passing.c
@@ -0,0 +1,21 @@
+// RUN: clang-cc -triple i386-pc-linux-gnu -emit-llvm -o %t %s &&
+// RUN: grep 'declare i32 @f0() readnone$' %t &&
+// RUN: grep 'declare i32 @f1() readonly$' %t &&
+// RUN: grep 'declare void @f2(.* noalias sret)$' %t &&
+// RUN: grep 'declare void @f3(.* noalias sret)$' %t &&
+// RUN: grep 'declare void @f4(.* byval)$' %t &&
+// RUN: grep 'declare void @f5(.* byval)$' %t &&
+// RUN: true
+// PR3835
+
+typedef int T0;
+typedef struct { int a[16]; } T1;
+
+T0 __attribute__((const)) f0(void);
+T0 __attribute__((pure)) f1(void);
+T1 __attribute__((const)) f2(void);
+T1 __attribute__((pure)) f3(void);
+void __attribute__((const)) f4(T1 a);
+void __attribute__((pure)) f5(T1 a);
+
+void *ps[] = { f0, f1, f2, f3, f4, f5 };
diff --git a/test/CodeGen/struct-x86-darwin.c b/test/CodeGen/struct-x86-darwin.c
new file mode 100644
index 000000000000..050e26dcab9e
--- /dev/null
+++ b/test/CodeGen/struct-x86-darwin.c
@@ -0,0 +1,25 @@
+// RUN: clang-cc < %s -emit-llvm > %t1 -triple=i686-apple-darwin9
+// Run grep "STest1 = type <{ i32, \[4 x i16\], double }>" %t1 &&
+// RUN: grep "STest2 = type <{ i16, i16, i32, i32 }>" %t1 &&
+// RUN: grep "STest3 = type <{ i8, i8, i16, i32 }>" %t1 &&
+// RUN: grep "STestB1 = type <{ i8, i8 }>" %t1 &&
+// RUN: grep "STestB2 = type <{ i8, i8, i8 }>" %t1 &&
+// RUN: grep "STestB3 = type <{ i8, i8 }>" %t1 &&
+// RUN: grep "STestB4 = type <{ i8, i8, i8, i8 }>" %t1 &&
+// RUN: grep "STestB5 = type <{ i8, i8, i8, i8, i8, i8 }>" %t1 &&
+// RUN: grep "STestB6 = type <{ i8, i8, i8, i8 }>" %t1
+// Test struct layout for x86-darwin target
+
+struct STest1 {int x; short y[4]; double z; } st1;
+struct STest2 {short a,b; int c,d; } st2;
+struct STest3 {char a; short b; int c; } st3;
+
+// Bitfields
+struct STestB1 {char a; char b:2; } stb1;
+struct STestB2 {char a; char b:5; char c:4; } stb2;
+struct STestB3 {char a; char b:2; } stb3;
+struct STestB4 {char a; short b:2; char c; } stb4;
+struct STestB5 {char a; short b:10; char c; } stb5;
+struct STestB6 {int a:1; char b; int c:13 } stb6;
+
+// Packed struct STestP1 {char a; short b; int c; } __attribute__((__packed__)) stp1;
diff --git a/test/CodeGen/struct.c b/test/CodeGen/struct.c
new file mode 100644
index 000000000000..ed3684280e88
--- /dev/null
+++ b/test/CodeGen/struct.c
@@ -0,0 +1,192 @@
+// RUN: clang-cc -triple i386-unknown-unknown %s -emit-llvm -o -
+
+struct {
+ int x;
+ int y;
+} point;
+
+void fn1() {
+ point.x = 42;
+}
+
+/* Nested member */
+struct {
+ struct {
+ int a;
+ int b;
+ } p1;
+} point2;
+
+void fn2() {
+ point2.p1.a = 42;
+}
+
+/* Indirect reference */
+typedef struct __sf {
+ unsigned char *c;
+ short flags;
+} F;
+
+typedef struct __sf2 {
+ F *ff;
+} F2;
+
+int fn3(F2 *c) {
+ if (c->ff->c >= 0)
+ return 1;
+ else
+ return 0;
+}
+
+/* Nested structs */
+typedef struct NA {
+ int data;
+ struct NA *next;
+} NA;
+void f1() { NA a; }
+
+typedef struct NB {
+ int d1;
+ struct _B2 {
+ int d2;
+ struct NB *n2;
+ } B2;
+} NB;
+
+void f2() { NB b; }
+
+extern NB *f3();
+void f4() {
+ f3()->d1 = 42;
+}
+
+void f5() {
+ (f3())->d1 = 42;
+}
+
+/* Function calls */
+typedef struct {
+ int location;
+ int length;
+} range;
+extern range f6();
+void f7()
+{
+ range r = f6();
+}
+
+/* Member expressions */
+typedef struct {
+ range range1;
+ range range2;
+} rangepair;
+
+void f8()
+{
+ rangepair p;
+
+ range r = p.range1;
+}
+
+void f9(range *p)
+{
+ range r = *p;
+}
+
+void f10(range *p)
+{
+ range r = p[0];
+}
+
+/* _Bool types */
+
+struct _w
+{
+ short a,b;
+ short c,d;
+ short e,f;
+ short g;
+
+ unsigned int h,i;
+
+ _Bool j,k;
+} ws;
+
+/* Implicit casts (due to typedefs) */
+typedef struct _a
+{
+ int a;
+} a;
+
+void f11()
+{
+ struct _a a1;
+ a a2;
+
+ a1 = a2;
+ a2 = a1;
+}
+
+/* Implicit casts (due to const) */
+void f12()
+{
+ struct _a a1;
+ const struct _a a2;
+
+ a1 = a2;
+}
+
+/* struct initialization */
+struct a13 {int b; int c;};
+struct a13 c13 = {5};
+typedef struct a13 a13;
+struct a14 { short a; int b; } x = {1, 1};
+
+/* flexible array members */
+struct a15 {char a; int b[];} c15;
+int a16(void) {c15.a = 1;}
+
+/* compound literals */
+void f13()
+{
+ a13 x; x = (a13){1,2};
+}
+
+/* va_arg */
+int f14(int i, ...) {
+ __builtin_va_list l;
+ __builtin_va_start(l,i);
+ a13 b = __builtin_va_arg(l, a13);
+ int c = __builtin_va_arg(l, a13).c;
+ return b.b;
+}
+
+/* Attribute packed */
+struct __attribute__((packed)) S2839 { double a[19]; signed char b; } s2839[5];
+
+struct __attribute__((packed)) SS { long double a; char b; } SS;
+
+
+/* As lvalue */
+
+int f15() {
+ extern range f15_ext();
+ return f15_ext().location;
+}
+
+range f16() {
+ extern rangepair f16_ext();
+ return f16_ext().range1;
+}
+
+int f17() {
+ extern range f17_ext();
+ range r;
+ return (r = f17_ext()).location;
+}
+
+range f18() {
+ extern rangepair f18_ext();
+ rangepair rp;
+ return (rp = f18_ext()).range1;
+}
diff --git a/test/CodeGen/switch.c b/test/CodeGen/switch.c
new file mode 100644
index 000000000000..3254fbf3c938
--- /dev/null
+++ b/test/CodeGen/switch.c
@@ -0,0 +1,87 @@
+// RUN: clang-cc %s -emit-llvm-bc -o - | opt -std-compile-opts -disable-output
+
+int foo(int i) {
+ int j = 0;
+ switch (i) {
+ case -1:
+ j = 1; break;
+ case 1 :
+ j = 2; break;
+ case 2:
+ j = 3; break;
+ default:
+ j = 42; break;
+ }
+ j = j + 1;
+ return j;
+}
+
+
+int foo2(int i) {
+ int j = 0;
+ switch (i) {
+ case 1 :
+ j = 2; break;
+ case 2 ... 10:
+ j = 3; break;
+ default:
+ j = 42; break;
+ }
+ j = j + 1;
+ return j;
+}
+
+
+int foo3(int i) {
+ int j = 0;
+ switch (i) {
+ default:
+ j = 42; break;
+ case 111:
+ j = 111; break;
+ case 0 ... 100:
+ j = 1; break;
+ case 222:
+ j = 222; break;
+ }
+ return j;
+}
+
+
+int foo4(int i) {
+ int j = 0;
+ switch (i) {
+ case 111:
+ j = 111; break;
+ case 0 ... 100:
+ j = 1; break;
+ case 222:
+ j = 222; break;
+ default:
+ j = 42; break;
+ case 501 ... 600:
+ j = 5; break;
+ }
+ return j;
+}
+
+void foo5(){
+ switch(0){
+ default:
+ if (0) {
+
+ }
+ }
+}
+
+void foo6(){
+ switch(0){
+ }
+}
+
+void foo7(){
+ switch(0){
+ foo7();
+ }
+}
+
diff --git a/test/CodeGen/tentative-decls.c b/test/CodeGen/tentative-decls.c
new file mode 100644
index 000000000000..3301c234c55a
--- /dev/null
+++ b/test/CodeGen/tentative-decls.c
@@ -0,0 +1,39 @@
+// RUN: clang-cc -emit-llvm -o %t %s &&
+
+// RUN: grep '@r = common global \[1 x .*\] zeroinitializer' %t &&
+
+int r[];
+int (*a)[] = &r;
+
+struct s0;
+struct s0 x;
+// RUN: grep '@x = common global .struct.s0 zeroinitializer' %t &&
+
+struct s0 y;
+// RUN: grep '@y = common global .struct.s0 zeroinitializer' %t &&
+struct s0 *f0() {
+ return &y;
+}
+
+struct s0 {
+ int x;
+};
+
+// RUN: grep '@b = common global \[1 x .*\] zeroinitializer' %t &&
+int b[];
+int *f1() {
+ return b;
+}
+
+// Check that the most recent tentative definition wins.
+// RUN: grep '@c = common global \[4 x .*\] zeroinitializer' %t &&
+int c[];
+int c[4];
+
+// Check that we emit static tentative definitions
+// RUN: grep '@c5 = internal global \[1 x .*\] zeroinitializer' %t &&
+static int c5[];
+static int func() { return c5[0]; }
+int callfunc() { return func(); }
+
+// RUN: true
diff --git a/test/CodeGen/thread-specifier.c b/test/CodeGen/thread-specifier.c
new file mode 100644
index 000000000000..456f7a6d9761
--- /dev/null
+++ b/test/CodeGen/thread-specifier.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -triple i686-pc-linux-gnu -emit-llvm -o - %s | grep thread_local | count 4
+
+__thread int a;
+extern __thread int b;
+int c() { return &b; }
+int d() {
+ __thread static int e;
+ __thread static union {float a; int b;} f = {.b = 1};
+}
+
diff --git a/test/CodeGen/trapv.c b/test/CodeGen/trapv.c
new file mode 100644
index 000000000000..c96488b8e99b
--- /dev/null
+++ b/test/CodeGen/trapv.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -ftrapv %s -emit-llvm -o %t &&
+// RUN: grep "__overflow_handler" %t | count 2
+
+unsigned int ui, uj, uk;
+int i, j, k;
+
+void foo() {
+ ui = uj + uk;
+ i = j + k;
+}
diff --git a/test/CodeGen/typedef-func.c b/test/CodeGen/typedef-func.c
new file mode 100644
index 000000000000..a64426ddb274
--- /dev/null
+++ b/test/CodeGen/typedef-func.c
@@ -0,0 +1,16 @@
+// RUN: clang-cc -emit-llvm < %s
+
+// PR2414
+struct mad_frame{};
+enum mad_flow {};
+
+typedef enum mad_flow filter_func_t(void *, struct mad_frame *);
+
+filter_func_t mono_filter;
+
+void addfilter2(filter_func_t *func){}
+
+void setup_filters()
+{
+ addfilter2( mono_filter);
+}
diff --git a/test/CodeGen/typedef.c b/test/CodeGen/typedef.c
new file mode 100644
index 000000000000..3bdd52f6c572
--- /dev/null
+++ b/test/CodeGen/typedef.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -emit-llvm %s -o -
+
+typedef struct { int i; } Value;
+typedef Value *PValue;
+
+int get_value(PValue v) {
+ return v->i;
+}
diff --git a/test/CodeGen/types.c b/test/CodeGen/types.c
new file mode 100644
index 000000000000..75cb851c2599
--- /dev/null
+++ b/test/CodeGen/types.c
@@ -0,0 +1,34 @@
+// RUN: clang-cc -emit-llvm <%s
+
+struct FileName {
+ struct FileName *next;
+} *fnhead;
+
+
+struct ieeeExternal {
+ struct ieeeExternal *next;
+} *exthead;
+
+
+void test1()
+{
+ struct ieeeExternal *exttmp = exthead;
+}
+
+struct MpegEncContext;
+typedef struct MpegEncContext {int pb;} MpegEncContext;
+static void test2(void) {MpegEncContext s; s.pb;}
+
+
+struct Village;
+
+struct List {
+ struct Village *v;
+};
+
+struct Village {
+ struct List returned;
+};
+
+void test3(struct List a) {
+}
diff --git a/test/CodeGen/uint128_t.c b/test/CodeGen/uint128_t.c
new file mode 100644
index 000000000000..b3bf7279623f
--- /dev/null
+++ b/test/CodeGen/uint128_t.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc %s -emit-llvm -o - -triple=x86_64-apple-darwin9
+
+typedef unsigned long long uint64_t;
+extern uint64_t numer;
+extern uint64_t denom;
+
+uint64_t
+f(uint64_t val)
+{
+ __uint128_t tmp;
+
+ tmp = val;
+ tmp *= numer;
+ tmp /= denom;
+
+ return tmp;
+}
+
diff --git a/test/CodeGen/union-init.c b/test/CodeGen/union-init.c
new file mode 100644
index 000000000000..c882d3180c72
--- /dev/null
+++ b/test/CodeGen/union-init.c
@@ -0,0 +1,31 @@
+// RUN: clang-cc -emit-llvm < %s -o -
+
+// A nice and complicated initialization example with unions from Python
+typedef int Py_ssize_t;
+
+typedef union _gc_head {
+ struct {
+ union _gc_head *gc_next;
+ union _gc_head *gc_prev;
+ Py_ssize_t gc_refs;
+ } gc;
+ long double dummy; /* force worst-case alignment */
+} PyGC_Head;
+
+struct gc_generation {
+ PyGC_Head head;
+ int threshold; /* collection threshold */
+ int count; /* count of allocations or collections of younger
+ generations */
+};
+
+#define NUM_GENERATIONS 3
+#define GEN_HEAD(n) (&generations[n].head)
+
+/* linked lists of container objects */
+struct gc_generation generations[NUM_GENERATIONS] = {
+ /* 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/union.c b/test/CodeGen/union.c
new file mode 100644
index 000000000000..4884690f3fdc
--- /dev/null
+++ b/test/CodeGen/union.c
@@ -0,0 +1,41 @@
+// RUN: clang-cc %s -emit-llvm -o -
+
+union u_tag {
+ int a;
+ float b;
+} u;
+
+void f() {
+ u.b = 11;
+}
+
+float get_b(union u_tag *my_u) {
+ return my_u->b;
+}
+
+int f2( float __x ) {
+ union{
+ float __f;
+ unsigned int __u;
+ }__u;
+ return (int)(__u.__u >> 31);
+}
+
+typedef union { int i; int *j; } value;
+
+int f3(value v) {
+ return *v.j;
+}
+
+enum E9 { one, two };
+union S65 { enum E9 a; } ; union S65 s65;
+void fS65() { enum E9 e = s65.a; }
+
+typedef union{
+ unsigned char x[65536];
+} q;
+int qfunc() {q buf; unsigned char* x = buf.x;}
+
+union RR {_Bool a : 1;} RRU;
+int RRF(void) {return RRU.a;}
+
diff --git a/test/CodeGen/unwind-attr.c b/test/CodeGen/unwind-attr.c
new file mode 100644
index 000000000000..b2890c4c10de
--- /dev/null
+++ b/test/CodeGen/unwind-attr.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fexceptions -emit-llvm -o - %s | grep "@foo() {" | count 1 &&
+// RUN: clang-cc -emit-llvm -o - %s | grep "@foo() nounwind {" | count 1
+
+int foo(void) {
+}
diff --git a/test/CodeGen/var-align.c b/test/CodeGen/var-align.c
new file mode 100644
index 000000000000..b0b62ae26473
--- /dev/null
+++ b/test/CodeGen/var-align.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -emit-llvm %s -o - | grep "align 16" | count 2
+
+__attribute((aligned(16))) float a[128];
+union {int a[4]; __attribute((aligned(16))) float b[4];} u;
diff --git a/test/CodeGen/variable-array.c b/test/CodeGen/variable-array.c
new file mode 100644
index 000000000000..f5621c289d7a
--- /dev/null
+++ b/test/CodeGen/variable-array.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc -emit-llvm < %s | grep puts | count 4
+
+// PR3248
+int a(int x)
+{
+ int (*y)[x];
+ return sizeof(*(puts("asdf"),y));
+}
+
+// PR3247
+int b() {
+ return sizeof(*(char(*)[puts("asdf")])0);
+}
+
+// PR3247
+int c() {
+ static int (*y)[puts("asdf")];
+ return sizeof(*y);
+}
diff --git a/test/CodeGen/vector.c b/test/CodeGen/vector.c
new file mode 100644
index 000000000000..2e753b42c4d7
--- /dev/null
+++ b/test/CodeGen/vector.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -emit-llvm %s -o -
+typedef short __v4hi __attribute__ ((__vector_size__ (8)));
+
+void f()
+{
+ __v4hi A = (__v4hi)0LL;
+}
+
+__v4hi x = {1,2,3};
+__v4hi y = {1,2,3,4};
+
+typedef int vty __attribute((vector_size(16)));
+int a() { vty b; return b[2LL]; }
diff --git a/test/CodeGen/visibility.c b/test/CodeGen/visibility.c
new file mode 100644
index 000000000000..bb9b6e0d50ce
--- /dev/null
+++ b/test/CodeGen/visibility.c
@@ -0,0 +1,41 @@
+// RUN: clang-cc -triple i386-unknown-unknown -fvisibility=default -emit-llvm -o %t %s &&
+// RUN: grep '@g_com = common global i32 0' %t &&
+// RUN: grep '@g_def = global i32 0' %t &&
+// RUN: grep '@g_ext = external global i32' %t &&
+// RUN: grep '@g_deferred = internal global' %t &&
+// RUN: grep 'declare void @f_ext()' %t &&
+// RUN: grep 'define internal void @f_deferred()' %t &&
+// RUN: grep 'define i32 @f_def()' %t &&
+// RUN: clang-cc -triple i386-unknown-unknown -fvisibility=protected -emit-llvm -o %t %s &&
+// RUN: grep '@g_com = common protected global i32 0' %t &&
+// RUN: grep '@g_def = protected global i32 0' %t &&
+// RUN: grep '@g_ext = external global i32' %t &&
+// RUN: grep '@g_deferred = internal global' %t &&
+// RUN: grep 'declare void @f_ext()' %t &&
+// RUN: grep 'define internal void @f_deferred()' %t &&
+// RUN: grep 'define protected i32 @f_def()' %t &&
+// RUN: clang-cc -triple i386-unknown-unknown -fvisibility=hidden -emit-llvm -o %t %s &&
+// RUN: grep '@g_com = common hidden global i32 0' %t &&a
+// RUN: grep '@g_def = hidden global i32 0' %t &&
+// RUN: grep '@g_ext = external global i32' %t &&
+// RUN: grep '@g_deferred = internal global' %t &&
+// RUN: grep 'declare void @f_ext()' %t &&
+// RUN: grep 'define internal void @f_deferred()' %t &&
+// RUN: grep 'define hidden i32 @f_def()' %t &&
+// RUN: true
+
+int g_com;
+int g_def = 0;
+extern int g_ext;
+static char g_deferred[] = "hello";
+
+extern void f_ext(void);
+
+static void f_deferred(void) {
+}
+
+int f_def(void) {
+ f_ext();
+ f_deferred();
+ return g_com + g_def + g_ext + g_deferred[0];
+}
diff --git a/test/CodeGen/vla.c b/test/CodeGen/vla.c
new file mode 100644
index 000000000000..844e49e72c46
--- /dev/null
+++ b/test/CodeGen/vla.c
@@ -0,0 +1,37 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+
+int b(char* x);
+
+// Extremely basic VLA test
+void a(int x) {
+ char arry[x];
+ arry[0] = 10;
+ b(arry);
+}
+
+int c(int n)
+{
+ return sizeof(int[n]);
+}
+
+int f0(int x) {
+ int vla[x];
+ return vla[x-1];
+}
+
+void
+f(int count)
+{
+ int a[count];
+
+ do { } while (0);
+
+ if (a[0] != 3) {
+ }
+}
+
+void g(int count) {
+ // Make sure we emit sizes correctly in some obscure cases
+ int (*a[5])[count];
+ int (*b)[][count];
+}
diff --git a/test/CodeGen/volatile-1.c b/test/CodeGen/volatile-1.c
new file mode 100644
index 000000000000..ac3b4c2e97b2
--- /dev/null
+++ b/test/CodeGen/volatile-1.c
@@ -0,0 +1,143 @@
+// RUN: clang-cc -Wno-unused-value -emit-llvm < %s -o %t &&
+// RUN: grep volatile %t | count 145 &&
+// RUN: grep memcpy %t | count 4
+
+volatile int i, j, k;
+volatile int ar[5];
+volatile char c;
+volatile _Complex int ci;
+volatile struct S {
+#ifdef __cplusplus
+ void operator =(volatile struct S&o) volatile;
+#endif
+ int i;
+} a, b;
+
+//void operator =(volatile struct S&o1, volatile struct S&o2) volatile;
+#include <stdio.h>
+
+int main() {
+ // A use.
+ i;
+ // A use of the real part
+ (float)(ci);
+ // A use.
+ (void)ci;
+ // A use.
+ (void)a;
+ // Not a use.
+ (void)(ci=ci);
+ // Not a use.
+ (void)(i=j);
+ ci+=ci;
+ (ci += ci) + ci;
+ asm("nop");
+ (i += j) + k;
+ asm("nop");
+ // A use
+ (i += j) + 1;
+ asm("nop");
+ ci+ci;
+ // A use.
+ __real i;
+ // A use.
+ +ci;
+ asm("nop");
+ // Not a use.
+ (void)(i=i);
+ (float)(i=i);
+ // A use.
+ (void)i;
+ i=i;
+ i=i=i;
+#ifndef __cplusplus
+ // Not a use.
+ (void)__builtin_choose_expr(0, i=i, j=j);
+#endif
+ // A use.
+ k ? (i=i) : (j=j);
+ (void)(i,(i=i));
+ i=i,i;
+ (i=j,k=j);
+ (i=j,k);
+ (i,j);
+ i=c=k;
+ i+=k;
+ // A use of both.
+ ci;
+#ifndef __cplusplus
+ // A use of _real.
+ (int)ci;
+ // A use of both.
+ (_Bool)ci;
+#endif
+ ci=ci;
+ ci=ci=ci;
+ __imag ci = __imag ci = __imag ci;
+ // Not a use.
+ __real (i = j);
+ // Not a use.
+ __imag i;
+
+ // ============================================================
+ // FIXME: Test cases we get wrong.
+
+ // A use. We load all of a into a copy of a, then load i. gcc forgets to do
+ // the assignment.
+ // (a = a).i;
+
+ // ============================================================
+ // Test cases where we intentionally differ from gcc, due to suspected bugs in
+ // gcc.
+
+ // Not a use. gcc forgets to do the assignment.
+ ((a=a),a);
+
+ // Not a use. gcc gets this wrong, it doesn't emit the copy!
+ // (void)(a=a);
+
+ // 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);
+
+#ifndef __cplusplus
+ // A use of the real part
+ (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.
+ (int)(ci=ci);
+#endif
+
+ // A use.
+ (float)(i=i);
+ // A use. gcc treats this as not a use, that's probably a bug due to tree
+ // folding ignoring volatile.
+ (int)(i=i);
+
+ // A use.
+ -(i=j);
+ // A use. gcc treats this a not a use, that's probably a bug due to tree
+ // folding ignoring volatile.
+ +(i=k);
+
+ // A use. gcc treats this a not a use, that's probably a bug due to tree
+ // folding ignoring volatile.
+ __real (ci=ci);
+
+ // A use.
+ i + 0;
+ // A use.
+ (i=j) + i;
+ // A use. gcc treats this as not a use, that's probably a bug due to tree
+ // folding ignoring volatile.
+ (i=j) + 0;
+
+#ifdef __cplusplus
+ (i,j)=k;
+ (j=k,i)=i;
+ struct { int x; } s, s1;
+ printf("s is at %p\n", &s);
+ printf("s is at %p\n", &(s = s1));
+ printf("s.x is at %p\n", &((s = s1).x));
+#endif
+}
diff --git a/test/CodeGen/volatile.c b/test/CodeGen/volatile.c
new file mode 100644
index 000000000000..212a0aeb1e35
--- /dev/null
+++ b/test/CodeGen/volatile.c
@@ -0,0 +1,94 @@
+// RUN: clang-cc -emit-llvm < %s -o %t &&
+// RUN: grep volatile %t | count 25 &&
+// RUN: grep memcpy %t | count 7
+
+// The number 25 comes from the current codegen for volatile loads;
+// if this number changes, it's not necessarily something wrong, but
+// something has changed to affect volatile load/store codegen
+
+int S;
+volatile int vS;
+
+int* pS;
+volatile int* pvS;
+
+int A[10];
+volatile int vA[10];
+
+struct { int x; } F;
+struct { volatile int x; } vF;
+
+struct { int x; } F2;
+volatile struct { int x; } vF2;
+volatile struct { int x; } *vpF2;
+
+struct { struct { int y; } x; } F3;
+volatile struct { struct { int y; } x; } vF3;
+
+struct { int x:3; } BF;
+struct { volatile int x:3; } vBF;
+
+typedef int v4si __attribute__ ((vector_size (16)));
+v4si V;
+volatile v4si vV;
+
+typedef __attribute__(( ext_vector_type(4) )) int extv4;
+extv4 VE;
+volatile extv4 vVE;
+
+volatile struct {int x;} aggFct(void);
+
+void main() {
+ int i;
+
+ // load
+ i=S;
+ i=vS;
+ i=*pS;
+ i=*pvS;
+ i=A[2];
+ i=vA[2];
+ i=F.x;
+ i=vF.x;
+ i=F2.x;
+ i=vF2.x;
+ i=vpF2->x;
+ i=F3.x.y;
+ i=vF3.x.y;
+ i=BF.x;
+ i=vBF.x;
+ i=V[3];
+ i=vV[3];
+ i=VE.yx[1];
+ i=vVE.zy[1];
+ i = aggFct().x;
+
+
+ // store
+ S=i;
+ vS=i;
+ *pS=i;
+ *pvS=i;
+ A[2]=i;
+ vA[2]=i;
+ F.x=i;
+ vF.x=i;
+ F2.x=i;
+ vF2.x=i;
+ vpF2->x=i;
+ vF3.x.y=i;
+ BF.x=i;
+ vBF.x=i;
+ V[3]=i;
+ vV[3]=i;
+
+ // other ops:
+ ++S;
+ ++vS;
+ i+=S;
+ i+=vS;
+ (void)vF2;
+ vF2 = vF2;
+ vF2 = vF2 = vF2;
+ vF2 = (vF2, vF2);
+}
diff --git a/test/CodeGen/weak-global.c b/test/CodeGen/weak-global.c
new file mode 100644
index 000000000000..d4ee52f48956
--- /dev/null
+++ b/test/CodeGen/weak-global.c
@@ -0,0 +1,3 @@
+// RUN: clang-cc -emit-llvm < %s | grep common
+
+int i;
diff --git a/test/CodeGen/weak-incomplete.c b/test/CodeGen/weak-incomplete.c
new file mode 100644
index 000000000000..a15dbac03cb7
--- /dev/null
+++ b/test/CodeGen/weak-incomplete.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -emit-llvm < %s | grep 'extern_weak' | count 1
+
+struct S;
+void __attribute__((weak)) foo1(struct S);
+void (*foo2)(struct S) = foo1;
diff --git a/test/CodeGen/whilestmt.c b/test/CodeGen/whilestmt.c
new file mode 100644
index 000000000000..95e18f4d21ff
--- /dev/null
+++ b/test/CodeGen/whilestmt.c
@@ -0,0 +1,62 @@
+// RUN: clang-cc %s -emit-llvm -o -
+
+int bar();
+int foo() {
+ int i;
+ i = 1 + 2;
+ while(1) {
+ i = bar();
+ i = bar();
+ };
+ return i;
+}
+
+
+int foo1() {
+ int i;
+ i = 1 + 2;
+ while(1) {
+ i = bar();
+ if (i == 42)
+ break;
+ i = bar();
+ };
+ return i;
+}
+
+
+int foo2() {
+ int i;
+ i = 1 + 2;
+ while(1) {
+ i = bar();
+ if (i == 42)
+ continue;
+ i = bar();
+ };
+ return i;
+}
+
+
+int foo3() {
+ int i;
+ i = 1 + 2;
+ while(1) {
+ i = bar();
+ if (i == 42)
+ break;
+ };
+ return i;
+}
+
+
+int foo4() {
+ int i;
+ i = 1 + 2;
+ while(1) {
+ i = bar();
+ if (i == 42)
+ continue;
+ };
+ return i;
+}
diff --git a/test/CodeGen/writable-strings.c b/test/CodeGen/writable-strings.c
new file mode 100644
index 000000000000..c8b70d5f0540
--- /dev/null
+++ b/test/CodeGen/writable-strings.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -emit-llvm -o - -fwritable-strings %s
+
+int main() {
+ char *str = "abc";
+ str[0] = '1';
+ printf("%s", str);
+}
+
diff --git a/test/CodeGen/x86.c b/test/CodeGen/x86.c
new file mode 100644
index 000000000000..10808dca8782
--- /dev/null
+++ b/test/CodeGen/x86.c
@@ -0,0 +1,23 @@
+// RUN: clang-cc %s -triple=i686-pc-linux-gnu -emit-llvm -o - > %t1
+// RUN: grep "ax" %t1 &&
+// RUN: grep "bx" %t1 &&
+// RUN: grep "cx" %t1 &&
+// RUN: grep "dx" %t1 &&
+// RUN: grep "di" %t1 &&
+// RUN: grep "si" %t1 &&
+// RUN: grep "st" %t1 &&
+// RUN: grep "st(1)" %t1
+
+void test1() {
+ int d1, d2;
+ asm ("" : "=a" (d1), "=b" (d2) :
+ "c" (0), "d" (0), "S" (0), "D" (0), "t" (0), "u" (0));
+}
+
+
+// rdar://6803924
+typedef double T __attribute__ ((__vector_size__ (16)));
+T test2(T va) {
+ return __builtin_ia32_shufpd(va, va, 3);
+}
+
diff --git a/test/CodeGen/x86_32-arguments.c b/test/CodeGen/x86_32-arguments.c
new file mode 100644
index 000000000000..8980c66b2072
--- /dev/null
+++ b/test/CodeGen/x86_32-arguments.c
@@ -0,0 +1,157 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm -o %t %s &&
+// RUN: grep 'define signext i8 @f0()' %t &&
+// RUN: grep 'define signext i16 @f1()' %t &&
+// RUN: grep 'define i32 @f2()' %t &&
+// RUN: grep 'define float @f3()' %t &&
+// RUN: grep 'define double @f4()' %t &&
+// RUN: grep 'define x86_fp80 @f5()' %t &&
+// RUN: grep 'define void @f6(i8 signext %a0, i16 signext %a1, i32 %a2, i64 %a3, i8\* %a4)' %t &&
+// RUN: grep 'define void @f7(i32 %a0)' %t &&
+// RUN: grep 'define i64 @f8_1()' %t &&
+// RUN: grep 'define void @f8_2(i32 %a0.0, i32 %a0.1)' %t &&
+
+char f0(void) {
+}
+
+short f1(void) {
+}
+
+int f2(void) {
+}
+
+float f3(void) {
+}
+
+double f4(void) {
+}
+
+long double f5(void) {
+}
+
+void f6(char a0, short a1, int a2, long long a3, void *a4) {
+}
+
+typedef enum { A, B, C } E;
+
+void f7(E a0) {
+}
+
+struct s8 {
+ int a;
+ int b;
+};
+struct s8 f8_1(void) {
+}
+void f8_2(struct s8 a0) {
+}
+
+// This should be passed just as s8.
+
+// RUN: grep 'define i64 @f9_1()' %t &&
+
+// FIXME: llvm-gcc expands this, this may have some value for the
+// backend in terms of optimization but doesn't change the ABI.
+// RUN: grep 'define void @f9_2(%.truct.s9\* byval %a0)' %t &&
+struct s9 {
+ int a : 17;
+ int b;
+};
+struct s9 f9_1(void) {
+}
+void f9_2(struct s9 a0) {
+}
+
+// Return of small structures and unions
+
+// RUN: grep 'float @f10()' %t &&
+struct s10 {
+ union { };
+ float f;
+} f10(void) {}
+
+// Small vectors and 1 x {i64,double} are returned in registers
+
+// RUN: grep 'i32 @f11()' %t &&
+// RUN: grep -F 'void @f12(<2 x i32>* noalias sret %agg.result)' %t &&
+// RUN: grep 'i64 @f13()' %t &&
+// RUN: grep 'i64 @f14()' %t &&
+// RUN: grep '<2 x i64> @f15()' %t &&
+// RUN: grep '<2 x i64> @f16()' %t &&
+typedef short T11 __attribute__ ((vector_size (4)));
+T11 f11(void) {}
+typedef int T12 __attribute__ ((vector_size (8)));
+T12 f12(void) {}
+typedef long long T13 __attribute__ ((vector_size (8)));
+T13 f13(void) {}
+typedef double T14 __attribute__ ((vector_size (8)));
+T14 f14(void) {}
+typedef long long T15 __attribute__ ((vector_size (16)));
+T15 f15(void) {}
+typedef double T16 __attribute__ ((vector_size (16)));
+T16 f16(void) {}
+
+// And when the single element in a struct (but not for 64 and
+// 128-bits).
+
+// RUN: grep 'i32 @f17()' %t &&
+// RUN: grep -F 'void @f18(%2* noalias sret %agg.result)' %t &&
+// RUN: grep -F 'void @f19(%3* noalias sret %agg.result)' %t &&
+// RUN: grep -F 'void @f20(%4* noalias sret %agg.result)' %t &&
+// RUN: grep -F 'void @f21(%5* noalias sret %agg.result)' %t &&
+// RUN: grep -F 'void @f22(%6* noalias sret %agg.result)' %t &&
+struct { T11 a; } f17(void) {}
+struct { T12 a; } f18(void) {}
+struct { T13 a; } f19(void) {}
+struct { T14 a; } f20(void) {}
+struct { T15 a; } f21(void) {}
+struct { T16 a; } f22(void) {}
+
+// Single element structures are handled specially
+
+// RUN: grep -F 'float @f23()' %t &&
+// RUN: grep -F 'float @f24()' %t &&
+// RUN: grep -F 'float @f25()' %t &&
+struct { float a; } f23(void) {}
+struct { float a[1]; } f24(void) {}
+struct { struct {} a; struct { float a[1]; } b; } f25(void) {}
+
+// Small structures are handled recursively
+// RUN: grep -F 'i32 @f26()' %t &&
+// RUN: grep 'void @f27(%.truct.s27\* noalias sret %agg.result)' %t &&
+struct s26 { struct { char a, b; } a; struct { char a, b; } b; } f26(void) {}
+struct s27 { struct { char a, b, c; } a; struct { char a; } b; } f27(void) {}
+
+// RUN: grep 'void @f28(%.truct.s28\* noalias sret %agg.result)' %t &&
+struct s28 { int a; int b[]; } f28(void) {}
+
+// RUN: grep 'define i16 @f29()' %t &&
+struct s29 { struct { } a[1]; char b; char c; } f29(void) {}
+
+// RUN: grep 'define i16 @f30()' %t &&
+struct s30 { char a; char b : 4; } f30(void) {}
+
+// RUN: grep 'define float @f31()' %t &&
+struct s31 { char : 0; float b; char : 0; } f31(void) {}
+
+// RUN: grep 'define i32 @f32()' %t &&
+struct s32 { char a; unsigned : 0; } f32(void) {}
+
+// RUN: grep 'define float @f33()' %t &&
+struct s33 { float a; long long : 0; } f33(void) {}
+
+// RUN: grep 'define float @f34()' %t &&
+struct s34 { struct { int : 0; } a; float b; } f34(void) {}
+
+// RUN: grep 'define i16 @f35()' %t &&
+struct s35 { struct { int : 0; } a; char b; char c; } f35(void) {}
+
+// RUN: grep 'define i16 @f36()' %t &&
+struct s36 { struct { int : 0; } a[2][10]; char b; char c; } f36(void) {}
+
+// RUN: grep 'define float @f37()' %t &&
+struct s37 { float c[1][1]; } f37(void) {}
+
+// RUN: grep 'define void @f38(.struct.s38. noalias sret .agg.result)' %t &&
+struct s38 { char a[3]; short b; } f38(void) {}
+
+// RUN: true
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
new file mode 100644
index 000000000000..6f7ec82872be
--- /dev/null
+++ b/test/CodeGen/x86_64-arguments.c
@@ -0,0 +1,85 @@
+// RUN: clang-cc -triple x86_64-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: grep 'define signext i8 @f0()' %t &&
+// RUN: grep 'define signext i16 @f1()' %t &&
+// RUN: grep 'define i32 @f2()' %t &&
+// RUN: grep 'define float @f3()' %t &&
+// RUN: grep 'define double @f4()' %t &&
+// RUN: grep 'define x86_fp80 @f5()' %t &&
+// RUN: grep 'define void @f6(i8 signext %a0, i16 signext %a1, i32 %a2, i64 %a3, i8\* %a4)' %t &&
+// RUN: grep 'define void @f7(i32 %a0)' %t &&
+// RUN: grep 'type { i64, double }.*type .0' %t &&
+// RUN: grep 'define .0 @f8_1()' %t &&
+// RUN: grep 'define void @f8_2(.0)' %t &&
+
+char f0(void) {
+}
+
+short f1(void) {
+}
+
+int f2(void) {
+}
+
+float f3(void) {
+}
+
+double f4(void) {
+}
+
+long double f5(void) {
+}
+
+void f6(char a0, short a1, int a2, long long a3, void *a4) {
+}
+
+typedef enum { A, B, C } E;
+
+void f7(E a0) {
+}
+
+// Test merging/passing of upper eightbyte with X87 class.
+union u8 {
+ long double a;
+ int b;
+};
+union u8 f8_1() {}
+void f8_2(union u8 a0) {}
+
+// RUN: grep 'define i64 @f9()' %t &&
+struct s9 { int a; int b; int : 0; } f9(void) {}
+
+// RUN: grep 'define void @f10(i64)' %t &&
+struct s10 { int a; int b; int : 0; };
+void f10(struct s10 a0) {}
+
+// RUN: grep 'define void @f11(.union.anon. noalias sret .agg.result)' %t &&
+union { long double a; float b; } f11() {}
+
+// RUN: grep 'define i64 @f12_0()' %t &&
+// RUN: grep 'define void @f12_1(i64)' %t &&
+struct s12 { int a __attribute__((aligned(16))); };
+struct s12 f12_0(void) {}
+void f12_1(struct s12 a0) {}
+
+// Check that sret parameter is accounted for when checking available integer
+// registers.
+// RUN: grep 'define void @f13(.struct.s13_0. noalias sret .agg.result, i32 .a, i32 .b, i32 .c, i32 .d, .struct.s13_1. byval .e, i32 .f)' %t &&
+
+struct s13_0 { long long f0[3]; };
+struct s13_0 f13(int a, int b, int c, int d,
+ struct s13_1 { long long f0[2]; } e, int f) {}
+
+// RUN: grep 'define void @f14(.*, i8 signext .X)' %t &&
+void f14(int a, int b, int c, int d, int e, int f,
+ char X) {}
+// RUN: grep 'define void @f15(.*, i8\* .X)' %t &&
+void f15(int a, int b, int c, int d, int e, int f,
+ void *X) {}
+// RUN: grep 'define void @f16(.*, float .X)' %t &&
+void f16(float a, float b, float c, float d, float e, float f, float g, float h,
+ float X) {}
+// RUN: grep 'define void @f17(.*, x86_fp80 .X)' %t &&
+void f17(float a, float b, float c, float d, float e, float f, float g, float h,
+ long double X) {}
+
+// RUN: true
diff --git a/test/CodeGenCXX/__null.cpp b/test/CodeGenCXX/__null.cpp
new file mode 100644
index 000000000000..476b0ad083bc
--- /dev/null
+++ b/test/CodeGenCXX/__null.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc %s -emit-llvm -o %t
+
+int* a = __null;
+int b = __null;
+
+void f() {
+ int* c = __null;
+ int d = __null;
+}
diff --git a/test/CodeGenCXX/const-init.cpp b/test/CodeGenCXX/const-init.cpp
new file mode 100644
index 000000000000..427ba5372992
--- /dev/null
+++ b/test/CodeGenCXX/const-init.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-cc -verify -emit-llvm -o %t %s
+
+int a = 10;
+int &ar = a;
+
+void f();
+void (&fr)() = f;
+
+struct S { int& a; };
+S s = { a };
+
diff --git a/test/CodeGenCXX/explicit-instantiation.cpp b/test/CodeGenCXX/explicit-instantiation.cpp
new file mode 100644
index 000000000000..38966aad2deb
--- /dev/null
+++ b/test/CodeGenCXX/explicit-instantiation.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-cc -emit-llvm -femit-all-decls -o %t %s &&
+// RUN: grep "_ZNK4plusIillEclERKiRKl" %t | count 1
+
+template<typename T, typename U, typename Result>
+struct plus {
+ Result operator()(const T& t, const U& u) const {
+ return t + u;
+ }
+};
+
+template struct plus<int, long, long>;
diff --git a/test/CodeGenCXX/expr.cpp b/test/CodeGenCXX/expr.cpp
new file mode 100644
index 000000000000..ae5b0e644f27
--- /dev/null
+++ b/test/CodeGenCXX/expr.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-cc -emit-llvm -x c++ < %s
+
+void f(int x) {
+ if (x != 0) return;
+}
diff --git a/test/CodeGenCXX/extern-c.cpp b/test/CodeGenCXX/extern-c.cpp
new file mode 100644
index 000000000000..635329323354
--- /dev/null
+++ b/test/CodeGenCXX/extern-c.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-cc -emit-llvm %s -o %t &&
+namespace foo {
+
+// RUN: not grep "@a = global i32" %t &&
+extern "C" int a;
+
+// RUN: not grep "@_ZN3foo1bE = global i32" %t &&
+extern int b;
+
+// RUN: grep "@_ZN3foo1cE = global i32" %t | count 1
+int c = 5;
+
+}
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
new file mode 100644
index 000000000000..ef36a8b23cfc
--- /dev/null
+++ b/test/CodeGenCXX/mangle.cpp
@@ -0,0 +1,87 @@
+// RUN: clang-cc -emit-llvm %s -o %t -triple=x86_64-apple-darwin9 &&
+
+// FIXME: This test is intentionally trivial, because we can't yet
+// CodeGen anything real in C++.
+struct X { };
+struct Y { };
+
+// RUN: grep _ZplRK1YRA100_P1X %t | count 1 &&
+bool operator+(const Y&, X* (&xs)[100]) { return false; }
+
+// RUN: grep _Z1f1s %t | count 1 &&
+typedef struct { int a; } s;
+void f(s) { }
+
+// RUN: grep _Z1f1e %t| count 1 &&
+typedef enum { foo } e;
+void f(e) { }
+
+// RUN: grep _Z1f1u %t | count 1 &&
+typedef union { int a; } u;
+void f(u) { }
+
+// RUN: grep _Z1f1x %t | count 1 &&
+typedef struct { int a; } x,y;
+void f(y) { }
+
+// RUN: grep _Z1fv %t | count 1 &&
+void f() { }
+
+// RUN: grep _ZN1N1fEv %t | count 1 &&
+namespace N { void f() { } }
+
+// RUN: grep _ZN1N1N1fEv %t | count 1 &&
+namespace N { namespace N { void f() { } } }
+
+// RUN: grep unmangled_function %t | count 1 &&
+extern "C" { namespace N { void unmangled_function() { } } }
+
+// RUN: grep unmangled_variable %t | count 1 &&
+extern "C" { namespace N { int unmangled_variable = 10; } }
+
+// RUN: grep _ZN1N1iE %t | count 1 &&
+namespace N { int i; }
+
+// RUN: grep _ZZN1N1fEiiE1b %t | count 2 &&
+namespace N { int f(int, int) { static int b; return b; } }
+
+// RUN: grep "_ZZN1N1gEvE1a =" %t | count 1 &&
+// RUN: grep "_ZGVZN1N1gEvE1a =" %t | count 1 &&
+namespace N { int h(); void g() { static int a = h(); } }
+
+// RUN: grep "_Z1fno" %t | count 1 &&
+void f(__int128_t, __uint128_t) { }
+
+template <typename T> struct S1 {};
+
+// RUN: grep "_Z1f2S1IiE" %t | count 1 &&
+void f(S1<int>) {}
+
+// RUN: grep "_Z1f2S1IdE" %t | count 1 &&
+void f(S1<double>) {}
+
+template <int N> struct S2 {};
+// RUN: grep "_Z1f2S2ILi100EE" %t | count 1 &&
+void f(S2<100>) {}
+
+// RUN: grep "_Z1f2S2ILin100EE" %t | count 1 &&
+void f(S2<-100>) {}
+
+template <bool B> struct S3 {};
+
+// RUN: grep "_Z1f2S3ILb1EE" %t | count 1 &&
+void f(S3<true>) {}
+
+// RUN: grep "_Z1f2S3ILb0EE" %t | count 1 &&
+void f(S3<false>) {}
+
+// RUN: grep "_Z2f22S3ILb1EE" %t | count 1 &&
+void f2(S3<100>) {}
+
+struct S;
+
+// RUN: grep "_Z1fM1SKFvvE" %t | count 1 &&
+void f(void (S::*)() const) {}
+
+// RUN: grep "_Z1fM1SFvvE" %t | count 1
+void f(void (S::*)()) {}
diff --git a/test/CodeGenCXX/member-functions.cpp b/test/CodeGenCXX/member-functions.cpp
new file mode 100644
index 000000000000..8ada907117be
--- /dev/null
+++ b/test/CodeGenCXX/member-functions.cpp
@@ -0,0 +1,63 @@
+// RUN: clang-cc -emit-llvm %s -triple x86_64-apple-darwin9 -o %t &&
+struct C {
+ void f();
+ void g(int, ...);
+};
+
+// RUN: grep "define void @_ZN1C1fEv" %t | count 1 &&
+void C::f() {
+}
+
+void test1() {
+ C c;
+
+// RUN: grep "call void @_ZN1C1fEv" %t | count 1 &&
+ c.f();
+
+// RUN: grep "call void (.struct.C\*, i32, ...)\* @_ZN1C1gEiz" %t | count 1 &&
+ c.g(1, 2, 3);
+}
+
+
+struct S {
+ // RUN: grep "define linkonce_odr void @_ZN1SC1Ev" %t &&
+ inline S() { }
+ // RUN: grep "define linkonce_odr void @_ZN1SC1Ev" %t &&
+ inline ~S() { }
+
+
+ // RUN: grep "define linkonce_odr void @_ZN1S9f_inline1Ev" %t &&
+ void f_inline1() { }
+ // RUN: grep "define linkonce_odr void @_ZN1S9f_inline2Ev" %t &&
+ inline void f_inline2() { }
+
+ // RUN: grep "define linkonce_odr void @_ZN1S1gEv" %t &&
+ static void g() { }
+
+ static void f();
+};
+
+// RUN: grep "define void @_ZN1S1fEv" %t &&
+void S::f() {
+}
+
+void test2() {
+ S s;
+
+ s.f_inline1();
+ s.f_inline2();
+
+ S::g();
+
+}
+
+struct T {
+ T operator+(const T&);
+};
+
+void test3() {
+ T t1, t2;
+
+ // RUN: grep "call void @_ZN1TpsERK1T" %t
+ T result = t1 + t2;
+}
diff --git a/test/CodeGenCXX/new.cpp b/test/CodeGenCXX/new.cpp
new file mode 100644
index 000000000000..480bbcefc08d
--- /dev/null
+++ b/test/CodeGenCXX/new.cpp
@@ -0,0 +1,56 @@
+// RUN: clang-cc %s -emit-llvm -o %t &&
+
+void t1() {
+ int* a = new int;
+}
+
+// Placement.
+void* operator new(unsigned long, void*) throw();
+
+void t2(int* a) {
+ int* b = new (a) int;
+}
+
+struct S {
+ int a;
+};
+
+// POD types.
+void t3() {
+ int *a = new int(10);
+ _Complex int* b = new _Complex int(10i);
+
+ S s;
+ s.a = 10;
+ S *sp = new S(s);
+}
+
+// Non-POD
+struct T {
+ T();
+ int a;
+};
+
+void t4() {
+ // RUN: grep "call void @_ZN1TC1Ev" %t | count 1 &&
+ T *t = new T;
+}
+
+struct T2 {
+ int a;
+ T2(int, int);
+};
+
+void t5() {
+ // RUN: grep "call void @_ZN2T2C1Eii" %t | count 1
+ T2 *t2 = new T2(10, 10);
+}
+
+int *t6() {
+ // Null check.
+ return new (0) int(10);
+}
+
+void t7() {
+ new int();
+}
diff --git a/test/CodeGenCXX/reference-field.cpp b/test/CodeGenCXX/reference-field.cpp
new file mode 100644
index 000000000000..88d4c1f37e6e
--- /dev/null
+++ b/test/CodeGenCXX/reference-field.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-cc -emit-llvm -o - %s -O2 | grep "@_Z1bv"
+
+// Make sure the call to b() doesn't get optimized out.
+extern struct x {char& x,y;}y;
+int b();
+int a() { if (!&y.x) b(); }
diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp
new file mode 100644
index 000000000000..8e1935675766
--- /dev/null
+++ b/test/CodeGenCXX/references.cpp
@@ -0,0 +1,89 @@
+// RUN: clang-cc -verify -emit-llvm -o %t %s
+
+void t1() {
+ extern int& a;
+ int b = a;
+}
+
+void t2(int& a) {
+ int b = a;
+}
+
+int g;
+int& gr = g;
+int& grr = gr;
+void t3() {
+ int b = gr;
+}
+
+// Test reference binding.
+
+struct C { int a; };
+
+void f(const bool&);
+void f(const int&);
+void f(const _Complex int&);
+void f(const C&);
+
+C aggregate_return();
+
+bool& bool_reference_return();
+int& int_reference_return();
+_Complex int& complex_int_reference_return();
+C& aggregate_reference_return();
+
+void test_bool() {
+ bool a = true;
+ f(a);
+
+ f(true);
+
+ bool_reference_return() = true;
+ a = bool_reference_return();
+}
+
+void test_scalar() {
+ int a = 10;
+ f(a);
+
+ struct { int bitfield : 3; } s = { 3 };
+ f(s.bitfield);
+
+ f(10);
+
+ __attribute((vector_size(16))) typedef int vec4;
+ f((vec4){1,2,3,4}[0]);
+
+ int_reference_return() = 10;
+ a = int_reference_return();
+}
+
+void test_complex() {
+ _Complex int a = 10i;
+ f(a);
+
+ f(10i);
+
+ complex_int_reference_return() = 10i;
+ a = complex_int_reference_return();
+}
+
+void test_aggregate() {
+ C c;
+ f(c);
+
+ f(aggregate_return());
+ aggregate_reference_return().a = 10;
+
+ c = aggregate_reference_return();
+}
+
+int& reference_return() {
+ return g;
+}
+
+int reference_decl() {
+ int& a = g;
+ const int& b = 1;
+ return a+b;
+}
diff --git a/test/CodeGenObjC/2008-10-23-invalid-icmp.m b/test/CodeGenObjC/2008-10-23-invalid-icmp.m
new file mode 100644
index 000000000000..2c58b9217675
--- /dev/null
+++ b/test/CodeGenObjC/2008-10-23-invalid-icmp.m
@@ -0,0 +1,7 @@
+// RUN: clang-cc -emit-llvm -o %t %s
+
+@protocol P @end
+
+int f0(id<P> d) {
+ return (d != ((void*) 0));
+}
diff --git a/test/CodeGenObjC/attr-strong.c b/test/CodeGenObjC/attr-strong.c
new file mode 100644
index 000000000000..ca8333449435
--- /dev/null
+++ b/test/CodeGenObjC/attr-strong.c
@@ -0,0 +1,9 @@
+// RUN: clang -emit-llvm -S -o %t %s
+
+struct s0 {
+ void *a;
+};
+struct s0 * __attribute__((objc_gc(strong))) g0;
+void f0(void) {
+ g0->a = 0;
+}
diff --git a/test/CodeGenObjC/bitfield-1.m b/test/CodeGenObjC/bitfield-1.m
new file mode 100644
index 000000000000..06ea91132ef3
--- /dev/null
+++ b/test/CodeGenObjC/bitfield-1.m
@@ -0,0 +1,81 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -fnext-runtime -emit-llvm -o %t %s &&
+// RUN: clang-cc -triple i386-apple-darwin9 -fnext-runtime -emit-llvm -o %t %s &&
+// RUN: clang-cc -triple i386-pc-linux-gnu -emit-llvm -o %t %s
+
+@interface Object
+- (id) alloc;
+- (id) init;
+@end
+
+extern void abort(void);
+
+#define CHECK_IF(expr) if(!(expr)) abort();
+
+@interface Base: Object
+{
+ int full;
+ int full2: 32;
+ int _refs: 8;
+ int field2: 3;
+ unsigned f3: 8;
+ short cc;
+ unsigned g: 16;
+ int r2: 8;
+ int r3: 8;
+ int r4: 2;
+ int r5: 8;
+ char c;
+}
+- (void)setValues;
+@end
+
+@interface Derived: Base
+{
+ char d;
+ int _field3: 6;
+}
+- (void)checkValues;
+@end
+
+@implementation Base
+-(void)setValues {
+ full = 1;
+ full2 = 2;
+ _refs = 3;
+ field2 = 1;
+ f3 = 6;
+ cc = 7;
+ g = 8;
+ r2 = 9;
+ r3 = 10;
+ r4 = 1;
+ r5 = 12;
+ c = 13;
+}
+@end
+
+@implementation Derived
+-(void)checkValues {
+ CHECK_IF(full == 1);
+ CHECK_IF(full2 == 2);
+ CHECK_IF(_refs == 3);
+ CHECK_IF(field2 == 1);
+ CHECK_IF(f3 == 6);
+ CHECK_IF(cc == 7);
+ CHECK_IF(g == 8);
+ CHECK_IF(r2 == 9);
+ CHECK_IF(r3 == 10);
+ CHECK_IF(r4 == 1);
+ CHECK_IF(r5 == 12);
+ CHECK_IF(c == 13);
+}
+@end
+
+int main(void) {
+ Derived *obj = [[Derived alloc] init];
+
+ [obj setValues];
+ [obj checkValues];
+
+ return 0;
+}
diff --git a/test/CodeGenObjC/bitfield-ivar-metadata.m b/test/CodeGenObjC/bitfield-ivar-metadata.m
new file mode 100644
index 000000000000..542a2424caa1
--- /dev/null
+++ b/test/CodeGenObjC/bitfield-ivar-metadata.m
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fnext-runtime -emit-llvm -o %t %s
+
+@interface INTF
+{
+ unsigned ivar1;
+ unsigned ivar2;
+ unsigned char BDIVAR3:1;
+ unsigned char BDIVAR4:1;
+}
+@end
+
+@implementation INTF
+@end
+
+
diff --git a/test/CodeGenObjC/bitfield-ivar-offsets.m b/test/CodeGenObjC/bitfield-ivar-offsets.m
new file mode 100644
index 000000000000..23a09a3a15b8
--- /dev/null
+++ b/test/CodeGenObjC/bitfield-ivar-offsets.m
@@ -0,0 +1,26 @@
+// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
+// RUN: clang-cc -triple x86_64-apple-darwin10 -emit-llvm -o %t %s &&
+// RUN: grep -F '@"OBJC_IVAR_$_I0._b0" = global i64 0, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep -F '@"OBJC_IVAR_$_I0._b1" = global i64 0, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep -F '@"OBJC_IVAR_$_I0._b2" = global i64 1, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep -F '@"OBJC_IVAR_$_I0._x" = global i64 2, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep -F '@"OBJC_IVAR_$_I0._b3" = global i64 4, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep -F '@"OBJC_IVAR_$_I0._y" = global i64 6, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep -F '@"OBJC_IVAR_$_I0._b4" = global i64 7, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep -F '@"OBJC_IVAR_$_I0." = global' %t | count 0 &&
+// RUN: true
+
+@interface I0 {
+ unsigned _b0:4;
+ unsigned _b1:5;
+ unsigned _b2:5;
+ char _x;
+ unsigned _b3:9;
+ char _y;
+ char _b4:3;
+ char : 0;
+}
+@end
+
+@implementation I0
+@end
diff --git a/test/CodeGenObjC/blocks-1.m b/test/CodeGenObjC/blocks-1.m
new file mode 100644
index 000000000000..2b4f8faeb82e
--- /dev/null
+++ b/test/CodeGenObjC/blocks-1.m
@@ -0,0 +1,33 @@
+// RUN: clang-cc %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10 &&
+// RUN: grep "_Block_object_dispose" %t | count 6 &&
+// RUN: grep "__copy_helper_block_" %t | count 4 &&
+// RUN: grep "__destroy_helper_block_" %t | count 4 &&
+// RUN: grep "__Block_byref_id_object_copy_" %t | count 2 &&
+// RUN: grep "__Block_byref_id_object_dispose_" %t | count 2 &&
+// RUN: grep "i32 135)" %t | count 0 &&
+// RUN: grep "_Block_object_assign" %t | count 4 &&
+// RUN: grep "objc_read_weak" %t | count 2 &&
+// RUN: grep "objc_assign_weak" %t | count 3
+
+@interface NSDictionary @end
+
+void test1(NSDictionary * dict) {
+ ^{ (void)dict; }();
+}
+
+@interface D
+@end
+
+void foo() {
+ __block __weak D *weakSelf;
+ D *l;
+ l = weakSelf;
+ weakSelf = l;
+}
+
+void (^__weak b)(void);
+
+void test2() {
+ __block int i = 0;
+ b = ^ { ++i; };
+}
diff --git a/test/CodeGenObjC/blocks-2.m b/test/CodeGenObjC/blocks-2.m
new file mode 100644
index 000000000000..a4d8bfa6b7fc
--- /dev/null
+++ b/test/CodeGenObjC/blocks-2.m
@@ -0,0 +1,11 @@
+// RUN: clang-cc %s -emit-llvm -o %t -fobjc-gc -fblocks -triple i386-apple-darwin10 &&
+// RUN: grep "objc_assign_strongCast" %t | count 2 &&
+// RUN: true
+
+// This should generate a strong cast.
+
+id test3(id x) {
+ __block id result;
+ ^{ result = x; }();
+ return result;
+}
diff --git a/test/CodeGenObjC/blocks.m b/test/CodeGenObjC/blocks.m
new file mode 100644
index 000000000000..18c455ad9ebe
--- /dev/null
+++ b/test/CodeGenObjC/blocks.m
@@ -0,0 +1,36 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm -fblocks -o %t %s &&
+// rdar://6676764
+
+struct S {
+ void (^F)(struct S*);
+} P;
+
+
+@interface T
+
+ - (int)foo: (T (^)(T*)) x;
+@end
+
+void foo(T *P) {
+ [P foo: 0];
+}
+
+@interface A
+-(void) im0;
+@end
+
+// RUN: grep 'define internal i32 @"__-\[A im0\]_block_invoke_"' %t &&
+@implementation A
+-(void) im0 {
+ (void) ^{ return 1; }();
+}
+@end
+
+@interface B : A @end
+@implementation B
+-(void) im1 {
+ ^(void) { [super im0]; }();
+}
+@end
+
+// RUN: true
diff --git a/test/CodeGenObjC/category-super-class-meth.m b/test/CodeGenObjC/category-super-class-meth.m
new file mode 100644
index 000000000000..95d8b3103c9f
--- /dev/null
+++ b/test/CodeGenObjC/category-super-class-meth.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fnext-runtime -emit-llvm -o %t %s
+
+@interface BASE
++ (int) BaseMeth;
+@end
+
+@interface Child: BASE
+@end
+
+@interface Child (Categ)
++ (int) flushCache2;
+@end
+
+@implementation Child @end
+
+@implementation Child (Categ)
++ (int) flushCache2 { [super BaseMeth]; }
+@end
+
diff --git a/test/CodeGenObjC/class-getter-dotsyntax.m b/test/CodeGenObjC/class-getter-dotsyntax.m
new file mode 100644
index 000000000000..3c82f78d08b5
--- /dev/null
+++ b/test/CodeGenObjC/class-getter-dotsyntax.m
@@ -0,0 +1,21 @@
+// RUN: clang-cc -fnext-runtime -emit-llvm -o %t %s
+
+@interface Test { }
++ (Test *)crash;
++ (void)setCrash: (int)value;
+@end
+
+@implementation Test
+static int _value;
+- (void)cachesPath
+{
+ static Test *cachesPath;
+
+ if (!cachesPath) {
+ Test *crash = Test.crash;
+ }
+}
++ (Test *)crash{ return 0; }
++ (void)setCrash: (int)value{ _value = value; }
+@end
+
diff --git a/test/CodeGenObjC/class-obj-hidden-visibility.m b/test/CodeGenObjC/class-obj-hidden-visibility.m
new file mode 100644
index 000000000000..fc4ac12b1836
--- /dev/null
+++ b/test/CodeGenObjC/class-obj-hidden-visibility.m
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fvisibility=hidden -triple x86_64-apple-darwin10 -S -o - %s | grep -e "private_extern _OBJC_" | count 2
+
+@interface INTF @end
+
+@implementation INTF @end
+
diff --git a/test/CodeGenObjC/class-type.m b/test/CodeGenObjC/class-type.m
new file mode 100644
index 000000000000..794d9a355794
--- /dev/null
+++ b/test/CodeGenObjC/class-type.m
@@ -0,0 +1,36 @@
+// RUN: clang-cc -triple x86_64-unknown-unknown -emit-llvm -o - %s &&
+// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm -o - %s &&
+// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm -o - %s
+
+
+@interface I0 {
+ struct { int a; } a;
+}
+@end
+
+@class I2;
+
+@interface I1 {
+ I2 *_imageBrowser;
+}
+@end
+
+@implementation I1
+@end
+
+@interface I2 : I0
+@end
+
+@implementation I2
+@end
+
+
+// Implementations without interface declarations.
+// rdar://6804402
+@class foo;
+@implementation foo
+@end
+
+@implementation bar
+@end
+
diff --git a/test/CodeGenObjC/compatibility-alias.m b/test/CodeGenObjC/compatibility-alias.m
new file mode 100644
index 000000000000..11e5a27ab713
--- /dev/null
+++ b/test/CodeGenObjC/compatibility-alias.m
@@ -0,0 +1,8 @@
+// RUN: clang-cc -emit-llvm -o %t %s
+
+@interface Int1 @end
+
+typedef Int1 Int1Typedef;
+@compatibility_alias Int1Alias Int1Typedef;
+
+@implementation Int1Alias @end
diff --git a/test/CodeGenObjC/constant-strings.m b/test/CodeGenObjC/constant-strings.m
new file mode 100644
index 000000000000..d4fefd903653
--- /dev/null
+++ b/test/CodeGenObjC/constant-strings.m
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fnext-runtime -emit-llvm -o %t %s
+
+id a = @"Hello World!";
+
diff --git a/test/CodeGenObjC/continuation-class.m b/test/CodeGenObjC/continuation-class.m
new file mode 100644
index 000000000000..925f3cd0c50d
--- /dev/null
+++ b/test/CodeGenObjC/continuation-class.m
@@ -0,0 +1,35 @@
+// RUN: clang-cc -fnext-runtime --emit-llvm -o %t %s
+
+@interface Object
+- (id)new;
+@end
+
+@interface ReadOnly : Object
+{
+ int _object;
+ int _Anotherobject;
+}
+@property(readonly) int object;
+@property(readonly) int Anotherobject;
+@end
+
+@interface ReadOnly ()
+@property(readwrite) int object;
+@property(readwrite, setter = myAnotherobjectSetter:) int Anotherobject;
+@end
+
+@implementation ReadOnly
+@synthesize object = _object;
+@synthesize Anotherobject = _Anotherobject;
+- (void) myAnotherobjectSetter : (int)val {
+ _Anotherobject = val;
+}
+@end
+
+int main(int argc, char **argv) {
+ ReadOnly *test = [ReadOnly new];
+ test.object = 12345;
+ test.Anotherobject = 200;
+ return test.object - 12345 + test.Anotherobject - 200;
+}
+
diff --git a/test/CodeGenObjC/debug-info.m b/test/CodeGenObjC/debug-info.m
new file mode 100644
index 000000000000..9c461ba68fb4
--- /dev/null
+++ b/test/CodeGenObjC/debug-info.m
@@ -0,0 +1,18 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -g -emit-llvm -o %t %s &&
+// RUN: grep '@.str3 = internal constant \[8 x i8\] c"-\[A m0\]\\00"' %t &&
+// RUN: grep '@.str4 = internal constant \[9 x i8\] c"\\01-\[A m0\]\\00"' %t &&
+// RUN: grep '@llvm.dbg.subprogram = .* @.str3, .* @.str3, .* @.str4,' %t &&
+// RUN: grep '@llvm.dbg.composite.* = .* i32 15, i64 0, i64 8, .* i32 16' %t &&
+// RUN: true
+
+
+
+
+
+
+
+
+@interface A @end
+@implementation A // Line 15
+-(void) m0 {}
+@end
diff --git a/test/CodeGenObjC/dot-syntax-1.m b/test/CodeGenObjC/dot-syntax-1.m
new file mode 100644
index 000000000000..6c4dcbbef0dc
--- /dev/null
+++ b/test/CodeGenObjC/dot-syntax-1.m
@@ -0,0 +1,264 @@
+// RUN: clang-cc -fnext-runtime --emit-llvm -o %t %s
+
+#include <stdio.h>
+
+@interface Root
+-(id) alloc;
+-(id) init;
+@end
+
+// Property above methods...
+
+@interface Top0 : Root
+@property(getter=_getX,setter=_setX:) int x;
+@end
+
+@interface Bot0 : Top0
+-(int) x;
+-(void) setX: (int) arg;
+@end
+
+@implementation Top0
+-(int) _getX {
+ printf("-[ Top0 _getX ]\n");
+ return 0;
+}
+-(void) _setX: (int) arg {
+ printf("-[ Top0 _setX: %d ]\n", arg);
+}
+@end
+
+@implementation Bot0
+-(int) x {
+ printf("-[ Bot0 _getX ]\n");
+ return 0;
+}
+-(void) setX: (int) arg {
+ printf("-[ Bot0 _setX: %d ]\n", arg);
+}
+@end
+
+// Methods above property...
+
+@interface Top1 : Root
+-(int) x;
+-(void) setX: (int) arg;
+@end
+
+@interface Bot1 : Top1
+@property(getter=_getX,setter=_setX:) int x;
+@end
+
+@implementation Top1
+-(int) x {
+ printf("-[ Top1 x ]\n");
+ return 0;
+}
+-(void) setX: (int) arg {
+ printf("-[ Top1 setX: %d ]\n", arg);
+}
+@end
+
+@implementation Bot1
+-(int) _getX {
+ printf("-[ Bot1 _getX ]\n");
+ return 0;
+}
+-(void) _setX: (int) arg {
+ printf("-[ Bot1 _setX: %d ]\n", arg);
+}
+@end
+
+// Mixed setter & getter (variant 1)
+
+@interface Top2 : Root
+-(int) x;
+-(void) _setX: (int) arg;
+@end
+
+@interface Bot2 : Top2
+@property(getter=_getX,setter=_setX:) int x;
+@end
+
+@implementation Top2
+-(int) x {
+ printf("-[ Top2 x ]\n");
+ return 0;
+}
+-(void) _setX: (int) arg {
+ printf("-[ Top2 _setX: %d ]\n", arg);
+}
+@end
+
+@implementation Bot2
+-(int) _getX {
+ printf("-[ Bot2 _getX ]\n");
+ return 0;
+}
+-(void) setX: (int) arg {
+ printf("-[ Bot2 setX: %d ]\n", arg);
+}
+@end
+
+// Mixed setter & getter (variant 2)
+
+@interface Top3 : Root
+-(int) _getX;
+-(void) setX: (int) arg;
+@end
+
+@interface Bot3 : Top3
+@property(getter=_getX,setter=_setX:) int x;
+@end
+
+@implementation Top3
+-(int) _getX {
+ printf("-[ Top3 _getX ]\n");
+ return 0;
+}
+-(void) setX: (int) arg {
+ printf("-[ Top3 setX: %d ]\n", arg);
+}
+@end
+
+@implementation Bot3
+-(int) x {
+ printf("-[ Bot3 x ]\n");
+ return 0;
+}
+-(void) _setX: (int) arg {
+ printf("-[ Bot3 _setX: %d ]\n", arg);
+}
+@end
+
+// Mixed setter & getter (variant 3)
+
+@interface Top4 : Root
+@property(getter=_getX,setter=_setX:) int x;
+@end
+
+@interface Bot4 : Top4
+-(int) _getX;
+-(void) setX: (int) arg;
+@end
+
+@implementation Top4
+-(int) x {
+ printf("-[ Top4 x ]\n");
+ return 0;
+}
+-(void) _setX: (int) arg {
+ printf("-[ Top4 _setX: %d ]\n", arg);
+}
+@end
+
+@implementation Bot4
+-(int) _getX {
+ printf("-[ Bot4 _getX ]\n");
+ return 0;
+}
+-(void) setX: (int) arg {
+ printf("-[ Bot4 setX: %d ]\n", arg);
+}
+@end
+
+// Mixed setter & getter (variant 4)
+
+@interface Top5 : Root
+@property(getter=_getX,setter=_setX:) int x;
+@end
+
+@interface Bot5 : Top5
+-(int) x;
+-(void) _setX: (int) arg;
+@end
+
+@implementation Top5
+-(int) _getX {
+ printf("-[ Top5 _getX ]\n");
+ return 0;
+}
+-(void) setX: (int) arg {
+ printf("-[ Top5 setX: %d ]\n", arg);
+}
+@end
+
+@implementation Bot5
+-(int) x {
+ printf("-[ Bot5 x ]\n");
+ return 0;
+}
+-(void) _setX: (int) arg {
+ printf("-[ Bot5 _setX: %d ]\n", arg);
+}
+@end
+
+// Mixed level calls (variant 1)
+
+@interface Top6 : Root
+-(int) x;
+@end
+
+@interface Bot6 : Top6
+-(void) setX: (int) arg;
+@end
+
+@implementation Top6
+-(int) x {
+ printf("-[ Top6 x ]\n");
+ return 0;
+}
+@end
+
+@implementation Bot6
+-(void) setX: (int) arg {
+ printf("-[ Bot5 setX: %d ]\n", arg);
+}
+@end
+
+// Mixed level calls (variant 1)
+
+@interface Top7 : Root
+-(void) setX: (int) arg;
+@end
+
+@interface Bot7 : Top7
+-(int) x;
+@end
+
+@implementation Top7
+-(void) setX: (int) arg {
+ printf("-[ Top7 setX: %d ]\n", arg);
+}
+@end
+
+@implementation Bot7
+-(int) x {
+ printf("-[ Bot7 x ]\n");
+ return 0;
+}
+@end
+
+//
+
+// FIXME: Two more (thats it?) interesting cases. Method access on
+// getter w/o setter and method access on setter w/o getter.
+
+int main() {
+#define test(N) { \
+ Bot##N *ob = [[Bot##N alloc] init]; \
+ int x = ob.x; \
+ ob.x = 10; }
+
+ test(0);
+ test(1);
+ test(2);
+ test(3);
+ test(4);
+ test(5);
+ // test(6);
+ // test(7);
+
+ return 0;
+}
+
diff --git a/test/CodeGenObjC/dot-syntax.m b/test/CodeGenObjC/dot-syntax.m
new file mode 100644
index 000000000000..68c8ad0b7580
--- /dev/null
+++ b/test/CodeGenObjC/dot-syntax.m
@@ -0,0 +1,98 @@
+// RUN: clang-cc -fnext-runtime --emit-llvm -o %t %s
+
+#include <stdio.h>
+
+@interface Root
+-(id) alloc;
+-(id) init;
+@end
+
+typedef struct {
+ float x, y, z[2];
+} S;
+
+@interface A : Root {
+ int myX;
+ // __complex myY;
+ S myZ;
+}
+
+@property int x;
+//@property __complex int y;
+@property S z;
+@end
+
+@implementation A
+-(int) x {
+ printf("-[A x] = %d\n", myX);
+ return myX;
+}
+-(void) setX: (int) arg {
+ myX = arg;
+ printf("-[A setX: %d]\n", myX);
+}
+
+// FIXME: Add back
+#if 0
+-(__complex int) y {
+ printf("-[A y] = (%d, %d)\n", __real myY, __imag myY);
+ return myY;
+}
+-(void) setY: (__complex int) arg {
+ myY = arg;
+ printf("-[A setY: (%d, %d)]\n", __real myY, __imag myY);
+}
+#endif
+
+-(S) z {
+ printf("-[A z] = { %f, %f, { %f, %f } }\n",
+ myZ.x, myZ.y, myZ.z[0], myZ.z[1]);
+ return myZ;
+}
+-(void) setZ: (S) arg {
+ myZ = arg;
+ printf("-[A setZ: { %f, %f, { %f, %f } } ]\n",
+ myZ.x, myZ.y, myZ.z[0], myZ.z[1]);
+}
+
+@end
+
+int main() {
+#define SWAP(T,a,b) { T a_tmp = a; a = b; b = a_tmp; }
+ A *a = [[A alloc] init];
+ A *b = [[A alloc] init];
+ int a0 = 23;
+ // __complex a1 = 25 + 10i;
+ S a2 = { 246, 458, {275, 12} };
+ int b0 = 42673;
+ // __complex b1 = 15 + 13i;
+ S b2 = { 26, 2, {367, 13} };
+
+ a.x = a0;
+ // a.y = a1;
+ a.z = a2;
+
+ a.x += a0;
+ // a.y += a1;
+ // Yay, no compound assign of structures. A GCC extension in the
+ // works, perhaps?
+
+ b.x = b0;
+ // b.y = b1;
+ b.z = b2;
+
+ int x0 = (b.x = b0);
+ printf("(b.x = b0): %d\n", x0);
+
+ // int x1 = __real (b.y = b1);
+ // printf("__real (b.y = b1) = %d\n", x1);
+
+ float x2 = (b.z = b2).x;
+ printf("(b.z = b2).x: %f\n", x2);
+
+ SWAP(int, a.x, b.x);
+ // SWAP(__complex int, a.y, b.y);
+ SWAP(S, a.z, b.z);
+
+ return 0;
+}
diff --git a/test/CodeGenObjC/encode-test-1.m b/test/CodeGenObjC/encode-test-1.m
new file mode 100644
index 000000000000..b4f3b0f9c33d
--- /dev/null
+++ b/test/CodeGenObjC/encode-test-1.m
@@ -0,0 +1,36 @@
+// RUN: clang-cc -triple=i686-apple-darwin9 -fnext-runtime -emit-llvm -o %t %s &&
+// RUN: grep -e "{Base=b2b3b4b5}" %t | count 1 &&
+// RUN: grep -e "{Derived=b2b3b4b5b5b4b3}" %t | count 1
+
+enum Enum { one, two, three, four };
+
+@interface Base {
+ unsigned a: 2;
+ int b: 3;
+ enum Enum c: 4;
+ unsigned d: 5;
+}
+@end
+
+@interface Derived: Base {
+ signed e: 5;
+ int f: 4;
+ enum Enum g: 3;
+}
+@end
+
+@implementation Base @end
+
+@implementation Derived @end
+
+int main(void)
+{
+
+ const char *en = @encode(Base);
+// printf ("%s\n", en);
+
+ const char *ed = @encode(Derived);
+ // printf ("%s\n", ed);
+
+ return 0;
+}
diff --git a/test/CodeGenObjC/encode-test-2.m b/test/CodeGenObjC/encode-test-2.m
new file mode 100644
index 000000000000..6901168b1d09
--- /dev/null
+++ b/test/CodeGenObjC/encode-test-2.m
@@ -0,0 +1,29 @@
+// RUN: clang-cc -triple=i686-apple-darwin9 -fnext-runtime -emit-llvm -o %t %s &&
+// RUN: grep -e "@\\\22<X>\\\22" %t &&
+// RUN: grep -e "@\\\22<X><Y>\\\22" %t &&
+// RUN: grep -e "@\\\22<X><Y><Z>\\\22" %t &&
+// RUN: grep -e "@\\\22Foo<X><Y><Z>\\\22" %t &&
+// RUN: grep -e "{Intf=@@@@}" %t
+
+@protocol X, Y, Z;
+@class Foo;
+
+@protocol Proto
+@end
+
+@interface Intf <Proto>
+{
+id <X> IVAR_x;
+id <X, Y> IVAR_xy;
+id <X, Y, Z> IVAR_xyz;
+Foo <X, Y, Z> *IVAR_Fooxyz;
+}
+@end
+
+@implementation Intf
+@end
+
+int main()
+{
+ const char * en = @encode(Intf);
+}
diff --git a/test/CodeGenObjC/encode-test-3.m b/test/CodeGenObjC/encode-test-3.m
new file mode 100644
index 000000000000..116e825e32a0
--- /dev/null
+++ b/test/CodeGenObjC/encode-test-3.m
@@ -0,0 +1,21 @@
+// RUN: clang-cc -triple=i686-apple-darwin9 -fnext-runtime -emit-llvm -o %t %s &&
+// RUN: grep -e "\^i" %t | count 1 &&
+// RUN: grep -e "\[0i\]" %t | count 1
+
+int main() {
+ int n;
+
+ const char * inc = @encode(int[]);
+ const char * vla = @encode(int[n]);
+}
+
+// PR3648
+int a[sizeof(@encode(int)) == 2 ? 1 : -1]; // Type is char[2]
+const char *B = @encode(int);
+char (*c)[2] = &@encode(int); // @encode is an lvalue
+
+char d[] = @encode(int); // infer size.
+char e[1] = @encode(int); // truncate
+char f[2] = @encode(int); // fits
+char g[3] = @encode(int); // zero fill
+
diff --git a/test/CodeGenObjC/encode-test-4.m b/test/CodeGenObjC/encode-test-4.m
new file mode 100644
index 000000000000..90b300200a06
--- /dev/null
+++ b/test/CodeGenObjC/encode-test-4.m
@@ -0,0 +1,5 @@
+// RUN: clang-cc -emit-llvm -o - %s -O2 | grep "ret i32 1"
+
+int a() {
+ return @encode(int) == @encode(int);
+}
diff --git a/test/CodeGenObjC/encode-test-5.m b/test/CodeGenObjC/encode-test-5.m
new file mode 100644
index 000000000000..a76b071e7fed
--- /dev/null
+++ b/test/CodeGenObjC/encode-test-5.m
@@ -0,0 +1,16 @@
+// RUN: clang-cc -triple=x86_64-apple-darwin9 -fnext-runtime -emit-llvm -o %t %s &&
+
+// RUN: grep ji %t | count 1 &&
+char *a = @encode(_Complex int);
+
+// RUN: grep jf %t | count 1 &&
+char *b = @encode(_Complex float);
+
+// RUN: grep jd %t | count 1 &&
+char *c = @encode(_Complex double);
+
+// RUN: grep "t.00" %t | count 1 &&
+char *e = @encode(__int128_t);
+
+// RUN: grep "T.00" %t | count 1
+char *f = @encode(__uint128_t);
diff --git a/test/CodeGenObjC/encode-test.m b/test/CodeGenObjC/encode-test.m
new file mode 100644
index 000000000000..ca54a51c3b1c
--- /dev/null
+++ b/test/CodeGenObjC/encode-test.m
@@ -0,0 +1,94 @@
+// RUN: clang-cc -triple=i686-apple-darwin9 -fnext-runtime -emit-llvm -o %t %s &&
+// RUN: grep -e "\^{Innermost=CC}" %t | count 1 &&
+// RUN: grep -e "{Derived=#ib32b8b3b8sb16b8b8b2b8ccb6}" %t | count 1 &&
+// RUN: grep -e "{B1=#@c}" %t | count 1 &&
+// RUN: grep -e "v12@0:4\[3\[4@]]8" %t | count 1 &&
+// RUN: grep -e "r\^{S=i}" %t | count 1 &&
+// RUN: grep -e "\^{Object=#}" %t | count 1
+
+@class Int1;
+
+struct Innermost {
+ unsigned char a, b;
+};
+
+@interface Int1 {
+ signed char a, b;
+ struct Innermost *innermost;
+}
+@end
+
+@implementation Int1
+@end
+
+@interface Base
+{
+ struct objc_class *isa;
+ int full;
+ int full2: 32;
+ int _refs: 8;
+ int field2: 3;
+ unsigned f3: 8;
+ short cc;
+ unsigned g: 16;
+ int r2: 8;
+ int r3: 8;
+ int r4: 2;
+ int r5: 8;
+ char c;
+}
+@end
+
+@interface Derived: Base
+{
+ char d;
+ int _field3: 6;
+}
+@end
+
+@implementation Base
+@end
+
+@implementation Derived
+@end
+
+@interface B1
+{
+ struct objc_class *isa;
+ Int1 *sBase;
+ char c;
+}
+@end
+
+@implementation B1
+@end
+
+@interface Test
+{
+ int ivar;
+}
+-(void) test3: (Test* [3] [4])b ;
+@end
+
+@implementation Test
+-(void) test3: (Test* [3] [4])b {}
+@end
+
+struct S { int iS; };
+
+@interface Object
+{
+ Class isa;
+}
+@end
+typedef Object MyObj;
+
+int main()
+{
+ const char *en = @encode(Derived);
+ const char *eb = @encode(B1);
+ const char *es = @encode(const struct S *);
+ const char *ec = @encode(const struct S);
+ const char *ee = @encode(MyObj *const);
+}
+
diff --git a/test/CodeGenObjC/forward-class-impl-metadata.m b/test/CodeGenObjC/forward-class-impl-metadata.m
new file mode 100644
index 000000000000..b8ce10aaa510
--- /dev/null
+++ b/test/CodeGenObjC/forward-class-impl-metadata.m
@@ -0,0 +1,41 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -emit-llvm -o %t %s
+
+@interface BASE {
+@private
+ void* _reserved;
+}
+@end
+
+@class PVR;
+
+@interface PVRHandldler
+{
+ PVR *_imageBrowser;
+}
+@end
+
+@implementation PVRHandldler @end
+
+
+@interface PVR : BASE
+@end
+
+@implementation PVR
+@end
+
+// Reopen of an interface after use.
+
+@interface A {
+@public
+ int x;
+}
+@property int p0;
+@end
+
+int f0(A *a) {
+ return a.p0;
+}
+
+@implementation A
+@synthesize p0 = _p0;
+@end
diff --git a/test/CodeGenObjC/hidden-synthesized-ivar.m b/test/CodeGenObjC/hidden-synthesized-ivar.m
new file mode 100644
index 000000000000..50a87cb2f453
--- /dev/null
+++ b/test/CodeGenObjC/hidden-synthesized-ivar.m
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fvisibility=hidden -triple x86_64-apple-darwin10 -S -o - %s | grep -e "private_extern _OBJC_IVAR_"
+@interface I
+{
+ int P;
+}
+
+@property int P;
+@end
+
+@implementation I
+@synthesize P;
+@end
+
diff --git a/test/CodeGenObjC/hidden.m b/test/CodeGenObjC/hidden.m
new file mode 100644
index 000000000000..6b86ca0581cc
--- /dev/null
+++ b/test/CodeGenObjC/hidden.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fnext-runtime --emit-llvm -o %t %s
+
+__attribute__((visibility("hidden")))
+@interface Hidden
++(void) bar;
+@end
+
+@implementation Hidden
++(void) bar {}
+@end
+
+__attribute__((visibility("default")))
+@interface Default
++(void) bar;
+@end
+
+@implementation Default
++(void) bar {}
+@end
diff --git a/test/CodeGenObjC/image-info.m b/test/CodeGenObjC/image-info.m
new file mode 100644
index 000000000000..e8650129e3f7
--- /dev/null
+++ b/test/CodeGenObjC/image-info.m
@@ -0,0 +1,2 @@
+// RUN: clang-cc -triple x86_64-apple-darwin-10 -emit-llvm -o %t %s &&
+// RUN: grep -F '@"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__OBJC, __image_info,regular"' %t
diff --git a/test/CodeGenObjC/implicit-objc_msgSend.m b/test/CodeGenObjC/implicit-objc_msgSend.m
new file mode 100644
index 000000000000..4511cca338b2
--- /dev/null
+++ b/test/CodeGenObjC/implicit-objc_msgSend.m
@@ -0,0 +1,7 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm -o %t %s &&
+// RUN: grep -F 'declare i8* @objc_msgSend(...)' %t
+
+typedef struct objc_selector *SEL;
+id f0(id x, SEL s) {
+ return objc_msgSend(x, s);
+}
diff --git a/test/CodeGenObjC/implicit-property.m b/test/CodeGenObjC/implicit-property.m
new file mode 100644
index 000000000000..206d496252d8
--- /dev/null
+++ b/test/CodeGenObjC/implicit-property.m
@@ -0,0 +1,16 @@
+// RUN: clang-cc -emit-llvm -triple=i686-apple-darwin8 -o %t %s
+// RUNX: clang-cc -emit-llvm -o %t %s
+
+@interface A
+ -(void) setOk:(int)arg;
+ -(int) ok;
+
+ -(void) setX:(int)arg;
+ -(int) x;
+@end
+
+void f0(A *a) {
+ a.x = 1;
+ a.ok = a.x;
+}
+
diff --git a/test/CodeGenObjC/interface-layout-64.m b/test/CodeGenObjC/interface-layout-64.m
new file mode 100644
index 000000000000..13d6a8770f65
--- /dev/null
+++ b/test/CodeGenObjC/interface-layout-64.m
@@ -0,0 +1,124 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -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_const", align 8' %t &&
+// RUN: grep '@"OBJC_IVAR_$_I3._iv3" = global i64 12, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"OBJC_IVAR_$_I4._iv4" = global i64 13, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"OBJC_IVAR_$_I5._iv5" = global i64 14, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"OBJC_IVAR_$_I5._iv6_synth" = global i64 16, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"OBJC_IVAR_$_I5._iv7_synth" = global i64 20, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"OBJC_IVAR_$_I6.iv0" = global i64 0, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"OBJC_IVAR_$_I8.b" = global i64 8, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"OBJC_IVAR_$_I9.iv0" = global i64 0, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"OBJC_IVAR_$_I10.iv1" = global i64 4, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"OBJC_IVAR_$_I12.iv2" = global i64 8, section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '_OBJC_CLASS_RO_$_I3" = internal global .* { i32 0, i32 8, i32 13, .*' %t &&
+// RUN: grep '_OBJC_CLASS_RO_$_I4" = internal global .* { i32 0, i32 13, i32 14, .*' %t &&
+// RUN: grep '_OBJC_CLASS_RO_$_I5" = internal global .* { i32 0, i32 14, i32 24, .*' %t &&
+// RUN: grep '_OBJC_CLASS_RO_$_I6" = internal global .* { i32 2, i32 0, i32 1, .*' %t &&
+// RUN: grep '_OBJC_CLASS_RO_$_I8" = internal global .* { i32 0, i32 8, i32 16, .*' %t &&
+// RUN: grep '_OBJC_CLASS_RO_$_I9" = internal global .* { i32 2, i32 0, i32 4, .*' %t &&
+// RUN: grep '_OBJC_CLASS_RO_$_I10" = internal global .* { i32 0, i32 4, i32 5, .*' %t &&
+// RUN: grep '_OBJC_CLASS_RO_$_I11" = internal global .* { i32 0, i32 5, i32 5, .*' %t &&
+// RUN: grep '_OBJC_CLASS_RO_$_I12" = internal global .* { i32 0, i32 8, i32 12, .*' %t &&
+
+// RUN: true
+
+/*
+ Compare to:
+ gcc -m64 -S -o - interface-layout-64.m | grep '^_OBJC_IVAR_$_*.*' -A 1
+ and
+ gcc -m64 -S -o - interface-layout-64.m | grep '^l.*_CLASS_RO_$_I[0-9]*' -A 3
+ */
+
+struct s0 {
+ double x;
+};
+
+@interface I2 {
+ struct s0 _iv1;
+}
+@end
+
+@interface I3 : I2 {
+ unsigned int _iv2 :1;
+ unsigned : 0;
+ unsigned int _iv3 : 3;
+}
+@end
+
+@interface I4 : I3 {
+ char _iv4;
+}
+@end
+
+@interface I5 : I4 {
+ char _iv5;
+}
+
+@property int prop0;
+@end
+
+@implementation I3
+@end
+
+@implementation I4
+@end
+
+@interface I5 ()
+@property int prop1;
+@property char prop2;
+@end
+
+@implementation I5
+@synthesize prop0 = _iv6_synth;
+@synthesize prop1 = _iv7_synth;
+@synthesize prop2 = _iv5;
+@end
+
+// The size rounds up to the next available byte.
+@interface I6 {
+ unsigned iv0 : 2;
+}
+@end
+@implementation I6
+@end
+
+// The start of the subclass includes padding for its own alignment.
+@interface I7 {
+ char a;
+}
+@end
+@interface I8 : I7 {
+ double b;
+}
+@end
+@implementation I8
+@end
+
+// Padding bit-fields
+@interface I9 {
+ unsigned iv0 : 2;
+ unsigned : 0;
+}
+@end
+@implementation I9
+@end
+@interface I10 : I9 {
+ unsigned iv1 : 2;
+}
+@end
+@implementation I10
+@end
+
+// Empty structures
+@interface I11 : I10
+@end
+@implementation I11
+@end
+@interface I12 : I11 {
+ unsigned iv2;
+}
+@end
+@implementation I12
+@end
diff --git a/test/CodeGenObjC/interface.m b/test/CodeGenObjC/interface.m
new file mode 100644
index 000000000000..d506e88ee7c9
--- /dev/null
+++ b/test/CodeGenObjC/interface.m
@@ -0,0 +1,34 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -O3 -emit-llvm -o %t %s &&
+// RUN: grep 'ret i32 385' %t
+
+void *alloca();
+
+@interface I0 {
+@public
+ int iv0;
+ int iv1;
+ int iv2;
+}
+@end
+
+static int f0(I0 *a0) {
+ return (*(a0 + 2)).iv0;
+}
+
+static int f1(I0 *a0) {
+ return a0[2].iv1;
+}
+
+static int f2(I0 *a0) {
+ return (*(a0 - 1)).iv2;
+}
+
+int g0(void) {
+ I0 *a = alloca(sizeof(*a) * 4);
+ a[2].iv0 = 5;
+ a[2].iv1 = 7;
+ a[2].iv2 = 11;
+ return f0(a) * f1(a) * f2(&a[3]);
+}
+
+
diff --git a/test/CodeGenObjC/ivar-layout-64.m b/test/CodeGenObjC/ivar-layout-64.m
new file mode 100644
index 000000000000..7301e168218e
--- /dev/null
+++ b/test/CodeGenObjC/ivar-layout-64.m
@@ -0,0 +1,89 @@
+// RUNX: llvm-gcc -m64 -fobjc-gc -emit-llvm -S -o %t %s &&
+// RUN: clang-cc -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s &&
+// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"A\\00"' %t &&
+// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\11q\\10\\00"' %t &&
+// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"!q\\00"' %t &&
+// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\01\\14\\00"' %t &&
+// RUN: true
+
+/*
+
+Here is a handy command for looking at llvm-gcc's output:
+llvm-gcc -m64 -fobjc-gc -emit-llvm -S -o - ivar-layout-64.m | \
+ grep 'OBJC_CLASS_NAME.* =.*global' | \
+ sed -e 's#, section.*# ...#' | \
+ sed -e 's#_[0-9]*"#_NNN#' | \
+ sort
+
+*/
+
+@interface B @end
+
+@interface A {
+ struct s0 {
+ int f0;
+ int f1;
+ } f0;
+ id f1;
+__weak B *f2;
+ int f3 : 5;
+ struct s1 {
+ int *f0;
+ int *f1;
+ } f4[2][1];
+}
+@end
+
+@interface C : A
+@property int p3;
+@end
+
+@implementation C
+@synthesize p3 = _p3;
+@end
+
+@interface A()
+@property int p0;
+@property (assign) __strong id p1;
+@property (assign) __weak id p2;
+@end
+
+// FIXME: Check layout for this class, once it is clear what the right
+// answer is.
+@implementation A
+@synthesize p0 = _p0;
+@synthesize p1 = _p1;
+@synthesize p2 = _p2;
+@end
+
+@interface D : A
+@property int p3;
+@end
+
+// FIXME: Check layout for this class, once it is clear what the right
+// answer is.
+@implementation D
+@synthesize p3 = _p3;
+@end
+
+typedef unsigned short UInt16;
+
+
+typedef signed char BOOL;
+typedef unsigned int FSCatalogInfoBitmap;
+
+@interface NSFileLocationComponent {
+ @private
+
+ id _specifierOrStandardizedPath;
+ BOOL _carbonCatalogInfoAndNameAreValid;
+ FSCatalogInfoBitmap _carbonCatalogInfoMask;
+ id _name;
+ id _containerComponent;
+ id _presentableName;
+ id _iconAsAttributedString;
+}
+@end
+
+@implementation NSFileLocationComponent @end
+
diff --git a/test/CodeGenObjC/ivars.m b/test/CodeGenObjC/ivars.m
new file mode 100644
index 000000000000..327b628532e1
--- /dev/null
+++ b/test/CodeGenObjC/ivars.m
@@ -0,0 +1,14 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm -o - %s &&
+// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm -o - %s
+
+// rdar://6800926
+@interface ITF {
+@public
+ unsigned field :1 ;
+ _Bool boolfield :1 ;
+}
+@end
+
+void foo(ITF *P) {
+ P->boolfield = 1;
+}
diff --git a/test/CodeGenObjC/link-errors.m b/test/CodeGenObjC/link-errors.m
new file mode 100644
index 000000000000..b50d93993fc8
--- /dev/null
+++ b/test/CodeGenObjC/link-errors.m
@@ -0,0 +1,39 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -fnext-runtime -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-cc -triple i386-apple-darwin9 -DWITH_IMPL -fnext-runtime -emit-llvm -o %t %s &&
+// RUN: grep '.lazy_reference .objc_class_name_Root' %t | count 1
+
+@interface Root
+-(id) alloc;
+-(id) init;
+@end
+
+@protocol P;
+
+@interface A : Root
+@end
+
+@interface A (Category)
++(void) foo;
+@end
+
+#ifdef WITH_IMPL
+@implementation A
+@end
+#endif
+
+@interface Unknown
++test;
+@end
+
+
+int main() {
+ id x = @protocol(P);
+ [ A alloc ];
+ [ A foo ];
+ [ Unknown test ];
+ return 0;
+}
+
diff --git a/test/CodeGenObjC/message-arrays.m b/test/CodeGenObjC/message-arrays.m
new file mode 100644
index 000000000000..c618672feab2
--- /dev/null
+++ b/test/CodeGenObjC/message-arrays.m
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fnext-runtime -emit-llvm -o %t %s
+
+void f0(id a) {
+ // This should have an implicit cast
+ [ a print: "hello" ];
+}
+
+@interface A
+-(void) m: (int) arg0, ...;
+@end
+
+int f1(A *a) {
+ // This should also get an implicit cast (for the vararg)
+ [a m: 1, "test"];
+}
diff --git a/test/CodeGenObjC/messages-2.m b/test/CodeGenObjC/messages-2.m
new file mode 100644
index 000000000000..ca0eb9493387
--- /dev/null
+++ b/test/CodeGenObjC/messages-2.m
@@ -0,0 +1,139 @@
+// RUN: clang-cc -fnext-runtime --emit-llvm -o %t %s
+
+#include <stdio.h>
+
+@interface Root
+@end
+
+typedef struct {
+ int x, y, z[10];
+} MyPoint;
+typedef struct {
+ float width, height;
+} MySize;
+
+@interface A : Root
++(void) printThisInt: (int) arg0 andThatFloat: (float) arg1 andADouble: (double) arg2 andAPoint: (MyPoint) arg3;
++(float) returnAFloat;
++(double) returnADouble;
++(MyPoint) returnAPoint;
++(void) printThisSize: (MySize) arg0;
++(MySize) returnASize;
+
+-(void) printThisInt: (int) arg0 andThatFloat: (float) arg1 andADouble: (double) arg2 andAPoint: (MyPoint) arg3;
+-(float) returnAFloat;
+-(double) returnADouble;
+-(MyPoint) returnAPoint;
+-(void) printThisSize: (MySize) arg0;
+-(MySize) returnASize;
+@end
+@interface B : A
+@end
+
+@implementation A
++(void) printThisInt: (int) arg0 andThatFloat: (float) arg1 andADouble: (double) arg2 andAPoint: (MyPoint) arg3 {
+ printf("(CLASS) theInt: %d, theFloat: %f, theDouble: %f, thePoint: { %d, %d }\n",
+ arg0, arg1, arg2, arg3.x, arg3.y);
+}
++(float) returnAFloat {
+ return 15.;
+}
++(double) returnADouble {
+ return 25.;
+}
++(MyPoint) returnAPoint {
+ MyPoint x = { 35, 45 };
+ return x;
+}
++(void) printThisSize: (MySize) arg0 {
+ printf("(CLASS) theSize: { %f, %f }\n",
+ arg0.width, arg0.height);
+}
++(MySize) returnASize {
+ MySize x = { 32, 44 };
+ return x;
+}
+
+-(void) printThisInt: (int) arg0 andThatFloat: (float) arg1 andADouble: (double) arg2 andAPoint: (MyPoint) arg3 {
+ printf("theInt: %d, theFloat: %f, theDouble: %f, thePoint: { %d, %d }\n",
+ arg0, arg1, arg2, arg3.x, arg3.y);
+}
+-(float) returnAFloat {
+ return 10.;
+}
+-(double) returnADouble {
+ return 20.;
+}
+-(MyPoint) returnAPoint {
+ MyPoint x = { 30, 40 };
+ return x;
+}
+-(void) printThisSize: (MySize) arg0 {
+ printf("theSize: { %f, %f }\n",
+ arg0.width, arg0.height);
+}
+-(MySize) returnASize {
+ MySize x = { 22, 34 };
+ return x;
+}
+@end
+
+@implementation B
++(void) printThisInt: (int) arg0 andThatFloat: (float) arg1 andADouble: (double) arg2 andAPoint: (MyPoint) arg3 {
+ arg3.x *= 2;
+ arg3.y *= 2;
+ [ super printThisInt: arg0*2 andThatFloat: arg1*2 andADouble: arg2*2 andAPoint: arg3 ];
+}
++(void) printThisSize: (MySize) arg0 {
+ arg0.width *= 2;
+ arg0.height *= 2;
+ [ super printThisSize: arg0 ];
+}
++(float) returnAFloat {
+ return [ super returnAFloat ]*2;
+}
++(double) returnADouble {
+ return [ super returnADouble ]*2;
+}
++(MyPoint) returnAPoint {
+ MyPoint x = [ super returnAPoint ];
+ x.x *= 2;
+ x.y *= 2;
+ return x;
+}
++(MySize) returnASize {
+ MySize x = [ super returnASize ];
+ x.width *= 2;
+ x.height *= 2;
+ return x;
+}
+
+-(void) printThisInt: (int) arg0 andThatFloat: (float) arg1 andADouble: (double) arg2 andAPoint: (MyPoint) arg3 {
+ arg3.x *= 2;
+ arg3.y *= 2;
+ [ super printThisInt: arg0*2 andThatFloat: arg1*2 andADouble: arg2*2 andAPoint: arg3 ];
+}
+-(void) printThisSize: (MySize) arg0 {
+ arg0.width *= 2;
+ arg0.height *= 2;
+ [ super printThisSize: arg0 ];
+}
+-(float) returnAFloat {
+ return [ super returnAFloat ]*2;
+}
+-(double) returnADouble {
+ return [ super returnADouble ]*2;
+}
+-(MyPoint) returnAPoint {
+ MyPoint x = [ super returnAPoint ];
+ x.x *= 2;
+ x.y *= 2;
+ return x;
+}
+-(MySize) returnASize {
+ MySize x = [ super returnASize ];
+ x.width *= 2;
+ x.height *= 2;
+ return x;
+}
+@end
diff --git a/test/CodeGenObjC/messages.m b/test/CodeGenObjC/messages.m
new file mode 100644
index 000000000000..f9b9be6e11a3
--- /dev/null
+++ b/test/CodeGenObjC/messages.m
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fnext-runtime --emit-llvm -o %t %s &&
+// RUN: grep "objc_msgSend" %t | count 6 &&
+// RUN: clang-cc -fgnu-runtime --emit-llvm -o %t %s &&
+// RUN: grep "objc_msg_lookup" %t | count 6 &&
+// RUN: clang-cc -fgnu-runtime -fobjc-sender-dependent-dispatch --emit-llvm -o %t %s &&
+// RUN: grep "objc_msg_lookup_sender" %t | count 6
+// RUN: true
+
+typedef struct {
+ int x;
+ int y;
+ int z[10];
+} MyPoint;
+
+void f0(id a) {
+ int i;
+ MyPoint pt = { 1, 2};
+
+ [a print0];
+ [a print1: 10];
+ [a print2: 10 and: "hello" and: 2.2];
+ [a takeStruct: pt ];
+
+ void *s = @selector(print0);
+ for (i=0; i<2; ++i)
+ [a performSelector:s];
+}
diff --git a/test/CodeGenObjC/metadata-symbols-32.m b/test/CodeGenObjC/metadata-symbols-32.m
new file mode 100644
index 000000000000..8cebe4976e23
--- /dev/null
+++ b/test/CodeGenObjC/metadata-symbols-32.m
@@ -0,0 +1,88 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm -o %t %s &&
+// RUNX: llvm-gcc -m32 -emit-llvm -S -o %t %s &&
+
+// RUN: grep '@"\\01L_OBJC_CATEGORY_A_Cat" = internal global .*section "__OBJC,__category,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_CATEGORY_CLASS_METHODS_A_Cat" = internal global .*section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_CATEGORY_INSTANCE_METHODS_A_Cat" = internal global .*section "__OBJC,__cat_inst_meth,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_CLASSEXT_A" = internal global .*section "__OBJC,__class_ext,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_METHODS_A" = internal global .*section "__OBJC,__cls_meth,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_CLASS_NAME_[0-9]*" = internal global .*section "__TEXT,__cstring,cstring_literals", align 1' %t &&
+// RUN: grep '@"\\01L_OBJC_CLASS_PROTOCOLS_A" = internal global .*section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_CLASS_REFERENCES_[0-9]*" = internal global .*section "__OBJC,__cls_refs,literal_pointers,no_dead_strip", align 4' %t &&
+
+// Clang's Obj-C 32-bit doesn't emit ivars for the root class.
+// RUNX: grep '@"\\01L_OBJC_CLASS_VARIABLES_A" = internal global .*section "__OBJC,__class_vars,regular,no_dead_strip", align 4' %t &&
+
+// RUN: grep '@"\\01L_OBJC_INSTANCE_METHODS_A" = internal global .*section "__OBJC,__inst_meth,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_INSTANCE_VARIABLES_A" = internal global .*section "__OBJC,__instance_vars,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_METACLASS_A" = internal global .*section "__OBJC,__meta_class,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_METH_VAR_NAME_[0-9]*" = internal global .*section "__TEXT,__cstring,cstring_literals", align 1' %t &&
+// RUN: grep '@"\\01L_OBJC_METH_VAR_TYPE_[0-9]*" = internal global .*section "__TEXT,__cstring,cstring_literals", align 1' %t &&
+// RUN: grep '@"\\01L_OBJC_MODULES" = internal global .*section "__OBJC,__module_info,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_PROP_NAME_ATTR_[0-9]*" = internal global .*section "__TEXT,__cstring,cstring_literals", align 1' %t &&
+// RUN: grep '@"\\01L_OBJC_PROTOCOL_CLASS_METHODS_P" = internal global .*section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_PROTOCOL_INSTANCE_METHODS_P" = internal global .*section "__OBJC,__cat_inst_meth,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_PROTOCOL_P" = internal global .*section "__OBJC,__protocol,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_SELECTOR_REFERENCES_[0-9]*" = internal global .*section "__OBJC,__message_refs,literal_pointers,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_SYMBOLS" = internal global .*section "__OBJC,__symbols,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01l_OBJC_$_PROP_LIST_A" = internal global .*section "__OBJC,__property,regular,no_dead_strip", align 4' %t &&
+// RUN: grep "\.lazy_reference \.objc_class_name_J0" %t &&
+
+// RUN: true
+
+/*
+
+Here is a handy command for looking at llvm-gcc's output:
+llvm-gcc -m32 -emit-llvm -S -o - metadata-symbols-32.m | \
+ grep '=.*global' | \
+ sed -e 's#global.*, section#global ... section#' | \
+ sort
+
+*/
+
+@interface B
+@end
+@interface C
+@end
+
+@protocol P
++(void) fm0;
+-(void) im0;
+@end
+
+@interface A<P> {
+ int _ivar;
+}
+
+@property (assign) int ivar;
+
++(void) fm0;
+-(void) im0;
+@end
+
+@implementation A
+@synthesize ivar = _ivar;
++(void) fm0 {
+}
+-(void) im0 {
+}
+@end
+
+@implementation A (Cat)
++(void) fm1 {
+}
+-(void) im1 {
+}
+@end
+
+@interface J0
+@end
+
+@implementation J0(Category) @end
+
+void *f0() {
+ [B im0];
+ [C im1];
+}
+
diff --git a/test/CodeGenObjC/metadata-symbols-64.m b/test/CodeGenObjC/metadata-symbols-64.m
new file mode 100644
index 000000000000..bfc4ae9e7546
--- /dev/null
+++ b/test/CodeGenObjC/metadata-symbols-64.m
@@ -0,0 +1,130 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm -o %t %s &&
+// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
+
+// RUN: grep '@"OBJC_CLASS_$_A" = global' %t &&
+// RUN: grep '@"OBJC_CLASS_$_B" = external global' %t &&
+// RUN: grep '@"OBJC_IVAR_$_A._ivar" = global .* section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"OBJC_METACLASS_$_A" = global .* section "__DATA, __objc_data", align 8' %t &&
+// RUN: grep '@"\\01L_OBJC_CLASSLIST_REFERENCES_$_[0-9]*" = internal global .* section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8' %t &&
+// RUN: grep '@"\\01L_OBJC_CLASSLIST_SUP_REFS_$_[0-9]*" = internal global .* section "__DATA, __objc_superrefs, regular, no_dead_strip", align 8' %t | count 2 &&
+// RUN: grep '@"\\01L_OBJC_CLASS_NAME_[0-9]*" = internal global .* section "__TEXT,__cstring,cstring_literals", align 1' %t &&
+// RUN: grep '@"\\01L_OBJC_LABEL_CATEGORY_$" = internal global .* section "__DATA, __objc_catlist, regular, no_dead_strip", align 8' %t &&
+// RUN: grep '@"\\01L_OBJC_LABEL_CLASS_$" = internal global .* section "__DATA, __objc_classlist, regular, no_dead_strip", align 8' %t &&
+// RUN: grep '@"\\01L_OBJC_METH_VAR_NAME_[0-9]*" = internal global .* section "__TEXT,__cstring,cstring_literals", align 1' %t &&
+// RUN: grep '@"\\01L_OBJC_METH_VAR_TYPE_[0-9]*" = internal global .* section "__TEXT,__cstring,cstring_literals", align 1' %t &&
+// RUN: grep '@"\\01L_OBJC_PROP_NAME_ATTR_[0-9]*" = internal global .* section "__TEXT,__cstring,cstring_literals", align 1' %t &&
+// RUN: grep '@"\\01L_OBJC_SELECTOR_REFERENCES_*" = internal global .* section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"' %t &&
+// RUN: grep '@"\\01l_OBJC_$_CATEGORY_A_$_Cat" = internal global .* section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"\\01l_OBJC_$_CATEGORY_CLASS_METHODS_A_$_Cat" = internal global .* section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"\\01l_OBJC_$_CATEGORY_INSTANCE_METHODS_A_$_Cat" = internal global .* section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"\\01l_OBJC_$_CLASS_METHODS_A" = internal global .* section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"\\01l_OBJC_$_INSTANCE_METHODS_A" = internal global .* section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"\\01l_OBJC_$_INSTANCE_VARIABLES_A" = internal global .* section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"\\01l_OBJC_$_PROP_LIST_A" = internal global .* section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"\\01l_OBJC_$_PROTOCOL_CLASS_METHODS_P" = internal global .* section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"\\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_P" = internal global .* section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"\\01l_OBJC_CLASS_PROTOCOLS_$_A" = internal global .* section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"\\01l_OBJC_CLASS_RO_$_A" = internal global .* section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"\\01l_OBJC_LABEL_PROTOCOL_$_P" = weak hidden global .* section "__DATA, __objc_protolist, coalesced, no_dead_strip", align 8' %t &&
+// RUN: grep '@"\\01l_OBJC_METACLASS_RO_$_A" = internal global .* section "__DATA, __objc_const", align 8' %t &&
+// RUN: grep '@"\\01l_OBJC_PROTOCOL_$_P" = weak hidden global .* section "__DATA,__datacoal_nt,coalesced", align 8' %t &&
+// RUN: grep '@"\\01l_objc_msgSend_fixup_alloc" = weak hidden global .* section "__DATA, __objc_msgrefs, coalesced", align 16' %t &&
+// RUN: grep '@_objc_empty_cache = external global' %t &&
+// RUN: grep '@_objc_empty_vtable = external global' %t &&
+// RUN: grep '@objc_msgSend_fixup(' %t &&
+// RUN: grep '@objc_msgSend_fpret(' %t &&
+
+// RUN: true
+
+/*
+
+Here is a handy command for looking at llvm-gcc's output:
+llvm-gcc -m64 -emit-llvm -S -o - metadata-symbols-64.m | \
+ grep '=.*global' | \
+ sed -e 's#global.*, section#global ... section#' | \
+ sort
+
+*/
+
+@interface B
+@end
+@interface C
+@end
+
+@protocol P
++(void) fm0;
+-(void) im0;
+@end
+
+@interface A<P> {
+ int _ivar;
+}
+
+@property (assign) int ivar;
+
++(void) fm0;
+-(void) im0;
+@end
+
+@implementation A
+@synthesize ivar = _ivar;
++(void) fm0 {
+}
+-(void) im0 {
+}
+@end
+
+@implementation A (Cat)
++(void) fm1 {
+}
+-(void) im1 {
+}
+@end
+
+@interface D : A
+@end
+
+@implementation D
++(void) fm2 {
+ [super fm1];
+}
+-(void) im2 {
+ [super im1];
+}
+@end
+
+// Test for FP dispatch method APIs
+@interface Example
+@end
+
+float FLOAT;
+double DOUBLE;
+long double LONGDOUBLE;
+id ID;
+
+@implementation Example
+ - (double) RET_DOUBLE
+ {
+ return DOUBLE;
+ }
+ - (float) RET_FLOAT
+ {
+ return FLOAT;
+ }
+ - (long double) RET_LONGDOUBLE
+ {
+ return LONGDOUBLE;
+ }
+@end
+
+void *f0(id x) {
+ Example* pe;
+ double dd = [pe RET_DOUBLE];
+ dd = [pe RET_FLOAT];
+ dd = [pe RET_LONGDOUBLE];
+
+ [B im0];
+ [C im1];
+ [D alloc];
+}
+
diff --git a/test/CodeGenObjC/metadata_symbols.m b/test/CodeGenObjC/metadata_symbols.m
new file mode 100644
index 000000000000..1a1d1e1d9810
--- /dev/null
+++ b/test/CodeGenObjC/metadata_symbols.m
@@ -0,0 +1,61 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm -o %t %s &&
+
+// RUN: grep '@"OBJC_METACLASS_$_A" = global .*section "__DATA, __objc_data", align 8' %t &&
+// RUN: grep '@"OBJC_CLASS_$_A" = global .*section "__DATA, __objc_data", align 8' %t &&
+// RUN: grep '@"OBJC_EHTYPE_$_EH1" = weak global .*section "__DATA,__datacoal_nt,coalesced", align 8' %t &&
+// RUN: grep '@"OBJC_EHTYPE_$_EH2" = external global' %t &&
+// RUN: grep '@"OBJC_EHTYPE_$_EH3" = global .*section "__DATA,__objc_const", align 8' %t &&
+// RUN: grep '@"OBJC_EHTYPE_$_EH3"' %t | count 3 &&
+// RUN: grep '@"\\01L_OBJC_CLASS_NAME_" =.*section "__TEXT,__cstring,cstring_literals", align 1' %t | count 1 &&
+// RUN: grep -F 'define internal void @"\01-[A im0]"' %t &&
+// RUN: grep -F 'define internal void @"\01-[A(Cat) im1]"' %t &&
+
+// RUN: clang-cc -fvisibility=hidden -triple x86_64-apple-darwin9 -emit-llvm -o %t %s &&
+
+// RUN: grep '@"OBJC_METACLASS_$_A" = hidden global .*section "__DATA, __objc_data", align 8' %t &&
+// RUN: grep '@"OBJC_CLASS_$_A" = hidden global .*section "__DATA, __objc_data", align 8' %t &&
+// RUN: grep '@"OBJC_EHTYPE_$_EH1" = weak hidden global .*section "__DATA,__datacoal_nt,coalesced"' %t &&
+// RUN: grep '@"OBJC_EHTYPE_$_EH2" = external global' %t &&
+// RUN: grep '@"OBJC_EHTYPE_$_EH3" = hidden global .*section "__DATA,__objc_const", align 8' %t &&
+// RUN: grep -F 'define internal void @"\01-[A im0]"' %t &&
+// RUN: grep -F 'define internal void @"\01-[A(Cat) im1]"' %t &&
+
+// RUN: true
+
+@interface A
+@end
+
+@implementation A
+-(void) im0 {
+}
+@end
+
+@implementation A (Cat)
+-(void) im1 {
+}
+@end
+
+@interface EH1
+@end
+
+__attribute__((__objc_exception__))
+@interface EH2
+@end
+
+__attribute__((__objc_exception__))
+@interface EH3
+@end
+
+void f1();
+
+void f0(id x) {
+ @try {
+ f1();
+ } @catch (EH1 *x) {
+ } @catch (EH2 *x) {
+ } @catch (EH3 *x) {
+ }
+}
+
+@implementation EH3
+@end
diff --git a/test/CodeGenObjC/newproperty-nested-synthesis-1.m b/test/CodeGenObjC/newproperty-nested-synthesis-1.m
new file mode 100644
index 000000000000..5196b8244dbb
--- /dev/null
+++ b/test/CodeGenObjC/newproperty-nested-synthesis-1.m
@@ -0,0 +1,78 @@
+// RUN: clang-cc -fnext-runtime --emit-llvm -o %t %s
+
+@interface Object
+- (id) new;
+@end
+
+@interface Tester : Object
+@property char PropertyAtomic_char;
+@property short PropertyAtomic_short;
+@property int PropertyAtomic_int;
+@property long PropertyAtomic_long;
+@property long long PropertyAtomic_longlong;
+@property float PropertyAtomic_float;
+@property double PropertyAtomic_double;
+@property(assign) id PropertyAtomic_id;
+@property(retain) id PropertyAtomicRetained_id;
+@property(copy) id PropertyAtomicRetainedCopied_id;
+@property(retain) id PropertyAtomicRetainedGCOnly_id;
+@property(copy) id PropertyAtomicRetainedCopiedGCOnly_id;
+@end
+
+@implementation Tester
+@dynamic PropertyAtomic_char;
+@dynamic PropertyAtomic_short;
+@dynamic PropertyAtomic_int;
+@dynamic PropertyAtomic_long;
+@dynamic PropertyAtomic_longlong;
+@dynamic PropertyAtomic_float;
+@dynamic PropertyAtomic_double;
+@dynamic PropertyAtomic_id;
+@dynamic PropertyAtomicRetained_id;
+@dynamic PropertyAtomicRetainedCopied_id;
+@dynamic PropertyAtomicRetainedGCOnly_id;
+@dynamic PropertyAtomicRetainedCopiedGCOnly_id;
+@end
+
+@interface SubClass : Tester
+{
+ char PropertyAtomic_char;
+ short PropertyAtomic_short;
+ int PropertyAtomic_int;
+ long PropertyAtomic_long;
+ long long PropertyAtomic_longlong;
+ float PropertyAtomic_float;
+ double PropertyAtomic_double;
+ id PropertyAtomic_id;
+ id PropertyAtomicRetained_id;
+ id PropertyAtomicRetainedCopied_id;
+ id PropertyAtomicRetainedGCOnly_id;
+ id PropertyAtomicRetainedCopiedGCOnly_id;
+}
+@end
+
+@implementation SubClass
+@synthesize PropertyAtomic_char;
+@synthesize PropertyAtomic_short;
+@synthesize PropertyAtomic_int;
+@synthesize PropertyAtomic_long;
+@synthesize PropertyAtomic_longlong;
+@synthesize PropertyAtomic_float;
+@synthesize PropertyAtomic_double;
+@synthesize PropertyAtomic_id;
+@synthesize PropertyAtomicRetained_id;
+@synthesize PropertyAtomicRetainedCopied_id;
+@synthesize PropertyAtomicRetainedGCOnly_id;
+@synthesize PropertyAtomicRetainedCopiedGCOnly_id;
+@end
+
+int main()
+{
+ SubClass *f = [SubClass new];
+ f.PropertyAtomic_int = 1;
+
+ f.PropertyAtomic_int += 3;
+
+ f.PropertyAtomic_int -= 4;
+ return f.PropertyAtomic_int;
+}
diff --git a/test/CodeGenObjC/no-category-class.m b/test/CodeGenObjC/no-category-class.m
new file mode 100644
index 000000000000..34bf603da57d
--- /dev/null
+++ b/test/CodeGenObjC/no-category-class.m
@@ -0,0 +1,8 @@
+// RUN: clang-cc -triple x86_64-unknown-unknown -emit-llvm -o %t %s
+
+@interface NSObject
+@end
+
+@implementation NSObject(IBXLIFFIntegration)
+@end
+
diff --git a/test/CodeGenObjC/non-lazy-classes.m b/test/CodeGenObjC/non-lazy-classes.m
new file mode 100644
index 000000000000..079cc40886f9
--- /dev/null
+++ b/test/CodeGenObjC/non-lazy-classes.m
@@ -0,0 +1,33 @@
+// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
+// RUN: clang-cc -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 &&
+// RUN: true
+
+@interface A @end
+@implementation A
++(void) load {
+}
+@end
+
+@interface A (Cat) @end
+@implementation A (Cat)
++(void) load {
+}
+@end
+
+@interface B @end
+@implementation B
+-(void) load {
+}
+@end
+
+@interface B (Cat) @end
+@implementation B (Cat)
+-(void) load {
+}
+@end
+
+@interface C : A @end
+@implementation C
+@end
diff --git a/test/CodeGenObjC/objc-align.m b/test/CodeGenObjC/objc-align.m
new file mode 100644
index 000000000000..eca5959a392a
--- /dev/null
+++ b/test/CodeGenObjC/objc-align.m
@@ -0,0 +1,47 @@
+// 32-bit
+
+// RUNX: llvm-gcc -m32 -emit-llvm -S -o %t %s &&
+// RUN: clang-cc -triple i386-apple-darwin9 -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 &&
+// RUN: grep '@"\\01L_OBJC_CLASS_PROTOCOLS_C" = internal global .*, section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_IMAGE_INFO" = internal constant .*, section "__OBJC, __image_info,regular"' %t &&
+// RUN: grep '@"\\01L_OBJC_METACLASS_A" = internal global .*, section "__OBJC,__meta_class,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_METACLASS_C" = internal global .*, section "__OBJC,__meta_class,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_MODULES" = internal global .*, section "__OBJC,__module_info,regular,no_dead_strip", align 4' %t &&
+// RUN: grep '@"\\01L_OBJC_PROTOCOL_P" = internal global .*, section "__OBJC,__protocol,regular,no_dead_strip", align 4' %t &&
+
+// 64-bit
+
+// RUNX: clang-cc -triple i386-apple-darwin9 -emit-llvm -o %t %s &&
+// RUNX: grep '@"OBJC_CLASS_$_A" = global' %t &&
+// RUNX: grep '@"OBJC_CLASS_$_C" = global' %t &&
+// RUNX: grep '@"OBJC_METACLASS_$_A" = global' %t &&
+// RUNX: grep '@"OBJC_METACLASS_$_C" = global' %t &&
+// RUNX: grep '@"\\01L_OBJC_CLASSLIST_REFERENCES_$_0" = internal global .*, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8' %t &&
+// RUNX: grep '@"\\01L_OBJC_IMAGE_INFO" = internal constant .*, section "__DATA, __objc_imageinfo, regular, no_dead_strip"' %t &&
+// RUNX: grep '@"\\01L_OBJC_LABEL_CATEGORY_$" = internal global .*, section "__DATA, __objc_catlist, regular, no_dead_strip", align 8' %t &&
+// RUNX: grep '@"\\01L_OBJC_LABEL_CLASS_$" = internal global .*, section "__DATA, __objc_classlist, regular, no_dead_strip", align 8' %t &&
+// RUNX: grep '@"\\01l_OBJC_$_CATEGORY_A_$_Cat" = internal global .*, section "__DATA, __objc_const", align 8' %t &&
+// RUNX: grep '@"\\01l_OBJC_CLASS_PROTOCOLS_$_C" = internal global .*, section "__DATA, __objc_const", align 8' %t &&
+// RUNX: grep '@"\\01l_OBJC_CLASS_RO_$_A" = internal global .*, section "__DATA, __objc_const", align 8' %t &&
+// RUNX: grep '@"\\01l_OBJC_CLASS_RO_$_C" = internal global .*, section "__DATA, __objc_const", align 8' %t &&
+// RUNX: grep '@"\\01l_OBJC_LABEL_PROTOCOL_$_P" = weak hidden global .*, section "__DATA, __objc_protolist, coalesced, no_dead_strip", align 8' %t &&
+// RUNX: grep '@"\\01l_OBJC_METACLASS_RO_$_A" = internal global .*, section "__DATA, __objc_const", align 8' %t &&
+// RUNX: grep '@"\\01l_OBJC_METACLASS_RO_$_C" = internal global .*, section "__DATA, __objc_const", align 8' %t &&
+// RUNX: grep '@"\\01l_OBJC_PROTOCOL_$_P" = weak hidden global .*, section "__DATA,__datacoal_nt,coalesced", align 8' %t &&
+
+// RUN: true
+
+@interface A @end
+@implementation A
+@end
+@implementation A (Cat)
+@end
+@protocol P
+@end
+@interface C <P>
+@end
+@implementation C
+@end
diff --git a/test/CodeGenObjC/objc2-assign-global.m b/test/CodeGenObjC/objc2-assign-global.m
new file mode 100644
index 000000000000..ae407619093e
--- /dev/null
+++ b/test/CodeGenObjC/objc2-assign-global.m
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fnext-runtime -fobjc-gc -emit-llvm -o %t %s &&
+// RUN: grep -F '@objc_assign_global' %t | count 2 &&
+// RUN: true
+id a;
+int main() {
+ a = 0;
+}
+
diff --git a/test/CodeGenObjC/objc2-no-strong-cast.m b/test/CodeGenObjC/objc2-no-strong-cast.m
new file mode 100644
index 000000000000..bce50cd4544c
--- /dev/null
+++ b/test/CodeGenObjC/objc2-no-strong-cast.m
@@ -0,0 +1,22 @@
+// RUN: clang-cc -emit-llvm -o %t %s
+
+@interface PDFViewPrivateVars
+{
+@public
+ __attribute__((objc_gc(strong))) char *addedTooltips;
+}
+@end
+
+@interface PDFView
+{
+ PDFViewPrivateVars *_pdfPriv;
+}
+@end
+
+@implementation PDFView
+- (void) addTooltipsForPage
+{
+ _pdfPriv->addedTooltips[4] = 1;
+}
+@end
+
diff --git a/test/CodeGenObjC/objc2-no-write-barrier.m b/test/CodeGenObjC/objc2-no-write-barrier.m
new file mode 100644
index 000000000000..2c5350969416
--- /dev/null
+++ b/test/CodeGenObjC/objc2-no-write-barrier.m
@@ -0,0 +1,18 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s &&
+// RUN: grep 'objc_assign' %t | count 0
+
+typedef struct {
+ int ival;
+ id submenu;
+} XCBinderContextMenuItem;
+
+id actionMenuForDataNode(void) {
+ XCBinderContextMenuItem menusToCreate[] = {
+ {1, 0}
+ };
+ return 0;
+}
+
+XCBinderContextMenuItem GmenusToCreate[] = {
+ {1, 0}
+};
diff --git a/test/CodeGenObjC/objc2-property-encode.m b/test/CodeGenObjC/objc2-property-encode.m
new file mode 100644
index 000000000000..2bff2fc1a4ed
--- /dev/null
+++ b/test/CodeGenObjC/objc2-property-encode.m
@@ -0,0 +1,13 @@
+// RUN: clang-cc -triple=i686-apple-darwin9 -fnext-runtime -emit-llvm -o %t %s &&
+// RUN: grep -e "T@\\\\22NSString\\\\22" %t
+@interface NSString @end
+
+typedef NSString StoreVersionID ;
+
+@interface Parent
+ @property(retain) StoreVersionID* foo;
+@end
+
+@implementation Parent
+@dynamic foo;
+@end
diff --git a/test/CodeGenObjC/objc2-protocol-enc.m b/test/CodeGenObjC/objc2-protocol-enc.m
new file mode 100644
index 000000000000..559b0b8c76a0
--- /dev/null
+++ b/test/CodeGenObjC/objc2-protocol-enc.m
@@ -0,0 +1,43 @@
+// RUN: clang-cc -triple=i686-apple-darwin9 -fnext-runtime -emit-llvm -o %t %s &&
+// RUN: grep -e "T@\\\22<X>\\\22" %t &&
+// RUN: grep -e "T@\\\22<X><Y>\\\22" %t &&
+// RUN: grep -e "T@\\\22<X><Y><Z>\\\22" %t &&
+// RUN: grep -e "T@\\\22Foo<X><Y><Z>\\\22" %t
+
+@protocol X, Y, Z;
+@class Foo;
+
+@protocol Proto
+@property (copy) id <X> x;
+@property (copy) id <X, Y> xy;
+@property (copy) id <X, Y, Z> xyz;
+@property(copy) Foo <X, Y, Z> *fooxyz;
+@end
+
+@interface Intf <Proto>
+{
+id <X> IVAR_x;
+id <X, Y> IVAR_xy;
+id <X, Y, Z> IVAR_xyz;
+Foo <X, Y, Z> *IVAR_Fooxyz;
+}
+@end
+
+@implementation Intf
+@dynamic x, xy, xyz, fooxyz;
+@end
+
+/**
+This protocol should generate the following metadata:
+struct objc_property_list __Protocol_Test_metadata = {
+ sizeof(struct objc_property), 4,
+ {
+ { "x", "T@\"<X>\"" },
+ { "xy", "T@\"<X><Y>\"" },
+ { "xyz", "T@\"<X><Y><Z>\"" },
+ { "fooxyz", "T@\"Foo<X><Y><Z>\"" }
+ }
+};
+
+"T@\"<X><Y><Z>\",D
+*/
diff --git a/test/CodeGenObjC/objc2-retain-codegen.m b/test/CodeGenObjC/objc2-retain-codegen.m
new file mode 100644
index 000000000000..d78bc366d398
--- /dev/null
+++ b/test/CodeGenObjC/objc2-retain-codegen.m
@@ -0,0 +1,12 @@
+// RUN: clang-cc -triple x86_64-unknown-unknown -fobjc-gc-only -emit-llvm -o %t %s
+
+@interface I0 {
+ I0 *_f0;
+}
+@property (retain) id p0;
+@end
+
+@implementation I0
+ @synthesize p0 = _f0;
+@end
+
diff --git a/test/CodeGenObjC/objc2-strong-cast-1.m b/test/CodeGenObjC/objc2-strong-cast-1.m
new file mode 100644
index 000000000000..8cad08c88a60
--- /dev/null
+++ b/test/CodeGenObjC/objc2-strong-cast-1.m
@@ -0,0 +1,23 @@
+// RUN: clang-cc -triple x86_64-unknown-unknown -fobjc-gc -emit-llvm -o %t %s
+
+@interface I {
+ __attribute__((objc_gc(strong))) int *i_IdocumentIDs;
+ __attribute__((objc_gc(strong))) long *l_IdocumentIDs;
+ __attribute__((objc_gc(strong))) long long *ll_IdocumentIDs;
+ __attribute__((objc_gc(strong))) float *IdocumentIDs;
+ __attribute__((objc_gc(strong))) double *d_IdocumentIDs;
+}
+- (void) _getResultsOfMatches;
+@end
+
+@implementation I
+-(void) _getResultsOfMatches {
+ IdocumentIDs[2] = IdocumentIDs[3];
+ d_IdocumentIDs[2] = d_IdocumentIDs[3];
+ l_IdocumentIDs[2] = l_IdocumentIDs[3];
+ ll_IdocumentIDs[2] = ll_IdocumentIDs[3];
+ i_IdocumentIDs[2] = i_IdocumentIDs[3];
+}
+
+@end
+
diff --git a/test/CodeGenObjC/objc2-strong-cast-2.m b/test/CodeGenObjC/objc2-strong-cast-2.m
new file mode 100644
index 000000000000..b617c9fee4ea
--- /dev/null
+++ b/test/CodeGenObjC/objc2-strong-cast-2.m
@@ -0,0 +1,27 @@
+// RUN: clang-cc -triple x86_64-darwin-10 -fobjc-gc -emit-llvm -o %t %s &&
+// RUN: grep objc_assign_strongCast %t | count 4 &&
+// RUN: true
+
+@interface A
+@end
+
+typedef struct s0 {
+ A *a[4];
+} T;
+
+T g0;
+
+void f0(id x) {
+ g0.a[0] = x;
+}
+
+void f1(id x) {
+ ((T*) &g0)->a[0] = x;
+}
+
+void f2(unsigned idx)
+{
+ id *keys;
+ keys[idx] = 0;
+}
+
diff --git a/test/CodeGenObjC/objc2-strong-cast.m b/test/CodeGenObjC/objc2-strong-cast.m
new file mode 100644
index 000000000000..d0fcb6ced928
--- /dev/null
+++ b/test/CodeGenObjC/objc2-strong-cast.m
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fnext-runtime -fobjc-gc -emit-llvm -o %t %s
+
+@interface I {
+ __attribute__((objc_gc(strong))) signed long *_documentIDs;
+ __attribute__((objc_gc(strong))) id *IdocumentIDs;
+}
+- (void) _getResultsOfMatches;
+@end
+
+@implementation I
+-(void) _getResultsOfMatches {
+ _documentIDs[2] = _documentIDs[3];
+ IdocumentIDs[2] = IdocumentIDs[3];
+}
+
+@end
+
diff --git a/test/CodeGenObjC/objc2-weak-compare.m b/test/CodeGenObjC/objc2-weak-compare.m
new file mode 100644
index 000000000000..be769899a17d
--- /dev/null
+++ b/test/CodeGenObjC/objc2-weak-compare.m
@@ -0,0 +1,24 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -fnext-runtime -fobjc-gc -emit-llvm -o %t %s
+
+@interface PBXTarget
+{
+
+PBXTarget * __weak _lastKnownTarget;
+PBXTarget * __weak _KnownTarget;
+PBXTarget * result;
+}
+- Meth;
+@end
+
+@implementation PBXTarget
+- Meth {
+ if (_lastKnownTarget != result)
+ foo();
+ if (result != _lastKnownTarget)
+ foo();
+
+ if (_lastKnownTarget != _KnownTarget)
+ foo();
+}
+
+@end
diff --git a/test/CodeGenObjC/objc2-weak-ivar.m b/test/CodeGenObjC/objc2-weak-ivar.m
new file mode 100644
index 000000000000..592c1f05474b
--- /dev/null
+++ b/test/CodeGenObjC/objc2-weak-ivar.m
@@ -0,0 +1,10 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -fobjc-gc -emit-llvm -o %t %s
+@class NSObject;
+
+@interface Foo {
+@public
+ __weak NSObject *nsobject;
+}
+@end
+
+@implementation Foo @end
diff --git a/test/CodeGenObjC/overloadable.m b/test/CodeGenObjC/overloadable.m
new file mode 100644
index 000000000000..972dc4ed5895
--- /dev/null
+++ b/test/CodeGenObjC/overloadable.m
@@ -0,0 +1,10 @@
+// rdar://6657613
+// RUN: clang-cc -emit-llvm %s -o %t &&
+
+@class C;
+
+// RUN: grep _Z1fP11objc_object %t | count 1 &&
+void __attribute__((overloadable)) f(C *c) { }
+
+// RUN: grep _Z1fP1C %t | count 1
+void __attribute__((overloadable)) f(id c) { }
diff --git a/test/CodeGenObjC/predefined-expr-in-method.m b/test/CodeGenObjC/predefined-expr-in-method.m
new file mode 100644
index 000000000000..812ef97252dc
--- /dev/null
+++ b/test/CodeGenObjC/predefined-expr-in-method.m
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fnext-runtime --emit-llvm -o %t %s
+
+@interface A
+@end
+@implementation A
++(void) foo {
+ printf("__func__: %s\n", __func__);
+ printf("__FUNCTION__: %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__: %s\n", __PRETTY_FUNCTION__);
+ return 0;
+}
+@end
+
+int main() {
+ [A foo];
+ return 0;
+}
diff --git a/test/CodeGenObjC/property-aggr-type.m b/test/CodeGenObjC/property-aggr-type.m
new file mode 100644
index 000000000000..0cb7a5e2f40a
--- /dev/null
+++ b/test/CodeGenObjC/property-aggr-type.m
@@ -0,0 +1,50 @@
+// RUN: clang-cc -fnext-runtime -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-agrr-getter.m b/test/CodeGenObjC/property-agrr-getter.m
new file mode 100644
index 000000000000..0a1df123bffe
--- /dev/null
+++ b/test/CodeGenObjC/property-agrr-getter.m
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fnext-runtime -emit-llvm -o %t %s
+
+typedef struct {
+ unsigned f0;
+} s0;
+
+@interface A
+- (s0) f0;
+@end
+
+@implementation A
+-(s0) f0{}
+- (unsigned) bar {
+ return self.f0.f0;
+}
+@end
+
diff --git a/test/CodeGenObjC/property-getter-dot-syntax.m b/test/CodeGenObjC/property-getter-dot-syntax.m
new file mode 100644
index 000000000000..d98e9bab6da9
--- /dev/null
+++ b/test/CodeGenObjC/property-getter-dot-syntax.m
@@ -0,0 +1,11 @@
+// RUN: clang-cc -fnext-runtime --emit-llvm -o %t %s
+
+@protocol NSObject
+- (void *)description;
+@end
+
+int main()
+{
+ id<NSObject> eggs;
+ void *eggsText= eggs.description;
+}
diff --git a/test/CodeGenObjC/property-incr-decr-1.m b/test/CodeGenObjC/property-incr-decr-1.m
new file mode 100644
index 000000000000..772e872a214f
--- /dev/null
+++ b/test/CodeGenObjC/property-incr-decr-1.m
@@ -0,0 +1,29 @@
+// RUN: clang-cc -fnext-runtime -emit-llvm -o %t %s
+
+@interface Object
+- (id) new;
+@end
+
+@interface SomeClass : Object
+{
+ int _myValue;
+}
+@property int myValue;
+@end
+
+@implementation SomeClass
+@synthesize myValue=_myValue;
+@end
+
+int main()
+{
+ int val;
+ SomeClass *o = [SomeClass new];
+ o.myValue = -1;
+ val = o.myValue++; /* val -1, o.myValue 0 */
+ val += o.myValue--; /* val -1. o.myValue -1 */
+ val += ++o.myValue; /* val -1, o.myValue 0 */
+ val += --o.myValue; /* val -2, o.myValue -1 */
+ return ++o.myValue + (val+2);
+}
+
diff --git a/test/CodeGenObjC/property-setter-attr.m b/test/CodeGenObjC/property-setter-attr.m
new file mode 100644
index 000000000000..390392415d73
--- /dev/null
+++ b/test/CodeGenObjC/property-setter-attr.m
@@ -0,0 +1,10 @@
+// RUN: clang-cc -emit-llvm -triple=i686-apple-darwin8 -o %t %s
+// RUN: grep -e "SiSetOtherThings:" %t
+
+@interface A
+@property(setter=iSetOtherThings:) int otherThings;
+@end
+
+@implementation A
+@dynamic otherThings;
+@end
diff --git a/test/CodeGenObjC/property.m b/test/CodeGenObjC/property.m
new file mode 100644
index 000000000000..264adf1106e2
--- /dev/null
+++ b/test/CodeGenObjC/property.m
@@ -0,0 +1,52 @@
+// RUN: clang-cc -fnext-runtime --emit-llvm -o %t %s
+
+#include <stdio.h>
+
+@interface Root
+-(id) alloc;
+-(id) init;
+@end
+
+@interface A : Root {
+ int x;
+ int y, ro, z;
+ id ob0, ob1, ob2, ob3, ob4;
+}
+@property int x;
+@property int y;
+@property int z;
+@property(readonly) int ro;
+@property(assign) id ob0;
+@property(retain) id ob1;
+@property(copy) id ob2;
+@property(retain, nonatomic) id ob3;
+@property(copy, nonatomic) id ob4;
+@end
+
+@implementation A
+@dynamic x;
+@synthesize y;
+@synthesize z = z;
+@synthesize ro;
+@synthesize ob0;
+@synthesize ob1;
+@synthesize ob2;
+@synthesize ob3;
+@synthesize ob4;
+-(int) y {
+ return x + 1;
+}
+-(void) setZ: (int) arg {
+ x = arg - 1;
+}
+@end
+
+@interface A (Cat)
+@property int dyn;
+@end
+
+@implementation A (Cat)
+-(int) dyn {
+ return 10;
+}
+@end
diff --git a/test/CodeGenObjC/protocol-definition-hidden-visibility.m b/test/CodeGenObjC/protocol-definition-hidden-visibility.m
new file mode 100644
index 000000000000..31a864b22d55
--- /dev/null
+++ b/test/CodeGenObjC/protocol-definition-hidden-visibility.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -S -o - %s | grep -e "private_extern l_OBJC_PROTOCOL_" | count 2
+
+@interface FOO @end
+
+@interface NSObject @end
+
+@protocol SSHIPCProtocolHandler_BDC;
+
+typedef NSObject<SSHIPCProtocolHandler_BDC> _SSHIPCProtocolHandler_BDC;
+
+@interface SSHIPC_v2_RPFSProxy
+@property(nonatomic,readonly,retain) _SSHIPCProtocolHandler_BDC* protocolHandler_BDC;
+@end
+
+@implementation FOO
+- (_SSHIPCProtocolHandler_BDC*) protocolHandler_BDC {@protocol(SSHIPCProtocolHandler_BDC); }
+@end
+
+
diff --git a/test/CodeGenObjC/protocol-property-synth.m b/test/CodeGenObjC/protocol-property-synth.m
new file mode 100644
index 000000000000..e91f3552310d
--- /dev/null
+++ b/test/CodeGenObjC/protocol-property-synth.m
@@ -0,0 +1,33 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -emit-llvm -o %t %s
+
+@interface BaseClass {
+ id _delegate;
+}
+@end
+
+@protocol MyProtocol
+@optional
+@property(assign) id delegate;
+@end
+
+@protocol AnotherProtocol
+@optional
+@property(assign) id myanother;
+@end
+
+@protocol SubProtocol <MyProtocol>
+@property(assign) id another;
+@end
+
+@interface SubClass : BaseClass <SubProtocol, AnotherProtocol> {
+}
+
+@end
+
+@implementation BaseClass @end
+
+@implementation SubClass
+@synthesize delegate = _Subdelegate;
+@synthesize another;
+@synthesize myanother;
+@end
diff --git a/test/CodeGenObjC/protocols-lazy.m b/test/CodeGenObjC/protocols-lazy.m
new file mode 100644
index 000000000000..e91cc0aea836
--- /dev/null
+++ b/test/CodeGenObjC/protocols-lazy.m
@@ -0,0 +1,48 @@
+// RUN: clang-cc -emit-llvm -triple=i686-apple-darwin8 -o %t %s &&
+// RUNX: llvm-gcc -S -emit-llvm -o %t %s &&
+
+// No object generated
+// RUN: grep OBJC_PROTOCOL_P0 %t | count 0 &&
+@protocol P0;
+
+// No object generated
+// RUN: grep OBJC_PROTOCOL_P1 %t | count 0 &&
+@protocol P1 -im1; @end
+
+// Definition triggered by protocol reference.
+// RUN: grep OBJC_PROTOCOL_P2 %t | count 3 &&
+// RUN: grep OBJC_PROTOCOL_INSTANCE_METHODS_P2 %t | count 3 &&
+@protocol P2 -im1; @end
+void f0() { id x = @protocol(P2); }
+
+// Forward definition triggered by protocol reference.
+// RUN: grep OBJC_PROTOCOL_P3 %t | count 3 &&
+// RUN: grep OBJC_PROTOCOL_INSTANCE_METHODS_P3 %t | count 0 &&
+@protocol P3;
+void f1() { id x = @protocol(P3); }
+
+// Definition triggered by class reference.
+// RUN: grep OBJC_PROTOCOL_P4 %t | count 3 &&
+// RUN: grep OBJC_PROTOCOL_INSTANCE_METHODS_P4 %t | count 3 &&
+@protocol P4 -im1; @end
+@interface I0<P4> @end
+@implementation I0 -im1 {}; @end
+
+// Definition following forward reference.
+// RUN: grep OBJC_PROTOCOL_P5 %t | count 3 &&
+// RUN: grep OBJC_PROTOCOL_INSTANCE_METHODS_P5 %t | count 3 &&
+@protocol P5;
+void f2() { id x = @protocol(P5); } // This generates a forward
+ // reference, which has to be
+ // updated on the next line.
+@protocol P5 -im1; @end
+
+// Protocol reference following definition.
+// RUN: grep OBJC_PROTOCOL_P6 %t | count 4 &&
+// RUN: grep OBJC_PROTOCOL_INSTANCE_METHODS_P6 %t | count 3 &&
+@protocol P6 -im1; @end
+@interface I1<P6> @end
+@implementation I1 -im1 {}; @end
+void f3() { id x = @protocol(P6); }
+
+// RUN: true
diff --git a/test/CodeGenObjC/runtime-fns.m b/test/CodeGenObjC/runtime-fns.m
new file mode 100644
index 000000000000..0d8570799902
--- /dev/null
+++ b/test/CodeGenObjC/runtime-fns.m
@@ -0,0 +1,33 @@
+// RUN: clang-cc -fnext-runtime -emit-llvm -o %t %s &&
+// RUN: grep -e "^de.*objc_msgSend[0-9]*(" %t | count 1 &&
+// RUN: clang-cc -DWITHDEF -fnext-runtime -emit-llvm -o %t %s &&
+// RUN: grep -e "^de.*objc_msgSend[0-9]*(" %t | count 1
+
+id objc_msgSend(int x);
+
+@interface A @end
+
+@implementation A
+-(void) f0 {
+ objc_msgSend(12);
+}
+
+-(void) hello {
+}
+@end
+
+void f0(id x) {
+ [x hello];
+}
+
+#ifdef WITHDEF
+// This isn't a very good send function.
+id objc_msgSend(int x) {
+ return 0;
+}
+
+// rdar://6800430
+void objc_assign_weak(id value, id *location) {
+}
+
+#endif
diff --git a/test/CodeGenObjC/super-classmethod-category.m b/test/CodeGenObjC/super-classmethod-category.m
new file mode 100644
index 000000000000..27cdbf6aed41
--- /dev/null
+++ b/test/CodeGenObjC/super-classmethod-category.m
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fnext-runtime -emit-llvm -o %t %s
+
+@interface SUPER
++ (void)Meth;
+@end
+
+@interface CURRENT : SUPER
++ (void)Meth;
+@end
+
+@implementation CURRENT(CAT)
++ (void)Meth { [super Meth]; }
+@end
diff --git a/test/CodeGenObjC/super-dotsyntax-property.m b/test/CodeGenObjC/super-dotsyntax-property.m
new file mode 100644
index 000000000000..6e4f176724c8
--- /dev/null
+++ b/test/CodeGenObjC/super-dotsyntax-property.m
@@ -0,0 +1,41 @@
+// RUN: clang-cc -emit-llvm -o %t %s
+
+@interface B
+{
+ int _parent;
+}
+@property int parent;
+ +(int) classGetter;
+ +(void) setClassGetter:(int) arg;
+
+ -(int) getter;
+ -(void) setGetter:(int)arg;
+@end
+
+@interface A : B
+@end
+
+@implementation A
++(int) classGetter {
+ return 0;
+}
+
++(int) classGetter2 {
+ super.classGetter = 100;
+ return super.classGetter;
+}
+
+-(void) method {
+ super.getter = 200;
+ int x = super.getter;
+}
+-(void) setParent : (int) arg {
+ super.parent = arg + super.parent;
+
+}
+@end
+
+void f0() {
+ int l1 = A.classGetter;
+ int l2 = [A classGetter2];
+}
diff --git a/test/CodeGenObjC/synchronized.m b/test/CodeGenObjC/synchronized.m
new file mode 100644
index 000000000000..b398ca6c0a59
--- /dev/null
+++ b/test/CodeGenObjC/synchronized.m
@@ -0,0 +1,41 @@
+// RUN: clang-cc -emit-llvm -triple=i686-apple-darwin9 -o %t %s -O2 &&
+// RUN: grep 'ret i32' %t | count 1 &&
+// RUN: grep 'ret i32 1' %t | count 1
+
+@interface MyClass
+{
+}
+- (void)method;
+@end
+
+@implementation MyClass
+
+- (void)method
+{
+ @synchronized(self)
+ {
+ }
+}
+
+@end
+
+void foo(id a) {
+ @synchronized(a) {
+ return;
+ }
+}
+
+int f0(id a) {
+ int x = 0;
+ @synchronized((x++, a)) {
+ }
+ return x; // ret i32 1
+}
+
+void f1(id a) {
+ // The trick here is that the return shouldn't go through clean up,
+ // but there isn't a simple way to check this property.
+ @synchronized(({ return; }), a) {
+ return;
+ }
+}
diff --git a/test/CodeGenObjC/synthesize_ivar-cont-class.m b/test/CodeGenObjC/synthesize_ivar-cont-class.m
new file mode 100644
index 000000000000..b1a7d0e68030
--- /dev/null
+++ b/test/CodeGenObjC/synthesize_ivar-cont-class.m
@@ -0,0 +1,18 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -emit-llvm -o %t %s &&
+// RUN: grep '@"OBJC_IVAR_$_XCOrganizerDeviceNodeInfo.viewController"' %t
+
+@interface XCOrganizerNodeInfo
+@property (readonly, retain) id viewController;
+@end
+
+@interface XCOrganizerDeviceNodeInfo : XCOrganizerNodeInfo
+@end
+
+@interface XCOrganizerDeviceNodeInfo()
+@property (retain) id viewController;
+@end
+
+@implementation XCOrganizerDeviceNodeInfo
+@synthesize viewController;
+@end
+
diff --git a/test/CodeGenObjC/synthesize_ivar.m b/test/CodeGenObjC/synthesize_ivar.m
new file mode 100644
index 000000000000..7646f707bf76
--- /dev/null
+++ b/test/CodeGenObjC/synthesize_ivar.m
@@ -0,0 +1,27 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -emit-llvm -o %t %s
+
+@interface I
+{
+}
+@property int IP;
+@end
+
+@implementation I
+@synthesize IP;
+- (int) Meth {
+ return IP;
+}
+@end
+
+// Test for synthesis of ivar for a property
+// declared in continuation class.
+@interface OrganizerViolatorView
+@end
+
+@interface OrganizerViolatorView()
+@property (retain) id bindingInfo;
+@end
+
+@implementation OrganizerViolatorView
+@synthesize bindingInfo;
+@end
diff --git a/test/CodeGenObjC/try.m b/test/CodeGenObjC/try.m
new file mode 100644
index 000000000000..7701b23e0819
--- /dev/null
+++ b/test/CodeGenObjC/try.m
@@ -0,0 +1,9 @@
+// RUN: clang-cc %s -S -o - -triple=i686-apple-darwin9 &&
+// RUN: clang-cc %s -S -o - -triple=x86_64-apple-darwin9
+
+// rdar://6757213 - Don't crash if the internal proto for
+// __objc_personality_v0 mismatches with an actual one.
+void __objc_personality_v0() { }
+void test1(void) {
+ @try { } @catch (...) { }
+}
diff --git a/test/CodeGenObjC/unname-bf-metadata.m b/test/CodeGenObjC/unname-bf-metadata.m
new file mode 100644
index 000000000000..a7636e4ebc8b
--- /dev/null
+++ b/test/CodeGenObjC/unname-bf-metadata.m
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fnext-runtime -emit-llvm -o %t %s
+// Test that meta-data for ivar lists with unnamed bitfield are generated.
+//
+@interface Foo {
+@private
+ int first;
+ int :1;
+ int third :1;
+ int :1;
+ int fifth :1;
+}
+@end
+@implementation Foo
+@end
diff --git a/test/Coverage/ast-printing.c b/test/Coverage/ast-printing.c
new file mode 100644
index 000000000000..efa950934ba0
--- /dev/null
+++ b/test/Coverage/ast-printing.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc --fsyntax-only %s &&
+// RUN: clang-cc --ast-print %s &&
+// RUN: clang-cc --ast-dump %s &&
+// RUN: clang-cc --ast-print-xml -o %t %s
+
+#include "c-language-features.inc"
diff --git a/test/Coverage/ast-printing.cpp b/test/Coverage/ast-printing.cpp
new file mode 100644
index 000000000000..10d01c743744
--- /dev/null
+++ b/test/Coverage/ast-printing.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-cc --fsyntax-only %s &&
+// RUN: clang-cc --ast-print %s &&
+// RUN: clang-cc --ast-dump %s
+// FIXME: clang-cc --ast-print-xml -o %t %s
+
+#include "cxx-language-features.inc"
diff --git a/test/Coverage/ast-printing.m b/test/Coverage/ast-printing.m
new file mode 100644
index 000000000000..85bbd4314a4d
--- /dev/null
+++ b/test/Coverage/ast-printing.m
@@ -0,0 +1,5 @@
+// RUN: clang-cc --fsyntax-only %s &&
+// RUN: clang-cc --ast-print %s &&
+// RUN: clang-cc --ast-dump %s
+
+#include "objc-language-features.inc"
diff --git a/test/Coverage/c-language-features.inc b/test/Coverage/c-language-features.inc
new file mode 100644
index 000000000000..bcf4127299f0
--- /dev/null
+++ b/test/Coverage/c-language-features.inc
@@ -0,0 +1,181 @@
+//-*- C -*-
+
+/* This is a
+ multiline comment */
+
+// Intended to exercise all syntactic parts of the C language.
+
+int g0;
+int g1, g2;
+
+struct s0;
+
+struct s0 {
+ int x;
+};
+
+int g3 = 10;
+
+__asm("");
+
+typedef int td0;
+
+td0 g4;
+
+enum e0 {
+ ec0
+};
+
+static void f0(int x) {
+}
+
+inline void f0_0(int x) {
+ ;
+}
+
+extern void f0_1(int x) {
+}
+
+void f1(int, ...);
+
+// Statements.
+void f2() {
+ for (;;) {
+ break;
+ continue;
+ }
+
+ while (0) {
+ }
+
+ do {
+ } while (0);
+
+ void *label = &&theif;
+ goto *label;
+
+ goto theif;
+theif:
+ if (0) {
+ ;
+ } else if (0) {
+ } else {
+ }
+
+ switch(0) {
+ case 0:
+ case 1 ... 2:
+ break;
+ default:
+ break;
+ }
+
+ asm ("nop");
+
+ return;
+}
+
+// Expressions.
+
+#include <stdarg.h>
+
+typedef struct ipair {
+ int first, second;
+} ipair;
+
+void f4(int a0, int a1, int a2, va_list ap) {
+ int t0 = a0 ? a1 : a2;
+ float t1 = (float) a0;
+ ipair t2 = {1, 2};
+ ipair t2a = { .second = 2 };
+ int t3 = sizeof(ipair);
+ ipair t4;
+ t4 = (ipair) {1, 2};
+ extern int g(int);
+ int t5 = g(a0);
+ int t6 = t4.first;
+ int t7[10];
+ int t8 = t7[a0];
+ t8++;
+ const char *t9 = __FUNCTION__;
+ char t10 = 'x';
+ int t11 = __builtin_offsetof(ipair, first);
+ int t12 = __builtin_types_compatible_p(ipair, int);
+ int t12_0 = __builtin_classify_type(t0);
+ int t12_1 = __builtin_classify_type(t1);
+ int t12_2 = __builtin_classify_type(t2);
+ // FIXME: Add _Complex and aggregate cases.
+ int t13 = va_arg(ap, int);
+ va_list t13_0;
+ va_copy(t13_0, ap);
+ int t14 = __extension__(t13);
+ int t15 = +t13;
+ unsigned t16 = t14 ^ t15;
+ int t17 = t14 % t15;
+ int t17_0 = t16 % t16;
+ float t18;
+ int t19 = t18 ? 0 : 1;
+ char *t20; ++t20; --t20;
+ float t21; ++t21; --t21;
+ double t22; ++t22; --t22;
+ long double t23; ++t23; --t23;
+ int t24 = !t19;
+ int t25 = __real t24;
+ int t26 = __imag t24;
+ const char *t27 = t9;
+ t27 += (unsigned char) 0xFF;
+ t27 += (signed char) 0xFF;
+
+ struct { char f0[10]; } *t28;
+ int t29 = t28 - t28;
+ char *t30 = &t28->f0[1];
+
+ struct s1 { int f0; };
+ struct s1 t31_a, t31_b;
+ int t31_cond;
+ int t31 = (t31_cond ? t31_a : t31_b).f0;
+
+ _Complex float t32_a, t32_b;
+ int t32_cond;
+ int t32 = __real (t32_cond ? t32_a : t32_b);
+
+ struct { int x, y; } t33, *t34, t35[12], t36(int, float);
+ float t37, *t38, t39[9], t40(double);
+}
+
+// Extended vectors
+
+typedef __attribute__((ext_vector_type(2))) float float2;
+typedef __attribute__((ext_vector_type(4))) float float4;
+
+void f5() {
+ float4 t0 = (float4) { 0, 1, 2, 3 };
+ float4 t1 = t0;
+ t0.lo.even = t1.hi.x;
+
+ // irgen doesn't support this yet.
+#if 0
+ int t2_cond;
+ float2 t2 = (t2_cond ? t0 : t1).lo;
+#endif
+}
+
+void f6() {
+ const char *s0 = __func__;
+ const char *s1 = __FUNCTION__;
+ const char *s2 = __PRETTY_FUNCTION__;
+}
+
+// Arg mismatch with passed type.
+void f7(x)
+ float x;
+{
+}
+
+void f8(x)
+ short x;
+{
+}
+
+// Function which inputs an array
+void f9(int x[]) { }
diff --git a/test/Coverage/codegen-gnu.m b/test/Coverage/codegen-gnu.m
new file mode 100644
index 000000000000..bc8d6d642e41
--- /dev/null
+++ b/test/Coverage/codegen-gnu.m
@@ -0,0 +1,3 @@
+// RUN: clang-cc -triple i386-unknown-unknown -fgnu-runtime -emit-llvm -o %t %s
+
+#include "objc-language-features.inc"
diff --git a/test/Coverage/codegen-next.m b/test/Coverage/codegen-next.m
new file mode 100644
index 000000000000..bca83cba6931
--- /dev/null
+++ b/test/Coverage/codegen-next.m
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fnext-runtime -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -fnext-runtime -emit-llvm -o %t %s
+
+#include "objc-language-features.inc"
diff --git a/test/Coverage/codegen.c b/test/Coverage/codegen.c
new file mode 100644
index 000000000000..543c361e1bbd
--- /dev/null
+++ b/test/Coverage/codegen.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm-bc -o %t %s &&
+// RUN: clang-cc -triple i386-unknown-unknown -g -emit-llvm-bc -o %t %s &&
+// RUN: clang-cc -triple x86_64-unknown-unknown -emit-llvm-bc -o %t %s &&
+// RUN: clang-cc -triple x86_64-unknown-unknown -g -emit-llvm-bc -o %t %s
+
+#include "c-language-features.inc"
diff --git a/test/Coverage/cxx-language-features.inc b/test/Coverage/cxx-language-features.inc
new file mode 100644
index 000000000000..51c11046a84c
--- /dev/null
+++ b/test/Coverage/cxx-language-features.inc
@@ -0,0 +1,21 @@
+//-*- C++ -*-
+
+// Intended to exercise all syntactic parts of the C++ language that
+// aren't part of C.
+
+namespace std {
+ namespace debug {
+ }
+}
+
+using namespace std::debug;
+using namespace std;
+
+namespace safestl = ::std::debug;
+
+class Base1 {
+};
+
+class Base2 { };
+
+class Derived1 : Base1, virtual public Base2 { };
diff --git a/test/Coverage/html-diagnostics.c b/test/Coverage/html-diagnostics.c
new file mode 100644
index 000000000000..6144f2fb98a3
--- /dev/null
+++ b/test/Coverage/html-diagnostics.c
@@ -0,0 +1,15 @@
+// RUN: rm -rf %t &&
+// RUN: clang-cc --html-diags=%t -checker-simple %s
+
+void f0(int x) {
+ int *p = &x;
+
+ if (x > 10) {
+ if (x == 22)
+ p = 0;
+ }
+
+ *p = 10;
+}
+
+
diff --git a/test/Coverage/html-print.c b/test/Coverage/html-print.c
new file mode 100644
index 000000000000..dab156b145a8
--- /dev/null
+++ b/test/Coverage/html-print.c
@@ -0,0 +1,3 @@
+// RUN: clang-cc -emit-html -o %t %s
+
+#include "c-language-features.inc"
diff --git a/test/Coverage/objc-language-features.inc b/test/Coverage/objc-language-features.inc
new file mode 100644
index 000000000000..dd57dfbedd03
--- /dev/null
+++ b/test/Coverage/objc-language-features.inc
@@ -0,0 +1,81 @@
+//-*- ObjC -*-
+
+@protocol P0;
+
+@protocol P1
+-(void) fm0;
+@end
+
+@class B;
+
+@interface Root
+@end
+
+@interface A : Root <P1> {
+ int iv0;
+ B *iv1;
+}
+
+@property(readonly) int p0;
+@property(assign,nonatomic,readwrite) int p1;
+@property(copy) id p2;
+@property(retain) id p3;
+@property(assign, getter=getme, setter=setme:) id p4;
+@end
+
+@implementation A
+@dynamic p0;
+@synthesize p1 = iv0;
++(void) fm0 {
+ [super fm0];
+}
+-(void) im0 {
+ const char *s0 = __func__;
+ const char *s1 = __FUNCTION__;
+ const char *s2 = __PRETTY_FUNCTION__;
+ [super im0];
+ int x = super.p0;
+}
+-(void) im1: (int) x, ... {
+}
+@end
+
+@implementation C : A
+@end
+
+@interface A (Cat)
+@end
+
+@implementation A (Cat)
+@end
+
+@interface B
+@end
+
+int f0(id x) {
+ @synchronized(x) {
+ }
+
+ @try {
+ @throw x;
+
+ } @catch(A *e) {
+ @throw;
+
+ // @catch param doesn't require name.
+ } @catch(B *) {
+
+ } @finally {
+ ;
+ }
+
+ for (id y in x) {
+ break;
+ }
+}
+
+#ifndef __OBJC2__
+struct s0 {
+ @defs(A);
+};
+#endif
diff --git a/test/Coverage/parse-callbacks.c b/test/Coverage/parse-callbacks.c
new file mode 100644
index 000000000000..309074de9e7d
--- /dev/null
+++ b/test/Coverage/parse-callbacks.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc --parse-noop %s &&
+// RUN: clang-cc --parse-print-callbacks %s
+
+#include "c-language-features.inc"
diff --git a/test/Coverage/parse-callbacks.m b/test/Coverage/parse-callbacks.m
new file mode 100644
index 000000000000..dc1dcfc66270
--- /dev/null
+++ b/test/Coverage/parse-callbacks.m
@@ -0,0 +1,4 @@
+// RUN: clang-cc --parse-noop %s &&
+// RUN: clang-cc --parse-print-callbacks %s
+
+#include "objc-language-features.inc"
diff --git a/test/Coverage/targets.c b/test/Coverage/targets.c
new file mode 100644
index 000000000000..5a547a53add9
--- /dev/null
+++ b/test/Coverage/targets.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc -g -triple i686-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple i686-pc-linux-gnu -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple i686-unknown-dragonfly -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple i686-unknown-win32 -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple i686-apple-darwin9 -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple x86_64-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple x86_64-pc-linux-gnu -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple x86_64-apple-darwin9 -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple ppc-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple ppc-apple-darwin9 -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple ppc64-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple ppc64-apple-darwin9 -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple armv6-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple armv6-apple-darwin9 -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple sparc-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple sparc-unknown-solaris -emit-llvm -o %t %s &&
+// RUN: clang-cc -g -triple pic16-unknown-unknown -emit-llvm -o %t %s &&
+// RUN: true
diff --git a/test/Coverage/verbose.c b/test/Coverage/verbose.c
new file mode 100644
index 000000000000..a75557b3fdee
--- /dev/null
+++ b/test/Coverage/verbose.c
@@ -0,0 +1 @@
+// RUN: clang-cc -fsyntax-only -v %s
diff --git a/test/Driver/Xarch.c b/test/Driver/Xarch.c
new file mode 100644
index 000000000000..a2a3fdea309e
--- /dev/null
+++ b/test/Driver/Xarch.c
@@ -0,0 +1,10 @@
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -m32 -Xarch_i386 -O2 %s -S -### 2> %t.log &&
+// RUN: grep ' "-O2" ' %t.log | count 1 &&
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -m64 -Xarch_i386 -O2 %s -S -### 2> %t.log &&
+// RUN: grep ' "-O2" ' %t.log | count 0 &&
+// RUN: grep "argument unused during compilation: '-Xarch_i386 -O2'" %t.log &&
+// RUN: not clang -ccc-host-triple i386-apple-darwin9 -m32 -Xarch_i386 -o -Xarch_i386 -S %s -S -Xarch_i386 -o 2> %t.log &&
+// RUN: grep "error: invalid Xarch argument: '-Xarch_i386 -o'" %t.log | count 2 &&
+// RUN: grep "error: invalid Xarch argument: '-Xarch_i386 -S'" %t.log &&
+// RUN: true
+
diff --git a/test/Driver/analyze.c b/test/Driver/analyze.c
new file mode 100644
index 000000000000..338c6148c1c3
--- /dev/null
+++ b/test/Driver/analyze.c
@@ -0,0 +1,9 @@
+// Verify that the analyzer gets the same flags as normal compilation
+// (at least for a few key ones).
+
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -### --analyze -o /dev/null %s -msse 2> %t.log &&
+// RUN: grep '"-analyze"' %t.log &&
+// RUN: grep '"--fmath-errno=0"' %t.log &&
+// RUN: grep '"-target-feature" "+sse"' %t.log &&
+// RUN: grep '"-mmacosx-version-min=10.5.0"' %t.log
+
diff --git a/test/Driver/bindings.c b/test/Driver/bindings.c
new file mode 100644
index 000000000000..3cac22c94be3
--- /dev/null
+++ b/test/Driver/bindings.c
@@ -0,0 +1,56 @@
+// Basic binding.
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings %s 2> %t &&
+// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: ".*\.s"' %t &&
+// RUN: grep '"gcc::Assemble", inputs: \[".*\.s"\], output: ".*\.o"' %t &&
+// RUN: grep '"gcc::Link", inputs: \[".*\.o"\], output: "a.out"' %t &&
+
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -ccc-no-clang %s 2> %t &&
+// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: ".*\.s"' %t &&
+// RUN: grep '"gcc::Assemble", inputs: \[".*\.s"\], output: ".*\.o"' %t &&
+// RUN: grep '"gcc::Link", inputs: \[".*\.o"\], output: "a.out"' %t &&
+
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -ccc-no-clang -no-integrated-cpp %s 2> %t &&
+// RUN: grep '"gcc::Preprocess", inputs: \[".*bindings.c"\], output: ".*\.i"' %t &&
+// RUN: grep '"gcc::Compile", inputs: \[".*\.i"\], output: ".*\.s"' %t &&
+// RUN: grep '"gcc::Assemble", inputs: \[".*\.s"\], output: ".*\.o"' %t &&
+// RUN: grep '"gcc::Link", inputs: \[".*\.o"\], output: "a.out"' %t &&
+
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -ccc-no-clang -no-integrated-cpp -pipe %s 2> %t &&
+// RUN: grep '"gcc::Preprocess", inputs: \[".*bindings.c"\], output: (pipe)' %t &&
+// RUN: grep '"gcc::Compile", inputs: \[(pipe)\], output: (pipe)' %t &&
+// RUN: grep '"gcc::Assemble", inputs: \[(pipe)\], output: ".*\.o"' %t &&
+// RUN: grep '"gcc::Link", inputs: \[".*\.o"\], output: "a.out"' %t &&
+
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -ccc-no-clang -x c-header %s 2> %t &&
+// RUN: grep '"gcc::Precompile", inputs: \[".*bindings.c"\], output: ".*bindings.c.gch' %t &&
+
+// Clang control options
+
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -fsyntax-only %s 2> %t &&
+// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: (nothing)' %t &&
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -ccc-no-clang -fsyntax-only %s 2> %t &&
+// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: (nothing)' %t &&
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -fsyntax-only -x c++ %s 2> %t &&
+// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: (nothing)' %t &&
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -ccc-clang-cxx -fsyntax-only -x c++ %s 2> %t &&
+// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: (nothing)' %t &&
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -ccc-no-clang-cpp -fsyntax-only -no-integrated-cpp %s 2> %t &&
+// RUN: grep '"gcc::Preprocess", inputs: \[".*bindings.c"\], output: ".*\.i"' %t &&
+// RUN: grep '"clang", inputs: \[".*\.i"\], output: (nothing)' %t &&
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-bindings -ccc-clang-archs i386 %s -S -arch ppc 2> %t &&
+// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: "bindings.s"' %t &&
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-bindings -ccc-clang-archs ppc %s -S -arch ppc 2> %t &&
+// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: "bindings.s"' %t &&
+
+// RUN: clang -ccc-host-triple powerpc-unknown-unknown -ccc-print-bindings -ccc-clang-archs "" %s -S 2> %t &&
+// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: "bindings.s"' %t &&
+// RUN: clang -ccc-host-triple powerpc-unknown-unknown -ccc-print-bindings %s -S 2> %t &&
+// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: "bindings.s"' %t &&
+
+// Darwin bindings
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-bindings %s 2> %t &&
+// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: ".*\.s"' %t &&
+// RUN: grep '"darwin::Assemble", inputs: \[".*\.s"\], output: ".*\.o"' %t &&
+// RUN: grep '"darwin::Link", inputs: \[".*\.o"\], output: "a.out"' %t &&
+
+// RUN: true
diff --git a/test/Driver/ccc-add-args.c b/test/Driver/ccc-add-args.c
new file mode 100644
index 000000000000..b504b0b42933
--- /dev/null
+++ b/test/Driver/ccc-add-args.c
@@ -0,0 +1,3 @@
+// RUN: env CCC_ADD_ARGS="-ccc-echo,-ccc-print-options,,-v" clang -### 2> %t &&
+// RUN: grep -F 'Option 0 - Name: "-v", Values: {}' %t &&
+// RUN: grep -F 'Option 1 - Name: "-###", Values: {}' %t
diff --git a/test/Driver/clang-translation.c b/test/Driver/clang-translation.c
new file mode 100644
index 000000000000..ca60a8d8c6bc
--- /dev/null
+++ b/test/Driver/clang-translation.c
@@ -0,0 +1,16 @@
+// RUN: clang -ccc-host-triple i386-unknown-unknown -### -S -O0 -Os %s -o %t.s -fverbose-asm 2> %t.log
+// RUN: grep '"-triple" "i386-unknown-unknown"' %t.log &&
+// RUN: grep '"-S"' %t.log &&
+// RUN: grep '"-disable-free"' %t.log &&
+// RUN: grep '"--relocation-model" "static"' %t.log &&
+// RUN: grep '"--disable-fp-elim"' %t.log &&
+// RUN: grep '"--unwind-tables=0"' %t.log &&
+// RUN: grep '"--fmath-errno=1"' %t.log &&
+// RUN: grep '"-Os"' %t.log &&
+// RUN: grep '"-o" .*clang-translation\.c\.out\.tmp\.s' %t.log &&
+// RUN: grep '"--asm-verbose"' %t.log &&
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -### -S %s -o %t.s 2> %t.log
+// RUN: grep '"--mcpu=yonah"' %t.log &&
+// RUN: clang -ccc-host-triple x86_64-apple-darwin9 -### -S %s -o %t.s 2> %t.log
+// RUN: grep '"--mcpu=core2"' %t.log &&
+// RUN: true
diff --git a/test/Driver/clang_cpp.c b/test/Driver/clang_cpp.c
new file mode 100644
index 000000000000..fdbb321e1e91
--- /dev/null
+++ b/test/Driver/clang_cpp.c
@@ -0,0 +1,4 @@
+// Verify that -include isn't included twice with -save-temps.
+// RUN: clang -S -o - %s -include %t.h -save-temps -### 2> %t.log &&
+// RUN: grep '"-include' %t.log | count 1
+
diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c
new file mode 100644
index 000000000000..9dc8f63db8de
--- /dev/null
+++ b/test/Driver/clang_f_opts.c
@@ -0,0 +1,10 @@
+// RUN: clang -### -S -x c /dev/null -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fno-math-errno -fno-common -fno-pascal-strings -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings %s 2> %t &&
+// RUN: grep -F '"-fblocks"' %t &&
+// RUN: grep -F '"--fmath-errno=1"' %t &&
+// RUN: grep -F '"-fpascal-strings"' %t &&
+// RUN: clang -### -S -x c /dev/null -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fno-math-errno -fno-common -fno-pascal-strings %s 2> %t &&
+// RUN: grep -F '"-fblocks=0"' %t &&
+// RUN: grep -F '"-fbuiltin=0"' %t &&
+// RUN: grep -F '"-fno-common"' %t &&
+// RUN: grep -F '"--fmath-errno=0"' %t &&
+// RUN: true
diff --git a/test/Driver/darwin-cc.c b/test/Driver/darwin-cc.c
new file mode 100644
index 000000000000..77193cda4441
--- /dev/null
+++ b/test/Driver/darwin-cc.c
@@ -0,0 +1,6 @@
+// RUN: clang -ccc-no-clang -ccc-host-triple i386-apple-darwin10 -m32 -### -MD -g -fast -Q -dA -mkernel -ansi -aFOO -S -o /tmp/OUTPUTNAME -g0 -gfull -O2 -Werror -pedantic -Wmost -w -std=c99 -trigraphs -v -pg -fFOO -undef -Qn --param a=b -fmudflap -coverage -save-temps -nostdinc -I ARG0 -F ARG1 -I ARG2 -P -MF ARG3 -MG -MP -remap -g3 -H -D ARG4 -U ARG5 -A ARG6 -D ARG7 -U ARG8 -A ARG9 -include ARG10 -pthread %s 2> %t.log &&
+// RUN: grep ' ".*cc1" "-E" "-nostdinc" "-v" "-I" "ARG0" "-F" "ARG1" "-I" "ARG2" "-P" "-MD" "/tmp/OUTPUTNAME.d" "-MF" "ARG3" "-MG" "-MP" "-MQ" "/tmp/OUTPUTNAME" "-remap" "-dD" "-H" "-D__STATIC__" "-D_REENTRANT" "-D" "ARG4" "-U" "ARG5" "-A" "ARG6" "-D" "ARG7" "-U" "ARG8" "-A" "ARG9" "-include" "ARG10" ".*darwin-cc.c" "-D_MUDFLAP" "-include" "mf-runtime.h" "-mmacosx-version-min=10.6.0" "-m32" "-mkernel" "-mtune=core2" "-ansi" "-std=c99" "-trigraphs" "-Werror" "-pedantic" "-Wmost" "-w" "-fast" "-fno-eliminate-unused-debug-symbols" "-fFOO" "-fmudflap" "-O2" "-undef" "-fpch-preprocess" "-o" ".*darwin-cc.i"' %t.log &&
+// RUN: grep ' ".*cc1" "-fpreprocessed" ".*darwin-cc.i" "-O3" "-dumpbase" ".*darwin-cc.c" "-dA" "-mmacosx-version-min=10.6.0" "-m32" "-mkernel" "-mtune=core2" "-ansi" "-aFOO" "-auxbase-strip" "/tmp/OUTPUTNAME" "-g" "-g0" "-g" "-g3" "-O2" "-Werror" "-pedantic" "-Wmost" "-w" "-ansi" "-std=c99" "-trigraphs" "-version" "-p" "-fast" "-fno-eliminate-unused-debug-symbols" "-fFOO" "-fmudflap" "-undef" "-fno-ident" "-o" "/tmp/OUTPUTNAME" "--param" "a=b" "-fno-builtin" "-fno-merge-constants" "-fprofile-arcs" "-ftest-coverage"' %t.log &&
+
+// RUN: true
+
diff --git a/test/Driver/darwin-ld.c b/test/Driver/darwin-ld.c
new file mode 100644
index 000000000000..5ac5ae39172a
--- /dev/null
+++ b/test/Driver/darwin-ld.c
@@ -0,0 +1,44 @@
+// Check that ld gets arch_multiple.
+
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -arch i386 -arch x86_64 %s -### -o foo 2> %t.log &&
+// RUN: grep '".*ld" .*"-arch_multiple" "-final_output" "foo"' %t.log &&
+
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -### -filelist FOO -static 2> %t.log &&
+// RUN: grep '"-lcrt0.o" .*"-lgcc_static"' %t.log &&
+// RUN: grep '"-lgcc"' %t.log | count 0 &&
+// RUN: clang -ccc-host-triple i386-apple-darwin7 -### -filelist FOO 2> %t.log &&
+// RUN: grep '"-lcrt1.o" .*"-lgcc" "-lSystem"' %t.log &&
+// RUN: grep '"-lgcc_s"' %t.log | count 0 &&
+// RUN: clang -ccc-host-triple i386-apple-darwin8 -### -filelist FOO 2> %t.log &&
+// RUN: grep '"-lcrt1.o" .*"-lgcc_s.10.4" "-lgcc" "-lSystem"' %t.log &&
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -### -filelist FOO 2> %t.log &&
+// RUN: grep '"-lcrt1.10.5.o" .*"-lgcc_s.10.5" "-lgcc" "-lSystem"' %t.log &&
+// RUN: clang -ccc-host-triple i386-apple-darwin10 -### -filelist FOO 2> %t.log &&
+// RUN: grep '"-lcrt1.10.6.o" .*"-lSystem" "-lgcc"' %t.log &&
+// RUN: grep '"-lgcc_s"' %t.log | count 0 &&
+
+// Make sure we run dsymutil on source input files.
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -### -g %s -o BAR 2> %t.log &&
+// RUN: grep '".*dsymutil" "BAR"' %t.log &&
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -### -g -filelist FOO %s -o BAR 2> %t.log &&
+// RUN: grep '".*dsymutil" "BAR"' %t.log &&
+
+// Splatter test case. This is gross, but it works for now. For the
+// driver, just getting coverage of the tool code and checking the
+// output options is nearly good enough. The main thing we are
+// protecting against here is unintended changes in the driver
+// output. Intended changes should add more reasonable test cases, and
+// just update this test to match the expected behavior.
+//
+// Note that at conception, this exactly matches gcc.
+
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -### -A ARG0 -F ARG1 -L ARG2 -Mach -T ARG4 -X -Z -all_load -allowable_client ARG8 -bind_at_load -compatibility_version ARG11 -current_version ARG12 -d -dead_strip -dylib_file ARG14 -dylinker -dylinker_install_name ARG16 -dynamic -dynamiclib -e ARG19 -exported_symbols_list ARG20 -fexceptions -flat_namespace -fnested-functions -fopenmp -force_cpusubtype_ALL -fpie -fprofile-arcs -headerpad_max_install_names -image_base ARG29 -init ARG30 -install_name ARG31 -m ARG33 -miphoneos-version-min=2.0 -mmacosx-version-min=10.3.2 -multi_module -multiply_defined ARG37 -multiply_defined_unused ARG38 -no_dead_strip_inits_and_terms -nodefaultlibs -nofixprebinding -nomultidefs -noprebind -noseglinkedit -nostartfiles -nostdlib -object -pagezero_size ARG54 -pg -prebind -prebind_all_twolevel_modules -preload -r -read_only_relocs ARG55 -s -sectalign ARG57_0 ARG57_1 ARG57_2 -sectcreate ARG58_0 ARG58_1 ARG58_2 -sectobjectsymbols ARG59_0 ARG59_1 -sectorder ARG60_0 ARG60_1 ARG60_2 -seg1addr ARG61 -seg_addr_table ARG62 -seg_addr_table_filename ARG63 -segaddr ARG64_0 ARG64_1 -segcreate ARG65_0 ARG65_1 ARG65_2 -seglinkedit -segprot ARG67_0 ARG67_1 ARG67_2 -segs_read_FOO -segs_read_only_addr ARG69 -segs_read_write_addr ARG70 -shared-libgcc -single_module -static -static-libgcc -sub_library ARG77 -sub_umbrella ARG78 -t -twolevel_namespace -twolevel_namespace_hints -u ARG82 -umbrella ARG83 -undefined ARG84 -unexported_symbols_list ARG85 -w -weak_reference_mismatches ARG87 -whatsloaded -whyload -y -filelist FOO 2> %t.log &&
+// RUN: grep '".*ld" "-static" "-dylib" "-dylib_compatibility_version" "ARG11" "-dylib_current_version" "ARG12" "-arch" "i386" "-dylib_install_name" "ARG31" "-all_load" "-allowable_client" "ARG8" "-bind_at_load" "-dead_strip" "-no_dead_strip_inits_and_terms" "-dylib_file" "ARG14" "-dynamic" "-exported_symbols_list" "ARG20" "-flat_namespace" "-headerpad_max_install_names" "-image_base" "ARG29" "-init" "ARG30" "-macosx_version_min" "10.3.2" "-iphoneos_version_min" "2.0" "-nomultidefs" "-multi_module" "-single_module" "-multiply_defined" "ARG37" "-multiply_defined_unused" "ARG38" "-pie" "-prebind" "-noprebind" "-nofixprebinding" "-prebind_all_twolevel_modules" "-read_only_relocs" "ARG55" "-sectcreate" "ARG58_0" "ARG58_1" "ARG58_2" "-sectorder" "ARG60_0" "ARG60_1" "ARG60_2" "-seg1addr" "ARG61" "-segprot" "ARG67_0" "ARG67_1" "ARG67_2" "-segaddr" "ARG64_0" "ARG64_1" "-segs_read_only_addr" "ARG69" "-segs_read_write_addr" "ARG70" "-seg_addr_table" "ARG62" "-seg_addr_table_filename" "ARG63" "-sub_library" "ARG77" "-sub_umbrella" "ARG78" "-twolevel_namespace" "-twolevel_namespace_hints" "-umbrella" "ARG83" "-undefined" "ARG84" "-unexported_symbols_list" "ARG85" "-weak_reference_mismatches" "ARG87" "-X" "-y" "-w" "-pagezero_size" "ARG54" "-segs_read_FOO" "-seglinkedit" "-noseglinkedit" "-sectalign" "ARG57_0" "ARG57_1" "ARG57_2" "-sectobjectsymbols" "ARG59_0" "ARG59_1" "-segcreate" "ARG65_0" "ARG65_1" "ARG65_2" "-whyload" "-whatsloaded" "-dylinker_install_name" "ARG16" "-dylinker" "-Mach" "-d" "-s" "-t" "-Z" "-u" "ARG82" "-undefined" "ARG84" "-A" "ARG0" "-e" "ARG19" "-m" "ARG33" "-r" "-object" "-o" "a.out" "-L" "ARG2" "-lgomp" "-L/usr/lib/i686-apple-darwin9/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin9/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin9/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin9/4.2.1/../../../i686-apple-darwin9/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin9/4.2.1/../../.." "-filelist" "FOO" "-lgcov" "-allow_stack_execute" "-T" "ARG4" "-F" "ARG1"' %t.log &&
+
+// Don't run dsymutil on a fat build of an executable.
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -### -arch i386 -arch x86_64 -g %s 2> %t.log &&
+// RUN: grep dsymutil %t.log | count 0 &&
+
+// RUN: true
+
+
diff --git a/test/Driver/darwin-version.c b/test/Driver/darwin-version.c
new file mode 100644
index 000000000000..dd6905a58961
--- /dev/null
+++ b/test/Driver/darwin-version.c
@@ -0,0 +1,6 @@
+// RUN: env MACOSX_DEPLOYMENT_TARGET=10.1 clang -ccc-host-triple i386-apple-darwin9 -E %s
+
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 1010
+#error Invalid version
+#endif
+
diff --git a/test/Driver/dragonfly.c b/test/Driver/dragonfly.c
new file mode 100644
index 000000000000..5d7b0b0f0045
--- /dev/null
+++ b/test/Driver/dragonfly.c
@@ -0,0 +1,6 @@
+// RUN: clang -ccc-host-triple amd64-pc-dragonfly %s -### 2> %t.log &&
+// RUN: grep 'clang-cc" "-triple" "x86_64-pc-dragonfly"' %t.log &&
+// RUN: grep 'as" "-o" ".*\.o" ".*\.s' %t.log &&
+// RUN: grep 'ld" "-dynamic-linker" ".*ld-elf.*" "-o" "a\.out" ".*crt1.o" ".*crti.o" "crtbegin.o" ".*\.o" "-L.*/gcc.*" .* "-lc" "-lgcc" ".*crtend.o" ".*crtn.o"' %t.log &&
+// RUN: true
+
diff --git a/test/Driver/emit-llvm.c b/test/Driver/emit-llvm.c
new file mode 100644
index 000000000000..a4aabe7256dc
--- /dev/null
+++ b/test/Driver/emit-llvm.c
@@ -0,0 +1,3 @@
+// RUN: not clang -ccc-host-triple i386-pc-linux-gnu -emit-llvm -o %t %s 2> %t.log &&
+// RUN: grep 'unable to pass LLVM bit-code files to linker' %t.log
+
diff --git a/test/Driver/flags.c b/test/Driver/flags.c
new file mode 100644
index 000000000000..53f3995f394d
--- /dev/null
+++ b/test/Driver/flags.c
@@ -0,0 +1,9 @@
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -### -S -msoft-float %s 2> %t.log &&
+// RUN: grep '"--soft-float"' %t.log &&
+
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -### -S -msoft-float -mno-soft-float %s 2> %t.log &&
+// RUN: grep '"--soft-float"' %t.log | count 0 &&
+
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -### -S -mno-soft-float %s -msoft-float 2> %t.log &&
+// RUN: grep '"--soft-float"' %t.log
+
diff --git a/test/Driver/freebsd.c b/test/Driver/freebsd.c
new file mode 100644
index 000000000000..91258d9e5728
--- /dev/null
+++ b/test/Driver/freebsd.c
@@ -0,0 +1,7 @@
+// RUN: clang -ccc-clang-archs "" -ccc-host-triple ppc64-pc-freebsd8 %s -### 2> %t.log &&
+// RUN: cat %t.log &&
+// RUN: grep 'clang-cc" "-triple" "powerpc64-pc-freebsd8"' %t.log &&
+// RUN: grep 'as" "-o" ".*\.o" ".*\.s' %t.log &&
+// RUN: grep 'ld" "--eh-frame-hdr" "-dynamic-linker" ".*ld-elf.*" "-o" "a\.out" ".*crt1.o" ".*crti.o" "crtbegin.o" ".*\.o" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" ".*crtend.o" ".*crtn.o"' %t.log &&
+// RUN: true
+
diff --git a/test/Driver/hello.c b/test/Driver/hello.c
new file mode 100644
index 000000000000..7dbe9c74f9c5
--- /dev/null
+++ b/test/Driver/hello.c
@@ -0,0 +1,14 @@
+// RUN: clang -ccc-echo -o %t %s 2> %t.log &&
+
+// Make sure we used clang.
+// RUN: grep 'clang-cc" .*hello.c' %t.log &&
+
+// RUN: %t > %t.out &&
+// RUN: grep "I'm a little driver, short and stout." %t.out
+
+#include <stdio.h>
+
+int main() {
+ printf("I'm a little driver, short and stout.");
+ return 0;
+}
diff --git a/test/Driver/immediate-options.c b/test/Driver/immediate-options.c
new file mode 100644
index 000000000000..34af89f44d0e
--- /dev/null
+++ b/test/Driver/immediate-options.c
@@ -0,0 +1,5 @@
+// RUN: clang --help &&
+// RUN: clang --help-hidden &&
+// RUN: clang -dumpversion &&
+// RUN: clang -print-search-dirs &&
+// RUN: true
diff --git a/test/Driver/lto.c b/test/Driver/lto.c
new file mode 100644
index 000000000000..01ef2ebc2e03
--- /dev/null
+++ b/test/Driver/lto.c
@@ -0,0 +1,25 @@
+// -emit-llvm, -flto, and -O4 all cause a switch to llvm-bc object
+// files.
+// RUN: clang -ccc-print-phases -c %s -flto 2> %t.log &&
+// RUN: grep '2: compiler, {1}, llvm-bc' %t.log &&
+// RUN: clang -ccc-print-phases -c %s -O4 2> %t.log &&
+// RUN: grep '2: compiler, {1}, llvm-bc' %t.log &&
+
+// and -emit-llvm doesn't alter pipeline (unfortunately?).
+// RUN: clang -ccc-print-phases %s -emit-llvm 2> %t.log &&
+// RUN: grep '0: input, ".*lto.c", c' %t.log &&
+// RUN: grep '1: preprocessor, {0}, cpp-output' %t.log &&
+// RUN: grep '2: compiler, {1}, llvm-bc' %t.log &&
+// RUN: grep '3: linker, {2}, image' %t.log &&
+
+// llvm-bc and llvm-ll outputs need to match regular suffixes
+// (unfortunately).
+// RUN: clang %s -emit-llvm -save-temps -### 2> %t.log &&
+// RUN: grep '"-o" ".*lto\.i" "-x" "c" ".*lto\.c"' %t.log &&
+// RUN: grep '"-o" ".*lto\.o" .*".*lto\.i"' %t.log &&
+// RUN: grep '".*a.out" .*".*lto\.o"' %t.log &&
+
+// RUN: clang %s -emit-llvm -S -### 2> %t.log &&
+// RUN: grep '"-o" ".*lto\.s" "-x" "c" ".*lto\.c"' %t.log &&
+
+// RUN: true
diff --git a/test/Driver/parsing.c b/test/Driver/parsing.c
new file mode 100644
index 000000000000..7b6444050d7d
--- /dev/null
+++ b/test/Driver/parsing.c
@@ -0,0 +1,24 @@
+// RUN: clang -ccc-print-options input -Yunknown -m32 -arch ppc -djoined -A separate -Ajoined -Wp,one,two -Xarch_joined AndSeparate -sectalign 1 2 3 2> %t &&
+// RUN: grep 'Option 0 - Name: "<input>", Values: {"input"}' %t &&
+// RUN: grep 'Option 1 - Name: "<unknown>", Values: {"-Yunknown"}' %t &&
+// RUN: grep 'Option 2 - Name: "-m32", Values: {}' %t &&
+// RUN: grep 'Option 3 - Name: "-arch", Values: {"ppc"}' %t &&
+// RUN: grep 'Option 4 - Name: "-d", Values: {"joined"}' %t &&
+// RUN: grep 'Option 5 - Name: "-A", Values: {"separate"}' %t &&
+// RUN: grep 'Option 6 - Name: "-A", Values: {"joined"}' %t &&
+// RUN: grep 'Option 7 - Name: "-Wp,", Values: {"one", "two"}' %t &&
+// RUN: grep 'Option 8 - Name: "-Xarch_", Values: {"joined", "AndSeparate"}' %t &&
+// RUN: grep 'Option 9 - Name: "-sectalign", Values: {"1", "2", "3"}' %t &&
+
+// RUN: not clang -V 2> %t &&
+// RUN: grep "error: argument to '-V' is missing (expected 1 value)" %t &&
+// RUN: not clang -sectalign 1 2 2> %t &&
+// RUN: grep "error: argument to '-sectalign' is missing (expected 3 values)" %t &&
+
+// Verify that search continues after find the first option.
+// RUN: clang -ccc-print-options -Wally 2> %t &&
+// RUN: grep 'Option 0 - Name: "-W", Values: {"ally"}' %t &&
+
+// RUN: true
+
+
diff --git a/test/Driver/phases.c b/test/Driver/phases.c
new file mode 100644
index 000000000000..0967d33816fe
--- /dev/null
+++ b/test/Driver/phases.c
@@ -0,0 +1,79 @@
+// Basic compilation for various types of files.
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -x c %s -x objective-c %s -x c++ %s -x objective-c++ -x assembler %s -x assembler-with-cpp %s -x none %s 2> %t &&
+// RUN: grep '0: input, ".*phases.c", c' %t &&
+// RUN: grep -F '1: preprocessor, {0}, cpp-output' %t &&
+// RUN: grep -F '2: compiler, {1}, assembler' %t &&
+// RUN: grep -F '3: assembler, {2}, object' %t &&
+// RUN: grep '4: input, ".*phases.c", objective-c' %t &&
+// RUN: grep -F '5: preprocessor, {4}, objective-c-cpp-output' %t &&
+// RUN: grep -F '6: compiler, {5}, assembler' %t &&
+// RUN: grep -F '7: assembler, {6}, object' %t &&
+// RUN: grep '8: input, ".*phases.c", c++' %t &&
+// RUN: grep -F '9: preprocessor, {8}, c++-cpp-output' %t &&
+// RUN: grep -F '10: compiler, {9}, assembler' %t &&
+// RUN: grep -F '11: assembler, {10}, object' %t &&
+// RUN: grep '12: input, ".*phases.c", assembler' %t &&
+// RUN: grep -F '13: assembler, {12}, object' %t &&
+// RUN: grep '14: input, ".*phases.c", assembler-with-cpp' %t &&
+// RUN: grep -F '15: preprocessor, {14}, assembler' %t &&
+// RUN: grep -F '16: assembler, {15}, object' %t &&
+// RUN: grep '17: input, ".*phases.c", c' %t &&
+// RUN: grep -F '18: preprocessor, {17}, cpp-output' %t &&
+// RUN: grep -F '19: compiler, {18}, assembler' %t &&
+// RUN: grep -F '20: assembler, {19}, object' %t &&
+// RUN: grep -F '21: linker, {3, 7, 11, 13, 16, 20}, image' %t &&
+
+// Universal linked image.
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -x c %s -arch ppc -arch i386 2> %t &&
+// RUN: grep '0: input, ".*phases.c", c' %t &&
+// RUN: grep -F '1: preprocessor, {0}, cpp-output' %t &&
+// RUN: grep -F '2: compiler, {1}, assembler' %t &&
+// RUN: grep -F '3: assembler, {2}, object' %t &&
+// RUN: grep -F '4: linker, {3}, image' %t &&
+// RUN: grep -F '5: bind-arch, "ppc", {4}, image' %t &&
+// RUN: grep -F '6: bind-arch, "i386", {4}, image' %t &&
+// RUN: grep -F '7: lipo, {5, 6}, image' %t &&
+
+// Universal object file.
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c -x c %s -arch ppc -arch i386 2> %t &&
+// RUN: grep '0: input, ".*phases.c", c' %t &&
+// RUN: grep -F '1: preprocessor, {0}, cpp-output' %t &&
+// RUN: grep -F '2: compiler, {1}, assembler' %t &&
+// RUN: grep -F '3: assembler, {2}, object' %t &&
+// RUN: grep -F '4: bind-arch, "ppc", {3}, object' %t &&
+// RUN: grep -F '5: bind-arch, "i386", {3}, object' %t &&
+// RUN: grep -F '6: lipo, {4, 5}, object' %t &&
+
+// Arch defaulting
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c -x assembler %s 2> %t &&
+// RUN: grep -F '2: bind-arch, "i386", {1}, object' %t &&
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c -x assembler %s -m32 -m64 2> %t &&
+// RUN: grep -F '2: bind-arch, "x86_64", {1}, object' %t &&
+// RUN: clang -ccc-host-triple x86_64-apple-darwin9 -ccc-print-phases -c -x assembler %s 2> %t &&
+// RUN: grep -F '2: bind-arch, "x86_64", {1}, object' %t &&
+// RUN: clang -ccc-host-triple x86_64-apple-darwin9 -ccc-print-phases -c -x assembler %s -m64 -m32 2> %t &&
+// RUN: grep -F '2: bind-arch, "i386", {1}, object' %t &&
+
+// Analyzer
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases --analyze %s 2> %t &&
+// RUN: grep '0: input, ".*phases.c", c' %t &&
+// RUN: grep -F '1: preprocessor, {0}, cpp-output' %t &&
+// RUN: grep -F '2: analyzer, {1}, plist' %t &&
+
+// Precompiler
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -x c-header %s 2> %t &&
+// RUN: grep '0: input, ".*phases.c", c-header' %t &&
+// RUN: grep -F '1: preprocessor, {0}, c-header-cpp-output' %t &&
+// RUN: grep -F '2: precompiler, {1}, precompiled-header' %t &&
+
+// Darwin overrides the handling for .s
+// RUN: touch %t.s &&
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -c %t.s 2> %t &&
+// RUN: grep '0: input, ".*\.s", assembler' %t &&
+// RUN: grep -F '1: assembler, {0}, object' %t &&
+// RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c %t.s 2> %t &&
+// RUN: grep '0: input, ".*\.s", assembler-with-cpp' %t &&
+// RUN: grep -F '1: preprocessor, {0}, assembler' %t &&
+// RUN: grep -F '2: assembler, {1}, object' %t &&
+
+// RUN: true
diff --git a/test/Driver/preprocessor.c b/test/Driver/preprocessor.c
new file mode 100644
index 000000000000..ec1f42f5bafd
--- /dev/null
+++ b/test/Driver/preprocessor.c
@@ -0,0 +1,6 @@
+// RUN: clang -E -x c-header %s > %t &&
+// RUN: grep 'B B' %t
+
+#define A B
+A A
+
diff --git a/test/Driver/pth.c b/test/Driver/pth.c
new file mode 100644
index 000000000000..748053809a7c
--- /dev/null
+++ b/test/Driver/pth.c
@@ -0,0 +1,8 @@
+// Test transparent PTH support.
+
+// RUN: clang -ccc-pch-is-pth -x c-header %s -o %t.h.pth -### 2> %t.log &&
+// RUN: grep '".*/clang-cc" .* "-o" ".*\.h\.pth" "-x" "c-header" ".*pth\.c"' %t.log &&
+
+// RUN: touch %t.h.pth &&
+// RUN: clang -ccc-pch-is-pth -E -include %t.h %s -### 2> %t.log &&
+// RUN: grep '".*/clang-cc" .*"-include-pth" ".*\.h\.pth" .*"-x" "c" ".*pth\.c"' %t.log
diff --git a/test/Driver/qa_override.c b/test/Driver/qa_override.c
new file mode 100644
index 000000000000..0ff578c2a814
--- /dev/null
+++ b/test/Driver/qa_override.c
@@ -0,0 +1,6 @@
+// RUN: env QA_OVERRIDE_GCC3_OPTIONS="+-Os +-Oz +-O +-O3 +-Oignore +a +b +c xb Xa Omagic ^-ccc-print-options " clang x -O2 b -O3 2> %t &&
+// RUN: grep -F 'Option 0 - Name: "<input>", Values: {"x"}' %t &&
+// RUN: grep -F 'Option 1 - Name: "-O", Values: {"ignore"}' %t &&
+// RUN: grep -F 'Option 2 - Name: "-O", Values: {"magic"}' %t &&
+// RUN: true
+
diff --git a/test/Driver/std.c b/test/Driver/std.c
new file mode 100644
index 000000000000..ef6d8f197754
--- /dev/null
+++ b/test/Driver/std.c
@@ -0,0 +1,8 @@
+// RUN: clang -std=c99 -trigraphs -std=gnu99 %s -E -o %t &&
+// RUN: grep '??(??)' %t &&
+// RUN: clang -ansi %s -E -o %t &&
+// RUN: grep -F '[]' %t &&
+// RUN: clang -std=gnu99 -trigraphs %s -E -o %t &&
+// RUN: grep -F '[]' %t
+
+??(??)
diff --git a/test/Driver/unknown-gcc-arch.c b/test/Driver/unknown-gcc-arch.c
new file mode 100644
index 000000000000..de9e8e84c4ae
--- /dev/null
+++ b/test/Driver/unknown-gcc-arch.c
@@ -0,0 +1,8 @@
+// RUN: clang -ccc-host-triple x86_64-unknown-unknown -c -x assembler %s -### 2> %t.log &&
+// RUN: grep '.*gcc.*"-m64"' %t.log &&
+// RUN: clang -ccc-host-triple x86_64-unknown-unknown -c -x assembler %s -### -m32 2> %t.log &&
+// RUN: grep '.*gcc.*"-m32"' %t.log &&
+// RUN: clang -ccc-host-triple i386-unknown-unknown -c -x assembler %s -### 2> %t.log &&
+// RUN: grep '.*gcc.*"-m32"' %t.log &&
+// RUN: clang -ccc-host-triple i386-unknown-unknown -c -x assembler %s -### -m64 2> %t.log &&
+// RUN: grep '.*gcc.*"-m64"' %t.log
diff --git a/test/Driver/x86_features.c b/test/Driver/x86_features.c
new file mode 100644
index 000000000000..efb3681f9de0
--- /dev/null
+++ b/test/Driver/x86_features.c
@@ -0,0 +1,3 @@
+// RUN: clang -ccc-host-triple i386-unknown-unknown -### -S %s -msse -msse4 -mno-sse -mno-mmx -msse 2> %t &&
+// RUN: grep '"-target-feature" "+sse" "-target-feature" "+sse4" "-target-feature" "-sse" "-target-feature" "-mmx" "-target-feature" "+sse"' %t
+
diff --git a/test/FixIt/fixit-at.c b/test/FixIt/fixit-at.c
new file mode 100644
index 000000000000..42488f56bc7b
--- /dev/null
+++ b/test/FixIt/fixit-at.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only -fixit-at=fixit-at.c:3:1 %s -o - | clang-cc -verify -x c -
+
+_Complex cd;
+
+int i0[1] = { { 17 } }; // expected-warning{{braces}}
diff --git a/test/FixIt/fixit-c90.c b/test/FixIt/fixit-c90.c
new file mode 100644
index 000000000000..03c94953db4e
--- /dev/null
+++ b/test/FixIt/fixit-c90.c
@@ -0,0 +1,11 @@
+/* RUN: clang-cc -fsyntax-only -std=c90 -pedantic -fixit %s -o - | clang-cc -pedantic -x c -std=c90 -Werror -
+ */
+
+/* This is a test of the various code modification hints that are
+ provided as part of warning or extension diagnostics. All of the
+ warnings will be fixed by -fixit, and the resulting file should
+ compile cleanly with -Werror -pedantic. */
+
+enum e0 {
+ e1,
+};
diff --git a/test/FixIt/fixit-errors-1.c b/test/FixIt/fixit-errors-1.c
new file mode 100644
index 000000000000..14329ead8599
--- /dev/null
+++ b/test/FixIt/fixit-errors-1.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -pedantic -fixit %s -o - | clang-cc -pedantic -Werror -x c -
+
+/* This is a test of the various code modification hints that are
+ provided as part of warning or extension diagnostics. All of the
+ warnings will be fixed by -fixit, and the resulting file should
+ compile cleanly with -Werror -pedantic. */
+
+// FIXME: If you put a space at the end of the line, it doesn't work yet!
+char *s = "hi\
+there";
+
+// The following line isn't terminated, don't fix it.
+int i; // expected-error{{no newline at end of file}}
diff --git a/test/FixIt/fixit-errors.c b/test/FixIt/fixit-errors.c
new file mode 100644
index 000000000000..9c5258dbcb74
--- /dev/null
+++ b/test/FixIt/fixit-errors.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -pedantic -fixit %s -o - | clang-cc -pedantic -Werror -x c -
+
+/* This is a test of the various code modification hints that are
+ provided as part of warning or extension diagnostics. All of the
+ warnings will be fixed by -fixit, and the resulting file should
+ compile cleanly with -Werror -pedantic. */
+
+struct s; // expected-note{{previous use is here}}
+
+union s *s1; // expected-error{{use of 's' with tag type that does not match previous declaration}}
diff --git a/test/FixIt/fixit-objc.m b/test/FixIt/fixit-objc.m
new file mode 100644
index 000000000000..baef2337c10c
--- /dev/null
+++ b/test/FixIt/fixit-objc.m
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -fixit-at=fixit-at.c:3:1 %s -o %t.m &&
+// RUN: clang-cc -verify %t.m
+
+@protocol X;
+
+void foo() {
+ <X> *P; // should be fixed to 'id<X>'.
+}
diff --git a/test/FixIt/fixit.c b/test/FixIt/fixit.c
new file mode 100644
index 000000000000..1378df4de152
--- /dev/null
+++ b/test/FixIt/fixit.c
@@ -0,0 +1,29 @@
+// RUN: clang-cc -fsyntax-only -pedantic -fixit %s -o - | clang-cc -pedantic -Werror -x c -
+
+/* This is a test of the various code modification hints that are
+ provided as part of warning or extension diagnostics. All of the
+ warnings will be fixed by -fixit, and the resulting file should
+ compile cleanly with -Werror -pedantic. */
+#include <string.h> // FIXME: FIX-IT hint should add this for us!
+
+void f0(void) { };
+
+struct s {
+ int x, y;;
+};
+
+_Complex cd;
+
+struct s s0 = { y: 5 };
+int array0[5] = { [3] 3 };
+
+void f1(x, y)
+{
+}
+
+int i0 = { 17 };
+
+int f2(const char *my_string) {
+ // FIXME: terminal output isn't so good when "my_string" is shorter
+ return my_string == "foo";
+}
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
new file mode 100644
index 000000000000..ccddd959452b
--- /dev/null
+++ b/test/FixIt/fixit.cpp
@@ -0,0 +1,29 @@
+// RUN: clang-cc -fsyntax-only -pedantic -fixit %s -o - | clang-cc -fsyntax-only -pedantic -Werror -x c++ -
+
+/* This is a test of the various code modification hints that are
+ provided as part of warning or extension diagnostics. All of the
+ warnings will be fixed by -fixit, and the resulting file should
+ compile cleanly with -Werror -pedantic. */
+
+struct C1 {
+ virtual void f();
+ static void g();
+};
+struct C2 : virtual public virtual C1 { }; // expected-error{{duplicate}}
+
+virtual void C1::f() { } // expected-error{{'virtual' can only be specified inside the class definition}}
+
+static void C1::g() { } // expected-error{{'static' can only be specified inside the class definition}}
+
+template<int Value> struct CT { }; // expected-note{{previous use is here}}
+
+CT<10 >> 2> ct; // expected-warning{{require parentheses}}
+
+class C3 {
+public:
+ C3(C3, int i = 0); // expected-error{{copy constructor must pass its first argument by reference}}
+};
+
+struct CT<0> { }; // expected-error{{'template<>'}}
+
+template<> class CT<1> { }; // expected-error{{tag type}}
diff --git a/test/Frontend/darwin-version.c b/test/Frontend/darwin-version.c
new file mode 100644
index 000000000000..513ea197e847
--- /dev/null
+++ b/test/Frontend/darwin-version.c
@@ -0,0 +1,23 @@
+// RUN: clang-cc -triple armv6-apple-darwin9 -dM -E -o %t - < /dev/null &&
+// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | grep '10000' | count 1 &&
+// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | count 0 &&
+// RUN: clang-cc -triple armv6-apple-darwin9 -miphoneos-version-min=2.0 -dM -E -o %t - < /dev/null &&
+// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | grep '20000' | count 1 &&
+// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | count 0 &&
+// RUN: clang-cc -triple armv6-apple-darwin9 -miphoneos-version-min=2.2 -dM -E -o %t - < /dev/null &&
+// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | grep '20200' | count 1 &&
+// RUN: clang-cc -triple i686-apple-darwin8 -dM -E -o %t - < /dev/null &&
+// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | count 0 &&
+// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1040' | count 1 &&
+// RUN: clang-cc -triple i686-apple-darwin9 -dM -E -o %t - < /dev/null &&
+// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1050' | count 1 &&
+// RUN: clang-cc -triple i686-apple-darwin10 -dM -E -o %t - < /dev/null &&
+// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1060' | count 1 &&
+// RUN: clang-cc -triple i686-apple-darwin9 -mmacosx-version-min=10.4 -dM -E -o %t - < /dev/null &&
+// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | count 0 &&
+// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1040' | count 1 &&
+// RUN: clang-cc -triple i686-apple-darwin9 -mmacosx-version-min=10.5 -dM -E -o %t - < /dev/null &&
+// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1050' | count 1 &&
+// RUN: clang-cc -triple i686-apple-darwin9 -mmacosx-version-min=10.6 -dM -E -o %t - < /dev/null &&
+// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1060' | count 1 &&
+// RUN: true
diff --git a/test/Frontend/dependency-gen.c b/test/Frontend/dependency-gen.c
new file mode 100644
index 000000000000..456ce947f091
--- /dev/null
+++ b/test/Frontend/dependency-gen.c
@@ -0,0 +1,7 @@
+// rdar://6533411
+// RUN: clang -MD -MF %t.d -c -x c -o %t.o /dev/null &&
+// RUN: grep '.*dependency-gen.c.out.tmp.o:' %t.d &&
+// RUN: grep '/dev/null' %t.d &&
+
+// RUN: clang -M -x c /dev/null -o %t.deps &&
+// RUN: grep 'null.o: /dev/null' %t.deps
diff --git a/test/Frontend/mmacosx-version-min-test.c b/test/Frontend/mmacosx-version-min-test.c
new file mode 100644
index 000000000000..d117d1c776a8
--- /dev/null
+++ b/test/Frontend/mmacosx-version-min-test.c
@@ -0,0 +1 @@
+// RUN: not clang-cc -fsyntax-only -mmacosx-version-min=10.4 -triple=x86_64-apple-darwin %s
diff --git a/test/Frontend/rewrite-macros.c b/test/Frontend/rewrite-macros.c
new file mode 100644
index 000000000000..32e02ecb266f
--- /dev/null
+++ b/test/Frontend/rewrite-macros.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc -verify --rewrite-macros -o %t %s &&
+
+#define A(a,b) a ## b
+
+// RUN: grep '12 */\*A\*/ /\*(1,2)\*/' %t &&
+A(1,2)
+
+// RUN: grep '/\*_Pragma("mark")\*/' %t &&
+_Pragma("mark")
+
+// RUN: grep "//#warning eek" %t &&
+/* expected-warning {{#warning eek}} */ #warning eek
+
+// RUN: grep "//#pragma mark mark" %t &&
+#pragma mark mark
+
+// RUN: true
+
diff --git a/test/Frontend/stdin.c b/test/Frontend/stdin.c
new file mode 100644
index 000000000000..35fe45d35b40
--- /dev/null
+++ b/test/Frontend/stdin.c
@@ -0,0 +1,3 @@
+// RUN: clang-cc -E - < /dev/null > %t
+// RUN: grep '<built-in>' %t
+
diff --git a/test/Lexer/11-27-2007-FloatLiterals.c b/test/Lexer/11-27-2007-FloatLiterals.c
new file mode 100644
index 000000000000..f3ea7cbaf9f4
--- /dev/null
+++ b/test/Lexer/11-27-2007-FloatLiterals.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc %s -emit-llvm -o - | grep 0x3BFD83C940000000 | count 2 &&
+// RUN: clang-cc %s -emit-llvm -o - | grep 2.000000e+32 | count 2
+
+float F = 1e-19f;
+double D = 2e32;
+float F2 = 01e-19f;
+double D2 = 02e32;
diff --git a/test/Lexer/badstring_in_if0.c b/test/Lexer/badstring_in_if0.c
new file mode 100644
index 000000000000..5fa5a2bb2403
--- /dev/null
+++ b/test/Lexer/badstring_in_if0.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -E %s 2>&1 | not grep error
+#if 0
+
+ "
+
+ '
+
+#endif
diff --git a/test/Lexer/block_cmt_end.c b/test/Lexer/block_cmt_end.c
new file mode 100644
index 000000000000..d85cf81f214a
--- /dev/null
+++ b/test/Lexer/block_cmt_end.c
@@ -0,0 +1,38 @@
+/*
+ RUN: clang-cc -E -trigraphs %s | grep bar &&
+ RUN: clang-cc -E -trigraphs %s | grep foo &&
+ RUN: clang-cc -E -trigraphs %s | not grep abc &&
+ RUN: clang-cc -E -trigraphs %s | not grep xyz &&
+ RUN: clang-cc -fsyntax-only -trigraphs -verify %s
+*/
+
+// This is a simple comment, /*/ does not end a comment, the trailing */ does.
+int i = /*/ */ 1;
+
+/* abc
+
+next comment ends with normal escaped newline:
+*/
+
+/* expected-warning {{escaped newline}} expected-warning {{backslash and newline}} *\
+/
+
+int bar
+
+/* xyz
+
+next comment ends with a trigraph escaped newline: */
+
+/* expected-warning {{escaped newline between}} expected-warning {{backslash and newline separated by space}} expected-warning {{trigraph ends block comment}} *??/
+/
+
+foo /* expected-error {{invalid token after top level declarator}} */
+
+
+// rdar://6060752 - We should not get warnings about trigraphs in comments:
+// '????'
+/* ???? */
+
+
+
+
diff --git a/test/Lexer/c90.c b/test/Lexer/c90.c
new file mode 100644
index 000000000000..d743d68cd501
--- /dev/null
+++ b/test/Lexer/c90.c
@@ -0,0 +1,13 @@
+/* RUN: clang-cc -std=c90 -fsyntax-only %s -verify -pedantic-errors
+ */
+
+enum { cast_hex = (long) (
+ 0x0p-1 /* expected-error {{hexadecimal floating constants are a C99 feature}} */
+ ) };
+
+/* PR2477 */
+int test1(int a,int b) {return a//* This is a divide followed by block comment in c89 mode */
+b;}
+
+// comment accepted as extension /* expected-error {{// comments are not allowed in this language}}
+
diff --git a/test/Lexer/comment-escape.c b/test/Lexer/comment-escape.c
new file mode 100644
index 000000000000..c568cd611f1b
--- /dev/null
+++ b/test/Lexer/comment-escape.c
@@ -0,0 +1,6 @@
+// RUN: clang -fsyntax-only %s
+// rdar://6757323
+// foo \
+
+#define blork 32
+
diff --git a/test/Lexer/constants.c b/test/Lexer/constants.c
new file mode 100644
index 000000000000..fcb6de954516
--- /dev/null
+++ b/test/Lexer/constants.c
@@ -0,0 +1,35 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic -trigraphs %s
+
+int x = 000000080; // expected-error {{invalid digit}}
+
+int y = 0000\
+00080; // expected-error {{invalid digit}}
+
+
+
+float X = 1.17549435e-38F;
+float Y = 08.123456;
+
+// PR2252
+#if -0x8000000000000000 // should not warn.
+#endif
+
+
+char c[] = {
+ 'df', // expected-warning {{multi-character character constant}}
+ '\t',
+ '\\
+t',
+ '??!', // expected-warning {{trigraph converted to '|' character}}
+ 'abcd' // expected-warning {{multi-character character constant}}
+};
+
+
+#pragma clang diagnostic ignored "-Wmultichar"
+
+char d = 'df'; // no warning.
+char e = 'abcd'; // still warn: expected-warning {{multi-character character constant}}
+
+#pragma clang diagnostic ignored "-Wfour-char-constants"
+
+char f = 'abcd'; // ignored.
diff --git a/test/Lexer/counter.c b/test/Lexer/counter.c
new file mode 100644
index 000000000000..9b2c2c7434f4
--- /dev/null
+++ b/test/Lexer/counter.c
@@ -0,0 +1,16 @@
+// __COUNTER__ support: rdar://4329310
+// RUN: clang -E %s > %t &&
+
+#define PASTE2(x,y) x##y
+#define PASTE1(x,y) PASTE2(x,y)
+#define UNIQUE(x) PASTE1(x,__COUNTER__)
+
+// RUN: grep "A: 0" %t &&
+A: __COUNTER__
+
+// RUN: grep "B: foo1" %t &&
+B: UNIQUE(foo);
+// RUN: grep "C: foo2" %t &&
+C: UNIQUE(foo);
+// RUN: grep "D: 3" %t
+D: __COUNTER__
diff --git a/test/Lexer/cxx0x_keyword.cpp b/test/Lexer/cxx0x_keyword.cpp
new file mode 100644
index 000000000000..412c25e83c48
--- /dev/null
+++ b/test/Lexer/cxx0x_keyword.cpp
@@ -0,0 +1,2 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %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
new file mode 100644
index 000000000000..9f8aea127cb9
--- /dev/null
+++ b/test/Lexer/cxx0x_keyword_as_cxx98.cpp
@@ -0,0 +1,2 @@
+// RUN: clang-cc %s -fsyntax-only
+int static_assert;
diff --git a/test/Lexer/digraph.c b/test/Lexer/digraph.c
new file mode 100644
index 000000000000..4d494ca1dd94
--- /dev/null
+++ b/test/Lexer/digraph.c
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify < %s
+
+%:include <stdio.h>
+
+ %:ifndef BUFSIZE
+ %:define BUFSIZE 512
+ %:endif
+
+ void copy(char d<::>, const char s<::>, int len)
+ <%
+ while (len-- >= 0)
+ <%
+ d<:len:> = s<:len:>;
+ %>
+ %>
diff --git a/test/Lexer/dollar-idents.c b/test/Lexer/dollar-idents.c
new file mode 100644
index 000000000000..7635ea112eb7
--- /dev/null
+++ b/test/Lexer/dollar-idents.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -dump-tokens %s 2> %t &&
+// RUN: grep "identifier '\$A'" %t
+// RUN: clang-cc -dump-tokens -x assembler-with-cpp %s 2> %t &&
+// RUN: grep "identifier 'A'" %t
+// PR3808
+
+$A
diff --git a/test/Lexer/escape_newline.c b/test/Lexer/escape_newline.c
new file mode 100644
index 000000000000..ce120ed7c828
--- /dev/null
+++ b/test/Lexer/escape_newline.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -E -trigraphs %s | grep -- ' ->' &&
+// RUN: clang-cc -E -trigraphs %s 2>&1 | grep 'backslash and newline separated by space' &&
+// RUN: clang-cc -E -trigraphs %s 2>&1 | grep 'trigraph converted'
+
+// This is an ugly way to spell a -> token.
+ -??/
+>
diff --git a/test/Lexer/multiple-include.c b/test/Lexer/multiple-include.c
new file mode 100644
index 000000000000..e5fd52926eee
--- /dev/null
+++ b/test/Lexer/multiple-include.c
@@ -0,0 +1,27 @@
+// RUN: clang-cc %s -fsyntax-only
+
+#ifndef XVID_AUTO_INCLUDE
+
+#define XVID_AUTO_INCLUDE
+#define FUNC_H H_Pass_16_C
+#include "multiple-include.c"
+
+#define FUNC_H H_Pass_8_C
+
+#include "multiple-include.c"
+#undef XVID_AUTO_INCLUDE
+
+typedef void ff();
+typedef struct { ff *a;} S;
+
+S s = { H_Pass_8_C };
+
+#endif
+
+#if defined(XVID_AUTO_INCLUDE) && defined(REFERENCE_CODE)
+#elif defined(XVID_AUTO_INCLUDE) && !defined(REFERENCE_CODE)
+
+static void FUNC_H(){};
+#undef FUNC_H
+
+#endif
diff --git a/test/Lexer/numeric-literal-trash.c b/test/Lexer/numeric-literal-trash.c
new file mode 100644
index 000000000000..047e0b8e95f9
--- /dev/null
+++ b/test/Lexer/numeric-literal-trash.c
@@ -0,0 +1,13 @@
+/* RUN: clang-cc -fsyntax-only -verify %s
+ */
+# define XRECORD(x, c_name) e##c (x, __LINE__)
+
+
+
+
+
+
+ void x() {
+
+XRECORD (XRECORD (1, 1), 1);
+ }
diff --git a/test/Lexer/pragma-mark.c b/test/Lexer/pragma-mark.c
new file mode 100644
index 000000000000..f4204aa9d807
--- /dev/null
+++ b/test/Lexer/pragma-mark.c
@@ -0,0 +1,11 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+// Lexer diagnostics shouldn't be included in #pragma mark.
+#pragma mark Mike's world
+_Pragma("mark foo ' bar")
+
+#define X(S) _Pragma(S)
+X("mark foo ' bar")
+
+int i;
+
diff --git a/test/Lexer/rdr-6096838-2.c b/test/Lexer/rdr-6096838-2.c
new file mode 100644
index 000000000000..b135dc1409cb
--- /dev/null
+++ b/test/Lexer/rdr-6096838-2.c
@@ -0,0 +1,5 @@
+/* RUN: clang-cc -pedantic -std=gnu89 -fsyntax-only -verify %s
+ rdar://6096838
+ */
+
+long double d = 0x0.0000003ffffffff00000p-16357L; /* expected-warning {{ hexadecimal floating constants are a C99 feature }} */
diff --git a/test/Lexer/rdr-6096838.c b/test/Lexer/rdr-6096838.c
new file mode 100644
index 000000000000..60e5244646ad
--- /dev/null
+++ b/test/Lexer/rdr-6096838.c
@@ -0,0 +1,6 @@
+/* RUN: clang-cc -fsyntax-only -verify %s &&
+ * RUN: clang-cc -std=gnu89 -fsyntax-only -verify %s
+ rdar://6096838
+ */
+
+long double d = 0x0.0000003ffffffff00000p-16357L;
diff --git a/test/Lexer/token-concat.c b/test/Lexer/token-concat.c
new file mode 100644
index 000000000000..4e27d5d723e2
--- /dev/null
+++ b/test/Lexer/token-concat.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -E -x c -o %t %s &&
+// RUN: grep 'IDENT.2' %t
+
+IDENT.2
diff --git a/test/Lexer/unknown-char.c b/test/Lexer/unknown-char.c
new file mode 100644
index 000000000000..acbf4f039a71
--- /dev/null
+++ b/test/Lexer/unknown-char.c
@@ -0,0 +1,2 @@
+// RUN: clang-cc -E %s 2>&1 | not grep error
+ ` ` ` `
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 000000000000..1ebaedd6b7da
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,47 @@
+LEVEL = ../../..
+include $(LEVEL)/Makefile.common
+
+# Test in all immediate subdirectories if unset.
+TESTDIRS ?= $(shell echo $(PROJ_SRC_DIR)/*/)
+
+# Only run rewriter tests on darwin.
+ifeq ($(OS),Darwin)
+TESTDIRS +=
+endif
+
+ifdef VERBOSE
+ifeq ($(VERBOSE),0)
+PROGRESS = :
+REPORTFAIL = echo 'FAIL: clang' $(TARGET_TRIPLE) $(subst $(LLVM_SRC_ROOT)/tools/clang/,,$<)
+DONE = $(LLVMToolDir)/clang -v
+else
+PROGRESS = echo $<
+REPORTFAIL = cat $@
+DONE = true
+endif
+else
+PROGRESS = printf '.'
+REPORTFAIL = (echo; echo '----' $< 'failed ----')
+DONE = echo
+endif
+
+TESTS := $(addprefix Output/, $(addsuffix .testresults, $(shell find $(TESTDIRS) \( -name '*.c' -or -name '*.cpp' -or -name '*.m' -or -name '*.mm' -or -name '*.S' \) | grep -v "Output/")))
+Output/%.testresults: %
+ @ $(PROGRESS)
+ @ PATH=$(ToolDir):$(LLVM_SRC_ROOT)/test/Scripts:$$PATH VG=$(VG) $(PROJ_SRC_DIR)/TestRunner.sh $< > $@ || $(REPORTFAIL)
+
+all::
+ @ mkdir -p $(addprefix Output/, $(TESTDIRS))
+ @ rm -f $(TESTS)
+ @ echo '--- Running clang tests for $(TARGET_TRIPLE) ---'
+ @ $(MAKE) $(TESTS)
+ @ $(DONE)
+ @ !(cat $(TESTS) | grep -q " FAILED! ")
+
+report: $(TESTS)
+ @ cat $^
+
+clean::
+ @ rm -rf Output/
+
+.PHONY: all report clean
diff --git a/test/Misc/caret-diags-macros.c b/test/Misc/caret-diags-macros.c
new file mode 100644
index 000000000000..58d293fb043e
--- /dev/null
+++ b/test/Misc/caret-diags-macros.c
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only %s > %t 2>&1 &&
+
+#define M1(x) x
+
+// RUN: grep ":6:12: note: instantiated from:" %t &&
+#define M2 1;
+
+void foo() {
+ // RUN: grep ":10:2: warning: expression result unused" %t &&
+ M1(
+ // RUN: grep ":12:5: note: instantiated from:" %t &&
+ M2)
+}
+
+// RUN: grep ":16:11: note: instantiated from:" %t &&
+#define A 1
+// RUN: grep ":18:11: note: instantiated from:" %t &&
+#define B A
+// RUN: grep ":20:11: note: instantiated from:" %t &&
+#define C B
+
+void bar() {
+ // RUN: grep ":24:3: warning: expression result unused" %t
+ C;
+}
+
diff --git a/test/Misc/caret-diags-scratch-buffer.c b/test/Misc/caret-diags-scratch-buffer.c
new file mode 100644
index 000000000000..e339d5635754
--- /dev/null
+++ b/test/Misc/caret-diags-scratch-buffer.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only %s 2>&1 | not grep keyXXXX
+// This should not show keyXXXX in the caret diag output. This once
+// happened because the two tokens ended up in the scratch buffer and
+// the caret diag from the scratch buffer included the previous token.
+#define M(name) \
+ if (name ## XXXX != name ## _sb);
+
+void foo() {
+ int keyXXXX;
+ M(key);
+}
+
diff --git a/test/Misc/diag-checker.c b/test/Misc/diag-checker.c
new file mode 100644
index 000000000000..4733ee1e03d7
--- /dev/null
+++ b/test/Misc/diag-checker.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+#include <stdio.h>
+
+void foo(FILE *FP) {}
diff --git a/test/Misc/diag-mapping.c b/test/Misc/diag-mapping.c
new file mode 100644
index 000000000000..dc07e0d092b5
--- /dev/null
+++ b/test/Misc/diag-mapping.c
@@ -0,0 +1,30 @@
+// This should warn by default.
+// RUN: clang-cc %s 2>&1 | grep "warning:" &&
+// This should not emit anything.
+// RUN: clang-cc %s -Wno-extra-tokens 2>&1 | not grep diagnostic &&
+
+// -Werror can map all warnings to error.
+// RUN: clang-cc %s -Werror 2>&1 | grep "error:" &&
+
+// -Werror can map this one warning to error.
+// RUN: clang-cc %s -Werror=extra-tokens 2>&1 | grep "error:" &&
+
+// Mapping unrelated diags to errors doesn't affect this one.
+// RUN: clang-cc %s -Werror=trigraphs 2>&1 | grep "warning:" &&
+
+// This should stay a warning with -pedantic.
+// RUN: clang-cc %s -pedantic 2>&1 | grep "warning:" &&
+
+// This should emit an error with -pedantic-errors.
+// RUN: clang-cc %s -pedantic-errors 2>&1 | grep "error:" &&
+
+// This should emit a warning, because -Wfoo overrides -pedantic*.
+// RUN: clang-cc %s -pedantic-errors -Wextra-tokens 2>&1 | grep "warning:" &&
+
+// This should emit nothing, because -Wno-extra-tokens overrides -pedantic*
+// RUN: clang-cc %s -pedantic-errors -Wno-extra-tokens 2>&1 | not grep diagnostic
+
+#ifdef foo
+#endif bad // extension!
+
+int x;
diff --git a/test/Misc/diag-mapping2.c b/test/Misc/diag-mapping2.c
new file mode 100644
index 000000000000..7e0d7742a9fe
--- /dev/null
+++ b/test/Misc/diag-mapping2.c
@@ -0,0 +1,19 @@
+// This should warn by default.
+// RUN: clang-cc %s 2>&1 | grep "warning:" &&
+
+// This should not emit anything.
+// RUN: clang-cc %s -w 2>&1 | not grep diagnostic &&
+// RUN: clang-cc %s -Wno-#warnings 2>&1 | not grep diagnostic &&
+
+// -Werror can map all warnings to error.
+// RUN: clang-cc %s -Werror 2>&1 | grep "error:" &&
+
+// -Werror can map this one warning to error.
+// RUN: clang-cc %s -Werror=#warnings 2>&1 | grep "error:" &&
+
+// -Wno-error= overrides -Werror. rdar://3158301
+// RUN: clang-cc %s -Werror -Wno-error=#warnings 2>&1 | grep "warning:"
+
+#warning foo
+
+
diff --git a/test/Misc/emit-html-insert.c b/test/Misc/emit-html-insert.c
new file mode 100644
index 000000000000..ac6b519a3a0d
--- /dev/null
+++ b/test/Misc/emit-html-insert.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc %s -emit-html -o - | grep ">&lt; 10; }"
+
+int a(int x) { return x
+< 10; }
diff --git a/test/Misc/emit-html.c b/test/Misc/emit-html.c
new file mode 100644
index 000000000000..22d0d28dd65d
--- /dev/null
+++ b/test/Misc/emit-html.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc %s -emit-html -o -
+
+// rdar://6562329
+#line 42 "foo.c"
+
+// PR3635
+#define F(fmt, ...) fmt, ## __VA_ARGS__
+int main(int argc, char **argv) {
+ return F(argc, 1);
+}
+
+// PR3798
+#define FOR_ALL_FILES(f,i) i
+
+#if 0
+ FOR_ALL_FILES(f) { }
+#endif
+
diff --git a/test/Misc/message-length.c b/test/Misc/message-length.c
new file mode 100644
index 000000000000..ac5dab99ca52
--- /dev/null
+++ b/test/Misc/message-length.c
@@ -0,0 +1,35 @@
+// RUN: clang -fsyntax-only -fmessage-length=72 %s 2> %t &&
+
+// RUN: grep -A4 "FILE:23" %t > %t.msg &&
+// FIXME: This diagnostic is getting truncated very poorly.
+// RUN: grep -e '^ ...// some long comment text and a brace, eh {} ' %t.msg &&
+// RUN: grep -e '^ \^' %t.msg &&
+// RUN: clang -fsyntax-only -fmessage-length=1 %s &&
+// RUN: true
+
+// Hack so we can check things better, force the file name and line.
+
+# 1 "FILE" 1
+
+/* It's tough to verify the results of this test mechanically, since
+ the length of the filename (and, therefore, how the word-wrapping
+ behaves) changes depending on where the test-suite resides in the
+ file system. */
+void f(int, float, char, float);
+
+void g() {
+ int (*fp1)(int, float, short, float) = f;
+
+ int (*fp2)(int, float, short, float) = f;
+}
+
+void a_func_to_call(int, int, int);
+
+void a_very_long_line(int *ip, float *FloatPointer) {
+ for (int ALongIndexName = 0; ALongIndexName < 100; ALongIndexName++) if (ip[ALongIndexName] == 17) a_func_to_call(ip == FloatPointer, ip[ALongIndexName], FloatPointer[ALongIndexName]);
+
+
+ int array0[] = { [3] 3, 5, 7, 4, 2, 7, 6, 3, 4, 5, 6, 7, 8, 9, 12, 345, 14, 345, 789, 234, 678, 345, 123, 765, 234 };
+}
+
+#pragma STDC CX_LIMITED_RANGE // some long comment text and a brace, eh {}
diff --git a/test/Misc/predefines.c b/test/Misc/predefines.c
new file mode 100644
index 000000000000..c7fac86331a5
--- /dev/null
+++ b/test/Misc/predefines.c
@@ -0,0 +1,5 @@
+/* RUN: clang-cc -fsyntax-only -verify -std=c89 -pedantic-errors %s
+ * rdar://6814950
+ */
+#include <stdint.h>
+
diff --git a/test/PCH/asm.c b/test/PCH/asm.c
new file mode 100644
index 000000000000..bff271de0390
--- /dev/null
+++ b/test/PCH/asm.c
@@ -0,0 +1,11 @@
+// Test this without pch.
+// RUN: clang-cc -triple i386-unknown-unknown -include %S/asm.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -triple i386-unknown-unknown -emit-pch -o %t %S/asm.h &&
+// RUN: clang-cc -triple i386-unknown-unknown -include-pch %t -fsyntax-only -verify %s
+
+
+void call_f(void) { f(); }
+
+void call_clobbers(void) { clobbers(); }
diff --git a/test/PCH/asm.h b/test/PCH/asm.h
new file mode 100644
index 000000000000..a568058d58f6
--- /dev/null
+++ b/test/PCH/asm.h
@@ -0,0 +1,14 @@
+// Header for the PCH test asm.c
+
+void f() {
+ int i;
+
+ asm ("foo\n" : : "a" (i + 2));
+ asm ("foo\n" : [symbolic_name] "=a" (i) : "[symbolic_name]" (i));
+}
+
+void clobbers() {
+ asm ("nop" : : : "ax", "#ax", "%ax");
+ asm ("nop" : : : "eax", "rax", "ah", "al");
+ asm ("nop" : : : "0", "%0", "#0");
+}
diff --git a/test/PCH/attrs.c b/test/PCH/attrs.c
new file mode 100644
index 000000000000..1ffb467f63db
--- /dev/null
+++ b/test/PCH/attrs.c
@@ -0,0 +1,8 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/attrs.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -emit-pch -o %t %S/attrs.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
+// expected-note{{previous overload}}
+double f(double); // expected-error{{overloadable}}
diff --git a/test/PCH/attrs.h b/test/PCH/attrs.h
new file mode 100644
index 000000000000..0d0156515c88
--- /dev/null
+++ b/test/PCH/attrs.h
@@ -0,0 +1,7 @@
+// Header for PCH test exprs.c
+
+
+
+
+
+int f(int) __attribute__((overloadable));
diff --git a/test/PCH/blocks.c b/test/PCH/blocks.c
new file mode 100644
index 000000000000..f3efc8ac4bcc
--- /dev/null
+++ b/test/PCH/blocks.c
@@ -0,0 +1,12 @@
+// Test this without pch.
+// RUN: clang-cc -fblocks -include %S/blocks.h -fsyntax-only -emit-llvm -o - %s &&
+
+// Test with pch.
+// RUN: clang-cc -emit-pch -fblocks -o %t %S/blocks.h &&
+// RUN: clang-cc -fblocks -include-pch %t -fsyntax-only -emit-llvm -o - %s
+
+int do_add(int x, int y) { return add(x, y); }
+
+int do_scaled_add(int a, int b, int s) {
+ return scaled_add(a, b, s);
+}
diff --git a/test/PCH/blocks.h b/test/PCH/blocks.h
new file mode 100644
index 000000000000..af7bb6fc657f
--- /dev/null
+++ b/test/PCH/blocks.h
@@ -0,0 +1,14 @@
+// Header for PCH test blocks.c
+
+int call_block(int (^bl)(int x, int y), int a, int b) {
+ return bl(a, b);
+}
+
+int add(int a, int b) {
+ return call_block(^(int x, int y) { return x + y; }, a, b);
+}
+
+int scaled_add(int a, int b, int s) {
+ __block int scale = s;
+ return call_block(^(int x, int y) { return x*scale + y; }, a, b);
+}
diff --git a/test/PCH/builtins.c b/test/PCH/builtins.c
new file mode 100644
index 000000000000..3d1786ba7713
--- /dev/null
+++ b/test/PCH/builtins.c
@@ -0,0 +1,10 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/builtins.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -emit-pch -o %t %S/builtins.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
+
+void hello() {
+ printf("Hello, World!");
+}
diff --git a/test/PCH/builtins.h b/test/PCH/builtins.h
new file mode 100644
index 000000000000..56e4a53814de
--- /dev/null
+++ b/test/PCH/builtins.h
@@ -0,0 +1,2 @@
+// Header for PCH test builtins.c
+int printf(char const *, ...);
diff --git a/test/PCH/enum.c b/test/PCH/enum.c
new file mode 100644
index 000000000000..45b0491c6f53
--- /dev/null
+++ b/test/PCH/enum.c
@@ -0,0 +1,15 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/enum.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -emit-pch -o %t %S/enum.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
+
+int i = Red;
+
+int return_enum_constant() {
+ int result = aRoundShape;
+ return result;
+}
+
+enum Shape s = Triangle;
diff --git a/test/PCH/enum.h b/test/PCH/enum.h
new file mode 100644
index 000000000000..7dc4e631d6cb
--- /dev/null
+++ b/test/PCH/enum.h
@@ -0,0 +1,16 @@
+/* Used in enum.c test */
+
+enum Color {
+ Red,
+ Green,
+ Blue
+};
+
+enum Shape {
+ Square,
+ Triangle = 17,
+ Rhombus,
+ Circle
+};
+
+enum Shape aRoundShape = Circle;
diff --git a/test/PCH/exprs.c b/test/PCH/exprs.c
new file mode 100644
index 000000000000..c8e6d1dc3030
--- /dev/null
+++ b/test/PCH/exprs.c
@@ -0,0 +1,89 @@
+// Test this without pch.
+// RUN: clang-cc -fblocks -include %S/exprs.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -emit-pch -fblocks -o %t %S/exprs.h &&
+// RUN: clang-cc -fblocks -include-pch %t -fsyntax-only -verify %s
+
+int integer;
+long long_integer;
+double floating;
+_Complex double floating_complex;
+
+// DeclRefExpr
+int_decl_ref *int_ptr1 = &integer;
+enum_decl_ref *enum_ptr1 = &integer;
+
+// IntegerLiteral
+integer_literal *int_ptr2 = &integer;
+long_literal *long_ptr1 = &long_integer;
+
+// FloatingLiteral + ParenExpr
+floating_literal *double_ptr = &floating;
+
+// ImaginaryLiteral
+imaginary_literal *cdouble_ptr = &floating_complex;
+
+// StringLiteral
+const char* printHello() {
+ return hello;
+}
+
+// CharacterLiteral
+char_literal *int_ptr3 = &integer;
+
+// UnaryOperator
+negate_enum *int_ptr4 = &integer;
+
+// SizeOfAlignOfExpr
+typeof(sizeof(float)) size_t_value;
+typeof_sizeof *size_t_ptr = &size_t_value;
+typeof_sizeof2 *size_t_ptr2 = &size_t_value;
+
+// ArraySubscriptExpr
+array_subscript *double_ptr1_5 = &floating;
+
+// CallExpr
+call_returning_double *double_ptr2 = &floating;
+
+// MemberExpr
+member_ref_double *double_ptr3 = &floating;
+
+// BinaryOperator
+add_result *int_ptr5 = &integer;
+
+// CompoundAssignOperator
+addeq_result *int_ptr6 = &integer;
+
+// ConditionalOperator
+conditional_operator *double_ptr4 = &floating;
+
+// CStyleCastExpr
+void_ptr vp1 = &integer;
+
+// CompoundLiteral
+struct S s;
+compound_literal *sptr = &s;
+
+// ExtVectorElementExpr
+ext_vector_element *double_ptr5 = &floating;
+
+// InitListExpr
+double get_from_double_array(unsigned Idx) { return double_array[Idx]; }
+
+/// DesignatedInitExpr
+float get_from_designated(unsigned Idx) {
+ return designated_inits[2].y;
+}
+
+// TypesCompatibleExpr
+types_compatible *int_ptr7 = &integer;
+
+// ChooseExpr
+choose_expr *int_ptr8 = &integer;
+
+// GNUNullExpr FIXME: needs C++
+//null_type null = __null;
+
+// ShuffleVectorExpr
+shuffle_expr *vec_ptr = &vec2;
diff --git a/test/PCH/exprs.h b/test/PCH/exprs.h
new file mode 100644
index 000000000000..7012422aad33
--- /dev/null
+++ b/test/PCH/exprs.h
@@ -0,0 +1,86 @@
+// Header for PCH test exprs.c
+
+// DeclRefExpr
+int i = 17;
+enum Enum { Enumerator = 18 };
+typedef typeof(i) int_decl_ref;
+typedef typeof(Enumerator) enum_decl_ref;
+
+// IntegerLiteral
+typedef typeof(17) integer_literal;
+typedef typeof(17l) long_literal;
+
+// FloatingLiteral and ParenExpr
+typedef typeof((42.5)) floating_literal;
+
+// ImaginaryLiteral
+typedef typeof(17.0i) imaginary_literal;
+
+// StringLiteral
+const char *hello = "Hello" "PCH" "World";
+
+// CharacterLiteral
+typedef typeof('a') char_literal;
+
+// UnaryOperator
+typedef typeof(-Enumerator) negate_enum;
+
+// SizeOfAlignOfExpr
+typedef typeof(sizeof(int)) typeof_sizeof;
+typedef typeof(sizeof(Enumerator)) typeof_sizeof2;
+
+// ArraySubscriptExpr
+extern double values[];
+typedef typeof(values[2]) array_subscript;
+
+// CallExpr
+double dplus(double x, double y);
+double d0, d1;
+typedef typeof((&dplus)(d0, d1)) call_returning_double;
+
+// MemberExpr
+struct S {
+ double x;
+};
+typedef typeof(((struct S*)0)->x) member_ref_double;
+
+// BinaryOperator
+typedef typeof(i + Enumerator) add_result;
+
+// CompoundAssignOperator
+typedef typeof(i += Enumerator) addeq_result;
+
+// ConditionalOperator
+typedef typeof(i? : d0) conditional_operator;
+
+// CStyleCastExpr
+typedef typeof((void *)0) void_ptr;
+
+// CompoundLiteral
+typedef typeof((struct S){.x = 3.5}) compound_literal;
+
+// ExtVectorElementExpr
+typedef __attribute__(( ext_vector_type(2) )) double double2;
+extern double2 vec2, vec2b;
+typedef typeof(vec2.x) ext_vector_element;
+
+// InitListExpr
+double double_array[3] = { 1.0, 2.0 };
+
+// DesignatedInitExpr
+struct {
+ int x;
+ float y;
+} designated_inits[3] = { [0].y = 17, [2].x = 12.3, 3.5 };
+
+// TypesCompatibleExpr
+typedef typeof(__builtin_types_compatible_p(float, double)) types_compatible;
+
+// ChooseExpr
+typedef typeof(__builtin_choose_expr(17 > 19, d0, 1)) choose_expr;
+
+// GNUNullExpr FIXME: needs C++
+// typedef typeof(__null) null_type;
+
+// ShuffleVectorExpr
+typedef typeof(__builtin_shufflevector(vec2, vec2b, 2, 1)) shuffle_expr;
diff --git a/test/PCH/ext_vector.c b/test/PCH/ext_vector.c
new file mode 100644
index 000000000000..4b5c25980e56
--- /dev/null
+++ b/test/PCH/ext_vector.c
@@ -0,0 +1,10 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/ext_vector.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -emit-pch -o %t %S/ext_vector.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
+
+int test(float4 f4) {
+ return f4.xy; // expected-error{{float2}}
+}
diff --git a/test/PCH/ext_vector.h b/test/PCH/ext_vector.h
new file mode 100644
index 000000000000..39ab9233584d
--- /dev/null
+++ b/test/PCH/ext_vector.h
@@ -0,0 +1,4 @@
+// Header file for ext_vector.c PCH test
+
+typedef __attribute__((ext_vector_type(2))) float float2;
+typedef __attribute__((ext_vector_type(4))) float float4;
diff --git a/test/PCH/external-defs.c b/test/PCH/external-defs.c
new file mode 100644
index 000000000000..b7eb700e6b3e
--- /dev/null
+++ b/test/PCH/external-defs.c
@@ -0,0 +1,19 @@
+// Test with pch.
+// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-pch -o %t.pch %S/external-defs.h &&
+// RUN: clang-cc -triple x86_64-apple-darwin9 -include-pch %t.pch -emit-llvm -o %t %s &&
+
+// RUN: grep "@x = common global i32 0" %t | count 1 &&
+// RUN: grep "@z" %t | count 0 &&
+
+// RUN: grep "@x2 = global i32 19" %t | count 1 &&
+int x2 = 19;
+
+// RUN: grep "@incomplete_array = common global .*1 x i32" %t | count 1 &&
+// RUN: grep "@incomplete_array2 = common global .*17 x i32" %t | count 1 &&
+int incomplete_array2[17];
+// RUN: grep "@incomplete_array3 = common global .*1 x i32" %t | count 1
+int incomplete_array3[];
+
+struct S {
+ int x, y;
+};
diff --git a/test/PCH/external-defs.h b/test/PCH/external-defs.h
new file mode 100644
index 000000000000..657b47bcc141
--- /dev/null
+++ b/test/PCH/external-defs.h
@@ -0,0 +1,13 @@
+// Helper for external-defs.c test
+
+// Tentative definitions
+int x;
+int x2;
+
+// Should not show up
+static int z;
+
+int incomplete_array[];
+int incomplete_array2[];
+
+struct S s;
diff --git a/test/PCH/functions.c b/test/PCH/functions.c
new file mode 100644
index 000000000000..6d3c5a0f7b81
--- /dev/null
+++ b/test/PCH/functions.c
@@ -0,0 +1,20 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/functions.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -emit-pch -o %t %S/functions.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
+
+int f0(int x0, int y0, ...) { return x0 + y0; }
+
+float *test_f1(int val, double x, double y) {
+ if (val > 5)
+ return f1(x, y);
+ else
+ return f1(x); // expected-error{{too few arguments to function call}}
+}
+
+void test_g0(int *x, float * y) {
+ g0(y); // expected-warning{{incompatible pointer types passing 'float *', expected 'int *'}}
+ g0(x);
+}
diff --git a/test/PCH/functions.h b/test/PCH/functions.h
new file mode 100644
index 000000000000..bc28ad7321c7
--- /dev/null
+++ b/test/PCH/functions.h
@@ -0,0 +1,6 @@
+/* For use with the functions.c test */
+
+int f0(int x, int y, ...);
+float *f1(float x, float y);
+
+void g0(int *);
diff --git a/test/PCH/fuzzy-pch.c b/test/PCH/fuzzy-pch.c
new file mode 100644
index 000000000000..2ddcb8bb089b
--- /dev/null
+++ b/test/PCH/fuzzy-pch.c
@@ -0,0 +1,19 @@
+// Test with pch.
+// RUN: clang-cc -emit-pch -DFOO -o %t %S/variables.h &&
+// RUN: clang-cc -DBAR=int -include-pch %t -fsyntax-only -pedantic %s &&
+// RUN: clang-cc -DFOO -DBAR=int -include-pch %t -Werror %s &&
+// RUN: not clang-cc -DFOO -DBAR=int -DX=5 -include-pch %t -Werror %s
+
+BAR bar = 17;
+
+#ifndef FOO
+# error FOO was not defined
+#endif
+
+#if FOO != 1
+# error FOO has the wrong definition
+#endif
+
+#ifndef BAR
+# error BAR was not defined
+#endif
diff --git a/test/PCH/fuzzy-pch.h b/test/PCH/fuzzy-pch.h
new file mode 100644
index 000000000000..9eb1005ce447
--- /dev/null
+++ b/test/PCH/fuzzy-pch.h
@@ -0,0 +1,2 @@
+// Header for PCH test fuzzy-pch.c
+void f(int X);
diff --git a/test/PCH/line-directive.c b/test/PCH/line-directive.c
new file mode 100644
index 000000000000..53edb3c06b8c
--- /dev/null
+++ b/test/PCH/line-directive.c
@@ -0,0 +1,25 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/line-directive.h -fsyntax-only %s 2>&1|grep "25:5" &&
+
+// Test with pch.
+// RUN: clang-cc -emit-pch -o %t %S/line-directive.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only %s 2>&1|grep "25:5"
+
+double x; // expected-error{{redefinition of 'x' with a different type}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// expected-note{{previous definition is here}}
diff --git a/test/PCH/line-directive.h b/test/PCH/line-directive.h
new file mode 100644
index 000000000000..c5594b420e65
--- /dev/null
+++ b/test/PCH/line-directive.h
@@ -0,0 +1,2 @@
+#line 25 "line-directive.c"
+int x;
diff --git a/test/PCH/method_pool.h b/test/PCH/method_pool.h
new file mode 100644
index 000000000000..f7af9044d92d
--- /dev/null
+++ b/test/PCH/method_pool.h
@@ -0,0 +1,37 @@
+/* For use with the method_pool.m test */
+
+/* Whitespace below is significant */
+
+
+
+
+
+
+
+
+
+
+
+@interface TestMethodPool1
++ alloc;
+- (double)instMethod:(int)foo;
+@end
+
+@interface TestMethodPool2
+- (char)instMethod:(int)foo;
+@end
+
+@implementation TestMethodPool1
++ alloc {
+}
+
+- (double)instMethod:(int)foo {
+ return foo;
+}
+@end
+
+@implementation TestMethodPool2
+- (char)instMethod:(int)foo {
+ return foo;
+}
+@end
diff --git a/test/PCH/method_pool.m b/test/PCH/method_pool.m
new file mode 100644
index 000000000000..8dd7834f1dab
--- /dev/null
+++ b/test/PCH/method_pool.m
@@ -0,0 +1,21 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/method_pool.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -x=objective-c -emit-pch -o %t %S/method_pool.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
+
+int message_id(id x) {
+ return [x instMethod:17]; // expected-warning{{multiple methods}}
+}
+
+
+
+
+
+/* Whitespace below is significant */
+/* expected-note{{using}} */
+
+
+
+/* expected-note{{also}} */
diff --git a/test/PCH/multiple_decls.c b/test/PCH/multiple_decls.c
new file mode 100644
index 000000000000..4b2fc6247ce7
--- /dev/null
+++ b/test/PCH/multiple_decls.c
@@ -0,0 +1,17 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/multiple_decls.h -fsyntax-only -ast-print -o - %s &&
+
+// Test with pch.
+// RUN: clang-cc -emit-pch -o %t %S/multiple_decls.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -ast-print -o - %s
+
+void f0(char c) {
+ wide(c);
+}
+
+struct wide w;
+struct narrow n;
+
+void f1(int i) {
+ narrow(i);
+}
diff --git a/test/PCH/multiple_decls.h b/test/PCH/multiple_decls.h
new file mode 100644
index 000000000000..23696b0470dc
--- /dev/null
+++ b/test/PCH/multiple_decls.h
@@ -0,0 +1,7 @@
+// Header for PCH test multiple_decls.c
+
+struct wide { int value; };
+int wide(char);
+
+struct narrow { char narrow; };
+char narrow(int);
diff --git a/test/PCH/nonvisible-external-defs.c b/test/PCH/nonvisible-external-defs.c
new file mode 100644
index 000000000000..bfe5ccab20a3
--- /dev/null
+++ b/test/PCH/nonvisible-external-defs.c
@@ -0,0 +1,10 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/nonvisible-external-defs.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -emit-pch -o %t %S/nonvisible-external-defs.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
+
+int g(int, float); // expected-error{{conflicting types}}
+
+// expected-note{{previous declaration}}
diff --git a/test/PCH/nonvisible-external-defs.h b/test/PCH/nonvisible-external-defs.h
new file mode 100644
index 000000000000..a36fc2ea468c
--- /dev/null
+++ b/test/PCH/nonvisible-external-defs.h
@@ -0,0 +1,11 @@
+// Helper for PCH test nonvisible-external-defs.h
+
+
+
+
+
+
+
+void f() {
+ extern int g(int, int);
+}
diff --git a/test/PCH/objc_exprs.h b/test/PCH/objc_exprs.h
new file mode 100644
index 000000000000..b811430c2e89
--- /dev/null
+++ b/test/PCH/objc_exprs.h
@@ -0,0 +1,18 @@
+
+@protocol foo;
+@class itf;
+
+// Expressions
+typedef typeof(@"foo" "bar") objc_string;
+typedef typeof(@encode(int)) objc_encode;
+typedef typeof(@protocol(foo)) objc_protocol;
+typedef typeof(@selector(noArgs)) objc_selector_noArgs;
+typedef typeof(@selector(oneArg:)) objc_selector_oneArg;
+typedef typeof(@selector(foo:bar:)) objc_selector_twoArg;
+
+
+// Types.
+typedef typeof(id<foo>) objc_id_protocol_ty;
+
+typedef typeof(itf*) objc_interface_ty;
+typedef typeof(itf<foo>*) objc_qual_interface_ty;
diff --git a/test/PCH/objc_exprs.m b/test/PCH/objc_exprs.m
new file mode 100644
index 000000000000..eb1ae434a7e0
--- /dev/null
+++ b/test/PCH/objc_exprs.m
@@ -0,0 +1,28 @@
+// Test this without pch.
+// RUN: clang-cc -fblocks -include %S/objc_exprs.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -x objective-c-header -emit-pch -fblocks -o %t %S/objc_exprs.h &&
+// RUN: clang-cc -fblocks -include-pch %t -fsyntax-only -verify %s
+
+// Expressions
+int *A1 = (objc_string)0; // expected-warning {{'struct objc_object *'}}
+
+char A2 = (objc_encode){}; // expected-error {{not a compile-time constant}} \
+ expected-warning {{char [2]}}
+
+int *A3 = (objc_protocol)0; // expected-warning {{aka 'Protocol *'}}
+
+
+// Types.
+int *T0 = (objc_id_protocol_ty)0; // expected-error {{not a compile-time constant}} \
+ expected-warning {{aka 'id<foo>'}}
+
+int *T1 = (objc_interface_ty)0; // expected-warning {{aka 'itf *'}}
+int *T2 = (objc_qual_interface_ty)0; // expected-warning {{aka 'itf<foo> *'}}
+
+objc_selector_noArgs s1;
+objc_selector_oneArg s2;
+objc_selector_twoArg s3;
+
+
diff --git a/test/PCH/objc_import.h b/test/PCH/objc_import.h
new file mode 100644
index 000000000000..8af87ab25c7d
--- /dev/null
+++ b/test/PCH/objc_import.h
@@ -0,0 +1,7 @@
+/* For use with the objc_import.m test */
+
+@interface TestPCH
++ alloc;
+- (void)instMethod;
+@end
+
diff --git a/test/PCH/objc_import.m b/test/PCH/objc_import.m
new file mode 100644
index 000000000000..86c1c25ae5c9
--- /dev/null
+++ b/test/PCH/objc_import.m
@@ -0,0 +1,15 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/objc_import.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -x=objective-c -emit-pch -o %t %S/objc_import.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
+
+#import "objc_import.h"
+
+void func() {
+ TestPCH *xx;
+
+ xx = [TestPCH alloc];
+ [xx instMethod];
+}
diff --git a/test/PCH/objc_methods.h b/test/PCH/objc_methods.h
new file mode 100644
index 000000000000..4c6b1e1ccec0
--- /dev/null
+++ b/test/PCH/objc_methods.h
@@ -0,0 +1,11 @@
+/* For use with the methods.m test */
+
+@interface TestPCH
++ alloc;
+- (void)instMethod;
+@end
+
+@class TestForwardClassDecl;
+
+// FIXME: @compatibility_alias AliasForTestPCH TestPCH;
+
diff --git a/test/PCH/objc_methods.m b/test/PCH/objc_methods.m
new file mode 100644
index 000000000000..1a198b18d380
--- /dev/null
+++ b/test/PCH/objc_methods.m
@@ -0,0 +1,16 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/objc_methods.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -x=objective-c -emit-pch -o %t %S/objc_methods.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
+
+void func() {
+ TestPCH *xx;
+ TestForwardClassDecl *yy;
+// FIXME:
+// AliasForTestPCH *zz;
+
+ xx = [TestPCH alloc];
+ [xx instMethod];
+}
diff --git a/test/PCH/objc_property.h b/test/PCH/objc_property.h
new file mode 100644
index 000000000000..2432370be4e8
--- /dev/null
+++ b/test/PCH/objc_property.h
@@ -0,0 +1,12 @@
+/* For use with the objc_property.m PCH test */
+@interface TestProperties
+{
+ int value;
+ float percentage;
+}
+
++ alloc;
+
+@property int value;
+@property float percentage;
+@end
diff --git a/test/PCH/objc_property.m b/test/PCH/objc_property.m
new file mode 100644
index 000000000000..5cf6de759375
--- /dev/null
+++ b/test/PCH/objc_property.m
@@ -0,0 +1,11 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/objc_property.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -x=objective-c -emit-pch -o %t %S/objc_property.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
+
+void func() {
+ TestProperties *xx = [TestProperties alloc];
+ xx.value = 5;
+}
diff --git a/test/PCH/preprocess.c b/test/PCH/preprocess.c
new file mode 100644
index 000000000000..128cc0acb973
--- /dev/null
+++ b/test/PCH/preprocess.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -emit-pch -o %t %S/preprocess.h &&
+// RUN: clang-cc -include-pch %t -E -o - %s | grep -c "a_typedef" | count 1
+#include "preprocess.h"
+
+int a_value;
diff --git a/test/PCH/preprocess.h b/test/PCH/preprocess.h
new file mode 100644
index 000000000000..39fa006181f2
--- /dev/null
+++ b/test/PCH/preprocess.h
@@ -0,0 +1,7 @@
+// Helper header for preprocess.c PCH test
+#ifndef PREPROCESS_H
+#define PREPROCESS_H
+
+typedef int a_typedef;
+
+#endif // PREPROCESS_H
diff --git a/test/PCH/stmts.c b/test/PCH/stmts.c
new file mode 100644
index 000000000000..0d906f291f2c
--- /dev/null
+++ b/test/PCH/stmts.c
@@ -0,0 +1,14 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/stmts.h -fsyntax-only -emit-llvm -o - %s &&
+
+// Test with pch.
+// RUN: clang-cc -emit-pch -o %t %S/stmts.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -emit-llvm -o - %s
+
+void g0(void) { f0(5); }
+int g1(int x) { return f1(x); }
+const char* query_name(void) { return what_is_my_name(); }
+
+int use_computed_goto(int x) { return computed_goto(x); }
+
+int get_weird_max(int x, int y) { return weird_max(x, y); }
diff --git a/test/PCH/stmts.h b/test/PCH/stmts.h
new file mode 100644
index 000000000000..4267e2c2b352
--- /dev/null
+++ b/test/PCH/stmts.h
@@ -0,0 +1,96 @@
+// Header for PCH test stmts.c
+
+void f0(int x) {
+ // NullStmt
+ ;
+ // IfStmt
+ if (x) {
+ } else if (x + 1) {
+ }
+
+ switch (x) {
+ case 0:
+ x = 17;
+ break;
+
+ case 1:
+ break;
+
+ default:
+ switch (x >> 1) {
+ case 7:
+ // fall through
+ case 9:
+ break;
+ }
+ x += 2;
+ break;
+ }
+
+ while (x > 20) {
+ if (x > 30) {
+ --x;
+ continue;
+ } else if (x < 5)
+ break;
+ else
+ goto done;
+ }
+
+ do {
+ x++;
+ } while (x < 10);
+
+ almost_done:
+ for (int y = x; y < 20; ++y) {
+ if (x + y == 12)
+ return;
+ else if (x - y == 7)
+ goto almost_done;
+ }
+
+ done:
+ x = x + 2;
+
+ int z = x, *y, j = 5;
+}
+
+int f1(int x) {
+ switch (x) {
+ case 17:
+ return 12;
+
+ default:
+ break;
+ }
+
+ // variable-length array
+ int array[x * 17 + 3];
+
+ return x*2;
+}
+
+const char* what_is_my_name(void) { return __func__; }
+
+int computed_goto(int x) {
+ start:
+ x = x << 1;
+ void *location = &&start;
+
+ if (x > 17)
+ location = &&done;
+
+ while (x > 12) {
+ --x;
+ if (x == 15)
+ goto *location;
+ }
+
+ done:
+ return 5;
+}
+
+#define maxint(a,b) ({int _a = (a), _b = (b); _a > _b ? _a : _b; })
+int weird_max(int x, int y) {
+ return maxint(++x, --y);
+}
diff --git a/test/PCH/struct.c b/test/PCH/struct.c
new file mode 100644
index 000000000000..f1e28115d0d7
--- /dev/null
+++ b/test/PCH/struct.c
@@ -0,0 +1,28 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/struct.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -emit-pch -o %t %S/struct.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
+
+struct Point *p1;
+
+float getX(struct Point *p1) {
+ return p1->x;
+}
+
+void *get_fun_ptr() {
+ return fun->is_ptr? fun->ptr : 0;
+}
+
+struct Fun2 {
+ int very_fun;
+};
+
+int get_very_fun() {
+ return fun2->very_fun;
+}
+
+int *int_ptr_fail = &fun->is_ptr; // expected-error{{address of bit-field requested}}
+
+struct Nested nested = { 1, 2 };
diff --git a/test/PCH/struct.h b/test/PCH/struct.h
new file mode 100644
index 000000000000..2ffdd4aea586
--- /dev/null
+++ b/test/PCH/struct.h
@@ -0,0 +1,29 @@
+// Used with the struct.c test
+
+struct Point {
+ float x, y, z;
+};
+
+struct Point2 {
+ float xValue, yValue, zValue;
+};
+
+struct Fun;
+
+struct Fun *fun;
+
+struct Fun {
+ int is_ptr : 1;
+
+ union {
+ void *ptr;
+ int *integer;
+ };
+};
+
+struct Fun2;
+struct Fun2 *fun2;
+
+struct S {
+ struct Nested { int x, y; } nest;
+};
diff --git a/test/PCH/tentative-defs.c b/test/PCH/tentative-defs.c
new file mode 100644
index 000000000000..980cfab0834b
--- /dev/null
+++ b/test/PCH/tentative-defs.c
@@ -0,0 +1,9 @@
+// Test with pch.
+// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-pch -o %t.pch %S/tentative-defs.h &&
+// RUN: clang-cc -triple x86_64-apple-darwin9 -include-pch %t.pch -verify -emit-llvm -o %t %s &&
+
+// RUN: grep "@variable = common global i32 0" %t | count 1 &&
+// RUN: grep "@incomplete_array = common global .*1 x i32" %t | count 1
+
+
+// FIXME: tentative-defs.h expected-warning{{tentative}}
diff --git a/test/PCH/tentative-defs.h b/test/PCH/tentative-defs.h
new file mode 100644
index 000000000000..4675d9a62eac
--- /dev/null
+++ b/test/PCH/tentative-defs.h
@@ -0,0 +1,9 @@
+// Header for PCH test tentative-defs.c
+int variable;
+
+
+
+
+
+
+int incomplete_array[];
diff --git a/test/PCH/types.c b/test/PCH/types.c
new file mode 100644
index 000000000000..c111c9ea7459
--- /dev/null
+++ b/test/PCH/types.c
@@ -0,0 +1,72 @@
+// Test this without pch.
+// RUN: clang-cc -fblocks -include %S/types.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -emit-pch -fblocks -o %t %S/types.h &&
+// RUN: clang-cc -fblocks -include-pch %t -fsyntax-only -verify %s
+
+typedef int INT;
+INT int_value;
+
+__attribute__((address_space(1))) int int_as_one;
+
+// TYPE_EXT_QUAL
+ASInt *as_int_ptr1 = &int_value; // expected-error{{different address spaces}} \
+ // FIXME: expected-warning{{discards qualifiers}}
+ASInt *as_int_ptr2 = &int_as_one;
+
+// FIXME: TYPE_FIXED_WIDTH_INT
+
+// TYPE_COMPLEX
+_Complex float Cfloat_val;
+Cfloat *Cfloat_ptr = &Cfloat_val;
+
+// TYPE_POINTER
+int_ptr int_value_ptr = &int_value;
+
+// TYPE_BLOCK_POINTER
+void test_block_ptr(Block *bl) {
+ *bl = ^(int x, float f) { return x; };
+}
+
+// TYPE_CONSTANT_ARRAY
+five_ints fvi = { 1, 2, 3, 4, 5 };
+
+// TYPE_INCOMPLETE_ARRAY
+float_array fa1 = { 1, 2, 3 };
+float_array fa2 = { 1, 2, 3, 4, 5, 6, 7, 8 };
+
+// TYPE_VARIABLE_ARRAY in stmts.[ch]
+
+// TYPE_VECTOR
+float4 f4 = { 1.0, 2.0, 3.0, 4.0 };
+
+// TYPE_EXT_VECTOR
+ext_float4 ef4 = { 1.0, 2.0, 3.0, 4.0 };
+
+// TYPE_FUNCTION_NO_PROTO
+noproto np1;
+int np1(x, y)
+ int x;
+ float y;
+{
+ return x;
+}
+
+// TYPE_FUNCTION_PROTO
+proto p1;
+float p1(float x, float y, ...) {
+ return x + y;
+}
+proto *p2 = p1;
+
+// TYPE_TYPEDEF
+int_ptr_ptr ipp = &int_value_ptr;
+
+// TYPE_TYPEOF_EXPR
+typeof_17 *t17 = &int_value;
+struct S { int x, y; };
+typeof_17 t17_2 = (struct S){1, 2}; // expected-error{{incompatible type initializing}}
+
+// TYPE_TYPEOF
+int_ptr_ptr2 ipp2 = &int_value_ptr;
diff --git a/test/PCH/types.h b/test/PCH/types.h
new file mode 100644
index 000000000000..df9f5c8607f7
--- /dev/null
+++ b/test/PCH/types.h
@@ -0,0 +1,44 @@
+/* Used with the types.c test */
+
+// TYPE_EXT_QUAL
+typedef __attribute__((address_space(1))) int ASInt;
+
+// FIXME: TYPE_FIXED_WIDTH_INT
+
+// TYPE_COMPLEX
+typedef _Complex float Cfloat;
+
+// TYPE_POINTER
+typedef int * int_ptr;
+
+// TYPE_BLOCK_POINTER
+typedef int (^Block)(int, float);
+
+// TYPE_CONSTANT_ARRAY
+typedef int five_ints[5];
+
+// TYPE_INCOMPLETE_ARRAY
+typedef float float_array[];
+
+// TYPE_VARIABLE_ARRAY in stmts.[ch]
+
+// TYPE_VECTOR
+typedef float float4 __attribute__((vector_size(16)));
+
+// TYPE_EXT_VECTOR
+typedef float ext_float4 __attribute__((ext_vector_type(4)));
+
+// TYPE_FUNCTION_NO_PROTO
+typedef int noproto();
+
+// TYPE_FUNCTION_PROTO
+typedef float proto(float, float, ...);
+
+// TYPE_TYPEDEF
+typedef int_ptr * int_ptr_ptr;
+
+// TYPE_TYPEOF_EXPR
+typedef typeof(17) typeof_17;
+
+// TYPE_TYPEOF
+typedef typeof(int_ptr *) int_ptr_ptr2;
diff --git a/test/PCH/va_arg.c b/test/PCH/va_arg.c
new file mode 100644
index 000000000000..75cee06d656f
--- /dev/null
+++ b/test/PCH/va_arg.c
@@ -0,0 +1,12 @@
+// Test this without pch.
+// RUN: clang-cc -triple=x86_64-unknown-freebsd7.0 -include %S/va_arg.h %s -emit-llvm -o - &&
+
+// Test with pch.
+// RUN: clang-cc -triple=x86_64-unknown-freebsd7.0 -emit-pch -o %t %S/va_arg.h &&
+// RUN: clang-cc -triple=x86_64-unknown-freebsd7.0 -include-pch %t %s -emit-llvm -o -
+
+char *g0(char** argv, int argc) { return argv[argc]; }
+
+char *g(char **argv) {
+ f(g0, argv, 1, 2, 3);
+}
diff --git a/test/PCH/va_arg.h b/test/PCH/va_arg.h
new file mode 100644
index 000000000000..4a8e5102bc6d
--- /dev/null
+++ b/test/PCH/va_arg.h
@@ -0,0 +1,8 @@
+// Header for PCH test va_arg.c
+
+typedef __builtin_va_list va_list;
+char *f (char * (*g) (char **, int), char **p, ...) {
+ char *s;
+ va_list v;
+ s = g (p, __builtin_va_arg(v, int));
+}
diff --git a/test/PCH/variables.c b/test/PCH/variables.c
new file mode 100644
index 000000000000..c988a59ce605
--- /dev/null
+++ b/test/PCH/variables.c
@@ -0,0 +1,23 @@
+// Test this without pch.
+// RUN: clang-cc -include %S/variables.h -fsyntax-only -verify %s &&
+
+// Test with pch.
+// RUN: clang-cc -emit-pch -o %t %S/variables.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
+
+int *ip2 = &x;
+float *fp = &ip; // expected-warning{{incompatible pointer types}}
+// FIXME:variables.h expected-note{{previous}}
+double z; // expected-error{{redefinition}}
+// FIXME:variables.h expected-note{{previous}}
+int z2 = 18; // expected-error{{redefinition}}
+double VeryHappy; // expected-error{{redefinition}}
+// FIXME:variables.h expected-note{{previous definition is here}}
+
+int Q = A_MACRO_IN_THE_PCH;
+
+int R = FUNCLIKE_MACRO(A_MACRO_, IN_THE_PCH);
+
+
+int UNIQUE(a); // a2
+int *Arr[] = { &a0, &a1, &a2 };
diff --git a/test/PCH/variables.h b/test/PCH/variables.h
new file mode 100644
index 000000000000..70aec6518091
--- /dev/null
+++ b/test/PCH/variables.h
@@ -0,0 +1,26 @@
+// RUN: clang-cc -emit-pch -o variables.h.pch variables.h
+// Do not mess with the whitespace in this file. It's important.
+
+
+
+
+extern float y;
+extern int *ip, x;
+
+float z;
+
+int z2 = 17;
+
+#define MAKE_HAPPY(X) X##Happy
+int MAKE_HAPPY(Very);
+
+#define A_MACRO_IN_THE_PCH 492
+#define FUNCLIKE_MACRO(X, Y) X ## Y
+
+#define PASTE2(x,y) x##y
+#define PASTE1(x,y) PASTE2(x,y)
+#define UNIQUE(x) PASTE1(x,__COUNTER__)
+
+int UNIQUE(a); // a0
+int UNIQUE(a); // a1
+
diff --git a/test/Parser/2008-10-31-parse-noop-failure.c b/test/Parser/2008-10-31-parse-noop-failure.c
new file mode 100755
index 000000000000..0598ea7dc9e7
--- /dev/null
+++ b/test/Parser/2008-10-31-parse-noop-failure.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -verify -parse-noop %t
+
+void add_attribute(id) int id; {}
+
diff --git a/test/Parser/CompoundStmtScope.c b/test/Parser/CompoundStmtScope.c
new file mode 100644
index 000000000000..6a404aa3a2c6
--- /dev/null
+++ b/test/Parser/CompoundStmtScope.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int foo() {
+ {
+ typedef float X;
+ }
+ X Y; // expected-error {{use of undeclared identifier}}
+}
diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c
new file mode 100644
index 000000000000..6f5622e93932
--- /dev/null
+++ b/test/Parser/MicrosoftExtensions.c
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify -fms-extensions -x=objective-c++ %s
+__stdcall int func0();
+int __stdcall func();
+typedef int (__cdecl *tptr)();
+void (*__fastcall fastpfunc)();
+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 );
+}
+__forceinline InterlockedBitTestAndSet (long *Base, long Bit) // expected-warning {{type specifier missing, defaults to 'int'}}
+{
+ __asm {
+ mov eax, Bit
+ mov ecx, Base
+ lock bts [ecx], eax
+ setc al
+ };
+}
+
+void *_alloca(int);
+
+void foo() {
+ __declspec(align(16)) int *buffer = (int *)_alloca(9);
+}
+
+typedef bool (__stdcall __stdcall *blarg)(int);
diff --git a/test/Parser/argument_qualified.c b/test/Parser/argument_qualified.c
new file mode 100644
index 000000000000..c9494e7373a0
--- /dev/null
+++ b/test/Parser/argument_qualified.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc %s
+int abc (const float x) {
+ return 1;
+}
+
diff --git a/test/Parser/argument_redef.c b/test/Parser/argument_redef.c
new file mode 100644
index 000000000000..1a43178a40cd
--- /dev/null
+++ b/test/Parser/argument_redef.c
@@ -0,0 +1,6 @@
+/* RUN: clang-cc -fsyntax-only -verify %s
+*/
+
+int foo(int A) { /* expected-note {{previous definition is here}} */
+ int A; /* expected-error {{redefinition of 'A'}} */
+}
diff --git a/test/Parser/argument_scope.c b/test/Parser/argument_scope.c
new file mode 100644
index 000000000000..5e6f439cfdf8
--- /dev/null
+++ b/test/Parser/argument_scope.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only %s
+typedef struct foo foo;
+
+void blah(int foo) {
+ foo = 1;
+}
diff --git a/test/Parser/asm.c b/test/Parser/asm.c
new file mode 100644
index 000000000000..9cf9046aab6a
--- /dev/null
+++ b/test/Parser/asm.c
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f1() {
+ asm ("ret" : : :); // expected-error {{expected string literal}}
+}
+
+void f2() {
+ asm("foo" : "=r" (a)); // expected-error {{use of undeclared identifier 'a'}}
+ asm("foo" : : "r" (b)); // expected-error {{use of undeclared identifier 'b'}}
+}
+
+
+// rdar://5952468
+__asm ; // expected-error {{expected '(' after 'asm'}}
+
diff --git a/test/Parser/attributes.c b/test/Parser/attributes.c
new file mode 100644
index 000000000000..dc2bb02670c6
--- /dev/null
+++ b/test/Parser/attributes.c
@@ -0,0 +1,53 @@
+// RUN: clang-cc -fsyntax-only -verify %s -pedantic -std=c99
+
+int __attribute__(()) x;
+
+__inline void __attribute__((__always_inline__, __nodebug__))
+foo(void) {
+}
+
+
+__attribute__(()) y; // expected-warning {{defaults to 'int'}}
+
+// PR2796
+int (__attribute__(()) *z)(long y);
+
+
+void f1(__attribute__(()) int x);
+
+int f2(y, __attribute__(()) x); // expected-error {{expected identifier}}
+
+// This is parsed as a normal argument list (with two args that are implicit
+// int) because the __attribute__ is a declspec.
+void f3(__attribute__(()) x, // expected-warning {{defaults to 'int'}}
+ y); // expected-warning {{defaults to 'int'}}
+
+void f4(__attribute__(())); // expected-error {{expected parameter declarator}}
+
+
+// This is ok, the __attribute__ applies to the pointer.
+int baz(int (__attribute__(()) *x)(long y));
+
+void g1(void (*f1)(__attribute__(()) int x));
+void g2(int (*f2)(y, __attribute__(()) x)); // expected-error {{expected identifier}}
+void g3(void (*f3)(__attribute__(()) x, int y)); // expected-warning {{defaults to 'int'}}
+void g4(void (*f4)(__attribute__(()))); // expected-error {{expected parameter declarator}}
+
+
+void (*h1)(void (*f1)(__attribute__(()) int x));
+void (*h2)(int (*f2)(y, __attribute__(()) x)); // expected-error {{expected identifier}}
+
+void (*h3)(void (*f3)(__attribute__(()) x)); // expected-warning {{defaults to 'int'}}
+void (*h4)(void (*f4)(__attribute__(()))); // expected-error {{expected parameter declarator}}
+
+
+
+// rdar://6131260
+int foo42(void) {
+ int x, __attribute__((unused)) y, z;
+ return 0;
+}
+
+// rdar://6096491
+void __attribute__((noreturn)) d0(void), __attribute__((noreturn)) d1(void);
+
diff --git a/test/Parser/bad-control.c b/test/Parser/bad-control.c
new file mode 100644
index 000000000000..6e59667c3549
--- /dev/null
+++ b/test/Parser/bad-control.c
@@ -0,0 +1,9 @@
+/* RUN: clang-cc -fsyntax-only -verify %s
+*/
+int foo() {
+ break; /* expected-error {{'break' statement not in loop or switch statement}} */
+}
+
+int foo2() {
+ continue; /* expected-error {{'continue' statement not in loop statement}} */
+}
diff --git a/test/Parser/block-block-storageclass.c b/test/Parser/block-block-storageclass.c
new file mode 100644
index 000000000000..d24ec5f1c698
--- /dev/null
+++ b/test/Parser/block-block-storageclass.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fsyntax-only -verify -parse-noop %s
+#if 0
+#include <stdio.h>
+void _Block_byref_release(void*src){}
+
+int main() {
+ __block int X = 1234;
+ __block const char * message = "HELLO";
+
+ X = X - 1234;
+
+ X += 1;
+
+ printf ("%s(%d)\n", message, X);
+ X -= 1;
+
+ return X;
+}
+#endif
diff --git a/test/Parser/block-pointer-decl.c b/test/Parser/block-pointer-decl.c
new file mode 100644
index 000000000000..7a21651bad32
--- /dev/null
+++ b/test/Parser/block-pointer-decl.c
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -verify -parse-noop -fblocks %s
+
+struct blockStruct {
+ int (^a)(float, int);
+ int b;
+};
+
+int blockTaker (int (^myBlock)(int), int other_input)
+{
+ return 5 * myBlock (other_input);
+}
+
+int main (int argc, char **argv)
+{
+ int (^blockptr) (int) = ^(int inval) {
+ printf ("Inputs: %d, %d.\n", argc, inval);
+ return argc * inval;
+ };
+
+
+ argc = 10;
+ printf ("I got: %d.\n",
+ blockTaker (blockptr, 6));
+ return 0;
+}
+
diff --git a/test/Parser/builtin_classify_type.c b/test/Parser/builtin_classify_type.c
new file mode 100644
index 000000000000..7046310eb4a8
--- /dev/null
+++ b/test/Parser/builtin_classify_type.c
@@ -0,0 +1,21 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct foo { int a; };
+
+int main() {
+ int a;
+ float b;
+ double d;
+ struct foo s;
+
+ static int ary[__builtin_classify_type(a)];
+ static int ary2[(__builtin_classify_type)(a)]; // expected-error{{variable length array declaration can not have 'static' storage duration}}
+ static int ary3[(*__builtin_classify_type)(a)]; // expected-error{{variable length array declaration can not have 'static' storage duration}}
+
+ int result;
+
+ result = __builtin_classify_type(a);
+ result = __builtin_classify_type(b);
+ result = __builtin_classify_type(d);
+ result = __builtin_classify_type(s);
+}
diff --git a/test/Parser/builtin_types_compatible.c b/test/Parser/builtin_types_compatible.c
new file mode 100644
index 000000000000..0664a9f55641
--- /dev/null
+++ b/test/Parser/builtin_types_compatible.c
@@ -0,0 +1,43 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+extern int funcInt(int);
+extern float funcFloat(float);
+extern double funcDouble(double);
+// figure out why "char *" doesn't work (with gcc, nothing to do with clang)
+//extern void funcCharPtr(char *);
+
+#define func(expr) \
+ do { \
+ typeof(expr) tmp; \
+ if (__builtin_types_compatible_p(typeof(expr), int)) funcInt(tmp); \
+ else if (__builtin_types_compatible_p(typeof(expr), float)) funcFloat(tmp); \
+ else if (__builtin_types_compatible_p(typeof(expr), double)) funcDouble(tmp); \
+ } while (0)
+#define func_choose(expr) \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(expr), int), funcInt(expr), \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(expr), float), funcFloat(expr), \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(expr), double), funcDouble(expr), (void)0)))
+
+static void test()
+{
+ int a;
+ float b;
+ double d;
+
+ func(a);
+ func(b);
+ func(d);
+ a = func_choose(a);
+ b = func_choose(b);
+ d = func_choose(d);
+
+ int c;
+ struct xx { int a; } x, y;
+
+ c = __builtin_choose_expr(a+3-7, b, x); // expected-error{{'__builtin_choose_expr' requires a constant expression}}
+ c = __builtin_choose_expr(0, b, x); // expected-error{{incompatible type assigning 'struct xx', expected 'int'}}
+ c = __builtin_choose_expr(5+3-7, b, x);
+ y = __builtin_choose_expr(4+3-7, b, x);
+
+}
+
diff --git a/test/Parser/c-namespace.c b/test/Parser/c-namespace.c
new file mode 100644
index 000000000000..ffca15e6a2eb
--- /dev/null
+++ b/test/Parser/c-namespace.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only %s
+void bla1() {
+ struct XXX;
+ int XXX;
+}
+
diff --git a/test/Parser/char-literal-printing.c b/test/Parser/char-literal-printing.c
new file mode 100644
index 000000000000..f6ad0ff511be
--- /dev/null
+++ b/test/Parser/char-literal-printing.c
@@ -0,0 +1,31 @@
+// RUN: clang-cc -ast-print %s
+
+#include <stddef.h>
+
+char test1(void) { return '\\'; }
+wchar_t test2(void) { return L'\\'; }
+char test3(void) { return '\''; }
+wchar_t test4(void) { return L'\''; }
+char test5(void) { return '\a'; }
+wchar_t test6(void) { return L'\a'; }
+char test7(void) { return '\b'; }
+wchar_t test8(void) { return L'\b'; }
+char test9(void) { return '\e'; }
+wchar_t test10(void) { return L'\e'; }
+char test11(void) { return '\f'; }
+wchar_t test12(void) { return L'\f'; }
+char test13(void) { return '\n'; }
+wchar_t test14(void) { return L'\n'; }
+char test15(void) { return '\r'; }
+wchar_t test16(void) { return L'\r'; }
+char test17(void) { return '\t'; }
+wchar_t test18(void) { return L'\t'; }
+char test19(void) { return '\v'; }
+wchar_t test20(void) { return L'\v'; }
+
+char test21(void) { return 'c'; }
+wchar_t test22(void) { return L'c'; }
+char test23(void) { return '\x3'; }
+wchar_t test24(void) { return L'\x3'; }
+
+wchar_t test25(void) { return L'\x333'; }
diff --git a/test/Parser/check-objc2-syntax-1.m b/test/Parser/check-objc2-syntax-1.m
new file mode 100644
index 000000000000..f596e9ba0f37
--- /dev/null
+++ b/test/Parser/check-objc2-syntax-1.m
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface Subclass
++ (int)magicNumber;
+@end
+
+int main (void) {
+ return Subclass.magicNumber;
+}
+
diff --git a/test/Parser/check-syntax-1.m b/test/Parser/check-syntax-1.m
new file mode 100644
index 000000000000..f4aa430cde18
--- /dev/null
+++ b/test/Parser/check-syntax-1.m
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int @interface bla ; // expected-error {{cannot combine with previous 'int' declaration specifier}}
+@end
diff --git a/test/Parser/check_cast.c b/test/Parser/check_cast.c
new file mode 100644
index 000000000000..4df851c7bf9f
--- /dev/null
+++ b/test/Parser/check_cast.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct foo {
+ int a;
+};
+
+int main() {
+ struct foo xxx;
+ int i;
+
+ xxx = (struct foo)1; // expected-error {{used type 'struct foo' where arithmetic or pointer type is required}}
+ i = (int)xxx; // expected-error {{operand of type 'struct foo' where arithmetic or pointer type is required}}
+}
diff --git a/test/Parser/compound_literal.c b/test/Parser/compound_literal.c
new file mode 100644
index 000000000000..c263763b2e2a
--- /dev/null
+++ b/test/Parser/compound_literal.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+int main() {
+ char *s;
+ s = (char []){"whatever"};
+}
diff --git a/test/Parser/control-scope.c b/test/Parser/control-scope.c
new file mode 100644
index 000000000000..7ffc6ac46c0f
--- /dev/null
+++ b/test/Parser/control-scope.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc %s -std=c90 -verify &&
+// RUN: clang-cc %s -std=c99
+
+int f (int z) {
+ if (z + sizeof (enum {a})) // expected-note {{previous definition is here}}
+ return 1 + sizeof (enum {a}); // expected-error {{redefinition of enumerator 'a'}}
+ return 0;
+}
diff --git a/test/Parser/cxx-ambig-paren-expr.cpp b/test/Parser/cxx-ambig-paren-expr.cpp
new file mode 100644
index 000000000000..6f23b35d3e6b
--- /dev/null
+++ b/test/Parser/cxx-ambig-paren-expr.cpp
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+
+void f() {
+ typedef int T;
+ int x, *px;
+
+ // Type id.
+ (T())x; // expected-error {{used type 'T (void)'}}
+ (T())+x; // expected-error {{used type 'T (void)'}}
+ (T())*px; // expected-error {{used type 'T (void)'}}
+
+ // Expression.
+ x = (T());
+ x = (T())/x;
+
+ typedef int *PT;
+ // Make sure stuff inside the parens are parsed only once (only one warning).
+ x = (PT()[(int){1}]); // expected-warning {{compound literals}}
+
+ // Special case: empty parens is a call, not an expression
+ struct S{int operator()();};
+ (S())();
+
+ // FIXME: Special case: "++" is postfix here, not prefix
+ // (S())++;
+}
diff --git a/test/Parser/cxx-bool.cpp b/test/Parser/cxx-bool.cpp
new file mode 100644
index 000000000000..f0b3a9f9f038
--- /dev/null
+++ b/test/Parser/cxx-bool.cpp
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only %s
+
+bool a = true;
+bool b = false;
diff --git a/test/Parser/cxx-casting.cpp b/test/Parser/cxx-casting.cpp
new file mode 100644
index 000000000000..1fdc28d2c880
--- /dev/null
+++ b/test/Parser/cxx-casting.cpp
@@ -0,0 +1,36 @@
+// RUN: clang-cc -fsyntax-only %s
+
+char *const_cast_test(const char *var)
+{
+ return const_cast<char*>(var);
+}
+
+#if 0
+// FIXME: Uncomment when C++ is supported more.
+struct A {
+ virtual ~A() {}
+};
+
+struct B : public A {
+};
+
+struct B *dynamic_cast_test(struct A *a)
+{
+ return dynamic_cast<struct B*>(a);
+}
+#endif
+
+char *reinterpret_cast_test()
+{
+ return reinterpret_cast<char*>(0xdeadbeef);
+}
+
+double static_cast_test(int i)
+{
+ return static_cast<double>(i);
+}
+
+char postfix_expr_test()
+{
+ return reinterpret_cast<char*>(0xdeadbeef)[0];
+}
diff --git a/test/Parser/cxx-class.cpp b/test/Parser/cxx-class.cpp
new file mode 100644
index 000000000000..ff452b919114
--- /dev/null
+++ b/test/Parser/cxx-class.cpp
@@ -0,0 +1,38 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class C;
+class C {
+public:
+protected:
+ typedef int A,B;
+ static int sf(), u;
+
+ struct S {};
+ enum {};
+ int; // expected-error {{declaration does not declare anything}}
+ int : 1, : 2;
+
+public:
+ void m() {
+ int l = 2;
+ }
+ virtual int vf() const volatile = 0;
+
+private:
+ int x,f(),y,g();
+ inline int h();
+ static const int sci = 10;
+ mutable int mi;
+};
+void glo()
+{
+ struct local {};
+}
+
+// PR3177
+typedef union {
+ __extension__ union {
+ int a;
+ float b;
+ } y;
+} bug3177;
+
diff --git a/test/Parser/cxx-condition.cpp b/test/Parser/cxx-condition.cpp
new file mode 100644
index 000000000000..8fbca2a90f78
--- /dev/null
+++ b/test/Parser/cxx-condition.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-cc -parse-noop -verify %s
+
+void f() {
+ int a;
+ while (a) ;
+ while (int x) ; // expected-error {{expected '=' after declarator}}
+ while (float x = 0) ;
+ if (const int x = a) ;
+ switch (int x = a+10) {}
+ for (; int x = ++a; ) ;
+}
diff --git a/test/Parser/cxx-decl.cpp b/test/Parser/cxx-decl.cpp
new file mode 100644
index 000000000000..3fa284282ad6
--- /dev/null
+++ b/test/Parser/cxx-decl.cpp
@@ -0,0 +1,3 @@
+// RUN: clang-cc -verify -fsyntax-only %s
+
+int x(*g); // expected-error {{use of undeclared identifier 'g'}}
diff --git a/test/Parser/cxx-exception-spec.cpp b/test/Parser/cxx-exception-spec.cpp
new file mode 100644
index 000000000000..0a87ab702302
--- /dev/null
+++ b/test/Parser/cxx-exception-spec.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only %s
+
+struct X { };
+
+struct Y { };
+
+void f() throw() { }
+
+void g(int) throw(X) { }
+
+void h() throw(X, Y) { }
+
+class Class {
+ void foo() throw (X, Y) { }
+};
+
+void (*fptr)() throw();
diff --git a/test/Parser/cxx-friend.cpp b/test/Parser/cxx-friend.cpp
new file mode 100644
index 000000000000..ea30ddcbd0a8
--- /dev/null
+++ b/test/Parser/cxx-friend.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only %s
+
+class C {
+ friend class D;
+};
+
+class A {
+public:
+ void f();
+};
+
+class B {
+ // 'A' here should refer to the declaration above.
+ friend class A;
+
+ void f(A *a) { a->f(); }
+};
diff --git a/test/Parser/cxx-namespace-alias.cpp b/test/Parser/cxx-namespace-alias.cpp
new file mode 100644
index 000000000000..65e1459d379b
--- /dev/null
+++ b/test/Parser/cxx-namespace-alias.cpp
@@ -0,0 +1,8 @@
+// RUN: clang-cc -parse-noop -verify %s
+
+namespace A = B;
+
+namespace A = !; // expected-error {{expected namespace name}}
+namespace A = A::!; // expected-error {{expected namespace name}}
+
+
diff --git a/test/Parser/cxx-reference.cpp b/test/Parser/cxx-reference.cpp
new file mode 100644
index 000000000000..0d2b9d29c369
--- /dev/null
+++ b/test/Parser/cxx-reference.cpp
@@ -0,0 +1,21 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+extern char *bork;
+char *& bar = bork;
+
+int val;
+
+void foo(int &a) {
+}
+
+typedef int & A;
+
+void g(const A aref) {
+}
+
+int & const X = val; // expected-error {{'const' qualifier may not be applied to a reference}}
+int & volatile Y = val; // expected-error {{'volatile' qualifier may not be applied to a reference}}
+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-error {{rvalue references are only allowed in C++0x}}
diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp
new file mode 100644
index 000000000000..ae5d8f9e0cce
--- /dev/null
+++ b/test/Parser/cxx-template-decl.cpp
@@ -0,0 +1,82 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Errors
+export class foo { }; // expected-error {{expected template}}
+template x; // expected-error {{C++ requires a type specifier for all declarations}}
+export template x; // expected-error {{expected '<' after 'template'}} \
+ // expected-note {{exported templates are unsupported}} \
+// expected-error {{C++ requires a type specifier for all declarations}}
+// See Sema::ParsedFreeStandingDeclSpec about the double diagnostic. This is
+// because ParseNonTypeTemplateParameter starts parsing a DeclSpec.
+template < ; // expected-error {{parse error}} expected-error {{declaration does not declare anything}}
+template <template X> struct Err1; // expected-error {{expected '<' after 'template'}}
+template <template <typename> > struct Err2; // expected-error {{expected 'class' before '>'}}
+template <template <typename> Foo> struct Err3; // expected-error {{expected 'class' before 'Foo'}}
+
+// Template function declarations
+template <typename T> void foo();
+template <typename T, typename U> void foo();
+
+// Template function definitions.
+template <typename T> void foo() { }
+
+// Template class (forward) declarations
+template <typename T> struct A;
+template <typename T, typename U> struct b;
+template <typename> struct C;
+template <typename, typename> struct D;
+
+// Forward declarations with default parameters?
+template <typename T = int> class X1;
+template <typename = int> class X2;
+
+// Forward declarations w/template template parameters
+template <template <typename> class T> class TTP1;
+template <template <typename> class> class TTP2;
+template <template <typename> class T = foo> class TTP3; // FIXME:expected-error{{template argument for template template parameter must be a template}}
+template <template <typename> class = foo> class TTP3; // FIXME:expected-error{{template argument for template template parameter must be a template}}
+template <template <typename X, typename Y> class T> class TTP5;
+
+// Forward declararations with non-type params
+template <int> class NTP0;
+template <int N> class NTP1;
+template <int N = 5> class NTP2;
+template <int = 10> class NTP3;
+template <unsigned int N = 12u> class NTP4;
+template <unsigned int = 12u> class NTP5;
+template <unsigned = 15u> class NTP6;
+template <typename T, T Obj> class NTP7;
+
+// Template class declarations
+template <typename T> struct A { };
+template <typename T, typename U> struct B { };
+
+// Template parameter shadowing
+template<typename T, // expected-note{{template parameter is declared here}}
+ typename T> // expected-error{{declaration of 'T' shadows template parameter}}
+ void shadow1();
+
+template<typename T> // expected-note{{template parameter is declared here}}
+void shadow2(int T); // expected-error{{declaration of 'T' shadows template parameter}}
+
+template<typename T> // expected-note{{template parameter is declared here}}
+class T { // expected-error{{declaration of 'T' shadows template parameter}}
+};
+
+template<int Size> // expected-note{{template parameter is declared here}}
+void shadow3(int Size); // expected-error{{declaration of 'Size' shadows template parameter}}
+
+// Non-type template parameters in scope
+template<int Size>
+void f(int& i) {
+ i = Size;
+ Size = i; // expected-error{{expression is not assignable}}
+}
+
+template<typename T>
+const T& min(const T&, const T&);
+
+void f2() {
+ int x;
+ A< typeof(x>1) > a;
+}
diff --git a/test/Parser/cxx-throw.cpp b/test/Parser/cxx-throw.cpp
new file mode 100644
index 000000000000..bcc49ec1b4fb
--- /dev/null
+++ b/test/Parser/cxx-throw.cpp
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int i;
+
+void foo() {
+ (throw,throw);
+ (1 ? throw 1 : throw 2);
+ throw int(1);
+ throw;
+ throw 1;
+ throw;
+ 1 ? throw : (void)42;
+ __extension__ throw 1; // expected-error {{expected expression}}
+ (void)throw; // expected-error {{expected expression}}
+}
diff --git a/test/Parser/cxx-try.cpp b/test/Parser/cxx-try.cpp
new file mode 100644
index 000000000000..535f40d78057
--- /dev/null
+++ b/test/Parser/cxx-try.cpp
@@ -0,0 +1,41 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f()
+{
+ try {
+ ;
+ } catch(int i) {
+ ;
+ } catch(...) {
+ }
+}
+
+void g()
+{
+ try; // expected-error {{expected '{'}}
+
+ try {}
+ catch; // expected-error {{expected '('}}
+
+ try {}
+ catch (...); // expected-error {{expected '{'}}
+
+ try {}
+ catch {} // expected-error {{expected '('}}
+}
+
+void h() try {
+} catch(...) {
+}
+
+struct A {
+ int i;
+ A(int);
+ A(char);
+ A() try : i(0) {} catch(...) {}
+ void f() try {} catch(...) {}
+ A(float) : i(0) try {} // expected-error {{expected '{' or ','}}
+};
+
+A::A(char) : i(0) try {} // expected-error {{expected '{' or ','}}
+A::A(int j) try : i(j) {} catch(...) {}
diff --git a/test/Parser/cxx-typeid.cpp b/test/Parser/cxx-typeid.cpp
new file mode 100644
index 000000000000..5a92e7322f1f
--- /dev/null
+++ b/test/Parser/cxx-typeid.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// FIXME: This should really include <typeinfo>, but we don't have that yet.
+namespace std {
+ class type_info;
+}
+
+void f()
+{
+ (void)typeid(int);
+ (void)typeid(0);
+ (void)typeid 1; // expected-error {{error: expected '(' after 'typeid'}}
+}
diff --git a/test/Parser/cxx-typeof.cpp b/test/Parser/cxx-typeof.cpp
new file mode 100644
index 000000000000..0bf446316cfc
--- /dev/null
+++ b/test/Parser/cxx-typeof.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+static void test() {
+ int *pi;
+ int x;
+ typeof pi[x] y;
+}
diff --git a/test/Parser/cxx-using-directive.cpp b/test/Parser/cxx-using-directive.cpp
new file mode 100644
index 000000000000..676f4e6c5a5e
--- /dev/null
+++ b/test/Parser/cxx-using-directive.cpp
@@ -0,0 +1,41 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class A {};
+
+namespace B {
+ namespace A {}
+ using namespace A ;
+}
+
+namespace C {}
+
+namespace D {
+
+ class C {
+
+ using namespace B ; // expected-error{{expected member name or ';' after declaration specifiers}}
+ //FIXME: this needs better error message
+ };
+
+ namespace B {}
+
+ using namespace C ;
+ using namespace B::A ; // expected-error{{expected namespace name}}
+ //FIXME: would be nice to note, that A is not member of D::B
+ using namespace ::B::A ;
+ using namespace ::D::C ; // expected-error{{expected namespace name}}
+}
+
+using namespace ! ; // expected-error{{expected namespace name}}
+using namespace A ; // expected-error{{expected namespace name}}
+using namespace ::A // expected-error{{expected namespace name}} \
+ // expected-error{{expected ';' after namespace name}}
+ B ;
+
+void test_nslookup() {
+ int B;
+ class C;
+ using namespace B;
+ using namespace C;
+}
+
diff --git a/test/Parser/cxx-variadic-func.cpp b/test/Parser/cxx-variadic-func.cpp
new file mode 100644
index 000000000000..86d6b6bf2c5d
--- /dev/null
+++ b/test/Parser/cxx-variadic-func.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only %s
+
+void f(...) {
+ int g(int(...));
+}
diff --git a/test/Parser/cxx0x-rvalue-reference.cpp b/test/Parser/cxx0x-rvalue-reference.cpp
new file mode 100644
index 000000000000..389f2b947003
--- /dev/null
+++ b/test/Parser/cxx0x-rvalue-reference.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+
+int && r1(int &&a);
+
+typedef int && R;
+void r2(const R a) {
+ int & &&ar = a; // expected-error{{'ar' declared as a reference to a reference}}
+}
+
diff --git a/test/Parser/declarators.c b/test/Parser/declarators.c
new file mode 100644
index 000000000000..26e8027d1078
--- /dev/null
+++ b/test/Parser/declarators.c
@@ -0,0 +1,66 @@
+// RUN: clang-cc %s -fsyntax-only -verify -pedantic
+
+extern int a1[];
+
+void f0();
+void f1(int [*]);
+void f2(int [const *]);
+void f3(int [volatile const*]);
+int f4(*XX)(void); /* expected-error {{cannot return}} expected-warning {{type specifier missing, defaults to 'int'}} */
+
+char ((((*X))));
+
+void (*signal(int, void (*)(int)))(int);
+
+int aaaa, ***C, * const D, B(int);
+
+int *A;
+
+struct str;
+
+int test2(int *P, int A) {
+ struct str;
+
+ // Hard case for array decl, not Array[*].
+ int Array[*(int*)P+A];
+}
+
+typedef int atype;
+int test3(x,
+ atype /* expected-error {{unexpected type name 'atype': expected identifier}} */
+ ) int x, atype; {}
+
+int test4(x, x) int x; {} /* expected-error {{redefinition of parameter 'x'}} */
+
+
+// PR3031
+int (test5), ; // expected-error {{expected identifier or '('}}
+
+
+
+// PR3963 & rdar://6759604 - test error recovery for mistyped "typenames".
+
+foo_t *d; // expected-error {{unknown type name 'foo_t'}}
+foo_t a; // expected-error {{unknown type name 'foo_t'}}
+int test6() { return a; } // a should be declared.
+
+// Use of tagged type without tag. rdar://6783347
+struct xyz { int y; };
+enum myenum { ASDFAS };
+xyz b; // expected-error {{use of tagged type 'xyz' without 'struct' tag}}
+myenum c; // expected-error {{use of tagged type 'myenum' without 'enum' tag}}
+
+float *test7() {
+ // We should recover 'b' by parsing it with a valid type of "struct xyz", which
+ // allows us to diagnose other bad things done with y, such as this.
+ return &b.y; // expected-warning {{incompatible pointer types returning 'int *', expected 'float *'}}
+}
+
+struct xyz test8() { return a; } // a should be be marked invalid, no diag.
+
+
+// Verify that implicit int still works.
+static f; // expected-warning {{type specifier missing, defaults to 'int'}}
+static g = 4; // expected-warning {{type specifier missing, defaults to 'int'}}
+static h // expected-warning {{type specifier missing, defaults to 'int'}}
+ __asm__("foo");
diff --git a/test/Parser/designator.c b/test/Parser/designator.c
new file mode 100644
index 000000000000..76c2d435227f
--- /dev/null
+++ b/test/Parser/designator.c
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only %s -verify -pedantic
+
+int X[] = {
+ [4]4, // expected-warning {{use of GNU 'missing =' extension in designator}}
+ [5] = 7
+};
+
+struct foo {
+ int arr[10];
+};
+
+struct foo Y[10] = {
+ [4] .arr [2] = 4,
+
+ // This is not the GNU array init designator extension.
+ [4] .arr [2] 4 // expected-error {{expected '=' or another designator}}
+};
diff --git a/test/Parser/encode.m b/test/Parser/encode.m
new file mode 100644
index 000000000000..1e088a011511
--- /dev/null
+++ b/test/Parser/encode.m
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int main(void) {
+ const char ch = @encode(char *)[2];
+ char c = @encode(char *)[2] + 4;
+ return c;
+}
+
diff --git a/test/Parser/enhanced-proto-1.m b/test/Parser/enhanced-proto-1.m
new file mode 100644
index 000000000000..1f42ec2efbb4
--- /dev/null
+++ b/test/Parser/enhanced-proto-1.m
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@protocol MyProto1
+@optional
+- (void) FOO;
+@optional
+- (void) FOO;
+@required
+- (void) REQ;
+@optional
+@end
+
+@protocol MyProto2 <MyProto1>
+- (void) FOO2;
+@optional
+- (void) FOO3;
+@end
diff --git a/test/Parser/expressions.c b/test/Parser/expressions.c
new file mode 100644
index 000000000000..2b4d4636ebb1
--- /dev/null
+++ b/test/Parser/expressions.c
@@ -0,0 +1,50 @@
+// RUN: clang-cc -parse-noop -verify %s
+
+void test1() {
+ if (sizeof (int){ 1}); // sizeof compound literal
+ if (sizeof (int)); // sizeof type
+
+ (int)4; // cast.
+ (int){4}; // compound literal.
+
+ // FIXME: change this to the struct version when we can.
+ //int A = (struct{ int a;}){ 1}.a;
+ int A = (int){ 1}.a;
+}
+
+int test2(int a, int b) {
+ return a ? a,b : a;
+}
+
+int test3(int a, int b, int c) {
+ return a = b = c;
+}
+
+int test4() {
+ test4();
+}
+
+int test_offsetof() {
+ // FIXME: change into something that is semantically correct.
+ __builtin_offsetof(int, a.b.c[4][5]);
+}
+
+void test_sizeof(){
+ int arr[10];
+ sizeof arr[0];
+ sizeof(arr[0]);
+ sizeof(arr)[0];
+}
+
+// PR3418
+int test_leading_extension() {
+ __extension__ (*(char*)0) = 1;
+}
+
+// PR3972
+int test5(int);
+int test6(void) {
+ return test5( // expected-note {{to match}}
+ test5(1)
+ ; // expected-error {{expected ')'}}
+}
diff --git a/test/Parser/expressions.m b/test/Parser/expressions.m
new file mode 100644
index 000000000000..e9e41216f986
--- /dev/null
+++ b/test/Parser/expressions.m
@@ -0,0 +1,6 @@
+// RUN: clang-cc -parse-noop %s
+
+void test1() {
+ @"s"; // expected-warning {{expression result unused}}
+}
+
diff --git a/test/Parser/extension.c b/test/Parser/extension.c
new file mode 100644
index 000000000000..519dc053c82f
--- /dev/null
+++ b/test/Parser/extension.c
@@ -0,0 +1,20 @@
+/* RUN: clang-cc %s -fsyntax-only -pedantic -verify -std=c89
+ */
+
+/* Top level extension marker. */
+
+__extension__ typedef struct
+{
+ long long int quot;
+ long long int rem;
+} lldiv_t;
+
+
+/* Decl/expr __extension__ marker. */
+void bar() {
+ __extension__ int i;
+ int j;
+ __extension__ (j = 10LL);
+ __extension__ j = 10LL; /* expected-warning {{'long long' is an extension}} */
+}
+
diff --git a/test/Parser/function-decls.c b/test/Parser/function-decls.c
new file mode 100644
index 000000000000..28bb5c2e18da
--- /dev/null
+++ b/test/Parser/function-decls.c
@@ -0,0 +1,10 @@
+/* RUN: clang-cc %s -ast-print
+ */
+
+void foo() {
+ int X;
+ X = sizeof(void (*(*)())());
+ X = sizeof(int(*)(int, float, ...));
+ X = sizeof(void (*(int arga, void (*argb)(double Y)))(void* Z));
+}
+
diff --git a/test/Parser/goto-ident.c b/test/Parser/goto-ident.c
new file mode 100644
index 000000000000..e8d1963e38c2
--- /dev/null
+++ b/test/Parser/goto-ident.c
@@ -0,0 +1,6 @@
+/* RUN: clang-cc -fsyntax-only -verify %s
+*/
+
+void foo() {
+ goto ; /* expected-error {{expected identifier}} */
+}
diff --git a/test/Parser/if-scope-c90.c b/test/Parser/if-scope-c90.c
new file mode 100644
index 000000000000..fdc75e9f10b0
--- /dev/null
+++ b/test/Parser/if-scope-c90.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify --std=c90 %s
+
+int f (int z)
+{
+ if (z > sizeof (enum {a, b}))
+ return a;
+ return b;
+}
diff --git a/test/Parser/if-scope-c99.c b/test/Parser/if-scope-c99.c
new file mode 100644
index 000000000000..37cd0e15ab8e
--- /dev/null
+++ b/test/Parser/if-scope-c99.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify --std=c99 %s
+
+int f (int z)
+{
+ if (z > sizeof (enum {a, b}))
+ return a;
+ return b; // expected-error{{use of undeclared identifier}}
+}
diff --git a/test/Parser/implicit-casts.c b/test/Parser/implicit-casts.c
new file mode 100644
index 000000000000..e7d20980da47
--- /dev/null
+++ b/test/Parser/implicit-casts.c
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+_Complex double X;
+void test1(int c) {
+ X = 5;
+}
+void test2() {
+ int i;
+ double d = i;
+ double _Complex a = 5;
+
+ test1(a);
+ a = 5;
+ d = i;
+}
+int test3() {
+ int a[2];
+ a[0] = test3; // expected-warning{{incompatible pointer to integer conversion assigning 'int ()', expected 'int'}}
+}
+short x; void test4(char c) { x += c; }
+int y; void test5(char c) { y += c; }
diff --git a/test/Parser/method-prototype-1.m b/test/Parser/method-prototype-1.m
new file mode 100644
index 000000000000..1d535de8c140
--- /dev/null
+++ b/test/Parser/method-prototype-1.m
@@ -0,0 +1,43 @@
+// RUN: clang-cc %s -parse-noop
+@interface MyObject
+- (void) bycopy : (int) woodo, ... ;
+- (void) break : (int) woodo, ... ;
+- (void) enum : (int) woodo, ... ;
+- (void) struct : (int) woodo, ... ;
+- (void) union : (int) woodo, ... ;
+- (void) if : (int) woodo, int i, char chh, ... ;
+- (void) else : (int) woodo, ... ;
+- (void) while : (int) woodo, ... ;
+- (void) do : (int) woodo, ... ;
+- (void) for : (int) woodo, ... ;
+- (void) switch : (int) woodo, ... ;
+- (void) case : (int) woodo, ... ;
+- (void) default : (int) woodo, ... ;
+- (void) break : (int) woodo, ... ;
+- (void) continue : (int) woodo, ... ;
+- (void) return : (int) woodo, ... ;
+- (void) goto : (int) woodo, ... ;
+- (void) sizeof : (int) woodo, ... ;
+- (void) typeof : (int) woodo, ... ;
+- (void) __alignof : (int) woodo, ... ;
+- (void) unsigned : (int) woodo, ... ;
+- (void) long : (int) woodo, ... ;
+- (void) const : (int) woodo, ... ;
+- (void) short : (int) woodo, ... ;
+- (void) volatile : (int) woodo, ... ;
+- (void) signed : (int) woodo, ... ;
+- (void) restrict : (int) woodo, ... ;
+- (void) _Complex : (int) woodo, ... ;
+- (void) in : (int) woodo, ... ;
+- (void) out : (int) woodo, ... ;
+- (void) inout : (int) woodo, ... ;
+- (void) bycopy : (int) woodo, ... ;
+- (void) byref : (int) woodo, ... ;
+- (void) oneway : (int) woodo, ... ;
+- (void) int : (int) woodo, ... ;
+- (void) char : (int) woodo, ... ;
+- (void) float : (int) woodo, ... ;
+- (void) double : (int) woodo, ... ;
+- (void) void : (int) woodo, ... ;
+- (void) _Bool : (int) woodo, ... ;
+@end
diff --git a/test/Parser/namelookup-bug-1.c b/test/Parser/namelookup-bug-1.c
new file mode 100644
index 000000000000..3c8b85a2d61a
--- /dev/null
+++ b/test/Parser/namelookup-bug-1.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -verify %s
+
+typedef int Object;
+
+struct Object *pp;
+
+Object staticObject1;
diff --git a/test/Parser/namelookup-bug-2.c b/test/Parser/namelookup-bug-2.c
new file mode 100644
index 000000000000..42298c39c46f
--- /dev/null
+++ b/test/Parser/namelookup-bug-2.c
@@ -0,0 +1,14 @@
+// RUN: clang-cc -verify %s
+
+typedef int Object;
+
+struct Object {int i1; } *P;
+
+void foo() {
+ struct Object { int i2; } *X;
+ Object:
+ {
+ Object a;
+ }
+}
+
diff --git a/test/Parser/objc-alias-printing.m b/test/Parser/objc-alias-printing.m
new file mode 100644
index 000000000000..e121bed0aea8
--- /dev/null
+++ b/test/Parser/objc-alias-printing.m
@@ -0,0 +1,18 @@
+// RUN: clang-cc -ast-print %s
+
+@protocol P1 @end
+@protocol P2 @end
+
+@interface INTF @end
+
+@compatibility_alias alias INTF;
+
+
+int foo ()
+{
+ INTF *pi;
+ INTF<P2,P1> *pi2;
+ alias *p;
+ alias<P1,P2> *p2;
+ return pi2 == p2;
+}
diff --git a/test/Parser/objc-category-neg-1.m b/test/Parser/objc-category-neg-1.m
new file mode 100644
index 000000000000..6c1bd2951736
--- /dev/null
+++ b/test/Parser/objc-category-neg-1.m
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void __assert_rtn(const char *, const char *, int, const char *) __attribute__((__noreturn__));
+static __inline__ int __inline_isfinitef (float ) __attribute__ ((always_inline));
+
+@interface NSATSTypesetter (NSPantherCompatibility) // expected-error {{ "cannot find interface declaration for 'NSATSTypesetter'" }}
+- (id)lineFragmentRectForProposedRect:(id)proposedRect remainingRect:(id)remainingRect __attribute__((deprecated));
+@end
diff --git a/test/Parser/objc-forcollection-1.m b/test/Parser/objc-forcollection-1.m
new file mode 100644
index 000000000000..21ec308a28a1
--- /dev/null
+++ b/test/Parser/objc-forcollection-1.m
@@ -0,0 +1,43 @@
+// RUN: clang-cc -fsyntax-only %s
+
+typedef struct objc_class *Class;
+typedef struct objc_object {
+ Class isa;
+} *id;
+
+
+@protocol P @end
+
+@interface MyList
+@end
+
+@implementation MyList
+- (unsigned int)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state objects: (id *)items count:(unsigned int)stackcount
+{
+ return 0;
+}
+@end
+
+@interface MyList (BasicTest)
+- (void)compilerTestAgainst;
+@end
+
+@implementation MyList (BasicTest)
+- (void)compilerTestAgainst {
+ int i;
+ for (id elem in self)
+ ++i;
+ for (MyList *elem in self)
+ ++i;
+ for (id<P> se in self)
+ ++i;
+
+ MyList<P> *p;
+ for (p in self)
+ ++i;
+
+ for (p in p)
+ ++i;
+}
+@end
+
diff --git a/test/Parser/objc-forcollection-neg-2.m b/test/Parser/objc-forcollection-neg-2.m
new file mode 100644
index 000000000000..ddb279b6f7c1
--- /dev/null
+++ b/test/Parser/objc-forcollection-neg-2.m
@@ -0,0 +1,38 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef struct objc_class *Class;
+typedef struct objc_object {
+ Class isa;
+} *id;
+
+
+@protocol P @end
+
+@interface MyList
+@end
+
+@implementation MyList
+- (unsigned int)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state objects: (id *)items count:(unsigned int)stackcount
+{
+ return 0;
+}
+@end
+
+@interface MyList (BasicTest)
+- (void)compilerTestAgainst;
+@end
+
+@implementation MyList (BasicTest)
+- (void)compilerTestAgainst {
+ static i;// expected-warning {{type specifier missing, defaults to 'int'}}
+ for (id el, elem in self) // expected-error {{only one element declaration is allowed}}
+ ++i;
+ for (id el in self)
+ ++i;
+ MyList<P> ***p;
+ for (p in self) // expected-error {{selector element type 'MyList<P> ***' is not a valid object type}}
+ ++i;
+
+}
+@end
+
diff --git a/test/Parser/objc-forcollection-neg.m b/test/Parser/objc-forcollection-neg.m
new file mode 100644
index 000000000000..0f2bb90df85f
--- /dev/null
+++ b/test/Parser/objc-forcollection-neg.m
@@ -0,0 +1,37 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef struct objc_class *Class;
+typedef struct objc_object {
+ Class isa;
+} *id;
+
+
+@interface MyList
+@end
+
+@implementation MyList
+- (unsigned int)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state objects: (id *)items count:(unsigned int)stackcount
+{
+ return 0;
+}
+@end
+
+@interface MyList (BasicTest)
+- (void)compilerTestAgainst;
+@end
+
+@implementation MyList (BasicTest)
+- (void)compilerTestAgainst {
+
+ int i=0;
+ for (int * elem in elem) // expected-error {{selector element type 'int *' is not a valid object}} \
+ expected-error {{collection expression type 'int *' is not a valid object}}
+ ++i;
+ for (i in elem) // expected-error {{use of undeclared identifier 'elem'}} \
+ expected-error {{selector element type 'int' is not a valid object}}
+ ++i;
+ for (id se in i) // expected-error {{collection expression type 'int' is not a valid object}}
+ ++i;
+}
+@end
+
diff --git a/test/Parser/objc-foreach-syntax.m b/test/Parser/objc-foreach-syntax.m
new file mode 100644
index 000000000000..977dccc88b1d
--- /dev/null
+++ b/test/Parser/objc-foreach-syntax.m
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+
+
+@implementation MyList // expected-warning {{cannot find interface declaration for 'MyList'}}
+- (unsigned int)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state objects: (id *)items count:(unsigned int)stackcount
+{
+ return 0;
+}
+@end
+
+
+int LOOP();
+
+@implementation MyList (BasicTest)
+- (void)compilerTestAgainst {
+MyList * el;
+ for (el in @"foo")
+ { LOOP(); }
+}
+@end
+
+
+static int test7(id keys) {
+ for (id key; in keys) ; // expected-error {{use of undeclared identifier 'in'}}
+}
diff --git a/test/Parser/objc-init.m b/test/Parser/objc-init.m
new file mode 100644
index 000000000000..a91ac9cf285b
--- /dev/null
+++ b/test/Parser/objc-init.m
@@ -0,0 +1,41 @@
+// RUN: clang-cc -fsyntax-only -verify %s -pedantic
+// rdar://5707001
+
+@interface NSNumber;
+- () METH;
+- (unsigned) METH2;
+@end
+
+struct SomeStruct {
+ int x, y, z, q;
+};
+
+void test1() {
+ id objects[] = {[NSNumber METH]};
+}
+
+void test2(NSNumber x) { // expected-error {{Objective-C interface type 'NSNumber' cannot be passed by value}}
+ id objects[] = {[x METH]};
+}
+
+void test3(NSNumber *x) {
+ id objects[] = {[x METH]};
+}
+
+
+// rdar://5977581
+void test4() {
+ unsigned x[] = {[NSNumber METH2]+2};
+}
+
+void test5(NSNumber *x) {
+ unsigned y[] = {
+ [4][NSNumber METH2]+2, // expected-warning {{use of GNU 'missing =' extension in designator}}
+ [4][x METH2]+2 // expected-warning {{use of GNU 'missing =' extension in designator}}
+ };
+
+ struct SomeStruct z = {
+ .x = [x METH2], // ok.
+ .x [x METH2] // expected-error {{expected '=' or another designator}}
+ };
+}
diff --git a/test/Parser/objc-interfaces.m b/test/Parser/objc-interfaces.m
new file mode 100644
index 000000000000..7aa672901fff
--- /dev/null
+++ b/test/Parser/objc-interfaces.m
@@ -0,0 +1,8 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+// Test features and error recovery for objc interfaces.
+
+@interface INTF
+- (int*) foo2 __attribute__((deprecated)) : (int) x1 __attribute__((deprecated)); // expected-error {{expected ';' after method prototype}}
+@end
+
diff --git a/test/Parser/objc-messaging-1.m b/test/Parser/objc-messaging-1.m
new file mode 100644
index 000000000000..4a36fc950fa8
--- /dev/null
+++ b/test/Parser/objc-messaging-1.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc %s -parse-noop
+int main ()
+{
+ int i,j;
+ struct S *p;
+ id a, b, c;
+ [p ii];
+ [p if: 1 :2];
+ [p inout: 1 :2 another:(2,3,4)];
+ [p inout: 1 :2 another:(2,3,4), 6,6,8];
+ [p inout: 1 :2 another:(2,3,4), (6,4,5),6,8];
+ [p inout: 1 :2 another:(i+10), (i,j-1,5),6,8];
+ [p long: 1 :2 another:(i+10), (i,j-1,5),6,8];
+ [p : "Hello\n" :2 another:(i+10), (i,j-1,5),6,8];
+
+ // Comma expression as receiver (rdar://6222856)
+ [a, b, c foo];
+
+}
diff --git a/test/Parser/objc-messaging-neg-1.m b/test/Parser/objc-messaging-neg-1.m
new file mode 100644
index 000000000000..a1ec116fb7b4
--- /dev/null
+++ b/test/Parser/objc-messaging-neg-1.m
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int main()
+ {
+ id a;
+ [a bla:0 6:7]; // expected-error {{expected ']'}}
+ }
diff --git a/test/Parser/objc-missing-impl.m b/test/Parser/objc-missing-impl.m
new file mode 100644
index 000000000000..9108451f1bff
--- /dev/null
+++ b/test/Parser/objc-missing-impl.m
@@ -0,0 +1,2 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+@end // expected-warning {{@end must appear in an @implementation context}}
diff --git a/test/Parser/objc-property-syntax.m b/test/Parser/objc-property-syntax.m
new file mode 100644
index 000000000000..cf75aaa2d5a2
--- /dev/null
+++ b/test/Parser/objc-property-syntax.m
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface MyClass {
+
+};
+@property unsigned char bufferedUTF8Bytes[4]; // expected-error {{property cannot have array or function type}}
+@property unsigned char bufferedUTFBytes:1; // expected-error {{property name cannot be a bitfield}}
+@end
+
+@implementation MyClass
+@end
+
diff --git a/test/Parser/objc-quirks.m b/test/Parser/objc-quirks.m
new file mode 100644
index 000000000000..2913b580c5fc
--- /dev/null
+++ b/test/Parser/objc-quirks.m
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// FIXME: This is a horrible error message here. Fix.
+int @"s" = 5; // expected-error {{prefix attribute must be}}
+
+
+// rdar://6480479
+@interface A
+}; // expected-error {{missing @end}} expected-error {{expected external declaration}}
+
diff --git a/test/Parser/objc-try-catch-1.m b/test/Parser/objc-try-catch-1.m
new file mode 100644
index 000000000000..a8d37f0ab959
--- /dev/null
+++ b/test/Parser/objc-try-catch-1.m
@@ -0,0 +1,68 @@
+// RUN: clang-cc -fsyntax-only -verify %s &&
+// RUN: clang-cc -fsyntax-only -verify -x objective-c++ %s
+void * proc();
+
+@interface NSConstantString
+@end
+
+@interface Frob
+@end
+
+@interface Frob1
+@end
+
+void * foo()
+{
+ @try {
+ return proc();
+ }
+ @catch (Frob* ex) {
+ @throw;
+ }
+ @catch (Frob1* ex) {
+ @throw proc();
+ }
+ @finally {
+ @try {
+ return proc();
+ }
+ @catch (Frob* ex) {
+ @throw 1,2; // expected-error {{@throw requires an Objective-C object type ('int' invalid)}}
+ }
+ @catch (float x) { // expected-error {{@catch parameter is not a pointer to an interface type}}
+
+ }
+ @catch(...) {
+ @throw (4,3,proc());
+ }
+ }
+
+ @try { // expected-error {{@try statement without a @catch and @finally clause}}
+ return proc();
+ }
+}
+
+
+void bar()
+{
+ @try {}// expected-error {{@try statement without a @catch and @finally clause}}
+ @"s"; // expected-warning {{result unused}}
+}
+
+void baz()
+{
+ @try {}// expected-error {{@try statement without a @catch and @finally clause}}
+ @try {}
+ @finally {}
+}
+
+void noTwoTokenLookAheadRequiresABitOfFancyFootworkInTheParser() {
+ @try {
+ // Do something
+ } @catch (...) {}
+ @try {
+ // Do something
+ } @catch (...) {}
+ return;
+}
+
diff --git a/test/Parser/objc-type-printing.m b/test/Parser/objc-type-printing.m
new file mode 100644
index 000000000000..d9ad70474f2b
--- /dev/null
+++ b/test/Parser/objc-type-printing.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc -ast-print %s
+
+@protocol P1 @end
+@protocol P2 @end
+@protocol P3 @end
+
+@interface INTF
+- (INTF<P1>*) METH;
+@end
+
+void foo()
+{
+ INTF *pintf;
+ INTF<P1>* p1;
+ INTF<P1, P1>* p2;
+ INTF<P1, P3>* p3;
+ INTF<P1, P3, P2>* p4;
+ INTF<P2,P2, P3, P1>* p5;
+}
diff --git a/test/Parser/parmvardecl_conversion.c b/test/Parser/parmvardecl_conversion.c
new file mode 100644
index 000000000000..f35487ee95c6
--- /dev/null
+++ b/test/Parser/parmvardecl_conversion.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f (int p[]) { p++; }
+
diff --git a/test/Parser/pointer-arithmetic.c b/test/Parser/pointer-arithmetic.c
new file mode 100644
index 000000000000..d252b42c9b15
--- /dev/null
+++ b/test/Parser/pointer-arithmetic.c
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int *test1(int *a) { return a + 1; }
+int *test2(int *a) { return 1 + a; }
+int *test3(int *a) { return a - 1; }
+int test4(int *a, int *b) { return a - b; }
+
+int test5(int *a, int *b) { return a + b; } /* expected-error {{invalid operands}} */
+int *test6(int *a) { return 1 - a; } /* expected-error {{invalid operands}} */
diff --git a/test/Parser/pointer_promotion.c b/test/Parser/pointer_promotion.c
new file mode 100644
index 000000000000..0254828e0f02
--- /dev/null
+++ b/test/Parser/pointer_promotion.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int test() {
+ void *vp;
+ int *ip;
+ char *cp;
+ struct foo *fp;
+ struct bar *bp;
+ short sint = 7;
+
+ if (ip < cp) {} // expected-warning {{comparison of distinct pointer types ('int *' and 'char *')}}
+ if (cp < fp) {} // expected-warning {{comparison of distinct pointer types ('char *' and 'struct foo *')}}
+ if (fp < bp) {} // expected-warning {{comparison of distinct pointer types ('struct foo *' and 'struct bar *')}}
+ if (ip < 7) {} // expected-warning {{comparison between pointer and integer ('int *' and 'int')}}
+ if (sint < ip) {} // expected-warning {{comparison between pointer and integer ('int' and 'int *')}}
+ if (ip == cp) {} // expected-warning {{comparison of distinct pointer types ('int *' and 'char *')}}
+}
+
diff --git a/test/Parser/pragma-pack.c b/test/Parser/pragma-pack.c
new file mode 100644
index 000000000000..d42bbe5c40d2
--- /dev/null
+++ b/test/Parser/pragma-pack.c
@@ -0,0 +1,32 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Note that this puts the expected lines before the directives to work around
+// limitations in the -verify mode.
+
+/* expected-warning {{missing '(' after '#pragma pack'}}*/ #pragma pack 10
+#pragma pack()
+#pragma pack(8)
+
+/*expected-warning {{unknown action for '#pragma pack'}}*/ #pragma pack(hello)
+#pragma pack(push)
+#pragma pack(pop)
+
+/* expected-warning {{expected integer or identifier in '#pragma pack'}}*/ #pragma pack(push,)
+/* expected-warning {{expected integer or identifier in '#pragma pack'}}*/ #pragma pack(push,)
+/* expected-warning {{expected integer or identifier in '#pragma pack'}}*/ #pragma pack(pop,)
+
+#pragma pack(push,i)
+/* expected-warning {{expected integer or identifier in '#pragma pack'}}*/ #pragma pack(push,i,
+/* expected-warning {{expected integer or identifier in '#pragma pack'}}*/ #pragma pack(push,i,)
+/* expected-warning {{expected integer or identifier in '#pragma pack'}}*/ #pragma pack(push,i,help)
+
+#pragma pack(push,8)
+/* expected-warning {{missing ')' after '#pragma pack'}}*/ #pragma pack(push,8,
+/* expected-warning {{missing ')' after '#pragma pack'}}*/ #pragma pack(push,8,)
+/* expected-warning {{missing ')' after '#pragma pack'}}*/ #pragma pack(push,i,8
+#pragma pack(push,i,8)
+
+/* expected-warning {{missing ')' after '#pragma pack'}}*/ #pragma pack(push
+
+_Pragma("pack(push)")
+/* expected-warning {{expected integer or identifier in '#pragma pack'}}*/ _Pragma("pack(push,)")
diff --git a/test/Parser/prefix-attributes.m b/test/Parser/prefix-attributes.m
new file mode 100644
index 000000000000..bb6d04da2a08
--- /dev/null
+++ b/test/Parser/prefix-attributes.m
@@ -0,0 +1,8 @@
+// RUN: clang-cc -verify -fsyntax-only %s
+
+__attribute__((deprecated)) @class B; // expected-error {{prefix attribute must be followed by an interface or protocol}}
+
+__attribute__((deprecated)) @interface A @end
+__attribute__((deprecated)) @protocol P0;
+__attribute__((deprecated)) @protocol P1
+@end
diff --git a/test/Parser/promote_types_in_proto.c b/test/Parser/promote_types_in_proto.c
new file mode 100644
index 000000000000..faff3e35d5a3
--- /dev/null
+++ b/test/Parser/promote_types_in_proto.c
@@ -0,0 +1,9 @@
+// RUN: clang-cc %s
+void functionPromotion(void f(char *const []));
+void arrayPromotion(char * const argv[]);
+
+int whatever(int argc, char *argv[])
+{
+ arrayPromotion(argv);
+ functionPromotion(arrayPromotion);
+}
diff --git a/test/Parser/recovery.c b/test/Parser/recovery.c
new file mode 100644
index 000000000000..89eac564a329
--- /dev/null
+++ b/test/Parser/recovery.c
@@ -0,0 +1,75 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic -fblocks %s
+
+// PR2241
+float test2241[2] = {
+ 1e, // expected-error {{exponent}}
+ 1ee0 // expected-error {{exponent}}
+};
+
+
+// Testcase derived from PR2692
+static char *f (char * (*g) (char **, int), char **p, ...) {
+ char *s;
+ va_list v; // expected-error {{identifier}}
+ s = g (p, __builtin_va_arg(v, int)); // expected-error {{identifier}}
+}
+
+
+// PR3172
+} // expected-error {{expected external declaration}}
+
+
+// rdar://6094870
+int test(int a) {
+ struct { int i; } x;
+
+ if (x.hello) // expected-error {{no member named 'hello'}}
+ test(0);
+ else
+ ;
+
+ if (x.hello == 0) // expected-error {{no member named 'hello'}}
+ test(0);
+ else
+ ;
+
+ if ((x.hello == 0)) // expected-error {{no member named 'hello'}}
+ test(0);
+ else
+ ;
+
+ if (x.i == 0)) // expected-error {{expected expression}}
+ test(0);
+ else
+ ;
+}
+
+
+
+char (((( /* expected-note {{to match this '('}} */
+ *X x ] )))); /* expected-error {{expected ')'}} */
+
+; // expected-warning {{ISO C does not allow an extra ';' outside of a function}}
+
+
+
+
+struct S { void *X, *Y; };
+
+struct S A = {
+&BADIDENT, 0 /* expected-error {{use of undeclared identifier}} */
+};
+
+// rdar://6248081
+int test6248081() {
+ [10] // expected-error {{expected expression}}
+}
+
+struct forward; // expected-note{{forward declaration of 'struct forward'}}
+void x(struct forward* x) {switch(x->a) {}} // expected-error {{incomplete definition of type}}
+
+// PR3410
+void foo() {
+ int X;
+ X = 4 // expected-error{{expected ';' after expression}}
+}
diff --git a/test/Parser/selector-1.m b/test/Parser/selector-1.m
new file mode 100644
index 000000000000..85ef919689df
--- /dev/null
+++ b/test/Parser/selector-1.m
@@ -0,0 +1,14 @@
+// RUN: clang-cc -parse-noop %s
+
+int main() {
+ SEL s = @selector(retain);
+ SEL s1 = @selector(meth1:);
+ SEL s2 = @selector(retainArgument::);
+ SEL s3 = @selector(retainArgument:::::);
+ SEL s4 = @selector(retainArgument:with:);
+ SEL s5 = @selector(meth1:with:with:);
+ SEL s6 = @selector(getEnum:enum:bool:);
+ SEL s7 = @selector(char:float:double:unsigned:short:long:);
+
+ SEL s9 = @selector(:enum:bool:);
+}
diff --git a/test/Parser/statements.c b/test/Parser/statements.c
new file mode 100644
index 000000000000..c5923bc0641b
--- /dev/null
+++ b/test/Parser/statements.c
@@ -0,0 +1,56 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int test1() {
+ { ; { ;;}} ;;
+}
+
+int test2() {
+ if (0) { if (1) {} } else { }
+
+ do { } while (0);
+
+ while (0) while(0) do ; while(0);
+
+ for (0;0;0)
+ for (;;)
+ for (9;0;2)
+ ;
+ for (int X = 0; 0; 0);
+}
+
+int test3() {
+ switch (0) {
+
+ case 4:
+ if (0) {
+ case 6: ;
+ }
+ default:
+ ;
+ }
+}
+
+int test4() {
+ if (0); // expected-warning {{if statement has empty body}}
+
+ int X; // declaration in a block.
+
+foo: if (0); // expected-warning {{if statement has empty body}}
+}
+
+typedef int t;
+void test5() {
+ if (0); // expected-warning {{if statement has empty body}}
+
+ t x = 0;
+
+ if (0); // expected-warning {{if statement has empty body}}
+}
+
+
+void test6(void) {
+ do
+ . // expected-error {{expected expression}}
+ while (0);
+}
+
diff --git a/test/Parser/struct-recursion.c b/test/Parser/struct-recursion.c
new file mode 100644
index 000000000000..11e5f7e97ab1
--- /dev/null
+++ b/test/Parser/struct-recursion.c
@@ -0,0 +1,11 @@
+// RUN: clang-cc %s -fsyntax-only
+
+// C99 6.7.2.3p11
+
+// mutually recursive structs
+struct s1 { struct s2 *A; };
+struct s2 { struct s1 *B; };
+
+// both types are complete now.
+struct s1 a;
+struct s2 b;
diff --git a/test/Parser/traditional_arg_scope.c b/test/Parser/traditional_arg_scope.c
new file mode 100644
index 000000000000..2a21ec3708d4
--- /dev/null
+++ b/test/Parser/traditional_arg_scope.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only %s -verify
+
+int x(a) int a; {return a;}
+int y(b) int b; {return a;} // expected-error {{use of undeclared identifier}}
+
+// PR2332
+int a(a)int a;{a=10;return a;}
diff --git a/test/Parser/typeof.c b/test/Parser/typeof.c
new file mode 100644
index 000000000000..a7c488023ae2
--- /dev/null
+++ b/test/Parser/typeof.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef int TInt;
+
+static void test() {
+ int *pi;
+
+ int typeof (int) aIntInt; // expected-error{{cannot combine with previous 'int' declaration specifier}}
+ short typeof (int) aShortInt; // expected-error{{'short typeof' is invalid}}
+ int int ttt; // expected-error{{cannot combine with previous 'int' declaration specifier}}
+ typeof(TInt) anInt;
+ short TInt eee; // expected-error{{expected ';' at end of declaration}}
+ void ary[7] fff; // expected-error{{array has incomplete element type 'void'}} expected-error{{expected ';' at end of declaration}}
+ typeof(void ary[7]) anIntError; // expected-error{{expected ')'}} expected-note {{to match this '('}} expected-error {{variable has incomplete type 'typeof(void)' (aka 'void')}}
+ typeof(const int) aci;
+ const typeof (*pi) aConstInt;
+ int xx;
+ int *i;
+}
diff --git a/test/Parser/types.c b/test/Parser/types.c
new file mode 100644
index 000000000000..2131ab0346f4
--- /dev/null
+++ b/test/Parser/types.c
@@ -0,0 +1,14 @@
+// RUN: clang-cc %s -parse-noop
+
+// Test the X can be overloaded inside the struct.
+typedef int X;
+struct Y { short X; };
+
+// Variable shadows type, PR3872
+
+typedef struct foo { int x; } foo;
+void test() {
+ foo *foo;
+ foo->x = 0;
+}
+
diff --git a/test/Preprocessor/_Pragma-dependency.c b/test/Preprocessor/_Pragma-dependency.c
new file mode 100644
index 000000000000..da1d87f741e6
--- /dev/null
+++ b/test/Preprocessor/_Pragma-dependency.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc %s -E 2>&1 | grep 'DO_PRAGMA (STR' &&
+// RUN: clang-cc %s -E 2>&1 | grep '7:3'
+
+#define DO_PRAGMA _Pragma
+#define STR "GCC dependency \"parse.y\"")
+ // Test that this line is printed by caret diagnostics.
+ DO_PRAGMA (STR
diff --git a/test/Preprocessor/_Pragma-location.c b/test/Preprocessor/_Pragma-location.c
new file mode 100644
index 000000000000..61cadfbb8a18
--- /dev/null
+++ b/test/Preprocessor/_Pragma-location.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc %s -E | not grep 'scratch space'
+
+#define push _Pragma ("pack(push)")
+push
diff --git a/test/Preprocessor/_Pragma-physloc.c b/test/Preprocessor/_Pragma-physloc.c
new file mode 100644
index 000000000000..87379491676d
--- /dev/null
+++ b/test/Preprocessor/_Pragma-physloc.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc %s -E | grep '#pragma x y z' &&
+// RUN: clang-cc %s -E | grep '#pragma a b c'
+
+_Pragma("x y z")
+_Pragma("a b c")
+
diff --git a/test/Preprocessor/_Pragma-syshdr2.c b/test/Preprocessor/_Pragma-syshdr2.c
new file mode 100644
index 000000000000..de7f2d3dc3b1
--- /dev/null
+++ b/test/Preprocessor/_Pragma-syshdr2.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -E %s 2>&1 | grep 'file not found'
+
+#define DO_PRAGMA _Pragma
+DO_PRAGMA ("GCC dependency \"blahblabh\"")
+
diff --git a/test/Preprocessor/_Pragma.c b/test/Preprocessor/_Pragma.c
new file mode 100644
index 000000000000..9c0c97d1f011
--- /dev/null
+++ b/test/Preprocessor/_Pragma.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc %s -verify -Wall
+
+_Pragma ("GCC system_header") // expected-warning {{system_header ignored in main file}}
+
+// rdar://6880630
+_Pragma("#define macro") // expected-warning {{unknown pragma ignored}}
+
+#ifdef macro
+#error #define invalid
+#endif
diff --git a/test/Preprocessor/assembler-with-cpp.c b/test/Preprocessor/assembler-with-cpp.c
new file mode 100644
index 000000000000..2e84ed1a6b07
--- /dev/null
+++ b/test/Preprocessor/assembler-with-cpp.c
@@ -0,0 +1,77 @@
+// RUN: clang-cc -x assembler-with-cpp -fdollars-in-identifiers=0 -E %s > %t &&
+
+#ifndef __ASSEMBLER__
+#error "__ASSEMBLER__ not defined"
+#endif
+
+
+// Invalid token pasting is ok.
+// RUN: grep '1: X .' %t &&
+#define A X ## .
+1: A
+
+// Line markers are not linemarkers in .S files, they are passed through.
+// RUN: grep '# 321' %t &&
+# 321
+
+// Unknown directives are passed through.
+// RUN: grep '# B C' %t &&
+# B C
+
+// Unknown directives are expanded.
+// RUN: grep '# BAR42' %t &&
+#define D(x) BAR ## x
+# D(42)
+
+// Unmatched quotes are permitted.
+// RUN: grep "2: '" %t &&
+// RUN: grep '3: "' %t &&
+2: '
+3: "
+
+// (balance quotes to keep editors happy): "'
+
+// Empty char literals are ok.
+// RUN: grep "4: ''" %t &&
+4: ''
+
+
+// Portions of invalid pasting should still expand as macros.
+// rdar://6709206
+// RUN: grep "5: expanded (" %t &&
+#define M4 expanded
+#define M5() M4 ## (
+
+5: M5()
+
+// rdar://6804322
+// RUN: grep -F "6: blarg $foo" %t &&
+#define FOO(name) name ## $foo
+6: FOO(blarg)
+
+// RUN: clang-cc -x assembler-with-cpp -fdollars-in-identifiers=1 -E %s > %t &&
+// RUN: grep -F "7: blarg$foo" %t &&
+#define FOO(name) name ## $foo
+7: FOO(blarg)
+
+
+//
+#define T6() T6 #nostring
+#define T7(x) T7 #x
+8: T6()
+9: T7(foo)
+// RUN: grep '8: T6 #nostring' %t &&
+// RUN: grep '9: T7 "foo"' %t &&
+
+// Concatenation with period doesn't leave a space
+// RUN: grep -F '10: .T8' %t &&
+#define T8(A,B) A ## B
+10: T8(.,T8)
+
+
+// This should not crash.
+// RUN: grep '11: #0' %t &&
+#define T11(a) #0
+11: T11(b)
+
+// RUN: true
diff --git a/test/Preprocessor/builtin_line.c b/test/Preprocessor/builtin_line.c
new file mode 100644
index 000000000000..db01e47995a8
--- /dev/null
+++ b/test/Preprocessor/builtin_line.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc %s -E | grep "^ 4" &&
+#define FOO __LINE__
+
+ FOO
+
+// PR3579 - This should expand to the __LINE__ of the ')' not of the X.
+// RUN: clang-cc %s -E | grep "^A 13"
+
+#define X() __LINE__
+
+A X(
+
+)
diff --git a/test/Preprocessor/c90.c b/test/Preprocessor/c90.c
new file mode 100644
index 000000000000..ed63d1b3d7cc
--- /dev/null
+++ b/test/Preprocessor/c90.c
@@ -0,0 +1,10 @@
+/* RUN: clang-cc %s -std=c89 -Eonly -verify -pedantic-errors
+ */
+
+/* PR3919 */
+
+#define foo`bar /* expected-error {{whitespace required after macro name}} */
+#define foo2!bar /* expected-warning {{whitespace recommended after macro name}} */
+
+#define foo3$bar /* expected-error {{'$' in identifier}} */
+
diff --git a/test/Preprocessor/c99-6_10_3_3_p4.c b/test/Preprocessor/c99-6_10_3_3_p4.c
new file mode 100644
index 000000000000..89660549b9a1
--- /dev/null
+++ b/test/Preprocessor/c99-6_10_3_3_p4.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -E %s | grep -F 'char p[] = "x ## y";'
+#define hash_hash # ## #
+#define mkstr(a) # a
+#define in_between(a) mkstr(a)
+#define join(c, d) in_between(c hash_hash d)
+char p[] = join(x, y);
diff --git a/test/Preprocessor/c99-6_10_3_4_p5.c b/test/Preprocessor/c99-6_10_3_4_p5.c
new file mode 100644
index 000000000000..22bdf8258cbe
--- /dev/null
+++ b/test/Preprocessor/c99-6_10_3_4_p5.c
@@ -0,0 +1,29 @@
+// Example from C99 6.10.3.4p5
+
+// RUN: clang-cc -E %s | grep -F 'f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);' &&
+// RUN: clang-cc -E %s | grep -F 'f(2 * (2 +(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);' &&
+// RUN: clang-cc -E %s | grep -F 'int i[] = { 1, 23, 4, 5, };' &&
+// RUN: clang-cc -E %s | grep -F 'char c[2][6] = { "hello", "" };'
+
+
+#define x 3
+#define f(a) f(x * (a))
+#undef x
+#define x 2
+#define g f
+#define z z[0]
+#define h g(~
+#define m(a) a(w)
+#define w 0,1
+#define t(a) a
+#define p() int
+#define q(x) x
+#define r(x,y) x ## y
+#define str(x) # x
+ f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
+ g(x+(3,4)-w) | h 5) & m
+(f)^m(m);
+p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) };
+char c[2][6] = { str(hello), str() };
+
+
diff --git a/test/Preprocessor/c99-6_10_3_4_p6.c b/test/Preprocessor/c99-6_10_3_4_p6.c
new file mode 100644
index 000000000000..c48d2efd2eff
--- /dev/null
+++ b/test/Preprocessor/c99-6_10_3_4_p6.c
@@ -0,0 +1,24 @@
+// Example from C99 6.10.3.4p6
+
+// RUN: clang-cc -E %s | grep -F 'printf("x" "1" "= %d, x" "2" "= s" x1, x2);' &&
+// RUN: clang-cc -E %s | grep 'fputs("strncmp(\\"abc\\\\0d\\" \\"abc\\", .\\\\4.) == 0" ": @\\n", s);' &&
+// RUN: clang-cc -E %s | grep -F 'include "vers2.h"' &&
+// RUN: clang-cc -E %s | grep -F '"hello";' &&
+// RUN: clang-cc -E %s | grep -F '"hello" ", world"'
+
+#define str(s) # s
+#define xstr(s) str(s)
+#define debug(s, t) printf("x" # s "= %d, x" # t "= s" \
+ x ## s, x ## t)
+#define INCFILE(n) vers ## n
+#define glue(a, b) a ## b
+#define xglue(a, b) glue(a, b)
+#define HIGHLOW "hello"
+#define LOW LOW ", world"
+debug(1, 2);
+fputs(str(strncmp("abc\0d" "abc", '\4') // this goes away
+ == 0) str(: @\n), s);
+include xstr(INCFILE(2).h)
+glue(HIGH, LOW);
+xglue(HIGH, LOW)
+
diff --git a/test/Preprocessor/c99-6_10_3_4_p7.c b/test/Preprocessor/c99-6_10_3_4_p7.c
new file mode 100644
index 000000000000..a53df8263f19
--- /dev/null
+++ b/test/Preprocessor/c99-6_10_3_4_p7.c
@@ -0,0 +1,9 @@
+// Example from C99 6.10.3.4p7
+
+// RUN: clang-cc -E %s | grep -F 'int j[] = { 123, 45, 67, 89,' &&
+// RUN: clang-cc -E %s | grep -F '10, 11, 12, };'
+
+#define t(x,y,z) x ## y ## z
+int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,),
+t(10,,), t(,11,), t(,,12), t(,,) };
+
diff --git a/test/Preprocessor/c99-6_10_3_4_p9.c b/test/Preprocessor/c99-6_10_3_4_p9.c
new file mode 100644
index 000000000000..39c34546ad4d
--- /dev/null
+++ b/test/Preprocessor/c99-6_10_3_4_p9.c
@@ -0,0 +1,16 @@
+// Example from C99 6.10.3.4p9
+
+// RUN: clang-cc -E %s | grep -F 'fprintf(stderr, "Flag");' &&
+// RUN: clang-cc -E %s | grep -F 'fprintf(stderr, "X = %d\n", x);' &&
+// RUN: clang-cc -E %s | grep -F 'puts("The first, second, and third items.");' &&
+// RUN: clang-cc -E %s | grep -F '((x>y)?puts("x>y"): printf("x is %d but y is %d", x, y));'
+
+#define debug(...) fprintf(stderr, __VA_ARGS__)
+#define showlist(...) puts(#__VA_ARGS__)
+#define report(test, ...) ((test)?puts(#test):\
+ printf(__VA_ARGS__))
+debug("Flag");
+debug("X = %d\n", x);
+showlist(The first, second, and third items.);
+report(x>y, "x is %d but y is %d", x, y);
+
diff --git a/test/Preprocessor/clang_headers.c b/test/Preprocessor/clang_headers.c
new file mode 100644
index 000000000000..1cb331998f43
--- /dev/null
+++ b/test/Preprocessor/clang_headers.c
@@ -0,0 +1,3 @@
+// RUN: clang-cc -E %s
+
+#include <limits.h>
diff --git a/test/Preprocessor/comment_save.c b/test/Preprocessor/comment_save.c
new file mode 100644
index 000000000000..30b043433c97
--- /dev/null
+++ b/test/Preprocessor/comment_save.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -E -C %s | grep '^// foo$' &&
+// RUN: clang-cc -E -C %s | grep -F '^/* bar */$'
+
+// foo
+/* bar */
+
+
diff --git a/test/Preprocessor/comment_save_if.c b/test/Preprocessor/comment_save_if.c
new file mode 100644
index 000000000000..c08b2d7c78b7
--- /dev/null
+++ b/test/Preprocessor/comment_save_if.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc %s -E -CC -pedantic 2>&1 | grep -v '^/' | not grep warning
+
+#if 1 /*bar */
+
+#endif /*foo*/
+
diff --git a/test/Preprocessor/comment_save_macro.c b/test/Preprocessor/comment_save_macro.c
new file mode 100644
index 000000000000..66b59d136d73
--- /dev/null
+++ b/test/Preprocessor/comment_save_macro.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -E -C %s | grep '^boo bork bar // zot$' &&
+// RUN: clang-cc -E -CC %s | grep -F '^boo bork /* blah*/ bar // zot$' &&
+// RUN: clang-cc -E %s | grep '^boo bork bar$'
+
+
+#define FOO bork // blah
+boo FOO bar // zot
+
diff --git a/test/Preprocessor/cxx_and.cpp b/test/Preprocessor/cxx_and.cpp
new file mode 100644
index 000000000000..971b7bc991dc
--- /dev/null
+++ b/test/Preprocessor/cxx_and.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-cc -DA -DB -E %s | grep 'int a = 37 == 37' &&
+// RUN: clang-cc -DA -E %s | grep 'int a = 927 == 927' &&
+// RUN: clang-cc -DB -E %s | grep 'int a = 927 == 927' &&
+// RUN: clang-cc -E %s | grep 'int a = 927 == 927'
+#if defined(A) and defined(B)
+#define X 37
+#else
+#define X 927
+#endif
+
+#if defined(A) && defined(B)
+#define Y 37
+#else
+#define Y 927
+#endif
+
+int a = X == Y;
diff --git a/test/Preprocessor/cxx_bitand.cpp b/test/Preprocessor/cxx_bitand.cpp
new file mode 100644
index 000000000000..8d7fe678e3e0
--- /dev/null
+++ b/test/Preprocessor/cxx_bitand.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -DA=1 -DB=2 -E %s | grep 'int a = 927 == 927' &&
+// RUN: clang-cc -DA=1 -DB=1 -E %s | grep 'int a = 37 == 37' &&
+// RUN: clang-cc -E %s | grep 'int a = 927 == 927'
+#if A bitand B
+#define X 37
+#else
+#define X 927
+#endif
+
+#if A & B
+#define Y 37
+#else
+#define Y 927
+#endif
+
+int a = X == Y;
diff --git a/test/Preprocessor/cxx_bitor.cpp b/test/Preprocessor/cxx_bitor.cpp
new file mode 100644
index 000000000000..7645c7ee5133
--- /dev/null
+++ b/test/Preprocessor/cxx_bitor.cpp
@@ -0,0 +1,18 @@
+// RUN: clang-cc -DA=1 -DB=1 -E %s | grep 'int a = 37 == 37' &&
+// RUN: clang-cc -DA=0 -DB=1 -E %s | grep 'int a = 37 == 37' &&
+// RUN: clang-cc -DA=1 -DB=0 -E %s | grep 'int a = 37 == 37' &&
+// RUN: clang-cc -DA=0 -DB=0 -E %s | grep 'int a = 927 == 927' &&
+// RUN: clang-cc -E %s | grep 'int a = 927 == 927'
+#if A bitor B
+#define X 37
+#else
+#define X 927
+#endif
+
+#if A | B
+#define Y 37
+#else
+#define Y 927
+#endif
+
+int a = X == Y;
diff --git a/test/Preprocessor/cxx_compl.cpp b/test/Preprocessor/cxx_compl.cpp
new file mode 100644
index 000000000000..f1cc6d2800d5
--- /dev/null
+++ b/test/Preprocessor/cxx_compl.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -DA=1 -E %s | grep 'int a = 37 == 37' &&
+// RUN: clang-cc -DA=0 -E %s | grep 'int a = 927 == 927' &&
+// RUN: clang-cc -E %s | grep 'int a = 927 == 927'
+#if compl 0 bitand A
+#define X 37
+#else
+#define X 927
+#endif
+
+#if ~0 & A
+#define Y 37
+#else
+#define Y 927
+#endif
+
+int a = X == Y;
diff --git a/test/Preprocessor/cxx_not.cpp b/test/Preprocessor/cxx_not.cpp
new file mode 100644
index 000000000000..dd3190117d92
--- /dev/null
+++ b/test/Preprocessor/cxx_not.cpp
@@ -0,0 +1,15 @@
+// RUN: clang-cc -DA=1 -E %s | grep 'int a = 927 == 927' &&
+// RUN: clang-cc -E %s | grep 'int a = 37 == 37'
+#if not defined(A)
+#define X 37
+#else
+#define X 927
+#endif
+
+#if ! defined(A)
+#define Y 37
+#else
+#define Y 927
+#endif
+
+int a = X == Y;
diff --git a/test/Preprocessor/cxx_not_eq.cpp b/test/Preprocessor/cxx_not_eq.cpp
new file mode 100644
index 000000000000..4940f3b0a7bf
--- /dev/null
+++ b/test/Preprocessor/cxx_not_eq.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -DA=1 -DB=1 -E %s | grep 'int a = 927 == 927' &&
+// RUN: clang-cc -E %s | grep 'int a = 927 == 927' &&
+// RUN: clang-cc -DA=1 -DB=2 -E %s | grep 'int a = 37 == 37'
+#if A not_eq B
+#define X 37
+#else
+#define X 927
+#endif
+
+#if A != B
+#define Y 37
+#else
+#define Y 927
+#endif
+
+int a = X == Y;
diff --git a/test/Preprocessor/cxx_oper_keyword.cpp b/test/Preprocessor/cxx_oper_keyword.cpp
new file mode 100644
index 000000000000..faae68741eed
--- /dev/null
+++ b/test/Preprocessor/cxx_oper_keyword.cpp
@@ -0,0 +1,7 @@
+// RUN: not clang-cc %s -E &&
+// RUN: clang-cc %s -E -fno-operator-names
+
+// Not valid in C++ unless -fno-operator-names is passed.
+#define and foo
+
+
diff --git a/test/Preprocessor/cxx_oper_spelling.cpp b/test/Preprocessor/cxx_oper_spelling.cpp
new file mode 100644
index 000000000000..85f0426ca3a9
--- /dev/null
+++ b/test/Preprocessor/cxx_oper_spelling.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-cc -E %s | grep 'a: "and"'
+
+#define X(A) #A
+
+// C++'03 2.5p2: "In all respects of the language, each alternative
+// token behaves the same, respectively, as its primary token,
+// except for its spelling"
+//
+// This should be spelled as 'and', not '&&'
+a: X(and)
+
diff --git a/test/Preprocessor/cxx_or.cpp b/test/Preprocessor/cxx_or.cpp
new file mode 100644
index 000000000000..133f28516b42
--- /dev/null
+++ b/test/Preprocessor/cxx_or.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-cc -DA -DB -E %s | grep 'int a = 37 == 37' &&
+// RUN: clang-cc -DA -E %s | grep 'int a = 37 == 37' &&
+// RUN: clang-cc -DB -E %s | grep 'int a = 37 == 37' &&
+// RUN: clang-cc -E %s | grep 'int a = 927 == 927'
+#if defined(A) or defined(B)
+#define X 37
+#else
+#define X 927
+#endif
+
+#if defined(A) || defined(B)
+#define Y 37
+#else
+#define Y 927
+#endif
+
+int a = X == Y;
diff --git a/test/Preprocessor/cxx_true.cpp b/test/Preprocessor/cxx_true.cpp
new file mode 100644
index 000000000000..e35c54d7b3fc
--- /dev/null
+++ b/test/Preprocessor/cxx_true.cpp
@@ -0,0 +1,13 @@
+/* RUN: clang-cc -E %s -x=c++ | grep block_1 &&
+ RUN: clang-cc -E %s -x=c++ | not grep block_2 &&
+ RUN: clang-cc -E %s -x=c | not grep block
+*/
+
+#if true
+block_1
+#endif
+
+#if false
+block_2
+#endif
+
diff --git a/test/Preprocessor/cxx_xor.cpp b/test/Preprocessor/cxx_xor.cpp
new file mode 100644
index 000000000000..a38c3c5454b9
--- /dev/null
+++ b/test/Preprocessor/cxx_xor.cpp
@@ -0,0 +1,18 @@
+// RUN: clang-cc -DA=1 -DB=1 -E %s | grep 'int a = 927 == 927' &&
+// RUN: clang-cc -DA=0 -DB=1 -E %s | grep 'int a = 37 == 37' &&
+// RUN: clang-cc -DA=1 -DB=0 -E %s | grep 'int a = 37 == 37' &&
+// RUN: clang-cc -DA=0 -DB=0 -E %s | grep 'int a = 927 == 927' &&
+// RUN: clang-cc -E %s | grep 'int a = 927 == 927'
+#if A xor B
+#define X 37
+#else
+#define X 927
+#endif
+
+#if A ^ B
+#define Y 37
+#else
+#define Y 927
+#endif
+
+int a = X == Y;
diff --git a/test/Preprocessor/dependencies-and-pp.c b/test/Preprocessor/dependencies-and-pp.c
new file mode 100644
index 000000000000..1dc4d026b18d
--- /dev/null
+++ b/test/Preprocessor/dependencies-and-pp.c
@@ -0,0 +1,5 @@
+// RUN: clang -E -o %t.1 %s &&
+// RUN: clang -E -MD -MF %t.d -MT foo -o %t.2 %s &&
+// RUN: diff %t.1 %t.2 &&
+// RUN: grep "foo:" %t.d &&
+// RUN: grep "dependencies-and-pp.c" %t.d
diff --git a/test/Preprocessor/disabled-cond-diags.c b/test/Preprocessor/disabled-cond-diags.c
new file mode 100644
index 000000000000..eb7632f29b3f
--- /dev/null
+++ b/test/Preprocessor/disabled-cond-diags.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -E %s 2>&1 | not grep "warning\|error"
+
+#if 0
+
+// Shouldn't get warnings here.
+??( ??)
+
+// Should not get an error here.
+` ` ` `
+#endif
diff --git a/test/Preprocessor/dump-macros-spacing.c b/test/Preprocessor/dump-macros-spacing.c
new file mode 100644
index 000000000000..335e37c97e0e
--- /dev/null
+++ b/test/Preprocessor/dump-macros-spacing.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -E -dD < %s | grep stdin | grep -v define
+#define A A
+/* 1
+ * 2
+ * 3
+ * 4
+ * 5
+ * 6
+ * 7
+ * 8
+ */
+#define B B
+
diff --git a/test/Preprocessor/dump-options.c b/test/Preprocessor/dump-options.c
new file mode 100644
index 000000000000..6910e1a314e4
--- /dev/null
+++ b/test/Preprocessor/dump-options.c
@@ -0,0 +1,3 @@
+// RUN: clang %s -E -dD | grep __INTMAX_MAX__ &&
+// RUN: clang %s -E -dM | grep __INTMAX_MAX__
+
diff --git a/test/Preprocessor/dump_macros.c b/test/Preprocessor/dump_macros.c
new file mode 100644
index 000000000000..d3e06b2bfac7
--- /dev/null
+++ b/test/Preprocessor/dump_macros.c
@@ -0,0 +1,31 @@
+// RUN: clang-cc -E -dM %s -o %t &&
+
+// Space even without expansion tokens
+// RUN: grep "#define A(x) " %t &&
+#define A(x)
+
+// Space before expansion list.
+// RUN: grep "#define B(x,y) x y" %t &&
+#define B(x,y)x y
+
+// No space in expansion list.
+// RUN: grep "#define C(x,y) x y" %t &&
+#define C(x, y) x y
+
+// No paste avoidance.
+// RUN: grep "#define X() .." %t &&
+#define X() ..
+
+// Simple test.
+// RUN: grep "#define Y ." %t &&
+// RUN: grep "#define Z X()Y" %t &&
+#define Y .
+#define Z X()Y
+
+// gcc prints macros at end of translation unit, so last one wins.
+// RUN: grep "#define foo 2" %t &&
+// RUN: not grep "#define foo 1" %t
+#define foo 1
+#undef foo
+#define foo 2
+
diff --git a/test/Preprocessor/dumptokens_phyloc.c b/test/Preprocessor/dumptokens_phyloc.c
new file mode 100644
index 000000000000..c0e78c9b155d
--- /dev/null
+++ b/test/Preprocessor/dumptokens_phyloc.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -dump-tokens %s 2>&1 | grep "Spelling=.*dumptokens_phyloc.c:3:20"
+
+#define TESTPHYLOC 10
+
+TESTPHYLOC
diff --git a/test/Preprocessor/expr_comma.c b/test/Preprocessor/expr_comma.c
new file mode 100644
index 000000000000..0a24baca46c9
--- /dev/null
+++ b/test/Preprocessor/expr_comma.c
@@ -0,0 +1,10 @@
+// Comma is not allowed in C89
+// RUN: not clang-cc -E %s -std=c89 -pedantic-errors &&
+
+// Comma is allowed if unevaluated in C99
+// RUN: clang-cc -E %s -std=c99 -pedantic-errors
+
+// PR2279
+
+#if 0? 1,2:3
+#endif
diff --git a/test/Preprocessor/expr_invalid_tok.c b/test/Preprocessor/expr_invalid_tok.c
new file mode 100644
index 000000000000..5e750a462be0
--- /dev/null
+++ b/test/Preprocessor/expr_invalid_tok.c
@@ -0,0 +1,15 @@
+// RUN: not clang-cc -E %s 2>&1 | grep 'invalid token at start of a preprocessor expression' &&
+// RUN: not clang-cc -E %s 2>&1 | grep 'token is not a valid binary operator in a preprocessor subexpression' &&
+// RUN: not clang-cc -E %s 2>&1 | grep ':14: error: expected end of line in preprocessor expression'
+// PR2220
+
+#if 1 * * 2
+#endif
+
+#if 4 [ 2
+#endif
+
+
+// PR2284 - The constant-expr production does not including comma.
+#if 1 ? 2 : 0, 1
+#endif
diff --git a/test/Preprocessor/expr_liveness.c b/test/Preprocessor/expr_liveness.c
new file mode 100644
index 000000000000..3d1e25edd4e6
--- /dev/null
+++ b/test/Preprocessor/expr_liveness.c
@@ -0,0 +1,52 @@
+/* RUN: clang-cc -E %s -DNO_ERRORS -Werror -Wundef &&
+ RUN: not clang-cc -E %s
+ */
+
+#ifdef NO_ERRORS
+/* None of these divisions by zero are in live parts of the expression, do not
+ emit any diagnostics. */
+
+#define MACRO_0 0
+#define MACRO_1 1
+
+#if MACRO_0 && 10 / MACRO_0
+foo
+#endif
+
+#if MACRO_1 || 10 / MACRO_0
+bar
+#endif
+
+#if 0 ? 124/0 : 42
+#endif
+
+// PR2279
+#if 0 ? 1/0: 2
+#else
+#error
+#endif
+
+// PR2279
+#if 1 ? 2 ? 3 : 4 : 5
+#endif
+
+// PR2284
+#if 1 ? 0: 1 ? 1/0: 1/0
+#endif
+
+#else
+
+
+/* The 1/0 is live, it should error out. */
+#if 0 && 1 ? 4 : 1 / 0
+baz
+#endif
+
+
+#endif
+
+// rdar://6505352
+// -Wundef should not warn about use of undefined identifier if not live.
+#if (!defined(XXX) || XXX > 42)
+#endif
+
diff --git a/test/Preprocessor/expr_multichar.c b/test/Preprocessor/expr_multichar.c
new file mode 100644
index 000000000000..4df8f3d4f9ea
--- /dev/null
+++ b/test/Preprocessor/expr_multichar.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc < %s -E -verify -triple i686-pc-linux-gnu
+
+#if (('1234' >> 24) != '1')
+#error Bad multichar constant calculation!
+#endif
diff --git a/test/Preprocessor/expr_usual_conversions.c b/test/Preprocessor/expr_usual_conversions.c
new file mode 100644
index 000000000000..47aca7beca6f
--- /dev/null
+++ b/test/Preprocessor/expr_usual_conversions.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc %s -E 2>&1 | grep warning | wc -l | grep 2
+
+#define INTMAX_MIN (-9223372036854775807LL -1)
+
+#if (-42 + 0U) / -2
+foo
+#endif
+
+// Shifts don't want the usual conversions: PR2279
+#if (2 << 1U) - 30 >= 0
+#error
+#endif
+
diff --git a/test/Preprocessor/extension-warning.c b/test/Preprocessor/extension-warning.c
new file mode 100644
index 000000000000..7b5095f6e923
--- /dev/null
+++ b/test/Preprocessor/extension-warning.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+
+// The preprocessor shouldn't warn about extensions within macro bodies that
+// aren't expanded.
+#define TY typeof
+#define TY1 typeof(1)
+
+// But we should warn here
+TY1 x; // expected-warning {{extension}}
+TY(1) x; // FIXME: And we should warn here
+
+// Note: this warning intentionally doesn't trigger on keywords like
+// __attribute; the standard allows implementation-defined extensions
+// prefixed with "__".
+// Current list of keywords this can trigger on:
+// inline, restrict, asm, typeof, _asm
+
+void whatever() {}
diff --git a/test/Preprocessor/file_to_include.h b/test/Preprocessor/file_to_include.h
new file mode 100644
index 000000000000..97728ab0830b
--- /dev/null
+++ b/test/Preprocessor/file_to_include.h
@@ -0,0 +1,3 @@
+
+#warning file successfully included
+
diff --git a/test/Preprocessor/function_macro_file.c b/test/Preprocessor/function_macro_file.c
new file mode 100644
index 000000000000..6a266dd0790a
--- /dev/null
+++ b/test/Preprocessor/function_macro_file.c
@@ -0,0 +1,5 @@
+/* RUN: clang-cc -E -P %s | grep f
+ */
+
+#include "function_macro_file.h"
+()
diff --git a/test/Preprocessor/function_macro_file.h b/test/Preprocessor/function_macro_file.h
new file mode 100644
index 000000000000..43d1199bfebb
--- /dev/null
+++ b/test/Preprocessor/function_macro_file.h
@@ -0,0 +1,3 @@
+
+#define f() x
+f
diff --git a/test/Preprocessor/hash_line.c b/test/Preprocessor/hash_line.c
new file mode 100644
index 000000000000..7ed65d1b424d
--- /dev/null
+++ b/test/Preprocessor/hash_line.c
@@ -0,0 +1,8 @@
+// The 1 and # should not go on the same line.
+// RUN: clang-cc %s -E | not grep "1 #" &&
+// RUN: clang-cc %s -E | grep '^1$' &&
+// RUN: clang-cc %s -E | grep '^ #$'
+1
+#define EMPTY
+EMPTY #
+
diff --git a/test/Preprocessor/hash_space.c b/test/Preprocessor/hash_space.c
new file mode 100644
index 000000000000..e7dbd3bc617b
--- /dev/null
+++ b/test/Preprocessor/hash_space.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc %s -E | grep " #"
+
+// Should put a space before the # so that -fpreprocessed mode doesn't
+// macro expand this again.
+#define HASH #
+HASH define foo bar
diff --git a/test/Preprocessor/header_lookup1.c b/test/Preprocessor/header_lookup1.c
new file mode 100644
index 000000000000..df58a6ea9c54
--- /dev/null
+++ b/test/Preprocessor/header_lookup1.c
@@ -0,0 +1,2 @@
+// RUN: clang-cc -I /usr/include %s -E | grep 'stdio.h.*3.*4'
+#include <stdio.h>
diff --git a/test/Preprocessor/if_warning.c b/test/Preprocessor/if_warning.c
new file mode 100644
index 000000000000..5567513c3630
--- /dev/null
+++ b/test/Preprocessor/if_warning.c
@@ -0,0 +1,21 @@
+// RUN: clang-cc %s -Eonly -Werror=undef -verify &&
+// RUN: clang-cc %s -Eonly -Werror-undef -verify
+
+extern int x;
+
+#if foo // expected-error {{'foo' is not defined, evaluates to 0}}
+#endif
+
+#ifdef foo
+#endif
+
+#if defined(foo)
+#endif
+
+
+// PR3938
+#if 0
+#ifdef D
+#else 1 // Should not warn due to C99 6.10p4
+#endif
+#endif
diff --git a/test/Preprocessor/ifdef-recover.c b/test/Preprocessor/ifdef-recover.c
new file mode 100644
index 000000000000..3fffcc0290de
--- /dev/null
+++ b/test/Preprocessor/ifdef-recover.c
@@ -0,0 +1,15 @@
+/* RUN: clang-cc -E %s 2>&1 >/dev/null | grep error: | count 3
+ */
+
+#ifdef
+
+#endif
+
+/* End of function-like macro invocation in #ifdef */
+/* PR1936 */
+#define f(x) x
+#if f(2
+#endif
+
+int x;
+
diff --git a/test/Preprocessor/import_self.c b/test/Preprocessor/import_self.c
new file mode 100644
index 000000000000..2cabe3d71ca6
--- /dev/null
+++ b/test/Preprocessor/import_self.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -E -I. %s | grep BODY_OF_FILE | wc -l | grep 1
+
+// This #import should have no effect, as we're importing the current file.
+#import <import_self.c>
+
+BODY_OF_FILE
+
diff --git a/test/Preprocessor/include-directive1.c b/test/Preprocessor/include-directive1.c
new file mode 100644
index 000000000000..66f70fb3a9e5
--- /dev/null
+++ b/test/Preprocessor/include-directive1.c
@@ -0,0 +1,14 @@
+// RUN: clang-cc -E %s -fno-caret-diagnostics 2>&1 >/dev/null | grep 'file successfully included' | count 3
+
+// XX expands to nothing.
+#define XX
+
+// expand macros to get to file to include
+#define FILE "file_to_include.h"
+#include XX FILE
+
+#include FILE
+
+// normal include
+#include "file_to_include.h"
+
diff --git a/test/Preprocessor/include-directive2.c b/test/Preprocessor/include-directive2.c
new file mode 100644
index 000000000000..123998246bff
--- /dev/null
+++ b/test/Preprocessor/include-directive2.c
@@ -0,0 +1,17 @@
+// RUN: clang-cc -Eonly -verify %s
+# define HEADER <float.h>
+
+# include HEADER
+
+#include <limits.h> NON_EMPTY // expected-warning {{extra tokens at end of #include directive}}
+
+// PR3916: these are ok.
+#define EMPTY
+#include <limits.h> EMPTY
+#include HEADER EMPTY
+
+// PR3916
+#define FN limits.h>
+#include <FN
+
+#include <> // expected-error {{empty filename}}
diff --git a/test/Preprocessor/include-directive3.c b/test/Preprocessor/include-directive3.c
new file mode 100644
index 000000000000..e5b7a940c6cb
--- /dev/null
+++ b/test/Preprocessor/include-directive3.c
@@ -0,0 +1,3 @@
+// RUN: clang-cc -include %S/file_to_include.h -E %s -fno-caret-diagnostics 2>&1 >/dev/null | grep 'file successfully included' | count 1
+// PR3464
+
diff --git a/test/Preprocessor/include-macros.c b/test/Preprocessor/include-macros.c
new file mode 100644
index 000000000000..d64ee5e3e6d9
--- /dev/null
+++ b/test/Preprocessor/include-macros.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -E -Dtest=FOO -imacros %S/pr2086.h %s | grep 'HERE: test'
+
+// This should not be expanded into FOO because pr2086.h undefs 'test'.
+HERE: test
diff --git a/test/Preprocessor/include-pth.c b/test/Preprocessor/include-pth.c
new file mode 100644
index 000000000000..2afc66a55b0b
--- /dev/null
+++ b/test/Preprocessor/include-pth.c
@@ -0,0 +1,3 @@
+// RUN: clang-cc -emit-pth %s -o %t &&
+// RUN: clang-cc -include-pth %t %s -E | grep 'file_to_include' | count 2
+#include "file_to_include.h"
diff --git a/test/Preprocessor/indent_macro.c b/test/Preprocessor/indent_macro.c
new file mode 100644
index 000000000000..f6b411e93ff0
--- /dev/null
+++ b/test/Preprocessor/indent_macro.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -E %s | grep '^ zzap$'
+
+// zzap is on a new line, should be indented.
+#define BLAH zzap
+ BLAH
+
diff --git a/test/Preprocessor/line-directive.c b/test/Preprocessor/line-directive.c
new file mode 100644
index 000000000000..ed9a6c40e5d7
--- /dev/null
+++ b/test/Preprocessor/line-directive.c
@@ -0,0 +1,92 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s &&
+// RUN: clang-cc -E %s 2>&1 | grep 'blonk.c:92:2: error: #error ABC' &&
+// RUN: clang-cc -E %s 2>&1 | grep 'blonk.c:93:2: error: #error DEF'
+
+#line 'a' // expected-error {{#line directive requires a positive integer argument}}
+#line 0 // expected-error {{#line directive requires a positive integer argument}}
+#line 00 // expected-error {{#line directive requires a positive integer argument}}
+#line 2147483648 // expected-warning {{C requires #line number to be less than 2147483648, allowed as extension}}
+#line 42 // ok
+#line 42 'a' // expected-error {{invalid filename for #line directive}}
+#line 42 "foo/bar/baz.h" // ok
+
+
+// #line directives expand macros.
+#define A 42 "foo"
+#line A
+
+# 42
+# 42 "foo"
+# 42 "foo" 2 // expected-error {{invalid line marker flag '2': cannot pop empty include stack}}
+# 42 "foo" 1 3 // enter
+# 42 "foo" 2 3 // exit
+# 42 "foo" 2 3 4 // expected-error {{invalid line marker flag '2': cannot pop empty include stack}}
+# 42 "foo" 3 4
+
+# 'a' // expected-error {{invalid preprocessing directive}}
+# 42 'f' // expected-error {{invalid filename for line marker directive}}
+# 42 1 3 // expected-error {{invalid filename for line marker directive}}
+# 42 "foo" 3 1 // expected-error {{invalid flag line marker directive}}
+# 42 "foo" 42 // expected-error {{invalid flag line marker directive}}
+# 42 "foo" 1 2 // expected-error {{invalid flag line marker directive}}
+
+
+// These are checked by the RUN line.
+#line 92 "blonk.c"
+#error ABC // expected-error {{#error ABC}}
+#error DEF // expected-error {{#error DEF}}
+
+
+// Verify that linemarker diddling of the system header flag works.
+
+# 192 "glomp.h" // not a system header.
+typedef int x; // expected-note {{previous definition is here}}
+typedef int x; // expected-error {{redefinition of typedef 'x' is invalid in C}}
+
+# 192 "glomp.h" 3 // System header.
+typedef int y; // ok
+typedef int y; // ok
+
+typedef int q; // q is in system header.
+
+#line 42 "blonk.h" // doesn't change system headerness.
+
+typedef int z; // ok
+typedef int z; // ok
+
+# 97 // doesn't change system headerness.
+
+typedef int z1; // ok
+typedef int z1; // ok
+
+# 42 "blonk.h" // DOES change system headerness.
+
+typedef int w; // expected-note {{previous definition is here}}
+typedef int w; // expected-error {{redefinition of typedef 'w' is invalid in C}}
+
+typedef int q; // original definition in system header, should not diagnose.
+
+// This should not produce an "extra tokens at end of #line directive" warning,
+// because #line is allowed to contain expanded tokens.
+#define EMPTY()
+#line 2 "foo.c" EMPTY( )
+#line 2 "foo.c" NONEMPTY( ) // expected-warning{{extra tokens at end of #line directive}}
+
+// PR3940
+#line 0xf // expected-error {{#line directive requires a simple digit sequence}}
+#line 42U // expected-error {{#line directive requires a simple digit sequence}}
+
+
+// Line markers are digit strings interpreted as decimal numbers, this is
+// 10, not 8.
+#line 010 // expected-warning {{#line directive interprets number as decimal, not octal}}
+extern int array[__LINE__ == 10 ? 1:-1];
+
+/* PR3917 */
+#line 41
+extern char array2[\
+_\
+_LINE__ == 42 ? 1: -1]; /* line marker is location of first _ */
+
+
+
diff --git a/test/Preprocessor/macro-multiline.c b/test/Preprocessor/macro-multiline.c
new file mode 100644
index 000000000000..eb15668ce31f
--- /dev/null
+++ b/test/Preprocessor/macro-multiline.c
@@ -0,0 +1,8 @@
+// RUN: clang -E %s "-DX=A
+// RUN: THIS_SHOULD_NOT_EXIST_IN_THE_OUTPUT" > %t &&
+// RUN: grep "GOOD: A" %t &&
+// RUN: not grep THIS_SHOULD_NOT_EXIST_IN_THE_OUTPUT %t
+// rdar://6762183
+
+GOOD: X
+
diff --git a/test/Preprocessor/macro_arg_keyword.c b/test/Preprocessor/macro_arg_keyword.c
new file mode 100644
index 000000000000..92b1ae535713
--- /dev/null
+++ b/test/Preprocessor/macro_arg_keyword.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -E %s | grep xxx-xxx
+
+#define foo(return) return-return
+
+foo(xxx)
+
diff --git a/test/Preprocessor/macro_disable.c b/test/Preprocessor/macro_disable.c
new file mode 100644
index 000000000000..ff861d262197
--- /dev/null
+++ b/test/Preprocessor/macro_disable.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -E %s | grep 'a: 2 + M_0(3)(4)(5);' &&
+// RUN: clang-cc -E %s | grep 'b: 4 + 4 + 3 + 2 + 1 + M_0(3)(2)(1);'
+
+#define M_0(x) M_ ## x
+#define M_1(x) x + M_0(0)
+#define M_2(x) x + M_1(1)
+#define M_3(x) x + M_2(2)
+#define M_4(x) x + M_3(3)
+#define M_5(x) x + M_4(4)
+
+a: M_0(1)(2)(3)(4)(5);
+b: M_0(5)(4)(3)(2)(1);
+
diff --git a/test/Preprocessor/macro_disable2.c b/test/Preprocessor/macro_disable2.c
new file mode 100644
index 000000000000..286539e96f43
--- /dev/null
+++ b/test/Preprocessor/macro_disable2.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -E %s | grep 'A B C A B A C A B C A'
+
+#define A A B C
+#define B B C A
+#define C C A B
+
+A
+
diff --git a/test/Preprocessor/macro_disable3.c b/test/Preprocessor/macro_disable3.c
new file mode 100644
index 000000000000..011de3beed3d
--- /dev/null
+++ b/test/Preprocessor/macro_disable3.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc %s -E | grep -F 'f(2 * (f(2 * (z[0]))));'
+// Check for C99 6.10.3.4p2.
+
+#define f(a) f(x * (a))
+#define x 2
+#define z z[0]
+f(f(z));
+
diff --git a/test/Preprocessor/macro_disable4.c b/test/Preprocessor/macro_disable4.c
new file mode 100644
index 000000000000..b652b988d020
--- /dev/null
+++ b/test/Preprocessor/macro_disable4.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -P -E %s | grep 'int f(void)'
+// PR1820
+
+#define f(x) h(x
+#define h(x) x(void)
+extern int f(f));
diff --git a/test/Preprocessor/macro_expand.c b/test/Preprocessor/macro_expand.c
new file mode 100644
index 000000000000..74b3922d1e13
--- /dev/null
+++ b/test/Preprocessor/macro_expand.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc -E %s | grep '^A: Y$' &&
+// RUN: clang-cc -E %s | grep '^B: f()$' &&
+// RUN: clang-cc -E %s | grep '^C: for()$'
+
+#define X() Y
+#define Y() X
+
+A: X()()()
+
+// PR3927
+#define f(x) h(x
+#define for(x) h(x
+#define h(x) x()
+B: f(f))
+C: for(for))
+
+// rdar://6880648
+#define f(x,y...) y
+f()
diff --git a/test/Preprocessor/macro_expandloc.c b/test/Preprocessor/macro_expandloc.c
new file mode 100644
index 000000000000..ce1efd20a277
--- /dev/null
+++ b/test/Preprocessor/macro_expandloc.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc %s -E 2>&1 | grep '#include'
+#define FOO 1
+
+// The error message should be on the #include line, not the 1.
+#include FOO
+
diff --git a/test/Preprocessor/macro_expandloc2.c b/test/Preprocessor/macro_expandloc2.c
new file mode 100644
index 000000000000..9adf3fd911f9
--- /dev/null
+++ b/test/Preprocessor/macro_expandloc2.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc %s -E 2>&1 | grep '#include'
+#define FOO BAR
+
+// The error message should be on the #include line, not the 1.
+#include FOO
+
diff --git a/test/Preprocessor/macro_fn.c b/test/Preprocessor/macro_fn.c
new file mode 100644
index 000000000000..5c55c0ceed5f
--- /dev/null
+++ b/test/Preprocessor/macro_fn.c
@@ -0,0 +1,46 @@
+/* RUN: clang-cc %s -Eonly -std=c89 -pedantic -verify
+*/
+/* PR3937 */
+#define zero() 0
+#define one(x) 0
+#define two(x, y) 0
+#define zero_dot(...) 0 /* expected-warning {{variadic macros were introduced in C99}} */
+#define one_dot(x, ...) 0 /* expected-warning {{variadic macros were introduced in C99}} */
+
+zero()
+zero(1); /* expected-error {{too many arguments provided to function-like macro invocation}} */
+zero(1, 2, 3); /* expected-error {{too many arguments provided to function-like macro invocation}} */
+
+one() /* ok */
+one(a)
+one(a,) /* expected-error {{too many arguments provided to function-like macro invocation}} */
+one(a, b) /* expected-error {{too many arguments provided to function-like macro invocation}} */
+
+two() /* expected-error {{too few arguments provided to function-like macro invocation}} */
+two(a) /* expected-error {{too few arguments provided to function-like macro invocation}} */
+two(a,b)
+two(a, ) /* expected-warning {{empty macro arguments were standardized in C99}} */
+two(a,b,c) /* expected-error {{too many arguments provided to function-like macro invocation}} */
+two(
+ , /* expected-warning {{empty macro arguments were standardized in C99}} */
+ , /* expected-warning {{empty macro arguments were standardized in C99}} \
+ expected-error {{too many arguments provided to function-like macro invocation}} */
+ )
+two(,) /* expected-warning 2 {{empty macro arguments were standardized in C99}} */
+
+
+
+/* PR4006 & rdar://6807000 */
+#define e(...) __VA_ARGS__ /* expected-warning {{variadic macros were introduced in C99}} */
+e(x)
+e()
+
+zero_dot()
+one_dot(x) /* empty ... argument: expected-warning {{varargs argument missing, but tolerated as an extension}} */
+one_dot() /* empty first argument, elided ...: expected-warning {{varargs argument missing, but tolerated as an extension}} */
+
+
+/* rdar://6816766 - Crash with function-like macro test at end of directive. */
+#define E() (i == 0)
+#if E
+#endif
diff --git a/test/Preprocessor/macro_fn_comma_swallow.c b/test/Preprocessor/macro_fn_comma_swallow.c
new file mode 100644
index 000000000000..e985138a5c44
--- /dev/null
+++ b/test/Preprocessor/macro_fn_comma_swallow.c
@@ -0,0 +1,21 @@
+// Test the GNU comma swallowing extension.
+// RUN: clang-cc %s -E | grep 'foo{A, }' &&
+// RUN: clang-cc %s -E | grep 'fo2{A,}' &&
+// RUN: clang-cc %s -E | grep '{foo}'
+
+#define X(Y) foo{A, Y}
+X()
+
+#define X2(Y) fo2{A,##Y}
+X2()
+
+// should eat the comma.
+#define X3(b, ...) {b, ## __VA_ARGS__}
+X3(foo)
+
+
+
+// RUN: clang-cc %s -E | grep 'AA BB'
+// PR3880
+#define X4(...) AA , ## __VA_ARGS__ BB
+X4()
diff --git a/test/Preprocessor/macro_fn_disable_expand.c b/test/Preprocessor/macro_fn_disable_expand.c
new file mode 100644
index 000000000000..d99c01832eac
--- /dev/null
+++ b/test/Preprocessor/macro_fn_disable_expand.c
@@ -0,0 +1,11 @@
+// RUN: clang-cc %s -E | grep 'bar foo (2)' &&
+// RUN: clang-cc %s -E | grep 'm(ABCD)'
+
+#define foo(x) bar x
+foo(foo) (2)
+
+
+#define m(a) a(w)
+#define w ABCD
+m(m) // m(ABCD)
+
diff --git a/test/Preprocessor/macro_fn_lparen_scan.c b/test/Preprocessor/macro_fn_lparen_scan.c
new file mode 100644
index 000000000000..1056fd82341a
--- /dev/null
+++ b/test/Preprocessor/macro_fn_lparen_scan.c
@@ -0,0 +1,27 @@
+// RUN: clang-cc -E %s | grep 'noexp: foo y' &&
+// RUN: clang-cc -E %s | grep 'expand: abc' &&
+// RUN: clang-cc -E %s | grep 'noexp2: foo nonexp' &&
+// RUN: clang-cc -E %s | grep 'expand2: abc'
+
+#define A foo
+#define foo() abc
+#define X A y
+
+// This should not expand to abc, because the foo macro isn't followed by (.
+noexp: X
+
+
+// This should expand to abc.
+#undef X
+#define X A ()
+expand: X
+
+
+// This should be 'foo nonexp'
+noexp2: A nonexp
+
+// This should expand
+expand2: A (
+)
+
+
diff --git a/test/Preprocessor/macro_fn_lparen_scan2.c b/test/Preprocessor/macro_fn_lparen_scan2.c
new file mode 100644
index 000000000000..fb64befaf1e9
--- /dev/null
+++ b/test/Preprocessor/macro_fn_lparen_scan2.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -E %s | grep 'FUNC (3 +1);'
+
+#define F(a) a
+#define FUNC(a) (a+1)
+
+F(FUNC) FUNC (3); /* final token sequence is FUNC(3+1) */
+
diff --git a/test/Preprocessor/macro_fn_placemarker.c b/test/Preprocessor/macro_fn_placemarker.c
new file mode 100644
index 000000000000..ff688ce2d7ae
--- /dev/null
+++ b/test/Preprocessor/macro_fn_placemarker.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc %s -E | grep 'foo(A, )'
+
+#define X(Y) foo(A, Y)
+X()
+
diff --git a/test/Preprocessor/macro_fn_preexpand.c b/test/Preprocessor/macro_fn_preexpand.c
new file mode 100644
index 000000000000..a392263aef43
--- /dev/null
+++ b/test/Preprocessor/macro_fn_preexpand.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc %s -E | grep 'pre: 1 1 X' &&
+// RUN: clang-cc %s -E | grep 'nopre: 1A(X)'
+
+/* Preexpansion of argument. */
+#define A(X) 1 X
+pre: A(A(X))
+
+/* The ## operator disables preexpansion. */
+#undef A
+#define A(X) 1 ## X
+nopre: A(A(X))
+
diff --git a/test/Preprocessor/macro_fn_varargs_iso.c b/test/Preprocessor/macro_fn_varargs_iso.c
new file mode 100644
index 000000000000..78ad212405cf
--- /dev/null
+++ b/test/Preprocessor/macro_fn_varargs_iso.c
@@ -0,0 +1,11 @@
+
+// RUN: clang-cc -E %s | grep 'foo{a, b, c, d, e}' &&
+// RUN: clang-cc -E %s | grep 'foo2{d, C, B}' &&
+// RUN: clang-cc -E %s | grep 'foo2{d,e, C, B}'
+
+#define va1(...) foo{a, __VA_ARGS__, e}
+va1(b, c, d)
+#define va2(a, b, ...) foo2{__VA_ARGS__, b, a}
+va2(B, C, d)
+va2(B, C, d,e)
+
diff --git a/test/Preprocessor/macro_fn_varargs_named.c b/test/Preprocessor/macro_fn_varargs_named.c
new file mode 100644
index 000000000000..c2841b1574b1
--- /dev/null
+++ b/test/Preprocessor/macro_fn_varargs_named.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -E %s | grep '^a: x$' &&
+// RUN: clang-cc -E %s | grep '^b: x y, z,h$' &&
+// RUN: clang-cc -E %s | grep '^c: foo(x)$'
+
+#define A(b, c...) b c
+a: A(x)
+b: A(x, y, z,h)
+
+#define B(b, c...) foo(b, ## c)
+c: B(x)
diff --git a/test/Preprocessor/macro_misc.c b/test/Preprocessor/macro_misc.c
new file mode 100644
index 000000000000..169c5ec772a2
--- /dev/null
+++ b/test/Preprocessor/macro_misc.c
@@ -0,0 +1,23 @@
+// RUN: clang-cc %s -Eonly -verify
+
+// This should not be rejected.
+#ifdef defined
+#endif
+
+
+
+// PR3764
+
+// This should not produce a redefinition warning.
+#define FUNC_LIKE(a) (a)
+#define FUNC_LIKE(a)(a)
+
+// This either.
+#define FUNC_LIKE2(a)\
+(a)
+#define FUNC_LIKE2(a) (a)
+
+// This should.
+#define FUNC_LIKE3(a) ( a) // expected-note {{previous definition is here}}
+#define FUNC_LIKE3(a) (a) // expected-warning {{'FUNC_LIKE3' macro redefined}}
+
diff --git a/test/Preprocessor/macro_not_define.c b/test/Preprocessor/macro_not_define.c
new file mode 100644
index 000000000000..a42240bab607
--- /dev/null
+++ b/test/Preprocessor/macro_not_define.c
@@ -0,0 +1,9 @@
+// RUN: clang-cc -E %s | grep '^ # define X 3$'
+
+#define H #
+ #define D define
+
+ #define DEFINE(a, b) H D a b
+
+ DEFINE(X, 3)
+
diff --git a/test/Preprocessor/macro_paste_bad.c b/test/Preprocessor/macro_paste_bad.c
new file mode 100644
index 000000000000..1212c44c1aa7
--- /dev/null
+++ b/test/Preprocessor/macro_paste_bad.c
@@ -0,0 +1,35 @@
+// RUN: clang-cc -Eonly -verify -pedantic %s
+// pasting ""x"" and ""+"" does not give a valid preprocessing token
+#define XYZ x ## +
+XYZ // expected-error {{pasting formed 'x+', an invalid preprocessing token}}
+#define XXYZ . ## test
+XXYZ // expected-error {{pasting formed '.test', an invalid preprocessing token}}
+
+// GCC PR 20077
+
+#define a a ## ## // expected-error {{'##' cannot appear at end of macro expansion}}
+#define b() b ## ## // expected-error {{'##' cannot appear at end of macro expansion}}
+#define c c ## // expected-error {{'##' cannot appear at end of macro expansion}}
+#define d() d ## // expected-error {{'##' cannot appear at end of macro expansion}}
+
+
+#define e ## ## e // expected-error {{'##' cannot appear at start of macro expansion}}
+#define f() ## ## f // expected-error {{'##' cannot appear at start of macro expansion}}
+#define g ## g // expected-error {{'##' cannot appear at start of macro expansion}}
+#define h() ## h // expected-error {{'##' cannot appear at start of macro expansion}}
+#define i ## // expected-error {{'##' cannot appear at start of macro expansion}}
+#define j() ## // expected-error {{'##' cannot appear at start of macro expansion}}
+
+// Invalid token pasting.
+// PR3918
+
+// When pasting creates poisoned identifiers, we error.
+#pragma GCC poison BLARG
+BLARG // expected-error {{attempt to use a poisoned identifier}}
+#define XX BL ## ARG
+XX // expected-error {{attempt to use a poisoned identifier}}
+
+#define VA __VA_ ## ARGS__
+int VA; // expected-warning {{__VA_ARGS__ can only appear in the expansion of a C99 variadic macro}}
+
+
diff --git a/test/Preprocessor/macro_paste_bcpl_comment.c b/test/Preprocessor/macro_paste_bcpl_comment.c
new file mode 100644
index 000000000000..8bbee5dc2dd9
--- /dev/null
+++ b/test/Preprocessor/macro_paste_bcpl_comment.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc %s -Eonly 2>&1 | grep error
+
+#define COMM1 / ## /
+COMM1
+
diff --git a/test/Preprocessor/macro_paste_c_block_comment.c b/test/Preprocessor/macro_paste_c_block_comment.c
new file mode 100644
index 000000000000..86f812421d8c
--- /dev/null
+++ b/test/Preprocessor/macro_paste_c_block_comment.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc %s -Eonly 2>&1 | grep error &&
+// RUN: clang-cc %s -Eonly 2>&1 | not grep unterminated &&
+// RUN: clang-cc %s -Eonly 2>&1 | not grep scratch
+
+#define COMM / ## *
+COMM
+
diff --git a/test/Preprocessor/macro_paste_commaext.c b/test/Preprocessor/macro_paste_commaext.c
new file mode 100644
index 000000000000..e98849b15afc
--- /dev/null
+++ b/test/Preprocessor/macro_paste_commaext.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc %s -E | grep 'V);' &&
+// RUN: clang-cc %s -E | grep 'W, 1, 2);' &&
+// RUN: clang-cc %s -E | grep 'X, 1, 2);' &&
+// RUN: clang-cc %s -E | grep 'Y, );' &&
+// RUN: clang-cc %s -E | grep 'Z, );'
+
+#define debug(format, ...) format, ## __VA_ARGS__)
+debug(V);
+debug(W, 1, 2);
+debug(X, 1, 2 );
+debug(Y, );
+debug(Z,);
+
diff --git a/test/Preprocessor/macro_paste_empty.c b/test/Preprocessor/macro_paste_empty.c
new file mode 100644
index 000000000000..75504bc22a78
--- /dev/null
+++ b/test/Preprocessor/macro_paste_empty.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -E %s | grep 'a:Y' &&
+// RUN: clang-cc -E %s | grep 'b:Y' &&
+// RUN: clang-cc -E %s | grep 'c:YY'
+
+#define FOO(X) X ## Y
+a:FOO()
+
+#define FOO2(X) Y ## X
+b:FOO2()
+
+#define FOO3(X) X ## Y ## X ## Y ## X ## X
+c:FOO3()
+
diff --git a/test/Preprocessor/macro_paste_hard.c b/test/Preprocessor/macro_paste_hard.c
new file mode 100644
index 000000000000..25b6c1994b5c
--- /dev/null
+++ b/test/Preprocessor/macro_paste_hard.c
@@ -0,0 +1,17 @@
+// RUN: clang-cc -E %s | grep '1: aaab 2' &&
+// RUN: clang-cc -E %s | grep '2: 2 baaa' &&
+// RUN: clang-cc -E %s | grep '3: 2 xx'
+
+#define a(n) aaa ## n
+#define b 2
+1: a(b b) // aaab 2 2 gets expanded, not b.
+
+#undef a
+#undef b
+#define a(n) n ## aaa
+#define b 2
+2: a(b b) // 2 baaa 2 gets expanded, not b.
+
+#define baaa xx
+3: a(b b) // 2 xx
+
diff --git a/test/Preprocessor/macro_paste_hashhash.c b/test/Preprocessor/macro_paste_hashhash.c
new file mode 100644
index 000000000000..42654fd1b18b
--- /dev/null
+++ b/test/Preprocessor/macro_paste_hashhash.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -E %s | grep '^"x ## y";$'
+#define hash_hash # ## #
+#define mkstr(a) # a
+#define in_between(a) mkstr(a)
+#define join(c, d) in_between(c hash_hash d)
+join(x, y);
+
diff --git a/test/Preprocessor/macro_paste_mscomment.c b/test/Preprocessor/macro_paste_mscomment.c
new file mode 100644
index 000000000000..b0fc57101c64
--- /dev/null
+++ b/test/Preprocessor/macro_paste_mscomment.c
@@ -0,0 +1,20 @@
+// RUN: clang-cc -P -E -fms-extensions %s | sed '/^#.\+/d' | tr -d '\n' |
+// RUN: grep '^int foo;int bar;int baz;$' | count 1
+// This horrible stuff should preprocess into (other than whitespace):
+// int foo;
+// int bar;
+// int baz;
+
+int foo;
+
+#define comment /##/ dead tokens live here
+comment This is stupidity
+
+int bar;
+
+#define nested(x) int x comment cute little dead tokens...
+
+nested(baz) rise of the dead tokens
+
+;
+
diff --git a/test/Preprocessor/macro_paste_none.c b/test/Preprocessor/macro_paste_none.c
new file mode 100644
index 000000000000..e978fca22508
--- /dev/null
+++ b/test/Preprocessor/macro_paste_none.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -E %s | grep '!!'
+
+#define A(B,C) B ## C
+
+!A(,)!
+
diff --git a/test/Preprocessor/macro_paste_simple.c b/test/Preprocessor/macro_paste_simple.c
new file mode 100644
index 000000000000..2affbac0dec3
--- /dev/null
+++ b/test/Preprocessor/macro_paste_simple.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc %s -E | grep "barbaz123"
+
+#define FOO bar ## baz ## 123
+
+FOO
diff --git a/test/Preprocessor/macro_paste_spacing.c b/test/Preprocessor/macro_paste_spacing.c
new file mode 100644
index 000000000000..130548dbf99e
--- /dev/null
+++ b/test/Preprocessor/macro_paste_spacing.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc %s -E | grep "^xy$"
+
+#define A x ## y
+blah
+
+A
+
diff --git a/test/Preprocessor/macro_paste_spacing2.c b/test/Preprocessor/macro_paste_spacing2.c
new file mode 100644
index 000000000000..0db721aa7b41
--- /dev/null
+++ b/test/Preprocessor/macro_paste_spacing2.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc %s -E | grep "movl %eax"
+// PR4132
+#define R1E %eax
+#define epilogue(r1) movl r1 ## E;
+epilogue(R1)
+
diff --git a/test/Preprocessor/macro_rescan.c b/test/Preprocessor/macro_rescan.c
new file mode 100644
index 000000000000..17b4dc2756fd
--- /dev/null
+++ b/test/Preprocessor/macro_rescan.c
@@ -0,0 +1,9 @@
+// RUN: clang-cc -E %s | grep 'ei_1 = (17 +1);' &&
+// RUN: clang-cc -E %s | grep 'ei_2 = (M1)(17);'
+
+#define M1(a) (a+1)
+#define M2(b) b
+
+int ei_1 = M2(M1)(17); /* becomes int ei_1 = (17+1); */
+int ei_2 = (M2(M1))(17); /* becomes int ei_2 = (M1)(17); */
+
diff --git a/test/Preprocessor/macro_rescan2.c b/test/Preprocessor/macro_rescan2.c
new file mode 100644
index 000000000000..6914ae0ac5f3
--- /dev/null
+++ b/test/Preprocessor/macro_rescan2.c
@@ -0,0 +1,15 @@
+// RUN: clang-cc %s -E | grep 'a: 2\*f(9)' &&
+// RUN: clang-cc %s -E | grep 'b: 2\*9\*g'
+
+#define f(a) a*g
+#define g f
+a: f(2)(9)
+
+#undef f
+#undef g
+
+#define f(a) a*g
+#define g(a) f(a)
+
+b: f(2)(9)
+
diff --git a/test/Preprocessor/macro_rescan_varargs.c b/test/Preprocessor/macro_rescan_varargs.c
new file mode 100644
index 000000000000..ed1056ab1b3f
--- /dev/null
+++ b/test/Preprocessor/macro_rescan_varargs.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -E %s | grep -F "1: F, (, 'a', 'b', );" &&
+// RUN: clang-cc -E %s | grep -F "2: 'a' + 'b';"
+#define LPAREN (
+#define RPAREN )
+#define F(x, y) x + y
+#define ELLIP_FUNC(...) __VA_ARGS__
+
+1: ELLIP_FUNC(F, LPAREN, 'a', 'b', RPAREN); /* 1st invocation */
+2: ELLIP_FUNC(F LPAREN 'a', 'b' RPAREN); /* 2nd invocation */
+
diff --git a/test/Preprocessor/macro_rparen_scan.c b/test/Preprocessor/macro_rparen_scan.c
new file mode 100644
index 000000000000..927509883845
--- /dev/null
+++ b/test/Preprocessor/macro_rparen_scan.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -E %s | grep '^3 ;$'
+
+/* Right paren scanning, hard case. Should expand to 3. */
+#define i(x) 3
+#define a i(yz
+#define b )
+a b ) ;
+
diff --git a/test/Preprocessor/macro_rparen_scan2.c b/test/Preprocessor/macro_rparen_scan2.c
new file mode 100644
index 000000000000..41748ac459b9
--- /dev/null
+++ b/test/Preprocessor/macro_rparen_scan2.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -E %s | grep -F 'static int glob = (1 + 1 );'
+
+#define R_PAREN )
+
+#define FUNC(a) a
+
+static int glob = (1 + FUNC(1 R_PAREN );
+
diff --git a/test/Preprocessor/macro_space.c b/test/Preprocessor/macro_space.c
new file mode 100644
index 000000000000..4fdbb0a0ceef
--- /dev/null
+++ b/test/Preprocessor/macro_space.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc %s -E | grep '! ,'
+
+#define XX
+! XX,
+
diff --git a/test/Preprocessor/mi_opt.c b/test/Preprocessor/mi_opt.c
new file mode 100644
index 000000000000..aa69e2b4aeac
--- /dev/null
+++ b/test/Preprocessor/mi_opt.c
@@ -0,0 +1,11 @@
+// RUN: not clang-cc -fsyntax-only %s
+// PR1900
+// This test should get a redefinition error from m_iopt.h: the MI opt
+// shouldn't apply.
+
+#define MACRO
+#include "mi_opt.h"
+#undef MACRO
+#define MACRO || 1
+#include "mi_opt.h"
+
diff --git a/test/Preprocessor/mi_opt.h b/test/Preprocessor/mi_opt.h
new file mode 100644
index 000000000000..a82aa6af0f9c
--- /dev/null
+++ b/test/Preprocessor/mi_opt.h
@@ -0,0 +1,4 @@
+#if !defined foo MACRO
+#define foo
+int x = 2;
+#endif
diff --git a/test/Preprocessor/objc-pp.m b/test/Preprocessor/objc-pp.m
new file mode 100644
index 000000000000..4ab2f07cef26
--- /dev/null
+++ b/test/Preprocessor/objc-pp.m
@@ -0,0 +1,4 @@
+// RUN: clang-cc %s -fsyntax-only -verify -pedantic
+
+#import <limits.h> // no warning on #import in objc mode.
+
diff --git a/test/Preprocessor/optimize.c b/test/Preprocessor/optimize.c
new file mode 100644
index 000000000000..46df2a66b920
--- /dev/null
+++ b/test/Preprocessor/optimize.c
@@ -0,0 +1,29 @@
+// RUN: clang-cc -Eonly %s -DOPT_O2 -O2 -verify &&
+#ifdef OPT_O2
+ #ifndef __OPTIMIZE__
+ #error "__OPTIMIZE__ not defined"
+ #endif
+ #ifdef __OPTIMIZE_SIZE__
+ #error "__OPTIMIZE_SIZE__ defined"
+ #endif
+#endif
+
+// RUN: clang-cc -Eonly %s -DOPT_O0 -O0 -verify &&
+#ifdef OPT_O0
+ #ifdef __OPTIMIZE__
+ #error "__OPTIMIZE__ defined"
+ #endif
+ #ifdef __OPTIMIZE_SIZE__
+ #error "__OPTIMIZE_SIZE__ defined"
+ #endif
+#endif
+
+// RUN: clang-cc -Eonly %s -DOPT_OS -Os -verify
+#ifdef OPT_OS
+ #ifndef __OPTIMIZE__
+ #error "__OPTIMIZE__ not defined"
+ #endif
+ #ifdef __OPTIMIZE_SIZE__
+ #error "__OPTIMIZE_SIZE__ not defined"
+ #endif
+#endif
diff --git a/test/Preprocessor/output_paste_avoid.c b/test/Preprocessor/output_paste_avoid.c
new file mode 100644
index 000000000000..ff8afc3e47ac
--- /dev/null
+++ b/test/Preprocessor/output_paste_avoid.c
@@ -0,0 +1,23 @@
+// RUN: clang-cc -E %s -o %t &&
+// This should print as ".. ." to avoid turning into ...
+// RUN: grep -F 'A: . . .' %t &&
+#define y(a) ..a
+A: y(.)
+
+// RUN: grep -F 'C: .. .' %t &&
+#define DOT .
+C: ..DOT
+
+
+// RUN: grep -F 'D: + + - - + + = = =' %t &&
+#define PLUS +
+#define EMPTY
+#define f(x) =x=
+D: +PLUS -EMPTY- PLUS+ f(=)
+
+// RUN: grep -F 'E: L "str"' %t
+
+// Should expand to L "str" not L"str"
+#define test(x) L#x
+E: test(str)
+
diff --git a/test/Preprocessor/overflow.c b/test/Preprocessor/overflow.c
new file mode 100644
index 000000000000..297a35e658fd
--- /dev/null
+++ b/test/Preprocessor/overflow.c
@@ -0,0 +1,25 @@
+// RUN: clang-cc -Eonly %s -verify -triple i686-pc-linux-gnu
+
+// Multiply signed overflow
+#if 0x7FFFFFFFFFFFFFFF*2 // expected-warning {{overflow}}
+#endif
+
+// Multiply unsigned overflow
+#if 0xFFFFFFFFFFFFFFFF*2
+#endif
+
+// Add signed overflow
+#if 0x7FFFFFFFFFFFFFFF+1 // expected-warning {{overflow}}
+#endif
+
+// Add unsigned overflow
+#if 0xFFFFFFFFFFFFFFFF+1
+#endif
+
+// Subtract signed overflow
+#if 0x7FFFFFFFFFFFFFFF- -1 // expected-warning {{overflow}}
+#endif
+
+// Subtract unsigned overflow
+#if 0xFFFFFFFFFFFFFFFF- -1 // expected-warning {{converted from negative value}}
+#endif
diff --git a/test/Preprocessor/pic.c b/test/Preprocessor/pic.c
new file mode 100644
index 000000000000..1cddaa1a91e6
--- /dev/null
+++ b/test/Preprocessor/pic.c
@@ -0,0 +1,10 @@
+// RUN: clang -ccc-host-triple i386-unknown-unknown -static -dM -E -o %t %s &&
+// RUN: grep '#define __PIC__' %t | count 0 &&
+// RUN: grep '#define __pic__' %t | count 0 &&
+// RUN: clang -ccc-host-triple i386-unknown-unknown -fpic -dM -E -o %t %s &&
+// RUN: grep '#define __PIC__ 1' %t | count 1 &&
+// RUN: grep '#define __pic__ 1' %t | count 1 &&
+// RUN: clang -ccc-host-triple i386-unknown-unknown -fPIC -dM -E -o %t %s &&
+// RUN: grep '#define __PIC__ 2' %t | count 1 &&
+// RUN: grep '#define __pic__ 2' %t | count 1 &&
+// RUN: true
diff --git a/test/Preprocessor/pr2086.c b/test/Preprocessor/pr2086.c
new file mode 100644
index 000000000000..4df65a4f7c67
--- /dev/null
+++ b/test/Preprocessor/pr2086.c
@@ -0,0 +1,11 @@
+// RUN: clang-cc -E %s
+
+#define test
+#include "pr2086.h"
+#define test
+#include "pr2086.h"
+
+#ifdef test
+#error
+#endif
+
diff --git a/test/Preprocessor/pr2086.h b/test/Preprocessor/pr2086.h
new file mode 100644
index 000000000000..b98b996d6cca
--- /dev/null
+++ b/test/Preprocessor/pr2086.h
@@ -0,0 +1,6 @@
+#ifndef test
+#endif
+
+#ifdef test
+#undef test
+#endif
diff --git a/test/Preprocessor/pragma_microsoft.c b/test/Preprocessor/pragma_microsoft.c
new file mode 100644
index 000000000000..81e90e3de69f
--- /dev/null
+++ b/test/Preprocessor/pragma_microsoft.c
@@ -0,0 +1,20 @@
+// RUN: clang-cc %s -fsyntax-only -verify -fms-extensions
+
+// rdar://6495941
+
+#define FOO 1
+#define BAR "2"
+
+#pragma comment(linker,"foo=" FOO) // expected-error {{pragma comment requires parenthesized identifier and optional string}}
+#pragma comment(linker," bar=" BAR)
+
+#pragma comment( user, "Compiled on " __DATE__ " at " __TIME__ )
+
+#pragma comment(foo) // expected-error {{unknown kind of pragma comment}}
+#pragma comment(compiler,) // expected-error {{pragma comment requires}}
+#define foo compiler
+#pragma comment(foo) // macro expand kind.
+#pragma comment(foo) x // expected-error {{pragma comment requires}}
+
+#pragma comment(user, "foo\abar\nbaz\tsome thing")
+
diff --git a/test/Preprocessor/pragma_poison.c b/test/Preprocessor/pragma_poison.c
new file mode 100644
index 000000000000..d91feb7ff2de
--- /dev/null
+++ b/test/Preprocessor/pragma_poison.c
@@ -0,0 +1,20 @@
+// RUN: clang-cc %s -Eonly -verify
+
+#pragma GCC poison rindex
+rindex(some_string, 'h'); // expected-error {{attempt to use a poisoned identifier}}
+
+#define BAR _Pragma ("GCC poison XYZW") XYZW /*NO ERROR*/
+ XYZW // ok
+BAR
+ XYZW // expected-error {{attempt to use a poisoned identifier}}
+
+// Pragma poison shouldn't warn from macro expansions defined before the token
+// is poisoned.
+
+#define strrchr rindex2
+#pragma GCC poison rindex2
+
+// Can poison multiple times.
+#pragma GCC poison rindex2
+
+strrchr(some_string, 'h'); // ok.
diff --git a/test/Preprocessor/pragma_unknown.c b/test/Preprocessor/pragma_unknown.c
new file mode 100644
index 000000000000..16bf43b3f42e
--- /dev/null
+++ b/test/Preprocessor/pragma_unknown.c
@@ -0,0 +1,28 @@
+// RUN: clang-cc -E %s | grep '#pragma foo bar' &&
+// RUN: clang-cc -fsyntax-only -Wunknown-pragmas -verify %s
+
+// GCC doesn't expand macro args for unrecognized pragmas.
+#define bar xX
+#pragma foo bar // expected-warning {{unknown pragma ignored}}
+
+#pragma STDC FP_CONTRACT ON
+#pragma STDC FP_CONTRACT OFF
+#pragma STDC FP_CONTRACT DEFAULT
+#pragma STDC FP_CONTRACT IN_BETWEEN // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}}
+
+#pragma STDC FENV_ACCESS ON // expected-warning {{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}}
+#pragma STDC FENV_ACCESS OFF
+#pragma STDC FENV_ACCESS DEFAULT
+#pragma STDC FENV_ACCESS IN_BETWEEN // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}}
+
+#pragma STDC CX_LIMITED_RANGE ON
+#pragma STDC CX_LIMITED_RANGE OFF
+#pragma STDC CX_LIMITED_RANGE DEFAULT
+#pragma STDC CX_LIMITED_RANGE IN_BETWEEN // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}}
+
+#pragma STDC CX_LIMITED_RANGE // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}}
+#pragma STDC CX_LIMITED_RANGE ON FULL POWER // expected-warning {{expected end of macro in STDC pragma}}
+
+#pragma STDC SO_GREAT // expected-warning {{unknown pragma in STDC namespace}}
+#pragma STDC // expected-warning {{unknown pragma in STDC namespace}}
+
diff --git a/test/Preprocessor/print_line_track.c b/test/Preprocessor/print_line_track.c
new file mode 100644
index 000000000000..539433d1af04
--- /dev/null
+++ b/test/Preprocessor/print_line_track.c
@@ -0,0 +1,17 @@
+/* RUN: clang-cc -E %s | grep 'a 3' &&
+ * RUN: clang-cc -E %s | grep 'b 16' &&
+ * RUN: clang-cc -E -P %s | grep 'a 3' &&
+ * RUN: clang-cc -E -P %s | grep 'b 16' &&
+ * RUN: clang-cc -E %s | not grep '# 0 '
+ * PR1848
+ * PR3437
+*/
+
+#define t(x) x
+
+t(a
+3)
+
+t(b
+__LINE__)
+
diff --git a/test/Preprocessor/skipping_unclean.c b/test/Preprocessor/skipping_unclean.c
new file mode 100644
index 000000000000..31ce9b460def
--- /dev/null
+++ b/test/Preprocessor/skipping_unclean.c
@@ -0,0 +1,9 @@
+// RUN: clang-cc -E %s | grep bark
+
+#if 0
+blah
+#\
+else
+bark
+#endif
+
diff --git a/test/Preprocessor/stringize_misc.c b/test/Preprocessor/stringize_misc.c
new file mode 100644
index 000000000000..251116acad66
--- /dev/null
+++ b/test/Preprocessor/stringize_misc.c
@@ -0,0 +1,26 @@
+// RUN: clang-cc -E %s | grep -F '"f(1, 2)" "g((x=y++, y))"' &&
+// RUN: clang-cc -E %s | grep -F '"{a=1" "b=2;}"' &&
+// RUN: clang-cc -E %s | grep -F '"<" "["' &&
+// RUN: clang-cc -E %s | grep -F '"(,)" "(...)"' &&
+// RUN: clang-cc -E %s | grep -F '{a=1 c=3; b=2;}' &&
+// RUN: clang-cc -E %s | grep -F '"a COMMA b" "(a, b)"'
+
+#define M(x, y) #x #y
+
+M( f(1, 2), g((x=y++, y)))
+M( {a=1 , b=2;} ) /* A semicolon is not a comma */
+M( <, [ ) /* Passes the arguments < and [ */
+M( (,), (...) ) /* Passes the arguments (,) and (...) */
+
+#define START_END(start, end) start c=3; end
+
+START_END( {a=1 , b=2;} ) /* braces are not parentheses */
+
+/*
+ * To pass a comma token as an argument it is
+ * necessary to write:
+ */
+#define COMMA ,
+
+M(a COMMA b, (a, b))
+
diff --git a/test/Preprocessor/stringize_space.c b/test/Preprocessor/stringize_space.c
new file mode 100644
index 000000000000..e41736c81683
--- /dev/null
+++ b/test/Preprocessor/stringize_space.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -E %s | grep -- '-"" , - "" , -"" , - ""'
+
+#define A(b) -#b , - #b , -# b , - # b
+A()
diff --git a/test/Preprocessor/stringize_space2.c b/test/Preprocessor/stringize_space2.c
new file mode 100644
index 000000000000..6a96894de6ee
--- /dev/null
+++ b/test/Preprocessor/stringize_space2.c
@@ -0,0 +1,6 @@
+/* RUN: clang-cc -E %s | grep 'a c'
+ */
+#define t(x) #x
+t(a
+c)
+
diff --git a/test/Preprocessor/undef-error.c b/test/Preprocessor/undef-error.c
new file mode 100644
index 000000000000..f818e59a6d1f
--- /dev/null
+++ b/test/Preprocessor/undef-error.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc %s -pedantic-errors -verify
+// PR2045
+
+#define b
+/* expected-error {{extra tokens at end of #undef directive}} */ #undef a b
diff --git a/test/Preprocessor/unterminated.c b/test/Preprocessor/unterminated.c
new file mode 100644
index 000000000000..2040aac17de2
--- /dev/null
+++ b/test/Preprocessor/unterminated.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -E -verify %s
+// PR3096
+#ifdef FOO // expected-error {{unterminated conditional directive}}
+/* /* */
+
diff --git a/test/Preprocessor/x86_target_features.c b/test/Preprocessor/x86_target_features.c
new file mode 100644
index 000000000000..90a717b81e8a
--- /dev/null
+++ b/test/Preprocessor/x86_target_features.c
@@ -0,0 +1,35 @@
+// FIXME: Use -triple, not -ccc-host-triple.
+
+// RUN: clang -ccc-host-triple i386-unknown-unknown -march=core2 -msse4 -x c -E -dM -o %t %s &&
+// RUN: grep '#define __SSE2_MATH__ 1' %t &&
+// RUN: grep '#define __SSE2__ 1' %t &&
+// RUN: grep '#define __SSE3__ 1' %t &&
+// RUN: grep '#define __SSE4_1__ 1' %t &&
+// RUN: grep '#define __SSE4_2__ 1' %t &&
+// RUN: grep '#define __SSE_MATH__ 1' %t &&
+// RUN: grep '#define __SSE__ 1' %t &&
+// RUN: grep '#define __SSSE3__ 1' %t &&
+
+// RUN: clang -ccc-host-triple i386-unknown-unknown -march=core2 -msse4 -mno-sse2 -x c -E -dM -o %t %s &&
+// RUN: grep '#define __SSE2_MATH__ 1' %t | count 0 &&
+// RUN: grep '#define __SSE2__ 1' %t | count 0 &&
+// RUN: grep '#define __SSE3__ 1' %t | count 0 &&
+// RUN: grep '#define __SSE4_1__ 1' %t | count 0 &&
+// RUN: grep '#define __SSE4_2__ 1' %t | count 0 &&
+// RUN: grep '#define __SSE_MATH__ 1' %t &&
+// RUN: grep '#define __SSE__ 1' %t &&
+// RUN: grep '#define __SSSE3__ 1' %t | count 0 &&
+
+// RUN: clang -ccc-host-triple i386-unknown-unknown -march=pentium-m -x c -E -dM -o %t %s &&
+// RUN: grep '#define __SSE2_MATH__ 1' %t &&
+// RUN: grep '#define __SSE2__ 1' %t &&
+// RUN: grep '#define __SSE3__ 1' %t | count 0 &&
+// RUN: grep '#define __SSE4_1__ 1' %t | count 0 &&
+// RUN: grep '#define __SSE4_2__ 1' %t | count 0 &&
+// RUN: grep '#define __SSE_MATH__ 1' %t &&
+// RUN: grep '#define __SSE__ 1' %t &&
+// RUN: grep '#define __SSSE3__ 1' %t | count 0 &&
+
+// RUN: true
+
+
diff --git a/test/Rewriter/block-test.c b/test/Rewriter/block-test.c
new file mode 100644
index 000000000000..9b24e6323d45
--- /dev/null
+++ b/test/Rewriter/block-test.c
@@ -0,0 +1,38 @@
+// RUN: clang-cc -rewrite-blocks %s -fblocks -o -
+
+static int (^block)(const void *, const void *) = (int (^)(const void *, const void *))0;
+static int (*func)(int (^block)(void *, void *)) = (int (*)(int (^block)(void *, void *)))0;
+
+typedef int (^block_T)(const void *, const void *);
+typedef int (*func_T)(int (^block)(void *, void *));
+
+void foo(const void *a, const void *b, void *c) {
+ int (^block)(const void *, const void *) = (int (^)(const void *, const void *))c;
+ int (*func)(int (^block)(void *, void *)) = (int (*)(int (^block)(void *, void *)))c;
+}
+
+typedef void (^test_block_t)();
+
+int main(int argc, char **argv) {
+ int a;
+
+ void (^test_block_v)();
+ void (^test_block_v2)(int, float);
+
+ void (^test_block_v3)(void (^barg)(int));
+
+ a = 77;
+ test_block_v = ^(){ int local=1; printf("a=%d\n",a+local); };
+ test_block_v();
+ a++;
+ test_block_v();
+
+ __block int b;
+
+ b = 88;
+ test_block_v2 = ^(int x, float f){ printf("b=%d\n",b); };
+ test_block_v2(1,2.0);
+ b++;
+ test_block_v2(3,4.0);
+ return 7;
+}
diff --git a/test/Rewriter/crash.m b/test/Rewriter/crash.m
new file mode 100644
index 000000000000..d4aba58c7b60
--- /dev/null
+++ b/test/Rewriter/crash.m
@@ -0,0 +1,25 @@
+// RUN: clang-cc -rewrite-objc -o - %s
+// rdar://5950938
+@interface NSArray {}
++ (id)arrayWithObjects:(id)firstObj, ...;
+@end
+
+@interface NSConstantString {}
+@end
+
+int main() {
+ id foo = [NSArray arrayWithObjects:@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"11", @"12", 0];
+ return 0;
+}
+
+// rdar://6291588
+@protocol A
+@end
+
+@interface Foo
+@end
+
+void func() {
+ id <A> obj = (id <A>)[Foo bar];
+}
+
diff --git a/test/Rewriter/finally.m b/test/Rewriter/finally.m
new file mode 100644
index 000000000000..bdc5a34fdf2d
--- /dev/null
+++ b/test/Rewriter/finally.m
@@ -0,0 +1,27 @@
+// RUN: clang-cc -rewrite-objc -verify %s -o -
+
+int main() {
+ @try {
+ printf("executing try"); // expected-warning{{implicitly declaring C library function 'printf' with type 'int (char const *, ...)'}} \
+ // expected-note{{please include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
+ return(0); // expected-warning{{rewriter doesn't support user-specified control flow semantics for @try/@finally (code may not execute properly)}}
+ } @finally {
+ printf("executing finally");
+ }
+ while (1) {
+ @try {
+ printf("executing try");
+ break; // expected-warning{{rewriter doesn't support user-specified control flow semantics for @try/@finally (code may not execute properly)}}
+ } @finally {
+ printf("executing finally");
+ }
+ printf("executing after finally block");
+ }
+ @try {
+ printf("executing try");
+ } @finally {
+ printf("executing finally");
+ }
+ return 0;
+}
+
diff --git a/test/Rewriter/id-test-3.m b/test/Rewriter/id-test-3.m
new file mode 100644
index 000000000000..ad1e76decf80
--- /dev/null
+++ b/test/Rewriter/id-test-3.m
@@ -0,0 +1,14 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@protocol P
+- (id<P>) Meth: (id<P>) Arg;
+@end
+
+@interface INTF<P>
+- (id<P>)IMeth;
+@end
+
+@implementation INTF
+- (id<P>)IMeth { return [(id<P>)self Meth: (id<P>)0]; }
+- (id<P>) Meth : (id<P>) Arg {}
+@end
diff --git a/test/Rewriter/ivar-encoding-1.m b/test/Rewriter/ivar-encoding-1.m
new file mode 100644
index 000000000000..759146175d44
--- /dev/null
+++ b/test/Rewriter/ivar-encoding-1.m
@@ -0,0 +1,15 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@interface Intf
+{
+ id ivar;
+ id ivar1[12];
+
+ id **ivar3;
+
+ id (*ivar4) (id, id);
+}
+@end
+
+@implementation Intf
+@end
diff --git a/test/Rewriter/ivar-encoding-2.m b/test/Rewriter/ivar-encoding-2.m
new file mode 100644
index 000000000000..86cc9b6a88f3
--- /dev/null
+++ b/test/Rewriter/ivar-encoding-2.m
@@ -0,0 +1,12 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@implementation Intf
+{
+ id ivar;
+ id ivar1[12];
+
+ id **ivar3;
+
+ id (*ivar4) (id, id);
+}
+@end
diff --git a/test/Rewriter/metadata-test-1.m b/test/Rewriter/metadata-test-1.m
new file mode 100644
index 000000000000..40eded121ece
--- /dev/null
+++ b/test/Rewriter/metadata-test-1.m
@@ -0,0 +1,12 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@interface Intf
+@end
+
+@implementation Intf(Category)
+- (void) CatMeth {}
+@end
+
+@implementation Another
+- (void) CatMeth {}
+@end
diff --git a/test/Rewriter/metadata-test-2.m b/test/Rewriter/metadata-test-2.m
new file mode 100644
index 000000000000..ab838f18bb93
--- /dev/null
+++ b/test/Rewriter/metadata-test-2.m
@@ -0,0 +1,15 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+typedef struct _NSPoint {
+ float x;
+ float y;
+} NSPoint;
+
+@interface Intf
+- (void) MyMeth : (NSPoint) Arg1;
+@end
+
+@implementation Intf
+- (void) MyMeth : (NSPoint) Arg1{}
+@end
+
diff --git a/test/Rewriter/method-encoding-1.m b/test/Rewriter/method-encoding-1.m
new file mode 100644
index 000000000000..25dccbf75084
--- /dev/null
+++ b/test/Rewriter/method-encoding-1.m
@@ -0,0 +1,18 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@protocol P1
+- (void) MyProtoMeth : (int **) arg1 : (void*) arg2;
++ (void) MyProtoMeth : (int **) arg1 : (void*) arg2;
+@end
+
+@interface Intf <P1>
+- (char *) MyMeth : (double) arg1 : (char *[12]) arg2;
+- (id) address:(void *)location with:(unsigned **)arg2;
+@end
+
+@implementation Intf
+- (char *) MyMeth : (double) arg1 : (char *[12]) arg2{}
+- (void) MyProtoMeth : (int **) arg1 : (void*) arg2 {}
++ (void) MyProtoMeth : (int **) arg1 : (void*) arg2 {}
+- (id) address:(void *)location with:(unsigned **)arg2{}
+@end
diff --git a/test/Rewriter/objc-encoding-bug-1.m b/test/Rewriter/objc-encoding-bug-1.m
new file mode 100644
index 000000000000..684a0d2ded09
--- /dev/null
+++ b/test/Rewriter/objc-encoding-bug-1.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+typedef struct NSMethodFrameArgInfo {
+ struct NSMethodFrameArgInfo *subInfo;
+ struct NSMethodFrameArgInfo *an;
+} NSMethodFrameArgInfo;
+
+@interface NSMethodSignature
+- (NSMethodFrameArgInfo *)_argInfo;
+@end
+
+@implementation NSMethodSignature
+
+- (NSMethodFrameArgInfo *)_argInfo{
+ return 0;
+}
+
+@end
+
diff --git a/test/Rewriter/objc-ivar-receiver-1.m b/test/Rewriter/objc-ivar-receiver-1.m
new file mode 100644
index 000000000000..c7ad05a1884d
--- /dev/null
+++ b/test/Rewriter/objc-ivar-receiver-1.m
@@ -0,0 +1,24 @@
+// RUN: clang-cc -rewrite-objc %s -o - &&
+// RUN: clang-cc -rewrite-objc %s -o - | grep 'newInv->_container'
+
+@interface NSMutableArray
+- (void)addObject:(id)addObject;
+@end
+
+@interface NSInvocation {
+@private
+ id _container;
+}
++ (NSInvocation *)invocationWithMethodSignature;
+
+@end
+
+@implementation NSInvocation
+
++ (NSInvocation *)invocationWithMethodSignature {
+ NSInvocation *newInv;
+ id obj = newInv->_container;
+ [newInv->_container addObject:0];
+ return 0;
+}
+@end
diff --git a/test/Rewriter/objc-string-concat-1.m b/test/Rewriter/objc-string-concat-1.m
new file mode 100644
index 000000000000..e8f8a88f2056
--- /dev/null
+++ b/test/Rewriter/objc-string-concat-1.m
@@ -0,0 +1,14 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@class NSString;
+
+@interface NSConstantString;
+@end
+
+
+
+NSConstantString *t0 = @"123";
+NSConstantString *t = @"123" @"4567"; // concat
+NSConstantString *t1 = @"123" @"4567" /* COMMENT */ @"89"; // concat
+NSConstantString *t2 = @"123" @/* COMMENT */ "4567"; // concat
+
diff --git a/test/Rewriter/objc-super-test.m b/test/Rewriter/objc-super-test.m
new file mode 100644
index 000000000000..500933d835da
--- /dev/null
+++ b/test/Rewriter/objc-super-test.m
@@ -0,0 +1,18 @@
+// RUN: clang-cc -rewrite-objc %s -o - | grep objc_msgSendSuper | grep MainMethod
+
+typedef struct objc_selector *SEL;
+typedef struct objc_object *id;
+
+@interface SUPER
+- (int) MainMethod;
+@end
+
+@interface MyDerived : SUPER
+- (int) instanceMethod;
+@end
+
+@implementation MyDerived
+- (int) instanceMethod {
+ return [super MainMethod];
+}
+@end
diff --git a/test/Rewriter/objc-synchronized-1.m b/test/Rewriter/objc-synchronized-1.m
new file mode 100644
index 000000000000..e3c41165db22
--- /dev/null
+++ b/test/Rewriter/objc-synchronized-1.m
@@ -0,0 +1,20 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+id SYNCH_EXPR();
+void SYNCH_BODY();
+void SYNCH_BEFORE();
+void SYNC_AFTER();
+
+void foo(id sem)
+{
+ SYNCH_BEFORE();
+ @synchronized (SYNCH_EXPR()) {
+ SYNCH_BODY();
+ return;
+ }
+ SYNC_AFTER();
+ @synchronized ([sem self]) {
+ SYNCH_BODY();
+ return;
+ }
+}
diff --git a/test/Rewriter/properties.m b/test/Rewriter/properties.m
new file mode 100644
index 000000000000..ac8ee9ff8c97
--- /dev/null
+++ b/test/Rewriter/properties.m
@@ -0,0 +1,54 @@
+// RUN: clang-cc -rewrite-objc %s -o -
+
+@interface Foo {
+ int i;
+ int rrrr;
+ Foo *o;
+}
+@property int i;
+@property(readonly) int rrrr;
+@property int d;
+@property(retain) Foo *o;
+
+- (void)foo;
+@end
+
+@implementation Foo
+@synthesize i;
+@synthesize rrrr;
+@synthesize o;
+
+@dynamic d;
+
+- (void)foo {
+ i = 99;
+}
+
+- (int)bar {
+ return i;
+}
+@end
+
+@interface Bar {
+}
+@end
+
+@implementation Bar
+
+static int func(int i);
+
+- (void)baz {
+ Foo *obj1, *obj2;
+ int i;
+ if (obj1.i == obj2.rrrr)
+ obj1.i = 33;
+ obj1.i = func(obj2.rrrr);
+ obj1.i = obj2.rrrr;
+ obj1.i = (obj2.rrrr);
+ [obj1 setI:[obj2 rrrr]];
+ obj1.i = [obj2 rrrr];
+ obj1.i = 3 + [obj2 rrrr];
+ i = obj1.o.i;
+ obj1.o.i = 77;
+}
+@end
diff --git a/test/Rewriter/protocol-rewrite-1.m b/test/Rewriter/protocol-rewrite-1.m
new file mode 100644
index 000000000000..263a97d85d28
--- /dev/null
+++ b/test/Rewriter/protocol-rewrite-1.m
@@ -0,0 +1,48 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+typedef struct MyWidget {
+ int a;
+} MyWidget;
+
+MyWidget gWidget = { 17 };
+
+@protocol MyProto
+- (MyWidget *)widget;
+@end
+
+@interface Foo
+@end
+
+@interface Bar: Foo <MyProto>
+@end
+
+@interface Container
++ (MyWidget *)elementForView:(Foo *)view;
+@end
+
+@implementation Foo
+@end
+
+@implementation Bar
+- (MyWidget *)widget {
+ return &gWidget;
+}
+@end
+
+@implementation Container
++ (MyWidget *)elementForView:(Foo *)view
+{
+ MyWidget *widget = (void*)0;
+ if (@protocol(MyProto)) {
+ widget = [(id <MyProto>)view widget];
+ }
+ return widget;
+}
+@end
+
+int main(void) {
+ id view;
+ MyWidget *w = [Container elementForView: view];
+
+ return 0;
+}
diff --git a/test/Rewriter/rewrite-api-bug.m b/test/Rewriter/rewrite-api-bug.m
new file mode 100644
index 000000000000..ba0511b64650
--- /dev/null
+++ b/test/Rewriter/rewrite-api-bug.m
@@ -0,0 +1,11 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@interface MyDerived
+- (void) instanceMethod;
+@end
+
+@implementation MyDerived
+- (void) instanceMethod {
+}
+@end
+
diff --git a/test/Rewriter/rewrite-foreach-1.m b/test/Rewriter/rewrite-foreach-1.m
new file mode 100644
index 000000000000..eef33f88c9ca
--- /dev/null
+++ b/test/Rewriter/rewrite-foreach-1.m
@@ -0,0 +1,37 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@protocol P @end
+
+@interface MyList
+@end
+
+@implementation MyList
+- (unsigned int)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state objects: (id *)items count:(unsigned int)stackcount
+{
+ return 0;
+}
+@end
+
+@interface MyList (BasicTest)
+- (void)compilerTestAgainst;
+@end
+
+int LOOP();
+@implementation MyList (BasicTest)
+- (void)compilerTestAgainst {
+ id el;
+ for (el in self)
+ { LOOP(); }
+ for (id el1 in self)
+ LOOP();
+
+ for (el in (self))
+ if (el)
+ LOOP();
+
+ for (el in ((self)))
+ if (el)
+ LOOP();
+}
+@end
+
diff --git a/test/Rewriter/rewrite-foreach-2.m b/test/Rewriter/rewrite-foreach-2.m
new file mode 100644
index 000000000000..12f0e834df42
--- /dev/null
+++ b/test/Rewriter/rewrite-foreach-2.m
@@ -0,0 +1,34 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@protocol P @end
+
+@interface MyList
+@end
+
+@implementation MyList
+- (unsigned int)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state objects: (id *)items count:(unsigned int)stackcount
+{
+ return 0;
+}
+@end
+
+@interface MyList (BasicTest)
+- (void)compilerTestAgainst;
+@end
+
+int LOOP();
+int INNERLOOP();
+void END_LOOP();
+@implementation MyList (BasicTest)
+- (void)compilerTestAgainst {
+ id el;
+ for (el in self)
+ { LOOP();
+ for (id el1 in self)
+ INNER_LOOP();
+
+ END_LOOP();
+ }
+}
+@end
+
diff --git a/test/Rewriter/rewrite-foreach-3.m b/test/Rewriter/rewrite-foreach-3.m
new file mode 100644
index 000000000000..3aa0d95b44bb
--- /dev/null
+++ b/test/Rewriter/rewrite-foreach-3.m
@@ -0,0 +1,29 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@protocol P @end
+
+@interface MyList
+@end
+
+@implementation MyList
+- (unsigned int)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state objects: (id *)items count:(unsigned int)stackcount
+{
+ return 0;
+}
+@end
+
+@interface MyList (BasicTest)
+- (void)compilerTestAgainst;
+@end
+
+int LOOP();
+@implementation MyList (BasicTest)
+- (void)compilerTestAgainst {
+ MyList * el;
+ for (el in self)
+ { LOOP(); }
+ for (MyList * el1 in self)
+ LOOP();
+}
+@end
+
diff --git a/test/Rewriter/rewrite-foreach-4.m b/test/Rewriter/rewrite-foreach-4.m
new file mode 100644
index 000000000000..774f9a0b75c8
--- /dev/null
+++ b/test/Rewriter/rewrite-foreach-4.m
@@ -0,0 +1,32 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@interface MyList
+- (id) allKeys;
+@end
+
+@implementation MyList
+- (unsigned int)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state objects: (id *)items count:(unsigned int)stackcount
+{
+ return 0;
+}
+- (id) allKeys {}
+@end
+
+@interface MyList (BasicTest)
+- (void)compilerTestAgainst;
+@end
+
+int LOOP();
+@implementation MyList (BasicTest)
+- (void)compilerTestAgainst {
+ MyList * el;
+ for (el in [el allKeys]) { LOOP();
+ }
+
+ for (id el1 in[el allKeys]) { LOOP();
+ }
+ for (el in([el allKeys])) { LOOP();
+ }
+}
+@end
+
diff --git a/test/Rewriter/rewrite-foreach-5.m b/test/Rewriter/rewrite-foreach-5.m
new file mode 100644
index 000000000000..d0d12444a3e7
--- /dev/null
+++ b/test/Rewriter/rewrite-foreach-5.m
@@ -0,0 +1,47 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@interface MyList
+- (id) allKeys;
+@end
+
+@implementation MyList
+- (unsigned int)countByEnumeratingWithState: (struct __objcFastEnumerationState *)state objects: (id *)items count:(unsigned int)stackcount
+{
+ return 0;
+}
+- (id) allKeys {}
+@end
+
+@interface MyList (BasicTest)
+- (void)compilerTestAgainst;
+@end
+
+int LOOP();
+@implementation MyList (BasicTest)
+- (void)compilerTestAgainst {
+ MyList * el;
+ int i;
+ for (el in [el allKeys]) {
+ for (i = 0; i < 10; i++)
+ if (i == 5)
+ break;
+
+ if (el == 0)
+ break;
+ if (el != self)
+ continue;
+ LOOP();
+ }
+
+ for (id el1 in[el allKeys]) {
+ LOOP();
+ for (el in self) {
+ if (el)
+ continue;
+ }
+ if (el1)
+ break;
+ }
+}
+@end
+
diff --git a/test/Rewriter/rewrite-foreach-6.m b/test/Rewriter/rewrite-foreach-6.m
new file mode 100644
index 000000000000..c6043bb98eb4
--- /dev/null
+++ b/test/Rewriter/rewrite-foreach-6.m
@@ -0,0 +1,13 @@
+// RUN: clang-cc %s -rewrite-objc -o=-
+// rdar://5716356
+// FIXME: Should be able to pipe into clang, but code is not
+// yet correct for other reasons: rdar://5716940
+
+@class NSNotification;
+@class NSMutableArray;
+
+void foo(NSMutableArray *notificationArray, id X) {
+ for (NSNotification *notification in notificationArray)
+ [X postNotification:notification];
+}
+
diff --git a/test/Rewriter/rewrite-nest.m b/test/Rewriter/rewrite-nest.m
new file mode 100644
index 000000000000..7a1690a3630b
--- /dev/null
+++ b/test/Rewriter/rewrite-nest.m
@@ -0,0 +1,27 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@interface NSMapTable @end
+@interface NSEnumerator @end
+
+typedef unsigned int NSUInteger;
+
+@interface NSConcreteMapTable : NSMapTable {
+@public
+ NSUInteger capacity;
+}
+@end
+
+@interface NSConcreteMapTableValueEnumerator : NSEnumerator {
+ NSConcreteMapTable *mapTable;
+}
+@end
+
+@implementation NSConcreteMapTableValueEnumerator
+
+- nextObject {
+ while (mapTable->capacity) {
+ }
+ return 0;
+}
+@end
+
diff --git a/test/Rewriter/rewrite-protocol-type-1.m b/test/Rewriter/rewrite-protocol-type-1.m
new file mode 100644
index 000000000000..48dc02971ca9
--- /dev/null
+++ b/test/Rewriter/rewrite-protocol-type-1.m
@@ -0,0 +1,24 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@protocol MyProto1
+@end
+
+@protocol MyProto2
+@end
+
+@interface INTF @end
+
+INTF <MyProto1> *g1;
+
+INTF <MyProto1, MyProto2> *g2, *g3;
+
+INTF <MyProto1> * Func(INTF <MyProto1> *p2, INTF<MyProto1> *p3, INTF *p4, INTF<MyProto1> *p5)
+{
+ return p2;
+}
+
+INTF <MyProto1, MyProto2> * Func1(INTF *p2, INTF<MyProto1, MyProto2> *p3, INTF *p4, INTF<MyProto1> *p5)
+{
+ return p3;
+}
+
diff --git a/test/Rewriter/rewrite-try-catch.m b/test/Rewriter/rewrite-try-catch.m
new file mode 100644
index 000000000000..8c6d08f2e01d
--- /dev/null
+++ b/test/Rewriter/rewrite-try-catch.m
@@ -0,0 +1,27 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@interface Foo @end
+@interface GARF @end
+
+void foo() {
+ @try { TRY(); }
+ @catch (...) { SPLATCH(); @throw; }
+}
+
+int main()
+{
+
+ @try {
+ MYTRY();
+ }
+
+ @catch (Foo* localException) {
+ MYCATCH();
+ @throw;
+ }
+
+ // no catch clause
+ @try { }
+ @finally { }
+}
+
diff --git a/test/Rewriter/static-type-protocol-1.m b/test/Rewriter/static-type-protocol-1.m
new file mode 100644
index 000000000000..0985a9d77554
--- /dev/null
+++ b/test/Rewriter/static-type-protocol-1.m
@@ -0,0 +1,27 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@protocol Proto
+- (void) ProtoDidget;
+@end
+
+@protocol MyProto <Proto>
+- (void) widget;
+@end
+
+@interface Foo
+- (void)StillMode;
+@end
+
+@interface Container
++ (void)MyMeth;
+@end
+
+@implementation Container
++ (void)MyMeth
+{
+ Foo *view;
+ [(Foo <MyProto> *)view StillMode];
+ [(Foo <MyProto> *)view widget];
+ [(Foo <MyProto> *)view ProtoDidget];
+}
+@end
diff --git a/test/Rewriter/undecl-objc-h.m b/test/Rewriter/undecl-objc-h.m
new file mode 100644
index 000000000000..b09765163ec0
--- /dev/null
+++ b/test/Rewriter/undecl-objc-h.m
@@ -0,0 +1,29 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+typedef struct S {
+ int * pint;
+ int size;
+}NSRec;
+
+@interface SUPER
+- (NSRec) MainMethod : (NSRec) Arg1 : (NSRec) Arg2;
+@end
+
+@interface MyDerived : SUPER
+{
+ NSRec d;
+}
+- (int) instanceMethod;
+- (int) another : (int) arg;
+- (NSRec) MainMethod : (NSRec) Arg1 : (NSRec) Arg2;
+@end
+
+@implementation MyDerived
+- (int) instanceMethod {
+ return [self another : [self MainMethod : d : d].size];
+}
+
+- (int) another : (int) arg { return arg; }
+- (NSRec) MainMethod : (NSRec) Arg1 : (NSRec) Arg2 { return Arg2; }
+@end
+
diff --git a/test/Rewriter/undeclared-method-1.m b/test/Rewriter/undeclared-method-1.m
new file mode 100644
index 000000000000..795fd61b4afa
--- /dev/null
+++ b/test/Rewriter/undeclared-method-1.m
@@ -0,0 +1,9 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@interface Derived @end
+
+int main(void) {
+ Derived *v ;
+ [v free];
+ return 0;
+}
diff --git a/test/Rewriter/undef-field-reference-1.m b/test/Rewriter/undef-field-reference-1.m
new file mode 100644
index 000000000000..43bc2ad8bfa5
--- /dev/null
+++ b/test/Rewriter/undef-field-reference-1.m
@@ -0,0 +1,15 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+@interface MyDerived
+{
+@public
+ int IVAR;
+}
+@end
+
+MyDerived *pd;
+int main() {
+ return pd->IVAR;
+}
+
+
diff --git a/test/Rewriter/va-method.m b/test/Rewriter/va-method.m
new file mode 100644
index 000000000000..3bee599435e7
--- /dev/null
+++ b/test/Rewriter/va-method.m
@@ -0,0 +1,17 @@
+// RUN: clang-cc -rewrite-objc %s -o=-
+
+#include <stdarg.h>
+
+@interface NSObject @end
+@interface XX : NSObject @end
+
+@implementation XX
+- (void)encodeValuesOfObjCTypes:(const char *)types, ... {
+ va_list ap;
+ va_start(ap, types);
+ while (*types) ;
+ va_end(ap);
+}
+
+@end
+
diff --git a/test/Sema/128bitint.c b/test/Sema/128bitint.c
new file mode 100644
index 000000000000..2a18d904f8f2
--- /dev/null
+++ b/test/Sema/128bitint.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+typedef int i128 __attribute__((__mode__(TI)));
+typedef unsigned u128 __attribute__((__mode__(TI)));
+
+int a[((i128)-1 ^ (i128)-2) == 1 ? 1 : -1];
+int a[(u128)-1 > 1LL ? 1 : -1];
diff --git a/test/Sema/PR2727.c b/test/Sema/PR2727.c
new file mode 100644
index 000000000000..52d8392ee9e5
--- /dev/null
+++ b/test/Sema/PR2727.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -verify -fsyntax-only -std=c90 %s &&
+// RUN: clang-cc -verify -fsyntax-only -std=c99 %s
+
+int f (int x)
+{
+ // sizeof applied to a type should not delete the type.
+ return sizeof (int[x]);
+}
diff --git a/test/Sema/PR2728.c b/test/Sema/PR2728.c
new file mode 100644
index 000000000000..26c96fe625be
--- /dev/null
+++ b/test/Sema/PR2728.c
@@ -0,0 +1,9 @@
+// RUN: clang-cc -verify -fsyntax-only -std=c90 %s &&
+// RUN: clang-cc -verify -fsyntax-only -std=c99 %s
+
+struct s
+{
+ int a;
+};
+
+int a[__builtin_offsetof(struct s, a) == 0];
diff --git a/test/Sema/PR2919-builtin-types-compat-strips-crv.c b/test/Sema/PR2919-builtin-types-compat-strips-crv.c
new file mode 100644
index 000000000000..160ec4a38058
--- /dev/null
+++ b/test/Sema/PR2919-builtin-types-compat-strips-crv.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only %s
+
+typedef struct foo T0;
+typedef const struct foo T1;
+
+int a0[__builtin_types_compatible_p(T0,
+ const T1) ? 1 : -1];
diff --git a/test/Sema/PR2923.c b/test/Sema/PR2923.c
new file mode 100644
index 000000000000..c75e7baed1a1
--- /dev/null
+++ b/test/Sema/PR2923.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Test for absence of crash reported in PR 2923:
+//
+// http://llvm.org/bugs/show_bug.cgi?id=2923
+//
+// Previously we had a crash when deallocating the FunctionDecl for 'bar'
+// because FunctionDecl::getNumParams() just used the type of foo to determine
+// the number of parameters it has. In the case of 'bar' there are no
+// ParmVarDecls.
+int foo(int x, int y) { return x + y; }
+extern typeof(foo) bar;
diff --git a/test/Sema/PR2963-enum-constant.c b/test/Sema/PR2963-enum-constant.c
new file mode 100644
index 000000000000..78f2326dae1b
--- /dev/null
+++ b/test/Sema/PR2963-enum-constant.c
@@ -0,0 +1,17 @@
+// RUN: clang-cc %s -verify -pedantic -fsyntax-only
+
+typedef short short_fixed;
+
+enum
+{
+ // 8.8 short_fixed
+ SHORT_FIXED_FRACTIONAL_BITS= 8,
+ SHORT_FIXED_ONE= 1<<SHORT_FIXED_FRACTIONAL_BITS
+};
+
+#define FLOAT_TO_SHORT_FIXED(f) ((short_fixed)((f)*SHORT_FIXED_ONE))
+
+enum
+{
+ SOME_VALUE= FLOAT_TO_SHORT_FIXED(0.1) // expected-warning{{expression is not integer constant expression}}
+};
diff --git a/test/Sema/address-constant.c b/test/Sema/address-constant.c
new file mode 100644
index 000000000000..69f2f79f6857
--- /dev/null
+++ b/test/Sema/address-constant.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int i;
+int a[] = {0};
+struct { int i; } s;
+
+int *array[] = {&i, a, &s.i};
+
+extern void f(void);
+void (*f_addr)(void) = &f;
diff --git a/test/Sema/address_spaces.c b/test/Sema/address_spaces.c
new file mode 100644
index 000000000000..b79799f0230c
--- /dev/null
+++ b/test/Sema/address_spaces.c
@@ -0,0 +1,32 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+#define _AS1 __attribute__((address_space(1)))
+#define _AS2 __attribute__((address_space(2)))
+#define _AS3 __attribute__((address_space(3)))
+
+void foo(_AS3 float *a) {
+ _AS2 *x;// expected-warning {{type specifier missing, defaults to 'int'}}
+ _AS1 float * _AS2 *B;
+
+ int _AS1 _AS2 *Y; // expected-error {{multiple address spaces specified for type}}
+ int *_AS1 _AS2 *Z; // expected-error {{multiple address spaces specified for type}}
+
+ _AS1 int local; // expected-error {{automatic variable qualified with an address space}}
+ _AS1 int array[5]; // expected-error {{automatic variable qualified with an address space}}
+ _AS1 int arrarr[5][5]; // expected-error {{automatic variable qualified with an address space}}
+
+ *a = 5.0f;
+}
+
+struct _st {
+ int x, y;
+} s __attribute ((address_space(1))) = {1, 1};
+
+
+// rdar://6774906
+__attribute__((address_space(256))) void * * const base = 0;
+void * get_0(void) {
+ return base[0]; // expected-error {{illegal implicit cast between two pointers with different address spaces}} \
+ expected-warning {{returning 'void __attribute__((address_space(256)))*' discards qualifiers, expected 'void *'}}
+}
+
diff --git a/test/Sema/align-x86.c b/test/Sema/align-x86.c
new file mode 100644
index 000000000000..2bc1cc848554
--- /dev/null
+++ b/test/Sema/align-x86.c
@@ -0,0 +1,14 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -fsyntax-only -verify %s
+
+// PR3433
+double g1;
+short chk1[__alignof__(g1) == 8 ? 1 : -1];
+short chk2[__alignof__(double) == 8 ? 1 : -1];
+
+long long g2;
+short chk1[__alignof__(g2) == 8 ? 1 : -1];
+short chk2[__alignof__(long long) == 8 ? 1 : -1];
+
+_Complex double g3;
+short chk1[__alignof__(g3) == 8 ? 1 : -1];
+short chk2[__alignof__(_Complex double) == 8 ? 1 : -1];
diff --git a/test/Sema/annotate.c b/test/Sema/annotate.c
new file mode 100644
index 000000000000..aec2af8b022f
--- /dev/null
+++ b/test/Sema/annotate.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+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 requires 1 argument(s)}}
+}
diff --git a/test/Sema/anonymous-struct-union.c b/test/Sema/anonymous-struct-union.c
new file mode 100644
index 000000000000..ca1133bd8ace
--- /dev/null
+++ b/test/Sema/anonymous-struct-union.c
@@ -0,0 +1,98 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct X {
+ union {
+ float f3;
+ double d2;
+ } named;
+
+ union {
+ int i;
+ float f;
+
+ union {
+ float f2;
+ double d;
+ };
+ };
+
+ struct {
+ int a;
+ float b;
+ };
+};
+
+void test_unqual_references(struct X x, const struct X xc) {
+ x.i = 0;
+ x.f = 0.0;
+ x.f2 = x.f;
+ x.d = x.f;
+ x.f3 = 0; // expected-error{{no member named 'f3'}}
+ x.a = 0;
+
+ xc.d = 0.0; // expected-error{{read-only variable is not assignable}}
+ xc.f = 0; // expected-error{{read-only variable is not assignable}}
+ xc.a = 0; // expected-error{{read-only variable is not assignable}}
+}
+
+
+struct Redecl {
+ int x; // expected-note{{previous declaration is here}}
+ struct y { };
+
+ union {
+ int x; // expected-error{{member of anonymous union redeclares 'x'}}
+ float y;
+ double z; // expected-note{{previous declaration is here}}
+ double zz; // expected-note{{previous declaration is here}}
+ };
+
+ int z; // expected-error{{duplicate member 'z'}}
+ void zz(); // expected-error{{duplicate member 'zz'}}
+};
+
+union { // expected-error{{declaration does not declare anything}}
+ int int_val;
+ float float_val;
+};
+
+static union { // expected-error{{declaration does not declare anything}}
+ int int_val2;
+ float float_val2;
+};
+
+void f() {
+ int_val2 = 0; // expected-error{{use of undeclared identifier}}
+ float_val2 = 0.0; // expected-error{{use of undeclared identifier}}
+}
+
+void g() {
+ union { // expected-error{{declaration does not declare anything}}
+ int i;
+ float f2;
+ };
+ i = 0; // expected-error{{use of undeclared identifier}}
+ f2 = 0.0; // expected-error{{use of undeclared identifier}}
+}
+
+// <rdar://problem/6483159>
+struct s0 { union { int f0; }; };
+
+// <rdar://problem/6481130>
+typedef struct { }; // expected-error{{declaration does not declare anything}}
+
+// PR3675
+struct s1 {
+ int f0; // expected-note{{previous declaration is here}}
+ union {
+ int f0; // expected-error{{member of anonymous union redeclares 'f0'}}
+ };
+};
+
+// PR3680
+struct {}; // expected-error{{declaration does not declare anything}}
+
+struct s2 {
+ union {
+ int a;
+ }
+}; // expected-error{{expected member name or ';' after declaration specifiers}}
diff --git a/test/Sema/arg-duplicate.c b/test/Sema/arg-duplicate.c
new file mode 100644
index 000000000000..e40a964234d9
--- /dev/null
+++ b/test/Sema/arg-duplicate.c
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int f3(y, x,
+ x) // expected-error {{redefinition of parameter}}
+ int y, x,
+ x; // expected-error {{redefinition of parameter}}
+{
+ return x + y;
+}
+
+void f4(void) {
+ f3 (1, 1, 2, 3, 4); // expected-warning{{too many arguments}}
+}
+
diff --git a/test/Sema/arg-scope-c99.c b/test/Sema/arg-scope-c99.c
new file mode 100644
index 000000000000..b5b1c8a812c1
--- /dev/null
+++ b/test/Sema/arg-scope-c99.c
@@ -0,0 +1,2 @@
+// RUN: clang-cc -fsyntax-only -std=c99 -verify %s
+int bb(int sz, int ar[sz][sz]) { }
diff --git a/test/Sema/arg-scope.c b/test/Sema/arg-scope.c
new file mode 100644
index 000000000000..c1cc7e112f88
--- /dev/null
+++ b/test/Sema/arg-scope.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+int aa(int b, int x[sizeof b]) {}
+
+void foo(int i, int A[i]) {}
+
diff --git a/test/Sema/array-constraint.c b/test/Sema/array-constraint.c
new file mode 100644
index 000000000000..5a09e20ecbff
--- /dev/null
+++ b/test/Sema/array-constraint.c
@@ -0,0 +1,52 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+
+struct s; // expected-note 2 {{forward declaration of 'struct s'}}
+struct s* t (struct s z[]) { // expected-error {{array has incomplete element type}}
+ return z;
+}
+
+void ff() {
+ struct s v, *p; // expected-error {{variable has incomplete type 'struct s'}}
+
+ p = &v;
+}
+
+void *k (void l[2]) { // expected-error {{array has incomplete element type}}
+ return l;
+}
+
+struct vari {
+ int a;
+ int b[];
+};
+
+struct vari *func(struct vari a[]) { // expected-warning {{'struct vari' may not be used as an array element due to flexible array member}}
+ return a;
+}
+
+int foo[](void); // expected-error {{'foo' declared as array of functions}}
+int foo2[1](void); // expected-error {{'foo2' declared as array of functions}}
+
+typedef int (*pfunc)(void);
+
+pfunc xx(int f[](void)) { // expected-error {{'f' declared as array of functions}}
+ return f;
+}
+
+void check_size() {
+ float f;
+ int size_not_int[f]; // expected-error {{size of array has non-integer type 'float'}}
+ int negative_size[1-2]; // expected-error{{array size is negative}}
+ int zero_size[0]; // expected-warning{{zero size arrays are an extension}}
+}
+
+static int I;
+typedef int TA[I]; // expected-error {{variable length array declaration not allowed at file scope}}
+
+void strFunc(char *);
+const char staticAry[] = "test";
+int checkStaticAry() {
+ strFunc(staticAry); // expected-warning{{passing 'char const [5]' discards qualifiers, expected 'char *'}}
+}
+
+
diff --git a/test/Sema/array-declared-as-incorrect-type.c b/test/Sema/array-declared-as-incorrect-type.c
new file mode 100644
index 000000000000..3f6fa33a3bd2
--- /dev/null
+++ b/test/Sema/array-declared-as-incorrect-type.c
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+
+extern int a1[];
+int a1[1];
+
+extern int a2[]; // expected-note {{previous definition is here}}
+float a2[1]; // expected-error {{redefinition of 'a2'}}
+
+extern int a3[][2];
+int a3[1][2];
+
+extern int a4[][2]; // expected-note {{previous definition is here}}
+int a4[2]; // expected-error {{redefinition of 'a4'}}
+
+extern int a5[1][2][3]; // expected-note {{previous definition is here}}
+int a5[3][2][1]; // expected-error {{redefinition of 'a5'}}
diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c
new file mode 100644
index 000000000000..50148a83ae13
--- /dev/null
+++ b/test/Sema/array-init.c
@@ -0,0 +1,265 @@
+// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+
+extern int foof() = 1; // expected-error{{illegal initializer (only variables can be initialized)}}
+
+static int x, y, z;
+
+static int ary[] = { x, y, z }; // expected-error{{initializer element is not a compile-time constant}}
+int ary2[] = { x, y, z }; // expected-error{{initializer element is not a compile-time constant}}
+
+extern int fileScopeExtern[3] = { 1, 3, 5 }; // expected-warning{{'extern' variable has an initializer}}
+
+static long ary3[] = { 1, "abc", 3, 4 }; // expected-warning{{incompatible pointer to integer conversion initializing 'char [4]', expected 'long'}}
+
+void func() {
+ int x = 1;
+
+ typedef int TInt = 1; // expected-error{{illegal initializer (only variables can be initialized)}}
+
+ int xComputeSize[] = { 1, 3, 5 };
+
+ int x3[x] = { 1, 2 }; // expected-error{{variable-sized object may not be initialized}}
+
+ int x4 = { 1, 2 }; // expected-warning{{excess elements in scalar initializer}}
+
+ int y[4][3] = {
+ { 1, 3, 5 },
+ { 2, 4, 6 },
+ { 3, 5, 7 },
+ };
+
+ int y2[4][3] = {
+ 1, 3, 5, 2, 4, 6, 3, 5, 7
+ };
+
+ int y3[4][3] = {
+ { 1, 3, 5 },
+ { 2, 4, 6 },
+ { 3, 5, 7 },
+ { 4, 6, 8 },
+ { 5 }, // expected-warning{{excess elements in array initializer}}
+ };
+
+ struct threeElements {
+ int a,b,c;
+ } z = { 1 };
+
+ struct threeElements *p = 7; // expected-warning{{incompatible integer to pointer conversion initializing 'int', expected 'struct threeElements *'}}
+
+ extern int blockScopeExtern[3] = { 1, 3, 5 }; // expected-error{{'extern' variable cannot have an initializer}}
+
+ static long x2[3] = { 1.0, "abc" , 5.8 }; // expected-warning{{incompatible pointer to integer conversion initializing 'char [4]', expected 'long'}}
+}
+
+void test() {
+ int y1[3] = {
+ { 1, 2, 3 } // expected-warning{{braces around scalar initializer}} expected-warning{{excess elements in scalar initializer}}
+ };
+ int y3[4][3] = {
+ { 1, 3, 5 },
+ { 2, 4, 6 },
+ { 3, 5, 7 },
+ { 4, 6, 8 },
+ { }, // expected-warning{{use of GNU empty initializer extension}} expected-warning{{excess elements in array initializer}}
+ };
+ int y4[4][3] = {
+ { 1, 3, 5, 2 }, // expected-warning{{excess elements in array initializer}}
+ { 4, 6 },
+ { 3, 5, 7 },
+ { 4, 6, 8 },
+ };
+}
+
+void allLegalAndSynonymous() {
+ short q[4][3][2] = {
+ { 1 },
+ { 2, 3 },
+ { 4, 5, 6 }
+ };
+ short q2[4][3][2] = {
+ { 1, 0, 0, 0, 0, 0 },
+ { 2, 3, 0, 0, 0, 0 },
+ { 4, 5, 6 }
+ };
+ short q3[4][3][2] = {
+ {
+ { 1 },
+ },
+ {
+ { 2, 3 },
+ },
+ {
+ { 4, 5 },
+ { 6 },
+ },
+ };
+}
+
+void legal() {
+ short q[][3][2] = {
+ { 1 },
+ { 2, 3 },
+ { 4, 5, 6 }
+ };
+ int q_sizecheck[(sizeof(q) / sizeof(short [3][2])) == 3? 1 : -1];
+}
+
+unsigned char asso_values[] = { 34 };
+int legal2() {
+ return asso_values[0];
+}
+
+void illegal() {
+ short q2[4][][2] = { // expected-error{{array has incomplete element type 'short [][2]'}}
+ { 1, 0, 0, 0, 0, 0 },
+ { 2, 3, 0, 0, 0, 0 },
+ { 4, 5, 6 }
+ };
+ short q3[4][3][] = { // expected-error{{array has incomplete element type 'short []'}}
+ {
+ { 1 },
+ },
+ {
+ { 2, 3 },
+ },
+ {
+ { 4, 5 },
+ { 6 },
+ },
+ };
+ int a[][] = { 1, 2 }; // expected-error{{array has incomplete element type 'int []'}}
+}
+
+typedef int AryT[];
+
+void testTypedef()
+{
+ AryT a = { 1, 2 }, b = { 3, 4, 5 };
+ int a_sizecheck[(sizeof(a) / sizeof(int)) == 2? 1 : -1];
+ int b_sizecheck[(sizeof(b) / sizeof(int)) == 3? 1 : -1];
+}
+
+static char const xx[] = "test";
+int xx_sizecheck[(sizeof(xx) / sizeof(char)) == 5? 1 : -1];
+static char const yy[5] = "test";
+static char const zz[3] = "test"; // expected-warning{{initializer-string for char array is too long}}
+
+void charArrays()
+{
+ static char const test[] = "test";
+ int test_sizecheck[(sizeof(test) / sizeof(char)) == 5? 1 : -1];
+ static char const test2[] = { "weird stuff" };
+ static char const test3[] = { "test", "excess stuff" }; // expected-warning{{excess elements in char array initializer}}
+
+ char* cp[] = { "Hello" };
+
+ char c[] = { "Hello" };
+ int l[sizeof(c) == 6 ? 1 : -1];
+
+ int i[] = { "Hello "}; // expected-warning{{incompatible pointer to integer conversion initializing 'char [7]', expected 'int'}}
+ char c2[] = { "Hello", "Good bye" }; //expected-warning{{excess elements in char array initializer}}
+
+ int i2[1] = { "Hello" }; //expected-warning{{incompatible pointer to integer conversion initializing 'char [6]', expected 'int'}}
+ char c3[5] = { "Hello" };
+ char c4[4] = { "Hello" }; //expected-warning{{initializer-string for char array is too long}}
+
+ int i3[] = {}; //expected-warning{{zero size arrays are an extension}} expected-warning{{use of GNU empty initializer extension}}
+}
+
+void variableArrayInit() {
+ int a = 4;
+ char strlit[a] = "foo"; //expected-error{{variable-sized object may not be initialized}}
+ int b[a] = { 1, 2, 4 }; //expected-error{{variable-sized object may not be initialized}}
+}
+
+// Pure array tests
+float r1[10] = {{7}}; //expected-warning{{braces around scalar initializer}}
+float r2[] = {{8}}; //expected-warning{{braces around scalar initializer}}
+char r3[][5] = {1,2,3,4,5,6};
+int r3_sizecheck[(sizeof(r3) / sizeof(char[5])) == 2? 1 : -1];
+char r3_2[sizeof r3 == 10 ? 1 : -1];
+float r4[1][2] = {1,{2},3,4}; //expected-warning{{braces around scalar initializer}} expected-warning{{excess elements in array initializer}}
+char r5[][5] = {"aa", "bbb", "ccccc"};
+char r6[sizeof r5 == 15 ? 1 : -1];
+const char r7[] = "zxcv";
+char r8[5] = "5char";
+char r9[5] = "6chars"; //expected-warning{{initializer-string for char array is too long}}
+
+int r11[0] = {}; //expected-warning{{zero size arrays are an extension}} expected-warning{{use of GNU empty initializer extension}}
+
+// Some struct tests
+void autoStructTest() {
+struct s1 {char a; char b;} t1;
+struct s2 {struct s1 c;} t2 = { t1 };
+// The following is a less than great diagnostic (though it's on par with EDG).
+struct s1 t3[] = {t1, t1, "abc", 0}; //expected-warning{{incompatible pointer to integer conversion initializing 'char [4]', expected 'char'}}
+int t4[sizeof t3 == 6 ? 1 : -1];
+}
+struct foo { int z; } w;
+int bar (void) {
+ struct foo z = { w }; //expected-error{{incompatible type initializing 'struct foo', expected 'int'}}
+ return z.z;
+}
+struct s3 {void (*a)(void);} t5 = {autoStructTest};
+struct {int a; int b[];} t6 = {1, {1, 2, 3}}; // expected-warning{{flexible array initialization is a GNU extension}} \
+// expected-note{{initialized flexible array member 'b' is here}}
+union {char a; int b;} t7[] = {1, 2, 3};
+int t8[sizeof t7 == (3*sizeof(int)) ? 1 : -1];
+
+struct bittest{int : 31, a, :21, :12, b;};
+struct bittest bittestvar = {1, 2, 3, 4}; //expected-warning{{excess elements in struct initializer}}
+
+// Not completely sure what should happen here...
+int u1 = {}; //expected-warning{{use of GNU empty initializer extension}} expected-error{{scalar initializer cannot be empty}}
+int u2 = {{3}}; //expected-error{{too many braces around scalar initializer}}
+
+// PR2362
+void varArray() {
+ int c[][x] = { 0 }; //expected-error{{variable-sized object may not be initialized}}
+}
+
+// PR2151
+int emptyInit() {struct {} x[] = {6};} //expected-warning{{empty struct extension}} expected-error{{initializer for aggregate with no elements}}
+
+int noNamedInit() {
+struct {int:5;} x[] = {6}; //expected-error{{initializer for aggregate with no elements}}
+}
+struct {int a; int:5;} noNamedImplicit[] = {1,2,3};
+int noNamedImplicitCheck[sizeof(noNamedImplicit) == 3 * sizeof(*noNamedImplicit) ? 1 : -1];
+
+
+// ptrs are constant
+struct soft_segment_descriptor {
+ long ssd_base;
+};
+static int dblfault_tss;
+
+union uniao { int ola; } xpto[1];
+
+struct soft_segment_descriptor gdt_segs[] = {
+ {(long) &dblfault_tss},
+ { (long)xpto},
+};
+
+static void sppp_ipv6cp_up();
+const struct {} ipcp = { sppp_ipv6cp_up }; //expected-warning{{empty struct extension}} expected-warning{{excess elements in struct initializer}}
+
+struct _Matrix { union { float m[4][4]; }; }; //expected-warning{{anonymous unions are a GNU extension in C}}
+typedef struct _Matrix Matrix;
+void test_matrix() {
+ const Matrix mat1 = {
+ { { 1.0f, 2.0f, 3.0f, 4.0f,
+ 5.0f, 6.0f, 7.0f, 8.0f,
+ 9.0f, 10.0f, 11.0f, 12.0f,
+ 13.0f, 14.0f, 15.0f, 16.0f } }
+ };
+
+ const Matrix mat2 = {
+ 1.0f, 2.0f, 3.0f, 4.0f,
+ 5.0f, 6.0f, 7.0f, 8.0f,
+ 9.0f, 10.0f, 11.0f, 12.0f,
+ 13.0f, 14.0f, 15.0f, 16.0f
+ };
+}
+
+char badchararray[1] = { badchararray[0], "asdf" }; // expected-warning {{excess elements in array initializer}} expected-error {{initializer element is not a compile-time constant}}
diff --git a/test/Sema/asm.c b/test/Sema/asm.c
new file mode 100644
index 000000000000..0a62545a1e08
--- /dev/null
+++ b/test/Sema/asm.c
@@ -0,0 +1,78 @@
+// RUN: clang-cc %s -triple i386-pc-linux-gnu -verify -fsyntax-only
+
+void f() {
+ int i;
+
+ asm ("foo\n" : : "a" (i + 2));
+ asm ("foo\n" : : "a" (f())); // expected-error {{invalid type 'void' in asm input}}
+
+ asm ("foo\n" : "=a" (f())); // expected-error {{invalid lvalue in asm output}}
+ asm ("foo\n" : "=a" (i + 2)); // expected-error {{invalid lvalue in asm output}}
+
+ asm ("foo\n" : [symbolic_name] "=a" (i) : "[symbolic_name]" (i));
+ asm ("foo\n" : "=a" (i) : "[" (i)); // expected-error {{invalid input constraint '[' in asm}}
+ asm ("foo\n" : "=a" (i) : "[foo" (i)); // expected-error {{invalid input constraint '[foo' in asm}}
+ asm ("foo\n" : "=a" (i) : "[symbolic_name]" (i)); // expected-error {{invalid input constraint '[symbolic_name]' in asm}}
+}
+
+void clobbers() {
+ asm ("nop" : : : "ax", "#ax", "%ax");
+ asm ("nop" : : : "eax", "rax", "ah", "al");
+ asm ("nop" : : : "0", "%0", "#0");
+ asm ("nop" : : : "foo"); // expected-error {{unknown register name 'foo' in asm}}
+ asm ("nop" : : : "52");
+ asm ("nop" : : : "53"); // expected-error {{unknown register name '53' in asm}}
+ asm ("nop" : : : "-1"); // expected-error {{unknown register name '-1' in asm}}
+ asm ("nop" : : : "+1"); // expected-error {{unknown register name '+1' in asm}}
+}
+
+// rdar://6094010
+void test3() {
+ int x;
+ asm(L"foo" : "=r"(x)); // expected-error {{wide string}}
+ asm("foo" : L"=r"(x)); // expected-error {{wide string}}
+}
+
+// <rdar://problem/6156893>
+void test4(const volatile void *addr)
+{
+ asm ("nop" : : "r"(*addr)); // expected-error {{invalid type 'void const volatile' in asm input for constraint 'r'}}
+ asm ("nop" : : "m"(*addr));
+
+ asm ("nop" : : "r"(test4(addr))); // expected-error {{invalid type 'void' in asm input for constraint 'r'}}
+ asm ("nop" : : "m"(test4(addr))); // expected-error {{invalid lvalue in asm input for constraint 'm'}}
+
+ asm ("nop" : : "m"(f())); // expected-error {{invalid lvalue in asm input for constraint 'm'}}
+}
+
+// <rdar://problem/6512595>
+void test5() {
+ asm("nop" : : "X" (8));
+}
+
+// PR3385
+void test6(long i) {
+ asm("nop" : : "er"(i));
+}
+
+void asm_string_tests(int i) {
+ asm("%!"); // simple asm string, %! is not an error.
+ asm("%!" : ); // expected-error {{invalid % escape in inline assembly string}}
+ asm("xyz %" : ); // expected-error {{invalid % escape in inline assembly string}}
+
+ asm ("%[somename]" :: [somename] "i"(4)); // ok
+ asm ("%[somename]" :: "i"(4)); // expected-error {{unknown symbolic operand name in inline assembly string}}
+ asm ("%[somename" :: "i"(4)); // expected-error {{unterminated symbolic operand name in inline assembly string}}
+ asm ("%[]" :: "i"(4)); // expected-error {{empty symbolic operand name in inline assembly string}}
+
+ // PR3258
+ asm("%9" :: "i"(4)); // expected-error {{invalid operand number in inline asm string}}
+ asm("%1" : "+r"(i)); // ok, referring to input.
+}
+
+// PR4077
+int test7(unsigned long long b) {
+ int a;
+ asm volatile("foo %0 %1" : "=a" (a) :"0" (b)); // expected-error {{input with type 'unsigned long long' matching output with type 'int'}}
+ return a;
+}
diff --git a/test/Sema/assign-null.c b/test/Sema/assign-null.c
new file mode 100644
index 000000000000..a343c8069fdc
--- /dev/null
+++ b/test/Sema/assign-null.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+#include <stddef.h>
+
+typedef void (*hookfunc)(void *arg);
+hookfunc hook;
+
+void clear_hook() {
+ hook = NULL;
+}
diff --git a/test/Sema/assign.c b/test/Sema/assign.c
new file mode 100644
index 000000000000..b25262c62438
--- /dev/null
+++ b/test/Sema/assign.c
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void *test1(void) { return 0; }
+
+void test2 (const struct {int a;} *x) {
+ x->a = 10; // expected-error {{read-only variable is not assignable}}
+}
+
+typedef int arr[10];
+void test3() {
+ const arr b;
+ const int b2[10];
+ b[4] = 1; // expected-error {{read-only variable is not assignable}}
+ b2[4] = 1; // expected-error {{read-only variable is not assignable}}
+}
diff --git a/test/Sema/ast-print.c b/test/Sema/ast-print.c
new file mode 100644
index 000000000000..a8988b029f49
--- /dev/null
+++ b/test/Sema/ast-print.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc %s -ast-print
+
+typedef void func_typedef();
+func_typedef xxx;
+
+typedef void func_t(int x);
+func_t a;
+
diff --git a/test/Sema/attr-aligned.c b/test/Sema/attr-aligned.c
new file mode 100644
index 000000000000..6e641cb371f9
--- /dev/null
+++ b/test/Sema/attr-aligned.c
@@ -0,0 +1,21 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -fsyntax-only -verify %s
+
+int x __attribute__((aligned(3))); // expected-error {{requested alignment is not a power of 2}}
+
+// PR3254
+short g0[3] __attribute__((aligned));
+short g0_chk[__alignof__(g0) == 16 ? 1 : -1];
+
+// <rdar://problem/6840045>
+typedef char ueber_aligned_char __attribute__((aligned(8)));
+
+struct struct_with_ueber_char {
+ ueber_aligned_char c;
+};
+
+char c = 0;
+
+char a0[__alignof__(ueber_aligned_char) == 8? 1 : -1] = { 0 };
+char a1[__alignof__(struct struct_with_ueber_char) == 8? 1 : -1] = { 0 };
+char a2[__alignof__(c) == 1? : -1] = { 0 };
+char a3[sizeof(c) == 1? : -1] = { 0 };
diff --git a/test/Sema/attr-cleanup.c b/test/Sema/attr-cleanup.c
new file mode 100644
index 000000000000..0434981c6c4a
--- /dev/null
+++ b/test/Sema/attr-cleanup.c
@@ -0,0 +1,40 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+void c1(int *a);
+
+extern int g1 __attribute((cleanup(c1))); // expected-warning {{cleanup attribute ignored}}
+int g2 __attribute((cleanup(c1))); // expected-warning {{cleanup attribute ignored}}
+static int g3 __attribute((cleanup(c1))); // expected-warning {{cleanup attribute ignored}}
+
+void t1()
+{
+ int v1 __attribute((cleanup)); // expected-error {{attribute requires 1 argument(s)}}
+ int v2 __attribute((cleanup(1, 2))); // expected-error {{attribute requires 1 argument(s)}}
+
+ static int v3 __attribute((cleanup(c1))); // expected-warning {{cleanup attribute ignored}}
+
+ int v4 __attribute((cleanup(h))); // expected-error {{'cleanup' argument 'h' not found}}
+
+ int v5 __attribute((cleanup(c1)));
+ int v6 __attribute((cleanup(v3))); // expected-error {{'cleanup' argument 'v3' is not a function}}
+}
+
+struct s {
+ int a, b;
+};
+
+void c2();
+void c3(struct s a);
+
+void t2()
+{
+ int v1 __attribute__((cleanup(c2))); // expected-error {{'cleanup' function 'c2' must take 1 parameter}}
+ int v2 __attribute__((cleanup(c3))); // expected-error {{'cleanup' function 'c3' parameter has type 'struct s' which is incompatible with type 'int *'}}
+}
+
+// This is a manufactured testcase, but gcc accepts it...
+void c4(_Bool a);
+void t4() {
+ __attribute((cleanup(c4))) void* g;
+}
+
diff --git a/test/Sema/attr-deprecated.c b/test/Sema/attr-deprecated.c
new file mode 100644
index 000000000000..6597bad4b572
--- /dev/null
+++ b/test/Sema/attr-deprecated.c
@@ -0,0 +1,45 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+int f() __attribute__((deprecated));
+void g() __attribute__((deprecated));
+void g();
+
+void z() __attribute__((bogusattr)); // expected-warning {{'bogusattr' attribute ignored}}
+
+extern int var __attribute__((deprecated));
+
+int a() {
+ int (*ptr)() = f; // expected-warning {{'f' is deprecated}}
+ f(); // expected-warning {{'f' is deprecated}}
+
+ // test if attributes propagate to functions
+ g(); // expected-warning {{'g' is deprecated}}
+
+ return var; // expected-warning {{'var' is deprecated}}
+}
+
+// test if attributes propagate to variables
+extern int var;
+int w() {
+ return var; // expected-warning {{'var' is deprecated}}
+}
+
+int old_fn() __attribute__ ((deprecated));
+int old_fn();
+int (*fn_ptr)() = old_fn; // expected-warning {{'old_fn' is deprecated}}
+
+int old_fn() {
+ return old_fn()+1; // no warning, deprecated functions can use deprecated symbols.
+}
+
+
+struct foo {
+ int x __attribute__((deprecated));
+};
+
+void test1(struct foo *F) {
+ ++F->x; // expected-warning {{'x' is deprecated}}
+}
+
+typedef struct foo foo_dep __attribute__((deprecated));
+foo_dep *test2; // expected-warning {{'foo_dep' is deprecated}}
diff --git a/test/Sema/attr-mode.c b/test/Sema/attr-mode.c
new file mode 100644
index 000000000000..ac411d7c42dd
--- /dev/null
+++ b/test/Sema/attr-mode.c
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef int i16_1 __attribute((mode(HI)));
+int i16_1_test[sizeof(i16_1) == 2 ? 1 : -1];
+typedef int i16_2 __attribute((__mode__(__HI__)));
+int i16_2_test[sizeof(i16_1) == 2 ? 1 : -1];
+
+typedef float f64 __attribute((mode(DF)));
+int f64_test[sizeof(f64) == 8 ? 1 : -1];
+
+typedef int invalid_1 __attribute((mode)); // expected-error{{attribute requires unquoted parameter}}
+typedef int invalid_2 __attribute((mode())); // expected-error{{attribute requires unquoted parameter}}
+typedef int invalid_3 __attribute((mode(II))); // expected-error{{unknown machine mode}}
+typedef struct {int i,j,k;} invalid_4 __attribute((mode(SI))); // expected-error{{mode attribute only supported for integer and floating-point types}}
+typedef float invalid_5 __attribute((mode(SI))); // expected-error{{type of machine mode does not match type of base type}}
+
+int **__attribute((mode(QI)))* i32; // expected-error{{mode attribute}}
+
+typedef _Complex double c32 __attribute((mode(SC)));
+int c32_test[sizeof(c32) == 8 ? 1 : -1];
+typedef _Complex float c64 __attribute((mode(DC)));
+typedef _Complex float c80 __attribute((mode(XC)));
diff --git a/test/Sema/attr-nodebug.c b/test/Sema/attr-nodebug.c
new file mode 100644
index 000000000000..512ecfdcafc6
--- /dev/null
+++ b/test/Sema/attr-nodebug.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+int a __attribute__((nodebug)); // expected-warning {{'nodebug' attribute only applies to function types}}
+
+void t1() __attribute__((nodebug));
+
+void t2() __attribute__((nodebug(2))); // expected-error {{attribute requires 0 argument(s)}}
+
diff --git a/test/Sema/attr-noinline.c b/test/Sema/attr-noinline.c
new file mode 100644
index 000000000000..cf695f0d21f5
--- /dev/null
+++ b/test/Sema/attr-noinline.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+int a __attribute__((noinline)); // expected-warning {{'noinline' attribute only applies to function types}}
+
+void t1() __attribute__((noinline));
+
+void t2() __attribute__((noinline(2))); // expected-error {{attribute requires 0 argument(s)}}
+
diff --git a/test/Sema/attr-noreturn.c b/test/Sema/attr-noreturn.c
new file mode 100644
index 000000000000..d1417f093ffb
--- /dev/null
+++ b/test/Sema/attr-noreturn.c
@@ -0,0 +1,27 @@
+// RUN: clang-cc -verify -fsyntax-only %s
+
+static void (*fp0)(void) __attribute__((noreturn));
+
+static void __attribute__((noreturn)) f0(void) {
+ fatal();
+}
+
+// On K&R
+int f1() __attribute__((noreturn));
+
+int g0 __attribute__((noreturn)); // expected-warning {{'noreturn' attribute only applies to function types}}
+
+int f2() __attribute__((noreturn(1, 2))); // expected-error {{attribute requires 0 argument(s)}}
+
+void f3() __attribute__((noreturn));
+void f3() {
+ return; // expected-error {{function 'f3' declared 'noreturn' should not return}}
+}
+
+#pragma clang diagnostic warning "-Winvalid-noreturn"
+
+void f4() __attribute__((noreturn));
+void f4() {
+ return; // expected-warning {{function 'f4' declared 'noreturn' should not return}}
+}
+
diff --git a/test/Sema/attr-regparm.c b/test/Sema/attr-regparm.c
new file mode 100644
index 000000000000..944f01489c8b
--- /dev/null
+++ b/test/Sema/attr-regparm.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -fsyntax-only -verify %s
+
+__attribute((regparm(2))) int x(void);
+__attribute((regparm(1.0))) int x(void); // expected-error{{'regparm' attribute requires integer constant}}
+__attribute((regparm(-1))) int x(void); // expected-error{{'regparm' parameter must be between 0 and 3 inclusive}}
+__attribute((regparm(5))) int x(void); // expected-error{{'regparm' parameter must be between 0 and 3 inclusive}}
+__attribute((regparm(5,3))) int x(void); // expected-error{{attribute requires 1 argument(s)}}
diff --git a/test/Sema/attr-unused.c b/test/Sema/attr-unused.c
new file mode 100644
index 000000000000..dbb5e630d7a1
--- /dev/null
+++ b/test/Sema/attr-unused.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -verify -fsyntax-only %s
+
+static void (*fp0)(void) __attribute__((unused));
+
+static void __attribute__((unused)) f0(void);
+
+// On K&R
+int f1() __attribute__((unused));
+
+int g0 __attribute__((unused));
+
+int f2() __attribute__((unused(1, 2))); // expected-error {{attribute requires 0 argument(s)}}
diff --git a/test/Sema/attr-used.c b/test/Sema/attr-used.c
new file mode 100644
index 000000000000..fdabf7ff2ad5
--- /dev/null
+++ b/test/Sema/attr-used.c
@@ -0,0 +1,20 @@
+// RUN: clang-cc -verify -fsyntax-only %s
+
+extern int l0 __attribute__((used)); // expected-warning {{used attribute ignored}}
+__private_extern__ int l1 __attribute__((used)); // expected-warning {{used attribute ignored}}
+
+struct __attribute__((used)) s { // expected-warning {{'used' attribute only applies to variable and function types}}
+ int x;
+};
+
+int a __attribute__((used));
+
+static void __attribute__((used)) f0(void) {
+}
+
+void f1() {
+ static int a __attribute__((used));
+ int b __attribute__((used)); // expected-warning {{used attribute ignored}}
+}
+
+
diff --git a/test/Sema/attr-warn_unused_result.c b/test/Sema/attr-warn_unused_result.c
new file mode 100644
index 000000000000..b4ef1bbeaf0e
--- /dev/null
+++ b/test/Sema/attr-warn_unused_result.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+// rdar://6587766
+
+int fn1() __attribute__ ((warn_unused_result));
+int fn2() __attribute__ ((pure));
+int fn3() __attribute__ ((const));
+
+int foo() {
+ if (fn1() < 0 || fn2(2,1) < 0 || fn3(2) < 0) // no warnings
+ return -1;
+
+ fn1(); // expected-warning {{expression result unused}}
+ fn2(92, 21); // expected-warning {{expression result unused}}
+ fn3(42); // expected-warning {{expression result unused}}
+ return 0;
+}
+
+int bar __attribute__ ((warn_unused_result)); // expected-warning {{warning: 'warn_unused_result' attribute only applies to function types}}
+
diff --git a/test/Sema/attr-weak.c b/test/Sema/attr-weak.c
new file mode 100644
index 000000000000..b79e1e7dfca7
--- /dev/null
+++ b/test/Sema/attr-weak.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -verify -fsyntax-only %s
+
+extern int g0 __attribute__((weak));
+extern int g1 __attribute__((weak_import));
+int g2 __attribute__((weak));
+int g3 __attribute__((weak_import)); // expected-warning {{'weak_import' attribute cannot be specified on a definition}}
+int __attribute__((weak_import)) g4(void);
+int __attribute__((weak_import)) g5(void) {
+}
+
+struct __attribute__((weak)) s0 {}; // expected-warning {{'weak' attribute only applies to variable and function types}}
+struct __attribute__((weak_import)) s1 {}; // expected-warning {{'weak_import' attribute only applies to variable and function types}}
+
diff --git a/test/Sema/bitfield-layout.c b/test/Sema/bitfield-layout.c
new file mode 100644
index 000000000000..4405c80fee6b
--- /dev/null
+++ b/test/Sema/bitfield-layout.c
@@ -0,0 +1,32 @@
+// RUN: clang-cc %s -fsyntax-only -verify -triple=i686-apple-darwin9
+
+#define CHECK_SIZE(kind, name, size) extern int name##1[sizeof(kind name) == size ? 1 : -1];
+#define CHECK_ALIGN(kind, name, size) extern int name##2[__alignof(kind name) == size ? 1 : -1];
+
+// Zero-width bit-fields
+struct a {char x; int : 0; char y;};
+CHECK_SIZE(struct, a, 5)
+CHECK_ALIGN(struct, a, 1)
+
+union b {char x; int : 0; char y;};
+CHECK_SIZE(union, b, 1)
+CHECK_ALIGN(union, b, 1)
+
+// Unnamed bit-field align
+struct c {char x; int : 20;};
+CHECK_SIZE(struct, c, 4)
+CHECK_ALIGN(struct, c, 1)
+
+union d {char x; int : 20;};
+CHECK_SIZE(union, d, 3)
+CHECK_ALIGN(union, d, 1)
+
+// Bit-field packing
+struct __attribute__((packed)) e {int x : 4, y : 30, z : 30;};
+CHECK_SIZE(struct, e, 8)
+CHECK_ALIGN(struct, e, 1)
+
+// Alignment on bit-fields
+struct f {__attribute((aligned(8))) int x : 30, y : 30, z : 30;};
+CHECK_SIZE(struct, f, 24)
+CHECK_ALIGN(struct, f, 8)
diff --git a/test/Sema/bitfield.c b/test/Sema/bitfield.c
new file mode 100644
index 000000000000..655f74121a32
--- /dev/null
+++ b/test/Sema/bitfield.c
@@ -0,0 +1,36 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+enum e0; // expected-note{{forward declaration of 'enum e0'}}
+
+struct a {
+ int a : -1; // expected-error{{bit-field 'a' has negative width}}
+
+ // rdar://6081627
+ int b : 33; // expected-error{{size of bit-field 'b' exceeds size of its type (32 bits)}}
+
+ int c : (1 + 0.25); // expected-error{{expression is not an integer constant expression}}
+ int d : (int)(1 + 0.25);
+
+ // rdar://6138816
+ int e : 0; // expected-error {{bit-field 'e' has zero width}}
+
+ float xx : 4; // expected-error {{bit-field 'xx' has non-integral type}}
+
+ // PR3607
+ enum e0 f : 1; // expected-error {{field has incomplete type 'enum e0'}}
+
+ int g : (_Bool)1;
+
+ // PR4017
+ char : 10; // expected-error {{size of anonymous bitfield exceeds size of its type (8 bits)}}
+ unsigned : -2; // expected-error {{anonymous bit-field has negative width (-2)}}
+ float : 12; // expected-error {{anonymous bit-field has non-integral type 'float'}}
+};
+
+struct b {unsigned x : 2;} x;
+__typeof__(x.x+1) y;
+int y;
+
+struct {unsigned x : 2;} x2;
+__typeof__((x.x+=1)+1) y;
+__typeof__(x.x<<1) y;
+int y;
diff --git a/test/Sema/block-args.c b/test/Sema/block-args.c
new file mode 100644
index 000000000000..a2d8e5a86731
--- /dev/null
+++ b/test/Sema/block-args.c
@@ -0,0 +1,29 @@
+// RUN: clang-cc %s -fsyntax-only -verify -fblocks
+
+void take(void*);
+
+void test() {
+ take(^(int x){});
+ take(^(int x, int y){});
+ take(^(int x, int y){});
+ take(^(int x, int x){}); // expected-error {{redefinition of parameter 'x'}}
+
+
+ take(^(int x) { return x+1; });
+
+ int (^CP)(int) = ^(int x) { return x*x; };
+ take(CP);
+
+ int arg;
+ ^{return 1;}();
+ ^{return 2;}(arg); // expected-error {{too many arguments to block call}}
+ ^(void){return 3;}(1); // expected-error {{too many arguments to block call}}
+ ^(){return 4;}(arg); // C style (...), ok.
+ ^(int x, ...){return 5;}(arg, arg); // Explicit varargs, ok.
+}
+
+int main(int argc) {
+ ^(int argCount) {
+ argCount = 3;
+ }(argc);
+}
diff --git a/test/Sema/block-as-object.m b/test/Sema/block-as-object.m
new file mode 100644
index 000000000000..219b1a065325
--- /dev/null
+++ b/test/Sema/block-as-object.m
@@ -0,0 +1,20 @@
+// RUN: clang-cc %s -fsyntax-only -verify -fblocks
+
+@interface Whatever
+- copy;
+@end
+
+typedef long (^MyBlock)(id obj1, id obj2);
+
+void foo(MyBlock b) {
+ id bar = [b copy];
+}
+
+void foo2(id b) {
+}
+
+void foo3(void (^block)(void)) {
+ foo2(block);
+ id x;
+ foo(x);
+}
diff --git a/test/Sema/block-byref-args.c b/test/Sema/block-byref-args.c
new file mode 100644
index 000000000000..39745d54efa4
--- /dev/null
+++ b/test/Sema/block-byref-args.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc %s -fsyntax-only -verify -fblocks
+
+#include <stdio.h>
+
+int main(int argc, char **argv) {
+ __block void(*bobTheFunction)(void);
+ __block void(^bobTheBlock)(void);
+
+ bobTheBlock = ^{;};
+
+ __block int JJJJ;
+ __attribute__((__blocks__(byref))) int III;
+
+ int (^XXX)(void) = ^{ return III+JJJJ; };
+
+ return 0;
+}
+
diff --git a/test/Sema/block-call.c b/test/Sema/block-call.c
new file mode 100644
index 000000000000..9d3ff71e2195
--- /dev/null
+++ b/test/Sema/block-call.c
@@ -0,0 +1,55 @@
+// RUN: clang-cc -fsyntax-only -verify %s -fblocks
+
+int (*FP)();
+int (^IFP) ();
+int (^II) (int);
+int main() {
+ int (*FPL) (int) = FP; // C doesn't consider this an error.
+
+ // For Blocks, the ASTContext::typesAreBlockCompatible() makes sure this is an error.
+ int (^PFR) (int) = IFP; // expected-error {{incompatible block pointer types initializing 'int (^)()', expected 'int (^)(int)'}}
+ PFR = II; // OK
+
+ int (^IFP) () = PFR;
+
+
+ const int (^CIC) () = IFP; // expected-error {{incompatible block pointer types initializing 'int (^)()', expected 'int const (^)()'}}
+
+
+ const int (^CICC) () = CIC;
+
+ int * const (^IPCC) () = 0;
+
+ int * const (^IPCC1) () = IPCC;
+
+ int * (^IPCC2) () = IPCC; // expected-error {{incompatible block pointer types initializing 'int *const (^)()', expected 'int *(^)()'}}
+
+ int (^IPCC3) (const int) = PFR;
+
+
+ int (^IPCC4) (int, char (^CArg) (double));
+
+
+ int (^IPCC5) (int, char (^CArg) (double)) = IPCC4;
+
+ int (^IPCC6) (int, char (^CArg) (float)) = IPCC4; // expected-error {{incompatible block pointer types initializing 'int (^)(int, char (^)(double))', expected 'int (^)(int, char (^)(float))'}}
+
+ IPCC2 = 0;
+ IPCC2 = 1; // expected-error {{invalid conversion assigning integer 'int', expected block pointer 'int *(^)()'}}
+ int (^x)() = 0;
+ int (^y)() = 3; // expected-error {{invalid conversion initializing integer 'int', expected block pointer 'int (^)()'}}
+ int a = 1;
+ int (^z)() = a+4; // expected-error {{invalid conversion initializing integer 'int', expected block pointer 'int (^)()'}}
+}
+
+int blah() {
+ int (^IFP) (float);
+ char (^PCP)(double, double, char);
+
+ IFP(1.0);
+ IFP (1.0, 2.0); // expected-error {{too many arguments to block call}}
+
+ char ch = PCP(1.0, 2.0, 'a');
+ return PCP(1.0, 2.0); // expected-error {{too few arguments to block}}
+}
+
diff --git a/test/Sema/block-explicit-return-type.c b/test/Sema/block-explicit-return-type.c
new file mode 100644
index 000000000000..c7b26b3d6bf6
--- /dev/null
+++ b/test/Sema/block-explicit-return-type.c
@@ -0,0 +1,81 @@
+// RUN: clang-cc -ObjC -fsyntax-only %s -verify -fblocks
+// FIXME: should compile
+// Test for blocks with explicit return type specified.
+
+typedef float * PF;
+float gf;
+
+@interface NSView
+ - (id) some_method_that_returns_id;
+@end
+
+NSView *some_object;
+
+void some_func (NSView * (^) (id));
+
+typedef struct dispatch_item_s *dispatch_item_t;
+typedef void (^completion_block_t)(void);
+
+typedef double (^myblock)(int);
+double test(myblock I);
+
+int main()
+{
+ __block int x = 1;
+ __block int y = 2;
+
+ (void)^void *{ return 0; };
+
+ (void)^float(float y){ return y; };
+
+ (void)^double (float y, double d)
+ {
+ if (y)
+ return d;
+ else
+ return y;
+ };
+
+ const char * (^chb) (int flag, const char *arg, char *arg1) = ^ const char * (int flag, const char *arg, char *arg1) {
+ if (flag)
+ return 0;
+ if (flag == 1)
+ return arg;
+ else if (flag == 2)
+ return "";
+ return arg1;
+ };
+
+ (void)^PF { return &gf; };
+
+ some_func(^ NSView * (id whatever) { return [some_object some_method_that_returns_id]; });
+
+ double res = test(^(int z){x = y+z; return (double)z; });
+}
+
+void func()
+{
+ completion_block_t X;
+
+ completion_block_t (^blockx)(dispatch_item_t) = ^completion_block_t (dispatch_item_t item) {
+ return X;
+ };
+
+ completion_block_t (^blocky)(dispatch_item_t) = ^(dispatch_item_t item) {
+ return X;
+ };
+
+ blockx = blocky;
+
+}
+
+
+// intent: block taking int returning block that takes char,int and returns int
+int (^(^block)(double x))(char, short);
+
+void foo() {
+ int one = 1;
+ block = ^(double x){ return ^(char c, short y) { return one + c + y; };}; // expected-error {{returning block that lives on the local stack}}
+ // or:
+ block = ^(double x){ return ^(char c, short y) { return one + (int)c + y; };}; // expected-error {{returning block that lives on the local stack}}
+}
diff --git a/test/Sema/block-labels.c b/test/Sema/block-labels.c
new file mode 100644
index 000000000000..f0f8c4856d81
--- /dev/null
+++ b/test/Sema/block-labels.c
@@ -0,0 +1,17 @@
+// RUN: clang-cc %s -verify -fblocks -fsyntax-only
+
+int a() {
+ A:if (1) xx();
+ return ^{A:return 1;}();
+}
+int b() {
+ A: return ^{int a; A:return 1;}();
+}
+
+int d() {
+ A: return ^{int a; A: a = ^{int a; A:return 1;}() + ^{int b; A:return 2;}(); return a; }();
+}
+
+int c() {
+ goto A; return ^{ A:return 1;}(); // expected-error {{use of undeclared label 'A'}}
+}
diff --git a/test/Sema/block-literal.c b/test/Sema/block-literal.c
new file mode 100644
index 000000000000..19d476fc294f
--- /dev/null
+++ b/test/Sema/block-literal.c
@@ -0,0 +1,124 @@
+// RUN: clang-cc -fsyntax-only %s -verify -fblocks
+
+void I( void (^)(void));
+void (^noop)(void);
+
+void nothing();
+int printf(const char*, ...);
+
+typedef void (^T) (void);
+
+void takeclosure(T);
+int takeintint(int (^C)(int)) { return C(4); }
+
+T somefunction() {
+ if (^{ })
+ nothing();
+
+ noop = ^{};
+
+ noop = ^{printf("\nClosure\n"); };
+
+ I(^{ });
+
+ return ^{printf("\nClosure\n"); };
+}
+void test2() {
+ int x = 4;
+
+ takeclosure(^{ printf("%d\n", x); });
+
+ while (1) {
+ takeclosure(^{
+ break; // expected-error {{'break' statement not in loop or switch statement}}
+ continue; // expected-error {{'continue' statement not in loop statement}}
+ while(1) break; // ok
+ goto foo; // expected-error {{goto not allowed}}
+ });
+ break;
+ }
+
+foo:
+ takeclosure(^{ x = 4; }); // expected-error {{variable is not assignable (missing __block type specifier)}}
+ __block y = 7; // expected-warning {{type specifier missing, defaults to 'int'}}
+ takeclosure(^{ y = 8; });
+}
+
+
+void (^test3())(void) {
+ return ^{};
+}
+
+void test4() {
+ void (^noop)(void) = ^{};
+ void (*noop2)() = 0;
+}
+
+void myfunc(int (^block)(int)) {}
+
+void myfunc3(const int *x);
+
+void test5() {
+ int a;
+
+ myfunc(^(int abcd) {
+ myfunc3(&a);
+ return 1;
+ });
+}
+
+void *X;
+
+void test_arguments() {
+ int y;
+ int (^c)(char);
+ (1 ? c : 0)('x');
+ (1 ? 0 : c)('x');
+
+ (1 ? c : c)('x');
+}
+
+static int global_x = 10;
+void (^global_block)(void) = ^{ printf("global x is %d\n", global_x); };
+
+typedef void (^void_block_t)(void);
+
+static const void_block_t myBlock = ^{ };
+
+static const void_block_t myBlock2 = ^ void(void) { };
+
+#if 0
+// Old syntax. FIXME: convert/test.
+void test_byref() {
+ int i;
+
+ X = ^{| g |}; // error {{use of undeclared identifier 'g'}}
+
+ X = ^{| i,i,i | };
+
+ X = ^{|i| i = 0; };
+
+}
+
+// TODO: global closures someday.
+void *A = ^{};
+void *B = ^(int){ A = 0; };
+
+
+// Closures can not take return types at this point.
+void test_retvals() {
+ // Explicit return value.
+ ^int{}; // error {{closure with explicit return type requires argument list}}
+ X = ^void(){};
+
+ // Optional specification of return type.
+ X = ^char{ return 'x'; }; // error {{closure with explicit return type requires argument list}}
+
+ X = ^/*missing declspec*/ *() { return (void*)0; };
+ X = ^void*() { return (void*)0; };
+
+ //X = ^char(short c){ if (c) return c; else return (int)4; };
+
+}
+
+#endif
diff --git a/test/Sema/block-misc.c b/test/Sema/block-misc.c
new file mode 100644
index 000000000000..93ca3c49d425
--- /dev/null
+++ b/test/Sema/block-misc.c
@@ -0,0 +1,187 @@
+// RUN: clang-cc -fsyntax-only -verify %s -fblocks
+void donotwarn();
+
+int (^IFP) ();
+int (^II) (int);
+int test1() {
+ int (^PFR) (int) = 0; // OK
+ PFR = II; // OK
+
+ if (PFR == II) // OK
+ donotwarn();
+
+ if (PFR == IFP) // expected-error {{comparison of distinct block types}}
+ donotwarn();
+
+ if (PFR == (int (^) (int))IFP) // OK
+ donotwarn();
+
+ if (PFR == 0) // OK
+ donotwarn();
+
+ if (PFR) // OK
+ donotwarn();
+
+ if (!PFR) // OK
+ donotwarn();
+
+ return PFR != IFP; // expected-error {{comparison of distinct block types}}
+}
+
+int test2(double (^S)()) {
+ double (^I)(int) = (void*) S;
+ (void*)I = (void *)S; // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
+
+ void *pv = I;
+
+ pv = S;
+
+ I(1);
+
+ return (void*)I == (void *)S;
+}
+
+int^ x; // expected-error {{block pointer to non-function type is invalid}}
+int^^ x1; // expected-error {{block pointer to non-function type is invalid}} expected-error {{block pointer to non-function type is invalid}}
+
+int test3() {
+ char *^ y; // expected-error {{block pointer to non-function type is invalid}}
+}
+
+
+
+enum {NSBIRLazilyAllocated = 0};
+
+int test4(int argc) { // rdar://6251437
+ ^{
+ switch (argc) {
+ case NSBIRLazilyAllocated: // is an integer constant expression.
+ default:
+ break;
+ }
+ }();
+ return 0;
+}
+
+
+// rdar://6257721 - reference to static/global is byref by default.
+static int test5g;
+void test5() {
+ bar(^{ test5g = 1; });
+}
+
+// rdar://6405429 - __func__ in a block refers to the containing function name.
+const char*test6() {
+ return ^{
+ return __func__;
+ } ();
+}
+
+// radr://6732116 - block comparisons
+void (^test7a)();
+int test7(void (^p)()) {
+ return test7a == p;
+}
+
+
+void test8() {
+somelabel:
+ // FIXME: This should say "jump out of block not legal" when gotos are allowed.
+ ^{ goto somelabel; }(); // expected-error {{goto not allowed in block literal}}
+}
+
+void test9() {
+ goto somelabel; // expected-error {{use of undeclared label 'somelabel'}}
+ ^{ somelabel: ; }();
+}
+
+void test10(int i) {
+ switch (i) {
+ case 41: ;
+ ^{ case 42: ; }(); // expected-error {{'case' statement not in switch statement}}
+ }
+}
+
+void test11(int i) {
+ switch (i) {
+ case 41: ;
+ ^{ break; }(); // expected-error {{'break' statement not in loop or switch statement}}
+ }
+
+ for (; i < 100; ++i)
+ ^{ break; }(); // expected-error {{'break' statement not in loop or switch statement}}
+}
+
+void (^test12f)(void);
+void test12() {
+ test12f = ^test12f; // expected-error {{type name requires a specifier or qualifier}} expected-error {{expected expression}}
+}
+
+// rdar://6808730
+void *test13 = ^{
+ int X = 32;
+
+ void *P = ^{
+ return X+4; // References outer block's "X", so outer block is constant.
+ };
+};
+
+void test14() {
+ int X = 32;
+ static void *P = ^{ // expected-error {{initializer element is not a compile-time constant}}
+
+ void *Q = ^{
+ // References test14's "X": outer block is non constant.
+ return X+4;
+ };
+ };
+}
+
+enum { LESS };
+
+void foo(long (^comp)()) {
+}
+
+void (^test15f)(void);
+void test15() {
+ foo(^{ return LESS; }); // expected-error {{incompatible block pointer types passing 'int (^)(void)', expected 'long (^)()'}}
+}
+
+__block int test16i; // expected-error {{__block attribute not allowed, only allowed on local variables}}
+
+void test16(__block int i) { // expected-error {{__block attribute not allowed, only allowed on local variables}}
+ int size = 5;
+ extern __block double extern_var; // expected-error {{__block attribute not allowed, only allowed on local variables}}
+ static __block char * pch; // expected-error {{__block attribute not allowed, only allowed on local variables}}
+ __block int a[size]; // expected-error {{__block attribute not allowed on declaration with a variably modified type}}
+ __block int (*ap)[size]; // expected-error {{__block attribute not allowed on declaration with a variably modified type}}
+}
+
+void test17() {
+ void (^bp)(int);
+ void (*rp)(int);
+ void (^bp1)();
+ void *vp = bp;
+
+ f(1 ? bp : vp);
+ f(1 ? vp : bp);
+ f(1 ? bp : bp1); // expected-error {{incompatible operand types ('void (^)(int)' and 'void (^)()')}}
+ (void)(bp > rp); // expected-error {{invalid operands}}
+ (void)(bp > 0); // expected-error {{invalid operands}}
+ (void)(bp > bp); // expected-error {{invalid operands}}
+ (void)(bp > vp); // expected-error {{invalid operands}}
+ f(1 ? bp : rp); // expected-error {{incompatible operand types ('void (^)(int)' and 'void (*)(int)')}}
+ (void)(bp == 1); // expected-error {{invalid operands to binary expression}}
+ (void)(bp == 0);
+ (void)(1 == bp); // expected-error {{invalid operands to binary expression}}
+ (void)(0 == bp);
+ (void)(bp < 1); // expected-error {{invalid operands to binary expression}}
+ (void)(bp < 0); // expected-error {{invalid operands to binary expression}}
+ (void)(1 < bp); // expected-error {{invalid operands to binary expression}}
+ (void)(0 < bp); // expected-error {{invalid operands to binary expression}}
+}
+
+void test18() {
+ void (^const blockA)(void) = ^{ };
+ blockA = ^{ }; // expected-error {{read-only variable is not assignable}}
+}
diff --git a/test/Sema/block-printf-attribute-1.c b/test/Sema/block-printf-attribute-1.c
new file mode 100644
index 000000000000..ce30b8e855b7
--- /dev/null
+++ b/test/Sema/block-printf-attribute-1.c
@@ -0,0 +1,15 @@
+// RUN: clang-cc %s -fsyntax-only -verify -fblocks
+
+int main()
+{
+ void (^b) (int arg, const char * format, ...) __attribute__ ((__format__ (__printf__, 1, 3))) = // expected-error {{format argument not a string type}}
+ ^ __attribute__ ((__format__ (__printf__, 1, 3))) (int arg, const char * format, ...) {}; // expected-error {{format argument not a string type}}
+
+ void (^z) (int arg, const char * format, ...) __attribute__ ((__format__ (__printf__, 2, 3))) = ^ __attribute__ ((__format__ (__printf__, 2, 3))) (int arg, const char * format, ...) {};
+
+ // FIXME: argument type poking not yet supportted.
+ z(1, "%s", 1); /* { dg-warning "format \\'\%s\\' expects type \\'char \\*\\'\, but argument 3 has type \\'int\\'" } */
+ z(1, "%s", "HELLO"); // OK
+
+}
+
diff --git a/test/Sema/block-return.c b/test/Sema/block-return.c
new file mode 100644
index 000000000000..e1a3cfd8123d
--- /dev/null
+++ b/test/Sema/block-return.c
@@ -0,0 +1,104 @@
+// RUN: clang-cc -fsyntax-only %s -verify -fblocks
+
+typedef void (^CL)(void);
+
+CL foo() {
+ short y;
+ short (^add1)(void) = ^{ return y+1; }; // expected-error {{incompatible block pointer types initializing 'int (^)(void)', expected 'short (^)(void)'}}
+
+ CL X = ^{
+ if (2)
+ return;
+ return 1; // expected-error {{void block should not return a value}}
+ };
+
+ int (^Y) (void) = ^{
+ if (3)
+ return 1;
+ else
+ return; // expected-error {{non-void block should return a value}}
+ };
+
+ char *(^Z)(void) = ^{
+ if (3)
+ return "";
+ else
+ return (char*)0;
+ };
+
+ double (^A)(void) = ^ { // expected-error {{incompatible block pointer types initializing 'float (^)(void)', expected 'double (^)(void)'}}
+ if (1)
+ return (float)1.0;
+ else
+ if (2)
+ return (double)2.0;
+ return 1;
+ };
+ char *(^B)(void) = ^{
+ if (3)
+ return "";
+ else
+ return 2; // expected-warning {{incompatible integer to pointer conversion returning 'int', expected 'char *'}}
+ };
+
+ return ^{ return 1; }; // expected-error {{incompatible block pointer types returning 'int (^)(void)', expected 'CL'}}
+}
+
+typedef int (^CL2)(void);
+
+CL2 foo2() {
+ return ^{ return 1; };
+}
+
+typedef unsigned int * uintptr_t;
+typedef char Boolean;
+typedef int CFBasicHash;
+
+#define INVOKE_CALLBACK2(P, A, B) (P)(A, B)
+
+typedef struct {
+ Boolean (^isEqual)(const CFBasicHash *, uintptr_t stack_value_or_key1, uintptr_t stack_value_or_key2, Boolean is_key);
+} CFBasicHashCallbacks;
+
+int foo3() {
+ CFBasicHashCallbacks cb;
+
+ Boolean (*value_equal)(uintptr_t, uintptr_t) = 0;
+
+ cb.isEqual = ^(const CFBasicHash *table, uintptr_t stack_value_or_key1, uintptr_t stack_value_or_key2, Boolean is_key) {
+ return (Boolean)(uintptr_t)INVOKE_CALLBACK2(value_equal, (uintptr_t)stack_value_or_key1, (uintptr_t)stack_value_or_key2);
+ };
+}
+
+static int funk(char *s) {
+ if (^{} == ((void*)0))
+ return 1;
+ else
+ return 0;
+}
+void foo4() {
+ int (^xx)(const char *s) = ^(char *s) { return 1; }; // expected-error {{incompatible block pointer types initializing 'int (^)(char *)', expected 'int (^)(char const *)'}}
+ int (*yy)(const char *s) = funk; // expected-warning {{incompatible pointer types initializing 'int (char *)', expected 'int (*)(char const *)'}}
+
+ int (^nested)(char *s) = ^(char *str) { void (^nest)(void) = ^(void) { printf("%s\n", str); }; next(); return 1; }; // expected-warning{{implicitly declaring C library function 'printf' with type 'int (char const *, ...)'}} \
+ // expected-note{{please include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
+}
+
+typedef void (^bptr)(void);
+
+bptr foo5(int j) {
+ __block int i;
+ if (j)
+ return ^{ ^{ i=0; }(); }; // expected-error {{returning block that lives on the local stack}}
+ return ^{ i=0; }; // expected-error {{returning block that lives on the local stack}}
+}
+
+int (*funcptr3[5])(long);
+int sz8 = sizeof(^int (*[5])(long) {return funcptr3;}); // expected-error {{block declared as returning an array}}
+
+void foo6() {
+ int (^b)(int) __attribute__((noreturn));
+ b = ^ (int i) __attribute__((noreturn)) { return 1; }; // expected-error {{block declared 'noreturn' should not return}}
+ b(1);
+ int (^c)(void) __attribute__((noreturn)) = ^ __attribute__((noreturn)) { return 100; }; // expected-error {{block declared 'noreturn' should not return}}
+}
diff --git a/test/Sema/block-sentinel-attribute.c b/test/Sema/block-sentinel-attribute.c
new file mode 100644
index 000000000000..a7d4df108ea7
--- /dev/null
+++ b/test/Sema/block-sentinel-attribute.c
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fblocks -fsyntax-only -verify %s
+
+void (^e) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (1,1)));
+
+int main()
+{
+ void (^bbad) (int arg, const char * format) __attribute__ ((__sentinel__)) ; // expected-warning {{sentinel' attribute only supported for variadic blocks}}
+ void (^b) (int arg, const char * format, ...) __attribute__ ((__sentinel__)) = // expected-note {{block has been explicitly marked sentinel here}}
+ ^ __attribute__ ((__sentinel__)) (int arg, const char * format, ...) {};
+ void (^z) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (2))) = ^ __attribute__ ((__sentinel__ (2))) (int arg, const char * format, ...) {}; // expected-note {{block has been explicitly marked sentinel here}}
+
+
+ void (^y) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (5))) = ^ __attribute__ ((__sentinel__ (5))) (int arg, const char * format, ...) {}; // expected-note {{block has been explicitly marked sentinel here}}
+
+ b(1, "%s", (void*)0); // OK
+ b(1, "%s", 0); // expected-warning {{missing sentinel in block call}}
+ z(1, "%s",4 ,1,0); // expected-warning {{missing sentinel in block call}}
+ z(1, "%s", (void*)0, 1, 0); // OK
+
+ y(1, "%s", 1,2,3,4,5,6,7); // expected-warning {{missing sentinel in block call}}
+
+ y(1, "%s", (void*)0,3,4,5,6,7); // OK
+
+}
+
diff --git a/test/Sema/block-storageclass.c b/test/Sema/block-storageclass.c
new file mode 100644
index 000000000000..3d2527b3f4e8
--- /dev/null
+++ b/test/Sema/block-storageclass.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc %s -fsyntax-only -verify -fblocks
+
+#include <stdio.h>
+void _Block_byref_release(void*src){}
+
+int main() {
+ __block int X = 1234;
+ __block const char * message = "HELLO";
+
+ X = X - 1234;
+
+ X += 1;
+
+ printf ("%s(%d)\n", message, X);
+ X -= 1;
+
+ return X;
+}
diff --git a/test/Sema/builtin-object-size.c b/test/Sema/builtin-object-size.c
new file mode 100644
index 000000000000..4b15cb1f0e23
--- /dev/null
+++ b/test/Sema/builtin-object-size.c
@@ -0,0 +1,28 @@
+// RUN: clang-cc -fsyntax-only -verify %s &&
+// RUN: clang-cc -fsyntax-only -triple x86_64-apple-darwin9 -verify %s
+
+int a[10];
+
+int f0() {
+ return __builtin_object_size(&a); // expected-error {{too few arguments to function}}
+}
+int f1() {
+ return (__builtin_object_size(&a, 0) +
+ __builtin_object_size(&a, 1) +
+ __builtin_object_size(&a, 2) +
+ __builtin_object_size(&a, 3));
+}
+int f2() {
+ return __builtin_object_size(&a, -1); // expected-error {{argument should be a value from 0 to 3}}
+}
+int f3() {
+ return __builtin_object_size(&a, 4); // expected-error {{argument should be a value from 0 to 3}}
+}
+
+
+// rdar://6252231 - cannot call vsnprintf with va_list on x86_64
+void f4(const char *fmt, ...) {
+ __builtin_va_list args;
+ __builtin___vsnprintf_chk (0, 42, 0, 11, fmt, args);
+}
+
diff --git a/test/Sema/builtin-prefetch.c b/test/Sema/builtin-prefetch.c
new file mode 100644
index 000000000000..6b39e75d5257
--- /dev/null
+++ b/test/Sema/builtin-prefetch.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int foo() {
+ int a;
+ __builtin_prefetch(&a);
+ __builtin_prefetch(&a, 1);
+ __builtin_prefetch(&a, 1, 2);
+ __builtin_prefetch(&a, 1, 9, 3); // expected-error{{too many arguments to function}}
+ __builtin_prefetch(&a, "hello", 2); // expected-error{{argument to __builtin_prefetch must be a constant integer}}
+ __builtin_prefetch(&a, 2); // expected-error{{argument should be a value from 0 to 1}}
+ __builtin_prefetch(&a, 0, 4); // expected-error{{argument should be a value from 0 to 3}}
+ __builtin_prefetch(&a, -1, 4); // expected-error{{argument should be a value from 0 to 1}}
+}
diff --git a/test/Sema/builtin-stackaddress.c b/test/Sema/builtin-stackaddress.c
new file mode 100644
index 000000000000..67582a549f5f
--- /dev/null
+++ b/test/Sema/builtin-stackaddress.c
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+void* a(unsigned x) {
+return __builtin_return_address(0);
+}
+
+void b(unsigned x) {
+return __builtin_return_address(x); // expected-error{{the level argument for a stack address builtin must be constant}}
+}
+
+void* c(unsigned x) {
+return __builtin_frame_address(0);
+}
+
+void d(unsigned x) {
+return __builtin_frame_address(x); // expected-error{{the level argument for a stack address builtin must be constant}}
+}
diff --git a/test/Sema/builtins.c b/test/Sema/builtins.c
new file mode 100644
index 000000000000..e57aec51bc55
--- /dev/null
+++ b/test/Sema/builtins.c
@@ -0,0 +1,52 @@
+// RUN: clang-cc %s -fsyntax-only -verify -pedantic -triple=i686-apple-darwin9
+// This test needs to set the target because it uses __builtin_ia32_vec_ext_v4si
+
+int test1(float a, int b) {
+ return __builtin_isless(a, b);
+}
+int test2(int a, int b) {
+ return __builtin_islessequal(a, b); // expected-error {{floating point type}}
+}
+
+int test3(double a, float b) {
+ return __builtin_isless(a, b);
+}
+int test4(int* a, double b) {
+ return __builtin_islessequal(a, b); // expected-error {{floating point type}}
+}
+
+int test5(float a, long double b) {
+ return __builtin_isless(a, b, b); // expected-error {{too many arguments}}
+}
+int test6(float a, long double b) {
+ return __builtin_islessequal(a); // expected-error {{too few arguments}}
+}
+
+
+#define CFSTR __builtin___CFStringMakeConstantString
+void test7() {
+ CFSTR("\242");
+ CFSTR("\0"); // expected-warning {{ CFString literal contains NUL character }}
+ CFSTR(242); // expected-error {{ CFString literal is not a string constant }} expected-warning {{incompatible integer to pointer conversion}}
+ CFSTR("foo", "bar"); // expected-error {{too many arguments to function call}}
+}
+
+
+typedef __attribute__(( ext_vector_type(16) )) unsigned char uchar16;
+
+// rdar://5905347
+unsigned char test8( short v ) {
+ uchar16 c;
+ return __builtin_ia32_vec_ext_v4si( c ); // expected-error {{too few arguments to function}}
+}
+
+
+// atomics.
+
+unsigned char test9(short v) {
+ unsigned i, old;
+
+ old = __sync_fetch_and_add(); // expected-error {{too few arguments to function call}}
+ old = __sync_fetch_and_add(&old); // expected-error {{too few arguments to function call}}
+ old = __sync_fetch_and_add((int**)0, 42i); // expected-warning {{imaginary constants are an extension}}
+}
diff --git a/test/Sema/c89-2.c b/test/Sema/c89-2.c
new file mode 100644
index 000000000000..723bd7c18d88
--- /dev/null
+++ b/test/Sema/c89-2.c
@@ -0,0 +1,7 @@
+/* RUN: not clang-cc %s -std=c89 -pedantic-errors
+ */
+
+/* We can't put expected-warning lines on #if lines. */
+
+#if 1LL /* expected-warning {{long long}} */
+#endif
diff --git a/test/Sema/c89.c b/test/Sema/c89.c
new file mode 100644
index 000000000000..e7585c31926c
--- /dev/null
+++ b/test/Sema/c89.c
@@ -0,0 +1,82 @@
+/* RUN: clang-cc %s -std=c89 -pedantic -fsyntax-only -verify
+ */
+void test1() {
+ {
+ int i;
+ i = i + 1;
+ int j; /* expected-warning {{mixing declarations and code}} */
+ }
+ {
+ __extension__ int i;
+ i = i + 1;
+ int j; /* expected-warning {{mixing declarations and code}} */
+ }
+ {
+ int i;
+ i = i + 1;
+ __extension__ int j; /* expected-warning {{mixing declarations and code}} */
+ }
+}
+
+long long test2; /* expected-warning {{extension}} */
+
+
+void test3(int i) {
+ int A[i]; /* expected-warning {{variable length array}} */
+}
+
+int test4 = 0LL; /* expected-warning {{long long}} */
+
+/* PR1999 */
+void test5(register);
+
+/* PR2041 */
+int *restrict;
+int *__restrict; /* expected-error {{expected identifier}} */
+
+
+/* Implicit int, always ok */
+test6() {}
+
+/* PR2012 */
+test7; /* expected-warning {{declaration specifier missing, defaulting to 'int'}} */
+
+void test8(int, x); /* expected-warning {{declaration specifier missing, defaulting to 'int'}} */
+
+typedef int sometype;
+int a(sometype, y) {return 0;} /* expected-warning {{declaration specifier missing, defaulting to 'int'}} \
+ expected-error {{parameter name omitted}}*/
+
+
+
+
+void bar (void *);
+void f11 (z) /* expected-error {{may not have 'void' type}} */
+void z;
+{ bar (&z); }
+
+typedef void T;
+void foo(T); /* typedef for void is allowed */
+
+void foo(void) {}
+
+/* PR2759 */
+void test10 (int x[*]); /* expected-warning {{use of C99-specific array features}} */
+void test11 (int x[static 4]); /* expected-warning {{use of C99-specific array features}} */
+
+void test12 (int x[const 4]) { /* expected-warning {{use of C99-specific array features}} */
+ int Y[x[1]]; /* expected-warning {{variable length arrays are a C99 feature, accepted as an extension}} */
+}
+
+/* PR4074 */
+struct test13 {
+ int X[23];
+} test13a();
+
+void test13b() {
+ int a = test13a().X[1]; /* expected-warning {{ISO C90 does not allow subscripting non-lvalue array}} */
+ int b = 1[test13a().X]; /* expected-warning {{ISO C90 does not allow subscripting non-lvalue array}} */
+}
+
+/* Make sure we allow *test14 as a "function designator" */
+int test14() { return (&*test14)(); }
diff --git a/test/Sema/callingconv.c b/test/Sema/callingconv.c
new file mode 100644
index 000000000000..cb69c59c403a
--- /dev/null
+++ b/test/Sema/callingconv.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+void __attribute__((fastcall)) foo(float *a) {
+}
+
+void __attribute__((stdcall)) bar(float *a) {
+}
+
+void __attribute__((fastcall(1))) baz(float *a) { // expected-error {{attribute requires 0 argument(s)}}
+}
diff --git a/test/Sema/carbon-pth.c b/test/Sema/carbon-pth.c
new file mode 100644
index 000000000000..c956d2a7a1c8
--- /dev/null
+++ b/test/Sema/carbon-pth.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -mcpu=pentium4 -emit-pth -o %t %s &&
+// RUN: clang-cc -mcpu=pentium4 -token-cache %t %s &&
+// RUN: clang-cc -mcpu=pentium4 -token-cache %t %s -E %s -o /dev/null
+#ifdef __APPLE__
+#include <Carbon/Carbon.h>
+#endif
+
diff --git a/test/Sema/carbon.c b/test/Sema/carbon.c
new file mode 100644
index 000000000000..5eda4385ac49
--- /dev/null
+++ b/test/Sema/carbon.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -mcpu=pentium4 %s -print-stats
+#ifdef __APPLE__
+#include <Carbon/Carbon.h>
+#endif
+
diff --git a/test/Sema/cast-to-union.c b/test/Sema/cast-to-union.c
new file mode 100644
index 000000000000..24f913b9ea33
--- /dev/null
+++ b/test/Sema/cast-to-union.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+
+union u { int i; };
+void f(union u);
+
+void test(int x) {
+ f((union u)x); // expected-warning {{C99 forbids casts to union type}}
+ f((union u)&x); // expected-error {{cast to union type from type 'int *' not present in union}}
+}
+
+union u w = (union u)2; // expected-warning {{C99 forbids casts to union type}}
+union u ww = (union u)1.0; // expected-error{{cast to union type from type 'double' not present in union}}
+union u x = 7; // expected-error{{incompatible type initializing 'int', expected 'union u'}}
+int i;
+union u zz = (union u)i; // expected-error{{initializer element is not a compile-time constant}} expected-warning {{C99 forbids casts to union type}}
+
+struct s {int a, b;};
+struct s y = { 1, 5 };
+struct s z = (struct s){ 1, 5 };
diff --git a/test/Sema/cast.c b/test/Sema/cast.c
new file mode 100644
index 000000000000..ec19626d28e0
--- /dev/null
+++ b/test/Sema/cast.c
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only %s -verify
+
+typedef struct { unsigned long bits[(((1) + (64) - 1) / (64))]; } cpumask_t;
+cpumask_t x;
+void foo() {
+ (void)x;
+}
+void bar() {
+ char* a;
+ double b;
+ b = (double)a; // expected-error {{pointer cannot be cast to type}}
+ a = (char*)b; // expected-error {{cannot be cast to a pointer type}}
+}
+
diff --git a/test/Sema/check-increment.c b/test/Sema/check-increment.c
new file mode 100644
index 000000000000..9809544854d8
--- /dev/null
+++ b/test/Sema/check-increment.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+#include <stdio.h>
+typedef int *pint;
+int main() {
+ int a[5] = {0};
+ pint p = a;
+ p++;
+ printf("%d\n", *p);
+}
diff --git a/test/Sema/compare.c b/test/Sema/compare.c
new file mode 100644
index 000000000000..4b44bf5b96a0
--- /dev/null
+++ b/test/Sema/compare.c
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+
+int test(char *C) { // nothing here should warn.
+ return C != ((void*)0);
+ return C != (void*)0;
+ return C != 0;
+}
+
+int equal(char *a, const char *b)
+{
+ return a == b;
+}
+
+int arrays(char (*a)[5], char(*b)[10], char(*c)[5]) {
+ int d = (a == c);
+ return a == b; // expected-warning {{comparison of distinct pointer types}}
+}
diff --git a/test/Sema/complex-int.c b/test/Sema/complex-int.c
new file mode 100644
index 000000000000..5977b4d1e0cb
--- /dev/null
+++ b/test/Sema/complex-int.c
@@ -0,0 +1,52 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+void a() {
+__complex__ int arr;
+__complex__ short brr;
+__complex__ unsigned xx;
+__complex__ signed yy;
+__complex__ int result;
+int ii;
+int aa = 1 + 1.0iF;
+
+result = arr*ii;
+result = ii*brr;
+
+result = arr*brr;
+result = xx*yy;
+
+switch (arr) { // expected-error{{statement requires expression of integer type ('_Complex int' invalid)}}
+ case brr: ; // expected-error{{expression is not an integer constant expression}}
+ case xx: ; // expected-error{{expression is not an integer constant expression}}
+}
+}
+
+void Tester() {
+__complex short a1;
+__complex int a2;
+__complex float a3;
+__complex double a4;
+short a5;
+int a6;
+float a7;
+double a8;
+#define TestPair(m,n) int x##m##n = a##m+a##n;
+#define TestPairs(m) TestPair(m,1) TestPair(m,2) \
+ TestPair(m,3) TestPair(m,4) \
+ TestPair(m,5) TestPair(m,6) \
+ TestPair(m,7) TestPair(m,8)
+TestPairs(1); TestPairs(2);
+TestPairs(3); TestPairs(4);
+TestPairs(5); TestPairs(6);
+TestPairs(7); TestPairs(8);
+}
+
+// rdar://6097730
+void test3(_Complex int *x) {
+ *x = ~*x;
+}
+
+void test4(_Complex float *x) {
+ *x = ~*x;
+}
+
diff --git a/test/Sema/complex-promotion.c b/test/Sema/complex-promotion.c
new file mode 100644
index 000000000000..3d86c20eb248
--- /dev/null
+++ b/test/Sema/complex-promotion.c
@@ -0,0 +1,15 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+float a;
+
+int b[__builtin_classify_type(a + 1i) == 9 ? 1 : -1];
+int c[__builtin_classify_type(1i + a) == 9 ? 1 : -1];
+
+double d;
+__typeof__ (d + 1i) e;
+
+int f[sizeof(e) == 2 * sizeof(double) ? 1 : -1];
+
+int g;
+int h[__builtin_classify_type(g + 1.0i) == 9 ? 1 : -1];
+int i[__builtin_classify_type(1.0i + a) == 9 ? 1 : -1];
diff --git a/test/Sema/compound-literal.c b/test/Sema/compound-literal.c
new file mode 100644
index 000000000000..b51bcfe2a233
--- /dev/null
+++ b/test/Sema/compound-literal.c
@@ -0,0 +1,33 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+
+struct foo { int a, b; };
+
+static struct foo t = (struct foo){0,0};
+static struct foo t2 = {0,0};
+static struct foo t3 = t2; // -expected-error {{initializer element is not a compile-time constant}}
+static int *p = (int []){2,4};
+static int x = (int){1};
+
+static int *p2 = (int []){2,x}; // -expected-error {{initializer element is not a compile-time constant}}
+static long *p3 = (long []){2,"x"}; // -expected-warning {{incompatible pointer to integer conversion initializing 'char [2]', expected 'long'}}
+
+typedef struct { } cache_t; // -expected-warning{{use of empty struct extension}}
+static cache_t clo_I1_cache = ((cache_t) { } ); // -expected-warning{{use of GNU empty initializer extension}}
+
+typedef struct Test {int a;int b;} Test;
+static Test* ll = &(Test) {0,0};
+
+extern void fooFunc(struct foo *pfoo);
+
+int main(int argc, char **argv) {
+ int *l = (int []){x, *p, *p2};
+ fooFunc(&(struct foo){ 1, 2 });
+}
+
+struct Incomplete; // expected-note{{forward declaration of 'struct Incomplete'}}
+struct Incomplete* I1 = &(struct Incomplete){1, 2, 3}; // -expected-error {{variable has incomplete type}}
+void IncompleteFunc(unsigned x) {
+ struct Incomplete* I2 = (struct foo[x]){1, 2, 3}; // -expected-error {{variable-sized object may not be initialized}}
+ (void){1,2,3}; // -expected-error {{variable has incomplete type}}
+ (void(void)) { 0 }; // -expected-error{{illegal initializer type 'void (void)'}}
+}
diff --git a/test/Sema/conditional-expr.c b/test/Sema/conditional-expr.c
new file mode 100644
index 000000000000..1f0a9deb5e47
--- /dev/null
+++ b/test/Sema/conditional-expr.c
@@ -0,0 +1,51 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+void foo() {
+ *(0 ? (double *)0 : (void *)0) = 0;
+ // FIXME: GCC doesn't consider the the following two statements to be errors.
+ *(0 ? (double *)0 : (void *)(int *)0) = 0; // expected-error {{incomplete type 'void' is not assignable}}
+ *(0 ? (double *)0 : (void *)(double *)0) = 0; // expected-error {{incomplete type 'void' is not assignable}}
+ *(0 ? (double *)0 : (int *)(void *)0) = 0; // expected-error {{incomplete type 'void' is not assignable}} expected-warning {{pointer type mismatch ('double *' and 'int *')}}
+ *(0 ? (double *)0 : (double *)(void *)0) = 0;
+ *((void *) 0) = 0; // expected-error {{incomplete type 'void' is not assignable}}
+ double *dp;
+ int *ip;
+ void *vp;
+
+ dp = vp;
+ vp = dp;
+ ip = dp; // expected-warning {{incompatible pointer types assigning 'double *', expected 'int *'}}
+ dp = ip; // expected-warning {{incompatible pointer types assigning 'int *', expected 'double *'}}
+ dp = 0 ? (double *)0 : (void *)0;
+ vp = 0 ? (double *)0 : (void *)0;
+ ip = 0 ? (double *)0 : (void *)0; // expected-warning {{incompatible pointer types assigning 'double *', expected 'int *'}}
+
+ const int *cip;
+ vp = (0 ? vp : cip); // expected-warning {{discards qualifiers}}
+ vp = (0 ? cip : vp); // expected-warning {{discards qualifiers}}
+
+ int i = 2;
+ int (*pf)[2];
+ int (*pv)[i];
+ pf = (i ? pf : pv);
+
+ enum {xxx,yyy,zzz} e, *ee;
+ short x;
+ ee = ee ? &x : ee ? &i : &e; // expected-warning {{pointer type mismatch}}
+
+ typedef void *asdf;
+ *(0 ? (asdf) 0 : &x) = 10;
+}
+
+int Postgresql() {
+ char x;
+ return ((((&x) != ((void *) 0)) ? (*(&x) = ((char) 1)) : (void) ((void *) 0)), (unsigned long) ((void *) 0)); // expected-warning {{C99 forbids conditional expressions with only one void side}}
+}
+
+#define nil ((void*) 0)
+
+extern int f1(void);
+
+int f0(int a) {
+ // GCC considers this a warning.
+ return a ? f1() : nil; // expected-warning {{pointer/integer type mismatch in conditional expression ('int' and 'void *')}} expected-warning {{incompatible pointer to integer conversion returning 'void *', expected 'int'}}
+}
diff --git a/test/Sema/conditional.c b/test/Sema/conditional.c
new file mode 100644
index 000000000000..1c7486a6133e
--- /dev/null
+++ b/test/Sema/conditional.c
@@ -0,0 +1,15 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+const char* test1 = 1 ? "i" : 1 == 1 ? "v" : "r";
+
+void _efree(void *ptr);
+
+int _php_stream_free1()
+{
+ return (1 ? free(0) : _efree(0)); // expected-error {{incompatible type returning 'void', expected 'int'}}
+}
+
+int _php_stream_free2()
+{
+ return (1 ? _efree(0) : free(0)); // expected-error {{incompatible type returning 'void', expected 'int'}}
+}
diff --git a/test/Sema/const-eval.c b/test/Sema/const-eval.c
new file mode 100644
index 000000000000..79f96b9c39bf
--- /dev/null
+++ b/test/Sema/const-eval.c
@@ -0,0 +1,67 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+#define EVAL_EXPR(testno, expr) int test##testno = sizeof(struct{char qq[expr];});
+int x;
+EVAL_EXPR(1, (_Bool)&x)
+EVAL_EXPR(2, (int)(1.0+(double)4))
+EVAL_EXPR(3, (int)(1.0+(float)4.0))
+EVAL_EXPR(4, (_Bool)(1 ? (void*)&x : 0))
+EVAL_EXPR(5, (_Bool)(int[]){0})
+struct y {int x,y;};
+EVAL_EXPR(6, (int)(1+(struct y*)0))
+EVAL_EXPR(7, (int)&((struct y*)0)->y)
+EVAL_EXPR(8, (_Bool)"asdf")
+EVAL_EXPR(9, !!&x)
+EVAL_EXPR(10, ((void)1, 12))
+void g0(void);
+EVAL_EXPR(11, (g0(), 12)) // FIXME: This should give an error
+EVAL_EXPR(12, 1.0&&2.0)
+EVAL_EXPR(13, x || 3.0)
+
+unsigned int l_19 = 1;
+EVAL_EXPR(14, (1 ^ l_19) && 1); // expected-error {{fields must have a constant size}}
+
+void f()
+{
+ int a;
+ EVAL_EXPR(15, (_Bool)&a); // expected-error {{fields must have a constant size}}
+}
+
+// FIXME: Turn into EVAL_EXPR test once we have more folding.
+_Complex float g16 = (1.0f + 1.0fi);
+
+// ?: in constant expressions.
+int g17[(3?:1) - 2];
+
+EVAL_EXPR(18, ((int)((void*)10 + 10)) == 20 ? 1 : -1);
+
+struct s {
+ int a[(int)-1.0f]; // expected-error {{array size is negative}}
+};
+
+EVAL_EXPR(19, ((int)&*(char*)10 == 10 ? 1 : -1));
+
+EVAL_EXPR(20, __builtin_constant_p(*((int*) 10), -1, 1));
+
+EVAL_EXPR(21, (__imag__ 2i) == 2 ? 1 : -1);
+
+EVAL_EXPR(22, (__real__ (2i+3)) == 3 ? 1 : -1);
+
+int g23[(int)(1.0 / 1.0)] = { 1 };
+int g24[(int)(1.0 / 1.0)] = { 1 , 2 }; // expected-warning {{excess elements in array initializer}}
+int g25[(int)(1.0 + 1.0)], g26 = sizeof(g25);
+
+EVAL_EXPR(26, (_Complex double)0 ? -1 : 1)
+EVAL_EXPR(27, (_Complex int)0 ? -1 : 1)
+EVAL_EXPR(28, (_Complex double)1 ? 1 : -1)
+EVAL_EXPR(29, (_Complex int)1 ? 1 : -1)
+
+
+// PR4027 + rdar://6808859
+struct a { int x, y };
+static struct a V2 = (struct a)(struct a){ 1, 2};
+static const struct a V1 = (struct a){ 1, 2};
+
+EVAL_EXPR(30, (int)(_Complex float)((1<<30)-1) == (1<<30) ? 1 : -1)
+EVAL_EXPR(31, (int*)0 == (int*)0 ? 1 : -1)
+EVAL_EXPR(32, (int*)0 != (int*)0 ? -1 : 1)
diff --git a/test/Sema/const-ptr-int-ptr-cast.c b/test/Sema/const-ptr-int-ptr-cast.c
new file mode 100644
index 000000000000..4e08bfff2cbb
--- /dev/null
+++ b/test/Sema/const-ptr-int-ptr-cast.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+#include <stdint.h>
+
+char *a = (void*)(uintptr_t)(void*)&a;
diff --git a/test/Sema/constant-builtins-2.c b/test/Sema/constant-builtins-2.c
new file mode 100644
index 000000000000..146d9e9bb92b
--- /dev/null
+++ b/test/Sema/constant-builtins-2.c
@@ -0,0 +1,50 @@
+// RUN: clang-cc -fsyntax-only %s
+
+// Math stuff
+
+double g0 = __builtin_huge_val();
+float g1 = __builtin_huge_valf();
+long double g2 = __builtin_huge_vall();
+
+double g3 = __builtin_inf();
+float g4 = __builtin_inff();
+long double g5 = __builtin_infl();
+
+double g6 = __builtin_nan("");
+float g7 = __builtin_nanf("");
+long double g8 = __builtin_nanl("");
+
+// GCC constant folds these too (via native strtol):
+//double g6_1 = __builtin_nan("1");
+//float g7_1 = __builtin_nanf("1");
+//long double g8_1 = __builtin_nanl("1");
+
+// APFloat doesn't have signalling NaN functions.
+//double g9 = __builtin_nans("");
+//float g10 = __builtin_nansf("");
+//long double g11 = __builtin_nansl("");
+
+//int g12 = __builtin_abs(-12);
+
+double g13 = __builtin_fabs(-12.);
+double g13_0 = __builtin_fabs(-0.);
+double g13_1 = __builtin_fabs(-__builtin_inf());
+float g14 = __builtin_fabsf(-12.f);
+// GCC doesn't eat this one.
+//long double g15 = __builtin_fabsfl(-12.0L);
+
+float g16 = __builtin_copysign(1.0, -1.0);
+double g17 = __builtin_copysignf(1.0f, -1.0f);
+long double g18 = __builtin_copysignl(1.0L, -1.0L);
+
+//double g19 = __builtin_powi(2.0, 4);
+//float g20 = __builtin_powif(2.0f, 4);
+//long double g21 = __builtin_powil(2.0L, 4);
+
+// GCC misc stuff
+
+extern int f();
+
+int h0 = __builtin_types_compatible_p(int, float);
+//int h1 = __builtin_choose_expr(1, 10, f());
+//int h2 = __builtin_expect(0, 0);
diff --git a/test/Sema/constant-builtins.c b/test/Sema/constant-builtins.c
new file mode 100644
index 000000000000..f8cea33d6762
--- /dev/null
+++ b/test/Sema/constant-builtins.c
@@ -0,0 +1,24 @@
+// RUN: clang-cc -fsyntax-only %s -verify -pedantic
+
+// Math stuff
+
+float g0 = __builtin_huge_val();
+double g1 = __builtin_huge_valf();
+long double g2 = __builtin_huge_vall();
+float g3 = __builtin_inf();
+double g4 = __builtin_inff();
+long double g5 = __builtin_infl();
+
+// GCC misc stuff
+
+extern int f();
+
+int h0 = __builtin_types_compatible_p(int,float);
+//int h1 = __builtin_choose_expr(1, 10, f());
+//int h2 = __builtin_expect(0, 0);
+
+short somefunc();
+
+short t = __builtin_constant_p(5353) ? 42 : somefunc();
+
+
diff --git a/test/Sema/constructor-attribute.c b/test/Sema/constructor-attribute.c
new file mode 100644
index 000000000000..bf876f344a8f
--- /dev/null
+++ b/test/Sema/constructor-attribute.c
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int x __attribute__((constructor)); // expected-warning {{'constructor' attribute only applies to function types}}
+int f() __attribute__((constructor));
+int f() __attribute__((constructor(1)));
+int f() __attribute__((constructor(1,2))); // expected-error {{attribute requires 0 or 1 argument(s)}}
+int f() __attribute__((constructor(1.0))); // expected-error {{'constructor' attribute requires parameter 1 to be an integer constant}}
+
+int x __attribute__((destructor)); // expected-warning {{'destructor' attribute only applies to function types}}
+int f() __attribute__((destructor));
+int f() __attribute__((destructor(1)));
+int f() __attribute__((destructor(1,2))); // expected-error {{attribute requires 0 or 1 argument(s)}}
+int f() __attribute__((destructor(1.0))); // expected-error {{'destructor' attribute requires parameter 1 to be an integer constant}}
+
+
diff --git a/test/Sema/darwin-align-cast.c b/test/Sema/darwin-align-cast.c
new file mode 100644
index 000000000000..09808b5af2e8
--- /dev/null
+++ b/test/Sema/darwin-align-cast.c
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+typedef long unsigned int __darwin_size_t;
+typedef long __darwin_ssize_t;
+typedef __darwin_size_t size_t;
+typedef __darwin_ssize_t ssize_t;
+
+struct cmsghdr {};
+
+#if 0
+This code below comes from the following system headers:
+sys/socket.h:#define CMSG_SPACE(l) (__DARWIN_ALIGN(sizeof(struct
+cmsghdr)) + __DARWIN_ALIGN(l))
+
+i386/_param.h:#define __DARWIN_ALIGN(p) ((__darwin_size_t)((char *)(p)
++ __DARWIN_ALIGNBYTES) &~ __DARWIN_ALIGNBYTES)
+#endif
+
+ssize_t sendFileDescriptor(int fd, void *data, size_t nbytes, int sendfd) {
+ union {
+ char control[(((__darwin_size_t)((char *)(sizeof(struct cmsghdr)) + (sizeof(__darwin_size_t) - 1)) &~ (sizeof(__darwin_size_t) - 1)) + ((__darwin_size_t)((char *)(sizeof(int)) + (sizeof(__darwin_size_t) - 1)) &~ (sizeof(__darwin_size_t) - 1)))];
+ } control_un;
+}
+
diff --git a/test/Sema/decl-invalid.c b/test/Sema/decl-invalid.c
new file mode 100644
index 000000000000..051f0f7ffbcc
--- /dev/null
+++ b/test/Sema/decl-invalid.c
@@ -0,0 +1,29 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+// See Sema::ParsedFreeStandingDeclSpec about the double diagnostic
+typedef union <anonymous> __mbstate_t; // expected-error {{declaration of anonymous union must be a definition}} expected-error {{declaration does not declare anything}}
+
+
+// PR2017
+void x();
+int a() {
+ int r[x()]; // expected-error {{size of array has non-integer type 'void'}}
+
+ static y ?; // expected-error{{unknown type name 'y'}} \
+ expected-error{{expected identifier or '('}} \
+ expected-error{{expected ';' at end of declaration}}
+}
+
+int; // expected-error {{declaration does not declare anything}}
+typedef int; // expected-error {{declaration does not declare anything}}
+const int; // expected-error {{declaration does not declare anything}}
+struct; // expected-error {{declaration of anonymous struct must be a definition}} // expected-error {{declaration does not declare anything}}
+typedef int I;
+I; // expected-error {{declaration does not declare anything}}
+
+
+
+// rdar://6880449
+register int test1; // expected-error {{illegal storage class on file-scoped variable}}
+register int test2 __asm__("edi"); // expected-error {{global register variables are not supported}}
+
diff --git a/test/Sema/decl-type-merging.c b/test/Sema/decl-type-merging.c
new file mode 100644
index 000000000000..1b789a142ade
--- /dev/null
+++ b/test/Sema/decl-type-merging.c
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -std=c99 -verify -pedantic %s
+
+int x[10];
+int x[] = {1,2,3};
+int testx[(sizeof(x) == sizeof(int) * 10) ? 1 : -1];
+
+int (*a)(int (*x)[10], int (*y)[]);
+int (*a)(int (*x)[], int (*y)[5]);
+int b() {
+int x[10], y[5];
+a(&x, &y);
+a(&y, &y); // expected-warning {{incompatible pointer}}
+a(&x, &x); // expected-warning {{incompatible pointer}}
+}
+
+
diff --git a/test/Sema/declspec.c b/test/Sema/declspec.c
new file mode 100644
index 000000000000..e325cc83521a
--- /dev/null
+++ b/test/Sema/declspec.c
@@ -0,0 +1,23 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+typedef char T[4];
+
+T foo(int n, int m) { } // expected-error {{cannot return array or function}}
+
+void foof(const char *, ...) __attribute__((__format__(__printf__, 1, 2))), barf (void);
+
+int typedef validTypeDecl() { } // expected-error {{function definition declared 'typedef'}}
+
+struct _zend_module_entry { }
+typedef struct _zend_function_entry { } // expected-error {{cannot combine with previous 'struct' declaration specifier}}
+static void buggy(int *x) { } // expected-error {{function definition declared 'typedef'}} \
+ // expected-error {{cannot combine with previous 'typedef' declaration specifier}} \
+ // expected-error {{cannot combine with previous 'struct' declaration specifier}}
+
+// Type qualifiers.
+typedef int f(void);
+typedef f* fptr;
+const f* v1; // expected-warning {{qualifier on function type 'f' (aka 'int (void)') has unspecified behavior}}
+__restrict__ f* v2; // expected-error {{restrict requires a pointer or reference ('f' (aka 'int (void)') is invalid)}}
+__restrict__ fptr v3; // expected-error {{pointer to function type 'f' (aka 'int (void)') may not be 'restrict' qualified}}
+f *__restrict__ v4; // expected-error {{pointer to function type 'f' (aka 'int (void)') may not be 'restrict' qualified}}
+
diff --git a/test/Sema/default.c b/test/Sema/default.c
new file mode 100644
index 000000000000..5dac99131b6b
--- /dev/null
+++ b/test/Sema/default.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f5 (int z) {
+ if (z)
+ default: // expected-error {{not in switch statement}}
+ ; // expected-warning {{if statement has empty body}}
+}
+
diff --git a/test/Sema/default1.c b/test/Sema/default1.c
new file mode 100644
index 000000000000..6e8a27bf5733
--- /dev/null
+++ b/test/Sema/default1.c
@@ -0,0 +1,2 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+void f(int i = 0); // expected-error {{C does not support default arguments}}
diff --git a/test/Sema/deref.c b/test/Sema/deref.c
new file mode 100644
index 000000000000..965940e26d5e
--- /dev/null
+++ b/test/Sema/deref.c
@@ -0,0 +1,44 @@
+/* RUN: clang-cc -fsyntax-only -verify -std=c90 -pedantic %s
+ */
+void
+foo (void)
+{
+ struct b;
+ struct b* x = 0;
+ struct b* y = &*x;
+}
+
+void foo2 (void)
+{
+ typedef int (*arrayptr)[];
+ arrayptr x = 0;
+ arrayptr y = &*x;
+}
+
+void foo3 (void)
+{
+ void* x = 0;
+ void* y = &*x; /* expected-warning{{address of an expression of type 'void'}} */
+}
+
+extern const void cv1;
+
+const void *foo4 (void)
+{
+ return &cv1;
+}
+
+extern void cv2;
+void *foo5 (void)
+{
+ return &cv2; /* expected-warning{{address of an expression of type 'void'}} */
+}
+
+typedef const void CVT;
+extern CVT cv3;
+
+const void *foo6 (void)
+{
+ return &cv3;
+}
+
diff --git a/test/Sema/designated-initializers.c b/test/Sema/designated-initializers.c
new file mode 100644
index 000000000000..ae951d42a1a6
--- /dev/null
+++ b/test/Sema/designated-initializers.c
@@ -0,0 +1,234 @@
+// RUN: clang-cc -fsyntax-only -verify -triple x86_64-unknown-unknown %s
+
+int complete_array_from_init[] = { 1, 2, [10] = 5, 1, 2, [5] = 2, 6 };
+
+int complete_array_from_init_check[((sizeof(complete_array_from_init) / sizeof(int)) == 13)? 1 : -1];
+
+int iarray[10] = {
+ [0] = 1,
+ [1 ... 5] = 2,
+ [ 6 ... 6 ] = 3,
+ [ 8 ... 7 ] = 4, // expected-error{{array designator range [8, 7] is empty}}
+ [10] = 5,
+ [-1] = 6 // expected-error{{array designator value '-1' is negative}}
+};
+
+int iarray2[10] = {
+ [10] = 1, // expected-error{{array designator index (10) exceeds array bounds (10)}}
+};
+
+int iarray3[10] = {
+ [3] 2, // expected-warning{{use of GNU 'missing =' extension in designator}}
+ [5 ... 12] = 2 // expected-error{{array designator index (12) exceeds array bounds (10)}}
+};
+
+struct point {
+ double x;
+ double y;
+};
+
+struct point p1 = {
+ .y = 1.0,
+ x: 2.0, // expected-warning{{}}
+ .a = 4.0, // expected-error{{field designator 'a' does not refer to any field in type 'struct point'}}
+};
+
+struct point p2 = {
+ [1] = 1.0 // expected-error{{array designator cannot initialize non-array type}}
+};
+
+struct point array[10] = {
+ [0].x = 1.0,
+ [1].y = 2.0,
+ [2].z = 3.0, // expected-error{{field designator 'z' does not refer to any field in type 'struct point'}}
+};
+
+struct point array2[10] = {
+ [10].x = 2.0, // expected-error{{array designator index (10) exceeds array bounds (10)}}
+ [4 ... 5].y = 2.0,
+ [4 ... 6] = { .x = 3, .y = 4.0 }
+};
+
+struct point array3[10] = {
+ .x = 5 // expected-error{{field designator cannot initialize a non-struct, non-union type}}
+};
+
+struct rect {
+ struct point top_left;
+ struct point bottom_right;
+};
+
+struct rect window = { .top_left.x = 1.0 };
+
+struct rect windows[] = {
+ [2].top_left = { 1.0, 2.0 },
+ [4].bottom_right = { .y = 1.0 },
+ { { .y = 7.0, .x = 8.0 }, { .x = 5.0 } },
+ [3] = { .top_left = { 1.1, 2.2 }, .bottom_right = { .y = 1.1 } }
+};
+
+int windows_size[((sizeof(windows) / sizeof(struct rect)) == 6)? 1 : -1];
+
+struct rect windows_bad[3] = {
+ [2].top_left = { { .x = 1.1 } }, // expected-error{{designator in initializer for scalar type}}
+ [1].top_left = { .x = 1.1 }
+};
+
+struct gui {
+ struct rect windows[10];
+};
+
+struct gui gui[] = {
+ [5].windows[3].top_left.x = { 7.0 } // expected-warning{{braces around scalar initializer}}
+};
+
+struct translator {
+ struct wonky { int * ptr; } wonky ;
+ struct rect window;
+ struct point offset;
+} tran = {
+ .window = { .top_left = { 1.0, 2.0 } },
+ { .x = 5.0, .y = 6.0 },
+ .wonky = { 0 }
+};
+
+int anint;
+struct {int x,*y;} z[] = {[0].x = 2, &z[0].x};
+
+struct outer { struct inner { int x, *y; } in, *inp; } zz[] = {
+ [0].in.x = 2, &zz[0].in.x, &zz[0].in,
+ 0, &anint, &zz[1].in,
+ [3].in = { .y = &anint, .x = 17 },
+ [7].in.y = &anint, &zz[0].in,
+ [4].in.y = &anint, [5].in.x = 12
+};
+
+int zz_sizecheck[sizeof(zz) / sizeof(struct outer) == 8? 1 : -1 ];
+
+struct disklabel_ops {
+ struct {} type;
+ int labelsize;
+};
+
+struct disklabel_ops disklabel64_ops = {
+ .labelsize = sizeof(struct disklabel_ops)
+};
+
+// PR clang/3378
+int bitwidth[] = { [(long long int)1] = 5, [(short int)2] = 2 };
+int a[]= { [sizeof(int)] = 0 };
+int a2[]= { [0 ... sizeof(int)] = 0 };
+
+// Test warnings about initializers overriding previous initializers
+struct X {
+ int a, b, c;
+};
+
+int counter = 0;
+int get8() { ++counter; return 8; }
+
+void test() {
+ struct X xs[] = {
+ [0] = (struct X){1, 2}, // expected-note{{previous initialization is here}}
+ [0].c = 3, // expected-warning{{subobject initialization overrides initialization of other fields within its enclosing subobject}}
+ (struct X) {4, 5, 6}, // expected-note{{previous initialization is here}}
+ [1].b = get8(), // expected-warning{{subobject initialization overrides initialization of other fields within its enclosing subobject}}
+ [0].b = 8
+ };
+}
+
+// FIXME: How do we test that this initializes the long properly?
+union { char c; long l; } u1 = { .l = 0xFFFF };
+
+extern float global_float;
+
+struct XX { int a, *b; };
+struct XY { int before; struct XX xx, *xp; float* after; } xy[] = {
+ 0, 0, &xy[0].xx.a, &xy[0].xx, &global_float,
+ [1].xx = 0, &xy[1].xx.a, &xy[1].xx, &global_float,
+ 0, // expected-note{{previous initialization is here}}
+ 0, // expected-note{{previous initialization is here}}
+ [2].before = 0, // expected-warning{{initializer overrides prior initialization of this subobject}}
+ 0, // expected-warning{{initializer overrides prior initialization of this subobject}}
+ &xy[2].xx.a, &xy[2].xx, &global_float
+};
+
+// PR3519
+struct foo {
+ int arr[10];
+};
+
+struct foo Y[10] = {
+ [1] .arr [1] = 2,
+ [4] .arr [2] = 4
+};
+
+struct bar {
+ struct foo f;
+ float *arr[10];
+};
+
+extern float f;
+struct bar saloon = {
+ .f.arr[3] = 1,
+ .arr = { &f }
+};
+
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+
+union wibble {
+ u_char arr1[6];
+ u_short arr2[3];
+};
+
+const union wibble wobble = { .arr2[0] = 0xffff,
+ .arr2[1] = 0xffff,
+ .arr2[2] = 0xffff };
+
+const union wibble wobble2 = { .arr2 = {4, 5, 6}, 7 }; // expected-warning{{excess elements in union initializer}}
+
+// PR3778
+struct s {
+ union { int i; };
+};
+struct s si = {
+ { .i = 1 }
+};
+
+double d0;
+char c0;
+float f0;
+int i0;
+
+struct Enigma {
+ union {
+ struct {
+ struct {
+ double *double_ptr;
+ char *string;
+ };
+ float *float_ptr;
+ };
+ int *int_ptr;
+ };
+ char *string2;
+};
+
+struct Enigma enigma = {
+ .double_ptr = &d0, &c0,
+ &f0, // expected-note{{previous}}
+ &c0,
+ .float_ptr = &f0 // expected-warning{{overrides}}
+};
+
+
+/// PR4073
+/// Should use evaluate to fold aggressively and emit a warning if not an ice.
+extern int crazy_x;
+
+int crazy_Y[] = {
+ [ 0 ? crazy_x : 4] = 1
+};
+
+
diff --git a/test/Sema/dllimport-dllexport.c b/test/Sema/dllimport-dllexport.c
new file mode 100644
index 000000000000..90ed1456d24d
--- /dev/null
+++ b/test/Sema/dllimport-dllexport.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+inline void __attribute__((dllexport)) foo1(){} // expected-warning{{dllexport attribute ignored}}
+inline void __attribute__((dllimport)) foo2(){} // expected-warning{{dllimport attribute ignored}}
+
+void __attribute__((dllimport)) foo3(){} // expected-error{{dllimport attribute can be applied only to symbol declaration}}
+
+void __attribute__((dllimport, dllexport)) foo4(); // expected-warning{{dllimport attribute ignored}}
+
+void __attribute__((dllexport)) foo5();
+void __attribute__((dllimport)) foo5(); // expected-warning{{dllimport attribute ignored}}
+
+typedef int __attribute__((dllexport)) type6; // expected-warning{{'dllexport' attribute only applies to variable and function types}}
+
+typedef int __attribute__((dllimport)) type7; // expected-warning{{'dllimport' attribute only applies to variable and function}}
+
+void __attribute__((dllimport)) foo6();
+void foo6(){} // expected-warning {{'foo6' redeclared without dllimport attribute: previous dllimport ignored}}
diff --git a/test/Sema/enum.c b/test/Sema/enum.c
new file mode 100644
index 000000000000..adb937551237
--- /dev/null
+++ b/test/Sema/enum.c
@@ -0,0 +1,86 @@
+// RUN: clang-cc %s -fsyntax-only -verify -pedantic
+enum e {A,
+ B = 42LL << 32, // expected-warning {{ISO C restricts enumerator values to range of 'int'}}
+ C = -4, D = 12456 };
+
+enum f { a = -2147483648, b = 2147483647 }; // ok.
+
+enum g { // too negative
+ c = -2147483649, // expected-warning {{ISO C restricts enumerator values to range of 'int'}}
+ d = 2147483647 };
+enum h { e = -2147483648, // too pos
+ f = 2147483648 // expected-warning {{ISO C restricts enumerator values to range of 'int'}}
+};
+
+// minll maxull
+enum x // expected-warning {{enumeration values exceed range of largest integer}}
+{ y = -9223372036854775807LL-1, // expected-warning {{ISO C restricts enumerator values to range of 'int'}}
+z = 9223372036854775808ULL }; // expected-warning {{ISO C restricts enumerator values to range of 'int'}}
+
+int test() {
+ return sizeof(enum e) ;
+}
+
+enum gccForwardEnumExtension ve; // expected-warning{{ISO C forbids forward references to 'enum' types}} \
+// expected-error{{tentative definition has type 'enum gccForwardEnumExtension' that is never completed}} \
+// expected-note{{forward declaration of 'enum gccForwardEnumExtension'}}
+
+int test2(int i)
+{
+ ve + i; // expected-error{{invalid operands to binary expression}}
+}
+
+// PR2020
+union u0; // expected-note {{previous use is here}}
+enum u0 { U0A }; // expected-error {{use of 'u0' with tag type that does not match previous declaration}}
+
+
+// rdar://6095136
+extern enum some_undefined_enum ve2; // expected-warning {{ISO C forbids forward references to 'enum' types}}
+
+void test4() {
+ for (; ve2;) // expected-error {{statement requires expression of scalar type}}
+ ;
+ (_Bool)ve2; // expected-error {{arithmetic or pointer type is required}}
+
+ for (; ;ve2)
+ ;
+ (void)ve2;
+ ve2; // expected-warning {{expression result unused}}
+}
+
+// PR2416
+enum someenum {}; // expected-warning {{use of empty enum extension}}
+
+// <rdar://problem/6093889>
+enum e0 { // expected-note {{previous definition is here}}
+ E0 = sizeof(enum e0 { E1 }), // expected-error {{nested redefinition}}
+};
+
+// PR3173
+enum { PR3173A, PR3173B = PR3173A+50 };
+
+// PR2753
+void foo() {
+ enum xpto; // expected-warning{{ISO C forbids forward references to 'enum' types}}
+ enum xpto; // expected-warning{{ISO C forbids forward references to 'enum' types}}
+}
+
+// <rdar://problem/6503878>
+typedef enum { X = 0 }; // expected-warning{{typedef requires a name}}
+
+
+enum NotYetComplete { // expected-note{{definition of 'enum NotYetComplete' is not complete until the closing '}'}}
+ NYC1 = sizeof(enum NotYetComplete) // expected-error{{invalid application of 'sizeof' to an incomplete type 'enum NotYetComplete'}}
+};
+
+/// PR3688
+struct s1 {
+ enum e1 (*bar)(void); // expected-warning{{ISO C forbids forward references to 'enum' types}}
+};
+
+enum e1 { YES, NO };
+
+static enum e1 badfunc(struct s1 *q) {
+ return q->bar();
+}
diff --git a/test/Sema/expr-address-of.c b/test/Sema/expr-address-of.c
new file mode 100644
index 000000000000..909acfb26662
--- /dev/null
+++ b/test/Sema/expr-address-of.c
@@ -0,0 +1,109 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+struct xx { int bitf:1; };
+
+struct entry { struct xx *whatever;
+ int value;
+ int bitf:1; };
+void add_one(int *p) { (*p)++; }
+
+void test() {
+ register struct entry *p;
+ add_one(&p->value);
+ struct entry pvalue;
+ add_one(&p->bitf); // expected-error {{address of bit-field requested}}
+ add_one(&pvalue.bitf); // expected-error {{address of bit-field requested}}
+ add_one(&p->whatever->bitf); // expected-error {{address of bit-field requested}}
+}
+
+void foo() {
+ register int x[10];
+ &x[10]; // expected-error {{address of register variable requested}}
+
+ register int *y;
+
+ int *x2 = &y; // expected-error {{address of register variable requested}}
+ int *x3 = &y[10];
+}
+
+void testVectorComponentAccess() {
+ typedef float v4sf __attribute__ ((vector_size (16)));
+ static v4sf q;
+ float* r = &q[0]; // expected-error {{address of vector element requested}}
+}
+
+typedef __attribute__(( ext_vector_type(4) )) float float4;
+
+float *testExtVectorComponentAccess(float4 x) {
+ return &x.w; // expected-error {{address of vector element requested}}
+}
+
+void f0() {
+ register int *x0;
+ int *_dummy0 = &(*x0);
+
+ register int *x1;
+ int *_dummy1 = &(*(x1 + 1));
+}
+
+// FIXME: The checks for this function are broken; we should error
+// on promoting a register array to a pointer! (C99 6.3.2.1p3)
+void f1() {
+ register int x0[10];
+ int *_dummy00 = x0; // fixme-error {{address of register variable requested}}
+ int *_dummy01 = &(*x0); // fixme-error {{address of register variable requested}}
+
+ register int x1[10];
+ int *_dummy1 = &(*(x1 + 1)); // fixme-error {{address of register variable requested}}
+
+ register int *x2;
+ int *_dummy2 = &(*(x2 + 1));
+
+ register int x3[10][10][10];
+ int (*_dummy3)[10] = &x3[0][0]; // expected-error {{address of register variable requested}}
+
+ register struct { int f0[10]; } x4;
+ int *_dummy4 = &x4.f0[2]; // expected-error {{address of register variable requested}}
+}
+
+void f2() {
+ register int *y;
+
+ int *_dummy0 = &y; // expected-error {{address of register variable requested}}
+ int *_dummy1 = &y[10];
+}
+
+void f3() {
+ extern void f4();
+ void (*_dummy0)() = &****f4;
+}
+
+void f4() {
+ register _Complex int x;
+
+ int *_dummy0 = &__real__ x; // expected-error {{address of register variable requested}}
+}
+
+void f5() {
+ register int arr[2];
+
+ /* This is just here because if we happened to support this as an
+ lvalue we would need to give a warning. Note that gcc warns about
+ this as a register before it warns about it as an invalid
+ lvalue. */
+ int *_dummy0 = &(int*) arr; // expected-error {{address expression must be an lvalue or a function designator}}
+ int *_dummy1 = &(arr + 1); // expected-error {{address expression must be an lvalue or a function designator}}
+}
+
+void f6(register int x) {
+ int * dummy0 = &x; // expected-error {{address of register variable requested}}
+}
+
+char* f7() {
+ register struct {char* x;} t1 = {"Hello"};
+ char* dummy1 = &(t1.x[0]);
+
+ struct {int a : 10;} t2;
+ int* dummy2 = &(t2.a); // expected-error {{address of bit-field requested}}
+
+ void* t3 = &(*(void*)0);
+}
diff --git a/test/Sema/expr-comma-c89.c b/test/Sema/expr-comma-c89.c
new file mode 100644
index 000000000000..b2b17dc33591
--- /dev/null
+++ b/test/Sema/expr-comma-c89.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc %s -fsyntax-only -verify -std=c99
+// rdar://6095180
+
+#include <assert.h>
+struct s { char c[17]; };
+extern struct s foo(void);
+
+struct s a, b, c;
+
+int A[sizeof((foo().c)) == 17 ? 1 : -1];
+int B[sizeof((a.c)) == 17 ? 1 : -1];
+
+
+// comma does array/function promotion in c99.
+int X[sizeof(0, (foo().c)) == sizeof(char*) ? 1 : -1];
+int Y[sizeof(0, (a,b).c) == sizeof(char*) ? 1 : -1];
+int Z[sizeof(0, (a=b).c) == sizeof(char*) ? 1 : -1];
+
diff --git a/test/Sema/expr-comma.c b/test/Sema/expr-comma.c
new file mode 100644
index 000000000000..64079866ca99
--- /dev/null
+++ b/test/Sema/expr-comma.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc %s -fsyntax-only -verify -std=c89
+// rdar://6095180
+
+#include <assert.h>
+struct s { char c[17]; };
+extern struct s foo(void);
+
+struct s a, b, c;
+
+int A[sizeof((foo().c)) == 17 ? 1 : -1];
+int B[sizeof((a.c)) == 17 ? 1 : -1];
+
+
+// comma does not promote array/function in c90 unless they are lvalues.
+int W[sizeof(0, a.c) == sizeof(char*) ? 1 : -1];
+int X[sizeof(0, (foo().c)) == 17 ? 1 : -1];
+int Y[sizeof(0, (a,b).c) == 17 ? 1 : -1];
+int Z[sizeof(0, (a=b).c) == 17 ? 1 : -1];
diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c
new file mode 100644
index 000000000000..3fd1437da880
--- /dev/null
+++ b/test/Sema/exprs.c
@@ -0,0 +1,108 @@
+// RUN: clang-cc %s -verify -pedantic -fsyntax-only -fblocks=0
+
+// PR1966
+_Complex double test1() {
+ return __extension__ 1.0if;
+}
+
+_Complex double test2() {
+ return 1.0if; // expected-warning {{imaginary constants are an extension}}
+}
+
+// rdar://6097308
+void test3() {
+ int x;
+ (__extension__ x) = 10;
+}
+
+// rdar://6162726
+void test4() {
+ static int var;
+ var =+ 5; // expected-warning {{use of unary operator that may be intended as compound assignment (+=)}}
+ var =- 5; // expected-warning {{use of unary operator that may be intended as compound assignment (-=)}}
+ var = +5; // no warning when space between the = and +.
+ var = -5;
+
+ var =+5; // no warning when the subexpr of the unary op has no space before it.
+ var =-5;
+
+#define FIVE 5
+ var=-FIVE; // no warning with macros.
+ var=-FIVE;
+}
+
+// rdar://6319320
+void test5(int *X, float *P) {
+ (float*)X = P; // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
+#define FOO ((float*) X)
+ FOO = P; // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
+}
+
+void test6() {
+ int X;
+ X(); // expected-error {{called object type 'int' is not a function or function pointer}}
+}
+
+void test7(int *P, _Complex float Gamma) {
+ P = (P-42) + Gamma*4; // expected-error {{invalid operands to binary expression ('int *' and '_Complex float')}}
+}
+
+
+// rdar://6095061
+int test8(void) {
+ int i;
+ __builtin_choose_expr (0, 42, i) = 10;
+ return i;
+}
+
+
+// PR3386
+struct f { int x : 4; float y[]; };
+int test9(struct f *P) {
+ int R;
+ R = __alignof(P->x); // expected-error {{invalid application of '__alignof' to bitfield}}
+ R = __alignof(P->y); // ok.
+ R = sizeof(P->x); // expected-error {{invalid application of 'sizeof' to bitfield}}
+ return R;
+}
+
+// PR3562
+void test10(int n,...) {
+ struct S {
+ double a[n]; // expected-error {{fields must have a constant size}}
+ } s;
+ double x = s.a[0]; // should not get another error here.
+}
+
+
+#define MYMAX(A,B) __extension__ ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __b : __a; })
+
+struct mystruct {int A; };
+void test11(struct mystruct P, float F) {
+ MYMAX(P, F); // expected-error {{invalid operands to binary expression ('typeof (P)' (aka 'struct mystruct') and 'typeof (F)' (aka 'float'))}}
+}
+
+// PR3753
+int test12(const char *X) {
+ return X == "foo"; // expected-warning {{comparison against a string literal is unspecified}}
+}
+
+// rdar://6719156
+void test13(
+ void (^P)()) { // expected-error {{blocks support disabled - compile with -fblocks}}
+ P();
+ P = ^(){}; // expected-error {{blocks support disabled - compile with -fblocks}}
+}
+
+
+// rdar://6326239 - Vector comparisons are not fully trusted yet, until the
+// backend is known to work, just unconditionally reject them.
+void test14() {
+ typedef long long __m64 __attribute__((__vector_size__(8)));
+ typedef short __v4hi __attribute__((__vector_size__(8)));
+
+ __v4hi a;
+ __m64 mask = (__m64)((__v4hi)a > // expected-error {{comparison of vector types ('__v4hi' and '__v4hi') not supported yet}}
+ (__v4hi)a);
+}
+
diff --git a/test/Sema/ext_vector_components.c b/test/Sema/ext_vector_components.c
new file mode 100644
index 000000000000..422a9e6f2287
--- /dev/null
+++ b/test/Sema/ext_vector_components.c
@@ -0,0 +1,37 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef __attribute__(( ext_vector_type(2) )) float float2;
+typedef __attribute__(( ext_vector_type(3) )) float float3;
+typedef __attribute__(( ext_vector_type(4) )) float float4;
+
+static void test() {
+ float2 vec2, vec2_2;
+ float3 vec3;
+ float4 vec4, vec4_2, *vec4p;
+ float f;
+
+ vec2.z; // expected-error {{vector component access exceeds type 'float2'}}
+ vec2.xyzw; // expected-error {{vector component access exceeds type 'float2'}}
+ vec4.xyzw; // expected-warning {{expression result unused}}
+ vec4.xyzc; // expected-error {{illegal vector component name 'c'}}
+ vec4.s01z; // expected-error {{illegal vector component name 'z'}}
+ vec2 = vec4.s01; // legal, shorten
+
+ vec3 = vec4.xyz; // legal, shorten
+ f = vec2.x; // legal, shorten
+ f = vec4.xy.x; // legal, shorten
+
+ vec2 = vec3.hi; // expected-error {{vector component access invalid for odd-sized type 'float3'}}
+
+ vec4_2.xyzx = vec4.xyzw; // expected-error {{vector is not assignable (contains duplicate components)}}
+ vec4_2.xyzz = vec4.xyzw; // expected-error {{vector is not assignable (contains duplicate components)}}
+ vec4_2.xyyw = vec4.xyzw; // expected-error {{vector is not assignable (contains duplicate components)}}
+ vec2.x = f;
+ vec2.xx = vec2_2.xy; // expected-error {{vector is not assignable (contains duplicate components)}}
+ vec2.yx = vec2_2.xy;
+ vec4 = (float4){ 1,2,3,4 };
+ vec4.xy.w; // expected-error {{vector component access exceeds type 'float2'}}
+ vec4.s06; // expected-error {{vector component access exceeds type 'float4'}}
+
+ vec4p->yz = vec4p->xy;
+}
diff --git a/test/Sema/flexible-array-init.c b/test/Sema/flexible-array-init.c
new file mode 100644
index 000000000000..afe31fb8294f
--- /dev/null
+++ b/test/Sema/flexible-array-init.c
@@ -0,0 +1,58 @@
+// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+struct one {
+ int a;
+ int values[]; // expected-note 3{{initialized flexible array member 'values' is here}}
+} x = {5, {1, 2, 3}}; // expected-warning{{flexible array initialization is a GNU extension}}
+
+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}}
+}
+
+struct foo {
+ int x;
+ int y[]; // expected-note 6 {{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 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}}
+
+struct foo desig_foo = { .y = {2, 3, 4} };
+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}}
+struct foo design_foo2 = { .y = 2 }; // expected-error{{flexible array requires brace-enclosed initializer}}
+
+struct point {
+ int x, y;
+};
+
+struct polygon {
+ int numpoints;
+ struct point points[]; // expected-note{{initialized flexible array member 'points' is here}}
+};
+struct polygon poly = {
+ .points[2] = { 1, 2} }; // expected-error{{designator into flexible array member subobject}}
+
+// PR3540
+struct X {
+ int a;
+ int b;
+ char data[];
+};
+
+struct Y {
+ int a:4;
+ int b:4;
+ int c;
+ int d;
+ int e;
+ struct X xs[]; // expected-warning{{'struct X' may not be used as an array element due to flexible array member}}
+};
diff --git a/test/Sema/floating-point-compare.c b/test/Sema/floating-point-compare.c
new file mode 100644
index 000000000000..763a8f4b86b4
--- /dev/null
+++ b/test/Sema/floating-point-compare.c
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -Wfloat-equal -verify %s
+
+int f1(float x, float y) {
+ return x == y; // expected-warning {{comparing floating point with ==}}
+}
+
+int f2(float x, float y) {
+ return x != y; // expected-warning {{comparing floating point with ==}}
+}
+
+int f3(float x) {
+ return x == x; // no-warning
+}
+
+int f4(float x) {
+ return x == 0.0; // no-warning {{comparing}}
+}
+
+int f5(float x) {
+ return x == __builtin_inf(); // no-warning
+}
+
+int f7(float x) {
+ return x == 3.14159; // expected-warning {{comparing}}
+}
diff --git a/test/Sema/for.c b/test/Sema/for.c
new file mode 100644
index 000000000000..183a95d0ab44
--- /dev/null
+++ b/test/Sema/for.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Check C99 6.8.5p3
+void b1 (void) { for (void (*f) (void);;); }
+void b2 (void) { for (void f (void);;); } // expected-error {{declaration of non-local variable}}
+void b3 (void) { for (static int f;;); } // expected-error {{declaration of non-local variable}}
+void b4 (void) { for (typedef int f;;); } // expected-error {{declaration of non-local variable}}
diff --git a/test/Sema/format-attribute.c b/test/Sema/format-attribute.c
new file mode 100644
index 000000000000..cb823318592e
--- /dev/null
+++ b/test/Sema/format-attribute.c
@@ -0,0 +1,34 @@
+//RUN: clang-cc -fsyntax-only -verify %s
+
+#include <stdarg.h>
+
+void a(const char *a, ...) __attribute__((format(printf, 1,2))); // no-error
+void b(const char *a, ...) __attribute__((format(printf, 1,1))); // expected-error {{'format' attribute parameter 3 is out of bounds}}
+void c(const char *a, ...) __attribute__((format(printf, 0,2))); // expected-error {{'format' attribute parameter 2 is out of bounds}}
+void d(const char *a, int c) __attribute__((format(printf, 1,2))); // expected-error {{format attribute requires variadic function}}
+void e(char *str, int c, ...) __attribute__((format(printf, 2,3))); // expected-error {{format argument not a string type}}
+
+typedef const char* xpto;
+void f(xpto c, va_list list) __attribute__((format(printf, 1, 0))); // no-error
+void g(xpto c) __attribute__((format(printf, 1, 0))); // no-error
+
+void y(char *str) __attribute__((format(strftime, 1,0))); // no-error
+void z(char *str, int c, ...) __attribute__((format(strftime, 1,2))); // expected-error {{strftime format attribute requires 3rd parameter to be 0}}
+
+int (*f_ptr)(char*,...) __attribute__((format(printf, 1,2))); // no-error
+int (*f2_ptr)(double,...) __attribute__((format(printf, 1, 2))); // expected-error {{format argument not a string type}}
+
+struct _mystruct {
+ int (*printf)(const char *format, ...) __attribute__((__format__(printf, 1, 2))); // no-error
+ int (*printf2)(double format, ...) __attribute__((__format__(printf, 1, 2))); // expected-error {{format argument not a string type}}
+};
+
+typedef int (*f3_ptr)(char*,...) __attribute__((format(printf,1,0))); // no-error
+
+// <rdar://problem/6623513>
+int rdar6623513(void *, const char*, const char*, ...)
+ __attribute__ ((format (printf, 3, 0)));
+
+int rdar6623513_aux(int len, const char* s) {
+ rdar6623513(0, "hello", "%.*s", len, s);
+}
diff --git a/test/Sema/format-string-percentm.c b/test/Sema/format-string-percentm.c
new file mode 100644
index 000000000000..f531372fd451
--- /dev/null
+++ b/test/Sema/format-string-percentm.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only -verify %s -triple i686-pc-linux-gnu
+
+int printf(char const*,...);
+void percentm(void) {
+ printf("%m");
+}
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
new file mode 100644
index 000000000000..1826c7457e30
--- /dev/null
+++ b/test/Sema/format-strings.c
@@ -0,0 +1,132 @@
+// RUN: clang-cc -fsyntax-only -verify -Wformat-nonliteral %s
+
+// Define this to get vasprintf on Linux
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdarg.h>
+
+char * global_fmt;
+
+void check_string_literal( FILE* fp, const char* s, char *buf, ... ) {
+
+ char * b;
+ va_list ap;
+ va_start(ap,buf);
+
+ printf(s); // expected-warning {{format string is not a string literal}}
+ vprintf(s,ap); // // no-warning
+ fprintf(fp,s); // expected-warning {{format string is not a string literal}}
+ vfprintf(fp,s,ap); // no-warning
+ asprintf(&b,s); // expected-warning {{format string is not a string lit}}
+ vasprintf(&b,s,ap); // no-warning
+ sprintf(buf,s); // expected-warning {{format string is not a string literal}}
+ snprintf(buf,2,s); // expected-warning {{format string is not a string lit}}
+ __builtin___sprintf_chk(buf,0,-1,s); // expected-warning {{format string is not a string literal}}
+ __builtin___snprintf_chk(buf,2,0,-1,s); // expected-warning {{format string is not a string lit}}
+ vsprintf(buf,s,ap); // no-warning
+ vsnprintf(buf,2,s,ap); // no-warning
+ vsnprintf(buf,2,global_fmt,ap); // expected-warning {{format string is not a string literal}}
+ __builtin___vsnprintf_chk(buf,2,0,-1,s,ap); // no-warning
+ __builtin___vsnprintf_chk(buf,2,0,-1,global_fmt,ap); // expected-warning {{format string is not a string literal}}
+
+ // rdar://6079877
+ printf("abc"
+ "%*d", (unsigned) 1, 1); // expected-warning {{field width should have type 'int'}}
+ printf("abc\
+def"
+ "%*d", (unsigned) 1, 1); // expected-warning {{field width should have type 'int'}}
+
+}
+
+void check_conditional_literal(const char* s, int i) {
+ printf(i == 1 ? "yes" : "no"); // no-warning
+ printf(i == 0 ? (i == 1 ? "yes" : "no") : "dont know"); // no-warning
+ printf(i == 0 ? (i == 1 ? s : "no") : "dont know"); // expected-warning{{format string is not a string literal}}
+}
+
+void check_writeback_specifier()
+{
+ int x;
+ char *b;
+
+ printf("%n",&x); // expected-warning {{'%n' in format string discouraged}}
+ sprintf(b,"%d%%%n",1, &x); // expected-warning {{'%n' in format string dis}}
+}
+
+void check_invalid_specifier(FILE* fp, char *buf)
+{
+ printf("%s%lb%d","unix",10,20); // expected-warning {{lid conversion '%lb'}}
+ fprintf(fp,"%%%l"); // expected-warning {{lid conversion '%l'}}
+ sprintf(buf,"%%%%%ld%d%d", 1, 2, 3); // no-warning
+ snprintf(buf, 2, "%%%%%ld%;%d", 1, 2, 3); // expected-warning {{sion '%;'}}
+}
+
+void check_null_char_string(char* b)
+{
+ printf("\0this is bogus%d",1); // expected-warning {{string contains '\0'}}
+ snprintf(b,10,"%%%%%d\0%d",1,2); // expected-warning {{string contains '\0'}}
+ printf("%\0d",1); // expected-warning {{string contains '\0'}}
+}
+
+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}}
+}
+
+void check_wide_string(char* b, ...)
+{
+ va_list ap;
+ va_start(ap,b);
+
+ printf(L"foo %d",2); // expected-warning {{incompatible pointer types}}, expected-warning {{should not be a wide string}}
+ vasprintf(&b,L"bar %d",ap); // expected-warning {{incompatible pointer types}}, expected-warning {{should not be a wide string}}
+}
+
+void check_asterisk_precision_width(int x) {
+ printf("%*d"); // expected-warning {{'*' specified field width is missing a matching 'int' argument}}
+ printf("%.*d"); // expected-warning {{'.*' specified field precision is missing a matching 'int' argument}}
+ printf("%*d",12,x); // no-warning
+ printf("%*d","foo",x); // expected-warning {{field width should have type 'int', but argument has type 'char *'}}
+ printf("%.*d","foo",x); // expected-warning {{field precision should have type 'int', but argument has type 'char *'}}
+}
+
+void __attribute__((format(printf,1,3))) myprintf(const char*, int blah, ...);
+
+void test_myprintf() {
+ myprintf("%d", 17, 18); // okay
+}
+
+void test_constant_bindings(void) {
+ const char * const s1 = "hello";
+ const char s2[] = "hello";
+ const char *s3 = "hello";
+ char * const s4 = "hello";
+ extern const char s5[];
+
+ printf(s1); // no-warning
+ printf(s2); // no-warning
+ printf(s3); // expected-warning{{not a string literal}}
+ printf(s4); // expected-warning{{not a string literal}}
+ printf(s5); // expected-warning{{not a string literal}}
+}
+
+
+// Test what happens when -Wformat-security only.
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#pragma GCC diagnostic warning "-Wformat-security"
+
+void test9(char *P) {
+ int x;
+ printf(P); // expected-warning {{format string is not a string literal (potentially insecure)}}
+ printf(P, 42);
+ printf("%n", &x); // expected-warning {{use of '%n' in format string discouraged }}
+}
+
+void torture(va_list v8) {
+ vprintf ("%*.*d", v8); // no-warning
+}
+
diff --git a/test/Sema/function-pointer-sentinel-attribute.c b/test/Sema/function-pointer-sentinel-attribute.c
new file mode 100644
index 000000000000..0de02fa5363c
--- /dev/null
+++ b/test/Sema/function-pointer-sentinel-attribute.c
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void (*e) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (1,1)));
+
+int main()
+{
+ void (*b) (int arg, const char * format, ...) __attribute__ ((__sentinel__)); // expected-note {{function has been explicitly marked sentinel here}}
+ void (*z) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (2))); // expected-note {{function has been explicitly marked sentinel here}}
+
+
+ void (*y) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (5))); // expected-note {{function has been explicitly marked sentinel here}}
+
+ b(1, "%s", (void*)0); // OK
+ b(1, "%s", 0); // expected-warning {{missing sentinel in function call}}
+ z(1, "%s",4 ,1,0); // expected-warning {{missing sentinel in function call}}
+ z(1, "%s", (void*)0, 1, 0); // OK
+
+ y(1, "%s", 1,2,3,4,5,6,7); // expected-warning {{missing sentinel in function call}}
+
+ y(1, "%s", (void*)0,3,4,5,6,7); // OK
+
+}
+
diff --git a/test/Sema/function-ptr.c b/test/Sema/function-ptr.c
new file mode 100644
index 000000000000..6b410018f4b7
--- /dev/null
+++ b/test/Sema/function-ptr.c
@@ -0,0 +1,11 @@
+// RUN: clang-cc %s -verify -pedantic
+typedef int unary_int_func(int arg);
+unary_int_func *func;
+
+unary_int_func *set_func(void *p) {
+ func = p; // expected-warning {{converts between void* and function pointer}}
+ p = func; // expected-warning {{converts between void* and function pointer}}
+
+ return p; // expected-warning {{converts between void* and function pointer}}
+}
+
diff --git a/test/Sema/function-redecl.c b/test/Sema/function-redecl.c
new file mode 100644
index 000000000000..28593b0678d1
--- /dev/null
+++ b/test/Sema/function-redecl.c
@@ -0,0 +1,127 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// PR3588
+void g0(int, int);
+void g0(); // expected-note{{previous declaration is here}}
+
+void f0() {
+ g0(1, 2, 3); // expected-error{{too many arguments to function call}}
+}
+
+void g0(int); // expected-error{{conflicting types for 'g0'}}
+
+int g1(int, int);
+
+typedef int INT;
+
+INT g1(x, y)
+ int x;
+ int y;
+{
+ return x + y;
+}
+
+int g2(int, int); // expected-note{{previous declaration is here}}
+
+INT g2(x) // expected-error{{conflicting types for 'g2'}}
+ int x;
+{
+ return x;
+}
+
+void test() {
+ int f1;
+ {
+ void f1(double);
+ {
+ void f1(double); // expected-note{{previous declaration is here}}
+ {
+ int f1(int); // expected-error{{conflicting types for 'f1'}}
+ }
+ }
+ }
+}
+
+extern void g3(int); // expected-note{{previous declaration is here}}
+static void g3(int x) { } // expected-error{{static declaration of 'g3' follows non-static declaration}}
+
+void test2() {
+ extern int f2; // expected-note 2 {{previous definition is here}}
+ {
+ void f2(int); // expected-error{{redefinition of 'f2' as different kind of symbol}}
+ }
+
+ {
+ int f2;
+ {
+ void f2(int); // expected-error{{redefinition of 'f2' as different kind of symbol}}
+ }
+ }
+}
+
+// <rdar://problem/6127293>
+int outer1(int); // expected-note{{previous declaration is here}}
+struct outer3 { };
+int outer4(int);
+int outer5; // expected-note{{previous definition is here}}
+int *outer7(int);
+
+void outer_test() {
+ int outer1(float); // expected-error{{conflicting types for 'outer1'}}
+ int outer2(int); // expected-note{{previous declaration is here}}
+ int outer3(int); // expected-note{{previous declaration is here}}
+ int outer4(int); // expected-note{{previous declaration is here}}
+ int outer5(int); // expected-error{{redefinition of 'outer5' as different kind of symbol}}
+ int* outer6(int); // expected-note{{previous declaration is here}}
+ int *outer7(int);
+ int outer8(int);
+
+ int *ip7 = outer7(6);
+}
+
+int outer2(float); // expected-error{{conflicting types for 'outer2'}}
+int outer3(float); // expected-error{{conflicting types for 'outer3'}}
+int outer4(float); // expected-error{{conflicting types for 'outer4'}}
+
+void outer_test2(int x) {
+ int* ip = outer6(x); // expected-warning{{use of out-of-scope declaration of 'outer6'}}
+ int *ip2 = outer7(x);
+}
+
+void outer_test3() {
+ int *(*fp)(int) = outer8; // expected-error{{use of undeclared identifier 'outer8'}}
+}
+
+static float outer8(float); // okay
+
+enum e { e1, e2 };
+
+// GNU extension: prototypes and K&R function definitions
+int isroot(short x, // expected-note{{previous declaration is here}}
+ enum e);
+
+int isroot(x, y)
+ short x; // expected-warning{{promoted type 'int' of K&R function parameter is not compatible with the parameter type 'short' declared in a previous prototype}}
+ unsigned int y;
+{
+ return x == 1;
+}
+
+// PR3817
+void *h0(unsigned a0, ...);
+extern __typeof (h0) h1 __attribute__((__sentinel__));
+extern __typeof (h1) h1 __attribute__((__sentinel__));
+
+// PR3840
+void i0 (unsigned short a0);
+extern __typeof (i0) i1;
+extern __typeof (i1) i1;
+
+typedef int a();
+typedef int a2(int*);
+a x;
+a2 x2;
+void test_x() {
+ x(5);
+ x2(5); // expected-warning{{incompatible integer to pointer conversion passing 'int', expected 'int *'}}
+}
diff --git a/test/Sema/function-sentinel-attr.c b/test/Sema/function-sentinel-attr.c
new file mode 100644
index 000000000000..66304796127f
--- /dev/null
+++ b/test/Sema/function-sentinel-attr.c
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+#define NULL (void*)0
+
+#define ATTR __attribute__ ((__sentinel__))
+
+void foo1 (int x, ...) ATTR; // expected-note {{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}}
+
+int main ()
+{
+
+ foo1(1, NULL); // OK
+ foo1(1, 0) ; // expected-warning {{missing sentinel in function call}}
+ foo5(1, NULL, 2); // OK
+ foo5(1,2,NULL, 1); // OK
+ foo5(1, NULL, 2, 1); // expected-warning {{missing sentinel in function call}}
+
+ foo6(1,2,3,4,5,6,7); // expected-warning {{missing sentinel in function call}}
+ foo6(1,NULL,3,4,5,6,7); // OK
+ foo7(1); // expected-warning {{not enough variable arguments in 'foo7' declaration to fit a sentinel}}
+ foo7(1, NULL); // OK
+
+ foo12(1); // expected-warning {{not enough variable arguments in 'foo12' declaration to fit a sentinel}}
+}
+
diff --git a/test/Sema/function.c b/test/Sema/function.c
new file mode 100644
index 000000000000..c9d8630c47f6
--- /dev/null
+++ b/test/Sema/function.c
@@ -0,0 +1,89 @@
+// RUN: clang-cc %s -fsyntax-only -verify -pedantic
+// PR1892
+void f(double a[restrict][5]); // should promote to restrict ptr.
+void f(double (* restrict a)[5]);
+
+int foo (__const char *__path);
+int foo(__const char *__restrict __file);
+
+void func(const char*); // expected-note {{previous declaration is here}}
+void func(char*); // expected-error{{conflicting types for 'func'}}
+
+void g(int (*)(const void **, const void **));
+void g(int (*compar)()) {
+}
+
+void h(); // expected-note {{previous declaration is here}}
+void h (const char *fmt, ...) {} // expected-error{{conflicting types for 'h'}}
+
+// PR1965
+int t5(b); // expected-error {{parameter list without types}}
+int t6(int x, g); // expected-warning {{type specifier missing, defaults to 'int'}}
+
+int t7(, ); // expected-error {{expected parameter declarator}} expected-error {{expected parameter declarator}}
+int t8(, int a); // expected-error {{expected parameter declarator}}
+int t9(int a, ); // expected-error {{expected parameter declarator}}
+
+
+// PR2042
+void t10(){}
+void t11(){t10(1);} // expected-warning{{too many arguments}}
+
+// PR3208
+void t12(int) {} // expected-error{{parameter name omitted}}
+
+// PR2790
+void t13() {
+ return 0; // expected-warning {{void function 't13' should not return a value}}
+}
+int t14() {
+ return; // expected-warning {{non-void function 't14' should return a value}}
+}
+
+// <rdar://problem/6097326>
+y(y) { return y; } // expected-warning{{parameter 'y' was not declared, defaulting to type 'int'}} \
+ // expected-warning{{type specifier missing, defaults to 'int'}}
+
+
+// PR3137, <rdar://problem/6127293>
+extern int g0_3137(void);
+void f0_3137() {
+ int g0_3137(void);
+}
+void f1_3137() {
+ int (*fp)(void) = g0_3137;
+}
+
+void f1static() {
+ static void f2static(int); // expected-error{{function declared in block scope cannot have 'static' storage class}}
+ register void f2register(int); // expected-error{{illegal storage class on function}}
+}
+
+struct incomplete_test a(void) {} // expected-error{{incomplete result type 'struct incomplete_test' in function definition}} \
+ // expected-note{{forward declaration of 'struct incomplete_test'}}
+
+
+extern __inline
+__attribute__((__gnu_inline__))
+void gnu_inline1() {}
+
+void
+__attribute__((__gnu_inline__)) // expected-warning {{'gnu_inline' attribute requires function to be marked 'inline', attribute ignored}}
+gnu_inline2() {}
+
+
+// rdar://6802350
+inline foo_t invalid_type() { // expected-error {{unknown type name 'foo_t'}}
+}
+
+typedef void fn_t(void);
+fn_t t17;
+
+// PR4049
+unknown_type t18(void*) { // expected-error {{unknown type name 'unknown_type'}} expected-error{{parameter name omitted}}
+}
+
+unknown_type t19(int* P) { // expected-error {{unknown type name 'unknown_type'}}
+ P = P+1; // no warning.
+}
+
diff --git a/test/Sema/gnu89.c b/test/Sema/gnu89.c
new file mode 100644
index 000000000000..4601cbe93f6e
--- /dev/null
+++ b/test/Sema/gnu89.c
@@ -0,0 +1,3 @@
+// RUN: clang-cc %s -std=gnu89 -pedantic -fsyntax-only -verify
+
+int f(int restrict);
diff --git a/test/Sema/heinous-extensions-off.c b/test/Sema/heinous-extensions-off.c
new file mode 100644
index 000000000000..3a9880ce7f75
--- /dev/null
+++ b/test/Sema/heinous-extensions-off.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc %s -verify
+
+int foo() {
+ int a;
+ // PR3788
+ asm("nop" : : "m"((int)(a))); // expected-error {{cast in a inline asm context requiring an l-value}}
+ // PR3794
+ asm("nop" : "=r"((unsigned)a)); // expected-error {{cast in a inline asm context requiring an l-value}}
+}
+
diff --git a/test/Sema/heinous-extensions-on.c b/test/Sema/heinous-extensions-on.c
new file mode 100644
index 000000000000..480b1b41e906
--- /dev/null
+++ b/test/Sema/heinous-extensions-on.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc %s -verify -fheinous-gnu-extensions
+
+int foo() {
+ int a;
+ // PR3788
+ asm("nop" : : "m"((int)(a))); // expected-warning {{cast in a inline asm context requiring an l-value}}
+ // PR3794
+ asm("nop" : "=r"((unsigned)a)); // expected-warning {{cast in a inline asm context requiring an l-value}}
+}
+
diff --git a/test/Sema/i-c-e.c b/test/Sema/i-c-e.c
new file mode 100644
index 000000000000..de279669922b
--- /dev/null
+++ b/test/Sema/i-c-e.c
@@ -0,0 +1,66 @@
+// RUN: clang-cc %s -fsyntax-only -verify -pedantic -fpascal-strings
+
+#include <stdint.h>
+#include <limits.h>
+
+int a() {int p; *(1 ? &p : (void*)(0 && (a(),1))) = 10;} // expected-error {{incomplete type 'void' is not assignable}}
+
+// rdar://6091492 - ?: with __builtin_constant_p as the operand is an i-c-e.
+int expr;
+char w[__builtin_constant_p(expr) ? expr : 1];
+
+
+// __builtin_constant_p as the condition of ?: allows arbitrary foldable
+// constants to be transmogrified into i-c-e's.
+char b[__builtin_constant_p((int)(1.0+2.0)) ? (int)(1.0+2.0) : -1];
+
+struct c {
+ int a : ( // expected-error {{expression is not an integer constant expression}}
+ __builtin_constant_p((int)(1.0+2.0)) ? (int)(1.0+
+ expr // expected-note {{subexpression not valid in an integer constant expression}}
+ ) : -1);
+};
+
+
+
+
+void test1(int n, int* p) { *(n ? p : (void *)(7-7)) = 1; }
+void test2(int n, int* p) { *(n ? p : (void *)0) = 1; }
+
+
+
+char array[1024/(sizeof (long))];
+
+int x['\xBb' == (char) 187 ? 1: -1];
+
+// PR1992
+void func(int x)
+{
+ switch (x) {
+ case sizeof("abc"): break;
+ case sizeof("loooong"): func(4);
+ case sizeof("\ploooong"): func(4);
+ }
+}
+
+
+// rdar://4213768
+int expr;
+char y[__builtin_constant_p(expr) ? -1 : 1];
+char z[__builtin_constant_p(4) ? 1 : -1];
+
+// Comma tests
+int comma1[0?1,2:3];
+int comma2[1||(1,2)];
+int comma3[(1,2)]; // expected-warning {{size of static array must be an integer constant expression}}
+
+// Pointer + __builtin_constant_p
+char pbcp[__builtin_constant_p(4) ? (intptr_t)&expr : 0]; // expected-error {{variable length array declaration not allowed at file scope}}
+
+int illegaldiv1[1 || 1/0];
+int illegaldiv2[1/0]; // expected-error {{variable length array declaration not allowed at file scope}}
+int illegaldiv3[INT_MIN / -1]; // expected-error {{variable length array declaration not allowed at file scope}}
+
+int chooseexpr[__builtin_choose_expr(1, 1, expr)];
+int realop[(__real__ 4) == 4 ? 1 : -1];
+int imagop[(__imag__ 4) == 0 ? 1 : -1];
diff --git a/test/Sema/if-empty-body.c b/test/Sema/if-empty-body.c
new file mode 100644
index 000000000000..1d1df40bd6a3
--- /dev/null
+++ b/test/Sema/if-empty-body.c
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f1(int a) {
+ if (a); // expected-warning {{if statement has empty body}}
+}
+
+void f2(int a) {
+ if (a) {}
+}
+
+void f3() {
+ if (1)
+ xx; // expected-error {{use of undeclared identifier}}
+ return; // no empty body warning.
+}
+
diff --git a/test/Sema/illegal-types.c b/test/Sema/illegal-types.c
new file mode 100644
index 000000000000..c932bb28dcca
--- /dev/null
+++ b/test/Sema/illegal-types.c
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++98 %s
+
+void a (void []()); // expected-error{{'type name' declared as array of functions}}
+void b (void p[]()); // expected-error{{'p' declared as array of functions}}
+void c (int &[]); // expected-error{{'type name' declared as array of references}}
+void d (int &p[]); // expected-error{{'p' declared as array of references}}
+
diff --git a/test/Sema/implicit-builtin-decl.c b/test/Sema/implicit-builtin-decl.c
new file mode 100644
index 000000000000..696a2b926c9b
--- /dev/null
+++ b/test/Sema/implicit-builtin-decl.c
@@ -0,0 +1,53 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+void f() {
+ int *ptr = malloc(sizeof(int) * 10); // expected-warning{{implicitly declaring C library function 'malloc' with type}} \
+ // expected-note{{please include the header <stdlib.h> or explicitly provide a declaration for 'malloc'}} \
+ // expected-note{{'malloc' is a builtin with type 'void *}}
+}
+
+void *alloca(__SIZE_TYPE__); // redeclaration okay
+
+int *calloc(__SIZE_TYPE__, __SIZE_TYPE__); // expected-warning{{incompatible redeclaration of library function 'calloc'}} \
+ // expected-note{{'calloc' is a builtin with type 'void *}}
+
+
+void g(int malloc) { // okay: these aren't functions
+ int calloc = 1;
+}
+
+void h() {
+ int malloc(int); // expected-warning{{incompatible redeclaration of library function 'malloc'}}
+ int strcpy(int); // expected-warning{{incompatible redeclaration of library function 'strcpy'}} \
+ // expected-note{{'strcpy' is a builtin with type 'char *(char *, char const *)'}}
+}
+
+void f2() {
+ fprintf(0, "foo"); // expected-error{{implicit declaration of 'fprintf' requires inclusion of the header <stdio.h>}}
+}
+
+// PR2892
+void __builtin_object_size(); // expected-error{{conflicting types}} \
+// expected-note{{'__builtin_object_size' is a builtin with type}}
+
+int a[10];
+
+int f0() {
+ return __builtin_object_size(&a); // expected-error {{too few arguments to function}}
+}
+
+void * realloc(void *p, int size) { // expected-warning{{incompatible redeclaration of library function 'realloc'}} \
+// expected-note{{'realloc' is a builtin with type 'void *(void *,}}
+ return p;
+}
+
+// PR3855
+void snprintf(); // expected-warning{{incompatible redeclaration of library function 'snprintf'}} \
+ // expected-note{{'snprintf' is a builtin}}
+
+int
+main(int argc, char *argv[])
+{
+ snprintf();
+}
+
+void snprintf() { }
diff --git a/test/Sema/implicit-builtin-freestanding.c b/test/Sema/implicit-builtin-freestanding.c
new file mode 100644
index 000000000000..9bd5c05892ec
--- /dev/null
+++ b/test/Sema/implicit-builtin-freestanding.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only -verify -ffreestanding %s
+
+int malloc(int a) { return a; }
+
diff --git a/test/Sema/implicit-builtin-redecl.c b/test/Sema/implicit-builtin-redecl.c
new file mode 100644
index 000000000000..cd99b5455318
--- /dev/null
+++ b/test/Sema/implicit-builtin-redecl.c
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// PR3592
+static void* malloc(int);
+static void* malloc(int size) {
+ return ((void*)0); /*do not use heap in this file*/
+}
+
+void *calloc(int, int, int); // expected-warning{{incompatible redeclaration of library function 'calloc' will be ignored}} \
+// expected-note{{'calloc' is a builtin with type 'void *}}
+
+void f1(void) {
+ calloc(0, 0, 0);
+}
diff --git a/test/Sema/implicit-cast.c b/test/Sema/implicit-cast.c
new file mode 100644
index 000000000000..ce34ad6d1c65
--- /dev/null
+++ b/test/Sema/implicit-cast.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only %s
+
+static char *test1(int cf) {
+ return cf ? "abc" : 0;
+}
+static char *test2(int cf) {
+ return cf ? 0 : "abc";
+}
diff --git a/test/Sema/implicit-decl.c b/test/Sema/implicit-decl.c
new file mode 100644
index 000000000000..8873e76098ca
--- /dev/null
+++ b/test/Sema/implicit-decl.c
@@ -0,0 +1,17 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+typedef int int32_t;
+typedef unsigned char Boolean;
+
+void func() {
+ int32_t *vector[16];
+ const char compDesc[16 + 1];
+ int32_t compCount = 0;
+ if (_CFCalendarDecomposeAbsoluteTimeV(compDesc, vector, compCount)) { // expected-note {{previous implicit declaration is here}}
+ }
+ return ((void *)0); // expected-warning {{void function 'func' should not return a value}}
+}
+Boolean _CFCalendarDecomposeAbsoluteTimeV(const char *componentDesc, int32_t **vector, int32_t count) { // expected-error{{conflicting types for '_CFCalendarDecomposeAbsoluteTimeV'}}
+ return 0;
+}
+
diff --git a/test/Sema/implicit-def.c b/test/Sema/implicit-def.c
new file mode 100644
index 000000000000..2c2594680a11
--- /dev/null
+++ b/test/Sema/implicit-def.c
@@ -0,0 +1,8 @@
+/* RUN: clang-cc -fsyntax-only %s -std=c89 &&
+ * RUN: not clang-cc -fsyntax-only %s -std=c99 -pedantic-errors
+ */
+
+int A() {
+ return X();
+}
+
diff --git a/test/Sema/implicit-int.c b/test/Sema/implicit-int.c
new file mode 100644
index 000000000000..04b27a8f0ea9
--- /dev/null
+++ b/test/Sema/implicit-int.c
@@ -0,0 +1,31 @@
+// RUN: clang-cc -fsyntax-only %s -verify -pedantic
+
+foo() { // expected-warning {{type specifier missing, defaults to 'int'}}
+}
+
+y; // expected-warning {{type specifier missing, defaults to 'int'}}
+
+// rdar://6131634
+void f((x)); // expected-warning {{type specifier missing, defaults to 'int'}}
+
+
+// PR3702
+#define PAD(ms10) { \
+ register i; \
+}
+
+#define ILPAD() PAD((NROW - tt.tt_row) * 10) /* 1 ms per char */
+
+void
+h19_insline(n) // expected-warning {{parameter 'n' was not declared, defaulting to type 'int'}}
+{
+ ILPAD(); // expected-warning {{type specifier missing, defaults to 'int'}}
+}
+
+struct foo {
+ __extension__ __attribute__((packed)) x : 4; // expected-warning {{type specifier missing, defaults to 'int'}}
+};
+
+
+
+
diff --git a/test/Sema/incompatible-sign.c b/test/Sema/incompatible-sign.c
new file mode 100644
index 000000000000..a62f9a8ba709
--- /dev/null
+++ b/test/Sema/incompatible-sign.c
@@ -0,0 +1,5 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+int a(int* x);
+int b(unsigned* y) { return a(y); } // expected-warning {{pointer types point to integer types with different sign}}
+
diff --git a/test/Sema/incomplete-call.c b/test/Sema/incomplete-call.c
new file mode 100644
index 000000000000..aedfe50bbfdd
--- /dev/null
+++ b/test/Sema/incomplete-call.c
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct foo; // expected-note 3 {{forward declaration of 'struct foo'}}
+
+struct foo a();
+void b(struct foo);
+void c();
+
+void func() {
+ a(); // expected-error{{return type of called function ('struct foo') is incomplete}}
+ b(*(struct foo*)0); // expected-error{{argument type 'struct foo' is incomplete}}
+ c(*(struct foo*)0); // expected-error{{argument type 'struct foo' is incomplete}}
+}
diff --git a/test/Sema/incomplete-decl.c b/test/Sema/incomplete-decl.c
new file mode 100644
index 000000000000..eb93e8e38031
--- /dev/null
+++ b/test/Sema/incomplete-decl.c
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct foo; // expected-note 4 {{forward declaration of 'struct foo'}}
+
+void b; // expected-error {{variable has incomplete type 'void'}}
+struct foo f; // expected-error{{tentative definition has type 'struct foo' that is never completed}}
+
+static void c; // expected-error {{variable has incomplete type 'void'}}
+static struct foo g; // expected-error {{variable has incomplete type 'struct foo'}}
+
+extern void d;
+extern struct foo e;
+
+int ary[]; // expected-warning {{tentative array definition assumed to have one element}}
+struct foo bary[]; // expected-error {{array has incomplete element type 'struct foo'}}
+
+void func() {
+ int ary[]; // expected-error{{variable has incomplete type 'int []'}}
+ void b; // expected-error {{variable has incomplete type 'void'}}
+ struct foo f; // expected-error {{variable has incomplete type 'struct foo'}}
+}
+
+int h[]; // expected-warning {{tentative array definition assumed to have one element}}
+int (*i)[] = &h+1; // expected-error {{arithmetic on pointer to incomplete type 'int (*)[]'}}
+
+struct bar j = {1}; // expected-error {{variable has incomplete type 'struct bar'}} \
+ expected-note {{forward declaration of 'struct bar'}}
+struct bar k;
+struct bar { int a; };
+
diff --git a/test/Sema/indirect-goto.c b/test/Sema/indirect-goto.c
new file mode 100644
index 000000000000..35fb5e6315e2
--- /dev/null
+++ b/test/Sema/indirect-goto.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct c {int x;};
+int a(struct c x, long long y) {
+ goto *x; // expected-error{{incompatible type}}
+ goto *y; // expected-warning{{incompatible integer to pointer conversion}}
+}
+
diff --git a/test/Sema/init-struct-qualified.c b/test/Sema/init-struct-qualified.c
new file mode 100644
index 000000000000..539820ae418c
--- /dev/null
+++ b/test/Sema/init-struct-qualified.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify < %s
+typedef float CGFloat;
+typedef struct _NSPoint { CGFloat x; CGFloat y; } NSPoint;
+typedef struct _NSSize { CGFloat width; CGFloat height; } NSSize;
+typedef struct _NSRect { NSPoint origin; NSSize size; } NSRect;
+
+extern const NSPoint NSZeroPoint;
+
+extern NSSize canvasSize();
+void func() {
+ const NSRect canvasRect = { NSZeroPoint, canvasSize() };
+}
diff --git a/test/Sema/init.c b/test/Sema/init.c
new file mode 100644
index 000000000000..1cbcbb7e36f8
--- /dev/null
+++ b/test/Sema/init.c
@@ -0,0 +1,128 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef void (* fp)(void);
+void foo(void);
+
+// PR clang/3377
+fp a[(short int)1] = { foo };
+
+int myArray[5] = {1, 2, 3, 4, 5};
+int *myPointer2 = myArray;
+int *myPointer = &(myArray[2]);
+
+
+extern int x;
+void *g = &x;
+int *h = &x;
+
+int test() {
+int a[10];
+int b[10] = a; // expected-error {{initialization with '{...}' expected}}
+int +; // expected-error {{expected identifier or '('}} expected-error {{expected ';' at end of declaration}}
+}
+
+
+// PR2050
+struct cdiff_cmd {
+ const char *name;
+ unsigned short argc;
+ int (*handler)();
+};
+int cdiff_cmd_open();
+struct cdiff_cmd commands[] = {
+ {"OPEN", 1, &cdiff_cmd_open }
+};
+
+// PR2348
+static struct { int z; } s[2];
+int *t = &(*s).z;
+
+// PR2349
+short *a2(void)
+{
+ short int b;
+ static short *bp = &b; // expected-error {{initializer element is not a compile-time constant}}
+
+ return bp;
+}
+
+int pbool(void) {
+ typedef const _Bool cbool;
+ _Bool pbool1 = (void *) 0;
+ cbool pbool2 = &pbool;
+ return pbool2;
+}
+
+
+// rdar://5870981
+union { float f; unsigned u; } u = { 1.0f };
+
+// rdar://6156694
+int f3(int x) { return x; }
+typedef void (*vfunc)(void);
+void *bar = (vfunc) f3;
+
+// PR2747
+struct sym_reg {
+ char nc_gpreg;
+};
+int sym_fw1a_scr[] = {
+ ((int)(&((struct sym_reg *)0)->nc_gpreg)) & 0,
+ 8 * ((int)(&((struct sym_reg *)0)->nc_gpreg))
+};
+
+// PR3001
+struct s1 s2 = {
+ .a = sizeof(struct s3), // expected-error {{invalid application of 'sizeof'}} \
+ // expected-note{{forward declaration of 'struct s3'}}
+ .b = bogus // expected-error {{use of undeclared identifier 'bogus'}}
+}
+
+// PR3382
+char t[] = ("Hello");
+
+// <rdar://problem/6094855>
+typedef struct { } empty;
+
+typedef struct {
+ empty e;
+ int i2;
+} st;
+
+st st1 = { .i2 = 1 };
+
+// <rdar://problem/6096826>
+struct {
+ int a;
+ int z[2];
+} y = { .z = {} };
+
+int bbb[10];
+
+struct foo2 {
+ uintptr_t a;
+};
+
+struct foo2 bar2[] = {
+ { (intptr_t)bbb }
+};
+
+struct foo2 bar3 = { 1, 2 }; // expected-warning{{excess elements in struct initializer}}
+
+int* ptest1 = __builtin_choose_expr(1, (int*)0, (int*)0);
+
+typedef int32_t ivector4 __attribute((vector_size(16)));
+ivector4 vtest1 = 1 ? (ivector4){1} : (ivector4){1};
+ivector4 vtest2 = __builtin_choose_expr(1, (ivector4){1}, (ivector4){1});
+ivector4 vtest3 = __real__ (ivector4){1};
+ivector4 vtest4 = __imag__ (ivector4){1};
+
+uintptr_t ptrasintadd1 = (uintptr_t)&a - 4;
+uintptr_t ptrasintadd2 = (uintptr_t)&a + 4;
+uintptr_t ptrasintadd3 = 4 + (uintptr_t)&a;
+
+// PR4285
+const wchar_t widestr[] = L"asdf";
diff --git a/test/Sema/inline.c b/test/Sema/inline.c
new file mode 100644
index 000000000000..adcde51363eb
--- /dev/null
+++ b/test/Sema/inline.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Check that we don't allow illegal uses of inline
+inline int a; // expected-error{{'inline' can only appear on functions}}
+typedef inline int b; // expected-error{{'inline' can only appear on functions}}
+int d(inline int a); // expected-error{{'inline' can only appear on functions}}
diff --git a/test/Sema/int-arith-convert.c b/test/Sema/int-arith-convert.c
new file mode 100644
index 000000000000..5bbab7d9af96
--- /dev/null
+++ b/test/Sema/int-arith-convert.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -triple=i686-linux-gnu -fsyntax-only -verify %s
+
+// Check types are the same through redeclaration
+unsigned long x;
+__typeof(1u+1l) x;
+
+unsigned y;
+__typeof(1+1u) y;
+__typeof(1u+1) y;
+
+long long z;
+__typeof(1ll+1u) z;
diff --git a/test/Sema/invalid-decl.c b/test/Sema/invalid-decl.c
new file mode 100644
index 000000000000..8c458008cb5c
--- /dev/null
+++ b/test/Sema/invalid-decl.c
@@ -0,0 +1,22 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+void test() {
+ char = 4; // expected-error {{expected identifier}}
+}
+
+
+// PR2400
+typedef xtype (*x)(void* handle); // expected-error {{function cannot return array or function type}} expected-warning {{type specifier missing, defaults to 'int'}} expected-warning {{type specifier missing, defaults to 'int'}}
+
+typedef void ytype();
+
+
+typedef struct _zend_module_entry zend_module_entry;
+struct _zend_module_entry {
+ ytype globals_size; // expected-error {{field 'globals_size' declared as a function}}
+};
+
+zend_module_entry openssl_module_entry = {
+ sizeof(zend_module_entry)
+};
+
diff --git a/test/Sema/invalid-init-diag.c b/test/Sema/invalid-init-diag.c
new file mode 100644
index 000000000000..724d0ea368ba
--- /dev/null
+++ b/test/Sema/invalid-init-diag.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+int a;
+struct {int x;} x = a; // expected-error {{incompatible type initializing 'int', expected 'struct <anonymous>'}}
diff --git a/test/Sema/invalid-struct-init.c b/test/Sema/invalid-struct-init.c
new file mode 100644
index 000000000000..73e2e446f131
--- /dev/null
+++ b/test/Sema/invalid-struct-init.c
@@ -0,0 +1,29 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+typedef struct _zend_module_entry zend_module_entry;
+struct _zend_module_entry {
+ _efree((p)); // expected-error{{type name requires a specifier or qualifier}} \
+ expected-error{{field '_efree' declared as a function}} \
+ expected-warning {{type specifier missing, defaults to 'int'}} \
+ expected-warning {{type specifier missing, defaults to 'int'}}
+
+};
+typedef struct _zend_function_entry { } zend_function_entry;
+typedef struct _zend_pcre_globals { } zend_pcre_globals;
+zend_pcre_globals pcre_globals;
+
+static void zm_globals_ctor_pcre(zend_pcre_globals *pcre_globals ) { }
+static void zm_globals_dtor_pcre(zend_pcre_globals *pcre_globals ) { }
+static void zm_info_pcre(zend_module_entry *zend_module ) { }
+static int zm_startup_pcre(int type, int module_number ) { }
+
+static int zm_shutdown_pcre(int type, int module_number ) {
+ zend_function_entry pcre_functions[] = {{ }; // expected-error{{expected '}'}} expected-note {{to match this '{'}}
+ zend_module_entry pcre_module_entry = {
+ sizeof(zend_module_entry), 20071006, 0, 0, ((void *)0), ((void *)0),
+ "pcre", pcre_functions, zm_startup_pcre, zm_shutdown_pcre, ((void *)0),
+ ((void *)0), zm_info_pcre, ((void *)0), sizeof(zend_pcre_globals), &pcre_globals,
+ ((void (*)(void* ))(zm_globals_ctor_pcre)), ((void (*)(void* ))(zm_globals_dtor_pcre)),
+ ((void *)0), 0, 0, ((void *)0), 0
+ };
+}
diff --git a/test/Sema/knr-def-call.c b/test/Sema/knr-def-call.c
new file mode 100644
index 000000000000..6b033fc3a21f
--- /dev/null
+++ b/test/Sema/knr-def-call.c
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// C DR #316, PR 3626.
+void f0(a, b, c, d) int a,b,c,d; {}
+void t0(void) {
+ f0(1); // expected-warning{{too few arguments}}
+}
+
+void f1(a, b) int a, b; {}
+void t1(void) {
+ f1(1, 2, 3); // expected-warning{{too many arguments}}
+}
+
+void f2(float); // expected-note{{previous declaration is here}}
+void f2(x) float x; { } // expected-warning{{promoted type 'double' of K&R function parameter is not compatible with the parameter type 'float' declared in a previous prototype}}
+
+typedef void (*f3)(void);
+f3 t3(int b) { return b? f0 : f1; } // okay
diff --git a/test/Sema/knr-variadic-def.c b/test/Sema/knr-variadic-def.c
new file mode 100644
index 000000000000..070ba071ca67
--- /dev/null
+++ b/test/Sema/knr-variadic-def.c
@@ -0,0 +1,29 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+// PR4287
+
+#include <stdarg.h>
+char *foo = "test";
+int test(char*,...);
+
+int test(fmt)
+ char*fmt;
+{
+ va_list ap;
+ char*a;
+ int x;
+
+ va_start(ap,fmt);
+ a=va_arg(ap,char*);
+ x=(a!=foo);
+ va_end(ap);
+ return x;
+}
+
+void exit();
+
+int main(argc,argv)
+ int argc;char**argv;
+{
+ exit(test("",foo));
+}
+
diff --git a/test/Sema/member-reference.c b/test/Sema/member-reference.c
new file mode 100644
index 000000000000..b810ccf15b72
--- /dev/null
+++ b/test/Sema/member-reference.c
@@ -0,0 +1,20 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+struct simple { int i; };
+
+void f(void) {
+ struct simple s[1];
+ s->i = 1;
+}
+
+typedef int x;
+struct S {
+ int x;
+ x z;
+};
+
+void g(void) {
+ struct S s[1];
+ s->x = 1;
+ s->z = 2;
+}
diff --git a/test/Sema/merge-decls.c b/test/Sema/merge-decls.c
new file mode 100644
index 000000000000..f4c25f511429
--- /dev/null
+++ b/test/Sema/merge-decls.c
@@ -0,0 +1,39 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+void foo(void);
+void foo(void) {}
+void foo(void);
+void foo(void); // expected-note {{previous declaration is here}}
+
+void foo(int); // expected-error {{conflicting types for 'foo'}}
+
+int funcdef()
+{
+ return 0;
+}
+
+int funcdef();
+
+int funcdef2() { return 0; } // expected-note {{previous definition is here}}
+int funcdef2() { return 0; } // expected-error {{redefinition of 'funcdef2'}}
+
+// PR2502
+void (*f)(void);
+void (*f)() = 0;
+
+typedef __attribute__(( ext_vector_type(2) )) int Vi2;
+typedef __attribute__(( ext_vector_type(2) )) float Vf2;
+
+Vf2 g0; // expected-note {{previous definition is here}}
+Vi2 g0; // expected-error {{redefinition of 'g0'}}
+
+_Complex int g1; // expected-note {{previous definition is here}}
+_Complex float g1; // expected-error {{redefinition of 'g1'}}
+
+// rdar://6096412
+extern char i6096412[10];
+extern char i6096412[];
+void foo6096412(void) {
+ int x = sizeof(i6096412);
+}
+
diff --git a/test/Sema/ms-fuzzy-asm.c b/test/Sema/ms-fuzzy-asm.c
new file mode 100644
index 000000000000..58dcbcfc5232
--- /dev/null
+++ b/test/Sema/ms-fuzzy-asm.c
@@ -0,0 +1,9 @@
+// RUN: clang-cc %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 }
+
diff --git a/test/Sema/nested-redef.c b/test/Sema/nested-redef.c
new file mode 100644
index 000000000000..ea180910128b
--- /dev/null
+++ b/test/Sema/nested-redef.c
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct X { // expected-note{{previous definition is here}}
+ struct X { } x; // expected-error{{nested redefinition of 'X'}}
+};
+
+struct Y { };
+void f(void) {
+ struct Y { }; // okay: this is a different Y
+}
+
+struct T;
+struct Z {
+ struct T { int x; } t;
+ struct U { int x; } u;
+};
+
+void f2(void) {
+ struct T t;
+ struct U u;
+}
+
+
diff --git a/test/Sema/nonnull.c b/test/Sema/nonnull.c
new file mode 100644
index 000000000000..3bed2feb5012
--- /dev/null
+++ b/test/Sema/nonnull.c
@@ -0,0 +1,32 @@
+// RUN: clang-cc -fblocks -fsyntax-only -verify %s
+
+int f1(int x) __attribute__((nonnull)); // expected-warning{{'nonnull' attribute applied to function with no pointer arguments}}
+int f2(int *x) __attribute__ ((nonnull (1)));
+int f3(int *x) __attribute__ ((nonnull (0))); // expected-error {{'nonnull' attribute parameter 1 is out of bounds}}
+int f4(int *x, int *y) __attribute__ ((nonnull (1,2)));
+int f5(int *x, int *y) __attribute__ ((nonnull (2,1)));
+
+extern void func1 (void (^block1)(), void (^block2)(), int) __attribute__((nonnull));
+
+extern void func3 (void (^block1)(), int, void (^block2)(), int)
+__attribute__((nonnull(1,3)));
+
+extern void func4 (void (^block1)(), void (^block2)()) __attribute__((nonnull(1)))
+__attribute__((nonnull(2)));
+
+void
+foo (int i1, int i2, int i3, void (^cp1)(), void (^cp2)(), void (^cp3)())
+{
+ func1(cp1, cp2, i1);
+
+ func1(0, cp2, i1); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ func1(cp1, 0, i1); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ func1(cp1, cp2, 0);
+
+
+ func3(0, i2, cp3, i3); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ func3(cp3, i2, 0, i3); // expected-warning {{null passed to a callee which requires a non-null argument}}
+
+ func4(0, cp1); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ func4(cp1, 0); // expected-warning {{null passed to a callee which requires a non-null argument}}
+}
diff --git a/test/Sema/offsetof.c b/test/Sema/offsetof.c
new file mode 100644
index 000000000000..f8b9fed03c3c
--- /dev/null
+++ b/test/Sema/offsetof.c
@@ -0,0 +1,50 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
+
+typedef struct P { int i; float f; } PT;
+struct external_sun3_core
+{
+ unsigned c_regs;
+
+ PT X[100];
+
+};
+
+void swap()
+{
+ int x;
+ x = offsetof(struct external_sun3_core, c_regs);
+ x = __builtin_offsetof(struct external_sun3_core, X[42].f);
+
+ x = __builtin_offsetof(struct external_sun3_core, X[42].f2); // expected-error {{no member named 'f2'}}
+ x = __builtin_offsetof(int, X[42].f2); // expected-error {{offsetof requires struct}}
+
+ int a[__builtin_offsetof(struct external_sun3_core, X) == 4 ? 1 : -1];
+ int b[__builtin_offsetof(struct external_sun3_core, X[42]) == 340 ? 1 : -1];
+ int c[__builtin_offsetof(struct external_sun3_core, X[42].f2) == 344 ? 1 : -1]; // expected-error {{no member named 'f2'}}
+}
+
+extern int f();
+
+struct s1 { int a; };
+int v1 = offsetof (struct s1, a) == 0 ? 0 : f();
+
+struct s2 { int a; };
+int v2 = (int)(&((struct s2 *) 0)->a) == 0 ? 0 : f();
+
+struct s3 { int a; };
+int v3 = __builtin_offsetof(struct s3, a) == 0 ? 0 : f();
+
+// PR3396
+struct sockaddr_un {
+ unsigned char sun_len;
+ char sun_path[104];
+};
+int a(int len) {
+int a[__builtin_offsetof(struct sockaddr_un, sun_path[len+1])];
+}
+
+// PR4079
+union x {struct {int x;};};
+int x[__builtin_offsetof(union x, x)];
diff --git a/test/Sema/overloadable-complex.c b/test/Sema/overloadable-complex.c
new file mode 100644
index 000000000000..62b388213347
--- /dev/null
+++ b/test/Sema/overloadable-complex.c
@@ -0,0 +1,50 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+char *foo(float) __attribute__((__overloadable__)); // expected-note 3 {{candidate function}}
+
+void test_foo_1(float fv, double dv, float _Complex fc, double _Complex dc) {
+ char *cp1 = foo(fv);
+ char *cp2 = foo(dv);
+ // Note: GCC and EDG reject these two, but they are valid C99 conversions
+ char *cp3 = foo(fc);
+ char *cp4 = foo(dc);
+}
+
+int *foo(float _Complex) __attribute__((__overloadable__)); // expected-note 3 {{candidate function}}
+
+void test_foo_2(float fv, double dv, float _Complex fc, double _Complex dc) {
+ char *cp1 = foo(fv);
+ char *cp2 = foo(dv); // expected-error{{call to 'foo' is ambiguous; candidates are:}}
+ int *ip = foo(fc);
+ int *lp = foo(dc); // expected-error{{call to 'foo' is ambiguous; candidates are:}}
+}
+
+long *foo(double _Complex) __attribute__((__overloadable__)); // expected-note {{candidate function}}
+
+void test_foo_3(float fv, double dv, float _Complex fc, double _Complex dc) {
+ char *cp1 = foo(fv);
+ char *cp2 = foo(dv); // expected-error{{call to 'foo' is ambiguous; candidates are:}}
+ int *ip = foo(fc);
+ long *lp = foo(dc);
+}
+
+char *promote_or_convert(double _Complex) __attribute__((__overloadable__)); // expected-note 2 {{candidate function}}
+int *promote_or_convert(long double _Complex) __attribute__((__overloadable__)); // expected-note 2 {{candidate function}}
+
+void test_promote_or_convert(float f, float _Complex fc) {
+ char *cp = promote_or_convert(fc); // expected-error{{call to 'promote_or_convert' is ambiguous; candidates are:}}
+ int *ip2 = promote_or_convert(f); // expected-error{{call to 'promote_or_convert' is ambiguous; candidates are:}}
+}
+
+char *promote_or_convert2(float) __attribute__((__overloadable__));
+int *promote_or_convert2(double _Complex) __attribute__((__overloadable__));
+
+void test_promote_or_convert2(float _Complex fc) {
+ int *cp = promote_or_convert2(fc);
+}
+
+char *promote_or_convert3(int _Complex) __attribute__((__overloadable__));
+int *promote_or_convert3(long _Complex) __attribute__((__overloadable__));
+
+void test_promote_or_convert3(short _Complex sc) {
+ char *cp = promote_or_convert3(sc);
+}
diff --git a/test/Sema/overloadable.c b/test/Sema/overloadable.c
new file mode 100644
index 000000000000..0d5db3a98454
--- /dev/null
+++ b/test/Sema/overloadable.c
@@ -0,0 +1,53 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int var __attribute__((overloadable)); // expected-error{{'overloadable' attribute can only be applied to a function}}
+
+int *f(int) __attribute__((overloadable)); // expected-note 2{{previous overload of function is here}}
+float *f(float); // expected-error{{overloaded function 'f' must have the 'overloadable' attribute}}
+int *f(int); // expected-error{{redeclaration of 'f' must have the 'overloadable' attribute}} \
+ // expected-note{{previous declaration is here}}
+double *f(double) __attribute__((overloadable)); // okay, new
+
+void test_f(int iv, float fv, double dv) {
+ int *ip = f(iv);
+ float *fp = f(fv);
+ double *dp = f(dv);
+}
+
+int *accept_funcptr(int (*)()) __attribute__((overloadable)); // \
+ // expected-note{{candidate function}}
+float *accept_funcptr(int (*)(int, double)) __attribute__((overloadable)); // \
+ // expected-note{{candidate function}}
+
+void test_funcptr(int (*f1)(int, double),
+ int (*f2)(int, float)) {
+ float *fp = accept_funcptr(f1);
+ accept_funcptr(f2); // expected-error{{no matching function for call to 'accept_funcptr'; candidates are:}}
+}
+
+struct X { int x; float y; };
+struct Y { int x; float y; };
+int* accept_struct(struct X x) __attribute__((__overloadable__));
+float* accept_struct(struct Y y) __attribute__((overloadable));
+
+void test_struct(struct X x, struct Y y) {
+ int *ip = accept_struct(x);
+ float *fp = accept_struct(y);
+}
+
+double *f(int) __attribute__((overloadable)); // expected-error{{conflicting types for 'f'}}
+
+double promote(float) __attribute__((__overloadable__));
+double promote(double) __attribute__((__overloadable__));
+long double promote(long double) __attribute__((__overloadable__));
+
+void promote() __attribute__((__overloadable__)); // expected-error{{'overloadable' function 'promote' must have a prototype}}
+void promote(...) __attribute__((__overloadable__, __unavailable__)); // \
+ // expected-note{{candidate function}}
+
+void test_promote(short* sp) {
+ promote(1.0);
+ promote(sp); // expected-error{{call to unavailable function 'promote'}}
+}
+
+
diff --git a/test/Sema/pointer-addition.c b/test/Sema/pointer-addition.c
new file mode 100644
index 000000000000..87d5eaf39c99
--- /dev/null
+++ b/test/Sema/pointer-addition.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc %s -fsyntax-only -verify -pedantic
+
+typedef struct S S; // expected-note 3 {{forward declaration of 'struct S'}}
+void a(S* b, void* c) {
+ void (*fp)(int) = 0;
+ b++; // expected-error {{arithmetic on pointer to incomplete type}}
+ b += 1; // expected-error {{arithmetic on pointer to incomplete type}}
+ c++; // expected-warning {{use of GNU void* extension}}
+ c += 1; // expected-warning {{use of GNU void* extension}}
+ c--; // expected-warning {{use of GNU void* extension}}
+ c -= 1; // expected-warning {{use of GNU void* extension}}
+ b = 1+b; // expected-error {{arithmetic on pointer to incomplete type}}
+ /* The next couple tests are only pedantic warnings in gcc */
+ void (*d)(S*,void*) = a;
+ d += 1; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}}
+ d++; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}}}
+ d--; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}}
+ d -= 1; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}}
+}
diff --git a/test/Sema/pointer-subtract-compat.c b/test/Sema/pointer-subtract-compat.c
new file mode 100644
index 000000000000..b3be37e7f185
--- /dev/null
+++ b/test/Sema/pointer-subtract-compat.c
@@ -0,0 +1,11 @@
+// RUN: clang-cc %s -fsyntax-only -verify -pedantic
+
+typedef const char rchar;
+int a(char* a, rchar* b) {
+ return a-b;
+}
+
+// <rdar://problem/6520707>
+void f0(void (*fp)(void)) {
+ int x = fp - fp; // expected-warning{{arithmetic on pointer to function type 'void (*)(void)' is a GNU extension}}
+}
diff --git a/test/Sema/pragma-pack-2.c b/test/Sema/pragma-pack-2.c
new file mode 100644
index 000000000000..25be5539783e
--- /dev/null
+++ b/test/Sema/pragma-pack-2.c
@@ -0,0 +1,93 @@
+// RUN: clang-cc -triple i686-apple-darwin9 %s -fsyntax-only -verify
+
+#include <stddef.h>
+
+#pragma pack(4)
+
+// Baseline
+struct s0 {
+ char f0;
+ int f1;
+};
+extern int a0[offsetof(struct s0, f1) == 4 ? 1 : -1];
+
+#pragma pack(push, 2)
+struct s1 {
+ char f0;
+ int f1;
+};
+extern int a1[offsetof(struct s1, f1) == 2 ? 1 : -1];
+#pragma pack(pop)
+
+// Test scope of definition
+
+#pragma pack(push, 2)
+struct s2_0 {
+#pragma pack(pop)
+ char f0;
+ int f1;
+};
+extern int a2_0[offsetof(struct s2_0, f1) == 2 ? 1 : -1];
+
+struct s2_1 {
+ char f0;
+#pragma pack(push, 2)
+ int f1;
+#pragma pack(pop)
+};
+extern int a2_1[offsetof(struct s2_1, f1) == 4 ? 1 : -1];
+
+struct s2_2 {
+ char f0;
+ int f1;
+#pragma pack(push, 2)
+};
+#pragma pack(pop)
+extern int a2_2[offsetof(struct s2_2, f1) == 4 ? 1 : -1];
+
+struct s2_3 {
+ char f0;
+#pragma pack(push, 2)
+ struct s2_3_0 {
+#pragma pack(pop)
+ int f0;
+ } f1;
+};
+extern int a2_3[offsetof(struct s2_3, f1) == 2 ? 1 : -1];
+
+struct s2_4 {
+ char f0;
+ struct s2_4_0 {
+ int f0;
+#pragma pack(push, 2)
+ } f1;
+#pragma pack(pop)
+};
+extern int a2_4[offsetof(struct s2_4, f1) == 4 ? 1 : -1];
+
+#pragma pack(1)
+struct s3_0 {
+ char f0;
+ int f1;
+};
+#pragma pack()
+struct s3_1 {
+ char f0;
+ int f1;
+};
+extern int a3_0[offsetof(struct s3_0, f1) == 1 ? 1 : -1];
+extern int a3_1[offsetof(struct s3_1, f1) == 4 ? 1 : -1];
+
+// pack(0) is like pack()
+#pragma pack(1)
+struct s4_0 {
+ char f0;
+ int f1;
+};
+#pragma pack(0)
+struct s4_1 {
+ char f0;
+ int f1;
+};
+extern int a4_0[offsetof(struct s4_0, f1) == 1 ? 1 : -1];
+extern int a4_1[offsetof(struct s4_1, f1) == 4 ? 1 : -1];
diff --git a/test/Sema/pragma-pack-3.c b/test/Sema/pragma-pack-3.c
new file mode 100644
index 000000000000..a2d665ea7417
--- /dev/null
+++ b/test/Sema/pragma-pack-3.c
@@ -0,0 +1,34 @@
+// RUN: clang-cc -triple i686-apple-darwin9 %s -fsyntax-only -verify
+
+// Stack: [], Alignment: 8
+
+#pragma pack(push, 1)
+// Stack: [8], Alignment: 1
+
+#pragma pack(push, 4)
+// Stack: [8, 1], Alignment: 4
+
+// Note that this differs from gcc; pack() in gcc appears to pop the
+// top stack entry and resets the current alignment. This is both
+// inconsistent with MSVC, and the gcc documentation. In other cases,
+// for example changing this to pack(8), I don't even understand what gcc
+// is doing.
+
+#pragma pack()
+// Stack: [8, 1], Alignment: 8
+
+#pragma pack(pop)
+// Stack: [8], Alignment: 1
+struct s0 {
+ char f0;
+ short f1;
+};
+int a[sizeof(struct s0) == 3 ? 1 : -1];
+
+#pragma pack(pop)
+// Stack: [], Alignment: 8
+struct s1 {
+ char f0;
+ short f1;
+};
+int b[sizeof(struct s1) == 4 ? 1 : -1];
diff --git a/test/Sema/pragma-pack.c b/test/Sema/pragma-pack.c
new file mode 100644
index 000000000000..51398fa0a554
--- /dev/null
+++ b/test/Sema/pragma-pack.c
@@ -0,0 +1,27 @@
+// RUN: clang-cc -triple i686-apple-darwin9 -fsyntax-only -verify %s
+
+/* expected-warning {{value of #pragma pack(show) == 8}} */ #pragma pack(show)
+/* expected-warning {{expected #pragma pack parameter to be}} */ #pragma pack(3)
+/* expected-warning {{value of #pragma pack(show) == 8}} */ #pragma pack(show)
+#pragma pack(4)
+/* expected-warning {{value of #pragma pack(show) == 4}} */ #pragma pack(show)
+#pragma pack() // resets to default
+/* expected-warning {{value of #pragma pack(show) == 8}} */ #pragma pack(show)
+#pragma pack(2)
+#pragma pack(push, eek, 16) // -> (eek, 2), 16
+/* expected-warning {{value of #pragma pack(show) == 16}} */ #pragma pack(show)
+#pragma pack(push) // -> (eek, 2), (, 2), 16
+/* expected-warning {{value of #pragma pack(show) == 16}} */ #pragma pack(show)
+#pragma pack(1)
+#pragma pack(push, 8) // -> (eek, 2), (, 2), (, 1), 8
+/* expected-warning {{value of #pragma pack(show) == 8}} */ #pragma pack(show)
+#pragma pack(pop) // -> (eek, 2), (,2), 1
+/* expected-warning {{value of #pragma pack(show) == 1}} */ #pragma pack(show)
+#pragma pack(pop, eek)
+/* expected-warning {{value of #pragma pack(show) == 2}} */ #pragma pack(show)
+/* expected-warning {{pack(pop, ...) failed: stack empty}} */ #pragma pack(pop)
+
+#pragma pack(push)
+#pragma pack(pop, 16)
+/* expected-warning {{value of #pragma pack(show) == 16}} */ #pragma pack(show)
+
diff --git a/test/Sema/pragma-unused.c b/test/Sema/pragma-unused.c
new file mode 100644
index 000000000000..fe8bf8608bc3
--- /dev/null
+++ b/test/Sema/pragma-unused.c
@@ -0,0 +1,38 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f1(void) {
+ int x, y, z;
+ #pragma unused(x)
+ #pragma unused(y, z)
+
+ int w; // FIXME: We should emit a warning that 'w' is unused.
+ #pragma unused w // expected-warning{{missing '(' after '#pragma unused' - ignoring}}
+}
+
+void f2(void) {
+ int x, y;
+ #pragma unused(x,) // expected-warning{{expected '#pragma unused' argument to be a variable name}}
+ #pragma unused() // expected-warning{{expected '#pragma unused' argument to be a variable name}}
+}
+
+void f3(void) {
+ #pragma unused(x) // expected-error{{use of undeclared identifier 'x'}}
+}
+
+void f4(void) {
+ int w; // FIXME: We should emit a warning that 'w' is unused.
+ #pragma unused((w)) // expected-warning{{expected '#pragma unused' argument to be a variable name}}
+}
+
+int k;
+void f5(void) {
+ #pragma unused(k) // expected-warning{{only local variables can be arguments to '#pragma unused' - ignored}}
+}
+
+void f6(void) {
+ int z; // no-warning
+ {
+ #pragma unused(z) // no-warning
+ }
+}
+
diff --git a/test/Sema/predef.c b/test/Sema/predef.c
new file mode 100644
index 000000000000..7b3fe5038f96
--- /dev/null
+++ b/test/Sema/predef.c
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void abcdefghi12(void) {
+ const char (*ss)[12] = &__func__;
+ static int arr[sizeof(__func__)==12 ? 1 : -1];
+}
+
+char *X = __func__; // expected-warning {{predefined identifier is only valid}} \
+ expected-warning {{initializing 'char const [1]' discards qualifiers, expected 'char *'}}
+
+void a() {
+ __func__[0] = 'a'; // expected-error {{variable is not assignable}}
+}
+
+// rdar://6097892 - GCC permits this insanity.
+const char *b = __func__; // expected-warning {{predefined identifier is only valid}}
+const char *c = __FUNCTION__; // expected-warning {{predefined identifier is only valid}}
+const char *d = __PRETTY_FUNCTION__; // expected-warning {{predefined identifier is only valid}}
+
diff --git a/test/Sema/predefined-function.c b/test/Sema/predefined-function.c
new file mode 100644
index 000000000000..e8ccb3636b8e
--- /dev/null
+++ b/test/Sema/predefined-function.c
@@ -0,0 +1,38 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+
+char *funk(int format);
+enum Test {A=-1};
+char *funk(enum Test x);
+
+int eli(float b); // expected-note {{previous declaration is here}}
+int b(int c) {return 1;}
+
+int foo();
+int foo()
+{
+ int eli(int (int)); // expected-error {{conflicting types for 'eli'}}
+ eli(b); // expected-error{{incompatible type passing}}
+ return 0;
+}
+
+int bar();
+int bar(int i) // expected-note {{previous definition is here}}
+{
+ return 0;
+}
+int bar() // expected-error {{redefinition of 'bar'}}
+{
+ return 0;
+}
+
+int foobar(int); // note {{previous declaration is here}}
+int foobar() // error {{conflicting types for 'foobar'}}
+{
+ return 0;
+}
+
+int wibble(); // expected-note {{previous declaration is here}}
+float wibble() // expected-error {{conflicting types for 'wibble'}}
+{
+ return 0.0f;
+}
diff --git a/test/Sema/private-extern.c b/test/Sema/private-extern.c
new file mode 100644
index 000000000000..5dd37f430efa
--- /dev/null
+++ b/test/Sema/private-extern.c
@@ -0,0 +1,88 @@
+// RUN: clang-cc -verify -fsyntax-only %s
+
+static int g0; // expected-note{{previous definition}}
+int g0; // expected-error{{non-static declaration of 'g0' follows static declaration}}
+
+static int g1;
+extern int g1;
+
+static int g2;
+__private_extern__ int g2;
+
+int g3; // expected-note{{previous definition}}
+static int g3; // expected-error{{static declaration of 'g3' follows non-static declaration}}
+
+extern int g4; // expected-note{{previous definition}}
+static int g4; // expected-error{{static declaration of 'g4' follows non-static declaration}}
+
+__private_extern__ int g5; // expected-note{{previous definition}}
+static int g5; // expected-error{{static declaration of 'g5' follows non-static declaration}}
+
+void f0() {
+ // FIXME: Diagnose this?
+ int g6;
+ extern int g6;
+}
+
+void f1() {
+ // FIXME: Diagnose this?
+ int g7;
+ __private_extern__ int g7;
+}
+
+void f2() {
+ extern int g8; // expected-note{{previous definition}}
+ // FIXME: Improve this diagnostic.
+ int g8; // expected-error{{redefinition of 'g8'}}
+}
+
+void f3() {
+ __private_extern__ int g9; // expected-note{{previous definition}}
+ // FIXME: Improve this diagnostic.
+ int g9; // expected-error{{redefinition of 'g9'}}
+}
+
+void f4() {
+ extern int g10;
+ extern int g10;
+}
+
+void f5() {
+ __private_extern__ int g11;
+ __private_extern__ int g11;
+}
+
+void f6() {
+ // FIXME: Diagnose
+ extern int g12;
+ __private_extern__ int g12;
+}
+
+void f7() {
+ // FIXME: Diagnose
+ __private_extern__ int g13;
+ extern int g13;
+}
+
+struct s0;
+void f8() {
+ extern struct s0 g14;
+ __private_extern__ struct s0 g14;
+}
+struct s0 { int x; };
+
+void f9() {
+ extern int g15 = 0; // expected-error{{'extern' variable cannot have an initializer}}
+ // FIXME: linkage specifier in warning.
+ __private_extern__ int g16 = 0; // expected-error{{'extern' variable cannot have an initializer}}
+}
+
+extern int g17;
+int g17 = 0;
+
+extern int g18 = 0; // expected-warning{{'extern' variable has an initializer}}
+
+__private_extern__ int g19;
+int g19 = 0;
+
+__private_extern__ int g20 = 0;
diff --git a/test/Sema/rdar6248119.m b/test/Sema/rdar6248119.m
new file mode 100644
index 000000000000..631c7b35a992
--- /dev/null
+++ b/test/Sema/rdar6248119.m
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fsyntax-only %s -verify
+// Test case for:
+// <rdar://problem/6248119> @finally doesn't introduce a new scope
+
+void f0() {
+ int i;
+ @try {
+ } @finally {
+ int i = 0;
+ }
+}
+
+void f1() {
+ int i;
+ @try {
+ int i =0;
+ } @finally {
+ }
+}
+
+void f2() {
+ int i;
+ @try {
+ } @catch(id e) {
+ int i = 0;
+ }
+}
diff --git a/test/Sema/rdr6094103-unordered-compare-promote.c b/test/Sema/rdr6094103-unordered-compare-promote.c
new file mode 100644
index 000000000000..636f770e3ee0
--- /dev/null
+++ b/test/Sema/rdr6094103-unordered-compare-promote.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -ast-dump %s 2>&1 | grep ImplicitCastExpr | count 2
+
+int foo (double x, long double y) {
+ // There needs to be an implicit cast on x here.
+ return __builtin_isgreater(x, y);
+}
diff --git a/test/Sema/recover-goto.c b/test/Sema/recover-goto.c
new file mode 100644
index 000000000000..e7b9f3c8eafc
--- /dev/null
+++ b/test/Sema/recover-goto.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only %s -verify
+
+void a() {goto A; // expected-error {{use of undeclared label}}
+// expected-error {{expected '}'}}
diff --git a/test/Sema/redefinition.c b/test/Sema/redefinition.c
new file mode 100644
index 000000000000..26c90c8e6d4f
--- /dev/null
+++ b/test/Sema/redefinition.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+int f(int a) { } // expected-note {{previous definition is here}}
+int f(int);
+int f(int a) { } // expected-error {{redefinition of 'f'}}
+
+// <rdar://problem/6097326>
+int foo(x) {
+ return 0;
+}
+int x = 1;
diff --git a/test/Sema/return-silent.c b/test/Sema/return-silent.c
new file mode 100644
index 000000000000..b3b2a5621819
--- /dev/null
+++ b/test/Sema/return-silent.c
@@ -0,0 +1,9 @@
+// RUN: clang-cc %s -Wno-return-type -fsyntax-only -verify
+
+int t14() {
+ return;
+}
+
+void t15() {
+ return 1;
+}
diff --git a/test/Sema/return.c b/test/Sema/return.c
new file mode 100644
index 000000000000..d96cede68a61
--- /dev/null
+++ b/test/Sema/return.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+// clang emits the following warning by default.
+// With GCC, -pedantic, -Wreturn-type or -Wall are required to produce the
+// following warning.
+int t14() {
+ return; // expected-warning {{non-void function 't14' should return a value}}
+}
+
+void t15() {
+ return 1; // expected-warning {{void function 't15' should not return a value}}
+}
diff --git a/test/Sema/scope-check.c b/test/Sema/scope-check.c
new file mode 100644
index 000000000000..76041c491653
--- /dev/null
+++ b/test/Sema/scope-check.c
@@ -0,0 +1,196 @@
+// RUN: clang-cc -fsyntax-only -verify -fblocks -std=gnu99 %s
+
+int test1(int x) {
+ goto L; // expected-error{{illegal goto into protected scope}}
+ int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
+ int b[x]; // expected-note {{jump bypasses initialization of variable length array}}
+ L:
+ return sizeof a;
+}
+
+int test2(int x) {
+ goto L; // expected-error{{illegal goto into protected scope}}
+ typedef int a[x]; // expected-note {{jump bypasses initialization of VLA typedef}}
+ L:
+ return sizeof(a);
+}
+
+void test3clean(int*);
+
+int test3() {
+ goto L; // expected-error{{illegal goto into protected scope}}
+int a __attribute((cleanup(test3clean))); // expected-note {{jump bypasses initialization of declaration with __attribute__((cleanup))}}
+L:
+ return a;
+}
+
+int test4(int x) {
+ goto L; // expected-error{{illegal goto into protected scope}}
+int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
+ test4(x);
+L:
+ return sizeof a;
+}
+
+int test5(int x) {
+ int a[x];
+ test5(x);
+ goto L; // Ok.
+L:
+ goto L; // Ok.
+ return sizeof a;
+}
+
+int test6() {
+ // just plain invalid.
+ goto x; // expected-error {{use of undeclared label 'x'}}
+}
+
+void test7(int x) {
+ switch (x) {
+ case 1: ;
+ int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
+ case 2: // expected-error {{illegal switch case into protected scope}}
+ a[1] = 2;
+ break;
+ }
+}
+
+int test8(int x) {
+ // For statement.
+ goto L2; // expected-error {{illegal goto into protected scope}}
+ for (int arr[x]; // expected-note {{jump bypasses initialization of variable length array}}
+ ; ++x)
+ L2:;
+
+ // Statement expressions.
+ goto L3; // expected-error {{illegal goto into protected scope}}
+ int Y = ({ int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
+ L3: 4; });
+
+ goto L4; // expected-error {{illegal goto into protected scope}}
+ {
+ int A[x], // expected-note {{jump bypasses initialization of variable length array}}
+ B[x]; // expected-note {{jump bypasses initialization of variable length array}}
+ L4: ;
+ }
+
+ {
+ L5: ;// ok
+ int A[x], B = ({ if (x)
+ goto L5;
+ else
+ goto L6;
+ 4; });
+ L6:; // ok.
+ if (x) goto L6; // ok
+ }
+
+ {
+ L7: ;// ok
+ int A[x], B = ({ if (x)
+ goto L7;
+ else
+ goto L8; // expected-error {{illegal goto into protected scope}}
+ 4; }),
+ C[x]; // expected-note {{jump bypasses initialization of variable length array}}
+ L8:; // bad
+ }
+
+ {
+ L9: ;// ok
+ int A[({ if (x)
+ goto L9;
+ else
+ // FIXME:
+ goto L10; // fixme-error {{illegal goto into protected scope}}
+ 4; })];
+ L10:; // bad
+ }
+
+ {
+ // FIXME: Crashes goto checker.
+ //goto L11;// ok
+ //int A[({ L11: 4; })];
+ }
+
+ {
+ goto L12;
+
+ int y = 4; // fixme-warn: skips initializer.
+ L12:
+ ;
+ }
+
+ // Statement expressions 2.
+ goto L1; // expected-error {{illegal goto into protected scope}}
+ return x == ({
+ int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
+ L1:
+ 42; });
+}
+
+void test9(int n, void *P) {
+ int Y;
+ int Z = 4;
+ goto *P; // ok.
+
+L2: ;
+ int a[n]; // expected-note 2 {{jump bypasses initialization of variable length array}}
+
+L3:
+L4:
+ goto *P; // expected-error {{illegal indirect goto in protected scope, unknown effect on scopes}}
+ goto L3; // ok
+ goto L4; // ok
+
+ void *Ptrs[] = {
+ &&L2, // Ok.
+ &&L3 // expected-error {{address taken of label in protected scope, jump to it would have unknown effect on scope}}
+ };
+}
+
+void test10(int n, void *P) {
+ goto L0; // expected-error {{illegal goto into protected scope}}
+ typedef int A[n]; // expected-note {{jump bypasses initialization of VLA typedef}}
+L0:
+
+ goto L1; // expected-error {{illegal goto into protected scope}}
+ A b, c[10]; // expected-note 2 {{jump bypasses initialization of variable length array}}
+L1:
+ goto L2; // expected-error {{illegal goto into protected scope}}
+ A d[n]; // expected-note {{jump bypasses initialization of variable length array}}
+L2:
+ return;
+}
+
+void test11(int n) {
+ void *P = ^{
+ switch (n) {
+ case 1:;
+ case 2:
+ case 3:;
+ int Arr[n]; // expected-note {{jump bypasses initialization of variable length array}}
+ case 4: // expected-error {{illegal switch case into protected scope}}
+ return;
+ }
+ };
+}
+
+
+// TODO: When and if gotos are allowed in blocks, this should work.
+void test12(int n) {
+ void *P = ^{
+ goto L1; // expected-error {{goto not allowed in block literal}}
+ L1:
+ goto L2; // expected-error {{goto not allowed in block literal}}
+ L2:
+ goto L3; // expected-error {{goto not allowed in block literal}}
+ // todo-error {{illegal goto into protected scope}}
+ int Arr[n]; // todo-note {{jump bypasses initialization of variable length array}}
+ L3:
+ goto L4; // expected-error {{goto not allowed in block literal}}
+ L4: return;
+ };
+}
+
diff --git a/test/Sema/self-comparison.c b/test/Sema/self-comparison.c
new file mode 100644
index 000000000000..db56e8bf17d8
--- /dev/null
+++ b/test/Sema/self-comparison.c
@@ -0,0 +1,33 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int foo(int x) {
+ return x == x; // expected-warning {{self-comparison always results}}
+}
+
+int foo2(int x) {
+ return (x) != (((x))); // expected-warning {{self-comparison always results}}
+}
+
+int qux(int x) {
+ return x < x; // expected-warning {{self-comparison}}
+}
+
+int qux2(int x) {
+ return x > x; // expected-warning {{self-comparison}}
+}
+
+int bar(float x) {
+ return x == x; // no-warning
+}
+
+int bar2(float x) {
+ return x != x; // no-warning
+}
+
+// Motivated by <rdar://problem/6703892>, self-comparisons of enum constants
+// should not be warned about. These can be expanded from macros, and thus
+// are usually deliberate.
+int compare_enum() {
+ enum { A };
+ return A == A; // no-warning
+}
diff --git a/test/Sema/sentinel-attribute.c b/test/Sema/sentinel-attribute.c
new file mode 100644
index 000000000000..c40f8df29c33
--- /dev/null
+++ b/test/Sema/sentinel-attribute.c
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+int x __attribute__((sentinel)); //expected-warning{{'sentinel' attribute only applies to function, method or block types}}
+
+void f1(int a, ...) __attribute__ ((sentinel));
+void f2(int a, ...) __attribute__ ((sentinel(1)));
+
+void f3(int a, ...) __attribute__ ((sentinel("hello"))); //expected-error{{'sentinel' attribute requires parameter 1 to be an integer constant}}
+void f4(int a, ...) __attribute__ ((sentinel(1, 2, 3))); //expected-error{{attribute requires 0, 1 or 2 argument(s)}}
+void f4(int a, ...) __attribute__ ((sentinel(-1))); //expected-error{{parameter 1 less than zero}}
+void f4(int a, ...) __attribute__ ((sentinel(0, 2))); // expected-error{{parameter 2 not 0 or 1}}
+
+void f5(int a) __attribute__ ((sentinel)); //expected-warning{{'sentinel' attribute only supported for variadic functions}}
+
+
+void f6() __attribute__((__sentinel__)); // expected-warning {{'sentinel' attribute requires named arguments}}
diff --git a/test/Sema/shift.c b/test/Sema/shift.c
new file mode 100644
index 000000000000..5acbe12ac33e
--- /dev/null
+++ b/test/Sema/shift.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only %s
+
+void test() {
+ char c;
+ c <<= 14;
+}
diff --git a/test/Sema/statements.c b/test/Sema/statements.c
new file mode 100644
index 000000000000..9a71a403700d
--- /dev/null
+++ b/test/Sema/statements.c
@@ -0,0 +1,29 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+typedef unsigned __uint32_t;
+
+#define __byte_swap_int_var(x) \
+__extension__ ({ register __uint32_t __X = (x); \
+ __asm ("bswap %0" : "+r" (__X)); \
+ __X; })
+
+int test(int _x) {
+ return (__byte_swap_int_var(_x));
+}
+
+// PR2374
+int test2() { return ({L:5;}); }
+int test3() { return ({ {5;} }); } // expected-error {{incompatible type returning 'void', expected 'int'}}\
+ // expected-warning {{expression result unused}}
+int test4() { return ({ ({5;}); }); }
+int test5() { return ({L1: L2: L3: 5;}); }
+int test6() { return ({5;}); }
+void test7() { ({5;}); } // expected-warning {{expression result unused}}
+
+// PR3062
+int test8[({10;})]; // expected-error {{statement expression not allowed at file scope}}
+
+// PR3912
+void test9(const void *P) {
+ __builtin_prefetch(P);
+}
diff --git a/test/Sema/static-init.c b/test/Sema/static-init.c
new file mode 100644
index 000000000000..cd495568ca3f
--- /dev/null
+++ b/test/Sema/static-init.c
@@ -0,0 +1,23 @@
+// RUN: clang-cc -triple i386-pc-linux-gnu -fsyntax-only -verify %s
+
+#include <stdint.h>
+
+static int f = 10;
+static int b = f; // expected-error {{initializer element is not a compile-time constant}}
+
+float r = (float) (intptr_t) &r; // expected-error {{initializer element is not a compile-time constant}}
+intptr_t s = (intptr_t) &s;
+_Bool t = &t;
+
+
+union bar {
+ int i;
+};
+
+struct foo {
+ unsigned ptr;
+};
+
+union bar u[1];
+struct foo x = {(intptr_t) u}; // no-error
+struct foo y = {(char) u}; // expected-error {{initializer element is not a compile-time constant}}
diff --git a/test/Sema/stdcall-fastcall.c b/test/Sema/stdcall-fastcall.c
new file mode 100644
index 000000000000..353bbfc25297
--- /dev/null
+++ b/test/Sema/stdcall-fastcall.c
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// CC qualifier can be applied only to functions
+int __attribute__((stdcall)) var1; // expected-warning{{'stdcall' attribute only applies to function types}}
+int __attribute__((fastcall)) var2; // expected-warning{{'fastcall' attribute only applies to function types}}
+
+// Different CC qualifiers are not compatible
+void __attribute__((stdcall, fastcall)) foo3(); // expected-error{{stdcall and fastcall attributes are not compatible}}
+void __attribute__((stdcall)) foo4();
+void __attribute__((fastcall)) foo4(); // expected-error{{fastcall and stdcall attributes are not compatible}}
diff --git a/test/Sema/struct-cast.c b/test/Sema/struct-cast.c
new file mode 100644
index 000000000000..063e8e32c02d
--- /dev/null
+++ b/test/Sema/struct-cast.c
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only %s -verify
+
+struct S {
+ int one;
+ int two;
+};
+
+struct S const foo(void);
+
+struct S tmp;
+
+void priv_sock_init() {
+ tmp = (struct S)foo();
+}
diff --git a/test/Sema/struct-compat.c b/test/Sema/struct-compat.c
new file mode 100644
index 000000000000..35d8fb1aa0c2
--- /dev/null
+++ b/test/Sema/struct-compat.c
@@ -0,0 +1,17 @@
+/* RUN: clang-cc %s -fsyntax-only -pedantic -verify
+ */
+
+extern struct {int a;} x; // expected-note {{previous definition is here}}
+extern struct {int a;} x; // expected-error {{redefinition of 'x'}}
+
+struct x;
+int a(struct x* b) {
+// Per C99 6.7.2.3, since the outer and inner "struct x"es have different
+// scopes, they don't refer to the same type, and are therefore incompatible
+struct x {int a;} *c = b; // expected-warning {{incompatible pointer types}}
+}
+
+struct x {int a;} r;
+int b() {
+struct x {char x;} s = r; // expected-error {{incompatible type initializing}}
+}
diff --git a/test/Sema/struct-decl.c b/test/Sema/struct-decl.c
new file mode 100644
index 000000000000..2c0945f9f86b
--- /dev/null
+++ b/test/Sema/struct-decl.c
@@ -0,0 +1,43 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// PR3459
+struct bar {
+ char n[1];
+};
+
+struct foo {
+ char name[(int)&((struct bar *)0)->n];
+ char name2[(int)&((struct bar *)0)->n - 1]; //expected-error{{array size is negative}}
+};
+
+// PR3430
+struct s {
+ struct st {
+ int v;
+ } *ts;
+};
+
+struct st;
+
+int foo() {
+ struct st *f;
+ return f->v + f[0].v;
+}
+
+// PR3642, PR3671
+struct pppoe_tag {
+ short tag_type;
+ char tag_data[];
+};
+struct datatag {
+ struct pppoe_tag hdr; //expected-warning{{field 'hdr' with variable sized type 'struct pppoe_tag' not at the end of a struct or class is a GNU extension}}
+ char data;
+};
+
+
+// PR4092
+struct s0 {
+ char a; // expected-note {{previous declaration is here}}
+ char a; // expected-error {{duplicate member 'a'}}
+};
+
+struct s0 f0(void) {}
diff --git a/test/Sema/struct-packed-align.c b/test/Sema/struct-packed-align.c
new file mode 100644
index 000000000000..8250c14d4420
--- /dev/null
+++ b/test/Sema/struct-packed-align.c
@@ -0,0 +1,111 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+// Packed structs.
+struct s {
+ char a;
+ int b __attribute__((packed));
+ char c;
+ int d;
+};
+
+extern int a1[sizeof(struct s) == 12 ? 1 : -1];
+extern int a2[__alignof(struct s) == 4 ? 1 : -1];
+
+struct __attribute__((packed)) packed_s {
+ char a;
+ int b __attribute__((packed));
+ char c;
+ int d;
+};
+
+extern int b1[sizeof(struct packed_s) == 10 ? 1 : -1];
+extern int b2[__alignof(struct packed_s) == 1 ? 1 : -1];
+
+struct fas {
+ char a;
+ int b[];
+};
+
+extern int c1[sizeof(struct fas) == 4 ? 1 : -1];
+extern int c2[__alignof(struct fas) == 4 ? 1 : -1];
+
+struct __attribute__((packed)) packed_fas {
+ char a;
+ int b[];
+};
+
+extern int d1[sizeof(struct packed_fas) == 1 ? 1 : -1];
+extern int d2[__alignof(struct packed_fas) == 1 ? 1 : -1];
+
+// Alignment
+
+struct __attribute__((aligned(8))) as1 {
+ char c;
+};
+
+extern int e1[sizeof(struct as1) == 8 ? 1 : -1];
+extern int e2[__alignof(struct as1) == 8 ? 1 : -1];
+
+// FIXME: Will need to force arch once max usable alignment isn't hard
+// coded.
+struct __attribute__((aligned)) as1_2 {
+ char c;
+};
+extern int e1_2[sizeof(struct as1_2) == 16 ? 1 : -1];
+extern int e2_2[__alignof(struct as1_2) == 16 ? 1 : -1];
+
+struct as2 {
+ char c;
+ int __attribute__((aligned(8))) a;
+};
+
+extern int f1[sizeof(struct as2) == 16 ? 1 : -1];
+extern int f2[__alignof(struct as2) == 8 ? 1 : -1];
+
+struct __attribute__((packed)) as3 {
+ char c;
+ int a;
+ int __attribute__((aligned(8))) b;
+};
+
+extern int g1[sizeof(struct as3) == 16 ? 1 : -1];
+extern int g2[__alignof(struct as3) == 8 ? 1 : -1];
+
+
+// rdar://5921025
+struct packedtest {
+ int ted_likes_cheese;
+ void *args[] __attribute__((packed));
+};
+
+// Packed union
+union __attribute__((packed)) au4 {char c; int x;};
+extern int h1[sizeof(union au4) == 4 ? 1 : -1];
+extern int h2[__alignof(union au4) == 1 ? 1 : -1];
+
+// Aligned union
+union au5 {__attribute__((aligned(4))) char c;};
+extern int h1[sizeof(union au5) == 4 ? 1 : -1];
+extern int h2[__alignof(union au5) == 4 ? 1 : -1];
+
+// Alignment+packed
+struct as6 {char c; __attribute__((packed, aligned(2))) int x;};
+extern int i1[sizeof(struct as6) == 6 ? 1 : -1];
+extern int i2[__alignof(struct as6) == 2 ? 1 : -1];
+
+union au6 {char c; __attribute__((packed, aligned(2))) int x;};
+extern int k1[sizeof(union au6) == 4 ? 1 : -1];
+extern int k2[__alignof(union au6) == 2 ? 1 : -1];
+
+// Check postfix attributes
+union au7 {char c; int x;} __attribute__((packed));
+extern int l1[sizeof(union au7) == 4 ? 1 : -1];
+extern int l2[__alignof(union au7) == 1 ? 1 : -1];
+
+struct packed_fas2 {
+ char a;
+ int b[];
+} __attribute__((packed));
+
+extern int m1[sizeof(struct packed_fas2) == 1 ? 1 : -1];
+extern int m2[__alignof(struct packed_fas2) == 1 ? 1 : -1];
diff --git a/test/Sema/surpress-deprecated.c b/test/Sema/surpress-deprecated.c
new file mode 100644
index 000000000000..8dbe9dd36581
--- /dev/null
+++ b/test/Sema/surpress-deprecated.c
@@ -0,0 +1,7 @@
+// RUN: clang -fsyntax-only -Wno-deprecated-declarations -verify %s
+extern void OldFunction() __attribute__((deprecated));
+
+int main (int argc, const char * argv[]) {
+ OldFunction();
+}
+
diff --git a/test/Sema/switch.c b/test/Sema/switch.c
new file mode 100644
index 000000000000..5999f342aefa
--- /dev/null
+++ b/test/Sema/switch.c
@@ -0,0 +1,70 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f (int z) {
+ while (z) {
+ default: z--; // expected-error {{statement not in switch}}
+ }
+}
+
+void foo(int X) {
+ switch (X) {
+ case 42: ; // expected-note {{previous case}}
+ case 5000000000LL: // expected-warning {{overflow}}
+ case 42: // expected-error {{duplicate case value}}
+ ;
+
+ case 100 ... 99: ; // expected-warning {{empty case range}}
+
+ case 43: ; // expected-note {{previous case}}
+ case 43 ... 45: ; // expected-error {{duplicate case value}}
+
+ case 100 ... 20000:; // expected-note {{previous case}}
+ case 15000 ... 40000000:; // expected-error {{duplicate case value}}
+ }
+}
+
+void test3(void) {
+ // empty switch;
+ switch (0);
+}
+
+extern int g();
+
+void test4()
+{
+ switch (1) {
+ case 0 && g():
+ case 1 || g():
+ break;
+ }
+
+ switch(1) {
+ case g(): // expected-error {{expression is not an integer constant expression}}
+ case 0 ... g(): // expected-error {{expression is not an integer constant expression}}
+ break;
+ }
+
+ switch (1) {
+ case 0 && g() ... 1 || g():
+ break;
+ }
+
+ switch (1) {
+ case g() && 0: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}}
+ break;
+ }
+
+ switch (1) {
+ case 0 ... g() || 1: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}}
+ break;
+ }
+}
+
+void test5(int z) {
+ switch(z) {
+ default: // expected-note {{previous case defined here}}
+ default: // expected-error {{multiple default labels in one switch}}
+ break;
+ }
+}
+
diff --git a/test/Sema/tentative-decls.c b/test/Sema/tentative-decls.c
new file mode 100644
index 000000000000..e3c893c77718
--- /dev/null
+++ b/test/Sema/tentative-decls.c
@@ -0,0 +1,65 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+// PR3310
+struct a x1; // expected-note 2{{forward declaration of 'struct a'}}
+static struct a x2; // expected-error{{variable has incomplete type 'struct a'}}
+struct a x3[10]; // expected-error{{array has incomplete element type 'struct a'}}
+struct a {int x;};
+static struct a x2_okay;
+struct a x3_okay[10];
+struct b x4; // expected-error{{tentative definition has type 'struct b' that is never completed}} \
+ // expected-note{{forward declaration of 'struct b'}}
+
+const int a [1] = {1};
+extern const int a[];
+
+extern const int b[];
+const int b [1] = {1};
+
+extern const int c[] = {1}; // expected-warning{{'extern' variable has an initializer}}
+const int c[];
+
+int i1 = 1; // expected-note {{previous definition is here}}
+int i1 = 2; // expected-error {{redefinition of 'i1'}}
+int i1;
+int i1;
+extern int i5; // expected-note {{previous definition is here}}
+static int i5; // expected-error{{static declaration of 'i5' follows non-static declaration}}
+
+static int i2 = 5; // expected-note 1 {{previous definition is here}}
+int i2 = 3; // expected-error{{non-static declaration of 'i2' follows static declaration}}
+
+static int i3 = 5;
+extern int i3;
+
+__private_extern__ int pExtern;
+int pExtern = 0;
+
+int i4;
+int i4;
+extern int i4;
+
+int (*pToArray)[];
+int (*pToArray)[8];
+
+int redef[10];
+int redef[]; // expected-note {{previous definition is here}}
+int redef[11]; // expected-error{{redefinition of 'redef'}}
+
+void func() {
+ extern int i6; // expected-note {{previous definition is here}}
+ static int i6; // expected-error{{static declaration of 'i6' follows non-static declaration}}
+}
+
+void func2(void)
+{
+ extern double *p;
+ extern double *p;
+}
+
+// <rdar://problem/6808352>
+static int a0[];
+static int b0;
+
+static int a0[] = { 4 };
+static int b0 = 5;
diff --git a/test/Sema/text-diag.c b/test/Sema/text-diag.c
new file mode 100644
index 000000000000..19847c6d1e91
--- /dev/null
+++ b/test/Sema/text-diag.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only %s
+unsigned char *foo = "texto\
+que continua\
+e continua";
diff --git a/test/Sema/thread-specifier.c b/test/Sema/thread-specifier.c
new file mode 100644
index 000000000000..8d66e539c875
--- /dev/null
+++ b/test/Sema/thread-specifier.c
@@ -0,0 +1,21 @@
+// RUN: clang-cc -triple i686-pc-linux-gnu -fsyntax-only -verify %s
+
+__thread int t1;
+__thread extern int t2;
+__thread static int t3;
+__thread __private_extern__ int t4;
+struct t5 { __thread int x; }; // expected-error {{type name does not allow storage class to be specified}}
+__thread int t6(); // expected-error {{'__thread' is only allowed on variable declarations}}
+int f(__thread int t7) { // expected-error {{'__thread' is only allowed on variable declarations}}
+ __thread int t8; // expected-error {{'__thread' variables must have global storage}}
+ __thread extern int t9;
+ __thread static int t10;
+ __thread __private_extern__ int t11;
+ __thread auto int t12; // expected-error {{'__thread' variables must have global storage}}
+ __thread register int t13; // expected-error {{'__thread' variables must have global storage}}
+}
+__thread typedef int t14; // expected-error {{'__thread' is only allowed on variable declarations}}
+__thread int t15; // expected-note {{[previous definition is here}}
+int t15; // expected-error {{non-thread-local declaration of 't15' follows thread-local declaration}}
+int t16; // expected-note {{[previous definition is here}}
+__thread int t16; // expected-error {{thread-local declaration of 't16' follows non-thread-local declaration}}
diff --git a/test/Sema/transparent-union-pointer.c b/test/Sema/transparent-union-pointer.c
new file mode 100644
index 000000000000..ea761f17e7d6
--- /dev/null
+++ b/test/Sema/transparent-union-pointer.c
@@ -0,0 +1,14 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+typedef union {
+ union wait *__uptr;
+ int *__iptr;
+} __WAIT_STATUS __attribute__ ((__transparent_union__));
+
+extern int wait (__WAIT_STATUS __stat_loc);
+
+void fastcgi_cleanup() {
+ int status = 0;
+ wait(&status);
+}
+
diff --git a/test/Sema/transparent-union.c b/test/Sema/transparent-union.c
new file mode 100644
index 000000000000..90ecaadea6e7
--- /dev/null
+++ b/test/Sema/transparent-union.c
@@ -0,0 +1,40 @@
+// RUN: clang -fsyntax-only -Xclang -verify %s
+typedef union {
+ int *ip;
+ float *fp;
+} TU __attribute__((transparent_union));
+
+void f(TU);
+
+void g(int *ip, float *fp, char *cp) {
+ f(ip);
+ f(fp);
+ f(cp); // expected-error{{incompatible type}}
+ f(0);
+
+ TU tu_ip = ip; // expected-error{{incompatible type}}
+ TU tu;
+ tu.ip = ip;
+}
+
+/* FIXME: we'd like to just use an "int" here and align it differently
+ from the normal "int", but if we do so we lose the alignment
+ information from the typedef within the compiler. */
+typedef struct { int x, y; } __attribute__((aligned(8))) aligned_struct8;
+
+typedef struct { int x, y; } __attribute__((aligned(4))) aligned_struct4;
+typedef union {
+ aligned_struct4 s4; // expected-note{{alignment of first field}}
+ aligned_struct8 s8; // expected-warning{{alignment of field}}
+} TU1 __attribute__((transparent_union));
+
+typedef union {
+ char c; // expected-note{{size of first field is 8 bits}}
+ int i; // expected-warning{{size of field}}
+} TU2 __attribute__((transparent_union));
+
+typedef union {
+ float f; // expected-warning{{floating}}
+} TU3 __attribute__((transparent_union));
+
+typedef union { } TU4 __attribute__((transparent_union)); // expected-warning{{field}}
diff --git a/test/Sema/type-spec-struct-union.c b/test/Sema/type-spec-struct-union.c
new file mode 100644
index 000000000000..2b68b7877318
--- /dev/null
+++ b/test/Sema/type-spec-struct-union.c
@@ -0,0 +1,65 @@
+// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+
+/* This test checks the introduction of struct and union types based
+ on a type specifier of the form "struct-or-union identifier" when they
+ type has not yet been declared. See C99 6.7.2.3p8. */
+
+typedef struct S1 {
+ union {
+ struct S2 *x;
+ struct S3 *y;
+ } u1;
+} S1;
+
+int test_struct_scope(S1 *s1, struct S2 *s2, struct S3 *s3) {
+ if (s1->u1.x == s2) return 1;
+ if (s1->u1.y == s3) return 1;
+ return 0;
+}
+
+int test_struct_scope_2(S1 *s1) {
+ struct S2 { int x; } *s2 = 0;
+ if (s1->u1.x == s2) return 1; /* expected-warning {{comparison of distinct pointer types ('struct S2 *' and 'struct S2 *')}} */
+ return 0;
+}
+
+// FIXME: We do not properly implement C99 6.2.1p4, which says that
+// the type "struct S4" declared in the function parameter list has
+// block scope within the function definition. The problem, in this
+// case, is that the code is ill-formed but we warn about the two S4's
+// being incompatible (we think they are two different types).
+int test_struct_scope_3(struct S4 * s4) { // expected-warning{{declaration of 'struct S4' will not be visible outside of this function}}
+ struct S4 { int y; } *s4_2 = 0;
+ /* if (s4 == s4_2) return 1; */
+ return 0;
+}
+
+void f(struct S5 { int y; } s5); // expected-warning{{declaration of 'struct S5' will not be visible outside of this function}}
+
+// PR clang/3312
+struct S6 {
+ enum { BAR } e;
+};
+
+void test_S6() {
+ struct S6 a;
+ a.e = BAR;
+}
+
+// <rdar://problem/6487669>
+typedef struct z_foo_s {
+ struct bar_baz *baz;
+} z_foo;
+typedef z_foo *z_foop;
+struct bar_baz {
+ enum {
+ SQUAT, FLAG, DICT4, DICT3, DICT2, DICT1, DICT0, HOP, CHECK4, CHECK3, CHECK2, CHECK1, DONE, BAD
+ } mode;
+ int nowrap;
+};
+int
+wizbiz_quxPoof(z)
+ z_foop z;
+{
+ z->baz->mode = z->baz->nowrap ? HOP : SQUAT;
+}
diff --git a/test/Sema/typecheck-binop.c b/test/Sema/typecheck-binop.c
new file mode 100644
index 000000000000..f5bdcbb70e83
--- /dev/null
+++ b/test/Sema/typecheck-binop.c
@@ -0,0 +1,27 @@
+/* RUN: clang-cc %s -fsyntax-only -pedantic -verify
+ */
+struct incomplete; // expected-note{{forward declaration of 'struct incomplete'}}
+
+int sub1(int *a, double *b) {
+ return a - b; /* expected-error{{not pointers to compatible types}} */
+}
+
+void *sub2(struct incomplete *P) {
+ return P-4; /* expected-error{{subtraction of pointer 'struct incomplete *' requires pointee to be a complete object type}} */
+}
+
+void *sub3(void *P) {
+ return P-4; /* expected-warning{{GNU void* extension}} */
+}
+
+int sub4(void *P, void *Q) {
+ return P-Q; /* expected-warning{{GNU void* extension}} */
+}
+
+int sub5(void *P, int *Q) {
+ return P-Q; /* expected-error{{not pointers to compatible types}} */
+}
+
+int logicaland1(int a) {
+ return a && (void)a; /* expected-error{{invalid operands}} */
+}
diff --git a/test/Sema/typedef-prototype.c b/test/Sema/typedef-prototype.c
new file mode 100644
index 000000000000..fc0e05ead292
--- /dev/null
+++ b/test/Sema/typedef-prototype.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef int unary_int_func(int arg);
+unary_int_func add_one;
+
+int add_one(int arg) {
+ return arg + 1;
+}
diff --git a/test/Sema/typedef-redef.c b/test/Sema/typedef-redef.c
new file mode 100644
index 000000000000..9a1c48873242
--- /dev/null
+++ b/test/Sema/typedef-redef.c
@@ -0,0 +1,11 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef const int x; // expected-note {{previous definition is here}}
+extern x a;
+typedef int x; // expected-error {{typedef redefinition with different types}}
+extern x a;
+
+// <rdar://problem/6097585>
+int y; // expected-note 2 {{previous definition is here}}
+float y; // expected-error{{redefinition of 'y' with a different type}}
+double y; // expected-error{{redefinition of 'y' with a different type}}
diff --git a/test/Sema/typedef-retain.c b/test/Sema/typedef-retain.c
new file mode 100644
index 000000000000..ef9ec76f467b
--- /dev/null
+++ b/test/Sema/typedef-retain.c
@@ -0,0 +1,38 @@
+// RUN: clang-cc -fsyntax-only -verify %s -fno-lax-vector-conversions
+
+typedef float float4 __attribute__((vector_size(16)));
+typedef int int4 __attribute__((vector_size(16)));
+typedef int4* int4p;
+
+void test1(float4 a, int4 *result, int i) {
+ result[i] = a; // expected-error {{assigning 'float4', expected 'int4'}}
+}
+
+void test2(float4 a, int4p result, int i) {
+ result[i] = a; // expected-error {{assigning 'float4', expected 'int4'}}
+}
+
+// PR2039
+typedef int a[5];
+void test3() {
+ typedef const a b;
+ b r;
+ r[0]=10; // expected-error {{read-only variable is not assignable}}
+}
+
+int test4(const a y) {
+ y[0] = 10; // expected-error {{read-only variable is not assignable}}
+}
+
+// PR2189
+int test5() {
+ const int s[5]; int t[5];
+ return &s == &t; // expected-warning {{comparison of distinct pointer types}}
+}
+
+int test6() {
+ const a s;
+ a t;
+ return &s == &t; // expected-warning {{comparison of distinct pointer types}}
+}
+
diff --git a/test/Sema/typedef-variable-type.c b/test/Sema/typedef-variable-type.c
new file mode 100644
index 000000000000..7a9bb4879bc2
--- /dev/null
+++ b/test/Sema/typedef-variable-type.c
@@ -0,0 +1,3 @@
+// RUN: clang-cc %s -verify -fsyntax-only -pedantic
+
+typedef int (*a)[!.0]; // expected-warning{{size of static array must be an integer constant expression}}
diff --git a/test/Sema/types.c b/test/Sema/types.c
new file mode 100644
index 000000000000..e7d4b00a4d2a
--- /dev/null
+++ b/test/Sema/types.c
@@ -0,0 +1,39 @@
+// RUN: clang-cc %s -pedantic -verify -triple=x86_64-apple-darwin9
+
+// rdar://6097662
+typedef int (*T)[2];
+restrict T x;
+
+typedef int *S[2];
+restrict S y; // expected-error {{restrict requires a pointer or reference ('S' (aka 'int *[2]') is invalid)}}
+
+
+
+// int128_t is available.
+int a() {
+ __int128_t s;
+ __uint128_t t;
+}
+// but not a keyword
+int b() {
+ int __int128_t;
+ int __uint128_t;
+}
+
+
+// Array type merging should convert array size to whatever matches the target
+// pointer size.
+// rdar://6880874
+extern int i[1LL];
+int i[(short)1];
+
+enum e { e_1 };
+extern int j[sizeof(enum e)]; // expected-note {{previous definition}}
+int j[42]; // expected-error {{redefinition of 'j' with a different type}}
+
+// rdar://6880104
+_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 type}}
diff --git a/test/Sema/ucn-cstring.c b/test/Sema/ucn-cstring.c
new file mode 100644
index 000000000000..6d021fd82d16
--- /dev/null
+++ b/test/Sema/ucn-cstring.c
@@ -0,0 +1,17 @@
+// RUN: clang-cc %s -verify -fsyntax-only -pedantic
+
+#include <stdio.h>
+
+int main(void) {
+ int a[sizeof("hello \u2192 \u2603 \u2190 world") == 24 ? 1 : -1];
+
+ printf("%s (%d)\n", "hello \u2192 \u2603 \u2190 world", sizeof("hello \u2192 \u2603 \u2190 world"));
+ printf("%s (%d)\n", "\U00010400\U0001D12B", sizeof("\U00010400\U0001D12B"));
+ // Some error conditions...
+ printf("%s\n", "\U"); // expected-error{{\u used with no following hex digits}}
+ printf("%s\n", "\U00"); // expected-error{{incomplete universal character name}}
+ printf("%s\n", "\U0001"); // expected-error{{incomplete universal character name}}
+ printf("%s\n", "\u0001"); // expected-error{{invalid universal character}}
+ return 0;
+}
+
diff --git a/test/Sema/unnamed-bitfield-init.c b/test/Sema/unnamed-bitfield-init.c
new file mode 100644
index 000000000000..249f06e07d94
--- /dev/null
+++ b/test/Sema/unnamed-bitfield-init.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+typedef struct {
+ int a; int : 24; char b;
+} S;
+
+S a = { 1, 2 };
diff --git a/test/Sema/unused-expr.c b/test/Sema/unused-expr.c
new file mode 100644
index 000000000000..9c231e960a2a
--- /dev/null
+++ b/test/Sema/unused-expr.c
@@ -0,0 +1,46 @@
+// RUN: clang-cc -fsyntax-only -verify -fmath-errno=0 %s
+
+int foo(int X, int Y);
+
+double sqrt(double X); // implicitly const because of -fno-math-errno!
+
+void bar(volatile int *VP, int *P, int A,
+ _Complex double C, volatile _Complex double VC) {
+
+ VP == P; // expected-warning {{expression result unused}}
+ (void)A;
+ (void)foo(1,2); // no warning.
+
+ A == foo(1, 2); // expected-warning {{expression result unused}}
+
+ foo(1,2)+foo(4,3); // expected-warning {{expression result unused}}
+
+
+ *P; // expected-warning {{expression result unused}}
+ *VP; // no warning.
+ P[4]; // expected-warning {{expression result unused}}
+ VP[4]; // no warning.
+
+ __real__ C; // expected-warning {{expression result unused}}
+ __real__ VC;
+
+ // We know this can't change errno because of -fno-math-errno.
+ sqrt(A); // expected-warning {{expression result unused}}
+}
+
+extern void t1();
+extern void t2();
+void t3(int c) {
+ c ? t1() : t2();
+}
+
+// This shouldn't warn: the expr at the end of the stmtexpr really is used.
+int stmt_expr(int x, int y) {
+ return ({int _a = x, _b = y; _a > _b ? _a : _b; });
+}
+
+void nowarn(unsigned char* a, unsigned char* b)
+{
+ unsigned char c = 1;
+ *a |= c, *b += c;
+}
diff --git a/test/Sema/usual-float.c b/test/Sema/usual-float.c
new file mode 100644
index 000000000000..40c0bde4e0cf
--- /dev/null
+++ b/test/Sema/usual-float.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc %s -fsyntax-only
+
+typedef float CGFloat;
+
+extern void func(CGFloat);
+void foo(int dir, int n, int tindex) {
+ const float PI = 3.142;
+ CGFloat cgf = 3.4;
+
+ float ang = (float) tindex * (-dir*2.0f*PI/n);
+ func((CGFloat)cgf/65535.0f);
+}
diff --git a/test/Sema/va_arg_x86_32.c b/test/Sema/va_arg_x86_32.c
new file mode 100644
index 000000000000..850d324dbfc9
--- /dev/null
+++ b/test/Sema/va_arg_x86_32.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only -verify -triple=i686-pc-linux-gnu %s
+
+int a() {
+ __builtin_va_arg((char*)0, int); // expected-error {{expression is not assignable}}
+ __builtin_va_arg((void*){0}, int); // expected-error {{first argument to 'va_arg' is of type 'void *'}}
+}
diff --git a/test/Sema/va_arg_x86_64.c b/test/Sema/va_arg_x86_64.c
new file mode 100644
index 000000000000..680abb714b91
--- /dev/null
+++ b/test/Sema/va_arg_x86_64.c
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify -triple=x86_64-unknown-freebsd7.0 %s
+
+// PR2631
+char* foo(char *fmt, __builtin_va_list ap)
+{
+ return __builtin_va_arg((ap), char *);
+}
+
+// PR2692
+typedef __builtin_va_list va_list;
+static char *f (char * (*g) (char **, int), char **p, ...) {
+ char *s;
+ va_list v;
+ s = g (p, __builtin_va_arg(v, int));
+}
+
diff --git a/test/Sema/var-redecl.c b/test/Sema/var-redecl.c
new file mode 100644
index 000000000000..129fd17cd533
--- /dev/null
+++ b/test/Sema/var-redecl.c
@@ -0,0 +1,61 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int outer1; // expected-note{{previous definition is here}}
+extern int outer2; // expected-note{{previous definition is here}}
+int outer4;
+int outer4; // expected-note{{previous definition is here}}
+int outer5;
+int outer6(float); // expected-note{{previous definition is here}}
+int outer7(float);
+
+void outer_test() {
+ extern float outer1; // expected-error{{redefinition of 'outer1' with a different type}}
+ extern float outer2; // expected-error{{redefinition of 'outer2' with a different type}}
+ extern float outer3; // expected-note{{previous definition is here}}
+ double outer4;
+ extern int outer5; // expected-note{{previous definition is here}}
+ extern int outer6; // expected-error{{redefinition of 'outer6' as different kind of symbol}}
+ int outer7;
+ extern int outer8; // expected-note{{previous definition is here}}
+ extern int outer9;
+ {
+ extern int outer9; // expected-note{{previous definition is here}}
+ }
+}
+
+int outer3; // expected-error{{redefinition of 'outer3' with a different type}}
+float outer4; // expected-error{{redefinition of 'outer4' with a different type}}
+float outer5; // expected-error{{redefinition of 'outer5' with a different type}}
+int outer8(int); // expected-error{{redefinition of 'outer8' as different kind of symbol}}
+float outer9; // expected-error{{redefinition of 'outer9' with a different type}}
+
+extern int outer13; // expected-note{{previous definition is here}}
+void outer_shadowing_test() {
+ extern int outer10;
+ extern int outer11; // expected-note{{previous definition is here}}
+ extern int outer12; // expected-note{{previous definition is here}}
+ {
+ float outer10;
+ float outer11;
+ float outer12;
+ {
+ extern int outer10; // okay
+ extern float outer11; // expected-error{{redefinition of 'outer11' with a different type}}
+ static double outer12;
+ {
+ extern float outer12; // expected-error{{redefinition of 'outer12' with a different type}}
+ extern float outer13; // expected-error{{redefinition of 'outer13' with a different type}}
+ }
+ }
+ }
+}
+
+void g18(void) {
+ extern int g19;
+}
+int *p=&g19; // expected-error{{use of undeclared identifier 'g19'}}
+
+// PR3645
+static int a;
+extern int a;
+int a;
diff --git a/test/Sema/varargs-x86-64.c b/test/Sema/varargs-x86-64.c
new file mode 100644
index 000000000000..7c71c9673891
--- /dev/null
+++ b/test/Sema/varargs-x86-64.c
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s -triple x86_64-apple-darwin9
+
+// rdar://6726818
+void f1() {
+ const __builtin_va_list args2;
+ (void)__builtin_va_arg(args2, int); // expected-error {{first argument to 'va_arg' is of type '__builtin_va_list const' and not 'va_list'}}
+}
+
diff --git a/test/Sema/varargs.c b/test/Sema/varargs.c
new file mode 100644
index 000000000000..8d2f0b1fa83e
--- /dev/null
+++ b/test/Sema/varargs.c
@@ -0,0 +1,63 @@
+// RUN: clang-cc -fsyntax-only -verify %s &&
+// RUN: clang-cc -fsyntax-only -verify %s -triple x86_64-apple-darwin9
+
+void f1(int a)
+{
+ __builtin_va_list ap;
+
+ __builtin_va_start(ap, a, a); // expected-error {{too many arguments to function}}
+ __builtin_va_start(ap, a); // expected-error {{'va_start' used in function with fixed args}}
+}
+
+void f2(int a, int b, ...)
+{
+ __builtin_va_list ap;
+
+ __builtin_va_start(ap, 10); // expected-warning {{second parameter of 'va_start' not last named argument}}
+ __builtin_va_start(ap, a); // expected-warning {{second parameter of 'va_start' not last named argument}}
+ __builtin_va_start(ap, b);
+}
+
+void f3(float a, ...)
+{
+ __builtin_va_list ap;
+
+ __builtin_va_start(ap, a);
+ __builtin_va_start(ap, (a));
+}
+
+
+// stdarg: PR3075
+void f4(const char *msg, ...) {
+ __builtin_va_list ap;
+ __builtin_stdarg_start((ap), (msg));
+ __builtin_va_end (ap);
+}
+
+void f5() {
+ __builtin_va_list ap;
+ __builtin_va_start(ap,ap); // expected-error {{'va_start' used in function with fixed args}}
+}
+
+void f6(int a, ...) {
+ __builtin_va_list ap;
+ __builtin_va_start(ap); // expected-error {{too few arguments to function}}
+}
+
+// PR3350
+void
+foo(__builtin_va_list authors, ...) {
+ __builtin_va_start (authors, authors);
+ (void)__builtin_va_arg(authors, int);
+ __builtin_va_end (authors);
+}
+
+void f7(int a, ...) {
+ __builtin_va_list ap;
+ __builtin_va_start(ap, a);
+ // FIXME: This error message is sub-par.
+ __builtin_va_arg(ap, int) = 1; // expected-error {{expression is not assignable}}
+ int *x = &__builtin_va_arg(ap, int); // expected-error {{address expression must be an lvalue or a function designator}}
+ __builtin_va_end(ap);
+}
+
diff --git a/test/Sema/variadic-block.c b/test/Sema/variadic-block.c
new file mode 100644
index 000000000000..29f597b00672
--- /dev/null
+++ b/test/Sema/variadic-block.c
@@ -0,0 +1,41 @@
+// RUN: clang-cc %s -verify -fsyntax-only -fblocks
+
+#include <stdarg.h>
+
+int main(int argc, char *argv[]) {
+
+ long (^addthem)(const char *, ...) = ^long (const char *format, ...){
+ va_list argp;
+ const char *p;
+ int i;
+ char c;
+ double d;
+ long result = 0;
+ va_start(argp, format);
+ for (p = format; *p; p++) switch (*p) {
+ case 'i':
+ i = va_arg(argp, int);
+ result += i;
+ break;
+ case 'd':
+ d = va_arg(argp, double);
+ result += (int)d;
+ break;
+ case 'c':
+ c = va_arg(argp, int);
+ result += c;
+ break;
+ }
+ return result;
+ };
+ long testresult = addthem("ii", 10, 20);
+ if (testresult != 30) {
+ return 1;
+ }
+ testresult = addthem("idc", 30, 40.0, 'a');
+ if (testresult != (70+'a')) {
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/test/Sema/vector-assign.c b/test/Sema/vector-assign.c
new file mode 100644
index 000000000000..5162e1a41c21
--- /dev/null
+++ b/test/Sema/vector-assign.c
@@ -0,0 +1,45 @@
+// RUN: clang-cc %s -verify -fsyntax-only -Wvector-conversions
+typedef unsigned int v2u __attribute__ ((vector_size (8)));
+typedef signed int v2s __attribute__ ((vector_size (8)));
+typedef signed int v1s __attribute__ ((vector_size (4)));
+typedef float v2f __attribute__ ((vector_size(8)));
+typedef signed short v4ss __attribute__ ((vector_size (8)));
+
+void f() {
+ v2s v1;
+ v2u v2;
+ v1s v3;
+ v2f v4;
+ v4ss v5;
+
+ v1 = v2; // expected-warning {{incompatible vector types assigning 'v2u', expected 'v2s'}}
+ v1 = v3; // expected-error {{incompatible type assigning 'v1s', expected 'v2s'}}
+ v1 = v4; // expected-warning {{incompatible vector types assigning 'v2f', expected 'v2s'}}
+ v1 = v5; // expected-warning {{incompatible vector types assigning 'v4ss', expected 'v2s'}}
+
+ v2 = v1; // expected-warning {{incompatible vector types assigning 'v2s', expected 'v2u'}}
+ v2 = v3; // expected-error {{incompatible type assigning 'v1s', expected 'v2u'}}
+ v2 = v4; // expected-warning {{incompatible vector types assigning 'v2f', expected 'v2u'}}
+ v2 = v5; // expected-warning {{incompatible vector types assigning 'v4ss', expected 'v2u'}}
+
+ v3 = v1; // expected-error {{incompatible type assigning 'v2s', expected 'v1s'}}
+ v3 = v2; // expected-error {{incompatible type assigning 'v2u', expected 'v1s'}}
+ v3 = v4; // expected-error {{incompatible type assigning 'v2f', expected 'v1s'}}
+ v3 = v5; // expected-error {{incompatible type assigning 'v4ss', expected 'v1s'}}
+
+ v4 = v1; // expected-warning {{incompatible vector types assigning 'v2s', expected 'v2f'}}
+ v4 = v2; // expected-warning {{incompatible vector types assigning 'v2u', expected 'v2f'}}
+ v4 = v3; // expected-error {{incompatible type assigning 'v1s', expected 'v2f'}}
+ v4 = v5; // expected-warning {{incompatible vector types assigning 'v4ss', expected 'v2f'}}
+
+ v5 = v1; // expected-warning {{incompatible vector types assigning 'v2s', expected 'v4ss'}}
+ v5 = v2; // expected-warning {{incompatible vector types assigning 'v2u', expected 'v4ss'}}
+ v5 = v3; // expected-error {{incompatible type assigning 'v1s', expected 'v4ss'}}
+ v5 = v4; // expected-warning {{incompatible vector types assigning 'v2f', expected 'v4ss'}}
+}
+
+// PR2263
+float f2(__attribute__((vector_size(16))) float a, int b) {
+ return a[b];
+}
+
diff --git a/test/Sema/vector-cast.c b/test/Sema/vector-cast.c
new file mode 100644
index 000000000000..bd09e69800cc
--- /dev/null
+++ b/test/Sema/vector-cast.c
@@ -0,0 +1,38 @@
+// RUN: clang-cc -fsyntax-only %s -verify -Wvector-conversions
+
+typedef long long t1 __attribute__ ((vector_size (8)));
+typedef char t2 __attribute__ ((vector_size (16)));
+typedef float t3 __attribute__ ((vector_size (16)));
+
+void f()
+{
+ t1 v1;
+ t2 v2;
+ t3 v3;
+
+ v2 = (t2)v1; // -expected-error {{invalid conversion between vector type \
+'t1' and 't2' of different size}}
+ v1 = (t1)v2; // -expected-error {{invalid conversion between vector type \
+'t2' and 't1' of different size}}
+ v3 = (t3)v2;
+
+ v1 = (t1)(char *)10; // -expected-error {{invalid conversion between vector \
+type 't1' and scalar type 'char *'}}
+ v1 = (t1)(long long)10;
+ v1 = (t1)(short)10; // -expected-error {{invalid conversion between vector \
+type 't1' and integer type 'int' of different size}}
+
+ long long r1 = (long long)v1;
+ short r2 = (short)v1; // -expected-error {{invalid conversion between vector \
+type 't1' and integer type 'short' of different size}}
+ char *r3 = (char *)v1; // -expected-error {{invalid conversion between vector\
+ type 't1' and scalar type 'char *'}}
+}
+
+
+void f2(t2 X);
+
+void f3(t3 Y) {
+ f2(Y); // expected-warning {{incompatible vector types passing 't3', expected 't2'}}
+}
+
diff --git a/test/Sema/vector-init.c b/test/Sema/vector-init.c
new file mode 100644
index 000000000000..6eab32425adf
--- /dev/null
+++ b/test/Sema/vector-init.c
@@ -0,0 +1,23 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+//typedef __attribute__(( ext_vector_type(4) )) float float4;
+typedef float float4 __attribute__((vector_size(16)));
+
+float4 foo = (float4){ 1.0, 2.0, 3.0, 4.0 };
+
+float4 foo2 = (float4){ 1.0, 2.0, 3.0, 4.0 , 5.0 }; // expected-warning{{excess elements in vector initializer}}
+
+float4 array[] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
+int array_sizecheck[(sizeof(array) / sizeof(float4)) == 3? 1 : -1];
+
+float4 array2[2] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0,
+ 9.0 }; // expected-warning {{excess elements in array initializer}}
+
+float4 array3[2] = { {1.0, 2.0, 3.0}, 5.0, 6.0, 7.0, 8.0,
+ 9.0 }; // expected-warning {{excess elements in array initializer}}
+
+
+// rdar://6881069
+__attribute__((vector_size(16))) // expected-error {{unsupported type 'float (void)' for vector_size attribute, please use on typedef}}
+float f1(void) {
+}
diff --git a/test/Sema/vla.c b/test/Sema/vla.c
new file mode 100644
index 000000000000..70ba08b7eb0a
--- /dev/null
+++ b/test/Sema/vla.c
@@ -0,0 +1,56 @@
+// RUN: clang-cc %s -verify -fsyntax-only -pedantic
+
+int test1() {
+ typedef int x[test1()]; // vla
+ static int y = sizeof(x); // expected-error {{not a compile-time constant}}
+}
+
+// PR2347
+void f (unsigned int m)
+{
+ int e[2][m];
+
+ e[0][0] = 0;
+}
+
+// PR3048
+int x = sizeof(struct{char qq[x];}); // expected-error {{fields must have a constant size}}
+
+// PR2352
+void f2(unsigned int m)
+{
+ extern int e1[2][m]; // expected-error {{variable length array declaration can not have 'extern' linkage}}
+
+ e1[0][0] = 0;
+
+}
+
+// PR2361
+int i;
+int c[][i]; // expected-error {{variably modified type declaration not allowed at file scope}}
+int d[i]; // expected-error {{variable length array declaration not allowed at file scope}}
+
+int (*e)[i]; // expected-error {{variably modified type declaration not allowed at file scope}}
+
+void f3()
+{
+ static int a[i]; // expected-error {{variable length array declaration can not have 'static' storage duration}}
+ extern int b[i]; // expected-error {{variable length array declaration can not have 'extern' linkage}}
+
+ extern int (*c1)[i]; // expected-error {{variably modified type declaration can not have 'extern' linkage}}
+ static int (*d)[i];
+}
+
+// PR3663
+static const unsigned array[((2 * (int)((((4) / 2) + 1.0/3.0) * (4) - 1e-8)) + 1)]; // expected-warning {{size of static array must be an integer constant expression}}
+
+int a[*]; // expected-error {{star modifier used outside of function prototype}}
+int f4(int a[*][*]);
+
+// PR2044
+int pr2044(int b) {int (*c(void))[b];**c() = 2;} // expected-error {{variably modified type}}
+int pr2044b;
+int (*pr2044c(void))[pr2044b]; // expected-error {{variably modified type}}
+
+const int f5_ci = 1;
+void f5() { char a[][f5_ci] = {""}; } // expected-error {{variable-sized object may not be initialized}}
diff --git a/test/Sema/void_arg.c b/test/Sema/void_arg.c
new file mode 100644
index 000000000000..6799146a5ff9
--- /dev/null
+++ b/test/Sema/void_arg.c
@@ -0,0 +1,26 @@
+/* RUN: clang-cc -fsyntax-only %s -verify
+ */
+
+typedef void Void;
+
+void foo() {
+ int X;
+
+ X = sizeof(int (void a)); // expected-error {{argument may not have 'void' type}}
+ X = sizeof(int (int, void)); // expected-error {{must be the first and only parameter}}
+ X = sizeof(int (void, ...)); // expected-error {{must be the first and only parameter}}
+
+ X = sizeof(int (Void a)); // expected-error {{argument may not have 'void' type}}
+ X = sizeof(int (int, Void)); // expected-error {{must be the first and only parameter}}
+ X = sizeof(int (Void, ...)); // expected-error {{must be the first and only parameter}}
+
+ // Accept these.
+ X = sizeof(int (void));
+ X = sizeof(int (Void));
+}
+
+// this is ok.
+void bar(Void) {
+}
+
+void f(const void); // expected-error {{parameter must not have type qualifiers}}
diff --git a/test/Sema/warn-freestanding-complex.c b/test/Sema/warn-freestanding-complex.c
new file mode 100644
index 000000000000..a4d3f5be3189
--- /dev/null
+++ b/test/Sema/warn-freestanding-complex.c
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only -ffreestanding -pedantic -verify %s
+
+void foo(float _Complex c) { // expected-warning{{complex numbers are an extension in a freestanding C99 implementation}}
+}
diff --git a/test/Sema/warn-missing-prototypes.c b/test/Sema/warn-missing-prototypes.c
new file mode 100644
index 000000000000..299d8a726585
--- /dev/null
+++ b/test/Sema/warn-missing-prototypes.c
@@ -0,0 +1,37 @@
+// RUN: clang -Wmissing-prototypes -fsyntax-only -Xclang -verify %s
+
+int f();
+
+int f(int x) { return x; } // expected-warning{{no previous prototype for function 'f'}}
+
+static int g(int x) { return x; }
+
+int h(int x) { return x; } // expected-warning{{no previous prototype for function 'h'}}
+
+static int g2();
+
+int g2(int x) { return x; }
+
+void test(void);
+
+int h3();
+int h4(int);
+int h4();
+
+void test(void) {
+ int h2(int x);
+ int h3(int x);
+ int h4();
+}
+
+int h2(int x) { return x; } // expected-warning{{no previous prototype for function 'h2'}}
+int h3(int x) { return x; } // expected-warning{{no previous prototype for function 'h3'}}
+int h4(int x) { return x; }
+
+int f2(int);
+int f2();
+
+int f2(int x) { return x; }
+
+// rdar://6759522
+int main(void) { return 0; }
diff --git a/test/Sema/wchar.c b/test/Sema/wchar.c
new file mode 100644
index 000000000000..16376009ab13
--- /dev/null
+++ b/test/Sema/wchar.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+#include <wchar.h>
+
+int check_wchar_size[sizeof(*L"") == sizeof(wchar_t) ? 1 : -1];
+
+void foo() {
+ int t1[] = L"x";
+ wchar_t tab[] = L"x";
+
+ int t2[] = "x"; // expected-error {{initialization}}
+ char t3[] = L"x"; // expected-error {{initialization}}
+}
diff --git a/test/SemaCXX/__null.cpp b/test/SemaCXX/__null.cpp
new file mode 100644
index 000000000000..4672801fd7bb
--- /dev/null
+++ b/test/SemaCXX/__null.cpp
@@ -0,0 +1,14 @@
+// RUN: clang-cc -triple x86_64-unknown-unknown %s -fsyntax-only -verify &&
+// RUN: clang-cc -triple i686-unknown-unknown %s -fsyntax-only -verify
+
+void f() {
+ int* i = __null;
+ i = __null;
+ int i2 = __null;
+
+ // Verify statically that __null is the right size
+ int a[sizeof(typeof(__null)) == sizeof(void*)? 1 : -1];
+
+ // Verify that null is evaluated as 0.
+ int b[__null ? -1 : 1];
+}
diff --git a/test/SemaCXX/abstract.cpp b/test/SemaCXX/abstract.cpp
new file mode 100644
index 000000000000..dc764da5322b
--- /dev/null
+++ b/test/SemaCXX/abstract.cpp
@@ -0,0 +1,128 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+
+#ifndef __GXX_EXPERIMENTAL_CXX0X__
+#define __CONCAT(__X, __Y) __CONCAT1(__X, __Y)
+#define __CONCAT1(__X, __Y) __X ## __Y
+
+#define static_assert(__b, __m) \
+ typedef int __CONCAT(__sa, __LINE__)[__b ? 1 : -1]
+#endif
+
+class C {
+ virtual void f() = 0; // expected-note {{pure virtual function 'f'}}
+};
+
+static_assert(__is_abstract(C), "C has a pure virtual function");
+
+class D : C {
+};
+
+static_assert(__is_abstract(D), "D inherits from an abstract class");
+
+class E : D {
+ virtual void f();
+};
+
+static_assert(!__is_abstract(E), "E inherits from an abstract class but implements f");
+
+C *d = new C; // expected-error {{allocation of an object of abstract type 'C'}}
+
+C c; // expected-error {{variable type 'C' is an abstract class}}
+void t1(C c); // expected-error {{parameter type 'C' is an abstract class}}
+void t2(C); // expected-error {{parameter type 'C' is an abstract class}}
+
+struct S {
+ C c; // expected-error {{field type 'C' is an abstract class}}
+};
+
+void t3(const C&);
+
+void f() {
+ C(); // expected-error {{allocation of an object of abstract type 'C'}}
+ t3(C()); // expected-error {{allocation of an object of abstract type 'C'}}
+}
+
+C e1[2]; // expected-error {{variable type 'C' is an abstract class}}
+C (*e2)[2]; // expected-error {{variable type 'C' is an abstract class}}
+C (**e3)[2]; // expected-error {{variable type 'C' is an abstract class}}
+
+void t4(C c[2]); // expected-error {{parameter type 'C' is an abstract class}}
+
+void t5(void (*)(C)); // expected-error {{parameter type 'C' is an abstract class}}
+
+typedef void (*Func)(C); // expected-error {{parameter type 'C' is an abstract class}}
+void t6(Func);
+
+class F {
+ F a() { } // expected-error {{return type 'F' is an abstract class}}
+
+ class D {
+ void f(F c); // expected-error {{parameter type 'F' is an abstract class}}
+ };
+
+ union U {
+ void u(F c); // expected-error {{parameter type 'F' is an abstract class}}
+ };
+
+ virtual void f() = 0; // expected-note {{pure virtual function 'f'}}
+};
+
+class Abstract;
+
+void t7(Abstract a); // expected-error {{parameter type 'Abstract' is an abstract class}}
+
+void t8() {
+ void h(Abstract a); // expected-error {{parameter type 'Abstract' is an abstract class}}
+}
+
+namespace N {
+ void h(Abstract a); // expected-error {{parameter type 'Abstract' is an abstract class}}
+}
+
+class Abstract {
+ virtual void f() = 0; // expected-note {{pure virtual function 'f'}}
+};
+
+// <rdar://problem/6854087>
+class foo {
+public:
+ virtual foo *getFoo() = 0;
+};
+
+class bar : public foo {
+public:
+ virtual bar *getFoo();
+};
+
+bar x;
+
+// <rdar://problem/6902298>
+class A
+{
+public:
+ virtual void release() = 0;
+ virtual void release(int count) = 0;
+ virtual void retain() = 0;
+};
+
+class B : public A
+{
+public:
+ virtual void release();
+ virtual void release(int count);
+ virtual void retain();
+};
+
+void foo(void)
+{
+ B b;
+}
+
+struct K {
+ int f;
+ virtual ~K();
+};
+
+struct L : public K {
+ void f();
+};
diff --git a/test/SemaCXX/access-base-class.cpp b/test/SemaCXX/access-base-class.cpp
new file mode 100644
index 000000000000..4a9ee51dbfb5
--- /dev/null
+++ b/test/SemaCXX/access-base-class.cpp
@@ -0,0 +1,82 @@
+// RUN: clang-cc -fsyntax-only -faccess-control -verify %s
+namespace T1 {
+
+class A { };
+class B : private A { }; // expected-note {{'private' inheritance specifier here}}
+
+void f(B* b) {
+ A *a = b; // expected-error{{conversion from 'class T1::B' to inaccessible base class 'class T1::A'}} \
+ expected-error{{incompatible type initializing 'class T1::B *', expected 'class T1::A *'}}
+}
+
+}
+
+namespace T2 {
+
+class A { };
+class B : A { }; // expected-note {{inheritance is implicitly 'private'}}
+
+void f(B* b) {
+ A *a = b; // expected-error {{conversion from 'class T2::B' to inaccessible base class 'class T2::A'}} \
+ expected-error {{incompatible type initializing 'class T2::B *', expected 'class T2::A *'}}
+}
+
+}
+
+namespace T3 {
+
+class A { };
+class B : public A { };
+
+void f(B* b) {
+ A *a = b;
+}
+
+}
+
+namespace T4 {
+
+class A {};
+
+class B : private virtual A {};
+class C : public virtual A {};
+
+class D : public B, public C {};
+
+void f(D *d) {
+ // This takes the D->C->B->A path.
+ A *a = d;
+}
+
+}
+
+namespace T5 {
+ class A {};
+
+ class B : private A {
+ void f(B *b) {
+ A *a = b;
+ }
+ };
+}
+
+namespace T6 {
+ class C;
+
+ class A {};
+
+ class B : private A { // expected-note {{'private' inheritance specifier here}}
+ void f(C* c);
+ };
+
+ class C : public B {
+ void f(C *c) {
+ A* a = c; // expected-error {{conversion from 'class T6::C' to inaccessible base class 'class T6::A'}} \
+ expected-error {{incompatible type initializing 'class T6::C *', expected 'class T6::A *'}}
+ }
+ };
+
+ void B::f(C *c) {
+ A *a = c;
+ }
+}
diff --git a/test/SemaCXX/access.cpp b/test/SemaCXX/access.cpp
new file mode 100644
index 000000000000..cfbc9c80692b
--- /dev/null
+++ b/test/SemaCXX/access.cpp
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class C {
+ struct S; // expected-note {{previously declared 'private' here}}
+public:
+
+ struct S {}; // expected-error {{'S' redeclared with 'public' access}}
+};
+
+struct S {
+ class C; // expected-note {{previously declared 'public' here}}
+
+private:
+ class C { }; // expected-error {{'C' redeclared with 'private' access}}
+};
+
+class T {
+protected:
+ template<typename T> struct A; // expected-note {{previously declared 'protected' here}}
+
+private:
+ template<typename T> struct A {}; // expected-error {{'A' redeclared with 'private' access}}
+};
diff --git a/test/SemaCXX/addr-of-overloaded-function.cpp b/test/SemaCXX/addr-of-overloaded-function.cpp
new file mode 100644
index 000000000000..9c9f0e19ef3c
--- /dev/null
+++ b/test/SemaCXX/addr-of-overloaded-function.cpp
@@ -0,0 +1,29 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+int f(double);
+int f(int);
+
+int (*pfd)(double) = f; // selects f(double)
+int (*pfd2)(double) = &f; // selects f(double)
+int (*pfd3)(double) = ((&((f)))); // selects f(double)
+int (*pfi)(int) = &f; // selects f(int)
+// FIXME: This error message is not very good. We need to keep better
+// track of what went wrong when the implicit conversion failed to
+// give a better error message here.
+int (*pfe)(...) = &f; // expected-error{{incompatible type initializing '<overloaded function type>', expected 'int (*)(...)'}}
+int (&rfi)(int) = f; // selects f(int)
+int (&rfd)(double) = f; // selects f(double)
+
+void g(int (*fp)(int)); // expected-note{{note: candidate function}}
+void g(int (*fp)(float));
+void g(int (*fp)(double)); // expected-note{{note: candidate function}}
+
+int g1(int);
+int g1(char);
+
+int g2(int);
+int g2(double);
+
+void g_test() {
+ g(g1);
+ g(g2); // expected-error{{call to 'g' is ambiguous; candidates are:}}
+}
diff --git a/test/SemaCXX/address-of.cpp b/test/SemaCXX/address-of.cpp
new file mode 100644
index 000000000000..4e436d6e98b2
--- /dev/null
+++ b/test/SemaCXX/address-of.cpp
@@ -0,0 +1,35 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// PR clang/3175
+
+void bar(int*);
+
+class c {
+ int var;
+ static int svar;
+ void foo() {
+ bar(&var);
+ bar(&svar);
+ }
+
+ static void wibble() {
+ bar(&var); // expected-error{{invalid use of member 'var' in static member function}}
+ bar(&svar);
+ }
+};
+
+enum E {
+ Enumerator
+};
+
+void test() {
+ (void)&Enumerator; // expected-error{{address expression must be an lvalue or a function designator}}
+}
+
+template<int N>
+void test2() {
+ (void)&N; // expected-error{{address expression must be an lvalue or a function designator}}
+}
+
+// PR clang/3222
+void xpto();
+void (*xyz)(void) = &xpto;
diff --git a/test/SemaCXX/aggregate-initialization.cpp b/test/SemaCXX/aggregate-initialization.cpp
new file mode 100644
index 000000000000..c96eda448032
--- /dev/null
+++ b/test/SemaCXX/aggregate-initialization.cpp
@@ -0,0 +1,28 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++98 %s
+
+// Verify that we can't initialize non-aggregates with an initializer
+// list.
+struct NonAggr1 {
+ NonAggr1(int) { }
+
+ int m;
+};
+
+struct Base { };
+struct NonAggr2 : public Base {
+ int m;
+};
+
+class NonAggr3 {
+ int m;
+};
+
+struct NonAggr4 {
+ int m;
+ virtual void f();
+};
+
+NonAggr1 na1 = { 17 }; // expected-error{{initialization of non-aggregate type 'struct NonAggr1' with an initializer list}}
+NonAggr2 na2 = { 17 }; // expected-error{{initialization of non-aggregate type 'struct NonAggr2' with an initializer list}}
+NonAggr3 na3 = { 17 }; // expected-error{{initialization of non-aggregate type 'class NonAggr3' with an initializer list}}
+NonAggr4 na4 = { 17 }; // expected-error{{initialization of non-aggregate type 'struct NonAggr4' with an initializer list}}
diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp
new file mode 100644
index 000000000000..f77fa03328f6
--- /dev/null
+++ b/test/SemaCXX/anonymous-union.cpp
@@ -0,0 +1,113 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct X {
+ union {
+ float f3;
+ double d2;
+ } named;
+
+ union {
+ int i;
+ float f;
+
+ union {
+ float f2;
+ mutable double d;
+ };
+ };
+
+ void test_unqual_references();
+
+ struct {
+ int a;
+ float b;
+ };
+
+ void test_unqual_references_const() const;
+
+ mutable union { // expected-error{{anonymous union at class scope must not have a storage specifier}}
+ float c1;
+ double c2;
+ };
+};
+
+void X::test_unqual_references() {
+ i = 0;
+ f = 0.0;
+ f2 = f;
+ d = f;
+ f3 = 0; // expected-error{{use of undeclared identifier 'f3'}}
+ a = 0;
+}
+
+void X::test_unqual_references_const() const {
+ d = 0.0;
+ f2 = 0; // expected-error{{read-only variable is not assignable}}
+ a = 0; // expected-error{{read-only variable is not assignable}}
+}
+
+void test_unqual_references(X x, const X xc) {
+ x.i = 0;
+ x.f = 0.0;
+ x.f2 = x.f;
+ x.d = x.f;
+ x.f3 = 0; // expected-error{{no member named 'f3'}}
+ x.a = 0;
+
+ xc.d = 0.0;
+ xc.f = 0; // expected-error{{read-only variable is not assignable}}
+ xc.a = 0; // expected-error{{read-only variable is not assignable}}
+}
+
+
+struct Redecl {
+ int x; // expected-note{{previous declaration is here}}
+ class y { };
+
+ union {
+ int x; // expected-error{{member of anonymous union redeclares 'x'}}
+ float y;
+ double z; // expected-note{{previous declaration is here}}
+ double zz; // expected-note{{previous definition is here}}
+ };
+
+ int z; // expected-error{{duplicate member 'z'}}
+ void zz(); // expected-error{{redefinition of 'zz' as different kind of symbol}}
+};
+
+union { // expected-error{{anonymous unions at namespace or global scope must be declared 'static'}}
+ int int_val;
+ float float_val;
+};
+
+static union {
+ int int_val2;
+ float float_val2;
+};
+
+void f() {
+ int_val2 = 0;
+ float_val2 = 0.0;
+}
+
+void g() {
+ union {
+ int i;
+ float f2;
+ };
+ i = 0;
+ f2 = 0.0;
+}
+
+struct BadMembers {
+ union {
+ struct X { }; // expected-error {{types cannot be declared in an anonymous union}}
+ struct { int x; int y; } y;
+
+ void f(); // expected-error{{functions cannot be declared in an anonymous union}}
+ private: int x1; // expected-error{{anonymous union cannot contain a private data member}}
+ protected: float x2; // expected-error{{anonymous union cannot contain a protected data member}}
+ };
+};
+
+// <rdar://problem/6481130>
+typedef union { }; // expected-error{{declaration does not declare anything}}
diff --git a/test/SemaCXX/attr-unavailable.cpp b/test/SemaCXX/attr-unavailable.cpp
new file mode 100644
index 000000000000..8e5f76bcacfa
--- /dev/null
+++ b/test/SemaCXX/attr-unavailable.cpp
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int &foo(int);
+double &foo(double);
+void foo(...) __attribute__((__unavailable__)); // expected-note {{candidate function}} \
+// expected-note{{function has been explicitly marked unavailable here}}
+
+void bar(...) __attribute__((__unavailable__)); // expected-note 2{{explicitly marked unavailable}}
+
+void test_foo(short* sp) {
+ int &ir = foo(1);
+ double &dr = foo(1.0);
+ foo(sp); // expected-error{{call to unavailable function 'foo'}}
+
+ void (*fp)(...) = &bar; // expected-warning{{'bar' is unavailable}}
+ void (*fp2)(...) = bar; // expected-warning{{'bar' is unavailable}}
+
+ int &(*fp3)(int) = foo;
+ void (*fp4)(...) = foo; // expected-warning{{'foo' is unavailable}}
+}
diff --git a/test/SemaCXX/basic_lookup_argdep.cpp b/test/SemaCXX/basic_lookup_argdep.cpp
new file mode 100644
index 000000000000..486a688d9437
--- /dev/null
+++ b/test/SemaCXX/basic_lookup_argdep.cpp
@@ -0,0 +1,60 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace N {
+ struct X { };
+
+ X operator+(X, X);
+
+ void f(X);
+ void g(X); // expected-note{{candidate function}}
+
+ void test_multiadd(X x) {
+ (void)(x + x);
+ }
+}
+
+namespace M {
+ struct Y : N::X { };
+}
+
+void f();
+
+void test_operator_adl(N::X x, M::Y y) {
+ (void)(x + x);
+ (void)(y + y);
+}
+
+void test_func_adl(N::X x, M::Y y) {
+ f(x);
+ f(y);
+ (f)(x); // expected-error{{too many arguments to function call}}
+ ::f(x); // expected-error{{too many arguments to function call}}
+}
+
+namespace N {
+ void test_multiadd2(X x) {
+ (void)(x + x);
+ }
+}
+
+
+void test_func_adl_only(N::X x) {
+ g(x);
+}
+
+namespace M {
+ int g(N::X); // expected-note{{candidate function}}
+
+ void test(N::X x) {
+ g(x); // expected-error{{call to 'g' is ambiguous; candidates are:}}
+ int i = (g)(x);
+
+ int g(N::X);
+ g(x); // okay; calls locally-declared function, no ADL
+ }
+}
+
+
+void test_operator_name_adl(N::X x) {
+ (void)operator+(x, x);
+}
diff --git a/test/SemaCXX/blocks.cpp b/test/SemaCXX/blocks.cpp
new file mode 100644
index 000000000000..9d789bb3252a
--- /dev/null
+++ b/test/SemaCXX/blocks.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-cc -fsyntax-only -verify %s -fblocks
+
+void tovoid(void*);
+
+void tovoid_test(int (^f)(int, int)) {
+ tovoid(f);
+}
+
+void reference_lvalue_test(int& (^f)()) {
+ f() = 10;
+}
diff --git a/test/SemaCXX/bool.cpp b/test/SemaCXX/bool.cpp
new file mode 100644
index 000000000000..bc44c73d8cac
--- /dev/null
+++ b/test/SemaCXX/bool.cpp
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Bool literals can be enum values.
+enum {
+ ReadWrite = false,
+ ReadOnly = true
+};
+
+// bool cannot be decremented, and gives a warning on increment
+void test(bool b)
+{
+ ++b; // expected-warning {{incrementing expression of type bool is deprecated}}
+ b++; // expected-warning {{incrementing expression of type bool is deprecated}}
+ --b; // expected-error {{cannot decrement expression of type bool}}
+ b--; // expected-error {{cannot decrement expression of type bool}}
+
+ bool *b1 = (int *)0; // expected-error{{expected 'bool *'}}
+}
diff --git a/test/SemaCXX/carbon.cpp b/test/SemaCXX/carbon.cpp
new file mode 100644
index 000000000000..0e7570f33529
--- /dev/null
+++ b/test/SemaCXX/carbon.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-cc -mcpu=pentium4 %s -fsyntax-only -print-stats
+#ifdef __APPLE__
+#include <Carbon/Carbon.h>
+#endif
+
diff --git a/test/SemaCXX/class-names.cpp b/test/SemaCXX/class-names.cpp
new file mode 100644
index 000000000000..a5569c0c767b
--- /dev/null
+++ b/test/SemaCXX/class-names.cpp
@@ -0,0 +1,52 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class C { };
+
+C c;
+
+void D(int);
+
+class D {}; // expected-note {{previous use is here}}
+
+void foo()
+{
+ D(5);
+ class D d;
+}
+
+class D;
+
+enum D; // expected-error {{use of 'D' with tag type that does not match previous declaration}}
+
+class A * A;
+
+class A * a2;
+
+void bar()
+{
+ A = 0;
+}
+
+void C(int);
+
+void bar2()
+{
+ C(17);
+}
+
+extern int B;
+class B;
+class B {};
+int B;
+
+enum E { e1_val };
+E e1;
+
+void E(int);
+
+void bar3() {
+ E(17);
+}
+
+enum E e2;
+
+enum E2 { E2 };
diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp
new file mode 100644
index 000000000000..d2a8114f7b06
--- /dev/null
+++ b/test/SemaCXX/class.cpp
@@ -0,0 +1,112 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class C {
+public:
+ auto int errx; // expected-error {{error: storage class specified for a member declaration}}
+ 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}}
+
+ static void sm() {
+ sx = 0;
+ this->x = 0; // expected-error {{error: invalid use of 'this' outside of a nonstatic member function}}
+ x = 0; // expected-error {{error: invalid use of member 'x' in static member function}}
+ }
+
+ class NestedC {
+ void m() {
+ sx = 0;
+ x = 0; // expected-error {{error: invalid use of nonstatic data member 'x'}}
+ }
+ };
+
+ int b : 1, w : 2;
+ int : 1, : 2;
+ typedef int E : 1; // expected-error {{typedef member 'E' cannot be a bit-field}}
+ static int sb : 1; // expected-error {{error: static member 'sb' cannot be a bit-field}}
+ static int vs;
+
+ typedef int func();
+ func tm;
+ func *ptm;
+ func btm : 1; // expected-error {{bit-field 'btm' has non-integral type}}
+ NestedC bc : 1; // expected-error {{bit-field 'bc' has non-integral type}}
+
+ enum E1 { en1, en2 };
+
+ int i = 0; // expected-error {{error: 'i' can only be initialized if it is a static const integral data member}}
+ static int si = 0; // expected-error {{error: 'si' can only be initialized if it is a static const integral data member}}
+ static const NestedC ci = 0; // expected-error {{error: 'ci' can only be initialized if it is a static const integral data member}}
+ static const int nci = vs; // expected-error {{in-class initializer is not an integral constant expression}}
+ static const int vi = 0;
+ static const E evi = 0;
+
+ void m() {
+ sx = 0;
+ this->x = 0;
+ y = 0;
+ this = 0; // expected-error {{error: expression is not assignable}}
+ }
+
+ int f1(int p) {
+ A z = 6;
+ return p + x + this->y + z;
+ }
+
+ typedef int A;
+
+ virtual int viv; // expected-error {{'virtual' can only appear on non-static member functions}}
+ virtual static int vsif(); // expected-error {{error: 'virtual' can only appear on non-static member functions}}
+ virtual int vif();
+
+private:
+ int x,y;
+ static int sx;
+
+ mutable int mi;
+ mutable int &mir; // expected-error {{error: 'mutable' cannot be applied to references}}
+ mutable void mfn(); // expected-error {{error: 'mutable' cannot be applied to functions}}
+ mutable const int mci; // expected-error {{error: 'mutable' and 'const' cannot be mixed}}
+
+ static const int number = 50;
+ static int arr[number];
+};
+
+class C2 {
+ void f() {
+ static int lx;
+ class LC1 {
+ int m() { return lx; }
+ };
+ class LC2 {
+ int m() { return lx; }
+ };
+ }
+};
+
+struct C3 {
+ int i;
+ mutable int j;
+};
+void f()
+{
+ const C3 c3 = { 1, 2 };
+ (void)static_cast<int*>(&c3.i); // expected-error {{static_cast from 'int const *' to 'int *' is not allowed}}
+ // but no error here
+ (void)static_cast<int*>(&c3.j);
+}
+
+// Play with mutable a bit more, to make sure it doesn't crash anything.
+mutable int gi; // expected-error {{error: 'mutable' can only be applied to member variables}}
+mutable void gfn(); // expected-error {{illegal storage class on function}}
+void ogfn()
+{
+ mutable int ml; // expected-error {{error: 'mutable' can only be applied to member variables}}
+
+ // PR3020: This used to crash due to double ownership of C4.
+ struct C4;
+ C4; // expected-error {{declaration does not declare anything}}
+}
+
+struct C4 {
+ void f(); // expected-note{{previous declaration is here}}
+ int f; // expected-error{{duplicate member 'f'}}
+};
diff --git a/test/SemaCXX/complex-overload.cpp b/test/SemaCXX/complex-overload.cpp
new file mode 100644
index 000000000000..55d3c76d0638
--- /dev/null
+++ b/test/SemaCXX/complex-overload.cpp
@@ -0,0 +1,50 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+char *foo(float); // expected-note 3 {{candidate function}}
+
+void test_foo_1(float fv, double dv, float _Complex fc, double _Complex dc) {
+ char *cp1 = foo(fv);
+ char *cp2 = foo(dv);
+ // Note: GCC and EDG reject these two, but they are valid C99 conversions
+ char *cp3 = foo(fc);
+ char *cp4 = foo(dc);
+}
+
+int *foo(float _Complex); // expected-note 3 {{candidate function}}
+
+void test_foo_2(float fv, double dv, float _Complex fc, double _Complex dc) {
+ char *cp1 = foo(fv);
+ char *cp2 = foo(dv); // expected-error{{call to 'foo' is ambiguous; candidates are:}}
+ int *ip = foo(fc);
+ int *lp = foo(dc); // expected-error{{call to 'foo' is ambiguous; candidates are:}}
+}
+
+long *foo(double _Complex); // expected-note {{candidate function}}
+
+void test_foo_3(float fv, double dv, float _Complex fc, double _Complex dc) {
+ char *cp1 = foo(fv);
+ char *cp2 = foo(dv); // expected-error{{call to 'foo' is ambiguous; candidates are:}}
+ int *ip = foo(fc);
+ long *lp = foo(dc);
+}
+
+char *promote_or_convert(double _Complex); // expected-note{{candidate function}}
+int *promote_or_convert(long double _Complex); // expected-note{{candidate function}}
+
+void test_promote_or_convert(float f, float _Complex fc) {
+ char *cp = promote_or_convert(fc);
+ int *ip2 = promote_or_convert(f); // expected-error{{call to 'promote_or_convert' is ambiguous; candidates are:}}
+}
+
+char *promote_or_convert2(float);
+int *promote_or_convert2(double _Complex);
+
+void test_promote_or_convert2(float _Complex fc) {
+ int *cp = promote_or_convert2(fc);
+}
+
+char *promote_or_convert3(int _Complex);
+int *promote_or_convert3(long _Complex);
+
+void test_promote_or_convert3(short _Complex sc) {
+ char *cp = promote_or_convert3(sc);
+}
diff --git a/test/SemaCXX/composite-pointer-type.cpp b/test/SemaCXX/composite-pointer-type.cpp
new file mode 100644
index 000000000000..b4a5c884f755
--- /dev/null
+++ b/test/SemaCXX/composite-pointer-type.cpp
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class Base { };
+class Derived1 : public Base { };
+class Derived2 : public Base { };
+
+void f0(volatile Base *b, Derived1 *d1, const Derived2 *d2) {
+ if (b > d1)
+ return;
+ if (d1 <= b)
+ return;
+ if (b > d2)
+ return;
+ if (d1 >= d2) // expected-error{{comparison of distinct}}
+ return;
+}
+
+void f1(volatile Base *b, Derived1 *d1, const Derived2 *d2) {
+ if (b == d1)
+ return;
+ if (d1 == b)
+ return;
+ if (b != d2)
+ return;
+ if (d1 == d2) // expected-error{{comparison of distinct}}
+ return;
+}
diff --git a/test/SemaCXX/condition.cpp b/test/SemaCXX/condition.cpp
new file mode 100644
index 000000000000..7c9cee59da6f
--- /dev/null
+++ b/test/SemaCXX/condition.cpp
@@ -0,0 +1,35 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void test() {
+ int x;
+ if (x) ++x;
+ if (int x=0) ++x;
+
+ typedef int arr[10];
+ while (arr x=0) ; // expected-error {{an array type is not allowed here}} expected-error {{initialization with '{...}' expected for array}}
+ while (int f()=0) ; // expected-error {{a function type is not allowed here}}
+
+ struct S {} s;
+ if (s) ++x; // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
+ while (struct S x=s) ; // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
+ do ; while (s); // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
+ for (;s;) ; // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
+ switch (s) {} // expected-error {{statement requires expression of integer type ('struct S' invalid)}}
+
+ while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
+ while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{value of type 'struct <anonymous>' is not contextually convertible to 'bool'}}
+ switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{incompatible type}}
+
+ if (int x=0) { // expected-note 2 {{previous definition is here}}
+ int x; // expected-error {{redefinition of 'x'}}
+ }
+ else
+ int x; // expected-error {{redefinition of 'x'}}
+ while (int x=0) int x; // expected-error {{redefinition of 'x'}} expected-note {{previous definition is here}}
+ while (int x=0) { int x; } // expected-error {{redefinition of 'x'}} expected-note {{previous definition is here}}
+ for (int x; int x=0; ) ; // expected-error {{redefinition of 'x'}} expected-note {{previous definition is here}}
+ for (int x; ; ) int x; // expected-error {{redefinition of 'x'}} expected-note {{previous definition is here}}
+ for (; int x=0; ) int x; // expected-error {{redefinition of 'x'}} expected-note {{previous definition is here}}
+ for (; int x=0; ) { int x; } // expected-error {{redefinition of 'x'}} expected-note {{previous definition is here}}
+ switch (int x=0) { default: int x; } // expected-error {{redefinition of 'x'}} expected-note {{previous definition is here}}
+}
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
new file mode 100644
index 000000000000..3f4d7159a0f8
--- /dev/null
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -0,0 +1,181 @@
+// RUN: clang-cc -fsyntax-only -verify -faccess-control -std=c++0x %s
+
+// C++ rules for ?: are a lot stricter than C rules, and have to take into
+// account more conversion options.
+// This test runs in C++0x mode for the contextual conversion of the condition.
+
+struct ToBool { explicit operator bool(); };
+
+struct B;
+struct A { A(); A(const B&); };
+struct B { operator A() const; };
+struct I { operator int(); };
+struct J { operator I(); };
+struct K { operator double(); };
+typedef void (*vfn)();
+struct F { operator vfn(); };
+struct G { operator vfn(); };
+
+struct Base {
+ int trick();
+ A trick() const;
+ void fn1();
+};
+struct Derived : Base {
+ void fn2();
+};
+struct Convertible { operator Base&(); };
+struct Priv : private Base {}; // expected-note 2 {{'private' inheritance specifier here}}
+struct Mid : Base {};
+struct Fin : Mid, Derived {};
+typedef void (Derived::*DFnPtr)();
+struct ToMemPtr { operator DFnPtr(); };
+
+struct BadDerived;
+struct BadBase { operator BadDerived&(); };
+struct BadDerived : BadBase {};
+
+struct Fields {
+ int i1, i2, b1 : 3, b2 : 3;
+};
+struct MixedFields {
+ int i;
+ volatile int vi;
+ const int ci;
+ const volatile int cvi;
+};
+struct MixedFieldsDerived : MixedFields {
+};
+
+enum Enum { EVal };
+
+struct Ambig {
+ operator short();
+ operator signed char();
+};
+
+void test()
+{
+ // This function tests C++0x 5.16
+
+ // p1 (contextually convert to bool)
+ int i1 = ToBool() ? 0 : 1;
+
+ // p2 (one or both void, and throwing)
+ i1 ? throw 0 : throw 1;
+ i1 ? test() : throw 1;
+ i1 ? throw 0 : test();
+ i1 ? test() : test();
+ i1 = i1 ? throw 0 : 0;
+ i1 = i1 ? 0 : throw 0;
+ i1 ? 0 : test(); // expected-error {{right operand to ? is void, but left operand is of type 'int'}}
+ i1 ? test() : 0; // expected-error {{left operand to ? is void, but right operand is of type 'int'}}
+ (i1 ? throw 0 : i1) = 0; // expected-error {{expression is not assignable}}
+ (i1 ? i1 : throw 0) = 0; // expected-error {{expression is not assignable}}
+
+ // p3 (one or both class type, convert to each other)
+ // b1 (lvalues)
+ Base base;
+ Derived derived;
+ Convertible conv;
+ Base &bar1 = i1 ? base : derived;
+ Base &bar2 = i1 ? derived : base;
+ Base &bar3 = i1 ? base : conv;
+ Base &bar4 = i1 ? conv : base;
+ // these are ambiguous
+ BadBase bb;
+ BadDerived bd;
+ (void)(i1 ? bb : bd); // expected-error {{conditional expression is ambiguous; 'struct BadBase' can be converted to 'struct BadDerived' and vice versa}}
+ (void)(i1 ? bd : bb); // expected-error {{conditional expression is ambiguous}}
+ // curiously enough (and a defect?), these are not
+ // for rvalues, hierarchy takes precedence over other conversions
+ (void)(i1 ? BadBase() : BadDerived());
+ (void)(i1 ? BadDerived() : BadBase());
+
+ // b2.1 (hierarchy stuff)
+ const Base constret();
+ const Derived constder();
+ // should use const overload
+ A a1((i1 ? constret() : Base()).trick());
+ A a2((i1 ? Base() : constret()).trick());
+ A a3((i1 ? constret() : Derived()).trick());
+ A a4((i1 ? Derived() : constret()).trick());
+ // should use non-const overload
+ i1 = (i1 ? Base() : Base()).trick();
+ i1 = (i1 ? Base() : Base()).trick();
+ i1 = (i1 ? Base() : Derived()).trick();
+ i1 = (i1 ? Derived() : Base()).trick();
+ // should fail: const lost
+ (void)(i1 ? Base() : constder()); // expected-error {{incompatible operand types ('struct Base' and 'struct Derived const')}}
+ (void)(i1 ? constder() : Base()); // expected-error {{incompatible operand types ('struct Derived const' and 'struct Base')}}
+
+ // FIXME: these are invalid hierarchy conversions
+ Priv priv;
+ Fin fin;
+ (void)(i1 ? Base() : Priv()); // xpected-error private base
+ (void)(i1 ? Priv() : Base()); // xpected-error private base
+ (void)(i1 ? Base() : Fin()); // xpected-error ambiguous base
+ (void)(i1 ? Fin() : Base()); // xpected-error ambiguous base
+ (void)(i1 ? base : priv); // expected-error {{conversion from 'struct Priv' to inaccessible base class 'struct Base'}}
+ (void)(i1 ? priv : base); // expected-error {{conversion from 'struct Priv' to inaccessible base class 'struct Base'}}
+ (void)(i1 ? base : fin); // expected-error {{ambiguous conversion from derived class 'struct Fin' to base class 'struct Base'}}
+ (void)(i1 ? fin : base); // expected-error {{ambiguous conversion from derived class 'struct Fin' to base class 'struct Base'}}
+
+ // b2.2 (non-hierarchy)
+ i1 = i1 ? I() : i1;
+ i1 = i1 ? i1 : I();
+ I i2(i1 ? I() : J());
+ I i3(i1 ? J() : I());
+ // "the type [it] woud have if E2 were converted to an rvalue"
+ vfn pfn = i1 ? F() : test;
+ pfn = i1 ? test : F();
+ // these are ambiguous - better messages would be nice
+ (void)(i1 ? A() : B()); // expected-error {{incompatible operand types}}
+ (void)(i1 ? B() : A()); // expected-error {{incompatible operand types}}
+ (void)(i1 ? 1 : Ambig()); // expected-error {{incompatible operand types}}
+ (void)(i1 ? Ambig() : 1); // expected-error {{incompatible operand types}}
+ // By the way, this isn't an lvalue:
+ &(i1 ? i1 : i2); // expected-error {{address expression must be an lvalue or a function designator}}
+
+ // p4 (lvalue, same type)
+ Fields flds;
+ int &ir1 = i1 ? flds.i1 : flds.i2;
+ (i1 ? flds.b1 : flds.i2) = 0;
+ (i1 ? flds.i1 : flds.b2) = 0;
+ (i1 ? flds.b1 : flds.b2) = 0;
+
+ // p5 (conversion to built-in types)
+ // GCC 4.3 fails these
+ double d1 = i1 ? I() : K();
+ pfn = i1 ? F() : G();
+ DFnPtr pfm;
+ pfm = i1 ? DFnPtr() : &Base::fn1;
+ pfm = i1 ? &Base::fn1 : DFnPtr();
+
+ // p6 (final conversions)
+ i1 = i1 ? i1 : ir1;
+ int *pi1 = i1 ? &i1 : 0;
+ pi1 = i1 ? 0 : &i1;
+ i1 = i1 ? i1 : EVal;
+ i1 = i1 ? EVal : i1;
+ d1 = i1 ? 'c' : 4.0;
+ d1 = i1 ? 4.0 : 'c';
+ Base *pb = i1 ? (Base*)0 : (Derived*)0;
+ pb = i1 ? (Derived*)0 : (Base*)0;
+ pfm = i1 ? &Base::fn1 : &Derived::fn2;
+ pfm = i1 ? &Derived::fn2 : &Base::fn1;
+ pfm = i1 ? &Derived::fn2 : 0;
+ pfm = i1 ? 0 : &Derived::fn2;
+ const int (MixedFieldsDerived::*mp1) =
+ i1 ? &MixedFields::ci : &MixedFieldsDerived::i;
+ const volatile int (MixedFields::*mp2) =
+ i1 ? &MixedFields::ci : &MixedFields::cvi;
+ i1 ? &MixedFields::ci : &MixedFields::vi; // expected-error {{incompatible operand types}}
+ // Conversion of primitives does not result in an lvalue.
+ &(i1 ? i1 : d1); // expected-error {{address expression must be an lvalue or a function designator}}
+
+
+ // Note the thing that this does not test: since DR446, various situations
+ // *must* create a separate temporary copy of class objects. This can only
+ // be properly tested at runtime, though.
+}
diff --git a/test/SemaCXX/const-cast.cpp b/test/SemaCXX/const-cast.cpp
new file mode 100644
index 000000000000..39d61db0dc94
--- /dev/null
+++ b/test/SemaCXX/const-cast.cpp
@@ -0,0 +1,63 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct A {};
+
+// See if aliasing can confuse this baby.
+typedef char c;
+typedef c *cp;
+typedef cp *cpp;
+typedef cpp *cppp;
+typedef cppp &cpppr;
+typedef const cppp &cpppcr;
+typedef const char cc;
+typedef cc *ccp;
+typedef volatile ccp ccvp;
+typedef ccvp *ccvpp;
+typedef const volatile ccvpp ccvpcvp;
+typedef ccvpcvp *ccvpcvpp;
+typedef int iar[100];
+typedef iar &iarr;
+typedef int (*f)(int);
+
+char ***good_const_cast_test(ccvpcvpp var)
+{
+ // Cast away deep consts and volatiles.
+ char ***var2 = const_cast<cppp>(var);
+ char ***const &var3 = var2;
+ // Const reference to reference.
+ char ***&var4 = const_cast<cpppr>(var3);
+ // Drop reference. Intentionally without qualifier change.
+ char *** var5 = const_cast<cppp>(var4);
+ const int ar[100] = {0};
+ int (&rar)[100] = const_cast<iarr>(ar); // expected-error {{const_cast from 'int const [100]' to 'iarr' (aka 'iar &') is not allowed}}
+ // Array decay. Intentionally without qualifier change.
+ int *pi = const_cast<int*>(ar);
+ f fp = 0;
+ // Don't misidentify fn** as a function pointer.
+ f *fpp = const_cast<f*>(&fp);
+ int const A::* const A::*icapcap = 0;
+ int A::* A::* iapap = const_cast<int A::* A::*>(icapcap);
+
+ return var4;
+}
+
+short *bad_const_cast_test(char const *volatile *const volatile *var)
+{
+ // Different pointer levels.
+ char **var2 = const_cast<char**>(var); // expected-error {{const_cast from 'char const *volatile *const volatile *' to 'char **' is not allowed}}
+ // Different final type.
+ short ***var3 = const_cast<short***>(var); // expected-error {{const_cast from 'char const *volatile *const volatile *' to 'short ***' is not allowed}}
+ // Rvalue to reference.
+ char ***&var4 = const_cast<cpppr>(&var2); // expected-error {{const_cast from rvalue to reference type 'cpppr'}}
+ // Non-pointer.
+ char v = const_cast<char>(**var2); // expected-error {{const_cast to 'char', which is not a reference, pointer-to-object, or pointer-to-data-member}}
+ const int *ar[100] = {0};
+ // Not even lenient g++ accepts this.
+ int *(*rar)[100] = const_cast<int *(*)[100]>(&ar); // expected-error {{const_cast from 'int const *(*)[100]' to 'int *(*)[100]' is not allowed}}
+ f fp1 = 0;
+ // Function pointers.
+ f fp2 = const_cast<f>(fp1); // expected-error {{const_cast to 'f' (aka 'int (*)(int)'), which is not a reference, pointer-to-object, or pointer-to-data-member}}
+ void (A::*mfn)() = 0;
+ (void)const_cast<void (A::*)()>(mfn); // expected-error {{const_cast to 'void (struct A::*)(void)', which is not a reference, pointer-to-object, or pointer-to-data-member}}
+ return **var3;
+}
diff --git a/test/SemaCXX/constant-expression.cpp b/test/SemaCXX/constant-expression.cpp
new file mode 100644
index 000000000000..02ea802c7265
--- /dev/null
+++ b/test/SemaCXX/constant-expression.cpp
@@ -0,0 +1,83 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++98 %s
+
+// C++ [expr.const]p1:
+// In several places, C++ requires expressions that evaluate to an integral
+// or enumeration constant: as array bounds, as case expressions, as
+// bit-field lengths, as enumerator initializers, as static member
+// initializers, and as integral or enumeration non-type template arguments.
+// An integral constant-expression can involve only literals, enumerators,
+// const variables or static data members of integral or enumeration types
+// initialized with constant expressions, and sizeof expressions. Floating
+// literals can appear only if they are cast to integral or enumeration types.
+
+enum Enum { eval = 1 };
+const int cval = 2;
+const Enum ceval = eval;
+struct Struct {
+ static const int sval = 3;
+ static const Enum seval = eval;
+};
+
+template <int itval, Enum etval> struct C {
+ enum E {
+ v1 = 1,
+ v2 = eval,
+ v3 = cval,
+ v4 = ceval,
+ v5 = Struct::sval,
+ v6 = Struct::seval,
+ v7 = itval,
+ v8 = etval,
+ v9 = (int)1.5,
+ v10 = sizeof(Struct),
+ v11 = true? 1 + cval * Struct::sval ^ itval / (int)1.5 - sizeof(Struct) : 0
+ };
+ unsigned
+ b1 : 1,
+ b2 : eval,
+ b3 : cval,
+ b4 : ceval,
+ b5 : Struct::sval,
+ b6 : Struct::seval,
+ b7 : itval,
+ b8 : etval,
+ b9 : (int)1.5,
+ b10 : sizeof(Struct),
+ b11 : true? 1 + cval * Struct::sval ^ itval / (int)1.5 - sizeof(Struct) : 0
+ ;
+ static const int
+ i1 = 1,
+ i2 = eval,
+ i3 = cval,
+ i4 = ceval,
+ i5 = Struct::sval,
+ i6 = Struct::seval,
+ i7 = itval,
+ i8 = etval,
+ i9 = (int)1.5,
+ i10 = sizeof(Struct),
+ i11 = true? 1 + cval * Struct::sval ^ itval / (int)1.5 - sizeof(Struct) : 0
+ ;
+ void f() {
+ switch(0) {
+ case 0 + 1:
+ case 100 + eval:
+ case 200 + cval:
+ case 300 + ceval:
+ case 400 + Struct::sval:
+ case 500 + Struct::seval:
+ case 600 + itval:
+ case 700 + etval:
+ case 800 + (int)1.5:
+ case 900 + sizeof(Struct):
+ case 1000 + (true? 1 + cval * Struct::sval ^
+ itval / (int)1.5 - sizeof(Struct) : 0):
+ ;
+ }
+ }
+ typedef C<itval, etval> T0;
+};
+
+template struct C<1, eval>;
+//template struct C<cval, ceval>;
+//template struct C<Struct::sval, Struct::seval>;
diff --git a/test/SemaCXX/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp
new file mode 100644
index 000000000000..d0c978a80d15
--- /dev/null
+++ b/test/SemaCXX/constructor-initializer.cpp
@@ -0,0 +1,56 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class A {
+ int m;
+};
+
+class B : public A {
+public:
+ B() : A(), m(1), n(3.14) { }
+
+private:
+ int m;
+ float n;
+};
+
+
+class C : public virtual B {
+public:
+ C() : B() { }
+};
+
+class D : public C {
+public:
+ D() : B(), C() { }
+};
+
+class E : public D, public B {
+public:
+ E() : B(), D() { } // expected-error{{base class initializer 'B' names both a direct base class and an inherited virtual base class}}
+};
+
+
+typedef int INT;
+
+class F : public B {
+public:
+ int B;
+
+ F() : B(17),
+ m(17), // expected-error{{member initializer 'm' does not name a non-static data member or base class}}
+ INT(17) // expected-error{{constructor initializer 'INT' (aka 'int') does not name a class}}
+ {
+ }
+};
+
+class G : A {
+ G() : A(10); // expected-error{{expected '{'}}
+};
+
+void f() : a(242) { } // expected-error{{only constructors take base initializers}}
+
+class H : A {
+ H();
+};
+
+H::H() : A(10) { }
+
diff --git a/test/SemaCXX/constructor-recovery.cpp b/test/SemaCXX/constructor-recovery.cpp
new file mode 100644
index 000000000000..50fdc9622e4c
--- /dev/null
+++ b/test/SemaCXX/constructor-recovery.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct C { // expected-note {{candidate function}}
+ virtual C() = 0; // expected-error{{constructor cannot be declared 'virtual'}} \
+ expected-note {{candidate function}}
+};
+
+void f() {
+ C c; // expected-error {{call to constructor of 'c' is ambiguous}}
+}
diff --git a/test/SemaCXX/constructor.cpp b/test/SemaCXX/constructor.cpp
new file mode 100644
index 000000000000..8f289a2b1e96
--- /dev/null
+++ b/test/SemaCXX/constructor.cpp
@@ -0,0 +1,60 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+typedef int INT;
+
+class Foo {
+ Foo();
+ (Foo)(float) { }
+ explicit Foo(int); // expected-note {{previous declaration is here}}
+ Foo(const Foo&);
+
+ ((Foo))(INT); // expected-error{{cannot be redeclared}}
+
+ Foo(Foo foo, int i = 17, int j = 42); // expected-error{{copy constructor must pass its first argument by reference}}
+
+ static Foo(short, short); // expected-error{{constructor cannot be declared 'static'}}
+ virtual Foo(double); // expected-error{{constructor cannot be declared 'virtual'}}
+ Foo(long) const; // expected-error{{'const' qualifier is not allowed on a constructor}}
+
+ int Foo(int, int); // expected-error{{constructor cannot have a return type}}
+};
+
+Foo::Foo(const Foo&) { }
+
+typedef struct {
+ int version;
+} Anon;
+extern const Anon anon;
+extern "C" const Anon anon2;
+
+// PR3188: The extern declaration complained about not having an appropriate
+// constructor.
+struct x;
+extern x a;
+
+// A similar case.
+struct y {
+ y(int);
+};
+extern y b;
+
+struct Length {
+ Length l() const { return *this; }
+};
+
+// <rdar://problem/6815988>
+struct mmst_reg{
+ char mmst_reg[10];
+};
+
+// PR3948
+namespace PR3948 {
+// PR3948
+class a {
+ public:
+ int b(int a());
+};
+int x();
+void y() {
+ a z; z.b(x);
+}
+}
diff --git a/test/SemaCXX/conversion-function.cpp b/test/SemaCXX/conversion-function.cpp
new file mode 100644
index 000000000000..1ca1e689eab0
--- /dev/null
+++ b/test/SemaCXX/conversion-function.cpp
@@ -0,0 +1,66 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class X {
+public:
+ operator bool();
+ operator int() const;
+
+ bool f() {
+ return operator bool();
+ }
+
+ float g() {
+ return operator float(); // expected-error{{no matching function for call to 'operator float'}}
+ }
+};
+
+operator int(); // expected-error{{conversion function must be a non-static member function}}
+
+operator int; // expected-error{{'operator int' cannot be the name of a variable or data member}}
+
+typedef int func_type(int);
+typedef int array_type[10];
+
+class Y {
+public:
+ void operator bool(int, ...) const; // expected-error{{conversion function cannot have a return type}} \
+ // expected-error{{conversion function cannot have any parameters}}
+
+ operator float(...) const; // expected-error{{conversion function cannot be variadic}}
+
+
+ operator func_type(); // expected-error{{conversion function cannot convert to a function type}}
+ operator array_type(); // expected-error{{conversion function cannot convert to an array type}}
+};
+
+
+typedef int INT;
+typedef INT* INT_PTR;
+
+class Z {
+ operator int(); // expected-note {{previous declaration is here}}
+ operator int**(); // expected-note {{previous declaration is here}}
+
+ operator INT(); // expected-error{{conversion function cannot be redeclared}}
+ operator INT_PTR*(); // expected-error{{conversion function cannot be redeclared}}
+};
+
+
+class A { };
+
+class B : public A {
+public:
+ operator A&() const; // expected-warning{{conversion function converting 'class B' to its base class 'class A' will never be used}}
+ operator const void() const; // expected-warning{{conversion function converting 'class B' to 'void const' will never be used}}
+ operator const B(); // expected-warning{{conversion function converting 'class B' to itself will never be used}}
+};
+
+// This used to crash Clang.
+struct Flip;
+struct Flop {
+ Flop();
+ Flop(const Flip&);
+};
+struct Flip {
+ operator Flop() const;
+};
+Flop flop = Flip(); // expected-error {{cannot initialize 'flop' with an rvalue of type 'struct Flip'}}
diff --git a/test/SemaCXX/convert-to-bool.cpp b/test/SemaCXX/convert-to-bool.cpp
new file mode 100644
index 000000000000..937b2729d1c3
--- /dev/null
+++ b/test/SemaCXX/convert-to-bool.cpp
@@ -0,0 +1,67 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct ConvToBool {
+ operator bool() const;
+};
+
+struct ConvToInt {
+ operator int();
+};
+
+struct ExplicitConvToBool {
+ explicit operator bool(); // expected-warning{{explicit conversion functions are a C++0x extension}}
+};
+
+void test_conv_to_bool(ConvToBool ctb, ConvToInt cti, ExplicitConvToBool ecb) {
+ if (ctb) { }
+ if (cti) { }
+ if (ecb) { }
+ for (; ctb; ) { }
+ for (; cti; ) { }
+ for (; ecb; ) { }
+ while (ctb) { };
+ while (cti) { }
+ while (ecb) { }
+ do { } while (ctb);
+ do { } while (cti);
+ do { } while (ecb);
+
+ if (!ctb) { }
+ if (!cti) { }
+ if (!ecb) { }
+
+ bool b1 = !ecb;
+ if (ctb && ecb) { }
+ bool b2 = ctb && ecb;
+ if (ctb || ecb) { }
+ bool b3 = ctb || ecb;
+}
+
+void accepts_bool(bool) { } // expected-note{{candidate function}}
+
+struct ExplicitConvToRef {
+ explicit operator int&(); // expected-warning{{explicit conversion functions are a C++0x extension}}
+};
+
+void test_explicit_bool(ExplicitConvToBool ecb) {
+ bool b1(ecb); // okay
+ bool b2 = ecb; // expected-error{{incompatible type initializing 'struct ExplicitConvToBool', expected 'bool'}}
+ accepts_bool(ecb); // expected-error{{no matching function for call to}}
+}
+
+void test_explicit_conv_to_ref(ExplicitConvToRef ecr) {
+ int& i1 = ecr; // expected-error{{non-const lvalue reference to type 'int' cannot be initialized with a value of type 'struct ExplicitConvToRef'}}
+ int& i2(ecr); // okay
+}
+
+struct A { };
+struct B { };
+struct C {
+ explicit operator A&(); // expected-warning{{explicit conversion functions are a C++0x extension}}
+ operator B&();
+};
+
+void test_copy_init_conversions(C c) {
+ A &a = c; // expected-error{{non-const lvalue reference to type 'struct A' cannot be initialized with a value of type 'struct C'}}
+ B &b = b; // okay
+}
+
diff --git a/test/SemaCXX/converting-constructor.cpp b/test/SemaCXX/converting-constructor.cpp
new file mode 100644
index 000000000000..59b793e3f28c
--- /dev/null
+++ b/test/SemaCXX/converting-constructor.cpp
@@ -0,0 +1,40 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class Z { };
+
+class Y {
+public:
+ Y(const Z&);
+};
+
+class X {
+public:
+ X(int);
+ X(const Y&);
+};
+
+void f(X); // expected-note{{candidate function}}
+
+void g(short s, Y y, Z z) {
+ f(s);
+ f(1.0f);
+ f(y);
+ f(z); // expected-error{{no matching function}}
+}
+
+
+class FromShort {
+public:
+ FromShort(short s);
+};
+
+class FromShortExplicitly {
+public:
+ explicit FromShortExplicitly(short s);
+};
+
+void explicit_constructor(short s) {
+ FromShort fs1(s);
+ FromShort fs2 = s;
+ FromShortExplicitly fse1(s);
+ FromShortExplicitly fse2 = s; // expected-error{{error: cannot initialize 'fse2' with an lvalue of type 'short'}}
+}
diff --git a/test/SemaCXX/copy-assignment.cpp b/test/SemaCXX/copy-assignment.cpp
new file mode 100644
index 000000000000..6e5012f5a7a1
--- /dev/null
+++ b/test/SemaCXX/copy-assignment.cpp
@@ -0,0 +1,99 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct A {
+};
+
+struct ConvertibleToA {
+ operator A();
+};
+
+struct ConvertibleToConstA {
+ operator const A();
+};
+
+struct B {
+ B& operator=(B&);
+};
+
+struct ConvertibleToB {
+ operator B();
+};
+
+struct ConvertibleToBref {
+ operator B&();
+};
+
+struct ConvertibleToConstB {
+ operator const B();
+};
+
+struct ConvertibleToConstBref {
+ operator const B&();
+};
+
+struct C {
+ int operator=(int); // expected-note{{candidate function}}
+ long operator=(long); // expected-note{{candidate function}}
+ int operator+=(int); // expected-note{{candidate function}}
+ int operator+=(long); // expected-note{{candidate function}}
+};
+
+struct D {
+ D& operator+=(const D &);
+};
+
+struct ConvertibleToInt {
+ operator int();
+};
+
+void test() {
+ A a, na;
+ const A constA;
+ ConvertibleToA convertibleToA;
+ ConvertibleToConstA convertibleToConstA;
+
+ B b, nb;
+ const B constB;
+ ConvertibleToB convertibleToB;
+ ConvertibleToBref convertibleToBref;
+ ConvertibleToConstB convertibleToConstB;
+ ConvertibleToConstBref convertibleToConstBref;
+
+ C c, nc;
+ const C constC;
+
+ D d, nd;
+ const D constD;
+
+ ConvertibleToInt convertibleToInt;
+
+ na = a;
+ na = constA;
+ na = convertibleToA;
+ na = convertibleToConstA;
+ na += a; // expected-error{{no viable overloaded '+='}}
+
+ nb = b;
+ nb = constB; // expected-error{{no viable overloaded '='}}
+ nb = convertibleToB; // expected-error{{no viable overloaded '='}}
+ nb = convertibleToBref;
+ nb = convertibleToConstB; // expected-error{{no viable overloaded '='}}
+ nb = convertibleToConstBref; // expected-error{{no viable overloaded '='}}
+
+ nc = c;
+ nc = constC;
+ nc = 1;
+ nc = 1L;
+ nc = 1.0; // expected-error{{use of overloaded operator '=' is ambiguous}}
+ nc += 1;
+ nc += 1L;
+ nc += 1.0; // expected-error{{use of overloaded operator '+=' is ambiguous}}
+
+ nd = d;
+ nd += d;
+ nd += constD;
+
+ int i;
+ i = convertibleToInt;
+ i = a; // expected-error{{incompatible type assigning 'struct A', expected 'int'}}
+}
+
diff --git a/test/SemaCXX/copy-initialization.cpp b/test/SemaCXX/copy-initialization.cpp
new file mode 100644
index 000000000000..5b1fbaa46052
--- /dev/null
+++ b/test/SemaCXX/copy-initialization.cpp
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class X {
+public:
+ explicit X(const X&);
+ X(int*); // expected-note{{candidate function}}
+ explicit X(float*);
+};
+
+class Y : public X { };
+
+void f(Y y, int *ip, float *fp) {
+ X x1 = y; // expected-error{{no matching constructor for initialization of 'x1'; candidate is:}}
+ X x2 = 0;
+ X x3 = ip;
+ X x4 = fp; // expected-error{{cannot initialize 'x4' with an lvalue of type 'float *'}}
+}
+
+struct foo {
+ void bar();
+};
+
+// PR3600
+void test(const foo *P) { P->bar(); } // expected-error{{cannot initialize object parameter of type 'struct foo' with an expression of type 'struct foo const'}}
diff --git a/test/SemaCXX/dcl_ambig_res.cpp b/test/SemaCXX/dcl_ambig_res.cpp
new file mode 100644
index 000000000000..57bf4095afd0
--- /dev/null
+++ b/test/SemaCXX/dcl_ambig_res.cpp
@@ -0,0 +1,66 @@
+// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+
+// [dcl.ambig.res]p1:
+struct S {
+ S(int);
+ void bar();
+};
+
+int returns_an_int();
+
+void foo(double a)
+{
+ S w(int(a)); // expected-warning{{disambiguated}}
+ w(17);
+ S x(int()); // expected-warning{{disambiguated}}
+ x(&returns_an_int);
+ S y((int)a);
+ y.bar();
+ S z = int(a);
+ z.bar();
+}
+
+// [dcl.ambig.res]p3:
+char *p;
+void *operator new(__SIZE_TYPE__, int);
+void foo3() {
+ const int x = 63;
+ new (int(*p)) int; //new-placement expression
+ new (int(*[x])); //new type-id
+}
+
+// [dcl.ambig.res]p4:
+template <class T> // expected-note{{here}}
+struct S4 {
+ T *p;
+};
+S4<int()> x; //type-id
+S4<int(1)> y; // expected-error{{must be a type}}
+
+// [dcl.ambig.res]p5:
+void foo5()
+{
+ (void)sizeof(int(1)); //expression
+ // FIXME: should we make this an error rather than a warning?
+ // (It affects SFINAE)
+ (void)sizeof(int()); // expected-warning{{function type}}
+}
+
+// [dcl.ambig.res]p6:
+void foo6()
+{
+ (void)(int(1)); //expression
+ (void)(int())1; // expected-error{{used type}}
+}
+
+// [dcl.ambig.res]p7:
+class C7 { };
+void f7(int(C7)) { } // expected-note{{candidate}}
+int g7(C7);
+void foo7() {
+ f7(1); // expected-error{{no matching function}}
+ f7(g7); //OK
+}
+
+void h7(int *(C7[10])) { } // expected-note{{previous}}
+void h7(int *(*_fp)(C7 _parm[10])) { } // expected-error{{redefinition}}
diff --git a/test/SemaCXX/dcl_init_aggr.cpp b/test/SemaCXX/dcl_init_aggr.cpp
new file mode 100644
index 000000000000..10c15ccc9061
--- /dev/null
+++ b/test/SemaCXX/dcl_init_aggr.cpp
@@ -0,0 +1,122 @@
+// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+// C++ [dcl.init.aggr]p2
+struct A {
+ int x;
+ struct B {
+ int i;
+ int j;
+ } b;
+} a1 = { 1, { 2, 3 } };
+
+struct NonAggregate {
+ NonAggregate();
+
+ int a, b;
+};
+NonAggregate non_aggregate_test = { 1, 2 }; // expected-error{{initialization of non-aggregate type 'struct NonAggregate' with an initializer list}}
+
+NonAggregate non_aggregate_test2[2] = { { 1, 2 }, { 3, 4 } }; // expected-error 2 {{initialization of non-aggregate type 'struct NonAggregate' with an initializer list}}
+
+
+// C++ [dcl.init.aggr]p3
+A a_init = A();
+
+// C++ [dcl.init.aggr]p4
+int x[] = { 1, 3, 5 };
+int x_sizecheck[(sizeof(x) / sizeof(int)) == 3? 1 : -1];
+int x2[] = { }; // expected-warning{{zero size arrays are an extension}}
+
+// C++ [dcl.init.aggr]p5
+struct StaticMemberTest {
+ int i;
+ static int s;
+ int *j;
+} smt = { 1, &smt.i };
+
+// C++ [dcl.init.aggr]p6
+char cv[4] = { 'a', 's', 'd', 'f', 0 }; // expected-error{{excess elements in array initializer}}
+
+// C++ [dcl.init.aggr]p7
+struct TooFew { int a; char* b; int c; };
+TooFew too_few = { 1, "asdf" }; // okay
+
+struct NoDefaultConstructor { // expected-note 5 {{candidate function}}
+ NoDefaultConstructor(int); // expected-note 5 {{candidate function}}
+};
+struct TooFewError {
+ int a;
+ NoDefaultConstructor nodef;
+};
+TooFewError too_few_okay = { 1, 1 };
+TooFewError too_few_error = { 1 }; // expected-error{{no matching constructor}}
+
+TooFewError too_few_okay2[2] = { 1, 1 };
+TooFewError too_few_error2[2] = { 1 }; // expected-error{{no matching constructor}}
+
+NoDefaultConstructor too_few_error3[3] = { }; // expected-error 3 {{no matching constructor}}
+
+// C++ [dcl.init.aggr]p8
+struct Empty { };
+struct EmptyTest {
+ Empty s;
+ int i;
+} empty_test = { { }, 3 };
+
+EmptyTest empty_test2 = { 3 }; // expected-error{{initializer for aggregate with no elements requires explicit braces}}
+
+struct NonEmpty {
+ int a;
+ Empty empty;
+};
+struct NonEmptyTest {
+ NonEmpty a, b;
+} non_empty_test = { { }, { } };
+
+// C++ [dcl.init.aggr]p9
+struct HasReference {
+ int i;
+ int &j; // expected-note{{uninitialized reference member is here}}
+};
+int global_int;
+HasReference r1 = { 1, global_int };
+HasReference r2 = { 1 } ; // expected-error{{initialization leaves reference member of type 'int &' uninitialized}}
+
+// C++ [dcl.init.aggr]p10
+// Note: the behavior here is identical to C
+int xs[2][2] = { 3, 1, 4, 2 };
+float y[4][3] = { { 1 }, { 2 }, { 3 }, { 4 } };
+
+// C++ [dcl.init.aggr]p11
+// Note: the behavior here is identical to C
+float y2[4][3] = { { 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7 } };
+float same_as_y2[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 };
+
+// C++ [dcl.init.aggr]p12
+struct A2 {
+ int i;
+ operator int *();
+};
+struct B2 {
+ A2 a1, a2;
+ int *z;
+};
+struct C2 {
+ operator A2();
+};
+struct D2 {
+ operator int();
+};
+A2 a2;
+C2 c2;
+D2 d2;
+B2 b2 = { 4, a2, a2 };
+B2 b2_2 = { 4, d2, 0 };
+B2 b2_3 = { c2, a2, a2 };
+
+// C++ [dcl.init.aggr]p15:
+union u { int a; char* b; };
+u u1 = { 1 };
+u u2 = u1;
+u u3 = 1; // expected-error{{cannot initialize 'u3' with an rvalue of type 'int'}}
+u u4 = { 0, "asdf" }; // expected-error{{excess elements in union initializer}}
+u u5 = { "asdf" }; // expected-error{{incompatible type initializing 'char const [5]', expected 'int'}}
diff --git a/test/SemaCXX/decl-expr-ambiguity.cpp b/test/SemaCXX/decl-expr-ambiguity.cpp
new file mode 100644
index 000000000000..bff333464b91
--- /dev/null
+++ b/test/SemaCXX/decl-expr-ambiguity.cpp
@@ -0,0 +1,43 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic-errors %s
+
+void f() {
+ int a;
+ struct S { int m; };
+ typedef S *T;
+
+ // Expressions.
+ T(a)->m = 7;
+ int(a)++; // expected-error {{expression is not assignable}}
+ __extension__ int(a)++; // expected-error {{expression is not assignable}}
+ __typeof(int)(a,5)<<a; // expected-error {{function-style cast to a builtin type can only take one argument}}
+ void(a), ++a; // expected-warning {{expression result unused}}
+ if (int(a)+1) {}
+ for (int(a)+1;;) {}
+ a = sizeof(int()+1);
+ a = sizeof(int(1));
+ typeof(int()+1) a2; // expected-error {{extension used}}
+ (int(1)); // expected-warning {{expression result unused}}
+
+ // type-id
+ (int())1; // expected-error {{used type 'int (void)' where arithmetic or pointer type is required}}
+
+ // Declarations.
+ int fd(T(a)); // expected-warning {{parentheses were disambiguated as a function declarator}}
+ T(*d)(int(p)); // expected-warning {{parentheses were disambiguated as a function declarator}} expected-note {{previous definition is here}}
+ T(d)[5]; // expected-error {{redefinition of 'd'}}
+ typeof(int[])(f) = { 1, 2 }; // expected-error {{extension used}}
+ void(b)(int);
+ int(d2) __attribute__(());
+ if (int(a)=1) {}
+ int(d3(int()));
+}
+
+class C { };
+void fn(int(C)) { } // void fn(int(*fp)(C c)) { } expected-note{{candidate function}}
+ // not: void fn(int C);
+int g(C);
+
+void foo() {
+ fn(1); // expected-error {{no matching function}}
+ fn(g); // OK
+}
diff --git a/test/SemaCXX/default1.cpp b/test/SemaCXX/default1.cpp
new file mode 100644
index 000000000000..be264ad62b13
--- /dev/null
+++ b/test/SemaCXX/default1.cpp
@@ -0,0 +1,31 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+void f(int i);
+void f(int i = 0); // expected-note {{previous definition is here}}
+void f(int i = 17); // expected-error {{redefinition of default argument}}
+
+
+void g(int i, int j, int k = 3);
+void g(int i, int j = 2, int k);
+void g(int i = 1, int j, int k);
+
+void h(int i, int j = 2, int k = 3,
+ int l, // expected-error {{missing default argument on parameter 'l'}}
+ int, // expected-error {{missing default argument on parameter}}
+ int n);// expected-error {{missing default argument on parameter 'n'}}
+
+struct S { } s;
+void i(int = s) { } // expected-error {{incompatible type}}
+
+struct X {
+ X(int);
+};
+
+void j(X x = 17);
+
+struct Y {
+ explicit Y(int);
+};
+
+void k(Y y = 17); // expected-error{{cannot initialize 'y' with an rvalue of type 'int'}}
+
+void kk(Y = 17); // expected-error{{cannot initialize a value of type 'struct Y' with an rvalue of type 'int'}}
diff --git a/test/SemaCXX/default2.cpp b/test/SemaCXX/default2.cpp
new file mode 100644
index 000000000000..f99e45415dc4
--- /dev/null
+++ b/test/SemaCXX/default2.cpp
@@ -0,0 +1,123 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f(int i, int j, int k = 3);
+void f(int i, int j, int k);
+void f(int i, int j = 2, int k);
+void f(int i, int j, int k);
+void f(int i = 1, int j, int k);
+void f(int i, int j, int k);
+
+void i()
+{
+ f();
+ f(0);
+ f(0, 1);
+ f(0, 1, 2);
+}
+
+
+int f1(int i, int i, int j) { // expected-error {{redefinition of parameter 'i'}}
+ i = 17;
+ return j;
+}
+
+int x;
+void g(int x, int y = x); // expected-error {{default argument references parameter 'x'}}
+
+void h()
+{
+ int i;
+ extern void h2(int x = sizeof(i)); // expected-error {{default argument references local variable 'i' of enclosing function}}
+}
+
+void g2(int x, int y, int z = x + y); // expected-error {{default argument references parameter 'x'}} expected-error {{default argument references parameter 'y'}}
+
+void nondecl(int (*f)(int x = 5)) // {expected-error {{default arguments can only be specified}}}
+{
+ void (*f2)(int = 17) // {expected-error {{default arguments can only be specified}}}
+ = (void (*)(int = 42))f; // {expected-error {{default arguments can only be specified}}}
+}
+
+class X {
+ void f(X* x = this); // expected-error{{invalid use of 'this' outside of a nonstatic member function}}
+
+ void g() {
+ int f(X* x = this); // expected-error{{default argument references 'this'}}
+ }
+};
+
+// C++ [dcl.fct.default]p6
+class C {
+ static int x;
+ void f(int i = 3); // expected-note{{previous definition is here}}
+ void g(int i, int j = x);
+
+ void h();
+};
+void C::f(int i = 3) // expected-error{{redefinition of default argument}}
+{ }
+
+void C::g(int i = 88, int j) {}
+
+void C::h() {
+ g(); // okay
+}
+
+// C++ [dcl.fct.default]p9
+struct Y {
+ int a;
+ int mem1(int i = a); // expected-error{{invalid use of nonstatic data member 'a'}}
+ int mem2(int i = b); // OK; use Y::b
+ int mem3(int i);
+ int mem4(int i);
+
+ struct Nested {
+ int mem5(int i = b, // OK; use Y::b
+ int j = c, // OK; use Y::Nested::c
+ int k = j, // expected-error{{default argument references parameter 'j'}}
+ int l = a, // expected-error{{invalid use of nonstatic data member 'a'}}
+ Nested* self = this, // expected-error{{invalid use of 'this' outside of a nonstatic member function}}
+ int m); // expected-error{{missing default argument on parameter 'm'}}
+ static int c;
+ };
+
+ static int b;
+
+ int (*f)(int = 17); // expected-error{{default arguments can only be specified for parameters in a function declaration}}
+
+ void mem8(int (*fp)(int) = (int (*)(int = 17))0); // expected-error{{default arguments can only be specified for parameters in a function declaration}}
+};
+
+int Y::mem3(int i = b) { return i; } // OK; use X::b
+
+int Y::mem4(int i = a) // expected-error{{invalid use of nonstatic data member 'a'}}
+{ return i; }
+
+
+// Try to verify that default arguments interact properly with copy
+// constructors.
+class Z {
+public:
+ Z(Z&, int i = 17); // expected-note 2 {{candidate function}}
+
+ void f(Z& z) {
+ Z z2; // expected-error{{no matching constructor for initialization}}
+ Z z3(z);
+ }
+
+ void test_Z(const Z& z) {
+ Z z2(z); // expected-error{{no matching constructor for initialization of 'z2'}}
+ }
+};
+
+void test_Z(const Z& z) {
+ Z z2(z); // expected-error{{no matching constructor for initialization of 'z2'}}
+}
+
+struct ZZ {
+ void f(ZZ z = g()); // expected-error{{no matching constructor for initialization}}
+
+ static ZZ g(int = 17);
+
+ ZZ(ZZ&, int = 17); // expected-note{{candidate function}}
+};
diff --git a/test/SemaCXX/deleted-function.cpp b/test/SemaCXX/deleted-function.cpp
new file mode 100644
index 000000000000..8064ed349b08
--- /dev/null
+++ b/test/SemaCXX/deleted-function.cpp
@@ -0,0 +1,36 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+
+int i = delete; // expected-error {{only functions can have deleted definitions}}
+
+void fn() = delete; // expected-note {{candidate function has been explicitly deleted}}
+
+void fn2(); // expected-note {{previous declaration is here}}
+void fn2() = delete; // expected-error {{deleted definition must be first declaration}}
+
+void fn3() = delete;
+void fn3() {
+ // FIXME: This definition should be invalid.
+}
+
+void ov(int) {} // expected-note {{candidate function}}
+void ov(double) = delete; // expected-note {{candidate function has been explicitly deleted}}
+
+struct WithDel {
+ WithDel() = delete; // expected-note {{candidate function has been explicitly deleted}}
+ void fn() = delete; // expected-note {{function has been explicitly marked deleted here}}
+ operator int() = delete;
+ void operator +(int) = delete;
+
+ int i = delete; // expected-error {{only functions can have deleted definitions}}
+};
+
+void test() {
+ fn(); // expected-error {{call to deleted function 'fn'}}
+ ov(1);
+ ov(1.0); // expected-error {{call to deleted function 'ov'}}
+
+ WithDel dd; // expected-error {{call to deleted constructor of 'dd'}}
+ WithDel *d = 0;
+ d->fn(); // expected-error {{attempt to use a deleted function}}
+ int i = *d; // expected-error {{incompatible type initializing}}
+}
diff --git a/test/SemaCXX/dependent-types.cpp b/test/SemaCXX/dependent-types.cpp
new file mode 100644
index 000000000000..b2a5c45787c9
--- /dev/null
+++ b/test/SemaCXX/dependent-types.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+
+template<typename T, int Size> void f() {
+ T x1;
+ T* x2;
+ T& x3; // expected-error{{declaration of reference variable 'x3' requires an initializer}}
+ T x4[]; // expected-error{{variable has incomplete type 'T []'}}
+ T x5[Size];
+ int x6[Size];
+}
diff --git a/test/SemaCXX/derived-to-base-ambig.cpp b/test/SemaCXX/derived-to-base-ambig.cpp
new file mode 100644
index 000000000000..e15ddde9d91f
--- /dev/null
+++ b/test/SemaCXX/derived-to-base-ambig.cpp
@@ -0,0 +1,33 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class A { };
+class B : public A { };
+class C : public A { };
+class D : public B, public C { };
+
+void f(D* d) {
+ A* a;
+ a = d; // expected-error{{ambiguous conversion from derived class 'class D' to base class 'class A'}} expected-error{{incompatible type assigning 'class D *', expected 'class A *'}}
+}
+
+class Object2 { };
+class A2 : public Object2 { };
+class B2 : public virtual A2 { };
+class C2 : virtual public A2 { };
+class D2 : public B2, public C2 { };
+class E2 : public D2, public C2, public virtual A2 { };
+class F2 : public E2, public A2 { };
+
+void g(E2* e2, F2* f2) {
+ Object2* o2;
+ o2 = e2;
+ o2 = f2; // expected-error{{ambiguous conversion from derived class 'class F2' to base class 'class Object2'}} expected-error{{incompatible type assigning 'class F2 *', expected 'class Object2 *'}}
+}
+
+// Test that ambiguous/inaccessibility checking does not trigger too
+// early, because it should not apply during overload resolution.
+void overload_okay(Object2*);
+void overload_okay(E2*);
+
+void overload_call(F2* f2) {
+ overload_okay(f2);
+}
diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp
new file mode 100644
index 000000000000..f544db0b1b6e
--- /dev/null
+++ b/test/SemaCXX/destructor.cpp
@@ -0,0 +1,56 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class A {
+public:
+ ~A();
+};
+
+class B {
+public:
+ ~B() { }
+};
+
+class C {
+public:
+ (~C)() { }
+};
+
+struct D {
+ static void ~D(int, ...) const { } // \
+ // expected-error{{type qualifier is not allowed on this function}} \
+ // expected-error{{destructor cannot be declared 'static'}} \
+ // expected-error{{destructor cannot have any parameters}} \
+ // expected-error{{destructor cannot be variadic}}
+};
+
+struct D2 {
+ void ~D2() { } // \
+ // expected-error{{destructor cannot have a return type}}
+};
+
+
+struct E;
+
+typedef E E_typedef;
+struct E {
+ ~E_typedef(); // expected-error{{destructor cannot be declared using a typedef 'E_typedef' (aka 'struct E') of the class name}}
+};
+
+struct F {
+ (~F)(); // expected-note {{previous declaration is here}}
+ ~F(); // expected-error {{destructor cannot be redeclared}}
+};
+
+~; // expected-error {{expected class name}}
+~undef(); // expected-error {{expected class name}}
+~F(){} // expected-error {{destructor must be a non-static member function}}
+
+struct G {
+ ~G();
+};
+
+G::~G() { }
+
+// <rdar://problem/6841210>
+struct H {
+ ~H(void) { }
+};
diff --git a/test/SemaCXX/direct-initializer.cpp b/test/SemaCXX/direct-initializer.cpp
new file mode 100644
index 000000000000..149b65c8d71d
--- /dev/null
+++ b/test/SemaCXX/direct-initializer.cpp
@@ -0,0 +1,36 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int x(1);
+int (x2)(1);
+
+void f() {
+ int x(1);
+ int (x2)(1);
+ for (int x(1);;) {}
+}
+
+class Y {
+ explicit Y(float);
+};
+
+class X { // expected-note{{candidate function}}
+public:
+ explicit X(int); // expected-note{{candidate function}}
+ X(float, float, float); // expected-note{{candidate function}}
+ X(float, Y); // expected-note{{candidate function}}
+};
+
+class Z {
+public:
+ Z(int);
+};
+
+void g() {
+ X x1(5);
+ X x2(1.0, 3, 4.2);
+ X x3(1.0, 1.0); // expected-error{{no matching constructor for initialization of 'x3'; candidates are:}}
+ Y y(1.0);
+ X x4(3.14, y);
+
+ Z z; // expected-error{{no matching constructor for initialization of 'z'}}
+}
diff --git a/test/SemaCXX/do-while-scope.cpp b/test/SemaCXX/do-while-scope.cpp
new file mode 100644
index 000000000000..4e4a48325c1c
--- /dev/null
+++ b/test/SemaCXX/do-while-scope.cpp
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void test() {
+ int x;
+ do
+ int x;
+ while (1);
+}
diff --git a/test/SemaCXX/dynamic-cast.cpp b/test/SemaCXX/dynamic-cast.cpp
new file mode 100644
index 000000000000..42c5e0132a82
--- /dev/null
+++ b/test/SemaCXX/dynamic-cast.cpp
@@ -0,0 +1,74 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct A {};
+struct B : A {};
+struct C : B {};
+
+struct D : private A {};
+struct E : A {};
+struct F : B, E {};
+
+struct Incomplete; // expected-note 2 {{forward declaration of 'struct Incomplete'}}
+
+struct Poly
+{
+ virtual void f();
+};
+
+struct PolyDerived : Poly
+{
+};
+
+void basic_bad()
+{
+ // ptr -> nonptr
+ (void)dynamic_cast<A>((A*)0); // expected-error {{'struct A' is not a reference or pointer}}
+ // nonptr -> ptr
+ (void)dynamic_cast<A*>(0); // expected-error {{'int' is not a pointer}}
+ // ptr -> noncls
+ (void)dynamic_cast<int*>((A*)0); // expected-error {{'int' is not a class}}
+ // noncls -> ptr
+ (void)dynamic_cast<A*>((int*)0); // expected-error {{'int' is not a class}}
+ // ref -> noncls
+ (void)dynamic_cast<int&>(*((A*)0)); // expected-error {{'int' is not a class}}
+ // noncls -> ref
+ (void)dynamic_cast<A&>(*((int*)0)); // expected-error {{'int' is not a class}}
+ // ptr -> incomplete
+ (void)dynamic_cast<Incomplete*>((A*)0); // expected-error {{'struct Incomplete' is an incomplete type}}
+ // incomplete -> ptr
+ (void)dynamic_cast<A*>((Incomplete*)0); // expected-error {{'struct Incomplete' is an incomplete type}}
+}
+
+void same()
+{
+ (void)dynamic_cast<A*>((A*)0);
+ (void)dynamic_cast<A&>(*((A*)0));
+}
+
+void up()
+{
+ (void)dynamic_cast<A*>((B*)0);
+ (void)dynamic_cast<A&>(*((B*)0));
+ (void)dynamic_cast<A*>((C*)0);
+ (void)dynamic_cast<A&>(*((C*)0));
+
+ // Inaccessible
+ //(void)dynamic_cast<A*>((D*)0);
+ //(void)dynamic_cast<A&>(*((D*)0));
+
+ // Ambiguous
+ (void)dynamic_cast<A*>((F*)0); // expected-error {{ambiguous conversion from derived class 'struct F' to base class 'struct A':\n struct F -> struct B -> struct A\n struct F -> struct E -> struct A}}
+ (void)dynamic_cast<A&>(*((F*)0)); // expected-error {{ambiguous conversion from derived class 'struct F' to base class 'struct A':\n struct F -> struct B -> struct A\n struct F -> struct E -> struct A}}
+}
+
+void poly()
+{
+ (void)dynamic_cast<A*>((Poly*)0);
+ (void)dynamic_cast<A&>(*((Poly*)0));
+ (void)dynamic_cast<A*>((PolyDerived*)0);
+ (void)dynamic_cast<A&>(*((PolyDerived*)0));
+
+ // Not polymorphic source
+ (void)dynamic_cast<Poly*>((A*)0); // expected-error {{'struct A' is not polymorphic}}
+ (void)dynamic_cast<PolyDerived&>(*((A*)0)); // expected-error {{'struct A' is not polymorphic}}
+}
diff --git a/test/SemaCXX/elaborated-type-specifier.cpp b/test/SemaCXX/elaborated-type-specifier.cpp
new file mode 100644
index 000000000000..70478e0f32c4
--- /dev/null
+++ b/test/SemaCXX/elaborated-type-specifier.cpp
@@ -0,0 +1,47 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Test the use of elaborated-type-specifiers to inject the names of
+// structs (or classes or unions) into an outer scope as described in
+// C++ [basic.scope.pdecl]p5.
+typedef struct S1 {
+ union {
+ struct S2 *x;
+ struct S3 *y;
+ };
+} S1;
+
+bool test_elab(S1 *s1, struct S2 *s2, struct S3 *s3) {
+ if (s1->x == s2) return true;
+ if (s1->y == s3) return true;
+ return false;
+}
+
+namespace NS {
+ class X {
+ public:
+ void test_elab2(struct S4 *s4);
+ };
+
+ void X::test_elab2(S4 *s4) { }
+}
+
+void test_X_elab(NS::X x) {
+ struct S4 *s4 = 0;
+ x.test_elab2(s4); // expected-error{{incompatible type passing 'struct S4 *', expected 'struct NS::S4 *'}}
+}
+
+namespace NS {
+ S4 *get_S4();
+}
+
+void test_S5_scope() {
+ S4 *s4; // expected-error{{use of undeclared identifier 'S4'}}
+}
+
+int test_funcparam_scope(struct S5 * s5) {
+ struct S5 { int y; } *s5_2 = 0;
+ if (s5 == s5_2) return 1; // expected-error {{comparison of distinct pointer types ('struct S5 *' and 'struct S5 *')}}
+ return 0;
+}
+
+
diff --git a/test/SemaCXX/enum.cpp b/test/SemaCXX/enum.cpp
new file mode 100644
index 000000000000..9668c84693d3
--- /dev/null
+++ b/test/SemaCXX/enum.cpp
@@ -0,0 +1,38 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+enum E {
+ Val1,
+ Val2
+};
+
+int& enumerator_type(int);
+float& enumerator_type(E);
+
+void f() {
+ E e = Val1;
+ float& fr = enumerator_type(Val2);
+}
+
+// <rdar://problem/6502934>
+typedef enum Foo {
+ A = 0,
+ B = 1
+} Foo;
+
+
+void bar() {
+ Foo myvar = A;
+ myvar = B;
+}
+
+/// PR3688
+struct s1 {
+ enum e1 (*bar)(void); // expected-error{{ISO C++ forbids forward references to 'enum' types}} expected-note{{forward declaration of 'enum s1::e1'}}
+};
+
+enum e1 { YES, NO };
+
+static enum e1 badfunc(struct s1 *q) {
+ return q->bar(); // expected-error{{return type of called function ('enum s1::e1') is incomplete}}
+}
+
+enum e2; // expected-error{{ISO C++ forbids forward references to 'enum' types}}
diff --git a/test/SemaCXX/exception-spec.cpp b/test/SemaCXX/exception-spec.cpp
new file mode 100644
index 000000000000..ea02aac4915f
--- /dev/null
+++ b/test/SemaCXX/exception-spec.cpp
@@ -0,0 +1,35 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Straight from the standard:
+// Plain function with spec
+void f() throw(int);
+// Pointer to function with spec
+void (*fp)() throw (int);
+// Function taking reference to function with spec
+void g(void pfa() throw(int));
+// Typedef for pointer to function with spec
+typedef int (*pf)() throw(int); // expected-error {{specifications are not allowed in typedefs}}
+
+// Some more:
+// Function returning function with spec
+void (*h())() throw(int);
+// Ultimate parser thrill: function with spec returning function with spec and
+// taking pointer to function with spec.
+// The actual function throws int, the return type double, the argument float.
+void (*i() throw(int))(void (*)() throw(float)) throw(double);
+// Pointer to pointer to function taking function with spec
+void (**k)(void pfa() throw(int)); // no-error
+// Pointer to pointer to function with spec
+void (**j)() throw(int); // expected-error {{not allowed beyond a single}}
+// Pointer to function returning pointer to pointer to function with spec
+void (**(*h())())() throw(int); // expected-error {{not allowed beyond a single}}
+
+struct Incomplete;
+
+// Exception spec must not have incomplete types, or pointers to them, except
+// void.
+void ic1() throw(void); // expected-error {{incomplete type 'void' is not allowed in exception specification}}
+void ic2() throw(Incomplete); // expected-error {{incomplete type 'struct Incomplete' is not allowed in exception specification}}
+void ic3() throw(void*);
+void ic4() throw(Incomplete*); // expected-error {{pointer to incomplete type 'struct Incomplete' is not allowed in exception specification}}
+void ic5() throw(Incomplete&); // expected-error {{reference to incomplete type 'struct Incomplete' is not allowed in exception specification}}
diff --git a/test/SemaCXX/exceptions.cpp b/test/SemaCXX/exceptions.cpp
new file mode 100644
index 000000000000..5882b9cb7083
--- /dev/null
+++ b/test/SemaCXX/exceptions.cpp
@@ -0,0 +1,99 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct A; // expected-note 4 {{forward declaration of 'struct A'}}
+
+struct Abstract { virtual void f() = 0; }; // expected-note {{pure virtual function 'f'}}
+
+void trys() {
+ try {
+ } catch(int i) { // expected-note {{previous definition}}
+ int j = i;
+ int i; // expected-error {{redefinition of 'i'}}
+ } catch(float i) {
+ } catch(void v) { // expected-error {{cannot catch incomplete type 'void'}}
+ } catch(A a) { // expected-error {{cannot catch incomplete type 'struct A'}}
+ } catch(A *a) { // expected-error {{cannot catch pointer to incomplete type 'struct A'}}
+ } catch(A &a) { // expected-error {{cannot catch reference to incomplete type 'struct A'}}
+ } catch(Abstract) { // expected-error {{variable type 'Abstract' is an abstract class}}
+ } catch(...) {
+ int j = i; // expected-error {{use of undeclared identifier 'i'}}
+ }
+
+ try {
+ } catch(...) { // expected-error {{catch-all handler must come last}}
+ } catch(int) {
+ }
+}
+
+void throws() {
+ throw;
+ throw 0;
+ throw throw; // expected-error {{cannot throw object of incomplete type 'void'}}
+ throw (A*)0; // expected-error {{cannot throw pointer to object of incomplete type 'struct A'}}
+}
+
+void jumps() {
+l1:
+ goto l5;
+ goto l4; // expected-error {{illegal goto into protected scope}}
+ goto l3; // expected-error {{illegal goto into protected scope}}
+ goto l2; // expected-error {{illegal goto into protected scope}}
+ goto l1;
+ try { // expected-note 4 {{jump bypasses initialization of try block}}
+ l2:
+ goto l5;
+ goto l4; // expected-error {{illegal goto into protected scope}}
+ goto l3; // expected-error {{illegal goto into protected scope}}
+ goto l2;
+ goto l1;
+ } catch(int) { // expected-note 4 {{jump bypasses initialization of catch block}}
+ l3:
+ goto l5;
+ goto l4; // expected-error {{illegal goto into protected scope}}
+ goto l3;
+ goto l2; // expected-error {{illegal goto into protected scope}}
+ goto l1;
+ } catch(...) { // expected-note 4 {{jump bypasses initialization of catch block}}
+ l4:
+ goto l5;
+ goto l4;
+ goto l3; // expected-error {{illegal goto into protected scope}}
+ goto l2; // expected-error {{illegal goto into protected scope}}
+ goto l1;
+ }
+l5:
+ goto l5;
+ goto l4; // expected-error {{illegal goto into protected scope}}
+ goto l3; // expected-error {{illegal goto into protected scope}}
+ goto l2; // expected-error {{illegal goto into protected scope}}
+ goto l1;
+}
+
+struct BadReturn {
+ BadReturn() try {
+ } catch(...) {
+ // Try to hide
+ try {
+ } catch(...) {
+ {
+ if (0)
+ return; // expected-error {{return in the catch of a function try block of a constructor is illegal}}
+ }
+ }
+ }
+ BadReturn(int);
+};
+
+BadReturn::BadReturn(int) try {
+} catch(...) {
+ // Try to hide
+ try {
+ } catch(int) {
+ return; // expected-error {{return in the catch of a function try block of a constructor is illegal}}
+ } catch(...) {
+ {
+ if (0)
+ return; // expected-error {{return in the catch of a function try block of a constructor is illegal}}
+ }
+ }
+}
diff --git a/test/SemaCXX/expressions.cpp b/test/SemaCXX/expressions.cpp
new file mode 100644
index 000000000000..6a2f30d33e5e
--- /dev/null
+++ b/test/SemaCXX/expressions.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void choice(int);
+int choice(bool);
+
+void test() {
+ // Result of ! must be type bool.
+ int i = choice(!1);
+}
diff --git a/test/SemaCXX/fntype-decl.cpp b/test/SemaCXX/fntype-decl.cpp
new file mode 100644
index 000000000000..ae85ff45353d
--- /dev/null
+++ b/test/SemaCXX/fntype-decl.cpp
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// PR2942
+typedef void fn(int);
+fn f; // expected-note {{previous declaration is here}}
+
+int g(int x, int y);
+int g(int x, int y = 2);
+
+typedef int g_type(int, int);
+g_type g;
+
+int h(int x) { // expected-note {{previous definition is here}}
+ return g(x);
+}
+
+float f(int) { } // expected-error{{functions that differ only in their return type cannot be overloaded}}
+
+int h(int) { } // expected-error{{redefinition of 'h'}}
+
diff --git a/test/SemaCXX/friend.cpp b/test/SemaCXX/friend.cpp
new file mode 100644
index 000000000000..76e84e5fbe84
--- /dev/null
+++ b/test/SemaCXX/friend.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+friend class A; // expected-error {{'friend' used outside of class}}
+void f() { friend class A; } // expected-error {{'friend' used outside of class}}
+class C { friend class A; };
+class D { void f() { friend class A; } }; // expected-error {{'friend' used outside of class}}
diff --git a/test/SemaCXX/function-redecl.cpp b/test/SemaCXX/function-redecl.cpp
new file mode 100644
index 000000000000..9f6783731d33
--- /dev/null
+++ b/test/SemaCXX/function-redecl.cpp
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+int foo(int);
+
+namespace N {
+ void f1() {
+ void foo(int); // okay
+ }
+
+ // FIXME: we shouldn't even need this declaration to detect errors
+ // below.
+ void foo(int); // expected-note{{previous declaration is here}}
+
+ void f2() {
+ int foo(int); // expected-error{{functions that differ only in their return type cannot be overloaded}}
+
+ {
+ int foo;
+ {
+ // FIXME: should diagnose this because it's incompatible with
+ // N::foo. However, name lookup isn't properly "skipping" the
+ // "int foo" above.
+ float foo(int);
+ }
+ }
+ }
+}
diff --git a/test/SemaCXX/function-type-qual.cpp b/test/SemaCXX/function-type-qual.cpp
new file mode 100644
index 000000000000..f1d5aac7fc99
--- /dev/null
+++ b/test/SemaCXX/function-type-qual.cpp
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f() const; // expected-error {{type qualifier is not allowed on this function}}
+
+typedef void cfn() const;
+cfn f2; // expected-error {{a qualified function type cannot be used to declare a nonmember function or a static member function}}
+
+class C {
+ void f() const;
+ cfn f2;
+ static void f3() const; // expected-error {{type qualifier is not allowed on this function}}
+ static cfn f4; // expected-error {{a qualified function type cannot be used to declare a nonmember function or a static member function}}
+
+ void m1() {
+ x = 0;
+ }
+
+ void m2() const {
+ x = 0; // expected-error {{read-only variable is not assignable}}
+ }
+
+ int x;
+};
diff --git a/test/SemaCXX/functional-cast.cpp b/test/SemaCXX/functional-cast.cpp
new file mode 100644
index 000000000000..0be7ddb53ae8
--- /dev/null
+++ b/test/SemaCXX/functional-cast.cpp
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct SimpleValueInit {
+ int i;
+};
+
+struct InitViaConstructor {
+ InitViaConstructor(int i = 7);
+};
+
+// FIXME: error messages for implicitly-declared special member
+// function candidates are very poor
+struct NoValueInit { // expected-note 2 {{candidate function}}
+ NoValueInit(int i, int j); // expected-note 2 {{candidate function}}
+};
+
+void test_cxx_functional_value_init() {
+ (void)SimpleValueInit();
+ (void)InitViaConstructor();
+ (void)NoValueInit(); // expected-error{{no matching constructor for initialization}}
+}
+
+void test_cxx_function_cast_multi() {
+ (void)NoValueInit(0, 0);
+ (void)NoValueInit(0, 0, 0); // expected-error{{no matching constructor for initialization}}
+ (void)int(1, 2); // expected-error{{function-style cast to a builtin type can only take one argument}}
+}
diff --git a/test/SemaCXX/i-c-e-cxx.cpp b/test/SemaCXX/i-c-e-cxx.cpp
new file mode 100644
index 000000000000..32d04e2da40b
--- /dev/null
+++ b/test/SemaCXX/i-c-e-cxx.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// C++-specific tests for integral constant expressions.
+
+const int c = 10;
+int ar[c];
diff --git a/test/SemaCXX/implicit-int.cpp b/test/SemaCXX/implicit-int.cpp
new file mode 100644
index 000000000000..6fa8dd3463d3
--- /dev/null
+++ b/test/SemaCXX/implicit-int.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+x; // expected-error{{C++ requires a type specifier for all declarations}}
+
+f(int y) { return y; } // expected-error{{C++ requires a type specifier for all declarations}}
diff --git a/test/SemaCXX/inherit.cpp b/test/SemaCXX/inherit.cpp
new file mode 100644
index 000000000000..eaad97cc82a0
--- /dev/null
+++ b/test/SemaCXX/inherit.cpp
@@ -0,0 +1,32 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class A { };
+
+class B1 : A { };
+
+class B2 : virtual A { };
+
+class B3 : virtual virtual A { }; // expected-error{{duplicate 'virtual' in base specifier}}
+
+class C : public B1, private B2 { };
+
+
+class D; // expected-note {{forward declaration of 'class D'}}
+
+class E : public D { }; // expected-error{{base class has incomplete type}}
+
+typedef int I;
+
+class F : public I { }; // expected-error{{base specifier must name a class}}
+
+union U1 : public A { }; // expected-error{{unions cannot have base classes}}
+
+union U2 {};
+
+class G : public U2 { }; // expected-error{{unions cannot be base classes}}
+
+typedef G G_copy;
+typedef G G_copy_2;
+typedef G_copy G_copy_3;
+
+class H : G_copy, A, G_copy_2, // expected-error{{base class 'G_copy' (aka 'class G') specified more than once as a direct base class}}
+ public G_copy_3 { }; // expected-error{{base class 'G_copy' (aka 'class G') specified more than once as a direct base class}}
diff --git a/test/SemaCXX/inline.cpp b/test/SemaCXX/inline.cpp
new file mode 100644
index 000000000000..7d0505a435ee
--- /dev/null
+++ b/test/SemaCXX/inline.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Check that we don't allow illegal uses of inline
+// (checking C++-only constructs here)
+struct c {inline int a;}; // expected-error{{'inline' can only appear on functions}}
diff --git a/test/SemaCXX/linkage-spec.cpp b/test/SemaCXX/linkage-spec.cpp
new file mode 100644
index 000000000000..864953e9f9c2
--- /dev/null
+++ b/test/SemaCXX/linkage-spec.cpp
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+extern "C" {
+ extern "C" void f(int);
+}
+
+extern "C++" {
+ extern "C++" int& g(int);
+ float& g();
+}
+double& g(double);
+
+void test(int x, double d) {
+ f(x);
+ float &f1 = g();
+ int& i1 = g(x);
+ double& d1 = g(d);
+}
+
+extern "C" int foo;
+extern "C" int foo;
+
+extern "C" const int bar;
+extern "C" int const bar;
+
+// <rdar://problem/6895431>
+extern "C" struct bar d;
+extern struct bar e;
diff --git a/test/SemaCXX/member-expr-static.cpp b/test/SemaCXX/member-expr-static.cpp
new file mode 100644
index 000000000000..b6495a852041
--- /dev/null
+++ b/test/SemaCXX/member-expr-static.cpp
@@ -0,0 +1,21 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+typedef void (*thread_continue_t)();
+
+extern "C" {
+extern void kernel_thread_start(thread_continue_t continuation);
+extern void pure_c(void);
+}
+
+class _IOConfigThread
+{
+public:
+ static void main( void );
+};
+
+
+void foo( void )
+{
+ kernel_thread_start(&_IOConfigThread::main);
+ kernel_thread_start((thread_continue_t)&_IOConfigThread::main);
+ kernel_thread_start(&pure_c);
+}
diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp
new file mode 100644
index 000000000000..60ee10df7f6a
--- /dev/null
+++ b/test/SemaCXX/member-expr.cpp
@@ -0,0 +1,33 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class X{
+public:
+ enum E {Enumerator};
+ int f();
+ static int mem;
+ static float g();
+};
+
+void test(X* xp, X x) {
+ int i1 = x.f();
+ int i2 = xp->f();
+ x.E; // expected-error{{cannot refer to type member 'E' with '.'}}
+ xp->E; // expected-error{{cannot refer to type member 'E' with '->'}}
+ int i3 = x.Enumerator;
+ int i4 = xp->Enumerator;
+ x.mem = 1;
+ xp->mem = 2;
+ float f1 = x.g();
+ float f2 = xp->g();
+}
+
+struct A {
+ int f0;
+};
+struct B {
+ A *f0();
+};
+int f0(B *b) {
+ return b->f0->f0; // expected-error{{member reference base type 'struct A *(void)' is not a structure or union}} \
+ // expected-note{{perhaps you meant to call this function}}
+}
diff --git a/test/SemaCXX/member-location.cpp b/test/SemaCXX/member-location.cpp
new file mode 100644
index 000000000000..cb53ae15123d
--- /dev/null
+++ b/test/SemaCXX/member-location.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// PR4103: Make sure we have a location for the error
+class A { float a(int *); int b(); };
+int A::b() { return a(a((int*)0)); } // expected-error {{incompatible type}}
+
diff --git a/test/SemaCXX/member-name-lookup.cpp b/test/SemaCXX/member-name-lookup.cpp
new file mode 100644
index 000000000000..9fcd922ddf7d
--- /dev/null
+++ b/test/SemaCXX/member-name-lookup.cpp
@@ -0,0 +1,148 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct A {
+ int a; // expected-note 4{{member found by ambiguous name lookup}}
+ static int b;
+ static int c; // expected-note 4{{member found by ambiguous name lookup}}
+
+ enum E { enumerator };
+
+ typedef int type;
+
+ static void f(int);
+ void f(float); // expected-note 2{{member found by ambiguous name lookup}}
+
+ static void static_f(int);
+ static void static_f(double);
+};
+
+struct B : A {
+ int d; // expected-note 2{{member found by ambiguous name lookup}}
+
+ enum E2 { enumerator2 };
+
+ enum E3 { enumerator3 }; // expected-note 2{{member found by ambiguous name lookup}}
+};
+
+struct C : A {
+ int c; // expected-note 2{{member found by ambiguous name lookup}}
+ int d; // expected-note 2{{member found by ambiguous name lookup}}
+
+ enum E3 { enumerator3_2 }; // expected-note 2{{member found by ambiguous name lookup}}
+};
+
+struct D : B, C {
+ void test_lookup();
+};
+
+void test_lookup(D d) {
+ d.a; // expected-error{{non-static member 'a' found in multiple base-class subobjects of type 'struct A'}}
+ (void)d.b; // okay
+ d.c; // expected-error{{member 'c' found in multiple base classes of different types}}
+ d.d; // expected-error{{member 'd' found in multiple base classes of different types}}
+ d.f(0); // expected-error{{non-static member 'f' found in multiple base-class subobjects of type 'struct A'}}
+ d.static_f(0); // okay
+
+ D::E e = D::enumerator; // okay
+ D::type t = 0; // okay
+
+ D::E2 e2 = D::enumerator2; // okay
+
+ D::E3 e3; // expected-error{{multiple base classes}}
+}
+
+void D::test_lookup() {
+ a; // expected-error{{non-static member 'a' found in multiple base-class subobjects of type 'struct A'}}
+ (void)b; // okay
+ c; // expected-error{{member 'c' found in multiple base classes of different types}}
+ d; // expected-error{{member 'd' found in multiple base classes of different types}}
+ f(0); // expected-error{{non-static member 'f' found in multiple base-class subobjects of type 'struct A'}}
+ static_f(0); // okay
+
+ E e = enumerator; // okay
+ type t = 0; // okay
+
+ E2 e2 = enumerator2; // okay
+
+ E3 e3; // expected-error{{member 'E3' found in multiple base classes of different types}}
+}
+
+struct B2 : virtual A {
+ int d; // expected-note 2{{member found by ambiguous name lookup}}
+
+ enum E2 { enumerator2 };
+
+ enum E3 { enumerator3 }; // expected-note 2 {{member found by ambiguous name lookup}}
+};
+
+struct C2 : virtual A {
+ int c; // expected-note 2{{member found by ambiguous name lookup}}
+ int d; // expected-note 2{{member found by ambiguous name lookup}}
+
+ enum E3 { enumerator3_2 }; // expected-note 2{{member found by ambiguous name lookup}}
+};
+
+struct D2 : B2, C2 {
+ void test_virtual_lookup();
+};
+
+struct F : A { };
+struct G : F, D2 {
+ void test_virtual_lookup();
+};
+
+void test_virtual_lookup(D2 d2, G g) {
+ (void)d2.a;
+ (void)d2.b;
+ d2.c; // expected-error{{member 'c' found in multiple base classes of different types}}
+ d2.d; // expected-error{{member 'd' found in multiple base classes of different types}}
+ d2.f(0); // okay
+ d2.static_f(0); // okay
+
+ D2::E e = D2::enumerator; // okay
+ D2::type t = 0; // okay
+
+ D2::E2 e2 = D2::enumerator2; // okay
+
+ D2::E3 e3; // expected-error{{member 'E3' found in multiple base classes of different types}}
+
+ g.a; // expected-error{{non-static member 'a' found in multiple base-class subobjects of type 'struct A'}}
+ g.static_f(0); // okay
+}
+
+void D2::test_virtual_lookup() {
+ (void)a;
+ (void)b;
+ c; // expected-error{{member 'c' found in multiple base classes of different types}}
+ d; // expected-error{{member 'd' found in multiple base classes of different types}}
+ f(0); // okay
+ static_f(0); // okay
+
+ E e = enumerator; // okay
+ type t = 0; // okay
+
+ E2 e2 = enumerator2; // okay
+
+ E3 e3; // expected-error{{member 'E3' found in multiple base classes of different types}}
+}
+
+void G::test_virtual_lookup() {
+ a; // expected-error{{non-static member 'a' found in multiple base-class subobjects of type 'struct A'}}
+ static_f(0); // okay
+}
+
+
+struct HasMemberType1 {
+ struct type { }; // expected-note{{member found by ambiguous name lookup}}
+};
+
+struct HasMemberType2 {
+ struct type { }; // expected-note{{member found by ambiguous name lookup}}
+};
+
+struct HasAnotherMemberType : HasMemberType1, HasMemberType2 {
+ struct type { };
+};
+
+struct UsesAmbigMemberType : HasMemberType1, HasMemberType2 {
+ type t; // expected-error{{member 'type' found in multiple base classes of different types}}
+};
diff --git a/test/SemaCXX/member-pointer-size.cpp b/test/SemaCXX/member-pointer-size.cpp
new file mode 100644
index 000000000000..f86e72b288cd
--- /dev/null
+++ b/test/SemaCXX/member-pointer-size.cpp
@@ -0,0 +1,15 @@
+// RUN: clang-cc -triple x86_64-unknown-unknown %s -fsyntax-only -verify &&
+// RUN: clang-cc -triple i686-unknown-unknown %s -fsyntax-only -verify
+#include <stddef.h>
+
+struct A;
+
+void f() {
+ int A::*dataMember;
+
+ int (A::*memberFunction)();
+
+ typedef int assert1[sizeof(dataMember) == sizeof(ptrdiff_t) ? 1 : -1];
+ typedef int assert2[sizeof(memberFunction) == sizeof(ptrdiff_t) * 2 ? 1 : -1];
+}
+
diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp
new file mode 100644
index 000000000000..cfe4f75dd17d
--- /dev/null
+++ b/test/SemaCXX/member-pointer.cpp
@@ -0,0 +1,129 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct A {};
+enum B { Dummy };
+namespace C {}
+struct D : A {};
+struct E : A {};
+struct F : D, E {};
+struct G : virtual D {};
+
+int A::*pdi1;
+int (::A::*pdi2);
+int (A::*pfi)(int);
+
+int B::*pbi; // expected-error {{expected a class or namespace}}
+int C::*pci; // expected-error {{'pci' does not point into a class}}
+void A::*pdv; // expected-error {{'pdv' declared as a member pointer to void}}
+int& A::*pdr; // expected-error {{'pdr' declared as a pointer to a reference}}
+
+void f() {
+ // This requires tentative parsing.
+ int (A::*pf)(int, int);
+
+ // Implicit conversion to bool.
+ bool b = pdi1;
+ b = pfi;
+
+ // Conversion from null pointer constant.
+ pf = 0;
+ pf = __null;
+
+ // Conversion to member of derived.
+ int D::*pdid = pdi1;
+ pdid = pdi2;
+
+ // Fail conversion due to ambiguity and virtuality.
+ int F::*pdif = pdi1; // expected-error {{ambiguous conversion from pointer to member of base class 'struct A' to pointer to member of derived class 'struct F'}} expected-error {{incompatible type}}
+ int G::*pdig = pdi1; // expected-error {{conversion from pointer to member of class 'struct A' to pointer to member of class 'struct G' via virtual base 'struct D' is not allowed}} expected-error {{incompatible type}}
+
+ // Conversion to member of base.
+ pdi1 = pdid; // expected-error {{incompatible type assigning 'int struct D::*', expected 'int struct A::*'}}
+}
+
+struct TheBase
+{
+ void d();
+};
+
+struct HasMembers : TheBase
+{
+ int i;
+ void f();
+
+ void g();
+ void g(int);
+ static void g(double);
+};
+
+namespace Fake
+{
+ int i;
+ void f();
+}
+
+void g() {
+ HasMembers hm;
+
+ int HasMembers::*pmi = &HasMembers::i;
+ int *pni = &Fake::i;
+ int *pmii = &hm.i;
+
+ void (HasMembers::*pmf)() = &HasMembers::f;
+ void (*pnf)() = &Fake::f;
+ &hm.f; // FIXME: needs diagnostic expected-warning{{result unused}}
+
+ void (HasMembers::*pmgv)() = &HasMembers::g;
+ void (HasMembers::*pmgi)(int) = &HasMembers::g;
+ void (*pmgd)(double) = &HasMembers::g;
+
+ void (HasMembers::*pmd)() = &HasMembers::d;
+}
+
+struct Incomplete;
+
+void h() {
+ HasMembers hm, *phm = &hm;
+
+ int HasMembers::*pi = &HasMembers::i;
+ hm.*pi = 0;
+ int i = phm->*pi;
+ (void)&(hm.*pi);
+ (void)&(phm->*pi);
+ (void)&((&hm)->*pi); // expected-error {{address expression must be an lvalue or a function designator}}
+
+ void (HasMembers::*pf)() = &HasMembers::f;
+ (hm.*pf)();
+ (phm->*pf)();
+
+ (void)(hm->*pi); // expected-error {{left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'struct HasMembers'}}
+ (void)(phm.*pi); // expected-error {{left hand operand to .* must be a class compatible with the right hand operand, but is 'struct HasMembers *'}}
+ (void)(i.*pi); // expected-error {{left hand operand to .* must be a class compatible with the right hand operand, but is 'int'}}
+ int *ptr;
+ (void)(ptr->*pi); // expected-error {{left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'int *'}}
+
+ int A::*pai = 0;
+ D d, *pd = &d;
+ (void)(d.*pai);
+ (void)(pd->*pai);
+ F f, *ptrf = &f;
+ (void)(f.*pai); // expected-error {{left hand operand to .* must be a class compatible with the right hand operand, but is 'struct F'}}
+ (void)(ptrf->*pai); // expected-error {{left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'struct F *'}}
+
+ (void)(hm.*i); // expected-error {{pointer-to-member}}
+ (void)(phm->*i); // expected-error {{pointer-to-member}}
+
+ Incomplete *inc;
+ int Incomplete::*pii = 0;
+ (void)(inc->*pii); // okay
+}
+
+struct OverloadsPtrMem
+{
+ int operator ->*(const char *);
+};
+
+void i() {
+ OverloadsPtrMem m;
+ int foo = m->*"Awesome!";
+}
diff --git a/test/SemaCXX/ms-exception-spec.cpp b/test/SemaCXX/ms-exception-spec.cpp
new file mode 100644
index 000000000000..b84ea178e1e2
--- /dev/null
+++ b/test/SemaCXX/ms-exception-spec.cpp
@@ -0,0 +1,3 @@
+// RUN: clang-cc %s -fsyntax-only -verify -fms-extensions
+
+void f() throw(...) { }
diff --git a/test/SemaCXX/namespace-alias.cpp b/test/SemaCXX/namespace-alias.cpp
new file mode 100644
index 000000000000..d5e423848cb5
--- /dev/null
+++ b/test/SemaCXX/namespace-alias.cpp
@@ -0,0 +1,64 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace N { };
+
+namespace A = N;
+
+int B; // expected-note {{previous definition is here}}
+namespace B = N; // expected-error {{redefinition of 'B' as different kind of symbol}}
+
+namespace C { } // expected-note {{previous definition is here}}
+namespace C = N; // expected-error {{redefinition of 'C'}}
+
+int i;
+namespace D = i; // expected-error {{expected namespace name}}
+
+namespace E = N::Foo; // expected-error {{expected namespace name}}
+
+namespace F {
+ namespace A { namespace B { } } // expected-note {{candidate found by name lookup is 'F::A::B'}}
+ namespace B { } // expected-note {{candidate found by name lookup is 'F::B'}}
+ using namespace A;
+ namespace D = B; // expected-error {{reference to 'B' is ambiguous}}
+}
+
+namespace G {
+ namespace B = N;
+}
+
+namespace H {
+ namespace A1 { }
+ namespace A2 { }
+
+ // These all point to A1.
+ namespace B = A1; // expected-note {{previous definition is here}}
+ namespace B = A1;
+ namespace C = B;
+ namespace B = C;
+
+ namespace B = A2; // expected-error {{redefinition of 'B' as different kind of symbol}}
+}
+
+namespace I {
+ namespace A1 { int i; }
+
+ namespace A2 = A1;
+}
+
+int f() {
+ return I::A2::i;
+}
+
+namespace J {
+ namespace A {
+ namespace B { void func (); }
+ }
+
+ namespace C = A;
+
+ using namespace C::B;
+
+ void g() {
+ func();
+ }
+}
diff --git a/test/SemaCXX/namespace.cpp b/test/SemaCXX/namespace.cpp
new file mode 100644
index 000000000000..696ea818f657
--- /dev/null
+++ b/test/SemaCXX/namespace.cpp
@@ -0,0 +1,69 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+namespace A { // expected-note 2 {{previous definition is here}}
+ int A;
+ void f() { A = 0; }
+}
+
+void f() { A = 0; } // expected-error {{unexpected namespace name 'A': expected expression}}
+int A; // expected-error {{redefinition of 'A' as different kind of symbol}}
+class A; // expected-error {{redefinition of 'A' as different kind of symbol}}
+
+class B {}; // expected-note {{previous definition is here}}
+
+void C(); // expected-note {{previous definition is here}}
+namespace C {} // expected-error {{redefinition of 'C' as different kind of symbol}}
+
+namespace D {
+ class D {};
+}
+
+namespace S1 {
+ int x;
+
+ namespace S2 {
+
+ namespace S3 {
+ B x;
+ }
+ }
+}
+
+namespace S1 {
+ void f() {
+ x = 0;
+ }
+
+ namespace S2 {
+
+ namespace S3 {
+ void f() {
+ x = 0; // expected-error {{no viable overloaded '='}}
+ }
+ }
+
+ int y;
+ }
+}
+
+namespace S1 {
+ namespace S2 {
+ namespace S3 {
+ void f3() {
+ y = 0;
+ }
+ }
+ }
+}
+
+namespace B {} // expected-error {{redefinition of 'B' as different kind of symbol}}
+
+
+namespace foo {
+ enum x {
+ Y
+ };
+}
+
+static foo::x test1; // ok
+
+static foo::X test2; // typo: expected-error {{unknown type name 'X'}}
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
new file mode 100644
index 000000000000..4c3ecee09051
--- /dev/null
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -0,0 +1,173 @@
+// RUN: clang-cc -fsyntax-only -std=c++98 -verify %s
+namespace A {
+ struct C {
+ static int cx;
+
+ static int cx2;
+
+ static int Ag1();
+ static int Ag2();
+ };
+ int ax;
+ void Af();
+}
+
+A:: ; // expected-error {{expected unqualified-id}}
+::A::ax::undef ex3; // expected-error {{expected a class or namespace}} expected-error {{unknown type name 'undef'}}
+A::undef1::undef2 ex4; // expected-error {{no member named 'undef1'}} expected-error {{unknown type name 'undef2'}}
+
+int A::C::Ag1() { return 0; }
+
+static int A::C::Ag2() { return 0; } // expected-error{{'static' can}}
+
+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 f(const int& parm); // expected-note{{member declaration nearly matches}}
+ void f(int) const; // expected-note{{member declaration nearly matches}}
+ void f(float);
+
+ int x;
+};
+
+void C2::m() const { } // expected-error{{out-of-line definition does not match any declaration in 'C2'}}
+
+void C2::f(int) { } // expected-error{{out-of-line definition does not match any declaration in 'C2'}}
+
+void C2::m() {
+ x = 0;
+}
+
+namespace B {
+ void ::A::Af() {} // expected-error {{definition or redeclaration of 'Af' not in a namespace enclosing 'A'}}
+}
+
+void f1() {
+ void A::Af(); // expected-error {{definition or redeclaration of 'Af' not allowed inside a function}}
+}
+
+void f2() {
+ A:: ; // expected-error {{expected unqualified-id}}
+ A::C::undef = 0; // expected-error {{no member named 'undef'}}
+ ::A::C::cx = 0;
+ int x = ::A::ax = A::C::cx;
+ x = sizeof(A::C);
+ x = sizeof(::A::C::cx);
+}
+
+A::C c1;
+struct A::C c2;
+struct S : public A::C {};
+struct A::undef; // expected-error {{'undef' does not name a tag member in the specified scope}}
+
+namespace A2 {
+ typedef int INT;
+ struct RC;
+ struct CC {
+ struct NC;
+ };
+}
+
+struct A2::RC {
+ INT x;
+};
+
+struct A2::CC::NC {
+ void m() {}
+};
+
+void f3() {
+ N::x = 0; // expected-error {{use of undeclared identifier 'N'}}
+ int N;
+ N::x = 0; // expected-error {{expected a class or namespace}}
+ { int A; A::ax = 0; }
+ { typedef int A; A::ax = 0; } // expected-error{{expected a class or namespace}}
+ { int A(); A::ax = 0; }
+ { typedef A::C A; A::ax = 0; } // expected-error {{no member named 'ax'}}
+ { typedef A::C A; A::cx = 0; }
+}
+
+// make sure the following doesn't hit any asserts
+void f4(undef::C); // expected-error {{use of undeclared identifier 'undef'}} \
+ expected-error {{variable has incomplete type 'void'}}
+
+typedef void C2::f5(int); // expected-error{{typedef declarator cannot be qualified}}
+
+void f6(int A2::RC::x); // expected-error{{parameter declarator cannot be qualified}}
+
+int A2::RC::x; // expected-error{{non-static data member defined out-of-line}}
+
+void A2::CC::NC::m(); // expected-error{{out-of-line declaration of a member must be a definition}}
+
+
+namespace E {
+ int X = 5;
+
+ namespace Nested {
+ enum E {
+ X = 0
+ };
+
+ void f() {
+ return E::X; // expected-error{{expected a class or namespace}}
+ }
+ }
+}
+
+
+class Operators {
+ Operators operator+(const Operators&) const; // expected-note{{member declaration nearly matches}}
+ operator bool();
+};
+
+Operators Operators::operator+(const Operators&) { // expected-error{{out-of-line definition does not match any declaration in 'Operators'}}
+ Operators ops;
+ return ops;
+}
+
+Operators Operators::operator+(const Operators&) const {
+ Operators ops;
+ return ops;
+}
+
+Operators::operator bool() {
+ return true;
+}
+
+namespace A {
+ void g(int&); // expected-note{{member declaration nearly matches}}
+}
+
+void A::f() {} // expected-error{{out-of-line definition does not match any declaration in 'A'}}
+
+void A::g(const int&) { } // expected-error{{out-of-line definition does not match any declaration in 'A'}}
+
+struct Struct { };
+
+void Struct::f() { } // expected-error{{out-of-line definition does not match any declaration in 'Struct'}}
+
+void global_func(int);
+void global_func2(int);
+
+namespace N {
+ void ::global_func(int) { } // expected-error{{definition or redeclaration of 'global_func' cannot name the global scope}}
+
+ void f();
+ // FIXME: if we move this to a separate definition of N, things break!
+}
+void ::global_func2(int) { } // expected-error{{definition or redeclaration of 'global_func2' cannot name the global scope}}
+
+void N::f() { } // okay
+
+struct Y; // expected-note{{forward declaration of 'struct Y'}}
+Y::foo y; // expected-error{{incomplete type 'struct Y' named in nested name specifier}} \
+ // expected-error{{unknown type name 'foo'}}
+
+X::X() : a(5) { } // expected-error{{use of undeclared identifier 'X'}} \
+ // expected-error{{C++ requires a type specifier for all declarations}} \
+ // expected-error{{only constructors take base initializers}}
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
new file mode 100644
index 000000000000..f890bf56e36b
--- /dev/null
+++ b/test/SemaCXX/new-delete.cpp
@@ -0,0 +1,97 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+#include <stddef.h>
+
+struct S // expected-note {{candidate}}
+{
+ S(int, int, double); // expected-note {{candidate}}
+ S(double, int); // expected-note 2 {{candidate}}
+ S(float, int); // expected-note 2 {{candidate}}
+};
+struct T; // expected-note{{forward declaration of 'struct T'}}
+struct U
+{
+ // A special new, to verify that the global version isn't used.
+ void* operator new(size_t, S*); // expected-note {{candidate}}
+};
+struct V : U
+{
+};
+
+void* operator new(size_t); // expected-note 2 {{candidate}}
+void* operator new(size_t, int*); // expected-note 3 {{candidate}}
+void* operator new(size_t, float*); // expected-note 3 {{candidate}}
+void* operator new(size_t, S); // expected-note 2 {{candidate}}
+
+void good_news()
+{
+ int *pi = new int;
+ float *pf = new (pi) float();
+ pi = new int(1);
+ pi = new int('c');
+ const int *pci = new const int();
+ S *ps = new S(1, 2, 3.4);
+ ps = new (pf) (S)(1, 2, 3.4);
+ S *(*paps)[2] = new S*[*pi][2];
+ ps = new (S[3])(1, 2, 3.4);
+ typedef int ia4[4];
+ ia4 *pai = new (int[3][4]);
+ pi = ::new int;
+ U *pu = new (ps) U;
+ // FIXME: Inherited functions are not looked up currently.
+ //V *pv = new (ps) V;
+
+ pi = new (S(1.0f, 2)) int;
+}
+
+struct abstract {
+ virtual ~abstract() = 0;
+};
+
+void bad_news(int *ip)
+{
+ int i = 1;
+ (void)new; // expected-error {{missing type specifier}}
+ (void)new 4; // expected-error {{missing type specifier}}
+ (void)new () int; // expected-error {{expected expression}}
+ (void)new int[1.1]; // expected-error {{array size expression must have integral or enumerated type, not 'double'}}
+ (void)new int[1][i]; // expected-error {{only the first dimension}}
+ (void)new (int[1][i]); // expected-error {{only the first dimension}}
+ (void)new int(*(S*)0); // expected-error {{incompatible type initializing}}
+ (void)new int(1, 2); // expected-error {{initializer of a builtin type can only take one argument}}
+ (void)new S(1); // expected-error {{no matching constructor}}
+ (void)new S(1, 1); // expected-error {{call to constructor of 'S' is ambiguous}}
+ (void)new const int; // expected-error {{must provide an initializer}}
+ (void)new float*(ip); // expected-error {{incompatible type initializing 'int *', expected 'float *'}}
+ // Undefined, but clang should reject it directly.
+ (void)new int[-1]; // expected-error {{array size is negative}}
+ (void)new int[*(S*)0]; // expected-error {{array size expression must have integral or enumerated type, not 'struct S'}}
+ (void)::S::new int; // expected-error {{expected unqualified-id}}
+ (void)new (0, 0) int; // expected-error {{no matching function for call to 'operator new'}}
+ (void)new (0L) int; // expected-error {{call to 'operator new' is ambiguous}}
+ // This must fail, because the member version shouldn't be found.
+ (void)::new ((S*)0) U; // expected-error {{no matching function for call to 'operator new'}}
+ // This must fail, because any member version hides all global versions.
+ (void)new U; // expected-error {{no matching function for call to 'operator new'}}
+ (void)new (int[]); // expected-error {{array size must be specified in new expressions}}
+ (void)new int&; // expected-error {{cannot allocate reference type 'int &' with new}}
+ // Some lacking cases due to lack of sema support.
+}
+
+void good_deletes()
+{
+ delete (int*)0;
+ delete [](int*)0;
+ delete (S*)0;
+ ::delete (int*)0;
+}
+
+void bad_deletes()
+{
+ delete 0; // expected-error {{cannot delete expression of type 'int'}}
+ delete [0] (int*)0; // expected-error {{expected ']'}} \
+ // expected-note {{to match this '['}}
+ delete (void*)0; // expected-error {{cannot delete expression}}
+ delete (T*)0; // expected-warning {{deleting pointer to incomplete type}}
+ ::S::delete (int*)0; // expected-error {{expected unqualified-id}}
+}
diff --git a/test/SemaCXX/no-implicit-builtin-decls.cpp b/test/SemaCXX/no-implicit-builtin-decls.cpp
new file mode 100644
index 000000000000..bd11f92f7e62
--- /dev/null
+++ b/test/SemaCXX/no-implicit-builtin-decls.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f() {
+ void *p = malloc(sizeof(int) * 10); // expected-error{{no matching function for call to 'malloc'}}
+}
+
+int malloc(double);
diff --git a/test/SemaCXX/nullptr.cpp b/test/SemaCXX/nullptr.cpp
new file mode 100644
index 000000000000..6cc5a8168313
--- /dev/null
+++ b/test/SemaCXX/nullptr.cpp
@@ -0,0 +1,67 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+#include <stdint.h>
+
+// Don't have decltype yet.
+typedef __typeof__(nullptr) nullptr_t;
+
+struct A {};
+
+int o1(char*);
+void o1(uintptr_t);
+void o2(char*); // expected-note {{candidate}}
+void o2(int A::*); // expected-note {{candidate}}
+
+nullptr_t f(nullptr_t null)
+{
+ // Implicit conversions.
+ null = nullptr;
+ void *p = nullptr;
+ p = null;
+ int *pi = nullptr;
+ pi = null;
+ null = 0;
+ int A::*pm = nullptr;
+ pm = null;
+ void (*pf)() = nullptr;
+ pf = null;
+ void (A::*pmf)() = nullptr;
+ pmf = null;
+ bool b = nullptr;
+
+ // Can't convert nullptr to integral implicitly.
+ uintptr_t i = nullptr; // expected-error {{incompatible type initializing}}
+
+ // Operators
+ (void)(null == nullptr);
+ (void)(null <= nullptr);
+ (void)(null == (void*)0);
+ (void)((void*)0 == nullptr);
+ (void)(null <= (void*)0);
+ (void)((void*)0 <= nullptr);
+ (void)(1 > nullptr); // expected-error {{invalid operands to binary expression}}
+ (void)(1 != nullptr); // expected-error {{invalid operands to binary expression}}
+ (void)(1 + nullptr); // expected-error {{invalid operands to binary expression}}
+ (void)(0 ? nullptr : 0); // expected-error {{incompatible operand types}}
+ (void)(0 ? nullptr : (void*)0);
+
+ // Overloading
+ int t = o1(nullptr);
+ t = o1(null);
+ o2(nullptr); // expected-error {{ambiguous}}
+
+ // nullptr is an rvalue, null is an lvalue
+ (void)&nullptr; // expected-error {{address expression must be an lvalue}}
+ nullptr_t *pn = &null;
+
+ // You can reinterpret_cast nullptr to an integer.
+ (void)reinterpret_cast<uintptr_t>(nullptr);
+
+ // You can throw nullptr.
+ throw nullptr;
+}
+
+// Template arguments can be nullptr.
+template <int *PI, void (*PF)(), int A::*PM, void (A::*PMF)()>
+struct T {};
+
+typedef T<nullptr, nullptr, nullptr, nullptr> NT;
diff --git a/test/SemaCXX/offsetof.cpp b/test/SemaCXX/offsetof.cpp
new file mode 100644
index 000000000000..f0290e889a29
--- /dev/null
+++ b/test/SemaCXX/offsetof.cpp
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify %s -Winvalid-offsetof
+
+struct NonPOD {
+ virtual void f();
+ int m;
+};
+
+struct P {
+ NonPOD fieldThatPointsToANonPODType;
+};
+
+void f() {
+ int i = __builtin_offsetof(P, fieldThatPointsToANonPODType.m); // expected-warning{{offset of on non-POD type 'struct P'}}
+}
+
diff --git a/test/SemaCXX/overload-call-copycon.cpp b/test/SemaCXX/overload-call-copycon.cpp
new file mode 100644
index 000000000000..755e27adbac8
--- /dev/null
+++ b/test/SemaCXX/overload-call-copycon.cpp
@@ -0,0 +1,48 @@
+// RUN: clang-cc -fsyntax-only %s
+class X { };
+
+int& copycon(X x);
+float& copycon(...);
+
+void test_copycon(X x, X const xc, X volatile xv) {
+ int& i1 = copycon(x);
+ int& i2 = copycon(xc);
+ float& f1 = copycon(xv);
+}
+
+class A {
+public:
+ A(A&);
+};
+
+class B : public A { };
+
+short& copycon2(A a);
+int& copycon2(B b);
+float& copycon2(...);
+
+void test_copycon2(A a, const A ac, B b, B const bc, B volatile bv) {
+ int& i1 = copycon2(b);
+ float& f1 = copycon2(bc);
+ float& f2 = copycon2(bv);
+ short& s1 = copycon2(a);
+ float& f3 = copycon2(ac);
+}
+
+int& copycon3(A a);
+float& copycon3(...);
+
+void test_copycon3(B b, const B bc) {
+ int& i1 = copycon3(b);
+ float& f1 = copycon3(bc);
+}
+
+
+class C : public B { };
+
+float& copycon4(A a);
+int& copycon4(B b);
+
+void test_copycon4(C c) {
+ int& i = copycon4(c);
+};
diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp
new file mode 100644
index 000000000000..94f352efc76c
--- /dev/null
+++ b/test/SemaCXX/overload-call.cpp
@@ -0,0 +1,280 @@
+// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+int* f(int) { return 0; }
+float* f(float) { return 0; }
+void f();
+
+void test_f(int iv, float fv) {
+ float* fp = f(fv);
+ int* ip = f(iv);
+}
+
+int* g(int, float, int); // expected-note {{ candidate function }}
+float* g(int, int, int); // expected-note {{ candidate function }}
+double* g(int, float, float); // expected-note {{ candidate function }}
+char* g(int, float, ...); // expected-note {{ candidate function }}
+void g();
+
+void test_g(int iv, float fv) {
+ int* ip1 = g(iv, fv, 0);
+ float* fp1 = g(iv, iv, 0);
+ double* dp1 = g(iv, fv, fv);
+ char* cp1 = g(0, 0);
+ char* cp2 = g(0, 0, 0, iv, fv);
+
+ double* dp2 = g(0, fv, 1.5); // expected-error {{ call to 'g' is ambiguous; candidates are: }}
+}
+
+double* h(double f);
+int* h(int);
+
+void test_h(float fv, unsigned char cv) {
+ double* dp = h(fv);
+ int* ip = h(cv);
+}
+
+int* i(int);
+double* i(long);
+
+void test_i(short sv, int iv, long lv, unsigned char ucv) {
+ int* ip1 = i(sv);
+ int* ip2 = i(iv);
+ int* ip3 = i(ucv);
+ double* dp1 = i(lv);
+}
+
+int* j(void*);
+double* j(bool);
+
+void test_j(int* ip) {
+ int* ip1 = j(ip);
+}
+
+int* k(char*);
+double* k(bool);
+
+void test_k() {
+ int* ip1 = k("foo");
+ double* dp1 = k(L"foo");
+}
+
+int* l(wchar_t*);
+double* l(bool);
+
+void test_l() {
+ int* ip1 = l(L"foo");
+ double* dp1 = l("foo");
+}
+
+int* m(const char*);
+double* m(char*);
+
+void test_m() {
+ int* ip = m("foo");
+}
+
+int* n(char*);
+double* n(void*);
+class E;
+
+void test_n(E* e) {
+ char ca[7];
+ int* ip1 = n(ca);
+ int* ip2 = n("foo");
+
+ float fa[7];
+ double* dp1 = n(fa);
+
+ double* dp2 = n(e);
+}
+
+enum PromotesToInt {
+ PromotesToIntValue = -1
+};
+
+enum PromotesToUnsignedInt {
+ PromotesToUnsignedIntValue = 1u
+};
+
+int* o(int);
+double* o(unsigned int);
+float* o(long);
+
+void test_o() {
+ int* ip1 = o(PromotesToIntValue);
+ double* dp1 = o(PromotesToUnsignedIntValue);
+}
+
+int* p(int);
+double* p(double);
+
+void test_p() {
+ int* ip = p((short)1);
+ double* dp = p(1.0f);
+}
+
+struct Bits {
+ signed short int_bitfield : 5;
+ unsigned int uint_bitfield : 8;
+};
+
+int* bitfields(int, int);
+float* bitfields(unsigned int, int);
+
+void test_bitfield(Bits bits, int x) {
+ int* ip = bitfields(bits.int_bitfield, 0);
+ float* fp = bitfields(bits.uint_bitfield, 0u);
+}
+
+int* multiparm(long, int, long); // expected-note {{ candidate function }}
+float* multiparm(int, int, int); // expected-note {{ candidate function }}
+double* multiparm(int, int, short); // expected-note {{ candidate function }}
+
+void test_multiparm(long lv, short sv, int iv) {
+ int* ip1 = multiparm(lv, iv, lv);
+ int* ip2 = multiparm(lv, sv, lv);
+ float* fp1 = multiparm(iv, iv, iv);
+ float* fp2 = multiparm(sv, iv, iv);
+ double* dp1 = multiparm(sv, sv, sv);
+ double* dp2 = multiparm(iv, sv, sv);
+ multiparm(sv, sv, lv); // expected-error {{ call to 'multiparm' is ambiguous; candidates are: }}
+}
+
+// Test overloading based on qualification vs. no qualification
+// conversion.
+int* quals1(int const * p);
+char* quals1(int * p);
+
+int* quals2(int const * const * pp);
+char* quals2(int * * pp);
+
+int* quals3(int const * * const * ppp);
+char* quals3(int *** ppp);
+
+void test_quals(int * p, int * * pp, int * * * ppp) {
+ char* q1 = quals1(p);
+ char* q2 = quals2(pp);
+ char* q3 = quals3(ppp);
+}
+
+// Test overloading based on qualification ranking (C++ 13.3.2)p3.
+int* quals_rank1(int const * p);
+float* quals_rank1(int const volatile *p);
+char* quals_rank1(char*);
+double* quals_rank1(const char*);
+
+int* quals_rank2(int const * const * pp);
+float* quals_rank2(int * const * pp);
+
+void quals_rank3(int const * const * const volatile * p); // expected-note{{candidate function}}
+void quals_rank3(int const * const volatile * const * p); // expected-note{{candidate function}}
+
+void quals_rank3(int const *); // expected-note{{candidate function}}
+void quals_rank3(int volatile *); // expected-note{{candidate function}}
+
+void test_quals_ranking(int * p, int volatile *pq, int * * pp, int * * * ppp) {
+ int* q1 = quals_rank1(p);
+ float* q2 = quals_rank1(pq);
+ double* q3 = quals_rank1("string literal");
+ char a[17];
+ const char* ap = a;
+ char* q4 = quals_rank1(a);
+ double* q5 = quals_rank1(ap);
+
+ float* q6 = quals_rank2(pp);
+
+ quals_rank3(ppp); // expected-error {{call to 'quals_rank3' is ambiguous; candidates are:}}
+
+ quals_rank3(p); // expected-error {{call to 'quals_rank3' is ambiguous; candidates are:}}
+ quals_rank3(pq);
+}
+
+// Test overloading based on derived-to-base conversions
+class A { };
+class B : public A { };
+class C : public B { };
+class D : public C { };
+
+int* derived1(A*);
+char* derived1(const A*);
+float* derived1(void*);
+
+int* derived2(A*);
+float* derived2(B*);
+
+int* derived3(A*);
+float* derived3(const B*);
+char* derived3(C*);
+
+void test_derived(B* b, B const* bc, C* c, const C* cc, void* v, D* d) {
+ int* d1 = derived1(b);
+ char* d2 = derived1(bc);
+ int* d3 = derived1(c);
+ char* d4 = derived1(cc);
+ float* d5 = derived1(v);
+
+ float* d6 = derived2(b);
+ float* d7 = derived2(c);
+
+ char* d8 = derived3(d);
+}
+
+// Test overloading of references.
+// (FIXME: tests binding to determine candidate sets, not overload
+// resolution per se).
+int* intref(int&);
+float* intref(const int&);
+
+void intref_test() {
+ float* ir1 = intref(5);
+ float* ir2 = intref(5.5);
+}
+
+// Test reference binding vs. standard conversions.
+int& bind_vs_conv(const double&);
+float& bind_vs_conv(int);
+
+void bind_vs_conv_test()
+{
+ int& i1 = bind_vs_conv(1.0f);
+ float& f1 = bind_vs_conv((short)1);
+}
+
+// Test that cv-qualifiers get subsumed in the reference binding.
+struct X { };
+struct Y { };
+struct Z : X, Y { };
+
+int& cvqual_subsume(X&); // expected-note{{candidate function}}
+float& cvqual_subsume(const Y&); // expected-note{{candidate function}}
+
+int& cvqual_subsume2(const X&);
+float& cvqual_subsume2(const volatile Y&);
+
+Z get_Z();
+
+void cvqual_subsume_test(Z z) {
+ cvqual_subsume(z); // expected-error{{call to 'cvqual_subsume' is ambiguous; candidates are:}}
+ int& x = cvqual_subsume2(get_Z()); // okay: only binds to the first one
+}
+
+// Test overloading with cv-qualification differences in reference
+// binding.
+int& cvqual_diff(X&);
+float& cvqual_diff(const X&);
+
+void cvqual_diff_test(X x, Z z) {
+ int& i1 = cvqual_diff(x);
+ int& i2 = cvqual_diff(z);
+}
+
+// Test overloading with derived-to-base differences in reference
+// binding.
+struct Z2 : Z { };
+
+int& db_rebind(X&);
+long& db_rebind(Y&);
+float& db_rebind(Z&);
+
+void db_rebind_test(Z2 z2) {
+ float& f1 = db_rebind(z2);
+}
diff --git a/test/SemaCXX/overload-decl.cpp b/test/SemaCXX/overload-decl.cpp
new file mode 100644
index 000000000000..2bc832f558f7
--- /dev/null
+++ b/test/SemaCXX/overload-decl.cpp
@@ -0,0 +1,31 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+void f();
+void f(int);
+void f(int, float);
+void f(int, int);
+void f(int, ...);
+
+typedef float Float;
+void f(int, Float); // expected-note {{previous declaration is here}}
+
+int f(int, Float); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+
+void g(void); // expected-note {{previous declaration is here}}
+int g(); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+
+typedef int INT;
+
+class X {
+ void f();
+ void f(int); // expected-note {{previous declaration is here}}
+ void f() const;
+
+ void f(INT); // expected-error{{cannot be redeclared}}
+
+ void g(int); // expected-note {{previous declaration is here}}
+ void g(int, float); // expected-note {{previous declaration is here}}
+ int g(int, Float); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+
+ static void g(float);
+ static void g(int); // expected-error {{static and non-static member functions with the same parameter types cannot be overloaded}}
+};
diff --git a/test/SemaCXX/overload-member-call.cpp b/test/SemaCXX/overload-member-call.cpp
new file mode 100644
index 000000000000..96e570da654b
--- /dev/null
+++ b/test/SemaCXX/overload-member-call.cpp
@@ -0,0 +1,56 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct X {
+ int& f(int) const; // expected-note 2 {{candidate function}}
+ float& f(int); // expected-note 2 {{candidate function}}
+
+ void test_f(int x) const {
+ int& i = f(x);
+ }
+
+ void test_f2(int x) {
+ float& f2 = f(x);
+ }
+
+ int& g(int) const; // expected-note 2 {{candidate function}}
+ float& g(int); // expected-note 2 {{candidate function}}
+ static double& g(double); // expected-note 2 {{candidate function}}
+
+ void h(int);
+
+ void test_member() {
+ float& f1 = f(0);
+ float& f2 = g(0);
+ double& d1 = g(0.0);
+ }
+
+ void test_member_const() const {
+ int &i1 = f(0);
+ int &i2 = g(0);
+ double& d1 = g(0.0);
+ }
+
+ static void test_member_static() {
+ double& d1 = g(0.0);
+ g(0); // expected-error{{call to 'g' is ambiguous; candidates are:}}
+ }
+};
+
+void test(X x, const X xc, X* xp, const X* xcp, volatile X xv, volatile X* xvp) {
+ int& i1 = xc.f(0);
+ int& i2 = xcp->f(0);
+ float& f1 = x.f(0);
+ float& f2 = xp->f(0);
+ xv.f(0); // expected-error{{no matching member function for call to 'f'; candidates are:}}
+ xvp->f(0); // expected-error{{no matching member function for call to 'f'; candidates are:}}
+
+ int& i3 = xc.g(0);
+ int& i4 = xcp->g(0);
+ float& f3 = x.g(0);
+ float& f4 = xp->g(0);
+ double& d1 = xp->g(0.0);
+ double& d2 = X::g(0.0);
+ X::g(0); // expected-error{{call to 'g' is ambiguous; candidates are:}}
+
+ X::h(0); // expected-error{{call to non-static member function without an object argument}}
+}
diff --git a/test/SemaCXX/overloaded-builtin-operators.cpp b/test/SemaCXX/overloaded-builtin-operators.cpp
new file mode 100644
index 000000000000..2a6c24a6778a
--- /dev/null
+++ b/test/SemaCXX/overloaded-builtin-operators.cpp
@@ -0,0 +1,122 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct yes;
+struct no;
+
+struct Short {
+ operator short();
+};
+
+struct Long {
+ operator long();
+};
+
+enum E1 { };
+struct Enum1 {
+ operator E1();
+};
+
+enum E2 { };
+struct Enum2 {
+ operator E2();
+};
+
+yes& islong(long);
+yes& islong(unsigned long); // FIXME: shouldn't be needed
+no& islong(int);
+
+void f(Short s, Long l, Enum1 e1, Enum2 e2) {
+ // C++ [over.built]p8
+ int i1 = +e1;
+ int i2 = -e2;
+
+ // C++ [over.built]p10:
+ int i3 = ~s;
+ bool b1 = !s;
+
+ // C++ [over.built]p12
+ (void)static_cast<yes&>(islong(s + l));
+ (void)static_cast<no&>(islong(s + s));
+
+ // C++ [over.built]p17
+ (void)static_cast<yes&>(islong(s % l));
+ (void)static_cast<yes&>(islong(l << s));
+ (void)static_cast<no&>(islong(s << l));
+ (void)static_cast<yes&>(islong(e1 % l));
+ // FIXME: should pass (void)static_cast<no&>(islong(e1 % e2));
+}
+
+struct ShortRef {
+ operator short&();
+};
+
+struct LongRef {
+ operator volatile long&();
+};
+
+void g(ShortRef sr, LongRef lr) {
+ // C++ [over.built]p3
+ short s1 = sr++;
+
+ // C++ [over.built]p3
+ long l1 = lr--;
+
+ // C++ [over.built]p18
+ short& sr1 = (sr *= lr);
+ volatile long& lr1 = (lr *= sr);
+
+ // C++ [over.built]p22
+ short& sr2 = (sr %= lr);
+ volatile long& lr2 = (lr <<= sr);
+
+ bool b1 = (sr && lr) || (sr || lr);
+}
+
+struct VolatileIntPtr {
+ operator int volatile *();
+};
+
+struct ConstIntPtr {
+ operator int const *();
+};
+
+struct VolatileIntPtrRef {
+ operator int volatile *&();
+};
+
+struct ConstIntPtrRef {
+ operator int const *&();
+};
+
+void test_with_ptrs(VolatileIntPtr vip, ConstIntPtr cip, ShortRef sr,
+ VolatileIntPtrRef vipr, ConstIntPtrRef cipr) {
+ const int& cir1 = cip[sr];
+ const int& cir2 = sr[cip];
+ volatile int& vir1 = vip[sr];
+ volatile int& vir2 = sr[vip];
+ bool b1 = (vip == cip);
+ long p1 = vip - cip;
+
+ // C++ [over.built]p5:
+ int volatile *vip1 = vipr++;
+ int const *cip1 = cipr++;
+ int volatile *&vipr1 = ++vipr;
+ int const *&cipr1 = --cipr;
+
+ // C++ [over.built]p6:
+ int volatile &ivr = *vip;
+
+ // C++ [over.built]p8:
+ int volatile *vip2 = +vip;
+ int i1 = +sr;
+ int i2 = -sr;
+
+ // C++ [over.built]p13:
+ int volatile &ivr2 = vip[17];
+ int const &icr2 = 17[cip];
+}
+
+// C++ [over.match.open]p4
+
+void test_assign_restrictions(ShortRef& sr) {
+ sr = (short)0; // expected-error{{no viable overloaded '='}}
+}
diff --git a/test/SemaCXX/overloaded-operator-decl.cpp b/test/SemaCXX/overloaded-operator-decl.cpp
new file mode 100644
index 000000000000..fc17faf6634f
--- /dev/null
+++ b/test/SemaCXX/overloaded-operator-decl.cpp
@@ -0,0 +1,39 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct X {
+ X();
+ X(int);
+};
+
+X operator+(X, X);
+X operator-(X, X) { X x; return x; }
+
+struct Y {
+ Y operator-() const;
+ void operator()(int x = 17) const;
+ int operator[](int);
+
+ static int operator+(Y, Y); // expected-error{{overloaded 'operator+' cannot be a static member function}}
+};
+
+
+void f(X x) {
+ x = operator+(x, x);
+}
+
+X operator+(int, float); // expected-error{{overloaded 'operator+' must have at least one parameter of class or enumeration type}}
+
+X operator*(X, X = 5); // expected-error{{parameter of overloaded 'operator*' cannot have a default argument}}
+
+X operator/(X, X, ...); // expected-error{{overloaded 'operator/' cannot be variadic}}
+
+X operator%(Y); // expected-error{{overloaded 'operator%' must be a binary operator (has 1 parameter)}}
+
+void operator()(Y&, int, int); // expected-error{{overloaded 'operator()' must be a non-static member function}}
+
+typedef int INT;
+typedef float FLOAT;
+Y& operator++(Y&);
+Y operator++(Y&, INT);
+X operator++(X&, FLOAT); // expected-error{{parameter of overloaded post-increment operator must have type 'int' (not 'FLOAT' (aka 'float'))}}
+
+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
new file mode 100644
index 000000000000..916d753a3ff5
--- /dev/null
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -0,0 +1,211 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class X { };
+
+X operator+(X, X);
+
+void f(X x) {
+ x = x + x;
+}
+
+struct Y;
+struct Z;
+
+struct Y {
+ Y(const Z&);
+};
+
+struct Z {
+ Z(const Y&);
+};
+
+Y operator+(Y, Y);
+bool operator-(Y, Y); // expected-note{{candidate function}}
+bool operator-(Z, Z); // expected-note{{candidate function}}
+
+void g(Y y, Z z) {
+ y = y + z;
+ bool b = y - z; // expected-error{{use of overloaded operator '-' is ambiguous; candidates are:}}
+}
+
+struct A {
+ bool operator==(Z&); // expected-note{{candidate function}}
+};
+
+A make_A();
+
+bool operator==(A&, Z&); // expected-note{{candidate function}}
+
+void h(A a, const A ac, Z z) {
+ make_A() == z;
+ a == z; // expected-error{{use of overloaded operator '==' is ambiguous; candidates are:}}
+ ac == z; // expected-error{{invalid operands to binary expression ('struct A const' and 'struct Z')}}
+}
+
+struct B {
+ bool operator==(const B&) const;
+
+ void test(Z z) {
+ make_A() == z;
+ }
+};
+
+enum Enum1 { };
+enum Enum2 { };
+
+struct E1 {
+ E1(Enum1) { }
+};
+
+struct E2 {
+ E2(Enum2);
+};
+
+// C++ [over.match.oper]p3 - enum restriction.
+float& operator==(E1, E2);
+
+void enum_test(Enum1 enum1, Enum2 enum2, E1 e1, E2 e2) {
+ float &f1 = (e1 == e2);
+ float &f2 = (enum1 == e2);
+ float &f3 = (e1 == enum2);
+ float &f4 = (enum1 == enum2); // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a temporary of type 'bool'}}
+}
+
+
+struct PostInc {
+ PostInc operator++(int);
+ PostInc& operator++();
+};
+
+struct PostDec {
+ PostDec operator--(int);
+ PostDec& operator--();
+};
+
+void incdec_test(PostInc pi, PostDec pd) {
+ const PostInc& pi1 = pi++;
+ const PostDec& pd1 = pd--;
+ PostInc &pi2 = ++pi;
+ PostDec &pd2 = --pd;
+}
+
+struct SmartPtr {
+ int& operator*();
+ long& operator*() const volatile;
+};
+
+void test_smartptr(SmartPtr ptr, const SmartPtr cptr,
+ const volatile SmartPtr cvptr) {
+ int &ir = *ptr;
+ long &lr = *cptr;
+ long &lr2 = *cvptr;
+}
+
+
+struct ArrayLike {
+ int& operator[](int);
+};
+
+void test_arraylike(ArrayLike a) {
+ int& ir = a[17];
+}
+
+struct SmartRef {
+ int* operator&();
+};
+
+void test_smartref(SmartRef r) {
+ int* ip = &r;
+}
+
+bool& operator,(X, Y);
+
+void test_comma(X x, Y y) {
+ bool& b1 = (x, y);
+ X& xr = (x, x);
+}
+
+struct Callable {
+ int& operator()(int, double = 2.71828); // expected-note{{candidate function}}
+ float& operator()(int, double, long, ...); // expected-note{{candidate function}}
+
+ double& operator()(float); // expected-note{{candidate function}}
+};
+
+struct Callable2 {
+ int& operator()(int i = 0);
+ double& operator()(...) const;
+};
+
+void test_callable(Callable c, Callable2 c2, const Callable2& c2c) {
+ int &ir = c(1);
+ float &fr = c(1, 3.14159, 17, 42);
+
+ c(); // expected-error{{no matching function for call to object of type 'struct Callable'; candidates are:}}
+
+ double &dr = c(1.0f);
+
+ int &ir2 = c2();
+ int &ir3 = c2(1);
+ double &fr2 = c2c();
+}
+
+typedef float FLOAT;
+typedef int& INTREF;
+typedef INTREF Func1(FLOAT, double);
+typedef float& Func2(int, double);
+
+struct ConvertToFunc {
+ operator Func1*(); // expected-note{{conversion candidate of type 'INTREF (*)(FLOAT, double)'}}
+ operator Func2&(); // expected-note{{conversion candidate of type 'float &(&)(int, double)'}}
+ void operator()();
+};
+
+void test_funcptr_call(ConvertToFunc ctf) {
+ int &i1 = ctf(1.0f, 2.0);
+ float &f2 = ctf((short int)1, 1.0f);
+ ctf((long int)17, 2.0); // expected-error{{error: call to object of type 'struct ConvertToFunc' is ambiguous; candidates are:}}
+ ctf();
+}
+
+struct HasMember {
+ int m;
+};
+
+struct Arrow1 {
+ HasMember* operator->();
+};
+
+struct Arrow2 {
+ Arrow1 operator->(); // expected-note{{candidate function}}
+};
+
+void test_arrow(Arrow1 a1, Arrow2 a2, const Arrow2 a3) {
+ int &i1 = a1->m;
+ int &i2 = a2->m;
+ a3->m; // expected-error{{no viable overloaded 'operator->'; candidate is}}
+}
+
+struct CopyConBase {
+};
+
+struct CopyCon : public CopyConBase {
+ CopyCon(const CopyConBase &Base);
+
+ CopyCon(const CopyConBase *Base) {
+ *this = *Base;
+ }
+};
+
+namespace N {
+ struct X { };
+}
+
+namespace M {
+ N::X operator+(N::X, N::X);
+}
+
+namespace M {
+ void test_X(N::X x) {
+ (void)(x + x);
+ }
+}
diff --git a/test/SemaCXX/qualification-conversion.cpp b/test/SemaCXX/qualification-conversion.cpp
new file mode 100644
index 000000000000..01e503ddac6c
--- /dev/null
+++ b/test/SemaCXX/qualification-conversion.cpp
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+int* quals1(int const * p);
+int* quals2(int const * const * pp);
+int* quals3(int const * * const * ppp); // expected-note{{candidate function}}
+
+void test_quals(int * p, int * * pp, int * * * ppp) {
+ int const * const * pp2 = pp;
+ quals1(p);
+ quals2(pp);
+ quals3(ppp); // expected-error {{no matching}}
+}
+
+struct A {};
+void mquals1(int const A::*p);
+void mquals2(int const A::* const A::*pp);
+void mquals3(int const A::* A::* const A::*ppp); // expected-note{{candidate function}}
+
+void test_mquals(int A::*p, int A::* A::*pp, int A::* A::* A::*ppp) {
+ int const A::* const A::* pp2 = pp;
+ mquals1(p);
+ mquals2(pp);
+ mquals3(ppp); // expected-error {{no matching}}
+}
diff --git a/test/SemaCXX/qualified-id-lookup.cpp b/test/SemaCXX/qualified-id-lookup.cpp
new file mode 100644
index 000000000000..254a18de1f32
--- /dev/null
+++ b/test/SemaCXX/qualified-id-lookup.cpp
@@ -0,0 +1,111 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+namespace Ns {
+ int f(); // expected-note{{previous declaration is here}}
+
+ enum E {
+ Enumerator
+ };
+}
+namespace Ns {
+ double f(); // expected-error{{functions that differ only in their return type cannot be overloaded}}
+
+ int x = Enumerator;
+}
+
+namespace Ns2 {
+ float f();
+}
+
+int y = Ns::Enumerator;
+
+namespace Ns2 {
+ float f(int); // expected-note{{previous declaration is here}}
+}
+
+namespace Ns2 {
+ double f(int); // expected-error{{functions that differ only in their return type cannot be overloaded}}
+}
+
+namespace N {
+ int& f1();
+}
+
+namespace N {
+ struct f1 {
+ static int member;
+
+ typedef int type;
+
+ void foo(type);
+ };
+
+ void test_f1() {
+ int &i1 = f1();
+ }
+}
+
+void N::f1::foo(int i) {
+ f1::member = i;
+ f1::type &ir = i;
+}
+
+namespace N {
+ float& f1(int x) {
+ N::f1::type& i1 = x;
+ f1::type& i2 = x;
+ }
+
+ struct f2 {
+ static int member;
+ };
+ void f2();
+}
+
+int i1 = N::f1::member;
+typedef struct N::f1 type1;
+int i2 = N::f2::member;
+typedef struct N::f2 type2;
+
+void test_f1(int i) {
+ int &v1 = N::f1();
+ float &v2 = N::f1(i);
+ int v3 = ::i1;
+ int v4 = N::f1::member;
+}
+
+typedef int f2_type;
+namespace a {
+ typedef int f2_type(int, int);
+
+ void test_f2() {
+ ::f2_type(1, 2); // expected-error {{function-style cast to a builtin type can only take one argument}}
+ }
+}
+
+// PR clang/3291
+namespace a {
+ namespace a { // A1
+ namespace a { // A2
+ int i;
+ }
+ }
+}
+
+void test_a() {
+ a::a::i = 3; // expected-error{{no member named 'i'}}
+ a::a::a::i = 4;
+}
+
+struct Undef { // expected-note{{definition of 'struct Undef' is not complete until the closing '}'}}
+ typedef int type;
+
+ Undef::type member;
+
+ static int size = sizeof(Undef); // expected-error{{invalid application of 'sizeof' to an incomplete type 'struct Undef'}}
+
+ int f();
+};
+
+int Undef::f() {
+ return sizeof(Undef);
+}
diff --git a/test/SemaCXX/qualified-names-diag.cpp b/test/SemaCXX/qualified-names-diag.cpp
new file mode 100644
index 000000000000..3bffd7c05d3b
--- /dev/null
+++ b/test/SemaCXX/qualified-names-diag.cpp
@@ -0,0 +1,33 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+namespace foo {
+ namespace wibble {
+ struct x { int y; };
+
+ namespace bar {
+ namespace wonka {
+ struct x {
+ struct y { };
+ };
+ }
+ }
+ }
+}
+
+namespace bar {
+ typedef int y;
+
+ struct incomplete; // expected-note{{forward declaration of 'struct bar::incomplete'}}
+}
+void test() {
+ foo::wibble::x a;
+ ::bar::y b;
+ a + b; // expected-error{{invalid operands to binary expression ('foo::wibble::x' and '::bar::y' (aka 'int'))}}
+
+ ::foo::wibble::bar::wonka::x::y c;
+ c + b; // expected-error{{invalid operands to binary expression ('::foo::wibble::bar::wonka::x::y' and '::bar::y' (aka 'int'))}}
+
+ (void)sizeof(bar::incomplete); // expected-error{{invalid application of 'sizeof' to an incomplete type 'bar::incomplete'}}
+}
+
+int ::foo::wibble::bar::wonka::x::y::* ptrmem;
+
diff --git a/test/SemaCXX/qualified-names-print.cpp b/test/SemaCXX/qualified-names-print.cpp
new file mode 100644
index 000000000000..1cb19f0312e4
--- /dev/null
+++ b/test/SemaCXX/qualified-names-print.cpp
@@ -0,0 +1,15 @@
+// RUN: clang-cc -ast-print %s 2>&1 | grep "N::M::X<INT>::value"
+namespace N {
+ namespace M {
+ template<typename T>
+ struct X {
+ enum { value };
+ };
+ }
+}
+
+typedef int INT;
+
+int test() {
+ return N::M::X<INT>::value;
+}
diff --git a/test/SemaCXX/references.cpp b/test/SemaCXX/references.cpp
new file mode 100644
index 000000000000..9067a8661d7c
--- /dev/null
+++ b/test/SemaCXX/references.cpp
@@ -0,0 +1,89 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+int g(int);
+
+void f() {
+ int i;
+ int &r = i;
+ r = 1;
+ int *p = &r;
+ int &rr = r;
+ int (&rg)(int) = g;
+ rg(i);
+ int a[3];
+ int (&ra)[3] = a;
+ ra[1] = i;
+ int *Q;
+ int *& P = Q;
+ P[1] = 1;
+}
+
+typedef int t[1];
+void test2() {
+ t a;
+ t& b = a;
+
+
+ int c[3];
+ int (&rc)[3] = c;
+}
+
+// C++ [dcl.init.ref]p5b1
+struct A { };
+struct B : A { } b;
+
+void test3() {
+ double d = 2.0;
+ double& rd = d; // rd refers to d
+ const double& rcd = d; // rcd refers to d
+
+ A& ra = b; // ra refers to A subobject in b
+ const A& rca = b; // rca refers to A subobject in b
+}
+
+B fB();
+
+// C++ [dcl.init.ref]p5b2
+void test4() {
+ double& rd2 = 2.0; // expected-error{{non-const lvalue reference to type 'double' cannot be initialized with a temporary of type 'double'}}
+ int i = 2;
+ double& rd3 = i; // expected-error{{non-const lvalue reference to type 'double' cannot be initialized with a value of type 'int'}}
+
+ const A& rca = fB();
+}
+
+void test5() {
+ const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0
+ const volatile int cvi = 1;
+ const int& r = cvi; // expected-error{{initialization of reference to type 'int const' with a value of type 'int const volatile' drops qualifiers}}
+}
+
+// C++ [dcl.init.ref]p3
+int& test6(int& x) {
+ int& yo; // expected-error{{declaration of reference variable 'yo' requires an initializer}}
+
+ return x;
+}
+int& not_initialized_error; // expected-error{{declaration of reference variable 'not_initialized_error' requires an initializer}}
+extern int& not_initialized_okay;
+
+class Test6 {
+ int& okay;
+};
+
+struct C : B, A { };
+
+void test7(C& c) {
+ A& a1 = c; // expected-error {{ambiguous conversion from derived class 'struct C' to base class 'struct A':}}
+}
+
+// C++ [dcl.ref]p1, C++ [dcl.ref]p4
+void test8(int& const,// expected-error{{'const' qualifier may not be applied to a reference}}
+
+ void&, // expected-error{{cannot form a reference to 'void'}}
+ int& &) // expected-error{{type name declared as a reference to a reference}}
+{
+ typedef int& intref;
+ typedef intref& intrefref; // C++ DR 106: reference collapsing
+
+ typedef intref const intref_c; // okay. FIXME: how do we verify that this is the same type as intref?
+}
diff --git a/test/SemaCXX/reinterpret-cast.cpp b/test/SemaCXX/reinterpret-cast.cpp
new file mode 100644
index 000000000000..fd5ca8cf39d4
--- /dev/null
+++ b/test/SemaCXX/reinterpret-cast.cpp
@@ -0,0 +1,90 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+enum test { testval = 1 };
+struct structure { int m; };
+typedef void (*fnptr)();
+
+// Test the conversion to self.
+void self_conversion()
+{
+ // T*->T* is allowed, T->T in general not.
+ int i = 0;
+ (void)reinterpret_cast<int>(i); // expected-error {{reinterpret_cast from 'int' to 'int' is not allowed}}
+ structure s;
+ (void)reinterpret_cast<structure>(s); // expected-error {{reinterpret_cast from 'struct structure' to 'struct structure' is not allowed}}
+ int *pi = 0;
+ (void)reinterpret_cast<int*>(pi);
+}
+
+// Test conversion between pointer and integral types, as in /3 and /4.
+void integral_conversion()
+{
+ void *vp = reinterpret_cast<void*>(testval);
+ long l = reinterpret_cast<long>(vp);
+ (void)reinterpret_cast<float*>(l);
+ fnptr fnp = reinterpret_cast<fnptr>(l);
+ (void)reinterpret_cast<char>(fnp); // expected-error {{cast from pointer to smaller type 'char' loses information}}
+ (void)reinterpret_cast<long>(fnp);
+}
+
+void pointer_conversion()
+{
+ int *p1 = 0;
+ float *p2 = reinterpret_cast<float*>(p1);
+ structure *p3 = reinterpret_cast<structure*>(p2);
+ typedef int **ppint;
+ ppint *deep = reinterpret_cast<ppint*>(p3);
+ (void)reinterpret_cast<fnptr*>(deep);
+}
+
+void constness()
+{
+ int ***const ipppc = 0;
+ // Valid: T1* -> T2 const*
+ int const *icp = reinterpret_cast<int const*>(ipppc);
+ // Invalid: T1 const* -> T2*
+ (void)reinterpret_cast<int*>(icp); // expected-error {{reinterpret_cast from 'int const *' to 'int *' casts away constness}}
+ // Invalid: T1*** -> T2 const* const**
+ int const *const **icpcpp = reinterpret_cast<int const* const**>(ipppc); // expected-error {{reinterpret_cast from 'int ***const' to 'int const *const **' casts away constness}}
+ // Valid: T1* -> T2*
+ int *ip = reinterpret_cast<int*>(icpcpp);
+ // Valid: T* -> T const*
+ (void)reinterpret_cast<int const*>(ip);
+ // Valid: T*** -> T2 const* const* const*
+ (void)reinterpret_cast<int const* const* const*>(ipppc);
+}
+
+void fnptrs()
+{
+ typedef int (*fnptr2)(int);
+ fnptr fp = 0;
+ (void)reinterpret_cast<fnptr2>(fp);
+ void *vp = reinterpret_cast<void*>(fp);
+ (void)reinterpret_cast<fnptr>(vp);
+}
+
+void refs()
+{
+ long l = 0;
+ char &c = reinterpret_cast<char&>(l);
+ // Bad: from rvalue
+ (void)reinterpret_cast<int&>(&c); // expected-error {{reinterpret_cast from rvalue to reference type 'int &'}}
+}
+
+void memptrs()
+{
+ const int structure::*psi = 0;
+ (void)reinterpret_cast<const float structure::*>(psi);
+ (void)reinterpret_cast<int structure::*>(psi); // expected-error {{reinterpret_cast from 'int const struct structure::*' to 'int struct structure::*' casts away constness}}
+
+ void (structure::*psf)() = 0;
+ (void)reinterpret_cast<int (structure::*)()>(psf);
+
+ (void)reinterpret_cast<void (structure::*)()>(psi); // expected-error {{reinterpret_cast from 'int const struct structure::*' to 'void (struct structure::*)(void)' is not allowed}}
+ (void)reinterpret_cast<int structure::*>(psf); // expected-error {{reinterpret_cast from 'void (struct structure::*)(void)' to 'int struct structure::*' is not allowed}}
+
+ // Cannot cast from integers to member pointers, not even the null pointer
+ // literal.
+ (void)reinterpret_cast<void (structure::*)()>(0); // expected-error {{reinterpret_cast from 'int' to 'void (struct structure::*)(void)' is not allowed}}
+ (void)reinterpret_cast<int structure::*>(0); // expected-error {{reinterpret_cast from 'int' to 'int struct structure::*' is not allowed}}
+}
diff --git a/test/SemaCXX/reinterpret-fn-obj-pedantic.cpp b/test/SemaCXX/reinterpret-fn-obj-pedantic.cpp
new file mode 100644
index 000000000000..16b8659711e2
--- /dev/null
+++ b/test/SemaCXX/reinterpret-fn-obj-pedantic.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++98 -pedantic %s
+
+void fnptrs()
+{
+ typedef void (*fnptr)();
+ fnptr fp = 0;
+ void *vp = reinterpret_cast<void*>(fp); // expected-warning {{reinterpret_cast between pointer-to-function and pointer-to-object is an extension}}
+ (void)reinterpret_cast<fnptr>(vp); // expected-warning {{reinterpret_cast between pointer-to-function and pointer-to-object is an extension}}
+}
diff --git a/test/SemaCXX/return-stack-addr.cpp b/test/SemaCXX/return-stack-addr.cpp
new file mode 100644
index 000000000000..457de297b008
--- /dev/null
+++ b/test/SemaCXX/return-stack-addr.cpp
@@ -0,0 +1,112 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+int* ret_local() {
+ int x = 1;
+ return &x; // expected-warning {{address of stack memory}}
+}
+
+int* ret_local_array() {
+ int x[10];
+ return x; // expected-warning {{address of stack memory}}
+}
+
+int* ret_local_array_element(int i) {
+ int x[10];
+ return &x[i]; // expected-warning {{address of stack memory}}
+}
+
+int *ret_local_array_element_reversed(int i) {
+ int x[10];
+ return &i[x]; // expected-warning {{address of stack memory}}
+}
+
+int* ret_local_array_element_const_index() {
+ int x[10];
+ return &x[2]; // expected-warning {{address of stack memory}}
+}
+
+int& ret_local_ref() {
+ int x = 1;
+ return x; // expected-warning {{reference to stack memory}}
+}
+
+int* ret_local_addrOf() {
+ int x = 1;
+ return &*&x; // expected-warning {{address of stack memory}}
+}
+
+int* ret_local_addrOf_paren() {
+ int x = 1;
+ return (&(*(&x))); // expected-warning {{address of stack memory}}
+}
+
+int* ret_local_addrOf_ptr_arith() {
+ int x = 1;
+ return &*(&x+1); // expected-warning {{address of stack memory}}
+}
+
+int* ret_local_addrOf_ptr_arith2() {
+ int x = 1;
+ return &*(&x+1); // expected-warning {{address of stack memory}}
+}
+
+int* ret_local_field() {
+ struct { int x; } a;
+ return &a.x; // expected-warning {{address of stack memory}}
+}
+
+int& ret_local_field_ref() {
+ struct { int x; } a;
+ return a.x; // expected-warning {{reference to stack memory}}
+}
+
+int* ret_conditional(bool cond) {
+ int x = 1;
+ int y = 2;
+ return cond ? &x : &y; // expected-warning {{address of stack memory}}
+}
+
+int* ret_conditional_rhs(int *x, bool cond) {
+ int y = 1;
+ return cond ? x : &y; // expected-warning {{address of stack memory}}
+}
+
+void* ret_c_cast() {
+ int x = 1;
+ return (void*) &x; // expected-warning {{address of stack memory}}
+}
+
+int* ret_static_var() {
+ static int x = 1;
+ return &x; // no warning.
+}
+
+int z = 1;
+
+int* ret_global() {
+ return &z; // no warning.
+}
+
+int* ret_parameter(int x) {
+ return &x; // expected-warning {{address of stack memory}}
+}
+
+
+void* ret_cpp_static_cast(short x) {
+ return static_cast<void*>(&x); // expected-warning {{address of stack memory}}
+}
+
+int* ret_cpp_reinterpret_cast(double x) {
+ return reinterpret_cast<int*>(&x); // expected-warning {{address of stack me}}
+}
+
+int* ret_cpp_reinterpret_cast_no_warning(long x) {
+ return reinterpret_cast<int*>(x); // no-warning
+}
+
+int* ret_cpp_const_cast(const int x) {
+ return const_cast<int*>(&x); // expected-warning {{address of stack memory}}
+}
+
+// TODO: test case for dynamic_cast. clang does not yet have
+// support for C++ classes to write such a test case.
diff --git a/test/SemaCXX/rval-references.cpp b/test/SemaCXX/rval-references.cpp
new file mode 100644
index 000000000000..a7d26bb4b0e1
--- /dev/null
+++ b/test/SemaCXX/rval-references.cpp
@@ -0,0 +1,91 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+
+typedef int&& irr;
+typedef irr& ilr_c1; // Collapses to int&
+typedef int& ilr;
+typedef ilr&& ilr_c2; // Collapses to int&
+
+irr ret_irr() {
+ return 0;
+}
+
+struct not_int {};
+
+int over(int&);
+not_int over(int&&);
+
+int over2(const int&);
+not_int over2(int&&);
+
+struct conv_to_not_int_rvalue {
+ operator not_int &&();
+};
+
+void f() {
+ int &&virr1; // expected-error {{declaration of reference variable 'virr1' requires an initializer}}
+ int &&virr2 = 0;
+ int &&virr3 = virr2; // expected-error {{rvalue reference cannot bind to lvalue}}
+ int i1 = 0;
+ int &&virr4 = i1; // expected-error {{rvalue reference cannot bind to lvalue}}
+ int &&virr5 = ret_irr();
+ int &&virr6 = static_cast<int&&>(i1);
+ (void)static_cast<not_int&&>(i1); // expected-error {{types are not compatible}}
+
+ int i2 = over(i1);
+ not_int ni1 = over(0);
+ int i3 = over(virr2);
+ not_int ni2 = over(ret_irr());
+
+ int i4 = over2(i1);
+ not_int ni3 = over2(0);
+
+ ilr_c1 vilr1 = i1;
+ ilr_c2 vilr2 = i1;
+
+ conv_to_not_int_rvalue cnir;
+ not_int &&ni4 = cnir; // expected-error {{rvalue reference cannot bind to lvalue}}
+ not_int &ni5 = cnir; // expected-error{{non-const lvalue reference to type 'struct not_int' cannot be initialized with a value of type 'struct conv_to_not_int_rvalue'}}
+ not_int &&ni6 = conv_to_not_int_rvalue();
+
+
+ try {
+ } catch(int&&) { // expected-error {{cannot catch exceptions by rvalue reference}}
+ }
+}
+
+int&& should_warn(int i) {
+ // FIXME: The stack address return test doesn't reason about casts.
+ return static_cast<int&&>(i); // xpected-warning {{returning reference to temporary}}
+}
+int&& should_not_warn(int&& i) { // But GCC 4.4 does
+ return static_cast<int&&>(i);
+}
+
+
+// Test the return dance. This also tests IsReturnCopyElidable.
+struct MoveOnly {
+ MoveOnly();
+ MoveOnly(const MoveOnly&) = delete;
+ MoveOnly(MoveOnly&&);
+ MoveOnly(int&&);
+};
+
+MoveOnly returning() {
+ MoveOnly mo;
+ return mo;
+}
+
+MoveOnly gmo;
+MoveOnly returningNonEligible() {
+ int i;
+ static MoveOnly mo;
+ MoveOnly &r = mo;
+ if (0) // Copy from global can't be elided
+ return gmo; // expected-error {{incompatible type returning}}
+ else if (0) // Copy from local static can't be elided
+ return mo; // expected-error {{incompatible type returning}}
+ else if (0) // Copy from reference can't be elided
+ return r; // expected-error {{incompatible type returning}}
+ else // Construction from different type can't be elided
+ return i; // expected-error {{incompatible type returning}}
+}
diff --git a/test/SemaCXX/statements.cpp b/test/SemaCXX/statements.cpp
new file mode 100644
index 000000000000..d6925fe032e9
--- /dev/null
+++ b/test/SemaCXX/statements.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-cc %s -fsyntax-only -pedantic
+
+void foo() {
+ return foo();
+}
diff --git a/test/SemaCXX/static-assert.cpp b/test/SemaCXX/static-assert.cpp
new file mode 100644
index 000000000000..caf76033af70
--- /dev/null
+++ b/test/SemaCXX/static-assert.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+
+int f();
+
+static_assert(f(), "f"); // expected-error {{static_assert expression is not an integral constant expression}}
+static_assert(true, "true is not false");
+static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}}
+
+void g() {
+ static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}}
+}
+
+class C {
+ static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}}
+};
+
+template<int N> struct T {
+ static_assert(N == 2, "N is not 2!"); // expected-error {{static_assert failed "N is not 2!"}}
+};
+
+T<1> t1; // expected-note {{in instantiation of template class 'struct T<1>' requested here}}
+T<2> t2;
+
+template<typename T> struct S {
+ static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static_assert failed "Type not big enough!"}}
+};
+
+S<char> s1; // expected-note {{in instantiation of template class 'struct S<char>' requested here}}
+S<int> s2;
+
diff --git a/test/SemaCXX/static-cast.cpp b/test/SemaCXX/static-cast.cpp
new file mode 100644
index 000000000000..8399e77085b3
--- /dev/null
+++ b/test/SemaCXX/static-cast.cpp
@@ -0,0 +1,129 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct A {};
+struct B : public A {}; // Single public base.
+struct C1 : public virtual B {}; // Single virtual base.
+struct C2 : public virtual B {};
+struct D : public C1, public C2 {}; // Diamond
+struct E : private A {}; // Single private base.
+struct F : public C1 {}; // Single path to B with virtual.
+struct G1 : public B {};
+struct G2 : public B {};
+struct H : public G1, public G2 {}; // Ambiguous path to B.
+
+enum Enum { En1, En2 };
+enum Onom { On1, On2 };
+
+// Explicit implicits
+void t_529_2()
+{
+ int i = 1;
+ (void)static_cast<float>(i);
+ double d = 1.0;
+ (void)static_cast<float>(d);
+ (void)static_cast<int>(d);
+ (void)static_cast<char>(i);
+ (void)static_cast<unsigned long>(i);
+ (void)static_cast<int>(En1);
+ (void)static_cast<double>(En1);
+ (void)static_cast<int&>(i);
+ (void)static_cast<const int&>(i);
+
+ int ar[1];
+ (void)static_cast<const int*>(ar);
+ (void)static_cast<void (*)()>(t_529_2);
+
+ (void)static_cast<void*>(0);
+ (void)static_cast<void*>((int*)0);
+ (void)static_cast<volatile const void*>((const int*)0);
+ (void)static_cast<A*>((B*)0);
+ (void)static_cast<A&>(*((B*)0));
+ (void)static_cast<const B*>((C1*)0);
+ (void)static_cast<B&>(*((C1*)0));
+ (void)static_cast<A*>((D*)0);
+ (void)static_cast<const A&>(*((D*)0));
+ (void)static_cast<int B::*>((int A::*)0);
+ (void)static_cast<void (B::*)()>((void (A::*)())0);
+
+ // TODO: User-defined conversions
+
+ // Bad code below
+
+ (void)static_cast<void*>((const int*)0); // expected-error {{static_cast from 'int const *' to 'void *' is not allowed}}
+ //(void)static_cast<A*>((E*)0); // {{static_cast from 'struct E *' to 'struct A *' is not allowed}}
+ //(void)static_cast<A*>((H*)0); // {{static_cast from 'struct H *' to 'struct A *' is not allowed}}
+ (void)static_cast<int>((int*)0); // expected-error {{static_cast from 'int *' to 'int' is not allowed}}
+ (void)static_cast<A**>((B**)0); // expected-error {{static_cast from 'struct B **' to 'struct A **' is not allowed}}
+ (void)static_cast<char&>(i); // expected-error {{non-const lvalue reference to type 'char' cannot be initialized with a value of type 'int'}}
+}
+
+// Anything to void
+void t_529_4()
+{
+ static_cast<void>(1);
+ static_cast<void>(t_529_4);
+}
+
+// Static downcasts
+void t_529_5_8()
+{
+ (void)static_cast<B*>((A*)0);
+ (void)static_cast<B&>(*((A*)0));
+ (void)static_cast<const G1*>((A*)0);
+ (void)static_cast<const G1&>(*((A*)0));
+
+ // Bad code below
+
+ (void)static_cast<C1*>((A*)0); // expected-error {{cannot cast 'struct A *' to 'struct C1 *' via virtual base 'struct B'}}
+ (void)static_cast<C1&>(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'struct C1 &' via virtual base 'struct B'}}
+ (void)static_cast<D*>((A*)0); // expected-error {{cannot cast 'struct A *' to 'struct D *' via virtual base 'struct B'}}
+ (void)static_cast<D&>(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'struct D &' via virtual base 'struct B'}}
+ (void)static_cast<B*>((const A*)0); // expected-error {{static_cast from 'struct A const *' to 'struct B *' casts away constness}}
+ (void)static_cast<B&>(*((const A*)0)); // expected-error {{static_cast from 'struct A const' to 'struct B &' casts away constness}}
+ // Accessibility is not yet tested
+ //(void)static_cast<E*>((A*)0); // {{static_cast from 'struct A *' to 'struct E *' is not allowed}}
+ //(void)static_cast<E&>(*((A*)0)); // {{static_cast from 'struct A' to 'struct E &' is not allowed}}
+ (void)static_cast<H*>((A*)0); // expected-error {{ambiguous static_cast from base 'struct A' to derived 'struct H':\n struct A -> struct B -> struct G1 -> struct H\n struct A -> struct B -> struct G2 -> struct H}}
+ (void)static_cast<H&>(*((A*)0)); // expected-error {{ambiguous static_cast from base 'struct A' to derived 'struct H':\n struct A -> struct B -> struct G1 -> struct H\n struct A -> struct B -> struct G2 -> struct H}}
+ (void)static_cast<E*>((B*)0); // expected-error {{static_cast from 'struct B *' to 'struct E *' is not allowed}}
+ (void)static_cast<E&>(*((B*)0)); // expected-error {{non-const lvalue reference to type 'struct E' cannot be initialized with a value of type 'struct B'}}
+
+ // TODO: Test inaccessible base in context where it's accessible, i.e.
+ // member function and friend.
+
+ // TODO: Test DR427. This requires user-defined conversions, though.
+}
+
+// Enum conversions
+void t_529_7()
+{
+ (void)static_cast<Enum>(1);
+ (void)static_cast<Enum>(1.0);
+ (void)static_cast<Onom>(En1);
+
+ // Bad code below
+
+ (void)static_cast<Enum>((int*)0); // expected-error {{static_cast from 'int *' to 'enum Enum' is not allowed}}
+}
+
+// Void pointer to object pointer
+void t_529_10()
+{
+ (void)static_cast<int*>((void*)0);
+ (void)static_cast<const A*>((void*)0);
+
+ // Bad code below
+
+ (void)static_cast<int*>((const void*)0); // expected-error {{static_cast from 'void const *' to 'int *' casts away constness}}
+ (void)static_cast<void (*)()>((void*)0); // expected-error {{static_cast from 'void *' to 'void (*)(void)' is not allowed}}
+}
+
+// Member pointer upcast.
+void t_529_9()
+{
+ (void)static_cast<int A::*>((int B::*)0);
+
+ // Bad code below
+ (void)static_cast<int A::*>((int H::*)0); // expected-error {{ambiguous conversion from pointer to member of derived class 'struct H'}}
+ (void)static_cast<int A::*>((int F::*)0); // expected-error {{conversion from pointer to member of class 'struct F'}}
+}
diff --git a/test/SemaCXX/static-initializers.cpp b/test/SemaCXX/static-initializers.cpp
new file mode 100644
index 000000000000..3d92a532ae1a
--- /dev/null
+++ b/test/SemaCXX/static-initializers.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+int f()
+{
+ return 10;
+}
+
+void g()
+{
+ static int a = f();
+}
+
+static int b = f();
diff --git a/test/SemaCXX/struct-class-redecl.cpp b/test/SemaCXX/struct-class-redecl.cpp
new file mode 100644
index 000000000000..4b6cef6dd2bf
--- /dev/null
+++ b/test/SemaCXX/struct-class-redecl.cpp
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -Wmismatched-tags -verify %s
+class X; // expected-note 2{{here}}
+typedef struct X * X_t; // expected-warning{{previously declared}}
+
+template<typename T> struct Y; // expected-note{{previous}}
+template<class U> class Y { }; // expected-warning{{previously declared}}
+
+union X { int x; float y; }; // expected-error{{use of 'X' with tag type that does not match previous declaration}}
diff --git a/test/SemaCXX/template-specialization.cpp b/test/SemaCXX/template-specialization.cpp
new file mode 100644
index 000000000000..b3bb08d7e6a2
--- /dev/null
+++ b/test/SemaCXX/template-specialization.cpp
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<int N> void f(int (&array)[N]);
+
+template<> void f<1>(int (&array)[1]) { }
diff --git a/test/SemaCXX/this.cpp b/test/SemaCXX/this.cpp
new file mode 100644
index 000000000000..0577d3c2b9bf
--- /dev/null
+++ b/test/SemaCXX/this.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+int x = this; // expected-error {{error: invalid use of 'this' outside of a nonstatic member function}}
+
+void f() {
+ int x = this; // expected-error {{error: invalid use of 'this' outside of a nonstatic member function}}
+}
diff --git a/test/SemaCXX/trivial-constructor.cpp b/test/SemaCXX/trivial-constructor.cpp
new file mode 100644
index 000000000000..8fc14d9c82cb
--- /dev/null
+++ b/test/SemaCXX/trivial-constructor.cpp
@@ -0,0 +1,38 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+struct T1 {
+};
+static_assert(__has_trivial_constructor(T1), "T1 has trivial constructor!");
+
+struct T2 {
+ T2();
+};
+static_assert(!__has_trivial_constructor(T2), "T2 has a user-declared constructor!");
+
+struct T3 {
+ virtual void f();
+};
+static_assert(!__has_trivial_constructor(T3), "T3 has a virtual function!");
+
+struct T4 : virtual T3 {
+};
+static_assert(!__has_trivial_constructor(T4), "T4 has a virtual base class!");
+
+struct T5 : T1 {
+};
+static_assert(__has_trivial_constructor(T5), "All the direct base classes of T5 have trivial constructors!");
+
+struct T6 {
+ T5 t5;
+ T1 t1[2][2];
+ static T2 t2;
+};
+static_assert(__has_trivial_constructor(T6), "All nonstatic data members of T6 have trivial constructors!");
+
+struct T7 {
+ T4 t4;
+};
+static_assert(!__has_trivial_constructor(T7), "t4 does not have a trivial constructor!");
+
+struct T8 : T2 {
+};
+static_assert(!__has_trivial_constructor(T8), "The base class T2 does not have a trivial constructor!");
diff --git a/test/SemaCXX/trivial-destructor.cpp b/test/SemaCXX/trivial-destructor.cpp
new file mode 100644
index 000000000000..9e7f3a16dd66
--- /dev/null
+++ b/test/SemaCXX/trivial-destructor.cpp
@@ -0,0 +1,38 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+struct T1 {
+};
+static_assert(__has_trivial_destructor(T1), "T1 has trivial destructor!");
+
+struct T2 {
+ ~T2();
+};
+static_assert(!__has_trivial_destructor(T2), "T2 has a user-declared destructor!");
+
+struct T3 {
+ virtual void f();
+};
+static_assert(__has_trivial_destructor(T3), "T3 has a virtual function (but still a trivial destructor)!");
+
+struct T4 : virtual T3 {
+};
+static_assert(__has_trivial_destructor(T4), "T4 has a virtual base class! (but still a trivial destructor)!");
+
+struct T5 : T1 {
+};
+static_assert(__has_trivial_destructor(T5), "All the direct base classes of T5 have trivial destructors!");
+
+struct T6 {
+ T5 t5;
+ T1 t1[2][2];
+ static T2 t2;
+};
+static_assert(__has_trivial_destructor(T6), "All nonstatic data members of T6 have trivial destructors!");
+
+struct T7 {
+ T2 t2;
+};
+static_assert(!__has_trivial_destructor(T7), "t2 does not have a trivial destructor!");
+
+struct T8 : T2 {
+};
+static_assert(!__has_trivial_destructor(T8), "The base class T2 does not have a trivial destructor!");
diff --git a/test/SemaCXX/type-convert-construct.cpp b/test/SemaCXX/type-convert-construct.cpp
new file mode 100644
index 000000000000..1840456bde8e
--- /dev/null
+++ b/test/SemaCXX/type-convert-construct.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f() {
+ float v1 = float(1);
+ int v2 = typeof(int)(1,2); // expected-error {{function-style cast to a builtin type can only take one argument}}
+ typedef int arr[];
+ int v3 = arr(); // expected-error {{array types cannot be value-initialized}}
+ int v4 = int();
+ int v5 = int; // expected-error {{expected '(' for function-style cast or type construction}}
+ typedef int T;
+ int *p;
+ bool v6 = T(0) == p;
+ char *str;
+ str = "a string";
+ wchar_t *wstr;
+ wstr = L"a wide string";
+}
diff --git a/test/SemaCXX/type-definition-in-specifier.cpp b/test/SemaCXX/type-definition-in-specifier.cpp
new file mode 100644
index 000000000000..60c28b0f5e43
--- /dev/null
+++ b/test/SemaCXX/type-definition-in-specifier.cpp
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct S0;
+struct S1;
+struct S2;
+struct S3;
+struct S4;
+struct S5;
+struct S6;
+
+struct S0 { int x; };
+
+void f0() {
+ typedef struct S1 { int x; } S1_typedef;
+
+ (void)((struct S2 { int x; }*)0); // expected-error{{can not be defined}}
+
+ struct S3 { int x; } s3;
+
+ (void)static_cast<struct S4 { int x; } *>(0); // expected-error{{can not be defined}}
+}
+
+struct S5 { int x; } f1() { return S5(); } // expected-error{{result type}}
+
+void f2(struct S6 { int x; } p); // expected-error{{parameter type}}
diff --git a/test/SemaCXX/type-dependent-exprs.cpp b/test/SemaCXX/type-dependent-exprs.cpp
new file mode 100644
index 000000000000..dd31ef020c6a
--- /dev/null
+++ b/test/SemaCXX/type-dependent-exprs.cpp
@@ -0,0 +1,24 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class X {
+public:
+ virtual int f();
+};
+
+void g(int); // expected-note{{candidate function}}
+
+template<typename T>
+T f(T x) {
+ (void)(x + 0);
+ (void)T(0);
+ (void)(x += 0);
+ (void)(x? x : x);
+ (void)static_cast<int>(x);
+ (void)reinterpret_cast<int>(x);
+ (void)dynamic_cast<X*>(&x);
+ (void)const_cast<int>(x);
+ return g(x);
+ h(x); // h is a dependent name
+ g(1, 1); // expected-error{{no matching function for call}}
+ h(1); // expected-error{{no matching function for call to 'h'}}
+ return 0;
+}
diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
new file mode 100644
index 000000000000..1a2e329b2a44
--- /dev/null
+++ b/test/SemaCXX/type-traits.cpp
@@ -0,0 +1,111 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+#define T(b) (b) ? 1 : -1
+#define F(b) (b) ? -1 : 1
+
+struct NonPOD { NonPOD(int); };
+
+// PODs
+enum Enum { EV };
+struct POD { Enum e; int i; float f; NonPOD* p; };
+typedef int Int;
+typedef Int IntAr[10];
+class Statics { static int priv; static NonPOD np; };
+
+// Not PODs
+struct Derives : POD {};
+struct HasCons { HasCons(int); };
+struct HasAssign { HasAssign operator =(const HasAssign&); };
+struct HasDest { ~HasDest(); };
+class HasPriv { int priv; };
+class HasProt { protected: int prot; };
+struct HasRef { int i; int& ref; HasRef() : i(0), ref(i) {} };
+struct HasNonPOD { NonPOD np; };
+struct HasVirt { virtual void Virt() {}; };
+typedef Derives NonPODAr[10];
+
+void is_pod()
+{
+ int t01[T(__is_pod(int))];
+ int t02[T(__is_pod(Enum))];
+ int t03[T(__is_pod(POD))];
+ int t04[T(__is_pod(Int))];
+ int t05[T(__is_pod(IntAr))];
+ int t06[T(__is_pod(Statics))];
+
+ int t21[F(__is_pod(Derives))];
+ int t22[F(__is_pod(HasCons))];
+ int t23[F(__is_pod(HasAssign))];
+ int t24[F(__is_pod(HasDest))];
+ int t25[F(__is_pod(HasPriv))];
+ int t26[F(__is_pod(HasProt))];
+ int t27[F(__is_pod(HasRef))];
+ int t28[F(__is_pod(HasNonPOD))];
+ int t29[F(__is_pod(HasVirt))];
+ int t30[F(__is_pod(NonPODAr))];
+}
+
+union Union { int i; float f; };
+typedef Derives ClassType;
+
+void is_class()
+{
+ int t01[T(__is_class(Derives))];
+ int t02[T(__is_class(HasPriv))];
+ int t03[T(__is_class(ClassType))];
+
+ int t11[F(__is_class(int))];
+ int t12[F(__is_class(Enum))];
+ int t13[F(__is_class(Int))];
+ int t14[F(__is_class(IntAr))];
+ int t15[F(__is_class(NonPODAr))];
+ int t16[F(__is_class(Union))];
+}
+
+typedef Union UnionAr[10];
+typedef Union UnionType;
+
+void is_union()
+{
+ int t01[T(__is_union(Union))];
+ int t02[T(__is_union(UnionType))];
+
+ int t11[F(__is_union(int))];
+ int t12[F(__is_union(Enum))];
+ int t13[F(__is_union(Int))];
+ int t14[F(__is_union(IntAr))];
+ int t15[F(__is_union(UnionAr))];
+}
+
+typedef Enum EnumType;
+
+void is_enum()
+{
+ int t01[T(__is_enum(Enum))];
+ int t02[T(__is_enum(EnumType))];
+
+ int t11[F(__is_enum(int))];
+ int t12[F(__is_enum(Union))];
+ int t13[F(__is_enum(Int))];
+ int t14[F(__is_enum(IntAr))];
+ int t15[F(__is_enum(UnionAr))];
+ int t16[F(__is_enum(Derives))];
+ int t17[F(__is_enum(ClassType))];
+}
+
+struct Polymorph { virtual void f(); };
+struct InheritPolymorph : Polymorph {};
+
+void is_polymorphic()
+{
+ int t01[T(__is_polymorphic(Polymorph))];
+ int t02[T(__is_polymorphic(InheritPolymorph))];
+
+ int t11[F(__is_polymorphic(int))];
+ int t12[F(__is_polymorphic(Union))];
+ int t13[F(__is_polymorphic(Int))];
+ int t14[F(__is_polymorphic(IntAr))];
+ int t15[F(__is_polymorphic(UnionAr))];
+ int t16[F(__is_polymorphic(Derives))];
+ int t17[F(__is_polymorphic(ClassType))];
+ int t18[F(__is_polymorphic(Enum))];
+}
diff --git a/test/SemaCXX/typedef-redecl.cpp b/test/SemaCXX/typedef-redecl.cpp
new file mode 100644
index 000000000000..e38f47436d1c
--- /dev/null
+++ b/test/SemaCXX/typedef-redecl.cpp
@@ -0,0 +1,31 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+typedef int INT;
+typedef INT REALLY_INT; // expected-note {{previous definition is here}}
+typedef REALLY_INT REALLY_REALLY_INT;
+typedef REALLY_INT BOB;
+typedef float REALLY_INT; // expected-error{{typedef redefinition with different types ('float' vs 'INT' (aka 'int'))}}
+
+struct X {
+ typedef int result_type; // expected-note {{previous definition is here}}
+ typedef INT result_type; // expected-error {{redefinition of 'result_type'}}
+};
+
+struct Y; // expected-note{{previous definition is here}}
+typedef int Y; // expected-error{{typedef redefinition with different types ('int' vs 'struct Y')}}
+
+typedef int Y2; // expected-note{{previous definition is here}}
+struct Y2; // expected-error{{definition of type 'struct Y2' conflicts with typedef of the same name}}
+
+void f(); // expected-note{{previous definition is here}}
+typedef int f; // expected-error{{redefinition of 'f' as different kind of symbol}}
+
+typedef int f2; // expected-note{{previous definition is here}}
+void f2(); // expected-error{{redefinition of 'f2' as different kind of symbol}}
+
+typedef struct s s;
+typedef int I;
+typedef int I;
+typedef I I;
+
+struct s { };
+
diff --git a/test/SemaCXX/typeid.cpp b/test/SemaCXX/typeid.cpp
new file mode 100644
index 000000000000..f9ad7592187c
--- /dev/null
+++ b/test/SemaCXX/typeid.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f()
+{
+ (void)typeid(int); // expected-error {{error: you need to include <typeinfo> before using the 'typeid' operator}}
+}
+
+// FIXME: This should really include <typeinfo>, but we don't have that yet.
+namespace std {
+ class type_info;
+}
+
+void g()
+{
+ (void)typeid(int);
+}
diff --git a/test/SemaCXX/types_compatible_p.cpp b/test/SemaCXX/types_compatible_p.cpp
new file mode 100644
index 000000000000..30b16006c685
--- /dev/null
+++ b/test/SemaCXX/types_compatible_p.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+bool f() {
+ return __builtin_types_compatible_p(int, const int); // expected-error{{C++}}
+}
diff --git a/test/SemaCXX/unused.cpp b/test/SemaCXX/unused.cpp
new file mode 100644
index 000000000000..55f959de0f02
--- /dev/null
+++ b/test/SemaCXX/unused.cpp
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// PR4103 : Make sure we don't get a bogus unused expression warning
+class APInt {
+ char foo;
+};
+class APSInt : public APInt {
+ char bar;
+public:
+ APSInt &operator=(const APSInt &RHS);
+};
+
+APSInt& APSInt::operator=(const APSInt &RHS) {
+ APInt::operator=(RHS);
+ return *this;
+}
diff --git a/test/SemaCXX/user-defined-conversions.cpp b/test/SemaCXX/user-defined-conversions.cpp
new file mode 100644
index 000000000000..0a4bb773d396
--- /dev/null
+++ b/test/SemaCXX/user-defined-conversions.cpp
@@ -0,0 +1,69 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct X {
+ operator bool();
+};
+
+int& f(bool);
+float& f(int);
+
+void f_test(X x) {
+ int& i1 = f(x);
+}
+
+struct Y {
+ operator short();
+ operator float();
+};
+
+void g(int);
+
+void g_test(Y y) {
+ g(y);
+ short s;
+ s = y;
+}
+
+struct A { };
+struct B : A { };
+
+struct C {
+ operator B&();
+};
+
+// Test reference binding via an lvalue conversion function.
+void h(volatile A&);
+void h_test(C c) {
+ h(c);
+}
+
+// Test conversion followed by copy-construction
+struct FunkyDerived;
+
+struct Base {
+ Base(const FunkyDerived&);
+};
+
+struct Derived : Base { };
+
+struct FunkyDerived : Base { };
+
+struct ConvertibleToBase {
+ operator Base();
+};
+
+struct ConvertibleToDerived {
+ operator Derived();
+};
+
+struct ConvertibleToFunkyDerived {
+ operator FunkyDerived();
+};
+
+void test_conversion(ConvertibleToBase ctb, ConvertibleToDerived ctd,
+ ConvertibleToFunkyDerived ctfd) {
+ Base b1 = ctb;
+ Base b2(ctb);
+ Base b3 = ctd;
+ Base b4(ctd);
+ Base b5 = ctfd;
+}
diff --git a/test/SemaCXX/using-directive.cpp b/test/SemaCXX/using-directive.cpp
new file mode 100644
index 000000000000..924cf077b63f
--- /dev/null
+++ b/test/SemaCXX/using-directive.cpp
@@ -0,0 +1,108 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace A {
+ short i; // expected-note 2{{candidate found by name lookup is 'A::i'}}
+ namespace B {
+ long i; // expected-note{{candidate found by name lookup is 'A::B::i'}}
+ void f() {} // expected-note{{candidate function}}
+ int k;
+ namespace E {} // \
+ expected-note{{candidate found by name lookup is 'A::B::E'}}
+ }
+
+ namespace E {} // expected-note{{candidate found by name lookup is 'A::E'}}
+
+ namespace C {
+ using namespace B;
+ namespace E {} // \
+ expected-note{{candidate found by name lookup is 'A::C::E'}}
+ }
+
+ void f() {} // expected-note{{candidate function}}
+
+ class K1 {
+ void foo();
+ };
+
+ void local_i() {
+ char i;
+ using namespace A;
+ using namespace B;
+ int a[sizeof(i) == sizeof(char)? 1 : -1]; // okay
+ }
+ namespace B {
+ int j;
+ }
+
+ void ambig_i() {
+ using namespace A;
+ using namespace A::B;
+ (void) i; // expected-error{{reference to 'i' is ambiguous}}
+ f(); // expected-error{{call to 'f' is ambiguous}}
+ (void) j; // okay
+ using namespace C;
+ (void) k; // okay
+ using namespace E; // expected-error{{reference to 'E' is ambiguous}}
+ }
+
+ struct K2 {}; // expected-note{{candidate found by name lookup is 'A::K2'}}
+}
+
+struct K2 {}; // expected-note{{candidate found by name lookup is 'K2'}}
+
+using namespace A;
+
+void K1::foo() {} // okay
+
+// FIXME: Do we want err_ovl_no_viable_function_in_init here?
+struct K2 k2; // expected-error{{reference to 'K2' is ambiguous}} \
+ expected-error{{incomplete type}}
+
+// FIXME: This case is incorrectly diagnosed!
+//K2 k3;
+
+
+class X { // expected-note{{candidate found by name lookup is 'X'}}
+ // FIXME: produce a suitable error message for this
+ using namespace A; // expected-error{{expected member name or}}
+};
+
+namespace N {
+ struct K2;
+ struct K2 { };
+}
+
+namespace Ni {
+ int i(); // expected-note{{candidate found by name lookup is 'Ni::i'}}
+}
+
+namespace NiTest {
+ using namespace A;
+ using namespace Ni;
+
+ int test() {
+ return i; // expected-error{{reference to 'i' is ambiguous}}
+ }
+}
+
+namespace OneTag {
+ struct X; // expected-note{{candidate found by name lookup is 'OneTag::X'}}
+}
+
+namespace OneFunction {
+ void X(); // expected-note{{candidate found by name lookup is 'OneFunction::X'}}
+}
+
+namespace TwoTag {
+ struct X; // expected-note{{candidate found by name lookup is 'TwoTag::X'}}
+}
+
+namespace FuncHidesTagAmbiguity {
+ using namespace OneTag;
+ using namespace OneFunction;
+ using namespace TwoTag;
+
+ void test() {
+ (void)X(); // expected-error{{reference to 'X' is ambiguous}}
+ }
+}
diff --git a/test/SemaCXX/vararg-non-pod.cpp b/test/SemaCXX/vararg-non-pod.cpp
new file mode 100644
index 000000000000..1c5fe74a154d
--- /dev/null
+++ b/test/SemaCXX/vararg-non-pod.cpp
@@ -0,0 +1,56 @@
+// RUN: clang-cc -fsyntax-only -verify -fblocks %s
+
+extern char version[];
+
+class C {
+public:
+ C(int);
+ void g(int a, ...);
+ static void h(int a, ...);
+};
+
+void g(int a, ...);
+
+void t1()
+{
+ C c(10);
+
+ g(10, c); // expected-warning{{cannot pass object of non-POD type 'class C' through variadic function; call will abort at runtime}}
+ g(10, version);
+}
+
+void t2()
+{
+ C c(10);
+
+ c.g(10, c); // expected-warning{{cannot pass object of non-POD type 'class C' through variadic method; call will abort at runtime}}
+ c.g(10, version);
+
+ C::h(10, c); // expected-warning{{cannot pass object of non-POD type 'class C' through variadic function; call will abort at runtime}}
+ C::h(10, version);
+}
+
+int (^block)(int, ...);
+
+void t3()
+{
+ C c(10);
+
+ block(10, c); // expected-warning{{cannot pass object of non-POD type 'class C' through variadic block; call will abort at runtime}}
+ block(10, version);
+}
+
+class D {
+public:
+ void operator() (int a, ...);
+};
+
+void t4()
+{
+ C c(10);
+
+ D d;
+
+ d(10, c); // expected-warning{{Line 48: cannot pass object of non-POD type 'class C' through variadic method; call will abort at runtime}}
+ d(10, version);
+}
diff --git a/test/SemaCXX/virtual-override.cpp b/test/SemaCXX/virtual-override.cpp
new file mode 100644
index 000000000000..4a3b10fa9764
--- /dev/null
+++ b/test/SemaCXX/virtual-override.cpp
@@ -0,0 +1,106 @@
+// RUN: clang-cc -fsyntax-only -faccess-control -verify %s
+
+namespace T1 {
+
+class A {
+ virtual int f(); // expected-note{{overridden virtual function is here}}
+};
+
+class B : A {
+ virtual void f(); // expected-error{{virtual function 'f' has a different return type ('void') than the function it overrides (which has return type 'int')}}
+};
+
+}
+
+namespace T2 {
+
+struct a { };
+struct b { };
+
+class A {
+ virtual a* f(); // expected-note{{overridden virtual function is here}}
+};
+
+class B : A {
+ virtual b* f(); // expected-error{{return type of virtual function 'f' is not covariant with the return type of the function it overrides ('struct T2::b *' is not derived from 'struct T2::a *')}}
+};
+
+}
+
+namespace T3 {
+
+struct a { };
+struct b : private a { }; // expected-note{{'private' inheritance specifier here}}
+
+class A {
+ virtual a* f(); // expected-note{{overridden virtual function is here}}
+};
+
+class B : A {
+ virtual b* f(); // expected-error{{return type of virtual function 'f' is not covariant with the return type of the function it overrides (conversion from 'struct T3::b' to inaccessible base class 'struct T3::a')}}
+};
+
+}
+
+namespace T4 {
+
+struct a { };
+struct a1 : a { };
+struct b : a, a1 { };
+
+class A {
+ virtual a* f(); // expected-note{{overridden virtual function is here}}
+};
+
+class B : A {
+ virtual b* f(); // expected-error{{return type of virtual function 'f' is not covariant with the return type of the function it overrides (ambiguous conversion from derived class 'struct T4::b' to base class 'struct T4::a':\n\
+ struct T4::b -> struct T4::a\n\
+ struct T4::b -> struct T4::a1 -> struct T4::a)}}
+};
+
+}
+
+namespace T5 {
+
+struct a { };
+
+class A {
+ virtual a* const f();
+ virtual a* const g(); // expected-note{{overridden virtual function is here}}
+};
+
+class B : A {
+ virtual a* const f();
+ virtual a* g(); // expected-error{{return type of virtual function 'g' is not covariant with the return type of the function it overrides ('struct T5::a *' has different qualifiers than 'struct T5::a *const')}}
+};
+
+}
+
+namespace T6 {
+
+struct a { };
+
+class A {
+ virtual const a* f();
+ virtual a* g(); // expected-note{{overridden virtual function is here}}
+};
+
+class B : A {
+ virtual a* f();
+ virtual const a* g(); // expected-error{{return type of virtual function 'g' is not covariant with the return type of the function it overrides (class type 'struct T6::a const *' is more qualified than class type 'struct T6::a *'}}
+};
+
+}
+
+namespace T7 {
+ struct a { };
+ struct b { };
+
+ class A {
+ a* f();
+ };
+
+ class B : A {
+ virtual b* f();
+ };
+}
diff --git a/test/SemaCXX/virtuals.cpp b/test/SemaCXX/virtuals.cpp
new file mode 100644
index 000000000000..c2ac77b30479
--- /dev/null
+++ b/test/SemaCXX/virtuals.cpp
@@ -0,0 +1,38 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class A {
+ virtual void f();
+ virtual void g() = 0;
+
+ void h() = 0; // expected-error {{'h' is not virtual and cannot be declared pure}}
+ void i() = 1; // expected-error {{initializer on function does not look like a pure-specifier}}
+ void j() = 0u; // expected-error {{initializer on function does not look like a pure-specifier}}
+
+
+ void k();
+
+public:
+ A(int);
+};
+
+virtual void A::k() { } // expected-error{{'virtual' can only be specified inside the class definition}}
+
+class B : public A {
+ // Needs to recognize that overridden function is virtual.
+ //void g() = 0;
+
+ // Needs to recognize that function does not override.
+ //void g(int) = 0;
+};
+
+// Needs to recognize invalid uses of abstract classes.
+/*
+A fn(A)
+{
+ A a;
+ static_cast<A>(0);
+ try {
+ } catch(A) {
+ }
+}
+*/
diff --git a/test/SemaCXX/warn-for-var-in-else.cpp b/test/SemaCXX/warn-for-var-in-else.cpp
new file mode 100644
index 000000000000..3368da223a48
--- /dev/null
+++ b/test/SemaCXX/warn-for-var-in-else.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// rdar://6425550
+int bar();
+void do_something(int);
+
+int foo() {
+ if (int X = bar()) {
+ return X;
+ } else {
+ do_something(X); // expected-warning{{'X' is always zero in this context}}
+ }
+}
+
+bool foo2() {
+ if (bool B = bar()) {
+ if (int Y = bar()) {
+ return B;
+ } else {
+ do_something(Y); // expected-warning{{'Y' is always zero in this context}}
+ return B;
+ }
+ } else {
+ if (bool B2 = B) { // expected-warning{{'B' is always false in this context}}
+ do_something(B); // expected-warning{{'B' is always false in this context}}
+ } else if (B2) { // expected-warning{{'B2' is always false in this context}}
+ do_something(B); // expected-warning{{'B' is always false in this context}}
+ }
+ return B; // expected-warning{{'B' is always false in this context}}
+ }
+}
diff --git a/test/SemaCXX/wchar_t.cpp b/test/SemaCXX/wchar_t.cpp
new file mode 100644
index 000000000000..fc258da7d1a6
--- /dev/null
+++ b/test/SemaCXX/wchar_t.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+wchar_t x;
+
+void f(wchar_t p) {
+ wchar_t x;
+ unsigned wchar_t y; // expected-warning {{'wchar_t' cannot be signed or unsigned}}
+ signed wchar_t z; // expected-warning {{'wchar_t' cannot be signed or unsigned}}
+ ++x;
+}
diff --git a/test/SemaObjC/ContClassPropertyLookup.m b/test/SemaObjC/ContClassPropertyLookup.m
new file mode 100644
index 000000000000..aa5afa7854f0
--- /dev/null
+++ b/test/SemaObjC/ContClassPropertyLookup.m
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface MyObject {
+ int _foo;
+}
+@end
+
+@interface MyObject(whatever)
+@property (assign) int foo;
+@end
+
+@interface MyObject()
+@property (assign) int foo;
+@end
+
+@implementation MyObject
+@synthesize foo = _foo;
+@end
diff --git a/test/SemaObjC/DoubleMethod.m b/test/SemaObjC/DoubleMethod.m
new file mode 100644
index 000000000000..e43c1a0ab032
--- /dev/null
+++ b/test/SemaObjC/DoubleMethod.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface Subclass
+{
+ int ivar;
+}
+
+- (void) method;
+- (void) method;
+@end
+
+@implementation Subclass
+- (void) method {;} // expected-note {{previous declaration is here}}
+- (void) method {;} // expected-error {{duplicate declaration of method 'method'}}
+@end
+
+int main (void) {
+ return 0;
+}
diff --git a/test/SemaObjC/access-property-getter.m b/test/SemaObjC/access-property-getter.m
new file mode 100644
index 000000000000..50a301688905
--- /dev/null
+++ b/test/SemaObjC/access-property-getter.m
@@ -0,0 +1,35 @@
+// RUN: clang-cc -verify %s
+
+@protocol NSObject
+- (oneway void)release;
+@end
+
+@protocol XCOutputStreams <NSObject>
+@end
+
+
+@interface XCWorkQueueCommandInvocation
+{
+ id <XCOutputStreams> _outputStream;
+}
+@end
+
+@interface XCWorkQueueCommandSubprocessInvocation : XCWorkQueueCommandInvocation
+@end
+
+@interface XCWorkQueueCommandLocalSubprocessInvocation : XCWorkQueueCommandSubprocessInvocation
+@end
+
+@interface XCWorkQueueCommandDistributedSubprocessInvocation : XCWorkQueueCommandSubprocessInvocation
+@end
+
+@interface XCWorkQueueCommandCacheFetchInvocation : XCWorkQueueCommandSubprocessInvocation
+
+@end
+
+@implementation XCWorkQueueCommandCacheFetchInvocation
+- (id)harvestPredictivelyProcessedOutputFiles
+{
+ _outputStream.release;
+}
+@end
diff --git a/test/SemaObjC/alias-test-1.m b/test/SemaObjC/alias-test-1.m
new file mode 100644
index 000000000000..39358cd62a6c
--- /dev/null
+++ b/test/SemaObjC/alias-test-1.m
@@ -0,0 +1,31 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@compatibility_alias alias4 foo; // expected-warning {{cannot find interface declaration for 'foo'}}
+
+@class class2; // expected-note {{previous declaration is here}}
+@class class3;
+
+typedef int I; // expected-note {{previous declaration is here}}
+
+@compatibility_alias alias1 I; // expected-warning {{cannot find interface declaration for 'I'}}
+
+@compatibility_alias alias class2;
+@compatibility_alias alias class3; // expected-error {{conflicting types for alias 'alias'}}
+
+
+typedef int alias2; // expected-note {{previous declaration is here}}
+@compatibility_alias alias2 class3; // expected-error {{conflicting types for alias 'alias2'}}
+
+alias *p;
+class2 *p2;
+
+int foo ()
+{
+
+ if (p == p2) {
+ int alias = 1;
+ }
+
+ alias *p3;
+ return p3 == p2;
+}
diff --git a/test/SemaObjC/alias-test-2.m b/test/SemaObjC/alias-test-2.m
new file mode 100644
index 000000000000..e0baf4e4d374
--- /dev/null
+++ b/test/SemaObjC/alias-test-2.m
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Note: GCC doesn't produce any of the following errors.
+@interface Super @end // expected-note {{previous definition is here}}
+
+@interface MyWpModule @end // expected-note {{previous definition is here}}
+
+@compatibility_alias MyAlias MyWpModule;
+
+@compatibility_alias AliasForSuper Super;
+
+@interface MyAlias : AliasForSuper // expected-error {{duplicate interface definition for class 'MyWpModule'}}
+@end
+
+@implementation MyAlias : AliasForSuper // expected-error {{conflicting super class name 'Super'}}
+@end
+
diff --git a/test/SemaObjC/argument-checking.m b/test/SemaObjC/argument-checking.m
new file mode 100644
index 000000000000..1b6c10d29c6b
--- /dev/null
+++ b/test/SemaObjC/argument-checking.m
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+
+struct S { int a; };
+
+extern int charStarFunc(char *);
+extern int charFunc(char);
+
+@interface Test
++alloc;
+-(int)charStarMeth:(char *)s;
+-structMeth:(struct S)s;
+-structMeth:(struct S)s :(struct S)s2;
+@end
+
+void test() {
+ id obj = [Test alloc];
+ struct S sInst;
+
+ charStarFunc(1); // expected-warning {{incompatible integer to pointer conversion passing 'int', expected 'char *'}}
+ charFunc("abc"); // expected-warning {{incompatible pointer to integer conversion passing 'char [4]', expected 'char'}}
+
+ [obj charStarMeth:1]; // expected-warning {{incompatible integer to pointer conversion sending 'int'}}
+ [obj structMeth:1]; // expected-error {{incompatible type sending 'int'}}
+ [obj structMeth:sInst :1]; // expected-error {{incompatible type sending 'int'}}
+}
diff --git a/test/SemaObjC/at-defs.m b/test/SemaObjC/at-defs.m
new file mode 100644
index 000000000000..78ce63cd5299
--- /dev/null
+++ b/test/SemaObjC/at-defs.m
@@ -0,0 +1,29 @@
+// RUN: clang-cc -triple i386-unknown-unknown %s -fsyntax-only
+
+@interface Test {
+ double a;
+}
+@end
+@implementation Test
+@end
+@interface TestObject : Test {
+@public
+ float bar;
+ int foo;
+}
+@end
+@implementation TestObject
+@end
+struct wibble {
+ @defs(TestObject)
+};
+
+
+int main(void)
+{
+ TestObject * a = (id)malloc(100);
+ a->foo = 12;
+ printf("12: %d\n", ((struct wibble*)a)->foo);
+ printf("%d: %d\n", ((char*)&(((struct wibble*)a)->foo)) - (char*)a, ((char*)&(a->foo)) - (char*)a);
+ return 0;
+}
diff --git a/test/SemaObjC/attr-cleanup.m b/test/SemaObjC/attr-cleanup.m
new file mode 100644
index 000000000000..f4d057b2b830
--- /dev/null
+++ b/test/SemaObjC/attr-cleanup.m
@@ -0,0 +1,10 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+@class NSString;
+
+void c1(id *a);
+
+void t1()
+{
+ NSString *s __attribute((cleanup(c1)));
+}
diff --git a/test/SemaObjC/attr-deprecated.m b/test/SemaObjC/attr-deprecated.m
new file mode 100644
index 000000000000..e385a977f55b
--- /dev/null
+++ b/test/SemaObjC/attr-deprecated.m
@@ -0,0 +1,99 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+@interface A {
+ int X __attribute__((deprecated));
+}
++ (void)F __attribute__((deprecated));
+- (void)f __attribute__((deprecated));
+@end
+
+@implementation A
++ (void)F __attribute__((deprecated))
+{ // expected-warning {{method attribute can only be specified on method declarations}}
+ [self F]; // no warning, since the caller is also deprecated.
+}
+
+- (void)g
+{
+ X++; // expected-warning{{'X' is deprecated}}
+ self->X++; // expected-warning{{'X' is deprecated}}
+ [self f]; // expected-warning{{'f' is deprecated}}
+}
+
+- (void)f
+{
+ [self f]; // no warning, the caller is deprecated in its interface.
+}
+@end
+
+@interface B: A
+@end
+
+@implementation B
++ (void)G
+{
+ [super F]; // expected-warning{{'F' is deprecated}}
+}
+
+- (void)g
+{
+ [super f]; // // expected-warning{{'f' is deprecated}}
+}
+@end
+
+@protocol P
+- (void)p __attribute__((deprecated));
+@end
+
+void t1(A *a)
+{
+ [A F]; // expected-warning{{'F' is deprecated}}
+ [a f]; // expected-warning{{'f' is deprecated}}
+}
+
+void t2(id a)
+{
+ [a f];
+}
+
+void t3(A<P>* a)
+{
+ [a f]; // expected-warning{{'f' is deprecated}}
+ [a p]; // expected-warning{{'p' is deprecated}}
+}
+
+void t4(Class c)
+{
+ [c F];
+}
+
+
+
+@interface Bar
+
+@property (assign, setter = MySetter:) int FooBar __attribute__ ((deprecated));
+- (void) MySetter : (int) value;
+@end
+
+int t5() {
+ Bar *f;
+ f.FooBar = 1; // expected-warning {{warning: 'FooBar' is deprecated}}
+ return f.FooBar; // expected-warning {{warning: 'FooBar' is deprecated}}
+}
+
+
+__attribute ((deprecated))
+@interface DEPRECATED {
+ @public int ivar;
+}
+- (int) instancemethod;
+@property int prop;
+@end
+
+@interface DEPRECATED (Category) // expected-warning {{warning: 'DEPRECATED' is deprecated}}
+@end
+
+@interface NS : DEPRECATED // expected-warning {{warning: 'DEPRECATED' is deprecated}}
+@end
+
+
diff --git a/test/SemaObjC/attr-objc-exception.m b/test/SemaObjC/attr-objc-exception.m
new file mode 100644
index 000000000000..3efb8cfa40ce
--- /dev/null
+++ b/test/SemaObjC/attr-objc-exception.m
@@ -0,0 +1,16 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+__attribute__((__objc_exception__))
+@interface NSException {
+ int x;
+}
+
+@end
+
+
+__attribute__((__objc_exception__)) // expected-error {{attribute may only be applied to an Objective-C interface}}
+int X;
+
+__attribute__((__objc_exception__)) // expected-error {{attribute may only be applied to an Objective-C interface}}
+void foo();
+
diff --git a/test/SemaObjC/attr-objc-gc.m b/test/SemaObjC/attr-objc-gc.m
new file mode 100644
index 000000000000..20da639c3cb9
--- /dev/null
+++ b/test/SemaObjC/attr-objc-gc.m
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+static id __attribute((objc_gc(weak))) a;
+static id __attribute((objc_gc(strong))) b;
+
+static id __attribute((objc_gc())) c; // expected-error{{'objc_gc' attribute requires parameter 1 to be a string}}
+static id __attribute((objc_gc(123))) d; // expected-error{{'objc_gc' attribute requires parameter 1 to be a string}}
+static id __attribute((objc_gc(foo, 456))) e; // expected-error{{attribute requires 1 argument(s)}}
+static id __attribute((objc_gc(hello))) f; // expected-warning{{'objc_gc' attribute argument not supported: 'hello'}}
diff --git a/test/SemaObjC/bad-receiver-1.m b/test/SemaObjC/bad-receiver-1.m
new file mode 100644
index 000000000000..64ff3d199314
--- /dev/null
+++ b/test/SemaObjC/bad-receiver-1.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface I
+- (id) retain;
+@end
+
+void __raiseExc1() {
+ [objc_lookUpClass("NSString") retain]; // expected-warning {{receiver type 'int' is not 'id'}} \
+ expected-warning {{method '-retain' not found}}
+}
+
+typedef const struct __CFString * CFStringRef;
+
+void func() {
+ CFStringRef obj;
+
+ [obj self]; // expected-warning {{receiver type 'CFStringRef' (aka 'struct __CFString const *') is not 'id'}} \\
+ expected-warning {{method '-self' not found}}
+}
diff --git a/test/SemaObjC/block-attr.m b/test/SemaObjC/block-attr.m
new file mode 100644
index 000000000000..d67fd3543548
--- /dev/null
+++ b/test/SemaObjC/block-attr.m
@@ -0,0 +1,9 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -fobjc-gc-only %s
+
+@interface Thing {}
+
+@property void(^someBlock)(void); // expected-warning {{'copy' attribute must be specified for the block property}}
+@property(copy) void(^OK)(void);
+
+
+@end
diff --git a/test/SemaObjC/block-ivar.m b/test/SemaObjC/block-ivar.m
new file mode 100644
index 000000000000..231c9a23f8ad
--- /dev/null
+++ b/test/SemaObjC/block-ivar.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fsyntax-only -verify %s -fblocks
+
+@interface NSObject {
+ struct objc_object *isa;
+}
+@end
+@interface Foo : NSObject {
+ int _prop;
+}
+@end
+
+@implementation Foo
+- (int)doSomething {
+ int (^blk)(void) = ^{ return _prop; };
+ return blk();
+}
+
+@end
+
diff --git a/test/SemaObjC/blocks.m b/test/SemaObjC/blocks.m
new file mode 100644
index 000000000000..baadbde3e040
--- /dev/null
+++ b/test/SemaObjC/blocks.m
@@ -0,0 +1,46 @@
+// RUN: clang-cc -fsyntax-only -verify -fblocks %s
+@protocol NSObject;
+
+void bar(id(^)(void));
+void foo(id <NSObject>(^objectCreationBlock)(void)) {
+ return bar(objectCreationBlock);
+}
+
+void bar2(id(*)(void));
+void foo2(id <NSObject>(*objectCreationBlock)(void)) {
+ return bar2(objectCreationBlock);
+}
+
+void bar3(id(*)());
+void foo3(id (*objectCreationBlock)(int)) {
+ return bar3(objectCreationBlock);
+}
+
+void bar4(id(^)());
+void foo4(id (^objectCreationBlock)(int)) {
+ return bar4(objectCreationBlock);
+}
+
+void bar5(id(^)(void));
+void foo5(id (^objectCreationBlock)(int)) {
+ return bar5(objectCreationBlock); // expected-error {{incompatible block pointer types passing 'id (^)(int)', expected 'id (^)(void)'}}
+}
+
+void bar6(id(^)(int));
+void foo6(id (^objectCreationBlock)()) {
+ return bar6(objectCreationBlock); // expected-error {{incompatible block pointer types passing 'id (^)()', expected 'id (^)(int)'}}
+}
+
+void foo7(id (^x)(int)) {
+ if (x) { }
+}
+
+@interface itf
+@end
+
+void foo8() {
+ void *P = ^(itf x) {}; // expected-error {{Objective-C interface type 'itf' cannot be passed by value}}
+ P = ^itf(int x) {}; // expected-error {{Objective-C interface type 'itf' cannot be returned by value}}
+ P = ^itf() {}; // expected-error {{Objective-C interface type 'itf' cannot be returned by value}}
+ P = ^itf{}; // expected-error {{Objective-C interface type 'itf' cannot be returned by value}}
+}
diff --git a/test/SemaObjC/call-super-2.m b/test/SemaObjC/call-super-2.m
new file mode 100644
index 000000000000..92bec27c6783
--- /dev/null
+++ b/test/SemaObjC/call-super-2.m
@@ -0,0 +1,98 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+#include <stddef.h>
+
+typedef struct objc_object *id;
+id objc_getClass(const char *s);
+
+@interface Object
+@end
+
+@protocol Func
++ (int) class_func0;
+- (int) instance_func0;
+@end
+
+@interface Derived: Object
++ (int) class_func1;
++ (int) class_func2;
++ (int) class_func3;
++ (int) class_func4;
++ (int) class_func5;
++ (int) class_func6;
++ (int) class_func7;
+- (int) instance_func1;
+- (int) instance_func2;
+- (int) instance_func3;
+- (int) instance_func4;
+- (int) instance_func5;
+- (int) instance_func6;
+- (int) instance_func7;
+@end
+
+@implementation Derived
++ (int) class_func1
+{
+ int i = (size_t)[self class_func0]; // expected-warning {{method '-class_func0' not found (return type defaults to 'id')}}
+ return i + (size_t)[super class_func0]; // expected-warning {{method '+class_func0' not found (return type defaults to 'id')}}
+}
++ (int) class_func2
+{
+ int i = [(id <Func>)self class_func0];
+ i += [(id <Func>)super class_func0]; // expected-error {{cannot cast 'super' (it isn't an expression)}}
+ i += [(Class <Func>)self class_func0]; // expected-error {{protocol qualified 'Class' is unsupported}}
+ return i + [(Class <Func>)super class_func0]; // expected-error {{protocol qualified 'Class' is unsupported}} // expected-error {{cannot cast 'super' (it isn't an expression)}}
+}
++ (int) class_func3
+{
+ return [(Object <Func> *)super class_func0]; // expected-error {{cannot cast 'super' (it isn't an expression)}}
+}
++ (int) class_func4
+{
+ return [(Derived <Func> *)super class_func0]; // expected-error {{cannot cast 'super' (it isn't an expression)}}
+}
++ (int) class_func5
+{
+ int i = (size_t)[Derived class_func0]; // expected-warning {{method '+class_func0' not found (return type defaults to 'id')}}
+ return i + (size_t)[Object class_func0]; // expected-warning {{method '+class_func0' not found (return type defaults to 'id')}}
+}
++ (int) class_func6
+{
+ return (size_t)[objc_getClass("Object") class_func1]; // GCC warns about this
+}
++ (int) class_func7
+{
+ return [objc_getClass("Derived") class_func1];
+}
+- (int) instance_func1
+{
+ int i = (size_t)[self instance_func0]; // expected-warning {{method '-instance_func0' not found (return type defaults to 'id'))}}
+ return i + (size_t)[super instance_func0]; // expected-warning {{method '-instance_func0' not found (return type defaults to 'id')}}
+}
+- (int) instance_func2
+{
+ return [(id <Func>)super instance_func0]; // expected-error {{cannot cast 'super' (it isn't an expression)}}
+}
+- (int) instance_func3
+{
+ return [(Object <Func> *)super instance_func0]; // expected-error {{cannot cast 'super' (it isn't an expression)}}
+}
+- (int) instance_func4
+{
+ return [(Derived <Func> *)super instance_func0]; // expected-error {{cannot cast 'super' (it isn't an expression)}}
+}
+- (int) instance_func5
+{
+ int i = (size_t)[Derived instance_func1]; // expected-warning {{method '+instance_func1' not found (return type defaults to 'id')}}
+ return i + (size_t)[Object instance_func1]; // expected-warning {{method '+instance_func1' not found (return type defaults to 'id')}}
+}
+- (int) instance_func6
+{
+ return (size_t)[objc_getClass("Object") class_func1];
+}
+- (int) instance_func7
+{
+ return [objc_getClass("Derived") class_func1];
+}
+@end
+
diff --git a/test/SemaObjC/catch-stmt.m b/test/SemaObjC/catch-stmt.m
new file mode 100644
index 000000000000..6dcbcdebfba4
--- /dev/null
+++ b/test/SemaObjC/catch-stmt.m
@@ -0,0 +1,13 @@
+// RUN: clang-cc -verify %s
+
+@protocol P;
+
+void f() {
+ @try {
+ } @catch (void a) { // expected-error{{@catch parameter is not a pointer to an interface type}}
+ } @catch (int) { // expected-error{{@catch parameter is not a pointer to an interface type}}
+ } @catch (int *b) { // expected-error{{@catch parameter is not a pointer to an interface type}}
+ } @catch (id <P> c) { // expected-error{{illegal qualifiers on @catch parameter}}
+ }
+}
+
diff --git a/test/SemaObjC/category-1.m b/test/SemaObjC/category-1.m
new file mode 100644
index 000000000000..6ae775848e78
--- /dev/null
+++ b/test/SemaObjC/category-1.m
@@ -0,0 +1,56 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface MyClass1 @end
+
+@protocol p1,p2,p3;
+
+@interface MyClass1 (Category1) <p1> // expected-warning {{cannot find protocol definition for 'p1'}} expected-note {{previous definition is here}}
+@end
+
+@interface MyClass1 (Category1) // expected-warning {{duplicate definition of category 'Category1' on interface 'MyClass1'}}
+@end
+
+@interface MyClass1 (Category3)
+@end
+
+@interface MyClass1 (Category4) @end // expected-note {{previous definition is here}}
+@interface MyClass1 (Category5) @end
+@interface MyClass1 (Category6) @end
+@interface MyClass1 (Category7) @end // expected-note {{previous definition is here}}
+@interface MyClass1 (Category8) @end // expected-note {{previous definition is here}}
+
+
+@interface MyClass1 (Category4) @end // expected-warning {{duplicate definition of category 'Category4' on interface 'MyClass1'}}
+@interface MyClass1 (Category7) @end // expected-warning {{duplicate definition of category 'Category7' on interface 'MyClass1'}}
+@interface MyClass1 (Category8) @end // expected-warning {{duplicate definition of category 'Category8' on interface 'MyClass1'}}
+
+
+@protocol p3 @end
+
+@interface MyClass1 (Category) <p2, p3> @end // expected-warning {{cannot find protocol definition for 'p2'}}
+
+@interface MyClass (Category) @end // expected-error {{cannot find interface declaration for 'MyClass'}}
+
+@class MyClass2;
+
+@interface MyClass2 (Category) @end // expected-error {{cannot find interface declaration for 'MyClass2'}}
+
+@interface XCRemoteComputerManager
+@end
+
+@interface XCRemoteComputerManager()
+@end
+
+@interface XCRemoteComputerManager()
+@end
+
+@interface XCRemoteComputerManager(x) // expected-note {{previous definition is here}}
+@end
+
+@interface XCRemoteComputerManager(x) // expected-warning {{duplicate definition of category 'x' on interface 'XCRemoteComputerManager'}}
+@end
+
+@implementation XCRemoteComputerManager
+@end
+
+
diff --git a/test/SemaObjC/category-method-lookup-2.m b/test/SemaObjC/category-method-lookup-2.m
new file mode 100644
index 000000000000..76048cc2f74c
--- /dev/null
+++ b/test/SemaObjC/category-method-lookup-2.m
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef struct objc_class *Class;
+@interface NSObject
+- (Class)class;
+@end
+@interface Bar : NSObject
+@end
+@interface Bar (Cat)
+@end
+
+// NOTE: No class implementation for Bar precedes this category definition.
+@implementation Bar (Cat)
+
+// private method.
++ classMethod { return self; }
+
+- instanceMethod {
+ [[self class] classMethod];
+}
+
+@end
diff --git a/test/SemaObjC/category-method-lookup.m b/test/SemaObjC/category-method-lookup.m
new file mode 100644
index 000000000000..bda465783b5d
--- /dev/null
+++ b/test/SemaObjC/category-method-lookup.m
@@ -0,0 +1,31 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface Foo
+@end
+@implementation Foo
+@end
+
+@implementation Foo(Whatever)
++(float)returnsFloat { return 7.0; }
+@end
+
+@interface Foo (MoreStuff)
++(int)returnsInt;
+@end
+
+@implementation Foo (MoreStuff)
++(int)returnsInt {
+ return 0;
+}
+
++(void)returnsNothing {
+}
+-(int)callsReturnsInt {
+ float f = [Foo returnsFloat]; // GCC doesn't find this method (which is a bug IMHO).
+ [Foo returnsNothing];
+ return [Foo returnsInt];
+}
+@end
+
+int main() {return 0;}
+
diff --git a/test/SemaObjC/check-dup-decl-methods-1.m b/test/SemaObjC/check-dup-decl-methods-1.m
new file mode 100644
index 000000000000..ae0cab0b5d41
--- /dev/null
+++ b/test/SemaObjC/check-dup-decl-methods-1.m
@@ -0,0 +1,38 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface SUPER
+- (int) meth;
++ (int) foobar;
+@end
+
+@interface T @end
+
+@interface class1 : SUPER
+- (int) meth; // expected-note {{previous declaration is here}}
+- (int*) meth; // expected-error {{duplicate declaration of method 'meth'}}
+- (T*) meth1;
+- (T*) meth1;
++ (T*) meth1;
+@end
+
+@interface class1(cat)
+- (int) catm : (char)ch1; // expected-note {{previous declaration is here}}
+- (int) catm1 : (char)ch : (int)i;
+- (int) catm : (char*)ch1; // expected-error {{duplicate declaration of method 'catm:'}}
++ (int) catm1 : (char)ch : (int)i;
++ (T*) meth1;
+@end
+
+@interface class1(cat1)
++ (int) catm1 : (char)ch : (int)i; // expected-note {{previous declaration is here}}
++ (T*) meth1; // expected-note {{previous declaration is here}}
++ (int) catm1 : (char)ch : (int*)i; // expected-error {{duplicate declaration of method 'catm1::'}}
++ (T**) meth1; // expected-error {{duplicate declaration of method 'meth1'}}
++ (int) foobar;
+@end
+
+@protocol P
+- (int) meth; // expected-note {{previous declaration is here}}
+- (int*) meth; // expected-error {{duplicate declaration of method 'meth'}}
+@end
+
diff --git a/test/SemaObjC/check-dup-objc-decls-1.m b/test/SemaObjC/check-dup-objc-decls-1.m
new file mode 100644
index 000000000000..1dfaf0905083
--- /dev/null
+++ b/test/SemaObjC/check-dup-objc-decls-1.m
@@ -0,0 +1,39 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface Foo // expected-note {{previous definition is here}}
+@end
+
+float Foo; // expected-error {{redefinition of 'Foo' as different kind of symbol}}
+
+@class Bar; // expected-note {{previous definition is here}}
+
+typedef int Bar; // expected-error {{redefinition of 'Bar' as different kind of symbol}}
+
+@implementation FooBar // expected-warning {{cannot find interface declaration for 'FooBar'}}
+@end
+
+
+typedef int OBJECT; // expected-note {{previous definition is here}}
+
+@class OBJECT ; // expected-error {{redefinition of 'OBJECT' as different kind of symbol}}
+
+
+typedef int Gorf; // expected-note {{previous definition is here}}
+
+@interface Gorf @end // expected-error {{redefinition of 'Gorf' as different kind of symbol}} expected-note {{previous definition is here}}
+
+void Gorf() // expected-error {{redefinition of 'Gorf' as different kind of symbol}}
+{
+ int Bar, Foo, FooBar;
+}
+
+@protocol P -im1; @end
+@protocol Q -im2; @end
+@interface A<P> @end // expected-note {{previous definition is here}}
+@interface A<Q> @end // expected-error {{duplicate interface definition for class 'A'}}
+
+@protocol PP<P> @end // expected-note {{previous definition is here}}
+@protocol PP<Q> @end // expected-warning {{duplicate protocol definition of 'PP'}}
+
+@interface A(Cat)<P> @end // expected-note {{previous definition is here}}
+@interface A(Cat)<Q> @end // expected-warning {{duplicate definition of category 'Cat' on interface 'A'}}
diff --git a/test/SemaObjC/class-bitfield.m b/test/SemaObjC/class-bitfield.m
new file mode 100644
index 000000000000..01b532464c28
--- /dev/null
+++ b/test/SemaObjC/class-bitfield.m
@@ -0,0 +1,37 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+@interface X
+{
+ int a : -1; // expected-error{{bit-field 'a' has negative width}}
+
+ // rdar://6081627
+ int b : 33; // expected-error{{size of bit-field 'b' exceeds size of its type (32 bits)}}
+
+ int c : (1 + 0.25); // expected-error{{expression is not an integer constant expression}}
+ int d : (int)(1 + 0.25);
+
+ // rdar://6138816
+ int e : 0; // expected-error {{bit-field 'e' has zero width}}
+}
+@end
+
+@interface Base {
+ int i;
+}
+@end
+
+@interface WithBitfields: Base {
+ void *isa; // expected-note {{previous definition is here}}
+ unsigned a: 5;
+ signed b: 4;
+ int c: 5; // expected-note {{previous definition is here}}
+}
+@end
+
+@implementation WithBitfields {
+ char *isa; // expected-error {{instance variable 'isa' has conflicting type: 'char *' vs 'void *'}}
+ unsigned a: 5;
+ signed b: 4;
+ int c: 3; // expected-error {{instance variable 'c' has conflicting bitfield width}}
+}
+@end
diff --git a/test/SemaObjC/class-conforming-protocol-1.m b/test/SemaObjC/class-conforming-protocol-1.m
new file mode 100644
index 000000000000..a9712b23a6a8
--- /dev/null
+++ b/test/SemaObjC/class-conforming-protocol-1.m
@@ -0,0 +1,21 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@protocol P1 @end
+@protocol P2 @end
+@protocol P3 @end
+
+@interface INTF
+- (INTF*) METH1; // expected-note {{previous declaration is here}}
+- (INTF<P1>*) METH1; // expected-error {{duplicate declaration of method 'METH1'}}
+
+- (INTF<P1,P2>*) METH2;
+- (INTF<P2,P1>*) METH2; // expected-note {{previous declaration is here}}
+- (INTF<P2,P1,P3>*) METH2; // expected-error {{duplicate declaration of method 'METH2'}}
+
+- (INTF<P2,P1,P3>*) METH3;
+- (INTF<P3,P1,P2, P3>*) METH3;
+
+@end
+
+INTF<P2,P1,P3>* p1;
+
diff --git a/test/SemaObjC/class-conforming-protocol-2.m b/test/SemaObjC/class-conforming-protocol-2.m
new file mode 100644
index 000000000000..7b218bdbd803
--- /dev/null
+++ b/test/SemaObjC/class-conforming-protocol-2.m
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@protocol NSWindowDelegate @end
+
+@interface NSWindow
+- (void)setDelegate:(id <NSWindowDelegate>)anObject;
+- (id <NSWindowDelegate>) delegate;
+@end
+
+@protocol IBStringsTableWindowDelegate <NSWindowDelegate>
+@end
+
+@interface IBStringsTableWindow : NSWindow {}
+@end
+
+@implementation IBStringsTableWindow
+- (void)setDelegate:(id <IBStringsTableWindowDelegate>)delegate {
+}
+- (id <IBStringsTableWindowDelegate>)delegate {
+ return 0;
+}
+@end
diff --git a/test/SemaObjC/class-def-test-1.m b/test/SemaObjC/class-def-test-1.m
new file mode 100644
index 000000000000..da8a3267662f
--- /dev/null
+++ b/test/SemaObjC/class-def-test-1.m
@@ -0,0 +1,33 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@protocol SUPER;
+
+@interface SUPER <SUPER> @end // expected-warning {{cannot find protocol definition for 'SUPER'}}
+
+typedef int INTF; // expected-note {{previous definition is here}}
+
+@interface INTF @end // expected-error {{redefinition of 'INTF' as different kind of symbol}}
+
+@interface OBJECT @end // expected-note {{previous definition is here}}
+
+@interface INTF1 : OBJECT @end // expected-note {{previous definition is here}}
+
+@interface INTF1 : OBJECT @end // expected-error {{duplicate interface definition for class 'INTF1'}}
+
+typedef int OBJECT; // expected-error {{redefinition of 'OBJECT' as different kind of symbol}}
+
+typedef int OBJECT2; // expected-note {{previous definition is here}}
+@interface INTF2 : OBJECT2 @end // expected-error {{redefinition of 'OBJECT2' as different kind of symbol}}
+
+
+@protocol PROTO;
+
+@interface INTF3 : PROTO @end // expected-error {{cannot find interface declaration for 'PROTO', superclass of 'INTF3'}}
+
+// Make sure we allow the following (for GCC compatibility).
+@interface NSObject @end
+typedef NSObject TD_NSObject;
+@interface XCElementUnit : TD_NSObject {}
+@end
+
+
diff --git a/test/SemaObjC/class-extension-dup-methods.m b/test/SemaObjC/class-extension-dup-methods.m
new file mode 100644
index 000000000000..f50b293ade36
--- /dev/null
+++ b/test/SemaObjC/class-extension-dup-methods.m
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface Foo
+- (int) garf; // expected-note {{ previous declaration is here}}
+- (int) OK;
++ (int) cgarf; // expected-note {{ previous declaration is here}}
+- (int) InstMeth;
+@end
+
+@interface Foo()
+- (void) garf; // expected-error {{duplicate declaration of method 'garf'}}
++ (void) cgarf; // expected-error {{duplicate declaration of method 'cgarf'}}
++ (int) InstMeth;
+- (int) OK;
+@end
diff --git a/test/SemaObjC/class-impl-1.m b/test/SemaObjC/class-impl-1.m
new file mode 100644
index 000000000000..5a67bef3d605
--- /dev/null
+++ b/test/SemaObjC/class-impl-1.m
@@ -0,0 +1,40 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef int INTF3; // expected-note {{previous definition is here}}
+
+@interface SUPER @end // expected-note {{previous definition is here}}
+
+@interface OBJECT @end
+
+@interface INTF : OBJECT
+@end
+
+@implementation INTF @end
+
+@implementation INTF // expected-error {{reimplementation of class 'INTF'}}
+@end
+
+
+@interface INTF1 : OBJECT
+@end
+
+@implementation INTF1 : SUPER // expected-error {{conflicting super class name 'SUPER'}}
+@end
+
+@interface INTF2
+@end
+
+@implementation INTF2 : SUPR // expected-error {{cannot find interface declaration for 'SUPR', superclass of 'INTF2'}}
+@end
+
+@implementation INTF3 @end // expected-error {{redefinition of 'INTF3' as different kind of symbol}}
+
+@implementation INTF4 @end // expected-warning {{cannot find interface declaration for 'INTF4'}}
+
+@class INTF5;
+
+@implementation INTF5 { // expected-warning {{cannot find interface declaration for 'INTF5'}}
+ int x;
+}
+@end
+
diff --git a/test/SemaObjC/class-method-lookup.m b/test/SemaObjC/class-method-lookup.m
new file mode 100644
index 000000000000..cba93825a4e0
--- /dev/null
+++ b/test/SemaObjC/class-method-lookup.m
@@ -0,0 +1,46 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface MyBase
+- (void) rootInstanceMethod;
+@end
+
+@interface MyIntermediate: MyBase
+@end
+
+@interface MyDerived: MyIntermediate
+- (void) instanceMethod;
++ (void) classMethod;
+@end
+
+@implementation MyDerived
+- (void) instanceMethod {
+}
+
++ (void) classMethod { /* If a class method is not found, the root */
+ [self rootInstanceMethod]; /* class is searched for an instance method */
+ [MyIntermediate rootInstanceMethod]; /* with the same name. */
+
+ [self instanceMethod];// expected-warning {{'-instanceMethod' not found (return type defaults to 'id')}}
+ [MyDerived instanceMethod];// expected-warning {{'+instanceMethod' not found (return type defaults to 'id')}}
+}
+@end
+
+@interface Object @end
+
+@interface Class1
+- (void)setWindow:(Object *)wdw;
+@end
+
+@interface Class2
+- (void)setWindow:(Class1 *)window;
+@end
+
+#define nil (void*)0
+
+id foo(void) {
+ Object *obj;
+ id obj2 = obj;
+ [obj setWindow:nil]; // expected-warning {{Object may not respond to 'setWindow:'}}
+
+ return obj;
+}
diff --git a/test/SemaObjC/class-method-self.m b/test/SemaObjC/class-method-self.m
new file mode 100644
index 000000000000..d36bc8cbc91b
--- /dev/null
+++ b/test/SemaObjC/class-method-self.m
@@ -0,0 +1,26 @@
+// RUN: clang-cc -verify %s
+
+typedef struct objc_class *Class;
+@interface XX
+
+- (void)addObserver:(XX*)o;
+
+@end
+
+@interface YY
+
++ (void)classMethod;
+
+@end
+
+@implementation YY
+
+static XX *obj;
+
++ (void)classMethod {
+ [obj addObserver:self];
+ Class whatever;
+ [obj addObserver:whatever]; // GCC warns about this.
+}
+@end
+
diff --git a/test/SemaObjC/class-property-access.m b/test/SemaObjC/class-property-access.m
new file mode 100644
index 000000000000..663b87d2ff18
--- /dev/null
+++ b/test/SemaObjC/class-property-access.m
@@ -0,0 +1,12 @@
+// RUN: clang -fsyntax-only -verify %s
+
+@interface Test {}
++ (Test*)one;
+- (int)two;
+@end
+
+int main ()
+{
+ return Test.one.two;
+}
+
diff --git a/test/SemaObjC/class-proto-1.m b/test/SemaObjC/class-proto-1.m
new file mode 100644
index 000000000000..8f0f3d8826c2
--- /dev/null
+++ b/test/SemaObjC/class-proto-1.m
@@ -0,0 +1,36 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface INTF1 @end
+
+@protocol p1,p2,p3;
+
+@protocol p1;
+
+@protocol PROTO1
+- (INTF1<p1>*) meth;
+@end
+
+@protocol p1 @end
+
+@interface I1 <p1> @end
+
+@interface E1 <p2> @end // expected-warning {{cannot find protocol definition for 'p2'}}
+
+@protocol p2 @end
+
+
+@interface I2 <p1,p2> @end
+
+@interface E2 <p1,p2,p3> @end // expected-warning {{cannot find protocol definition for 'p3'}}
+
+@class U1, U2;
+
+@interface E3 : U1 @end // expected-error {{cannot find interface declaration for 'U1', superclass of 'E3'}}
+
+
+@interface I3 : E3 @end
+
+@interface U2 @end
+
+@interface I4 : U2 <p1,p2>
+@end
diff --git a/test/SemaObjC/cocoa-pth.m b/test/SemaObjC/cocoa-pth.m
new file mode 100644
index 000000000000..dc806dfb7c09
--- /dev/null
+++ b/test/SemaObjC/cocoa-pth.m
@@ -0,0 +1,7 @@
+// RUN: clang-cc -mcpu=pentium4 -emit-pth -o %t %s &&
+// RUN: clang-cc -mcpu=pentium4 -token-cache %t %s &&
+// RUN: clang-cc -mcpu=pentium4 -token-cache %t %s -E %s -o /dev/null
+#ifdef __APPLE__
+#include <Cocoa/Cocoa.h>
+#endif
+
diff --git a/test/SemaObjC/cocoa.m b/test/SemaObjC/cocoa.m
new file mode 100644
index 000000000000..b73b3c4ccd33
--- /dev/null
+++ b/test/SemaObjC/cocoa.m
@@ -0,0 +1,5 @@
+// RUN: clang-cc -mcpu=pentium4 %s -print-stats
+#ifdef __APPLE__
+#include <Cocoa/Cocoa.h>
+#endif
+
diff --git a/test/SemaObjC/compare-qualified-id.m b/test/SemaObjC/compare-qualified-id.m
new file mode 100644
index 000000000000..86845c0358d2
--- /dev/null
+++ b/test/SemaObjC/compare-qualified-id.m
@@ -0,0 +1,33 @@
+// RUN: clang-cc -fsyntax-only -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 NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
+@interface NSObject <NSObject> {} @end
+typedef struct {} NSFastEnumerationState;
+@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; @end
+@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count; @end
+@interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey; @end
+extern NSString * const NSTaskDidTerminateNotification;
+
+@interface XCPropertyExpansionContext : NSObject <NSCopying> {
+ NSMutableDictionary * _propNamesToPropValuesCache;
+} @end
+
+@protocol XCPropertyValues <NSObject, NSCopying>
+- (NSString *)evaluateAsStringInContext:(XCPropertyExpansionContext *)context withNestingState:(const void *)state;
+@end
+
+@implementation XCPropertyExpansionContext
+- (NSString *)expandedValueForProperty:(NSString *)property {
+ id <XCPropertyValues> cachedValueNode = [_propNamesToPropValuesCache objectForKey:property]; // expected-warning {{method '-objectForKey:' not found (return type defaults to 'id')}}
+ if (cachedValueNode == ((void *)0)) { }
+ NSString * expandedValue = [cachedValueNode evaluateAsStringInContext:self withNestingState:((void *)0)];
+ return expandedValue;
+}
+
diff --git a/test/SemaObjC/compatible-protocol-qualified-types.m b/test/SemaObjC/compatible-protocol-qualified-types.m
new file mode 100644
index 000000000000..3c27b5f0d3cd
--- /dev/null
+++ b/test/SemaObjC/compatible-protocol-qualified-types.m
@@ -0,0 +1,75 @@
+// RUN: clang-cc -pedantic -fsyntax-only -verify %s
+typedef signed char BOOL;
+
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+@end
+
+@protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+
+@interface NSObject <NSObject> {}
+@end
+
+typedef float CGFloat;
+
+@interface NSResponder : NSObject <NSCoding> {}
+@end
+
+@protocol XCSelectionSource;
+
+@interface XCSelection : NSResponder {}
+- (NSObject <XCSelectionSource> *) source;
+@end
+
+extern NSString * const XCActiveSelectionLevel;
+
+@interface XCActionManager : NSResponder {}
++defaultActionManager;
+-selectionAtLevel:(NSString *const)s;
+@end
+
+@implementation XDMenuItemsManager // expected-warning {{cannot find interface declaration for 'XDMenuItemsManager'}}
++ (void)initialize {
+ id<XCSelectionSource, NSObject> source =
+ [[[XCActionManager defaultActionManager] selectionAtLevel:XCActiveSelectionLevel] source];
+}
+@end
+
+@protocol NSTextStorageDelegate;
+@class NSNotification;
+
+@interface NSTextStorage : NSObject
+
+- (void)setDelegate:(id <NSTextStorageDelegate>)delegate;
+- (id <NSTextStorageDelegate>)delegate;
+
+@end
+
+@protocol NSTextStorageDelegate <NSObject>
+@optional
+
+- (void)textStorageWillProcessEditing:(NSNotification *)notification;
+- (void)textStorageDidProcessEditing:(NSNotification *)notification;
+
+@end
+
+@interface SKTText : NSObject {
+ @private
+
+
+ NSTextStorage *_contents;
+}
+@end
+
+@implementation SKTText
+
+
+- (NSTextStorage *)contents {
+ [_contents setDelegate:self]; // expected-warning {{incompatible type sending 'SKTText *', expected 'id<NSTextStorageDelegate>'}}
+}
+
+@end
diff --git a/test/SemaObjC/comptypes-1.m b/test/SemaObjC/comptypes-1.m
new file mode 100644
index 000000000000..8717bd09eb84
--- /dev/null
+++ b/test/SemaObjC/comptypes-1.m
@@ -0,0 +1,91 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+
+#define nil (void *)0;
+#define Nil (void *)0;
+
+extern void foo();
+
+@protocol MyProtocol
+- (void) foo;
+@end
+
+@interface MyClass
+@end
+
+@interface MyOtherClass <MyProtocol>
+- (void) foo;
+@end
+
+int main()
+{
+ id obj = nil;
+ id<MyProtocol> obj_p = nil;
+ MyClass *obj_c = nil;
+ MyOtherClass *obj_cp = nil;
+ Class obj_C = Nil;
+
+ /* Assigning to an 'id' variable should never
+ generate a warning. */
+ obj = obj_p; /* Ok */
+ obj = obj_c; /* Ok */
+ obj = obj_cp; /* Ok */
+ obj = obj_C; /* Ok */
+
+ /* Assigning to a 'MyClass *' variable should always generate a
+ warning, unless done from an 'id'. */
+ obj_c = obj; /* Ok */
+ obj_c = obj_cp; // // expected-warning {{incompatible pointer types assigning 'MyOtherClass *', expected 'MyClass *'}}
+ obj_c = obj_C;
+
+ /* Assigning to an 'id<MyProtocol>' variable should generate a
+ warning if done from a 'MyClass *' (which doesn't implement
+ MyProtocol), but not from an 'id' or from a 'MyOtherClass *'
+ (which implements MyProtocol). */
+ obj_p = obj; /* Ok */
+ obj_p = obj_c; // expected-warning {{incompatible type assigning 'MyClass *', expected 'id<MyProtocol>'}}
+ obj_p = obj_cp; /* Ok */
+ obj_p = obj_C; // Ok
+
+ /* Assigning to a 'MyOtherClass *' variable should always generate
+ a warning, unless done from an 'id' or an 'id<MyProtocol>' (since
+ MyOtherClass implements MyProtocol). */
+ obj_cp = obj; /* Ok */
+ obj_cp = obj_c; // expected-warning {{incompatible pointer types assigning 'MyClass *', expected 'MyOtherClass *'}}
+ obj_cp = obj_p; /* Ok */
+ obj_cp = obj_C;
+
+ /* Any comparison involving an 'id' must be without warnings. */
+ if (obj == obj_p) foo() ; /* Ok */ /*Bogus warning here in 2.95.4*/
+ if (obj_p == obj) foo() ; /* Ok */
+ if (obj == obj_c) foo() ; /* Ok */
+ if (obj_c == obj) foo() ; /* Ok */
+ if (obj == obj_cp) foo() ; /* Ok */
+ if (obj_cp == obj) foo() ; /* Ok */
+ if (obj == obj_C) foo() ; /* Ok */
+ if (obj_C == obj) foo() ; /* Ok */
+
+ /* Any comparison between 'MyClass *' and anything which is not an 'id'
+ must generate a warning. */
+ /* FIXME: GCC considers this a warning ("comparison of distinct pointer types"). */
+ /* There is a corresponding FIXME in ASTContext::mergeTypes() */
+ if (obj_p == obj_c) foo() ;
+
+ if (obj_c == obj_cp) foo() ; // expected-warning {{comparison of distinct pointer types ('MyClass *' and 'MyOtherClass *')}}
+ if (obj_cp == obj_c) foo() ; // expected-warning {{comparison of distinct pointer types ('MyOtherClass *' and 'MyClass *')}}
+
+ if (obj_c == obj_C) foo() ;
+ if (obj_C == obj_c) foo() ;
+
+ /* Any comparison between 'MyOtherClass *' (which implements
+ MyProtocol) and an 'id' implementing MyProtocol are Ok. */
+ if (obj_cp == obj_p) foo() ; /* Ok */
+ if (obj_p == obj_cp) foo() ; /* Ok */
+
+
+ if (obj_p == obj_C) foo() ;
+ if (obj_C == obj_p) foo() ;
+ if (obj_cp == obj_C) foo() ;
+ if (obj_C == obj_cp) foo() ;
+
+ return 0;
+}
diff --git a/test/SemaObjC/comptypes-2.m b/test/SemaObjC/comptypes-2.m
new file mode 100644
index 000000000000..c24b67b15ed1
--- /dev/null
+++ b/test/SemaObjC/comptypes-2.m
@@ -0,0 +1,37 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+#define nil (void *)0;
+#define Nil (void *)0;
+
+@protocol MyProtocol
+- (void) foo;
+@end
+
+@interface MyClass
+@end
+
+int main()
+{
+ id obj = nil;
+ id<MyProtocol> obj_p = nil;
+ MyClass *obj_c = nil;
+ Class obj_C = Nil;
+
+ /* All these casts should generate no warnings. */
+
+ obj = (id)obj_p;
+ obj = (id)obj_c;
+ obj = (id)obj_C;
+ obj_c = (MyClass *)obj;
+ obj_c = (MyClass *)obj_p;
+ obj_c = (MyClass *)obj_C;
+ obj_p = (id<MyProtocol>)obj;
+ obj_p = (id<MyProtocol>)obj_c;
+ obj_p = (id<MyProtocol>)obj_C;
+ obj_C = (Class)obj;
+ obj_C = (Class)obj_p;
+ obj_C = (Class)obj_c;
+
+
+ return 0;
+}
diff --git a/test/SemaObjC/comptypes-3.m b/test/SemaObjC/comptypes-3.m
new file mode 100644
index 000000000000..2d8f19d806a7
--- /dev/null
+++ b/test/SemaObjC/comptypes-3.m
@@ -0,0 +1,64 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+#define nil (void *)0;
+
+extern void foo();
+
+@protocol MyProtocolA
+- (void) methodA;
+@end
+
+@protocol MyProtocolB
+- (void) methodB;
+@end
+
+@protocol MyProtocolAB <MyProtocolA, MyProtocolB>
+@end
+
+@protocol MyProtocolAC <MyProtocolA>
+- (void) methodC;
+@end
+
+int main()
+{
+ id<MyProtocolA> obj_a = nil;
+ id<MyProtocolB> obj_b = nil;
+ id<MyProtocolAB> obj_ab = nil;
+ id<MyProtocolAC> obj_ac = nil;
+
+ obj_a = obj_b; // expected-warning {{incompatible type assigning 'id<MyProtocolB>', expected 'id<MyProtocolA>'}}
+ obj_a = obj_ab; /* Ok */
+ obj_a = obj_ac; /* Ok */
+
+ obj_b = obj_a; // expected-warning {{incompatible type assigning 'id<MyProtocolA>', expected 'id<MyProtocolB>'}}
+ obj_b = obj_ab; /* Ok */
+ obj_b = obj_ac; // expected-warning {{incompatible type assigning 'id<MyProtocolAC>', expected 'id<MyProtocolB>'}}
+
+ obj_ab = obj_a; // expected-warning {{incompatible type assigning 'id<MyProtocolA>', expected 'id<MyProtocolAB>'}}
+ obj_ab = obj_b; // expected-warning {{incompatible type assigning 'id<MyProtocolB>', expected 'id<MyProtocolAB>'}}
+ obj_ab = obj_ac; // expected-warning {{incompatible type assigning 'id<MyProtocolAC>', expected 'id<MyProtocolAB>'}}
+
+ obj_ac = obj_a; // expected-warning {{incompatible type assigning 'id<MyProtocolA>', expected 'id<MyProtocolAC>'}}
+ obj_ac = obj_b; // expected-warning {{incompatible type assigning 'id<MyProtocolB>', expected 'id<MyProtocolAC>'}}
+ obj_ac = obj_ab; // expected-warning {{incompatible type assigning 'id<MyProtocolAB>', expected 'id<MyProtocolAC>'}}
+
+ if (obj_a == obj_b) foo (); // expected-warning {{invalid operands to binary expression ('id<MyProtocolA>' and 'id<MyProtocolB>')}}
+ if (obj_b == obj_a) foo (); // expected-warning {{invalid operands to binary expression ('id<MyProtocolB>' and 'id<MyProtocolA>')}}
+
+ if (obj_a == obj_ab) foo (); /* Ok */
+ if (obj_ab == obj_a) foo (); /* Ok */
+
+ if (obj_a == obj_ac) foo (); /* Ok */
+ if (obj_ac == obj_a) foo (); /* Ok */
+
+ if (obj_b == obj_ab) foo (); /* Ok */
+ if (obj_ab == obj_b) foo (); /* Ok */
+
+ if (obj_b == obj_ac) foo (); // expected-warning {{invalid operands to binary expression ('id<MyProtocolB>' and 'id<MyProtocolAC>')}}
+ if (obj_ac == obj_b) foo (); // expected-warning {{invalid operands to binary expression ('id<MyProtocolAC>' and 'id<MyProtocolB>')}}
+
+ if (obj_ab == obj_ac) foo (); // expected-warning {{invalid operands to binary expression ('id<MyProtocolAB>' and 'id<MyProtocolAC>')}}
+ if (obj_ac == obj_ab) foo (); // expected-warning {{invalid operands to binary expression ('id<MyProtocolAC>' and 'id<MyProtocolAB>')}}
+
+ return 0;
+}
diff --git a/test/SemaObjC/comptypes-4.m b/test/SemaObjC/comptypes-4.m
new file mode 100644
index 000000000000..598901148a8a
--- /dev/null
+++ b/test/SemaObjC/comptypes-4.m
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+extern void foo();
+
+@protocol MyProtocol @end
+
+@interface MyClass @end
+
+int main()
+{
+ MyClass <MyProtocol> *obj_p;
+ MyClass *obj_cp;
+
+ obj_cp = obj_p;
+ obj_p = obj_cp;
+
+ if (obj_cp == obj_p)
+ foo();
+
+ if (obj_p == obj_cp)
+ foo();
+
+}
+
+
diff --git a/test/SemaObjC/comptypes-5.m b/test/SemaObjC/comptypes-5.m
new file mode 100644
index 000000000000..afd8a4949ed6
--- /dev/null
+++ b/test/SemaObjC/comptypes-5.m
@@ -0,0 +1,44 @@
+// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+
+#define nil (void *)0;
+
+extern void foo();
+
+@protocol MyProtocol
+- (void) method;
+@end
+
+@interface MyClass
+@end
+
+@interface MyClass (Addition) <MyProtocol>
+- (void) method;
+@end
+
+@interface MyOtherClass : MyClass
+@end
+
+int main()
+{
+ id <MyProtocol> obj_id_p = nil;
+ MyClass *obj_c_cat_p = nil;
+ MyOtherClass *obj_c_super_p = nil;
+ MyOtherClass<MyProtocol> *obj_c_super_p_q = nil;
+ MyClass<MyProtocol> *obj_c_cat_p_q = nil;
+
+ obj_c_cat_p = obj_id_p; // expected-warning {{incompatible type assigning 'id<MyProtocol>', expected 'MyClass *'}}
+ obj_c_super_p = obj_id_p; // expected-warning {{incompatible type assigning 'id<MyProtocol>', expected 'MyOtherClass *'}}
+ obj_id_p = obj_c_cat_p; /* Ok */
+ obj_id_p = obj_c_super_p; /* Ok */
+
+ if (obj_c_cat_p == obj_id_p) foo(); /* Ok */
+ if (obj_c_super_p == obj_id_p) foo() ; /* Ok */
+ if (obj_id_p == obj_c_cat_p) foo(); /* Ok */
+ if (obj_id_p == obj_c_super_p) foo(); /* Ok */
+
+ obj_c_cat_p = obj_c_super_p; // ok.
+ obj_c_cat_p = obj_c_super_p_q; // ok.
+ obj_c_super_p = obj_c_cat_p_q; // expected-warning {{incompatible pointer types}}
+ obj_c_cat_p_q = obj_c_super_p;
+ return 0;
+}
diff --git a/test/SemaObjC/comptypes-6.m b/test/SemaObjC/comptypes-6.m
new file mode 100644
index 000000000000..32176755ef76
--- /dev/null
+++ b/test/SemaObjC/comptypes-6.m
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+
+@interface Derived
+@end
+
+@interface Object @end
+
+extern Object* foo(void);
+
+static Derived *test(void)
+{
+ Derived *m = foo(); // expected-warning {{incompatible pointer types initializing 'Object *', expected 'Derived *'}}
+
+ return m;
+}
+
diff --git a/test/SemaObjC/comptypes-7.m b/test/SemaObjC/comptypes-7.m
new file mode 100644
index 000000000000..faca6937cb74
--- /dev/null
+++ b/test/SemaObjC/comptypes-7.m
@@ -0,0 +1,70 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+
+#define nil (void *)0;
+#define Nil (void *)0;
+
+extern void foo();
+
+@protocol MyProtocol
+- (void) method;
+@end
+
+@interface MyClass
+@end
+
+int main()
+{
+ id obj = nil;
+ id <MyProtocol> obj_p = nil;
+ MyClass *obj_c = nil;
+ Class obj_C = Nil;
+
+ int i = 0;
+ int *j = nil;
+
+ /* These should all generate warnings. */
+
+ obj = i; // expected-warning {{incompatible integer to pointer conversion assigning 'int', expected 'id'}}
+ obj = j; // expected-warning {{incompatible pointer types assigning 'int *', expected 'id'}}
+
+ obj_p = i; // expected-warning {{incompatible integer to pointer conversion assigning 'int', expected 'id<MyProtocol>'}}
+ obj_p = j; // expected-warning {{incompatible type assigning 'int *', expected 'id<MyProtocol>'}}
+
+ obj_c = i; // expected-warning {{incompatible integer to pointer conversion assigning 'int', expected 'MyClass *'}}
+ obj_c = j; // expected-warning {{incompatible pointer types assigning 'int *', expected 'MyClass *'}}
+
+ obj_C = i; // expected-warning {{incompatible integer to pointer conversion assigning 'int', expected 'Class'}}
+ obj_C = j; // expected-warning {{incompatible pointer types assigning 'int *', expected 'Class'}}
+
+ i = obj; // expected-warning {{incompatible pointer to integer conversion assigning 'id', expected 'int'}}
+ i = obj_p; // expected-warning {{incompatible pointer to integer conversion assigning 'id<MyProtocol>', expected 'int'}}
+ i = obj_c; // expected-warning {{incompatible pointer to integer conversion assigning 'MyClass *', expected 'int'}}
+ i = obj_C; // expected-warning {{incompatible pointer to integer conversion assigning 'Class', expected 'int'}}
+
+ j = obj; // expected-warning {{incompatible pointer types assigning 'id', expected 'int *'}}
+ j = obj_p; // expected-warning {{incompatible type assigning 'id<MyProtocol>', expected 'int *'}}
+ j = obj_c; // expected-warning {{incompatible pointer types assigning 'MyClass *', expected 'int *'}}
+ j = obj_C; // expected-warning {{incompatible pointer types assigning 'Class', expected 'int *'}}
+
+ if (obj == i) foo() ; // expected-warning {{comparison between pointer and integer ('id' and 'int')}}
+ if (i == obj) foo() ; // expected-warning {{comparison between pointer and integer ('int' and 'id')}}
+ if (obj == j) foo() ; // expected-warning {{comparison of distinct pointer types ('id' and 'int *')}}
+ if (j == obj) foo() ; // expected-warning {{comparison of distinct pointer types ('int *' and 'id')}}
+
+ if (obj_c == i) foo() ; // expected-warning {{comparison between pointer and integer ('MyClass *' and 'int')}}
+ if (i == obj_c) foo() ; // expected-warning {{comparison between pointer and integer ('int' and 'MyClass *')}}
+ if (obj_c == j) foo() ; // expected-warning {{comparison of distinct pointer types ('MyClass *' and 'int *')}}
+ if (j == obj_c) foo() ; // expected-warning {{comparison of distinct pointer types ('int *' and 'MyClass *')}}
+
+ if (obj_p == i) foo() ; // expected-warning {{comparison between pointer and integer ('id<MyProtocol>' and 'int')}}
+ if (i == obj_p) foo() ; // expected-warning {{comparison between pointer and integer ('int' and 'id<MyProtocol>')}}
+ if (obj_p == j) foo() ; // expected-warning {{comparison of distinct pointer types ('id<MyProtocol>' and 'int *')}}
+ if (j == obj_p) foo() ; // expected-warning {{comparison of distinct pointer types ('int *' and 'id<MyProtocol>')}}
+
+ if (obj_C == i) foo() ; // expected-warning {{comparison between pointer and integer ('Class' and 'int')}}
+ if (i == obj_C) foo() ; // expected-warning {{comparison between pointer and integer ('int' and 'Class')}}
+ if (obj_C == j) foo() ; // expected-warning {{comparison of distinct pointer types ('Class' and 'int *')}}
+ if (j == obj_C) foo() ; // expected-warning {{comparison of distinct pointer types ('int *' and 'Class')}}
+
+ return 0;
+}
diff --git a/test/SemaObjC/comptypes-8.m b/test/SemaObjC/comptypes-8.m
new file mode 100644
index 000000000000..af9267e499f6
--- /dev/null
+++ b/test/SemaObjC/comptypes-8.m
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@protocol MyProtocol
+@end
+
+id<MyProtocol> obj_p = 0;
+
+int main()
+{
+ obj_p = 0;
+}
+
diff --git a/test/SemaObjC/comptypes-9.m b/test/SemaObjC/comptypes-9.m
new file mode 100644
index 000000000000..caa93b49e6f3
--- /dev/null
+++ b/test/SemaObjC/comptypes-9.m
@@ -0,0 +1,86 @@
+// RUN: clang-cc -fsyntax-only %s
+// FIXME: This test case tests the patch applied in: http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20080602/006017.html
+// Eventually that logic should be treated as an extension.
+
+typedef signed char BOOL;
+typedef int NSInteger;
+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 NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+
+@protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+
+@interface NSObject <NSObject> {}
+@end
+
+@class NSArray;
+
+typedef struct {} NSFastEnumerationState;
+
+@protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end
+
+@class NSString;
+
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+- (id)objectAtIndex:(NSUInteger)index;
+@end
+
+typedef unsigned short unichar;
+
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
+@end
+
+@interface NSSimpleCString : NSString
+{}
+
+@end
+
+@interface NSConstantString : NSSimpleCString @end
+
+extern void *_NSConstantStringClassReference;
+
+@interface NSResponder : NSObject <NSCoding> {}
+@end
+
+@class NSDate, NSDictionary, NSError, NSException, NSNotification;
+
+@interface NSWindowController : NSResponder <NSCoding> {}
+@end
+
+@class PBXBuildLog, PBXBuildLogItem, PBXBuildLogContainerItem, XCWorkQueueCommand, XCBuildLogContainerItemMutationState;
+
+@protocol PBXBuildLogContainerItems <NSObject>
+- (PBXBuildLog *)buildLog;
+@end
+
+@interface PBXBuildLogItem : NSObject {}
+- (id <PBXBuildLogContainerItems>)superitem;
+@end
+@interface PBXBuildResultsModule
+@end
+
+@implementation PBXBuildResultsModule
+- (void) revealItems
+{
+ PBXBuildLogItem *objItem;
+ PBXBuildLogItem *superitem = [objItem superitem];
+}
+@end
diff --git a/test/SemaObjC/comptypes-a.m b/test/SemaObjC/comptypes-a.m
new file mode 100644
index 000000000000..936c6dfc5de9
--- /dev/null
+++ b/test/SemaObjC/comptypes-a.m
@@ -0,0 +1,32 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+typedef signed char BOOL;
+typedef int NSInteger;
+
+@class NSString;
+
+@protocol PBXCompletionItem
+- (NSString *) name;
+- (NSInteger)priority;
+@end
+
+extern NSInteger codeAssistantCaseCompareItems(id a, id b, void *context);
+
+NSInteger codeAssistantCaseCompareItems(id<PBXCompletionItem> a, id<PBXCompletionItem> b, void *context)
+{
+}
+
+@interface TedWantsToVerifyObjCDoesTheRightThing
+
+- compareThis:(int)a withThat:(id)b; // expected-note {{previous definition is here}}
+
+@end
+
+@implementation TedWantsToVerifyObjCDoesTheRightThing
+
+- compareThis:(id<PBXCompletionItem>)
+ a // expected-warning {{conflicting parameter types in implementation of 'compareThis:withThat:': 'int' vs 'id<PBXCompletionItem>'}}
+ withThat:(id<PBXCompletionItem>)b {
+ return self;
+}
+
+@end
diff --git a/test/SemaObjC/comptypes-legal.m b/test/SemaObjC/comptypes-legal.m
new file mode 100644
index 000000000000..cd7f89b61d0d
--- /dev/null
+++ b/test/SemaObjC/comptypes-legal.m
@@ -0,0 +1,37 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+
+@protocol NSObject
+@end
+@interface NSObject <NSObject> {
+}
+@end
+@interface NSString : NSObject
+@end
+void __setRetained(id *ivar, id value, NSObject **o) {
+ *ivar = value;
+}
+static NSString *_logProcessPrefix = 0;
+void func() {
+ __setRetained(&_logProcessPrefix, _logProcessPrefix, &_logProcessPrefix);
+}
+@implementation NSObject (ScopeAdditions)
++ (void)setObjectLogProcessPrefix:(NSString *)processPrefix {
+ __setRetained(&_logProcessPrefix, processPrefix, &_logProcessPrefix);
+}
+@end
+
+@class Derived;
+
+NSObject *ExternFunc (NSObject *filePath, NSObject *key);
+typedef id FuncSignature (NSObject *arg1, Derived *arg2);
+
+@interface Derived: NSObject
++ (void)registerFunc:(FuncSignature *)function;
+@end
+
+void foo(void)
+{
+ // GCC currently allows this (it has some fiarly new support for covariant return types and contravariant argument types).
+ // Since registerFunc: expects a Derived object as it's second argument, I don't know why this would be legal.
+ [Derived registerFunc: ExternFunc]; // expected-warning{{incompatible pointer types sending 'NSObject *(NSObject *, NSObject *)', expected 'FuncSignature *'}}
+}
diff --git a/test/SemaObjC/conditional-expr-2.m b/test/SemaObjC/conditional-expr-2.m
new file mode 100644
index 000000000000..08758488c540
--- /dev/null
+++ b/test/SemaObjC/conditional-expr-2.m
@@ -0,0 +1,29 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface A
+@end
+@interface B
+@end
+
+void f0(int cond, A *a, B *b) {
+ // Ensure that we can still send a message to result of incompatible
+ // conditional expression.
+ [ (cond ? a : b) test ]; // expected-warning{{incompatible operand types ('A *' and 'B *')}} expected-warning {{method '-test' not found}}
+}
+
+@interface NSKey @end
+@interface KeySub : NSKey @end
+
+@interface UpdatesList @end
+
+void foo (int i, NSKey *NSKeyValueCoding_NullValue, UpdatesList *nukedUpdatesList)
+{
+ id obj;
+ NSKey *key;
+ KeySub *keysub;
+
+ obj = i ? NSKeyValueCoding_NullValue : nukedUpdatesList; // expected-warning{{incompatible operand types ('NSKey *' and 'UpdatesList *')}}
+ key = i ? NSKeyValueCoding_NullValue : nukedUpdatesList; // expected-warning{{incompatible operand types ('NSKey *' and 'UpdatesList *')}}
+ key = i ? NSKeyValueCoding_NullValue : keysub;
+ keysub = i ? NSKeyValueCoding_NullValue : keysub; // expected-warning{{incompatible pointer types assigning 'NSKey *', expected 'KeySub *'}}
+}
diff --git a/test/SemaObjC/conditional-expr-3.m b/test/SemaObjC/conditional-expr-3.m
new file mode 100644
index 000000000000..31d4834ff0af
--- /dev/null
+++ b/test/SemaObjC/conditional-expr-3.m
@@ -0,0 +1,67 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@protocol P0
+@end
+@protocol P1
+@end
+@protocol P2
+@end
+
+@interface A <P0>
+@end
+
+@interface B : A
+@end
+
+void bar(id x);
+void barP0(id<P0> x);
+void barP1(id<P1> x);
+void barP2(id<P2> x);
+
+void f0(A *a) {
+ id l = a;
+}
+
+void f1(id x, A *a) {
+ id<P0> l = a;
+}
+
+void f2(id<P1> x) {
+ id<P0> l = x; // expected-warning {{incompatible type initializing 'id<P1>', expected 'id<P0>'}}
+}
+
+void f3(A *a) {
+ id<P1> l = a; // expected-warning {{incompatible type initializing 'A *', expected 'id<P1>'}}
+}
+
+void f4(int cond, id x, A *a) {
+ bar(cond ? x : a);
+}
+
+void f5(int cond, A *a, B *b) {
+ bar(cond ? a : b);
+}
+
+void f6(int cond, id x, A *a) {
+ bar(cond ? (id<P0, P1>) x : a);
+}
+
+void f7(int cond, id x, A *a) {
+ bar(cond ? a : (id<P0, P1>) x);
+}
+
+void f8(int cond, id<P0,P1> x0, id<P0,P2> x1) {
+ barP0(cond ? x0 : x1);
+}
+
+void f9(int cond, id<P0,P1> x0, id<P0,P2> x1) {
+ barP1(cond ? x0 : x1);
+}
+
+void f10(int cond, id<P0,P1> x0, id<P0,P2> x1) {
+ barP2(cond ? x0 : x1);
+}
+
+int f11(int cond, A* a, B* b) {
+ return (cond? b : a)->x; // expected-error{{'A' does not have a member named 'x'}}
+}
diff --git a/test/SemaObjC/conditional-expr-4.m b/test/SemaObjC/conditional-expr-4.m
new file mode 100644
index 000000000000..7d50ba60750c
--- /dev/null
+++ b/test/SemaObjC/conditional-expr-4.m
@@ -0,0 +1,78 @@
+// RUN: clang-cc -fsyntax-only %s
+// XFAIL
+// <rdar://problem/6212771>
+
+#define nil ((void*) 0)
+
+@interface A
+@property int x;
+@end
+
+@interface B : A
+@end
+
+// Basic checks...
+id f0(int cond, id a, void *b) {
+ return cond ? a : b;
+}
+A *f0_a(int cond, A *a, void *b) {
+ return cond ? a : b;
+}
+
+id f1(int cond, id a) {
+ return cond ? a : nil;
+}
+A *f1_a(int cond, A *a) {
+ return cond ? a : nil;
+}
+
+// Check interaction with qualified id
+
+@protocol P0 @end
+
+id f2(int cond, id<P0> a, void *b) {
+ return cond ? a : b;
+}
+
+id f3(int cond, id<P0> a) {
+ return cond ? a : nil;
+}
+
+// Check that result actually has correct type.
+
+// Using properties is one way to find the compiler internal type of a
+// conditional expression. Simple assignment doesn't work because if
+// the type is id then it can be implicitly promoted.
+@protocol P1
+@property int x;
+@end
+
+int f5(int cond, id<P1> a, id<P1> b) {
+ // This should result in something with id type, currently. This is
+ // almost certainly wrong and should be fixed.
+ return (cond ? a : b).x; // expected-error {{member reference base type ('id') is not a structure or union}}
+}
+int f5_a(int cond, A *a, A *b) {
+ return (cond ? a : b).x;
+}
+int f5_b(int cond, A *a, B *b) {
+ return (cond ? a : b).x;
+}
+
+int f6(int cond, id<P1> a, void *b) {
+ // This should result in something with id type, currently.
+ return (cond ? a : b).x; // expected-error {{member reference base type ('id') is not a structure or union}}
+}
+
+int f7(int cond, id<P1> a) {
+ return (cond ? a : nil).x;
+}
+
+int f8(int cond, id<P1> a, A *b) {
+ // GCC regards this as a warning (comparison of distinct Objective-C types lacks a cast)
+ return a == b; // expected-error {{invalid operands to binary expression}}
+}
+
+int f9(int cond, id<P1> a, A *b) {
+ return (cond ? a : b).x; // expected-error {{incompatible operand types}}
+}
diff --git a/test/SemaObjC/conditional-expr.m b/test/SemaObjC/conditional-expr.m
new file mode 100644
index 000000000000..ec3613b2aa9b
--- /dev/null
+++ b/test/SemaObjC/conditional-expr.m
@@ -0,0 +1,44 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+@protocol NSObject
+@end
+
+@protocol DTOutputStreams <NSObject>
+@end
+
+@interface DTFilterOutputStream <DTOutputStreams>
+- nextOutputStream;
+@end
+
+@implementation DTFilterOutputStream
+- (id)initWithNextOutputStream:(id <DTOutputStreams>) outputStream {
+ id <DTOutputStreams> nextOutputStream = [self nextOutputStream];
+ self = nextOutputStream;
+ return nextOutputStream ? nextOutputStream : self;
+}
+- nextOutputStream {
+ return self;
+}
+@end
+
+@interface DTFilterOutputStream2
+- nextOutputStream;
+@end
+
+@implementation DTFilterOutputStream2 // expected-warning {{incomplete implementation}} expected-warning {{method definition for 'nextOutputStream' not found}}
+- (id)initWithNextOutputStream:(id <DTOutputStreams>) outputStream {
+ id <DTOutputStreams> nextOutputStream = [self nextOutputStream];
+ // GCC warns about both of these.
+ self = nextOutputStream; // expected-warning {{incompatible type assigning 'id<DTOutputStreams>', expected 'DTFilterOutputStream2 *'}}
+ return nextOutputStream ? nextOutputStream : self;
+}
+@end
+
+// No @interface declaration for DTFilterOutputStream3
+@implementation DTFilterOutputStream3 // expected-warning {{cannot find interface declaration for 'DTFilterOutputStream3'}}
+- (id)initWithNextOutputStream:(id <DTOutputStreams>) outputStream {
+ id <DTOutputStreams> nextOutputStream = [self nextOutputStream]; // expected-warning {{method '-nextOutputStream' not found (return type defaults to 'id')}}
+ // GCC warns about both of these as well (no errors).
+ self = nextOutputStream; // expected-warning {{incompatible type assigning 'id<DTOutputStreams>', expected 'DTFilterOutputStream3 *'}}
+ return nextOutputStream ? nextOutputStream : self;
+}
+@end
diff --git a/test/SemaObjC/conflicting-ivar-test-1.m b/test/SemaObjC/conflicting-ivar-test-1.m
new file mode 100644
index 000000000000..20ed15722477
--- /dev/null
+++ b/test/SemaObjC/conflicting-ivar-test-1.m
@@ -0,0 +1,86 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface INTF
+{
+@public
+ int IVAR; // expected-note {{previous definition is here}}
+}
+@end
+
+@implementation INTF
+{
+@private
+
+ int XIVAR; // expected-error {{conflicting instance variable names: 'XIVAR' vs 'IVAR'}}
+}
+@end
+
+
+
+@interface INTF1
+{
+@public
+ int IVAR;
+ int IVAR1; // expected-error {{inconsistent number of instance variables specified}}
+}
+@end
+
+@implementation INTF1
+{
+@private
+
+ int IVAR;
+}
+@end
+
+
+@interface INTF2
+{
+@public
+ int IVAR;
+}
+@end
+
+@implementation INTF2
+{
+@private
+
+ int IVAR;
+ int IVAR1; // expected-error {{inconsistent number of instance variables specified}}
+}
+@end
+
+
+@interface INTF3
+{
+@public
+ int IVAR; // expected-note {{previous definition is here}}
+}
+@end
+
+@implementation INTF3
+{
+@private
+
+ short IVAR; // expected-error {{instance variable 'IVAR' has conflicting type: 'short' vs 'int'}}
+}
+@end
+
+@implementation INTF4 // expected-warning {{cannot find interface declaration for 'INTF4'}}
+{
+@private
+
+ short IVAR;
+}
+@end
+
+@interface INTF5
+{
+ char * ch;
+}
+@end
+
+@implementation INTF5
+{
+}
+@end
diff --git a/test/SemaObjC/continuation-class-err.m b/test/SemaObjC/continuation-class-err.m
new file mode 100644
index 000000000000..f516a9326a95
--- /dev/null
+++ b/test/SemaObjC/continuation-class-err.m
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface ReadOnly
+{
+ id _object;
+ id _object1;
+}
+@property(readonly) id object;
+@property(readwrite, assign) id object1;
+@end
+
+@interface ReadOnly ()
+@property(readwrite, copy) id object;
+@property(readonly) id object1; // expected-error {{attribute of property in continuation class of 'ReadOnly' can only be 'readwrite'}}
+@end
diff --git a/test/SemaObjC/duplicate-ivar-check.m b/test/SemaObjC/duplicate-ivar-check.m
new file mode 100644
index 000000000000..7cab982e6e21
--- /dev/null
+++ b/test/SemaObjC/duplicate-ivar-check.m
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface B1 {
+@public
+ double fill_B; // expected-note {{previous declaration is here}}
+ unsigned : 0;
+}
+@end
+
+@interface B : B1 {
+@public
+ int one; // expected-note {{previous declaration is here}}
+ int one; // expected-error {{duplicate member 'one'}}
+ unsigned : 0;
+}
+@end
+
+@interface A : B {
+@public
+ int fill_B; // expected-error {{duplicate member 'fill_B'}}
+}
+@end
diff --git a/test/SemaObjC/enhanced-proto-2.m b/test/SemaObjC/enhanced-proto-2.m
new file mode 100644
index 000000000000..0450d7ba9deb
--- /dev/null
+++ b/test/SemaObjC/enhanced-proto-2.m
@@ -0,0 +1,21 @@
+// RUN: clang-cc -verify %s
+
+@protocol MyProto1
+@optional
+- (void) FOO;
+@optional
+- (void) FOO;
+@optional
+- (void) REQ;
+@optional
+@end
+
+@interface MyProto2 <MyProto1>
+- (void) FOO2;
+- (void) FOO3;
+@end
+
+@implementation MyProto2
+- (void) FOO2{}
+- (void) FOO3{}
+@end
diff --git a/test/SemaObjC/error-property-gc-attr.m b/test/SemaObjC/error-property-gc-attr.m
new file mode 100644
index 000000000000..a44ba4f3768d
--- /dev/null
+++ b/test/SemaObjC/error-property-gc-attr.m
@@ -0,0 +1,27 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify %s
+
+@interface INTF
+{
+ id IVAR;
+ __weak id II;
+ __weak id WID;
+ id ID;
+ __weak INTF* AWEAK;
+ __weak INTF* WI;
+}
+@property (assign) __weak id pweak;
+@property (assign) __weak id WID;
+@property (assign) __strong id not;
+@property (assign) id ID;
+@property (assign) INTF* AWEAK;
+@property (assign) __weak INTF* WI;
+@end
+
+@implementation INTF
+@synthesize pweak=IVAR; // expected-error {{existing ivar 'IVAR' for __weak property 'pweak' must be __weak}}
+@synthesize not=II; // expected-error {{existing ivar 'II' for a __strong property 'not' must be garbage collectable}}
+@synthesize WID;
+@synthesize ID;
+@synthesize AWEAK; // expected-error {{existing ivar 'AWEAK' for a __strong property 'AWEAK' must be garbage collectable}}
+@synthesize WI;
+@end
diff --git a/test/SemaObjC/exprs.m b/test/SemaObjC/exprs.m
new file mode 100644
index 000000000000..d51d135fa27a
--- /dev/null
+++ b/test/SemaObjC/exprs.m
@@ -0,0 +1,21 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+// rdar://6597252
+Class test1(Class X) {
+ return 1 ? X : X;
+}
+
+
+// rdar://6079877
+void test2() {
+ id str = @"foo"
+ "bar\0" // expected-warning {{literal contains NUL character}}
+ @"baz" " blarg";
+ id str2 = @"foo"
+ "bar"
+ @"baz"
+ " b\0larg"; // expected-warning {{literal contains NUL character}}
+
+
+ if (@encode(int) == "foo") { } // expected-warning {{result of comparison against @encode is unspecified}}
+}
diff --git a/test/SemaObjC/foreach.m b/test/SemaObjC/foreach.m
new file mode 100644
index 000000000000..f136adfa363b
--- /dev/null
+++ b/test/SemaObjC/foreach.m
@@ -0,0 +1,18 @@
+/* RUN: clang-cc -fsyntax-only -verify -std=c89 -pedantic %s
+ */
+
+@class NSArray;
+
+void f(NSArray *a) {
+ id keys;
+ for (int i in a); /* expected-error{{selector element type 'int' is not a valid object}} */
+ for ((id)2 in a); /* expected-error{{selector element is not a valid lvalue}} */
+ for (2 in a); /* expected-error{{selector element is not a valid lvalue}} */
+
+ /* This should be ok, 'thisKey' should be scoped to the loop in question,
+ * and no diagnostics even in pedantic mode should happen.
+ * rdar://6814674
+ */
+ for (id thisKey in keys);
+ for (id thisKey in keys);
+}
diff --git a/test/SemaObjC/format-arg-attribute.m b/test/SemaObjC/format-arg-attribute.m
new file mode 100644
index 000000000000..60cc7cb44f25
--- /dev/null
+++ b/test/SemaObjC/format-arg-attribute.m
@@ -0,0 +1,28 @@
+// RUN: clang-cc -verify -fsyntax-only %s
+
+@class NSString;
+
+extern NSString *fa2 (const NSString *) __attribute__((format_arg(1)));
+extern NSString *fa3 (NSString *) __attribute__((format_arg(1)));
+
+extern void fc1 (const NSString *) __attribute__((format_arg)); // expected-error {{attribute requires 1 argument(s)}}
+extern void fc2 (const NSString *) __attribute__((format_arg())); // expected-error {{attribute requires 1 argument(s)}}
+extern void fc3 (const NSString *) __attribute__((format_arg(1, 2))); // expected-error {{attribute requires 1 argument(s)}}
+
+struct s1 { int i; } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to function types}}
+union u1 { int i; } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to function types}}
+// FIXME: We don't flag this yet.
+enum e1 { E1V0 } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on enum" } */
+
+extern NSString *ff3 (const NSString *) __attribute__((format_arg(3-2)));
+extern NSString *ff4 (const NSString *) __attribute__((format_arg(foo))); // expected-error {{attribute requires 1 argument(s)}}
+
+/* format_arg formats must take and return a string. */
+extern NSString *fi0 (int) __attribute__((format_arg(1))); // expected-error {{format argument not a string type}}
+extern NSString *fi1 (NSString *) __attribute__((format_arg(1)));
+
+extern NSString *fi2 (NSString *) __attribute__((format_arg(1)));
+
+extern int fi3 (const NSString *) __attribute__((format_arg(1))); // expected-error {{function does not return NSString}}
+extern NSString *fi4 (const NSString *) __attribute__((format_arg(1)));
+extern NSString *fi5 (const NSString *) __attribute__((format_arg(1)));
diff --git a/test/SemaObjC/format-strings-objc.m b/test/SemaObjC/format-strings-objc.m
new file mode 100644
index 000000000000..4b8490291ad0
--- /dev/null
+++ b/test/SemaObjC/format-strings-objc.m
@@ -0,0 +1,43 @@
+// RUN: clang-cc -fsyntax-only -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 svelt and
+// portable to non-Mac platforms.
+//===----------------------------------------------------------------------===//
+
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+@class NSString, Protocol;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end
+@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
+@interface NSObject <NSObject> {} @end
+typedef float CGFloat;
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length; @end
+@interface NSSimpleCString : NSString {} @end
+@interface NSConstantString : NSSimpleCString @end
+extern void *_NSConstantStringClassReference;
+
+typedef const struct __CFString * CFStringRef;
+extern void CFStringCreateWithFormat(CFStringRef format, ...) __attribute__((format(CFString, 1, 2)));
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+void check_nslog(unsigned k) {
+ NSLog(@"%d%%", k); // no-warning
+ NSLog(@"%s%lb%d", "unix", 10,20); // expected-warning {{lid conversion '%lb'}}
+}
+
+// Check type validation
+extern void NSLog2(int format, ...) __attribute__((format(__NSString__, 1, 2))); // expected-error {{format argument not an NSString}}
+extern void CFStringCreateWithFormat2(int *format, ...) __attribute__((format(CFString, 1, 2))); // expected-error {{format argument not a CFString}}
diff --git a/test/SemaObjC/forward-class-1.m b/test/SemaObjC/forward-class-1.m
new file mode 100644
index 000000000000..f5f950566672
--- /dev/null
+++ b/test/SemaObjC/forward-class-1.m
@@ -0,0 +1,47 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@class FOO, BAR;
+@class FOO, BAR;
+
+@interface INTF : FOO // expected-error {{cannot find interface declaration for 'FOO', superclass of 'INTF'}}
+@end
+
+@interface FOO
+- (BAR*) Meth1;
+- (FOO*) Meth2;
+@end
+
+@interface INTF1 : FOO
+@end
+
+@interface INTF2 : INTF1 // expected-note {{previous definition is here}}
+@end
+
+
+@class INTF1, INTF2;
+
+@interface INTF2 : INTF1 // expected-error {{duplicate interface definition for class 'INTF2'}}
+@end
+
+// 2nd test of a forward class declaration matching a typedef name
+// referring to class object.
+// FIXME. This may become a negative test should we decide to make this an error.
+//
+@interface NSObject @end
+
+@protocol XCElementP @end
+
+typedef NSObject <XCElementP> XCElement;
+
+@interface XCElementMainImp {
+ XCElement * _editingElement;
+}
+@end
+
+@class XCElement;
+
+@implementation XCElementMainImp
+- (XCElement *)editingElement { return _editingElement; }
+@end
+
+
diff --git a/test/SemaObjC/forward-class-receiver.m b/test/SemaObjC/forward-class-receiver.m
new file mode 100644
index 000000000000..ebba0fd896dc
--- /dev/null
+++ b/test/SemaObjC/forward-class-receiver.m
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface I
++ new; // expected-note {{method 'new' is used for the forward class}}
+@end
+Class isa;
+
+@class NotKnown;
+
+void foo(NotKnown *n) {
+ [isa new];
+ [NotKnown new]; /* expected-warning {{receiver 'NotKnown' is a forward class and corresponding}} */
+}
diff --git a/test/SemaObjC/gcc-cast-ext.m b/test/SemaObjC/gcc-cast-ext.m
new file mode 100644
index 000000000000..5d6670e0f67c
--- /dev/null
+++ b/test/SemaObjC/gcc-cast-ext.m
@@ -0,0 +1,24 @@
+// RUN: clang-cc %s -verify -fms-extensions
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+typedef struct _NSRange { } NSRange;
+
+@class PBXFileReference;
+
+@interface PBXDocBookmark
++ alloc;
+- autorelease;
+@end
+
+// GCC allows pointer expressions in integer constant expressions.
+struct {
+ char control[((int)(char *)2)];
+} xx;
+
+@implementation PBXDocBookmark // expected-warning {{incomplete implementation}} expected-warning {{method definition for 'autorelease' not found}} expected-warning {{method definition for 'alloc' not found}}
+
++ (id)bookmarkWithFileReference:(PBXFileReference *)fileRef gylphRange:(NSRange)range anchor:(NSString *)htmlAnchor
+{
+ NSRange r = (NSRange)range;
+ return [[[self alloc] initWithFileReference:fileRef gylphRange:(NSRange)range anchor:(NSString *)htmlAnchor] autorelease]; // expected-warning {{method '-initWithFileReference:gylphRange:anchor:' not found (return type defaults to 'id')}}
+}
+@end
diff --git a/test/SemaObjC/id.m b/test/SemaObjC/id.m
new file mode 100644
index 000000000000..1781ce71d9c3
--- /dev/null
+++ b/test/SemaObjC/id.m
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@protocol Foo;
+
+Class T;
+id<Foo> S;
+id R;
+void foo() {
+ // Test assignment compatibility of Class and id. No warning should be
+ // produced.
+ // rdar://6770142 - Class and id<foo> are compatible.
+ S = T; T = S;
+ R = T; T = R;
+ R = S; S = R;
+}
+
+// Test attempt to redefine 'id' in an incompatible fashion.
+typedef int id; // expected-error {{typedef redefinition with different types}}
+id b;
+
diff --git a/test/SemaObjC/id_builtin.m b/test/SemaObjC/id_builtin.m
new file mode 100644
index 000000000000..134753726cbb
--- /dev/null
+++ b/test/SemaObjC/id_builtin.m
@@ -0,0 +1,10 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+// id is now builtin. There should be no errors.
+id obj;
+
+@interface Foo
+
+- defaultToId;
+
+@end
diff --git a/test/SemaObjC/ignore-weakimport-method.m b/test/SemaObjC/ignore-weakimport-method.m
new file mode 100644
index 000000000000..369d9023acfb
--- /dev/null
+++ b/test/SemaObjC/ignore-weakimport-method.m
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface foo
++ (void) cx __attribute__((weak_import));
+- (void) x __attribute__((weak_import));
+@end
+
diff --git a/test/SemaObjC/incompatible-protocol-qualified-types.m b/test/SemaObjC/incompatible-protocol-qualified-types.m
new file mode 100644
index 000000000000..862265ca6476
--- /dev/null
+++ b/test/SemaObjC/incompatible-protocol-qualified-types.m
@@ -0,0 +1,40 @@
+// RUN: clang-cc -pedantic -fsyntax-only -verify %s
+
+@protocol MyProto1
+@end
+
+@protocol MyProto2
+@end
+
+@interface INTF @end
+
+INTF <MyProto1> * Func(INTF <MyProto1, MyProto2> *p2)
+{
+ return p2;
+}
+
+
+INTF <MyProto1> * Func1(INTF <MyProto1, MyProto2> *p2)
+{
+ return p2;
+}
+
+INTF <MyProto1, MyProto2> * Func2(INTF <MyProto1> *p2)
+{
+ Func(p2); // expected-warning {{incompatible pointer types passing 'INTF<MyProto1> *', expected 'INTF<MyProto1,MyProto2> *}}
+ return p2; // expected-warning {{incompatible pointer types returning 'INTF<MyProto1> *', expected 'INTF<MyProto1,MyProto2> *}}
+}
+
+
+
+INTF <MyProto1> * Func3(INTF <MyProto2> *p2)
+{
+ return p2; // expected-warning {{incompatible pointer types returning 'INTF<MyProto2> *', expected 'INTF<MyProto1> *}}
+}
+
+
+INTF <MyProto1, MyProto2> * Func4(INTF <MyProto2, MyProto1> *p2)
+{
+ return p2;
+}
+
diff --git a/test/SemaObjC/inst-method-lookup-in-root.m b/test/SemaObjC/inst-method-lookup-in-root.m
new file mode 100644
index 000000000000..93f28e69f945
--- /dev/null
+++ b/test/SemaObjC/inst-method-lookup-in-root.m
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@protocol P
+- (id) inst_in_proto;
+@end
+
+@interface Object <P>
+- (id) inst_in_root;
+@end
+
+@interface Base
+@end
+
+@interface Derived: Base
+- (id)starboard;
+@end
+
+void foo(void) {
+ Class receiver;
+
+ [Derived starboard]; // expected-warning {{method '+starboard' not found}}
+
+ [receiver starboard]; // expected-warning {{instance method 'starboard' is being used on 'Class'}}
+ [receiver inst_in_root]; // Ok!
+ [receiver inst_in_proto]; // Ok!
+}
+
diff --git a/test/SemaObjC/interface-1.m b/test/SemaObjC/interface-1.m
new file mode 100644
index 000000000000..85a2a91a8c13
--- /dev/null
+++ b/test/SemaObjC/interface-1.m
@@ -0,0 +1,38 @@
+// RUN: clang-cc -triple i386-apple-darwin9 %s -fsyntax-only -verify
+// rdar://5957506
+
+@interface NSWhatever :
+NSObject // expected-error {{cannot find interface declaration for 'NSObject'}}
+<NSCopying> // expected-error {{cannot find protocol declaration for 'NSCopying'}}
+@end
+
+
+// rdar://6095245
+@interface A
+{
+ int x
+} // expected-error {{expected ';' at end of declaration list}}
+@end
+
+
+// rdar://4304469
+@interface INT1
+@end
+
+void test2() {
+ // rdar://6827200
+ INT1 b[3]; // expected-error {{array of interface 'INT1' is invalid (probably should be an array of pointers)}}
+ INT1 *c = &b[0];
+ ++c;
+}
+
+
+// rdar://6611778
+@interface FOO // expected-note {{previous definition is here}}
+- (void)method;
+@end
+
+@interface FOO // expected-error {{duplicate interface definition for class 'FOO'}}
+- (void)method2;
+@end
+
diff --git a/test/SemaObjC/interface-layout-2.m b/test/SemaObjC/interface-layout-2.m
new file mode 100644
index 000000000000..ec03a00ca75e
--- /dev/null
+++ b/test/SemaObjC/interface-layout-2.m
@@ -0,0 +1,16 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+@interface A
+{
+ int ivar;
+}
+@end
+
+@interface B : A
+- (int)ivar;
+@end
+
+@implementation B
+- (int)ivar {
+ return ivar;
+}
+@end
diff --git a/test/SemaObjC/interface-layout.m b/test/SemaObjC/interface-layout.m
new file mode 100644
index 000000000000..6ad891554844
--- /dev/null
+++ b/test/SemaObjC/interface-layout.m
@@ -0,0 +1,27 @@
+// RUN: clang-cc %s -fsyntax-only -verify -triple i386-apple-darwin9
+typedef struct objc_object {} *id;
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+typedef struct _NSZone NSZone;
+
+@protocol NSObject
+- (BOOL) isEqual:(id) object;
+@end
+
+@protocol NSCopying
+- (id) copyWithZone:(NSZone *) zone;
+@end
+
+@interface NSObject < NSObject > {}
+@end
+
+extern id NSAllocateObject (Class aClass, NSUInteger extraBytes, NSZone * zone);
+
+@interface MyClassBase : NSObject < NSCopying > {}
+@end
+
+@interface MyClassDirectNode : MyClassBase < NSCopying >
+{
+ @public NSUInteger attributeRuns[((1024 - 16 - sizeof (MyClassBase)) / (sizeof (NSUInteger) + sizeof (void *)))];
+}
+@end
diff --git a/test/SemaObjC/interface-scope-2.m b/test/SemaObjC/interface-scope-2.m
new file mode 100644
index 000000000000..d054e714f3b2
--- /dev/null
+++ b/test/SemaObjC/interface-scope-2.m
@@ -0,0 +1,126 @@
+// RUN: clang-cc -fsyntax-only -verify -triple i686-apple-darwin9 %s
+// FIXME: must also compile as Objective-C++
+
+// <rdar://problem/6487662>
+typedef struct objc_selector *SEL;
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (BOOL)respondsToSelector:(SEL)aSelector;
+@end
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end
+@protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+@protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
+@end
+@class NSString, NSData;
+typedef struct _NSPoint {}
+NSRange;
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
+@end
+@interface NSMutableString : NSString
+- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)aString;
+@end
+@class NSArray, NSDictionary, NSMapTable;
+@interface NSResponder : NSObject <NSCoding> {}
+@end
+@protocol NSAnimatablePropertyContainer
+- (id)animator;
+@end
+extern NSString *NSAnimationTriggerOrderIn ;
+@interface NSView : NSResponder <NSAnimatablePropertyContainer> {
+ struct __VFlags2 {} _vFlags2;
+}
+@end
+@class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView;
+@interface FooiagramView : NSView {
+id _delegate;
+}
+@end
+@class FooiagramView;
+@interface _FooiagramViewReserved : NSObject {
+@public
+ NSMutableString *_typeToSelectString;
+ struct _FooiagramViewFlags {
+ unsigned int delegateRespondsToPrintInfoForBarView : 1;
+ } _dvFlags;
+}
+@end
+extern _FooiagramViewReserved *_FooiagramViewBarViewReserved(FooiagramView *BarView);
+@interface FooiagramView (FooiagramViewPrivate)
++ (Class)_defaultBarToolManagerClass;
+@end
+@implementation FooiagramView
+static NSMapTable *_defaultMenuForClass = 0;
+- (void)setDelegate:(id)delegate {
+ if (_delegate != delegate) {
+ struct _FooiagramViewFlags *dvFlags =
+ &_FooiagramViewBarViewReserved(self)->_dvFlags;
+ if (_delegate != ((void *)0)) {
+ dvFlags->delegateRespondsToPrintInfoForBarView = [_delegate respondsToSelector:@selector(printInfoForBarView:)];
+ }
+ }
+}
+@end
+
+// <rdar://problem/6487684>
+@interface WizKing_MIKeep {
+struct __LoreStuffNode *_historyStuff;
+}
+@end
+typedef struct __LoreStuffNode {} LoreStuffNode;
+@implementation WizKing_MIKeep
+- init {
+ LoreStuffNode *node;
+ node = &(_historyStuff[1]);
+}
+@end
+
+// <rdar://problem/6487702>
+typedef long unsigned int __darwin_size_t;
+typedef __darwin_size_t size_t;
+void *memset(void *, int, size_t);
+@class NSString, NSURL, NSError;
+@interface OingoWerdnaPeon : NSObject {}
+@end typedef enum {
+OingoPT_SmashOK, OingoPT_NoSuchFile, }
+OingoWerdnaPeonIOMethod;
+@interface OingoWerdnaPeonSmashDrivel : NSObject <NSCopying> {}
+@end
+@interface OingoBoingoContraptionPeon : OingoWerdnaPeon {
+struct _OingoBoingoContraptionPeonFlags {}
+_nfttFlags;
+}
+@end
+@implementation OingoBoingoContraptionPeon
++ (void)initialize {}
+- (id)initWithSmashDrivel:(OingoWerdnaPeonSmashDrivel *)info {
+ if (self != ((void *)0)) {
+ (void)memset(&_nfttFlags, 0, sizeof(struct _OingoBoingoContraptionPeonFlags));
+ }
+}
+@end
+
+@interface Blah {
+ struct X {
+ int x;
+ } value;
+}
+@end
+
+@implementation Blah
+- (int)getValue {
+ struct X *xp = &value;
+ return xp->x;
+}
+@end
diff --git a/test/SemaObjC/interface-scope.m b/test/SemaObjC/interface-scope.m
new file mode 100644
index 000000000000..b4dfff683bb1
--- /dev/null
+++ b/test/SemaObjC/interface-scope.m
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface I1 {
+@private
+ int x;
+ struct {
+ unsigned int x : 3;
+ unsigned int y : 3;
+ } flags;
+ int y;
+}
+@end
diff --git a/test/SemaObjC/interface-tu-variable.m b/test/SemaObjC/interface-tu-variable.m
new file mode 100644
index 000000000000..9bf816ab69fb
--- /dev/null
+++ b/test/SemaObjC/interface-tu-variable.m
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface XX
+int x; // expected-error {{cannot declare variable inside @interface or @protocol}}
+int one=1; // expected-error {{cannot declare variable inside @interface or @protocol}}
+@end
+
+@protocol PPP
+int ddd; // expected-error {{cannot declare variable inside @interface or @protocol}}
+@end
+
+@interface XX(CAT)
+ char * III; // expected-error {{cannot declare variable inside @interface or @protocol}}
+ extern int OK;
+@end
+
+@interface XX()
+ char * III2; // expected-error {{cannot declare variable inside @interface or @protocol}}
+ extern int OK2;
+@end
+
+
+int main( int argc, const char *argv[] ) {
+ return x+one;
+}
+
diff --git a/test/SemaObjC/invalid-code.m b/test/SemaObjC/invalid-code.m
new file mode 100644
index 000000000000..6eacba05f4ae
--- /dev/null
+++ b/test/SemaObjC/invalid-code.m
@@ -0,0 +1,7 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+// rdar://6124613
+void test1() {
+ void *p = @1; // expected-error {{unexpected '@' in program}}
+}
+
diff --git a/test/SemaObjC/invalid-objc-decls-1.m b/test/SemaObjC/invalid-objc-decls-1.m
new file mode 100644
index 000000000000..e3a94f62d5a6
--- /dev/null
+++ b/test/SemaObjC/invalid-objc-decls-1.m
@@ -0,0 +1,34 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface Super @end
+Super s1; // expected-error{{interface type cannot be statically allocated}}
+
+extern Super e1; // expected-error{{interface type cannot be statically allocated}}
+
+struct S {
+ Super s1; // expected-error{{interface type cannot be statically allocated}}
+};
+
+@protocol P1 @end
+
+@interface INTF
+{
+ Super ivar1; // expected-error{{interface type cannot be statically allocated}}
+}
+@end
+
+struct whatever {
+ Super objField; // expected-error{{interface type cannot be statically allocated}}
+};
+
+@interface MyIntf
+{
+ Super<P1> ivar1; // expected-error{{interface type cannot be statically allocated}}
+}
+@end
+
+Super foo( // expected-error{{interface interface type 'Super' cannot be returned by value}}
+ Super parm1) { // expected-error{{interface interface type 'Super' cannot be passed by value}}
+ Super p1; // expected-error{{interface type cannot be statically allocated}}
+ return p1;
+}
diff --git a/test/SemaObjC/invalid-receiver.m b/test/SemaObjC/invalid-receiver.m
new file mode 100644
index 000000000000..e79df96942cc
--- /dev/null
+++ b/test/SemaObjC/invalid-receiver.m
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef struct NotAClass {
+ int a, b;
+} NotAClass;
+
+void foo() {
+ [NotAClass nonexistent_method]; // expected-error {{invalid receiver to message expression}}
+}
diff --git a/test/SemaObjC/invalid-typename.m b/test/SemaObjC/invalid-typename.m
new file mode 100644
index 000000000000..4077f91a9a66
--- /dev/null
+++ b/test/SemaObjC/invalid-typename.m
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@class NSString, NSArray;
+
+@protocol ISyncSessionCallback
+- (oneway void)clientWithId:(bycopy NSString *)clientId
+ canBeginSyncingPlanWithId:(bycopy NSString *)planId
+ syncModes:(bycopy NSArray /* ISDSyncState */ *)syncModes
+ entities:(bycopy NSArray /* ISDEntity */ *)entities
+ truthPullers:(bycopy NSDictionary /* NSString -> [NSString] */ *)truthPullers; // expected-error{{expected ')'}} expected-note {{to match this '('}}
+@end
+
diff --git a/test/SemaObjC/ivar-access-package.m b/test/SemaObjC/ivar-access-package.m
new file mode 100644
index 000000000000..77a15cca5142
--- /dev/null
+++ b/test/SemaObjC/ivar-access-package.m
@@ -0,0 +1,45 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef unsigned char BOOL;
+
+@interface NSObject {
+ id isa;
+}
++new;
++alloc;
+-init;
+-autorelease;
+@end
+
+@interface NSAutoreleasePool : NSObject
+- drain;
+@end
+
+@interface A : NSObject {
+@package
+ id object;
+}
+@end
+
+@interface B : NSObject
+- (BOOL)containsSelf:(A*)a;
+@end
+
+@implementation A
+@end
+
+@implementation B
+- (BOOL)containsSelf:(A*)a {
+ return a->object == self;
+}
+@end
+
+int main (int argc, const char * argv[]) {
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ A *a = [[A new] autorelease];
+ B *b = [[B new] autorelease];
+ NSLog(@"%s", [b containsSelf:a] ? "YES" : "NO");
+ [pool drain];
+ return 0;
+}
+
diff --git a/test/SemaObjC/ivar-access-tests.m b/test/SemaObjC/ivar-access-tests.m
new file mode 100644
index 000000000000..ca3cc4cf1d46
--- /dev/null
+++ b/test/SemaObjC/ivar-access-tests.m
@@ -0,0 +1,122 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface MySuperClass
+{
+@private
+ int private;
+
+@protected
+ int protected;
+
+@public
+ int public;
+}
+@end
+
+@implementation MySuperClass
+- (void) test {
+ int access;
+ MySuperClass *s = 0;
+ access = s->private;
+ access = s->protected;
+}
+@end
+
+
+@interface MyClass : MySuperClass
+@end
+
+@implementation MyClass
+- (void) test {
+ int access;
+ MySuperClass *s = 0;
+ access = s->private; // expected-error {{instance variable 'private' is private}}
+ access = s->protected;
+ MyClass *m=0;
+ access = m->private; // expected-error {{instance variable 'private' is private}}
+ access = m->protected;
+}
+@end
+
+
+@interface Deeper : MyClass
+@end
+
+@implementation Deeper
+- (void) test {
+ int access;
+ MySuperClass *s = 0;
+ access = s->private; // expected-error {{instance variable 'private' is private}}
+ access = s->protected;
+ MyClass *m=0;
+ access = m->private; // expected-error {{instance variable 'private' is private}}
+ access = m->protected;
+}
+@end
+
+@interface Unrelated
+@end
+
+@implementation Unrelated
+- (void) test {
+ int access;
+ MySuperClass *s = 0;
+ access = s->private; // expected-error {{instance variable 'private' is private}}
+ access = s->protected; // expected-error {{instance variable 'protected' is protected}}
+ MyClass *m=0;
+ access = m->private; // expected-error {{instance variable 'private' is private}}
+ access = m->protected; // expected-error {{instance variable 'protected' is protected}}
+}
+@end
+
+int main (void)
+{
+ MySuperClass *s = 0;
+ int access;
+ access = s->private; // expected-error {{instance variable 'private' is private}}
+ access = s->protected; // expected-error {{instance variable 'protected' is protected}}
+ return 0;
+}
+
+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 NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
+@end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+@interface NSResponder : NSObject <NSCoding> {}
+@end
+@protocol NSAnimatablePropertyContainer
+- (id)animator;
+@end
+extern NSString *NSAnimationTriggerOrderIn ;
+@interface NSView : NSResponder <NSAnimatablePropertyContainer> {
+ struct __VFlags2 {
+ }
+ _vFlags2;
+}
+@end
+@class NSFontDescriptor, NSAffineTransform, NSGraphicsContext;
+@interface NSScrollView : NSView {}
+@end
+
+@class CasperMixerView;
+@interface CasperDiffScrollView : NSScrollView {
+@private
+ CasperMixerView *_comparatorView;
+ NSView *someField;
+}
+@end
+
+@implementation CasperDiffScrollView
++ (void)initialize {}
+static void _CasperDiffScrollViewInstallMixerView(CasperDiffScrollView *scrollView) {
+ if (scrollView->someField != ((void *)0)) {
+ }
+}
+@end
diff --git a/test/SemaObjC/ivar-lookup.m b/test/SemaObjC/ivar-lookup.m
new file mode 100644
index 000000000000..b168976da136
--- /dev/null
+++ b/test/SemaObjC/ivar-lookup.m
@@ -0,0 +1,18 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+@interface Test {
+ int x;
+}
+
+-(void) setX: (int) d;
+@end
+
+extern struct foo x;
+
+@implementation Test
+
+-(void) setX: (int) n {
+ x = n;
+}
+
+@end
diff --git a/test/SemaObjC/ivar-ref-misuse.m b/test/SemaObjC/ivar-ref-misuse.m
new file mode 100644
index 000000000000..85ede5786d5b
--- /dev/null
+++ b/test/SemaObjC/ivar-ref-misuse.m
@@ -0,0 +1,41 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface Sprite {
+ int sprite, spree;
+ int UseGlobalBar;
+}
++ (void)setFoo:(int)foo;
++ (void)setSprite:(int)sprite;
+- (void)setFoo:(int)foo;
+- (void)setSprite:(int)sprite;
+@end
+
+int spree = 23;
+int UseGlobalBar;
+
+@implementation Sprite
++ (void)setFoo:(int)foo {
+ sprite = foo; // expected-error {{use of undeclared identifier 'sprite'}}
+ spree = foo;
+ Xsprite = foo; // expected-error {{use of undeclared identifier 'Xsprite'}}
+ UseGlobalBar = 10;
+}
++ (void)setSprite:(int)sprite {
+ int spree;
+ sprite = 15;
+ spree = 17;
+ ((Sprite *)self)->sprite = 16; /* NB: This is how one _should_ access */
+ ((Sprite *)self)->spree = 18; /* ivars from within class methods! */
+}
+- (void)setFoo:(int)foo {
+ sprite = foo;
+ spree = foo;
+}
+- (void)setSprite:(int)sprite {
+ int spree;
+ sprite = 15; // expected-warning {{local declaration of 'sprite' hides instance variable}}
+ self->sprite = 16;
+ spree = 17; // expected-warning {{local declaration of 'spree' hides instance variable}}
+ self->spree = 18;
+}
+@end
diff --git a/test/SemaObjC/ivar-sem-check-1.m b/test/SemaObjC/ivar-sem-check-1.m
new file mode 100644
index 000000000000..957abc397e89
--- /dev/null
+++ b/test/SemaObjC/ivar-sem-check-1.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct S; // expected-note{{forward declaration of 'struct S'}}
+typedef int FOO();
+
+@interface INTF
+{
+ struct F {} JJ;
+ int arr[]; // expected-error {{field has incomplete type}}
+ struct S IC; // expected-error {{field has incomplete type}}
+ struct T { // expected-note {{previous definition is here}}
+ struct T {} X; // expected-error {{nested redefinition of 'T'}}
+ }YYY;
+ FOO BADFUNC; // expected-error {{field 'BADFUNC' declared as a function}}
+ int kaka; // expected-note {{previous declaration is here}}
+ int kaka; // expected-error {{duplicate member 'kaka'}}
+ char ch[]; // expected-error {{field has incomplete type}}
+}
+@end
diff --git a/test/SemaObjC/ivar-sem-check-2.m b/test/SemaObjC/ivar-sem-check-2.m
new file mode 100644
index 000000000000..ba6b38934bd1
--- /dev/null
+++ b/test/SemaObjC/ivar-sem-check-2.m
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -triple x86_64-apple-darwin10 -verify %s
+
+@interface Super {
+ id value2; // expected-note {{previously declared 'value2' here}}
+}
+@property(retain) id value;
+@property(retain) id value1;
+@property(retain) id prop;
+@end
+
+@interface Sub : Super
+{
+ id value;
+}
+@end
+
+@implementation Sub
+@synthesize value; // expected-note {{previous use is here}}
+@synthesize value1=value; // expected-error {{synthesized properties 'value1' and 'value' both claim ivar 'value'}}
+@synthesize prop=value2; // expected-error {{property 'prop' attempting to use ivar 'value2' declared in super class 'Super'}}
+@end
+
+
diff --git a/test/SemaObjC/legacy-implementation-1.m b/test/SemaObjC/legacy-implementation-1.m
new file mode 100644
index 000000000000..63768ffb50ea
--- /dev/null
+++ b/test/SemaObjC/legacy-implementation-1.m
@@ -0,0 +1,11 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@implementation INTF // expected-warning {{cannot find interface declaration for 'INTF'}}
+@end
+
+INTF* pi;
+
+INTF* FUNC()
+{
+ return pi;
+}
diff --git a/test/SemaObjC/message.m b/test/SemaObjC/message.m
new file mode 100644
index 000000000000..7b6a4ee3f796
--- /dev/null
+++ b/test/SemaObjC/message.m
@@ -0,0 +1,100 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef struct objc_object {
+ Class isa;
+} *id;
+
+
+@interface foo
+- (void)meth;
+@end
+
+@implementation foo
+- (void) contents {} // No declaration in @interface!
+- (void) meth { [self contents]; }
+@end
+
+typedef struct _NSPoint {
+ float x;
+ float y;
+} NSPoint;
+
+typedef struct _NSSize {
+ float width;
+ float height;
+} NSSize;
+
+typedef struct _NSRect {
+ NSPoint origin;
+ NSSize size;
+} NSRect;
+
+@interface AnyClass
+- (NSRect)rect;
+@end
+
+@class Helicopter;
+
+static void func(Helicopter *obj) {
+ // Note that the proto for "rect" is found in the global pool even when
+ // a statically typed object's class interface isn't in scope! This
+ // behavior isn't very desirable, however wee need it for GCC compatibility.
+ NSRect r = [obj rect];
+}
+
+@interface NSObject @end
+
+extern Class NSClassFromObject(id object);
+
+@interface XX : NSObject
+@end
+
+@implementation XX
+
++ _privateMethod {
+ return self;
+}
+
+- (void) xx {
+ [NSClassFromObject(self) _privateMethod];
+}
+@end
+
+@implementation XX (Private)
+- (void) yy {
+ [NSClassFromObject(self) _privateMethod];
+}
+@end
+
+@interface I0
+-(void) nonVararg: (int) x;
+@end
+
+int f0(I0 *ob) {
+ [ ob nonVararg: 0, 1, 2]; // expected-error {{too many arguments to method call}}
+}
+
+int f2() {
+ const id foo;
+ [foo bar]; // expected-warning {{method '-bar' not found (return type defaults to 'id')}}
+ return 0;
+}
+
+
+// PR3766
+struct S { int X; } S;
+
+int test5(int X) {
+ int a = [X somemsg]; // expected-warning {{receiver type 'int' is not 'id'}} \
+ expected-warning {{method '-somemsg' not found}} \
+ expected-warning {{incompatible pointer to integer conversion initializing 'id', expected 'int'}}
+ int b = [S somemsg]; // expected-error {{bad receiver type 'struct S'}}
+}
+
+// PR4021
+void foo4() {
+ struct objc_object X[10];
+
+ [X rect];
+}
+
diff --git a/test/SemaObjC/method-arg-decay.m b/test/SemaObjC/method-arg-decay.m
new file mode 100644
index 000000000000..4b045914c095
--- /dev/null
+++ b/test/SemaObjC/method-arg-decay.m
@@ -0,0 +1,95 @@
+// RUN: clang-cc -checker-cfref -verify %s
+typedef signed char BOOL;
+typedef int NSInteger;
+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 NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end @interface NSObject <NSObject> {
+}
+@end extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value;
+@end @class NSString, NSData, NSMutableData, NSMutableDictionary, NSMutableArray;
+typedef struct {
+}
+ NSFastEnumerationState;
+@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end @class NSString;
+typedef struct _NSRange {
+}
+ NSRange;
+@interface NSValue (NSValueRangeExtensions) + (NSValue *)valueWithRange:(NSRange)range;
+- (id)objectAtIndex:(NSUInteger)index;
+@end typedef unsigned short unichar;
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
+@end @class NSArray, NSDictionary, NSString, NSError;
+@interface NSSet : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+@end extern NSString *NSAccessibilityRoleDescription(NSString *role, NSString *subrole) ;
+@interface NSResponder : NSObject <NSCoding> {
+}
+@end @protocol NSAnimatablePropertyContainer - (id)animator;
+@end extern NSString *NSAnimationTriggerOrderIn ;
+@interface NSView : NSResponder <NSAnimatablePropertyContainer> {
+}
+@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView;
+@interface NSWindowController : NSResponder <NSCoding> {
+}
+@end @class NSArray, NSFont, NSTabViewItem;
+@interface NSTabView : NSView {
+}
+- (NSArray *)tabViewItems;
+- (NSString *)label;
+@end typedef enum {
+PBXNoItemChanged = 0x00, PBXProjectItemChanged = 0x01, PBXReferenceChanged = 0x02, PBXGroupChanged = 0x04, PBXTargetChanged = 0x08, PBXBuildPhaseChanged = 0x10, PBXBuildFileChanged = 0x20, PBXBreakpointChanged = 0x40, }
+ PBXArchiveMask;
+@interface PBXModule : NSWindowController {
+}
+@end typedef enum {
+PBXFindMatchContains, PBXFindMatchStartsWith, PBXFindMatchWholeWords, PBXFindMatchEndsWith }
+ PBXFindMatchStyle;
+@protocol PBXSelectableText - (NSString *)selectedString;
+@end @protocol PBXFindableText <PBXSelectableText> - (BOOL)findText:(NSString *)string ignoreCase:(BOOL)ignoreCase matchStyle:(PBXFindMatchStyle)matchStyle backwards:(BOOL)backwards wrap:(BOOL)wrap;
+@end @class PBXProjectDocument, PBXProject, PBXAttributedStatusView;
+@interface PBXProjectModule : PBXModule <PBXFindableText> {
+}
+@end @class PBXBookmark;
+@protocol PBXSelectionTarget - (NSObject <PBXSelectionTarget> *) performAction:(id)action withSelection:(NSArray *)selection;
+@end @class XCPropertyDictionary, XCPropertyCondition, XCPropertyConditionSet, XCMutablePropertyConditionSet;
+extern NSMutableArray *XCFindPossibleKeyModules(PBXModule *module, BOOL useExposedModulesOnly);
+@interface NSString (StringUtilities) - (NSString *) trimToLength:(NSInteger)length preserveRange:(NSRange)range;
+- (id) objectOfType:(Class)type matchingFunction:(BOOL (void *, void *))comparator usingData:(void *)data;
+@end @class XCControlView;
+@protocol XCDockViewHeader - (NSImage *) headerImage;
+@end @class XCDockableTabModule;
+@interface XCExtendedTabView : NSTabView <XCDockViewHeader> {
+}
+@end @class PBXProjectDocument, PBXFileReference, PBXModule, XCWindowTool;
+@interface XCPerspectiveModule : PBXProjectModule <PBXSelectionTarget> {
+ XCExtendedTabView *_perspectivesTabView;
+}
+- (PBXModule *) moduleForTab:(NSTabViewItem *)item;
+@end
+@implementation XCPerspectiveModule
++ (void) openForProjectDocument:(PBXProjectDocument *)projectDocument {
+}
+- (PBXModule *) type:(Class)type inPerspective:(id)perspectiveIdentifer matchingFunction:(BOOL (void *, void *))comparator usingData:(void *)data {
+ NSArray *allItems = [_perspectivesTabView tabViewItems];
+ NSInteger i, c = [allItems count];
+ for (i = 0;
+ i < c;
+ i++) {
+ NSTabViewItem *item = [allItems objectAtIndex:i];
+ if ([[item label] isEqual:perspectiveIdentifer]) {
+ PBXProjectModule *pModule = (PBXProjectModule *)[self moduleForTab:item];
+ PBXModule *obj = [XCFindPossibleKeyModules(pModule, (BOOL)0) objectOfType:type matchingFunction:comparator usingData:data];
+ }
+ }
+}
+- (BOOL)buffer:(char *)buf containsAnyPrompts:(char *[])prompts
+{
+ prompts++;
+ return (BOOL)0;
+}
diff --git a/test/SemaObjC/method-attributes.m b/test/SemaObjC/method-attributes.m
new file mode 100644
index 000000000000..c4d4fba25d6e
--- /dev/null
+++ b/test/SemaObjC/method-attributes.m
@@ -0,0 +1,32 @@
+// RUN: clang-cc -verify -fsyntax-only %s
+
+@class NSString;
+
+@interface A
+-t1 __attribute__((noreturn));
+- (NSString *)stringByAppendingFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2)));
+-(void) m0 __attribute__((noreturn));
+-(void) m1 __attribute__((unused));
+@end
+
+
+@interface INTF
+- (int) foo1: (int)arg1 __attribute__((deprecated));
+
+- (int) foo: (int)arg1;
+
+- (int) foo2: (int)arg1 __attribute__((deprecated)) __attribute__((unavailable));
+@end
+
+@implementation INTF
+- (int) foo: (int)arg1 __attribute__((deprecated)){ // expected-warning {{method attribute can only be specified}}
+ return 10;
+}
+- (int) foo1: (int)arg1 {
+ return 10;
+}
+- (int) foo2: (int)arg1 __attribute__((deprecated)) { // expected-warning {{method attribute can only be specified}}
+ return 10;
+}
+@end
+
diff --git a/test/SemaObjC/method-bad-param.m b/test/SemaObjC/method-bad-param.m
new file mode 100644
index 000000000000..f797188669ad
--- /dev/null
+++ b/test/SemaObjC/method-bad-param.m
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface foo
+@end
+
+@implementation foo
+@end
+
+@interface bar
+-(void) my_method:(foo) my_param; // expected-error {{Objective-C interface type 'foo' cannot be passed by value}}
+- (foo)cccccc:(long)ddddd; // expected-error {{Objective-C interface type 'foo' cannot be returned by value}}
+@end
+
+@implementation bar
+-(void) my_method:(foo) my_param // expected-error {{Objective-C interface type 'foo' cannot be passed by value}}
+{
+}
+- (foo)cccccc:(long)ddddd // expected-error {{Objective-C interface type 'foo' cannot be returned by value}}
+{
+}
+@end
+
+void somefunc(foo x) {} // expected-error {{Objective-C interface type 'foo' cannot be passed by value}}
+foo somefunc2() {} // expected-error {{Objective-C interface type 'foo' cannot be returned by value}}
+
+// rdar://6780761
+void f0(foo *a0) {
+ extern void g0(int x, ...);
+ g0(1, *(foo*)0); // expected-error {{cannot pass object with interface type 'foo' by-value through variadic function}}
+}
diff --git a/test/SemaObjC/method-conflict.m b/test/SemaObjC/method-conflict.m
new file mode 100644
index 000000000000..7a9b9f0beee8
--- /dev/null
+++ b/test/SemaObjC/method-conflict.m
@@ -0,0 +1,53 @@
+// RUN: clang-cc -fsyntax-only -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 NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end @interface NSObject <NSObject> {
+}
+@end extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value;
+@end @class NSString;
+typedef struct _NSRange {
+}
+ NSRange;
+@interface NSValue (NSValueRangeExtensions) + (NSValue *)valueWithRange:(NSRange)range;
+@end @interface NSAttributedString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSString *)string;
+@end @interface NSMutableAttributedString : NSAttributedString - (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str;
+@end @class NSArray, NSDictionary, NSString, NSError;
+@interface NSScanner : NSObject <NSCopying> - (NSString *)string;
+@end typedef struct {
+}
+ CSSM_FIELDGROUP, *CSSM_FIELDGROUP_PTR;
+@protocol XDUMLClassifier;
+@protocol XDUMLClassInterfaceCommons <XDUMLClassifier>
+@end @protocol XDUMLImplementation;
+@protocol XDUMLElement <NSObject> - (NSArray *) ownedElements;
+@end @protocol XDUMLDataType;
+@protocol XDUMLNamedElement <XDUMLElement> - (NSString *) name;
+@end enum _XDSourceLanguage {
+XDSourceUnknown=0, XDSourceJava, XDSourceC, XDSourceCPP, XDSourceObjectiveC };
+typedef NSUInteger XDSourceLanguage;
+@protocol XDSCClassifier <XDUMLClassInterfaceCommons> - (XDSourceLanguage)language;
+@end @class XDSCDocController;
+@interface XDSCDisplaySpecification : NSObject <NSCoding>{
+}
+@end @class XDSCOperation;
+@interface XDSCClassFormatter : NSObject {
+}
++ (NSUInteger) compartmentsForClassifier: (id <XDUMLClassifier>) classifier withSpecification: (XDSCDisplaySpecification *) displaySpec;
+@end
+@class NSString;
+@implementation XDSCClassFormatter
+
++ appendVisibility: (id <XDUMLNamedElement>) element withSpecification: (XDSCDisplaySpecification *) displaySpec to: (NSMutableAttributedString *) attributedString
+{
+}
++ (NSUInteger) compartmentsForClassifier: (id <XDSCClassifier>) classifier withSpecification: (XDSCDisplaySpecification *) displaySpec {
+}
+@end
diff --git a/test/SemaObjC/method-def-1.m b/test/SemaObjC/method-def-1.m
new file mode 100644
index 000000000000..3eb94b9153d9
--- /dev/null
+++ b/test/SemaObjC/method-def-1.m
@@ -0,0 +1,40 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface foo
+- (int)meth;
+@end
+
+@implementation foo
+- (int) meth { return [self meth]; }
+@end
+
+// PR2708
+@interface MyClass
++- (void)myMethod; // expected-error {{expected selector for Objective-C method}}
+- (vid)myMethod2; // expected-error {{expected a type}}
+@end
+
+@implementation MyClass
+- (void)myMethod { }
+- (vid)myMethod2 { } // expected-error {{expected a type}}
+
+@end
+
+
+@protocol proto;
+@protocol NSObject;
+
+//@protocol GrowlPluginHandler <NSObject> @end
+
+
+@interface SomeClass2
+- (int)myMethod1: (id<proto>)
+arg; // expected-note {{previous definition is here}}
+@end
+
+@implementation SomeClass2
+- (int)myMethod1: (id<NSObject>)
+ arg { // expected-warning {{conflicting parameter types in implementation of 'myMethod1:': 'id<proto>' vs 'id<NSObject>'}}
+
+}
+@end
diff --git a/test/SemaObjC/method-def-2.m b/test/SemaObjC/method-def-2.m
new file mode 100644
index 000000000000..84cdd70259fa
--- /dev/null
+++ b/test/SemaObjC/method-def-2.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc -ast-print %s
+extern void abort(void);
+#define CHECK_IF(expr) if(!(expr)) abort()
+
+static double d = 4.5920234e2;
+
+@interface Foo
+-(void) brokenType: (int)x floatingPoint: (double)y;
+@end
+
+
+@implementation Foo
+-(void) brokenType: (int)x floatingPoint: (double)y
+{
+ CHECK_IF(x == 459);
+ CHECK_IF(y == d);
+}
+@end
+
diff --git a/test/SemaObjC/method-encoding-2.m b/test/SemaObjC/method-encoding-2.m
new file mode 100644
index 000000000000..64a0bc4c323d
--- /dev/null
+++ b/test/SemaObjC/method-encoding-2.m
@@ -0,0 +1,12 @@
+// RUN: clang-cc %s
+// TODO: We don't support rewrite of method definitions
+
+@interface Intf
+- (in out bycopy id) address:(byref inout void *)location with:(out oneway unsigned **)arg2;
+- (id) another:(void *)location with:(unsigned **)arg2;
+@end
+
+@implementation Intf
+- (in out bycopy id) address:(byref inout void *)location with:(out oneway unsigned **)arg2{}
+- (id) another:(void *)location with:(unsigned **)arg2 {}
+@end
diff --git a/test/SemaObjC/method-lookup-2.m b/test/SemaObjC/method-lookup-2.m
new file mode 100644
index 000000000000..dd0bca93644e
--- /dev/null
+++ b/test/SemaObjC/method-lookup-2.m
@@ -0,0 +1,62 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+typedef signed char BOOL;
+
+@protocol NSObject
++ alloc;
+- init;
+- (BOOL) isEqual:(id) object;
+- (Class)class;
+@end
+
+@interface NSObject < NSObject > {} @end
+
+@class NSString, NSPort;
+
+@interface NSPortNameServer:NSObject
++ (NSPortNameServer *) systemDefaultPortNameServer;
+@end
+
+@interface NSMachBootstrapServer:NSPortNameServer + (id) sharedInstance; @end
+
+enum {
+ NSWindowsNTOperatingSystem = 1, NSWindows95OperatingSystem, NSSolarisOperatingSystem, NSHPUXOperatingSystem, NSMACHOperatingSystem, NSSunOSOperatingSystem, NSOSF1OperatingSystem
+};
+
+@interface NSRunLoop:NSObject {} @end
+
+@interface NSRunLoop(NSRunLoopConveniences)
+- (void) run;
+@end
+
+extern NSString *const NSWillBecomeMultiThreadedNotification;
+
+@interface SenTestTool:NSObject {}
+@end
+
+@implementation SenTestTool
++ (void) initialize {}
++(SenTestTool *) sharedInstance {}
+-(int) run {}
++(int) run {
+ return[[self sharedInstance] run];
+}
+@end
+
+@interface XX : NSObject
+
++ classMethod;
+
+@end
+
+@interface YY : NSObject
+- whatever;
+@end
+
+@implementation YY
+
+- whatever {
+ id obj = [[XX alloc] init];
+ [[obj class] classMethod];
+}
+
+@end
diff --git a/test/SemaObjC/method-lookup-3.m b/test/SemaObjC/method-lookup-3.m
new file mode 100644
index 000000000000..8ed583faebc7
--- /dev/null
+++ b/test/SemaObjC/method-lookup-3.m
@@ -0,0 +1,52 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef struct { int y; } Abstract;
+
+typedef struct { int x; } Alternate;
+
+#define INTERFERE_TYPE Alternate*
+
+@protocol A
+@property Abstract *x; // expected-note {{using}}
+@end
+
+@interface B
+@property Abstract *y; // expected-note {{using}}
+@end
+
+@interface B (Category)
+@property Abstract *z; // expected-note {{using}}
+@end
+
+@interface InterferencePre
+-(void) x; // expected-note {{also found}}
+-(void) y; // expected-note {{also found}}
+-(void) z; // expected-note {{also found}}
+-(void) setX: (INTERFERE_TYPE) arg;
+-(void) setY: (INTERFERE_TYPE) arg;
+-(void) setZ: (INTERFERE_TYPE) arg;
+@end
+
+void f0(id a0) {
+ Abstract *l = [a0 x]; // expected-warning {{multiple methods named 'x' found}}
+}
+
+void f1(id a0) {
+ Abstract *l = [a0 y]; // expected-warning {{multiple methods named 'y' found}}
+}
+
+void f2(id a0) {
+ Abstract *l = [a0 z]; // expected-warning {{multiple methods named 'z' found}}
+}
+
+void f3(id a0, Abstract *a1) {
+ [ a0 setX: a1];
+}
+
+void f4(id a0, Abstract *a1) {
+ [ a0 setY: a1];
+}
+
+void f5(id a0, Abstract *a1) {
+ [ a0 setZ: a1];
+}
diff --git a/test/SemaObjC/method-lookup-4.m b/test/SemaObjC/method-lookup-4.m
new file mode 100644
index 000000000000..3b2548b92c11
--- /dev/null
+++ b/test/SemaObjC/method-lookup-4.m
@@ -0,0 +1,62 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface NSObject {}
+
+@end
+
+@interface MyClass : NSObject {}
+
+@end
+
+@interface MyClass (MyCategorie)
+
+@end
+
+@interface MySubClass : MyClass {}
+
+@end
+
+@interface MySubSubClass : MySubClass {}
+
+@end
+
+@implementation NSObject (NSObjectCategory)
+- (void)rootMethod {}
+@end
+
+@implementation MyClass
+
++ (void)myClassMethod { }
+- (void)myMethod { }
+
+@end
+
+@implementation MyClass (MyCategorie)
++ (void)myClassCategoryMethod { }
+- (void)categoryMethod {}
+@end
+
+@implementation MySubClass
+
+- (void)mySubMethod {}
+
+- (void)myTest {
+ [self mySubMethod];
+ // should lookup method in superclass implementation if available
+ [self myMethod];
+ [super myMethod];
+
+ [self categoryMethod];
+ [super categoryMethod];
+
+ // instance method of root class
+ [MyClass rootMethod];
+
+ [MyClass myClassMethod];
+ [MySubClass myClassMethod];
+
+ [MyClass myClassCategoryMethod];
+ [MySubClass myClassCategoryMethod];
+}
+
+@end
diff --git a/test/SemaObjC/method-lookup.m b/test/SemaObjC/method-lookup.m
new file mode 100644
index 000000000000..917ad6b3ee92
--- /dev/null
+++ b/test/SemaObjC/method-lookup.m
@@ -0,0 +1,34 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+typedef signed char BOOL;
+typedef int NSInteger;
+
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (BOOL)respondsToSelector:(SEL)s;
+@end
+
+@interface NSObject <NSObject> {}
+@end
+
+@class NSString, NSData, NSMutableData, NSMutableDictionary, NSMutableArray;
+
+@protocol PBXCompletionItem
+- (NSString *) name;
+- (NSInteger)priority;
+- setPriority:(NSInteger)p;
+@end
+
+@implementation PBXCodeAssistant // expected-warning{{cannot find interface declaration for 'PBXCodeAssistant'}}
+static NSMutableArray * recentCompletions = ((void *)0);
++ (float) factorForRecentCompletion:(NSString *) completion
+{
+ for (NSObject<PBXCompletionItem> * item in [self completionItems]) // expected-warning{{method '-completionItems' not found (return type defaults to 'id')}}
+ {
+ if ([item respondsToSelector:@selector(setPriority:)])
+ {
+ [(id)item setPriority:[item priority] / [PBXCodeAssistant factorForRecentCompletion:[item name]]];
+ }
+ }
+}
+@end
+
diff --git a/test/SemaObjC/method-no-context.m b/test/SemaObjC/method-no-context.m
new file mode 100644
index 000000000000..9351cb91579a
--- /dev/null
+++ b/test/SemaObjC/method-no-context.m
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+- im0 { int a; return 0; // expected-error{{missing context for method declaration}}
+// expected-error{{expected '}'}}
diff --git a/test/SemaObjC/method-not-defined.m b/test/SemaObjC/method-not-defined.m
new file mode 100644
index 000000000000..3848fa28c927
--- /dev/null
+++ b/test/SemaObjC/method-not-defined.m
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface Foo
+@end
+
+void test() {
+ Foo *fooObj;
+ id obj;
+
+ [[Foo alloc] init]; // expected-warning {{method '+alloc' not found (return type defaults to 'id')}} expected-warning {{method '-init' not found (return type defaults to 'id')}}
+ [fooObj notdefined]; // expected-warning {{method '-notdefined' not found (return type defaults to 'id')}}
+ [obj whatever:1 :2 :3]; // expected-warning {{method '-whatever:::' not found (return type defaults to 'id'))}}
+}
diff --git a/test/SemaObjC/method-sentinel-attr.m b/test/SemaObjC/method-sentinel-attr.m
new file mode 100644
index 000000000000..8f31e9ab5e41
--- /dev/null
+++ b/test/SemaObjC/method-sentinel-attr.m
@@ -0,0 +1,37 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+#define NULL (void*)0
+
+#define ATTR __attribute__ ((__sentinel__))
+
+@interface INTF
+- (void) foo1 : (int)x, ... ATTR; // expected-note {{method has been explicitly marked sentinel here}}
+- (void) foo3 : (int)x __attribute__ ((__sentinel__)) ; // expected-warning {{'sentinel' attribute only supported for variadic functions}}
+- (void) foo5 : (int)x, ... __attribute__ ((__sentinel__(1))); // expected-note {{method has been explicitly marked sentinel here}}
+- (void) foo6 : (int)x, ... __attribute__ ((__sentinel__(5))); // expected-note {{method has been explicitly marked sentinel here}}
+- (void) foo7 : (int)x, ... __attribute__ ((__sentinel__(0))); // expected-note {{method has been explicitly marked sentinel here}}
+- (void) foo8 : (int)x, ... __attribute__ ((__sentinel__("a"))); // expected-error {{'sentinel' attribute requires parameter 1 to be an integer constant}}
+- (void) foo9 : (int)x, ... __attribute__ ((__sentinel__(-1))); // expected-error {{'sentinel' parameter 1 less than zero}}
+- (void) foo10 : (int)x, ... __attribute__ ((__sentinel__(1,1)));
+- (void) foo11 : (int)x, ... __attribute__ ((__sentinel__(1,1,3))); // expected-error {{attribute requires 0, 1 or 2 argument(s)}}
+- (void) foo12 : (int)x, ... ATTR; // expected-note {{method has been explicitly marked sentinel here}}
+@end
+
+int main ()
+{
+ INTF *p;
+
+ [p foo1:1, NULL]; // OK
+ [p foo1:1, 0]; // expected-warning {{missing sentinel in method dispatch}}
+ [p foo5:1, NULL, 2]; // OK
+ [p foo5:1, 2, NULL, 1]; // OK
+ [p foo5:1, NULL, 2, 1]; // expected-warning {{missing sentinel in method dispatch}}
+
+ [p foo6:1,2,3,4,5,6,7]; // expected-warning {{missing sentinel in method dispatch}}
+ [p foo6:1,NULL,3,4,5,6,7]; // OK
+ [p foo7:1]; // expected-warning {{not enough variable arguments in 'foo7:' declaration to fit a sentinel}}
+ [p foo7:1, NULL]; // ok
+
+ [p foo12:1]; // expected-warning {{not enough variable arguments in 'foo12:' declaration to fit a sentinel}}
+}
+
diff --git a/test/SemaObjC/method-typecheck-1.m b/test/SemaObjC/method-typecheck-1.m
new file mode 100644
index 000000000000..d110c858a41a
--- /dev/null
+++ b/test/SemaObjC/method-typecheck-1.m
@@ -0,0 +1,37 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface A
+- (void) setMoo: (int) x; // expected-note {{previous definition is here}}
+- (int) setMoo1: (int) x; // expected-note {{previous definition is here}}
+- (int) setOk : (int) x : (double) d;
+@end
+
+@implementation A
+-(void) setMoo: (float) x {} // expected-warning {{conflicting parameter types in implementation of 'setMoo:': 'int' vs 'float'}}
+- (char) setMoo1: (int) x {} // expected-warning {{conflicting return type in implementation of 'setMoo1:': 'int' vs 'char'}}
+- (int) setOk : (int) x : (double) d {}
+@end
+
+
+
+@interface C
++ (void) cMoo: (int) x; // expected-note 2 {{previous definition is here}}
+@end
+
+@implementation C
++(float) cMoo: // expected-warning {{conflicting return type in implementation of 'cMoo:': 'void' vs 'float'}}
+ (float) x {} // expected-warning {{conflicting parameter types in implementation of 'cMoo:': 'int' vs 'float'}}
+@end
+
+
+@interface A(CAT)
+- (void) setCat: (int) x; // expected-note 2 {{previous definition is here}}
++ (void) cCat: (int) x; // expected-note {{previous definition is here}}
+@end
+
+@implementation A(CAT)
+-(float) setCat: // expected-warning {{conflicting return type in implementation of 'setCat:': 'void' vs 'float'}}
+(float) x {} // expected-warning {{conflicting parameter types in implementation of 'setCat:': 'int' vs 'float'}}
++ (int) cCat: (int) x {} // expected-warning {{conflicting return type in implementation of 'cCat:': 'void' vs 'int'}}
+@end
+
diff --git a/test/SemaObjC/method-typecheck-2.m b/test/SemaObjC/method-typecheck-2.m
new file mode 100644
index 000000000000..d0a091d85615
--- /dev/null
+++ b/test/SemaObjC/method-typecheck-2.m
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@protocol P
+- (void) doSomethingInProtocol: (float) x; // expected-note {{previous definition is here}}
++ (void) doSomethingClassyInProtocol: (float) x; // expected-note {{previous definition is here}}
+- (void) doNothingInProtocol : (float) x;
++ (void) doNothingClassyInProtocol : (float) x;
+@end
+
+@interface I <P>
+- (void) doSomething: (float) x; // expected-note {{previous definition is here}}
++ (void) doSomethingClassy: (int) x; // expected-note {{previous definition is here}}
+@end
+
+@interface Bar : I
+@end
+
+@implementation Bar
+- (void) doSomething: (int) x {} // expected-warning {{conflicting parameter types}}
++ (void) doSomethingClassy: (float) x{} // expected-warning {{conflicting parameter types}}
+- (void) doSomethingInProtocol: (id) x {} // expected-warning {{conflicting parameter types}}
++ (void) doSomethingClassyInProtocol: (id) x {} // expected-warning {{conflicting parameter types}}
+@end
+
+
diff --git a/test/SemaObjC/method-undef-category-warn-1.m b/test/SemaObjC/method-undef-category-warn-1.m
new file mode 100644
index 000000000000..82fd3c8ba6ff
--- /dev/null
+++ b/test/SemaObjC/method-undef-category-warn-1.m
@@ -0,0 +1,32 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface MyClass1
+@end
+
+@protocol P
+- (void) Pmeth;
+- (void) Pmeth1;
+@end
+
+@interface MyClass1(CAT) <P>
+- (void) meth2;
+@end
+
+@implementation MyClass1(CAT) // expected-warning {{incomplete implementation}} \
+ expected-warning {{method definition for 'meth2' not found}} \
+ expected-warning {{method definition for 'Pmeth' not found}}
+- (void) Pmeth1{}
+@end
+
+@interface MyClass1(DOG) <P>
+- (void)ppp;
+@end
+
+@implementation MyClass1(DOG) // expected-warning {{incomplete implementation}} \
+ expected-warning {{method definition for 'ppp' not found}} \
+ expected-warning {{method definition for 'Pmeth1' not found}}
+- (void) Pmeth {}
+@end
+
+@implementation MyClass1(CAT1)
+@end
diff --git a/test/SemaObjC/method-undef-extension-warn-1.m b/test/SemaObjC/method-undef-extension-warn-1.m
new file mode 100644
index 000000000000..7ce015f886ec
--- /dev/null
+++ b/test/SemaObjC/method-undef-extension-warn-1.m
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface MyClass
+@end
+
+@protocol P
+- (void)Pmeth;
+- (void)Pmeth1;
+@end
+
+// Class extension
+@interface MyClass () <P>
+- (void)meth2;
+@end
+
+// Add a category to test that clang does not emit warning for this method.
+@interface MyClass (Category)
+- (void)categoryMethod;
+@end
+
+@implementation MyClass // expected-warning {{incomplete implementation}} \
+ expected-warning {{method definition for 'meth2' not found}} \
+ expected-warning {{method definition for 'Pmeth1' not found}}
+- (void)Pmeth {}
+@end
diff --git a/test/SemaObjC/method-undefined-warn-1.m b/test/SemaObjC/method-undefined-warn-1.m
new file mode 100644
index 000000000000..fbb01dfb1f79
--- /dev/null
+++ b/test/SemaObjC/method-undefined-warn-1.m
@@ -0,0 +1,42 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface INTF
+- (void) meth;
+- (void) meth : (int) arg1;
+- (int) int_meth;
++ (int) cls_meth;
++ (void) cls_meth1 : (int) arg1;
+@end
+
+@implementation INTF // expected-warning {{incomplete implementation}} expected-warning {{method definition for 'int_meth' not found}} expected-warning {{method definition for 'cls_meth' not found}} expected-warning {{method definition for 'cls_meth1:' not found}}
+- (void) meth {}
+- (void) meth : (int) arg2{}
+- (void) cls_meth1 : (int) arg2{}
+@end
+
+@interface INTF1
+- (void) meth;
+- (void) meth : (int) arg1;
+- (int) int_meth;
++ (int) cls_meth;
++ (void) cls_meth1 : (int) arg1;
+@end
+
+@implementation INTF1 // expected-warning {{incomplete implementation}} expected-warning {{method definition for 'int_meth' not found}} expected-warning {{method definition for 'cls_meth' not found}} expected-warning {{method definition for 'cls_meth1:' not found}}
+- (void) meth {}
+- (void) meth : (int) arg2{}
+- (void) cls_meth1 : (int) arg2{}
+@end
+
+@interface INTF2
+- (void) meth;
+- (void) meth : (int) arg1;
+- (void) cls_meth1 : (int) arg1;
+@end
+
+@implementation INTF2
+- (void) meth {}
+- (void) meth : (int) arg2{}
+- (void) cls_meth1 : (int) arg2{}
+@end
+
diff --git a/test/SemaObjC/missing-method-context.m b/test/SemaObjC/missing-method-context.m
new file mode 100644
index 000000000000..2d0758b1fa8d
--- /dev/null
+++ b/test/SemaObjC/missing-method-context.m
@@ -0,0 +1,4 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+- (void)compilerTestAgainst; // expected-error {{missing context for method declaration}}
+
+void xx(); // expected-error {{expected method body}}
diff --git a/test/SemaObjC/newproperty-class-method-1.m b/test/SemaObjC/newproperty-class-method-1.m
new file mode 100644
index 000000000000..4946210c8dcc
--- /dev/null
+++ b/test/SemaObjC/newproperty-class-method-1.m
@@ -0,0 +1,60 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+@interface Subclass
++ (int)magicNumber;
++ (void)setMagicNumber:(int)value;
++ (void)setFakeSetterNumber:(int)value;
+@end
+
+@implementation Subclass
+int _magicNumber = 0;
++ (int)magicNumber {
+ return _magicNumber;
+}
+
++ (void)setMagicNumber:(int)value {
+ _magicNumber = value;
+}
+
++ (void)setFakeSetterNumber:(int)value {
+ _magicNumber = value;
+}
+
++ (void) classMeth
+{
+ self.magicNumber = 10;
+ if (self.magicNumber != 10)
+ abort ();
+}
+@end
+
+int main (void) {
+
+ int a;
+ Subclass.magicNumber = 2 /*[Subclass setMagicNumber:2]*/;
+ if (Subclass.magicNumber != 0)
+ abort ();
+ if (Subclass.magicNumber != 2)
+ abort ();
+ Subclass.magicNumber += 3;
+ if (Subclass.magicNumber != 5)
+ abort ();
+ Subclass.magicNumber -= 5;
+ if (Subclass.magicNumber != 0)
+ abort ();
+ /* We only have a setter in the following case. */
+ Subclass.fakeSetterNumber = 123;
+
+ /* We read it using the other getter. */
+ if (Subclass.magicNumber != 123)
+ abort ();
+ Subclass.fakeSetterNumber = Subclass.magicNumber;
+ if (Subclass.magicNumber != 123)
+ abort ();
+
+ Subclass.fakeSetterNumberX = 123; // expected-error{{property 'fakeSetterNumberX' not found on object of type 'Subclass'}}
+
+ /* Test class methods using the new syntax. */
+ [Subclass classMeth];
+ return 0;
+}
diff --git a/test/SemaObjC/no-gc-weak-test.m b/test/SemaObjC/no-gc-weak-test.m
new file mode 100644
index 000000000000..f494929ce02d
--- /dev/null
+++ b/test/SemaObjC/no-gc-weak-test.m
@@ -0,0 +1,28 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -fsyntax-only -verify %s
+
+@interface Subtask
+{
+ id _delegate;
+}
+@property(nonatomic,readwrite,assign) id __weak delegate;
+@end
+
+@implementation Subtask
+@synthesize delegate = _delegate;
+@end
+
+
+@interface PVSelectionOverlayView2
+{
+ id __weak _selectionRect;
+}
+
+@property(assign) id selectionRect;
+
+@end
+
+@implementation PVSelectionOverlayView2
+
+@synthesize selectionRect = _selectionRect;
+@end
+
diff --git a/test/SemaObjC/no-warn-synth-protocol-meth.m b/test/SemaObjC/no-warn-synth-protocol-meth.m
new file mode 100644
index 000000000000..860a0ca2befe
--- /dev/null
+++ b/test/SemaObjC/no-warn-synth-protocol-meth.m
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@protocol CYCdef
+- (int)name;
+@end
+
+@interface JSCdef <CYCdef> {
+ int name;
+}
+
+@property (assign) int name;
+@end
+
+@implementation JSCdef
+@synthesize name;
+@end
+
diff --git a/test/SemaObjC/no-warn-unimpl-method.m b/test/SemaObjC/no-warn-unimpl-method.m
new file mode 100644
index 000000000000..756c47b2fe80
--- /dev/null
+++ b/test/SemaObjC/no-warn-unimpl-method.m
@@ -0,0 +1,42 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
+// This program tests that if class implements the forwardInvocation method, then
+// every method possible is implemented in the class and should not issue
+// warning of the "Method definition not found" kind. */
+
+@interface NSObject
+@end
+
+@interface NSInvocation
+@end
+
+@interface NSProxy
+@end
+
+@protocol MyProtocol
+ -(void) doSomething;
+@end
+
+@interface DestinationClass : NSObject<MyProtocol>
+ -(void) doSomething;
+@end
+
+@implementation DestinationClass
+ -(void) doSomething
+ {
+ }
+@end
+
+@interface MyProxy : NSProxy<MyProtocol>
+{
+ DestinationClass *mTarget;
+}
+ - (id) init;
+ - (void)forwardInvocation:(NSInvocation *)anInvocation;
+@end
+
+@implementation MyProxy
+ - (void)forwardInvocation:(NSInvocation *)anInvocation
+ {
+ }
+ - (id) init {}
+@end
diff --git a/test/SemaObjC/nsobject-attribute-1.m b/test/SemaObjC/nsobject-attribute-1.m
new file mode 100644
index 000000000000..d1f673a9fba9
--- /dev/null
+++ b/test/SemaObjC/nsobject-attribute-1.m
@@ -0,0 +1,48 @@
+// RUN: clang-cc -fblocks -fsyntax-only -verify %s
+
+@interface NSObject
+- (id)self;
+- (id)copy;
+@end
+
+typedef struct _foo *__attribute__((NSObject)) Foo_ref;
+
+@interface TestObject {
+ Foo_ref dict;
+}
+@property(retain) Foo_ref dict;
+@end
+
+@implementation TestObject
+@synthesize dict;
+@end
+
+@interface NSDictionary
+- (int)retainCount;
+@end
+
+int main(int argc, char *argv[]) {
+ NSDictionary *dictRef;
+ Foo_ref foo = (Foo_ref)dictRef;
+
+ // do Properties retain?
+ int before = [dictRef retainCount];
+ int after = [dictRef retainCount];
+
+ if ([foo retainCount] != [dictRef retainCount]) {
+ }
+
+ // do Blocks retain?
+ {
+ void (^block)(void) = ^{
+ [foo self];
+ };
+ before = [foo retainCount];
+ id save = [block copy];
+ after = [foo retainCount];
+ if (after <= before) {
+ ;
+ }
+ }
+ return 0;
+}
diff --git a/test/SemaObjC/nsobject-attribute.m b/test/SemaObjC/nsobject-attribute.m
new file mode 100644
index 000000000000..3544cb139aab
--- /dev/null
+++ b/test/SemaObjC/nsobject-attribute.m
@@ -0,0 +1,36 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef struct CGColor * __attribute__ ((NSObject)) CGColorRef;
+static int count;
+static CGColorRef tmp = 0;
+
+typedef struct S1 __attribute__ ((NSObject)) CGColorRef1; // expected-error {{__attribute ((NSObject)) is for pointer types only}}
+typedef void * __attribute__ ((NSObject)) CGColorRef2; // expected-error {{__attribute ((NSObject)) is for pointer types only}}
+
+@interface HandTested {
+@public
+ CGColorRef x;
+}
+@property(copy) CGColorRef x;
+@end
+
+void setProperty(id self, id value) {
+ ((HandTested *)self)->x = value;
+}
+
+id getProperty(id self) {
+ return (id)((HandTested *)self)->x;
+}
+
+@implementation HandTested
+@synthesize x=x;
+@end
+
+int main(char *argc, char *argv[]) {
+ HandTested *to;
+ to.x = tmp; // setter
+ if (tmp != to.x)
+ to.x = tmp;
+ return 0;
+}
+
diff --git a/test/SemaObjC/objc-string-constant.m b/test/SemaObjC/objc-string-constant.m
new file mode 100644
index 000000000000..98239229a2c7
--- /dev/null
+++ b/test/SemaObjC/objc-string-constant.m
@@ -0,0 +1,39 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+#define nil 0 /* id of Nil instance */
+
+@interface NSObject
+@end
+
+@interface NSString : NSObject
+
+@end
+
+@interface NSMutableString : NSString
+
+@end
+
+@interface NSSimpleCString : NSString {
+@protected
+ char *bytes;
+ int numBytes;
+}
+@end
+
+@interface NSConstantString : NSSimpleCString
+@end
+
+
+@interface Subclass : NSObject
+- (NSString *)token;
+@end
+
+@implementation Subclass
+- (NSString *)token;
+{
+ NSMutableString *result = nil;
+
+ return (result != nil) ? result : @"";
+}
+@end
+
diff --git a/test/SemaObjC/objc2-merge-gc-attribue-decl.m b/test/SemaObjC/objc2-merge-gc-attribue-decl.m
new file mode 100644
index 000000000000..4e3b3ec7a4dd
--- /dev/null
+++ b/test/SemaObjC/objc2-merge-gc-attribue-decl.m
@@ -0,0 +1,12 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify %s
+@interface INTF @end
+
+extern INTF* p2;
+extern __strong INTF* p2;
+
+extern __strong id p1;
+extern id p1;
+
+extern id CFRunLoopGetMain();
+extern __strong id CFRunLoopGetMain();
+
diff --git a/test/SemaObjC/objc2-warn-weak-decl.m b/test/SemaObjC/objc2-warn-weak-decl.m
new file mode 100644
index 000000000000..5de52ba2203c
--- /dev/null
+++ b/test/SemaObjC/objc2-warn-weak-decl.m
@@ -0,0 +1,10 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s
+struct S {
+ __weak id p; // expected-warning {{__weak attribute cannot be specified on a field declaration}}
+};
+
+int main ()
+{
+ __weak id local; // expected-warning {{__weak attribute cannot be specified on an automatic variable}}
+}
+
diff --git a/test/SemaObjC/property-10.m b/test/SemaObjC/property-10.m
new file mode 100644
index 000000000000..81b8ee199cb2
--- /dev/null
+++ b/test/SemaObjC/property-10.m
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -Wreadonly-setter-attrs -verify %s -fblocks
+
+// Check property attribute consistency.
+
+@interface I0
+@property(readonly, readwrite) int p0; // expected-error {{property attributes 'readonly' and 'readwrite' are mutually exclusive}}
+
+@property(retain) int p1; // expected-error {{property with 'retain' attribute must be of object type}}
+
+@property(copy) int p2; // expected-error {{property with 'copy' attribute must be of object type}}
+
+@property(assign, copy) id p3_0; // expected-error {{property attributes 'assign' and 'copy' are mutually exclusive}}
+@property(assign, retain) id p3_1; // expected-error {{property attributes 'assign' and 'retain' are mutually exclusive}}
+@property(copy, retain) id p3_2; // expected-error {{property attributes 'copy' and 'retain' are mutually exclusive}}
+@property(assign, copy, retain) id p3_3; // expected-error {{property attributes 'assign' and 'copy' are mutually exclusive}}, expected-error {{property attributes 'assign' and 'retain' are mutually exclusive}}
+
+@property id p4; // 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}}
+
+@property(nonatomic,copy) int (^includeMailboxCondition)();
+@property(nonatomic,copy) int (*includeMailboxCondition2)(); // expected-error {{property with 'copy' attribute must be of object type}}
+
+@end
diff --git a/test/SemaObjC/property-11.m b/test/SemaObjC/property-11.m
new file mode 100644
index 000000000000..e8e60914716d
--- /dev/null
+++ b/test/SemaObjC/property-11.m
@@ -0,0 +1,35 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface NSSound
+@end
+@interface NSFont
+@end
+
+@interface NSSound (Adds)
+@end
+
+@implementation NSSound (Adds)
+- foo {
+ return self;
+}
+- (void)setFoo:obj {
+}
+@end
+
+@implementation NSFont (Adds)
+
+- xx {
+ NSSound *x;
+ id o;
+
+ // GCC does *not* warn about the following. Since foo/setFoo: are not in the
+ // class or category interface for NSSound, the compiler shouldn't find them.
+ // For now, we will support GCC's behavior (sigh).
+ o = [x foo];
+ o = x.foo;
+ [x setFoo:o];
+ x.foo = o;
+}
+
+@end
+
diff --git a/test/SemaObjC/property-12.m b/test/SemaObjC/property-12.m
new file mode 100644
index 000000000000..50fb63bc006b
--- /dev/null
+++ b/test/SemaObjC/property-12.m
@@ -0,0 +1,32 @@
+// RUN: clang-cc -fsyntax-only -Wreadonly-setter-attrs -verify %s
+
+@protocol P0
+@property(readonly,assign) id X; // expected-warning {{property attributes 'readonly' and 'assign' are mutually exclusive}}
+@end
+
+@protocol P1
+@property(readonly,retain) id X; // expected-warning {{property attributes 'readonly' and 'retain' are mutually exclusive}}
+@end
+
+@protocol P2
+@property(readonly,copy) id X; // expected-warning {{property attributes 'readonly' and 'copy' are mutually exclusive}}
+@end
+
+@protocol P3
+@property(readonly,readwrite) id X; // expected-error {{property attributes 'readonly' and 'readwrite' are mutually exclusive}}
+@end
+
+@protocol P4
+@property(assign,copy) id X; // expected-error {{property attributes 'assign' and 'copy' are mutually exclusive}}
+@end
+
+@protocol P5
+@property(assign,retain) id X; // expected-error {{property attributes 'assign' and 'retain' are mutually exclusive}}
+@end
+
+@protocol P6
+@property(copy,retain) id X; // expected-error {{property attributes 'copy' and 'retain' are mutually exclusive}}
+@end
+
+
+
diff --git a/test/SemaObjC/property-13.m b/test/SemaObjC/property-13.m
new file mode 100644
index 000000000000..d0e40dcf86ed
--- /dev/null
+++ b/test/SemaObjC/property-13.m
@@ -0,0 +1,77 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface NSObject
++ alloc;
+- init;
+@end
+
+@protocol Test
+ @property int required;
+
+@optional
+ @property int optional;
+ @property int optional1;
+ @property int optional_preexisting_setter_getter;
+ @property (setter = setOptional_preexisting_setter_getter: ,
+ getter = optional_preexisting_setter_getter) int optional_with_setter_getter_attr;
+@required
+ @property int required1;
+@optional
+ @property int optional_to_be_defined;
+ @property (readonly, getter = optional_preexisting_setter_getter) int optional_getter_attr;
+@end
+
+@interface Test : NSObject <Test> {
+ int ivar;
+ int ivar1;
+ int ivar2;
+}
+@property int required;
+@property int optional_to_be_defined;
+- (int) optional_preexisting_setter_getter;
+- (void) setOptional_preexisting_setter_getter:(int)value;
+@end
+
+@implementation Test
+@synthesize required = ivar;
+@synthesize required1 = ivar1;
+@synthesize optional_to_be_defined = ivar2;
+- (int) optional_preexisting_setter_getter { return ivar; }
+- (void) setOptional_preexisting_setter_getter:(int)value
+ {
+ ivar = value;
+ }
+- (void) setOptional_getter_attr:(int)value { ivar = value; }
+@end
+
+int main ()
+{
+ Test *x = [[Test alloc] init];
+ /* 1. Test of a requred property */
+ x.required1 = 100;
+ if (x.required1 != 100)
+ abort ();
+
+ /* 2. Test of a synthesize optional property */
+ x.optional_to_be_defined = 123;
+ if (x.optional_to_be_defined != 123)
+ abort ();
+
+ /* 3. Test of optional property with pre-sxisting defined setter/getter */
+ x.optional_preexisting_setter_getter = 200;
+ if (x.optional_preexisting_setter_getter != 200)
+ abort ();
+
+ /* 4. Test of optional property with setter/getter attribute */
+ if (x.optional_with_setter_getter_attr != 200)
+ abort ();
+ return 0;
+
+ /* 5. Test of optional property with getter attribute and default setter method. */
+ x.optional_getter_attr = 1000;
+ if (x.optional_getter_attr != 1000)
+ abort ();
+
+ return 0;
+}
+
diff --git a/test/SemaObjC/property-2.m b/test/SemaObjC/property-2.m
new file mode 100644
index 000000000000..159e06b07afa
--- /dev/null
+++ b/test/SemaObjC/property-2.m
@@ -0,0 +1,63 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface Tester
+@property char PropertyAtomic_char;
+@property short PropertyAtomic_short;
+@property int PropertyAtomic_int;
+@property long PropertyAtomic_long;
+@property long long PropertyAtomic_longlong;
+@property float PropertyAtomic_float;
+@property double PropertyAtomic_double;
+@property(assign) id PropertyAtomic_id;
+@property(retain) id PropertyAtomicRetained_id;
+@property(copy) id PropertyAtomicRetainedCopied_id;
+@property(retain) id PropertyAtomicRetainedGCOnly_id;
+@property(copy) id PropertyAtomicRetainedCopiedGCOnly_id;
+@end
+
+@implementation Tester
+@dynamic PropertyAtomic_char;
+@dynamic PropertyAtomic_short;
+@dynamic PropertyAtomic_int;
+@dynamic PropertyAtomic_long;
+@dynamic PropertyAtomic_longlong;
+@dynamic PropertyAtomic_float;
+@dynamic PropertyAtomic_double;
+@dynamic PropertyAtomic_id;
+@dynamic PropertyAtomicRetained_id;
+@dynamic PropertyAtomicRetainedCopied_id;
+@dynamic PropertyAtomicRetainedGCOnly_id;
+@dynamic PropertyAtomicRetainedCopiedGCOnly_id;
+@end
+
+@interface SubClass : Tester
+{
+ char PropertyAtomic_char;
+ short PropertyAtomic_short;
+ int PropertyAtomic_int;
+ long PropertyAtomic_long;
+ long long PropertyAtomic_longlong;
+ float PropertyAtomic_float;
+ double PropertyAtomic_double;
+ id PropertyAtomic_id;
+ id PropertyAtomicRetained_id;
+ id PropertyAtomicRetainedCopied_id;
+ id PropertyAtomicRetainedGCOnly_id;
+ id PropertyAtomicRetainedCopiedGCOnly_id;
+}
+@end
+
+@implementation SubClass
+@synthesize PropertyAtomic_char;
+@synthesize PropertyAtomic_short;
+@synthesize PropertyAtomic_int;
+@synthesize PropertyAtomic_long;
+@synthesize PropertyAtomic_longlong;
+@synthesize PropertyAtomic_float;
+@synthesize PropertyAtomic_double;
+@synthesize PropertyAtomic_id;
+@synthesize PropertyAtomicRetained_id;
+@synthesize PropertyAtomicRetainedCopied_id;
+@synthesize PropertyAtomicRetainedGCOnly_id;
+@synthesize PropertyAtomicRetainedCopiedGCOnly_id;
+@end
diff --git a/test/SemaObjC/property-3.m b/test/SemaObjC/property-3.m
new file mode 100644
index 000000000000..a66b3d5e1e16
--- /dev/null
+++ b/test/SemaObjC/property-3.m
@@ -0,0 +1,14 @@
+// RUN: clang-cc -verify %s
+
+@interface I
+{
+ id d1;
+}
+@property (readwrite, copy) id d1;
+@property (readwrite, copy) id d2;
+@end
+
+@interface NOW : I
+@property (readonly) id d1; // expected-warning {{attribute 'readonly' of property 'd1' restricts attribute 'readwrite' of property inherited from 'I'}} expected-warning {{property 'd1' 'copy' attribute does not match the property inherited from 'I'}}
+@property (readwrite, copy) I* d2;
+@end
diff --git a/test/SemaObjC/property-4.m b/test/SemaObjC/property-4.m
new file mode 100644
index 000000000000..56db28274c1a
--- /dev/null
+++ b/test/SemaObjC/property-4.m
@@ -0,0 +1,29 @@
+// RUN: clang-cc -verify %s
+
+@interface Object
+@end
+
+@protocol ProtocolObject
+@property int class;
+@property (copy) id MayCauseError;
+@end
+
+@protocol ProtocolDerivedGCObject <ProtocolObject>
+@property int Dclass;
+@end
+
+@interface GCObject : Object <ProtocolDerivedGCObject> {
+ int ifield;
+ int iOwnClass;
+ int iDclass;
+}
+@property int OwnClass;
+@end
+
+@interface ReleaseObject : GCObject <ProtocolObject> {
+ int newO;
+ int oldO;
+}
+@property (retain) id MayCauseError; // expected-warning {{property 'MayCauseError' 'copy' attribute does not match the property inherited from 'ProtocolObject'}}
+@end
+
diff --git a/test/SemaObjC/property-5.m b/test/SemaObjC/property-5.m
new file mode 100644
index 000000000000..f463aae62910
--- /dev/null
+++ b/test/SemaObjC/property-5.m
@@ -0,0 +1,34 @@
+// RUN: clang-cc -verify %s
+
+@protocol P1 @end
+@protocol P2 @end
+@protocol P3 @end
+
+@interface NSData @end
+
+@interface MutableNSData : NSData @end
+
+@interface Base : NSData <P1>
+@property(readonly) id ref;
+@property(readonly) Base *p_base;
+@property(readonly) NSData *nsdata;
+@property(readonly) NSData * m_nsdata;
+@end
+
+@interface Data : Base <P1, P2>
+@property(readonly) NSData *ref;
+@property(readonly) Data *p_base;
+@property(readonly) MutableNSData * m_nsdata;
+@end
+
+@interface MutedData: Data
+@property(readonly) id p_base;
+@end
+
+@interface ConstData : Data <P1, P2, P3>
+@property(readonly) ConstData *p_base;
+@end
+
+void foo(Base *b, id x) {
+ [ b setRef: x ]; // expected-warning {{method '-setRef:' not found}}
+}
diff --git a/test/SemaObjC/property-6.m b/test/SemaObjC/property-6.m
new file mode 100644
index 000000000000..8f77cf1ad212
--- /dev/null
+++ b/test/SemaObjC/property-6.m
@@ -0,0 +1,69 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+# 1 "<command line>"
+# 1 "/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h" 1 3
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+typedef struct _NSZone NSZone;
+
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
++ class;
+@end
+
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end
+
+@protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+
+@protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+
+@interface NSObject <NSObject> {}
+@end
+
+typedef struct {} NSFastEnumerationState;
+
+@protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end
+
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+@end
+
+@interface NSMutableArray : NSArray
+- (void)addObject:(id)anObject;
++ (id)arrayWithCapacity:(int)numItems;
+@end
+
+@interface NSBundle : NSObject {}
++ (NSBundle *)bundleForClass:(Class)aClass;
+- (NSString *)bundlePath;
+- (void)setBundlePath:(NSString *)x;
+@end
+
+@interface NSException : NSObject <NSCopying, NSCoding> {}
+@end
+
+@class NSArray, NSDictionary, NSError, NSString, NSURL;
+
+@interface DTPlugInManager : NSObject
+@end
+
+@implementation DTPlugInManager
++ (DTPlugInManager *)defaultPlugInManager {
+ @try {
+ NSMutableArray *plugInPaths = [NSMutableArray arrayWithCapacity:100];
+ NSBundle *frameworkBundle = [NSBundle bundleForClass:[DTPlugInManager class]];
+ frameworkBundle.bundlePath = 0;
+ [plugInPaths addObject:frameworkBundle.bundlePath];
+ }
+ @catch (NSException *exception) {}
+}
+@end
diff --git a/test/SemaObjC/property-7.m b/test/SemaObjC/property-7.m
new file mode 100644
index 000000000000..99c16cef73d8
--- /dev/null
+++ b/test/SemaObjC/property-7.m
@@ -0,0 +1,34 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+typedef signed char BOOL;
+typedef struct _NSZone NSZone;
+
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+@end
+
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end
+
+@interface NSObject <NSObject> {}
+@end
+
+@class NSString, NSData, NSMutableData, NSMutableDictionary, NSMutableArray;
+
+@interface SCMObject : NSObject <NSCopying> {}
+ @property(assign) SCMObject *__attribute__((objc_gc(weak))) parent;
+@end
+
+@interface SCMNode : SCMObject
+{
+ NSString *_name;
+}
+@property(copy) NSString *name;
+@end
+
+@implementation SCMNode
+ @synthesize name = _name;
+ - (void) setParent:(SCMObject *__attribute__((objc_gc(weak)))) inParent {
+ super.parent = inParent;
+ }
+@end
diff --git a/test/SemaObjC/property-8.m b/test/SemaObjC/property-8.m
new file mode 100644
index 000000000000..49bd409f27c5
--- /dev/null
+++ b/test/SemaObjC/property-8.m
@@ -0,0 +1,74 @@
+// RUN: clang-cc -fsyntax-only -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 NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
+
+@interface NSObject <NSObject> {} @end
+
+typedef float CGFloat;
+
+typedef enum { NSMinXEdge = 0, NSMinYEdge = 1, NSMaxXEdge = 2, NSMaxYEdge = 3 } NSFastEnumerationState;
+
+@protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end
+
+@class NSString;
+
+@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+@end
+
+extern NSString * const NSBundleDidLoadNotification;
+
+@interface NSObject(NSKeyValueObserving)
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
+- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
+@end
+
+enum { NSCaseInsensitivePredicateOption = 0x01, NSDiacriticInsensitivePredicateOption = 0x02 };
+
+@interface NSResponder : NSObject <NSCoding> {}
+@end
+
+extern NSString * const NSFullScreenModeAllScreens;
+@interface NSWindowController : NSResponder <NSCoding> {}
+@end
+
+extern NSString *NSAlignmentBinding ;
+
+@interface _XCOQQuery : NSObject {}
+@end
+
+extern NSString *PBXWindowDidChangeFirstResponderNotification;
+
+@interface PBXModule : NSWindowController {}
+@end
+
+@class _XCOQHelpTextBackgroundView;
+@interface PBXOpenQuicklyModule : PBXModule
+{
+@private
+ _XCOQQuery *_query;
+}
+@end
+
+@interface PBXOpenQuicklyModule ()
+@property(readwrite, retain) _XCOQQuery *query;
+@end
+
+@implementation PBXOpenQuicklyModule
+@synthesize query = _query;
+- (void) _clearQuery
+{
+ [self.query removeObserver: self forKeyPath: @"matches"];
+}
+@end
+
diff --git a/test/SemaObjC/property-9-impl-method.m b/test/SemaObjC/property-9-impl-method.m
new file mode 100644
index 000000000000..c97f38891190
--- /dev/null
+++ b/test/SemaObjC/property-9-impl-method.m
@@ -0,0 +1,94 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+// rdar://5967199
+
+typedef signed char BOOL;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+
+@protocol NSObject
+- (BOOL) isEqual:(id) object;
+@end
+
+@protocol NSCoding
+- (void) encodeWithCoder:(NSCoder *) aCoder;
+@end
+
+@interface NSObject < NSObject > {}
+@end
+
+typedef float CGFloat;
+typedef struct _NSPoint {} NSSize;
+typedef struct _NSRect {} NSRect;
+typedef enum { NSMinXEdge = 0, NSMinYEdge = 1, NSMaxXEdge = 2, NSMaxYEdge = 3} NSRectEdge;
+extern void NSDivideRect(NSRect inRect, NSRect * slice, NSRect * rem, CGFloat amount, NSRectEdge edge);
+
+@interface NSResponder:NSObject < NSCoding > {}
+@end
+
+@protocol NSAnimatablePropertyContainer
+- (id) animator;
+@end
+
+extern NSString *NSAnimationTriggerOrderIn;
+
+@interface NSView:NSResponder < NSAnimatablePropertyContainer > {}
+-(NSRect) bounds;
+@end
+
+enum {
+ NSBackgroundStyleLight = 0, NSBackgroundStyleDark, NSBackgroundStyleRaised, NSBackgroundStyleLowered
+};
+
+@interface NSTabView:NSView {}
+@end
+
+@ class OrganizerTabHeader;
+
+@interface OrganizerTabView:NSTabView {}
+@property(assign)
+NSSize minimumSize;
+@end
+
+@interface OrganizerTabView()
+@property(readonly) OrganizerTabHeader *tabHeaderView;
+@property(readonly) NSRect headerRect;
+@end
+
+@implementation OrganizerTabView
+@dynamic tabHeaderView, headerRect, minimumSize;
+-(CGFloat) tabAreaThickness {}
+-(NSRectEdge) rectEdgeForTabs {
+ NSRect dummy, result = {};
+ NSDivideRect(self.bounds, &result, &dummy, self.tabAreaThickness, self.rectEdgeForTabs);
+}
+@end
+
+@class NSImage;
+
+@interface XCImageArchiveEntry : NSObject
+{
+ NSImage *_cachedImage;
+}
+
+@end
+
+@implementation XCImageArchiveEntry
+
+- (NSImage *)image
+{
+ return _cachedImage;
+}
+
+@end
+
+@interface XCImageArchive : NSObject
+@end
+
+@implementation XCImageArchive
+
+- (NSImage *)imageNamed:(NSString *)name
+{
+ XCImageArchiveEntry * entry;
+ return entry ? entry.image : ((void *)0);
+}
+
+@end
diff --git a/test/SemaObjC/property-9.m b/test/SemaObjC/property-9.m
new file mode 100644
index 000000000000..752f9c09ebf6
--- /dev/null
+++ b/test/SemaObjC/property-9.m
@@ -0,0 +1,86 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+typedef signed char BOOL;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+
+@interface NSObject <NSObject> {} @end
+
+@interface _NSServicesInContextMenu : NSObject {
+ id _requestor;
+ NSObject *_appleEventDescriptor;
+}
+
+@property (retain, nonatomic) id requestor;
+@property (retain, nonatomic) id appleEventDescriptor;
+
+@end
+
+@implementation _NSServicesInContextMenu
+
+@synthesize requestor = _requestor, appleEventDescriptor = _appleEventDescriptor;
+
+@end
+
+@class NSString;
+
+@protocol MyProtocol
+- (NSString *)stringValue;
+@end
+
+@interface MyClass : NSObject {
+ id _myIvar;
+}
+@property (readwrite, retain) id<MyProtocol> myIvar;
+@end
+
+@implementation MyClass
+@synthesize myIvar = _myIvar;
+@end
+
+
+@interface BadPropClass
+{
+ int _awesome;
+}
+
+@property (readonly) int; // expected-error {{declaration does not declare anything}}
+@property (readonly) ; // expected-error {{type name requires a specifier or qualifier}} \
+ expected-error {{declaration does not declare anything}}
+@property (readonly) int : 4; // expected-error {{property requires fields to be named}}
+
+
+// test parser recovery: rdar://6254579
+@property ( // expected-note {{to match this '('}}
+ readonly getter=isAwesome) // expected-error {{error: expected ')'}}
+
+ int _awesome;
+@property (readonlyx) // expected-error {{unknown property attribute 'readonlyx'}}
+ int _awesome2;
+
+@property ( // expected-note {{to match this '('}}
+ +) // expected-error {{error: expected ')'}}
+
+ int _awesome3;
+
+@end
+
+@protocol PVImageViewProtocol
+@property int inEyeDropperMode;
+@end
+
+@interface Cls
+@property int inEyeDropperMode;
+@end
+
+@interface PVAdjustColor @end
+
+@implementation PVAdjustColor
+
+- xx {
+ id <PVImageViewProtocol> view;
+ Cls *c;
+
+ c.inEyeDropperMode = 1;
+ view.inEyeDropperMode = 1;
+}
+@end
diff --git a/test/SemaObjC/property-category-1.m b/test/SemaObjC/property-category-1.m
new file mode 100644
index 000000000000..6695239fd352
--- /dev/null
+++ b/test/SemaObjC/property-category-1.m
@@ -0,0 +1,52 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface Object
++ (id)new;
+@end
+
+@interface ReadOnly : Object
+{
+ int _object;
+ int _Anotherobject;
+}
+@property(readonly) int object;
+@property(readonly) int Anotherobject;
+@end
+
+@interface ReadOnly ()
+@property(readwrite) int object;
+@property(readwrite, setter = myAnotherobjectSetter:) int Anotherobject;
+@end
+
+@implementation ReadOnly
+@synthesize object = _object;
+@synthesize Anotherobject = _Anotherobject;
+- (void) myAnotherobjectSetter : (int)val {
+ _Anotherobject = val;
+}
+@end
+
+int main(int argc, char **argv) {
+ ReadOnly *test = [ReadOnly new];
+ test.object = 12345;
+ test.Anotherobject = 200;
+ return test.object - 12345 + test.Anotherobject - 200;
+}
+
+///
+
+@interface I0
+@property(readonly) int p0; // expected-warning {{property 'p0' requires method 'p0' to be defined}}
+@end
+
+@interface I0 (Cat0)
+@end
+
+@interface I0 (Cat1)
+@end
+
+@implementation I0 // expected-note {{implementation is here}}
+- (void) foo {
+ self.p0 = 0; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+}
+@end
diff --git a/test/SemaObjC/property-category-2.m b/test/SemaObjC/property-category-2.m
new file mode 100644
index 000000000000..c245e36819cc
--- /dev/null
+++ b/test/SemaObjC/property-category-2.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// Test that a property can be synthesize in a category
+// implementation with no error.
+
+@protocol MyProtocol
+@property float myFloat;
+@property float anotherFloat;
+@end
+
+@interface MyObject { float anotherFloat; }
+@end
+
+@interface MyObject (CAT) <MyProtocol>
+@end
+
+@implementation MyObject (CAT)
+@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
new file mode 100644
index 000000000000..bf9e8cbd9d9f
--- /dev/null
+++ b/test/SemaObjC/property-category-3.m
@@ -0,0 +1,31 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@protocol P
+ @property(readonly) int X;
+@end
+
+@protocol P1<P>
+ @property (copy) id ID;
+@end
+
+@interface I
+@end
+
+@interface I (Cat) <P>
+@property float X; // expected-warning {{property type 'float' is incompatible with type 'int' inherited from 'P'}}
+@end
+
+@interface I (Cat2) <P1>
+@property (retain) id ID; // expected-warning {{property 'ID' 'copy' attribute does not match the property inherited from 'P1'}}
+@end
+
+
+@interface A
+@property(assign) int categoryProperty;
+@end
+
+// Don't issue warning on unimplemented setter/getter
+// because property is @dynamic.
+@implementation A
+@dynamic categoryProperty;
+@end
diff --git a/test/SemaObjC/property-error-readonly-assign.m b/test/SemaObjC/property-error-readonly-assign.m
new file mode 100644
index 000000000000..edeff09dfadd
--- /dev/null
+++ b/test/SemaObjC/property-error-readonly-assign.m
@@ -0,0 +1,21 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface A
+ -(int) x;
+@property (readonly) int x;
+@property int ok;
+@end
+
+@interface B
+ -(void) setOk:(int)arg;
+ -(int) x;
+ -(int) ok;
+@end
+
+void f0(A *a, B* b) {
+ a.x = 10; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+ a.ok = 20;
+ b.x = 10; // expected-error {{setter method is needed to assign to object using property assignment syntax}}
+ b.ok = 20;
+}
+
diff --git a/test/SemaObjC/property-impl-misuse.m b/test/SemaObjC/property-impl-misuse.m
new file mode 100644
index 000000000000..7b956b5f7b4d
--- /dev/null
+++ b/test/SemaObjC/property-impl-misuse.m
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface I {
+ int Y;
+}
+@property int X;
+@property int Y;
+@property int Z;
+@end
+
+@implementation I
+@dynamic X; // expected-note {{previous declaration is here}}
+@dynamic X; // expected-error {{property 'X' is already implemented}}
+@synthesize Y; // expected-note {{previous use is here}}
+@synthesize Z=Y; // expected-error {{synthesized properties 'Z' and 'Y' both claim ivar 'Y'}}
+@end
diff --git a/test/SemaObjC/property-inherited.m b/test/SemaObjC/property-inherited.m
new file mode 100644
index 000000000000..6c06b90a9f0a
--- /dev/null
+++ b/test/SemaObjC/property-inherited.m
@@ -0,0 +1,44 @@
+// RUN: clang-cc %s -fsyntax-only -verify
+
+// <rdar://problem/6497242> Inherited overridden protocol declared objects don't work
+
+@protocol NSObject @end
+@interface NSObject @end
+
+@protocol FooDelegate<NSObject>
+@optional
+- (void)fooTask;
+@end
+
+@protocol BarDelegate<NSObject, FooDelegate>
+@optional
+- (void)barTask;
+@end
+
+@interface Foo : NSObject {
+ id _delegate;
+}
+@property(nonatomic, assign) id<FooDelegate> delegate;
+@property(nonatomic, assign) id<BarDelegate> delegate2;
+@end
+@interface Bar : Foo {
+}
+@property(nonatomic, assign) id<BarDelegate> delegate;
+@property(nonatomic, assign) id<FooDelegate> delegate2; // expected-warning{{property type 'id<FooDelegate>' is incompatible with type 'id<BarDelegate>' inherited from 'Foo'}}
+@end
+
+@interface NSData @end
+
+@interface NSMutableData : NSData @end
+
+@interface Base : NSData
+@property(assign) id ref;
+@property(assign) Base *p_base;
+@property(assign) NSMutableData *p_data;
+@end
+
+@interface Data : Base
+@property(assign) NSData *ref;
+@property(assign) Data *p_base;
+@property(assign) NSData *p_data; // expected-warning{{property type 'NSData *' is incompatible with type 'NSMutableData *' inherited from 'Base'}}
+@end
diff --git a/test/SemaObjC/property-ivar-mismatch.m b/test/SemaObjC/property-ivar-mismatch.m
new file mode 100644
index 000000000000..75c1e97c4ee9
--- /dev/null
+++ b/test/SemaObjC/property-ivar-mismatch.m
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// Test that arithmatic types on property and its ivar have exact match.
+
+@interface Test4
+{
+ char ivar;
+}
+@property int prop;
+@end
+
+@implementation Test4
+@synthesize prop = ivar; // expected-error {{type of property 'prop' does not match type of ivar 'ivar'}}
+@end
+
diff --git a/test/SemaObjC/property-method-lookup-impl.m b/test/SemaObjC/property-method-lookup-impl.m
new file mode 100644
index 000000000000..ed7e9bcd4315
--- /dev/null
+++ b/test/SemaObjC/property-method-lookup-impl.m
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface SSyncCEList
+{
+ id _list;
+}
+@end
+
+@implementation SSyncCEList
+
+- (id) list
+{
+}
+@end
+
+@interface SSyncConflictList : SSyncCEList
+@end
+
+@implementation SSyncConflictList
+
+- (id)Meth : (SSyncConflictList*)other
+ {
+ return other.list;
+ }
+@end
+
diff --git a/test/SemaObjC/property-missing.m b/test/SemaObjC/property-missing.m
new file mode 100644
index 000000000000..1aa94ce71b25
--- /dev/null
+++ b/test/SemaObjC/property-missing.m
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// PR3234
+
+@protocol NSCopying @end
+@interface NSObject @end
+
+void f1(NSObject *o)
+{
+ o.foo; // expected-error{{property 'foo' not found on object of type 'NSObject *'}}
+}
+
+void f2(id<NSCopying> o)
+{
+ o.foo; // expected-error{{property 'foo' not found on object of type 'id<NSCopying>'}}
+}
+
+void f3(id o)
+{
+ o.foo; // expected-error{{member reference base type 'id' is not a structure or union}}
+}
+
diff --git a/test/SemaObjC/property-nonfragile-abi.m b/test/SemaObjC/property-nonfragile-abi.m
new file mode 100644
index 000000000000..e2de77d3a28c
--- /dev/null
+++ b/test/SemaObjC/property-nonfragile-abi.m
@@ -0,0 +1,21 @@
+// RUN: clang-cc -fsyntax-only -triple x86_64-apple-darwin9 -verify %s
+
+typedef signed char BOOL;
+
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+@end
+
+@interface NSObject <NSObject> {}
+@end
+
+@interface XCDeviceWillExecuteInfoBaton : NSObject {}
+ @property (retain) __attribute__((objc_gc(strong))) NSString *sdkPath;
+@end
+
+@implementation XCDeviceWillExecuteInfoBaton
+ @synthesize sdkPath;
+@end
+
diff --git a/test/SemaObjC/property-noprotocol-warning.m b/test/SemaObjC/property-noprotocol-warning.m
new file mode 100644
index 000000000000..95ec15aa1e0c
--- /dev/null
+++ b/test/SemaObjC/property-noprotocol-warning.m
@@ -0,0 +1,36 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+
+@interface Object
++ (id) new;
+@end
+
+@protocol GCObject
+@property int class;
+@end
+
+@protocol DerivedGCObject <GCObject>
+@property int Dclass;
+@end
+
+@interface GCObject : Object <DerivedGCObject> {
+ int ifield;
+ int iOwnClass;
+ int iDclass;
+}
+@property int OwnClass;
+@end
+
+@implementation GCObject : Object
+@synthesize class=ifield;
+@synthesize Dclass=iDclass;
+@synthesize OwnClass=iOwnClass;
+@end
+
+int main(int argc, char **argv) {
+ GCObject *f = [GCObject new];
+ f.class = 5;
+ f.Dclass = 1;
+ f.OwnClass = 3;
+ return f.class + f.Dclass + f.OwnClass - 9;
+}
diff --git a/test/SemaObjC/property-redundant-decl-accessor.m b/test/SemaObjC/property-redundant-decl-accessor.m
new file mode 100644
index 000000000000..ffd5129c8e5a
--- /dev/null
+++ b/test/SemaObjC/property-redundant-decl-accessor.m
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -Werror -verify %s
+
+@interface MyClass {
+ const char *_myName;
+}
+
+@property const char *myName;
+
+- (const char *)myName;
+- (void)setMyName:(const char *)name;
+
+@end
+
+@implementation MyClass
+
+@synthesize myName = _myName;
+
+@end
diff --git a/test/SemaObjC/property-typecheck-1.m b/test/SemaObjC/property-typecheck-1.m
new file mode 100644
index 000000000000..ca8a1393b01b
--- /dev/null
+++ b/test/SemaObjC/property-typecheck-1.m
@@ -0,0 +1,101 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface A
+-(float) x; // expected-note {{declared at}}
+@property int x; // expected-warning {{type of property 'x' does not match type of accessor 'x'}}
+@end
+
+@interface A (Cat)
+@property int moo; // expected-note {{previous definition is here}}
+@end
+
+@implementation A (Cat)
+-(int) moo {
+ return 0;
+}
+-(void) setMoo: (float) x { // expected-warning {{conflicting parameter types in implementation of 'setMoo:': 'int' vs 'float'}}
+}
+@end
+
+
+typedef int T[2];
+typedef void (F)(void);
+
+@interface C
+@property(assign) T p2; // expected-error {{property cannot have array or function type 'T'}}
+
+@property(assign) F f2; // expected-error {{property cannot have array or function type 'F'}}
+
+@end
+
+
+@class SSyncSet;
+
+@interface SPeer
+ @property(nonatomic,readonly,retain) SSyncSet* syncSet;
+@end
+
+@class SSyncSet_iDisk;
+
+@interface SPeer_iDisk_remote1 : SPeer
+- (SSyncSet_iDisk*) syncSet; // expected-note {{declared at}}
+@end
+
+@interface SPeer_iDisk_local
+- (SSyncSet_iDisk*) syncSet;
+@end
+
+@interface SSyncSet
+@end
+
+@interface SSyncSet_iDisk
+@property(nonatomic,readonly,retain) SPeer_iDisk_local* localPeer;
+@end
+
+@interface SPeer_iDisk_remote1 (protected)
+@end
+
+@implementation SPeer_iDisk_remote1 (protected)
+- (id) preferredSource1
+{
+ return self.syncSet.localPeer; // expected-warning {{type of property 'syncSet' does not match type of accessor 'syncSet'}}
+}
+@end
+
+@interface NSArray @end
+
+@interface NSMutableArray : NSArray
+@end
+
+@interface Class1
+{
+ NSMutableArray* pieces;
+ NSArray* first;
+}
+
+@property (readonly) NSArray* pieces; // expected-warning {{type of property 'pieces' does not match type of accessor 'pieces'}}
+@property (readonly) NSMutableArray* first;
+
+- (NSMutableArray*) pieces; // expected-note {{declared at}} // expected-note {{declared at}}
+- (NSArray*) first;
+@end
+
+@interface Class2 {
+ Class1* container;
+}
+
+@end
+
+@implementation Class2
+
+- (id) lastPiece
+{
+ return container.pieces; // expected-warning {{type of property 'pieces' does not match type of accessor 'pieces'}}
+}
+
+- (id)firstPeice
+{
+ return container.first;
+}
+@end
+
diff --git a/test/SemaObjC/property-user-setter.m b/test/SemaObjC/property-user-setter.m
new file mode 100644
index 000000000000..9b0380ede88e
--- /dev/null
+++ b/test/SemaObjC/property-user-setter.m
@@ -0,0 +1,90 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface I0
+@property(readonly) int x;
+@property(readonly) int y;
+@property(readonly) int z;
+-(void) setY: (int) y0;
+@end
+
+@interface I0 (Cat0)
+-(void) setX: (int) a0;
+@end
+
+@implementation I0
+@dynamic x;
+@dynamic y;
+@dynamic z;
+-(void) setY: (int) y0{}
+
+-(void) im0 {
+ self.x = 0;
+ self.y = 2;
+ self.z = 2; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+}
+@end
+
+// Test when property is 'readonly' but it has a setter in
+// its implementation only.
+@interface I1 {
+}
+@property(readonly) int identifier;
+@end
+
+
+@implementation I1
+@dynamic identifier;
+- (void)setIdentifier:(int)ident {}
+
+- (id)initWithIdentifier:(int)Arg {
+ self.identifier = 0;
+}
+
+@end
+
+
+// Also in a category implementation
+@interface I1(CAT)
+@property(readonly) int rprop;
+@end
+
+
+@implementation I1(CAT)
+@dynamic rprop;
+- (void)setRprop:(int)ident {}
+
+- (id)initWithIdentifier:(int)Arg {
+ self.rprop = 0;
+}
+
+@end
+
+static int g_val;
+
+@interface Root
++ alloc;
+- init;
+@end
+
+@interface Subclass : Root
+{
+ int setterOnly;
+}
+- (void) setSetterOnly:(int)value;
+@end
+
+@implementation Subclass
+- (void) setSetterOnly:(int)value {
+ setterOnly = value;
+ g_val = setterOnly;
+}
+@end
+
+int main (void) {
+ Subclass *x = [[Subclass alloc] init];
+
+ x.setterOnly = 4;
+ if (g_val != 4)
+ abort ();
+ return 0;
+}
diff --git a/test/SemaObjC/property-weak.m b/test/SemaObjC/property-weak.m
new file mode 100644
index 000000000000..293432fc828f
--- /dev/null
+++ b/test/SemaObjC/property-weak.m
@@ -0,0 +1,5 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -fsyntax-only -verify %s
+
+@interface foo
+@property(nonatomic) int foo __attribute__((weak_import));
+@end
diff --git a/test/SemaObjC/property.m b/test/SemaObjC/property.m
new file mode 100644
index 000000000000..cf2624f8204d
--- /dev/null
+++ b/test/SemaObjC/property.m
@@ -0,0 +1,55 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -fsyntax-only -verify %s
+
+@interface I
+{
+ int IVAR;
+ int name;
+}
+@property int d1;
+@property id prop_id; // 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}}
+@property int name;
+@end
+
+@interface I(CAT)
+@property int d1;
+@end
+
+@implementation I
+@synthesize d1; // expected-error {{synthesized property 'd1' must either be named the same as}}
+@dynamic bad; // expected-error {{property implementation must have its declaration in interface 'I'}}
+@synthesize prop_id; // expected-error {{synthesized property 'prop_id' must either be named the same}} // expected-note {{previous declaration is here}}
+@synthesize prop_id = IVAR; // expected-error {{type of property 'prop_id' does not match type of ivar 'IVAR'}} // expected-error {{property 'prop_id' is already implemented}}
+@synthesize name; // OK! property with same name as an accessible ivar of same name
+@end
+
+@implementation I(CAT)
+@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
+
+@implementation E // expected-warning {{cannot find interface declaration for 'E'}}
+@dynamic d; // expected-error {{property implementation must have its declaration in interface 'E'}}
+@end
+
+@implementation Q(MYCAT) // expected-error {{cannot find interface declaration for 'Q'}}
+@dynamic d; // expected-error {{property implementation in a category with no category declaration}}
+@end
+
+@interface Foo
+@property double bar;
+@end
+
+int func1() {
+ id foo;
+ double bar = [foo bar];
+ return 0;
+}
+
+// PR3932
+typedef id BYObjectIdentifier;
+@interface Foo1 {
+ void *isa;
+}
+@property(copy) BYObjectIdentifier identifier;
+@end
+
diff --git a/test/SemaObjC/props-on-prots.m b/test/SemaObjC/props-on-prots.m
new file mode 100644
index 000000000000..7bee8a0bc319
--- /dev/null
+++ b/test/SemaObjC/props-on-prots.m
@@ -0,0 +1,65 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+typedef signed char BOOL;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+
+@protocol NSObject
+- (BOOL) isEqual:(id) object;
+@end
+
+@protocol NSCoding
+- (void) encodeWithCoder:(NSCoder *) aCoder;
+@end
+
+@interface NSObject < NSObject > {} @end
+
+typedef float CGFloat;
+
+@interface NSResponder:NSObject < NSCoding > {} @end
+
+@class XCElementView;
+
+typedef struct _XCElementInset {} XCElementInset;
+
+@protocol XCElementP < NSObject >
+-(id) vertical;
+@end
+
+@protocol XCElementDisplayDelegateP;
+@protocol XCElementTabMarkerP;
+
+typedef NSObject < XCElementTabMarkerP > XCElementTabMarker;
+
+@protocol XCElementTabberP < XCElementP >
+-(void) setMarker:(XCElementTabMarker *) marker;
+@end
+
+typedef NSObject < XCElementTabberP > XCElementTabber;
+
+@protocol XCElementTabMarkerP < NSObject >
+@property(nonatomic)
+BOOL variableSized;
+@end
+
+@protocol XCElementJustifierP < XCElementP >
+-(void) setHJustification:(CGFloat) hJust;
+@end
+
+typedef NSObject < XCElementJustifierP > XCElementJustifier;
+@interface XCElementImp:NSObject < XCElementP > {}
+@end
+
+@class XCElementImp;
+
+@interface XCElementTabberImp:XCElementImp < XCElementTabberP > {
+ XCElementTabMarker *_marker;
+}
+@end
+
+@implementation XCElementTabberImp
+- (void) setMarker:(XCElementTabMarker *) marker {
+ if (_marker && _marker.variableSized) {
+ }
+}
+- (id)vertical { return self; }
+- (BOOL)isEqual:x { return 1; }
+@end
diff --git a/test/SemaObjC/protocol-archane.m b/test/SemaObjC/protocol-archane.m
new file mode 100644
index 000000000000..3e70c0509652
--- /dev/null
+++ b/test/SemaObjC/protocol-archane.m
@@ -0,0 +1,35 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// rdar://5986251
+
+@protocol SomeProtocol
+- (void) bar;
+@end
+
+void foo(id x) {
+ bar((short<SomeProtocol>)x); // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ bar((<SomeProtocol>)x); // expected-warning {{protocol qualifiers without 'id' is archaic}}
+
+ [(<SomeProtocol>)x bar]; // expected-warning {{protocol qualifiers without 'id' is archaic}}
+}
+
+@protocol MyProtocol
+- (void)doSomething;
+@end
+
+@interface MyClass
+- (void)m1:(id <MyProtocol> const)arg1;
+
+// FIXME: provide a better diagnostic (no typedef).
+- (void)m2:(id <MyProtocol> short)arg1; // expected-error {{'short type-name' is invalid}}
+@end
+
+typedef int NotAnObjCObjectType;
+
+// GCC doesn't diagnose this.
+NotAnObjCObjectType <SomeProtocol> *obj; // expected-error {{invalid protocol qualifiers on non-ObjC type}}
+
+// Decided not to support the following GCC extension. Found while researching rdar://6497631
+typedef struct objc_class *Class;
+
+Class <SomeProtocol> UnfortunateGCCExtension; // expected-error {{protocol qualified 'Class' is unsupported}}
+
diff --git a/test/SemaObjC/protocol-attribute.m b/test/SemaObjC/protocol-attribute.m
new file mode 100644
index 000000000000..ae8441132c77
--- /dev/null
+++ b/test/SemaObjC/protocol-attribute.m
@@ -0,0 +1,49 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+__attribute ((unavailable))
+@protocol FwProto; // expected-note{{marked unavailable}}
+
+Class <FwProto> cFw = 0; // expected-warning {{'FwProto' is unavailable}} expected-error{{protocol qualified 'Class' is unsupported}}
+
+
+__attribute ((deprecated)) @protocol MyProto1
+@end
+
+@protocol Proto2 <MyProto1> // expected-warning {{'MyProto1' is deprecated}}
++method2;
+@end
+
+
+@interface MyClass1 <MyProto1> // expected-warning {{'MyProto1' is deprecated}}
+{
+ Class isa;
+}
+@end
+
+@interface Derived : MyClass1 <MyProto1> // expected-warning {{'MyProto1' is deprecated}}
+{
+ id <MyProto1> ivar; // expected-warning {{'MyProto1' is deprecated}}
+}
+@end
+
+@interface MyClass1 (Category) <MyProto1, Proto2> // expected-warning {{'MyProto1' is deprecated}}
+@end
+
+
+
+Class <MyProto1> clsP1 = 0; // expected-warning {{'MyProto1' is deprecated}} expected-error{{protocol qualified 'Class' is unsupported}}
+
+@protocol FwProto @end // expected-note{{marked unavailable}}
+
+@interface MyClass2 <FwProto> // expected-warning {{'FwProto' is unavailable}}
+@end
+
+__attribute ((unavailable)) __attribute ((deprecated)) @protocol XProto; // expected-note{{marked unavailable}}
+
+id <XProto> idX = 0; // expected-warning {{'XProto' is unavailable}} expected-warning {{'XProto' is deprecated}}
+
+int main ()
+{
+ MyClass1 <MyProto1> *p1; // expected-warning {{'MyProto1' is deprecated}}
+}
+
diff --git a/test/SemaObjC/protocol-expr-1.m b/test/SemaObjC/protocol-expr-1.m
new file mode 100644
index 000000000000..cc1c3231d5e5
--- /dev/null
+++ b/test/SemaObjC/protocol-expr-1.m
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@protocol fproto;
+
+@protocol p1
+@end
+
+@class cl;
+
+int main()
+{
+ Protocol *proto = @protocol(p1);
+ Protocol *fproto = @protocol(fproto);
+}
+
diff --git a/test/SemaObjC/protocol-expr-neg-1.m b/test/SemaObjC/protocol-expr-neg-1.m
new file mode 100644
index 000000000000..9393fde3c3c7
--- /dev/null
+++ b/test/SemaObjC/protocol-expr-neg-1.m
@@ -0,0 +1,19 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@class Protocol;
+
+@protocol fproto;
+
+@protocol p1
+@end
+
+@class cl;
+
+int main()
+{
+ Protocol *proto = @protocol(p1);
+ Protocol *fproto = @protocol(fproto);
+ Protocol *pp = @protocol(i); // expected-error {{cannot find protocol declaration for 'i'}}
+ Protocol *p1p = @protocol(cl); // expected-error {{cannot find protocol declaration for 'cl'}}
+}
+
diff --git a/test/SemaObjC/protocol-id-test-1.m b/test/SemaObjC/protocol-id-test-1.m
new file mode 100644
index 000000000000..5e737a8fae07
--- /dev/null
+++ b/test/SemaObjC/protocol-id-test-1.m
@@ -0,0 +1,16 @@
+// RUN: clang-cc -verify %s
+
+@interface FF
+- (void) Meth;
+@end
+
+@protocol P
+@end
+
+@interface INTF<P>
+- (void)IMeth;
+@end
+
+@implementation INTF
+- (void)IMeth {INTF<P> *pi; [pi Meth]; } // expected-warning {{method '-Meth' not found (return type defaults to 'id')}}
+@end
diff --git a/test/SemaObjC/protocol-id-test-2.m b/test/SemaObjC/protocol-id-test-2.m
new file mode 100644
index 000000000000..a55923c21058
--- /dev/null
+++ b/test/SemaObjC/protocol-id-test-2.m
@@ -0,0 +1,12 @@
+// RUN: clang-cc -verify %s
+
+@protocol P
+@end
+
+@interface INTF<P>
+- (void)IMeth;
+@end
+
+@implementation INTF
+- (void)IMeth { [(id<P>)self Meth]; } // expected-warning {{method '-Meth' not found (return type defaults to 'id')}}
+@end
diff --git a/test/SemaObjC/protocol-id-test-3.m b/test/SemaObjC/protocol-id-test-3.m
new file mode 100644
index 000000000000..3c7f84a181f1
--- /dev/null
+++ b/test/SemaObjC/protocol-id-test-3.m
@@ -0,0 +1,94 @@
+// RUN: clang-cc -pedantic -fsyntax-only -verify %s
+
+@protocol MyProto1
+@end
+
+@protocol MyProto2
+@end
+
+@interface INTF @end
+
+id<MyProto1> Func(INTF <MyProto1, MyProto2> *p2)
+{
+ return p2;
+}
+
+
+
+
+ id<MyProto1> Gunc(id <MyProto1, MyProto2>p2)
+{
+ return p2;
+}
+
+
+ id<MyProto1> Gunc1(id <MyProto1, MyProto2>p2)
+{
+ return p2;
+}
+
+id<MyProto1, MyProto2> Gunc2(id <MyProto1>p2)
+{
+ Func(p2); // expected-warning {{incompatible type passing 'id<MyProto1>', expected 'INTF<MyProto1,MyProto2> *'}}
+ return p2; // expected-warning {{incompatible type returning 'id<MyProto1>', expected 'id<MyProto1,MyProto2>'}}
+}
+
+
+
+id<MyProto1> Gunc3(id <MyProto2>p2)
+{
+ return p2; // expected-warning {{incompatible type returning 'id<MyProto2>', expected 'id<MyProto1>'}}
+}
+
+
+id<MyProto1, MyProto2> Gunc4(id <MyProto2, MyProto1>p2)
+{
+ return p2;
+}
+
+
+
+INTF<MyProto1> * Hunc(id <MyProto1, MyProto2>p2)
+{
+ return p2;
+}
+
+
+INTF<MyProto1> * Hunc1(id <MyProto1, MyProto2>p2)
+{
+ return p2;
+}
+
+INTF<MyProto1, MyProto2> * Hunc2(id <MyProto1>p2)
+{
+ Func(p2); // expected-warning {{incompatible type passing 'id<MyProto1>', expected 'INTF<MyProto1,MyProto2> *'}}
+ return p2; // expected-warning {{incompatible type returning 'id<MyProto1>', expected 'INTF<MyProto1,MyProto2> *'}}
+}
+
+INTF<MyProto1> * Hunc3(id <MyProto2>p2)
+{
+ return p2; // expected-warning {{incompatible type returning 'id<MyProto2>', expected 'INTF<MyProto1> *'}}
+}
+
+
+INTF<MyProto1, MyProto2> * Hunc4(id <MyProto2, MyProto1>p2)
+{
+ return p2;
+}
+
+id Iunc(id <MyProto1, MyProto2>p2)
+{
+ return p2;
+}
+
+
+id<MyProto1> Iunc1(id p2)
+{
+ return p2;
+}
+
+id<MyProto1, MyProto2> Iunc2(id p2)
+{
+ Iunc(p2);
+ return p2;
+}
diff --git a/test/SemaObjC/protocol-implementation-inherited.m b/test/SemaObjC/protocol-implementation-inherited.m
new file mode 100644
index 000000000000..1aace211c844
--- /dev/null
+++ b/test/SemaObjC/protocol-implementation-inherited.m
@@ -0,0 +1,56 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@protocol P0
+-bar;
+@end
+
+@interface A <P0>
+@end
+
+// Interface conforms to inherited protocol
+
+@interface B0 : A <P0>
+@end
+
+@implementation B0
+@end
+
+// Interface conforms to a protocol which extends another. The other
+// protocol is inherited, and extended methods are implemented.
+
+@protocol P1 <P0>
+-foo;
+@end
+
+@interface B1 : A <P1>
+@end
+
+@implementation B1
+-foo {};
+@end
+
+// Interface conforms to a protocol whose methods are provided by an
+// alternate inherited protocol.
+
+@protocol P2
+-bar;
+@end
+
+@interface B2 : A <P2>
+@end
+
+@implementation B2
+@end
+
+// Interface conforms to a protocol whose methods are provided by a base class.
+
+@interface A1
+-bar;
+@end
+
+@interface B3 : A1 <P2>
+@end
+
+@implementation B3
+@end
+
diff --git a/test/SemaObjC/protocol-lookup-2.m b/test/SemaObjC/protocol-lookup-2.m
new file mode 100644
index 000000000000..64d0c3acf036
--- /dev/null
+++ b/test/SemaObjC/protocol-lookup-2.m
@@ -0,0 +1,33 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+@interface NSObject @end
+
+@protocol ProtocolA
+
++ (id)classMethod;
+- (id)instanceMethod;
+
+@end
+
+@protocol ProtocolB <ProtocolA>
+
+@end
+
+@interface Foo : NSObject <ProtocolB>
+
+@end
+
+@interface SubFoo : Foo
+
+@end
+
+@implementation SubFoo
+
++ (id)method {
+ return [super classMethod];
+}
+
+- (id)method {
+ return [super instanceMethod];
+}
+
+@end
diff --git a/test/SemaObjC/protocol-lookup.m b/test/SemaObjC/protocol-lookup.m
new file mode 100644
index 000000000000..0f1860d2c88e
--- /dev/null
+++ b/test/SemaObjC/protocol-lookup.m
@@ -0,0 +1,50 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+@protocol NSObject
+- retain;
+- release;
+@end
+
+@interface NSObject
+- init;
+- dealloc;
+@end
+
+@protocol Foo <NSObject>
+@end
+
+@protocol Bar <Foo>
+@end
+
+@interface Baz : NSObject {
+ id <Foo> _foo;
+ id <Bar> _bar;
+}
+- (id)initWithFoo:(id <Foo>)foo bar:(id <Bar>)bar;
+@end
+
+@implementation Baz
+
+- (id)init
+{
+ return [self initWithFoo:0 bar:0];
+}
+
+- (id)initWithFoo:(id <Foo>)foo bar:(id <Bar>)bar
+{
+ self = [super init];
+ if (self != 0) {
+ _foo = [foo retain];
+ _bar = [bar retain];
+ }
+ return self;
+}
+
+- dealloc
+{
+ [_foo release];
+ [_bar release];
+ [super dealloc];
+}
+
+@end
+
diff --git a/test/SemaObjC/protocol-qualified-class-unsupported.m b/test/SemaObjC/protocol-qualified-class-unsupported.m
new file mode 100644
index 000000000000..ad1ed5dc9411
--- /dev/null
+++ b/test/SemaObjC/protocol-qualified-class-unsupported.m
@@ -0,0 +1,40 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+#include <stddef.h>
+
+typedef struct objc_class *Class;
+typedef struct objc_object {
+ Class isa;
+} *id;
+id objc_getClass(const char *s);
+
+@interface Object
++ self;
+@end
+
+@protocol Func
++ (void) class_func0;
+- (void) instance_func0;
+@end
+
+@interface Derived: Object <Func>
+@end
+
+@interface Derived2: Object <Func>
+@end
+
+static void doSomething(Class <Func> unsupportedObjectType) { // expected-error {{protocol qualified 'Class' is unsupported}}
+ [unsupportedObjectType class_func0];
+}
+
+static void doSomethingElse(id <Func> pleaseConvertToThisType) {
+ [pleaseConvertToThisType class_func0];
+}
+
+int main(int argv, char *argc[]) {
+ doSomething([Derived self]);
+ doSomething([Derived2 self]);
+ doSomethingElse([Derived self]);
+ doSomethingElse([Derived2 self]);
+}
+
diff --git a/test/SemaObjC/protocol-typecheck.m b/test/SemaObjC/protocol-typecheck.m
new file mode 100644
index 000000000000..de66dedda70a
--- /dev/null
+++ b/test/SemaObjC/protocol-typecheck.m
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface NSObject @end
+@protocol XCElementP @end
+@protocol XCElementSpacerP <XCElementP> @end
+
+@protocol PWhatever @end
+
+@interface XX
+
+- (void)setFlexElement:(NSObject <PWhatever, XCElementP> *)flexer;
+- (void)setFlexElement2:(NSObject <PWhatever, XCElementSpacerP> *)flexer;
+
+@end
+
+void func() {
+ NSObject <PWhatever, XCElementSpacerP> * flexer;
+ NSObject <PWhatever, XCElementP> * flexer2;
+ XX *obj;
+ [obj setFlexElement:flexer];
+ // FIXME: GCC provides the following diagnostic (which is much better):
+ // protocol-typecheck.m:21: warning: class 'NSObject <PWhatever, XCElementP>' does not implement the 'XCElementSpacerP' protocol
+ [obj setFlexElement2:flexer2]; // expected-warning{{incompatible pointer types sending 'NSObject<PWhatever,XCElementP> *', expected 'NSObject<PWhatever,XCElementSpacerP> *'}}
+}
+
diff --git a/test/SemaObjC/protocols.m b/test/SemaObjC/protocols.m
new file mode 100644
index 000000000000..9fbdc16759dd
--- /dev/null
+++ b/test/SemaObjC/protocols.m
@@ -0,0 +1,63 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface INTF1
+@required // expected-error {{directive may only be specified in protocols only}}
+- (int) FooBar;
+- (int) FooBar1;
+- (int) FooBar2;
+@optional // expected-error {{directive may only be specified in protocols only}}
++ (int) C;
+
+- (int)I;
+@end
+
+@protocol p1,p2,p3;
+
+@protocol p1;
+
+@protocol PROTO1
+@required
+- (int) FooBar;
+@optional
+- (void) MyMethod1;
++ (int) S;
+@end
+
+
+@protocol PROTO2<p1>
+@end
+
+@protocol p1 @end
+
+@protocol PROTO<p1> // expected-note {{previous definition is here}}
+@end
+
+@protocol PROTO<p1> // expected-warning {{duplicate protocol definition of 'PROTO'}}
+@end
+
+@protocol PROTO3<p1, p1>
+@end
+
+@protocol p2 <p1>
+@end
+
+@protocol PROTO4 <p1, p2, PROTO, PROTO3, p3>
+@end
+
+
+// rdar://6771034
+@protocol XX;
+@protocol YY <XX> // Use of declaration of XX here should not cause a warning.
+- zz;
+@end
+
+
+// Detect circular dependencies.
+@protocol B;
+@protocol C < B > // expected-note{{previous definition is here}}
+@end
+@protocol A < C >
+@end
+@protocol B < A > // expected-error{{protocol has circular dependency}}
+@end
+
diff --git a/test/SemaObjC/rdr-6211479-array-property.m b/test/SemaObjC/rdr-6211479-array-property.m
new file mode 100644
index 000000000000..f8e4a07cba58
--- /dev/null
+++ b/test/SemaObjC/rdr-6211479-array-property.m
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// XFAIL
+// <rdar://problem/6211479>
+
+typedef int T[2];
+
+@interface A
+@property(assign) T p2; // expected-error {{FIXME: property has invalid type}}
+@end
diff --git a/test/SemaObjC/scope-check.m b/test/SemaObjC/scope-check.m
new file mode 100644
index 000000000000..0835373ba748
--- /dev/null
+++ b/test/SemaObjC/scope-check.m
@@ -0,0 +1,103 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@class A, B, C;
+
+void test1() {
+ goto L; // expected-error{{illegal goto into protected scope}}
+ goto L2; // expected-error{{illegal goto into protected scope}}
+ goto L3; // expected-error{{illegal goto into protected scope}}
+ @try { // expected-note {{jump bypasses initialization of @try block}}
+L: ;
+ } @catch (A *x) { // expected-note {{jump bypasses initialization of @catch block}}
+L2: ;
+ } @catch (B *x) {
+ } @catch (C *c) {
+ } @finally {// expected-note {{jump bypasses initialization of @finally block}}
+L3: ;
+ }
+
+ @try {
+ goto L4; // expected-error{{illegal goto into protected scope}}
+ goto L5; // expected-error{{illegal goto into protected scope}}
+ } @catch (C *c) { // expected-note {{jump bypasses initialization of @catch block}}
+ L5: ;
+ goto L6; // expected-error{{illegal goto into protected scope}}
+ } @catch (B *c) { // expected-note {{jump bypasses initialization of @catch block}}
+ L6: ;
+ } @finally { // expected-note {{jump bypasses initialization of @finally block}}
+ L4: ;
+ }
+
+
+ @try { // expected-note 2 {{jump bypasses initialization of @try block}}
+ L7: ;
+ } @catch (C *c) {
+ goto L7; // expected-error{{illegal goto into protected scope}}
+ } @finally {
+ goto L7; // expected-error{{illegal goto into protected scope}}
+ }
+
+ goto L8; // expected-error{{illegal goto into protected scope}}
+ @try {
+ } @catch (A *c) {
+ } @catch (B *c) {
+ } @catch (C *c) { // expected-note {{jump bypasses initialization of @catch block}}
+ L8: ;
+ }
+
+ // rdar://6810106
+ id X;
+ goto L9; // expected-error{{illegal goto into protected scope}}
+ goto L10; // ok
+ @synchronized // expected-note {{jump bypasses initialization of @synchronized block}}
+ ( ({ L10: ; X; })) {
+ L9:
+ ;
+ }
+}
+
+void test2(int a) {
+ if (a) goto L0;
+ @try {} @finally {}
+ L0:
+ return;
+}
+
+// rdar://6803963
+void test3() {
+ @try {
+ goto blargh;
+ blargh: ;
+ } @catch (...) {}
+}
+
+@interface Greeter
++ (void) hello;
+@end
+
+@implementation Greeter
++ (void) hello {
+
+ @try {
+ goto blargh; // expected-error {{illegal goto into protected scope}}
+ } @catch (...) { // expected-note {{jump bypasses initialization of @catch block}}
+ blargh: ;
+ }
+}
+
++ (void)meth2 {
+ int n; void *P;
+ goto L0; // expected-error {{illegal goto into protected scope}}
+ typedef int A[n]; // expected-note {{jump bypasses initialization of VLA typedef}}
+ L0:
+
+ goto L1; // expected-error {{illegal goto into protected scope}}
+ A b, c[10]; // expected-note 2 {{jump bypasses initialization of variable length array}}
+ L1:
+ goto L2; // expected-error {{illegal goto into protected scope}}
+ A d[n]; // expected-note {{jump bypasses initialization of variable length array}}
+ L2:
+ return;
+}
+
+@end
diff --git a/test/SemaObjC/selector-1.m b/test/SemaObjC/selector-1.m
new file mode 100644
index 000000000000..ee77015041db
--- /dev/null
+++ b/test/SemaObjC/selector-1.m
@@ -0,0 +1,22 @@
+// RUN: clang-cc -verify %s
+
+@interface Lancelot @end
+@implementation Lancelot
+
+- (void):(int)x {}
+- (void)xx:(int)x :(int)y { }
+
+@end
+
+int main() {
+ SEL s = @selector(retain);
+ SEL s1 = @selector(meth1:);
+ SEL s2 = @selector(retainArgument::);
+ SEL s3 = @selector(retainArgument:::::);
+ SEL s4 = @selector(retainArgument:with:);
+ SEL s5 = @selector(meth1:with:with:);
+ SEL s6 = @selector(getEnum:enum:bool:);
+ SEL s7 = @selector(char:float:double:unsigned:short:long:);
+
+ SEL s9 = @selector(:enum:bool:);
+}
diff --git a/test/SemaObjC/selector-error.m b/test/SemaObjC/selector-error.m
new file mode 100644
index 000000000000..cc2a40472640
--- /dev/null
+++ b/test/SemaObjC/selector-error.m
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface Foo
+- (char*) foo;
+- (void) bar;
+@end
+
+@implementation Foo
+- (void) bar
+{
+}
+
+- (char*) foo
+{
+ char* a,b,c;
+ a = (char*)@selector(bar); // expected-error {{cannot type cast @selector expression}}
+ return (char*)@selector(bar); // expected-error {{cannot type cast @selector expression}}
+}
+@end
+
diff --git a/test/SemaObjC/selector-overload.m b/test/SemaObjC/selector-overload.m
new file mode 100644
index 000000000000..7c30f79ceaec
--- /dev/null
+++ b/test/SemaObjC/selector-overload.m
@@ -0,0 +1,47 @@
+// RUN: clang-cc %s -fsyntax-only
+
+@interface NSObject
++ alloc;
+- init;
+@end
+
+struct D {
+ double d;
+};
+
+@interface Foo : NSObject
+
+- method:(int)a;
+- method:(int)a;
+
+@end
+
+@interface Bar : NSObject
+
+- method:(void *)a;
+
+@end
+
+@interface Car : NSObject
+
+- method:(struct D)a;
+
+@end
+
+@interface Zar : NSObject
+
+- method:(float)a;
+
+@end
+
+@interface Rar : NSObject
+
+- method:(float)a;
+
+@end
+
+int main() {
+ id xx = [[Car alloc] init]; // expected-warning {{incompatible types assigning 'int' to 'id'}}
+
+ [xx method:4];
+}
diff --git a/test/SemaObjC/sizeof-interface.m b/test/SemaObjC/sizeof-interface.m
new file mode 100644
index 000000000000..75d7daafbbcc
--- /dev/null
+++ b/test/SemaObjC/sizeof-interface.m
@@ -0,0 +1,79 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -verify -fsyntax-only %s
+
+@class I0;
+
+// rdar://6811884
+int g0 = sizeof(I0); // expected-error{{invalid application of 'sizeof' to an incomplete type 'I0'}}
+
+// rdar://6821047
+void *g3(I0 *P) {
+ P = P+5; // expected-error {{arithmetic on pointer to incomplete type 'I0 *'}}
+
+ return &P[4]; // expected-error{{subscript of pointer to incomplete type 'I0'}}
+}
+
+
+
+@interface I0 {
+@public
+ char x[4];
+}
+
+@property int p0;
+@end
+
+// size == 4
+int g1[ sizeof(I0) // expected-error {{invalid application of 'sizeof' to interface 'I0' in non-fragile ABI}}
+ == 4 ? 1 : -1];
+
+@implementation I0
+@synthesize p0 = _p0;
+@end
+
+// size == 4 (we do not include extended properties in the
+// sizeof).
+int g2[ sizeof(I0) // expected-error {{invalid application of 'sizeof' to interface 'I0' in non-fragile ABI}}
+ == 4 ? 1 : -1];
+
+@interface I1
+@property int p0;
+@end
+
+@implementation I1
+@synthesize p0 = _p0;
+@end
+
+typedef struct { @defs(I1) } I1_defs; // expected-error {{invalid application of @defs in non-fragile ABI}}
+
+// FIXME: This is currently broken due to the way the record layout we
+// create is tied to whether we have seen synthesized properties. Ugh.
+// int g3[ sizeof(I1) == 0 ? 1 : -1];
+
+// rdar://6821047
+int bar(I0 *P) {
+ P = P+5; // expected-error {{arithmetic on pointer to interface 'I0', which is not a constant size in non-fragile ABI}}
+ P = 5+P; // expected-error {{arithmetic on pointer to interface 'I0', which is not a constant size in non-fragile ABI}}
+ P = P-5; // expected-error {{arithmetic on pointer to interface 'I0', which is not a constant size in non-fragile ABI}}
+
+ return P[4].x[2]; // expected-error {{subscript requires size of interface 'I0', which is not constant in non-fragile ABI}}
+}
+
+
+@interface I @end
+
+@interface XCAttributeRunDirectNode
+{
+ @public
+ unsigned long attributeRuns[1024 + sizeof(I)]; // expected-error {{invalid application of 'sizeof' to interface 'I' in non-fragile ABI}}
+ int i;
+}
+@end
+
+@implementation XCAttributeRunDirectNode
+
+- (unsigned long)gatherStats:(id )stats
+{
+ return attributeRuns[i];
+}
+@end
+
diff --git a/test/SemaObjC/static-ivar-ref-1.m b/test/SemaObjC/static-ivar-ref-1.m
new file mode 100644
index 000000000000..3c37e9e83026
--- /dev/null
+++ b/test/SemaObjC/static-ivar-ref-1.m
@@ -0,0 +1,17 @@
+// RUN: clang-cc -ast-print %s
+
+@interface current
+{
+@public
+ int ivar;
+ int ivar1;
+ int ivar2;
+}
+@end
+
+current *pc;
+
+int foo()
+{
+ return pc->ivar2 + (*pc).ivar + pc->ivar1;
+}
diff --git a/test/SemaObjC/stmts.m b/test/SemaObjC/stmts.m
new file mode 100644
index 000000000000..1d4ea0a77189
--- /dev/null
+++ b/test/SemaObjC/stmts.m
@@ -0,0 +1,14 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+
+struct some_struct;
+
+// Note: NSException is not declared.
+void f0(id x) {
+ @try {
+ } @catch (NSException *x) { // expected-error {{unknown type name 'NSException'}}
+ } @catch (struct some_struct x) { // expected-error {{@catch parameter is not a pointer to an interface type}}
+ } @catch (int x) { // expected-error {{@catch parameter is not a pointer to an interface type}}
+ } @catch (...) {
+ }
+}
+
diff --git a/test/SemaObjC/string.m b/test/SemaObjC/string.m
new file mode 100644
index 000000000000..3f078f6543ee
--- /dev/null
+++ b/test/SemaObjC/string.m
@@ -0,0 +1,15 @@
+// RUN: clang-cc %s -verify -fsyntax-only &&
+// RUN: clang-cc %s -verify -fsyntax-only -DDECLAREIT
+
+// a declaration of NSConstantString is not required.
+#ifdef DECLAREIT
+@interface NSConstantString;
+@end
+#endif
+
+
+
+id s = @"123"; // simple
+id t = @"123" @"456"; // concat
+id u = @"123" @ blah; // expected-error {{unexpected token}}
+
diff --git a/test/SemaObjC/super-cat-prot.m b/test/SemaObjC/super-cat-prot.m
new file mode 100644
index 000000000000..1ab0752faa38
--- /dev/null
+++ b/test/SemaObjC/super-cat-prot.m
@@ -0,0 +1,48 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
+@interface NSObject <NSObject> {} @end
+typedef float CGFloat;
+typedef struct _NSSize {} NSSize;
+typedef struct _NSRect {} NSRect;
+@interface NSResponder : NSObject <NSCoding> {} @end
+@protocol NSAnimatablePropertyContainer - (id)animator; @end
+extern NSString *NSAnimationTriggerOrderIn ;
+@interface NSView : NSResponder <NSAnimatablePropertyContainer> {} @end
+@class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView;
+enum { NSBoxPrimary = 0, NSBoxSecondary = 1, NSBoxSeparator = 2, NSBoxOldStyle = 3, NSBoxCustom = 4};
+typedef NSUInteger NSBoxType;
+@interface NSBox : NSView {} - (NSBoxType)boxType; @end
+@class NSArray, NSError, NSImage, NSView, NSNotificationCenter, NSURL;
+@interface NSProBox:NSBox {} @end
+enum IBKnobPosition { IBNoKnobPosition = -1, IBBottomLeftKnobPosition = 0,
+ IBMiddleLeftKnobPosition, IBTopLeftKnobPosition,
+ IBTopMiddleKnobPosition, IBTopRightKnobPosition,
+ IBMiddleRightKnobPosition, IBBottomRightKnobPosition,
+ IBBottomMiddleKnobPosition };
+typedef enum IBKnobPosition IBKnobPosition;
+typedef struct _IBInset {} IBInset;
+@protocol IBObjectProtocol -(NSString *)inspectorClassName; @end
+@protocol IBViewProtocol
+ -(NSSize)minimumFrameSizeFromKnobPosition:(IBKnobPosition)position;
+ -(IBInset)ibShadowInset;
+@end
+@class NSPasteboard;
+@interface NSObject (NSObject_IBObjectProtocol) <IBObjectProtocol> @end
+@interface NSView (NSView_IBViewProtocol) <IBViewProtocol> - (NSRect)layoutRect; @end
+typedef enum { NSProTextFieldSquareBezel = 0, NSProTextFieldRoundedBezel = 1, NSProTextFieldDisplayBezel = 2 } MKModuleReusePolicy;
+@implementation NSProBox(IBAdditions)
+-(NSString *)inspectorClassName {}
+-(IBInset)ibShadowInset {
+ if ([self boxType] == NSBoxSeparator) {
+ return [super ibShadowInset];
+ }
+}
+-(NSSize)minimumFrameSizeFromKnobPosition:(IBKnobPosition)knobPosition {
+ if ([self boxType] != NSBoxSeparator)
+ return [super minimumFrameSizeFromKnobPosition:knobPosition];
+}
+@end
diff --git a/test/SemaObjC/super-property-message-expr.m b/test/SemaObjC/super-property-message-expr.m
new file mode 100644
index 000000000000..082d8bd5b48a
--- /dev/null
+++ b/test/SemaObjC/super-property-message-expr.m
@@ -0,0 +1,21 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface SStoreNodeInfo
+
+@property(nonatomic,readonly,retain) id descriptionShort;
+
+- (id)stringByAppendingFormat:(int)format, ... ;
+
+@end
+
+@interface SStoreNodeInfo_iDisk : SStoreNodeInfo
+{
+@private
+ id _etag;
+}
+@end
+
+@implementation SStoreNodeInfo_iDisk
+- (id) X { return [super.descriptionShort stringByAppendingFormat:1, _etag]; }
+
+@end
diff --git a/test/SemaObjC/super-property-notation.m b/test/SemaObjC/super-property-notation.m
new file mode 100644
index 000000000000..3b0887f26eff
--- /dev/null
+++ b/test/SemaObjC/super-property-notation.m
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface B
++(int) classGetter;
+-(int) getter;
+@end
+
+@interface A : B
+@end
+
+@implementation A
++(int) classGetter {
+ return 0;
+}
+
++(int) classGetter2 {
+ return super.classGetter;
+}
+
+-(void) method {
+ int x = super.getter;
+}
+@end
+
+void f0() {
+ // FIXME: not implemented yet.
+ //int l1 = A.classGetter;
+ int l2 = [A classGetter2];
+}
+
diff --git a/test/SemaObjC/super.m b/test/SemaObjC/super.m
new file mode 100644
index 000000000000..9afd4eb983c5
--- /dev/null
+++ b/test/SemaObjC/super.m
@@ -0,0 +1,40 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface Foo
+- iMethod;
++ cMethod;
+@end
+
+@interface A
+@end
+
+@interface B : A
+- (void)instanceMethod;
++ classMethod;
+@end
+
+@implementation B
+
+- (void)instanceMethod {
+ [super iMethod]; // expected-warning{{method '-iMethod' not found (return type defaults to 'id')}}
+}
+
++ classMethod {
+ [super cMethod]; // expected-warning{{method '+cMethod' not found (return type defaults to 'id')}}
+}
+@end
+
+@interface XX
+- m;
+@end
+
+void f(id super) {
+ [super m];
+}
+void f0(int super) {
+ [super m]; // expected-warning{{receiver type 'int' is not 'id'}} \
+ expected-warning {{method '-m' not found (return type defaults to 'id')}}
+}
+void f1(int puper) {
+ [super m]; // expected-error{{use of undeclared identifier 'super'}}
+}
diff --git a/test/SemaObjC/synchronized.m b/test/SemaObjC/synchronized.m
new file mode 100644
index 000000000000..7131265b5bb7
--- /dev/null
+++ b/test/SemaObjC/synchronized.m
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface PBXTrackableTaskManager @end
+
+@implementation PBXTrackableTaskManager
+- (id) init {}
+- (void) unregisterTask:(id) task {
+ @synchronized (self) {
+ id taskID = [task taskIdentifier]; // expected-warning {{method '-taskIdentifier' not found (return type defaults to 'id')}}
+ }
+}
+@end
+
+
+struct x { int a; } b;
+
+void test1() {
+ @synchronized (b) { // expected-error {{@synchronized requires an Objective-C object type ('struct x' invalid)}}
+ }
+
+ @synchronized (42) { // expected-error {{@synchronized requires an Objective-C object type ('int' invalid)}}
+ }
+}
diff --git a/test/SemaObjC/synthesize-setter-contclass.m b/test/SemaObjC/synthesize-setter-contclass.m
new file mode 100644
index 000000000000..78490c8db0d3
--- /dev/null
+++ b/test/SemaObjC/synthesize-setter-contclass.m
@@ -0,0 +1,24 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface TestClass
+{
+ int _isItIsOrIsItAint;
+}
+@property (readonly) int itIsOrItAint;
+-(void) doSomething;
+@end
+
+@interface TestClass()
+@property (readwrite) int itIsOrItAint;
+@end
+
+@implementation TestClass
+@synthesize itIsOrItAint = _isItIsOrIsItAint;
+
+-(void) doSomething
+{
+ int i = [self itIsOrItAint];
+
+ [self setItIsOrItAint:(int)1];
+}
+@end
diff --git a/test/SemaObjC/synthesized-ivar.m b/test/SemaObjC/synthesized-ivar.m
new file mode 100644
index 000000000000..de44857934fc
--- /dev/null
+++ b/test/SemaObjC/synthesized-ivar.m
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -triple x86_64-apple-darwin9 -verify %s
+@interface I
+{
+}
+@property int IP;
+@end
+
+@implementation I
+@synthesize IP;
+- (int) Meth {
+ return IP;
+}
+@end
diff --git a/test/SemaObjC/try-catch.m b/test/SemaObjC/try-catch.m
new file mode 100644
index 000000000000..076eff542968
--- /dev/null
+++ b/test/SemaObjC/try-catch.m
@@ -0,0 +1,47 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+typedef signed char BOOL;
+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
+
+@interface NSObject <NSObject> {}
+@end
+
+@class NSData, NSArray, NSDictionary, NSCharacterSet, NSData, NSURL, NSError, NSLocale;
+
+@interface NSException : NSObject <NSCopying, NSCoding> {}
+@end
+
+@class ASTNode, XCRefactoringParser, Transform, TransformInstance, XCRefactoringSelectionInfo;
+
+@interface XCRefactoringTransformation : NSObject {}
+@end
+
+@implementation XCRefactoringTransformation
+- (NSDictionary *)setUpInfoForTransformKey:(NSString *)transformKey outError:(NSError **)outError; {
+ @try {}
+ // the exception name is optional (weird)
+ @catch (NSException *) {}
+}
+@end
+
+int foo() {
+ struct s { int a, b; } agg, *pagg;
+
+ @throw 42; // expected-error {{@throw requires an Objective-C object type ('int' invalid))}}
+ @throw agg; // expected-error {{@throw requires an Objective-C object type ('struct s' invalid)}}
+ @throw pagg; // expected-error {{@throw requires an Objective-C object type ('struct s *' invalid)}}
+ @throw; // expected-error {{@throw (rethrow) used outside of a @catch block}}
+}
diff --git a/test/SemaObjC/typedef-class.m b/test/SemaObjC/typedef-class.m
new file mode 100644
index 000000000000..128815602d4d
--- /dev/null
+++ b/test/SemaObjC/typedef-class.m
@@ -0,0 +1,78 @@
+// RUN: clang-cc -fsyntax-only -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
+
+@interface NSObject < NSObject > {}
++(id) alloc;
+@end
+
+typedef float CGFloat;
+
+@interface NSTask:NSObject
+- (id) init;
+@end
+
+typedef NSUInteger NSControlSize;
+typedef struct __CFlags {} _CFlags;
+
+@interface NSCell:NSObject < NSCopying, NSCoding > {}
+@end
+
+@interface NSActionCell:NSCell {} @end
+
+@class NSAttributedString, NSFont, NSImage, NSSound;
+
+typedef struct _XCElementInset {} XCElementInset;
+
+@protocol XCElementP < NSObject >
+-(BOOL) vertical;
+@end
+
+@protocol XCElementDisplayDelegateP;
+@protocol XCElementDisplayDelegateP < NSObject >
+-(void) configureForControlSize:(NSControlSize)size font:(NSFont *)font addDefaultSpace:(XCElementInset) additionalSpace;
+@end
+
+@protocol XCElementSpacerP < XCElementP >
+@end
+
+typedef NSObject < XCElementSpacerP > XCElementSpacer;
+
+@protocol XCElementTogglerP < XCElementP > -(void) setDisplayed:(BOOL) displayed;
+@end
+
+typedef NSObject < XCElementTogglerP > XCElementToggler;
+
+@interface XCElementRootFace:NSObject {} @end
+
+@interface XCElementFace:XCElementRootFace {} @end
+
+@class XCElementToggler;
+
+@interface XCRASlice:XCElementFace {} @end
+
+@class XCElementSpacings;
+
+@interface XCElementDisplay:NSObject < XCElementDisplayDelegateP > {} @end
+@interface XCElementDisplayRect:XCElementDisplay {} @end
+
+typedef XCElementDisplayRect XCElementGraphicsRect;
+
+@interface XCElementDisplayFillerImage:XCElementDisplay {} @end
+
+@implementation XCRASlice
+- (void) addSliceWithLabel:(NSString *)label statusKey:(NSString *)statusKey disclosed:(BOOL)disclosed
+{
+ static XCElementGraphicsRect *_sGraphicsDelegate = ((void *) 0);
+ if (!_sGraphicsDelegate) {
+ _sGraphicsDelegate =[[XCElementGraphicsRect alloc] init];
+ }
+}
+@end
diff --git a/test/SemaObjC/ucn-objc-string.m b/test/SemaObjC/ucn-objc-string.m
new file mode 100644
index 000000000000..1d94ea2363a1
--- /dev/null
+++ b/test/SemaObjC/ucn-objc-string.m
@@ -0,0 +1,13 @@
+// RUN: clang %s -verify -fsyntax-only
+@class NSString;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+
+int main() {
+ NSLog(@"Hi…");
+ NSLog(@"Exposé");
+ NSLog(@"\U00010400\U0001D12B");
+ NSLog(@"hello \u2192 \u2603 \u2190 world");
+ NSLog(@"hello → ☃ ↠world");
+ return 0;
+}
+
diff --git a/test/SemaObjC/undef-class-messagin-error.m b/test/SemaObjC/undef-class-messagin-error.m
new file mode 100644
index 000000000000..114b6ca5f6f4
--- /dev/null
+++ b/test/SemaObjC/undef-class-messagin-error.m
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface _Child
++ (int) flashCache;
+@end
+
+@interface Child (Categ) // expected-error {{cannot find interface declaration for 'Child'}}
++ (int) flushCache2;
+@end
+
+@implementation Child (Categ) // expected-error {{cannot find interface declaration for 'Child'}}
++ (int) flushCache2 { [super flashCache]; } // expected-error {{no @interface declaration found in class messaging of 'flushCache2'}}
+@end
diff --git a/test/SemaObjC/undef-protocol-methods-1.m b/test/SemaObjC/undef-protocol-methods-1.m
new file mode 100644
index 000000000000..05245523fb6a
--- /dev/null
+++ b/test/SemaObjC/undef-protocol-methods-1.m
@@ -0,0 +1,42 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@protocol P1
+- (void) P1proto;
++ (void) ClsP1Proto;
+- (void) DefP1proto;
+@end
+@protocol P2
+- (void) P2proto;
++ (void) ClsP2Proto;
+@end
+
+@protocol P3<P2>
+- (void) P3proto;
++ (void) ClsP3Proto;
++ (void) DefClsP3Proto;
+@end
+
+@protocol PROTO<P1, P3>
+- (void) meth;
+- (void) meth : (int) arg1;
++ (void) cls_meth : (int) arg1;
+@end
+
+@interface INTF <PROTO>
+@end
+
+@implementation INTF // expected-warning {{incomplete implementation}} \
+ expected-warning {{method definition for 'meth' not found}} \
+ expected-warning {{method definition for 'meth:' not found}} \
+ expected-warning {{method definition for 'cls_meth:' not found}} \
+ expected-warning {{method definition for 'P3proto' not found}} \
+ expected-warning {{method definition for 'ClsP3Proto' not found}} \
+ expected-warning {{method definition for 'P2proto' not found}} \
+ expected-warning {{method definition for 'ClsP2Proto' not found}} \
+ expected-warning {{method definition for 'ClsP1Proto' not found}} \
+ expected-warning {{method definition for 'P1proto' not found}}
+- (void) DefP1proto{}
+
++ (void) DefClsP3Proto{}
+
+@end
diff --git a/test/SemaObjC/undef-superclass-1.m b/test/SemaObjC/undef-superclass-1.m
new file mode 100644
index 000000000000..0d670f8c0809
--- /dev/null
+++ b/test/SemaObjC/undef-superclass-1.m
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@class SUPER, Y;
+
+@interface INTF :SUPER // expected-error {{cannot find interface declaration for 'SUPER', superclass of 'INTF'}}
+@end
+
+@interface SUPER @end
+
+@interface INTF1 : SUPER // expected-note {{previous definition is here}}
+@end
+
+@interface INTF2 : INTF1
+@end
+
+@interface INTF3 : Y // expected-error {{cannot find interface declaration for 'Y', superclass of 'INTF3'}}
+@end
+
+@interface INTF1 // expected-error {{duplicate interface definition for class 'INTF1'}}
+@end
+
+@implementation SUPER
+- (void)dealloc {
+ [super dealloc]; // expected-error {{no super class declared in @interface for 'SUPER'}}
+}
+@end
diff --git a/test/SemaObjC/undefined-protocol-type-1.m b/test/SemaObjC/undefined-protocol-type-1.m
new file mode 100644
index 000000000000..572d55f26854
--- /dev/null
+++ b/test/SemaObjC/undefined-protocol-type-1.m
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@protocol p1, p4;
+@protocol p2 @end
+
+@interface T
+- (T<p2, p3, p1, p4>*) meth; // expected-error {{cannot find protocol declaration for 'p3'}}
+- (T<p2, p3, p1, p4>*) meth; // expected-error {{cannot find protocol declaration for 'p3'}}
+@end
diff --git a/test/SemaObjC/unused.m b/test/SemaObjC/unused.m
new file mode 100644
index 000000000000..88c6f1054c8d
--- /dev/null
+++ b/test/SemaObjC/unused.m
@@ -0,0 +1,18 @@
+// RUN: clang-cc %s -verify -fsyntax-only
+#include <stdio.h>
+
+@interface Greeter
++ (void) hello;
+@end
+
+@implementation Greeter
++ (void) hello {
+ fprintf(stdout, "Hello, World!\n");
+}
+@end
+
+int main (void) {
+ [Greeter hello];
+ return 0;
+}
+
diff --git a/test/SemaObjC/va-method-1.m b/test/SemaObjC/va-method-1.m
new file mode 100644
index 000000000000..3c8998f983ce
--- /dev/null
+++ b/test/SemaObjC/va-method-1.m
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+#include <stdarg.h>
+
+@interface NSObject @end
+@interface XX : NSObject @end
+
+@implementation XX
+- (void)encodeValuesOfObjCTypes:(const char *)types, ... {
+ va_list ap;
+ va_start(ap, types);
+ while (*types) ;
+ va_end(ap);
+}
+
+@end
+
diff --git a/test/SemaObjC/warn-selector-selection.m b/test/SemaObjC/warn-selector-selection.m
new file mode 100644
index 000000000000..4ab89b7e1e2c
--- /dev/null
+++ b/test/SemaObjC/warn-selector-selection.m
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface Object
+- (void)foo;
+@end
+
+@interface Class1
+- (void)setWindow:(Object *)wdw;
+@end
+
+void foo(void) {
+ Object *obj;
+ [obj setWindow:0]; // expected-warning{{Object may not respond to 'setWindow:'}}
+}
diff --git a/test/SemaObjC/warn-weak-field.m b/test/SemaObjC/warn-weak-field.m
new file mode 100644
index 000000000000..3850f217beea
--- /dev/null
+++ b/test/SemaObjC/warn-weak-field.m
@@ -0,0 +1,24 @@
+// RUN: clang-cc -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s
+
+struct S {
+ __weak id w; // expected-warning {{__weak attribute cannot be specified on a field declaration}}
+ __strong id p1;
+};
+
+@interface I
+{
+ __weak id w; // OK
+ __strong id LHS;
+}
+- (void) foo;
+@end
+@implementation I
+- (void) foo { w = 0; LHS = w; }
+@end
+
+int main ()
+{
+ struct I {
+ __weak id w1; // expected-warning {{__weak attribute cannot be specified on a field declaration}}
+ };
+}
diff --git a/test/SemaObjC/weak-attr-ivar.m b/test/SemaObjC/weak-attr-ivar.m
new file mode 100644
index 000000000000..9e0e8cb4b3af
--- /dev/null
+++ b/test/SemaObjC/weak-attr-ivar.m
@@ -0,0 +1,73 @@
+// RUN: clang-cc -fsyntax-only -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 NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
+@end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+typedef struct {
+ id *itemsPtr;
+ unsigned long *mutationsPtr;
+} NSFastEnumerationState;
+@protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end
+@class NSString;
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+@end
+@interface NSMutableArray : NSArray - (void)addObject:(id)anObject;
+@end
+extern NSString * const NSUndoManagerCheckpointNotification;
+@interface NSValueTransformer : NSObject {} @end
+@class FooModel;
+@interface FooObject : NSObject <NSCopying> {}
+@end
+@interface FooNode : FooObject {}
+- (NSArray *) children;
+@end
+typedef enum { Foo_HUH_NONE } FooHUHCode;
+@interface FooPlaypenEntry : FooNode {
+ NSMutableArray *_interestingChildren;
+ FooHUHCode _HUH;
+ __attribute__((objc_gc(weak))) FooPlaypenEntry *_mostInterestingChild;
+ id _author;
+}
+@property(copy) NSString *author;
+- (BOOL) isInteresting;
+@end NSString *FooHUHCodeToString(FooHUHCode HUH) {
+}
+@interface FooHUHCodeToStringTransformer: NSValueTransformer {
+}
+@end @implementation FooPlaypenEntry @synthesize author = _author;
+- (BOOL) isInteresting { return 1; }
+- (NSArray *) interestingChildren {
+ if (!_interestingChildren) {
+ for (FooPlaypenEntry *child in [self children]) {
+ if ([child isInteresting]) {
+ if (!_mostInterestingChild)
+ _mostInterestingChild = child;
+ else if (child->_HUH > _mostInterestingChild->_HUH)
+ _mostInterestingChild = child;
+ }
+ }
+ }
+}
+- (FooHUHCode) HUH {
+ if (_HUH == Foo_HUH_NONE) {
+ if (_mostInterestingChild)
+ return [_mostInterestingChild HUH];
+ }
+}
+@end
+
diff --git a/test/SemaObjC/writable-property-in-superclass.m b/test/SemaObjC/writable-property-in-superclass.m
new file mode 100644
index 000000000000..182b1c47bb39
--- /dev/null
+++ b/test/SemaObjC/writable-property-in-superclass.m
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface MessageStore
+@property (assign, readonly) int P;
+@end
+
+@interface MessageStore (CAT)
+@property (assign) int P;
+@end
+
+@interface NeXTMbox : MessageStore
+@end
+
+@implementation NeXTMbox
+- (void) Meth { self.P = 1; }
+@end
+
diff --git a/test/SemaObjCXX/blocks.mm b/test/SemaObjCXX/blocks.mm
new file mode 100644
index 000000000000..3d421a878e59
--- /dev/null
+++ b/test/SemaObjCXX/blocks.mm
@@ -0,0 +1,46 @@
+// RUN: clang-cc -fsyntax-only -verify -fblocks %s
+@protocol NSObject;
+
+void bar(id(^)(void));
+void foo(id <NSObject>(^objectCreationBlock)(void)) {
+ return bar(objectCreationBlock); // expected-warning{{incompatible pointer types passing 'id (^)(void)', expected 'id<NSObject> (^)(void)'}}
+}
+
+void bar2(id(*)(void));
+void foo2(id <NSObject>(*objectCreationBlock)(void)) {
+ return bar2(objectCreationBlock); // expected-warning{{incompatible pointer types passing 'id (*)(void)', expected 'id<NSObject> (*)(void)'}}
+}
+
+void bar3(id(*)()); // expected-note{{candidate function}}
+void foo3(id (*objectCreationBlock)(int)) {
+ return bar3(objectCreationBlock); // expected-error{{no matching}}
+}
+
+void bar4(id(^)()); // expected-note{{candidate function}}
+void foo4(id (^objectCreationBlock)(int)) {
+ return bar4(objectCreationBlock); // expected-error{{no matching}}
+}
+
+void foo5(id (^x)(int)) {
+ if (x) { }
+}
+
+// <rdar://problem/6590445>
+@interface Foo {
+ @private
+ void (^_block)(void);
+}
+- (void)bar;
+@end
+
+namespace N {
+ class X { };
+ void foo(X);
+}
+
+@implementation Foo
+- (void)bar {
+ _block();
+ foo(N::X()); // okay
+}
+@end
diff --git a/test/SemaObjCXX/cocoa.mm b/test/SemaObjCXX/cocoa.mm
new file mode 100644
index 000000000000..c061d4e09684
--- /dev/null
+++ b/test/SemaObjCXX/cocoa.mm
@@ -0,0 +1,4 @@
+// RUN: clang-cc -mcpu=pentium4 %s -print-stats
+#ifdef __APPLE__
+#include <Cocoa/Cocoa.h>
+#endif
diff --git a/test/SemaObjCXX/linkage-spec.mm b/test/SemaObjCXX/linkage-spec.mm
new file mode 100644
index 000000000000..2cc0936b2ed2
--- /dev/null
+++ b/test/SemaObjCXX/linkage-spec.mm
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+extern "C" {
+@class Protocol;
+}
diff --git a/test/SemaObjCXX/objc-decls-inside-namespace.mm b/test/SemaObjCXX/objc-decls-inside-namespace.mm
new file mode 100644
index 000000000000..cedfcfdb9e4b
--- /dev/null
+++ b/test/SemaObjCXX/objc-decls-inside-namespace.mm
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace C {
+
+@protocol P; //expected-error{{Objective-C declarations may only appear in global scope}}
+
+@class Bar; //expected-error{{Objective-C declarations may only appear in global scope}}
+
+@compatibility_alias Foo Bar; //expected-error{{Objective-C declarations may only appear in global scope}}
+
+@interface A //expected-error{{Objective-C declarations may only appear in global scope}}
+@end
+
+@implementation A //expected-error{{Objective-C declarations may only appear in global scope}}
+@end
+
+@protocol P //expected-error{{Objective-C declarations may only appear in global scope}}
+@end
+
+@interface A(C) //expected-error{{Objective-C declarations may only appear in global scope}}
+@end
+
+@implementation A(C) //expected-error{{Objective-C declarations may only appear in global scope}}
+@end
+
+}
+
diff --git a/test/SemaObjCXX/overload.mm b/test/SemaObjCXX/overload.mm
new file mode 100644
index 000000000000..8ab22e1ca73e
--- /dev/null
+++ b/test/SemaObjCXX/overload.mm
@@ -0,0 +1,94 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+@interface Foo
+@end
+
+@implementation Foo
+
+void func(id);
+
++ zone {
+ func(self);
+ return self;
+}
+@end
+
+@protocol P0
+@end
+
+@protocol P1
+@end
+
+@interface A <P0>
+@end
+
+@interface B : A
+@end
+
+@interface C <P1>
+@end
+
+int& f(A*);
+float& f(B*);
+void g(A*);
+
+int& h(A*);
+float& h(id);
+
+void test(A* a, B* b, id val) {
+ int& i1 = f(a);
+ float& f1 = f(b);
+ float& f2 = f(val);
+ g(a);
+ g(b);
+ g(val);
+ int& i2 = h(a);
+ float& f3 = h(val);
+ // int& i3 = h(b); FIXME: we match GCC here, but shouldn't this work?
+}
+
+void downcast_test(A* a, A** ap) {
+ B* b = a; // expected-warning{{incompatible pointer types initializing 'B *', expected 'A *'}}
+ b = a; // expected-warning{{incompatible pointer types assigning 'B *', expected 'A *'}}
+
+ B** bp = ap; // expected-warning{{incompatible pointer types initializing 'B **', expected 'A **'}}
+ bp = ap; // expected-warning{{incompatible pointer types assigning 'B **', expected 'A **'}}
+}
+
+int& cv(A*);
+float& cv(const A*);
+int& cv2(void*);
+float& cv2(const void*);
+
+void cv_test(A* a, B* b, const A* ac, const B* bc) {
+ int &i1 = cv(a);
+ int &i2 = cv(b);
+ float &f1 = cv(ac);
+ float &f2 = cv(bc);
+ int& i3 = cv2(a);
+ float& f3 = cv2(ac);
+}
+
+
+int& qualid(id<P0>);
+float& qualid(id<P1>); // FIXME: GCC complains that this isn't an overload. Is it?
+
+void qualid_test(A *a, B *b, C *c) {
+ int& i1 = qualid(a);
+ int& i2 = qualid(b);
+ float& f1 = qualid(c);
+
+ id<P0> p1 = 0;
+ p1 = 0;
+}
+
+
+@class NSException;
+typedef struct {
+ void (*throw_exc)(id);
+}
+objc_exception_functions_t;
+
+void (*_NSExceptionRaiser(void))(NSException *) {
+ objc_exception_functions_t exc_funcs;
+ return exc_funcs.throw_exc; // expected-warning{{incompatible pointer types returning 'void (*)(NSException *)', expected 'void (*)(id)'}}
+}
diff --git a/test/SemaObjCXX/protocol-lookup.mm b/test/SemaObjCXX/protocol-lookup.mm
new file mode 100644
index 000000000000..0f1860d2c88e
--- /dev/null
+++ b/test/SemaObjCXX/protocol-lookup.mm
@@ -0,0 +1,50 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+@protocol NSObject
+- retain;
+- release;
+@end
+
+@interface NSObject
+- init;
+- dealloc;
+@end
+
+@protocol Foo <NSObject>
+@end
+
+@protocol Bar <Foo>
+@end
+
+@interface Baz : NSObject {
+ id <Foo> _foo;
+ id <Bar> _bar;
+}
+- (id)initWithFoo:(id <Foo>)foo bar:(id <Bar>)bar;
+@end
+
+@implementation Baz
+
+- (id)init
+{
+ return [self initWithFoo:0 bar:0];
+}
+
+- (id)initWithFoo:(id <Foo>)foo bar:(id <Bar>)bar
+{
+ self = [super init];
+ if (self != 0) {
+ _foo = [foo retain];
+ _bar = [bar retain];
+ }
+ return self;
+}
+
+- dealloc
+{
+ [_foo release];
+ [_bar release];
+ [super dealloc];
+}
+
+@end
+
diff --git a/test/SemaObjCXX/reserved-keyword-selectors.mm b/test/SemaObjCXX/reserved-keyword-selectors.mm
new file mode 100644
index 000000000000..2875f9352737
--- /dev/null
+++ b/test/SemaObjCXX/reserved-keyword-selectors.mm
@@ -0,0 +1,35 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+@interface A
+- (void)asm;
+- (void)bool;
+- (void)catch;
+- (void)class;
+- (void)const_cast;
+- (void)delete;
+- (void)dynamic_cast;
+- (void)explicit;
+- (void)export;
+- (void)false;
+- (void)friend;
+- (void)mutable;
+- (void)namespace;
+- (void)new;
+- (void)operator;
+- (void)private;
+- (void)protected;
+- (void)public;
+- (void)reinterpret_cast;
+- (void)static_cast;
+- (void)template;
+- (void)this;
+- (void)throw;
+- (void)true;
+- (void)try;
+- (void)typename;
+- (void)typeid;
+- (void)using;
+- (void)virtual;
+- (void)wchar_t;
+@end
+
diff --git a/test/SemaObjCXX/vararg-non-pod.mm b/test/SemaObjCXX/vararg-non-pod.mm
new file mode 100644
index 000000000000..eeed09e61637
--- /dev/null
+++ b/test/SemaObjCXX/vararg-non-pod.mm
@@ -0,0 +1,32 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+extern char version[];
+
+@protocol P;
+
+class C {
+public:
+ C(int);
+};
+
+@interface D
+- (void)g:(int)a, ...;
+@end
+
+void t1(D *d)
+{
+ C c(10);
+
+ [d g:10, c]; // expected-warning{{cannot pass object of non-POD type 'class C' through variadic method; call will abort at runtime}}
+ [d g:10, version];
+}
+
+void t2(D *d, id p)
+{
+ [d g:10, p];
+}
+
+void t3(D *d, id<P> p)
+{
+ [d g:10, p];
+}
diff --git a/test/SemaObjCXX/void_to_obj.mm b/test/SemaObjCXX/void_to_obj.mm
new file mode 100644
index 000000000000..d1fbf6b69079
--- /dev/null
+++ b/test/SemaObjCXX/void_to_obj.mm
@@ -0,0 +1,11 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// <rdar://problem/6463729>
+@class XX;
+
+void func() {
+ XX *obj;
+ void *vv;
+
+ obj = vv; // expected-error{{incompatible type assigning 'void *', expected 'XX *'}}
+}
diff --git a/test/SemaTemplate/class-template-decl.cpp b/test/SemaTemplate/class-template-decl.cpp
new file mode 100644
index 000000000000..c81267771297
--- /dev/null
+++ b/test/SemaTemplate/class-template-decl.cpp
@@ -0,0 +1,49 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T> class A;
+
+extern "C++" {
+ template<typename T> class B;
+}
+
+namespace N {
+ template<typename T> class C;
+}
+
+extern "C" {
+ template<typename T> class D; // expected-error{{templates must have C++ linkage}}
+}
+
+template<class U> class A; // expected-note{{previous template declaration is here}}
+
+template<int N> class A; // expected-error{{template parameter has a different kind in template redeclaration}}
+
+template<int N> class NonTypeTemplateParm;
+
+typedef int INT;
+
+template<INT M> class NonTypeTemplateParm; // expected-note{{previous non-type template parameter with type 'INT' (aka 'int') is here}}
+
+template<long> class NonTypeTemplateParm; // expected-error{{template non-type parameter has a different type 'long' in template redeclaration}}
+
+template<template<typename T> class X> class TemplateTemplateParm;
+
+template<template<class> class Y> class TemplateTemplateParm; // expected-note{{previous template declaration is here}} \
+ // expected-note{{previous template template parameter is here}}
+
+template<typename> class TemplateTemplateParm; // expected-error{{template parameter has a different kind in template redeclaration}}
+
+template<template<typename T, int> class X> class TemplateTemplateParm; // expected-error{{too many template parameters in template template parameter redeclaration}}
+
+#if 0
+// FIXME: parse template declarations in these scopes, so that we can
+// complain about the one at function scope.
+class X {
+public:
+ template<typename T> class C;
+};
+
+void f() {
+ template<typename T> class X;
+}
+#endif
diff --git a/test/SemaTemplate/class-template-id-2.cpp b/test/SemaTemplate/class-template-id-2.cpp
new file mode 100644
index 000000000000..c4388a7c1556
--- /dev/null
+++ b/test/SemaTemplate/class-template-id-2.cpp
@@ -0,0 +1,24 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+namespace N {
+ template<typename T> class A { };
+
+ template<> class A<int> { };
+
+ template<> class A<float>; // expected-note{{forward declaration of 'class N::A<float>'}}
+
+ class B : public A<int> { };
+}
+
+class C1 : public N::A<int> { };
+
+class C2 : public N::A<float> { }; // expected-error{{base class has incomplete type}}
+
+struct D1 {
+ operator N::A<int>();
+};
+
+namespace N {
+ struct D2 {
+ operator A<int>();
+ };
+}
diff --git a/test/SemaTemplate/class-template-id.cpp b/test/SemaTemplate/class-template-id.cpp
new file mode 100644
index 000000000000..e74a6f8dcca9
--- /dev/null
+++ b/test/SemaTemplate/class-template-id.cpp
@@ -0,0 +1,38 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T, typename U = float> struct A { };
+
+typedef A<int> A_int;
+
+typedef float FLOAT;
+
+A<int, FLOAT> *foo(A<int> *ptr, A<int> const *ptr2, A<int, double> *ptr3) {
+ if (ptr)
+ return ptr; // okay
+ else if (ptr2)
+ return ptr2; // expected-error{{incompatible type returning 'A<int> const *', expected 'A<int, FLOAT> *'}}
+ else {
+ return ptr3; // expected-error{{incompatible type returning 'A<int, double> *', expected 'A<int, FLOAT> *'}}
+ }
+}
+
+template<int I> struct B;
+
+const int value = 12;
+B<17 + 2> *bar(B<(19)> *ptr1, B< (::value + 7) > *ptr2, B<19 - 3> *ptr3) {
+ if (ptr1)
+ return ptr1;
+ else if (ptr2)
+ return ptr2;
+ else
+ return ptr3; // expected-error{{incompatible type returning 'B<19 - 3> *', expected 'B<17 + 2> *'}}
+}
+
+typedef B<5> B5;
+
+
+namespace N {
+ template<typename T> struct C {};
+}
+
+N::C<int> c1;
+typedef N::C<float> c2;
diff --git a/test/SemaTemplate/class-template-spec.cpp b/test/SemaTemplate/class-template-spec.cpp
new file mode 100644
index 000000000000..71d8ea14be6b
--- /dev/null
+++ b/test/SemaTemplate/class-template-spec.cpp
@@ -0,0 +1,80 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T, typename U = int> struct A; // expected-note 2{{template is declared here}}
+
+template<> struct A<double, double>; // expected-note{{forward declaration}}
+
+template<> struct A<float, float> { // expected-note{{previous definition}}
+ int x;
+};
+
+template<> struct A<float> { // expected-note{{previous definition}}
+ int y;
+};
+
+int test_specs(A<float, float> *a1, A<float, int> *a2) {
+ return a1->x + a2->y;
+}
+
+int test_incomplete_specs(A<double, double> *a1,
+ A<double> *a2)
+{
+ (void)a1->x; // expected-error{{incomplete definition of type 'A<double, double>'}}
+ (void)a2->x; // expected-error{{implicit instantiation of undefined template 'struct A<double, int>'}}
+}
+
+typedef float FLOAT;
+
+template<> struct A<float, FLOAT>;
+
+template<> struct A<FLOAT, float> { }; // expected-error{{redefinition}}
+
+template<> struct A<float, int> { }; // expected-error{{redefinition}}
+
+template<typename T, typename U = int> struct X;
+
+template <> struct X<int, int> { int foo(); }; // #1
+template <> struct X<float> { int bar(); }; // #2
+
+typedef int int_type;
+void testme(X<int_type> *x1, X<float, int> *x2) {
+ (void)x1->foo(); // okay: refers to #1
+ (void)x2->bar(); // okay: refers to #2
+}
+
+// Make sure specializations are proper classes.
+template<>
+struct A<char> {
+ A();
+};
+
+A<char>::A() { }
+
+// Diagnose specialization errors
+struct A<double> { }; // expected-error{{template specialization requires 'template<>'}}
+
+template<> struct ::A<double>;
+
+namespace N {
+ template<typename T> struct B; // expected-note 2{{template is declared here}}
+
+ template<> struct ::N::B<char>; // okay
+ template<> struct ::N::B<short>; // okay
+ template<> struct ::N::B<int>; // okay
+
+ int f(int);
+}
+
+template<> struct N::B<int> { }; // okay
+
+template<> struct N::B<float> { }; // expected-error{{class template specialization of 'B' not in namespace 'N'}}
+
+namespace M {
+ template<> struct ::N::B<short> { }; // expected-error{{class template specialization of 'B' not in a namespace enclosing 'N'}}
+
+ template<> struct ::A<long double>; // expected-error{{class template specialization of 'A' must occur in the global scope}}
+}
+
+template<> struct N::B<char> {
+ int testf(int x) { return f(x); }
+};
+
diff --git a/test/SemaTemplate/current-instantiation.cpp b/test/SemaTemplate/current-instantiation.cpp
new file mode 100644
index 000000000000..603c14016fbc
--- /dev/null
+++ b/test/SemaTemplate/current-instantiation.cpp
@@ -0,0 +1,71 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// This test concerns the identity of dependent types within the
+// canonical type system, specifically focusing on the difference
+// between members of the current instantiation and membmers of an
+// unknown specialization. This considers C++ [temp.type], which
+// specifies type equivalence within a template, and C++0x
+// [temp.dep.type], which defines what it means to be a member of the
+// current instantiation.
+
+template<typename T, typename U>
+struct X0 {
+ typedef T T_type;
+ typedef U U_type;
+
+ void f0(T&); // expected-note{{previous}}
+ void f0(typename X0::U_type&);
+ void f0(typename X0::T_type&); // expected-error{{redecl}}
+
+ void f1(T&); // expected-note{{previous}}
+ void f1(typename X0::U_type&);
+ void f1(typename X0<T, U>::T_type&); // expected-error{{redecl}}
+
+ void f2(T&); // expected-note{{previous}}
+ void f2(typename X0::U_type&);
+ void f2(typename X0<T_type, U_type>::T_type&); // expected-error{{redecl}}
+
+ void f3(T&); // expected-note{{previous}}
+ void f3(typename X0::U_type&);
+ void f3(typename ::X0<T_type, U_type>::T_type&); // expected-error{{redecl}}
+
+ struct X1 {
+ typedef T my_T_type;
+
+ void g0(T&); // expected-note{{previous}}
+ void g0(typename X0::U_type&);
+ void g0(typename X0::T_type&); // expected-error{{redecl}}
+
+ void g1(T&); // expected-note{{previous}}
+ void g1(typename X0::U_type&);
+ void g1(typename X0<T, U>::T_type&); // expected-error{{redecl}}
+
+ void g2(T&); // expected-note{{previous}}
+ void g2(typename X0::U_type&);
+ void g2(typename X0<T_type, U_type>::T_type&); // expected-error{{redecl}}
+
+ void g3(T&); // expected-note{{previous}}
+ void g3(typename X0::U_type&);
+ void g3(typename ::X0<T_type, U_type>::T_type&); // expected-error{{redecl}}
+
+ void g4(T&); // expected-note{{previous}}
+ void g4(typename X0::U_type&);
+ void g4(typename X1::my_T_type&); // expected-error{{redecl}}
+
+ void g5(T&); // expected-note{{previous}}
+ void g5(typename X0::U_type&);
+ void g5(typename X0::X1::my_T_type&); // expected-error{{redecl}}
+
+ void g6(T&); // expected-note{{previous}}
+ void g6(typename X0::U_type&);
+ void g6(typename X0<T, U>::X1::my_T_type&); // expected-error{{redecl}}
+
+ void g7(T&); // expected-note{{previous}}
+ void g7(typename X0::U_type&);
+ void g7(typename ::X0<typename X1::my_T_type, U_type>::X1::my_T_type&); // expected-error{{redecl}}
+
+ void g8(T&); // expected-note{{previous}}
+ void g8(typename X0<U, T_type>::T_type&);
+ void g8(typename ::X0<typename X0<T_type, U>::X1::my_T_type, U_type>::X1::my_T_type&); // expected-error{{redecl}}
+ };
+};
diff --git a/test/SemaTemplate/default-arguments.cpp b/test/SemaTemplate/default-arguments.cpp
new file mode 100644
index 000000000000..572227cb61de
--- /dev/null
+++ b/test/SemaTemplate/default-arguments.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, int N = 2> struct X; // expected-note{{template is declared here}}
+
+X<int, 1> *x1;
+X<int> *x2;
+
+X<> *x3; // expected-error{{too few template arguments for class template 'X'}}
+
+template<typename U = float, int M> struct X;
+
+X<> *x4;
diff --git a/test/SemaTemplate/dependent-type-identity.cpp b/test/SemaTemplate/dependent-type-identity.cpp
new file mode 100644
index 000000000000..739cb7f39fa3
--- /dev/null
+++ b/test/SemaTemplate/dependent-type-identity.cpp
@@ -0,0 +1,72 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// This test concerns the identity of dependent types within the
+// canonical type system. This corresponds to C++ [temp.type], which
+// specifies type equivalence within a template.
+//
+// FIXME: template template parameters
+
+namespace N {
+ template<typename T>
+ struct X2 {
+ template<typename U>
+ struct apply {
+ typedef U* type;
+ };
+ };
+}
+
+namespace Nalias = N;
+
+template<typename T>
+struct X0 { };
+
+using namespace N;
+
+template<typename T, typename U>
+struct X1 {
+ typedef T type;
+ typedef U U_type;
+
+ void f0(T); // expected-note{{previous}}
+ void f0(U);
+ void f0(type); // expected-error{{redeclar}}
+
+ void f1(T*); // expected-note{{previous}}
+ void f1(U*);
+ void f1(type*); // expected-error{{redeclar}}
+
+ void f2(X0<T>*); // expected-note{{previous}}
+ void f2(X0<U>*);
+ void f2(X0<type>*); // expected-error{{redeclar}}
+
+ void f3(X0<T>*); // expected-note{{previous}}
+ void f3(X0<U>*);
+ void f3(::X0<type>*); // expected-error{{redeclar}}
+
+ void f4(typename T::template apply<U>*); // expected-note{{previous}}
+ void f4(typename U::template apply<U>*);
+ void f4(typename type::template apply<T>*);
+ void f4(typename type::template apply<U_type>*); // expected-error{{redeclar}}
+
+ void f5(typename T::template apply<U>::type*); // expected-note{{previous}}
+ void f5(typename U::template apply<U>::type*);
+ void f5(typename U::template apply<T>::type*);
+ void f5(typename type::template apply<T>::type*);
+ void f5(typename type::template apply<U_type>::type*); // expected-error{{redeclar}}
+
+ void f6(typename N::X2<T>::template apply<U> *); // expected-note{{previous}}
+ void f6(typename N::X2<U>::template apply<U> *);
+ void f6(typename N::X2<U>::template apply<T> *);
+ void f6(typename ::N::X2<type>::template apply<U_type> *); // expected-error{{redeclar}}
+
+ void f7(typename N::X2<T>::template apply<U> *); // expected-note{{previous}}
+ void f7(typename N::X2<U>::template apply<U> *);
+ void f7(typename N::X2<U>::template apply<T> *);
+ void f7(typename X2<type>::template apply<U_type> *); // expected-error{{redeclar}}
+
+ void f8(typename N::X2<T>::template apply<U> *); // expected-note{{previous}}
+ void f8(typename N::X2<U>::template apply<U> *);
+ void f8(typename N::X2<U>::template apply<T> *);
+ void f8(typename ::Nalias::X2<type>::template apply<U_type> *); // expected-error{{redeclar}}
+};
diff --git a/test/SemaTemplate/enum-argument.cpp b/test/SemaTemplate/enum-argument.cpp
new file mode 100644
index 000000000000..101a1d0cd9da
--- /dev/null
+++ b/test/SemaTemplate/enum-argument.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+enum Enum { val = 1 };
+template <Enum v> struct C {
+ typedef C<v> Self;
+};
+template struct C<val>;
diff --git a/test/SemaTemplate/example-dynarray.cpp b/test/SemaTemplate/example-dynarray.cpp
new file mode 100644
index 000000000000..cca3709bebbf
--- /dev/null
+++ b/test/SemaTemplate/example-dynarray.cpp
@@ -0,0 +1,150 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+#include <stddef.h>
+#include <stdlib.h>
+#include <assert.h>
+
+// Placement new requires <new> to be included, but we don't support that yet.
+void* operator new(size_t, void* ptr) throw() {
+ return ptr;
+}
+void operator delete(void*, void*) throw() {
+}
+
+template<typename T>
+class dynarray {
+public:
+ dynarray() { Start = Last = End = 0; }
+
+ dynarray(const dynarray &other) {
+ Start = (T*)malloc(sizeof(T) * other.size());
+ Last = End = Start + other.size();
+
+ for (unsigned I = 0, N = other.size(); I != N; ++I)
+ new (Start + I) T(other[I]);
+ }
+
+ ~dynarray() {
+ free(Start);
+ }
+
+ dynarray &operator=(const dynarray &other) {
+ T* NewStart = (T*)malloc(sizeof(T) * other.size());
+
+ for (unsigned I = 0, N = other.size(); I != N; ++I)
+ new (NewStart + I) T(other[I]);
+
+ // FIXME: destroy everything in Start
+ free(Start);
+ Start = NewStart;
+ Last = End = NewStart + other.size();
+ return *this;
+ }
+
+ unsigned size() const { return Last - Start; }
+ unsigned capacity() const { return End - Start; }
+
+ void push_back(const T& value) {
+ if (Last == End) {
+ unsigned NewCapacity = capacity() * 2;
+ if (NewCapacity == 0)
+ NewCapacity = 4;
+
+ T* NewStart = (T*)malloc(sizeof(T) * NewCapacity);
+
+ unsigned Size = size();
+ for (unsigned I = 0; I != Size; ++I)
+ new (NewStart + I) T(Start[I]);
+
+ // FIXME: destruct old values
+ free(Start);
+
+ Start = NewStart;
+ Last = Start + Size;
+ End = Start + NewCapacity;
+ }
+
+ new (Last) T(value);
+ ++Last;
+ }
+
+ void pop_back() {
+ // FIXME: destruct old value
+ --Last;
+ }
+
+ T& operator[](unsigned Idx) {
+ return Start[Idx];
+ }
+
+ const T& operator[](unsigned Idx) const {
+ return Start[Idx];
+ }
+
+ typedef T* iterator;
+ typedef const T* const_iterator;
+
+ iterator begin() { return Start; }
+ const_iterator begin() const { return Start; }
+
+ iterator end() { return Last; }
+ const_iterator end() const { return Last; }
+
+public:
+ T* Start, *Last, *End;
+};
+
+struct Point {
+ Point() { x = y = z = 0.0; }
+ Point(const Point& other) : x(other.x), y(other.y), z(other.z) { }
+
+ float x, y, z;
+};
+
+// FIXME: remove these when we have implicit instantiation for member
+// functions of class templates.
+template class dynarray<int>;
+template class dynarray<Point>;
+
+int main() {
+ dynarray<int> di;
+ di.push_back(0);
+ di.push_back(1);
+ di.push_back(2);
+ di.push_back(3);
+ di.push_back(4);
+ assert(di.size() == 5);
+ for (dynarray<int>::iterator I = di.begin(), IEnd = di.end(); I != IEnd; ++I)
+ assert(*I == I - di.begin());
+
+ for (int I = 0, N = di.size(); I != N; ++I)
+ assert(di[I] == I);
+
+ di.pop_back();
+ assert(di.size() == 4);
+ di.push_back(4);
+
+ dynarray<int> di2 = di;
+ assert(di2.size() == 5);
+ assert(di.begin() != di2.begin());
+ for (dynarray<int>::iterator I = di2.begin(), IEnd = di2.end();
+ I != IEnd; ++I)
+ assert(*I == I - di2.begin());
+
+ dynarray<int> di3(di);
+ assert(di3.size() == 5);
+ assert(di.begin() != di3.begin());
+ for (dynarray<int>::iterator I = di3.begin(), IEnd = di3.end();
+ I != IEnd; ++I)
+ assert(*I == I - di3.begin());
+
+ dynarray<int> di4;
+ assert(di4.size() == 0);
+ di4 = di;
+ assert(di4.size() == 5);
+ assert(di.begin() != di4.begin());
+ for (dynarray<int>::iterator I = di4.begin(), IEnd = di4.end();
+ I != IEnd; ++I)
+ assert(*I == I - di4.begin());
+
+ return 0;
+}
diff --git a/test/SemaTemplate/fibonacci.cpp b/test/SemaTemplate/fibonacci.cpp
new file mode 100644
index 000000000000..6cd50157e2bd
--- /dev/null
+++ b/test/SemaTemplate/fibonacci.cpp
@@ -0,0 +1,66 @@
+// RUN: clang-cc -fsyntax-only %s
+
+template<unsigned I>
+struct FibonacciEval;
+
+template<unsigned I>
+struct Fibonacci {
+ enum { value = FibonacciEval<I-1>::value + FibonacciEval<I-2>::value };
+};
+
+template<unsigned I>
+struct FibonacciEval {
+ enum { value = Fibonacci<I>::value };
+};
+
+template<> struct Fibonacci<0> {
+ enum { value = 0 };
+};
+
+template<> struct Fibonacci<1> {
+ enum { value = 1 };
+};
+
+int array5[Fibonacci<5>::value == 5? 1 : -1];
+int array10[Fibonacci<10>::value == 55? 1 : -1];
+
+template<unsigned I>
+struct FibonacciEval2;
+
+template<unsigned I>
+struct Fibonacci2 {
+ static const unsigned value
+ = FibonacciEval2<I-1>::value + FibonacciEval2<I-2>::value;
+};
+
+template<unsigned I>
+struct FibonacciEval2 {
+ static const unsigned value = Fibonacci2<I>::value;
+};
+
+template<> struct Fibonacci2<0> {
+ static const unsigned value = 0;
+};
+
+template<> struct Fibonacci2<1> {
+ static const unsigned value = 1;
+};
+
+int array5_2[Fibonacci2<5>::value == 5? 1 : -1];
+int array10_2[Fibonacci2<10>::value == 55? 1 : -1];
+
+template<unsigned I>
+struct Fibonacci3 {
+ static const unsigned value = Fibonacci3<I-1>::value + Fibonacci3<I-2>::value;
+};
+
+template<> struct Fibonacci3<0> {
+ static const unsigned value = 0;
+};
+
+template<> struct Fibonacci3<1> {
+ static const unsigned value = 1;
+};
+
+int array5_3[Fibonacci3<5>::value == 5? 1 : -1];
+int array10_3[Fibonacci3<10>::value == 55? 1 : -1];
diff --git a/test/SemaTemplate/fun-template-def.cpp b/test/SemaTemplate/fun-template-def.cpp
new file mode 100644
index 000000000000..8833ef4ddc1d
--- /dev/null
+++ b/test/SemaTemplate/fun-template-def.cpp
@@ -0,0 +1,43 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Tests that dependent expressions are always allowed, whereas non-dependent
+// are checked as usual.
+
+#include <stddef.h>
+
+// Fake typeid, lacking a typeinfo header.
+namespace std { class type_info {}; }
+
+struct dummy {};
+
+template <typename T, typename U>
+T f(T t1, U u1, int i1)
+{
+ T t2 = i1;
+ t2 = i1 + u1;
+ ++u1;
+ u1++;
+ int i2 = u1;
+
+ i1 = t1[u1];
+ i1 *= t1;
+
+ i1(u1, t1); // error
+ u1(i1, t1);
+
+ U u2 = (T)i1;
+ static_cast<void>(static_cast<U>(reinterpret_cast<T>(
+ dynamic_cast<U>(const_cast<T>(i1)))));
+
+ new U(i1, t1);
+ new int(t1, u1); // expected-error {{initializer of a builtin type can only take one argument}}
+ new (t1, u1) int;
+ delete t1;
+
+ dummy d1 = sizeof(t1); // FIXME: delayed checking okay?
+ dummy d2 = offsetof(T, foo); // expected-error {{cannot initialize 'd2'}}
+ dummy d3 = __alignof(u1); // FIXME: delayed checking okay?
+ i1 = typeid(t1); // expected-error {{incompatible type assigning}}
+
+ return u1;
+}
diff --git a/test/SemaTemplate/injected-class-name.cpp b/test/SemaTemplate/injected-class-name.cpp
new file mode 100644
index 000000000000..c5f826d849ca
--- /dev/null
+++ b/test/SemaTemplate/injected-class-name.cpp
@@ -0,0 +1,40 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T>
+struct X {
+ X<T*> *ptr;
+};
+
+X<int> x;
+
+template<>
+struct X<int***> {
+ typedef X<int***> *ptr;
+};
+
+// FIXME: EDG rejects this in their strict-conformance mode, but I
+// don't see any wording making this ill-formed. Actually,
+// [temp.local]p2 might make it ill-formed. Are we "in the scope of
+// the class template specialization?"
+X<float>::X<int> xi = x;
+
+// [temp.local]p1:
+
+// FIXME: test non-type and template template parameters
+template<typename T, typename U>
+struct X0 {
+ typedef T type;
+ typedef U U_type;
+ typedef U_type U_type2;
+
+ void f0(const X0&); // expected-note{{here}}
+ void f0(X0&);
+ void f0(const X0<T, U>&); // expected-error{{redecl}}
+
+ void f1(const X0&); // expected-note{{here}}
+ void f1(X0&);
+ void f1(const X0<type, U_type2>&); // expected-error{{redecl}}
+
+ void f2(const X0&); // expected-note{{here}}
+ void f2(X0&);
+ void f2(const ::X0<type, U_type2>&); // expected-error{{redecl}}
+};
diff --git a/test/SemaTemplate/instantiate-array.cpp b/test/SemaTemplate/instantiate-array.cpp
new file mode 100644
index 000000000000..29279b436899
--- /dev/null
+++ b/test/SemaTemplate/instantiate-array.cpp
@@ -0,0 +1,28 @@
+// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
+
+#ifndef __GXX_EXPERIMENTAL_CXX0X__
+#define __CONCAT(__X, __Y) __CONCAT1(__X, __Y)
+#define __CONCAT1(__X, __Y) __X ## __Y
+
+#define static_assert(__b, __m) \
+ typedef int __CONCAT(__sa, __LINE__)[__b ? 1 : -1]
+#endif
+
+template <int N> class IntArray {
+ int elems[N];
+};
+
+static_assert(sizeof(IntArray<10>) == sizeof(int) * 10, "Array size mismatch");
+static_assert(sizeof(IntArray<1>) == sizeof(int) * 1, "Array size mismatch");
+
+template <typename T> class TenElementArray {
+ int elems[10];
+};
+
+static_assert(sizeof(TenElementArray<int>) == sizeof(int) * 10, "Array size mismatch");
+
+template<typename T, int N> class Array {
+ T elems[N];
+};
+
+static_assert(sizeof(Array<int, 10>) == sizeof(int) * 10, "Array size mismatch");
diff --git a/test/SemaTemplate/instantiate-c99.cpp b/test/SemaTemplate/instantiate-c99.cpp
new file mode 100644
index 000000000000..cf691cffad36
--- /dev/null
+++ b/test/SemaTemplate/instantiate-c99.cpp
@@ -0,0 +1,81 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Test template instantiation for C99-specific features.
+
+// ---------------------------------------------------------------------
+// Designated initializers
+// ---------------------------------------------------------------------
+template<typename T, typename XType, typename YType>
+struct DesigInit0 {
+ void f(XType x, YType y) {
+ T agg = {
+ .y = y, // expected-error{{does not refer}}
+ .x = x // expected-error{{does not refer}}
+ };
+ }
+};
+
+struct Point2D {
+ float x, y;
+};
+
+template struct DesigInit0<Point2D, int, double>;
+
+struct Point3D {
+ float x, y, z;
+};
+
+template struct DesigInit0<Point3D, int, double>;
+
+struct Color {
+ unsigned char red, green, blue;
+};
+
+struct ColorPoint3D {
+ Color color;
+ float x, y, z;
+};
+
+template struct DesigInit0<ColorPoint3D, int, double>;
+template struct DesigInit0<Color, int, double>; // expected-note{{instantiation}}
+
+template<typename T, int Subscript1, int Subscript2,
+ typename Val1, typename Val2>
+struct DesigArrayInit0 {
+ void f(Val1 val1, Val2 val2) {
+ T array = {
+ [Subscript1] = val1,
+ [Subscript2] = val2 // expected-error{{exceeds array bounds}}
+ };
+
+ int array2[10] = { [5] = 3 };
+ }
+};
+
+template struct DesigArrayInit0<int[8], 5, 3, float, int>;
+template struct DesigArrayInit0<int[8], 5, 13, float, int>; // expected-note{{instantiation}}
+
+template<typename T, int Subscript1, int Subscript2,
+ typename Val1>
+struct DesigArrayRangeInit0 {
+ void f(Val1 val1) {
+ T array = {
+ [Subscript1...Subscript2] = val1 // expected-error{{exceeds}}
+ };
+ }
+};
+
+template struct DesigArrayRangeInit0<int[8], 3, 5, float>;
+template struct DesigArrayRangeInit0<int[8], 5, 13, float>; // expected-note{{instantiation}}
+
+// ---------------------------------------------------------------------
+// Compound literals
+// ---------------------------------------------------------------------
+template<typename T, typename Arg1, typename Arg2>
+struct CompoundLiteral0 {
+ T f(Arg1 a1, Arg2 a2) {
+ return (T){a1, a2};
+ }
+};
+
+template struct CompoundLiteral0<Point2D, int, float>;
diff --git a/test/SemaTemplate/instantiate-call.cpp b/test/SemaTemplate/instantiate-call.cpp
new file mode 100644
index 000000000000..a9c4bf481ded
--- /dev/null
+++ b/test/SemaTemplate/instantiate-call.cpp
@@ -0,0 +1,50 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace N1 {
+ struct X0 { };
+
+ int& f0(X0);
+}
+
+namespace N2 {
+ char& f0(char);
+
+ template<typename T, typename Result>
+ struct call_f0 {
+ void test_f0(T t) {
+ Result result = f0(t);
+ }
+ };
+}
+
+template struct N2::call_f0<int, char&>;
+template struct N2::call_f0<N1::X0, int&>;
+
+namespace N3 {
+ template<typename T, typename Result>
+ struct call_f0 {
+ void test_f0(T t) {
+ Result &result = f0(t); // expected-error 2{{no matching}}
+ }
+ };
+}
+
+template struct N3::call_f0<int, char&>; // expected-note{{instantiation}}
+template struct N3::call_f0<N1::X0, int&>;
+
+short& f0(char);
+namespace N4 {
+ template<typename T, typename Result>
+ struct call_f0 {
+ void test_f0(T t) {
+ Result &result = f0(t);
+ }
+ };
+}
+
+template struct N4::call_f0<int, short&>;
+template struct N4::call_f0<N1::X0, int&>;
+template struct N3::call_f0<int, short&>; // expected-note{{instantiation}}
+
+// FIXME: test overloaded function call operators, calls to member
+// functions, etc.
diff --git a/test/SemaTemplate/instantiate-cast.cpp b/test/SemaTemplate/instantiate-cast.cpp
new file mode 100644
index 000000000000..d99f3e556602
--- /dev/null
+++ b/test/SemaTemplate/instantiate-cast.cpp
@@ -0,0 +1,109 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct A { int x; };
+
+class Base {
+public:
+ virtual void f();
+};
+
+class Derived : public Base { };
+
+struct ConvertibleToInt {
+ operator int() const;
+};
+
+struct Constructible {
+ Constructible(int, float);
+};
+
+// ---------------------------------------------------------------------
+// C-style casts
+// ---------------------------------------------------------------------
+template<typename T, typename U>
+struct CStyleCast0 {
+ void f(T t) {
+ (void)((U)t); // FIXME:ugly expected-error{{operand}}
+ }
+};
+
+template struct CStyleCast0<int, float>;
+template struct CStyleCast0<A, int>; // expected-note{{instantiation}}
+
+// ---------------------------------------------------------------------
+// static_cast
+// ---------------------------------------------------------------------
+template<typename T, typename U>
+struct StaticCast0 {
+ void f(T t) {
+ (void)static_cast<U>(t); // expected-error{{static_cast}}
+ }
+};
+
+template struct StaticCast0<ConvertibleToInt, bool>;
+template struct StaticCast0<int, float>;
+template struct StaticCast0<int, A>; // expected-note{{instantiation}}
+
+// ---------------------------------------------------------------------
+// dynamic_cast
+// ---------------------------------------------------------------------
+template<typename T, typename U>
+struct DynamicCast0 {
+ void f(T t) {
+ (void)dynamic_cast<U>(t); // expected-error{{not a reference or pointer}}
+ }
+};
+
+template struct DynamicCast0<Base*, Derived*>;
+template struct DynamicCast0<Base*, A>; // expected-note{{instantiation}}
+
+// ---------------------------------------------------------------------
+// reinterpret_cast
+// ---------------------------------------------------------------------
+template<typename T, typename U>
+struct ReinterpretCast0 {
+ void f(T t) {
+ (void)reinterpret_cast<U>(t); // expected-error{{constness}}
+ }
+};
+
+template struct ReinterpretCast0<void (*)(int), void (*)(float)>;
+template struct ReinterpretCast0<int const *, float *>; // expected-note{{instantiation}}
+
+// ---------------------------------------------------------------------
+// const_cast
+// ---------------------------------------------------------------------
+template<typename T, typename U>
+struct ConstCast0 {
+ void f(T t) {
+ (void)const_cast<U>(t); // expected-error{{not allowed}}
+ }
+};
+
+template struct ConstCast0<int const * *, int * *>;
+template struct ConstCast0<int const *, float *>; // expected-note{{instantiation}}
+
+// ---------------------------------------------------------------------
+// C++ functional cast
+// ---------------------------------------------------------------------
+template<typename T, typename U>
+struct FunctionalCast1 {
+ void f(T t) {
+ (void)U(t); // FIXME:ugly expected-error{{operand}}
+ }
+};
+
+template struct FunctionalCast1<int, float>;
+template struct FunctionalCast1<A, int>; // expected-note{{instantiation}}
+
+#if 0
+// Generates temporaries, which we cannot handle yet.
+template<int N, long M>
+struct FunctionalCast2 {
+ void f() {
+ (void)Constructible(N, M);
+ }
+};
+
+template struct FunctionalCast2<1, 3>;
+#endif
diff --git a/test/SemaTemplate/instantiate-clang.cpp b/test/SemaTemplate/instantiate-clang.cpp
new file mode 100644
index 000000000000..a6c28d9e19db
--- /dev/null
+++ b/test/SemaTemplate/instantiate-clang.cpp
@@ -0,0 +1,35 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Test template instantiation for Clang-specific features.
+
+// ---------------------------------------------------------------------
+// Vector types
+// ---------------------------------------------------------------------
+typedef __attribute__(( ext_vector_type(2) )) double double2;
+typedef __attribute__(( ext_vector_type(4) )) double double4;
+
+template<typename T>
+struct ExtVectorAccess0 {
+ void f(T v1, double4 v2) {
+ v1.xy = v2.yx;
+ }
+};
+
+template struct ExtVectorAccess0<double2>;
+template struct ExtVectorAccess0<double4>;
+
+typedef __attribute__(( ext_vector_type(2) )) double double2;
+
+template<typename T, typename U, int N, int M>
+struct ShuffleVector0 {
+ void f(T t, U u, double2 a, double2 b) {
+ (void)__builtin_shufflevector(t, u, N, M); // expected-error{{index}}
+ (void)__builtin_shufflevector(a, b, N, M);
+ (void)__builtin_shufflevector(a, b, 2, 1);
+ }
+};
+
+template struct ShuffleVector0<double2, double2, 2, 1>;
+template struct ShuffleVector0<double2, double2, 4, 3>; // expected-note{{instantiation}}
+
+
diff --git a/test/SemaTemplate/instantiate-complete.cpp b/test/SemaTemplate/instantiate-complete.cpp
new file mode 100644
index 000000000000..babc55217a95
--- /dev/null
+++ b/test/SemaTemplate/instantiate-complete.cpp
@@ -0,0 +1,47 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Tests various places where requiring a complete type involves
+// instantiation of that type.
+
+template<typename T>
+struct X {
+ X(T);
+
+ T f; // expected-error{{data member instantiated with function type 'float (int)'}} \
+ // expected-error{{data member instantiated with function type 'int (int)'}} \
+ // expected-error{{data member instantiated with function type 'char (char)'}} \
+ // expected-error{{data member instantiated with function type 'short (short)'}} \
+ // expected-error{{data member instantiated with function type 'float (float)'}}
+};
+
+X<int> f() { return 0; }
+
+struct XField {
+ X<float(int)> xf; // expected-note{{in instantiation of template class 'struct X<float (int)>' requested here}}
+};
+
+void test_subscript(X<double> *ptr1, X<int(int)> *ptr2, int i) {
+ (void)ptr1[i];
+ (void)ptr2[i]; // expected-note{{in instantiation of template class 'struct X<int (int)>' requested here}}
+}
+
+void test_arith(X<signed char> *ptr1, X<unsigned char> *ptr2,
+ X<char(char)> *ptr3, X<short(short)> *ptr4) {
+ (void)(ptr1 + 5);
+ // FIXME: if I drop the ')' after void, below, it still parses (!)
+ (void)(5 + ptr2);
+ (void)(ptr3 + 5); // expected-note{{in instantiation of template class 'struct X<char (char)>' requested here}}
+ (void)(5 + ptr4); // expected-note{{in instantiation of template class 'struct X<short (short)>' requested here}}
+}
+
+void test_new() {
+ (void)new X<float>(0);
+ (void)new X<float(float)>; // expected-note{{in instantiation of template class 'struct X<float (float)>' requested here}}
+}
+
+void test_memptr(X<long> *p1, long X<long>::*pm1,
+ X<long(long)> *p2,
+ long (X<long(long)>::*pm2)(long)) {
+ (void)(p1->*pm1);
+ (void)((p2->*pm2)(0));
+}
diff --git a/test/SemaTemplate/instantiate-declref.cpp b/test/SemaTemplate/instantiate-declref.cpp
new file mode 100644
index 000000000000..051c6050abea
--- /dev/null
+++ b/test/SemaTemplate/instantiate-declref.cpp
@@ -0,0 +1,71 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+namespace N {
+ struct Outer {
+ struct Inner {
+ template<typename T>
+ struct InnerTemplate {
+ struct VeryInner {
+ typedef T type;
+
+ static enum K1 { K1Val = sizeof(T) } Kind1;
+ static enum { K2Val = sizeof(T)*2 } Kind2;
+ enum { K3Val = sizeof(T)*2 } Kind3;
+
+ void foo() {
+ K1 k1 = K1Val;
+ Kind1 = K1Val;
+ Outer::Inner::InnerTemplate<type>::VeryInner::Kind2 = K2Val;
+ Kind3 = K3Val;
+ }
+
+ struct UeberInner {
+ void bar() {
+ K1 k1 = K1Val;
+ Kind1 = K1Val;
+ Outer::Inner::InnerTemplate<type>::VeryInner::Kind2 = K2Val;
+
+ InnerTemplate t;
+ InnerTemplate<type> t2;
+ }
+ };
+ };
+ };
+ };
+ };
+}
+
+typedef int INT;
+template struct N::Outer::Inner::InnerTemplate<INT>::VeryInner;
+template struct N::Outer::Inner::InnerTemplate<INT>::UeberInner; // expected-error{{'UeberInner' does not name a tag member}}
+
+namespace N2 {
+ struct Outer2 {
+ template<typename T, typename U = T>
+ struct Inner {
+ void foo() {
+ enum { K1Val = sizeof(T) } k1;
+ enum K2 { K2Val = sizeof(T)*2 } k2a;
+
+ K2 k2b = K2Val;
+
+ struct S { T x, y; } s1;
+ struct { U x, y; } s2;
+ s1.x = s2.x; // expected-error{{incompatible}}
+
+ typedef T type;
+ type t2 = s1.x;
+
+ typedef struct { T z; } type2;
+ type2 t3 = { s1.x };
+
+ Inner i1;
+ i1.foo();
+ Inner<T> i2;
+ i2.foo();
+ }
+ };
+ };
+}
+
+template struct N2::Outer2::Inner<float>;
+template struct N2::Outer2::Inner<int*, float*>; // expected-note{{instantiation}}
diff --git a/test/SemaTemplate/instantiate-enum.cpp b/test/SemaTemplate/instantiate-enum.cpp
new file mode 100644
index 000000000000..a7acf22a45a1
--- /dev/null
+++ b/test/SemaTemplate/instantiate-enum.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-cc -fsyntax-only %s
+
+template<typename T, T I, int J>
+struct adder {
+ enum {
+ value = I + J,
+ value2
+ };
+};
+
+int array1[adder<long, 3, 4>::value == 7? 1 : -1];
diff --git a/test/SemaTemplate/instantiate-expr-1.cpp b/test/SemaTemplate/instantiate-expr-1.cpp
new file mode 100644
index 000000000000..13ee3ab525ba
--- /dev/null
+++ b/test/SemaTemplate/instantiate-expr-1.cpp
@@ -0,0 +1,71 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<int I, int J>
+struct Bitfields {
+ int simple : I; // expected-error{{bit-field 'simple' has zero width}}
+ int parens : (J);
+};
+
+void test_Bitfields(Bitfields<0, 5> *b) {
+ (void)sizeof(Bitfields<10, 5>);
+ (void)sizeof(Bitfields<0, 1>); // expected-note{{in instantiation of template class 'struct Bitfields<0, 1>' requested here}}
+}
+
+template<int I, int J>
+struct BitfieldPlus {
+ int bitfield : I + J; // expected-error{{bit-field 'bitfield' has zero width}}
+};
+
+void test_BitfieldPlus() {
+ (void)sizeof(BitfieldPlus<0, 1>);
+ (void)sizeof(BitfieldPlus<-5, 5>); // expected-note{{in instantiation of template class 'struct BitfieldPlus<-5, 5>' requested here}}
+}
+
+template<int I, int J>
+struct BitfieldMinus {
+ int bitfield : I - J; // expected-error{{bit-field 'bitfield' has negative width (-1)}} \
+ // expected-error{{bit-field 'bitfield' has zero width}}
+};
+
+void test_BitfieldMinus() {
+ (void)sizeof(BitfieldMinus<5, 1>);
+ (void)sizeof(BitfieldMinus<0, 1>); // expected-note{{in instantiation of template class 'struct BitfieldMinus<0, 1>' requested here}}
+ (void)sizeof(BitfieldMinus<5, 5>); // expected-note{{in instantiation of template class 'struct BitfieldMinus<5, 5>' requested here}}
+}
+
+template<int I, int J>
+struct BitfieldDivide {
+ int bitfield : I / J; // expected-error{{expression is not an integer constant expression}} \
+ // expected-note{{division by zero}}
+};
+
+void test_BitfieldDivide() {
+ (void)sizeof(BitfieldDivide<5, 1>);
+ (void)sizeof(BitfieldDivide<5, 0>); // expected-note{{in instantiation of template class 'struct BitfieldDivide<5, 0>' requested here}}
+}
+
+template<typename T, T I, int J>
+struct BitfieldDep {
+ int bitfield : I + J;
+};
+
+void test_BitfieldDep() {
+ (void)sizeof(BitfieldDep<int, 1, 5>);
+}
+
+template<int I>
+struct BitfieldNeg {
+ int bitfield : (-I); // expected-error{{bit-field 'bitfield' has negative width (-5)}}
+};
+
+template<typename T, T I>
+struct BitfieldNeg2 {
+ int bitfield : (-I); // expected-error{{bit-field 'bitfield' has negative width (-5)}}
+};
+
+void test_BitfieldNeg() {
+ (void)sizeof(BitfieldNeg<-5>); // okay
+ (void)sizeof(BitfieldNeg<5>); // expected-note{{in instantiation of template class 'struct BitfieldNeg<5>' requested here}}
+ (void)sizeof(BitfieldNeg2<int, -5>); // okay
+ (void)sizeof(BitfieldNeg2<int, 5>); // expected-note{{in instantiation of template class 'struct BitfieldNeg2<int, 5>' requested here}}
+}
diff --git a/test/SemaTemplate/instantiate-expr-2.cpp b/test/SemaTemplate/instantiate-expr-2.cpp
new file mode 100644
index 000000000000..80f403ed56fe
--- /dev/null
+++ b/test/SemaTemplate/instantiate-expr-2.cpp
@@ -0,0 +1,132 @@
+// RUN: clang-cc -fsyntax-only %s
+typedef char one_byte;
+typedef char (&two_bytes)[2];
+typedef char (&four_bytes)[4];
+typedef char (&eight_bytes)[8];
+
+template<int N> struct A { };
+
+namespace N1 {
+ struct X { };
+}
+
+namespace N2 {
+ struct Y { };
+
+ two_bytes operator+(Y, Y);
+}
+
+namespace N3 {
+ struct Z { };
+
+ eight_bytes operator+(Z, Z);
+}
+
+namespace N4 {
+ one_byte operator+(N1::X, N2::Y);
+
+ template<typename T, typename U>
+ struct BinOpOverload {
+ typedef A<sizeof(T() + U())> type;
+ };
+}
+
+namespace N1 {
+ four_bytes operator+(X, X);
+}
+
+namespace N3 {
+ eight_bytes operator+(Z, Z); // redeclaration
+}
+
+void test_bin_op_overload(A<1> *a1, A<2> *a2, A<4> *a4, A<8> *a8) {
+ typedef N4::BinOpOverload<N1::X, N2::Y>::type XY;
+ XY *xy = a1;
+ typedef N4::BinOpOverload<N1::X, N1::X>::type XX;
+ XX *xx = a4;
+ typedef N4::BinOpOverload<N2::Y, N2::Y>::type YY;
+ YY *yy = a2;
+ typedef N4::BinOpOverload<N3::Z, N3::Z>::type ZZ;
+ ZZ *zz = a8;
+}
+
+namespace N3 {
+ eight_bytes operator-(::N3::Z);
+}
+
+namespace N4 {
+ template<typename T>
+ struct UnaryOpOverload {
+ typedef A<sizeof(-T())> type;
+ };
+}
+
+void test_unary_op_overload(A<8> *a8) {
+ typedef N4::UnaryOpOverload<N3::Z>::type UZ;
+ UZ *uz = a8;
+}
+
+/*
+namespace N5 {
+ template<int I>
+ struct Lookup {
+ enum { val = I, more = val + 1 };
+ };
+
+ template<bool B>
+ struct Cond {
+ enum Junk { is = B ? Lookup<B>::more : Lookup<Lookup<B+1>::more>::val };
+ };
+
+ enum { resultT = Cond<true>::is,
+ resultF = Cond<false>::is };
+}
+*/
+
+namespace N6 {
+ // non-typedependent
+ template<int I>
+ struct Lookup {};
+
+ template<bool B, typename T, typename E>
+ struct Cond {
+ typedef Lookup<B ? sizeof(T) : sizeof(E)> True;
+ typedef Lookup<!B ? sizeof(T) : sizeof(E)> False;
+ };
+
+ typedef Cond<true, int, char>::True True;
+ typedef Cond<true, int, char>::False False;
+
+ // check that we have the right types
+ Lookup<1> const &L1(False());
+ Lookup<sizeof(int)> const &L2(True());
+}
+
+
+namespace N7 {
+ // type dependent
+ template<int I>
+ struct Lookup {};
+
+ template<bool B, typename T, typename E>
+ struct Cond {
+ T foo() { return B ? T() : E(); }
+ typedef Lookup<sizeof(B ? T() : E())> Type;
+ };
+
+ //Cond<true, int*, double> C; // Errors
+ //int V(C.foo()); // Errors
+ //typedef Cond<true, int*, double>::Type Type; // Errors
+ typedef Cond<true, int, double>::Type Type;
+}
+
+template<typename T, unsigned long N> struct IntegralConstant { };
+
+template<typename T>
+struct X0 {
+ void f(T x, IntegralConstant<T, sizeof(x)>);
+};
+
+void test_X0(X0<int> x, IntegralConstant<int, sizeof(int)> ic) {
+ x.f(5,ic);
+}
diff --git a/test/SemaTemplate/instantiate-expr-3.cpp b/test/SemaTemplate/instantiate-expr-3.cpp
new file mode 100644
index 000000000000..696b58325cd7
--- /dev/null
+++ b/test/SemaTemplate/instantiate-expr-3.cpp
@@ -0,0 +1,115 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// ---------------------------------------------------------------------
+// Imaginary literals
+// ---------------------------------------------------------------------
+template<typename T>
+struct ImaginaryLiteral0 {
+ void f(T &x) {
+ x = 3.0I; // expected-error{{incompatible type}}
+ }
+};
+
+template struct ImaginaryLiteral0<_Complex float>;
+template struct ImaginaryLiteral0<int*>; // expected-note{{instantiation}}
+
+// ---------------------------------------------------------------------
+// Compound assignment operator
+// ---------------------------------------------------------------------
+namespace N1 {
+ struct X { };
+
+ int& operator+=(X&, int); // expected-note{{candidate}}
+}
+
+namespace N2 {
+ long& operator+=(N1::X&, long); // expected-note{{candidate}}
+
+ template<typename T, typename U, typename Result>
+ struct PlusEquals0 {
+ void f(T t, U u) {
+ Result r = t += u; // expected-error{{ambiguous}}
+ }
+ };
+}
+
+namespace N3 {
+ struct Y : public N1::X {
+ short& operator+=(long); // expected-note{{candidate}}
+ };
+}
+
+template struct N2::PlusEquals0<N1::X, int, int&>;
+template struct N2::PlusEquals0<N1::X, long, long&>;
+template struct N2::PlusEquals0<N3::Y, long, short&>;
+template struct N2::PlusEquals0<int, int, int&>;
+template struct N2::PlusEquals0<N3::Y, int, short&>; // expected-note{{instantiation}}
+
+// ---------------------------------------------------------------------
+// Conditional operator
+// ---------------------------------------------------------------------
+template<typename T, typename U, typename Result>
+struct Conditional0 {
+ void f(T t, U u) {
+ Result result = t? : u;
+ }
+};
+
+template struct Conditional0<int, int, int>;
+
+// ---------------------------------------------------------------------
+// Statement expressions
+// ---------------------------------------------------------------------
+template<typename T>
+struct StatementExpr0 {
+ void f(T t) {
+ (void)({ if (t) t = t + 17; t + 12;}); // expected-error{{invalid}}
+ }
+};
+
+template struct StatementExpr0<int>;
+template struct StatementExpr0<N1::X>; // expected-note{{instantiation}}
+
+// ---------------------------------------------------------------------
+// __builtin_choose_expr
+// ---------------------------------------------------------------------
+template<bool Cond, typename T, typename U, typename Result>
+struct Choose0 {
+ void f(T t, U u) {
+ Result r = __builtin_choose_expr(Cond, t, u); // expected-error{{lvalue}}
+ }
+};
+
+template struct Choose0<true, int, float, int&>;
+template struct Choose0<false, int, float, float&>;
+template struct Choose0<true, int, float, float&>; // expected-note{{instantiation}}
+
+// ---------------------------------------------------------------------
+// __builtin_va_arg
+// ---------------------------------------------------------------------
+template<typename ArgType>
+struct VaArg0 {
+ void f(int n, ...) {
+ __builtin_va_list va;
+ __builtin_va_start(va, n);
+ for (int i = 0; i != n; ++i)
+ (void)__builtin_va_arg(va, ArgType);
+ __builtin_va_end(va);
+ }
+};
+
+template struct VaArg0<int>;
+
+template<typename VaList, typename ArgType>
+struct VaArg1 {
+ void f(int n, ...) {
+ VaList va;
+ __builtin_va_start(va, n); // expected-error{{int}}
+ for (int i = 0; i != n; ++i)
+ (void)__builtin_va_arg(va, ArgType);
+ __builtin_va_end(va);
+ }
+};
+
+template struct VaArg1<__builtin_va_list, int>;
+template struct VaArg1<int, int>; // expected-note{{instantiation}}
diff --git a/test/SemaTemplate/instantiate-expr-4.cpp b/test/SemaTemplate/instantiate-expr-4.cpp
new file mode 100644
index 000000000000..cd74a21d6dbc
--- /dev/null
+++ b/test/SemaTemplate/instantiate-expr-4.cpp
@@ -0,0 +1,289 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// ---------------------------------------------------------------------
+// C++ Functional Casts
+// ---------------------------------------------------------------------
+template<int N>
+struct ValueInit0 {
+ int f() {
+ return int();
+ }
+};
+
+template struct ValueInit0<5>;
+
+template<int N>
+struct FunctionalCast0 {
+ int f() {
+ return int(N);
+ }
+};
+
+template struct FunctionalCast0<5>;
+
+struct X { // expected-note 2 {{candidate function}}
+ X(int, int); // expected-note 2 {{candidate function}}
+};
+
+template<int N, int M>
+struct BuildTemporary0 {
+ X f() {
+ return X(N, M);
+ }
+};
+
+template struct BuildTemporary0<5, 7>;
+
+template<int N, int M>
+struct Temporaries0 {
+ void f() {
+ (void)X(N, M);
+ }
+};
+
+template struct Temporaries0<5, 7>;
+
+// ---------------------------------------------------------------------
+// new/delete expressions
+// ---------------------------------------------------------------------
+struct Y { };
+
+template<typename T>
+struct New0 {
+ T* f(bool x) {
+ if (x)
+ return new T; // expected-error{{no matching}}
+ else
+ return new T();
+ }
+};
+
+template struct New0<int>;
+template struct New0<Y>;
+template struct New0<X>; // expected-note{{instantiation}}
+
+template<typename T, typename Arg1>
+struct New1 {
+ T* f(bool x, Arg1 a1) {
+ return new T(a1); // expected-error{{no matching}}
+ }
+};
+
+template struct New1<int, float>;
+template struct New1<Y, Y>;
+template struct New1<X, Y>; // expected-note{{instantiation}}
+
+template<typename T, typename Arg1, typename Arg2>
+struct New2 {
+ T* f(bool x, Arg1 a1, Arg2 a2) {
+ return new T(a1, a2); // expected-error{{no matching}}
+ }
+};
+
+template struct New2<X, int, float>;
+template struct New2<X, int, int*>; // expected-note{{instantiation}}
+// FIXME: template struct New2<int, int, float>;
+
+template<typename T>
+struct Delete0 {
+ void f(T t) {
+ delete t; // expected-error{{cannot delete}}
+ ::delete [] t;
+ }
+};
+
+template struct Delete0<int*>;
+template struct Delete0<X*>;
+template struct Delete0<int>; // expected-note{{instantiation}}
+
+// ---------------------------------------------------------------------
+// throw expressions
+// ---------------------------------------------------------------------
+template<typename T>
+struct Throw1 {
+ void f(T t) {
+ throw;
+ throw t; // expected-error{{incomplete type}}
+ }
+};
+
+struct Incomplete; // expected-note{{forward}}
+
+template struct Throw1<int>;
+template struct Throw1<int*>;
+template struct Throw1<Incomplete*>; // expected-note{{instantiation}}
+
+// ---------------------------------------------------------------------
+// typeid expressions
+// ---------------------------------------------------------------------
+
+// FIXME: This should really include <typeinfo>, but we don't have that yet.
+namespace std {
+ class type_info;
+}
+
+template<typename T>
+struct TypeId0 {
+ const std::type_info &f(T* ptr) {
+ if (ptr)
+ return typeid(ptr);
+ else
+ return typeid(T);
+ }
+};
+
+struct Abstract {
+ virtual void f() = 0;
+};
+
+template struct TypeId0<int>;
+template struct TypeId0<Incomplete>;
+template struct TypeId0<Abstract>;
+
+// ---------------------------------------------------------------------
+// type traits
+// ---------------------------------------------------------------------
+template<typename T>
+struct is_pod {
+ static const bool value = __is_pod(T);
+};
+
+static const int is_pod0[is_pod<X>::value? -1 : 1];
+static const int is_pod1[is_pod<Y>::value? 1 : -1];
+
+// ---------------------------------------------------------------------
+// initializer lists
+// ---------------------------------------------------------------------
+template<typename T, typename Val1>
+struct InitList1 {
+ void f(Val1 val1) {
+ T x = { val1 };
+ }
+};
+
+struct APair {
+ int *x;
+ const float *y;
+};
+
+template struct InitList1<int[1], float>;
+template struct InitList1<APair, int*>;
+
+template<typename T, typename Val1, typename Val2>
+struct InitList2 {
+ void f(Val1 val1, Val2 val2) {
+ T x = { val1, val2 }; // expected-error{{incompatible}}
+ }
+};
+
+template struct InitList2<APair, int*, float*>;
+template struct InitList2<APair, int*, double*>; // expected-note{{instantiation}}
+
+// ---------------------------------------------------------------------
+// member references
+// ---------------------------------------------------------------------
+template<typename T, typename Result>
+struct DotMemRef0 {
+ void f(T t) {
+ Result result = t.m; // expected-error{{cannot be initialized}}
+ }
+};
+
+struct MemInt {
+ int m;
+};
+
+struct InheritsMemInt : MemInt { };
+
+struct MemIntFunc {
+ static int m(int);
+};
+
+template struct DotMemRef0<MemInt, int&>;
+template struct DotMemRef0<InheritsMemInt, int&>;
+template struct DotMemRef0<MemIntFunc, int (*)(int)>;
+template struct DotMemRef0<MemInt, float&>; // expected-note{{instantiation}}
+
+template<typename T, typename Result>
+struct ArrowMemRef0 {
+ void f(T t) {
+ Result result = t->m; // expected-error 2{{cannot be initialized}}
+ }
+};
+
+template<typename T>
+struct ArrowWrapper {
+ T operator->();
+};
+
+template struct ArrowMemRef0<MemInt*, int&>;
+template struct ArrowMemRef0<InheritsMemInt*, int&>;
+template struct ArrowMemRef0<MemIntFunc*, int (*)(int)>;
+template struct ArrowMemRef0<MemInt*, float&>; // expected-note{{instantiation}}
+
+template struct ArrowMemRef0<ArrowWrapper<MemInt*>, int&>;
+template struct ArrowMemRef0<ArrowWrapper<InheritsMemInt*>, int&>;
+template struct ArrowMemRef0<ArrowWrapper<MemIntFunc*>, int (*)(int)>;
+template struct ArrowMemRef0<ArrowWrapper<MemInt*>, float&>; // expected-note{{instantiation}}
+template struct ArrowMemRef0<ArrowWrapper<ArrowWrapper<MemInt*> >, int&>;
+
+// FIXME: we should be able to return a MemInt without the reference!
+MemInt &createMemInt(int);
+
+template<int N>
+struct NonDepMemberExpr0 {
+ void f() {
+ createMemInt(N).m = N;
+ }
+};
+
+template struct NonDepMemberExpr0<0>;
+
+template<typename T, typename Result>
+struct MemberFuncCall0 {
+ void f(T t) {
+ Result result = t.f();
+ }
+};
+
+template<typename T>
+struct HasMemFunc0 {
+ T f();
+};
+
+
+template struct MemberFuncCall0<HasMemFunc0<int&>, const int&>;
+
+template<typename Result>
+struct ThisMemberFuncCall0 {
+ Result g();
+
+ void f() {
+ Result r1 = g();
+ Result r2 = this->g();
+ }
+};
+
+template struct ThisMemberFuncCall0<int&>;
+
+template<typename T>
+struct NonDepMemberCall0 {
+ void foo(HasMemFunc0<int&> x) {
+ T result = x.f(); // expected-error{{initialized}}
+ }
+};
+
+template struct NonDepMemberCall0<int&>;
+template struct NonDepMemberCall0<const int&>;
+template struct NonDepMemberCall0<float&>; // expected-note{{instantiation}}
+
+
+template<typename T>
+struct QualifiedDeclRef0 {
+ T f() {
+ return is_pod<X>::value; // expected-error{{initialized}}
+ }
+};
+
+template struct QualifiedDeclRef0<bool>;
+template struct QualifiedDeclRef0<int&>; // expected-note{{instantiation}}
diff --git a/test/SemaTemplate/instantiate-expr-basic.cpp b/test/SemaTemplate/instantiate-expr-basic.cpp
new file mode 100644
index 000000000000..2b5fcaeb0454
--- /dev/null
+++ b/test/SemaTemplate/instantiate-expr-basic.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only -Wno-unused-value -std=c++0x %s
+
+template <typename T>
+struct S {
+ void f() {
+ __func__; // PredefinedExpr
+ 10; // IntegerLiteral
+ 10.5; // FloatingLiteral
+ 'c'; // CharacterLiteral
+ "hello"; // StringLiteral
+ true; // CXXBooleanLiteralExpr
+ nullptr; // CXXNullPtrLiteralExpr
+ __null; // GNUNullExpr
+ }
+};
+
+template struct S<int>;
diff --git a/test/SemaTemplate/instantiate-field.cpp b/test/SemaTemplate/instantiate-field.cpp
new file mode 100644
index 000000000000..8e2a3758b0d7
--- /dev/null
+++ b/test/SemaTemplate/instantiate-field.cpp
@@ -0,0 +1,28 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X {
+ int x;
+ T y; // expected-error{{data member instantiated with function type}}
+ T* z;
+ T bitfield : 12; // expected-error{{bit-field 'bitfield' has non-integral type 'float'}} \
+ // expected-error{{data member instantiated with function type}}
+
+ mutable T x2; // expected-error{{data member instantiated with function type}}
+};
+
+void test1(const X<int> *xi) {
+ int i1 = xi->x;
+ const int &i2 = xi->y;
+ int* ip1 = xi->z;
+ int i3 = xi->bitfield;
+ xi->x2 = 17;
+}
+
+void test2(const X<float> *xf) {
+ (void)xf->x; // expected-note{{in instantiation of template class 'struct X<float>' requested here}}
+}
+
+void test3(const X<int(int)> *xf) {
+ (void)xf->x; // expected-note{{in instantiation of template class 'struct X<int (int)>' requested here}}
+}
diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp
new file mode 100644
index 000000000000..5b3a6d998404
--- /dev/null
+++ b/test/SemaTemplate/instantiate-function-1.cpp
@@ -0,0 +1,211 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T, typename U>
+struct X0 {
+ void f(T x, U y) {
+ (void)(x + y); // expected-error{{invalid operands}}
+ }
+};
+
+struct X1 { };
+
+template struct X0<int, float>;
+template struct X0<int*, int>;
+template struct X0<int X1::*, int>; // expected-note{{instantiation of}}
+
+template<typename T>
+struct X2 {
+ void f(T);
+
+ T g(T x, T y) {
+ /* DeclStmt */;
+ T *xp = &x, &yr = y; // expected-error{{pointer to a reference}}
+ /* NullStmt */;
+ }
+};
+
+template struct X2<int>;
+template struct X2<int&>; // expected-note{{instantiation of}}
+
+template<typename T>
+struct X3 {
+ void f(T) {
+ Label:
+ T x;
+ goto Label;
+ }
+};
+
+template struct X3<int>;
+
+template <typename T> struct X4 {
+ T f() const {
+ return; // expected-warning{{non-void function 'f' should return a value}}
+ }
+
+ T g() const {
+ return 1; // expected-warning{{void function 'g' should not return a value}}
+ }
+};
+
+template struct X4<void>; // expected-note{{in instantiation of}}
+template struct X4<int>; // expected-note{{in instantiation of}}
+
+struct Incomplete; // expected-note 2{{forward declaration}}
+
+template<typename T> struct X5 {
+ T f() { } // expected-error{{incomplete result type}}
+};
+void test_X5(X5<Incomplete> x5); // okay!
+
+template struct X5<Incomplete>; // expected-note{{instantiation}}
+
+template<typename T, typename U, typename V> struct X6 {
+ U f(T t, U u, V v) {
+ // IfStmt
+ if (t > 0)
+ return u;
+ else {
+ if (t < 0)
+ return v; // expected-error{{incompatible type}}
+ }
+
+ if (T x = t) {
+ t = x;
+ }
+ return v;
+ }
+};
+
+struct ConvertibleToInt {
+ operator int() const;
+};
+
+template struct X6<ConvertibleToInt, float, char>;
+template struct X6<bool, int, int*>; // expected-note{{instantiation}}
+
+template <typename T> struct X7 {
+ void f() {
+ void *v = this;
+ }
+};
+
+template struct X7<int>;
+
+template<typename T> struct While0 {
+ void f(T t) {
+ while (t) {
+ }
+
+ while (T t2 = T()) ;
+ }
+};
+
+template struct While0<float>;
+
+template<typename T> struct Do0 {
+ void f(T t) {
+ do {
+ } while (t); // expected-error{{not contextually}}
+
+ do {
+ } while (T t2 = T());
+ }
+};
+
+struct NotConvertibleToBool { };
+template struct Do0<ConvertibleToInt>;
+template struct Do0<NotConvertibleToBool>; // expected-note{{instantiation}}
+
+template<typename T> struct For0 {
+ void f(T f, T l) {
+ for (; f != l; ++f) {
+ if (*f)
+ continue;
+ else if (*f == 17)
+ break;
+ }
+ }
+};
+
+template struct For0<int*>;
+
+template<typename T> struct Member0 {
+ void f(T t) {
+ t;
+ t.f;
+ t->f;
+
+ T* tp;
+ tp.f; // expected-error{{member reference base type 'T *' is not a structure or union}}
+ tp->f;
+
+ this->f;
+ this.f; // expected-error{{member reference base type 'struct Member0 *const' is not a structure or union}}
+ }
+};
+
+template<typename T, typename U> struct Switch0 {
+ U f(T value, U v0, U v1, U v2) {
+ switch (value) {
+ case 0: return v0;
+
+ case 1: return v1;
+
+ case 2: // fall through
+
+ default:
+ return v2;
+ }
+ }
+};
+
+template struct Switch0<int, float>;
+
+template<typename T, int I1, int I2> struct Switch1 {
+ T f(T x, T y, T z) {
+ switch (x) {
+ case I1: return y; // expected-note{{previous}}
+ case I2: return z; // expected-error{{duplicate}}
+ default: return x;
+ }
+ }
+};
+
+template struct Switch1<int, 1, 2>;
+template struct Switch1<int, 2, 2>; // expected-note{{instantiation}}
+
+template<typename T> struct IndirectGoto0 {
+ void f(T x) {
+ // FIXME: crummy error message below
+ goto *x; // expected-error{{incompatible}}
+
+ prior:
+ T prior_label = &&prior;
+
+ T later_label = &&later;
+
+ later:
+ (void)(1+1);
+ }
+};
+
+template struct IndirectGoto0<void*>;
+template struct IndirectGoto0<int>; // expected-note{{instantiation}}
+
+template<typename T> struct TryCatch0 {
+ void f() {
+ try {
+ } catch (T t) { // expected-error{{incomplete type}} \
+ // expected-error{{abstract class}}
+ } catch (...) {
+ }
+ }
+};
+
+struct Abstract {
+ virtual void foo() = 0; // expected-note{{pure virtual}}
+};
+
+template struct TryCatch0<int>; // okay
+template struct TryCatch0<Incomplete*>; // expected-note{{instantiation}}
+template struct TryCatch0<Abstract>; // expected-note{{instantiation}}
diff --git a/test/SemaTemplate/instantiate-function-1.mm b/test/SemaTemplate/instantiate-function-1.mm
new file mode 100644
index 000000000000..aef2d9dbb7eb
--- /dev/null
+++ b/test/SemaTemplate/instantiate-function-1.mm
@@ -0,0 +1,14 @@
+template<typename T> struct Member0 {
+ void f(T t) {
+ t;
+ t.f;
+ t->f;
+
+ T* tp;
+ tp.f;
+ tp->f;
+
+ this->f;
+ this.f; // expected-error{{member reference base type 'struct Member0 *const' is not a structure or union}}
+ }
+};
diff --git a/test/SemaTemplate/instantiate-function-2.cpp b/test/SemaTemplate/instantiate-function-2.cpp
new file mode 100644
index 000000000000..51a60146d46a
--- /dev/null
+++ b/test/SemaTemplate/instantiate-function-2.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template <typename T> struct S {
+ S() { }
+ S(T t);
+};
+
+template struct S<int>;
+
+void f() {
+ S<int> s1;
+ S<int> s2(10);
+}
diff --git a/test/SemaTemplate/instantiate-member-class.cpp b/test/SemaTemplate/instantiate-member-class.cpp
new file mode 100644
index 000000000000..fab65cef2e45
--- /dev/null
+++ b/test/SemaTemplate/instantiate-member-class.cpp
@@ -0,0 +1,38 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+class X {
+public:
+ struct C { T &foo(); };
+
+ struct D {
+ struct E { T &bar(); }; // expected-error{{cannot form a reference to 'void'}}
+ struct F; // expected-note{{member is declared here}}
+ };
+};
+
+X<int>::C *c1;
+X<float>::C *c2;
+
+X<int>::X *xi;
+X<float>::X *xf;
+
+void test_naming() {
+ c1 = c2; // expected-error{{incompatible type assigning 'X<float>::C *', expected 'X<int>::C *'}}
+ xi = xf; // expected-error{{incompatible type assigning}}
+ // FIXME: error above doesn't print the type X<int>::X cleanly!
+}
+
+void test_instantiation(X<double>::C *x,
+ X<float>::D::E *e,
+ X<float>::D::F *f) {
+ double &dr = x->foo();
+ float &fr = e->bar();
+ f->foo(); // expected-error{{implicit instantiation of undefined member 'struct X<float>::D::F'}}
+
+}
+
+
+X<void>::C *c3; // okay
+X<void>::D::E *e1; // okay
+X<void>::D::E e2; // expected-note{{in instantiation of member class 'struct X<void>::D::E' requested here}}
diff --git a/test/SemaTemplate/instantiate-method.cpp b/test/SemaTemplate/instantiate-method.cpp
new file mode 100644
index 000000000000..daea7465dc12
--- /dev/null
+++ b/test/SemaTemplate/instantiate-method.cpp
@@ -0,0 +1,74 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T>
+class X {
+public:
+ void f(T x); // expected-error{{argument may not have 'void' type}}
+ void g(T*);
+
+ static int h(T, T); // expected-error 2{{argument may not have 'void' type}}
+};
+
+int identity(int x) { return x; }
+
+void test(X<int> *xi, int *ip, X<int(int)> *xf) {
+ xi->f(17);
+ xi->g(ip);
+ xf->f(&identity);
+ xf->g(identity);
+ X<int>::h(17, 25);
+ X<int(int)>::h(identity, &identity);
+}
+
+void test_bad() {
+ X<void> xv; // expected-note{{in instantiation of template class 'class X<void>' requested here}}
+}
+
+template<typename T, typename U>
+class Overloading {
+public:
+ int& f(T, T); // expected-note{{previous declaration is here}}
+ float& f(T, U); // expected-error{{functions that differ only in their return type cannot be overloaded}}
+};
+
+void test_ovl(Overloading<int, long> *oil, int i, long l) {
+ int &ir = oil->f(i, i);
+ float &fr = oil->f(i, l);
+}
+
+void test_ovl_bad() {
+ Overloading<float, float> off; // expected-note{{in instantiation of template class 'class Overloading<float, float>' requested here}}
+}
+
+template<typename T>
+class HasDestructor {
+public:
+ virtual ~HasDestructor() = 0;
+};
+
+int i = sizeof(HasDestructor<int>); // FIXME: forces instantiation, but
+ // the code below should probably instantiate by itself.
+int abstract_destructor[__is_abstract(HasDestructor<int>)? 1 : -1];
+
+
+template<typename T>
+class Constructors {
+public:
+ Constructors(const T&);
+ Constructors(const Constructors &other);
+};
+
+void test_constructors() {
+ Constructors<int> ci1(17);
+ Constructors<int> ci2 = ci1;
+}
+
+
+template<typename T>
+struct ConvertsTo {
+ operator T();
+};
+
+void test_converts_to(ConvertsTo<int> ci, ConvertsTo<int *> cip) {
+ int i = ci;
+ int *ip = cip;
+}
diff --git a/test/SemaTemplate/instantiate-static-var.cpp b/test/SemaTemplate/instantiate-static-var.cpp
new file mode 100644
index 000000000000..99e6b9cc06c3
--- /dev/null
+++ b/test/SemaTemplate/instantiate-static-var.cpp
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, T Divisor>
+class X {
+public:
+ static const T value = 10 / Divisor; // expected-error{{in-class initializer is not an integral constant expression}}
+};
+
+int array1[X<int, 2>::value == 5? 1 : -1];
+X<int, 0> xi0; // expected-note{{in instantiation of template class 'class X<int, 0>' requested here}}
+
+
+template<typename T>
+class Y {
+ static const T value = 0; // expected-error{{'value' can only be initialized if it is a static const integral data member}}
+};
+
+Y<float> fy; // expected-note{{in instantiation of template class 'class Y<float>' requested here}}
diff --git a/test/SemaTemplate/instantiate-subscript.cpp b/test/SemaTemplate/instantiate-subscript.cpp
new file mode 100644
index 000000000000..434d84e2b893
--- /dev/null
+++ b/test/SemaTemplate/instantiate-subscript.cpp
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+
+struct Sub0 {
+ int &operator[](int);
+};
+
+struct Sub1 {
+ long &operator[](long);
+};
+
+struct ConvertibleToInt {
+ operator int();
+};
+
+template<typename T, typename U, typename Result>
+struct Subscript0 {
+ void test(T t, U u) {
+ Result &result = t[u]; // expected-error{{subscripted value is not}}
+ }
+};
+
+template struct Subscript0<int*, int, int&>;
+template struct Subscript0<Sub0, int, int&>;
+template struct Subscript0<Sub1, ConvertibleToInt, long&>;
+template struct Subscript0<Sub1, Sub0, long&>; // expected-note{{instantiation}}
diff --git a/test/SemaTemplate/instantiate-template-template-parm.cpp b/test/SemaTemplate/instantiate-template-template-parm.cpp
new file mode 100644
index 000000000000..b158251915a0
--- /dev/null
+++ b/test/SemaTemplate/instantiate-template-template-parm.cpp
@@ -0,0 +1,21 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<template<typename T> class MetaFun, typename Value>
+struct apply {
+ typedef typename MetaFun<Value>::type type;
+};
+
+template<class T>
+struct add_pointer {
+ typedef T* type;
+};
+
+template<class T>
+struct add_reference {
+ typedef T& type;
+};
+
+int i;
+apply<add_pointer, int>::type ip = &i;
+apply<add_reference, int>::type ir = i;
+apply<add_reference, float>::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a value of type 'int'}}
diff --git a/test/SemaTemplate/instantiate-try-catch.cpp b/test/SemaTemplate/instantiate-try-catch.cpp
new file mode 100644
index 000000000000..074afa9d173d
--- /dev/null
+++ b/test/SemaTemplate/instantiate-try-catch.cpp
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only -std=c++0x -verify %s
+
+template<typename T> struct TryCatch0 {
+ void f() {
+ try {
+ } catch (T&&) { // expected-error 2{{cannot catch exceptions by rvalue reference}}
+ }
+ }
+};
+
+template struct TryCatch0<int&>; // okay
+template struct TryCatch0<int&&>; // expected-note{{instantiation}}
+template struct TryCatch0<int>; // expected-note{{instantiation}}
+
diff --git a/test/SemaTemplate/instantiate-type.cpp b/test/SemaTemplate/instantiate-type.cpp
new file mode 100644
index 000000000000..48060c4e384e
--- /dev/null
+++ b/test/SemaTemplate/instantiate-type.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only %s
+
+int* f(int);
+float *f(...);
+
+template<typename T>
+struct X {
+ typedef typeof(T*) typeof_type;
+ typedef typeof(f(T())) typeof_expr;
+};
+
+int *iptr0;
+float *fptr0;
+X<int>::typeof_type &iptr1 = iptr0;
+
+X<int>::typeof_expr &iptr2 = iptr0;
+X<float*>::typeof_expr &fptr1 = fptr0;
diff --git a/test/SemaTemplate/instantiate-typedef.cpp b/test/SemaTemplate/instantiate-typedef.cpp
new file mode 100644
index 000000000000..d30309cc86ca
--- /dev/null
+++ b/test/SemaTemplate/instantiate-typedef.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct add_pointer {
+ typedef T* type; // expected-error{{'type' declared as a pointer to a reference}}
+};
+
+add_pointer<int>::type test1(int * ptr) { return ptr; }
+
+add_pointer<float>::type test2(int * ptr) {
+ return ptr; // expected-error{{incompatible type returning 'int *', expected 'add_pointer<float>::type' (aka 'float *')}}
+}
+
+add_pointer<int&>::type // expected-note{{in instantiation of template class 'struct add_pointer<int &>' requested here}} \
+// expected-error {{unknown type name 'type'}}
+test3();
diff --git a/test/SemaTemplate/instantiation-backtrace.cpp b/test/SemaTemplate/instantiation-backtrace.cpp
new file mode 100644
index 000000000000..869662268dd2
--- /dev/null
+++ b/test/SemaTemplate/instantiation-backtrace.cpp
@@ -0,0 +1,32 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T> struct A; // expected-note 4{{template is declared here}}
+
+template<typename T> struct B : A<T*> { }; // expected-error{{implicit instantiation of undefined template}} \
+// expected-error{{implicit instantiation of undefined template 'struct A<X *>'}}
+
+template<typename T> struct C : B<T> { } ; // expected-note{{instantiation of template class}}
+
+template<typename T> struct D : C<T> { }; // expected-note{{instantiation of template class}}
+
+template<typename T> struct E : D<T> { }; // expected-note{{instantiation of template class}}
+
+template<typename T> struct F : E<T(T)> { }; // expected-note{{instantiation of template class}}
+
+void f() {
+ (void)sizeof(F<int>); // expected-note{{instantiation of template class}}
+}
+
+typedef struct { } X;
+
+void g() {
+ (void)sizeof(B<X>); // expected-note{{in instantiation of template class 'struct B<X>' requested here}}
+}
+
+template<typename T>
+struct G : A<T>, // expected-error{{implicit instantiation of undefined template 'struct A<int>'}}
+ A<T*> // expected-error{{implicit instantiation of undefined template 'struct A<int *>'}}
+ { };
+
+void h() {
+ (void)sizeof(G<int>); // expected-note{{in instantiation of template class 'struct G<int>' requested here}}
+}
diff --git a/test/SemaTemplate/instantiation-default-1.cpp b/test/SemaTemplate/instantiation-default-1.cpp
new file mode 100644
index 000000000000..f0ce0d3cc669
--- /dev/null
+++ b/test/SemaTemplate/instantiation-default-1.cpp
@@ -0,0 +1,102 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T, typename U = const T> struct Def1;
+
+template<> struct Def1<int> {
+ void foo();
+};
+
+template<> struct Def1<const int> { // expected-note{{previous definition is here}}
+ void bar();
+};
+
+template<> struct Def1<int&> {
+ void wibble();
+};
+
+void test_Def1(Def1<int, const int> *d1, Def1<const int, const int> *d2,
+ Def1<int&, int&> *d3) {
+ d1->foo();
+ d2->bar();
+ d3->wibble();
+}
+
+template<typename T, // FIXME: bad error message below, needs better location info
+ typename T2 = const T*> // expected-error{{'T2' declared as a pointer to a reference}}
+ struct Def2;
+
+template<> struct Def2<int> {
+ void foo();
+};
+
+void test_Def2(Def2<int, int const*> *d2) {
+ d2->foo();
+}
+
+typedef int& int_ref_t;
+Def2<int_ref_t> *d2; // expected-note{{in instantiation of default argument for 'Def2<int &>' required here}}
+
+
+template<> struct Def1<const int, const int> { }; // expected-error{{redefinition of 'Def1<int const>'}}
+
+template<typename T, typename T2 = T&> struct Def3;
+
+template<> struct Def3<int> {
+ void foo();
+};
+
+template<> struct Def3<int&> {
+ void bar();
+};
+
+void test_Def3(Def3<int, int&> *d3a, Def3<int&, int&> *d3b) {
+ d3a->foo();
+ d3b->bar();
+}
+
+
+template<typename T, typename T2 = T[]> struct Def4;
+
+template<> struct Def4<int> {
+ void foo();
+};
+
+void test_Def4(Def4<int, int[]> *d4a) {
+ d4a->foo();
+}
+
+template<typename T, typename T2 = T const[12]> struct Def5;
+
+template<> struct Def5<int> {
+ void foo();
+};
+
+template<> struct Def5<int, int const[13]> {
+ void bar();
+};
+
+void test_Def5(Def5<int, const int[12]> *d5a, Def5<int, const int[13]> *d5b) {
+ d5a->foo();
+ d5b->bar();
+}
+
+template<typename R, typename Arg1, typename Arg2 = Arg1,
+ typename FuncType = R (*)(Arg1, Arg2)>
+ struct Def6;
+
+template<> struct Def6<int, float> {
+ void foo();
+};
+
+template<> struct Def6<bool, int[5], float(double, double)> {
+ void bar();
+};
+
+bool test_Def6(Def6<int, float, float> *d6a,
+ Def6<int, float, float, int (*)(float, float)> *d6b,
+ Def6<bool, int[5], float(double, double),
+ bool(*)(int*, float(*)(double, double))> *d6c) {
+ d6a->foo();
+ d6b->foo();
+ d6c->bar();
+ return d6a == d6b;
+}
diff --git a/test/SemaTemplate/instantiation-default-2.cpp b/test/SemaTemplate/instantiation-default-2.cpp
new file mode 100644
index 000000000000..740832c5ba39
--- /dev/null
+++ b/test/SemaTemplate/instantiation-default-2.cpp
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, T Value> struct Constant; // expected-note{{template parameter is declared here}} \
+// FIXME: bad location expected-error{{a non-type template parameter cannot have type 'float'}}
+
+Constant<int, 5> *c1;
+
+int x;
+float f(int, double);
+
+Constant<int&, x> *c2;
+Constant<int*, &x> *c3;
+Constant<float (*)(int, double), f> *c4;
+Constant<float (*)(int, double), &f> *c5;
+
+Constant<float (*)(int, int), f> *c6; // expected-error{{non-type template argument of type 'float (*)(int, double)' cannot be converted to a value of type 'float (*)(int, int)'}}
+
+Constant<float, 0> *c7; // expected-note{{in instantiation of default argument for 'Constant<float>' required here}}
diff --git a/test/SemaTemplate/instantiation-default-3.cpp b/test/SemaTemplate/instantiation-default-3.cpp
new file mode 100644
index 000000000000..521edf66f24c
--- /dev/null
+++ b/test/SemaTemplate/instantiation-default-3.cpp
@@ -0,0 +1,21 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T> struct A { };
+
+template<typename T, typename U = A<T*> >
+ struct B : U { };
+
+template<>
+struct A<int*> {
+ void foo();
+};
+
+template<>
+struct A<float*> {
+ void bar();
+};
+
+void test(B<int> *b1, B<float> *b2) {
+ b1->foo();
+ b2->bar();
+}
diff --git a/test/SemaTemplate/instantiation-depth.cpp b/test/SemaTemplate/instantiation-depth.cpp
new file mode 100644
index 000000000000..522c4e1cbb5c
--- /dev/null
+++ b/test/SemaTemplate/instantiation-depth.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -ftemplate-depth=5 -verify %s
+
+template<typename T> struct X : X<T*> { }; // expected-error{{recursive template instantiation exceeded maximum depth of 5}} \
+// expected-note{{use -ftemplate-depth-N to increase recursive template instantiation depth}} \
+// expected-note 5 {{instantiation of template class}}
+
+void test() {
+ (void)sizeof(X<int>); // expected-note {{instantiation of template class}}
+}
diff --git a/test/SemaTemplate/metafun-apply.cpp b/test/SemaTemplate/metafun-apply.cpp
new file mode 100644
index 000000000000..7bc971f24b59
--- /dev/null
+++ b/test/SemaTemplate/metafun-apply.cpp
@@ -0,0 +1,43 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct add_pointer {
+ template<typename T>
+ struct apply {
+ typedef T* type;
+ };
+};
+
+struct add_reference {
+ template<typename T>
+ struct apply {
+ typedef T& type; // expected-error{{cannot form a reference to 'void'}}
+ };
+};
+
+struct bogus {
+ struct apply {
+ typedef int type;
+ };
+};
+
+template<typename MetaFun, typename T>
+struct apply1 {
+ typedef typename MetaFun::template apply<T>::type type; // expected-note{{in instantiation of template class 'struct add_reference::apply<void>' requested here}} \
+ // expected-error{{'apply' following the 'template' keyword does not refer to a template}} \
+ // FIXME: expected-error{{type 'MetaFun::template apply<int>' cannot be used prior to '::' because it has no members}}
+};
+
+int i;
+apply1<add_pointer, int>::type ip = &i;
+apply1<add_reference, int>::type ir = i;
+apply1<add_reference, float>::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a value of type 'int'}}
+
+void test() {
+ apply1<add_reference, void>::type t; // expected-note{{in instantiation of template class 'struct apply1<struct add_reference, void>' requested here}} \
+ // FIXME: expected-error{{unexpected type name 'type': expected expression}}
+
+ apply1<bogus, int>::type t2; // expected-note{{in instantiation of template class 'struct apply1<struct bogus, int>' requested here}} \
+ // FIXME: expected-error{{unexpected type name 'type': expected expression}}
+}
+
+
diff --git a/test/SemaTemplate/nested-name-spec-template.cpp b/test/SemaTemplate/nested-name-spec-template.cpp
new file mode 100644
index 000000000000..a5aa2dcb527a
--- /dev/null
+++ b/test/SemaTemplate/nested-name-spec-template.cpp
@@ -0,0 +1,61 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace N {
+ namespace M {
+ template<typename T> struct Promote;
+
+ template<> struct Promote<short> {
+ typedef int type;
+ };
+
+ template<> struct Promote<int> {
+ typedef int type;
+ };
+
+ template<> struct Promote<float> {
+ typedef double type;
+ };
+
+ Promote<short>::type *ret_intptr(int* ip) { return ip; }
+ Promote<int>::type *ret_intptr2(int* ip) { return ip; }
+ }
+
+ M::Promote<int>::type *ret_intptr3(int* ip) { return ip; }
+ M::template Promote<int>::type *ret_intptr4(int* ip) { return ip; }
+}
+
+N::M::Promote<int>::type *ret_intptr5(int* ip) { return ip; }
+::N::M::Promote<int>::type *ret_intptr6(int* ip) { return ip; }
+
+
+N::M::template; // expected-error{{expected template name after 'template' keyword in nested name specifier}} \
+ // expected-error{{expected unqualified-id}}
+
+N::M::template Promote; // expected-error{{expected '<' after 'template Promote' in nested name specifier}} \
+// expected-error{{C++ requires a type specifier for all declarations}}
+
+namespace N {
+ template<typename T> struct A;
+
+ template<>
+ struct A<int> {
+ struct X;
+ };
+
+ struct B;
+}
+
+struct ::N::A<int>::X {
+ int foo;
+};
+
+#if 0
+// FIXME: the following crashes the parser, because Sema has no way to
+// communicate that the "dependent" template-name N::template B doesn't
+// actually refer to a template.
+template<typename T>
+struct TestA {
+ typedef typename N::template B<T>::type type; // xpected-error{{'B' following the 'template' keyword does not refer to a template}}
+ // FIXME: should show what B *does* refer to.
+};
+#endif
diff --git a/test/SemaTemplate/nested-template.cpp b/test/SemaTemplate/nested-template.cpp
new file mode 100644
index 000000000000..bd9e89f76a0a
--- /dev/null
+++ b/test/SemaTemplate/nested-template.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only %s
+
+class A;
+
+class S {
+public:
+ template<typename T> struct A {
+ struct Nested {
+ typedef T type;
+ };
+ };
+};
+
+int i;
+S::A<int>::Nested::type *ip = &i;
+
diff --git a/test/SemaTemplate/qualified-names-diag.cpp b/test/SemaTemplate/qualified-names-diag.cpp
new file mode 100644
index 000000000000..c875332905fb
--- /dev/null
+++ b/test/SemaTemplate/qualified-names-diag.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace std {
+ template<typename T> class vector { };
+}
+
+typedef int INT;
+typedef float Real;
+
+void test() {
+ using namespace std;
+
+ std::vector<INT> v1;
+ vector<Real> v2;
+ v1 = v2; // expected-error{{no viable overloaded '='}}
+}
diff --git a/test/SemaTemplate/right-angle-brackets-0x.cpp b/test/SemaTemplate/right-angle-brackets-0x.cpp
new file mode 100644
index 000000000000..57b6ee22410c
--- /dev/null
+++ b/test/SemaTemplate/right-angle-brackets-0x.cpp
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -std=c++0x -verify %s
+template<typename T> struct X;
+template<int I> struct Y;
+
+X<X<int>> *x1;
+
+Y<(1 >> 2)> *y1;
+Y<1 >> 2> *y2; // FIXME: expected-error{{expected unqualified-id}}
+
+X<X<X<X<X<int>>>>> *x2;
+
+template<> struct X<int> { };
+typedef X<int> X_int;
+struct Z : X_int { };
+
+void f(const X<int> x) {
+ (void)reinterpret_cast<X<int>>(x); // expected-error{{reinterpret_cast from}}
+ (void)reinterpret_cast<X<X<X<int>>>>(x); // expected-error{{reinterpret_cast from}}
+
+ X<X<int>> *x1;
+}
+
diff --git a/test/SemaTemplate/right-angle-brackets-98.cpp b/test/SemaTemplate/right-angle-brackets-98.cpp
new file mode 100644
index 000000000000..764bb7bae073
--- /dev/null
+++ b/test/SemaTemplate/right-angle-brackets-98.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -std=c++98 -verify %s
+template<typename T> struct X;
+template<int I> struct Y;
+
+X<X<int> > *x1;
+X<X<int>> *x2; // expected-error{{a space is required between consecutive right angle brackets (use '> >')}}
+
+X<X<X<X<int>> // expected-error{{a space is required between consecutive right angle brackets (use '> >')}}
+ >> *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}}
diff --git a/test/SemaTemplate/temp.cpp b/test/SemaTemplate/temp.cpp
new file mode 100644
index 000000000000..8be4739a741b
--- /dev/null
+++ b/test/SemaTemplate/temp.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+
+// p3
+template<typename T> int foo(T), bar(T, T); // expected-error{{single entity}}
diff --git a/test/SemaTemplate/temp_arg.cpp b/test/SemaTemplate/temp_arg.cpp
new file mode 100644
index 000000000000..e873b8e2a61d
--- /dev/null
+++ b/test/SemaTemplate/temp_arg.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T,
+ int I,
+ template<typename> class TT>
+ class A; // expected-note 2 {{template is declared here}}
+
+template<typename> class X;
+
+A<int, 0, X> * a1;
+
+A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}}
+A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}}
diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp
new file mode 100644
index 000000000000..fe18fe657c16
--- /dev/null
+++ b/test/SemaTemplate/temp_arg_nontype.cpp
@@ -0,0 +1,124 @@
+// RUN: clang-cc -fsyntax-only -std=c++98 -verify %s
+template<int N> struct A; // expected-note 5{{template parameter is declared here}}
+
+A<0> *a0;
+
+A<int()> *a1; // expected-error{{template argument for non-type template parameter is treated as type 'int (void)'}}
+
+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}}
+
+// C++ [temp.arg.nontype]p5:
+A<A> *a4; // expected-error{{must have an integral or enumeration type}} \
+ // FIXME: the error message above is a bit lame
+
+enum E { Enumerator = 17 };
+A<E> *a5; // expected-error{{template argument for non-type template parameter must be an expression}}
+template<E Value> struct A1; // expected-note{{template parameter is declared here}}
+A1<Enumerator> *a6; // okay
+A1<17> *a7; // expected-error{{non-type template argument of type 'int' cannot be converted to a value of type 'enum E'}}
+
+const long LongValue = 12345678;
+A<LongValue> *a8;
+const short ShortValue = 17;
+A<ShortValue> *a9;
+
+int f(int);
+A<f(17)> *a10; // expected-error{{non-type template argument of type 'int' is not an integral constant expression}}
+
+class X {
+public:
+ X();
+ X(int, int);
+ operator int() const;
+};
+A<X(17, 42)> *a11; // expected-error{{non-type template argument of type 'class X' must have an integral or enumeration type}}
+
+template<X const *Ptr> struct A2;
+
+X *X_ptr;
+X an_X;
+X array_of_Xs[10];
+A2<X_ptr> *a12;
+A2<array_of_Xs> *a13;
+A2<&an_X> *a13_2;
+A2<(&an_X)> *a13_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}}
+
+float f(float);
+
+float g(float);
+double g(double);
+
+int h(int);
+float h2(float);
+
+template<int fp(int)> struct A3; // expected-note 2{{template parameter is declared here}}
+A3<h> *a14_1;
+A3<&h> *a14_2;
+A3<f> *a14_3;
+A3<&f> *a14_4;
+A3<h2> *a14_6; // expected-error{{non-type template argument of type 'float (*)(float)' cannot be converted to a value of type 'int (*)(int)'}}
+A3<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (*)(int)'}}
+// FIXME: the first error includes the string <overloaded function
+// type>, which makes Doug slightly unhappy.
+
+
+struct Y { } y;
+
+volatile X * X_volatile_ptr;
+template<X const &AnX> struct A4; // expected-note 2{{template parameter is declared here}}
+A4<an_X> *a15_1; // okay
+A4<*X_volatile_ptr> *a15_2; // expected-error{{reference binding of non-type template parameter of type 'class X const &' to template argument of type 'class X volatile' ignores qualifiers}}
+A4<y> *15_3; // expected-error{{non-type template parameter of reference type 'class X const &' cannot bind to template argument of type 'struct Y'}} \
+ // FIXME: expected-error{{expected unqualified-id}}
+
+template<int (&fr)(int)> struct A5; // expected-note 2{{template parameter is declared here}}
+A5<h> *a16_1;
+A5<f> *a16_3;
+A5<h2> *a16_6; // expected-error{{non-type template argument of type 'float (float)' cannot be converted to a value of type 'int (&)(int)'}}
+A5<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (&)(int)'}}
+// FIXME: the first error includes the string <overloaded function
+// type>, which makes Doug slightly unhappy.
+
+struct Z {
+ int foo(int);
+ float bar(float);
+ int bar(int);
+ double baz(double);
+
+ int int_member;
+ float float_member;
+};
+template<int (Z::*pmf)(int)> struct A6; // expected-note{{template parameter is declared here}}
+A6<&Z::foo> *a17_1;
+A6<&Z::bar> *a17_2;
+A6<&Z::baz> *a17_3; // expected-error{{non-type template argument of type 'double (struct Z::*)(double)' cannot be converted to a value of type 'int (struct Z::*)(int)'}}
+
+
+template<int Z::*pm> struct A7; // expected-note{{template parameter is declared here}}
+template<int Z::*pm> struct A7c;
+A7<&Z::int_member> *a18_1;
+A7c<&Z::int_member> *a18_2;
+A7<&Z::float_member> *a18_3; // expected-error{{non-type template argument of type 'float struct Z::*' cannot be converted to a value of type 'int struct Z::*'}}
+A7c<(&Z::int_member)> *a18_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}}
+
+template<unsigned char C> struct Overflow; // expected-note{{template parameter is declared here}}
+
+Overflow<5> *overflow1; // okay
+Overflow<256> *overflow2; // expected-error{{non-type template argument value '256' is too large for template parameter of type 'unsigned char'}}
+
+
+template<unsigned> struct Signedness; // expected-note{{template parameter is declared here}}
+Signedness<10> *signedness1; // okay
+Signedness<-10> *signedness2; // expected-error{{non-type template argument provides negative value '-10' for unsigned template parameter of type 'unsigned int'}}
+
+// Check canonicalization of template arguments.
+template<int (*)(int, int)> struct FuncPtr0;
+int func0(int, int);
+extern FuncPtr0<&func0> *fp0;
+template<int (*)(int, int)> struct FuncPtr0;
+extern FuncPtr0<&func0> *fp0;
+int func0(int, int);
+extern FuncPtr0<&func0> *fp0;
+
diff --git a/test/SemaTemplate/temp_arg_template.cpp b/test/SemaTemplate/temp_arg_template.cpp
new file mode 100644
index 000000000000..a5e9f75fa77a
--- /dev/null
+++ b/test/SemaTemplate/temp_arg_template.cpp
@@ -0,0 +1,38 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<template<typename T> class X> struct A; // expected-note 2{{previous template template parameter is here}}
+
+template<template<typename T, int I> class X> struct B; // expected-note{{previous template template parameter is here}}
+
+template<template<int I> class X> struct C; // expected-note{{previous non-type template parameter with type 'int' is here}}
+
+template<class> struct X; // expected-note{{too few template parameters in template template argument}}
+template<int N> struct Y; // expected-note{{template parameter has a different kind in template argument}}
+template<long N> struct Ylong; // expected-note{{template non-type parameter has a different type 'long' in template argument}}
+
+namespace N {
+ template<class> struct Z;
+}
+template<class, class> struct TooMany; // expected-note{{too many template parameters in template template argument}}
+
+
+A<X> *a1;
+A<N::Z> *a2;
+A< ::N::Z> *a3;
+
+A<Y> *a4; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
+A<TooMany> *a5; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
+B<X> *a6; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
+C<Y> *a7;
+C<Ylong> *a8; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
+
+template<typename T> void f(int);
+
+// FIXME: we're right to provide an error message, but it should say
+// that we need a class template. We won't get this right until name
+// lookup of 'f' returns a TemplateDecl.
+A<f> *a9; // expected-error{{template argument for template template parameter must be a template}}
+
+// FIXME: The code below is ill-formed, because of the evil digraph '<:'.
+// We should provide a much better error message than we currently do.
+// A<::N::Z> *a10;
diff --git a/test/SemaTemplate/temp_arg_type.cpp b/test/SemaTemplate/temp_arg_type.cpp
new file mode 100644
index 000000000000..b322dae98b90
--- /dev/null
+++ b/test/SemaTemplate/temp_arg_type.cpp
@@ -0,0 +1,24 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T> class A; // expected-note 2 {{template parameter is declared here}}
+
+// [temp.arg.type]p1
+A<0> *a1; // expected-error{{template argument for template type parameter must be a type}}
+
+A<A> *a2; // expected-error{{template argument for template type parameter must be a type}}
+
+A<int> *a3;
+A<int()> *a4;
+A<int(float)> *a5;
+A<A<int> > *a6;
+
+// [temp.arg.type]p2
+void f() {
+ class X { };
+ A<X> * a = 0; // expected-error{{template argument uses local type 'class X'}}
+}
+
+struct { int x; } Unnamed; // expected-note{{unnamed type used in template argument was declared here}}
+A<__typeof__(Unnamed)> *a7; // expected-error{{template argument uses unnamed type}}
+
+// FIXME: [temp.arg.type]p3. The check doesn't really belong here (it
+// belongs somewhere in the template instantiation section).
diff --git a/test/SemaTemplate/temp_class_spec.cpp b/test/SemaTemplate/temp_class_spec.cpp
new file mode 100644
index 000000000000..df652b5ba38d
--- /dev/null
+++ b/test/SemaTemplate/temp_class_spec.cpp
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T>
+struct is_pointer {
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_pointer<T*> {
+ static const bool value = true;
+};
+
+template<typename T>
+struct is_pointer<const T*> {
+ static const bool value = true;
+};
+
+int array0[is_pointer<int>::value? -1 : 1];
+int array1[is_pointer<int*>::value? 1 : -1];
+int array2[is_pointer<const int*>::value? 1 : -1]; // expected-error{{partial ordering}} \
+// expected-error{{negative}}
diff --git a/test/SemaTemplate/temp_explicit.cpp b/test/SemaTemplate/temp_explicit.cpp
new file mode 100644
index 000000000000..0292964a1a76
--- /dev/null
+++ b/test/SemaTemplate/temp_explicit.cpp
@@ -0,0 +1,111 @@
+// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+//
+// Tests explicit instantiation of templates.
+template<typename T, typename U = T> class X0 { };
+
+namespace N {
+ template<typename T, typename U = T> class X1 { };
+}
+
+// Check the syntax of explicit instantiations.
+template class X0<int, float>;
+template class X0<int>; // expected-note{{previous}}
+
+template class N::X1<int>;
+template class ::N::X1<int, float>;
+
+using namespace N;
+template class X1<float>;
+
+// Check for some bogus syntax that probably means that the user
+// wanted to write an explicit specialization, but forgot the '<>'
+// after 'template'.
+template class X0<double> { }; // expected-error{{explicit specialization}}
+
+// Check for explicit instantiations that come after other kinds of
+// instantiations or declarations.
+template class X0<int, int>; // expected-error{{duplicate}}
+
+template<> class X0<char> { }; // expected-note{{previous}}
+template class X0<char>; // expected-warning{{ignored}}
+
+void foo(X0<short>) { }
+template class X0<short>;
+
+// Check that explicit instantiations actually produce definitions. We
+// determine whether this happens by placing semantic errors in the
+// definition of the template we're instantiating.
+template<typename T> struct X2; // expected-note{{declared here}}
+
+template struct X2<float>; // expected-error{{undefined template}}
+
+template<typename T>
+struct X2 {
+ void f0(T*); // expected-error{{pointer to a reference}}
+};
+
+template struct X2<int>; // okay
+template struct X2<int&>; // expected-note{{in instantiation of}}
+
+// Check that explicit instantiations instantiate member classes.
+template<typename T> struct X3 {
+ struct Inner {
+ void f(T*); // expected-error{{pointer to a reference}}
+ };
+};
+
+void f1(X3<int&>); // okay, Inner, not instantiated
+
+template struct X3<int&>; // expected-note{{instantiation}}
+
+template<typename T> struct X4 {
+ struct Inner {
+ struct VeryInner {
+ void f(T*); // expected-error 2{{pointer to a reference}}
+ };
+ };
+};
+
+void f2(X4<int&>); // okay, Inner, not instantiated
+void f3(X4<int&>::Inner); // okay, Inner::VeryInner, not instantiated
+
+template struct X4<int&>; // expected-note{{instantiation}}
+template struct X4<float&>; // expected-note{{instantiation}}
+
+// Check explicit instantiation of member classes
+namespace N2 {
+
+template<typename T>
+struct X5 {
+ struct Inner1 {
+ void f(T&);
+ };
+
+ struct Inner2 {
+ struct VeryInner {
+ void g(T*); // expected-error 2{{pointer to a reference}}
+ };
+ };
+};
+
+}
+
+template struct N2::X5<void>::Inner2;
+
+using namespace N2;
+template struct X5<int&>::Inner2; // expected-note{{instantiation}}
+
+void f4(X5<float&>::Inner2);
+template struct X5<float&>::Inner2; // expected-note{{instantiation}}
+
+namespace N3 {
+ template struct N2::X5<int>::Inner2;
+}
+
+struct X6 {
+ struct Inner { // expected-note{{here}}
+ void f();
+ };
+};
+
+template struct X6::Inner; // expected-error{{non-templated}}
diff --git a/test/SemaTemplate/temp_explicit_cxx0x.cpp b/test/SemaTemplate/temp_explicit_cxx0x.cpp
new file mode 100644
index 000000000000..7045afc3032f
--- /dev/null
+++ b/test/SemaTemplate/temp_explicit_cxx0x.cpp
@@ -0,0 +1,24 @@
+// RUN: clang-cc -fsyntax-only -std=c++0x -verify %s
+namespace N1 {
+
+ template<typename T> struct X0 { }; // expected-note{{here}}
+
+ namespace Inner {
+ template<typename T> struct X1 { };
+ }
+
+ template struct X0<int>;
+ template struct Inner::X1<int>;
+}
+
+template<typename T> struct X2 { }; // expected-note{{here}}
+
+template struct ::N1::Inner::X1<float>;
+
+namespace N2 {
+ using namespace N1;
+
+ template struct X0<double>; // expected-error{{not in a namespace enclosing}}
+
+ template struct X2<float>; // expected-error{{at global scope}}
+}
diff --git a/test/SemaTemplate/temp_param.cpp b/test/SemaTemplate/temp_param.cpp
new file mode 100644
index 000000000000..c042f0849a04
--- /dev/null
+++ b/test/SemaTemplate/temp_param.cpp
@@ -0,0 +1,90 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class X;
+
+// C++ [temp.param]p4
+typedef int INT;
+enum E { enum1, enum2 };
+template<int N> struct A1;
+template<INT N, INT M> struct A2;
+template<enum E x, E y> struct A3;
+template<int &X> struct A4;
+template<int *Ptr> struct A5;
+template<int (&f)(int, int)> struct A6;
+template<int (*fp)(float, double)> struct A7;
+template<int X::*pm> struct A8;
+template<float (X::*pmf)(float, int)> struct A9;
+template<typename T, T x> struct A10;
+
+template<float f> struct A11; // expected-error{{a non-type template parameter cannot have type 'float'}}
+
+template<void *Ptr> struct A12; // expected-error{{a non-type template parameter cannot have type 'void *'}}
+
+// C++ [temp.param]p8
+template<int X[10]> struct A5;
+template<int f(float, double)> struct A7;
+
+// C++ [temp.param]p11:
+template<typename> struct Y1; // expected-note{{too few template parameters in template template argument}}
+template<typename, int> struct Y2;
+
+template<class T1 = int, // expected-note{{previous default template argument defined here}}
+ class T2> // expected-error{{template parameter missing a default argument}}
+ class B1;
+
+template<template<class> class = Y1, // expected-note{{previous default template argument defined here}}
+ template<class> class> // expected-error{{template parameter missing a default argument}}
+ class B1t;
+
+template<int N = 5, // expected-note{{previous default template argument defined here}}
+ int M> // expected-error{{template parameter missing a default argument}}
+ class B1n;
+
+// Check for bogus template parameter shadow warning.
+template<template<class T> class,
+ template<class T> class>
+ class B1noshadow;
+
+// C++ [temp.param]p10:
+template<class T1, class T2 = int> class B2;
+template<class T1 = int, class T2> class B2;
+
+template<template<class, int> class, template<class> class = Y1> class B2t;
+template<template<class, int> class = Y2, template<class> class> class B2t;
+
+template<int N, int M = 5> class B2n;
+template<int N = 5, int M> class B2n;
+
+// C++ [temp.param]p12:
+template<class T1,
+ class T2 = int> // expected-note{{previous default template argument defined here}}
+ class B3;
+template<class T1, typename T2> class B3;
+template<class T1,
+ typename T2 = float> // expected-error{{template parameter redefines default argument}}
+ class B3;
+
+template<template<class, int> class,
+ template<class> class = Y1> // expected-note{{previous default template argument defined here}}
+ class B3t;
+
+template<template<class, int> class, template<class> class> class B3t;
+
+template<template<class, int> class,
+ template<class> class = Y1> // expected-error{{template parameter redefines default argument}}
+ class B3t;
+
+template<int N,
+ int M = 5> // expected-note{{previous default template argument defined here}}
+ class B3n;
+
+template<int N, int M> class B3n;
+
+template<int N,
+ int M = 7> // expected-error{{template parameter redefines default argument}}
+ class B3n;
+
+// Check validity of default arguments
+template<template<class, int> class // expected-note{{previous template template parameter is here}}
+ = Y1> // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
+ class C1;
diff --git a/test/SemaTemplate/typename-specifier-2.cpp b/test/SemaTemplate/typename-specifier-2.cpp
new file mode 100644
index 000000000000..99e628523158
--- /dev/null
+++ b/test/SemaTemplate/typename-specifier-2.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename MetaFun, typename T>
+struct bind_metafun {
+ typedef typename MetaFun::template apply<T> type;
+};
+
+struct add_pointer {
+ template<typename T>
+ struct apply {
+ typedef T* type;
+ };
+};
+
+int i;
+// FIXME: if we make the declarator below a pointer (e.g., with *ip),
+// the error message isn't so good because we don't get the handy
+// 'aka' telling us that we're dealing with an int**. Should we fix
+// getDesugaredType to dig through pointers and such?
+bind_metafun<add_pointer, int>::type::type ip = &i;
+bind_metafun<add_pointer, float>::type::type fp = &i; // expected-error{{incompatible type initializing 'int *', expected 'bind_metafun<add_pointer, float>::type::type' (aka 'float *')}}
+
+
+template<typename T>
+struct extract_type_type {
+ typedef typename T::type::type t;
+};
+
+double d;
+extract_type_type<bind_metafun<add_pointer, double> >::t dp = &d;
diff --git a/test/SemaTemplate/typename-specifier.cpp b/test/SemaTemplate/typename-specifier.cpp
new file mode 100644
index 000000000000..d3fca3eacad5
--- /dev/null
+++ b/test/SemaTemplate/typename-specifier.cpp
@@ -0,0 +1,74 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+namespace N {
+ struct A {
+ typedef int type;
+ };
+
+ struct B {
+ };
+
+ struct C {
+ struct type { };
+ int type; // expected-note 2{{referenced member 'type' is declared here}}
+ };
+}
+
+int i;
+
+typename N::A::type *ip1 = &i;
+typename N::B::type *ip2 = &i; // expected-error{{ no type named 'type' in 'B'}}
+typename N::C::type *ip3 = &i; // expected-error{{typename specifier refers to non-type member 'type'}}
+
+void test(double d) {
+ typename N::A::type f(typename N::A::type(a)); // expected-warning{{parentheses were disambiguated as a function declarator}}
+ int five = f(5);
+
+ using namespace N;
+ for (typename A::type i = 0; i < 10; ++i)
+ five += 1;
+
+ const typename N::A::type f2(d);
+}
+
+namespace N {
+ template<typename T>
+ struct X {
+ typedef typename T::type type; // expected-error 2{{no type named 'type' in 'B'}} \
+ // FIXME: location info for error above isn't very good \
+ // expected-error 2{{typename specifier refers to non-type member 'type'}} \
+ // expected-error{{type 'int' cannot be used prior to '::' because it has no members}}
+ };
+}
+
+N::X<N::A>::type *ip4 = &i;
+N::X<N::B>::type *ip5 = &i; // expected-note{{in instantiation of template class 'struct N::X<struct N::B>' requested here}} \
+// expected-error{{unknown type name 'type'}}
+N::X<N::C>::type *ip6 = &i; // expected-note{{in instantiation of template class 'struct N::X<struct N::C>' requested here}} \
+// expected-error{{unknown type name 'type'}}
+
+N::X<int>::type fail1; // expected-note{{in instantiation of template class 'struct N::X<int>' requested here}} \
+// expected-error{{unknown type name 'type'}}
+
+template<typename T>
+struct Y {
+ typedef typename N::X<T>::type *type; // expected-note{{in instantiation of template class 'struct N::X<struct B>' requested here}} \
+ // expected-note{{in instantiation of template class 'struct N::X<struct C>' requested here}}
+};
+
+struct A {
+ typedef int type;
+};
+
+struct B {
+};
+
+struct C {
+ struct type { };
+ int type; // expected-note{{referenced member 'type' is declared here}}
+};
+
+::Y<A>::type ip7 = &i;
+::Y<B>::type ip8 = &i; // expected-note{{in instantiation of template class 'struct Y<struct B>' requested here}} \
+// expected-error{{unknown type name 'type'}}
+::Y<C>::type ip9 = &i; // expected-note{{in instantiation of template class 'struct Y<struct C>' requested here}} \
+// expected-error{{unknown type name 'type'}}
diff --git a/test/TestRunner.sh b/test/TestRunner.sh
new file mode 100755
index 000000000000..bb20728578c1
--- /dev/null
+++ b/test/TestRunner.sh
@@ -0,0 +1,134 @@
+#!/bin/sh
+#
+# TestRunner.sh - This script is used to run arbitrary unit tests. Unit
+# tests must contain the command used to run them in the input file, starting
+# immediately after a "RUN:" string.
+#
+# This runner recognizes and replaces the following strings in the command:
+#
+# %s - Replaced with the input name of the program, or the program to
+# execute, as appropriate.
+# %S - Replaced with the directory where the input file resides
+# %prcontext - prcontext.tcl script
+# %t - temporary file name (derived from testcase name)
+#
+
+FILENAME=$1
+TESTNAME=$1
+SUBST=$1
+FILEDIR=`dirname $TESTNAME`
+
+OUTPUT=Output/$1.out
+
+# create the output directory if it does not already exist
+mkdir -p `dirname $OUTPUT` > /dev/null 2>&1
+
+if test $# != 1; then
+ # If more than one parameter is passed in, there must be three parameters:
+ # The filename to read from (already processed), the command used to execute,
+ # and the file to output to.
+ SUBST=$2
+ OUTPUT=$3
+ TESTNAME=$3
+fi
+
+ulimit -t 40
+
+# Verify the script contains a run line.
+grep -q 'RUN:' $FILENAME || (
+ echo "******************** TEST '$TESTNAME' HAS NO RUN LINE! ********************"
+ exit 1
+)
+
+# Run under valgrind if the VG environment variable has been set.
+CLANG=$CLANG
+if [ ! -n "$CLANG" ]; then
+ CLANG="clang"
+fi
+
+# Resolve the path, and Make sure $CLANG actually exists; otherwise
+# ensuing failures are non-obvious.
+CLANG=$(which "$CLANG")
+if [ -z $CLANG ]; then
+ echo "Couldn't find 'clang' program, try setting CLANG in your environment"
+ exit 1
+fi
+
+if [ -n "$VG" ]; then
+ rm -f $OUTPUT.vg
+ CLANG="valgrind --leak-check=full --quiet --log-file=$OUTPUT.vg $CLANG"
+fi
+
+# Assuming $CLANG is correct, use it to derive clang-cc. We expect to
+# be looking in a build directory, so just add '-cc'.
+CLANGCC=$CLANGCC
+if [ ! -n "$CLANGCC" ]; then
+ CLANGCC="$CLANG-cc"
+fi
+
+# Try to sanity check $CLANGCC too
+CLANGCC=$(which "$CLANGCC")
+# If that failed, ask clang.
+if [ -z "$CLANGCC" ]; then
+ CLANGCC=$($CLANG -print-prog-name=clang-cc)
+fi
+if [ -z "$CLANGCC" ]; then
+ echo "Couldn't find 'clang-cc' program, make sure clang is found in your build directory"
+ exit 1
+fi
+
+SCRIPT=$OUTPUT.script
+TEMPOUTPUT=$OUTPUT.tmp
+grep 'RUN:' $FILENAME | \
+ sed -e "s|^.*RUN:\(.*\)$|\1|g" \
+ -e "s| clang | $CLANG |g" \
+ -e "s| clang-cc | $CLANGCC |g" \
+ -e "s|%s|$SUBST|g" \
+ -e "s|%S|$FILEDIR|g" \
+ -e "s|%prcontext|prcontext.tcl|g" \
+ -e "s|%t|$TEMPOUTPUT|g" > $SCRIPT
+
+IS_XFAIL=0
+if (grep -q XFAIL $FILENAME); then
+ IS_XFAIL=1
+ printf "XFAILED '$TESTNAME': "
+ grep XFAIL $FILENAME
+fi
+
+/bin/sh $SCRIPT > $OUTPUT 2>&1
+SCRIPT_STATUS=$?
+
+if [ -n "$VG" ]; then
+ [ ! -s $OUTPUT.vg ]
+ VG_STATUS=$?
+else
+ VG_STATUS=0
+fi
+
+if [ $IS_XFAIL -ne 0 ]; then
+ if [ $SCRIPT_STATUS -ne 0 ]; then
+ SCRIPT_STATUS=0
+ else
+ SCRIPT_STATUS=1
+ fi
+fi
+
+if [ $SCRIPT_STATUS -ne 0 -o $VG_STATUS -ne 0 ]; then
+ echo "******************** TEST '$TESTNAME' FAILED! ********************"
+ echo "Command: "
+ cat $SCRIPT
+ if [ $SCRIPT_STATUS -eq 0 ]; then
+ echo "Output:"
+ elif [ $IS_XFAIL -ne 0 ]; then
+ echo "Incorrect Output (Expected Failure):"
+ else
+ echo "Incorrect Output:"
+ fi
+ cat $OUTPUT
+ if [ $VG_STATUS -ne 0 ]; then
+ echo "Valgrind Output:"
+ cat $OUTPUT.vg
+ fi
+ echo "******************** TEST '$TESTNAME' FAILED! ********************"
+ exit 1
+fi
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
new file mode 100644
index 000000000000..6c66deac03eb
--- /dev/null
+++ b/tools/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(clang-cc)
+add_subdirectory(driver)
diff --git a/tools/Makefile b/tools/Makefile
new file mode 100644
index 000000000000..43124ba47cc5
--- /dev/null
+++ b/tools/Makefile
@@ -0,0 +1,13 @@
+##===- tools/Makefile --------------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL := ../../..
+DIRS := clang-cc driver
+
+include $(LEVEL)/Makefile.common
diff --git a/tools/clang-cc/CMakeLists.txt b/tools/clang-cc/CMakeLists.txt
new file mode 100644
index 000000000000..ec2ea3d62909
--- /dev/null
+++ b/tools/clang-cc/CMakeLists.txt
@@ -0,0 +1,26 @@
+set(LLVM_NO_RTTI 1)
+
+set( LLVM_USED_LIBS
+ clangFrontend
+ clangCodeGen
+ clangAnalysis
+ clangRewrite
+ clangSema
+ clangAST
+ clangParse
+ clangLex
+ clangBasic
+ )
+
+set( LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ bitreader
+ bitwriter
+ codegen
+ ipo
+ selectiondag
+ )
+
+add_clang_executable(clang-cc
+ clang-cc.cpp
+ )
diff --git a/tools/clang-cc/Makefile b/tools/clang-cc/Makefile
new file mode 100644
index 000000000000..874a42fc1913
--- /dev/null
+++ b/tools/clang-cc/Makefile
@@ -0,0 +1,32 @@
+##===- tools/clang-cc/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-cc
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CXXFLAGS = -fno-rtti
+
+# Clang has no plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+# Include this here so we can get the configuration of the targets
+# that have been configured for construction. We have to do this
+# early so we can set up LINK_COMPONENTS before including Makefile.rules
+include $(LEVEL)/Makefile.config
+
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) bitreader bitwriter codegen ipo selectiondag
+USEDLIBS = clangFrontend.a clangCodeGen.a clangAnalysis.a \
+ clangRewrite.a clangSema.a clangAST.a clangParse.a \
+ clangLex.a clangBasic.a
+
+# clang-cc lives in a special location; we can get away with this
+# because nothing else gets installed from here.
+PROJ_bindir := $(DESTDIR)$(PROJ_prefix)/libexec
+
+include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp
new file mode 100644
index 000000000000..a0ccafa9afce
--- /dev/null
+++ b/tools/clang-cc/clang-cc.cpp
@@ -0,0 +1,2293 @@
+//===--- clang.cpp - C-Language Front-end ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This utility may be invoked in the following manner:
+// clang --help - Output help info.
+// clang [options] - Read from stdin.
+// clang [options] file - Read from "file".
+// clang [options] file1 file2 - Read these files.
+//
+//===----------------------------------------------------------------------===//
+//
+// TODO: Options to support:
+//
+// -Wfatal-errors
+// -ftabstop=width
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/AnalysisConsumer.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/CompileOptions.h"
+#include "clang/Frontend/FixItRewriter.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/InitHeaderSearch.h"
+#include "clang/Frontend/InitPreprocessor.h"
+#include "clang/Frontend/PathDiagnosticClients.h"
+#include "clang/Frontend/PCHReader.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Sema/ParseAST.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Version.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PluginLoader.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/System/Host.h"
+#include "llvm/System/Path.h"
+#include "llvm/System/Process.h"
+#include "llvm/System/Program.h"
+#include "llvm/System/Signals.h"
+#include <cstdlib>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Source Location Parser
+//===----------------------------------------------------------------------===//
+
+/// \brief A source location that has been parsed on the command line.
+struct ParsedSourceLocation {
+ std::string FileName;
+ unsigned Line;
+ unsigned Column;
+
+ /// \brief Try to resolve the file name of a parsed source location.
+ ///
+ /// \returns true if there was an error, false otherwise.
+ bool ResolveLocation(FileManager &FileMgr, RequestedSourceLocation &Result);
+};
+
+bool
+ParsedSourceLocation::ResolveLocation(FileManager &FileMgr,
+ RequestedSourceLocation &Result) {
+ const FileEntry *File = FileMgr.getFile(FileName);
+ if (!File)
+ return true;
+
+ Result.File = File;
+ Result.Line = Line;
+ Result.Column = Column;
+ return false;
+}
+
+namespace llvm {
+ namespace cl {
+ /// \brief Command-line option parser that parses source locations.
+ ///
+ /// Source locations are of the form filename:line:column.
+ template<>
+ class parser<ParsedSourceLocation>
+ : public basic_parser<ParsedSourceLocation> {
+ public:
+ bool parse(Option &O, const char *ArgName,
+ const std::string &ArgValue,
+ ParsedSourceLocation &Val);
+ };
+
+ bool
+ parser<ParsedSourceLocation>::
+ parse(Option &O, const char *ArgName, const std::string &ArgValue,
+ ParsedSourceLocation &Val) {
+ using namespace clang;
+
+ const char *ExpectedFormat
+ = "source location must be of the form filename:line:column";
+ std::string::size_type SecondColon = ArgValue.rfind(':');
+ if (SecondColon == std::string::npos) {
+ std::fprintf(stderr, "%s\n", ExpectedFormat);
+ return true;
+ }
+ char *EndPtr;
+ long Column
+ = std::strtol(ArgValue.c_str() + SecondColon + 1, &EndPtr, 10);
+ if (EndPtr != ArgValue.c_str() + ArgValue.size()) {
+ std::fprintf(stderr, "%s\n", ExpectedFormat);
+ return true;
+ }
+
+ std::string::size_type FirstColon = ArgValue.rfind(':', SecondColon-1);
+ if (SecondColon == std::string::npos) {
+ std::fprintf(stderr, "%s\n", ExpectedFormat);
+ return true;
+ }
+ long Line = std::strtol(ArgValue.c_str() + FirstColon + 1, &EndPtr, 10);
+ if (EndPtr != ArgValue.c_str() + SecondColon) {
+ std::fprintf(stderr, "%s\n", ExpectedFormat);
+ return true;
+ }
+
+ Val.FileName = ArgValue.substr(0, FirstColon);
+ Val.Line = Line;
+ Val.Column = Column;
+ return false;
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Global options.
+//===----------------------------------------------------------------------===//
+
+/// ClangFrontendTimer - The front-end activities should charge time to it with
+/// TimeRegion. The -ftime-report option controls whether this will do
+/// anything.
+llvm::Timer *ClangFrontendTimer = 0;
+
+static bool HadErrors = false;
+
+static llvm::cl::opt<bool>
+Verbose("v", llvm::cl::desc("Enable verbose output"));
+static llvm::cl::opt<bool>
+Stats("print-stats",
+ llvm::cl::desc("Print performance metrics and statistics"));
+static llvm::cl::opt<bool>
+DisableFree("disable-free",
+ llvm::cl::desc("Disable freeing of memory on exit"),
+ llvm::cl::init(false));
+static llvm::cl::opt<bool>
+EmptyInputOnly("empty-input-only",
+ llvm::cl::desc("Force running on an empty input file"));
+
+enum ProgActions {
+ RewriteObjC, // ObjC->C Rewriter.
+ RewriteBlocks, // ObjC->C Rewriter for Blocks.
+ RewriteMacros, // Expand macros but not #includes.
+ RewriteTest, // Rewriter playground
+ FixIt, // Fix-It Rewriter
+ HTMLTest, // HTML displayer testing stuff.
+ EmitAssembly, // Emit a .s file.
+ EmitLLVM, // Emit a .ll file.
+ EmitBC, // Emit a .bc file.
+ EmitLLVMOnly, // Generate LLVM IR, but do not
+ EmitHTML, // Translate input source into HTML.
+ ASTPrint, // Parse ASTs and print them.
+ ASTPrintXML, // Parse ASTs and print them in XML.
+ ASTDump, // Parse ASTs and dump them.
+ ASTView, // Parse ASTs and view them in Graphviz.
+ PrintDeclContext, // Print DeclContext and their Decls.
+ ParsePrintCallbacks, // Parse and print each callback.
+ ParseSyntaxOnly, // Parse and perform semantic analysis.
+ ParseNoop, // Parse with noop callbacks.
+ RunPreprocessorOnly, // Just lex, no output.
+ PrintPreprocessedInput, // -E mode.
+ DumpTokens, // Dump out preprocessed tokens.
+ DumpRawTokens, // Dump out raw tokens.
+ RunAnalysis, // Run one or more source code analyses.
+ GeneratePTH, // Generate pre-tokenized header.
+ GeneratePCH, // Generate pre-compiled header.
+ InheritanceView // View C++ inheritance for a specified class.
+};
+
+static llvm::cl::opt<ProgActions>
+ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore,
+ llvm::cl::init(ParseSyntaxOnly),
+ llvm::cl::values(
+ clEnumValN(RunPreprocessorOnly, "Eonly",
+ "Just run preprocessor, no output (for timings)"),
+ clEnumValN(PrintPreprocessedInput, "E",
+ "Run preprocessor, emit preprocessed file"),
+ clEnumValN(DumpRawTokens, "dump-raw-tokens",
+ "Lex file in raw mode and dump raw tokens"),
+ clEnumValN(RunAnalysis, "analyze",
+ "Run static analysis engine"),
+ clEnumValN(DumpTokens, "dump-tokens",
+ "Run preprocessor, dump internal rep of tokens"),
+ clEnumValN(ParseNoop, "parse-noop",
+ "Run parser with noop callbacks (for timings)"),
+ clEnumValN(ParseSyntaxOnly, "fsyntax-only",
+ "Run parser and perform semantic analysis"),
+ clEnumValN(ParsePrintCallbacks, "parse-print-callbacks",
+ "Run parser and print each callback invoked"),
+ clEnumValN(EmitHTML, "emit-html",
+ "Output input source as HTML"),
+ clEnumValN(ASTPrint, "ast-print",
+ "Build ASTs and then pretty-print them"),
+ clEnumValN(ASTPrintXML, "ast-print-xml",
+ "Build ASTs and then print them in XML format"),
+ clEnumValN(ASTDump, "ast-dump",
+ "Build ASTs and then debug dump them"),
+ clEnumValN(ASTView, "ast-view",
+ "Build ASTs and view them with GraphViz"),
+ clEnumValN(PrintDeclContext, "print-decl-contexts",
+ "Print DeclContexts and their Decls"),
+ clEnumValN(GeneratePTH, "emit-pth",
+ "Generate pre-tokenized header file"),
+ clEnumValN(GeneratePCH, "emit-pch",
+ "Generate pre-compiled header file"),
+ clEnumValN(EmitAssembly, "S",
+ "Emit native assembly code"),
+ clEnumValN(EmitLLVM, "emit-llvm",
+ "Build ASTs then convert to LLVM, emit .ll file"),
+ clEnumValN(EmitBC, "emit-llvm-bc",
+ "Build ASTs then convert to LLVM, emit .bc file"),
+ clEnumValN(EmitLLVMOnly, "emit-llvm-only",
+ "Build ASTs and convert to LLVM, discarding output"),
+ clEnumValN(RewriteTest, "rewrite-test",
+ "Rewriter playground"),
+ clEnumValN(RewriteObjC, "rewrite-objc",
+ "Rewrite ObjC into C (code rewriter example)"),
+ clEnumValN(RewriteMacros, "rewrite-macros",
+ "Expand macros without full preprocessing"),
+ clEnumValN(RewriteBlocks, "rewrite-blocks",
+ "Rewrite Blocks to C"),
+ clEnumValN(FixIt, "fixit",
+ "Apply fix-it advice to the input source"),
+ clEnumValEnd));
+
+
+static llvm::cl::opt<std::string>
+OutputFile("o",
+ llvm::cl::value_desc("path"),
+ llvm::cl::desc("Specify output file"));
+
+
+//===----------------------------------------------------------------------===//
+// PTH.
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<std::string>
+TokenCache("token-cache", llvm::cl::value_desc("path"),
+ llvm::cl::desc("Use specified token cache file"));
+
+//===----------------------------------------------------------------------===//
+// Diagnostic Options
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<bool>
+VerifyDiagnostics("verify",
+ llvm::cl::desc("Verify emitted diagnostics and warnings"));
+
+static llvm::cl::opt<std::string>
+HTMLDiag("html-diags",
+ llvm::cl::desc("Generate HTML to report diagnostics"),
+ llvm::cl::value_desc("HTML directory"));
+
+static llvm::cl::opt<bool>
+NoShowColumn("fno-show-column",
+ llvm::cl::desc("Do not include column number on diagnostics"));
+
+static llvm::cl::opt<bool>
+NoShowLocation("fno-show-source-location",
+ llvm::cl::desc("Do not include source location information with"
+ " diagnostics"));
+
+static llvm::cl::opt<bool>
+NoCaretDiagnostics("fno-caret-diagnostics",
+ llvm::cl::desc("Do not include source line and caret with"
+ " diagnostics"));
+
+static llvm::cl::opt<bool>
+NoDiagnosticsFixIt("fno-diagnostics-fixit-info",
+ llvm::cl::desc("Do not include fixit information in"
+ " diagnostics"));
+
+static llvm::cl::opt<bool>
+PrintSourceRangeInfo("fdiagnostics-print-source-range-info",
+ llvm::cl::desc("Print source range spans in numeric form"));
+
+static llvm::cl::opt<bool>
+PrintDiagnosticOption("fdiagnostics-show-option",
+ llvm::cl::desc("Print diagnostic name with mappable diagnostics"));
+
+static llvm::cl::opt<unsigned>
+MessageLength("fmessage-length",
+ llvm::cl::desc("Format message diagnostics so that they fit "
+ "within N columns or fewer, when possible."),
+ llvm::cl::value_desc("N"));
+
+//===----------------------------------------------------------------------===//
+// C++ Visualization.
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<std::string>
+InheritanceViewCls("cxx-inheritance-view",
+ llvm::cl::value_desc("class name"),
+ llvm::cl::desc("View C++ inheritance for a specified class"));
+
+//===----------------------------------------------------------------------===//
+// Builtin Options
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<bool>
+TimeReport("ftime-report",
+ llvm::cl::desc("Print the amount of time each "
+ "phase of compilation takes"));
+
+static llvm::cl::opt<bool>
+Freestanding("ffreestanding",
+ llvm::cl::desc("Assert that the compilation takes place in a "
+ "freestanding environment"));
+
+static llvm::cl::opt<bool>
+AllowBuiltins("fbuiltin", llvm::cl::init(true),
+ llvm::cl::desc("Disable implicit builtin knowledge of functions"));
+
+
+static llvm::cl::opt<bool>
+MathErrno("fmath-errno", llvm::cl::init(true),
+ llvm::cl::desc("Require math functions to respect errno"));
+
+//===----------------------------------------------------------------------===//
+// Language Options
+//===----------------------------------------------------------------------===//
+
+enum LangKind {
+ langkind_unspecified,
+ langkind_c,
+ langkind_c_cpp,
+ langkind_asm_cpp,
+ langkind_cxx,
+ langkind_cxx_cpp,
+ langkind_objc,
+ langkind_objc_cpp,
+ langkind_objcxx,
+ langkind_objcxx_cpp
+};
+
+static llvm::cl::opt<LangKind>
+BaseLang("x", llvm::cl::desc("Base language to compile"),
+ llvm::cl::init(langkind_unspecified),
+ llvm::cl::values(clEnumValN(langkind_c, "c", "C"),
+ clEnumValN(langkind_cxx, "c++", "C++"),
+ clEnumValN(langkind_objc, "objective-c", "Objective C"),
+ clEnumValN(langkind_objcxx,"objective-c++","Objective C++"),
+ clEnumValN(langkind_c_cpp, "cpp-output",
+ "Preprocessed C"),
+ clEnumValN(langkind_asm_cpp, "assembler-with-cpp",
+ "Preprocessed asm"),
+ clEnumValN(langkind_cxx_cpp, "c++-cpp-output",
+ "Preprocessed C++"),
+ clEnumValN(langkind_objc_cpp, "objective-c-cpp-output",
+ "Preprocessed Objective C"),
+ clEnumValN(langkind_objcxx_cpp, "objective-c++-cpp-output",
+ "Preprocessed Objective C++"),
+ clEnumValN(langkind_c, "c-header",
+ "C header"),
+ clEnumValN(langkind_objc, "objective-c-header",
+ "Objective-C header"),
+ clEnumValN(langkind_cxx, "c++-header",
+ "C++ header"),
+ clEnumValN(langkind_objcxx, "objective-c++-header",
+ "Objective-C++ header"),
+ clEnumValEnd));
+
+static llvm::cl::opt<bool>
+LangObjC("ObjC", llvm::cl::desc("Set base language to Objective-C"),
+ llvm::cl::Hidden);
+static llvm::cl::opt<bool>
+LangObjCXX("ObjC++", llvm::cl::desc("Set base language to Objective-C++"),
+ llvm::cl::Hidden);
+
+static llvm::cl::opt<bool>
+ObjCExclusiveGC("fobjc-gc-only",
+ llvm::cl::desc("Use GC exclusively for Objective-C related "
+ "memory management"));
+
+static llvm::cl::opt<bool>
+ObjCEnableGC("fobjc-gc",
+ llvm::cl::desc("Enable Objective-C garbage collection"));
+
+static llvm::cl::opt<bool>
+ObjCEnableGCBitmapPrint("print-ivar-layout",
+ llvm::cl::desc("Enable Objective-C Ivar layout bitmap print trace"));
+
+static llvm::cl::opt<LangOptions::VisibilityMode>
+SymbolVisibility("fvisibility",
+ llvm::cl::desc("Set the default symbol visibility:"),
+ llvm::cl::init(LangOptions::Default),
+ llvm::cl::values(clEnumValN(LangOptions::Default, "default",
+ "Use default symbol visibility"),
+ clEnumValN(LangOptions::Hidden, "hidden",
+ "Use hidden symbol visibility"),
+ clEnumValN(LangOptions::Protected,"protected",
+ "Use protected symbol visibility"),
+ clEnumValEnd));
+
+static llvm::cl::opt<bool>
+OverflowChecking("ftrapv",
+ llvm::cl::desc("Trap on integer overflow"),
+ llvm::cl::init(false));
+
+static llvm::cl::opt<bool>
+ObjCSenderDispatch("fobjc-sender-dependent-dispatch",
+ llvm::cl::desc("Enable sender-dependent dispatch for"
+ "Objective-C messages"), llvm::cl::init(false));
+
+/// InitializeBaseLanguage - Handle the -x foo options.
+static void InitializeBaseLanguage() {
+ if (LangObjC)
+ BaseLang = langkind_objc;
+ else if (LangObjCXX)
+ BaseLang = langkind_objcxx;
+}
+
+static LangKind GetLanguage(const std::string &Filename) {
+ if (BaseLang != langkind_unspecified)
+ return BaseLang;
+
+ std::string::size_type DotPos = Filename.rfind('.');
+
+ if (DotPos == std::string::npos) {
+ BaseLang = langkind_c; // Default to C if no extension.
+ return langkind_c;
+ }
+
+ std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end());
+ // C header: .h
+ // C++ header: .hh or .H;
+ // assembler no preprocessing: .s
+ // assembler: .S
+ if (Ext == "c")
+ return langkind_c;
+ else if (Ext == "S" ||
+ // If the compiler is run on a .s file, preprocess it as .S
+ Ext == "s")
+ return langkind_asm_cpp;
+ else if (Ext == "i")
+ return langkind_c_cpp;
+ else if (Ext == "ii")
+ return langkind_cxx_cpp;
+ else if (Ext == "m")
+ return langkind_objc;
+ else if (Ext == "mi")
+ return langkind_objc_cpp;
+ else if (Ext == "mm" || Ext == "M")
+ return langkind_objcxx;
+ else if (Ext == "mii")
+ return langkind_objcxx_cpp;
+ else if (Ext == "C" || Ext == "cc" || Ext == "cpp" || Ext == "CPP" ||
+ Ext == "c++" || Ext == "cp" || Ext == "cxx")
+ return langkind_cxx;
+ else
+ return langkind_c;
+}
+
+
+static void InitializeCOptions(LangOptions &Options) {
+ // Do nothing.
+}
+
+static void InitializeObjCOptions(LangOptions &Options) {
+ Options.ObjC1 = Options.ObjC2 = 1;
+}
+
+
+static void InitializeLangOptions(LangOptions &Options, LangKind LK){
+ // FIXME: implement -fpreprocessed mode.
+ bool NoPreprocess = false;
+
+ switch (LK) {
+ default: assert(0 && "Unknown language kind!");
+ case langkind_asm_cpp:
+ Options.AsmPreprocessor = 1;
+ // FALLTHROUGH
+ case langkind_c_cpp:
+ NoPreprocess = true;
+ // FALLTHROUGH
+ case langkind_c:
+ InitializeCOptions(Options);
+ break;
+ case langkind_cxx_cpp:
+ NoPreprocess = true;
+ // FALLTHROUGH
+ case langkind_cxx:
+ Options.CPlusPlus = 1;
+ break;
+ case langkind_objc_cpp:
+ NoPreprocess = true;
+ // FALLTHROUGH
+ case langkind_objc:
+ InitializeObjCOptions(Options);
+ break;
+ case langkind_objcxx_cpp:
+ NoPreprocess = true;
+ // FALLTHROUGH
+ case langkind_objcxx:
+ Options.ObjC1 = Options.ObjC2 = 1;
+ Options.CPlusPlus = 1;
+ break;
+ }
+
+ if (ObjCExclusiveGC)
+ Options.setGCMode(LangOptions::GCOnly);
+ else if (ObjCEnableGC)
+ Options.setGCMode(LangOptions::HybridGC);
+
+ if (ObjCEnableGCBitmapPrint)
+ Options.ObjCGCBitmapPrint = 1;
+
+ Options.setVisibilityMode(SymbolVisibility);
+ Options.OverflowChecking = OverflowChecking;
+}
+
+/// LangStds - Language standards we support.
+enum LangStds {
+ lang_unspecified,
+ lang_c89, lang_c94, lang_c99,
+ lang_gnu_START,
+ lang_gnu89 = lang_gnu_START, lang_gnu99,
+ lang_cxx98, lang_gnucxx98,
+ lang_cxx0x, lang_gnucxx0x
+};
+
+static llvm::cl::opt<LangStds>
+LangStd("std", llvm::cl::desc("Language standard to compile for"),
+ llvm::cl::init(lang_unspecified),
+ llvm::cl::values(clEnumValN(lang_c89, "c89", "ISO C 1990"),
+ clEnumValN(lang_c89, "c90", "ISO C 1990"),
+ clEnumValN(lang_c89, "iso9899:1990", "ISO C 1990"),
+ clEnumValN(lang_c94, "iso9899:199409",
+ "ISO C 1990 with amendment 1"),
+ clEnumValN(lang_c99, "c99", "ISO C 1999"),
+ clEnumValN(lang_c99, "c9x", "ISO C 1999"),
+ clEnumValN(lang_c99, "iso9899:1999", "ISO C 1999"),
+ clEnumValN(lang_c99, "iso9899:199x", "ISO C 1999"),
+ clEnumValN(lang_gnu89, "gnu89",
+ "ISO C 1990 with GNU extensions"),
+ clEnumValN(lang_gnu99, "gnu99",
+ "ISO C 1999 with GNU extensions (default for C)"),
+ clEnumValN(lang_gnu99, "gnu9x",
+ "ISO C 1999 with GNU extensions"),
+ clEnumValN(lang_cxx98, "c++98",
+ "ISO C++ 1998 with amendments"),
+ clEnumValN(lang_gnucxx98, "gnu++98",
+ "ISO C++ 1998 with amendments and GNU "
+ "extensions (default for C++)"),
+ clEnumValN(lang_cxx0x, "c++0x",
+ "Upcoming ISO C++ 200x with amendments"),
+ clEnumValN(lang_gnucxx0x, "gnu++0x",
+ "Upcoming ISO C++ 200x with amendments and GNU "
+ "extensions"),
+ clEnumValEnd));
+
+static llvm::cl::opt<bool>
+NoOperatorNames("fno-operator-names",
+ llvm::cl::desc("Do not treat C++ operator name keywords as "
+ "synonyms for operators"));
+
+static llvm::cl::opt<bool>
+PascalStrings("fpascal-strings",
+ llvm::cl::desc("Recognize and construct Pascal-style "
+ "string literals"));
+
+static llvm::cl::opt<bool>
+MSExtensions("fms-extensions",
+ llvm::cl::desc("Accept some non-standard constructs used in "
+ "Microsoft header files "));
+
+static llvm::cl::opt<bool>
+WritableStrings("fwritable-strings",
+ llvm::cl::desc("Store string literals as writable data"));
+
+static llvm::cl::opt<bool>
+NoLaxVectorConversions("fno-lax-vector-conversions",
+ llvm::cl::desc("Disallow implicit conversions between "
+ "vectors with a different number of "
+ "elements or different element types"));
+
+static llvm::cl::opt<bool>
+EnableBlocks("fblocks", llvm::cl::desc("enable the 'blocks' language feature"));
+
+static llvm::cl::opt<bool>
+EnableHeinousExtensions("fheinous-gnu-extensions",
+ llvm::cl::desc("enable GNU extensions that you really really shouldn't use"),
+ llvm::cl::ValueDisallowed, llvm::cl::Hidden);
+
+static llvm::cl::opt<bool>
+ObjCNonFragileABI("fobjc-nonfragile-abi",
+ llvm::cl::desc("enable objective-c's nonfragile abi"));
+
+
+static llvm::cl::opt<bool>
+EmitAllDecls("femit-all-decls",
+ llvm::cl::desc("Emit all declarations, even if unused"));
+
+static llvm::cl::opt<bool>
+Exceptions("fexceptions",
+ llvm::cl::desc("Enable support for exception handling"));
+
+static llvm::cl::opt<bool>
+GNURuntime("fgnu-runtime",
+ llvm::cl::desc("Generate output compatible with the standard GNU "
+ "Objective-C runtime"));
+
+static llvm::cl::opt<bool>
+NeXTRuntime("fnext-runtime",
+ llvm::cl::desc("Generate output compatible with the NeXT "
+ "runtime"));
+
+
+
+static llvm::cl::opt<bool>
+Trigraphs("trigraphs", llvm::cl::desc("Process trigraph sequences"));
+
+static llvm::cl::opt<unsigned>
+TemplateDepth("ftemplate-depth", llvm::cl::init(99),
+ llvm::cl::desc("Maximum depth of recursive template "
+ "instantiation"));
+static llvm::cl::opt<bool>
+DollarsInIdents("fdollars-in-identifiers",
+ llvm::cl::desc("Allow '$' in identifiers"));
+
+
+static llvm::cl::opt<bool>
+OptSize("Os", llvm::cl::desc("Optimize for size"));
+
+static llvm::cl::opt<bool>
+NoCommon("fno-common",
+ llvm::cl::desc("Compile common globals like normal definitions"),
+ llvm::cl::ValueDisallowed);
+
+static llvm::cl::opt<std::string>
+MainFileName("main-file-name",
+ llvm::cl::desc("Main file name to use for debug info"));
+
+// FIXME: Also add an "-fno-access-control" option.
+static llvm::cl::opt<bool>
+AccessControl("faccess-control",
+ llvm::cl::desc("Enable C++ access control"));
+
+// It might be nice to add bounds to the CommandLine library directly.
+struct OptLevelParser : public llvm::cl::parser<unsigned> {
+ bool parse(llvm::cl::Option &O, const char *ArgName,
+ const std::string &Arg, unsigned &Val) {
+ if (llvm::cl::parser<unsigned>::parse(O, ArgName, Arg, Val))
+ return true;
+ if (Val > 3)
+ return O.error(": '" + Arg + "' invalid optimization level!");
+ return false;
+ }
+};
+static llvm::cl::opt<unsigned, false, OptLevelParser>
+OptLevel("O", llvm::cl::Prefix,
+ llvm::cl::desc("Optimization level"),
+ llvm::cl::init(0));
+
+static llvm::cl::opt<unsigned>
+PICLevel("pic-level", llvm::cl::desc("Value for __PIC__"));
+
+static llvm::cl::opt<bool>
+StaticDefine("static-define", llvm::cl::desc("Should __STATIC__ be defined"));
+
+static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
+ TargetInfo *Target,
+ const llvm::StringMap<bool> &Features) {
+ // Allow the target to set the default the langauge options as it sees fit.
+ Target->getDefaultLangOptions(Options);
+
+ // Pass the map of target features to the target for validation and
+ // processing.
+ Target->HandleTargetFeatures(Features);
+
+ if (LangStd == lang_unspecified) {
+ // Based on the base language, pick one.
+ switch (LK) {
+ case lang_unspecified: assert(0 && "Unknown base language");
+ case langkind_c:
+ case langkind_asm_cpp:
+ case langkind_c_cpp:
+ case langkind_objc:
+ case langkind_objc_cpp:
+ LangStd = lang_gnu99;
+ break;
+ case langkind_cxx:
+ case langkind_cxx_cpp:
+ case langkind_objcxx:
+ case langkind_objcxx_cpp:
+ LangStd = lang_gnucxx98;
+ break;
+ }
+ }
+
+ switch (LangStd) {
+ default: assert(0 && "Unknown language standard!");
+
+ // Fall through from newer standards to older ones. This isn't really right.
+ // FIXME: Enable specifically the right features based on the language stds.
+ case lang_gnucxx0x:
+ case lang_cxx0x:
+ Options.CPlusPlus0x = 1;
+ // FALL THROUGH
+ case lang_gnucxx98:
+ case lang_cxx98:
+ Options.CPlusPlus = 1;
+ Options.CXXOperatorNames = !NoOperatorNames;
+ // FALL THROUGH.
+ case lang_gnu99:
+ case lang_c99:
+ Options.C99 = 1;
+ Options.HexFloats = 1;
+ // FALL THROUGH.
+ case lang_gnu89:
+ Options.BCPLComment = 1; // Only for C99/C++.
+ // FALL THROUGH.
+ case lang_c94:
+ Options.Digraphs = 1; // C94, C99, C++.
+ // FALL THROUGH.
+ case lang_c89:
+ break;
+ }
+
+ // GNUMode - Set if we're in gnu99, gnu89, gnucxx98, etc.
+ Options.GNUMode = LangStd >= lang_gnu_START;
+
+ if (Options.CPlusPlus) {
+ Options.C99 = 0;
+ Options.HexFloats = Options.GNUMode;
+ }
+
+ if (LangStd == lang_c89 || LangStd == lang_c94 || LangStd == lang_gnu89)
+ Options.ImplicitInt = 1;
+ else
+ Options.ImplicitInt = 0;
+
+ // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs
+ // is specified, or -std is set to a conforming mode.
+ Options.Trigraphs = !Options.GNUMode;
+ if (Trigraphs.getPosition())
+ Options.Trigraphs = Trigraphs; // Command line option wins if specified.
+
+ // If in a conformant language mode (e.g. -std=c99) Blocks defaults to off
+ // even if they are normally on for the target. In GNU modes (e.g.
+ // -std=gnu99) the default for blocks depends on the target settings.
+ // However, blocks are not turned off when compiling Obj-C or Obj-C++ code.
+ if (!Options.ObjC1 && !Options.GNUMode)
+ Options.Blocks = 0;
+
+ // Default to not accepting '$' in identifiers when preprocessing assembler,
+ // but do accept when preprocessing C. FIXME: these defaults are right for
+ // darwin, are they right everywhere?
+ Options.DollarIdents = LK != langkind_asm_cpp;
+ if (DollarsInIdents.getPosition()) // Explicit setting overrides default.
+ Options.DollarIdents = DollarsInIdents;
+
+ if (PascalStrings.getPosition())
+ Options.PascalStrings = PascalStrings;
+ Options.Microsoft = MSExtensions;
+ Options.WritableStrings = WritableStrings;
+ if (NoLaxVectorConversions.getPosition())
+ Options.LaxVectorConversions = 0;
+ Options.Exceptions = Exceptions;
+ if (EnableBlocks.getPosition())
+ Options.Blocks = EnableBlocks;
+
+ if (!AllowBuiltins)
+ Options.NoBuiltin = 1;
+ if (Freestanding)
+ Options.Freestanding = Options.NoBuiltin = 1;
+
+ if (EnableHeinousExtensions)
+ Options.HeinousExtensions = 1;
+
+ if (AccessControl)
+ Options.AccessControl = 1;
+
+ Options.MathErrno = MathErrno;
+
+ Options.InstantiationDepth = TemplateDepth;
+
+ // Override the default runtime if the user requested it.
+ if (NeXTRuntime)
+ Options.NeXTRuntime = 1;
+ else if (GNURuntime)
+ Options.NeXTRuntime = 0;
+
+ if (ObjCNonFragileABI)
+ Options.ObjCNonFragileABI = 1;
+
+ Options.ObjCSenderDispatch = ObjCSenderDispatch;
+
+ if (EmitAllDecls)
+ Options.EmitAllDecls = 1;
+
+ // The __OPTIMIZE_SIZE__ define is tied to -Oz, which we don't
+ // support.
+ Options.OptimizeSize = 0;
+
+ // -Os implies -O2
+ if (OptSize || OptLevel)
+ Options.Optimize = 1;
+
+ assert(PICLevel <= 2 && "Invalid value for -pic-level");
+ Options.PICLevel = PICLevel;
+
+ Options.GNUInline = !Options.C99;
+ // FIXME: This is affected by other options (-fno-inline).
+ Options.NoInline = !OptSize && !OptLevel;
+
+ Options.Static = StaticDefine;
+
+ if (MainFileName.getPosition())
+ Options.setMainFileName(MainFileName.c_str());
+}
+
+//===----------------------------------------------------------------------===//
+// Target Triple Processing.
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<std::string>
+TargetTriple("triple",
+ llvm::cl::desc("Specify target triple (e.g. i686-apple-darwin9)"));
+
+static llvm::cl::opt<std::string>
+MacOSVersionMin("mmacosx-version-min",
+ llvm::cl::desc("Specify target Mac OS X version (e.g. 10.5)"));
+
+// If -mmacosx-version-min=10.3.9 is specified, change the triple from being
+// something like powerpc-apple-darwin9 to powerpc-apple-darwin7
+
+// FIXME: We should have the driver do this instead.
+static void HandleMacOSVersionMin(std::string &Triple) {
+ std::string::size_type DarwinDashIdx = Triple.find("-darwin");
+ if (DarwinDashIdx == std::string::npos) {
+ fprintf(stderr,
+ "-mmacosx-version-min only valid for darwin (Mac OS X) targets\n");
+ exit(1);
+ }
+ unsigned DarwinNumIdx = DarwinDashIdx + strlen("-darwin");
+
+ // Remove the number.
+ Triple.resize(DarwinNumIdx);
+
+ // Validate that MacOSVersionMin is a 'version number', starting with 10.[3-9]
+ bool MacOSVersionMinIsInvalid = false;
+ int VersionNum = 0;
+ if (MacOSVersionMin.size() < 4 ||
+ MacOSVersionMin.substr(0, 3) != "10." ||
+ !isdigit(MacOSVersionMin[3])) {
+ MacOSVersionMinIsInvalid = true;
+ } else {
+ const char *Start = MacOSVersionMin.c_str()+3;
+ char *End = 0;
+ VersionNum = (int)strtol(Start, &End, 10);
+
+ // The version number must be in the range 0-9.
+ MacOSVersionMinIsInvalid = (unsigned)VersionNum > 9;
+
+ // Turn MacOSVersionMin into a darwin number: e.g. 10.3.9 is 3 -> 7.
+ Triple += llvm::itostr(VersionNum+4);
+
+ if (End[0] == '.' && isdigit(End[1]) && End[2] == '\0') { // 10.4.7 is ok.
+ // Add the period piece (.7) to the end of the triple. This gives us
+ // something like ...-darwin8.7
+ Triple += End;
+ } else if (End[0] != '\0') { // "10.4" is ok. 10.4x is not.
+ MacOSVersionMinIsInvalid = true;
+ }
+ }
+
+ if (MacOSVersionMinIsInvalid) {
+ fprintf(stderr,
+ "-mmacosx-version-min=%s is invalid, expected something like '10.4'.\n",
+ MacOSVersionMin.c_str());
+ exit(1);
+ }
+ else if (VersionNum <= 4 &&
+ !strncmp(Triple.c_str(), "x86_64", strlen("x86_64"))) {
+ fprintf(stderr,
+ "-mmacosx-version-min=%s is invalid with -arch x86_64.\n",
+ MacOSVersionMin.c_str());
+ exit(1);
+ }
+
+}
+
+static llvm::cl::opt<std::string>
+IPhoneOSVersionMin("miphoneos-version-min",
+ llvm::cl::desc("Specify target iPhone OS version (e.g. 2.0)"));
+
+// If -miphoneos-version-min=2.2 is specified, change the triple from being
+// something like armv6-apple-darwin10 to armv6-apple-darwin9.2.2. We use
+// 9 as the default major Darwin number, and encode the iPhone OS version
+// number in the minor version and revision.
+
+// FIXME: We should have the driver do this instead.
+static void HandleIPhoneOSVersionMin(std::string &Triple) {
+ std::string::size_type DarwinDashIdx = Triple.find("-darwin");
+ if (DarwinDashIdx == std::string::npos) {
+ fprintf(stderr,
+ "-miphoneos-version-min only valid for darwin (Mac OS X) targets\n");
+ exit(1);
+ }
+ unsigned DarwinNumIdx = DarwinDashIdx + strlen("-darwin");
+
+ // Remove the number.
+ Triple.resize(DarwinNumIdx);
+
+ // Validate that IPhoneOSVersionMin is a 'version number', starting with [2-9].[0-9]
+ bool IPhoneOSVersionMinIsInvalid = false;
+ int VersionNum = 0;
+ if (IPhoneOSVersionMin.size() < 3 ||
+ !isdigit(IPhoneOSVersionMin[0])) {
+ IPhoneOSVersionMinIsInvalid = true;
+ } else {
+ const char *Start = IPhoneOSVersionMin.c_str();
+ char *End = 0;
+ VersionNum = (int)strtol(Start, &End, 10);
+
+ // The version number must be in the range 0-9.
+ IPhoneOSVersionMinIsInvalid = (unsigned)VersionNum > 9;
+
+ // Turn IPhoneOSVersionMin into a darwin number: e.g. 2.0 is 2 -> 9.2.
+ Triple += "9." + llvm::itostr(VersionNum);
+
+ if (End[0] == '.' && isdigit(End[1]) && End[2] == '\0') { // 2.2 is ok.
+ // Add the period piece (.2) to the end of the triple. This gives us
+ // something like ...-darwin9.2.2
+ Triple += End;
+ } else if (End[0] != '\0') { // "2.2" is ok. 2x is not.
+ IPhoneOSVersionMinIsInvalid = true;
+ }
+ }
+
+ if (IPhoneOSVersionMinIsInvalid) {
+ fprintf(stderr,
+ "-miphoneos-version-min=%s is invalid, expected something like '2.0'.\n",
+ IPhoneOSVersionMin.c_str());
+ exit(1);
+ }
+}
+
+/// CreateTargetTriple - Process the various options that affect the target
+/// triple and build a final aggregate triple that we are compiling for.
+static std::string CreateTargetTriple() {
+ // Initialize base triple. If a -triple option has been specified, use
+ // that triple. Otherwise, default to the host triple.
+ std::string Triple = TargetTriple;
+ if (Triple.empty())
+ Triple = llvm::sys::getHostTriple();
+
+ // If -mmacosx-version-min=10.3.9 is specified, change the triple from being
+ // something like powerpc-apple-darwin9 to powerpc-apple-darwin7
+ if (!MacOSVersionMin.empty())
+ HandleMacOSVersionMin(Triple);
+ else if (!IPhoneOSVersionMin.empty())
+ HandleIPhoneOSVersionMin(Triple);;
+
+ return Triple;
+}
+
+//===----------------------------------------------------------------------===//
+// SourceManager initialization.
+//===----------------------------------------------------------------------===//
+
+static bool InitializeSourceManager(Preprocessor &PP,
+ const std::string &InFile) {
+ // Figure out where to get and map in the main file.
+ SourceManager &SourceMgr = PP.getSourceManager();
+ FileManager &FileMgr = PP.getFileManager();
+
+ if (EmptyInputOnly) {
+ const char *EmptyStr = "";
+ llvm::MemoryBuffer *SB =
+ llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<empty input>");
+ SourceMgr.createMainFileIDForMemBuffer(SB);
+ } else if (InFile != "-") {
+ const FileEntry *File = FileMgr.getFile(InFile);
+ if (File) SourceMgr.createMainFileID(File, SourceLocation());
+ if (SourceMgr.getMainFileID().isInvalid()) {
+ PP.getDiagnostics().Report(FullSourceLoc(), diag::err_fe_error_reading)
+ << InFile.c_str();
+ return true;
+ }
+ } else {
+ llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN();
+
+ // If stdin was empty, SB is null. Cons up an empty memory
+ // buffer now.
+ if (!SB) {
+ const char *EmptyStr = "";
+ SB = llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<stdin>");
+ }
+
+ SourceMgr.createMainFileIDForMemBuffer(SB);
+ if (SourceMgr.getMainFileID().isInvalid()) {
+ PP.getDiagnostics().Report(FullSourceLoc(),
+ diag::err_fe_error_reading_stdin);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Initialization
+//===----------------------------------------------------------------------===//
+
+// FIXME: Preprocessor builtins to support.
+// -A... - Play with #assertions
+// -undef - Undefine all predefined macros
+
+static llvm::cl::list<std::string>
+D_macros("D", llvm::cl::value_desc("macro"), llvm::cl::Prefix,
+ llvm::cl::desc("Predefine the specified macro"));
+static llvm::cl::list<std::string>
+U_macros("U", llvm::cl::value_desc("macro"), llvm::cl::Prefix,
+ llvm::cl::desc("Undefine the specified macro"));
+
+static llvm::cl::list<std::string>
+ImplicitIncludes("include", llvm::cl::value_desc("file"),
+ llvm::cl::desc("Include file before parsing"));
+static llvm::cl::list<std::string>
+ImplicitMacroIncludes("imacros", llvm::cl::value_desc("file"),
+ llvm::cl::desc("Include macros from file before parsing"));
+
+static llvm::cl::opt<std::string>
+ImplicitIncludePCH("include-pch", llvm::cl::value_desc("file"),
+ llvm::cl::desc("Include precompiled header file"));
+
+static llvm::cl::opt<std::string>
+ImplicitIncludePTH("include-pth", llvm::cl::value_desc("file"),
+ llvm::cl::desc("Include file before parsing"));
+
+
+//===----------------------------------------------------------------------===//
+// Preprocessor include path information.
+//===----------------------------------------------------------------------===//
+
+// This tool exports a large number of command line options to control how the
+// preprocessor searches for header files. At root, however, the Preprocessor
+// object takes a very simple interface: a list of directories to search for
+//
+// FIXME: -nostdinc++
+// FIXME: -imultilib
+//
+
+static llvm::cl::opt<bool>
+nostdinc("nostdinc", llvm::cl::desc("Disable standard #include directories"));
+
+// Various command line options. These four add directories to each chain.
+static llvm::cl::list<std::string>
+F_dirs("F", llvm::cl::value_desc("directory"), llvm::cl::Prefix,
+ llvm::cl::desc("Add directory to framework include search path"));
+static llvm::cl::list<std::string>
+I_dirs("I", llvm::cl::value_desc("directory"), llvm::cl::Prefix,
+ llvm::cl::desc("Add directory to include search path"));
+static llvm::cl::list<std::string>
+idirafter_dirs("idirafter", llvm::cl::value_desc("directory"), llvm::cl::Prefix,
+ llvm::cl::desc("Add directory to AFTER include search path"));
+static llvm::cl::list<std::string>
+iquote_dirs("iquote", llvm::cl::value_desc("directory"), llvm::cl::Prefix,
+ llvm::cl::desc("Add directory to QUOTE include search path"));
+static llvm::cl::list<std::string>
+isystem_dirs("isystem", llvm::cl::value_desc("directory"), llvm::cl::Prefix,
+ llvm::cl::desc("Add directory to SYSTEM include search path"));
+
+// These handle -iprefix/-iwithprefix/-iwithprefixbefore.
+static llvm::cl::list<std::string>
+iprefix_vals("iprefix", llvm::cl::value_desc("prefix"), llvm::cl::Prefix,
+ llvm::cl::desc("Set the -iwithprefix/-iwithprefixbefore prefix"));
+static llvm::cl::list<std::string>
+iwithprefix_vals("iwithprefix", llvm::cl::value_desc("dir"), llvm::cl::Prefix,
+ llvm::cl::desc("Set directory to SYSTEM include search path with prefix"));
+static llvm::cl::list<std::string>
+iwithprefixbefore_vals("iwithprefixbefore", llvm::cl::value_desc("dir"),
+ llvm::cl::Prefix,
+ llvm::cl::desc("Set directory to include search path with prefix"));
+
+static llvm::cl::opt<std::string>
+isysroot("isysroot", llvm::cl::value_desc("dir"), llvm::cl::init("/"),
+ llvm::cl::desc("Set the system root directory (usually /)"));
+
+// Finally, implement the code that groks the options above.
+
+/// InitializeIncludePaths - Process the -I options and set them in the
+/// HeaderSearch object.
+void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
+ FileManager &FM, const LangOptions &Lang) {
+ InitHeaderSearch Init(Headers, Verbose, isysroot);
+
+ // Handle -I... and -F... options, walking the lists in parallel.
+ unsigned Iidx = 0, Fidx = 0;
+ while (Iidx < I_dirs.size() && Fidx < F_dirs.size()) {
+ if (I_dirs.getPosition(Iidx) < F_dirs.getPosition(Fidx)) {
+ Init.AddPath(I_dirs[Iidx], InitHeaderSearch::Angled, false, true, false);
+ ++Iidx;
+ } else {
+ Init.AddPath(F_dirs[Fidx], InitHeaderSearch::Angled, false, true, true);
+ ++Fidx;
+ }
+ }
+
+ // Consume what's left from whatever list was longer.
+ for (; Iidx != I_dirs.size(); ++Iidx)
+ Init.AddPath(I_dirs[Iidx], InitHeaderSearch::Angled, false, true, false);
+ for (; Fidx != F_dirs.size(); ++Fidx)
+ Init.AddPath(F_dirs[Fidx], InitHeaderSearch::Angled, false, true, true);
+
+ // Handle -idirafter... options.
+ for (unsigned i = 0, e = idirafter_dirs.size(); i != e; ++i)
+ Init.AddPath(idirafter_dirs[i], InitHeaderSearch::After,
+ false, true, false);
+
+ // Handle -iquote... options.
+ for (unsigned i = 0, e = iquote_dirs.size(); i != e; ++i)
+ Init.AddPath(iquote_dirs[i], InitHeaderSearch::Quoted, false, true, false);
+
+ // Handle -isystem... options.
+ for (unsigned i = 0, e = isystem_dirs.size(); i != e; ++i)
+ Init.AddPath(isystem_dirs[i], InitHeaderSearch::System, false, true, false);
+
+ // Walk the -iprefix/-iwithprefix/-iwithprefixbefore argument lists in
+ // parallel, processing the values in order of occurance to get the right
+ // prefixes.
+ {
+ std::string Prefix = ""; // FIXME: this isn't the correct default prefix.
+ unsigned iprefix_idx = 0;
+ unsigned iwithprefix_idx = 0;
+ unsigned iwithprefixbefore_idx = 0;
+ bool iprefix_done = iprefix_vals.empty();
+ bool iwithprefix_done = iwithprefix_vals.empty();
+ bool iwithprefixbefore_done = iwithprefixbefore_vals.empty();
+ while (!iprefix_done || !iwithprefix_done || !iwithprefixbefore_done) {
+ if (!iprefix_done &&
+ (iwithprefix_done ||
+ iprefix_vals.getPosition(iprefix_idx) <
+ iwithprefix_vals.getPosition(iwithprefix_idx)) &&
+ (iwithprefixbefore_done ||
+ iprefix_vals.getPosition(iprefix_idx) <
+ iwithprefixbefore_vals.getPosition(iwithprefixbefore_idx))) {
+ Prefix = iprefix_vals[iprefix_idx];
+ ++iprefix_idx;
+ iprefix_done = iprefix_idx == iprefix_vals.size();
+ } else if (!iwithprefix_done &&
+ (iwithprefixbefore_done ||
+ iwithprefix_vals.getPosition(iwithprefix_idx) <
+ iwithprefixbefore_vals.getPosition(iwithprefixbefore_idx))) {
+ Init.AddPath(Prefix+iwithprefix_vals[iwithprefix_idx],
+ InitHeaderSearch::System, false, false, false);
+ ++iwithprefix_idx;
+ iwithprefix_done = iwithprefix_idx == iwithprefix_vals.size();
+ } else {
+ Init.AddPath(Prefix+iwithprefixbefore_vals[iwithprefixbefore_idx],
+ InitHeaderSearch::Angled, false, false, false);
+ ++iwithprefixbefore_idx;
+ iwithprefixbefore_done =
+ iwithprefixbefore_idx == iwithprefixbefore_vals.size();
+ }
+ }
+ }
+
+ Init.AddDefaultEnvVarPaths(Lang);
+
+ // Add the clang headers, which are relative to the clang binary.
+ llvm::sys::Path MainExecutablePath =
+ llvm::sys::Path::GetMainExecutable(Argv0,
+ (void*)(intptr_t)InitializeIncludePaths);
+ if (!MainExecutablePath.isEmpty()) {
+ MainExecutablePath.eraseComponent(); // Remove /clang from foo/bin/clang
+ MainExecutablePath.eraseComponent(); // Remove /bin from foo/bin
+
+ // Get foo/lib/clang/<version>/include
+ MainExecutablePath.appendComponent("lib");
+ MainExecutablePath.appendComponent("clang");
+ MainExecutablePath.appendComponent(CLANG_VERSION_STRING);
+ MainExecutablePath.appendComponent("include");
+
+ // We pass true to ignore sysroot so that we *always* look for clang headers
+ // relative to our executable, never relative to -isysroot.
+ Init.AddPath(MainExecutablePath.c_str(), InitHeaderSearch::System,
+ false, false, false, true /*ignore sysroot*/);
+ }
+
+ if (!nostdinc)
+ Init.AddDefaultSystemIncludePaths(Lang);
+
+ // Now that we have collected all of the include paths, merge them all
+ // together and tell the preprocessor about them.
+
+ Init.Realize();
+}
+
+void InitializePreprocessorInitOptions(PreprocessorInitOptions &InitOpts)
+{
+ // Add macros from the command line.
+ unsigned d = 0, D = D_macros.size();
+ unsigned u = 0, U = U_macros.size();
+ while (d < D || u < U) {
+ if (u == U || (d < D && D_macros.getPosition(d) < U_macros.getPosition(u)))
+ InitOpts.addMacroDef(D_macros[d++]);
+ else
+ InitOpts.addMacroUndef(U_macros[u++]);
+ }
+
+ // If -imacros are specified, include them now. These are processed before
+ // any -include directives.
+ for (unsigned i = 0, e = ImplicitMacroIncludes.size(); i != e; ++i)
+ InitOpts.addMacroInclude(ImplicitMacroIncludes[i]);
+
+ if (!ImplicitIncludePTH.empty() || !ImplicitIncludes.empty() ||
+ (!ImplicitIncludePCH.empty() && ProgAction == PrintPreprocessedInput)) {
+ // We want to add these paths to the predefines buffer in order, make a
+ // temporary vector to sort by their occurrence.
+ llvm::SmallVector<std::pair<unsigned, std::string*>, 8> OrderedPaths;
+
+ if (!ImplicitIncludePTH.empty())
+ OrderedPaths.push_back(std::make_pair(ImplicitIncludePTH.getPosition(),
+ &ImplicitIncludePTH));
+ if (!ImplicitIncludePCH.empty() && ProgAction == PrintPreprocessedInput)
+ OrderedPaths.push_back(std::make_pair(ImplicitIncludePCH.getPosition(),
+ &ImplicitIncludePCH));
+ for (unsigned i = 0, e = ImplicitIncludes.size(); i != e; ++i)
+ OrderedPaths.push_back(std::make_pair(ImplicitIncludes.getPosition(i),
+ &ImplicitIncludes[i]));
+ llvm::array_pod_sort(OrderedPaths.begin(), OrderedPaths.end());
+
+
+ // Now that they are ordered by position, add to the predefines buffer.
+ for (unsigned i = 0, e = OrderedPaths.size(); i != e; ++i) {
+ std::string *Ptr = OrderedPaths[i].second;
+ if (!ImplicitIncludes.empty() &&
+ Ptr >= &ImplicitIncludes[0] &&
+ Ptr <= &ImplicitIncludes[ImplicitIncludes.size()-1]) {
+ InitOpts.addInclude(*Ptr, false);
+ } else if (Ptr == &ImplicitIncludePTH) {
+ InitOpts.addInclude(*Ptr, true);
+ } else {
+ // We end up here when we're producing preprocessed output and
+ // we loaded a PCH file. In this case, just include the header
+ // file that was used to build the precompiled header.
+ assert(Ptr == &ImplicitIncludePCH);
+ std::string OriginalFile = PCHReader::getOriginalSourceFile(*Ptr);
+ if (!OriginalFile.empty()) {
+ InitOpts.addInclude(OriginalFile, false);
+ ImplicitIncludePCH.clear();
+ }
+ }
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Driver PreprocessorFactory - For lazily generating preprocessors ...
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN DriverPreprocessorFactory : public PreprocessorFactory {
+ Diagnostic &Diags;
+ const LangOptions &LangInfo;
+ TargetInfo &Target;
+ SourceManager &SourceMgr;
+ HeaderSearch &HeaderInfo;
+
+public:
+ DriverPreprocessorFactory(Diagnostic &diags, const LangOptions &opts,
+ TargetInfo &target, SourceManager &SM,
+ HeaderSearch &Headers)
+ : Diags(diags), LangInfo(opts), Target(target),
+ SourceMgr(SM), HeaderInfo(Headers) {}
+
+
+ virtual ~DriverPreprocessorFactory() {}
+
+ virtual Preprocessor* CreatePreprocessor() {
+ llvm::OwningPtr<PTHManager> PTHMgr;
+
+ if (!TokenCache.empty() && !ImplicitIncludePTH.empty()) {
+ fprintf(stderr, "error: cannot use both -token-cache and -include-pth "
+ "options\n");
+ exit(1);
+ }
+
+ // Use PTH?
+ if (!TokenCache.empty() || !ImplicitIncludePTH.empty()) {
+ const std::string& x = TokenCache.empty() ? ImplicitIncludePTH:TokenCache;
+ PTHMgr.reset(PTHManager::Create(x, &Diags,
+ TokenCache.empty() ? Diagnostic::Error
+ : Diagnostic::Warning));
+ }
+
+ if (Diags.hasErrorOccurred())
+ exit(1);
+
+ // Create the Preprocessor.
+ llvm::OwningPtr<Preprocessor> PP(new Preprocessor(Diags, LangInfo, Target,
+ SourceMgr, HeaderInfo,
+ PTHMgr.get()));
+
+ // 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.get());
+ PP->setPTHManager(PTHMgr.take());
+ }
+
+ PreprocessorInitOptions InitOpts;
+ InitializePreprocessorInitOptions(InitOpts);
+ if (InitializePreprocessor(*PP, InitOpts))
+ return 0;
+
+ return PP.take();
+ }
+};
+}
+
+//===----------------------------------------------------------------------===//
+// Basic Parser driver
+//===----------------------------------------------------------------------===//
+
+static void ParseFile(Preprocessor &PP, MinimalAction *PA) {
+ Parser P(PP, *PA);
+ PP.EnterMainSourceFile();
+
+ // Parsing the specified input file.
+ P.ParseTranslationUnit();
+ delete PA;
+}
+
+//===----------------------------------------------------------------------===//
+// Code generation options
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<bool>
+GenerateDebugInfo("g",
+ llvm::cl::desc("Generate source level debug information"));
+
+static llvm::cl::opt<std::string>
+TargetCPU("mcpu",
+ llvm::cl::desc("Target a specific cpu type (-mcpu=help for details)"));
+
+static llvm::cl::list<std::string>
+TargetFeatures("target-feature", llvm::cl::desc("Target specific attributes"));
+
+/// ComputeTargetFeatures - Recompute the target feature list to only
+/// be the list of things that are enabled, based on the target cpu
+/// and feature list.
+static void ComputeFeatureMap(TargetInfo *Target,
+ llvm::StringMap<bool> &Features) {
+ assert(Features.empty() && "invalid map");
+
+ // Initialize the feature map based on the target.
+ Target->getDefaultFeatures(TargetCPU, Features);
+
+ // Apply the user specified deltas.
+ for (llvm::cl::list<std::string>::iterator it = TargetFeatures.begin(),
+ ie = TargetFeatures.end(); it != ie; ++it) {
+ const char *Name = it->c_str();
+
+ // FIXME: Don't handle errors like this.
+ if (Name[0] != '-' && Name[0] != '+') {
+ fprintf(stderr, "error: clang-cc: invalid target feature string: %s\n",
+ Name);
+ exit(1);
+ }
+ if (!Target->setFeatureEnabled(Features, Name + 1, (Name[0] == '+'))) {
+ fprintf(stderr, "error: clang-cc: invalid target feature name: %s\n",
+ Name + 1);
+ exit(1);
+ }
+ }
+}
+
+static void InitializeCompileOptions(CompileOptions &Opts,
+ const LangOptions &LangOpts,
+ const llvm::StringMap<bool> &Features) {
+ Opts.OptimizeSize = OptSize;
+ Opts.DebugInfo = GenerateDebugInfo;
+ if (OptSize) {
+ // -Os implies -O2
+ // FIXME: Diagnose conflicting options.
+ Opts.OptimizationLevel = 2;
+ } else {
+ Opts.OptimizationLevel = OptLevel;
+ }
+
+ // FIXME: There are llvm-gcc options to control these selectively.
+ Opts.InlineFunctions = (Opts.OptimizationLevel > 1);
+ Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !OptSize);
+ Opts.SimplifyLibCalls = !LangOpts.NoBuiltin;
+
+#ifdef NDEBUG
+ Opts.VerifyModule = 0;
+#endif
+
+ Opts.CPU = TargetCPU;
+ Opts.Features.clear();
+ for (llvm::StringMap<bool>::const_iterator it = Features.begin(),
+ ie = Features.end(); it != ie; ++it) {
+ // FIXME: If we are completely confident that we have the right
+ // set, we only need to pass the minuses.
+ std::string Name(it->second ? "+" : "-");
+ Name += it->first();
+ Opts.Features.push_back(Name);
+ }
+
+ Opts.NoCommon = NoCommon | LangOpts.CPlusPlus;
+
+ // Handle -ftime-report.
+ Opts.TimePasses = TimeReport;
+}
+
+//===----------------------------------------------------------------------===//
+// Fix-It Options
+//===----------------------------------------------------------------------===//
+static llvm::cl::list<ParsedSourceLocation>
+FixItAtLocations("fixit-at", llvm::cl::value_desc("source-location"),
+ llvm::cl::desc("Perform Fix-It modifications at the given source location"));
+
+//===----------------------------------------------------------------------===//
+// ObjC Rewriter Options
+//===----------------------------------------------------------------------===//
+static llvm::cl::opt<bool>
+SilenceRewriteMacroWarning("Wno-rewrite-macros", llvm::cl::init(false),
+ llvm::cl::desc("Silence ObjC rewriting warnings"));
+
+//===----------------------------------------------------------------------===//
+// Warning Options
+//===----------------------------------------------------------------------===//
+
+// This gets all -W options, including -Werror, -W[no-]system-headers, etc. The
+// driver has stripped off -Wa,foo etc. The driver has also translated -W to
+// -Wextra, so we don't need to worry about it.
+static llvm::cl::list<std::string>
+OptWarnings("W", llvm::cl::Prefix, llvm::cl::ValueOptional);
+
+static llvm::cl::opt<bool> OptPedantic("pedantic");
+static llvm::cl::opt<bool> OptPedanticErrors("pedantic-errors");
+static llvm::cl::opt<bool> OptNoWarnings("w");
+
+//===----------------------------------------------------------------------===//
+// Preprocessing (-E mode) Options
+//===----------------------------------------------------------------------===//
+static llvm::cl::opt<bool>
+DisableLineMarkers("P", llvm::cl::desc("Disable linemarker output in -E mode"));
+static llvm::cl::opt<bool>
+EnableCommentOutput("C", llvm::cl::desc("Enable comment output in -E mode"));
+static llvm::cl::opt<bool>
+EnableMacroCommentOutput("CC",
+ llvm::cl::desc("Enable comment output in -E mode, "
+ "even from macro expansions"));
+static llvm::cl::opt<bool>
+DumpMacros("dM", llvm::cl::desc("Print macro definitions in -E mode instead of"
+ " normal output"));
+static llvm::cl::opt<bool>
+DumpDefines("dD", llvm::cl::desc("Print macro definitions in -E mode in "
+ "addition to normal output"));
+
+//===----------------------------------------------------------------------===//
+// Dependency file options
+//===----------------------------------------------------------------------===//
+static llvm::cl::opt<std::string>
+DependencyFile("dependency-file",
+ llvm::cl::desc("Filename (or -) to write dependency output to"));
+
+static llvm::cl::opt<bool>
+DependenciesIncludeSystemHeaders("sys-header-deps",
+ llvm::cl::desc("Include system headers in dependency output"));
+
+static llvm::cl::list<std::string>
+DependencyTargets("MT",
+ llvm::cl::desc("Specify target for dependency"));
+
+// FIXME: Implement feature
+static llvm::cl::opt<bool>
+PhonyDependencyTarget("MP",
+ llvm::cl::desc("Create phony target for each dependency "
+ "(other than main file)"));
+
+//===----------------------------------------------------------------------===//
+// Analysis options
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::list<Analyses>
+AnalysisList(llvm::cl::desc("Source Code Analysis - Checks and Analyses"),
+llvm::cl::values(
+#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\
+clEnumValN(NAME, CMDFLAG, DESC),
+#include "clang/Frontend/Analyses.def"
+clEnumValEnd));
+
+static llvm::cl::opt<AnalysisStores>
+AnalysisStoreOpt("analyzer-store",
+ llvm::cl::desc("Source Code Analysis - Abstract Memory Store Models"),
+ llvm::cl::init(BasicStoreModel),
+ llvm::cl::values(
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN)\
+clEnumValN(NAME##Model, CMDFLAG, DESC),
+#include "clang/Frontend/Analyses.def"
+clEnumValEnd));
+
+static llvm::cl::opt<AnalysisConstraints>
+AnalysisConstraintsOpt("analyzer-constraints",
+ llvm::cl::desc("Source Code Analysis - Symbolic Constraint Engines"),
+ llvm::cl::init(RangeConstraintsModel),
+ llvm::cl::values(
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN)\
+clEnumValN(NAME##Model, CMDFLAG, DESC),
+#include "clang/Frontend/Analyses.def"
+clEnumValEnd));
+
+static llvm::cl::opt<AnalysisDiagClients>
+AnalysisDiagOpt("analyzer-output",
+ llvm::cl::desc("Source Code Analysis - Output Options"),
+ llvm::cl::init(PD_HTML),
+ llvm::cl::values(
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE)\
+clEnumValN(PD_##NAME, CMDFLAG, DESC),
+#include "clang/Frontend/Analyses.def"
+clEnumValEnd));
+
+static llvm::cl::opt<bool>
+VisualizeEGDot("analyzer-viz-egraph-graphviz",
+ llvm::cl::desc("Display exploded graph using GraphViz"));
+
+static llvm::cl::opt<bool>
+VisualizeEGUbi("analyzer-viz-egraph-ubigraph",
+ llvm::cl::desc("Display exploded graph using Ubigraph"));
+
+static llvm::cl::opt<bool>
+AnalyzeAll("analyzer-opt-analyze-headers",
+ llvm::cl::desc("Force the static analyzer to analyze "
+ "functions defined in header files"));
+
+static llvm::cl::opt<bool>
+AnalyzerDisplayProgress("analyzer-display-progress",
+ llvm::cl::desc("Emit verbose output about the analyzer's progress."));
+
+static llvm::cl::opt<bool>
+PurgeDead("analyzer-purge-dead",
+ llvm::cl::init(true),
+ llvm::cl::desc("Remove dead symbols, bindings, and constraints before"
+ " processing a statement."));
+
+static llvm::cl::opt<bool>
+EagerlyAssume("analyzer-eagerly-assume",
+ llvm::cl::init(false),
+ llvm::cl::desc("Eagerly assume the truth/falseness of some "
+ "symbolic constraints."));
+
+static llvm::cl::opt<std::string>
+AnalyzeSpecificFunction("analyze-function",
+ llvm::cl::desc("Run analysis on specific function"));
+
+static llvm::cl::opt<bool>
+TrimGraph("trim-egraph",
+ llvm::cl::desc("Only show error-related paths in the analysis graph"));
+
+static AnalyzerOptions ReadAnalyzerOptions() {
+ AnalyzerOptions Opts;
+ Opts.AnalysisList = AnalysisList;
+ Opts.AnalysisStoreOpt = AnalysisStoreOpt;
+ Opts.AnalysisConstraintsOpt = AnalysisConstraintsOpt;
+ Opts.AnalysisDiagOpt = AnalysisDiagOpt;
+ Opts.VisualizeEGDot = VisualizeEGDot;
+ Opts.VisualizeEGUbi = VisualizeEGUbi;
+ Opts.AnalyzeAll = AnalyzeAll;
+ Opts.AnalyzerDisplayProgress = AnalyzerDisplayProgress;
+ Opts.PurgeDead = PurgeDead;
+ Opts.EagerlyAssume = EagerlyAssume;
+ Opts.AnalyzeSpecificFunction = AnalyzeSpecificFunction;
+ Opts.TrimGraph = TrimGraph;
+ return Opts;
+}
+
+//===----------------------------------------------------------------------===//
+// -dump-build-information Stuff
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<std::string>
+DumpBuildInformation("dump-build-information",
+ llvm::cl::value_desc("filename"),
+ llvm::cl::desc("output a dump of some build information to a file"));
+
+static llvm::raw_ostream *BuildLogFile = 0;
+
+/// LoggingDiagnosticClient - This is a simple diagnostic client that forwards
+/// all diagnostics to both BuildLogFile and a chained DiagnosticClient.
+namespace {
+class LoggingDiagnosticClient : public DiagnosticClient {
+ llvm::OwningPtr<DiagnosticClient> Chain1;
+ llvm::OwningPtr<DiagnosticClient> Chain2;
+public:
+
+ LoggingDiagnosticClient(DiagnosticClient *Normal) {
+ // Output diags both where requested...
+ Chain1.reset(Normal);
+ // .. and to our log file.
+ Chain2.reset(new TextDiagnosticPrinter(*BuildLogFile,
+ !NoShowColumn,
+ !NoCaretDiagnostics,
+ !NoShowLocation,
+ PrintSourceRangeInfo,
+ PrintDiagnosticOption,
+ !NoDiagnosticsFixIt,
+ MessageLength));
+ }
+
+ virtual void setLangOptions(const LangOptions *LO) {
+ Chain1->setLangOptions(LO);
+ Chain2->setLangOptions(LO);
+ }
+
+ virtual bool IncludeInDiagnosticCounts() const {
+ return Chain1->IncludeInDiagnosticCounts();
+ }
+
+ virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info) {
+ Chain1->HandleDiagnostic(DiagLevel, Info);
+ Chain2->HandleDiagnostic(DiagLevel, Info);
+ }
+};
+} // end anonymous namespace.
+
+static void SetUpBuildDumpLog(unsigned argc, char **argv,
+ llvm::OwningPtr<DiagnosticClient> &DiagClient) {
+
+ std::string ErrorInfo;
+ BuildLogFile = new llvm::raw_fd_ostream(DumpBuildInformation.c_str(), false,
+ ErrorInfo);
+
+ if (!ErrorInfo.empty()) {
+ llvm::errs() << "error opening -dump-build-information file '"
+ << DumpBuildInformation << "', option ignored!\n";
+ delete BuildLogFile;
+ BuildLogFile = 0;
+ DumpBuildInformation = "";
+ return;
+ }
+
+ (*BuildLogFile) << "clang-cc command line arguments: ";
+ for (unsigned i = 0; i != argc; ++i)
+ (*BuildLogFile) << argv[i] << ' ';
+ (*BuildLogFile) << '\n';
+
+ // LoggingDiagnosticClient - Insert a new logging diagnostic client in between
+ // the diagnostic producers and the normal receiver.
+ DiagClient.reset(new LoggingDiagnosticClient(DiagClient.take()));
+}
+
+
+
+//===----------------------------------------------------------------------===//
+// Main driver
+//===----------------------------------------------------------------------===//
+
+static llvm::raw_ostream* ComputeOutFile(const std::string& InFile,
+ const char* Extension,
+ bool Binary,
+ llvm::sys::Path& OutPath) {
+ llvm::raw_ostream* Ret;
+ bool UseStdout = false;
+ std::string OutFile;
+ if (OutputFile == "-" || (OutputFile.empty() && InFile == "-")) {
+ UseStdout = true;
+ } else if (!OutputFile.empty()) {
+ OutFile = OutputFile;
+ } else if (Extension) {
+ llvm::sys::Path Path(InFile);
+ Path.eraseSuffix();
+ Path.appendSuffix(Extension);
+ OutFile = Path.toString();
+ } else {
+ UseStdout = true;
+ }
+
+ if (UseStdout) {
+ Ret = new llvm::raw_stdout_ostream();
+ if (Binary)
+ llvm::sys::Program::ChangeStdoutToBinary();
+ } else {
+ std::string Error;
+ Ret = new llvm::raw_fd_ostream(OutFile.c_str(), Binary, Error);
+ if (!Error.empty()) {
+ // FIXME: Don't fail this way.
+ llvm::cerr << "ERROR: " << Error << "\n";
+ ::exit(1);
+ }
+ OutPath = OutFile;
+ }
+
+ return Ret;
+}
+
+/// ProcessInputFile - Process a single input file with the specified state.
+///
+static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
+ const std::string &InFile, ProgActions PA,
+ const llvm::StringMap<bool> &Features) {
+ llvm::OwningPtr<llvm::raw_ostream> OS;
+ llvm::OwningPtr<ASTConsumer> Consumer;
+ bool ClearSourceMgr = false;
+ FixItRewriter *FixItRewrite = 0;
+ bool CompleteTranslationUnit = true;
+ llvm::sys::Path OutPath;
+
+ switch (PA) {
+ default:
+ fprintf(stderr, "Unexpected program action!\n");
+ HadErrors = true;
+ return;
+
+ case ASTPrint:
+ OS.reset(ComputeOutFile(InFile, 0, false, OutPath));
+ Consumer.reset(CreateASTPrinter(OS.get()));
+ break;
+
+ case ASTPrintXML:
+ OS.reset(ComputeOutFile(InFile, "xml", false, OutPath));
+ Consumer.reset(CreateASTPrinterXML(OS.get()));
+ break;
+
+ case ASTDump:
+ Consumer.reset(CreateASTDumper());
+ break;
+
+ case ASTView:
+ Consumer.reset(CreateASTViewer());
+ break;
+
+ case PrintDeclContext:
+ Consumer.reset(CreateDeclContextPrinter());
+ break;
+
+ case EmitHTML:
+ OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
+ Consumer.reset(CreateHTMLPrinter(OS.get(), PP.getDiagnostics(), &PP, &PPF));
+ break;
+
+ case InheritanceView:
+ Consumer.reset(CreateInheritanceViewer(InheritanceViewCls));
+ break;
+
+ case EmitAssembly:
+ case EmitLLVM:
+ case EmitBC:
+ case EmitLLVMOnly: {
+ BackendAction Act;
+ if (ProgAction == EmitAssembly) {
+ Act = Backend_EmitAssembly;
+ OS.reset(ComputeOutFile(InFile, "s", true, OutPath));
+ } else if (ProgAction == EmitLLVM) {
+ Act = Backend_EmitLL;
+ OS.reset(ComputeOutFile(InFile, "ll", true, OutPath));
+ } else if (ProgAction == EmitLLVMOnly) {
+ Act = Backend_EmitNothing;
+ } else {
+ Act = Backend_EmitBC;
+ OS.reset(ComputeOutFile(InFile, "bc", true, OutPath));
+ }
+
+ CompileOptions Opts;
+ InitializeCompileOptions(Opts, PP.getLangOptions(), Features);
+ Consumer.reset(CreateBackendConsumer(Act, PP.getDiagnostics(),
+ PP.getLangOptions(), Opts, InFile,
+ OS.get()));
+ break;
+ }
+
+ case GeneratePCH:
+ OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
+ Consumer.reset(CreatePCHGenerator(PP, OS.get()));
+ CompleteTranslationUnit = false;
+ break;
+
+ case RewriteObjC:
+ OS.reset(ComputeOutFile(InFile, "cpp", true, OutPath));
+ Consumer.reset(CreateObjCRewriter(InFile, OS.get(), PP.getDiagnostics(),
+ PP.getLangOptions(),
+ SilenceRewriteMacroWarning));
+ break;
+
+ case RewriteBlocks:
+ Consumer.reset(CreateBlockRewriter(InFile, PP.getDiagnostics(),
+ PP.getLangOptions()));
+ break;
+
+ case RunAnalysis: {
+ Consumer.reset(CreateAnalysisConsumer(PP.getDiagnostics(), &PP, &PPF,
+ PP.getLangOptions(), OutputFile,
+ ReadAnalyzerOptions()));
+ break;
+ }
+
+ case DumpRawTokens: {
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ SourceManager &SM = PP.getSourceManager();
+ // Start lexing the specified input file.
+ Lexer RawLex(SM.getMainFileID(), SM, PP.getLangOptions());
+ RawLex.SetKeepWhitespaceMode(true);
+
+ Token RawTok;
+ RawLex.LexFromRawLexer(RawTok);
+ while (RawTok.isNot(tok::eof)) {
+ PP.DumpToken(RawTok, true);
+ fprintf(stderr, "\n");
+ RawLex.LexFromRawLexer(RawTok);
+ }
+ ClearSourceMgr = true;
+ break;
+ }
+ case DumpTokens: { // Token dump mode.
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ Token Tok;
+ // Start preprocessing the specified input file.
+ PP.EnterMainSourceFile();
+ do {
+ PP.Lex(Tok);
+ PP.DumpToken(Tok, true);
+ fprintf(stderr, "\n");
+ } while (Tok.isNot(tok::eof));
+ ClearSourceMgr = true;
+ break;
+ }
+ case RunPreprocessorOnly:
+ break;
+
+ case GeneratePTH: {
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ if (OutputFile.empty() || OutputFile == "-") {
+ // FIXME: Don't fail this way.
+ // FIXME: Verify that we can actually seek in the given file.
+ llvm::cerr << "ERROR: PTH requires an seekable file for output!\n";
+ ::exit(1);
+ }
+ OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
+ CacheTokens(PP, static_cast<llvm::raw_fd_ostream*>(OS.get()));
+ ClearSourceMgr = true;
+ break;
+ }
+
+ case PrintPreprocessedInput:
+ OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
+ break;
+
+ case ParseNoop:
+ break;
+
+ case ParsePrintCallbacks: {
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
+ ParseFile(PP, CreatePrintParserActionsAction(PP, OS.get()));
+ ClearSourceMgr = true;
+ break;
+ }
+
+ case ParseSyntaxOnly: { // -fsyntax-only
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ Consumer.reset(new ASTConsumer());
+ break;
+ }
+
+ case RewriteMacros:
+ OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
+ RewriteMacrosInInput(PP, OS.get());
+ ClearSourceMgr = true;
+ break;
+
+ case RewriteTest:
+ OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
+ DoRewriteTest(PP, OS.get());
+ ClearSourceMgr = true;
+ break;
+
+ case FixIt:
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ Consumer.reset(new ASTConsumer());
+ FixItRewrite = new FixItRewriter(PP.getDiagnostics(),
+ PP.getSourceManager(),
+ PP.getLangOptions());
+ break;
+ }
+
+ if (FixItAtLocations.size() > 0) {
+ // Even without the "-fixit" flag, with may have some specific
+ // locations where the user has requested fixes. Process those
+ // locations now.
+ if (!FixItRewrite)
+ FixItRewrite = new FixItRewriter(PP.getDiagnostics(),
+ PP.getSourceManager(),
+ PP.getLangOptions());
+
+ bool AddedFixitLocation = false;
+ for (unsigned Idx = 0, Last = FixItAtLocations.size();
+ Idx != Last; ++Idx) {
+ RequestedSourceLocation Requested;
+ if (FixItAtLocations[Idx].ResolveLocation(PP.getFileManager(),
+ Requested)) {
+ fprintf(stderr, "FIX-IT could not find file \"%s\"\n",
+ FixItAtLocations[Idx].FileName.c_str());
+ } else {
+ FixItRewrite->addFixItLocation(Requested);
+ AddedFixitLocation = true;
+ }
+ }
+
+ if (!AddedFixitLocation) {
+ // All of the fix-it locations were bad. Don't fix anything.
+ delete FixItRewrite;
+ FixItRewrite = 0;
+ }
+ }
+
+ llvm::OwningPtr<ASTContext> ContextOwner;
+ if (Consumer)
+ ContextOwner.reset(new ASTContext(PP.getLangOptions(),
+ PP.getSourceManager(),
+ PP.getTargetInfo(),
+ PP.getIdentifierTable(),
+ PP.getSelectorTable(),
+ /* FreeMemory = */ !DisableFree,
+ /* size_reserve = */0,
+ /* InitializeBuiltins = */ImplicitIncludePCH.empty()));
+ llvm::OwningPtr<PCHReader> Reader;
+ llvm::OwningPtr<ExternalASTSource> Source;
+
+ if (!ImplicitIncludePCH.empty()) {
+ Reader.reset(new PCHReader(PP, ContextOwner.get()));
+
+ // The user has asked us to include a precompiled header. Load
+ // the precompiled header into the AST context.
+ switch (Reader->ReadPCH(ImplicitIncludePCH)) {
+ case PCHReader::Success: {
+ // Set the predefines buffer as suggested by the PCH
+ // reader. Typically, the predefines buffer will be empty.
+ PP.setPredefines(Reader->getSuggestedPredefines());
+
+ // Attach the PCH reader to the AST context as an external AST
+ // source, so that declarations will be deserialized from the
+ // PCH file as needed.
+ if (ContextOwner) {
+ Source.reset(Reader.take());
+ ContextOwner->setExternalSource(Source);
+ }
+ break;
+ }
+
+ case PCHReader::Failure:
+ // Unrecoverable failure: don't even try to process the input
+ // file.
+ return;
+
+ case PCHReader::IgnorePCH:
+ // No suitable PCH file could be found. Return an error.
+ return;
+
+#if 0
+ // FIXME: We can recover from failed attempts to load PCH
+ // files. This code will do so, if we ever want to enable it.
+
+ // We delayed the initialization of builtins in the hope of
+ // loading the PCH file. Since the PCH file could not be
+ // loaded, initialize builtins now.
+ if (ContextOwner)
+ ContextOwner->InitializeBuiltins(PP.getIdentifierTable());
+#endif
+ }
+
+ // Finish preprocessor initialization. We do this now (rather
+ // than earlier) because this initialization creates new source
+ // location entries in the source manager, which must come after
+ // the source location entries for the PCH file.
+ if (InitializeSourceManager(PP, InFile))
+ return;
+ }
+
+
+ // If we have an ASTConsumer, run the parser with it.
+ if (Consumer)
+ ParseAST(PP, Consumer.get(), *ContextOwner.get(), Stats,
+ CompleteTranslationUnit);
+
+ if (PA == RunPreprocessorOnly) { // Just lex as fast as we can, no output.
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ Token Tok;
+ // Start parsing the specified input file.
+ PP.EnterMainSourceFile();
+ do {
+ PP.Lex(Tok);
+ } while (Tok.isNot(tok::eof));
+ ClearSourceMgr = true;
+ } else if (PA == ParseNoop) { // -parse-noop
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ ParseFile(PP, new MinimalAction(PP));
+ ClearSourceMgr = true;
+ } else if (PA == PrintPreprocessedInput){ // -E mode.
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ if (DumpMacros)
+ DoPrintMacros(PP, OS.get());
+ else
+ DoPrintPreprocessedInput(PP, OS.get(), EnableCommentOutput,
+ EnableMacroCommentOutput,
+ DisableLineMarkers, DumpDefines);
+ ClearSourceMgr = true;
+ }
+
+ if (FixItRewrite)
+ FixItRewrite->WriteFixedFile(InFile, OutputFile);
+
+ // If in -disable-free mode, don't deallocate ASTContext.
+ if (DisableFree)
+ ContextOwner.take();
+ else
+ ContextOwner.reset(); // Delete ASTContext
+
+ if (VerifyDiagnostics)
+ if (CheckDiagnostics(PP))
+ exit(1);
+
+ if (Stats) {
+ fprintf(stderr, "\nSTATISTICS FOR '%s':\n", InFile.c_str());
+ PP.PrintStats();
+ PP.getIdentifierTable().PrintStats();
+ PP.getHeaderSearchInfo().PrintStats();
+ PP.getSourceManager().PrintStats();
+ fprintf(stderr, "\n");
+ }
+
+ // For a multi-file compilation, some things are ok with nuking the source
+ // manager tables, other require stable fileid/macroid's across multiple
+ // files.
+ if (ClearSourceMgr)
+ PP.getSourceManager().clearIDTables();
+
+ if (DisableFree)
+ Consumer.take();
+ else
+ Consumer.reset();
+
+ // Always delete the output stream because we don't want to leak file
+ // handles. Also, we don't want to try to erase an open file.
+ OS.reset();
+
+ if ((HadErrors || (PP.getDiagnostics().getNumErrors() != 0)) &&
+ !OutPath.isEmpty()) {
+ // If we had errors, try to erase the output file.
+ OutPath.eraseFromDisk();
+ }
+}
+
+static llvm::cl::list<std::string>
+InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input files>"));
+
+int main(int argc, char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal();
+ llvm::PrettyStackTraceProgram X(argc, argv);
+ llvm::cl::ParseCommandLineOptions(argc, argv,
+ "LLVM 'Clang' Compiler: http://clang.llvm.org\n");
+
+ if (TimeReport)
+ ClangFrontendTimer = new llvm::Timer("Clang front-end time");
+
+ if (Verbose)
+ fprintf(stderr, "clang-cc version 1.0 based upon " PACKAGE_STRING
+ " hosted on " LLVM_HOSTTRIPLE "\n");
+
+ // If no input was specified, read from stdin.
+ if (InputFilenames.empty())
+ InputFilenames.push_back("-");
+
+ // Create the diagnostic client for reporting errors or for
+ // implementing -verify.
+ llvm::OwningPtr<DiagnosticClient> DiagClient;
+ if (VerifyDiagnostics) {
+ // When checking diagnostics, just buffer them up.
+ DiagClient.reset(new TextDiagnosticBuffer());
+ if (InputFilenames.size() != 1) {
+ fprintf(stderr, "-verify only works on single input files for now.\n");
+ return 1;
+ }
+ if (!HTMLDiag.empty()) {
+ fprintf(stderr, "-verify and -html-diags don't work together\n");
+ return 1;
+ }
+ } else if (HTMLDiag.empty()) {
+ // Print diagnostics to stderr by default.
+
+ // If -fmessage-length=N was not specified, determine whether this
+ // is a terminal and, if so, implicitly define -fmessage-length
+ // appropriately.
+ if (MessageLength.getNumOccurrences() == 0)
+ MessageLength.setValue(llvm::sys::Process::StandardErrColumns());
+
+ DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(),
+ !NoShowColumn,
+ !NoCaretDiagnostics,
+ !NoShowLocation,
+ PrintSourceRangeInfo,
+ PrintDiagnosticOption,
+ !NoDiagnosticsFixIt,
+ MessageLength));
+ } else {
+ DiagClient.reset(CreateHTMLDiagnosticClient(HTMLDiag));
+ }
+
+ if (!DumpBuildInformation.empty()) {
+ if (!HTMLDiag.empty()) {
+ fprintf(stderr,
+ "-dump-build-information and -html-diags don't work together\n");
+ return 1;
+ }
+
+ SetUpBuildDumpLog(argc, argv, DiagClient);
+ }
+
+
+ // Configure our handling of diagnostics.
+ Diagnostic Diags(DiagClient.get());
+ if (ProcessWarningOptions(Diags, OptWarnings, OptPedantic, OptPedanticErrors,
+ OptNoWarnings))
+ return 1;
+
+ // -I- is a deprecated GCC feature, scan for it and reject it.
+ for (unsigned i = 0, e = I_dirs.size(); i != e; ++i) {
+ if (I_dirs[i] == "-") {
+ Diags.Report(FullSourceLoc(), diag::err_pp_I_dash_not_supported);
+ I_dirs.erase(I_dirs.begin()+i);
+ --i;
+ }
+ }
+
+ // Get information about the target being compiled for.
+ std::string Triple = CreateTargetTriple();
+ llvm::OwningPtr<TargetInfo> Target(TargetInfo::CreateTargetInfo(Triple));
+
+ if (Target == 0) {
+ Diags.Report(FullSourceLoc(), diag::err_fe_unknown_triple)
+ << Triple.c_str();
+ return 1;
+ }
+
+ if (!InheritanceViewCls.empty()) // C++ visualization?
+ ProgAction = InheritanceView;
+
+ llvm::OwningPtr<SourceManager> SourceMgr;
+
+ // Create a file manager object to provide access to and cache the filesystem.
+ FileManager FileMgr;
+
+ // Compute the feature set, unfortunately this effects the language!
+ llvm::StringMap<bool> Features;
+ ComputeFeatureMap(Target.get(), Features);
+
+ for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
+ const std::string &InFile = InputFilenames[i];
+
+ /// Create a SourceManager object. This tracks and owns all the file
+ /// buffers allocated to a translation unit.
+ if (!SourceMgr)
+ SourceMgr.reset(new SourceManager());
+ else
+ SourceMgr->clearIDTables();
+
+ // Initialize language options, inferring file types from input filenames.
+ LangOptions LangInfo;
+ DiagClient->setLangOptions(&LangInfo);
+
+ InitializeBaseLanguage();
+ LangKind LK = GetLanguage(InFile);
+ InitializeLangOptions(LangInfo, LK);
+ InitializeLanguageStandard(LangInfo, LK, Target.get(), Features);
+
+ // Process the -I options and set them in the HeaderInfo.
+ HeaderSearch HeaderInfo(FileMgr);
+
+
+ InitializeIncludePaths(argv[0], HeaderInfo, FileMgr, LangInfo);
+
+ // Set up the preprocessor with these options.
+ DriverPreprocessorFactory PPFactory(Diags, LangInfo, *Target,
+ *SourceMgr.get(), HeaderInfo);
+
+ llvm::OwningPtr<Preprocessor> PP(PPFactory.CreatePreprocessor());
+
+ if (!PP)
+ continue;
+
+ // Handle generating dependencies, if requested
+ if (!DependencyFile.empty()) {
+ llvm::raw_ostream *DependencyOS;
+ if (DependencyTargets.empty()) {
+ // FIXME: Use a proper diagnostic
+ llvm::cerr << "-dependency-file requires at least one -MT option\n";
+ HadErrors = true;
+ continue;
+ }
+ std::string ErrStr;
+ DependencyOS =
+ new llvm::raw_fd_ostream(DependencyFile.c_str(), false, ErrStr);
+ if (!ErrStr.empty()) {
+ // FIXME: Use a proper diagnostic
+ llvm::cerr << "unable to open dependency file: " + ErrStr;
+ HadErrors = true;
+ continue;
+ }
+
+ AttachDependencyFileGen(PP.get(), DependencyOS, DependencyTargets,
+ DependenciesIncludeSystemHeaders,
+ PhonyDependencyTarget);
+ }
+
+ if (ImplicitIncludePCH.empty() &&
+ InitializeSourceManager(*PP.get(), InFile))
+ continue;
+
+ if (!HTMLDiag.empty())
+ ((PathDiagnosticClient*)DiagClient.get())->SetPreprocessor(PP.get());
+
+ // Process the source file.
+ ProcessInputFile(*PP, PPFactory, InFile, ProgAction, Features);
+
+ HeaderInfo.ClearFileInfo();
+ DiagClient->setLangOptions(0);
+ }
+
+ if (!NoCaretDiagnostics)
+ if (unsigned NumDiagnostics = Diags.getNumDiagnostics())
+ fprintf(stderr, "%d diagnostic%s generated.\n", NumDiagnostics,
+ (NumDiagnostics == 1 ? "" : "s"));
+
+ if (Stats) {
+ FileMgr.PrintStats();
+ fprintf(stderr, "\n");
+ }
+
+ delete ClangFrontendTimer;
+ delete BuildLogFile;
+
+ // If verifying diagnostics and we reached here, all is well.
+ if (VerifyDiagnostics)
+ return 0;
+
+ // Managed static deconstruction. Useful for making things like
+ // -time-passes usable.
+ llvm::llvm_shutdown();
+
+ return HadErrors || (Diags.getNumErrors() != 0);
+}
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
new file mode 100644
index 000000000000..fc7464afe052
--- /dev/null
+++ b/tools/driver/CMakeLists.txt
@@ -0,0 +1,12 @@
+set(LLVM_NO_RTTI 1)
+
+set( LLVM_USED_LIBS
+ clangDriver
+ clangBasic
+ )
+
+set(LLVM_LINK_COMPONENTS system support bitreader bitwriter)
+
+add_clang_executable(clang
+ driver.cpp
+ )
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
new file mode 100644
index 000000000000..8e9c291cc80c
--- /dev/null
+++ b/tools/driver/Makefile
@@ -0,0 +1,23 @@
+##===- 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.
+#
+##===----------------------------------------------------------------------===##
+LEVEL = ../../../..
+
+TOOLNAME = clang
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CXXFLAGS = -fno-rtti
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+# FIXME: It is unfortunate we need to pull in the bitcode reader and
+# writer just to get the serializer stuff used by clangBasic.
+LINK_COMPONENTS := system support bitreader bitwriter
+USEDLIBS = clangDriver.a clangBasic.a
+
+include $(LEVEL)/Makefile.common
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
new file mode 100644
index 000000000000..804bef4058c9
--- /dev/null
+++ b/tools/driver/driver.cpp
@@ -0,0 +1,228 @@
+//===-- driver.cpp - Clang GCC-Compatible Driver --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the entry point to the clang driver; it is a thin wrapper
+// for functionality in the Driver clang library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Option.h"
+#include "clang/Driver/Options.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Host.h"
+#include "llvm/System/Path.h"
+#include "llvm/System/Signals.h"
+using namespace clang;
+using namespace clang::driver;
+
+class DriverDiagnosticPrinter : public DiagnosticClient {
+ std::string ProgName;
+ llvm::raw_ostream &OS;
+
+public:
+ DriverDiagnosticPrinter(const std::string _ProgName,
+ llvm::raw_ostream &_OS)
+ : ProgName(_ProgName),
+ OS(_OS) {}
+
+ virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info);
+};
+
+void DriverDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
+ const DiagnosticInfo &Info) {
+ OS << ProgName << ": ";
+
+ 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;
+ }
+
+ llvm::SmallString<100> OutStr;
+ Info.FormatDiagnostic(OutStr);
+ OS.write(OutStr.begin(), OutStr.size());
+ OS << '\n';
+}
+
+llvm::sys::Path GetExecutablePath(const char *Argv0) {
+ // This just needs to be some symbol in the binary; C++ doesn't
+ // allow taking the address of ::main however.
+ void *P = (void*) (intptr_t) GetExecutablePath;
+ return llvm::sys::Path::GetMainExecutable(Argv0, P);
+}
+
+static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
+ const std::string &S) {
+ return SavedStrings.insert(S).first->c_str();
+}
+
+/// ApplyQAOverride - Apply a list of edits to the input argument lists.
+///
+/// The input string is a space separate list of edits to perform,
+/// they are applied in order to the input argument lists. Edits
+/// should be one of the following forms:
+///
+/// '^': Add FOO as a new argument at the beginning of the command line.
+///
+/// '+': Add FOO as a new argument at the end of the command line.
+///
+/// 's/XXX/YYY/': Replace the literal argument XXX by YYY in the
+/// command line.
+///
+/// 'xOPTION': Removes all instances of the literal argument OPTION.
+///
+/// 'XOPTION': Removes all instances of the literal argument OPTION,
+/// and the following argument.
+///
+/// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
+/// at the end of the command line.
+void ApplyOneQAOverride(std::vector<const char*> &Args,
+ const std::string &Edit,
+ std::set<std::string> &SavedStrings) {
+ // This does not need to be efficient.
+
+ if (Edit[0] == '^') {
+ const char *Str =
+ SaveStringInSet(SavedStrings, Edit.substr(1, std::string::npos));
+ llvm::errs() << "### Adding argument " << Str << " at beginning\n";
+ Args.insert(Args.begin() + 1, Str);
+ } else if (Edit[0] == '+') {
+ const char *Str =
+ SaveStringInSet(SavedStrings, Edit.substr(1, std::string::npos));
+ llvm::errs() << "### Adding argument " << Str << " at end\n";
+ Args.push_back(Str);
+ } else if (Edit[0] == 'x' || Edit[0] == 'X') {
+ std::string Option = Edit.substr(1, std::string::npos);
+ for (unsigned i = 1; i < Args.size();) {
+ if (Option == Args[i]) {
+ llvm::errs() << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ if (Edit[0] == 'X') {
+ if (i < Args.size()) {
+ llvm::errs() << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ } else
+ llvm::errs() << "### Invalid X edit, end of command line!\n";
+ }
+ } else
+ ++i;
+ }
+ } else if (Edit[0] == 'O') {
+ for (unsigned i = 1; i < Args.size();) {
+ const char *A = Args[i];
+ if (A[0] == '-' && A[1] == 'O' &&
+ (A[2] == '\0' ||
+ (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
+ ('0' <= A[2] && A[2] <= '9'))))) {
+ llvm::errs() << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ } else
+ ++i;
+ }
+ llvm::errs() << "### Adding argument " << Edit << " at end\n";
+ Args.push_back(SaveStringInSet(SavedStrings, '-' + Edit));
+ } else {
+ llvm::errs() << "### Unrecognized edit: " << Edit << "\n";
+ }
+}
+
+/// ApplyQAOverride - Apply a comma separate list of edits to the
+/// input argument lists. See ApplyOneQAOverride.
+void ApplyQAOverride(std::vector<const char*> &Args, const char *OverrideStr,
+ std::set<std::string> &SavedStrings) {
+ llvm::errs() << "### QA_OVERRIDE_GCC3_OPTIONS: " << OverrideStr << "\n";
+
+ // This does not need to be efficient.
+
+ const char *S = OverrideStr;
+ while (*S) {
+ const char *End = ::strchr(S, ' ');
+ if (!End)
+ End = S + strlen(S);
+ if (End != S)
+ ApplyOneQAOverride(Args, std::string(S, End), SavedStrings);
+ S = End;
+ if (*S != '\0')
+ ++S;
+ }
+}
+
+int main(int argc, const char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal();
+ llvm::PrettyStackTraceProgram X(argc, argv);
+
+ llvm::sys::Path Path = GetExecutablePath(argv[0]);
+ DriverDiagnosticPrinter DiagClient(Path.getBasename(), llvm::errs());
+
+ Diagnostic Diags(&DiagClient);
+
+ Driver TheDriver(Path.getBasename().c_str(), Path.getDirname().c_str(),
+ llvm::sys::getHostTriple().c_str(),
+ "a.out", Diags);
+
+ llvm::OwningPtr<Compilation> C;
+
+ // Handle QA_OVERRIDE_GCC3_OPTIONS and CCC_ADD_ARGS, used for editing a
+ // command line behind the scenes.
+ std::set<std::string> SavedStrings;
+ if (const char *OverrideStr = ::getenv("QA_OVERRIDE_GCC3_OPTIONS")) {
+ // FIXME: Driver shouldn't take extra initial argument.
+ std::vector<const char*> StringPointers(argv, argv + argc);
+
+ ApplyQAOverride(StringPointers, OverrideStr, SavedStrings);
+
+ C.reset(TheDriver.BuildCompilation(StringPointers.size(),
+ &StringPointers[0]));
+ } else if (const char *Cur = ::getenv("CCC_ADD_ARGS")) {
+ std::vector<const char*> StringPointers;
+
+ // FIXME: Driver shouldn't take extra initial argument.
+ StringPointers.push_back(argv[0]);
+
+ for (;;) {
+ const char *Next = strchr(Cur, ',');
+
+ if (Next) {
+ StringPointers.push_back(SaveStringInSet(SavedStrings,
+ std::string(Cur, Next)));
+ Cur = Next + 1;
+ } else {
+ if (*Cur != '\0')
+ StringPointers.push_back(SaveStringInSet(SavedStrings, Cur));
+ break;
+ }
+ }
+
+ StringPointers.insert(StringPointers.end(), argv + 1, argv + argc);
+
+ C.reset(TheDriver.BuildCompilation(StringPointers.size(),
+ &StringPointers[0]));
+ } else
+ C.reset(TheDriver.BuildCompilation(argc, argv));
+
+ int Res = 0;
+ if (C.get())
+ Res = C->Execute();
+
+ llvm::llvm_shutdown();
+
+ return Res;
+}
+
diff --git a/tools/scan-view/Reporter.py b/tools/scan-view/Reporter.py
new file mode 100644
index 000000000000..9560fc1aabbb
--- /dev/null
+++ b/tools/scan-view/Reporter.py
@@ -0,0 +1,248 @@
+"""Methods for reporting bugs."""
+
+import subprocess, sys, os
+
+__all__ = ['ReportFailure', 'BugReport', 'getReporters']
+
+#
+
+class ReportFailure(Exception):
+ """Generic exception for failures in bug reporting."""
+ def __init__(self, value):
+ self.value = value
+
+# Collect information about a bug.
+
+class BugReport:
+ def __init__(self, title, description, files):
+ self.title = title
+ self.description = description
+ self.files = files
+
+# Reporter interfaces.
+
+import os
+
+import email, mimetypes, smtplib
+from email import encoders
+from email.message import Message
+from email.mime.base import MIMEBase
+from email.mime.multipart import MIMEMultipart
+from email.mime.text import MIMEText
+
+#===------------------------------------------------------------------------===#
+# ReporterParameter
+#===------------------------------------------------------------------------===#
+
+class ReporterParameter:
+ def __init__(self, n):
+ self.name = n
+ def getName(self):
+ return self.name
+ def getValue(self,r,bugtype,getConfigOption):
+ return getConfigOption(r.getName(),self.getName())
+ def saveConfigValue(self):
+ return True
+
+class TextParameter (ReporterParameter):
+ def getHTML(self,r,bugtype,getConfigOption):
+ return """\
+<tr>
+<td class="form_clabel">%s:</td>
+<td class="form_value"><input type="text" name="%s_%s" value="%s"></td>
+</tr>"""%(self.getName(),r.getName(),self.getName(),self.getValue(r,bugtype,getConfigOption))
+
+class SelectionParameter (ReporterParameter):
+ def __init__(self, n, values):
+ ReporterParameter.__init__(self,n)
+ self.values = values
+
+ def getHTML(self,r,bugtype,getConfigOption):
+ default = self.getValue(r,bugtype,getConfigOption)
+ return """\
+<tr>
+<td class="form_clabel">%s:</td><td class="form_value"><select name="%s_%s">
+%s
+</select></td>"""%(self.getName(),r.getName(),self.getName(),'\n'.join(["""\
+<option value="%s"%s>%s</option>"""%(o[0],
+ o[0] == default and ' selected="selected"' or '',
+ o[1]) for o in self.values]))
+
+#===------------------------------------------------------------------------===#
+# Reporters
+#===------------------------------------------------------------------------===#
+
+class EmailReporter:
+ def getName(self):
+ return 'Email'
+
+ def getParameters(self):
+ return map(lambda x:TextParameter(x),['To', 'From', 'SMTP Server', 'SMTP Port'])
+
+ # Lifted from python email module examples.
+ def attachFile(self, outer, path):
+ # Guess the content type based on the file's extension. Encoding
+ # will be ignored, although we should check for simple things like
+ # gzip'd or compressed files.
+ ctype, encoding = mimetypes.guess_type(path)
+ if ctype is None or encoding is not None:
+ # No guess could be made, or the file is encoded (compressed), so
+ # use a generic bag-of-bits type.
+ ctype = 'application/octet-stream'
+ maintype, subtype = ctype.split('/', 1)
+ if maintype == 'text':
+ fp = open(path)
+ # Note: we should handle calculating the charset
+ msg = MIMEText(fp.read(), _subtype=subtype)
+ fp.close()
+ else:
+ fp = open(path, 'rb')
+ msg = MIMEBase(maintype, subtype)
+ msg.set_payload(fp.read())
+ fp.close()
+ # Encode the payload using Base64
+ encoders.encode_base64(msg)
+ # Set the filename parameter
+ msg.add_header('Content-Disposition', 'attachment', filename=os.path.basename(path))
+ outer.attach(msg)
+
+ def fileReport(self, report, parameters):
+ mainMsg = """\
+BUG REPORT
+---
+Title: %s
+Description: %s
+"""%(report.title, report.description)
+
+ if not parameters.get('To'):
+ raise ReportFailure('No "To" address specified.')
+ if not parameters.get('From'):
+ raise ReportFailure('No "From" address specified.')
+
+ msg = MIMEMultipart()
+ msg['Subject'] = 'BUG REPORT: %s'%(report.title)
+ # FIXME: Get config parameters
+ msg['To'] = parameters.get('To')
+ msg['From'] = parameters.get('From')
+ msg.preamble = mainMsg
+
+ msg.attach(MIMEText(mainMsg, _subtype='text/plain'))
+ for file in report.files:
+ self.attachFile(msg, file)
+
+ try:
+ s = smtplib.SMTP(host=parameters.get('SMTP Server'),
+ port=parameters.get('SMTP Port'))
+ s.sendmail(msg['From'], msg['To'], msg.as_string())
+ s.close()
+ except:
+ raise ReportFailure('Unable to send message via SMTP.')
+
+ return "Message sent!"
+
+class BugzillaReporter:
+ def getName(self):
+ return 'Bugzilla'
+
+ def getParameters(self):
+ return map(lambda x:TextParameter(x),['URL','Product'])
+
+ def fileReport(self, report, parameters):
+ raise NotImplementedError
+
+
+class RadarClassificationParameter(SelectionParameter):
+ def __init__(self):
+ SelectionParameter.__init__(self,"Classification",
+ [['1', 'Security'], ['2', 'Crash/Hang/Data Loss'],
+ ['3', 'Performance'], ['4', 'UI/Usability'],
+ ['6', 'Serious Bug'], ['7', 'Other']])
+
+ def saveConfigValue(self):
+ return False
+
+ def getValue(self,r,bugtype,getConfigOption):
+ if bugtype.find("leak") != -1:
+ return '3'
+ elif bugtype.find("dereference") != -1:
+ return '2'
+ elif bugtype.find("missing ivar release") != -1:
+ return '3'
+ else:
+ return '7'
+
+class RadarReporter:
+ @staticmethod
+ def isAvailable():
+ # FIXME: Find this .scpt better
+ path = os.path.join(os.path.dirname(__file__),'Resources/GetRadarVersion.scpt')
+ try:
+ p = subprocess.Popen(['osascript',path],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ except:
+ return False
+ data,err = p.communicate()
+ res = p.wait()
+ # FIXME: Check version? Check for no errors?
+ return res == 0
+
+ def getName(self):
+ return 'Radar'
+
+ def getParameters(self):
+ return [ TextParameter('Component'), TextParameter('Component Version'),
+ RadarClassificationParameter() ]
+
+ def fileReport(self, report, parameters):
+ component = parameters.get('Component', '')
+ componentVersion = parameters.get('Component Version', '')
+ classification = parameters.get('Classification', '')
+ personID = ""
+ diagnosis = ""
+ config = ""
+
+ if not component.strip():
+ component = 'Bugs found by clang Analyzer'
+ if not componentVersion.strip():
+ componentVersion = 'X'
+
+ script = os.path.join(os.path.dirname(__file__),'Resources/FileRadar.scpt')
+ args = ['osascript', script, component, componentVersion, classification, personID, report.title,
+ report.description, diagnosis, config] + map(os.path.abspath, report.files)
+# print >>sys.stderr, args
+ try:
+ p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ except:
+ raise ReportFailure("Unable to file radar (AppleScript failure).")
+ data, err = p.communicate()
+ res = p.wait()
+
+ if res:
+ raise ReportFailure("Unable to file radar (AppleScript failure).")
+
+ try:
+ values = eval(data)
+ except:
+ raise ReportFailure("Unable to process radar results.")
+
+ # We expect (int: bugID, str: message)
+ if len(values) != 2 or not isinstance(values[0], int):
+ raise ReportFailure("Unable to process radar results.")
+
+ bugID,message = values
+ bugID = int(bugID)
+
+ if not bugID:
+ raise ReportFailure(message)
+
+ return "Filed: <a href=\"rdar://%d/\">%d</a>"%(bugID,bugID)
+
+###
+
+def getReporters():
+ reporters = []
+ if RadarReporter.isAvailable():
+ reporters.append(RadarReporter())
+ reporters.append(EmailReporter())
+ return reporters
+
diff --git a/tools/scan-view/Resources/FileRadar.scpt b/tools/scan-view/Resources/FileRadar.scpt
new file mode 100644
index 000000000000..1c7455285ccb
--- /dev/null
+++ b/tools/scan-view/Resources/FileRadar.scpt
Binary files differ
diff --git a/tools/scan-view/Resources/GetRadarVersion.scpt b/tools/scan-view/Resources/GetRadarVersion.scpt
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tools/scan-view/Resources/GetRadarVersion.scpt
diff --git a/tools/scan-view/Resources/bugcatcher.ico b/tools/scan-view/Resources/bugcatcher.ico
new file mode 100644
index 000000000000..22d39b592036
--- /dev/null
+++ b/tools/scan-view/Resources/bugcatcher.ico
Binary files differ
diff --git a/tools/scan-view/ScanView.py b/tools/scan-view/ScanView.py
new file mode 100644
index 000000000000..837adae0f763
--- /dev/null
+++ b/tools/scan-view/ScanView.py
@@ -0,0 +1,770 @@
+import BaseHTTPServer
+import SimpleHTTPServer
+import os
+import sys
+import urllib, urlparse
+import posixpath
+import StringIO
+import re
+import shutil
+import threading
+import time
+import socket
+import itertools
+
+import Reporter
+import ConfigParser
+
+###
+# Various patterns matched or replaced by server.
+
+kReportFileRE = re.compile('(.*/)?report-(.*)\\.html')
+
+kBugKeyValueRE = re.compile('<!-- BUG([^ ]*) (.*) -->')
+
+# <!-- REPORTPROBLEM file="crashes/clang_crash_ndSGF9.mi" stderr="crashes/clang_crash_ndSGF9.mi.stderr.txt" info="crashes/clang_crash_ndSGF9.mi.info" -->
+
+kReportCrashEntryRE = re.compile('<!-- REPORTPROBLEM (.*?)-->')
+kReportCrashEntryKeyValueRE = re.compile(' ?([^=]+)="(.*?)"')
+
+kReportReplacements = []
+
+# Add custom javascript.
+kReportReplacements.append((re.compile('<!-- SUMMARYENDHEAD -->'), """\
+<script language="javascript" type="text/javascript">
+function load(url) {
+ if (window.XMLHttpRequest) {
+ req = new XMLHttpRequest();
+ } else if (window.ActiveXObject) {
+ req = new ActiveXObject("Microsoft.XMLHTTP");
+ }
+ if (req != undefined) {
+ req.open("GET", url, true);
+ req.send("");
+ }
+}
+</script>"""))
+
+# Insert additional columns.
+kReportReplacements.append((re.compile('<!-- REPORTBUGCOL -->'),
+ '<td></td><td></td>'))
+
+# Insert report bug and open file links.
+kReportReplacements.append((re.compile('<!-- REPORTBUG id="report-(.*)\\.html" -->'),
+ ('<td class="Button"><a href="report/\\1">Report Bug</a></td>' +
+ '<td class="Button"><a href="javascript:load(\'open/\\1\')">Open File</a></td>')))
+
+kReportReplacements.append((re.compile('<!-- REPORTHEADER -->'),
+ '<h3><a href="/">Summary</a> > Report %(report)s</h3>'))
+
+kReportReplacements.append((re.compile('<!-- REPORTSUMMARYEXTRA -->'),
+ '<td class="Button"><a href="report/%(report)s">Report Bug</a></td>'))
+
+# Insert report crashes link.
+
+# Disabled for the time being until we decide exactly when this should
+# be enabled. Also the radar reporter needs to be fixed to report
+# multiple files.
+
+#kReportReplacements.append((re.compile('<!-- REPORTCRASHES -->'),
+# '<br>These files will automatically be attached to ' +
+# 'reports filed here: <a href="report_crashes">Report Crashes</a>.'))
+
+###
+# Other simple parameters
+
+kResources = posixpath.join(posixpath.dirname(__file__), 'Resources')
+kConfigPath = os.path.expanduser('~/.scanview.cfg')
+
+###
+
+__version__ = "0.1"
+
+__all__ = ["create_server"]
+
+class ReporterThread(threading.Thread):
+ def __init__(self, report, reporter, parameters, server):
+ threading.Thread.__init__(self)
+ self.report = report
+ self.server = server
+ self.reporter = reporter
+ self.parameters = parameters
+ self.success = False
+ self.status = None
+
+ def run(self):
+ result = None
+ try:
+ if self.server.options.debug:
+ print >>sys.stderr, "%s: SERVER: submitting bug."%(sys.argv[0],)
+ self.status = self.reporter.fileReport(self.report, self.parameters)
+ self.success = True
+ time.sleep(3)
+ if self.server.options.debug:
+ print >>sys.stderr, "%s: SERVER: submission complete."%(sys.argv[0],)
+ except Reporter.ReportFailure,e:
+ self.status = e.value
+ except Exception,e:
+ s = StringIO.StringIO()
+ import traceback
+ print >>s,'<b>Unhandled Exception</b><br><pre>'
+ traceback.print_exc(e,file=s)
+ print >>s,'</pre>'
+ self.status = s.getvalue()
+
+class ScanViewServer(BaseHTTPServer.HTTPServer):
+ def __init__(self, address, handler, root, reporters, options):
+ BaseHTTPServer.HTTPServer.__init__(self, address, handler)
+ self.root = root
+ self.reporters = reporters
+ self.options = options
+ self.halted = False
+ self.config = None
+ self.load_config()
+
+ def load_config(self):
+ self.config = ConfigParser.RawConfigParser()
+
+ # Add defaults
+ self.config.add_section('ScanView')
+ for r in self.reporters:
+ self.config.add_section(r.getName())
+ for p in r.getParameters():
+ if p.saveConfigValue():
+ self.config.set(r.getName(), p.getName(), '')
+
+ # Ignore parse errors
+ try:
+ self.config.read([kConfigPath])
+ except:
+ pass
+
+ # Save on exit
+ import atexit
+ atexit.register(lambda: self.save_config())
+
+ def save_config(self):
+ # Ignore errors (only called on exit).
+ try:
+ f = open(kConfigPath,'w')
+ self.config.write(f)
+ f.close()
+ except:
+ pass
+
+ def halt(self):
+ self.halted = True
+ if self.options.debug:
+ print >>sys.stderr, "%s: SERVER: halting." % (sys.argv[0],)
+
+ def serve_forever(self):
+ while not self.halted:
+ if self.options.debug > 1:
+ print >>sys.stderr, "%s: SERVER: waiting..." % (sys.argv[0],)
+ try:
+ self.handle_request()
+ except OSError,e:
+ print 'OSError',e.errno
+
+ def finish_request(self, request, client_address):
+ if self.options.autoReload:
+ import ScanView
+ self.RequestHandlerClass = reload(ScanView).ScanViewRequestHandler
+ BaseHTTPServer.HTTPServer.finish_request(self, request, client_address)
+
+ def handle_error(self, request, client_address):
+ # Ignore socket errors
+ info = sys.exc_info()
+ if info and isinstance(info[1], socket.error):
+ if self.options.debug > 1:
+ print >>sys.stderr, "%s: SERVER: ignored socket error." % (sys.argv[0],)
+ return
+ BaseHTTPServer.HTTPServer.handle_error(self, request, client_address)
+
+# Borrowed from Quixote, with simplifications.
+def parse_query(qs, fields=None):
+ if fields is None:
+ fields = {}
+ for chunk in filter(None, qs.split('&')):
+ if '=' not in chunk:
+ name = chunk
+ value = ''
+ else:
+ name, value = chunk.split('=', 1)
+ name = urllib.unquote(name.replace('+', ' '))
+ value = urllib.unquote(value.replace('+', ' '))
+ item = fields.get(name)
+ if item is None:
+ fields[name] = [value]
+ else:
+ item.append(value)
+ return fields
+
+class ScanViewRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+ server_version = "ScanViewServer/" + __version__
+ dynamic_mtime = time.time()
+
+ def do_HEAD(self):
+ try:
+ SimpleHTTPServer.SimpleHTTPRequestHandler.do_HEAD(self)
+ except Exception,e:
+ self.handle_exception(e)
+
+ def do_GET(self):
+ try:
+ SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
+ except Exception,e:
+ self.handle_exception(e)
+
+ def do_POST(self):
+ """Serve a POST request."""
+ try:
+ length = self.headers.getheader('content-length') or "0"
+ try:
+ length = int(length)
+ except:
+ length = 0
+ content = self.rfile.read(length)
+ fields = parse_query(content)
+ f = self.send_head(fields)
+ if f:
+ self.copyfile(f, self.wfile)
+ f.close()
+ except Exception,e:
+ self.handle_exception(e)
+
+ def log_message(self, format, *args):
+ if self.server.options.debug:
+ sys.stderr.write("%s: SERVER: %s - - [%s] %s\n" %
+ (sys.argv[0],
+ self.address_string(),
+ self.log_date_time_string(),
+ format%args))
+
+ def load_report(self, report):
+ path = os.path.join(self.server.root, 'report-%s.html'%report)
+ data = open(path).read()
+ keys = {}
+ for item in kBugKeyValueRE.finditer(data):
+ k,v = item.groups()
+ keys[k] = v
+ return keys
+
+ def load_crashes(self):
+ path = posixpath.join(self.server.root, 'index.html')
+ data = open(path).read()
+ problems = []
+ for item in kReportCrashEntryRE.finditer(data):
+ fieldData = item.group(1)
+ fields = dict([i.groups() for i in
+ kReportCrashEntryKeyValueRE.finditer(fieldData)])
+ problems.append(fields)
+ return problems
+
+ def handle_exception(self, exc):
+ import traceback
+ s = StringIO.StringIO()
+ print >>s, "INTERNAL ERROR\n"
+ traceback.print_exc(exc, s)
+ f = self.send_string(s.getvalue(), 'text/plain')
+ if f:
+ self.copyfile(f, self.wfile)
+ f.close()
+
+ def get_scalar_field(self, name):
+ if name in self.fields:
+ return self.fields[name][0]
+ else:
+ return None
+
+ def submit_bug(self, c):
+ title = self.get_scalar_field('title')
+ description = self.get_scalar_field('description')
+ report = self.get_scalar_field('report')
+ reporterIndex = self.get_scalar_field('reporter')
+ files = []
+ for fileID in self.fields.get('files',[]):
+ try:
+ i = int(fileID)
+ except:
+ i = None
+ if i is None or i<0 or i>=len(c.files):
+ return (False, 'Invalid file ID')
+ files.append(c.files[i])
+
+ if not title:
+ return (False, "Missing title.")
+ if not description:
+ return (False, "Missing description.")
+ try:
+ reporterIndex = int(reporterIndex)
+ except:
+ return (False, "Invalid report method.")
+
+ # Get the reporter and parameters.
+ reporter = self.server.reporters[reporterIndex]
+ parameters = {}
+ for o in reporter.getParameters():
+ name = '%s_%s'%(reporter.getName(),o.getName())
+ if name not in self.fields:
+ return (False,
+ 'Missing field "%s" for %s report method.'%(name,
+ reporter.getName()))
+ parameters[o.getName()] = self.get_scalar_field(name)
+
+ # Update config defaults.
+ if report != 'None':
+ self.server.config.set('ScanView', 'reporter', reporterIndex)
+ for o in reporter.getParameters():
+ if o.saveConfigValue():
+ name = o.getName()
+ self.server.config.set(reporter.getName(), name, parameters[name])
+
+ # Create the report.
+ bug = Reporter.BugReport(title, description, files)
+
+ # Kick off a reporting thread.
+ t = ReporterThread(bug, reporter, parameters, self.server)
+ t.start()
+
+ # Wait for thread to die...
+ while t.isAlive():
+ time.sleep(.25)
+ submitStatus = t.status
+
+ return (t.success, t.status)
+
+ def send_report_submit(self):
+ report = self.get_scalar_field('report')
+ c = self.get_report_context(report)
+ if c.reportSource is None:
+ reportingFor = "Report Crashes > "
+ fileBug = """\
+<a href="/report_crashes">File Bug</a> > """%locals()
+ else:
+ reportingFor = '<a href="/%s">Report %s</a> > ' % (c.reportSource,
+ report)
+ fileBug = '<a href="/report/%s">File Bug</a> > ' % report
+ title = self.get_scalar_field('title')
+ description = self.get_scalar_field('description')
+
+ res,message = self.submit_bug(c)
+
+ if res:
+ statusClass = 'SubmitOk'
+ statusName = 'Succeeded'
+ else:
+ statusClass = 'SubmitFail'
+ statusName = 'Failed'
+
+ result = """
+<head>
+ <title>Bug Submission</title>
+ <link rel="stylesheet" type="text/css" href="/scanview.css" />
+</head>
+<body>
+<h3>
+<a href="/">Summary</a> >
+%(reportingFor)s
+%(fileBug)s
+Submit</h3>
+<form name="form" action="">
+<table class="form">
+<tr><td>
+<table class="form_group">
+<tr>
+ <td class="form_clabel">Title:</td>
+ <td class="form_value">
+ <input type="text" name="title" size="50" value="%(title)s" disabled>
+ </td>
+</tr>
+<tr>
+ <td class="form_label">Description:</td>
+ <td class="form_value">
+<textarea rows="10" cols="80" name="description" disabled>
+%(description)s
+</textarea>
+ </td>
+</table>
+</td></tr>
+</table>
+</form>
+<h1 class="%(statusClass)s">Submission %(statusName)s</h1>
+%(message)s
+<p>
+<hr>
+<a href="/">Return to Summary</a>
+</body>
+</html>"""%locals()
+ return self.send_string(result)
+
+ def send_open_report(self, report):
+ try:
+ keys = self.load_report(report)
+ except IOError:
+ return self.send_error(400, 'Invalid report.')
+
+ file = keys.get('FILE')
+ if not file or not posixpath.exists(file):
+ return self.send_error(400, 'File does not exist: "%s"' % file)
+
+ import startfile
+ if self.server.options.debug:
+ print >>sys.stderr, '%s: SERVER: opening "%s"'%(sys.argv[0],
+ file)
+
+ status = startfile.open(file)
+ if status:
+ res = 'Opened: "%s"' % file
+ else:
+ res = 'Open failed: "%s"' % file
+
+ return self.send_string(res, 'text/plain')
+
+ def get_report_context(self, report):
+ class Context:
+ pass
+ if report is None or report == 'None':
+ data = self.load_crashes()
+ # Don't allow empty reports.
+ if not data:
+ raise ValueError, 'No crashes detected!'
+ c = Context()
+ c.title = 'clang static analyzer failures'
+
+ stderrSummary = ""
+ for item in data:
+ if 'stderr' in item:
+ path = posixpath.join(self.server.root, item['stderr'])
+ if os.path.exists(path):
+ lns = itertools.islice(open(path), 0, 10)
+ stderrSummary += '%s\n--\n%s' % (item.get('src',
+ '<unknown>'),
+ ''.join(lns))
+
+ c.description = """\
+The clang static analyzer failed on these inputs:
+%s
+
+STDERR Summary
+--------------
+%s
+""" % ('\n'.join([item.get('src','<unknown>') for item in data]),
+ stderrSummary)
+ c.reportSource = None
+ c.navMarkup = "Report Crashes > "
+ c.files = []
+ for item in data:
+ c.files.append(item.get('src',''))
+ c.files.append(posixpath.join(self.server.root,
+ item.get('file','')))
+ c.files.append(posixpath.join(self.server.root,
+ item.get('clangfile','')))
+ c.files.append(posixpath.join(self.server.root,
+ item.get('stderr','')))
+ c.files.append(posixpath.join(self.server.root,
+ item.get('info','')))
+ # Just in case something failed, ignore files which don't
+ # exist.
+ c.files = [f for f in c.files
+ if os.path.exists(f) and os.path.isfile(f)]
+ else:
+ # Check that this is a valid report.
+ path = posixpath.join(self.server.root, 'report-%s.html' % report)
+ if not posixpath.exists(path):
+ raise ValueError, 'Invalid report ID'
+ keys = self.load_report(report)
+ c = Context()
+ c.title = keys.get('DESC','clang error (unrecognized')
+ c.description = """\
+Bug reported by the clang static analyzer.
+
+Description: %s
+File: %s
+Line: %s
+"""%(c.title, keys.get('FILE','<unknown>'), keys.get('LINE', '<unknown>'))
+ c.reportSource = 'report-%s.html' % report
+ c.navMarkup = """<a href="/%s">Report %s</a> > """ % (c.reportSource,
+ report)
+
+ c.files = [path]
+ return c
+
+ def send_report(self, report, configOverrides=None):
+ def getConfigOption(section, field):
+ if (configOverrides is not None and
+ section in configOverrides and
+ field in configOverrides[section]):
+ return configOverrides[section][field]
+ return self.server.config.get(section, field)
+
+ # report is None is used for crashes
+ try:
+ c = self.get_report_context(report)
+ except ValueError, e:
+ return self.send_error(400, e.message)
+
+ title = c.title
+ description= c.description
+ reportingFor = c.navMarkup
+ if c.reportSource is None:
+ extraIFrame = ""
+ else:
+ extraIFrame = """\
+<iframe src="/%s" width="100%%" height="40%%"
+ scrolling="auto" frameborder="1">
+ <a href="/%s">View Bug Report</a>
+</iframe>""" % (c.reportSource, c.reportSource)
+
+ reporterSelections = []
+ reporterOptions = []
+
+ try:
+ active = int(getConfigOption('ScanView','reporter'))
+ except:
+ active = 0
+ for i,r in enumerate(self.server.reporters):
+ selected = (i == active)
+ if selected:
+ selectedStr = ' selected'
+ else:
+ selectedStr = ''
+ reporterSelections.append('<option value="%d"%s>%s</option>'%(i,selectedStr,r.getName()))
+ options = '\n'.join([ o.getHTML(r,title,getConfigOption) for o in r.getParameters()])
+ display = ('none','')[selected]
+ reporterOptions.append("""\
+<tr id="%sReporterOptions" style="display:%s">
+ <td class="form_label">%s Options</td>
+ <td class="form_value">
+ <table class="form_inner_group">
+%s
+ </table>
+ </td>
+</tr>
+"""%(r.getName(),display,r.getName(),options))
+ reporterSelections = '\n'.join(reporterSelections)
+ reporterOptionsDivs = '\n'.join(reporterOptions)
+ reportersArray = '[%s]'%(','.join([`r.getName()` for r in self.server.reporters]))
+
+ if c.files:
+ fieldSize = min(5, len(c.files))
+ attachFileOptions = '\n'.join(["""\
+<option value="%d" selected>%s</option>""" % (i,v) for i,v in enumerate(c.files)])
+ attachFileRow = """\
+<tr>
+ <td class="form_label">Attach:</td>
+ <td class="form_value">
+<select style="width:100%%" name="files" multiple size=%d>
+%s
+</select>
+ </td>
+</tr>
+""" % (min(5, len(c.files)), attachFileOptions)
+ else:
+ attachFileRow = ""
+
+ result = """<html>
+<head>
+ <title>File Bug</title>
+ <link rel="stylesheet" type="text/css" href="/scanview.css" />
+</head>
+<script language="javascript" type="text/javascript">
+var reporters = %(reportersArray)s;
+function updateReporterOptions() {
+ index = document.getElementById('reporter').selectedIndex;
+ for (var i=0; i < reporters.length; ++i) {
+ o = document.getElementById(reporters[i] + "ReporterOptions");
+ if (i == index) {
+ o.style.display = "";
+ } else {
+ o.style.display = "none";
+ }
+ }
+}
+</script>
+<body onLoad="updateReporterOptions()">
+<h3>
+<a href="/">Summary</a> >
+%(reportingFor)s
+File Bug</h3>
+<form name="form" action="/report_submit" method="post">
+<input type="hidden" name="report" value="%(report)s">
+
+<table class="form">
+<tr><td>
+<table class="form_group">
+<tr>
+ <td class="form_clabel">Title:</td>
+ <td class="form_value">
+ <input type="text" name="title" size="50" value="%(title)s">
+ </td>
+</tr>
+<tr>
+ <td class="form_label">Description:</td>
+ <td class="form_value">
+<textarea rows="10" cols="80" name="description">
+%(description)s
+</textarea>
+ </td>
+</tr>
+
+%(attachFileRow)s
+
+</table>
+<br>
+<table class="form_group">
+<tr>
+ <td class="form_clabel">Method:</td>
+ <td class="form_value">
+ <select id="reporter" name="reporter" onChange="updateReporterOptions()">
+ %(reporterSelections)s
+ </select>
+ </td>
+</tr>
+%(reporterOptionsDivs)s
+</table>
+<br>
+</td></tr>
+<tr><td class="form_submit">
+ <input align="right" type="submit" name="Submit" value="Submit">
+</td></tr>
+</table>
+</form>
+
+%(extraIFrame)s
+
+</body>
+</html>"""%locals()
+
+ return self.send_string(result)
+
+ def send_head(self, fields=None):
+ if (self.server.options.onlyServeLocal and
+ self.client_address[0] != '127.0.0.1'):
+ return self.send_error('401', 'Unauthorized host.')
+
+ if fields is None:
+ fields = {}
+ self.fields = fields
+
+ o = urlparse.urlparse(self.path)
+ self.fields = parse_query(o.query, fields)
+ path = posixpath.normpath(urllib.unquote(o.path))
+
+ # Split the components and strip the root prefix.
+ components = path.split('/')[1:]
+
+ # Special case some top-level entries.
+ if components:
+ name = components[0]
+ if len(components)==2:
+ if name=='report':
+ return self.send_report(components[1])
+ elif name=='open':
+ return self.send_open_report(components[1])
+ elif len(components)==1:
+ if name=='quit':
+ self.server.halt()
+ return self.send_string('Goodbye.', 'text/plain')
+ elif name=='report_submit':
+ return self.send_report_submit()
+ elif name=='report_crashes':
+ overrides = { 'ScanView' : {},
+ 'Radar' : {},
+ 'Email' : {} }
+ for i,r in enumerate(self.server.reporters):
+ if r.getName() == 'Radar':
+ overrides['ScanView']['reporter'] = i
+ break
+ overrides['Radar']['Component'] = 'llvm - checker'
+ overrides['Radar']['Component Version'] = 'X'
+ return self.send_report(None, overrides)
+ elif name=='favicon.ico':
+ return self.send_path(posixpath.join(kResources,'bugcatcher.ico'))
+
+ # Match directory entries.
+ if components[-1] == '':
+ components[-1] = 'index.html'
+
+ suffix = '/'.join(components)
+
+ # The summary may reference source files on disk using rooted
+ # paths. Make sure these resolve correctly for now.
+ # FIXME: This isn't a very good idea... we should probably
+ # mark rooted paths somehow.
+ if os.path.exists(posixpath.join('/', suffix)):
+ path = posixpath.join('/', suffix)
+ else:
+ path = posixpath.join(self.server.root, suffix)
+
+ if self.server.options.debug > 1:
+ print >>sys.stderr, '%s: SERVER: sending path "%s"'%(sys.argv[0],
+ path)
+ return self.send_path(path)
+
+ def send_404(self):
+ self.send_error(404, "File not found")
+ return None
+
+ def send_path(self, path):
+ ctype = self.guess_type(path)
+ if ctype.startswith('text/'):
+ # Patch file instead
+ return self.send_patched_file(path, ctype)
+ else:
+ mode = 'rb'
+ try:
+ f = open(path, mode)
+ except IOError:
+ return self.send_404()
+ return self.send_file(f, ctype)
+
+ def send_file(self, f, ctype):
+ # Patch files to add links, but skip binary files.
+ self.send_response(200)
+ self.send_header("Content-type", ctype)
+ fs = os.fstat(f.fileno())
+ self.send_header("Content-Length", str(fs[6]))
+ self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
+ self.end_headers()
+ return f
+
+ def send_string(self, s, ctype='text/html', headers=True, mtime=None):
+ if headers:
+ self.send_response(200)
+ self.send_header("Content-type", ctype)
+ self.send_header("Content-Length", str(len(s)))
+ if mtime is None:
+ mtime = self.dynamic_mtime
+ self.send_header("Last-Modified", self.date_time_string(mtime))
+ self.end_headers()
+ return StringIO.StringIO(s)
+
+ def send_patched_file(self, path, ctype):
+ # Allow a very limited set of variables. This is pretty gross.
+ variables = {}
+ variables['report'] = ''
+ m = kReportFileRE.match(path)
+ if m:
+ variables['report'] = m.group(2)
+
+ try:
+ f = open(path,'r')
+ except IOError:
+ return self.send_404()
+ fs = os.fstat(f.fileno())
+ data = f.read()
+ for a,b in kReportReplacements:
+ data = a.sub(b % variables, data)
+ return self.send_string(data, ctype, mtime=fs.st_mtime)
+
+
+def create_server(address, options, root):
+ import Reporter
+
+ reporters = Reporter.getReporters()
+
+ return ScanViewServer(address, ScanViewRequestHandler,
+ root,
+ reporters,
+ options)
diff --git a/tools/scan-view/scan-view b/tools/scan-view/scan-view
new file mode 100755
index 000000000000..fb27da698882
--- /dev/null
+++ b/tools/scan-view/scan-view
@@ -0,0 +1,131 @@
+#!/usr/bin/env python
+
+"""The clang static analyzer results viewer.
+"""
+
+import sys
+import posixpath
+import thread
+import time
+import urllib
+import webbrowser
+
+# How long to wait for server to start.
+kSleepTimeout = .05
+kMaxSleeps = int(60 / kSleepTimeout)
+
+# Default server parameters
+
+kDefaultHost = '127.0.0.1'
+kDefaultPort = 8181
+kMaxPortsToTry = 100
+
+###
+
+def url_is_up(url):
+ try:
+ o = urllib.urlopen(url)
+ except IOError:
+ return False
+ o.close()
+ return True
+
+def start_browser(port, options):
+ import urllib, webbrowser
+
+ url = 'http://%s:%d'%(options.host, port)
+
+ # Wait for server to start...
+ if options.debug:
+ sys.stderr.write('%s: Waiting for server.' % sys.argv[0])
+ sys.stderr.flush()
+ for i in range(kMaxSleeps):
+ if url_is_up(url):
+ break
+ if options.debug:
+ sys.stderr.write('.')
+ sys.stderr.flush()
+ time.sleep(kSleepTimeout)
+ else:
+ print >>sys.stderr,'WARNING: Unable to detect that server started.'
+
+ if options.debug:
+ print >>sys.stderr,'%s: Starting webbrowser...' % sys.argv[0]
+ webbrowser.open(url)
+
+def run(port, options, root):
+ import ScanView
+ try:
+ print 'Starting scan-view at: http://%s:%d'%(options.host,
+ port)
+ print ' Use Ctrl-C to exit.'
+ httpd = ScanView.create_server((options.host, port),
+ options, root)
+ httpd.serve_forever()
+ except KeyboardInterrupt:
+ pass
+
+def port_is_open(port):
+ import SocketServer
+ try:
+ t = SocketServer.TCPServer((kDefaultHost,port),None)
+ except:
+ return False
+ t.server_close()
+ return True
+
+def main():
+ from optparse import OptionParser
+ parser = OptionParser('usage: %prog [options] <results directory>')
+ parser.set_description(__doc__)
+ parser.add_option(
+ '--host', dest="host", default=kDefaultHost, type="string",
+ help="Host interface to listen on. (default=%s)" % kDefaultHost)
+ parser.add_option(
+ '--port', dest="port", default=None, type="int",
+ help="Port to listen on. (default=%s)" % kDefaultPort)
+ parser.add_option("--debug", dest="debug", default=0,
+ action="count",
+ help="Print additional debugging information.")
+ parser.add_option("--auto-reload", dest="autoReload", default=False,
+ action="store_true",
+ help="Automatically update module for each request.")
+ parser.add_option("--no-browser", dest="startBrowser", default=True,
+ action="store_false",
+ help="Don't open a webbrowser on startup.")
+ parser.add_option("--allow-all-hosts", dest="onlyServeLocal", default=True,
+ action="store_false",
+ help='Allow connections from any host (access restricted to "127.0.0.1" by default)')
+ (options, args) = parser.parse_args()
+
+ if len(args) != 1:
+ parser.error('No results directory specified.')
+ root, = args
+
+ # Make sure this directory is in a reasonable state to view.
+ if not posixpath.exists(posixpath.join(root,'index.html')):
+ parser.error('Invalid directory, analysis results not found!')
+
+ # Find an open port. We aren't particularly worried about race
+ # conditions here. Note that if the user specified a port we only
+ # use that one.
+ if options.port is not None:
+ port = options.port
+ else:
+ for i in range(kMaxPortsToTry):
+ if port_is_open(kDefaultPort + i):
+ port = kDefaultPort + i
+ break
+ else:
+ parser.error('Unable to find usable port in [%d,%d)'%(kDefaultPort,
+ kDefaultPort+kMaxPortsToTry))
+
+ # Kick off thread to wait for server and start web browser, if
+ # requested.
+ if options.startBrowser:
+ t = thread.start_new_thread(start_browser, (port,options))
+
+ run(port, options, root)
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/scan-view/startfile.py b/tools/scan-view/startfile.py
new file mode 100644
index 000000000000..e8fbe2d5a84e
--- /dev/null
+++ b/tools/scan-view/startfile.py
@@ -0,0 +1,203 @@
+"""Utility for opening a file using the default application in a cross-platform
+manner. Modified from http://code.activestate.com/recipes/511443/.
+"""
+
+__version__ = '1.1x'
+__all__ = ['open']
+
+import os
+import sys
+import webbrowser
+import subprocess
+
+_controllers = {}
+_open = None
+
+
+class BaseController(object):
+ '''Base class for open program controllers.'''
+
+ def __init__(self, name):
+ self.name = name
+
+ def open(self, filename):
+ raise NotImplementedError
+
+
+class Controller(BaseController):
+ '''Controller for a generic open program.'''
+
+ def __init__(self, *args):
+ super(Controller, self).__init__(os.path.basename(args[0]))
+ self.args = list(args)
+
+ def _invoke(self, cmdline):
+ if sys.platform[:3] == 'win':
+ closefds = False
+ startupinfo = subprocess.STARTUPINFO()
+ startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
+ else:
+ closefds = True
+ startupinfo = None
+
+ if (os.environ.get('DISPLAY') or sys.platform[:3] == 'win' or
+ sys.platform == 'darwin'):
+ inout = file(os.devnull, 'r+')
+ else:
+ # for TTY programs, we need stdin/out
+ inout = None
+
+ # if possible, put the child precess in separate process group,
+ # so keyboard interrupts don't affect child precess as well as
+ # Python
+ setsid = getattr(os, 'setsid', None)
+ if not setsid:
+ setsid = getattr(os, 'setpgrp', None)
+
+ pipe = subprocess.Popen(cmdline, stdin=inout, stdout=inout,
+ stderr=inout, close_fds=closefds,
+ preexec_fn=setsid, startupinfo=startupinfo)
+
+ # It is assumed that this kind of tools (gnome-open, kfmclient,
+ # exo-open, xdg-open and open for OSX) immediately exit after lauching
+ # the specific application
+ returncode = pipe.wait()
+ if hasattr(self, 'fixreturncode'):
+ returncode = self.fixreturncode(returncode)
+ return not returncode
+
+ def open(self, filename):
+ if isinstance(filename, basestring):
+ cmdline = self.args + [filename]
+ else:
+ # assume it is a sequence
+ cmdline = self.args + filename
+ try:
+ return self._invoke(cmdline)
+ except OSError:
+ return False
+
+
+# Platform support for Windows
+if sys.platform[:3] == 'win':
+
+ class Start(BaseController):
+ '''Controller for the win32 start progam through os.startfile.'''
+
+ def open(self, filename):
+ try:
+ os.startfile(filename)
+ except WindowsError:
+ # [Error 22] No application is associated with the specified
+ # file for this operation: '<URL>'
+ return False
+ else:
+ return True
+
+ _controllers['windows-default'] = Start('start')
+ _open = _controllers['windows-default'].open
+
+
+# Platform support for MacOS
+elif sys.platform == 'darwin':
+ _controllers['open']= Controller('open')
+ _open = _controllers['open'].open
+
+
+# Platform support for Unix
+else:
+
+ import commands
+
+ # @WARNING: use the private API of the webbrowser module
+ from webbrowser import _iscommand
+
+ class KfmClient(Controller):
+ '''Controller for the KDE kfmclient program.'''
+
+ def __init__(self, kfmclient='kfmclient'):
+ super(KfmClient, self).__init__(kfmclient, 'exec')
+ self.kde_version = self.detect_kde_version()
+
+ def detect_kde_version(self):
+ kde_version = None
+ try:
+ info = commands.getoutput('kde-config --version')
+
+ for line in info.splitlines():
+ if line.startswith('KDE'):
+ kde_version = line.split(':')[-1].strip()
+ break
+ except (OSError, RuntimeError):
+ pass
+
+ return kde_version
+
+ def fixreturncode(self, returncode):
+ if returncode is not None and self.kde_version > '3.5.4':
+ return returncode
+ else:
+ return os.EX_OK
+
+ def detect_desktop_environment():
+ '''Checks for known desktop environments
+
+ Return the desktop environments name, lowercase (kde, gnome, xfce)
+ or "generic"
+
+ '''
+
+ desktop_environment = 'generic'
+
+ if os.environ.get('KDE_FULL_SESSION') == 'true':
+ desktop_environment = 'kde'
+ elif os.environ.get('GNOME_DESKTOP_SESSION_ID'):
+ desktop_environment = 'gnome'
+ else:
+ try:
+ info = commands.getoutput('xprop -root _DT_SAVE_MODE')
+ if ' = "xfce4"' in info:
+ desktop_environment = 'xfce'
+ except (OSError, RuntimeError):
+ pass
+
+ return desktop_environment
+
+
+ def register_X_controllers():
+ if _iscommand('kfmclient'):
+ _controllers['kde-open'] = KfmClient()
+
+ for command in ('gnome-open', 'exo-open', 'xdg-open'):
+ if _iscommand(command):
+ _controllers[command] = Controller(command)
+
+ def get():
+ controllers_map = {
+ 'gnome': 'gnome-open',
+ 'kde': 'kde-open',
+ 'xfce': 'exo-open',
+ }
+
+ desktop_environment = detect_desktop_environment()
+
+ try:
+ controller_name = controllers_map[desktop_environment]
+ return _controllers[controller_name].open
+
+ except KeyError:
+ if _controllers.has_key('xdg-open'):
+ return _controllers['xdg-open'].open
+ else:
+ return webbrowser.open
+
+
+ if os.environ.get("DISPLAY"):
+ register_X_controllers()
+ _open = get()
+
+
+def open(filename):
+ '''Open a file or an URL in the registered default application.'''
+
+ return _open(filename)
diff --git a/utils/ABITest/ABITestGen.py b/utils/ABITest/ABITestGen.py
new file mode 100755
index 000000000000..5598caae3d9b
--- /dev/null
+++ b/utils/ABITest/ABITestGen.py
@@ -0,0 +1,638 @@
+#!/usr/bin/python
+
+from pprint import pprint
+import random, atexit, time
+from random import randrange
+import re
+
+from Enumeration import *
+from TypeGen import *
+
+####
+
+class TypePrinter:
+ def __init__(self, output, outputHeader=None,
+ outputTests=None, outputDriver=None,
+ headerName=None, info=None):
+ self.output = output
+ self.outputHeader = outputHeader
+ self.outputTests = outputTests
+ self.outputDriver = outputDriver
+ self.writeBody = outputHeader or outputTests or outputDriver
+ self.types = {}
+ self.testValues = {}
+ self.testReturnValues = {}
+ self.layoutTests = []
+
+ if info:
+ for f in (self.output,self.outputHeader,self.outputTests,self.outputDriver):
+ if f:
+ print >>f,info
+
+ if self.writeBody:
+ print >>self.output, '#include <stdio.h>\n'
+ if self.outputTests:
+ print >>self.outputTests, '#include <stdio.h>'
+ print >>self.outputTests, '#include <string.h>'
+ print >>self.outputTests, '#include <assert.h>\n'
+
+ if headerName:
+ for f in (self.output,self.outputTests,self.outputDriver):
+ if f is not None:
+ print >>f, '#include "%s"\n'%(headerName,)
+
+ if self.outputDriver:
+ print >>self.outputDriver, '#include <stdio.h>\n'
+ print >>self.outputDriver, 'int main(int argc, char **argv) {'
+ print >>self.outputDriver, ' int index = -1;'
+ print >>self.outputDriver, ' if (argc > 1) index = atoi(argv[1]);'
+
+ def finish(self):
+ if self.layoutTests:
+ print >>self.output, 'int main(int argc, char **argv) {'
+ print >>self.output, ' int index = -1;'
+ print >>self.output, ' if (argc > 1) index = atoi(argv[1]);'
+ for i,f in self.layoutTests:
+ print >>self.output, ' if (index == -1 || index == %d)' % i
+ print >>self.output, ' %s();' % f
+ print >>self.output, ' return 0;'
+ print >>self.output, '}'
+
+ if self.outputDriver:
+ print >>self.outputDriver, ' printf("DONE\\n");'
+ print >>self.outputDriver, ' return 0;'
+ print >>self.outputDriver, '}'
+
+ def getTypeName(self, T):
+ if isinstance(T,BuiltinType):
+ return T.name
+ name = self.types.get(T)
+ if name is None:
+ name = 'T%d'%(len(self.types),)
+ # Reserve slot
+ self.types[T] = None
+ if self.outputHeader:
+ print >>self.outputHeader,T.getTypedefDef(name, self)
+ else:
+ print >>self.output,T.getTypedefDef(name, self)
+ if self.outputTests:
+ print >>self.outputTests,T.getTypedefDef(name, self)
+ self.types[T] = name
+ return name
+
+ def writeLayoutTest(self, i, ty):
+ tyName = self.getTypeName(ty)
+ tyNameClean = tyName.replace(' ','_').replace('*','star')
+ fnName = 'test_%s' % tyNameClean
+
+ print >>self.output,'void %s(void) {' % fnName
+ self.printSizeOfType(' %s'%fnName, tyName, ty, self.output)
+ self.printAlignOfType(' %s'%fnName, tyName, ty, self.output)
+ self.printOffsetsOfType(' %s'%fnName, tyName, ty, self.output)
+ print >>self.output,'}'
+ print >>self.output
+
+ self.layoutTests.append((i,fnName))
+
+ def writeFunction(self, i, FT):
+ args = ', '.join(['%s arg%d'%(self.getTypeName(t),i) for i,t in enumerate(FT.argTypes)])
+ if not args:
+ args = 'void'
+
+ if FT.returnType is None:
+ retvalName = None
+ retvalTypeName = 'void'
+ else:
+ retvalTypeName = self.getTypeName(FT.returnType)
+ if self.writeBody or self.outputTests:
+ retvalName = self.getTestReturnValue(FT.returnType)
+
+ fnName = 'fn%d'%(FT.index,)
+ if self.outputHeader:
+ print >>self.outputHeader,'%s %s(%s);'%(retvalTypeName, fnName, args)
+ elif self.outputTests:
+ print >>self.outputTests,'%s %s(%s);'%(retvalTypeName, fnName, args)
+
+ print >>self.output,'%s %s(%s)'%(retvalTypeName, fnName, args),
+ if self.writeBody:
+ print >>self.output, '{'
+
+ for i,t in enumerate(FT.argTypes):
+ self.printValueOfType(' %s'%fnName, 'arg%d'%i, t)
+
+ if retvalName is not None:
+ print >>self.output, ' return %s;'%(retvalName,)
+ print >>self.output, '}'
+ else:
+ print >>self.output, '{}'
+ print >>self.output
+
+ if self.outputDriver:
+ print >>self.outputDriver, ' if (index == -1 || index == %d) {' % i
+ print >>self.outputDriver, ' extern void test_%s(void);' % fnName
+ print >>self.outputDriver, ' test_%s();' % fnName
+ print >>self.outputDriver, ' }'
+
+ if self.outputTests:
+ if self.outputHeader:
+ print >>self.outputHeader, 'void test_%s(void);'%(fnName,)
+
+ if retvalName is None:
+ retvalTests = None
+ else:
+ retvalTests = self.getTestValuesArray(FT.returnType)
+ tests = map(self.getTestValuesArray, FT.argTypes)
+ print >>self.outputTests, 'void test_%s(void) {'%(fnName,)
+
+ if retvalTests is not None:
+ print >>self.outputTests, ' printf("%s: testing return.\\n");'%(fnName,)
+ print >>self.outputTests, ' for (int i=0; i<%d; ++i) {'%(retvalTests[1],)
+ args = ', '.join(['%s[%d]'%(t,randrange(l)) for t,l in tests])
+ print >>self.outputTests, ' %s RV;'%(retvalTypeName,)
+ print >>self.outputTests, ' %s = %s[i];'%(retvalName, retvalTests[0])
+ print >>self.outputTests, ' RV = %s(%s);'%(fnName, args)
+ self.printValueOfType(' %s_RV'%fnName, 'RV', FT.returnType, output=self.outputTests, indent=4)
+ self.checkTypeValues('RV', '%s[i]' % retvalTests[0], FT.returnType, output=self.outputTests, indent=4)
+ print >>self.outputTests, ' }'
+
+ if tests:
+ print >>self.outputTests, ' printf("%s: testing arguments.\\n");'%(fnName,)
+ for i,(array,length) in enumerate(tests):
+ for j in range(length):
+ args = ['%s[%d]'%(t,randrange(l)) for t,l in tests]
+ args[i] = '%s[%d]'%(array,j)
+ print >>self.outputTests, ' %s(%s);'%(fnName, ', '.join(args),)
+ print >>self.outputTests, '}'
+
+ def getTestReturnValue(self, type):
+ typeName = self.getTypeName(type)
+ info = self.testReturnValues.get(typeName)
+ if info is None:
+ name = '%s_retval'%(typeName.replace(' ','_').replace('*','star'),)
+ print >>self.output, '%s %s;'%(typeName,name)
+ if self.outputHeader:
+ print >>self.outputHeader, 'extern %s %s;'%(typeName,name)
+ elif self.outputTests:
+ print >>self.outputTests, 'extern %s %s;'%(typeName,name)
+ info = self.testReturnValues[typeName] = name
+ return info
+
+ def getTestValuesArray(self, type):
+ typeName = self.getTypeName(type)
+ info = self.testValues.get(typeName)
+ if info is None:
+ name = '%s_values'%(typeName.replace(' ','_').replace('*','star'),)
+ print >>self.outputTests, 'static %s %s[] = {'%(typeName,name)
+ length = 0
+ for item in self.getTestValues(type):
+ print >>self.outputTests, '\t%s,'%(item,)
+ length += 1
+ print >>self.outputTests,'};'
+ info = self.testValues[typeName] = (name,length)
+ return info
+
+ def getTestValues(self, t):
+ if isinstance(t, BuiltinType):
+ if t.name=='float':
+ for i in ['0.0','-1.0','1.0']:
+ yield i+'f'
+ elif t.name=='double':
+ for i in ['0.0','-1.0','1.0']:
+ yield i
+ elif t.name in ('void *'):
+ yield '(void*) 0'
+ yield '(void*) -1'
+ else:
+ yield '(%s) 0'%(t.name,)
+ yield '(%s) -1'%(t.name,)
+ yield '(%s) 1'%(t.name,)
+ elif isinstance(t, RecordType):
+ nonPadding = [f for f in t.fields
+ if not f.isPaddingBitField()]
+
+ if not nonPadding:
+ yield '{ }'
+ return
+
+ # FIXME: Use designated initializers to access non-first
+ # fields of unions.
+ if t.isUnion:
+ for v in self.getTestValues(nonPadding[0]):
+ yield '{ %s }' % v
+ return
+
+ fieldValues = map(list, map(self.getTestValues, nonPadding))
+ for i,values in enumerate(fieldValues):
+ for v in values:
+ elements = map(random.choice,fieldValues)
+ elements[i] = v
+ yield '{ %s }'%(', '.join(elements))
+
+ elif isinstance(t, ComplexType):
+ for t in self.getTestValues(t.elementType):
+ yield '%s + %s * 1i'%(t,t)
+ elif isinstance(t, ArrayType):
+ values = list(self.getTestValues(t.elementType))
+ if not values:
+ yield '{ }'
+ for i in range(t.numElements):
+ for v in values:
+ elements = [random.choice(values) for i in range(t.numElements)]
+ elements[i] = v
+ yield '{ %s }'%(', '.join(elements))
+ else:
+ raise NotImplementedError,'Cannot make tests values of type: "%s"'%(t,)
+
+ def printSizeOfType(self, prefix, name, t, output=None, indent=2):
+ print >>output, '%*sprintf("%s: sizeof(%s) = %%ld\\n", (long)sizeof(%s));'%(indent, '', prefix, name, name)
+ def printAlignOfType(self, prefix, name, t, output=None, indent=2):
+ print >>output, '%*sprintf("%s: __alignof__(%s) = %%ld\\n", (long)__alignof__(%s));'%(indent, '', prefix, name, name)
+ def printOffsetsOfType(self, prefix, name, t, output=None, indent=2):
+ if isinstance(t, RecordType):
+ for i,f in enumerate(t.fields):
+ if f.isBitField():
+ continue
+ fname = 'field%d' % i
+ print >>output, '%*sprintf("%s: __builtin_offsetof(%s, %s) = %%ld\\n", (long)__builtin_offsetof(%s, %s));'%(indent, '', prefix, name, fname, name, fname)
+
+ def printValueOfType(self, prefix, name, t, output=None, indent=2):
+ if output is None:
+ output = self.output
+ if isinstance(t, BuiltinType):
+ if t.name.endswith('long long'):
+ code = 'lld'
+ elif t.name.endswith('long'):
+ code = 'ld'
+ elif t.name.split(' ')[-1] in ('_Bool','char','short','int'):
+ code = 'd'
+ elif t.name in ('float','double'):
+ code = 'f'
+ elif t.name == 'long double':
+ code = 'Lf'
+ else:
+ code = 'p'
+ print >>output, '%*sprintf("%s: %s = %%%s\\n", %s);'%(indent, '', prefix, name, code, name)
+ elif isinstance(t, RecordType):
+ if not t.fields:
+ print >>output, '%*sprintf("%s: %s (empty)\\n");'%(indent, '', prefix, name)
+ for i,f in enumerate(t.fields):
+ if f.isPaddingBitField():
+ continue
+ fname = '%s.field%d'%(name,i)
+ self.printValueOfType(prefix, fname, f, output=output, indent=indent)
+ elif isinstance(t, ComplexType):
+ self.printValueOfType(prefix, '(__real %s)'%name, t.elementType, output=output,indent=indent)
+ self.printValueOfType(prefix, '(__imag %s)'%name, t.elementType, output=output,indent=indent)
+ elif isinstance(t, ArrayType):
+ for i in range(t.numElements):
+ # Access in this fashion as a hackish way to portably
+ # access vectors.
+ if t.isVector:
+ self.printValueOfType(prefix, '((%s*) &%s)[%d]'%(t.elementType,name,i), t.elementType, output=output,indent=indent)
+ else:
+ self.printValueOfType(prefix, '%s[%d]'%(name,i), t.elementType, output=output,indent=indent)
+ else:
+ raise NotImplementedError,'Cannot print value of type: "%s"'%(t,)
+
+ def checkTypeValues(self, nameLHS, nameRHS, t, output=None, indent=2):
+ prefix = 'foo'
+ if output is None:
+ output = self.output
+ if isinstance(t, BuiltinType):
+ print >>output, '%*sassert(%s == %s);' % (indent, '', nameLHS, nameRHS)
+ elif isinstance(t, RecordType):
+ for i,f in enumerate(t.fields):
+ if f.isPaddingBitField():
+ continue
+ self.checkTypeValues('%s.field%d'%(nameLHS,i), '%s.field%d'%(nameRHS,i),
+ f, output=output, indent=indent)
+ if t.isUnion:
+ break
+ elif isinstance(t, ComplexType):
+ self.checkTypeValues('(__real %s)'%nameLHS, '(__real %s)'%nameRHS, t.elementType, output=output,indent=indent)
+ self.checkTypeValues('(__imag %s)'%nameLHS, '(__imag %s)'%nameRHS, t.elementType, output=output,indent=indent)
+ elif isinstance(t, ArrayType):
+ for i in range(t.numElements):
+ # Access in this fashion as a hackish way to portably
+ # access vectors.
+ if t.isVector:
+ self.checkTypeValues('((%s*) &%s)[%d]'%(t.elementType,nameLHS,i),
+ '((%s*) &%s)[%d]'%(t.elementType,nameRHS,i),
+ t.elementType, output=output,indent=indent)
+ else:
+ self.checkTypeValues('%s[%d]'%(nameLHS,i), '%s[%d]'%(nameRHS,i),
+ t.elementType, output=output,indent=indent)
+ else:
+ raise NotImplementedError,'Cannot print value of type: "%s"'%(t,)
+
+import sys
+
+def main():
+ from optparse import OptionParser, OptionGroup
+ parser = OptionParser("%prog [options] {indices}")
+ parser.add_option("", "--mode", dest="mode",
+ help="autogeneration mode (random or linear) [default %default]",
+ type='choice', choices=('random','linear'), default='linear')
+ parser.add_option("", "--count", dest="count",
+ help="autogenerate COUNT functions according to MODE",
+ type=int, default=0)
+ parser.add_option("", "--min", dest="minIndex", metavar="N",
+ help="start autogeneration with the Nth function type [default %default]",
+ type=int, default=0)
+ parser.add_option("", "--max", dest="maxIndex", metavar="N",
+ help="maximum index for random autogeneration [default %default]",
+ type=int, default=10000000)
+ parser.add_option("", "--seed", dest="seed",
+ help="random number generator seed [default %default]",
+ type=int, default=1)
+ parser.add_option("", "--use-random-seed", dest="useRandomSeed",
+ help="use random value for initial random number generator seed",
+ action='store_true', default=False)
+ parser.add_option("-o", "--output", dest="output", metavar="FILE",
+ help="write output to FILE [default %default]",
+ type=str, default='-')
+ parser.add_option("-O", "--output-header", dest="outputHeader", metavar="FILE",
+ help="write header file for output to FILE [default %default]",
+ type=str, default=None)
+ parser.add_option("-T", "--output-tests", dest="outputTests", metavar="FILE",
+ help="write function tests to FILE [default %default]",
+ type=str, default=None)
+ parser.add_option("-D", "--output-driver", dest="outputDriver", metavar="FILE",
+ help="write test driver to FILE [default %default]",
+ type=str, default=None)
+ parser.add_option("", "--test-layout", dest="testLayout", metavar="FILE",
+ help="test structure layout",
+ action='store_true', default=False)
+
+ group = OptionGroup(parser, "Type Enumeration Options")
+ # Builtins - Ints
+ group.add_option("", "--no-char", dest="useChar",
+ help="do not generate char types",
+ action="store_false", default=True)
+ group.add_option("", "--no-short", dest="useShort",
+ help="do not generate short types",
+ action="store_false", default=True)
+ group.add_option("", "--no-int", dest="useInt",
+ help="do not generate int types",
+ action="store_false", default=True)
+ group.add_option("", "--no-long", dest="useLong",
+ help="do not generate long types",
+ action="store_false", default=True)
+ group.add_option("", "--no-long-long", dest="useLongLong",
+ help="do not generate long long types",
+ action="store_false", default=True)
+ group.add_option("", "--no-unsigned", dest="useUnsigned",
+ help="do not generate unsigned integer types",
+ action="store_false", default=True)
+
+ # Other builtins
+ group.add_option("", "--no-bool", dest="useBool",
+ help="do not generate bool types",
+ action="store_false", default=True)
+ group.add_option("", "--no-float", dest="useFloat",
+ help="do not generate float types",
+ action="store_false", default=True)
+ group.add_option("", "--no-double", dest="useDouble",
+ help="do not generate double types",
+ action="store_false", default=True)
+ group.add_option("", "--no-long-double", dest="useLongDouble",
+ help="do not generate long double types",
+ action="store_false", default=True)
+ group.add_option("", "--no-void-pointer", dest="useVoidPointer",
+ help="do not generate void* types",
+ action="store_false", default=True)
+
+ # Derived types
+ group.add_option("", "--no-array", dest="useArray",
+ help="do not generate record types",
+ action="store_false", default=True)
+ group.add_option("", "--no-complex", dest="useComplex",
+ help="do not generate complex types",
+ action="store_false", default=True)
+ group.add_option("", "--no-record", dest="useRecord",
+ help="do not generate record types",
+ action="store_false", default=True)
+ group.add_option("", "--no-union", dest="recordUseUnion",
+ help="do not generate union types",
+ action="store_false", default=True)
+ group.add_option("", "--no-vector", dest="useVector",
+ help="do not generate vector types",
+ action="store_false", default=True)
+ group.add_option("", "--no-bit-field", dest="useBitField",
+ help="do not generate bit-field record members",
+ action="store_false", default=True)
+ group.add_option("", "--no-builtins", dest="useBuiltins",
+ help="do not use any types",
+ action="store_false", default=True)
+
+ # Tuning
+ group.add_option("", "--no-function-return", dest="functionUseReturn",
+ help="do not generate return types for functions",
+ action="store_false", default=True)
+ group.add_option("", "--vector-types", dest="vectorTypes",
+ help="comma separated list of vector types (e.g., v2i32) [default %default]",
+ action="store", type=str, default='v2i16, v1i64, v2i32, v4i16, v8i8, v2f32, v2i64, v4i32, v8i16, v16i8, v2f64, v4f32, v16f32', metavar="N")
+ group.add_option("", "--bit-fields", dest="bitFields",
+ help="comma separated list 'type:width' bit-field specifiers [default %default]",
+ action="store", type=str, default="char:0,char:4,unsigned:0,unsigned:4,unsigned:13,unsigned:24")
+ group.add_option("", "--max-args", dest="functionMaxArgs",
+ help="maximum number of arguments per function [default %default]",
+ action="store", type=int, default=4, metavar="N")
+ group.add_option("", "--max-array", dest="arrayMaxSize",
+ help="maximum array size [default %default]",
+ action="store", type=int, default=4, metavar="N")
+ group.add_option("", "--max-record", dest="recordMaxSize",
+ help="maximum number of fields per record [default %default]",
+ action="store", type=int, default=4, metavar="N")
+ group.add_option("", "--max-record-depth", dest="recordMaxDepth",
+ help="maximum nested structure depth [default %default]",
+ action="store", type=int, default=None, metavar="N")
+ parser.add_option_group(group)
+ (opts, args) = parser.parse_args()
+
+ if not opts.useRandomSeed:
+ random.seed(opts.seed)
+
+ # Contruct type generator
+ builtins = []
+ if opts.useBuiltins:
+ ints = []
+ if opts.useChar: ints.append(('char',1))
+ if opts.useShort: ints.append(('short',2))
+ if opts.useInt: ints.append(('int',4))
+ # FIXME: Wrong size.
+ if opts.useLong: ints.append(('long',4))
+ if opts.useLongLong: ints.append(('long long',8))
+ if opts.useUnsigned:
+ ints = ([('unsigned %s'%i,s) for i,s in ints] +
+ [('signed %s'%i,s) for i,s in ints])
+ builtins.extend(ints)
+
+ if opts.useBool: builtins.append(('_Bool',1))
+ if opts.useFloat: builtins.append(('float',4))
+ if opts.useDouble: builtins.append(('double',8))
+ if opts.useLongDouble: builtins.append(('long double',16))
+ # FIXME: Wrong size.
+ if opts.useVoidPointer: builtins.append(('void*',4))
+
+ btg = FixedTypeGenerator([BuiltinType(n,s) for n,s in builtins])
+
+ bitfields = []
+ for specifier in opts.bitFields.split(','):
+ if not specifier.strip():
+ continue
+ name,width = specifier.strip().split(':', 1)
+ bitfields.append(BuiltinType(name,None,int(width)))
+ bftg = FixedTypeGenerator(bitfields)
+
+ charType = BuiltinType('char',1)
+ shortType = BuiltinType('short',2)
+ intType = BuiltinType('int',4)
+ longlongType = BuiltinType('long long',8)
+ floatType = BuiltinType('float',4)
+ doubleType = BuiltinType('double',8)
+ sbtg = FixedTypeGenerator([charType, intType, floatType, doubleType])
+
+ atg = AnyTypeGenerator()
+ artg = AnyTypeGenerator()
+ def makeGenerator(atg, subgen, subfieldgen, useRecord, useArray, useBitField):
+ atg.addGenerator(btg)
+ if useBitField and opts.useBitField:
+ atg.addGenerator(bftg)
+ if useRecord and opts.useRecord:
+ assert subgen
+ atg.addGenerator(RecordTypeGenerator(subfieldgen, opts.recordUseUnion,
+ opts.recordMaxSize))
+ if opts.useComplex:
+ # FIXME: Allow overriding builtins here
+ atg.addGenerator(ComplexTypeGenerator(sbtg))
+ if useArray and opts.useArray:
+ assert subgen
+ atg.addGenerator(ArrayTypeGenerator(subgen, opts.arrayMaxSize))
+ if opts.useVector:
+ vTypes = []
+ for i,t in enumerate(opts.vectorTypes.split(',')):
+ m = re.match('v([1-9][0-9]*)([if][1-9][0-9]*)', t.strip())
+ if not m:
+ parser.error('Invalid vector type: %r' % t)
+ count,kind = m.groups()
+ count = int(count)
+ type = { 'i8' : charType,
+ 'i16' : shortType,
+ 'i32' : intType,
+ 'i64' : longlongType,
+ 'f32' : floatType,
+ 'f64' : doubleType,
+ }.get(kind)
+ if not type:
+ parser.error('Invalid vector type: %r' % t)
+ vTypes.append(ArrayType(i, True, type, count * type.size))
+
+ atg.addGenerator(FixedTypeGenerator(vTypes))
+
+ if opts.recordMaxDepth is None:
+ # Fully recursive, just avoid top-level arrays.
+ subFTG = AnyTypeGenerator()
+ subTG = AnyTypeGenerator()
+ atg = AnyTypeGenerator()
+ makeGenerator(subFTG, atg, atg, True, True, True)
+ makeGenerator(subTG, atg, subFTG, True, True, False)
+ makeGenerator(atg, subTG, subFTG, True, False, False)
+ else:
+ # Make a chain of type generators, each builds smaller
+ # structures.
+ base = AnyTypeGenerator()
+ fbase = AnyTypeGenerator()
+ makeGenerator(base, None, None, False, False, False)
+ makeGenerator(fbase, None, None, False, False, True)
+ for i in range(opts.recordMaxDepth):
+ n = AnyTypeGenerator()
+ fn = AnyTypeGenerator()
+ makeGenerator(n, base, fbase, True, True, False)
+ makeGenerator(fn, base, fbase, True, True, True)
+ base = n
+ fbase = fn
+ atg = AnyTypeGenerator()
+ makeGenerator(atg, base, fbase, True, False, False)
+
+ if opts.testLayout:
+ ftg = atg
+ else:
+ ftg = FunctionTypeGenerator(atg, opts.functionUseReturn, opts.functionMaxArgs)
+
+ # Override max,min,count if finite
+ if opts.maxIndex is None:
+ if ftg.cardinality is aleph0:
+ opts.maxIndex = 10000000
+ else:
+ opts.maxIndex = ftg.cardinality
+ opts.maxIndex = min(opts.maxIndex, ftg.cardinality)
+ opts.minIndex = max(0,min(opts.maxIndex-1, opts.minIndex))
+ if not opts.mode=='random':
+ opts.count = min(opts.count, opts.maxIndex-opts.minIndex)
+
+ if opts.output=='-':
+ output = sys.stdout
+ else:
+ output = open(opts.output,'w')
+ atexit.register(lambda: output.close())
+
+ outputHeader = None
+ if opts.outputHeader:
+ outputHeader = open(opts.outputHeader,'w')
+ atexit.register(lambda: outputHeader.close())
+
+ outputTests = None
+ if opts.outputTests:
+ outputTests = open(opts.outputTests,'w')
+ atexit.register(lambda: outputTests.close())
+
+ outputDriver = None
+ if opts.outputDriver:
+ outputDriver = open(opts.outputDriver,'w')
+ atexit.register(lambda: outputDriver.close())
+
+ info = ''
+ info += '// %s\n'%(' '.join(sys.argv),)
+ info += '// Generated: %s\n'%(time.strftime('%Y-%m-%d %H:%M'),)
+ info += '// Cardinality of function generator: %s\n'%(ftg.cardinality,)
+ info += '// Cardinality of type generator: %s\n'%(atg.cardinality,)
+
+ if opts.testLayout:
+ info += '\n#include <stdio.h>'
+
+ P = TypePrinter(output,
+ outputHeader=outputHeader,
+ outputTests=outputTests,
+ outputDriver=outputDriver,
+ headerName=opts.outputHeader,
+ info=info)
+
+ def write(N):
+ try:
+ FT = ftg.get(N)
+ except RuntimeError,e:
+ if e.args[0]=='maximum recursion depth exceeded':
+ print >>sys.stderr,'WARNING: Skipped %d, recursion limit exceeded (bad arguments?)'%(N,)
+ return
+ raise
+ if opts.testLayout:
+ P.writeLayoutTest(N, FT)
+ else:
+ P.writeFunction(N, FT)
+
+ if args:
+ [write(int(a)) for a in args]
+
+ for i in range(opts.count):
+ if opts.mode=='linear':
+ index = opts.minIndex + i
+ else:
+ index = opts.minIndex + int((opts.maxIndex-opts.minIndex) * random.random())
+ write(index)
+
+ P.finish()
+
+if __name__=='__main__':
+ main()
+
diff --git a/utils/ABITest/Enumeration.py b/utils/ABITest/Enumeration.py
new file mode 100644
index 000000000000..47e47026db08
--- /dev/null
+++ b/utils/ABITest/Enumeration.py
@@ -0,0 +1,276 @@
+"""Utilities for enumeration of finite and countably infinite sets.
+"""
+###
+# Countable iteration
+
+# Simplifies some calculations
+class Aleph0(int):
+ _singleton = None
+ def __new__(type):
+ if type._singleton is None:
+ type._singleton = int.__new__(type)
+ return type._singleton
+ def __repr__(self): return '<aleph0>'
+ def __str__(self): return 'inf'
+
+ def __cmp__(self, b):
+ return 1
+
+ def __sub__(self, b):
+ raise ValueError,"Cannot subtract aleph0"
+ __rsub__ = __sub__
+
+ def __add__(self, b):
+ return self
+ __radd__ = __add__
+
+ def __mul__(self, b):
+ if b == 0: return b
+ return self
+ __rmul__ = __mul__
+
+ def __floordiv__(self, b):
+ if b == 0: raise ZeroDivisionError
+ return self
+ __rfloordiv__ = __floordiv__
+ __truediv__ = __floordiv__
+ __rtuediv__ = __floordiv__
+ __div__ = __floordiv__
+ __rdiv__ = __floordiv__
+
+ def __pow__(self, b):
+ if b == 0: return 1
+ return self
+aleph0 = Aleph0()
+
+def base(line):
+ return line*(line+1)//2
+
+def pairToN((x,y)):
+ line,index = x+y,y
+ return base(line)+index
+
+def getNthPairInfo(N):
+ # Avoid various singularities
+ if N==0:
+ return (0,0)
+
+ # Gallop to find bounds for line
+ line = 1
+ next = 2
+ while base(next)<=N:
+ line = next
+ next = line << 1
+
+ # Binary search for starting line
+ lo = line
+ hi = line<<1
+ while lo + 1 != hi:
+ #assert base(lo) <= N < base(hi)
+ mid = (lo + hi)>>1
+ if base(mid)<=N:
+ lo = mid
+ else:
+ hi = mid
+
+ line = lo
+ return line, N - base(line)
+
+def getNthPair(N):
+ line,index = getNthPairInfo(N)
+ return (line - index, index)
+
+def getNthPairBounded(N,W=aleph0,H=aleph0,useDivmod=False):
+ """getNthPairBounded(N, W, H) -> (x, y)
+
+ Return the N-th pair such that 0 <= x < W and 0 <= y < H."""
+
+ if W <= 0 or H <= 0:
+ raise ValueError,"Invalid bounds"
+ elif N >= W*H:
+ raise ValueError,"Invalid input (out of bounds)"
+
+ # Simple case...
+ if W is aleph0 and H is aleph0:
+ return getNthPair(N)
+
+ # Otherwise simplify by assuming W < H
+ if H < W:
+ x,y = getNthPairBounded(N,H,W,useDivmod=useDivmod)
+ return y,x
+
+ if useDivmod:
+ return N%W,N//W
+ else:
+ # Conceptually we want to slide a diagonal line across a
+ # rectangle. This gives more interesting results for large
+ # bounds than using divmod.
+
+ # If in lower left, just return as usual
+ cornerSize = base(W)
+ if N < cornerSize:
+ return getNthPair(N)
+
+ # Otherwise if in upper right, subtract from corner
+ if H is not aleph0:
+ M = W*H - N - 1
+ if M < cornerSize:
+ x,y = getNthPair(M)
+ return (W-1-x,H-1-y)
+
+ # Otherwise, compile line and index from number of times we
+ # wrap.
+ N = N - cornerSize
+ index,offset = N%W,N//W
+ # p = (W-1, 1+offset) + (-1,1)*index
+ return (W-1-index, 1+offset+index)
+def getNthPairBoundedChecked(N,W=aleph0,H=aleph0,useDivmod=False,GNP=getNthPairBounded):
+ x,y = GNP(N,W,H,useDivmod)
+ assert 0 <= x < W and 0 <= y < H
+ return x,y
+
+def getNthNTuple(N, W, H=aleph0, useLeftToRight=False):
+ """getNthNTuple(N, W, H) -> (x_0, x_1, ..., x_W)
+
+ Return the N-th W-tuple, where for 0 <= x_i < H."""
+
+ if useLeftToRight:
+ elts = [None]*W
+ for i in range(W):
+ elts[i],N = getNthPairBounded(N, H)
+ return tuple(elts)
+ else:
+ if W==0:
+ return ()
+ elif W==1:
+ return (N,)
+ elif W==2:
+ return getNthPairBounded(N, H, H)
+ else:
+ LW,RW = W//2, W - (W//2)
+ L,R = getNthPairBounded(N, H**LW, H**RW)
+ return (getNthNTuple(L,LW,H=H,useLeftToRight=useLeftToRight) +
+ getNthNTuple(R,RW,H=H,useLeftToRight=useLeftToRight))
+def getNthNTupleChecked(N, W, H=aleph0, useLeftToRight=False, GNT=getNthNTuple):
+ t = GNT(N,W,H,useLeftToRight)
+ assert len(t) == W
+ for i in t:
+ assert i < H
+ return t
+
+def getNthTuple(N, maxSize=aleph0, maxElement=aleph0, useDivmod=False, useLeftToRight=False):
+ """getNthTuple(N, maxSize, maxElement) -> x
+
+ Return the N-th tuple where len(x) < maxSize and for y in x, 0 <=
+ y < maxElement."""
+
+ # All zero sized tuples are isomorphic, don't ya know.
+ if N == 0:
+ return ()
+ N -= 1
+ if maxElement is not aleph0:
+ if maxSize is aleph0:
+ raise NotImplementedError,'Max element size without max size unhandled'
+ bounds = [maxElement**i for i in range(1, maxSize+1)]
+ S,M = getNthPairVariableBounds(N, bounds)
+ else:
+ S,M = getNthPairBounded(N, maxSize, useDivmod=useDivmod)
+ return getNthNTuple(M, S+1, maxElement, useLeftToRight=useLeftToRight)
+def getNthTupleChecked(N, maxSize=aleph0, maxElement=aleph0,
+ useDivmod=False, useLeftToRight=False, GNT=getNthTuple):
+ # FIXME: maxsize is inclusive
+ t = GNT(N,maxSize,maxElement,useDivmod,useLeftToRight)
+ assert len(t) <= maxSize
+ for i in t:
+ assert i < maxElement
+ return t
+
+def getNthPairVariableBounds(N, bounds):
+ """getNthPairVariableBounds(N, bounds) -> (x, y)
+
+ Given a finite list of bounds (which may be finite or aleph0),
+ return the N-th pair such that 0 <= x < len(bounds) and 0 <= y <
+ bounds[x]."""
+
+ if not bounds:
+ raise ValueError,"Invalid bounds"
+ if not (0 <= N < sum(bounds)):
+ raise ValueError,"Invalid input (out of bounds)"
+
+ level = 0
+ active = range(len(bounds))
+ active.sort(key=lambda i: bounds[i])
+ prevLevel = 0
+ for i,index in enumerate(active):
+ level = bounds[index]
+ W = len(active) - i
+ if level is aleph0:
+ H = aleph0
+ else:
+ H = level - prevLevel
+ levelSize = W*H
+ if N<levelSize: # Found the level
+ idelta,delta = getNthPairBounded(N, W, H)
+ return active[i+idelta],prevLevel+delta
+ else:
+ N -= levelSize
+ prevLevel = level
+ else:
+ raise RuntimError,"Unexpected loop completion"
+
+def getNthPairVariableBoundsChecked(N, bounds, GNVP=getNthPairVariableBounds):
+ x,y = GNVP(N,bounds)
+ assert 0 <= x < len(bounds) and 0 <= y < bounds[x]
+ return (x,y)
+
+###
+
+def testPairs():
+ W = 3
+ H = 6
+ a = [[' ' for x in range(10)] for y in range(10)]
+ b = [[' ' for x in range(10)] for y in range(10)]
+ for i in range(min(W*H,40)):
+ x,y = getNthPairBounded(i,W,H)
+ x2,y2 = getNthPairBounded(i,W,H,useDivmod=True)
+ print i,(x,y),(x2,y2)
+ a[y][x] = '%2d'%i
+ b[y2][x2] = '%2d'%i
+
+ print '-- a --'
+ for ln in a[::-1]:
+ if ''.join(ln).strip():
+ print ' '.join(ln)
+ print '-- b --'
+ for ln in b[::-1]:
+ if ''.join(ln).strip():
+ print ' '.join(ln)
+
+def testPairsVB():
+ bounds = [2,2,4,aleph0,5,aleph0]
+ a = [[' ' for x in range(15)] for y in range(15)]
+ b = [[' ' for x in range(15)] for y in range(15)]
+ for i in range(min(sum(bounds),40)):
+ x,y = getNthPairVariableBounds(i, bounds)
+ print i,(x,y)
+ a[y][x] = '%2d'%i
+
+ print '-- a --'
+ for ln in a[::-1]:
+ if ''.join(ln).strip():
+ print ' '.join(ln)
+
+###
+
+# Toggle to use checked versions of enumeration routines.
+if False:
+ getNthPairVariableBounds = getNthPairVariableBoundsChecked
+ getNthPairBounded = getNthPairBoundedChecked
+ getNthNTuple = getNthNTupleChecked
+ getNthTuple = getNthTupleChecked
+
+if __name__ == '__main__':
+ testPairs()
+
+ testPairsVB()
+
diff --git a/utils/ABITest/Makefile.test.common b/utils/ABITest/Makefile.test.common
new file mode 100644
index 000000000000..3c208adf0c54
--- /dev/null
+++ b/utils/ABITest/Makefile.test.common
@@ -0,0 +1,170 @@
+# -*- Makefile -*-
+
+# Usage: make test.N.report
+#
+# COUNT can be over-ridden to change the number of tests generated per
+# file, and TESTARGS is used to change the type generation. Make sure
+# to 'make clean' after changing either of these parameters.
+
+TESTARGS := --no-unsigned --no-vector --no-complex --no-bool
+
+COUNT := 1
+TIMEOUT := 5
+
+CFLAGS := -std=gnu99
+
+X_COMPILER := gcc
+X_LL_CFLAGS := -emit-llvm -S
+Y_COMPILER := clang
+Y_LL_CFLAGS := -emit-llvm -S
+CC := gcc
+
+###
+
+ABITESTGEN := ../ABITestGen.py
+
+ifndef VERBOSE
+ Verb := @
+endif
+
+.PHONY: test.%.report
+test.%.report: temps/test.%.xx.diff temps/test.%.xy.diff temps/test.%.yx.diff temps/test.%.yy.diff
+ @ok=1;\
+ for t in $^; do \
+ if [ -s $$t ]; then \
+ echo "TEST $*: $$t failed"; \
+ ok=0;\
+ fi; \
+ done; \
+ if [ $$ok -eq 1 ]; then \
+ true; \
+ else \
+ false; \
+ fi
+
+
+.PHONY: test.%.defs-report
+test.%.defs-report: temps/test.%.defs.diff
+ @for t in $^; do \
+ if [ -s $$t ]; then \
+ echo "TEST $*: $$t failed"; \
+ cat $$t; \
+ fi; \
+ done
+
+.PHONY: test.%.build
+test.%.build: temps/test.%.ref temps/test.%.xx temps/test.%.xy temps/test.%.yx temps/test.%.yy temps/test.%.x.defs temps/test.%.y.defs
+ @true
+
+###
+
+# Diffs and output
+
+.PRECIOUS: temps/.dir
+
+.PRECIOUS: temps/test.%.xx.diff
+temps/test.%.xx.diff: temps/test.%.ref.out temps/test.%.xx.out
+ $(Verb) diff $^ > $@ || true
+.PRECIOUS: temps/test.%.xy.diff
+temps/test.%.xy.diff: temps/test.%.ref.out temps/test.%.xy.out
+ $(Verb) diff $^ > $@ || true
+.PRECIOUS: temps/test.%.yx.diff
+temps/test.%.yx.diff: temps/test.%.ref.out temps/test.%.yx.out
+ $(Verb) diff $^ > $@ || true
+.PRECIOUS: temps/test.%.yy.diff
+temps/test.%.yy.diff: temps/test.%.ref.out temps/test.%.yy.out
+ $(Verb) diff $^ > $@ || true
+.PRECIOUS: temps/test.%.defs.diff
+temps/test.%.defs.diff: temps/test.%.x.defs temps/test.%.y.defs
+ $(Verb) zipdifflines \
+ --replace "%struct.T[0-9]+" "%struct.s" \
+ --replace "%union.T[0-9]+" "%struct.s" \
+ --replace "byval align [0-9]+" "byval" \
+ $^ > $@
+
+.PRECIOUS: temps/test.%.out
+temps/test.%.out: temps/test.%
+ -$(Verb) ./$< > $@
+
+# Executables
+
+.PRECIOUS: temps/test.%.ref
+temps/test.%.ref: temps/test.%.driver.ref.o temps/test.%.a.ref.o temps/test.%.b.ref.o
+ $(Verb) $(CC) $(CFLAGS) $(CC_CFLAGS) -O3 -o $@ $^
+.PRECIOUS: temps/test.%.xx
+temps/test.%.xx: temps/test.%.driver.ref.o temps/test.%.a.x.o temps/test.%.b.x.o
+ $(Verb) $(CC) $(CFLAGS) $(CC_CFLAGS) -O3 -o $@ $^
+.PRECIOUS: temps/test.%.xy
+temps/test.%.xy: temps/test.%.driver.ref.o temps/test.%.a.x.o temps/test.%.b.y.o
+ $(Verb) $(CC) $(CFLAGS) $(CC_CFLAGS) -O3 -o $@ $^
+.PRECIOUS: temps/test.%.yx
+temps/test.%.yx: temps/test.%.driver.ref.o temps/test.%.a.y.o temps/test.%.b.x.o
+ $(Verb) $(CC) $(CFLAGS) $(CC_CFLAGS) -O3 -o $@ $^
+.PRECIOUS: temps/test.%.yy
+temps/test.%.yy: temps/test.%.driver.ref.o temps/test.%.a.y.o temps/test.%.b.y.o
+ $(Verb) $(CC) $(CFLAGS) $(CC_CFLAGS) -O3 -o $@ $^
+
+# Object files
+
+.PRECIOUS: temps/test.%.ref.o
+temps/test.%.ref.o: inputs/test.%.c temps/.dir
+ $(Verb) $(CC) -c $(CFLAGS) $(CC_CFLAGS) -o $@ $<
+.PRECIOUS: temps/test.%.x.o
+temps/test.%.x.o: inputs/test.%.c temps/.dir
+ $(Verb) $(X_COMPILER) -c $(CFLAGS) $(X_CFLAGS) -o $@ $<
+.PRECIOUS: temps/test.%.y.o
+temps/test.%.y.o: inputs/test.%.c temps/.dir
+ $(Verb) $(Y_COMPILER) -c $(CFLAGS) $(Y_CFLAGS) -o $@ $<
+
+.PRECIOUS: temps/test.%.x.defs
+temps/test.%.x.defs: temps/test.%.a.x.ll temps/.dir
+ -$(Verb) -grep '^define ' $< > $@
+.PRECIOUS: temps/test.%.y.defs
+temps/test.%.y.defs: temps/test.%.a.y.ll temps/.dir
+ -$(Verb) -grep '^define ' $< > $@
+
+.PRECIOUS: temps/test.%.a.x.ll
+temps/test.%.a.x.ll: inputs/test.%.a.c temps/.dir
+ $(Verb) $(X_COMPILER) $(CFLAGS) $(X_LL_CFLAGS) $(X_CFLAGS) -o $@ $<
+.PRECIOUS: temps/test.%.b.x.ll
+temps/test.%.b.x.ll: inputs/test.%.b.c temps/.dir
+ $(Verb) $(X_COMPILER) $(CFLAGS) $(X_LL_CFLAGS) $(X_CFLAGS) -o $@ $<
+.PRECIOUS: temps/test.%.a.y.ll
+temps/test.%.a.y.ll: inputs/test.%.a.c temps/.dir
+ $(Verb) $(Y_COMPILER) $(CFLAGS) $(Y_LL_CFLAGS) $(Y_CFLAGS) -o $@ $<
+.PRECIOUS: temps/test.%.b.y.ll
+temps/test.%.b.y.ll: inputs/test.%.b.c temps/.dir
+ $(Verb) $(Y_COMPILER) $(CFLAGS) $(Y_LL_CFLAGS) $(Y_CFLAGS) -o $@ $<
+
+# Input generation
+
+.PHONY: test.%.top
+test.%.top: inputs/test.%.a.c inputs/test.%.b.c inputs/test.%.driver.c
+ @true
+
+.PRECIOUS: inputs/test.%.a.c inputs/test.%.b.c inputs/test.%.driver.c
+inputs/test.%.a.c: test.%.generate
+ @true
+inputs/test.%.b.c: test.%.generate
+ @true
+inputs/test.%.driver.c: test.%.generate
+ @true
+
+.PHONY: test.%.generate
+.PRECIOUS: inputs/.dir
+test.%.generate: $(ABITESTGEN) inputs/.dir
+ $(Verb) $(ABITESTGEN) $(TESTARGS) -o inputs/test.$*.a.c -T inputs/test.$*.b.c -D inputs/test.$*.driver.c --min=$(shell expr $* '*' $(COUNT)) --count=$(COUNT)
+
+# Cleaning
+
+clean-temps:
+ $(Verb) rm -rf temps
+
+clean:
+ $(Verb) rm -rf temps inputs
+
+# Etc.
+
+%/.dir:
+ $(Verb) mkdir -p $* > /dev/null
+ $(Verb) $(DATE) > $@
diff --git a/utils/ABITest/TypeGen.py b/utils/ABITest/TypeGen.py
new file mode 100644
index 000000000000..d5678db6a0e8
--- /dev/null
+++ b/utils/ABITest/TypeGen.py
@@ -0,0 +1,381 @@
+"""Flexible enumeration of C types."""
+
+from Enumeration import *
+
+# TODO:
+
+# - struct improvements (flexible arrays, packed &
+# unpacked, alignment)
+# - objective-c qualified id
+# - anonymous / transparent unions
+# - VLAs
+# - block types
+# - K&R functions
+# - pass arguments of different types (test extension, transparent union)
+# - varargs
+
+###
+# Actual type types
+
+class Type:
+ def isBitField(self):
+ return False
+
+ def isPaddingBitField(self):
+ return False
+
+class BuiltinType(Type):
+ def __init__(self, name, size, bitFieldSize=None):
+ self.name = name
+ self.size = size
+ self.bitFieldSize = bitFieldSize
+
+ def isBitField(self):
+ return self.bitFieldSize is not None
+
+ def isPaddingBitField(self):
+ return self.bitFieldSize is 0
+
+ def getBitFieldSize(self):
+ assert self.isBitField()
+ return self.bitFieldSize
+
+ def sizeof(self):
+ return self.size
+
+ def __str__(self):
+ return self.name
+
+class RecordType(Type):
+ def __init__(self, index, isUnion, fields):
+ self.index = index
+ self.isUnion = isUnion
+ self.fields = fields
+ self.name = None
+
+ def __str__(self):
+ def getField(t):
+ if t.isBitField():
+ return "%s : %d;" % (t, t.getBitFieldSize())
+ else:
+ return "%s;" % t
+
+ return '%s { %s }'%(('struct','union')[self.isUnion],
+ ' '.join(map(getField, self.fields)))
+
+ def getTypedefDef(self, name, printer):
+ def getField((i, t)):
+ if t.isBitField():
+ if t.isPaddingBitField():
+ return '%s : 0;'%(printer.getTypeName(t),)
+ else:
+ return '%s field%d : %d;'%(printer.getTypeName(t),i,
+ t.getBitFieldSize())
+ else:
+ return '%s field%d;'%(printer.getTypeName(t),i)
+ fields = map(getField, enumerate(self.fields))
+ # Name the struct for more readable LLVM IR.
+ return 'typedef %s %s { %s } %s;'%(('struct','union')[self.isUnion],
+ name, ' '.join(fields), name)
+
+class ArrayType(Type):
+ def __init__(self, index, isVector, elementType, size):
+ if isVector:
+ # Note that for vectors, this is the size in bytes.
+ assert size > 0
+ else:
+ assert size is None or size >= 0
+ self.index = index
+ self.isVector = isVector
+ self.elementType = elementType
+ self.size = size
+ if isVector:
+ eltSize = self.elementType.sizeof()
+ assert not (self.size % eltSize)
+ self.numElements = self.size // eltSize
+ else:
+ self.numElements = self.size
+
+ def __str__(self):
+ if self.isVector:
+ return 'vector (%s)[%d]'%(self.elementType,self.size)
+ elif self.size is not None:
+ return '(%s)[%d]'%(self.elementType,self.size)
+ else:
+ return '(%s)[]'%(self.elementType,)
+
+ def getTypedefDef(self, name, printer):
+ elementName = printer.getTypeName(self.elementType)
+ if self.isVector:
+ return 'typedef %s %s __attribute__ ((vector_size (%d)));'%(elementName,
+ name,
+ self.size)
+ else:
+ if self.size is None:
+ sizeStr = ''
+ else:
+ sizeStr = str(self.size)
+ return 'typedef %s %s[%s];'%(elementName, name, sizeStr)
+
+class ComplexType(Type):
+ def __init__(self, index, elementType):
+ self.index = index
+ self.elementType = elementType
+
+ def __str__(self):
+ return '_Complex (%s)'%(self.elementType)
+
+ def getTypedefDef(self, name, printer):
+ return 'typedef _Complex %s %s;'%(printer.getTypeName(self.elementType), name)
+
+class FunctionType(Type):
+ def __init__(self, index, returnType, argTypes):
+ self.index = index
+ self.returnType = returnType
+ self.argTypes = argTypes
+
+ def __str__(self):
+ if self.returnType is None:
+ rt = 'void'
+ else:
+ rt = str(self.returnType)
+ if not self.argTypes:
+ at = 'void'
+ else:
+ at = ', '.join(map(str, self.argTypes))
+ return '%s (*)(%s)'%(rt, at)
+
+ def getTypedefDef(self, name, printer):
+ if self.returnType is None:
+ rt = 'void'
+ else:
+ rt = str(self.returnType)
+ if not self.argTypes:
+ at = 'void'
+ else:
+ at = ', '.join(map(str, self.argTypes))
+ return 'typedef %s (*%s)(%s);'%(rt, name, at)
+
+###
+# Type enumerators
+
+class TypeGenerator(object):
+ def __init__(self):
+ self.cache = {}
+
+ def setCardinality(self):
+ abstract
+
+ def get(self, N):
+ T = self.cache.get(N)
+ if T is None:
+ assert 0 <= N < self.cardinality
+ T = self.cache[N] = self.generateType(N)
+ return T
+
+ def generateType(self, N):
+ abstract
+
+class FixedTypeGenerator(TypeGenerator):
+ def __init__(self, types):
+ TypeGenerator.__init__(self)
+ self.types = types
+ self.setCardinality()
+
+ def setCardinality(self):
+ self.cardinality = len(self.types)
+
+ def generateType(self, N):
+ return self.types[N]
+
+class ComplexTypeGenerator(TypeGenerator):
+ def __init__(self, typeGen):
+ TypeGenerator.__init__(self)
+ self.typeGen = typeGen
+ self.setCardinality()
+
+ def setCardinality(self):
+ self.cardinality = self.typeGen.cardinality
+
+ def generateType(self, N):
+ return ComplexType(N, self.typeGen.get(N))
+
+class VectorTypeGenerator(TypeGenerator):
+ def __init__(self, typeGen, sizes):
+ TypeGenerator.__init__(self)
+ self.typeGen = typeGen
+ self.sizes = tuple(map(int,sizes))
+ self.setCardinality()
+
+ def setCardinality(self):
+ self.cardinality = len(self.sizes)*self.typeGen.cardinality
+
+ def generateType(self, N):
+ S,T = getNthPairBounded(N, len(self.sizes), self.typeGen.cardinality)
+ return ArrayType(N, True, self.typeGen.get(T), self.sizes[S])
+
+class FixedArrayTypeGenerator(TypeGenerator):
+ def __init__(self, typeGen, sizes):
+ TypeGenerator.__init__(self)
+ self.typeGen = typeGen
+ self.sizes = tuple(size)
+ self.setCardinality()
+
+ def setCardinality(self):
+ self.cardinality = len(self.sizes)*self.typeGen.cardinality
+
+ def generateType(self, N):
+ S,T = getNthPairBounded(N, len(self.sizes), self.typeGen.cardinality)
+ return ArrayType(N, false, self.typeGen.get(T), self.sizes[S])
+
+class ArrayTypeGenerator(TypeGenerator):
+ def __init__(self, typeGen, maxSize, useIncomplete=False, useZero=False):
+ TypeGenerator.__init__(self)
+ self.typeGen = typeGen
+ self.useIncomplete = useIncomplete
+ self.useZero = useZero
+ self.maxSize = int(maxSize)
+ self.W = useIncomplete + useZero + self.maxSize
+ self.setCardinality()
+
+ def setCardinality(self):
+ self.cardinality = self.W * self.typeGen.cardinality
+
+ def generateType(self, N):
+ S,T = getNthPairBounded(N, self.W, self.typeGen.cardinality)
+ if self.useIncomplete:
+ if S==0:
+ size = None
+ S = None
+ else:
+ S = S - 1
+ if S is not None:
+ if self.useZero:
+ size = S
+ else:
+ size = S + 1
+ return ArrayType(N, False, self.typeGen.get(T), size)
+
+class RecordTypeGenerator(TypeGenerator):
+ def __init__(self, typeGen, useUnion, maxSize):
+ TypeGenerator.__init__(self)
+ self.typeGen = typeGen
+ self.useUnion = bool(useUnion)
+ self.maxSize = int(maxSize)
+ self.setCardinality()
+
+ def setCardinality(self):
+ M = 1 + self.useUnion
+ if self.maxSize is aleph0:
+ S = aleph0 * self.typeGen.cardinality
+ else:
+ S = 0
+ for i in range(self.maxSize+1):
+ S += M * (self.typeGen.cardinality ** i)
+ self.cardinality = S
+
+ def generateType(self, N):
+ isUnion,I = False,N
+ if self.useUnion:
+ isUnion,I = (I&1),I>>1
+ fields = map(self.typeGen.get,getNthTuple(I,self.maxSize,self.typeGen.cardinality))
+ return RecordType(N, isUnion, fields)
+
+class FunctionTypeGenerator(TypeGenerator):
+ def __init__(self, typeGen, useReturn, maxSize):
+ TypeGenerator.__init__(self)
+ self.typeGen = typeGen
+ self.useReturn = useReturn
+ self.maxSize = maxSize
+ self.setCardinality()
+
+ def setCardinality(self):
+ if self.maxSize is aleph0:
+ S = aleph0 * self.typeGen.cardinality()
+ elif self.useReturn:
+ S = 0
+ for i in range(1,self.maxSize+1+1):
+ S += self.typeGen.cardinality ** i
+ else:
+ S = 0
+ for i in range(self.maxSize+1):
+ S += self.typeGen.cardinality ** i
+ self.cardinality = S
+
+ def generateType(self, N):
+ if self.useReturn:
+ # Skip the empty tuple
+ argIndices = getNthTuple(N+1, self.maxSize+1, self.typeGen.cardinality)
+ retIndex,argIndices = argIndices[0],argIndices[1:]
+ retTy = self.typeGen.get(retIndex)
+ else:
+ retTy = None
+ argIndices = getNthTuple(N, self.maxSize, self.typeGen.cardinality)
+ args = map(self.typeGen.get, argIndices)
+ return FunctionType(N, retTy, args)
+
+class AnyTypeGenerator(TypeGenerator):
+ def __init__(self):
+ TypeGenerator.__init__(self)
+ self.generators = []
+ self.bounds = []
+ self.setCardinality()
+ self._cardinality = None
+
+ def getCardinality(self):
+ if self._cardinality is None:
+ return aleph0
+ else:
+ return self._cardinality
+ def setCardinality(self):
+ self.bounds = [g.cardinality for g in self.generators]
+ self._cardinality = sum(self.bounds)
+ cardinality = property(getCardinality, None)
+
+ def addGenerator(self, g):
+ self.generators.append(g)
+ for i in range(100):
+ prev = self._cardinality
+ self._cardinality = None
+ for g in self.generators:
+ g.setCardinality()
+ self.setCardinality()
+ if (self._cardinality is aleph0) or prev==self._cardinality:
+ break
+ else:
+ raise RuntimeError,"Infinite loop in setting cardinality"
+
+ def generateType(self, N):
+ index,M = getNthPairVariableBounds(N, self.bounds)
+ return self.generators[index].get(M)
+
+def test():
+ fbtg = FixedTypeGenerator([BuiltinType('char', 4),
+ BuiltinType('char', 4, 0),
+ BuiltinType('int', 4, 5)])
+
+ fields1 = AnyTypeGenerator()
+ fields1.addGenerator( fbtg )
+
+ fields0 = AnyTypeGenerator()
+ fields0.addGenerator( fbtg )
+# fields0.addGenerator( RecordTypeGenerator(fields1, False, 4) )
+
+ btg = FixedTypeGenerator([BuiltinType('char', 4),
+ BuiltinType('int', 4)])
+
+ atg = AnyTypeGenerator()
+ atg.addGenerator( btg )
+ atg.addGenerator( RecordTypeGenerator(fields0, False, 4) )
+ print 'Cardinality:',atg.cardinality
+ for i in range(100):
+ if i == atg.cardinality:
+ try:
+ atg.get(i)
+ raise RuntimeError,"Cardinality was wrong"
+ except AssertionError:
+ break
+ print '%4d: %s'%(i, atg.get(i))
+
+if __name__ == '__main__':
+ test()
diff --git a/utils/ABITest/build-and-summarize-all.sh b/utils/ABITest/build-and-summarize-all.sh
new file mode 100755
index 000000000000..23e34a4669b6
--- /dev/null
+++ b/utils/ABITest/build-and-summarize-all.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+set -eu
+
+if [ $# != 1 ]; then
+ echo "usage: $0 <num-tests>"
+ exit 1
+fi
+
+for bits in 32 64; do
+ for kind in return-types single-args; do
+ echo "-- $kind-$bits --"
+ (cd $kind-$bits && ../build-and-summarize.sh $1)
+ done
+done
diff --git a/utils/ABITest/build-and-summarize.sh b/utils/ABITest/build-and-summarize.sh
new file mode 100755
index 000000000000..602728b79f91
--- /dev/null
+++ b/utils/ABITest/build-and-summarize.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+set -eu
+
+if [ $# != 1 ]; then
+ echo "usage: $0 <num-tests>"
+ exit 1
+fi
+
+dir=$(dirname $0)
+$dir/build.sh $1 &> /dev/null || true
+../summarize.sh $1 &> fails-x.txt
+cat fails-x.txt
+wc -l fails-x.txt
diff --git a/utils/ABITest/build.sh b/utils/ABITest/build.sh
new file mode 100755
index 000000000000..a50d14ab8d06
--- /dev/null
+++ b/utils/ABITest/build.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+set -eu
+
+if [ $# != 1 ]; then
+ echo "usage: $0 <num-tests>"
+ exit 1
+fi
+
+CPUS=2
+make -j $CPUS \
+ $(for i in $(seq 0 $1); do echo test.$i.report; done) -k
diff --git a/utils/ABITest/layout/Makefile b/utils/ABITest/layout/Makefile
new file mode 100644
index 000000000000..0520625fcf29
--- /dev/null
+++ b/utils/ABITest/layout/Makefile
@@ -0,0 +1,68 @@
+# Usage: make test.N.report
+#
+# COUNT can be over-ridden to change the number of tests generated per
+# file, and TESTARGS is used to change the type generation. Make sure
+# to 'make clean' after changing either of these parameters.
+
+ABITESTGEN := ../ABITestGen.py
+TESTARGS := --max-args 0 --test-layout
+COUNT := 1000
+TIMEOUT := 5
+
+CFLAGS := -std=gnu99
+
+X_COMPILER := llvm-gcc
+Y_COMPILER := clang
+CC := gcc
+
+ifeq (0, 0)
+X_CFLAGS := -m32
+Y_CFLAGS := -m32
+CC_CFLAGS := -m32
+else
+X_CFLAGS := -m64
+Y_CFLAGS := -m64
+CC_CFLAGS := -m64
+endif
+
+.PHONY: test.%.report
+test.%.report: test.%.x.diff test.%.y.diff
+ @for t in $^; do \
+ if [ -s $$t ]; then \
+ echo "TEST $*: $$t failed"; \
+ fi; \
+ done
+
+.PHONY: test.%.build
+test.%.build: test.%.ref test.%.x test.%.y
+ @true
+
+###
+
+.PRECIOUS: test.%.x.diff
+test.%.x.diff: test.%.ref.out test.%.x.out
+ -diff $^ > $@
+.PRECIOUS: test.%.y.diff
+test.%.y.diff: test.%.ref.out test.%.y.out
+ -diff $^ > $@
+
+.PRECIOUS: test.%.out
+test.%.out: test.%
+ -./$< > $@
+
+.PRECIOUS: test.%.ref
+test.%.ref: test.%.c
+ $(CC) $(CFLAGS) $(CC_CFLAGS) -o $@ $^
+.PRECIOUS: test.%.x
+test.%.x: test.%.c
+ $(X_COMPILER) $(CFLAGS) $(X_CFLAGS) -o $@ $^
+.PRECIOUS: test.%.y
+test.%.y: test.%.c
+ $(Y_COMPILER) $(CFLAGS) $(Y_CFLAGS) -o $@ $^
+
+.PRECIOUS: test.%.c
+test.%.c: $(ABITESTGEN)
+ $(ABITESTGEN) $(TESTARGS) -o $@ --min=$(shell expr $* '*' $(COUNT)) --count=$(COUNT)
+
+clean:
+ rm -f test.* *~
diff --git a/utils/ABITest/return-types-32/Makefile b/utils/ABITest/return-types-32/Makefile
new file mode 100644
index 000000000000..df1c53f1a166
--- /dev/null
+++ b/utils/ABITest/return-types-32/Makefile
@@ -0,0 +1,7 @@
+X_CFLAGS := -m32
+Y_CFLAGS := -m32
+CC_CFLAGS := -m32
+
+include ../Makefile.test.common
+
+TESTARGS += --max-args 0
diff --git a/utils/ABITest/return-types-64/Makefile b/utils/ABITest/return-types-64/Makefile
new file mode 100644
index 000000000000..9616e45cba94
--- /dev/null
+++ b/utils/ABITest/return-types-64/Makefile
@@ -0,0 +1,7 @@
+X_CFLAGS := -m64
+Y_CFLAGS := -m64
+CC_CFLAGS := -m64
+
+include ../Makefile.test.common
+
+TESTARGS += --max-args 0
diff --git a/utils/ABITest/single-args-32/Makefile b/utils/ABITest/single-args-32/Makefile
new file mode 100644
index 000000000000..9ff417fc29e5
--- /dev/null
+++ b/utils/ABITest/single-args-32/Makefile
@@ -0,0 +1,7 @@
+X_CFLAGS := -m32
+Y_CFLAGS := -m32
+CC_CFLAGS := -m32
+
+include ../Makefile.test.common
+
+TESTARGS += --no-function-return --max-args 1
diff --git a/utils/ABITest/single-args-64/Makefile b/utils/ABITest/single-args-64/Makefile
new file mode 100644
index 000000000000..b8acb70c1354
--- /dev/null
+++ b/utils/ABITest/single-args-64/Makefile
@@ -0,0 +1,13 @@
+# Usage: make test.N.report
+#
+# COUNT can be over-ridden to change the number of tests generated per
+# file, and TESTARGS is used to change the type generation. Make sure
+# to 'make clean' after changing either of these parameters.
+
+X_CFLAGS := -m64
+Y_CFLAGS := -m64
+CC_CFLAGS := -m64
+
+include ../Makefile.test.common
+
+TESTARGS += --no-function-return --max-args 1
diff --git a/utils/ABITest/summarize.sh b/utils/ABITest/summarize.sh
new file mode 100755
index 000000000000..3efb52bf7227
--- /dev/null
+++ b/utils/ABITest/summarize.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+set -eu
+
+if [ $# != 1 ]; then
+ echo "usage: $0 <num-tests>"
+ exit 1
+fi
+
+for i in $(seq 0 $1); do
+ if (! make test.$i.report &> /dev/null); then
+ echo "FAIL: $i";
+ fi;
+done
+
diff --git a/utils/CaptureCmd b/utils/CaptureCmd
new file mode 100755
index 000000000000..3bce357e12e8
--- /dev/null
+++ b/utils/CaptureCmd
@@ -0,0 +1,73 @@
+#!/usr/bin/python
+
+"""CaptureCmd - A generic tool for capturing information about the
+invocations of another program.
+
+Usage
+--
+1. Move the original tool to a safe known location.
+
+2. Link CaptureCmd to the original tool's location.
+
+3. Define CAPTURE_CMD_PROGRAM to the known location of the original
+tool; this must be an absolute path.
+
+4. Define CAPTURE_CMD_DIR to a directory to write invocation
+information to.
+"""
+
+import hashlib
+import os
+import sys
+import time
+
+def saveCaptureData(prefix, dir, object):
+ string = repr(object) + '\n'
+ key = hashlib.sha1(string).hexdigest()
+ path = os.path.join(dir,
+ prefix + key)
+ if not os.path.exists(path):
+ f = open(path, 'wb')
+ f.write(string)
+ f.close()
+ return prefix + key
+
+def main():
+ program = os.getenv('CAPTURE_CMD_PROGRAM')
+ dir = os.getenv('CAPTURE_CMD_DIR')
+ fallback = os.getenv('CAPTURE_CMD_FALLBACK')
+ if not program:
+ raise ValueError('CAPTURE_CMD_PROGRAM is not defined!')
+ if not dir:
+ raise ValueError('CAPTURE_CMD_DIR is not defined!')
+
+ # Make the output directory if it doesn't already exist.
+ if not os.path.exists(dir):
+ os.mkdir(dir, 0700)
+
+ # Get keys for various data.
+ env = os.environ.items()
+ env.sort()
+ envKey = saveCaptureData('env-', dir, env)
+ cwdKey = saveCaptureData('cwd-', dir, os.getcwd())
+ argvKey = saveCaptureData('argv-', dir, sys.argv)
+ entry = (time.time(), envKey, cwdKey, argvKey)
+ saveCaptureData('cmd-', dir, entry)
+
+ if fallback:
+ pid = os.fork()
+ if not pid:
+ os.execv(program, sys.argv)
+ os._exit(1)
+ else:
+ res = os.waitpid(pid, 0)
+ if not res:
+ os.execv(fallback, sys.argv)
+ os._exit(1)
+ os._exit(res)
+ else:
+ os.execv(program, sys.argv)
+ os._exit(1)
+
+if __name__ == '__main__':
+ main()
diff --git a/utils/CmpDriver b/utils/CmpDriver
new file mode 100755
index 000000000000..97c91a820915
--- /dev/null
+++ b/utils/CmpDriver
@@ -0,0 +1,194 @@
+#!/usr/bin/python
+
+import subprocess
+
+def splitArgs(s):
+ it = iter(s)
+ current = ''
+ inQuote = False
+ for c in it:
+ if c == '"':
+ if inQuote:
+ inQuote = False
+ yield current + '"'
+ else:
+ inQuote = True
+ current = '"'
+ elif inQuote:
+ if c == '\\':
+ current += c
+ current += it.next()
+ else:
+ current += c
+ elif not c.isspace():
+ yield c
+
+def insertMinimumPadding(a, b, dist):
+ """insertMinimumPadding(a,b) -> (a',b')
+
+ Return two lists of equal length, where some number of Nones have
+ been inserted into the shorter list such that sum(map(dist, a',
+ b')) is minimized.
+
+ Assumes dist(X, Y) -> int and non-negative.
+ """
+
+ # Yay for simplicity over complexity.
+
+ def extend(aElt, bElt, solution):
+ d0,(a0,b0) = solution
+ return d0 + dist(aElt,bElt), (([aElt]+a0),([bElt]+b0))
+
+ def f(a, b):
+ if len(a) == len(b):
+ return (sum(map(dist, a, b)), (a, b))
+
+ if not a or not b:
+ if not a:
+ a += [None] * len(b)
+ else:
+ b += [None] * len(a)
+ return (sum(map(dist, a, b)), (a, b))
+
+ if int(dist(a[0], b[0])) == 0:
+ # Non-negative condition implies maximum is satisfied
+ # taking this.
+ return extend(a[0], b[0], f(a[1:], b[1:]))
+
+ if len(a) < len(b):
+ return min(f([None] + a, b),
+ extend(a[0], b[0], f(a[1:], b[1:])))
+ else:
+ return min(f(a, [None] + b),
+ extend(a[0], b[0], f(a[1:], b[1:])))
+
+ return f(a, b)[1]
+
+class ZipperDiff(object):
+ """ZipperDiff - Simple (slow) diff only accomodating inserts."""
+
+ def __init__(self, a, b):
+ self.a = a
+ self.b = b
+
+ def dist(self, a, b):
+ return a != b
+
+ def getDiffs(self):
+ a,b = insertMinimumPadding(self.a, self.b, self.dist)
+ for aElt,bElt in zip(a,b):
+ if self.dist(aElt, bElt):
+ yield aElt,bElt
+
+class DriverZipperDiff(ZipperDiff):
+ def isTempFile(self, filename):
+ if filename[0] != '"' or filename[-1] != '"':
+ return False
+ return (filename.startswith('/tmp/', 1) or
+ filename.startswith('/var/', 1))
+
+ def dist(self, a, b):
+ if a and b and self.isTempFile(a) and self.isTempFile(b):
+ return 0
+ return super(DriverZipperDiff, self).dist(a,b)
+
+class CompileInfo:
+ def __init__(self, out, err, res):
+ self.commands = []
+
+ # Standard out isn't used for much.
+ self.stdout = out
+ self.stderr = ''
+
+ # FIXME: Compare error messages as well.
+ for ln in err.split('\n'):
+ if (ln == 'Using built-in specs.' or
+ ln.startswith('Target: ') or
+ ln.startswith('Configured with: ') or
+ ln.startswith('Thread model: ') or
+ ln.startswith('gcc version') or
+ ln.startswith('ccc version')):
+ pass
+ elif ln.strip().startswith('"'):
+ self.commands.append(list(splitArgs(ln)))
+ else:
+ self.stderr += ln + '\n'
+
+ self.stderr = self.stderr.strip()
+ self.exitCode = res
+
+def captureDriverInfo(cmd, args):
+ p = subprocess.Popen([cmd,'-###'] + args,
+ stdin=None,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ out,err = p.communicate()
+ res = p.wait()
+ return CompileInfo(out,err,res)
+
+def main():
+ import os, sys
+
+ args = sys.argv[1:]
+ driverA = os.getenv('DRIVER_A') or 'gcc'
+ driverB = os.getenv('DRIVER_B') or 'xcc'
+
+ infoA = captureDriverInfo(driverA, args)
+ infoB = captureDriverInfo(driverB, args)
+
+ differ = False
+
+ # Compare stdout.
+ if infoA.stdout != infoB.stdout:
+ print '-- STDOUT DIFFERS -'
+ print 'A: ',infoA.stdout
+ print 'B: ',infoB.stdout
+ differ = True
+
+ # Compare stderr.
+ if infoA.stderr != infoB.stderr:
+ print '-- STDERR DIFFERS -'
+ print 'A: ',infoA.stderr
+ print 'B: ',infoB.stderr
+ differ = True
+
+ # Compare commands.
+ for i,(a,b) in enumerate(map(None, infoA.commands, infoB.commands)):
+ if a is None:
+ print 'A MISSING:',' '.join(b)
+ differ = True
+ continue
+ elif b is None:
+ print 'B MISSING:',' '.join(a)
+ differ = True
+ continue
+
+ diff = DriverZipperDiff(a,b)
+ diffs = list(diff.getDiffs())
+ if diffs:
+ print '-- COMMAND %d DIFFERS -' % i
+ print 'A COMMAND:',' '.join(a)
+ print 'B COMMAND:',' '.join(b)
+ print
+ for i,(aElt,bElt) in enumerate(diffs):
+ if aElt is None:
+ print 'A missing: %s' % bElt
+ elif bElt is None:
+ print 'B missing: %s' % aElt
+ else:
+ print 'mismatch: A: %s' % aElt
+ print ' B: %s' % bElt
+ differ = True
+
+ # Compare result codes.
+ if infoA.exitCode != infoB.exitCode:
+ print '-- EXIT CODES DIFFER -'
+ print 'A: ',infoA.exitCode
+ print 'B: ',infoB.exitCode
+ differ = True
+
+ if differ:
+ sys.exit(1)
+
+if __name__ == '__main__':
+ main()
diff --git a/utils/FindSpecRefs b/utils/FindSpecRefs
new file mode 100755
index 000000000000..c74ca3d22883
--- /dev/null
+++ b/utils/FindSpecRefs
@@ -0,0 +1,910 @@
+#!/usr/bin/python
+
+import os
+import re
+import time
+from pprint import pprint
+
+###
+
+c99URL = 'http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf'
+c99TOC = [('Foreword', 'xi'),
+('Introduction', 'xiv'),
+('1. Scope', '1'),
+('2. Normative references', '2'),
+('3. Terms, definitions, and symbols', '3'),
+('4. Conformance', '7'),
+('5. Environment', '9'),
+('5.1 Conceptual models', '9'),
+('5.1.1 Translation environment', '9'),
+('5.1.2 Execution environments', '11'),
+('5.2 Environmental considerations', '17'),
+('5.2.1 Character sets', '17'),
+('5.2.2 Character display semantics', '19'),
+('5.2.3 Signals and interrupts', '20'),
+('5.2.4 Environmental limits', '20'),
+('6. Language', '29'),
+('6.1 Notation', '29'),
+('6.2 Concepts', '29'),
+('6.2.1 Scopes of identifiers', '29'),
+('6.2.2 Linkages of identifiers', '30'),
+('6.2.3 Name spaces of identifiers', '31'),
+('6.2.4 Storage durations of objects', '32'),
+('6.2.5 Types', '33'),
+('6.2.6 Representations of types', '37'),
+('6.2.7 Compatible type and composite type', '40'),
+('6.3 Conversions', '42'),
+('6.3.1 Arithmetic operands', '42'),
+('6.3.2 Other operands', '46'),
+('6.4 Lexical elements', '49'),
+('6.4.1 Keywords', '50'),
+('6.4.2 Identifiers', '51'),
+('6.4.3 Universal character names', '53'),
+('6.4.4 Constants', '54'),
+('6.4.5 String literals', '62'),
+('6.4.6 Punctuators', '63'),
+('6.4.7 Header names', '64'),
+('6.4.8 Preprocessing numbers', '65'),
+('6.4.9 Comments', '66'),
+('6.5 Expressions', '67'),
+('6.5.1 Primary expressions', '69'),
+('6.5.2 Postfix operators', '69'),
+('6.5.3 Unary operators', '78'),
+('6.5.4 Cast operators', '81'),
+('6.5.5 Multiplicative operators', '82'),
+('6.5.6 Additive operators', '82'),
+('6.5.7 Bitwise shift operators', '84'),
+('6.5.8 Relational operators', '85'),
+('6.5.9 Equality operators', '86'),
+('6.5.10 Bitwise AND operator', '87'),
+('6.5.11 Bitwise exclusive OR operator', '88'),
+('6.5.12 Bitwise inclusive OR operator', '88'),
+('6.5.13 Logical AND operator', '89'),
+('6.5.14 Logical OR operator', '89'),
+('6.5.15 Conditional operator', '90'),
+('6.5.16 Assignment operators', '91'),
+('6.5.17 Comma operator', '94'),
+('6.6 Constant expressions', '95'),
+('6.7 Declarations', '97'),
+('6.7.1 Storage-class specifiers', '98'),
+('6.7.2 Type specifiers', '99'),
+('6.7.3 Type qualifiers', '108'),
+('6.7.4 Function specifiers', '112'),
+('6.7.5 Declarators', '114'),
+('6.7.6 Type names', '122'),
+('6.7.7 Type definitions', '123'),
+('6.7.8 Initialization', '125'),
+('6.8 Statements and blocks', '131'),
+('6.8.1 Labeled statements', '131'),
+('6.8.2 Compound statement', '132'),
+('6.8.3 Expression and null statements', '132'),
+('6.8.4 Selection statements', '133'),
+('6.8.5 Iteration statements', '135'),
+('6.8.6 Jump statements', '136'),
+('6.9 External definitions', '140'),
+('6.9.1 Function definitions', '141'),
+('6.9.2 External object definitions', '143'),
+('6.10 Preprocessing directives', '145'),
+('6.10.1 Conditional inclusion', '147'),
+('6.10.2 Source file inclusion', '149'),
+('6.10.3 Macro replacement', '151'),
+('6.10.4 Line control', '158'),
+('6.10.5 Error directive', '159'),
+('6.10.6 Pragma directive', '159'),
+('6.10.7 Null directive', '160'),
+('6.10.8 Predefined macro names', '160'),
+('6.10.9 Pragma operator', '161'),
+('6.11 Future language directions', '163'),
+('6.11.1 Floating types', '163'),
+('6.11.2 Linkages of identifiers', '163'),
+('6.11.3 External names', '163'),
+('6.11.4 Character escape sequences', '163'),
+('6.11.5 Storage-class specifiers', '163'),
+('6.11.6 Function declarators', '163'),
+('6.11.7 Function definitions', '163'),
+('6.11.8 Pragma directives', '163'),
+('6.11.9 Predefined macro names', '163'),
+('7. Library', '164'),
+('7.1 Introduction', '164'),
+('7.1.1 Definitions of terms', '164'),
+('7.1.2 Standard headers', '165'),
+('7.1.3 Reserved identifiers', '166'),
+('7.1.4 Use of library functions', '166'),
+('7.2 Diagnostics <assert.h>', '169'),
+('7.2.1 Program diagnostics', '169'),
+('7.3 Complex arithmetic <complex.h>', '170'),
+('7.3.1 Introduction', '170'),
+('7.3.2 Conventions', '170'),
+('7.3.3 Branch cuts', '171'),
+('7.3.4 The CX_LIMITED_RANGE pragma', '171'),
+('7.3.5 Trigonometric functions', '172'),
+('7.3.6 Hyperbolic functions', '174'),
+('7.3.7 Exponential and logarithmic functions', '176'),
+('7.3.8 Power and absolute-value functions', '177'),
+('7.3.9 Manipulation functions', '178'),
+('7.4 Character handling <ctype.h>', '181'),
+('7.4.1 Character classification functions', '181'),
+('7.4.2 Character case mapping functions', '184'),
+('7.5 Errors <errno.h>', '186'),
+('7.6 Floating-point environment <fenv.h>', '187'),
+('7.6.1 The FENV_ACCESS pragma', '189'),
+('7.6.2 Floating-point exceptions', '190'),
+('7.6.3 Rounding', '193'),
+('7.6.4 Environment', '194'),
+('7.7 Characteristics of floating types <float.h>', '197'),
+('7.8 Format conversion of integer types <inttypes.h>', '198'),
+('7.8.1 Macros for format specifiers', '198'),
+('7.8.2 Functions for greatest-width integer types', '199'),
+('7.9 Alternative spellings <iso646.h>', '202'),
+('7.10 Sizes of integer types <limits.h>', '203'),
+('7.11 Localization <locale.h>', '204'),
+('7.11.1 Locale control', '205'),
+('7.11.2 Numeric formatting convention inquiry', '206'),
+('7.12 Mathematics <math.h>', '212'),
+('7.12.1 Treatment of error conditions', '214'),
+('7.12.2 The FP_CONTRACT pragma', '215'),
+('7.12.3 Classification macros', '216'),
+('7.12.4 Trigonometric functions', '218'),
+('7.12.5 Hyperbolic functions', '221'),
+('7.12.6 Exponential and logarithmic functions', '223'),
+('7.12.7 Power and absolute-value functions', '228'),
+('7.12.8 Error and gamma functions', '230'),
+('7.12.9 Nearest integer functions', '231'),
+('7.12.10 Remainder functions', '235'),
+('7.12.11 Manipulation functions', '236'),
+('7.12.12 Maximum, minimum, and positive difference functions', '238'),
+('7.12.13 Floating multiply-add', '239'),
+('7.12.14 Comparison macros', '240'),
+('7.13 Nonlocal jumps <setjmp.h>', '243'),
+('7.13.1 Save calling environment', '243'),
+('7.13.2 Restore calling environment', '244'),
+('7.14 Signal handling <signal.h>', '246'),
+('7.14.1 Specify signal handling', '247'),
+('7.14.2 Send signal', '248'),
+('7.15 Variable arguments <stdarg.h>', '249'),
+('7.15.1 Variable argument list access macros', '249'),
+('7.16 Boolean type and values <stdbool.h>', '253'),
+('7.17 Common definitions <stddef.h>', '254'),
+('7.18 Integer types <stdint.h>', '255'),
+('7.18.1 Integer types', '255'),
+('7.18.2 Limits of specified-width integer types', '257'),
+('7.18.3 Limits of other integer types', '259'),
+('7.18.4 Macros for integer constants', '260'),
+('7.19 Input/output <stdio.h>', '262'),
+('7.19.1 Introduction', '262'),
+('7.19.2 Streams', '264'),
+('7.19.3 Files', '266'),
+('7.19.4 Operations on files', '268'),
+('7.19.5 File access functions', '270'),
+('7.19.6 Formatted input/output functions', '274'),
+('7.19.7 Character input/output functions', '296'),
+('7.19.8 Direct input/output functions', '301'),
+('7.19.9 File positioning functions', '302'),
+('7.19.10 Error-handling functions', '304'),
+('7.20 General utilities <stdlib.h>', '306'),
+('7.20.1 Numeric conversion functions', '307'),
+('7.20.2 Pseudo-random sequence generation functions', '312'),
+('7.20.3 Memory management functions', '313'),
+('7.20.4 Communication with the environment', '315'),
+('7.20.5 Searching and sorting utilities', '318'),
+('7.20.6 Integer arithmetic functions', '320'),
+('7.20.7 Multibyte/wide character conversion functions', '321'),
+('7.20.8 Multibyte/wide string conversion functions', '323'),
+('7.21 String handling <string.h>', '325'),
+('7.21.1 String function conventions', '325'),
+('7.21.2 Copying functions', '325'),
+('7.21.3 Concatenation functions', '327'),
+('7.21.4 Comparison functions', '328'),
+('7.21.5 Search functions', '330'),
+('7.21.6 Miscellaneous functions', '333'),
+('7.22 Type-generic math <tgmath.h>', '335'),
+('7.23 Date and time <time.h>', '338'),
+('7.23.1 Components of time', '338'),
+('7.23.2 Time manipulation functions', '339'),
+('7.23.3 Time conversion functions', '341'),
+('7.24 Extended multibyte and wide character utilities <wchar.h>', '348'),
+('7.24.1 Introduction', '348'),
+('7.24.2 Formatted wide character input/output functions', '349'),
+('7.24.3 Wide character input/output functions', '367'),
+('7.24.4 General wide string utilities', '371'),
+('7.24.5 Wide character time conversion functions', '385'),
+('7.24.6 Extended multibyte/wide character conversion utilities', '386'),
+('7.25 Wide character classification and mapping utilities <wctype.h>',
+ '393'),
+('7.25.1 Introduction', '393'),
+('7.25.2 Wide character classification utilities', '394'),
+('7.25.3 Wide character case mapping utilities', '399'),
+('7.26 Future library directions', '401'),
+('7.26.1 Complex arithmetic <complex.h>', '401'),
+('7.26.2 Character handling <ctype.h>', '401'),
+('7.26.3 Errors <errno.h>', '401'),
+('7.26.4 Format conversion of integer types <inttypes.h>', '401'),
+('7.26.5 Localization <locale.h>', '401'),
+('7.26.6 Signal handling <signal.h>', '401'),
+('7.26.7 Boolean type and values <stdbool.h>', '401'),
+('7.26.8 Integer types <stdint.h>', '401'),
+('7.26.9 Input/output <stdio.h>', '402'),
+('7.26.10 General utilities <stdlib.h>', '402'),
+('7.26.11 String handling <string.h>', '402'),
+('<wchar.h>', '402'),
+('<wctype.h>', '402'),
+('Annex A (informative) Language syntax summary', '403'),
+('A.1 Lexical grammar', '403'),
+('A.2 Phrase structure grammar', '409'),
+('A.3 Preprocessing directives', '416'),
+('Annex B (informative) Library summary', '418'),
+('B.1 Diagnostics <assert.h>', '418'),
+('B.2 Complex <complex.h>', '418'),
+('B.3 Character handling <ctype.h>', '420'),
+('B.4 Errors <errno.h>', '420'),
+('B.5 Floating-point environment <fenv.h>', '420'),
+('B.6 Characteristics of floating types <float.h>', '421'),
+('B.7 Format conversion of integer types <inttypes.h>', '421'),
+('B.8 Alternative spellings <iso646.h>', '422'),
+('B.9 Sizes of integer types <limits.h>', '422'),
+('B.10 Localization <locale.h>', '422'),
+('B.11 Mathematics <math.h>', '422'),
+('B.12 Nonlocal jumps <setjmp.h>', '427'),
+('B.13 Signal handling <signal.h>', '427'),
+('B.14 Variable arguments <stdarg.h>', '427'),
+('B.15 Boolean type and values <stdbool.h>', '427'),
+('B.16 Common definitions <stddef.h>', '428'),
+('B.17 Integer types <stdint.h>', '428'),
+('B.18 Input/output <stdio.h>', '428'),
+('B.19 General utilities <stdlib.h>', '430'),
+('B.20 String handling <string.h>', '432'),
+('B.21 Type-generic math <tgmath.h>', '433'),
+('B.22 Date and time <time.h>', '433'),
+('B.23 Extended multibyte/wide character utilities <wchar.h>', '434'),
+('B.24 Wide character classification and mapping utilities <wctype.h>',
+ '436'),
+('Annex C (informative) Sequence points', '438'),
+('Annex D (normative) Universal character names for identifiers', '439'),
+('Annex E (informative) Implementation limits', '441'),
+('Annex F (normative) IEC 60559 floating-point arithmetic', '443'),
+('F.1 Introduction', '443'),
+('F.2 Types', '443'),
+('F.3 Operators and functions', '444'),
+('F.4 Floating to integer conversion', '446'),
+('F.5 Binary-decimal conversion', '446'),
+('F.6 Contracted expressions', '447'),
+('F.7 Floating-point environment', '447'),
+('F.8 Optimization', '450'),
+('F.9 Mathematics <math.h>', '453'),
+('Annex G (informative) IEC 60559-compatible complex arithmetic', '466'),
+('G.1 Introduction', '466'),
+('G.2 Types', '466'),
+('G.3 Conventions', '466'),
+('G.4 Conversions', '467'),
+('G.5 Binary operators', '467'),
+('G.6 Complex arithmetic <complex.h>', '471'),
+('G.7 Type-generic math <tgmath.h>', '479'),
+('Annex H (informative) Language independent arithmetic', '480'),
+('H.1 Introduction', '480'),
+('H.2 Types', '480'),
+('H.3 Notification', '484'),
+('Annex I (informative) Common warnings', '486'),
+('Annex J (informative) Portability issues', '488'),
+('J.1 Unspecified behavior', '488'),
+('J.2 Undefined behavior', '491'),
+('J.3 Implementation-defined behavior', '504'),
+('J.4 Locale-specific behavior', '511'),
+('J.5 Common extensions', '512'),
+('Bibliography', '515'),
+('Index', '517')]
+
+cXXURL = 'http://open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2723.pdf'
+cXXTOC = [('Contents', 'ii'),
+('List of Tables', 'ix'),
+('1 General', '1'),
+('1.1 Scope', '1'),
+('1.2 Normative references', '1'),
+('1.3 Definitions', '2'),
+('1.4 Implementation compliance', '4'),
+('1.5 Structure of this International Standard', '5'),
+('1.6 Syntax notation', '5'),
+('1.7 The C++ memory model', '6'),
+('1.8 The C++ object model', '6'),
+('1.9 Program execution', '7'),
+('1.10 Multi-threaded executions and data races', '10'),
+('1.11 Acknowledgments', '13'),
+('2 Lexical conventions', '15'),
+('2.1 Phases of translation', '15'),
+('2.2 Character sets', '16'),
+('2.3 Trigraph sequences', '17'),
+('2.4 Preprocessing tokens', '17'),
+('2.5 Alternative tokens', '18'),
+('2.6 Tokens', '19'),
+('2.7 Comments', '19'),
+('2.8 Header names', '19'),
+('2.9 Preprocessing numbers', '20'),
+('2.10 Identifiers', '20'),
+('2.11 Keywords', '20'),
+('2.12 Operators and punctuators', '21'),
+('2.13 Literals', '21'),
+('3 Basic concepts', '29'),
+('3.1 Declarations and definitions', '29'),
+('3.2 One definition rule', '31'),
+('3.3 Declarative regions and scopes', '33'),
+('3.4 Name lookup', '38'),
+('3.5 Program and linkage', '51'),
+('3.6 Start and termination', '54'),
+('3.7 Storage duration', '58'),
+('3.8 Object Lifetime', '62'),
+('3.9 Types', '65'),
+('3.10 Lvalues and rvalues', '70'),
+('3.11 Alignment', '72'),
+('4 Standard conversions', '73'),
+('4.1 Lvalue-to-rvalue conversion', '74'),
+('4.2 Array-to-pointer conversion', '74'),
+('4.3 Function-to-pointer conversion', '74'),
+('4.4 Qualification conversions', '74'),
+('4.5 Integral promotions', '75'),
+('4.6 Floating point promotion', '76'),
+('4.7 Integral conversions', '76'),
+('4.8 Floating point conversions', '76'),
+('4.9 Floating-integral conversions', '77'),
+('4.10 Pointer conversions', '77'),
+('4.11 Pointer to member conversions', '77'),
+('4.12 Boolean conversions', '78'),
+('4.13 Integer conversion rank', '78'),
+('5 Expressions', '79'),
+('5.1 Primary expressions', '80'),
+('5.2 Postfix expressions', '85'),
+('5.3 Unary expressions', '96'),
+('5.4 Explicit type conversion (cast notation)', '104'),
+('5.5 Pointer-to-member operators', '105'),
+('5.6 Multiplicative operators', '106'),
+('5.7 Additive operators', '106'),
+('5.8 Shift operators', '107'),
+('5.9 Relational operators', '108'),
+('5.10 Equality operators', '109'),
+('5.11 Bitwise AND operator', '110'),
+('5.12 Bitwise exclusive OR operator', '110'),
+('5.13 Bitwise inclusive OR operator', '110'),
+('5.14 Logical AND operator', '110'),
+('5.15 Logical OR operator', '110'),
+('5.16 Conditional operator', '111'),
+('5.17 Assignment and compound assignment operators', '112'),
+('5.18 Comma operator', '113'),
+('5.19 Constant expressions', '113'),
+('6 Statements', '116'),
+('6.1 Labeled statement', '116'),
+('6.2 Expression statement', '116'),
+('6.3 Compound statement or block', '116'),
+('6.4 Selection statements', '117'),
+('6.5 Iteration statements', '118'),
+('6.6 Jump statements', '121'),
+('6.7 Declaration statement', '122'),
+('6.8 Ambiguity resolution', '123'),
+('7 Declarations', '125'),
+('7.1 Specifiers', '126'),
+('7.2 Enumeration declarations', '140'),
+('7.3 Namespaces', '143'),
+('7.4 The asm declaration', '156'),
+('7.5 Linkage specifications', '156'),
+('8 Declarators', '160'),
+('8.1 Type names', '161'),
+('8.2 Ambiguity resolution', '161'),
+('8.3 Meaning of declarators', '163'),
+('8.4 Function definitions', '175'),
+('8.5 Initializers', '177'),
+('9 Classes', '191'),
+('9.1 Class names', '193'),
+('9.2 Class members', '194'),
+('9.3 Member functions', '197'),
+('9.4 Static members', '200'),
+('9.5 Unions', '202'),
+('9.6 Bit-fields', '203'),
+('9.7 Nested class declarations', '204'),
+('9.8 Local class declarations', '205'),
+('9.9 Nested type names', '206'),
+('10 Derived classes', '207'),
+('10.1 Multiple base classes', '208'),
+('10.2 Member name lookup', '210'),
+('10.3 Virtual functions', '213'),
+('10.4 Abstract classes', '217'),
+('11 Member access control', '219'),
+('11.1 Access specifiers', '221'),
+('11.2 Accessibility of base classes and base class members', '222'),
+('11.3 Access declarations', '224'),
+('11.4 Friends', '225'),
+('11.5 Protected member access', '228'),
+('11.6 Access to virtual functions', '229'),
+('11.7 Multiple access', '230'),
+('11.8 Nested classes', '230'),
+('12 Special member functions', '231'),
+('12.1 Constructors', '231'),
+('12.2 Temporary objects', '233'),
+('12.3 Conversions', '235'),
+('12.4 Destructors', '238'),
+('12.5 Free store', '240'),
+('12.6 Initialization', '242'),
+('12.7 Construction and destruction', '247'),
+('12.8 Copying class objects', '250'),
+('12.9 Inheriting Constructors', '255'),
+('13 Overloading', '259'),
+('13.1 Overloadable declarations', '259'),
+('13.2 Declaration matching', '261'),
+('13.3 Overload resolution', '262'),
+('13.4 Address of overloaded function', '281'),
+('13.5 Overloaded operators', '282'),
+('13.6 Built-in operators', '286'),
+('14 Templates', '290'),
+('14.1 Template parameters', '291'),
+('14.2 Names of template specializations', '294'),
+('14.3 Template arguments', '296'),
+('14.4 Type equivalence', '302'),
+('14.5 Template declarations', '303'),
+('14.6 Name resolution', '318'),
+('14.7 Template instantiation and specialization', '331'),
+('14.8 Function template specializations', '343'),
+('15 Exception handling', '363'),
+('15.1 Throwing an exception', '364'),
+('15.2 Constructors and destructors', '366'),
+('15.3 Handling an exception', '366'),
+('15.4 Exception specifications', '368'),
+('15.5 Special functions', '371'),
+('15.6 Exceptions and access', '372'),
+('16 Preprocessing directives', '373'),
+('16.1 Conditional inclusion', '375'),
+('16.2 Source file inclusion', '376'),
+('16.3 Macro replacement', '377'),
+('16.4 Line control', '382'),
+('16.5 Error directive', '383'),
+('16.6 Pragma directive', '383'),
+('16.7 Null directive', '383'),
+('16.8 Predefined macro names', '383'),
+('16.9 Pragma operator', '384'),
+('17 Library introduction', '386'),
+('17.1 General', '386'),
+('17.2 Overview', '386'),
+('17.3 Definitions', '386'),
+('17.4 Additional definitions', '390'),
+('17.5 Method of description (Informative)', '390'),
+('17.6 Library-wide requirements', '396'),
+('18 Language support library', '407'),
+('18.1 Types', '407'),
+('18.2 Implementation properties', '408'),
+('18.3 Integer types', '417'),
+('18.4 Start and termination', '418'),
+('18.5 Dynamic memory management', '420'),
+('18.6 Type identification', '424'),
+('18.7 Exception handling', '427'),
+('18.8 Initializer lists', '432'),
+('18.9 Other runtime support', '434'),
+('19 Diagnostics library', '435'),
+('19.1 Exception classes', '435'),
+('19.2 Assertions', '439'),
+('19.3 Error numbers', '440'),
+('19.4 System error support', '440'),
+('20 General utilities library', '452'),
+('20.1 Requirements', '452'),
+('20.2 Utility components', '457'),
+('20.3 Compile-time rational arithmetic', '463'),
+('20.4 Tuples', '465'),
+('20.5 Metaprogramming and type traits', '473'),
+('20.6 Function objects', '486'),
+('20.7 Memory', '509'),
+('20.8 Time utilities', '548'),
+('20.9 Date and time functions', '562'),
+('21 Strings library', '563'),
+('21.1 Character traits', '563'),
+('21.2 String classes', '569'),
+('21.3 Class template basic_string', '572'),
+('21.4 Numeric Conversions', '599'),
+('21.5 Null-terminated sequence utilities', '600'),
+('22 Localization library', '604'),
+('22.1 Locales', '604'),
+('22.2 Standard locale categories', '617'),
+('22.3 Standard code conversion facets', '657'),
+('22.4 C Library Locales', '659'),
+('23 Containers library', '660'),
+('23.1 Container requirements', '660'),
+('23.2 Sequence containers', '681'),
+('23.3 Associative containers', '719'),
+('23.4 Unordered associative containers', '744'),
+('24 Iterators library', '759'),
+('24.1 Iterator requirements', '759'),
+('24.2 Header <iterator> synopsis', '764'),
+('24.3 Iterator primitives', '767'),
+('24.4 Predefined iterators', '770'),
+('24.5 Stream iterators', '784'),
+('25 Algorithms library', '792'),
+('25.1 Non-modifying sequence operations', '802'),
+('25.2 Mutating sequence operations', '806'),
+('25.3 Sorting and related operations', '815'),
+('25.4 C library algorithms', '829'),
+('26 Numerics library', '831'),
+('26.1 Numeric type requirements', '831'),
+('26.2 The floating-point environment', '832'),
+('26.3 Complex numbers', '833'),
+('26.4 Random number generation', '842'),
+('26.5 Numeric arrays', '884'),
+('26.6 Generalized numeric operations', '904'),
+('26.7 C Library', '907'),
+('27 Input/output library', '912'),
+('27.1 Iostreams requirements', '912'),
+('27.2 Forward declarations', '912'),
+('27.3 Standard iostream objects', '915'),
+('27.4 Iostreams base classes', '916'),
+('27.5 Stream buffers', '934'),
+('27.6 Formatting and manipulators', '944'),
+('27.7 String-based streams', '972'),
+('27.8 File-based streams', '984'),
+('28 Regular expressions library', '1000'),
+('28.1 Definitions', '1000'),
+('28.2 Requirements', '1000'),
+('28.3 Regular expressions summary', '1002'),
+('28.4 Header <regex> synopsis', '1003'),
+('28.5 Namespace std::regex_constants', '1009'),
+('28.6 Class regex_error', '1012'),
+('28.7 Class template regex_traits', '1012'),
+('28.8 Class template basic_regex', '1015'),
+('28.9 Class template sub_match', '1020'),
+('28.10Class template match_results', '1025'),
+('28.11Regular expression algorithms', '1029'),
+('28.12Regular expression Iterators', '1033'),
+('28.13Modified ECMAScript regular expression grammar', '1039'),
+('29 Atomic operations library', '1042'),
+('29.1 Order and Consistency', '1044'),
+('29.2 Lock-free Property', '1046'),
+('29.3 Atomic Types', '1046'),
+('29.4 Operations on Atomic Types', '1051'),
+('29.5 Flag Type and Operations', '1054'),
+('30 Thread support library', '1057'),
+('30.1 Requirements', '1057'),
+('30.2 Threads', '1058'),
+('30.3 Mutual exclusion', '1063'),
+('30.4 Condition variables', '1077'),
+('A Grammar summary', '1085'),
+('A.1 Keywords', '1085'),
+('A.2 Lexical conventions', '1085'),
+('A.3 Basic concepts', '1089'),
+('A.4 Expressions', '1090'),
+('A.5 Statements', '1093'),
+('A.6 Declarations', '1094'),
+('A.7 Declarators', '1097'),
+('A.8 Classes', '1098'),
+('A.9 Derived classes', '1099'),
+('A.10 Special member functions', '1099'),
+('A.11 Overloading', '1100'),
+('A.12 Templates', '1100'),
+('A.13 Exception handling', '1101'),
+('A.14 Preprocessing directives', '1101'),
+('B Implementation quantities', '1103'),
+('C Compatibility', '1105'),
+('C.1 C++ and ISO C', '1105'),
+('C.2 Standard C library', '1114'),
+('D Compatibility features', '1119'),
+('D.1 Increment operator with bool operand', '1119'),
+('D.2 static keyword', '1119'),
+('D.3 Access declarations', '1119'),
+('D.4 Implicit conversion from const strings', '1119'),
+('D.5 C standard library headers', '1119'),
+('D.6 Old iostreams members', '1120'),
+('D.7 char* streams', '1121'),
+('D.8 Binders', '1130'),
+('D.9 auto_ptr', '1132'),
+('E Universal-character-names', '1135'),
+('F Cross references', '1137'),
+('Index', '1153')]
+
+kDocuments = {
+ 'C99' : (c99URL, c99TOC, 12),
+ 'C++' : (cXXURL, cXXTOC, 12),
+}
+
+def findClosestTOCEntry(data, target):
+ # FIXME: Fix for named spec references
+ if isinstance(target[0],str):
+ return ('.'.join(target),'<named>',1)
+
+ offset = data[2]
+ best = None
+ for (name,page) in data[1]:
+ if ' ' in name:
+ section,name = name.split(' ',1)
+ if section == 'Annex':
+ section,name = name.split(' ',1)
+ section = 'Annex '+section
+ else:
+ section = None
+ try:
+ page = int(page) + offset
+ except:
+ page = 1
+ try:
+ spec = SpecIndex.fromstring(section)
+ except:
+ spec = None
+
+ # Meh, could be better...
+ if spec is not None:
+ dist = spec - target
+ if best is None or dist < best[0]:
+ best = (dist, (section, name, page))
+ return best[1]
+
+# What a hack. Slow to boot.
+doxyLineRefRE = re.compile(r"<a name=\"l([0-9]+)\"></a>")
+def findClosestLineReference(clangRoot, doxyName, target):
+ try:
+ f = open(os.path.join(clangRoot, 'docs', 'doxygen', 'html', doxyName))
+ except:
+ return None
+
+ best = None
+ for m in doxyLineRefRE.finditer(f.read()):
+ line = int(m.group(1), 10)
+ dist = abs(line - target)
+ if best is None or dist < best[0]:
+ best = (dist,'l'+m.group(1))
+ f.close()
+ if best is not None:
+ return best[1]
+ return None
+
+###
+
+nameAndSpecRefRE = re.compile(r"(C99|C90|C\+\+|H\&S) ((([0-9]+)(\.[0-9]+)*|\[[^]]+\])(p[0-9]+)?)")
+loneSpecRefRE = re.compile(r" (([0-9]+)(\.[0-9]+){2,100}(p[0-9]+)?)")
+def scanFile(path, filename):
+ try:
+ f = open(path)
+ except IOError:
+ print >>sys.stderr,'WARNING: Unable to open:',path
+ return
+
+ for i,ln in enumerate(f):
+ ignore = set()
+ for m in nameAndSpecRefRE.finditer(ln):
+ section = m.group(2)
+ name = m.group(1)
+ if section.endswith('.'):
+ section = section[:-1]
+ yield RefItem(name, section, filename, path, i+1)
+ ignore.add(section)
+ for m in loneSpecRefRE.finditer(ln):
+ section = m.group(1)
+ if section.endswith('.'):
+ section = section[:-1]
+ if section not in ignore:
+ yield RefItem(None, section, filename, path, i+1)
+
+###
+
+class SpecIndex:
+ @staticmethod
+ def fromstring(str):
+ # Check for named sections
+ if str[0] == '[':
+ assert ']' in str
+ secs = str[1:str.index(']')].split('.')
+ tail = str[str.index(']')+1:]
+ if tail:
+ assert tail[0] == 'p'
+ paragraph = int(tail[1:])
+ else:
+ paragraph = None
+ indices = secs
+ else:
+ secs = str.split('.')
+ paragraph = None
+ if 'p' in secs[-1]:
+ secs[-1],p = secs[-1].split('p',1)
+ paragraph = int(p)
+ indices = map(int, secs)
+ return SpecIndex(indices, paragraph)
+
+ def __init__(self, indices, paragraph=None):
+ assert len(indices)>0
+ self.indices = tuple(indices)
+ self.paragraph = paragraph
+
+ def __str__(self):
+ s = '.'.join(map(str,self.indices))
+ if self.paragraph is not None:
+ s += '.p%d'%(self.paragraph,)
+ return s
+
+ def __repr__(self):
+ return 'SpecIndex(%s, %s)'%(self.indices, self.paragraph)
+
+ def __cmp__(self, b):
+ return cmp((self.indices,self.paragraph),
+ (b.indices,b.paragraph))
+
+ def __hash__(self):
+ return hash((self.indices,self.paragraph))
+
+ def __sub__(self, indices):
+ def sub(a,b):
+ a = a or 0
+ b = b or 0
+ return abs(a-b)
+ return map(sub,self.indices,indices)
+
+class RefItem:
+ def __init__(self, name, section, filename, path, line):
+ self.name = name
+ self.section = SpecIndex.fromstring(section)
+ self.filename = filename
+ self.path = path
+ self.line = line
+
+ def __str__(self):
+ if self.name is not None:
+ return '%s %s'%(self.name, self.section)
+ else:
+ return '--- %s'%(self.section,)
+
+ def __repr__(self):
+ return 'RefItem(%s, %r, "%s", "%s", %d)'%(self.name,
+ self.section,
+ self.filename,
+ self.path,
+ self.line)
+
+ def __cmp__(self, b):
+ return cmp((self.name,self.section,self.filename,self.path,self.line),
+ (b.name,b.section,self.filename,self.path,self.line))
+
+ def __hash__(self):
+ return hash((self.name,self.section,self.filename,self.path,self.line))
+
+###
+
+def sorted(l):
+ l = list(l)
+ l.sort()
+ return l
+
+def getRevision(path):
+ import subprocess
+ p = subprocess.Popen(['svn', 'info', path],
+ stdin=open('/dev/null','r'),
+ stdout=subprocess.PIPE)
+ for ln in p.stdout.read(1024).split('\n'):
+ if ln.startswith('Revision:'):
+ return ln.split(':',1)[1].strip()
+ return None
+
+def buildRefTree(references):
+ root = (None, {}, [])
+
+ def getNode(keys):
+ if not keys:
+ return root
+ key,parent = keys[-1],getNode(keys[:-1])
+ node = parent[1].get(key)
+ if node is None:
+ parent[1][key] = node = (key, {}, [])
+ return node
+
+ for ref in references:
+ n = getNode((ref.name,) + ref.section.indices)
+ n[2].append(ref)
+
+ def flatten((key, children, data)):
+ children = sorted(map(flatten,children.values()))
+ return (key, children, sorted(data))
+
+ return flatten(root)
+
+def preorder(node,parents=(),first=True):
+ (key,children,data) = node
+ if first:
+ yield parents+(node,)
+ for c in children:
+ for item in preorder(c, parents+(node,)):
+ yield item
+
+def main():
+ global options
+ from optparse import OptionParser
+ parser = OptionParser("usage: %prog [options] CLANG_ROOT <output-dir>")
+ parser.add_option("", "--debug", dest="debug",
+ help="Print extra debugging output",
+ action="store_true",
+ default=False)
+ (opts, args) = parser.parse_args()
+
+ if len(args) != 2:
+ parser.error("incorrect number of arguments")
+
+ references = []
+ root,outputDir = args
+ if os.path.isdir(root):
+ for (dirpath, dirnames, filenames) in os.walk(root):
+ for filename in filenames:
+ name,ext = os.path.splitext(filename)
+ if ext in ('.c', '.cpp', '.h', '.def'):
+ fullpath = os.path.join(dirpath, filename)
+ references.extend(list(scanFile(fullpath, filename)))
+ else:
+ references.extend(list(scanFile(root, root)))
+
+ refTree = buildRefTree(references)
+
+ specs = {}
+ for ref in references:
+ spec = specs[ref.name] = specs.get(ref.name,{})
+ items = spec[ref.section] = spec.get(ref.section,[])
+ items.append(ref)
+
+ print 'Found %d references.'%(len(references),)
+
+ if opts.debug:
+ pprint(refTree)
+
+ referencesPath = os.path.join(outputDir,'references.html')
+ print 'Writing: %s'%(referencesPath,)
+ f = open(referencesPath,'w')
+ print >>f, '<html><head><title>clang: Specification References</title></head>'
+ print >>f, '<body>'
+ print >>f, '\t<h2>Specification References</h2>'
+ for i,node in enumerate(refTree[1]):
+ specName = node[0] or 'Unknown'
+ print >>f, '<a href="#spec%d">%s</a><br>'%(i,specName)
+ for i,node in enumerate(refTree[1]):
+ specName = node[0] or 'Unknown'
+ print >>f, '<hr>'
+ print >>f, '<a name="spec%d">'%(i,)
+ print >>f, '<h3>Document: %s</h3>'%(specName or 'Unknown',)
+ print >>f, '<table border="1" cellspacing="2" width="80%">'
+ print >>f, '<tr><th width="20%">Name</th><th>References</th></tr>'
+ docData = kDocuments.get(specName)
+ for path in preorder(node,first=False):
+ if not path[-1][2]:
+ continue
+ components = '.'.join([str(p[0]) for p in path[1:]])
+ print >>f, '\t<tr>'
+ tocEntry = None
+ if docData is not None:
+ tocEntry = findClosestTOCEntry(docData, [p[0] for p in path[1:]])
+ if tocEntry is not None:
+ section,name,page = tocEntry
+ # If section is exact print the TOC name
+ if page is not None:
+ linkStr = '<a href="%s#page=%d">%s</a> (pg.%d)'%(docData[0],page,components,page)
+ else:
+ linkStr = components
+ if section == components:
+ print >>f, '\t\t<td valign=top>%s<br>%s</td>'%(linkStr,name)
+ else:
+ print >>f, '\t\t<td valign=top>%s</td>'%(linkStr,)
+ else:
+ print >>f, '\t\t<td valign=top>%s</td>'%(components,)
+ print >>f, '\t\t<td valign=top>'
+ for item in path[-1][2]:
+ # XXX total hack
+ relativePath = item.path[len(root):]
+ if relativePath.startswith('/'):
+ relativePath = relativePath[1:]
+ # XXX this is broken, how does doxygen mangle w/ multiple
+ # refs? Can we just read its map?
+ filename = os.path.basename(relativePath)
+ doxyName = '%s-source.html'%(filename.replace('.','_8'),)
+ # Grrr, why can't doxygen write line number references.
+ lineReference = findClosestLineReference(root,doxyName,item.line)
+ if lineReference is not None:
+ linkStr = 'http://clang.llvm.org/doxygen/%s#%s'%(doxyName,lineReference)
+ else:
+ linkStr = 'http://clang.llvm.org/doxygen/%s'%(doxyName,)
+ if item.section.paragraph is not None:
+ paraText = '&nbsp;(p%d)'%(item.section.paragraph,)
+ else:
+ paraText = ''
+ print >>f,'<a href="%s">%s:%d</a>%s<br>'%(linkStr,relativePath,item.line,paraText)
+ print >>f, '\t\t</td>'
+ print >>f, '\t</tr>'
+ print >>f, '</table>'
+ print >>f, '<hr>'
+ print >>f, 'Generated: %s<br>'%(time.strftime('%Y-%m-%d %H:%M'),)
+ print >>f, 'SVN Revision: %s'%(getRevision(root),)
+ print >>f, '</body>'
+ f.close()
+
+if __name__=='__main__':
+ main()
diff --git a/utils/SummarizeErrors b/utils/SummarizeErrors
new file mode 100755
index 000000000000..64d78240dd2f
--- /dev/null
+++ b/utils/SummarizeErrors
@@ -0,0 +1,117 @@
+#!/usr/bin/python
+
+import os, sys, re
+
+class multidict:
+ def __init__(self, elts=()):
+ self.data = {}
+ for key,value in elts:
+ self[key] = value
+
+ def __getitem__(self, item):
+ return self.data[item]
+ def __setitem__(self, key, value):
+ if key in self.data:
+ self.data[key].append(value)
+ else:
+ self.data[key] = [value]
+ def items(self):
+ return self.data.items()
+ def values(self):
+ return self.data.values()
+ def keys(self):
+ return self.data.keys()
+ def __len__(self):
+ return len(self.data)
+
+kDiagnosticRE = re.compile(': (error|warning): (.*)')
+kAssertionRE = re.compile('Assertion failed: (.*, function .*, file .*, line [0-9]+\\.)')
+
+def readInfo(path, opts):
+ lastProgress = [-100,0]
+ def progress(pos):
+ pct = (100. * pos) / (size * 2)
+ if (pct - lastProgress[0]) >= 10:
+ lastProgress[0] = pct
+ print '%d/%d = %.2f%%' % (pos, size*2, pct)
+
+ f = open(path)
+ data = f.read()
+ f.close()
+
+ if opts.truncate != -1:
+ data = data[:opts.truncate]
+
+ size = len(data)
+ warnings = multidict()
+ errors = multidict()
+ for m in kDiagnosticRE.finditer(data):
+ progress(m.end())
+ if m.group(1) == 'error':
+ d = errors
+ else:
+ d = warnings
+ d[m.group(2)] = m
+ warnings = warnings.items()
+ errors = errors.items()
+ assertions = multidict()
+ for m in kAssertionRE.finditer(data):
+ print '%d/%d = %.2f%%' % (size + m.end(), size, (float(m.end()) / (size*2)) * 100.)
+ assertions[m.group(1)] = m
+ assertions = assertions.items()
+
+ # Manual scan for stack traces
+ aborts = multidict()
+ if 0:
+ prevLine = None
+ lnIter = iter(data.split('\n'))
+ for ln in lnIter:
+ m = kStackDumpLineRE.match(ln)
+ if m:
+ stack = [m.group(2)]
+ for ln in lnIter:
+ m = kStackDumpLineRE.match(ln)
+ if not m:
+ break
+ stack.append(m.group(2))
+ if prevLine is None or not kAssertionRE.match(prevLine):
+ aborts[tuple(stack)] = stack
+ prevLine = ln
+
+ sections = [
+ (warnings, 'Warnings'),
+ (errors, 'Errors'),
+ (assertions, 'Assertions'),
+ (aborts.items(), 'Aborts'),
+ ]
+
+ if opts.ascending:
+ sections.reverse()
+
+ for l,title in sections:
+ l.sort(key = lambda (a,b): -len(b))
+ if l:
+ print '-- %d %s (%d kinds) --' % (sum([len(b) for a,b in l]), title, len(l))
+ for name,elts in l:
+ print '%5d:' % len(elts), name
+
+def main():
+ global options
+ from optparse import OptionParser
+ parser = OptionParser("usage: %prog [options] {inputs}")
+ parser.add_option("", "--ascending", dest="ascending",
+ help="Print output in ascending order of severity.",
+ action="store_true", default=False)
+ parser.add_option("", "--truncate", dest="truncate",
+ help="Truncate input file (for testing).",
+ type=int, action="store", default=-1)
+ (opts, args) = parser.parse_args()
+
+ if not args:
+ parser.error('No inputs specified')
+
+ for arg in args:
+ readInfo(arg, opts)
+
+if __name__=='__main__':
+ main()
diff --git a/utils/builtin-defines.c b/utils/builtin-defines.c
new file mode 100644
index 000000000000..9bbe5be25026
--- /dev/null
+++ b/utils/builtin-defines.c
@@ -0,0 +1,85 @@
+/*
+This is a clang style test case for checking that preprocessor
+defines match gcc.
+*/
+
+/*
+RUN: for arch in -m32 -m64; do \
+RUN: for lang in -std=gnu89 -ansi -std=c99 -std=gnu99; do \
+RUN: for input in c objective-c; do \
+RUN: for opts in "-O0" "-O1 -dynamic" "-O2 -static" "-Os"; do \
+RUN: echo "-- $arch, $lang, $input, $opts --"; \
+RUN: for cc in 0 1; do \
+RUN: if [ "$cc" == 0 ]; then \
+RUN: cc_prog=clang; \
+RUN: output=%t0; \
+RUN: else \
+RUN: cc_prog=gcc; \
+RUN: output=%t1; \
+RUN: fi; \
+RUN: $cc_prog $arch $lang $opts -march=core2 -dM -E -x $input %s | sort > $output; \
+RUN: done; \
+RUN: if (! diff %t0 %t1); then exit 1; fi; \
+RUN: done; \
+RUN: done; \
+RUN: done; \
+RUN: done;
+*/
+
+/* We don't care about this difference */
+#ifdef __PIC__
+#if __PIC__ == 1
+#undef __PIC__
+#undef __pic__
+#define __PIC__ 2
+#define __pic__ 2
+#endif
+#endif
+
+/* Undefine things we don't expect to match. */
+#undef __core2
+#undef __core2__
+#undef __SSSE3__
+
+/* Undefine things we don't expect to match. */
+#undef __DEC_EVAL_METHOD__
+#undef __INT16_TYPE__
+#undef __INT32_TYPE__
+#undef __INT64_TYPE__
+#undef __INT8_TYPE__
+#undef __SSP__
+#undef __APPLE_CC__
+#undef __VERSION__
+#undef __clang__
+#undef __llvm__
+#undef __nocona
+#undef __nocona__
+#undef __k8
+#undef __k8__
+#undef __tune_nocona__
+#undef __tune_core2__
+#undef __POINTER_WIDTH__
+#undef __INTPTR_TYPE__
+#undef __NO_MATH_INLINES
+
+#undef __DEC128_DEN__
+#undef __DEC128_EPSILON__
+#undef __DEC128_MANT_DIG__
+#undef __DEC128_MAX_EXP__
+#undef __DEC128_MAX__
+#undef __DEC128_MIN_EXP__
+#undef __DEC128_MIN__
+#undef __DEC32_DEN__
+#undef __DEC32_EPSILON__
+#undef __DEC32_MANT_DIG__
+#undef __DEC32_MAX_EXP__
+#undef __DEC32_MAX__
+#undef __DEC32_MIN_EXP__
+#undef __DEC32_MIN__
+#undef __DEC64_DEN__
+#undef __DEC64_EPSILON__
+#undef __DEC64_MANT_DIG__
+#undef __DEC64_MAX_EXP__
+#undef __DEC64_MAX__
+#undef __DEC64_MIN_EXP__
+#undef __DEC64_MIN__
diff --git a/utils/ccc-analyzer b/utils/ccc-analyzer
new file mode 100755
index 000000000000..e4bf415b163f
--- /dev/null
+++ b/utils/ccc-analyzer
@@ -0,0 +1,617 @@
+#!/usr/bin/env perl
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# A script designed to interpose between the build system and gcc. It invokes
+# both gcc and the static analyzer.
+#
+##===----------------------------------------------------------------------===##
+
+use strict;
+use warnings;
+use Cwd qw/ getcwd abs_path /;
+use File::Temp qw/ tempfile /;
+use File::Path qw / mkpath /;
+use File::Basename;
+use Text::ParseWords;
+
+my $CC = $ENV{'CCC_CC'};
+if (!defined $CC) { $CC = "gcc"; }
+my $CleanupFile;
+my $ResultFile;
+
+# Remove any stale files at exit.
+END {
+ if (defined $CleanupFile && -z $CleanupFile) {
+ `rm -f $CleanupFile`;
+ }
+}
+
+##----------------------------------------------------------------------------##
+# Process Clang Crashes.
+##----------------------------------------------------------------------------##
+
+sub GetPPExt {
+ my $Lang = shift;
+ if ($Lang =~ /objective-c/) { return ".mi"; }
+ return ".i";
+}
+
+# Set this to 1 if we want to include 'parser rejects' files.
+my $IncludeParserRejects = 0;
+my $ParserRejects = "Parser Rejects";
+
+my $AttributeIgnored = "Attribute Ignored";
+
+sub ProcessClangFailure {
+ my ($ClangCC, $Lang, $file, $Args, $HtmlDir, $ErrorType, $ofile) = @_;
+ my $Dir = "$HtmlDir/failures";
+ mkpath $Dir;
+
+ my $prefix = "clang_crash";
+ if ($ErrorType eq $ParserRejects) {
+ $prefix = "clang_parser_rejects";
+ }
+ elsif ($ErrorType eq $AttributeIgnored) {
+ $prefix = "clang_attribute_ignored";
+ }
+
+ # Generate the preprocessed file with cc (i.e., gcc).
+ my ($PPH, $PPFile) = tempfile( $prefix . "_XXXXXX",
+ SUFFIX => GetPPExt($Lang),
+ DIR => $Dir);
+
+ system $CC, @$Args, "-E", "-o", $PPFile;
+ close ($PPH);
+
+ # Generate the preprocessed file with clang.
+ my $PPFile_Clang = $PPFile;
+ $PPFile_Clang =~ s/[.](.+)$/.clang.$1/;
+ system $ClangCC, @$Args, "-E", "-o", "$PPFile_Clang";
+
+ # Create the info file.
+ open (OUT, ">", "$PPFile.info.txt") or die "Cannot open $PPFile.info.txt\n";
+ print OUT abs_path($file), "\n";
+ print OUT "$ErrorType\n";
+ print OUT "@$Args\n";
+ close OUT;
+ `uname -a >> $PPFile.info.txt 2>&1`;
+ `$CC -v >> $PPFile.info.txt 2>&1`;
+ system 'mv',$ofile,"$PPFile.stderr.txt";
+ return (basename $PPFile);
+}
+
+##----------------------------------------------------------------------------##
+# Running the analyzer.
+##----------------------------------------------------------------------------##
+
+# Determine what clang executable to use.
+my $Clang = $ENV{'CLANG'};
+if (!defined $Clang) { $Clang = 'clang'; }
+
+sub GetCCArgs {
+ my $Args = shift;
+
+ pipe (FROM_CHILD, TO_PARENT);
+ my $pid = fork();
+ if ($pid == 0) {
+ close FROM_CHILD;
+ open(STDOUT,">&", \*TO_PARENT);
+ open(STDERR,">&", \*TO_PARENT);
+ exec $Clang, "-###", "-fsyntax-only", @$Args;
+ }
+ close(TO_PARENT);
+ my $line;
+ while (<FROM_CHILD>) {
+ next if (!/clang-cc/);
+ $line = $_;
+ }
+
+ waitpid($pid,0);
+ close(FROM_CHILD);
+
+ die "could not find clang-cc line\n" if (!defined $line);
+ # Strip the newline and initial whitspace
+ chomp $line;
+ $line =~ s/^\s+//;
+
+ my @items = quotewords('\s+', 1, $line);
+ for (my $i = 0 ; $ i < scalar(@items); ++$i) {
+ $items[$i] =~ s/^\"//;
+ $items[$i] =~ s/\"$//;
+ }
+ my $cmd = shift @items;
+ die "cannot find 'clang-cc' in 'clang' command\n" if (!($cmd =~ /clang-cc/));
+ return \@items;
+}
+
+sub Analyze {
+ my ($ClangCC, $Args, $AnalyzeArgs, $Lang, $Output, $Verbose, $HtmlDir,
+ $file, $Analyses) = @_;
+
+ $Args = GetCCArgs($Args);
+
+ # Skip anything related to C++.
+ return if ($Lang =~ /c[+][+]/);
+
+ my $RunAnalyzer = 0;
+ my $Cmd;
+ my @CmdArgs;
+ my @CmdArgsSansAnalyses;
+
+ if ($Lang =~ /header/) {
+ exit 0 if (!defined ($Output));
+ $Cmd = 'cp';
+ push @CmdArgs,$file;
+ # Remove the PCH extension.
+ $Output =~ s/[.]gch$//;
+ push @CmdArgs,$Output;
+ @CmdArgsSansAnalyses = @CmdArgs;
+ }
+ else {
+ $Cmd = $ClangCC;
+ push @CmdArgs,'-DIBOutlet=__attribute__((iboutlet))';
+ push @CmdArgs,@$Args;
+ @CmdArgsSansAnalyses = @CmdArgs;
+ push @CmdArgs,'-analyze';
+ push @CmdArgs,"-analyzer-display-progress";
+ push @CmdArgs,"-analyzer-eagerly-assume";
+ push @CmdArgs,(split /\s/,$Analyses);
+ $RunAnalyzer = 1;
+ }
+
+ # Add the analysis arguments passed down from scan-build.
+ foreach my $Arg (@$AnalyzeArgs) {
+ push @CmdArgs, $Arg;
+ }
+
+ my @PrintArgs;
+ my $dir;
+
+ if ($Verbose) {
+ $dir = getcwd();
+ print STDERR "\n[LOCATION]: $dir\n";
+ push @PrintArgs,"'$Cmd'";
+ foreach my $arg (@CmdArgs) { push @PrintArgs,"\'$arg\'"; }
+ }
+
+ if ($Verbose == 1) {
+ # We MUST print to stderr. Some clients use the stdout output of
+ # gcc for various purposes.
+ print STDERR join(' ',@PrintArgs);
+ print STDERR "\n";
+ }
+ elsif ($Verbose == 2) {
+ print STDERR "#SHELL (cd '$dir' && @PrintArgs)\n";
+ }
+
+ if ($RunAnalyzer) {
+ if (defined $ResultFile) {
+ push @CmdArgs,'-o';
+ push @CmdArgs, $ResultFile;
+ }
+ elsif (defined $HtmlDir) {
+ push @CmdArgs,'-o';
+ push @CmdArgs, $HtmlDir;
+ }
+ }
+
+ if (defined $ENV{'CCC_UBI'}) {
+ push @CmdArgs,"--analyzer-viz-egraph-ubigraph";
+ }
+
+ # Capture the STDERR of clang and send it to a temporary file.
+ # Capture the STDOUT of clang and reroute it to ccc-analyzer's STDERR.
+ # We save the output file in the 'crashes' directory if clang encounters
+ # any problems with the file.
+ pipe (FROM_CHILD, TO_PARENT);
+ my $pid = fork();
+ if ($pid == 0) {
+ close FROM_CHILD;
+ open(STDOUT,">&", \*TO_PARENT);
+ open(STDERR,">&", \*TO_PARENT);
+ exec $Cmd, @CmdArgs;
+ }
+
+ close TO_PARENT;
+ my ($ofh, $ofile) = tempfile("clang_output_XXXXXX", DIR => $HtmlDir);
+
+ while (<FROM_CHILD>) {
+ print $ofh $_;
+ print STDERR $_;
+ }
+
+ waitpid($pid,0);
+ close(FROM_CHILD);
+ my $Result = $?;
+
+ # Did the command die because of a signal?
+ if ($Result & 127 and $Cmd eq $ClangCC and defined $HtmlDir) {
+ ProcessClangFailure($ClangCC, $Lang, $file, \@CmdArgsSansAnalyses, $HtmlDir,
+ "Crash", $ofile);
+ }
+ elsif ($Result) {
+ if ($IncludeParserRejects && !($file =~/conftest/)) {
+ ProcessClangFailure($ClangCC, $Lang, $file, \@CmdArgsSansAnalyses, $HtmlDir,
+ $ParserRejects, $ofile);
+ }
+ }
+ else {
+ # Check if there were any unhandled attributes.
+ if (open(CHILD, $ofile)) {
+ my %attributes_not_handled;
+
+ # Don't flag warnings about the following attributes that we
+ # know are currently not supported by Clang.
+ $attributes_not_handled{"cdecl"} = 1;
+
+ my $ppfile;
+ while (<CHILD>) {
+ next if (! /warning: '([^\']+)' attribute ignored/);
+
+ # Have we already spotted this unhandled attribute?
+ next if (defined $attributes_not_handled{$1});
+ $attributes_not_handled{$1} = 1;
+
+ # Get the name of the attribute file.
+ my $dir = "$HtmlDir/failures";
+ my $afile = "$dir/attribute_ignored_$1.txt";
+
+ # Only create another preprocessed file if the attribute file
+ # doesn't exist yet.
+ next if (-e $afile);
+
+ # Add this file to the list of files that contained this attribute.
+ # Generate a preprocessed file if we haven't already.
+ if (!(defined $ppfile)) {
+ $ppfile = ProcessClangFailure($ClangCC, $Lang, $file,
+ \@CmdArgsSansAnalyses,
+ $HtmlDir, $AttributeIgnored, $ofile);
+ }
+
+ mkpath $dir;
+ open(AFILE, ">$afile");
+ print AFILE "$ppfile\n";
+ close(AFILE);
+ }
+ close CHILD;
+ }
+ }
+
+ `rm -f $ofile`;
+}
+
+##----------------------------------------------------------------------------##
+# Lookup tables.
+##----------------------------------------------------------------------------##
+
+my %CompileOptionMap = (
+ '-nostdinc' => 0,
+ '-fblocks' => 0,
+ '-fobjc-gc-only' => 0,
+ '-fobjc-gc' => 0,
+ '-ffreestanding' => 0,
+ '-include' => 1,
+ '-idirafter' => 1,
+ '-iprefix' => 1,
+ '-iquote' => 1,
+ '-isystem' => 1,
+ '-iwithprefix' => 1,
+ '-iwithprefixbefore' => 1
+);
+
+my %LinkerOptionMap = (
+ '-framework' => 1
+);
+
+my %CompilerLinkerOptionMap = (
+ '-isysroot' => 1,
+ '-arch' => 1,
+ '-v' => 0,
+ '-fpascal-strings' => 0,
+ '-mmacosx-version-min' => 0, # This is really a 1 argument, but always has '='
+ '-miphoneos-version-min' => 0 # This is really a 1 argument, but always has '='
+);
+
+my %IgnoredOptionMap = (
+ '-MT' => 1, # Ignore these preprocessor options.
+ '-MF' => 1,
+
+ '-fsyntax-only' => 0,
+ '-save-temps' => 0,
+ '-install_name' => 1,
+ '-exported_symbols_list' => 1,
+ '-current_version' => 1,
+ '-compatibility_version' => 1,
+ '-init' => 1,
+ '-e' => 1,
+ '-seg1addr' => 1,
+ '-bundle_loader' => 1,
+ '-multiply_defined' => 1,
+ '-sectorder' => 3,
+ '--param' => 1,
+ '-u' => 1
+);
+
+my %LangMap = (
+ 'c' => 'c',
+ 'cpp' => 'c++',
+ 'cc' => 'c++',
+ 'i' => 'c-cpp-output',
+ 'm' => 'objective-c',
+ 'mi' => 'objective-c-cpp-output'
+);
+
+my %UniqueOptions = (
+ '-isysroot' => 0
+);
+
+my %LangsAccepted = (
+ "objective-c" => 1,
+ "c" => 1
+);
+
+##----------------------------------------------------------------------------##
+# Main Logic.
+##----------------------------------------------------------------------------##
+
+my $Action = 'link';
+my @CompileOpts;
+my @LinkOpts;
+my @Files;
+my $Lang;
+my $Output;
+my %Uniqued;
+
+# Forward arguments to gcc.
+my $Status = system($CC,@ARGV);
+if ($Status) { exit($Status >> 8); }
+
+# Get the analysis options.
+my $Analyses = $ENV{'CCC_ANALYZER_ANALYSIS'};
+if (!defined($Analyses)) { $Analyses = '-checker-cfref'; }
+
+# Get the store model.
+my $StoreModel = $ENV{'CCC_ANALYZER_STORE_MODEL'};
+if (!defined $StoreModel) { $StoreModel = "basic"; }
+
+# Get the constraints engine.
+my $ConstraintsModel = $ENV{'CCC_ANALYZER_CONSTRAINTS_MODEL'};
+if (!defined $ConstraintsModel) { $ConstraintsModel = "range"; }
+
+# Get the output format.
+my $OutputFormat = $ENV{'CCC_ANALYZER_OUTPUT_FORMAT'};
+if (!defined $OutputFormat) { $OutputFormat = "html"; }
+
+# Determine the level of verbosity.
+my $Verbose = 0;
+if (defined $ENV{CCC_ANALYZER_VERBOSE}) { $Verbose = 1; }
+if (defined $ENV{CCC_ANALYZER_LOG}) { $Verbose = 2; }
+
+# Determine what clang-cc executable to use.
+my $ClangCC = $ENV{'CLANG_CC'};
+if (!defined $ClangCC) { $ClangCC = 'clang-cc'; }
+
+# Get the HTML output directory.
+my $HtmlDir = $ENV{'CCC_ANALYZER_HTML'};
+
+my %DisabledArchs = ('ppc' => 1, 'ppc64' => 1);
+my %ArchsSeen;
+my $HadArch = 0;
+
+# Process the arguments.
+foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
+ my $Arg = $ARGV[$i];
+ my ($ArgKey) = split /=/,$Arg,2;
+
+ # Modes ccc-analyzer supports
+ if ($Arg eq '-E') { $Action = 'preprocess'; }
+ elsif ($Arg eq '-c') { $Action = 'compile'; }
+ elsif ($Arg =~ /^-print-prog-name/) { exit 0; }
+
+ # Specially handle duplicate cases of -arch
+ if ($Arg eq "-arch") {
+ my $arch = $ARGV[$i+1];
+ # We don't want to process 'ppc' because of Clang's lack of support
+ # for Altivec (also some #defines won't likely be defined correctly, etc.)
+ if (!(defined $DisabledArchs{$arch})) { $ArchsSeen{$arch} = 1; }
+ $HadArch = 1;
+ ++$i;
+ next;
+ }
+
+ # Options with possible arguments that should pass through to compiler.
+ if (defined $CompileOptionMap{$ArgKey}) {
+ my $Cnt = $CompileOptionMap{$ArgKey};
+ push @CompileOpts,$Arg;
+ while ($Cnt > 0) { ++$i; --$Cnt; push @CompileOpts, $ARGV[$i]; }
+ next;
+ }
+
+ # Options with possible arguments that should pass through to linker.
+ if (defined $LinkerOptionMap{$ArgKey}) {
+ my $Cnt = $LinkerOptionMap{$ArgKey};
+ push @LinkOpts,$Arg;
+ while ($Cnt > 0) { ++$i; --$Cnt; push @LinkOpts, $ARGV[$i]; }
+ next;
+ }
+
+ # Options with possible arguments that should pass through to both compiler
+ # and the linker.
+ if (defined $CompilerLinkerOptionMap{$ArgKey}) {
+ my $Cnt = $CompilerLinkerOptionMap{$ArgKey};
+
+ # Check if this is an option that should have a unique value, and if so
+ # determine if the value was checked before.
+ if ($UniqueOptions{$Arg}) {
+ if (defined $Uniqued{$Arg}) {
+ $i += $Cnt;
+ next;
+ }
+ $Uniqued{$Arg} = 1;
+ }
+
+ push @CompileOpts,$Arg;
+ push @LinkOpts,$Arg;
+
+ while ($Cnt > 0) {
+ ++$i; --$Cnt;
+ push @CompileOpts, $ARGV[$i];
+ push @LinkOpts, $ARGV[$i];
+ }
+ next;
+ }
+
+ # Ignored options.
+ if (defined $IgnoredOptionMap{$ArgKey}) {
+ my $Cnt = $IgnoredOptionMap{$ArgKey};
+ while ($Cnt > 0) {
+ ++$i; --$Cnt;
+ }
+ next;
+ }
+
+ # Compile mode flags.
+ if ($Arg =~ /^-[D,I,U](.*)$/) {
+ my $Tmp = $Arg;
+ if ($1 eq '') {
+ # FIXME: Check if we are going off the end.
+ ++$i;
+ $Tmp = $Arg . $ARGV[$i];
+ }
+ push @CompileOpts,$Tmp;
+ next;
+ }
+
+ # Language.
+ if ($Arg eq '-x') {
+ $Lang = $ARGV[$i+1];
+ ++$i; next;
+ }
+
+ # Output file.
+ if ($Arg eq '-o') {
+ ++$i;
+ $Output = $ARGV[$i];
+ next;
+ }
+
+ # Get the link mode.
+ if ($Arg =~ /^-[l,L,O]/) {
+ if ($Arg eq '-O') { push @LinkOpts,'-O1'; }
+ elsif ($Arg eq '-Os') { push @LinkOpts,'-O2'; }
+ else { push @LinkOpts,$Arg; }
+ next;
+ }
+
+ if ($Arg =~ /^-std=/) {
+ push @CompileOpts,$Arg;
+ next;
+ }
+
+# if ($Arg =~ /^-f/) {
+# # FIXME: Not sure if the remaining -fxxxx options have no arguments.
+# push @CompileOpts,$Arg;
+# push @LinkOpts,$Arg; # FIXME: Not sure if these are link opts.
+# }
+
+ # Get the compiler/link mode.
+ if ($Arg =~ /^-F(.+)$/) {
+ my $Tmp = $Arg;
+ if ($1 eq '') {
+ # FIXME: Check if we are going off the end.
+ ++$i;
+ $Tmp = $Arg . $ARGV[$i];
+ }
+ push @CompileOpts,$Tmp;
+ push @LinkOpts,$Tmp;
+ next;
+ }
+
+ # Input files.
+ if ($Arg eq '-filelist') {
+ # FIXME: Make sure we aren't walking off the end.
+ open(IN, $ARGV[$i+1]);
+ while (<IN>) { s/\015?\012//; push @Files,$_; }
+ close(IN);
+ ++$i; next;
+ }
+
+ if (!($Arg =~ /^-/)) {
+ push @Files,$Arg; next;
+ }
+}
+
+if ($Action eq 'compile' or $Action eq 'link') {
+ my @Archs = keys %ArchsSeen;
+ # Skip the file if we don't support the architectures specified.
+ exit 0 if ($HadArch && scalar(@Archs) == 0);
+
+ foreach my $file (@Files) {
+ # Determine the language for the file.
+ my $FileLang = $Lang;
+
+ if (!defined($FileLang)) {
+ # Infer the language from the extension.
+ if ($file =~ /[.]([^.]+)$/) {
+ $FileLang = $LangMap{$1};
+ }
+ }
+
+ next if (!defined $FileLang);
+ next if (!defined $LangsAccepted{$FileLang});
+
+ my @CmdArgs;
+ my @AnalyzeArgs;
+
+ if ($FileLang ne 'unknown') {
+ push @CmdArgs,'-x';
+ push @CmdArgs,$FileLang;
+ }
+
+ if (defined $StoreModel) {
+ push @AnalyzeArgs, "-analyzer-store=$StoreModel";
+ }
+
+ if (defined $ConstraintsModel) {
+ push @AnalyzeArgs, "-analyzer-constraints=$ConstraintsModel";
+ }
+
+ if (defined $OutputFormat) {
+ push @AnalyzeArgs, "-analyzer-output=" . $OutputFormat;
+ if ($OutputFormat eq "plist") {
+ # Change "Output" to be a file.
+ my ($h, $f) = tempfile("report-XXXXXX", SUFFIX => ".plist",
+ DIR => $HtmlDir);
+ $ResultFile = $f;
+ $CleanupFile = $f;
+ }
+ }
+
+ push @CmdArgs,@CompileOpts;
+ push @CmdArgs,$file;
+
+ if (scalar @Archs) {
+ foreach my $arch (@Archs) {
+ my @NewArgs;
+ push @NewArgs, '-arch';
+ push @NewArgs, $arch;
+ push @NewArgs, @CmdArgs;
+ Analyze($ClangCC, \@NewArgs, \@AnalyzeArgs, $FileLang, $Output,
+ $Verbose, $HtmlDir, $file, $Analyses);
+ }
+ }
+ else {
+ Analyze($ClangCC, \@CmdArgs, \@AnalyzeArgs, $FileLang, $Output,
+ $Verbose, $HtmlDir, $file, $Analyses);
+ }
+ }
+}
+
+exit($Status >> 8);
+
diff --git a/utils/pch-test.pl b/utils/pch-test.pl
new file mode 100755
index 000000000000..2e17117a2a29
--- /dev/null
+++ b/utils/pch-test.pl
@@ -0,0 +1,61 @@
+#!/usr/bin/perl -w
+
+# This tiny little script, which should be run from the clang
+# directory (with clang-cc in your patch), tries to take each
+# compilable Clang test and build a PCH file from that test, then read
+# and dump the contents of the PCH file just created.
+use POSIX;
+
+$exitcode = 0;
+sub testfiles($$) {
+ my $suffix = shift;
+ my $language = shift;
+ my $passed = 0;
+ my $failed = 0;
+ my $skipped = 0;
+
+ @files = `ls test/*/*.$suffix`;
+ foreach $file (@files) {
+ chomp($file);
+ my $code = system("clang-cc -fsyntax-only -x $language $file > /dev/null 2>&1");
+ if ($code == 0) {
+ print(".");
+ $code = system("clang-cc -emit-pch -x $language -o $file.pch $file > /dev/null 2>&1");
+ if ($code == 0) {
+ $code = system("clang-cc -include-pch $file.pch -x $language -ast-dump /dev/null > /dev/null 2>&1");
+ if ($code == 0) {
+ $passed++;
+ } elsif (($code & 0xFF) == SIGINT) {
+ exit($exitcode);
+ } else {
+ print("\n---Failed to dump AST file for \"$file\"---\n");
+ $exitcode = 1;
+ $failed++;
+ }
+ unlink "$file.pch";
+ } elsif (($code & 0xFF) == SIGINT) {
+ exit($exitcode);
+ } else {
+ print("\n---Failed to build PCH file for \"$file\"---\n");
+ $exitcode = 1;
+ $failed++;
+ }
+ } elsif (($code & 0xFF) == SIGINT) {
+ exit($exitcode);
+ } else {
+ print("x");
+ $skipped++;
+ }
+ }
+
+ print("\n\n$passed tests passed\n");
+ print("$failed tests failed\n");
+ print("$skipped tests skipped ('x')\n")
+}
+
+printf("-----Testing precompiled headers for C-----\n");
+testfiles("c", "c");
+printf("\n-----Testing precompiled headers for Objective-C-----\n");
+testfiles("m", "objective-c");
+print("\n");
+exit($exitcode);
diff --git a/utils/scan-build b/utils/scan-build
new file mode 100755
index 000000000000..5835628d59ba
--- /dev/null
+++ b/utils/scan-build
@@ -0,0 +1,1278 @@
+#!/usr/bin/env perl
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# A script designed to wrap a build so that all calls to gcc are intercepted
+# and piped to the static analyzer.
+#
+##===----------------------------------------------------------------------===##
+
+use strict;
+use warnings;
+use FindBin qw($RealBin);
+use Digest::MD5;
+use File::Basename;
+use Term::ANSIColor;
+use Term::ANSIColor qw(:constants);
+use Cwd qw/ getcwd abs_path /;
+use Sys::Hostname;
+
+my $Verbose = 0; # Verbose output from this script.
+my $Prog = "scan-build";
+my $BuildName;
+my $BuildDate;
+my $CXX; # Leave undefined initially.
+
+my $TERM = $ENV{'TERM'};
+my $UseColor = (defined $TERM and $TERM eq 'xterm-color' and -t STDOUT
+ and defined $ENV{'SCAN_BUILD_COLOR'});
+
+my $UserName = HtmlEscape(getpwuid($<) || 'unknown');
+my $HostName = HtmlEscape(hostname() || 'unknown');
+my $CurrentDir = HtmlEscape(getcwd());
+my $CurrentDirSuffix = basename($CurrentDir);
+
+my $CmdArgs;
+
+my $HtmlTitle;
+
+my $Date = localtime();
+
+##----------------------------------------------------------------------------##
+# Diagnostics
+##----------------------------------------------------------------------------##
+
+sub Diag {
+ if ($UseColor) {
+ print BOLD, MAGENTA "$Prog: @_";
+ print RESET;
+ }
+ else {
+ print "$Prog: @_";
+ }
+}
+
+sub DiagCrashes {
+ my $Dir = shift;
+ 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")
+}
+
+sub DieDiag {
+ if ($UseColor) {
+ print BOLD, RED "$Prog: ";
+ print RESET, RED @_;
+ print RESET;
+ }
+ else {
+ print "$Prog: ", @_;
+ }
+ exit(0);
+}
+
+##----------------------------------------------------------------------------##
+# Some initial preprocessing of Clang options.
+##----------------------------------------------------------------------------##
+
+# First, look for 'clang-cc' in libexec.
+my $ClangCCSB = Cwd::realpath("$RealBin/libexec/clang-cc");
+# Second, look for 'clang-cc' in the same directory as scan-build.
+if (!defined $ClangCCSB || ! -x $ClangCCSB) {
+ $ClangCCSB = Cwd::realpath("$RealBin/clang-cc");
+}
+# Third, look for 'clang-cc' in ../libexec
+if (!defined $ClangCCSB || ! -x $ClangCCSB) {
+ $ClangCCSB = Cwd::realpath("$RealBin/../libexec/clang-cc");
+}
+# Finally, default to looking for 'clang-cc' in the path.
+if (!defined $ClangCCSB || ! -x $ClangCCSB) {
+ $ClangCCSB = "clang-cc";
+}
+my $ClangCC = $ClangCCSB;
+
+# Now find 'clang'
+my $ClangSB = Cwd::realpath("$RealBin/bin/clang");
+if (!defined $ClangSB || ! -x $ClangSB) {
+ $ClangSB = Cwd::realpath("$RealBin/clang");
+}
+# Third, look for 'clang' in ../bin
+if (!defined $ClangSB || ! -x $ClangSB) {
+ $ClangSB = Cwd::realpath("$RealBin/../bin/clang");
+}
+# Finally, default to looking for 'clang-cc' in the path.
+if (!defined $ClangSB || ! -x $ClangSB) {
+ $ClangSB = "clang";
+}
+my $Clang = $ClangSB;
+
+
+my %AvailableAnalyses;
+
+# Query clang for analysis options.
+open(PIPE, "-|", $ClangCC, "--help") or
+ DieDiag("Cannot execute '$ClangCC'\n");
+
+my $FoundAnalysis = 0;
+
+while(<PIPE>) {
+ if ($FoundAnalysis == 0) {
+ if (/Checks and Analyses/) {
+ $FoundAnalysis = 1;
+ }
+ next;
+ }
+
+ if (/^\s\s\s\s([^\s]+)\s(.+)$/) {
+ next if ($1 =~ /-dump/ or $1 =~ /-view/
+ or $1 =~ /-checker-simple/ or $1 =~ /-warn-uninit/);
+
+ $AvailableAnalyses{$1} = $2;
+ next;
+ }
+ last;
+}
+
+close (PIPE);
+
+my %AnalysesDefaultEnabled = (
+ '-warn-dead-stores' => 1,
+ '-checker-cfref' => 1,
+ '-warn-objc-methodsigs' => 1,
+ # Do not enable the missing -dealloc check by default.
+ # '-warn-objc-missing-dealloc' => 1,
+ '-warn-objc-unused-ivars' => 1,
+);
+
+##----------------------------------------------------------------------------##
+# GetHTMLRunDir - Construct an HTML directory name for the current sub-run.
+##----------------------------------------------------------------------------##
+
+sub GetHTMLRunDir {
+
+ die "Not enough arguments." if (@_ == 0);
+ my $Dir = shift @_;
+
+ my $TmpMode = 0;
+ if (!defined $Dir) {
+ if (`uname` =~ /Darwin/) {
+ $Dir = $ENV{'TMPDIR'};
+ if (!defined $Dir) { $Dir = "/tmp"; }
+ }
+ else {
+ $Dir = "/tmp";
+ }
+
+ $TmpMode = 1;
+ }
+
+ # Chop off any trailing '/' characters.
+ while ($Dir =~ /\/$/) { chop $Dir; }
+
+ # Get current date and time.
+
+ my @CurrentTime = localtime();
+
+ my $year = $CurrentTime[5] + 1900;
+ my $day = $CurrentTime[3];
+ my $month = $CurrentTime[4] + 1;
+
+ my $DateString = sprintf("%d-%02d-%02d", $year, $month, $day);
+
+ # Determine the run number.
+
+ my $RunNumber;
+
+ if (-d $Dir) {
+
+ if (! -r $Dir) {
+ DieDiag("directory '$Dir' exists but is not readable.\n");
+ }
+
+ # Iterate over all files in the specified directory.
+
+ my $max = 0;
+
+ opendir(DIR, $Dir);
+ my @FILES = grep { -d "$Dir/$_" } readdir(DIR);
+ closedir(DIR);
+
+ foreach my $f (@FILES) {
+
+ # Strip the prefix '$Prog-' if we are dumping files to /tmp.
+ if ($TmpMode) {
+ next if (!($f =~ /^$Prog-(.+)/));
+ $f = $1;
+ }
+
+
+ my @x = split/-/, $f;
+ next if (scalar(@x) != 4);
+ next if ($x[0] != $year);
+ next if ($x[1] != $month);
+ next if ($x[2] != $day);
+
+ if ($x[3] > $max) {
+ $max = $x[3];
+ }
+ }
+
+ $RunNumber = $max + 1;
+ }
+ else {
+
+ if (-x $Dir) {
+ DieDiag("'$Dir' exists but is not a directory.\n");
+ }
+
+ if ($TmpMode) {
+ DieDiag("The directory '/tmp' does not exist or cannot be accessed.\n");
+ }
+
+ # $Dir does not exist. It will be automatically created by the
+ # clang driver. Set the run number to 1.
+
+ $RunNumber = 1;
+ }
+
+ die "RunNumber must be defined!" if (!defined $RunNumber);
+
+ # Append the run number.
+ my $NewDir;
+ if ($TmpMode) {
+ $NewDir = "$Dir/$Prog-$DateString-$RunNumber";
+ }
+ else {
+ $NewDir = "$Dir/$DateString-$RunNumber";
+ }
+ system 'mkdir','-p',$NewDir;
+ return $NewDir;
+}
+
+sub SetHtmlEnv {
+
+ die "Wrong number of arguments." if (scalar(@_) != 2);
+
+ my $Args = shift;
+ my $Dir = shift;
+
+ die "No build command." if (scalar(@$Args) == 0);
+
+ my $Cmd = $$Args[0];
+
+ if ($Cmd =~ /configure/) {
+ return;
+ }
+
+ if ($Verbose) {
+ Diag("Emitting reports for this run to '$Dir'.\n");
+ }
+
+ $ENV{'CCC_ANALYZER_HTML'} = $Dir;
+}
+
+##----------------------------------------------------------------------------##
+# ComputeDigest - Compute a digest of the specified file.
+##----------------------------------------------------------------------------##
+
+sub ComputeDigest {
+ my $FName = shift;
+ DieDiag("Cannot read $FName to compute Digest.\n") if (! -r $FName);
+
+ # Use Digest::MD5. We don't have to be cryptographically secure. We're
+ # just looking for duplicate files that come from a non-malicious source.
+ # We use Digest::MD5 because it is a standard Perl module that should
+ # come bundled on most systems.
+ open(FILE, $FName) or DieDiag("Cannot open $FName when computing Digest.\n");
+ binmode FILE;
+ my $Result = Digest::MD5->new->addfile(*FILE)->hexdigest;
+ close(FILE);
+
+ # Return the digest.
+ return $Result;
+}
+
+##----------------------------------------------------------------------------##
+# UpdatePrefix - Compute the common prefix of files.
+##----------------------------------------------------------------------------##
+
+my $Prefix;
+
+sub UpdatePrefix {
+ my $x = shift;
+ my $y = basename($x);
+ $x =~ s/\Q$y\E$//;
+
+ if (!defined $Prefix) {
+ $Prefix = $x;
+ return;
+ }
+
+ chop $Prefix while (!($x =~ /^\Q$Prefix/));
+}
+
+sub GetPrefix {
+ return $Prefix;
+}
+
+##----------------------------------------------------------------------------##
+# UpdateInFilePath - Update the path in the report file.
+##----------------------------------------------------------------------------##
+
+sub UpdateInFilePath {
+ my $fname = shift;
+ my $regex = shift;
+ my $newtext = shift;
+
+ open (RIN, $fname) or die "cannot open $fname";
+ open (ROUT, ">", "$fname.tmp") or die "cannot open $fname.tmp";
+
+ while (<RIN>) {
+ s/$regex/$newtext/;
+ print ROUT $_;
+ }
+
+ close (ROUT);
+ close (RIN);
+ system("mv", "$fname.tmp", $fname);
+}
+
+##----------------------------------------------------------------------------##
+# ScanFile - Scan a report file for various identifying attributes.
+##----------------------------------------------------------------------------##
+
+# Sometimes a source file is scanned more than once, and thus produces
+# multiple error reports. We use a cache to solve this problem.
+
+my %AlreadyScanned;
+
+sub ScanFile {
+
+ my $Index = shift;
+ my $Dir = shift;
+ my $FName = shift;
+
+ # Compute a digest for the report file. Determine if we have already
+ # scanned a file that looks just like it.
+
+ my $digest = ComputeDigest("$Dir/$FName");
+
+ if (defined $AlreadyScanned{$digest}) {
+ # Redundant file. Remove it.
+ system ("rm", "-f", "$Dir/$FName");
+ return;
+ }
+
+ $AlreadyScanned{$digest} = 1;
+
+ # At this point the report file is not world readable. Make it happen.
+ system ("chmod", "644", "$Dir/$FName");
+
+ # Scan the report file for tags.
+ open(IN, "$Dir/$FName") or DieDiag("Cannot open '$Dir/$FName'\n");
+
+ my $BugType = "";
+ my $BugFile = "";
+ my $BugCategory;
+ my $BugPathLength = 1;
+ my $BugLine = 0;
+ my $found = 0;
+
+ while (<IN>) {
+
+ last if ($found == 5);
+
+ if (/<!-- BUGTYPE (.*) -->$/) {
+ $BugType = $1;
+ ++$found;
+ }
+ elsif (/<!-- BUGFILE (.*) -->$/) {
+ $BugFile = abs_path($1);
+ UpdatePrefix($BugFile);
+ ++$found;
+ }
+ elsif (/<!-- BUGPATHLENGTH (.*) -->$/) {
+ $BugPathLength = $1;
+ ++$found;
+ }
+ elsif (/<!-- BUGLINE (.*) -->$/) {
+ $BugLine = $1;
+ ++$found;
+ }
+ elsif (/<!-- BUGCATEGORY (.*) -->$/) {
+ $BugCategory = $1;
+ ++$found;
+ }
+ }
+
+ close(IN);
+
+ if (!defined $BugCategory) {
+ $BugCategory = "Other";
+ }
+
+ push @$Index,[ $FName, $BugCategory, $BugType, $BugFile, $BugLine,
+ $BugPathLength ];
+}
+
+##----------------------------------------------------------------------------##
+# CopyFiles - Copy resource files to target directory.
+##----------------------------------------------------------------------------##
+
+sub CopyFiles {
+
+ my $Dir = shift;
+
+ my $JS = Cwd::realpath("$RealBin/sorttable.js");
+
+ DieDiag("Cannot find 'sorttable.js'.\n")
+ if (! -r $JS);
+
+ system ("cp", $JS, "$Dir");
+
+ DieDiag("Could not copy 'sorttable.js' to '$Dir'.\n")
+ if (! -r "$Dir/sorttable.js");
+
+ my $CSS = Cwd::realpath("$RealBin/scanview.css");
+
+ DieDiag("Cannot find 'scanview.css'.\n")
+ if (! -r $CSS);
+
+ system ("cp", $CSS, "$Dir");
+
+ DieDiag("Could not copy 'scanview.css' to '$Dir'.\n")
+ if (! -r $CSS);
+}
+
+##----------------------------------------------------------------------------##
+# Postprocess - Postprocess the results of an analysis scan.
+##----------------------------------------------------------------------------##
+
+sub Postprocess {
+
+ my $Dir = shift;
+ my $BaseDir = shift;
+
+ die "No directory specified." if (!defined $Dir);
+
+ if (! -d $Dir) {
+ Diag("No bugs found.\n");
+ return 0;
+ }
+
+ opendir(DIR, $Dir);
+ my @files = grep { /^report-.*\.html$/ } readdir(DIR);
+ closedir(DIR);
+
+ if (scalar(@files) == 0 and ! -e "$Dir/failures") {
+ Diag("Removing directory '$Dir' because it contains no reports.\n");
+ system ("rm", "-fR", $Dir);
+ return 0;
+ }
+
+ # Scan each report file and build an index.
+ my @Index;
+ foreach my $file (@files) { ScanFile(\@Index, $Dir, $file); }
+
+ # Scan the failures directory and use the information in the .info files
+ # to update the common prefix directory.
+ my @failures;
+ my @attributes_ignored;
+ if (-d "$Dir/failures") {
+ opendir(DIR, "$Dir/failures");
+ @failures = grep { /[.]info.txt$/ && !/attribute_ignored/; } readdir(DIR);
+ closedir(DIR);
+ opendir(DIR, "$Dir/failures");
+ @attributes_ignored = grep { /^attribute_ignored/; } readdir(DIR);
+ closedir(DIR);
+ foreach my $file (@failures) {
+ open IN, "$Dir/failures/$file" or DieDiag("cannot open $file\n");
+ my $Path = <IN>;
+ if (defined $Path) { UpdatePrefix($Path); }
+ close IN;
+ }
+ }
+
+ # Generate an index.html file.
+ my $FName = "$Dir/index.html";
+ open(OUT, ">", $FName) or DieDiag("Cannot create file '$FName'\n");
+
+ # Print out the header.
+
+print OUT <<ENDTEXT;
+<html>
+<head>
+<title>${HtmlTitle}</title>
+<link type="text/css" rel="stylesheet" href="scanview.css"/>
+<script src="sorttable.js"></script>
+<script language='javascript' type="text/javascript">
+function SetDisplay(RowClass, DisplayVal)
+{
+ var Rows = document.getElementsByTagName("tr");
+ for ( var i = 0 ; i < Rows.length; ++i ) {
+ if (Rows[i].className == RowClass) {
+ Rows[i].style.display = DisplayVal;
+ }
+ }
+}
+
+function CopyCheckedStateToCheckButtons(SummaryCheckButton) {
+ var Inputs = document.getElementsByTagName("input");
+ for ( var i = 0 ; i < Inputs.length; ++i ) {
+ if (Inputs[i].type == "checkbox") {
+ if(Inputs[i] != SummaryCheckButton) {
+ Inputs[i].checked = SummaryCheckButton.checked;
+ Inputs[i].onclick();
+ }
+ }
+ }
+}
+
+function returnObjById( id ) {
+ if (document.getElementById)
+ var returnVar = document.getElementById(id);
+ else if (document.all)
+ var returnVar = document.all[id];
+ else if (document.layers)
+ var returnVar = document.layers[id];
+ return returnVar;
+}
+
+var NumUnchecked = 0;
+
+function ToggleDisplay(CheckButton, ClassName) {
+ if (CheckButton.checked) {
+ SetDisplay(ClassName, "");
+ if (--NumUnchecked == 0) {
+ returnObjById("AllBugsCheck").checked = true;
+ }
+ }
+ else {
+ SetDisplay(ClassName, "none");
+ NumUnchecked++;
+ returnObjById("AllBugsCheck").checked = false;
+ }
+}
+</script>
+<!-- SUMMARYENDHEAD -->
+</head>
+<body>
+<h1>${HtmlTitle}</h1>
+
+<table>
+<tr><th>User:</th><td>${UserName}\@${HostName}</td></tr>
+<tr><th>Working Directory:</th><td>${CurrentDir}</td></tr>
+<tr><th>Command Line:</th><td>${CmdArgs}</td></tr>
+<tr><th>Date:</th><td>${Date}</td></tr>
+ENDTEXT
+
+print OUT "<tr><th>Version:</th><td>${BuildName} (${BuildDate})</td></tr>\n"
+ if (defined($BuildName) && defined($BuildDate));
+
+print OUT <<ENDTEXT;
+</table>
+ENDTEXT
+
+ if (scalar(@files)) {
+ # Print out the summary table.
+ my %Totals;
+
+ for my $row ( @Index ) {
+ my $bug_type = ($row->[2]);
+ my $bug_category = ($row->[1]);
+ my $key = "$bug_category:$bug_type";
+
+ if (!defined $Totals{$key}) { $Totals{$key} = [1,$bug_category,$bug_type]; }
+ else { $Totals{$key}->[0]++; }
+ }
+
+ print OUT "<h2>Bug Summary</h2>";
+
+ if (defined $BuildName) {
+ print OUT "\n<p>Results in this analysis run are based on analyzer build <b>$BuildName</b>.</p>\n"
+ }
+
+ my $TotalBugs = scalar(@Index);
+print OUT <<ENDTEXT;
+<table>
+<thead><tr><td>Bug Type</td><td>Quantity</td><td class="sorttable_nosort">Display?</td></tr></thead>
+<tr style="font-weight:bold"><td class="SUMM_DESC">All Bugs</td><td class="Q">$TotalBugs</td><td><center><input type="checkbox" id="AllBugsCheck" onClick="CopyCheckedStateToCheckButtons(this);" checked/></center></td></tr>
+ENDTEXT
+
+ my $last_category;
+
+ for my $key (
+ sort {
+ my $x = $Totals{$a};
+ my $y = $Totals{$b};
+ my $res = $x->[1] cmp $y->[1];
+ $res = $x->[2] cmp $y->[2] if ($res == 0);
+ $res
+ } keys %Totals )
+ {
+ my $val = $Totals{$key};
+ my $category = $val->[1];
+ if (!defined $last_category or $last_category ne $category) {
+ $last_category = $category;
+ print OUT "<tr><th>$category</th><th colspan=2></th></tr>\n";
+ }
+ my $x = lc $key;
+ $x =~ s/[ ,'":\/()]+/_/g;
+ print OUT "<tr><td class=\"SUMM_DESC\">";
+ print OUT $val->[2];
+ print OUT "</td><td class=\"Q\">";
+ print OUT $val->[0];
+ print OUT "</td><td><center><input type=\"checkbox\" onClick=\"ToggleDisplay(this,'bt_$x');\" checked/></center></td></tr>\n";
+ }
+
+ # Print out the table of errors.
+
+print OUT <<ENDTEXT;
+</table>
+<h2>Reports</h2>
+
+<table class="sortable" style="table-layout:automatic">
+<thead><tr>
+ <td>Bug Group</td>
+ <td class="sorttable_sorted">Bug Type<span id="sorttable_sortfwdind">&nbsp;&#x25BE;</span></td>
+ <td>File</td>
+ <td class="Q">Line</td>
+ <td class="Q">Path Length</td>
+ <td class="sorttable_nosort"></td>
+ <!-- REPORTBUGCOL -->
+</tr></thead>
+<tbody>
+ENDTEXT
+
+ my $prefix = GetPrefix();
+ my $regex;
+ my $InFileRegex;
+ my $InFilePrefix = "File:</td><td>";
+
+ if (defined $prefix) {
+ $regex = qr/^\Q$prefix\E/is;
+ $InFileRegex = qr/\Q$InFilePrefix$prefix\E/is;
+ }
+
+ for my $row ( sort { $a->[2] cmp $b->[2] } @Index ) {
+ my $x = "$row->[1]:$row->[2]";
+ $x = lc $x;
+ $x =~ s/[ ,'":\/()]+/_/g;
+
+ my $ReportFile = $row->[0];
+
+ print OUT "<tr class=\"bt_$x\">";
+ print OUT "<td class=\"DESC\">";
+ print OUT $row->[1];
+ print OUT "</td>";
+ print OUT "<td class=\"DESC\">";
+ print OUT $row->[2];
+ print OUT "</td>";
+
+ # Update the file prefix.
+ my $fname = $row->[3];
+
+ if (defined $regex) {
+ $fname =~ s/$regex//;
+ UpdateInFilePath("$Dir/$ReportFile", $InFileRegex, $InFilePrefix)
+ }
+
+ print OUT "<td>";
+ my @fname = split /\//,$fname;
+ if ($#fname > 0) {
+ while ($#fname >= 0) {
+ my $x = shift @fname;
+ print OUT $x;
+ if ($#fname >= 0) {
+ print OUT "<span class=\"W\"> </span>/";
+ }
+ }
+ }
+ else {
+ print OUT $fname;
+ }
+ print OUT "</td>";
+
+ # Print out the quantities.
+ for my $j ( 4 .. 5 ) {
+ print OUT "<td class=\"Q\">$row->[$j]</td>";
+ }
+
+ # Print the rest of the columns.
+ for (my $j = 6; $j <= $#{$row}; ++$j) {
+ print OUT "<td>$row->[$j]</td>"
+ }
+
+ # Emit the "View" link.
+ print OUT "<td><a href=\"$ReportFile#EndPath\">View Report</a></td>";
+
+ # Emit REPORTBUG markers.
+ print OUT "\n<!-- REPORTBUG id=\"$ReportFile\" -->\n";
+
+ # End the row.
+ print OUT "</tr>\n";
+ }
+
+ print OUT "</tbody>\n</table>\n\n";
+ }
+
+ if (scalar (@failures) || scalar(@attributes_ignored)) {
+ print OUT "<h2>Analyzer Failures</h2>\n";
+
+ if (scalar @attributes_ignored) {
+ print OUT "The analyzer's parser ignored the following attributes:<p>\n";
+ print OUT "<table>\n";
+ print OUT "<thead><tr><td>Attribute</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>\n";
+ foreach my $file (sort @attributes_ignored) {
+ die "cannot demangle attribute name\n" if (! ($file =~ /^attribute_ignored_(.+).txt/));
+ my $attribute = $1;
+ # Open the attribute file to get the first file that failed.
+ next if (!open (ATTR, "$Dir/failures/$file"));
+ my $ppfile = <ATTR>;
+ chomp $ppfile;
+ close ATTR;
+ next if (! -e "$Dir/failures/$ppfile");
+ # Open the info file and get the name of the source file.
+ open (INFO, "$Dir/failures/$ppfile.info.txt") or
+ die "Cannot open $Dir/failures/$ppfile.info.txt\n";
+ my $srcfile = <INFO>;
+ chomp $srcfile;
+ close (INFO);
+ # Print the information in the table.
+ my $prefix = GetPrefix();
+ if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
+ print OUT "<tr><td>$attribute</td><td>$srcfile</td><td><a href=\"failures/$ppfile\">$ppfile</a></td><td><a href=\"failures/$ppfile.stderr.txt\">$ppfile.stderr.txt</a></td></tr>\n";
+ my $ppfile_clang = $ppfile;
+ $ppfile_clang =~ s/[.](.+)$/.clang.$1/;
+ print OUT " <!-- REPORTPROBLEM src=\"$srcfile\" file=\"failures/$ppfile\" clangfile=\"failures/$ppfile_clang\" stderr=\"failures/$ppfile.stderr.txt\" info=\"failures/$ppfile.info.txt\" -->\n";
+ }
+ print OUT "</table>\n";
+ }
+
+ if (scalar @failures) {
+ print OUT "<p>The analyzer had problems processing the following files:</p>\n";
+ print OUT "<table>\n";
+ print OUT "<thead><tr><td>Problem</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>\n";
+ foreach my $file (sort @failures) {
+ $file =~ /(.+).info.txt$/;
+ # Get the preprocessed file.
+ my $ppfile = $1;
+ # Open the info file and get the name of the source file.
+ open (INFO, "$Dir/failures/$file") or
+ die "Cannot open $Dir/failures/$file\n";
+ my $srcfile = <INFO>;
+ chomp $srcfile;
+ my $problem = <INFO>;
+ chomp $problem;
+ close (INFO);
+ # Print the information in the table.
+ my $prefix = GetPrefix();
+ if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
+ print OUT "<tr><td>$problem</td><td>$srcfile</td><td><a href=\"failures/$ppfile\">$ppfile</a></td><td><a href=\"failures/$ppfile.stderr.txt\">$ppfile.stderr.txt</a></td></tr>\n";
+ my $ppfile_clang = $ppfile;
+ $ppfile_clang =~ s/[.](.+)$/.clang.$1/;
+ print OUT " <!-- REPORTPROBLEM src=\"$srcfile\" file=\"failures/$ppfile\" clangfile=\"failures/$ppfile_clang\" stderr=\"failures/$ppfile.stderr.txt\" info=\"failures/$ppfile.info.txt\" -->\n";
+ }
+ 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 "</body></html>\n";
+ close(OUT);
+ CopyFiles($Dir);
+
+ # Make sure $Dir and $BaseDir are world readable/executable.
+ system("chmod", "755", $Dir);
+ if (defined $BaseDir) { system("chmod", "755", $BaseDir); }
+
+ my $Num = scalar(@Index);
+ Diag("$Num bugs found.\n");
+ if ($Num > 0 && -r "$Dir/index.html") {
+ Diag("Run 'scan-view $Dir' to examine bug reports.\n");
+ }
+
+ DiagCrashes($Dir) if (scalar @failures || scalar @attributes_ignored);
+
+ return $Num;
+}
+
+##----------------------------------------------------------------------------##
+# RunBuildCommand - Run the build command.
+##----------------------------------------------------------------------------##
+
+sub AddIfNotPresent {
+ my $Args = shift;
+ my $Arg = shift;
+ my $found = 0;
+
+ foreach my $k (@$Args) {
+ if ($k eq $Arg) {
+ $found = 1;
+ last;
+ }
+ }
+
+ if ($found == 0) {
+ push @$Args, $Arg;
+ }
+}
+
+sub RunBuildCommand {
+
+ my $Args = shift;
+ my $IgnoreErrors = shift;
+ my $Cmd = $Args->[0];
+ my $CCAnalyzer = shift;
+
+ # Get only the part of the command after the last '/'.
+ if ($Cmd =~ /\/([^\/]+)$/) {
+ $Cmd = $1;
+ }
+
+ if ($Cmd =~ /(.*\/?gcc[^\/]*$)/ or
+ $Cmd =~ /(.*\/?cc[^\/]*$)/ or
+ $Cmd =~ /(.*\/?llvm-gcc[^\/]*$)/ or
+ $Cmd =~ /(.*\/?ccc-analyzer[^\/]*$)/) {
+
+ if (!($Cmd =~ /ccc-analyzer/) and !defined $ENV{"CCC_CC"}) {
+ $ENV{"CCC_CC"} = $1;
+ }
+
+ shift @$Args;
+ unshift @$Args, $CCAnalyzer;
+ }
+ elsif ($IgnoreErrors) {
+ if ($Cmd eq "make" or $Cmd eq "gmake") {
+ AddIfNotPresent($Args,"-k");
+ AddIfNotPresent($Args,"-i");
+ }
+ elsif ($Cmd eq "xcodebuild") {
+ AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES");
+ }
+ }
+
+ if ($Cmd eq "xcodebuild") {
+ # Check if using iPhone SDK 3.0 (simulator). If so the compiler being
+ # used should be gcc-4.2.
+ if (!defined $ENV{"CCC_CC"}) {
+ for (my $i = 0 ; $i < scalar(@$Args); ++$i) {
+ if ($Args->[$i] eq "-sdk" && $i + 1 < scalar(@$Args)) {
+ if (@$Args[$i+1] =~ /^iphonesimulator3/) {
+ $ENV{"CCC_CC"} = "gcc-4.2";
+ }
+ }
+ }
+ }
+
+ # Disable distributed builds for xcodebuild.
+ AddIfNotPresent($Args,"-nodistribute");
+
+ # Disable PCH files until clang supports them.
+ AddIfNotPresent($Args,"GCC_PRECOMPILE_PREFIX_HEADER=NO");
+
+ # When 'CC' is set, xcodebuild uses it to do all linking, even if we are
+ # linking C++ object files. Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
+ # when linking such files.
+ die if (!defined $CXX);
+ my $LDPLUSPLUS = `which $CXX`;
+ $LDPLUSPLUS =~ s/\015?\012//; # strip newlines
+ $ENV{'LDPLUSPLUS'} = $LDPLUSPLUS;
+ }
+
+ return (system(@$Args) >> 8);
+}
+
+##----------------------------------------------------------------------------##
+# DisplayHelp - Utility function to display all help options.
+##----------------------------------------------------------------------------##
+
+sub DisplayHelp {
+
+print <<ENDTEXT;
+USAGE: $Prog [options] <build command> [build options]
+
+ENDTEXT
+
+ if (defined $BuildName) {
+ print "ANALYZER BUILD: $BuildName ($BuildDate)\n\n";
+ }
+
+print <<ENDTEXT;
+OPTIONS:
+
+ -analyze-headers - Also analyze functions in #included files.
+
+ -o - Target directory for HTML report files. Subdirectories
+ will be created as needed to represent separate "runs" of
+ the analyzer. If this option is not specified, a directory
+ is created in /tmp (TMPDIR on Mac OS X) to store the reports.
+
+ -h - Display this message.
+ --help
+
+ -k - Add a "keep on going" option to the specified build command.
+ --keep-going This option currently supports make and xcodebuild.
+ This is a convenience option; one can specify this
+ behavior directly using build options.
+
+ --html-title [title] - Specify the title used on generated HTML pages.
+ --html-title=[title] If not specified, a default title will be used.
+
+ -plist - By default the output of scan-build is a set of HTML files.
+ This option outputs the results as a set of .plist files.
+
+ --status-bugs - By default, the exit status of $Prog is the same as the
+ executed build command. Specifying this option causes the
+ exit status of $Prog to be 1 if it found potential bugs
+ and 0 otherwise.
+
+ --use-cc [compiler path] - By default, $Prog uses 'gcc' to compile and link
+ --use-cc=[compiler path] your C and Objective-C code. Use this option
+ to specify an alternate compiler.
+
+ --use-c++ [compiler path] - By default, $Prog uses 'g++' to compile and link
+ --use-c++=[compiler path] your C++ and Objective-C++ code. Use this option
+ to specify an alternate compiler.
+
+ -v - Verbose output from $Prog and the analyzer.
+ A second and third '-v' increases verbosity.
+
+ -V - View analysis results in a web browser when the build
+ --view completes.
+
+ADVANCED OPTIONS:
+
+ -constraints [model] - Specify the contraint engine used by the analyzer.
+ By default the 'range' model is used. Specifying
+ 'basic' uses a simpler, less powerful constraint model
+ used by checker-0.160 and earlier.
+
+ -store [model] - Specify the store model used by the analyzer. By default,
+ the 'basic' store model is used. 'region' specifies a field-
+ sensitive store model. Be warned that the 'region' model
+ is still in very early testing phase and may often crash.
+
+AVAILABLE ANALYSES (multiple analyses may be specified):
+
+ENDTEXT
+
+ foreach my $Analysis (sort keys %AvailableAnalyses) {
+ if (defined $AnalysesDefaultEnabled{$Analysis}) {
+ print " (+)";
+ }
+ else {
+ print " ";
+ }
+
+ print " $Analysis $AvailableAnalyses{$Analysis}\n";
+ }
+
+print <<ENDTEXT
+
+ NOTE: "(+)" indicates that an analysis is enabled by default unless one
+ or more analysis options are specified
+
+BUILD OPTIONS
+
+ You can specify any build option acceptable to the build command.
+
+EXAMPLE
+
+ $Prog -o /tmp/myhtmldir make -j4
+
+ The above example causes analysis reports to be deposited into
+ a subdirectory of "/tmp/myhtmldir" and to run "make" with the "-j4" option.
+ A different subdirectory is created each time $Prog analyzes a project.
+ The analyzer should support most parallel builds, but not distributed builds.
+
+ENDTEXT
+}
+
+##----------------------------------------------------------------------------##
+# HtmlEscape - HTML entity encode characters that are special in HTML
+##----------------------------------------------------------------------------##
+
+sub HtmlEscape {
+ # copy argument to new variable so we don't clobber the original
+ my $arg = shift || '';
+ my $tmp = $arg;
+ $tmp =~ s/&/&amp;/g;
+ $tmp =~ s/</&lt;/g;
+ $tmp =~ s/>/&gt;/g;
+ return $tmp;
+}
+
+##----------------------------------------------------------------------------##
+# ShellEscape - backslash escape characters that are special to the shell
+##----------------------------------------------------------------------------##
+
+sub ShellEscape {
+ # copy argument to new variable so we don't clobber the original
+ my $arg = shift || '';
+ if ($arg =~ /["\s]/) { return "'" . $arg . "'"; }
+ return $arg;
+}
+
+##----------------------------------------------------------------------------##
+# Process command-line arguments.
+##----------------------------------------------------------------------------##
+
+my $AnalyzeHeaders = 0;
+my $HtmlDir; # Parent directory to store HTML files.
+my $IgnoreErrors = 0; # Ignore build errors.
+my $ViewResults = 0; # View results when the build terminates.
+my $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found
+my @AnalysesToRun;
+my $StoreModel;
+my $ConstraintsModel;
+my $OutputFormat;
+
+if (!@ARGV) {
+ DisplayHelp();
+ exit 1;
+}
+
+while (@ARGV) {
+
+ # Scan for options we recognize.
+
+ my $arg = $ARGV[0];
+
+ if ($arg eq "-h" or $arg eq "--help") {
+ DisplayHelp();
+ exit 0;
+ }
+
+ if ($arg eq '-analyze-headers') {
+ shift @ARGV;
+ $AnalyzeHeaders = 1;
+ next;
+ }
+
+ if (defined $AvailableAnalyses{$arg}) {
+ shift @ARGV;
+ push @AnalysesToRun, $arg;
+ next;
+ }
+
+ if ($arg eq "-o") {
+ shift @ARGV;
+
+ if (!@ARGV) {
+ DieDiag("'-o' option requires a target directory name.\n");
+ }
+
+ # Construct an absolute path. Uses the current working directory
+ # as a base if the original path was not absolute.
+ $HtmlDir = abs_path(shift @ARGV);
+
+ next;
+ }
+
+ if ($arg =~ /^--html-title(=(.+))?$/) {
+ shift @ARGV;
+
+ if (!defined $2 || $2 eq '') {
+ if (!@ARGV) {
+ DieDiag("'--html-title' option requires a string.\n");
+ }
+
+ $HtmlTitle = shift @ARGV;
+ } else {
+ $HtmlTitle = $2;
+ }
+
+ next;
+ }
+
+ if ($arg eq "-k" or $arg eq "--keep-going") {
+ shift @ARGV;
+ $IgnoreErrors = 1;
+ next;
+ }
+
+ if ($arg =~ /^--use-cc(=(.+))?$/) {
+ shift @ARGV;
+ my $cc;
+
+ if (!defined $2 || $2 eq "") {
+ if (!@ARGV) {
+ DieDiag("'--use-cc' option requires a compiler executable name.\n");
+ }
+ $cc = shift @ARGV;
+ }
+ else {
+ $cc = $2;
+ }
+
+ $ENV{"CCC_CC"} = $cc;
+ next;
+ }
+
+ if ($arg =~ /^--use-c\+\+(=(.+))?$/) {
+ shift @ARGV;
+
+ if (!defined $2 || $2 eq "") {
+ if (!@ARGV) {
+ DieDiag("'--use-c++' option requires a compiler executable name.\n");
+ }
+ $CXX = shift @ARGV;
+ }
+ else {
+ $CXX = $2;
+ }
+ next;
+ }
+
+ if ($arg eq "-v") {
+ shift @ARGV;
+ $Verbose++;
+ next;
+ }
+
+ if ($arg eq "-V" or $arg eq "--view") {
+ shift @ARGV;
+ $ViewResults = 1;
+ next;
+ }
+
+ if ($arg eq "--status-bugs") {
+ shift @ARGV;
+ $ExitStatusFoundBugs = 1;
+ next;
+ }
+
+ if ($arg eq "-store") {
+ shift @ARGV;
+ $StoreModel = shift @ARGV;
+ next;
+ }
+
+ if ($arg eq "-constraints") {
+ shift @ARGV;
+ $ConstraintsModel = shift @ARGV;
+ next;
+ }
+
+ if ($arg eq "-plist") {
+ shift @ARGV;
+ $OutputFormat = "plist";
+ next;
+ }
+
+ DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
+
+ last;
+}
+
+if (!@ARGV) {
+ Diag("No build command specified.\n\n");
+ DisplayHelp();
+ exit 1;
+}
+
+$CmdArgs = HtmlEscape(join(' ', map(ShellEscape($_), @ARGV)));
+$HtmlTitle = "${CurrentDirSuffix} - scan-build results"
+ unless (defined($HtmlTitle));
+
+# Determine the output directory for the HTML reports.
+my $BaseDir = $HtmlDir;
+$HtmlDir = GetHTMLRunDir($HtmlDir);
+
+# Set the appropriate environment variables.
+SetHtmlEnv(\@ARGV, $HtmlDir);
+
+my $Cmd = Cwd::realpath("$RealBin/libexec/ccc-analyzer");
+if (!defined $Cmd || ! -x $Cmd) {
+ $Cmd = Cwd::realpath("$RealBin/ccc-analyzer");
+ DieDiag("Executable 'ccc-analyzer' does not exist at '$Cmd'\n") if(! -x $Cmd);
+}
+
+if (!defined $ClangCCSB || ! -x $ClangCCSB) {
+ Diag("'clang-cc' executable not found in '$RealBin/libexec'.\n");
+ Diag("Using 'clang-cc' from path.\n");
+}
+if (!defined $ClangSB || ! -x $ClangSB) {
+ Diag("'clang' executable not found in '$RealBin/bin'.\n");
+ Diag("Using 'clang' from path.\n");
+}
+
+if (defined $CXX) {
+ $ENV{'CXX'} = $CXX;
+}
+else {
+ $CXX = 'g++'; # This variable is used by other parts of scan-build
+ # that need to know a default C++ compiler to fall back to.
+}
+
+$ENV{'CC'} = $Cmd;
+$ENV{'CLANG_CC'} = $ClangCC;
+$ENV{'CLANG'} = $Clang;
+
+if ($Verbose >= 2) {
+ $ENV{'CCC_ANALYZER_VERBOSE'} = 1;
+}
+
+if ($Verbose >= 3) {
+ $ENV{'CCC_ANALYZER_LOG'} = 1;
+}
+
+if (scalar(@AnalysesToRun) == 0) {
+ foreach my $key (keys %AnalysesDefaultEnabled) {
+ push @AnalysesToRun,$key;
+ }
+}
+
+if ($AnalyzeHeaders) {
+ push @AnalysesToRun,"-analyzer-opt-analyze-headers";
+}
+
+$ENV{'CCC_ANALYZER_ANALYSIS'} = join ' ',@AnalysesToRun;
+
+if (defined $StoreModel) {
+ $ENV{'CCC_ANALYZER_STORE_MODEL'} = $StoreModel;
+}
+
+if (defined $ConstraintsModel) {
+ $ENV{'CCC_ANALYZER_CONSTRAINTS_MODEL'} = $ConstraintsModel;
+}
+
+if (defined $OutputFormat) {
+ $ENV{'CCC_ANALYZER_OUTPUT_FORMAT'} = $OutputFormat;
+}
+
+
+# Run the build.
+my $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd);
+
+if (defined $OutputFormat and $OutputFormat eq "plist") {
+ Diag "Analysis run complete.\n";
+ Diag "Analysis results (plist files) deposited in '$HtmlDir'\n";
+}
+else {
+ # Postprocess the HTML directory.
+ my $NumBugs = Postprocess($HtmlDir, $BaseDir);
+
+ if ($ViewResults and -r "$HtmlDir/index.html") {
+ Diag "Analysis run complete.\n";
+ Diag "Viewing analysis results in '$HtmlDir' using scan-view.\n";
+ my $ScanView = Cwd::realpath("$RealBin/scan-view");
+ if (! -x $ScanView) { $ScanView = "scan-view"; }
+ exec $ScanView, "$HtmlDir";
+ }
+
+ if ($ExitStatusFoundBugs) {
+ exit 1 if ($NumBugs > 0);
+ exit 0;
+ }
+}
+
+exit $ExitStatus;
+
diff --git a/utils/scanview.css b/utils/scanview.css
new file mode 100644
index 000000000000..a0406f37a038
--- /dev/null
+++ b/utils/scanview.css
@@ -0,0 +1,62 @@
+body { color:#000000; background-color:#ffffff }
+body { font-family: Helvetica, sans-serif; font-size:9pt }
+h1 { font-size: 14pt; }
+h2 { font-size: 12pt; }
+table { font-size:9pt }
+table { border-spacing: 0px; border: 1px solid black }
+th, table thead {
+ background-color:#eee; color:#666666;
+ font-weight: bold; cursor: default;
+ text-align:center;
+ font-weight: bold; font-family: Verdana;
+ white-space:nowrap;
+}
+.W { font-size:0px }
+th, td { padding:5px; padding-left:8px; text-align:left }
+td.SUMM_DESC { padding-left:12px }
+td.DESC { white-space:pre }
+td.Q { text-align:right }
+td { text-align:left }
+tbody.scrollContent { overflow:auto }
+
+table.form_group {
+ background-color: #ccc;
+ border: 1px solid #333;
+ padding: 2px;
+}
+
+table.form_inner_group {
+ background-color: #ccc;
+ border: 1px solid #333;
+ padding: 0px;
+}
+
+table.form {
+ background-color: #999;
+ border: 1px solid #333;
+ padding: 2px;
+}
+
+td.form_label {
+ text-align: right;
+ vertical-align: top;
+}
+/* For one line entires */
+td.form_clabel {
+ text-align: right;
+ vertical-align: center;
+}
+td.form_value {
+ text-align: left;
+ vertical-align: top;
+}
+td.form_submit {
+ text-align: right;
+ vertical-align: top;
+}
+
+h1.SubmitFail {
+ color: #f00;
+}
+h1.SubmitOk {
+}
diff --git a/utils/sorttable.js b/utils/sorttable.js
new file mode 100644
index 000000000000..4352d3be0a5f
--- /dev/null
+++ b/utils/sorttable.js
@@ -0,0 +1,493 @@
+/*
+ SortTable
+ version 2
+ 7th April 2007
+ Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
+
+ Instructions:
+ Download this file
+ Add <script src="sorttable.js"></script> to your HTML
+ Add class="sortable" to any table you'd like to make sortable
+ Click on the headers to sort
+
+ Thanks to many, many people for contributions and suggestions.
+ Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
+ This basically means: do what you want with it.
+*/
+
+
+var stIsIE = /*@cc_on!@*/false;
+
+sorttable = {
+ init: function() {
+ // quit if this function has already been called
+ if (arguments.callee.done) return;
+ // flag this function so we don't do the same thing twice
+ arguments.callee.done = true;
+ // kill the timer
+ if (_timer) clearInterval(_timer);
+
+ if (!document.createElement || !document.getElementsByTagName) return;
+
+ sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
+
+ forEach(document.getElementsByTagName('table'), function(table) {
+ if (table.className.search(/\bsortable\b/) != -1) {
+ sorttable.makeSortable(table);
+ }
+ });
+
+ },
+
+ makeSortable: function(table) {
+ if (table.getElementsByTagName('thead').length == 0) {
+ // table doesn't have a tHead. Since it should have, create one and
+ // put the first table row in it.
+ the = document.createElement('thead');
+ the.appendChild(table.rows[0]);
+ table.insertBefore(the,table.firstChild);
+ }
+ // Safari doesn't support table.tHead, sigh
+ if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
+
+ if (table.tHead.rows.length != 1) return; // can't cope with two header rows
+
+ // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
+ // "total" rows, for example). This is B&R, since what you're supposed
+ // to do is put them in a tfoot. So, if there are sortbottom rows,
+ // for backwards compatibility, move them to tfoot (creating it if needed).
+ sortbottomrows = [];
+ for (var i=0; i<table.rows.length; i++) {
+ if (table.rows[i].className.search(/\bsortbottom\b/) != -1) {
+ sortbottomrows[sortbottomrows.length] = table.rows[i];
+ }
+ }
+ if (sortbottomrows) {
+ if (table.tFoot == null) {
+ // table doesn't have a tfoot. Create one.
+ tfo = document.createElement('tfoot');
+ table.appendChild(tfo);
+ }
+ for (var i=0; i<sortbottomrows.length; i++) {
+ tfo.appendChild(sortbottomrows[i]);
+ }
+ delete sortbottomrows;
+ }
+
+ // work through each column and calculate its type
+ headrow = table.tHead.rows[0].cells;
+ for (var i=0; i<headrow.length; i++) {
+ // manually override the type with a sorttable_type attribute
+ if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col
+ mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
+ if (mtch) { override = mtch[1]; }
+ if (mtch && typeof sorttable["sort_"+override] == 'function') {
+ headrow[i].sorttable_sortfunction = sorttable["sort_"+override];
+ } else {
+ headrow[i].sorttable_sortfunction = sorttable.guessType(table,i);
+ }
+ // make it clickable to sort
+ headrow[i].sorttable_columnindex = i;
+ headrow[i].sorttable_tbody = table.tBodies[0];
+ dean_addEvent(headrow[i],"click", function(e) {
+
+ if (this.className.search(/\bsorttable_sorted\b/) != -1) {
+ // if we're already sorted by this column, just
+ // reverse the table, which is quicker
+ sorttable.reverse(this.sorttable_tbody);
+ this.className = this.className.replace('sorttable_sorted',
+ 'sorttable_sorted_reverse');
+ this.removeChild(document.getElementById('sorttable_sortfwdind'));
+ sortrevind = document.createElement('span');
+ sortrevind.id = "sorttable_sortrevind";
+ sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25B4;';
+ this.appendChild(sortrevind);
+ return;
+ }
+ if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
+ // if we're already sorted by this column in reverse, just
+ // re-reverse the table, which is quicker
+ sorttable.reverse(this.sorttable_tbody);
+ this.className = this.className.replace('sorttable_sorted_reverse',
+ 'sorttable_sorted');
+ this.removeChild(document.getElementById('sorttable_sortrevind'));
+ sortfwdind = document.createElement('span');
+ sortfwdind.id = "sorttable_sortfwdind";
+ sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
+ this.appendChild(sortfwdind);
+ return;
+ }
+
+ // remove sorttable_sorted classes
+ theadrow = this.parentNode;
+ forEach(theadrow.childNodes, function(cell) {
+ if (cell.nodeType == 1) { // an element
+ cell.className = cell.className.replace('sorttable_sorted_reverse','');
+ cell.className = cell.className.replace('sorttable_sorted','');
+ }
+ });
+ sortfwdind = document.getElementById('sorttable_sortfwdind');
+ if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); }
+ sortrevind = document.getElementById('sorttable_sortrevind');
+ if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); }
+
+ this.className += ' sorttable_sorted';
+ sortfwdind = document.createElement('span');
+ sortfwdind.id = "sorttable_sortfwdind";
+ sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
+ this.appendChild(sortfwdind);
+
+ // build an array to sort. This is a Schwartzian transform thing,
+ // i.e., we "decorate" each row with the actual sort key,
+ // sort based on the sort keys, and then put the rows back in order
+ // which is a lot faster because you only do getInnerText once per row
+ row_array = [];
+ col = this.sorttable_columnindex;
+ rows = this.sorttable_tbody.rows;
+ for (var j=0; j<rows.length; j++) {
+ row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]];
+ }
+ /* If you want a stable sort, uncomment the following line */
+ sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
+ /* and comment out this one */
+ //row_array.sort(this.sorttable_sortfunction);
+
+ tb = this.sorttable_tbody;
+ for (var j=0; j<row_array.length; j++) {
+ tb.appendChild(row_array[j][1]);
+ }
+
+ delete row_array;
+ });
+ }
+ }
+ },
+
+ guessType: function(table, column) {
+ // guess the type of a column based on its first non-blank row
+ sortfn = sorttable.sort_alpha;
+ for (var i=0; i<table.tBodies[0].rows.length; i++) {
+ text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
+ if (text != '') {
+ if (text.match(/^-?[£$¤]?[\d,.]+%?$/)) {
+ return sorttable.sort_numeric;
+ }
+ // check for a date: dd/mm/yyyy or dd/mm/yy
+ // can have / or . or - as separator
+ // can be mm/dd as well
+ possdate = text.match(sorttable.DATE_RE)
+ if (possdate) {
+ // looks like a date
+ first = parseInt(possdate[1]);
+ second = parseInt(possdate[2]);
+ if (first > 12) {
+ // definitely dd/mm
+ return sorttable.sort_ddmm;
+ } else if (second > 12) {
+ return sorttable.sort_mmdd;
+ } else {
+ // looks like a date, but we can't tell which, so assume
+ // that it's dd/mm (English imperialism!) and keep looking
+ sortfn = sorttable.sort_ddmm;
+ }
+ }
+ }
+ }
+ return sortfn;
+ },
+
+ getInnerText: function(node) {
+ // gets the text we want to use for sorting for a cell.
+ // strips leading and trailing whitespace.
+ // this is *not* a generic getInnerText function; it's special to sorttable.
+ // for example, you can override the cell text with a customkey attribute.
+ // it also gets .value for <input> fields.
+
+ hasInputs = (typeof node.getElementsByTagName == 'function') &&
+ node.getElementsByTagName('input').length;
+
+ if (node.getAttribute("sorttable_customkey") != null) {
+ return node.getAttribute("sorttable_customkey");
+ }
+ else if (typeof node.textContent != 'undefined' && !hasInputs) {
+ return node.textContent.replace(/^\s+|\s+$/g, '');
+ }
+ else if (typeof node.innerText != 'undefined' && !hasInputs) {
+ return node.innerText.replace(/^\s+|\s+$/g, '');
+ }
+ else if (typeof node.text != 'undefined' && !hasInputs) {
+ return node.text.replace(/^\s+|\s+$/g, '');
+ }
+ else {
+ switch (node.nodeType) {
+ case 3:
+ if (node.nodeName.toLowerCase() == 'input') {
+ return node.value.replace(/^\s+|\s+$/g, '');
+ }
+ case 4:
+ return node.nodeValue.replace(/^\s+|\s+$/g, '');
+ break;
+ case 1:
+ case 11:
+ var innerText = '';
+ for (var i = 0; i < node.childNodes.length; i++) {
+ innerText += sorttable.getInnerText(node.childNodes[i]);
+ }
+ return innerText.replace(/^\s+|\s+$/g, '');
+ break;
+ default:
+ return '';
+ }
+ }
+ },
+
+ reverse: function(tbody) {
+ // reverse the rows in a tbody
+ newrows = [];
+ for (var i=0; i<tbody.rows.length; i++) {
+ newrows[newrows.length] = tbody.rows[i];
+ }
+ for (var i=newrows.length-1; i>=0; i--) {
+ tbody.appendChild(newrows[i]);
+ }
+ delete newrows;
+ },
+
+ /* sort functions
+ each sort function takes two parameters, a and b
+ you are comparing a[0] and b[0] */
+ sort_numeric: function(a,b) {
+ aa = parseFloat(a[0].replace(/[^0-9.-]/g,''));
+ if (isNaN(aa)) aa = 0;
+ bb = parseFloat(b[0].replace(/[^0-9.-]/g,''));
+ if (isNaN(bb)) bb = 0;
+ return aa-bb;
+ },
+ sort_alpha: function(a,b) {
+ if (a[0]==b[0]) return 0;
+ if (a[0]<b[0]) return -1;
+ return 1;
+ },
+ sort_ddmm: function(a,b) {
+ mtch = a[0].match(sorttable.DATE_RE);
+ y = mtch[3]; m = mtch[2]; d = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt1 = y+m+d;
+ mtch = b[0].match(sorttable.DATE_RE);
+ y = mtch[3]; m = mtch[2]; d = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt2 = y+m+d;
+ if (dt1==dt2) return 0;
+ if (dt1<dt2) return -1;
+ return 1;
+ },
+ sort_mmdd: function(a,b) {
+ mtch = a[0].match(sorttable.DATE_RE);
+ y = mtch[3]; d = mtch[2]; m = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt1 = y+m+d;
+ mtch = b[0].match(sorttable.DATE_RE);
+ y = mtch[3]; d = mtch[2]; m = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt2 = y+m+d;
+ if (dt1==dt2) return 0;
+ if (dt1<dt2) return -1;
+ return 1;
+ },
+
+ shaker_sort: function(list, comp_func) {
+ // A stable sort function to allow multi-level sorting of data
+ // see: http://en.wikipedia.org/wiki/Cocktail_sort
+ // thanks to Joseph Nahmias
+ var b = 0;
+ var t = list.length - 1;
+ var swap = true;
+
+ while(swap) {
+ swap = false;
+ for(var i = b; i < t; ++i) {
+ if ( comp_func(list[i], list[i+1]) > 0 ) {
+ var q = list[i]; list[i] = list[i+1]; list[i+1] = q;
+ swap = true;
+ }
+ } // for
+ t--;
+
+ if (!swap) break;
+
+ for(var i = t; i > b; --i) {
+ if ( comp_func(list[i], list[i-1]) < 0 ) {
+ var q = list[i]; list[i] = list[i-1]; list[i-1] = q;
+ swap = true;
+ }
+ } // for
+ b++;
+
+ } // while(swap)
+ }
+}
+
+/* ******************************************************************
+ Supporting functions: bundled here to avoid depending on a library
+ ****************************************************************** */
+
+// Dean Edwards/Matthias Miller/John Resig
+
+/* for Mozilla/Opera9 */
+if (document.addEventListener) {
+ document.addEventListener("DOMContentLoaded", sorttable.init, false);
+}
+
+/* for Internet Explorer */
+/*@cc_on @*/
+/*@if (@_win32)
+ document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
+ var script = document.getElementById("__ie_onload");
+ script.onreadystatechange = function() {
+ if (this.readyState == "complete") {
+ sorttable.init(); // call the onload handler
+ }
+ };
+/*@end @*/
+
+/* for Safari */
+if (/WebKit/i.test(navigator.userAgent)) { // sniff
+ var _timer = setInterval(function() {
+ if (/loaded|complete/.test(document.readyState)) {
+ sorttable.init(); // call the onload handler
+ }
+ }, 10);
+}
+
+/* for other browsers */
+window.onload = sorttable.init;
+
+// written by Dean Edwards, 2005
+// with input from Tino Zijdel, Matthias Miller, Diego Perini
+
+// http://dean.edwards.name/weblog/2005/10/add-event/
+
+function dean_addEvent(element, type, handler) {
+ if (element.addEventListener) {
+ element.addEventListener(type, handler, false);
+ } else {
+ // assign each event handler a unique ID
+ if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++;
+ // create a hash table of event types for the element
+ if (!element.events) element.events = {};
+ // create a hash table of event handlers for each element/event pair
+ var handlers = element.events[type];
+ if (!handlers) {
+ handlers = element.events[type] = {};
+ // store the existing event handler (if there is one)
+ if (element["on" + type]) {
+ handlers[0] = element["on" + type];
+ }
+ }
+ // store the event handler in the hash table
+ handlers[handler.$$guid] = handler;
+ // assign a global event handler to do all the work
+ element["on" + type] = handleEvent;
+ }
+};
+// a counter used to create unique IDs
+dean_addEvent.guid = 1;
+
+function removeEvent(element, type, handler) {
+ if (element.removeEventListener) {
+ element.removeEventListener(type, handler, false);
+ } else {
+ // delete the event handler from the hash table
+ if (element.events && element.events[type]) {
+ delete element.events[type][handler.$$guid];
+ }
+ }
+};
+
+function handleEvent(event) {
+ var returnValue = true;
+ // grab the event object (IE uses a global event object)
+ event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
+ // get a reference to the hash table of event handlers
+ var handlers = this.events[event.type];
+ // execute each event handler
+ for (var i in handlers) {
+ this.$$handleEvent = handlers[i];
+ if (this.$$handleEvent(event) === false) {
+ returnValue = false;
+ }
+ }
+ return returnValue;
+};
+
+function fixEvent(event) {
+ // add W3C standard event methods
+ event.preventDefault = fixEvent.preventDefault;
+ event.stopPropagation = fixEvent.stopPropagation;
+ return event;
+};
+fixEvent.preventDefault = function() {
+ this.returnValue = false;
+};
+fixEvent.stopPropagation = function() {
+ this.cancelBubble = true;
+}
+
+// Dean's forEach: http://dean.edwards.name/base/forEach.js
+/*
+ forEach, version 1.0
+ Copyright 2006, Dean Edwards
+ License: http://www.opensource.org/licenses/mit-license.php
+*/
+
+// array-like enumeration
+if (!Array.forEach) { // mozilla already supports this
+ Array.forEach = function(array, block, context) {
+ for (var i = 0; i < array.length; i++) {
+ block.call(context, array[i], i, array);
+ }
+ };
+}
+
+// generic enumeration
+Function.prototype.forEach = function(object, block, context) {
+ for (var key in object) {
+ if (typeof this.prototype[key] == "undefined") {
+ block.call(context, object[key], key, object);
+ }
+ }
+};
+
+// character enumeration
+String.forEach = function(string, block, context) {
+ Array.forEach(string.split(""), function(chr, index) {
+ block.call(context, chr, index, string);
+ });
+};
+
+// globally resolve forEach enumeration
+var forEach = function(object, block, context) {
+ if (object) {
+ var resolve = Object; // default
+ if (object instanceof Function) {
+ // functions have a "length" property
+ resolve = Function;
+ } else if (object.forEach instanceof Function) {
+ // the object implements a custom forEach method so use that
+ object.forEach(block, context);
+ return;
+ } else if (typeof object == "string") {
+ // the object is a string
+ resolve = String;
+ } else if (typeof object.length == "number") {
+ // the object is array-like
+ resolve = Array;
+ }
+ resolve.forEach(object, block, context);
+ }
+};
+
diff --git a/utils/test/Makefile.multi b/utils/test/Makefile.multi
new file mode 100644
index 000000000000..3e9cd5669aa8
--- /dev/null
+++ b/utils/test/Makefile.multi
@@ -0,0 +1,21 @@
+LEVEL = ../../..
+include $(LEVEL)/Makefile.common
+
+# Test in all immediate subdirectories if unset.
+TESTDIRS ?= $(shell echo $(PROJ_SRC_DIR)/*/)
+
+ifndef TESTARGS
+ifdef VERBOSE
+TESTARGS = -v
+else
+TESTARGS = -s
+endif
+endif
+
+all::
+ @ PATH=$(ToolDir):$(LLVM_SRC_ROOT)/test/Scripts:$$PATH VG=$(VG) ../utils/test/MultiTestRunner.py $(TESTARGS) $(TESTDIRS)
+
+clean::
+ @ rm -rf Output/
+
+.PHONY: all report clean
diff --git a/utils/test/MultiTestRunner.py b/utils/test/MultiTestRunner.py
new file mode 100755
index 000000000000..57650f9e275f
--- /dev/null
+++ b/utils/test/MultiTestRunner.py
@@ -0,0 +1,331 @@
+#!/usr/bin/python
+
+"""
+MultiTestRunner - Harness for running multiple tests in the simple clang style.
+
+TODO
+--
+ - Fix Ctrl-c issues
+ - Use a timeout
+ - Detect signalled failures (abort)
+ - Better support for finding tests
+"""
+
+# TOD
+import os, sys, re, random, time
+import threading
+import ProgressBar
+import TestRunner
+from TestRunner import TestStatus
+from Queue import Queue
+
+kTestFileExtensions = set(['.mi','.i','.c','.cpp','.m','.mm','.ll'])
+
+def getTests(inputs):
+ for path in inputs:
+ if not os.path.exists(path):
+ print >>sys.stderr,"WARNING: Invalid test \"%s\""%(path,)
+ continue
+
+ if os.path.isdir(path):
+ for dirpath,dirnames,filenames in os.walk(path):
+ dotTests = os.path.join(dirpath,'.tests')
+ if os.path.exists(dotTests):
+ for ln in open(dotTests):
+ if ln.strip():
+ yield os.path.join(dirpath,ln.strip())
+ else:
+ # FIXME: This doesn't belong here
+ if 'Output' in dirnames:
+ dirnames.remove('Output')
+ for f in filenames:
+ base,ext = os.path.splitext(f)
+ if ext in kTestFileExtensions:
+ yield os.path.join(dirpath,f)
+ else:
+ yield path
+
+class TestingProgressDisplay:
+ def __init__(self, opts, numTests, progressBar=None):
+ self.opts = opts
+ self.numTests = numTests
+ self.digits = len(str(self.numTests))
+ self.current = None
+ self.lock = threading.Lock()
+ self.progressBar = progressBar
+ self.progress = 0.
+
+ def update(self, index, tr):
+ # Avoid locking overhead in quiet mode
+ if self.opts.quiet and not tr.failed():
+ return
+
+ # Output lock
+ self.lock.acquire()
+ try:
+ self.handleUpdate(index, tr)
+ finally:
+ self.lock.release()
+
+ def finish(self):
+ if self.progressBar:
+ self.progressBar.clear()
+ elif self.opts.succinct:
+ sys.stdout.write('\n')
+
+ def handleUpdate(self, index, tr):
+ if self.progressBar:
+ if tr.failed():
+ self.progressBar.clear()
+ else:
+ # Force monotonicity
+ self.progress = max(self.progress, float(index)/self.numTests)
+ self.progressBar.update(self.progress, tr.path)
+ return
+ elif self.opts.succinct:
+ if not tr.failed():
+ sys.stdout.write('.')
+ sys.stdout.flush()
+ return
+ else:
+ sys.stdout.write('\n')
+
+ extra = ''
+ if tr.code==TestStatus.Invalid:
+ extra = ' - (Invalid test)'
+ elif tr.code==TestStatus.NoRunLine:
+ extra = ' - (No RUN line)'
+ elif tr.failed():
+ extra = ' - %s'%(TestStatus.getName(tr.code).upper(),)
+ print '%*d/%*d - %s%s'%(self.digits, index+1, self.digits,
+ self.numTests, tr.path, extra)
+
+ if tr.failed() and self.opts.showOutput:
+ TestRunner.cat(tr.testResults, sys.stdout)
+
+class TestResult:
+ def __init__(self, path, code, testResults):
+ self.path = path
+ self.code = code
+ self.testResults = testResults
+
+ def failed(self):
+ return self.code in (TestStatus.Fail,TestStatus.XPass)
+
+class TestProvider:
+ def __init__(self, opts, tests, display):
+ self.opts = opts
+ self.tests = tests
+ self.index = 0
+ self.lock = threading.Lock()
+ self.results = [None]*len(self.tests)
+ self.startTime = time.time()
+ self.progress = display
+
+ def get(self):
+ self.lock.acquire()
+ try:
+ if self.opts.maxTime is not None:
+ if time.time() - self.startTime > self.opts.maxTime:
+ return None
+ if self.index >= len(self.tests):
+ return None
+ item = self.tests[self.index],self.index
+ self.index += 1
+ return item
+ finally:
+ self.lock.release()
+
+ def setResult(self, index, result):
+ self.results[index] = result
+ self.progress.update(index, result)
+
+class Tester(threading.Thread):
+ def __init__(self, provider):
+ threading.Thread.__init__(self)
+ self.provider = provider
+
+ def run(self):
+ while 1:
+ item = self.provider.get()
+ if item is None:
+ break
+ self.runTest(item)
+
+ def runTest(self, (path,index)):
+ command = path
+ # Use hand concatentation here because we want to override
+ # absolute paths.
+ output = 'Output/' + path + '.out'
+ testname = path
+ testresults = 'Output/' + path + '.testresults'
+ TestRunner.mkdir_p(os.path.dirname(testresults))
+ numTests = len(self.provider.tests)
+ digits = len(str(numTests))
+ code = None
+ try:
+ opts = self.provider.opts
+ if opts.debugDoNotTest:
+ code = None
+ else:
+ code = TestRunner.runOneTest(path, command, output, testname,
+ opts.clang,
+ useValgrind=opts.useValgrind,
+ useDGCompat=opts.useDGCompat,
+ useScript=opts.testScript,
+ output=open(testresults,'w'))
+ except KeyboardInterrupt:
+ # This is a sad hack. Unfortunately subprocess goes
+ # bonkers with ctrl-c and we start forking merrily.
+ print 'Ctrl-C detected, goodbye.'
+ os.kill(0,9)
+
+ self.provider.setResult(index, TestResult(path, code, testresults))
+
+def detectCPUs():
+ """
+ Detects the number of CPUs on a system. Cribbed from pp.
+ """
+ # Linux, Unix and MacOS:
+ if hasattr(os, "sysconf"):
+ if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"):
+ # Linux & Unix:
+ ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
+ if isinstance(ncpus, int) and ncpus > 0:
+ return ncpus
+ else: # OSX:
+ return int(os.popen2("sysctl -n hw.ncpu")[1].read())
+ # Windows:
+ if os.environ.has_key("NUMBER_OF_PROCESSORS"):
+ ncpus = int(os.environ["NUMBER_OF_PROCESSORS"]);
+ if ncpus > 0:
+ return ncpus
+ return 1 # Default
+
+def main():
+ global options
+ from optparse import OptionParser
+ parser = OptionParser("usage: %prog [options] {inputs}")
+ parser.add_option("-j", "--threads", dest="numThreads",
+ help="Number of testing threads",
+ type=int, action="store",
+ default=detectCPUs())
+ parser.add_option("", "--clang", dest="clang",
+ help="Program to use as \"clang\"",
+ action="store", default="clang")
+ parser.add_option("", "--vg", dest="useValgrind",
+ help="Run tests under valgrind",
+ action="store_true", default=False)
+ parser.add_option("", "--dg", dest="useDGCompat",
+ help="Use llvm dejagnu compatibility mode",
+ action="store_true", default=False)
+ parser.add_option("", "--script", dest="testScript",
+ help="Default script to use",
+ action="store", default=None)
+ parser.add_option("-v", "--verbose", dest="showOutput",
+ help="Show all test output",
+ action="store_true", default=False)
+ parser.add_option("-q", "--quiet", dest="quiet",
+ help="Suppress no error output",
+ action="store_true", default=False)
+ parser.add_option("-s", "--succinct", dest="succinct",
+ help="Reduce amount of output",
+ action="store_true", default=False)
+ parser.add_option("", "--max-tests", dest="maxTests",
+ help="Maximum number of tests to run",
+ action="store", type=int, default=None)
+ parser.add_option("", "--max-time", dest="maxTime",
+ help="Maximum time to spend testing (in seconds)",
+ action="store", type=float, default=None)
+ parser.add_option("", "--shuffle", dest="shuffle",
+ help="Run tests in random order",
+ action="store_true", default=False)
+ parser.add_option("", "--seed", dest="seed",
+ help="Seed for random number generator (default: random).",
+ action="store", default=None)
+ parser.add_option("", "--no-progress-bar", dest="useProgressBar",
+ help="Do not use curses based progress bar",
+ action="store_false", default=True)
+ parser.add_option("", "--debug-do-not-test", dest="debugDoNotTest",
+ help="DEBUG: Skip running actual test script",
+ action="store_true", default=False)
+ (opts, args) = parser.parse_args()
+
+ if not args:
+ parser.error('No inputs specified')
+
+ # FIXME: It could be worth loading these in parallel with testing.
+ allTests = list(getTests(args))
+ allTests.sort()
+
+ tests = allTests
+ if opts.seed is not None:
+ try:
+ seed = int(opts.seed)
+ except:
+ parser.error('--seed argument should be an integer')
+ random.seed(seed)
+ if opts.shuffle:
+ random.shuffle(tests)
+ if opts.maxTests is not None:
+ tests = tests[:opts.maxTests]
+
+ extra = ''
+ if len(tests) != len(allTests):
+ extra = ' of %d'%(len(allTests),)
+ header = '-- Testing: %d%s tests, %d threads --'%(len(tests),extra,opts.numThreads)
+
+ progressBar = None
+ if not opts.quiet:
+ if opts.useProgressBar:
+ try:
+ tc = ProgressBar.TerminalController()
+ progressBar = ProgressBar.ProgressBar(tc, header)
+ except ValueError:
+ pass
+
+ if not progressBar:
+ print header
+
+ display = TestingProgressDisplay(opts, len(tests), progressBar)
+ provider = TestProvider(opts, tests, display)
+
+ testers = [Tester(provider) for i in range(opts.numThreads)]
+ startTime = time.time()
+ for t in testers:
+ t.start()
+ try:
+ for t in testers:
+ t.join()
+ except KeyboardInterrupt:
+ sys.exit(1)
+
+ display.finish()
+
+ if not opts.quiet:
+ print 'Testing Time: %.2fs'%(time.time() - startTime)
+
+ # List test results organized organized by kind.
+ byCode = {}
+ for t in provider.results:
+ if t:
+ if t.code not in byCode:
+ byCode[t.code] = []
+ byCode[t.code].append(t)
+ for title,code in (('Expected Failures', TestStatus.XFail),
+ ('Unexpected Passing Tests', TestStatus.XPass),
+ ('Failing Tests', TestStatus.Fail)):
+ elts = byCode.get(code)
+ if not elts:
+ continue
+ print '*'*20
+ print '%s (%d):' % (title, len(elts))
+ for tr in elts:
+ print '\t%s'%(tr.path,)
+
+ numFailures = len(byCode.get(TestStatus.Fail,[]))
+ if numFailures:
+ print '\nFailures: %d' % (numFailures,)
+
+if __name__=='__main__':
+ main()
diff --git a/utils/test/ProgressBar.py b/utils/test/ProgressBar.py
new file mode 100644
index 000000000000..2e1f24ae79a1
--- /dev/null
+++ b/utils/test/ProgressBar.py
@@ -0,0 +1,227 @@
+#!/usr/bin/python
+
+# Source: http://code.activestate.com/recipes/475116/, with
+# modifications by Daniel Dunbar.
+
+import sys, re, time
+
+class TerminalController:
+ """
+ A class that can be used to portably generate formatted output to
+ a terminal.
+
+ `TerminalController` defines a set of instance variables whose
+ values are initialized to the control sequence necessary to
+ perform a given action. These can be simply included in normal
+ output to the terminal:
+
+ >>> term = TerminalController()
+ >>> print 'This is '+term.GREEN+'green'+term.NORMAL
+
+ Alternatively, the `render()` method can used, which replaces
+ '${action}' with the string required to perform 'action':
+
+ >>> term = TerminalController()
+ >>> print term.render('This is ${GREEN}green${NORMAL}')
+
+ If the terminal doesn't support a given action, then the value of
+ the corresponding instance variable will be set to ''. As a
+ result, the above code will still work on terminals that do not
+ support color, except that their output will not be colored.
+ Also, this means that you can test whether the terminal supports a
+ given action by simply testing the truth value of the
+ corresponding instance variable:
+
+ >>> term = TerminalController()
+ >>> if term.CLEAR_SCREEN:
+ ... print 'This terminal supports clearning the screen.'
+
+ Finally, if the width and height of the terminal are known, then
+ they will be stored in the `COLS` and `LINES` attributes.
+ """
+ # Cursor movement:
+ BOL = '' #: Move the cursor to the beginning of the line
+ UP = '' #: Move the cursor up one line
+ DOWN = '' #: Move the cursor down one line
+ LEFT = '' #: Move the cursor left one char
+ RIGHT = '' #: Move the cursor right one char
+
+ # Deletion:
+ CLEAR_SCREEN = '' #: Clear the screen and move to home position
+ CLEAR_EOL = '' #: Clear to the end of the line.
+ CLEAR_BOL = '' #: Clear to the beginning of the line.
+ CLEAR_EOS = '' #: Clear to the end of the screen
+
+ # Output modes:
+ BOLD = '' #: Turn on bold mode
+ BLINK = '' #: Turn on blink mode
+ DIM = '' #: Turn on half-bright mode
+ REVERSE = '' #: Turn on reverse-video mode
+ NORMAL = '' #: Turn off all modes
+
+ # Cursor display:
+ HIDE_CURSOR = '' #: Make the cursor invisible
+ SHOW_CURSOR = '' #: Make the cursor visible
+
+ # Terminal size:
+ COLS = None #: Width of the terminal (None for unknown)
+ LINES = None #: Height of the terminal (None for unknown)
+
+ # Foreground colors:
+ BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = ''
+
+ # Background colors:
+ BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = ''
+ BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = ''
+
+ _STRING_CAPABILITIES = """
+ BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1
+ CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold
+ BLINK=blink DIM=dim REVERSE=rev UNDERLINE=smul NORMAL=sgr0
+ HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split()
+ _COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split()
+ _ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split()
+
+ def __init__(self, term_stream=sys.stdout):
+ """
+ Create a `TerminalController` and initialize its attributes
+ with appropriate values for the current terminal.
+ `term_stream` is the stream that will be used for terminal
+ output; if this stream is not a tty, then the terminal is
+ assumed to be a dumb terminal (i.e., have no capabilities).
+ """
+ # Curses isn't available on all platforms
+ try: import curses
+ except: return
+
+ # If the stream isn't a tty, then assume it has no capabilities.
+ if not term_stream.isatty(): return
+
+ # Check the terminal type. If we fail, then assume that the
+ # terminal has no capabilities.
+ try: curses.setupterm()
+ except: return
+
+ # Look up numeric capabilities.
+ self.COLS = curses.tigetnum('cols')
+ self.LINES = curses.tigetnum('lines')
+
+ # Look up string capabilities.
+ for capability in self._STRING_CAPABILITIES:
+ (attrib, cap_name) = capability.split('=')
+ setattr(self, attrib, self._tigetstr(cap_name) or '')
+
+ # Colors
+ set_fg = self._tigetstr('setf')
+ if set_fg:
+ for i,color in zip(range(len(self._COLORS)), self._COLORS):
+ setattr(self, color, curses.tparm(set_fg, i) or '')
+ set_fg_ansi = self._tigetstr('setaf')
+ if set_fg_ansi:
+ for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
+ setattr(self, color, curses.tparm(set_fg_ansi, i) or '')
+ set_bg = self._tigetstr('setb')
+ if set_bg:
+ for i,color in zip(range(len(self._COLORS)), self._COLORS):
+ setattr(self, 'BG_'+color, curses.tparm(set_bg, i) or '')
+ set_bg_ansi = self._tigetstr('setab')
+ if set_bg_ansi:
+ for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
+ setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '')
+
+ def _tigetstr(self, cap_name):
+ # String capabilities can include "delays" of the form "$<2>".
+ # For any modern terminal, we should be able to just ignore
+ # these, so strip them out.
+ import curses
+ cap = curses.tigetstr(cap_name) or ''
+ return re.sub(r'\$<\d+>[/*]?', '', cap)
+
+ def render(self, template):
+ """
+ Replace each $-substitutions in the given template string with
+ the corresponding terminal control string (if it's defined) or
+ '' (if it's not).
+ """
+ return re.sub(r'\$\$|\${\w+}', self._render_sub, template)
+
+ def _render_sub(self, match):
+ s = match.group()
+ if s == '$$': return s
+ else: return getattr(self, s[2:-1])
+
+#######################################################################
+# Example use case: progress bar
+#######################################################################
+
+class ProgressBar:
+ """
+ A 3-line progress bar, which looks like::
+
+ Header
+ 20% [===========----------------------------------]
+ progress message
+
+ The progress bar is colored, if the terminal supports color
+ output; and adjusts to the width of the terminal.
+ """
+ BAR = '%s${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}%s\n'
+ HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n'
+
+ def __init__(self, term, header, useETA=True):
+ self.term = term
+ if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL):
+ raise ValueError("Terminal isn't capable enough -- you "
+ "should use a simpler progress dispaly.")
+ self.width = self.term.COLS or 75
+ self.bar = term.render(self.BAR)
+ self.header = self.term.render(self.HEADER % header.center(self.width))
+ self.cleared = 1 #: true if we haven't drawn the bar yet.
+ self.useETA = useETA
+ if self.useETA:
+ self.startTime = time.time()
+ self.update(0, '')
+
+ def update(self, percent, message):
+ if self.cleared:
+ sys.stdout.write(self.header)
+ self.cleared = 0
+ prefix = '%3d%% ' % (percent*100,)
+ suffix = ''
+ if self.useETA:
+ elapsed = time.time() - self.startTime
+ if percent > .0001 and elapsed > 1:
+ total = elapsed / percent
+ eta = int(total - elapsed)
+ h = eta//3600.
+ m = (eta//60) % 60
+ s = eta % 60
+ suffix = ' ETA: %02d:%02d:%02d'%(h,m,s)
+ barWidth = self.width - len(prefix) - len(suffix) - 2
+ n = int(barWidth*percent)
+ if len(message) < self.width:
+ message = message + ' '*(self.width - len(message))
+ else:
+ message = '... ' + message[-(self.width-4):]
+ sys.stdout.write(
+ self.term.BOL + self.term.UP + self.term.CLEAR_EOL +
+ (self.bar % (prefix, '='*n, '-'*(barWidth-n), suffix)) +
+ self.term.CLEAR_EOL + message)
+
+ def clear(self):
+ if not self.cleared:
+ sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL +
+ self.term.UP + self.term.CLEAR_EOL +
+ self.term.UP + self.term.CLEAR_EOL)
+ self.cleared = 1
+
+def test():
+ import time
+ tc = TerminalController()
+ p = ProgressBar(tc, 'Tests')
+ for i in range(101):
+ p.update(i/100., str(i))
+ time.sleep(.3)
+
+if __name__=='__main__':
+ test()
diff --git a/utils/test/TestRunner.py b/utils/test/TestRunner.py
new file mode 100755
index 000000000000..1cb8b9db75b9
--- /dev/null
+++ b/utils/test/TestRunner.py
@@ -0,0 +1,210 @@
+#!/usr/bin/python
+#
+# TestRunner.py - This script is used to run arbitrary unit tests. Unit
+# tests must contain the command used to run them in the input file, starting
+# immediately after a "RUN:" string.
+#
+# This runner recognizes and replaces the following strings in the command:
+#
+# %s - Replaced with the input name of the program, or the program to
+# execute, as appropriate.
+# %S - Replaced with the directory where the input resides.
+# %llvmgcc - llvm-gcc command
+# %llvmgxx - llvm-g++ command
+# %prcontext - prcontext.tcl script
+# %t - temporary file name (derived from testcase name)
+#
+
+import os
+import sys
+import subprocess
+import errno
+import re
+
+class TestStatus:
+ Pass = 0
+ XFail = 1
+ Fail = 2
+ XPass = 3
+ NoRunLine = 4
+ Invalid = 5
+
+ kNames = ['Pass','XFail','Fail','XPass','NoRunLine','Invalid']
+ @staticmethod
+ def getName(code): return TestStatus.kNames[code]
+
+def mkdir_p(path):
+ if not path:
+ pass
+ elif os.path.exists(path):
+ pass
+ else:
+ parent = os.path.dirname(path)
+ if parent != path:
+ mkdir_p(parent)
+ try:
+ os.mkdir(path)
+ except OSError,e:
+ if e.errno != errno.EEXIST:
+ raise
+
+def remove(path):
+ try:
+ os.remove(path)
+ except OSError:
+ pass
+
+def cat(path, output):
+ f = open(path)
+ output.writelines(f)
+ f.close()
+
+def runOneTest(FILENAME, SUBST, OUTPUT, TESTNAME, CLANG,
+ useValgrind=False,
+ useDGCompat=False,
+ useScript=None,
+ output=sys.stdout):
+ if useValgrind:
+ VG_OUTPUT = '%s.vg'%(OUTPUT,)
+ if os.path.exists:
+ remove(VG_OUTPUT)
+ CLANG = 'valgrind --leak-check=full --quiet --log-file=%s %s'%(VG_OUTPUT, CLANG)
+
+ # Create the output directory if it does not already exist.
+ mkdir_p(os.path.dirname(OUTPUT))
+
+ # FIXME
+ #ulimit -t 40
+
+ # FIXME: Load script once
+ # FIXME: Support "short" script syntax
+
+ if useScript:
+ scriptFile = useScript
+ else:
+ # See if we have a per-dir test script.
+ dirScriptFile = os.path.join(os.path.dirname(FILENAME), 'test.script')
+ if os.path.exists(dirScriptFile):
+ scriptFile = dirScriptFile
+ else:
+ scriptFile = FILENAME
+
+ # Verify the script contains a run line.
+ for ln in open(scriptFile):
+ if 'RUN:' in ln:
+ break
+ else:
+ print >>output, "******************** TEST '%s' HAS NO RUN LINE! ********************"%(TESTNAME,)
+ output.flush()
+ return TestStatus.NoRunLine
+
+ OUTPUT = os.path.abspath(OUTPUT)
+ FILENAME = os.path.abspath(FILENAME)
+ SCRIPT = OUTPUT + '.script'
+ TEMPOUTPUT = OUTPUT + '.tmp'
+
+ substitutions = [('%s',SUBST),
+ ('%S',os.path.dirname(SUBST)),
+ ('%llvmgcc','llvm-gcc -emit-llvm -w'),
+ ('%llvmgxx','llvm-g++ -emit-llvm -w'),
+ ('%prcontext','prcontext.tcl'),
+ ('%t',TEMPOUTPUT),
+ ('clang',CLANG)]
+ scriptLines = []
+ xfailLines = []
+ for ln in open(scriptFile):
+ if 'RUN:' in ln:
+ # Isolate run parameters
+ index = ln.index('RUN:')
+ ln = ln[index+4:]
+
+ # Apply substitutions
+ for a,b in substitutions:
+ ln = ln.replace(a,b)
+
+ if useDGCompat:
+ ln = re.sub(r'\{(.*)\}', r'"\1"', ln)
+ scriptLines.append(ln)
+ elif 'XFAIL' in ln:
+ xfailLines.append(ln)
+
+ if xfailLines:
+ print >>output, "XFAILED '%s':"%(TESTNAME,)
+ output.writelines(xfailLines)
+
+ # Write script file
+ f = open(SCRIPT,'w')
+ f.write(''.join(scriptLines))
+ f.close()
+
+ outputFile = open(OUTPUT,'w')
+ p = None
+ try:
+ p = subprocess.Popen(["/bin/sh",SCRIPT],
+ cwd=os.path.dirname(FILENAME),
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ out,err = p.communicate()
+ outputFile.write(out)
+ outputFile.write(err)
+ SCRIPT_STATUS = p.wait()
+ except KeyboardInterrupt:
+ if p is not None:
+ os.kill(p.pid)
+ raise
+ outputFile.close()
+
+ if xfailLines:
+ SCRIPT_STATUS = not SCRIPT_STATUS
+
+ if useValgrind:
+ VG_STATUS = len(list(open(VG_OUTPUT)))
+ else:
+ VG_STATUS = 0
+
+ if SCRIPT_STATUS or VG_STATUS:
+ print >>output, "******************** TEST '%s' FAILED! ********************"%(TESTNAME,)
+ print >>output, "Command: "
+ output.writelines(scriptLines)
+ if not SCRIPT_STATUS:
+ print >>output, "Output:"
+ else:
+ print >>output, "Incorrect Output:"
+ cat(OUTPUT, output)
+ if VG_STATUS:
+ print >>output, "Valgrind Output:"
+ cat(VG_OUTPUT, output)
+ print >>output, "******************** TEST '%s' FAILED! ********************"%(TESTNAME,)
+ output.flush()
+ if xfailLines:
+ return TestStatus.XPass
+ else:
+ return TestStatus.Fail
+
+ if xfailLines:
+ return TestStatus.XFail
+ else:
+ return TestStatus.Pass
+
+def main():
+ _,path = sys.argv
+ command = path
+ # Use hand concatentation here because we want to override
+ # absolute paths.
+ output = 'Output/' + path + '.out'
+ testname = path
+
+ # Determine which clang to use.
+ CLANG = os.getenv('CLANG')
+ if not CLANG:
+ CLANG = 'clang'
+
+ res = runOneTest(path, command, output, testname, CLANG,
+ useValgrind=bool(os.getenv('VG')),
+ useDGCompat=bool(os.getenv('DG_COMPAT')),
+ useScript=os.getenv("TEST_SCRIPT"))
+
+ sys.exit(res == TestStatus.Fail or res == TestStatus.XPass)
+
+if __name__=='__main__':
+ main()
diff --git a/utils/token-delta.py b/utils/token-delta.py
new file mode 100755
index 000000000000..327fa9221f05
--- /dev/null
+++ b/utils/token-delta.py
@@ -0,0 +1,251 @@
+#!/usr/bin/env python
+
+import os
+import re
+import subprocess
+import sys
+import tempfile
+
+###
+
+class DeltaAlgorithm(object):
+ def __init__(self):
+ self.cache = set()
+
+ def test(self, changes):
+ abstract
+
+ ###
+
+ def getTestResult(self, changes):
+ # There is no reason to cache successful tests because we will
+ # always reduce the changeset when we see one.
+
+ changeset = frozenset(changes)
+ if changeset in self.cache:
+ return False
+ elif not self.test(changes):
+ self.cache.add(changeset)
+ return False
+ else:
+ return True
+
+ def run(self, changes, force=False):
+ # Make sure the initial test passes, if not then (a) either
+ # the user doesn't expect monotonicity, and we may end up
+ # doing O(N^2) tests, or (b) the test is wrong. Avoid the
+ # O(N^2) case unless user requests it.
+ if not force:
+ if not self.getTestResult(changes):
+ raise ValueError,'Initial test passed to delta fails.'
+
+ # Check empty set first to quickly find poor test functions.
+ if self.getTestResult(set()):
+ return set()
+ else:
+ return self.delta(changes, self.split(changes))
+
+ def split(self, S):
+ """split(set) -> [sets]
+
+ Partition a set into one or two pieces.
+ """
+
+ # There are many ways to split, we could do a better job with more
+ # context information (but then the API becomes grosser).
+ L = list(S)
+ mid = len(L)//2
+ if mid==0:
+ return L,
+ else:
+ return L[:mid],L[mid:]
+
+ def delta(self, c, sets):
+ # assert(reduce(set.union, sets, set()) == c)
+
+ # If there is nothing left we can remove, we are done.
+ if len(sets) <= 1:
+ return c
+
+ # Look for a passing subset.
+ res = self.search(c, sets)
+ if res is not None:
+ return res
+
+ # Otherwise, partition sets if possible; if not we are done.
+ refined = sum(map(list, map(self.split, sets)), [])
+ if len(refined) == len(sets):
+ return c
+
+ return self.delta(c, refined)
+
+ def search(self, c, sets):
+ for i,S in enumerate(sets):
+ # If test passes on this subset alone, recurse.
+ if self.getTestResult(S):
+ return self.delta(S, self.split(S))
+
+ # Otherwise if we have more than two sets, see if test
+ # pases without this subset.
+ if len(sets) > 2:
+ complement = sum(sets[:i] + sets[i+1:],[])
+ if self.getTestResult(complement):
+ return self.delta(complement, sets[:i] + sets[i+1:])
+
+###
+
+class Token:
+ def __init__(self, type, data, flags, file, line, column):
+ self.type = type
+ self.data = data
+ self.flags = flags
+ self.file = file
+ self.line = line
+ self.column = column
+
+kTokenRE = re.compile(r"""([a-z_]+) '(.*)'\t(.*)\tLoc=<(.*):(.*):(.*)>""",
+ re.DOTALL | re.MULTILINE)
+
+def getTokens(path):
+ p = subprocess.Popen(['clang','-dump-raw-tokens',path],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ out,err = p.communicate()
+
+ tokens = []
+ collect = None
+ for ln in err.split('\n'):
+ # Silly programmers refuse to print in simple machine readable
+ # formats. Whatever.
+ if collect is None:
+ collect = ln
+ else:
+ collect = collect + '\n' + ln
+ if 'Loc=<' in ln and ln.endswith('>'):
+ ln,collect = collect,None
+ tokens.append(Token(*kTokenRE.match(ln).groups()))
+
+ return tokens
+
+###
+
+class TMBDDelta(DeltaAlgorithm):
+ def __init__(self, testProgram, tokenLists, log):
+ def patchName(name, suffix):
+ base,ext = os.path.splitext(name)
+ return base + '.' + suffix + ext
+ super(TMBDDelta, self).__init__()
+ self.testProgram = testProgram
+ self.tokenLists = tokenLists
+ self.tempFiles = [patchName(f,'tmp')
+ for f,_ in self.tokenLists]
+ self.targetFiles = [patchName(f,'ok')
+ for f,_ in self.tokenLists]
+ self.log = log
+ self.numTests = 0
+
+ def writeFiles(self, changes, fileNames):
+ assert len(fileNames) == len(self.tokenLists)
+ byFile = [[] for i in self.tokenLists]
+ for i,j in changes:
+ byFile[i].append(j)
+
+ for i,(file,tokens) in enumerate(self.tokenLists):
+ f = open(fileNames[i],'w')
+ for j in byFile[i]:
+ f.write(tokens[j])
+ f.close()
+
+ return byFile
+
+ def test(self, changes):
+ self.numTests += 1
+
+ byFile = self.writeFiles(changes, self.tempFiles)
+
+ if self.log:
+ print >>sys.stderr, 'TEST - ',
+ if self.log > 1:
+ for i,(file,_) in enumerate(self.tokenLists):
+ indices = byFile[i]
+ if i:
+ sys.stderr.write('\n ')
+ sys.stderr.write('%s:%d tokens: [' % (file,len(byFile[i])))
+ prev = None
+ for j in byFile[i]:
+ if prev is None or j != prev + 1:
+ if prev:
+ sys.stderr.write('%d][' % prev)
+ sys.stderr.write(str(j))
+ sys.stderr.write(':')
+ prev = j
+ if byFile[i]:
+ sys.stderr.write(str(byFile[i][-1]))
+ sys.stderr.write('] ')
+ else:
+ print >>sys.stderr, ', '.join(['%s:%d tokens' % (file, len(byFile[i]))
+ for i,(file,_) in enumerate(self.tokenLists)]),
+
+ p = subprocess.Popen([self.testProgram] + self.tempFiles)
+ res = p.wait() == 0
+
+ if res:
+ self.writeFiles(changes, self.targetFiles)
+
+ if self.log:
+ print >>sys.stderr, '=> %s' % res
+ else:
+ if res:
+ print '\nSUCCESS (%d tokens)' % len(changes)
+ else:
+ sys.stderr.write('.')
+
+ return res
+
+ def run(self):
+ res = super(TMBDDelta, self).run([(i,j)
+ for i,(file,tokens) in enumerate(self.tokenLists)
+ for j in range(len(tokens))])
+ self.writeFiles(res, self.targetFiles)
+ if not self.log:
+ print >>sys.stderr
+ return res
+
+def tokenBasedMultiDelta(program, files, log):
+ # Read in the lists of tokens.
+ tokenLists = [(file, [t.data for t in getTokens(file)])
+ for file in files]
+
+ numTokens = sum([len(tokens) for _,tokens in tokenLists])
+ print "Delta on %s with %d tokens." % (', '.join(files), numTokens)
+
+ tbmd = TMBDDelta(program, tokenLists, log)
+
+ res = tbmd.run()
+
+ print "Finished %s with %d tokens (in %d tests)." % (', '.join(tbmd.targetFiles),
+ len(res),
+ tbmd.numTests)
+
+def main():
+ from optparse import OptionParser, OptionGroup
+ parser = OptionParser("%prog <test program> {files+}")
+ parser.add_option("", "--debug", dest="debugLevel",
+ help="set debug level [default %default]",
+ action="store", type=int, default=0)
+ (opts, args) = parser.parse_args()
+
+ if len(args) <= 1:
+ parser.error('Invalid number of arguments.')
+
+ program,files = args[0],args[1:]
+
+ md = tokenBasedMultiDelta(program, files, log=opts.debugLevel)
+
+if __name__ == '__main__':
+ try:
+ main()
+ except KeyboardInterrupt:
+ print >>sys.stderr,'Interrupted.'
+ os._exit(1) # Avoid freeing our giant cache.
diff --git a/utils/ubiviz b/utils/ubiviz
new file mode 100755
index 000000000000..1582797c63f9
--- /dev/null
+++ b/utils/ubiviz
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This script reads visualization data emitted by the static analyzer for
+# display in Ubigraph.
+#
+##===----------------------------------------------------------------------===##
+
+import xmlrpclib
+import sys
+
+def Error(message):
+ print >> sys.stderr, 'ubiviz: ' + message
+ sys.exit(1)
+
+def StreamData(filename):
+ file = open(filename)
+ for ln in file:
+ yield eval(ln)
+ file.close()
+
+def Display(G, data):
+ action = data[0]
+ if action == 'vertex':
+ vertex = data[1]
+ G.new_vertex_w_id(vertex)
+ for attribute in data[2:]:
+ G.set_vertex_attribute(vertex, attribute[0], attribute[1])
+ elif action == 'edge':
+ src = data[1]
+ dst = data[2]
+ edge = G.new_edge(src,dst)
+ for attribute in data[3:]:
+ G.set_edge_attribute(edge, attribute[0], attribute[1])
+ elif action == "vertex_style":
+ style_id = data[1]
+ parent_id = data[2]
+ G.new_vertex_style_w_id(style_id, parent_id)
+ for attribute in data[3:]:
+ G.set_vertex_style_attribute(style_id, attribute[0], attribute[1])
+ elif action == "vertex_style_attribute":
+ style_id = data[1]
+ for attribute in data[2:]:
+ G.set_vertex_style_attribute(style_id, attribute[0], attribute[1])
+ elif action == "change_vertex_style":
+ vertex_id = data[1]
+ style_id = data[2]
+ G.change_vertex_style(vertex_id,style_id)
+
+def main(args):
+ if len(args) == 0:
+ Error('no input files')
+
+ server = xmlrpclib.Server('http://127.0.0.1:20738/RPC2')
+ G = server.ubigraph
+
+ for arg in args:
+ G.clear()
+ for x in StreamData(arg):
+ Display(G,x)
+
+ sys.exit(0)
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
+
+ \ No newline at end of file
diff --git a/win32/clangAST/clangAST.vcproj b/win32/clangAST/clangAST.vcproj
new file mode 100644
index 000000000000..8795412ba8cd
--- /dev/null
+++ b/win32/clangAST/clangAST.vcproj
@@ -0,0 +1,347 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="clangAST"
+ ProjectGUID="{5125C3DB-FBD6-4BF8-8D8B-CE51D6E93BCD}"
+ RootNamespace="clangAST"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\$(ProjectName).pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4146"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\$(ProjectName).pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4146"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\lib\AST\APValue.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\ASTConsumer.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\ASTContext.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\Builtins.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\CFG.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\Decl.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\DeclarationName.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\DeclBase.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\DeclCXX.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\DeclGroup.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\DeclObjC.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\DeclSerialization.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\Expr.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\ExprConstant.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\ExprCXX.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\InheritViz.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\ParentMap.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\Stmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\StmtDumper.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\StmtIterator.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\StmtPrinter.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\StmtSerialization.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\StmtViz.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\TranslationUnit.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\Type.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\AST\TypeSerialization.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\include\clang\AST\AST.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\ASTConsumer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\ASTContext.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\Builtins.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\CFG.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\Decl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\DeclCXX.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\DeclObjC.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\Expr.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\ExprCXX.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\ParentMap.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\PrettyPrinter.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\RecordLayout.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\Stmt.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\StmtGraphTraits.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\StmtIterator.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\StmtVisitor.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\Type.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\AST\TypeOrdering.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/win32/clangAnalysis/clangAnalysis.vcproj b/win32/clangAnalysis/clangAnalysis.vcproj
new file mode 100644
index 000000000000..c9850e059cff
--- /dev/null
+++ b/win32/clangAnalysis/clangAnalysis.vcproj
@@ -0,0 +1,351 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="clangAnalysis"
+ ProjectGUID="{6C98551A-4C36-4E74-8419-4D3EEEC9D8E0}"
+ RootNamespace="clangAnalysis"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\$(ProjectName).pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4146"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\$(ProjectName).pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4146"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\lib\Analysis\BasicConstraintManager.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\BasicObjCFoundationChecks.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\BasicObjCFoundationChecks.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\BasicStore.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\BasicValueFactory.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\BugReporter.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\CFRefCount.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\CheckDeadStores.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\CheckNSError.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\CheckObjCDealloc.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\CheckObjCInstMethSignature.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\CheckObjCUnusedIVars.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\Environment.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\ExplodedGraph.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\GRBlockCounter.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\GRCoreEngine.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\GRExprEngine.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\GRExprEngineInternalChecks.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\GRSimpleVals.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\GRSimpleVals.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\GRState.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\GRTransferFuncs.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\LiveVariables.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\MemRegion.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\PathDiagnostic.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\RegionStore.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\SVals.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\SymbolManager.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Analysis\UninitializedValues.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\include\clang\Analysis\ExprDeclBitVector.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Analysis\LiveVariables.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Analysis\LocalCheckers.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Analysis\ProgramEdge.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Analysis\UninitializedValues.h"
+ >
+ </File>
+ <Filter
+ Name="Visitors"
+ >
+ <File
+ RelativePath="..\..\include\clang\Analysis\Visitors\CFGRecStmtDeclVisitor.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Analysis\Visitors\CFGRecStmtVisitor.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Analysis\Visitors\CFGStmtVisitor.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Analysis\Visitors\CFGVarDeclVisitor.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="ADT"
+ >
+ <File
+ RelativePath="..\..\include\clang\Analysis\ADT\PersistentMap.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Support"
+ >
+ <File
+ RelativePath="..\..\include\clang\Analysis\Support\IntrusiveSPtr.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="FlowSensitive"
+ >
+ <File
+ RelativePath="..\..\include\clang\Analysis\FlowSensitive\DataflowSolver.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Analysis\FlowSensitive\DataflowValues.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/win32/clangBasic/clangBasic.vcproj b/win32/clangBasic/clangBasic.vcproj
new file mode 100644
index 000000000000..d836a6604c73
--- /dev/null
+++ b/win32/clangBasic/clangBasic.vcproj
@@ -0,0 +1,236 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="clangBasic"
+ ProjectGUID="{298B4876-6EF1-4E80-85D7-72F80693BBEB}"
+ RootNamespace="Basic"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\clangBasic.pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)\clangBasic.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\clangBasic.pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4355,4146,4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)\clangBasic.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\lib\Basic\Diagnostic.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Basic\FileManager.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Basic\IdentifierTable.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Basic\LangOptions.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Basic\SourceLocation.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Basic\SourceManager.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Basic\TargetInfo.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Basic\Targets.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Basic\TokenKinds.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\include\clang\Basic\Diagnostic.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Basic\FileManager.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Basic\IdentifierTable.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Basic\LangOptions.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Basic\SourceLocation.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Basic\SourceManager.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Basic\TargetInfo.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Basic\TokenKinds.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/win32/clangCodeGen/clangCodeGen.vcproj b/win32/clangCodeGen/clangCodeGen.vcproj
new file mode 100644
index 000000000000..a819fd94d867
--- /dev/null
+++ b/win32/clangCodeGen/clangCodeGen.vcproj
@@ -0,0 +1,271 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="clangCodeGen"
+ ProjectGUID="{4CEC5897-D957-47E7-A6AE-2021D4F44A8F}"
+ RootNamespace="clangCodeGen"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\$(ProjectName).pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4146"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\$(ProjectName).pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4146"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\lib\CodeGen\CGBuiltin.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGCall.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGCXX.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGDebugInfo.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGDecl.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGExpr.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGExprAgg.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGExprComplex.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGExprConstant.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGExprScalar.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGObjC.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGObjCGNU.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGObjCMac.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGStmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CodeGenFunction.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CodeGenModule.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CodeGenTypes.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\ModuleBuilder.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\lib\CodeGen\CGCall.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGDebugInfo.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGObjCRuntime.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CGValue.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CodeGenFunction.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CodeGenModule.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\CodeGen\CodeGenTypes.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\CodeGen\ModuleBuilder.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/win32/clangDriver/clangDriver.vcproj b/win32/clangDriver/clangDriver.vcproj
new file mode 100644
index 000000000000..0a744bbe4e9c
--- /dev/null
+++ b/win32/clangDriver/clangDriver.vcproj
@@ -0,0 +1,270 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="clangDriver"
+ ProjectGUID="{7E7DA455-C276-4B93-8D02-8F7E2F629BAF}"
+ RootNamespace="clangDriver"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ ManagedExtensions="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\$(ProjectName).pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4355,4146,4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)\clang.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(TargetDir)/clang.pdb"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="mkdir &quot;%DSTROOT%\AppleInternal\Bin&quot;&#x0D;&#x0A;copy &quot;$(TargetDir)$(TargetName).exe&quot; &quot;%DSTROOT%\AppleInternal\Bin&quot;&#x0D;&#x0A;"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\$(ProjectName).pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4355,4146,4800"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)\clang.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(TargetDir)/clang.pdb"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="mkdir &quot;%DSTROOT%\AppleInternal\Bin&quot;&#x0D;&#x0A;copy &quot;$(TargetDir)$(TargetName).exe&quot; &quot;%DSTROOT%\AppleInternal\Bin&quot;&#x0D;&#x0A;"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\Driver\AnalysisConsumer.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\ASTConsumers.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\Backend.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\CacheTokens.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\clang-cc.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\DependencyFile.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\DiagChecker.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\HTMLPrint.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\PrintParserCallbacks.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\PrintPreprocessedOutput.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\RewriteBlocks.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\RewriteMacros.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\RewriteObjC.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\SerializationTest.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\Driver\AnalysisConsumer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\ASTConsumers.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\clang-cc.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/win32/clangLex/clangLex.vcproj b/win32/clangLex/clangLex.vcproj
new file mode 100644
index 000000000000..5bec4b8b8e7f
--- /dev/null
+++ b/win32/clangLex/clangLex.vcproj
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="clangLex"
+ ProjectGUID="{030F6909-B2FA-4E53-BEA7-9A559CFC2F73}"
+ RootNamespace="clangLex"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\$(ProjectName).pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4146"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\$(ProjectName).pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4146"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\lib\Lex\HeaderMap.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\HeaderSearch.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\Lexer.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\LiteralSupport.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\MacroArgs.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\MacroInfo.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\PPCaching.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\PPDirectives.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\PPExpressions.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\PPLexerChange.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\PPMacroExpansion.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\Pragma.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\Preprocessor.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\PreprocessorLexer.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\PTHLexer.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\ScratchBuffer.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Lex\TokenLexer.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\include\clang\Lex\DirectoryLookup.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Lex\HeaderSearch.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Lex\Lexer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Lex\LiteralSupport.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Lex\MacroExpander.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Lex\MacroInfo.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Lex\MultipleIncludeOpt.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Lex\PPCallbacks.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Lex\Pragma.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Lex\Preprocessor.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Lex\ScratchBuffer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Lex\Token.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/win32/clangLibDriver/clangLibDriver.vcproj b/win32/clangLibDriver/clangLibDriver.vcproj
new file mode 100644
index 000000000000..de42ef72a787
--- /dev/null
+++ b/win32/clangLibDriver/clangLibDriver.vcproj
@@ -0,0 +1,205 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="clangLibDriver"
+ ProjectGUID="{AECB78DF-C319-4D49-B2FD-F98F62EBBDF4}"
+ RootNamespace="clangLibDriver"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\lib\Driver\HTMLDiagnostics.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Driver\InitHeaderSearch.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Driver\ManagerRegistry.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Driver\PlistDiagnostics.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Driver\RewriteTest.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Driver\TextDiagnosticBuffer.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Driver\TextDiagnosticPrinter.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\include\clang\Driver\HTMLDiagnostics.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Driver\InitHeaderSearch.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Driver\TextDiagnosticBuffer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Driver\TextDiagnosticPrinter.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/win32/clangParse/clangParse.vcproj b/win32/clangParse/clangParse.vcproj
new file mode 100644
index 000000000000..4cf552530545
--- /dev/null
+++ b/win32/clangParse/clangParse.vcproj
@@ -0,0 +1,248 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="clangParse"
+ ProjectGUID="{05DF3074-11AF-491A-B078-83BD2EDC31F6}"
+ RootNamespace="clangParse"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ DisableLanguageExtensions="true"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\$(ProjectName).pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4146"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\$(ProjectName).pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4146"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\lib\Parse\AttributeList.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Parse\DeclSpec.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Parse\MinimalAction.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Parse\ParseCXXInlineMethods.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Parse\ParseDecl.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Parse\ParseDeclCXX.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Parse\ParseExpr.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Parse\ParseExprCXX.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Parse\ParseInit.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Parse\ParseObjc.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Parse\ParsePragma.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Parse\Parser.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Parse\ParseStmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Parse\ParseTemplate.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Parse\ParseTentative.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\include\clang\Parse\Action.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Parse\AttributeList.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Parse\DeclSpec.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Parse\Parser.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Parse\Scope.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/win32/clangRewrite/clangRewrite.vcproj b/win32/clangRewrite/clangRewrite.vcproj
new file mode 100644
index 000000000000..7b1f898f9d67
--- /dev/null
+++ b/win32/clangRewrite/clangRewrite.vcproj
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="clangRewrite"
+ ProjectGUID="{F9FBDDA2-9EE1-473C-A456-BE20B7B2439D}"
+ RootNamespace="clangRewrite"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\lib\Rewrite\DeltaTree.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Rewrite\HTMLRewrite.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Rewrite\Rewriter.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Rewrite\RewriteRope.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Rewrite\TokenRewriter.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\include\clang\Rewrite\Rewriter.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\clang\Rewrite\RewriteRope.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/win32/clangSema/clangSema.vcproj b/win32/clangSema/clangSema.vcproj
new file mode 100644
index 000000000000..572c3effcafa
--- /dev/null
+++ b/win32/clangSema/clangSema.vcproj
@@ -0,0 +1,263 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="clangSema"
+ ProjectGUID="{4727E8B7-AA99-41C9-AB09-A8A862595DB7}"
+ RootNamespace="clangSema"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\$(ProjectName).pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4146"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\..\win32\common.vsprops"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\include;..\..\..\..\include;..\..\..\..\win32"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;__STDC_LIMIT_MACROS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ ProgramDataBaseFileName="$(OutDir)\$(ProjectName).pdb"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4146"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\lib\Sema\IdentifierResolver.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\ParseAST.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\Sema.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaChecking.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaCXXScopeSpec.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaDecl.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaDeclAttr.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaDeclCXX.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaDeclObjC.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaExpr.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaExprCXX.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaExprObjC.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaInherit.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaInit.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaLookup.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaNamedCast.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaOverload.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaStmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaTemplate.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaType.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\lib\Sema\CXXFieldCollector.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\IdentifierResolver.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\Sema.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\lib\Sema\SemaUtil.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/www/CheckerNotes.html b/www/CheckerNotes.html
new file mode 100644
index 000000000000..523048de7690
--- /dev/null
+++ b/www/CheckerNotes.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<title>Static Analysis</title>
+<meta http-equiv="REFRESH" content="0;url=http://clang.llvm.org/StaticAnalysis.html"></HEAD>
+<BODY>
+This page has relocated: <a href="http://clang.llvm.org/StaticAnalysis.html">http://clang.llvm.org/StaticAnalysis.html</a>.
+</BODY>
+</HTML>
diff --git a/www/OpenProjects.html b/www/OpenProjects.html
new file mode 100644
index 000000000000..69b398457fb1
--- /dev/null
+++ b/www/OpenProjects.html
@@ -0,0 +1,112 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Clang - Get Involved</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+</head>
+<body>
+
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<h1>Open Clang Projects</h1>
+
+<p>Here are a few tasks that are available for newcomers to work on, depending
+on what your interests are. This list is provided to generate ideas, it is not
+intended to be comprehensive. Please ask on cfe-dev for more specifics or to
+verify that one of these isn't already completed. :)</p>
+
+<ul>
+<li><b>Compile your favorite C/ObjC project with Clang</b>:
+Clang's type-checking and code generation is very close to complete (but not bug free!) for C and Objective-C. We appreciate all reports of code that is
+rejected or miscompiled by the front-end. If you notice invalid code that is not rejected, or poor diagnostics when code is rejected, that is also very important to us. For make-based projects,
+the <a href="get_started.html#ccc"><code>ccc</code></a> driver works as a drop-in replacement for GCC.</li>
+
+<li><b>Overflow detection</b>: an interesting project would be to add a -ftrapv
+compilation mode that causes -emit-llvm to generate overflow tests for all
+signed integer arithmetic operators, and call abort if they overflow. Overflow
+is undefined in C and hard for people to reason about. LLVM IR also has
+intrinsics for generating arithmetic with overflow checks directly.</li>
+
+<li><b>Undefined behavior checking</b>: similar to adding -ftrapv, codegen could
+insert runtime checks for all sorts of different undefined behaviors, from
+reading uninitialized variables, buffer overflows, and many other things. This
+checking would be expensive, but the optimizers could eliminate many of the
+checks in some cases, and it would be very interesting to test code in this mode
+for certain crowds of people. Because the inserted code is coming from clang,
+the "abort" message could be very detailed about exactly what went wrong.</li>
+
+<li><b>Improve target support</b>: The current target interfaces are heavily
+stubbed out and need to be implemented fully. See the FIXME's in TargetInfo.
+Additionally, the actual target implementations (instances of TargetInfoImpl)
+also need to be completed.</li>
+
+<li><b>Implement an tool to generate code documentation</b>: Clang's
+library-based design allows it to be used by a variety of tools that reason
+about source code. One great application of Clang would be to build an
+auto-documentation system like doxygen that generates code documentation from
+source code. The advantage of using Clang for such a tool is that the tool would
+use the same preprocessor/parser/ASTs as the compiler itself, giving it a very
+rich understanding of the code.</li>
+
+<li><b>Use clang libraries to implement better versions of existing tools</b>:
+Clang is built as a set of libraries, which means that it is possible to
+implement capabilities similar to other source language tools, improving them
+in various ways. Two examples are <a href="http://distcc.samba.org/">distcc</a>
+and the <a href="http://delta.tigris.org/">delta testcase reduction tool</a>.
+The former can be improved to scale better and be more efficient. The later
+could also be faster and more efficient at reducing C-family programs if built
+on the clang preprocessor.</li>
+
+<li><b>Use clang libraries to extend Ragel with a JIT</b>: <a
+href="http://research.cs.queensu.ca/~thurston/ragel/">Ragel</a> is a state
+machine compiler that lets you embed C code into state machines and generate
+C code. It would be relatively easy to turn this into a JIT compiler using
+LLVM.</li>
+
+<li><b>Self-testing using clang</b>: There are several neat ways to
+improve the quality of clang by self-testing. Some examples:
+<ul>
+ <li>Improve the reliability of AST printing and serialization by
+ ensuring that the AST produced by clang on an input doesn't change
+ when it is reparsed or unserialized.
+
+ <li>Improve parser reliability and error generation by automatically
+ or randomly changing the input checking that clang doesn't crash and
+ that it doesn't generate excessive errors for small input
+ changes. Manipulating the input at both the text and token levels is
+ likely to produce interesting test cases.
+</ul>
+</li>
+
+<li><b>Continue work on C++ support</b>: Implementing all of C++ is a very big
+job, but there are lots of little pieces that can be picked off and implemented. Here are some small- to mid-sized C++ implementation projects:
+<ul>
+ <li>Using declarations: These are completely unsupported at the moment.</li>
+ <li>Type-checking for the conditional operator (? :): this currently follows C semantics, not C++ semantics.</li>
+ <li>Type-checking for explicit conversions: currently follows C semantics, not C++ semantics.</li>
+ <li>Type-checking for copy assignment: Clang parses overloaded copy-assignment operators, but they aren't used as part of assignment syntax ("a = b").</li>
+ <li>Qualified member references: C++ supports qualified member references such as <code>x-&gt;Base::foo</code>, but Clang has no parsing or semantic analysis for them.</li>
+ <li>Virtual functions: Clang parses <code>virtual</code> and attaches it to the AST. However, it does not determine whether a given function overrides a virtual function in a base class.</li>
+ <li>Implicit definitions of special member functions: Clang implicitly declares the various special member functions (default constructor, copy constructor, copy assignment operator, destructor) when necessary, but is not yet able to provide definitions for these functions.</li>
+ <li>Parsing and AST representations of friend classes and functions</li>
+ <li>AST representation for implicit C++ conversions: implicit conversions that involve non-trivial operations (e.g., invoking a user-defined conversion function, performing a base-to-derived or derived-to-base conversion) need explicit representation in Clang's AST.</li>
+ <li>Improved diagnostics for overload resolution failures: after an overload resolution failure, we currently print out the overload resolution candidates. We should also print out the reason that each candidate failed, e.g., "too few arguments", "too many arguments", "cannot initialize parameter with an lvalue of type 'foo'", etc.</li>
+</ul>
+
+Also, see the <a href="cxx_status.html">C++ status report page</a> to
+find out what is missing and what is already at least partially
+supported.</li>
+</ul>
+
+<p>If you hit a bug with clang, it is very useful for us if you reduce the code
+that demonstrates the problem down to something small. There are many ways to
+do this; ask on cfe-dev for advice.</p>
+
+</div>
+</body>
+</html>
diff --git a/www/StaticAnalysis.html b/www/StaticAnalysis.html
new file mode 100644
index 000000000000..81176a96acf4
--- /dev/null
+++ b/www/StaticAnalysis.html
@@ -0,0 +1,156 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>LLVM/Clang Static Analyzer</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+</head>
+<body>
+
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<h1>LLVM/Clang Static Analyzer</h1>
+
+<p>The LLVM/Clang static analyzer is a standalone tool that finds bugs in C and
+Objective-C programs. Currently the analyzer is invoked as a command-line tool.
+It is intended to run in tandem with a build of a project or code base.</p>
+
+<p>Here are some important points we ask you to consider when using the static
+analyzer:</p>
+
+<ul>
+
+<li><b>This tool is <b>very early</b> in development.</b> There are many planned
+enhancements to improve both the precision and scope of its analysis algorithms
+as well as the kinds bugs it will find.</li>
+
+<li><b>Static analysis can be much slower than compilation.</b> While the
+analyzer is being designed to be as fast and light-weight as possible, please do
+not expect it to be as fast as compiling a program (even with optimizations
+enabled). Some of the algorithms needed to find bugs require in the worst case
+exponential time. The analyzer runs in a reasonable amount of time by both
+bounding the amount of checking work it will do as well as using clever
+algorithms to reduce the amount of work it must do to find bugs.</li>
+
+<li><b>False positives.</b> Static analysis is not perfect. It can falsely flag
+bugs in a program where the code behaves correctly. Because some code checks
+require more analysis precision than others, the frequency of false positives
+can vary widely between different checks. Our eventual goal is to have the
+analyzer have a low false positive rate for most code on all checks.</li>
+</ul>
+
+<h3>Please tell us about False Positives</h3>
+
+<p>If you encounter a false positive, <b>please let us know</b> by <a
+href="StaticAnalysisUsage.html#filingbugs">filing a bug report</a>. False
+positives cannot be addressed unless we know about them.</p>
+
+<h3>Want more bugs?</h3>
+
+<p>If there are specific kinds of bugs you would like the tool to find,
+please feel free to file <a href="StaticAnalysisUsage.html#filingbugs">feature
+requests</a>.</p>
+
+<!-- Generated from: http://www.spiffycorners.com/index.php -->
+
+<style type="text/css">
+.spiffy{display:block}
+.spiffy *{
+ display:block;
+ height:1px;
+ overflow:hidden;
+ font-size:.01em;
+ background:#EBF0FA}
+.spiffy1{
+ margin-left:3px;
+ margin-right:3px;
+ padding-left:1px;
+ padding-right:1px;
+ border-left:1px solid #f6f8fc;
+ border-right:1px solid #f6f8fc;
+ background:#f0f3fb}
+.spiffy2{
+ margin-left:1px;
+ margin-right:1px;
+ padding-right:1px;
+ padding-left:1px;
+ border-left:1px solid #fdfdfe;
+ border-right:1px solid #fdfdfe;
+ background:#eef2fa}
+.spiffy3{
+ margin-left:1px;
+ margin-right:1px;
+ border-left:1px solid #eef2fa;
+ border-right:1px solid #eef2fa;}
+.spiffy4{
+ border-left:1px solid #f6f8fc;
+ border-right:1px solid #f6f8fc}
+.spiffy5{
+ border-left:1px solid #f0f3fb;
+ border-right:1px solid #f0f3fb}
+.spiffyfg{
+ background:#EBF0FA}
+
+.spiffyfg h2 {
+ margin:0px; padding:10px;
+}
+</style>
+
+<style type="text/css">
+ #left { float:left; }
+ #left h2 { margin:1px; padding-top:0px; }
+ #right { float:left; margin-left:50px; padding:0px ;}
+ #right h2 { padding:0px; margin:0px; }
+ #wrappedcontent { padding:15px;}
+</style>
+
+<div id="left">
+ <h2>Using the Analyzer</h2>
+ <ul>
+ <li><a href="StaticAnalysisUsage.html#Obtaining">Obtaining the Analyzer</a></li>
+ <li><a href="StaticAnalysisUsage.html#BasicUsage">Basic Usage</a></li>
+ <li><a href="StaticAnalysisUsage.html#Output">Output of the Analyzer</a></li>
+ <li><a href="StaticAnalysisUsage.html#RecommendedUsageGuidelines">Recommended Usage Guidelines</a></li>
+ <li><a href="StaticAnalysisUsage.html#Debugging">Debugging the Analyzer</a></li>
+ <li><a href="StaticAnalysisUsage.html#filingbugs">Filing Bugs and Feature Requests</a></li>
+ </ul>
+</div>
+
+<div id="right">
+ <b class="spiffy">
+ <b class="spiffy1"><b></b></b>
+ <b class="spiffy2"><b></b></b>
+ <b class="spiffy3"></b>
+ <b class="spiffy4"></b>
+ <b class="spiffy5"></b></b>
+
+ <div class="spiffyfg">
+ <div id="wrappedcontent">
+ <h2>Download</h2>
+ <ul>
+ <li>Mac OS X (Universal, 10.5+):
+ <p>
+ <!--#include virtual="latest_checker.html.incl"-->
+ </p>
+ </li>
+ <li><a href="StaticAnalysisUsage.html#OtherUsage">Other Platforms</a> (Building from Source)</li>
+ </div>
+
+ </div>
+
+ <b class="spiffy">
+ <b class="spiffy5"></b>
+ <b class="spiffy4"></b>
+ <b class="spiffy3"></b>
+ <b class="spiffy2"><b></b></b>
+ <b class="spiffy1"><b></b></b></b>
+</div>
+
+
+</div>
+</body>
+</html>
+
diff --git a/www/StaticAnalysisUsage.html b/www/StaticAnalysisUsage.html
new file mode 100644
index 000000000000..daab89f724aa
--- /dev/null
+++ b/www/StaticAnalysisUsage.html
@@ -0,0 +1,274 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Information on using the Static Analyzer ("Clang Checker")</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+ <style>
+ thead {
+ background-color:#eee; color:#666666;
+ font-weight: bold; cursor: default;
+ text-align:center;
+ border-top: 2px solid #000000;
+ border-bottom: 2px solid #000000;
+ font-weight: bold; font-family: Verdana
+ }
+ table { border: 1px #000000 solid }
+ table { border-collapse: collapse; border-spacing: 0px }
+ table { margin-left:20px; margin-top:20px; margin-bottom:20px }
+ td { border-bottom: 1px #000000 dotted }
+ td { padding:5px; padding-left:8px; padding-right:8px }
+ td { text-align:left; font-size:9pt }
+ td.View { padding-left: 10px }
+ </style>
+</head>
+<body>
+
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<h1>Information on using the Static Analyzer</h1>
+
+<h2 id="Obtaining">Obtaining the Analyzer</h2>
+
+<p> Using the analyzer involves executing <tt>scan-build</tt> (see <a
+href="#BasicUsage">Basic Usage</a>). <tt>scan-build</tt> will first look for a
+<tt>clang</tt> executable in the same directory as <tt>scan-build</tt>, and then
+search your path.</p>
+
+<p>If one is using the analyzer directly from the Clang sources, it suffices to
+just directly execute <tt>scan-build</tt> in the <tt>utils</tt> directory. No
+other special installation is needed.</p>
+
+<h3>Packaged Builds (Mac OS X)</h3>
+
+<p>Semi-regular pre-built binaries of the analyzer are available on Mac OS X
+(10.5).</p>
+
+<p>The latest build is:
+ <!--#include virtual="latest_checker.html.incl"-->
+</p>
+
+Packaged builds for other platforms may eventually be provided, but as the tool
+is in its early stages we are not actively promoting releases yet. If you wish
+to help contribute regular builds of the analyzer on other platforms, please
+email the <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev">Clang
+Developers' mailing list</a>.</p>
+
+<p>Packaged builds of the analyzer expand to the following files:</p>
+
+<table id="package">
+<thead><tr><td>File</td><td>Purpose</td></tr></thead>
+<tr><td><tt><b>scan-build</b></tt></td><td>Script for running the analyzer over a project build. <b>This is the only file you care about.</b></td></tr>
+<tr><td><tt>ccc-analyzer</tt></td><td>GCC interceptor (called by scan-build)</td></tr>
+<tr><td><tt>clang</tt></td><td>Static Analyzer (called by ccc-analyzer)</td><tr>
+<tr><td><tt>sorttable.js</tt></td><td>JavaScript used for displaying error reports</td></tr>
+</table>
+
+<h3 id="OtherPlatforms">Other Platforms (Building the Analyzer from Source)</h3>
+
+<p>Packaged builds simply consist of a few files from the Clang source tree,
+meaning that <b>anyone</b> who can build Clang can use the static analyzer.
+Please see the <a href="get_started.html">Getting Started</a> page for more
+details on downloading and compiling Clang.</p>
+
+<p>All files used by the analyzer (and included in packaged builds; <a
+href="#package">see above</a>) other than a compiled <tt>clang</tt> executable
+are found in the <tt>utils</tt> subdirectory in the Clang tree.</p>
+
+<h2 id="BasicUsage">Basic Usage</h2>
+
+<p>The analyzer is executed from the command-line. To run the analyzer, you will
+use <tt>scan-build</tt> to analyze the source files compiled by <tt>gcc</tt>
+during a project build.</p>
+
+<p>For example, to analyze the files compiled under a build:</p>
+
+<pre>
+ $ <b>scan-build</b> make
+ $ <b>scan-build</b> xcodebuild
+</pre>
+
+<p> In the first case <tt>scan-build</tt> analyzes the code of a project built
+with <tt>make</tt>, and in the second case <tt>scan-build</tt> analyzes a project
+built using <tt>xcodebuild</tt>. In general, the format is: </p>
+
+<pre>
+ $ <b>scan-build</b> <i>[scan-build options]</i> <b>&lt;command&gt;</b> <i>[command options]</i>
+</pre>
+
+<p> Operationally, <tt>scan-build</tt> literally runs <command> with all of the
+subsequent options passed to it. For example:</p>
+
+<pre>
+ $ scan-build make <b>-j4</b>
+</pre>
+
+<p>In this example, <tt>scan-build</tt> makes no effort to interpret the options
+after the build command (in this case, <tt>make</tt>); it just passes them
+through. In general, <tt>scan-build</tt> should support parallel builds, but
+<b>not distributed builds</b>. Similarly, you can use <tt>scan-build</tt> to
+analyze specific files:
+
+<pre>
+ $ scan-build gcc -c <b>t1.c t2.c</b>
+</pre>
+
+<p>
+This example causes the files <tt>t1.c</tt> and <tt>t2.c</tt> to be analyzed.
+</p>
+
+<h3>Other Options</h3>
+
+<p>
+As mentioned above, extra options can be passed to <tt>scan-build</tt>. These
+options prefix the build command. For example:</p>
+
+<pre>
+ $ scan-build <b>-k -V</b> make
+ $ scan-build <b>-k -V</b> xcodebuild
+</pre>
+
+<p>Here is a subset of useful options:</p>
+
+<table>
+ <thead><tr><td>Option</td><td>Description</td></tr></thead>
+
+ <tr><td><b>-o</b></td><td>Target directory for HTML report files. Subdirectories will be
+ created as needed to represent separate "runs" of the analyzer. If this option
+is not specified, a directory is created in <tt>/tmp</tt> to store the
+reports.</td><tr>
+
+ <tr><td><b>-h</b><br><i><nobr>(or no arguments)</nobr></i></td><td>Display all <tt>scan-build</tt> options.</td></tr>
+
+ <tr><td><b>-k</b><br><nobr><b>--keep-going</b></nobr></td><td>Add a "keep on going" option to the
+ specified build command. <p>This option currently supports <tt>make</tt> and
+ <tt>xcodebuild</tt>.</p> <p>This is a convenience option; one can specify this
+ behavior directly using build options.</p></td></tr>
+
+ <tr><td><b>-v<b></td><td>Verbose output from scan-build and the analyzer. <b>A second and third
+ "-v" increases verbosity</b>, and is useful for filing bug reports against the analyzer.</td></tr>
+
+ <tr><td><b>-V</b></td><td>View analysis results in a web browser when the build command completes.</td></tr>
+</table>
+
+<h2 id="Output">Output of the Analyzer</h2>
+
+<p>
+The output of the analyzer is a set of HTML files, each one which represents a
+separate bug report. A single <tt>index.html</tt> file is generated for
+surveying all of the bugs. You can then just open <tt>index.html</tt> in a web
+browser to view the bug reports.
+</p>
+
+<p>
+Where the HTML files are generated is specified with a <b>-o</b> option to
+<tt>scan-build</tt>. If <b>-o</b> isn't specified, a directory in <tt>/tmp</tt>
+is created to store the files (<tt>scan-build</tt> will print a message telling
+you where they are). If you want to view the reports immediately after the build
+completes, pass <b>-V</b> to <tt>scan-build</tt>.
+</p>
+
+
+<h2 id="RecommendedUsageGuidelines">Recommended Usage Guidelines</h2>
+
+Here are a few recommendations with running the analyzer:
+
+<h3>Always Analyze a Project in its "Debug" Configuration</h3>
+
+<p>Most projects can be built in a "debug" mode that enables assertions.
+Assertions are picked up by the static analyzer to prune infeasible paths, which
+in some cases can greatly reduce the number of false positives (bogus error
+reports) emitted by the tool.</p>
+
+<h3>Pass -k to scan-build</h3>
+
+<p>While <tt>ccc-analyzer</tt> invokes <tt>gcc</tt> to compile code, any
+problems in correctly forwarding arguments to <tt>gcc</tt> may result in a build
+failure. Passing <b>-k</b> to <tt>scan-build</tt> potentially allows you to
+analyze other code in a project for which this problem doesn't occur.</p>
+
+<p> Also, it is useful to analyze a project even if not all of the source files
+are compilable. This is great when using <tt>scan-build</tt> as part of your
+compile-debug cycle.</p>
+
+<h3>Use Verbose Output when Debugging scan-build</h3>
+
+<p><tt>scan-build</tt> takes a <b>-v</b> option to emit verbose output about
+what it's doing; two <b>-v</b> options emit more information. Redirecting the
+output of <tt>scan-build</tt> to a text file (make sure to redirect standard
+error) is useful for filing bug reports against <tt>scan-build</tt> or the
+analyzer, as we can see the exact options (and files) passed to the analyzer.
+For more comprehensible logs, don't perform a parallel build.</p>
+
+<h2 id="Debugging">Debugging the Analyzer</h2>
+
+<p>This section provides information on debugging the analyzer, and troubleshooting
+it when you have problems analyzing a particular project.</p>
+
+<h3>How it Works</h3>
+
+<p>To analyze a project, <tt>scan-build</tt> simply sets the environment variable
+<tt>CC</tt> to the full path to <tt>ccc-analyzer</tt>. It also sets a few other
+environment variables to communicate to <tt>ccc-analyzer</tt> where to dump HTML
+report files.</p>
+
+<p>Some Makefiles (or equivalent project files) hardcode the compiler; for such
+projects simply overriding <tt>CC</tt> won't cause <tt>ccc-analyzer</tt> to be
+called. This will cause the compiled code <b>to not be analyzed.</b></p> If you
+find that your code isn't being analyzed, check to see if <tt>CC</tt> is
+hardcoded. If this is the case, you can hardcode it instead to the <b>full
+path</b> to <tt>ccc-analyzer</tt>.</p>
+
+<p>When applicable, you can also run <tt>./configure</tt> for a project through
+<tt>scan-build</tt> so that configure sets up the location of <tt>CC</tt> based
+on the environment passed in from <tt>scan-build</tt>:
+
+<pre>
+ $ scan-build <b>./configure</b>
+</pre>
+
+<p><tt>scan-build</tt> has special knowledge about <tt>configure</tt>, so it in
+most cases will not actually analyze the configure tests run by
+<tt>configure</tt>.</p>
+
+<p>Under the hood, <tt>ccc-analyzer</tt> directly invokes <tt>gcc</tt> to
+compile the actual code in addition to running the analyzer (which occurs by it
+calling <tt>clang</tt>). <tt>ccc-analyzer</tt> tries to correctly forward all
+the arguments over to <tt>gcc</tt>, but this may not work perfectly (please
+report bugs of this kind).
+
+<h2 id="filingbugs">Filing Bugs and Feature Requests</h2>
+
+<p>We encourage users to file bug reports for any problems that they encounter.
+We also welcome feature requests. When filing a bug report, please do the
+following:</p>
+
+<ul>
+
+<li>Include the checker build (for prebuilt Mac OS X binaries) or the SVN
+revision number.</li>
+
+<li>Provide a self-encapsulated, reduced test case that exhibits the issue
+ you are experiencing.</li>
+
+<li>Test cases don't tell us everything. Please briefly describe the problem you are seeing.</li>
+
+</ul>
+
+<h3>Outside Apple</h3>
+
+<p>Please <a href="http://llvm.org/bugs/enter_bug.cgi?product=clang">file
+bugs</a> in LLVM's Bugzilla database against the Clang <b>Static Analyzer</b>
+component.</p>
+
+<h3>Apple-internal Users</h3>
+
+<p>Please file bugs in Radar against the <b>llvm - checker</b> component.</p>
+
+</div>
+</body>
+</html>
+
diff --git a/www/carbon-compile.png b/www/carbon-compile.png
new file mode 100644
index 000000000000..e8516c7055bb
--- /dev/null
+++ b/www/carbon-compile.png
Binary files differ
diff --git a/www/clang_video-05-25-2007.html b/www/clang_video-05-25-2007.html
new file mode 100644
index 000000000000..ade0269f4688
--- /dev/null
+++ b/www/clang_video-05-25-2007.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>2007 LLVM Developer's Meeting</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+</head>
+<body>
+ <!--#include virtual="menu.html.incl"-->
+ <div id="content">
+ <h1>2007 LLVM Developer's Meeting</h1>
+ Discussion about Clang at the <a href="http://llvm.org/devmtg/2007-05/">2007 LLVM Developer's Meeting</a>.
+ <h2>About:</h2>
+ <p>In this video, Steve Naroff introduces the Clang project and talks about some of the goals and motivations for starting the project.
+ <br><br>
+ <p><b>Details:</b> New LLVM C Front-end - This talk describes a new from-scratch C frontend (which is aiming to support Objective C and C++ someday) for LLVM, built as a native part of the LLVM system and in the LLVM design style.
+ <h2>The Presentation:</h2>
+ <p>You can download a copy of the presentation in mov format. However, due to the picture quality, it is recommended that you also download the lecture slides for viewing while you watch the video.
+ <ul>
+ <li><a href="http://llvm.org/devmtg/2007-05/09-Naroff-CFE.mov">Video (mov file)</a>
+ <li><a href="http://llvm.org/devmtg/2007-05/09-Naroff-CFE.pdf">Lecture slides (PDF)</a>
+ </ul>
+ </div>
+</body>
+</html> \ No newline at end of file
diff --git a/www/clang_video-07-25-2007.html b/www/clang_video-07-25-2007.html
new file mode 100644
index 000000000000..d2225896c50b
--- /dev/null
+++ b/www/clang_video-07-25-2007.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>LLVM 2.0 and Beyond!</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+</head>
+<body>
+ <!--#include virtual="menu.html.incl"-->
+ <div id="content">
+ <h1>LLVM 2.0 and Beyond!</h1>
+ A Google Techtalk by <a href="http://www.nondot.org/sabre/">Chris Lattner</a>
+ <h2>About:</h2>
+ <p>In this video, Chris Lattner talks about some of the features of Clang, especially in regards to performance.
+ <br><br>
+ <p><b>Details:</b> The LLVM 2.0 release brings a number of new features and capabilities to the LLVM toolset. This talk briefly describes those features, then moves on to talk about what is next: llvm 2.1, llvm-gcc 4.2, and puts a special emphasis on the 'clang' C front-end. This describes how the 'clang' preprocessor can be used to improve the scalability of distcc by up to 4.4x.
+ <h2>The Presentation:</h2>
+ <p>You can view the presentation through google video. In addition, the slides from the presentation are also available, if you wish to retain a copy.
+ <ul>
+ <li><a href="http://video.google.com/videoplay?docid=1921156852099786640">Google Tech Talk Video (19:00-)</a> (Note: the Clang lecture starts at 19 minutes into the video.)
+ <li><a href="http://llvm.org/pubs/2007-07-25-LLVM-2.0-and-Beyond.pdf">LLVM 2.0 and Beyond! slides (PDF)</a>
+ </ul>
+ <h2>Publishing Information:</h2>
+ "LLVM 2.0 and Beyond!", Chris Lattner,<br>
+ <i>Google Tech Talk</i>, Mountain View, CA, July 2007.
+ </div>
+</body>
+</html> \ No newline at end of file
diff --git a/www/comparison.html b/www/comparison.html
new file mode 100644
index 000000000000..0bfff127201b
--- /dev/null
+++ b/www/comparison.html
@@ -0,0 +1,195 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Comparing clang to other open source compilers</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+</head>
+<body>
+ <!--#include virtual="menu.html.incl"-->
+ <div id="content">
+ <h1>Clang vs Other Open Source Compilers</h1>
+
+ <p>Building an entirely new compiler front-end is a big task, and it isn't
+ always clear to people why we decided to do this. Here we compare clang
+ and its goals to other open source compiler front-ends that are
+ available. We restrict the discussion to very specific objective points
+ to avoid controversy where possible. Also, software is infinitely
+ mutable, so we don't talk about little details that can be fixed with
+ a reasonable amount of effort: we'll talk about issues that are
+ difficult to fix for architectural or political reasons.</p>
+
+ <p>The goal of this list is to describe how differences in goals lead to
+ different strengths and weaknesses, not to make some compiler look bad.
+ This will hopefully help you to evaluate whether using clang is a good
+ idea for your personal goals. Because we don't know specifically what
+ <em>you</em> want to do, we describe the features of these compilers in
+ terms of <em>our</em> goals: if you are only interested in static
+ analysis, you may not care that something lacks codegen support, for
+ example.</p>
+
+ <p>Please email cfe-dev if you think we should add another compiler to this
+ list or if you think some characterization is unfair here.</p>
+
+ <ul>
+ <li><a href="#gcc">Clang vs GCC</a> (GNU Compiler Collection)</li>
+ <li><a href="#elsa">Clang vs Elsa</a> (Elkhound-based C++ Parser)</li>
+ <li><a href="#pcc">Clang vs PCC</a> (Portable C Compiler)</li>
+ </ul>
+
+
+ <!--=====================================================================-->
+ <h2><a name="gcc">Clang vs GCC (GNU Compiler Collection)</a></h2>
+ <!--=====================================================================-->
+
+ <p>Pro's of GCC vs clang:</p>
+
+ <ul>
+ <li>GCC supports languages that clang does not aim to, such as Java, Ada,
+ FORTRAN, etc.</li>
+ <li>GCC front-ends are very mature and already support C++.
+ <a href="cxx_status.html">clang's support for C++</a> is nowhere near
+ what GCC supports.</li>
+ <li>GCC supports more targets than LLVM.</li>
+ <li>GCC is popular and widely adopted.</li>
+ <li>GCC does not require a C++ compiler to build it.</li>
+ </ul>
+
+ <p>Pro's of clang vs GCC:</p>
+
+ <ul>
+ <li>The Clang ASTs and design are intended to be <a
+ href="features.html#simplecode">easily understandable</a> by
+ anyone who is familiar with the languages involved and who has a basic
+ understanding of how a compiler works. GCC has a very old codebase
+ which presents a steep learning curve to new developers.</li>
+ <li>Clang is designed as an API from its inception, allowing it to be reused
+ by source analysis tools, refactoring, IDEs (etc) as well as for code
+ generation. GCC is built as a monolithic static compiler, which makes
+ it extremely difficult to use as an API and integrate into other tools.
+ Further, its historic design and <a
+ href="http://gcc.gnu.org/ml/gcc/2007-11/msg00460.html">current</a>
+ <a href="http://gcc.gnu.org/ml/gcc/2004-12/msg00888.html">policy</a>
+ makes it difficult to decouple the front-end from the rest of the
+ compiler. </li>
+ <li>Various GCC design decisions make it very difficult to reuse: its build
+ system is difficult to modify, you can't link multiple targets into one
+ binary, you can't link multiple front-ends into one binary, it uses a
+ custom garbage collector, uses global variables extensively, is not
+ reentrant or multi-threadable, etc. Clang has none of these problems.
+ </li>
+ <li>For every token, clang tracks information about where it was written and
+ where it was ultimately expanded into if it was involved in a macro.
+ GCC does not track information about macro instantiations when parsing
+ source code. This makes it very difficult for source rewriting tools
+ (e.g. for refactoring) to work in the presence of (even simple)
+ macros.</li>
+ <li>Clang does not implicitly simplify code as it parses it like GCC does.
+ Doing so causes many problems for source analysis tools: as one simple
+ example, if you write "x-x" in your source code, the GCC AST will
+ contain "0", with no mention of 'x'. This is extremely bad for a
+ refactoring tool that wants to rename 'x'.</li>
+ <li>Clang can serialize its AST out to disk and read it back into another
+ program, which is useful for whole program analysis. GCC does not have
+ this. GCC's PCH mechanism (which is just a dump of the compiler
+ memory image) is related, but is architecturally only
+ able to read the dump back into the exact same executable as the one
+ that produced it (it is not a structured format).</li>
+ <li>Clang is <a href="features.html#performance">much faster and uses far
+ less memory</a> than GCC.</li>
+ <li>Clang aims to provide extremely clear and concise diagnostics (error and
+ warning messages), and includes support for <a
+ href="diagnostics.html">expressive diagnostics</a>. GCC's warnings are
+ sometimes acceptable, but are often confusing and it does not support
+ expressive diagnostics. Clang also preserves typedefs in diagnostics
+ consistently, showing macro expansions and many other features.</li>
+ <li>GCC is licensed under the GPL license. clang uses a BSD license, which
+ allows it to be used by projects that do not themselves want to be
+ GPL.</li>
+ <li>Clang inherits a number of features from its use of LLVM as a backend,
+ including support for a bytecode representation for intermediate code,
+ pluggable optimizers, link-time optimization support, Just-In-Time
+ compilation, ability to link in multiple code generators, etc.</li>
+ </ul>
+
+ <!--=====================================================================-->
+ <h2><a name="elsa">Clang vs Elsa (Elkhound-based C++ Parser)</a></h2>
+ <!--=====================================================================-->
+
+ <p>Pro's of Elsa vs clang:</p>
+
+ <ul>
+ <li>Elsa's support for C++ is far beyond what clang provides. If you need
+ C++ support in the next year, Elsa is a great way to get it. That said,
+ Elsa is missing important support for templates and other pieces: for
+ example, it is not capable of compiling the GCC STL headers from any
+ version newer than GCC 3.4.</li>
+ <li>Elsa's parser and AST is designed to be easily extensible by adding
+ grammar rules. Clang has a very simple and easily hackable parser,
+ but requires you to write C++ code to do it.</li>
+ </ul>
+
+ <p>Pro's of clang vs Elsa:</p>
+
+ <ul>
+ <li>The Elsa community is extremely small and major development work seems
+ to have ceased in 2005, though it continues to be used by other small
+ projects
+ (e.g. Oink). Clang has a vibrant community including developers that
+ are paid to work on it full time. In practice this means that you can
+ file bugs against Clang and they will often be fixed for you. If you
+ use Elsa, you are (mostly) on your own for bug fixes and feature
+ enhancements.</li>
+ <li>Elsa is not built as a stack of reusable libraries like clang is. It is
+ very difficult to use part of Elsa without the whole front-end. For
+ example, you cannot use Elsa to parse C/ObjC code without building an
+ AST. You can do this in Clang and it is much faster than building an
+ AST.</li>
+ <li>Elsa does not have an integrated preprocessor, which makes it extremely
+ difficult to accurately map from a source location in the AST back to
+ its original position before preprocessing. Like GCC, it does not keep
+ track of macro expansions.</li>
+ <li>Elsa is even slower and uses more memory than GCC, which itself requires
+ far more space and time than clang.</li>
+ <li>Elsa only does partial semantic analysis. It is intended to work on
+ code that is already validated by GCC, so it does not do many semantic
+ checks required by the languages it implements.</li>
+ <li>Elsa does not support Objective-C.</li>
+ <li>Elsa does not support native code generation.</li>
+ </ul>
+
+ <p>Note that there is a fork of Elsa known as "Pork". It addresses some of
+ these shortcomings by loosely integrating a preprocessor. This allows it
+ to map from a source location in the AST to the original position before
+ preprocessing, providing it better support for static analysis and
+ refactoring. Note that Pork is in stasis now too.</p>
+
+
+ <!--=====================================================================-->
+ <h2><a name="pcc">Clang vs PCC (Portable C Compiler)</a></h2>
+ <!--=====================================================================-->
+
+ <p>Pro's of PCC vs clang:</p>
+
+ <ul>
+ <li>The PCC source base is very small and builds quickly with just a C
+ compiler.</li>
+ </ul>
+
+ <p>Pro's of clang vs PCC:</p>
+
+ <ul>
+ <li>PCC dates from the 1970's and has been dormant for most of that time.
+ The clang + llvm communities are very active.</li>
+ <li>PCC doesn't support C99, Objective-C, and doesn't aim to support
+ C++.</li>
+ <li>PCC's code generation is very limited compared to LLVM. It produces very
+ inefficient code and does not support many important targets.</li>
+ <li>Like Elsa, PCC's does not have an integrated preprocessor, making it
+ extremely difficult to use it for source analysis tools.</li>
+ </div>
+</body>
+</html>
diff --git a/www/content.css b/www/content.css
new file mode 100644
index 000000000000..ab6983b48491
--- /dev/null
+++ b/www/content.css
@@ -0,0 +1,25 @@
+html, body {
+ padding:0px;
+ font-size:small; font-family:"Lucida Grande", "Lucida Sans Unicode", Arial, Verdana, Helvetica, sans-serif; background-color: #fff; color: #222;
+ line-height:1.5;
+}
+
+h1, h2, h3, tt { color: #000 }
+
+h1 { padding-top:0px; margin-top:0px;}
+h2 { color:#333333; padding-top:0.5em; }
+h3 { padding-top: 0.5em; margin-bottom: -0.25em; color:#2d58b7}
+li { padding-bottom: 0.5em; }
+ul { padding-left:1.5em; }
+
+/* Slides */
+IMG.img_slide {
+ display: block;
+ margin-left: auto;
+ margin-right: auto
+}
+
+.itemTitle { color:#2d58b7 }
+
+/* Tables */
+tr { vertical-align:top }
diff --git a/www/cxx_status.html b/www/cxx_status.html
new file mode 100644
index 000000000000..d85d451f559e
--- /dev/null
+++ b/www/cxx_status.html
@@ -0,0 +1,2320 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Clang - C++ Support</title>
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
+ <style type="text/css">
+ .na { background-color: #C0C0C0; text-align: center; }
+ .broken { background-color: #C11B17 }
+ .basic { background-color: #F88017 }
+ .medium { background-color: #FDD017 }
+ .advanced { background-color: #347C17 }
+ .complete { background-color: #00FF00 }
+ </style>
+</head>
+<body>
+
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<!--*************************************************************************-->
+<h1>C++ Support in Clang</h1>
+<!--*************************************************************************-->
+
+<p>
+This page tracks the status of C++ support in Clang.<br>
+Currently most of the C++ features are missing; here you can find features that are at least partially supported in Clang. If you are looking to <a href="get_involved.html">get involved with Clang development</a> to help work on support for C++, please also look at our <a href="OpenProjects.html">Open Projects</a> page for some specific ideas.</p>
+
+
+<!-- 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++03 standard. We use a
+ simple, somewhat arbitrary color-coding scheme to describe the
+ relative completeness of features by section:</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"></td>
+ <td class="complete" align="center">&#x2713;</td>
+ </tr>
+</table>
+
+<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++ standard. Note that many C++ features are
+actually described in several different sections within the 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>
+
+ <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>
+
+ <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! Since Clang already supports
+much of C, and therefore much C++, many of the currently-white cells
+could be filled in. If you wish to do so, please compare Clang's
+implementation against the C++ standard and provide a patch that
+updates the table accordingly. Tests for the various features are also
+welcome!</p>
+
+<table width="689" border="1" cellspacing="0">
+ <tr>
+ <th>Section</th>
+ <th>Parse</th>
+ <th>AST</th>
+ <th>Sema</th>
+ <th>CodeGen</th>
+ <th>Notes</th>
+ </tr>
+<tr>
+ <td>2 [lex]</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;2.1 [lex.phases]</td>
+ <td class="advanced" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td>Extended characters aren't handled.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;2.2 [lex.charset]</td>
+ <td class="basic"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td>No support for extended characters.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;2.3 [lex.trigraph]</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;2.4 [lex.pptoken]</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;2.5 [lex.digraph]</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;2.6 [lex.token]</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;2.7 [lex.comment]</td>
+ <td class="advanced" align="center"></td>
+ <td></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td>NDR "form feed or vtab in comment" is not diagnosed. No AST representation of comments.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;2.8 [lex.header]</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;2.9 [lex.ppnumber]</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;2.10 [lex.name]</td>
+ <td class="advanced" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td>No support for extended characters</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;2.11 [lex.key]</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;2.12 [lex.operators]</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;2.13 [lex.literal]</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;2.13.1 [lex.icon]</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;2.13.2 [lex.ccon]</td>
+ <td class="advanced" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td>Poor support for extended characters</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;2.13.3 [lex.fcon]</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;2.13.4 [lex.string]</td>
+ <td class="advanced" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td>Poor support for extended characters</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;2.13.5 [lex.bool]</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+<td>3 [basic]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;3.1 [basic.def]</td>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;3.2 [basic.def.odr]</td>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;3.3 [basic.scope]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.1 [basic.scope.pdecl]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.2 [basic.scope.local]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.3 [basic.scope.proto]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.4 [basic.funscope]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.5 [basic.scope.namespace]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.6 [basic.scope.class]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;3.3.7 [basic.scope.hiding]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;3.4 [basic.lookup]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;3.4.1 [basic.lookup.unqual]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="medium"></td>
+ <td class="na">N/A</td>
+ <td>Many cases beyond simple global and function-local lookup don't work</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;3.4.2 [basic.lookup.argdep]</td>
+ <td class="na">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na">N/A</td>
+ <td>Missing support for templates, friend functions.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;3.4.3 [basic.lookup.qual]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="advanced"></td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.4.3.1 [class.qual]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="advanced"></td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.4.3.2 [namespace.qual]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="advanced"></td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.4.4 [basic.lookup.elab]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.4.5 [basic.lookup.classref]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.4.6 [basic.lookup.udir]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;3.5 [basic.link]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;3.6 [basic.start]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.6.1 [basic.start.main]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.6.2 [basic.start.init]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.6.3 [basic.start.term]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;3.7 [basic.stc]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.7.1 [basic.stc.static]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.7.2 [basic.stc.auto]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.7.3 [basic.stc.dynamic]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.7.3.1 [basic.stc.dynamic.allocation]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.7.3.2 [basic.stc.dynamic.deallocation]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.7.4 [basic.stc.inherit]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;3.8 [basic.life]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;3.9 [basic.types]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.9.1 [basic.fundamental]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.9.2 [basic.compound]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;3.9.3 [basic.type.qualifier]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;3.10 [basic.lval]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+ <td>4 [conv]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;4.1 [conv.lval]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="advanced" align="center"></td> <!-- p2: sizeof -->
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;4.2 [conv.array]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;4.3 [conv.func]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;4.4 [conv.qual]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;4.5 [conv.prom]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;4.6 [conv.fpprom]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;4.7 [conv.integral]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;4.8 [conv.double]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;4.9 [conv.fpint]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;4.10 [conv.ptr]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;4.11 [conv.mem]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;4.12 [conv.bool]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>5 [expr]</td>
+ <td class="na">N/A</td>
+ <td class="na">N/A</td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.1 [expr.prim]</td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td></td>
+ <td>template-ids are not supported, name lookup is not complete</td>
+</tr>
+<tr><td>&nbsp;&nbsp;5.2 [expr.post]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.1 [expr.sub]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.2 [expr.call]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.3 [expr.type.conv]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="basic"></td>
+ <td></td>
+ <td>Only between non-class types</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.4 [expr.pseudo]</td>
+ <td class="broken"></td>
+ <td class="broken"></td>
+ <td class="broken"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.5 [expr.ref]</td>
+ <td class="complete" align="center"></td>
+ <td class="medium"></td>
+ <td class="medium"></td>
+ <td></td>
+ <td>Cannot look up operator names, qualified-ids, or names in base classes</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.6 [expr.post.incr]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.7 [expr.dynamic.cast]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.8 [expr.typeid]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.9 [expr.static.cast]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td></td>
+ <td>Some custom conversions don't work.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.10 [expr.reinterpret.cast]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.11 [expr.const.cast]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr><td>&nbsp;&nbsp;5.3 [expr.unary]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.1 [expr.unary.op]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.3.1p1 Unary *</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.3.1p2-5 Unary &amp;</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.3.1p6 Unary +</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.3.1p7 Unary -</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.3.1p8 Unary !</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.3.1p9 Unary ~</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.2 [expr.pre.incr]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.3 [expr.sizeof]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.4 [expr.new]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td></td>
+ <td>operator delete is not looked up, initialization not quite correct</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.5 [expr.delete]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.4 [expr.cast]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="medium"></td>
+ <td></td>
+ <td>Too lenient, and may not always have correct semantics</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.5 [expr.mptr.oper]</td>
+ <td class="complete" align="center"></td>
+ <td class="advanced"></td>
+ <td class="advanced"></td>
+ <td></td>
+ <td>Dereferenced member function pointers have the wrong type.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.6 [expr.mul]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.7 [expr.add]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.8 [expr.shift]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.9 [expr.rel]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.10 [expr.eq]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.11 [expr.bit.and]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.12 [expr.xor]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.13 [expr.or]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.14 [expr.log.and]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.15 [expr.log.or]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.16 [expr.cond]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td>some invalid hierarchy casts still accepted, but that's a general problem</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.17 [expr.ass]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.18 [expr.comma]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;5.19 [expr.const]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="basic"></td>
+ <td></td>
+ <td>Uses C semantics</td>
+</tr>
+<tr>
+ <td>6 [stmt.stmt]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;6.1 [stmt.label]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;6.2 [stmt.expr]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;6.3 [stmt.block]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;6.4 [stmt.select]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td></td>
+ <td>Conversion of declarations to required types not really supported.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;6.4.1 [stmt.if]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;6.4.2 [stmt.switch]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;6.5 [stmt.iter]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td></td>
+ <td>Conversion of declarations to required types not really supported.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;6.5.1 [stmt.while]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;6.5.2 [stmt.do]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;6.5.3 [stmt.for]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;6.6 [stmt.jump]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;6.6.1 [stmt.break]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;6.6.2 [stmt.cont]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;6.6.3 [stmt.return]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;6.6.4 [stmt.goto]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;6.7 [stmt.dcl]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td></td>
+ <td>Skipping of initialization is not flagged. Existence and accessibility of destructors is not tested for.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;6.8 [stmt.ambig]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr><td>7 [dcl.dcl]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>
+ &nbsp;&nbsp;7.1 [dcl.spec]</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td></td>
+ <td>No support for friend declarations.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.1 [dcl.stc]</td>
+ <td class="complete" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td></td>
+ <td>Linkage merging has some errors.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.2 [dcl.fct.spec]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.3 [dcl.typedef]</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></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.4 [dcl.friend]</td>
+ <td class="broken"></td>
+ <td class="broken"></td>
+ <td class="broken"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.5 [dcl.type]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7.1.5.1 [dcl.type.cv]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7.1.5.2 [dcl.type.simple]</td>
+ <td class="medium"></td>
+ <td class="advanced"></td>
+ <td class="advanced"></td>
+ <td></td>
+ <td>Cannot parse template IDs.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7.1.5.3 [dcl.type.elab]</td>
+ <td class="medium"></td>
+ <td class="advanced"></td>
+ <td class="advanced"></td>
+ <td></td>
+ <td>Cannot parse template IDs.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;7.2 [dcl.enum]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;7.3 [basic.namespace]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;7.3.1 [namespace.def]</td>
+ <td class="medium"></td>
+ <td class="medium"></td>
+ <td class="medium"></td>
+ <td></td>
+ <td>Cannot parse namespace aliases.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7.3.1.1 [namespace.unnamed]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="broken"></td>
+ <td></td>
+ <td>Unnamed namespace members cannot be looked up.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7.3.1.2 [namespace.memdef]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="advanced"></td>
+ <td></td>
+ <td>The friend stuff is not supported.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;7.3.2 [namespace.alias]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;7.3.3 [namespace.udecl]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;7.3.4[namespace.udir]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="advanced"></td>
+ <td class="broken" align="center"></td>
+ <td>Example in p4 fails.</td>
+</tr>
+<tr><td>
+ &nbsp;&nbsp;7.4 [dcl.asm]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;7.5 [dcl.link]</td>
+ <td class="complete" align="center"></td>
+ <td class="basic"></td>
+ <td class="basic"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>8 [dcl.decl]</td><td></td><td></td><td></td><td></td><td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;8.1 [dcl.name]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;8.2 [dcl.ambig.res]</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="na" align="center">N/A</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;8.3 [dcl.meaning]</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>Qualified declarator-ids are not fully implemented.</td>
+</tr>
+ <tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;8.3.1 [dcl.ptr]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;8.3.2 [dcl.ref]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;8.3.3 [dcl.mptr]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;8.3.4 [dcl.array]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;8.3.5 [dcl.fct]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;8.3.6 [dcl.fct.default]</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="na">N/A</td>
+ <td>Missing default arguments for templates.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;8.4 [dcl.fct.def]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td>ctor-initializers are not fully type-checked.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;8.5 [dcl.init]</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;8.5.1[dcl.init.aggr]</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td>No CodeGen for initializing non-aggregates or dynamic initialization.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;8.5.2[dcl.init.string]</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;8.5.3 [dcl.init.ref]</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>9 [class]</td>
+ <td class="advanced" align="center"></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;9.1 [class.name]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;9.2 [class.mem]</td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td>No parser support for using declarations or member templates.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;9.3 [class.mfct]</td>
+ <td class="complete" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;9.3.1 [class.mfct.non-static]</td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;9.3.2 [class.this]</td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;9.4 [class.static]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;9.4.1 [class.static.mfct]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;9.4.2 [class.static.data]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;9.5 [class.union]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="medium"></td>
+ <td class="medium"></td>
+ <td>Semantic analysis does not yet check all of the requirements placed on the members of unions.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;9.6 [class.bit]</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></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;9.7 [class.nest]</td>
+ <td class="complete" align="center"></td>
+ <td class="advanced"></td>
+ <td class="advanced"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;9.8 [class.local]</td>
+ <td class="complete" align="center"></td>
+ <td class="medium"></td>
+ <td class="broken"></td>
+ <td class="broken"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;9.9 [class.nested.type]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>10 [class.derived]</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;10.1 [class.mi]</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>No layout of base classes</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;10.2 [class.member.lookup]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;10.3 [class.virtual]</td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>No semantic analysis for overriding virtual functions or inheriting a virtual function. No layout of classes with virtual functions.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;10.4 [class.abstract]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+ </tr>
+<tr>
+ <td>11 [class.access]</td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;11.1 [class.access.spec]</td>
+ <td class="complete" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;11.2 [class.access.base]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;11.3 [class.access.dcl]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;11.4 [class.friend]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;11.5 [class.protected]</td>
+ <td class="na" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;11.6 [class.access.virt]</td>
+ <td class="na" align="center"></td>
+ <td class="na" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;11.7 [class.paths]</td>
+ <td class="na" align="center"></td>
+ <td class="na" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;11.8 [class.access.nest]</td>
+ <td class="na" align="center"></td>
+ <td class="na" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr><td>12 [special]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+ <td>&nbsp;&nbsp;12.1 [class.ctor]</td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td>Implicitly-declared constructors are never defined.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;12.2 [class.temporary]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td>Implementation of temporary objects is in its initial stages.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;12.3 [class.conv]</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;12.3.1 [class.conv.ctor]</td>
+ <td class="complete" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;12.3.2 [class.conv.fct]</td>
+ <td class="complete" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>No support for inheritance of conversion functions.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;12.4 [class.dtor]</td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>Most of the semantics of destructors are unimplemented.</td>
+</tr>
+<tr><td>&nbsp;&nbsp;12.5 [class.free]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;12.6 [class.init]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;12.6.1 [class.expl.init]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;12.6.2 [class.base.init]</td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>No actual direct initialization; implicit initialization not checked.</td>
+</tr>
+<tr><td>&nbsp;&nbsp;12.7 [class.cdtor]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+ <td>&nbsp;&nbsp;12.8 [class.copy]</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>Copy assignment operators are mostly ignored by semantic analysis.</td>
+</tr>
+
+<tr><td>13 [over]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+ <td>&nbsp;&nbsp;13.1 [over.load]</td>
+ <td class="complete" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>Missing name mangling.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;13.2 [over.dcl]</td>
+ <td class="complete" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;13.3 [over.match]</td>
+ <td class="complete" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;13.3.1 [over.match.funcs]</td>
+ <td class="complete" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.1 [over.match.call]</td>
+ <td class="complete" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.1.1 [over.call.func]</td>
+ <td class="complete" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.1.2 [over.call.object]</td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>Missing AST representation for the implicit conversion to a function reference/pointer</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.2 [over.match.oper]</td>
+ <td class="complete" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.3 [over.match.ctor]</td>
+ <td class="complete" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.4 [over.match.copy]</td>
+ <td class="complete" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.5 [over.match.conv]</td>
+ <td class="complete" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.1.6 [over.match.ref]</td>
+ <td class="complete" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;13.3.2 [over.match.viable]</td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;13.3.3 [over.match.best]</td>
+ <td class="complete" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.3.1 [over.best.ics]</td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.3.1.1 [over.ics.scs]</td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.3.1.2 [over.ics.user]</td>
+ <td class="complete" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.3.1.3 [over.ics.ellipsis]</td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.3.1.4 [over.ics.ref]</td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;13.3.3.2 [over.ics.rank]</td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;13.4 [over.over]</td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>Error messages need some work. Without templates or using
+ declarations, we don't have any ambiguities, so the semantic
+ analysis is incomplete.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;13.5 [over.oper]</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>Some overloaded operators can only be called with function syntax, e.g., <code>operator[](x)</code>.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.1 [over.unary]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.2 [over.binary]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.3 [over.ass]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.4 [over.call]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.5 [over.sub]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.6 [over.ref]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.7 [over.inc]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;13.6 [over.built]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>Missing pointer-to-member versions (p11, p16) and support for
+ the ternary operator (p24, p25).</td>
+</tr>
+<tr>
+ <td>14 [temp]</td>
+ <td class="basic" align="center">N/A</td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;14.1 [temp.param]</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="medium" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td>Template template parameters cannot actually be used in templates</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;14.2 [temp.names]</td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td>Cannot name function template specializations</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;14.3 [temp.arg]</td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td>Cannot name function template specializations</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.3.1 [temp.arg.type]</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td>Paragraph 3 will be tested elsewhere</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.3.2 [temp.arg.nontype]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.3.3 [temp.arg.template]</td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;14.4 [temp.type]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;14.5 [temp.decls]</td><td></td><td></td><td></td><td></td><td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.5.1 [temp.class]</td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>No out-of-line definitions of the members of a template.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.1.1 [temp.mem.func]</td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>No out-of-line definitions of the member functions of a class template.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.1.2 [temp.mem.class]</td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>No out-of-line definitions of the member classes of a class template.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.1.3 [temp.static]</td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>No out-of-line definitions of the static data members of a class template.</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.5.2 [temp.mem]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.5.3 [temp.friend]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.5.4 [temp.class.spec]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.5.1 [temp.class.spec.match]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.5.2 [temp.class.order]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.5.3 [temp.class.spec.mfunc]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.5.5 [temp.fct]</td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.5.1 [temp.over.link]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.5.5.2 [temp.func.order]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;14.6 [temp.res]</td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="na" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.6.1 [temp.local]</td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="na" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.6.2 [temp.dep]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="na" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.6.2.1 [temp.dep.type]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="na" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.6.2.2 [temp.dep.expr]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="na" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.6.2.3 [temp.dep.constexpr]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="na" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.6.2.4 [temp.dep.temp]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="na" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.6.3 [temp.nondep]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.6.4 [temp.dep.res]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="na" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.6.4.1 [temp.point]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center"></td>
+ <td>Only class templates are instantiated</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.6.4.2 [temp.dep.candidate]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="na" align="center"></td>
+ <td>Not restricted to functions with external linkage</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.6.5 [temp.inject]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="na" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;14.7 [temp.spec]</td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>Function templates cannot be instantiated</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.7.1 [temp.inst]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>Function templates cannot be instantiated</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.7.2 [temp.explicit]</td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>Function templates cannot be instantiated</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.7.3 [temp.expl.spec]</td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="basic" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>Only class template specialization is available</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;14.8 [temp.fct.spec]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.8.1 [temp.arg.explicit]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.8.2 [temp.deduct]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.8.2.1 [temp.deduct.call]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.8.2.2 [temp.deduct.funcaddr]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.8.2.3 [temp.deduct.conv]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.8.2.4 [temp.deduct.type]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;14.8.3 [temp.over]</td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>15 [except]</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;15.1 [except.throw]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td></td>
+ <td>Does not check for existence of copy constructor and destructor, and some other details</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;15.2 [except.ctor]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;15.3 [except.handle]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td></td>
+ <td>Not all constraints are checked</td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;15.4 [except.spec]</td>
+ <td class="complete" align="center"></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;15.5 [except.special]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;15.5.1 [except.terminate]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;15.5.2 [except.unexpected]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;15.5.3 [except.uncaught]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>&nbsp;&nbsp;15.6 [except.access]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td class="na" align="center">N/A</td>
+ <td>Redundant - struck from C++0x</td>
+</tr>
+<tr><td>16 [cpp]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;16.1 [cpp.cond]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;16.2 [cpp.include]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;16.3 [cpp.replace]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;16.3.1 [cpp.subst]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;16.3.2 [cpp.stringize]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;16.3.3 [cpp.concat]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;16.3.4 [cpp.rescan]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;16.3.5 [cpp.scope]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;16.4 [cpp.line]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;16.5 [cpp.error]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;16.6 [cpp.pragma]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;16.7 [cpp.null]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;16.8 [cpp.predefined]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>A [gram]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;A.1 [gram.key]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;A.2 [gram.lex]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;A.3 [gram.basic]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;A.4 [gram.expr]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;A.5 [gram.stmt]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;A.6 [gram.dcl]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;A.7 [gram.decl]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;A.8 [gram.class]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;A.9 [gram.derived]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;A.10 [gram.special]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;A.11 [gram.over]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;A.12 [gram.temp]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;A.13 [gram.except]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;A.14 [gram.cpp]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>B [implimits]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>C [diff]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;C.1 [diff.iso]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.1 [diff.lex]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.2 [diff.basic]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.3 [diff.expr]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.4 [diff.stat]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.5 [diff.dcl]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.6 [diff.decl]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.7 [diff.class]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.8 [diff.special]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.1.9 [diff.cpp]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;C.2 [diff.library]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.2.1 [diff.mods.to.headers]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.2.2 [diff.mods.to.definitions]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C.2.2.2 [diff.wchar.t]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C.2.2.3 [diff.header.iso646.h]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C.2.2.4 [diff.null]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.2.3 [diff.mods.to.declarations]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;C.2.4 [diff.mods.to.behavior]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C.2.4.1 [diff.offsetof]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C.2.4.2 [diff.malloc]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>D [depr]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;D.1 [depr.incr.bool]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;D.2 [depr.static]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;D.3 [depr.access.dcl]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;D.4 [depr.string]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>&nbsp;&nbsp;D.5 [depr.c.headers]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr><td>E [extendid]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+ <td colspan="6" align="center" bgcolor="#ffffcc">C++0x Features</td>
+</tr>
+<tr>
+ <td>Explicit conversion operators (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf">N2437</a>)</td>
+ <td class="complete" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="advanced" align="center"></td>
+ <td class="broken"></td>
+ <td>No name mangling; ASTs don't contain calls to conversion operators</td>
+</tr>
+<tr>
+ <td>Static assertions (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.pdf">N1720</a>)</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>Deleted functions (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm">N2346</a>)</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="na">N/A</td>
+ <td></td>
+</tr>
+<tr>
+ <td>Rvalue references (<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>)</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="broken"></td>
+ <td></td>
+</tr>
+<tr>
+ <td>nullptr (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf">N2431</a>)</td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="complete" align="center"></td>
+ <td class="broken"></td>
+ <td></td>
+</tr>
+
+</table>
+<br />
+</div>
+</body>
+</html>
diff --git a/www/demo/DemoInfo.html b/www/demo/DemoInfo.html
new file mode 100644
index 000000000000..54a5afa1d799
--- /dev/null
+++ b/www/demo/DemoInfo.html
@@ -0,0 +1,83 @@
+
+<html>
+<head>
+<title>
+Demo page information
+</title>
+</head>
+
+<body>
+
+<h1>Demo page information</h1>
+
+<p>Press "back" or <a href=".">click here</a> to return to the demo
+page.</p>
+
+<h2><a name="hints">Hints and Advice</a></h2>
+
+<ul>
+<li>The generated LLVM code will be easier to read if
+you use stdio (e.g., printf) than iostreams (e.g., std::cout).</li>
+
+<li>Unused inline functions and methods are not generated. Instead
+of '<tt>class foo { void bar() {}};</tt>',
+try writing '<tt>class foo { void bar(); }; void foo::bar() {}</tt>'.</li>
+
+<li>If you want to try out a file that uses non-standard header files, you should
+ preprocess it (e.g., with the <tt>-save-temps</tt> or <tt>-E</tt> options to
+ <tt>gcc</tt>) then upload the result.</li>
+
+</ul>
+
+
+<h2><a name="demangle">Demangle C++ names with C++ filt</a></h2>
+
+<p>
+Select this option if you want to run the output LLVM IR through "c++filt",
+which converts 'mangled' C++ names to their unmangled version.
+Note that LLVM code produced will not be lexically valid, but it will
+be easier to understand.
+</p>
+
+<h2><a name="lto">Run link-time optimizer</a></h2>
+
+<p>
+Select this option to run the LLVM link-time optimizer, which is designed to
+optimize across files in your application. Since the demo page doesn't allow
+you to upload multiple files at once, and does not link in any libraries, we
+configured the demo page optimizer to assume there are no calls
+coming in from outside the source file, allowing it to optimize more
+aggressively.</p>
+
+<p>Note that you have to define 'main' in your program for this
+to make much of a difference.
+</p>
+
+<h2><a name="stats">Show detailed pass statistics</a></h2>
+
+<p>
+Select this option to enable compilation timings and statistics from various
+optimizers.</p>
+
+
+<h2><a name="bcanalyzer">Analyze generated bytecode</a></h2>
+
+<p>
+Select this option to run the <a
+href="http://llvm.org/cmds/llvm-bcanalyzer.html">llvm-bcanalyzer</a> tool
+on the generated bytecode, which introspects into the format of the .bc file
+itself. </p>
+
+
+<h2><a name="llvm2cpp">Show C++ API code</a></h2>
+
+<p>
+Select this option to run the <a
+href="http://llvm.org/cmds/llvm2cpp.html">llvm2cpp</a> tool
+on the generated bytecode, which auto generates the C++ API calls that could
+be used to create the .bc file.
+</p>
+
+</body>
+</html>
+
diff --git a/www/demo/cathead.png b/www/demo/cathead.png
new file mode 100644
index 000000000000..3bf1a45ec6f3
--- /dev/null
+++ b/www/demo/cathead.png
Binary files differ
diff --git a/www/demo/index.cgi b/www/demo/index.cgi
new file mode 100644
index 000000000000..b29efb60e9cc
--- /dev/null
+++ b/www/demo/index.cgi
@@ -0,0 +1,461 @@
+#!/usr/dcs/software/supported/bin/perl -w
+# LLVM Web Demo script
+#
+
+use strict;
+use CGI;
+use POSIX;
+use Mail::Send;
+
+$| = 1;
+
+my $ROOT = "/tmp/webcompile";
+#my $ROOT = "/home/vadve/lattner/webcompile";
+
+open( STDERR, ">&STDOUT" ) or die "can't redirect stderr to stdout";
+
+if ( !-d $ROOT ) { mkdir( $ROOT, 0777 ); }
+
+my $LOGFILE = "$ROOT/log.txt";
+my $FORM_URL = 'index.cgi';
+my $MAILADDR = 'sabre@nondot.org';
+my $CONTACT_ADDRESS = 'Questions or comments? Email the <a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev">LLVMdev mailing list</a>.';
+my $LOGO_IMAGE_URL = 'cathead.png';
+my $TIMEOUTAMOUNT = 20;
+$ENV{'LD_LIBRARY_PATH'} = '/home/vadve/shared/localtools/fc1/lib/';
+
+my @PREPENDPATHDIRS =
+ (
+ '/home/vadve/shared/llvm-gcc4.0-2.1/bin/',
+ '/home/vadve/shared/llvm-2.1/Release/bin');
+
+my $defaultsrc = "#include <stdio.h>\n#include <stdlib.h>\n\n" .
+ "int power(int X) {\n if (X == 0) return 1;\n" .
+ " return X*power(X-1);\n}\n\n" .
+ "int main(int argc, char **argv) {\n" .
+ " printf(\"%d\\n\", power(atoi(argv[0])));\n}\n";
+
+sub getname {
+ my ($extension) = @_;
+ for ( my $count = 0 ; ; $count++ ) {
+ my $name =
+ sprintf( "$ROOT/_%d_%d%s", $$, $count, $extension );
+ if ( !-f $name ) { return $name; }
+ }
+}
+
+my $c;
+
+sub barf {
+ print "<b>", @_, "</b>\n";
+ print $c->end_html;
+ system("rm -f $ROOT/locked");
+ exit 1;
+}
+
+sub writeIntoFile {
+ my $extension = shift @_;
+ my $contents = join "", @_;
+ my $name = getname($extension);
+ local (*FILE);
+ open( FILE, ">$name" ) or barf("Can't write to $name: $!");
+ print FILE $contents;
+ close FILE;
+ return $name;
+}
+
+sub addlog {
+ my ( $source, $pid, $result ) = @_;
+ open( LOG, ">>$LOGFILE" );
+ my $time = scalar localtime;
+ my $remotehost = $ENV{'REMOTE_ADDR'};
+ print LOG "[$time] [$remotehost]: $pid\n";
+ print LOG "<<<\n$source\n>>>\nResult is: <<<\n$result\n>>>\n";
+ close LOG;
+}
+
+sub dumpFile {
+ my ( $header, $file ) = @_;
+ my $result;
+ open( FILE, "$file" ) or barf("Can't read $file: $!");
+ while (<FILE>) {
+ $result .= $_;
+ }
+ close FILE;
+ my $UnhilightedResult = $result;
+ my $HtmlResult =
+ "<h3>$header</h3>\n<pre>\n" . $c->escapeHTML($result) . "\n</pre>\n";
+ if (wantarray) {
+ return ( $UnhilightedResult, $HtmlResult );
+ }
+ else {
+ return $HtmlResult;
+ }
+}
+
+sub syntaxHighlightLLVM {
+ my ($input) = @_;
+ $input =~ s@\b(void|i8|i1|i16|i32|i64|float|double|type|label|opaque)\b@<span class="llvm_type">$1</span>@g;
+ $input =~ s@\b(add|sub|mul|div|rem|and|or|xor|setne|seteq|setlt|setgt|setle|setge|phi|tail|call|cast|to|shl|shr|vaarg|vanext|ret|br|switch|invoke|unwind|malloc|alloca|free|load|store|getelementptr|begin|end|true|false|declare|global|constant|const|internal|uninitialized|external|implementation|linkonce|weak|appending|null|to|except|not|target|endian|pointersize|big|little|volatile)\b@<span class="llvm_keyword">$1</span>@g;
+
+ # Add links to the FAQ.
+ $input =~ s@(_ZNSt8ios_base4Init[DC]1Ev)@<a href="../docs/FAQ.html#iosinit">$1</a>@g;
+ $input =~ s@\bundef\b@<a href="../docs/FAQ.html#undef">undef</a>@g;
+ return $input;
+}
+
+sub mailto {
+ my ( $recipient, $body ) = @_;
+ my $msg =
+ new Mail::Send( Subject => "LLVM Demo Page Run", To => $recipient );
+ my $fh = $msg->open();
+ print $fh $body;
+ $fh->close();
+}
+
+$c = new CGI;
+print $c->header;
+
+print <<EOF;
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <title>Try out LLVM in your browser!</title>
+ <style>
+ \@import url("syntax.css");
+ \@import url("http://llvm.org/llvm.css");
+ </style>
+</head>
+<body leftmargin="10" marginwidth="10">
+
+<div class="www_sectiontitle">
+ Try out LLVM in your browser!
+</div>
+
+<table border=0><tr><td>
+<img align=right width=100 height=111 src="$LOGO_IMAGE_URL">
+</td><td>
+EOF
+
+if ( -f "$ROOT/locked" ) {
+ my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$locktime) =
+ stat("$ROOT/locked");
+ my $currtime = time();
+ if ($locktime + 60 > $currtime) {
+ print "This page is already in use by someone else at this ";
+ print "time, try reloading in a second or two. Meow!</td></tr></table>'\n";
+ exit 0;
+ }
+}
+
+system("touch $ROOT/locked");
+
+print <<END;
+Bitter Melon the cat says, paste a C/C++ program in the text box or upload
+one from your computer, and you can see LLVM compile it, meow!!
+</td></tr></table><p>
+END
+
+print $c->start_multipart_form( 'POST', $FORM_URL );
+
+my $source = $c->param('source');
+
+
+# Start the user out with something valid if no code.
+$source = $defaultsrc if (!defined($source));
+
+print '<table border="0"><tr><td>';
+
+print "Type your source code in below: (<a href='DemoInfo.html#hints'>hints and
+advice</a>)<br>\n";
+
+print $c->textarea(
+ -name => "source",
+ -rows => 16,
+ -columns => 60,
+ -default => $source
+), "<br>";
+
+print "Or upload a file: ";
+print $c->filefield( -name => 'uploaded_file', -default => '' );
+
+print "<p />\n";
+
+
+print '<p></td><td valign=top>';
+
+print "<center><h3>General Options</h3></center>";
+
+print "Source language: ",
+ $c->radio_group(
+ -name => 'language',
+ -values => [ 'C', 'C++' ],
+ -default => 'C'
+ ), "<p>";
+
+print $c->checkbox(
+ -name => 'linkopt',
+ -label => 'Run link-time optimizer',
+ -checked => 'checked'
+ ),' <a href="DemoInfo.html#lto">?</a><br>';
+
+print $c->checkbox(
+ -name => 'showstats',
+ -label => 'Show detailed pass statistics'
+ ), ' <a href="DemoInfo.html#stats">?</a><br>';
+
+print $c->checkbox(
+ -name => 'cxxdemangle',
+ -label => 'Demangle C++ names'
+ ),' <a href="DemoInfo.html#demangle">?</a><p>';
+
+
+print "<center><h3>Output Options</h3></center>";
+
+print $c->checkbox(
+ -name => 'showbcanalysis',
+ -label => 'Show detailed bytecode analysis'
+ ),' <a href="DemoInfo.html#bcanalyzer">?</a><br>';
+
+print $c->checkbox(
+ -name => 'showllvm2cpp',
+ -label => 'Show LLVM C++ API code'
+ ), ' <a href="DemoInfo.html#llvm2cpp">?</a>';
+
+print "</td></tr></table>";
+
+print "<center>", $c->submit(-value=> 'Compile Source Code'),
+ "</center>\n", $c->endform;
+
+print "\n<p>If you have questions about the LLVM code generated by the
+front-end, please check the <a href='/docs/FAQ.html#cfe_code'>FAQ</a> and
+the demo page <a href='DemoInfo.html#hints'>hints section</a>.
+</p>\n";
+
+$ENV{'PATH'} = ( join ( ':', @PREPENDPATHDIRS ) ) . ":" . $ENV{'PATH'};
+
+sub sanitychecktools {
+ my $sanitycheckfail = '';
+
+ # insert tool-specific sanity checks here
+ $sanitycheckfail .= ' llvm-dis'
+ if `llvm-dis --help 2>&1` !~ /ll disassembler/;
+
+ $sanitycheckfail .= ' llvm-gcc'
+ if ( `llvm-gcc --version 2>&1` !~ /Free Software Foundation/ );
+
+ $sanitycheckfail .= ' llvm-ld'
+ if `llvm-ld --help 2>&1` !~ /llvm linker/;
+
+ $sanitycheckfail .= ' llvm-bcanalyzer'
+ if `llvm-bcanalyzer --help 2>&1` !~ /bcanalyzer/;
+
+ barf(
+"<br/>The demo page is currently unavailable. [tools: ($sanitycheckfail ) failed sanity check]"
+ )
+ if $sanitycheckfail;
+}
+
+sanitychecktools();
+
+sub try_run {
+ my ( $program, $commandline, $outputFile ) = @_;
+ my $retcode = 0;
+
+ eval {
+ local $SIG{ALRM} = sub { die "timeout"; };
+ alarm $TIMEOUTAMOUNT;
+ $retcode = system($commandline);
+ alarm 0;
+ };
+ if ( $@ and $@ =~ /timeout/ ) {
+ 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 );
+ }
+ #print "<p>Finished dumping command output.</p>\n";
+ if ( WIFEXITED($retcode) && WEXITSTATUS($retcode) != 0 ) {
+ barf(
+"$program exited with an error. Please correct source and resubmit.<p>\n" .
+"Please note that this form only allows fully formed and correct source" .
+" files. It will not compile fragments of code.<p>"
+ );
+ }
+ if ( WIFSIGNALED($retcode) != 0 ) {
+ my $sig = WTERMSIG($retcode);
+ barf(
+ "Ouch, $program caught signal $sig. Sorry, better luck next time!\n"
+ );
+ }
+}
+
+my %suffixes = (
+ 'Java' => '.java',
+ 'JO99' => '.jo9',
+ 'C' => '.c',
+ 'C++' => '.cc',
+ 'Stacker' => '.st',
+ 'preprocessed C' => '.i',
+ 'preprocessed C++' => '.ii'
+);
+my %languages = (
+ '.jo9' => 'JO99',
+ '.java' => 'Java',
+ '.c' => 'C',
+ '.i' => 'preprocessed C',
+ '.ii' => 'preprocessed C++',
+ '.cc' => 'C++',
+ '.cpp' => 'C++',
+ '.st' => 'Stacker'
+);
+
+my $uploaded_file_name = $c->param('uploaded_file');
+if ($uploaded_file_name) {
+ if ($source) {
+ barf(
+"You must choose between uploading a file and typing code in. You can't do both at the same time."
+ );
+ }
+ $uploaded_file_name =~ s/^.*(\.[A-Za-z]+)$/$1/;
+ my $language = $languages{$uploaded_file_name};
+ $c->param( 'language', $language );
+
+ print "<p>Processing uploaded file. It looks like $language.</p>\n";
+ my $fh = $c->upload('uploaded_file');
+ if ( !$fh ) {
+ barf( "Error uploading file: " . $c->cgi_error );
+ }
+ while (<$fh>) {
+ $source .= $_;
+ }
+ close $fh;
+}
+
+if ($c->param('source')) {
+ print $c->hr;
+ my $extension = $suffixes{ $c->param('language') };
+ barf "Unknown language; can't compile\n" unless $extension;
+
+ # Add a newline to the source here to avoid a warning from gcc.
+ $source .= "\n";
+
+ # Avoid security hole due to #including bad stuff.
+ $source =~
+s@(\n)?#include.*[<"](.*\.\..*)[">].*\n@$1#error "invalid #include file $2 detected"\n@g;
+
+ my $inputFile = writeIntoFile( $extension, $source );
+ my $pid = $$;
+
+ my $bytecodeFile = getname(".bc");
+ my $outputFile = getname(".llvm-gcc.out");
+ my $timerFile = getname(".llvm-gcc.time");
+
+ my $stats = '';
+ if ( $extension eq ".st" ) {
+ $stats = "-stats -time-passes "
+ if ( $c->param('showstats') );
+ try_run( "llvm Stacker front-end (stkrc)",
+ "stkrc $stats -o $bytecodeFile $inputFile > $outputFile 2>&1",
+ $outputFile );
+ } else {
+ #$stats = "-Wa,--stats,--time-passes,--info-output-file=$timerFile"
+ $stats = "-ftime-report"
+ if ( $c->param('showstats') );
+ try_run( "llvm C/C++ front-end (llvm-gcc)",
+ "llvm-gcc -emit-llvm -W -Wall -O2 $stats -o $bytecodeFile -c $inputFile > $outputFile 2>&1",
+ $outputFile );
+ }
+
+ if ( $c->param('showstats') && -s $timerFile ) {
+ my ( $UnhilightedResult, $HtmlResult ) =
+ dumpFile( "Statistics for front-end compilation", $timerFile );
+ print "$HtmlResult\n";
+ }
+
+ if ( $c->param('linkopt') ) {
+ my $stats = '';
+ my $outputFile = getname(".gccld.out");
+ my $timerFile = getname(".gccld.time");
+ $stats = "--stats --time-passes --info-output-file=$timerFile"
+ if ( $c->param('showstats') );
+ my $tmpFile = getname(".bc");
+ try_run(
+ "optimizing linker (llvm-ld)",
+"llvm-ld $stats -o=$tmpFile $bytecodeFile > $outputFile 2>&1",
+ $outputFile
+ );
+ system("mv $tmpFile.bc $bytecodeFile");
+ system("rm $tmpFile");
+
+ if ( $c->param('showstats') && -s $timerFile ) {
+ my ( $UnhilightedResult, $HtmlResult ) =
+ dumpFile( "Statistics for optimizing linker", $timerFile );
+ print "$HtmlResult\n";
+ }
+ }
+
+ print " Bytecode size is ", -s $bytecodeFile, " bytes.\n";
+
+ my $disassemblyFile = getname(".ll");
+ try_run( "llvm-dis",
+ "llvm-dis -o=$disassemblyFile $bytecodeFile > $outputFile 2>&1",
+ $outputFile );
+
+ if ( $c->param('cxxdemangle') ) {
+ print " Demangling disassembler output.\n";
+ my $tmpFile = getname(".ll");
+ system("c++filt < $disassemblyFile > $tmpFile 2>&1");
+ system("mv $tmpFile $disassemblyFile");
+ }
+
+ my ( $UnhilightedResult, $HtmlResult );
+ if ( -s $disassemblyFile ) {
+ ( $UnhilightedResult, $HtmlResult ) =
+ dumpFile( "Output from LLVM disassembler", $disassemblyFile );
+ print syntaxHighlightLLVM($HtmlResult);
+ }
+ else {
+ print "<p>Hmm, that's weird, llvm-dis didn't produce any output.</p>\n";
+ }
+
+ if ( $c->param('showbcanalysis') ) {
+ my $analFile = getname(".bca");
+ try_run( "llvm-bcanalyzer", "llvm-bcanalyzer $bytecodeFile > $analFile 2>&1",
+ $analFile);
+ }
+ if ($c->param('showllvm2cpp') ) {
+ my $l2cppFile = getname(".l2cpp");
+ try_run("llvm2cpp","llvm2cpp $bytecodeFile -o $l2cppFile 2>&1",
+ $l2cppFile);
+ }
+
+ # Get the source presented by the user to CGI, convert newline sequences to simple \n.
+ my $actualsrc = $c->param('source');
+ $actualsrc =~ s/\015\012/\n/go;
+ # Don't log this or mail it if it is the default code.
+ if ($actualsrc ne $defaultsrc) {
+ addlog( $source, $pid, $UnhilightedResult );
+
+ my ( $ip, $host, $lg, $lines );
+ chomp( $lines = `wc -l < $inputFile` );
+ $lg = $c->param('language');
+ $ip = $c->remote_addr();
+ chomp( $host = `host $ip` ) if $ip;
+ mailto( $MAILADDR,
+ "--- Query: ---\nFrom: ($ip) $host\nInput: $lines lines of $lg\n"
+ . "C++ demangle = "
+ . ( $c->param('cxxdemangle') ? 1 : 0 )
+ . ", Link opt = "
+ . ( $c->param('linkopt') ? 1 : 0 ) . "\n\n"
+ . ", Show stats = "
+ . ( $c->param('showstats') ? 1 : 0 ) . "\n\n"
+ . "--- Source: ---\n$source\n"
+ . "--- Result: ---\n$UnhilightedResult\n" );
+ }
+ unlink( $inputFile, $bytecodeFile, $outputFile, $disassemblyFile );
+}
+
+print $c->hr, "<address>$CONTACT_ADDRESS</address>", $c->end_html;
+system("rm $ROOT/locked");
+exit 0;
diff --git a/www/demo/syntax.css b/www/demo/syntax.css
new file mode 100644
index 000000000000..90daf5fcbd1f
--- /dev/null
+++ b/www/demo/syntax.css
@@ -0,0 +1,4 @@
+/* LLVM syntax highlighting for the Web */
+
+.llvm_type { font-style: oblique; color: green }
+.llvm_keyword { font-weight: bold; color: blue }
diff --git a/www/demo/what is this directory.txt b/www/demo/what is this directory.txt
new file mode 100644
index 000000000000..a1306ac0dc5b
--- /dev/null
+++ b/www/demo/what is this directory.txt
@@ -0,0 +1,15 @@
+This is for the LLVM+Clang browser based demo.
+It is supposed to work like the LLVM+GCC demo here: http://llvm.org/demo/ but for the BSD licensed Clang instead.
+
+Perhaps it could also be used for getting crash information and details on errors.... I'm not sure if this would require some major changes or not to report this info. Maybe also adding ways that people can use it to test for errors and a way to report such errors would also be good.
+
+Status:
+Anyways, right now, these file a basically just a copy of the LLVM+GCC demo (no changes have been made). The files don't even work right in this location on the server. As such, someone will need to edit the file or rewrite it.
+
+If nobody in the LLVM community has the skills, one suggestion would be to post a request on a friendly Perl forum and see if anybody might be interested in taking on the challenge.
+
+Alternatively, you could try a PHP, Python, Ruby, or Lisp mailing list and see if there are any takers who would be interested (and willing to do a rewrite to their language of choice).
+
+--
+BTW, once this feature was working, my intention was to link to it from the index.html page in the section entitled:
+Try Clang \ No newline at end of file
diff --git a/www/diagnostics.html b/www/diagnostics.html
new file mode 100644
index 000000000000..5be4db207409
--- /dev/null
+++ b/www/diagnostics.html
@@ -0,0 +1,279 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Clang - Expressive Diagnostics</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+ <style type="text/css">
+</style>
+</head>
+<body>
+
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+
+<!--=======================================================================-->
+<h1>Expressive Diagnostics</h1>
+<!--=======================================================================-->
+
+<p>In addition to being fast and functional, we aim to make Clang extremely user
+friendly. As far as a command-line compiler goes, this basically boils down to
+making the diagnostics (error and warning messages) generated by the compiler
+be as useful as possible. There are several ways that we do this. This section
+talks about the experience provided by the command line compiler, contrasting
+Clang output to GCC 4.2's output in several examples.
+<!--
+Other clients
+that embed Clang and extract equivalent information through internal APIs.-->
+</p>
+
+<h2>Column Numbers and Caret Diagnostics</h2>
+
+<p>First, all diagnostics produced by clang include full column number
+information, and use this to print "caret diagnostics". This is a feature
+provided by many commercial compilers, but is generally missing from open source
+compilers. This is nice because it makes it very easy to understand exactly
+what is wrong in a particular piece of code, an example is:</p>
+
+<pre>
+ $ <b>gcc-4.2 -fsyntax-only -Wformat format-strings.c</b>
+ format-strings.c:91: warning: too few arguments for format
+ $ <b>clang -fsyntax-only format-strings.c</b>
+ format-strings.c:91:13: warning: '.*' specified field precision is missing a matching 'int' argument
+ <font color="darkgreen"> printf("%.*d");</font>
+ <font color="blue"> ^</font>
+</pre>
+
+<p>The caret (the blue "^" character) exactly shows where the problem is, even
+inside of the string. This makes it really easy to jump to the problem and
+helps when multiple instances of the same character occur on a line. We'll
+revisit this more in following examples.</p>
+
+<h2>Range Highlighting for Related Text</h2>
+
+<p>Clang captures and accurately tracks range information for expressions,
+statements, and other constructs in your program and uses this to make
+diagnostics highlight related information. For example, here's a somewhat
+nonsensical example to illustrate this:</p>
+
+<pre>
+ $ <b>gcc-4.2 -fsyntax-only t.c</b>
+ t.c:7: error: invalid operands to binary + (have 'int' and 'struct A')
+ $ <b>clang -fsyntax-only t.c</b>
+ t.c:7:39: error: invalid operands to binary expression ('int' and 'struct A')
+ <font color="darkgreen"> return y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X);</font>
+ <font color="blue"> ~~~~~~~~~~~~~~ ^ ~~~~~</font>
+</pre>
+
+<p>Here you can see that you don't even need to see the original source code to
+understand what is wrong based on the Clang error: Because clang prints a
+caret, you know exactly <em>which</em> plus it is complaining about. The range
+information highlights the left and right side of the plus which makes it
+immediately obvious what the compiler is talking about, which is very useful for
+cases involving precedence issues and many other cases.</p>
+
+<h2>Precision in Wording</h2>
+
+<p>A detail is that we have tried really hard to make the diagnostics that come
+out of clang contain exactly the pertinent information about what is wrong and
+why. In the example above, we tell you what the inferred types are for
+the left and right hand sides, and we don't repeat what is obvious from the
+caret (that this is a "binary +"). Many other examples abound, here is a simple
+one:</p>
+
+<pre>
+ $ <b>gcc-4.2 -fsyntax-only t.c</b>
+ t.c:5: error: invalid type argument of 'unary *'
+ $ <b>clang -fsyntax-only t.c</b>
+ t.c:5:11: error: indirection requires pointer operand ('int' invalid)
+ <font color="darkgreen"> int y = *SomeA.X;</font>
+ <font color="blue"> ^~~~~~~~</font>
+</pre>
+
+<p>In this example, not only do we tell you that there is a problem with the *
+and point to it, we say exactly why and tell you what the type is (in case it is
+a complicated subexpression, such as a call to an overloaded function). This
+sort of attention to detail makes it much easier to understand and fix problems
+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>
+
+<pre>
+ $ <b>gcc-4.2 -fsyntax-only t.c</b>
+ #'exact_div_expr' not supported by pp_c_expression#'t.c:12: error: called object is not a function
+ $ <b>clang -fsyntax-only t.c</b>
+ t.c:12:8: error: called object type 'int' is not a function or function pointer
+ <font color="darkgreen"> (P-Q)();</font>
+ <font color="blue"> ~~~~~^</font>
+</pre>
+
+
+<h2>Typedef Preservation and Selective Unwrapping</h2>
+
+<p>Many programmers use high-level user defined types, typedefs, and other
+syntactic sugar to refer to types in their program. This is useful because they
+can abbreviate otherwise very long types and it is useful to preserve the
+typename in diagnostics. However, sometimes very simple typedefs can wrap
+trivial types and it is important to strip off the typedef to understand what
+is going on. Clang aims to handle both cases well.<p>
+
+<p>For example, here is an example that shows where it is important to preserve
+a typedef in C:</p>
+
+<pre>
+ $ <b>gcc-4.2 -fsyntax-only t.c</b>
+ t.c:15: error: invalid operands to binary / (have 'float __vector__' and 'const int *')
+ $ <b>clang -fsyntax-only t.c</b>
+ t.c:15:11: error: can't convert between vector values of different size ('__m128' and 'int const *')
+ <font color="darkgreen"> myvec[1]/P;</font>
+ <font color="blue"> ~~~~~~~~^~</font>
+</pre>
+
+<p>Here the type printed by GCC isn't even valid, but if the error were about a
+very long and complicated type (as often happens in C++) the error message would
+be ugly just because it was long and hard to read. Here's an example where it
+is useful for the compiler to expose underlying details of a typedef:</p>
+
+<pre>
+ $ <b>gcc-4.2 -fsyntax-only t.c</b>
+ t.c:13: error: request for member 'x' in something not a structure or union
+ $ <b>clang -fsyntax-only t.c</b>
+ t.c:13:9: error: member reference base type 'pid_t' (aka 'int') is not a structure or union
+ <font color="darkgreen"> myvar = myvar.x;</font>
+ <font color="blue"> ~~~~~ ^</font>
+</pre>
+
+<p>If the user was somehow confused about how the system "pid_t" typedef is
+defined, Clang helpfully displays it with "aka".</p>
+
+<p>In C++, type preservation includes retaining any qualification written into type names. For example, if we take a small snippet of code such as:
+
+<blockquote>
+<pre>
+namespace services {
+ struct WebService { };
+}
+namespace myapp {
+ namespace servers {
+ struct Server { };
+ }
+}
+
+using namespace myapp;
+void addHTTPService(servers::Server const &server, ::services::WebService const *http) {
+ server += http;
+}
+</pre>
+</blockquote>
+
+<p>and then compile it, we see that Clang is both providing more accurate information and is retaining the types as written by the user (e.g., "servers::Server", "::services::WebService"):
+
+<pre>
+ $ <b>g++-4.2 -fsyntax-only t.cpp</b>
+ t.cpp:9: error: no match for 'operator+=' in 'server += http'
+ $ <b>clang -fsyntax-only t.cpp</b>
+ t.cpp:9:10: error: invalid operands to binary expression ('servers::Server const' and '::services::WebService const *')
+ <font color="darkgreen">server += http;</font>
+ <font color="blue">~~~~~~ ^ ~~~~</font>
+</pre>
+
+<p>Naturally, type preservation extends to uses of templates, and Clang retains information about how a particular template specialization (like <code>std::vector&lt;Real&gt;</code>) was spelled within the source code. For example:</p>
+
+<pre>
+ $ <b>g++-4.2 -fsyntax-only t.cpp</b>
+ t.cpp:12: error: no match for 'operator=' in 'str = vec'
+ $ <b>clang -fsyntax-only t.cpp</b>
+ t.cpp:12:7: error: incompatible type assigning 'vector&lt;Real&gt;', expected 'std::string' (aka 'class std::basic_string&lt;char&gt;')
+ <font color="darkgreen">str = vec</font>;
+ <font color="blue">^ ~~~</font>
+</pre>
+
+<h2>Fix-it Hints</h2>
+
+<p>"Fix-it" hints provide advice for fixing small, localized problems
+in source code. When Clang produces a diagnostic about a particular
+problem that it can work around (e.g., non-standard or redundant
+syntax, missing keywords, common mistakes, etc.), it may also provide
+specific guidance in the form of a code transformation to correct the
+problem. For example, here Clang warns about the use of a GCC
+extension that has been considered obsolete since 1993:</p>
+
+<pre>
+ $ <b>clang t.c</b>
+ t.c:5:28: warning: use of GNU old-style field designator extension
+ <font color="darkgreen">struct point origin = { x: 0.0, y: 0.0 };</font>
+ <font color="red">~~</font> <font color="blue">^</font>
+ <font color="darkgreen">.x = </font>
+ t.c:5:36: warning: use of GNU old-style field designator extension
+ <font color="darkgreen">struct point origin = { x: 0.0, y: 0.0 };</font>
+ <font color="red">~~</font> <font color="blue">^</font>
+ <font color="darkgreen">.y = </font>
+</pre>
+
+<p>The underlined code should be removed, then replaced with the code below the caret line (".x =" or ".y =", respectively). "Fix-it" hints are most useful for working around common user errors and misconceptions. For example, C++ users commonly forget the syntax for explicit specialization of class templates, as in the following error:</p>
+
+<pre>
+ $ <b>clang t.cpp</b>
+ t.cpp:9:3: error: template specialization requires 'template&lt;&gt;'
+ struct iterator_traits&lt;file_iterator&gt; {
+ <font color="blue">^</font>
+ <font color="darkgreen">template&lt;&gt; </font>
+</pre>
+
+<p>Again, after describing the problem, Clang provides the fix--add <code>template&lt;&gt;</code>--as part of the diagnostic.<p>
+
+<h2>Automatic Macro Expansion</h2>
+
+<p>Many errors happen in macros that are sometimes deeply nested. With
+traditional compilers, you need to dig deep into the definition of the macro to
+understand how you got into trouble. Here's a simple example that shows how
+Clang helps you out:</p>
+
+<pre>
+ $ <b>gcc-4.2 -fsyntax-only t.c</b>
+ t.c: In function 'test':
+ t.c:80: error: invalid operands to binary &lt; (have 'struct mystruct' and 'float')
+ $ <b>clang -fsyntax-only t.c</b>
+ t.c:80:3: error: invalid operands to binary expression ('typeof(P)' (aka 'struct mystruct') and 'typeof(F)' (aka 'float'))
+ <font color="darkgreen"> X = MYMAX(P, F);</font>
+ <font color="blue"> ^~~~~~~~~~~</font>
+ t.c:76:94: note: instantiated from:
+ <font color="darkgreen">#define MYMAX(A,B) __extension__ ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a &lt; __b ? __b : __a; })</font>
+ <font color="blue"> ~~~ ^ ~~~</font>
+</pre>
+
+<p>This shows how clang automatically prints instantiation information and
+nested range information for diagnostics as they are instantiated through macros
+and also shows how some of the other pieces work in a bigger example. Here's
+another real world warning that occurs in the "window" Unix package (which
+implements the "wwopen" class of APIs):</p>
+
+<pre>
+ $ <b>clang -fsyntax-only t.c</b>
+ t.c:22:2: warning: type specifier missing, defaults to 'int'
+ <font color="darkgreen"> ILPAD();</font>
+ <font color="blue"> ^</font>
+ t.c:17:17: note: instantiated from:
+ <font color="darkgreen">#define ILPAD() PAD((NROW - tt.tt_row) * 10) /* 1 ms per char */</font>
+ <font color="blue"> ^</font>
+ t.c:14:2: note: instantiated from:
+ <font color="darkgreen"> register i; \</font>
+ <font color="blue"> ^</font>
+</pre>
+
+<p>In practice, we've found that this is actually more useful in multiply nested
+macros that in simple ones.</p>
+
+</div>
+</body>
+</html>
diff --git a/www/distclang_status.html b/www/distclang_status.html
new file mode 100644
index 000000000000..26ba31424f85
--- /dev/null
+++ b/www/distclang_status.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Clang - Distributed Compilation Support</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+ <style type="text/css">
+</style>
+</head>
+<body>
+
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<!--*************************************************************************-->
+<h1>Distributed Compilation Support in Clang</h1>
+<!--*************************************************************************-->
+
+<p>
+This page tracks the status of Distributed Compilation support in Clang.<br>
+Currently some basic features are working but the code is under heavy
+development. </p>
+
+
+</div>
+</body>
+</html>
diff --git a/www/feature-compile1.png b/www/feature-compile1.png
new file mode 100644
index 000000000000..cec7c4851492
--- /dev/null
+++ b/www/feature-compile1.png
Binary files differ
diff --git a/www/feature-compile2.png b/www/feature-compile2.png
new file mode 100644
index 000000000000..0eb93001ffca
--- /dev/null
+++ b/www/feature-compile2.png
Binary files differ
diff --git a/www/feature-memory1.png b/www/feature-memory1.png
new file mode 100644
index 000000000000..29368aa83820
--- /dev/null
+++ b/www/feature-memory1.png
Binary files differ
diff --git a/www/features.html b/www/features.html
new file mode 100644
index 000000000000..21382fd5b17f
--- /dev/null
+++ b/www/features.html
@@ -0,0 +1,423 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Clang - Features and Goals</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+ <style type="text/css">
+</style>
+</head>
+<body>
+
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<!--*************************************************************************-->
+<h1>Clang - Features and Goals</h1>
+<!--*************************************************************************-->
+
+<p>
+This page describes the <a href="index.html#goals">features and goals</a> of
+Clang in more detail and gives a more broad explanation about what we mean.
+These features are:
+</p>
+
+<p>End-User Features:</p>
+
+<ul>
+<li><a href="#performance">Fast compiles and low memory use</a></li>
+<li><a href="#expressivediags">Expressive diagnostics</a></li>
+<li><a href="#gcccompat">GCC compatibility</a></li>
+</ul>
+
+<p>Utility and Applications:</p>
+
+<ul>
+<li><a href="#libraryarch">Library based architecture</a></li>
+<li><a href="#diverseclients">Support diverse clients</a></li>
+<li><a href="#ideintegration">Integration with IDEs</a></li>
+<li><a href="#license">Use the LLVM 'BSD' License</a></li>
+</ul>
+
+<p>Internal Design and Implementation:</p>
+
+<ul>
+<li><a href="#real">A real-world, production quality compiler</a></li>
+<li><a href="#simplecode">A simple and hackable code base</a></li>
+<li><a href="#unifiedparser">A single unified parser for C, Objective C, C++,
+ and Objective C++</a></li>
+<li><a href="#conformance">Conformance with C/C++/ObjC and their
+ variants</a></li>
+</ul>
+
+<!--*************************************************************************-->
+<h2><a name="enduser">End-User Features</a></h2>
+<!--*************************************************************************-->
+
+
+<!--=======================================================================-->
+<h3><a name="performance">Fast compiles and Low Memory Use</a></h3>
+<!--=======================================================================-->
+
+<p>A major focus of our work on clang is to make it fast, light and scalable.
+The library-based architecture of clang makes it straight-forward to time and
+profile the cost of each layer of the stack, and the driver has a number of
+options for performance analysis.</p>
+
+<p>While there is still much that can be done, we find that the clang front-end
+is significantly quicker than gcc and uses less memory For example, when
+compiling "Carbon.h" on Mac OS/X, we see that clang is 2.5x faster than GCC:</p>
+
+<img class="img_slide" src="feature-compile1.png" width="400" height="300" />
+
+<p>Carbon.h is a monster: it transitively includes 558 files, 12.3M of code,
+declares 10000 functions, has 2000 struct definitions, 8000 fields, 20000 enum
+constants, etc (see slide 25+ of the <a href="clang_video-07-25-2007.html">clang
+talk</a> for more information). It is also #include'd into almost every C file
+in a GUI app on the Mac, so its compile time is very important.</p>
+
+<p>From the slide above, you can see that we can measure the time to preprocess
+the file independently from the time to parse it, and independently from the
+time to build the ASTs for the code. GCC doesn't provide a way to measure the
+parser without AST building (it only provides -fsyntax-only). In our
+measurements, we find that clang's preprocessor is consistently 40% faster than
+GCCs, and the parser + AST builder is ~4x faster than GCC's. If you have
+sources that do not depend as heavily on the preprocessor (or if you
+use Precompiled Headers) you may see a much bigger speedup from clang.
+</p>
+
+<p>Compile time performance is important, but when using clang as an API, often
+memory use is even moreso: the less memory the code takes the more code you can
+fit into memory at a time (useful for whole program analysis tools, for
+example).</p>
+
+<img class="img_slide" src="feature-memory1.png" width="400" height="300" />
+
+<p>Here we see a huge advantage of clang: its ASTs take <b>5x less memory</b>
+than GCC's syntax trees, despite the fact that clang's ASTs capture far more
+source-level information than GCC's trees do. This feat is accomplished through
+the use of carefully designed APIs and efficient representations.</p>
+
+<p>In addition to being efficient when pitted head-to-head against GCC in batch
+mode, clang is built with a <a href="#libraryarch">library based
+architecture</a> that makes it relatively easy to adapt it and build new tools
+with it. This means that it is often possible to apply out-of-the-box thinking
+and novel techniques to improve compilation in various ways.</p>
+
+<img class="img_slide" src="feature-compile2.png" width="400" height="300" />
+
+<p>This slide shows how the clang preprocessor can be used to make "distcc"
+parallelization <b>3x</b> more scalable than when using the GCC preprocessor.
+"distcc" quickly bottlenecks on the preprocessor running on the central driver
+machine, so a fast preprocessor is very useful. Comparing the first two bars
+of each group shows how a ~40% faster preprocessor can reduce preprocessing time
+of these large C++ apps by about 40% (shocking!).</p>
+
+<p>The third bar on the slide is the interesting part: it shows how trivial
+caching of file system accesses across invocations of the preprocessor allows
+clang to reduce time spent in the kernel by 10x, making distcc over 3x more
+scalable. This is obviously just one simple hack, doing more interesting things
+(like caching tokens across preprocessed files) would yield another substantial
+speedup.</p>
+
+<p>The clean framework-based design of clang means that many things are possible
+that would be very difficult in other systems, for example incremental
+compilation, multithreading, intelligent caching, etc. We are only starting
+to tap the full potential of the clang design.</p>
+
+
+<!--=======================================================================-->
+<h3><a name="expressivediags">Expressive Diagnostics</a></h3>
+<!--=======================================================================-->
+
+<p>In addition to being fast and functional, we aim to make Clang extremely user
+friendly. As far as a command-line compiler goes, this basically boils down to
+making the diagnostics (error and warning messages) generated by the compiler
+be as useful as possible. There are several ways that we do this, but the
+most important are pinpointing exactly what is wrong in the program,
+highlighting related information so that it is easy to understand at a glance,
+and making the wording as clear as possible.</p>
+
+<p>Here is one simple example that illustrates the difference between a typical
+GCC and Clang diagnostic:</p>
+
+<pre>
+ $ <b>gcc-4.2 -fsyntax-only t.c</b>
+ t.c:7: error: invalid operands to binary + (have 'int' and 'struct A')
+ $ <b>clang -fsyntax-only t.c</b>
+ t.c:7:39: error: invalid operands to binary expression ('int' and 'struct A')
+ <font color="darkgreen"> return y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X);</font>
+ <font color="blue"> ~~~~~~~~~~~~~~ ^ ~~~~~</font>
+</pre>
+
+<p>Here you can see that you don't even need to see the original source code to
+understand what is wrong based on the Clang error: Because clang prints a
+caret, you know exactly <em>which</em> plus it is complaining about. The range
+information highlights the left and right side of the plus which makes it
+immediately obvious what the compiler is talking about, which is very useful for
+cases involving precedence issues and many other situations.</p>
+
+<p>Clang diagnostics are very polished and have many features. For more
+information and examples, please see the <a href="diagnostics.html">Expressive
+Diagnostics</a> page.</p>
+
+<!--=======================================================================-->
+<h3><a name="gcccompat">GCC Compatibility</a></h3>
+<!--=======================================================================-->
+
+<p>GCC is currently the defacto-standard open source compiler today, and it
+routinely compiles a huge volume of code. GCC supports a huge number of
+extensions and features (many of which are undocumented) and a lot of
+code and header files depend on these features in order to build.</p>
+
+<p>While it would be nice to be able to ignore these extensions and focus on
+implementing the language standards to the letter, pragmatics force us to
+support the GCC extensions that see the most use. Many users just want their
+code to compile, they don't care to argue about whether it is pedantically C99
+or not.</p>
+
+<p>As mentioned above, all
+extensions are explicitly recognized as such and marked with extension
+diagnostics, which can be mapped to warnings, errors, or just ignored.
+</p>
+
+
+<!--*************************************************************************-->
+<h2><a name="applications">Utility and Applications</a></h2>
+<!--*************************************************************************-->
+
+<!--=======================================================================-->
+<h3><a name="libraryarch">Library Based Architecture</a></h3>
+<!--=======================================================================-->
+
+<p>A major design concept for clang is its use of a library-based
+architecture. In this design, various parts of the front-end can be cleanly
+divided into separate libraries which can then be mixed up for different needs
+and uses. In addition, the library-based approach encourages good interfaces
+and makes it easier for new developers to get involved (because they only need
+to understand small pieces of the big picture).</p>
+
+<blockquote>
+"The world needs better compiler tools, tools which are built as libraries.
+This design point allows reuse of the tools in new and novel ways. However,
+building the tools as libraries isn't enough: they must have clean APIs, be as
+decoupled from each other as possible, and be easy to modify/extend. This
+requires clean layering, decent design, and keeping the libraries independent of
+any specific client."</blockquote>
+
+<p>
+Currently, clang is divided into the following libraries and tool:
+</p>
+
+<ul>
+<li><b>libsupport</b> - Basic support library, from LLVM.</li>
+<li><b>libsystem</b> - System abstraction library, from LLVM.</li>
+<li><b>libbasic</b> - Diagnostics, SourceLocations, SourceBuffer abstraction,
+ file system caching for input source files.</li>
+<li><b>libast</b> - Provides classes to represent the C AST, the C type system,
+ builtin functions, and various helpers for analyzing and manipulating the
+ AST (visitors, pretty printers, etc).</li>
+<li><b>liblex</b> - Lexing and preprocessing, identifier hash table, pragma
+ handling, tokens, and macro expansion.</li>
+<li><b>libparse</b> - Parsing. This library invokes coarse-grained 'Actions'
+ provided by the client (e.g. libsema builds ASTs) but knows nothing about
+ ASTs or other client-specific data structures.</li>
+<li><b>libsema</b> - Semantic Analysis. This provides a set of parser actions
+ to build a standardized AST for programs.</li>
+<li><b>libcodegen</b> - Lower the AST to LLVM IR for optimization &amp; code
+ generation.</li>
+<li><b>librewrite</b> - Editing of text buffers (important for code rewriting
+ transformation, like refactoring).</li>
+<li><b>libanalysis</b> - Static analysis support.</li>
+<li><b>clang</b> - A driver program, client of the libraries at various
+ levels.</li>
+</ul>
+
+<p>As an example of the power of this library based design.... If you wanted to
+build a preprocessor, you would take the Basic and Lexer libraries. If you want
+an indexer, you would take the previous two and add the Parser library and
+some actions for indexing. If you want a refactoring, static analysis, or
+source-to-source compiler tool, you would then add the AST building and
+semantic analyzer libraries.</p>
+
+<p>For more information about the low-level implementation details of the
+various clang libraries, please see the <a href="docs/InternalsManual.html">
+clang Internals Manual</a>.</p>
+
+<!--=======================================================================-->
+<h3><a name="diverseclients">Support Diverse Clients</a></h3>
+<!--=======================================================================-->
+
+<p>Clang is designed and built with many grand plans for how we can use it. The
+driving force is the fact that we use C and C++ daily, and have to suffer due to
+a lack of good tools available for it. We believe that the C and C++ tools
+ecosystem has been significantly limited by how difficult it is to parse and
+represent the source code for these languages, and we aim to rectify this
+problem in clang.</p>
+
+<p>The problem with this goal is that different clients have very different
+requirements. Consider code generation, for example: a simple front-end that
+parses for code generation must analyze the code for validity and emit code
+in some intermediate form to pass off to a optimizer or backend. Because
+validity analysis and code generation can largely be done on the fly, there is
+not hard requirement that the front-end actually build up a full AST for all
+the expressions and statements in the code. TCC and GCC are examples of
+compilers that either build no real AST (in the former case) or build a stripped
+down and simplified AST (in the later case) because they focus primarily on
+codegen.</p>
+
+<p>On the opposite side of the spectrum, some clients (like refactoring) want
+highly detailed information about the original source code and want a complete
+AST to describe it with. Refactoring wants to have information about macro
+expansions, the location of every paren expression '(((x)))' vs 'x', full
+position information, and much more. Further, refactoring wants to look
+<em>across the whole program</em> to ensure that it is making transformations
+that are safe. Making this efficient and getting this right requires a
+significant amount of engineering and algorithmic work that simply are
+unnecessary for a simple static compiler.</p>
+
+<p>The beauty of the clang approach is that it does not restrict how you use it.
+In particular, it is possible to use the clang preprocessor and parser to build
+an extremely quick and light-weight on-the-fly code generator (similar to TCC)
+that does not build an AST at all. As an intermediate step, clang supports
+using the current AST generation and semantic analysis code and having a code
+generation client free the AST for each function after code generation. Finally,
+clang provides support for building and retaining fully-fledged ASTs, and even
+supports writing them out to disk.</p>
+
+<p>Designing the libraries with clean and simple APIs allows these high-level
+policy decisions to be determined in the client, instead of forcing "one true
+way" in the implementation of any of these libraries. Getting this right is
+hard, and we don't always get it right the first time, but we fix any problems
+when we realize we made a mistake.</p>
+
+<!--=======================================================================-->
+<h3><a name="ideintegration">Integration with IDEs</h3>
+<!--=======================================================================-->
+
+<p>
+We believe that Integrated Development Environments (IDE's) are a great way
+to pull together various pieces of the development puzzle, and aim to make clang
+work well in such an environment. The chief advantage of an IDE is that they
+typically have visibility across your entire project and are long-lived
+processes, whereas stand-alone compiler tools are typically invoked on each
+individual file in the project, and thus have limited scope.</p>
+
+<p>There are many implications of this difference, but a significant one has to
+do with efficiency and caching: sharing an address space across different files
+in a project, means that you can use intelligent caching and other techniques to
+dramatically reduce analysis/compilation time.</p>
+
+<p>A further difference between IDEs and batch compiler is that they often
+impose very different requirements on the front-end: they depend on high
+performance in order to provide a "snappy" experience, and thus really want
+techniques like "incremental compilation", "fuzzy parsing", etc. Finally, IDEs
+often have very different requirements than code generation, often requiring
+information that a codegen-only frontend can throw away. Clang is
+specifically designed and built to capture this information.
+</p>
+
+
+<!--=======================================================================-->
+<h3><a name="license">Use the LLVM 'BSD' License</a></h3>
+<!--=======================================================================-->
+
+<p>We actively indend for clang (and a LLVM as a whole) to be used for
+commercial projects, and the BSD license is the simplest way to allow this. We
+feel that the license encourages contributors to pick up the source and work
+with it, and believe that those individuals and organizations will contribute
+back their work if they do not want to have to maintain a fork forever (which is
+time consuming and expensive when merges are involved). Further, nobody makes
+money on compilers these days, but many people need them to get bigger goals
+accomplished: it makes sense for everyone to work together.</p>
+
+<p>For more information about the LLVM/clang license, please see the <a
+href="http://llvm.org/docs/DeveloperPolicy.html#license">LLVM License
+Description</a> for more information.</p>
+
+
+
+<!--*************************************************************************-->
+<h2><a name="design">Internal Design and Implementation</a></h2>
+<!--*************************************************************************-->
+
+<!--=======================================================================-->
+<h3><a name="real">A real-world, production quality compiler</a></h3>
+<!--=======================================================================-->
+
+<p>
+Clang is designed and built by experienced compiler developers who
+are increasingly frustrated with the problems that <a
+href="comparison.html">existing open source compilers</a> have. Clang is
+carefully and thoughtfully designed and built to provide the foundation of a
+whole new generation of C/C++/Objective C development tools, and we intend for
+it to be production quality.</p>
+
+<p>Being a production quality compiler means many things: it means being high
+performance, being solid and (relatively) bug free, and it means eventually
+being used and depended on by a broad range of people. While we are still in
+the early development stages, we strongly believe that this will become a
+reality.</p>
+
+<!--=======================================================================-->
+<h3><a name="simplecode">A simple and hackable code base</a></h3>
+<!--=======================================================================-->
+
+<p>Our goal is to make it possible for anyone with a basic understanding
+of compilers and working knowledge of the C/C++/ObjC languages to understand and
+extend the clang source base. A large part of this falls out of our decision to
+make the AST mirror the languages as closely as possible: you have your friendly
+if statement, for statement, parenthesis expression, structs, unions, etc, all
+represented in a simple and explicit way.</p>
+
+<p>In addition to a simple design, we work to make the source base approachable
+by commenting it well, including citations of the language standards where
+appropriate, and designing the code for simplicity. Beyond that, clang offers
+a set of AST dumpers, printers, and visualizers that make it easy to put code in
+and see how it is represented.</p>
+
+<!--=======================================================================-->
+<h3><a name="unifiedparser">A single unified parser for C, Objective C, C++,
+and Objective C++</a></h3>
+<!--=======================================================================-->
+
+<p>Clang is the "C Language Family Front-end", which means we intend to support
+the most popular members of the C family. We are convinced that the right
+parsing technology for this class of languages is a hand-built recursive-descent
+parser. Because it is plain C++ code, recursive descent makes it very easy for
+new developers to understand the code, it easily supports ad-hoc rules and other
+strange hacks required by C/C++, and makes it straight-forward to implement
+excellent diagnostics and error recovery.</p>
+
+<p>We believe that implementing C/C++/ObjC in a single unified parser makes the
+end result easier to maintain and evolve than maintaining a separate C and C++
+parser which must be bugfixed and maintained independently of each other.</p>
+
+<!--=======================================================================-->
+<h3><a name="conformance">Conformance with C/C++/ObjC and their
+ variants</a></h3>
+<!--=======================================================================-->
+
+<p>When you start work on implementing a language, you find out that there is a
+huge gap between how the language works and how most people understand it to
+work. This gap is the difference between a normal programmer and a (scary?
+super-natural?) "language lawyer", who knows the ins and outs of the language
+and can grok standardese with ease.</p>
+
+<p>In practice, being conformant with the languages means that we aim to support
+the full language, including the dark and dusty corners (like trigraphs,
+preprocessor arcana, C99 VLAs, etc). Where we support extensions above and
+beyond what the standard officially allows, we make an effort to explicitly call
+this out in the code and emit warnings about it (which are disabled by default,
+but can optionally be mapped to either warnings or errors), allowing you to use
+clang in "strict" mode if you desire.</p>
+
+<p>We also intend to support "dialects" of these languages, such as C89, K&amp;R
+C, C++'03, Objective-C 2, etc.</p>
+
+</div>
+</body>
+</html>
diff --git a/www/get_involved.html b/www/get_involved.html
new file mode 100644
index 000000000000..a383d7013225
--- /dev/null
+++ b/www/get_involved.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Clang - Get Involved</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+</head>
+<body>
+
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<h1>Getting Involved with the Clang Project</h1>
+
+<p>Once you have <a href="get_started.html">checked out and built</a> clang and
+played around with it, you might be wondering what you can do to make it better
+and contribute to its development. Alternatively, maybe you just want to follow
+the development of the project to see it progress.
+</p>
+
+<h2>Follow what's going on</h2>
+
+<p>Clang is a subproject of the <a href="http://llvm.org">LLVM Project</a>, but
+has its own mailing lists because the communities have people with different
+interests. The two clang lists are:</p>
+
+<ul>
+<li><a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits">cfe-commits
+</a> - This list is for patch submission/discussion.</li>
+
+<li><a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev">cfe-dev</a> -
+This list is for everything else clang related (questions and answers, bug
+reports, etc).</li>
+
+</ul>
+
+<p>If you are interested in clang only, these two lists should be all
+you need. If you are interested in the LLVM optimizer and code generator,
+please consider signing up for <a
+href="http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev">llvmdev</a> and <a
+href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits">llvm-commits</a>
+as well.</p>
+
+
+<p>The best way to talk with other developers on the project is through the <a
+href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev">cfe-dev mailing
+list</a>. The clang mailing list is a very friendly place and we welcome
+newcomers. In addition to the cfe-dev list, a significant amount of design
+discussion takes place on the <a
+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>
+
+</div>
+</body>
+</html>
diff --git a/www/get_started.html b/www/get_started.html
new file mode 100644
index 000000000000..437cb38808f8
--- /dev/null
+++ b/www/get_started.html
@@ -0,0 +1,228 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Clang - Getting Started</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+</head>
+<body>
+
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<h1>Getting Started: Building and Running Clang</h1>
+
+<p>This page gives you the shortest path to checking out Clang and demos a few
+options. This should get you up and running with the minimum of muss and fuss.
+If you like what you see, please consider <a href="get_involved.html">getting
+involved</a> with the Clang community.</p>
+
+<h2>A Word of Warning</h2>
+
+<p>While this work aims to provide a fully functional C/C++/ObjC front-end, it
+is still relatively new and under heavy development. Currently we believe clang
+to be very usable as a C and Objective-C compiler, however there is no real C++
+support yet (this is obviously a big project). Additionally, for C and
+Objective-C:</p>
+
+<ol>
+ <li>The semantic analyzer does not produce all of the warnings it should.</li>
+ <li>We don't consider the API to be stable yet, and reserve the right to
+ change fundamental things.</li>
+ <li>Only the X86-32 and X86-64 targets have been well tested.</li>
+</ol>
+
+<p>If you run into problems, please file
+bugs in <a href="http://llvm.org/bugs/">LLVM Bugzilla</a> or bring up the issue
+on the
+<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev">Clang development
+mailing list</a>.</p>
+
+<h2 id="build">Building Clang and Working with the Code</h2>
+
+<p>If you would like to check out and build Clang, the current procedure is as
+follows:</p>
+
+<ol>
+ <li><a href="http://www.llvm.org/docs/GettingStarted.html#checkout">Checkout
+ and build LLVM</a> from SVN head:</li>
+
+ <ul>
+ <li><tt>svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm</tt></li>
+ <li><tt>cd llvm</tt></li>
+ <li><tt>./configure; make</tt></li>
+ </ul>
+ <li>Checkout Clang:</li>
+ <ul>
+ <li>From within the <tt>llvm</tt> directory (where you
+ built llvm):</li>
+ <li><tt>cd tools</tt>
+ <li><tt>svn co http://llvm.org/svn/llvm-project/cfe/trunk clang</tt></li>
+
+ </ul>
+ <li>If you intend to work on Clang C++ support, you may need to tell it how
+ to find your C++ standard library headers. If Clang cannot find your
+ system libstdc++ headers, please follow these instructions:</li>
+
+ <ul>
+ <li>'<tt>touch empty.cpp; gcc -v empty.cpp -fsyntax-only</tt>' to get the
+ path.</li>
+ <li>Look for the comment "FIXME: temporary hack:
+ hard-coded paths" in <tt>clang/lib/Frontend/InitHeaderSearch.cpp</tt> and
+ change the lines below to include that path.</li>
+ </ul>
+
+ <li>Build Clang:</li>
+ <ul>
+ <li><tt>cd clang</tt> (assuming that you are in <tt>llvm/tools</tt>)</li>
+ <li><tt>make</tt> (this will give you a debug build)</li>
+ </ul>
+
+ <li>Try it out (assuming you add llvm/Debug/bin to your path):</li>
+ <ul>
+ <li><tt>clang-cc --help</tt></li>
+ <li><tt>clang-cc file.c -fsyntax-only</tt> (check for correctness)</li>
+ <li><tt>clang-cc file.c -ast-dump</tt> (internal debug dump of ast)</li>
+ <li><tt>clang-cc file.c -ast-view</tt> (<a
+ href="http://llvm.org/docs/ProgrammersManual.html#ViewGraph">set up graphviz
+ and rebuild llvm first</a>)</li>
+ <li><tt>clang-cc file.c -emit-llvm</tt> (print out unoptimized llvm code)</li>
+ <li><tt>clang-cc file.c -emit-llvm -o - | llvm-as | opt -std-compile-opts |
+ llvm-dis</tt> (print out optimized llvm code)</li>
+ <li><tt>clang-cc file.c -emit-llvm -o - | llvm-as | opt -std-compile-opts | llc
+ &gt; file.s</tt> (output native machine code)</li>
+ </ul>
+
+ <p><em>Note</em>: Here <tt>clang-cc</tt> is the "low-level" frontend
+ executable that is similar in purpose to <tt>cc1</tt>. Clang also has a <a
+ href="#driver">high-level compiler driver</a> that acts as a drop-in
+ replacement for <tt>gcc</tt>.
+</ol>
+
+<p>Note that the C front-end uses LLVM, but does not depend on llvm-gcc. If you
+encounter problems with building Clang, make sure you have the latest SVN
+version of LLVM. LLVM contains support libraries for Clang that will be updated
+as well as development on Clang progresses.</p>
+
+<h3>Simultaneously Building Clang and LLVM:</h3>
+
+<p>Once you have checked out Clang into the llvm source tree it will build along
+with the rest of <tt>llvm</tt>. To build all of LLVM and Clang together all at
+once simply run <tt>make</tt> from the root LLVM directory.</p>
+
+<p><em>Note:</em> Observe that Clang is technically part of a separate
+Subversion repository. As mentioned above, the latest Clang sources are tied to
+the latest sources in the LLVM tree. You can update your toplevel LLVM project
+and all (possibly unrelated) projects inside it with <tt><b>make
+update</b></tt>. This will run <tt>svn update</tt> on all subdirectories related
+to subversion. </p>
+
+<a name="driver"><h2>High-Level Compiler Driver (Drop-in Substitute for GCC)</h2></a>
+
+<p>While the <tt>clang-cc</tt> executable is a low-level frontend executable
+that can perform code generation, program analysis, and other actions, it is not
+designed to be a drop-in replacement for GCC's <tt>cc</tt>. For this purpose,
+use the high-level driver, aptly named <tt>clang</tt>. Here are some
+examples of how to use the high-level driver:
+</p>
+
+<pre class="code">
+$ <b>cat t.c</b>
+#include &lt;stdio.h&gt;
+int main(int argc, char **argv) { printf("hello world\n"); }
+$ <b>clang t.c</b>
+$ <b>./a.out</b>
+hello world
+</pre>
+
+<h2>Examples of using Clang</h2>
+
+<p>The high-level driver <tt>clang</tt> is designed to understand most of GCC's
+options, and the lower-level <tt>clang-cc</tt> executable also directly takes
+many of GCC's options. You can see which options <tt>clang-cc</tt> accepts with
+'<tt>clang-cc --help</tt>'. Here are a few examples of using <tt>clang</tt> and
+<tt>clang-cc</tt>:</p>
+
+<!-- Thanks to
+ http://shiflett.org/blog/2006/oct/formatting-and-highlighting-php-code-listings
+Site suggested using pre in CSS, but doesn't work in IE, so went for the <pre>
+tag. -->
+
+<pre class="code">
+$ <b>cat ~/t.c</b>
+typedef float V __attribute__((vector_size(16)));
+V foo(V a, V b) { return a+b*a; }
+</pre>
+
+
+<h3>Preprocessing:</h3>
+
+<pre class="code">
+$ <b>clang ~/t.c -E</b>
+# 1 "/Users/sabre/t.c" 1
+
+typedef float V __attribute__((vector_size(16)));
+
+V foo(V a, V b) { return a+b*a; }
+</pre>
+
+
+<h3>Type checking:</h3>
+
+<pre class="code">
+$ <b>clang -fsyntax-only ~/t.c</b>
+</pre>
+
+
+<h3>GCC options:</h3>
+
+<pre class="code">
+$ <b>clang -fsyntax-only ~/t.c -pedantic</b>
+/Users/sabre/t.c:2:17: warning: extension used
+typedef float V __attribute__((vector_size(16)));
+ ^
+1 diagnostic generated.
+</pre>
+
+
+<h3>Pretty printing from the AST:</h3>
+
+<pre class="code">
+$ <b>clang-cc ~/t.c -ast-print</b>
+typedef float V __attribute__(( vector_size(16) ));
+V foo(V a, V b) {
+ return a + b * a;
+}
+</pre>
+
+
+<h3>Code generation with LLVM:</h3>
+
+<pre class="code">
+$ <b>clang-cc ~/t.c -emit-llvm -o - | llvm-as | opt -std-compile-opts | llvm-dis</b>
+define &lt;4 x float&gt; @foo(&lt;4 x float&gt; %a, &lt;4 x float&gt; %b) {
+entry:
+ %mul = mul &lt;4 x float&gt; %b, %a
+ %add = add &lt;4 x float&gt; %mul, %a
+ ret &lt;4 x float&gt; %add
+}
+$ <b>clang-cc ~/t.c -emit-llvm -o - | llvm-as | opt -std-compile-opts | llc -march=ppc32 -mcpu=g5</b>
+..
+_foo:
+ vmaddfp v2, v3, v2, v2
+ blr
+$ <b>clang-cc ~/t.c -emit-llvm -o - | llvm-as | opt -std-compile-opts | llc -march=x86 -mcpu=yonah</b>
+..
+_foo:
+ mulps %xmm0, %xmm1
+ addps %xmm0, %xmm1
+ movaps %xmm1, %xmm0
+ ret
+</pre>
+
+</div>
+</body>
+</html>
diff --git a/www/hacking.html b/www/hacking.html
new file mode 100644
index 000000000000..db83861502ba
--- /dev/null
+++ b/www/hacking.html
@@ -0,0 +1,101 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Hacking on clang</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+</head>
+<body>
+<!--#include virtual="menu.html.incl"-->
+<div id="content">
+ <!--*********************************************************************-->
+ <h1>Hacking on Clang</h1>
+ <!--*********************************************************************-->
+
+ <p>This document provides some hints for how to get started hacking
+ on Clang for developers who are new to the Clang and/or LLVM
+ codebases.</p>
+ <ul>
+ <li><a href="#docs">Developer Documentation</a></li>
+ <li><a href="#debugging">Debugging</a></li>
+ <li><a href="#testing">Testing</a></li>
+ <li><a href="#irgen">LLVM IR Generation</a></li>
+ </ul>
+
+ <!--=====================================================================-->
+ <h2 id="docs">Developer Documentation</h2>
+ <!--=====================================================================-->
+
+ <p>Both Clang and LLVM use doxygen to provide API documentation. Their
+ respective web pages (generated nightly) are here:</p>
+ <ul>
+ <li><a href="http://clang.llvm.org/doxygen">Clang</a></li>
+ <li><a href="http://llvm.org/doxygen">LLVM</a></li>
+ </ul>
+
+ <p>For work on the LLVM IR generation, the LLVM assembly language
+ <a href="http://llvm.org/docs/LangRef.html">reference manual</a> is
+ also useful.</p>
+
+ <!--=====================================================================-->
+ <h2 id="debugging">Debugging</h2>
+ <!--=====================================================================-->
+
+ <p>Inspecting data structures in a debugger:</p>
+ <ul>
+ <li>Many LLVM and Clang data structures provide
+ a <tt>dump()</tt> method which will print a description of the
+ data structure to <tt>stderr</tt>.</li>
+ <li>The <a href="docs/InternalsManual.html#QualType"><tt>QualType</tt></a>
+ structure is used pervasively. This is a simple value class for
+ wrapping types with qualifiers; you can use
+ the <tt>isConstQualified()</tt>, for example, to get one of the
+ qualifiers, and the <tt>getTypePtr()</tt> method to get the
+ wrapped <tt>Type*</tt> which you can then dump.</li>
+ </ul>
+
+ <!--=====================================================================-->
+ <h2 id="testing">Testing</h2>
+ <!--=====================================================================-->
+
+ <p>Clang includes a basic regression suite in the tree which can be
+ run with <tt>make test</tt> from the top-level clang directory, or
+ just <tt>make</tt> in the <em>test</em> sub-directory. <tt>make
+ report</tt> can be used after running the tests to summarize the
+ results, and <tt>make VERBOSE=1</tt> can be used to show more detail
+ about what is being run.</p>
+
+ <p>The regression suite can also be run with Valgrind by running
+ <tt>make test VG=1</tt> in the top-level clang directory.</p>
+
+ <p>For more intensive changes, running
+ the <a href="http://llvm.org/docs/TestingGuide.html#testsuiterun">LLVM
+ Test Suite</a> with clang is recommended. Currently the best way to
+ override LLVMGCC, as in: <tt>make LLVMGCC="ccc -std=gnu89"
+ TEST=nightly report</tt> (make sure ccc is in your PATH or use the
+ full path).</p>
+
+ <!--=====================================================================-->
+ <h2 id="irgen">LLVM IR Generation</h2>
+ <!--=====================================================================-->
+
+ <p>The LLVM IR generation part of clang handles conversion of the
+ AST nodes output by the Sema module to the LLVM Intermediate
+ Representation (IR). Historically, this was referred to as
+ "codegen", and the Clang code for this lives
+ in <tt>lib/CodeGen</tt>.</p>
+
+ <p>The output is most easily inspected using the <tt>-emit-llvm</tt>
+ option to clang (possibly in conjunction with <tt>-o -</tt>). You
+ can also use <tt>-emit-llvm-bc</tt> to write an LLVM bitcode file
+ which can be processed by the suite of LLVM tools
+ like <tt>llvm-dis</tt>, <tt>llvm-nm</tt>, etc. See the LLVM
+ <a href="http://llvm.org/docs/CommandGuide/">Command Guide</a>
+ for more information.</p>
+
+</div>
+</body>
+</html>
diff --git a/www/index.html b/www/index.html
new file mode 100644
index 000000000000..776c72962260
--- /dev/null
+++ b/www/index.html
@@ -0,0 +1,117 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>"clang" C Language Family Frontend for LLVM</title>
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
+</head>
+<body>
+<!--#include virtual="menu.html.incl"-->
+<div id="content">
+ <!--*********************************************************************-->
+ <h1>clang: a C language family frontend for LLVM</h1>
+ <!--*********************************************************************-->
+
+ <p>The goal of the Clang project is to create a new C, C++, Objective C and
+ Objective C++ front-end for the <a href="http://www.llvm.org/">LLVM</a>
+ compiler. You can <a href="get_started.html">get and build</a> the source
+ today.</p>
+
+ <!--=====================================================================-->
+ <h2 id="goals">Features and Goals</h2>
+ <!--=====================================================================-->
+
+ <p>Some of the goals for the project include the following:</p>
+
+ <p><b><a href="features.html#enduser">End-User Features</a></b>:</p>
+
+ <ul>
+ <li>Fast compiles and low memory use</li>
+ <li>Expressive diagnostics (<a href="diagnostics.html">examples</a>)</li>
+ <li>GCC compatibility</li>
+ </ul>
+
+ <p><b><a href="features.html#applications">Utility and
+ Applications</a></b>:</p>
+
+ <ul>
+ <li>Modular library based architecture</li>
+ <li>Support diverse clients (refactoring, static analysis, code generation,
+ etc)</li>
+ <li>Allow tight integration with IDEs</li>
+ <li>Use the LLVM 'BSD' License</li>
+ </ul>
+
+ <p><b><a href="features.html#design">Internal Design and
+ Implementation</a></b>:</p>
+
+ <ul>
+ <li>A real-world, production quality compiler</li>
+ <li>A simple and hackable code base</li>
+ <li>A single unified parser for C, Objective C, C++, and Objective C++</li>
+ <li>Conformance with C/C++/ObjC and their variants</li>
+ </ul>
+
+ <p>Of course this is only a rough outline of the goals and features of
+ Clang. To get a true sense of what it is all about, see the <a
+ href="features.html">Features</a> section, which breaks
+ each of these down and explains them in more detail.</p>
+
+
+ <!--=====================================================================-->
+ <h2>Why?</h2>
+ <!--=====================================================================-->
+
+ <p>The development of a new front-end was started out of a need -- a need
+ for a compiler that allows better diagnostics, better integration with
+ IDEs, a license that is compatible with commercial products, and a
+ nimble compiler that is easy to develop and maintain. All of these were
+ motivations for starting work on a new front-end that could
+ meet these needs.</p>
+
+ <p>A good (but quite dated) introduction to Clang can be found in the
+ following video lectures:</p>
+
+ <ul>
+ <li><a href="clang_video-05-25-2007.html">Clang Introduction</a>
+ (May 2007)</li>
+ <li><a href="clang_video-07-25-2007.html">Features and Performance of
+ Clang</a> (July 2007)</li>
+ </ul>
+
+ <p>For a more detailed comparison between Clang and other compilers, please
+ see the <a href="comparison.html">clang comparison page</a>.</p>
+
+ <!--=====================================================================-->
+ <h2>Current Status</h2>
+ <!--=====================================================================-->
+
+ <p>Clang is still under heavy development. Clang is considered to be
+ a production quality C and Objective-C compiler when targetting X86-32 and X86-64
+ (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. If you are interested in C++,
+ <a href="cxx_status.html">full support</a> is still way off.</p>
+
+ <!--=====================================================================-->
+ <h2>Get it and get involved!</h2>
+ <!--=====================================================================-->
+
+ <p>Start by <a href="get_started.html">getting the code, building it, and
+ playing with it</a>. This will show you the sorts of things we can do
+ today and will let you have the "clang experience" first hand: hopefully
+ it will "resonate" with you. :)</p>
+
+ <p>Once you've done that, please consider <a href="get_involved.html">getting
+ involved in the clang community</a>. The clang developers include numerous
+ volunteer contributors with a variety of backgrounds. If you're
+ interested in
+ following the development of clang, signing up for a mailing list is a good
+ way to learn about how the project works.</p>
+</div>
+</body>
+</html>
diff --git a/www/latest_checker.html.incl b/www/latest_checker.html.incl
new file mode 100644
index 000000000000..90d444a40ba1
--- /dev/null
+++ b/www/latest_checker.html.incl
@@ -0,0 +1 @@
+<b><a href="http://checker.minormatter.com/checker-0.209.tar.bz2">checker-0.209.tar.bz2</a></b> (built May 18, 2009)
diff --git a/www/menu.css b/www/menu.css
new file mode 100644
index 000000000000..6e96a457ab53
--- /dev/null
+++ b/www/menu.css
@@ -0,0 +1,39 @@
+/***************/
+/* page layout */
+/***************/
+
+[id=menu] {
+ position:fixed;
+ width:25ex;
+}
+[id=content] {
+ /* ***** EDIT THIS VALUE IF CONTENT OVERLAPS MENU ***** */
+ position:absolute;
+ left:29ex;
+ padding-right:4ex;
+}
+
+/**************/
+/* menu style */
+/**************/
+
+#menu .submenu {
+ padding-top:1em;
+ display:block;
+}
+
+#menu label {
+ display:block;
+ font-weight: bold;
+ text-align: center;
+ background-color: rgb(192,192,192);
+}
+#menu a {
+ padding:0 .2em;
+ display:block;
+ text-align: center;
+ background-color: rgb(235,235,235);
+}
+#menu a:visited {
+ color:rgb(100,50,100);
+} \ No newline at end of file
diff --git a/www/menu.html.incl b/www/menu.html.incl
new file mode 100644
index 000000000000..ab3bf1dcf399
--- /dev/null
+++ b/www/menu.html.incl
@@ -0,0 +1,43 @@
+<div id="menu">
+ <div>
+ <a href="http://llvm.org/">LLVM Home</a>
+ </div>
+
+ <div class="submenu">
+ <label>Clang Info</label>
+ <a href="/index.html">About</a>
+ <a href="/features.html">Features</a>
+ <a href="/comparison.html">Comparisons</a>
+ <a href="/get_started.html">Get&nbsp;Started</a>
+ <a href="/get_involved.html">Get&nbsp;Involved</a>
+ <a href="/OpenProjects.html">Open&nbsp;Projects</a>
+ <a href="/cxx_status.html">C++ Status</a>
+ <a href="/docs/LanguageExtensions.html">Language&nbsp;Extensions</a>
+ <a href="/docs/InternalsManual.html">Clang&nbsp;Internals</a>
+ <a href="/hacking.html">Hacking on Clang</a>
+ <a href="/performance.html">Performance</a>
+ </div>
+
+ <div class="submenu">
+ <label>Clang Tools</label>
+ <a href="/StaticAnalysis.html">Automatic Bug-Finding</a>
+ </div>
+
+ <div class="submenu">
+ <label>Quick Links</label>
+ <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev">cfe-dev</a>
+ <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits">cfe-commits</a>
+ <a href="http://llvm.org/bugs/">Bug Reports</a>
+ <a href="http://llvm.org/svn/llvm-project/cfe/trunk/">Browse SVN</a>
+ <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/">Browse ViewVC</a>
+ <a href="http://clang.llvm.org/doxygen/">doxygen</a>
+ <a href="http://t1.minormatter.com/~ddunbar/references.html">Spec. References</a>
+ <a href="http://t1.minormatter.com/~ddunbar/clang-cov/">Testing Coverage</a>
+ </div>
+
+ <div class="submenu">
+ <label>Events</label>
+ <a href="http://llvm.org/devmtg/">August 1, 2008 - LLVM/Clang Developer Meeting</a>
+ </div>
+
+</div>
diff --git a/www/performance-2008-10-31.html b/www/performance-2008-10-31.html
new file mode 100644
index 000000000000..5246ac30b857
--- /dev/null
+++ b/www/performance-2008-10-31.html
@@ -0,0 +1,134 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Clang - Performance</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+ <style type="text/css">
+</style>
+</head>
+<body>
+
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<!--*************************************************************************-->
+<h1>Clang - Performance</h1>
+<!--*************************************************************************-->
+
+<p>This page tracks the compile time performance of Clang on two
+interesting benchmarks:
+<ul>
+ <li><i>Sketch</i>: The Objective-C example application shipped on
+ Mac OS X as part of Xcode. <i>Sketch</i> is indicative of a
+ "typical" Objective-C app. The source itself has a relatively
+ small amount of code (~7,500 lines of source code), but it relies
+ on the extensive Cocoa APIs to build its functionality. Like many
+ Objective-C applications, it includes
+ <tt>Cocoa/Cocoa.h</tt> in all of its source files, which represents a
+ significant stress test of the front-end's performance on lexing,
+ preprocessing, parsing, and syntax analysis.</li>
+ <li><i>176.gcc</i>: This is the gcc-2.7.2.2 code base as present in
+ SPECINT 2000. In contrast to Sketch, <i>176.gcc</i> consists of a
+ large amount of C source code (~220,000 lines) with few system
+ dependencies. This stresses the back-end's performance on generating
+ assembly code and debug information.</li>
+</ul>
+</p>
+
+<!--*************************************************************************-->
+<h2><a name="enduser">Experiments</a></h2>
+<!--*************************************************************************-->
+
+<p>Measurements are done by serially processing each file in the
+respective benchmark, using Clang, gcc, and llvm-gcc as compilers. In
+order to track the performance of various subsystems the timings have
+been broken down into separate stages where possible:
+
+<ul>
+ <li><tt>-Eonly</tt>: This option runs the preprocessor but does not
+ perform any output. For gcc and llvm-gcc, the -MM option is used
+ as a rough equivalent to this step.</li>
+ <li><tt>-parse-noop</tt>: This option runs the parser on the input,
+ but without semantic analysis or any output. gcc and llvm-gcc have
+ no equivalent for this option.</li>
+ <li><tt>-fsyntax-only</tt>: This option runs the parser with semantic
+ analysis.</li>
+ <li><tt>-emit-llvm -O0</tt>: For Clang and llvm-gcc, this option
+ converts to the LLVM intermediate representation but doesn't
+ generate native code.</li>
+ <li><tt>-S -O0</tt>: Perform actual code generation to produce a
+ native assembler file.</li>
+ <li><tt>-S -O0 -g</tt>: This adds emission of debug information to
+ the assembly output.</li>
+</ul>
+</p>
+
+<p>This set of stages is chosen to be approximately additive, that is
+each subsequent stage simply adds some additional processing. The
+timings measure the delta of the given stage from the previous
+one. For example, the timings for <tt>-fsyntax-only</tt> below show
+the difference of running with <tt>-fsyntax-only</tt> versus running
+with <tt>-parse-noop</tt> (for clang) or <tt>-MM</tt> with gcc and
+llvm-gcc. This amounts to a fairly accurate measure of only the time
+to perform semantic analysis (and parsing, in the case of gcc and llvm-gcc).</p>
+
+<p>These timings are chosen to break down the compilation process for
+clang as much as possible. The graphs below show these numbers
+combined so that it is easy to see how the time for a particular task
+is divided among various components. For example, <tt>-S -O0</tt>
+includes the time of <tt>-fsyntax-only</tt> and <tt>-emit-llvm -O0</tt>.</p>
+
+<p>Note that we already know that the LLVM optimizers are substantially (30-40%)
+faster than the GCC optimizers at a given -O level, so we only focus on -O0
+compile time here.</p>
+
+<!--*************************************************************************-->
+<h2><a name="enduser">Timing Results</a></h2>
+<!--*************************************************************************-->
+
+<!--=======================================================================-->
+<h3><a name="2008-10-31">2008-10-31</a></h3>
+<!--=======================================================================-->
+
+<center><h4>Sketch</h4></center>
+<img class="img_slide"
+ src="timing-data/2008-10-31/sketch.png" alt="Sketch Timings"/>
+
+<p>This shows Clang's substantial performance improvements in
+preprocessing and semantic analysis; over 90% faster on
+-fsyntax-only. As expected, time spent in code generation for this
+benchmark is relatively small. One caveat, Clang's debug information
+generation for Objective-C is very incomplete; this means the <tt>-S
+-O0 -g</tt> numbers are unfair since Clang is generating substantially
+less output.</p>
+
+<p>This chart also shows the effect of using precompiled headers (PCH)
+on compiler time. gcc and llvm-gcc see a large performance improvement
+with PCH; about 4x in wall time. Unfortunately, Clang does not yet
+have an implementation of PCH-style optimizations, but we are actively
+working to address this.</p>
+
+<center><h4>176.gcc</h4></center>
+<img class="img_slide"
+ src="timing-data/2008-10-31/176.gcc.png" alt="176.gcc Timings"/>
+
+<p>Unlike the <i>Sketch</i> timings, compilation of <i>176.gcc</i>
+involves a large amount of code generation. The time spent in Clang's
+LLVM IR generation and code generation is on par with gcc's code
+generation time but the improved parsing & semantic analysis
+performance means Clang still comes in at ~29% faster versus gcc
+on <tt>-S -O0 -g</tt> and ~20% faster versus llvm-gcc.</p>
+
+<p>These numbers indicate that Clang still has room for improvement in
+several areas, notably our LLVM IR generation is significantly slower
+than that of llvm-gcc, and both Clang and llvm-gcc incur a
+significantly higher cost for adding debugging information compared to
+gcc.</p>
+
+</div>
+</body>
+</html>
diff --git a/www/performance.html b/www/performance.html
new file mode 100644
index 000000000000..f76fc7a0094d
--- /dev/null
+++ b/www/performance.html
@@ -0,0 +1,112 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Clang - Performance</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+ <style type="text/css">
+</style>
+</head>
+<body>
+
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<!--*************************************************************************-->
+<h1>Clang - Performance</h1>
+<!--*************************************************************************-->
+
+<p>This page shows the compile time performance of Clang on two
+interesting benchmarks:
+<ul>
+ <li><i>Sketch</i>: The Objective-C example application shipped on
+ Mac OS X as part of Xcode. <i>Sketch</i> is indicative of a
+ "typical" Objective-C app. The source itself has a relatively
+ small amount of code (~7,500 lines of source code), but it relies
+ on the extensive Cocoa APIs to build its functionality. Like many
+ Objective-C applications, it includes <tt>Cocoa/Cocoa.h</tt> in
+ all of its source files, which represents a significant stress
+ test of the front-end's performance on lexing, preprocessing,
+ parsing, and syntax analysis.</li>
+ <li><i>176.gcc</i>: This is the gcc-2.7.2.2 code base as present in
+ SPECINT 2000. In contrast to Sketch, <i>176.gcc</i> consists of a
+ large amount of C source code (~200,000 lines) with few system
+ dependencies. This stresses the back-end's performance on generating
+ assembly code and debug information.</li>
+</ul>
+</p>
+
+<p>
+For previous performance numbers, please
+go <a href="performance-2008-10-31.html">here</a>.
+</p>
+
+<!--*************************************************************************-->
+<h2><a name="experiments">Experiments</a></h2>
+<!--*************************************************************************-->
+
+<p>Measurements are done by running a full build (using xcodebuild or
+make for Sketch and 176.gcc respectively) using Clang and gcc 4.2 as
+compilers; gcc is run both with and without the new clang driver (ccc)
+in order to evaluate the overhead of the driver itself.</p>
+
+<p>In order to track the performance of various subsystems the timings
+have been broken down into separate stages where possible. This is
+done by over-riding the CC environment variable used during the build
+to point to one of a few simple shell scripts which may skip part of
+the build.
+
+<ul>
+ <li><tt>non-compiler</tt>: The overhead of the build system itself;
+ for Sketch this also includes the time to build/copy various
+ non-source code resource files.</li>
+ <li><tt>+ driver</tt>: Add execution of the driver, but do not execute any
+ commands (by using the -### driver option).</li>
+ <li><tt>+ pch gen</tt>: Add generation of PCH files.</li>
+ <li><tt>+ cpp</tt>: Add preprocessing of source files (this time is
+ include in syntax for gcc).</li>
+ <li><tt>+ parse</tt>: Add parsing of source files (this time is
+ include in syntax for gcc).</li>
+ <li><tt>+ syntax</tt>: Add semantic checking of source files (for
+ gcc, this includes preprocessing and parsing as well).</li>
+ <li><tt>+ IRgen</tt>: Add generation of LLVM IR (gcc has no
+ corresponding phase).</li>
+ <li><tt>+ codegen</tt>: Add generation of assembler files.</li>
+ <li><tt>+ assembler</tt>: Add assembler time to generate .o files.</li>
+ <li><tt>+ linker</tt>: Add linker time.</li>
+</ul>
+</p>
+
+<p>This set of stages is chosen to be approximately additive, that is
+each subsequent stage simply adds some additional processing. The
+timings measure the delta of the given stage from the previous
+one. For example, the timings for <tt>+ syntax</tt> below show the
+difference of running with <tt>+ syntax</tt> versus running with <tt>+
+parse</tt> (for clang) or <tt>+ driver</tt> with gcc. This amounts to
+a fairly accurate measure of only the time to perform semantic
+analysis (and preprocessing/parsing, in the case of gcc).</p>
+
+<!--*************************************************************************-->
+<h2><a name="timings">Timing Results</a></h2>
+<!--*************************************************************************-->
+
+<!--=======================================================================-->
+<h3><a name="2009-03-02">2009-03-02</a></h3>
+<!--=======================================================================-->
+
+<a href="timing-data/2009-03-02/sketch.pdf">
+<img class="img_slide"
+ src="timing-data/2009-03-02/sketch.png" alt="Sketch Timings"/>
+</a>
+
+<a href="timing-data/2009-03-02/176.gcc.pdf">
+<img class="img_slide"
+ src="timing-data/2009-03-02/176.gcc.png" alt="176.gcc Timings"/>
+</a>
+
+</div>
+</body>
+</html>
diff --git a/www/timing-data/2008-10-31/176.gcc-01.txt b/www/timing-data/2008-10-31/176.gcc-01.txt
new file mode 100644
index 000000000000..3809e0d3b299
--- /dev/null
+++ b/www/timing-data/2008-10-31/176.gcc-01.txt
@@ -0,0 +1,135 @@
+Title: 176.gcc Timings
+Timestamp: 2008-10-31_17-10
+Uname: Darwin lordcrumb.apple.com 10.0.0d3 Darwin Kernel Version 10.0.0d3: Fri Oct 24 02:12:11 PDT 2008; root:xnu-1353~2/RELEASE_I386 i386
+Path: /Users/ddunbar/nightlytest/176.gcc
+Runs: 3
+
+LLVM SVN Rev.: 58536
+
+clang: /Users/ddunbar/llvm/Release-Asserts/bin//clang
+gcc: /usr/bin/gcc-4.2
+llvm-gcc: /Users/ddunbar/llvm-gcc/install/bin/llvm-gcc
+
+Mode: Eonly Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 0.8321 0.8274 0.8274 0.8435 0.0080 2.4964
+ sys 0.4209 0.4140 0.4140 0.4307 0.0071 1.2626
+wall 1.2965 1.2829 1.2829 1.3176 0.0152 3.8894
+
+Mode: Eonly Compiler: gcc PCH: 0 Flags:
+name avg min med max SD total
+user 0.8534 0.8465 0.8563 0.8575 0.0050 2.5603
+ sys 0.5327 0.5200 0.5291 0.5490 0.0121 1.5980
+wall 1.4336 1.4104 1.4330 1.4575 0.0192 4.3009
+
+Mode: Eonly Compiler: llvm-gcc PCH: 0 Flags:
+name avg min med max SD total
+user 1.1313 1.1277 1.1304 1.1359 0.0034 3.3940
+ sys 0.5579 0.5530 0.5539 0.5669 0.0063 1.6738
+wall 1.7860 1.7669 1.7890 1.8020 0.0145 5.3580
+
+
+Mode: parse-noop Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 0.9276 0.9267 0.9269 0.9292 0.0011 2.7827
+ sys 0.4284 0.4244 0.4255 0.4353 0.0049 1.2852
+wall 1.3994 1.3941 1.3954 1.4086 0.0066 4.1981
+
+
+Mode: disable-free Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 1.2716 1.2497 1.2713 1.2937 0.0180 3.8147
+ sys 0.4835 0.4815 0.4738 0.4953 0.0089 1.4506
+wall 1.8149 1.7838 1.8137 1.8471 0.0259 5.4446
+
+
+Mode: syntax Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 1.4042 1.4031 1.4044 1.4044 0.0009 4.2127
+ sys 0.4818 0.4802 0.4838 0.4838 0.0015 1.4454
+wall 1.9359 1.9333 1.9376 1.9376 0.0019 5.8077
+
+Mode: syntax Compiler: gcc PCH: 0 Flags:
+name avg min med max SD total
+user 3.9188 3.8766 3.8846 3.9951 0.0541 11.7563
+ sys 1.0207 1.0195 1.0141 1.0285 0.0059 3.0622
+wall 5.0500 5.0023 5.0092 5.1386 0.0627 15.1500
+
+Mode: syntax Compiler: llvm-gcc PCH: 0 Flags:
+name avg min med max SD total
+user 3.8854 3.8647 3.8868 3.9048 0.0164 11.6563
+ sys 0.8548 0.8436 0.8455 0.8753 0.0145 2.5644
+wall 4.8695 4.8369 4.8614 4.9103 0.0305 14.6086
+
+
+Mode: llvm Compiler: clang PCH: 0 Flags: -O0
+name avg min med max SD total
+user 2.7903 2.7606 2.8026 2.8079 0.0211 8.3710
+ sys 0.6645 0.6509 0.6759 0.6667 0.0104 1.9935
+wall 3.5577 3.4894 3.5650 3.6186 0.0530 10.6730
+
+Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0
+name avg min med max SD total
+user 4.1711 4.1389 4.1729 4.2015 0.0256 12.5133
+ sys 0.9335 0.9339 0.9218 0.9448 0.0094 2.8004
+wall 5.2380 5.1985 5.2417 5.2738 0.0309 15.7140
+
+
+Mode: asm Compiler: clang PCH: 0 Flags: -O0
+name avg min med max SD total
+user 5.2797 5.1709 5.2643 5.4040 0.0958 15.8392
+ sys 0.7739 0.7547 0.7726 0.7944 0.0162 2.3217
+wall 6.1807 6.1082 6.1174 6.3165 0.0961 18.5421
+ Asm Lines: 735931
+
+Mode: asm Compiler: gcc PCH: 0 Flags: -O0
+name avg min med max SD total
+user 8.2410 8.1034 8.2230 8.3965 0.1203 24.7230
+ sys 1.1924 1.1576 1.2112 1.2082 0.0246 3.5771
+wall 9.6010 9.3792 9.6800 9.7438 0.1590 28.8030
+ Asm Lines: 514962
+
+Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0
+name avg min med max SD total
+user 6.3978 6.3894 6.3894 6.4726 0.0579 19.1935
+ sys 1.0638 1.0562 1.0562 1.0861 0.0160 3.1914
+wall 7.6185 7.5807 7.5807 7.6876 0.0489 22.8555
+ Asm Lines: 597193
+
+
+Mode: llvm Compiler: clang PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 3.9798 3.9728 3.9752 3.9914 0.0083 11.9393
+ sys 0.7313 0.7260 0.7326 0.7353 0.0039 2.1938
+wall 4.7915 4.7799 4.7878 4.8066 0.0112 14.3744
+
+Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 5.4838 5.4701 5.4701 5.5172 0.0238 16.4513
+ sys 1.0527 1.0401 1.0401 1.0757 0.0163 3.1581
+wall 6.7059 6.6768 6.6768 6.7254 0.0210 20.1177
+
+
+Mode: asm Compiler: clang PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 6.8213 6.7836 6.8060 6.8743 0.0386 20.4639
+ sys 0.8527 0.8376 0.8598 0.8607 0.0107 2.5582
+wall 7.8055 7.7154 7.8109 7.8902 0.0714 23.4165
+ Asm Lines: 1581804
+
+Mode: asm Compiler: gcc PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 8.7962 8.6334 8.7861 8.9691 0.1373 26.3887
+ sys 1.2758 1.2395 1.2780 1.3100 0.0288 3.8275
+wall 10.2714 10.1274 10.2232 10.4635 0.1414 30.8142
+ Asm Lines: 1403421
+
+Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 7.9903 7.9383 7.9821 8.0504 0.0461 23.9708
+ sys 1.1587 1.1374 1.1592 1.1794 0.0171 3.4760
+wall 9.3711 9.2555 9.2884 9.5692 0.1408 28.1132
+ Asm Lines: 1580849
+
+
+ Done: 2008-10-31_17-16
diff --git a/www/timing-data/2008-10-31/176.gcc-02.txt b/www/timing-data/2008-10-31/176.gcc-02.txt
new file mode 100644
index 000000000000..dd898c181068
--- /dev/null
+++ b/www/timing-data/2008-10-31/176.gcc-02.txt
@@ -0,0 +1,135 @@
+Title: 176.gcc Timings
+Timestamp: 2008-10-31_17-17
+Uname: Darwin lordcrumb.apple.com 10.0.0d3 Darwin Kernel Version 10.0.0d3: Fri Oct 24 02:12:11 PDT 2008; root:xnu-1353~2/RELEASE_I386 i386
+Path: /Users/ddunbar/nightlytest/176.gcc
+Runs: 3
+
+LLVM SVN Rev.: 58536
+
+clang: /Users/ddunbar/llvm/Release-Asserts/bin//clang
+gcc: /usr/bin/gcc-4.2
+llvm-gcc: /Users/ddunbar/llvm-gcc/install/bin/llvm-gcc
+
+Mode: Eonly Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 0.8238 0.8184 0.8187 0.8342 0.0074 2.4713
+ sys 0.4030 0.3891 0.3953 0.4247 0.0155 1.2091
+wall 1.2731 1.2477 1.2565 1.3152 0.0299 3.8194
+
+Mode: Eonly Compiler: gcc PCH: 0 Flags:
+name avg min med max SD total
+user 0.8584 0.8501 0.8560 0.8692 0.0080 2.5753
+ sys 0.5426 0.5268 0.5453 0.5556 0.0119 1.6277
+wall 1.4485 1.4214 1.4503 1.4737 0.0214 4.3454
+
+Mode: Eonly Compiler: llvm-gcc PCH: 0 Flags:
+name avg min med max SD total
+user 1.1289 1.1338 1.1322 1.1207 0.0058 3.3866
+ sys 0.5857 0.5787 0.5734 0.6051 0.0138 1.7572
+wall 1.8195 1.8110 1.8124 1.8350 0.0110 5.4585
+
+
+Mode: parse-noop Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 0.9286 0.9250 0.9250 0.9370 0.0059 2.7859
+ sys 0.4255 0.4163 0.4163 0.4417 0.0115 1.2764
+wall 1.3970 1.3826 1.3826 1.4241 0.0192 4.1910
+
+
+Mode: disable-free Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 1.2962 1.2963 1.2963 1.3114 0.0125 3.8885
+ sys 0.4842 0.4864 0.4864 0.4901 0.0059 1.4527
+wall 1.8424 1.8356 1.8356 1.8534 0.0078 5.5273
+
+
+Mode: syntax Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 1.4120 1.4055 1.4118 1.4188 0.0054 4.2360
+ sys 0.4824 0.4786 0.4821 0.4864 0.0032 1.4471
+wall 1.9573 1.9467 1.9570 1.9682 0.0088 5.8719
+
+Mode: syntax Compiler: gcc PCH: 0 Flags:
+name avg min med max SD total
+user 3.9243 3.8431 3.9624 3.9675 0.0575 11.7730
+ sys 1.0094 0.9967 1.0135 1.0180 0.0091 3.0282
+wall 5.0495 4.9447 5.1012 5.1025 0.0741 15.1484
+
+Mode: syntax Compiler: llvm-gcc PCH: 0 Flags:
+name avg min med max SD total
+user 3.9287 3.8760 3.9226 3.9874 0.0457 11.7860
+ sys 0.8949 0.8684 0.9014 0.9147 0.0195 2.6846
+wall 4.9625 4.8722 4.9601 5.0550 0.0747 14.8874
+
+
+Mode: llvm Compiler: clang PCH: 0 Flags: -O0
+name avg min med max SD total
+user 2.8082 2.7806 2.8106 2.8334 0.0216 8.4246
+ sys 0.6608 0.6564 0.6582 0.6677 0.0049 1.9823
+wall 3.5453 3.5150 3.5559 3.5650 0.0218 10.6359
+
+Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0
+name avg min med max SD total
+user 4.1471 4.1512 4.1505 4.1395 0.0053 12.4413
+ sys 0.9221 0.9069 0.9203 0.9391 0.0132 2.7663
+wall 5.2138 5.1919 5.2001 5.2495 0.0255 15.6415
+
+
+Mode: asm Compiler: clang PCH: 0 Flags: -O0
+name avg min med max SD total
+user 5.1674 5.1537 5.1637 5.1637 0.0129 15.5022
+ sys 0.7424 0.7404 0.7376 0.7376 0.0049 2.2271
+wall 6.0284 5.9844 6.0964 6.0964 0.0487 18.0852
+ Asm Lines: 735931
+
+Mode: asm Compiler: gcc PCH: 0 Flags: -O0
+name avg min med max SD total
+user 8.0945 8.0259 8.1235 8.1342 0.0487 24.2835
+ sys 1.1599 1.1517 1.1626 1.1654 0.0059 3.4796
+wall 9.4120 9.2935 9.4036 9.5390 0.1004 28.2361
+ Asm Lines: 514962
+
+Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0
+name avg min med max SD total
+user 6.4405 6.3577 6.4623 6.5014 0.0607 19.3214
+ sys 1.0571 1.0454 1.0359 1.0902 0.0237 3.1714
+wall 7.6688 7.5631 7.6376 7.8058 0.1015 23.0065
+ Asm Lines: 597193
+
+
+Mode: llvm Compiler: clang PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 3.9883 3.9539 3.9626 4.0485 0.0427 11.9650
+ sys 0.7333 0.7209 0.7377 0.7413 0.0089 2.1998
+wall 4.8088 4.7485 4.7821 4.8957 0.0630 14.4263
+
+Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 5.4875 5.4528 5.5017 5.5017 0.0247 16.4626
+ sys 1.0308 1.0231 1.0248 1.0248 0.0097 3.0923
+wall 6.6781 6.6372 6.7006 6.7006 0.0290 20.0342
+
+
+Mode: asm Compiler: clang PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 6.7945 6.6664 6.7352 6.9819 0.1355 20.3835
+ sys 0.8359 0.8172 0.8329 0.8577 0.0167 2.5077
+wall 7.7458 7.6003 7.7080 7.9290 0.1368 23.2374
+ Asm Lines: 1581804
+
+Mode: asm Compiler: gcc PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 8.7280 8.6884 8.7084 8.7870 0.0426 26.1839
+ sys 1.3031 1.2940 1.3118 1.3037 0.0073 3.9094
+wall 10.2039 10.1039 10.1162 10.3916 0.1328 30.6116
+ Asm Lines: 1403421
+
+Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 7.9987 7.9805 7.9805 8.0493 0.0362 23.9962
+ sys 1.1561 1.1523 1.1523 1.1626 0.0047 3.4682
+wall 9.3154 9.2801 9.2801 9.3606 0.0336 27.9463
+ Asm Lines: 1580849
+
+
+ Done: 2008-10-31_17-23
diff --git a/www/timing-data/2008-10-31/176.gcc.png b/www/timing-data/2008-10-31/176.gcc.png
new file mode 100644
index 000000000000..53efd879312b
--- /dev/null
+++ b/www/timing-data/2008-10-31/176.gcc.png
Binary files differ
diff --git a/www/timing-data/2008-10-31/sketch-01.txt b/www/timing-data/2008-10-31/sketch-01.txt
new file mode 100644
index 000000000000..ff5d83e1281b
--- /dev/null
+++ b/www/timing-data/2008-10-31/sketch-01.txt
@@ -0,0 +1,187 @@
+Title: Sketch Timings
+Timestamp: 2008-10-31_16-46
+Uname: Darwin lordcrumb.apple.com 10.0.0d3 Darwin Kernel Version 10.0.0d3: Fri Oct 24 02:12:11 PDT 2008; root:xnu-1353~2/RELEASE_I386 i386
+Path: /Users/ddunbar/nightlytest/Sketch.ref
+Runs: 3
+
+LLVM SVN Rev.: 58536
+
+clang: /Users/ddunbar/llvm/Release-Asserts/bin//clang
+gcc: /usr/bin/gcc-4.2
+llvm-gcc: /Users/ddunbar/llvm-gcc/install/bin/llvm-gcc
+
+Mode: Eonly Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 1.3762 1.3711 1.3724 1.3849 0.0062 4.1285
+ sys 0.8306 0.8276 0.8274 0.8367 0.0044 2.4917
+wall 2.2290 2.2207 2.2219 2.2445 0.0109 6.6870
+
+Mode: Eonly Compiler: gcc PCH: 0 Flags:
+name avg min med max SD total
+user 2.2970 2.2352 2.2374 2.4184 0.0858 6.8910
+ sys 1.0716 1.0338 1.0342 1.1470 0.0533 3.2149
+wall 3.4039 3.3027 3.3046 3.6043 0.1417 10.2116
+
+Mode: Eonly Compiler: llvm-gcc PCH: 0 Flags:
+name avg min med max SD total
+user 2.8472 2.7770 2.7770 2.9893 0.1005 8.5416
+ sys 1.3153 1.2699 1.2699 1.4079 0.0655 3.9460
+wall 4.2134 4.0909 4.0909 4.4421 0.1618 12.6403
+
+
+Mode: parse-noop Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 1.7295 1.7228 1.7237 1.7421 0.0089 5.1886
+ sys 0.8510 0.8468 0.8448 0.8615 0.0074 2.5530
+wall 2.6034 2.5913 2.5914 2.6277 0.0172 7.8103
+
+
+Mode: disable-free Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 2.7310 2.7274 2.7288 2.7288 0.0042 8.1930
+ sys 0.9950 0.9890 0.9917 0.9917 0.0068 2.9851
+wall 3.7720 3.7515 3.7866 3.7866 0.0150 11.3161
+
+
+Mode: syntax Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 3.1817 3.1284 3.1620 3.2547 0.0534 9.5451
+ sys 1.0815 1.0569 1.0737 1.1138 0.0239 3.2444
+wall 4.2918 4.2129 4.2635 4.3991 0.0786 12.8755
+
+Mode: syntax Compiler: gcc PCH: 0 Flags:
+name avg min med max SD total
+user 6.4086 6.3289 6.4012 6.4956 0.0682 19.2258
+ sys 1.7617 1.7257 1.7615 1.7979 0.0295 5.2851
+wall 8.2403 8.1235 8.2432 8.3541 0.0942 24.7208
+
+Mode: syntax Compiler: llvm-gcc PCH: 0 Flags:
+name avg min med max SD total
+user 6.9711 6.8657 6.9738 7.0739 0.0850 20.9133
+ sys 1.7577 1.7226 1.7801 1.7702 0.0251 5.2730
+wall 8.8020 8.6601 8.8243 8.9216 0.1079 26.4061
+
+Mode: syntax Compiler: gcc PCH: 1 Flags:
+name avg min med max SD total
+user 0.6082 0.6078 0.6083 0.6085 0.0003 1.8245
+ sys 0.8901 0.8826 0.8949 0.8927 0.0053 2.6702
+wall 1.5593 1.5558 1.5605 1.5617 0.0025 4.6780
+
+Mode: syntax Compiler: llvm-gcc PCH: 1 Flags:
+name avg min med max SD total
+user 0.6413 0.6409 0.6409 0.6407 0.0008 1.9240
+ sys 0.7872 0.7805 0.7805 0.7954 0.0062 2.3615
+wall 1.4837 1.4760 1.4760 1.4877 0.0054 4.4510
+
+
+Mode: llvm Compiler: clang PCH: 0 Flags: -O0
+name avg min med max SD total
+user 3.3512 3.2800 3.3205 3.4530 0.0739 10.0535
+ sys 1.0991 1.0690 1.0833 1.1450 0.0330 3.2974
+wall 4.4934 4.4015 4.4394 4.6392 0.1043 13.4801
+
+Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0
+name avg min med max SD total
+user 7.1104 7.0581 7.1061 7.1670 0.0446 21.3311
+ sys 1.7621 1.7462 1.7556 1.7845 0.0163 5.2863
+wall 8.9510 8.8993 8.9352 9.0187 0.0500 26.8531
+
+Mode: llvm Compiler: llvm-gcc PCH: 1 Flags: -O0
+name avg min med max SD total
+user 0.8446 0.8300 0.8499 0.8538 0.0104 2.5338
+ sys 0.8742 0.8366 0.8861 0.9000 0.0272 2.6227
+wall 1.7871 1.7366 1.8046 1.8201 0.0362 5.3613
+
+
+Mode: asm Compiler: clang PCH: 0 Flags: -O0
+name avg min med max SD total
+user 3.4794 3.4750 3.4794 3.4794 0.0035 10.4381
+ sys 1.0876 1.0817 1.0874 1.0874 0.0049 3.2628
+wall 4.6112 4.5958 4.6223 4.6223 0.0112 13.8337
+ Asm Lines: 46279
+
+Mode: asm Compiler: gcc PCH: 0 Flags: -O0
+name avg min med max SD total
+user 6.8875 6.7735 6.8748 7.0143 0.0987 20.6626
+ sys 1.8035 1.7586 1.8049 1.8472 0.0362 5.4106
+wall 8.7785 8.6100 8.7574 8.9682 0.1470 26.3356
+ Asm Lines: 41008
+
+Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0
+name avg min med max SD total
+user 7.3392 7.2327 7.3071 7.4779 0.1026 22.0176
+ sys 1.8018 1.7703 1.7930 1.8420 0.0299 5.4053
+wall 9.2274 9.0793 9.1968 9.4062 0.1352 27.6823
+ Asm Lines: 47243
+
+Mode: asm Compiler: gcc PCH: 1 Flags: -O0
+name avg min med max SD total
+user 1.0485 1.0361 1.0429 1.0666 0.0131 3.1456
+ sys 1.0277 1.0097 1.0437 1.0296 0.0140 3.0830
+wall 2.1621 2.1181 2.1496 2.2185 0.0419 6.4862
+ Asm Lines: 41001
+
+Mode: asm Compiler: llvm-gcc PCH: 1 Flags: -O0
+name avg min med max SD total
+user 0.9927 0.9898 0.9932 0.9951 0.0022 2.9781
+ sys 0.8640 0.8529 0.8610 0.8781 0.0105 2.5920
+wall 1.9183 1.9041 1.9193 1.9315 0.0112 5.7550
+ Asm Lines: 47238
+
+
+Mode: llvm Compiler: clang PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 3.3843 3.3639 3.3719 3.4173 0.0235 10.1530
+ sys 1.0862 1.0743 1.0789 1.1053 0.0136 3.2585
+wall 4.5248 4.4754 4.4906 4.6084 0.0595 13.5744
+
+Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 7.4463 7.3855 7.3897 7.5638 0.0831 22.3390
+ sys 1.7927 1.7653 1.7841 1.8286 0.0265 5.3780
+wall 9.3259 9.2350 9.2660 9.4767 0.1074 27.9777
+
+Mode: llvm Compiler: llvm-gcc PCH: 1 Flags: -O0 -g
+name avg min med max SD total
+user 1.1532 1.1527 1.1527 1.1556 0.0018 3.4596
+ sys 0.8746 0.8663 0.8663 0.8774 0.0060 2.6238
+wall 2.1168 2.0914 2.0914 2.1464 0.0226 6.3503
+
+
+Mode: asm Compiler: clang PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 3.6819 3.5955 3.7080 3.7422 0.0627 11.0458
+ sys 1.1386 1.0879 1.1480 1.1798 0.0381 3.4158
+wall 4.8606 4.7204 4.8947 4.9668 0.1034 14.5819
+ Asm Lines: 106056
+
+Mode: asm Compiler: gcc PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 7.9271 7.8581 7.8581 8.0696 0.1008 23.7814
+ sys 2.0275 1.9943 1.9943 2.0711 0.0322 6.0826
+wall 10.0313 9.9266 9.9266 10.2314 0.1415 30.0939
+ Asm Lines: 177342
+
+Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 7.7083 7.6793 7.6941 7.6941 0.0312 23.1249
+ sys 1.8122 1.7971 1.8204 1.8204 0.0107 5.4365
+wall 9.6227 9.5591 9.6555 9.6555 0.0450 28.8682
+ Asm Lines: 203358
+
+Mode: asm Compiler: gcc PCH: 1 Flags: -O0 -g
+name avg min med max SD total
+user 1.2589 1.2129 1.2130 1.3509 0.0650 3.7767
+ sys 1.2141 1.1467 1.1601 1.3355 0.0860 3.6423
+wall 2.5426 2.4325 2.4357 2.7596 0.1534 7.6278
+ Asm Lines: 177335
+
+Mode: asm Compiler: llvm-gcc PCH: 1 Flags: -O0 -g
+name avg min med max SD total
+user 1.4234 1.3843 1.4009 1.4849 0.0440 4.2701
+ sys 0.9822 0.9153 0.9446 1.0867 0.0749 2.9466
+wall 2.4856 2.3713 2.4482 2.6372 0.1117 7.4567
+ Asm Lines: 203353
+
+
+ Done: 2008-10-31_16-55
diff --git a/www/timing-data/2008-10-31/sketch-02.txt b/www/timing-data/2008-10-31/sketch-02.txt
new file mode 100644
index 000000000000..88af3267ea61
--- /dev/null
+++ b/www/timing-data/2008-10-31/sketch-02.txt
@@ -0,0 +1,187 @@
+Title: Sketch Timings
+Timestamp: 2008-10-31_16-59
+Uname: Darwin lordcrumb.apple.com 10.0.0d3 Darwin Kernel Version 10.0.0d3: Fri Oct 24 02:12:11 PDT 2008; root:xnu-1353~2/RELEASE_I386 i386
+Path: /Users/ddunbar/nightlytest/Sketch.ref
+Runs: 3
+
+LLVM SVN Rev.: 58536
+
+clang: /Users/ddunbar/llvm/Release-Asserts/bin//clang
+gcc: /usr/bin/gcc-4.2
+llvm-gcc: /Users/ddunbar/llvm-gcc/install/bin/llvm-gcc
+
+Mode: Eonly Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 1.4030 1.3765 1.3887 1.4437 0.0293 4.2089
+ sys 0.8561 0.8388 0.8497 0.8796 0.0173 2.5682
+wall 2.2809 2.2373 2.2586 2.3468 0.0474 6.8426
+
+Mode: Eonly Compiler: gcc PCH: 0 Flags:
+name avg min med max SD total
+user 2.3041 2.2821 2.2821 2.3563 0.0371 6.9123
+ sys 1.0772 1.0593 1.0593 1.0976 0.0157 3.2316
+wall 3.4323 3.3918 3.3918 3.4905 0.0422 10.2970
+
+Mode: Eonly Compiler: llvm-gcc PCH: 0 Flags:
+name avg min med max SD total
+user 2.7593 2.7038 2.7831 2.7831 0.0393 8.2778
+ sys 1.2805 1.2605 1.2868 1.2868 0.0144 3.8414
+wall 4.0893 4.0056 4.1319 4.1319 0.0592 12.2679
+
+
+Mode: parse-noop Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 1.7430 1.7252 1.7429 1.7610 0.0146 5.2291
+ sys 0.8573 0.8457 0.8605 0.8656 0.0085 2.5718
+wall 2.6237 2.5942 2.6266 2.6504 0.0230 7.8711
+
+
+Mode: disable-free Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 2.7684 2.7291 2.7310 2.8450 0.0542 8.3051
+ sys 1.0088 0.9948 0.9960 1.0356 0.0189 3.0263
+wall 3.8203 3.7581 3.7635 3.9394 0.0842 11.4610
+
+
+Mode: syntax Compiler: clang PCH: 0 Flags:
+name avg min med max SD total
+user 3.1106 3.1115 3.1107 3.1095 0.0008 9.3317
+ sys 1.0674 1.0630 1.0672 1.0721 0.0037 3.2022
+wall 4.2059 4.2015 4.2077 4.2085 0.0031 12.6176
+
+Mode: syntax Compiler: gcc PCH: 0 Flags:
+name avg min med max SD total
+user 6.4166 6.3461 6.4479 6.4559 0.0500 19.2499
+ sys 1.7649 1.7256 1.7836 1.7854 0.0278 5.2946
+wall 8.2536 8.1547 8.3018 8.3045 0.0700 24.7609
+
+Mode: syntax Compiler: llvm-gcc PCH: 0 Flags:
+name avg min med max SD total
+user 7.0297 6.9018 7.0003 7.1869 0.1182 21.0890
+ sys 1.7782 1.7336 1.7875 1.8136 0.0333 5.3347
+wall 8.8942 8.7128 8.8699 9.0999 0.1590 26.6826
+
+Mode: syntax Compiler: gcc PCH: 1 Flags:
+name avg min med max SD total
+user 0.6133 0.6065 0.6089 0.6244 0.0079 1.8398
+ sys 0.9115 0.8880 0.9019 0.9446 0.0241 2.7345
+wall 1.5864 1.5593 1.5669 1.6330 0.0331 4.7592
+
+Mode: syntax Compiler: llvm-gcc PCH: 1 Flags:
+name avg min med max SD total
+user 0.6412 0.6387 0.6387 0.6477 0.0047 1.9235
+ sys 0.7820 0.7654 0.7654 0.7955 0.0125 2.3461
+wall 1.4909 1.4783 1.4783 1.5124 0.0153 4.4726
+
+
+Mode: llvm Compiler: clang PCH: 0 Flags: -O0
+name avg min med max SD total
+user 3.2926 3.2939 3.2939 3.2998 0.0065 9.8778
+ sys 1.0746 1.0728 1.0728 1.0793 0.0034 3.2237
+wall 4.4097 4.4045 4.4045 4.4150 0.0043 13.2290
+
+Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0
+name avg min med max SD total
+user 7.3232 7.2559 7.3145 7.3991 0.0588 21.9695
+ sys 1.8050 1.7967 1.7982 1.8201 0.0107 5.4151
+wall 9.2155 9.1243 9.2130 9.3092 0.0755 27.6465
+
+Mode: llvm Compiler: llvm-gcc PCH: 1 Flags: -O0
+name avg min med max SD total
+user 0.8337 0.8288 0.8288 0.8444 0.0076 2.5011
+ sys 0.8575 0.8484 0.8484 0.8773 0.0140 2.5725
+wall 1.7973 1.7406 1.7406 1.9054 0.0764 5.3919
+
+
+Mode: asm Compiler: clang PCH: 0 Flags: -O0
+name avg min med max SD total
+user 3.4909 3.4823 3.4896 3.4896 0.0077 10.4728
+ sys 1.0997 1.1027 1.1028 1.1028 0.0043 3.2991
+wall 4.6332 4.6179 4.6483 4.6483 0.0124 13.8996
+ Asm Lines: 46279
+
+Mode: asm Compiler: gcc PCH: 0 Flags: -O0
+name avg min med max SD total
+user 6.8956 6.7882 6.9057 6.9929 0.0839 20.6868
+ sys 1.7978 1.7703 1.7928 1.8302 0.0247 5.3933
+wall 8.7724 8.6360 8.7818 8.8994 0.1077 26.3172
+ Asm Lines: 41008
+
+Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0
+name avg min med max SD total
+user 7.2722 7.2087 7.3014 7.3014 0.0450 21.8167
+ sys 1.8020 1.7828 1.8083 1.8083 0.0139 5.4060
+wall 9.1527 9.0609 9.2011 9.2011 0.0650 27.4582
+ Asm Lines: 47243
+
+Mode: asm Compiler: gcc PCH: 1 Flags: -O0
+name avg min med max SD total
+user 1.0563 1.0337 1.0373 1.0979 0.0294 3.1689
+ sys 1.0249 0.9862 0.9837 1.1048 0.0565 3.0747
+wall 2.1458 2.0764 2.0838 2.2772 0.0930 6.4374
+ Asm Lines: 41001
+
+Mode: asm Compiler: llvm-gcc PCH: 1 Flags: -O0
+name avg min med max SD total
+user 0.9983 0.9929 0.9929 1.0110 0.0090 2.9950
+ sys 0.8616 0.8525 0.8525 0.8822 0.0146 2.5849
+wall 1.9268 1.9061 1.9061 1.9632 0.0259 5.7804
+ Asm Lines: 47238
+
+
+Mode: llvm Compiler: clang PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 3.4344 3.3999 3.4302 3.4730 0.0300 10.3032
+ sys 1.1155 1.0881 1.1394 1.1191 0.0211 3.3466
+wall 4.5875 4.5279 4.6054 4.6292 0.0432 13.7626
+
+Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 7.5996 7.5021 7.5389 7.7578 0.1129 22.7988
+ sys 1.8546 1.8469 1.8262 1.8908 0.0270 5.5639
+wall 9.5392 9.4246 9.4575 9.7353 0.1394 28.6175
+
+Mode: llvm Compiler: llvm-gcc PCH: 1 Flags: -O0 -g
+name avg min med max SD total
+user 1.1556 1.1512 1.1542 1.1542 0.0042 3.4667
+ sys 0.9021 0.8890 0.8971 0.8971 0.0131 2.7062
+wall 2.1308 2.1126 2.1487 2.1487 0.0147 6.3924
+
+
+Mode: asm Compiler: clang PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 3.6020 3.5895 3.5904 3.6259 0.0169 10.8059
+ sys 1.0967 1.0879 1.0879 1.1143 0.0124 3.2901
+wall 4.7362 4.7169 4.7182 4.7736 0.0264 14.2087
+ Asm Lines: 106056
+
+Mode: asm Compiler: gcc PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 8.0264 7.8409 8.0350 8.2033 0.1481 24.0792
+ sys 2.0315 1.9767 2.0315 2.0864 0.0448 6.0946
+wall 10.1477 9.9000 10.1584 10.3846 0.1980 30.4430
+ Asm Lines: 177342
+
+Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
+name avg min med max SD total
+user 7.8449 7.8189 7.8471 7.8687 0.0204 23.5346
+ sys 1.8727 1.8768 1.8539 1.8874 0.0140 5.6181
+wall 9.8164 9.7803 9.8029 9.8661 0.0363 29.4492
+ Asm Lines: 203358
+
+Mode: asm Compiler: gcc PCH: 1 Flags: -O0 -g
+name avg min med max SD total
+user 1.2216 1.2137 1.2168 1.2342 0.0090 3.6647
+ sys 1.1771 1.1627 1.1630 1.2055 0.0201 3.5312
+wall 2.4619 2.4419 2.4429 2.5008 0.0275 7.3856
+ Asm Lines: 177335
+
+Mode: asm Compiler: llvm-gcc PCH: 1 Flags: -O0 -g
+name avg min med max SD total
+user 1.3980 1.3682 1.3688 1.4569 0.0416 4.1939
+ sys 0.9354 0.8951 0.9181 0.9930 0.0418 2.8062
+wall 2.4380 2.3312 2.3606 2.6224 0.1309 7.3141
+ Asm Lines: 203353
+
+
+ Done: 2008-10-31_17-08
diff --git a/www/timing-data/2008-10-31/sketch.png b/www/timing-data/2008-10-31/sketch.png
new file mode 100644
index 000000000000..5ce3b11087ac
--- /dev/null
+++ b/www/timing-data/2008-10-31/sketch.png
Binary files differ
diff --git a/www/timing-data/2009-03-02/176.gcc.pdf b/www/timing-data/2009-03-02/176.gcc.pdf
new file mode 100644
index 000000000000..0b2e610d085a
--- /dev/null
+++ b/www/timing-data/2009-03-02/176.gcc.pdf
Binary files differ
diff --git a/www/timing-data/2009-03-02/176.gcc.png b/www/timing-data/2009-03-02/176.gcc.png
new file mode 100644
index 000000000000..4ae08e11adc4
--- /dev/null
+++ b/www/timing-data/2009-03-02/176.gcc.png
Binary files differ
diff --git a/www/timing-data/2009-03-02/176.gcc.txt b/www/timing-data/2009-03-02/176.gcc.txt
new file mode 100644
index 000000000000..f965e9729e6a
--- /dev/null
+++ b/www/timing-data/2009-03-02/176.gcc.txt
@@ -0,0 +1,1120 @@
+ccc_path = """/Volumes/Data/ddunbar/llvm.install/bin/ccc"""
+ccc_clang = """/Volumes/Data/ddunbar/zorg/xcb_scripts/cc/xcc.fb"""
+ccc_gcc = """/Volumes/Data/ddunbar/zorg/xcb_scripts/cc/xcc.fb -ccc-no-clang"""
+gcc = """/usr/bin/gcc-4.2"""
+ccc_clang_info = """
+ccc version 1.0 (https://ddunbar@llvm.org/svn/llvm-project/cfe/trunk)
+ "/Volumes/Data/ddunbar/llvm.install/bin/clang" "-S" "-disable-free" "--relocation-model=pic" "--disable-fp-elim" "--nozero-initialized-in-bss" "--unwind-tables=1" "--mcpu=core2" "--fmath-errno=0" "-mmacosx-version-min=10.6.0" "-arch" "x86_64" "-o" "/tmp/tmp62ee6x.s" "-x" "c" "/dev/null"
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/tmp/tmpyLxO26.o" "/tmp/tmp62ee6x.s"
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.5.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/tmp/tmpyLxO26.o" "-lgcc_s.10.5" "-lgcc" "-lSystem"
+"""
+ccc_gcc_info = """
+ccc version 1.0 (https://ddunbar@llvm.org/svn/llvm-project/cfe/trunk)
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/cc1" "-quiet" "-imultilib" "x86_64" "-D__DYNAMIC__" "/dev/null" "-fPIC" "-quiet" "-dumpbase" "null" "-mmacosx-version-min=10.6.0" "-m64" "-mtune=core2" "-auxbase" "null" "-o" "/tmp/tmpDx0Rtr.s"
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/tmp/tmpNbvYrM.o" "/tmp/tmpDx0Rtr.s"
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.5.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/tmp/tmpNbvYrM.o" "-lgcc_s.10.5" "-lgcc" "-lSystem"
+"""
+gcc_info = """
+Using built-in specs.
+Target: i686-apple-darwin10
+Configured with: /var/tmp/gcc/gcc-5641~3/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10
+Thread model: posix
+gcc version 4.2.1 (Apple Inc. build 5641)
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/cc1" "-quiet" "-imultilib" "x86_64" "-D__DYNAMIC__" "/dev/null" "-fPIC" "-quiet" "-dumpbase" "null" "-mmacosx-version-min=10.6.0" "-m64" "-mtune=core2" "-auxbase" "null" "-o" "/var/tmp//ccDnCoVC.s"
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/var/tmp//ccwsOXBR.o" "/var/tmp//ccDnCoVC.s"
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.6.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/var/tmp//ccwsOXBR.o" "-lgcc" "-lSystem"
+"""
+style = """make"""
+runs = []
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"null",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.041626, 0.067272, 0.122191),
+ (1, 0.041643, 0.067045, 0.122192),
+ (2, 0.041655, 0.067055, 0.121649),
+ (3, 0.041562, 0.066648, 0.121432),
+ (4, 0.041613, 0.066810, 0.121305),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"null",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.041606, 0.066993, 0.121704),
+ (1, 0.041581, 0.066630, 0.121471),
+ (2, 0.041602, 0.066922, 0.121765),
+ (3, 0.041581, 0.066859, 0.121405),
+ (4, 0.041689, 0.066980, 0.124326),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"null",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.041675, 0.067138, 0.121728),
+ (1, 0.041612, 0.066859, 0.121205),
+ (2, 0.041580, 0.066483, 0.120964),
+ (3, 0.041594, 0.066483, 0.120985),
+ (4, 0.041568, 0.066532, 0.120499),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"###",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.186639, 1.937014, 4.437061),
+ (1, 2.186681, 1.945610, 4.433872),
+ (2, 2.188041, 1.947231, 4.462319),
+ (3, 2.188190, 1.943516, 4.470365),
+ (4, 2.187020, 1.950682, 4.436890),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"###",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.195748, 1.947951, 4.443053),
+ (1, 2.194402, 1.940449, 4.432535),
+ (2, 2.195423, 1.943498, 4.447053),
+ (3, 2.196253, 1.950332, 4.448664),
+ (4, 2.195660, 1.942226, 4.437071),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"###",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.136111, 0.313413, 0.499384),
+ (1, 0.136203, 0.313310, 0.500697),
+ (2, 0.136639, 0.314917, 0.558877),
+ (3, 0.136173, 0.313843, 0.501008),
+ (4, 0.135965, 0.312723, 0.498594),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"cpp",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.819676, 2.374582, 5.801642),
+ (1, 2.819568, 2.375962, 5.525720),
+ (2, 2.819725, 2.377977, 5.526612),
+ (3, 2.819563, 2.374766, 5.525245),
+ (4, 2.820020, 2.378179, 5.531853),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"parse",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.979842, 2.393759, 5.773241),
+ (1, 2.978360, 2.388217, 5.699588),
+ (2, 2.979615, 2.392749, 5.713015),
+ (3, 2.978055, 2.388861, 5.697303),
+ (4, 2.979260, 2.390138, 5.710568),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"syntax",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.525414, 2.495433, 6.457547),
+ (1, 3.523990, 2.498728, 6.378505),
+ (2, 3.523183, 2.492712, 6.370535),
+ (3, 3.523363, 2.494413, 6.376960),
+ (4, 3.525216, 2.501657, 6.413753),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"syntax",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 6.143927, 2.857721, 9.407785),
+ (1, 6.144766, 2.871091, 9.396498),
+ (2, 6.143893, 2.860256, 9.392155),
+ (3, 6.146454, 2.866420, 9.447510),
+ (4, 6.146771, 2.864488, 9.664806),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"syntax",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.975961, 1.044303, 5.199328),
+ (1, 3.976843, 1.044060, 5.209434),
+ (2, 3.976622, 1.043787, 5.223585),
+ (3, 3.975836, 1.043403, 5.198575),
+ (4, 3.975980, 1.035674, 5.196275),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"irgen",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 5.707728, 2.859466, 9.115580),
+ (1, 5.709064, 2.858221, 9.094858),
+ (2, 5.707868, 2.868881, 9.006296),
+ (3, 5.706836, 2.856589, 8.998487),
+ (4, 5.706603, 2.857047, 9.028045),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_asm",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 7.855523, 3.041195, 11.679531),
+ (1, 7.855184, 3.046897, 11.389012),
+ (2, 7.855530, 3.039149, 11.435265),
+ (3, 7.856299, 3.037483, 11.382391),
+ (4, 7.854147, 3.043133, 11.373174),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_asm",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.926280, 3.168833, 14.542014),
+ (1, 10.931726, 3.174573, 14.573554),
+ (2, 10.933809, 3.163183, 14.857843),
+ (3, 10.927966, 3.164824, 14.543822),
+ (4, 10.927423, 3.166222, 14.658131),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_asm",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 8.755856, 1.342961, 10.311273),
+ (1, 8.756782, 1.346296, 10.314137),
+ (2, 8.760167, 1.338744, 10.442545),
+ (3, 8.759031, 1.346241, 10.333765),
+ (4, 8.758174, 1.339294, 10.328992),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_compile",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.159773, 3.431851, 13.319311),
+ (1, 9.156190, 3.421113, 13.203571),
+ (2, 9.157752, 3.417859, 13.220865),
+ (3, 9.156178, 3.413504, 13.204341),
+ (4, 9.150167, 3.412242, 13.252471),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_compile",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 12.062994, 3.497204, 16.184210),
+ (1, 12.065757, 3.486858, 16.503552),
+ (2, 12.063830, 3.499430, 16.171503),
+ (3, 12.065427, 3.500838, 16.268848),
+ (4, 12.063384, 3.503007, 16.164980),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_compile",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.836694, 1.570806, 11.863629),
+ (1, 9.835162, 1.580921, 11.762224),
+ (2, 9.836416, 1.572111, 11.893337),
+ (3, 9.835066, 1.571860, 11.751330),
+ (4, 9.836771, 1.575158, 11.783299),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"all",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.262905, 3.437217, 13.459870),
+ (1, 9.262539, 3.446216, 13.349994),
+ (2, 9.260750, 3.445077, 13.357125),
+ (3, 9.263932, 3.448647, 13.366228),
+ (4, 9.258133, 3.443125, 13.369278),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"all",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 12.163348, 3.513017, 16.559292),
+ (1, 12.159476, 3.526493, 16.430252),
+ (2, 12.157784, 3.513763, 16.306505),
+ (3, 12.159307, 3.530832, 16.495815),
+ (4, 12.160843, 3.516564, 16.331499),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"all",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.945925, 1.592199, 11.971326),
+ (1, 9.944375, 1.603629, 11.899797),
+ (2, 9.945863, 1.601172, 11.917642),
+ (3, 9.946878, 1.601530, 12.113196),
+ (4, 9.943168, 1.596300, 11.910257),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"null",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.042234, 0.072110, 0.068216),
+ (1, 0.042155, 0.071582, 0.067917),
+ (2, 0.042120, 0.071280, 0.067838),
+ (3, 0.042134, 0.071281, 0.067688),
+ (4, 0.042182, 0.071185, 0.068571),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"null",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.042195, 0.072394, 0.067753),
+ (1, 0.042154, 0.071378, 0.067667),
+ (2, 0.042126, 0.071503, 0.067645),
+ (3, 0.042142, 0.071525, 0.067641),
+ (4, 0.042137, 0.071263, 0.067512),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"null",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.042117, 0.071863, 0.067866),
+ (1, 0.042095, 0.071587, 0.067778),
+ (2, 0.042123, 0.071824, 0.067718),
+ (3, 0.042017, 0.071448, 0.067336),
+ (4, 0.042098, 0.071669, 0.067649),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"###",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.312764, 2.250083, 2.579668),
+ (1, 2.313524, 2.255599, 2.581617),
+ (2, 2.314576, 2.236269, 2.751308),
+ (3, 2.313798, 2.247632, 2.576000),
+ (4, 2.308146, 2.127675, 2.449384),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"###",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.319161, 2.248583, 2.579843),
+ (1, 2.320569, 2.254949, 2.582595),
+ (2, 2.319615, 2.254838, 2.582868),
+ (3, 2.317640, 2.234440, 2.566378),
+ (4, 2.319468, 2.253768, 2.582185),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"###",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.138760, 0.342468, 0.274713),
+ (1, 0.138529, 0.338083, 0.270603),
+ (2, 0.138419, 0.339997, 0.272035),
+ (3, 0.138474, 0.339942, 0.271676),
+ (4, 0.138476, 0.339545, 0.271208),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"cpp",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.927601, 2.621882, 3.040263),
+ (1, 2.928817, 2.618327, 3.042979),
+ (2, 2.925842, 2.616328, 3.034669),
+ (3, 2.933845, 2.642455, 3.077028),
+ (4, 2.947212, 2.620121, 3.167388),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"parse",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.095391, 2.632837, 3.130378),
+ (1, 3.096120, 2.626309, 3.120448),
+ (2, 3.095708, 2.622912, 3.125333),
+ (3, 3.096435, 2.628234, 3.124718),
+ (4, 3.095836, 2.623590, 3.124194),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"syntax",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.674570, 2.716479, 3.444615),
+ (1, 3.673243, 2.720120, 3.443432),
+ (2, 3.673080, 2.709820, 3.443546),
+ (3, 3.673200, 2.709185, 3.426130),
+ (4, 3.670534, 2.711744, 3.427015),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"syntax",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 6.389665, 3.072630, 4.983543),
+ (1, 6.385878, 3.080763, 4.975980),
+ (2, 6.389956, 3.069652, 4.982242),
+ (3, 6.388396, 3.078156, 4.977871),
+ (4, 6.391305, 3.090905, 4.994381),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"syntax",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.079359, 1.112710, 2.692685),
+ (1, 4.077052, 1.114109, 2.689234),
+ (2, 4.078218, 1.119202, 2.693919),
+ (3, 4.077124, 1.108491, 2.690559),
+ (4, 4.077296, 1.112142, 2.684408),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"irgen",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 6.043907, 3.082369, 4.874229),
+ (1, 6.044110, 3.072240, 4.860724),
+ (2, 6.049991, 3.085666, 4.927778),
+ (3, 6.050681, 3.087747, 4.866959),
+ (4, 6.046383, 3.081174, 4.865700),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_asm",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 8.277376, 3.241075, 6.041627),
+ (1, 8.274767, 3.246052, 6.032635),
+ (2, 8.273632, 3.240323, 6.034355),
+ (3, 8.283322, 3.235898, 6.055232),
+ (4, 8.279572, 3.237813, 6.040545),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_asm",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 11.267468, 3.368598, 7.582008),
+ (1, 11.264991, 3.356817, 7.573902),
+ (2, 11.258736, 3.371794, 7.616322),
+ (3, 11.272174, 3.375177, 7.750662),
+ (4, 11.265369, 3.355828, 7.569228),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_asm",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 8.948892, 1.408841, 5.346675),
+ (1, 8.947425, 1.388794, 5.341078),
+ (2, 8.959290, 1.397633, 5.703015),
+ (3, 8.948915, 1.391639, 5.351654),
+ (4, 8.946706, 1.404458, 5.345449),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_compile",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.576401, 3.659016, 6.972346),
+ (1, 9.577255, 3.641158, 6.953448),
+ (2, 9.572443, 3.647954, 7.051130),
+ (3, 9.571615, 3.646782, 6.956555),
+ (4, 9.572963, 3.653229, 6.957711),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_compile",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 12.425333, 3.720605, 8.468826),
+ (1, 12.420657, 3.729020, 8.648778),
+ (2, 12.424221, 3.709511, 8.467562),
+ (3, 12.425595, 3.726297, 8.449276),
+ (4, 12.422584, 3.718660, 8.713483),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_compile",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.042865, 1.647364, 6.147098),
+ (1, 10.038624, 1.646965, 6.107788),
+ (2, 10.036193, 1.643319, 6.100944),
+ (3, 10.037764, 1.637319, 6.121365),
+ (4, 10.044532, 1.648919, 6.354301),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"all",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.686781, 3.657538, 7.098294),
+ (1, 9.679355, 3.674326, 7.109849),
+ (2, 9.678938, 3.659032, 7.093127),
+ (3, 9.683371, 3.655282, 7.396885),
+ (4, 9.677578, 3.661111, 7.086666),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"all",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 12.511083, 3.753316, 8.574587),
+ (1, 12.517391, 3.745202, 8.579089),
+ (2, 12.515167, 3.747517, 8.906780),
+ (3, 12.510503, 3.744116, 8.561728),
+ (4, 12.516263, 3.740046, 8.578455),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"all",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.139224, 1.659640, 6.213839),
+ (1, 10.144829, 1.668260, 6.423697),
+ (2, 10.144182, 1.670476, 6.213931),
+ (3, 10.144068, 1.658834, 6.211693),
+ (4, 10.138223, 1.667654, 6.222308),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"null",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.044057, 0.093485, 0.045956),
+ (1, 0.044004, 0.092769, 0.045605),
+ (2, 0.043901, 0.092551, 0.045247),
+ (3, 0.043818, 0.091785, 0.045295),
+ (4, 0.043924, 0.091899, 0.045216),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"null",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.043938, 0.092531, 0.045317),
+ (1, 0.043985, 0.092990, 0.045413),
+ (2, 0.043847, 0.091943, 0.044986),
+ (3, 0.043889, 0.091626, 0.045207),
+ (4, 0.043936, 0.091446, 0.045068),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"null",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.043935, 0.092137, 0.045550),
+ (1, 0.044036, 0.092432, 0.045443),
+ (2, 0.043907, 0.092597, 0.045207),
+ (3, 0.043906, 0.092773, 0.045220),
+ (4, 0.043932, 0.092273, 0.045162),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"###",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.510229, 2.524326, 1.447378),
+ (1, 2.511153, 2.582682, 1.463158),
+ (2, 2.509131, 2.551808, 1.443700),
+ (3, 2.530506, 2.606601, 1.631594),
+ (4, 2.525546, 2.556516, 1.460912),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"###",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.519330, 2.572381, 1.455862),
+ (1, 2.519059, 2.662137, 1.521106),
+ (2, 2.506144, 2.556738, 1.456221),
+ (3, 2.511366, 2.577441, 1.459606),
+ (4, 2.526218, 2.553722, 1.574747),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"###",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.147023, 0.430956, 0.176525),
+ (1, 0.147430, 0.429136, 0.175834),
+ (2, 0.146893, 0.428812, 0.175145),
+ (3, 0.147174, 0.429968, 0.175169),
+ (4, 0.147492, 0.431385, 0.174682),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"cpp",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.167799, 3.158706, 1.805685),
+ (1, 3.167239, 3.135936, 1.802571),
+ (2, 3.157960, 3.130196, 1.803330),
+ (3, 3.146711, 3.153077, 1.813078),
+ (4, 3.149927, 3.152081, 1.801526),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"parse",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.342516, 3.109718, 1.823208),
+ (1, 3.353297, 3.103074, 1.819566),
+ (2, 3.333260, 3.149734, 1.829796),
+ (3, 3.338234, 3.103725, 1.822010),
+ (4, 3.336550, 3.100652, 1.832110),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"syntax",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.970523, 3.209725, 1.991844),
+ (1, 3.937210, 3.198855, 1.976041),
+ (2, 3.955488, 3.206959, 1.989544),
+ (3, 3.946574, 3.198149, 1.980601),
+ (4, 3.948581, 3.205880, 1.983994),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"syntax",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 6.732216, 3.619584, 2.782476),
+ (1, 6.745420, 3.616948, 2.790903),
+ (2, 6.750526, 3.594650, 2.790881),
+ (3, 6.738845, 3.612443, 2.790569),
+ (4, 6.747457, 3.617553, 2.788687),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"syntax",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.194680, 1.292044, 1.444048),
+ (1, 4.190321, 1.300927, 1.441506),
+ (2, 4.198820, 1.293219, 1.444174),
+ (3, 4.209445, 1.289162, 1.447259),
+ (4, 4.187489, 1.282234, 1.440277),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"irgen",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 6.517757, 3.615464, 2.854763),
+ (1, 6.519460, 3.617775, 2.756124),
+ (2, 6.498704, 3.602169, 2.756365),
+ (3, 6.509982, 3.621462, 2.745702),
+ (4, 6.489827, 3.608797, 2.747793),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_asm",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 8.825143, 3.794072, 3.362608),
+ (1, 8.824013, 3.765690, 3.355471),
+ (2, 8.813541, 3.783641, 3.357039),
+ (3, 8.786371, 3.786659, 3.345793),
+ (4, 8.772730, 3.771638, 3.454307),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_asm",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 11.738484, 3.836784, 4.120546),
+ (1, 11.739288, 3.848616, 4.125808),
+ (2, 11.738261, 3.837534, 4.136642),
+ (3, 11.735003, 3.844597, 4.120444),
+ (4, 11.761638, 3.862457, 4.145417),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_asm",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.155087, 1.561075, 2.833868),
+ (1, 9.154934, 1.538791, 2.833134),
+ (2, 9.183035, 1.553281, 2.902132),
+ (3, 9.151130, 1.546822, 2.879777),
+ (4, 9.151844, 1.542450, 2.825560),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_compile",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.166988, 4.242308, 3.894601),
+ (1, 10.218686, 4.265537, 3.896997),
+ (2, 10.208211, 4.256174, 3.905990),
+ (3, 10.182169, 4.254989, 4.094963),
+ (4, 10.165336, 4.239672, 3.873703),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_compile",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 12.960833, 4.319633, 4.628599),
+ (1, 12.997509, 4.323695, 4.942418),
+ (2, 12.940625, 4.326994, 4.624419),
+ (3, 12.947641, 4.300034, 4.597456),
+ (4, 12.942562, 4.308688, 4.619190),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_compile",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.300396, 1.823967, 3.250894),
+ (1, 10.305252, 1.822285, 3.244746),
+ (2, 10.307011, 1.845773, 3.260861),
+ (3, 10.319953, 1.831435, 3.500671),
+ (4, 10.320805, 1.834782, 3.246639),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"all",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.297812, 4.264184, 4.013061),
+ (1, 10.315407, 4.293257, 4.021099),
+ (2, 10.257966, 4.265659, 4.006248),
+ (3, 10.307857, 4.273741, 4.044614),
+ (4, 10.273398, 4.260286, 4.216469),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"all",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 13.040233, 4.302015, 4.719135),
+ (1, 13.046999, 4.316412, 5.773880),
+ (2, 13.081143, 4.324329, 4.745519),
+ (3, 13.025611, 4.311093, 4.738916),
+ (4, 13.063041, 4.336277, 4.771969),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"all",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.419745, 1.855515, 3.343652),
+ (1, 10.447391, 1.858839, 3.374031),
+ (2, 10.428436, 1.866242, 3.381289),
+ (3, 10.428931, 1.879273, 3.582034),
+ (4, 10.410715, 1.836761, 3.371333),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"null",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.044629, 0.104236, 0.047124),
+ (1, 0.044357, 0.101072, 0.046054),
+ (2, 0.044261, 0.099350, 0.045512),
+ (3, 0.044279, 0.099032, 0.045401),
+ (4, 0.044291, 0.098233, 0.045262),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"null",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.044388, 0.101047, 0.045972),
+ (1, 0.044267, 0.100816, 0.045836),
+ (2, 0.044319, 0.100931, 0.045829),
+ (3, 0.044242, 0.102208, 0.046286),
+ (4, 0.044197, 0.101894, 0.046310),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"null",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.044199, 0.099476, 0.045336),
+ (1, 0.044064, 0.099032, 0.045431),
+ (2, 0.044081, 0.097169, 0.044910),
+ (3, 0.044055, 0.099088, 0.044957),
+ (4, 0.044322, 0.099454, 0.045563),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"###",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.768949, 3.566605, 1.008622),
+ (1, 2.753933, 3.515221, 1.011067),
+ (2, 2.790210, 3.581213, 1.006835),
+ (3, 2.742393, 3.612996, 1.065939),
+ (4, 2.783563, 3.457715, 0.977203),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"###",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.803126, 3.542212, 1.140376),
+ (1, 2.794538, 3.523127, 1.000266),
+ (2, 2.821545, 3.533185, 0.996633),
+ (3, 2.754702, 3.604113, 1.127400),
+ (4, 2.773800, 3.590831, 1.023085),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"###",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.162694, 0.629660, 0.131824),
+ (1, 0.162231, 0.630903, 0.131937),
+ (2, 0.162713, 0.636833, 0.133010),
+ (3, 0.163527, 0.627696, 0.130973),
+ (4, 0.162591, 0.628073, 0.128269),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"cpp",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.398995, 4.386961, 1.222372),
+ (1, 3.433913, 4.302404, 1.191109),
+ (2, 3.403972, 4.249079, 1.179600),
+ (3, 3.430418, 4.241026, 1.173406),
+ (4, 3.405708, 4.295249, 1.192367),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"parse",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.589608, 4.234909, 1.206952),
+ (1, 3.595580, 4.250801, 1.195809),
+ (2, 3.598782, 4.186360, 1.189533),
+ (3, 3.576135, 4.210771, 1.192198),
+ (4, 3.596508, 4.272774, 1.195682),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"syntax",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.188318, 4.323380, 1.272841),
+ (1, 4.204432, 4.301331, 1.276169),
+ (2, 4.232123, 4.359346, 1.308850),
+ (3, 4.254709, 4.295013, 1.277959),
+ (4, 4.214074, 4.293825, 1.275462),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"syntax",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 7.056727, 4.672983, 1.677022),
+ (1, 7.064183, 4.697158, 1.685536),
+ (2, 7.013256, 4.653804, 1.669026),
+ (3, 7.077917, 4.720479, 1.692836),
+ (4, 7.028864, 4.654591, 1.674130),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"syntax",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.250811, 1.598520, 0.822128),
+ (1, 4.255341, 1.616523, 0.819562),
+ (2, 4.282720, 1.628032, 0.823764),
+ (3, 4.296236, 1.628292, 0.828753),
+ (4, 4.263254, 1.614337, 0.822968),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"irgen",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 6.828563, 4.698920, 1.665128),
+ (1, 6.887088, 4.678607, 1.660858),
+ (2, 6.867776, 4.703203, 1.657673),
+ (3, 6.841523, 4.645255, 1.637169),
+ (4, 6.904172, 4.682556, 1.690968),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_asm",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.164624, 4.728257, 2.026243),
+ (1, 9.258789, 4.757386, 1.996115),
+ (2, 9.215979, 4.740186, 1.995604),
+ (3, 9.241390, 4.750833, 2.007054),
+ (4, 9.161773, 4.742841, 1.987729),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_asm",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 12.113609, 4.726450, 2.385739),
+ (1, 12.121322, 4.784194, 2.416434),
+ (2, 12.095256, 4.762198, 2.394130),
+ (3, 12.125848, 4.743744, 2.386863),
+ (4, 12.117883, 4.759723, 2.384746),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_asm",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.196017, 1.794764, 1.538604),
+ (1, 9.293693, 1.830825, 1.559088),
+ (2, 9.210498, 1.813935, 1.538989),
+ (3, 9.207860, 1.799598, 1.536893),
+ (4, 9.202729, 1.797648, 1.530905),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_compile",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.574802, 5.298921, 2.539728),
+ (1, 10.657320, 5.376201, 2.329437),
+ (2, 10.650595, 5.345177, 2.311878),
+ (3, 10.611628, 5.366770, 2.319432),
+ (4, 10.599574, 5.358888, 2.479782),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_compile",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 13.432160, 5.417611, 2.691172),
+ (1, 13.443341, 5.377409, 2.678012),
+ (2, 13.343336, 5.338212, 2.812471),
+ (3, 13.333183, 5.333529, 2.687594),
+ (4, 13.384371, 5.414969, 2.837339),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_compile",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.381974, 2.152140, 1.786428),
+ (1, 10.378996, 2.143003, 1.774503),
+ (2, 10.453921, 2.187323, 1.794154),
+ (3, 10.398109, 2.212740, 2.013101),
+ (4, 10.435604, 2.197729, 1.779200),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"all",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.786656, 5.383657, 2.435159),
+ (1, 10.689933, 5.362047, 2.435158),
+ (2, 10.761754, 5.406655, 2.462640),
+ (3, 10.760319, 5.401706, 2.571526),
+ (4, 10.666932, 5.361587, 2.444485),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"all",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 13.519919, 5.421898, 2.821722),
+ (1, 13.447262, 5.364940, 2.926024),
+ (2, 13.464838, 5.369476, 2.802961),
+ (3, 13.514555, 5.440290, 2.831226),
+ (4, 13.443975, 5.410124, 2.947296),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"all",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.498388, 2.171118, 2.153460),
+ (1, 10.524313, 2.175829, 1.899075),
+ (2, 10.502688, 2.185754, 1.894639),
+ (3, 10.498667, 2.201617, 1.888811),
+ (4, 10.488970, 2.166527, 1.885400),
+]}
+))
diff --git a/www/timing-data/2009-03-02/sketch.pdf b/www/timing-data/2009-03-02/sketch.pdf
new file mode 100644
index 000000000000..3b98a3d054a3
--- /dev/null
+++ b/www/timing-data/2009-03-02/sketch.pdf
Binary files differ
diff --git a/www/timing-data/2009-03-02/sketch.png b/www/timing-data/2009-03-02/sketch.png
new file mode 100644
index 000000000000..3d1bc142beea
--- /dev/null
+++ b/www/timing-data/2009-03-02/sketch.png
Binary files differ
diff --git a/www/timing-data/2009-03-02/sketch.txt b/www/timing-data/2009-03-02/sketch.txt
new file mode 100644
index 000000000000..d2270e471a2b
--- /dev/null
+++ b/www/timing-data/2009-03-02/sketch.txt
@@ -0,0 +1,2368 @@
+ccc_path = """/Volumes/Data/ddunbar/llvm.install/bin/ccc"""
+ccc_clang = """/Volumes/Data/ddunbar/zorg/xcb_scripts/cc/xcc.fb"""
+ccc_gcc = """/Volumes/Data/ddunbar/zorg/xcb_scripts/cc/xcc.fb -ccc-no-clang"""
+gcc = """/usr/bin/gcc-4.2"""
+ccc_clang_info = """
+ccc version 1.0 (https://ddunbar@llvm.org/svn/llvm-project/cfe/trunk)
+ "/Volumes/Data/ddunbar/llvm.install/bin/clang" "-S" "-disable-free" "--relocation-model=pic" "--disable-fp-elim" "--nozero-initialized-in-bss" "--unwind-tables=1" "--mcpu=core2" "--fmath-errno=0" "-mmacosx-version-min=10.6.0" "-arch" "x86_64" "-o" "/tmp/tmpugUQni.s" "-x" "c" "/dev/null"
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/tmp/tmpH8AOZI.o" "/tmp/tmpugUQni.s"
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.5.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/tmp/tmpH8AOZI.o" "-lgcc_s.10.5" "-lgcc" "-lSystem"
+"""
+ccc_gcc_info = """
+ccc version 1.0 (https://ddunbar@llvm.org/svn/llvm-project/cfe/trunk)
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/cc1" "-quiet" "-imultilib" "x86_64" "-D__DYNAMIC__" "/dev/null" "-fPIC" "-quiet" "-dumpbase" "null" "-mmacosx-version-min=10.6.0" "-m64" "-mtune=core2" "-auxbase" "null" "-o" "/tmp/tmpTiOyJZ.s"
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/tmp/tmpTi0lCN.o" "/tmp/tmpTiOyJZ.s"
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.5.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/tmp/tmpTi0lCN.o" "-lgcc_s.10.5" "-lgcc" "-lSystem"
+"""
+gcc_info = """
+Using built-in specs.
+Target: i686-apple-darwin10
+Configured with: /var/tmp/gcc/gcc-5630~5/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10
+Thread model: posix
+gcc version 4.2.1 (Apple Inc. build 5630)
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/cc1" "-quiet" "-imultilib" "x86_64" "-D__DYNAMIC__" "/dev/null" "-fPIC" "-quiet" "-dumpbase" "null" "-mmacosx-version-min=10.6.0" "-m64" "-mtune=core2" "-auxbase" "null" "-o" "/var/tmp//ccuvh82w.s"
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/var/tmp//ccb3T8Fr.o" "/var/tmp//ccuvh82w.s"
+ "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.5.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/var/tmp//ccb3T8Fr.o" "-lgcc_s.10.5" "-lgcc" "-lSystem"
+"""
+style = """xcb"""
+runs = []
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"null",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.405425, 0.222438, 0.698198),
+ (1, 0.403472, 0.218381, 0.695599),
+ (2, 0.403354, 0.217344, 0.695414),
+ (3, 0.403856, 0.218787, 0.703370),
+ (4, 0.404353, 0.221186, 0.695619),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"null",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.393260, 0.212802, 0.656048),
+ (1, 0.393075, 0.211285, 0.654796),
+ (2, 0.394300, 0.213498, 0.695105),
+ (3, 0.393851, 0.213657, 0.695272),
+ (4, 0.395458, 0.213304, 0.695908),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"null",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.403360, 0.216918, 0.704434),
+ (1, 0.403818, 0.219731, 0.696158),
+ (2, 0.402206, 0.218530, 0.697751),
+ (3, 0.403133, 0.218441, 0.695443),
+ (4, 0.403311, 0.218882, 0.695080),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"null",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.395200, 0.213912, 0.696117),
+ (1, 0.395331, 0.213822, 0.695887),
+ (2, 0.395293, 0.212402, 0.697557),
+ (3, 0.395446, 0.213684, 0.695732),
+ (4, 0.394667, 0.213321, 0.656472),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"null",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.403665, 0.217763, 0.694820),
+ (1, 0.403482, 0.217606, 0.695959),
+ (2, 0.404965, 0.219817, 0.819840),
+ (3, 0.404437, 0.217515, 0.695675),
+ (4, 0.402886, 0.216456, 0.703275),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"null",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.393583, 0.212237, 0.655196),
+ (1, 0.394063, 0.212744, 0.695220),
+ (2, 0.393998, 0.212889, 0.695448),
+ (3, 0.394364, 0.213507, 0.695090),
+ (4, 0.395886, 0.214974, 0.696254),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"###",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.129656, 0.771133, 2.056006),
+ (1, 1.129855, 0.772644, 2.055649),
+ (2, 1.130559, 0.768629, 2.055976),
+ (3, 1.130291, 0.769030, 2.059280),
+ (4, 1.130861, 0.771000, 2.055720),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"###",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.086760, 0.741197, 1.976344),
+ (1, 1.087919, 0.739640, 1.975560),
+ (2, 1.087589, 0.739815, 2.015386),
+ (3, 1.087730, 0.738847, 1.976232),
+ (4, 1.088193, 0.739529, 2.016033),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"###",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.138506, 0.768675, 2.064631),
+ (1, 1.138085, 0.770549, 2.097210),
+ (2, 1.138889, 0.771511, 2.096435),
+ (3, 1.138765, 0.770142, 2.064291),
+ (4, 1.138779, 0.768611, 2.095530),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"###",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.096902, 0.741661, 2.015757),
+ (1, 1.097165, 0.740449, 2.015432),
+ (2, 1.096494, 0.740608, 2.016453),
+ (3, 1.096410, 0.739960, 1.975427),
+ (4, 1.096579, 0.743114, 2.016444),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"###",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.444144, 0.284384, 0.814217),
+ (1, 0.445853, 0.286540, 0.816314),
+ (2, 0.446338, 0.287002, 0.814997),
+ (3, 0.445384, 0.284369, 0.823090),
+ (4, 0.444071, 0.284531, 0.815854),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"###",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.435113, 0.278547, 0.817260),
+ (1, 0.433108, 0.275659, 0.775024),
+ (2, 0.434473, 0.276611, 0.784047),
+ (3, 0.434224, 0.275786, 0.775677),
+ (4, 0.433396, 0.276622, 0.775240),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_pch",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.328464, 0.973747, 2.577016),
+ (1, 1.324318, 0.855290, 2.424347),
+ (2, 1.323693, 0.856675, 2.416951),
+ (3, 1.323004, 0.857324, 2.417132),
+ (4, 1.323843, 0.856000, 2.415804),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_pch",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.748207, 1.141266, 4.576484),
+ (1, 2.744640, 1.137930, 4.416237),
+ (2, 2.745616, 1.136230, 4.495978),
+ (3, 2.746108, 1.139037, 4.496219),
+ (4, 2.746059, 1.137958, 4.416920),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_pch",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.051374, 0.650962, 3.144706),
+ (1, 2.050914, 0.648174, 3.215974),
+ (2, 2.050343, 0.649010, 3.176205),
+ (3, 2.051910, 0.648745, 3.176613),
+ (4, 2.051386, 0.648306, 3.217578),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"cpp",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.835919, 1.148648, 3.257076),
+ (1, 1.835307, 1.146862, 3.264809),
+ (2, 1.834812, 1.147964, 3.257005),
+ (3, 1.835016, 1.144979, 3.256861),
+ (4, 1.836571, 1.148836, 3.256094),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"cpp",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.288802, 1.569778, 4.095720),
+ (1, 2.288176, 1.573356, 4.176816),
+ (2, 2.287878, 1.573807, 4.096939),
+ (3, 2.288041, 1.571541, 4.097750),
+ (4, 2.288190, 1.569398, 4.097146),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"parse",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.220738, 1.167367, 3.657062),
+ (1, 2.219840, 1.170754, 3.657627),
+ (2, 2.220897, 1.172925, 3.657043),
+ (3, 2.221644, 1.167701, 3.656328),
+ (4, 2.223199, 1.171444, 3.657134),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"parse",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.717655, 1.602645, 4.536037),
+ (1, 2.716324, 1.603188, 4.536210),
+ (2, 2.718783, 1.605672, 4.576816),
+ (3, 2.718146, 1.602360, 4.536958),
+ (4, 2.718544, 1.606428, 4.577367),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"syntax",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.453390, 1.390902, 5.176330),
+ (1, 3.453408, 1.394547, 5.176325),
+ (2, 3.453141, 1.392043, 5.176946),
+ (3, 3.457040, 1.390031, 5.257617),
+ (4, 3.453262, 1.395063, 5.138977),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"syntax",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.077200, 1.866592, 6.223139),
+ (1, 4.076044, 1.873001, 6.214158),
+ (2, 4.079719, 1.869271, 6.235665),
+ (3, 4.078223, 1.866927, 6.217922),
+ (4, 4.076013, 1.867985, 6.204512),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"syntax",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.397072, 2.178746, 6.177185),
+ (1, 3.397804, 2.167804, 6.177276),
+ (2, 3.398193, 2.168075, 6.250655),
+ (3, 3.397029, 2.165686, 6.184421),
+ (4, 3.397568, 2.178013, 6.179279),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"syntax",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 7.486708, 2.445768, 10.254543),
+ (1, 7.491379, 2.458432, 10.337225),
+ (2, 7.486408, 2.433698, 10.257034),
+ (3, 7.487016, 2.456457, 10.270939),
+ (4, 7.487323, 2.439337, 10.258257),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"syntax",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.670173, 1.622433, 4.897808),
+ (1, 2.666760, 1.609756, 4.776822),
+ (2, 2.667040, 1.610998, 4.856885),
+ (3, 2.671149, 1.594163, 4.816301),
+ (4, 2.669699, 1.607578, 4.866539),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"syntax",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 6.803057, 1.908280, 8.963127),
+ (1, 6.805076, 1.939662, 8.969825),
+ (2, 6.802844, 1.921782, 8.970996),
+ (3, 6.805031, 1.913186, 8.967523),
+ (4, 6.805252, 1.919294, 8.959788),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"irgen",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.627373, 1.415978, 5.377556),
+ (1, 3.625026, 1.415306, 5.337455),
+ (2, 3.624699, 1.411942, 5.377834),
+ (3, 3.627468, 1.422229, 5.376680),
+ (4, 3.625721, 1.421354, 5.377509),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"irgen",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.249780, 1.891114, 6.438770),
+ (1, 4.248041, 1.893114, 6.416578),
+ (2, 4.248877, 1.890255, 6.422580),
+ (3, 4.248459, 1.891867, 6.425267),
+ (4, 4.251042, 1.896335, 6.438381),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_asm",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.813308, 1.436255, 5.577048),
+ (1, 3.812973, 1.436260, 5.577759),
+ (2, 3.814667, 1.436329, 5.576892),
+ (3, 3.814164, 1.439684, 5.577863),
+ (4, 3.816874, 1.432057, 5.625098),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_asm",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.438589, 1.914821, 6.634438),
+ (1, 4.436802, 1.913064, 6.628424),
+ (2, 4.438023, 1.918364, 6.632666),
+ (3, 4.438494, 1.922851, 6.645062),
+ (4, 4.439727, 1.920331, 6.685016),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_asm",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.975290, 2.296164, 6.913135),
+ (1, 3.977464, 2.309821, 6.916908),
+ (2, 3.976537, 2.309954, 6.848258),
+ (3, 3.977155, 2.305060, 7.357985),
+ (4, 3.974276, 2.289059, 6.862249),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_asm",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 8.928091, 2.684142, 11.969055),
+ (1, 8.929295, 2.683263, 11.988445),
+ (2, 8.929175, 2.678390, 11.956474),
+ (3, 8.926613, 2.665122, 11.965071),
+ (4, 8.926613, 2.680630, 11.964381),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_asm",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.249871, 1.745454, 5.497846),
+ (1, 3.249460, 1.737577, 5.538376),
+ (2, 3.253966, 1.727548, 5.616847),
+ (3, 3.251405, 1.725884, 5.496698),
+ (4, 3.250563, 1.721386, 5.536694),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_asm",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 8.249350, 2.147359, 10.672894),
+ (1, 8.252421, 2.146136, 10.687439),
+ (2, 8.252766, 2.142015, 10.683719),
+ (3, 8.279512, 2.152184, 11.070527),
+ (4, 8.250015, 2.161431, 10.703253),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_compile",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.917675, 1.531758, 5.777717),
+ (1, 3.917453, 1.532169, 5.777704),
+ (2, 3.920630, 1.538518, 5.857605),
+ (3, 3.917549, 1.535710, 5.776730),
+ (4, 3.917673, 1.529128, 5.776450),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_compile",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.536313, 2.003164, 6.831313),
+ (1, 4.537451, 2.014513, 6.846562),
+ (2, 4.540679, 2.016759, 6.865437),
+ (3, 4.538081, 2.008899, 6.845811),
+ (4, 4.538438, 2.009600, 6.836498),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_compile",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.123486, 2.383752, 7.115483),
+ (1, 4.127545, 2.372840, 7.151675),
+ (2, 4.125900, 2.381678, 7.138942),
+ (3, 4.123891, 2.369579, 7.127788),
+ (4, 4.125164, 2.370661, 7.117664),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_compile",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.076157, 2.771491, 12.341310),
+ (1, 9.074681, 2.764608, 12.205139),
+ (2, 9.076881, 2.766755, 12.228073),
+ (3, 9.073910, 2.771638, 12.204252),
+ (4, 9.076773, 2.777037, 12.235749),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_compile",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.388061, 1.779190, 5.737793),
+ (1, 3.387862, 1.790856, 5.697850),
+ (2, 3.387800, 1.789477, 5.780238),
+ (3, 3.387509, 1.788586, 5.743236),
+ (4, 3.388152, 1.784450, 6.178092),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_compile",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 8.376118, 2.205600, 10.877337),
+ (1, 8.372512, 2.219382, 10.868894),
+ (2, 8.375968, 2.225479, 10.996566),
+ (3, 8.379525, 2.215791, 10.910221),
+ (4, 8.375433, 2.210534, 10.890280),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"all",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.948571, 1.553366, 5.857777),
+ (1, 3.946872, 1.549844, 5.817926),
+ (2, 3.948643, 1.545410, 5.817794),
+ (3, 3.947022, 1.548687, 5.816790),
+ (4, 3.951557, 1.560511, 5.937022),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"all",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.568105, 2.037309, 6.888153),
+ (1, 4.567872, 2.037818, 6.893678),
+ (2, 4.569582, 2.037795, 6.894469),
+ (3, 4.571991, 2.042292, 6.920444),
+ (4, 4.568506, 2.036233, 6.895221),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"all",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.153075, 2.389230, 7.183219),
+ (1, 4.150947, 2.401330, 7.175264),
+ (2, 4.150807, 2.390926, 7.237253),
+ (3, 4.152335, 2.393576, 7.265347),
+ (4, 4.154240, 2.408743, 7.201345),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"all",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.104507, 2.799196, 12.284425),
+ (1, 9.102214, 2.804734, 12.263326),
+ (2, 9.102799, 2.797758, 12.263314),
+ (3, 9.102472, 2.797718, 12.283471),
+ (4, 9.101655, 2.799231, 12.257987),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"all",
+ 'threads':"1",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.412096, 1.803347, 5.817859),
+ (1, 3.412334, 1.792039, 5.897059),
+ (2, 3.413608, 1.789291, 5.817810),
+ (3, 3.413812, 1.785669, 5.827047),
+ (4, 3.413291, 1.782601, 5.738213),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"all",
+ 'threads':"1",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 8.402455, 2.228676, 10.943842),
+ (1, 8.396442, 2.225608, 10.902714),
+ (2, 8.401735, 2.220712, 10.918381),
+ (3, 8.400619, 2.226284, 10.926158),
+ (4, 8.398896, 2.221540, 10.901292),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"null",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.421126, 0.234655, 0.534969),
+ (1, 0.418396, 0.232067, 0.536121),
+ (2, 0.419512, 0.236062, 0.536636),
+ (3, 0.420755, 0.236390, 0.535508),
+ (4, 0.421343, 0.234614, 0.537189),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"null",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.411128, 0.230994, 0.499097),
+ (1, 0.412593, 0.231427, 0.536123),
+ (2, 0.407668, 0.229908, 0.495794),
+ (3, 0.410890, 0.229289, 0.535618),
+ (4, 0.412812, 0.229662, 0.535043),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"null",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.421792, 0.234957, 0.536236),
+ (1, 0.421073, 0.235668, 0.538946),
+ (2, 0.418909, 0.236416, 0.535464),
+ (3, 0.420363, 0.235692, 0.535257),
+ (4, 0.419598, 0.234400, 0.534633),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"null",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.409040, 0.230090, 0.534802),
+ (1, 0.411753, 0.232552, 0.537293),
+ (2, 0.415536, 0.231495, 0.536877),
+ (3, 0.410714, 0.227612, 0.535090),
+ (4, 0.409547, 0.230152, 0.497187),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"null",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.421181, 0.235033, 0.535407),
+ (1, 0.420747, 0.236700, 0.535928),
+ (2, 0.418786, 0.235032, 0.534312),
+ (3, 0.420015, 0.233378, 0.535452),
+ (4, 0.421154, 0.235218, 0.535269),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"null",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.411356, 0.231786, 0.537593),
+ (1, 0.412772, 0.230723, 0.537039),
+ (2, 0.410034, 0.228264, 0.494194),
+ (3, 0.412693, 0.230932, 0.536339),
+ (4, 0.411372, 0.228262, 0.497113),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"###",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.185856, 0.840347, 1.416460),
+ (1, 1.186435, 0.854091, 1.415674),
+ (2, 1.183343, 0.844916, 1.415643),
+ (3, 1.181560, 0.857296, 1.415242),
+ (4, 1.187699, 0.853918, 1.415647),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"###",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.138810, 0.818035, 1.335935),
+ (1, 1.141064, 0.827249, 1.337062),
+ (2, 1.138410, 0.811996, 1.335346),
+ (3, 1.142644, 0.820159, 1.337486),
+ (4, 1.138460, 0.815423, 1.335647),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"###",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.194684, 0.841290, 1.415885),
+ (1, 1.195720, 0.844873, 1.416552),
+ (2, 1.194440, 0.850513, 1.415595),
+ (3, 1.191931, 0.850890, 1.414722),
+ (4, 1.192481, 0.853052, 1.416102),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"###",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.148891, 0.817183, 1.335717),
+ (1, 1.149617, 0.823096, 1.336040),
+ (2, 1.149791, 0.805679, 1.337424),
+ (3, 1.150876, 0.814239, 1.336748),
+ (4, 1.153157, 0.809177, 1.336246),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"###",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.463514, 0.310817, 0.614767),
+ (1, 0.464612, 0.310198, 0.618455),
+ (2, 0.463460, 0.308990, 0.616282),
+ (3, 0.463413, 0.311280, 0.617026),
+ (4, 0.467009, 0.310382, 0.857752),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"###",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.453517, 0.301571, 0.575912),
+ (1, 0.452100, 0.300588, 0.576359),
+ (2, 0.448456, 0.297936, 0.575121),
+ (3, 0.451645, 0.298907, 0.577323),
+ (4, 0.450964, 0.301582, 0.574520),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_pch",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.381350, 0.944251, 1.776275),
+ (1, 1.380373, 0.930919, 1.775617),
+ (2, 1.379352, 0.937129, 1.736723),
+ (3, 1.380977, 0.944068, 1.737369),
+ (4, 1.381796, 0.938486, 1.776093),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_pch",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.805408, 1.220930, 3.697693),
+ (1, 2.804236, 1.204836, 3.657105),
+ (2, 2.803037, 1.210121, 3.696933),
+ (3, 2.807280, 1.219531, 3.779261),
+ (4, 2.802821, 1.208316, 3.736487),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_pch",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.076567, 0.672051, 2.896169),
+ (1, 2.070465, 0.668786, 2.895749),
+ (2, 2.077549, 0.673245, 2.896393),
+ (3, 2.075634, 0.671026, 2.976119),
+ (4, 2.074463, 0.671262, 2.975937),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"cpp",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.909827, 1.258607, 2.215806),
+ (1, 1.910547, 1.261354, 2.255924),
+ (2, 1.907436, 1.262299, 2.216659),
+ (3, 1.908875, 1.254564, 2.256077),
+ (4, 1.906568, 1.264632, 2.215638),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"cpp",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.384586, 1.708563, 2.495874),
+ (1, 2.386876, 1.705256, 2.456596),
+ (2, 2.383560, 1.707485, 2.456364),
+ (3, 2.388580, 1.714631, 2.496008),
+ (4, 2.383943, 1.709754, 2.455848),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"parse",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.296978, 1.274825, 2.415106),
+ (1, 2.303460, 1.279010, 2.456151),
+ (2, 2.300862, 1.277879, 2.536542),
+ (3, 2.297727, 1.277312, 2.416137),
+ (4, 2.299045, 1.281014, 2.457338),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"parse",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.823962, 1.752509, 2.738192),
+ (1, 2.825617, 1.738546, 2.736478),
+ (2, 2.825608, 1.744360, 2.735298),
+ (3, 2.822577, 1.756988, 2.735053),
+ (4, 2.828362, 1.751245, 2.737930),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"syntax",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.586428, 1.498329, 3.258357),
+ (1, 3.581922, 1.510793, 3.258049),
+ (2, 3.584574, 1.523963, 3.256754),
+ (3, 3.585929, 1.525886, 3.296728),
+ (4, 3.583339, 1.509529, 3.255773),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"syntax",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.249019, 2.030066, 3.658088),
+ (1, 4.244427, 1.997319, 3.618002),
+ (2, 4.247446, 2.034549, 3.656419),
+ (3, 4.250734, 1.984081, 3.616241),
+ (4, 4.247304, 2.029095, 3.656926),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"syntax",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.533690, 2.339185, 4.777496),
+ (1, 3.542505, 2.348833, 4.697715),
+ (2, 3.544757, 2.349717, 4.658518),
+ (3, 3.542116, 2.342489, 4.697843),
+ (4, 3.532830, 2.358614, 4.777230),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"syntax",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 7.911000, 2.638922, 5.859227),
+ (1, 7.898019, 2.606325, 5.856922),
+ (2, 7.905536, 2.635740, 5.857377),
+ (3, 7.904312, 2.612189, 5.858381),
+ (4, 7.905098, 2.630487, 5.896411),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"syntax",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.751623, 1.803556, 3.817713),
+ (1, 2.747727, 1.810833, 3.816503),
+ (2, 2.748505, 1.805853, 3.937231),
+ (3, 2.751082, 1.785040, 3.856857),
+ (4, 2.712181, 1.628194, 4.458047),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"syntax",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 7.130218, 2.046734, 5.375091),
+ (1, 7.178329, 2.050762, 5.101087),
+ (2, 7.169060, 2.043104, 5.099096),
+ (3, 7.173283, 2.044239, 5.098124),
+ (4, 7.175252, 2.051192, 5.098199),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"irgen",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.789165, 1.527458, 3.336326),
+ (1, 3.777274, 1.538660, 3.375557),
+ (2, 3.784557, 1.519313, 3.376128),
+ (3, 3.787602, 1.522217, 3.335926),
+ (4, 3.787288, 1.526795, 3.337409),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"irgen",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.447726, 2.033431, 3.740433),
+ (1, 4.442726, 2.033703, 3.738224),
+ (2, 4.442734, 2.032771, 3.738289),
+ (3, 4.444849, 2.031724, 3.737305),
+ (4, 4.447839, 2.041379, 3.737854),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_asm",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.976113, 1.536616, 3.457503),
+ (1, 3.982885, 1.550541, 3.459236),
+ (2, 3.980745, 1.542500, 3.418313),
+ (3, 3.983197, 1.534735, 3.416768),
+ (4, 3.984319, 1.549369, 3.456912),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_asm",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.646497, 2.058736, 3.857968),
+ (1, 4.645902, 2.056331, 3.816948),
+ (2, 4.644425, 2.042617, 3.817483),
+ (3, 4.650170, 2.053945, 3.816996),
+ (4, 4.652057, 2.054087, 3.817612),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_asm",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.227559, 2.531595, 5.137862),
+ (1, 4.227397, 2.523166, 5.177460),
+ (2, 4.221999, 2.507393, 5.217410),
+ (3, 4.222567, 2.526250, 5.217654),
+ (4, 4.227901, 2.540431, 5.098870),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_asm",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.519619, 2.893774, 6.844787),
+ (1, 9.519173, 2.909991, 6.855886),
+ (2, 9.510792, 2.877242, 6.838998),
+ (3, 9.510783, 2.891383, 6.824785),
+ (4, 9.519126, 2.885516, 6.833841),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_asm",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.451087, 1.898383, 4.336398),
+ (1, 3.449852, 1.892527, 4.337959),
+ (2, 3.454374, 1.893303, 4.658079),
+ (3, 3.455111, 1.882656, 4.378217),
+ (4, 3.450626, 1.869007, 4.337978),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_asm",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 8.787702, 2.320593, 6.058270),
+ (1, 8.789275, 2.306274, 6.057923),
+ (2, 8.784843, 2.316817, 6.057423),
+ (3, 8.783675, 2.311861, 6.060013),
+ (4, 8.781261, 2.313746, 6.057873),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_compile",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.083893, 1.630474, 3.536216),
+ (1, 4.087591, 1.635289, 3.497630),
+ (2, 4.085695, 1.632900, 3.538942),
+ (3, 4.091750, 1.621504, 3.537607),
+ (4, 4.083429, 1.624206, 3.538044),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_compile",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.741063, 2.114975, 3.939181),
+ (1, 4.742471, 2.134199, 3.937271),
+ (2, 4.751861, 2.134679, 3.937887),
+ (3, 4.748915, 2.139128, 3.937938),
+ (4, 4.744369, 2.118603, 4.016509),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_compile",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.373580, 2.603582, 5.297729),
+ (1, 4.375890, 2.576323, 5.258865),
+ (2, 4.371432, 2.583884, 5.297363),
+ (3, 4.374495, 2.589453, 5.257298),
+ (4, 4.369606, 2.606228, 5.257661),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_compile",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.661360, 2.976421, 7.177350),
+ (1, 9.668097, 2.986125, 6.963308),
+ (2, 9.667800, 2.983053, 6.959276),
+ (3, 9.663941, 2.979323, 6.939242),
+ (4, 9.662299, 2.970007, 6.988974),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_compile",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.579784, 1.946620, 4.378033),
+ (1, 3.579704, 1.964725, 4.377985),
+ (2, 3.584964, 1.951670, 4.376971),
+ (3, 3.576692, 1.920906, 4.418008),
+ (4, 3.590239, 1.966765, 4.377119),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_compile",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 8.908318, 2.358443, 6.137820),
+ (1, 8.900847, 2.342913, 6.137705),
+ (2, 8.902168, 2.355932, 6.179136),
+ (3, 8.903369, 2.363490, 6.097751),
+ (4, 8.896827, 2.364196, 6.098246),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"all",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.122590, 1.633583, 3.696664),
+ (1, 4.114949, 1.638141, 3.578111),
+ (2, 4.114996, 1.631617, 3.536742),
+ (3, 4.118038, 1.641230, 3.578327),
+ (4, 4.112972, 1.639592, 3.575918),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"all",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.774701, 2.146296, 3.977572),
+ (1, 4.775361, 2.153011, 3.979860),
+ (2, 4.767364, 2.152865, 4.057217),
+ (3, 4.762550, 2.149360, 3.979342),
+ (4, 4.778981, 2.139902, 3.978489),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"all",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.400574, 2.604084, 5.299578),
+ (1, 4.404470, 2.623904, 5.338578),
+ (2, 4.396282, 2.608549, 5.297828),
+ (3, 4.410117, 2.614698, 5.340116),
+ (4, 4.406122, 2.619452, 5.337443),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"all",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.691876, 2.983326, 7.028989),
+ (1, 9.686101, 2.995257, 6.984466),
+ (2, 9.699200, 2.989842, 7.028152),
+ (3, 9.694729, 2.989742, 6.973924),
+ (4, 9.684670, 2.977108, 6.989194),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"all",
+ 'threads':"2",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.603234, 1.964083, 4.458006),
+ (1, 3.607074, 1.941178, 4.417525),
+ (2, 3.603034, 1.943612, 4.737094),
+ (3, 3.602477, 1.935710, 4.378785),
+ (4, 3.603014, 1.920944, 4.496731),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"all",
+ 'threads':"2",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 8.919863, 2.380177, 6.178527),
+ (1, 8.915304, 2.377547, 6.139442),
+ (2, 8.912262, 2.361640, 6.382166),
+ (3, 8.928109, 2.368477, 6.192743),
+ (4, 8.926360, 2.372693, 6.196191),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"null",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.433816, 0.270779, 0.497217),
+ (1, 0.435460, 0.270028, 0.496532),
+ (2, 0.433553, 0.269600, 0.496135),
+ (3, 0.444402, 0.277012, 0.497745),
+ (4, 0.435023, 0.270357, 0.496884),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"null",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.427882, 0.266594, 0.456246),
+ (1, 0.436036, 0.268734, 0.457465),
+ (2, 0.432485, 0.268278, 0.495730),
+ (3, 0.431188, 0.269520, 0.457981),
+ (4, 0.429806, 0.265927, 0.457372),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"null",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.439986, 0.271715, 0.496550),
+ (1, 0.433586, 0.270013, 0.496199),
+ (2, 0.432029, 0.268060, 0.497939),
+ (3, 0.439059, 0.272464, 0.497620),
+ (4, 0.434181, 0.272563, 0.497461),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"null",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.432427, 0.269396, 0.457136),
+ (1, 0.428288, 0.270302, 0.737128),
+ (2, 0.431231, 0.268325, 0.456252),
+ (3, 0.427926, 0.267086, 0.456874),
+ (4, 0.420557, 0.264270, 0.457617),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"null",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.434424, 0.272190, 0.498161),
+ (1, 0.434165, 0.269235, 0.494824),
+ (2, 0.432662, 0.270415, 0.500255),
+ (3, 0.438368, 0.274265, 0.496769),
+ (4, 0.436696, 0.274610, 0.495729),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"null",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.433117, 0.267209, 0.457335),
+ (1, 0.431207, 0.267527, 0.457362),
+ (2, 0.427488, 0.263088, 0.456154),
+ (3, 0.424716, 0.264632, 0.456745),
+ (4, 0.430324, 0.266478, 0.457237),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"###",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.243380, 0.979720, 1.137169),
+ (1, 1.278996, 0.992319, 1.137506),
+ (2, 1.287192, 0.993761, 1.138362),
+ (3, 1.287132, 0.979672, 1.137975),
+ (4, 1.280673, 0.991069, 1.134803),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"###",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.199258, 0.944011, 1.056302),
+ (1, 1.238243, 0.967198, 1.055378),
+ (2, 1.251064, 0.952736, 1.058118),
+ (3, 1.238275, 0.953812, 1.056281),
+ (4, 1.230085, 0.961011, 1.058278),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"###",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.303555, 1.002749, 1.177122),
+ (1, 1.297516, 0.987769, 1.179257),
+ (2, 1.291316, 0.989683, 1.134877),
+ (3, 1.297521, 0.998087, 1.177932),
+ (4, 1.298070, 0.996104, 1.136646),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"###",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.242426, 0.951754, 1.054691),
+ (1, 1.251845, 0.955747, 1.055754),
+ (2, 1.216099, 0.939568, 1.057614),
+ (3, 1.252534, 0.953115, 1.057181),
+ (4, 1.255139, 0.957134, 1.056560),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"###",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.480008, 0.367388, 0.535985),
+ (1, 0.482634, 0.363998, 0.537057),
+ (2, 0.487524, 0.362915, 0.536461),
+ (3, 0.486824, 0.371502, 0.536601),
+ (4, 0.486100, 0.368487, 0.536231),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"###",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.471967, 0.356792, 0.537280),
+ (1, 0.471389, 0.351906, 0.537328),
+ (2, 0.476653, 0.364830, 0.536856),
+ (3, 0.473745, 0.360644, 0.536245),
+ (4, 0.471692, 0.358740, 0.536919),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_pch",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.488745, 1.084366, 1.498790),
+ (1, 1.477772, 1.072057, 1.497152),
+ (2, 1.481656, 1.079815, 1.497487),
+ (3, 1.488131, 1.086291, 1.497713),
+ (4, 1.484908, 1.083611, 1.497307),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_pch",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.892219, 1.358115, 3.416973),
+ (1, 2.908085, 1.361083, 3.458190),
+ (2, 2.911845, 1.363507, 3.498229),
+ (3, 2.861631, 1.340626, 3.497350),
+ (4, 2.902695, 1.349841, 3.498252),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_pch",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.094289, 0.731166, 2.856787),
+ (1, 2.094159, 0.727149, 3.098345),
+ (2, 2.099123, 0.725737, 2.857987),
+ (3, 2.099356, 0.725484, 2.857824),
+ (4, 2.092198, 0.722902, 2.856964),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"cpp",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.072042, 1.472173, 1.777206),
+ (1, 2.082600, 1.489627, 1.777280),
+ (2, 2.056884, 1.488123, 1.817614),
+ (3, 2.070744, 1.497244, 1.776597),
+ (4, 2.067240, 1.482836, 1.777571),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"cpp",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.533060, 2.043311, 1.777522),
+ (1, 2.628373, 2.047752, 1.777593),
+ (2, 2.630915, 2.051977, 1.777852),
+ (3, 2.630455, 2.065881, 1.777911),
+ (4, 2.631787, 2.049902, 1.778263),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"parse",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.505337, 1.496155, 1.898006),
+ (1, 2.495744, 1.488942, 1.897842),
+ (2, 2.515831, 1.484552, 1.897723),
+ (3, 2.498317, 1.488449, 1.897741),
+ (4, 2.515904, 1.484614, 1.897771),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"parse",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.125124, 2.066737, 1.896962),
+ (1, 3.066430, 2.061710, 1.897127),
+ (2, 2.951498, 2.032558, 1.899777),
+ (3, 3.102248, 2.072226, 1.938907),
+ (4, 2.965375, 2.034301, 1.901575),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"syntax",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.959637, 1.775658, 2.417471),
+ (1, 3.731703, 1.768139, 2.338378),
+ (2, 3.938876, 1.797903, 2.376989),
+ (3, 3.942618, 1.776899, 2.376468),
+ (4, 3.955662, 1.784850, 2.417537),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"syntax",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.711232, 2.418611, 2.457315),
+ (1, 4.710700, 2.405150, 2.458243),
+ (2, 4.701677, 2.393935, 2.458244),
+ (3, 4.700064, 2.411945, 2.458502),
+ (4, 4.435552, 2.373475, 2.417904),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"syntax",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.765235, 3.147148, 4.457806),
+ (1, 3.792075, 3.092380, 4.138512),
+ (2, 3.755530, 3.109232, 4.099198),
+ (3, 3.775577, 3.132702, 4.259349),
+ (4, 3.765380, 3.153395, 4.138279),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"syntax",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 8.733600, 3.141350, 3.819429),
+ (1, 8.729315, 3.130464, 3.818712),
+ (2, 8.758360, 3.153188, 3.898371),
+ (3, 8.284330, 3.049157, 3.698701),
+ (4, 8.287672, 3.024545, 3.697567),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"syntax",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.874930, 2.387032, 3.537592),
+ (1, 2.912332, 2.467479, 3.577891),
+ (2, 2.864476, 2.410851, 3.499089),
+ (3, 2.907625, 2.451013, 3.618200),
+ (4, 2.911261, 2.404477, 4.099524),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"syntax",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 7.915458, 2.450591, 3.219913),
+ (1, 7.956233, 2.439542, 3.300366),
+ (2, 7.913691, 2.473252, 3.218957),
+ (3, 7.509113, 2.397069, 3.138018),
+ (4, 7.904014, 2.456804, 3.218425),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"irgen",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.942240, 1.800567, 2.417458),
+ (1, 4.154844, 1.814089, 2.457805),
+ (2, 4.176584, 1.830900, 2.457020),
+ (3, 4.158194, 1.830085, 2.778865),
+ (4, 4.150232, 1.830750, 2.459318),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"irgen",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.905547, 2.434522, 2.537988),
+ (1, 4.924605, 2.457269, 2.538644),
+ (2, 4.657417, 2.378047, 2.458053),
+ (3, 4.911690, 2.470984, 2.537993),
+ (4, 4.929673, 2.455544, 2.538190),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_asm",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.418219, 1.850523, 2.536990),
+ (1, 4.366724, 1.852566, 2.538399),
+ (2, 4.384926, 1.854429, 2.539958),
+ (3, 4.394250, 1.842192, 2.539435),
+ (4, 4.397239, 1.838145, 2.540060),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_asm",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 5.130585, 2.493244, 2.579148),
+ (1, 5.162982, 2.497135, 2.578713),
+ (2, 5.129066, 2.472889, 2.619872),
+ (3, 4.874468, 2.405774, 2.497419),
+ (4, 5.128376, 2.467295, 2.578880),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_asm",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.630875, 3.227827, 4.420094),
+ (1, 4.603130, 3.292521, 4.698425),
+ (2, 4.637749, 3.169974, 4.378697),
+ (3, 4.662829, 3.216485, 4.459226),
+ (4, 4.661186, 3.194321, 4.459337),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_asm",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.094412, 3.382733, 4.299690),
+ (1, 10.607728, 3.485426, 4.420339),
+ (2, 10.672437, 3.500697, 4.499281),
+ (3, 10.081432, 3.369802, 4.260940),
+ (4, 10.637020, 3.507006, 4.419349),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_asm",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.756469, 2.606486, 3.858024),
+ (1, 3.742525, 2.585514, 3.860432),
+ (2, 3.763984, 2.594155, 3.858338),
+ (3, 3.750329, 2.597445, 3.861970),
+ (4, 3.780330, 2.594397, 4.178249),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_asm",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.783391, 2.778921, 3.858346),
+ (1, 9.291026, 2.713206, 3.741779),
+ (2, 9.763105, 2.769221, 3.818018),
+ (3, 9.781831, 2.771892, 3.860051),
+ (4, 9.795868, 2.814192, 3.861095),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_compile",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.526822, 1.970779, 2.579904),
+ (1, 4.516155, 1.962200, 2.579553),
+ (2, 4.502726, 1.967558, 2.657639),
+ (3, 4.475255, 1.944838, 2.578810),
+ (4, 4.552333, 1.965428, 2.620439),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_compile",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 5.260314, 2.603498, 2.660341),
+ (1, 4.995161, 2.487917, 2.539731),
+ (2, 5.272310, 2.582304, 2.619170),
+ (3, 5.297074, 2.584287, 2.659045),
+ (4, 5.276844, 2.591704, 2.658579),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_compile",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.820446, 3.357945, 4.457265),
+ (1, 4.695519, 3.299694, 4.700489),
+ (2, 4.802906, 3.355605, 4.499002),
+ (3, 4.790937, 3.298910, 4.497635),
+ (4, 4.807253, 3.403019, 4.538081),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_compile",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.775635, 3.627255, 4.498454),
+ (1, 10.819002, 3.627111, 4.498795),
+ (2, 10.777939, 3.603335, 4.579594),
+ (3, 10.261991, 3.489692, 4.340296),
+ (4, 10.783511, 3.603470, 4.497803),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_compile",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.926690, 2.635944, 3.858194),
+ (1, 3.904631, 2.622227, 3.819312),
+ (2, 3.902995, 2.656935, 3.899565),
+ (3, 3.842353, 2.559599, 3.939178),
+ (4, 3.912334, 2.629019, 3.858092),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_compile",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.417663, 2.778879, 3.779754),
+ (1, 9.981881, 2.854902, 3.981156),
+ (2, 9.922719, 2.849422, 3.895627),
+ (3, 9.932923, 2.851789, 3.899661),
+ (4, 9.882651, 2.809967, 3.860299),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"all",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.524352, 1.986189, 2.979131),
+ (1, 4.571793, 1.979632, 2.617329),
+ (2, 4.551874, 1.976839, 2.657311),
+ (3, 4.535069, 1.982461, 2.660565),
+ (4, 4.517949, 1.967234, 2.619985),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"all",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 5.308971, 2.608535, 2.660880),
+ (1, 5.300322, 2.591561, 2.698928),
+ (2, 5.007866, 2.516937, 2.617425),
+ (3, 5.004273, 2.518780, 2.620204),
+ (4, 5.298584, 2.603459, 2.697609),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"all",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.829605, 3.306560, 4.499574),
+ (1, 4.834964, 3.359516, 4.499708),
+ (2, 4.848950, 3.406535, 4.500607),
+ (3, 4.846305, 3.301867, 4.501270),
+ (4, 4.841747, 3.311314, 4.460786),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"all",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.261230, 3.487758, 4.377307),
+ (1, 10.821449, 3.608144, 4.579734),
+ (2, 10.818690, 3.639902, 4.538873),
+ (3, 10.288671, 3.520532, 4.378760),
+ (4, 10.827655, 3.621076, 4.540632),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"all",
+ 'threads':"4",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.945245, 2.727926, 4.020004),
+ (1, 3.927023, 2.718237, 3.937944),
+ (2, 3.864097, 2.645215, 4.258710),
+ (3, 3.959593, 2.659668, 3.857486),
+ (4, 3.949860, 2.636461, 3.860314),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"all",
+ 'threads':"4",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.988320, 2.894515, 3.979462),
+ (1, 9.984554, 2.865497, 3.978603),
+ (2, 9.969262, 2.894911, 3.940909),
+ (3, 9.971215, 2.860655, 3.939045),
+ (4, 9.928752, 2.859610, 4.140611),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"null",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.437223, 0.305541, 0.456598),
+ (1, 0.437365, 0.302782, 0.455612),
+ (2, 0.444941, 0.302766, 0.458539),
+ (3, 0.443284, 0.309348, 0.457267),
+ (4, 0.438558, 0.302788, 0.456867),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"null",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.433141, 0.299426, 0.457566),
+ (1, 0.433713, 0.302028, 0.456971),
+ (2, 0.432310, 0.301072, 0.457115),
+ (3, 0.431210, 0.298571, 0.456809),
+ (4, 0.432891, 0.306442, 0.458554),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"null",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.440129, 0.307891, 0.457005),
+ (1, 0.441966, 0.305756, 0.456712),
+ (2, 0.444503, 0.310015, 0.457176),
+ (3, 0.439473, 0.304319, 0.457442),
+ (4, 0.443194, 0.306398, 0.457362),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"null",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.431106, 0.301673, 0.458410),
+ (1, 0.434829, 0.302589, 0.456891),
+ (2, 0.430545, 0.302707, 0.457500),
+ (3, 0.436609, 0.301462, 0.456980),
+ (4, 0.429837, 0.300629, 0.456958),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"null",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.441827, 0.306401, 0.457803),
+ (1, 0.440791, 0.307818, 0.456863),
+ (2, 0.441486, 0.306428, 0.456280),
+ (3, 0.441639, 0.303644, 0.457488),
+ (4, 0.435752, 0.302272, 0.456606),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"null",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.434382, 0.299908, 0.458576),
+ (1, 0.430466, 0.299767, 0.458895),
+ (2, 0.433482, 0.301923, 0.457146),
+ (3, 0.437816, 0.305736, 0.460591),
+ (4, 0.433787, 0.300150, 0.457657),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"###",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.248580, 1.078897, 1.137297),
+ (1, 1.240939, 1.052455, 1.415574),
+ (2, 1.241209, 1.084570, 1.136554),
+ (3, 1.240406, 1.093724, 1.136429),
+ (4, 1.240385, 1.082323, 1.136401),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"###",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.290192, 1.199382, 0.936326),
+ (1, 1.276522, 1.198278, 0.936272),
+ (2, 1.273170, 1.185225, 0.935751),
+ (3, 1.281657, 1.188458, 0.934154),
+ (4, 1.285165, 1.186782, 0.935658),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"###",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.261013, 1.087419, 1.135864),
+ (1, 1.261208, 1.088418, 1.134847),
+ (2, 1.243520, 1.091952, 1.135702),
+ (3, 1.256916, 1.061697, 1.138041),
+ (4, 1.262088, 1.105355, 1.137939),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"###",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.304031, 1.188856, 0.937909),
+ (1, 1.293276, 1.188637, 0.935459),
+ (2, 1.278288, 1.189283, 0.936833),
+ (3, 1.302987, 1.181945, 0.936069),
+ (4, 1.293851, 1.192556, 0.936999),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"###",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.490107, 0.418154, 0.575664),
+ (1, 0.489843, 0.413785, 0.535501),
+ (2, 0.487683, 0.415899, 0.535610),
+ (3, 0.484014, 0.413119, 0.535279),
+ (4, 0.491381, 0.413503, 0.537277),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"###",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 0.486695, 0.445844, 0.494296),
+ (1, 0.481367, 0.455675, 0.497159),
+ (2, 0.481974, 0.481187, 0.496221),
+ (3, 0.479369, 0.425384, 0.495441),
+ (4, 0.478301, 0.457115, 0.494315),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_pch",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.434857, 1.168123, 1.455765),
+ (1, 1.436208, 1.190995, 1.496024),
+ (2, 1.439552, 1.161674, 1.455066),
+ (3, 1.436967, 1.180953, 1.494596),
+ (4, 1.435067, 1.162529, 1.456440),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_pch",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.854271, 1.448036, 3.456023),
+ (1, 2.864284, 1.464534, 3.456831),
+ (2, 2.860290, 1.477350, 3.377527),
+ (3, 2.857286, 1.458217, 3.417068),
+ (4, 2.855595, 1.464395, 3.376247),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_pch",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.095114, 0.776987, 2.855911),
+ (1, 2.099607, 0.795455, 2.856180),
+ (2, 2.095073, 0.792649, 2.896811),
+ (3, 2.094082, 0.789727, 2.897515),
+ (4, 2.100236, 0.781259, 2.774968),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"cpp",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 1.999042, 1.594807, 1.777251),
+ (1, 1.990498, 1.601683, 1.736392),
+ (2, 2.006314, 1.599276, 1.897380),
+ (3, 1.994969, 1.622299, 1.775973),
+ (4, 1.988203, 1.577170, 1.736153),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"cpp",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.703651, 2.613281, 1.374149),
+ (1, 2.700635, 2.658189, 1.415542),
+ (2, 2.723514, 2.623613, 1.375880),
+ (3, 2.698653, 2.597336, 1.376495),
+ (4, 2.682678, 2.616761, 1.377316),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"parse",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.415923, 1.586213, 1.856706),
+ (1, 2.413466, 1.580113, 1.854297),
+ (2, 2.415569, 1.611288, 1.856562),
+ (3, 2.398350, 1.569858, 1.855165),
+ (4, 2.394427, 1.597305, 1.856311),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"parse",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.166052, 2.593652, 1.456512),
+ (1, 3.196717, 2.604754, 1.456743),
+ (2, 3.101508, 2.536190, 1.456607),
+ (3, 3.174828, 2.591447, 1.456659),
+ (4, 3.201618, 2.596692, 1.457126),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"syntax",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.712949, 1.873531, 2.336073),
+ (1, 3.691984, 1.870964, 2.297376),
+ (2, 3.733735, 1.860346, 2.296816),
+ (3, 3.702759, 1.885194, 2.336534),
+ (4, 3.725368, 1.861191, 2.296488),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"syntax",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.674568, 2.896322, 1.777463),
+ (1, 4.751183, 2.932167, 1.774656),
+ (2, 4.619575, 2.943985, 1.775820),
+ (3, 4.831743, 2.966127, 1.785376),
+ (4, 4.696926, 2.918956, 1.774947),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"syntax",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.619956, 3.111231, 4.057294),
+ (1, 3.634434, 3.079039, 4.176458),
+ (2, 3.619489, 3.150783, 4.138602),
+ (3, 3.621266, 3.104540, 4.058816),
+ (4, 3.608454, 3.122193, 4.057912),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"syntax",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 8.685876, 3.735123, 2.538354),
+ (1, 8.928202, 3.820031, 2.775907),
+ (2, 9.001593, 3.780341, 2.615105),
+ (3, 8.914982, 3.802006, 2.576587),
+ (4, 8.672801, 3.745031, 2.537300),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"syntax",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 2.804784, 2.299355, 3.497193),
+ (1, 2.837757, 2.362386, 3.538558),
+ (2, 2.872059, 2.437397, 3.497046),
+ (3, 2.822245, 2.354290, 3.416766),
+ (4, 2.852352, 2.360742, 3.536904),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"syntax",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 7.840658, 2.912237, 2.176625),
+ (1, 7.786177, 2.867490, 2.098460),
+ (2, 8.029733, 2.900113, 2.094914),
+ (3, 7.787848, 2.850907, 2.096058),
+ (4, 8.009086, 2.890278, 2.097071),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"irgen",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.924865, 1.882098, 2.377105),
+ (1, 3.946578, 1.907070, 2.377384),
+ (2, 3.942964, 1.879682, 2.376026),
+ (3, 3.891159, 1.892699, 2.377748),
+ (4, 3.967042, 1.868087, 2.417171),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"irgen",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.959364, 2.975161, 1.817129),
+ (1, 5.054176, 2.984549, 1.817835),
+ (2, 4.919681, 2.991480, 1.815857),
+ (3, 4.910313, 2.971126, 1.816666),
+ (4, 4.951734, 2.972542, 1.815437),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_asm",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.101830, 1.911448, 2.454536),
+ (1, 4.134987, 1.907901, 2.417187),
+ (2, 4.137531, 1.889402, 2.416253),
+ (3, 4.106261, 1.900297, 2.418632),
+ (4, 4.116540, 1.914047, 2.415859),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_asm",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 5.144013, 2.981688, 1.855810),
+ (1, 5.084562, 2.953167, 1.816353),
+ (2, 5.123251, 2.985708, 1.937743),
+ (3, 5.218549, 3.005248, 1.816337),
+ (4, 5.121341, 2.958136, 1.817163),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_asm",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.391211, 3.194895, 4.297978),
+ (1, 4.320212, 3.215877, 4.336974),
+ (2, 4.317236, 3.185048, 4.297096),
+ (3, 4.347551, 3.210930, 4.337750),
+ (4, 4.340133, 3.158959, 4.298051),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_asm",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.533776, 4.099156, 2.857560),
+ (1, 10.875003, 4.167712, 2.978028),
+ (2, 10.559224, 4.084177, 2.898004),
+ (3, 10.529217, 4.091320, 2.857602),
+ (4, 10.531274, 4.079794, 2.857786),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_asm",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.572211, 2.564058, 3.657172),
+ (1, 3.610311, 2.554201, 3.738315),
+ (2, 3.503969, 2.457425, 3.656664),
+ (3, 3.497522, 2.477225, 3.776817),
+ (4, 3.516315, 2.450350, 3.697352),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_asm",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.667563, 3.247271, 2.416874),
+ (1, 9.737532, 3.221747, 2.496587),
+ (2, 9.683672, 3.255651, 2.416956),
+ (3, 9.897372, 3.270324, 2.457738),
+ (4, 9.960110, 3.282960, 2.536374),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_compile",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.216047, 2.040267, 2.417042),
+ (1, 4.198596, 2.057673, 2.417291),
+ (2, 4.355761, 2.050442, 2.456578),
+ (3, 4.269654, 2.046761, 2.414728),
+ (4, 4.258278, 2.065794, 2.415867),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"only_compile",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 5.364820, 3.155647, 1.856490),
+ (1, 5.380241, 3.164256, 1.895779),
+ (2, 5.258991, 3.099702, 1.858494),
+ (3, 5.408499, 3.143804, 1.858232),
+ (4, 5.433442, 3.172182, 1.896951),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_compile",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.509842, 3.336711, 4.298495),
+ (1, 4.493119, 3.342058, 4.338363),
+ (2, 4.497302, 3.391293, 4.376365),
+ (3, 4.552023, 3.326395, 4.296523),
+ (4, 4.511749, 3.315174, 4.258914),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"only_compile",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 11.063909, 4.331076, 2.975250),
+ (1, 10.750918, 4.265164, 2.897127),
+ (2, 10.773158, 4.274519, 2.858005),
+ (3, 10.989661, 4.295921, 2.937906),
+ (4, 10.991448, 4.334725, 2.977596),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_compile",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.668731, 2.619398, 3.657468),
+ (1, 3.654504, 2.592248, 3.696077),
+ (2, 3.665061, 2.625732, 3.699196),
+ (3, 3.673349, 2.573183, 3.697462),
+ (4, 3.682111, 2.613733, 3.738984),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"only_compile",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 9.810406, 3.300637, 2.416778),
+ (1, 10.048934, 3.350114, 2.496649),
+ (2, 9.875004, 3.340279, 2.537774),
+ (3, 10.160045, 3.376951, 2.619453),
+ (4, 10.115032, 3.362591, 2.537008),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"all",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.241536, 2.082256, 2.455986),
+ (1, 4.286330, 2.067488, 2.496313),
+ (2, 4.291944, 2.084961, 2.496839),
+ (3, 4.299382, 2.050242, 2.497274),
+ (4, 4.256038, 2.063266, 2.497293),
+]}
+))
+runs.append(( { 'cc':"ccc_clang",
+ 'script':"all",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 5.421218, 3.170845, 1.936421),
+ (1, 5.384884, 3.153992, 1.897806),
+ (2, 5.296851, 3.153219, 1.951468),
+ (3, 5.260795, 3.139369, 2.177163),
+ (4, 5.278498, 3.141780, 1.895288),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"all",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 4.484287, 3.364861, 4.377941),
+ (1, 4.531560, 3.308326, 4.377562),
+ (2, 4.578896, 3.345062, 4.377173),
+ (3, 4.566615, 3.446052, 4.417550),
+ (4, 4.515315, 3.375575, 4.336788),
+]}
+))
+runs.append(( { 'cc':"ccc_gcc",
+ 'script':"all",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.788959, 4.299290, 2.977905),
+ (1, 11.090341, 4.345425, 3.058836),
+ (2, 11.066430, 4.319885, 2.976521),
+ (3, 10.779432, 4.283670, 3.018155),
+ (4, 10.788091, 4.327036, 2.978633),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"all",
+ 'threads':"8",
+ 'pch':"pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 3.682013, 2.568734, 3.737019),
+ (1, 3.782095, 2.599814, 3.777516),
+ (2, 3.694371, 2.626584, 3.858657),
+ (3, 3.701257, 2.616141, 4.138741),
+ (4, 3.772297, 2.652233, 3.697378),
+]}
+))
+runs.append(( { 'cc':"gcc",
+ 'script':"all",
+ 'threads':"8",
+ 'pch':"no_pch" },
+{ 'version' : 0,
+ 'samples' : [
+ (0, 10.129212, 3.382389, 2.576426),
+ (1, 10.165855, 3.362136, 2.579688),
+ (2, 10.085414, 3.375557, 2.539346),
+ (3, 10.106707, 3.375161, 2.777265),
+ (4, 10.163243, 3.374295, 2.579247),
+]}
+))